@felloinnovations/brand-kit 0.5.0 → 0.5.3
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/AGENTS.md +29 -9
- package/CHANGELOG.md +110 -0
- package/README.md +14 -6
- package/design-system/01-how-claude-decides.md +5 -3
- package/design-system/03-colour.md +22 -3
- package/design-system/05-space-and-layout.md +2 -1
- package/design-system/08-choosing-components.md +20 -4
- package/design-system/09-charts.md +7 -4
- package/design-system/10-patterns.md +1 -1
- package/design-system/11-page-recipes.md +40 -1
- package/design-system/13-motion.md +4 -4
- package/design-system/15-ai-experiences.md +11 -0
- package/design-system/17-decisions.md +51 -0
- package/design-system/components/AppShell/README.md +89 -21
- package/design-system/components/AppShell/preview.html +148 -3
- package/design-system/components/AppShell/style.css +47 -0
- package/design-system/components/Avatar/README.md +6 -3
- package/design-system/components/Avatar/preview.html +2 -1
- package/design-system/components/Avatar/style.css +3 -0
- package/design-system/components/Banner/README.md +9 -5
- package/design-system/components/Banner/preview.html +9 -0
- package/design-system/components/Banner/style.css +3 -0
- package/design-system/components/Button/README.md +29 -2
- package/design-system/components/Button/preview.html +33 -1
- package/design-system/components/Button/style.css +21 -0
- package/design-system/components/Calendar/README.md +148 -0
- package/design-system/components/Calendar/preview.html +449 -0
- package/design-system/components/Calendar/style.css +61 -0
- package/design-system/components/Card/README.md +13 -0
- package/design-system/components/Card/preview.html +23 -0
- package/design-system/components/Card/style.css +19 -0
- package/design-system/components/ChatCard/README.md +74 -3
- package/design-system/components/ChatCard/preview.html +126 -25
- package/design-system/components/ChatCard/style.css +6 -0
- package/design-system/components/CheckRow/README.md +1 -1
- package/design-system/components/CheckRow/preview.html +1 -1
- package/design-system/components/CheckRow/style.css +1 -1
- package/design-system/components/Chip/README.md +16 -7
- package/design-system/components/Chip/preview.html +25 -1
- package/design-system/components/Chip/style.css +5 -0
- package/design-system/components/Combobox/README.md +10 -4
- package/design-system/components/Combobox/preview.html +19 -4
- package/design-system/components/Combobox/style.css +7 -1
- package/design-system/components/CommentThread/README.md +138 -0
- package/design-system/components/CommentThread/preview.html +134 -0
- package/design-system/components/CommentThread/style.css +41 -0
- package/design-system/components/DateInput/README.md +38 -4
- package/design-system/components/DateInput/preview.html +50 -2
- package/design-system/components/DateInput/style.css +6 -0
- package/design-system/components/Dialog/README.md +26 -3
- package/design-system/components/Dialog/preview.html +80 -0
- package/design-system/components/Dialog/style.css +28 -3
- package/design-system/components/EmptyState/README.md +1 -1
- package/design-system/components/Fold/README.md +21 -0
- package/design-system/components/Fold/preview.html +44 -1
- package/design-system/components/Fold/style.css +30 -0
- package/design-system/components/InlineEdit/README.md +116 -0
- package/design-system/components/InlineEdit/preview.html +135 -0
- package/design-system/components/InlineEdit/style.css +34 -0
- package/design-system/components/Input/README.md +20 -1
- package/design-system/components/Input/preview.html +24 -0
- package/design-system/components/Input/style.css +13 -1
- package/design-system/components/KanbanBoard/README.md +69 -5
- package/design-system/components/KanbanBoard/preview.html +129 -0
- package/design-system/components/KanbanBoard/style.css +32 -1
- package/design-system/components/ListDetail/preview.html +1 -1
- package/design-system/components/Matrix/README.md +1 -1
- package/design-system/components/Matrix/preview.html +1 -1
- package/design-system/components/Motion/README.md +2 -2
- package/design-system/components/Motion/preview.html +8 -8
- package/design-system/components/PlanTimeline/README.md +144 -0
- package/design-system/components/PlanTimeline/preview.html +109 -0
- package/design-system/components/PlanTimeline/style.css +64 -0
- package/design-system/components/README.md +12 -7
- package/design-system/components/ScoreHero/README.md +2 -2
- package/design-system/components/ScoreHero/style.css +1 -1
- package/design-system/components/ShareBar/README.md +1 -1
- package/design-system/components/ShareBar/style.css +1 -1
- package/design-system/components/Skeleton/README.md +82 -17
- package/design-system/components/Skeleton/preview.html +84 -2
- package/design-system/components/Skeleton/style.css +9 -14
- package/design-system/components/Starter/README.md +1 -1
- package/design-system/components/Starter/preview.html +1 -1
- package/design-system/components/Stepper/README.md +81 -5
- package/design-system/components/Stepper/preview.html +64 -1
- package/design-system/components/Stepper/style.css +29 -0
- package/design-system/components/StreakCalendar/README.md +1 -0
- package/design-system/components/Table/README.md +8 -4
- package/design-system/components/Table/preview.html +16 -1
- package/design-system/components/Table/style.css +3 -1
- package/design-system/components/TextDiff/README.md +96 -0
- package/design-system/components/TextDiff/preview.html +42 -0
- package/design-system/components/TextDiff/style.css +21 -0
- package/design-system/components/TickStrip/README.md +1 -1
- package/design-system/components/TickStrip/preview.html +1 -1
- package/design-system/components/TickStrip/style.css +1 -1
- package/design-system/components/Timeline/README.md +4 -2
- package/design-system/components/TrendLine/README.md +38 -7
- package/design-system/components/TrendLine/preview.html +140 -3
- package/design-system/components/TrendLine/style.css +12 -2
- package/design-system/components/Well/README.md +1 -1
- package/design-system/components/Well/style.css +2 -2
- package/design-system/components/_house.css +1 -1
- package/design-system/components/bundle.css +501 -30
- package/design-system/tokens.json +17 -7
- package/dist/fello-core.css +2 -2
- package/dist/fello.css +2 -2
- package/dist/fello.scoped.css +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/scoped.js +2 -2
- package/dist/tokens.d.ts +16 -8
- package/dist/tokens.js +16 -8
- package/package.json +7 -2
- package/scripts/check-drift.mjs +325 -0
- package/scripts/token-model.mjs +2 -1
- package/tokens/_dark.css +3 -2
- package/tokens/_product.css +13 -11
- package/tokens/palettes.ts +1 -1
- package/tokens/shadcn-compat.css +1 -1
- package/tokens/shadcn-compat.hsl.css +1 -1
- package/tokens/tokens.css +23 -15
- package/tokens/tokens.md +56 -50
- package/tokens/tokens.root.css +23 -15
- package/tokens/tokens.ts +17 -9
|
@@ -1,30 +1,46 @@
|
|
|
1
|
-
A ghost of what is coming, in the shape it will take, with North's shimmer
|
|
1
|
+
A ghost of what is coming, in the shape it will take, with North's shimmer passing over it in one quiet grey, so
|
|
2
2
|
nothing jumps when the real content lands.
|
|
3
3
|
|
|
4
4
|
## Use it when
|
|
5
5
|
|
|
6
6
|
- A card, a row or a line of text has not loaded yet, and the layout it will take is already known.
|
|
7
|
-
- A whole page is loading (
|
|
7
|
+
- A whole page is loading its data (a dashboard, an account's page): the page ghost (A page, below). The page's own
|
|
8
|
+
`PageBar` shows at once with its name, the words and acts that wait on the data are ghosts, and the board holds a tile
|
|
9
|
+
or card skeleton where each real one will land.
|
|
8
10
|
- A list or a well is still being read: a few rows stand in placeholders' places (`Well busy`, `WellRow hidden`).
|
|
9
11
|
|
|
10
12
|
## Not for
|
|
11
13
|
|
|
14
|
+
- A list page or a board page: the page's `PageBar` and `FilterBar` at once, then `Table`'s own ghost rows
|
|
15
|
+
(`ws-table__placeholder`) or `KanbanBoard`'s ghost cards (`ws-kanban-board__ghost`), their heads shown at once. Never a
|
|
16
|
+
bento of cards in place of a table or a board.
|
|
12
17
|
- "There is an answer and it is nothing": use `EmptyState`.
|
|
13
18
|
- A single control waiting on its own request (a pressed button): use the button's own `pending` state (a working dot), not a skeleton.
|
|
14
19
|
- Content whose final size is unknown: a skeleton promises a shape; guessing wildly causes more jumping than a plain loading line would.
|
|
15
20
|
|
|
16
21
|
## Anatomy
|
|
17
22
|
|
|
18
|
-
- A ghost block (`ws-skeleton`): 4 px corners (`--ws-radius-control`), the shimmer
|
|
19
|
-
|
|
23
|
+
- A ghost block (`ws-skeleton`): 4 px corners (`--ws-radius-control`), the shimmer (`--ws-shimmer`: the ghost grey
|
|
24
|
+
#E3DFDB with a lighter pass of the same grey, #F6F3F0, at 300 %; no chart hues), sized where used. Steps: `--line` 12 px
|
|
20
25
|
tall, `--title` 28 px (a title's line), `--button` 120 x 36 with 6 px corners (North's button place, on the grid).
|
|
21
26
|
- Lines: a column 8 px apart (`ws-stack`), full width except the last, two thirds.
|
|
22
27
|
- A card skeleton: the same card (`ws-card`) with ghosts for its head (`ws-skeleton__head`, 20 in), its body
|
|
23
|
-
(`ws-skeleton__body`) and its band; a tile keeps its tray foot.
|
|
24
|
-
|
|
25
|
-
- A chart ghost (`ws-skeleton__chart`): 160 px tall, the bars 4 px apart
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
(`ws-skeleton__body`) and its band; a tile keeps its tray foot. The ghost grey shows on the tray too (1.13:1, the
|
|
29
|
+
cream 1.29:1), so a ghost in a foot or a band is the same ghost.
|
|
30
|
+
- A chart ghost (`ws-skeleton__chart`): 160 px tall, the bars 4 px apart, each a ghost under the same shimmer as every
|
|
31
|
+
other ghost. North's colour band over the drawing is not taken (0.5.1): loaders are one neutral tone.
|
|
32
|
+
- A page (the page ghost; no class of its own, the page's own layout and the ghosts above): the real `.ws-page` (or
|
|
33
|
+
`AppShell`'s body) with `aria-busy="true"` and one `ws-sr` status line, so the ghost lands where the page will and
|
|
34
|
+
nothing jumps.
|
|
35
|
+
- Its `PageBar` is the real bar, 56 tall either way: the name shows at once (a page knows its own name). Words that
|
|
36
|
+
wait on the data are ghosts on their own classes (`ws-page-bar__context ws-skeleton ws-skeleton--line`, 200 wide),
|
|
37
|
+
so they wrap, and hide in a shell's bar on a phone, as the words will. An act that needs the data is a button place
|
|
38
|
+
(`--button`); one that does not ("Sync now") stays a real button. A name that comes with the data (an account's
|
|
39
|
+
page) is a ghost line in the title's place.
|
|
40
|
+
- Its board is the real board: `ws-board ws-board--4` for a row of tiles (four, two or one, never three), `ws-board`
|
|
41
|
+
for the chart cards, each a card skeleton the shape of the card that lands. The chart ghost stands for a 160 px plot;
|
|
42
|
+
set it to the card's own plot height when that is shorter (`ws-card__bars` is 72), and a card with rows gets a ghost
|
|
43
|
+
row per row. Draw only the cards above the fold; the rest come as they load.
|
|
28
44
|
|
|
29
45
|
## Variants and sizes
|
|
30
46
|
|
|
@@ -34,16 +50,18 @@ nothing jumps when the real content lands.
|
|
|
34
50
|
| A card or tile skeleton | A chart card or tile still loading, keeping the page's layout steady |
|
|
35
51
|
| A chart ghost | The drawing inside a chart card that is still being built |
|
|
36
52
|
| A button place | The band's act before the card knows it |
|
|
53
|
+
| A page | A whole page still loading its data: the real bar with its name, its waiting words and acts as ghosts, a board of tile and card skeletons |
|
|
37
54
|
|
|
38
55
|
## States
|
|
39
56
|
|
|
40
57
|
- **Loading** (the only state): the shimmer passes over every ghost every 1.8 s (`--ws-loop-shimmer` on
|
|
41
|
-
`--ws-ease-shimmer`)
|
|
58
|
+
`--ws-ease-shimmer`), the chart's bars included.
|
|
42
59
|
- **Loaded**: the skeleton is removed and the real content takes its place; nothing jumps, since the ghosts use the
|
|
43
60
|
content's own sizes.
|
|
44
|
-
- **Reduced motion**: nothing travels. The ghosts are
|
|
45
|
-
|
|
46
|
-
- **Dark**: the
|
|
61
|
+
- **Reduced motion**: nothing travels. The ghosts are the still ghost grey (`--ws-ghost`, the shimmer's own ground),
|
|
62
|
+
never a frozen frame of the sweep; still plainly a placeholder.
|
|
63
|
+
- **Dark and palettes**: the ghost and its pass are theme tokens (the night's ghost #273544 with a pass of 7 % ink), so
|
|
64
|
+
the shimmer is one neutral tone in every theme and palette.
|
|
47
65
|
|
|
48
66
|
## Behaviour
|
|
49
67
|
|
|
@@ -71,12 +89,17 @@ The kit's own `Skeleton` takes a `className` for its shape and size directly (he
|
|
|
71
89
|
|
|
72
90
|
- Never invent a size: a skeleton's bars use the real content's own token sizes (a title's line height, a card's padding), so nothing jumps when the content replaces it.
|
|
73
91
|
- A loading region is announced once (`aria-busy`, `aria-live="polite"` on the container), not per placeholder bar.
|
|
92
|
+
- A page's name never waits on its data, and a page ghost is the page's own bar and board, never a layout of its own:
|
|
93
|
+
what lands takes the ghost's place in the same grid.
|
|
74
94
|
- With reduced motion, a skeleton is still visibly a placeholder (still grey ghosts), never indistinguishable from real, blank content.
|
|
75
95
|
|
|
76
96
|
## Source
|
|
77
97
|
|
|
78
|
-
**Derived from**: North's loading (style1.css:1458-1469: the
|
|
79
|
-
|
|
98
|
+
**Derived from**: North's loading (style1.css:1458-1469: the shimmer over blocks, the ghost shapes, the 116 x 38
|
|
99
|
+
button place), North's `CanvasLoading` for the page ghost (a header pair and a bento of card-shaped ghosts; here on the
|
|
100
|
+
page's own bar and board, the name shown at once, as `AppShell`, `Table` and `KanbanBoard` show their heads; Hemanth's
|
|
101
|
+
ask for a page-level loader, 10 Nov 2026) and the kit's own `Skeleton`. North's sweep in the chart colours and its colour band over the chart are
|
|
102
|
+
not taken: loaders are one quiet grey (Amit, 10 Nov 2026, Decisions). It replaces the breathing
|
|
80
103
|
pulse, which read as blank (1.10:1 on the cream, field evidence S01). **Precedent**: the first product built on the
|
|
81
104
|
system.
|
|
82
105
|
|
|
@@ -95,8 +118,50 @@ system.
|
|
|
95
118
|
</div>
|
|
96
119
|
```
|
|
97
120
|
|
|
121
|
+
A page (the preview draws four tiles and two chart cards; repeat the tile and the card for each one that lands):
|
|
122
|
+
|
|
123
|
+
```html
|
|
124
|
+
<main class="ws-page" aria-busy="true">
|
|
125
|
+
<span class="ws-sr" role="status">Loading onboarding</span>
|
|
126
|
+
<header class="ws-page-bar">
|
|
127
|
+
<div class="ws-page-bar__words">
|
|
128
|
+
<h1 class="ws-page-bar__title">Onboarding</h1>
|
|
129
|
+
<span class="ws-page-bar__context ws-skeleton ws-skeleton--line" style="width: var(--space-9xl);" aria-hidden="true"></span>
|
|
130
|
+
</div>
|
|
131
|
+
<div class="ws-page-bar__acts" aria-hidden="true"><div class="ws-skeleton ws-skeleton--button"></div></div>
|
|
132
|
+
</header>
|
|
133
|
+
<div class="ws-board ws-board--4">
|
|
134
|
+
<div class="ws-card" aria-hidden="true">
|
|
135
|
+
<div class="ws-card__surface ws-card__surface--pad ws-stack">
|
|
136
|
+
<div class="ws-skeleton ws-skeleton--line" style="width: 50%;"></div>
|
|
137
|
+
<div class="ws-skeleton" style="height: var(--ws-leading-figure); width: 40%;"></div>
|
|
138
|
+
</div>
|
|
139
|
+
<div class="ws-card__foot"><div class="ws-skeleton ws-skeleton--line" style="width: 40%;"></div></div>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
<div class="ws-board">
|
|
143
|
+
<div class="ws-card ws-card--compound" aria-hidden="true">
|
|
144
|
+
<div class="ws-skeleton__head">
|
|
145
|
+
<div class="ws-skeleton ws-skeleton--title" style="width: 55%;"></div>
|
|
146
|
+
<div class="ws-skeleton ws-skeleton--line" style="width: 80%;"></div>
|
|
147
|
+
</div>
|
|
148
|
+
<div class="ws-skeleton__body">
|
|
149
|
+
<div class="ws-skeleton__chart"><i style="height: 35%;"></i><i style="height: 60%;"></i><i style="height: 45%;"></i><i style="height: 75%;"></i></div>
|
|
150
|
+
</div>
|
|
151
|
+
<footer class="ws-band">
|
|
152
|
+
<div class="ws-band__words"><div class="ws-skeleton ws-skeleton--line" style="width: 50%;"></div></div>
|
|
153
|
+
<div class="ws-band__acts"><div class="ws-skeleton ws-skeleton--button"></div></div>
|
|
154
|
+
</footer>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
</main>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
In `AppShell` the nav and the bar are already there: put the bar's ghosts in the shell's bar and the boards straight in
|
|
161
|
+
its body (`aria-busy="true"` and the status line on the body), with no `.ws-page` inside.
|
|
162
|
+
|
|
98
163
|
## Styles
|
|
99
164
|
|
|
100
165
|
`Skeleton/style.css`, built into `bundle.css` and `fello.css`. The keyframe is the house's `ws-shimmer`. Tokens:
|
|
101
|
-
`--ws-shimmer
|
|
102
|
-
`--ws-
|
|
166
|
+
`--ws-shimmer` (over `--ws-shimmer-ground`), `--ws-ghost`, `--ws-loop-shimmer`, `--ws-ease-shimmer`,
|
|
167
|
+
`--ws-radius-control`, `--ws-radius-row`, `--ws-radius-bar`.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- @dsCard group="Cards" height=
|
|
1
|
+
<!-- @dsCard group="Cards" height=1180 -->
|
|
2
2
|
<!doctype html>
|
|
3
3
|
<html>
|
|
4
4
|
<head>
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
</div>
|
|
31
31
|
|
|
32
32
|
<div class="ws-stack" style="width: 380px;">
|
|
33
|
-
<span class="ws-muted">A chart card still loading:
|
|
33
|
+
<span class="ws-muted">A chart card still loading: each bar a ghost under the same shimmer</span>
|
|
34
34
|
<div class="ws-card ws-card--compound" aria-busy="true">
|
|
35
35
|
<span class="ws-sr">Loading the chart</span>
|
|
36
36
|
<div class="ws-skeleton__head" aria-hidden="true">
|
|
@@ -51,5 +51,87 @@
|
|
|
51
51
|
</div>
|
|
52
52
|
</div>
|
|
53
53
|
</div>
|
|
54
|
+
|
|
55
|
+
<div class="ws-stage ws-stage--column ws-stage--bleed">
|
|
56
|
+
<span class="ws-muted" style="padding: var(--ws-gap-component) var(--ws-gap-component) 0;">A whole page still loading: its own bar with the name shown at once, the context and the act as ghosts, then a board of tile and card skeletons where the real ones will land</span>
|
|
57
|
+
<main class="ws-page" aria-busy="true">
|
|
58
|
+
<span class="ws-sr" role="status">Loading onboarding</span>
|
|
59
|
+
<header class="ws-page-bar">
|
|
60
|
+
<div class="ws-page-bar__words">
|
|
61
|
+
<h1 class="ws-page-bar__title">Onboarding</h1>
|
|
62
|
+
<span class="ws-page-bar__context ws-skeleton ws-skeleton--line" style="width: var(--space-9xl);" aria-hidden="true"></span>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="ws-page-bar__acts" aria-hidden="true">
|
|
65
|
+
<div class="ws-skeleton ws-skeleton--button"></div>
|
|
66
|
+
</div>
|
|
67
|
+
</header>
|
|
68
|
+
<div class="ws-board ws-board--4">
|
|
69
|
+
<div class="ws-card" aria-hidden="true">
|
|
70
|
+
<div class="ws-card__surface ws-card__surface--pad ws-stack">
|
|
71
|
+
<div class="ws-skeleton ws-skeleton--line" style="width: 50%;"></div>
|
|
72
|
+
<div class="ws-skeleton" style="height: var(--ws-leading-figure); width: 40%;"></div>
|
|
73
|
+
</div>
|
|
74
|
+
<div class="ws-card__foot">
|
|
75
|
+
<div class="ws-skeleton ws-skeleton--line" style="width: 40%;"></div>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="ws-card" aria-hidden="true">
|
|
79
|
+
<div class="ws-card__surface ws-card__surface--pad ws-stack">
|
|
80
|
+
<div class="ws-skeleton ws-skeleton--line" style="width: 60%;"></div>
|
|
81
|
+
<div class="ws-skeleton" style="height: var(--ws-leading-figure); width: 30%;"></div>
|
|
82
|
+
</div>
|
|
83
|
+
<div class="ws-card__foot">
|
|
84
|
+
<div class="ws-skeleton ws-skeleton--line" style="width: 50%;"></div>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
<div class="ws-card" aria-hidden="true">
|
|
88
|
+
<div class="ws-card__surface ws-card__surface--pad ws-stack">
|
|
89
|
+
<div class="ws-skeleton ws-skeleton--line" style="width: 45%;"></div>
|
|
90
|
+
<div class="ws-skeleton" style="height: var(--ws-leading-figure); width: 45%;"></div>
|
|
91
|
+
</div>
|
|
92
|
+
<div class="ws-card__foot">
|
|
93
|
+
<div class="ws-skeleton ws-skeleton--line" style="width: 35%;"></div>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
<div class="ws-card" aria-hidden="true">
|
|
97
|
+
<div class="ws-card__surface ws-card__surface--pad ws-stack">
|
|
98
|
+
<div class="ws-skeleton ws-skeleton--line" style="width: 55%;"></div>
|
|
99
|
+
<div class="ws-skeleton" style="height: var(--ws-leading-figure); width: 35%;"></div>
|
|
100
|
+
</div>
|
|
101
|
+
<div class="ws-card__foot">
|
|
102
|
+
<div class="ws-skeleton ws-skeleton--line" style="width: 45%;"></div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
<div class="ws-board">
|
|
107
|
+
<div class="ws-card ws-card--compound" aria-hidden="true">
|
|
108
|
+
<div class="ws-skeleton__head">
|
|
109
|
+
<div class="ws-skeleton ws-skeleton--title" style="width: 55%;"></div>
|
|
110
|
+
<div class="ws-skeleton ws-skeleton--line" style="width: 80%;"></div>
|
|
111
|
+
</div>
|
|
112
|
+
<div class="ws-skeleton__body">
|
|
113
|
+
<div class="ws-skeleton__chart"><i style="height: 35%;"></i><i style="height: 60%;"></i><i style="height: 45%;"></i><i style="height: 75%;"></i><i style="height: 55%;"></i><i style="height: 90%;"></i><i style="height: 70%;"></i><i style="height: 50%;"></i></div>
|
|
114
|
+
</div>
|
|
115
|
+
<footer class="ws-band">
|
|
116
|
+
<div class="ws-band__words"><div class="ws-skeleton ws-skeleton--line" style="width: 50%;"></div></div>
|
|
117
|
+
<div class="ws-band__acts"><div class="ws-skeleton ws-skeleton--button"></div></div>
|
|
118
|
+
</footer>
|
|
119
|
+
</div>
|
|
120
|
+
<div class="ws-card ws-card--compound" aria-hidden="true">
|
|
121
|
+
<div class="ws-skeleton__head">
|
|
122
|
+
<div class="ws-skeleton ws-skeleton--title" style="width: 45%;"></div>
|
|
123
|
+
<div class="ws-skeleton ws-skeleton--line" style="width: 70%;"></div>
|
|
124
|
+
</div>
|
|
125
|
+
<div class="ws-skeleton__body">
|
|
126
|
+
<div class="ws-skeleton__chart"><i style="height: 60%;"></i><i style="height: 40%;"></i><i style="height: 70%;"></i><i style="height: 50%;"></i><i style="height: 80%;"></i><i style="height: 65%;"></i><i style="height: 45%;"></i><i style="height: 55%;"></i></div>
|
|
127
|
+
</div>
|
|
128
|
+
<footer class="ws-band">
|
|
129
|
+
<div class="ws-band__words"><div class="ws-skeleton ws-skeleton--line" style="width: 40%;"></div></div>
|
|
130
|
+
<div class="ws-band__acts"><div class="ws-skeleton ws-skeleton--button"></div></div>
|
|
131
|
+
</footer>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
</main>
|
|
135
|
+
</div>
|
|
54
136
|
</body>
|
|
55
137
|
</html>
|
|
@@ -1,22 +1,17 @@
|
|
|
1
|
-
/* ---- Skeleton: ghost shapes of what is coming, with North's shimmer
|
|
2
|
-
/* A ghost block: the shimmer (the
|
|
3
|
-
breathing pulse (ws-working-slow), which read as blank. Under reduced motion it is
|
|
4
|
-
(the chart ghost's), never a frozen frame of the sweep
|
|
1
|
+
/* ---- Skeleton: ghost shapes of what is coming, with North's shimmer, one quiet grey, running over them; sized where used ---- */
|
|
2
|
+
/* A ghost block: the shimmer (the ghost grey with a lighter pass of the same grey) at 300 %, 1.8 s. It replaces the
|
|
3
|
+
breathing pulse (ws-working-slow), which read as blank. Under reduced motion it is the still ghost, the same grey
|
|
4
|
+
(North's ghost, the chart ghost's), never a frozen frame of the sweep. The ghost shows on the tray too (a card's foot,
|
|
5
|
+
a band), so it needs no ground of its own there. */
|
|
5
6
|
.ws-skeleton { border-radius: var(--ws-radius-control); background: var(--ws-ghost); }
|
|
6
7
|
.ws-skeleton--line { height: var(--space-sm); }
|
|
7
8
|
.ws-skeleton--title { height: var(--ws-leading-title); }
|
|
8
9
|
/* A button's place (North's 116 x 38 placeholder, on the grid: 120 x 36, 6 px corners). */
|
|
9
10
|
.ws-skeleton--button { width: var(--space-7xl); height: var(--ws-control-h-md); border-radius: var(--ws-radius-row); }
|
|
10
|
-
/* On the tray (a card's foot) and in a band the ghost's grey was the ground's own (1.04:1 on the tray in light, the same
|
|
11
|
-
grey as the track in dark), so the placeholder vanished: there it is built on the hover grey, with the dark theme's
|
|
12
|
-
recipe of 14 % salmon, purple and teal passes, on the token's stops (plain to 34 % and from 66 %, so the loop's end frames show no tint). */
|
|
13
|
-
:is(.ws-card__foot, .ws-band) .ws-skeleton { --ws-shimmer: linear-gradient(100deg, var(--ws-well-hover) 0 34%, color-mix(in srgb, var(--ws-chart-under-half) 14%, var(--ws-well-hover)) 44%, color-mix(in srgb, var(--ws-chart-past-half) 14%, var(--ws-well-hover)) 50%, color-mix(in srgb, var(--color-stat-positive) 14%, var(--ws-well-hover)) 56%, var(--ws-well-hover) 66% 100%); }
|
|
14
|
-
@media (prefers-reduced-motion: no-preference) { .ws-skeleton { background: var(--ws-shimmer); background-size: 300% 100%; animation: ws-shimmer var(--ws-loop-shimmer) var(--ws-ease-shimmer) infinite; } }
|
|
15
11
|
.ws-skeleton__head { display: flex; flex-direction: column; gap: var(--space-xs); padding: var(--ws-card-inset); }
|
|
16
12
|
.ws-skeleton__body { display: flex; flex-direction: column; gap: var(--space-xs); padding: 0 var(--ws-card-inset) var(--space-md); }
|
|
17
|
-
/* A chart still loading: its empty shapes
|
|
18
|
-
over the
|
|
19
|
-
.ws-skeleton__chart {
|
|
13
|
+
/* A chart still loading: its empty shapes, each a ghost with the same sweep as every other ghost. North's colour band
|
|
14
|
+
over the drawing is gone (0.5.1): loaders are one neutral tone, and a neutral band in blend mode colour paints nothing. */
|
|
15
|
+
.ws-skeleton__chart { display: flex; align-items: flex-end; gap: var(--space-xxs); height: var(--space-8xl); }
|
|
20
16
|
.ws-skeleton__chart > * { flex: 1 1 0; min-width: 0; border-radius: var(--ws-radius-bar) var(--ws-radius-bar) 0 0; background: var(--ws-ghost); }
|
|
21
|
-
|
|
22
|
-
@media (prefers-reduced-motion: no-preference) { .ws-skeleton__chart::after { opacity: 0.85; animation: ws-shimmer var(--ws-loop-shimmer) var(--ws-ease-shimmer) infinite; } }
|
|
17
|
+
@media (prefers-reduced-motion: no-preference) { :is(.ws-skeleton, .ws-skeleton__chart > *) { background: var(--ws-shimmer); background-size: 300% 100%; animation: ws-shimmer var(--ws-loop-shimmer) var(--ws-ease-shimmer) infinite; } }
|
|
@@ -23,7 +23,7 @@ paste the CSS into the `<style>`, then replace the sample content with the real
|
|
|
23
23
|
`fello-core.css`, then the styles of each component the page uses (each component's card lists them; this page needs
|
|
24
24
|
`Page`, `PageBar`, `Card`, `Button` and `Well`; the whole `fello.css` is too big to paste). The buttons and the well
|
|
25
25
|
rows need their own blocks: `fello-core.css` holds only their 0.4 look. A plain page links the whole file instead,
|
|
26
|
-
pinned: `https://brand-kit-site-production.up.railway.app/v/0.5.
|
|
26
|
+
pinned: `https://brand-kit-site-production.up.railway.app/v/0.5.3/fello.css`.
|
|
27
27
|
- `<main class="ws-page">`: the page (see `Page`), Seth's 32 gutter.
|
|
28
28
|
- `PageBar`: the page's 56 px header, its one `h1` (16 / 22 semibold) and a word of context beside it, and its acts
|
|
29
29
|
with the page's one navy primary last.
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<title>Starter</title>
|
|
8
8
|
<!-- In a claude.ai artifact, paste fello-core.css into the <style> below, then the styles of each component you use
|
|
9
9
|
(each component's card lists them): an artifact may load no stylesheet but Google Fonts. On a plain page, link the
|
|
10
|
-
whole kit instead, pinned: https://brand-kit-site-production.up.railway.app/v/0.5.
|
|
10
|
+
whole kit instead, pinned: https://brand-kit-site-production.up.railway.app/v/0.5.3/fello.css -->
|
|
11
11
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
12
12
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
13
13
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Instrument+Sans:wght@400..700&display=swap">
|
|
@@ -1,16 +1,23 @@
|
|
|
1
|
-
Ordered steps on a line that fills: done is a tick, the one in hand is ringed, the rest wait their turn.
|
|
1
|
+
Ordered steps on a line that fills: done is a tick, the one in hand is ringed, the rest wait their turn. Down the page
|
|
2
|
+
by default; `--across` lays the stages left to right; `--milestones` makes them dated points on one row.
|
|
2
3
|
|
|
3
4
|
## Use it when
|
|
4
5
|
|
|
5
6
|
- Something happens in a known sequence and the person benefits from seeing where it is (a setup's path, an onboarding
|
|
6
7
|
checklist, an audit).
|
|
7
8
|
- Several things run at once rather than in order (a scan's sources), and the page needs to say which are being read right now.
|
|
9
|
+
- One thing's stages under its title (an onboarding's Scheduling to Graduated, a deal's stages): `--across`.
|
|
10
|
+
- One thing's dated milestones, each reached or not, measured from the start (signed, first value, first agreement):
|
|
11
|
+
`--milestones`. A variant, not its own component: it is the same marks, line and done or waiting states on a row.
|
|
8
12
|
|
|
9
13
|
## Not for
|
|
10
14
|
|
|
11
15
|
- A share of a goal or a percent: use `GoalTicks` or `Ring`.
|
|
12
16
|
- A count out of a whole: use `TickRow`.
|
|
13
17
|
- A plain loading wait with no named steps: a working chip or spinner, not a `Stepper`.
|
|
18
|
+
- What happened, in order, grouped by day: use `Timeline`.
|
|
19
|
+
- Many things across their stages at once: use `KanbanBoard`.
|
|
20
|
+
- Phases and tasks as bars across dates (a plan): not in the kit yet (issue #24).
|
|
14
21
|
|
|
15
22
|
## Anatomy
|
|
16
23
|
|
|
@@ -20,6 +27,17 @@ Ordered steps on a line that fills: done is a tick, the one in hand is ringed, t
|
|
|
20
27
|
- Waiting: the cream with the fine hairline ring (drawn inside), muted grey number.
|
|
21
28
|
- Connecting line: a 1 px (`calc(--ws-hairline * 2)`) line between marks in `--ws-edge`, filled teal top to bottom when its step above is done.
|
|
22
29
|
- Title: 14 / 20 medium navy, its first line level with the mark; a note under it in `ws-muted` (how far, or "Done").
|
|
30
|
+
- A stall (`__late` on the note, with `ws-muted`): the note in needs-you words (`--ws-word-needs`), never a colour on
|
|
31
|
+
the mark: the in-hand ring stays navy.
|
|
32
|
+
- Across (`--across`): equal columns, each at least 120 (`--space-7xl`), the mark centred over its words, 8 between
|
|
33
|
+
them; the line runs at the mark's middle from its right edge to the next mark's left edge and fills left to right
|
|
34
|
+
(`ws-grow`). Wider than its column, the track scrolls inside and fades at the edge that hides stages (the house
|
|
35
|
+
`ws-scroll-edges` cue), and the in-hand stage opens in view (`scroll-initial-target`).
|
|
36
|
+
- Milestones (`--milestones`): an 8 px dot, 8 to the words, the name as the title and its measure beside it in
|
|
37
|
+
`ws-muted` (a date, or days since the start), on one line; the line takes the room left between the words and the
|
|
38
|
+
next dot, 8 from each. Reached is the teal dot; not reached a 1 px ring (`--ws-edge-card`) with "Not yet", and at
|
|
39
|
+
most one quiet act beside it (`ws-btn ws-btn--text`). The line after a milestone fills when the next is reached. 4 px
|
|
40
|
+
of room on every side, pulled back by a margin, so the act's focus ring is never cut.
|
|
23
41
|
|
|
24
42
|
## Variants and sizes
|
|
25
43
|
|
|
@@ -27,12 +45,18 @@ Ordered steps on a line that fills: done is a tick, the one in hand is ringed, t
|
|
|
27
45
|
| --- | --- |
|
|
28
46
|
| In order (default) | The first step not done is the one in hand, found automatically |
|
|
29
47
|
| Side by side (`active` set on any step) | Only steps with `active: true` are in hand (several at once); none active means none are in hand, every undone step simply waits |
|
|
48
|
+
| Across (`ws-stepper--across`) | The same steps left to right, a mark over its words; for a thing's stages under its title |
|
|
49
|
+
| Milestones (`ws-stepper--milestones`) | Dated points on one row: dots, no numbers, no in-hand ring; each reached or not yet |
|
|
30
50
|
|
|
31
51
|
## States
|
|
32
52
|
|
|
33
53
|
- Default: the first undone step is in hand, ringed in navy; everything after it waits.
|
|
34
54
|
- In hand (parallel): rings navy and breathes on `ws-working`, because something is actually in progress right now.
|
|
35
55
|
- Waiting (parallel, nothing active): every undone step sits quiet, no ring, no breathing; nothing has started reading yet.
|
|
56
|
+
- Stalled: the in-hand step has sat past its expected time. Its note says so with the time, in needs-you words
|
|
57
|
+
("Stalled 40 days"); the ring stays navy and nothing breathes.
|
|
58
|
+
- Late (milestones): reached past its target; the measure says by how much, in needs-you words ("52 days, 7 late").
|
|
59
|
+
- Not yet (milestones): the ring dot, "Not yet", and the one act if the person can log it ("Add date").
|
|
36
60
|
- Done: a filled teal circle with a check, popping in (`ws-pop`) the moment it completes, and the line below it filling down (`ws-grow-up`) the same moment.
|
|
37
61
|
- Disabled / error / hover / focus / pressed / selected: do not apply; a step is a status, not a control.
|
|
38
62
|
- Reduced motion: ticks, rings and the filling line are all simply in their final state, no pop, breathe or growth.
|
|
@@ -46,26 +70,36 @@ Ordered steps on a line that fills: done is a tick, the one in hand is ringed, t
|
|
|
46
70
|
|
|
47
71
|
## Content
|
|
48
72
|
|
|
49
|
-
- A step's title says what it does, not just its name ("Writing the three recommendations", not "Step 3").
|
|
73
|
+
- A step's title says what it does, not just its name ("Writing the three recommendations", not "Step 3"). A stage's
|
|
74
|
+
title is the stage's own name, sentence case ("Review and handoff").
|
|
50
75
|
- The note under an in-hand step says how far ("2 of 4") or what is happening now ("Reading now"); a waiting step carries no note.
|
|
76
|
+
- A stall or a late milestone says the time in words, never a bare "40d" or a colour alone.
|
|
77
|
+
- A milestone's name is plain words, not an acronym the reader must know ("First value", not "TTV1"); its measure is a
|
|
78
|
+
date ("Sep 11") or days since the start ("15 days").
|
|
51
79
|
|
|
52
80
|
## Props
|
|
53
81
|
|
|
54
82
|
| Name | Type | Meaning |
|
|
55
83
|
| --- | --- | --- |
|
|
56
84
|
| `label` | `string` | Names the whole sequence for the `<ol>` |
|
|
57
|
-
| `steps` | `{ key, title, note?, done, active? }[]` | Each step; `active` turns on the side-by-side mode across the whole list |
|
|
85
|
+
| `steps` | `{ key, title, note?, done, active?, late? }[]` | Each step; `active` turns on the side-by-side mode across the whole list; `late` puts the note in needs-you words |
|
|
86
|
+
| `layout` | `"down" \| "across" \| "milestones"` | Down the page (default), stages left to right, or dated milestones on a row |
|
|
58
87
|
|
|
59
88
|
## Rules
|
|
60
89
|
|
|
61
90
|
- Sequences and waits are steps; do not reach for a progress bar or a percent where a named sequence says it plainer.
|
|
62
91
|
- The in-hand ring is always navy; a step never borrows a chart's tone (teal, salmon, purple) for its own status beyond "done".
|
|
92
|
+
A stall or a late milestone is said in needs-you words, not painted on the mark.
|
|
93
|
+
- Across needs room for every stage at 120; on a phone it scrolls with the in-hand stage in view. Where every stage
|
|
94
|
+
must show at once in a narrow column, use the default, down the page.
|
|
95
|
+
- One act at most on a milestone row, on a milestone not yet reached; a step or a milestone itself never takes a click.
|
|
63
96
|
- A step that cannot start yet (no data, blocked) still appears in its place, waiting; it is never removed from the list.
|
|
64
97
|
|
|
65
98
|
## Source
|
|
66
99
|
|
|
67
100
|
**Derived from**: the brand kit's own guidance that sequences and waits are drawn as steps, not a progress bar
|
|
68
|
-
(21 Oct 2026). **Precedent**: the first product built on the system.
|
|
101
|
+
(21 Oct 2026). **Precedent**: the first product built on the system. `--across` and `--milestones`: the Customer
|
|
102
|
+
Value onboarding detail (Hemanth, 10 Nov 2026), whose stage track and milestone row were built by hand for want of them.
|
|
69
103
|
|
|
70
104
|
## Markup
|
|
71
105
|
|
|
@@ -83,7 +117,49 @@ Ordered steps on a line that fills: done is a tick, the one in hand is ringed, t
|
|
|
83
117
|
</ol>
|
|
84
118
|
```
|
|
85
119
|
|
|
120
|
+
Across: a thing's stages under its title (the line under a done stage fills; the stalled note under the in-hand one).
|
|
121
|
+
|
|
122
|
+
```html
|
|
123
|
+
<ol class="ws-stepper ws-stepper--across" aria-label="Onboarding stages">
|
|
124
|
+
<li class="ws-stepper__item">
|
|
125
|
+
<span class="ws-stepper__line"><span class="ws-stepper__line-fill ws-grow"></span></span>
|
|
126
|
+
<span class="ws-stepper__mark ws-stepper__mark--done" aria-hidden="true"><svg viewBox="0 0 16 16" width="12" height="12" fill="none"><path d="M3.5 8.5L6.5 11.5L12.5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
|
|
127
|
+
<span class="ws-stepper__body"><span class="ws-stepper__title">Optimizing</span></span>
|
|
128
|
+
</li>
|
|
129
|
+
<li class="ws-stepper__item" aria-current="step">
|
|
130
|
+
<span class="ws-stepper__line"></span>
|
|
131
|
+
<span class="ws-stepper__mark ws-stepper__mark--current" aria-hidden="true">5</span>
|
|
132
|
+
<span class="ws-stepper__body"><span class="ws-stepper__title">Review and handoff</span><span class="ws-muted ws-stepper__late">Stalled 40 days</span></span>
|
|
133
|
+
</li>
|
|
134
|
+
<li class="ws-stepper__item">
|
|
135
|
+
<span class="ws-stepper__mark ws-stepper__mark--wait" aria-hidden="true">6</span>
|
|
136
|
+
<span class="ws-stepper__body"><span class="ws-stepper__title">Graduated</span></span>
|
|
137
|
+
</li>
|
|
138
|
+
</ol>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Milestones: reached, late and not yet, with the one act.
|
|
142
|
+
|
|
143
|
+
```html
|
|
144
|
+
<ol class="ws-stepper ws-stepper--milestones" aria-label="Milestones">
|
|
145
|
+
<li class="ws-stepper__item">
|
|
146
|
+
<span class="ws-stepper__line"><span class="ws-stepper__line-fill ws-grow"></span></span>
|
|
147
|
+
<span class="ws-stepper__mark ws-stepper__mark--done" aria-hidden="true"></span>
|
|
148
|
+
<span class="ws-stepper__body"><span class="ws-stepper__title">Signed</span><span class="ws-muted">Sep 11</span></span>
|
|
149
|
+
</li>
|
|
150
|
+
<li class="ws-stepper__item">
|
|
151
|
+
<span class="ws-stepper__line"></span>
|
|
152
|
+
<span class="ws-stepper__mark ws-stepper__mark--done" aria-hidden="true"></span>
|
|
153
|
+
<span class="ws-stepper__body"><span class="ws-stepper__title">First agreement</span><span class="ws-muted ws-stepper__late">52 days, 7 late</span></span>
|
|
154
|
+
</li>
|
|
155
|
+
<li class="ws-stepper__item">
|
|
156
|
+
<span class="ws-stepper__mark ws-stepper__mark--wait" aria-hidden="true"></span>
|
|
157
|
+
<span class="ws-stepper__body"><span class="ws-stepper__title">Graduated</span><span class="ws-muted">Not yet</span><button type="button" class="ws-btn ws-btn--text" aria-label="Add the graduation date">Add date</button></span>
|
|
158
|
+
</li>
|
|
159
|
+
</ol>
|
|
160
|
+
```
|
|
161
|
+
|
|
86
162
|
## Styles
|
|
87
163
|
|
|
88
164
|
`design-system/components/Stepper/style.css`: `ws-stepper`, `__item`, `__line`, `__line-fill`, `__mark` with `--done`,
|
|
89
|
-
`--current`, `--wait`; `__body`, `__title`.
|
|
165
|
+
`--current`, `--wait`; `__body`, `__title`, `__late`; layouts `ws-stepper--across` and `ws-stepper--milestones`.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- @dsCard group="Progress" height=
|
|
1
|
+
<!-- @dsCard group="Progress" height=520 -->
|
|
2
2
|
<!doctype html>
|
|
3
3
|
<html>
|
|
4
4
|
<head>
|
|
@@ -104,6 +104,69 @@
|
|
|
104
104
|
</ol>
|
|
105
105
|
</div>
|
|
106
106
|
|
|
107
|
+
<div class="ws-stack" style="width: 100%;">
|
|
108
|
+
<span class="ws-muted">Across: four stages done, the fifth in hand and stalled, the last to come</span>
|
|
109
|
+
<ol class="ws-stepper ws-stepper--across" aria-label="Onboarding stages">
|
|
110
|
+
<li class="ws-stepper__item">
|
|
111
|
+
<span class="ws-stepper__line"><span class="ws-stepper__line-fill ws-grow"></span></span>
|
|
112
|
+
<span class="ws-stepper__mark ws-stepper__mark--done" aria-hidden="true"><svg viewBox="0 0 16 16" width="12" height="12" fill="none"><path d="M3.5 8.5L6.5 11.5L12.5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
|
|
113
|
+
<span class="ws-stepper__body"><span class="ws-stepper__title">Scheduling</span></span>
|
|
114
|
+
</li>
|
|
115
|
+
<li class="ws-stepper__item">
|
|
116
|
+
<span class="ws-stepper__line"><span class="ws-stepper__line-fill ws-grow" style="animation-delay: 30ms;"></span></span>
|
|
117
|
+
<span class="ws-stepper__mark ws-stepper__mark--done" aria-hidden="true"><svg viewBox="0 0 16 16" width="12" height="12" fill="none"><path d="M3.5 8.5L6.5 11.5L12.5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
|
|
118
|
+
<span class="ws-stepper__body"><span class="ws-stepper__title">Implementing</span></span>
|
|
119
|
+
</li>
|
|
120
|
+
<li class="ws-stepper__item">
|
|
121
|
+
<span class="ws-stepper__line"><span class="ws-stepper__line-fill ws-grow" style="animation-delay: 60ms;"></span></span>
|
|
122
|
+
<span class="ws-stepper__mark ws-stepper__mark--done" aria-hidden="true"><svg viewBox="0 0 16 16" width="12" height="12" fill="none"><path d="M3.5 8.5L6.5 11.5L12.5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
|
|
123
|
+
<span class="ws-stepper__body"><span class="ws-stepper__title">Enabling</span></span>
|
|
124
|
+
</li>
|
|
125
|
+
<li class="ws-stepper__item">
|
|
126
|
+
<span class="ws-stepper__line"><span class="ws-stepper__line-fill ws-grow" style="animation-delay: 90ms;"></span></span>
|
|
127
|
+
<span class="ws-stepper__mark ws-stepper__mark--done" aria-hidden="true"><svg viewBox="0 0 16 16" width="12" height="12" fill="none"><path d="M3.5 8.5L6.5 11.5L12.5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
|
|
128
|
+
<span class="ws-stepper__body"><span class="ws-stepper__title">Optimizing</span></span>
|
|
129
|
+
</li>
|
|
130
|
+
<li class="ws-stepper__item" aria-current="step">
|
|
131
|
+
<span class="ws-stepper__line"></span>
|
|
132
|
+
<span class="ws-stepper__mark ws-stepper__mark--current" aria-hidden="true">5</span>
|
|
133
|
+
<span class="ws-stepper__body">
|
|
134
|
+
<span class="ws-stepper__title">Review and handoff</span>
|
|
135
|
+
<span class="ws-muted ws-stepper__late">Stalled 40 days</span>
|
|
136
|
+
</span>
|
|
137
|
+
</li>
|
|
138
|
+
<li class="ws-stepper__item">
|
|
139
|
+
<span class="ws-stepper__mark ws-stepper__mark--wait" aria-hidden="true">6</span>
|
|
140
|
+
<span class="ws-stepper__body"><span class="ws-stepper__title">Graduated</span></span>
|
|
141
|
+
</li>
|
|
142
|
+
</ol>
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
<div class="ws-stack" style="width: 100%;">
|
|
146
|
+
<span class="ws-muted">Milestones: three reached (one late), the last not yet</span>
|
|
147
|
+
<ol class="ws-stepper ws-stepper--milestones" aria-label="Milestones">
|
|
148
|
+
<li class="ws-stepper__item">
|
|
149
|
+
<span class="ws-stepper__line"><span class="ws-stepper__line-fill ws-grow"></span></span>
|
|
150
|
+
<span class="ws-stepper__mark ws-stepper__mark--done" aria-hidden="true"></span>
|
|
151
|
+
<span class="ws-stepper__body"><span class="ws-stepper__title">Signed</span><span class="ws-muted">Sep 11</span></span>
|
|
152
|
+
</li>
|
|
153
|
+
<li class="ws-stepper__item">
|
|
154
|
+
<span class="ws-stepper__line"><span class="ws-stepper__line-fill ws-grow" style="animation-delay: 30ms;"></span></span>
|
|
155
|
+
<span class="ws-stepper__mark ws-stepper__mark--done" aria-hidden="true"></span>
|
|
156
|
+
<span class="ws-stepper__body"><span class="ws-stepper__title">First value</span><span class="ws-muted">15 days</span></span>
|
|
157
|
+
</li>
|
|
158
|
+
<li class="ws-stepper__item">
|
|
159
|
+
<span class="ws-stepper__line"></span>
|
|
160
|
+
<span class="ws-stepper__mark ws-stepper__mark--done" aria-hidden="true"></span>
|
|
161
|
+
<span class="ws-stepper__body"><span class="ws-stepper__title">First agreement</span><span class="ws-muted ws-stepper__late">52 days, 7 late</span></span>
|
|
162
|
+
</li>
|
|
163
|
+
<li class="ws-stepper__item">
|
|
164
|
+
<span class="ws-stepper__mark ws-stepper__mark--wait" aria-hidden="true"></span>
|
|
165
|
+
<span class="ws-stepper__body"><span class="ws-stepper__title">Graduated</span><span class="ws-muted">Not yet</span><button type="button" class="ws-btn ws-btn--text" aria-label="Add the graduation date">Add date</button></span>
|
|
166
|
+
</li>
|
|
167
|
+
</ol>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
107
170
|
</div>
|
|
108
171
|
</body>
|
|
109
172
|
</html>
|
|
@@ -11,3 +11,32 @@
|
|
|
11
11
|
.ws-stepper__body { display: flex; flex: 1; min-width: 0; flex-direction: column; padding-top: var(--space-3xs); }
|
|
12
12
|
.ws-stepper__title { font-size: var(--ws-text-body); line-height: calc(var(--space-md) + var(--space-xxs)); font-weight: 500; color: var(--color-text-heading); }
|
|
13
13
|
|
|
14
|
+
/* A stall in words: the in-hand step's note when it has sat too long ("40 days in this stage"), and a milestone past its target. */
|
|
15
|
+
.ws-stepper__late { color: var(--ws-word-needs); }
|
|
16
|
+
/* Across: stages left to right, each mark over its words, the line running mark to mark. Equal columns (so the line
|
|
17
|
+
can reach the next mark's centre from its own item), each at least 120; past that the track scrolls inside and fades
|
|
18
|
+
at the edge that hides stages, like Segmented's stages. */
|
|
19
|
+
.ws-stepper--across { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(var(--space-7xl), 1fr); overflow-x: auto; scrollbar-width: none; }
|
|
20
|
+
.ws-stepper--across::-webkit-scrollbar { display: none; }
|
|
21
|
+
.ws-stepper--across > .ws-stepper__item { flex-direction: column; align-items: center; gap: var(--space-xs); padding: 0 var(--space-xxs); text-align: center; }
|
|
22
|
+
.ws-stepper--across .ws-stepper__line { top: calc(var(--space-lg) / 2 - var(--ws-hairline)); bottom: auto; left: calc(50% + var(--space-lg) / 2); right: calc(var(--space-lg) / 2 - 50%); width: auto; height: calc(var(--ws-hairline) * 2); }
|
|
23
|
+
.ws-stepper--across .ws-stepper__line-fill { transform-origin: left; }
|
|
24
|
+
.ws-stepper--across .ws-stepper__body { align-items: center; padding-top: 0; }
|
|
25
|
+
.ws-stepper--across .ws-stepper__title { text-wrap: balance; }
|
|
26
|
+
/* The in-hand stage opens in view on a track that scrolls (a phone): the browser scrolls to it once, on load. */
|
|
27
|
+
.ws-stepper--across > [aria-current="step"] { scroll-snap-align: center; scroll-initial-target: nearest; }
|
|
28
|
+
/* Milestones: dated points on one row, an 8 px dot and its words, the line between them taking the room left. The
|
|
29
|
+
measure sits on the milestone (a date, or days since the start), so the line carries no words. 4 px of room on every
|
|
30
|
+
side, pulled back by a margin, so an act's focus ring and a text button's bleed are never cut by the scroll box. */
|
|
31
|
+
.ws-stepper--milestones { flex-direction: row; gap: var(--space-xs); overflow-x: auto; scrollbar-width: none; padding: var(--space-xxs); margin: calc(var(--space-xxs) * -1); }
|
|
32
|
+
.ws-stepper--milestones::-webkit-scrollbar { display: none; }
|
|
33
|
+
.ws-stepper--milestones > .ws-stepper__item { flex: 1 0 auto; align-items: center; gap: var(--space-xs); padding: 0; }
|
|
34
|
+
.ws-stepper--milestones > .ws-stepper__item:last-child { flex-grow: 0; }
|
|
35
|
+
.ws-stepper--milestones .ws-stepper__line { position: relative; inset: auto; order: 1; flex: 1 0 var(--space-lg); width: auto; height: calc(var(--ws-hairline) * 2); }
|
|
36
|
+
.ws-stepper--milestones .ws-stepper__line-fill { transform-origin: left; }
|
|
37
|
+
.ws-stepper--milestones .ws-stepper__mark { width: var(--space-xs); height: var(--space-xs); }
|
|
38
|
+
.ws-stepper--milestones .ws-stepper__mark--wait { box-shadow: inset 0 0 0 calc(var(--ws-hairline) * 2) var(--ws-edge-card); }
|
|
39
|
+
.ws-stepper--milestones .ws-stepper__body { flex: 0 0 auto; flex-direction: row; align-items: baseline; gap: var(--space-xxs-plus); padding-top: 0; white-space: nowrap; }
|
|
40
|
+
@supports (animation-timeline: scroll()) {
|
|
41
|
+
.ws-stepper--across, .ws-stepper--milestones { mask-image: linear-gradient(90deg, transparent, currentColor var(--ws-fade-start), currentColor calc(100% - var(--ws-fade-end)), transparent); animation: ws-scroll-edges linear; animation-timeline: scroll(self inline); }
|
|
42
|
+
}
|
|
@@ -9,6 +9,7 @@ Eight weeks of activity as rows, Monday to Sunday across: a done day a pill, an
|
|
|
9
9
|
**Not for**
|
|
10
10
|
|
|
11
11
|
- Several people's attendance at once: use `ActivityGrid`.
|
|
12
|
+
- Things that fall on a day (posts, tasks, sends) to open from their date: use `Calendar`.
|
|
12
13
|
- A count out of a whole with no date axis: use `TickRow` or `GoalTicks`.
|
|
13
14
|
- A trend line of a number changing day to day: this chart never plots a value, only whether a day happened.
|
|
14
15
|
|