mirror of
https://github.com/Aviortheking/codestats-readme.git
synced 2025-04-22 10:42:08 +00:00
Misc Update
Signed-off-by: Florian Bouillon <florian.bouillon@delta-wings.net>
This commit is contained in:
parent
332be009cf
commit
21a6c06f35
@ -66,6 +66,8 @@
|
|||||||
"padded-blocks": ["error", { "classes": "always" }],
|
"padded-blocks": ["error", { "classes": "always" }],
|
||||||
"import/order": ["error"],
|
"import/order": ["error"],
|
||||||
"import/no-named-as-default-member": "off",
|
"import/no-named-as-default-member": "off",
|
||||||
"import/no-named-as-default": "off"
|
"import/no-named-as-default": "off",
|
||||||
|
"camelcase": "off",
|
||||||
|
"valid-jsdoc": "off"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
.github/ISSUE_TEMPLATE/bug_report.md
vendored
13
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -22,20 +22,9 @@ Add any other context about the problem here.
|
|||||||
|
|
||||||
PLEASE READ THE FAQs!!!
|
PLEASE READ THE FAQs!!!
|
||||||
|
|
||||||
Q: How to hide jupyter Notebook?
|
|
||||||
Ans: &hide=jupyter%20notebook
|
|
||||||
|
|
||||||
Q: I could not figure out how to deploy on my own vercel instance
|
Q: I could not figure out how to deploy on my own vercel instance
|
||||||
Ans:
|
Ans:
|
||||||
- docs: https://github.com/anuraghazra/github-readme-stats/#deploy-on-your-own-vercel-instance
|
- docs: https://github.com/aviortheking/codestats-readme/#deploy-on-your-own-vercel-instance
|
||||||
- YT tutorial by codeSTACKr: https://www.youtube.com/watch?v=n6d4KHSKqGk&feature=youtu.be&t=107
|
- YT tutorial by codeSTACKr: https://www.youtube.com/watch?v=n6d4KHSKqGk&feature=youtu.be&t=107
|
||||||
|
|
||||||
Q: Language Card is incorrect
|
|
||||||
Ans: Please read all the issues / comments before opening any issues regarding language card stats:
|
|
||||||
- https://github.com/anuraghazra/github-readme-stats/issues/136#issuecomment-665164174
|
|
||||||
- https://github.com/anuraghazra/github-readme-stats/issues/136#issuecomment-665172181
|
|
||||||
|
|
||||||
Q: How to count private stats?
|
|
||||||
Ans: We can only count private commits & we cannot access any other private info of any users, so it's not possible. only way is to deploy on your own instance & use your own PAT (Personal Access Token)
|
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
13
.github/ISSUE_TEMPLATE/feature_request.md
vendored
13
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -22,20 +22,9 @@ Add any other context or screenshots about the feature request here.
|
|||||||
|
|
||||||
PLEASE READ THE FAQs!!!
|
PLEASE READ THE FAQs!!!
|
||||||
|
|
||||||
Q: How to hide jupyter Notebook?
|
|
||||||
Ans: &hide=jupyter%20notebook
|
|
||||||
|
|
||||||
Q: I could not figure out how to deploy on my own vercel instance
|
Q: I could not figure out how to deploy on my own vercel instance
|
||||||
Ans:
|
Ans:
|
||||||
- docs: https://github.com/anuraghazra/github-readme-stats/#deploy-on-your-own-vercel-instance
|
- docs: https://github.com/aviortheking/codestats-readme/#deploy-on-your-own-vercel-instance
|
||||||
- YT tutorial by codeSTACKr: https://www.youtube.com/watch?v=n6d4KHSKqGk&feature=youtu.be&t=107
|
- YT tutorial by codeSTACKr: https://www.youtube.com/watch?v=n6d4KHSKqGk&feature=youtu.be&t=107
|
||||||
|
|
||||||
Q: Language Card is incorrect
|
|
||||||
Ans: Please read all the issues / comments before opening any issues regarding language card stats:
|
|
||||||
- https://github.com/anuraghazra/github-readme-stats/issues/136#issuecomment-665164174
|
|
||||||
- https://github.com/anuraghazra/github-readme-stats/issues/136#issuecomment-665172181
|
|
||||||
|
|
||||||
Q: How to count private stats?
|
|
||||||
Ans: We can only count private commits & we cannot access any other private info of any users, so it's not possible. only way is to deploy on your own instance & use your own PAT (Personal Access Token)
|
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
2
.github/labeler.yml
vendored
2
.github/labeler.yml
vendored
@ -1,2 +0,0 @@
|
|||||||
themes: themes/index.js
|
|
||||||
doc-translation: docs/*
|
|
35
.github/workflows/generate-theme-doc.yml
vendored
35
.github/workflows/generate-theme-doc.yml
vendored
@ -1,35 +0,0 @@
|
|||||||
name: Generate Theme Readme
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
paths:
|
|
||||||
- "themes/index.js"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v1
|
|
||||||
- name: setup node
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: "12.x"
|
|
||||||
|
|
||||||
- name: npm install, generate readme
|
|
||||||
run: |
|
|
||||||
npm install
|
|
||||||
npm run theme-readme-gen
|
|
||||||
env:
|
|
||||||
CI: true
|
|
||||||
|
|
||||||
- name: Run Script
|
|
||||||
uses: skx/github-action-tester@master
|
|
||||||
with:
|
|
||||||
script: ./scripts/push-theme-readme.sh
|
|
||||||
env:
|
|
||||||
CI: true
|
|
||||||
PERSONAL_TOKEN: ${{ secrets.PERSONAL_TOKEN }}
|
|
||||||
GH_REPO: ${{ secrets.GH_REPO }}
|
|
11
.github/workflows/label-pr.yml
vendored
11
.github/workflows/label-pr.yml
vendored
@ -1,11 +0,0 @@
|
|||||||
name: "Pull Request Labeler"
|
|
||||||
on:
|
|
||||||
- pull_request_target
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
triage:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/labeler@v2
|
|
||||||
with:
|
|
||||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
|
28
.github/workflows/preview-theme.yml
vendored
28
.github/workflows/preview-theme.yml
vendored
@ -1,28 +0,0 @@
|
|||||||
name: Theme preview
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
types: [opened, synchronize, reopened]
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
- theme-preview-script
|
|
||||||
- "themes/index.js"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v1
|
|
||||||
- name: setup node
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: "12.x"
|
|
||||||
|
|
||||||
- name: npm install, preview theme
|
|
||||||
run: |
|
|
||||||
npm install
|
|
||||||
npm run preview-theme
|
|
||||||
env:
|
|
||||||
CI: true
|
|
||||||
PERSONAL_TOKEN: ${{ secrets.PERSONAL_TOKEN }}
|
|
39
.github/workflows/test.yml
vendored
39
.github/workflows/test.yml
vendored
@ -1,39 +0,0 @@
|
|||||||
name: Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- "*"
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: "12.x"
|
|
||||||
|
|
||||||
- name: Cache node modules
|
|
||||||
uses: actions/cache@v2
|
|
||||||
env:
|
|
||||||
cache-name: cache-node-modules
|
|
||||||
with:
|
|
||||||
path: ~/.npm
|
|
||||||
key: ${{ runner.os }}-npm-cache-${{ hashFiles('**/package-lock.json') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-npm-cache-
|
|
||||||
|
|
||||||
- name: Install & Test
|
|
||||||
run: |
|
|
||||||
npm install
|
|
||||||
npm run test
|
|
||||||
|
|
||||||
- name: Code Coverage
|
|
||||||
uses: codecov/codecov-action@v1
|
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,8 +1,6 @@
|
|||||||
.vercel
|
.vercel
|
||||||
.env
|
.env
|
||||||
node_modules
|
node_modules
|
||||||
package-lock.json
|
|
||||||
*.lock
|
|
||||||
.vscode/
|
.vscode/
|
||||||
coverage
|
coverage
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
|
@ -1,16 +1,13 @@
|
|||||||
import { parseBoolean, prepareResponse, setCache, parseNumber, clampValue, parseArray} from '../src/common/utils'
|
|
||||||
import { fetchHistory } from '../src/fetcher'
|
|
||||||
import { Request, Response } from 'express'
|
import { Request, Response } from 'express'
|
||||||
import ReactDOMServer from 'react-dom/server'
|
import ReactDOMServer from 'react-dom/server'
|
||||||
|
import { parseBoolean, prepareResponse, setCache, parseNumber, clampValue, parseArray } from '../src/common/utils'
|
||||||
|
import { fetchHistory } from '../src/fetcher'
|
||||||
import Error from '../src/components/Error'
|
import Error from '../src/components/Error'
|
||||||
import HistoryCard from '../src/cards/HistoryCard'
|
import HistoryCard from '../src/cards/HistoryCard'
|
||||||
|
import themes from '../themes/themes.json'
|
||||||
|
|
||||||
export interface query {
|
export interface query {
|
||||||
username: string
|
username: string
|
||||||
hide_title?: string
|
|
||||||
hide_border?: string
|
|
||||||
title_color?: string
|
|
||||||
bg_color?: string
|
|
||||||
days_count?: string
|
days_count?: string
|
||||||
cache_seconds?: string
|
cache_seconds?: string
|
||||||
width?: string
|
width?: string
|
||||||
@ -18,28 +15,43 @@ export interface query {
|
|||||||
hide?: string
|
hide?: string
|
||||||
language_count?: string
|
language_count?: string
|
||||||
layout?: 'horizontal'
|
layout?: 'horizontal'
|
||||||
|
reverse_order?: string
|
||||||
|
hide_legend?: string
|
||||||
|
|
||||||
|
// Mater
|
||||||
|
bg_color?: string
|
||||||
|
hide_border?: string
|
||||||
|
hide_title?: string
|
||||||
|
theme?: keyof typeof themes
|
||||||
|
title_color?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async (req: Request<unknown, unknown, unknown, query>, res: Response) => {
|
export default async (req: Request<unknown, unknown, unknown, query>, res: Response) => {
|
||||||
const {
|
const {
|
||||||
username,
|
username,
|
||||||
hide_title,
|
|
||||||
hide_border,
|
|
||||||
title_color,
|
|
||||||
bg_color,
|
|
||||||
days_count,
|
days_count,
|
||||||
cache_seconds,
|
cache_seconds,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
language_count,
|
language_count,
|
||||||
hide,
|
hide,
|
||||||
layout
|
layout,
|
||||||
} = req.query;
|
reverse_order,
|
||||||
|
hide_legend,
|
||||||
|
|
||||||
|
// Master
|
||||||
|
bg_color,
|
||||||
|
hide_border,
|
||||||
|
hide_title,
|
||||||
|
theme,
|
||||||
|
title_color
|
||||||
|
} = req.query
|
||||||
|
|
||||||
prepareResponse(res)
|
prepareResponse(res)
|
||||||
|
console.log(theme)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await fetchHistory(username, clampValue(parseNumber(days_count) || 14, 1, 30));
|
const data = await fetchHistory(username, clampValue(parseNumber(days_count) || 14, 1, 30))
|
||||||
|
|
||||||
setCache(res, parseInt(cache_seconds || ''))
|
setCache(res, parseInt(cache_seconds || ''))
|
||||||
|
|
||||||
@ -48,8 +60,11 @@ export default async (req: Request<unknown, unknown, unknown, query>, res: Respo
|
|||||||
hide_title: parseBoolean(hide_title),
|
hide_title: parseBoolean(hide_title),
|
||||||
hide_border: parseBoolean(hide_border),
|
hide_border: parseBoolean(hide_border),
|
||||||
title_color,
|
title_color,
|
||||||
|
hide_legend: parseBoolean(hide_legend),
|
||||||
bg_color,
|
bg_color,
|
||||||
layout,
|
layout,
|
||||||
|
theme,
|
||||||
|
reverse_order: parseBoolean(reverse_order),
|
||||||
language_count: parseNumber(language_count),
|
language_count: parseNumber(language_count),
|
||||||
width: parseNumber(width),
|
width: parseNumber(width),
|
||||||
height: clampValue(parseNumber(height) || 300, 200),
|
height: clampValue(parseNumber(height) || 300, 200),
|
||||||
@ -59,6 +74,6 @@ export default async (req: Request<unknown, unknown, unknown, query>, res: Respo
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
return res.send(
|
return res.send(
|
||||||
ReactDOMServer.renderToStaticMarkup(new Error(err).render())
|
ReactDOMServer.renderToStaticMarkup(new Error(err).render())
|
||||||
);
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
47
api/index.ts
47
api/index.ts
@ -1,48 +1,53 @@
|
|||||||
import { parseBoolean, parseArray, prepareResponse, setCache} from '../src/common/utils'
|
import { Request, Response } from 'express'
|
||||||
import { fetchProfile } from '../src/fetcher'
|
|
||||||
import { Request, Response } from 'express';
|
|
||||||
import ReactDOMServer from 'react-dom/server'
|
import ReactDOMServer from 'react-dom/server'
|
||||||
import themes from '../themes/themes.json';
|
import { parseBoolean, parseArray, prepareResponse, setCache, parseNumber } from '../src/common/utils'
|
||||||
import ProfileCard from '../src/cards/ProfileCard';
|
import { fetchProfile } from '../src/fetcher'
|
||||||
import Error from '../src/components/Error';
|
import themes from '../themes/themes.json'
|
||||||
|
import ProfileCard from '../src/cards/ProfileCard'
|
||||||
|
import Error from '../src/components/Error'
|
||||||
|
|
||||||
export interface query {
|
export interface query {
|
||||||
username: string
|
username: string
|
||||||
hide?: string
|
hide?: string
|
||||||
hide_title?: string
|
|
||||||
hide_border?: string
|
|
||||||
hide_rank?: string
|
hide_rank?: string
|
||||||
show_icons?: string
|
show_icons?: string
|
||||||
line_height?: string
|
line_height?: string
|
||||||
title_color?: string
|
|
||||||
icon_color?: string
|
icon_color?: string
|
||||||
text_color?: string
|
text_color?: string
|
||||||
bg_color?: string
|
|
||||||
theme?: keyof typeof themes
|
|
||||||
cache_seconds?: string
|
cache_seconds?: string
|
||||||
|
|
||||||
|
// Mater
|
||||||
|
bg_color?: string
|
||||||
|
hide_border?: string
|
||||||
|
hide_title?: string
|
||||||
|
theme?: keyof typeof themes
|
||||||
|
title_color?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async (req: Request<unknown, unknown, unknown, query>, res: Response) => {
|
export default async (req: Request<unknown, unknown, unknown, query>, res: Response) => {
|
||||||
const {
|
const {
|
||||||
username,
|
username,
|
||||||
hide,
|
hide,
|
||||||
hide_title,
|
|
||||||
hide_border,
|
|
||||||
hide_rank,
|
hide_rank,
|
||||||
show_icons,
|
show_icons,
|
||||||
line_height,
|
line_height,
|
||||||
title_color,
|
|
||||||
icon_color,
|
icon_color,
|
||||||
text_color,
|
text_color,
|
||||||
|
cache_seconds,
|
||||||
|
|
||||||
|
// Master
|
||||||
bg_color,
|
bg_color,
|
||||||
|
hide_border,
|
||||||
|
hide_title,
|
||||||
theme,
|
theme,
|
||||||
cache_seconds
|
title_color
|
||||||
} = req.query;
|
|
||||||
|
} = req.query
|
||||||
|
|
||||||
prepareResponse(res)
|
prepareResponse(res)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await fetchProfile(username);
|
const data = await fetchProfile(username)
|
||||||
|
|
||||||
setCache(res, parseInt(cache_seconds || ''))
|
setCache(res, parseInt(cache_seconds || ''))
|
||||||
|
|
||||||
@ -53,17 +58,17 @@ export default async (req: Request<unknown, unknown, unknown, query>, res: Respo
|
|||||||
hide_title: parseBoolean(hide_title),
|
hide_title: parseBoolean(hide_title),
|
||||||
hide_border: parseBoolean(hide_border),
|
hide_border: parseBoolean(hide_border),
|
||||||
hide_rank: parseBoolean(hide_rank),
|
hide_rank: parseBoolean(hide_rank),
|
||||||
line_height: line_height ? parseInt(line_height , 10) : undefined,
|
line_height: parseNumber(line_height),
|
||||||
title_color,
|
title_color,
|
||||||
icon_color,
|
icon_color,
|
||||||
text_color,
|
text_color,
|
||||||
bg_color,
|
bg_color,
|
||||||
theme,
|
theme
|
||||||
}).render()
|
}).render()
|
||||||
))
|
))
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return res.send(
|
return res.send(
|
||||||
ReactDOMServer.renderToStaticMarkup(new Error(err).render())
|
ReactDOMServer.renderToStaticMarkup(new Error(err).render())
|
||||||
);
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
|
import { Request, Response } from 'express'
|
||||||
|
import ReactDOMServer from 'react-dom/server'
|
||||||
import { parseBoolean, parseArray, prepareResponse, setCache, parseNumber } from '../src/common/utils'
|
import { parseBoolean, parseArray, prepareResponse, setCache, parseNumber } from '../src/common/utils'
|
||||||
import { fetchTopLanguages } from '../src/fetcher'
|
import { fetchTopLanguages } from '../src/fetcher'
|
||||||
import TopLanguagesCard from '../src/cards/TopLanguagesCard'
|
import TopLanguagesCard from '../src/cards/TopLanguagesCard'
|
||||||
import { Request, Response } from 'express';
|
import themes from '../themes/themes.json'
|
||||||
import ReactDOMServer from 'react-dom/server'
|
import Error from '../src/components/Error'
|
||||||
import themes from '../themes/themes.json';
|
|
||||||
import Error from '../src/components/Error';
|
|
||||||
|
|
||||||
export interface query {
|
export interface query {
|
||||||
username: string
|
username: string
|
||||||
@ -35,8 +35,8 @@ export default async (req: Request<unknown, unknown, unknown, query>, res: Respo
|
|||||||
language_count,
|
language_count,
|
||||||
theme,
|
theme,
|
||||||
cache_seconds,
|
cache_seconds,
|
||||||
layout,
|
layout
|
||||||
} = req.query;
|
} = req.query
|
||||||
|
|
||||||
prepareResponse(res)
|
prepareResponse(res)
|
||||||
|
|
||||||
|
12
package.json
12
package.json
@ -10,31 +10,23 @@
|
|||||||
"author": "Anurag Hazra",
|
"author": "Anurag Hazra",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@actions/core": "^1.2.4",
|
|
||||||
"@actions/github": "^4.0.0",
|
|
||||||
"@testing-library/dom": "^7.20.0",
|
|
||||||
"@testing-library/jest-dom": "^5.11.0",
|
|
||||||
"@types/express": "^4.17.8",
|
"@types/express": "^4.17.8",
|
||||||
"@types/node-fetch": "^2.5.7",
|
"@types/node-fetch": "^2.5.7",
|
||||||
"@types/react": "^16.9.49",
|
"@types/react": "^16.9.49",
|
||||||
"@types/react-dom": "^16.9.8",
|
"@types/react-dom": "^16.9.8",
|
||||||
"css-to-object": "^1.1.0",
|
"@typescript-eslint/eslint-plugin": "^4.1.1",
|
||||||
|
"@typescript-eslint/parser": "^4.1.1",
|
||||||
"eslint": "^7.9.0",
|
"eslint": "^7.9.0",
|
||||||
"eslint-config-google": "^0.14.0",
|
"eslint-config-google": "^0.14.0",
|
||||||
"eslint-import-resolver-typescript": "^2.3.0",
|
"eslint-import-resolver-typescript": "^2.3.0",
|
||||||
"eslint-plugin-import": "^2.22.0",
|
"eslint-plugin-import": "^2.22.0",
|
||||||
"eslint-plugin-react": "^7.20.6",
|
"eslint-plugin-react": "^7.20.6",
|
||||||
"eslint-plugin-sonarjs": "^0.5.0",
|
"eslint-plugin-sonarjs": "^0.5.0",
|
||||||
"husky": "^4.2.5",
|
|
||||||
"jest": "^26.1.0",
|
"jest": "^26.1.0",
|
||||||
"parse-diff": "^0.7.0",
|
|
||||||
"ts-node": "^9.0.0",
|
"ts-node": "^9.0.0",
|
||||||
"vercel": "^20.1.0"
|
"vercel": "^20.1.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dotenv": "^8.2.0",
|
|
||||||
"emoji-name-map": "^1.2.8",
|
|
||||||
"github-username-regex": "^1.0.0",
|
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-dom": "^16.13.1",
|
"react-dom": "^16.13.1",
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import theme from '../themes'
|
import theme from '../themes/themes.json'
|
||||||
|
|
||||||
const TARGET_FILE = "./themes/README.md";
|
const BASE_URL = 'https://codestats-readme.vercel.app'
|
||||||
const REPO_CARD_LINKS_FLAG = "<!-- REPO_CARD_LINKS -->";
|
// const BASE_URL = 'http://localhost:3000'
|
||||||
const STAT_CARD_LINKS_FLAG = "<!-- STATS_CARD_LINKS -->";
|
|
||||||
|
|
||||||
const STAT_CARD_TABLE_FLAG = "<!-- STATS_CARD_TABLE -->";
|
const TARGET_FILE = './themes/README.md'
|
||||||
const REPO_CARD_TABLE_FLAG = "<!-- REPO_CARD_TABLE -->";
|
const LINKS_FLAG = '<!-- LINKS_FLAG -->'
|
||||||
|
|
||||||
|
const PROFILE_CARD_TABLE_FLAG = '<!-- PROFILE_TABLE -->'
|
||||||
|
const TOP_LANGS_CARD_TABLE_FLAG = '<!-- TOP_LANGS_TABLE -->'
|
||||||
|
const HISTORY_CARD_TABLE_FLAG = '<!-- HISTORY_TABLE -->'
|
||||||
|
|
||||||
const THEME_TEMPLATE = `## Available Themes
|
const THEME_TEMPLATE = `## Available Themes
|
||||||
|
|
||||||
@ -17,99 +20,100 @@ With inbuilt themes you can customize the look of the card without doing any man
|
|||||||
Use \`?theme=THEME_NAME\` parameter like so :-
|
Use \`?theme=THEME_NAME\` parameter like so :-
|
||||||
|
|
||||||
\`\`\`md
|
\`\`\`md
|
||||||

|

|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
## Stats
|
## Profile
|
||||||
|
|
||||||
> These themes work both for the Stats Card and Repo Card.
|
|
||||||
|
|
||||||
| | | |
|
| | | |
|
||||||
| :--: | :--: | :--: |
|
| :--: | :--: | :--: |
|
||||||
${STAT_CARD_TABLE_FLAG}
|
${PROFILE_CARD_TABLE_FLAG}
|
||||||
|
|
||||||
## Repo Card
|
## History Card
|
||||||
|
|
||||||
> These themes work both for the Stats Card and Repo Card.
|
|
||||||
|
|
||||||
| | | |
|
| | | |
|
||||||
| :--: | :--: | :--: |
|
| :--: | :--: | :--: |
|
||||||
${REPO_CARD_TABLE_FLAG}
|
${HISTORY_CARD_TABLE_FLAG}
|
||||||
|
|
||||||
${STAT_CARD_LINKS_FLAG}
|
## Top Langs Card
|
||||||
|
|
||||||
${REPO_CARD_LINKS_FLAG}
|
| | | |
|
||||||
|
| :--: | :--: | :--: |
|
||||||
|
${TOP_LANGS_CARD_TABLE_FLAG}
|
||||||
|
|
||||||
|
${LINKS_FLAG}
|
||||||
|
|
||||||
[add-theme]: https://github.com/aviortheking/codestats-readme/edit/master/themes/index.js
|
[add-theme]: https://github.com/aviortheking/codestats-readme/edit/master/themes/index.js
|
||||||
|
|
||||||
Wanted to add a new theme? Consider reading the [contribution guidelines](../CONTRIBUTING.md#themes-contribution) :D
|
Wanted to add a new theme? Consider reading the [contribution guidelines](../CONTRIBUTING.md#themes-contribution) :D
|
||||||
`;
|
`
|
||||||
|
|
||||||
const createRepoMdLink = (theme: string) => {
|
const createTopLangsMdLink = (theme: string) => {
|
||||||
return `\n[${theme}_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=${theme}`;
|
return `\n[top_langs_${theme}]: ${BASE_URL}/api/top-langs/?username=aviortheking&theme=${theme}`
|
||||||
};
|
}
|
||||||
const createStatMdLink = (theme: string) => {
|
const createProfileMdLink = (theme: string) => {
|
||||||
return `\n[${theme}]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=${theme}`;
|
return `\n[profile_${theme}]: ${BASE_URL}/api?username=aviortheking&show_icons=true&theme=${theme}`
|
||||||
};
|
}
|
||||||
|
|
||||||
const generateLinks = (fn: Function) => {
|
const createHistoryMdLink = (theme: string) => {
|
||||||
|
return `\n[history_${theme}]: ${BASE_URL}/api/history?username=Aviortheking&layout=horizontal&theme=${theme}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const generateLinks = (fn: typeof createHistoryMdLink) => {
|
||||||
return Object.keys(theme)
|
return Object.keys(theme)
|
||||||
.map((name) => fn(name))
|
.map((name) => fn(name))
|
||||||
.join("");
|
.join('')
|
||||||
};
|
}
|
||||||
|
|
||||||
const createTableItem = ({ link, label, isRepoCard }: {link: string, label: string, isRepoCard?: boolean}) => {
|
const createTableItem = ({ link, label }: {link: string, label: string}) => {
|
||||||
if (!link || !label) return "";
|
if (!link || !label) return ''
|
||||||
return `\`${label}\` ![${link}][${link}${isRepoCard ? "_repo" : ""}]`;
|
return `\`${label}\` ![${link}][${link}]`
|
||||||
};
|
}
|
||||||
const generateTable = ({ isRepoCard }: {isRepoCard?: boolean}) => {
|
const generateTable = (prefix: string) => {
|
||||||
const rows = [];
|
const rows = []
|
||||||
const themes = Object.keys(theme).filter(
|
const themes = Object.keys(theme)
|
||||||
(name) => name !== (!isRepoCard ? "default_repocard" : "default")
|
|
||||||
);
|
|
||||||
|
|
||||||
for (let i = 0; i < themes.length; i += 3) {
|
for (let i = 0; i < themes.length; i += 3) {
|
||||||
const one = themes[i];
|
const one = prefix + themes[i]
|
||||||
const two = themes[i + 1];
|
const two = prefix + themes[i + 1]
|
||||||
const three = themes[i + 2];
|
const three = prefix + themes[i + 2]
|
||||||
|
|
||||||
let tableItem1 = createTableItem({ link: one, label: one, isRepoCard });
|
const tableItem1 = createTableItem({ link: one, label: themes[i] })
|
||||||
let tableItem2 = createTableItem({ link: two, label: two, isRepoCard });
|
const tableItem2 = createTableItem({ link: two, label: themes[i + 1] })
|
||||||
let tableItem3 = createTableItem({ link: three, label: three, isRepoCard });
|
let tableItem3 = createTableItem({ link: three, label: themes[i + 2] })
|
||||||
|
|
||||||
if (three === undefined) {
|
if (three === undefined) {
|
||||||
tableItem3 = `[Add your theme][add-theme]`;
|
tableItem3 = '[Add your theme][add-theme]'
|
||||||
}
|
}
|
||||||
rows.push(`| ${tableItem1} | ${tableItem2} | ${tableItem3} |`);
|
rows.push(`| ${tableItem1} | ${tableItem2} | ${tableItem3} |`)
|
||||||
|
|
||||||
// if it's the last row & the row has no empty space push a new row
|
// if it's the last row & the row has no empty space push a new row
|
||||||
if (three && i + 3 === themes.length) {
|
if (three && i + 3 === themes.length) {
|
||||||
rows.push(`| [Add your theme][add-theme] | | |`);
|
rows.push('| [Add your theme][add-theme] | | |')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rows.join("\n");
|
return rows.join('\n')
|
||||||
};
|
}
|
||||||
|
|
||||||
const buildReadme = () => {
|
const buildReadme = () => {
|
||||||
return THEME_TEMPLATE.split("\n")
|
return THEME_TEMPLATE.split('\n')
|
||||||
.map((line) => {
|
.map((line) => {
|
||||||
if (line.includes(REPO_CARD_LINKS_FLAG)) {
|
if (line.includes(LINKS_FLAG)) {
|
||||||
return generateLinks(createRepoMdLink);
|
return generateLinks(createTopLangsMdLink) + generateLinks(createHistoryMdLink) + generateLinks(createProfileMdLink)
|
||||||
}
|
}
|
||||||
if (line.includes(STAT_CARD_LINKS_FLAG)) {
|
if (line.includes(PROFILE_CARD_TABLE_FLAG)) {
|
||||||
return generateLinks(createStatMdLink);
|
return generateTable('profile_')
|
||||||
}
|
}
|
||||||
if (line.includes(REPO_CARD_TABLE_FLAG)) {
|
if (line.includes(TOP_LANGS_CARD_TABLE_FLAG)) {
|
||||||
return generateTable({ isRepoCard: true });
|
return generateTable('top_langs_')
|
||||||
}
|
}
|
||||||
if (line.includes(STAT_CARD_TABLE_FLAG)) {
|
if (line.includes(HISTORY_CARD_TABLE_FLAG)) {
|
||||||
return generateTable({ isRepoCard: false });
|
return generateTable('history_')
|
||||||
}
|
}
|
||||||
return line;
|
return line
|
||||||
})
|
})
|
||||||
.join("\n");
|
.join('\n')
|
||||||
};
|
}
|
||||||
|
|
||||||
fs.writeFileSync(TARGET_FILE, buildReadme());
|
fs.writeFileSync(TARGET_FILE, buildReadme())
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
import { formatDateNumber, getColorOfLanguage } from "../common/utils"
|
|
||||||
import Card, { CardOptions } from '../common/Card'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import FlexLayout from "../components/FlexLayout"
|
import { formatDateNumber, getColor, getColorOfLanguage } from '../common/utils'
|
||||||
|
import Card, { CardOptions } from '../common/Card'
|
||||||
|
import FlexLayout from '../components/FlexLayout'
|
||||||
|
|
||||||
interface HistoryOptions extends CardOptions {
|
interface HistoryOptions extends CardOptions {
|
||||||
width?: number
|
width?: number
|
||||||
height?: number
|
height?: number
|
||||||
layout?: 'horizontal'
|
layout?: 'horizontal'
|
||||||
hide_legend?: boolean
|
hide_legend?: boolean
|
||||||
|
text_color?: string
|
||||||
|
title?: string
|
||||||
|
reverse_order?: boolean
|
||||||
|
|
||||||
// Put language in Other
|
// Put language in Other
|
||||||
hide?: Array<string>
|
hide?: Array<string>
|
||||||
@ -18,23 +21,19 @@ export default class HistoryCard extends Card {
|
|||||||
|
|
||||||
private topLanguages: Array<string>
|
private topLanguages: Array<string>
|
||||||
|
|
||||||
|
private legendMinWidth = 180
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
private username: string,
|
private username: string,
|
||||||
private days: Array<{day: string, total: number, data: Array<{xp: number, language: string}>}>,
|
private days: Array<{day: string, total: number, data: Array<{xp: number, language: string}>}>,
|
||||||
private options: HistoryOptions
|
private options: HistoryOptions
|
||||||
) {
|
) {
|
||||||
super(options)
|
super(options)
|
||||||
|
this.processOptions()
|
||||||
this.height = 45 + (this.days.length + 1) * 40
|
|
||||||
this.width = options.width ?? 500
|
|
||||||
if (options.layout === 'horizontal') {
|
|
||||||
this.width = 45 + (this.days.length + 1) * 40 + 100
|
|
||||||
this.height = options.height ?? 300
|
|
||||||
}
|
|
||||||
|
|
||||||
const languagesToHide = options.hide || []
|
const languagesToHide = options.hide || []
|
||||||
|
|
||||||
let languageCount: Array<{language: string, xp: number}> = []
|
const languageCount: Array<{language: string, xp: number}> = []
|
||||||
for (const day of this.days) {
|
for (const day of this.days) {
|
||||||
for (const data of day.data) {
|
for (const data of day.data) {
|
||||||
let index = languageCount.findIndex((item) => item.language === data.language)
|
let index = languageCount.findIndex((item) => item.language === data.language)
|
||||||
@ -56,15 +55,28 @@ export default class HistoryCard extends Card {
|
|||||||
this.topLanguages.push('Other')
|
this.topLanguages.push('Other')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.hideLanguages(languagesToHide)
|
||||||
|
}
|
||||||
|
|
||||||
|
private hideLanguages(languagesToHide: Array<string>) {
|
||||||
for (const day of this.days) {
|
for (const day of this.days) {
|
||||||
|
// Prepare array of indexes to remove
|
||||||
const toRemove: Array<number> = []
|
const toRemove: Array<number> = []
|
||||||
|
|
||||||
|
// Loop through data
|
||||||
for (let i = 0; i < day.data.length; i++) {
|
for (let i = 0; i < day.data.length; i++) {
|
||||||
const element = day.data[i];
|
const element = day.data[i]
|
||||||
if (languagesToHide.includes(element.language)) {
|
|
||||||
const otherIndex = day.data.findIndex((el) => el.language === 'Other')
|
// If Language should not be hidden: goto next
|
||||||
|
if (!languagesToHide.includes(element.language)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search indexOf 'Others'
|
||||||
|
const otherIndex = day.data.findIndex((el) => el.language === 'Others')
|
||||||
if (otherIndex === -1) {
|
if (otherIndex === -1) {
|
||||||
day.data.push({
|
day.data.push({
|
||||||
language: 'Other',
|
language: 'Others',
|
||||||
xp: element.xp
|
xp: element.xp
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@ -72,14 +84,28 @@ export default class HistoryCard extends Card {
|
|||||||
}
|
}
|
||||||
toRemove.push(i)
|
toRemove.push(i)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Reverse array and remove each indexes
|
||||||
for (const index of toRemove.reverse()) {
|
for (const index of toRemove.reverse()) {
|
||||||
day.data.splice(index, 1)
|
day.data.splice(index, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.title = 'Code History Language breakdown'
|
private processOptions() {
|
||||||
this.css = ProgressNode.getCSS('#000')
|
this.height = 45 + (this.days.length + 1) * 40
|
||||||
|
this.width = this.options.width ?? 500
|
||||||
|
if (this.options.layout === 'horizontal') {
|
||||||
|
this.width = 45 + (this.days.length + 1) * 40 + (this.options.hide_legend ? 0 : this.legendMinWidth)
|
||||||
|
this.height = this.options.height ?? 300
|
||||||
|
}
|
||||||
|
|
||||||
|
this.title = this.options.title ?? `Last ${this.days.length} days XP history`
|
||||||
|
this.css = ProgressNode.getCSS(getColor('text_color', this.options.text_color, this.options.theme))
|
||||||
|
|
||||||
|
if (this.options.reverse_order) {
|
||||||
|
this.days = this.days.reverse()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
@ -90,57 +116,71 @@ export default class HistoryCard extends Card {
|
|||||||
return prvs
|
return prvs
|
||||||
}, 0)
|
}, 0)
|
||||||
|
|
||||||
const legendWidth = Math.max(this.width * 20 / 100 + 60, 150)
|
const legendWidth = this.options.hide_legend ? 0 : Math.max(this.width * 20 / 100 + 60, this.legendMinWidth)
|
||||||
const historyWidth = this.width - legendWidth
|
const historyWidth = this.width - legendWidth
|
||||||
return super.render(
|
|
||||||
<svg x="25">
|
const items: Array<JSX.Element> = []
|
||||||
<FlexLayout items={[(() => {
|
|
||||||
if (this.options.layout === 'horizontal') {
|
// Format History bars
|
||||||
return (
|
const history = this.options.layout === 'horizontal' ? (
|
||||||
<FlexLayout items={
|
<FlexLayout
|
||||||
|
key={0}
|
||||||
|
items={
|
||||||
this.days.reverse().map((el, index) => (
|
this.days.reverse().map((el, index) => (
|
||||||
<VerticalProgressNode
|
<VerticalProgressNode
|
||||||
|
key={index}
|
||||||
{...el}
|
{...el}
|
||||||
totalTotal={totalTotal} height={this.height - 120} />
|
totalTotal={totalTotal}
|
||||||
|
height={this.height - 120}
|
||||||
|
/>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
gap={40}
|
gap={40}
|
||||||
// direction="column"
|
|
||||||
/>
|
/>
|
||||||
)
|
) : (
|
||||||
} else {
|
<FlexLayout
|
||||||
return (
|
key={0}
|
||||||
<FlexLayout items={
|
items={
|
||||||
this.days.map((el, index) => (
|
this.days.map((el, index) => (
|
||||||
<ProgressNode
|
<ProgressNode
|
||||||
|
key={index}
|
||||||
{...el}
|
{...el}
|
||||||
totalTotal={totalTotal} width={historyWidth - 30} />
|
totalTotal={totalTotal} width={historyWidth - 60} />
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
gap={40}
|
gap={40}
|
||||||
direction="column"
|
direction="column"
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
items.push(history)
|
||||||
})(), (
|
|
||||||
<FlexLayout items={
|
if (!this.options.hide_legend) {
|
||||||
|
items.push(
|
||||||
|
<FlexLayout
|
||||||
|
key={1}
|
||||||
|
items={
|
||||||
this.topLanguages.map((el, index) => (
|
this.topLanguages.map((el, index) => (
|
||||||
<>
|
<React.Fragment key={index}>
|
||||||
<rect rx="5" x="2" y="7" height="12" width="12" fill={getColorOfLanguage(el)} />
|
<rect rx="5" x="2" y="7" height="12" width="12" fill={getColorOfLanguage(el)} />
|
||||||
<text x="18" y="18" className="lang-name" key={index}>{el}</text>
|
<text x="18" y="18" className="lang-name" key={index}>{el}</text>
|
||||||
</>
|
</React.Fragment>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
gap={20}
|
gap={20}
|
||||||
direction="column"
|
direction="column"
|
||||||
/>
|
/>
|
||||||
)]}
|
)
|
||||||
gap={this.options.layout === 'horizontal' ? this.width - 180 : historyWidth - 20}
|
}
|
||||||
/>
|
|
||||||
|
|
||||||
|
return super.render(
|
||||||
|
<svg x="25">
|
||||||
|
<FlexLayout items={items}
|
||||||
|
gap={historyWidth}
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -159,7 +199,7 @@ class ProgressNode extends React.Component<{
|
|||||||
}
|
}
|
||||||
.xp-txt {
|
.xp-txt {
|
||||||
font: 400 12px 'Segoe UI', Ubuntu, Sans-Serif;
|
font: 400 12px 'Segoe UI', Ubuntu, Sans-Serif;
|
||||||
fill: ${textColor};
|
fill: black;
|
||||||
}
|
}
|
||||||
.xp-txt-invert {
|
.xp-txt-invert {
|
||||||
font: 600 12px 'Segoe UI', Ubuntu, Sans-Serif;
|
font: 600 12px 'Segoe UI', Ubuntu, Sans-Serif;
|
||||||
@ -197,7 +237,18 @@ class ProgressNode extends React.Component<{
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
{(() => {
|
{this.getXPText(offset)}
|
||||||
|
|
||||||
|
</svg>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private calcSize(number: number) {
|
||||||
|
return number * this.props.width / this.props.totalTotal
|
||||||
|
}
|
||||||
|
|
||||||
|
private getXPText(offset: number) {
|
||||||
let size = this.calcSize(offset) + 6
|
let size = this.calcSize(offset) + 6
|
||||||
const txtSize = (this.props.total.toString().length + 3) * 8
|
const txtSize = (this.props.total.toString().length + 3) * 8
|
||||||
let classes = 'xp-txt'
|
let classes = 'xp-txt'
|
||||||
@ -208,16 +259,8 @@ class ProgressNode extends React.Component<{
|
|||||||
return (
|
return (
|
||||||
<text x={size} y="33" className={classes}>{this.props.total} XP</text>
|
<text x={size} y="33" className={classes}>{this.props.total} XP</text>
|
||||||
)
|
)
|
||||||
})()}
|
|
||||||
|
|
||||||
</svg>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected calcSize(number: number) {
|
|
||||||
return number * this.props.width / this.props.totalTotal
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -228,6 +271,7 @@ class VerticalProgressNode extends React.Component<{
|
|||||||
data: Array<{xp: number, language: string}>
|
data: Array<{xp: number, language: string}>
|
||||||
height: number
|
height: number
|
||||||
}> {
|
}> {
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
let offset = this.props.totalTotal
|
let offset = this.props.totalTotal
|
||||||
const maskId = `mask-${this.props.day}`
|
const maskId = `mask-${this.props.day}`
|
||||||
@ -258,12 +302,12 @@ class VerticalProgressNode extends React.Component<{
|
|||||||
|
|
||||||
</svg>
|
</svg>
|
||||||
<text x="2" y={this.props.height + 18} className="subtitle">{new Date(this.props.day).toDateString().substr(4, 3)}</text>
|
<text x="2" y={this.props.height + 18} className="subtitle">{new Date(this.props.day).toDateString().substr(4, 3)}</text>
|
||||||
<text x="5" y={this.props.height + 34} className="subtitle">{formatDateNumber(new Date(this.props.day).getDate())}</text>
|
<text x="6" y={this.props.height + 34} className="subtitle">{formatDateNumber(new Date(this.props.day).getDate())}</text>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected calcSize(number: number) {
|
private calcSize(number: number) {
|
||||||
return number * this.props.height / this.props.totalTotal
|
return number * this.props.height / this.props.totalTotal
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,4 +323,5 @@ class VerticalProgressNode extends React.Component<{
|
|||||||
<text transform={`rotate(90, 4, ${position})`} letterSpacing="5" y={position} x="4" rotate="-90" className={classes}>{this.props.total} XP</text>
|
<text transform={`rotate(90, 4, ${position})`} letterSpacing="5" y={position} x="4" rotate="-90" className={classes}>{this.props.total} XP</text>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
import { kFormatter, encodeHTML, getProgress, getLevel, parseBoolean, calculateCircleProgress, getColor } from '../common/utils'
|
import React from 'react'
|
||||||
|
import {
|
||||||
|
kFormatter,
|
||||||
|
encodeHTML,
|
||||||
|
getProgress,
|
||||||
|
getLevel,
|
||||||
|
calculateCircleProgress,
|
||||||
|
getColor
|
||||||
|
} from '../common/utils'
|
||||||
import icons from '../common/icons'
|
import icons from '../common/icons'
|
||||||
import Card, { CardOptions } from '../common/Card'
|
import Card, { CardOptions } from '../common/Card'
|
||||||
import React from 'react'
|
|
||||||
import FlexLayout from '../components/FlexLayout'
|
import FlexLayout from '../components/FlexLayout'
|
||||||
|
|
||||||
interface ProfileCardOptions extends CardOptions {
|
interface ProfileCardOptions extends CardOptions {
|
||||||
@ -14,6 +21,7 @@ interface ProfileCardOptions extends CardOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class ProfileCard extends Card {
|
export default class ProfileCard extends Card {
|
||||||
|
|
||||||
private stats: Record<string, {
|
private stats: Record<string, {
|
||||||
icon: JSX.Element
|
icon: JSX.Element
|
||||||
label: string
|
label: string
|
||||||
@ -39,14 +47,14 @@ export default class ProfileCard extends Card {
|
|||||||
this.stats = {
|
this.stats = {
|
||||||
xp: {
|
xp: {
|
||||||
icon: icons.star,
|
icon: icons.star,
|
||||||
label: "XP",
|
label: 'XP',
|
||||||
value: xp,
|
value: xp
|
||||||
},
|
},
|
||||||
recent_xp: {
|
recent_xp: {
|
||||||
icon: icons.commits,
|
icon: icons.commits,
|
||||||
label: 'Recent xp',
|
label: 'Recent xp',
|
||||||
value: this.recentXp,
|
value: this.recentXp
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Card Settings
|
// Card Settings
|
||||||
@ -57,7 +65,7 @@ export default class ProfileCard extends Card {
|
|||||||
)
|
)
|
||||||
|
|
||||||
this.title = `${encodeHTML(this.username)}${
|
this.title = `${encodeHTML(this.username)}${
|
||||||
["x", "s"].includes(this.username.slice(-1)) ? "" : "s"
|
['x', 's'].includes(this.username.slice(-1)) ? '' : 's'
|
||||||
} Code::Stats Profile`
|
} Code::Stats Profile`
|
||||||
|
|
||||||
const textColor = getColor('text_color', options.text_color, options.theme)
|
const textColor = getColor('text_color', options.text_color, options.theme)
|
||||||
@ -67,7 +75,7 @@ export default class ProfileCard extends Card {
|
|||||||
this.css += RankCircle.getCSS(textColor, iconColor, getProgress(xp))
|
this.css += RankCircle.getCSS(textColor, iconColor, getProgress(xp))
|
||||||
}
|
}
|
||||||
if ((this.options.hide || []) < Object.keys(this.stats)) {
|
if ((this.options.hide || []) < Object.keys(this.stats)) {
|
||||||
this.css += TextNode.getCSS(textColor, !!this.options.show_icons ? iconColor : undefined)
|
this.css += TextNode.getCSS(textColor, this.options.show_icons ? iconColor : undefined)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,18 +85,23 @@ export default class ProfileCard extends Card {
|
|||||||
<RankCircle xp={this.options.hide_rank ? undefined : this.xp} />
|
<RankCircle xp={this.options.hide_rank ? undefined : this.xp} />
|
||||||
<svg x="0" y="0">
|
<svg x="0" y="0">
|
||||||
<FlexLayout
|
<FlexLayout
|
||||||
items={Object.keys(this.stats).filter((item) => !(this.options.hide || []).includes(item)).map((el, index) => {
|
items={
|
||||||
|
Object
|
||||||
|
.keys(this.stats)
|
||||||
|
.filter((item) => !(this.options.hide || []).includes(item))
|
||||||
|
.map((el, index) => {
|
||||||
const item = this.stats[el]
|
const item = this.stats[el]
|
||||||
return (
|
return (
|
||||||
<TextNode
|
<TextNode
|
||||||
{...item}
|
{...item}
|
||||||
icon={!!this.options.show_icons ? item.icon : undefined}
|
icon={this.options.show_icons ? item.icon : undefined}
|
||||||
key={index}
|
key={index}
|
||||||
index={index}
|
index={index}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
})}
|
})
|
||||||
|
}
|
||||||
gap={this.options.line_height || this.defaults.line_height}
|
gap={this.options.line_height || this.defaults.line_height}
|
||||||
direction="column"
|
direction="column"
|
||||||
/>
|
/>
|
||||||
@ -96,6 +109,7 @@ export default class ProfileCard extends Card {
|
|||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class RankCircle extends React.Component<{
|
class RankCircle extends React.Component<{
|
||||||
@ -160,6 +174,7 @@ class RankCircle extends React.Component<{
|
|||||||
</g>
|
</g>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TextNode extends React.Component<{
|
class TextNode extends React.Component<{
|
||||||
@ -200,7 +215,11 @@ class TextNode extends React.Component<{
|
|||||||
) : undefined
|
) : undefined
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g className="stagger" data-index={this.props.index} style={{animationDelay: `${delay}ms`}} transform="translate(25, 0)">
|
<g
|
||||||
|
className="stagger"
|
||||||
|
style={{ animationDelay: `${delay}ms` }}
|
||||||
|
transform="translate(25, 0)"
|
||||||
|
>
|
||||||
{icon}
|
{icon}
|
||||||
<text className="stat bold" x={this.props.icon ? 25 : undefined} y="12.5">{this.props.label}:</text>
|
<text className="stat bold" x={this.props.icon ? 25 : undefined} y="12.5">{this.props.label}:</text>
|
||||||
<text
|
<text
|
||||||
@ -211,4 +230,5 @@ class TextNode extends React.Component<{
|
|||||||
</g>
|
</g>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { getColor, getProgress, trunc } from "../common/utils"
|
|
||||||
import Card, { CardOptions } from '../common/Card'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import FlexLayout from "../components/FlexLayout";
|
import { getColor, getPercent, getProgress, trunc } from '../common/utils'
|
||||||
import { TopLanguage } from "../interfaces";
|
import Card, { CardOptions } from '../common/Card'
|
||||||
|
import FlexLayout from '../components/FlexLayout'
|
||||||
|
import { TopLanguage } from '../interfaces'
|
||||||
|
|
||||||
interface TopLanguagesOptions extends CardOptions {
|
interface TopLanguagesOptions extends CardOptions {
|
||||||
hide?: Array<string>
|
hide?: Array<string>
|
||||||
@ -34,11 +34,12 @@ export default class TopLanguagesCard extends Card {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const textColor = getColor('text_color', options.text_color, options.theme)
|
const textColor = getColor('text_color', options.text_color, options.theme)
|
||||||
this.title = "Most Used Languages"
|
this.title = 'Most Used Languages'
|
||||||
this.css = CompactTextNode.getCSS(textColor as string)
|
this.css = CompactTextNode.getCSS(textColor as string)
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
|
const total = this.langs.reduce((acc, curr) => acc + curr.xp, 0)
|
||||||
if (this.options.layout === 'compact') {
|
if (this.options.layout === 'compact') {
|
||||||
this.width = this.width + 50
|
this.width = this.width + 50
|
||||||
this.height = 90 + Math.round(this.langs.length / 2) * 25
|
this.height = 90 + Math.round(this.langs.length / 2) * 25
|
||||||
@ -47,9 +48,9 @@ export default class TopLanguagesCard extends Card {
|
|||||||
<mask id="rect-mask">
|
<mask id="rect-mask">
|
||||||
<rect x="0" y="0" width={this.width - 50} height="8" fill="white" rx="5" />
|
<rect x="0" y="0" width={this.width - 50} height="8" fill="white" rx="5" />
|
||||||
</mask>
|
</mask>
|
||||||
<CompactProgressBar langs={this.langs} parentWidth={this.width} />
|
<CompactProgressBar langs={this.langs} total={total} parentWidth={this.width} />
|
||||||
{this.langs.map((el, index) => (
|
{this.langs.map((el, index) => (
|
||||||
<CompactTextNode key={index} index={index} lang={el} />
|
<CompactTextNode key={index} index={index} total={total} lang={el} />
|
||||||
))}
|
))}
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
@ -58,7 +59,7 @@ export default class TopLanguagesCard extends Card {
|
|||||||
<svg x="25">
|
<svg x="25">
|
||||||
<FlexLayout items={
|
<FlexLayout items={
|
||||||
this.langs.map((el, index) => (
|
this.langs.map((el, index) => (
|
||||||
<ProgressNode lang={el} parentWidth={this.width} />
|
<ProgressNode key={index} lang={el} total={total} parentWidth={this.width} />
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
gap={40}
|
gap={40}
|
||||||
@ -68,19 +69,21 @@ export default class TopLanguagesCard extends Card {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CompactProgressBar extends React.Component<{
|
class CompactProgressBar extends React.Component<{
|
||||||
langs: Array<TopLanguage>
|
langs: Array<TopLanguage>
|
||||||
parentWidth: number
|
parentWidth: number
|
||||||
|
total: number
|
||||||
}> {
|
}> {
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
|
|
||||||
let offset = 0
|
let offset = 0
|
||||||
const totalSize = this.props.langs.reduce((acc, curr) => acc + curr.xp, 0)
|
|
||||||
|
|
||||||
return this.props.langs.map((lang, index) => {
|
return this.props.langs.map((lang, index) => {
|
||||||
const percent = trunc((lang.xp / totalSize) * (this.props.parentWidth - 50), 2)
|
const percent = trunc((lang.xp / this.props.total) * (this.props.parentWidth - 50), 2)
|
||||||
const progress = percent < 10 ? percent + 10 : percent
|
const progress = percent < 10 ? percent + 10 : percent
|
||||||
|
|
||||||
const output = (
|
const output = (
|
||||||
@ -92,7 +95,7 @@ class CompactProgressBar extends React.Component<{
|
|||||||
y="0"
|
y="0"
|
||||||
width={progress}
|
width={progress}
|
||||||
height="8"
|
height="8"
|
||||||
fill={lang.color || "#858585"}
|
fill={lang.color || '#858585'}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -100,11 +103,13 @@ class CompactProgressBar extends React.Component<{
|
|||||||
return output
|
return output
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CompactTextNode extends React.Component<{
|
class CompactTextNode extends React.Component<{
|
||||||
index: number
|
index: number
|
||||||
lang: TopLanguage
|
lang: TopLanguage
|
||||||
|
total: number
|
||||||
}> {
|
}> {
|
||||||
|
|
||||||
public static getCSS = (textColor: string) => `
|
public static getCSS = (textColor: string) => `
|
||||||
@ -128,17 +133,19 @@ class CompactTextNode extends React.Component<{
|
|||||||
<g transform={`translate(${x}, ${y})`}>
|
<g transform={`translate(${x}, ${y})`}>
|
||||||
<circle cx="5" cy="6" r="5" fill={this.props.lang.color} />
|
<circle cx="5" cy="6" r="5" fill={this.props.lang.color} />
|
||||||
<text data-testid="lang-name" x="15" y="10" className='lang-name'>
|
<text data-testid="lang-name" x="15" y="10" className='lang-name'>
|
||||||
{this.props.lang.name} {getProgress(this.props.lang.xp)}%
|
{this.props.lang.name} {getPercent(this.props.lang.xp, this.props.total)}%
|
||||||
</text>
|
</text>
|
||||||
</g>
|
</g>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ProgressNode extends React.Component<{
|
class ProgressNode extends React.Component<{
|
||||||
lang: TopLanguage
|
lang: TopLanguage
|
||||||
parentWidth: number
|
parentWidth: number
|
||||||
|
total: number
|
||||||
}> {
|
}> {
|
||||||
|
|
||||||
private paddingRight = 60
|
private paddingRight = 60
|
||||||
@ -146,12 +153,18 @@ class ProgressNode extends React.Component<{
|
|||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const width = this.props.parentWidth - this.paddingRight
|
const width = this.props.parentWidth - this.paddingRight
|
||||||
const progress1 = getProgress(this.props.lang.xp)
|
const progress1 = getPercent(this.props.lang.xp, this.props.total)
|
||||||
const progress2 = getProgress(this.props.lang.xp - this.props.lang.recentXp)
|
const progress2 = getPercent(this.props.lang.xp - this.props.lang.recentXp, this.props.total)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<text data-testid="lang-name" x="2" y="15" className="lang-name">{this.props.lang.name} {progress1}% {this.props.lang.recentXp >= 1 ? ' + ' + (trunc(progress1 - progress2, 2)) + '%' : ''}</text>
|
<text
|
||||||
|
x="2"
|
||||||
|
y="15"
|
||||||
|
className="lang-name"
|
||||||
|
>
|
||||||
|
{this.props.lang.name} {progress1}% {this.props.lang.recentXp >= 1 ? ` + ${trunc(progress1 - progress2, 2)}%` : ''}
|
||||||
|
</text>
|
||||||
<svg width={width}>
|
<svg width={width}>
|
||||||
<rect rx="5" ry="5" x="0" y="25" width={width} height="8" fill="#ddd" />
|
<rect rx="5" ry="5" x="0" y="25" width={width} height="8" fill="#ddd" />
|
||||||
{progress1 !== progress2 && (
|
{progress1 !== progress2 && (
|
||||||
@ -176,4 +189,5 @@ class ProgressNode extends React.Component<{
|
|||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ export interface CardOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class Card {
|
export default class Card {
|
||||||
|
|
||||||
public hideBorder = false
|
public hideBorder = false
|
||||||
public hideTitle = false
|
public hideTitle = false
|
||||||
public css = ''
|
public css = ''
|
||||||
@ -34,7 +35,7 @@ export default class Card {
|
|||||||
this.hideTitle = parseBoolean(options.hide_title)
|
this.hideTitle = parseBoolean(options.hide_title)
|
||||||
this.colors = {
|
this.colors = {
|
||||||
titleColor: getColor('title_color', options.title_color, options.theme),
|
titleColor: getColor('title_color', options.title_color, options.theme),
|
||||||
bgColor: getColor('bg_color', options.bg_color, options.theme),
|
bgColor: getColor('bg_color', options.bg_color, options.theme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,24 +76,24 @@ export default class Card {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderGradient() {
|
renderGradient() {
|
||||||
if (typeof this.colors.bgColor !== "object") return;
|
if (typeof this.colors.bgColor !== 'object') return
|
||||||
|
|
||||||
const gradients = this.colors.bgColor.slice(1);
|
const gradients = this.colors.bgColor.slice(1)
|
||||||
return typeof this.colors.bgColor === "object"
|
return typeof this.colors.bgColor === 'object' ?
|
||||||
? (
|
(
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient
|
<linearGradient
|
||||||
id="gradient"
|
id="gradient"
|
||||||
gradientTransform={`rotate(${this.colors.bgColor[0]})`}
|
gradientTransform={`rotate(${this.colors.bgColor[0]})`}
|
||||||
>
|
>
|
||||||
{gradients.map((grad, index) => {
|
{gradients.map((grad, index) => {
|
||||||
let offset = (index * 100) / (gradients.length - 1);
|
const offset = (index * 100) / (gradients.length - 1)
|
||||||
return `<stop offset="${offset}%" stop-color="#${grad}" />`;
|
return `<stop offset="${offset}%" stop-color="#${grad}" />`
|
||||||
})}
|
})}
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
)
|
) :
|
||||||
: "";
|
''
|
||||||
}
|
}
|
||||||
|
|
||||||
render(body: JSX.Element) {
|
render(body: JSX.Element) {
|
||||||
@ -141,14 +142,14 @@ export default class Card {
|
|||||||
stroke="#E4E2E2"
|
stroke="#E4E2E2"
|
||||||
width={this.width - 1}
|
width={this.width - 1}
|
||||||
fill={
|
fill={
|
||||||
typeof this.colors.bgColor === "object"
|
typeof this.colors.bgColor === 'object' ?
|
||||||
? "url(#gradient)"
|
'url(#gradient)' :
|
||||||
: this.colors.bgColor
|
this.colors.bgColor
|
||||||
}
|
}
|
||||||
strokeOpacity={this.hideBorder ? 0 : 1}
|
strokeOpacity={this.hideBorder ? 0 : 1}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{this.hideTitle ? "" : this.renderTitle()}
|
{this.hideTitle ? '' : this.renderTitle()}
|
||||||
|
|
||||||
<g
|
<g
|
||||||
transform={`translate(0, ${
|
transform={`translate(0, ${
|
||||||
@ -160,4 +161,5 @@ export default class Card {
|
|||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,6 @@ const icons = {
|
|||||||
issues: <path fillRule="evenodd" d="M8 1.5a6.5 6.5 0 100 13 6.5 6.5 0 000-13zM0 8a8 8 0 1116 0A8 8 0 010 8zm9 3a1 1 0 11-2 0 1 1 0 012 0zm-.25-6.25a.75.75 0 00-1.5 0v3.5a.75.75 0 001.5 0v-3.5z"/>,
|
issues: <path fillRule="evenodd" d="M8 1.5a6.5 6.5 0 100 13 6.5 6.5 0 000-13zM0 8a8 8 0 1116 0A8 8 0 010 8zm9 3a1 1 0 11-2 0 1 1 0 012 0zm-.25-6.25a.75.75 0 00-1.5 0v3.5a.75.75 0 001.5 0v-3.5z"/>,
|
||||||
icon: <path fillRule="evenodd" d="M2 2.5A2.5 2.5 0 014.5 0h8.75a.75.75 0 01.75.75v12.5a.75.75 0 01-.75.75h-2.5a.75.75 0 110-1.5h1.75v-2h-8a1 1 0 00-.714 1.7.75.75 0 01-1.072 1.05A2.495 2.495 0 012 11.5v-9zm10.5-1V9h-8c-.356 0-.694.074-1 .208V2.5a1 1 0 011-1h8zM5 12.25v3.25a.25.25 0 00.4.2l1.45-1.087a.25.25 0 01.3 0L8.6 15.7a.25.25 0 00.4-.2v-3.25a.25.25 0 00-.25-.25h-3.5a.25.25 0 00-.25.25z"/>,
|
icon: <path fillRule="evenodd" d="M2 2.5A2.5 2.5 0 014.5 0h8.75a.75.75 0 01.75.75v12.5a.75.75 0 01-.75.75h-2.5a.75.75 0 110-1.5h1.75v-2h-8a1 1 0 00-.714 1.7.75.75 0 01-1.072 1.05A2.495 2.495 0 012 11.5v-9zm10.5-1V9h-8c-.356 0-.694.074-1 .208V2.5a1 1 0 011-1h8zM5 12.25v3.25a.25.25 0 00.4.2l1.45-1.087a.25.25 0 01.3 0L8.6 15.7a.25.25 0 00.4-.2v-3.25a.25.25 0 00-.25-.25h-3.5a.25.25 0 00-.25.25z"/>,
|
||||||
contribs: <path fillRule="evenodd" d="M2 2.5A2.5 2.5 0 014.5 0h8.75a.75.75 0 01.75.75v12.5a.75.75 0 01-.75.75h-2.5a.75.75 0 110-1.5h1.75v-2h-8a1 1 0 00-.714 1.7.75.75 0 01-1.072 1.05A2.495 2.495 0 012 11.5v-9zm10.5-1V9h-8c-.356 0-.694.074-1 .208V2.5a1 1 0 011-1h8zM5 12.25v3.25a.25.25 0 00.4.2l1.45-1.087a.25.25 0 01.3 0L8.6 15.7a.25.25 0 00.4-.2v-3.25a.25.25 0 00-.25-.25h-3.5a.25.25 0 00-.25.25z"/>,
|
contribs: <path fillRule="evenodd" d="M2 2.5A2.5 2.5 0 014.5 0h8.75a.75.75 0 01.75.75v12.5a.75.75 0 01-.75.75h-2.5a.75.75 0 110-1.5h1.75v-2h-8a1 1 0 00-.714 1.7.75.75 0 01-1.072 1.05A2.495 2.495 0 012 11.5v-9zm10.5-1V9h-8c-.356 0-.694.074-1 .208V2.5a1 1 0 011-1h8zM5 12.25v3.25a.25.25 0 00.4.2l1.45-1.087a.25.25 0 01.3 0L8.6 15.7a.25.25 0 00.4-.2v-3.25a.25.25 0 00-.25-.25h-3.5a.25.25 0 00-.25.25z"/>,
|
||||||
fork: <path fillRule="evenodd" d="M5 3.25a.75.75 0 11-1.5 0 .75.75 0 011.5 0zm0 2.122a2.25 2.25 0 10-1.5 0v.878A2.25 2.25 0 005.75 8.5h1.5v2.128a2.251 2.251 0 101.5 0V8.5h1.5a2.25 2.25 0 002.25-2.25v-.878a2.25 2.25 0 10-1.5 0v.878a.75.75 0 01-.75.75h-4.5A.75.75 0 015 6.25v-.878zm3.75 7.378a.75.75 0 11-1.5 0 .75.75 0 011.5 0zm3-8.75a.75.75 0 100-1.5.75.75 0 000 1.5z"/>,
|
fork: <path fillRule="evenodd" d="M5 3.25a.75.75 0 11-1.5 0 .75.75 0 011.5 0zm0 2.122a2.25 2.25 0 10-1.5 0v.878A2.25 2.25 0 005.75 8.5h1.5v2.128a2.251 2.251 0 101.5 0V8.5h1.5a2.25 2.25 0 002.25-2.25v-.878a2.25 2.25 0 10-1.5 0v.878a.75.75 0 01-.75.75h-4.5A.75.75 0 015 6.25v-.878zm3.75 7.378a.75.75 0 11-1.5 0 .75.75 0 011.5 0zm3-8.75a.75.75 0 100-1.5.75.75 0 000 1.5z"/>
|
||||||
};
|
}
|
||||||
export default icons
|
export default icons
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
import { CodeStatsResponse } from '../interfaces'
|
||||||
import { CustomError } from './utils'
|
import { CustomError } from './utils'
|
||||||
import { CodeStatsResponse } from '../interfaces';
|
|
||||||
|
|
||||||
export default async function retryer<T = Promise<CodeStatsResponse>>(
|
export default async function retryer<T = Promise<CodeStatsResponse>>(
|
||||||
fetcher: (username: string) => T,
|
fetcher: (username: string) => T,
|
||||||
@ -8,7 +8,7 @@ export default async function retryer<T = Promise<CodeStatsResponse>>(
|
|||||||
err?: any
|
err?: any
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
if (retries > 7) {
|
if (retries > 7) {
|
||||||
throw new CustomError("Maximum retries exceeded" + err, 'MAX_RETRY')
|
throw new CustomError('Maximum retries exceeded' + err, 'MAX_RETRY')
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return await fetcher(
|
return await fetcher(
|
||||||
|
@ -2,7 +2,7 @@ import fetch from 'node-fetch'
|
|||||||
import { Response } from 'express'
|
import { Response } from 'express'
|
||||||
import wrap from 'word-wrap'
|
import wrap from 'word-wrap'
|
||||||
import themes from '../../themes/themes.json'
|
import themes from '../../themes/themes.json'
|
||||||
import { CodeStatsResponse } from '../interfaces';
|
import { CodeStatsResponse } from '../interfaces'
|
||||||
import languageColor from '../../themes/language-bar.json'
|
import languageColor from '../../themes/language-bar.json'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -14,42 +14,38 @@ import languageColor from '../../themes/language-bar.json'
|
|||||||
export function encodeHTML(str: string) {
|
export function encodeHTML(str: string) {
|
||||||
return str
|
return str
|
||||||
.replace(/[\u00A0-\u9999<>&](?!#)/gim, (i) => {
|
.replace(/[\u00A0-\u9999<>&](?!#)/gim, (i) => {
|
||||||
return "&#" + i.charCodeAt(0) + ";";
|
return '&#' + i.charCodeAt(0) + ';'
|
||||||
})
|
})
|
||||||
.replace(/\u0008/gim, "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const kFormatter = (num: number) =>
|
export function kFormatter(num: number) {
|
||||||
Math.abs(num) > 999 ?
|
return Math.abs(num) > 999 ?
|
||||||
trunc(num / 1000) + 'k' :
|
trunc(num / 1000) + 'k' :
|
||||||
num
|
num
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform the `value` into a Boolean
|
* Transform the `value` query string into a Boolean
|
||||||
* @param value the value to transform
|
* @param value the value to transform
|
||||||
*/
|
*/
|
||||||
export function parseBoolean(value: boolean | string | undefined) {
|
export function parseBoolean(value: boolean | string | undefined) {
|
||||||
if (value === "true" || value === true) {
|
return value === 'true' || value === '' || value === true
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseArray(str: string | undefined) {
|
export function parseArray(str: string | undefined) {
|
||||||
if (!str) return [];
|
if (!str) return []
|
||||||
return str.split(",");
|
return str.split(',')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clampValue(number: number, min: number, max?: number) {
|
export function clampValue(number: number, min: number, max?: number) {
|
||||||
return Math.max(min, max ? Math.min(number, max) : number);
|
return Math.max(min, max ? Math.min(number, max) : number)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function request(username: string): Promise<CodeStatsResponse> {
|
export async function request(username: string): Promise<CodeStatsResponse> {
|
||||||
const resp = await fetch(
|
const resp = await fetch(
|
||||||
`https://codestats.net/api/users/${username}`
|
`https://codestats.net/api/users/${username}`
|
||||||
);
|
)
|
||||||
return resp.json();
|
return resp.json()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function profileGraphRequest<T>(body: string): Promise<T> {
|
export async function profileGraphRequest<T>(body: string): Promise<T> {
|
||||||
@ -63,25 +59,28 @@ export async function profileGraphRequest<T>(body: string): Promise<T> {
|
|||||||
return resp.json()
|
return resp.json()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getColor(color: keyof typeof themes.default, replacementColor?: string, theme: keyof typeof themes = 'default') {
|
export function getColor(
|
||||||
|
color: keyof typeof themes.default,
|
||||||
|
replacementColor?: string,
|
||||||
|
theme: keyof typeof themes = 'default'
|
||||||
|
) {
|
||||||
return '#' + (replacementColor ? replacementColor : themes[theme][color])
|
return '#' + (replacementColor ? replacementColor : themes[theme][color])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function wrapTextMultiline(text: string, width = 60, maxLines = 3) {
|
export function wrapTextMultiline(text: string, width = 60, maxLines = 3) {
|
||||||
const wrapped = wrap(encodeHTML(text), { width })
|
const wrapped = wrap(encodeHTML(text), { width })
|
||||||
.split("\n") // Split wrapped lines to get an array of lines
|
.split('\n') // Split wrapped lines to get an array of lines
|
||||||
.map((line) => line.trim()); // Remove leading and trailing whitespace of each line
|
.map((line) => line.trim()) // Remove leading and trailing whitespace of each line
|
||||||
|
|
||||||
const lines = wrapped.slice(0, maxLines); // Only consider maxLines lines
|
const lines = wrapped.slice(0, maxLines) // Only consider maxLines lines
|
||||||
|
|
||||||
// Add "..." to the last line if the text exceeds maxLines
|
// Add "..." to the last line if the text exceeds maxLines
|
||||||
if (wrapped.length > maxLines) {
|
if (wrapped.length > maxLines) {
|
||||||
lines[maxLines - 1] += "...";
|
lines[maxLines - 1] += '...'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove empty lines if text fits in less than maxLines lines
|
// Remove empty lines if text fits in less than maxLines lines
|
||||||
const multiLineText = lines.filter(Boolean);
|
return lines.filter(Boolean)
|
||||||
return multiLineText;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CONSTANTS = {
|
export const CONSTANTS = {
|
||||||
@ -89,23 +88,25 @@ export const CONSTANTS = {
|
|||||||
TWO_HOURS: 7200,
|
TWO_HOURS: 7200,
|
||||||
FOUR_HOURS: 14400,
|
FOUR_HOURS: 14400,
|
||||||
ONE_DAY: 86400,
|
ONE_DAY: 86400,
|
||||||
LEVEL_FACTOR: 0.025,
|
LEVEL_FACTOR: 0.025
|
||||||
};
|
}
|
||||||
|
|
||||||
export const SECONDARY_ERROR_MESSAGES = {
|
export const SECONDARY_ERROR_MESSAGES = {
|
||||||
MAX_RETRY: "Make sur your profile is not private"
|
MAX_RETRY: 'Make sur your profile is not private'
|
||||||
};
|
}
|
||||||
|
|
||||||
export class CustomError extends Error {
|
export class CustomError extends Error {
|
||||||
|
|
||||||
public secondaryMessage: string
|
public secondaryMessage: string
|
||||||
|
|
||||||
constructor(message: string, public type: keyof typeof SECONDARY_ERROR_MESSAGES) {
|
constructor(message: string, public type: keyof typeof SECONDARY_ERROR_MESSAGES) {
|
||||||
super(message);
|
super(message)
|
||||||
this.secondaryMessage = SECONDARY_ERROR_MESSAGES[type] || "adsad";
|
this.secondaryMessage = SECONDARY_ERROR_MESSAGES[type] || 'adsad'
|
||||||
}
|
}
|
||||||
|
|
||||||
static MAX_RETRY = "MAX_RETRY";
|
static MAX_RETRY = 'MAX_RETRY'
|
||||||
static USER_NOT_FOUND = "USER_NOT_FOUND";
|
static USER_NOT_FOUND = 'USER_NOT_FOUND'
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -127,15 +128,19 @@ export function getProgress(xp: number): number {
|
|||||||
return trunc((CONSTANTS.LEVEL_FACTOR * Math.sqrt(xp) - currentLvl) * 100, 2)
|
return trunc((CONSTANTS.LEVEL_FACTOR * Math.sqrt(xp) - currentLvl) * 100, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getPercent(number: number, total: number) {
|
||||||
|
return trunc(number * 100 / total, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Truncate a number without moving it to a string and reparsing it
|
* Round a number without moving it to a string and reparsing it
|
||||||
*
|
*
|
||||||
* https://stackoverflow.com/a/29494612/7335674
|
* https://stackoverflow.com/a/29494612/7335674
|
||||||
* @param number the number to truncate
|
* @param number the number to truncate
|
||||||
* @param digits the number of digits after the dot
|
* @param digits the number of digits after the dot
|
||||||
*/
|
*/
|
||||||
export function trunc(number: number, digits: number = 0) {
|
export function trunc(number: number, digits = 0) {
|
||||||
const pow = Math.pow(10, digits)
|
const pow = Math.pow(10, digits)
|
||||||
return Math.round(number * pow) / pow
|
return Math.round(number * pow) / pow
|
||||||
}
|
}
|
||||||
@ -152,14 +157,12 @@ export function parseNumber(number: string | number | undefined): number | undef
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function calculateCircleProgress(percent: number) {
|
export function calculateCircleProgress(percent: number, radius = 40) {
|
||||||
let radius = 40;
|
const c = Math.PI * radius * 2
|
||||||
let c = Math.PI * radius * 2
|
|
||||||
|
|
||||||
percent = clampValue(percent, 0, 100)
|
percent = clampValue(percent, 0, 100)
|
||||||
|
|
||||||
let percentage = ((100 - percent) / 100) * c
|
return ((100 - percent) / 100) * c
|
||||||
return percentage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,7 +170,7 @@ export function calculateCircleProgress(percent: number) {
|
|||||||
* @param res the response object
|
* @param res the response object
|
||||||
*/
|
*/
|
||||||
export function prepareResponse(res: Response) {
|
export function prepareResponse(res: Response) {
|
||||||
res.setHeader("Content-Type", "image/svg+xml")
|
res.setHeader('Content-Type', 'image/svg+xml')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -175,7 +178,7 @@ export function prepareResponse(res: Response) {
|
|||||||
* @param res the Response object
|
* @param res the Response object
|
||||||
* @param cache The cache time in seconds
|
* @param cache The cache time in seconds
|
||||||
*/
|
*/
|
||||||
export function setCache(res: Response, cache: number) {
|
export function setCache(res: Response, cache = CONSTANTS.THIRTY_MINUTES) {
|
||||||
if (isNaN(cache)) {
|
if (isNaN(cache)) {
|
||||||
cache = CONSTANTS.THIRTY_MINUTES
|
cache = CONSTANTS.THIRTY_MINUTES
|
||||||
}
|
}
|
||||||
@ -204,5 +207,5 @@ export function formatDate(date: Date): string {
|
|||||||
|
|
||||||
|
|
||||||
export function getColorOfLanguage(name: string): string {
|
export function getColorOfLanguage(name: string): string {
|
||||||
return name in languageColor ? languageColor[name as keyof typeof languageColor].color || '#000' : '#000'
|
return name in languageColor ? languageColor[name as keyof typeof languageColor].color || '#3e4053' : '#3e4053'
|
||||||
}
|
}
|
||||||
|
@ -21,4 +21,5 @@ export default class Error extends React.Component<{
|
|||||||
</text>
|
</text>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ export default class FlexLayout extends React.Component<{
|
|||||||
gap: number
|
gap: number
|
||||||
direction?: 'column'
|
direction?: 'column'
|
||||||
}> {
|
}> {
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return this.props.items.filter(Boolean).map((item, index) => (
|
return this.props.items.filter(Boolean).map((item, index) => (
|
||||||
<g key={index} transform={this.getGap(index)}>{item}</g>
|
<g key={index} transform={this.getGap(index)}>{item}</g>
|
||||||
@ -19,4 +20,5 @@ export default class FlexLayout extends React.Component<{
|
|||||||
}
|
}
|
||||||
return transform
|
return transform
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { request, CONSTANTS, getLevel, profileGraphRequest, CustomError, formatDateNumber, formatDate, getColorOfLanguage } from '../common/utils'
|
import { request, getLevel, profileGraphRequest, CustomError, formatDate, getColorOfLanguage } from '../common/utils'
|
||||||
import retryer from '../common/retryer'
|
import retryer from '../common/retryer'
|
||||||
import { CodeStatsHistoryGraph, TopLanguages } from '../interfaces'
|
import { CodeStatsHistoryGraph, TopLanguages } from '../interfaces'
|
||||||
|
|
||||||
@ -28,6 +28,7 @@ export async function fetchHistory(username: string, days: number) {
|
|||||||
}`
|
}`
|
||||||
|
|
||||||
const response = await retryer<Promise<CodeStatsHistoryGraph>>(profileGraphRequest, body)
|
const response = await retryer<Promise<CodeStatsHistoryGraph>>(profileGraphRequest, body)
|
||||||
|
|
||||||
if (response.errors) {
|
if (response.errors) {
|
||||||
throw new CustomError(response.errors[0].message, 'MAX_RETRY')
|
throw new CustomError(response.errors[0].message, 'MAX_RETRY')
|
||||||
}
|
}
|
||||||
@ -48,23 +49,19 @@ export async function fetchHistory(username: string, days: number) {
|
|||||||
xp: data.xp,
|
xp: data.xp,
|
||||||
language: data.language
|
language: data.language
|
||||||
})
|
})
|
||||||
if (data.language in languagesData) {
|
if (!(data.language in languagesData)) {
|
||||||
|
languagesData[data.language] = 0
|
||||||
|
}
|
||||||
|
|
||||||
languagesData[data.language] += data.xp
|
languagesData[data.language] += data.xp
|
||||||
} else {
|
|
||||||
languagesData[data.language] = data.xp
|
|
||||||
}
|
|
||||||
|
|
||||||
result[data.date] = day
|
result[data.date] = day
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const key of Object.keys(result)) {
|
|
||||||
const item = result[key]
|
|
||||||
result[key] = item.sort((a, b) => languagesData[b.language] - languagesData[a.language])
|
|
||||||
}
|
|
||||||
|
|
||||||
const keys = Object.keys(result)
|
const keys = Object.keys(result)
|
||||||
|
|
||||||
for (const day of keys) {
|
for (const day of keys) {
|
||||||
|
const item = result[day]
|
||||||
|
result[day] = item.sort((a, b) => languagesData[b.language] - languagesData[a.language])
|
||||||
if (keys.indexOf(day) === 0 && day === formatDate(date)) {
|
if (keys.indexOf(day) === 0 && day === formatDate(date)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -77,21 +74,19 @@ export async function fetchHistory(username: string, days: number) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Object.keys(result).map((el) => {
|
return Object.keys(result).map((el) => ({
|
||||||
return {
|
|
||||||
data: result[el],
|
data: result[el],
|
||||||
day: el,
|
day: el,
|
||||||
total: result[el].reduce((prvs, crnt) => prvs + crnt.xp, 0)
|
total: result[el].reduce((prvs, crnt) => prvs + crnt.xp, 0)
|
||||||
}
|
})).sort((a, b) => a.day < b.day ? 1 : -1)
|
||||||
}).sort((a, b) => a.day < b.day ? 1 : -1)
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchTopLanguages(username: string): Promise<TopLanguages> {
|
export async function fetchTopLanguages(username: string): Promise<TopLanguages> {
|
||||||
if (!username) throw Error("Invalid username")
|
if (!username) throw Error('Invalid username')
|
||||||
|
|
||||||
let res = await retryer(request, username)
|
const res = await retryer(request, username)
|
||||||
|
|
||||||
const langs = res.languages
|
const langs = res.languages
|
||||||
|
|
||||||
|
259
themes/README.md
259
themes/README.md
@ -10,124 +10,169 @@ Use `?theme=THEME_NAME` parameter like so :-
|
|||||||

|

|
||||||
```
|
```
|
||||||
|
|
||||||
## Stats
|
## Profile
|
||||||
|
|
||||||
> These themes work both for the Stats Card and Repo Card.
|
|
||||||
|
|
||||||
| | | |
|
| | | |
|
||||||
| :--: | :--: | :--: |
|
| :--: | :--: | :--: |
|
||||||
| `default` ![default][default] | `dark` ![dark][dark] | `radical` ![radical][radical] |
|
| `default` ![profile_default][profile_default] | `dark` ![profile_dark][profile_dark] | `radical` ![profile_radical][profile_radical] |
|
||||||
| `merko` ![merko][merko] | `gruvbox` ![gruvbox][gruvbox] | `tokyonight` ![tokyonight][tokyonight] |
|
| `merko` ![profile_merko][profile_merko] | `gruvbox` ![profile_gruvbox][profile_gruvbox] | `tokyonight` ![profile_tokyonight][profile_tokyonight] |
|
||||||
| `onedark` ![onedark][onedark] | `cobalt` ![cobalt][cobalt] | `synthwave` ![synthwave][synthwave] |
|
| `onedark` ![profile_onedark][profile_onedark] | `cobalt` ![profile_cobalt][profile_cobalt] | `synthwave` ![profile_synthwave][profile_synthwave] |
|
||||||
| `highcontrast` ![highcontrast][highcontrast] | `dracula` ![dracula][dracula] | `prussian` ![prussian][prussian] |
|
| `highcontrast` ![profile_highcontrast][profile_highcontrast] | `dracula` ![profile_dracula][profile_dracula] | `prussian` ![profile_prussian][profile_prussian] |
|
||||||
| `monokai` ![monokai][monokai] | `vue` ![vue][vue] | `vue-dark` ![vue-dark][vue-dark] |
|
| `monokai` ![profile_monokai][profile_monokai] | `vue` ![profile_vue][profile_vue] | `vue-dark` ![profile_vue-dark][profile_vue-dark] |
|
||||||
| `shades-of-purple` ![shades-of-purple][shades-of-purple] | `nightowl` ![nightowl][nightowl] | `buefy` ![buefy][buefy] |
|
| `shades-of-purple` ![profile_shades-of-purple][profile_shades-of-purple] | `nightowl` ![profile_nightowl][profile_nightowl] | `buefy` ![profile_buefy][profile_buefy] |
|
||||||
| `blue-green` ![blue-green][blue-green] | `algolia` ![algolia][algolia] | `great-gatsby` ![great-gatsby][great-gatsby] |
|
| `blue-green` ![profile_blue-green][profile_blue-green] | `algolia` ![profile_algolia][profile_algolia] | `great-gatsby` ![profile_great-gatsby][profile_great-gatsby] |
|
||||||
| `darcula` ![darcula][darcula] | `bear` ![bear][bear] | `solarized-dark` ![solarized-dark][solarized-dark] |
|
| `darcula` ![profile_darcula][profile_darcula] | `bear` ![profile_bear][profile_bear] | `solarized-dark` ![profile_solarized-dark][profile_solarized-dark] |
|
||||||
| `solarized-light` ![solarized-light][solarized-light] | `chartreuse-dark` ![chartreuse-dark][chartreuse-dark] | `nord` ![nord][nord] |
|
| `solarized-light` ![profile_solarized-light][profile_solarized-light] | `chartreuse-dark` ![profile_chartreuse-dark][profile_chartreuse-dark] | `nord` ![profile_nord][profile_nord] |
|
||||||
| `gotham` ![gotham][gotham] | `material-palenight` ![material-palenight][material-palenight] | `graywhite` ![graywhite][graywhite] |
|
| `gotham` ![profile_gotham][profile_gotham] | `material-palenight` ![profile_material-palenight][profile_material-palenight] | `graywhite` ![profile_graywhite][profile_graywhite] |
|
||||||
| `vision-friendly-dark` ![vision-friendly-dark][vision-friendly-dark] | `ayu-mirage` ![ayu-mirage][ayu-mirage] | `midnight-purple` ![midnight-purple][midnight-purple] |
|
| `vision-friendly-dark` ![profile_vision-friendly-dark][profile_vision-friendly-dark] | `ayu-mirage` ![profile_ayu-mirage][profile_ayu-mirage] | `midnight-purple` ![profile_midnight-purple][profile_midnight-purple] |
|
||||||
| `calm` ![calm][calm] | `omni` ![omni][omni] | `react` ![react][react] |
|
| `calm` ![profile_calm][profile_calm] | `omni` ![profile_omni][profile_omni] | `react` ![profile_react][profile_react] |
|
||||||
| [Add your theme][add-theme] | | |
|
| [Add your theme][add-theme] | | |
|
||||||
|
|
||||||
## Repo Card
|
## History Card
|
||||||
|
|
||||||
> These themes work both for the Stats Card and Repo Card.
|
|
||||||
|
|
||||||
| | | |
|
| | | |
|
||||||
| :--: | :--: | :--: |
|
| :--: | :--: | :--: |
|
||||||
| `default_repocard` ![default_repocard][default_repocard_repo] | `dark` ![dark][dark_repo] | `radical` ![radical][radical_repo] |
|
| `default` ![history_default][history_default] | `dark` ![history_dark][history_dark] | `radical` ![history_radical][history_radical] |
|
||||||
| `merko` ![merko][merko_repo] | `gruvbox` ![gruvbox][gruvbox_repo] | `tokyonight` ![tokyonight][tokyonight_repo] |
|
| `merko` ![history_merko][history_merko] | `gruvbox` ![history_gruvbox][history_gruvbox] | `tokyonight` ![history_tokyonight][history_tokyonight] |
|
||||||
| `onedark` ![onedark][onedark_repo] | `cobalt` ![cobalt][cobalt_repo] | `synthwave` ![synthwave][synthwave_repo] |
|
| `onedark` ![history_onedark][history_onedark] | `cobalt` ![history_cobalt][history_cobalt] | `synthwave` ![history_synthwave][history_synthwave] |
|
||||||
| `highcontrast` ![highcontrast][highcontrast_repo] | `dracula` ![dracula][dracula_repo] | `prussian` ![prussian][prussian_repo] |
|
| `highcontrast` ![history_highcontrast][history_highcontrast] | `dracula` ![history_dracula][history_dracula] | `prussian` ![history_prussian][history_prussian] |
|
||||||
| `monokai` ![monokai][monokai_repo] | `vue` ![vue][vue_repo] | `vue-dark` ![vue-dark][vue-dark_repo] |
|
| `monokai` ![history_monokai][history_monokai] | `vue` ![history_vue][history_vue] | `vue-dark` ![history_vue-dark][history_vue-dark] |
|
||||||
| `shades-of-purple` ![shades-of-purple][shades-of-purple_repo] | `nightowl` ![nightowl][nightowl_repo] | `buefy` ![buefy][buefy_repo] |
|
| `shades-of-purple` ![history_shades-of-purple][history_shades-of-purple] | `nightowl` ![history_nightowl][history_nightowl] | `buefy` ![history_buefy][history_buefy] |
|
||||||
| `blue-green` ![blue-green][blue-green_repo] | `algolia` ![algolia][algolia_repo] | `great-gatsby` ![great-gatsby][great-gatsby_repo] |
|
| `blue-green` ![history_blue-green][history_blue-green] | `algolia` ![history_algolia][history_algolia] | `great-gatsby` ![history_great-gatsby][history_great-gatsby] |
|
||||||
| `darcula` ![darcula][darcula_repo] | `bear` ![bear][bear_repo] | `solarized-dark` ![solarized-dark][solarized-dark_repo] |
|
| `darcula` ![history_darcula][history_darcula] | `bear` ![history_bear][history_bear] | `solarized-dark` ![history_solarized-dark][history_solarized-dark] |
|
||||||
| `solarized-light` ![solarized-light][solarized-light_repo] | `chartreuse-dark` ![chartreuse-dark][chartreuse-dark_repo] | `nord` ![nord][nord_repo] |
|
| `solarized-light` ![history_solarized-light][history_solarized-light] | `chartreuse-dark` ![history_chartreuse-dark][history_chartreuse-dark] | `nord` ![history_nord][history_nord] |
|
||||||
| `gotham` ![gotham][gotham_repo] | `material-palenight` ![material-palenight][material-palenight_repo] | `graywhite` ![graywhite][graywhite_repo] |
|
| `gotham` ![history_gotham][history_gotham] | `material-palenight` ![history_material-palenight][history_material-palenight] | `graywhite` ![history_graywhite][history_graywhite] |
|
||||||
| `vision-friendly-dark` ![vision-friendly-dark][vision-friendly-dark_repo] | `ayu-mirage` ![ayu-mirage][ayu-mirage_repo] | `midnight-purple` ![midnight-purple][midnight-purple_repo] |
|
| `vision-friendly-dark` ![history_vision-friendly-dark][history_vision-friendly-dark] | `ayu-mirage` ![history_ayu-mirage][history_ayu-mirage] | `midnight-purple` ![history_midnight-purple][history_midnight-purple] |
|
||||||
| `calm` ![calm][calm_repo] | `omni` ![omni][omni_repo] | `react` ![react][react_repo] |
|
| `calm` ![history_calm][history_calm] | `omni` ![history_omni][history_omni] | `react` ![history_react][history_react] |
|
||||||
|
| [Add your theme][add-theme] | | |
|
||||||
|
|
||||||
|
## Top Langs Card
|
||||||
|
|
||||||
|
| | | |
|
||||||
|
| :--: | :--: | :--: |
|
||||||
|
| `default` ![top_langs_default][top_langs_default] | `dark` ![top_langs_dark][top_langs_dark] | `radical` ![top_langs_radical][top_langs_radical] |
|
||||||
|
| `merko` ![top_langs_merko][top_langs_merko] | `gruvbox` ![top_langs_gruvbox][top_langs_gruvbox] | `tokyonight` ![top_langs_tokyonight][top_langs_tokyonight] |
|
||||||
|
| `onedark` ![top_langs_onedark][top_langs_onedark] | `cobalt` ![top_langs_cobalt][top_langs_cobalt] | `synthwave` ![top_langs_synthwave][top_langs_synthwave] |
|
||||||
|
| `highcontrast` ![top_langs_highcontrast][top_langs_highcontrast] | `dracula` ![top_langs_dracula][top_langs_dracula] | `prussian` ![top_langs_prussian][top_langs_prussian] |
|
||||||
|
| `monokai` ![top_langs_monokai][top_langs_monokai] | `vue` ![top_langs_vue][top_langs_vue] | `vue-dark` ![top_langs_vue-dark][top_langs_vue-dark] |
|
||||||
|
| `shades-of-purple` ![top_langs_shades-of-purple][top_langs_shades-of-purple] | `nightowl` ![top_langs_nightowl][top_langs_nightowl] | `buefy` ![top_langs_buefy][top_langs_buefy] |
|
||||||
|
| `blue-green` ![top_langs_blue-green][top_langs_blue-green] | `algolia` ![top_langs_algolia][top_langs_algolia] | `great-gatsby` ![top_langs_great-gatsby][top_langs_great-gatsby] |
|
||||||
|
| `darcula` ![top_langs_darcula][top_langs_darcula] | `bear` ![top_langs_bear][top_langs_bear] | `solarized-dark` ![top_langs_solarized-dark][top_langs_solarized-dark] |
|
||||||
|
| `solarized-light` ![top_langs_solarized-light][top_langs_solarized-light] | `chartreuse-dark` ![top_langs_chartreuse-dark][top_langs_chartreuse-dark] | `nord` ![top_langs_nord][top_langs_nord] |
|
||||||
|
| `gotham` ![top_langs_gotham][top_langs_gotham] | `material-palenight` ![top_langs_material-palenight][top_langs_material-palenight] | `graywhite` ![top_langs_graywhite][top_langs_graywhite] |
|
||||||
|
| `vision-friendly-dark` ![top_langs_vision-friendly-dark][top_langs_vision-friendly-dark] | `ayu-mirage` ![top_langs_ayu-mirage][top_langs_ayu-mirage] | `midnight-purple` ![top_langs_midnight-purple][top_langs_midnight-purple] |
|
||||||
|
| `calm` ![top_langs_calm][top_langs_calm] | `omni` ![top_langs_omni][top_langs_omni] | `react` ![top_langs_react][top_langs_react] |
|
||||||
| [Add your theme][add-theme] | | |
|
| [Add your theme][add-theme] | | |
|
||||||
|
|
||||||
|
|
||||||
[default]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=default
|
[top_langs_default]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=default
|
||||||
[default_repocard]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=default_repocard
|
[top_langs_dark]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=dark
|
||||||
[dark]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=dark
|
[top_langs_radical]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=radical
|
||||||
[radical]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=radical
|
[top_langs_merko]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=merko
|
||||||
[merko]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=merko
|
[top_langs_gruvbox]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=gruvbox
|
||||||
[gruvbox]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=gruvbox
|
[top_langs_tokyonight]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=tokyonight
|
||||||
[tokyonight]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=tokyonight
|
[top_langs_onedark]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=onedark
|
||||||
[onedark]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=onedark
|
[top_langs_cobalt]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=cobalt
|
||||||
[cobalt]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=cobalt
|
[top_langs_synthwave]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=synthwave
|
||||||
[synthwave]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=synthwave
|
[top_langs_highcontrast]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=highcontrast
|
||||||
[highcontrast]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=highcontrast
|
[top_langs_dracula]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=dracula
|
||||||
[dracula]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=dracula
|
[top_langs_prussian]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=prussian
|
||||||
[prussian]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=prussian
|
[top_langs_monokai]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=monokai
|
||||||
[monokai]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=monokai
|
[top_langs_vue]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=vue
|
||||||
[vue]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=vue
|
[top_langs_vue-dark]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=vue-dark
|
||||||
[vue-dark]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=vue-dark
|
[top_langs_shades-of-purple]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=shades-of-purple
|
||||||
[shades-of-purple]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=shades-of-purple
|
[top_langs_nightowl]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=nightowl
|
||||||
[nightowl]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=nightowl
|
[top_langs_buefy]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=buefy
|
||||||
[buefy]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=buefy
|
[top_langs_blue-green]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=blue-green
|
||||||
[blue-green]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=blue-green
|
[top_langs_algolia]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=algolia
|
||||||
[algolia]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=algolia
|
[top_langs_great-gatsby]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=great-gatsby
|
||||||
[great-gatsby]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=great-gatsby
|
[top_langs_darcula]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=darcula
|
||||||
[darcula]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=darcula
|
[top_langs_bear]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=bear
|
||||||
[bear]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=bear
|
[top_langs_solarized-dark]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=solarized-dark
|
||||||
[solarized-dark]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=solarized-dark
|
[top_langs_solarized-light]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=solarized-light
|
||||||
[solarized-light]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=solarized-light
|
[top_langs_chartreuse-dark]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=chartreuse-dark
|
||||||
[chartreuse-dark]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=chartreuse-dark
|
[top_langs_nord]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=nord
|
||||||
[nord]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=nord
|
[top_langs_gotham]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=gotham
|
||||||
[gotham]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=gotham
|
[top_langs_material-palenight]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=material-palenight
|
||||||
[material-palenight]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=material-palenight
|
[top_langs_graywhite]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=graywhite
|
||||||
[graywhite]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=graywhite
|
[top_langs_vision-friendly-dark]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=vision-friendly-dark
|
||||||
[vision-friendly-dark]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=vision-friendly-dark
|
[top_langs_ayu-mirage]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=ayu-mirage
|
||||||
[ayu-mirage]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=ayu-mirage
|
[top_langs_midnight-purple]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=midnight-purple
|
||||||
[midnight-purple]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=midnight-purple
|
[top_langs_calm]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=calm
|
||||||
[calm]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=calm
|
[top_langs_omni]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=omni
|
||||||
[omni]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=omni
|
[top_langs_react]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=react
|
||||||
[react]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=react
|
[history_default]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=default
|
||||||
|
[history_dark]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=dark
|
||||||
|
[history_radical]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=radical
|
||||||
[default_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=default
|
[history_merko]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=merko
|
||||||
[default_repocard_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=default_repocard
|
[history_gruvbox]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=gruvbox
|
||||||
[dark_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=dark
|
[history_tokyonight]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=tokyonight
|
||||||
[radical_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=radical
|
[history_onedark]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=onedark
|
||||||
[merko_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=merko
|
[history_cobalt]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=cobalt
|
||||||
[gruvbox_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=gruvbox
|
[history_synthwave]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=synthwave
|
||||||
[tokyonight_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=tokyonight
|
[history_highcontrast]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=highcontrast
|
||||||
[onedark_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=onedark
|
[history_dracula]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=dracula
|
||||||
[cobalt_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=cobalt
|
[history_prussian]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=prussian
|
||||||
[synthwave_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=synthwave
|
[history_monokai]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=monokai
|
||||||
[highcontrast_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=highcontrast
|
[history_vue]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=vue
|
||||||
[dracula_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=dracula
|
[history_vue-dark]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=vue-dark
|
||||||
[prussian_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=prussian
|
[history_shades-of-purple]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=shades-of-purple
|
||||||
[monokai_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=monokai
|
[history_nightowl]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=nightowl
|
||||||
[vue_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=vue
|
[history_buefy]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=buefy
|
||||||
[vue-dark_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=vue-dark
|
[history_blue-green]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=blue-green
|
||||||
[shades-of-purple_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=shades-of-purple
|
[history_algolia]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=algolia
|
||||||
[nightowl_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=nightowl
|
[history_great-gatsby]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=great-gatsby
|
||||||
[buefy_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=buefy
|
[history_darcula]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=darcula
|
||||||
[blue-green_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=blue-green
|
[history_bear]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=bear
|
||||||
[algolia_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=algolia
|
[history_solarized-dark]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=solarized-dark
|
||||||
[great-gatsby_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=great-gatsby
|
[history_solarized-light]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=solarized-light
|
||||||
[darcula_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=darcula
|
[history_chartreuse-dark]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=chartreuse-dark
|
||||||
[bear_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=bear
|
[history_nord]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=nord
|
||||||
[solarized-dark_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=solarized-dark
|
[history_gotham]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=gotham
|
||||||
[solarized-light_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=solarized-light
|
[history_material-palenight]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=material-palenight
|
||||||
[chartreuse-dark_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=chartreuse-dark
|
[history_graywhite]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=graywhite
|
||||||
[nord_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=nord
|
[history_vision-friendly-dark]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=vision-friendly-dark
|
||||||
[gotham_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=gotham
|
[history_ayu-mirage]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=ayu-mirage
|
||||||
[material-palenight_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=material-palenight
|
[history_midnight-purple]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=midnight-purple
|
||||||
[graywhite_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=graywhite
|
[history_calm]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=calm
|
||||||
[vision-friendly-dark_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=vision-friendly-dark
|
[history_omni]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=omni
|
||||||
[ayu-mirage_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=ayu-mirage
|
[history_react]: https://codestats-readme.vercel.app/api/history?username=Aviortheking&layout=horizontal&theme=react
|
||||||
[midnight-purple_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=midnight-purple
|
[profile_default]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=default
|
||||||
[calm_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=calm
|
[profile_dark]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=dark
|
||||||
[omni_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=omni
|
[profile_radical]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=radical
|
||||||
[react_repo]: https://codestats-readme.vercel.app/api/top-langs/?username=aviortheking&theme=react
|
[profile_merko]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=merko
|
||||||
|
[profile_gruvbox]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=gruvbox
|
||||||
|
[profile_tokyonight]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=tokyonight
|
||||||
|
[profile_onedark]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=onedark
|
||||||
|
[profile_cobalt]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=cobalt
|
||||||
|
[profile_synthwave]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=synthwave
|
||||||
|
[profile_highcontrast]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=highcontrast
|
||||||
|
[profile_dracula]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=dracula
|
||||||
|
[profile_prussian]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=prussian
|
||||||
|
[profile_monokai]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=monokai
|
||||||
|
[profile_vue]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=vue
|
||||||
|
[profile_vue-dark]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=vue-dark
|
||||||
|
[profile_shades-of-purple]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=shades-of-purple
|
||||||
|
[profile_nightowl]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=nightowl
|
||||||
|
[profile_buefy]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=buefy
|
||||||
|
[profile_blue-green]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=blue-green
|
||||||
|
[profile_algolia]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=algolia
|
||||||
|
[profile_great-gatsby]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=great-gatsby
|
||||||
|
[profile_darcula]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=darcula
|
||||||
|
[profile_bear]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=bear
|
||||||
|
[profile_solarized-dark]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=solarized-dark
|
||||||
|
[profile_solarized-light]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=solarized-light
|
||||||
|
[profile_chartreuse-dark]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=chartreuse-dark
|
||||||
|
[profile_nord]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=nord
|
||||||
|
[profile_gotham]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=gotham
|
||||||
|
[profile_material-palenight]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=material-palenight
|
||||||
|
[profile_graywhite]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=graywhite
|
||||||
|
[profile_vision-friendly-dark]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=vision-friendly-dark
|
||||||
|
[profile_ayu-mirage]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=ayu-mirage
|
||||||
|
[profile_midnight-purple]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=midnight-purple
|
||||||
|
[profile_calm]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=calm
|
||||||
|
[profile_omni]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=omni
|
||||||
|
[profile_react]: https://codestats-readme.vercel.app/api?username=aviortheking&show_icons=true&theme=react
|
||||||
|
|
||||||
[add-theme]: https://github.com/aviortheking/codestats-readme/edit/master/themes/index.js
|
[add-theme]: https://github.com/aviortheking/codestats-readme/edit/master/themes/index.js
|
||||||
|
|
||||||
|
@ -1071,7 +1071,7 @@
|
|||||||
"color": null,
|
"color": null,
|
||||||
"url": "https://github.com/trending?l=OpenSCAD"
|
"url": "https://github.com/trending?l=OpenSCAD"
|
||||||
},
|
},
|
||||||
"Other": {
|
"Others": {
|
||||||
"color": "#b276b2"
|
"color": "#b276b2"
|
||||||
},
|
},
|
||||||
"Ox": {
|
"Ox": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user