@nanisoft/prism-llms 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.
Files changed (175) hide show
  1. package/README.md +88 -0
  2. package/THIRD-PARTY-NOTICES.md +48 -0
  3. package/dist/data.json +4037 -386
  4. package/dist/demo-graph.d.ts +21 -12
  5. package/dist/demo-graph.js +37 -21
  6. package/dist/extractor.d.ts +24 -17
  7. package/dist/extractor.js +299 -156
  8. package/dist/index.d.ts +12 -7
  9. package/dist/index.js +9 -7
  10. package/dist/llms-full.txt +8248 -2013
  11. package/dist/llms.txt +98 -93
  12. package/dist/markdown.d.ts +69 -23
  13. package/dist/markdown.js +131 -72
  14. package/dist/md/blocks/app-shell-01.md +135 -0
  15. package/dist/md/blocks/auth-form-01.md +135 -0
  16. package/dist/md/blocks/cta-01.md +88 -0
  17. package/dist/md/blocks/data-table-01.md +196 -0
  18. package/dist/md/blocks/feature-grid-01.md +92 -0
  19. package/dist/md/blocks/hero-01.md +90 -0
  20. package/dist/md/blocks/instrument-panel-01.md +109 -0
  21. package/dist/md/blocks/logo-strip-01.md +97 -0
  22. package/dist/md/blocks/note-grid-01.md +98 -0
  23. package/dist/md/blocks/page-header-01.md +97 -0
  24. package/dist/md/blocks/pricing-01.md +91 -0
  25. package/dist/md/blocks/process-rail-01.md +106 -0
  26. package/dist/md/blocks/product-grid-01.md +107 -0
  27. package/dist/md/blocks/settings-panel-01.md +146 -0
  28. package/dist/md/blocks/site-footer.md +103 -11
  29. package/dist/md/blocks/site-header.md +107 -11
  30. package/dist/md/blocks/stack-grid-01.md +108 -0
  31. package/dist/md/blocks/stats-01.md +89 -0
  32. package/dist/md/blocks/status-ledger-01.md +121 -0
  33. package/dist/md/changelogs/prism-llms.md +244 -0
  34. package/dist/md/changelogs/prism-mcp-server.md +95 -0
  35. package/dist/md/changelogs/prism-tokens.md +126 -0
  36. package/dist/md/changelogs/prism-ui.md +467 -0
  37. package/dist/md/components/accordion.md +108 -0
  38. package/dist/md/components/alert.md +90 -7
  39. package/dist/md/components/avatar.md +89 -7
  40. package/dist/md/components/badge.md +74 -7
  41. package/dist/md/components/breadcrumb.md +84 -7
  42. package/dist/md/components/button.md +90 -7
  43. package/dist/md/components/card.md +90 -7
  44. package/dist/md/components/checkbox.md +101 -7
  45. package/dist/md/components/cta-link.md +98 -0
  46. package/dist/md/components/diagram.md +124 -0
  47. package/dist/md/components/dialog.md +128 -0
  48. package/dist/md/components/dropdown-menu.md +125 -0
  49. package/dist/md/components/fact-list.md +85 -0
  50. package/dist/md/components/field.md +116 -0
  51. package/dist/md/components/input.md +86 -7
  52. package/dist/md/components/kbd.md +77 -0
  53. package/dist/md/components/pagination.md +95 -7
  54. package/dist/md/components/popover.md +95 -7
  55. package/dist/md/components/product-mark.md +114 -0
  56. package/dist/md/components/product-switcher.md +88 -0
  57. package/dist/md/components/progress.md +88 -7
  58. package/dist/md/components/prose.md +91 -0
  59. package/dist/md/components/radio-group.md +111 -0
  60. package/dist/md/components/section.md +91 -0
  61. package/dist/md/components/select.md +143 -7
  62. package/dist/md/components/separator.md +77 -0
  63. package/dist/md/components/skeleton.md +71 -7
  64. package/dist/md/components/slider.md +90 -7
  65. package/dist/md/components/switch.md +104 -7
  66. package/dist/md/components/table.md +104 -7
  67. package/dist/md/components/tabs.md +105 -7
  68. package/dist/md/components/textarea.md +101 -0
  69. package/dist/md/components/tooltip.md +95 -7
  70. package/dist/md/components/typography.md +82 -7
  71. package/dist/md/content/about-content.md +36 -0
  72. package/dist/md/content/audience.md +43 -0
  73. package/dist/md/content/glossary.md +69 -0
  74. package/dist/md/content/product-vocabulary.md +53 -0
  75. package/dist/md/content/voice.md +52 -0
  76. package/dist/md/content/writing-mechanics.md +58 -0
  77. package/dist/md/foundation/colors.md +10 -0
  78. package/dist/md/foundation/iconography.md +14 -0
  79. package/dist/md/foundation/motion.md +10 -0
  80. package/dist/md/foundation/radii.md +9 -0
  81. package/dist/md/foundation/shadows.md +9 -0
  82. package/dist/md/foundation/spacings.md +8 -0
  83. package/dist/md/foundation/typography.md +9 -0
  84. package/dist/md/foundation/variables.md +9 -0
  85. package/dist/md/overview/architecture.md +76 -0
  86. package/dist/md/overview/brand.md +41 -0
  87. package/dist/md/overview/composition.md +77 -0
  88. package/dist/md/overview/quickstart.md +97 -0
  89. package/dist/md/overview/theming.md +89 -0
  90. package/dist/md/overview/using-llms.md +83 -0
  91. package/dist/md/pages/auth-page.md +149 -0
  92. package/dist/md/pages/blog-post-page.md +136 -0
  93. package/dist/md/pages/dashboard-page.md +241 -0
  94. package/dist/md/pages/docs-shell.md +210 -15
  95. package/dist/md/pages/marketing-page.md +199 -0
  96. package/dist/md/pages/not-found-page.md +105 -0
  97. package/dist/md/pages/settings-page.md +206 -0
  98. package/dist/prism-skill.md +50 -0
  99. package/dist/store.d.ts +203 -0
  100. package/dist/store.js +317 -0
  101. package/package.json +29 -26
  102. package/dist/demo-graph.d.ts.map +0 -1
  103. package/dist/demo-graph.js.map +0 -1
  104. package/dist/extractor.d.ts.map +0 -1
  105. package/dist/extractor.js.map +0 -1
  106. package/dist/index.d.ts.map +0 -1
  107. package/dist/index.js.map +0 -1
  108. package/dist/markdown.d.ts.map +0 -1
  109. package/dist/markdown.js.map +0 -1
  110. package/dist/md/blocks/component-demo.md +0 -19
  111. package/dist/md/blocks/page-header.md +0 -19
  112. package/dist/md/components/affix.md +0 -14
  113. package/dist/md/components/anchor.md +0 -14
  114. package/dist/md/components/auto-complete.md +0 -14
  115. package/dist/md/components/back-top.md +0 -14
  116. package/dist/md/components/border-beam.md +0 -14
  117. package/dist/md/components/calendar.md +0 -14
  118. package/dist/md/components/carousel.md +0 -14
  119. package/dist/md/components/cascader.md +0 -14
  120. package/dist/md/components/col.md +0 -14
  121. package/dist/md/components/collapse.md +0 -14
  122. package/dist/md/components/color-picker.md +0 -14
  123. package/dist/md/components/date-picker.md +0 -14
  124. package/dist/md/components/descriptions.md +0 -14
  125. package/dist/md/components/display-title.md +0 -20
  126. package/dist/md/components/divider.md +0 -14
  127. package/dist/md/components/drawer.md +0 -14
  128. package/dist/md/components/dropdown.md +0 -14
  129. package/dist/md/components/empty.md +0 -14
  130. package/dist/md/components/flex.md +0 -14
  131. package/dist/md/components/float-button.md +0 -14
  132. package/dist/md/components/form.md +0 -14
  133. package/dist/md/components/grid.md +0 -14
  134. package/dist/md/components/image.md +0 -14
  135. package/dist/md/components/input-number.md +0 -14
  136. package/dist/md/components/layout.md +0 -14
  137. package/dist/md/components/list.md +0 -14
  138. package/dist/md/components/listy.md +0 -14
  139. package/dist/md/components/masonry.md +0 -14
  140. package/dist/md/components/mentions.md +0 -14
  141. package/dist/md/components/menu.md +0 -14
  142. package/dist/md/components/modal.md +0 -14
  143. package/dist/md/components/popconfirm.md +0 -14
  144. package/dist/md/components/qrcode.md +0 -14
  145. package/dist/md/components/radio.md +0 -14
  146. package/dist/md/components/rate.md +0 -14
  147. package/dist/md/components/result.md +0 -14
  148. package/dist/md/components/row.md +0 -14
  149. package/dist/md/components/segmented.md +0 -14
  150. package/dist/md/components/space.md +0 -14
  151. package/dist/md/components/spin.md +0 -14
  152. package/dist/md/components/splitter.md +0 -14
  153. package/dist/md/components/statistic.md +0 -14
  154. package/dist/md/components/steps.md +0 -14
  155. package/dist/md/components/tag.md +0 -14
  156. package/dist/md/components/time-picker.md +0 -14
  157. package/dist/md/components/timeline.md +0 -14
  158. package/dist/md/components/tour.md +0 -14
  159. package/dist/md/components/transfer.md +0 -14
  160. package/dist/md/components/tree-select.md +0 -14
  161. package/dist/md/components/tree.md +0 -14
  162. package/dist/md/components/upload.md +0 -14
  163. package/dist/md/components/watermark.md +0 -14
  164. package/dist/md/docs/brand.md +0 -41
  165. package/dist/md/pages/blog-layout.md +0 -19
  166. package/dist/md/theme/blue-dark.md +0 -127
  167. package/dist/md/theme/blue-light.md +0 -129
  168. package/dist/md/theme/green-dark.md +0 -127
  169. package/dist/md/theme/green-light.md +0 -129
  170. package/dist/md/theme/lavender-dark.md +0 -127
  171. package/dist/md/theme/lavender-light.md +0 -129
  172. package/dist/md/theme/peach-dark.md +0 -127
  173. package/dist/md/theme/peach-light.md +0 -129
  174. package/dist/md/theme/rose-dark.md +0 -127
  175. package/dist/md/theme/rose-light.md +0 -129
@@ -0,0 +1,199 @@
1
+ # MarketingPage
2
+
3
+ A complete marketing page composing a hero, a feature grid, a KPI row, a plan comparison and a closing call to action.
4
+
5
+ ```tsx
6
+ import { MarketingPage } from '@nanisoft/prism-ui/pages/marketing-page'
7
+ ```
8
+
9
+ ## Overview
10
+
11
+ MarketingPage is a complete marketing screen. It composes five blocks in reading
12
+ order and passes each one its own content, so the page adds the sequence and
13
+ nothing else: an opening hero, a capability grid, a row of key figures, a plan
14
+ comparison and a closing call to action.
15
+
16
+ The page composes these blocks:
17
+
18
+ | Section | Block | Role |
19
+ | --- | --- | --- |
20
+ | Opening | Hero01 | the headline, the supporting line and one or two actions |
21
+ | Capabilities | FeatureGrid01 | a grid of short feature blurbs, with or without icons |
22
+ | Figures | Stats01 | two to four key numbers, each with an optional delta |
23
+ | Plans | Pricing01 | a plan comparison with one highlighted tier |
24
+ | Closing | Cta01 | the final call to action on a filled surface |
25
+
26
+ Every string, number, icon, price and action is a prop. The page ships no sample
27
+ copy and fetches nothing. It is a product-agnostic screen model, so a consumer
28
+ installs it, passes their own content and owns the links. It is not this site's
29
+ own landing route: that page is site-owned and composes the same blocks at the
30
+ call site.
31
+
32
+ ## Guidelines
33
+
34
+ ### When to use
35
+
36
+ Use MarketingPage for a public landing route whose job is to introduce a product
37
+ and move a reader to one next step. It works when the five sections form one
38
+ argument from the headline to the closing action.
39
+
40
+ ### When not to use
41
+
42
+ Do not use it inside an authenticated screen. A hero and a plan comparison carry
43
+ marketing weight that competes with the task an application screen exists to
44
+ support; compose the blocks you need directly instead.
45
+
46
+ Do not use it as a documentation page. Guides and item pages have their own
47
+ shell, and a marketing hero would sit above content that is already scoped.
48
+
49
+ Do not use it when the sequence is not the five sections. The page is a fixed
50
+ composition; a different order or a missing section is a page the consumer
51
+ builds from the blocks.
52
+
53
+ ### Best practices
54
+
55
+ - Pass every block its own props. The page does not merge or default them, so
56
+ omitting a section's content renders an empty section rather than a fallback.
57
+ - Keep the hero as the only `h1`. The page defaults `headingLevel` to `h1`; when
58
+ it is embedded under a heading the consumer already owns, pass one level
59
+ deeper and the rest of the outline follows.
60
+ - Put the primary action on the hero and the secondary action on the closing
61
+ band, not both in each. One decision per band keeps the page from reading as
62
+ two pitches.
63
+ - Keep the figures real. Stats01 renders exactly the numbers it is given, so the
64
+ page makes no claim the consumer did not make.
65
+
66
+ ### Content guidelines
67
+
68
+ - The hero headline states an outcome, not a feature name.
69
+ - The feature titles are the four or five things the product does; the bodies
70
+ are one sentence each.
71
+ - The closing line is a verb phrase and the action names what the reader gets.
72
+
73
+ **The marketing page, composed with placeholder sections.**
74
+
75
+ ```tsx
76
+ import { Blocks, Palette, ShieldCheck, Zap } from 'lucide-react'
77
+
78
+ import { MarketingPage } from '@nanisoft/prism-ui/pages/marketing-page'
79
+
80
+ /**
81
+ * The marketing page, composed with placeholder sections.
82
+ *
83
+ * The page owns the sequence; the demo owns the strings, the numbers and the
84
+ * feature icons. It renders at `h3` because the documentation page already owns
85
+ * an `h1`, which is the same reason a block demo nests its heading.
86
+ */
87
+ export default function MarketingPageDemo() {
88
+ return (
89
+ <MarketingPage
90
+ headingLevel="h3"
91
+ hero={{
92
+ eyebrow: 'Preview',
93
+ title: 'A headline that fits on two lines',
94
+ description:
95
+ 'One or two sentences of supporting copy, so the measure and the spacing around it can be judged.',
96
+ actions: [
97
+ { label: 'Primary action' },
98
+ { label: 'Secondary', variant: 'outline' },
99
+ ],
100
+ }}
101
+ features={{
102
+ eyebrow: 'Preview',
103
+ title: 'Section heading',
104
+ description: 'An optional line that explains what the set below it has in common.',
105
+ features: [
106
+ {
107
+ icon: Palette,
108
+ title: 'First item',
109
+ body: 'A short sentence describing the first thing in the set.',
110
+ },
111
+ {
112
+ icon: Blocks,
113
+ title: 'Second item',
114
+ body: 'A short sentence describing the second thing in the set.',
115
+ },
116
+ {
117
+ icon: Zap,
118
+ title: 'Third item',
119
+ body: 'A short sentence describing the third thing in the set.',
120
+ },
121
+ {
122
+ icon: ShieldCheck,
123
+ title: 'Fourth item',
124
+ body: 'A short sentence describing the fourth thing in the set.',
125
+ },
126
+ ],
127
+ }}
128
+ stats={{
129
+ eyebrow: 'Preview',
130
+ title: 'Section heading',
131
+ stats: [
132
+ { label: 'First metric', value: '1,284', delta: 12, hint: 'vs last month' },
133
+ { label: 'Second metric', value: '47.2%', delta: -3, hint: 'vs last month' },
134
+ { label: 'Third metric', value: '2.4d', delta: 0, hint: 'vs last quarter' },
135
+ { label: 'Fourth metric', value: '138' },
136
+ ],
137
+ }}
138
+ pricing={{
139
+ title: 'Section heading',
140
+ plans: [
141
+ {
142
+ name: 'First plan',
143
+ price: '$0',
144
+ period: ' / month',
145
+ body: 'One line on who it is for.',
146
+ features: ['First included line', 'Second included line', 'Third included line'],
147
+ cta: 'Choose',
148
+ },
149
+ {
150
+ name: 'Second plan',
151
+ price: '$24',
152
+ period: ' / month',
153
+ body: 'One line on who it is for.',
154
+ features: ['Everything in the first plan', 'One extra line', 'Another extra line'],
155
+ cta: 'Choose',
156
+ featured: true,
157
+ },
158
+ {
159
+ name: 'Third plan',
160
+ price: '$68',
161
+ period: ' / month',
162
+ body: 'One line on who it is for.',
163
+ features: ['Everything in the second plan', 'One extra line', 'Another extra line'],
164
+ cta: 'Choose',
165
+ },
166
+ ],
167
+ }}
168
+ cta={{
169
+ title: 'A closing line, two lines at most',
170
+ description: 'A sentence that says what happens next, then one action.',
171
+ action: { label: 'Do the thing', href: '/components/button' },
172
+ }}
173
+ />
174
+ )
175
+ }
176
+ ```
177
+
178
+ ## Props
179
+
180
+ **`hero`** `ComponentProps<typeof Hero01>` · required · default: — — The opening band: an optional eyebrow, the headline and one or two actions.
181
+ **`features`** `ComponentProps<typeof FeatureGrid01>` · required · default: — — The capability grid below the hero.
182
+ **`stats`** `ComponentProps<typeof Stats01>` · required · default: — — The key-figure row.
183
+ **`pricing`** `ComponentProps<typeof Pricing01>` · required · default: — — The plan comparison.
184
+ **`cta`** `ComponentProps<typeof Cta01>` · required · default: — — The closing call to action.
185
+ **`headingLevel`** `HeadingLevel` · optional · default: — — The heading level for the hero. Defaults to `h1`, because a page owns the top of the document outline. A consumer that embeds the page under a heading it already owns passes one level deeper.
186
+
187
+ ## Composition
188
+
189
+ **`exports`** `MarketingPage` — the public runtime names this Page promises
190
+ **`source`** `packages/ui/src/pages/marketing-page/index.tsx` — the file this Page is defined in
191
+ **`dependencies`** `Cta01, FeatureGrid01, Hero01, Pricing01, Stats01` — the public Prism exports this item composes
192
+
193
+ ## Blocks
194
+
195
+ - [Cta01](https://prism.nanisoft.com/blocks/cta-01.md)
196
+ - [FeatureGrid01](https://prism.nanisoft.com/blocks/feature-grid-01.md)
197
+ - [Hero01](https://prism.nanisoft.com/blocks/hero-01.md)
198
+ - [Pricing01](https://prism.nanisoft.com/blocks/pricing-01.md)
199
+ - [Stats01](https://prism.nanisoft.com/blocks/stats-01.md)
@@ -0,0 +1,105 @@
1
+ # NotFoundPage
2
+
3
+ A complete not-found screen: the status code as the heading of the page, one sentence about what happened, and the ways out.
4
+
5
+ ```tsx
6
+ import { NotFoundPage } from '@nanisoft/prism-ui/pages/not-found-page'
7
+ ```
8
+
9
+ ## Overview
10
+
11
+ NotFoundPage is a complete not-found screen: the code, what happened, and the ways
12
+ out.
13
+
14
+ All four NaniSoft sites compose one, each in its own not-found route, and three of
15
+ them are the same six lines with a different product name on it: a display title
16
+ carrying the code, one muted sentence, and two or three links. The fourth wrote
17
+ the same thing in its own markup. Four hand-written screens for one shape.
18
+
19
+ It is a Page rather than a Block because it is a whole screen: it owns the
20
+ document's `h1`, it is what a router renders when a route does not resolve, and
21
+ the band's job is not separable from the screen's. There is one correct page here
22
+ and it is short.
23
+
24
+ ## Guidelines
25
+
26
+ ### When to use
27
+
28
+ Use NotFoundPage as the body of whatever route your framework names for a
29
+ not-found response: Next's `not-found.tsx`, a Nuxt error page, a route your own
30
+ router falls through to.
31
+
32
+ Use it for every status that means "this address is not a page here", not only
33
+ 404. A 410 and a 404 are the same screen with a different code, and the code is a
34
+ prop.
35
+
36
+ ### When not to use
37
+
38
+ Do not use it for a request that failed. That is an error page with a retry, and a
39
+ reader who sees "this page does not exist" when the page exists and did not load
40
+ will not believe you next time.
41
+
42
+ Do not use it for a permission failure the reader might be granted later. That is
43
+ a 403, and it needs a sign-in link rather than a way back to the landing.
44
+
45
+ ### Best practices
46
+
47
+ - **The code is the `h1` and the sentence is not.** A not-found page whose `h1` is
48
+ "Page not found" gives a search engine and a screen reader nothing distinct to
49
+ index, and the code is the one string on the page that is the same for every
50
+ broken URL. The code takes the display step and the sentence takes the muted one,
51
+ which is the reverse of what a reader sees first and the right way round for
52
+ anything that reads the outline.
53
+ - Put the most useful destination first, and weight it as the primary action. A
54
+ not-found page that offers the homepage link before the documentation sends a
55
+ reader further from what they wanted.
56
+ - Leave `newTab` off every link. A reader who followed a broken link and is sent
57
+ to a new tab has to find their way back.
58
+ - Use the `children` slot for a search box or a list of recent posts, which is
59
+ what turns a dead end into a page.
60
+
61
+ ### Content guidelines
62
+
63
+ - Write the sentence as a fact about the address, not as an apology. "No node
64
+ here" beats "Sorry, we could not find that page".
65
+ - Say whether the page might exist later if it does. "This page does not exist
66
+ (yet)" is one clause longer and saves a support ticket.
67
+ - Keep each link label to one or two words.
68
+
69
+ **The not-found screen: the code as the h1, one sentence, and the ways out.**
70
+
71
+ ```tsx
72
+ import { NotFoundPage } from '@nanisoft/prism-ui/pages/not-found-page'
73
+
74
+ /** The not-found screen: the code as the h1, one sentence, and the ways out. */
75
+ export default function NotFoundPageDemo() {
76
+ return (
77
+ <NotFoundPage
78
+ code="404"
79
+ title="No node here."
80
+ description="The estate is fully mapped. This URL is not in the graph."
81
+ linksLabel="Ways out"
82
+ links={[
83
+ { label: 'Read the docs', href: '#docs' },
84
+ { label: 'Back to the landing', href: '#landing' },
85
+ ]}
86
+ />
87
+ )
88
+ }
89
+ ```
90
+
91
+ ## Props
92
+
93
+ **`code`** `string` · required · default: — — The status code, shown as the page's own `h1`. Required, and a string rather than a number because it is displayed, not computed: a Page never decides what code it is answering.
94
+ **`title`** `string` · required · default: — — The headline under the code: the sentence that says what happened. It is the part a reader actually reads, and it is the caller's because every product says it differently - "No node here", "This page does not exist (yet)".
95
+ **`description`** `string` · optional · default: — — One or two sentences under the headline, for anything a reader should know before they follow one of the links: that the URL may be mistyped, that the page is planned, that a search would find it.
96
+ **`links`** `readonly NotFoundLink[]` · required · default: — — The ways out, in the order a reader should see them. Put the destination most likely to help first; a not-found page that offers a homepage link before the documentation sends a reader further from what they wanted.
97
+ **`linksLabel`** `string` · required · default: — — The accessible name of the row of ways out. It is required, because it is a word a reader hears and a Page that ships no copy ships no reader-facing copy either. "Ways out" is the Page's own phrasing; a site that files its destinations differently names the same landmark differently.
98
+ **`children`** `ReactNode` · optional · default: — — A slot for whatever else the site wants to say here: a search box, a list of recent posts, a contact address.
99
+ **`className`** `string` · optional · default: — — Layout only, exactly as on every Component. Changing a Prism-owned visual property from here is prohibited.
100
+
101
+ ## Composition
102
+
103
+ **`exports`** `NotFoundPage` — the public runtime names this Page promises
104
+ **`source`** `packages/ui/src/pages/not-found-page/index.tsx` — the file this Page is defined in
105
+ **`dependencies`** `CtaLink, Prose, Section` — the public Prism exports this item composes
@@ -0,0 +1,206 @@
1
+ # SettingsPage
2
+
3
+ A full settings screen composing the app shell, a page header and tabs of grouped settings forms.
4
+
5
+ ```tsx
6
+ import { SettingsPage } from '@nanisoft/prism-ui/pages/settings-page'
7
+ ```
8
+
9
+ ## Overview
10
+
11
+ SettingsPage is a complete settings screen. It composes the shell, a page header
12
+ and a set of tabs, where each tab is either a saved settings form or a read-only
13
+ panel. The page owns the sequence and the tab wiring only.
14
+
15
+ The page composes these parts:
16
+
17
+ | Region | Piece | Role |
18
+ | --- | --- | --- |
19
+ | Frame | AppShell01 | the navigation rail, the top bar and the mobile navigation sheet |
20
+ | Header | PageHeader01 | the trail, the screen title and its actions |
21
+ | Tabs | Tabs, TabsList, TabsTrigger, TabsContent | the peer settings groups |
22
+ | Forms | SettingsPanel01 | the grouped and saved form for one tab |
23
+
24
+ A tab that carries `panel` renders `SettingsPanel01`: a titled card with grouped
25
+ sections, a save footer and one submit. A tab that carries `content` renders the
26
+ node as-is, which suits a read-only summary or a view that is not a form. Sections,
27
+ fields, options and labels are all props, and the page fetches nothing.
28
+
29
+ ## Guidelines
30
+
31
+ ### When to use
32
+
33
+ Use SettingsPage when a screen changes several settings that group naturally, and
34
+ each group can be saved on its own. It works when the tabs are stable and a reader
35
+ returns to one group rather than scanning the whole screen.
36
+
37
+ ### When not to use
38
+
39
+ Do not use it for a single setting. One field behind a tab is a heavier frame
40
+ than the choice deserves; put the control on the screen that owns it.
41
+
42
+ Do not use it when the settings must be compared side by side. Tabs hide one
43
+ group to show another, so a choice that depends on another group's value belongs
44
+ on one page, not behind a tab.
45
+
46
+ ### Best practices
47
+
48
+ - Keep one save per panel. A mixed model, where some fields save and others apply
49
+ immediately, makes the footer's promise unclear.
50
+ - Give every field a stable `id`, so the label is linked to the control.
51
+ - Use `content` for a read-only group. A panel with no `submitLabel` renders no
52
+ footer, which is the honest shape for a view that does not save.
53
+ - Set `defaultValue` to the group a reader is most likely to want, rather than
54
+ relying on the first tab by luck.
55
+ - Pass the same navigation node to both the rail and the sheet, and keep its ids
56
+ unique because AppShell01 renders it twice.
57
+
58
+ ### Content guidelines
59
+
60
+ - A tab label is one word in sentence case: "General", "Notifications".
61
+ - A section title is one or two words and a field label is a short noun phrase.
62
+ - A description states the effect of the group, not a policy for it.
63
+
64
+ **The settings page, with a grouped form per tab.**
65
+
66
+ ```tsx
67
+ 'use client'
68
+
69
+ import { SettingsPage } from '@nanisoft/prism-ui/pages/settings-page'
70
+
71
+ const LINKS = [
72
+ { href: '#general', label: 'General', current: false },
73
+ { href: '#settings', label: 'Settings', current: true },
74
+ { href: '#members', label: 'Members', current: false },
75
+ ]
76
+
77
+ /** The settings page, with a grouped form per tab. */
78
+ export default function SettingsPageDemo() {
79
+ return (
80
+ <SettingsPage
81
+ shell={{
82
+ navigationLabel: 'Primary',
83
+ brand: <span className="text-sm font-semibold">Northwind</span>,
84
+ breadcrumbs: [{ label: 'Settings', href: '#settings' }, { label: 'Workspace' }],
85
+ navigation: (
86
+ <ul className="flex flex-col gap-1 text-sm">
87
+ {LINKS.map((link) => (
88
+ <li key={link.href}>
89
+ <a
90
+ href={link.href}
91
+ className={
92
+ link.current
93
+ ? 'bg-accent text-accent-foreground block rounded-md px-3 py-2 font-medium'
94
+ : 'text-muted-foreground hover:text-foreground block rounded-md px-3 py-2'
95
+ }
96
+ >
97
+ {link.label}
98
+ </a>
99
+ </li>
100
+ ))}
101
+ </ul>
102
+ ),
103
+ }}
104
+ header={{
105
+ title: 'Workspace settings',
106
+ description: 'Manage how this workspace behaves for everyone on the team.',
107
+ }}
108
+ tabs={[
109
+ {
110
+ value: 'general',
111
+ label: 'General',
112
+ panel: {
113
+ title: 'General',
114
+ description: 'Shown to everyone you collaborate with.',
115
+ submitLabel: 'Save changes',
116
+ secondaryAction: { label: 'Cancel' },
117
+ sections: [
118
+ {
119
+ id: 'identity',
120
+ title: 'Identity',
121
+ fields: [
122
+ {
123
+ kind: 'text',
124
+ id: 'settings-workspace-name',
125
+ label: 'Workspace name',
126
+ defaultValue: 'Northwind',
127
+ },
128
+ {
129
+ kind: 'textarea',
130
+ id: 'settings-workspace-description',
131
+ label: 'Description',
132
+ placeholder: 'What does this workspace do?',
133
+ rows: 3,
134
+ },
135
+ {
136
+ kind: 'select',
137
+ id: 'settings-workspace-region',
138
+ label: 'Data region',
139
+ placeholder: 'Choose a region',
140
+ defaultValue: 'eu-west',
141
+ options: [
142
+ { label: 'Europe West', value: 'eu-west' },
143
+ { label: 'US East', value: 'us-east' },
144
+ ],
145
+ },
146
+ ],
147
+ },
148
+ ],
149
+ },
150
+ },
151
+ {
152
+ value: 'notifications',
153
+ label: 'Notifications',
154
+ panel: {
155
+ title: 'Notifications',
156
+ description: 'Choose what the workspace sends and when.',
157
+ submitLabel: 'Save changes',
158
+ sections: [
159
+ {
160
+ id: 'email',
161
+ title: 'Email',
162
+ fields: [
163
+ {
164
+ kind: 'switch',
165
+ id: 'settings-weekly-digest',
166
+ label: 'Weekly digest',
167
+ description: 'A summary of activity every Monday.',
168
+ defaultChecked: true,
169
+ },
170
+ {
171
+ kind: 'switch',
172
+ id: 'settings-mention-alerts',
173
+ label: 'Mention alerts',
174
+ description: 'Notify me when someone mentions my name.',
175
+ },
176
+ ],
177
+ },
178
+ ],
179
+ },
180
+ },
181
+ ]}
182
+ />
183
+ )
184
+ }
185
+ ```
186
+
187
+ ## Props
188
+
189
+ **`shell`** `Omit<ComponentProps<typeof AppShell01>, 'children'>` · required · default: — — The frame: rail, top bar and mobile navigation sheet.
190
+ **`header`** `ComponentProps<typeof PageHeader01>` · required · default: — — The page title band.
191
+ **`tabs`** `SettingsPageTab[]` · required · default: — — The tabs, in order. At least one is required.
192
+ **`defaultValue`** `string` · optional · default: — — The tab shown first, for uncontrolled tabs. Defaults to the first tab.
193
+ **`value`** `string` · optional · default: — — The controlled active tab.
194
+ **`onValueChange`** `(value: string) => void` · optional · default: —
195
+
196
+ ## Composition
197
+
198
+ **`exports`** `SettingsPage` — the public runtime names this Page promises
199
+ **`source`** `packages/ui/src/pages/settings-page/index.tsx` — the file this Page is defined in
200
+ **`dependencies`** `AppShell01, PageHeader01, SettingsPanel01, Tabs` — the public Prism exports this item composes
201
+
202
+ ## Blocks
203
+
204
+ - [AppShell01](https://prism.nanisoft.com/blocks/app-shell-01.md)
205
+ - [PageHeader01](https://prism.nanisoft.com/blocks/page-header-01.md)
206
+ - [SettingsPanel01](https://prism.nanisoft.com/blocks/settings-panel-01.md)
@@ -0,0 +1,50 @@
1
+ # Prism agent skill
2
+
3
+ Prism is NaniSoft's design system: design tokens, a React component library, a
4
+ documentation site, and this agent surface. This is the fast path. The index is
5
+ [`/llms.txt`](https://prism.nanisoft.com/llms.txt) and every page in full is
6
+ [`/llms-full.txt`](https://prism.nanisoft.com/llms-full.txt); both are generated from the
7
+ checked catalogue and the authored pages.
8
+
9
+ ## Start here
10
+
11
+ ```tsx
12
+ import '@nanisoft/prism-ui/styles.css'
13
+
14
+ import { PrismProvider, PrismThemeScript } from '@nanisoft/prism-ui/provider'
15
+ ```
16
+
17
+ Import the one stylesheet once. The provider is optional: the declarative axes
18
+ are `data-pack` on `<html>` and the `dark` class for mode.
19
+
20
+ ## Import contract
21
+
22
+ - Components: `@nanisoft/prism-ui/components/<slug>`
23
+ - Blocks: `@nanisoft/prism-ui/blocks/<slug>`
24
+ - Pages: `@nanisoft/prism-ui/pages/<slug>`
25
+
26
+ Compound parts stay inside their module. Base UI and every internal path are
27
+ never a consumer import.
28
+
29
+ ## MCP
30
+
31
+ The read-only MCP endpoint is `https://prism.nanisoft.com/mcp`. It exposes nine tools:
32
+ `list_items`, `get_item_doc`, `get_item_props`, `get_item_source`,
33
+ `get_theme_doc`, `list_pages`, `get_page`, `search_docs` and
34
+ `get_changelog`.
35
+
36
+ ## Truth rules
37
+
38
+ - Prism is the one source of truth. A consumer composes; it never writes CSS and
39
+ never overrides a style.
40
+ - There is no override path. When Prism lacks a component, token or variant,
41
+ request it upstream.
42
+ - Generated code imports from `@nanisoft/prism-ui` only.
43
+
44
+ ## This corpus
45
+
46
+ Generated from the catalogue and the authored pages: 34
47
+ Components, 19 Blocks and 7 Pages, plus the Overview,
48
+ Foundation, Content and Changelogs pages. The Changelogs pages are each
49
+ published package's own changelog, byte for byte; `get_changelog` returns one
50
+ package's, optionally one version of it.