@stats-forge/github-stats-forge-core 0.0.1 → 0.1.0
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/README.md +0 -10
- package/build/api/api-result.d.ts +6 -7
- package/build/api/api-result.d.ts.map +1 -1
- package/build/api/api-result.js +4 -5
- package/build/api/gist.d.ts +3 -10
- package/build/api/gist.d.ts.map +1 -1
- package/build/api/gist.js +4 -11
- package/build/api/index.d.ts +12 -12
- package/build/api/params.d.ts +11 -8
- package/build/api/params.d.ts.map +1 -1
- package/build/api/params.js +16 -14
- package/build/api/pin.d.ts +3 -19
- package/build/api/pin.d.ts.map +1 -1
- package/build/api/pin.js +6 -22
- package/build/api/stats.d.ts +10 -4
- package/build/api/stats.d.ts.map +1 -1
- package/build/api/stats.js +6 -32
- package/build/api/top-langs.d.ts +12 -6
- package/build/api/top-langs.d.ts.map +1 -1
- package/build/api/top-langs.js +6 -26
- package/build/api/wakatime.d.ts +13 -5
- package/build/api/wakatime.d.ts.map +1 -1
- package/build/api/wakatime.js +4 -21
- package/build/calculateRank.d.ts +0 -9
- package/build/calculateRank.d.ts.map +1 -1
- package/build/calculateRank.js +12 -17
- package/build/cards/gist.d.ts +2 -4
- package/build/cards/gist.d.ts.map +1 -1
- package/build/cards/gist.js +27 -36
- package/build/cards/options.d.ts +1 -1
- package/build/cards/repo.d.ts +2 -4
- package/build/cards/repo.d.ts.map +1 -1
- package/build/cards/repo.js +61 -93
- package/build/cards/stats.d.ts +3 -8
- package/build/cards/stats.d.ts.map +1 -1
- package/build/cards/stats.js +119 -165
- package/build/cards/top-languages.d.ts +5 -31
- package/build/cards/top-languages.d.ts.map +1 -1
- package/build/cards/top-languages.js +176 -384
- package/build/cards/wakatime.d.ts +4 -6
- package/build/cards/wakatime.d.ts.map +1 -1
- package/build/cards/wakatime.js +118 -185
- package/build/common/Card.d.ts +14 -62
- package/build/common/Card.d.ts.map +1 -1
- package/build/common/Card.js +97 -199
- package/build/common/I18n.d.ts +0 -6
- package/build/common/I18n.d.ts.map +1 -1
- package/build/common/I18n.js +3 -6
- package/build/common/color.d.ts +4 -17
- package/build/common/color.d.ts.map +1 -1
- package/build/common/color.js +67 -49
- package/build/common/config.d.ts +4 -14
- package/build/common/config.d.ts.map +1 -1
- package/build/common/config.js +3 -16
- package/build/common/constants.d.ts +4 -2
- package/build/common/constants.d.ts.map +1 -1
- package/build/common/constants.js +3 -1
- package/build/common/date.d.ts +0 -2
- package/build/common/date.d.ts.map +1 -1
- package/build/common/date.js +0 -2
- package/build/common/emojiMap.d.ts +8 -0
- package/build/common/emojiMap.d.ts.map +1 -0
- package/build/common/emojiMap.js +10 -0
- package/build/common/emojiMap.json +1915 -0
- package/build/common/error.d.ts +1 -10
- package/build/common/error.d.ts.map +1 -1
- package/build/common/error.js +1 -10
- package/build/common/fmt.d.ts +3 -15
- package/build/common/fmt.d.ts.map +1 -1
- package/build/common/fmt.js +7 -35
- package/build/common/http.d.ts +2 -7
- package/build/common/http.d.ts.map +1 -1
- package/build/common/http.js +8 -17
- package/build/common/icons.d.ts +18 -20
- package/build/common/icons.d.ts.map +1 -1
- package/build/common/icons.js +103 -67
- package/build/common/languageColors.d.ts +0 -1
- package/build/common/languageColors.d.ts.map +1 -1
- package/build/common/languageColors.js +1 -4
- package/build/common/languageColors.json +18 -2
- package/build/common/ops.d.ts +3 -14
- package/build/common/ops.d.ts.map +1 -1
- package/build/common/ops.js +19 -30
- package/build/common/render.d.ts +28 -82
- package/build/common/render.d.ts.map +1 -1
- package/build/common/render.js +175 -211
- package/build/common/retryer.d.ts +2 -7
- package/build/common/retryer.d.ts.map +1 -1
- package/build/common/retryer.js +4 -11
- package/build/fetchers/gist.d.ts +2 -5
- package/build/fetchers/gist.d.ts.map +1 -1
- package/build/fetchers/gist.js +1 -5
- package/build/fetchers/index.d.ts +12 -12
- package/build/fetchers/repo.d.ts +2 -11
- package/build/fetchers/repo.d.ts.map +1 -1
- package/build/fetchers/repo.js +20 -33
- package/build/fetchers/stats.d.ts +2 -32
- package/build/fetchers/stats.d.ts.map +1 -1
- package/build/fetchers/stats.js +27 -86
- package/build/fetchers/top-languages.d.ts +2 -9
- package/build/fetchers/top-languages.d.ts.map +1 -1
- package/build/fetchers/top-languages.js +15 -31
- package/build/fetchers/types.d.ts +1 -1
- package/build/fetchers/wakatime.d.ts +2 -6
- package/build/fetchers/wakatime.d.ts.map +1 -1
- package/build/fetchers/wakatime.js +1 -5
- package/build/graphql/contributionsDocument.d.ts +3 -3
- package/build/graphql/contributionsDocument.d.ts.map +1 -1
- package/build/graphql/contributionsDocument.js +0 -1
- package/build/graphql/generated/gist.d.ts +1 -1
- package/build/graphql/generated/repo.d.ts +1 -1
- package/build/graphql/generated/stats.d.ts +3 -3
- package/build/graphql/generated/top-languages.d.ts +2 -2
- package/build/graphql/graphqlDocument.d.ts +0 -1
- package/build/graphql/graphqlDocument.d.ts.map +1 -1
- package/build/graphql/graphqlDocument.js +0 -1
- package/build/graphql/reposContributedToDocument.d.ts +4 -5
- package/build/graphql/reposContributedToDocument.d.ts.map +1 -1
- package/build/graphql/reposContributedToDocument.js +0 -2
- package/build/markup/css.d.ts +35 -0
- package/build/markup/css.d.ts.map +1 -0
- package/build/markup/css.js +64 -0
- package/build/markup/element.d.ts +41 -0
- package/build/markup/element.d.ts.map +1 -0
- package/build/markup/element.js +127 -0
- package/build/markup/html.d.ts +13 -0
- package/build/markup/html.d.ts.map +1 -0
- package/build/markup/html.js +27 -0
- package/build/markup/index.d.ts +9 -0
- package/build/markup/index.d.ts.map +1 -0
- package/build/markup/index.js +6 -0
- package/build/markup/serialize.d.ts +16 -0
- package/build/markup/serialize.d.ts.map +1 -0
- package/build/markup/serialize.js +17 -0
- package/build/themes/index.d.ts +332 -333
- package/build/themes/index.d.ts.map +1 -1
- package/build/themes/index.js +1 -1
- package/build/translations.d.ts +2 -6
- package/build/translations.d.ts.map +1 -1
- package/build/translations.js +621 -628
- package/package.json +17 -26
- package/src/api/api-result.ts +10 -9
- package/src/api/gist.ts +11 -18
- package/src/api/index.ts +12 -12
- package/src/api/params.ts +27 -21
- package/src/api/pin.ts +13 -28
- package/src/api/stats.ts +13 -39
- package/src/api/top-langs.ts +13 -33
- package/src/api/wakatime.ts +11 -28
- package/src/calculateRank.ts +12 -23
- package/src/cards/gist.ts +40 -43
- package/src/cards/options.ts +1 -1
- package/src/cards/repo.ts +97 -107
- package/src/cards/stats.ts +165 -184
- package/src/cards/top-languages.ts +297 -413
- package/src/cards/wakatime.ts +193 -221
- package/src/common/Card.ts +165 -217
- package/src/common/I18n.ts +3 -6
- package/src/common/color.ts +80 -57
- package/src/common/config.ts +5 -18
- package/src/common/constants.ts +5 -2
- package/src/common/date.ts +0 -2
- package/src/common/emojiMap.json +1915 -0
- package/src/common/emojiMap.ts +13 -0
- package/src/common/error.ts +2 -11
- package/src/common/fmt.ts +7 -44
- package/src/common/http.ts +9 -15
- package/src/common/icons.ts +117 -42
- package/src/common/languageColors.json +18 -2
- package/src/common/languageColors.ts +1 -4
- package/src/common/ops.ts +26 -34
- package/src/common/render.ts +279 -232
- package/src/common/retryer.ts +8 -15
- package/src/fetchers/gist.ts +8 -12
- package/src/fetchers/index.ts +12 -12
- package/src/fetchers/repo.ts +27 -40
- package/src/fetchers/stats.ts +44 -102
- package/src/fetchers/top-languages.ts +26 -40
- package/src/fetchers/types.ts +1 -1
- package/src/fetchers/wakatime.ts +5 -9
- package/src/graphql/contributionsDocument.ts +7 -5
- package/src/graphql/generated/gist.ts +1 -1
- package/src/graphql/generated/repo.ts +1 -1
- package/src/graphql/generated/stats.ts +2 -2
- package/src/graphql/generated/top-languages.ts +2 -2
- package/src/graphql/graphqlDocument.ts +0 -1
- package/src/graphql/reposContributedToDocument.ts +6 -7
- package/src/markup/css.ts +118 -0
- package/src/markup/element.ts +246 -0
- package/src/markup/html.ts +34 -0
- package/src/markup/index.ts +9 -0
- package/src/markup/serialize.ts +27 -0
- package/src/themes/index.ts +1 -1
- package/src/translations.ts +622 -629
- package/build/cards/index.d.ts +0 -11
- package/build/cards/index.d.ts.map +0 -1
- package/build/cards/index.js +0 -7
- package/build/common/html.d.ts +0 -8
- package/build/common/html.d.ts.map +0 -1
- package/build/common/html.js +0 -14
- package/build/index.d.ts +0 -15
- package/build/index.d.ts.map +0 -1
- package/build/index.js +0 -10
- package/src/_emoji-name-map.d.ts +0 -10
- package/src/_github-username-regex.d.ts +0 -4
- package/src/cards/index.ts +0 -21
- package/src/common/html.ts +0 -17
- package/src/index.ts +0 -18
package/src/api/wakatime.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as z from 'zod/mini';
|
|
2
2
|
|
|
3
|
-
import { DISPLAY_FORMATS, WAKATIME_LAYOUTS, renderWakatimeCard } from '../cards/wakatime.
|
|
4
|
-
import type { CardConfig } from '../common/config.
|
|
5
|
-
import { fetchWakatimeStats } from '../fetchers/wakatime.
|
|
3
|
+
import { DISPLAY_FORMATS, WAKATIME_LAYOUTS, renderWakatimeCard } from '../cards/wakatime.ts';
|
|
4
|
+
import type { CardConfig } from '../common/config.ts';
|
|
5
|
+
import { fetchWakatimeStats } from '../fetchers/wakatime.ts';
|
|
6
6
|
|
|
7
|
-
import type { ApiResult } from './api-result.
|
|
8
|
-
import { errorResult } from './api-result.
|
|
9
|
-
import type { ApiQuery } from './params.
|
|
7
|
+
import type { ApiResult } from './api-result.ts';
|
|
8
|
+
import { errorResult } from './api-result.ts';
|
|
9
|
+
import type { ApiQuery } from './params.ts';
|
|
10
10
|
import {
|
|
11
11
|
booleanParam,
|
|
12
12
|
enumParam,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
parseParams,
|
|
19
19
|
rawParam,
|
|
20
20
|
safeParam,
|
|
21
|
-
} from './params.
|
|
21
|
+
} from './params.ts';
|
|
22
22
|
|
|
23
23
|
/** What the wakatime endpoint accepts, on top of the shared color params. */
|
|
24
24
|
const wakatimeQuery = z.object({
|
|
@@ -47,32 +47,15 @@ type WakatimeApiQuery = ApiQuery<typeof wakatimeQuery>;
|
|
|
47
47
|
*
|
|
48
48
|
* WakaTime needs no GitHub token, so the config is read only for the transport it carries.
|
|
49
49
|
*
|
|
50
|
-
* @param query Raw query params, plus any of the shared color params.
|
|
51
|
-
* @param query.username WakaTime username.
|
|
52
|
-
* @param query.hide_border Whether to hide the card border.
|
|
53
|
-
* @param query.card_width Card width.
|
|
54
|
-
* @param query.line_height Line height between the languages.
|
|
55
|
-
* @param query.hide_title Whether to hide the card title.
|
|
56
|
-
* @param query.hide_progress Whether to hide the progress bars.
|
|
57
|
-
* @param query.custom_title Card title.
|
|
58
|
-
* @param query.locale Language the card is rendered in.
|
|
59
|
-
* @param query.layout How the languages are laid out.
|
|
60
|
-
* @param query.langs_count Number of languages to show.
|
|
61
|
-
* @param query.hide Comma-separated languages to hide.
|
|
62
|
-
* @param query.api_domain WakaTime instance the stats are read from.
|
|
63
|
-
* @param query.border_radius Card border radius.
|
|
64
|
-
* @param query.display_format Whether values are shown as time or percentages.
|
|
65
|
-
* @param query.disable_animations Whether to disable the card animations.
|
|
66
|
-
* @param config Deployment config supplying the transport.
|
|
67
50
|
* @returns The rendered card, or a rendered error.
|
|
68
51
|
*/
|
|
69
52
|
const renderWakatime = async (query: WakatimeApiQuery, config: CardConfig): Promise<ApiResult> => {
|
|
70
53
|
let colors;
|
|
71
54
|
try {
|
|
72
55
|
colors = parseColorParams(query);
|
|
73
|
-
} catch (
|
|
56
|
+
} catch (error) {
|
|
74
57
|
// A rejected color cannot be used to draw its own error card.
|
|
75
|
-
return errorResult(
|
|
58
|
+
return errorResult(error);
|
|
76
59
|
}
|
|
77
60
|
|
|
78
61
|
try {
|
|
@@ -115,8 +98,8 @@ const renderWakatime = async (query: WakatimeApiQuery, config: CardConfig): Prom
|
|
|
115
98
|
disable_animations,
|
|
116
99
|
}),
|
|
117
100
|
};
|
|
118
|
-
} catch (
|
|
119
|
-
return errorResult(
|
|
101
|
+
} catch (error) {
|
|
102
|
+
return errorResult(error, colors);
|
|
120
103
|
}
|
|
121
104
|
};
|
|
122
105
|
|
package/src/calculateRank.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Calculates the exponential cdf.
|
|
3
3
|
*
|
|
4
|
-
* @param x The value.
|
|
5
4
|
* @returns The exponential cdf.
|
|
6
5
|
*/
|
|
7
6
|
function exponential_cdf(x: number): number {
|
|
@@ -11,7 +10,6 @@ function exponential_cdf(x: number): number {
|
|
|
11
10
|
/**
|
|
12
11
|
* Calculates the log normal cdf.
|
|
13
12
|
*
|
|
14
|
-
* @param x The value.
|
|
15
13
|
* @returns The log normal cdf.
|
|
16
14
|
*/
|
|
17
15
|
function log_normal_cdf(x: number): number {
|
|
@@ -22,15 +20,6 @@ function log_normal_cdf(x: number): number {
|
|
|
22
20
|
/**
|
|
23
21
|
* Calculates the users rank.
|
|
24
22
|
*
|
|
25
|
-
* @param params Parameters on which the user's rank depends.
|
|
26
|
-
* @param params.all_commits Whether `include_all_commits` was used.
|
|
27
|
-
* @param params.commits Number of commits.
|
|
28
|
-
* @param params.prs The number of pull requests.
|
|
29
|
-
* @param params.issues The number of issues.
|
|
30
|
-
* @param params.reviews The number of reviews.
|
|
31
|
-
* @param params.repos Total number of repos (accepted for compatibility, unused in the calculation).
|
|
32
|
-
* @param params.stars The number of stars.
|
|
33
|
-
* @param params.followers The number of followers.
|
|
34
23
|
* @returns The users rank.
|
|
35
24
|
*/
|
|
36
25
|
function calculateRank({
|
|
@@ -51,18 +40,18 @@ function calculateRank({
|
|
|
51
40
|
stars: number;
|
|
52
41
|
followers: number;
|
|
53
42
|
}): { level: string; percentile: number } {
|
|
54
|
-
const COMMITS_MEDIAN = all_commits ? 1000 : 250
|
|
55
|
-
|
|
56
|
-
const PRS_MEDIAN = 50
|
|
57
|
-
|
|
58
|
-
const ISSUES_MEDIAN = 25
|
|
59
|
-
|
|
60
|
-
const REVIEWS_MEDIAN = 2
|
|
61
|
-
|
|
62
|
-
const STARS_MEDIAN = 50
|
|
63
|
-
|
|
64
|
-
const FOLLOWERS_MEDIAN = 10
|
|
65
|
-
|
|
43
|
+
const COMMITS_MEDIAN = all_commits ? 1000 : 250;
|
|
44
|
+
const COMMITS_WEIGHT = 2;
|
|
45
|
+
const PRS_MEDIAN = 50;
|
|
46
|
+
const PRS_WEIGHT = 3;
|
|
47
|
+
const ISSUES_MEDIAN = 25;
|
|
48
|
+
const ISSUES_WEIGHT = 1;
|
|
49
|
+
const REVIEWS_MEDIAN = 2;
|
|
50
|
+
const REVIEWS_WEIGHT = 1;
|
|
51
|
+
const STARS_MEDIAN = 50;
|
|
52
|
+
const STARS_WEIGHT = 4;
|
|
53
|
+
const FOLLOWERS_MEDIAN = 10;
|
|
54
|
+
const FOLLOWERS_WEIGHT = 1;
|
|
66
55
|
|
|
67
56
|
const TOTAL_WEIGHT =
|
|
68
57
|
COMMITS_WEIGHT + PRS_WEIGHT + ISSUES_WEIGHT + REVIEWS_WEIGHT + STARS_WEIGHT + FOLLOWERS_WEIGHT;
|
package/src/cards/gist.ts
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getLightDarkColors } from '../common/color.
|
|
3
|
-
import { kFormatter
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { parseEmojis } from '../common/ops.js';
|
|
1
|
+
import { Card } from '../common/Card.ts';
|
|
2
|
+
import { getLightDarkColors } from '../common/color.ts';
|
|
3
|
+
import { kFormatter } from '../common/fmt.ts';
|
|
4
|
+
import { icons } from '../common/icons.ts';
|
|
5
|
+
import { getLanguageColor } from '../common/languageColors.ts';
|
|
6
|
+
import { parseEmojis } from '../common/ops.ts';
|
|
8
7
|
import {
|
|
9
8
|
countWrappedLines,
|
|
9
|
+
wrapTextMultiline,
|
|
10
10
|
createLanguageNode,
|
|
11
11
|
flexLayout,
|
|
12
12
|
iconWithLabel,
|
|
13
13
|
measureText,
|
|
14
14
|
wrappedTextNode,
|
|
15
15
|
wrappedTextStyles,
|
|
16
|
-
} from '../common/render.
|
|
17
|
-
import type { GistData } from '../fetchers/types.
|
|
16
|
+
} from '../common/render.ts';
|
|
17
|
+
import type { GistData } from '../fetchers/types.ts';
|
|
18
|
+
import type { Child } from '../markup/index.ts';
|
|
19
|
+
import { el, rule } from '../markup/index.ts';
|
|
18
20
|
|
|
19
|
-
import type { CardOptions, CommonCardOptions } from './options.
|
|
21
|
+
import type { CardOptions, CommonCardOptions } from './options.ts';
|
|
20
22
|
|
|
21
23
|
const ICON_SIZE = 16;
|
|
22
24
|
const CARD_DEFAULT_WIDTH = 400;
|
|
@@ -35,8 +37,6 @@ interface GistCardOptions extends CommonCardOptions {
|
|
|
35
37
|
/**
|
|
36
38
|
* Render gist card.
|
|
37
39
|
*
|
|
38
|
-
* @param gistData Gist data.
|
|
39
|
-
* @param options Gist card options.
|
|
40
40
|
* @returns Gist card.
|
|
41
41
|
*/
|
|
42
42
|
const renderGistCard = (gistData: GistData, options: CardOptions<GistCardOptions> = {}): string => {
|
|
@@ -54,7 +54,7 @@ const renderGistCard = (gistData: GistData, options: CardOptions<GistCardOptions
|
|
|
54
54
|
const desc = parseEmojis(description || 'No description provided');
|
|
55
55
|
|
|
56
56
|
let descriptionLines: number;
|
|
57
|
-
let descriptionSvg:
|
|
57
|
+
let descriptionSvg: Child;
|
|
58
58
|
if (browser_rendering) {
|
|
59
59
|
// The browser performs the actual text wrapping inside the foreignObject;
|
|
60
60
|
// we only estimate the line count server-side so the SVG can reserve enough
|
|
@@ -86,12 +86,11 @@ const renderGistCard = (gistData: GistData, options: CardOptions<GistCardOptions
|
|
|
86
86
|
linesLimit,
|
|
87
87
|
);
|
|
88
88
|
descriptionLines = multiLineDescription.length;
|
|
89
|
-
descriptionSvg =
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
</text>`;
|
|
89
|
+
descriptionSvg = el(
|
|
90
|
+
'text',
|
|
91
|
+
{ class: 'description', x: X_OFFSET, y: -5 },
|
|
92
|
+
multiLineDescription.map((line) => el('tspan', { dy: '1.2em', x: X_OFFSET }, line)),
|
|
93
|
+
);
|
|
95
94
|
}
|
|
96
95
|
|
|
97
96
|
const lineHeight = descriptionLines > 3 ? 12 : 10;
|
|
@@ -115,7 +114,7 @@ const renderGistCard = (gistData: GistData, options: CardOptions<GistCardOptions
|
|
|
115
114
|
ICON_SIZE + measureText(`${totalForks}`, 12),
|
|
116
115
|
],
|
|
117
116
|
gap: 25,
|
|
118
|
-
})
|
|
117
|
+
});
|
|
119
118
|
|
|
120
119
|
const header = show_owner ? nameWithOwner : name;
|
|
121
120
|
|
|
@@ -130,22 +129,23 @@ const renderGistCard = (gistData: GistData, options: CardOptions<GistCardOptions
|
|
|
130
129
|
});
|
|
131
130
|
|
|
132
131
|
card.setCSS({
|
|
133
|
-
light: ({ textColor, iconColor }) =>
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
.
|
|
148
|
-
|
|
132
|
+
light: ({ textColor, iconColor }) => [
|
|
133
|
+
rule('.description', {
|
|
134
|
+
font: `400 ${DESCRIPTION_FONT_SIZE}px 'Segoe UI', Ubuntu, Sans-Serif`,
|
|
135
|
+
fill: textColor,
|
|
136
|
+
...(browser_rendering ? wrappedTextStyles(textColor) : {}),
|
|
137
|
+
}),
|
|
138
|
+
rule('.gray', { font: "400 12px 'Segoe UI', Ubuntu, Sans-Serif", fill: textColor }),
|
|
139
|
+
rule('.icon', { fill: iconColor }),
|
|
140
|
+
],
|
|
141
|
+
dark: ({ textColor, iconColor }) => [
|
|
142
|
+
rule('.description', {
|
|
143
|
+
fill: textColor,
|
|
144
|
+
...(browser_rendering ? wrappedTextStyles(textColor) : {}),
|
|
145
|
+
}),
|
|
146
|
+
rule('.gray', { fill: textColor }),
|
|
147
|
+
rule('.icon', { fill: iconColor }),
|
|
148
|
+
],
|
|
149
149
|
});
|
|
150
150
|
|
|
151
151
|
card.setHideBorder(hide_border);
|
|
@@ -157,13 +157,10 @@ const renderGistCard = (gistData: GistData, options: CardOptions<GistCardOptions
|
|
|
157
157
|
desc: `${desc}. Language: ${languageName}, Stars: ${totalStars}, Forks: ${totalForks}`,
|
|
158
158
|
});
|
|
159
159
|
|
|
160
|
-
return card.render(
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
${starAndForkCount}
|
|
165
|
-
</g>
|
|
166
|
-
`);
|
|
160
|
+
return card.render([
|
|
161
|
+
descriptionSvg,
|
|
162
|
+
el('g', { transform: `translate(30, ${height - 75})` }, starAndForkCount),
|
|
163
|
+
]);
|
|
167
164
|
};
|
|
168
165
|
|
|
169
166
|
export { renderGistCard };
|
package/src/cards/options.ts
CHANGED
package/src/cards/repo.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { Card } from '../common/Card.
|
|
2
|
-
import { getLightDarkColors } from '../common/color.
|
|
3
|
-
import { kFormatter
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { buildSearchFilter, clampValue, parseEmojis } from '../common/ops.js';
|
|
1
|
+
import { Card } from '../common/Card.ts';
|
|
2
|
+
import { getLightDarkColors } from '../common/color.ts';
|
|
3
|
+
import { kFormatter } from '../common/fmt.ts';
|
|
4
|
+
import { I18n } from '../common/I18n.ts';
|
|
5
|
+
import { icons } from '../common/icons.ts';
|
|
6
|
+
import { buildSearchFilter, clampValue, parseEmojis } from '../common/ops.ts';
|
|
8
7
|
import {
|
|
9
8
|
countWrappedLines,
|
|
9
|
+
wrapTextMultiline,
|
|
10
10
|
createLanguageNode,
|
|
11
11
|
createTextNode,
|
|
12
12
|
flexLayout,
|
|
@@ -14,11 +14,13 @@ import {
|
|
|
14
14
|
measureText,
|
|
15
15
|
wrappedTextNode,
|
|
16
16
|
wrappedTextStyles,
|
|
17
|
-
} from '../common/render.
|
|
18
|
-
import type { RepositoryData } from '../fetchers/types.
|
|
19
|
-
import {
|
|
17
|
+
} from '../common/render.ts';
|
|
18
|
+
import type { RepositoryData } from '../fetchers/types.ts';
|
|
19
|
+
import type { Child, MarkupElement } from '../markup/index.ts';
|
|
20
|
+
import { el, rule } from '../markup/index.ts';
|
|
21
|
+
import { repoCardLocales } from '../translations.ts';
|
|
20
22
|
|
|
21
|
-
import type { CardOptions, CommonCardOptions } from './options.
|
|
23
|
+
import type { CardOptions, CommonCardOptions } from './options.ts';
|
|
22
24
|
|
|
23
25
|
const ICON_SIZE = 16;
|
|
24
26
|
const CARD_DEFAULT_WIDTH = 400;
|
|
@@ -42,7 +44,7 @@ interface RepoCardOptions extends CommonCardOptions {
|
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
interface RepoStatItem {
|
|
45
|
-
icon:
|
|
47
|
+
icon: Child;
|
|
46
48
|
label: string;
|
|
47
49
|
value: number | undefined;
|
|
48
50
|
id: string;
|
|
@@ -53,35 +55,34 @@ interface RepoStatItem {
|
|
|
53
55
|
/**
|
|
54
56
|
* Retrieves the repository description and wraps it to fit the card width.
|
|
55
57
|
*
|
|
56
|
-
* @param label The repository description.
|
|
57
|
-
* @param xOffset Horizontal offset of the badge.
|
|
58
58
|
* @returns Wrapped repo description SVG object.
|
|
59
59
|
*/
|
|
60
|
-
const getBadgeSVG = (label: string, xOffset = 0):
|
|
60
|
+
const getBadgeSVG = (label: string, xOffset = 0): MarkupElement => {
|
|
61
61
|
if (!Number.isFinite(xOffset)) {
|
|
62
|
-
throw new
|
|
62
|
+
throw new TypeError(`Invalid xOffset: "${xOffset}"`);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
return
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
65
|
+
return el(
|
|
66
|
+
'g',
|
|
67
|
+
{ 'data-testid': 'badge', class: 'badge', transform: `translate(${320 + xOffset}, -18)` },
|
|
68
|
+
el('rect', { 'stroke-width': 1, width: 70, height: 20, x: -12, y: -14, ry: 10, rx: 10 }),
|
|
69
|
+
el(
|
|
70
|
+
'text',
|
|
71
|
+
{
|
|
72
|
+
x: 23,
|
|
73
|
+
y: -5,
|
|
74
|
+
'alignment-baseline': 'central',
|
|
75
|
+
'dominant-baseline': 'central',
|
|
76
|
+
'text-anchor': 'middle',
|
|
77
|
+
},
|
|
78
|
+
label,
|
|
79
|
+
),
|
|
80
|
+
);
|
|
78
81
|
};
|
|
79
82
|
|
|
80
83
|
/**
|
|
81
84
|
* Renders repository card details.
|
|
82
85
|
*
|
|
83
|
-
* @param repo Repository data.
|
|
84
|
-
* @param options Card options.
|
|
85
86
|
* @returns Repository card SVG object.
|
|
86
87
|
*/
|
|
87
88
|
const renderRepoCard = (
|
|
@@ -121,7 +122,7 @@ const renderRepoCard = (
|
|
|
121
122
|
} = options;
|
|
122
123
|
|
|
123
124
|
const card_width =
|
|
124
|
-
card_width_input && !isNaN(card_width_input)
|
|
125
|
+
card_width_input && !Number.isNaN(card_width_input)
|
|
125
126
|
? card_width_input
|
|
126
127
|
: show.length >= 2
|
|
127
128
|
? CARD_DEFAULT_WIDTH + 30
|
|
@@ -199,16 +200,16 @@ const renderRepoCard = (
|
|
|
199
200
|
}),
|
|
200
201
|
);
|
|
201
202
|
|
|
202
|
-
const extraLHeight = parseInt(String(line_height), 10);
|
|
203
|
+
const extraLHeight = Number.parseInt(String(line_height), 10);
|
|
203
204
|
const lineHeight = 10;
|
|
204
205
|
const header = show_owner ? nameWithOwner : name;
|
|
205
|
-
const langName =
|
|
206
|
-
const langColor =
|
|
206
|
+
const langName = primaryLanguage?.name || 'Unspecified';
|
|
207
|
+
const langColor = primaryLanguage?.color || '#333';
|
|
207
208
|
const desc = parseEmojis(description || 'No description provided');
|
|
208
209
|
const descriptionBoxWidth = card_width - 2 * X_OFFSET;
|
|
209
210
|
|
|
210
211
|
let descriptionLinesCount: number;
|
|
211
|
-
let descriptionSvg:
|
|
212
|
+
let descriptionSvg: Child;
|
|
212
213
|
if (browser_rendering) {
|
|
213
214
|
// The browser performs the actual text wrapping inside the foreignObject;
|
|
214
215
|
// we only estimate the line count server-side so the SVG can reserve enough
|
|
@@ -240,23 +241,21 @@ const renderRepoCard = (
|
|
|
240
241
|
descriptionLinesCount = description_lines_count
|
|
241
242
|
? clampValue(description_lines_count, 1, DESCRIPTION_MAX_LINES)
|
|
242
243
|
: multiLineDescription.length;
|
|
243
|
-
descriptionSvg =
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
</text>`;
|
|
244
|
+
descriptionSvg = el(
|
|
245
|
+
'text',
|
|
246
|
+
{ class: 'description', x: X_OFFSET, y: -5 },
|
|
247
|
+
multiLineDescription.map((line) => el('tspan', { dy: '1.2em', x: X_OFFSET }, line)),
|
|
248
|
+
);
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
-
const extraHeight =
|
|
252
|
-
? -7 + (Math.ceil(statItems.length / 2) + 1) * extraLHeight
|
|
253
|
-
: 0;
|
|
251
|
+
const extraHeight =
|
|
252
|
+
Object.keys(STATS).length > 0 ? -7 + (Math.ceil(statItems.length / 2) + 1) * extraLHeight : 0;
|
|
254
253
|
const height =
|
|
255
254
|
(descriptionLinesCount > 1 ? 120 : 110) + descriptionLinesCount * lineHeight + extraHeight;
|
|
256
255
|
|
|
257
256
|
const { lightColors, darkColors } = getLightDarkColors({ ...options, theme });
|
|
258
257
|
|
|
259
|
-
const svgLanguage = primaryLanguage ? createLanguageNode(langName, langColor) :
|
|
258
|
+
const svgLanguage = primaryLanguage ? createLanguageNode(langName, langColor) : undefined;
|
|
260
259
|
|
|
261
260
|
const totalStars = kFormatter(stargazerCount);
|
|
262
261
|
const totalForks = kFormatter(forkCount);
|
|
@@ -271,27 +270,27 @@ const renderRepoCard = (
|
|
|
271
270
|
ICON_SIZE + measureText(`${totalForks}`, 12),
|
|
272
271
|
],
|
|
273
272
|
gap: 25,
|
|
274
|
-
})
|
|
273
|
+
});
|
|
275
274
|
|
|
276
|
-
const extraRows: Array<
|
|
275
|
+
const extraRows: Array<Child> = [];
|
|
277
276
|
for (let i = 0; i < statItems.length; i += 2) {
|
|
278
277
|
extraRows.push(
|
|
279
278
|
flexLayout({
|
|
280
279
|
items: statItems.slice(i, i + 2),
|
|
281
280
|
gap: 210,
|
|
282
281
|
direction: 'row',
|
|
283
|
-
})
|
|
282
|
+
}),
|
|
284
283
|
);
|
|
285
284
|
}
|
|
286
|
-
const extraItems =
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
285
|
+
const extraItems = el(
|
|
286
|
+
'svg',
|
|
287
|
+
{ x: 0, y: 0 },
|
|
288
|
+
el(
|
|
289
|
+
'g',
|
|
290
|
+
{ transform: `translate(-3, ${height - 52 - extraHeight})` },
|
|
291
|
+
flexLayout({ items: extraRows, gap: extraLHeight, direction: 'column' }),
|
|
292
|
+
),
|
|
293
|
+
);
|
|
295
294
|
|
|
296
295
|
const card = new Card({
|
|
297
296
|
defaultTitle: header.length > 35 ? `${header.slice(0, 35)}...` : header,
|
|
@@ -306,39 +305,36 @@ const renderRepoCard = (
|
|
|
306
305
|
card.setHideBorder(hide_border);
|
|
307
306
|
card.setHideTitle(false);
|
|
308
307
|
card.setCSS({
|
|
309
|
-
light: ({ textColor, iconColor }) =>
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
}
|
|
336
|
-
.
|
|
337
|
-
.
|
|
338
|
-
|
|
339
|
-
.stat { fill: ${textColor} }
|
|
340
|
-
.icon { fill: ${iconColor}; }
|
|
341
|
-
`,
|
|
308
|
+
light: ({ textColor, iconColor }) => [
|
|
309
|
+
rule('.description', {
|
|
310
|
+
font: `400 ${DESCRIPTION_FONT_SIZE}px 'Segoe UI', Ubuntu, Sans-Serif`,
|
|
311
|
+
fill: textColor,
|
|
312
|
+
...(browser_rendering ? wrappedTextStyles(textColor) : {}),
|
|
313
|
+
}),
|
|
314
|
+
rule('.gray', { font: "400 12px 'Segoe UI', Ubuntu, Sans-Serif", fill: textColor }),
|
|
315
|
+
rule('.badge', { font: "600 11px 'Segoe UI', Ubuntu, Sans-Serif" }),
|
|
316
|
+
rule('.badge rect', { opacity: 0.2, stroke: textColor }),
|
|
317
|
+
rule('.badge text', { fill: textColor }),
|
|
318
|
+
rule('.stat', { font: "400 12px 'Segoe UI', Ubuntu, Sans-Serif", fill: textColor }),
|
|
319
|
+
rule('.stagger', {
|
|
320
|
+
opacity: 0,
|
|
321
|
+
animation: 'fadeInAnimation 0.3s ease-in-out forwards',
|
|
322
|
+
}),
|
|
323
|
+
rule('.not_bold', { 'font-weight': 400 }),
|
|
324
|
+
rule('.bold', { 'font-weight': 700 }),
|
|
325
|
+
rule('.icon', { fill: iconColor, display: 'block' }),
|
|
326
|
+
],
|
|
327
|
+
dark: ({ textColor, iconColor }) => [
|
|
328
|
+
rule('.description', {
|
|
329
|
+
fill: textColor,
|
|
330
|
+
...(browser_rendering ? wrappedTextStyles(textColor) : {}),
|
|
331
|
+
}),
|
|
332
|
+
rule('.gray', { fill: textColor }),
|
|
333
|
+
rule('.badge rect', { stroke: textColor }),
|
|
334
|
+
rule('.badge text', { fill: textColor }),
|
|
335
|
+
rule('.stat', { fill: textColor }),
|
|
336
|
+
rule('.icon', { fill: iconColor }),
|
|
337
|
+
],
|
|
342
338
|
});
|
|
343
339
|
|
|
344
340
|
const extraStatLabels = Object.values(STATS)
|
|
@@ -355,22 +351,16 @@ const renderRepoCard = (
|
|
|
355
351
|
desc: [`${desc}.`, primaryLanguage ? langName : '', extraStatLabels].filter(Boolean).join(', '),
|
|
356
352
|
});
|
|
357
353
|
|
|
358
|
-
return card.render(
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
<g transform="translate(30, ${height - 75 - extraHeight})">
|
|
370
|
-
${starAndForkCount}
|
|
371
|
-
</g>
|
|
372
|
-
${extraItems}
|
|
373
|
-
`);
|
|
354
|
+
return card.render([
|
|
355
|
+
isTemplate
|
|
356
|
+
? getBadgeSVG(i18n.t('repocard.template'), card_width - CARD_DEFAULT_WIDTH)
|
|
357
|
+
: isArchived
|
|
358
|
+
? getBadgeSVG(i18n.t('repocard.archived'), card_width - CARD_DEFAULT_WIDTH)
|
|
359
|
+
: undefined,
|
|
360
|
+
descriptionSvg,
|
|
361
|
+
el('g', { transform: `translate(30, ${height - 75 - extraHeight})` }, starAndForkCount),
|
|
362
|
+
extraItems,
|
|
363
|
+
]);
|
|
374
364
|
};
|
|
375
365
|
|
|
376
366
|
export { renderRepoCard };
|