const { kFormatter, getCardColors, FlexLayout, encodeHTML, } = require("../common/utils"); const { getStyles } = require("../getStyles"); const icons = require("../common/icons"); const Card = require("../common/Card"); const createTextNode = ({ icon, label, value, id, index, showIcons, shiftValuePos, }) => { const kValue = kFormatter(value); const staggerDelay = (index + 3) * 150; const labelOffset = showIcons ? `x="25"` : ""; const iconSvg = showIcons ? ` ${icon} ` : ""; return ` ${iconSvg} ${label}: ${kValue} `; }; const renderStatsCard = (stats = {}, options = { hide: [] }) => { const { name, totalStars, totalCommits, totalIssues, totalPRs, contributedTo, rank, } = stats; const { hide = [], show_icons = false, hide_title = false, hide_border = false, hide_rank = false, include_all_commits = false, line_height = 25, title_color, icon_color, text_color, bg_color, theme = "default", } = options; const lheight = parseInt(line_height, 10); // returns theme based colors with proper overrides and defaults const { titleColor, textColor, iconColor, bgColor } = getCardColors({ title_color, icon_color, text_color, bg_color, theme, }); // Meta data for creating text nodes with createTextNode function const STATS = { stars: { icon: icons.star, label: "Total Stars", value: totalStars, id: "stars", }, commits: { icon: icons.commits, label: `Total Commits${ include_all_commits ? "" : ` (${new Date().getFullYear()})` }`, value: totalCommits, id: "commits", }, prs: { icon: icons.prs, label: "Total PRs", value: totalPRs, id: "prs", }, issues: { icon: icons.issues, label: "Total Issues", value: totalIssues, id: "issues", }, contribs: { icon: icons.contribs, label: "Contributed to", value: contributedTo, id: "contribs", }, }; // filter out hidden stats defined by user & create the text nodes const statItems = Object.keys(STATS) .filter((key) => !hide.includes(key)) .map((key, index) => // create the text nodes, and pass index so that we can calculate the line spacing createTextNode({ ...STATS[key], index, showIcons: show_icons, shiftValuePos: !include_all_commits, }) ); // Calculate the card height depending on how many items there are // but if rank circle is visible clamp the minimum height to `150` let height = Math.max( 45 + (statItems.length + 1) * lheight, hide_rank ? 0 : 150 ); // Conditionally rendered elements const rankCircle = hide_rank ? "" : ` ${rank.level} `; // the better user's score the the rank will be closer to zero so // subtracting 100 to get the progress in 100% const progress = 100 - rank.score; const cssStyles = getStyles({ titleColor, textColor, iconColor, show_icons, progress, }); const apostrophe = ["x", "s"].includes(name.slice(-1)) ? "" : "s"; const card = new Card({ title: `${encodeHTML(name)}'${apostrophe} GitHub Stats`, width: 495, height, colors: { titleColor, textColor, iconColor, bgColor, }, }); card.setHideBorder(hide_border); card.setHideTitle(hide_title); card.setCSS(cssStyles); return card.render(` ${rankCircle} ${FlexLayout({ items: statItems, gap: lheight, direction: "column", }).join("")} `); }; module.exports = renderStatsCard;