@stats-forge/github-stats-forge-core 0.0.2 → 0.2.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/contributed-to.d.ts +23 -0
- package/build/api/contributed-to.d.ts.map +1 -0
- package/build/api/contributed-to.js +43 -0
- package/build/api/gist.d.ts +8 -22
- package/build/api/gist.d.ts.map +1 -1
- package/build/api/gist.js +14 -36
- package/build/api/handler.d.ts +16 -0
- package/build/api/handler.d.ts.map +1 -0
- package/build/api/handler.js +29 -0
- package/build/api/index.d.ts +13 -12
- package/build/api/index.d.ts.map +1 -1
- package/build/api/index.js +1 -0
- package/build/api/params.d.ts +21 -12
- package/build/api/params.d.ts.map +1 -1
- package/build/api/params.js +41 -19
- package/build/api/pin.d.ts +11 -31
- package/build/api/pin.d.ts.map +1 -1
- package/build/api/pin.js +35 -63
- package/build/api/stats.d.ts +15 -16
- package/build/api/stats.d.ts.map +1 -1
- package/build/api/stats.js +60 -99
- package/build/api/top-langs.d.ts +13 -18
- package/build/api/top-langs.d.ts.map +1 -1
- package/build/api/top-langs.js +35 -72
- package/build/api/wakatime.d.ts +11 -17
- package/build/api/wakatime.d.ts.map +1 -1
- package/build/api/wakatime.js +27 -64
- package/build/calculateRank.d.ts +0 -9
- package/build/calculateRank.d.ts.map +1 -1
- package/build/calculateRank.js +12 -17
- package/build/cards/contributed-to.d.ts +19 -0
- package/build/cards/contributed-to.d.ts.map +1 -0
- package/build/cards/contributed-to.js +242 -0
- package/build/cards/gist.d.ts +3 -4
- package/build/cards/gist.d.ts.map +1 -1
- package/build/cards/gist.js +38 -43
- package/build/cards/options.d.ts +1 -1
- package/build/cards/repo.d.ts +14 -5
- package/build/cards/repo.d.ts.map +1 -1
- package/build/cards/repo.js +93 -103
- package/build/cards/stats.d.ts +18 -11
- package/build/cards/stats.d.ts.map +1 -1
- package/build/cards/stats.js +191 -222
- package/build/cards/top-languages.d.ts +18 -33
- package/build/cards/top-languages.d.ts.map +1 -1
- package/build/cards/top-languages.js +196 -387
- package/build/cards/wakatime.d.ts +17 -8
- package/build/cards/wakatime.d.ts.map +1 -1
- package/build/cards/wakatime.js +133 -187
- package/build/common/Card.d.ts +20 -59
- package/build/common/Card.d.ts.map +1 -1
- package/build/common/Card.js +131 -198
- package/build/common/I18n.d.ts +1 -7
- package/build/common/I18n.d.ts.map +1 -1
- package/build/common/I18n.js +7 -8
- package/build/common/brand.d.ts +76 -0
- package/build/common/brand.d.ts.map +1 -0
- package/build/common/brand.js +73 -0
- 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 +6 -2
- package/build/common/constants.d.ts.map +1 -1
- package/build/common/constants.js +5 -1
- package/build/common/date.d.ts +50 -5
- package/build/common/date.d.ts.map +1 -1
- package/build/common/date.js +104 -4
- 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 +20 -20
- package/build/common/icons.d.ts.map +1 -1
- package/build/common/icons.js +108 -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 +11 -17
- package/build/common/ops.d.ts.map +1 -1
- package/build/common/ops.js +22 -39
- package/build/common/render.d.ts +34 -82
- package/build/common/render.d.ts.map +1 -1
- package/build/common/render.js +225 -259
- 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/contributed-to.d.ts +62 -0
- package/build/fetchers/contributed-to.d.ts.map +1 -0
- package/build/fetchers/contributed-to.js +184 -0
- 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/graphql-error.d.ts +13 -0
- package/build/fetchers/graphql-error.d.ts.map +1 -0
- package/build/fetchers/graphql-error.js +29 -0
- package/build/fetchers/index.d.ts +13 -12
- package/build/fetchers/index.d.ts.map +1 -1
- package/build/fetchers/index.js +1 -0
- 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 +16 -40
- package/build/fetchers/stats.d.ts.map +1 -1
- package/build/fetchers/stats.js +89 -271
- 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 +16 -47
- package/build/fetchers/types.d.ts +25 -1
- package/build/fetchers/types.d.ts.map +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/contributionsCollection.d.ts +9 -0
- package/build/graphql/contributionsCollection.d.ts.map +1 -0
- package/build/graphql/contributionsCollection.js +12 -0
- package/build/graphql/contributionsDocument.d.ts +6 -6
- package/build/graphql/contributionsDocument.d.ts.map +1 -1
- package/build/graphql/contributionsDocument.js +8 -16
- package/build/graphql/generated/contributed-to.d.ts +22 -0
- package/build/graphql/generated/contributed-to.d.ts.map +1 -0
- package/build/graphql/generated/contributed-to.js +11 -0
- 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 +16 -4
- package/build/graphql/generated/stats.d.ts.map +1 -1
- package/build/graphql/generated/stats.js +2 -2
- package/build/graphql/generated/top-languages.d.ts +2 -2
- package/build/graphql/graphqlDocument.d.ts +1 -2
- 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 +11 -7
- 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 +66 -7
- package/build/translations.d.ts.map +1 -1
- package/build/translations.js +686 -629
- package/package.json +17 -26
- package/src/api/api-result.ts +10 -9
- package/src/api/contributed-to.ts +84 -0
- package/src/api/gist.ts +22 -46
- package/src/api/handler.ts +42 -0
- package/src/api/index.ts +13 -12
- package/src/api/params.ts +74 -29
- package/src/api/pin.ts +38 -65
- package/src/api/stats.ts +81 -118
- package/src/api/top-langs.ts +38 -80
- package/src/api/wakatime.ts +35 -73
- package/src/calculateRank.ts +12 -23
- package/src/cards/contributed-to.ts +373 -0
- package/src/cards/gist.ts +55 -49
- package/src/cards/options.ts +1 -1
- package/src/cards/repo.ts +134 -120
- package/src/cards/stats.ts +262 -252
- package/src/cards/top-languages.ts +315 -422
- package/src/cards/wakatime.ts +207 -225
- package/src/common/Card.ts +207 -214
- package/src/common/I18n.ts +7 -8
- package/src/common/brand.ts +109 -0
- package/src/common/color.ts +80 -57
- package/src/common/config.ts +5 -18
- package/src/common/constants.ts +8 -2
- package/src/common/date.ts +135 -5
- 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 +122 -42
- package/src/common/languageColors.json +18 -2
- package/src/common/languageColors.ts +1 -4
- package/src/common/ops.ts +31 -48
- package/src/common/render.ts +334 -284
- package/src/common/retryer.ts +8 -15
- package/src/fetchers/contributed-to.ts +271 -0
- package/src/fetchers/gist.ts +8 -12
- package/src/fetchers/graphql-error.ts +36 -0
- package/src/fetchers/index.ts +15 -12
- package/src/fetchers/repo.ts +27 -40
- package/src/fetchers/stats.ts +157 -366
- package/src/fetchers/top-languages.ts +27 -55
- package/src/fetchers/types.ts +27 -1
- package/src/fetchers/wakatime.ts +5 -9
- package/src/graphql/contributionsCollection.ts +18 -0
- package/src/graphql/contributionsDocument.ts +14 -19
- package/src/graphql/generated/contributed-to.ts +25 -0
- package/src/graphql/generated/gist.ts +1 -1
- package/src/graphql/generated/repo.ts +1 -1
- package/src/graphql/generated/stats.ts +21 -8
- package/src/graphql/generated/top-languages.ts +2 -2
- package/src/graphql/graphqlDocument.ts +1 -2
- package/src/graphql/queries/contributed-to.graphql +8 -0
- package/src/graphql/queries/stats.graphql +14 -2
- package/src/graphql/reposContributedToDocument.ts +16 -15
- 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 +699 -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/build/common/Card.js
CHANGED
|
@@ -1,6 +1,35 @@
|
|
|
1
|
+
import { atRule, cssComment, el, renderMarkup, rule, style } from '../markup/index.js';
|
|
2
|
+
import { ACCENT, firefoxFontSize, font, TITLE_BAND, TITLE_FIREFOX_SIZE } from './brand.js';
|
|
1
3
|
import { getCardColors, isPrefixedHexColor, isValidGradient } from './color.js';
|
|
2
|
-
import { encodeHTML } from './html.js';
|
|
3
4
|
import { flexLayout } from './render.js';
|
|
5
|
+
/** Stops every animation, whether the reader asked or the card did. */
|
|
6
|
+
const NO_MOTION = {
|
|
7
|
+
'animation-duration': '0s !important',
|
|
8
|
+
'animation-delay': '0s !important',
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Retrieves css animations for a card.
|
|
12
|
+
*
|
|
13
|
+
* @returns Animation css.
|
|
14
|
+
*/
|
|
15
|
+
const getAnimations = () => [
|
|
16
|
+
cssComment('Animations'),
|
|
17
|
+
atRule('@keyframes scaleInAnimation', rule('from', { transform: 'translate(-5px, 5px) scale(0)' }), rule('to', { transform: 'translate(-5px, 5px) scale(1)' })),
|
|
18
|
+
atRule('@keyframes fadeInAnimation', rule('from', { opacity: 0 }), rule('to', { opacity: 1 })),
|
|
19
|
+
atRule('@media (prefers-reduced-motion: reduce)', rule('*', NO_MOTION)),
|
|
20
|
+
];
|
|
21
|
+
/** One `linearGradient` definition, built from an angle followed by its stops. */
|
|
22
|
+
const buildGradientDef = (id, bgColor) => {
|
|
23
|
+
const gradients = bgColor.slice(1);
|
|
24
|
+
return el('linearGradient', {
|
|
25
|
+
id,
|
|
26
|
+
gradientTransform: `rotate(${String(bgColor[0])})`,
|
|
27
|
+
gradientUnits: 'userSpaceOnUse',
|
|
28
|
+
}, gradients.map((grad, index) => el('stop', {
|
|
29
|
+
offset: `${(index * 100) / (gradients.length - 1)}%`,
|
|
30
|
+
'stop-color': `#${grad}`,
|
|
31
|
+
})));
|
|
32
|
+
};
|
|
4
33
|
class Card {
|
|
5
34
|
width;
|
|
6
35
|
height;
|
|
@@ -19,32 +48,19 @@ class Card {
|
|
|
19
48
|
a11yDesc;
|
|
20
49
|
/**
|
|
21
50
|
* Creates a new card instance.
|
|
22
|
-
*
|
|
23
|
-
* The caller must ensure that the passed `titlePrefixIcon` is properly sanitized!
|
|
24
|
-
*
|
|
25
|
-
* @param props Card arguments.
|
|
26
|
-
* @param props.width Card width.
|
|
27
|
-
* @param props.height Card height.
|
|
28
|
-
* @param props.border_radius Card border radius.
|
|
29
|
-
* @param props.colors Card colors for light and dark mode.
|
|
30
|
-
* @param props.colors.light Card colors for light mode.
|
|
31
|
-
* @param props.colors.dark Card colors for dark mode, or `null` when no dark-mode override is needed.
|
|
32
|
-
* @param props.customTitle Card custom title.
|
|
33
|
-
* @param props.defaultTitle Card default title.
|
|
34
|
-
* @param props.titlePrefixIcon Sanitized card title prefix icon.
|
|
35
51
|
*/
|
|
36
|
-
constructor({ width = 100, height = 100, border_radius =
|
|
52
|
+
constructor({ width = 100, height = 100, border_radius = 8, colors = { light: getCardColors({}), dark: null }, customTitle, defaultTitle = '', titlePrefixIcon, }) {
|
|
37
53
|
this.width = width;
|
|
38
54
|
this.height = height;
|
|
39
55
|
this.hideBorder = false;
|
|
40
56
|
this.hideTitle = false;
|
|
41
|
-
this.border_radius = parseFloat(String(border_radius));
|
|
57
|
+
this.border_radius = Number.parseFloat(String(border_radius));
|
|
42
58
|
this.colors = colors;
|
|
43
|
-
this.title = customTitle
|
|
44
|
-
this.css =
|
|
45
|
-
this.darkCss =
|
|
59
|
+
this.title = customTitle ?? defaultTitle;
|
|
60
|
+
this.css = [];
|
|
61
|
+
this.darkCss = [];
|
|
46
62
|
this.paddingX = 25;
|
|
47
|
-
this.paddingY =
|
|
63
|
+
this.paddingY = 30;
|
|
48
64
|
this.titlePrefixIcon = titlePrefixIcon;
|
|
49
65
|
this.animations = true;
|
|
50
66
|
this.a11yTitle = '';
|
|
@@ -53,11 +69,6 @@ class Card {
|
|
|
53
69
|
disableAnimations() {
|
|
54
70
|
this.animations = false;
|
|
55
71
|
}
|
|
56
|
-
/**
|
|
57
|
-
* @param props The props object.
|
|
58
|
-
* @param props.title Accessibility title.
|
|
59
|
-
* @param props.desc Accessibility description.
|
|
60
|
-
*/
|
|
61
72
|
setAccessibilityLabel({ title, desc }) {
|
|
62
73
|
this.a11yTitle = title;
|
|
63
74
|
this.a11yDesc = desc;
|
|
@@ -68,26 +79,14 @@ class Card {
|
|
|
68
79
|
* Each builder receives the colors of its own color scheme,
|
|
69
80
|
* so a card never handles a missing dark palette itself:
|
|
70
81
|
* `dark` runs only when the card has dark colors, and always with non-null ones.
|
|
71
|
-
*
|
|
72
|
-
* @warning The caller must ensure that the returned CSS strings are properly sanitized!
|
|
73
|
-
*
|
|
74
|
-
* @param props The props object.
|
|
75
|
-
* @param props.light Builds the CSS applied unconditionally (light/default mode).
|
|
76
|
-
* @param props.dark Builds the CSS placed inside a `@media (prefers-color-scheme: dark)` block.
|
|
77
82
|
*/
|
|
78
83
|
setCSS({ light, dark }) {
|
|
79
84
|
this.css = light(this.colors.light);
|
|
80
|
-
this.darkCss = this.colors.dark ? dark(this.colors.dark) :
|
|
85
|
+
this.darkCss = this.colors.dark ? dark(this.colors.dark) : [];
|
|
81
86
|
}
|
|
82
|
-
/**
|
|
83
|
-
* @param value Whether to hide the border or not.
|
|
84
|
-
*/
|
|
85
87
|
setHideBorder(value) {
|
|
86
88
|
this.hideBorder = value;
|
|
87
89
|
}
|
|
88
|
-
/**
|
|
89
|
-
* @param value Whether to hide the title or not.
|
|
90
|
-
*/
|
|
91
90
|
setHideTitle(value) {
|
|
92
91
|
if (value && !this.hideTitle) {
|
|
93
92
|
this.height -= 30;
|
|
@@ -97,69 +96,61 @@ class Card {
|
|
|
97
96
|
}
|
|
98
97
|
this.hideTitle = value;
|
|
99
98
|
}
|
|
100
|
-
/**
|
|
101
|
-
* @param text The title to set.
|
|
102
|
-
*/
|
|
103
99
|
setTitle(text) {
|
|
104
100
|
this.title = text;
|
|
105
101
|
}
|
|
106
|
-
/**
|
|
107
|
-
* @returns The rendered card title.
|
|
108
|
-
*/
|
|
102
|
+
/** @returns The rendered card title. */
|
|
109
103
|
renderTitle() {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
>
|
|
128
|
-
${String(this.titlePrefixIcon)}
|
|
129
|
-
</svg>
|
|
130
|
-
`;
|
|
131
|
-
return `
|
|
132
|
-
<g
|
|
133
|
-
data-testid="card-title"
|
|
134
|
-
transform="translate(${this.paddingX}, ${this.paddingY})"
|
|
135
|
-
>
|
|
136
|
-
${flexLayout({
|
|
137
|
-
items: [this.titlePrefixIcon ? prefixIcon : '', titleText],
|
|
104
|
+
return el('g', {
|
|
105
|
+
'data-testid': 'card-title',
|
|
106
|
+
transform: `translate(${this.paddingX}, ${this.paddingY})`,
|
|
107
|
+
}, flexLayout({
|
|
108
|
+
items: [
|
|
109
|
+
this.titlePrefixIcon &&
|
|
110
|
+
el('svg', {
|
|
111
|
+
class: 'title-icon',
|
|
112
|
+
x: 0,
|
|
113
|
+
y: -13,
|
|
114
|
+
viewBox: '0 0 16 16',
|
|
115
|
+
version: '1.1',
|
|
116
|
+
width: 16,
|
|
117
|
+
height: 16,
|
|
118
|
+
}, this.titlePrefixIcon),
|
|
119
|
+
el('text', { x: 0, y: 0, class: 'header', 'data-testid': 'header' }, this.title),
|
|
120
|
+
],
|
|
138
121
|
gap: 25,
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
|
|
122
|
+
}), el('rect', {
|
|
123
|
+
'data-testid': 'title-accent',
|
|
124
|
+
class: 'title-accent',
|
|
125
|
+
x: 0,
|
|
126
|
+
y: ACCENT.y,
|
|
127
|
+
width: ACCENT.width,
|
|
128
|
+
height: ACCENT.height,
|
|
129
|
+
rx: ACCENT.height / 2,
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
/** Where the body starts, and so where the title band ends. */
|
|
133
|
+
get bodyOffset() {
|
|
134
|
+
return this.hideTitle ? this.paddingX : this.paddingY + 25;
|
|
142
135
|
}
|
|
143
136
|
/**
|
|
144
|
-
*
|
|
137
|
+
* The band behind the title. Its top corners follow the card's own and its bottom
|
|
138
|
+
* ones stay square, so it meets the body as an edge rather than a floating box.
|
|
139
|
+
*
|
|
140
|
+
* @returns The rendered title band.
|
|
145
141
|
*/
|
|
142
|
+
renderTitleBand() {
|
|
143
|
+
const height = this.bodyOffset - TITLE_BAND.gap;
|
|
144
|
+
const innerWidth = this.width - 1;
|
|
145
|
+
const r = Math.min(this.border_radius, height, innerWidth / 2);
|
|
146
|
+
return el('path', {
|
|
147
|
+
'data-testid': 'title-band',
|
|
148
|
+
class: 'title-band',
|
|
149
|
+
d: `M0.5 ${0.5 + r}a${r} ${r} 0 0 1 ${r} ${-r}h${innerWidth - 2 * r}a${r} ${r} 0 0 1 ${r} ${r}v${height - r - 0.5}h${-innerWidth}z`,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
/** @returns The card's gradient definitions, or nothing when no color is a gradient. */
|
|
146
153
|
renderGradient() {
|
|
147
|
-
const buildGradientDef = (id, bgColor) => {
|
|
148
|
-
const gradients = bgColor.slice(1);
|
|
149
|
-
return `
|
|
150
|
-
<linearGradient
|
|
151
|
-
id="${id}"
|
|
152
|
-
gradientTransform="rotate(${String(bgColor[0])})"
|
|
153
|
-
gradientUnits="userSpaceOnUse"
|
|
154
|
-
>
|
|
155
|
-
${gradients
|
|
156
|
-
.map((grad, index) => {
|
|
157
|
-
const offset = (index * 100) / (gradients.length - 1);
|
|
158
|
-
return `<stop offset="${offset}%" stop-color="#${grad}" />`;
|
|
159
|
-
})
|
|
160
|
-
.join(',')}
|
|
161
|
-
</linearGradient>`;
|
|
162
|
-
};
|
|
163
154
|
if (typeof this.colors.light.bgColor === 'object' &&
|
|
164
155
|
!isValidGradient(this.colors.light.bgColor)) {
|
|
165
156
|
throw new Error(`Invalid gradient: ${this.colors.light.bgColor.join(',')}`);
|
|
@@ -169,66 +160,32 @@ class Card {
|
|
|
169
160
|
!isValidGradient(this.colors.dark.bgColor)) {
|
|
170
161
|
throw new Error(`Invalid dark gradient: ${this.colors.dark.bgColor.join(',')}`);
|
|
171
162
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
163
|
+
const defs = [
|
|
164
|
+
typeof this.colors.light.bgColor === 'object' &&
|
|
165
|
+
buildGradientDef('gradient', this.colors.light.bgColor),
|
|
166
|
+
this.colors.dark &&
|
|
167
|
+
typeof this.colors.dark.bgColor === 'object' &&
|
|
168
|
+
buildGradientDef('gradient-dark', this.colors.dark.bgColor),
|
|
169
|
+
].filter(Boolean);
|
|
170
|
+
return defs.length === 0 ? undefined : el('defs', {}, defs);
|
|
178
171
|
}
|
|
179
|
-
/**
|
|
180
|
-
* Retrieves css animations for a card.
|
|
181
|
-
*
|
|
182
|
-
* @returns Animation css.
|
|
183
|
-
*/
|
|
184
|
-
getAnimations = () => {
|
|
185
|
-
return `
|
|
186
|
-
/* Animations */
|
|
187
|
-
@keyframes scaleInAnimation {
|
|
188
|
-
from {
|
|
189
|
-
transform: translate(-5px, 5px) scale(0);
|
|
190
|
-
}
|
|
191
|
-
to {
|
|
192
|
-
transform: translate(-5px, 5px) scale(1);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
@keyframes fadeInAnimation {
|
|
196
|
-
from {
|
|
197
|
-
opacity: 0;
|
|
198
|
-
}
|
|
199
|
-
to {
|
|
200
|
-
opacity: 1;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
`;
|
|
204
|
-
};
|
|
205
172
|
/**
|
|
206
173
|
* Builds the @media (prefers-color-scheme: dark) CSS block for the card.
|
|
207
|
-
* Returns
|
|
174
|
+
* Returns nothing when no dark colors are set.
|
|
208
175
|
*/
|
|
209
176
|
renderDarkMediaBlock() {
|
|
210
177
|
if (!this.colors.dark) {
|
|
211
|
-
return
|
|
178
|
+
return undefined;
|
|
212
179
|
}
|
|
213
180
|
const bgFill = typeof this.colors.dark.bgColor === 'object'
|
|
214
181
|
? 'url(#gradient-dark)'
|
|
215
182
|
: this.colors.dark.bgColor;
|
|
216
|
-
return
|
|
217
|
-
@media (prefers-color-scheme: dark) {
|
|
218
|
-
.header { fill: ${this.colors.dark.titleColor}; }
|
|
219
|
-
.card-bg { fill: ${bgFill}; stroke: ${this.colors.dark.borderColor}; }
|
|
220
|
-
${this.darkCss}
|
|
221
|
-
}`;
|
|
183
|
+
return atRule('@media (prefers-color-scheme: dark)', rule('.header', { fill: this.colors.dark.titleColor }), rule('.title-icon', { fill: this.colors.dark.iconColor }), rule('.title-accent', { fill: this.colors.dark.iconColor }), rule('.title-band', { fill: this.colors.dark.titleColor }), rule('.card-bg', { fill: bgFill, stroke: this.colors.dark.borderColor }), this.darkCss);
|
|
222
184
|
}
|
|
223
|
-
/**
|
|
224
|
-
* The caller must ensure that the passed `body` string is properly sanitized!
|
|
225
|
-
*
|
|
226
|
-
* @param body The sanitized inner body of the card.
|
|
227
|
-
* @returns The rendered card.
|
|
228
|
-
*/
|
|
185
|
+
/** @returns The rendered card. */
|
|
229
186
|
render(body) {
|
|
230
187
|
if (!Number.isFinite(this.border_radius)) {
|
|
231
|
-
throw new
|
|
188
|
+
throw new TypeError(`Invalid border radius: "${this.border_radius}"`);
|
|
232
189
|
}
|
|
233
190
|
if (!isPrefixedHexColor(this.colors.light.titleColor)) {
|
|
234
191
|
throw new Error(`Invalid title color: "${this.colors.light.titleColor}"`);
|
|
@@ -241,65 +198,41 @@ class Card {
|
|
|
241
198
|
: isPrefixedHexColor(this.colors.light.bgColor))) {
|
|
242
199
|
throw new Error(`Invalid background color: ${String(this.colors.light.bgColor)}`);
|
|
243
200
|
}
|
|
244
|
-
return
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
class="card-bg"
|
|
280
|
-
x="0.5"
|
|
281
|
-
y="0.5"
|
|
282
|
-
rx="${this.border_radius}"
|
|
283
|
-
height="99%"
|
|
284
|
-
stroke="${this.colors.light.borderColor}"
|
|
285
|
-
width="${this.width - 1}"
|
|
286
|
-
fill="${typeof this.colors.light.bgColor === 'object'
|
|
287
|
-
? 'url(#gradient)'
|
|
288
|
-
: this.colors.light.bgColor}"
|
|
289
|
-
stroke-opacity="${this.hideBorder ? 0 : 1}"
|
|
290
|
-
/>
|
|
291
|
-
|
|
292
|
-
${this.hideTitle ? '' : this.renderTitle()}
|
|
293
|
-
|
|
294
|
-
<g
|
|
295
|
-
data-testid="main-card-body"
|
|
296
|
-
transform="translate(0, ${this.hideTitle ? this.paddingX : this.paddingY + 20})"
|
|
297
|
-
>
|
|
298
|
-
${body}
|
|
299
|
-
</g>
|
|
300
|
-
</svg>
|
|
301
|
-
`;
|
|
201
|
+
return renderMarkup(el('svg', {
|
|
202
|
+
width: this.width,
|
|
203
|
+
height: this.height,
|
|
204
|
+
viewBox: `0 0 ${this.width} ${this.height}`,
|
|
205
|
+
fill: 'none',
|
|
206
|
+
xmlns: 'http://www.w3.org/2000/svg',
|
|
207
|
+
role: 'img',
|
|
208
|
+
'aria-labelledby': 'title-id desc-id',
|
|
209
|
+
}, el('title', { id: 'title-id' }, this.a11yTitle), el('desc', { id: 'desc-id' }, this.a11yDesc), style(rule('.header', {
|
|
210
|
+
font: font('semibold', 'title'),
|
|
211
|
+
fill: this.colors.light.titleColor,
|
|
212
|
+
animation: 'fadeInAnimation 0.8s ease-in-out forwards',
|
|
213
|
+
}), cssComment('The icon reads against the title rather than with it, so it keeps its own color.'), rule('.title-icon', {
|
|
214
|
+
fill: this.colors.light.iconColor,
|
|
215
|
+
animation: 'fadeInAnimation 0.8s ease-in-out forwards',
|
|
216
|
+
}), rule('.title-accent', {
|
|
217
|
+
fill: this.colors.light.iconColor,
|
|
218
|
+
animation: 'fadeInAnimation 0.8s ease-in-out forwards',
|
|
219
|
+
}), rule('.title-band', { fill: this.colors.light.titleColor, opacity: TITLE_BAND.opacity }), firefoxFontSize(['.header'], TITLE_FIREFOX_SIZE), this.css, this.renderDarkMediaBlock(), getAnimations(), !this.animations && rule('*', NO_MOTION)), this.renderGradient(), el('rect', {
|
|
220
|
+
'data-testid': 'card-bg',
|
|
221
|
+
class: 'card-bg',
|
|
222
|
+
x: 0.5,
|
|
223
|
+
y: 0.5,
|
|
224
|
+
rx: this.border_radius,
|
|
225
|
+
height: '99%',
|
|
226
|
+
stroke: this.colors.light.borderColor,
|
|
227
|
+
width: this.width - 1,
|
|
228
|
+
fill: typeof this.colors.light.bgColor === 'object'
|
|
229
|
+
? 'url(#gradient)'
|
|
230
|
+
: this.colors.light.bgColor,
|
|
231
|
+
'stroke-opacity': this.hideBorder ? 0 : 1,
|
|
232
|
+
}), !this.hideTitle && this.renderTitleBand(), !this.hideTitle && this.renderTitle(), el('g', {
|
|
233
|
+
'data-testid': 'main-card-body',
|
|
234
|
+
transform: `translate(0, ${this.bodyOffset})`,
|
|
235
|
+
}, body)));
|
|
302
236
|
}
|
|
303
237
|
}
|
|
304
238
|
export { Card };
|
|
305
|
-
export default Card;
|
package/build/common/I18n.d.ts
CHANGED
|
@@ -6,19 +6,13 @@ type TranslationsMap = Record<string, Record<string, string>>;
|
|
|
6
6
|
declare class I18n<Translations extends TranslationsMap = TranslationsMap> {
|
|
7
7
|
locale: string;
|
|
8
8
|
translations: Translations;
|
|
9
|
-
/**
|
|
10
|
-
* @param props Constructor arguments.
|
|
11
|
-
* @param props.locale Locale.
|
|
12
|
-
* @param props.translations Translations.
|
|
13
|
-
*/
|
|
14
9
|
constructor({ locale, translations, }: {
|
|
15
10
|
locale?: string | undefined;
|
|
16
11
|
translations: Translations;
|
|
17
12
|
});
|
|
18
13
|
/**
|
|
19
|
-
* Get translation.
|
|
14
|
+
* Get translation, falling back to the English string when the locale has no entry for the key.
|
|
20
15
|
*
|
|
21
|
-
* @param str String to translate.
|
|
22
16
|
* @returns Translated string.
|
|
23
17
|
*/
|
|
24
18
|
t(str: keyof Translations & string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"I18n.d.ts","sourceRoot":"","sources":["../../src/common/I18n.ts"],"names":[],"mappings":"AAEA,uDAAuD;AACvD,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE9D;;GAEG;AACH,cAAM,IAAI,CAAC,YAAY,SAAS,eAAe,GAAG,eAAe;IAC/D,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,YAAY,CAAC;IAE3B
|
|
1
|
+
{"version":3,"file":"I18n.d.ts","sourceRoot":"","sources":["../../src/common/I18n.ts"],"names":[],"mappings":"AAEA,uDAAuD;AACvD,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE9D;;GAEG;AACH,cAAM,IAAI,CAAC,YAAY,SAAS,eAAe,GAAG,eAAe;IAC/D,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,YAAY,CAAC;IAE3B,YAAY,EACV,MAAM,EACN,YAAY,GACb,EAAE;QAED,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC5B,YAAY,EAAE,YAAY,CAAC;KAC5B,EAGA;IAED;;;;OAIG;IACH,CAAC,CAAC,GAAG,EAAE,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,CAiB1C;CACF;AAED,OAAO,EAAE,IAAI,EAAE,CAAC"}
|
package/build/common/I18n.js
CHANGED
|
@@ -5,27 +5,26 @@ const FALLBACK_LOCALE = 'en';
|
|
|
5
5
|
class I18n {
|
|
6
6
|
locale;
|
|
7
7
|
translations;
|
|
8
|
-
/**
|
|
9
|
-
* @param props Constructor arguments.
|
|
10
|
-
* @param props.locale Locale.
|
|
11
|
-
* @param props.translations Translations.
|
|
12
|
-
*/
|
|
13
8
|
constructor({ locale, translations, }) {
|
|
14
9
|
this.locale = locale || FALLBACK_LOCALE;
|
|
15
10
|
this.translations = translations;
|
|
16
11
|
}
|
|
17
12
|
/**
|
|
18
|
-
* Get translation.
|
|
13
|
+
* Get translation, falling back to the English string when the locale has no entry for the key.
|
|
19
14
|
*
|
|
20
|
-
* @param str String to translate.
|
|
21
15
|
* @returns Translated string.
|
|
22
16
|
*/
|
|
23
17
|
t(str) {
|
|
24
18
|
const translation = this.translations[str];
|
|
19
|
+
// A key the type says is present can still be missing at runtime: a card passes
|
|
20
|
+
// a locale table it built, and `i18n.test.ts` covers exactly that.
|
|
21
|
+
// oxlint-disable-next-line typescript/no-unnecessary-condition
|
|
25
22
|
if (!translation) {
|
|
26
23
|
throw new Error(`${str} Translation string not found`);
|
|
27
24
|
}
|
|
28
|
-
|
|
25
|
+
// A key is written in `en` first and translated afterwards, so a locale the key has
|
|
26
|
+
// not reached yet reads the English string rather than failing the whole card.
|
|
27
|
+
const localized = translation[this.locale] ?? translation[FALLBACK_LOCALE];
|
|
29
28
|
if (!localized) {
|
|
30
29
|
throw new Error(`'${str}' translation not found for locale '${this.locale}'`);
|
|
31
30
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The visual vocabulary every card draws with: one font stack, one type scale,
|
|
3
|
+
* one set of widths and the accent rule that marks a card as this tool's.
|
|
4
|
+
* A card composes from here; it never writes a `font` shorthand or a size of its own.
|
|
5
|
+
*/
|
|
6
|
+
import type { CssChild } from '../markup/index.ts';
|
|
7
|
+
/** The type scale, in px. */
|
|
8
|
+
declare const FONT_SIZE: {
|
|
9
|
+
readonly display: 22;
|
|
10
|
+
readonly title: 18;
|
|
11
|
+
readonly lead: 16;
|
|
12
|
+
readonly body: 14;
|
|
13
|
+
readonly meta: 13;
|
|
14
|
+
readonly small: 12;
|
|
15
|
+
readonly micro: 11;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* The one size off the scale. Firefox is given 15.5px rather than the scale's next step down,
|
|
19
|
+
* because that half pixel is inherited tuning for long titles and nothing here can test the
|
|
20
|
+
* wrapping it protects; it lives with the scale so `brand.ts` still owns every size a card draws.
|
|
21
|
+
*/
|
|
22
|
+
declare const TITLE_FIREFOX_SIZE = 15.5;
|
|
23
|
+
/** `regular` labels, `semibold` the values they label, `bold` the rank glyph alone. */
|
|
24
|
+
declare const FONT_WEIGHT: {
|
|
25
|
+
readonly regular: 400;
|
|
26
|
+
readonly semibold: 600;
|
|
27
|
+
readonly bold: 700;
|
|
28
|
+
};
|
|
29
|
+
type FontSize = keyof typeof FONT_SIZE;
|
|
30
|
+
type FontWeight = keyof typeof FONT_WEIGHT;
|
|
31
|
+
/** @returns The `font` shorthand for one step of the scale. */
|
|
32
|
+
declare const font: (weight: FontWeight, size: FontSize) => string;
|
|
33
|
+
/**
|
|
34
|
+
* Firefox lays Segoe UI out wider than the other engines, so text that fits
|
|
35
|
+
* elsewhere overflows there; each affected selector steps down a size.
|
|
36
|
+
*
|
|
37
|
+
* @returns The `@supports` block that detects Firefox and resizes those selectors.
|
|
38
|
+
*/
|
|
39
|
+
declare const firefoxFontSize: (selectors: Array<string>, size: FontSize | number) => CssChild;
|
|
40
|
+
/**
|
|
41
|
+
* The widths a card may default to. A card picks the step nearest what its layout
|
|
42
|
+
* needs, so cards stacked in a README share an edge instead of forming a ragged one.
|
|
43
|
+
*/
|
|
44
|
+
declare const CARD_WIDTH: {
|
|
45
|
+
readonly compact: 300;
|
|
46
|
+
readonly standard: 400;
|
|
47
|
+
readonly wide: 500;
|
|
48
|
+
};
|
|
49
|
+
/** The tinted band behind every card title: the mark a card is recognized by. */
|
|
50
|
+
declare const TITLE_BAND: {
|
|
51
|
+
/** Enough to read as a band on every theme, little enough to leave the title legible. */
|
|
52
|
+
readonly opacity: 0.08;
|
|
53
|
+
/** Clear air the band leaves between its foot and the first row of the body. */
|
|
54
|
+
readonly gap: 9;
|
|
55
|
+
};
|
|
56
|
+
/** The rule under the title icon, sitting inside the band. */
|
|
57
|
+
declare const ACCENT: {
|
|
58
|
+
readonly width: 32;
|
|
59
|
+
readonly height: 2;
|
|
60
|
+
/** Below the title's descenders, clear of the band's foot. */
|
|
61
|
+
readonly y: 8;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* The title icon each card wears. They are distinct on purpose: with the band
|
|
65
|
+
* and the shared type, the icon is what tells one card from another at a glance.
|
|
66
|
+
*/
|
|
67
|
+
declare const CARD_ICON: {
|
|
68
|
+
contributedTo: import("../markup/element.ts").MarkupElement;
|
|
69
|
+
gist: import("../markup/element.ts").MarkupElement;
|
|
70
|
+
repo: import("../markup/element.ts").MarkupElement;
|
|
71
|
+
stats: import("../markup/element.ts").MarkupElement;
|
|
72
|
+
topLanguages: import("../markup/element.ts").MarkupElement;
|
|
73
|
+
wakatime: import("../markup/element.ts").MarkupElement;
|
|
74
|
+
};
|
|
75
|
+
export { ACCENT, CARD_ICON, CARD_WIDTH, FONT_SIZE, FONT_WEIGHT, firefoxFontSize, font, TITLE_BAND, TITLE_FIREFOX_SIZE, };
|
|
76
|
+
//# sourceMappingURL=brand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brand.d.ts","sourceRoot":"","sources":["../../src/common/brand.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAS,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAO1D,6BAA6B;AAC7B,QAAA,MAAM,SAAS;aACb,OAAO,EAAE,EAAE;aACX,KAAK,EAAE,EAAE;aACT,IAAI,EAAE,EAAE;aACR,IAAI,EAAE,EAAE;aACR,IAAI,EAAE,EAAE;aACR,KAAK,EAAE,EAAE;aACT,KAAK,EAAE,EAAE;CACD,CAAC;AAEX;;;;GAIG;AACH,QAAA,MAAM,kBAAkB,OAAO,CAAC;AAEhC,uFAAuF;AACvF,QAAA,MAAM,WAAW;aACf,OAAO,EAAE,GAAG;aACZ,QAAQ,EAAE,GAAG;aACb,IAAI,EAAE,GAAG;CACD,CAAC;AAEX,KAAK,QAAQ,GAAG,MAAM,OAAO,SAAS,CAAC;AACvC,KAAK,UAAU,GAAG,MAAM,OAAO,WAAW,CAAC;AAE3C,+DAA+D;AAC/D,QAAA,MAAM,IAAI,WAAY,UAAU,QAAQ,QAAQ,KAAG,MAC0B,CAAC;AAE9E;;;;;GAKG;AACH,QAAA,MAAM,eAAe,cAAe,KAAK,CAAC,MAAM,CAAC,QAAQ,QAAQ,GAAG,MAAM,KAAG,QAO5E,CAAC;AAEF;;;GAGG;AACH,QAAA,MAAM,UAAU;aACd,OAAO,EAAE,GAAG;aACZ,QAAQ,EAAE,GAAG;aACb,IAAI,EAAE,GAAG;CACD,CAAC;AAEX,iFAAiF;AACjF,QAAA,MAAM,UAAU;IACd,yFAAyF;aACzF,OAAO,EAAE,IAAI;IACb,gFAAgF;aAChF,GAAG,EAAE,CAAC;CACE,CAAC;AAEX,8DAA8D;AAC9D,QAAA,MAAM,MAAM;aACV,KAAK,EAAE,EAAE;aACT,MAAM,EAAE,CAAC;IACT,8DAA8D;aAC9D,CAAC,EAAE,CAAC;CACI,CAAC;AAEX;;;GAGG;AACH,QAAA,MAAM,SAAS;;;;;;;CAOkB,CAAC;AAElC,OAAO,EACL,MAAM,EACN,SAAS,EACT,UAAU,EACV,SAAS,EACT,WAAW,EACX,eAAe,EACf,IAAI,EACJ,UAAU,EACV,kBAAkB,GACnB,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { atRule, cssComment, rule } from '../markup/index.js';
|
|
2
|
+
import { icons } from './icons.js';
|
|
3
|
+
const FONT_STACK = `'Segoe UI', Ubuntu, "Helvetica Neue", Sans-Serif`;
|
|
4
|
+
/** The type scale, in px. */
|
|
5
|
+
const FONT_SIZE = {
|
|
6
|
+
display: 22,
|
|
7
|
+
title: 18,
|
|
8
|
+
lead: 16,
|
|
9
|
+
body: 14,
|
|
10
|
+
meta: 13,
|
|
11
|
+
small: 12,
|
|
12
|
+
micro: 11,
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* The one size off the scale. Firefox is given 15.5px rather than the scale's next step down,
|
|
16
|
+
* because that half pixel is inherited tuning for long titles and nothing here can test the
|
|
17
|
+
* wrapping it protects; it lives with the scale so `brand.ts` still owns every size a card draws.
|
|
18
|
+
*/
|
|
19
|
+
const TITLE_FIREFOX_SIZE = 15.5;
|
|
20
|
+
/** `regular` labels, `semibold` the values they label, `bold` the rank glyph alone. */
|
|
21
|
+
const FONT_WEIGHT = {
|
|
22
|
+
regular: 400,
|
|
23
|
+
semibold: 600,
|
|
24
|
+
bold: 700,
|
|
25
|
+
};
|
|
26
|
+
/** @returns The `font` shorthand for one step of the scale. */
|
|
27
|
+
const font = (weight, size) => `${String(FONT_WEIGHT[weight])} ${String(FONT_SIZE[size])}px ${FONT_STACK}`;
|
|
28
|
+
/**
|
|
29
|
+
* Firefox lays Segoe UI out wider than the other engines, so text that fits
|
|
30
|
+
* elsewhere overflows there; each affected selector steps down a size.
|
|
31
|
+
*
|
|
32
|
+
* @returns The `@supports` block that detects Firefox and resizes those selectors.
|
|
33
|
+
*/
|
|
34
|
+
const firefoxFontSize = (selectors, size) => {
|
|
35
|
+
const px = typeof size === 'number' ? size : FONT_SIZE[size];
|
|
36
|
+
return atRule('@supports(-moz-appearance: auto)', cssComment('Selector detects Firefox'), selectors.map((selector) => rule(selector, { 'font-size': `${String(px)}px` })));
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* The widths a card may default to. A card picks the step nearest what its layout
|
|
40
|
+
* needs, so cards stacked in a README share an edge instead of forming a ragged one.
|
|
41
|
+
*/
|
|
42
|
+
const CARD_WIDTH = {
|
|
43
|
+
compact: 300,
|
|
44
|
+
standard: 400,
|
|
45
|
+
wide: 500,
|
|
46
|
+
};
|
|
47
|
+
/** The tinted band behind every card title: the mark a card is recognized by. */
|
|
48
|
+
const TITLE_BAND = {
|
|
49
|
+
/** Enough to read as a band on every theme, little enough to leave the title legible. */
|
|
50
|
+
opacity: 0.08,
|
|
51
|
+
/** Clear air the band leaves between its foot and the first row of the body. */
|
|
52
|
+
gap: 9,
|
|
53
|
+
};
|
|
54
|
+
/** The rule under the title icon, sitting inside the band. */
|
|
55
|
+
const ACCENT = {
|
|
56
|
+
width: 32,
|
|
57
|
+
height: 2,
|
|
58
|
+
/** Below the title's descenders, clear of the band's foot. */
|
|
59
|
+
y: 8,
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* The title icon each card wears. They are distinct on purpose: with the band
|
|
63
|
+
* and the shared type, the icon is what tells one card from another at a glance.
|
|
64
|
+
*/
|
|
65
|
+
const CARD_ICON = {
|
|
66
|
+
contributedTo: icons.prs_merged,
|
|
67
|
+
gist: icons.gist,
|
|
68
|
+
repo: icons.repo,
|
|
69
|
+
stats: icons.pulse,
|
|
70
|
+
topLanguages: icons.code,
|
|
71
|
+
wakatime: icons.clock,
|
|
72
|
+
};
|
|
73
|
+
export { ACCENT, CARD_ICON, CARD_WIDTH, FONT_SIZE, FONT_WEIGHT, firefoxFontSize, font, TITLE_BAND, TITLE_FIREFOX_SIZE, };
|