Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add custom theme support #188

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 46 additions & 2 deletions api/cards/most-commit-language.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,21 @@ import {getCommitsLanguageSVGWithThemeName} from '../../src/cards/most-commit-la
import {changToNextGitHubToken} from '../utils/github-token-updater';
import {getErrorMsgCard} from '../utils/error-card';
import {translateLanguage} from '../../src/utils/translator';
import {Theme} from '../../src/const/theme';
import type {VercelRequest, VercelResponse} from '@vercel/node';

export default async (req: VercelRequest, res: VercelResponse) => {
let {username, theme = 'default', exclude = ''} = req.query;
let {
username,
theme = 'default',
exclude = '',
title_color = '',
text_color = '',
bg_color = '',
border_color = '',
icon_color = '',
chart_color = ''
} = req.query;

if (typeof theme !== 'string') {
res.status(400).send('theme must be a string');
Expand All @@ -19,16 +30,49 @@ export default async (req: VercelRequest, res: VercelResponse) => {
res.status(400).send('exclude must be a string');
return;
}
if (typeof title_color !== 'string') {
res.status(400).send('title_color must be a string');
return;
}
if (typeof text_color !== 'string') {
res.status(400).send('text_color must be a string');
return;
}
if (typeof bg_color !== 'string') {
res.status(400).send('bg_color must be a string');
return;
}
if (typeof border_color !== 'string') {
res.status(400).send('border_color must be a string');
return;
}
if (typeof icon_color !== 'string') {
res.status(400).send('icon_color must be a string');
return;
}
if (typeof chart_color !== 'string') {
res.status(400).send('chart_color must be a string');
return;
Comment on lines +33 to +55
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor the repeated validation code into a utility function to reduce redundancy and enhance maintainability.

+ function validateParam(param, paramName) {
+   if (typeof param !== 'string') {
+       res.status(400).send(`${paramName} must be a string`);
+       return false;
+   }
+   return true;
+ }
- if (typeof title_color !== 'string') {
-     res.status(400).send('title_color must be a string');
-     return;
- }
+ if (!validateParam(title_color, 'title_color')) return;

Committable suggestion was skipped due to low confidence.

}
let excludeArr = <string[]>[];
exclude.split(',').forEach(function (val) {
excludeArr.push(translateLanguage(val));
});
Comment on lines 58 to 60
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using an arrow function for the forEach callback to improve consistency with modern JavaScript syntax.

- exclude.split(',').forEach(function (val) {
+ exclude.split(',').forEach(val => {
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
exclude.split(',').forEach(function (val) {
excludeArr.push(translateLanguage(val));
});
exclude.split(',').forEach(val => {
excludeArr.push(translateLanguage(val));
});
Tools
Biome

[error] 58-60: This function expression can be turned into an arrow function. (lint/complexity/useArrowFunction)

Function expressions that don't use this can be turned into arrow functions.
Safe fix: Use an arrow function instead.

let customTheme = new Theme(
title_color,
text_color,
bg_color,
border_color,
-1, // strokeOpacity is not used in custom themes
icon_color,
chart_color
);

try {
let tokenIndex = 0;
while (true) {
try {
const cardSVG = await getCommitsLanguageSVGWithThemeName(username, theme, excludeArr);
const cardSVG = await getCommitsLanguageSVGWithThemeName(username, theme, customTheme, excludeArr);
res.setHeader('Content-Type', 'image/svg+xml');
res.send(cardSVG);
return;
Expand Down
49 changes: 47 additions & 2 deletions api/cards/productive-time.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
import {getProductiveTimeSVGWithThemeName} from '../../src/cards/productive-time-card';
import {changToNextGitHubToken} from '../utils/github-token-updater';
import {getErrorMsgCard} from '../utils/error-card';
import {Theme} from '../../src/const/theme';
import type {VercelRequest, VercelResponse} from '@vercel/node';

export default async (req: VercelRequest, res: VercelResponse) => {
const {username, theme = 'default', utcOffset = '0'} = req.query;
const {
username,
theme = 'default',
utcOffset = '0',
title_color = '',
text_color = '',
bg_color = '',
border_color = '',
icon_color = '',
chart_color = ''
} = req.query;
if (typeof theme !== 'string') {
res.status(400).send('theme must be a string');
return;
Expand All @@ -17,11 +28,45 @@ export default async (req: VercelRequest, res: VercelResponse) => {
res.status(400).send('utcOffset must be a string');
return;
}
if (typeof title_color !== 'string') {
res.status(400).send('title_color must be a string');
return;
}
if (typeof text_color !== 'string') {
res.status(400).send('text_color must be a string');
return;
}
if (typeof bg_color !== 'string') {
res.status(400).send('bg_color must be a string');
return;
}
if (typeof border_color !== 'string') {
res.status(400).send('border_color must be a string');
return;
}
if (typeof icon_color !== 'string') {
res.status(400).send('icon_color must be a string');
return;
}
if (typeof chart_color !== 'string') {
res.status(400).send('chart_color must be a string');
return;
}
let customTheme = new Theme(
title_color,
text_color,
bg_color,
border_color,
-1, // strokeOpacity is not used in custom themes
icon_color,
chart_color
);

try {
let tokenIndex = 0;
while (true) {
try {
const cardSVG = await getProductiveTimeSVGWithThemeName(username, theme, Number(utcOffset));
const cardSVG = await getProductiveTimeSVGWithThemeName(username, theme, customTheme, Number(utcOffset));
res.setHeader('Content-Type', 'image/svg+xml');
res.send(cardSVG);
return;
Expand Down
48 changes: 46 additions & 2 deletions api/cards/profile-details.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import {getProfileDetailsSVGWithThemeName} from '../../src/cards/profile-details-card';
import {changToNextGitHubToken} from '../utils/github-token-updater';
import {getErrorMsgCard} from '../utils/error-card';
import {Theme} from '../../src/const/theme';
import type {VercelRequest, VercelResponse} from '@vercel/node';

export default async (req: VercelRequest, res: VercelResponse) => {
const {username, theme = 'default'} = req.query;
const {
username,
theme = 'default',
title_color = '',
text_color = '',
bg_color = '',
border_color = '',
icon_color = '',
chart_color = ''
} = req.query;
if (typeof theme !== 'string') {
res.status(400).send('theme must be a string');
return;
Expand All @@ -13,11 +23,45 @@ export default async (req: VercelRequest, res: VercelResponse) => {
res.status(400).send('username must be a string');
return;
}
if (typeof title_color !== 'string') {
res.status(400).send('title_color must be a string');
return;
}
if (typeof text_color !== 'string') {
res.status(400).send('text_color must be a string');
return;
}
if (typeof bg_color !== 'string') {
res.status(400).send('bg_color must be a string');
return;
}
if (typeof border_color !== 'string') {
res.status(400).send('border_color must be a string');
return;
}
if (typeof icon_color !== 'string') {
res.status(400).send('icon_color must be a string');
return;
}
if (typeof chart_color !== 'string') {
res.status(400).send('chart_color must be a string');
return;
}
let customTheme = new Theme(
title_color,
text_color,
bg_color,
border_color,
-1, // strokeOpacity is not used in custom themes
icon_color,
chart_color
);

try {
let tokenIndex = 0;
while (true) {
try {
const cardSVG = await getProfileDetailsSVGWithThemeName(username, theme);
const cardSVG = await getProfileDetailsSVGWithThemeName(username, theme, customTheme);
res.setHeader('Content-Type', 'image/svg+xml');
res.send(cardSVG);
return;
Expand Down
48 changes: 46 additions & 2 deletions api/cards/repos-per-language.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,21 @@ import {getReposPerLanguageSVGWithThemeName} from '../../src/cards/repos-per-lan
import {changToNextGitHubToken} from '../utils/github-token-updater';
import {getErrorMsgCard} from '../utils/error-card';
import {translateLanguage} from '../../src/utils/translator';
import {Theme} from '../../src/const/theme';
import type {VercelRequest, VercelResponse} from '@vercel/node';

export default async (req: VercelRequest, res: VercelResponse) => {
let {username, theme = 'default', exclude = ''} = req.query;
let {
username,
theme = 'default',
exclude = '',
title_color = '',
text_color = '',
bg_color = '',
border_color = '',
icon_color = '',
chart_color = ''
} = req.query;

if (typeof theme !== 'string') {
res.status(400).send('theme must be a string');
Expand All @@ -19,6 +30,39 @@ export default async (req: VercelRequest, res: VercelResponse) => {
res.status(400).send('exclude must be a string');
return;
}
if (typeof title_color !== 'string') {
res.status(400).send('title_color must be a string');
return;
}
if (typeof text_color !== 'string') {
res.status(400).send('text_color must be a string');
return;
}
if (typeof bg_color !== 'string') {
res.status(400).send('bg_color must be a string');
return;
}
if (typeof border_color !== 'string') {
res.status(400).send('border_color must be a string');
return;
}
if (typeof icon_color !== 'string') {
res.status(400).send('icon_color must be a string');
return;
}
if (typeof chart_color !== 'string') {
res.status(400).send('chart_color must be a string');
return;
Comment on lines +33 to +55
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The repeated pattern of parameter validation can be refactored into a utility function to adhere to DRY principles.

+ function validateParam(param, paramName) {
+   if (typeof param !== 'string') {
+       res.status(400).send(`${paramName} must be a string`);
+       return false;
+   }
+   return true;
+ }
- if (typeof title_color !== 'string') {
-     res.status(400).send('title_color must be a string');
-     return;
- }
+ if (!validateParam(title_color, 'title_color')) return;

Committable suggestion was skipped due to low confidence.

}
let customTheme = new Theme(
title_color,
text_color,
bg_color,
border_color,
-1, // strokeOpacity is not used in custom themes
icon_color,
chart_color
);
let excludeArr = <string[]>[];
exclude.split(',').forEach(function (val) {
excludeArr.push(translateLanguage(val));
Expand All @@ -28,7 +72,7 @@ export default async (req: VercelRequest, res: VercelResponse) => {
let tokenIndex = 0;
while (true) {
try {
const cardSVG = await getReposPerLanguageSVGWithThemeName(username, theme, excludeArr);
const cardSVG = await getReposPerLanguageSVGWithThemeName(username, theme, customTheme, excludeArr);
res.setHeader('Content-Type', 'image/svg+xml');
res.send(cardSVG);
return;
Expand Down
48 changes: 46 additions & 2 deletions api/cards/stats.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import {getStatsSVGWithThemeName} from '../../src/cards/stats-card';
import {changToNextGitHubToken} from '../utils/github-token-updater';
import {getErrorMsgCard} from '../utils/error-card';
import {Theme} from '../../src/const/theme';
import type {VercelRequest, VercelResponse} from '@vercel/node';

export default async (req: VercelRequest, res: VercelResponse) => {
const {username, theme = 'default'} = req.query;
const {
username,
theme = 'default',
title_color = '',
text_color = '',
bg_color = '',
border_color = '',
icon_color = '',
chart_color = ''
} = req.query;
if (typeof theme !== 'string') {
res.status(400).send('theme must be a string');
return;
Expand All @@ -13,11 +23,45 @@ export default async (req: VercelRequest, res: VercelResponse) => {
res.status(400).send('username must be a string');
return;
}
if (typeof title_color !== 'string') {
res.status(400).send('title_color must be a string');
return;
}
if (typeof text_color !== 'string') {
res.status(400).send('text_color must be a string');
return;
}
if (typeof bg_color !== 'string') {
res.status(400).send('bg_color must be a string');
return;
}
if (typeof border_color !== 'string') {
res.status(400).send('border_color must be a string');
return;
}
if (typeof icon_color !== 'string') {
res.status(400).send('icon_color must be a string');
return;
}
if (typeof chart_color !== 'string') {
res.status(400).send('chart_color must be a string');
return;
}
let customTheme = new Theme(
title_color,
text_color,
bg_color,
border_color,
-1, // strokeOpacity is not used in custom themes
icon_color,
chart_color
);

try {
let tokenIndex = 0;
while (true) {
try {
const cardSVG = await getStatsSVGWithThemeName(username, theme);
const cardSVG = await getStatsSVGWithThemeName(username, theme, customTheme);
res.setHeader('Content-Type', 'image/svg+xml');
res.send(cardSVG);
return;
Expand Down
Loading
Loading