@spark-web/design-system 5.1.3 → 5.1.5
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/CLAUDE.md +38 -192
- package/package.json +20 -21
- package/patterns/CLAUDE.md +75 -35
- package/patterns/internal-admin/CLAUDE.md +7 -19
- package/patterns/internal-admin/{details-page.md → detail-page.md} +114 -51
- package/patterns/internal-admin/list-page.md +199 -137
- package/patterns/internal-admin/portal-hub.md +165 -0
- package/patterns/vendor-admin/CLAUDE.md +216 -0
- package/patterns/vendor-admin/dashboard.md +681 -0
- package/patterns/vendor-admin/form-page.md +504 -0
- package/patterns/vendor-admin/list-page.md +709 -0
- package/patterns/vendor-admin/vendor-portal.md +309 -0
- package/ai-context/layer-1-root.md +0 -158
- package/ai-context/layer-2-surface-pattern.md +0 -236
- package/ai-context/layer-3-component.md +0 -271
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# Vendor admin — interaction and pattern rules
|
|
2
|
+
|
|
3
|
+
These rules apply to all components and patterns built for vendor admin
|
|
4
|
+
surfaces. They sit above individual component rules. When a conflict exists
|
|
5
|
+
between these rules and a component-level CLAUDE.md, these rules take precedence
|
|
6
|
+
for vendor-admin surfaces.
|
|
7
|
+
|
|
8
|
+
Vendor-admin is the surface used by external vendors, installers, and partners
|
|
9
|
+
signing in to manage their own work (leads, applications, settings). It is a
|
|
10
|
+
distinct surface from internal-admin and has different chrome — do not apply
|
|
11
|
+
internal-admin rules here, and do not "correct" vendor-admin choices to match
|
|
12
|
+
internal-admin where they intentionally diverge (see Page title rule below).
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Layout shell and content region
|
|
17
|
+
|
|
18
|
+
Vendor-admin screens render inside a fixed application shell:
|
|
19
|
+
|
|
20
|
+
- A **fixed, sticky Header** pinned to the top, full width
|
|
21
|
+
(`position: fixed; top: 0`). It is `72px` tall on mobile and `90px` on tablet
|
|
22
|
+
and up.
|
|
23
|
+
- A **fixed left NavBar sidebar** on tablet and up
|
|
24
|
+
(`position: fixed; left: 0; width: 270px`, full height). On mobile the sidebar
|
|
25
|
+
collapses behind a hamburger (`MenuIcon`) toggle in the Header.
|
|
26
|
+
- A **main content region** that is offset to clear the shell and owns a
|
|
27
|
+
full-height scroll area:
|
|
28
|
+
- top offset `72px` on mobile, `90px` on tablet and up (clears the Header),
|
|
29
|
+
- left offset `0` on mobile, `270px` on tablet and up (clears the sidebar),
|
|
30
|
+
- height `calc(100svh - 90px)` so the region — not the document — scrolls.
|
|
31
|
+
|
|
32
|
+
The shell frame (Header + sidebar + offset content region) is the surface rule:
|
|
33
|
+
every vendor-admin page renders into this region and must not reproduce the
|
|
34
|
+
Header or sidebar itself. The **shell implementation is consumer-owned** — the
|
|
35
|
+
Header, NavBar, and the `_app`-level wrapper are local components, not published
|
|
36
|
+
`@spark-web/*` components. The concrete substitutions (component names, props)
|
|
37
|
+
live in the consumer overlay (a sibling file):
|
|
38
|
+
|
|
39
|
+
`node_modules/@spark-web/design-system/patterns/vendor-admin/vendor-portal.md`
|
|
40
|
+
|
|
41
|
+
The region and offsets above are the rule; the implementation is the overlay's.
|
|
42
|
+
|
|
43
|
+
A page authored for vendor-admin therefore starts at the page-content level (the
|
|
44
|
+
page title row, filters, content) and assumes the shell already exists around
|
|
45
|
+
it.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Page title rule
|
|
50
|
+
|
|
51
|
+
Vendor-admin uses `Heading level="2"` for the page title — **not**
|
|
52
|
+
internal-admin's `PageHeader` / `H1`.
|
|
53
|
+
|
|
54
|
+
This is the clearest divergence from internal-admin and is intentional: the two
|
|
55
|
+
surfaces have different chrome. On vendor-admin the fixed Header already carries
|
|
56
|
+
the product identity and primary navigation, so the in-page title is a section
|
|
57
|
+
heading within the shell, expressed as `<Heading level="2">`. Do not replace it
|
|
58
|
+
with `PageHeader` or promote it to `level="1"`. Within a page, sub-section
|
|
59
|
+
titles step down to `<Heading level="3">`.
|
|
60
|
+
|
|
61
|
+
**Dashboard exception.** The dashboard / overview screen type is a documented
|
|
62
|
+
exception to this single-page-title rule: an overview page has no single
|
|
63
|
+
dominant subject, so it leads with **section-level `Heading level="2"`**
|
|
64
|
+
headings (e.g. "Summary", "Support & resources", "What's New") and **no separate
|
|
65
|
+
page title**. Sub-headings within a dashboard section step down to `level="3"`.
|
|
66
|
+
This exception applies only to the dashboard/overview shell — see
|
|
67
|
+
`node_modules/@spark-web/design-system/patterns/vendor-admin/dashboard.md`. All
|
|
68
|
+
other screen types keep the single `Heading level="2"` page title above.
|
|
69
|
+
|
|
70
|
+
Page-level actions (e.g. an "Export" `Button`) sit on the same row as the title,
|
|
71
|
+
right-aligned, in a flex row that stacks to a column on mobile. A count or limit
|
|
72
|
+
indicator (`Badge`) may sit next to the title on the left.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Spacing and density
|
|
77
|
+
|
|
78
|
+
Vendor-admin pages use a generous rhythm. The observed page-level pattern across
|
|
79
|
+
screens:
|
|
80
|
+
|
|
81
|
+
- List pages wrap their content in a `Stack` with `gap="large"` and
|
|
82
|
+
`margin="xxlarge"` (often `marginBottom="none"` so the scroll region reaches
|
|
83
|
+
the viewport edge), `height="full"`.
|
|
84
|
+
- Form / settings pages center content in a `Container size="medium"` and use a
|
|
85
|
+
`Stack` with `gap="xxlarge"` between sections, with `marginY="xxlarge"`.
|
|
86
|
+
- Filter rows within a list page use `gap="medium"`.
|
|
87
|
+
|
|
88
|
+
Use these spacing tokens — never raw pixel gaps or margins. When in doubt for a
|
|
89
|
+
new vendor-admin page, default to `Stack gap="large"` for the page body and
|
|
90
|
+
`gap="xxlarge"` to separate major form sections.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Detail interaction rule — side panel vs full page
|
|
95
|
+
|
|
96
|
+
Vendor-admin opens a record's detail in a **slide-in side panel**, not by
|
|
97
|
+
navigating to a separate detail page.
|
|
98
|
+
|
|
99
|
+
- The side panel is a right-anchored slide-in within the content region
|
|
100
|
+
(`position: absolute; right: 0`): **~`90vw` on mobile, up to `500px`
|
|
101
|
+
(`maxWidth`) from tablet** (vendor-portal's current panel also offsets below
|
|
102
|
+
the header — see the overlay). It overlays the list rather than reflowing it.
|
|
103
|
+
- Opening a row's detail sets the selected record (typically via a URL query
|
|
104
|
+
param so the panel is deep-linkable) and renders the panel alongside the still
|
|
105
|
+
visible list.
|
|
106
|
+
|
|
107
|
+
**When to use a side panel vs a full page:**
|
|
108
|
+
|
|
109
|
+
- **Side panel** — the default for inspecting / lightly acting on a single
|
|
110
|
+
record while staying in the list context (viewing a lead, an application
|
|
111
|
+
summary, quick status changes). Use it whenever the user benefits from
|
|
112
|
+
remaining anchored to the list and the detail is bounded.
|
|
113
|
+
- **Full page** — reserve for heavyweight, standalone flows that do not belong
|
|
114
|
+
beside a list: multi-step forms, a dedicated settings screen, or a legacy /
|
|
115
|
+
embedded screen. Settings is a full page (`Container`-centered), not a panel.
|
|
116
|
+
|
|
117
|
+
The side panel itself is **consumer-supplied** and is a **COMPONENT GAP**: there
|
|
118
|
+
is no `@spark-web` drawer or side-panel component (verification note: see the
|
|
119
|
+
overlay). Until a Spark drawer exists, mark its use with
|
|
120
|
+
`// COMPONENT GAP: SidePanel/Drawer needed — not yet in Spark` and use the
|
|
121
|
+
consumer's `SidePanel`; see the overlay (a sibling file):
|
|
122
|
+
|
|
123
|
+
`node_modules/@spark-web/design-system/patterns/vendor-admin/vendor-portal.md`
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## List loading rule — infinite scroll vs pagination
|
|
128
|
+
|
|
129
|
+
Choose the list-loading strategy by the shape of the dataset:
|
|
130
|
+
|
|
131
|
+
- **Infinite scroll** — use for large or streamed datasets where the total is
|
|
132
|
+
unbounded or expensive to count, and the natural interaction is "keep
|
|
133
|
+
scrolling" (e.g. leads). Implement by fetching the next page when the bottom
|
|
134
|
+
of the scroll region is reached and appending rows.
|
|
135
|
+
- **Pagination** — use for bounded result sets where the user benefits from
|
|
136
|
+
jumping to a known page and seeing the total (e.g. applications, with an "X of
|
|
137
|
+
Y results" summary and page controls).
|
|
138
|
+
|
|
139
|
+
Default: if the PRD describes an open-ended, continuously growing list →
|
|
140
|
+
infinite scroll; if it describes a finite, countable list the user pages through
|
|
141
|
+
→ pagination.
|
|
142
|
+
|
|
143
|
+
- **Load More** (button-triggered incremental) — a THIRD list-loading mode: a
|
|
144
|
+
"Load More" `Button` fetches and appends the next page on click (the Button's
|
|
145
|
+
`loading` prop bound to the in-flight fetch), rather than auto-fetching on
|
|
146
|
+
scroll (infinite scroll) or exposing page controls (pagination). Use it for a
|
|
147
|
+
short, browse-occasionally feed where the user opts in to more — e.g. the
|
|
148
|
+
dashboard announcements / "What's New" feed (see
|
|
149
|
+
`node_modules/@spark-web/design-system/patterns/vendor-admin/dashboard.md`).
|
|
150
|
+
|
|
151
|
+
The **pagination control is consumer-supplied** and is a **COMPONENT GAP**:
|
|
152
|
+
there is no `@spark-web` pagination component. Mark its use with
|
|
153
|
+
`// COMPONENT GAP: TablePagination needed — not yet in Spark` and use the
|
|
154
|
+
consumer's pagination component; see the overlay.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Bulk actions rule
|
|
159
|
+
|
|
160
|
+
When a list supports selecting multiple rows, selecting one or more rows reveals
|
|
161
|
+
a **bottom-anchored bulk-action toast** pinned to the content region
|
|
162
|
+
(`position: absolute; bottom: 0; left: 0`). It exposes the actions that apply to
|
|
163
|
+
the current selection (e.g. assign, close) and a way to clear the selection.
|
|
164
|
+
|
|
165
|
+
Rules:
|
|
166
|
+
|
|
167
|
+
- The bulk-action toast appears **only when** the list is multi-select **and**
|
|
168
|
+
at least one row is selected; it is hidden when the selection is empty.
|
|
169
|
+
- A bulk-action toast and a record side panel are mutually exclusive in
|
|
170
|
+
practice: show the detail panel only when the selection is a single record,
|
|
171
|
+
and the bulk toast only when one or more rows are selected for a bulk
|
|
172
|
+
operation.
|
|
173
|
+
- Disable the toast's actions while a bulk mutation is in flight.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Badge and pill rules — tone mapping
|
|
178
|
+
|
|
179
|
+
Vendor-admin reuses the internal-admin badge tone mapping verbatim. Do not
|
|
180
|
+
re-derive it here. Read and apply the authoritative mapping at:
|
|
181
|
+
|
|
182
|
+
`node_modules/@spark-web/design-system/patterns/internal-admin/CLAUDE.md` (see
|
|
183
|
+
"Badge and pill rules" / "Badge tone mapping").
|
|
184
|
+
|
|
185
|
+
If a vendor-admin screen has status vocabulary not covered by the internal-admin
|
|
186
|
+
mapping (e.g. lead intents, vendor lead statuses, accreditation states), map
|
|
187
|
+
each new value with that same logic and record the new vocabulary in the
|
|
188
|
+
relevant pattern file rather than redefining tones here.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Role and feature-flag gating
|
|
193
|
+
|
|
194
|
+
Vendor-admin screens and individual nav items / actions may be gated by role
|
|
195
|
+
(e.g. vendor-admin-only screens) or by feature flags. This gating is **consumer
|
|
196
|
+
logic, not a design-system rule** — it lives in the consuming app (the shell's
|
|
197
|
+
nav config, route guards, and flag checks), not in `@spark-web` components or in
|
|
198
|
+
these surface rules.
|
|
199
|
+
|
|
200
|
+
Where it sits: gating wraps the page or nav entry at the shell / routing layer
|
|
201
|
+
and conditionally renders flag-guarded sections. A pattern or component doc
|
|
202
|
+
should never encode a specific role name or flag key. When a PRD specifies that
|
|
203
|
+
a screen is admin-only or behind a flag, treat that as the consumer's
|
|
204
|
+
responsibility and note it; build the screen's component tree per the pattern
|
|
205
|
+
regardless.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Rules that update as the system grows
|
|
210
|
+
|
|
211
|
+
When a new pattern or component is added to the vendor-admin surface, update
|
|
212
|
+
this file with any new interaction rules that apply globally. Do not duplicate
|
|
213
|
+
rules that already exist here in component-level CLAUDE.md files. If a new
|
|
214
|
+
pattern file is added under `patterns/vendor-admin/`, also update the
|
|
215
|
+
feature-type table in `node_modules/@spark-web/design-system/patterns/CLAUDE.md`
|
|
216
|
+
in the same commit.
|