@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.
- package/README.md +88 -0
- package/THIRD-PARTY-NOTICES.md +48 -0
- package/dist/data.json +4037 -386
- 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 +299 -156
- package/dist/index.d.ts +12 -7
- package/dist/index.js +9 -7
- package/dist/llms-full.txt +8248 -2013
- package/dist/llms.txt +98 -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 +98 -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 +107 -0
- package/dist/md/blocks/settings-panel-01.md +146 -0
- package/dist/md/blocks/site-footer.md +103 -11
- package/dist/md/blocks/site-header.md +107 -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 +244 -0
- package/dist/md/changelogs/prism-mcp-server.md +95 -0
- package/dist/md/changelogs/prism-tokens.md +126 -0
- package/dist/md/changelogs/prism-ui.md +467 -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 +114 -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/docs-shell.md +210 -15
- 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/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,135 @@
|
|
|
1
|
+
# AppShell01
|
|
2
|
+
|
|
3
|
+
A navigation shell with a desktop rail, a top bar and a mobile navigation sheet.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { AppShell01 } from '@nanisoft/prism-ui/blocks/app-shell-01'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
AppShell01 is the frame an application screen repeats: a navigation rail from
|
|
12
|
+
the large breakpoint up, a top bar with a breadcrumb trail and actions, and a
|
|
13
|
+
left-anchored sheet that carries the same navigation on narrow screens. The page
|
|
14
|
+
content is a slot, so the shell never decides what a screen contains.
|
|
15
|
+
|
|
16
|
+
The block composes these components:
|
|
17
|
+
|
|
18
|
+
| Part | Component | Role |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| Rail | Separator | the fixed navigation column and its dividers |
|
|
21
|
+
| Top bar | Breadcrumb, Button | the trail and the sheet trigger |
|
|
22
|
+
| Sheet | Dialog | the left drawer that holds navigation on small screens |
|
|
23
|
+
| Content | children | the application-owned main region |
|
|
24
|
+
|
|
25
|
+
The navigation is passed as a node rather than a route table. The block never
|
|
26
|
+
imports a router and fetches nothing, so the application keeps its own links and
|
|
27
|
+
data.
|
|
28
|
+
|
|
29
|
+
## Guidelines
|
|
30
|
+
|
|
31
|
+
### When to use
|
|
32
|
+
|
|
33
|
+
Use AppShell01 when several screens share one navigation frame. It works when
|
|
34
|
+
the navigation is stable across routes and the top bar carries the current
|
|
35
|
+
location rather than a page's own controls.
|
|
36
|
+
|
|
37
|
+
### When not to use
|
|
38
|
+
|
|
39
|
+
Do not use it on a marketing page or a docs article. Those pages have no
|
|
40
|
+
authenticated navigation rail, and the frame would collapse around content that
|
|
41
|
+
does not need it.
|
|
42
|
+
|
|
43
|
+
Do not use it for a single screen. One page does not justify a shell; render the
|
|
44
|
+
navigation directly.
|
|
45
|
+
|
|
46
|
+
### Best practices
|
|
47
|
+
|
|
48
|
+
- Pass the same navigation node to both the rail and the sheet. The block
|
|
49
|
+
renders it twice, so keep ids in the navigation unique or avoid ids there.
|
|
50
|
+
- Keep the breadcrumb to the ancestors and the current page. The page's own
|
|
51
|
+
title belongs in the page header, not the top bar.
|
|
52
|
+
- Put account controls, a theme switch or a search in `actions`.
|
|
53
|
+
- Give the shell a real `navigationLabel`: it names two navigation landmarks
|
|
54
|
+
and the sheet trigger, and it is the only required string.
|
|
55
|
+
|
|
56
|
+
### Content guidelines
|
|
57
|
+
|
|
58
|
+
- A brand mark is a wordmark or a short product name, not a headline.
|
|
59
|
+
- A breadcrumb label is the destination's display name.
|
|
60
|
+
- `navigationLabel` names the area for assistive technology, such as "Primary".
|
|
61
|
+
|
|
62
|
+
**The application shell with a rail, a top bar and a mobile navigation sheet.**
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
'use client'
|
|
66
|
+
|
|
67
|
+
import { AppShell01 } from '@nanisoft/prism-ui/blocks/app-shell-01'
|
|
68
|
+
|
|
69
|
+
const LINKS = [
|
|
70
|
+
{ href: '#dashboard', label: 'Dashboard', current: true },
|
|
71
|
+
{ href: '#projects', label: 'Projects', current: false },
|
|
72
|
+
{ href: '#team', label: 'Team', current: false },
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
/** The application shell with a rail, a top bar and a mobile navigation sheet. */
|
|
76
|
+
export default function AppShell01Demo() {
|
|
77
|
+
return (
|
|
78
|
+
<AppShell01
|
|
79
|
+
navigationLabel="Primary"
|
|
80
|
+
brand={<span className="text-sm font-semibold">Northwind</span>}
|
|
81
|
+
breadcrumbs={[
|
|
82
|
+
{ label: 'Dashboard', href: '#dashboard' },
|
|
83
|
+
{ label: 'Projects' },
|
|
84
|
+
]}
|
|
85
|
+
actions={
|
|
86
|
+
<span className="bg-muted text-muted-foreground rounded-full px-3 py-1 text-xs font-medium">
|
|
87
|
+
AR
|
|
88
|
+
</span>
|
|
89
|
+
}
|
|
90
|
+
navigation={
|
|
91
|
+
<ul className="flex flex-col gap-1 text-sm">
|
|
92
|
+
{LINKS.map((link) => (
|
|
93
|
+
<li key={link.href}>
|
|
94
|
+
<a
|
|
95
|
+
href={link.href}
|
|
96
|
+
className={
|
|
97
|
+
link.current
|
|
98
|
+
? 'bg-accent text-accent-foreground block rounded-md px-3 py-2 font-medium'
|
|
99
|
+
: 'text-muted-foreground hover:text-foreground block rounded-md px-3 py-2'
|
|
100
|
+
}
|
|
101
|
+
>
|
|
102
|
+
{link.label}
|
|
103
|
+
</a>
|
|
104
|
+
</li>
|
|
105
|
+
))}
|
|
106
|
+
</ul>
|
|
107
|
+
}
|
|
108
|
+
>
|
|
109
|
+
<div className="border-border rounded-xl border border-dashed p-6">
|
|
110
|
+
<h3 className="font-semibold">Main content</h3>
|
|
111
|
+
<p className="text-muted-foreground mt-1 text-sm">
|
|
112
|
+
The shell owns the frame; the application owns this region.
|
|
113
|
+
</p>
|
|
114
|
+
</div>
|
|
115
|
+
</AppShell01>
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Props
|
|
121
|
+
|
|
122
|
+
**`navigation`** `ReactNode` · required · default: — — The navigation rendered in the desktop rail and in the mobile sheet. Pass nodes rather than a route table: the block never imports a router.
|
|
123
|
+
**`navigationLabel`** `string` · required · default: — — The accessible name for the navigation regions and the sheet trigger.
|
|
124
|
+
**`brand`** `ReactNode` · optional · default: — — The brand or product mark at the top of the rail and the sheet.
|
|
125
|
+
**`breadcrumbs`** `AppShellCrumb[]` · optional · default: — — The trail shown in the top bar.
|
|
126
|
+
**`actions`** `ReactNode` · optional · default: — — Actions at the end of the top bar, e.g. an account menu.
|
|
127
|
+
**`railHeader`** `ReactNode` · optional · default: — — A slot above the navigation, e.g. a workspace switcher.
|
|
128
|
+
**`railFooter`** `ReactNode` · optional · default: — — A slot below the navigation, e.g. a user menu.
|
|
129
|
+
**`children`** `ReactNode` · required · default: —
|
|
130
|
+
|
|
131
|
+
## Composition
|
|
132
|
+
|
|
133
|
+
**`exports`** `AppShell01` — the public runtime names this Block promises
|
|
134
|
+
**`source`** `packages/ui/src/blocks/app-shell-01/index.tsx` — the file this Block is defined in
|
|
135
|
+
**`dependencies`** `Breadcrumb, Button, Dialog, Separator` — the public Prism exports this item composes
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# AuthForm01
|
|
2
|
+
|
|
3
|
+
A sign-in card with labelled credential fields, a remember control and an error slot.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { AuthForm01 } from '@nanisoft/prism-ui/blocks/auth-form-01'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
AuthForm01 is a sign-in card: a title, a supporting line, an error slot, the
|
|
12
|
+
credential fields, an optional remember row and the submit control.
|
|
13
|
+
|
|
14
|
+
The block composes these components:
|
|
15
|
+
|
|
16
|
+
| Part | Component | Role |
|
|
17
|
+
| --- | --- | --- |
|
|
18
|
+
| Surface | Card | the panel that centres the form |
|
|
19
|
+
| Fields | Field, Input | labelled email and password controls |
|
|
20
|
+
| Choices | Checkbox | the remember-me row |
|
|
21
|
+
| Feedback | Alert | the error message above the fields |
|
|
22
|
+
| Submit | Button | the one action on the card |
|
|
23
|
+
|
|
24
|
+
The block owns no credentials and makes no request. Each field value and the
|
|
25
|
+
submit handler come from the consumer, and the error line is a prop, so the
|
|
26
|
+
consumer's validation decides when it appears.
|
|
27
|
+
|
|
28
|
+
## Guidelines
|
|
29
|
+
|
|
30
|
+
### When to use
|
|
31
|
+
|
|
32
|
+
Use AuthForm01 for a sign-in or a similar single-step credential screen. It
|
|
33
|
+
works when the screen exists to collect one email and one secret and send them
|
|
34
|
+
somewhere.
|
|
35
|
+
|
|
36
|
+
### When not to use
|
|
37
|
+
|
|
38
|
+
Do not use it for registration, password reset or profile editing. Those have
|
|
39
|
+
different field sets; compose a form from the same parts.
|
|
40
|
+
|
|
41
|
+
Do not use it for an account picker or single sign-on landing; that is a
|
|
42
|
+
different shape, and `footer` is not the place for it.
|
|
43
|
+
|
|
44
|
+
### Best practices
|
|
45
|
+
|
|
46
|
+
- Set `type`, `autoComplete` and `required` on every field. Browsers use them to
|
|
47
|
+
fill and validate, so the typing is the whole reason the field is typed.
|
|
48
|
+
- Keep the error to one sentence and mark the failed fields. The Alert names the
|
|
49
|
+
problem; `aria-invalid` on each input is what a screen reader announces.
|
|
50
|
+
- Disable the submit control while `pending` and pass `pendingLabel`, so the
|
|
51
|
+
reader sees that work is happening.
|
|
52
|
+
|
|
53
|
+
### Content guidelines
|
|
54
|
+
|
|
55
|
+
- The title is a short verb phrase in sentence case: "Sign in", "Continue".
|
|
56
|
+
- The description states the outcome, not a policy.
|
|
57
|
+
- An error says what to do next: "Enter your email and password to continue."
|
|
58
|
+
|
|
59
|
+
**A sign-in card with controlled fields and a submit-time error.**
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
'use client'
|
|
63
|
+
|
|
64
|
+
import { useState } from 'react'
|
|
65
|
+
|
|
66
|
+
import { AuthForm01 } from '@nanisoft/prism-ui/blocks/auth-form-01'
|
|
67
|
+
|
|
68
|
+
/** A sign-in card with controlled fields and a submit-time error. */
|
|
69
|
+
export default function AuthForm01Demo() {
|
|
70
|
+
const [email, setEmail] = useState('')
|
|
71
|
+
const [password, setPassword] = useState('')
|
|
72
|
+
const [error, setError] = useState<string>()
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<AuthForm01
|
|
76
|
+
title="Sign in"
|
|
77
|
+
description="Welcome back. Enter your details to continue."
|
|
78
|
+
error={error}
|
|
79
|
+
submitLabel="Sign in"
|
|
80
|
+
fields={[
|
|
81
|
+
{
|
|
82
|
+
id: 'auth-email',
|
|
83
|
+
label: 'Email',
|
|
84
|
+
type: 'email',
|
|
85
|
+
autoComplete: 'email',
|
|
86
|
+
placeholder: 'you@example.com',
|
|
87
|
+
value: email,
|
|
88
|
+
onChange: setEmail,
|
|
89
|
+
required: true,
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: 'auth-password',
|
|
93
|
+
label: 'Password',
|
|
94
|
+
type: 'password',
|
|
95
|
+
autoComplete: 'current-password',
|
|
96
|
+
value: password,
|
|
97
|
+
onChange: setPassword,
|
|
98
|
+
required: true,
|
|
99
|
+
},
|
|
100
|
+
]}
|
|
101
|
+
remember={{ id: 'auth-remember', label: 'Remember me for 30 days' }}
|
|
102
|
+
onSubmit={(event) => {
|
|
103
|
+
event.preventDefault()
|
|
104
|
+
setError(
|
|
105
|
+
email && password ? undefined : 'Enter your email and password to continue.',
|
|
106
|
+
)
|
|
107
|
+
}}
|
|
108
|
+
footer={
|
|
109
|
+
<p className="text-muted-foreground text-center text-sm">
|
|
110
|
+
No account yet? Create one.
|
|
111
|
+
</p>
|
|
112
|
+
}
|
|
113
|
+
/>
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Props
|
|
119
|
+
|
|
120
|
+
**`title`** `string` · required · default: —
|
|
121
|
+
**`description`** `string` · optional · default: —
|
|
122
|
+
**`fields`** `AuthFormField[]` · required · default: — — The credential fields, in order.
|
|
123
|
+
**`error`** `string` · optional · default: — — An error message shown above the fields and marked on each control.
|
|
124
|
+
**`remember`** `AuthFormRemember` · optional · default: — — A remember-me row under the fields.
|
|
125
|
+
**`submitLabel`** `string` · required · default: — — The submit button label.
|
|
126
|
+
**`pendingLabel`** `string` · optional · default: — — The label shown while `pending` is true. Falls back to `submitLabel`.
|
|
127
|
+
**`pending`** `boolean` · optional · default: — — Disables the submit control while a request is in flight.
|
|
128
|
+
**`onSubmit`** `(event: FormEvent<HTMLFormElement>) => void` · optional · default: —
|
|
129
|
+
**`footer`** `ReactNode` · optional · default: — — A row under the submit button, e.g. a link to another screen.
|
|
130
|
+
|
|
131
|
+
## Composition
|
|
132
|
+
|
|
133
|
+
**`exports`** `AuthForm01` — the public runtime names this Block promises
|
|
134
|
+
**`source`** `packages/ui/src/blocks/auth-form-01/index.tsx` — the file this Block is defined in
|
|
135
|
+
**`dependencies`** `Alert, Button, Card, Checkbox, Field, Input` — the public Prism exports this item composes
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Cta01
|
|
2
|
+
|
|
3
|
+
A closing call to action on a filled primary surface.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { Cta01 } from '@nanisoft/prism-ui/blocks/cta-01'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
Cta01 is the closing band of a page: a headline, an optional supporting line and
|
|
12
|
+
one action, on a filled primary surface. It is the last thing a reader sees, so
|
|
13
|
+
it carries exactly one decision.
|
|
14
|
+
|
|
15
|
+
The copy and the action are props. The block previously shipped the library's
|
|
16
|
+
own pitch, which described the library rather than whatever product installed
|
|
17
|
+
it.
|
|
18
|
+
|
|
19
|
+
## Guidelines
|
|
20
|
+
|
|
21
|
+
### When to use
|
|
22
|
+
|
|
23
|
+
Use Cta01 at the end of a marketing page, after the reader has seen the product
|
|
24
|
+
and is ready to act. It works when there is one clear next step.
|
|
25
|
+
|
|
26
|
+
### When not to use
|
|
27
|
+
|
|
28
|
+
Do not use it more than once on a page. A second closing band tells the reader
|
|
29
|
+
the page ended twice.
|
|
30
|
+
|
|
31
|
+
Do not use it inside an application screen. Its filled surface is a marketing
|
|
32
|
+
emphasis, and inside a task flow it competes with the working surface.
|
|
33
|
+
|
|
34
|
+
Do not use it when the action is a download or an external link with no landing
|
|
35
|
+
page. The band promises a next step; the action must deliver one.
|
|
36
|
+
|
|
37
|
+
### Best practices
|
|
38
|
+
|
|
39
|
+
- Keep the description optional and short. The headline and the action carry the
|
|
40
|
+
band.
|
|
41
|
+
- Use one action. This block takes a single action object rather than a list,
|
|
42
|
+
because two equal choices at the end of a page cancel each other out.
|
|
43
|
+
- Set `headingLevel` to match the page outline, and leave the default when the
|
|
44
|
+
band is composed under a heading the page already owns.
|
|
45
|
+
- Keep the headline shorter than the hero's. The reader has already read the
|
|
46
|
+
page; the closing line reminds rather than introduces.
|
|
47
|
+
|
|
48
|
+
### Content guidelines
|
|
49
|
+
|
|
50
|
+
- The headline states the next step, not a repeat of the page title.
|
|
51
|
+
- The description adds one concrete detail: what the reader gets, or what it
|
|
52
|
+
costs.
|
|
53
|
+
- The action label is verb-first and sentence case: "Read the guides", "Start
|
|
54
|
+
free".
|
|
55
|
+
|
|
56
|
+
**The closing band, with one action.**
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { Cta01 } from '@nanisoft/prism-ui/blocks/cta-01'
|
|
60
|
+
|
|
61
|
+
/** The closing band, with one action. */
|
|
62
|
+
export default function Cta01Demo() {
|
|
63
|
+
return (
|
|
64
|
+
<Cta01
|
|
65
|
+
headingLevel="h3"
|
|
66
|
+
title="A closing line, two lines at most"
|
|
67
|
+
description="A sentence that says what happens next, then one action."
|
|
68
|
+
action={{ label: 'Do the thing', href: '/components/button' }}
|
|
69
|
+
/>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Props
|
|
75
|
+
|
|
76
|
+
**`title`** `string` · required · default: —
|
|
77
|
+
**`description`** `string` · optional · default: —
|
|
78
|
+
**`action`** `Cta01Action` · optional · default: — — The one action this band carries. Omit it for a closing statement that asks for nothing, and use `actionSlot` for a control that is not a call to action.
|
|
79
|
+
**`actionSlot`** `ReactNode` · optional · default: — — A slot for a control the block does not own, such as a client router's link or a menu. This is what a call to action with no destination becomes: a slot the consumer fills, rather than a control the block renders and cannot make work.
|
|
80
|
+
**`secondaryAction`** `Cta01Action` · optional · default: — — The second action, rendered beside the first at outline weight. It is a prop rather than a second `action` array because `action` is the one this Block styles as the closing ask and a second action in the same weight is two closing asks; a reader who has to choose between two equally-weighted buttons has been given a menu where a page wanted a decision. Three of the four NaniSoft sites render two actions in their closing band and all four do, and all four wrote the pair by hand, so each one re-decided the gap, the order and the weight between them.
|
|
81
|
+
**`note`** `ReactNode` · optional · default: — — The line under the actions: the footnote, the caveat, the sentence that qualifies the ask. Three of the four sites render one, and each wrote it by hand. A `ReactNode` rather than a string because the honest line is sometimes not one sentence: three of the four carry a link inside it, and a string prop would force a caller to compose a paragraph to say "this is in development, here is where to watch it".
|
|
82
|
+
**`headingLevel`** `HeadingLevel` · optional · default: — — Heading level for the headline. See `HeadingLevel`.
|
|
83
|
+
|
|
84
|
+
## Composition
|
|
85
|
+
|
|
86
|
+
**`exports`** `Cta01` — the public runtime names this Block promises
|
|
87
|
+
**`source`** `packages/ui/src/blocks/cta-01/index.tsx` — the file this Block is defined in
|
|
88
|
+
**`dependencies`** `CtaLink, Section` — the public Prism exports this item composes
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# DataTable01
|
|
2
|
+
|
|
3
|
+
A table section with a toolbar, filters, row selection and pagination.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { DataTable01 } from '@nanisoft/prism-ui/blocks/data-table-01'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
DataTable01 is a table section for a paged collection: a toolbar, a search
|
|
12
|
+
field, a filter popover, optional row selection, a per-row action menu and
|
|
13
|
+
pagination. It renders the rows it is given and reports every interaction
|
|
14
|
+
through a callback.
|
|
15
|
+
|
|
16
|
+
The block composes these components:
|
|
17
|
+
|
|
18
|
+
| Part | Component | Role |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| Toolbar | Input, Button, DropdownMenu, Popover | search, filters, column visibility |
|
|
21
|
+
| Grid | Table, Checkbox | the rows, with an optional selection column |
|
|
22
|
+
| Row menu | DropdownMenu | the actions for one row |
|
|
23
|
+
| Paging | Pagination, Button | the page window and the step controls |
|
|
24
|
+
|
|
25
|
+
The block owns no data and does no filtering, sorting or fetching. The page
|
|
26
|
+
number, the search text, the filter values and the selected ids are controlled
|
|
27
|
+
props, so a server page or a client cache drives it by the same contract. When a
|
|
28
|
+
controlled prop is omitted, that interaction falls back to internal state.
|
|
29
|
+
|
|
30
|
+
## Guidelines
|
|
31
|
+
|
|
32
|
+
### When to use
|
|
33
|
+
|
|
34
|
+
Use DataTable01 for a collection a reader scans, compares and acts on. It earns
|
|
35
|
+
its space when there is more than one column, a set that pages, and at least one
|
|
36
|
+
of search, filters or row selection.
|
|
37
|
+
|
|
38
|
+
### When not to use
|
|
39
|
+
|
|
40
|
+
Do not use it for fewer than a dozen rows with no paging. A plain `Table` with a
|
|
41
|
+
heading is lighter and reads the same.
|
|
42
|
+
|
|
43
|
+
Do not hide the page's primary action in the row menu. Keep the main action on
|
|
44
|
+
the screen and reserve the menu for secondary commands.
|
|
45
|
+
|
|
46
|
+
### Best practices
|
|
47
|
+
|
|
48
|
+
- Own the data at the call site. Filter and page there, and pass only the
|
|
49
|
+
current page in, so the table stays a view rather than a state store.
|
|
50
|
+
- Give every row a stable `getRowId`. An index-based id loses the selection
|
|
51
|
+
when the page changes.
|
|
52
|
+
- Pass every string in `labels`, and reset the page to one when the search or a
|
|
53
|
+
filter changes.
|
|
54
|
+
|
|
55
|
+
### Content guidelines
|
|
56
|
+
|
|
57
|
+
- A column header is a short noun: "Account", "Seats".
|
|
58
|
+
- A row action is a verb phrase: "View details", "Rename", "Delete".
|
|
59
|
+
|
|
60
|
+
**A data table wired to local state: search, filters, selection and paging.**
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
'use client'
|
|
64
|
+
|
|
65
|
+
import { useState } from 'react'
|
|
66
|
+
|
|
67
|
+
import { Button } from '@nanisoft/prism-ui/components/button'
|
|
68
|
+
import { DataTable01, type DataTableRow } from '@nanisoft/prism-ui/blocks/data-table-01'
|
|
69
|
+
|
|
70
|
+
const ACCOUNTS: DataTableRow[] = [
|
|
71
|
+
{ id: 'northwind', name: 'Northwind', plan: 'Team', status: 'Active', seats: '24' },
|
|
72
|
+
{ id: 'contoso', name: 'Contoso', plan: 'Business', status: 'Active', seats: '86' },
|
|
73
|
+
{ id: 'fabrikam', name: 'Fabrikam', plan: 'Team', status: 'Paused', seats: '12' },
|
|
74
|
+
{ id: 'adventure', name: 'Adventure Works', plan: 'Starter', status: 'Active', seats: '4' },
|
|
75
|
+
{ id: 'litware', name: 'Litware', plan: 'Business', status: 'Active', seats: '140' },
|
|
76
|
+
{ id: 'proseware', name: 'Proseware', plan: 'Starter', status: 'Paused', seats: '7' },
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
const PAGE_SIZE = 3
|
|
80
|
+
|
|
81
|
+
/** A data table wired to local state: search, filters, selection and paging. */
|
|
82
|
+
export default function DataTable01Demo() {
|
|
83
|
+
const [query, setQuery] = useState('')
|
|
84
|
+
const [filters, setFilters] = useState<Record<string, string | undefined>>({})
|
|
85
|
+
const [selected, setSelected] = useState<string[]>([])
|
|
86
|
+
const [page, setPage] = useState(1)
|
|
87
|
+
|
|
88
|
+
const filtered = ACCOUNTS.filter((row) => {
|
|
89
|
+
const matchesQuery = String(row.name).toLowerCase().includes(query.toLowerCase())
|
|
90
|
+
const matchesStatus = !filters.status || row.status === filters.status
|
|
91
|
+
return matchesQuery && matchesStatus
|
|
92
|
+
})
|
|
93
|
+
const pageCount = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE))
|
|
94
|
+
const pageRows = filtered.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE)
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<DataTable01
|
|
98
|
+
title="Accounts"
|
|
99
|
+
description="Every workspace you can manage."
|
|
100
|
+
columns={[
|
|
101
|
+
{ id: 'name', header: 'Account', label: 'Account', cell: (row) => String(row.name) },
|
|
102
|
+
{ id: 'plan', header: 'Plan', label: 'Plan', cell: (row) => String(row.plan) },
|
|
103
|
+
{ id: 'status', header: 'Status', label: 'Status', cell: (row) => String(row.status) },
|
|
104
|
+
{
|
|
105
|
+
id: 'seats',
|
|
106
|
+
header: 'Seats',
|
|
107
|
+
label: 'Seats',
|
|
108
|
+
className: 'text-right',
|
|
109
|
+
cell: (row) => String(row.seats),
|
|
110
|
+
},
|
|
111
|
+
]}
|
|
112
|
+
rows={pageRows}
|
|
113
|
+
getRowId={(row) => String(row.id)}
|
|
114
|
+
selectable
|
|
115
|
+
selectedIds={selected}
|
|
116
|
+
onSelectedIdsChange={setSelected}
|
|
117
|
+
searchValue={query}
|
|
118
|
+
onSearchChange={(value) => {
|
|
119
|
+
setQuery(value)
|
|
120
|
+
setPage(1)
|
|
121
|
+
}}
|
|
122
|
+
filters={[
|
|
123
|
+
{
|
|
124
|
+
id: 'status',
|
|
125
|
+
label: 'Status',
|
|
126
|
+
options: [
|
|
127
|
+
{ label: 'Active', value: 'Active' },
|
|
128
|
+
{ label: 'Paused', value: 'Paused' },
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
]}
|
|
132
|
+
filterValues={filters}
|
|
133
|
+
onFilterChange={(id, value) => {
|
|
134
|
+
setFilters((previous) => ({ ...previous, [id]: value }))
|
|
135
|
+
setPage(1)
|
|
136
|
+
}}
|
|
137
|
+
page={page}
|
|
138
|
+
pageCount={pageCount}
|
|
139
|
+
onPageChange={setPage}
|
|
140
|
+
rowActions={() => [
|
|
141
|
+
{ label: 'View details' },
|
|
142
|
+
{ label: 'Rename' },
|
|
143
|
+
{ label: 'Delete', variant: 'destructive' },
|
|
144
|
+
]}
|
|
145
|
+
toolbarActions={<Button size="sm">New account</Button>}
|
|
146
|
+
labels={{
|
|
147
|
+
search: 'Search accounts',
|
|
148
|
+
filters: 'Filters',
|
|
149
|
+
reset: 'Reset filters',
|
|
150
|
+
columns: 'Columns',
|
|
151
|
+
viewColumns: 'View',
|
|
152
|
+
selectAll: 'Select every account on this page',
|
|
153
|
+
selectRow: 'Select this account',
|
|
154
|
+
rowActions: 'Account actions',
|
|
155
|
+
previous: 'Previous',
|
|
156
|
+
next: 'Next',
|
|
157
|
+
page: (value) => `Go to page ${value}`,
|
|
158
|
+
selectedCount: (count) => `${count} selected`,
|
|
159
|
+
empty: 'No accounts match the current search and filters.',
|
|
160
|
+
}}
|
|
161
|
+
/>
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Props
|
|
167
|
+
|
|
168
|
+
**`title`** `ReactNode` · optional · default: —
|
|
169
|
+
**`description`** `ReactNode` · optional · default: —
|
|
170
|
+
**`columns`** `DataTableColumn[]` · required · default: —
|
|
171
|
+
**`rows`** `DataTableRow[]` · required · default: — — The rows for the current page. The block renders them; it never fetches.
|
|
172
|
+
**`getRowId`** `(row: DataTableRow) => string` · required · default: — — Returns a stable identity for a row.
|
|
173
|
+
**`caption`** `ReactNode` · optional · default: — — Names the table for assistive technology when no heading does.
|
|
174
|
+
**`selectable`** `boolean` · optional · default: — — Adds the selection column and the selection summary.
|
|
175
|
+
**`selectedIds`** `string[]` · optional · default: —
|
|
176
|
+
**`defaultSelectedIds`** `string[]` · optional · default: —
|
|
177
|
+
**`onSelectedIdsChange`** `(ids: string[]) => void` · optional · default: —
|
|
178
|
+
**`searchValue`** `string` · optional · default: —
|
|
179
|
+
**`onSearchChange`** `(value: string) => void` · optional · default: —
|
|
180
|
+
**`filters`** `DataTableFilter[]` · optional · default: —
|
|
181
|
+
**`filterValues`** `Record<string, string | undefined>` · optional · default: —
|
|
182
|
+
**`onFilterChange`** `(id: string, value: string | undefined) => void` · optional · default: —
|
|
183
|
+
**`page`** `number` · optional · default: — — The current page, 1-based.
|
|
184
|
+
**`defaultPage`** `number` · optional · default: —
|
|
185
|
+
**`pageCount`** `number` · required · default: — — How many pages exist. At least 1.
|
|
186
|
+
**`onPageChange`** `(page: number) => void` · optional · default: —
|
|
187
|
+
**`rowActions`** `(row: DataTableRow) => DataTableRowAction[]` · optional · default: — — The per-row action menu. Return an empty array to omit the menu.
|
|
188
|
+
**`toolbarActions`** `ReactNode` · optional · default: — — Controls rendered at the end of the toolbar, e.g. a create Button.
|
|
189
|
+
**`emptyMessage`** `ReactNode` · optional · default: — — Replaces the fallback empty line.
|
|
190
|
+
**`labels`** `DataTable01Labels` · required · default: —
|
|
191
|
+
|
|
192
|
+
## Composition
|
|
193
|
+
|
|
194
|
+
**`exports`** `DataTable01` — the public runtime names this Block promises
|
|
195
|
+
**`source`** `packages/ui/src/blocks/data-table-01/index.tsx` — the file this Block is defined in
|
|
196
|
+
**`dependencies`** `Button, Checkbox, DropdownMenu, Input, Pagination, Popover, Table` — the public Prism exports this item composes
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# FeatureGrid01
|
|
2
|
+
|
|
3
|
+
A feature grid with optional icon tiles and a section heading.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { FeatureGrid01 } from '@nanisoft/prism-ui/blocks/feature-grid-01'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
FeatureGrid01 is a grid of short feature blurbs under an optional section
|
|
12
|
+
heading. Each feature carries an icon, a title and a body, and the whole list is
|
|
13
|
+
a prop.
|
|
14
|
+
|
|
15
|
+
The `variant` prop chooses between `icon` tiles and a bare `bare` layout that
|
|
16
|
+
leans on the type alone. The list was previously hardcoded, which meant an
|
|
17
|
+
installed block argued for the library inside the consumer's product; it is a
|
|
18
|
+
prop now.
|
|
19
|
+
|
|
20
|
+
## Guidelines
|
|
21
|
+
|
|
22
|
+
### When to use
|
|
23
|
+
|
|
24
|
+
Use FeatureGrid01 to summarise a small set of peer features whose blurbs are
|
|
25
|
+
short. It reads best with two to four items, and it aligns to two columns from
|
|
26
|
+
the `sm` breakpoint.
|
|
27
|
+
|
|
28
|
+
### When not to use
|
|
29
|
+
|
|
30
|
+
Do not use it for a list that is actually a set of steps. Order matters in a
|
|
31
|
+
process, and a grid communicates that order does not.
|
|
32
|
+
|
|
33
|
+
Do not use it for long descriptions. A body longer than two sentences turns the
|
|
34
|
+
grid into a wall of text; use separate sections instead.
|
|
35
|
+
|
|
36
|
+
Do not use the `icon` variant when the icons are decorative and unrelated. Use
|
|
37
|
+
`variant="bare"` so the type carries the structure.
|
|
38
|
+
|
|
39
|
+
### Best practices
|
|
40
|
+
|
|
41
|
+
- Keep every body to the same approximate length so the tiles stay the same
|
|
42
|
+
height and a reader can scan the column edges.
|
|
43
|
+
- Use two to four features. Five items leave one orphan on its own row unless the
|
|
44
|
+
grid is full-bleed.
|
|
45
|
+
- Pass a `title` only when the section needs a heading. The grid renders
|
|
46
|
+
without one, which is correct when the surrounding page already introduces it.
|
|
47
|
+
- Keep icons from `lucide-react` and give each one a distinct silhouette, so the
|
|
48
|
+
tiles are distinguishable at a glance.
|
|
49
|
+
|
|
50
|
+
### Content guidelines
|
|
51
|
+
|
|
52
|
+
- A feature title is two or three words in sentence case.
|
|
53
|
+
- A feature body is one sentence and states what the feature does for the
|
|
54
|
+
reader, not how it is implemented.
|
|
55
|
+
- Do not repeat the section description in a feature body.
|
|
56
|
+
|
|
57
|
+
**The feature grid with four neutral placeholder features.**
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
import { Blocks, Palette, ShieldCheck, Zap } from 'lucide-react'
|
|
61
|
+
|
|
62
|
+
import { FeatureGrid01 } from '@nanisoft/prism-ui/blocks/feature-grid-01'
|
|
63
|
+
|
|
64
|
+
/** The feature grid with four neutral placeholder features. */
|
|
65
|
+
export default function FeatureGrid01Demo() {
|
|
66
|
+
return (
|
|
67
|
+
<FeatureGrid01
|
|
68
|
+
headingLevel="h3"
|
|
69
|
+
eyebrow="Preview"
|
|
70
|
+
title="Section heading"
|
|
71
|
+
description="An optional line that explains what the set below it has in common."
|
|
72
|
+
features={[
|
|
73
|
+
{ icon: Palette, title: 'First item', body: 'A short sentence describing the first thing in the set.' },
|
|
74
|
+
{ icon: Blocks, title: 'Second item', body: 'A short sentence describing the second thing in the set.' },
|
|
75
|
+
{ icon: Zap, title: 'Third item', body: 'A short sentence describing the third thing in the set.' },
|
|
76
|
+
{ icon: ShieldCheck, title: 'Fourth item', body: 'A short sentence describing the fourth thing in the set.' },
|
|
77
|
+
]}
|
|
78
|
+
/>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Props
|
|
84
|
+
|
|
85
|
+
**`variant`** `'icon'` · optional · default: —
|
|
86
|
+
**`features`** `IconFeature[]` · required · default: —
|
|
87
|
+
|
|
88
|
+
## Composition
|
|
89
|
+
|
|
90
|
+
**`exports`** `FeatureGrid01` — the public runtime names this Block promises
|
|
91
|
+
**`source`** `packages/ui/src/blocks/feature-grid-01/index.tsx` — the file this Block is defined in
|
|
92
|
+
**`dependencies`** `Card, Section` — the public Prism exports this item composes
|