diff --git a/api/index.js b/api/index.js deleted file mode 100644 index 87da679..0000000 --- a/api/index.js +++ /dev/null @@ -1,73 +0,0 @@ -require("dotenv").config(); -const { - renderError, - parseBoolean, - parseArray, - clampValue, - CONSTANTS, -} = require("../src/common/utils"); -const fetchStats = require("../src/fetchers/stats-fetcher"); -const renderStatsCard = require("../src/cards/stats-card"); -const blacklist = require("../src/common/blacklist"); - -module.exports = async (req, res) => { - const { - username, - hide, - hide_title, - hide_border, - hide_rank, - show_icons, - count_private, - include_all_commits, - line_height, - title_color, - icon_color, - text_color, - bg_color, - theme, - cache_seconds, - } = req.query; - let stats; - - res.setHeader("Content-Type", "image/svg+xml"); - - if (blacklist.includes(username)) { - return res.send(renderError("Something went wrong")); - } - - try { - stats = await fetchStats( - username, - parseBoolean(count_private), - parseBoolean(include_all_commits) - ); - - const cacheSeconds = clampValue( - parseInt(cache_seconds || CONSTANTS.TWO_HOURS, 10), - CONSTANTS.TWO_HOURS, - CONSTANTS.ONE_DAY - ); - - res.setHeader("Cache-Control", `public, max-age=${cacheSeconds}`); - - return res.send( - renderStatsCard(stats, { - hide: parseArray(hide), - show_icons: parseBoolean(show_icons), - hide_title: parseBoolean(hide_title), - hide_border: parseBoolean(hide_border), - hide_rank: parseBoolean(hide_rank), - include_all_commits: parseBoolean(include_all_commits), - line_height, - title_color, - icon_color, - text_color, - bg_color, - theme, - }) - ); - } catch (err) { - return res.send(renderError(err.message, err.secondaryMessage)); - } -}; diff --git a/api/pin.js b/api/pin.js deleted file mode 100644 index c09b2d6..0000000 --- a/api/pin.js +++ /dev/null @@ -1,70 +0,0 @@ -require("dotenv").config(); -const { - renderError, - parseBoolean, - clampValue, - CONSTANTS, -} = require("../src/common/utils"); -const fetchRepo = require("../src/fetchers/repo-fetcher"); -const renderRepoCard = require("../src/cards/repo-card"); -const blacklist = require("../src/common/blacklist"); - -module.exports = async (req, res) => { - const { - username, - repo, - title_color, - icon_color, - text_color, - bg_color, - theme, - show_owner, - cache_seconds, - } = req.query; - - let repoData; - - res.setHeader("Content-Type", "image/svg+xml"); - - if (blacklist.includes(username)) { - return res.send(renderError("Something went wrong")); - } - - try { - repoData = await fetchRepo(username, repo); - - let cacheSeconds = clampValue( - parseInt(cache_seconds || CONSTANTS.TWO_HOURS, 10), - CONSTANTS.TWO_HOURS, - CONSTANTS.ONE_DAY - ); - - /* - if star count & fork count is over 1k then we are kFormating the text - and if both are zero we are not showing the stats - so we can just make the cache longer, since there is no need to frequent updates - */ - const stars = repoData.stargazers.totalCount; - const forks = repoData.forkCount; - const isBothOver1K = stars > 1000 && forks > 1000; - const isBothUnder1 = stars < 1 && forks < 1; - if (!cache_seconds && (isBothOver1K || isBothUnder1)) { - cacheSeconds = CONSTANTS.FOUR_HOURS; - } - - res.setHeader("Cache-Control", `public, max-age=${cacheSeconds}`); - - return res.send( - renderRepoCard(repoData, { - title_color, - icon_color, - text_color, - bg_color, - theme, - show_owner: parseBoolean(show_owner), - }) - ); - } catch (err) { - return res.send(renderError(err.message, err.secondaryMessage)); - } -}; diff --git a/api/top-langs.js b/api/top-langs.js deleted file mode 100644 index fecf057..0000000 --- a/api/top-langs.js +++ /dev/null @@ -1,64 +0,0 @@ -require("dotenv").config(); -const { - renderError, - clampValue, - parseBoolean, - parseArray, - CONSTANTS, -} = require("../src/common/utils"); -const fetchTopLanguages = require("../src/fetchers/top-languages-fetcher"); -const renderTopLanguages = require("../src/cards/top-languages-card"); -const blacklist = require("../src/common/blacklist"); - -module.exports = async (req, res) => { - const { - username, - hide, - hide_title, - hide_border, - card_width, - title_color, - text_color, - bg_color, - language_count, - theme, - cache_seconds, - layout, - } = req.query; - let topLangs; - - res.setHeader("Content-Type", "image/svg+xml"); - - if (blacklist.includes(username)) { - return res.send(renderError("Something went wrong")); - } - - try { - topLangs = await fetchTopLanguages(username); - - const cacheSeconds = clampValue( - parseInt(cache_seconds || CONSTANTS.TWO_HOURS, 10), - CONSTANTS.TWO_HOURS, - CONSTANTS.ONE_DAY - ); - - res.setHeader("Cache-Control", `public, max-age=${cacheSeconds}`); - - return res.send( - renderTopLanguages(topLangs, { - hide_title: parseBoolean(hide_title), - hide_border: parseBoolean(hide_border), - card_width: parseInt(card_width, 10), - hide: parseArray(hide), - language_count: parseInt(language_count), - title_color, - text_color, - bg_color, - theme, - layout, - }) - ); - } catch (err) { - return res.send(renderError(err.message, err.secondaryMessage)); - } -}; diff --git a/api/top-langs.ts b/api/top-langs.ts new file mode 100644 index 0000000..5484858 --- /dev/null +++ b/api/top-langs.ts @@ -0,0 +1,79 @@ +import { renderError, clampValue, parseBoolean, parseArray, CONSTANTS} from '../src/common/utils' +import fetchTopLanguages from '../src/fetchers/top-languages-fetcher' +import renderTopLanguages from '../src/cards/top-languages-card' +import blacklist from '../src/common/blacklist' +import { Request, Response } from 'express'; +import ReactDOMServer from 'react-dom/server' +import themes from '../themes'; + +export interface query { + username: string + hide?: string + hide_title?: string + hide_border?: string + card_width?: string + title_color?: string + text_color?: string + bg_color?: string + language_count?: string + show_level?: string + theme?: keyof typeof themes + cache_seconds?: string + layout?: string +} + +export default async (req: Request, res: Response) => { + const { + username, + hide, + hide_title, + hide_border, + card_width, + title_color, + text_color, + bg_color, + language_count, + show_level, + theme, + cache_seconds, + layout, + } = req.query; + + res.setHeader("Content-Type", "image/svg+xml"); + + if (blacklist.includes(username)) { + return res.send(renderError("Something went wrong")); + } + + try { + const topLangs = await fetchTopLanguages(username); + + const cacheSeconds = clampValue( + parseInt(cache_seconds || CONSTANTS.TWO_HOURS + '', 10), + CONSTANTS.TWO_HOURS, + CONSTANTS.ONE_DAY + ); + + res.setHeader("Cache-Control", `public, max-age=${cacheSeconds}`); + + return res.send(ReactDOMServer.renderToStaticMarkup( + renderTopLanguages(topLangs, { + hide_title: parseBoolean(hide_title), + hide_border: parseBoolean(hide_border), + card_width: parseInt(card_width || '', 10), + hide: parseArray(hide), + language_count: parseInt(language_count || '6'), + title_color, + text_color, + bg_color, + show_level, + theme, + layout, + })) + ); + } catch (err) { + return res.send( + ReactDOMServer.renderToStaticMarkup(renderError(err.message, err.secondaryMessage)) + ); + } +}; diff --git a/package.json b/package.json index dc0ab2f..562840d 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,9 @@ "@actions/github": "^4.0.0", "@testing-library/dom": "^7.20.0", "@testing-library/jest-dom": "^5.11.0", + "@types/express": "^4.17.8", + "@types/react": "^16.9.49", + "@types/react-dom": "^16.9.8", "axios": "^0.19.2", "axios-mock-adapter": "^1.18.1", "css-to-object": "^1.1.0", @@ -28,6 +31,9 @@ "dotenv": "^8.2.0", "emoji-name-map": "^1.2.8", "github-username-regex": "^1.0.0", + "react": "^16.13.1", + "react-dom": "^16.13.1", + "typescript": "^4.0.2", "word-wrap": "^1.2.3" } } diff --git a/src/calculateRank.js b/src/calculateRank.js deleted file mode 100644 index 76909d0..0000000 --- a/src/calculateRank.js +++ /dev/null @@ -1,93 +0,0 @@ -// https://stackoverflow.com/a/5263759/10629172 -function normalcdf(mean, sigma, to) { - var z = (to - mean) / Math.sqrt(2 * sigma * sigma); - var t = 1 / (1 + 0.3275911 * Math.abs(z)); - var a1 = 0.254829592; - var a2 = -0.284496736; - var a3 = 1.421413741; - var a4 = -1.453152027; - var a5 = 1.061405429; - var erf = - 1 - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * Math.exp(-z * z); - var sign = 1; - if (z < 0) { - sign = -1; - } - return (1 / 2) * (1 + sign * erf); -} - -function calculateRank({ - totalRepos, - totalCommits, - contributions, - followers, - prs, - issues, - stargazers, -}) { - const COMMITS_OFFSET = 1.65; - const CONTRIBS_OFFSET = 1.65; - const ISSUES_OFFSET = 1; - const STARS_OFFSET = 0.75; - const PRS_OFFSET = 0.5; - const FOLLOWERS_OFFSET = 0.45; - const REPO_OFFSET = 1; - - const ALL_OFFSETS = - CONTRIBS_OFFSET + - ISSUES_OFFSET + - STARS_OFFSET + - PRS_OFFSET + - FOLLOWERS_OFFSET + - REPO_OFFSET; - - const RANK_S_VALUE = 1; - const RANK_DOUBLE_A_VALUE = 25; - const RANK_A2_VALUE = 45; - const RANK_A3_VALUE = 60; - const RANK_B_VALUE = 100; - - const TOTAL_VALUES = - RANK_S_VALUE + RANK_A2_VALUE + RANK_A3_VALUE + RANK_B_VALUE; - - // prettier-ignore - const score = ( - totalCommits * COMMITS_OFFSET + - contributions * CONTRIBS_OFFSET + - issues * ISSUES_OFFSET + - stargazers * STARS_OFFSET + - prs * PRS_OFFSET + - followers * FOLLOWERS_OFFSET + - totalRepos * REPO_OFFSET - ) / 100; - - const normalizedScore = normalcdf(score, TOTAL_VALUES, ALL_OFFSETS) * 100; - - let level = ""; - - if (normalizedScore < RANK_S_VALUE) { - level = "S+"; - } - if ( - normalizedScore >= RANK_S_VALUE && - normalizedScore < RANK_DOUBLE_A_VALUE - ) { - level = "S"; - } - if ( - normalizedScore >= RANK_DOUBLE_A_VALUE && - normalizedScore < RANK_A2_VALUE - ) { - level = "A++"; - } - if (normalizedScore >= RANK_A2_VALUE && normalizedScore < RANK_A3_VALUE) { - level = "A+"; - } - if (normalizedScore >= RANK_A3_VALUE && normalizedScore < RANK_B_VALUE) { - level = "B+"; - } - - return { level, score: normalizedScore }; -} - -module.exports = calculateRank; diff --git a/src/cards/repo-card.js b/src/cards/repo-card.js deleted file mode 100644 index 233812b..0000000 --- a/src/cards/repo-card.js +++ /dev/null @@ -1,159 +0,0 @@ -const { - kFormatter, - encodeHTML, - getCardColors, - FlexLayout, - wrapTextMultiline, -} = require("../common/utils"); -const icons = require("../common/icons"); -const Card = require("../common/Card"); -const toEmoji = require("emoji-name-map"); - -const renderRepoCard = (repo, options = {}) => { - const { - name, - nameWithOwner, - description, - primaryLanguage, - stargazers, - isArchived, - isTemplate, - forkCount, - } = repo; - const { - title_color, - icon_color, - text_color, - bg_color, - show_owner, - theme = "default_repocard", - } = options; - - const header = show_owner ? nameWithOwner : name; - const langName = (primaryLanguage && primaryLanguage.name) || "Unspecified"; - const langColor = (primaryLanguage && primaryLanguage.color) || "#333"; - - const shiftText = langName.length > 15 ? 0 : 30; - - let desc = description || "No description provided"; - - // parse emojis to unicode - desc = desc.replace(/:\w+:/gm, (emoji) => { - return toEmoji.get(emoji) || ""; - }); - - const multiLineDescription = wrapTextMultiline(desc); - const descriptionLines = multiLineDescription.length; - const lineHeight = 10; - - const height = - (descriptionLines > 1 ? 120 : 110) + descriptionLines * lineHeight; - - // returns theme based colors with proper overrides and defaults - const { titleColor, textColor, iconColor, bgColor } = getCardColors({ - title_color, - icon_color, - text_color, - bg_color, - theme, - }); - - const totalStars = kFormatter(stargazers.totalCount); - const totalForks = kFormatter(forkCount); - - const getBadgeSVG = (label) => ` - - - - ${label} - - - `; - - const svgLanguage = primaryLanguage - ? ` - - - ${langName} - - ` - : ""; - - const iconWithLabel = (icon, label, testid) => { - return ` - - ${icon} - - ${label} - `; - }; - const svgStars = - stargazers.totalCount > 0 && - iconWithLabel(icons.star, totalStars, "stargazers"); - const svgForks = - forkCount > 0 && iconWithLabel(icons.fork, totalForks, "forkcount"); - - const starAndForkCount = FlexLayout({ - items: [svgStars, svgForks], - gap: 65, - }).join(""); - - const card = new Card({ - title: header, - titlePrefixIcon: icons.contribs, - width: 400, - height, - colors: { - titleColor, - textColor, - iconColor, - bgColor, - }, - }); - - card.disableAnimations(); - card.setHideBorder(false); - 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} } - .badge { font: 600 11px 'Segoe UI', Ubuntu, Sans-Serif; } - .badge rect { opacity: 0.2 } - `); - - return card.render(` - ${ - isTemplate - ? getBadgeSVG("Template") - : isArchived - ? getBadgeSVG("Archived") - : "" - } - - - ${multiLineDescription - .map((line) => `${encodeHTML(line)}`) - .join("")} - - - - ${svgLanguage} - - - ${starAndForkCount} - - - `); -}; - -module.exports = renderRepoCard; diff --git a/src/cards/stats-card.js b/src/cards/stats-card.js deleted file mode 100644 index 3c7aab7..0000000 --- a/src/cards/stats-card.js +++ /dev/null @@ -1,198 +0,0 @@ -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; diff --git a/src/cards/top-languages-card.js b/src/cards/top-languages-card.js deleted file mode 100644 index 096d5ef..0000000 --- a/src/cards/top-languages-card.js +++ /dev/null @@ -1,207 +0,0 @@ -const { getCardColors, FlexLayout, clampValue } = require("../common/utils"); -const Card = require("../common/Card"); - -const createProgressNode = ({ width, color, name, progress, progress2 }) => { - 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 }) => { - const percentage = ((lang.size / totalSize) * 100).toFixed(2); - const color = lang.color || "#858585"; - - return ` - - - - ${lang.name} ${percentage}% - - - `; -}; - -const createLanguageTextNode = ({ langs, totalSize, x, y }) => { - return langs.map((lang, index) => { - if (index % 2 === 0) { - return createCompactLangNode({ - lang, - x, - y: 12.5 * index + y, - totalSize, - index, - }); - } - return createCompactLangNode({ - lang, - x: 150, - y: 12.5 + 12.5 * index, - totalSize, - index, - }); - }); -}; - -const lowercaseTrim = (name) => name.toLowerCase().trim(); - -const renderTopLanguages = (topLangs, options = {}) => { - 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 = {}; - - // 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 = isNaN(card_width) ? 300 : card_width; - let height = 45 + (langs.length + 1) * 40; - - let finalLayout = ""; - - // 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) => { - const percentage = ( - (lang.size / totalLanguageSize) * - (width - 50) - ).toFixed(2); - - const progress = - percentage < 10 ? parseFloat(percentage) + 10 : percentage; - - const output = ` - - `; - progressOffset += parseFloat(percentage); - return output; - }) - .join(""); - - finalLayout = ` - - - - ${compactProgressBar} - ${createLanguageTextNode({ - x: 0, - y: 25, - langs, - totalSize: totalLanguageSize, - }).join("")} - `; - } else { - finalLayout = FlexLayout({ - items: langs.map((lang) => { - return createProgressNode({ - width: width, - name: lang.name, - color: lang.color || "#858585", - progress: ((lang.size / totalLanguageSize) * 100).toFixed(2), - progress2: ((lang.recentSize / totalLanguageSize) * 100).toFixed(2), - }); - }), - gap: 40, - direction: "column", - }).join(""); - } - - const card = new Card({ - title: "Most Used Languages", - width, - height, - colors: { - titleColor, - textColor, - bgColor, - }, - }); - - card.disableAnimations(); - card.setHideBorder(hide_border); - card.setHideTitle(hide_title); - card.setCSS(` - .lang-name { font: 400 11px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor} } - `); - - return card.render(` - - ${finalLayout} - - `); -}; - -module.exports = renderTopLanguages; diff --git a/src/cards/top-languages-card.tsx b/src/cards/top-languages-card.tsx new file mode 100644 index 0000000..cc42936 --- /dev/null +++ b/src/cards/top-languages-card.tsx @@ -0,0 +1,243 @@ +import { getCardColors, FlexLayout, clampValue } from "../common/utils" +import Card from '../common/Card' +import { query } from "../../api/top-langs"; +import { data } from "../fetchers/top-languages-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 diff --git a/src/common/Card.js b/src/common/Card.js deleted file mode 100644 index 172bd6c..0000000 --- a/src/common/Card.js +++ /dev/null @@ -1,166 +0,0 @@ -const { FlexLayout } = require("../common/utils"); -const { getAnimations } = require("../getStyles"); - -class Card { - constructor({ - width = 100, - height = 100, - colors = {}, - title = "", - titlePrefixIcon, - }) { - this.width = width; - this.height = height; - - this.hideBorder = false; - this.hideTitle = false; - - // returns theme based colors with proper overrides and defaults - this.colors = colors; - this.title = title; - this.css = ""; - - this.paddingX = 25; - this.paddingY = 35; - this.titlePrefixIcon = titlePrefixIcon; - this.animations = true; - } - - disableAnimations() { - this.animations = false; - } - - setCSS(value) { - this.css = value; - } - - setHideBorder(value) { - this.hideBorder = value; - } - - setHideTitle(value) { - this.hideTitle = value; - if (value) { - this.height -= 30; - } - } - - setTitle(text) { - this.title = text; - } - - renderTitle() { - const titleText = ` - ${this.title} - `; - - const prefixIcon = ` - - ${this.titlePrefixIcon} - - `; - return ` - - ${FlexLayout({ - items: [this.titlePrefixIcon && prefixIcon, titleText], - gap: 25, - }).join("")} - - `; - } - - renderGradient() { - if (typeof this.colors.bgColor !== "object") return; - - const gradients = this.colors.bgColor.slice(1); - return typeof this.colors.bgColor === "object" - ? ` - - - ${gradients.map((grad, index) => { - let offset = (index * 100) / (gradients.length - 1); - return ``; - })} - - - ` - : ""; - } - - render(body) { - return ` - - - - ${this.renderGradient()} - - - - ${this.hideTitle ? "" : this.renderTitle()} - - - ${body} - - - `; - } -} - -module.exports = Card; diff --git a/src/common/Card.tsx b/src/common/Card.tsx new file mode 100644 index 0000000..c1c650c --- /dev/null +++ b/src/common/Card.tsx @@ -0,0 +1,158 @@ +import React from 'react' + +import { FlexLayout } from './utils' +import { getAnimations } from '../getStyles' + +export default class Card { + public hideBorder = false + public hideTitle = false + public css = '' + public paddingX = 25 + public paddingY = 35 + public animations = true + + constructor( + public width = 100, + public height = 100, + public colors: {titleColor?: string | Array, textColor?: string | Array, bgColor?: string | Array} = {}, + public title = "", + public titlePrefixIcon?: string + ) {} + + disableAnimations() { + this.animations = false; + } + + setCSS(value: string) { + this.css = value; + } + + setHideBorder(value: boolean) { + this.hideBorder = value; + } + + setHideTitle(value: boolean) { + this.hideTitle = value; + if (value) { + this.height -= 30; + } + } + + setTitle(text: string) { + this.title = text; + } + + renderTitle() { + const titleText = ( + {this.title} + ) + + + const prefixIcon = ( + + ${this.titlePrefixIcon} + + ) + return ( + + {FlexLayout({ + items: [this.titlePrefixIcon && prefixIcon, titleText], + gap: 25, + })} + + ) + } + + renderGradient() { + if (typeof this.colors.bgColor !== "object") return; + + const gradients = this.colors.bgColor.slice(1); + return typeof this.colors.bgColor === "object" + ? ( + + + {gradients.map((grad, index) => { + let offset = (index * 100) / (gradients.length - 1); + return ``; + })} + + + ) + : ""; + } + + render(body: JSX.Element) { + return ( + + + + {this.renderGradient()} + + + + {this.hideTitle ? "" : this.renderTitle()} + + + {body} + + + ) + } +} diff --git a/src/common/blacklist.js b/src/common/blacklist.ts similarity index 69% rename from src/common/blacklist.js rename to src/common/blacklist.ts index 3ef635c..fe63b58 100644 --- a/src/common/blacklist.js +++ b/src/common/blacklist.ts @@ -1,3 +1,3 @@ const blacklist = ["renovate-bot", "technote-space", "sw-yx"]; -module.exports = blacklist; +export default blacklist diff --git a/src/common/icons.js b/src/common/icons.js deleted file mode 100644 index 7b7e507..0000000 --- a/src/common/icons.js +++ /dev/null @@ -1,11 +0,0 @@ -const icons = { - star: ``, - commits: ``, - prs: ``, - issues: ``, - icon: ``, - contribs: ``, - fork: ``, -}; - -module.exports = icons; diff --git a/src/common/icons.tsx b/src/common/icons.tsx new file mode 100644 index 0000000..870c5ce --- /dev/null +++ b/src/common/icons.tsx @@ -0,0 +1,12 @@ +import React from 'react' + +const icons = { + star: , + commits: , + prs: , + issues: , + icon: , + contribs: , + fork: , +}; +export default icons diff --git a/src/common/retryer.js b/src/common/retryer.js deleted file mode 100644 index 592463e..0000000 --- a/src/common/retryer.js +++ /dev/null @@ -1,43 +0,0 @@ -const { logger, CustomError } = require("../common/utils"); - -const retryer = async (fetcher, variables, retries = 0) => { - if (retries > 7) { - throw new CustomError("Maximum retries exceeded", CustomError.MAX_RETRY); - } - try { - // try to fetch with the first token since RETRIES is 0 index i'm adding +1 - let response = await fetcher( - variables, - process.env[`PAT_${retries + 1}`], - retries - ); - - // prettier-ignore - const isRateExceeded = response.data.errors && response.data.errors[0].type === "RATE_LIMITED"; - - // if rate limit is hit increase the RETRIES and recursively call the retryer - // with username, and current RETRIES - if (isRateExceeded) { - logger.log(`PAT_${retries + 1} Failed`); - retries++; - // directly return from the function - return retryer(fetcher, variables, retries); - } - - // finally return the response - return response; - } catch (err) { - // prettier-ignore - // also checking for bad credentials if any tokens gets invalidated - const isBadCredential = err.response.data && err.response.data.message === "Bad credentials"; - - if (isBadCredential) { - logger.log(`PAT_${retries + 1} Failed`); - retries++; - // directly return from the function - return retryer(fetcher, variables, retries); - } - } -}; - -module.exports = retryer; diff --git a/src/common/retryer.ts b/src/common/retryer.ts new file mode 100644 index 0000000..5fcb890 --- /dev/null +++ b/src/common/retryer.ts @@ -0,0 +1,43 @@ +import { logger, CustomError } from './utils' + +const retryer = async (fetcher, variables, retries = 0) => { + if (retries > 7) { + throw new CustomError("Maximum retries exceeded", CustomError.MAX_RETRY); + } + try { + // try to fetch with the first token since RETRIES is 0 index i'm adding +1 + let response = await fetcher( + variables, + process.env[`PAT_${retries + 1}`], + retries + ); + + // prettier-ignore + const isRateExceeded = response.data.errors && response.data.errors[0].type === "RATE_LIMITED"; + + // if rate limit is hit increase the RETRIES and recursively call the retryer + // with username, and current RETRIES + if (isRateExceeded) { + logger.log(`PAT_${retries + 1} Failed`); + retries++; + // directly return from the function + return retryer(fetcher, variables, retries); + } + + // finally return the response + return response; + } catch (err) { + // prettier-ignore + // also checking for bad credentials if any tokens gets invalidated + const isBadCredential = err.response.data && err.response.data.message === "Bad credentials"; + + if (isBadCredential) { + logger.log(`PAT_${retries + 1} Failed`); + retries++; + // directly return from the function + return retryer(fetcher, variables, retries); + } + } +}; + +export default retryer diff --git a/src/common/utils.js b/src/common/utils.js deleted file mode 100644 index 6a6e121..0000000 --- a/src/common/utils.js +++ /dev/null @@ -1,215 +0,0 @@ -const axios = require("axios"); -const wrap = require("word-wrap"); -const themes = require("../../themes"); - -const renderError = (message, secondaryMessage = "") => { - return ` - - - - Something went wrong! file an issue at https://git.io/JJmN9 - - ${encodeHTML(message)} - ${secondaryMessage} - - - `; -}; - -// https://stackoverflow.com/a/48073476/10629172 -function encodeHTML(str) { - return str - .replace(/[\u00A0-\u9999<>&](?!#)/gim, (i) => { - return "&#" + i.charCodeAt(0) + ";"; - }) - .replace(/\u0008/gim, ""); -} - -function kFormatter(num) { - return Math.abs(num) > 999 - ? Math.sign(num) * (Math.abs(num) / 1000).toFixed(1) + "k" - : Math.sign(num) * Math.abs(num); -} - -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); -} - -function parseBoolean(value) { - if (value === "true") { - return true; - } else if (value === "false") { - return false; - } else { - return value; - } -} - -function parseArray(str) { - if (!str) return []; - return str.split(","); -} - -function clampValue(number, min, max) { - return Math.max(min, Math.min(number, max)); -} - -function isValidGradient(colors) { - return isValidHexColor(colors[1]) && isValidHexColor(colors[2]); -} - -function fallbackColor(color, fallbackColor) { - let colors = color.split(","); - let gradient = null; - - if (colors.length > 1 && isValidGradient(colors)) { - gradient = colors; - } - - return ( - (gradient ? gradient : isValidHexColor(color) && `#${color}`) || - fallbackColor - ); -} - -function request(data, headers) { - return axios({ - url: "https://api.github.com/graphql", - method: "post", - headers, - data, - }); -} - -function codeStatsRequest(data) { - return axios({ - url: "https://codestats.net/api/users/" + data.login, - method: "get", - }); -} - -/** - * - * @param {String[]} items - * @param {Number} gap - * @param {string} direction - * - * @description - * Auto layout utility, allows us to layout things - * vertically or horizontally with proper gaping - */ -function FlexLayout({ items, gap, direction }) { - // filter() for filtering out empty strings - return items.filter(Boolean).map((item, i) => { - let transform = `translate(${gap * i}, 0)`; - if (direction === "column") { - transform = `translate(0, ${gap * i})`; - } - return `${item}`; - }); -} - -// returns theme based colors with proper overrides and defaults -function getCardColors({ - title_color, - text_color, - icon_color, - bg_color, - theme, - fallbackTheme = "default", -}) { - const defaultTheme = themes[fallbackTheme]; - const selectedTheme = themes[theme] || defaultTheme; - - // get the color provided by the user else the theme color - // finally if both colors are invalid fallback to default theme - const titleColor = fallbackColor( - title_color || selectedTheme.title_color, - "#" + defaultTheme.title_color - ); - const iconColor = fallbackColor( - icon_color || selectedTheme.icon_color, - "#" + defaultTheme.icon_color - ); - const textColor = fallbackColor( - text_color || selectedTheme.text_color, - "#" + defaultTheme.text_color - ); - const bgColor = fallbackColor( - bg_color || selectedTheme.bg_color, - "#" + defaultTheme.bg_color - ); - - return { titleColor, iconColor, textColor, bgColor }; -} - -function wrapTextMultiline(text, width = 60, maxLines = 3) { - const wrapped = wrap(encodeHTML(text), { width }) - .split("\n") // Split wrapped lines to get an array of lines - .map((line) => line.trim()); // Remove leading and trailing whitespace of each line - - const lines = wrapped.slice(0, maxLines); // Only consider maxLines lines - - // Add "..." to the last line if the text exceeds maxLines - if (wrapped.length > maxLines) { - lines[maxLines - 1] += "..."; - } - - // Remove empty lines if text fits in less than maxLines lines - const multiLineText = lines.filter(Boolean); - return multiLineText; -} - -const noop = () => {}; -// return console instance based on the environment -const logger = - process.env.NODE_ENV !== "test" ? console : { log: noop, error: noop }; - -const CONSTANTS = { - THIRTY_MINUTES: 1800, - TWO_HOURS: 7200, - FOUR_HOURS: 14400, - ONE_DAY: 86400, -}; - -const SECONDARY_ERROR_MESSAGES = { - MAX_RETRY: - "Please add an env variable called PAT_1 with your github token in vercel", - USER_NOT_FOUND: "Make sure the provided username is not an organization", -}; - -class CustomError extends Error { - constructor(message, type) { - super(message); - this.type = type; - this.secondaryMessage = SECONDARY_ERROR_MESSAGES[type] || "adsad"; - } - - static MAX_RETRY = "MAX_RETRY"; - static USER_NOT_FOUND = "USER_NOT_FOUND"; -} - -module.exports = { - renderError, - kFormatter, - encodeHTML, - isValidHexColor, - request, - codeStatsRequest, - parseArray, - parseBoolean, - fallbackColor, - FlexLayout, - getCardColors, - clampValue, - wrapTextMultiline, - logger, - CONSTANTS, - CustomError, -}; diff --git a/src/common/utils.tsx b/src/common/utils.tsx new file mode 100644 index 0000000..4080400 --- /dev/null +++ b/src/common/utils.tsx @@ -0,0 +1,200 @@ +import React from 'react' + +import axios from 'axios' +import wrap from 'word-wrap' +import themes from '../../themes' + +export const renderError = (message: string, secondaryMessage = "") => { + return ( + + + + Something went wrong! file an issue at https://git.io/JJmN9 + + {encodeHTML(message)} + {secondaryMessage} + + + ) +}; + +// https://stackoverflow.com/a/48073476/10629172 +export function encodeHTML(str: string) { + return str + .replace(/[\u00A0-\u9999<>&](?!#)/gim, (i) => { + return "&#" + i.charCodeAt(0) + ";"; + }) + .replace(/\u0008/gim, ""); +} + +export function kFormatter(num: number) { + return Math.abs(num) > 999 + ? Math.sign(num) * (Math.abs(num) / 1000).toFixed(1) + "k" + : Math.sign(num) * Math.abs(num); +} + +export function isValidHexColor(hexColor: string) { + 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); +} + +export function parseBoolean(value: string | undefined) { + if (value === "true") { + return true; + } else { + return false; + } +} + +export function parseArray(str: string | undefined) { + if (!str) return []; + return str.split(","); +} + +export function clampValue(number: number, min: number, max: number) { + return Math.max(min, Math.min(number, max)); +} + +export function isValidGradient(colors: Array) { + return isValidHexColor(colors[1]) && isValidHexColor(colors[2]); +} + +export function fallbackColor(color: string, fallbackColor: Array| string) { + let colors = color.split(","); + let gradient = null; + + if (colors.length > 1 && isValidGradient(colors)) { + gradient = colors; + } + + return ( + (gradient ? gradient : isValidHexColor(color) && `#${color}`) || + fallbackColor + ); +} + +export function request(data?: any, headers?: any) { + return axios({ + url: "https://api.github.com/graphql", + method: "post", + headers, + data, + }); +} + +export function codeStatsRequest(data?: any) { + return axios({ + url: "https://codestats.net/api/users/" + data.login, + method: "get", + }); +} + +/** + * + * @param {String[]} items + * @param {Number} gap + * @param {string} direction + * + * @description + * Auto layout utility, allows us to layout things + * vertically or horizontally with proper gaping + */ +export function FlexLayout({ items, gap, direction }: {items: Array, gap: number, direction?: string}) { + // filter() for filtering out empty strings + return items.filter(Boolean).map((item, i) => { + let transform = `translate(${gap * i}, 0)`; + if (direction === "column") { + transform = `translate(0, ${gap * i})`; + } + return ( + {item} + ); + }); +} + +// returns theme based colors with proper overrides and defaults +export function getCardColors({ + title_color, + text_color, + icon_color, + bg_color, + theme, + fallbackTheme = "default", +}: {title_color?: string, text_color?: string, icon_color?: string, bg_color?: string, theme?: keyof typeof themes, fallbackTheme?: keyof typeof themes}) { + const defaultTheme = themes[fallbackTheme]; + const selectedTheme = themes[theme as 'default'] || defaultTheme; + + // get the color provided by the user else the theme color + // finally if both colors are invalid fallback to default theme + const titleColor = fallbackColor( + title_color || selectedTheme.title_color, + "#" + defaultTheme.title_color + ); + const iconColor = fallbackColor( + icon_color || selectedTheme.icon_color, + "#" + defaultTheme.icon_color + ); + const textColor = fallbackColor( + text_color || selectedTheme.text_color, + "#" + defaultTheme.text_color + ); + const bgColor = fallbackColor( + bg_color || selectedTheme.bg_color, + "#" + defaultTheme.bg_color + ); + + return { titleColor, iconColor, textColor, bgColor }; +} + +export function wrapTextMultiline(text: string, width = 60, maxLines = 3) { + const wrapped = wrap(encodeHTML(text), { width }) + .split("\n") // Split wrapped lines to get an array of lines + .map((line) => line.trim()); // Remove leading and trailing whitespace of each line + + const lines = wrapped.slice(0, maxLines); // Only consider maxLines lines + + // Add "..." to the last line if the text exceeds maxLines + if (wrapped.length > maxLines) { + lines[maxLines - 1] += "..."; + } + + // Remove empty lines if text fits in less than maxLines lines + const multiLineText = lines.filter(Boolean); + return multiLineText; +} + +export const noop = () => {}; +// return console instance based on the environment +export const logger = + process.env.NODE_ENV !== "test" ? console : { log: noop, error: noop }; + +export const CONSTANTS = { + THIRTY_MINUTES: 1800, + TWO_HOURS: 7200, + FOUR_HOURS: 14400, + ONE_DAY: 86400, + LEVEL_FACTOR: 0.025, +}; + +export const SECONDARY_ERROR_MESSAGES = { + MAX_RETRY: + "Please add an env variable called PAT_1 with your github token in vercel", + USER_NOT_FOUND: "Make sure the provided username is not an organization", +}; + +export class CustomError extends Error { + public secondaryMessage: string + + constructor(message: string, public type: keyof typeof SECONDARY_ERROR_MESSAGES) { + super(message); + this.secondaryMessage = SECONDARY_ERROR_MESSAGES[type] || "adsad"; + } + + static MAX_RETRY = "MAX_RETRY"; + static USER_NOT_FOUND = "USER_NOT_FOUND"; +} diff --git a/src/fetchers/repo-fetcher.js b/src/fetchers/repo-fetcher.js deleted file mode 100644 index c04a4cc..0000000 --- a/src/fetchers/repo-fetcher.js +++ /dev/null @@ -1,80 +0,0 @@ -const { request } = require("../common/utils"); -const retryer = require("../common/retryer"); - -const fetcher = (variables, token) => { - return request( - { - query: ` - fragment RepoInfo on Repository { - name - nameWithOwner - isPrivate - isArchived - isTemplate - stargazers { - totalCount - } - description - primaryLanguage { - color - id - name - } - forkCount - } - query getRepo($login: String!, $repo: String!) { - user(login: $login) { - repository(name: $repo) { - ...RepoInfo - } - } - organization(login: $login) { - repository(name: $repo) { - ...RepoInfo - } - } - } - `, - variables, - }, - { - Authorization: `bearer ${token}`, - } - ); -}; - -async function fetchRepo(username, reponame) { - if (!username || !reponame) { - throw new Error("Invalid username or reponame"); - } - - let res = await retryer(fetcher, { login: username, repo: reponame }); - - const data = res.data.data; - - if (!data.user && !data.organization) { - throw new Error("Not found"); - } - - const isUser = data.organization === null && data.user; - const isOrg = data.user === null && data.organization; - - if (isUser) { - if (!data.user.repository || data.user.repository.isPrivate) { - throw new Error("User Repository Not found"); - } - return data.user.repository; - } - - if (isOrg) { - if ( - !data.organization.repository || - data.organization.repository.isPrivate - ) { - throw new Error("Organization Repository Not found"); - } - return data.organization.repository; - } -} - -module.exports = fetchRepo; diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js deleted file mode 100644 index b7cc2af..0000000 --- a/src/fetchers/stats-fetcher.js +++ /dev/null @@ -1,151 +0,0 @@ -const { request, logger, CustomError } = require("../common/utils"); -const axios = require("axios"); -const retryer = require("../common/retryer"); -const calculateRank = require("../calculateRank"); -const githubUsernameRegex = require("github-username-regex"); - -require("dotenv").config(); - -const fetcher = (variables, token) => { - return request( - { - query: ` - query userInfo($login: String!) { - user(login: $login) { - name - login - contributionsCollection { - totalCommitContributions - restrictedContributionsCount - } - repositoriesContributedTo(first: 1, contributionTypes: [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY]) { - totalCount - } - pullRequests(first: 1) { - totalCount - } - issues(first: 1) { - totalCount - } - followers { - totalCount - } - repositories(first: 100, ownerAffiliations: OWNER, isFork: false, orderBy: {direction: DESC, field: STARGAZERS}) { - totalCount - nodes { - stargazers { - totalCount - } - } - } - } - } - `, - variables, - }, - { - Authorization: `bearer ${token}`, - } - ); -}; - -// https://github.com/anuraghazra/github-readme-stats/issues/92#issuecomment-661026467 -// https://github.com/anuraghazra/github-readme-stats/pull/211/ -const totalCommitsFetcher = async (username) => { - if (!githubUsernameRegex.test(username)) { - logger.log("Invalid username"); - return 0; - } - - // https://developer.github.com/v3/search/#search-commits - const fetchTotalCommits = (variables, token) => { - return axios({ - method: "get", - url: `https://api.github.com/search/commits?q=author:${variables.login}`, - headers: { - "Content-Type": "application/json", - Accept: "application/vnd.github.cloak-preview", - Authorization: `bearer ${token}`, - }, - }); - }; - - try { - let res = await retryer(fetchTotalCommits, { login: username }); - if (res.data.total_count) { - return res.data.total_count; - } - } catch (err) { - logger.log(err); - // just return 0 if there is something wrong so that - // we don't break the whole app - return 0; - } -}; - -async function fetchStats( - username, - count_private = false, - include_all_commits = false -) { - if (!username) throw Error("Invalid username"); - - const stats = { - name: "", - totalPRs: 0, - totalCommits: 0, - totalIssues: 0, - totalStars: 0, - contributedTo: 0, - rank: { level: "C", score: 0 }, - }; - - let res = await retryer(fetcher, { login: username }); - - let experimental_totalCommits = 0; - if (include_all_commits) { - experimental_totalCommits = await totalCommitsFetcher(username); - } - - if (res.data.errors) { - logger.error(res.data.errors); - throw new CustomError( - res.data.errors[0].message || "Could not fetch user", - CustomError.USER_NOT_FOUND - ); - } - - const user = res.data.data.user; - const contributionCount = user.contributionsCollection; - - stats.name = user.name || user.login; - stats.totalIssues = user.issues.totalCount; - - stats.totalCommits = - contributionCount.totalCommitContributions + experimental_totalCommits; - - if (count_private) { - stats.totalCommits += contributionCount.restrictedContributionsCount; - } - - stats.totalPRs = user.pullRequests.totalCount; - stats.contributedTo = user.repositoriesContributedTo.totalCount; - - stats.totalStars = user.repositories.nodes.reduce((prev, curr) => { - return prev + curr.stargazers.totalCount; - }, 0); - - stats.rank = calculateRank({ - totalCommits: stats.totalCommits, - totalRepos: user.repositories.totalCount, - followers: user.followers.totalCount, - contributions: stats.contributedTo, - stargazers: stats.totalStars, - prs: stats.totalPRs, - issues: stats.totalIssues, - }); - - return stats; -} - -module.exports = fetchStats; diff --git a/src/fetchers/top-languages-fetcher.js b/src/fetchers/top-languages-fetcher.js deleted file mode 100644 index ce83858..0000000 --- a/src/fetchers/top-languages-fetcher.js +++ /dev/null @@ -1,63 +0,0 @@ -const { codeStatsRequest, logger } = require("../common/utils"); -const retryer = require("../common/retryer"); -const languageColor = require('../../themes/language-bar') -require("dotenv").config(); - -const fetcher = (variables) => { - return codeStatsRequest( - variables - ); -}; - -async function fetchTopLanguages(username) { - if (!username) throw Error("Invalid username"); - - let res = await retryer(fetcher, { login: username }); - - if (res.data.errors) { - logger.error(res.data.errors); - throw Error(res.data.errors[0].message || "Could not fetch user"); - } - - let repoNodes = res.data.languages; - - // Remap nodes - const list = [] - for (const key in repoNodes) { - const item = repoNodes[key] - list.push({ - name: key, - color: languageColor[key] ? languageColor[key].color : '#000000', - xp: item.xps, - recentXp: item.new_xps + item.xps - }) - } - - repoNodes = list - .filter((node) => { - return node.xp > 0; - }) - .sort((a, b) => b.xp - a.xp) - .reduce((acc, prev) => { - return { - ...acc, - [prev.name]: { - name: prev.name, - color: prev.color, - size: prev.xp, - recentSize: prev.recentXp - }, - }; - }, {}); - - const topLangs = Object.keys(repoNodes) - // .slice(0, 5) - .reduce((result, key) => { - result[key] = repoNodes[key]; - return result; - }, {}); - - return topLangs; -} - -module.exports = fetchTopLanguages; diff --git a/src/fetchers/top-languages-fetcher.ts b/src/fetchers/top-languages-fetcher.ts new file mode 100644 index 0000000..cd7614d --- /dev/null +++ b/src/fetchers/top-languages-fetcher.ts @@ -0,0 +1,80 @@ +import { codeStatsRequest, logger, CONSTANTS } from '../common/utils' +import retryer from '../common/retryer' +import languageColor from '../../themes/language-bar.json' + +const fetcher = (variables: any) => { + return codeStatsRequest( + variables + ); +}; + +interface response { + user: string + total_xp: number + new_xp: number + machines: Record + languages: Record + dates: Record +} + +export interface data { + name: string + size: number + color: string + recentSize: number +} + +async function fetchTopLanguages(username: string) { + if (!username) throw Error("Invalid username"); + + let res: {data: response} = await retryer(fetcher, { login: username }); + + let repoNodes = res.data.languages; + + // Remap nodes + const list = [] + for (const key in repoNodes) { + const item = repoNodes[key] + list.push({ + name: key, + color: key in languageColor ? languageColor[key as keyof typeof languageColor].color || '#000000' : '#000000', + xp: item.xps, + recentXp: item.new_xps + item.xps, + lvl: Math.trunc(Math.floor(CONSTANTS.LEVEL_FACTOR * Math.sqrt(item.xps))) + }) + } + + repoNodes = list + .filter((node) => { + return node.xp > 0; + }) + .sort((a, b) => b.xp - a.xp) + .reduce((acc, prev) => { + return { + ...acc, + [prev.name]: { + name: prev.name, + color: prev.color, + size: prev.xp, + recentSize: prev.recentXp + }, + }; + }, {}); + + const topLangs = Object.keys(repoNodes) + // .slice(0, 5) + .reduce((result: Record, key) => { + result[key] = repoNodes[key]; + return result; + }, {}); + + return topLangs as Record +} + +export default fetchTopLanguages diff --git a/src/getStyles.js b/src/getStyles.js deleted file mode 100644 index b15f46d..0000000 --- a/src/getStyles.js +++ /dev/null @@ -1,94 +0,0 @@ -const calculateCircleProgress = (value) => { - let radius = 40; - let c = Math.PI * (radius * 2); - - if (value < 0) value = 0; - if (value > 100) value = 100; - - let percentage = ((100 - value) / 100) * c; - return percentage; -}; - -const getProgressAnimation = ({ progress }) => { - return ` - @keyframes rankAnimation { - from { - stroke-dashoffset: ${calculateCircleProgress(0)}; - } - to { - stroke-dashoffset: ${calculateCircleProgress(progress)}; - } - } - `; -}; - -const getAnimations = () => { - return ` - /* Animations */ - @keyframes scaleInAnimation { - from { - transform: translate(-5px, 5px) scale(0); - } - to { - transform: translate(-5px, 5px) scale(1); - } - } - @keyframes fadeInAnimation { - from { - opacity: 0; - } - to { - opacity: 1; - } - } - `; -}; - -const getStyles = ({ - titleColor, - textColor, - iconColor, - show_icons, - progress, -}) => { - return ` - .stat { - font: 600 14px 'Segoe UI', Ubuntu, "Helvetica Neue", Sans-Serif; fill: ${textColor}; - } - .stagger { - opacity: 0; - animation: fadeInAnimation 0.3s ease-in-out forwards; - } - .rank-text { - font: 800 24px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor}; - animation: scaleInAnimation 0.3s ease-in-out forwards; - } - - .bold { font-weight: 700 } - .icon { - fill: ${iconColor}; - display: ${!!show_icons ? "block" : "none"}; - } - - .rank-circle-rim { - stroke: ${titleColor}; - fill: none; - stroke-width: 6; - opacity: 0.2; - } - .rank-circle { - stroke: ${titleColor}; - stroke-dasharray: 250; - fill: none; - stroke-width: 6; - stroke-linecap: round; - opacity: 0.8; - transform-origin: -10px 8px; - transform: rotate(-90deg); - animation: rankAnimation 1s forwards ease-in-out; - } - ${process.env.NODE_ENV === "test" ? "" : getProgressAnimation({ progress })} - `; -}; - -module.exports = { getStyles, getAnimations }; diff --git a/src/getStyles.ts b/src/getStyles.ts new file mode 100644 index 0000000..eed9eea --- /dev/null +++ b/src/getStyles.ts @@ -0,0 +1,92 @@ +const calculateCircleProgress = (value: number) => { + let radius = 40; + let c = Math.PI * (radius * 2); + + if (value < 0) value = 0; + if (value > 100) value = 100; + + let percentage = ((100 - value) / 100) * c; + return percentage; +}; + +const getProgressAnimation = ({ progress }: {progress: number}) => { + return ` + @keyframes rankAnimation { + from { + stroke-dashoffset: ${calculateCircleProgress(0)}; + } + to { + stroke-dashoffset: ${calculateCircleProgress(progress)}; + } + } + `; +}; + +export const getAnimations = () => { + return ` + /* Animations */ + @keyframes scaleInAnimation { + from { + transform: translate(-5px, 5px) scale(0); + } + to { + transform: translate(-5px, 5px) scale(1); + } + } + @keyframes fadeInAnimation { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + `; +}; + +// export const getStyles = ({ +// titleColor, +// textColor, +// iconColor, +// show_icons, +// progress, +// }) => { +// return ` +// .stat { +// font: 600 14px 'Segoe UI', Ubuntu, "Helvetica Neue", Sans-Serif; fill: ${textColor}; +// } +// .stagger { +// opacity: 0; +// animation: fadeInAnimation 0.3s ease-in-out forwards; +// } +// .rank-text { +// font: 800 24px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor}; +// animation: scaleInAnimation 0.3s ease-in-out forwards; +// } + +// .bold { font-weight: 700 } +// .icon { +// fill: ${iconColor}; +// display: ${!!show_icons ? "block" : "none"}; +// } + +// .rank-circle-rim { +// stroke: ${titleColor}; +// fill: none; +// stroke-width: 6; +// opacity: 0.2; +// } +// .rank-circle { +// stroke: ${titleColor}; +// stroke-dasharray: 250; +// fill: none; +// stroke-width: 6; +// stroke-linecap: round; +// opacity: 0.8; +// transform-origin: -10px 8px; +// transform: rotate(-90deg); +// animation: rankAnimation 1s forwards ease-in-out; +// } +// ${process.env.NODE_ENV === "test" ? "" : getProgressAnimation({ progress })} +// `; +// }; diff --git a/tests/api.test.js b/tests/api.test.js deleted file mode 100644 index e48d3df..0000000 --- a/tests/api.test.js +++ /dev/null @@ -1,224 +0,0 @@ -require("@testing-library/jest-dom"); -const axios = require("axios"); -const MockAdapter = require("axios-mock-adapter"); -const api = require("../api/index"); -const renderStatsCard = require("../src/cards/stats-card"); -const { renderError, CONSTANTS } = require("../src/common/utils"); -const calculateRank = require("../src/calculateRank"); - -const stats = { - name: "Anurag Hazra", - totalStars: 100, - totalCommits: 200, - totalIssues: 300, - totalPRs: 400, - contributedTo: 500, - rank: null, -}; -stats.rank = calculateRank({ - totalCommits: stats.totalCommits, - totalRepos: 1, - followers: 0, - contributions: stats.contributedTo, - stargazers: stats.totalStars, - prs: stats.totalPRs, - issues: stats.totalIssues, -}); - -const data = { - data: { - user: { - name: stats.name, - repositoriesContributedTo: { totalCount: stats.contributedTo }, - contributionsCollection: { - totalCommitContributions: stats.totalCommits, - restrictedContributionsCount: 100, - }, - pullRequests: { totalCount: stats.totalPRs }, - issues: { totalCount: stats.totalIssues }, - followers: { totalCount: 0 }, - repositories: { - totalCount: 1, - nodes: [{ stargazers: { totalCount: 100 } }], - }, - }, - }, -}; - -const error = { - errors: [ - { - type: "NOT_FOUND", - path: ["user"], - locations: [], - message: "Could not fetch user", - }, - ], -}; - -const mock = new MockAdapter(axios); - -const faker = (query, data) => { - const req = { - query: { - username: "anuraghazra", - ...query, - }, - }; - const res = { - setHeader: jest.fn(), - send: jest.fn(), - }; - mock.onPost("https://api.github.com/graphql").reply(200, data); - - return { req, res }; -}; - -afterEach(() => { - mock.reset(); -}); - -describe("Test /api/", () => { - it("should test the request", async () => { - const { req, res } = faker({}, data); - - await api(req, res); - - expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); - expect(res.send).toBeCalledWith(renderStatsCard(stats, { ...req.query })); - }); - - it("should render error card on error", async () => { - const { req, res } = faker({}, error); - - await api(req, res); - - expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); - expect(res.send).toBeCalledWith( - renderError( - error.errors[0].message, - "Make sure the provided username is not an organization" - ) - ); - }); - - it("should get the query options", async () => { - const { req, res } = faker( - { - username: "anuraghazra", - hide: "issues,prs,contribs", - show_icons: true, - hide_border: true, - line_height: 100, - title_color: "fff", - icon_color: "fff", - text_color: "fff", - bg_color: "fff", - }, - data - ); - - await api(req, res); - - expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); - expect(res.send).toBeCalledWith( - renderStatsCard(stats, { - hide: ["issues", "prs", "contribs"], - show_icons: true, - hide_border: true, - line_height: 100, - title_color: "fff", - icon_color: "fff", - text_color: "fff", - bg_color: "fff", - }) - ); - }); - - it("should have proper cache", async () => { - const { req, res } = faker({}, data); - mock.onPost("https://api.github.com/graphql").reply(200, data); - - await api(req, res); - - expect(res.setHeader.mock.calls).toEqual([ - ["Content-Type", "image/svg+xml"], - ["Cache-Control", `public, max-age=${CONSTANTS.TWO_HOURS}`], - ]); - }); - - it("should set proper cache", async () => { - const { req, res } = faker({ cache_seconds: 8000 }, data); - await api(req, res); - - expect(res.setHeader.mock.calls).toEqual([ - ["Content-Type", "image/svg+xml"], - ["Cache-Control", `public, max-age=${8000}`], - ]); - }); - - it("should set proper cache with clamped values", async () => { - { - let { req, res } = faker({ cache_seconds: 200000 }, data); - await api(req, res); - - expect(res.setHeader.mock.calls).toEqual([ - ["Content-Type", "image/svg+xml"], - ["Cache-Control", `public, max-age=${CONSTANTS.ONE_DAY}`], - ]); - } - - // note i'm using block scoped vars - { - let { req, res } = faker({ cache_seconds: 0 }, data); - await api(req, res); - - expect(res.setHeader.mock.calls).toEqual([ - ["Content-Type", "image/svg+xml"], - ["Cache-Control", `public, max-age=${CONSTANTS.TWO_HOURS}`], - ]); - } - - { - let { req, res } = faker({ cache_seconds: -10000 }, data); - await api(req, res); - - expect(res.setHeader.mock.calls).toEqual([ - ["Content-Type", "image/svg+xml"], - ["Cache-Control", `public, max-age=${CONSTANTS.TWO_HOURS}`], - ]); - } - }); - - it("should add private contributions", async () => { - const { req, res } = faker( - { - username: "anuraghazra", - count_private: true, - }, - data - ); - - await api(req, res); - - expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); - expect(res.send).toBeCalledWith( - renderStatsCard( - { - ...stats, - totalCommits: stats.totalCommits + 100, - rank: calculateRank({ - totalCommits: stats.totalCommits + 100, - totalRepos: 1, - followers: 0, - contributions: stats.contributedTo, - stargazers: stats.totalStars, - prs: stats.totalPRs, - issues: stats.totalIssues, - }), - }, - {} - ) - ); - }); -}); diff --git a/tests/calculateRank.test.js b/tests/calculateRank.test.js deleted file mode 100644 index 52bb368..0000000 --- a/tests/calculateRank.test.js +++ /dev/null @@ -1,18 +0,0 @@ -require("@testing-library/jest-dom"); -const calculateRank = require("../src/calculateRank"); - -describe("Test calculateRank", () => { - it("should calculate rank correctly", () => { - expect( - calculateRank({ - totalCommits: 100, - totalRepos: 5, - followers: 100, - contributions: 61, - stargazers: 400, - prs: 300, - issues: 200, - }) - ).toStrictEqual({ level: "A+", score: 49.16605417270399 }); - }); -}); diff --git a/tests/card.test.js b/tests/card.test.js deleted file mode 100644 index bcaae7e..0000000 --- a/tests/card.test.js +++ /dev/null @@ -1,173 +0,0 @@ -require("@testing-library/jest-dom"); -const cssToObject = require("css-to-object"); -const Card = require("../src/common/Card"); -const icons = require("../src/common/icons"); -const { getCardColors } = require("../src/common/utils"); -const { queryByTestId } = require("@testing-library/dom"); - -describe("Card", () => { - it("should hide border", () => { - const card = new Card({}); - card.setHideBorder(true); - - document.body.innerHTML = card.render(``); - expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( - "stroke-opacity", - "0" - ); - }); - - it("should not hide border", () => { - const card = new Card({}); - card.setHideBorder(false); - - document.body.innerHTML = card.render(``); - expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( - "stroke-opacity", - "1" - ); - }); - - it("should hide title", () => { - const card = new Card({}); - card.setHideTitle(true); - - document.body.innerHTML = card.render(``); - expect(queryByTestId(document.body, "card-title")).toBeNull(); - }); - - it("should not hide title", () => { - const card = new Card({}); - card.setHideTitle(false); - - document.body.innerHTML = card.render(``); - expect(queryByTestId(document.body, "card-title")).toBeInTheDocument(); - }); - - it("title should have prefix icon", () => { - const card = new Card({ title: "ok", titlePrefixIcon: icons.contribs }); - - document.body.innerHTML = card.render(``); - expect(document.getElementsByClassName("icon")[0]).toBeInTheDocument(); - }); - - it("title should not have prefix icon", () => { - const card = new Card({ title: "ok" }); - - document.body.innerHTML = card.render(``); - expect(document.getElementsByClassName("icon")[0]).toBeUndefined(); - }); - - it("should have proper height, width", () => { - const card = new Card({ height: 200, width: 200, title: "ok" }); - document.body.innerHTML = card.render(``); - expect(document.getElementsByTagName("svg")[0]).toHaveAttribute( - "height", - "200" - ); - expect(document.getElementsByTagName("svg")[0]).toHaveAttribute( - "height", - "200" - ); - }); - - it("should have less height after title is hidden", () => { - const card = new Card({ height: 200, title: "ok" }); - card.setHideTitle(true); - - document.body.innerHTML = card.render(``); - expect(document.getElementsByTagName("svg")[0]).toHaveAttribute( - "height", - "170" - ); - }); - - it("main-card-body should have proper when title is visible", () => { - const card = new Card({ height: 200 }); - document.body.innerHTML = card.render(``); - expect(queryByTestId(document.body, "main-card-body")).toHaveAttribute( - "transform", - "translate(0, 55)" - ); - }); - - it("main-card-body should have proper position after title is hidden", () => { - const card = new Card({ height: 200 }); - card.setHideTitle(true); - - document.body.innerHTML = card.render(``); - expect(queryByTestId(document.body, "main-card-body")).toHaveAttribute( - "transform", - "translate(0, 25)" - ); - }); - - it("should render with correct colors", () => { - // returns theme based colors with proper overrides and defaults - const { titleColor, textColor, iconColor, bgColor } = getCardColors({ - title_color: "f00", - icon_color: "0f0", - text_color: "00f", - bg_color: "fff", - theme: "default", - }); - - const card = new Card({ - height: 200, - colors: { - titleColor, - textColor, - iconColor, - bgColor, - }, - }); - document.body.innerHTML = card.render(``); - - const styleTag = document.querySelector("style"); - const stylesObject = cssToObject(styleTag.innerHTML); - const headerClassStyles = stylesObject[".header"]; - - expect(headerClassStyles.fill).toBe("#f00"); - expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( - "fill", - "#fff" - ); - }); - it("should render gradient backgrounds", () => { - const { titleColor, textColor, iconColor, bgColor } = getCardColors({ - title_color: "f00", - icon_color: "0f0", - text_color: "00f", - bg_color: "90,fff,000,f00", - theme: "default", - }); - - const card = new Card({ - height: 200, - colors: { - titleColor, - textColor, - iconColor, - bgColor, - }, - }); - document.body.innerHTML = card.render(``); - expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( - "fill", - "url(#gradient)" - ); - expect(document.querySelector("defs linearGradient")).toHaveAttribute( - "gradientTransform", - "rotate(90)" - ); - expect( - document.querySelector("defs linearGradient stop:nth-child(1)") - ).toHaveAttribute("stop-color", "#fff"); - expect( - document.querySelector("defs linearGradient stop:nth-child(2)") - ).toHaveAttribute("stop-color", "#000"); - expect( - document.querySelector("defs linearGradient stop:nth-child(3)") - ).toHaveAttribute("stop-color", "#f00"); - }); -}); diff --git a/tests/fetchRepo.test.js b/tests/fetchRepo.test.js deleted file mode 100644 index dec4012..0000000 --- a/tests/fetchRepo.test.js +++ /dev/null @@ -1,96 +0,0 @@ -require("@testing-library/jest-dom"); -const axios = require("axios"); -const MockAdapter = require("axios-mock-adapter"); -const fetchRepo = require("../src/fetchers/repo-fetcher"); - -const data_repo = { - repository: { - name: "convoychat", - stargazers: { totalCount: 38000 }, - description: "Help us take over the world! React + TS + GraphQL Chat App", - primaryLanguage: { - color: "#2b7489", - id: "MDg6TGFuZ3VhZ2UyODc=", - name: "TypeScript", - }, - forkCount: 100, - }, -}; - -const data_user = { - data: { - user: { repository: data_repo }, - organization: null, - }, -}; -const data_org = { - data: { - user: null, - organization: { repository: data_repo }, - }, -}; - -const mock = new MockAdapter(axios); - -afterEach(() => { - mock.reset(); -}); - -describe("Test fetchRepo", () => { - it("should fetch correct user repo", async () => { - mock.onPost("https://api.github.com/graphql").reply(200, data_user); - - let repo = await fetchRepo("anuraghazra", "convoychat"); - expect(repo).toStrictEqual(data_repo); - }); - - it("should fetch correct org repo", async () => { - mock.onPost("https://api.github.com/graphql").reply(200, data_org); - - let repo = await fetchRepo("anuraghazra", "convoychat"); - expect(repo).toStrictEqual(data_repo); - }); - - it("should throw error if user is found but repo is null", async () => { - mock - .onPost("https://api.github.com/graphql") - .reply(200, { data: { user: { repository: null }, organization: null } }); - - await expect(fetchRepo("anuraghazra", "convoychat")).rejects.toThrow( - "User Repository Not found" - ); - }); - - it("should throw error if org is found but repo is null", async () => { - mock - .onPost("https://api.github.com/graphql") - .reply(200, { data: { user: null, organization: { repository: null } } }); - - await expect(fetchRepo("anuraghazra", "convoychat")).rejects.toThrow( - "Organization Repository Not found" - ); - }); - - it("should throw error if both user & org data not found", async () => { - mock - .onPost("https://api.github.com/graphql") - .reply(200, { data: { user: null, organization: null } }); - - await expect(fetchRepo("anuraghazra", "convoychat")).rejects.toThrow( - "Not found" - ); - }); - - it("should throw error if repository is private", async () => { - mock.onPost("https://api.github.com/graphql").reply(200, { - data: { - user: { repository: { ...data_repo, isPrivate: true } }, - organization: null, - }, - }); - - await expect(fetchRepo("anuraghazra", "convoychat")).rejects.toThrow( - "User Repository Not found" - ); - }); -}); diff --git a/tests/fetchStats.test.js b/tests/fetchStats.test.js deleted file mode 100644 index 0714578..0000000 --- a/tests/fetchStats.test.js +++ /dev/null @@ -1,136 +0,0 @@ -require("@testing-library/jest-dom"); -const axios = require("axios"); -const MockAdapter = require("axios-mock-adapter"); -const fetchStats = require("../src/fetchers/stats-fetcher"); -const calculateRank = require("../src/calculateRank"); - -const data = { - data: { - user: { - name: "Anurag Hazra", - repositoriesContributedTo: { totalCount: 61 }, - contributionsCollection: { - totalCommitContributions: 100, - restrictedContributionsCount: 50, - }, - pullRequests: { totalCount: 300 }, - issues: { totalCount: 200 }, - followers: { totalCount: 100 }, - repositories: { - totalCount: 5, - nodes: [ - { stargazers: { totalCount: 100 } }, - { stargazers: { totalCount: 100 } }, - { stargazers: { totalCount: 100 } }, - { stargazers: { totalCount: 50 } }, - { stargazers: { totalCount: 50 } }, - ], - }, - }, - }, -}; - -const error = { - errors: [ - { - type: "NOT_FOUND", - path: ["user"], - locations: [], - message: "Could not resolve to a User with the login of 'noname'.", - }, - ], -}; - -const mock = new MockAdapter(axios); - -afterEach(() => { - mock.reset(); -}); - -describe("Test fetchStats", () => { - it("should fetch correct stats", async () => { - mock.onPost("https://api.github.com/graphql").reply(200, data); - - let stats = await fetchStats("anuraghazra"); - const rank = calculateRank({ - totalCommits: 100, - totalRepos: 5, - followers: 100, - contributions: 61, - stargazers: 400, - prs: 300, - issues: 200, - }); - - expect(stats).toStrictEqual({ - contributedTo: 61, - name: "Anurag Hazra", - totalCommits: 100, - totalIssues: 200, - totalPRs: 300, - totalStars: 400, - rank, - }); - }); - - it("should throw error", async () => { - mock.onPost("https://api.github.com/graphql").reply(200, error); - - await expect(fetchStats("anuraghazra")).rejects.toThrow( - "Could not resolve to a User with the login of 'noname'." - ); - }); - - it("should fetch and add private contributions", async () => { - mock.onPost("https://api.github.com/graphql").reply(200, data); - - let stats = await fetchStats("anuraghazra", true); - const rank = calculateRank({ - totalCommits: 150, - totalRepos: 5, - followers: 100, - contributions: 61, - stargazers: 400, - prs: 300, - issues: 200, - }); - - expect(stats).toStrictEqual({ - contributedTo: 61, - name: "Anurag Hazra", - totalCommits: 150, - totalIssues: 200, - totalPRs: 300, - totalStars: 400, - rank, - }); - }); - - it("should fetch total commits", async () => { - mock.onPost("https://api.github.com/graphql").reply(200, data); - mock - .onGet("https://api.github.com/search/commits?q=author:anuraghazra") - .reply(200, { total_count: 1000 }); - - let stats = await fetchStats("anuraghazra", true, true); - const rank = calculateRank({ - totalCommits: 1000 + 150, - totalRepos: 5, - followers: 100, - contributions: 61, - stargazers: 400, - prs: 300, - issues: 200, - }); - - expect(stats).toStrictEqual({ - contributedTo: 61, - name: "Anurag Hazra", - totalCommits: 1000 + 150, - totalIssues: 200, - totalPRs: 300, - totalStars: 400, - rank, - }); - }); -}); diff --git a/tests/pin.test.js b/tests/pin.test.js deleted file mode 100644 index a85baf3..0000000 --- a/tests/pin.test.js +++ /dev/null @@ -1,126 +0,0 @@ -require("@testing-library/jest-dom"); -const axios = require("axios"); -const MockAdapter = require("axios-mock-adapter"); -const pin = require("../api/pin"); -const renderRepoCard = require("../src/cards/repo-card"); -const { renderError } = require("../src/common/utils"); - -const data_repo = { - repository: { - username: "anuraghazra", - name: "convoychat", - stargazers: { totalCount: 38000 }, - description: "Help us take over the world! React + TS + GraphQL Chat App", - primaryLanguage: { - color: "#2b7489", - id: "MDg6TGFuZ3VhZ2UyODc=", - name: "TypeScript", - }, - forkCount: 100, - isTemplate: false, - }, -}; - -const data_user = { - data: { - user: { repository: data_repo.repository }, - organization: null, - }, -}; - -const mock = new MockAdapter(axios); - -afterEach(() => { - mock.reset(); -}); - -describe("Test /api/pin", () => { - it("should test the request", async () => { - const req = { - query: { - username: "anuraghazra", - repo: "convoychat", - }, - }; - const res = { - setHeader: jest.fn(), - send: jest.fn(), - }; - mock.onPost("https://api.github.com/graphql").reply(200, data_user); - - await pin(req, res); - - expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); - expect(res.send).toBeCalledWith(renderRepoCard(data_repo.repository)); - }); - - it("should get the query options", async () => { - const req = { - query: { - username: "anuraghazra", - repo: "convoychat", - title_color: "fff", - icon_color: "fff", - text_color: "fff", - bg_color: "fff", - full_name: "1", - }, - }; - const res = { - setHeader: jest.fn(), - send: jest.fn(), - }; - mock.onPost("https://api.github.com/graphql").reply(200, data_user); - - await pin(req, res); - - expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); - expect(res.send).toBeCalledWith( - renderRepoCard(data_repo.repository, { ...req.query }) - ); - }); - - it("should render error card if user repo not found", async () => { - const req = { - query: { - username: "anuraghazra", - repo: "convoychat", - }, - }; - const res = { - setHeader: jest.fn(), - send: jest.fn(), - }; - mock - .onPost("https://api.github.com/graphql") - .reply(200, { data: { user: { repository: null }, organization: null } }); - - await pin(req, res); - - expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); - expect(res.send).toBeCalledWith(renderError("User Repository Not found")); - }); - - it("should render error card if org repo not found", async () => { - const req = { - query: { - username: "anuraghazra", - repo: "convoychat", - }, - }; - const res = { - setHeader: jest.fn(), - send: jest.fn(), - }; - mock - .onPost("https://api.github.com/graphql") - .reply(200, { data: { user: null, organization: { repository: null } } }); - - await pin(req, res); - - expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); - expect(res.send).toBeCalledWith( - renderError("Organization Repository Not found") - ); - }); -}); diff --git a/tests/renderRepoCard.test.js b/tests/renderRepoCard.test.js deleted file mode 100644 index 1d0d6cc..0000000 --- a/tests/renderRepoCard.test.js +++ /dev/null @@ -1,310 +0,0 @@ -require("@testing-library/jest-dom"); -const cssToObject = require("css-to-object"); -const renderRepoCard = require("../src/cards/repo-card"); - -const { queryByTestId } = require("@testing-library/dom"); -const themes = require("../themes"); - -const data_repo = { - repository: { - nameWithOwner: "anuraghazra/convoychat", - name: "convoychat", - stargazers: { totalCount: 38000 }, - description: "Help us take over the world! React + TS + GraphQL Chat App", - primaryLanguage: { - color: "#2b7489", - id: "MDg6TGFuZ3VhZ2UyODc=", - name: "TypeScript", - }, - forkCount: 100, - }, -}; - -describe("Test renderRepoCard", () => { - it("should render correctly", () => { - document.body.innerHTML = renderRepoCard(data_repo.repository); - - const [header] = document.getElementsByClassName("header"); - - expect(header).toHaveTextContent("convoychat"); - expect(header).not.toHaveTextContent("anuraghazra"); - expect(document.getElementsByClassName("description")[0]).toHaveTextContent( - "Help us take over the world! React + TS + GraphQL Chat App" - ); - expect(queryByTestId(document.body, "stargazers")).toHaveTextContent("38k"); - expect(queryByTestId(document.body, "forkcount")).toHaveTextContent("100"); - expect(queryByTestId(document.body, "lang-name")).toHaveTextContent( - "TypeScript" - ); - expect(queryByTestId(document.body, "lang-color")).toHaveAttribute( - "fill", - "#2b7489" - ); - }); - - it("should display username in title (full repo name)", () => { - document.body.innerHTML = renderRepoCard(data_repo.repository, { - show_owner: true, - }); - expect(document.getElementsByClassName("header")[0]).toHaveTextContent( - "anuraghazra/convoychat" - ); - }); - - it("should trim description", () => { - document.body.innerHTML = renderRepoCard({ - ...data_repo.repository, - description: - "The quick brown fox jumps over the lazy dog is an English-language pangram—a sentence that contains all of the letters of the English alphabet", - }); - - expect( - document.getElementsByClassName("description")[0].children[0].textContent - ).toBe("The quick brown fox jumps over the lazy dog is an"); - - expect( - document.getElementsByClassName("description")[0].children[1].textContent - ).toBe("English-language pangram—a sentence that contains all"); - - // Should not trim - document.body.innerHTML = renderRepoCard({ - ...data_repo.repository, - description: "Small text should not trim", - }); - - expect(document.getElementsByClassName("description")[0]).toHaveTextContent( - "Small text should not trim" - ); - }); - - it("should render emojis", () => { - document.body.innerHTML = renderRepoCard({ - ...data_repo.repository, - description: "This is a text with a :poop: poo emoji", - }); - - // poop emoji may not show in all editors but it's there between "a" and "poo" - expect(document.getElementsByClassName("description")[0]).toHaveTextContent( - "This is a text with a 💩 poo emoji" - ); - }); - - it("should shift the text position depending on language length", () => { - document.body.innerHTML = renderRepoCard({ - ...data_repo.repository, - primaryLanguage: { - ...data_repo.repository.primaryLanguage, - name: "Jupyter Notebook", - }, - }); - - expect(queryByTestId(document.body, "primary-lang")).toBeInTheDocument(); - expect(queryByTestId(document.body, "star-fork-group")).toHaveAttribute( - "transform", - "translate(155, 0)" - ); - - // Small lang - document.body.innerHTML = renderRepoCard({ - ...data_repo.repository, - primaryLanguage: { - ...data_repo.repository.primaryLanguage, - name: "Ruby", - }, - }); - - expect(queryByTestId(document.body, "star-fork-group")).toHaveAttribute( - "transform", - "translate(125, 0)" - ); - }); - - it("should hide language if primaryLanguage is null & fallback to correct values", () => { - document.body.innerHTML = renderRepoCard({ - ...data_repo.repository, - primaryLanguage: null, - }); - - expect(queryByTestId(document.body, "primary-lang")).toBeNull(); - - document.body.innerHTML = renderRepoCard({ - ...data_repo.repository, - primaryLanguage: { color: null, name: null }, - }); - - expect(queryByTestId(document.body, "primary-lang")).toBeInTheDocument(); - expect(queryByTestId(document.body, "lang-color")).toHaveAttribute( - "fill", - "#333" - ); - - expect(queryByTestId(document.body, "lang-name")).toHaveTextContent( - "Unspecified" - ); - }); - - it("should render default colors properly", () => { - document.body.innerHTML = renderRepoCard(data_repo.repository); - - const styleTag = document.querySelector("style"); - const stylesObject = cssToObject(styleTag.innerHTML); - - const headerClassStyles = stylesObject[".header"]; - const descClassStyles = stylesObject[".description"]; - const iconClassStyles = stylesObject[".icon"]; - - expect(headerClassStyles.fill).toBe("#2f80ed"); - expect(descClassStyles.fill).toBe("#333"); - expect(iconClassStyles.fill).toBe("#586069"); - expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( - "fill", - "#fffefe" - ); - }); - - it("should render custom colors properly", () => { - const customColors = { - title_color: "5a0", - icon_color: "1b998b", - text_color: "9991", - bg_color: "252525", - }; - - document.body.innerHTML = renderRepoCard(data_repo.repository, { - ...customColors, - }); - - const styleTag = document.querySelector("style"); - const stylesObject = cssToObject(styleTag.innerHTML); - - const headerClassStyles = stylesObject[".header"]; - const descClassStyles = stylesObject[".description"]; - const iconClassStyles = stylesObject[".icon"]; - - expect(headerClassStyles.fill).toBe(`#${customColors.title_color}`); - expect(descClassStyles.fill).toBe(`#${customColors.text_color}`); - expect(iconClassStyles.fill).toBe(`#${customColors.icon_color}`); - expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( - "fill", - "#252525" - ); - }); - - it("should render with all the themes", () => { - Object.keys(themes).forEach((name) => { - document.body.innerHTML = renderRepoCard(data_repo.repository, { - theme: name, - }); - - const styleTag = document.querySelector("style"); - const stylesObject = cssToObject(styleTag.innerHTML); - - const headerClassStyles = stylesObject[".header"]; - const descClassStyles = stylesObject[".description"]; - const iconClassStyles = stylesObject[".icon"]; - - expect(headerClassStyles.fill).toBe(`#${themes[name].title_color}`); - expect(descClassStyles.fill).toBe(`#${themes[name].text_color}`); - expect(iconClassStyles.fill).toBe(`#${themes[name].icon_color}`); - expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( - "fill", - `#${themes[name].bg_color}` - ); - }); - }); - - it("should render custom colors with themes", () => { - document.body.innerHTML = renderRepoCard(data_repo.repository, { - title_color: "5a0", - theme: "radical", - }); - - const styleTag = document.querySelector("style"); - const stylesObject = cssToObject(styleTag.innerHTML); - - const headerClassStyles = stylesObject[".header"]; - const descClassStyles = stylesObject[".description"]; - const iconClassStyles = stylesObject[".icon"]; - - expect(headerClassStyles.fill).toBe("#5a0"); - expect(descClassStyles.fill).toBe(`#${themes.radical.text_color}`); - expect(iconClassStyles.fill).toBe(`#${themes.radical.icon_color}`); - expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( - "fill", - `#${themes.radical.bg_color}` - ); - }); - - it("should render custom colors with themes and fallback to default colors if invalid", () => { - document.body.innerHTML = renderRepoCard(data_repo.repository, { - title_color: "invalid color", - text_color: "invalid color", - theme: "radical", - }); - - const styleTag = document.querySelector("style"); - const stylesObject = cssToObject(styleTag.innerHTML); - - const headerClassStyles = stylesObject[".header"]; - const descClassStyles = stylesObject[".description"]; - const iconClassStyles = stylesObject[".icon"]; - - expect(headerClassStyles.fill).toBe(`#${themes.default.title_color}`); - expect(descClassStyles.fill).toBe(`#${themes.default.text_color}`); - expect(iconClassStyles.fill).toBe(`#${themes.radical.icon_color}`); - expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( - "fill", - `#${themes.radical.bg_color}` - ); - }); - - it("should not render star count or fork count if either of the are zero", () => { - document.body.innerHTML = renderRepoCard({ - ...data_repo.repository, - stargazers: { totalCount: 0 }, - }); - - expect(queryByTestId(document.body, "stargazers")).toBeNull(); - expect(queryByTestId(document.body, "forkcount")).toBeInTheDocument(); - - document.body.innerHTML = renderRepoCard({ - ...data_repo.repository, - stargazers: { totalCount: 1 }, - forkCount: 0, - }); - - expect(queryByTestId(document.body, "stargazers")).toBeInTheDocument(); - expect(queryByTestId(document.body, "forkcount")).toBeNull(); - - document.body.innerHTML = renderRepoCard({ - ...data_repo.repository, - stargazers: { totalCount: 0 }, - forkCount: 0, - }); - - expect(queryByTestId(document.body, "stargazers")).toBeNull(); - expect(queryByTestId(document.body, "forkcount")).toBeNull(); - }); - - it("should render badges", () => { - document.body.innerHTML = renderRepoCard({ - ...data_repo.repository, - isArchived: true, - }); - - expect(queryByTestId(document.body, "badge")).toHaveTextContent("Archived"); - - document.body.innerHTML = renderRepoCard({ - ...data_repo.repository, - isTemplate: true, - }); - expect(queryByTestId(document.body, "badge")).toHaveTextContent("Template"); - }); - - it("should not render template", () => { - document.body.innerHTML = renderRepoCard({ - ...data_repo.repository, - }); - expect(queryByTestId(document.body, "badge")).toBeNull(); - }); -}); diff --git a/tests/renderStatsCard.test.js b/tests/renderStatsCard.test.js deleted file mode 100644 index ed04dd1..0000000 --- a/tests/renderStatsCard.test.js +++ /dev/null @@ -1,212 +0,0 @@ -require("@testing-library/jest-dom"); -const cssToObject = require("css-to-object"); -const renderStatsCard = require("../src/cards/stats-card"); - -const { - getByTestId, - queryByTestId, - queryAllByTestId, -} = require("@testing-library/dom"); -const themes = require("../themes"); - -describe("Test renderStatsCard", () => { - const stats = { - name: "Anurag Hazra", - totalStars: 100, - totalCommits: 200, - totalIssues: 300, - totalPRs: 400, - contributedTo: 500, - rank: { level: "A+", score: 40 }, - }; - - it("should render correctly", () => { - document.body.innerHTML = renderStatsCard(stats); - - expect(document.getElementsByClassName("header")[0].textContent).toBe( - "Anurag Hazra's GitHub Stats" - ); - - expect( - document.body.getElementsByTagName("svg")[0].getAttribute("height") - ).toBe("195"); - expect(getByTestId(document.body, "stars").textContent).toBe("100"); - expect(getByTestId(document.body, "commits").textContent).toBe("200"); - expect(getByTestId(document.body, "issues").textContent).toBe("300"); - expect(getByTestId(document.body, "prs").textContent).toBe("400"); - expect(getByTestId(document.body, "contribs").textContent).toBe("500"); - expect(queryByTestId(document.body, "card-bg")).toBeInTheDocument(); - expect(queryByTestId(document.body, "rank-circle")).toBeInTheDocument(); - }); - - it("should have proper name apostrophe", () => { - document.body.innerHTML = renderStatsCard({ ...stats, name: "Anil Das" }); - - expect(document.getElementsByClassName("header")[0].textContent).toBe( - "Anil Das' GitHub Stats" - ); - - document.body.innerHTML = renderStatsCard({ ...stats, name: "Felix" }); - - expect(document.getElementsByClassName("header")[0].textContent).toBe( - "Felix' GitHub Stats" - ); - }); - - it("should hide individual stats", () => { - document.body.innerHTML = renderStatsCard(stats, { - hide: ["issues", "prs", "contribs"], - }); - - expect( - document.body.getElementsByTagName("svg")[0].getAttribute("height") - ).toBe("150"); // height should be 150 because we clamped it. - - expect(queryByTestId(document.body, "stars")).toBeDefined(); - expect(queryByTestId(document.body, "commits")).toBeDefined(); - expect(queryByTestId(document.body, "issues")).toBeNull(); - expect(queryByTestId(document.body, "prs")).toBeNull(); - expect(queryByTestId(document.body, "contribs")).toBeNull(); - }); - - it("should hide_rank", () => { - document.body.innerHTML = renderStatsCard(stats, { hide_rank: true }); - - expect(queryByTestId(document.body, "rank-circle")).not.toBeInTheDocument(); - }); - - it("should render default colors properly", () => { - document.body.innerHTML = renderStatsCard(stats); - - const styleTag = document.querySelector("style"); - const stylesObject = cssToObject(styleTag.textContent); - - const headerClassStyles = stylesObject[".header"]; - const statClassStyles = stylesObject[".stat"]; - const iconClassStyles = stylesObject[".icon"]; - - expect(headerClassStyles.fill).toBe("#2f80ed"); - expect(statClassStyles.fill).toBe("#333"); - expect(iconClassStyles.fill).toBe("#4c71f2"); - expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( - "fill", - "#fffefe" - ); - }); - - it("should render custom colors properly", () => { - const customColors = { - title_color: "5a0", - icon_color: "1b998b", - text_color: "9991", - bg_color: "252525", - }; - - document.body.innerHTML = renderStatsCard(stats, { ...customColors }); - - const styleTag = document.querySelector("style"); - const stylesObject = cssToObject(styleTag.innerHTML); - - const headerClassStyles = stylesObject[".header"]; - const statClassStyles = stylesObject[".stat"]; - const iconClassStyles = stylesObject[".icon"]; - - expect(headerClassStyles.fill).toBe(`#${customColors.title_color}`); - expect(statClassStyles.fill).toBe(`#${customColors.text_color}`); - expect(iconClassStyles.fill).toBe(`#${customColors.icon_color}`); - expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( - "fill", - "#252525" - ); - }); - - it("should render custom colors with themes", () => { - document.body.innerHTML = renderStatsCard(stats, { - title_color: "5a0", - theme: "radical", - }); - - const styleTag = document.querySelector("style"); - const stylesObject = cssToObject(styleTag.innerHTML); - - const headerClassStyles = stylesObject[".header"]; - const statClassStyles = stylesObject[".stat"]; - const iconClassStyles = stylesObject[".icon"]; - - expect(headerClassStyles.fill).toBe("#5a0"); - expect(statClassStyles.fill).toBe(`#${themes.radical.text_color}`); - expect(iconClassStyles.fill).toBe(`#${themes.radical.icon_color}`); - expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( - "fill", - `#${themes.radical.bg_color}` - ); - }); - - it("should render with all the themes", () => { - Object.keys(themes).forEach((name) => { - document.body.innerHTML = renderStatsCard(stats, { - theme: name, - }); - - const styleTag = document.querySelector("style"); - const stylesObject = cssToObject(styleTag.innerHTML); - - const headerClassStyles = stylesObject[".header"]; - const statClassStyles = stylesObject[".stat"]; - const iconClassStyles = stylesObject[".icon"]; - - expect(headerClassStyles.fill).toBe(`#${themes[name].title_color}`); - expect(statClassStyles.fill).toBe(`#${themes[name].text_color}`); - expect(iconClassStyles.fill).toBe(`#${themes[name].icon_color}`); - expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( - "fill", - `#${themes[name].bg_color}` - ); - }); - }); - - it("should render custom colors with themes and fallback to default colors if invalid", () => { - document.body.innerHTML = renderStatsCard(stats, { - title_color: "invalid color", - text_color: "invalid color", - theme: "radical", - }); - - const styleTag = document.querySelector("style"); - const stylesObject = cssToObject(styleTag.innerHTML); - - const headerClassStyles = stylesObject[".header"]; - const statClassStyles = stylesObject[".stat"]; - const iconClassStyles = stylesObject[".icon"]; - - expect(headerClassStyles.fill).toBe(`#${themes.default.title_color}`); - expect(statClassStyles.fill).toBe(`#${themes.default.text_color}`); - expect(iconClassStyles.fill).toBe(`#${themes.radical.icon_color}`); - expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( - "fill", - `#${themes.radical.bg_color}` - ); - }); - - it("should render icons correctly", () => { - document.body.innerHTML = renderStatsCard(stats, { - show_icons: true, - }); - - expect(queryAllByTestId(document.body, "icon")[0]).toBeDefined(); - expect(queryByTestId(document.body, "stars")).toBeDefined(); - expect( - queryByTestId(document.body, "stars").previousElementSibling // the label - ).toHaveAttribute("x", "25"); - }); - - it("should not have icons if show_icons is false", () => { - document.body.innerHTML = renderStatsCard(stats, { show_icons: false }); - - expect(queryAllByTestId(document.body, "icon")[0]).not.toBeDefined(); - expect(queryByTestId(document.body, "stars")).toBeDefined(); - expect( - queryByTestId(document.body, "stars").previousElementSibling // the label - ).not.toHaveAttribute("x"); - }); -}); diff --git a/tests/renderTopLanguages.test.js b/tests/renderTopLanguages.test.js deleted file mode 100644 index b9d4095..0000000 --- a/tests/renderTopLanguages.test.js +++ /dev/null @@ -1,219 +0,0 @@ -require("@testing-library/jest-dom"); -const cssToObject = require("css-to-object"); -const renderTopLanguages = require("../src/cards/top-languages-card"); - -const { queryByTestId, queryAllByTestId } = require("@testing-library/dom"); -const themes = require("../themes"); - -describe("Test renderTopLanguages", () => { - const langs = { - HTML: { - color: "#0f0", - name: "HTML", - size: 200, - }, - javascript: { - color: "#0ff", - name: "javascript", - size: 200, - }, - css: { - color: "#ff0", - name: "css", - size: 100, - }, - }; - - it("should render correctly", () => { - document.body.innerHTML = renderTopLanguages(langs); - - expect(queryByTestId(document.body, "header")).toHaveTextContent( - "Most Used Languages" - ); - - expect(queryAllByTestId(document.body, "lang-name")[0]).toHaveTextContent( - "HTML" - ); - expect(queryAllByTestId(document.body, "lang-name")[1]).toHaveTextContent( - "javascript" - ); - expect(queryAllByTestId(document.body, "lang-name")[2]).toHaveTextContent( - "css" - ); - expect(queryAllByTestId(document.body, "lang-progress")[0]).toHaveAttribute( - "width", - "40%" - ); - expect(queryAllByTestId(document.body, "lang-progress")[1]).toHaveAttribute( - "width", - "40%" - ); - expect(queryAllByTestId(document.body, "lang-progress")[2]).toHaveAttribute( - "width", - "20%" - ); - }); - - it("should hide languages when hide is passed", () => { - document.body.innerHTML = renderTopLanguages(langs, { - hide: ["HTML"], - }); - expect(queryAllByTestId(document.body, "lang-name")[0]).toBeInTheDocument( - "javascript" - ); - expect(queryAllByTestId(document.body, "lang-name")[1]).toBeInTheDocument( - "css" - ); - expect(queryAllByTestId(document.body, "lang-name")[2]).not.toBeDefined(); - - // multiple languages passed - document.body.innerHTML = renderTopLanguages(langs, { - hide: ["HTML", "css"], - }); - expect(queryAllByTestId(document.body, "lang-name")[0]).toBeInTheDocument( - "javascript" - ); - expect(queryAllByTestId(document.body, "lang-name")[1]).not.toBeDefined(); - }); - - it("should resize the height correctly depending on langs", () => { - document.body.innerHTML = renderTopLanguages(langs, {}); - expect(document.querySelector("svg")).toHaveAttribute("height", "205"); - - document.body.innerHTML = renderTopLanguages( - { - ...langs, - python: { - color: "#ff0", - name: "python", - size: 100, - }, - }, - {} - ); - expect(document.querySelector("svg")).toHaveAttribute("height", "245"); - }); - - it("should render with custom width set", () => { - document.body.innerHTML = renderTopLanguages(langs, {}); - - expect(document.querySelector("svg")).toHaveAttribute("width", "300"); - - document.body.innerHTML = renderTopLanguages(langs, { card_width: 400 }); - expect(document.querySelector("svg")).toHaveAttribute("width", "400"); - }); - - it("should render default colors properly", () => { - document.body.innerHTML = renderTopLanguages(langs); - - const styleTag = document.querySelector("style"); - const stylesObject = cssToObject(styleTag.textContent); - - const headerStyles = stylesObject[".header"]; - const langNameStyles = stylesObject[".lang-name"]; - - expect(headerStyles.fill).toBe("#2f80ed"); - expect(langNameStyles.fill).toBe("#333"); - expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( - "fill", - "#fffefe" - ); - }); - - it("should render custom colors properly", () => { - const customColors = { - title_color: "5a0", - icon_color: "1b998b", - text_color: "9991", - bg_color: "252525", - }; - - document.body.innerHTML = renderTopLanguages(langs, { ...customColors }); - - const styleTag = document.querySelector("style"); - const stylesObject = cssToObject(styleTag.innerHTML); - - const headerStyles = stylesObject[".header"]; - const langNameStyles = stylesObject[".lang-name"]; - - expect(headerStyles.fill).toBe(`#${customColors.title_color}`); - expect(langNameStyles.fill).toBe(`#${customColors.text_color}`); - expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( - "fill", - "#252525" - ); - }); - - it("should render custom colors with themes", () => { - document.body.innerHTML = renderTopLanguages(langs, { - title_color: "5a0", - theme: "radical", - }); - - const styleTag = document.querySelector("style"); - const stylesObject = cssToObject(styleTag.innerHTML); - - const headerStyles = stylesObject[".header"]; - const langNameStyles = stylesObject[".lang-name"]; - - expect(headerStyles.fill).toBe("#5a0"); - expect(langNameStyles.fill).toBe(`#${themes.radical.text_color}`); - expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( - "fill", - `#${themes.radical.bg_color}` - ); - }); - - it("should render with all the themes", () => { - Object.keys(themes).forEach((name) => { - document.body.innerHTML = renderTopLanguages(langs, { - theme: name, - }); - - const styleTag = document.querySelector("style"); - const stylesObject = cssToObject(styleTag.innerHTML); - - const headerStyles = stylesObject[".header"]; - const langNameStyles = stylesObject[".lang-name"]; - - expect(headerStyles.fill).toBe(`#${themes[name].title_color}`); - expect(langNameStyles.fill).toBe(`#${themes[name].text_color}`); - expect(queryByTestId(document.body, "card-bg")).toHaveAttribute( - "fill", - `#${themes[name].bg_color}` - ); - }); - }); - - it("should render with layout compact", () => { - document.body.innerHTML = renderTopLanguages(langs, { layout: "compact" }); - - expect(queryByTestId(document.body, "header")).toHaveTextContent( - "Most Used Languages" - ); - - expect(queryAllByTestId(document.body, "lang-name")[0]).toHaveTextContent( - "HTML 40.00%" - ); - expect(queryAllByTestId(document.body, "lang-progress")[0]).toHaveAttribute( - "width", - "120.00" - ); - - expect(queryAllByTestId(document.body, "lang-name")[1]).toHaveTextContent( - "javascript 40.00%" - ); - expect(queryAllByTestId(document.body, "lang-progress")[1]).toHaveAttribute( - "width", - "120.00" - ); - - expect(queryAllByTestId(document.body, "lang-name")[2]).toHaveTextContent( - "css 20.00%" - ); - expect(queryAllByTestId(document.body, "lang-progress")[2]).toHaveAttribute( - "width", - "60.00" - ); - }); -}); diff --git a/tests/retryer.test.js b/tests/retryer.test.js deleted file mode 100644 index 627dcb2..0000000 --- a/tests/retryer.test.js +++ /dev/null @@ -1,51 +0,0 @@ -require("@testing-library/jest-dom"); -const retryer = require("../src/common/retryer"); -const { logger } = require("../src/common/utils"); - -const fetcher = jest.fn((variables, token) => { - logger.log(variables, token); - return new Promise((res, rej) => res({ data: "ok" })); -}); - -const fetcherFail = jest.fn(() => { - return new Promise((res, rej) => - res({ data: { errors: [{ type: "RATE_LIMITED" }] } }) - ); -}); - -const fetcherFailOnSecondTry = jest.fn((_vars, _token, retries) => { - return new Promise((res, rej) => { - // faking rate limit - if (retries < 1) { - return res({ data: { errors: [{ type: "RATE_LIMITED" }] } }); - } - return res({ data: "ok" }); - }); -}); - -describe("Test Retryer", () => { - it("retryer should return value and have zero retries on first try", async () => { - let res = await retryer(fetcher, {}); - - expect(fetcher).toBeCalledTimes(1); - expect(res).toStrictEqual({ data: "ok" }); - }); - - it("retryer should return value and have 2 retries", async () => { - let res = await retryer(fetcherFailOnSecondTry, {}); - - expect(fetcherFailOnSecondTry).toBeCalledTimes(2); - expect(res).toStrictEqual({ data: "ok" }); - }); - - it("retryer should throw error if maximum retries reached", async () => { - let res; - - try { - res = await retryer(fetcherFail, {}); - } catch (err) { - expect(fetcherFail).toBeCalledTimes(8); - expect(err.message).toBe("Maximum retries exceeded"); - } - }); -}); diff --git a/tests/top-langs.test.js b/tests/top-langs.test.js deleted file mode 100644 index 9d06b6f..0000000 --- a/tests/top-langs.test.js +++ /dev/null @@ -1,142 +0,0 @@ -require("@testing-library/jest-dom"); -const axios = require("axios"); -const MockAdapter = require("axios-mock-adapter"); -const topLangs = require("../api/top-langs"); -const renderTopLanguages = require("../src/cards/top-languages-card"); -const { renderError } = require("../src/common/utils"); - -const data_langs = { - data: { - user: { - repositories: { - nodes: [ - { - languages: { - edges: [{ size: 150, node: { color: "#0f0", name: "HTML" } }], - }, - }, - { - languages: { - edges: [{ size: 100, node: { color: "#0f0", name: "HTML" } }], - }, - }, - { - languages: { - edges: [ - { size: 100, node: { color: "#0ff", name: "javascript" } }, - ], - }, - }, - { - languages: { - edges: [ - { size: 100, node: { color: "#0ff", name: "javascript" } }, - ], - }, - }, - ], - }, - }, - }, -}; - -const error = { - errors: [ - { - type: "NOT_FOUND", - path: ["user"], - locations: [], - message: "Could not fetch user", - }, - ], -}; - -const langs = { - HTML: { - color: "#0f0", - name: "HTML", - size: 250, - }, - javascript: { - color: "#0ff", - name: "javascript", - size: 200, - }, -}; - -const mock = new MockAdapter(axios); - -afterEach(() => { - mock.reset(); -}); - -describe("Test /api/top-langs", () => { - it("should test the request", async () => { - const req = { - query: { - username: "anuraghazra", - }, - }; - const res = { - setHeader: jest.fn(), - send: jest.fn(), - }; - mock.onPost("https://api.github.com/graphql").reply(200, data_langs); - - await topLangs(req, res); - - expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); - expect(res.send).toBeCalledWith(renderTopLanguages(langs)); - }); - - it("should work with the query options", async () => { - const req = { - query: { - username: "anuraghazra", - hide_title: true, - card_width: 100, - title_color: "fff", - icon_color: "fff", - text_color: "fff", - bg_color: "fff", - }, - }; - const res = { - setHeader: jest.fn(), - send: jest.fn(), - }; - mock.onPost("https://api.github.com/graphql").reply(200, data_langs); - - await topLangs(req, res); - - expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); - expect(res.send).toBeCalledWith( - renderTopLanguages(langs, { - hide_title: true, - card_width: 100, - title_color: "fff", - icon_color: "fff", - text_color: "fff", - bg_color: "fff", - }) - ); - }); - - it("should render error card on error", async () => { - const req = { - query: { - username: "anuraghazra", - }, - }; - const res = { - setHeader: jest.fn(), - send: jest.fn(), - }; - mock.onPost("https://api.github.com/graphql").reply(200, error); - - await topLangs(req, res); - - expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml"); - expect(res.send).toBeCalledWith(renderError(error.errors[0].message)); - }); -}); diff --git a/tests/utils.test.js b/tests/utils.test.js deleted file mode 100644 index 54e1ddd..0000000 --- a/tests/utils.test.js +++ /dev/null @@ -1,136 +0,0 @@ -require("@testing-library/jest-dom"); -const { - kFormatter, - encodeHTML, - renderError, - FlexLayout, - getCardColors, - wrapTextMultiline, -} = require("../src/common/utils"); - -const { queryByTestId } = require("@testing-library/dom"); - -describe("Test utils.js", () => { - it("should test kFormatter", () => { - expect(kFormatter(1)).toBe(1); - expect(kFormatter(-1)).toBe(-1); - expect(kFormatter(500)).toBe(500); - expect(kFormatter(1000)).toBe("1k"); - expect(kFormatter(10000)).toBe("10k"); - expect(kFormatter(12345)).toBe("12.3k"); - expect(kFormatter(9900000)).toBe("9900k"); - }); - - it("should test encodeHTML", () => { - expect(encodeHTML(`hello world<,.#4^&^@%!))`)).toBe( - "<html>hello world<,.#4^&^@%!))" - ); - }); - - it("should test renderError", () => { - document.body.innerHTML = renderError("Something went wrong"); - expect( - queryByTestId(document.body, "message").children[0] - ).toHaveTextContent(/Something went wrong/gim); - expect(queryByTestId(document.body, "message").children[1]).toBeEmpty(2); - - // Secondary message - document.body.innerHTML = renderError( - "Something went wrong", - "Secondary Message" - ); - expect( - queryByTestId(document.body, "message").children[1] - ).toHaveTextContent(/Secondary Message/gim); - }); - - it("should test FlexLayout", () => { - const layout = FlexLayout({ - items: ["1", "2"], - gap: 60, - }).join(""); - - expect(layout).toBe( - `12` - ); - - const columns = FlexLayout({ - items: ["1", "2"], - gap: 60, - direction: "column", - }).join(""); - - expect(columns).toBe( - `12` - ); - }); - - it("getCardColors: should return expected values", () => { - let colors = getCardColors({ - title_color: "f00", - text_color: "0f0", - icon_color: "00f", - bg_color: "fff", - theme: "dark", - }); - expect(colors).toStrictEqual({ - titleColor: "#f00", - textColor: "#0f0", - iconColor: "#00f", - bgColor: "#fff", - }); - }); - - it("getCardColors: should fallback to default colors if color is invalid", () => { - let colors = getCardColors({ - title_color: "invalidcolor", - text_color: "0f0", - icon_color: "00f", - bg_color: "fff", - theme: "dark", - }); - expect(colors).toStrictEqual({ - titleColor: "#2f80ed", - textColor: "#0f0", - iconColor: "#00f", - bgColor: "#fff", - }); - }); - - it("getCardColors: should fallback to specified theme colors if is not defined", () => { - let colors = getCardColors({ - theme: "dark", - }); - expect(colors).toStrictEqual({ - titleColor: "#fff", - textColor: "#9f9f9f", - iconColor: "#79ff97", - bgColor: "#151515", - }); - }); -}); - -describe("wrapTextMultiline", () => { - it("should not wrap small texts", () => { - { - let multiLineText = wrapTextMultiline("Small text should not wrap"); - expect(multiLineText).toEqual(["Small text should not wrap"]); - } - }); - it("should wrap large texts", () => { - let multiLineText = wrapTextMultiline( - "Hello world long long long text", - 20, - 3 - ); - expect(multiLineText).toEqual(["Hello world long", "long long text"]); - }); - it("should wrap large texts and limit max lines", () => { - let multiLineText = wrapTextMultiline( - "Hello world long long long text", - 10, - 2 - ); - expect(multiLineText).toEqual(["Hello", "world long..."]); - }); -}); diff --git a/themes/index.js b/themes/index.js deleted file mode 100644 index c460a29..0000000 --- a/themes/index.js +++ /dev/null @@ -1,226 +0,0 @@ -const themes = { - default: { - title_color: "2f80ed", - icon_color: "4c71f2", - text_color: "333", - bg_color: "fffefe", - }, - default_repocard: { - title_color: "2f80ed", - icon_color: "586069", // icon color is different - text_color: "333", - bg_color: "fffefe", - }, - dark: { - title_color: "fff", - icon_color: "79ff97", - text_color: "9f9f9f", - bg_color: "151515", - }, - radical: { - title_color: "fe428e", - icon_color: "f8d847", - text_color: "a9fef7", - bg_color: "141321", - }, - merko: { - title_color: "abd200", - icon_color: "b7d364", - text_color: "68b587", - bg_color: "0a0f0b", - }, - gruvbox: { - title_color: "fabd2f", - icon_color: "fe8019", - text_color: "8ec07c", - bg_color: "282828", - }, - tokyonight: { - title_color: "70a5fd", - icon_color: "bf91f3", - text_color: "38bdae", - bg_color: "1a1b27", - }, - onedark: { - title_color: "e4bf7a", - icon_color: "8eb573", - text_color: "df6d74", - bg_color: "282c34", - }, - cobalt: { - title_color: "e683d9", - icon_color: "0480ef", - text_color: "75eeb2", - bg_color: "193549", - }, - synthwave: { - title_color: "e2e9ec", - icon_color: "ef8539", - text_color: "e5289e", - bg_color: "2b213a", - }, - highcontrast: { - title_color: "e7f216", - icon_color: "00ffff", - text_color: "fff", - bg_color: "000", - }, - dracula: { - title_color: "ff6e96", - icon_color: "79dafa", - text_color: "f8f8f2", - bg_color: "282a36", - }, - prussian: { - title_color: "bddfff", - icon_color: "38a0ff", - text_color: "6e93b5", - bg_color: "172f45", - }, - monokai: { - title_color: "eb1f6a", - icon_color: "e28905", - text_color: "f1f1eb", - bg_color: "272822", - }, - vue: { - title_color: "41b883", - icon_color: "41b883", - text_color: "273849", - bg_color: "fffefe", - }, - 'vue-dark': { - title_color: "41b883", - icon_color: "41b883", - text_color: "fffefe", - bg_color: "273849", - }, - "shades-of-purple": { - title_color: "fad000", - icon_color: "b362ff", - text_color: "a599e9", - bg_color: "2d2b55", - }, - nightowl: { - title_color: "c792ea", - icon_color: "ffeb95", - text_color: "7fdbca", - bg_color: "011627", - }, - buefy: { - title_color: "7957d5", - icon_color: "ff3860", - text_color: "363636", - bg_color: "ffffff", - }, - "blue-green": { - title_color: "2f97c1", - icon_color: "f5b700", - text_color: "0cf574", - bg_color: "040f0f", - }, - algolia: { - title_color: "00AEFF", - icon_color: "2DDE98", - text_color: "FFFFFF", - bg_color: "050F2C", - }, - "great-gatsby": { - title_color: "ffa726", - icon_color: "ffb74d", - text_color: "ffd95b", - bg_color: "000000", - }, - darcula: { - title_color: "BA5F17", - icon_color: "84628F", - text_color: "BEBEBE", - bg_color: "242424", - }, - bear: { - title_color: "e03c8a", - icon_color: "00AEFF", - text_color: "bcb28d", - bg_color: "1f2023", - }, - "solarized-dark": { - title_color: "268bd2", - icon_color: "b58900", - text_color: "859900", - bg_color: "002b36", - }, - "solarized-light": { - title_color: "268bd2", - icon_color: "b58900", - text_color: "859900", - bg_color: "fdf6e3", - }, - "chartreuse-dark": { - title_color: "7fff00", - icon_color: "00AEFF", - text_color: "fff", - bg_color: "000", - }, - "nord": { - title_color: "81a1c1", - text_color: "d8dee9", - icon_color: "88c0d0", - bg_color: "2e3440", - }, - "gotham": { - title_color: "2aa889", - icon_color: "599cab", - text_color: "99d1ce", - bg_color: "0c1014", - }, - "material-palenight": { - title_color: "c792ea", - icon_color: "89ddff", - text_color: "a6accd", - bg_color: "292d3e", - }, - "graywhite": { - title_color: "24292e", - icon_color: "24292e", - text_color: "24292e", - bg_color: "ffffff", - }, - "vision-friendly-dark": { - title_color: "ffb000", - icon_color: "785ef0", - text_color: "ffffff", - bg_color: "000000", - }, - "ayu-mirage": { - title_color: "f4cd7c", - icon_color: "73d0ff", - text_color: "c7c8c2", - bg_color: "1f2430", - }, - "midnight-purple":{ - title_color: "9745f5", - icon_color: "9f4bff", - text_color: "ffffff", - bg_color: "000000", - }, - calm: { - title_color: "e07a5f", - icon_color: "edae49", - text_color: "ebcfb2", - bg_color: "373f51", - }, - omni: { - title_color: "FF79C6", - icon_color: "e7de79", - text_color: "E1E1E6", - bg_color: "191622" - }, - react: { - title_color: "61dafb", - icon_color: "61dafb", - text_color: "ffffff", - bg_color: "20232a", - }, -}; - -module.exports = themes; diff --git a/themes/index.ts b/themes/index.ts new file mode 100644 index 0000000..2d4fa70 --- /dev/null +++ b/themes/index.ts @@ -0,0 +1,226 @@ +const themes = { + default: { + title_color: "2f80ed", + icon_color: "4c71f2", + text_color: "333", + bg_color: "fffefe", + }, + default_repocard: { + title_color: "2f80ed", + icon_color: "586069", // icon color is different + text_color: "333", + bg_color: "fffefe", + }, + dark: { + title_color: "fff", + icon_color: "79ff97", + text_color: "9f9f9f", + bg_color: "151515", + }, + radical: { + title_color: "fe428e", + icon_color: "f8d847", + text_color: "a9fef7", + bg_color: "141321", + }, + merko: { + title_color: "abd200", + icon_color: "b7d364", + text_color: "68b587", + bg_color: "0a0f0b", + }, + gruvbox: { + title_color: "fabd2f", + icon_color: "fe8019", + text_color: "8ec07c", + bg_color: "282828", + }, + tokyonight: { + title_color: "70a5fd", + icon_color: "bf91f3", + text_color: "38bdae", + bg_color: "1a1b27", + }, + onedark: { + title_color: "e4bf7a", + icon_color: "8eb573", + text_color: "df6d74", + bg_color: "282c34", + }, + cobalt: { + title_color: "e683d9", + icon_color: "0480ef", + text_color: "75eeb2", + bg_color: "193549", + }, + synthwave: { + title_color: "e2e9ec", + icon_color: "ef8539", + text_color: "e5289e", + bg_color: "2b213a", + }, + highcontrast: { + title_color: "e7f216", + icon_color: "00ffff", + text_color: "fff", + bg_color: "000", + }, + dracula: { + title_color: "ff6e96", + icon_color: "79dafa", + text_color: "f8f8f2", + bg_color: "282a36", + }, + prussian: { + title_color: "bddfff", + icon_color: "38a0ff", + text_color: "6e93b5", + bg_color: "172f45", + }, + monokai: { + title_color: "eb1f6a", + icon_color: "e28905", + text_color: "f1f1eb", + bg_color: "272822", + }, + vue: { + title_color: "41b883", + icon_color: "41b883", + text_color: "273849", + bg_color: "fffefe", + }, + 'vue-dark': { + title_color: "41b883", + icon_color: "41b883", + text_color: "fffefe", + bg_color: "273849", + }, + "shades-of-purple": { + title_color: "fad000", + icon_color: "b362ff", + text_color: "a599e9", + bg_color: "2d2b55", + }, + nightowl: { + title_color: "c792ea", + icon_color: "ffeb95", + text_color: "7fdbca", + bg_color: "011627", + }, + buefy: { + title_color: "7957d5", + icon_color: "ff3860", + text_color: "363636", + bg_color: "ffffff", + }, + "blue-green": { + title_color: "2f97c1", + icon_color: "f5b700", + text_color: "0cf574", + bg_color: "040f0f", + }, + algolia: { + title_color: "00AEFF", + icon_color: "2DDE98", + text_color: "FFFFFF", + bg_color: "050F2C", + }, + "great-gatsby": { + title_color: "ffa726", + icon_color: "ffb74d", + text_color: "ffd95b", + bg_color: "000000", + }, + darcula: { + title_color: "BA5F17", + icon_color: "84628F", + text_color: "BEBEBE", + bg_color: "242424", + }, + bear: { + title_color: "e03c8a", + icon_color: "00AEFF", + text_color: "bcb28d", + bg_color: "1f2023", + }, + "solarized-dark": { + title_color: "268bd2", + icon_color: "b58900", + text_color: "859900", + bg_color: "002b36", + }, + "solarized-light": { + title_color: "268bd2", + icon_color: "b58900", + text_color: "859900", + bg_color: "fdf6e3", + }, + "chartreuse-dark": { + title_color: "7fff00", + icon_color: "00AEFF", + text_color: "fff", + bg_color: "000", + }, + "nord": { + title_color: "81a1c1", + text_color: "d8dee9", + icon_color: "88c0d0", + bg_color: "2e3440", + }, + "gotham": { + title_color: "2aa889", + icon_color: "599cab", + text_color: "99d1ce", + bg_color: "0c1014", + }, + "material-palenight": { + title_color: "c792ea", + icon_color: "89ddff", + text_color: "a6accd", + bg_color: "292d3e", + }, + "graywhite": { + title_color: "24292e", + icon_color: "24292e", + text_color: "24292e", + bg_color: "ffffff", + }, + "vision-friendly-dark": { + title_color: "ffb000", + icon_color: "785ef0", + text_color: "ffffff", + bg_color: "000000", + }, + "ayu-mirage": { + title_color: "f4cd7c", + icon_color: "73d0ff", + text_color: "c7c8c2", + bg_color: "1f2430", + }, + "midnight-purple":{ + title_color: "9745f5", + icon_color: "9f4bff", + text_color: "ffffff", + bg_color: "000000", + }, + calm: { + title_color: "e07a5f", + icon_color: "edae49", + text_color: "ebcfb2", + bg_color: "373f51", + }, + omni: { + title_color: "FF79C6", + icon_color: "e7de79", + text_color: "E1E1E6", + bg_color: "191622" + }, + react: { + title_color: "61dafb", + icon_color: "61dafb", + text_color: "ffffff", + bg_color: "20232a", + }, +}; + +export default themes diff --git a/themes/language-bar.js b/themes/language-bar.js deleted file mode 100644 index c159728..0000000 --- a/themes/language-bar.js +++ /dev/null @@ -1,1710 +0,0 @@ -module.exports = { // https://github.com/ozh/github-colors - "1C Enterprise": { - "color": "#814CCC", - "url": "https://github.com/trending?l=1C-Enterprise" - }, - "4D": { - "color": null, - "url": "https://github.com/trending?l=4D" - }, - "ABAP": { - "color": "#E8274B", - "url": "https://github.com/trending?l=ABAP" - }, - "ActionScript": { - "color": "#882B0F", - "url": "https://github.com/trending?l=ActionScript" - }, - "Ada": { - "color": "#02f88c", - "url": "https://github.com/trending?l=Ada" - }, - "Agda": { - "color": "#315665", - "url": "https://github.com/trending?l=Agda" - }, - "AGS Script": { - "color": "#B9D9FF", - "url": "https://github.com/trending?l=AGS-Script" - }, - "AL Code": { - "color": "#3AA2B5", - "url": "https://github.com/trending?l=AL-Code" - }, - "Alloy": { - "color": "#64C800", - "url": "https://github.com/trending?l=Alloy" - }, - "Alpine Abuild": { - "color": null, - "url": "https://github.com/trending?l=Alpine-Abuild" - }, - "AMPL": { - "color": "#E6EFBB", - "url": "https://github.com/trending?l=AMPL" - }, - "AngelScript": { - "color": "#C7D7DC", - "url": "https://github.com/trending?l=AngelScript" - }, - "ANTLR": { - "color": "#9DC3FF", - "url": "https://github.com/trending?l=ANTLR" - }, - "Apex": { - "color": "#1797c0", - "url": "https://github.com/trending?l=Apex" - }, - "API Blueprint": { - "color": "#2ACCA8", - "url": "https://github.com/trending?l=API-Blueprint" - }, - "APL": { - "color": "#5A8164", - "url": "https://github.com/trending?l=APL" - }, - "Apollo Guidance Computer": { - "color": null, - "url": "https://github.com/trending?l=Apollo-Guidance-Computer" - }, - "AppleScript": { - "color": "#101F1F", - "url": "https://github.com/trending?l=AppleScript" - }, - "Arc": { - "color": "#aa2afe", - "url": "https://github.com/trending?l=Arc" - }, - "ASL": { - "color": null, - "url": "https://github.com/trending?l=ASL" - }, - "ASP.NET": { - "color": "#9400ff", - "url": "https://github.com/trending?l=ASP.NET" - }, - "AspectJ": { - "color": "#a957b0", - "url": "https://github.com/trending?l=AspectJ" - }, - "Assembly": { - "color": "#6E4C13", - "url": "https://github.com/trending?l=Assembly" - }, - "Asymptote": { - "color": "#ff0000", - "url": "https://github.com/trending?l=Asymptote" - }, - "ATS": { - "color": "#1ac620", - "url": "https://github.com/trending?l=ATS" - }, - "Augeas": { - "color": null, - "url": "https://github.com/trending?l=Augeas" - }, - "AutoHotkey": { - "color": "#6594b9", - "url": "https://github.com/trending?l=AutoHotkey" - }, - "AutoIt": { - "color": "#1C3552", - "url": "https://github.com/trending?l=AutoIt" - }, - "Awk": { - "color": null, - "url": "https://github.com/trending?l=Awk" - }, - "Ballerina": { - "color": "#FF5000", - "url": "https://github.com/trending?l=Ballerina" - }, - "Batchfile": { - "color": "#C1F12E", - "url": "https://github.com/trending?l=Batchfile" - }, - "Befunge": { - "color": null, - "url": "https://github.com/trending?l=Befunge" - }, - "Bison": { - "color": null, - "url": "https://github.com/trending?l=Bison" - }, - "BitBake": { - "color": null, - "url": "https://github.com/trending?l=BitBake" - }, - "Blade": { - "color": "#f7523f", - "url": "https://github.com/trending?l=Blade" - }, - "BlitzBasic": { - "color": null, - "url": "https://github.com/trending?l=BlitzBasic" - }, - "BlitzMax": { - "color": "#cd6400", - "url": "https://github.com/trending?l=BlitzMax" - }, - "Bluespec": { - "color": null, - "url": "https://github.com/trending?l=Bluespec" - }, - "Boo": { - "color": "#d4bec1", - "url": "https://github.com/trending?l=Boo" - }, - "Brainfuck": { - "color": "#2F2530", - "url": "https://github.com/trending?l=Brainfuck" - }, - "Brightscript": { - "color": null, - "url": "https://github.com/trending?l=Brightscript" - }, - "C": { - "color": "#555555", - "url": "https://github.com/trending?l=C" - }, - "C#": { - "color": "#178600", - "url": "https://github.com/trending?l=Csharp" - }, - "C++": { - "color": "#f34b7d", - "url": "https://github.com/trending?l=C++" - }, - "C2hs Haskell": { - "color": null, - "url": "https://github.com/trending?l=C2hs-Haskell" - }, - "Cap'n Proto": { - "color": null, - "url": "https://github.com/trending?l=Cap'n-Proto" - }, - "CartoCSS": { - "color": null, - "url": "https://github.com/trending?l=CartoCSS" - }, - "Ceylon": { - "color": "#dfa535", - "url": "https://github.com/trending?l=Ceylon" - }, - "Chapel": { - "color": "#8dc63f", - "url": "https://github.com/trending?l=Chapel" - }, - "Charity": { - "color": null, - "url": "https://github.com/trending?l=Charity" - }, - "ChucK": { - "color": null, - "url": "https://github.com/trending?l=ChucK" - }, - "Cirru": { - "color": "#ccccff", - "url": "https://github.com/trending?l=Cirru" - }, - "Clarion": { - "color": "#db901e", - "url": "https://github.com/trending?l=Clarion" - }, - "Classic ASP": { - "color": "#6a40fd", - "url": "https://github.com/trending?l=Classic-ASP" - }, - "Clean": { - "color": "#3F85AF", - "url": "https://github.com/trending?l=Clean" - }, - "Click": { - "color": "#E4E6F3", - "url": "https://github.com/trending?l=Click" - }, - "CLIPS": { - "color": null, - "url": "https://github.com/trending?l=CLIPS" - }, - "Clojure": { - "color": "#db5855", - "url": "https://github.com/trending?l=Clojure" - }, - "CMake": { - "color": null, - "url": "https://github.com/trending?l=CMake" - }, - "COBOL": { - "color": null, - "url": "https://github.com/trending?l=COBOL" - }, - "CodeQL": { - "color": null, - "url": "https://github.com/trending?l=CodeQL" - }, - "CoffeeScript": { - "color": "#244776", - "url": "https://github.com/trending?l=CoffeeScript" - }, - "ColdFusion": { - "color": "#ed2cd6", - "url": "https://github.com/trending?l=ColdFusion" - }, - "ColdFusion CFC": { - "color": null, - "url": "https://github.com/trending?l=ColdFusion-CFC" - }, - "Common Lisp": { - "color": "#3fb68b", - "url": "https://github.com/trending?l=Common-Lisp" - }, - "Common Workflow Language": { - "color": "#B5314C", - "url": "https://github.com/trending?l=Common-Workflow-Language" - }, - "Component Pascal": { - "color": "#B0CE4E", - "url": "https://github.com/trending?l=Component-Pascal" - }, - "Cool": { - "color": null, - "url": "https://github.com/trending?l=Cool" - }, - "Coq": { - "color": null, - "url": "https://github.com/trending?l=Coq" - }, - "Crystal": { - "color": "#000100", - "url": "https://github.com/trending?l=Crystal" - }, - "CSON": { - "color": "#244776", - "url": "https://github.com/trending?l=CSON" - }, - "Csound": { - "color": null, - "url": "https://github.com/trending?l=Csound" - }, - "Csound Document": { - "color": null, - "url": "https://github.com/trending?l=Csound-Document" - }, - "Csound Score": { - "color": null, - "url": "https://github.com/trending?l=Csound-Score" - }, - "CSS": { - "color": "#563d7c", - "url": "https://github.com/trending?l=CSS" - }, - "Cuda": { - "color": "#3A4E3A", - "url": "https://github.com/trending?l=Cuda" - }, - "CWeb": { - "color": null, - "url": "https://github.com/trending?l=CWeb" - }, - "Cycript": { - "color": null, - "url": "https://github.com/trending?l=Cycript" - }, - "Cython": { - "color": null, - "url": "https://github.com/trending?l=Cython" - }, - "D": { - "color": "#ba595e", - "url": "https://github.com/trending?l=D" - }, - "Dafny": { - "color": "#FFEC25", - "url": "https://github.com/trending?l=Dafny" - }, - "Dart": { - "color": "#00B4AB", - "url": "https://github.com/trending?l=Dart" - }, - "DataWeave": { - "color": "#003a52", - "url": "https://github.com/trending?l=DataWeave" - }, - "Dhall": { - "color": "#dfafff", - "url": "https://github.com/trending?l=Dhall" - }, - "DIGITAL Command Language": { - "color": null, - "url": "https://github.com/trending?l=DIGITAL-Command-Language" - }, - "DM": { - "color": "#447265", - "url": "https://github.com/trending?l=DM" - }, - "Dockerfile": { - "color": "#384d54", - "url": "https://github.com/trending?l=Dockerfile" - }, - "Dogescript": { - "color": "#cca760", - "url": "https://github.com/trending?l=Dogescript" - }, - "DTrace": { - "color": null, - "url": "https://github.com/trending?l=DTrace" - }, - "Dylan": { - "color": "#6c616e", - "url": "https://github.com/trending?l=Dylan" - }, - "E": { - "color": "#ccce35", - "url": "https://github.com/trending?l=E" - }, - "eC": { - "color": "#913960", - "url": "https://github.com/trending?l=eC" - }, - "ECL": { - "color": "#8a1267", - "url": "https://github.com/trending?l=ECL" - }, - "ECLiPSe": { - "color": null, - "url": "https://github.com/trending?l=ECLiPSe" - }, - "Eiffel": { - "color": "#4d6977", - "url": "https://github.com/trending?l=Eiffel" - }, - "Elixir": { - "color": "#6e4a7e", - "url": "https://github.com/trending?l=Elixir" - }, - "Elm": { - "color": "#60B5CC", - "url": "https://github.com/trending?l=Elm" - }, - "Emacs Lisp": { - "color": "#c065db", - "url": "https://github.com/trending?l=Emacs-Lisp" - }, - "EmberScript": { - "color": "#FFF4F3", - "url": "https://github.com/trending?l=EmberScript" - }, - "EQ": { - "color": "#a78649", - "url": "https://github.com/trending?l=EQ" - }, - "Erlang": { - "color": "#B83998", - "url": "https://github.com/trending?l=Erlang" - }, - "F#": { - "color": "#b845fc", - "url": "https://github.com/trending?l=Fsharp" - }, - "F*": { - "color": "#572e30", - "url": "https://github.com/trending?l=F*" - }, - "Factor": { - "color": "#636746", - "url": "https://github.com/trending?l=Factor" - }, - "Fancy": { - "color": "#7b9db4", - "url": "https://github.com/trending?l=Fancy" - }, - "Fantom": { - "color": "#14253c", - "url": "https://github.com/trending?l=Fantom" - }, - "Faust": { - "color": "#c37240", - "url": "https://github.com/trending?l=Faust" - }, - "Filebench WML": { - "color": null, - "url": "https://github.com/trending?l=Filebench-WML" - }, - "Filterscript": { - "color": null, - "url": "https://github.com/trending?l=Filterscript" - }, - "fish": { - "color": null, - "url": "https://github.com/trending?l=fish" - }, - "FLUX": { - "color": "#88ccff", - "url": "https://github.com/trending?l=FLUX" - }, - "Forth": { - "color": "#341708", - "url": "https://github.com/trending?l=Forth" - }, - "Fortran": { - "color": "#4d41b1", - "url": "https://github.com/trending?l=Fortran" - }, - "Fortran Free Form": { - "color": null, - "url": "https://github.com/trending?l=Fortran-Free-Form" - }, - "FreeMarker": { - "color": "#0050b2", - "url": "https://github.com/trending?l=FreeMarker" - }, - "Frege": { - "color": "#00cafe", - "url": "https://github.com/trending?l=Frege" - }, - "Futhark": { - "color": "#5f021f", - "url": "https://github.com/trending?l=Futhark" - }, - "G-code": { - "color": "#D08CF2", - "url": "https://github.com/trending?l=G-code" - }, - "Game Maker Language": { - "color": "#71b417", - "url": "https://github.com/trending?l=Game-Maker-Language" - }, - "GAML": { - "color": "#FFC766", - "url": "https://github.com/trending?l=GAML" - }, - "GAMS": { - "color": null, - "url": "https://github.com/trending?l=GAMS" - }, - "GAP": { - "color": null, - "url": "https://github.com/trending?l=GAP" - }, - "GCC Machine Description": { - "color": null, - "url": "https://github.com/trending?l=GCC-Machine-Description" - }, - "GDB": { - "color": null, - "url": "https://github.com/trending?l=GDB" - }, - "GDScript": { - "color": "#355570", - "url": "https://github.com/trending?l=GDScript" - }, - "Genie": { - "color": "#fb855d", - "url": "https://github.com/trending?l=Genie" - }, - "Genshi": { - "color": null, - "url": "https://github.com/trending?l=Genshi" - }, - "Gentoo Ebuild": { - "color": null, - "url": "https://github.com/trending?l=Gentoo-Ebuild" - }, - "Gentoo Eclass": { - "color": null, - "url": "https://github.com/trending?l=Gentoo-Eclass" - }, - "Gherkin": { - "color": "#5B2063", - "url": "https://github.com/trending?l=Gherkin" - }, - "GLSL": { - "color": null, - "url": "https://github.com/trending?l=GLSL" - }, - "Glyph": { - "color": "#c1ac7f", - "url": "https://github.com/trending?l=Glyph" - }, - "Gnuplot": { - "color": "#f0a9f0", - "url": "https://github.com/trending?l=Gnuplot" - }, - "Go": { - "color": "#00ADD8", - "url": "https://github.com/trending?l=Go" - }, - "Golo": { - "color": "#88562A", - "url": "https://github.com/trending?l=Golo" - }, - "Gosu": { - "color": "#82937f", - "url": "https://github.com/trending?l=Gosu" - }, - "Grace": { - "color": null, - "url": "https://github.com/trending?l=Grace" - }, - "Grammatical Framework": { - "color": "#ff0000", - "url": "https://github.com/trending?l=Grammatical-Framework" - }, - "Groovy": { - "color": "#e69f56", - "url": "https://github.com/trending?l=Groovy" - }, - "Groovy Server Pages": { - "color": null, - "url": "https://github.com/trending?l=Groovy-Server-Pages" - }, - "Hack": { - "color": "#878787", - "url": "https://github.com/trending?l=Hack" - }, - "Haml": { - "color": "#ece2a9", - "url": "https://github.com/trending?l=Haml" - }, - "Handlebars": { - "color": "#f7931e", - "url": "https://github.com/trending?l=Handlebars" - }, - "Harbour": { - "color": "#0e60e3", - "url": "https://github.com/trending?l=Harbour" - }, - "Haskell": { - "color": "#5e5086", - "url": "https://github.com/trending?l=Haskell" - }, - "Haxe": { - "color": "#df7900", - "url": "https://github.com/trending?l=Haxe" - }, - "HCL": { - "color": null, - "url": "https://github.com/trending?l=HCL" - }, - "HiveQL": { - "color": "#dce200", - "url": "https://github.com/trending?l=HiveQL" - }, - "HLSL": { - "color": null, - "url": "https://github.com/trending?l=HLSL" - }, - "HolyC": { - "color": "#ffefaf", - "url": "https://github.com/trending?l=HolyC" - }, - "HTML": { - "color": "#e34c26", - "url": "https://github.com/trending?l=HTML" - }, - "Hy": { - "color": "#7790B2", - "url": "https://github.com/trending?l=Hy" - }, - "HyPhy": { - "color": null, - "url": "https://github.com/trending?l=HyPhy" - }, - "IDL": { - "color": "#a3522f", - "url": "https://github.com/trending?l=IDL" - }, - "Idris": { - "color": "#b30000", - "url": "https://github.com/trending?l=Idris" - }, - "IGOR Pro": { - "color": "#0000cc", - "url": "https://github.com/trending?l=IGOR-Pro" - }, - "Inform 7": { - "color": null, - "url": "https://github.com/trending?l=Inform-7" - }, - "Inno Setup": { - "color": null, - "url": "https://github.com/trending?l=Inno-Setup" - }, - "Io": { - "color": "#a9188d", - "url": "https://github.com/trending?l=Io" - }, - "Ioke": { - "color": "#078193", - "url": "https://github.com/trending?l=Ioke" - }, - "Isabelle": { - "color": "#FEFE00", - "url": "https://github.com/trending?l=Isabelle" - }, - "Isabelle ROOT": { - "color": null, - "url": "https://github.com/trending?l=Isabelle-ROOT" - }, - "J": { - "color": "#9EEDFF", - "url": "https://github.com/trending?l=J" - }, - "Jasmin": { - "color": null, - "url": "https://github.com/trending?l=Jasmin" - }, - "Java": { - "color": "#b07219", - "url": "https://github.com/trending?l=Java" - }, - "Java Server Pages": { - "color": null, - "url": "https://github.com/trending?l=Java-Server-Pages" - }, - "JavaScript": { - "color": "#f1e05a", - "url": "https://github.com/trending?l=JavaScript" - }, - "JavaScript+ERB": { - "color": null, - "url": "https://github.com/trending?l=JavaScript+ERB" - }, - "JFlex": { - "color": null, - "url": "https://github.com/trending?l=JFlex" - }, - "Jison": { - "color": null, - "url": "https://github.com/trending?l=Jison" - }, - "Jison Lex": { - "color": null, - "url": "https://github.com/trending?l=Jison-Lex" - }, - "Jolie": { - "color": "#843179", - "url": "https://github.com/trending?l=Jolie" - }, - "JSONiq": { - "color": "#40d47e", - "url": "https://github.com/trending?l=JSONiq" - }, - "Jsonnet": { - "color": "#0064bd", - "url": "https://github.com/trending?l=Jsonnet" - }, - "JSX": { - "color": null, - "url": "https://github.com/trending?l=JSX" - }, - "Julia": { - "color": "#a270ba", - "url": "https://github.com/trending?l=Julia" - }, - "Jupyter Notebook": { - "color": "#DA5B0B", - "url": "https://github.com/trending?l=Jupyter-Notebook" - }, - "Kaitai Struct": { - "color": "#773b37", - "url": "https://github.com/trending?l=Kaitai-Struct" - }, - "Kotlin": { - "color": "#F18E33", - "url": "https://github.com/trending?l=Kotlin" - }, - "KRL": { - "color": "#28430A", - "url": "https://github.com/trending?l=KRL" - }, - "LabVIEW": { - "color": null, - "url": "https://github.com/trending?l=LabVIEW" - }, - "Lasso": { - "color": "#999999", - "url": "https://github.com/trending?l=Lasso" - }, - "Latte": { - "color": "#f2a542", - "url": "https://github.com/trending?l=Latte" - }, - "Lean": { - "color": null, - "url": "https://github.com/trending?l=Lean" - }, - "Less": { - "color": "#1d365d", - "url": "https://github.com/trending?l=Less" - }, - "Lex": { - "color": "#DBCA00", - "url": "https://github.com/trending?l=Lex" - }, - "LFE": { - "color": "#4C3023", - "url": "https://github.com/trending?l=LFE" - }, - "LilyPond": { - "color": null, - "url": "https://github.com/trending?l=LilyPond" - }, - "Limbo": { - "color": null, - "url": "https://github.com/trending?l=Limbo" - }, - "Literate Agda": { - "color": null, - "url": "https://github.com/trending?l=Literate-Agda" - }, - "Literate CoffeeScript": { - "color": null, - "url": "https://github.com/trending?l=Literate-CoffeeScript" - }, - "Literate Haskell": { - "color": null, - "url": "https://github.com/trending?l=Literate-Haskell" - }, - "LiveScript": { - "color": "#499886", - "url": "https://github.com/trending?l=LiveScript" - }, - "LLVM": { - "color": "#185619", - "url": "https://github.com/trending?l=LLVM" - }, - "Logos": { - "color": null, - "url": "https://github.com/trending?l=Logos" - }, - "Logtalk": { - "color": null, - "url": "https://github.com/trending?l=Logtalk" - }, - "LOLCODE": { - "color": "#cc9900", - "url": "https://github.com/trending?l=LOLCODE" - }, - "LookML": { - "color": "#652B81", - "url": "https://github.com/trending?l=LookML" - }, - "LoomScript": { - "color": null, - "url": "https://github.com/trending?l=LoomScript" - }, - "LSL": { - "color": "#3d9970", - "url": "https://github.com/trending?l=LSL" - }, - "Lua": { - "color": "#000080", - "url": "https://github.com/trending?l=Lua" - }, - "M": { - "color": null, - "url": "https://github.com/trending?l=M" - }, - "M4": { - "color": null, - "url": "https://github.com/trending?l=M4" - }, - "M4Sugar": { - "color": null, - "url": "https://github.com/trending?l=M4Sugar" - }, - "Macaulay2": { - "color": "#d8ffff", - "url": "https://github.com/trending?l=Macaulay2" - }, - "Makefile": { - "color": "#427819", - "url": "https://github.com/trending?l=Makefile" - }, - "Mako": { - "color": null, - "url": "https://github.com/trending?l=Mako" - }, - "Markdown": { - "color": "#083fa1", - "url": "https://github.com/trending?l=Markdown" - }, - "Marko": { - "color": "#42bff2", - "url": "https://github.com/trending?l=Marko" - }, - "Mask": { - "color": "#f97732", - "url": "https://github.com/trending?l=Mask" - }, - "Mathematica": { - "color": null, - "url": "https://github.com/trending?l=Mathematica" - }, - "MATLAB": { - "color": "#e16737", - "url": "https://github.com/trending?l=MATLAB" - }, - "Max": { - "color": "#c4a79c", - "url": "https://github.com/trending?l=Max" - }, - "MAXScript": { - "color": "#00a6a6", - "url": "https://github.com/trending?l=MAXScript" - }, - "mcfunction": { - "color": "#E22837", - "url": "https://github.com/trending?l=mcfunction" - }, - "Mercury": { - "color": "#ff2b2b", - "url": "https://github.com/trending?l=Mercury" - }, - "Meson": { - "color": "#007800", - "url": "https://github.com/trending?l=Meson" - }, - "Metal": { - "color": "#8f14e9", - "url": "https://github.com/trending?l=Metal" - }, - "MiniD": { - "color": null, - "url": "https://github.com/trending?l=MiniD" - }, - "Mirah": { - "color": "#c7a938", - "url": "https://github.com/trending?l=Mirah" - }, - "mIRC Script": { - "color": "#3d57c3", - "url": "https://github.com/trending?l=mIRC-Script" - }, - "MLIR": { - "color": "#5EC8DB", - "url": "https://github.com/trending?l=MLIR" - }, - "Modelica": { - "color": null, - "url": "https://github.com/trending?l=Modelica" - }, - "Modula-2": { - "color": null, - "url": "https://github.com/trending?l=Modula-2" - }, - "Modula-3": { - "color": "#223388", - "url": "https://github.com/trending?l=Modula-3" - }, - "Module Management System": { - "color": null, - "url": "https://github.com/trending?l=Module-Management-System" - }, - "Monkey": { - "color": null, - "url": "https://github.com/trending?l=Monkey" - }, - "Moocode": { - "color": null, - "url": "https://github.com/trending?l=Moocode" - }, - "MoonScript": { - "color": null, - "url": "https://github.com/trending?l=MoonScript" - }, - "Motorola 68K Assembly": { - "color": null, - "url": "https://github.com/trending?l=Motorola-68K-Assembly" - }, - "MQL4": { - "color": "#62A8D6", - "url": "https://github.com/trending?l=MQL4" - }, - "MQL5": { - "color": "#4A76B8", - "url": "https://github.com/trending?l=MQL5" - }, - "MTML": { - "color": "#b7e1f4", - "url": "https://github.com/trending?l=MTML" - }, - "MUF": { - "color": null, - "url": "https://github.com/trending?l=MUF" - }, - "mupad": { - "color": null, - "url": "https://github.com/trending?l=mupad" - }, - "Myghty": { - "color": null, - "url": "https://github.com/trending?l=Myghty" - }, - "NASL": { - "color": null, - "url": "https://github.com/trending?l=NASL" - }, - "NCL": { - "color": "#28431f", - "url": "https://github.com/trending?l=NCL" - }, - "Nearley": { - "color": "#990000", - "url": "https://github.com/trending?l=Nearley" - }, - "Nemerle": { - "color": "#3d3c6e", - "url": "https://github.com/trending?l=Nemerle" - }, - "nesC": { - "color": "#94B0C7", - "url": "https://github.com/trending?l=nesC" - }, - "NetLinx": { - "color": "#0aa0ff", - "url": "https://github.com/trending?l=NetLinx" - }, - "NetLinx+ERB": { - "color": "#747faa", - "url": "https://github.com/trending?l=NetLinx+ERB" - }, - "NetLogo": { - "color": "#ff6375", - "url": "https://github.com/trending?l=NetLogo" - }, - "NewLisp": { - "color": "#87AED7", - "url": "https://github.com/trending?l=NewLisp" - }, - "Nextflow": { - "color": "#3ac486", - "url": "https://github.com/trending?l=Nextflow" - }, - "Nim": { - "color": "#ffc200", - "url": "https://github.com/trending?l=Nim" - }, - "Nit": { - "color": "#009917", - "url": "https://github.com/trending?l=Nit" - }, - "Nix": { - "color": "#7e7eff", - "url": "https://github.com/trending?l=Nix" - }, - "NSIS": { - "color": null, - "url": "https://github.com/trending?l=NSIS" - }, - "Nu": { - "color": "#c9df40", - "url": "https://github.com/trending?l=Nu" - }, - "NumPy": { - "color": null, - "url": "https://github.com/trending?l=NumPy" - }, - "Objective-C": { - "color": "#438eff", - "url": "https://github.com/trending?l=Objective-C" - }, - "Objective-C++": { - "color": "#6866fb", - "url": "https://github.com/trending?l=Objective-C++" - }, - "Objective-J": { - "color": "#ff0c5a", - "url": "https://github.com/trending?l=Objective-J" - }, - "ObjectScript": { - "color": "#424893", - "url": "https://github.com/trending?l=ObjectScript" - }, - "OCaml": { - "color": "#3be133", - "url": "https://github.com/trending?l=OCaml" - }, - "Odin": { - "color": "#60AFFE", - "url": "https://github.com/trending?l=Odin" - }, - "Omgrofl": { - "color": "#cabbff", - "url": "https://github.com/trending?l=Omgrofl" - }, - "ooc": { - "color": "#b0b77e", - "url": "https://github.com/trending?l=ooc" - }, - "Opa": { - "color": null, - "url": "https://github.com/trending?l=Opa" - }, - "Opal": { - "color": "#f7ede0", - "url": "https://github.com/trending?l=Opal" - }, - "Open Policy Agent": { - "color": null, - "url": "https://github.com/trending?l=Open-Policy-Agent" - }, - "OpenCL": { - "color": null, - "url": "https://github.com/trending?l=OpenCL" - }, - "OpenEdge ABL": { - "color": null, - "url": "https://github.com/trending?l=OpenEdge-ABL" - }, - "OpenQASM": { - "color": "#AA70FF", - "url": "https://github.com/trending?l=OpenQASM" - }, - "OpenRC runscript": { - "color": null, - "url": "https://github.com/trending?l=OpenRC-runscript" - }, - "OpenSCAD": { - "color": null, - "url": "https://github.com/trending?l=OpenSCAD" - }, - "Ox": { - "color": null, - "url": "https://github.com/trending?l=Ox" - }, - "Oxygene": { - "color": "#cdd0e3", - "url": "https://github.com/trending?l=Oxygene" - }, - "Oz": { - "color": "#fab738", - "url": "https://github.com/trending?l=Oz" - }, - "P4": { - "color": "#7055b5", - "url": "https://github.com/trending?l=P4" - }, - "Pan": { - "color": "#cc0000", - "url": "https://github.com/trending?l=Pan" - }, - "Papyrus": { - "color": "#6600cc", - "url": "https://github.com/trending?l=Papyrus" - }, - "Parrot": { - "color": "#f3ca0a", - "url": "https://github.com/trending?l=Parrot" - }, - "Parrot Assembly": { - "color": null, - "url": "https://github.com/trending?l=Parrot-Assembly" - }, - "Parrot Internal Representation": { - "color": null, - "url": "https://github.com/trending?l=Parrot-Internal-Representation" - }, - "Pascal": { - "color": "#E3F171", - "url": "https://github.com/trending?l=Pascal" - }, - "Pawn": { - "color": "#dbb284", - "url": "https://github.com/trending?l=Pawn" - }, - "Pep8": { - "color": "#C76F5B", - "url": "https://github.com/trending?l=Pep8" - }, - "Perl": { - "color": "#0298c3", - "url": "https://github.com/trending?l=Perl" - }, - "PHP": { - "color": "#4F5D95", - "url": "https://github.com/trending?l=PHP" - }, - "PicoLisp": { - "color": null, - "url": "https://github.com/trending?l=PicoLisp" - }, - "PigLatin": { - "color": "#fcd7de", - "url": "https://github.com/trending?l=PigLatin" - }, - "Pike": { - "color": "#005390", - "url": "https://github.com/trending?l=Pike" - }, - "PLpgSQL": { - "color": null, - "url": "https://github.com/trending?l=PLpgSQL" - }, - "PLSQL": { - "color": "#dad8d8", - "url": "https://github.com/trending?l=PLSQL" - }, - "PogoScript": { - "color": "#d80074", - "url": "https://github.com/trending?l=PogoScript" - }, - "Pony": { - "color": null, - "url": "https://github.com/trending?l=Pony" - }, - "PostScript": { - "color": "#da291c", - "url": "https://github.com/trending?l=PostScript" - }, - "POV-Ray SDL": { - "color": null, - "url": "https://github.com/trending?l=POV-Ray-SDL" - }, - "PowerBuilder": { - "color": "#8f0f8d", - "url": "https://github.com/trending?l=PowerBuilder" - }, - "PowerShell": { - "color": "#012456", - "url": "https://github.com/trending?l=PowerShell" - }, - "Prisma": { - "color": "#0c344b", - "url": "https://github.com/trending?l=Prisma" - }, - "Processing": { - "color": "#0096D8", - "url": "https://github.com/trending?l=Processing" - }, - "Prolog": { - "color": "#74283c", - "url": "https://github.com/trending?l=Prolog" - }, - "Propeller Spin": { - "color": "#7fa2a7", - "url": "https://github.com/trending?l=Propeller-Spin" - }, - "Pug": { - "color": "#a86454", - "url": "https://github.com/trending?l=Pug" - }, - "Puppet": { - "color": "#302B6D", - "url": "https://github.com/trending?l=Puppet" - }, - "PureBasic": { - "color": "#5a6986", - "url": "https://github.com/trending?l=PureBasic" - }, - "PureScript": { - "color": "#1D222D", - "url": "https://github.com/trending?l=PureScript" - }, - "Python": { - "color": "#3572A5", - "url": "https://github.com/trending?l=Python" - }, - "Python console": { - "color": null, - "url": "https://github.com/trending?l=Python-console" - }, - "q": { - "color": "#0040cd", - "url": "https://github.com/trending?l=q" - }, - "Q#": { - "color": "#fed659", - "url": "https://github.com/trending?l=Qsharp" - }, - "QMake": { - "color": null, - "url": "https://github.com/trending?l=QMake" - }, - "QML": { - "color": "#44a51c", - "url": "https://github.com/trending?l=QML" - }, - "Qt Script": { - "color": "#00b841", - "url": "https://github.com/trending?l=Qt-Script" - }, - "Quake": { - "color": "#882233", - "url": "https://github.com/trending?l=Quake" - }, - "R": { - "color": "#198CE7", - "url": "https://github.com/trending?l=R" - }, - "Racket": { - "color": "#3c5caa", - "url": "https://github.com/trending?l=Racket" - }, - "Ragel": { - "color": "#9d5200", - "url": "https://github.com/trending?l=Ragel" - }, - "Raku": { - "color": "#0000fb", - "url": "https://github.com/trending?l=Raku" - }, - "RAML": { - "color": "#77d9fb", - "url": "https://github.com/trending?l=RAML" - }, - "Rascal": { - "color": "#fffaa0", - "url": "https://github.com/trending?l=Rascal" - }, - "REALbasic": { - "color": null, - "url": "https://github.com/trending?l=REALbasic" - }, - "Reason": { - "color": "#ff5847", - "url": "https://github.com/trending?l=Reason" - }, - "Rebol": { - "color": "#358a5b", - "url": "https://github.com/trending?l=Rebol" - }, - "Red": { - "color": "#f50000", - "url": "https://github.com/trending?l=Red" - }, - "Redcode": { - "color": null, - "url": "https://github.com/trending?l=Redcode" - }, - "Ren'Py": { - "color": "#ff7f7f", - "url": "https://github.com/trending?l=Ren'Py" - }, - "RenderScript": { - "color": null, - "url": "https://github.com/trending?l=RenderScript" - }, - "REXX": { - "color": null, - "url": "https://github.com/trending?l=REXX" - }, - "Ring": { - "color": "#2D54CB", - "url": "https://github.com/trending?l=Ring" - }, - "Riot": { - "color": "#A71E49", - "url": "https://github.com/trending?l=Riot" - }, - "RobotFramework": { - "color": null, - "url": "https://github.com/trending?l=RobotFramework" - }, - "Roff": { - "color": "#ecdebe", - "url": "https://github.com/trending?l=Roff" - }, - "Rouge": { - "color": "#cc0088", - "url": "https://github.com/trending?l=Rouge" - }, - "RPC": { - "color": null, - "url": "https://github.com/trending?l=RPC" - }, - "Ruby": { - "color": "#701516", - "url": "https://github.com/trending?l=Ruby" - }, - "RUNOFF": { - "color": "#665a4e", - "url": "https://github.com/trending?l=RUNOFF" - }, - "Rust": { - "color": "#dea584", - "url": "https://github.com/trending?l=Rust" - }, - "Sage": { - "color": null, - "url": "https://github.com/trending?l=Sage" - }, - "SaltStack": { - "color": "#646464", - "url": "https://github.com/trending?l=SaltStack" - }, - "SAS": { - "color": "#B34936", - "url": "https://github.com/trending?l=SAS" - }, - "Sass": { - "color": "#a53b70", - "url": "https://github.com/trending?l=Sass" - }, - "Scala": { - "color": "#c22d40", - "url": "https://github.com/trending?l=Scala" - }, - "Scheme": { - "color": "#1e4aec", - "url": "https://github.com/trending?l=Scheme" - }, - "Scilab": { - "color": null, - "url": "https://github.com/trending?l=Scilab" - }, - "SCSS": { - "color": "#c6538c", - "url": "https://github.com/trending?l=SCSS" - }, - "sed": { - "color": "#64b970", - "url": "https://github.com/trending?l=sed" - }, - "Self": { - "color": "#0579aa", - "url": "https://github.com/trending?l=Self" - }, - "ShaderLab": { - "color": null, - "url": "https://github.com/trending?l=ShaderLab" - }, - "Shell": { - "color": "#89e051", - "url": "https://github.com/trending?l=Shell" - }, - "ShellSession": { - "color": null, - "url": "https://github.com/trending?l=ShellSession" - }, - "Shen": { - "color": "#120F14", - "url": "https://github.com/trending?l=Shen" - }, - "Sieve": { - "color": null, - "url": "https://github.com/trending?l=Sieve" - }, - "Slash": { - "color": "#007eff", - "url": "https://github.com/trending?l=Slash" - }, - "Slice": { - "color": "#003fa2", - "url": "https://github.com/trending?l=Slice" - }, - "Slim": { - "color": "#2b2b2b", - "url": "https://github.com/trending?l=Slim" - }, - "Smali": { - "color": null, - "url": "https://github.com/trending?l=Smali" - }, - "Smalltalk": { - "color": "#596706", - "url": "https://github.com/trending?l=Smalltalk" - }, - "Smarty": { - "color": null, - "url": "https://github.com/trending?l=Smarty" - }, - "SmPL": { - "color": "#c94949", - "url": "https://github.com/trending?l=SmPL" - }, - "SMT": { - "color": null, - "url": "https://github.com/trending?l=SMT" - }, - "Solidity": { - "color": "#AA6746", - "url": "https://github.com/trending?l=Solidity" - }, - "SourcePawn": { - "color": "#f69e1d", - "url": "https://github.com/trending?l=SourcePawn" - }, - "SQF": { - "color": "#3F3F3F", - "url": "https://github.com/trending?l=SQF" - }, - "SQLPL": { - "color": null, - "url": "https://github.com/trending?l=SQLPL" - }, - "Squirrel": { - "color": "#800000", - "url": "https://github.com/trending?l=Squirrel" - }, - "SRecode Template": { - "color": "#348a34", - "url": "https://github.com/trending?l=SRecode-Template" - }, - "Stan": { - "color": "#b2011d", - "url": "https://github.com/trending?l=Stan" - }, - "Standard ML": { - "color": "#dc566d", - "url": "https://github.com/trending?l=Standard-ML" - }, - "Starlark": { - "color": "#76d275", - "url": "https://github.com/trending?l=Starlark" - }, - "Stata": { - "color": null, - "url": "https://github.com/trending?l=Stata" - }, - "Stylus": { - "color": "#ff6347", - "url": "https://github.com/trending?l=Stylus" - }, - "SuperCollider": { - "color": "#46390b", - "url": "https://github.com/trending?l=SuperCollider" - }, - "Svelte": { - "color": "#ff3e00", - "url": "https://github.com/trending?l=Svelte" - }, - "SVG": { - "color": "#ff9900", - "url": "https://github.com/trending?l=SVG" - }, - "Swift": { - "color": "#ffac45", - "url": "https://github.com/trending?l=Swift" - }, - "SWIG": { - "color": null, - "url": "https://github.com/trending?l=SWIG" - }, - "SystemVerilog": { - "color": "#DAE1C2", - "url": "https://github.com/trending?l=SystemVerilog" - }, - "Tcl": { - "color": "#e4cc98", - "url": "https://github.com/trending?l=Tcl" - }, - "Tcsh": { - "color": null, - "url": "https://github.com/trending?l=Tcsh" - }, - "Terra": { - "color": "#00004c", - "url": "https://github.com/trending?l=Terra" - }, - "TeX": { - "color": "#3D6117", - "url": "https://github.com/trending?l=TeX" - }, - "Thrift": { - "color": null, - "url": "https://github.com/trending?l=Thrift" - }, - "TI Program": { - "color": "#A0AA87", - "url": "https://github.com/trending?l=TI-Program" - }, - "TLA": { - "color": null, - "url": "https://github.com/trending?l=TLA" - }, - "TSQL": { - "color": null, - "url": "https://github.com/trending?l=TSQL" - }, - "TSX": { - "color": null, - "url": "https://github.com/trending?l=TSX" - }, - "Turing": { - "color": "#cf142b", - "url": "https://github.com/trending?l=Turing" - }, - "Twig": { - "color": "#c1d026", - "url": "https://github.com/trending?l=Twig" - }, - "TXL": { - "color": null, - "url": "https://github.com/trending?l=TXL" - }, - "TypeScript": { - "color": "#2b7489", - "url": "https://github.com/trending?l=TypeScript" - }, - "TypeScript (JSX)": { - "color": "#2b7489", - "url": "https://github.com/trending?l=TypeScript" - }, - "Unified Parallel C": { - "color": null, - "url": "https://github.com/trending?l=Unified-Parallel-C" - }, - "Unix Assembly": { - "color": null, - "url": "https://github.com/trending?l=Unix-Assembly" - }, - "Uno": { - "color": "#9933cc", - "url": "https://github.com/trending?l=Uno" - }, - "UnrealScript": { - "color": "#a54c4d", - "url": "https://github.com/trending?l=UnrealScript" - }, - "UrWeb": { - "color": null, - "url": "https://github.com/trending?l=UrWeb" - }, - "V": { - "color": "#4f87c4", - "url": "https://github.com/trending?l=V" - }, - "Vala": { - "color": "#fbe5cd", - "url": "https://github.com/trending?l=Vala" - }, - "VBA": { - "color": "#867db1", - "url": "https://github.com/trending?l=VBA" - }, - "VBScript": { - "color": "#15dcdc", - "url": "https://github.com/trending?l=VBScript" - }, - "VCL": { - "color": "#148AA8", - "url": "https://github.com/trending?l=VCL" - }, - "Verilog": { - "color": "#b2b7f8", - "url": "https://github.com/trending?l=Verilog" - }, - "VHDL": { - "color": "#adb2cb", - "url": "https://github.com/trending?l=VHDL" - }, - "Vim script": { - "color": "#199f4b", - "url": "https://github.com/trending?l=Vim-script" - }, - "Visual Basic .NET": { - "color": "#945db7", - "url": "https://github.com/trending?l=Visual-Basic-.NET" - }, - "Volt": { - "color": "#1F1F1F", - "url": "https://github.com/trending?l=Volt" - }, - "Vue": { - "color": "#2c3e50", - "url": "https://github.com/trending?l=Vue" - }, - "wdl": { - "color": "#42f1f4", - "url": "https://github.com/trending?l=wdl" - }, - "WebAssembly": { - "color": "#04133b", - "url": "https://github.com/trending?l=WebAssembly" - }, - "WebIDL": { - "color": null, - "url": "https://github.com/trending?l=WebIDL" - }, - "wisp": { - "color": "#7582D1", - "url": "https://github.com/trending?l=wisp" - }, - "Wollok": { - "color": "#a23738", - "url": "https://github.com/trending?l=Wollok" - }, - "X10": { - "color": "#4B6BEF", - "url": "https://github.com/trending?l=X10" - }, - "xBase": { - "color": "#403a40", - "url": "https://github.com/trending?l=xBase" - }, - "XC": { - "color": "#99DA07", - "url": "https://github.com/trending?l=XC" - }, - "Xojo": { - "color": null, - "url": "https://github.com/trending?l=Xojo" - }, - "XProc": { - "color": null, - "url": "https://github.com/trending?l=XProc" - }, - "XQuery": { - "color": "#5232e7", - "url": "https://github.com/trending?l=XQuery" - }, - "XS": { - "color": null, - "url": "https://github.com/trending?l=XS" - }, - "XSLT": { - "color": "#EB8CEB", - "url": "https://github.com/trending?l=XSLT" - }, - "Xtend": { - "color": null, - "url": "https://github.com/trending?l=Xtend" - }, - "Yacc": { - "color": "#4B6C4B", - "url": "https://github.com/trending?l=Yacc" - }, - "YAML": { - "color": "#cb171e", - "url": "https://github.com/trending?l=YAML" - }, - "YARA": { - "color": "#220000", - "url": "https://github.com/trending?l=YARA" - }, - "YASnippet": { - "color": "#32AB90", - "url": "https://github.com/trending?l=YASnippet" - }, - "ZAP": { - "color": "#0d665e", - "url": "https://github.com/trending?l=ZAP" - }, - "Zeek": { - "color": null, - "url": "https://github.com/trending?l=Zeek" - }, - "ZenScript": { - "color": "#00BCD1", - "url": "https://github.com/trending?l=ZenScript" - }, - "Zephir": { - "color": "#118f9e", - "url": "https://github.com/trending?l=Zephir" - }, - "Zig": { - "color": "#ec915c", - "url": "https://github.com/trending?l=Zig" - }, - "ZIL": { - "color": "#dc75e5", - "url": "https://github.com/trending?l=ZIL" - }, - "Zimpl": { - "color": null, - "url": "https://github.com/trending?l=Zimpl" - } -} diff --git a/themes/language-bar.json b/themes/language-bar.json new file mode 100644 index 0000000..79a4a2c --- /dev/null +++ b/themes/language-bar.json @@ -0,0 +1,1710 @@ +{ + "1C Enterprise": { + "color": "#814CCC", + "url": "https://github.com/trending?l=1C-Enterprise" + }, + "4D": { + "color": null, + "url": "https://github.com/trending?l=4D" + }, + "ABAP": { + "color": "#E8274B", + "url": "https://github.com/trending?l=ABAP" + }, + "ActionScript": { + "color": "#882B0F", + "url": "https://github.com/trending?l=ActionScript" + }, + "Ada": { + "color": "#02f88c", + "url": "https://github.com/trending?l=Ada" + }, + "Agda": { + "color": "#315665", + "url": "https://github.com/trending?l=Agda" + }, + "AGS Script": { + "color": "#B9D9FF", + "url": "https://github.com/trending?l=AGS-Script" + }, + "AL Code": { + "color": "#3AA2B5", + "url": "https://github.com/trending?l=AL-Code" + }, + "Alloy": { + "color": "#64C800", + "url": "https://github.com/trending?l=Alloy" + }, + "Alpine Abuild": { + "color": null, + "url": "https://github.com/trending?l=Alpine-Abuild" + }, + "AMPL": { + "color": "#E6EFBB", + "url": "https://github.com/trending?l=AMPL" + }, + "AngelScript": { + "color": "#C7D7DC", + "url": "https://github.com/trending?l=AngelScript" + }, + "ANTLR": { + "color": "#9DC3FF", + "url": "https://github.com/trending?l=ANTLR" + }, + "Apex": { + "color": "#1797c0", + "url": "https://github.com/trending?l=Apex" + }, + "API Blueprint": { + "color": "#2ACCA8", + "url": "https://github.com/trending?l=API-Blueprint" + }, + "APL": { + "color": "#5A8164", + "url": "https://github.com/trending?l=APL" + }, + "Apollo Guidance Computer": { + "color": null, + "url": "https://github.com/trending?l=Apollo-Guidance-Computer" + }, + "AppleScript": { + "color": "#101F1F", + "url": "https://github.com/trending?l=AppleScript" + }, + "Arc": { + "color": "#aa2afe", + "url": "https://github.com/trending?l=Arc" + }, + "ASL": { + "color": null, + "url": "https://github.com/trending?l=ASL" + }, + "ASP.NET": { + "color": "#9400ff", + "url": "https://github.com/trending?l=ASP.NET" + }, + "AspectJ": { + "color": "#a957b0", + "url": "https://github.com/trending?l=AspectJ" + }, + "Assembly": { + "color": "#6E4C13", + "url": "https://github.com/trending?l=Assembly" + }, + "Asymptote": { + "color": "#ff0000", + "url": "https://github.com/trending?l=Asymptote" + }, + "ATS": { + "color": "#1ac620", + "url": "https://github.com/trending?l=ATS" + }, + "Augeas": { + "color": null, + "url": "https://github.com/trending?l=Augeas" + }, + "AutoHotkey": { + "color": "#6594b9", + "url": "https://github.com/trending?l=AutoHotkey" + }, + "AutoIt": { + "color": "#1C3552", + "url": "https://github.com/trending?l=AutoIt" + }, + "Awk": { + "color": null, + "url": "https://github.com/trending?l=Awk" + }, + "Ballerina": { + "color": "#FF5000", + "url": "https://github.com/trending?l=Ballerina" + }, + "Batchfile": { + "color": "#C1F12E", + "url": "https://github.com/trending?l=Batchfile" + }, + "Befunge": { + "color": null, + "url": "https://github.com/trending?l=Befunge" + }, + "Bison": { + "color": null, + "url": "https://github.com/trending?l=Bison" + }, + "BitBake": { + "color": null, + "url": "https://github.com/trending?l=BitBake" + }, + "Blade": { + "color": "#f7523f", + "url": "https://github.com/trending?l=Blade" + }, + "BlitzBasic": { + "color": null, + "url": "https://github.com/trending?l=BlitzBasic" + }, + "BlitzMax": { + "color": "#cd6400", + "url": "https://github.com/trending?l=BlitzMax" + }, + "Bluespec": { + "color": null, + "url": "https://github.com/trending?l=Bluespec" + }, + "Boo": { + "color": "#d4bec1", + "url": "https://github.com/trending?l=Boo" + }, + "Brainfuck": { + "color": "#2F2530", + "url": "https://github.com/trending?l=Brainfuck" + }, + "Brightscript": { + "color": null, + "url": "https://github.com/trending?l=Brightscript" + }, + "C": { + "color": "#555555", + "url": "https://github.com/trending?l=C" + }, + "C#": { + "color": "#178600", + "url": "https://github.com/trending?l=Csharp" + }, + "C++": { + "color": "#f34b7d", + "url": "https://github.com/trending?l=C++" + }, + "C2hs Haskell": { + "color": null, + "url": "https://github.com/trending?l=C2hs-Haskell" + }, + "Cap'n Proto": { + "color": null, + "url": "https://github.com/trending?l=Cap'n-Proto" + }, + "CartoCSS": { + "color": null, + "url": "https://github.com/trending?l=CartoCSS" + }, + "Ceylon": { + "color": "#dfa535", + "url": "https://github.com/trending?l=Ceylon" + }, + "Chapel": { + "color": "#8dc63f", + "url": "https://github.com/trending?l=Chapel" + }, + "Charity": { + "color": null, + "url": "https://github.com/trending?l=Charity" + }, + "ChucK": { + "color": null, + "url": "https://github.com/trending?l=ChucK" + }, + "Cirru": { + "color": "#ccccff", + "url": "https://github.com/trending?l=Cirru" + }, + "Clarion": { + "color": "#db901e", + "url": "https://github.com/trending?l=Clarion" + }, + "Classic ASP": { + "color": "#6a40fd", + "url": "https://github.com/trending?l=Classic-ASP" + }, + "Clean": { + "color": "#3F85AF", + "url": "https://github.com/trending?l=Clean" + }, + "Click": { + "color": "#E4E6F3", + "url": "https://github.com/trending?l=Click" + }, + "CLIPS": { + "color": null, + "url": "https://github.com/trending?l=CLIPS" + }, + "Clojure": { + "color": "#db5855", + "url": "https://github.com/trending?l=Clojure" + }, + "CMake": { + "color": null, + "url": "https://github.com/trending?l=CMake" + }, + "COBOL": { + "color": null, + "url": "https://github.com/trending?l=COBOL" + }, + "CodeQL": { + "color": null, + "url": "https://github.com/trending?l=CodeQL" + }, + "CoffeeScript": { + "color": "#244776", + "url": "https://github.com/trending?l=CoffeeScript" + }, + "ColdFusion": { + "color": "#ed2cd6", + "url": "https://github.com/trending?l=ColdFusion" + }, + "ColdFusion CFC": { + "color": null, + "url": "https://github.com/trending?l=ColdFusion-CFC" + }, + "Common Lisp": { + "color": "#3fb68b", + "url": "https://github.com/trending?l=Common-Lisp" + }, + "Common Workflow Language": { + "color": "#B5314C", + "url": "https://github.com/trending?l=Common-Workflow-Language" + }, + "Component Pascal": { + "color": "#B0CE4E", + "url": "https://github.com/trending?l=Component-Pascal" + }, + "Cool": { + "color": null, + "url": "https://github.com/trending?l=Cool" + }, + "Coq": { + "color": null, + "url": "https://github.com/trending?l=Coq" + }, + "Crystal": { + "color": "#000100", + "url": "https://github.com/trending?l=Crystal" + }, + "CSON": { + "color": "#244776", + "url": "https://github.com/trending?l=CSON" + }, + "Csound": { + "color": null, + "url": "https://github.com/trending?l=Csound" + }, + "Csound Document": { + "color": null, + "url": "https://github.com/trending?l=Csound-Document" + }, + "Csound Score": { + "color": null, + "url": "https://github.com/trending?l=Csound-Score" + }, + "CSS": { + "color": "#563d7c", + "url": "https://github.com/trending?l=CSS" + }, + "Cuda": { + "color": "#3A4E3A", + "url": "https://github.com/trending?l=Cuda" + }, + "CWeb": { + "color": null, + "url": "https://github.com/trending?l=CWeb" + }, + "Cycript": { + "color": null, + "url": "https://github.com/trending?l=Cycript" + }, + "Cython": { + "color": null, + "url": "https://github.com/trending?l=Cython" + }, + "D": { + "color": "#ba595e", + "url": "https://github.com/trending?l=D" + }, + "Dafny": { + "color": "#FFEC25", + "url": "https://github.com/trending?l=Dafny" + }, + "Dart": { + "color": "#00B4AB", + "url": "https://github.com/trending?l=Dart" + }, + "DataWeave": { + "color": "#003a52", + "url": "https://github.com/trending?l=DataWeave" + }, + "Dhall": { + "color": "#dfafff", + "url": "https://github.com/trending?l=Dhall" + }, + "DIGITAL Command Language": { + "color": null, + "url": "https://github.com/trending?l=DIGITAL-Command-Language" + }, + "DM": { + "color": "#447265", + "url": "https://github.com/trending?l=DM" + }, + "Dockerfile": { + "color": "#384d54", + "url": "https://github.com/trending?l=Dockerfile" + }, + "Dogescript": { + "color": "#cca760", + "url": "https://github.com/trending?l=Dogescript" + }, + "DTrace": { + "color": null, + "url": "https://github.com/trending?l=DTrace" + }, + "Dylan": { + "color": "#6c616e", + "url": "https://github.com/trending?l=Dylan" + }, + "E": { + "color": "#ccce35", + "url": "https://github.com/trending?l=E" + }, + "eC": { + "color": "#913960", + "url": "https://github.com/trending?l=eC" + }, + "ECL": { + "color": "#8a1267", + "url": "https://github.com/trending?l=ECL" + }, + "ECLiPSe": { + "color": null, + "url": "https://github.com/trending?l=ECLiPSe" + }, + "Eiffel": { + "color": "#4d6977", + "url": "https://github.com/trending?l=Eiffel" + }, + "Elixir": { + "color": "#6e4a7e", + "url": "https://github.com/trending?l=Elixir" + }, + "Elm": { + "color": "#60B5CC", + "url": "https://github.com/trending?l=Elm" + }, + "Emacs Lisp": { + "color": "#c065db", + "url": "https://github.com/trending?l=Emacs-Lisp" + }, + "EmberScript": { + "color": "#FFF4F3", + "url": "https://github.com/trending?l=EmberScript" + }, + "EQ": { + "color": "#a78649", + "url": "https://github.com/trending?l=EQ" + }, + "Erlang": { + "color": "#B83998", + "url": "https://github.com/trending?l=Erlang" + }, + "F#": { + "color": "#b845fc", + "url": "https://github.com/trending?l=Fsharp" + }, + "F*": { + "color": "#572e30", + "url": "https://github.com/trending?l=F*" + }, + "Factor": { + "color": "#636746", + "url": "https://github.com/trending?l=Factor" + }, + "Fancy": { + "color": "#7b9db4", + "url": "https://github.com/trending?l=Fancy" + }, + "Fantom": { + "color": "#14253c", + "url": "https://github.com/trending?l=Fantom" + }, + "Faust": { + "color": "#c37240", + "url": "https://github.com/trending?l=Faust" + }, + "Filebench WML": { + "color": null, + "url": "https://github.com/trending?l=Filebench-WML" + }, + "Filterscript": { + "color": null, + "url": "https://github.com/trending?l=Filterscript" + }, + "fish": { + "color": null, + "url": "https://github.com/trending?l=fish" + }, + "FLUX": { + "color": "#88ccff", + "url": "https://github.com/trending?l=FLUX" + }, + "Forth": { + "color": "#341708", + "url": "https://github.com/trending?l=Forth" + }, + "Fortran": { + "color": "#4d41b1", + "url": "https://github.com/trending?l=Fortran" + }, + "Fortran Free Form": { + "color": null, + "url": "https://github.com/trending?l=Fortran-Free-Form" + }, + "FreeMarker": { + "color": "#0050b2", + "url": "https://github.com/trending?l=FreeMarker" + }, + "Frege": { + "color": "#00cafe", + "url": "https://github.com/trending?l=Frege" + }, + "Futhark": { + "color": "#5f021f", + "url": "https://github.com/trending?l=Futhark" + }, + "G-code": { + "color": "#D08CF2", + "url": "https://github.com/trending?l=G-code" + }, + "Game Maker Language": { + "color": "#71b417", + "url": "https://github.com/trending?l=Game-Maker-Language" + }, + "GAML": { + "color": "#FFC766", + "url": "https://github.com/trending?l=GAML" + }, + "GAMS": { + "color": null, + "url": "https://github.com/trending?l=GAMS" + }, + "GAP": { + "color": null, + "url": "https://github.com/trending?l=GAP" + }, + "GCC Machine Description": { + "color": null, + "url": "https://github.com/trending?l=GCC-Machine-Description" + }, + "GDB": { + "color": null, + "url": "https://github.com/trending?l=GDB" + }, + "GDScript": { + "color": "#355570", + "url": "https://github.com/trending?l=GDScript" + }, + "Genie": { + "color": "#fb855d", + "url": "https://github.com/trending?l=Genie" + }, + "Genshi": { + "color": null, + "url": "https://github.com/trending?l=Genshi" + }, + "Gentoo Ebuild": { + "color": null, + "url": "https://github.com/trending?l=Gentoo-Ebuild" + }, + "Gentoo Eclass": { + "color": null, + "url": "https://github.com/trending?l=Gentoo-Eclass" + }, + "Gherkin": { + "color": "#5B2063", + "url": "https://github.com/trending?l=Gherkin" + }, + "GLSL": { + "color": null, + "url": "https://github.com/trending?l=GLSL" + }, + "Glyph": { + "color": "#c1ac7f", + "url": "https://github.com/trending?l=Glyph" + }, + "Gnuplot": { + "color": "#f0a9f0", + "url": "https://github.com/trending?l=Gnuplot" + }, + "Go": { + "color": "#00ADD8", + "url": "https://github.com/trending?l=Go" + }, + "Golo": { + "color": "#88562A", + "url": "https://github.com/trending?l=Golo" + }, + "Gosu": { + "color": "#82937f", + "url": "https://github.com/trending?l=Gosu" + }, + "Grace": { + "color": null, + "url": "https://github.com/trending?l=Grace" + }, + "Grammatical Framework": { + "color": "#ff0000", + "url": "https://github.com/trending?l=Grammatical-Framework" + }, + "Groovy": { + "color": "#e69f56", + "url": "https://github.com/trending?l=Groovy" + }, + "Groovy Server Pages": { + "color": null, + "url": "https://github.com/trending?l=Groovy-Server-Pages" + }, + "Hack": { + "color": "#878787", + "url": "https://github.com/trending?l=Hack" + }, + "Haml": { + "color": "#ece2a9", + "url": "https://github.com/trending?l=Haml" + }, + "Handlebars": { + "color": "#f7931e", + "url": "https://github.com/trending?l=Handlebars" + }, + "Harbour": { + "color": "#0e60e3", + "url": "https://github.com/trending?l=Harbour" + }, + "Haskell": { + "color": "#5e5086", + "url": "https://github.com/trending?l=Haskell" + }, + "Haxe": { + "color": "#df7900", + "url": "https://github.com/trending?l=Haxe" + }, + "HCL": { + "color": null, + "url": "https://github.com/trending?l=HCL" + }, + "HiveQL": { + "color": "#dce200", + "url": "https://github.com/trending?l=HiveQL" + }, + "HLSL": { + "color": null, + "url": "https://github.com/trending?l=HLSL" + }, + "HolyC": { + "color": "#ffefaf", + "url": "https://github.com/trending?l=HolyC" + }, + "HTML": { + "color": "#e34c26", + "url": "https://github.com/trending?l=HTML" + }, + "Hy": { + "color": "#7790B2", + "url": "https://github.com/trending?l=Hy" + }, + "HyPhy": { + "color": null, + "url": "https://github.com/trending?l=HyPhy" + }, + "IDL": { + "color": "#a3522f", + "url": "https://github.com/trending?l=IDL" + }, + "Idris": { + "color": "#b30000", + "url": "https://github.com/trending?l=Idris" + }, + "IGOR Pro": { + "color": "#0000cc", + "url": "https://github.com/trending?l=IGOR-Pro" + }, + "Inform 7": { + "color": null, + "url": "https://github.com/trending?l=Inform-7" + }, + "Inno Setup": { + "color": null, + "url": "https://github.com/trending?l=Inno-Setup" + }, + "Io": { + "color": "#a9188d", + "url": "https://github.com/trending?l=Io" + }, + "Ioke": { + "color": "#078193", + "url": "https://github.com/trending?l=Ioke" + }, + "Isabelle": { + "color": "#FEFE00", + "url": "https://github.com/trending?l=Isabelle" + }, + "Isabelle ROOT": { + "color": null, + "url": "https://github.com/trending?l=Isabelle-ROOT" + }, + "J": { + "color": "#9EEDFF", + "url": "https://github.com/trending?l=J" + }, + "Jasmin": { + "color": null, + "url": "https://github.com/trending?l=Jasmin" + }, + "Java": { + "color": "#b07219", + "url": "https://github.com/trending?l=Java" + }, + "Java Server Pages": { + "color": null, + "url": "https://github.com/trending?l=Java-Server-Pages" + }, + "JavaScript": { + "color": "#f1e05a", + "url": "https://github.com/trending?l=JavaScript" + }, + "JavaScript+ERB": { + "color": null, + "url": "https://github.com/trending?l=JavaScript+ERB" + }, + "JFlex": { + "color": null, + "url": "https://github.com/trending?l=JFlex" + }, + "Jison": { + "color": null, + "url": "https://github.com/trending?l=Jison" + }, + "Jison Lex": { + "color": null, + "url": "https://github.com/trending?l=Jison-Lex" + }, + "Jolie": { + "color": "#843179", + "url": "https://github.com/trending?l=Jolie" + }, + "JSONiq": { + "color": "#40d47e", + "url": "https://github.com/trending?l=JSONiq" + }, + "Jsonnet": { + "color": "#0064bd", + "url": "https://github.com/trending?l=Jsonnet" + }, + "JSX": { + "color": null, + "url": "https://github.com/trending?l=JSX" + }, + "Julia": { + "color": "#a270ba", + "url": "https://github.com/trending?l=Julia" + }, + "Jupyter Notebook": { + "color": "#DA5B0B", + "url": "https://github.com/trending?l=Jupyter-Notebook" + }, + "Kaitai Struct": { + "color": "#773b37", + "url": "https://github.com/trending?l=Kaitai-Struct" + }, + "Kotlin": { + "color": "#F18E33", + "url": "https://github.com/trending?l=Kotlin" + }, + "KRL": { + "color": "#28430A", + "url": "https://github.com/trending?l=KRL" + }, + "LabVIEW": { + "color": null, + "url": "https://github.com/trending?l=LabVIEW" + }, + "Lasso": { + "color": "#999999", + "url": "https://github.com/trending?l=Lasso" + }, + "Latte": { + "color": "#f2a542", + "url": "https://github.com/trending?l=Latte" + }, + "Lean": { + "color": null, + "url": "https://github.com/trending?l=Lean" + }, + "Less": { + "color": "#1d365d", + "url": "https://github.com/trending?l=Less" + }, + "Lex": { + "color": "#DBCA00", + "url": "https://github.com/trending?l=Lex" + }, + "LFE": { + "color": "#4C3023", + "url": "https://github.com/trending?l=LFE" + }, + "LilyPond": { + "color": null, + "url": "https://github.com/trending?l=LilyPond" + }, + "Limbo": { + "color": null, + "url": "https://github.com/trending?l=Limbo" + }, + "Literate Agda": { + "color": null, + "url": "https://github.com/trending?l=Literate-Agda" + }, + "Literate CoffeeScript": { + "color": null, + "url": "https://github.com/trending?l=Literate-CoffeeScript" + }, + "Literate Haskell": { + "color": null, + "url": "https://github.com/trending?l=Literate-Haskell" + }, + "LiveScript": { + "color": "#499886", + "url": "https://github.com/trending?l=LiveScript" + }, + "LLVM": { + "color": "#185619", + "url": "https://github.com/trending?l=LLVM" + }, + "Logos": { + "color": null, + "url": "https://github.com/trending?l=Logos" + }, + "Logtalk": { + "color": null, + "url": "https://github.com/trending?l=Logtalk" + }, + "LOLCODE": { + "color": "#cc9900", + "url": "https://github.com/trending?l=LOLCODE" + }, + "LookML": { + "color": "#652B81", + "url": "https://github.com/trending?l=LookML" + }, + "LoomScript": { + "color": null, + "url": "https://github.com/trending?l=LoomScript" + }, + "LSL": { + "color": "#3d9970", + "url": "https://github.com/trending?l=LSL" + }, + "Lua": { + "color": "#000080", + "url": "https://github.com/trending?l=Lua" + }, + "M": { + "color": null, + "url": "https://github.com/trending?l=M" + }, + "M4": { + "color": null, + "url": "https://github.com/trending?l=M4" + }, + "M4Sugar": { + "color": null, + "url": "https://github.com/trending?l=M4Sugar" + }, + "Macaulay2": { + "color": "#d8ffff", + "url": "https://github.com/trending?l=Macaulay2" + }, + "Makefile": { + "color": "#427819", + "url": "https://github.com/trending?l=Makefile" + }, + "Mako": { + "color": null, + "url": "https://github.com/trending?l=Mako" + }, + "Markdown": { + "color": "#083fa1", + "url": "https://github.com/trending?l=Markdown" + }, + "Marko": { + "color": "#42bff2", + "url": "https://github.com/trending?l=Marko" + }, + "Mask": { + "color": "#f97732", + "url": "https://github.com/trending?l=Mask" + }, + "Mathematica": { + "color": null, + "url": "https://github.com/trending?l=Mathematica" + }, + "MATLAB": { + "color": "#e16737", + "url": "https://github.com/trending?l=MATLAB" + }, + "Max": { + "color": "#c4a79c", + "url": "https://github.com/trending?l=Max" + }, + "MAXScript": { + "color": "#00a6a6", + "url": "https://github.com/trending?l=MAXScript" + }, + "mcfunction": { + "color": "#E22837", + "url": "https://github.com/trending?l=mcfunction" + }, + "Mercury": { + "color": "#ff2b2b", + "url": "https://github.com/trending?l=Mercury" + }, + "Meson": { + "color": "#007800", + "url": "https://github.com/trending?l=Meson" + }, + "Metal": { + "color": "#8f14e9", + "url": "https://github.com/trending?l=Metal" + }, + "MiniD": { + "color": null, + "url": "https://github.com/trending?l=MiniD" + }, + "Mirah": { + "color": "#c7a938", + "url": "https://github.com/trending?l=Mirah" + }, + "mIRC Script": { + "color": "#3d57c3", + "url": "https://github.com/trending?l=mIRC-Script" + }, + "MLIR": { + "color": "#5EC8DB", + "url": "https://github.com/trending?l=MLIR" + }, + "Modelica": { + "color": null, + "url": "https://github.com/trending?l=Modelica" + }, + "Modula-2": { + "color": null, + "url": "https://github.com/trending?l=Modula-2" + }, + "Modula-3": { + "color": "#223388", + "url": "https://github.com/trending?l=Modula-3" + }, + "Module Management System": { + "color": null, + "url": "https://github.com/trending?l=Module-Management-System" + }, + "Monkey": { + "color": null, + "url": "https://github.com/trending?l=Monkey" + }, + "Moocode": { + "color": null, + "url": "https://github.com/trending?l=Moocode" + }, + "MoonScript": { + "color": null, + "url": "https://github.com/trending?l=MoonScript" + }, + "Motorola 68K Assembly": { + "color": null, + "url": "https://github.com/trending?l=Motorola-68K-Assembly" + }, + "MQL4": { + "color": "#62A8D6", + "url": "https://github.com/trending?l=MQL4" + }, + "MQL5": { + "color": "#4A76B8", + "url": "https://github.com/trending?l=MQL5" + }, + "MTML": { + "color": "#b7e1f4", + "url": "https://github.com/trending?l=MTML" + }, + "MUF": { + "color": null, + "url": "https://github.com/trending?l=MUF" + }, + "mupad": { + "color": null, + "url": "https://github.com/trending?l=mupad" + }, + "Myghty": { + "color": null, + "url": "https://github.com/trending?l=Myghty" + }, + "NASL": { + "color": null, + "url": "https://github.com/trending?l=NASL" + }, + "NCL": { + "color": "#28431f", + "url": "https://github.com/trending?l=NCL" + }, + "Nearley": { + "color": "#990000", + "url": "https://github.com/trending?l=Nearley" + }, + "Nemerle": { + "color": "#3d3c6e", + "url": "https://github.com/trending?l=Nemerle" + }, + "nesC": { + "color": "#94B0C7", + "url": "https://github.com/trending?l=nesC" + }, + "NetLinx": { + "color": "#0aa0ff", + "url": "https://github.com/trending?l=NetLinx" + }, + "NetLinx+ERB": { + "color": "#747faa", + "url": "https://github.com/trending?l=NetLinx+ERB" + }, + "NetLogo": { + "color": "#ff6375", + "url": "https://github.com/trending?l=NetLogo" + }, + "NewLisp": { + "color": "#87AED7", + "url": "https://github.com/trending?l=NewLisp" + }, + "Nextflow": { + "color": "#3ac486", + "url": "https://github.com/trending?l=Nextflow" + }, + "Nim": { + "color": "#ffc200", + "url": "https://github.com/trending?l=Nim" + }, + "Nit": { + "color": "#009917", + "url": "https://github.com/trending?l=Nit" + }, + "Nix": { + "color": "#7e7eff", + "url": "https://github.com/trending?l=Nix" + }, + "NSIS": { + "color": null, + "url": "https://github.com/trending?l=NSIS" + }, + "Nu": { + "color": "#c9df40", + "url": "https://github.com/trending?l=Nu" + }, + "NumPy": { + "color": null, + "url": "https://github.com/trending?l=NumPy" + }, + "Objective-C": { + "color": "#438eff", + "url": "https://github.com/trending?l=Objective-C" + }, + "Objective-C++": { + "color": "#6866fb", + "url": "https://github.com/trending?l=Objective-C++" + }, + "Objective-J": { + "color": "#ff0c5a", + "url": "https://github.com/trending?l=Objective-J" + }, + "ObjectScript": { + "color": "#424893", + "url": "https://github.com/trending?l=ObjectScript" + }, + "OCaml": { + "color": "#3be133", + "url": "https://github.com/trending?l=OCaml" + }, + "Odin": { + "color": "#60AFFE", + "url": "https://github.com/trending?l=Odin" + }, + "Omgrofl": { + "color": "#cabbff", + "url": "https://github.com/trending?l=Omgrofl" + }, + "ooc": { + "color": "#b0b77e", + "url": "https://github.com/trending?l=ooc" + }, + "Opa": { + "color": null, + "url": "https://github.com/trending?l=Opa" + }, + "Opal": { + "color": "#f7ede0", + "url": "https://github.com/trending?l=Opal" + }, + "Open Policy Agent": { + "color": null, + "url": "https://github.com/trending?l=Open-Policy-Agent" + }, + "OpenCL": { + "color": null, + "url": "https://github.com/trending?l=OpenCL" + }, + "OpenEdge ABL": { + "color": null, + "url": "https://github.com/trending?l=OpenEdge-ABL" + }, + "OpenQASM": { + "color": "#AA70FF", + "url": "https://github.com/trending?l=OpenQASM" + }, + "OpenRC runscript": { + "color": null, + "url": "https://github.com/trending?l=OpenRC-runscript" + }, + "OpenSCAD": { + "color": null, + "url": "https://github.com/trending?l=OpenSCAD" + }, + "Ox": { + "color": null, + "url": "https://github.com/trending?l=Ox" + }, + "Oxygene": { + "color": "#cdd0e3", + "url": "https://github.com/trending?l=Oxygene" + }, + "Oz": { + "color": "#fab738", + "url": "https://github.com/trending?l=Oz" + }, + "P4": { + "color": "#7055b5", + "url": "https://github.com/trending?l=P4" + }, + "Pan": { + "color": "#cc0000", + "url": "https://github.com/trending?l=Pan" + }, + "Papyrus": { + "color": "#6600cc", + "url": "https://github.com/trending?l=Papyrus" + }, + "Parrot": { + "color": "#f3ca0a", + "url": "https://github.com/trending?l=Parrot" + }, + "Parrot Assembly": { + "color": null, + "url": "https://github.com/trending?l=Parrot-Assembly" + }, + "Parrot Internal Representation": { + "color": null, + "url": "https://github.com/trending?l=Parrot-Internal-Representation" + }, + "Pascal": { + "color": "#E3F171", + "url": "https://github.com/trending?l=Pascal" + }, + "Pawn": { + "color": "#dbb284", + "url": "https://github.com/trending?l=Pawn" + }, + "Pep8": { + "color": "#C76F5B", + "url": "https://github.com/trending?l=Pep8" + }, + "Perl": { + "color": "#0298c3", + "url": "https://github.com/trending?l=Perl" + }, + "PHP": { + "color": "#4F5D95", + "url": "https://github.com/trending?l=PHP" + }, + "PicoLisp": { + "color": null, + "url": "https://github.com/trending?l=PicoLisp" + }, + "PigLatin": { + "color": "#fcd7de", + "url": "https://github.com/trending?l=PigLatin" + }, + "Pike": { + "color": "#005390", + "url": "https://github.com/trending?l=Pike" + }, + "PLpgSQL": { + "color": null, + "url": "https://github.com/trending?l=PLpgSQL" + }, + "PLSQL": { + "color": "#dad8d8", + "url": "https://github.com/trending?l=PLSQL" + }, + "PogoScript": { + "color": "#d80074", + "url": "https://github.com/trending?l=PogoScript" + }, + "Pony": { + "color": null, + "url": "https://github.com/trending?l=Pony" + }, + "PostScript": { + "color": "#da291c", + "url": "https://github.com/trending?l=PostScript" + }, + "POV-Ray SDL": { + "color": null, + "url": "https://github.com/trending?l=POV-Ray-SDL" + }, + "PowerBuilder": { + "color": "#8f0f8d", + "url": "https://github.com/trending?l=PowerBuilder" + }, + "PowerShell": { + "color": "#012456", + "url": "https://github.com/trending?l=PowerShell" + }, + "Prisma": { + "color": "#0c344b", + "url": "https://github.com/trending?l=Prisma" + }, + "Processing": { + "color": "#0096D8", + "url": "https://github.com/trending?l=Processing" + }, + "Prolog": { + "color": "#74283c", + "url": "https://github.com/trending?l=Prolog" + }, + "Propeller Spin": { + "color": "#7fa2a7", + "url": "https://github.com/trending?l=Propeller-Spin" + }, + "Pug": { + "color": "#a86454", + "url": "https://github.com/trending?l=Pug" + }, + "Puppet": { + "color": "#302B6D", + "url": "https://github.com/trending?l=Puppet" + }, + "PureBasic": { + "color": "#5a6986", + "url": "https://github.com/trending?l=PureBasic" + }, + "PureScript": { + "color": "#1D222D", + "url": "https://github.com/trending?l=PureScript" + }, + "Python": { + "color": "#3572A5", + "url": "https://github.com/trending?l=Python" + }, + "Python console": { + "color": null, + "url": "https://github.com/trending?l=Python-console" + }, + "q": { + "color": "#0040cd", + "url": "https://github.com/trending?l=q" + }, + "Q#": { + "color": "#fed659", + "url": "https://github.com/trending?l=Qsharp" + }, + "QMake": { + "color": null, + "url": "https://github.com/trending?l=QMake" + }, + "QML": { + "color": "#44a51c", + "url": "https://github.com/trending?l=QML" + }, + "Qt Script": { + "color": "#00b841", + "url": "https://github.com/trending?l=Qt-Script" + }, + "Quake": { + "color": "#882233", + "url": "https://github.com/trending?l=Quake" + }, + "R": { + "color": "#198CE7", + "url": "https://github.com/trending?l=R" + }, + "Racket": { + "color": "#3c5caa", + "url": "https://github.com/trending?l=Racket" + }, + "Ragel": { + "color": "#9d5200", + "url": "https://github.com/trending?l=Ragel" + }, + "Raku": { + "color": "#0000fb", + "url": "https://github.com/trending?l=Raku" + }, + "RAML": { + "color": "#77d9fb", + "url": "https://github.com/trending?l=RAML" + }, + "Rascal": { + "color": "#fffaa0", + "url": "https://github.com/trending?l=Rascal" + }, + "REALbasic": { + "color": null, + "url": "https://github.com/trending?l=REALbasic" + }, + "Reason": { + "color": "#ff5847", + "url": "https://github.com/trending?l=Reason" + }, + "Rebol": { + "color": "#358a5b", + "url": "https://github.com/trending?l=Rebol" + }, + "Red": { + "color": "#f50000", + "url": "https://github.com/trending?l=Red" + }, + "Redcode": { + "color": null, + "url": "https://github.com/trending?l=Redcode" + }, + "Ren'Py": { + "color": "#ff7f7f", + "url": "https://github.com/trending?l=Ren'Py" + }, + "RenderScript": { + "color": null, + "url": "https://github.com/trending?l=RenderScript" + }, + "REXX": { + "color": null, + "url": "https://github.com/trending?l=REXX" + }, + "Ring": { + "color": "#2D54CB", + "url": "https://github.com/trending?l=Ring" + }, + "Riot": { + "color": "#A71E49", + "url": "https://github.com/trending?l=Riot" + }, + "RobotFramework": { + "color": null, + "url": "https://github.com/trending?l=RobotFramework" + }, + "Roff": { + "color": "#ecdebe", + "url": "https://github.com/trending?l=Roff" + }, + "Rouge": { + "color": "#cc0088", + "url": "https://github.com/trending?l=Rouge" + }, + "RPC": { + "color": null, + "url": "https://github.com/trending?l=RPC" + }, + "Ruby": { + "color": "#701516", + "url": "https://github.com/trending?l=Ruby" + }, + "RUNOFF": { + "color": "#665a4e", + "url": "https://github.com/trending?l=RUNOFF" + }, + "Rust": { + "color": "#dea584", + "url": "https://github.com/trending?l=Rust" + }, + "Sage": { + "color": null, + "url": "https://github.com/trending?l=Sage" + }, + "SaltStack": { + "color": "#646464", + "url": "https://github.com/trending?l=SaltStack" + }, + "SAS": { + "color": "#B34936", + "url": "https://github.com/trending?l=SAS" + }, + "Sass": { + "color": "#a53b70", + "url": "https://github.com/trending?l=Sass" + }, + "Scala": { + "color": "#c22d40", + "url": "https://github.com/trending?l=Scala" + }, + "Scheme": { + "color": "#1e4aec", + "url": "https://github.com/trending?l=Scheme" + }, + "Scilab": { + "color": null, + "url": "https://github.com/trending?l=Scilab" + }, + "SCSS": { + "color": "#c6538c", + "url": "https://github.com/trending?l=SCSS" + }, + "sed": { + "color": "#64b970", + "url": "https://github.com/trending?l=sed" + }, + "Self": { + "color": "#0579aa", + "url": "https://github.com/trending?l=Self" + }, + "ShaderLab": { + "color": null, + "url": "https://github.com/trending?l=ShaderLab" + }, + "Shell": { + "color": "#89e051", + "url": "https://github.com/trending?l=Shell" + }, + "ShellSession": { + "color": null, + "url": "https://github.com/trending?l=ShellSession" + }, + "Shen": { + "color": "#120F14", + "url": "https://github.com/trending?l=Shen" + }, + "Sieve": { + "color": null, + "url": "https://github.com/trending?l=Sieve" + }, + "Slash": { + "color": "#007eff", + "url": "https://github.com/trending?l=Slash" + }, + "Slice": { + "color": "#003fa2", + "url": "https://github.com/trending?l=Slice" + }, + "Slim": { + "color": "#2b2b2b", + "url": "https://github.com/trending?l=Slim" + }, + "Smali": { + "color": null, + "url": "https://github.com/trending?l=Smali" + }, + "Smalltalk": { + "color": "#596706", + "url": "https://github.com/trending?l=Smalltalk" + }, + "Smarty": { + "color": null, + "url": "https://github.com/trending?l=Smarty" + }, + "SmPL": { + "color": "#c94949", + "url": "https://github.com/trending?l=SmPL" + }, + "SMT": { + "color": null, + "url": "https://github.com/trending?l=SMT" + }, + "Solidity": { + "color": "#AA6746", + "url": "https://github.com/trending?l=Solidity" + }, + "SourcePawn": { + "color": "#f69e1d", + "url": "https://github.com/trending?l=SourcePawn" + }, + "SQF": { + "color": "#3F3F3F", + "url": "https://github.com/trending?l=SQF" + }, + "SQLPL": { + "color": null, + "url": "https://github.com/trending?l=SQLPL" + }, + "Squirrel": { + "color": "#800000", + "url": "https://github.com/trending?l=Squirrel" + }, + "SRecode Template": { + "color": "#348a34", + "url": "https://github.com/trending?l=SRecode-Template" + }, + "Stan": { + "color": "#b2011d", + "url": "https://github.com/trending?l=Stan" + }, + "Standard ML": { + "color": "#dc566d", + "url": "https://github.com/trending?l=Standard-ML" + }, + "Starlark": { + "color": "#76d275", + "url": "https://github.com/trending?l=Starlark" + }, + "Stata": { + "color": null, + "url": "https://github.com/trending?l=Stata" + }, + "Stylus": { + "color": "#ff6347", + "url": "https://github.com/trending?l=Stylus" + }, + "SuperCollider": { + "color": "#46390b", + "url": "https://github.com/trending?l=SuperCollider" + }, + "Svelte": { + "color": "#ff3e00", + "url": "https://github.com/trending?l=Svelte" + }, + "SVG": { + "color": "#ff9900", + "url": "https://github.com/trending?l=SVG" + }, + "Swift": { + "color": "#ffac45", + "url": "https://github.com/trending?l=Swift" + }, + "SWIG": { + "color": null, + "url": "https://github.com/trending?l=SWIG" + }, + "SystemVerilog": { + "color": "#DAE1C2", + "url": "https://github.com/trending?l=SystemVerilog" + }, + "Tcl": { + "color": "#e4cc98", + "url": "https://github.com/trending?l=Tcl" + }, + "Tcsh": { + "color": null, + "url": "https://github.com/trending?l=Tcsh" + }, + "Terra": { + "color": "#00004c", + "url": "https://github.com/trending?l=Terra" + }, + "TeX": { + "color": "#3D6117", + "url": "https://github.com/trending?l=TeX" + }, + "Thrift": { + "color": null, + "url": "https://github.com/trending?l=Thrift" + }, + "TI Program": { + "color": "#A0AA87", + "url": "https://github.com/trending?l=TI-Program" + }, + "TLA": { + "color": null, + "url": "https://github.com/trending?l=TLA" + }, + "TSQL": { + "color": null, + "url": "https://github.com/trending?l=TSQL" + }, + "TSX": { + "color": null, + "url": "https://github.com/trending?l=TSX" + }, + "Turing": { + "color": "#cf142b", + "url": "https://github.com/trending?l=Turing" + }, + "Twig": { + "color": "#c1d026", + "url": "https://github.com/trending?l=Twig" + }, + "TXL": { + "color": null, + "url": "https://github.com/trending?l=TXL" + }, + "TypeScript": { + "color": "#2b7489", + "url": "https://github.com/trending?l=TypeScript" + }, + "TypeScript (JSX)": { + "color": "#2b7489", + "url": "https://github.com/trending?l=TypeScript" + }, + "Unified Parallel C": { + "color": null, + "url": "https://github.com/trending?l=Unified-Parallel-C" + }, + "Unix Assembly": { + "color": null, + "url": "https://github.com/trending?l=Unix-Assembly" + }, + "Uno": { + "color": "#9933cc", + "url": "https://github.com/trending?l=Uno" + }, + "UnrealScript": { + "color": "#a54c4d", + "url": "https://github.com/trending?l=UnrealScript" + }, + "UrWeb": { + "color": null, + "url": "https://github.com/trending?l=UrWeb" + }, + "V": { + "color": "#4f87c4", + "url": "https://github.com/trending?l=V" + }, + "Vala": { + "color": "#fbe5cd", + "url": "https://github.com/trending?l=Vala" + }, + "VBA": { + "color": "#867db1", + "url": "https://github.com/trending?l=VBA" + }, + "VBScript": { + "color": "#15dcdc", + "url": "https://github.com/trending?l=VBScript" + }, + "VCL": { + "color": "#148AA8", + "url": "https://github.com/trending?l=VCL" + }, + "Verilog": { + "color": "#b2b7f8", + "url": "https://github.com/trending?l=Verilog" + }, + "VHDL": { + "color": "#adb2cb", + "url": "https://github.com/trending?l=VHDL" + }, + "Vim script": { + "color": "#199f4b", + "url": "https://github.com/trending?l=Vim-script" + }, + "Visual Basic .NET": { + "color": "#945db7", + "url": "https://github.com/trending?l=Visual-Basic-.NET" + }, + "Volt": { + "color": "#1F1F1F", + "url": "https://github.com/trending?l=Volt" + }, + "Vue": { + "color": "#2c3e50", + "url": "https://github.com/trending?l=Vue" + }, + "wdl": { + "color": "#42f1f4", + "url": "https://github.com/trending?l=wdl" + }, + "WebAssembly": { + "color": "#04133b", + "url": "https://github.com/trending?l=WebAssembly" + }, + "WebIDL": { + "color": null, + "url": "https://github.com/trending?l=WebIDL" + }, + "wisp": { + "color": "#7582D1", + "url": "https://github.com/trending?l=wisp" + }, + "Wollok": { + "color": "#a23738", + "url": "https://github.com/trending?l=Wollok" + }, + "X10": { + "color": "#4B6BEF", + "url": "https://github.com/trending?l=X10" + }, + "xBase": { + "color": "#403a40", + "url": "https://github.com/trending?l=xBase" + }, + "XC": { + "color": "#99DA07", + "url": "https://github.com/trending?l=XC" + }, + "Xojo": { + "color": null, + "url": "https://github.com/trending?l=Xojo" + }, + "XProc": { + "color": null, + "url": "https://github.com/trending?l=XProc" + }, + "XQuery": { + "color": "#5232e7", + "url": "https://github.com/trending?l=XQuery" + }, + "XS": { + "color": null, + "url": "https://github.com/trending?l=XS" + }, + "XSLT": { + "color": "#EB8CEB", + "url": "https://github.com/trending?l=XSLT" + }, + "Xtend": { + "color": null, + "url": "https://github.com/trending?l=Xtend" + }, + "Yacc": { + "color": "#4B6C4B", + "url": "https://github.com/trending?l=Yacc" + }, + "YAML": { + "color": "#cb171e", + "url": "https://github.com/trending?l=YAML" + }, + "YARA": { + "color": "#220000", + "url": "https://github.com/trending?l=YARA" + }, + "YASnippet": { + "color": "#32AB90", + "url": "https://github.com/trending?l=YASnippet" + }, + "ZAP": { + "color": "#0d665e", + "url": "https://github.com/trending?l=ZAP" + }, + "Zeek": { + "color": null, + "url": "https://github.com/trending?l=Zeek" + }, + "ZenScript": { + "color": "#00BCD1", + "url": "https://github.com/trending?l=ZenScript" + }, + "Zephir": { + "color": "#118f9e", + "url": "https://github.com/trending?l=Zephir" + }, + "Zig": { + "color": "#ec915c", + "url": "https://github.com/trending?l=Zig" + }, + "ZIL": { + "color": "#dc75e5", + "url": "https://github.com/trending?l=ZIL" + }, + "Zimpl": { + "color": null, + "url": "https://github.com/trending?l=Zimpl" + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..ae2e14d --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "allowJs": true, + "checkJs": true, + "jsx": "react", + + "strict": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + } +}