mirror of
https://github.com/System-End/github-readme-stats.git
synced 2026-04-19 16:38:23 +00:00
refactor: jsdoc in utils & minor changes (#1377)
* refactor: jsdoc in utils & minor changes * chore: jsdoc Card class * chore: jsdoc for getStyles
This commit is contained in:
parent
d0ab2ff030
commit
02ebd3243b
7 changed files with 143 additions and 41 deletions
|
|
@ -34,8 +34,6 @@ module.exports = async (req, res) => {
|
|||
border_radius,
|
||||
border_color,
|
||||
} = req.query;
|
||||
let stats;
|
||||
|
||||
res.setHeader("Content-Type", "image/svg+xml");
|
||||
|
||||
if (blacklist.includes(username)) {
|
||||
|
|
@ -47,7 +45,7 @@ module.exports = async (req, res) => {
|
|||
}
|
||||
|
||||
try {
|
||||
stats = await fetchStats(
|
||||
const stats = await fetchStats(
|
||||
username,
|
||||
parseBoolean(count_private),
|
||||
parseBoolean(include_all_commits),
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@ module.exports = async (req, res) => {
|
|||
border_color,
|
||||
} = req.query;
|
||||
|
||||
let repoData;
|
||||
|
||||
res.setHeader("Content-Type", "image/svg+xml");
|
||||
|
||||
if (blacklist.includes(username)) {
|
||||
|
|
@ -40,7 +38,7 @@ module.exports = async (req, res) => {
|
|||
}
|
||||
|
||||
try {
|
||||
repoData = await fetchRepo(username, repo);
|
||||
const repoData = await fetchRepo(username, repo);
|
||||
|
||||
let cacheSeconds = clampValue(
|
||||
parseInt(cache_seconds || CONSTANTS.TWO_HOURS, 10),
|
||||
|
|
|
|||
|
|
@ -31,8 +31,6 @@ module.exports = async (req, res) => {
|
|||
border_radius,
|
||||
border_color,
|
||||
} = req.query;
|
||||
let topLangs;
|
||||
|
||||
res.setHeader("Content-Type", "image/svg+xml");
|
||||
|
||||
if (blacklist.includes(username)) {
|
||||
|
|
@ -44,7 +42,7 @@ module.exports = async (req, res) => {
|
|||
}
|
||||
|
||||
try {
|
||||
topLangs = await fetchTopLanguages(
|
||||
const topLangs = await fetchTopLanguages(
|
||||
username,
|
||||
parseArray(exclude_repo),
|
||||
parseArray(hide),
|
||||
|
|
|
|||
|
|
@ -110,15 +110,14 @@ const renderRepoCard = (repo, options = {}) => {
|
|||
});
|
||||
|
||||
// returns theme based colors with proper overrides and defaults
|
||||
const { titleColor, textColor, iconColor, bgColor, borderColor } =
|
||||
getCardColors({
|
||||
title_color,
|
||||
icon_color,
|
||||
text_color,
|
||||
bg_color,
|
||||
border_color,
|
||||
theme,
|
||||
});
|
||||
const colors = getCardColors({
|
||||
title_color,
|
||||
icon_color,
|
||||
text_color,
|
||||
bg_color,
|
||||
border_color,
|
||||
theme,
|
||||
});
|
||||
|
||||
const svgLanguage = primaryLanguage
|
||||
? createLanguageNode(langName, langColor)
|
||||
|
|
@ -145,22 +144,16 @@ const renderRepoCard = (repo, options = {}) => {
|
|||
width: 400,
|
||||
height,
|
||||
border_radius,
|
||||
colors: {
|
||||
titleColor,
|
||||
textColor,
|
||||
iconColor,
|
||||
bgColor,
|
||||
borderColor,
|
||||
},
|
||||
colors,
|
||||
});
|
||||
|
||||
card.disableAnimations();
|
||||
card.setHideBorder(hide_border);
|
||||
card.setHideTitle(false);
|
||||
card.setCSS(`
|
||||
.description { font: 400 13px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor} }
|
||||
.gray { font: 400 12px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor} }
|
||||
.icon { fill: ${iconColor} }
|
||||
.description { font: 400 13px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${colors.textColor} }
|
||||
.gray { font: 400 12px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${colors.textColor} }
|
||||
.icon { fill: ${colors.iconColor} }
|
||||
.badge { font: 600 11px 'Segoe UI', Ubuntu, Sans-Serif; }
|
||||
.badge rect { opacity: 0.2 }
|
||||
`);
|
||||
|
|
@ -168,9 +161,9 @@ const renderRepoCard = (repo, options = {}) => {
|
|||
return card.render(`
|
||||
${
|
||||
isTemplate
|
||||
? getBadgeSVG(i18n.t("repocard.template"), textColor)
|
||||
? getBadgeSVG(i18n.t("repocard.template"), colors.textColor)
|
||||
: isArchived
|
||||
? getBadgeSVG(i18n.t("repocard.archived"), textColor)
|
||||
? getBadgeSVG(i18n.t("repocard.archived"), colors.textColor)
|
||||
: ""
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,16 @@ const { getAnimations } = require("../getStyles");
|
|||
const { flexLayout, encodeHTML } = require("../common/utils");
|
||||
|
||||
class Card {
|
||||
/**
|
||||
* @param {object} args
|
||||
* @param {number?=} args.width
|
||||
* @param {number?=} args.height
|
||||
* @param {number?=} args.border_radius
|
||||
* @param {string?=} args.customTitle
|
||||
* @param {string?=} args.defaultTitle
|
||||
* @param {string?=} args.titlePrefixIcon
|
||||
* @param {ReturnType<import('../common/utils').getCardColors>?=} args.colors
|
||||
*/
|
||||
constructor({
|
||||
width = 100,
|
||||
height = 100,
|
||||
|
|
@ -38,14 +48,23 @@ class Card {
|
|||
this.animations = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
*/
|
||||
setCSS(value) {
|
||||
this.css = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} value
|
||||
*/
|
||||
setHideBorder(value) {
|
||||
this.hideBorder = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} value
|
||||
*/
|
||||
setHideTitle(value) {
|
||||
this.hideTitle = value;
|
||||
if (value) {
|
||||
|
|
@ -53,6 +72,9 @@ class Card {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
*/
|
||||
setTitle(text) {
|
||||
this.title = text;
|
||||
}
|
||||
|
|
@ -114,6 +136,9 @@ class Card {
|
|||
: "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} body
|
||||
*/
|
||||
render(body) {
|
||||
return `
|
||||
<svg
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
// @ts-check
|
||||
const axios = require("axios");
|
||||
const wrap = require("word-wrap");
|
||||
const themes = require("../../themes");
|
||||
const toEmoji = require("emoji-name-map");
|
||||
|
||||
/**
|
||||
* @param {string} message
|
||||
* @param {string} secondaryMessage
|
||||
* @returns {string}
|
||||
*/
|
||||
const renderError = (message, secondaryMessage = "") => {
|
||||
return `
|
||||
<svg width="495" height="120" viewBox="0 0 495 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
|
|
@ -21,7 +27,11 @@ const renderError = (message, secondaryMessage = "") => {
|
|||
`;
|
||||
};
|
||||
|
||||
// https://stackoverflow.com/a/48073476/10629172
|
||||
/**
|
||||
* @see https://stackoverflow.com/a/48073476/10629172
|
||||
* @param {string} str
|
||||
* @returns {string}
|
||||
*/
|
||||
function encodeHTML(str) {
|
||||
return str
|
||||
.replace(/[\u00A0-\u9999<>&](?!#)/gim, (i) => {
|
||||
|
|
@ -30,18 +40,29 @@ function encodeHTML(str) {
|
|||
.replace(/\u0008/gim, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} num
|
||||
*/
|
||||
function kFormatter(num) {
|
||||
return Math.abs(num) > 999
|
||||
? Math.sign(num) * (Math.abs(num) / 1000).toFixed(1) + "k"
|
||||
? Math.sign(num) * parseFloat((Math.abs(num) / 1000).toFixed(1)) + "k"
|
||||
: Math.sign(num) * Math.abs(num);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} hexColor
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isValidHexColor(hexColor) {
|
||||
return new RegExp(
|
||||
/^([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{4})$/,
|
||||
).test(hexColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @returns {boolean | string}
|
||||
*/
|
||||
function parseBoolean(value) {
|
||||
if (value === "true") {
|
||||
return true;
|
||||
|
|
@ -52,19 +73,37 @@ function parseBoolean(value) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
*/
|
||||
function parseArray(str) {
|
||||
if (!str) return [];
|
||||
return str.split(",");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} number
|
||||
* @param {number} min
|
||||
* @param {number} max
|
||||
*/
|
||||
function clampValue(number, min, max) {
|
||||
// @ts-ignore
|
||||
if (Number.isNaN(parseInt(number))) return min;
|
||||
return Math.max(min, Math.min(number, max));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} colors
|
||||
*/
|
||||
function isValidGradient(colors) {
|
||||
return isValidHexColor(colors[1]) && isValidHexColor(colors[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} color
|
||||
* @param {string} fallbackColor
|
||||
* @returns {string | string[]}
|
||||
*/
|
||||
function fallbackColor(color, fallbackColor) {
|
||||
let colors = color.split(",");
|
||||
let gradient = null;
|
||||
|
|
@ -79,7 +118,12 @@ function fallbackColor(color, fallbackColor) {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('axios').AxiosRequestConfig['data']} data
|
||||
* @param {import('axios').AxiosRequestConfig['headers']} headers
|
||||
*/
|
||||
function request(data, headers) {
|
||||
// @ts-ignore
|
||||
return axios({
|
||||
url: "https://api.github.com/graphql",
|
||||
method: "post",
|
||||
|
|
@ -92,8 +136,8 @@ function request(data, headers) {
|
|||
* @param {object} props
|
||||
* @param {string[]} props.items
|
||||
* @param {number} props.gap
|
||||
* @param {number[]} props.sizes
|
||||
* @param {"column" | "row"} props.direction
|
||||
* @param {number[]?=} props.sizes
|
||||
* @param {"column" | "row"?=} props.direction
|
||||
*
|
||||
* @returns {string[]}
|
||||
*
|
||||
|
|
@ -115,14 +159,27 @@ function flexLayout({ items, gap, direction, sizes = [] }) {
|
|||
});
|
||||
}
|
||||
|
||||
// returns theme based colors with proper overrides and defaults
|
||||
/**
|
||||
* @typedef {object} CardColors
|
||||
* @prop {string} title_color
|
||||
* @prop {string} text_color
|
||||
* @prop {string} icon_color
|
||||
* @prop {string} bg_color
|
||||
* @prop {string} border_color
|
||||
* @prop {keyof typeof import('../../themes')?=} fallbackTheme
|
||||
* @prop {keyof typeof import('../../themes')?=} theme
|
||||
*/
|
||||
/**
|
||||
* returns theme based colors with proper overrides and defaults
|
||||
* @param {CardColors} options
|
||||
*/
|
||||
function getCardColors({
|
||||
title_color,
|
||||
text_color,
|
||||
icon_color,
|
||||
bg_color,
|
||||
theme,
|
||||
border_color,
|
||||
theme,
|
||||
fallbackTheme = "default",
|
||||
}) {
|
||||
const defaultTheme = themes[fallbackTheme];
|
||||
|
|
@ -157,6 +214,12 @@ function getCardColors({
|
|||
return { titleColor, iconColor, textColor, bgColor, borderColor };
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {number} width
|
||||
* @param {number} maxLines
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function wrapTextMultiline(text, width = 60, maxLines = 3) {
|
||||
const wrapped = wrap(encodeHTML(text), { width })
|
||||
.split("\n") // Split wrapped lines to get an array of lines
|
||||
|
|
@ -193,6 +256,10 @@ const SECONDARY_ERROR_MESSAGES = {
|
|||
};
|
||||
|
||||
class CustomError extends Error {
|
||||
/**
|
||||
* @param {string} message
|
||||
* @param {string} type
|
||||
*/
|
||||
constructor(message, type) {
|
||||
super(message);
|
||||
this.type = type;
|
||||
|
|
@ -203,7 +270,12 @@ class CustomError extends Error {
|
|||
static USER_NOT_FOUND = "USER_NOT_FOUND";
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/48172630/10629172
|
||||
/**
|
||||
* @see https://stackoverflow.com/a/48172630/10629172
|
||||
* @param {string} str
|
||||
* @param {number} fontSize
|
||||
* @returns
|
||||
*/
|
||||
function measureText(str, fontSize = 10) {
|
||||
// prettier-ignore
|
||||
const widths = [
|
||||
|
|
@ -237,6 +309,8 @@ function measureText(str, fontSize = 10) {
|
|||
.reduce((cur, acc) => acc + cur) * fontSize
|
||||
);
|
||||
}
|
||||
|
||||
/** @param {string} name */
|
||||
const lowercaseTrim = (name) => name.toLowerCase().trim();
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,14 +1,21 @@
|
|||
/**
|
||||
* @param {number} value
|
||||
*/
|
||||
const calculateCircleProgress = (value) => {
|
||||
let radius = 40;
|
||||
let c = Math.PI * (radius * 2);
|
||||
const radius = 40;
|
||||
const c = Math.PI * (radius * 2);
|
||||
|
||||
if (value < 0) value = 0;
|
||||
if (value > 100) value = 100;
|
||||
|
||||
let percentage = ((100 - value) / 100) * c;
|
||||
return percentage;
|
||||
return ((100 - value) / 100) * c;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {{progress: number}} param0
|
||||
* @returns
|
||||
*/
|
||||
const getProgressAnimation = ({ progress }) => {
|
||||
return `
|
||||
@keyframes rankAnimation {
|
||||
|
|
@ -44,6 +51,15 @@ const getAnimations = () => {
|
|||
`;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {{
|
||||
* titleColor: string;
|
||||
* textColor: string;
|
||||
* iconColor: string;
|
||||
* show_icons: boolean;
|
||||
* progress: number;
|
||||
* }} args
|
||||
*/
|
||||
const getStyles = ({
|
||||
titleColor,
|
||||
textColor,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue