@felloinnovations/brand-kit 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +198 -24
- package/CHANGELOG.md +221 -0
- package/README.md +38 -9
- package/design-system/01-how-claude-decides.md +26 -17
- package/design-system/02-principles.md +11 -6
- package/design-system/03-colour.md +135 -47
- package/design-system/04-type.md +45 -23
- package/design-system/05-space-and-layout.md +175 -52
- package/design-system/06-sizing-profiles.md +4 -4
- package/design-system/07-scrolling.md +66 -20
- package/design-system/08-choosing-components.md +50 -22
- package/design-system/09-charts.md +71 -28
- package/design-system/10-patterns.md +33 -10
- package/design-system/11-page-recipes.md +110 -23
- package/design-system/12-content.md +2 -1
- package/design-system/13-motion.md +330 -47
- package/design-system/14-accessibility.md +47 -24
- package/design-system/15-ai-experiences.md +11 -6
- package/design-system/16-creativity.md +1 -1
- package/design-system/17-decisions.md +367 -1
- package/design-system/18-checklist.md +79 -16
- package/design-system/19-public-pages.md +6 -4
- package/design-system/20-palettes.md +275 -0
- package/design-system/README.md +30 -17
- package/design-system/components/ActionList/README.md +96 -10
- package/design-system/components/ActionList/preview.html +52 -7
- package/design-system/components/ActionList/style.css +64 -0
- package/design-system/components/ActivityGrid/README.md +38 -2
- package/design-system/components/ActivityGrid/preview.html +1 -1
- package/design-system/components/ActivityGrid/style.css +35 -0
- package/design-system/components/AppShell/README.md +205 -75
- package/design-system/components/AppShell/preview.html +339 -58
- package/design-system/components/AppShell/style.css +154 -0
- package/design-system/components/Avatar/README.md +37 -10
- package/design-system/components/Avatar/preview.html +13 -4
- package/design-system/components/Avatar/style.css +14 -0
- package/design-system/components/Badge/README.md +41 -19
- package/design-system/components/Badge/preview.html +13 -10
- package/design-system/components/Badge/style.css +23 -0
- package/design-system/components/Banner/README.md +30 -9
- package/design-system/components/Banner/preview.html +1 -1
- package/design-system/components/Banner/style.css +19 -0
- package/design-system/components/Breadcrumb/README.md +58 -46
- package/design-system/components/Breadcrumb/preview.html +16 -16
- package/design-system/components/Breadcrumb/style.css +17 -0
- package/design-system/components/Button/README.md +113 -55
- package/design-system/components/Button/preview.html +98 -25
- package/design-system/components/Button/style.css +86 -0
- package/design-system/components/Card/README.md +158 -49
- package/design-system/components/Card/preview.html +141 -19
- package/design-system/components/Card/style.css +115 -0
- package/design-system/components/CardBoard/README.md +58 -37
- package/design-system/components/CardBoard/preview.html +26 -29
- package/design-system/components/ChatCard/README.md +115 -29
- package/design-system/components/ChatCard/preview.html +149 -32
- package/design-system/components/ChatCard/style.css +49 -0
- package/design-system/components/ChatShell/README.md +116 -0
- package/design-system/components/ChatShell/preview.html +201 -0
- package/design-system/components/ChatShell/style.css +86 -0
- package/design-system/components/ChatTurn/README.md +78 -35
- package/design-system/components/ChatTurn/preview.html +60 -28
- package/design-system/components/ChatTurn/style.css +50 -0
- package/design-system/components/CheckRow/README.md +141 -0
- package/design-system/components/CheckRow/preview.html +140 -0
- package/design-system/components/CheckRow/style.css +88 -0
- package/design-system/components/Checkbox/README.md +58 -22
- package/design-system/components/Checkbox/preview.html +112 -50
- package/design-system/components/Checkbox/style.css +45 -0
- package/design-system/components/Chip/README.md +78 -47
- package/design-system/components/Chip/preview.html +29 -4
- package/design-system/components/Chip/style.css +17 -0
- package/design-system/components/Combobox/README.md +44 -11
- package/design-system/components/Combobox/preview.html +35 -12
- package/design-system/components/Combobox/style.css +54 -0
- package/design-system/components/Composer/README.md +137 -35
- package/design-system/components/Composer/preview.html +115 -40
- package/design-system/components/Composer/style.css +81 -0
- package/design-system/components/ConfirmDialog/README.md +73 -52
- package/design-system/components/ConfirmDialog/preview.html +70 -26
- package/design-system/components/ConfirmDialog/style.css +5 -0
- package/design-system/components/Cover/preview.html +3 -3
- package/design-system/components/Cover/style.css +19 -0
- package/design-system/components/DateInput/README.md +77 -12
- package/design-system/components/DateInput/preview.html +27 -12
- package/design-system/components/DateInput/style.css +38 -0
- package/design-system/components/Dialog/README.md +112 -44
- package/design-system/components/Dialog/preview.html +141 -18
- package/design-system/components/Dialog/style.css +74 -0
- package/design-system/components/EmptyState/README.md +42 -12
- package/design-system/components/EmptyState/preview.html +11 -11
- package/design-system/components/EmptyState/style.css +9 -0
- package/design-system/components/EntryShell/README.md +73 -48
- package/design-system/components/EntryShell/preview.html +60 -27
- package/design-system/components/EntryShell/style.css +19 -0
- package/design-system/components/FeatureGrid/README.md +61 -39
- package/design-system/components/FeatureGrid/preview.html +2 -2
- package/design-system/components/FeatureGrid/style.css +20 -0
- package/design-system/components/FileUpload/README.md +33 -3
- package/design-system/components/FileUpload/preview.html +18 -4
- package/design-system/components/FileUpload/style.css +23 -0
- package/design-system/components/FilterBar/README.md +114 -0
- package/design-system/components/FilterBar/preview.html +82 -0
- package/design-system/components/FilterBar/style.css +22 -0
- package/design-system/components/Fold/README.md +84 -26
- package/design-system/components/Fold/preview.html +77 -34
- package/design-system/components/Fold/style.css +48 -0
- package/design-system/components/Footer/README.md +62 -39
- package/design-system/components/Footer/preview.html +5 -5
- package/design-system/components/Footer/style.css +30 -0
- package/design-system/components/FunnelBars/README.md +24 -3
- package/design-system/components/FunnelBars/preview.html +5 -5
- package/design-system/components/FunnelBars/style.css +13 -0
- package/design-system/components/GoalBars/README.md +54 -10
- package/design-system/components/GoalBars/preview.html +69 -28
- package/design-system/components/GoalBars/style.css +51 -0
- package/design-system/components/GoalTicks/README.md +74 -58
- package/design-system/components/GoalTicks/preview.html +41 -118
- package/design-system/components/GoalTicks/style.css +37 -0
- package/design-system/components/GoalTubes/README.md +29 -3
- package/design-system/components/GoalTubes/preview.html +6 -6
- package/design-system/components/GoalTubes/style.css +23 -0
- package/design-system/components/Heatmap/README.md +133 -0
- package/design-system/components/Heatmap/preview.html +168 -0
- package/design-system/components/Heatmap/style.css +119 -0
- package/design-system/components/Hero/README.md +58 -40
- package/design-system/components/Hero/preview.html +1 -1
- package/design-system/components/Hero/style.css +19 -0
- package/design-system/components/HoverCard/README.md +114 -0
- package/design-system/components/HoverCard/preview.html +107 -0
- package/design-system/components/HoverCard/style.css +59 -0
- package/design-system/components/IconButton/README.md +69 -38
- package/design-system/components/IconButton/preview.html +77 -43
- package/design-system/components/IconButton/style.css +45 -0
- package/design-system/components/Input/README.md +36 -11
- package/design-system/components/Input/preview.html +1 -1
- package/design-system/components/Input/style.css +23 -0
- package/design-system/components/KanbanBoard/README.md +93 -45
- package/design-system/components/KanbanBoard/preview.html +159 -43
- package/design-system/components/KanbanBoard/style.css +53 -0
- package/design-system/components/Kbd/README.md +25 -9
- package/design-system/components/Kbd/preview.html +6 -2
- package/design-system/components/Kbd/style.css +9 -0
- package/design-system/components/KitButton/README.md +81 -47
- package/design-system/components/KitButton/preview.html +35 -13
- package/design-system/components/KitButton/style.css +46 -0
- package/design-system/components/KitCard/README.md +75 -44
- package/design-system/components/KitCard/preview.html +18 -10
- package/design-system/components/KitCard/style.css +15 -0
- package/design-system/components/KitInput/README.md +54 -39
- package/design-system/components/KitInput/preview.html +7 -7
- package/design-system/components/KitInput/style.css +23 -0
- package/design-system/components/Leaderboard/README.md +76 -49
- package/design-system/components/Leaderboard/preview.html +61 -26
- package/design-system/components/Leaderboard/style.css +44 -0
- package/design-system/components/ListDetail/README.md +222 -0
- package/design-system/components/ListDetail/preview.html +213 -0
- package/design-system/components/ListDetail/style.css +148 -0
- package/design-system/components/LoadBar/README.md +79 -0
- package/design-system/components/LoadBar/preview.html +40 -0
- package/design-system/components/LoadBar/style.css +17 -0
- package/design-system/components/MarketingNav/README.md +76 -42
- package/design-system/components/MarketingNav/preview.html +37 -8
- package/design-system/components/MarketingNav/style.css +45 -0
- package/design-system/components/Matrix/README.md +129 -0
- package/design-system/components/Matrix/preview.html +99 -0
- package/design-system/components/Matrix/style.css +84 -0
- package/design-system/components/Menu/README.md +117 -41
- package/design-system/components/Menu/preview.html +85 -23
- package/design-system/components/Menu/style.css +61 -0
- package/design-system/components/Meter/README.md +39 -4
- package/design-system/components/Meter/preview.html +18 -1
- package/design-system/components/Meter/style.css +23 -0
- package/design-system/components/MetricTile/README.md +237 -0
- package/design-system/components/MetricTile/preview.html +241 -0
- package/design-system/components/MetricTile/style.css +129 -0
- package/design-system/components/Morph/README.md +106 -0
- package/design-system/components/Morph/preview.html +103 -0
- package/design-system/components/Morph/style.css +31 -0
- package/design-system/components/Motion/README.md +164 -0
- package/design-system/components/Motion/preview.html +2537 -0
- package/design-system/components/NumberInput/README.md +27 -8
- package/design-system/components/NumberInput/preview.html +21 -5
- package/design-system/components/NumberInput/style.css +34 -0
- package/design-system/components/PaceBar/README.md +75 -0
- package/design-system/components/PaceBar/preview.html +67 -0
- package/design-system/components/PaceBar/style.css +25 -0
- package/design-system/components/Page/README.md +57 -18
- package/design-system/components/Page/preview.html +15 -17
- package/design-system/components/Page/style.css +7 -0
- package/design-system/components/PageBar/README.md +90 -34
- package/design-system/components/PageBar/preview.html +60 -19
- package/design-system/components/PageBar/style.css +35 -0
- package/design-system/components/PageHero/README.md +87 -51
- package/design-system/components/PageHero/preview.html +35 -6
- package/design-system/components/PageHero/style.css +31 -0
- package/design-system/components/Pagination/README.md +70 -49
- package/design-system/components/Pagination/preview.html +24 -15
- package/design-system/components/Pagination/style.css +12 -0
- package/design-system/components/Panel/README.md +109 -51
- package/design-system/components/Panel/preview.html +118 -20
- package/design-system/components/Panel/style.css +51 -0
- package/design-system/components/PasswordInput/README.md +50 -18
- package/design-system/components/PasswordInput/preview.html +71 -21
- package/design-system/components/PasswordInput/style.css +31 -0
- package/design-system/components/Plate/README.md +75 -17
- package/design-system/components/Plate/preview.html +40 -7
- package/design-system/components/Plate/style.css +37 -0
- package/design-system/components/Popover/README.md +70 -49
- package/design-system/components/Popover/preview.html +44 -22
- package/design-system/components/Popover/style.css +41 -0
- package/design-system/components/PricingTable/README.md +69 -49
- package/design-system/components/PricingTable/preview.html +21 -21
- package/design-system/components/PricingTable/style.css +21 -0
- package/design-system/components/ProgressPetals/README.md +31 -3
- package/design-system/components/ProgressPetals/preview.html +14 -15
- package/design-system/components/ProgressPetals/style.css +27 -0
- package/design-system/components/README.md +151 -0
- package/design-system/components/Radio/README.md +40 -17
- package/design-system/components/Radio/preview.html +16 -1
- package/design-system/components/Radio/style.css +21 -0
- package/design-system/components/RankBar/README.md +29 -2
- package/design-system/components/RankBar/preview.html +14 -12
- package/design-system/components/RankBar/style.css +18 -0
- package/design-system/components/Ring/README.md +61 -11
- package/design-system/components/Ring/preview.html +55 -10
- package/design-system/components/Ring/style.css +49 -0
- package/design-system/components/ScoreHero/README.md +91 -0
- package/design-system/components/ScoreHero/preview.html +104 -0
- package/design-system/components/ScoreHero/style.css +32 -0
- package/design-system/components/Section/README.md +72 -33
- package/design-system/components/Section/preview.html +46 -16
- package/design-system/components/Section/style.css +18 -0
- package/design-system/components/Segmented/README.md +100 -55
- package/design-system/components/Segmented/preview.html +107 -26
- package/design-system/components/Segmented/style.css +94 -0
- package/design-system/components/SegmentedProgress/README.md +64 -0
- package/design-system/components/SegmentedProgress/preview.html +69 -0
- package/design-system/components/SegmentedProgress/style.css +11 -0
- package/design-system/components/Select/README.md +47 -12
- package/design-system/components/Select/preview.html +28 -2
- package/design-system/components/Select/style.css +22 -0
- package/design-system/components/ShareBar/README.md +69 -0
- package/design-system/components/ShareBar/preview.html +72 -0
- package/design-system/components/ShareBar/style.css +25 -0
- package/design-system/components/SideList/README.md +147 -0
- package/design-system/components/SideList/preview.html +139 -0
- package/design-system/components/SideList/style.css +94 -0
- package/design-system/components/Skeleton/README.md +53 -16
- package/design-system/components/Skeleton/preview.html +35 -23
- package/design-system/components/Skeleton/style.css +17 -0
- package/design-system/components/Slider/README.md +95 -0
- package/design-system/components/Slider/preview.html +49 -0
- package/design-system/components/Slider/style.css +13 -0
- package/design-system/components/Split/README.md +112 -0
- package/design-system/components/Split/preview.html +105 -0
- package/design-system/components/Split/style.css +30 -0
- package/design-system/components/Starter/README.md +21 -9
- package/design-system/components/Starter/preview.html +5 -5
- package/design-system/components/Stat/README.md +64 -43
- package/design-system/components/Stat/preview.html +3 -3
- package/design-system/components/Stat/style.css +15 -0
- package/design-system/components/StatTiles/README.md +88 -44
- package/design-system/components/StatTiles/preview.html +142 -71
- package/design-system/components/StatTiles/style.css +64 -0
- package/design-system/components/StatusLine/README.md +85 -0
- package/design-system/components/StatusLine/preview.html +49 -0
- package/design-system/components/StatusLine/style.css +14 -0
- package/design-system/components/StatusScreen/README.md +49 -35
- package/design-system/components/StatusScreen/preview.html +20 -5
- package/design-system/components/StatusScreen/style.css +9 -0
- package/design-system/components/StepLine/README.md +97 -0
- package/design-system/components/StepLine/preview.html +108 -0
- package/design-system/components/StepLine/style.css +62 -0
- package/design-system/components/Stepper/README.md +35 -13
- package/design-system/components/Stepper/style.css +13 -0
- package/design-system/components/StreakCalendar/README.md +22 -1
- package/design-system/components/StreakCalendar/preview.html +10 -10
- package/design-system/components/StreakCalendar/style.css +12 -0
- package/design-system/components/SuggestionChip/README.md +87 -0
- package/design-system/components/SuggestionChip/preview.html +42 -0
- package/design-system/components/SuggestionChip/style.css +20 -0
- package/design-system/components/Switch/README.md +44 -24
- package/design-system/components/Switch/preview.html +23 -8
- package/design-system/components/Switch/style.css +31 -0
- package/design-system/components/Table/README.md +129 -58
- package/design-system/components/Table/preview.html +106 -72
- package/design-system/components/Table/style.css +104 -0
- package/design-system/components/Tabs/README.md +71 -46
- package/design-system/components/Tabs/preview.html +56 -24
- package/design-system/components/Tabs/style.css +44 -0
- package/design-system/components/Testimonial/README.md +48 -32
- package/design-system/components/Testimonial/preview.html +14 -14
- package/design-system/components/Testimonial/style.css +12 -0
- package/design-system/components/TextArea/README.md +27 -11
- package/design-system/components/TextArea/preview.html +8 -2
- package/design-system/components/TextArea/style.css +12 -0
- package/design-system/components/ThemeSwitch/README.md +116 -0
- package/design-system/components/ThemeSwitch/preview.html +57 -0
- package/design-system/components/ThemeSwitch/style.css +6 -0
- package/design-system/components/TickRow/README.md +52 -36
- package/design-system/components/TickRow/preview.html +64 -41
- package/design-system/components/TickRow/style.css +23 -0
- package/design-system/components/TickStrip/README.md +95 -0
- package/design-system/components/TickStrip/preview.html +88 -0
- package/design-system/components/TickStrip/style.css +42 -0
- package/design-system/components/Tile/README.md +79 -18
- package/design-system/components/Tile/preview.html +91 -40
- package/design-system/components/Tile/style.css +36 -0
- package/design-system/components/Timeline/README.md +68 -48
- package/design-system/components/Timeline/preview.html +27 -15
- package/design-system/components/Timeline/style.css +25 -0
- package/design-system/components/Toast/README.md +70 -38
- package/design-system/components/Toast/preview.html +43 -8
- package/design-system/components/Toast/style.css +25 -0
- package/design-system/components/Tooltip/README.md +93 -35
- package/design-system/components/Tooltip/preview.html +69 -15
- package/design-system/components/Tooltip/style.css +78 -0
- package/design-system/components/TopBar/README.md +67 -53
- package/design-system/components/TopBar/preview.html +14 -27
- package/design-system/components/TopBar/style.css +35 -0
- package/design-system/components/TopicRail/README.md +108 -0
- package/design-system/components/TopicRail/preview.html +58 -0
- package/design-system/components/TopicRail/style.css +48 -0
- package/design-system/components/TrendBars/README.md +52 -14
- package/design-system/components/TrendBars/preview.html +65 -32
- package/design-system/components/TrendBars/style.css +25 -0
- package/design-system/components/TrendLine/README.md +164 -0
- package/design-system/components/TrendLine/preview.html +373 -0
- package/design-system/components/TrendLine/style.css +155 -0
- package/design-system/components/Well/README.md +64 -22
- package/design-system/components/Well/preview.html +14 -14
- package/design-system/components/Well/style.css +22 -0
- package/design-system/components/_house.css +324 -0
- package/design-system/components/bundle.css +4086 -744
- package/design-system/tokens.json +1310 -124
- package/dist/fello-core.css +2 -2
- package/dist/fello.css +6 -1369
- package/dist/fello.scoped.css +7 -0
- package/dist/index.d.ts +109 -10
- package/dist/index.js +781 -96
- package/dist/palettes.d.ts +464 -0
- package/dist/palettes.js +497 -0
- package/dist/scoped.d.ts +3 -0
- package/dist/scoped.js +16 -0
- package/dist/toast.d.ts +14 -0
- package/dist/toast.js +33 -29
- package/dist/tokens.d.ts +1686 -62
- package/dist/tokens.js +1668 -61
- package/package.json +20 -4
- package/scripts/check-palette.mjs +295 -0
- package/scripts/token-model.mjs +552 -0
- package/tokens/_dark.css +173 -0
- package/tokens/_palettes.css +46 -0
- package/tokens/_product.css +266 -53
- package/tokens/_source.hubl.css +39 -19
- package/tokens/design-tokens.json +319 -0
- package/tokens/palettes.ts +504 -0
- package/tokens/shadcn-compat.css +19 -19
- package/tokens/shadcn-compat.hsl.css +76 -0
- package/tokens/tokens.css +1287 -62
- package/tokens/tokens.md +587 -61
- package/tokens/tokens.root.css +1293 -62
- package/tokens/tokens.ts +1677 -64
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
<!-- @dsCard group="Data" height=1080 -->
|
|
2
|
+
<!doctype html>
|
|
3
|
+
<html>
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>SideList</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
|
+
|
|
13
|
+
<div class="ws-stack" style="width: 340px;">
|
|
14
|
+
<div class="ws-cluster"><span class="ws-muted">Goal rows (North's goals beside the key metrics): navy on track, teal past the goal, alert red behind, a cut at the pace mark; with --draw the bars fill in order on arrival</span><button type="button" class="ws-btn ws-btn--secondary ws-btn--sm" data-replay="sl-build" aria-label="Replay the fill">Replay</button></div>
|
|
15
|
+
<div class="ws-build" id="sl-build">
|
|
16
|
+
<div class="ws-build__card">
|
|
17
|
+
<div class="ws-side-list ws-side-list--draw">
|
|
18
|
+
<section class="ws-side-list__group" aria-labelledby="sl-goals" style="--n: 4;">
|
|
19
|
+
<div class="ws-side-list__head">
|
|
20
|
+
<h3 class="ws-side-list__title" id="sl-goals">Q4 goals</h3>
|
|
21
|
+
<button type="button" class="ws-act">Edit</button>
|
|
22
|
+
</div>
|
|
23
|
+
<ul>
|
|
24
|
+
<li><a class="ws-side-list__row ws-side-list__row--measure" href="#goal-1" style="--i: 0;"><span class="ws-side-list__line"><span class="ws-side-list__name">Close $40M ending revenue</span><span class="ws-side-list__value">27%</span></span><span class="ws-side-list__bar" aria-hidden="true"><span style="width: 27%;"></span><i style="--at: 30%;"></i></span></a></li>
|
|
25
|
+
<li><a class="ws-side-list__row ws-side-list__row--measure" href="#goal-2" style="--i: 1;"><span class="ws-side-list__line"><span class="ws-side-list__name">Live for every team</span><span class="ws-side-list__value">60%</span></span><span class="ws-side-list__bar" aria-hidden="true"><span style="width: 60%;"></span><i style="--at: 30%;"></i></span></a></li>
|
|
26
|
+
<li><a class="ws-side-list__row ws-side-list__row--measure ws-side-list__row--over" href="#goal-3" style="--i: 2;"><span class="ws-side-list__line"><span class="ws-side-list__name">Book 40 expansion deals</span><span class="ws-side-list__value">112%</span></span><span class="ws-side-list__bar" aria-hidden="true"><span style="width: 100%;"></span><i style="--at: 30%;"></i></span></a></li>
|
|
27
|
+
<li><a class="ws-side-list__row ws-side-list__row--measure ws-side-list__row--behind" href="#goal-4" style="--i: 3;"><span class="ws-side-list__line"><span class="ws-side-list__name">Time to value under 15 days</span><span class="ws-side-list__value">9%</span></span><span class="ws-side-list__bar" aria-hidden="true"><span style="width: 9%;"></span><i style="--at: 30%;"></i></span></a></li>
|
|
28
|
+
</ul>
|
|
29
|
+
</section>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div class="ws-stack" style="width: 300px;">
|
|
36
|
+
<span class="ws-muted">A long goal wraps, its figure stays whole; a goal with nothing done yet is the empty track and 0%</span>
|
|
37
|
+
<div class="ws-side-list">
|
|
38
|
+
<section class="ws-side-list__group" aria-labelledby="sl-goals-edge">
|
|
39
|
+
<div class="ws-side-list__head"><h3 class="ws-side-list__title" id="sl-goals-edge">Team goals</h3></div>
|
|
40
|
+
<ul>
|
|
41
|
+
<li><a class="ws-side-list__row ws-side-list__row--measure" href="#goal-long"><span class="ws-side-list__line"><span class="ws-side-list__name">Every new agent books a first appointment inside their first fourteen days</span><span class="ws-side-list__value">48%</span></span><span class="ws-side-list__bar" aria-hidden="true"><span style="width: 48%;"></span><i style="--at: 30%;"></i></span></a></li>
|
|
42
|
+
<li><a class="ws-side-list__row ws-side-list__row--measure ws-side-list__row--behind" href="#goal-zero"><span class="ws-side-list__line"><span class="ws-side-list__name">Launch the referral program</span><span class="ws-side-list__value">0%</span></span><span class="ws-side-list__bar" aria-hidden="true"><i style="--at: 30%;"></i></span></a></li>
|
|
43
|
+
</ul>
|
|
44
|
+
</section>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<div class="ws-stack" style="width: 340px;">
|
|
49
|
+
<span class="ws-muted">Grouped, no card (Seth's Tally side column): rows that act with an arrow, value rows, a row with a measure</span>
|
|
50
|
+
<div class="ws-side-list">
|
|
51
|
+
<section class="ws-side-list__group" aria-labelledby="sl-input">
|
|
52
|
+
<div class="ws-side-list__head">
|
|
53
|
+
<h3 class="ws-side-list__title" id="sl-input">Needs your input</h3>
|
|
54
|
+
<span class="ws-side-list__count">2</span>
|
|
55
|
+
</div>
|
|
56
|
+
<ul>
|
|
57
|
+
<li><a class="ws-side-list__row" href="#team-size"><span class="ws-side-list__name">Add your team size</span><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round" aria-hidden="true"><path d="M4 10h12M11 5l5 5-5 5"/></svg></a></li>
|
|
58
|
+
<li><a class="ws-side-list__row" href="#sides"><span class="ws-side-list__name">Add closed sides and GCI for the last twelve months</span><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round" aria-hidden="true"><path d="M4 10h12M11 5l5 5-5 5"/></svg></a></li>
|
|
59
|
+
</ul>
|
|
60
|
+
</section>
|
|
61
|
+
<section class="ws-side-list__group" aria-labelledby="sl-seats">
|
|
62
|
+
<div class="ws-side-list__head">
|
|
63
|
+
<h3 class="ws-side-list__title" id="sl-seats">Seats Felix absorbs</h3>
|
|
64
|
+
<button type="button" class="ws-act">Edit</button>
|
|
65
|
+
</div>
|
|
66
|
+
<ul>
|
|
67
|
+
<li class="ws-side-list__row ws-side-list__row--measure">
|
|
68
|
+
<span class="ws-side-list__line"><span class="ws-side-list__name">ISAs</span><span class="ws-side-list__value">50%</span></span>
|
|
69
|
+
<span class="ws-side-list__bar" aria-hidden="true"><span style="width: 50%;"></span></span>
|
|
70
|
+
<span class="ws-side-list__caption">4, typical for your team</span>
|
|
71
|
+
</li>
|
|
72
|
+
<li class="ws-side-list__row"><span class="ws-side-list__name">Marketing managers</span><span class="ws-side-list__value ws-side-list__value--quiet">none, typical</span></li>
|
|
73
|
+
<li class="ws-side-list__row"><span class="ws-side-list__name">Database managers</span><span class="ws-side-list__value ws-side-list__value--quiet">none, typical</span></li>
|
|
74
|
+
<li class="ws-side-list__row"><span class="ws-side-list__name">Transaction coordinators</span><span class="ws-side-list__value ws-side-list__value--quiet">stays</span></li>
|
|
75
|
+
</ul>
|
|
76
|
+
</section>
|
|
77
|
+
<section class="ws-side-list__group" aria-labelledby="sl-done">
|
|
78
|
+
<div class="ws-side-list__head">
|
|
79
|
+
<h3 class="ws-side-list__title" id="sl-done">Waiting on others</h3>
|
|
80
|
+
<span class="ws-side-list__count">0</span>
|
|
81
|
+
</div>
|
|
82
|
+
<ul>
|
|
83
|
+
<li class="ws-side-list__row"><span class="ws-side-list__name ws-side-list__value--quiet">Nothing is waiting on anyone</span></li>
|
|
84
|
+
</ul>
|
|
85
|
+
</section>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<div class="ws-stack" style="width: 362px;">
|
|
90
|
+
<span class="ws-muted">__picks on a card's surface (North's board list, Tally's vendors): one row current, the lines beside it hidden, figures right-aligned as one block. Click a row: the fill slides to it on North's list highlight spring</span>
|
|
91
|
+
<section class="ws-card" aria-label="Tools">
|
|
92
|
+
<ul class="ws-side-list__picks">
|
|
93
|
+
<li><button type="button" class="ws-side-list__pick" style="--ws-dot: var(--ws-edge-card);">
|
|
94
|
+
<span class="ws-side-list__dot" aria-hidden="true"></span>
|
|
95
|
+
<span class="ws-side-list__main"><span class="ws-side-list__pick-name">Meta Ads</span><span class="ws-side-list__sub">Paid ads: media, stays</span></span>
|
|
96
|
+
<span class="ws-side-list__end"><span class="ws-side-list__figure">$24,000</span><span class="ws-side-list__sub">stays</span></span>
|
|
97
|
+
</button></li>
|
|
98
|
+
<li><button type="button" class="ws-side-list__pick" style="--ws-dot: var(--ws-edge-card);">
|
|
99
|
+
<span class="ws-side-list__dot" aria-hidden="true"></span>
|
|
100
|
+
<span class="ws-side-list__main"><span class="ws-side-list__pick-name" title="Zillow Premier Agent and Flex referrals">Zillow Premier Agent and Flex referrals</span><span class="ws-side-list__sub">Paid ads: media, stays</span></span>
|
|
101
|
+
<span class="ws-side-list__end"><span class="ws-side-list__figure">$24,000</span><span class="ws-side-list__sub">stays</span></span>
|
|
102
|
+
</button></li>
|
|
103
|
+
<li><button type="button" class="ws-side-list__pick" aria-current="true" style="--ws-dot: var(--ws-chart-past-half);">
|
|
104
|
+
<span class="ws-side-list__dot" aria-hidden="true"></span>
|
|
105
|
+
<span class="ws-side-list__main"><span class="ws-side-list__pick-name">Luxury Presence</span><span class="ws-side-list__sub">Website and IDX, Q1 2027</span></span>
|
|
106
|
+
<span class="ws-side-list__end"><span class="ws-side-list__figure">$20,400</span><span class="ws-side-list__sub ws-side-list__sub--needs">saves $20,400</span></span>
|
|
107
|
+
</button></li>
|
|
108
|
+
<li><button type="button" class="ws-side-list__pick" style="--ws-dot: var(--ws-chart-finished);">
|
|
109
|
+
<span class="ws-side-list__dot" aria-hidden="true"></span>
|
|
110
|
+
<span class="ws-side-list__main"><span class="ws-side-list__pick-name">Follow Up Boss</span><span class="ws-side-list__sub">CRM, Q1 2027</span></span>
|
|
111
|
+
<span class="ws-side-list__end"><span class="ws-side-list__figure">$7,452</span><span class="ws-side-list__sub ws-side-list__sub--needs">saves $7,452</span></span>
|
|
112
|
+
</button></li>
|
|
113
|
+
<li><button type="button" class="ws-side-list__pick" style="--ws-dot: var(--ws-chart-under-half);">
|
|
114
|
+
<span class="ws-side-list__dot" aria-hidden="true"></span>
|
|
115
|
+
<span class="ws-side-list__main"><span class="ws-side-list__pick-name">Mailchimp</span><span class="ws-side-list__sub">Email and marketing, today</span></span>
|
|
116
|
+
<span class="ws-side-list__end"><span class="ws-side-list__figure">$1,620</span><span class="ws-side-list__sub ws-side-list__sub--needs">saves $1,620</span></span>
|
|
117
|
+
</button></li>
|
|
118
|
+
</ul>
|
|
119
|
+
</section>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
</div>
|
|
123
|
+
<script>
|
|
124
|
+
/* Replay: a fresh copy of the build runs its build-in again (the app never needs this; a page builds in once). */
|
|
125
|
+
for (const b of document.querySelectorAll('[data-replay]')) b.addEventListener('click', () => {
|
|
126
|
+
const el = document.getElementById(b.dataset.replay);
|
|
127
|
+
el.replaceWith(el.cloneNode(true));
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
/* The demo's wiring: a click picks the row (an app keeps the pick; the fill slides on its own). */
|
|
132
|
+
document.addEventListener('click', (e) => {
|
|
133
|
+
const pick = e.target.closest('.ws-side-list__pick');
|
|
134
|
+
if (!pick) return;
|
|
135
|
+
for (const p of pick.closest('.ws-side-list__picks').querySelectorAll('.ws-side-list__pick')) p === pick ? p.setAttribute('aria-current', 'true') : p.removeAttribute('aria-current');
|
|
136
|
+
});
|
|
137
|
+
</script>
|
|
138
|
+
</body>
|
|
139
|
+
</html>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/* ---- SideList: short lists with no card of their own (Seth's Tally side column): groups 40 apart, a small head, rows
|
|
2
|
+
joined by 0.5 px lines, an act or a value at the right. __picks is the picker form that sits on a card's surface
|
|
3
|
+
(North's board list, Tally's vendors): rows as 6 px pills inside a 4 px padded surface, one row current, the lines
|
|
4
|
+
beside the current row hidden. ---- */
|
|
5
|
+
.ws-side-list { display: flex; flex-direction: column; gap: var(--space-2xl); min-width: 0; }
|
|
6
|
+
.ws-side-list__group { display: flex; flex-direction: column; min-width: 0; }
|
|
7
|
+
/* Head: 16 / 20 semibold navy, a count or a word act at the right, 14 in from the sides like the rows' words. */
|
|
8
|
+
.ws-side-list__head { display: flex; align-items: baseline; gap: var(--space-xs); padding: 0 var(--space-sm-plus) var(--space-xs); }
|
|
9
|
+
.ws-side-list__title { flex: 1; min-width: 0; font-size: var(--ws-text-value); line-height: calc(var(--space-md) + var(--space-xxs)); font-weight: 600; color: var(--color-text-heading); }
|
|
10
|
+
.ws-side-list__count { font-size: var(--ws-text-dense); line-height: var(--space-md); font-weight: 600; color: var(--color-text-heading); font-variant-numeric: tabular-nums; }
|
|
11
|
+
.ws-side-list__head .ws-act { margin-inline: calc(var(--space-3xs) * -1); padding-inline: var(--space-3xs); font-size: var(--ws-text-dense); line-height: var(--space-md); }
|
|
12
|
+
/* A row: 40 at least, 10 above and below, 14 at the sides, a 0.5 px line on top (the first one under the head too). */
|
|
13
|
+
.ws-side-list__row { position: relative; isolation: isolate; display: flex; align-items: center; gap: var(--space-xs-plus); width: 100%; min-height: var(--ws-row-h-dense); padding: var(--space-xs-plus) var(--space-sm-plus); border: 0; border-top: var(--ws-divider); background: none; font-size: var(--ws-text-control); line-height: var(--ws-leading-control); font-weight: 500; text-align: left; text-decoration: none; color: var(--color-text-heading); }
|
|
14
|
+
.ws-side-list__row > svg { width: var(--ws-icon-lg); height: var(--ws-icon-lg); flex-shrink: 0; }
|
|
15
|
+
.ws-side-list__name { flex: 1; min-width: 0; }
|
|
16
|
+
.ws-side-list__value { flex: none; font-size: var(--ws-text-dense); line-height: var(--space-md); font-weight: 600; color: var(--color-text-heading); font-variant-numeric: tabular-nums; }
|
|
17
|
+
.ws-side-list__value--quiet { font-weight: 500; color: var(--color-text-muted); }
|
|
18
|
+
/* A row that acts: North's inset pill, 6 px corners, 2 and 4 in from the row so the line above stays whole; the words sit
|
|
19
|
+
over it. Focus draws the ring inside the row. */
|
|
20
|
+
a.ws-side-list__row, button.ws-side-list__row { cursor: pointer; }
|
|
21
|
+
a.ws-side-list__row::after, button.ws-side-list__row::after { content: ""; position: absolute; z-index: -1; inset: var(--space-3xs) var(--space-xxs); border-radius: var(--ws-radius-row); background: var(--ws-hover); opacity: 0; transition: opacity var(--ws-duration-hover) var(--ws-ease-soft); pointer-events: none; }
|
|
22
|
+
@media (hover: hover) { a.ws-side-list__row:hover::after, button.ws-side-list__row:hover::after { opacity: 1; } }
|
|
23
|
+
a.ws-side-list__row:active::after, button.ws-side-list__row:active::after { opacity: 1; background: var(--ws-hover-strong); }
|
|
24
|
+
/* Focus: the pill shows with the 2 px ring on it, 6 px corners like a pick's, never a square box round the row. */
|
|
25
|
+
a.ws-side-list__row:focus-visible, button.ws-side-list__row:focus-visible { outline: none; }
|
|
26
|
+
a.ws-side-list__row:focus-visible::after, button.ws-side-list__row:focus-visible::after { opacity: 1; outline: var(--ws-focus-width) solid var(--ws-focus-color); outline-offset: calc(var(--ws-focus-width) * -1); }
|
|
27
|
+
/* A row with a measure (Seth's seat rows): the name and value line, a 4 px bar, an 11 / 13 caption. */
|
|
28
|
+
.ws-side-list__row--measure { flex-direction: column; align-items: stretch; gap: var(--space-xxs); padding-block: var(--space-xs); }
|
|
29
|
+
.ws-side-list__line { display: flex; align-items: baseline; gap: var(--space-xs); }
|
|
30
|
+
.ws-side-list__bar { position: relative; height: var(--space-xxs); border-radius: var(--ws-radius-chip); background: var(--ws-track); overflow: hidden; }
|
|
31
|
+
.ws-side-list__bar > span { position: absolute; inset: 0 auto 0 0; border-radius: inherit; background: var(--tone, var(--color-text-heading)); transform-origin: left; }
|
|
32
|
+
.ws-side-list__caption { font-size: var(--ws-text-micro); line-height: var(--ws-leading-micro); font-weight: 400; color: var(--color-text-muted); }
|
|
33
|
+
/* A goal row (North's goals beside the key metrics): the measure row's tone says where it stands. Navy on track; past
|
|
34
|
+
its goal (--over) the bar teal and the figure in teal's AA word; behind (--behind) the bar alert red and the figure
|
|
35
|
+
in its word. A target or pace mark (__bar > i, style="--at: 30%") is a 1.5 px cut in the ground's colour, so the
|
|
36
|
+
bar reads in two segments once the fill passes it. */
|
|
37
|
+
.ws-side-list__row--over { --tone: var(--ws-chart-finished); --tone-word: var(--ws-word-positive); }
|
|
38
|
+
.ws-side-list__row--behind { --tone: var(--ws-chart-alert); --tone-word: var(--ws-word-alert); }
|
|
39
|
+
.ws-side-list__row--measure .ws-side-list__value { color: var(--tone-word, var(--color-text-heading)); }
|
|
40
|
+
.ws-side-list__bar > i { position: absolute; z-index: 1; top: 0; bottom: 0; left: var(--at); width: calc(var(--ws-hairline) * 3); margin-left: calc(var(--ws-hairline) * -1.5); background: var(--color-bg-page); }
|
|
41
|
+
/* The fill on arrival (North's Home intro, "Metric + goal bars fill"): with --draw on the list, the bars fill in order
|
|
42
|
+
inside the card's share of the page fill (--ws-duration-fill-page x 0.79), from 10% to 80% of it:
|
|
43
|
+
row i of --n (on the group) starting at its share of the first 55% of that window and filling over the rest on the
|
|
44
|
+
settle curve. In a .ws-build card it starts at the card's --ws-build-at. Reduced motion: filled. */
|
|
45
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
46
|
+
.ws-side-list--draw { --ws-list-fill: calc(var(--ws-duration-fill-page) * 0.79 * 0.7); }
|
|
47
|
+
.ws-side-list--draw .ws-side-list__bar > span { animation: ws-grow calc(var(--ws-list-fill) * 0.45) var(--ws-ease-settle) backwards; animation-delay: calc(var(--ws-build-at, 0s) + var(--ws-duration-fill-page) * 0.079 + var(--ws-list-fill) * 0.55 * var(--i, 0) / max(var(--n, 2) - 1, 1)); }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* __picks: the picker on a card's surface. */
|
|
51
|
+
.ws-side-list__picks { display: flex; flex-direction: column; padding: var(--space-xxs); }
|
|
52
|
+
.ws-side-list__picks > li { position: relative; }
|
|
53
|
+
/* The line between rows runs the surface's full width (past its 4 px padding) and hides beside the current row. */
|
|
54
|
+
.ws-side-list__picks > li + li::before { content: ""; position: absolute; top: 0; left: calc(var(--space-xxs) * -1); right: calc(var(--space-xxs) * -1); border-top: var(--ws-divider); }
|
|
55
|
+
.ws-side-list__picks > li:has(> [aria-current="true"])::before, .ws-side-list__picks > li:has(> [aria-current="true"]) + li::before { opacity: 0; }
|
|
56
|
+
.ws-side-list__pick { display: flex; align-items: center; gap: var(--space-xs-plus); width: 100%; min-height: calc(var(--space-3xl) + var(--space-xs)); padding: var(--space-xs) var(--space-sm); border: 0; border-radius: var(--ws-radius-row); background: transparent; text-align: left; color: var(--color-text-heading); cursor: pointer; }
|
|
57
|
+
.ws-side-list__pick:focus-visible { outline-offset: calc(var(--ws-focus-width) * -1); }
|
|
58
|
+
@media (hover: hover) { .ws-side-list__pick:not([aria-current="true"]):hover { background: var(--ws-hover-faint); } }
|
|
59
|
+
/* The current row: the rim's grey as a pill, its name semibold. The words never change size, so nothing moves. */
|
|
60
|
+
.ws-side-list__pick[aria-current="true"] { background: var(--ws-tray); }
|
|
61
|
+
.ws-side-list__dot { flex-shrink: 0; width: var(--space-xxs-plus); height: var(--space-xxs-plus); border-radius: var(--radius-full); background: var(--ws-dot, var(--ws-edge-card)); }
|
|
62
|
+
.ws-side-list__main, .ws-side-list__end { display: flex; flex-direction: column; gap: var(--ws-line); min-width: 0; }
|
|
63
|
+
.ws-side-list__main { flex: 1; }
|
|
64
|
+
.ws-side-list__end { flex: none; align-items: flex-end; text-align: right; }
|
|
65
|
+
.ws-side-list__pick-name, .ws-side-list__figure { font-size: var(--ws-text-control); line-height: var(--space-md); color: var(--color-text-heading); }
|
|
66
|
+
.ws-side-list__pick-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }
|
|
67
|
+
.ws-side-list__pick[aria-current="true"] .ws-side-list__pick-name { font-weight: 600; }
|
|
68
|
+
.ws-side-list__figure { font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
69
|
+
.ws-side-list__sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--ws-text-micro); line-height: var(--ws-leading-micro); font-weight: 400; color: var(--color-text-muted); }
|
|
70
|
+
.ws-side-list__end .ws-side-list__sub { font-weight: 500; }
|
|
71
|
+
.ws-side-list__sub--needs { color: var(--ws-word-needs); }
|
|
72
|
+
|
|
73
|
+
/* ---- Motion: the current pick's fill slides to the new pick (North "List highlight slide", select.glide,
|
|
74
|
+
springs.highlight .45 / .14, the board list's layoutId "board-sel"; north-motion 3) instead of jumping. The current
|
|
75
|
+
pick is the anchor (CSS anchor positioning) and the list's ::before is a travelling fill, under the rows (each li sits
|
|
76
|
+
above it), its four edges easing on motion's own spring(.45, .14) written out as linear() (800 ms, a 0.5% give). At
|
|
77
|
+
rest the current pick paints its own fill, so a resting list is the 0.4 list pixel for pixel; while the list is
|
|
78
|
+
pointed at or holds focus the travelling fill takes its place (the same box, the same paint, at once), so a pick made
|
|
79
|
+
then slides; the lines beside the old and the new pick fade over 200 ms. Only a real pick moves it. No new markup.
|
|
80
|
+
Without anchor positioning, or under reduced motion, the fill moves at once. The spring is the global --ws-spring-highlight over --ws-spring-highlight-duration. ---- */
|
|
81
|
+
@supports (anchor-name: --a) {
|
|
82
|
+
.ws-side-list__picks { position: relative; anchor-scope: --ws-side-list-current; }
|
|
83
|
+
.ws-side-list__picks::before { content: ""; position: absolute; position-anchor: --ws-side-list-current; inset: anchor(top) anchor(right) anchor(bottom) anchor(left); border-radius: var(--ws-radius-row); background: var(--ws-tray); opacity: 0; pointer-events: none; }
|
|
84
|
+
.ws-side-list__pick[aria-current="true"] { anchor-name: --ws-side-list-current; }
|
|
85
|
+
}
|
|
86
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
87
|
+
.ws-side-list__picks > li + li::before { transition: opacity var(--ws-duration-hover) var(--ws-ease-soft); }
|
|
88
|
+
.ws-side-list__pick { transition: background-color var(--ws-duration-hover) var(--ws-ease-soft); }
|
|
89
|
+
@supports (anchor-name: --a) {
|
|
90
|
+
.ws-side-list__picks:is(:hover, :focus-within)::before { opacity: 1; transition: inset var(--ws-spring-highlight-duration) var(--ws-spring-highlight); }
|
|
91
|
+
.ws-side-list__picks:is(:hover, :focus-within) .ws-side-list__pick[aria-current="true"] { background: transparent; }
|
|
92
|
+
.ws-side-list__pick[aria-current="true"] { transition: none; }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
A
|
|
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
|
+
nothing jumps when the real content lands.
|
|
2
3
|
|
|
3
4
|
## Use it when
|
|
4
5
|
|
|
@@ -14,30 +15,42 @@ A placeholder shape that breathes gently in place of content still loading, so n
|
|
|
14
15
|
|
|
15
16
|
## Anatomy
|
|
16
17
|
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
- A ghost block (`ws-skeleton`): 4 px corners (`--ws-radius-control`), the shimmer (`--ws-shimmer`: the ghost grey
|
|
19
|
+
#E3DFDB with a lighter pass of the same grey, #F6F3F0, at 300 %; no chart hues), sized where used. Steps: `--line` 12 px
|
|
20
|
+
tall, `--title` 28 px (a title's line), `--button` 120 x 36 with 6 px corners (North's button place, on the grid).
|
|
21
|
+
- Lines: a column 8 px apart (`ws-stack`), full width except the last, two thirds.
|
|
22
|
+
- 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. The ghost grey shows on the tray too (1.13:1, the
|
|
24
|
+
cream 1.29:1), so a ghost in a foot or a band is the same ghost.
|
|
25
|
+
- A chart ghost (`ws-skeleton__chart`): 160 px tall, the bars 4 px apart, each a ghost under the same shimmer as every
|
|
26
|
+
other ghost. North's colour band over the drawing is not taken (0.5.1): loaders are one neutral tone.
|
|
20
27
|
|
|
21
28
|
## Variants and sizes
|
|
22
29
|
|
|
23
30
|
| Shape | Use |
|
|
24
31
|
| --- | --- |
|
|
25
|
-
|
|
|
26
|
-
| A
|
|
27
|
-
|
|
|
32
|
+
| Lines | A short paragraph or a few text rows still loading |
|
|
33
|
+
| A card or tile skeleton | A chart card or tile still loading, keeping the page's layout steady |
|
|
34
|
+
| A chart ghost | The drawing inside a chart card that is still being built |
|
|
35
|
+
| A button place | The band's act before the card knows it |
|
|
28
36
|
|
|
29
37
|
## States
|
|
30
38
|
|
|
31
|
-
- **Loading** (the only state):
|
|
32
|
-
-
|
|
33
|
-
- **
|
|
39
|
+
- **Loading** (the only state): the shimmer passes over every ghost every 1.8 s (`--ws-loop-shimmer` on
|
|
40
|
+
`--ws-ease-shimmer`), the chart's bars included.
|
|
41
|
+
- **Loaded**: the skeleton is removed and the real content takes its place; nothing jumps, since the ghosts use the
|
|
42
|
+
content's own sizes.
|
|
43
|
+
- **Reduced motion**: nothing travels. The ghosts are the still ghost grey (`--ws-ghost`, the shimmer's own ground),
|
|
44
|
+
never a frozen frame of the sweep; still plainly a placeholder.
|
|
45
|
+
- **Dark and palettes**: the ghost and its pass are theme tokens (the night's ghost #273544 with a pass of 7 % ink), so
|
|
46
|
+
the shimmer is one neutral tone in every theme and palette.
|
|
34
47
|
|
|
35
48
|
## Behaviour
|
|
36
49
|
|
|
37
|
-
- Keyboard: a skeleton holds
|
|
50
|
+
- Keyboard: a skeleton holds nothing focusable. Its ghosts are `aria-hidden`; the region they sit in carries
|
|
51
|
+
`aria-busy="true"` and one screen-reader line ("Loading the chart", `ws-sr`), said once, not per ghost.
|
|
38
52
|
- Pointer and touch: nothing to interact with.
|
|
39
|
-
- Motion: the
|
|
40
|
-
- Reduced motion: bars render statically, no pulse.
|
|
53
|
+
- Motion: the shimmer only; nothing moves or resizes.
|
|
41
54
|
|
|
42
55
|
## Content
|
|
43
56
|
|
|
@@ -58,9 +71,33 @@ The kit's own `Skeleton` takes a `className` for its shape and size directly (he
|
|
|
58
71
|
|
|
59
72
|
- 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.
|
|
60
73
|
- A loading region is announced once (`aria-busy`, `aria-live="polite"` on the container), not per placeholder bar.
|
|
61
|
-
- With reduced motion, a skeleton is still visibly a placeholder (
|
|
74
|
+
- With reduced motion, a skeleton is still visibly a placeholder (still grey ghosts), never indistinguishable from real, blank content.
|
|
62
75
|
|
|
63
76
|
## Source
|
|
64
77
|
|
|
65
|
-
**Derived from**:
|
|
66
|
-
|
|
78
|
+
**Derived from**: North's loading (style1.css:1458-1469: the shimmer over blocks, the ghost shapes, the 116 x 38
|
|
79
|
+
button place) and the kit's own `Skeleton`. North's sweep in the chart colours and its colour band over the chart are
|
|
80
|
+
not taken: loaders are one quiet grey (Amit, 10 Nov 2026, Decisions). It replaces the breathing
|
|
81
|
+
pulse, which read as blank (1.10:1 on the cream, field evidence S01). **Precedent**: the first product built on the
|
|
82
|
+
system.
|
|
83
|
+
|
|
84
|
+
## Markup
|
|
85
|
+
|
|
86
|
+
```html
|
|
87
|
+
<div class="ws-card ws-card--compound" aria-busy="true">
|
|
88
|
+
<span class="ws-sr">Loading the chart</span>
|
|
89
|
+
<div class="ws-skeleton__head" aria-hidden="true">
|
|
90
|
+
<div class="ws-skeleton ws-skeleton--title" style="width: 55%;"></div>
|
|
91
|
+
<div class="ws-skeleton ws-skeleton--line" style="width: 80%;"></div>
|
|
92
|
+
</div>
|
|
93
|
+
<div class="ws-skeleton__body" aria-hidden="true">
|
|
94
|
+
<div class="ws-skeleton__chart"><i style="height: 35%;"></i><i style="height: 60%;"></i><i style="height: 45%;"></i></div>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Styles
|
|
100
|
+
|
|
101
|
+
`Skeleton/style.css`, built into `bundle.css` and `fello.css`. The keyframe is the house's `ws-shimmer`. Tokens:
|
|
102
|
+
`--ws-shimmer` (over `--ws-shimmer-ground`), `--ws-ghost`, `--ws-loop-shimmer`, `--ws-ease-shimmer`,
|
|
103
|
+
`--ws-radius-control`, `--ws-radius-row`, `--ws-radius-bar`.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- @dsCard group="Cards" height=
|
|
1
|
+
<!-- @dsCard group="Cards" height=430 -->
|
|
2
2
|
<!doctype html>
|
|
3
3
|
<html>
|
|
4
4
|
<head>
|
|
@@ -8,36 +8,48 @@
|
|
|
8
8
|
<link rel="stylesheet" href="../bundle.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
|
-
<div class="ws-stage
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
<div class="ws-skeleton ws-
|
|
17
|
-
<div class="ws-skeleton ws-
|
|
18
|
-
|
|
11
|
+
<div class="ws-stage">
|
|
12
|
+
<div class="ws-stack" style="width: 240px;">
|
|
13
|
+
<span class="ws-muted">Lines: a title, two lines, the last shorter, the shimmer passing over them</span>
|
|
14
|
+
<div class="ws-stack" aria-hidden="true">
|
|
15
|
+
<div class="ws-skeleton ws-skeleton--title" style="width: 60%;"></div>
|
|
16
|
+
<div class="ws-skeleton ws-skeleton--line"></div>
|
|
17
|
+
<div class="ws-skeleton ws-skeleton--line" style="width: 66%;"></div>
|
|
18
|
+
</div>
|
|
19
|
+
<span class="ws-muted">A tile still loading</span>
|
|
20
|
+
<div class="ws-card" aria-busy="true">
|
|
21
|
+
<span class="ws-sr">Loading Zillow rating</span>
|
|
22
|
+
<div class="ws-card__surface ws-card__surface--pad ws-stack" aria-hidden="true">
|
|
23
|
+
<div class="ws-skeleton ws-skeleton--line" style="width: 50%;"></div>
|
|
24
|
+
<div class="ws-skeleton" style="height: var(--ws-leading-figure); width: 40%;"></div>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="ws-card__foot" aria-hidden="true">
|
|
27
|
+
<div class="ws-skeleton ws-skeleton--line" style="width: 40%;"></div>
|
|
28
|
+
</div>
|
|
19
29
|
</div>
|
|
20
30
|
</div>
|
|
21
31
|
|
|
22
|
-
<div class="ws-stack">
|
|
23
|
-
<span class="ws-muted">A card
|
|
24
|
-
<div
|
|
25
|
-
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
<div class="ws-skeleton ws-
|
|
29
|
-
<div class="ws-skeleton ws-working-slow" style="height: var(--space-sm); width: 75%;"></div>
|
|
32
|
+
<div class="ws-stack" style="width: 380px;">
|
|
33
|
+
<span class="ws-muted">A chart card still loading: each bar a ghost under the same shimmer</span>
|
|
34
|
+
<div class="ws-card ws-card--compound" aria-busy="true">
|
|
35
|
+
<span class="ws-sr">Loading the chart</span>
|
|
36
|
+
<div class="ws-skeleton__head" aria-hidden="true">
|
|
37
|
+
<div class="ws-skeleton ws-skeleton--title" style="width: 55%;"></div>
|
|
38
|
+
<div class="ws-skeleton ws-skeleton--line" style="width: 80%;"></div>
|
|
30
39
|
</div>
|
|
31
|
-
<div class="ws-skeleton__body">
|
|
32
|
-
<div class="ws-
|
|
40
|
+
<div class="ws-skeleton__body" aria-hidden="true">
|
|
41
|
+
<div class="ws-skeleton__chart">
|
|
42
|
+
<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>
|
|
43
|
+
</div>
|
|
33
44
|
</div>
|
|
34
|
-
<footer class="ws-band">
|
|
35
|
-
<div class="ws-
|
|
45
|
+
<footer class="ws-band" aria-hidden="true">
|
|
46
|
+
<div class="ws-band__words">
|
|
47
|
+
<div class="ws-skeleton ws-skeleton--line" style="width: 50%;"></div>
|
|
48
|
+
</div>
|
|
49
|
+
<div class="ws-band__acts"><div class="ws-skeleton ws-skeleton--button"></div></div>
|
|
36
50
|
</footer>
|
|
37
51
|
</div>
|
|
38
|
-
</div>
|
|
39
52
|
</div>
|
|
40
|
-
|
|
41
53
|
</div>
|
|
42
54
|
</body>
|
|
43
55
|
</html>
|
|
@@ -0,0 +1,17 @@
|
|
|
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. */
|
|
6
|
+
.ws-skeleton { border-radius: var(--ws-radius-control); background: var(--ws-ghost); }
|
|
7
|
+
.ws-skeleton--line { height: var(--space-sm); }
|
|
8
|
+
.ws-skeleton--title { height: var(--ws-leading-title); }
|
|
9
|
+
/* A button's place (North's 116 x 38 placeholder, on the grid: 120 x 36, 6 px corners). */
|
|
10
|
+
.ws-skeleton--button { width: var(--space-7xl); height: var(--ws-control-h-md); border-radius: var(--ws-radius-row); }
|
|
11
|
+
.ws-skeleton__head { display: flex; flex-direction: column; gap: var(--space-xs); padding: var(--ws-card-inset); }
|
|
12
|
+
.ws-skeleton__body { display: flex; flex-direction: column; gap: var(--space-xs); padding: 0 var(--ws-card-inset) var(--space-md); }
|
|
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); }
|
|
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); }
|
|
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; } }
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
A value picked by dragging along a range (a team size, a share), drawn by the browser in the house's navy, with the
|
|
2
|
+
value said in words beside its label.
|
|
3
|
+
|
|
4
|
+
## Use it when
|
|
5
|
+
|
|
6
|
+
- A worksheet asks for a number within a known range, where the feel of more or less matters more than the exact
|
|
7
|
+
figure (Tally's team size, a share of seats).
|
|
8
|
+
- The person will try a few values and watch something else on the page answer.
|
|
9
|
+
|
|
10
|
+
## Not for
|
|
11
|
+
|
|
12
|
+
- An exact figure someone types (a price, a count to the unit): use `NumberInput`.
|
|
13
|
+
- A choice among a few named options: use `Segmented` or `Radio`.
|
|
14
|
+
- A value the page reports rather than asks for: use `Meter` or a chart.
|
|
15
|
+
|
|
16
|
+
## Anatomy
|
|
17
|
+
|
|
18
|
+
- Head: the label (12 / 16 medium body, `ws-label`) at the left, the value in words at the right (13 / 18 semibold navy,
|
|
19
|
+
even numerals, `<output>`), on one baseline, 12 apart.
|
|
20
|
+
- Range: the browser's own `<input type="range">`, full width, 24 px tall (40 on touch), its fill and thumb the act's
|
|
21
|
+
navy (`accent-color`).
|
|
22
|
+
- Ends (optional): the lowest and highest values under the range, 12 / 16 muted, one at each end.
|
|
23
|
+
- 4 px between the parts.
|
|
24
|
+
|
|
25
|
+
## Variants and sizes
|
|
26
|
+
|
|
27
|
+
| Variant | What it looks like | Where |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| With its ends | the two ends named under the range | when the range itself helps ("1" to "40 people") |
|
|
30
|
+
| Plain | head and range | a share whose ends say themselves (0 to 100%) |
|
|
31
|
+
|
|
32
|
+
One size; it takes its column's width.
|
|
33
|
+
|
|
34
|
+
## States
|
|
35
|
+
|
|
36
|
+
- **Default:** the range at the value, the value in words in the head.
|
|
37
|
+
- **Hover / pressed:** the browser's own (the thumb under the pointer).
|
|
38
|
+
- **Focus:** the kit's ring, 2 px navy, 2 px out, round the range.
|
|
39
|
+
- **Disabled:** the whole slider, label and value with it, at 50% (as `Switch` and `Checkbox`), no pointer; the value
|
|
40
|
+
still says where it was set.
|
|
41
|
+
- **Error / empty / loading:** not applicable: a range always holds a value.
|
|
42
|
+
- **Long label:** the label wraps; the value keeps its line at the right.
|
|
43
|
+
- **Narrow:** the range takes the column's width.
|
|
44
|
+
- **Touch:** 40 tall; the thumb follows the finger.
|
|
45
|
+
- **Dark:** `accent-color` follows the light ink; the words take their dark values.
|
|
46
|
+
|
|
47
|
+
## Behaviour
|
|
48
|
+
|
|
49
|
+
- Keyboard: the browser's own: arrows step, Page Up and Down take bigger steps, Home and End jump to the ends.
|
|
50
|
+
- The page updates the `<output>` and the input's `aria-valuetext` ("12 people") on `input`, so a screen reader says the
|
|
51
|
+
value in words, not a bare number.
|
|
52
|
+
- Motion: none of its own.
|
|
53
|
+
|
|
54
|
+
## Content
|
|
55
|
+
|
|
56
|
+
- The label names the thing ("Your team size"), the value says it with its unit ("12 people", "50%").
|
|
57
|
+
- No em dashes.
|
|
58
|
+
|
|
59
|
+
## Props
|
|
60
|
+
|
|
61
|
+
| Name | Type | Meaning |
|
|
62
|
+
| --- | --- | --- |
|
|
63
|
+
| `label` | `string` | what is being set |
|
|
64
|
+
| `value` | `number` | the value |
|
|
65
|
+
| `min`, `max`, `step` | `number` | the range |
|
|
66
|
+
| `format` | `(value: number) => string` | the value in words, for the head and `aria-valuetext` |
|
|
67
|
+
| `showEnds` | `boolean` | name the two ends under the range |
|
|
68
|
+
| `onChange` | `(value: number) => void` | called as the value moves |
|
|
69
|
+
|
|
70
|
+
## Rules
|
|
71
|
+
|
|
72
|
+
- A native range, never a drawn one: the browser gives the keyboard, touch and screen-reader behaviour for free.
|
|
73
|
+
- The value is always said in words beside the label; the thumb's place alone is never the answer.
|
|
74
|
+
|
|
75
|
+
## Source
|
|
76
|
+
|
|
77
|
+
**Derived from**: Ignite's `Slider` (core/ui/controls.tsx, 3 Nov 2026, for Tally's worksheet): a native range,
|
|
78
|
+
`accent-color` navy, 24 px tall, the focus ring, disabled at 50%. **Precedent**: the first product built on the system.
|
|
79
|
+
|
|
80
|
+
## Markup
|
|
81
|
+
|
|
82
|
+
```html
|
|
83
|
+
<div class="ws-slider">
|
|
84
|
+
<div class="ws-slider__head">
|
|
85
|
+
<label class="ws-label" for="team">Your team size</label>
|
|
86
|
+
<output class="ws-slider__value" for="team">12 people</output>
|
|
87
|
+
</div>
|
|
88
|
+
<input class="ws-slider__input" id="team" type="range" min="1" max="40" value="12" aria-valuetext="12 people">
|
|
89
|
+
<div class="ws-slider__ends" aria-hidden="true"><span>1</span><span>40</span></div>
|
|
90
|
+
</div>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Styles
|
|
94
|
+
|
|
95
|
+
`design-system/components/Slider/style.css`: `ws-slider`, `__head`, `__value`, `__input`, `__ends`.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<!-- @dsCard group="Fields" height=344 -->
|
|
2
|
+
<!doctype html>
|
|
3
|
+
<html>
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>Slider</title>
|
|
7
|
+
<link rel="stylesheet" href="../../tokens.css">
|
|
8
|
+
<link rel="stylesheet" href="../bundle.css">
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div class="ws-stage ws-stage--column">
|
|
12
|
+
|
|
13
|
+
<div class="ws-stack" style="width: 360px; max-width: 100%;">
|
|
14
|
+
<span class="ws-muted">A value with its words at the right, the two ends under it</span>
|
|
15
|
+
<div class="ws-slider">
|
|
16
|
+
<div class="ws-slider__head">
|
|
17
|
+
<label class="ws-label" for="sl-team">Your team size</label>
|
|
18
|
+
<output class="ws-slider__value" for="sl-team">12 people</output>
|
|
19
|
+
</div>
|
|
20
|
+
<input class="ws-slider__input" id="sl-team" type="range" min="1" max="40" value="12" aria-valuetext="12 people">
|
|
21
|
+
<div class="ws-slider__ends" aria-hidden="true"><span>1</span><span>40</span></div>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div class="ws-stack" style="width: 240px; max-width: 100%;">
|
|
26
|
+
<span class="ws-muted">A share, and a long label that wraps beside its value (a 240 px column)</span>
|
|
27
|
+
<div class="ws-slider">
|
|
28
|
+
<div class="ws-slider__head">
|
|
29
|
+
<label class="ws-label" for="sl-share">Share of ISA seats Felix absorbs in the first quarter</label>
|
|
30
|
+
<output class="ws-slider__value" for="sl-share">50%</output>
|
|
31
|
+
</div>
|
|
32
|
+
<input class="ws-slider__input" id="sl-share" type="range" min="0" max="100" step="5" value="50" aria-valuetext="50 percent">
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div class="ws-stack" style="width: 360px; max-width: 100%;">
|
|
37
|
+
<span class="ws-muted">Disabled (set by an admin)</span>
|
|
38
|
+
<div class="ws-slider">
|
|
39
|
+
<div class="ws-slider__head">
|
|
40
|
+
<label class="ws-label" for="sl-dis">Weekly call goal</label>
|
|
41
|
+
<output class="ws-slider__value" for="sl-dis">60 calls</output>
|
|
42
|
+
</div>
|
|
43
|
+
<input class="ws-slider__input" id="sl-dis" type="range" min="0" max="100" value="60" disabled aria-valuetext="60 calls">
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
</div>
|
|
48
|
+
</body>
|
|
49
|
+
</html>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/* ---- Slider: a native range in the house's navy (Ignite's, 3 Nov): the browser's own control, so the keyboard, touch
|
|
2
|
+
and a screen reader work as they should; accent-color the navy act, 24 px tall (40 on touch), its value said in words
|
|
3
|
+
at the right of its label, the two ends named under it when they help. ---- */
|
|
4
|
+
.ws-slider { display: flex; min-width: 0; flex-direction: column; gap: var(--space-xxs); }
|
|
5
|
+
.ws-slider__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-sm); }
|
|
6
|
+
.ws-slider__value { flex-shrink: 0; font-size: var(--ws-text-control); line-height: var(--ws-leading-control); font-weight: 600; color: var(--color-text-heading); font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
7
|
+
.ws-slider__input { display: block; width: 100%; height: var(--space-lg); margin: 0; background: transparent; accent-color: var(--color-text-heading); cursor: pointer; }
|
|
8
|
+
/* Disabled: the whole slider at 50%, its label and value with it (as Switch and Checkbox), no pointer. */
|
|
9
|
+
.ws-slider:has(.ws-slider__input:disabled) { opacity: 0.5; }
|
|
10
|
+
.ws-slider__input:disabled { cursor: not-allowed; }
|
|
11
|
+
.ws-slider__ends { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-sm); font-size: var(--ws-text-dense); line-height: var(--space-md); color: var(--color-text-muted); font-variant-numeric: tabular-nums; }
|
|
12
|
+
.ws-slider__ends > :last-child { text-align: end; }
|
|
13
|
+
@media (pointer: coarse) { .ws-slider__input { height: var(--ws-touch); } }
|