@outs-tand-ing/ui 0.5.7 → 0.6.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/dist/index.js +4 -4
- package/dist/tokens/tokens.d.ts +169 -0
- package/dist/tokens/tokens.d.ts.map +1 -0
- package/package.json +8 -3
- package/src/assets/fonts/livvic/Livvic-Black.ttf +0 -0
- package/src/assets/fonts/livvic/Livvic-Black.woff2 +0 -0
- package/src/assets/fonts/livvic/Livvic-Bold.ttf +0 -0
- package/src/assets/fonts/livvic/Livvic-Bold.woff2 +0 -0
- package/src/assets/fonts/livvic/Livvic-Medium.ttf +0 -0
- package/src/assets/fonts/livvic/Livvic-Medium.woff2 +0 -0
- package/src/assets/fonts/livvic/Livvic-Regular.ttf +0 -0
- package/src/assets/fonts/livvic/Livvic-Regular.woff2 +0 -0
- package/src/assets/fonts/livvic/Livvic-SemiBold.ttf +0 -0
- package/src/assets/fonts/livvic/Livvic-SemiBold.woff2 +0 -0
- package/src/assets/fonts/livvic/OFL.txt +93 -0
- package/src/assets/typography.css +31 -20
- package/src/tokens/generated/Tokens.kt +136 -0
- package/src/tokens/generated/Tokens.swift +120 -0
- package/src/tokens/generated/tokens.css +383 -0
- package/src/tokens/tokens.ts +93 -0
- package/src/assets/fonts/Posterama_1984_W04_Black.ttf +0 -0
package/dist/index.js
CHANGED
|
@@ -29,7 +29,7 @@ function C(e, t, n, r, a, o) {
|
|
|
29
29
|
"text-5xl": n.size === "lg"
|
|
30
30
|
}]) }, "OUTSTANDING", 2);
|
|
31
31
|
}
|
|
32
|
-
var w = /*#__PURE__*/ S(x, [["render", C], ["__file", "/Users/kemal/Developer/outstanding/
|
|
32
|
+
var w = /*#__PURE__*/ S(x, [["render", C], ["__file", "/Users/kemal/Developer/outstanding/ws/design-tokens/outs/ui/src/components/BrandLogo.vue"]]), T = {
|
|
33
33
|
squircle: {
|
|
34
34
|
width: 100,
|
|
35
35
|
height: 100,
|
|
@@ -269,7 +269,7 @@ function L(t, n, o, s, l, f) {
|
|
|
269
269
|
var R = /*#__PURE__*/ S(O, [
|
|
270
270
|
["render", L],
|
|
271
271
|
["__scopeId", "data-v-00a84a8e"],
|
|
272
|
-
["__file", "/Users/kemal/Developer/outstanding/
|
|
272
|
+
["__file", "/Users/kemal/Developer/outstanding/ws/design-tokens/outs/ui/src/components/SVGShape.vue"]
|
|
273
273
|
]), z = /*@__PURE__*/ s({
|
|
274
274
|
__name: "AccessWrapper",
|
|
275
275
|
props: {
|
|
@@ -325,7 +325,7 @@ function K(e, t, s, c, l, u) {
|
|
|
325
325
|
}, null, -1), a("div", G, [_(e.$slots, "footer")])], 512)
|
|
326
326
|
]);
|
|
327
327
|
}
|
|
328
|
-
var q = /*#__PURE__*/ S(z, [["render", K], ["__file", "/Users/kemal/Developer/outstanding/
|
|
328
|
+
var q = /*#__PURE__*/ S(z, [["render", K], ["__file", "/Users/kemal/Developer/outstanding/ws/design-tokens/outs/ui/src/components/AccessWrapper.vue"]]), J = /*@__PURE__*/ s({
|
|
329
329
|
__name: "ScrollableArea",
|
|
330
330
|
props: {
|
|
331
331
|
axis: {
|
|
@@ -407,7 +407,7 @@ function Y(e, t, n, o, s, c) {
|
|
|
407
407
|
}, null, 6))
|
|
408
408
|
], 2);
|
|
409
409
|
}
|
|
410
|
-
var X = /*#__PURE__*/ S(J, [["render", Y], ["__file", "/Users/kemal/Developer/outstanding/
|
|
410
|
+
var X = /*#__PURE__*/ S(J, [["render", Y], ["__file", "/Users/kemal/Developer/outstanding/ws/design-tokens/outs/ui/src/components/ScrollableArea.vue"]]);
|
|
411
411
|
//#endregion
|
|
412
412
|
//#region src/utils/svg-parse.ts
|
|
413
413
|
function Z(e) {
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/** A 4pt scale. Native names spell the numeric prefixes out (`3xs` → `xxxs`) to stay valid identifiers. */
|
|
2
|
+
export declare const space: {
|
|
3
|
+
readonly '3xs': 2;
|
|
4
|
+
readonly '2xs': 4;
|
|
5
|
+
readonly xs: 8;
|
|
6
|
+
readonly sm: 12;
|
|
7
|
+
readonly md: 16;
|
|
8
|
+
readonly lg: 24;
|
|
9
|
+
readonly xl: 32;
|
|
10
|
+
readonly '2xl': 48;
|
|
11
|
+
readonly '3xl': 64;
|
|
12
|
+
};
|
|
13
|
+
export declare const radius: {
|
|
14
|
+
readonly sm: 4;
|
|
15
|
+
readonly md: 8;
|
|
16
|
+
readonly lg: 16;
|
|
17
|
+
readonly sheet: 28;
|
|
18
|
+
};
|
|
19
|
+
export declare const motion: {
|
|
20
|
+
readonly duration: {
|
|
21
|
+
readonly fast: 150;
|
|
22
|
+
readonly base: 250;
|
|
23
|
+
readonly slow: 400;
|
|
24
|
+
};
|
|
25
|
+
/** M3's standard easing; reduced motion swaps every transition for an instant or opacity-only change. */
|
|
26
|
+
readonly easing: readonly [0.2, 0, 0, 1];
|
|
27
|
+
};
|
|
28
|
+
/** `Livvic-SemiBold.ttf` → `livvic_semibold`: an Android resource name is lowercase, digits and underscores. */
|
|
29
|
+
export declare const androidFont: (file: string) => string;
|
|
30
|
+
/** Livvic ships as static weights (no variable file, no 800), one file per weight the roles use. */
|
|
31
|
+
export declare const typeface: {
|
|
32
|
+
readonly family: "Livvic";
|
|
33
|
+
readonly dir: "livvic";
|
|
34
|
+
readonly files: {
|
|
35
|
+
readonly 400: "Livvic-Regular.ttf";
|
|
36
|
+
readonly 500: "Livvic-Medium.ttf";
|
|
37
|
+
readonly 600: "Livvic-SemiBold.ttf";
|
|
38
|
+
readonly 700: "Livvic-Bold.ttf";
|
|
39
|
+
readonly 900: "Livvic-Black.ttf";
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
export type IosTextStyle = 'largeTitle' | 'title' | 'title2' | 'title3' | 'headline' | 'body' | 'callout' | 'subheadline' | 'footnote' | 'caption' | 'caption2';
|
|
43
|
+
export type M3Slot = 'displayLarge' | 'displayMedium' | 'displaySmall' | 'headlineLarge' | 'headlineMedium' | 'headlineSmall' | 'titleLarge' | 'titleMedium' | 'titleSmall' | 'bodyLarge' | 'bodyMedium' | 'bodySmall' | 'labelLarge' | 'labelMedium' | 'labelSmall';
|
|
44
|
+
export interface TypeRole {
|
|
45
|
+
/** pt / sp / px at the default text size; native scales it through `ios` and `m3`. */
|
|
46
|
+
size: number;
|
|
47
|
+
weight: number;
|
|
48
|
+
/** A multiple of size. */
|
|
49
|
+
lineHeight: number;
|
|
50
|
+
/** em. */
|
|
51
|
+
tracking: number;
|
|
52
|
+
tabular?: boolean;
|
|
53
|
+
/** Web only: the responsive step `typography.css` already used, where the role had one. */
|
|
54
|
+
clamp?: string;
|
|
55
|
+
ios: IosTextStyle;
|
|
56
|
+
m3: M3Slot;
|
|
57
|
+
}
|
|
58
|
+
export declare const typeRoles: {
|
|
59
|
+
readonly display: {
|
|
60
|
+
readonly size: 40;
|
|
61
|
+
readonly weight: 900;
|
|
62
|
+
readonly lineHeight: 1.1;
|
|
63
|
+
readonly tracking: -0.02;
|
|
64
|
+
readonly clamp: "clamp(2rem, 5vw, 3.5rem)";
|
|
65
|
+
readonly ios: "largeTitle";
|
|
66
|
+
readonly m3: "displaySmall";
|
|
67
|
+
};
|
|
68
|
+
readonly title: {
|
|
69
|
+
readonly size: 28;
|
|
70
|
+
readonly weight: 700;
|
|
71
|
+
readonly lineHeight: 1.15;
|
|
72
|
+
readonly tracking: -0.01;
|
|
73
|
+
readonly clamp: "clamp(1.5rem, 3.5vw, 2.25rem)";
|
|
74
|
+
readonly ios: "title";
|
|
75
|
+
readonly m3: "headlineMedium";
|
|
76
|
+
};
|
|
77
|
+
readonly headline: {
|
|
78
|
+
readonly size: 20;
|
|
79
|
+
readonly weight: 600;
|
|
80
|
+
readonly lineHeight: 1.25;
|
|
81
|
+
readonly tracking: 0;
|
|
82
|
+
readonly clamp: "clamp(1.25rem, 2.5vw, 1.75rem)";
|
|
83
|
+
readonly ios: "title3";
|
|
84
|
+
readonly m3: "titleLarge";
|
|
85
|
+
};
|
|
86
|
+
readonly body: {
|
|
87
|
+
readonly size: 16;
|
|
88
|
+
readonly weight: 400;
|
|
89
|
+
readonly lineHeight: 1.5;
|
|
90
|
+
readonly tracking: 0;
|
|
91
|
+
readonly ios: "body";
|
|
92
|
+
readonly m3: "bodyLarge";
|
|
93
|
+
};
|
|
94
|
+
readonly label: {
|
|
95
|
+
readonly size: 14;
|
|
96
|
+
readonly weight: 500;
|
|
97
|
+
readonly lineHeight: 1.3;
|
|
98
|
+
readonly tracking: 0.01;
|
|
99
|
+
readonly ios: "subheadline";
|
|
100
|
+
readonly m3: "labelLarge";
|
|
101
|
+
};
|
|
102
|
+
readonly caption: {
|
|
103
|
+
readonly size: 12;
|
|
104
|
+
readonly weight: 400;
|
|
105
|
+
readonly lineHeight: 1.35;
|
|
106
|
+
readonly tracking: 0.01;
|
|
107
|
+
readonly ios: "caption";
|
|
108
|
+
readonly m3: "bodySmall";
|
|
109
|
+
};
|
|
110
|
+
readonly numeral: {
|
|
111
|
+
readonly size: 16;
|
|
112
|
+
readonly weight: 500;
|
|
113
|
+
readonly lineHeight: 1.3;
|
|
114
|
+
readonly tracking: 0;
|
|
115
|
+
readonly tabular: true;
|
|
116
|
+
readonly ios: "body";
|
|
117
|
+
readonly m3: "titleMedium";
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
export type SeasonVar = '--color-season' | '--color-season-text' | '--color-accent' | '--color-surface' | '--color-border';
|
|
121
|
+
export type Mode = 'light' | 'dark';
|
|
122
|
+
/**
|
|
123
|
+
* Two tones, one set of names. `season` is the season's own colour at full strength, for the
|
|
124
|
+
* season track (season, round, question). `neutral` is the platform's own light/dark greys
|
|
125
|
+
* carrying a faint wash of the season's accent, for every page outside it.
|
|
126
|
+
*/
|
|
127
|
+
export declare const semantic: {
|
|
128
|
+
readonly season: {
|
|
129
|
+
readonly surface: "--color-season";
|
|
130
|
+
readonly surfaceRaised: "--color-surface";
|
|
131
|
+
readonly separator: "--color-border";
|
|
132
|
+
readonly textPrimary: "--color-season-text";
|
|
133
|
+
readonly accent: "--color-accent";
|
|
134
|
+
};
|
|
135
|
+
readonly neutral: {
|
|
136
|
+
readonly base: {
|
|
137
|
+
readonly light: {
|
|
138
|
+
readonly surface: "#f2f2f7";
|
|
139
|
+
readonly surfaceRaised: "#ffffff";
|
|
140
|
+
readonly separator: "#d1d1d6";
|
|
141
|
+
readonly textPrimary: "#111111";
|
|
142
|
+
};
|
|
143
|
+
readonly dark: {
|
|
144
|
+
readonly surface: "#000000";
|
|
145
|
+
readonly surfaceRaised: "#1c1c1e";
|
|
146
|
+
readonly separator: "#38383a";
|
|
147
|
+
readonly textPrimary: "#f2f2f2";
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
/** Share of the season accent mixed into each neutral base. */
|
|
151
|
+
readonly tint: {
|
|
152
|
+
readonly surface: 0.04;
|
|
153
|
+
readonly surfaceRaised: 0.03;
|
|
154
|
+
readonly separator: 0.08;
|
|
155
|
+
readonly textPrimary: 0;
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
/** text-secondary is text-primary mixed into the surface: this share at the faintest, more where a season needs it to clear 4.5:1. */
|
|
159
|
+
readonly textSecondaryShare: 0.7;
|
|
160
|
+
/** Not a season colour: red-700 / red-400, the reds that clear 4.5:1 on every season surface. */
|
|
161
|
+
readonly danger: {
|
|
162
|
+
readonly light: "#b91c1c";
|
|
163
|
+
readonly dark: "#f87171";
|
|
164
|
+
};
|
|
165
|
+
};
|
|
166
|
+
export declare const semanticRoles: readonly ["textPrimary", "textSecondary", "surface", "surfaceRaised", "separator", "accent", "danger", "onAccent"];
|
|
167
|
+
export type SemanticRole = (typeof semanticRoles)[number];
|
|
168
|
+
export type Tone = 'season' | 'neutral';
|
|
169
|
+
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/tokens/tokens.ts"],"names":[],"mappings":"AAIA,2GAA2G;AAC3G,eAAO,MAAM,KAAK;;;;;;;;;;CAA+F,CAAA;AAEjH,eAAO,MAAM,MAAM;;;;;CAA+C,CAAA;AAElE,eAAO,MAAM,MAAM;;;;;;IAEjB,yGAAyG;;CAEjG,CAAA;AAEV,gHAAgH;AAChH,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,WAAgE,CAAA;AAExG,oGAAoG;AACpG,eAAO,MAAM,QAAQ;;;;;;;;;;CAIX,CAAA;AAEV,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,aAAa,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAA;AAC/J,MAAM,MAAM,MAAM,GAAG,cAAc,GAAG,eAAe,GAAG,cAAc,GAAG,eAAe,GAAG,gBAAgB,GAAG,eAAe,GAAG,YAAY,GAAG,aAAa,GAAG,YAAY,GAAG,WAAW,GAAG,YAAY,GAAG,WAAW,GAAG,YAAY,GAAG,aAAa,GAAG,YAAY,CAAA;AAEpQ,MAAM,WAAW,QAAQ;IACvB,sFAAsF;IACtF,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU;IACV,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,2FAA2F;IAC3F,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,YAAY,CAAA;IACjB,EAAE,EAAE,MAAM,CAAA;CACX;AAED,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAQuB,CAAA;AAG7C,MAAM,MAAM,SAAS,GAAG,gBAAgB,GAAG,qBAAqB,GAAG,gBAAgB,GAAG,iBAAiB,GAAG,gBAAgB,CAAA;AAE1H,MAAM,MAAM,IAAI,GAAG,OAAO,GAAG,MAAM,CAAA;AAEnC;;;;GAIG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;QAajB,+DAA+D;;;;;;;;IAGjE,sIAAsI;;IAEtI,iGAAiG;;;;;CAOlG,CAAA;AAED,eAAO,MAAM,aAAa,oHAAqH,CAAA;AAC/I,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAA;AACzD,MAAM,MAAM,IAAI,GAAG,QAAQ,GAAG,SAAS,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@outs-tand-ing/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Shared Vue components, icons, and design tokens for the outstanding platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"./style.css": "./dist/ui.css",
|
|
17
17
|
"./typography.css": "./src/assets/typography.css",
|
|
18
|
+
"./tokens.css": "./src/tokens/generated/tokens.css",
|
|
18
19
|
"./components.css": "./src/assets/components.css",
|
|
19
20
|
"./seasons/24": {
|
|
20
21
|
"types": "./dist/seasons/season24/index.d.ts",
|
|
@@ -40,7 +41,10 @@
|
|
|
40
41
|
"./seasons/25.css": "./src/seasons/season25/style.css",
|
|
41
42
|
"./seasons/26.css": "./src/seasons/season26/style.css",
|
|
42
43
|
"./seasons/wc26.css": "./src/seasons/fifawc26/style.css",
|
|
43
|
-
"./seasons/27.css": "./src/seasons/season27/style.css"
|
|
44
|
+
"./seasons/27.css": "./src/seasons/season27/style.css",
|
|
45
|
+
"./seasons/-1.css": "./src/seasons/seasonminus1/style.css",
|
|
46
|
+
"./seasons/0.css": "./src/seasons/season0/style.css",
|
|
47
|
+
"./seasons/1.css": "./src/seasons/season1/style.css"
|
|
44
48
|
},
|
|
45
49
|
"files": [
|
|
46
50
|
"dist",
|
|
@@ -62,7 +66,8 @@
|
|
|
62
66
|
"generate:ios:icon": "bun scripts/generate-ios-icon.ts",
|
|
63
67
|
"generate:android:wordmark": "bun scripts/generate-android-wordmark.ts",
|
|
64
68
|
"generate:ios:wordmark": "bun scripts/generate-ios-wordmark.ts",
|
|
65
|
-
"generate:favicon": "bun scripts/generate-favicon.ts"
|
|
69
|
+
"generate:favicon": "bun scripts/generate-favicon.ts",
|
|
70
|
+
"generate:tokens": "bun scripts/generate-tokens.ts"
|
|
66
71
|
},
|
|
67
72
|
"peerDependencies": {
|
|
68
73
|
"vue": "^3.5.0"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Copyright 2019 The Livvic Project Authors (https://github.com/Fonthausen/Livvic)
|
|
2
|
+
|
|
3
|
+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
|
4
|
+
This license is copied below, and is also available with a FAQ at:
|
|
5
|
+
http://scripts.sil.org/OFL
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
-----------------------------------------------------------
|
|
9
|
+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
10
|
+
-----------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
PREAMBLE
|
|
13
|
+
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
14
|
+
development of collaborative font projects, to support the font creation
|
|
15
|
+
efforts of academic and linguistic communities, and to provide a free and
|
|
16
|
+
open framework in which fonts may be shared and improved in partnership
|
|
17
|
+
with others.
|
|
18
|
+
|
|
19
|
+
The OFL allows the licensed fonts to be used, studied, modified and
|
|
20
|
+
redistributed freely as long as they are not sold by themselves. The
|
|
21
|
+
fonts, including any derivative works, can be bundled, embedded,
|
|
22
|
+
redistributed and/or sold with any software provided that any reserved
|
|
23
|
+
names are not used by derivative works. The fonts and derivatives,
|
|
24
|
+
however, cannot be released under any other type of license. The
|
|
25
|
+
requirement for fonts to remain under this license does not apply
|
|
26
|
+
to any document created using the fonts or their derivatives.
|
|
27
|
+
|
|
28
|
+
DEFINITIONS
|
|
29
|
+
"Font Software" refers to the set of files released by the Copyright
|
|
30
|
+
Holder(s) under this license and clearly marked as such. This may
|
|
31
|
+
include source files, build scripts and documentation.
|
|
32
|
+
|
|
33
|
+
"Reserved Font Name" refers to any names specified as such after the
|
|
34
|
+
copyright statement(s).
|
|
35
|
+
|
|
36
|
+
"Original Version" refers to the collection of Font Software components as
|
|
37
|
+
distributed by the Copyright Holder(s).
|
|
38
|
+
|
|
39
|
+
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
40
|
+
or substituting -- in part or in whole -- any of the components of the
|
|
41
|
+
Original Version, by changing formats or by porting the Font Software to a
|
|
42
|
+
new environment.
|
|
43
|
+
|
|
44
|
+
"Author" refers to any designer, engineer, programmer, technical
|
|
45
|
+
writer or other person who contributed to the Font Software.
|
|
46
|
+
|
|
47
|
+
PERMISSION & CONDITIONS
|
|
48
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
49
|
+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
50
|
+
redistribute, and sell modified and unmodified copies of the Font
|
|
51
|
+
Software, subject to the following conditions:
|
|
52
|
+
|
|
53
|
+
1) Neither the Font Software nor any of its individual components,
|
|
54
|
+
in Original or Modified Versions, may be sold by itself.
|
|
55
|
+
|
|
56
|
+
2) Original or Modified Versions of the Font Software may be bundled,
|
|
57
|
+
redistributed and/or sold with any software, provided that each copy
|
|
58
|
+
contains the above copyright notice and this license. These can be
|
|
59
|
+
included either as stand-alone text files, human-readable headers or
|
|
60
|
+
in the appropriate machine-readable metadata fields within text or
|
|
61
|
+
binary files as long as those fields can be easily viewed by the user.
|
|
62
|
+
|
|
63
|
+
3) No Modified Version of the Font Software may use the Reserved Font
|
|
64
|
+
Name(s) unless explicit written permission is granted by the corresponding
|
|
65
|
+
Copyright Holder. This restriction only applies to the primary font name as
|
|
66
|
+
presented to the users.
|
|
67
|
+
|
|
68
|
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
69
|
+
Software shall not be used to promote, endorse or advertise any
|
|
70
|
+
Modified Version, except to acknowledge the contribution(s) of the
|
|
71
|
+
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
72
|
+
permission.
|
|
73
|
+
|
|
74
|
+
5) The Font Software, modified or unmodified, in part or in whole,
|
|
75
|
+
must be distributed entirely under this license, and must not be
|
|
76
|
+
distributed under any other license. The requirement for fonts to
|
|
77
|
+
remain under this license does not apply to any document created
|
|
78
|
+
using the Font Software.
|
|
79
|
+
|
|
80
|
+
TERMINATION
|
|
81
|
+
This license becomes null and void if any of the above conditions are
|
|
82
|
+
not met.
|
|
83
|
+
|
|
84
|
+
DISCLAIMER
|
|
85
|
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
86
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
87
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
88
|
+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
89
|
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
90
|
+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
91
|
+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
92
|
+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
93
|
+
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
1
|
+
/* The type roles for web. Sizes, weights and line heights are the tokens (tokens.css, generated from
|
|
2
|
+
src/tokens/tokens.ts), so this file only says which element takes which role. Import tokens.css
|
|
3
|
+
first. Posterama is the logo's alone and ships here no longer. */
|
|
4
|
+
|
|
5
|
+
@font-face { font-family: 'Livvic'; src: url('./fonts/livvic/Livvic-Regular.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; }
|
|
6
|
+
@font-face { font-family: 'Livvic'; src: url('./fonts/livvic/Livvic-Medium.woff2') format('woff2'); font-weight: 500; font-style: normal; font-display: swap; }
|
|
7
|
+
@font-face { font-family: 'Livvic'; src: url('./fonts/livvic/Livvic-SemiBold.woff2') format('woff2'); font-weight: 600; font-style: normal; font-display: swap; }
|
|
8
|
+
@font-face { font-family: 'Livvic'; src: url('./fonts/livvic/Livvic-Bold.woff2') format('woff2'); font-weight: 700; font-style: normal; font-display: swap; }
|
|
9
|
+
@font-face { font-family: 'Livvic'; src: url('./fonts/livvic/Livvic-Black.woff2') format('woff2'); font-weight: 900; font-style: normal; font-display: swap; }
|
|
8
10
|
|
|
9
11
|
@utility text-trim {
|
|
10
12
|
text-box-trim: trim-both;
|
|
@@ -21,30 +23,39 @@
|
|
|
21
23
|
text-box-edge: cap alphabetic;
|
|
22
24
|
}
|
|
23
25
|
|
|
26
|
+
@utility type-display { font-size: var(--type-display-size); font-weight: var(--type-display-weight); line-height: var(--type-display-line-height); letter-spacing: var(--type-display-tracking); }
|
|
27
|
+
@utility type-title { font-size: var(--type-title-size); font-weight: var(--type-title-weight); line-height: var(--type-title-line-height); letter-spacing: var(--type-title-tracking); }
|
|
28
|
+
@utility type-headline { font-size: var(--type-headline-size); font-weight: var(--type-headline-weight); line-height: var(--type-headline-line-height); letter-spacing: var(--type-headline-tracking); }
|
|
29
|
+
@utility type-body { font-size: var(--type-body-size); font-weight: var(--type-body-weight); line-height: var(--type-body-line-height); letter-spacing: var(--type-body-tracking); }
|
|
30
|
+
@utility type-label { font-size: var(--type-label-size); font-weight: var(--type-label-weight); line-height: var(--type-label-line-height); letter-spacing: var(--type-label-tracking); }
|
|
31
|
+
@utility type-caption { font-size: var(--type-caption-size); font-weight: var(--type-caption-weight); line-height: var(--type-caption-line-height); letter-spacing: var(--type-caption-tracking); }
|
|
32
|
+
@utility type-numeral { font-size: var(--type-numeral-size); font-weight: var(--type-numeral-weight); line-height: var(--type-numeral-line-height); letter-spacing: var(--type-numeral-tracking); font-variant-numeric: tabular-nums; }
|
|
33
|
+
|
|
24
34
|
@layer base {
|
|
35
|
+
body {
|
|
36
|
+
@apply type-body;
|
|
37
|
+
font-family: var(--font-family-base);
|
|
38
|
+
color: var(--ui-text-primary);
|
|
39
|
+
}
|
|
40
|
+
|
|
25
41
|
h1,
|
|
26
42
|
h2,
|
|
27
43
|
h3,
|
|
28
44
|
h4,
|
|
29
45
|
h5,
|
|
30
46
|
h6 {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
font-weight: 900;
|
|
34
|
-
line-height: 1.1;
|
|
35
|
-
letter-spacing: -0.02em;
|
|
36
|
-
transition: color 200ms ease, font-family 200ms ease;
|
|
47
|
+
color: var(--ui-text-primary);
|
|
48
|
+
transition: color var(--motion-base) var(--ease-standard);
|
|
37
49
|
}
|
|
38
50
|
|
|
39
|
-
h1 {
|
|
40
|
-
|
|
41
|
-
h2 { font-size: clamp(1.5rem, 3.5vw, 2.25rem); }
|
|
51
|
+
h1 { @apply type-display; }
|
|
42
52
|
|
|
43
|
-
|
|
53
|
+
h2 { @apply type-title; }
|
|
44
54
|
|
|
45
|
-
|
|
55
|
+
h3,
|
|
56
|
+
h4 { @apply type-headline; }
|
|
46
57
|
|
|
47
|
-
h5 {
|
|
58
|
+
h5 { @apply type-label; }
|
|
48
59
|
|
|
49
|
-
h6 {
|
|
60
|
+
h6 { @apply type-caption; color: var(--ui-text-secondary); }
|
|
50
61
|
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// AUTO-GENERATED — do not edit manually
|
|
2
|
+
// Run: bun run generate:tokens (from ui/)
|
|
3
|
+
// Source: ui/src/tokens/tokens.ts and each ui/src/seasons/<season>/style.css
|
|
4
|
+
package outs.tand.ing.ui.theme
|
|
5
|
+
|
|
6
|
+
import androidx.compose.animation.core.CubicBezierEasing
|
|
7
|
+
import androidx.compose.material3.Typography
|
|
8
|
+
import androidx.compose.runtime.Immutable
|
|
9
|
+
import androidx.compose.ui.graphics.Color
|
|
10
|
+
import androidx.compose.ui.text.TextStyle
|
|
11
|
+
import androidx.compose.ui.text.font.Font
|
|
12
|
+
import androidx.compose.ui.text.font.FontFamily
|
|
13
|
+
import androidx.compose.ui.text.font.FontWeight
|
|
14
|
+
import androidx.compose.ui.unit.dp
|
|
15
|
+
import androidx.compose.ui.unit.em
|
|
16
|
+
import androidx.compose.ui.unit.sp
|
|
17
|
+
import outs.tand.ing.R
|
|
18
|
+
|
|
19
|
+
object Space {
|
|
20
|
+
val xxxs = 2.dp
|
|
21
|
+
val xxs = 4.dp
|
|
22
|
+
val xs = 8.dp
|
|
23
|
+
val sm = 12.dp
|
|
24
|
+
val md = 16.dp
|
|
25
|
+
val lg = 24.dp
|
|
26
|
+
val xl = 32.dp
|
|
27
|
+
val xxl = 48.dp
|
|
28
|
+
val xxxl = 64.dp
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
object Radius {
|
|
32
|
+
val sm = 4.dp
|
|
33
|
+
val md = 8.dp
|
|
34
|
+
val lg = 16.dp
|
|
35
|
+
val sheet = 28.dp
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
object Motion {
|
|
39
|
+
const val FAST_MS = 150
|
|
40
|
+
const val BASE_MS = 250
|
|
41
|
+
const val SLOW_MS = 400
|
|
42
|
+
val standardEasing = CubicBezierEasing(0.2f, 0f, 0f, 1f)
|
|
43
|
+
|
|
44
|
+
/** Reduced motion (the system's "Remove animations") collapses every transition to an instant change. */
|
|
45
|
+
fun duration(ms: Int, reduceMotion: Boolean): Int = if (reduceMotion) 0 else ms
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Livvic, one static file per weight the type roles use. */
|
|
49
|
+
val Livvic = FontFamily(
|
|
50
|
+
Font(R.font.livvic_regular, FontWeight(400)),
|
|
51
|
+
Font(R.font.livvic_medium, FontWeight(500)),
|
|
52
|
+
Font(R.font.livvic_semibold, FontWeight(600)),
|
|
53
|
+
Font(R.font.livvic_bold, FontWeight(700)),
|
|
54
|
+
Font(R.font.livvic_black, FontWeight(900)),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
object TypeRole {
|
|
58
|
+
val display = TextStyle(fontFamily = Livvic, fontWeight = FontWeight(900), fontSize = 40.sp, lineHeight = 44.sp, letterSpacing = (-0.02).em)
|
|
59
|
+
val title = TextStyle(fontFamily = Livvic, fontWeight = FontWeight(700), fontSize = 28.sp, lineHeight = 32.2.sp, letterSpacing = (-0.01).em)
|
|
60
|
+
val headline = TextStyle(fontFamily = Livvic, fontWeight = FontWeight(600), fontSize = 20.sp, lineHeight = 25.sp, letterSpacing = (0).em)
|
|
61
|
+
val body = TextStyle(fontFamily = Livvic, fontWeight = FontWeight(400), fontSize = 16.sp, lineHeight = 24.sp, letterSpacing = (0).em)
|
|
62
|
+
val label = TextStyle(fontFamily = Livvic, fontWeight = FontWeight(500), fontSize = 14.sp, lineHeight = 18.2.sp, letterSpacing = (0.01).em)
|
|
63
|
+
val caption = TextStyle(fontFamily = Livvic, fontWeight = FontWeight(400), fontSize = 12.sp, lineHeight = 16.2.sp, letterSpacing = (0.01).em)
|
|
64
|
+
val numeral = TextStyle(fontFamily = Livvic, fontWeight = FontWeight(500), fontSize = 16.sp, lineHeight = 20.8.sp, letterSpacing = (0).em, fontFeatureSettings = "tnum")
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** The M3 type scale on the roles. A slot no role claims keeps M3's metrics in Livvic. */
|
|
68
|
+
val OutsTypography: Typography = Typography().let { base ->
|
|
69
|
+
Typography(
|
|
70
|
+
displayLarge = base.displayLarge.copy(fontFamily = Livvic),
|
|
71
|
+
displayMedium = base.displayMedium.copy(fontFamily = Livvic),
|
|
72
|
+
displaySmall = TypeRole.display,
|
|
73
|
+
headlineLarge = base.headlineLarge.copy(fontFamily = Livvic),
|
|
74
|
+
headlineMedium = TypeRole.title,
|
|
75
|
+
headlineSmall = base.headlineSmall.copy(fontFamily = Livvic),
|
|
76
|
+
titleLarge = TypeRole.headline,
|
|
77
|
+
titleMedium = TypeRole.numeral,
|
|
78
|
+
titleSmall = base.titleSmall.copy(fontFamily = Livvic),
|
|
79
|
+
bodyLarge = TypeRole.body,
|
|
80
|
+
bodyMedium = base.bodyMedium.copy(fontFamily = Livvic),
|
|
81
|
+
bodySmall = TypeRole.caption,
|
|
82
|
+
labelLarge = TypeRole.label,
|
|
83
|
+
labelMedium = base.labelMedium.copy(fontFamily = Livvic),
|
|
84
|
+
labelSmall = base.labelSmall.copy(fontFamily = Livvic),
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
enum class Tone { SEASON, NEUTRAL }
|
|
89
|
+
|
|
90
|
+
@Immutable
|
|
91
|
+
data class SemanticColor(
|
|
92
|
+
val textPrimary: Color,
|
|
93
|
+
val textSecondary: Color,
|
|
94
|
+
val surface: Color,
|
|
95
|
+
val surfaceRaised: Color,
|
|
96
|
+
val separator: Color,
|
|
97
|
+
val accent: Color,
|
|
98
|
+
val danger: Color,
|
|
99
|
+
val onAccent: Color,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
fun semanticColorFor(shortName: String, tone: Tone, isDark: Boolean = false): SemanticColor = when (Triple(shortName, tone, isDark)) {
|
|
103
|
+
Triple("24", Tone.SEASON, false) -> SemanticColor(textPrimary = Color(0xFF5B21B6), textSecondary = Color(0xFF7E51C4), surface = Color(0xFFEDEAEF), surfaceRaised = Color(0xFFF9F5FF), separator = Color(0xFFDDD0F5), accent = Color(0xFF7C3AED), danger = Color(0xFFB91C1C), onAccent = Color(0xFFFFFFFF))
|
|
104
|
+
Triple("24", Tone.SEASON, true) -> SemanticColor(textPrimary = Color(0xFFD0CCD6), textSecondary = Color(0xFF9B97A1), surface = Color(0xFF1E1A24), surfaceRaised = Color(0xFF130A24), separator = Color(0xFF2E1A52), accent = Color(0xFFA78BFA), danger = Color(0xFFF87171), onAccent = Color(0xFF000000))
|
|
105
|
+
Triple("24", Tone.NEUTRAL, false) -> SemanticColor(textPrimary = Color(0xFF111111), textSecondary = Color(0xFF535256), surface = Color(0xFFEDEBF7), surfaceRaised = Color(0xFFFBF9FE), separator = Color(0xFFCAC5D8), accent = Color(0xFF7C3AED), danger = Color(0xFFB91C1C), onAccent = Color(0xFFFFFFFF))
|
|
106
|
+
Triple("24", Tone.NEUTRAL, true) -> SemanticColor(textPrimary = Color(0xFFF2F2F2), textSecondary = Color(0xFFABABAC), surface = Color(0xFF07060A), surfaceRaised = Color(0xFF201F25), separator = Color(0xFF413F49), accent = Color(0xFFA78BFA), danger = Color(0xFFF87171), onAccent = Color(0xFF000000))
|
|
107
|
+
Triple("25", Tone.SEASON, false) -> SemanticColor(textPrimary = Color(0xFF9A3412), textSecondary = Color(0xFFA85134), surface = Color(0xFFF0EAE7), surfaceRaised = Color(0xFFFFF8F5), separator = Color(0xFFF5D5C8), accent = Color(0xFFEC8266), danger = Color(0xFFB91C1C), onAccent = Color(0xFF000000))
|
|
108
|
+
Triple("25", Tone.SEASON, true) -> SemanticColor(textPrimary = Color(0xFFD4CDC8), textSecondary = Color(0xFF9F9894), surface = Color(0xFF231C19), surfaceRaised = Color(0xFF1A0F0A), separator = Color(0xFF3D2318), accent = Color(0xFFF0A08A), danger = Color(0xFFF87171), onAccent = Color(0xFF000000))
|
|
109
|
+
Triple("25", Tone.NEUTRAL, false) -> SemanticColor(textPrimary = Color(0xFF111111), textSecondary = Color(0xFF555354), surface = Color(0xFFF2EEF1), surfaceRaised = Color(0xFFFEFBFA), separator = Color(0xFFD3CBCD), accent = Color(0xFFEC8266), danger = Color(0xFFB91C1C), onAccent = Color(0xFF000000))
|
|
110
|
+
Triple("25", Tone.NEUTRAL, true) -> SemanticColor(textPrimary = Color(0xFFF2F2F2), textSecondary = Color(0xFFACABAB), surface = Color(0xFF0A0606), surfaceRaised = Color(0xFF222021), separator = Color(0xFF474040), accent = Color(0xFFF0A08A), danger = Color(0xFFF87171), onAccent = Color(0xFF000000))
|
|
111
|
+
Triple("26", Tone.SEASON, false) -> SemanticColor(textPrimary = Color(0xFF152038), textSecondary = Color(0xFF545C6E), surface = Color(0xFFE7E9EC), surfaceRaised = Color(0xFFF5F7FA), separator = Color(0xFFC8CEDA), accent = Color(0xFF152038), danger = Color(0xFFB91C1C), onAccent = Color(0xFFFFFFFF))
|
|
112
|
+
Triple("26", Tone.SEASON, true) -> SemanticColor(textPrimary = Color(0xFFCACDD4), textSecondary = Color(0xFF94979F), surface = Color(0xFF171A22), surfaceRaised = Color(0xFF0A0E18), separator = Color(0xFF1E2D48), accent = Color(0xFF6B8FD4), danger = Color(0xFFF87171), onAccent = Color(0xFF000000))
|
|
113
|
+
Triple("26", Tone.NEUTRAL, false) -> SemanticColor(textPrimary = Color(0xFF111111), textSecondary = Color(0xFF525254), surface = Color(0xFFE9EAEF), surfaceRaised = Color(0xFFF8F8F9), separator = Color(0xFFC2C3C9), accent = Color(0xFF152038), danger = Color(0xFFB91C1C), onAccent = Color(0xFFFFFFFF))
|
|
114
|
+
Triple("26", Tone.NEUTRAL, true) -> SemanticColor(textPrimary = Color(0xFFF2F2F2), textSecondary = Color(0xFFABABAC), surface = Color(0xFF040608), surfaceRaised = Color(0xFF1E1F23), separator = Color(0xFF3C3F46), accent = Color(0xFF6B8FD4), danger = Color(0xFFF87171), onAccent = Color(0xFF000000))
|
|
115
|
+
Triple("wc26", Tone.SEASON, false) -> SemanticColor(textPrimary = Color(0xFF152038), textSecondary = Color(0xFF545C6E), surface = Color(0xFFE7E9EC), surfaceRaised = Color(0xFFF5F7FA), separator = Color(0xFFC8CEDA), accent = Color(0xFF152038), danger = Color(0xFFB91C1C), onAccent = Color(0xFFFFFFFF))
|
|
116
|
+
Triple("wc26", Tone.SEASON, true) -> SemanticColor(textPrimary = Color(0xFFCACDD4), textSecondary = Color(0xFF94979F), surface = Color(0xFF171A22), surfaceRaised = Color(0xFF0A0E18), separator = Color(0xFF1E2D48), accent = Color(0xFF6B8FD4), danger = Color(0xFFF87171), onAccent = Color(0xFF000000))
|
|
117
|
+
Triple("wc26", Tone.NEUTRAL, false) -> SemanticColor(textPrimary = Color(0xFF111111), textSecondary = Color(0xFF525254), surface = Color(0xFFE9EAEF), surfaceRaised = Color(0xFFF8F8F9), separator = Color(0xFFC2C3C9), accent = Color(0xFF152038), danger = Color(0xFFB91C1C), onAccent = Color(0xFFFFFFFF))
|
|
118
|
+
Triple("wc26", Tone.NEUTRAL, true) -> SemanticColor(textPrimary = Color(0xFFF2F2F2), textSecondary = Color(0xFFABABAC), surface = Color(0xFF040608), surfaceRaised = Color(0xFF1E1F23), separator = Color(0xFF3C3F46), accent = Color(0xFF6B8FD4), danger = Color(0xFFF87171), onAccent = Color(0xFF000000))
|
|
119
|
+
Triple("27", Tone.SEASON, false) -> SemanticColor(textPrimary = Color(0xFF422006), textSecondary = Color(0xFF785E47), surface = Color(0xFFF5F0E0), surfaceRaised = Color(0xFFFEFCE8), separator = Color(0xFFE2D6A4), accent = Color(0xFFCA8A04), danger = Color(0xFFB91C1C), onAccent = Color(0xFF000000))
|
|
120
|
+
Triple("27", Tone.SEASON, true) -> SemanticColor(textPrimary = Color(0xFFFDE047), textSecondary = Color(0xFFB6A136), surface = Color(0xFF0F0F0F), surfaceRaised = Color(0xFF1C1917), separator = Color(0xFF44403C), accent = Color(0xFFFACC15), danger = Color(0xFFF87171), onAccent = Color(0xFF000000))
|
|
121
|
+
Triple("27", Tone.NEUTRAL, false) -> SemanticColor(textPrimary = Color(0xFF111111), textSecondary = Color(0xFF545353), surface = Color(0xFFF0EEED), surfaceRaised = Color(0xFFFDFBF7), separator = Color(0xFFD0CBC5), accent = Color(0xFFCA8A04), danger = Color(0xFFB91C1C), onAccent = Color(0xFF000000))
|
|
122
|
+
Triple("27", Tone.NEUTRAL, true) -> SemanticColor(textPrimary = Color(0xFFF2F2F2), textSecondary = Color(0xFFACACAA), surface = Color(0xFF0A0801), surfaceRaised = Color(0xFF23211E), separator = Color(0xFF484437), accent = Color(0xFFFACC15), danger = Color(0xFFF87171), onAccent = Color(0xFF000000))
|
|
123
|
+
Triple("-1", Tone.SEASON, false) -> SemanticColor(textPrimary = Color(0xFF152038), textSecondary = Color(0xFF545C6E), surface = Color(0xFFE7E9EC), surfaceRaised = Color(0xFFF5F7FA), separator = Color(0xFFC8CEDA), accent = Color(0xFF152038), danger = Color(0xFFB91C1C), onAccent = Color(0xFFFFFFFF))
|
|
124
|
+
Triple("-1", Tone.SEASON, true) -> SemanticColor(textPrimary = Color(0xFFCACDD4), textSecondary = Color(0xFF94979F), surface = Color(0xFF171A22), surfaceRaised = Color(0xFF0A0E18), separator = Color(0xFF1E2D48), accent = Color(0xFF6B8FD4), danger = Color(0xFFF87171), onAccent = Color(0xFF000000))
|
|
125
|
+
Triple("-1", Tone.NEUTRAL, false) -> SemanticColor(textPrimary = Color(0xFF111111), textSecondary = Color(0xFF525254), surface = Color(0xFFE9EAEF), surfaceRaised = Color(0xFFF8F8F9), separator = Color(0xFFC2C3C9), accent = Color(0xFF152038), danger = Color(0xFFB91C1C), onAccent = Color(0xFFFFFFFF))
|
|
126
|
+
Triple("-1", Tone.NEUTRAL, true) -> SemanticColor(textPrimary = Color(0xFFF2F2F2), textSecondary = Color(0xFFABABAC), surface = Color(0xFF040608), surfaceRaised = Color(0xFF1E1F23), separator = Color(0xFF3C3F46), accent = Color(0xFF6B8FD4), danger = Color(0xFFF87171), onAccent = Color(0xFF000000))
|
|
127
|
+
Triple("0", Tone.SEASON, false) -> SemanticColor(textPrimary = Color(0xFF422006), textSecondary = Color(0xFF785E47), surface = Color(0xFFF5F0E0), surfaceRaised = Color(0xFFFEFCE8), separator = Color(0xFFE2D6A4), accent = Color(0xFFCA8A04), danger = Color(0xFFB91C1C), onAccent = Color(0xFF000000))
|
|
128
|
+
Triple("0", Tone.SEASON, true) -> SemanticColor(textPrimary = Color(0xFFFDE047), textSecondary = Color(0xFFB6A136), surface = Color(0xFF0F0F0F), surfaceRaised = Color(0xFF1C1917), separator = Color(0xFF44403C), accent = Color(0xFFFACC15), danger = Color(0xFFF87171), onAccent = Color(0xFF000000))
|
|
129
|
+
Triple("0", Tone.NEUTRAL, false) -> SemanticColor(textPrimary = Color(0xFF111111), textSecondary = Color(0xFF545353), surface = Color(0xFFF0EEED), surfaceRaised = Color(0xFFFDFBF7), separator = Color(0xFFD0CBC5), accent = Color(0xFFCA8A04), danger = Color(0xFFB91C1C), onAccent = Color(0xFF000000))
|
|
130
|
+
Triple("0", Tone.NEUTRAL, true) -> SemanticColor(textPrimary = Color(0xFFF2F2F2), textSecondary = Color(0xFFACACAA), surface = Color(0xFF0A0801), surfaceRaised = Color(0xFF23211E), separator = Color(0xFF484437), accent = Color(0xFFFACC15), danger = Color(0xFFF87171), onAccent = Color(0xFF000000))
|
|
131
|
+
Triple("1", Tone.SEASON, false) -> SemanticColor(textPrimary = Color(0xFF06423E), textSecondary = Color(0xFF437371), surface = Color(0xFFE0F0F5), surfaceRaised = Color(0xFFE8F5FE), separator = Color(0xFFA4CFE2), accent = Color(0xFF04A7CA), danger = Color(0xFFB91C1C), onAccent = Color(0xFF000000))
|
|
132
|
+
Triple("1", Tone.SEASON, true) -> SemanticColor(textPrimary = Color(0xFF47BFFD), textSecondary = Color(0xFF378EBA), surface = Color(0xFF0F0F0F), surfaceRaised = Color(0xFF171C1C), separator = Color(0xFF3C4444), accent = Color(0xFF15B5FA), danger = Color(0xFFF87171), onAccent = Color(0xFF000000))
|
|
133
|
+
Triple("1", Tone.NEUTRAL, false) -> SemanticColor(textPrimary = Color(0xFF111111), textSecondary = Color(0xFF525455), surface = Color(0xFFE8EFF5), surfaceRaised = Color(0xFFF7FCFD), separator = Color(0xFFC1CED5), accent = Color(0xFF04A7CA), danger = Color(0xFFB91C1C), onAccent = Color(0xFF000000))
|
|
134
|
+
Triple("1", Tone.NEUTRAL, true) -> SemanticColor(textPrimary = Color(0xFFF2F2F2), textSecondary = Color(0xFFAAABAC), surface = Color(0xFF01070A), surfaceRaised = Color(0xFF1C2125), separator = Color(0xFF354249), accent = Color(0xFF15B5FA), danger = Color(0xFFF87171), onAccent = Color(0xFF000000))
|
|
135
|
+
else -> semanticColorFor("0", tone, isDark)
|
|
136
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// AUTO-GENERATED — do not edit manually
|
|
2
|
+
// Run: bun run generate:tokens (from ui/)
|
|
3
|
+
// Source: ui/src/tokens/tokens.ts and each ui/src/seasons/<season>/style.css
|
|
4
|
+
import SwiftUI
|
|
5
|
+
|
|
6
|
+
enum Space {
|
|
7
|
+
static let xxxs: CGFloat = 2
|
|
8
|
+
static let xxs: CGFloat = 4
|
|
9
|
+
static let xs: CGFloat = 8
|
|
10
|
+
static let sm: CGFloat = 12
|
|
11
|
+
static let md: CGFloat = 16
|
|
12
|
+
static let lg: CGFloat = 24
|
|
13
|
+
static let xl: CGFloat = 32
|
|
14
|
+
static let xxl: CGFloat = 48
|
|
15
|
+
static let xxxl: CGFloat = 64
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
enum Radius {
|
|
19
|
+
static let sm: CGFloat = 4
|
|
20
|
+
static let md: CGFloat = 8
|
|
21
|
+
static let lg: CGFloat = 16
|
|
22
|
+
static let sheet: CGFloat = 28
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
enum Motion {
|
|
26
|
+
static let fast: Double = 0.15
|
|
27
|
+
static let base: Double = 0.25
|
|
28
|
+
static let slow: Double = 0.4
|
|
29
|
+
|
|
30
|
+
/// The one standard easing. Reduced motion gets no animation at all: the change lands instantly.
|
|
31
|
+
static func animation(_ duration: Double, reduceMotion: Bool) -> Animation? {
|
|
32
|
+
reduceMotion ? nil : .timingCurve(0.2, 0, 0, 1, duration: duration)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/// A type role: one Livvic face at a fixed size that scales with its Dynamic Type text style.
|
|
37
|
+
struct TypeRole: Sendable {
|
|
38
|
+
/// The face's PostScript name. A static family is picked by face, not by `.weight()` on the family.
|
|
39
|
+
var face: String
|
|
40
|
+
var size: CGFloat
|
|
41
|
+
var lineHeight: CGFloat
|
|
42
|
+
var tracking: CGFloat
|
|
43
|
+
var textStyle: Font.TextStyle
|
|
44
|
+
var tabular: Bool
|
|
45
|
+
|
|
46
|
+
var font: Font {
|
|
47
|
+
let font = Font.custom(face, size: size, relativeTo: textStyle)
|
|
48
|
+
return tabular ? font.monospacedDigit() : font
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static let display = TypeRole(face: "Livvic-Black", size: 40, lineHeight: 1.1, tracking: -0.02, textStyle: .largeTitle, tabular: false)
|
|
52
|
+
static let title = TypeRole(face: "Livvic-Bold", size: 28, lineHeight: 1.15, tracking: -0.01, textStyle: .title, tabular: false)
|
|
53
|
+
static let headline = TypeRole(face: "Livvic-SemiBold", size: 20, lineHeight: 1.25, tracking: 0, textStyle: .title3, tabular: false)
|
|
54
|
+
static let body = TypeRole(face: "Livvic-Regular", size: 16, lineHeight: 1.5, tracking: 0, textStyle: .body, tabular: false)
|
|
55
|
+
static let label = TypeRole(face: "Livvic-Medium", size: 14, lineHeight: 1.3, tracking: 0.01, textStyle: .subheadline, tabular: false)
|
|
56
|
+
static let caption = TypeRole(face: "Livvic-Regular", size: 12, lineHeight: 1.35, tracking: 0.01, textStyle: .caption, tabular: false)
|
|
57
|
+
static let numeral = TypeRole(face: "Livvic-Medium", size: 16, lineHeight: 1.3, tracking: 0, textStyle: .body, tabular: true)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
extension View {
|
|
61
|
+
func typeRole(_ role: TypeRole) -> some View {
|
|
62
|
+
font(role.font)
|
|
63
|
+
.tracking(role.size * role.tracking)
|
|
64
|
+
.lineSpacing(role.size * (role.lineHeight - 1))
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
nonisolated enum Tone: Sendable {
|
|
69
|
+
case season
|
|
70
|
+
case neutral
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
struct SemanticColor: Sendable {
|
|
74
|
+
var textPrimary: Color
|
|
75
|
+
var textSecondary: Color
|
|
76
|
+
var surface: Color
|
|
77
|
+
var surfaceRaised: Color
|
|
78
|
+
var separator: Color
|
|
79
|
+
var accent: Color
|
|
80
|
+
var danger: Color
|
|
81
|
+
var onAccent: Color
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
func semanticColorFor(_ shortName: String, tone: Tone, isDark: Bool = false) -> SemanticColor {
|
|
85
|
+
switch (shortName, tone, isDark) {
|
|
86
|
+
case ("24", .season, false): return SemanticColor(textPrimary: Color(hex: 0x5B21B6), textSecondary: Color(hex: 0x7E51C4), surface: Color(hex: 0xEDEAEF), surfaceRaised: Color(hex: 0xF9F5FF), separator: Color(hex: 0xDDD0F5), accent: Color(hex: 0x7C3AED), danger: Color(hex: 0xB91C1C), onAccent: Color(hex: 0xFFFFFF))
|
|
87
|
+
case ("24", .season, true): return SemanticColor(textPrimary: Color(hex: 0xD0CCD6), textSecondary: Color(hex: 0x9B97A1), surface: Color(hex: 0x1E1A24), surfaceRaised: Color(hex: 0x130A24), separator: Color(hex: 0x2E1A52), accent: Color(hex: 0xA78BFA), danger: Color(hex: 0xF87171), onAccent: Color(hex: 0x000000))
|
|
88
|
+
case ("24", .neutral, false): return SemanticColor(textPrimary: Color(hex: 0x111111), textSecondary: Color(hex: 0x535256), surface: Color(hex: 0xEDEBF7), surfaceRaised: Color(hex: 0xFBF9FE), separator: Color(hex: 0xCAC5D8), accent: Color(hex: 0x7C3AED), danger: Color(hex: 0xB91C1C), onAccent: Color(hex: 0xFFFFFF))
|
|
89
|
+
case ("24", .neutral, true): return SemanticColor(textPrimary: Color(hex: 0xF2F2F2), textSecondary: Color(hex: 0xABABAC), surface: Color(hex: 0x07060A), surfaceRaised: Color(hex: 0x201F25), separator: Color(hex: 0x413F49), accent: Color(hex: 0xA78BFA), danger: Color(hex: 0xF87171), onAccent: Color(hex: 0x000000))
|
|
90
|
+
case ("25", .season, false): return SemanticColor(textPrimary: Color(hex: 0x9A3412), textSecondary: Color(hex: 0xA85134), surface: Color(hex: 0xF0EAE7), surfaceRaised: Color(hex: 0xFFF8F5), separator: Color(hex: 0xF5D5C8), accent: Color(hex: 0xEC8266), danger: Color(hex: 0xB91C1C), onAccent: Color(hex: 0x000000))
|
|
91
|
+
case ("25", .season, true): return SemanticColor(textPrimary: Color(hex: 0xD4CDC8), textSecondary: Color(hex: 0x9F9894), surface: Color(hex: 0x231C19), surfaceRaised: Color(hex: 0x1A0F0A), separator: Color(hex: 0x3D2318), accent: Color(hex: 0xF0A08A), danger: Color(hex: 0xF87171), onAccent: Color(hex: 0x000000))
|
|
92
|
+
case ("25", .neutral, false): return SemanticColor(textPrimary: Color(hex: 0x111111), textSecondary: Color(hex: 0x555354), surface: Color(hex: 0xF2EEF1), surfaceRaised: Color(hex: 0xFEFBFA), separator: Color(hex: 0xD3CBCD), accent: Color(hex: 0xEC8266), danger: Color(hex: 0xB91C1C), onAccent: Color(hex: 0x000000))
|
|
93
|
+
case ("25", .neutral, true): return SemanticColor(textPrimary: Color(hex: 0xF2F2F2), textSecondary: Color(hex: 0xACABAB), surface: Color(hex: 0x0A0606), surfaceRaised: Color(hex: 0x222021), separator: Color(hex: 0x474040), accent: Color(hex: 0xF0A08A), danger: Color(hex: 0xF87171), onAccent: Color(hex: 0x000000))
|
|
94
|
+
case ("26", .season, false): return SemanticColor(textPrimary: Color(hex: 0x152038), textSecondary: Color(hex: 0x545C6E), surface: Color(hex: 0xE7E9EC), surfaceRaised: Color(hex: 0xF5F7FA), separator: Color(hex: 0xC8CEDA), accent: Color(hex: 0x152038), danger: Color(hex: 0xB91C1C), onAccent: Color(hex: 0xFFFFFF))
|
|
95
|
+
case ("26", .season, true): return SemanticColor(textPrimary: Color(hex: 0xCACDD4), textSecondary: Color(hex: 0x94979F), surface: Color(hex: 0x171A22), surfaceRaised: Color(hex: 0x0A0E18), separator: Color(hex: 0x1E2D48), accent: Color(hex: 0x6B8FD4), danger: Color(hex: 0xF87171), onAccent: Color(hex: 0x000000))
|
|
96
|
+
case ("26", .neutral, false): return SemanticColor(textPrimary: Color(hex: 0x111111), textSecondary: Color(hex: 0x525254), surface: Color(hex: 0xE9EAEF), surfaceRaised: Color(hex: 0xF8F8F9), separator: Color(hex: 0xC2C3C9), accent: Color(hex: 0x152038), danger: Color(hex: 0xB91C1C), onAccent: Color(hex: 0xFFFFFF))
|
|
97
|
+
case ("26", .neutral, true): return SemanticColor(textPrimary: Color(hex: 0xF2F2F2), textSecondary: Color(hex: 0xABABAC), surface: Color(hex: 0x040608), surfaceRaised: Color(hex: 0x1E1F23), separator: Color(hex: 0x3C3F46), accent: Color(hex: 0x6B8FD4), danger: Color(hex: 0xF87171), onAccent: Color(hex: 0x000000))
|
|
98
|
+
case ("wc26", .season, false): return SemanticColor(textPrimary: Color(hex: 0x152038), textSecondary: Color(hex: 0x545C6E), surface: Color(hex: 0xE7E9EC), surfaceRaised: Color(hex: 0xF5F7FA), separator: Color(hex: 0xC8CEDA), accent: Color(hex: 0x152038), danger: Color(hex: 0xB91C1C), onAccent: Color(hex: 0xFFFFFF))
|
|
99
|
+
case ("wc26", .season, true): return SemanticColor(textPrimary: Color(hex: 0xCACDD4), textSecondary: Color(hex: 0x94979F), surface: Color(hex: 0x171A22), surfaceRaised: Color(hex: 0x0A0E18), separator: Color(hex: 0x1E2D48), accent: Color(hex: 0x6B8FD4), danger: Color(hex: 0xF87171), onAccent: Color(hex: 0x000000))
|
|
100
|
+
case ("wc26", .neutral, false): return SemanticColor(textPrimary: Color(hex: 0x111111), textSecondary: Color(hex: 0x525254), surface: Color(hex: 0xE9EAEF), surfaceRaised: Color(hex: 0xF8F8F9), separator: Color(hex: 0xC2C3C9), accent: Color(hex: 0x152038), danger: Color(hex: 0xB91C1C), onAccent: Color(hex: 0xFFFFFF))
|
|
101
|
+
case ("wc26", .neutral, true): return SemanticColor(textPrimary: Color(hex: 0xF2F2F2), textSecondary: Color(hex: 0xABABAC), surface: Color(hex: 0x040608), surfaceRaised: Color(hex: 0x1E1F23), separator: Color(hex: 0x3C3F46), accent: Color(hex: 0x6B8FD4), danger: Color(hex: 0xF87171), onAccent: Color(hex: 0x000000))
|
|
102
|
+
case ("27", .season, false): return SemanticColor(textPrimary: Color(hex: 0x422006), textSecondary: Color(hex: 0x785E47), surface: Color(hex: 0xF5F0E0), surfaceRaised: Color(hex: 0xFEFCE8), separator: Color(hex: 0xE2D6A4), accent: Color(hex: 0xCA8A04), danger: Color(hex: 0xB91C1C), onAccent: Color(hex: 0x000000))
|
|
103
|
+
case ("27", .season, true): return SemanticColor(textPrimary: Color(hex: 0xFDE047), textSecondary: Color(hex: 0xB6A136), surface: Color(hex: 0x0F0F0F), surfaceRaised: Color(hex: 0x1C1917), separator: Color(hex: 0x44403C), accent: Color(hex: 0xFACC15), danger: Color(hex: 0xF87171), onAccent: Color(hex: 0x000000))
|
|
104
|
+
case ("27", .neutral, false): return SemanticColor(textPrimary: Color(hex: 0x111111), textSecondary: Color(hex: 0x545353), surface: Color(hex: 0xF0EEED), surfaceRaised: Color(hex: 0xFDFBF7), separator: Color(hex: 0xD0CBC5), accent: Color(hex: 0xCA8A04), danger: Color(hex: 0xB91C1C), onAccent: Color(hex: 0x000000))
|
|
105
|
+
case ("27", .neutral, true): return SemanticColor(textPrimary: Color(hex: 0xF2F2F2), textSecondary: Color(hex: 0xACACAA), surface: Color(hex: 0x0A0801), surfaceRaised: Color(hex: 0x23211E), separator: Color(hex: 0x484437), accent: Color(hex: 0xFACC15), danger: Color(hex: 0xF87171), onAccent: Color(hex: 0x000000))
|
|
106
|
+
case ("-1", .season, false): return SemanticColor(textPrimary: Color(hex: 0x152038), textSecondary: Color(hex: 0x545C6E), surface: Color(hex: 0xE7E9EC), surfaceRaised: Color(hex: 0xF5F7FA), separator: Color(hex: 0xC8CEDA), accent: Color(hex: 0x152038), danger: Color(hex: 0xB91C1C), onAccent: Color(hex: 0xFFFFFF))
|
|
107
|
+
case ("-1", .season, true): return SemanticColor(textPrimary: Color(hex: 0xCACDD4), textSecondary: Color(hex: 0x94979F), surface: Color(hex: 0x171A22), surfaceRaised: Color(hex: 0x0A0E18), separator: Color(hex: 0x1E2D48), accent: Color(hex: 0x6B8FD4), danger: Color(hex: 0xF87171), onAccent: Color(hex: 0x000000))
|
|
108
|
+
case ("-1", .neutral, false): return SemanticColor(textPrimary: Color(hex: 0x111111), textSecondary: Color(hex: 0x525254), surface: Color(hex: 0xE9EAEF), surfaceRaised: Color(hex: 0xF8F8F9), separator: Color(hex: 0xC2C3C9), accent: Color(hex: 0x152038), danger: Color(hex: 0xB91C1C), onAccent: Color(hex: 0xFFFFFF))
|
|
109
|
+
case ("-1", .neutral, true): return SemanticColor(textPrimary: Color(hex: 0xF2F2F2), textSecondary: Color(hex: 0xABABAC), surface: Color(hex: 0x040608), surfaceRaised: Color(hex: 0x1E1F23), separator: Color(hex: 0x3C3F46), accent: Color(hex: 0x6B8FD4), danger: Color(hex: 0xF87171), onAccent: Color(hex: 0x000000))
|
|
110
|
+
case ("0", .season, false): return SemanticColor(textPrimary: Color(hex: 0x422006), textSecondary: Color(hex: 0x785E47), surface: Color(hex: 0xF5F0E0), surfaceRaised: Color(hex: 0xFEFCE8), separator: Color(hex: 0xE2D6A4), accent: Color(hex: 0xCA8A04), danger: Color(hex: 0xB91C1C), onAccent: Color(hex: 0x000000))
|
|
111
|
+
case ("0", .season, true): return SemanticColor(textPrimary: Color(hex: 0xFDE047), textSecondary: Color(hex: 0xB6A136), surface: Color(hex: 0x0F0F0F), surfaceRaised: Color(hex: 0x1C1917), separator: Color(hex: 0x44403C), accent: Color(hex: 0xFACC15), danger: Color(hex: 0xF87171), onAccent: Color(hex: 0x000000))
|
|
112
|
+
case ("0", .neutral, false): return SemanticColor(textPrimary: Color(hex: 0x111111), textSecondary: Color(hex: 0x545353), surface: Color(hex: 0xF0EEED), surfaceRaised: Color(hex: 0xFDFBF7), separator: Color(hex: 0xD0CBC5), accent: Color(hex: 0xCA8A04), danger: Color(hex: 0xB91C1C), onAccent: Color(hex: 0x000000))
|
|
113
|
+
case ("0", .neutral, true): return SemanticColor(textPrimary: Color(hex: 0xF2F2F2), textSecondary: Color(hex: 0xACACAA), surface: Color(hex: 0x0A0801), surfaceRaised: Color(hex: 0x23211E), separator: Color(hex: 0x484437), accent: Color(hex: 0xFACC15), danger: Color(hex: 0xF87171), onAccent: Color(hex: 0x000000))
|
|
114
|
+
case ("1", .season, false): return SemanticColor(textPrimary: Color(hex: 0x06423E), textSecondary: Color(hex: 0x437371), surface: Color(hex: 0xE0F0F5), surfaceRaised: Color(hex: 0xE8F5FE), separator: Color(hex: 0xA4CFE2), accent: Color(hex: 0x04A7CA), danger: Color(hex: 0xB91C1C), onAccent: Color(hex: 0x000000))
|
|
115
|
+
case ("1", .season, true): return SemanticColor(textPrimary: Color(hex: 0x47BFFD), textSecondary: Color(hex: 0x378EBA), surface: Color(hex: 0x0F0F0F), surfaceRaised: Color(hex: 0x171C1C), separator: Color(hex: 0x3C4444), accent: Color(hex: 0x15B5FA), danger: Color(hex: 0xF87171), onAccent: Color(hex: 0x000000))
|
|
116
|
+
case ("1", .neutral, false): return SemanticColor(textPrimary: Color(hex: 0x111111), textSecondary: Color(hex: 0x525455), surface: Color(hex: 0xE8EFF5), surfaceRaised: Color(hex: 0xF7FCFD), separator: Color(hex: 0xC1CED5), accent: Color(hex: 0x04A7CA), danger: Color(hex: 0xB91C1C), onAccent: Color(hex: 0x000000))
|
|
117
|
+
case ("1", .neutral, true): return SemanticColor(textPrimary: Color(hex: 0xF2F2F2), textSecondary: Color(hex: 0xAAABAC), surface: Color(hex: 0x01070A), surfaceRaised: Color(hex: 0x1C2125), separator: Color(hex: 0x354249), accent: Color(hex: 0x15B5FA), danger: Color(hex: 0xF87171), onAccent: Color(hex: 0x000000))
|
|
118
|
+
default: return semanticColorFor("0", tone: tone, isDark: isDark)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
/* AUTO-GENERATED — do not edit manually */
|
|
2
|
+
/* Run: bun run generate:tokens (from ui/) */
|
|
3
|
+
/* Source: ui/src/tokens/tokens.ts and each ui/src/seasons/<season>/style.css */
|
|
4
|
+
|
|
5
|
+
:root {
|
|
6
|
+
--space-3xs: 2px;
|
|
7
|
+
--space-2xs: 4px;
|
|
8
|
+
--space-xs: 8px;
|
|
9
|
+
--space-sm: 12px;
|
|
10
|
+
--space-md: 16px;
|
|
11
|
+
--space-lg: 24px;
|
|
12
|
+
--space-xl: 32px;
|
|
13
|
+
--space-2xl: 48px;
|
|
14
|
+
--space-3xl: 64px;
|
|
15
|
+
--radius-sm: 4px;
|
|
16
|
+
--radius-md: 8px;
|
|
17
|
+
--radius-lg: 16px;
|
|
18
|
+
--radius-sheet: 28px;
|
|
19
|
+
--motion-fast: 150ms;
|
|
20
|
+
--motion-base: 250ms;
|
|
21
|
+
--motion-slow: 400ms;
|
|
22
|
+
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
|
23
|
+
--font-family-base: 'Livvic', system-ui, sans-serif;
|
|
24
|
+
--type-display-size: clamp(2rem, 5vw, 3.5rem);
|
|
25
|
+
--type-display-weight: 900;
|
|
26
|
+
--type-display-line-height: 1.1;
|
|
27
|
+
--type-display-tracking: -0.02em;
|
|
28
|
+
--type-title-size: clamp(1.5rem, 3.5vw, 2.25rem);
|
|
29
|
+
--type-title-weight: 700;
|
|
30
|
+
--type-title-line-height: 1.15;
|
|
31
|
+
--type-title-tracking: -0.01em;
|
|
32
|
+
--type-headline-size: clamp(1.25rem, 2.5vw, 1.75rem);
|
|
33
|
+
--type-headline-weight: 600;
|
|
34
|
+
--type-headline-line-height: 1.25;
|
|
35
|
+
--type-headline-tracking: 0em;
|
|
36
|
+
--type-body-size: 1rem;
|
|
37
|
+
--type-body-weight: 400;
|
|
38
|
+
--type-body-line-height: 1.5;
|
|
39
|
+
--type-body-tracking: 0em;
|
|
40
|
+
--type-label-size: 0.875rem;
|
|
41
|
+
--type-label-weight: 500;
|
|
42
|
+
--type-label-line-height: 1.3;
|
|
43
|
+
--type-label-tracking: 0.01em;
|
|
44
|
+
--type-caption-size: 0.75rem;
|
|
45
|
+
--type-caption-weight: 400;
|
|
46
|
+
--type-caption-line-height: 1.35;
|
|
47
|
+
--type-caption-tracking: 0.01em;
|
|
48
|
+
--type-numeral-size: 1rem;
|
|
49
|
+
--type-numeral-weight: 500;
|
|
50
|
+
--type-numeral-line-height: 1.3;
|
|
51
|
+
--type-numeral-tracking: 0em;
|
|
52
|
+
--ui-text-primary: var(--ui-neutral-text-primary);
|
|
53
|
+
--ui-text-secondary: var(--ui-neutral-text-secondary);
|
|
54
|
+
--ui-surface: var(--ui-neutral-surface);
|
|
55
|
+
--ui-surface-raised: var(--ui-neutral-surface-raised);
|
|
56
|
+
--ui-separator: var(--ui-neutral-separator);
|
|
57
|
+
--ui-accent: var(--ui-neutral-accent);
|
|
58
|
+
--ui-danger: var(--ui-neutral-danger);
|
|
59
|
+
--ui-on-accent: var(--ui-neutral-on-accent);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
[data-tone='season'] {
|
|
63
|
+
--ui-text-primary: var(--ui-season-text-primary);
|
|
64
|
+
--ui-text-secondary: var(--ui-season-text-secondary);
|
|
65
|
+
--ui-surface: var(--ui-season-surface);
|
|
66
|
+
--ui-surface-raised: var(--ui-season-surface-raised);
|
|
67
|
+
--ui-separator: var(--ui-season-separator);
|
|
68
|
+
--ui-accent: var(--ui-season-accent);
|
|
69
|
+
--ui-danger: var(--ui-season-danger);
|
|
70
|
+
--ui-on-accent: var(--ui-season-on-accent);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@media (prefers-reduced-motion: reduce) {
|
|
74
|
+
:root {
|
|
75
|
+
--motion-fast: 0ms;
|
|
76
|
+
--motion-base: 0ms;
|
|
77
|
+
--motion-slow: 0ms;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
:root[data-season='24'] {
|
|
82
|
+
--ui-season-text-primary: #5b21b6;
|
|
83
|
+
--ui-season-text-secondary: #7e51c4;
|
|
84
|
+
--ui-season-surface: #edeaef;
|
|
85
|
+
--ui-season-surface-raised: #f9f5ff;
|
|
86
|
+
--ui-season-separator: #ddd0f5;
|
|
87
|
+
--ui-season-accent: #7c3aed;
|
|
88
|
+
--ui-season-danger: #b91c1c;
|
|
89
|
+
--ui-season-on-accent: #ffffff;
|
|
90
|
+
--ui-neutral-text-primary: #111111;
|
|
91
|
+
--ui-neutral-text-secondary: #535256;
|
|
92
|
+
--ui-neutral-surface: #edebf7;
|
|
93
|
+
--ui-neutral-surface-raised: #fbf9fe;
|
|
94
|
+
--ui-neutral-separator: #cac5d8;
|
|
95
|
+
--ui-neutral-accent: #7c3aed;
|
|
96
|
+
--ui-neutral-danger: #b91c1c;
|
|
97
|
+
--ui-neutral-on-accent: #ffffff;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
:root[data-season='24'][data-theme='dark'] {
|
|
101
|
+
--ui-season-text-primary: #d0ccd6;
|
|
102
|
+
--ui-season-text-secondary: #9b97a1;
|
|
103
|
+
--ui-season-surface: #1e1a24;
|
|
104
|
+
--ui-season-surface-raised: #130a24;
|
|
105
|
+
--ui-season-separator: #2e1a52;
|
|
106
|
+
--ui-season-accent: #a78bfa;
|
|
107
|
+
--ui-season-danger: #f87171;
|
|
108
|
+
--ui-season-on-accent: #000000;
|
|
109
|
+
--ui-neutral-text-primary: #f2f2f2;
|
|
110
|
+
--ui-neutral-text-secondary: #ababac;
|
|
111
|
+
--ui-neutral-surface: #07060a;
|
|
112
|
+
--ui-neutral-surface-raised: #201f25;
|
|
113
|
+
--ui-neutral-separator: #413f49;
|
|
114
|
+
--ui-neutral-accent: #a78bfa;
|
|
115
|
+
--ui-neutral-danger: #f87171;
|
|
116
|
+
--ui-neutral-on-accent: #000000;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
:root[data-season='25'] {
|
|
120
|
+
--ui-season-text-primary: #9a3412;
|
|
121
|
+
--ui-season-text-secondary: #a85134;
|
|
122
|
+
--ui-season-surface: #f0eae7;
|
|
123
|
+
--ui-season-surface-raised: #fff8f5;
|
|
124
|
+
--ui-season-separator: #f5d5c8;
|
|
125
|
+
--ui-season-accent: #ec8266;
|
|
126
|
+
--ui-season-danger: #b91c1c;
|
|
127
|
+
--ui-season-on-accent: #000000;
|
|
128
|
+
--ui-neutral-text-primary: #111111;
|
|
129
|
+
--ui-neutral-text-secondary: #555354;
|
|
130
|
+
--ui-neutral-surface: #f2eef1;
|
|
131
|
+
--ui-neutral-surface-raised: #fefbfa;
|
|
132
|
+
--ui-neutral-separator: #d3cbcd;
|
|
133
|
+
--ui-neutral-accent: #ec8266;
|
|
134
|
+
--ui-neutral-danger: #b91c1c;
|
|
135
|
+
--ui-neutral-on-accent: #000000;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
:root[data-season='25'][data-theme='dark'] {
|
|
139
|
+
--ui-season-text-primary: #d4cdc8;
|
|
140
|
+
--ui-season-text-secondary: #9f9894;
|
|
141
|
+
--ui-season-surface: #231c19;
|
|
142
|
+
--ui-season-surface-raised: #1a0f0a;
|
|
143
|
+
--ui-season-separator: #3d2318;
|
|
144
|
+
--ui-season-accent: #f0a08a;
|
|
145
|
+
--ui-season-danger: #f87171;
|
|
146
|
+
--ui-season-on-accent: #000000;
|
|
147
|
+
--ui-neutral-text-primary: #f2f2f2;
|
|
148
|
+
--ui-neutral-text-secondary: #acabab;
|
|
149
|
+
--ui-neutral-surface: #0a0606;
|
|
150
|
+
--ui-neutral-surface-raised: #222021;
|
|
151
|
+
--ui-neutral-separator: #474040;
|
|
152
|
+
--ui-neutral-accent: #f0a08a;
|
|
153
|
+
--ui-neutral-danger: #f87171;
|
|
154
|
+
--ui-neutral-on-accent: #000000;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
:root[data-season='26'] {
|
|
158
|
+
--ui-season-text-primary: #152038;
|
|
159
|
+
--ui-season-text-secondary: #545c6e;
|
|
160
|
+
--ui-season-surface: #e7e9ec;
|
|
161
|
+
--ui-season-surface-raised: #f5f7fa;
|
|
162
|
+
--ui-season-separator: #c8ceda;
|
|
163
|
+
--ui-season-accent: #152038;
|
|
164
|
+
--ui-season-danger: #b91c1c;
|
|
165
|
+
--ui-season-on-accent: #ffffff;
|
|
166
|
+
--ui-neutral-text-primary: #111111;
|
|
167
|
+
--ui-neutral-text-secondary: #525254;
|
|
168
|
+
--ui-neutral-surface: #e9eaef;
|
|
169
|
+
--ui-neutral-surface-raised: #f8f8f9;
|
|
170
|
+
--ui-neutral-separator: #c2c3c9;
|
|
171
|
+
--ui-neutral-accent: #152038;
|
|
172
|
+
--ui-neutral-danger: #b91c1c;
|
|
173
|
+
--ui-neutral-on-accent: #ffffff;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
:root[data-season='26'][data-theme='dark'] {
|
|
177
|
+
--ui-season-text-primary: #cacdd4;
|
|
178
|
+
--ui-season-text-secondary: #94979f;
|
|
179
|
+
--ui-season-surface: #171a22;
|
|
180
|
+
--ui-season-surface-raised: #0a0e18;
|
|
181
|
+
--ui-season-separator: #1e2d48;
|
|
182
|
+
--ui-season-accent: #6b8fd4;
|
|
183
|
+
--ui-season-danger: #f87171;
|
|
184
|
+
--ui-season-on-accent: #000000;
|
|
185
|
+
--ui-neutral-text-primary: #f2f2f2;
|
|
186
|
+
--ui-neutral-text-secondary: #ababac;
|
|
187
|
+
--ui-neutral-surface: #040608;
|
|
188
|
+
--ui-neutral-surface-raised: #1e1f23;
|
|
189
|
+
--ui-neutral-separator: #3c3f46;
|
|
190
|
+
--ui-neutral-accent: #6b8fd4;
|
|
191
|
+
--ui-neutral-danger: #f87171;
|
|
192
|
+
--ui-neutral-on-accent: #000000;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
:root[data-season='wc26'] {
|
|
196
|
+
--ui-season-text-primary: #152038;
|
|
197
|
+
--ui-season-text-secondary: #545c6e;
|
|
198
|
+
--ui-season-surface: #e7e9ec;
|
|
199
|
+
--ui-season-surface-raised: #f5f7fa;
|
|
200
|
+
--ui-season-separator: #c8ceda;
|
|
201
|
+
--ui-season-accent: #152038;
|
|
202
|
+
--ui-season-danger: #b91c1c;
|
|
203
|
+
--ui-season-on-accent: #ffffff;
|
|
204
|
+
--ui-neutral-text-primary: #111111;
|
|
205
|
+
--ui-neutral-text-secondary: #525254;
|
|
206
|
+
--ui-neutral-surface: #e9eaef;
|
|
207
|
+
--ui-neutral-surface-raised: #f8f8f9;
|
|
208
|
+
--ui-neutral-separator: #c2c3c9;
|
|
209
|
+
--ui-neutral-accent: #152038;
|
|
210
|
+
--ui-neutral-danger: #b91c1c;
|
|
211
|
+
--ui-neutral-on-accent: #ffffff;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
:root[data-season='wc26'][data-theme='dark'] {
|
|
215
|
+
--ui-season-text-primary: #cacdd4;
|
|
216
|
+
--ui-season-text-secondary: #94979f;
|
|
217
|
+
--ui-season-surface: #171a22;
|
|
218
|
+
--ui-season-surface-raised: #0a0e18;
|
|
219
|
+
--ui-season-separator: #1e2d48;
|
|
220
|
+
--ui-season-accent: #6b8fd4;
|
|
221
|
+
--ui-season-danger: #f87171;
|
|
222
|
+
--ui-season-on-accent: #000000;
|
|
223
|
+
--ui-neutral-text-primary: #f2f2f2;
|
|
224
|
+
--ui-neutral-text-secondary: #ababac;
|
|
225
|
+
--ui-neutral-surface: #040608;
|
|
226
|
+
--ui-neutral-surface-raised: #1e1f23;
|
|
227
|
+
--ui-neutral-separator: #3c3f46;
|
|
228
|
+
--ui-neutral-accent: #6b8fd4;
|
|
229
|
+
--ui-neutral-danger: #f87171;
|
|
230
|
+
--ui-neutral-on-accent: #000000;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
:root[data-season='27'] {
|
|
234
|
+
--ui-season-text-primary: #422006;
|
|
235
|
+
--ui-season-text-secondary: #785e47;
|
|
236
|
+
--ui-season-surface: #f5f0e0;
|
|
237
|
+
--ui-season-surface-raised: #fefce8;
|
|
238
|
+
--ui-season-separator: #e2d6a4;
|
|
239
|
+
--ui-season-accent: #ca8a04;
|
|
240
|
+
--ui-season-danger: #b91c1c;
|
|
241
|
+
--ui-season-on-accent: #000000;
|
|
242
|
+
--ui-neutral-text-primary: #111111;
|
|
243
|
+
--ui-neutral-text-secondary: #545353;
|
|
244
|
+
--ui-neutral-surface: #f0eeed;
|
|
245
|
+
--ui-neutral-surface-raised: #fdfbf7;
|
|
246
|
+
--ui-neutral-separator: #d0cbc5;
|
|
247
|
+
--ui-neutral-accent: #ca8a04;
|
|
248
|
+
--ui-neutral-danger: #b91c1c;
|
|
249
|
+
--ui-neutral-on-accent: #000000;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
:root[data-season='27'][data-theme='dark'] {
|
|
253
|
+
--ui-season-text-primary: #fde047;
|
|
254
|
+
--ui-season-text-secondary: #b6a136;
|
|
255
|
+
--ui-season-surface: #0f0f0f;
|
|
256
|
+
--ui-season-surface-raised: #1c1917;
|
|
257
|
+
--ui-season-separator: #44403c;
|
|
258
|
+
--ui-season-accent: #facc15;
|
|
259
|
+
--ui-season-danger: #f87171;
|
|
260
|
+
--ui-season-on-accent: #000000;
|
|
261
|
+
--ui-neutral-text-primary: #f2f2f2;
|
|
262
|
+
--ui-neutral-text-secondary: #acacaa;
|
|
263
|
+
--ui-neutral-surface: #0a0801;
|
|
264
|
+
--ui-neutral-surface-raised: #23211e;
|
|
265
|
+
--ui-neutral-separator: #484437;
|
|
266
|
+
--ui-neutral-accent: #facc15;
|
|
267
|
+
--ui-neutral-danger: #f87171;
|
|
268
|
+
--ui-neutral-on-accent: #000000;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
:root[data-season='-1'] {
|
|
272
|
+
--ui-season-text-primary: #152038;
|
|
273
|
+
--ui-season-text-secondary: #545c6e;
|
|
274
|
+
--ui-season-surface: #e7e9ec;
|
|
275
|
+
--ui-season-surface-raised: #f5f7fa;
|
|
276
|
+
--ui-season-separator: #c8ceda;
|
|
277
|
+
--ui-season-accent: #152038;
|
|
278
|
+
--ui-season-danger: #b91c1c;
|
|
279
|
+
--ui-season-on-accent: #ffffff;
|
|
280
|
+
--ui-neutral-text-primary: #111111;
|
|
281
|
+
--ui-neutral-text-secondary: #525254;
|
|
282
|
+
--ui-neutral-surface: #e9eaef;
|
|
283
|
+
--ui-neutral-surface-raised: #f8f8f9;
|
|
284
|
+
--ui-neutral-separator: #c2c3c9;
|
|
285
|
+
--ui-neutral-accent: #152038;
|
|
286
|
+
--ui-neutral-danger: #b91c1c;
|
|
287
|
+
--ui-neutral-on-accent: #ffffff;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
:root[data-season='-1'][data-theme='dark'] {
|
|
291
|
+
--ui-season-text-primary: #cacdd4;
|
|
292
|
+
--ui-season-text-secondary: #94979f;
|
|
293
|
+
--ui-season-surface: #171a22;
|
|
294
|
+
--ui-season-surface-raised: #0a0e18;
|
|
295
|
+
--ui-season-separator: #1e2d48;
|
|
296
|
+
--ui-season-accent: #6b8fd4;
|
|
297
|
+
--ui-season-danger: #f87171;
|
|
298
|
+
--ui-season-on-accent: #000000;
|
|
299
|
+
--ui-neutral-text-primary: #f2f2f2;
|
|
300
|
+
--ui-neutral-text-secondary: #ababac;
|
|
301
|
+
--ui-neutral-surface: #040608;
|
|
302
|
+
--ui-neutral-surface-raised: #1e1f23;
|
|
303
|
+
--ui-neutral-separator: #3c3f46;
|
|
304
|
+
--ui-neutral-accent: #6b8fd4;
|
|
305
|
+
--ui-neutral-danger: #f87171;
|
|
306
|
+
--ui-neutral-on-accent: #000000;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
:root[data-season='0'] {
|
|
310
|
+
--ui-season-text-primary: #422006;
|
|
311
|
+
--ui-season-text-secondary: #785e47;
|
|
312
|
+
--ui-season-surface: #f5f0e0;
|
|
313
|
+
--ui-season-surface-raised: #fefce8;
|
|
314
|
+
--ui-season-separator: #e2d6a4;
|
|
315
|
+
--ui-season-accent: #ca8a04;
|
|
316
|
+
--ui-season-danger: #b91c1c;
|
|
317
|
+
--ui-season-on-accent: #000000;
|
|
318
|
+
--ui-neutral-text-primary: #111111;
|
|
319
|
+
--ui-neutral-text-secondary: #545353;
|
|
320
|
+
--ui-neutral-surface: #f0eeed;
|
|
321
|
+
--ui-neutral-surface-raised: #fdfbf7;
|
|
322
|
+
--ui-neutral-separator: #d0cbc5;
|
|
323
|
+
--ui-neutral-accent: #ca8a04;
|
|
324
|
+
--ui-neutral-danger: #b91c1c;
|
|
325
|
+
--ui-neutral-on-accent: #000000;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
:root[data-season='0'][data-theme='dark'] {
|
|
329
|
+
--ui-season-text-primary: #fde047;
|
|
330
|
+
--ui-season-text-secondary: #b6a136;
|
|
331
|
+
--ui-season-surface: #0f0f0f;
|
|
332
|
+
--ui-season-surface-raised: #1c1917;
|
|
333
|
+
--ui-season-separator: #44403c;
|
|
334
|
+
--ui-season-accent: #facc15;
|
|
335
|
+
--ui-season-danger: #f87171;
|
|
336
|
+
--ui-season-on-accent: #000000;
|
|
337
|
+
--ui-neutral-text-primary: #f2f2f2;
|
|
338
|
+
--ui-neutral-text-secondary: #acacaa;
|
|
339
|
+
--ui-neutral-surface: #0a0801;
|
|
340
|
+
--ui-neutral-surface-raised: #23211e;
|
|
341
|
+
--ui-neutral-separator: #484437;
|
|
342
|
+
--ui-neutral-accent: #facc15;
|
|
343
|
+
--ui-neutral-danger: #f87171;
|
|
344
|
+
--ui-neutral-on-accent: #000000;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
:root[data-season='1'] {
|
|
348
|
+
--ui-season-text-primary: #06423e;
|
|
349
|
+
--ui-season-text-secondary: #437371;
|
|
350
|
+
--ui-season-surface: #e0f0f5;
|
|
351
|
+
--ui-season-surface-raised: #e8f5fe;
|
|
352
|
+
--ui-season-separator: #a4cfe2;
|
|
353
|
+
--ui-season-accent: #04a7ca;
|
|
354
|
+
--ui-season-danger: #b91c1c;
|
|
355
|
+
--ui-season-on-accent: #000000;
|
|
356
|
+
--ui-neutral-text-primary: #111111;
|
|
357
|
+
--ui-neutral-text-secondary: #525455;
|
|
358
|
+
--ui-neutral-surface: #e8eff5;
|
|
359
|
+
--ui-neutral-surface-raised: #f7fcfd;
|
|
360
|
+
--ui-neutral-separator: #c1ced5;
|
|
361
|
+
--ui-neutral-accent: #04a7ca;
|
|
362
|
+
--ui-neutral-danger: #b91c1c;
|
|
363
|
+
--ui-neutral-on-accent: #000000;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
:root[data-season='1'][data-theme='dark'] {
|
|
367
|
+
--ui-season-text-primary: #47bffd;
|
|
368
|
+
--ui-season-text-secondary: #378eba;
|
|
369
|
+
--ui-season-surface: #0f0f0f;
|
|
370
|
+
--ui-season-surface-raised: #171c1c;
|
|
371
|
+
--ui-season-separator: #3c4444;
|
|
372
|
+
--ui-season-accent: #15b5fa;
|
|
373
|
+
--ui-season-danger: #f87171;
|
|
374
|
+
--ui-season-on-accent: #000000;
|
|
375
|
+
--ui-neutral-text-primary: #f2f2f2;
|
|
376
|
+
--ui-neutral-text-secondary: #aaabac;
|
|
377
|
+
--ui-neutral-surface: #01070a;
|
|
378
|
+
--ui-neutral-surface-raised: #1c2125;
|
|
379
|
+
--ui-neutral-separator: #354249;
|
|
380
|
+
--ui-neutral-accent: #15b5fa;
|
|
381
|
+
--ui-neutral-danger: #f87171;
|
|
382
|
+
--ui-neutral-on-accent: #000000;
|
|
383
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// The one source for spacing, radius, type, semantic colour and motion. scripts/generate-tokens.ts
|
|
2
|
+
// turns it into CSS custom properties, Tokens.swift and Tokens.kt; season colours stay in
|
|
3
|
+
// seasons/*/style.css and are referenced here by variable name.
|
|
4
|
+
|
|
5
|
+
/** A 4pt scale. Native names spell the numeric prefixes out (`3xs` → `xxxs`) to stay valid identifiers. */
|
|
6
|
+
export const space = { '3xs': 2, '2xs': 4, xs: 8, sm: 12, md: 16, lg: 24, xl: 32, '2xl': 48, '3xl': 64 } as const
|
|
7
|
+
|
|
8
|
+
export const radius = { sm: 4, md: 8, lg: 16, sheet: 28 } as const
|
|
9
|
+
|
|
10
|
+
export const motion = {
|
|
11
|
+
duration: { fast: 150, base: 250, slow: 400 },
|
|
12
|
+
/** M3's standard easing; reduced motion swaps every transition for an instant or opacity-only change. */
|
|
13
|
+
easing: [0.2, 0, 0, 1],
|
|
14
|
+
} as const
|
|
15
|
+
|
|
16
|
+
/** `Livvic-SemiBold.ttf` → `livvic_semibold`: an Android resource name is lowercase, digits and underscores. */
|
|
17
|
+
export const androidFont = (file: string) => file.replace(/\.ttf$/, '').replace(/-/g, '_').toLowerCase()
|
|
18
|
+
|
|
19
|
+
/** Livvic ships as static weights (no variable file, no 800), one file per weight the roles use. */
|
|
20
|
+
export const typeface = {
|
|
21
|
+
family: 'Livvic',
|
|
22
|
+
dir: 'livvic',
|
|
23
|
+
files: { 400: 'Livvic-Regular.ttf', 500: 'Livvic-Medium.ttf', 600: 'Livvic-SemiBold.ttf', 700: 'Livvic-Bold.ttf', 900: 'Livvic-Black.ttf' },
|
|
24
|
+
} as const
|
|
25
|
+
|
|
26
|
+
export type IosTextStyle = 'largeTitle' | 'title' | 'title2' | 'title3' | 'headline' | 'body' | 'callout' | 'subheadline' | 'footnote' | 'caption' | 'caption2'
|
|
27
|
+
export type M3Slot = 'displayLarge' | 'displayMedium' | 'displaySmall' | 'headlineLarge' | 'headlineMedium' | 'headlineSmall' | 'titleLarge' | 'titleMedium' | 'titleSmall' | 'bodyLarge' | 'bodyMedium' | 'bodySmall' | 'labelLarge' | 'labelMedium' | 'labelSmall'
|
|
28
|
+
|
|
29
|
+
export interface TypeRole {
|
|
30
|
+
/** pt / sp / px at the default text size; native scales it through `ios` and `m3`. */
|
|
31
|
+
size: number
|
|
32
|
+
weight: number
|
|
33
|
+
/** A multiple of size. */
|
|
34
|
+
lineHeight: number
|
|
35
|
+
/** em. */
|
|
36
|
+
tracking: number
|
|
37
|
+
tabular?: boolean
|
|
38
|
+
/** Web only: the responsive step `typography.css` already used, where the role had one. */
|
|
39
|
+
clamp?: string
|
|
40
|
+
ios: IosTextStyle
|
|
41
|
+
m3: M3Slot
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const typeRoles = {
|
|
45
|
+
display: { size: 40, weight: 900, lineHeight: 1.1, tracking: -0.02, clamp: 'clamp(2rem, 5vw, 3.5rem)', ios: 'largeTitle', m3: 'displaySmall' },
|
|
46
|
+
title: { size: 28, weight: 700, lineHeight: 1.15, tracking: -0.01, clamp: 'clamp(1.5rem, 3.5vw, 2.25rem)', ios: 'title', m3: 'headlineMedium' },
|
|
47
|
+
headline: { size: 20, weight: 600, lineHeight: 1.25, tracking: 0, clamp: 'clamp(1.25rem, 2.5vw, 1.75rem)', ios: 'title3', m3: 'titleLarge' },
|
|
48
|
+
body: { size: 16, weight: 400, lineHeight: 1.5, tracking: 0, ios: 'body', m3: 'bodyLarge' },
|
|
49
|
+
label: { size: 14, weight: 500, lineHeight: 1.3, tracking: 0.01, ios: 'subheadline', m3: 'labelLarge' },
|
|
50
|
+
caption: { size: 12, weight: 400, lineHeight: 1.35, tracking: 0.01, ios: 'caption', m3: 'bodySmall' },
|
|
51
|
+
numeral: { size: 16, weight: 500, lineHeight: 1.3, tracking: 0, tabular: true, ios: 'body', m3: 'titleMedium' },
|
|
52
|
+
} as const satisfies Record<string, TypeRole>
|
|
53
|
+
|
|
54
|
+
// The season variables a semantic role can stand on: the names each season's style.css declares.
|
|
55
|
+
export type SeasonVar = '--color-season' | '--color-season-text' | '--color-accent' | '--color-surface' | '--color-border'
|
|
56
|
+
|
|
57
|
+
export type Mode = 'light' | 'dark'
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Two tones, one set of names. `season` is the season's own colour at full strength, for the
|
|
61
|
+
* season track (season, round, question). `neutral` is the platform's own light/dark greys
|
|
62
|
+
* carrying a faint wash of the season's accent, for every page outside it.
|
|
63
|
+
*/
|
|
64
|
+
export const semantic = {
|
|
65
|
+
season: {
|
|
66
|
+
surface: '--color-season',
|
|
67
|
+
surfaceRaised: '--color-surface',
|
|
68
|
+
separator: '--color-border',
|
|
69
|
+
textPrimary: '--color-season-text',
|
|
70
|
+
accent: '--color-accent',
|
|
71
|
+
},
|
|
72
|
+
neutral: {
|
|
73
|
+
base: {
|
|
74
|
+
light: { surface: '#f2f2f7', surfaceRaised: '#ffffff', separator: '#d1d1d6', textPrimary: '#111111' },
|
|
75
|
+
dark: { surface: '#000000', surfaceRaised: '#1c1c1e', separator: '#38383a', textPrimary: '#f2f2f2' },
|
|
76
|
+
},
|
|
77
|
+
/** Share of the season accent mixed into each neutral base. */
|
|
78
|
+
tint: { surface: 0.04, surfaceRaised: 0.03, separator: 0.08, textPrimary: 0 },
|
|
79
|
+
},
|
|
80
|
+
/** text-secondary is text-primary mixed into the surface: this share at the faintest, more where a season needs it to clear 4.5:1. */
|
|
81
|
+
textSecondaryShare: 0.7,
|
|
82
|
+
/** Not a season colour: red-700 / red-400, the reds that clear 4.5:1 on every season surface. */
|
|
83
|
+
danger: { light: '#b91c1c', dark: '#f87171' },
|
|
84
|
+
} as const satisfies {
|
|
85
|
+
season: Record<'surface' | 'surfaceRaised' | 'separator' | 'textPrimary' | 'accent', SeasonVar>
|
|
86
|
+
neutral: { base: Record<Mode, Record<string, string>>; tint: Record<string, number> }
|
|
87
|
+
textSecondaryShare: number
|
|
88
|
+
danger: Record<Mode, string>
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const semanticRoles = ['textPrimary', 'textSecondary', 'surface', 'surfaceRaised', 'separator', 'accent', 'danger', 'onAccent'] as const
|
|
92
|
+
export type SemanticRole = (typeof semanticRoles)[number]
|
|
93
|
+
export type Tone = 'season' | 'neutral'
|
|
Binary file
|