import { getCardColors, FlexLayout, clampValue } from "../common/utils" import Card from '../common/Card' import { data } from "../fetcher"; import React from 'react' import themes from "../../themes"; export interface parsedQuery { hide?: Array hide_title?: boolean hide_border?: boolean card_width?: number title_color?: string text_color?: string bg_color?: string language_count?: number show_level?: string theme?: keyof typeof themes cache_seconds?: string layout?: string } const createProgressNode = ({ width, color, name, progress, progress2 }: {width: number ,color: string, name: string, progress: number, progress2:number}) => { const paddingRight = 60; const progressWidth = width - paddingRight; const progressPercentage = clampValue(progress, 2, 100); const progress2Percentage = clampValue(progress2, 2, 100); return ( <> {name} {progress}%{progress2 > progress ? ` + ${progress2 - progress}%` : ''} ) }; const createCompactLangNode = ({ lang, totalSize, x, y }: {lang: data, totalSize: number, x: number, y: number}) => { const percentage = ((lang.size / totalSize) * 100).toFixed(2); const color = lang.color || "#858585"; return ( {lang.name} {percentage}% ) }; const createLanguageTextNode = ({ langs, totalSize, x, y }: { langs: Array, totalSize: number, x: number, y: number}) => { return langs.map((lang, index) => { if (index % 2 === 0) { return createCompactLangNode({ lang, x, y: 12.5 * index + y, totalSize }); } return createCompactLangNode({ lang, x: 150, y: 12.5 + 12.5 * index, totalSize }); }); }; const lowercaseTrim = (name: string) => name.toLowerCase().trim(); const renderTopLanguages = (topLangs: Record, options: parsedQuery = {}) => { const { hide_title, hide_border, card_width, title_color, text_color, bg_color, hide, language_count, theme, layout, } = options; let langs = Object.values(topLangs); let langsToHide: Record = {}; // populate langsToHide map for quick lookup // while filtering out if (hide) { hide.forEach((langName) => { langsToHide[lowercaseTrim(langName)] = true; }); } // filter out langauges to be hidden langs = langs .sort((a, b) => b.size - a.size) .filter((lang) => { return !langsToHide[lowercaseTrim(lang.name)]; }) .slice(0, language_count || 5); const totalLanguageSize = langs.reduce((acc, curr) => { return acc + curr.size; }, 0); // returns theme based colors with proper overrides and defaults const { titleColor, textColor, bgColor } = getCardColors({ title_color, text_color, bg_color, theme, }); let width = typeof card_width !== 'number' ? 300 : isNaN(card_width) ? 300 : card_width; let height = 45 + (langs.length + 1) * 40; let finalLayout: JSX.Element | Array; // RENDER COMPACT LAYOUT if (layout === "compact") { width = width + 50; height = 30 + (langs.length / 2 + 1) * 40; // progressOffset holds the previous language's width and used to offset the next language // so that we can stack them one after another, like this: [--][----][---] let progressOffset = 0; const compactProgressBar = langs .map((lang, index) => { const percentage = parseFloat(( (lang.size / totalLanguageSize) * (width - 50) ).toFixed(2)); const progress = percentage < 10 ? percentage + 10 : percentage; const output = ( ) progressOffset += percentage; return output; }) finalLayout = ( <> {compactProgressBar} {createLanguageTextNode({ x: 0, y: 25, langs, totalSize: totalLanguageSize, })} ) finalLayout = ( <> {compactProgressBar} {createLanguageTextNode({ x: 0, y: 25, langs, totalSize: totalLanguageSize, })} ) } else { finalLayout = FlexLayout({ items: langs.map((lang) => { return createProgressNode({ width: width, name: lang.name, color: lang.color || "#858585", progress: parseFloat(((lang.size / totalLanguageSize) * 100).toFixed(2)), progress2: parseFloat(((lang.recentSize / totalLanguageSize) * 100).toFixed(2)), }); }), gap: 40, direction: "column", }) } const card = new Card( width, height, { titleColor, textColor, bgColor, }, "Most Used Languages", ) card.disableAnimations(); card.setHideBorder(hide_border || false); card.setHideTitle(hide_title || false); card.setCSS(` .lang-name { font: 400 11px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor} } `); return card.render( {finalLayout} ) }; export default renderTopLanguages