division-ds 0.2.0 → 0.2.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 +9 -3
- package/division-ds-0.2.1.tgz +0 -0
- package/package.json +1 -1
- package/public/docs/components/accordion.md +2 -0
- package/public/docs/components/ai-label.md +2 -0
- package/public/docs/components/alert-dialog.md +2 -0
- package/public/docs/components/alert.md +2 -0
- package/public/docs/components/approval-request.md +2 -0
- package/public/docs/components/auth-form.md +2 -0
- package/public/docs/components/avatar-group.md +2 -0
- package/public/docs/components/avatar.md +2 -0
- package/public/docs/components/badge.md +2 -0
- package/public/docs/components/breadcrumbs.md +2 -0
- package/public/docs/components/button.md +2 -0
- package/public/docs/components/card.md +2 -0
- package/public/docs/components/carousel.md +2 -0
- package/public/docs/components/cart.md +2 -0
- package/public/docs/components/chart-panel.md +2 -0
- package/public/docs/components/chat-message.md +3 -0
- package/public/docs/components/chat-thread.md +2 -0
- package/public/docs/components/checkbox.md +2 -0
- package/public/docs/components/checkout-form.md +2 -0
- package/public/docs/components/command-palette.md +2 -0
- package/public/docs/components/data-table.md +2 -0
- package/public/docs/components/description-list.md +2 -0
- package/public/docs/components/dialog.md +2 -0
- package/public/docs/components/divider.md +2 -0
- package/public/docs/components/dropdown-menu.md +2 -0
- package/public/docs/components/empty-state.md +2 -0
- package/public/docs/components/footer.md +2 -0
- package/public/docs/components/form-field.md +4 -1
- package/public/docs/components/icon-button.md +2 -0
- package/public/docs/components/input.md +2 -0
- package/public/docs/components/kanban-board.md +2 -0
- package/public/docs/components/kbd.md +2 -0
- package/public/docs/components/link.md +2 -0
- package/public/docs/components/list-item.md +3 -0
- package/public/docs/components/loading-animation.md +2 -0
- package/public/docs/components/multi-select.md +2 -0
- package/public/docs/components/navbar.md +2 -0
- package/public/docs/components/newsletter-form.md +2 -0
- package/public/docs/components/page-header.md +2 -0
- package/public/docs/components/pagination.md +2 -0
- package/public/docs/components/product-card.md +3 -0
- package/public/docs/components/progress.md +3 -1
- package/public/docs/components/prompt-input.md +2 -0
- package/public/docs/components/quantity-stepper.md +2 -0
- package/public/docs/components/radio.md +38 -1
- package/public/docs/components/rating.md +2 -0
- package/public/docs/components/score-ring.md +2 -0
- package/public/docs/components/search.md +2 -0
- package/public/docs/components/section-heading.md +2 -0
- package/public/docs/components/segmented-control.md +2 -0
- package/public/docs/components/select.md +3 -1
- package/public/docs/components/sheet.md +2 -0
- package/public/docs/components/sidebar.md +2 -0
- package/public/docs/components/skeleton.md +2 -0
- package/public/docs/components/slider.md +3 -1
- package/public/docs/components/sparkline.md +2 -0
- package/public/docs/components/spinner.md +4 -2
- package/public/docs/components/stat.md +2 -0
- package/public/docs/components/status-tracker.md +2 -0
- package/public/docs/components/stepper.md +2 -0
- package/public/docs/components/switch.md +4 -2
- package/public/docs/components/tabs.md +2 -0
- package/public/docs/components/tag.md +2 -0
- package/public/docs/components/textarea.md +2 -0
- package/public/docs/components/timeline.md +2 -0
- package/public/docs/components/toast.md +2 -0
- package/public/docs/components/tool-call.md +2 -0
- package/public/docs/components/tooltip.md +2 -0
- package/public/manifest/components.json +16 -9
- package/public/manifest/tokens.json +36 -5
- package/scripts/division-ds.mjs +5 -5
- package/scripts/lib/agent-docs.mjs +28 -6
- package/scripts/lib/ai-copy.mjs +15 -1
- package/scripts/lib/check-text.mjs +13 -0
- package/scripts/lib/mcp-server.mjs +2 -1
- package/scripts/lib/mcp-tools.mjs +33 -8
- package/scripts/lib/props-validator.mjs +2 -1
- package/scripts/lib/token-discipline.mjs +10 -3
- package/skills/division-ds/commands/add.md +1 -1
- package/skills/division-ds/commands/build.md +1 -1
- package/skills/division-ds/commands/fix.md +1 -1
- package/skills/division-ds/commands/review.md +2 -2
- package/skills/division-ds/topics/ai.md +2 -1
- package/skills/division-ds/topics/forms.md +3 -0
- package/skills/division-ds/topics/layout.md +3 -1
- package/division-ds-0.2.0.tgz +0 -0
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// Most design-system MCP servers stop at list / search / get docs (shadcn, Chakra, Dialtone,
|
|
6
6
|
// Blade, Vibe; surveyed 2026-10-25). `validate_code` is the one they lack: it runs the same gates
|
|
7
7
|
// as `division-ds check` on the code the agent has just written, before the agent says it is done.
|
|
8
|
+
import { alsoExports, INSTALLED_PATHS } from './agent-docs.mjs'
|
|
8
9
|
import { checkText } from './check-text.mjs'
|
|
9
10
|
import { contrastRatio } from './contrast.mjs'
|
|
10
11
|
import { buildIndex, closest } from './props-validator.mjs'
|
|
@@ -30,7 +31,11 @@ export function createTools(context) {
|
|
|
30
31
|
|
|
31
32
|
function findComponent(name) {
|
|
32
33
|
const wanted = String(name ?? '').trim().toLowerCase()
|
|
33
|
-
return
|
|
34
|
+
return (
|
|
35
|
+
components.find(c => c.name.toLowerCase() === wanted || c.slug === wanted) ??
|
|
36
|
+
// A component documented on another's page (ResponseFeedback on ChatMessage's) opens that page.
|
|
37
|
+
components.find(c => alsoExports(c).some(other => other.toLowerCase() === wanted))
|
|
38
|
+
)
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
function unknownComponent(name) {
|
|
@@ -66,7 +71,12 @@ export function createTools(context) {
|
|
|
66
71
|
run({ tier } = {}) {
|
|
67
72
|
if (tier !== undefined && !TIERS.includes(tier)) throw new ToolError(`tier is one of ${TIERS.join(', ')}.`)
|
|
68
73
|
const rows = components.filter(c => !tier || c.tier === tier)
|
|
69
|
-
return rows
|
|
74
|
+
return rows
|
|
75
|
+
.map(c => {
|
|
76
|
+
const also = alsoExports(c)
|
|
77
|
+
return `- ${c.name} (${c.tier}): ${c.useWhen}${c.notFor ? ` Not for: ${c.notFor}` : ''}${also.length ? ` Also on its page: ${also.join(', ')}.` : ''}`
|
|
78
|
+
})
|
|
79
|
+
.join('\n')
|
|
70
80
|
},
|
|
71
81
|
},
|
|
72
82
|
{
|
|
@@ -85,7 +95,7 @@ export function createTools(context) {
|
|
|
85
95
|
const c = findComponent(name) ?? unknownComponent(name)
|
|
86
96
|
const imports = c.imports.map(i => `import { ${i.names.join(', ')} } from '${i.from}'`).join('\n')
|
|
87
97
|
const props = c.props.map(p => `- ${p.name}: ${p.type}${p.default ? ` = ${p.default}` : ''}. ${p.description ?? ''}`.trimEnd()).join('\n')
|
|
88
|
-
const head = `# ${c.name} (${c.tier})\n\n${c.summary}\n\n${imports}\n\
|
|
98
|
+
const head = `# ${c.name} (${c.tier})\n\n${c.summary}\n\n${imports}\n\n${INSTALLED_PATHS}\n\n## Props\n\n${props}`
|
|
89
99
|
if (section === 'props') return head
|
|
90
100
|
const page = context.readDoc?.(c.slug)
|
|
91
101
|
// The page is the full contract (examples, keyboard, do and don't, written for agents).
|
|
@@ -112,13 +122,28 @@ export function createTools(context) {
|
|
|
112
122
|
run({ query, limit = 10 }) {
|
|
113
123
|
const terms = words(query)
|
|
114
124
|
if (terms.length === 0) throw new ToolError('query has no words to search for.')
|
|
115
|
-
|
|
125
|
+
// `props` is the prop descriptions: a word found there counts once, as a hint, so a long
|
|
126
|
+
// prop table does not outrank a component or token whose own summary is about the query.
|
|
127
|
+
const score = (title, body, props = '', propNames = '') => {
|
|
116
128
|
const t = words(title).join(' ')
|
|
117
129
|
const b = words(body)
|
|
118
|
-
|
|
130
|
+
const p = words(props)
|
|
131
|
+
const n = words(propNames)
|
|
132
|
+
const inMain = term => t.includes(term) || b.some(w => w.startsWith(term))
|
|
133
|
+
// Every word of the query in the name or summary beats one word found often: "page
|
|
134
|
+
// background" is the surface token, not PageHeader, whose name matches "page" alone.
|
|
135
|
+
const all = terms.length > 1 && terms.every(inMain) ? 5 : 0
|
|
136
|
+
return all + terms.reduce((sum, term) => sum + (t.includes(term) ? 3 : 0) + Math.min(b.filter(w => w.startsWith(term)).length, 3) + (inMain(term) ? 0 : n.some(w => w.startsWith(term)) ? 2 : p.some(w => w.startsWith(term)) ? 1 : 0), 0)
|
|
119
137
|
}
|
|
120
138
|
const hits = [
|
|
121
|
-
|
|
139
|
+
// The title holds every name on the page (ChatMessage and ResponseFeedback); the body adds
|
|
140
|
+
// the prop descriptions, where what a part does is written ("helpful", "thumbs up").
|
|
141
|
+
...components.map(c => {
|
|
142
|
+
const also = alsoExports(c)
|
|
143
|
+
const props = c.props.map(p => `${p.name} ${p.description ?? ''}`).join(' ')
|
|
144
|
+
const line = `${c.useWhen}${also.length ? ` Also on its page: ${also.join(', ')}.` : ''}`
|
|
145
|
+
return { kind: 'component', name: c.name, line, score: score(`${c.name} ${also.join(' ')}`, `${c.summary} ${c.useWhen}`, props, c.props.map(p => p.name).join(' ')) }
|
|
146
|
+
}),
|
|
122
147
|
// Primitives are not for screens (tokens.json's rule), so they never come up as an answer.
|
|
123
148
|
...tokens.tokens.filter(t => t.layer !== 'primitive').map(t => ({ kind: `${t.layer} token`, name: t.name, line: t.use ?? '', score: score(t.name, t.use ?? '') })),
|
|
124
149
|
]
|
|
@@ -158,13 +183,13 @@ export function createTools(context) {
|
|
|
158
183
|
type: 'object',
|
|
159
184
|
properties: {
|
|
160
185
|
code: { type: 'string', description: 'The whole file, imports included: props are matched through the imports.' },
|
|
161
|
-
filename: { type: 'string', description: 'Its name, e.g. "src/pages/Settings.tsx". The extension decides which gates run. Default "Screen.tsx".' },
|
|
186
|
+
filename: { type: 'string', description: 'Its name, e.g. "src/pages/Settings.tsx". The extension decides which gates run: a .css file gets the colour and token checks, and setting a real token (--color-surface-base: ...) is allowed there, since that is how a project themes the system. Default "Screen.tsx".' },
|
|
162
187
|
},
|
|
163
188
|
required: ['code'],
|
|
164
189
|
additionalProperties: false,
|
|
165
190
|
},
|
|
166
191
|
run({ code, filename = 'Screen.tsx' }) {
|
|
167
|
-
if (!/\.(tsx|jsx|ts)$/.test(filename)) throw new ToolError('filename ends in .tsx, .jsx or .
|
|
192
|
+
if (!/\.(tsx|jsx|ts|css)$/.test(filename)) throw new ToolError('filename ends in .tsx, .jsx, .ts or .css.')
|
|
168
193
|
const findings = checkText(String(code), filename, index, tokenNames)
|
|
169
194
|
if (findings.length === 0) {
|
|
170
195
|
return `No findings in ${filename}: colours, tokens, button spacing, props and AI copy are clean.\nNot checked: how the screen behaves. Run get_review_checklist, in a browser.`
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
// accepted; one the rest type names in its Omit<> is not. With a `...rest` row of a Radix
|
|
29
29
|
// component's props, any other prop is accepted (the Radix surface is not in the manifest).
|
|
30
30
|
import ts from 'typescript'
|
|
31
|
+
import { DOCS_SITE } from './agent-docs.mjs'
|
|
31
32
|
import { parseRowName, resolvePart } from './component-props.mjs'
|
|
32
33
|
|
|
33
34
|
/** Always accepted on any component: React's own props, and attributes every DOM wrapper takes. */
|
|
@@ -125,7 +126,7 @@ export function buildIndex(manifest) {
|
|
|
125
126
|
if (exportNames.length === 0) continue
|
|
126
127
|
const components = Object.fromEntries(exportNames.map(name => [name, true]))
|
|
127
128
|
const specs = Object.fromEntries(
|
|
128
|
-
exportNames.map(name => [name, { entry: entry.name, docs: entry.docs
|
|
129
|
+
exportNames.map(name => [name, { entry: entry.name, docs: entry.docs && `${DOCS_SITE}${entry.docs.replace(/^\//, '')}`, props: new Map(), rest: null }])
|
|
129
130
|
)
|
|
130
131
|
let unresolved = false
|
|
131
132
|
for (const row of entry.props ?? []) {
|
|
@@ -9,6 +9,12 @@
|
|
|
9
9
|
// Colour only, on purpose. Spacing is not gated: enforcing it before the scale is complete makes
|
|
10
10
|
// an author (or an agent) invent a token name to satisfy the rule, which is the worse failure.
|
|
11
11
|
|
|
12
|
+
import { DOCS_SITE } from './agent-docs.mjs'
|
|
13
|
+
|
|
14
|
+
/** Where a token list lives for whoever reads the finding: the MCP tool, or the docs site. A
|
|
15
|
+
* repository path meant nothing in a project that installed the components (2026-10-29 test). */
|
|
16
|
+
const TOKEN_LIST = `get_tokens over MCP, or ${DOCS_SITE}llms-tokens.txt`
|
|
17
|
+
|
|
12
18
|
export const SCANNED_ROOTS = ['src']
|
|
13
19
|
export const SCANNED_EXTENSIONS = /\.(tsx?|css)$/
|
|
14
20
|
|
|
@@ -16,6 +22,7 @@ export const SCANNED_EXTENSIONS = /\.(tsx?|css)$/
|
|
|
16
22
|
* A new entry needs a reason as good as these; "it was easier" is the case the gate exists for. */
|
|
17
23
|
export const EXEMPT = [
|
|
18
24
|
{ pattern: /^src\/styles\/tokens\.css$/, why: 'generated from tokens/: this is where the literals are meant to be' },
|
|
25
|
+
{ pattern: /(^|\/)division-ds\/styles\/tokens\.css$/, why: 'the same file, installed into a project by shadcn; it also names the MCP Apps host\'s own variables' },
|
|
19
26
|
{ pattern: /\.test\.tsx?$/, why: 'tests assert on literal values and on deliberately wrong input' },
|
|
20
27
|
{ pattern: /^src\/demo\/(scene|blob|terrain)\//, why: 'WebGL materials: three.js takes colours as numbers, not CSS variables' },
|
|
21
28
|
{ pattern: /^src\/components\/atoms\/loading-animation\/(palette|scene|kit|variants)\.ts$/, why: 'WebGL materials, read from the tokens at runtime where they can be' },
|
|
@@ -98,9 +105,9 @@ export function findViolations(text, path, tokenNames) {
|
|
|
98
105
|
if (name.endsWith('-')) continue
|
|
99
106
|
if (!known.has(name)) {
|
|
100
107
|
const near = suggest(name, tokenNames)
|
|
101
|
-
add('unknown-token', `var(${name})`, near.length ? `No such token. Did you mean ${near.join(', ')}?` :
|
|
108
|
+
add('unknown-token', `var(${name})`, near.length ? `No such token. Did you mean ${near.join(', ')}?` : `No such token. The full list: ${TOKEN_LIST}.`)
|
|
102
109
|
} else if (PRIMITIVE_RAMP.test(name) && inComponents(path)) {
|
|
103
|
-
add('primitive-in-component', `var(${name})`,
|
|
110
|
+
add('primitive-in-component', `var(${name})`, `A component reads semantic tokens, not a ramp step. Pick one by intent (accent.<state>.text, .fill or .ink): ${TOKEN_LIST}.`)
|
|
104
111
|
}
|
|
105
112
|
}
|
|
106
113
|
|
|
@@ -108,7 +115,7 @@ export function findViolations(text, path, tokenNames) {
|
|
|
108
115
|
// where a literal colour would be.
|
|
109
116
|
const rest = line.replace(/var\([^)]*\)/g, '')
|
|
110
117
|
for (const match of rest.matchAll(HEX)) {
|
|
111
|
-
add('raw-colour', match[0],
|
|
118
|
+
add('raw-colour', match[0], `Use a semantic token: text-[var(--color-text-primary)], bg-[var(--color-surface-base)]. Tokens and what each is for: ${TOKEN_LIST}.`)
|
|
112
119
|
}
|
|
113
120
|
for (const match of rest.matchAll(COLOR_FUNCTION)) {
|
|
114
121
|
add('raw-colour', match[0] + '…)', 'Use a semantic token. If no token fits, the colour is a change to the system: add it under tokens/ with a contrast pair.')
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Load when adding one component to a screen that already exists. Generated by `npm run agent-docs`; the procedure lives in scripts/lib/agent-docs.mjs.
|
|
4
4
|
|
|
5
|
-
Paths starting `public/` are in the Division DS repository. In a project that uses the components, read them online: `public/llms.txt` is `https://victor-ilioiu.vercel.app/systems/division-ds/llms.txt`, and so on.
|
|
5
|
+
Paths starting `public/` are in the Division DS repository. In a project that uses the components, read them online: `public/llms.txt` is `https://victor-ilioiu.vercel.app/systems/division-ds/llms.txt`, and so on. The other procedures named here (`commands/build.md` and the rest) are in the skill: `https://github.com/Victor-Ilioiu/division-ds/blob/main/skills/division-ds/commands/<name>.md`, or `npx division-ds skill` to install them.
|
|
6
6
|
|
|
7
7
|
1. Find it in `public/llms.txt`. Its "Best for" should describe your case and its "Not for"
|
|
8
8
|
should not; if "Not for" names your case, use the component it names instead.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Load when building a new screen or page. Plans the regions and their states before any code. Generated by `npm run agent-docs`; the procedure lives in scripts/lib/agent-docs.mjs.
|
|
4
4
|
|
|
5
|
-
Paths starting `public/` are in the Division DS repository. In a project that uses the components, read them online: `public/llms.txt` is `https://victor-ilioiu.vercel.app/systems/division-ds/llms.txt`, and so on.
|
|
5
|
+
Paths starting `public/` are in the Division DS repository. In a project that uses the components, read them online: `public/llms.txt` is `https://victor-ilioiu.vercel.app/systems/division-ds/llms.txt`, and so on. The other procedures named here (`commands/build.md` and the rest) are in the skill: `https://github.com/Victor-Ilioiu/division-ds/blob/main/skills/division-ds/commands/<name>.md`, or `npx division-ds skill` to install them.
|
|
6
6
|
|
|
7
7
|
Plan before code. The states a screen gets wrong are the ones nobody planned: an empty list
|
|
8
8
|
with no message, a load that fails into a blank panel, a button that is disabled with no reason.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Load when a gate, `division-ds check` or a test has failed and named a rule. What each message means and the fix. Generated by `npm run agent-docs`; the procedure lives in scripts/lib/agent-docs.mjs.
|
|
4
4
|
|
|
5
|
-
Paths starting `public/` are in the Division DS repository. In a project that uses the components, read them online: `public/llms.txt` is `https://victor-ilioiu.vercel.app/systems/division-ds/llms.txt`, and so on.
|
|
5
|
+
Paths starting `public/` are in the Division DS repository. In a project that uses the components, read them online: `public/llms.txt` is `https://victor-ilioiu.vercel.app/systems/division-ds/llms.txt`, and so on. The other procedures named here (`commands/build.md` and the rest) are in the skill: `https://github.com/Victor-Ilioiu/division-ds/blob/main/skills/division-ds/commands/<name>.md`, or `npx division-ds skill` to install them.
|
|
6
6
|
|
|
7
7
|
Every finding prints `path:line [rule] what was found` and a line saying what to write instead.
|
|
8
8
|
Do what that line says. Never silence a gate: no new EXEMPT entry, no `token-discipline: allow`
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
> Load when a screen is written and you are about to say it is done. The checklist to run over it. Generated by `npm run agent-docs`; the procedure lives in scripts/lib/agent-docs.mjs.
|
|
4
4
|
|
|
5
|
-
Paths starting `public/` are in the Division DS repository. In a project that uses the components, read them online: `public/llms.txt` is `https://victor-ilioiu.vercel.app/systems/division-ds/llms.txt`, and so on.
|
|
5
|
+
Paths starting `public/` are in the Division DS repository. In a project that uses the components, read them online: `public/llms.txt` is `https://victor-ilioiu.vercel.app/systems/division-ds/llms.txt`, and so on. The other procedures named here (`commands/build.md` and the rest) are in the skill: `https://github.com/Victor-Ilioiu/division-ds/blob/main/skills/division-ds/commands/<name>.md`, or `npx division-ds skill` to install them.
|
|
6
6
|
|
|
7
7
|
Go through every line. A line that does not hold is a change to make, not a note to leave.
|
|
8
8
|
|
|
9
|
-
- [ ] **States.** Every region has its empty, loading, error, success and disabled or no-permission state, as planned
|
|
9
|
+
- [ ] **States.** Every region has its empty, loading, error, success and disabled or no-permission state, as planned before the code (the regions-and-states plan of `commands/build.md`). An empty list says what is empty and offers the action that fills it.
|
|
10
10
|
- [ ] **Headings.** One `PageHeader`, so one `h1`. Section headings continue the outline: `h2` under the `h1`, `h3` inside an `h2`, no level skipped. `SectionHeading` is given the level.
|
|
11
11
|
- [ ] **Tokens only.** No hex, `rgb()`, palette class or invented token name. `division-ds check` passes.
|
|
12
12
|
- [ ] **Buttons.** Two or more side by side share a parent with a gap. One primary button per view. A busy button takes `loading`; a disabled one says why nearby. Icon-only actions are `IconButton` with a `label`.
|
|
@@ -4,4 +4,5 @@
|
|
|
4
4
|
|
|
5
5
|
**Assistant copy.** A button names the action ("Summarize"), never "AI". Say "response", not
|
|
6
6
|
"answer". No "please" or "!" in assistant labels. The interface says "Assistant"; only its own
|
|
7
|
-
messages say "I".
|
|
7
|
+
messages say "I". Response feedback: `ResponseFeedback` in `actions`.
|
|
8
|
+
A value the assistant filled is `aiValue` on that `Input` or `Textarea` only; leaving it accepts it.
|
|
@@ -10,6 +10,9 @@ bare and name it through its own `label` prop ("Role for Ilse Varga"). `Switch`,
|
|
|
10
10
|
renders `ErrorSummary` at the top and focuses it; `useFieldErrors` holds the state (signature in
|
|
11
11
|
`public/docs/helpers.md`).
|
|
12
12
|
|
|
13
|
+
A `RadioGroup` in a form sits in a `<fieldset>` whose `<legend>` names it (code on the Radio
|
|
14
|
+
page). A date is `<Input type="date">` in a `FormField`.
|
|
15
|
+
|
|
13
16
|
**Buttons.** Two or more buttons side by side need a parent with a gap
|
|
14
17
|
(`flex flex-wrap gap-3`); `DialogFooter` and `CardFooter` already are one. A `Button` is
|
|
15
18
|
`type="button"` unless you say `type="submit"`. A busy button takes `loading`, not `disabled`.
|
|
@@ -8,7 +8,9 @@ The shell paints the page background (`surface.base`) and supplies the gutter; a
|
|
|
8
8
|
own `max-w-*` and vertical spacing, and no page background. A form or an overlay is the
|
|
9
9
|
exception: it paints `surface.base` on itself, so its field colours never depend on what is
|
|
10
10
|
behind it. In a project that uses the components, your own root does this
|
|
11
|
-
(step 4 of `install.md`).
|
|
11
|
+
(step 4 of `install.md`). Toggle it with `setTheme()` from `src/lib/theme.ts`.
|
|
12
|
+
|
|
13
|
+
**App navigation.** A few views: `Navbar` (`current: true` on the open one). Many: `Sidebar`.
|
|
12
14
|
|
|
13
15
|
**Type.** Three families, as utilities: `font-display` (headings, figures), `font-body` (the
|
|
14
16
|
default, set by the shell), `font-mono` (labels, code, tabular numbers). A page title is
|
package/division-ds-0.2.0.tgz
DELETED
|
Binary file
|