@pokela/components 2.4.2 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/Timeline.d.ts +32 -0
- package/Timeline.js +24 -0
- package/guidelines/components.md +49 -0
- package/guidelines/setup.md +28 -0
- package/guidelines/styles.md +34 -0
- package/guidelines/tokens.md +18 -0
- package/index.d.ts +2 -0
- package/index.js +1 -0
- package/package.json +3 -2
- package/styles/timeline.css +39 -0
- package/styles.css +1 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @pokela/components
|
|
2
2
|
|
|
3
|
-
React-komponentit: **Pokela Design System**, versio 2.
|
|
3
|
+
React-komponentit: **Pokela Design System**, versio 2.5.1.
|
|
4
4
|
|
|
5
5
|
> Generoitu hakemistosta `components/` — samoista tiedostoista joita sivusto
|
|
6
6
|
> ajaa. Älä muokkaa käsin: muutokset tehdään lähteeseen ja paketti
|
|
@@ -21,6 +21,7 @@ tarvita.
|
|
|
21
21
|
- `Icon`
|
|
22
22
|
- `ListRow`
|
|
23
23
|
- `Accordion`
|
|
24
|
+
- `Timeline`
|
|
24
25
|
- `Grid`
|
|
25
26
|
- `Reveal`
|
|
26
27
|
- `ThemeScript`
|
|
@@ -52,6 +53,7 @@ import Link from 'next/link';
|
|
|
52
53
|
- `styles/icon.css`
|
|
53
54
|
- `styles/list-row.css`
|
|
54
55
|
- `styles/accordion.css`
|
|
56
|
+
- `styles/timeline.css`
|
|
55
57
|
|
|
56
58
|
Luokat ovat globaaleja, eivät CSS-moduuleja. Se on tarkoituksellista: sama
|
|
57
59
|
luokka on myös Figmassa komponentin nimenä, ja hajautettu nimi katkaisisi
|
package/Timeline.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Aikajana.
|
|
4
|
+
* ---------------------------------------------------------------
|
|
5
|
+
* Pystysuora jana: vasemmalla merkintä (aika, päivä, numero), keskellä
|
|
6
|
+
* kisko ja piste, oikealla otsikko, sivutieto ja kuvaus. Merkintä,
|
|
7
|
+
* kisko ja sisältö ovat listan ruudukon sarakkeita, jotta merkinnät
|
|
8
|
+
* asettuvat samaan linjaan; siksi `TimelineItem` piirretään aina
|
|
9
|
+
* `Timeline`-listan sisällä.
|
|
10
|
+
*
|
|
11
|
+
* `variant`:
|
|
12
|
+
* default ohut kisko, ontto piste
|
|
13
|
+
* emphasis paksu kisko ja täytetty piste: nostettu kohta
|
|
14
|
+
* end kisko päättyy pisteeseen: viimeinen kohta
|
|
15
|
+
*
|
|
16
|
+
* `weight` (0–1) venyttää kohdan kiskoa. Sillä pitkä vaihe näkyy jo
|
|
17
|
+
* pituudestaan, esimerkiksi keston osuutena koko ajasta.
|
|
18
|
+
*/
|
|
19
|
+
export default function Timeline({ children, className }: {
|
|
20
|
+
children: ReactNode;
|
|
21
|
+
className?: string;
|
|
22
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
export type TimelineVariant = 'default' | 'emphasis' | 'end';
|
|
24
|
+
export declare function TimelineItem({ label, title, meta, description, group, variant, weight, }: {
|
|
25
|
+
label: string;
|
|
26
|
+
title: string;
|
|
27
|
+
meta?: string | null;
|
|
28
|
+
description?: string | null;
|
|
29
|
+
group?: string | null;
|
|
30
|
+
variant?: TimelineVariant;
|
|
31
|
+
weight?: number;
|
|
32
|
+
}): import("react/jsx-runtime").JSX.Element;
|
package/Timeline.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Aikajana.
|
|
4
|
+
* ---------------------------------------------------------------
|
|
5
|
+
* Pystysuora jana: vasemmalla merkintä (aika, päivä, numero), keskellä
|
|
6
|
+
* kisko ja piste, oikealla otsikko, sivutieto ja kuvaus. Merkintä,
|
|
7
|
+
* kisko ja sisältö ovat listan ruudukon sarakkeita, jotta merkinnät
|
|
8
|
+
* asettuvat samaan linjaan; siksi `TimelineItem` piirretään aina
|
|
9
|
+
* `Timeline`-listan sisällä.
|
|
10
|
+
*
|
|
11
|
+
* `variant`:
|
|
12
|
+
* default ohut kisko, ontto piste
|
|
13
|
+
* emphasis paksu kisko ja täytetty piste: nostettu kohta
|
|
14
|
+
* end kisko päättyy pisteeseen: viimeinen kohta
|
|
15
|
+
*
|
|
16
|
+
* `weight` (0–1) venyttää kohdan kiskoa. Sillä pitkä vaihe näkyy jo
|
|
17
|
+
* pituudestaan, esimerkiksi keston osuutena koko ajasta.
|
|
18
|
+
*/
|
|
19
|
+
export default function Timeline({ children, className }) {
|
|
20
|
+
return _jsx("ol", { className: ['timeline', className].filter(Boolean).join(' '), children: children });
|
|
21
|
+
}
|
|
22
|
+
export function TimelineItem({ label, title, meta, description, group, variant = 'default', weight = 0, }) {
|
|
23
|
+
return (_jsxs("li", { className: ['timeline__item', variant === 'default' ? '' : `timeline__item--${variant}`].join(' '), style: { '--weight': weight.toFixed(3) }, children: [_jsx("span", { className: "meta faint timeline__label", children: label }), _jsx("span", { className: "timeline__rail", "aria-hidden": "true" }), _jsxs("span", { className: "timeline__body", children: [group ? _jsx("span", { className: "meta faint", children: group }) : null, _jsxs("span", { className: "timeline__head", children: [_jsx("span", { className: "body-l", children: title }), meta ? _jsx("span", { className: "meta faint", children: meta }) : null] }), description ? _jsx("span", { className: "body-s muted", children: description }) : null] })] }));
|
|
24
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Components
|
|
2
|
+
|
|
3
|
+
Use these instead of building an equivalent.
|
|
4
|
+
|
|
5
|
+
<!-- generated:make-komponentit -->
|
|
6
|
+
- `Icon`, `ICON_NAMES`
|
|
7
|
+
- `ListRow`
|
|
8
|
+
- `Accordion`, `useAccordionGroup`
|
|
9
|
+
- `Timeline`, `TimelineItem`
|
|
10
|
+
- `Grid`, `Col`
|
|
11
|
+
- `Reveal`
|
|
12
|
+
- `ThemeScript`, `THEME_STORAGE_KEY`
|
|
13
|
+
- `ThemeToggle`
|
|
14
|
+
<!-- /generated -->
|
|
15
|
+
|
|
16
|
+
`ListRow` is the signature component. Use it for any list of items — a work
|
|
17
|
+
list, an index, a menu. Its three visual variants are modifiers on one row,
|
|
18
|
+
not separate components.
|
|
19
|
+
|
|
20
|
+
`ListRow` renders a plain `<a>`. In a router-based app, pass the router's link
|
|
21
|
+
component instead:
|
|
22
|
+
|
|
23
|
+
```jsx
|
|
24
|
+
<ListRow as={Link} title="Work title" href="/work/example" />
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
To show a row as selected, use `className="invert"` — not a new colour.
|
|
28
|
+
|
|
29
|
+
`ListRow` already applies `bleed` itself. Do not pass it again in `className`.
|
|
30
|
+
|
|
31
|
+
`Accordion` is the same row as a `<button>`. Use it when the row expands
|
|
32
|
+
rather than navigates. Only one may be open at a time; `useAccordionGroup`
|
|
33
|
+
handles that.
|
|
34
|
+
|
|
35
|
+
`Timeline` is a vertical list of dated or timed items. Put `TimelineItem`s
|
|
36
|
+
inside it; the labels line up because they share the list's grid. Use
|
|
37
|
+
`variant="emphasis"` for the one item that matters most and `variant="end"`
|
|
38
|
+
for the last. `weight` (0–1) stretches an item's rail, e.g. by its share of
|
|
39
|
+
the total duration.
|
|
40
|
+
|
|
41
|
+
```jsx
|
|
42
|
+
<Timeline>
|
|
43
|
+
<TimelineItem label="0.00" title="Tokens" meta="under a second" />
|
|
44
|
+
<TimelineItem label="0.03" title="Images" meta="5 min 32 s" variant="emphasis" weight={0.9} />
|
|
45
|
+
<TimelineItem label="5.35" title="Site built" variant="end" />
|
|
46
|
+
</Timeline>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`Reveal` fades its children in on scroll. Wrap sections, not single elements.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Setup
|
|
2
|
+
|
|
3
|
+
Install **both** packages as direct dependencies, at the same, latest
|
|
4
|
+
version. `@pokela/components` uses the tokens of the same release.
|
|
5
|
+
|
|
6
|
+
Import the stylesheet once, in the app entry:
|
|
7
|
+
|
|
8
|
+
```js
|
|
9
|
+
import '@pokela/components/styles.css';
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
It pulls in the tokens. Do not import the tokens stylesheet separately.
|
|
13
|
+
|
|
14
|
+
Load the two typefaces from Google Fonts, once, in the document head. The
|
|
15
|
+
tokens fall back to them by name (`--font-display` → Bodoni Moda,
|
|
16
|
+
`--font-ui` → Archivo); without them the page renders in Georgia and
|
|
17
|
+
Helvetica.
|
|
18
|
+
|
|
19
|
+
<!-- generated:make-fontit -->
|
|
20
|
+
```html
|
|
21
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
22
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
23
|
+
<link href="https://fonts.googleapis.com/css2?family=Archivo:wght@400;500;600&family=Bodoni+Moda:wght@400;500&display=swap" rel="stylesheet">
|
|
24
|
+
```
|
|
25
|
+
<!-- /generated -->
|
|
26
|
+
|
|
27
|
+
Component props are typed. Read them from the package — they are not repeated
|
|
28
|
+
in these guidelines, because a copy would go stale.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Styles
|
|
2
|
+
|
|
3
|
+
**Do not use Tailwind utility classes for design system values.** This system
|
|
4
|
+
is plain CSS: global classes that come with the components, and CSS variables
|
|
5
|
+
for values. Writing `bg-blue-500` or `rounded-lg` bypasses the system and
|
|
6
|
+
produces the wrong result.
|
|
7
|
+
|
|
8
|
+
## Headings
|
|
9
|
+
|
|
10
|
+
Typography classes set the look, not the meaning. A page heading is an `<h1>`,
|
|
11
|
+
a section heading an `<h2>`, and so on — never a `<p>` carrying a display
|
|
12
|
+
class. The class and the element are two separate decisions, and a screen
|
|
13
|
+
reader only hears the element.
|
|
14
|
+
|
|
15
|
+
```jsx
|
|
16
|
+
<h1 className="display-xl">Selected work</h1>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Typography
|
|
20
|
+
|
|
21
|
+
Two families. `--font-display` (Bodoni Moda, a serif) is for display sizes
|
|
22
|
+
only — headings and the wordmark. `--font-ui` (Archivo) is for everything
|
|
23
|
+
else. Never set body text in the display face.
|
|
24
|
+
|
|
25
|
+
<!-- generated:make-painot -->**No font weight other than 400, 500 or 600.**<!-- /generated --> Only those are loaded, and
|
|
26
|
+
`font-synthesis-weight` is `none`, so any other weight silently renders wrong.
|
|
27
|
+
|
|
28
|
+
## Layout
|
|
29
|
+
|
|
30
|
+
<!-- generated:make-sarakkeet -->`Grid` is 12 columns: 4 on mobile, 8 from 600px, 12 from 900px.<!-- /generated --> Place
|
|
31
|
+
things in columns, never in pixels. `Col` takes the span per breakpoint.
|
|
32
|
+
|
|
33
|
+
**No icon libraries and no emoji.** Use `Icon`. <!-- generated:make-ikonit -->It draws its own 6 marks<!-- /generated --> on
|
|
34
|
+
a 16×16 grid with the same hairline as every border.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Tokens
|
|
2
|
+
|
|
3
|
+
Use CSS variables for every value: `var(--ink)`, `var(--space-24)`,
|
|
4
|
+
`var(--hairline)`. Never write a raw colour, length or font weight.
|
|
5
|
+
|
|
6
|
+
**No accent colour.** This system has none. Emphasis is a black and white
|
|
7
|
+
inversion — `--invert-surface` with `--invert-ink` — or the quiet
|
|
8
|
+
`--badge-surface`. Do not introduce a brand blue, a primary green, or any
|
|
9
|
+
coloured button. Colour on the page comes only from photographs.
|
|
10
|
+
|
|
11
|
+
**No shadows.** There are no shadow tokens. Separation is a 1px line
|
|
12
|
+
(`--hairline`), never elevation.
|
|
13
|
+
|
|
14
|
+
**No rounded corners.** `--radius` is `0`. Everything is square.
|
|
15
|
+
|
|
16
|
+
<!-- generated:make-valit -->**No spacing outside the scale.** 16 steps, each named by its value:<!-- /generated -->
|
|
17
|
+
`--space-24` is 24px. If a value is missing, use the nearest step rather than
|
|
18
|
+
inventing one.
|
package/index.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export { default as ListRow } from './ListRow.js';
|
|
|
4
4
|
export type { ListRowProps } from './ListRow.js';
|
|
5
5
|
export { Accordion, useAccordionGroup } from './Accordion.js';
|
|
6
6
|
export type { AccordionProps } from './Accordion.js';
|
|
7
|
+
export { default as Timeline, TimelineItem } from './Timeline.js';
|
|
8
|
+
export type { TimelineVariant } from './Timeline.js';
|
|
7
9
|
export { Grid, Col } from './Grid.js';
|
|
8
10
|
export { default as Reveal } from './Reveal.js';
|
|
9
11
|
export { default as ThemeScript, THEME_STORAGE_KEY } from './ThemeScript.js';
|
package/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
export { default as Icon, ICON_NAMES } from './Icon.js';
|
|
3
3
|
export { default as ListRow } from './ListRow.js';
|
|
4
4
|
export { Accordion, useAccordionGroup } from './Accordion.js';
|
|
5
|
+
export { default as Timeline, TimelineItem } from './Timeline.js';
|
|
5
6
|
export { Grid, Col } from './Grid.js';
|
|
6
7
|
export { default as Reveal } from './Reveal.js';
|
|
7
8
|
export { default as ThemeScript, THEME_STORAGE_KEY } from './ThemeScript.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pokela/components",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.1",
|
|
4
4
|
"description": "React-komponentit: Pokela Design System. Generoitu tiedostoista components/, ei käsin ylläpidetty.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Veli-Matti Pokela",
|
|
@@ -21,11 +21,12 @@
|
|
|
21
21
|
"*.d.ts",
|
|
22
22
|
"styles.css",
|
|
23
23
|
"styles/",
|
|
24
|
+
"guidelines/",
|
|
24
25
|
"README.md",
|
|
25
26
|
"LICENSE"
|
|
26
27
|
],
|
|
27
28
|
"dependencies": {
|
|
28
|
-
"@pokela/tokens": "^2.
|
|
29
|
+
"@pokela/tokens": "^2.5.1"
|
|
29
30
|
},
|
|
30
31
|
"peerDependencies": {
|
|
31
32
|
"react": ">=18"
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/* Aikajana (components/Timeline.tsx). Merkintä, kisko ja sisältö ovat
|
|
2
|
+
listan ruudukon sarakkeita, jotta merkinnät asettuvat samaan
|
|
3
|
+
linjaan; kohta itse on display: contents. Kisko venyy kohdan
|
|
4
|
+
painon mukaan (--weight): pitkä vaihe näkyy jo pituudestaan. */
|
|
5
|
+
.timeline {
|
|
6
|
+
display: grid;
|
|
7
|
+
grid-template-columns: max-content var(--space-16) minmax(0, 1fr);
|
|
8
|
+
column-gap: var(--space-16);
|
|
9
|
+
margin: 0; padding: 0; list-style: none;
|
|
10
|
+
}
|
|
11
|
+
.timeline__item { display: contents; }
|
|
12
|
+
.timeline__label { text-align: right; font-variant-numeric: tabular-nums; }
|
|
13
|
+
.timeline__rail { position: relative; }
|
|
14
|
+
.timeline__rail::before {
|
|
15
|
+
content: ''; position: absolute; top: 0; bottom: 0;
|
|
16
|
+
left: calc(50% - var(--hairline) / 2);
|
|
17
|
+
border-left: var(--hairline) solid var(--line);
|
|
18
|
+
}
|
|
19
|
+
.timeline__rail::after {
|
|
20
|
+
content: ''; position: absolute; top: var(--space-4);
|
|
21
|
+
left: calc(50% - var(--space-4));
|
|
22
|
+
width: var(--space-8); height: var(--space-8);
|
|
23
|
+
border-radius: 50%;
|
|
24
|
+
border: var(--hairline) solid var(--ink);
|
|
25
|
+
background: var(--paper);
|
|
26
|
+
}
|
|
27
|
+
.timeline__body {
|
|
28
|
+
display: flex; flex-direction: column; gap: var(--space-4);
|
|
29
|
+
padding-bottom: calc(var(--space-24) + var(--space-56) * 4 * var(--weight, 0));
|
|
30
|
+
}
|
|
31
|
+
.timeline__head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-16); }
|
|
32
|
+
.timeline__item--emphasis .timeline__rail::before {
|
|
33
|
+
left: calc(50% - var(--hairline-strong) / 2);
|
|
34
|
+
border-left: var(--hairline-strong) solid var(--ink);
|
|
35
|
+
}
|
|
36
|
+
.timeline__item--emphasis .timeline__rail::after { background: var(--ink); }
|
|
37
|
+
.timeline__item--end .timeline__rail::before { bottom: auto; height: var(--space-4); }
|
|
38
|
+
.timeline__item--end .timeline__rail::after { background: var(--ink); }
|
|
39
|
+
.timeline__item--end .timeline__body { padding-bottom: 0; }
|
package/styles.css
CHANGED