@felloinnovations/brand-kit 0.5.1 → 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 +86 -0
- package/README.md +10 -4
- package/design-system/01-how-claude-decides.md +5 -3
- package/design-system/03-colour.md +19 -1
- 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 +6 -3
- package/design-system/11-page-recipes.md +40 -1
- package/design-system/13-motion.md +1 -1
- package/design-system/15-ai-experiences.md +11 -0
- package/design-system/17-decisions.md +41 -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/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 +68 -4
- package/design-system/components/KanbanBoard/preview.html +129 -0
- package/design-system/components/KanbanBoard/style.css +31 -0
- 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 +11 -6
- package/design-system/components/Skeleton/README.md +66 -2
- package/design-system/components/Skeleton/preview.html +83 -1
- 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 +7 -3
- package/design-system/components/Table/preview.html +15 -0
- package/design-system/components/Table/style.css +2 -0
- 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/Timeline/README.md +3 -1
- 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/bundle.css +483 -7
- package/design-system/tokens.json +15 -1
- 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 +8 -0
- package/dist/tokens.js +8 -0
- package/package.json +7 -2
- package/scripts/check-drift.mjs +325 -0
- package/scripts/token-model.mjs +2 -1
- package/tokens/_dark.css +2 -0
- package/tokens/_product.css +2 -0
- 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 +14 -1
- package/tokens/tokens.md +53 -46
- package/tokens/tokens.root.css +14 -1
- package/tokens/tokens.ts +9 -1
|
@@ -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
|
|
|
@@ -25,7 +25,9 @@ a phone fold. This is the whole wide-table pattern; build every records table fr
|
|
|
25
25
|
and takes the card's corners). A wide table scrolls inside its card, never the page.
|
|
26
26
|
- Every cell: 8 px above and below (`--space-xs`), 12 at the sides (`--space-sm`), one line (`white-space: nowrap`, so
|
|
27
27
|
a squeezed table scrolls instead of breaking every cell to a word a line). A cell that may wrap takes `ws-table__wrap`
|
|
28
|
-
(at least 200 wide)
|
|
28
|
+
(at least 200 wide: one long column of words); several short prose columns (a note, a reason, a description) take
|
|
29
|
+
`ws-table__prose`, which wraps at whatever width the column gets, with no floor, so five columns still fit the card.
|
|
30
|
+
Put either on the `th` and every `td` of the column.
|
|
29
31
|
- The outer cells sit on the card's 20 px edge (`--ws-card-inset`): the first cell's left and the last cell's right, so
|
|
30
32
|
the table lines up with the card's head, band and pagination.
|
|
31
33
|
- Head: rows at least 40 (`--ws-row-h-dense`), 13 / 18 medium muted labels (`--ws-text-control`, `--color-text-muted`),
|
|
@@ -120,7 +122,7 @@ a phone fold. This is the whole wide-table pattern; build every records table fr
|
|
|
120
122
|
"Rows vs table"), and it always shows that it scrolls: the shade and the fade.
|
|
121
123
|
- **One content edge per card**: the first and last cells sit on the card's 20 px edge, like its head (K8).
|
|
122
124
|
- **Numbers line up through fixed numeric columns** (North, A4), right-aligned, tabular, the `th` included.
|
|
123
|
-
- **Every row is one line**: a squeezed table scrolls; only a cell marked `__wrap` breaks, and under 30rem the stuck
|
|
125
|
+
- **Every row is one line**: a squeezed table scrolls; only a cell marked `__wrap` or `__prose` breaks, and under 30rem the stuck
|
|
124
126
|
name, which would otherwise leave no room for the columns sliding under it.
|
|
125
127
|
- **A selected row never changes colour alone**: the navy mark travels with the tint.
|
|
126
128
|
- **Row acts are always in the DOM**: hover-to-reveal is cosmetic only.
|
|
@@ -173,5 +175,7 @@ columns with no cue, cells 12 in against the card's 20, no vertical padding, no
|
|
|
173
175
|
|
|
174
176
|
`design-system/components/Table/style.css`, in `bundle.css` and `fello.css`. Light, dark and the navy ground come from
|
|
175
177
|
the tokens (`--color-bg-page`, `--ws-surface-sunk`, `--ws-hover-faint`, `--ws-divider`); a table on another surface
|
|
176
|
-
sets `--ws-table-ground
|
|
178
|
+
sets `--ws-table-ground` to that surface's token, on the `ws-table` element: a white card or panel
|
|
179
|
+
`var(--color-surface)`, a raised panel or menu `var(--ws-raised)`, a plate `var(--ws-surface-sunk)`. A product card
|
|
180
|
+
is the cream already, so it needs nothing. The card is a size container named `ws-table`, so it needs the width of its column (a card in
|
|
177
181
|
a shrink-to-fit row collapses: give it a width). The edge cues use scroll-driven animations where the browser has them.
|
|
@@ -166,6 +166,21 @@
|
|
|
166
166
|
</section>
|
|
167
167
|
</div>
|
|
168
168
|
|
|
169
|
+
<div class="ws-stack" style="width: min(100%, 560px);">
|
|
170
|
+
<span class="ws-muted">Short prose columns (__prose): each wraps at the width its column gets, with no 200 px floor; on a phone the rest still scrolls</span>
|
|
171
|
+
<section class="ws-card ws-table" aria-label="Ads review">
|
|
172
|
+
<div class="ws-table__scroll">
|
|
173
|
+
<table>
|
|
174
|
+
<thead><tr><th scope="col" class="ws-table__name">Ad</th><th scope="col" class="ws-table__prose">Reason</th><th scope="col" class="ws-table__prose">Note</th><th scope="col" class="ws-table__num">Spend</th></tr></thead>
|
|
175
|
+
<tbody>
|
|
176
|
+
<tr><td class="ws-table__name">Spring open house</td><td class="ws-table__prose">The image is mostly words</td><td class="ws-table__prose">Swap in the porch photo</td><td class="ws-table__num">$420</td></tr>
|
|
177
|
+
<tr><td class="ws-table__name">First-time buyers</td><td class="ws-table__prose">Approved</td><td class="ws-table__prose">Runs through Friday</td><td class="ws-table__num">$1,180</td></tr>
|
|
178
|
+
</tbody>
|
|
179
|
+
</table>
|
|
180
|
+
</div>
|
|
181
|
+
</section>
|
|
182
|
+
</div>
|
|
183
|
+
|
|
169
184
|
<div class="ws-stack" style="width: 300px;">
|
|
170
185
|
<span class="ws-muted">Empty, no matches: the same card, the act that clears the filter</span>
|
|
171
186
|
<section class="ws-card ws-table" aria-label="Leads, no matches">
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
.ws-table tr > :first-child { padding-left: var(--ws-card-inset); }
|
|
20
20
|
.ws-table tr > :last-child { padding-right: var(--ws-card-inset); }
|
|
21
21
|
.ws-table .ws-table__wrap { white-space: normal; min-width: var(--space-9xl); }
|
|
22
|
+
/* A short prose cell (a note, a reason) that wraps at whatever width its column gets, with no floor (#21). */
|
|
23
|
+
.ws-table .ws-table__prose { white-space: normal; text-wrap: pretty; }
|
|
22
24
|
/* Head: 13 / 18 medium muted labels, stuck to the top of the scroller. */
|
|
23
25
|
.ws-table thead th { position: sticky; top: 0; z-index: 2; height: var(--ws-row-h-dense); font-size: var(--ws-text-control); line-height: var(--ws-leading-control); font-weight: 500; color: var(--color-text-muted); border-bottom: var(--ws-divider); }
|
|
24
26
|
.ws-table thead th[aria-sort="ascending"], .ws-table thead th[aria-sort="descending"] { color: var(--color-text-heading); }
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Two versions of a text side by side in one place: what was removed and what was added, by line or inside the words,
|
|
2
|
+
told apart by a sign, a strike or an underline as well as by colour.
|
|
3
|
+
|
|
4
|
+
## Use it when
|
|
5
|
+
|
|
6
|
+
- A person checks a change to text before accepting it, or looks back at what changed: a prompt before and after an
|
|
7
|
+
edit, a proposed rewrite of a blog body, a saved version against the current one.
|
|
8
|
+
- The point is the change itself, not either version alone.
|
|
9
|
+
|
|
10
|
+
## Not for
|
|
11
|
+
|
|
12
|
+
- A number that went up or down: a `ChangeChip` or the chart's own moment.
|
|
13
|
+
- A list of what someone did and when: `Timeline`.
|
|
14
|
+
- Showing one version: plain text in the card, with "Version of Nov 9" in its meta.
|
|
15
|
+
|
|
16
|
+
## Anatomy
|
|
17
|
+
|
|
18
|
+
- **By line** (`ws-diff`): a framed block on the field's white ground (the fine edge drawn inside, 4 px corners), 14 /
|
|
19
|
+
20 body words, line breaks kept (`pre-wrap`). Each line (`__line`) is a 16 px sign column (`__sign`), 8 apart, then
|
|
20
|
+
the words; 2 / 12 inside.
|
|
21
|
+
- A removed line (`<del class="ws-diff__line ws-diff__line--removed">`): the needs tint (`--ws-tint-needs`), its words
|
|
22
|
+
and its minus sign in the needs word (`--ws-word-needs`). Not struck: the old words stay easy to read.
|
|
23
|
+
- An added line (`<ins class="ws-diff__line ws-diff__line--added">`): the live tint (`--ws-tint-live`), its words and
|
|
24
|
+
its plus sign in the positive word (`--ws-word-positive`).
|
|
25
|
+
- An unchanged line: no ground, no sign, the body's words.
|
|
26
|
+
- A folded run of unchanged lines (`__skip`): one row on the sunk ground, the whole row the act ("6 unchanged
|
|
27
|
+
lines"), its words in the text column, navy medium in the meta size, the wash under the pointer, 24 tall (40 on
|
|
28
|
+
touch). Pressed, the run opens in its place (`aria-expanded`).
|
|
29
|
+
- **Inline** (`ws-diff__del`, `ws-diff__ins` inside a `ws-body` paragraph): removed words on the needs tint, in the
|
|
30
|
+
needs word, struck through; added words on the live tint, in the positive word, underlined. 2 px corners.
|
|
31
|
+
- Every change says itself to a screen reader: a hidden word first inside each `del` and `ins`
|
|
32
|
+
(`<span class="ws-sr">Removed: </span>`), because most screen readers do not announce the elements themselves.
|
|
33
|
+
- The card around it says what is compared ("Version of Nov 9 against the current one") and the count ("1 line
|
|
34
|
+
removed, 2 added") in its meta.
|
|
35
|
+
|
|
36
|
+
## Variants and sizes
|
|
37
|
+
|
|
38
|
+
| Variant | Use | Notes |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| By line (`ws-diff`) | a prompt, a list, a template, any text whose lines matter | unchanged runs of more than 3 lines fold, keeping 1 line of context on each side |
|
|
41
|
+
| Inline (`__del`, `__ins`) | a paragraph rewritten in places | when most words stay; a rewrite of most of it reads better by line |
|
|
42
|
+
|
|
43
|
+
## States
|
|
44
|
+
|
|
45
|
+
- **Folded**: unchanged runs behind their `__skip` row; the card's act "Show the whole prompt" opens them all.
|
|
46
|
+
- **Open**: every line shown, the changes still marked.
|
|
47
|
+
- **No changes**: no diff; one line in the card ("No changes since Nov 9").
|
|
48
|
+
- **Long line**: wraps inside its column, under its own words, never under the sign; never a sideways scroll.
|
|
49
|
+
- **Dark**: the tints and the words take their dark values (AA on each tint).
|
|
50
|
+
|
|
51
|
+
## Behaviour
|
|
52
|
+
|
|
53
|
+
- Keyboard: each `__skip` row is a button (Enter or Space opens its run); nothing else in a diff is a stop.
|
|
54
|
+
- The diff is computed by the app (by line or by word); the component only draws it. Lines keep their order: a changed
|
|
55
|
+
line is its removed version, then its added one.
|
|
56
|
+
- Copying a diff copies its words, not its signs (`user-select: none` on the sign).
|
|
57
|
+
- Motion: an opened run rises in (`ws-arrive` on its lines); still under reduced motion.
|
|
58
|
+
|
|
59
|
+
## Content
|
|
60
|
+
|
|
61
|
+
- Say what is compared and when ("Version of Nov 9 against the current one"), never "Old" and "New".
|
|
62
|
+
- The count in words: "1 line removed, 2 added", "3 changes".
|
|
63
|
+
|
|
64
|
+
## Rules
|
|
65
|
+
|
|
66
|
+
- Never colour alone: a removed line has its minus, an added one its plus; inline, removed is struck and added
|
|
67
|
+
underlined. An underline inside a diff means added, never a link: a diff holds no links.
|
|
68
|
+
- Removed is the needs tone, added the live tone, both at their AA word steps. Never the alert red, never a raw green.
|
|
69
|
+
- One diff per card, and the card says what it compares.
|
|
70
|
+
|
|
71
|
+
## Source
|
|
72
|
+
|
|
73
|
+
- **Derived from**: the kit's needs and live tints and their AA words (Colour), the field's ground and edge (`Input`),
|
|
74
|
+
`Plate`'s sunk ground for the folded run.
|
|
75
|
+
- **Precedent**: Marketing OS (ContentOS): the prompt diff, the SEO refresh's body changes and the content version
|
|
76
|
+
history, each hand-built on app-local error and success tints (issue #28, Madan, 10 Nov 2026).
|
|
77
|
+
|
|
78
|
+
## Markup
|
|
79
|
+
|
|
80
|
+
```html
|
|
81
|
+
<!-- By line -->
|
|
82
|
+
<div class="ws-diff" role="group" aria-label="Changes to the prompt">
|
|
83
|
+
<div class="ws-diff__line"><span class="ws-diff__sign" aria-hidden="true"></span><span>You write follow-up emails for real estate agents.</span></div>
|
|
84
|
+
<button type="button" class="ws-diff__skip" aria-expanded="false"><span>6 unchanged lines</span></button>
|
|
85
|
+
<del class="ws-diff__line ws-diff__line--removed"><span class="ws-diff__sign" aria-hidden="true">−</span><span><span class="ws-sr">Removed: </span>Keep every email under 200 words.</span></del>
|
|
86
|
+
<ins class="ws-diff__line ws-diff__line--added"><span class="ws-diff__sign" aria-hidden="true">+</span><span><span class="ws-sr">Added: </span>Keep every email under 120 words.</span></ins>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<!-- Inline -->
|
|
90
|
+
<p class="ws-body">Spring is <del class="ws-diff__del"><span class="ws-sr">removed: </span>usually</del> <ins class="ws-diff__ins"><span class="ws-sr">added: </span>still</ins> the busiest season.</p>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Styles
|
|
94
|
+
|
|
95
|
+
`design-system/components/TextDiff/style.css`: `ws-diff`, `__line` (`--removed`, `--added`), `__sign`, `__skip`,
|
|
96
|
+
`__del`, `__ins`.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<!-- @dsCard group="Data" height=620 -->
|
|
2
|
+
<!doctype html>
|
|
3
|
+
<html>
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>TextDiff</title>
|
|
7
|
+
<link rel="stylesheet" href="../../tokens.css">
|
|
8
|
+
<link rel="stylesheet" href="../bundle.css">
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div class="ws-stage">
|
|
12
|
+
<div class="ws-stack" style="width: 460px;">
|
|
13
|
+
<span class="ws-muted">By line: a prompt before and after an edit, the unchanged run folded</span>
|
|
14
|
+
<div class="ws-card ws-card--pad-md ws-stack ws-stack--loose">
|
|
15
|
+
<div class="ws-stack ws-stack--tight">
|
|
16
|
+
<h3 class="ws-section">What changes in the prompt</h3>
|
|
17
|
+
<p class="ws-meta">1 line removed, 2 added</p>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="ws-diff" role="group" aria-label="Changes to the prompt">
|
|
20
|
+
<div class="ws-diff__line"><span class="ws-diff__sign" aria-hidden="true"></span><span>You write follow-up emails for real estate agents.</span></div>
|
|
21
|
+
<button type="button" class="ws-diff__skip" aria-expanded="false"><span>6 unchanged lines</span></button>
|
|
22
|
+
<del class="ws-diff__line ws-diff__line--removed"><span class="ws-diff__sign" aria-hidden="true">−</span><span><span class="ws-sr">Removed: </span>Keep every email under 200 words.</span></del>
|
|
23
|
+
<ins class="ws-diff__line ws-diff__line--added"><span class="ws-diff__sign" aria-hidden="true">+</span><span><span class="ws-sr">Added: </span>Keep every email under 120 words.</span></ins>
|
|
24
|
+
<ins class="ws-diff__line ws-diff__line--added"><span class="ws-diff__sign" aria-hidden="true">+</span><span><span class="ws-sr">Added: </span>Name the listing in the first line.</span></ins>
|
|
25
|
+
<div class="ws-diff__line"><span class="ws-diff__sign" aria-hidden="true"></span><span>Sign off with the agent's first name.</span></div>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div class="ws-stack" style="width: 460px;">
|
|
31
|
+
<span class="ws-muted">Inline: a proposed rewrite of a blog paragraph, removed words struck, added words underlined</span>
|
|
32
|
+
<div class="ws-card ws-card--pad-md ws-stack ws-stack--loose">
|
|
33
|
+
<div class="ws-stack ws-stack--tight">
|
|
34
|
+
<h3 class="ws-section">Suggested rewrite</h3>
|
|
35
|
+
<p class="ws-meta">Version of Nov 9 against the current one</p>
|
|
36
|
+
</div>
|
|
37
|
+
<p class="ws-body">Spring is <del class="ws-diff__del"><span class="ws-sr">removed: </span>usually</del> <ins class="ws-diff__ins"><span class="ws-sr">added: </span>still</ins> the busiest season for listings in Ohio, and buyers who <del class="ws-diff__del"><span class="ws-sr">removed: </span>start looking in January</del> <ins class="ws-diff__ins"><span class="ws-sr">added: </span>get pre-approved by February</ins> close first.</p>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</body>
|
|
42
|
+
</html>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/* ---- TextDiff: two versions of a text, what was removed and what was added, told apart by more than colour. By line
|
|
2
|
+
(`ws-diff`): a framed block, each changed line on its tint with a sign in a 16 px gutter (minus removed, plus added),
|
|
3
|
+
unchanged runs folded behind a quiet act. Inline (`ws-diff__del`, `ws-diff__ins` in running words): removed words on
|
|
4
|
+
the needs tint and struck, added words on the live tint and underlined. Every change also says itself to a screen
|
|
5
|
+
reader (a ws-sr word inside the del or the ins). ---- */
|
|
6
|
+
.ws-diff { display: grid; min-width: 0; overflow: clip; border-radius: var(--ws-radius-control); background: var(--ws-field); box-shadow: var(--ws-shadow-hairline-in); color: var(--color-text-body); font-size: var(--ws-text-body); line-height: calc(var(--space-md) + var(--space-xxs)); }
|
|
7
|
+
.ws-diff__line { display: grid; grid-template-columns: var(--space-md) minmax(0, 1fr); column-gap: var(--space-xs); padding: var(--space-3xs) var(--space-sm); white-space: pre-wrap; overflow-wrap: anywhere; text-decoration: none; }
|
|
8
|
+
.ws-diff__sign { font-weight: 600; text-align: center; user-select: none; }
|
|
9
|
+
.ws-diff__line--removed { background: var(--ws-tint-needs); color: var(--ws-word-needs); }
|
|
10
|
+
.ws-diff__line--added { background: var(--ws-tint-live); color: var(--ws-word-positive); }
|
|
11
|
+
/* An unchanged run folded: the row itself is the act (it opens the run), on the sunk ground, its words in the text
|
|
12
|
+
column saying how many lines it holds, the wash under the pointer. */
|
|
13
|
+
.ws-diff__skip { display: grid; grid-template-columns: var(--space-md) minmax(0, 1fr); column-gap: var(--space-xs); width: 100%; min-height: var(--space-lg); padding: var(--space-3xs) var(--space-sm); border: 0; background: var(--ws-surface-sunk); color: var(--color-text-heading); font: inherit; font-size: var(--ws-text-meta); font-weight: 500; text-align: start; cursor: pointer; transition: background-color var(--ws-duration-hover) var(--ws-ease-soft); }
|
|
14
|
+
.ws-diff__skip > * { grid-column: 2; }
|
|
15
|
+
@media (pointer: coarse) { .ws-diff__skip { min-height: var(--ws-touch); } }
|
|
16
|
+
@media (hover: hover) { .ws-diff__skip:hover { background-image: linear-gradient(var(--ws-hover), var(--ws-hover)); } }
|
|
17
|
+
.ws-diff__skip:focus-visible { outline-offset: calc(var(--ws-focus-width) * -1); }
|
|
18
|
+
/* Inline: changed words inside a sentence. */
|
|
19
|
+
.ws-diff__del, .ws-diff__ins { border-radius: calc(var(--ws-radius-control) / 2); text-decoration-thickness: var(--ws-line); }
|
|
20
|
+
.ws-diff__del { background: var(--ws-tint-needs); color: var(--ws-word-needs); text-decoration-line: line-through; }
|
|
21
|
+
.ws-diff__ins { background: var(--ws-tint-live); color: var(--ws-word-positive); text-decoration-line: underline; text-underline-offset: var(--space-3xs); }
|
|
@@ -7,7 +7,9 @@ A vertical feed of what happened, grouped by day, a coloured dot on a fine line
|
|
|
7
7
|
|
|
8
8
|
## Not for
|
|
9
9
|
|
|
10
|
-
- A sequence of steps still in progress toward an end: use `Stepper`.
|
|
10
|
+
- A sequence of steps still in progress toward an end: use `Stepper`; a thing's stages across its head: `Stepper --across`.
|
|
11
|
+
- A few dated milestones on one row (signed, first value): use `Stepper --milestones`.
|
|
12
|
+
- A plan's phases across their dates: use `PlanTimeline`. Things that fall on a day (posts, sends): use `Calendar`.
|
|
11
13
|
- A list of records to compare or act on: use `Table` or rows in a `Card`.
|
|
12
14
|
- A single moment worth calling out inside a chart: use `TrendBars`' own labelled moment.
|
|
13
15
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
A value over periods against an axis, as a line with its dots and the hatched area under it, or as columns that collapse into the line's points and back.
|
|
1
|
+
A value over periods against an axis, as a line with its dots and the hatched area under it, or as columns that collapse into the line's points and back; up to three series in one unit as lines with a key.
|
|
2
2
|
|
|
3
3
|
**Use it when**
|
|
4
4
|
|
|
@@ -7,13 +7,17 @@ A value over periods against an axis, as a line with its dots and the hatched ar
|
|
|
7
7
|
- The same run reads two ways: columns to compare periods, a line to see the trend. A Bars / Line switch over the card
|
|
8
8
|
shows both, from the same data, with no reload: the columns collapse into the line's points.
|
|
9
9
|
- A tile needs a small preview of that run (`--bare`, inside `MetricTile`'s `__preview`).
|
|
10
|
+
- Two or three series in one unit move over the same periods and the reader compares them (onboardings started,
|
|
11
|
+
graduated and stalled, by month): one axis, a line each, a key naming them (`__series`).
|
|
10
12
|
|
|
11
13
|
**Not for**
|
|
12
14
|
|
|
13
15
|
- A day-by-day trend with one moment that explains it: use `TrendBars`.
|
|
14
16
|
- A bill or a rate that steps against a reference, the gap hatched: use `StepLine`.
|
|
15
17
|
- Parts of one whole: use `ShareBar`. A goal's share: `GoalTicks` or `PaceBar`.
|
|
16
|
-
-
|
|
18
|
+
- Series in different units, or one more than four times another (accounts and tickets): never two value axes. Stack
|
|
19
|
+
two TrendLines in one card on the same periods (Rules).
|
|
20
|
+
- More than three series: a `Table`, or the three that matter and the rest named in the sentence.
|
|
17
21
|
|
|
18
22
|
**Anatomy**
|
|
19
23
|
|
|
@@ -42,8 +46,16 @@ A value over periods against an axis, as a line with its dots and the hatched ar
|
|
|
42
46
|
each a `title`); the current one (`__now`) 600 navy.
|
|
43
47
|
- Key (`__legend`, optional): centred, 16 apart, 16 above; a 12 px swatch in the mark's look (`__key--now`,
|
|
44
48
|
`__key--ahead`, `__key--ref` for the dotted line), 8, 14/20 medium body grey.
|
|
45
|
-
-
|
|
46
|
-
the `
|
|
49
|
+
- Several series (up to 3): the first is the figure's own `__draw` and points; each other is a `__series` box after
|
|
50
|
+
them (`display: contents`, so its points still sit on the plot) holding its own `__draw` (the SVG path only, no
|
|
51
|
+
hatch) and its points, the same `--i` and `--n`. Tones in order: navy, teal (`--ws-chart-finished`), purple
|
|
52
|
+
(`--ws-chart-past-half`); salmon stays the reference's. `--tone` on a series overrides its tone (a figure that sets
|
|
53
|
+
its own `--tone` sets one on each series too, since the figure's is inherited). The key names every series:
|
|
54
|
+
`__key--2` and `__key--3` take the second and third tones (an overridden series' `<li>` carries the same `--tone`).
|
|
55
|
+
With several series there is no hatch (one area claims a whole; two cover each other) and the period in progress
|
|
56
|
+
keeps its series' tone: its name (`__now`) and the dotted `__ahead` say it.
|
|
57
|
+
- The reading (`__table`): a real `<table>` of every period and its value (a column a series), with a caption, hidden
|
|
58
|
+
from the eye inside the `__table` box. The plot is `aria-hidden`.
|
|
47
59
|
|
|
48
60
|
**Parts and modifiers**
|
|
49
61
|
|
|
@@ -54,6 +66,7 @@ A value over periods against an axis, as a line with its dots and the hatched ar
|
|
|
54
66
|
- `__point--now`, `__point--ahead`: the period in progress; a period to come.
|
|
55
67
|
- `__point--on`: the point held open (a tap, or the keyboard's mark when the app moves one); it looks hovered.
|
|
56
68
|
- `__band`: the hover band, last in the plot. `__now`: the current period's name.
|
|
69
|
+
- `__series`: a second or third series, after the first series' points; `__key--2`, `__key--3`: its swatch in the key.
|
|
57
70
|
|
|
58
71
|
**States**
|
|
59
72
|
|
|
@@ -77,7 +90,9 @@ A value over periods against an axis, as a line with its dots and the hatched ar
|
|
|
77
90
|
tall, the other columns step back to `--ws-dim` over the hover. Line: the band is a dashed guide from the dot to the
|
|
78
91
|
baseline, and the dot grows to 1.5 inside a faint halo over `--ws-duration-hover` (North's `r .2s`). The band rides
|
|
79
92
|
CSS anchor positioning: without it the band is left out and the rest still happens. A `HoverCard`
|
|
80
|
-
(`--above --follow`) reads the point.
|
|
93
|
+
(`--above --follow`) reads the point. With several series it reads the period, not the dot: the eyebrow names the
|
|
94
|
+
period (no swatch), then a row a series in the key's order, each with its swatch and value (`__row`); it sits over
|
|
95
|
+
the period's highest dot. The guide runs from the hovered dot to the baseline, through the others.
|
|
81
96
|
- Narrow (the figure under 30rem): the plot is 200 tall; with more than six names, every other one and the current
|
|
82
97
|
one's neighbours give way and the rest take two slots.
|
|
83
98
|
- Zero: every column a 2 px stub on the baseline, every dot on it. One period: a dot (or a column) and no line.
|
|
@@ -104,7 +119,12 @@ A value over periods against an axis, as a line with its dots and the hatched ar
|
|
|
104
119
|
|
|
105
120
|
**Rules**
|
|
106
121
|
|
|
107
|
-
- **
|
|
122
|
+
- **Up to three series in one unit, one optional reference.** One value axis, always: never two.
|
|
123
|
+
- **Different units or scales far apart** (one series more than four times another): two TrendLines stacked in one
|
|
124
|
+
card on the same periods (`--n`) and the same gutter (`--ws-trend-line-y`), each with its own value labels and a key
|
|
125
|
+
of one; the period names only under the last (leave the first's `__x` out). One title and one sentence for the pair.
|
|
126
|
+
- **Several series are lines only**: no hatch and no Bars / Line switch (two columns cannot share a slot and still
|
|
127
|
+
collapse into their dots). A chart that wants columns per period across series is a `Table` or two cards.
|
|
108
128
|
- **Columns start at zero.** A chart with the switch, or any columns, has its baseline at 0; a line alone may start
|
|
109
129
|
above zero only without the hatch (an area claims a whole).
|
|
110
130
|
- **The same data in both modes**: the switch changes the drawing, never the numbers.
|
|
@@ -143,6 +163,17 @@ A value over periods against an axis, as a line with its dots and the hatched ar
|
|
|
143
163
|
</figure>
|
|
144
164
|
```
|
|
145
165
|
|
|
166
|
+
A second series, after the first series' points (a third is another `__series` after it):
|
|
167
|
+
|
|
168
|
+
```html
|
|
169
|
+
<span class="ws-trend-line__series">
|
|
170
|
+
<span class="ws-trend-line__draw"><svg class="ws-trend-line__lines" viewBox="0 0 100 100" preserveAspectRatio="none" aria-hidden="true"><path d="M12.5 70 L37.5 62.5 L62.5 52.5 L87.5 40"/></svg></span>
|
|
171
|
+
<span class="ws-trend-line__point" style="--i: 0; --y: 70%;"></span><!-- a point a period -->
|
|
172
|
+
</span>
|
|
173
|
+
<!-- the key, after the plot: <ul class="ws-trend-line__legend" aria-hidden="true"><li>Started</li><li class="ws-trend-line__key--2">Graduated</li></ul> -->
|
|
174
|
+
<!-- the table: a column a series, <th scope="col"> named as the key -->
|
|
175
|
+
```
|
|
176
|
+
|
|
146
177
|
A reference goes after the rules: `<span class="ws-trend-line__ref" style="--y: 19.94%;"><span>Plan $40.03M</span></span>`.
|
|
147
178
|
What is to come: `__point--ahead` on its points, and a second path `<path class="ws-trend-line__ahead" d="...">` from
|
|
148
179
|
the last real point on. The switch, in the card's head:
|
|
@@ -160,5 +191,5 @@ on tokens, except North's own numbers: the dotted line's 0.1 dash (a round cap's
|
|
|
160
191
|
the hatch at 45%, the hovered dot's 1.5 and its halo at 12%, and the build's 55 / 45 share. Tokens: `--ws-duration-draw`,
|
|
161
192
|
`--ws-duration-settle`, `--ws-duration-hover`, `--ws-duration-exit`, `--ws-ease-settle`, `--ws-ease-steady`,
|
|
162
193
|
`--ws-ease-pop`, `--ws-ease-soft`, `--ws-ease-exit`, `--ws-spring-morph-chart` and its duration, `--ws-dim`,
|
|
163
|
-
`--ws-hover`, `--ws-chart-line`, `--ws-chart-navy-light`, `--ws-chart-under-half`, `--ws-word-needs`, `--ws-edge-slot`,
|
|
194
|
+
`--ws-hover`, `--ws-chart-line`, `--ws-chart-navy-light`, `--ws-chart-finished`, `--ws-chart-past-half`, `--ws-chart-under-half`, `--ws-word-needs`, `--ws-edge-slot`,
|
|
164
195
|
`--ws-edge-card`.
|