Compare commits

..
Author SHA1 Message Date
Rick Staa e2abbdf940 ci: fix top-issues-action syntax 2022-08-25 19:42:08 +02:00
64 changed files with 844 additions and 11192 deletions
-33
View File
@@ -1,33 +0,0 @@
name: Test Deployment
on:
deployment_status:
jobs:
e2eTests:
if:
github.event_name == 'deployment_status' &&
github.event.deployment_status.state == 'success'
name: Perform 2e2 tests
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x]
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: npm
- name: Install dependencies
run: npm ci
env:
CI: true
- name: Run end-to-end tests.
run: npm run test:e2e
env:
VERCEL_PREVIEW_URL: ${{ github.event.deployment_status.target_url }}
@@ -1,31 +0,0 @@
name: Close empty issues and templates
on:
issues:
types:
- reopened
- opened
- edited
jobs:
closeEmptyIssuesAndTemplates:
name: Close empty issues
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3 # NOTE: Retrieve issue templates.
- name: Run empty issues closer action
uses: rickstaa/empty-issues-closer-action@v1
env:
github_token: ${{ secrets.GITHUB_TOKEN }}
with:
close_comment:
Closing this issue because it appears to be empty. Please update the
issue for it to be reopened.
open_comment:
Reopening this issue because the author provided more information.
check_templates: true
template_close_comment:
Closing this issue since the issue template was not filled in.
Please provide us with more information to have this issue reopened.
template_open_comment:
Reopening this issue because the author provided more information.
+7 -12
View File
@@ -1,4 +1,5 @@
name: Generate Theme Readme
on:
push:
branches:
@@ -7,25 +8,19 @@ on:
- "themes/index.js"
jobs:
generateThemeDoc:
build:
runs-on: ubuntu-latest
name: Generate theme doc
strategy:
matrix:
node-version: [16.x]
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
- uses: actions/checkout@v1
- name: setup node
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
cache: npm
node-version: "12.x"
- name: npm install, generate readme
run: |
npm ci
npm install
npm run theme-readme-gen
env:
CI: true
+1 -1
View File
@@ -6,6 +6,6 @@ jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v4
- uses: actions/labeler@v2
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
+8 -17
View File
@@ -1,33 +1,24 @@
name: Theme preview
on:
pull_request_target:
types: [opened, edited, reopened, synchronize]
types: [opened, synchronize, reopened]
branches:
- master
paths:
- theme-preview-script
- "themes/index.js"
jobs:
previewTheme:
name: Install & Preview
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x]
name: Install & Preview
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: npm
- uses: actions/checkout@v1
- uses: bahmutov/npm-install@v1
with:
useLockFile: false
- run: npm run preview-theme
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CI: true
PERSONAL_TOKEN: ${{ secrets.PERSONAL_TOKEN }}
@@ -1,30 +0,0 @@
name: Close stale theme pull requests that have the 'invalid' label.
on:
schedule:
- cron: "0 0 */7 * *"
jobs:
closeOldThemePrs:
name: Close stale 'invalid' theme PRs
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x]
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: npm
- uses: bahmutov/npm-install@v1
with:
useLockFile: false
- run: npm run close-stale-theme-prs
env:
STALE_DAYS: 15
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+5 -13
View File
@@ -1,4 +1,5 @@
name: Test
on:
push:
branches:
@@ -9,29 +10,20 @@ on:
jobs:
build:
name: Perform tests
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
cache: npm
node-version: "12.x"
- name: Install & Test
run: |
npm ci
npm install
npm run test
- name: Run Prettier
run: |
npm run format:check
- name: Code Coverage
uses: codecov/codecov-action@v1
+1 -3
View File
@@ -1,7 +1,7 @@
name: Update top issues dashboard
on:
schedule:
- cron: "0 0 */3 * *"
- cron: "0 0 */7 * *"
jobs:
showAndLabelTopIssues:
@@ -13,10 +13,8 @@ jobs:
env:
github_token: ${{ secrets.GITHUB_TOKEN }}
with:
filter: "1772"
label: false
dashboard: true
dashboard_show_total_reactions: true
top_issues: true
top_bugs: true
top_features: true
+1
View File
@@ -1,6 +1,7 @@
.vercel
.env
node_modules
package-lock.json
*.lock
.vscode/
.idea/
+11 -19
View File
@@ -1,25 +1,22 @@
import * as dotenv from "dotenv";
import { renderStatsCard } from "../src/cards/stats-card.js";
import { blacklist } from "../src/common/blacklist.js";
import {
require("dotenv").config();
const {
renderError,
parseBoolean,
parseArray,
clampValue,
CONSTANTS,
parseArray,
parseBoolean,
renderError,
} from "../src/common/utils.js";
import { fetchStats } from "../src/fetchers/stats-fetcher.js";
import { isLocaleAvailable } from "../src/translations.js";
} = require("../src/common/utils");
const fetchStats = require("../src/fetchers/stats-fetcher");
const renderStatsCard = require("../src/cards/stats-card");
const blacklist = require("../src/common/blacklist");
const { isLocaleAvailable } = require("../src/translations");
dotenv.config();
export default async (req, res) => {
module.exports = async (req, res) => {
const {
username,
hide,
hide_title,
hide_border,
card_width,
hide_rank,
show_icons,
count_private,
@@ -28,11 +25,9 @@ export default async (req, res) => {
title_color,
icon_color,
text_color,
text_bold,
bg_color,
theme,
cache_seconds,
exclude_repo,
custom_title,
locale,
disable_animations,
@@ -54,7 +49,6 @@ export default async (req, res) => {
username,
parseBoolean(count_private),
parseBoolean(include_all_commits),
parseArray(exclude_repo),
);
const cacheSeconds = clampValue(
@@ -71,14 +65,12 @@ export default async (req, res) => {
show_icons: parseBoolean(show_icons),
hide_title: parseBoolean(hide_title),
hide_border: parseBoolean(hide_border),
card_width: parseInt(card_width, 10),
hide_rank: parseBoolean(hide_rank),
include_all_commits: parseBoolean(include_all_commits),
line_height,
title_color,
icon_color,
text_color,
text_bold: parseBoolean(text_bold),
bg_color,
theme,
custom_title,
+10 -9
View File
@@ -1,15 +1,16 @@
import { renderRepoCard } from "../src/cards/repo-card.js";
import { blacklist } from "../src/common/blacklist.js";
import {
require("dotenv").config();
const {
renderError,
parseBoolean,
clampValue,
CONSTANTS,
parseBoolean,
renderError,
} from "../src/common/utils.js";
import { fetchRepo } from "../src/fetchers/repo-fetcher.js";
import { isLocaleAvailable } from "../src/translations.js";
} = require("../src/common/utils");
const fetchRepo = require("../src/fetchers/repo-fetcher");
const renderRepoCard = require("../src/cards/repo-card");
const blacklist = require("../src/common/blacklist");
const { isLocaleAvailable } = require("../src/translations");
export default async (req, res) => {
module.exports = async (req, res) => {
const {
username,
repo,
+12 -14
View File
@@ -1,19 +1,17 @@
import * as dotenv from "dotenv";
import { renderTopLanguages } from "../src/cards/top-languages-card.js";
import { blacklist } from "../src/common/blacklist.js";
import {
clampValue,
CONSTANTS,
parseArray,
parseBoolean,
require("dotenv").config();
const {
renderError,
} from "../src/common/utils.js";
import { fetchTopLanguages } from "../src/fetchers/top-languages-fetcher.js";
import { isLocaleAvailable } from "../src/translations.js";
clampValue,
parseBoolean,
parseArray,
CONSTANTS,
} = require("../src/common/utils");
const fetchTopLanguages = require("../src/fetchers/top-languages-fetcher");
const renderTopLanguages = require("../src/cards/top-languages-card");
const blacklist = require("../src/common/blacklist");
const { isLocaleAvailable } = require("../src/translations");
dotenv.config();
export default async (req, res) => {
module.exports = async (req, res) => {
const {
username,
hide,
+12 -14
View File
@@ -1,18 +1,16 @@
import * as dotenv from "dotenv";
import { renderWakatimeCard } from "../src/cards/wakatime-card.js";
import {
clampValue,
CONSTANTS,
parseArray,
parseBoolean,
require("dotenv").config();
const {
renderError,
} from "../src/common/utils.js";
import { fetchWakatimeStats } from "../src/fetchers/wakatime-fetcher.js";
import { isLocaleAvailable } from "../src/translations.js";
parseBoolean,
clampValue,
parseArray,
CONSTANTS,
} = require("../src/common/utils");
const { isLocaleAvailable } = require("../src/translations");
const { fetchWakatimeStats } = require("../src/fetchers/wakatime-fetcher");
const wakatimeCard = require("../src/cards/wakatime-card");
dotenv.config();
export default async (req, res) => {
module.exports = async (req, res) => {
const {
username,
title_color,
@@ -58,7 +56,7 @@ export default async (req, res) => {
res.setHeader("Cache-Control", `public, max-age=${cacheSeconds}`);
return res.send(
renderWakatimeCard(stats, {
wakatimeCard(stats, {
custom_title,
hide_title: parseBoolean(hide_title),
hide_border: parseBoolean(hide_border),
+1 -10
View File
@@ -1,12 +1,3 @@
export default {
module.exports = {
clearMocks: true,
transform: {},
testEnvironment: "jsdom",
coverageProvider: "v8",
testPathIgnorePatterns: ["<rootDir>/node_modules/", "<rootDir>/tests/e2e/"],
modulePathIgnorePatterns: ["<rootDir>/node_modules/", "<rootDir>/tests/e2e/"],
coveragePathIgnorePatterns: [
"<rootDir>/node_modules/",
"<rootDir>/tests/E2E/",
],
};
-7
View File
@@ -1,7 +0,0 @@
export default {
clearMocks: true,
transform: {},
testEnvironment: "node",
coverageProvider: "v8",
testMatch: ["<rootDir>/tests/e2e/**/*.test.js"],
};
-9398
View File
File diff suppressed because it is too large Load Diff
+10 -15
View File
@@ -3,33 +3,29 @@
"version": "1.0.0",
"description": "Dynamically generate stats for your github readmes",
"main": "index.js",
"type": "module",
"scripts": {
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage",
"test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch",
"test:update:snapshot": "node --experimental-vm-modules node_modules/jest/bin/jest.js -u",
"test:e2e": "node --experimental-vm-modules node_modules/jest/bin/jest.js --config jest.e2e.config.js",
"test": "jest --coverage",
"test:watch": "jest --watch",
"theme-readme-gen": "node scripts/generate-theme-doc",
"preview-theme": "node scripts/preview-theme",
"close-stale-theme-prs": "node scripts/close-stale-theme-prs",
"generate-langs-json": "node scripts/generate-langs-json",
"format": "./node_modules/.bin/prettier --write .",
"format:check": "./node_modules/.bin/prettier --check ."
"generate-langs-json": "node scripts/generate-langs-json"
},
"author": "Anurag Hazra",
"license": "MIT",
"engines": {
"node": ">=13"
},
"devDependencies": {
"@actions/core": "^1.9.1",
"@actions/core": "^1.2.4",
"@actions/github": "^4.0.0",
"@testing-library/dom": "^8.17.1",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/dom": "^7.20.0",
"@testing-library/jest-dom": "^5.11.0",
"@uppercod/css-to-object": "^1.1.1",
"axios-mock-adapter": "^1.18.1",
"color-contrast-checker": "^2.1.0",
"hjson": "^3.2.2",
"husky": "^4.2.5",
"jest": "^29.0.3",
"jest-environment-jsdom": "^29.0.3",
"jest": "^26.1.0",
"js-yaml": "^4.1.0",
"lodash.snakecase": "^4.1.1",
"parse-diff": "^0.7.0",
@@ -40,7 +36,6 @@
"dotenv": "^8.2.0",
"emoji-name-map": "^1.2.8",
"github-username-regex": "^1.0.0",
"upgrade": "^1.1.0",
"word-wrap": "^1.2.3"
},
"husky": {
+99 -104
View File
@@ -6,9 +6,6 @@
<p align="center">
<a href="https://github.com/anuraghazra/github-readme-stats/actions">
<img alt="Tests Passing" src="https://github.com/anuraghazra/github-readme-stats/workflows/Test/badge.svg" />
</a>
<a href="https://github.com/anuraghazra/github-readme-stats/graphs/contributors">
<img alt="GitHub Contributors" src="https://img.shields.io/github/contributors/anuraghazra/github-readme-stats" />
</a>
<a href="https://codecov.io/gh/anuraghazra/github-readme-stats">
<img src="https://codecov.io/gh/anuraghazra/github-readme-stats/branch/master/graph/badge.svg" />
@@ -64,35 +61,36 @@
</p>
<p align="center">Love the project? Please consider <a href="https://www.paypal.me/anuraghazra">donating</a> to help it improve!
<p>
<a href="https://indiafightscorona.giveindia.org">
<img src="https://indiaspora.org/wp-content/uploads/2021/04/give-India-logo.png" alt="Give india logo" width="200" />
<img src="https://d2wvdrxmr8p0wf.cloudfront.net/static/giveindia.svg" alt="Give india logo" width="200" />
</a>
Are you considering supporting the project by donating? Please DON'T!!
Are you considering supporting the project by donating? Please DON'T!!
Instead, Help India fight the 2nd deadly wave of COVID-19.
Thousands of people are dying in India because of a lack of Oxygen & also COVID-related infrastructure.
Instead, Help India fight the 2nd deadly wave of COVID-19.
Thousands of people are dying in India because of a lack of Oxygen & also COVID-related infrastructure.
Visit <https://indiafightscorona.giveindia.org> and make a small donation to help us fight COVID and overcome this crisis.
Visit [https://indiafightscorona.giveindia.org](https://indiafightscorona.giveindia.org) and make a small donation to help us fight COVID and overcome this crisis.
A small donation goes a long way. :heart:
</p>
# Features
- [GitHub Stats Card](#github-stats-card)
- [GitHub Extra Pins](#github-extra-pins)
- [Top Languages Card](#top-languages-card)
- [Wakatime Week Stats](#wakatime-week-stats)
- [Themes](#themes)
- [Customization](#customization)
- [Common Options](#common-options)
- [Stats Card Exclusive Options](#stats-card-exclusive-options)
- [Repo Card Exclusive Options](#repo-card-exclusive-options)
- [Language Card Exclusive Options](#language-card-exclusive-options)
- [Wakatime Card Exclusive Option](#wakatime-card-exclusive-options)
- [Deploy Yourself](#deploy-on-your-own-vercel-instance)
- [GitHub Stats Card](#github-stats-card)
- [GitHub Extra Pins](#github-extra-pins)
- [Top Languages Card](#top-languages-card)
- [Wakatime Week Stats](#wakatime-week-stats)
- [Themes](#themes)
- [Customization](#customization)
- [Common Options](#common-options)
- [Stats Card Exclusive Options](#stats-card-exclusive-options)
- [Repo Card Exclusive Options](#repo-card-exclusive-options)
- [Language Card Exclusive Options](#language-card-exclusive-options)
- [Wakatime Card Exclusive Option](#wakatime-card-exclusive-options)
- [Deploy Yourself](#deploy-on-your-own-vercel-instance)
# GitHub Stats Card
@@ -162,58 +160,54 @@ You can customize the appearance of your `Stats Card` or `Repo Card` however you
#### Common Options:
- `title_color` - Card's title color _(hex color)_. Default: `2f80ed`.
- `text_color` - Body text color _(hex color)_. Default: `434d58`.
- `icon_color` - Icons color if available _(hex color)_. Default: `4c71f2`.
- `border_color` - Card's border color _(hex color)_. Default: `e4e2e2` (Does not apply when `hide_border` is enabled).
- `bg_color` - Card's background color _(hex color)_ **or** a gradient in the form of _angle,start,end_. Default: `fffefe`
- `hide_border` - Hides the card's border _(boolean)_. Default: `false`
- `theme` - name of the theme, choose from [all available themes](./themes/README.md). Default: `default` theme.
- `cache_seconds` - set the cache header manually _(min: 7200, max: 86400)_. Default: `14400 seconds (4 hours)`.
- `locale` - set the language in the card _(e.g. cn, de, es, etc.)_. Default: `en`.
- `border_radius` - Corner rounding on the card. Default: `4.5`.
- `title_color` - Card's title color _(hex color)_
- `text_color` - Body text color _(hex color)_
- `icon_color` - Icons color if available _(hex color)_
- `border_color` - Card's border color _(hex color)_. (Does not apply when `hide_border` is enabled)
- `bg_color` - Card's background color _(hex color)_ **or** a gradient in the form of _angle,start,end_
- `hide_border` - Hides the card's border _(boolean)_
- `theme` - name of the theme, choose from [all available themes](./themes/README.md)
- `cache_seconds` - set the cache header manually _(min: 7200, max: 86400)_
- `locale` - set the language in the card _(e.g. cn, de, es, etc.)_
- `border_radius` - Corner rounding on the card_
> Note: The minimum of cache_seconds is currently 4 hours as a temporary fix for PATs exhaustion.
> Note: The minimum of cache_seconds is currently 4 hours as a temporary fix for PATs exhaustion.
##### Gradient in bg_color
You can provide multiple comma-separated values in the bg_color option to render a gradient, with the following format:
&bg_color=DEG,COLOR1,COLOR2,COLOR3...COLOR10
```
&bg_color=DEG,COLOR1,COLOR2,COLOR3...COLOR10
```
> Note on cache: Repo cards have a default cache of 4 hours (14400 seconds) if the fork count & star count is less than 1k, otherwise, it's 2 hours (7200 seconds). Also, note that the cache is clamped to a minimum of 2 hours and a maximum of 24 hours.
#### Stats Card Exclusive Options:
- `hide` - Hides the [specified items](#hiding-individual-stats) from stats _(Comma-separated values)_. Default: `[] (blank array)`.
- `hide_title` - _(boolean)_. Default: `false`.
- `card_width` - Set the card's width manually _(number)_. Default: `500px (approx.)`.
- `hide_rank` - _(boolean)_ hides the rank and automatically resizes the card width. Default: `false`.
- `show_icons` - _(boolean)_. Default: `false`.
- `include_all_commits` - Count total commits instead of just the current year commits _(boolean)_. Default: `false`.
- `count_private` - Count private commits _(boolean)_. Default: `false`.
- `line_height` - Sets the line-height between text _(number)_. Default: `25`.
- `exclude_repo` - Exclude stars from specified repositories _(Comma-separated values)_. Default: `[] (blank array)`.
- `custom_title` - Sets a custom title for the card. Default: `<username> Github Stats`.
- `text_bold` - Use bold text _(boolean)_. Default: `true`.
- `disable_animations` - Disables all animations in the card _(boolean)_. Default: `false`.
> Note on `hide_rank`:
> When hide_rank=`true`, the minimum card width is 270 px + the title length and padding.
- `hide` - Hides the [specified items](#hiding-individual-stats) from stats _(Comma-separated values)_
- `hide_title` - _(boolean)_
- `hide_rank` - _(boolean)_ hides the rank and automatically resizes the card width
- `show_icons` - _(boolean)_
- `include_all_commits` - Count total commits instead of just the current year commits _(boolean)_
- `count_private` - Count private commits _(boolean)_
- `line_height` - Sets the line-height between text _(number)_
- `custom_title` - Sets a custom title for the card
- `disable_animations` - Disables all animations in the card _(boolean)_
#### Repo Card Exclusive Options:
- `show_owner` - Show the repo's owner name _(boolean)_. Defaults to `false`.
- `show_owner` - Show the repo's owner name _(boolean)_
#### Language Card Exclusive Options:
- `hide` - Hide the languages specified from the card _(Comma-separated values)_
- `hide_title` - _(boolean)_. Defaults to `false`.
- `layout` - Switch between two available layouts `default` & `compact`
- `card_width` - Set the card's width manually _(number)_
- `langs_count` - Show more languages on the card, between 1-10, defaults to 5 _(number)_
- `exclude_repo` - Exclude specified repositories _(Comma-separated values)_
- `custom_title` - Sets a custom title for the card
- `hide` - Hide the languages specified from the card _(Comma-separated values)_
- `hide_title` - _(boolean)_
- `layout` - Switch between two available layouts `default` & `compact`
- `card_width` - Set the card's width manually _(number)_
- `langs_count` - Show more languages on the card, between 1-10, defaults to 5 _(number)_
- `exclude_repo` - Exclude specified repositories _(Comma-separated values)_
- `custom_title` - Sets a custom title for the card
> :warning: **Important:**
> Language names should be uri-escaped, as specified in [Percent Encoding](https://en.wikipedia.org/wiki/Percent-encoding)
@@ -222,17 +216,17 @@ You can provide multiple comma-separated values in the bg_color option to render
#### Wakatime Card Exclusive Options:
- `hide` - Hide the languages specified from the card _(Comma-separated values)_
- `hide_title` - _(boolean)_. Defaults to `false`.
- `line_height` - Sets the line-height between text _(number)_. Default Value: `25`.
- `hide_progress` - Hides the progress bar and percentage _(boolean)_
- `custom_title` - Sets a custom title for the card
- `layout` - Switch between two available layouts `default` & `compact`
- `langs_count` - Limit the number of languages on the card, defaults to all reported languages
- `api_domain` - Set a custom API domain for the card, e.g. to use services like [Hakatime](https://github.com/mujx/hakatime) or [Wakapi](https://github.com/muety/wakapi)
- `range` Request a range different from your WakaTime default, e.g. `last_7_days`. See [WakaTime API docs](https://wakatime.com/developers#stats) for a list of available options.
- `hide` - Hide the languages specified from the card _(Comma-separated values)_
- `hide_title` - _(boolean)_
- `line_height` - Sets the line-height between text _(number)_
- `hide_progress` - Hides the progress bar and percentage _(boolean)_
- `custom_title` - Sets a custom title for the card
- `layout` - Switch between two available layouts `default` & `compact`
- `langs_count` - Limit the number of languages on the card, defaults to all reported languages
- `api_domain` - Set a custom API domain for the card, e.g. to use services like [Hakatime](https://github.com/mujx/hakatime) or [Wakapi](https://github.com/muety/wakapi)
- `range` Request a range different from your WakaTime default, e.g. `last_7_days`. See [WakaTime API docs](https://wakatime.com/developers#stats) for a list of available options.
* * *
---
# GitHub Extra Pins
@@ -310,7 +304,7 @@ You can use the `&layout=compact` option to change the card design.
[![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra)](https://github.com/anuraghazra/github-readme-stats)
- Compact layout
- Compact layout
[![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra&layout=compact)](https://github.com/anuraghazra/github-readme-stats)
@@ -330,65 +324,65 @@ Change the `?username=` value to your [Wakatime](https://wakatime.com) username.
[![willianrod's wakatime stats](https://github-readme-stats.vercel.app/api/wakatime?username=willianrod&hide_progress=true)](https://github.com/anuraghazra/github-readme-stats)
- Compact layout
- Compact layout
[![willianrod's wakatime stats](https://github-readme-stats.vercel.app/api/wakatime?username=willianrod&layout=compact)](https://github.com/anuraghazra/github-readme-stats)
* * *
---
### All Demos
- Default
- Default
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra)
- Hiding specific stats
- Hiding specific stats
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&hide=contribs,issues)
- Showing icons
- Showing icons
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&hide=issues&show_icons=true)
- Customize Border Color
- Customize Border Color
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&border_color=2e4058)
- Include All Commits
- Include All Commits
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&include_all_commits=true)
- Themes
- Themes
Choose from any of the [default themes](#themes)
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&theme=radical)
- Gradient
- Gradient
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&bg_color=30,e96443,904e95&title_color=fff&text_color=fff)
- Customizing stats card
- Customizing stats card
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api/?username=anuraghazra&show_icons=true&title_color=fff&icon_color=79ff97&text_color=9f9f9f&bg_color=151515)
- Setting card locale
- Setting card locale
![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api/?username=anuraghazra&locale=es)
- Customizing repo card
- Customizing repo card
![Customized Card](https://github-readme-stats.vercel.app/api/pin?username=anuraghazra&repo=github-readme-stats&title_color=fff&icon_color=f9f9f9&text_color=9f9f9f&bg_color=151515)
- Top languages
- Top languages
[![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=anuraghazra)](https://github.com/anuraghazra/github-readme-stats)
- Wakatime card
- Wakatime card
[![willianrod's wakatime stats](https://github-readme-stats.vercel.app/api/wakatime?username=willianrod)](https://github.com/anuraghazra/github-readme-stats)
* * *
---
### Quick Tip (Align The Repo Cards)
@@ -416,23 +410,23 @@ NOTE: Since [#58](https://github.com/anuraghazra/github-readme-stats/pull/58) we
<details>
<summary><b> Guide on setting up Vercel 🔨 </b></summary>
1. Go to [vercel.com](https://vercel.com/)
2. Click on `Log in`
![](https://files.catbox.moe/tct1wg.png)
3. Sign in with GitHub by pressing `Continue with GitHub`
![](https://files.catbox.moe/btd78j.jpeg)
4. Sign in to GitHub and allow access to all repositories, if prompted
5. Fork this repo
6. After forking the repo, open the [`vercel.json`](https://github.com/anuraghazra/github-readme-stats/blob/master/vercel.json#L5) file and change the `maxDuration` field to `10`
7. Go back to your [Vercel dashboard](https://vercel.com/dashboard)
8. Select `Import Project`
![](https://files.catbox.moe/qckos0.png)
9. Select `Import Git Repository`. Select root and keep everything as is.
![](https://files.catbox.moe/pqub9q.png)
10. Create a personal access token (PAT) [here](https://github.com/settings/tokens/new) and enable the `repo` permissions (this allows access to see private repo stats)
11. Add the PAT as an environment variable named `PAT_1` (as shown).
![](https://files.catbox.moe/0ez4g7.png)
12. Click deploy, and you're good to go. See your domains to use the API!
1. Go to [vercel.com](https://vercel.com/)
1. Click on `Log in`
![](https://files.catbox.moe/tct1wg.png)
1. Sign in with GitHub by pressing `Continue with GitHub`
![](https://files.catbox.moe/btd78j.jpeg)
1. Sign in to GitHub and allow access to all repositories, if prompted
1. Fork this repo
1. After forking the repo, open the [`vercel.json`](https://github.com/anuraghazra/github-readme-stats/blob/master/vercel.json#L5) file and change the `maxDuration` field to `10`
1. Go back to your [Vercel dashboard](https://vercel.com/dashboard)
1. Select `Import Project`
![](https://files.catbox.moe/qckos0.png)
1. Select `Import Git Repository`. Select root and keep everything as is.
![](https://files.catbox.moe/pqub9q.png)
1. Create a personal access token (PAT) [here](https://github.com/settings/tokens/new) and enable the `repo` permissions (this allows access to see private repo stats)
1. Add the PAT as an environment variable named `PAT_1` (as shown).
![](https://files.catbox.moe/0ez4g7.png)
1. Click deploy, and you're good to go. See your domains to use the API!
</details>
@@ -443,16 +437,17 @@ this takes time. You can use this service for free.
However, if you are using this project and are happy with it or just want to encourage me to continue creating stuff, there are a few ways you can do it:-
- Giving proper credit when you use github-readme-stats on your readme, linking back to it :D
- Starring and sharing the project :rocket:
- [![paypal.me/anuraghazra](https://ionicabizau.github.io/badges/paypal.svg)](https://www.paypal.me/anuraghazra) - You can make one-time donations via PayPal. I'll probably buy a ~~coffee~~ tea. :tea:
- Giving proper credit when you use github-readme-stats on your readme, linking back to it :D
- Starring and sharing the project :rocket:
- [![paypal.me/anuraghazra](https://ionicabizau.github.io/badges/paypal.svg)](https://www.paypal.me/anuraghazra) - You can make one-time donations via PayPal. I'll probably buy a ~~coffee~~ tea. :tea:
Thanks! :heart:
* * *
---
[![https://vercel.com?utm_source=github_readme_stats_team&utm_campaign=oss](./powered-by-vercel.svg)](https://vercel.com?utm_source=github_readme_stats_team&utm_campaign=oss)
Contributions are welcome! &lt;3
Contributions are welcome! <3
Made with :heart: and JavaScript.
-161
View File
@@ -1,161 +0,0 @@
/**
* @file Script that can be used to close stale theme PRs that have a `invalid` label.
*/
import * as dotenv from "dotenv";
dotenv.config();
import { debug, setFailed } from "@actions/core";
import github from "@actions/github";
import { RequestError } from "@octokit/request-error";
import { getGithubToken, getRepoInfo } from "./helpers.js";
// Script parameters
const CLOSING_COMMENT = `
\rThis PR has been automatically closed due to inactivity. Please feel free to reopen it if you need to continue working on it.\
\rThank you for your contributions.
`;
/**
* Fetch open PRs from a given repository.
* @param user The user name of the repository owner.
* @param repo The name of the repository.
* @returns The open PRs.
*/
export const fetchOpenPRs = async (octokit, user, repo) => {
const openPRs = [];
let hasNextPage = true;
let endCursor;
while (hasNextPage) {
try {
const { repository } = await octokit.graphql(
`
{
repository(owner: "${user}", name: "${repo}") {
open_prs: pullRequests(${
endCursor ? `after: "${endCursor}", ` : ""
}
first: 100, states: OPEN, orderBy: {field: CREATED_AT, direction: DESC}) {
nodes {
number
commits(last:1){
nodes{
commit{
pushedDate
}
}
}
labels(first: 100, orderBy:{field: CREATED_AT, direction: DESC}) {
nodes {
name
}
}
reviews(first: 1, states: CHANGES_REQUESTED, author: "github-actions[bot]") {
nodes {
updatedAt
}
}
}
pageInfo {
endCursor
hasNextPage
}
}
}
}
`,
);
openPRs.push(...repository.open_prs.nodes);
hasNextPage = repository.open_prs.pageInfo.hasNextPage;
endCursor = repository.open_prs.pageInfo.endCursor;
} catch (error) {
if (error instanceof RequestError) {
setFailed(`Could not retrieve top PRs using GraphQl: ${error.message}`);
}
throw error;
}
}
return openPRs;
};
/**
* Retrieve pull requests that have a given label.
* @param pull The pull requests to check.
* @param label The label to check for.
*/
export const pullsWithLabel = (pulls, label) => {
return pulls.filter((pr) => {
return pr.labels.nodes.some((lab) => lab.name === label);
});
};
/**
* Check if PR is stale. Meaning that it hasn't been updated in a given time.
* @param {Object} pullRequest request object.
* @param {number} days number of days.
* @returns Boolean indicating if PR is stale.
*/
const isStale = (pullRequest, staleDays) => {
const lastCommitDate = new Date(
pullRequest.commits.nodes[0].commit.pushedDate,
);
if (pullRequest.reviews.nodes[0]) {
const lastReviewDate = new Date(pullRequest.reviews.nodes[0].updatedAt);
const lastUpdateDate =
lastCommitDate >= lastReviewDate ? lastCommitDate : lastReviewDate;
const now = new Date();
return now - lastUpdateDate > 1000 * 60 * 60 * 24 * staleDays;
} else {
return false;
}
};
/**
* Main function.
*/
const run = async () => {
try {
// Create octokit client.
const dryRun = process.env.DRY_RUN === "true" || false;
const staleDays = process.env.STALE_DAYS || 15;
debug("Creating octokit client...");
const octokit = github.getOctokit(getGithubToken());
const { owner, repo } = getRepoInfo(github.context);
// Retrieve all theme pull requests.
debug("Retrieving all theme pull requests...");
const prs = await fetchOpenPRs(octokit, owner, repo);
const themePRs = pullsWithLabel(prs, "themes");
const invalidThemePRs = pullsWithLabel(themePRs, "invalid");
debug("Retrieving stale theme PRs...");
const staleThemePRs = invalidThemePRs.filter((pr) =>
isStale(pr, staleDays),
);
const staleThemePRsNumbers = staleThemePRs.map((pr) => pr.number);
debug(`Found ${staleThemePRs.length} stale theme PRs`);
// Loop through all stale invalid theme pull requests and close them.
for (const prNumber of staleThemePRsNumbers) {
debug(`Closing #${prNumber} because it is stale...`);
if (!dryRun) {
await octokit.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: CLOSING_COMMENT,
});
await octokit.pulls.update({
owner,
repo,
pull_number: prNumber,
state: "closed",
});
} else {
debug("Dry run enabled, skipping...");
}
}
} catch (error) {
setFailed(error.message);
}
};
run();
+18 -22
View File
@@ -1,30 +1,26 @@
import axios from "axios";
import fs from "fs";
import jsYaml from "js-yaml";
const fs = require('fs');
const jsYaml = require('js-yaml');
const axios = require('axios');
const LANGS_FILEPATH = "./src/common/languageColors.json";
const LANGS_FILEPATH = "./src/common/languageColors.json"
//Retrieve languages from github linguist repository yaml file
//@ts-ignore
axios
.get(
"https://raw.githubusercontent.com/github/linguist/master/lib/linguist/languages.yml",
)
.then((response) => {
//and convert them to a JS Object
const languages = jsYaml.load(response.data);
axios.get("https://raw.githubusercontent.com/github/linguist/master/lib/linguist/languages.yml")
.then((response) => {
const languageColors = {};
//and convert them to a JS Object
const languages = jsYaml.load(response.data);
//Filter only language colors from the whole file
Object.keys(languages).forEach((lang) => {
languageColors[lang] = languages[lang].color;
});
const languageColors = {};
//Debug Print
//console.dir(languageColors);
fs.writeFileSync(
LANGS_FILEPATH,
JSON.stringify(languageColors, null, " "),
);
//Filter only language colors from the whole file
Object.keys(languages).forEach((lang) => {
languageColors[lang] = languages[lang].color;
});
//Debug Print
//console.dir(languageColors);
fs.writeFileSync(LANGS_FILEPATH, JSON.stringify(languageColors, null, ' '));
});
+9 -9
View File
@@ -1,5 +1,5 @@
import fs from "fs";
import { themes } from "../themes/index.js";
const theme = require("../themes/index");
const fs = require("fs");
const TARGET_FILE = "./themes/README.md";
const REPO_CARD_LINKS_FLAG = "<!-- REPO_CARD_LINKS -->";
@@ -54,7 +54,7 @@ const createStatMdLink = (theme) => {
};
const generateLinks = (fn) => {
return Object.keys(themes)
return Object.keys(theme)
.map((name) => fn(name))
.join("");
};
@@ -65,14 +65,14 @@ const createTableItem = ({ link, label, isRepoCard }) => {
};
const generateTable = ({ isRepoCard }) => {
const rows = [];
const themesFiltered = Object.keys(themes).filter(
const themes = Object.keys(theme).filter(
(name) => name !== (!isRepoCard ? "default_repocard" : "default"),
);
for (let i = 0; i < themesFiltered.length; i += 3) {
const one = themesFiltered[i];
const two = themesFiltered[i + 1];
const three = themesFiltered[i + 2];
for (let i = 0; i < themes.length; i += 3) {
const one = themes[i];
const two = themes[i + 1];
const three = themes[i + 2];
let tableItem1 = createTableItem({ link: one, label: one, isRepoCard });
let tableItem2 = createTableItem({ link: two, label: two, isRepoCard });
@@ -84,7 +84,7 @@ const generateTable = ({ isRepoCard }) => {
rows.push(`| ${tableItem1} | ${tableItem2} | ${tableItem3} |`);
// if it's the last row & the row has no empty space push a new row
if (three && i + 3 === themesFiltered.length) {
if (three && i + 3 === themes.length) {
rows.push(`| [Add your theme][add-theme] | | |`);
}
}
-42
View File
@@ -1,42 +0,0 @@
/**
* @file Contains helper functions used in the scripts.
*/
import { getInput } from "@actions/core";
// Script variables.
const OWNER = "anuraghazra";
const REPO = "github-readme-stats";
/**
* Retrieve information about the repository that ran the action.
*
* @param {Object} context Action context.
* @returns {Object} Repository information.
*/
export const getRepoInfo = (ctx) => {
try {
return {
owner: ctx.repo.owner,
repo: ctx.repo.repo,
};
} catch (error) {
return {
owner: OWNER,
repo: REPO,
};
}
};
/**
* Retrieve github token and throw error if it is not found.
*
* @returns {string} Github token.
*/
export const getGithubToken = () => {
const token = getInput("github_token") || process.env.GITHUB_TOKEN;
if (!token) {
throw Error("Could not find github token");
}
return token;
};
+115 -492
View File
@@ -1,81 +1,26 @@
/**
* @file This script is used to preview the theme on theme PRs.
*/
import * as dotenv from "dotenv";
dotenv.config();
const core = require("@actions/core");
const github = require("@actions/github");
const parse = require("parse-diff");
const Hjson = require("hjson");
const snakeCase = require("lodash.snakecase");
const ColorContrastChecker = require("color-contrast-checker");
import { debug, setFailed } from "@actions/core";
import github from "@actions/github";
import ColorContrastChecker from "color-contrast-checker";
import { info } from "console";
import Hjson from "hjson";
import snakeCase from "lodash.snakecase";
import parse from "parse-diff";
import { inspect } from "util";
import { isValidHexColor } from "../src/common/utils.js";
import { themes } from "../themes/index.js";
import { getGithubToken, getRepoInfo } from "./helpers.js";
// Script variables.
const COMMENTER = "github-actions[bot]";
require("dotenv").config();
const OWNER = "anuraghazra";
const REPO = "github-readme-stats";
const COMMENT_TITLE = "Automated Theme Preview";
const THEME_PR_FAIL_TEXT = ":x: Theme PR does not adhere to our guidelines.";
const THEME_PR_SUCCESS_TEXT =
":heavy_check_mark: Theme PR does adhere to our guidelines.";
const FAIL_TEXT = `
\rUnfortunately, your theme PR does not adhere to our [theme guidelines](https://github.com/anuraghazra/github-readme-stats/blob/master/CONTRIBUTING.md#themes-contribution). Please fix the issues below, and we will review your\
\r PR again. This pull request will **automatically close in 15 days** if no changes are made. After this time, you must re-open the PR for it to be reviewed.
`;
const THEME_CONTRIB_GUIDELINESS = `
\rHi, thanks for the theme contribution. Please read our theme [contribution guidelines](https://github.com/anuraghazra/github-readme-stats/blob/master/CONTRIBUTING.md#themes-contribution).
\rWe are currently only accepting color combinations from any VSCode theme or themes with good colour combinations to minimize bloating the themes collection.
\r> Also, note that if this theme is exclusively for your personal use, then instead of adding it to our theme collection, you can use card [customization options](https://github.com/anuraghazra/github-readme-stats#customization).
`;
const COLOR_PROPS = {
title_color: 6,
icon_color: 6,
text_color: 6,
bg_color: 8,
border_color: 6,
};
const ACCEPTED_COLOR_PROPS = Object.keys(COLOR_PROPS);
const REQUIRED_COLOR_PROPS = ACCEPTED_COLOR_PROPS.slice(0, 4);
const INVALID_REVIEW_COMMENT = (commentUrl) =>
`Some themes are invalid. See the [Automated Theme Preview](${commentUrl}) comment above for more information.`;
/**
* Retrieve PR number from the event payload.
*
* @returns {number} PR number.
*/
const getPrNumber = () => {
if (process.env.MOCK_PR_NUMBER) return process.env.MOCK_PR_NUMBER; // For testing purposes.
function getPrNumber() {
const pullRequest = github.context.payload.pull_request;
if (!pullRequest) {
throw Error("Could not get pull request number from context");
return undefined;
}
return pullRequest.number;
};
}
/**
* Retrieve the commenting user.
* @returns {string} Commenting user.
*/
const getCommenter = () => {
return process.env.COMMENTER ? process.env.COMMENTER : COMMENTER;
};
/**
* Returns whether the comment is a preview comment.
*
* @param {Object} inputs Action inputs.
* @param {Object} comment Comment object.
* @returns {boolean} Whether the comment is a preview comment.
*/
const isPreviewComment = (inputs, comment) => {
function findCommentPredicate(inputs, comment) {
return (
(inputs.commentAuthor && comment.user
? comment.user.login === inputs.commentAuthor
@@ -84,482 +29,160 @@ const isPreviewComment = (inputs, comment) => {
? comment.body.includes(inputs.bodyIncludes)
: true)
);
};
}
/**
* Find the preview theme comment.
*
* @param {Object} octokit Octokit instance.
* @param {number} issueNumber Issue number.
* @param {string} repo Repository name.
* @param {string} owner Owner of the repository.
* @returns {Object} The Github comment object.
*/
const findComment = async (octokit, issueNumber, owner, repo, commenter) => {
async function findComment(octokit, issueNumber) {
const parameters = {
owner,
repo,
owner: OWNER,
repo: REPO,
issue_number: issueNumber,
};
const inputs = {
commentAuthor: commenter,
commentAuthor: OWNER,
bodyIncludes: COMMENT_TITLE,
};
// Search each page for the comment
for await (const { data: comments } of octokit.paginate.iterator(
octokit.rest.issues.listComments,
parameters,
)) {
// Search each page for the comment
const comment = comments.find((comment) =>
isPreviewComment(inputs, comment),
findCommentPredicate(inputs, comment),
);
if (comment) {
debug(`Found theme preview comment: ${inspect(comment)}`);
return comment;
} else {
debug(`No theme preview comment found.`);
}
if (comment) return comment;
}
};
}
/**
* Create or update the preview comment.
*
* @param {Object} octokit Octokit instance.
* @param {Object} props Comment properties.
* @return {string} The comment URL.
*/
const upsertComment = async (octokit, props) => {
let resp;
async function upsertComment(octokit, props) {
if (props.comment_id !== undefined) {
resp = await octokit.issues.updateComment(props);
await octokit.issues.updateComment(props);
} else {
resp = await octokit.issues.createComment(props);
await octokit.issues.createComment(props);
}
return resp.data.html_url;
};
}
/**
* Adds a review to the pull request.
*
* @param {Object} octokit Octokit instance.
* @param {number} prNumber Pull request number.
* @param {string} owner Owner of the repository.
* @param {string} repo Repository name.
* @param {string} reviewState The review state. Options are (APPROVE, REQUEST_CHANGES, COMMENT, PENDING).
* @param {string} reason The reason for the review.
*/
const addReview = async (
octokit,
prNumber,
owner,
repo,
reviewState,
reason,
) => {
await octokit.pulls.createReview({
owner,
repo,
pull_number: prNumber,
event: reviewState,
body: reason,
});
};
/**
* Add label to pull request.
*
* @param {Object} octokit Octokit instance.
* @param {number} prNumber Pull request number.
* @param {string} owner Repository owner.
* @param {string} repo Repository name.
* @param {string[]} labels Labels to add.
*/
const addLabel = async (octokit, prNumber, owner, repo, labels) => {
await octokit.issues.addLabels({
owner,
repo,
issue_number: prNumber,
labels,
});
};
/**
* Remove label from the pull request.
*
* @param {Object} octokit Octokit instance.
* @param {number} prNumber Pull request number.
* @param {string} owner Repository owner.
* @param {string} repo Repository name.
* @param {string} label Label to add or remove.
*/
const removeLabel = async (octokit, prNumber, owner, repo, label) => {
await octokit.issues.removeLabel({
owner,
repo,
issue_number: prNumber,
name: label,
});
};
/**
* Adds or removes a label from the pull request.
*
* @param {Object} octokit Octokit instance.
* @param {number} prNumber Pull request number.
* @param {string} owner Repository owner.
* @param {string} repo Repository name.
* @param {string} label Label to add or remove.
* @param {boolean} add Whether to add or remove the label.
*/
const addRemoveLabel = async (octokit, prNumber, owner, repo, label, add) => {
const res = await octokit.pulls.get({
owner,
repo,
pull_number: prNumber,
});
if (add) {
if (!res.data.labels.find((l) => l.name === label)) {
await addLabel(octokit, prNumber, owner, repo, [label]);
}
} else {
if (res.data.labels.find((l) => l.name === label)) {
await removeLabel(octokit, prNumber, owner, repo, label);
}
}
};
/**
* Retrieve webAim contrast color check link.
*
* @param {string} color1 First color.
* @param {string} color2 Second color.
* @returns {string} WebAim contrast color check link.
*/
const getWebAimLink = (color1, color2) => {
function getWebAimLink(color1, color2) {
return `https://webaim.org/resources/contrastchecker/?fcolor=${color1}&bcolor=${color2}`;
};
}
/**
* Retrieves the theme GRS url.
*
* @param {Object} colors The theme colors.
* @returns {string} GRS theme url.
*/
const getGRSLink = (colors) => {
function getGrsLink(colors) {
const url = `https://github-readme-stats.vercel.app/api?username=anuraghazra`;
const colorString = Object.keys(colors)
.map((colorKey) => `${colorKey}=${colors[colorKey]}`)
.join("&");
return `${url}&${colorString}&show_icons=true`;
};
}
/**
* Retrieve javascript object from json string.
*
* @description Wraps the Hjson parse function to fix several known json syntax errors.
*
* @param {string} json The json to parse.
* @returns {Object} Object parsed from the json.
*/
const parseJSON = (json) => {
const themeContribGuidelines = `
\rHi, thanks for the theme contribution, please read our theme [contribution guidelines](https://github.com/anuraghazra/github-readme-stats/blob/master/CONTRIBUTING.md#themes-contribution).
\rWe are currently only accepting color combinations from any VSCode theme or themes which have good color combination to minimize bloating the themes collection.
\r> Also note that if this theme is exclusively for your personal use, then instead of adding it to our theme collection you can use card [customization options](https://github.com/anuraghazra/github-readme-stats#customization)
`;
async function run() {
try {
const parsedJson = Hjson.parse(json);
if (typeof parsedJson === "object") {
return parsedJson;
} else {
throw new Error("PR diff is not a valid theme JSON object.");
}
} catch (error) {
let parsedJson = json
.split(/([\s\r\s]*}[\s\r\s]*,[\s\r\s]*)(?=[\w"-]+:)/)
.filter((x) => typeof x !== "string" || !!x.trim());
if (parsedJson[0].replace(/\s+/g, "") === "},") {
parsedJson[0] = "},";
if (!/\s*}\s*,?\s*$/.test(parsedJson[1])) {
parsedJson.push(parsedJson.shift());
} else {
parsedJson.shift();
}
return Hjson.parse(parsedJson.join(""));
} else {
throw error;
}
}
};
/**
* Check whether the theme name is still available.
* @param {string} name Theme name.
* @returns {boolean} Whether the theme name is available.
*/
const themeNameAlreadyExists = (name) => {
return themes[name] !== undefined;
};
/**
* Main function.
*/
export const run = async (prNumber) => {
try {
const dryRun = process.env.DRY_RUN === "true" || false;
debug("Retrieve action information from context...");
debug(`Context: ${inspect(github.context)}`);
let commentBody = `
\r# ${COMMENT_TITLE}
\r${THEME_CONTRIB_GUIDELINESS}
`;
const ccc = new ColorContrastChecker();
const octokit = github.getOctokit(getGithubToken());
const pullRequestId = prNumber ? prNumber : getPrNumber();
const commenter = getCommenter();
const { owner, repo } = getRepoInfo(github.context);
debug(`Owner: ${owner}`);
debug(`Repo: ${repo}`);
debug(`Commenter: ${commenter}`);
const warnings = [];
const token = core.getInput("token");
const octokit = github.getOctokit(token || process.env.PERSONAL_TOKEN);
const pullRequestId = getPrNumber();
if (!pullRequestId) {
console.log("PR not found");
return;
}
// Retrieve the PR diff and preview-theme comment.
debug("Retrieve PR diff...");
const res = await octokit.pulls.get({
owner,
repo,
owner: OWNER,
repo: REPO,
pull_number: pullRequestId,
mediaType: {
format: "diff",
},
});
debug("Retrieve preview-theme comment...");
const comment = await findComment(
octokit,
pullRequestId,
owner,
repo,
commenter,
);
const comment = await findComment(octokit, pullRequestId);
// Retrieve theme changes from the PR diff.
debug("Retrieve themes...");
const diff = parse(res.data);
const content = diff
.find((file) => file.to === "themes/index.js")
.chunks[0].changes.filter((c) => c.type === "add")
.map((c) => c.content.replace("+", ""))
.join("");
const themeObject = parseJSON(content);
if (
Object.keys(themeObject).every(
(key) => typeof themeObject[key] !== "object",
)
) {
throw new Error("PR diff is not a valid theme JSON object.");
const themeObject = Hjson.parse(content);
const themeName = Object.keys(themeObject)[0];
const colors = themeObject[themeName];
if (themeName !== snakeCase(themeName)) {
warnings.push("Theme name isn't in snake_case");
}
// Loop through themes and create theme preview body.
debug("Create theme preview body...");
const themeValid = Object.fromEntries(
Object.keys(themeObject).map((name) => [name, true]),
);
let previewBody = "";
for (const theme in themeObject) {
debug(`Create theme preview for ${theme}...`);
const themeName = theme;
const colors = themeObject[theme];
const warnings = [];
const errors = [];
// Check if the theme name is valid.
debug("Theme preview body: Check if the theme name is valid...");
if (themeNameAlreadyExists(themeName)) {
warnings.push("Theme name already taken");
themeValid[theme] = false;
}
if (themeName !== snakeCase(themeName)) {
warnings.push("Theme name isn't in snake_case");
themeValid[theme] = false;
}
// Check if the theme colors are valid.
debug("Theme preview body: Check if the theme colors are valid...");
let invalidColors = false;
if (!colors) {
warning.push("Theme colors are missing");
invalidColors = true;
} else {
const missingKeys = REQUIRED_COLOR_PROPS.filter(
(x) => !Object.keys(colors).includes(x),
);
const extraKeys = Object.keys(colors).filter(
(x) => !ACCEPTED_COLOR_PROPS.includes(x),
);
if (missingKeys.length > 0 || extraKeys.length > 0) {
for (const missingKey of missingKeys) {
errors.push(`Theme color properties \`${missingKey}\` are missing`);
}
for (const extraKey of extraKeys) {
warnings.push(
`Theme color properties \`${extraKey}\` is not supported`,
);
}
invalidColors = true;
} else {
for (const [colorKey, colorValue] of Object.entries(colors)) {
if (colorValue[0] === "#") {
errors.push(
`Theme color property \`${colorKey}\` should not start with '#'`,
);
invalidColors = true;
} else if (colorValue.length > COLOR_PROPS[colorKey]) {
errors.push(
`Theme color property \`${colorKey}\` can not be longer than \`${COLOR_PROPS[colorKey]}\` characters`,
);
invalidColors = true;
} else if (!isValidHexColor(colorValue)) {
errors.push(
`Theme color property \`${colorKey}\` is not a valid hex color: <code>#${colorValue}</code>`,
);
invalidColors = true;
}
}
}
}
if (invalidColors) {
themeValid[theme] = false;
previewBody += `
\r### ${
themeName.charAt(0).toUpperCase() + themeName.slice(1)
} theme preview
\r${warnings.map((warning) => `- :warning: ${warning}.\n`).join("")}
\r${errors.map((error) => `- :x: ${error}.\n`).join("")}
\r>:x: Cannot create theme preview.
`;
continue;
}
// Check color contrast.
debug("Theme preview body: Check color contrast...");
const titleColor = colors.title_color;
const iconColor = colors.icon_color;
const textColor = colors.text_color;
const bgColor = colors.bg_color;
const borderColor = colors.border_color;
const url = getGRSLink(colors);
const colorPairs = {
title_color: [titleColor, bgColor],
icon_color: [iconColor, bgColor],
text_color: [textColor, bgColor],
};
Object.keys(colorPairs).forEach((item) => {
let color1 = colorPairs[item][0];
let color2 = colorPairs[item][1];
color1 = color1.length === 4 ? color1.slice(0, 3) : color1.slice(0, 6);
color2 = color2.length === 4 ? color2.slice(0, 3) : color2.slice(0, 6);
if (!ccc.isLevelAA(`#${color1}`, `#${color2}`)) {
const permalink = getWebAimLink(color1, color2);
warnings.push(
`\`${item}\` does not pass [AA contrast ratio](${permalink})`,
);
themeValid[theme] = false;
}
});
// Create theme preview body.
debug("Theme preview body: Create theme preview body...");
previewBody += `
\r### ${
themeName.charAt(0).toUpperCase() + themeName.slice(1)
} theme preview
\r${warnings.map((warning) => `- :warning: ${warning}.\n`).join("")}
\ntitle_color: <code>#${titleColor}</code> | icon_color: <code>#${iconColor}</code> | text_color: <code>#${textColor}</code> | bg_color: <code>#${bgColor}</code>${
borderColor ? ` | border_color: <code>#${borderColor}</code>` : ""
}
\r[Preview Link](${url})
\r[![](${url})](${url})
`;
}
// Create comment body.
debug("Create comment body...");
commentBody += `
\r${
Object.values(themeValid).every((value) => value)
? THEME_PR_SUCCESS_TEXT
: THEME_PR_FAIL_TEXT
}
\r## Test results
\r${Object.entries(themeValid)
.map(
([key, value]) => `- ${value ? ":heavy_check_mark:" : ":x:"} ${key}`,
)
.join("\r")}
\r${
Object.values(themeValid).every((value) => value)
? "**Result:** :heavy_check_mark: All themes are valid."
: "**Result:** :x: Some themes are invalid.\n\n" + FAIL_TEXT
}
\r## Details
\r${previewBody}
`;
// Create or update theme-preview comment.
debug("Create or update theme-preview comment...");
let comment_url;
if (!dryRun) {
comment_url = await upsertComment(octokit, {
if (!colors) {
await upsertComment({
comment_id: comment?.id,
owner: OWNER,
repo: REPO,
issue_number: pullRequestId,
owner,
repo,
body: commentBody,
body: `
\r**${COMMENT_TITLE}**
\rCannot create theme preview
${themeContribGuidelines}
`,
});
} else {
info(`DRY_RUN: Comment body: ${commentBody}`);
comment_url = "";
return;
}
// Change review state and add/remove `invalid` label based on theme PR validity.
debug(
"Change review state and add/remove `invalid` label based on whether all themes passed...",
);
const themesValid = Object.values(themeValid).every((value) => value);
const reviewState = themesValid ? "APPROVE" : "REQUEST_CHANGES";
const reviewReason = themesValid
? undefined
: INVALID_REVIEW_COMMENT(comment_url);
if (!dryRun) {
await addReview(
octokit,
pullRequestId,
owner,
repo,
reviewState,
reviewReason,
);
await addRemoveLabel(
octokit,
pullRequestId,
owner,
repo,
"invalid",
!themesValid,
);
} else {
info(`DRY_RUN: Review state: ${reviewState}`);
info(`DRY_RUN: Review reason: ${reviewReason}`);
}
const titleColor = colors.title_color;
const iconColor = colors.icon_color;
const textColor = colors.text_color;
const bgColor = colors.bg_color;
const url = getGrsLink(colors);
const colorPairs = {
title_color: [titleColor, bgColor],
icon_color: [iconColor, bgColor],
text_color: [textColor, bgColor],
};
// check color contrast
Object.keys(colorPairs).forEach((key) => {
const color1 = colorPairs[key][0];
const color2 = colorPairs[key][1];
if (!ccc.isLevelAA(`#${color1}`, `#${color2}`)) {
const permalink = getWebAimLink(color1, color2);
warnings.push(
`\`${key}\` does not pass [AA contrast ratio](${permalink})`,
);
}
});
await upsertComment(octokit, {
comment_id: comment?.id,
issue_number: pullRequestId,
owner: OWNER,
repo: REPO,
body: `
\r**${COMMENT_TITLE}**
\r${warnings.map((warning) => `- :warning: ${warning}\n`).join("")}
\ntitle_color: <code>#${titleColor}</code> | icon_color: <code>#${iconColor}</code> | text_color: <code>#${textColor}</code> | bg_color: <code>#${bgColor}</code>
\r[Preview Link](${url})
\r[![](${url})](${url})
${themeContribGuidelines}
`,
});
} catch (error) {
setFailed(error.message);
console.log(error);
}
};
}
run();
+1 -1
View File
@@ -11,4 +11,4 @@ git checkout -b $BRANCH_NAME
git add --all
git commit --message "docs(theme): Auto update theme readme" || exit 0
git remote add origin-$BRANCH_NAME https://${PERSONAL_TOKEN}@github.com/${GH_REPO}.git
git push --force --quiet --set-upstream origin-$BRANCH_NAME $BRANCH_NAME
git push --force --quiet --set-upstream origin-$BRANCH_NAME $BRANCH_NAME
+8 -9
View File
@@ -57,22 +57,21 @@ function calculateRank({
issues * ISSUES_OFFSET +
stargazers * STARS_OFFSET +
prs * PRS_OFFSET +
followers * FOLLOWERS_OFFSET +
totalRepos * REPO_OFFSET
followers * FOLLOWERS_OFFSET +
totalRepos * REPO_OFFSET
) / 100;
const normalizedScore = normalcdf(score, TOTAL_VALUES, ALL_OFFSETS) * 100;
const level = (() => {
if (normalizedScore < RANK_S_VALUE) return "S+";
if (normalizedScore < RANK_DOUBLE_A_VALUE) return "S";
if (normalizedScore < RANK_A2_VALUE) return "A++";
if (normalizedScore < RANK_A3_VALUE) return "A+";
return "B+";
})();
if (normalizedScore >= RANK_S_VALUE && normalizedScore < RANK_DOUBLE_A_VALUE) return "S";
if (normalizedScore >= RANK_DOUBLE_A_VALUE && normalizedScore < RANK_A2_VALUE) return "A++";
if (normalizedScore >= RANK_A2_VALUE && normalizedScore < RANK_A3_VALUE) return "A+"
if (normalizedScore >= RANK_A3_VALUE && normalizedScore < RANK_B_VALUE) return "B+"
})()
return { level, score: normalizedScore };
}
export { calculateRank };
export default calculateRank;
module.exports = calculateRank;
+18 -19
View File
@@ -1,17 +1,17 @@
// @ts-check
import { Card } from "../common/Card.js";
import { I18n } from "../common/I18n.js";
import { icons } from "../common/icons.js";
import {
encodeHTML,
flexLayout,
getCardColors,
const {
kFormatter,
encodeHTML,
getCardColors,
flexLayout,
wrapTextMultiline,
measureText,
parseEmojis,
wrapTextMultiline,
} from "../common/utils.js";
import { repoCardLocales } from "../translations.js";
} = require("../common/utils");
const I18n = require("../common/I18n");
const Card = require("../common/Card");
const icons = require("../common/icons");
const { repoCardLocales } = require("../translations");
/**
* @param {string} label
@@ -67,8 +67,8 @@ const iconWithLabel = (icon, label, testid) => {
};
/**
* @param {import('../fetchers/types').RepositoryData} repo
* @param {Partial<import("./types").RepoCardOptions>} options
* @param {import('../fetchers/types').RepositoryData} repo
* @param {Partial<import("./types").RepoCardOptions>} options
* @returns {string}
*/
const renderRepoCard = (repo, options = {}) => {
@@ -88,7 +88,7 @@ const renderRepoCard = (repo, options = {}) => {
icon_color,
text_color,
bg_color,
show_owner = false,
show_owner,
theme = "default_repocard",
border_radius,
border_color,
@@ -167,11 +167,11 @@ const renderRepoCard = (repo, options = {}) => {
return card.render(`
${
isTemplate
? // @ts-ignore
getBadgeSVG(i18n.t("repocard.template"), colors.textColor)
// @ts-ignore
? getBadgeSVG(i18n.t("repocard.template"), colors.textColor)
: isArchived
? // @ts-ignore
getBadgeSVG(i18n.t("repocard.archived"), colors.textColor)
// @ts-ignore
? getBadgeSVG(i18n.t("repocard.archived"), colors.textColor)
: ""
}
@@ -185,5 +185,4 @@ const renderRepoCard = (repo, options = {}) => {
`);
};
export { renderRepoCard };
export default renderRepoCard;
module.exports = renderRepoCard;
+44 -77
View File
@@ -1,16 +1,16 @@
// @ts-check
import { Card } from "../common/Card.js";
import { I18n } from "../common/I18n.js";
import { icons } from "../common/icons.js";
import {
clampValue,
flexLayout,
getCardColors,
const I18n = require("../common/I18n");
const Card = require("../common/Card");
const icons = require("../common/icons");
const { getStyles } = require("../getStyles");
const { statCardLocales } = require("../translations");
const {
kFormatter,
flexLayout,
clampValue,
measureText,
} from "../common/utils.js";
import { getStyles } from "../getStyles.js";
import { statCardLocales } from "../translations.js";
getCardColors,
} = require("../common/utils");
const createTextNode = ({
icon,
@@ -20,7 +20,6 @@ const createTextNode = ({
index,
showIcons,
shiftValuePos,
bold,
}) => {
const kValue = kFormatter(value);
const staggerDelay = (index + 3) * 150;
@@ -36,13 +35,11 @@ const createTextNode = ({
return `
<g class="stagger" style="animation-delay: ${staggerDelay}ms" transform="translate(25, 0)">
${iconSvg}
<text class="stat ${
bold ? " bold" : "not_bold"
}" ${labelOffset} y="12.5">${label}:</text>
<text
class="stat ${bold ? " bold" : "not_bold"}"
x="${(showIcons ? 140 : 120) + shiftValuePos}"
y="12.5"
<text class="stat bold" ${labelOffset} y="12.5">${label}:</text>
<text
class="stat"
x="${(showIcons ? 140 : 120) + shiftValuePos}"
y="12.5"
data-testid="${id}"
>${kValue}</text>
</g>
@@ -69,14 +66,12 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
show_icons = false,
hide_title = false,
hide_border = false,
card_width,
hide_rank = false,
include_all_commits = false,
line_height = 25,
title_color,
icon_color,
text_color,
text_bold = true,
bg_color,
theme = "default",
custom_title,
@@ -169,7 +164,6 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
showIcons: show_icons,
shiftValuePos:
(!include_all_commits ? 50 : 35) + (isLongLocale ? 50 : 0),
bold: text_bold,
}),
);
@@ -180,6 +174,26 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
hide_rank ? 0 : 150,
);
// Conditionally rendered elements
const rankCircle = hide_rank
? ""
: `<g data-testid="rank-circle"
transform="translate(400, ${height / 2 - 50})">
<circle class="rank-circle-rim" cx="-10" cy="8" r="40" />
<circle class="rank-circle" cx="-10" cy="8" r="40" />
<g class="rank-text">
<text
x="-5"
y="3"
alignment-baseline="central"
dominant-baseline="central"
text-anchor="middle"
>
${rank.level}
</text>
</g>
</g>`;
// the better user's score the the rank will be closer to zero so
// subtracting 100 to get the progress in 100%
const progress = 100 - rank.score;
@@ -195,20 +209,13 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
return measureText(custom_title ? custom_title : i18n.t("statcard.title"));
};
/*
When hide_rank=true, the minimum card width is 270 px + the title length and padding.
When hide_rank=false, the minimum card_width is 340 px + the icon width (if show_icons=true).
Numbers are picked by looking at existing dimensions on production.
*/
const iconWidth = show_icons ? 16 : 0;
const minCardWidth = hide_rank
? clampValue(50 /* padding */ + calculateTextWidth() * 2, 270, Infinity)
: 340 + iconWidth;
const defaultCardWidth = hide_rank ? 270 : 495;
let width = isNaN(card_width) ? defaultCardWidth : card_width;
if (width < minCardWidth) {
width = minCardWidth;
}
const width = hide_rank
? clampValue(
50 /* padding */ + calculateTextWidth() * 2,
270 /* min */,
Infinity,
)
: 495;
const card = new Card({
customTitle: custom_title,
@@ -231,45 +238,6 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
if (disable_animations) card.disableAnimations();
/**
* Calculates the right rank circle translation values such that the rank circle
* keeps respecting the padding.
*
* width > 450: The default left padding of 50 px will be used.
* width < 450: The left and right padding will shrink equally.
*
* @returns {number} - Rank circle translation value.
*/
const calculateRankXTranslation = () => {
if (width < 450) {
return width - 95 + (45 * (450 - 340)) / 110;
} else {
return width - 95;
}
};
// Conditionally rendered elements
const rankCircle = hide_rank
? ""
: `<g data-testid="rank-circle"
transform="translate(${calculateRankXTranslation()}, ${
height / 2 - 50
})">
<circle class="rank-circle-rim" cx="-10" cy="8" r="40" />
<circle class="rank-circle" cx="-10" cy="8" r="40" />
<g class="rank-text">
<text
x="-5"
y="3"
alignment-baseline="central"
dominant-baseline="central"
text-anchor="middle"
>
${rank.level}
</text>
</g>
</g>`;
// Accessibility Labels
const labels = Object.keys(STATS)
.filter((key) => !hide.includes(key))
@@ -296,9 +264,8 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
gap: lheight,
direction: "column",
}).join("")}
</svg>
</svg>
`);
};
export { renderStatsCard };
export default renderStatsCard;
module.exports = renderStatsCard;
+12 -11
View File
@@ -1,16 +1,16 @@
// @ts-check
import { Card } from "../common/Card.js";
import { createProgressNode } from "../common/createProgressNode.js";
import { I18n } from "../common/I18n.js";
import {
chunkArray,
const Card = require("../common/Card");
const I18n = require("../common/I18n");
const { langCardLocales } = require("../translations");
const { createProgressNode } = require("../common/createProgressNode");
const {
clampValue,
flexLayout,
getCardColors,
flexLayout,
lowercaseTrim,
measureText,
} from "../common/utils.js";
import { langCardLocales } from "../translations.js";
chunkArray,
} = require("../common/utils");
const DEFAULT_CARD_WIDTH = 300;
const MIN_CARD_WIDTH = 230;
@@ -205,7 +205,7 @@ const calculateNormalLayoutHeight = (totalLangs) => {
const useLanguages = (topLangs, hide, langs_count) => {
let langs = Object.values(topLangs);
let langsToHide = {};
let langsCount = clampValue(parseInt(langs_count), 1, 100);
let langsCount = clampValue(parseInt(langs_count), 1, 10);
// populate langsToHide map for quick lookup
// while filtering out
@@ -235,7 +235,7 @@ const useLanguages = (topLangs, hide, langs_count) => {
*/
const renderTopLanguages = (topLangs, options = {}) => {
const {
hide_title = false,
hide_title,
hide_border,
card_width,
title_color,
@@ -311,4 +311,5 @@ const renderTopLanguages = (topLangs, options = {}) => {
`);
};
export { renderTopLanguages, MIN_CARD_WIDTH };
module.exports = renderTopLanguages;
module.exports.MIN_CARD_WIDTH = MIN_CARD_WIDTH;
+1 -2
View File
@@ -1,4 +1,4 @@
type ThemeNames = keyof typeof import("../../themes/index.js");
type ThemeNames = keyof typeof import("../../themes");
export type CommonOptions = {
title_color: string;
@@ -16,7 +16,6 @@ export type StatCardOptions = CommonOptions & {
show_icons: boolean;
hide_title: boolean;
hide_border: boolean;
card_width: number;
hide_rank: boolean;
include_all_commits: boolean;
line_height: number | string;
+11 -21
View File
@@ -1,26 +1,16 @@
// @ts-check
import { Card } from "../common/Card.js";
import { createProgressNode } from "../common/createProgressNode.js";
import { I18n } from "../common/I18n.js";
import {
const Card = require("../common/Card");
const I18n = require("../common/I18n");
const { getStyles } = require("../getStyles");
const { wakatimeCardLocales } = require("../translations");
const languageColors = require("../common/languageColors.json");
const { createProgressNode } = require("../common/createProgressNode");
const {
clampValue,
flexLayout,
getCardColors,
flexLayout,
lowercaseTrim,
} from "../common/utils.js";
import { getStyles } from "../getStyles.js";
import { wakatimeCardLocales } from "../translations.js";
/** Import language colors.
*
* @description Here we use the workaround found in
* https://stackoverflow.com/questions/66726365/how-should-i-import-json-in-node
* since vercel is using v16.14.0 which does not yet support json imports without the
* --experimental-json-modules flag.
*/
import { createRequire } from "module";
const require = createRequire(import.meta.url);
const languageColors = require("../common/languageColors.json"); // now works
} = require("../common/utils");
/**
* @param {{color: string, text: string}} param0
@@ -324,5 +314,5 @@ const renderWakatimeCard = (stats = {}, options = { hide: [] }) => {
`);
};
export { renderWakatimeCard };
export default renderWakatimeCard;
module.exports = renderWakatimeCard;
exports.createProgressNode = createProgressNode;
+4 -5
View File
@@ -1,5 +1,5 @@
import { getAnimations } from "../getStyles.js";
import { encodeHTML, flexLayout } from "./utils.js";
const { getAnimations } = require("../getStyles");
const { flexLayout, encodeHTML } = require("../common/utils");
class Card {
/**
@@ -10,7 +10,7 @@ class Card {
* @param {string?=} args.customTitle
* @param {string?=} args.defaultTitle
* @param {string?=} args.titlePrefixIcon
* @param {ReturnType<import('../common/utils.js').getCardColors>?=} args.colors
* @param {ReturnType<import('../common/utils').getCardColors>?=} args.colors
*/
constructor({
width = 100,
@@ -216,5 +216,4 @@ class Card {
}
}
export { Card };
export default Card;
module.exports = Card;
+1 -2
View File
@@ -18,5 +18,4 @@ class I18n {
}
}
export { I18n };
export default I18n;
module.exports = I18n;
+1 -2
View File
@@ -1,4 +1,3 @@
const blacklist = ["renovate-bot", "technote-space", "sw-yx"];
export { blacklist };
export default blacklist;
module.exports = blacklist;
+3 -4
View File
@@ -1,4 +1,4 @@
import { clampValue } from "./utils.js";
const { clampValue } = require("../common/utils");
const createProgressNode = ({
x,
@@ -16,7 +16,7 @@ const createProgressNode = ({
<rect
height="8"
fill="${color}"
rx="5" ry="5" x="0" y="0"
rx="5" ry="5" x="0" y="0"
data-testid="lang-progress"
width="${progressPercentage}%"
>
@@ -25,5 +25,4 @@ const createProgressNode = ({
`;
};
export { createProgressNode };
export default createProgressNode;
exports.createProgressNode = createProgressNode;
+1 -2
View File
@@ -8,5 +8,4 @@ const icons = {
fork: `<path fill-rule="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"></path>`,
};
export { icons };
export default icons;
module.exports = icons;
+3 -31
View File
@@ -15,7 +15,6 @@
"ATS": "#1ac620",
"ActionScript": "#882B0F",
"Ada": "#02f88c",
"Adblock Filter List": "#800000",
"Adobe Font Metrics": "#fa0f00",
"Agda": "#315665",
"Alloy": "#64C800",
@@ -23,7 +22,6 @@
"Altium Designer": "#A89663",
"AngelScript": "#C7D7DC",
"Ant Build System": "#A9157E",
"Antlers": "#ff269e",
"ApacheConf": "#d12127",
"Apex": "#1797c0",
"Apollo Guidance Computer": "#0B3D91",
@@ -43,10 +41,8 @@
"Ballerina": "#FF5000",
"Batchfile": "#C1F12E",
"Beef": "#a52f4e",
"Berry": "#15A13C",
"BibTeX": "#778899",
"Bicep": "#519aba",
"Bikeshed": "#5562ac",
"Bison": "#6A463F",
"BitBake": "#00bce4",
"Blade": "#f7523f",
@@ -56,13 +52,11 @@
"Boo": "#d4bec1",
"Boogie": "#c80fa0",
"Brainfuck": "#2F2530",
"BrighterScript": "#66AABB",
"Brightscript": "#662D91",
"Browserslist": "#ffd539",
"C": "#555555",
"C#": "#178600",
"C++": "#f34b7d",
"CAP CDS": "#0092d1",
"CLIPS": "#00A300",
"CMake": "#DA3434",
"COLLADA": "#F1A42B",
@@ -72,9 +66,7 @@
"CUE": "#5886E1",
"CWeb": "#00007a",
"Cabal Config": "#483465",
"Cadence": "#00ef8b",
"Cairo": "#ff4a48",
"CameLIGO": "#3be133",
"Cap'n Proto": "#c42727",
"Ceylon": "#dfa535",
"Chapel": "#8dc63f",
@@ -128,7 +120,6 @@
"Eiffel": "#4d6977",
"Elixir": "#6e4a7e",
"Elm": "#60B5CC",
"Elvish": "#55BB55",
"Emacs Lisp": "#c065db",
"EmberScript": "#FFF4F3",
"Erlang": "#B83998",
@@ -162,9 +153,6 @@
"GSC": "#FF6800",
"Game Maker Language": "#71b417",
"Gemfile.lock": "#701516",
"Gemini": "#ff6900",
"Genero": "#63408e",
"Genero Forms": "#d8df39",
"Genie": "#fb855d",
"Genshi": "#951531",
"Gentoo Ebuild": "#9400ff",
@@ -173,7 +161,6 @@
"Gherkin": "#5B2063",
"Git Attributes": "#F44D27",
"Git Config": "#F44D27",
"Git Revision List": "#F44D27",
"Gleam": "#ffaff3",
"Glyph": "#c1ac7f",
"Gnuplot": "#f0a9f0",
@@ -191,7 +178,6 @@
"Groovy Server Pages": "#4298b8",
"HAProxy": "#106da9",
"HLSL": "#aace60",
"HOCON": "#9ff8ee",
"HTML": "#e34c26",
"HTML+ECR": "#2e1052",
"HTML+EEX": "#6e4a7e",
@@ -236,7 +222,6 @@
"JavaScript": "#f1e05a",
"JavaScript+ERB": "#f1e05a",
"Jest Snapshot": "#15c213",
"JetBrains MPS": "#21D789",
"Jinja": "#a52a22",
"Jison": "#56b3cb",
"Jison Lex": "#56b3cb",
@@ -261,7 +246,6 @@
"Latte": "#f2a542",
"Less": "#1d365d",
"Lex": "#DBCA00",
"LigoLANG": "#0e74ff",
"LilyPond": "#9ccc7c",
"Liquid": "#67b8de",
"Literate Agda": "#315665",
@@ -294,16 +278,13 @@
"Modelica": "#de1d31",
"Modula-2": "#10253f",
"Modula-3": "#223388",
"Monkey C": "#8D6747",
"MoonScript": "#ff4585",
"Motoko": "#fbb03b",
"Motorola 68K Assembly": "#005daa",
"Move": "#4a137a",
"Mustache": "#724b3b",
"NCL": "#28431f",
"NPM Config": "#cb3837",
"NWScript": "#111522",
"Nasal": "#1d2c4e",
"Nearley": "#990000",
"Nemerle": "#3d3c6e",
"NetLinx": "#0aa0ff",
@@ -351,7 +332,6 @@
"PigLatin": "#fcd7de",
"Pike": "#005390",
"PogoScript": "#d80074",
"Portugol": "#f8bd00",
"PostCSS": "#dc3a0c",
"PostScript": "#da291c",
"PowerBuilder": "#8f0f8d",
@@ -386,7 +366,6 @@
"Rascal": "#fffaa0",
"ReScript": "#ed5051",
"Reason": "#ff5847",
"ReasonLIGO": "#ff5847",
"Rebol": "#358a5b",
"Record Jar": "#0673ba",
"Red": "#f50000",
@@ -398,7 +377,6 @@
"Roff": "#ecdebe",
"Roff Manpage": "#ecdebe",
"Rouge": "#cc0088",
"RouterOS Script": "#DE3941",
"Ruby": "#701516",
"Rust": "#dea584",
"SAS": "#B34936",
@@ -408,7 +386,6 @@
"SQL": "#e38c00",
"SQLPL": "#e38c00",
"SRecode Template": "#348a34",
"STL": "#373b5e",
"SVG": "#ff9900",
"SaltStack": "#646464",
"Sass": "#a53b70",
@@ -448,9 +425,8 @@
"TOML": "#9c4221",
"TSQL": "#e38c00",
"TSV": "#237346",
"TSX": "#3178c6",
"TSX": "#2b7489",
"TXL": "#0178b8",
"Talon": "#333333",
"Tcl": "#e4cc98",
"TeX": "#3D6117",
"Terra": "#00004c",
@@ -459,7 +435,7 @@
"Thrift": "#D12127",
"Turing": "#cf142b",
"Twig": "#c1d026",
"TypeScript": "#3178c6",
"TypeScript": "#2b7489",
"Unified Parallel C": "#4e3617",
"Unity3D Asset": "#222c37",
"Uno": "#9933cc",
@@ -470,9 +446,8 @@
"VBScript": "#15dcdc",
"VCL": "#148AA8",
"VHDL": "#adb2cb",
"Vala": "#a56de2",
"Vala": "#fbe5cd",
"Valve Data Format": "#f26025",
"Velocity Template Language": "#507cff",
"Verilog": "#b2b7f8",
"Vim Help File": "#199f4b",
"Vim Script": "#199f4b",
@@ -483,13 +458,11 @@
"Vyper": "#2980b9",
"Web Ontology Language": "#5b70bd",
"WebAssembly": "#04133b",
"Whiley": "#d5c397",
"Wikitext": "#fc5757",
"Windows Registry Entries": "#52d5ff",
"Witcher Script": "#ff0000",
"Wollok": "#a23738",
"World of Warcraft Addon Data": "#f7e43f",
"Wren": "#383838",
"X10": "#4B6BEF",
"XC": "#99DA07",
"XML": "#0060ac",
@@ -503,7 +476,6 @@
"YARA": "#220000",
"YASnippet": "#32AB90",
"Yacc": "#4B6C4B",
"Yul": "#794932",
"ZAP": "#0d665e",
"ZIL": "#dc75e5",
"ZenScript": "#00BCD1",
+2 -3
View File
@@ -1,4 +1,4 @@
import { CustomError, logger } from "./utils.js";
const { logger, CustomError } = require("../common/utils");
const retryer = async (fetcher, variables, retries = 0) => {
if (retries > 7) {
@@ -40,5 +40,4 @@ const retryer = async (fetcher, variables, retries = 0) => {
}
};
export { retryer };
export default retryer;
module.exports = retryer;
+5 -5
View File
@@ -1,8 +1,8 @@
// @ts-check
import axios from "axios";
import toEmoji from "emoji-name-map";
import wrap from "word-wrap";
import { themes } from "../../themes/index.js";
const axios = require("axios");
const wrap = require("word-wrap");
const themes = require("../../themes");
const toEmoji = require("emoji-name-map");
/**
* @param {string} message
@@ -370,7 +370,7 @@ function parseEmojis(str) {
});
}
export {
module.exports = {
renderError,
kFormatter,
encodeHTML,
+3 -4
View File
@@ -1,6 +1,6 @@
// @ts-check
import { retryer } from "../common/retryer.js";
import { MissingParamError, request } from "../common/utils.js";
const retryer = require("../common/retryer");
const { request, MissingParamError } = require("../common/utils");
/**
* @param {import('Axios').AxiosRequestHeaders} variables
@@ -97,5 +97,4 @@ async function fetchRepo(username, reponame) {
}
}
export { fetchRepo };
export default fetchRepo;
module.exports = fetchRepo;
+20 -38
View File
@@ -1,17 +1,17 @@
// @ts-check
import axios from "axios";
import * as dotenv from "dotenv";
import githubUsernameRegex from "github-username-regex";
import { calculateRank } from "../calculateRank.js";
import { retryer } from "../common/retryer.js";
import {
CustomError,
logger,
MissingParamError,
request,
} from "../common/utils.js";
const axios = require("axios").default;
const githubUsernameRegex = require("github-username-regex");
dotenv.config();
const retryer = require("../common/retryer");
const calculateRank = require("../calculateRank");
const {
request,
logger,
CustomError,
MissingParamError,
} = require("../common/utils");
require("dotenv").config();
/**
* @param {import('axios').AxiosRequestHeaders} variables
@@ -47,7 +47,6 @@ const fetcher = (variables, token) => {
repositories(first: 100, ownerAffiliations: OWNER, orderBy: {direction: DESC, field: STARGAZERS}) {
totalCount
nodes {
name
stargazers {
totalCount
}
@@ -87,16 +86,15 @@ const totalCommitsFetcher = async (username) => {
try {
let res = await retryer(fetchTotalCommits, { login: username });
let total_count = res.data.total_count;
if (!!total_count && !isNaN(total_count)) {
if (res.data.total_count) {
return res.data.total_count;
}
} catch (err) {
logger.log(err);
// just return 0 if there is something wrong so that
// we don't break the whole app
return 0;
}
// just return 0 if there is something wrong so that
// we don't break the whole app
return 0;
};
/**
@@ -109,7 +107,6 @@ async function fetchStats(
username,
count_private = false,
include_all_commits = false,
exclude_repo = [],
) {
if (!username) throw new MissingParamError(["username"]);
@@ -135,15 +132,6 @@ async function fetchStats(
const user = res.data.data.user;
// populate repoToHide map for quick lookup
// while filtering out
let repoToHide = {};
if (exclude_repo) {
exclude_repo.forEach((repoName) => {
repoToHide[repoName] = true;
});
}
stats.name = user.name || user.login;
stats.totalIssues = user.openIssues.totalCount + user.closedIssues.totalCount;
@@ -165,14 +153,9 @@ async function fetchStats(
stats.totalPRs = user.pullRequests.totalCount;
stats.contributedTo = user.repositoriesContributedTo.totalCount;
// Retrieve stars while filtering out repositories to be hidden
stats.totalStars = user.repositories.nodes
.filter((data) => {
return !repoToHide[data.name];
})
.reduce((prev, curr) => {
return prev + curr.stargazers.totalCount;
}, 0);
stats.totalStars = user.repositories.nodes.reduce((prev, curr) => {
return prev + curr.stargazers.totalCount;
}, 0);
stats.rank = calculateRank({
totalCommits: stats.totalCommits,
@@ -187,5 +170,4 @@ async function fetchStats(
return stats;
}
export { fetchStats };
export default fetchStats;
module.exports = fetchStats;
+4 -7
View File
@@ -1,9 +1,7 @@
// @ts-check
import * as dotenv from "dotenv";
import { retryer } from "../common/retryer.js";
import { logger, MissingParamError, request } from "../common/utils.js";
dotenv.config();
const { request, logger, MissingParamError } = require("../common/utils");
const retryer = require("../common/retryer");
require("dotenv").config();
/**
* @param {import('Axios').AxiosRequestHeaders} variables
@@ -106,5 +104,4 @@ async function fetchTopLanguages(username, exclude_repo = []) {
return topLangs;
}
export { fetchTopLanguages };
export default fetchTopLanguages;
module.exports = fetchTopLanguages;
+6 -5
View File
@@ -1,5 +1,5 @@
import axios from "axios";
import { MissingParamError } from "../common/utils.js";
const axios = require("axios");
const { MissingParamError } = require("../common/utils");
/**
* @param {{username: string, api_domain: string, range: string}} props
@@ -7,7 +7,7 @@ import { MissingParamError } from "../common/utils.js";
*/
const fetchWakatimeStats = async ({ username, api_domain, range }) => {
if (!username) throw new MissingParamError(["username"]);
try {
const { data } = await axios.get(
`https://${
@@ -26,5 +26,6 @@ const fetchWakatimeStats = async ({ username, api_domain, range }) => {
}
};
export { fetchWakatimeStats };
export default fetchWakatimeStats;
module.exports = {
fetchWakatimeStats,
};
+3 -4
View File
@@ -81,17 +81,16 @@ const getStyles = ({
animation: fadeInAnimation 0.3s ease-in-out forwards;
}
.rank-text {
font: 800 24px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor};
font: 800 24px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor};
animation: scaleInAnimation 0.3s ease-in-out forwards;
}
.not_bold { font-weight: 400 }
.bold { font-weight: 700 }
.icon {
fill: ${iconColor};
display: ${!!show_icons ? "block" : "none"};
}
.rank-circle-rim {
stroke: ${titleColor};
fill: none;
@@ -113,4 +112,4 @@ const getStyles = ({
`;
};
export { getStyles, getAnimations };
module.exports = { getStyles, getAnimations };
+2 -2
View File
@@ -1,4 +1,4 @@
import { encodeHTML } from "./common/utils.js";
const { encodeHTML } = require("./common/utils");
const statCardLocales = ({ name, apostrophe }) => {
const encodedName = encodeHTML(name);
@@ -358,7 +358,7 @@ function isLocaleAvailable(locale) {
return availableLocales.includes(locale.toLowerCase());
}
export {
module.exports = {
isLocaleAvailable,
availableLocales,
statCardLocales,
@@ -1,20 +1,18 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Test Render Wakatime Card should render correctly 1`] = `[Function]`;
exports[`Test Render Wakatime Card should render correctly with compact layout 1`] = `
exports[`Test Render Wakatime Card should render correctly 1`] = `
"
<svg
width="495"
height="115"
viewBox="0 0 495 115"
fill="none"
xmlns="http://www.w3.org/2000/svg"
role="img"
aria-labelledby="descId"
width=\\"495\\"
height=\\"150\\"
viewBox=\\"0 0 495 150\\"
fill=\\"none\\"
xmlns=\\"http://www.w3.org/2000/svg\\"
role=\\"img\\"
aria-labelledby=\\"descId\\"
>
<title id="titleId"></title>
<desc id="descId"></desc>
<title id=\\"titleId\\"></title>
<desc id=\\"descId\\"></desc>
<style>
.header {
font: 600 18px 'Segoe UI', Ubuntu, Sans-Serif;
@@ -28,7 +26,7 @@ exports[`Test Render Wakatime Card should render correctly with compact layout 1
.stat {
font: 600 14px 'Segoe UI', Ubuntu, "Helvetica Neue", Sans-Serif; fill: #434d58;
font: 600 14px 'Segoe UI', Ubuntu, \\"Helvetica Neue\\", Sans-Serif; fill: #434d58;
}
@supports(-moz-appearance: auto) {
/* Selector detects Firefox */
@@ -39,17 +37,16 @@ exports[`Test Render Wakatime Card should render correctly with compact layout 1
animation: fadeInAnimation 0.3s ease-in-out forwards;
}
.rank-text {
font: 800 24px 'Segoe UI', Ubuntu, Sans-Serif; fill: #434d58;
font: 800 24px 'Segoe UI', Ubuntu, Sans-Serif; fill: #434d58;
animation: scaleInAnimation 0.3s ease-in-out forwards;
}
.not_bold { font-weight: 400 }
.bold { font-weight: 700 }
.icon {
fill: #4c71f2;
display: none;
}
.rank-circle-rim {
stroke: #2f80ed;
fill: none;
@@ -79,75 +76,236 @@ exports[`Test Render Wakatime Card should render correctly with compact layout 1
<rect
data-testid="card-bg"
x="0.5"
y="0.5"
rx="4.5"
height="99%"
stroke="#e4e2e2"
width="494"
fill="#fffefe"
stroke-opacity="1"
data-testid=\\"card-bg\\"
x=\\"0.5\\"
y=\\"0.5\\"
rx=\\"4.5\\"
height=\\"99%\\"
stroke=\\"#e4e2e2\\"
width=\\"494\\"
fill=\\"#fffefe\\"
stroke-opacity=\\"1\\"
/>
<g
data-testid="card-title"
transform="translate(25, 35)"
data-testid=\\"card-title\\"
transform=\\"translate(25, 35)\\"
>
<g transform="translate(0, 0)">
<g transform=\\"translate(0, 0)\\">
<text
x="0"
y="0"
class="header"
data-testid="header"
x=\\"0\\"
y=\\"0\\"
class=\\"header\\"
data-testid=\\"header\\"
>Wakatime Stats</text>
</g>
</g>
<g
data-testid="main-card-body"
transform="translate(0, 55)"
data-testid=\\"main-card-body\\"
transform=\\"translate(0, 55)\\"
>
<svg x="0" y="0" width="100%">
<svg x=\\"0\\" y=\\"0\\" width=\\"100%\\">
<g transform=\\"translate(0, 0)\\">
<g class=\\"stagger\\" style=\\"animation-delay: NaNms\\" transform=\\"translate(25, 0)\\">
<text class=\\"stat bold\\" y=\\"12.5\\" data-testid=\\"Other\\">Other:</text>
<text
class=\\"stat\\"
x=\\"350\\"
y=\\"12.5\\"
>19 mins</text>
<mask id="rect-mask">
<rect x="25" y="0" width="440" height="8" fill="white" rx="5" />
<svg width=\\"220\\" x=\\"110\\" y=\\"4\\">
<rect rx=\\"5\\" ry=\\"5\\" x=\\"0\\" y=\\"0\\" width=\\"220\\" height=\\"8\\" fill=\\"#434d58\\"></rect>
<rect
height=\\"8\\"
fill=\\"#2f80ed\\"
rx=\\"5\\" ry=\\"5\\" x=\\"0\\" y=\\"0\\"
data-testid=\\"lang-progress\\"
width=\\"2%\\"
>
</rect>
</svg>
</g>
</g><g transform=\\"translate(0, 25)\\">
<g class=\\"stagger\\" style=\\"animation-delay: NaNms\\" transform=\\"translate(25, 0)\\">
<text class=\\"stat bold\\" y=\\"12.5\\" data-testid=\\"TypeScript\\">TypeScript:</text>
<text
class=\\"stat\\"
x=\\"350\\"
y=\\"12.5\\"
>1 min</text>
<svg width=\\"220\\" x=\\"110\\" y=\\"4\\">
<rect rx=\\"5\\" ry=\\"5\\" x=\\"0\\" y=\\"0\\" width=\\"220\\" height=\\"8\\" fill=\\"#434d58\\"></rect>
<rect
height=\\"8\\"
fill=\\"#2f80ed\\"
rx=\\"5\\" ry=\\"5\\" x=\\"0\\" y=\\"0\\"
data-testid=\\"lang-progress\\"
width=\\"2%\\"
>
</rect>
</svg>
</g>
</g>
</svg>
</g>
</svg>
"
`;
exports[`Test Render Wakatime Card should render correctly with compact layout 1`] = `
"
<svg
width=\\"495\\"
height=\\"115\\"
viewBox=\\"0 0 495 115\\"
fill=\\"none\\"
xmlns=\\"http://www.w3.org/2000/svg\\"
role=\\"img\\"
aria-labelledby=\\"descId\\"
>
<title id=\\"titleId\\"></title>
<desc id=\\"descId\\"></desc>
<style>
.header {
font: 600 18px 'Segoe UI', Ubuntu, Sans-Serif;
fill: #2f80ed;
animation: fadeInAnimation 0.8s ease-in-out forwards;
}
@supports(-moz-appearance: auto) {
/* Selector detects Firefox */
.header { font-size: 15.5px; }
}
.stat {
font: 600 14px 'Segoe UI', Ubuntu, \\"Helvetica Neue\\", Sans-Serif; fill: #434d58;
}
@supports(-moz-appearance: auto) {
/* Selector detects Firefox */
.stat { font-size:12px; }
}
.stagger {
opacity: 0;
animation: fadeInAnimation 0.3s ease-in-out forwards;
}
.rank-text {
font: 800 24px 'Segoe UI', Ubuntu, Sans-Serif; fill: #434d58;
animation: scaleInAnimation 0.3s ease-in-out forwards;
}
.bold { font-weight: 700 }
.icon {
fill: #4c71f2;
display: none;
}
.rank-circle-rim {
stroke: #2f80ed;
fill: none;
stroke-width: 6;
opacity: 0.2;
}
.rank-circle {
stroke: #2f80ed;
stroke-dasharray: 250;
fill: none;
stroke-width: 6;
stroke-linecap: round;
opacity: 0.8;
transform-origin: -10px 8px;
transform: rotate(-90deg);
animation: rankAnimation 1s forwards ease-in-out;
}
.lang-name { font: 400 11px 'Segoe UI', Ubuntu, Sans-Serif; fill: #434d58 }
</style>
<rect
data-testid=\\"card-bg\\"
x=\\"0.5\\"
y=\\"0.5\\"
rx=\\"4.5\\"
height=\\"99%\\"
stroke=\\"#e4e2e2\\"
width=\\"494\\"
fill=\\"#fffefe\\"
stroke-opacity=\\"1\\"
/>
<g
data-testid=\\"card-title\\"
transform=\\"translate(25, 35)\\"
>
<g transform=\\"translate(0, 0)\\">
<text
x=\\"0\\"
y=\\"0\\"
class=\\"header\\"
data-testid=\\"header\\"
>Wakatime Stats</text>
</g>
</g>
<g
data-testid=\\"main-card-body\\"
transform=\\"translate(0, 55)\\"
>
<svg x=\\"0\\" y=\\"0\\" width=\\"100%\\">
<mask id=\\"rect-mask\\">
<rect x=\\"25\\" y=\\"0\\" width=\\"440\\" height=\\"8\\" fill=\\"white\\" rx=\\"5\\" />
</mask>
<rect
mask="url(#rect-mask)"
data-testid="lang-progress"
x="0"
y="0"
width="6.6495"
height="8"
fill="#858585"
mask=\\"url(#rect-mask)\\"
data-testid=\\"lang-progress\\"
x=\\"0\\"
y=\\"0\\"
width=\\"6.6495\\"
height=\\"8\\"
fill=\\"#858585\\"
/>
<rect
mask="url(#rect-mask)"
data-testid="lang-progress"
x="6.6495"
y="0"
width="0.465"
height="8"
fill="#3178c6"
mask=\\"url(#rect-mask)\\"
data-testid=\\"lang-progress\\"
x=\\"6.6495\\"
y=\\"0\\"
width=\\"0.465\\"
height=\\"8\\"
fill=\\"#2b7489\\"
/>
<g transform="translate(25, 25)">
<circle cx="5" cy="6" r="5" fill="#858585" />
<text data-testid="lang-name" x="15" y="10" class='lang-name'>
<g transform=\\"translate(25, 25)\\">
<circle cx=\\"5\\" cy=\\"6\\" r=\\"5\\" fill=\\"#858585\\" />
<text data-testid=\\"lang-name\\" x=\\"15\\" y=\\"10\\" class='lang-name'>
Other - 19 mins
</text>
</g>
<g transform="translate(230, 25)">
<circle cx="5" cy="6" r="5" fill="#3178c6" />
<text data-testid="lang-name" x="15" y="10" class='lang-name'>
<g transform=\\"translate(230, 25)\\">
<circle cx=\\"5\\" cy=\\"6\\" r=\\"5\\" fill=\\"#2b7489\\" />
<text data-testid=\\"lang-name\\" x=\\"15\\" y=\\"10\\" class='lang-name'>
TypeScript - 1 min
</text>
</g>
+7 -7
View File
@@ -1,10 +1,10 @@
import { jest } from "@jest/globals";
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import api from "../api/index.js";
import { calculateRank } from "../src/calculateRank.js";
import { renderStatsCard } from "../src/cards/stats-card.js";
import { CONSTANTS, renderError } from "../src/common/utils.js";
require("@testing-library/jest-dom");
const axios = require("axios");
const MockAdapter = require("axios-mock-adapter");
const api = require("../api/index");
const renderStatsCard = require("../src/cards/stats-card");
const { renderError, CONSTANTS } = require("../src/common/utils");
const calculateRank = require("../src/calculateRank");
const stats = {
name: "Anurag Hazra",
+2 -2
View File
@@ -1,5 +1,5 @@
import "@testing-library/jest-dom";
import { calculateRank } from "../src/calculateRank.js";
require("@testing-library/jest-dom");
const calculateRank = require("../src/calculateRank");
describe("Test calculateRank", () => {
it("should calculate rank correctly", () => {
+6 -6
View File
@@ -1,9 +1,9 @@
import { queryByTestId } from "@testing-library/dom";
import "@testing-library/jest-dom";
import { cssToObject } from "@uppercod/css-to-object";
import { Card } from "../src/common/Card.js";
import { icons } from "../src/common/icons.js";
import { getCardColors } from "../src/common/utils.js";
require("@testing-library/jest-dom");
const cssToObject = require("@uppercod/css-to-object").cssToObject;
const Card = require("../src/common/Card");
const icons = require("../src/common/icons");
const { getCardColors } = require("../src/common/utils");
const { queryByTestId } = require("@testing-library/dom");
describe("Card", () => {
it("should hide border", () => {
-173
View File
@@ -1,173 +0,0 @@
/**
* @file Contains end-to-end tests for the Vercel preview instance.
*/
import dotenv from "dotenv";
dotenv.config();
import { describe } from "@jest/globals";
import axios from "axios";
import { renderRepoCard } from "../../src/cards/repo-card.js";
import { renderStatsCard } from "../../src/cards/stats-card.js";
import { renderTopLanguages } from "../../src/cards/top-languages-card.js";
import { renderWakatimeCard } from "../../src/cards/wakatime-card.js";
// Script variables
const REPO = "dummy-cra";
const USER = "grsdummy";
const STATS_DATA = {
name: "grsdummy",
totalPRs: 2,
totalCommits: 2,
totalIssues: 1,
totalStars: 1,
contributedTo: 2,
rank: {
level: "A+",
score: 51.01013099671447,
},
};
const LANGS_DATA = {
TypeScript: {
color: "#3178c6",
name: "TypeScript",
size: 2049,
},
HTML: {
color: "#e34c26",
name: "HTML",
size: 1721,
},
CSS: {
color: "#563d7c",
name: "CSS",
size: 930,
},
Python: {
color: "#3572A5",
name: "Python",
size: 671,
},
};
const WAKATIME_DATA = {
human_readable_range: "last week",
is_already_updating: false,
is_coding_activity_visible: false,
is_including_today: false,
is_other_usage_visible: false,
is_stuck: false,
is_up_to_date: false,
is_up_to_date_pending_future: false,
percent_calculated: 0,
range: "last_7_days",
status: "pending_update",
timeout: 15,
username: "grsdummy",
writes_only: false,
};
const REPOSITORY_DATA = {
name: "dummy-cra",
nameWithOwner: "grsdummy/dummy-cra",
isPrivate: false,
isArchived: false,
isTemplate: false,
stargazers: {
totalCount: 1,
},
description: "Dummy create react app.",
primaryLanguage: {
color: "#3178c6",
id: "MDg6TGFuZ3VhZ2UyODc=",
name: "TypeScript",
},
forkCount: 0,
starCount: 1,
};
describe("Fetch Cards", () => {
let VERCEL_PREVIEW_URL;
beforeAll(() => {
process.env.NODE_ENV = "development";
VERCEL_PREVIEW_URL = process.env.VERCEL_PREVIEW_URL;
});
test("retrieve stats card", async () => {
expect(VERCEL_PREVIEW_URL).toBeDefined();
// Check if the Vercel preview instance stats card function is up and running.
await expect(
axios.get(`${VERCEL_PREVIEW_URL}/api?username=${USER}`),
).resolves.not.toThrow();
// Get local stats card.
const localStatsCardSVG = renderStatsCard(STATS_DATA);
// Get the Vercel preview stats card response.
const serverStatsSvg = await axios.get(
`${VERCEL_PREVIEW_URL}/api?username=${USER}`,
);
// Check if stats card from deployment matches the stats card from local.
expect(serverStatsSvg.data).toEqual(localStatsCardSVG);
});
test("retrieve language card", async () => {
expect(VERCEL_PREVIEW_URL).toBeDefined();
// Check if the Vercel preview instance language card function is up and running.
await expect(
axios.get(`${VERCEL_PREVIEW_URL}/api/top-langs/?username=${USER}`),
).resolves.not.toThrow();
// Get local language card.
const localLanguageCardSVG = renderTopLanguages(LANGS_DATA);
// Get the Vercel preview language card response.
const severLanguageSVG = await axios.get(
`${VERCEL_PREVIEW_URL}/api/top-langs/?username=${USER}`,
);
// Check if language card from deployment matches the local language card.
expect(severLanguageSVG.data).toEqual(localLanguageCardSVG);
});
test("retrieve WakaTime card", async () => {
expect(VERCEL_PREVIEW_URL).toBeDefined();
// Check if the Vercel preview instance WakaTime function is up and running.
await expect(
axios.get(`${VERCEL_PREVIEW_URL}/api/wakatime?username=${USER}`),
).resolves.not.toThrow();
// Get local WakaTime card.
const localWakaCardSVG = renderWakatimeCard(WAKATIME_DATA);
// Get the Vercel preview WakaTime card response.
const serverWakaTimeSvg = await axios.get(
`${VERCEL_PREVIEW_URL}/api/wakatime?username=${USER}`,
);
// Check if WakaTime card from deployment matches the local WakaTime card.
expect(serverWakaTimeSvg.data).toEqual(localWakaCardSVG);
});
test("retrieve repo card", async () => {
expect(VERCEL_PREVIEW_URL).toBeDefined();
// Check if the Vercel preview instance Repo function is up and running.
await expect(
axios.get(`${VERCEL_PREVIEW_URL}/api/pin/?username=${USER}&repo=${REPO}`),
).resolves.not.toThrow();
// Get local repo card.
const localRepoCardSVG = renderRepoCard(REPOSITORY_DATA);
// Get the Vercel preview repo card response.
const serverRepoSvg = await axios.get(
`${VERCEL_PREVIEW_URL}/api/pin/?username=${USER}&repo=${REPO}`,
);
// Check if Repo card from deployment matches the local Repo card.
expect(serverRepoSvg.data).toEqual(localRepoCardSVG);
});
});
+4 -4
View File
@@ -1,7 +1,7 @@
import "@testing-library/jest-dom";
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import { fetchRepo } from "../src/fetchers/repo-fetcher.js";
require("@testing-library/jest-dom");
const axios = require("axios");
const MockAdapter = require("axios-mock-adapter");
const fetchRepo = require("../src/fetchers/repo-fetcher");
const data_repo = {
repository: {
+10 -38
View File
@@ -1,8 +1,8 @@
import "@testing-library/jest-dom";
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import { calculateRank } from "../src/calculateRank.js";
import { fetchStats } from "../src/fetchers/stats-fetcher.js";
require("@testing-library/jest-dom");
const axios = require("axios");
const MockAdapter = require("axios-mock-adapter");
const fetchStats = require("../src/fetchers/stats-fetcher");
const calculateRank = require("../src/calculateRank");
const data = {
data: {
@@ -20,11 +20,11 @@ const data = {
repositories: {
totalCount: 5,
nodes: [
{ name: "test-repo-1", stargazers: { totalCount: 100 } },
{ name: "test-repo-2", stargazers: { totalCount: 100 } },
{ name: "test-repo-3", stargazers: { totalCount: 100 } },
{ name: "test-repo-4", stargazers: { totalCount: 50 } },
{ name: "test-repo-5", stargazers: { totalCount: 50 } },
{ stargazers: { totalCount: 100 } },
{ stargazers: { totalCount: 100 } },
{ stargazers: { totalCount: 100 } },
{ stargazers: { totalCount: 50 } },
{ stargazers: { totalCount: 50 } },
],
},
},
@@ -134,32 +134,4 @@ describe("Test fetchStats", () => {
rank,
});
});
it("should exclude stars of the `test-repo-1` repository", async () => {
mock.onPost("https://api.github.com/graphql").reply(200, data);
mock
.onGet("https://api.github.com/search/commits?q=author:anuraghazra")
.reply(200, { total_count: 1000 });
let stats = await fetchStats("anuraghazra", true, true, ["test-repo-1"]);
const rank = calculateRank({
totalCommits: 1050,
totalRepos: 5,
followers: 100,
contributions: 61,
stargazers: 300,
prs: 300,
issues: 200,
});
expect(stats).toStrictEqual({
contributedTo: 61,
name: "Anurag Hazra",
totalCommits: 1050,
totalIssues: 200,
totalPRs: 300,
totalStars: 300,
rank,
});
});
});
+5 -5
View File
@@ -1,7 +1,7 @@
import "@testing-library/jest-dom";
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import { fetchTopLanguages } from "../src/fetchers/top-languages-fetcher.js";
require("@testing-library/jest-dom");
const axios = require("axios");
const MockAdapter = require("axios-mock-adapter");
const fetchTopLanguages = require("../src/fetchers/top-languages-fetcher");
const mock = new MockAdapter(axios);
@@ -81,7 +81,7 @@ describe("FetchTopLanguages", () => {
it("should fetch correct language data while excluding the 'test-repo-1' repository", async () => {
mock.onPost("https://api.github.com/graphql").reply(200, data_langs);
let repo = await fetchTopLanguages("anuraghazra", ["test-repo-1"]);
let repo = await fetchTopLanguages("anuraghazra", exclude_repo=["test-repo-1"]);
expect(repo).toStrictEqual({
HTML: {
color: "#0f0",
+17 -17
View File
@@ -1,7 +1,7 @@
import "@testing-library/jest-dom";
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import { fetchWakatimeStats } from "../src/fetchers/wakatime-fetcher.js";
require("@testing-library/jest-dom");
const axios = require("axios");
const MockAdapter = require("axios-mock-adapter");
const { fetchWakatimeStats } = require("../src/fetchers/wakatime-fetcher");
const mock = new MockAdapter(axios);
afterEach(() => {
@@ -111,9 +111,9 @@ describe("Wakatime fetcher", () => {
const repo = await fetchWakatimeStats({ username });
expect(repo).toMatchInlineSnapshot(`
{
"categories": [
{
Object {
"categories": Array [
Object {
"digital": "22:40",
"hours": 22,
"minutes": 40,
@@ -127,8 +127,8 @@ describe("Wakatime fetcher", () => {
"daily_average_including_other_language": 16329,
"days_including_holidays": 7,
"days_minus_holidays": 5,
"editors": [
{
"editors": Array [
Object {
"digital": "22:40",
"hours": 22,
"minutes": 40,
@@ -150,8 +150,8 @@ describe("Wakatime fetcher", () => {
"is_other_usage_visible": true,
"is_stuck": false,
"is_up_to_date": true,
"languages": [
{
"languages": Array [
Object {
"digital": "0:19",
"hours": 0,
"minutes": 19,
@@ -160,7 +160,7 @@ describe("Wakatime fetcher", () => {
"text": "19 mins",
"total_seconds": 1170.434361,
},
{
Object {
"digital": "0:01",
"hours": 0,
"minutes": 1,
@@ -169,7 +169,7 @@ describe("Wakatime fetcher", () => {
"text": "1 min",
"total_seconds": 83.293809,
},
{
Object {
"digital": "0:00",
"hours": 0,
"minutes": 0,
@@ -179,8 +179,8 @@ describe("Wakatime fetcher", () => {
"total_seconds": 54.975151,
},
],
"operating_systems": [
{
"operating_systems": Array [
Object {
"digital": "22:40",
"hours": 22,
"minutes": 40,
@@ -207,9 +207,9 @@ describe("Wakatime fetcher", () => {
mock.onGet(/\/https:\/\/wakatime\.com\/api/).reply(404, wakaTimeData);
await expect(fetchWakatimeStats("noone")).rejects.toThrow(
'Missing params "username" make sure you pass the parameters in URL',
"Missing params \"username\" make sure you pass the parameters in URL",
);
});
});
export { wakaTimeData };
module.exports = { wakaTimeData };
+1 -1
View File
@@ -1,4 +1,4 @@
import { flexLayout } from "../src/common/utils.js";
const { flexLayout } = require("../src/common/utils");
describe("flexLayout", () => {
it("should work with row & col layouts", () => {
+6 -7
View File
@@ -1,10 +1,9 @@
import { jest } from "@jest/globals";
import "@testing-library/jest-dom";
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import pin from "../api/pin.js";
import { renderRepoCard } from "../src/cards/repo-card.js";
import { renderError } from "../src/common/utils.js";
require("@testing-library/jest-dom");
const axios = require("axios");
const MockAdapter = require("axios-mock-adapter");
const pin = require("../api/pin");
const renderRepoCard = require("../src/cards/repo-card");
const { renderError } = require("../src/common/utils");
const data_repo = {
repository: {
+5 -5
View File
@@ -1,9 +1,9 @@
import { queryByTestId } from "@testing-library/dom";
import "@testing-library/jest-dom";
import { cssToObject } from "@uppercod/css-to-object";
import { renderRepoCard } from "../src/cards/repo-card.js";
require("@testing-library/jest-dom");
const cssToObject = require("@uppercod/css-to-object").cssToObject;
const renderRepoCard = require("../src/cards/repo-card");
import { themes } from "../themes/index.js";
const { queryByTestId } = require("@testing-library/dom");
const themes = require("../themes");
const data_repo = {
repository: {
+9 -56
View File
@@ -1,14 +1,13 @@
import {
getByTestId,
queryAllByTestId,
queryByTestId,
} from "@testing-library/dom";
import { cssToObject } from "@uppercod/css-to-object";
import { renderStatsCard } from "../src/cards/stats-card.js";
// adds special assertions like toHaveTextContent
import "@testing-library/jest-dom";
require("@testing-library/jest-dom");
const cssToObject = require("@uppercod/css-to-object").cssToObject;
const renderStatsCard = require("../src/cards/stats-card");
import { themes } from "../themes/index.js";
const {
getByTestId,
queryByTestId,
queryAllByTestId,
} = require("@testing-library/dom");
const themes = require("../themes");
describe("Test renderStatsCard", () => {
const stats = {
@@ -76,52 +75,6 @@ describe("Test renderStatsCard", () => {
expect(queryByTestId(document.body, "rank-circle")).not.toBeInTheDocument();
});
it("should render with custom width set", () => {
document.body.innerHTML = renderStatsCard(stats);
expect(document.querySelector("svg")).toHaveAttribute("width", "495");
document.body.innerHTML = renderStatsCard(stats, { card_width: 400 });
expect(document.querySelector("svg")).toHaveAttribute("width", "400");
});
it("should render with custom width set and limit minimum width", () => {
document.body.innerHTML = renderStatsCard(stats, { card_width: 1 });
expect(document.querySelector("svg")).toHaveAttribute("width", "340");
document.body.innerHTML = renderStatsCard(stats, {
card_width: 1,
hide_rank: true,
});
expect(document.querySelector("svg")).toHaveAttribute(
"width",
"305.81250000000006",
);
document.body.innerHTML = renderStatsCard(stats, {
card_width: 1,
hide_rank: true,
show_icons: true,
});
expect(document.querySelector("svg")).toHaveAttribute(
"width",
"305.81250000000006",
);
document.body.innerHTML = renderStatsCard(stats, {
card_width: 1,
hide_rank: false,
show_icons: true,
});
expect(document.querySelector("svg")).toHaveAttribute("width", "356");
document.body.innerHTML = renderStatsCard(stats, {
card_width: 1,
hide_rank: false,
show_icons: false,
});
expect(document.querySelector("svg")).toHaveAttribute("width", "340");
});
it("should render default colors properly", () => {
document.body.innerHTML = renderStatsCard(stats);
+9 -13
View File
@@ -1,13 +1,9 @@
import { queryAllByTestId, queryByTestId } from "@testing-library/dom";
import { cssToObject } from "@uppercod/css-to-object";
import {
MIN_CARD_WIDTH,
renderTopLanguages,
} from "../src/cards/top-languages-card.js";
// adds special assertions like toHaveTextContent
import "@testing-library/jest-dom";
require("@testing-library/jest-dom");
const cssToObject = require("@uppercod/css-to-object").cssToObject;
const renderTopLanguages = require("../src/cards/top-languages-card");
import { themes } from "../themes/index.js";
const { queryByTestId, queryAllByTestId } = require("@testing-library/dom");
const themes = require("../themes");
describe("Test renderTopLanguages", () => {
const langs = {
@@ -112,13 +108,13 @@ describe("Test renderTopLanguages", () => {
expect(document.querySelector("svg")).toHaveAttribute(
"width",
MIN_CARD_WIDTH.toString(),
renderTopLanguages.MIN_CARD_WIDTH.toString(),
);
document.body.innerHTML = renderTopLanguages(langs, { card_width: 100 });
expect(document.querySelector("svg")).toHaveAttribute(
"width",
MIN_CARD_WIDTH.toString(),
renderTopLanguages.MIN_CARD_WIDTH.toString(),
);
});
@@ -251,7 +247,7 @@ describe("Test renderTopLanguages", () => {
});
it("should render langs with specified langs_count", async () => {
const options = {
options = {
langs_count: 1,
};
document.body.innerHTML = renderTopLanguages(langs, { ...options });
@@ -261,7 +257,7 @@ describe("Test renderTopLanguages", () => {
});
it("should render langs with specified langs_count even when hide is set", async () => {
const options = {
options = {
hide: ["HTML"],
langs_count: 2,
};
+13 -17
View File
@@ -1,13 +1,14 @@
import { queryByTestId } from "@testing-library/dom";
import "@testing-library/jest-dom";
import { renderWakatimeCard } from "../src/cards/wakatime-card.js";
import { getCardColors } from "../src/common/utils.js";
import { wakaTimeData } from "./fetchWakatime.test.js";
require("@testing-library/jest-dom");
const { queryByTestId } = require("@testing-library/dom");
const renderWakatimeCard = require("../src/cards/wakatime-card");
const { wakaTimeData } = require("./fetchWakatime.test");
describe("Test Render Wakatime Card", () => {
it("should render correctly", () => {
const card = renderWakatimeCard(wakaTimeData.data);
expect(getCardColors).toMatchSnapshot();
expect(card).toMatchSnapshot();
});
it("should render correctly with compact layout", () => {
@@ -47,15 +48,10 @@ describe("Test Render Wakatime Card", () => {
});
it('should show "no coding activitiy this week" message when there hasn not been activity', () => {
document.body.innerHTML = renderWakatimeCard(
{
...wakaTimeData.data,
languages: undefined,
},
{},
);
expect(document.querySelector(".stat").textContent).toBe(
"No coding activity this week",
);
});
document.body.innerHTML = renderWakatimeCard({
...wakaTimeData.data,
languages: undefined
}, {});
expect(document.querySelector(".stat").textContent).toBe("No coding activity this week")
})
});
+3 -4
View File
@@ -1,7 +1,6 @@
import { jest } from "@jest/globals";
import "@testing-library/jest-dom";
import { retryer } from "../src/common/retryer.js";
import { logger } from "../src/common/utils.js";
require("@testing-library/jest-dom");
const retryer = require("../src/common/retryer");
const { logger } = require("../src/common/utils");
const fetcher = jest.fn((variables, token) => {
logger.log(variables, token);
+6 -7
View File
@@ -1,10 +1,9 @@
import { jest } from "@jest/globals";
import "@testing-library/jest-dom";
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import topLangs from "../api/top-langs.js";
import { renderTopLanguages } from "../src/cards/top-languages-card.js";
import { renderError } from "../src/common/utils.js";
require("@testing-library/jest-dom");
const axios = require("axios");
const MockAdapter = require("axios-mock-adapter");
const topLangs = require("../api/top-langs");
const renderTopLanguages = require("../src/cards/top-languages-card");
const { renderError } = require("../src/common/utils");
const data_langs = {
data: {
+9 -9
View File
@@ -1,12 +1,14 @@
import { queryByTestId } from "@testing-library/dom";
import "@testing-library/jest-dom";
import {
encodeHTML,
getCardColors,
require("@testing-library/jest-dom");
const {
kFormatter,
encodeHTML,
renderError,
flexLayout,
getCardColors,
wrapTextMultiline,
} from "../src/common/utils.js";
} = require("../src/common/utils");
const { queryByTestId } = require("@testing-library/dom");
describe("Test utils.js", () => {
it("should test kFormatter", () => {
@@ -30,9 +32,7 @@ describe("Test utils.js", () => {
expect(
queryByTestId(document.body, "message").children[0],
).toHaveTextContent(/Something went wrong/gim);
expect(
queryByTestId(document.body, "message").children[1],
).toBeEmptyDOMElement(2);
expect(queryByTestId(document.body, "message").children[1]).toBeEmpty(2);
// Secondary message
document.body.innerHTML = renderError(
+40 -44
View File
@@ -16,27 +16,26 @@ Use `?theme=THEME_NAME` parameter like so :-
| | | |
| :--: | :--: | :--: |
| `default` ![default][default] | `transparent` ![transparent][transparent] | `dark` ![dark][dark] |
| `radical` ![radical][radical] | `merko` ![merko][merko] | `gruvbox` ![gruvbox][gruvbox] |
| `gruvbox_light` ![gruvbox_light][gruvbox_light] | `tokyonight` ![tokyonight][tokyonight] | `onedark` ![onedark][onedark] |
| `cobalt` ![cobalt][cobalt] | `synthwave` ![synthwave][synthwave] | `highcontrast` ![highcontrast][highcontrast] |
| `dracula` ![dracula][dracula] | `prussian` ![prussian][prussian] | `monokai` ![monokai][monokai] |
| `vue` ![vue][vue] | `vue-dark` ![vue-dark][vue-dark] | `shades-of-purple` ![shades-of-purple][shades-of-purple] |
| `nightowl` ![nightowl][nightowl] | `buefy` ![buefy][buefy] | `blue-green` ![blue-green][blue-green] |
| `algolia` ![algolia][algolia] | `great-gatsby` ![great-gatsby][great-gatsby] | `darcula` ![darcula][darcula] |
| `bear` ![bear][bear] | `solarized-dark` ![solarized-dark][solarized-dark] | `solarized-light` ![solarized-light][solarized-light] |
| `chartreuse-dark` ![chartreuse-dark][chartreuse-dark] | `nord` ![nord][nord] | `gotham` ![gotham][gotham] |
| `material-palenight` ![material-palenight][material-palenight] | `graywhite` ![graywhite][graywhite] | `vision-friendly-dark` ![vision-friendly-dark][vision-friendly-dark] |
| `ayu-mirage` ![ayu-mirage][ayu-mirage] | `midnight-purple` ![midnight-purple][midnight-purple] | `calm` ![calm][calm] |
| `flag-india` ![flag-india][flag-india] | `omni` ![omni][omni] | `react` ![react][react] |
| `jolly` ![jolly][jolly] | `maroongold` ![maroongold][maroongold] | `yeblu` ![yeblu][yeblu] |
| `blueberry` ![blueberry][blueberry] | `slateorange` ![slateorange][slateorange] | `kacho_ga` ![kacho_ga][kacho_ga] |
| `outrun` ![outrun][outrun] | `ocean_dark` ![ocean_dark][ocean_dark] | `city_lights` ![city_lights][city_lights] |
| `github_dark` ![github_dark][github_dark] | `discord_old_blurple` ![discord_old_blurple][discord_old_blurple] | `aura_dark` ![aura_dark][aura_dark] |
| `panda` ![panda][panda] | `noctis_minimus` ![noctis_minimus][noctis_minimus] | `cobalt2` ![cobalt2][cobalt2] |
| `swift` ![swift][swift] | `aura` ![aura][aura] | `apprentice` ![apprentice][apprentice] |
| `moltack` ![moltack][moltack] | `codeSTACKr` ![codeSTACKr][codeSTACKr] | `rose_pine` ![rose_pine][rose_pine] |
| [Add your theme][add-theme] | | |
| `default` ![default][default] | `dark` ![dark][dark] | `radical` ![radical][radical] |
| `merko` ![merko][merko] | `gruvbox` ![gruvbox][gruvbox] | `gruvbox_light` ![gruvbox_light][gruvbox_light] |
| `tokyonight` ![tokyonight][tokyonight] | `onedark` ![onedark][onedark] | `cobalt` ![cobalt][cobalt] |
| `synthwave` ![synthwave][synthwave] | `highcontrast` ![highcontrast][highcontrast] | `dracula` ![dracula][dracula] |
| `prussian` ![prussian][prussian] | `monokai` ![monokai][monokai] | `vue` ![vue][vue] |
| `vue-dark` ![vue-dark][vue-dark] | `shades-of-purple` ![shades-of-purple][shades-of-purple] | `nightowl` ![nightowl][nightowl] |
| `buefy` ![buefy][buefy] | `blue-green` ![blue-green][blue-green] | `algolia` ![algolia][algolia] |
| `great-gatsby` ![great-gatsby][great-gatsby] | `darcula` ![darcula][darcula] | `bear` ![bear][bear] |
| `solarized-dark` ![solarized-dark][solarized-dark] | `solarized-light` ![solarized-light][solarized-light] | `chartreuse-dark` ![chartreuse-dark][chartreuse-dark] |
| `nord` ![nord][nord] | `gotham` ![gotham][gotham] | `material-palenight` ![material-palenight][material-palenight] |
| `graywhite` ![graywhite][graywhite] | `vision-friendly-dark` ![vision-friendly-dark][vision-friendly-dark] | `ayu-mirage` ![ayu-mirage][ayu-mirage] |
| `midnight-purple` ![midnight-purple][midnight-purple] | `calm` ![calm][calm] | `flag-india` ![flag-india][flag-india] |
| `omni` ![omni][omni] | `react` ![react][react] | `jolly` ![jolly][jolly] |
| `maroongold` ![maroongold][maroongold] | `yeblu` ![yeblu][yeblu] | `blueberry` ![blueberry][blueberry] |
| `slateorange` ![slateorange][slateorange] | `kacho_ga` ![kacho_ga][kacho_ga] | `outrun` ![outrun][outrun] |
| `ocean_dark` ![ocean_dark][ocean_dark] | `city_lights` ![city_lights][city_lights] | `github_dark` ![github_dark][github_dark] |
| `discord_old_blurple` ![discord_old_blurple][discord_old_blurple] | `aura_dark` ![aura_dark][aura_dark] | `panda` ![panda][panda] |
| `noctis_minimus` ![noctis_minimus][noctis_minimus] | `cobalt2` ![cobalt2][cobalt2] | `swift` ![swift][swift] |
| `aura` ![aura][aura] | `apprentice` ![apprentice][apprentice] | `moltack` ![moltack][moltack] |
| `codeSTACKr` ![codeSTACKr][codeSTACKr] | `rose_pine` ![rose_pine][rose_pine] | [Add your theme][add-theme] |
## Repo Card
@@ -44,32 +43,30 @@ Use `?theme=THEME_NAME` parameter like so :-
| | | |
| :--: | :--: | :--: |
| `default_repocard` ![default_repocard][default_repocard_repo] | `transparent` ![transparent][transparent_repo] | `dark` ![dark][dark_repo] |
| `radical` ![radical][radical_repo] | `merko` ![merko][merko_repo] | `gruvbox` ![gruvbox][gruvbox_repo] |
| `gruvbox_light` ![gruvbox_light][gruvbox_light_repo] | `tokyonight` ![tokyonight][tokyonight_repo] | `onedark` ![onedark][onedark_repo] |
| `cobalt` ![cobalt][cobalt_repo] | `synthwave` ![synthwave][synthwave_repo] | `highcontrast` ![highcontrast][highcontrast_repo] |
| `dracula` ![dracula][dracula_repo] | `prussian` ![prussian][prussian_repo] | `monokai` ![monokai][monokai_repo] |
| `vue` ![vue][vue_repo] | `vue-dark` ![vue-dark][vue-dark_repo] | `shades-of-purple` ![shades-of-purple][shades-of-purple_repo] |
| `nightowl` ![nightowl][nightowl_repo] | `buefy` ![buefy][buefy_repo] | `blue-green` ![blue-green][blue-green_repo] |
| `algolia` ![algolia][algolia_repo] | `great-gatsby` ![great-gatsby][great-gatsby_repo] | `darcula` ![darcula][darcula_repo] |
| `bear` ![bear][bear_repo] | `solarized-dark` ![solarized-dark][solarized-dark_repo] | `solarized-light` ![solarized-light][solarized-light_repo] |
| `chartreuse-dark` ![chartreuse-dark][chartreuse-dark_repo] | `nord` ![nord][nord_repo] | `gotham` ![gotham][gotham_repo] |
| `material-palenight` ![material-palenight][material-palenight_repo] | `graywhite` ![graywhite][graywhite_repo] | `vision-friendly-dark` ![vision-friendly-dark][vision-friendly-dark_repo] |
| `ayu-mirage` ![ayu-mirage][ayu-mirage_repo] | `midnight-purple` ![midnight-purple][midnight-purple_repo] | `calm` ![calm][calm_repo] |
| `flag-india` ![flag-india][flag-india_repo] | `omni` ![omni][omni_repo] | `react` ![react][react_repo] |
| `jolly` ![jolly][jolly_repo] | `maroongold` ![maroongold][maroongold_repo] | `yeblu` ![yeblu][yeblu_repo] |
| `blueberry` ![blueberry][blueberry_repo] | `slateorange` ![slateorange][slateorange_repo] | `kacho_ga` ![kacho_ga][kacho_ga_repo] |
| `outrun` ![outrun][outrun_repo] | `ocean_dark` ![ocean_dark][ocean_dark_repo] | `city_lights` ![city_lights][city_lights_repo] |
| `github_dark` ![github_dark][github_dark_repo] | `discord_old_blurple` ![discord_old_blurple][discord_old_blurple_repo] | `aura_dark` ![aura_dark][aura_dark_repo] |
| `panda` ![panda][panda_repo] | `noctis_minimus` ![noctis_minimus][noctis_minimus_repo] | `cobalt2` ![cobalt2][cobalt2_repo] |
| `swift` ![swift][swift_repo] | `aura` ![aura][aura_repo] | `apprentice` ![apprentice][apprentice_repo] |
| `moltack` ![moltack][moltack_repo] | `codeSTACKr` ![codeSTACKr][codeSTACKr_repo] | `rose_pine` ![rose_pine][rose_pine_repo] |
| [Add your theme][add-theme] | | |
| `default_repocard` ![default_repocard][default_repocard_repo] | `dark` ![dark][dark_repo] | `radical` ![radical][radical_repo] |
| `merko` ![merko][merko_repo] | `gruvbox` ![gruvbox][gruvbox_repo] | `gruvbox_light` ![gruvbox_light][gruvbox_light_repo] |
| `tokyonight` ![tokyonight][tokyonight_repo] | `onedark` ![onedark][onedark_repo] | `cobalt` ![cobalt][cobalt_repo] |
| `synthwave` ![synthwave][synthwave_repo] | `highcontrast` ![highcontrast][highcontrast_repo] | `dracula` ![dracula][dracula_repo] |
| `prussian` ![prussian][prussian_repo] | `monokai` ![monokai][monokai_repo] | `vue` ![vue][vue_repo] |
| `vue-dark` ![vue-dark][vue-dark_repo] | `shades-of-purple` ![shades-of-purple][shades-of-purple_repo] | `nightowl` ![nightowl][nightowl_repo] |
| `buefy` ![buefy][buefy_repo] | `blue-green` ![blue-green][blue-green_repo] | `algolia` ![algolia][algolia_repo] |
| `great-gatsby` ![great-gatsby][great-gatsby_repo] | `darcula` ![darcula][darcula_repo] | `bear` ![bear][bear_repo] |
| `solarized-dark` ![solarized-dark][solarized-dark_repo] | `solarized-light` ![solarized-light][solarized-light_repo] | `chartreuse-dark` ![chartreuse-dark][chartreuse-dark_repo] |
| `nord` ![nord][nord_repo] | `gotham` ![gotham][gotham_repo] | `material-palenight` ![material-palenight][material-palenight_repo] |
| `graywhite` ![graywhite][graywhite_repo] | `vision-friendly-dark` ![vision-friendly-dark][vision-friendly-dark_repo] | `ayu-mirage` ![ayu-mirage][ayu-mirage_repo] |
| `midnight-purple` ![midnight-purple][midnight-purple_repo] | `calm` ![calm][calm_repo] | `flag-india` ![flag-india][flag-india_repo] |
| `omni` ![omni][omni_repo] | `react` ![react][react_repo] | `jolly` ![jolly][jolly_repo] |
| `maroongold` ![maroongold][maroongold_repo] | `yeblu` ![yeblu][yeblu_repo] | `blueberry` ![blueberry][blueberry_repo] |
| `slateorange` ![slateorange][slateorange_repo] | `kacho_ga` ![kacho_ga][kacho_ga_repo] | `outrun` ![outrun][outrun_repo] |
| `ocean_dark` ![ocean_dark][ocean_dark_repo] | `city_lights` ![city_lights][city_lights_repo] | `github_dark` ![github_dark][github_dark_repo] |
| `discord_old_blurple` ![discord_old_blurple][discord_old_blurple_repo] | `aura_dark` ![aura_dark][aura_dark_repo] | `panda` ![panda][panda_repo] |
| `noctis_minimus` ![noctis_minimus][noctis_minimus_repo] | `cobalt2` ![cobalt2][cobalt2_repo] | `swift` ![swift][swift_repo] |
| `aura` ![aura][aura_repo] | `apprentice` ![apprentice][apprentice_repo] | `moltack` ![moltack][moltack_repo] |
| `codeSTACKr` ![codeSTACKr][codeSTACKr_repo] | `rose_pine` ![rose_pine][rose_pine_repo] | [Add your theme][add-theme] |
[default]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=default
[default_repocard]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=default_repocard
[transparent]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=transparent
[dark]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=dark
[radical]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=radical
[merko]: https://github-readme-stats.vercel.app/api?username=anuraghazra&show_icons=true&hide=contribs,prs&cache_seconds=86400&theme=merko
@@ -132,7 +129,6 @@ Use `?theme=THEME_NAME` parameter like so :-
[default_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=default
[default_repocard_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=default_repocard
[transparent_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=transparent
[dark_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=dark
[radical_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=radical
[merko_repo]: https://github-readme-stats.vercel.app/api/pin/?username=anuraghazra&repo=github-readme-stats&cache_seconds=86400&theme=merko
+4 -10
View File
@@ -1,4 +1,4 @@
export const themes = {
const themes = {
default: {
title_color: "2f80ed",
icon_color: "4c71f2",
@@ -12,12 +12,6 @@ export const themes = {
text_color: "434d58",
bg_color: "fffefe",
},
transparent: {
title_color: "006AFF",
icon_color: "0579C3",
text_color: "417E87",
bg_color: "ffffff00",
},
dark: {
title_color: "fff",
icon_color: "79ff97",
@@ -361,12 +355,12 @@ export const themes = {
bg_color: "09131B",
border_color: "0c1a25",
},
rose_pine: {
"rose_pine":{
title_color: "9ccfd8",
icon_color: "ebbcba",
text_color: "e0def4",
bg_color: "191724",
},
}
};
export default themes;
module.exports = themes;