@stats-forge/github-stats-forge-core 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +148 -0
- package/build/api/api-result.d.ts +44 -0
- package/build/api/api-result.d.ts.map +1 -0
- package/build/api/api-result.js +33 -0
- package/build/api/gist.d.ts +29 -0
- package/build/api/gist.d.ts.map +1 -0
- package/build/api/gist.js +52 -0
- package/build/api/index.d.ts +13 -0
- package/build/api/index.d.ts.map +1 -0
- package/build/api/index.js +8 -0
- package/build/api/params.d.ts +93 -0
- package/build/api/params.d.ts.map +1 -0
- package/build/api/params.js +145 -0
- package/build/api/pin.d.ts +47 -0
- package/build/api/pin.d.ts.map +1 -0
- package/build/api/pin.js +87 -0
- package/build/api/stats.d.ts +42 -0
- package/build/api/stats.d.ts.map +1 -0
- package/build/api/stats.js +132 -0
- package/build/api/top-langs.d.ts +37 -0
- package/build/api/top-langs.d.ts.map +1 -0
- package/build/api/top-langs.js +101 -0
- package/build/api/wakatime.d.ts +34 -0
- package/build/api/wakatime.d.ts.map +1 -0
- package/build/api/wakatime.js +91 -0
- package/build/calculateRank.d.ts +29 -0
- package/build/calculateRank.d.ts.map +1 -0
- package/build/calculateRank.js +58 -0
- package/build/cards/gist.d.ts +16 -0
- package/build/cards/gist.d.ts.map +1 -0
- package/build/cards/gist.js +119 -0
- package/build/cards/index.d.ts +11 -0
- package/build/cards/index.d.ts.map +1 -0
- package/build/cards/index.js +7 -0
- package/build/cards/options.d.ts +19 -0
- package/build/cards/options.d.ts.map +1 -0
- package/build/cards/options.js +1 -0
- package/build/cards/repo.d.ts +25 -0
- package/build/cards/repo.d.ts.map +1 -0
- package/build/cards/repo.js +276 -0
- package/build/cards/stats.d.ts +37 -0
- package/build/cards/stats.d.ts.map +1 -0
- package/build/cards/stats.js +457 -0
- package/build/cards/top-languages.d.ts +153 -0
- package/build/cards/top-languages.d.ts.map +1 -0
- package/build/cards/top-languages.js +805 -0
- package/build/cards/wakatime.d.ts +31 -0
- package/build/cards/wakatime.d.ts.map +1 -0
- package/build/cards/wakatime.js +376 -0
- package/build/common/Card.d.ts +121 -0
- package/build/common/Card.d.ts.map +1 -0
- package/build/common/Card.js +305 -0
- package/build/common/I18n.d.ts +27 -0
- package/build/common/I18n.d.ts.map +1 -0
- package/build/common/I18n.js +35 -0
- package/build/common/color.d.ts +112 -0
- package/build/common/color.d.ts.map +1 -0
- package/build/common/color.js +188 -0
- package/build/common/config.d.ts +53 -0
- package/build/common/config.d.ts.map +1 -0
- package/build/common/config.js +87 -0
- package/build/common/constants.d.ts +7 -0
- package/build/common/constants.d.ts.map +1 -0
- package/build/common/constants.js +9 -0
- package/build/common/date.d.ts +29 -0
- package/build/common/date.d.ts.map +1 -0
- package/build/common/date.js +23 -0
- package/build/common/error.d.ts +87 -0
- package/build/common/error.d.ts.map +1 -0
- package/build/common/error.js +108 -0
- package/build/common/fmt.d.ts +28 -0
- package/build/common/fmt.d.ts.map +1 -0
- package/build/common/fmt.js +68 -0
- package/build/common/html.d.ts +8 -0
- package/build/common/html.d.ts.map +1 -0
- package/build/common/html.js +14 -0
- package/build/common/http.d.ts +53 -0
- package/build/common/http.d.ts.map +1 -0
- package/build/common/http.js +47 -0
- package/build/common/icons.d.ts +28 -0
- package/build/common/icons.d.ts.map +1 -0
- package/build/common/icons.js +77 -0
- package/build/common/languageColors.d.ts +11 -0
- package/build/common/languageColors.d.ts.map +1 -0
- package/build/common/languageColors.js +15 -0
- package/build/common/languageColors.json +678 -0
- package/build/common/log.d.ts +9 -0
- package/build/common/log.d.ts.map +1 -0
- package/build/common/log.js +8 -0
- package/build/common/ops.d.ts +59 -0
- package/build/common/ops.d.ts.map +1 -0
- package/build/common/ops.js +115 -0
- package/build/common/render.d.ts +196 -0
- package/build/common/render.d.ts.map +1 -0
- package/build/common/render.js +474 -0
- package/build/common/retryer.d.ts +36 -0
- package/build/common/retryer.d.ts.map +1 -0
- package/build/common/retryer.js +67 -0
- package/build/fetchers/gist.d.ts +15 -0
- package/build/fetchers/gist.d.ts.map +1 -0
- package/build/fetchers/gist.js +68 -0
- package/build/fetchers/index.d.ts +13 -0
- package/build/fetchers/index.d.ts.map +1 -0
- package/build/fetchers/index.js +10 -0
- package/build/fetchers/repo.d.ts +27 -0
- package/build/fetchers/repo.d.ts.map +1 -0
- package/build/fetchers/repo.js +100 -0
- package/build/fetchers/stats.d.ts +74 -0
- package/build/fetchers/stats.d.ts.map +1 -0
- package/build/fetchers/stats.js +498 -0
- package/build/fetchers/top-languages.d.ts +23 -0
- package/build/fetchers/top-languages.d.ts.map +1 -0
- package/build/fetchers/top-languages.js +89 -0
- package/build/fetchers/types.d.ts +130 -0
- package/build/fetchers/types.d.ts.map +1 -0
- package/build/fetchers/types.js +1 -0
- package/build/fetchers/wakatime.d.ts +19 -0
- package/build/fetchers/wakatime.d.ts.map +1 -0
- package/build/fetchers/wakatime.js +36 -0
- package/build/graphql/contributionsDocument.d.ts +18 -0
- package/build/graphql/contributionsDocument.d.ts.map +1 -0
- package/build/graphql/contributionsDocument.js +30 -0
- package/build/graphql/generated/common.d.ts +42 -0
- package/build/graphql/generated/common.d.ts.map +1 -0
- package/build/graphql/generated/common.js +2 -0
- package/build/graphql/generated/gist.d.ts +44 -0
- package/build/graphql/generated/gist.d.ts.map +1 -0
- package/build/graphql/generated/gist.js +27 -0
- package/build/graphql/generated/repo.d.ts +67 -0
- package/build/graphql/generated/repo.d.ts.map +1 -0
- package/build/graphql/generated/repo.js +30 -0
- package/build/graphql/generated/stats.d.ts +150 -0
- package/build/graphql/generated/stats.d.ts.map +1 -0
- package/build/graphql/generated/stats.js +95 -0
- package/build/graphql/generated/top-languages.d.ts +54 -0
- package/build/graphql/generated/top-languages.d.ts.map +1 -0
- package/build/graphql/generated/top-languages.js +27 -0
- package/build/graphql/graphqlDocument.d.ts +22 -0
- package/build/graphql/graphqlDocument.d.ts.map +1 -0
- package/build/graphql/graphqlDocument.js +8 -0
- package/build/graphql/reposContributedToDocument.d.ts +27 -0
- package/build/graphql/reposContributedToDocument.d.ts.map +1 -0
- package/build/graphql/reposContributedToDocument.js +59 -0
- package/build/index.d.ts +15 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +10 -0
- package/build/themes/index.d.ts +505 -0
- package/build/themes/index.d.ts.map +1 -0
- package/build/themes/index.js +505 -0
- package/build/translations.d.ts +1153 -0
- package/build/translations.d.ts.map +1 -0
- package/build/translations.js +1156 -0
- package/package.json +114 -0
- package/src/_emoji-name-map.d.ts +10 -0
- package/src/_github-username-regex.d.ts +4 -0
- package/src/api/api-result.ts +69 -0
- package/src/api/gist.ts +66 -0
- package/src/api/index.ts +16 -0
- package/src/api/params.ts +221 -0
- package/src/api/pin.ts +126 -0
- package/src/api/stats.ts +195 -0
- package/src/api/top-langs.ts +150 -0
- package/src/api/wakatime.ts +130 -0
- package/src/calculateRank.ts +91 -0
- package/src/cards/gist.ts +169 -0
- package/src/cards/index.ts +21 -0
- package/src/cards/options.ts +18 -0
- package/src/cards/repo.ts +376 -0
- package/src/cards/stats.ts +615 -0
- package/src/cards/top-languages.ts +1077 -0
- package/src/cards/wakatime.ts +501 -0
- package/src/common/Card.ts +364 -0
- package/src/common/I18n.ts +51 -0
- package/src/common/color.ts +296 -0
- package/src/common/config.ts +118 -0
- package/src/common/constants.ts +12 -0
- package/src/common/date.ts +34 -0
- package/src/common/error.ts +163 -0
- package/src/common/fmt.ts +86 -0
- package/src/common/html.ts +17 -0
- package/src/common/http.ts +98 -0
- package/src/common/icons.ts +80 -0
- package/src/common/languageColors.json +678 -0
- package/src/common/languageColors.ts +19 -0
- package/src/common/log.ts +12 -0
- package/src/common/ops.ts +145 -0
- package/src/common/render.ts +641 -0
- package/src/common/retryer.ts +111 -0
- package/src/fetchers/gist.ts +82 -0
- package/src/fetchers/index.ts +25 -0
- package/src/fetchers/repo.ts +140 -0
- package/src/fetchers/stats.ts +742 -0
- package/src/fetchers/top-languages.ts +134 -0
- package/src/fetchers/types.ts +136 -0
- package/src/fetchers/wakatime.ts +56 -0
- package/src/graphql/contributionsDocument.ts +44 -0
- package/src/graphql/generated/common.ts +26 -0
- package/src/graphql/generated/gist.ts +56 -0
- package/src/graphql/generated/repo.ts +79 -0
- package/src/graphql/generated/stats.ts +180 -0
- package/src/graphql/generated/top-languages.ts +66 -0
- package/src/graphql/graphqlDocument.ts +25 -0
- package/src/graphql/queries/gist.graphql +25 -0
- package/src/graphql/queries/repo.graphql +28 -0
- package/src/graphql/queries/stats.graphql +113 -0
- package/src/graphql/queries/top-languages.graphql +27 -0
- package/src/graphql/reposContributedToDocument.ts +83 -0
- package/src/index.ts +18 -0
- package/src/themes/index.ts +519 -0
- package/src/translations.ts +1169 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { WakaTimeData } from '../fetchers/types.js';
|
|
2
|
+
import type { CardOptions, CommonCardOptions } from './options.js';
|
|
3
|
+
/** Layouts the card can draw; the api validates `layout` against this. */
|
|
4
|
+
declare const WAKATIME_LAYOUTS: readonly ["compact", "normal"];
|
|
5
|
+
type WakaTimeLayout = (typeof WAKATIME_LAYOUTS)[number];
|
|
6
|
+
/** How a language's time is written; the api validates `display_format` against this. */
|
|
7
|
+
declare const DISPLAY_FORMATS: readonly ["time", "percent"];
|
|
8
|
+
type DisplayFormat = (typeof DISPLAY_FORMATS)[number];
|
|
9
|
+
interface WakaTimeOptions extends CommonCardOptions {
|
|
10
|
+
locale: string;
|
|
11
|
+
hide_title: boolean;
|
|
12
|
+
hide: Array<string>;
|
|
13
|
+
card_width: number;
|
|
14
|
+
line_height: number | string;
|
|
15
|
+
hide_progress: boolean;
|
|
16
|
+
custom_title: string;
|
|
17
|
+
layout: WakaTimeLayout;
|
|
18
|
+
langs_count: number;
|
|
19
|
+
display_format: DisplayFormat;
|
|
20
|
+
disable_animations: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Renders WakaTime card.
|
|
24
|
+
*
|
|
25
|
+
* @param stats WakaTime stats.
|
|
26
|
+
* @param options Card options.
|
|
27
|
+
* @returns WakaTime card SVG.
|
|
28
|
+
*/
|
|
29
|
+
declare const renderWakatimeCard: (stats?: Partial<WakaTimeData>, options?: CardOptions<WakaTimeOptions>) => string;
|
|
30
|
+
export { DISPLAY_FORMATS, WAKATIME_LAYOUTS, renderWakatimeCard };
|
|
31
|
+
//# sourceMappingURL=wakatime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wakatime.d.ts","sourceRoot":"","sources":["../../src/cards/wakatime.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,sBAAsB,CAAC;AAGvE,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAWnE,0EAA0E;AAC1E,QAAA,MAAM,gBAAgB,gCAAiC,CAAC;AACxD,KAAK,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAExD,yFAAyF;AACzF,QAAA,MAAM,eAAe,8BAA+B,CAAC;AACrD,KAAK,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtD,UAAU,eAAgB,SAAQ,iBAAiB;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,cAAc,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,aAAa,CAAC;IAC9B,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AA4OD;;;;;;GAMG;AACH,QAAA,MAAM,kBAAkB,GACtB,QAAO,OAAO,CAAC,YAAY,CAAM,EACjC,UAAS,WAAW,CAAC,eAAe,CAAgB,KACnD,MAmNF,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,CAAC"}
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import { Card } from '../common/Card.js';
|
|
2
|
+
import { getLightDarkColors, isPrefixedHexColor } from '../common/color.js';
|
|
3
|
+
import { encodeHTML } from '../common/html.js';
|
|
4
|
+
import { I18n } from '../common/I18n.js';
|
|
5
|
+
import { getLanguageColor } from '../common/languageColors.js';
|
|
6
|
+
import { clampValue, lowercaseTrim } from '../common/ops.js';
|
|
7
|
+
import { createProgressNode, flexLayout } from '../common/render.js';
|
|
8
|
+
import { wakatimeCardLocales } from '../translations.js';
|
|
9
|
+
const DEFAULT_CARD_WIDTH = 495;
|
|
10
|
+
const MIN_CARD_WIDTH = 250;
|
|
11
|
+
const COMPACT_LAYOUT_MIN_WIDTH = 400;
|
|
12
|
+
const DEFAULT_LINE_HEIGHT = 25;
|
|
13
|
+
const PROGRESSBAR_PADDING = 130;
|
|
14
|
+
const HIDDEN_PROGRESSBAR_PADDING = 170;
|
|
15
|
+
const COMPACT_LAYOUT_PROGRESSBAR_PADDING = 25;
|
|
16
|
+
const TOTAL_TEXT_WIDTH = 275;
|
|
17
|
+
/** Layouts the card can draw; the api validates `layout` against this. */
|
|
18
|
+
const WAKATIME_LAYOUTS = ['compact', 'normal'];
|
|
19
|
+
/** How a language's time is written; the api validates `display_format` against this. */
|
|
20
|
+
const DISPLAY_FORMATS = ['time', 'percent'];
|
|
21
|
+
/**
|
|
22
|
+
* Creates the no coding activity SVG node.
|
|
23
|
+
*
|
|
24
|
+
* @param props The function properties.
|
|
25
|
+
* @param props.text No coding activity translated text.
|
|
26
|
+
* @returns No coding activity SVG node string.
|
|
27
|
+
*/
|
|
28
|
+
const noCodingActivityNode = ({ text }) => {
|
|
29
|
+
return `
|
|
30
|
+
<text x="25" y="11" class="stat bold">${encodeHTML(text)}</text>
|
|
31
|
+
`;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Format language value.
|
|
35
|
+
*
|
|
36
|
+
* @param args The function arguments.
|
|
37
|
+
* @param args.lang The language object.
|
|
38
|
+
* @param args.display_format The display format of the language node.
|
|
39
|
+
* @returns The formatted language value.
|
|
40
|
+
*/
|
|
41
|
+
const formatLanguageValue = ({ display_format, lang, }) => {
|
|
42
|
+
return display_format === 'percent' ? `${lang.percent.toFixed(2)} %` : lang.text;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Create compact WakaTime layout.
|
|
46
|
+
*
|
|
47
|
+
* @param args The function arguments.
|
|
48
|
+
* @param args.lang The languages array.
|
|
49
|
+
* @param args.x The x position of the language node.
|
|
50
|
+
* @param args.y The y position of the language node.
|
|
51
|
+
* @param args.display_format The display format of the language node.
|
|
52
|
+
* @returns The compact layout language SVG node.
|
|
53
|
+
*/
|
|
54
|
+
const createCompactLangNode = ({ lang, x, y, display_format, }) => {
|
|
55
|
+
if (!Number.isFinite(x)) {
|
|
56
|
+
throw new Error(`Invalid x: "${x}"`);
|
|
57
|
+
}
|
|
58
|
+
if (!Number.isFinite(y)) {
|
|
59
|
+
throw new Error(`Invalid y: "${y}"`);
|
|
60
|
+
}
|
|
61
|
+
const color = getLanguageColor(lang.name);
|
|
62
|
+
const value = formatLanguageValue({ display_format, lang });
|
|
63
|
+
return `
|
|
64
|
+
<g transform="translate(${x}, ${y})">
|
|
65
|
+
<circle cx="5" cy="6" r="5" fill="${color}" />
|
|
66
|
+
<text data-testid="lang-name" x="15" y="10" class='lang-name'>
|
|
67
|
+
${encodeHTML(lang.name)} - ${encodeHTML(value)}
|
|
68
|
+
</text>
|
|
69
|
+
</g>
|
|
70
|
+
`;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Create WakaTime language text node item.
|
|
74
|
+
*
|
|
75
|
+
* @param args The function arguments.
|
|
76
|
+
* @param args.langs The language objects.
|
|
77
|
+
* @param args.y The y position of the language node.
|
|
78
|
+
* @param args.display_format The display format of the language node.
|
|
79
|
+
* @param args.card_width Width in px of the card.
|
|
80
|
+
* @returns The language text node items.
|
|
81
|
+
*/
|
|
82
|
+
const createLanguageTextNode = ({ langs, y, display_format, card_width, }) => {
|
|
83
|
+
const LEFT_X = 25;
|
|
84
|
+
const RIGHT_X_BASE = 230;
|
|
85
|
+
const rightOffset = (card_width - DEFAULT_CARD_WIDTH) / 2;
|
|
86
|
+
const RIGHT_X = RIGHT_X_BASE + rightOffset;
|
|
87
|
+
return langs.map((lang, index) => {
|
|
88
|
+
const isLeft = index % 2 === 0;
|
|
89
|
+
return createCompactLangNode({
|
|
90
|
+
lang,
|
|
91
|
+
x: isLeft ? LEFT_X : RIGHT_X,
|
|
92
|
+
y: y + DEFAULT_LINE_HEIGHT * Math.floor(index / 2),
|
|
93
|
+
display_format,
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Create WakaTime text item.
|
|
99
|
+
*
|
|
100
|
+
* @param args The function arguments.
|
|
101
|
+
* @param args.id The id of the text node item.
|
|
102
|
+
* @param args.label The label of the text node item.
|
|
103
|
+
* @param args.value The value of the text node item.
|
|
104
|
+
* @param args.index The index of the text node item.
|
|
105
|
+
* @param args.percent Percentage of the text node item.
|
|
106
|
+
* @param args.hideProgress Whether to hide the progress bar.
|
|
107
|
+
* @param args.progressBarWidth The width of the progress bar.
|
|
108
|
+
* @returns The text SVG node.
|
|
109
|
+
*/
|
|
110
|
+
const createTextNode = ({ id, label, value, index, percent, hideProgress, progressBarWidth, }) => {
|
|
111
|
+
if (!Number.isFinite(index)) {
|
|
112
|
+
throw new Error(`Invalid index: "${index}"`);
|
|
113
|
+
}
|
|
114
|
+
if (!Number.isFinite(progressBarWidth)) {
|
|
115
|
+
throw new Error(`Invalid progressBarWidth: "${progressBarWidth}"`);
|
|
116
|
+
}
|
|
117
|
+
const staggerDelay = (index + 3) * 150;
|
|
118
|
+
const cardProgress = hideProgress
|
|
119
|
+
? null
|
|
120
|
+
: createProgressNode({
|
|
121
|
+
x: 110,
|
|
122
|
+
y: 4,
|
|
123
|
+
progress: percent,
|
|
124
|
+
width: progressBarWidth,
|
|
125
|
+
delay: staggerDelay + 300,
|
|
126
|
+
});
|
|
127
|
+
return `
|
|
128
|
+
<g class="stagger" style="animation-delay: ${staggerDelay}ms" transform="translate(25, 0)">
|
|
129
|
+
<text class="stat bold" y="12.5" data-testid="${encodeHTML(id)}">${encodeHTML(label)}:</text>
|
|
130
|
+
<text
|
|
131
|
+
class="stat"
|
|
132
|
+
x="${hideProgress ? HIDDEN_PROGRESSBAR_PADDING : PROGRESSBAR_PADDING + progressBarWidth}"
|
|
133
|
+
y="12.5"
|
|
134
|
+
>${encodeHTML(value)}</text>
|
|
135
|
+
${String(cardProgress)}
|
|
136
|
+
</g>
|
|
137
|
+
`;
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Recalculating percentages so that, compact layout's progress bar does not break when
|
|
141
|
+
* hiding languages.
|
|
142
|
+
*
|
|
143
|
+
* @param languages The languages array.
|
|
144
|
+
*/
|
|
145
|
+
const recalculatePercentages = (languages) => {
|
|
146
|
+
const totalSum = languages.reduce((totalSum, language) => totalSum + language.percent, 0);
|
|
147
|
+
const weight = +(100 / totalSum).toFixed(2);
|
|
148
|
+
languages.forEach((language) => {
|
|
149
|
+
language.percent = +(language.percent * weight).toFixed(2);
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* Retrieves CSS styles for a card.
|
|
154
|
+
*
|
|
155
|
+
* @param colors The colors to use for the card.
|
|
156
|
+
* @param colors.textColor The text color.
|
|
157
|
+
* @returns Card CSS styles.
|
|
158
|
+
*/
|
|
159
|
+
const getStyles = ({ textColor }) => {
|
|
160
|
+
if (!isPrefixedHexColor(textColor)) {
|
|
161
|
+
throw new Error(`Invalid text color: "${textColor}"`);
|
|
162
|
+
}
|
|
163
|
+
return `
|
|
164
|
+
.stat {
|
|
165
|
+
font: 600 14px 'Segoe UI', Ubuntu, "Helvetica Neue", Sans-Serif; fill: ${textColor};
|
|
166
|
+
}
|
|
167
|
+
@supports(-moz-appearance: auto) {
|
|
168
|
+
/* Selector detects Firefox */
|
|
169
|
+
.stat { font-size:12px; }
|
|
170
|
+
}
|
|
171
|
+
.stagger {
|
|
172
|
+
opacity: 0;
|
|
173
|
+
animation: fadeInAnimation 0.3s ease-in-out forwards;
|
|
174
|
+
}
|
|
175
|
+
.not_bold { font-weight: 400 }
|
|
176
|
+
.bold { font-weight: 700 }
|
|
177
|
+
`;
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* Normalize incoming width (string or number) and clamp to minimum.
|
|
181
|
+
*
|
|
182
|
+
* @param args The function arguments.
|
|
183
|
+
* @param args.layout The incoming layout value.
|
|
184
|
+
* @param args.value The incoming width value.
|
|
185
|
+
* @returns The normalized width value.
|
|
186
|
+
*/
|
|
187
|
+
const normalizeCardWidth = ({ value, layout, }) => {
|
|
188
|
+
if (value === undefined || isNaN(value)) {
|
|
189
|
+
return DEFAULT_CARD_WIDTH;
|
|
190
|
+
}
|
|
191
|
+
return Math.max(layout === 'compact' ? COMPACT_LAYOUT_MIN_WIDTH : MIN_CARD_WIDTH, value);
|
|
192
|
+
};
|
|
193
|
+
/**
|
|
194
|
+
* Renders WakaTime card.
|
|
195
|
+
*
|
|
196
|
+
* @param stats WakaTime stats.
|
|
197
|
+
* @param options Card options.
|
|
198
|
+
* @returns WakaTime card SVG.
|
|
199
|
+
*/
|
|
200
|
+
const renderWakatimeCard = (stats = {}, options = { hide: [] }) => {
|
|
201
|
+
let { languages = [] } = stats;
|
|
202
|
+
const { hide_title = false, hide_border = false, card_width, hide, line_height = DEFAULT_LINE_HEIGHT, hide_progress, custom_title, locale, layout, langs_count = languages.length, border_radius, display_format = 'time', disable_animations, } = options;
|
|
203
|
+
const normalizedWidth = normalizeCardWidth({ value: card_width, layout });
|
|
204
|
+
const shouldHideLangs = Array.isArray(hide) && hide.length > 0;
|
|
205
|
+
if (shouldHideLangs) {
|
|
206
|
+
const languagesToHide = new Set(hide.map((lang) => lowercaseTrim(lang)));
|
|
207
|
+
languages = languages.filter((lang) => !languagesToHide.has(lowercaseTrim(lang.name)));
|
|
208
|
+
}
|
|
209
|
+
// Since the percentages are sorted in descending order, we can just
|
|
210
|
+
// slice from the beginning without sorting.
|
|
211
|
+
languages = languages.slice(0, langs_count);
|
|
212
|
+
recalculatePercentages(languages);
|
|
213
|
+
const i18n = new I18n({
|
|
214
|
+
locale,
|
|
215
|
+
translations: wakatimeCardLocales,
|
|
216
|
+
});
|
|
217
|
+
const lheight = parseInt(String(line_height), 10);
|
|
218
|
+
const langsCount = clampValue(langs_count, 1, langs_count);
|
|
219
|
+
const { lightColors, darkColors } = getLightDarkColors(options);
|
|
220
|
+
const filteredLanguages = languages
|
|
221
|
+
.filter((language) => language.hours || language.minutes)
|
|
222
|
+
.slice(0, langsCount);
|
|
223
|
+
// Calculate the card height depending on how many items there are
|
|
224
|
+
// but if rank circle is visible clamp the minimum height to `150`
|
|
225
|
+
let height = Math.max(45 + (filteredLanguages.length + 1) * lheight, 150);
|
|
226
|
+
let finalLayout;
|
|
227
|
+
// RENDER COMPACT LAYOUT
|
|
228
|
+
if (layout === 'compact') {
|
|
229
|
+
const width = normalizedWidth - 5;
|
|
230
|
+
height = 90 + Math.round(filteredLanguages.length / 2) * DEFAULT_LINE_HEIGHT;
|
|
231
|
+
// progressOffset holds the previous language's width and used to offset the next language
|
|
232
|
+
// so that we can stack them one after another, like this: [--][----][---]
|
|
233
|
+
let progressOffset = 0;
|
|
234
|
+
const compactProgressBar = filteredLanguages
|
|
235
|
+
.map((language) => {
|
|
236
|
+
const progress = ((width - COMPACT_LAYOUT_PROGRESSBAR_PADDING) * language.percent) / 100;
|
|
237
|
+
const languageColor = getLanguageColor(language.name);
|
|
238
|
+
const output = `
|
|
239
|
+
<rect
|
|
240
|
+
mask="url(#rect-mask)"
|
|
241
|
+
data-testid="lang-progress"
|
|
242
|
+
x="${progressOffset}"
|
|
243
|
+
y="0"
|
|
244
|
+
width="${progress}"
|
|
245
|
+
height="8"
|
|
246
|
+
fill="${languageColor}"
|
|
247
|
+
/>
|
|
248
|
+
`;
|
|
249
|
+
progressOffset += progress;
|
|
250
|
+
return output;
|
|
251
|
+
})
|
|
252
|
+
.join('');
|
|
253
|
+
finalLayout = `
|
|
254
|
+
<mask id="rect-mask">
|
|
255
|
+
<rect x="${COMPACT_LAYOUT_PROGRESSBAR_PADDING}" y="0" width="${width - 2 * COMPACT_LAYOUT_PROGRESSBAR_PADDING}" height="8" fill="white" rx="5" />
|
|
256
|
+
</mask>
|
|
257
|
+
${compactProgressBar}
|
|
258
|
+
${filteredLanguages.length
|
|
259
|
+
? createLanguageTextNode({
|
|
260
|
+
y: 25,
|
|
261
|
+
langs: filteredLanguages,
|
|
262
|
+
display_format,
|
|
263
|
+
card_width: normalizedWidth,
|
|
264
|
+
}).join('')
|
|
265
|
+
: noCodingActivityNode({
|
|
266
|
+
text: stats.is_coding_activity_visible
|
|
267
|
+
? stats.is_other_usage_visible
|
|
268
|
+
? i18n.t('wakatimecard.nocodingactivity')
|
|
269
|
+
: i18n.t('wakatimecard.nocodedetails')
|
|
270
|
+
: i18n.t('wakatimecard.notpublic'),
|
|
271
|
+
})}
|
|
272
|
+
`;
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
finalLayout = flexLayout({
|
|
276
|
+
items: filteredLanguages.length
|
|
277
|
+
? filteredLanguages.map((language, index) => {
|
|
278
|
+
return createTextNode({
|
|
279
|
+
id: language.name,
|
|
280
|
+
label: language.name,
|
|
281
|
+
value: formatLanguageValue({ display_format, lang: language }),
|
|
282
|
+
index,
|
|
283
|
+
percent: language.percent,
|
|
284
|
+
hideProgress: hide_progress,
|
|
285
|
+
progressBarWidth: normalizedWidth - TOTAL_TEXT_WIDTH,
|
|
286
|
+
});
|
|
287
|
+
})
|
|
288
|
+
: [
|
|
289
|
+
noCodingActivityNode({
|
|
290
|
+
text: stats.is_coding_activity_visible
|
|
291
|
+
? stats.is_other_usage_visible
|
|
292
|
+
? i18n.t('wakatimecard.nocodingactivity')
|
|
293
|
+
: i18n.t('wakatimecard.nocodedetails')
|
|
294
|
+
: i18n.t('wakatimecard.notpublic'),
|
|
295
|
+
}),
|
|
296
|
+
],
|
|
297
|
+
gap: lheight,
|
|
298
|
+
direction: 'column',
|
|
299
|
+
}).join('');
|
|
300
|
+
}
|
|
301
|
+
// Get title range text
|
|
302
|
+
let titleText = i18n.t('wakatimecard.title');
|
|
303
|
+
switch (stats.range) {
|
|
304
|
+
case 'last_7_days':
|
|
305
|
+
titleText += ` (${i18n.t('wakatimecard.last7days')})`;
|
|
306
|
+
break;
|
|
307
|
+
case 'last_year':
|
|
308
|
+
titleText += ` (${i18n.t('wakatimecard.lastyear')})`;
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
const card = new Card({
|
|
312
|
+
customTitle: custom_title,
|
|
313
|
+
defaultTitle: titleText,
|
|
314
|
+
width: normalizedWidth,
|
|
315
|
+
height,
|
|
316
|
+
border_radius,
|
|
317
|
+
colors: { light: lightColors, dark: darkColors },
|
|
318
|
+
});
|
|
319
|
+
if (disable_animations) {
|
|
320
|
+
card.disableAnimations();
|
|
321
|
+
}
|
|
322
|
+
card.setHideBorder(hide_border);
|
|
323
|
+
card.setHideTitle(hide_title);
|
|
324
|
+
card.setCSS({
|
|
325
|
+
light: ({ titleColor, textColor }) => `
|
|
326
|
+
${getStyles({ textColor })}
|
|
327
|
+
@keyframes slideInAnimation {
|
|
328
|
+
from {
|
|
329
|
+
width: 0;
|
|
330
|
+
}
|
|
331
|
+
to {
|
|
332
|
+
width: calc(100%-100px);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
@keyframes growWidthAnimation {
|
|
336
|
+
from {
|
|
337
|
+
width: 0;
|
|
338
|
+
}
|
|
339
|
+
to {
|
|
340
|
+
width: 100%;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
.lang-name { font: 400 11px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor} }
|
|
344
|
+
#rect-mask rect{
|
|
345
|
+
animation: slideInAnimation 1s ease-in-out forwards;
|
|
346
|
+
}
|
|
347
|
+
.lang-progress{
|
|
348
|
+
animation: growWidthAnimation 0.6s ease-in-out forwards;
|
|
349
|
+
fill: ${titleColor};
|
|
350
|
+
}
|
|
351
|
+
.progress-background { fill: ${textColor === titleColor ? '#fff0' /* transparent */ : textColor}; }
|
|
352
|
+
`,
|
|
353
|
+
dark: ({ titleColor, textColor }) => `
|
|
354
|
+
${getStyles({ textColor })}
|
|
355
|
+
.lang-name { fill: ${textColor} }
|
|
356
|
+
.lang-progress { fill: ${titleColor}; }
|
|
357
|
+
.progress-background { fill: ${textColor === titleColor ? '#fff0' /* transparent */ : textColor}; }
|
|
358
|
+
`,
|
|
359
|
+
});
|
|
360
|
+
// `role="img"` hides the inner text from assistive tech, so everything the card
|
|
361
|
+
// shows has to be repeated here.
|
|
362
|
+
card.setAccessibilityLabel({
|
|
363
|
+
title: card.title,
|
|
364
|
+
desc: filteredLanguages.length
|
|
365
|
+
? filteredLanguages
|
|
366
|
+
.map((lang) => `${lang.name}: ${formatLanguageValue({ display_format, lang })}`)
|
|
367
|
+
.join(', ')
|
|
368
|
+
: i18n.t('wakatimecard.nocodingactivity'),
|
|
369
|
+
});
|
|
370
|
+
return card.render(`
|
|
371
|
+
<svg x="0" y="0" width="100%">
|
|
372
|
+
${finalLayout}
|
|
373
|
+
</svg>
|
|
374
|
+
`);
|
|
375
|
+
};
|
|
376
|
+
export { DISPLAY_FORMATS, WAKATIME_LAYOUTS, renderWakatimeCard };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { CardColors } from './color.js';
|
|
2
|
+
/**
|
|
3
|
+
* Builds the card CSS for one color scheme from that scheme's resolved colors.
|
|
4
|
+
*/
|
|
5
|
+
type CardCSSBuilder = (colors: CardColors) => string;
|
|
6
|
+
declare class Card {
|
|
7
|
+
width: number;
|
|
8
|
+
height: number;
|
|
9
|
+
hideBorder: boolean;
|
|
10
|
+
hideTitle: boolean;
|
|
11
|
+
border_radius: number;
|
|
12
|
+
colors: {
|
|
13
|
+
light: CardColors;
|
|
14
|
+
dark: CardColors | null;
|
|
15
|
+
};
|
|
16
|
+
title: string;
|
|
17
|
+
css: string;
|
|
18
|
+
darkCss: string;
|
|
19
|
+
paddingX: number;
|
|
20
|
+
paddingY: number;
|
|
21
|
+
titlePrefixIcon: string | undefined;
|
|
22
|
+
animations: boolean;
|
|
23
|
+
a11yTitle: string;
|
|
24
|
+
a11yDesc: string;
|
|
25
|
+
/**
|
|
26
|
+
* Creates a new card instance.
|
|
27
|
+
*
|
|
28
|
+
* The caller must ensure that the passed `titlePrefixIcon` is properly sanitized!
|
|
29
|
+
*
|
|
30
|
+
* @param props Card arguments.
|
|
31
|
+
* @param props.width Card width.
|
|
32
|
+
* @param props.height Card height.
|
|
33
|
+
* @param props.border_radius Card border radius.
|
|
34
|
+
* @param props.colors Card colors for light and dark mode.
|
|
35
|
+
* @param props.colors.light Card colors for light mode.
|
|
36
|
+
* @param props.colors.dark Card colors for dark mode, or `null` when no dark-mode override is needed.
|
|
37
|
+
* @param props.customTitle Card custom title.
|
|
38
|
+
* @param props.defaultTitle Card default title.
|
|
39
|
+
* @param props.titlePrefixIcon Sanitized card title prefix icon.
|
|
40
|
+
*/
|
|
41
|
+
constructor({ width, height, border_radius, colors, customTitle, defaultTitle, titlePrefixIcon, }: {
|
|
42
|
+
width?: number;
|
|
43
|
+
height?: number;
|
|
44
|
+
border_radius?: number | undefined;
|
|
45
|
+
colors?: {
|
|
46
|
+
light: CardColors;
|
|
47
|
+
dark: CardColors | null;
|
|
48
|
+
};
|
|
49
|
+
customTitle?: string | undefined;
|
|
50
|
+
defaultTitle?: string;
|
|
51
|
+
titlePrefixIcon?: string;
|
|
52
|
+
});
|
|
53
|
+
disableAnimations(): void;
|
|
54
|
+
/**
|
|
55
|
+
* @param props The props object.
|
|
56
|
+
* @param props.title Accessibility title.
|
|
57
|
+
* @param props.desc Accessibility description.
|
|
58
|
+
*/
|
|
59
|
+
setAccessibilityLabel({ title, desc }: {
|
|
60
|
+
title: string;
|
|
61
|
+
desc: string;
|
|
62
|
+
}): void;
|
|
63
|
+
/**
|
|
64
|
+
* Sets the card CSS for light and dark mode.
|
|
65
|
+
*
|
|
66
|
+
* Each builder receives the colors of its own color scheme,
|
|
67
|
+
* so a card never handles a missing dark palette itself:
|
|
68
|
+
* `dark` runs only when the card has dark colors, and always with non-null ones.
|
|
69
|
+
*
|
|
70
|
+
* @warning The caller must ensure that the returned CSS strings are properly sanitized!
|
|
71
|
+
*
|
|
72
|
+
* @param props The props object.
|
|
73
|
+
* @param props.light Builds the CSS applied unconditionally (light/default mode).
|
|
74
|
+
* @param props.dark Builds the CSS placed inside a `@media (prefers-color-scheme: dark)` block.
|
|
75
|
+
*/
|
|
76
|
+
setCSS({ light, dark }: {
|
|
77
|
+
light: CardCSSBuilder;
|
|
78
|
+
dark: CardCSSBuilder;
|
|
79
|
+
}): void;
|
|
80
|
+
/**
|
|
81
|
+
* @param value Whether to hide the border or not.
|
|
82
|
+
*/
|
|
83
|
+
setHideBorder(value: boolean): void;
|
|
84
|
+
/**
|
|
85
|
+
* @param value Whether to hide the title or not.
|
|
86
|
+
*/
|
|
87
|
+
setHideTitle(value: boolean): void;
|
|
88
|
+
/**
|
|
89
|
+
* @param text The title to set.
|
|
90
|
+
*/
|
|
91
|
+
setTitle(text: string): void;
|
|
92
|
+
/**
|
|
93
|
+
* @returns The rendered card title.
|
|
94
|
+
*/
|
|
95
|
+
renderTitle(): string;
|
|
96
|
+
/**
|
|
97
|
+
* @returns The rendered card gradient.
|
|
98
|
+
*/
|
|
99
|
+
renderGradient(): string;
|
|
100
|
+
/**
|
|
101
|
+
* Retrieves css animations for a card.
|
|
102
|
+
*
|
|
103
|
+
* @returns Animation css.
|
|
104
|
+
*/
|
|
105
|
+
getAnimations: () => string;
|
|
106
|
+
/**
|
|
107
|
+
* Builds the @media (prefers-color-scheme: dark) CSS block for the card.
|
|
108
|
+
* Returns an empty string when no dark colors are set.
|
|
109
|
+
*/
|
|
110
|
+
private renderDarkMediaBlock;
|
|
111
|
+
/**
|
|
112
|
+
* The caller must ensure that the passed `body` string is properly sanitized!
|
|
113
|
+
*
|
|
114
|
+
* @param body The sanitized inner body of the card.
|
|
115
|
+
* @returns The rendered card.
|
|
116
|
+
*/
|
|
117
|
+
render(body: string): string;
|
|
118
|
+
}
|
|
119
|
+
export { Card };
|
|
120
|
+
export default Card;
|
|
121
|
+
//# sourceMappingURL=Card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Card.d.ts","sourceRoot":"","sources":["../../src/common/Card.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI7C;;GAEG;AACH,KAAK,cAAc,GAAG,CAAC,MAAM,EAAE,UAAU,KAAK,MAAM,CAAC;AAErD,cAAM,IAAI;IACR,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE;QAAE,KAAK,EAAE,UAAU,CAAC;QAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAA;KAAE,CAAC;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;;;;;;;;;;;;OAeG;gBACS,EACV,KAAW,EACX,MAAY,EACZ,aAAmB,EACnB,MAAiD,EACjD,WAAW,EACX,YAAiB,EACjB,eAAe,GAChB,EAAE;QACD,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAEhB,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QACnC,MAAM,CAAC,EAAE;YAAE,KAAK,EAAE,UAAU,CAAC;YAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAA;SAAE,CAAC;QACxD,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QACjC,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B;IAuBD,iBAAiB,IAAI,IAAI;IAIzB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAK7E;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAAE,KAAK,EAAE,cAAc,CAAC;QAAC,IAAI,EAAE,cAAc,CAAA;KAAE,GAAG,IAAI;IAK9E;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAInC;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAUlC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI5B;;OAEG;IACH,WAAW,IAAI,MAAM;IAoCrB;;OAEG;IACH,cAAc,IAAI,MAAM;IAwCxB;;;;OAIG;IACH,aAAa,QAAO,MAAM,CAoBxB;IAEF;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;CAiF7B;AAED,OAAO,EAAE,IAAI,EAAE,CAAC;AAChB,eAAe,IAAI,CAAC"}
|