@nanisoft/prism-llms 0.4.0 → 0.5.0
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/README.md +88 -0
- package/THIRD-PARTY-NOTICES.md +48 -0
- package/dist/data.json +3996 -387
- package/dist/demo-graph.d.ts +21 -12
- package/dist/demo-graph.js +37 -21
- package/dist/extractor.d.ts +24 -17
- package/dist/extractor.js +269 -153
- package/dist/index.d.ts +12 -7
- package/dist/index.js +9 -7
- package/dist/llms-full.txt +7968 -2013
- package/dist/llms.txt +97 -93
- package/dist/markdown.d.ts +69 -23
- package/dist/markdown.js +131 -72
- package/dist/md/blocks/app-shell-01.md +135 -0
- package/dist/md/blocks/auth-form-01.md +135 -0
- package/dist/md/blocks/cta-01.md +88 -0
- package/dist/md/blocks/data-table-01.md +196 -0
- package/dist/md/blocks/feature-grid-01.md +92 -0
- package/dist/md/blocks/hero-01.md +90 -0
- package/dist/md/blocks/instrument-panel-01.md +109 -0
- package/dist/md/blocks/logo-strip-01.md +97 -0
- package/dist/md/blocks/note-grid-01.md +102 -0
- package/dist/md/blocks/page-header-01.md +97 -0
- package/dist/md/blocks/pricing-01.md +91 -0
- package/dist/md/blocks/process-rail-01.md +106 -0
- package/dist/md/blocks/product-grid-01.md +113 -0
- package/dist/md/blocks/settings-panel-01.md +148 -0
- package/dist/md/blocks/site-footer.md +103 -11
- package/dist/md/blocks/site-header.md +111 -11
- package/dist/md/blocks/stack-grid-01.md +108 -0
- package/dist/md/blocks/stats-01.md +89 -0
- package/dist/md/blocks/status-ledger-01.md +121 -0
- package/dist/md/changelogs/prism-llms.md +206 -0
- package/dist/md/changelogs/prism-mcp-server.md +88 -0
- package/dist/md/changelogs/prism-tokens.md +126 -0
- package/dist/md/changelogs/prism-ui.md +429 -0
- package/dist/md/components/accordion.md +108 -0
- package/dist/md/components/alert.md +90 -7
- package/dist/md/components/avatar.md +89 -7
- package/dist/md/components/badge.md +74 -7
- package/dist/md/components/breadcrumb.md +84 -7
- package/dist/md/components/button.md +90 -7
- package/dist/md/components/card.md +90 -7
- package/dist/md/components/checkbox.md +101 -7
- package/dist/md/components/cta-link.md +98 -0
- package/dist/md/components/diagram.md +124 -0
- package/dist/md/components/dialog.md +128 -0
- package/dist/md/components/dropdown-menu.md +125 -0
- package/dist/md/components/fact-list.md +85 -0
- package/dist/md/components/field.md +116 -0
- package/dist/md/components/input.md +86 -7
- package/dist/md/components/kbd.md +77 -0
- package/dist/md/components/pagination.md +95 -7
- package/dist/md/components/popover.md +95 -7
- package/dist/md/components/product-mark.md +123 -0
- package/dist/md/components/product-switcher.md +88 -0
- package/dist/md/components/progress.md +88 -7
- package/dist/md/components/prose.md +91 -0
- package/dist/md/components/radio-group.md +111 -0
- package/dist/md/components/section.md +91 -0
- package/dist/md/components/select.md +143 -7
- package/dist/md/components/separator.md +77 -0
- package/dist/md/components/skeleton.md +71 -7
- package/dist/md/components/slider.md +90 -7
- package/dist/md/components/switch.md +104 -7
- package/dist/md/components/table.md +104 -7
- package/dist/md/components/tabs.md +105 -7
- package/dist/md/components/textarea.md +101 -0
- package/dist/md/components/tooltip.md +95 -7
- package/dist/md/components/typography.md +82 -7
- package/dist/md/content/about-content.md +36 -0
- package/dist/md/content/audience.md +43 -0
- package/dist/md/content/glossary.md +69 -0
- package/dist/md/content/product-vocabulary.md +53 -0
- package/dist/md/content/voice.md +52 -0
- package/dist/md/content/writing-mechanics.md +58 -0
- package/dist/md/foundation/colors.md +10 -0
- package/dist/md/foundation/iconography.md +14 -0
- package/dist/md/foundation/motion.md +10 -0
- package/dist/md/foundation/radii.md +9 -0
- package/dist/md/foundation/shadows.md +9 -0
- package/dist/md/foundation/spacings.md +8 -0
- package/dist/md/foundation/typography.md +9 -0
- package/dist/md/foundation/variables.md +9 -0
- package/dist/md/overview/architecture.md +76 -0
- package/dist/md/overview/brand.md +41 -0
- package/dist/md/overview/composition.md +77 -0
- package/dist/md/overview/quickstart.md +97 -0
- package/dist/md/overview/theming.md +89 -0
- package/dist/md/overview/using-llms.md +83 -0
- package/dist/md/pages/auth-page.md +149 -0
- package/dist/md/pages/blog-post-page.md +136 -0
- package/dist/md/pages/dashboard-page.md +241 -0
- package/dist/md/pages/marketing-page.md +199 -0
- package/dist/md/pages/not-found-page.md +105 -0
- package/dist/md/pages/settings-page.md +206 -0
- package/dist/prism-skill.md +50 -0
- package/dist/store.d.ts +203 -0
- package/dist/store.js +317 -0
- package/package.json +29 -26
- package/dist/demo-graph.d.ts.map +0 -1
- package/dist/demo-graph.js.map +0 -1
- package/dist/extractor.d.ts.map +0 -1
- package/dist/extractor.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/markdown.d.ts.map +0 -1
- package/dist/markdown.js.map +0 -1
- package/dist/md/blocks/component-demo.md +0 -19
- package/dist/md/blocks/page-header.md +0 -19
- package/dist/md/components/affix.md +0 -14
- package/dist/md/components/anchor.md +0 -14
- package/dist/md/components/auto-complete.md +0 -14
- package/dist/md/components/back-top.md +0 -14
- package/dist/md/components/border-beam.md +0 -14
- package/dist/md/components/calendar.md +0 -14
- package/dist/md/components/carousel.md +0 -14
- package/dist/md/components/cascader.md +0 -14
- package/dist/md/components/col.md +0 -14
- package/dist/md/components/collapse.md +0 -14
- package/dist/md/components/color-picker.md +0 -14
- package/dist/md/components/date-picker.md +0 -14
- package/dist/md/components/descriptions.md +0 -14
- package/dist/md/components/display-title.md +0 -20
- package/dist/md/components/divider.md +0 -14
- package/dist/md/components/drawer.md +0 -14
- package/dist/md/components/dropdown.md +0 -14
- package/dist/md/components/empty.md +0 -14
- package/dist/md/components/flex.md +0 -14
- package/dist/md/components/float-button.md +0 -14
- package/dist/md/components/form.md +0 -14
- package/dist/md/components/grid.md +0 -14
- package/dist/md/components/image.md +0 -14
- package/dist/md/components/input-number.md +0 -14
- package/dist/md/components/layout.md +0 -14
- package/dist/md/components/list.md +0 -14
- package/dist/md/components/listy.md +0 -14
- package/dist/md/components/masonry.md +0 -14
- package/dist/md/components/mentions.md +0 -14
- package/dist/md/components/menu.md +0 -14
- package/dist/md/components/modal.md +0 -14
- package/dist/md/components/popconfirm.md +0 -14
- package/dist/md/components/qrcode.md +0 -14
- package/dist/md/components/radio.md +0 -14
- package/dist/md/components/rate.md +0 -14
- package/dist/md/components/result.md +0 -14
- package/dist/md/components/row.md +0 -14
- package/dist/md/components/segmented.md +0 -14
- package/dist/md/components/space.md +0 -14
- package/dist/md/components/spin.md +0 -14
- package/dist/md/components/splitter.md +0 -14
- package/dist/md/components/statistic.md +0 -14
- package/dist/md/components/steps.md +0 -14
- package/dist/md/components/tag.md +0 -14
- package/dist/md/components/time-picker.md +0 -14
- package/dist/md/components/timeline.md +0 -14
- package/dist/md/components/tour.md +0 -14
- package/dist/md/components/transfer.md +0 -14
- package/dist/md/components/tree-select.md +0 -14
- package/dist/md/components/tree.md +0 -14
- package/dist/md/components/upload.md +0 -14
- package/dist/md/components/watermark.md +0 -14
- package/dist/md/docs/brand.md +0 -41
- package/dist/md/pages/blog-layout.md +0 -19
- package/dist/md/pages/docs-shell.md +0 -23
- package/dist/md/theme/blue-dark.md +0 -127
- package/dist/md/theme/blue-light.md +0 -129
- package/dist/md/theme/green-dark.md +0 -127
- package/dist/md/theme/green-light.md +0 -129
- package/dist/md/theme/lavender-dark.md +0 -127
- package/dist/md/theme/lavender-light.md +0 -129
- package/dist/md/theme/peach-dark.md +0 -127
- package/dist/md/theme/peach-light.md +0 -129
- package/dist/md/theme/rose-dark.md +0 -127
- package/dist/md/theme/rose-light.md +0 -129
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# ProcessRail01
|
|
2
|
+
|
|
3
|
+
A process drawn as a rail: two, three or four steps on one line, each with an ordinal, a name and one caption.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { ProcessRail01 } from '@nanisoft/prism-ui/blocks/process-rail-01'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
ProcessRail01 draws a process as a rail: the steps of a pipeline, in order, on
|
|
12
|
+
one line, each with an ordinal, a name and one caption.
|
|
13
|
+
|
|
14
|
+
All four NaniSoft sites compose this section, and each one drew it by hand with
|
|
15
|
+
the same three parts: an ordinal per step, a name, and one caption per step,
|
|
16
|
+
separated by hairlines with a label on the last one. This is that section once,
|
|
17
|
+
with the ordinal and the separation owned here rather than by four sets of site
|
|
18
|
+
CSS.
|
|
19
|
+
|
|
20
|
+
**The rail admits four steps and refuses five, in the type.** `steps` is a tuple
|
|
21
|
+
union rather than an array, so a fifth element is a compile error and not a fifth
|
|
22
|
+
column. The reason is that a rail is a claim about a sequence, and a rail that
|
|
23
|
+
quietly dropped a step to fit a width would be a diagram of a process that is not
|
|
24
|
+
the process. Four is the number every one of the four sites actually states; a
|
|
25
|
+
longer process is a different shape and earns its own Block.
|
|
26
|
+
|
|
27
|
+
## Guidelines
|
|
28
|
+
|
|
29
|
+
### When to use
|
|
30
|
+
|
|
31
|
+
Use ProcessRail01 for a process with two to four steps where each step is one
|
|
32
|
+
name and one line: a data path, a build pipeline, a review loop.
|
|
33
|
+
|
|
34
|
+
Use it when the order is the point. A set of independent features is a
|
|
35
|
+
`FeatureGrid01`, and a set of stages that do not run in sequence is a set.
|
|
36
|
+
|
|
37
|
+
### When not to use
|
|
38
|
+
|
|
39
|
+
Do not use it for a process of five or more steps. It will not compile. That is
|
|
40
|
+
the design: a rail this wide stops reading as a line, and a longer process wants a
|
|
41
|
+
numbered list, which is a `Prose` and not a rail.
|
|
42
|
+
|
|
43
|
+
Do not use it for two steps that are really a before and an after. A rail with
|
|
44
|
+
two columns is two columns, and `NoteGrid01` says the same thing with less
|
|
45
|
+
ceremony.
|
|
46
|
+
|
|
47
|
+
### Best practices
|
|
48
|
+
|
|
49
|
+
- Keep each caption to about twelve words. A caption that wraps under its step and
|
|
50
|
+
the row stops reading as a line; the detail belongs above the rail in
|
|
51
|
+
`description`.
|
|
52
|
+
- Pass `finalLabel` only when the rail genuinely ends in a state worth naming.
|
|
53
|
+
"serving", "merged" and "verified" are claims; a rail that has not finished
|
|
54
|
+
should say nothing.
|
|
55
|
+
- Leave `title` out when the rail is composed under a heading the page already
|
|
56
|
+
owns.
|
|
57
|
+
|
|
58
|
+
### Content guidelines
|
|
59
|
+
|
|
60
|
+
- Name a step the way you would name it in conversation: a verb or a short noun
|
|
61
|
+
phrase, not a sentence.
|
|
62
|
+
- Write the caption as what happens, not as why it matters. The why belongs in
|
|
63
|
+
`description`.
|
|
64
|
+
- Do not number the steps yourself. The ordinal is rendered from the position, so
|
|
65
|
+
a list that carries its own numbers can disagree with its own order after a
|
|
66
|
+
sort.
|
|
67
|
+
|
|
68
|
+
**Four steps on one line, with the label on the last one.**
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
import { ProcessRail01 } from '@nanisoft/prism-ui/blocks/process-rail-01'
|
|
72
|
+
|
|
73
|
+
/** Four steps on one line, with the label on the last one. */
|
|
74
|
+
export default function ProcessRail01Demo() {
|
|
75
|
+
return (
|
|
76
|
+
<ProcessRail01
|
|
77
|
+
headingLevel="h3"
|
|
78
|
+
eyebrow="Preview"
|
|
79
|
+
title="The data path"
|
|
80
|
+
description="One line about the whole path, above the rail rather than inside it."
|
|
81
|
+
finalLabel="serving"
|
|
82
|
+
steps={[
|
|
83
|
+
{ name: 'Collect', description: 'The whole surface, every minute.' },
|
|
84
|
+
{ name: 'Conform', description: 'One timestamp, one symbol form.' },
|
|
85
|
+
{ name: 'Verify', description: 'The column list held by test.' },
|
|
86
|
+
{ name: 'Serve', description: 'One queryable view.' },
|
|
87
|
+
]}
|
|
88
|
+
/>
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Props
|
|
94
|
+
|
|
95
|
+
**`eyebrow`** `string` · optional · default: — — Optional label above the section title. See the No-Default-Eyebrow Rule.
|
|
96
|
+
**`title`** `string` · optional · default: — — The section title. Omit it for a rail that is composed under its own heading.
|
|
97
|
+
**`description`** `string` · optional · default: — — One or two sentences under the title.
|
|
98
|
+
**`finalLabel`** `string` · optional · default: — — The label on the last step, for a rail that ends in a state worth naming: "serving", "merged", "verified". Omit it when the last step needs no label, which is the honest state for a rail that has not finished.
|
|
99
|
+
**`steps`** `ProcessRail01Steps` · required · default: — — The steps, in the order the process runs. Two, three or four; a fifth is a type error. See `ProcessRail01Steps`.
|
|
100
|
+
**`headingLevel`** `HeadingLevel` · optional · default: — — Heading level for the section title. See `HeadingLevel`.
|
|
101
|
+
|
|
102
|
+
## Composition
|
|
103
|
+
|
|
104
|
+
**`exports`** `ProcessRail01` — the public runtime names this Block promises
|
|
105
|
+
**`source`** `packages/ui/src/blocks/process-rail-01/index.tsx` — the file this Block is defined in
|
|
106
|
+
**`dependencies`** `Section` — the public Prism exports this item composes
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# ProductGrid01
|
|
2
|
+
|
|
3
|
+
A set of products as hairline rows: a two-part ProductMark, a name, one tagline and a destination per row.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { ProductGrid01 } from '@nanisoft/prism-ui/blocks/product-grid-01'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
ProductGrid01 is a set of products as a stack of hairline rows: a two-part mark, a
|
|
12
|
+
name, one tagline and a destination per row.
|
|
13
|
+
|
|
14
|
+
All four NaniSoft sites publish this section, and each one drew it by hand with
|
|
15
|
+
the same three parts in the same order: a colour mark for the product, the
|
|
16
|
+
product's name, and one line about what it is, on a hairline row with the whole
|
|
17
|
+
row a link. Each site also resolved the mark's ink in JavaScript from the live
|
|
18
|
+
mode, which is the part that is a second source of truth.
|
|
19
|
+
|
|
20
|
+
**The mark is two parts, and it is `ProductMark`.** The ring is `brand-ink` and
|
|
21
|
+
the core is the product's own `primary`, with the name in the brand ink beside it.
|
|
22
|
+
That split is settled by a measurement rather than by taste: a pastel brand value
|
|
23
|
+
is a fill and never text, so the core may be `primary` and the name may not, and a
|
|
24
|
+
*filled* mark on a light card measures under the threshold a mark has to clear, so
|
|
25
|
+
the mark is a hairline ring around the fill rather than a disc of it.
|
|
26
|
+
|
|
27
|
+
## Guidelines
|
|
28
|
+
|
|
29
|
+
### When to use
|
|
30
|
+
|
|
31
|
+
Use ProductGrid01 where the reader's question is "which of these should I open".
|
|
32
|
+
That is a family of products, a set of integrations, a set of sibling sites.
|
|
33
|
+
|
|
34
|
+
Use it when each member is one line long. A member that needs a paragraph is a
|
|
35
|
+
`FeatureGrid01` card, and a paragraph in a row makes the row a column of
|
|
36
|
+
paragraphs.
|
|
37
|
+
|
|
38
|
+
### When not to use
|
|
39
|
+
|
|
40
|
+
Do not use it for a set of things that are not navigable. A grid of capabilities
|
|
41
|
+
is a `FeatureGrid01`; there is nothing to click, and a row that pretends to be a
|
|
42
|
+
link teaches a reader that everything on a page is.
|
|
43
|
+
|
|
44
|
+
Do not use it for two members. Two products side by side is a hero with two
|
|
45
|
+
things in it, and a hairline list of two is a list.
|
|
46
|
+
|
|
47
|
+
### Best practices
|
|
48
|
+
|
|
49
|
+
- Order the rows by how likely a reader is to want each one. Order is a claim and
|
|
50
|
+
it is yours.
|
|
51
|
+
- Pass `newTab` per row rather than globally. Prism does not decide what counts as
|
|
52
|
+
external, and a same-site link that opens a tab is a reader who has lost the
|
|
53
|
+
page.
|
|
54
|
+
- Leave `pack` off the one member that has no pack of its own. That member wears
|
|
55
|
+
the spectrum.
|
|
56
|
+
- Use one mark size across the grid. The grid passes one size to every mark, so a
|
|
57
|
+
mixed set is not reachable from here.
|
|
58
|
+
|
|
59
|
+
### Content guidelines
|
|
60
|
+
|
|
61
|
+
- Keep a tagline to one line. It is what a reader scans.
|
|
62
|
+
- Write the tagline as what the product is, not as what it does for the reader.
|
|
63
|
+
- Use the product's own name, in the case it uses everywhere else.
|
|
64
|
+
|
|
65
|
+
**Two members, one wearing a pack and one wearing the spectrum.**
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
import { ProductGrid01 } from '@nanisoft/prism-ui/blocks/product-grid-01'
|
|
69
|
+
|
|
70
|
+
/** Two members, one wearing a pack and one wearing the spectrum. */
|
|
71
|
+
export default function ProductGrid01Demo() {
|
|
72
|
+
return (
|
|
73
|
+
<ProductGrid01
|
|
74
|
+
headingLevel="h3"
|
|
75
|
+
eyebrow="Preview"
|
|
76
|
+
title="Built on one platform"
|
|
77
|
+
description="One line about the set, above the rows rather than inside one."
|
|
78
|
+
caption="The company root has no pack of its own, so its mark wears the spectrum."
|
|
79
|
+
products={[
|
|
80
|
+
{
|
|
81
|
+
id: 'nexus',
|
|
82
|
+
name: 'Nexus',
|
|
83
|
+
pack: 'lavender',
|
|
84
|
+
tagline: 'The agent factory: an issue in, a reviewed change out.',
|
|
85
|
+
href: '#nexus',
|
|
86
|
+
},
|
|
87
|
+
{ id: 'www', name: 'NaniSoft', tagline: 'The company behind the platform.', href: '#www' },
|
|
88
|
+
]}
|
|
89
|
+
/>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Props
|
|
95
|
+
|
|
96
|
+
**`eyebrow`** `string` · optional · default: — — Optional label above the section title. See the No-Default-Eyebrow Rule.
|
|
97
|
+
**`title`** `string` · optional · default: — — The section title. Omit it for a grid composed under its own heading.
|
|
98
|
+
**`description`** `string` · optional · default: — — One or two sentences under the title.
|
|
99
|
+
**`products`** `readonly ProductGrid01Product[]` · required · default: — — The products, in the order a reader should meet them. Order is the caller's because it is a claim about which product matters first.
|
|
100
|
+
**`caption`** `string` · optional · default: — — The line under the grid, for the sentence that qualifies it: what the set does not include, or where to read more.
|
|
101
|
+
**`headingLevel`** `HeadingLevel` · optional · default: — — Heading level for the section title. See `HeadingLevel`.
|
|
102
|
+
**`id`** `string` · required · default: — — The product's key within the set. Carried on the markup as `data-product` through `ProductMark`, so a test can name one product rather than the first one, and two products in one document are individually addressable.
|
|
103
|
+
**`name`** `string` · required · default: — — The product's own name, which is the second part of its mark. It is the anchor of the row and the first thing a reader reads.
|
|
104
|
+
**`pack`** `ProductMarkProps['pack']` · optional · default: — — The product's pack, which is the hue of the mark's core. Omit it, or pass `null`, for the one member of a set that has no pack of its own: that member wears the full spectrum rather than a colourless mark.
|
|
105
|
+
**`tagline`** `string` · required · default: — — One line about what the product is.
|
|
106
|
+
**`href`** `string` · required · default: — — Where the row goes. Rendered as a native anchor's `href`, so the row is a link with the browser's own affordances rather than a click handler.
|
|
107
|
+
**`newTab`** `boolean` · optional · default: — — Opens the destination in a new browsing context, which defaults the link relationship to `noopener noreferrer`. Prism does not decide what counts as external, so the caller declares it.
|
|
108
|
+
|
|
109
|
+
## Composition
|
|
110
|
+
|
|
111
|
+
**`exports`** `ProductGrid01` — the public runtime names this Block promises
|
|
112
|
+
**`source`** `packages/ui/src/blocks/product-grid-01/index.tsx` — the file this Block is defined in
|
|
113
|
+
**`dependencies`** `ProductMark, Section` — the public Prism exports this item composes
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# SettingsPanel01
|
|
2
|
+
|
|
3
|
+
A settings form grouped into sections of text, select and switch fields.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { SettingsPanel01 } from '@nanisoft/prism-ui/blocks/settings-panel-01'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
SettingsPanel01 is a settings form grouped into named sections. The card holds
|
|
12
|
+
the title and description, each section holds a heading and its fields, and the
|
|
13
|
+
footer holds the save and cancel controls, with a rule between sections.
|
|
14
|
+
|
|
15
|
+
The block composes these components:
|
|
16
|
+
|
|
17
|
+
| Part | Component | Role |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| Surface | Card, Separator | the panel and the rule between sections |
|
|
20
|
+
| Fields | Field, Input, Textarea | labelled text controls |
|
|
21
|
+
| Choices | Select, Switch | one-of-many and on-or-off fields |
|
|
22
|
+
| Footer | Button | the save and secondary actions |
|
|
23
|
+
|
|
24
|
+
A field is a small object that describes one control: its `kind`, its label, an
|
|
25
|
+
optional description and its value handlers. The block owns no values and no
|
|
26
|
+
copy. Omitting `submitLabel` renders no footer, the right shape for a read-only
|
|
27
|
+
view.
|
|
28
|
+
|
|
29
|
+
## Guidelines
|
|
30
|
+
|
|
31
|
+
### When to use
|
|
32
|
+
|
|
33
|
+
Use SettingsPanel01 when a screen changes several settings that share one save.
|
|
34
|
+
It works when the groups are stable and a reader scans them top to bottom.
|
|
35
|
+
|
|
36
|
+
### When not to use
|
|
37
|
+
|
|
38
|
+
Do not use it for a single setting. One field in a card is a heavier frame than
|
|
39
|
+
the choice deserves; put the control in the page.
|
|
40
|
+
|
|
41
|
+
Do not use it when each change should apply immediately with no save. A switch
|
|
42
|
+
inside a saved form reads as applied; use standalone switches with their own
|
|
43
|
+
handler instead.
|
|
44
|
+
|
|
45
|
+
### Best practices
|
|
46
|
+
|
|
47
|
+
- Give every field a stable `id`, so the label is linked to the control.
|
|
48
|
+
- Keep one save per panel. A mixed model, where some fields save and others do
|
|
49
|
+
not, makes the footer's promise unclear.
|
|
50
|
+
- Put the consequential choice first in its section, so a reader does not hunt
|
|
51
|
+
for the setting that matters most.
|
|
52
|
+
- Disable the submit control while a save is in flight.
|
|
53
|
+
|
|
54
|
+
### Content guidelines
|
|
55
|
+
|
|
56
|
+
- A section title is one or two words in sentence case: "General",
|
|
57
|
+
"Notifications".
|
|
58
|
+
- A field label is a short noun phrase and does not end in a colon.
|
|
59
|
+
|
|
60
|
+
**A grouped settings form with text, select and switch fields.**
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
'use client'
|
|
64
|
+
|
|
65
|
+
import { SettingsPanel01 } from '@nanisoft/prism-ui/blocks/settings-panel-01'
|
|
66
|
+
|
|
67
|
+
/** A grouped settings form with text, select and switch fields. */
|
|
68
|
+
export default function SettingsPanel01Demo() {
|
|
69
|
+
return (
|
|
70
|
+
<SettingsPanel01
|
|
71
|
+
title="Workspace settings"
|
|
72
|
+
description="Manage how this workspace behaves for everyone on the team."
|
|
73
|
+
submitLabel="Save changes"
|
|
74
|
+
secondaryAction={{ label: 'Cancel' }}
|
|
75
|
+
sections={[
|
|
76
|
+
{
|
|
77
|
+
id: 'general',
|
|
78
|
+
title: 'General',
|
|
79
|
+
description: 'Shown to everyone you collaborate with.',
|
|
80
|
+
fields: [
|
|
81
|
+
{
|
|
82
|
+
kind: 'text',
|
|
83
|
+
id: 'workspace-name',
|
|
84
|
+
label: 'Workspace name',
|
|
85
|
+
defaultValue: 'Northwind',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
kind: 'textarea',
|
|
89
|
+
id: 'workspace-description',
|
|
90
|
+
label: 'Description',
|
|
91
|
+
placeholder: 'What does this workspace do?',
|
|
92
|
+
rows: 3,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
kind: 'select',
|
|
96
|
+
id: 'workspace-region',
|
|
97
|
+
label: 'Data region',
|
|
98
|
+
placeholder: 'Choose a region',
|
|
99
|
+
defaultValue: 'eu-west',
|
|
100
|
+
options: [
|
|
101
|
+
{ label: 'Europe West', value: 'eu-west' },
|
|
102
|
+
{ label: 'US East', value: 'us-east' },
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
id: 'notifications',
|
|
109
|
+
title: 'Notifications',
|
|
110
|
+
fields: [
|
|
111
|
+
{
|
|
112
|
+
kind: 'switch',
|
|
113
|
+
id: 'weekly-digest',
|
|
114
|
+
label: 'Weekly digest',
|
|
115
|
+
description: 'A summary of activity every Monday.',
|
|
116
|
+
defaultChecked: true,
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
kind: 'switch',
|
|
120
|
+
id: 'mention-alerts',
|
|
121
|
+
label: 'Mention alerts',
|
|
122
|
+
description: 'Notify me when someone mentions my name.',
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
},
|
|
126
|
+
]}
|
|
127
|
+
/>
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Props
|
|
133
|
+
|
|
134
|
+
**`title`** `string` · required · default: —
|
|
135
|
+
**`description`** `string` · optional · default: —
|
|
136
|
+
**`sections`** `SettingsPanelSection[]` · required · default: — — The settings groups, each rendered with a heading and its own fields.
|
|
137
|
+
**`submitLabel`** `string` · optional · default: — — The submit button label. Omit to render no footer.
|
|
138
|
+
**`onSubmit`** `(event: FormEvent<HTMLFormElement>) => void` · optional · default: —
|
|
139
|
+
**`secondaryAction`** `{ label: string; onClick?: () => void; }` · optional · default: — — A secondary control, such as Cancel.
|
|
140
|
+
**`footer`** `ReactNode` · optional · default: — — Extra content in the footer, e.g. a status note.
|
|
141
|
+
**`label`** `string` · required · default: —
|
|
142
|
+
**`onClick`** `() => void` · optional · default: —
|
|
143
|
+
|
|
144
|
+
## Composition
|
|
145
|
+
|
|
146
|
+
**`exports`** `SettingsPanel01` — the public runtime names this Block promises
|
|
147
|
+
**`source`** `packages/ui/src/blocks/settings-panel-01/index.tsx` — the file this Block is defined in
|
|
148
|
+
**`dependencies`** `Button, Card, Field, Input, Select, Separator, Switch, Textarea` — the public Prism exports this item composes
|
|
@@ -1,19 +1,111 @@
|
|
|
1
1
|
# SiteFooter
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The block at the foot of a product site: a brand lockup, grouped destinations, the links that leave the site and a slot for the legal line.
|
|
4
4
|
|
|
5
|
-
```
|
|
6
|
-
import { SiteFooter } from '@nanisoft/prism-ui/blocks'
|
|
5
|
+
```tsx
|
|
6
|
+
import { SiteFooter } from '@nanisoft/prism-ui/blocks/site-footer'
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
SiteFooter is the block at the foot of a product site: a brand lockup, grouped
|
|
12
|
+
destinations, the links that leave the site, and an optional slot for the legal
|
|
13
|
+
line.
|
|
14
|
+
|
|
15
|
+
All four NaniSoft sites compose this exact footer in their root layout, and each
|
|
16
|
+
one wrote its own column model, its own mark and its own current-page treatment.
|
|
17
|
+
|
|
18
|
+
Every string is a prop and the block ships none. There is no site name, no
|
|
19
|
+
copyright, no year, no "built with" line and no default column: a footer that
|
|
20
|
+
hardcoded any of them would hand every consumer a claim about a product that is
|
|
21
|
+
not theirs and a year that was not this one.
|
|
22
|
+
|
|
23
|
+
## Guidelines
|
|
24
|
+
|
|
25
|
+
### When to use
|
|
26
|
+
|
|
27
|
+
Use SiteFooter as the chrome at the foot of a whole product site, in the root
|
|
28
|
+
layout, below the main region.
|
|
29
|
+
|
|
30
|
+
Use it wherever there are destinations a reader might otherwise not find: the
|
|
31
|
+
documentation, the blog, the repository, the company site.
|
|
32
|
+
|
|
33
|
+
### When not to use
|
|
34
|
+
|
|
35
|
+
Do not use it inside an application screen. `AppShell01` owns a signed-in shell
|
|
36
|
+
and its own foot.
|
|
37
|
+
|
|
38
|
+
Do not use it for a single link. A footer with one destination is a link with a
|
|
39
|
+
large margin around it.
|
|
40
|
+
|
|
41
|
+
### Best practices
|
|
42
|
+
|
|
43
|
+
- Group by what the links are, and name each group. Each column is its own
|
|
44
|
+
navigation region named by its title, so a reader navigating by landmark reaches
|
|
45
|
+
"Documentation" rather than one anonymous list of links.
|
|
46
|
+
- The columns collapse to one column on a narrow viewport, and a footer read as
|
|
47
|
+
three unreadable columns on a phone is three columns nobody reads. Group what
|
|
48
|
+
belongs together before you split it into columns.
|
|
49
|
+
- **Links that leave the site open in a new tab by default**, because a link that
|
|
50
|
+
leaves and comes back is a reader who has lost the page they were on. Pass
|
|
51
|
+
`newTab={false}` on one link to override it: Prism does not decide which
|
|
52
|
+
destinations are external, so the per-link prop wins.
|
|
53
|
+
- Put a social icon in `icon`. It is `aria-hidden`, so the label is announced once
|
|
54
|
+
rather than twice.
|
|
55
|
+
- Use `legal` for the copyright, the licence or the version. It is a slot because
|
|
56
|
+
every one of those is a fact about a specific product and about the year it was
|
|
57
|
+
published, and a block that held a year would be a block that went stale.
|
|
58
|
+
|
|
59
|
+
### Content guidelines
|
|
60
|
+
|
|
61
|
+
- Keep a link label to one or two words. A footer is scanned.
|
|
62
|
+
- Name a column after what the links in it are, not after where they live.
|
|
63
|
+
- Keep the social labels the same words a reader would use for the destination.
|
|
64
|
+
|
|
65
|
+
**The site chrome: a brand lockup, grouped destinations, a social link and a legal slot.**
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
import { SiteFooter } from '@nanisoft/prism-ui/blocks/site-footer'
|
|
69
|
+
|
|
70
|
+
/** The site chrome: a brand lockup, grouped destinations, a social link and a legal slot. */
|
|
71
|
+
export default function SiteFooterDemo() {
|
|
72
|
+
return (
|
|
73
|
+
<SiteFooter
|
|
74
|
+
product={{ id: 'nexus', name: 'Nexus', pack: 'lavender' }}
|
|
75
|
+
columns={[
|
|
76
|
+
{
|
|
77
|
+
title: 'Site',
|
|
78
|
+
links: [
|
|
79
|
+
{ label: 'Landing', href: '#landing' },
|
|
80
|
+
{ label: 'Docs', href: '#docs' },
|
|
81
|
+
{ label: 'Blog', href: '#blog' },
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
title: 'Elsewhere',
|
|
86
|
+
links: [
|
|
87
|
+
{ label: 'GitHub', href: '#github' },
|
|
88
|
+
{ label: 'nanisoft.com', href: '#company', newTab: true },
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
]}
|
|
92
|
+
social={[{ label: 'GitHub', href: '#github' }]}
|
|
93
|
+
legal={<span>2026 NaniSoft. One design language, five sites.</span>}
|
|
94
|
+
/>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
```
|
|
10
98
|
|
|
11
99
|
## Props
|
|
12
100
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
101
|
+
**`product`** `Pick<ProductMarkProps, 'id' | 'name' | 'pack'>` · required · default: — — The product this footer belongs to: the id, name and pack its `ProductMark` is drawn from. The footer renders the mark rather than taking a slot, because the brand lockup is the one part of a footer that is never product-specific and every consumer would otherwise reimplement it.
|
|
102
|
+
**`columns`** `readonly SiteFooterColumn[]` · optional · default: — — The groups of destinations: the sections of this site, its documentation, and anywhere else the site sends a reader. Omit it for a footer that carries only the brand lockup.
|
|
103
|
+
**`social`** `readonly SiteFooterSocial[]` · optional · default: — — The links that leave the site. A `ReactNode` icon is drawn beside each label and hidden from assistive technology, so a screen reader announces the label once.
|
|
104
|
+
**`legal`** `ReactNode` · optional · default: — — A slot for the line at the foot of the footer: a copyright, a licence, a version, a legal link. A slot rather than a prop, because every one of those is a fact about a specific product and about the year it was published, and a Block that held a year would be a Block that went stale.
|
|
105
|
+
**`className`** `string` · optional · default: — — Layout only, exactly as on every Component. Changing a Prism-owned visual property from here is prohibited.
|
|
106
|
+
|
|
107
|
+
## Composition
|
|
108
|
+
|
|
109
|
+
**`exports`** `SiteFooter` — the public runtime names this Block promises
|
|
110
|
+
**`source`** `packages/ui/src/blocks/site-footer/index.tsx` — the file this Block is defined in
|
|
111
|
+
**`dependencies`** `ProductMark` — the public Prism exports this item composes
|
|
@@ -1,19 +1,119 @@
|
|
|
1
1
|
# SiteHeader
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The bar at the top of a product site: a brand lockup, an optional product switcher, the site navigation and a slot for application controls.
|
|
4
4
|
|
|
5
|
-
```
|
|
6
|
-
import { SiteHeader } from '@nanisoft/prism-ui/blocks'
|
|
5
|
+
```tsx
|
|
6
|
+
import { SiteHeader } from '@nanisoft/prism-ui/blocks/site-header'
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
SiteHeader is the bar at the top of a product site: a brand lockup, an optional
|
|
12
|
+
product switcher, the site's own navigation, and a slot for the controls your
|
|
13
|
+
product owns.
|
|
14
|
+
|
|
15
|
+
All four NaniSoft sites compose this exact bar in their root layout, and each one
|
|
16
|
+
wrote its own: the mark in one place, the switcher in a popover in another, the
|
|
17
|
+
navigation in a third, and each wrote the focus and current-page wiring separately.
|
|
18
|
+
|
|
19
|
+
It is a Block and not a Component because it is a region of a page rather than a
|
|
20
|
+
control: it composes a `ProductMark`, a `ProductSwitcher` and a set of links, and
|
|
21
|
+
it owns the bar they sit in.
|
|
22
|
+
|
|
23
|
+
**There is no product directory in this package.** The product is passed as the
|
|
24
|
+
three facts its mark is drawn from rather than as an id this package would have to
|
|
25
|
+
resolve. That is the same answer `ProductMark` gives, and for the same reason: a
|
|
26
|
+
consumer that composes a set of its own products composes the header too.
|
|
27
|
+
|
|
28
|
+
## Guidelines
|
|
29
|
+
|
|
30
|
+
### When to use
|
|
31
|
+
|
|
32
|
+
Use SiteHeader as the chrome around a whole product site. One header per site, in
|
|
33
|
+
the root layout, above the main region.
|
|
34
|
+
|
|
35
|
+
Use it on the landing page and on every documentation and blog page alike. A
|
|
36
|
+
header that changes between sections of one site is two sites' worth of chrome.
|
|
37
|
+
|
|
38
|
+
### When not to use
|
|
39
|
+
|
|
40
|
+
Do not use it inside an application screen. `AppShell01` is that: a rail, a top
|
|
41
|
+
bar and a mobile sheet, for signed-in state rather than for a public site.
|
|
42
|
+
|
|
43
|
+
Do not use it for a product site's in-page navigation. That is a `Tabs` or a
|
|
44
|
+
`Breadcrumb`.
|
|
45
|
+
|
|
46
|
+
### Best practices
|
|
47
|
+
|
|
48
|
+
- Pass `product`, and pass `products` only when the site is one of several. A set
|
|
49
|
+
of one renders one mark, so pass nothing rather than a switcher with a single
|
|
50
|
+
member.
|
|
51
|
+
- Mark the current page with `current` on the one link whose destination is the
|
|
52
|
+
current route. The header marks it with `aria-current="page"`; it does not colour
|
|
53
|
+
it, because a colour is not a state a screen reader can read.
|
|
54
|
+
- `navLabel` and `productsLabel` are required, because they are words a reader
|
|
55
|
+
hears. A Block that ships no copy ships no reader-facing copy either, so the name
|
|
56
|
+
of your own landmarks is yours to pass.
|
|
57
|
+
- Put interactive controls in `actions`. It is a slot rather than a prop, because
|
|
58
|
+
an account menu, a sign-in link and a mode toggle are all application state and
|
|
59
|
+
none of them is a fact a header can be told.
|
|
60
|
+
- Use `sticky` only where the page scrolls. A sticky header on a page with no
|
|
61
|
+
scroll costs the reader a strip of viewport for nothing.
|
|
62
|
+
- The bar is one flex row that wraps. The switcher and the navigation wrap onto a
|
|
63
|
+
second line rather than overflowing, so a narrow viewport gets a taller header
|
|
64
|
+
and never a clipped one.
|
|
65
|
+
|
|
66
|
+
### Content guidelines
|
|
67
|
+
|
|
68
|
+
- Keep a nav label to one word. It is a bar.
|
|
69
|
+
- Use each product's own name in the lockup, in the case it uses everywhere else.
|
|
70
|
+
- Order the nav by how often a reader goes there, not alphabetically.
|
|
71
|
+
|
|
72
|
+
**The site chrome: a brand lockup, the product set, the site nav and a slot.**
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { SiteHeader } from '@nanisoft/prism-ui/blocks/site-header'
|
|
76
|
+
|
|
77
|
+
/** The site chrome: a brand lockup, the product set, the site nav and a slot. */
|
|
78
|
+
export default function SiteHeaderDemo() {
|
|
79
|
+
return (
|
|
80
|
+
<SiteHeader
|
|
81
|
+
product={{ id: 'nexus', name: 'Nexus', pack: 'lavender' }}
|
|
82
|
+
navLabel="Site"
|
|
83
|
+
productsLabel="Products"
|
|
84
|
+
products={[
|
|
85
|
+
{ id: 'nexus', name: 'Nexus', pack: 'lavender', href: '#nexus' },
|
|
86
|
+
{ id: 'atlas', name: 'Atlas', pack: 'mint', href: '#atlas' },
|
|
87
|
+
{ id: 'alphalens', name: 'AlphaLens', pack: 'blush', href: '#alphalens' },
|
|
88
|
+
]}
|
|
89
|
+
nav={[
|
|
90
|
+
{ label: 'Docs', href: '#docs' },
|
|
91
|
+
{ label: 'Blog', href: '#blog' },
|
|
92
|
+
{ label: 'About', href: '#about', current: true },
|
|
93
|
+
]}
|
|
94
|
+
actions={<span className="text-muted-foreground text-xs">A control you own</span>}
|
|
95
|
+
/>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
```
|
|
10
99
|
|
|
11
100
|
## Props
|
|
12
101
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
102
|
+
**`product`** `Pick<ProductMarkProps, 'id' | 'name' | 'pack'>` · required · default: — — The product this header belongs to: the id, name and pack its `ProductMark` is drawn from. The header renders the mark itself rather than a slot, because a header whose brand lockup is a slot is a header every consumer has to reimplement, and that is the one part of a site header that is never product-specific.
|
|
103
|
+
**`products`** `readonly SwitcherProduct[]` · optional · default: — — The set of products to move between, rendered as a `ProductSwitcher` between the mark and the navigation. Omit it on a site that is the only product, and pass it on a site that is one of several. A set of one renders one mark, so pass nothing rather than a switcher with a single member.
|
|
104
|
+
**`nav`** `readonly SiteHeaderLink[]` · optional · default: — — The header's own destinations: the sections of this site. Omit it for a header that carries only the brand lockup.
|
|
105
|
+
**`navLabel`** `string` · required · default: — — The accessible name of the site navigation, which is also the visible word a screen reader announces before the list. It is required rather than defaulted because it is a word a reader hears, and a Block that ships no copy ships no reader-facing copy either. A header that defaulted this would put its own name on every consumer's site navigation, and "Site" is right for a company site and wrong for a product that has a docs section it wants called something else.
|
|
106
|
+
**`productsLabel`** `string` · optional · default: — — The accessible name of the product switcher. Required whenever `products` is passed, for the same reason `navLabel` is: it is a word a reader hears, and a Block that ships no copy ships none of those either. Omit it and the switcher takes the site navigation's name, which is right when the two are the same set of places and wrong when they are not.
|
|
107
|
+
**`actions`** `ReactNode` · optional · default: — — A slot for the controls a product owns on the right: an account menu, a sign in link, a mode toggle, a theme picker. A slot rather than a prop, because every one of those is application state and none of them is a fact a header can be told.
|
|
108
|
+
**`sticky`** `boolean` · optional · default: — — Keeps the header at the top of the viewport as the page scrolls. Off by default, because a sticky header is a decision about a page rather than about a header, and a header that is sticky on a page with no scroll costs the reader a strip of their viewport.
|
|
109
|
+
**`className`** `string` · optional · default: — — Layout only, exactly as on every Component. Changing a Prism-owned visual property from here is prohibited.
|
|
110
|
+
**`label`** `string` · required · default: — — The text of the link.
|
|
111
|
+
**`href`** `string` · required · default: — — Where the link goes.
|
|
112
|
+
**`current`** `boolean` · optional · default: — — Marks this link as the page the reader is on. Set it on the one link whose destination is the current route; leave it off every other link.
|
|
113
|
+
**`newTab`** `boolean` · optional · default: — — Opens the destination in a new browsing context, which defaults the link relationship to `noopener noreferrer`. Prism does not decide what counts as external: a cross-origin destination is not by itself a reason to open a tab.
|
|
114
|
+
|
|
115
|
+
## Composition
|
|
116
|
+
|
|
117
|
+
**`exports`** `SiteHeader` — the public runtime names this Block promises
|
|
118
|
+
**`source`** `packages/ui/src/blocks/site-header/index.tsx` — the file this Block is defined in
|
|
119
|
+
**`dependencies`** `ProductMark, ProductSwitcher` — the public Prism exports this item composes
|