@pokela/tokens 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +50 -0
- package/index.d.ts +327 -0
- package/index.js +326 -0
- package/package.json +32 -0
- package/tokens.css +260 -0
- package/tokens.json +284 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Veli-Matti Pokela
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# @pokela/tokens
|
|
2
|
+
|
|
3
|
+
Design-tokenit: **Pokela Portfolio**, versio 1.1.0.
|
|
4
|
+
|
|
5
|
+
> Tämä paketti on generoitu tiedostosta `tokens.json`. Älä muokkaa sitä
|
|
6
|
+
> käsin — muutokset tehdään lähteeseen ja paketti rakennetaan uudelleen
|
|
7
|
+
> komennolla `npm run paketti`.
|
|
8
|
+
|
|
9
|
+
## Käyttö
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import tokens, { color, space } from '@pokela/tokens';
|
|
13
|
+
import '@pokela/tokens/tokens.css';
|
|
14
|
+
|
|
15
|
+
color.light.ink; // '#101112'
|
|
16
|
+
space['24']; // '24px'
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
CSS-muuttujat tulevat `tokens.css`:stä, esimerkiksi `var(--ink)` ja
|
|
20
|
+
`var(--space-24)`. Teema vaihtuu attribuutilla `data-theme`, ja ilman
|
|
21
|
+
sitä se seuraa käyttöjärjestelmää.
|
|
22
|
+
|
|
23
|
+
## Viennit
|
|
24
|
+
|
|
25
|
+
- `meta`
|
|
26
|
+
- `modes`
|
|
27
|
+
- `color`
|
|
28
|
+
- `font`
|
|
29
|
+
- `type`
|
|
30
|
+
- `typeScale`
|
|
31
|
+
- `lineHeightScale`
|
|
32
|
+
- `weight`
|
|
33
|
+
- `space`
|
|
34
|
+
- `layout`
|
|
35
|
+
- `border`
|
|
36
|
+
- `icon`
|
|
37
|
+
- `motion`
|
|
38
|
+
|
|
39
|
+
## Lisenssi
|
|
40
|
+
|
|
41
|
+
MIT. Koskee tätä pakettia, ei sitä repoa josta se on generoitu.
|
|
42
|
+
|
|
43
|
+
## Moodit
|
|
44
|
+
|
|
45
|
+
Moodi on ulottuvuus jolla tokenin arvo vaihtelee.
|
|
46
|
+
|
|
47
|
+
- `viewport` — base, sm, md, lg
|
|
48
|
+
|
|
49
|
+
Teema (vaalea/tumma) hoituu CSS:ssä `data-theme`-attribuutilla, joten
|
|
50
|
+
sitä ei tarvitse valita koodista.
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/* @pokela/tokens — generoitu tiedostosta tokens.json.
|
|
2
|
+
Älä muokkaa: aja `npm run paketti`. */
|
|
3
|
+
|
|
4
|
+
export declare const meta: {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly version: string;
|
|
7
|
+
readonly direction: string;
|
|
8
|
+
readonly defaultTheme: string;
|
|
9
|
+
readonly source: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Moodiakselit: millä ulottuvuuksilla tokenin arvo vaihtelee. minWidth
|
|
14
|
+
* kertoo myös suunnan — arvot kasvavat alhaalta ylös, eli CSS on
|
|
15
|
+
* mobile-first.
|
|
16
|
+
*/
|
|
17
|
+
export declare const modes: {
|
|
18
|
+
readonly viewport: {
|
|
19
|
+
readonly values: readonly string[];
|
|
20
|
+
readonly minWidth: {
|
|
21
|
+
readonly base: string;
|
|
22
|
+
readonly sm: string;
|
|
23
|
+
readonly md: string;
|
|
24
|
+
readonly lg: string;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export declare const color: {
|
|
30
|
+
readonly light: {
|
|
31
|
+
readonly paper: string;
|
|
32
|
+
readonly "paper-alt": string;
|
|
33
|
+
readonly line: string;
|
|
34
|
+
readonly "line-strong": string;
|
|
35
|
+
readonly ink: string;
|
|
36
|
+
readonly "ink-muted": string;
|
|
37
|
+
readonly "ink-faint": string;
|
|
38
|
+
readonly "badge-surface": string;
|
|
39
|
+
readonly "invert-surface": string;
|
|
40
|
+
readonly "invert-ink": string;
|
|
41
|
+
readonly "invert-faint": string;
|
|
42
|
+
readonly "placeholder-base": string;
|
|
43
|
+
readonly "placeholder-stripe": string;
|
|
44
|
+
readonly "code-surface": string;
|
|
45
|
+
readonly "code-ink": string;
|
|
46
|
+
readonly "code-muted": string;
|
|
47
|
+
readonly "code-faint": string;
|
|
48
|
+
};
|
|
49
|
+
readonly dark: {
|
|
50
|
+
readonly paper: string;
|
|
51
|
+
readonly "paper-alt": string;
|
|
52
|
+
readonly line: string;
|
|
53
|
+
readonly "line-strong": string;
|
|
54
|
+
readonly ink: string;
|
|
55
|
+
readonly "ink-muted": string;
|
|
56
|
+
readonly "ink-faint": string;
|
|
57
|
+
readonly "badge-surface": string;
|
|
58
|
+
readonly "invert-surface": string;
|
|
59
|
+
readonly "invert-ink": string;
|
|
60
|
+
readonly "invert-faint": string;
|
|
61
|
+
readonly "placeholder-base": string;
|
|
62
|
+
readonly "placeholder-stripe": string;
|
|
63
|
+
readonly "code-surface": string;
|
|
64
|
+
readonly "code-ink": string;
|
|
65
|
+
readonly "code-muted": string;
|
|
66
|
+
readonly "code-faint": string;
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Fallback on var():n sisällä — muuten puuttuva next/font-muuttuja tekisi
|
|
72
|
+
* koko määrittelystä epäkelvon.
|
|
73
|
+
*/
|
|
74
|
+
export declare const font: {
|
|
75
|
+
readonly display: string;
|
|
76
|
+
readonly ui: string;
|
|
77
|
+
readonly code: string;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* size/lineHeight ovat lg-arvoja (≥1200px). Pienemmät koot ovat kohdassa
|
|
82
|
+
* typeScale.
|
|
83
|
+
*/
|
|
84
|
+
export declare const type: {
|
|
85
|
+
readonly "display-xl": {
|
|
86
|
+
readonly size: string;
|
|
87
|
+
readonly lineHeight: string;
|
|
88
|
+
readonly tracking: string;
|
|
89
|
+
readonly weight: number;
|
|
90
|
+
readonly font: string;
|
|
91
|
+
readonly note: string;
|
|
92
|
+
};
|
|
93
|
+
readonly "display-l": {
|
|
94
|
+
readonly size: string;
|
|
95
|
+
readonly lineHeight: string;
|
|
96
|
+
readonly tracking: string;
|
|
97
|
+
readonly weight: number;
|
|
98
|
+
readonly font: string;
|
|
99
|
+
readonly note: string;
|
|
100
|
+
};
|
|
101
|
+
readonly "display-m": {
|
|
102
|
+
readonly size: string;
|
|
103
|
+
readonly lineHeight: string;
|
|
104
|
+
readonly tracking: string;
|
|
105
|
+
readonly weight: number;
|
|
106
|
+
readonly font: string;
|
|
107
|
+
readonly note: string;
|
|
108
|
+
};
|
|
109
|
+
readonly "display-s": {
|
|
110
|
+
readonly size: string;
|
|
111
|
+
readonly lineHeight: string;
|
|
112
|
+
readonly tracking: string;
|
|
113
|
+
readonly weight: number;
|
|
114
|
+
readonly font: string;
|
|
115
|
+
readonly note: string;
|
|
116
|
+
};
|
|
117
|
+
readonly "body-l": {
|
|
118
|
+
readonly size: string;
|
|
119
|
+
readonly lineHeight: string;
|
|
120
|
+
readonly weight: number;
|
|
121
|
+
readonly font: string;
|
|
122
|
+
};
|
|
123
|
+
readonly body: {
|
|
124
|
+
readonly size: string;
|
|
125
|
+
readonly lineHeight: string;
|
|
126
|
+
readonly weight: number;
|
|
127
|
+
readonly font: string;
|
|
128
|
+
};
|
|
129
|
+
readonly "body-s": {
|
|
130
|
+
readonly size: string;
|
|
131
|
+
readonly lineHeight: string;
|
|
132
|
+
readonly weight: number;
|
|
133
|
+
readonly font: string;
|
|
134
|
+
};
|
|
135
|
+
readonly meta: {
|
|
136
|
+
readonly size: string;
|
|
137
|
+
readonly lineHeight: string;
|
|
138
|
+
readonly tracking: string;
|
|
139
|
+
readonly weight: number;
|
|
140
|
+
readonly transform: string;
|
|
141
|
+
readonly font: string;
|
|
142
|
+
};
|
|
143
|
+
readonly "meta-s": {
|
|
144
|
+
readonly size: string;
|
|
145
|
+
readonly lineHeight: string;
|
|
146
|
+
readonly tracking: string;
|
|
147
|
+
readonly weight: number;
|
|
148
|
+
readonly transform: string;
|
|
149
|
+
readonly font: string;
|
|
150
|
+
};
|
|
151
|
+
readonly code: {
|
|
152
|
+
readonly size: string;
|
|
153
|
+
readonly lineHeight: string;
|
|
154
|
+
readonly weight: number;
|
|
155
|
+
readonly font: string;
|
|
156
|
+
readonly note: string;
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export declare const typeScale: {
|
|
161
|
+
readonly "display-xl": {
|
|
162
|
+
readonly base: string;
|
|
163
|
+
readonly sm: string;
|
|
164
|
+
readonly md: string;
|
|
165
|
+
readonly lg: string;
|
|
166
|
+
};
|
|
167
|
+
readonly "display-l": {
|
|
168
|
+
readonly base: string;
|
|
169
|
+
readonly sm: string;
|
|
170
|
+
readonly md: string;
|
|
171
|
+
readonly lg: string;
|
|
172
|
+
};
|
|
173
|
+
readonly "display-m": {
|
|
174
|
+
readonly base: string;
|
|
175
|
+
readonly sm: string;
|
|
176
|
+
readonly md: string;
|
|
177
|
+
readonly lg: string;
|
|
178
|
+
};
|
|
179
|
+
readonly "display-s": {
|
|
180
|
+
readonly base: string;
|
|
181
|
+
readonly sm: string;
|
|
182
|
+
readonly md: string;
|
|
183
|
+
readonly lg: string;
|
|
184
|
+
};
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Rivivälit breakpointeittain. Vain xl ja l muuttuvat (lg-tasolla
|
|
189
|
+
* tiukempi).
|
|
190
|
+
*/
|
|
191
|
+
export declare const lineHeightScale: {
|
|
192
|
+
readonly "display-xl": {
|
|
193
|
+
readonly base: string;
|
|
194
|
+
readonly sm: string;
|
|
195
|
+
readonly md: string;
|
|
196
|
+
readonly lg: string;
|
|
197
|
+
};
|
|
198
|
+
readonly "display-l": {
|
|
199
|
+
readonly base: string;
|
|
200
|
+
readonly sm: string;
|
|
201
|
+
readonly md: string;
|
|
202
|
+
readonly lg: string;
|
|
203
|
+
};
|
|
204
|
+
readonly "display-m": {
|
|
205
|
+
readonly base: string;
|
|
206
|
+
readonly sm: string;
|
|
207
|
+
readonly md: string;
|
|
208
|
+
readonly lg: string;
|
|
209
|
+
};
|
|
210
|
+
readonly "display-s": {
|
|
211
|
+
readonly base: string;
|
|
212
|
+
readonly sm: string;
|
|
213
|
+
readonly md: string;
|
|
214
|
+
readonly lg: string;
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Nimi = arvo. Vain ladatut leikkaukset: Archivo 400/500/600, Bodoni
|
|
220
|
+
* 400/500.
|
|
221
|
+
*/
|
|
222
|
+
export declare const weight: {
|
|
223
|
+
readonly "400": number;
|
|
224
|
+
readonly "500": number;
|
|
225
|
+
readonly "600": number;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Nimetty arvon mukaan: --space-24 on 24px. 32/40/48 lisättiin v1.1:ssä
|
|
230
|
+
* koska sivupohjat käyttivät niitä skaalan ulkopuolelta.
|
|
231
|
+
*/
|
|
232
|
+
export declare const space: {
|
|
233
|
+
readonly "4": string;
|
|
234
|
+
readonly "8": string;
|
|
235
|
+
readonly "12": string;
|
|
236
|
+
readonly "16": string;
|
|
237
|
+
readonly "20": string;
|
|
238
|
+
readonly "24": string;
|
|
239
|
+
readonly "28": string;
|
|
240
|
+
readonly "32": string;
|
|
241
|
+
readonly "36": string;
|
|
242
|
+
readonly "40": string;
|
|
243
|
+
readonly "44": string;
|
|
244
|
+
readonly "48": string;
|
|
245
|
+
readonly "56": string;
|
|
246
|
+
readonly "72": string;
|
|
247
|
+
readonly "96": string;
|
|
248
|
+
readonly "128": string;
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Lukumittoja on yksi: measure (62ch). Se riittää myös 14 pikselin
|
|
253
|
+
* tekstille, koska ch skaalautuu fonttikoon mukana — sama luku tarkoittaa
|
|
254
|
+
* suunnilleen samaa merkkimäärää joka koossa. Kaikki muut ch-arvot
|
|
255
|
+
* sivustolla olivat taittovarmistuksia eivätkä lukumittoja, ja ne on
|
|
256
|
+
* kirjoitettu pikseleiksi. Harvennettuun metatekstiin ch ei sovi lainkaan:
|
|
257
|
+
* se ei tunne letter-spacingia, joten 68ch lupasi 68 merkkiä mutta riville
|
|
258
|
+
* mahtui 35.
|
|
259
|
+
*/
|
|
260
|
+
export declare const layout: {
|
|
261
|
+
readonly maxWidth: string;
|
|
262
|
+
readonly pagePadding: {
|
|
263
|
+
readonly base: string;
|
|
264
|
+
readonly sm: string;
|
|
265
|
+
readonly md: string;
|
|
266
|
+
readonly lg: string;
|
|
267
|
+
};
|
|
268
|
+
readonly columns: {
|
|
269
|
+
readonly base: number;
|
|
270
|
+
readonly sm: number;
|
|
271
|
+
readonly md: number;
|
|
272
|
+
readonly lg: number;
|
|
273
|
+
};
|
|
274
|
+
readonly gutter: {
|
|
275
|
+
readonly base: string;
|
|
276
|
+
readonly sm: string;
|
|
277
|
+
readonly md: string;
|
|
278
|
+
readonly lg: string;
|
|
279
|
+
};
|
|
280
|
+
readonly sectionGap: {
|
|
281
|
+
readonly base: string;
|
|
282
|
+
readonly sm: string;
|
|
283
|
+
readonly md: string;
|
|
284
|
+
readonly lg: string;
|
|
285
|
+
};
|
|
286
|
+
readonly tapMin: string;
|
|
287
|
+
readonly measure: string;
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
export declare const border: {
|
|
291
|
+
readonly hairline: string;
|
|
292
|
+
readonly hairlineStrong: string;
|
|
293
|
+
readonly radius: string;
|
|
294
|
+
readonly focusWidth: string;
|
|
295
|
+
readonly focusOffset: string;
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Ikonit piirretään 16×16-ruudukolle ja skaalataan näihin kolmeen kokoon.
|
|
300
|
+
* Viivanpaksuus ei ole oma tokeninsa vaan border.hairline — ikoni on
|
|
301
|
+
* piirretty samalla viivalla kuin jokainen reuna. Kaaria ei ole
|
|
302
|
+
* (border.radius on 0), joten päätteet ovat tylpät ja kulmat terävät.
|
|
303
|
+
*/
|
|
304
|
+
export declare const icon: {
|
|
305
|
+
readonly s: string;
|
|
306
|
+
readonly m: string;
|
|
307
|
+
readonly l: string;
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
export declare const motion: {
|
|
311
|
+
readonly duration: {
|
|
312
|
+
readonly fast: string;
|
|
313
|
+
readonly base: string;
|
|
314
|
+
readonly slow: string;
|
|
315
|
+
readonly reveal: string;
|
|
316
|
+
};
|
|
317
|
+
readonly easing: {
|
|
318
|
+
readonly standard: string;
|
|
319
|
+
readonly out: string;
|
|
320
|
+
};
|
|
321
|
+
readonly reveal: {
|
|
322
|
+
readonly translate: string;
|
|
323
|
+
};
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
declare const _default: { meta: typeof meta; modes: typeof modes; color: typeof color; font: typeof font; type: typeof type; typeScale: typeof typeScale; lineHeightScale: typeof lineHeightScale; weight: typeof weight; space: typeof space; layout: typeof layout; border: typeof border; icon: typeof icon; motion: typeof motion };
|
|
327
|
+
export default _default;
|
package/index.js
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/* @pokela/tokens — generoitu tiedostosta tokens.json.
|
|
2
|
+
Älä muokkaa: aja `npm run paketti`. */
|
|
3
|
+
|
|
4
|
+
export const meta = {
|
|
5
|
+
name: "Pokela Portfolio",
|
|
6
|
+
version: "1.1.0",
|
|
7
|
+
direction: "1f / 1g — editorial grotesk layout with didone display",
|
|
8
|
+
defaultTheme: "system (light-dark), override via data-theme",
|
|
9
|
+
source: "styles/tokens.css — tämä tiedosto on sen koneluettava peili. scripts/check-tokens.mjs valvoo vastaavuutta.",
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Moodiakselit: millä ulottuvuuksilla tokenin arvo vaihtelee. minWidth
|
|
14
|
+
* kertoo myös suunnan — arvot kasvavat alhaalta ylös, eli CSS on
|
|
15
|
+
* mobile-first.
|
|
16
|
+
*/
|
|
17
|
+
export const modes = {
|
|
18
|
+
viewport: {
|
|
19
|
+
values: ["base", "sm", "md", "lg"],
|
|
20
|
+
minWidth: {
|
|
21
|
+
base: "0",
|
|
22
|
+
sm: "600px",
|
|
23
|
+
md: "900px",
|
|
24
|
+
lg: "1200px",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const color = {
|
|
30
|
+
light: {
|
|
31
|
+
paper: "#FFFFFF",
|
|
32
|
+
"paper-alt": "#FAFAF8",
|
|
33
|
+
line: "#E8E8E6",
|
|
34
|
+
"line-strong": "#101112",
|
|
35
|
+
ink: "#101112",
|
|
36
|
+
"ink-muted": "#45464A",
|
|
37
|
+
"ink-faint": "#6A6C6E",
|
|
38
|
+
"badge-surface": "#EDEDEA",
|
|
39
|
+
"invert-surface": "#101112",
|
|
40
|
+
"invert-ink": "#F4F4F2",
|
|
41
|
+
"invert-faint": "#B6B8BA",
|
|
42
|
+
"placeholder-base": "#EFEFEC",
|
|
43
|
+
"placeholder-stripe": "#E7E7E3",
|
|
44
|
+
"code-surface": "#101112",
|
|
45
|
+
"code-ink": "#F4F4F2",
|
|
46
|
+
"code-muted": "#A8ABAD",
|
|
47
|
+
"code-faint": "#8A8D90",
|
|
48
|
+
},
|
|
49
|
+
dark: {
|
|
50
|
+
paper: "#0E0F10",
|
|
51
|
+
"paper-alt": "#16181A",
|
|
52
|
+
line: "#262829",
|
|
53
|
+
"line-strong": "#F4F4F2",
|
|
54
|
+
ink: "#F4F4F2",
|
|
55
|
+
"ink-muted": "#B9BCBF",
|
|
56
|
+
"ink-faint": "#9A9DA1",
|
|
57
|
+
"badge-surface": "#232527",
|
|
58
|
+
"invert-surface": "#F4F4F2",
|
|
59
|
+
"invert-ink": "#0E0F10",
|
|
60
|
+
"invert-faint": "#4A4C4E",
|
|
61
|
+
"placeholder-base": "#1B1D1F",
|
|
62
|
+
"placeholder-stripe": "#16181A",
|
|
63
|
+
"code-surface": "#1B1D1F",
|
|
64
|
+
"code-ink": "#F4F4F2",
|
|
65
|
+
"code-muted": "#A8ABAD",
|
|
66
|
+
"code-faint": "#8A8D90",
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Fallback on var():n sisällä — muuten puuttuva next/font-muuttuja tekisi
|
|
72
|
+
* koko määrittelystä epäkelvon.
|
|
73
|
+
*/
|
|
74
|
+
export const font = {
|
|
75
|
+
display: "var(--font-bodoni, 'Bodoni Moda'), Georgia, serif",
|
|
76
|
+
ui: "var(--font-archivo, 'Archivo'), Helvetica, Arial, sans-serif",
|
|
77
|
+
code: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* size/lineHeight ovat lg-arvoja (≥1200px). Pienemmät koot ovat kohdassa
|
|
82
|
+
* typeScale.
|
|
83
|
+
*/
|
|
84
|
+
export const type = {
|
|
85
|
+
"display-xl": {
|
|
86
|
+
size: "136px",
|
|
87
|
+
lineHeight: "0.88",
|
|
88
|
+
tracking: "-0.02em",
|
|
89
|
+
weight: 400,
|
|
90
|
+
font: "display",
|
|
91
|
+
note: "wordmark / etusivun nimi",
|
|
92
|
+
},
|
|
93
|
+
"display-l": {
|
|
94
|
+
size: "82px",
|
|
95
|
+
lineHeight: "0.96",
|
|
96
|
+
tracking: "-0.005em",
|
|
97
|
+
weight: 400,
|
|
98
|
+
font: "display",
|
|
99
|
+
note: "footer-CTA, casesivun otsikko",
|
|
100
|
+
},
|
|
101
|
+
"display-m": {
|
|
102
|
+
size: "46px",
|
|
103
|
+
lineHeight: "1.12",
|
|
104
|
+
tracking: "-0.005em",
|
|
105
|
+
weight: 400,
|
|
106
|
+
font: "display",
|
|
107
|
+
note: "väitelause, osion otsikko",
|
|
108
|
+
},
|
|
109
|
+
"display-s": {
|
|
110
|
+
size: "38px",
|
|
111
|
+
lineHeight: "1",
|
|
112
|
+
tracking: "-0.005em",
|
|
113
|
+
weight: 400,
|
|
114
|
+
font: "display",
|
|
115
|
+
note: "indeksirivin työn nimi",
|
|
116
|
+
},
|
|
117
|
+
"body-l": {
|
|
118
|
+
size: "17px",
|
|
119
|
+
lineHeight: "1.65",
|
|
120
|
+
weight: 400,
|
|
121
|
+
font: "ui",
|
|
122
|
+
},
|
|
123
|
+
body: {
|
|
124
|
+
size: "16px",
|
|
125
|
+
lineHeight: "1.65",
|
|
126
|
+
weight: 400,
|
|
127
|
+
font: "ui",
|
|
128
|
+
},
|
|
129
|
+
"body-s": {
|
|
130
|
+
size: "14px",
|
|
131
|
+
lineHeight: "1.6",
|
|
132
|
+
weight: 400,
|
|
133
|
+
font: "ui",
|
|
134
|
+
},
|
|
135
|
+
meta: {
|
|
136
|
+
size: "11px",
|
|
137
|
+
lineHeight: "1.4",
|
|
138
|
+
tracking: "0.16em",
|
|
139
|
+
weight: 600,
|
|
140
|
+
transform: "uppercase",
|
|
141
|
+
font: "ui",
|
|
142
|
+
},
|
|
143
|
+
"meta-s": {
|
|
144
|
+
size: "10px",
|
|
145
|
+
lineHeight: "1.4",
|
|
146
|
+
tracking: "0.2em",
|
|
147
|
+
weight: 600,
|
|
148
|
+
transform: "uppercase",
|
|
149
|
+
font: "ui",
|
|
150
|
+
},
|
|
151
|
+
code: {
|
|
152
|
+
size: "13px",
|
|
153
|
+
lineHeight: "1.5",
|
|
154
|
+
weight: 400,
|
|
155
|
+
font: "code",
|
|
156
|
+
note: "koodilohko ja inline-koodi",
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export const typeScale = {
|
|
161
|
+
"display-xl": {
|
|
162
|
+
base: "52px",
|
|
163
|
+
sm: "76px",
|
|
164
|
+
md: "104px",
|
|
165
|
+
lg: "136px",
|
|
166
|
+
},
|
|
167
|
+
"display-l": {
|
|
168
|
+
base: "40px",
|
|
169
|
+
sm: "52px",
|
|
170
|
+
md: "64px",
|
|
171
|
+
lg: "82px",
|
|
172
|
+
},
|
|
173
|
+
"display-m": {
|
|
174
|
+
base: "28px",
|
|
175
|
+
sm: "34px",
|
|
176
|
+
md: "40px",
|
|
177
|
+
lg: "46px",
|
|
178
|
+
},
|
|
179
|
+
"display-s": {
|
|
180
|
+
base: "26px",
|
|
181
|
+
sm: "30px",
|
|
182
|
+
md: "34px",
|
|
183
|
+
lg: "38px",
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Rivivälit breakpointeittain. Vain xl ja l muuttuvat (lg-tasolla
|
|
189
|
+
* tiukempi).
|
|
190
|
+
*/
|
|
191
|
+
export const lineHeightScale = {
|
|
192
|
+
"display-xl": {
|
|
193
|
+
base: "0.92",
|
|
194
|
+
sm: "0.92",
|
|
195
|
+
md: "0.92",
|
|
196
|
+
lg: "0.88",
|
|
197
|
+
},
|
|
198
|
+
"display-l": {
|
|
199
|
+
base: "1",
|
|
200
|
+
sm: "1",
|
|
201
|
+
md: "1",
|
|
202
|
+
lg: "0.96",
|
|
203
|
+
},
|
|
204
|
+
"display-m": {
|
|
205
|
+
base: "1.12",
|
|
206
|
+
sm: "1.12",
|
|
207
|
+
md: "1.12",
|
|
208
|
+
lg: "1.12",
|
|
209
|
+
},
|
|
210
|
+
"display-s": {
|
|
211
|
+
base: "1",
|
|
212
|
+
sm: "1",
|
|
213
|
+
md: "1",
|
|
214
|
+
lg: "1",
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Nimi = arvo. Vain ladatut leikkaukset: Archivo 400/500/600, Bodoni
|
|
220
|
+
* 400/500.
|
|
221
|
+
*/
|
|
222
|
+
export const weight = {
|
|
223
|
+
"400": 400,
|
|
224
|
+
"500": 500,
|
|
225
|
+
"600": 600,
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Nimetty arvon mukaan: --space-24 on 24px. 32/40/48 lisättiin v1.1:ssä
|
|
230
|
+
* koska sivupohjat käyttivät niitä skaalan ulkopuolelta.
|
|
231
|
+
*/
|
|
232
|
+
export const space = {
|
|
233
|
+
"4": "4px",
|
|
234
|
+
"8": "8px",
|
|
235
|
+
"12": "12px",
|
|
236
|
+
"16": "16px",
|
|
237
|
+
"20": "20px",
|
|
238
|
+
"24": "24px",
|
|
239
|
+
"28": "28px",
|
|
240
|
+
"32": "32px",
|
|
241
|
+
"36": "36px",
|
|
242
|
+
"40": "40px",
|
|
243
|
+
"44": "44px",
|
|
244
|
+
"48": "48px",
|
|
245
|
+
"56": "56px",
|
|
246
|
+
"72": "72px",
|
|
247
|
+
"96": "96px",
|
|
248
|
+
"128": "128px",
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Lukumittoja on yksi: measure (62ch). Se riittää myös 14 pikselin
|
|
253
|
+
* tekstille, koska ch skaalautuu fonttikoon mukana — sama luku tarkoittaa
|
|
254
|
+
* suunnilleen samaa merkkimäärää joka koossa. Kaikki muut ch-arvot
|
|
255
|
+
* sivustolla olivat taittovarmistuksia eivätkä lukumittoja, ja ne on
|
|
256
|
+
* kirjoitettu pikseleiksi. Harvennettuun metatekstiin ch ei sovi lainkaan:
|
|
257
|
+
* se ei tunne letter-spacingia, joten 68ch lupasi 68 merkkiä mutta riville
|
|
258
|
+
* mahtui 35.
|
|
259
|
+
*/
|
|
260
|
+
export const layout = {
|
|
261
|
+
maxWidth: "1440px",
|
|
262
|
+
pagePadding: {
|
|
263
|
+
base: "20px",
|
|
264
|
+
sm: "24px",
|
|
265
|
+
md: "28px",
|
|
266
|
+
lg: "36px",
|
|
267
|
+
},
|
|
268
|
+
columns: {
|
|
269
|
+
base: 4,
|
|
270
|
+
sm: 8,
|
|
271
|
+
md: 12,
|
|
272
|
+
lg: 12,
|
|
273
|
+
},
|
|
274
|
+
gutter: {
|
|
275
|
+
base: "16px",
|
|
276
|
+
sm: "20px",
|
|
277
|
+
md: "24px",
|
|
278
|
+
lg: "24px",
|
|
279
|
+
},
|
|
280
|
+
sectionGap: {
|
|
281
|
+
base: "48px",
|
|
282
|
+
sm: "64px",
|
|
283
|
+
md: "80px",
|
|
284
|
+
lg: "96px",
|
|
285
|
+
},
|
|
286
|
+
tapMin: "44px",
|
|
287
|
+
measure: "62ch",
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
export const border = {
|
|
291
|
+
hairline: "1px",
|
|
292
|
+
hairlineStrong: "2px",
|
|
293
|
+
radius: "0px",
|
|
294
|
+
focusWidth: "2px",
|
|
295
|
+
focusOffset: "2px",
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Ikonit piirretään 16×16-ruudukolle ja skaalataan näihin kolmeen kokoon.
|
|
300
|
+
* Viivanpaksuus ei ole oma tokeninsa vaan border.hairline — ikoni on
|
|
301
|
+
* piirretty samalla viivalla kuin jokainen reuna. Kaaria ei ole
|
|
302
|
+
* (border.radius on 0), joten päätteet ovat tylpät ja kulmat terävät.
|
|
303
|
+
*/
|
|
304
|
+
export const icon = {
|
|
305
|
+
s: "12px",
|
|
306
|
+
m: "16px",
|
|
307
|
+
l: "24px",
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
export const motion = {
|
|
311
|
+
duration: {
|
|
312
|
+
fast: "180ms",
|
|
313
|
+
base: "220ms",
|
|
314
|
+
slow: "320ms",
|
|
315
|
+
reveal: "600ms",
|
|
316
|
+
},
|
|
317
|
+
easing: {
|
|
318
|
+
standard: "cubic-bezier(0.2, 0.8, 0.2, 1)",
|
|
319
|
+
out: "cubic-bezier(0.16, 1, 0.3, 1)",
|
|
320
|
+
},
|
|
321
|
+
reveal: {
|
|
322
|
+
translate: "12px",
|
|
323
|
+
},
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
export default { meta, modes, color, font, type, typeScale, lineHeightScale, weight, space, layout, border, icon, motion };
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pokela/tokens",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Design-tokenit: Pokela Portfolio. Generoitu, ei käsin ylläpidetty.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Veli-Matti Pokela",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"sideEffects": [
|
|
9
|
+
"*.css"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./index.d.ts",
|
|
14
|
+
"import": "./index.js"
|
|
15
|
+
},
|
|
16
|
+
"./tokens.css": "./tokens.css",
|
|
17
|
+
"./tokens.json": "./tokens.json"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"index.js",
|
|
21
|
+
"index.d.ts",
|
|
22
|
+
"tokens.css",
|
|
23
|
+
"tokens.json",
|
|
24
|
+
"README.md",
|
|
25
|
+
"LICENSE"
|
|
26
|
+
],
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/VeliMattiPokela/pokela.fi.git",
|
|
30
|
+
"directory": "packages/tokens"
|
|
31
|
+
}
|
|
32
|
+
}
|
package/tokens.css
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/* Pokela — design tokens
|
|
2
|
+
------------------------------------------------------------------
|
|
3
|
+
Väriarvot määritellään kerran parina (-l / -d). Teemanvaihto vain
|
|
4
|
+
uudelleenohjaa eikä sisällä yhtään väriarvoa, joten vaalea ja
|
|
5
|
+
tumma eivät voi ajautua erilleen.
|
|
6
|
+
|
|
7
|
+
Aksenttiväriä ei ole. Korostus = musta/valkoinen-käännös
|
|
8
|
+
(--invert-surface / --invert-ink) tai hiljainen --badge-surface.
|
|
9
|
+
Väri sivulle tulee vain työn kuvista.
|
|
10
|
+
|
|
11
|
+
Mobile first: :root on mobiilikoko, min-width kasvattaa.
|
|
12
|
+
Arvojen lähde: tokens.json. scripts/check-tokens.mjs valvoo että
|
|
13
|
+
nämä kaksi pysyvät samana.
|
|
14
|
+
|
|
15
|
+
Fontit (Google Fonts, OFL): Bodoni Moda 400/500, Archivo 400/500/600.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
:root {
|
|
19
|
+
color-scheme: light;
|
|
20
|
+
|
|
21
|
+
/* ---- type ------------------------------------------------------
|
|
22
|
+
--font-bodoni / --font-archivo tulevat next/fontista (itse
|
|
23
|
+
tarjoiltu, ei ulkoista pyyntöä).
|
|
24
|
+
|
|
25
|
+
Fallback on var()-funktion SISÄLLÄ, ei sen perässä. Jos
|
|
26
|
+
--font-bodoni puuttuu, `var(--font-bodoni), 'Bodoni Moda'`
|
|
27
|
+
tekisi koko määrittelystä epäkelvon (invalid at computed-value
|
|
28
|
+
time) ja typografia putoaisi selaimen oletusfonttiin ilman
|
|
29
|
+
virhettä. Tämä muoto kestää sen. */
|
|
30
|
+
--font-display: var(--font-bodoni, 'Bodoni Moda'), Georgia, serif;
|
|
31
|
+
--font-ui: var(--font-archivo, 'Archivo'), Helvetica, Arial, sans-serif;
|
|
32
|
+
/* Koodi on sivustolla toistuva elementti (komponenttinäkymä, /system,
|
|
33
|
+
Storybook), joten sen pino on token eikä viisi kertaa kirjoitettu
|
|
34
|
+
lista — joista yksi ehti jo erota muista. */
|
|
35
|
+
--font-code: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
36
|
+
|
|
37
|
+
/* MOBILE FIRST: base = 360–599 px. Isommat koot min-width-kyselyissä. */
|
|
38
|
+
--text-display-xl: 52px; --lh-display-xl: 0.92; --tr-display-xl: -0.02em;
|
|
39
|
+
--text-display-l: 40px; --lh-display-l: 1; --tr-display-l: -0.005em;
|
|
40
|
+
--text-display-m: 28px; --lh-display-m: 1.12; --tr-display-m: -0.005em;
|
|
41
|
+
--text-display-s: 26px; --lh-display-s: 1; --tr-display-s: -0.005em;
|
|
42
|
+
--text-body-l: 17px; --lh-body-l: 1.65;
|
|
43
|
+
--text-body: 16px; --lh-body: 1.65; /* älä laske alle 16px: iOS zoomaa inputit */
|
|
44
|
+
--text-body-s: 14px; --lh-body-s: 1.6;
|
|
45
|
+
--text-meta: 11px; --lh-meta: 1.4; --tr-meta: 0.16em;
|
|
46
|
+
--text-meta-s: 10px; --lh-meta-s: 1.4; --tr-meta-s: 0.2em;
|
|
47
|
+
--text-code: 13px; --lh-code: 1.5; /* monospace on optisesti isompi kuin body-s */
|
|
48
|
+
/* Paino on asteikko, koska ladattuja leikkauksia on vain kolme:
|
|
49
|
+
Archivo 400/500/600, Bodoni 400/500. font-synthesis-weight on
|
|
50
|
+
pois päältä, joten ladatun ulkopuolinen paino ei lihavoi vaan
|
|
51
|
+
jää huomaamatta. Nimi on arvo, kuten välistysasteikossa. */
|
|
52
|
+
--weight-400: 400;
|
|
53
|
+
--weight-500: 500;
|
|
54
|
+
--weight-600: 600;
|
|
55
|
+
--measure: 62ch; /* lukumitta — ainoa, myös 14px-tekstille */
|
|
56
|
+
|
|
57
|
+
/* ---- space (4px perusyksikkö) ----------------------------------
|
|
58
|
+
Nimetty arvon mukaan, ei juoksevalla numerolla: --space-24 on
|
|
59
|
+
24px eikä vaadi taulukon muistamista. 32 / 40 / 48 lisättiin
|
|
60
|
+
koska sivupohjat käyttävät niitä — aiemmin ne jäivät skaalan
|
|
61
|
+
ulkopuolelle ja päätyivät kovakoodatuiksi. */
|
|
62
|
+
--space-4: 4px; --space-8: 8px; --space-12: 12px; --space-16: 16px;
|
|
63
|
+
--space-20: 20px; --space-24: 24px; --space-28: 28px; --space-32: 32px;
|
|
64
|
+
--space-36: 36px; --space-40: 40px; --space-44: 44px; --space-48: 48px;
|
|
65
|
+
--space-56: 56px; --space-72: 72px; --space-96: 96px; --space-128: 128px;
|
|
66
|
+
|
|
67
|
+
/* ---- layout ---------------------------------------------------- */
|
|
68
|
+
--max-width: 1440px;
|
|
69
|
+
--page-padding: 20px;
|
|
70
|
+
--columns: 4;
|
|
71
|
+
--gutter: 16px;
|
|
72
|
+
--section-gap: 48px;
|
|
73
|
+
--tap-min: 44px;
|
|
74
|
+
--hairline: 1px;
|
|
75
|
+
/* Korostettu viiva: hoverin ja valitun tilan paksuus. Sama arvo
|
|
76
|
+
kuin --focus-width, mutta eri asia — focus on saavutettavuutta,
|
|
77
|
+
tämä on typografiaa, ja ne saavat muuttua toisistaan riippumatta. */
|
|
78
|
+
--hairline-strong: 2px;
|
|
79
|
+
--radius: 0px;
|
|
80
|
+
--focus-width: 2px;
|
|
81
|
+
--focus-offset: 2px;
|
|
82
|
+
|
|
83
|
+
/* ---- ikonit ------------------------------------------------------
|
|
84
|
+
Ikonit piirretään 16×16-ruudukolle ja skaalataan näihin kolmeen
|
|
85
|
+
kokoon. Viivanpaksuutta ei ole tässä: se on --hairline, sama viiva
|
|
86
|
+
jolla jokainen reuna piirretään. Ks. styles/components/icon.css. */
|
|
87
|
+
--icon-s: 12px;
|
|
88
|
+
--icon-m: 16px;
|
|
89
|
+
--icon-l: 24px;
|
|
90
|
+
|
|
91
|
+
/* ---- motion ---------------------------------------------------- */
|
|
92
|
+
--dur-fast: 180ms; --dur-base: 220ms; --dur-slow: 320ms; --dur-reveal: 600ms;
|
|
93
|
+
--ease-standard: cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
94
|
+
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
|
|
95
|
+
--reveal-shift: 12px;
|
|
96
|
+
|
|
97
|
+
/* ---- colour ----------------------------------------------------
|
|
98
|
+
Arvot määritellään KERRAN parina: -l on vaalea, -d tumma.
|
|
99
|
+
Teemanvaihto alla vain uudelleenohjaa, eikä sisällä yhtään
|
|
100
|
+
väriarvoa — siksi vaalea ja tumma eivät voi ajautua erilleen.
|
|
101
|
+
|
|
102
|
+
Miksi ei light-dark(): Next 16:n Lightning CSS transpiloi sen
|
|
103
|
+
omaksi polyfillikseen, joka reagoi vain käyttöjärjestelmän
|
|
104
|
+
prefers-color-schemeen. Nimenomainen data-theme-valinta jäisi
|
|
105
|
+
silloin tehottomaksi ja teksti näkymättömiin. Tämä muoto toimii
|
|
106
|
+
kaikkialla eikä riipu käännösketjusta.
|
|
107
|
+
|
|
108
|
+
scripts/check-tokens.mjs valvoo että jokaisella tokenilla on
|
|
109
|
+
molemmat arvot ja että molemmat vaihtolohkot kattavat saman
|
|
110
|
+
listan. */
|
|
111
|
+
--paper-l: #FFFFFF; --paper-d: #0E0F10;
|
|
112
|
+
--paper-alt-l: #FAFAF8; --paper-alt-d: #16181A;
|
|
113
|
+
--line-l: #E8E8E6; --line-d: #262829;
|
|
114
|
+
--line-strong-l: #101112; --line-strong-d: #F4F4F2;
|
|
115
|
+
--ink-l: #101112; --ink-d: #F4F4F2;
|
|
116
|
+
--ink-muted-l: #45464A; --ink-muted-d: #B9BCBF;
|
|
117
|
+
--ink-faint-l: #6A6C6E; --ink-faint-d: #9A9DA1;
|
|
118
|
+
--badge-surface-l: #EDEDEA; --badge-surface-d: #232527;
|
|
119
|
+
--invert-surface-l: #101112; --invert-surface-d: #F4F4F2;
|
|
120
|
+
--invert-ink-l: #F4F4F2; --invert-ink-d: #0E0F10;
|
|
121
|
+
--invert-faint-l: #B6B8BA; --invert-faint-d: #4A4C4E;
|
|
122
|
+
--placeholder-base-l: #EFEFEC; --placeholder-base-d: #1B1D1F;
|
|
123
|
+
--placeholder-stripe-l: #E7E7E3; --placeholder-stripe-d: #16181A;
|
|
124
|
+
|
|
125
|
+
/* Koodipaneeli. Tumma molemmissa teemoissa: koodi on oma
|
|
126
|
+
artefaktinsa, ei leipätekstiä, ja tumma pinta on se mitä lukija
|
|
127
|
+
odottaa koodilta. Vaaleassa teemassa se on käännetty pinta,
|
|
128
|
+
tummassa hieman paperista nostettu. Musteet ovat samat
|
|
129
|
+
molemmilla, joten korostuksen kartta ei muutu teeman mukana. */
|
|
130
|
+
--code-surface-l: #101112; --code-surface-d: #1B1D1F;
|
|
131
|
+
--code-ink-l: #F4F4F2; --code-ink-d: #F4F4F2;
|
|
132
|
+
--code-muted-l: #A8ABAD; --code-muted-d: #A8ABAD;
|
|
133
|
+
--code-faint-l: #8A8D90; --code-faint-d: #8A8D90;
|
|
134
|
+
|
|
135
|
+
/* Oletus: vaalea. */
|
|
136
|
+
--paper: var(--paper-l);
|
|
137
|
+
--paper-alt: var(--paper-alt-l);
|
|
138
|
+
--line: var(--line-l);
|
|
139
|
+
--line-strong: var(--line-strong-l);
|
|
140
|
+
--ink: var(--ink-l);
|
|
141
|
+
--ink-muted: var(--ink-muted-l);
|
|
142
|
+
--ink-faint: var(--ink-faint-l);
|
|
143
|
+
--badge-surface: var(--badge-surface-l);
|
|
144
|
+
--invert-surface: var(--invert-surface-l);
|
|
145
|
+
--invert-ink: var(--invert-ink-l);
|
|
146
|
+
--invert-faint: var(--invert-faint-l);
|
|
147
|
+
--placeholder-base: var(--placeholder-base-l);
|
|
148
|
+
--placeholder-stripe: var(--placeholder-stripe-l);
|
|
149
|
+
--code-surface: var(--code-surface-l);
|
|
150
|
+
--code-ink: var(--code-ink-l);
|
|
151
|
+
--code-muted: var(--code-muted-l);
|
|
152
|
+
--code-faint: var(--code-faint-l);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* Tumma paletti. Sama lista kahdesti, mutta ilman yhtäkään
|
|
156
|
+
väriarvoa — vain uudelleenohjaus. */
|
|
157
|
+
:root[data-theme='dark'] {
|
|
158
|
+
color-scheme: dark;
|
|
159
|
+
--paper: var(--paper-d);
|
|
160
|
+
--paper-alt: var(--paper-alt-d);
|
|
161
|
+
--line: var(--line-d);
|
|
162
|
+
--line-strong: var(--line-strong-d);
|
|
163
|
+
--ink: var(--ink-d);
|
|
164
|
+
--ink-muted: var(--ink-muted-d);
|
|
165
|
+
--ink-faint: var(--ink-faint-d);
|
|
166
|
+
--badge-surface: var(--badge-surface-d);
|
|
167
|
+
--invert-surface: var(--invert-surface-d);
|
|
168
|
+
--invert-ink: var(--invert-ink-d);
|
|
169
|
+
--invert-faint: var(--invert-faint-d);
|
|
170
|
+
--placeholder-base: var(--placeholder-base-d);
|
|
171
|
+
--placeholder-stripe: var(--placeholder-stripe-d);
|
|
172
|
+
--code-surface: var(--code-surface-d);
|
|
173
|
+
--code-ink: var(--code-ink-d);
|
|
174
|
+
--code-muted: var(--code-muted-d);
|
|
175
|
+
--code-faint: var(--code-faint-d);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/* Ilman nimenomaista valintaa seurataan käyttöjärjestelmää. */
|
|
179
|
+
@media (prefers-color-scheme: dark) {
|
|
180
|
+
:root:not([data-theme='light']) {
|
|
181
|
+
color-scheme: dark;
|
|
182
|
+
--paper: var(--paper-d);
|
|
183
|
+
--paper-alt: var(--paper-alt-d);
|
|
184
|
+
--line: var(--line-d);
|
|
185
|
+
--line-strong: var(--line-strong-d);
|
|
186
|
+
--ink: var(--ink-d);
|
|
187
|
+
--ink-muted: var(--ink-muted-d);
|
|
188
|
+
--ink-faint: var(--ink-faint-d);
|
|
189
|
+
--badge-surface: var(--badge-surface-d);
|
|
190
|
+
--invert-surface: var(--invert-surface-d);
|
|
191
|
+
--invert-ink: var(--invert-ink-d);
|
|
192
|
+
--invert-faint: var(--invert-faint-d);
|
|
193
|
+
--placeholder-base: var(--placeholder-base-d);
|
|
194
|
+
--placeholder-stripe: var(--placeholder-stripe-d);
|
|
195
|
+
--code-surface: var(--code-surface-d);
|
|
196
|
+
--code-ink: var(--code-ink-d);
|
|
197
|
+
--code-muted: var(--code-muted-d);
|
|
198
|
+
--code-faint: var(--code-faint-d);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
:root[data-theme='light'] { color-scheme: light; }
|
|
203
|
+
|
|
204
|
+
/* ---- paperi -------------------------------------------------------
|
|
205
|
+
Sama uudelleenkytkentä kuin tummalla teemalla, mutta medialle eikä
|
|
206
|
+
mieltymykselle. Ilman tätä tummalla teemalla tulostettaisiin
|
|
207
|
+
valkoinen teksti valkoiselle paperille: selain ei tulosta taustoja,
|
|
208
|
+
joten pinta katoaa mutta teksti ei vaihda väriä.
|
|
209
|
+
|
|
210
|
+
Viivat ovat paperilla tummempia kuin ruudulla. #E8E8E6 on ruudulla
|
|
211
|
+
juuri sopiva hiusviiva, mutta painossa se katoaa. */
|
|
212
|
+
@media print {
|
|
213
|
+
:root,
|
|
214
|
+
:root[data-theme='dark'],
|
|
215
|
+
:root[data-theme='light'] {
|
|
216
|
+
color-scheme: light;
|
|
217
|
+
--paper: #ffffff;
|
|
218
|
+
--paper-alt: #ffffff;
|
|
219
|
+
--line: #b8b8b4;
|
|
220
|
+
--line-strong: #101112;
|
|
221
|
+
--ink: #101112;
|
|
222
|
+
--ink-muted: #3a3b3e;
|
|
223
|
+
--ink-faint: #56585a;
|
|
224
|
+
--badge-surface: #ffffff;
|
|
225
|
+
--invert-surface: #ffffff;
|
|
226
|
+
--invert-ink: #101112;
|
|
227
|
+
--invert-faint: #56585a;
|
|
228
|
+
--placeholder-base: #f2f2f0;
|
|
229
|
+
--placeholder-stripe: #e9e9e6;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/* ---- breakpoints (mobile first, min-width) ------------------------
|
|
234
|
+
base 0–599 4 saraketta, padding 20, yksi palsta
|
|
235
|
+
sm 600 8 saraketta, padding 24
|
|
236
|
+
md 900 12 saraketta, padding 28
|
|
237
|
+
lg 1200 12 saraketta, padding 36, täysi editoriaalinen skaala
|
|
238
|
+
*/
|
|
239
|
+
@media (min-width: 600px) {
|
|
240
|
+
:root {
|
|
241
|
+
--page-padding: 24px; --columns: 8; --gutter: 20px; --section-gap: 64px;
|
|
242
|
+
--text-display-xl: 76px; --text-display-l: 52px;
|
|
243
|
+
--text-display-m: 34px; --text-display-s: 30px;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
@media (min-width: 900px) {
|
|
247
|
+
:root {
|
|
248
|
+
--page-padding: 28px; --columns: 12; --gutter: 24px; --section-gap: 80px;
|
|
249
|
+
--text-display-xl: 104px; --text-display-l: 64px;
|
|
250
|
+
--text-display-m: 40px; --text-display-s: 34px;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
@media (min-width: 1200px) {
|
|
254
|
+
:root {
|
|
255
|
+
--page-padding: 36px; --section-gap: 96px;
|
|
256
|
+
--text-display-xl: 136px; --lh-display-xl: 0.88;
|
|
257
|
+
--text-display-l: 82px; --lh-display-l: 0.96;
|
|
258
|
+
--text-display-m: 46px; --text-display-s: 38px;
|
|
259
|
+
}
|
|
260
|
+
}
|
package/tokens.json
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$meta": {
|
|
3
|
+
"name": "Pokela Portfolio",
|
|
4
|
+
"version": "1.1.0",
|
|
5
|
+
"direction": "1f / 1g — editorial grotesk layout with didone display",
|
|
6
|
+
"defaultTheme": "system (light-dark), override via data-theme",
|
|
7
|
+
"source": "styles/tokens.css — tämä tiedosto on sen koneluettava peili. scripts/check-tokens.mjs valvoo vastaavuutta."
|
|
8
|
+
},
|
|
9
|
+
"$modes": {
|
|
10
|
+
"$note": "Moodiakselit: millä ulottuvuuksilla tokenin arvo vaihtelee. minWidth kertoo myös suunnan — arvot kasvavat alhaalta ylös, eli CSS on mobile-first.",
|
|
11
|
+
"viewport": {
|
|
12
|
+
"values": [
|
|
13
|
+
"base",
|
|
14
|
+
"sm",
|
|
15
|
+
"md",
|
|
16
|
+
"lg"
|
|
17
|
+
],
|
|
18
|
+
"minWidth": {
|
|
19
|
+
"base": "0",
|
|
20
|
+
"sm": "600px",
|
|
21
|
+
"md": "900px",
|
|
22
|
+
"lg": "1200px"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"color": {
|
|
27
|
+
"light": {
|
|
28
|
+
"paper": "#FFFFFF",
|
|
29
|
+
"paper-alt": "#FAFAF8",
|
|
30
|
+
"line": "#E8E8E6",
|
|
31
|
+
"line-strong": "#101112",
|
|
32
|
+
"ink": "#101112",
|
|
33
|
+
"ink-muted": "#45464A",
|
|
34
|
+
"ink-faint": "#6A6C6E",
|
|
35
|
+
"badge-surface": "#EDEDEA",
|
|
36
|
+
"invert-surface": "#101112",
|
|
37
|
+
"invert-ink": "#F4F4F2",
|
|
38
|
+
"invert-faint": "#B6B8BA",
|
|
39
|
+
"placeholder-base": "#EFEFEC",
|
|
40
|
+
"placeholder-stripe": "#E7E7E3",
|
|
41
|
+
"code-surface": "#101112",
|
|
42
|
+
"code-ink": "#F4F4F2",
|
|
43
|
+
"code-muted": "#A8ABAD",
|
|
44
|
+
"code-faint": "#8A8D90"
|
|
45
|
+
},
|
|
46
|
+
"dark": {
|
|
47
|
+
"paper": "#0E0F10",
|
|
48
|
+
"paper-alt": "#16181A",
|
|
49
|
+
"line": "#262829",
|
|
50
|
+
"line-strong": "#F4F4F2",
|
|
51
|
+
"ink": "#F4F4F2",
|
|
52
|
+
"ink-muted": "#B9BCBF",
|
|
53
|
+
"ink-faint": "#9A9DA1",
|
|
54
|
+
"badge-surface": "#232527",
|
|
55
|
+
"invert-surface": "#F4F4F2",
|
|
56
|
+
"invert-ink": "#0E0F10",
|
|
57
|
+
"invert-faint": "#4A4C4E",
|
|
58
|
+
"placeholder-base": "#1B1D1F",
|
|
59
|
+
"placeholder-stripe": "#16181A",
|
|
60
|
+
"code-surface": "#1B1D1F",
|
|
61
|
+
"code-ink": "#F4F4F2",
|
|
62
|
+
"code-muted": "#A8ABAD",
|
|
63
|
+
"code-faint": "#8A8D90"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"font": {
|
|
67
|
+
"display": "var(--font-bodoni, 'Bodoni Moda'), Georgia, serif",
|
|
68
|
+
"ui": "var(--font-archivo, 'Archivo'), Helvetica, Arial, sans-serif",
|
|
69
|
+
"$note": "Fallback on var():n sisällä — muuten puuttuva next/font-muuttuja tekisi koko määrittelystä epäkelvon.",
|
|
70
|
+
"code": "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace"
|
|
71
|
+
},
|
|
72
|
+
"typeNote": "size/lineHeight ovat lg-arvoja (≥1200px). Pienemmät koot ovat kohdassa typeScale.",
|
|
73
|
+
"type": {
|
|
74
|
+
"display-xl": {
|
|
75
|
+
"size": "136px",
|
|
76
|
+
"lineHeight": "0.88",
|
|
77
|
+
"tracking": "-0.02em",
|
|
78
|
+
"weight": 400,
|
|
79
|
+
"font": "display",
|
|
80
|
+
"note": "wordmark / etusivun nimi"
|
|
81
|
+
},
|
|
82
|
+
"display-l": {
|
|
83
|
+
"size": "82px",
|
|
84
|
+
"lineHeight": "0.96",
|
|
85
|
+
"tracking": "-0.005em",
|
|
86
|
+
"weight": 400,
|
|
87
|
+
"font": "display",
|
|
88
|
+
"note": "footer-CTA, casesivun otsikko"
|
|
89
|
+
},
|
|
90
|
+
"display-m": {
|
|
91
|
+
"size": "46px",
|
|
92
|
+
"lineHeight": "1.12",
|
|
93
|
+
"tracking": "-0.005em",
|
|
94
|
+
"weight": 400,
|
|
95
|
+
"font": "display",
|
|
96
|
+
"note": "väitelause, osion otsikko"
|
|
97
|
+
},
|
|
98
|
+
"display-s": {
|
|
99
|
+
"size": "38px",
|
|
100
|
+
"lineHeight": "1",
|
|
101
|
+
"tracking": "-0.005em",
|
|
102
|
+
"weight": 400,
|
|
103
|
+
"font": "display",
|
|
104
|
+
"note": "indeksirivin työn nimi"
|
|
105
|
+
},
|
|
106
|
+
"body-l": {
|
|
107
|
+
"size": "17px",
|
|
108
|
+
"lineHeight": "1.65",
|
|
109
|
+
"weight": 400,
|
|
110
|
+
"font": "ui"
|
|
111
|
+
},
|
|
112
|
+
"body": {
|
|
113
|
+
"size": "16px",
|
|
114
|
+
"lineHeight": "1.65",
|
|
115
|
+
"weight": 400,
|
|
116
|
+
"font": "ui"
|
|
117
|
+
},
|
|
118
|
+
"body-s": {
|
|
119
|
+
"size": "14px",
|
|
120
|
+
"lineHeight": "1.6",
|
|
121
|
+
"weight": 400,
|
|
122
|
+
"font": "ui"
|
|
123
|
+
},
|
|
124
|
+
"meta": {
|
|
125
|
+
"size": "11px",
|
|
126
|
+
"lineHeight": "1.4",
|
|
127
|
+
"tracking": "0.16em",
|
|
128
|
+
"weight": 600,
|
|
129
|
+
"transform": "uppercase",
|
|
130
|
+
"font": "ui"
|
|
131
|
+
},
|
|
132
|
+
"meta-s": {
|
|
133
|
+
"size": "10px",
|
|
134
|
+
"lineHeight": "1.4",
|
|
135
|
+
"tracking": "0.2em",
|
|
136
|
+
"weight": 600,
|
|
137
|
+
"transform": "uppercase",
|
|
138
|
+
"font": "ui"
|
|
139
|
+
},
|
|
140
|
+
"code": {
|
|
141
|
+
"size": "13px",
|
|
142
|
+
"lineHeight": "1.5",
|
|
143
|
+
"weight": 400,
|
|
144
|
+
"font": "code",
|
|
145
|
+
"note": "koodilohko ja inline-koodi"
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
"weight": {
|
|
149
|
+
"400": 400,
|
|
150
|
+
"500": 500,
|
|
151
|
+
"600": 600
|
|
152
|
+
},
|
|
153
|
+
"weightNote": "Nimi = arvo. Vain ladatut leikkaukset: Archivo 400/500/600, Bodoni 400/500.",
|
|
154
|
+
"typeScale": {
|
|
155
|
+
"display-xl": {
|
|
156
|
+
"base": "52px",
|
|
157
|
+
"sm": "76px",
|
|
158
|
+
"md": "104px",
|
|
159
|
+
"lg": "136px"
|
|
160
|
+
},
|
|
161
|
+
"display-l": {
|
|
162
|
+
"base": "40px",
|
|
163
|
+
"sm": "52px",
|
|
164
|
+
"md": "64px",
|
|
165
|
+
"lg": "82px"
|
|
166
|
+
},
|
|
167
|
+
"display-m": {
|
|
168
|
+
"base": "28px",
|
|
169
|
+
"sm": "34px",
|
|
170
|
+
"md": "40px",
|
|
171
|
+
"lg": "46px"
|
|
172
|
+
},
|
|
173
|
+
"display-s": {
|
|
174
|
+
"base": "26px",
|
|
175
|
+
"sm": "30px",
|
|
176
|
+
"md": "34px",
|
|
177
|
+
"lg": "38px"
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
"space": {
|
|
181
|
+
"4": "4px",
|
|
182
|
+
"8": "8px",
|
|
183
|
+
"12": "12px",
|
|
184
|
+
"16": "16px",
|
|
185
|
+
"20": "20px",
|
|
186
|
+
"24": "24px",
|
|
187
|
+
"28": "28px",
|
|
188
|
+
"32": "32px",
|
|
189
|
+
"36": "36px",
|
|
190
|
+
"40": "40px",
|
|
191
|
+
"44": "44px",
|
|
192
|
+
"48": "48px",
|
|
193
|
+
"56": "56px",
|
|
194
|
+
"72": "72px",
|
|
195
|
+
"96": "96px",
|
|
196
|
+
"128": "128px"
|
|
197
|
+
},
|
|
198
|
+
"spaceNote": "Nimetty arvon mukaan: --space-24 on 24px. 32/40/48 lisättiin v1.1:ssä koska sivupohjat käyttivät niitä skaalan ulkopuolelta.",
|
|
199
|
+
"layout": {
|
|
200
|
+
"maxWidth": "1440px",
|
|
201
|
+
"pagePadding": {
|
|
202
|
+
"base": "20px",
|
|
203
|
+
"sm": "24px",
|
|
204
|
+
"md": "28px",
|
|
205
|
+
"lg": "36px"
|
|
206
|
+
},
|
|
207
|
+
"columns": {
|
|
208
|
+
"base": 4,
|
|
209
|
+
"sm": 8,
|
|
210
|
+
"md": 12,
|
|
211
|
+
"lg": 12
|
|
212
|
+
},
|
|
213
|
+
"gutter": {
|
|
214
|
+
"base": "16px",
|
|
215
|
+
"sm": "20px",
|
|
216
|
+
"md": "24px",
|
|
217
|
+
"lg": "24px"
|
|
218
|
+
},
|
|
219
|
+
"sectionGap": {
|
|
220
|
+
"base": "48px",
|
|
221
|
+
"sm": "64px",
|
|
222
|
+
"md": "80px",
|
|
223
|
+
"lg": "96px"
|
|
224
|
+
},
|
|
225
|
+
"tapMin": "44px",
|
|
226
|
+
"measure": "62ch"
|
|
227
|
+
},
|
|
228
|
+
"border": {
|
|
229
|
+
"hairline": "1px",
|
|
230
|
+
"hairlineStrong": "2px",
|
|
231
|
+
"radius": "0px",
|
|
232
|
+
"focusWidth": "2px",
|
|
233
|
+
"focusOffset": "2px"
|
|
234
|
+
},
|
|
235
|
+
"icon": {
|
|
236
|
+
"s": "12px",
|
|
237
|
+
"m": "16px",
|
|
238
|
+
"l": "24px"
|
|
239
|
+
},
|
|
240
|
+
"measureNote": "Lukumittoja on yksi: measure (62ch). Se riittää myös 14 pikselin tekstille, koska ch skaalautuu fonttikoon mukana — sama luku tarkoittaa suunnilleen samaa merkkimäärää joka koossa. Kaikki muut ch-arvot sivustolla olivat taittovarmistuksia eivätkä lukumittoja, ja ne on kirjoitettu pikseleiksi. Harvennettuun metatekstiin ch ei sovi lainkaan: se ei tunne letter-spacingia, joten 68ch lupasi 68 merkkiä mutta riville mahtui 35.",
|
|
241
|
+
"iconNote": "Ikonit piirretään 16×16-ruudukolle ja skaalataan näihin kolmeen kokoon. Viivanpaksuus ei ole oma tokeninsa vaan border.hairline — ikoni on piirretty samalla viivalla kuin jokainen reuna. Kaaria ei ole (border.radius on 0), joten päätteet ovat tylpät ja kulmat terävät.",
|
|
242
|
+
"motion": {
|
|
243
|
+
"duration": {
|
|
244
|
+
"fast": "180ms",
|
|
245
|
+
"base": "220ms",
|
|
246
|
+
"slow": "320ms",
|
|
247
|
+
"reveal": "600ms"
|
|
248
|
+
},
|
|
249
|
+
"easing": {
|
|
250
|
+
"standard": "cubic-bezier(0.2, 0.8, 0.2, 1)",
|
|
251
|
+
"out": "cubic-bezier(0.16, 1, 0.3, 1)"
|
|
252
|
+
},
|
|
253
|
+
"reveal": {
|
|
254
|
+
"translate": "12px"
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
"lineHeightScale": {
|
|
258
|
+
"display-xl": {
|
|
259
|
+
"base": "0.92",
|
|
260
|
+
"sm": "0.92",
|
|
261
|
+
"md": "0.92",
|
|
262
|
+
"lg": "0.88"
|
|
263
|
+
},
|
|
264
|
+
"display-l": {
|
|
265
|
+
"base": "1",
|
|
266
|
+
"sm": "1",
|
|
267
|
+
"md": "1",
|
|
268
|
+
"lg": "0.96"
|
|
269
|
+
},
|
|
270
|
+
"display-m": {
|
|
271
|
+
"base": "1.12",
|
|
272
|
+
"sm": "1.12",
|
|
273
|
+
"md": "1.12",
|
|
274
|
+
"lg": "1.12"
|
|
275
|
+
},
|
|
276
|
+
"display-s": {
|
|
277
|
+
"base": "1",
|
|
278
|
+
"sm": "1",
|
|
279
|
+
"md": "1",
|
|
280
|
+
"lg": "1"
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
"lineHeightNote": "Rivivälit breakpointeittain. Vain xl ja l muuttuvat (lg-tasolla tiukempi)."
|
|
284
|
+
}
|