@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,241 @@
|
|
|
1
|
+
# DashboardPage
|
|
2
|
+
|
|
3
|
+
A full dashboard screen composing the app shell, a page header, a KPI row and a data table.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { DashboardPage } from '@nanisoft/prism-ui/pages/dashboard-page'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
DashboardPage is a complete application screen. It composes the shell, a page
|
|
12
|
+
header, a row of key figures and a data table, and it owns the sequence and the
|
|
13
|
+
spacing only. The frame comes from the shell, the screen's name from the header,
|
|
14
|
+
the summary from the stats and the working set from the table.
|
|
15
|
+
|
|
16
|
+
The page composes these blocks:
|
|
17
|
+
|
|
18
|
+
| Region | Block | Role |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| Frame | AppShell01 | the navigation rail, the top bar and the mobile navigation sheet |
|
|
21
|
+
| Header | PageHeader01 | the trail, the page title and the page actions |
|
|
22
|
+
| Summary | Stats01 | the key figures above the table |
|
|
23
|
+
| Working set | DataTable01 | the toolbar, filters, selection and pagination |
|
|
24
|
+
|
|
25
|
+
Navigation, rows, columns, labels and every callback are props. The page fetches
|
|
26
|
+
nothing and imports no router, so the consumer owns the links and the data. The
|
|
27
|
+
table's search, page, filters and selection are controlled by the consumer, so
|
|
28
|
+
the same page can be driven by a server render or a client cache.
|
|
29
|
+
|
|
30
|
+
## Guidelines
|
|
31
|
+
|
|
32
|
+
### When to use
|
|
33
|
+
|
|
34
|
+
Use DashboardPage for the landing screen of an application, where a reader checks
|
|
35
|
+
the state of a workspace and acts on a collection. It works when the navigation
|
|
36
|
+
is stable across screens and the table is the reason the reader came.
|
|
37
|
+
|
|
38
|
+
### When not to use
|
|
39
|
+
|
|
40
|
+
Do not use it for a single-purpose screen with no collection. A dashboard with an
|
|
41
|
+
empty table is a header and a stat row around nothing; compose the header and the
|
|
42
|
+
stats directly instead.
|
|
43
|
+
|
|
44
|
+
Do not use it for a read-only report. The table's toolbar promises search,
|
|
45
|
+
filters and selection; a screen that does not offer them should not render the
|
|
46
|
+
toolbar.
|
|
47
|
+
|
|
48
|
+
### Best practices
|
|
49
|
+
|
|
50
|
+
- Pass the same navigation node to both the rail and the sheet. AppShell01 renders
|
|
51
|
+
it twice, so keep ids in the navigation unique or avoid ids there.
|
|
52
|
+
- Keep the page's own controls in the header, not the table toolbar. The header
|
|
53
|
+
action belongs to the screen; the toolbar belongs to the rows.
|
|
54
|
+
- Own the table state at the call site. Pass `page`, `searchValue`, `filterValues`
|
|
55
|
+
and `selectedIds`, and reset the page to one when the search or a filter
|
|
56
|
+
changes, so the view and the data never disagree.
|
|
57
|
+
- Give every row a stable `getRowId`. An index-based id loses the selection when
|
|
58
|
+
the page changes.
|
|
59
|
+
- Pass every string the table needs in `labels`. The page supplies none of them.
|
|
60
|
+
|
|
61
|
+
### Content guidelines
|
|
62
|
+
|
|
63
|
+
- The title names the screen: "Overview", not "View overview".
|
|
64
|
+
- A stat label is a noun phrase in sentence case, and the figure keeps one unit.
|
|
65
|
+
- A table column header is a short noun and a row action is a verb phrase.
|
|
66
|
+
|
|
67
|
+
**The dashboard page, with the shell, a header, a KPI row and a driven table.**
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
'use client'
|
|
71
|
+
|
|
72
|
+
import { useState } from 'react'
|
|
73
|
+
|
|
74
|
+
import { DashboardPage } from '@nanisoft/prism-ui/pages/dashboard-page'
|
|
75
|
+
|
|
76
|
+
const LINKS = [
|
|
77
|
+
{ href: '#dashboard', label: 'Dashboard', current: true },
|
|
78
|
+
{ href: '#projects', label: 'Projects', current: false },
|
|
79
|
+
{ href: '#team', label: 'Team', current: false },
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
const ACCOUNTS = [
|
|
83
|
+
{ id: 'northwind', name: 'Northwind', plan: 'Team', status: 'Active', seats: '24' },
|
|
84
|
+
{ id: 'contoso', name: 'Contoso', plan: 'Business', status: 'Active', seats: '86' },
|
|
85
|
+
{ id: 'fabrikam', name: 'Fabrikam', plan: 'Team', status: 'Paused', seats: '12' },
|
|
86
|
+
{ id: 'adventure', name: 'Adventure Works', plan: 'Starter', status: 'Active', seats: '4' },
|
|
87
|
+
{ id: 'litware', name: 'Litware', plan: 'Business', status: 'Active', seats: '140' },
|
|
88
|
+
{ id: 'proseware', name: 'Proseware', plan: 'Starter', status: 'Paused', seats: '7' },
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
const PAGE_SIZE = 3
|
|
92
|
+
|
|
93
|
+
/** The dashboard page, with the shell, a header, a KPI row and a driven table. */
|
|
94
|
+
export default function DashboardPageDemo() {
|
|
95
|
+
const [query, setQuery] = useState('')
|
|
96
|
+
const [filters, setFilters] = useState<Record<string, string | undefined>>({})
|
|
97
|
+
const [selected, setSelected] = useState<string[]>([])
|
|
98
|
+
const [page, setPage] = useState(1)
|
|
99
|
+
|
|
100
|
+
const filtered = ACCOUNTS.filter((row) => {
|
|
101
|
+
const matchesQuery = row.name.toLowerCase().includes(query.toLowerCase())
|
|
102
|
+
const matchesStatus = !filters.status || row.status === filters.status
|
|
103
|
+
return matchesQuery && matchesStatus
|
|
104
|
+
})
|
|
105
|
+
const pageCount = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE))
|
|
106
|
+
const pageRows = filtered.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE)
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<DashboardPage
|
|
110
|
+
shell={{
|
|
111
|
+
navigationLabel: 'Primary',
|
|
112
|
+
brand: <span className="text-sm font-semibold">Northwind</span>,
|
|
113
|
+
breadcrumbs: [{ label: 'Dashboard', href: '#dashboard' }, { label: 'Overview' }],
|
|
114
|
+
actions: (
|
|
115
|
+
<span className="bg-muted text-muted-foreground rounded-full px-3 py-1 text-xs font-medium">
|
|
116
|
+
AR
|
|
117
|
+
</span>
|
|
118
|
+
),
|
|
119
|
+
navigation: (
|
|
120
|
+
<ul className="flex flex-col gap-1 text-sm">
|
|
121
|
+
{LINKS.map((link) => (
|
|
122
|
+
<li key={link.href}>
|
|
123
|
+
<a
|
|
124
|
+
href={link.href}
|
|
125
|
+
className={
|
|
126
|
+
link.current
|
|
127
|
+
? 'bg-accent text-accent-foreground block rounded-md px-3 py-2 font-medium'
|
|
128
|
+
: 'text-muted-foreground hover:text-foreground block rounded-md px-3 py-2'
|
|
129
|
+
}
|
|
130
|
+
>
|
|
131
|
+
{link.label}
|
|
132
|
+
</a>
|
|
133
|
+
</li>
|
|
134
|
+
))}
|
|
135
|
+
</ul>
|
|
136
|
+
),
|
|
137
|
+
}}
|
|
138
|
+
header={{
|
|
139
|
+
breadcrumbs: [{ label: 'Dashboard', href: '#dashboard' }, { label: 'Overview' }],
|
|
140
|
+
title: 'Overview',
|
|
141
|
+
description: 'Accounts, usage and the people on this workspace.',
|
|
142
|
+
actions: [{ label: 'New account' }],
|
|
143
|
+
}}
|
|
144
|
+
stats={{
|
|
145
|
+
eyebrow: 'This month',
|
|
146
|
+
title: 'Delivery',
|
|
147
|
+
headingLevel: 'h2',
|
|
148
|
+
stats: [
|
|
149
|
+
{ label: 'Active accounts', value: '1,284', delta: 12, hint: 'vs last month' },
|
|
150
|
+
{ label: 'On track', value: '47.2%', delta: -3, hint: 'vs last month' },
|
|
151
|
+
{ label: 'Open issues', value: '138' },
|
|
152
|
+
],
|
|
153
|
+
}}
|
|
154
|
+
table={{
|
|
155
|
+
title: 'Accounts',
|
|
156
|
+
description: 'Every workspace you can manage.',
|
|
157
|
+
columns: [
|
|
158
|
+
{ id: 'name', header: 'Account', label: 'Account', cell: (row) => String(row.name) },
|
|
159
|
+
{ id: 'plan', header: 'Plan', label: 'Plan', cell: (row) => String(row.plan) },
|
|
160
|
+
{ id: 'status', header: 'Status', label: 'Status', cell: (row) => String(row.status) },
|
|
161
|
+
{
|
|
162
|
+
id: 'seats',
|
|
163
|
+
header: 'Seats',
|
|
164
|
+
label: 'Seats',
|
|
165
|
+
className: 'text-right',
|
|
166
|
+
cell: (row) => String(row.seats),
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
rows: pageRows,
|
|
170
|
+
getRowId: (row) => String(row.id),
|
|
171
|
+
selectable: true,
|
|
172
|
+
selectedIds: selected,
|
|
173
|
+
onSelectedIdsChange: setSelected,
|
|
174
|
+
searchValue: query,
|
|
175
|
+
onSearchChange: (value) => {
|
|
176
|
+
setQuery(value)
|
|
177
|
+
setPage(1)
|
|
178
|
+
},
|
|
179
|
+
filters: [
|
|
180
|
+
{
|
|
181
|
+
id: 'status',
|
|
182
|
+
label: 'Status',
|
|
183
|
+
options: [
|
|
184
|
+
{ label: 'Active', value: 'Active' },
|
|
185
|
+
{ label: 'Paused', value: 'Paused' },
|
|
186
|
+
],
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
filterValues: filters,
|
|
190
|
+
onFilterChange: (id, value) => {
|
|
191
|
+
setFilters((previous) => ({ ...previous, [id]: value }))
|
|
192
|
+
setPage(1)
|
|
193
|
+
},
|
|
194
|
+
page,
|
|
195
|
+
pageCount,
|
|
196
|
+
onPageChange: setPage,
|
|
197
|
+
rowActions: () => [
|
|
198
|
+
{ label: 'View details' },
|
|
199
|
+
{ label: 'Rename' },
|
|
200
|
+
{ label: 'Delete', variant: 'destructive' },
|
|
201
|
+
],
|
|
202
|
+
labels: {
|
|
203
|
+
search: 'Search accounts',
|
|
204
|
+
filters: 'Filters',
|
|
205
|
+
reset: 'Reset filters',
|
|
206
|
+
columns: 'Columns',
|
|
207
|
+
viewColumns: 'View',
|
|
208
|
+
selectAll: 'Select every account on this page',
|
|
209
|
+
selectRow: 'Select this account',
|
|
210
|
+
rowActions: 'Account actions',
|
|
211
|
+
previous: 'Previous',
|
|
212
|
+
next: 'Next',
|
|
213
|
+
page: (value) => `Go to page ${value}`,
|
|
214
|
+
selectedCount: (count) => `${count} selected`,
|
|
215
|
+
empty: 'No accounts match the current search and filters.',
|
|
216
|
+
},
|
|
217
|
+
}}
|
|
218
|
+
/>
|
|
219
|
+
)
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Props
|
|
224
|
+
|
|
225
|
+
**`shell`** `Omit<ComponentProps<typeof AppShell01>, 'children'>` · required · default: — — The frame: the navigation rail, the top bar and the mobile navigation sheet. Navigation, actions and the rail slots are passed as nodes, so the page never imports a router.
|
|
226
|
+
**`header`** `ComponentProps<typeof PageHeader01>` · required · default: — — The page title band.
|
|
227
|
+
**`stats`** `ComponentProps<typeof Stats01>` · required · default: — — The key-figure row above the table.
|
|
228
|
+
**`table`** `ComponentProps<typeof DataTable01>` · required · default: — — The main table, with its rows, columns, labels and callbacks.
|
|
229
|
+
|
|
230
|
+
## Composition
|
|
231
|
+
|
|
232
|
+
**`exports`** `DashboardPage` — the public runtime names this Page promises
|
|
233
|
+
**`source`** `packages/ui/src/pages/dashboard-page/index.tsx` — the file this Page is defined in
|
|
234
|
+
**`dependencies`** `AppShell01, DataTable01, PageHeader01, Stats01` — the public Prism exports this item composes
|
|
235
|
+
|
|
236
|
+
## Blocks
|
|
237
|
+
|
|
238
|
+
- [AppShell01](https://prism.nanisoft.com/blocks/app-shell-01.md)
|
|
239
|
+
- [DataTable01](https://prism.nanisoft.com/blocks/data-table-01.md)
|
|
240
|
+
- [PageHeader01](https://prism.nanisoft.com/blocks/page-header-01.md)
|
|
241
|
+
- [Stats01](https://prism.nanisoft.com/blocks/stats-01.md)
|
|
@@ -1,23 +1,218 @@
|
|
|
1
1
|
# DocsShell
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A documentation screen: a navigation rail whose shape arrives as data, the document at the measure, a contents rail, and a pager derived from the navigation rather than passed.
|
|
4
4
|
|
|
5
|
-
```
|
|
6
|
-
import { DocsShell } from '@nanisoft/prism-ui/pages'
|
|
5
|
+
```tsx
|
|
6
|
+
import { DocsShell } from '@nanisoft/prism-ui/pages/docs-shell'
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
DocsShell is a documentation screen: a navigation rail, the document, a contents
|
|
12
|
+
rail, and the pager to the neighbouring pages.
|
|
13
|
+
|
|
14
|
+
**It is the Page the other three NaniSoft sites import, and the name is theirs.**
|
|
15
|
+
All three already read `import { DocsShell, type DocsNavEntry } from
|
|
16
|
+
'@nanisoft/prism-ui/pages'` in their own document template, and all three map
|
|
17
|
+
their page tree into that shape in their own `lib/to-prism-tree`. A published
|
|
18
|
+
name cannot be cheaply changed and there is no redirect lane for item routes, so
|
|
19
|
+
the name follows those three import lines rather than this file's shape. It was
|
|
20
|
+
`docs-shell` in the retired line too, where it was an empty `div` and a class
|
|
21
|
+
name each site then had to style from scratch.
|
|
22
|
+
|
|
23
|
+
**The shape arrives as data.** The three sites publish full documentation sets
|
|
24
|
+
and none of them agrees on the shape:
|
|
25
|
+
|
|
26
|
+
- Nexus files six sections of five pages, each named for a documentation genre,
|
|
27
|
+
each with an index.
|
|
28
|
+
- Atlas files four sections, one of which holds nine pages under a single
|
|
29
|
+
heading, and not one of them has an index.
|
|
30
|
+
- AlphaLens files six sections separated by rules, named for subject matter
|
|
31
|
+
rather than for a genre, with a status inside three of the titles.
|
|
32
|
+
|
|
33
|
+
The tree is a prop and the Page renders it, so none of the three had to be told
|
|
34
|
+
which of the others it looks like.
|
|
35
|
+
|
|
36
|
+
## Guidelines
|
|
37
|
+
|
|
38
|
+
### When to use
|
|
39
|
+
|
|
40
|
+
Use DocsShell as the body of the route that renders one documentation page,
|
|
41
|
+
handed the page tree, the document's own outline, and the address being rendered.
|
|
42
|
+
|
|
43
|
+
Use it for every page of a documentation set. A documentation site whose pages
|
|
44
|
+
each carry their own rail is a site whose rail drifts.
|
|
45
|
+
|
|
46
|
+
### When not to use
|
|
47
|
+
|
|
48
|
+
Do not use it for a single-page site. It is a whole screen around a tree, and a
|
|
49
|
+
site with one page has no tree.
|
|
50
|
+
|
|
51
|
+
Do not use it for a blog. A post is a dated argument about one thing, and
|
|
52
|
+
`BlogPostPage` is that screen.
|
|
53
|
+
|
|
54
|
+
Do not hand it a `nav` you built by parsing a folder tree at render time. Map
|
|
55
|
+
the tree once, in your own adapter, and pass the result: a Page that walked a
|
|
56
|
+
filesystem would be a Page that fetches, and a Page imports no router and no data
|
|
57
|
+
client.
|
|
58
|
+
|
|
59
|
+
### Best practices
|
|
60
|
+
|
|
61
|
+
- **A section is a label, not a control.** It carries no status, no badge, no
|
|
62
|
+
count, no collapse and no sort, and that is the whole of its interface. AlphaLens
|
|
63
|
+
files its documentation as a pipeline, where "Unified data contract (approved)"
|
|
64
|
+
is a stage of the work and not a topic a reader may visit in any order, and
|
|
65
|
+
every structural affordance says the opposite. A status in the title is part of
|
|
66
|
+
the title and stays there as words: the Page reads no parentheses, matches no
|
|
67
|
+
vocabulary, and renders no pill beside a heading that has one.
|
|
68
|
+
- **Omit `href` on a group that has no index.** That absence is what makes the
|
|
69
|
+
heading a label rather than a route, and it is the same thing all three sites
|
|
70
|
+
already spell as `url: node.index?.url ?? ''`, which two of them then restyle
|
|
71
|
+
back into a label in their own stylesheets. Naming the case in the type makes
|
|
72
|
+
those rules dead rather than load-bearing, and the type is the only thing that
|
|
73
|
+
had to change.
|
|
74
|
+
- **Do not pass a previous and a next.** The pager is derived from `nav` and
|
|
75
|
+
`currentHref`, which removes one derivation from every consumer. It is derived
|
|
76
|
+
rather than passed for a second reason: a caller who passes neighbours can pass
|
|
77
|
+
a neighbour that is not in the tree, and this is the one arrangement where a
|
|
78
|
+
reader would notice.
|
|
79
|
+
- **Give the rail and the contents their own orders, and let both stand.** `nav`
|
|
80
|
+
is in the order the rail shows and `toc` is in the order the contents rail
|
|
81
|
+
shows. Nothing is sorted, deduplicated or alphabetised. A site that files its
|
|
82
|
+
rail as a pipeline and its contents as a reference has both in one render.
|
|
83
|
+
- Pass `toc` whole or not at all. A partial outline is a contents list that lies
|
|
84
|
+
about the page.
|
|
85
|
+
- Omit `title` when your document owns its own heading. The Page renders no empty
|
|
86
|
+
`h1` to fill the gap, so a document with no title keeps exactly the outline its
|
|
87
|
+
own content declares.
|
|
88
|
+
- Name the three regions. `navLabel`, `tocLabel` and `pagerLabel` are required
|
|
89
|
+
because they are words a reader hears, and a Page that ships no copy ships no
|
|
90
|
+
reader-facing copy either. A site that files its pages as a pipeline and its
|
|
91
|
+
contents as a reference names the three regions three different ways.
|
|
92
|
+
|
|
93
|
+
### Content guidelines
|
|
94
|
+
|
|
95
|
+
- Put a section's stage in its title, as AlphaLens does, and let it stay a
|
|
96
|
+
sentence. The Page will not pull it out into a badge for you, and a badge is a
|
|
97
|
+
state the reader can act on, which a stage of a pipeline is not.
|
|
98
|
+
- Keep a rule's title short or leave it empty. A rule with words is a label a
|
|
99
|
+
reader reads twice: once in the rule and once on the section beneath it.
|
|
100
|
+
- Keep a section index page's title the same as its section's title, so a reader
|
|
101
|
+
who arrives at the index and a reader who is already inside the section are
|
|
102
|
+
reading the same words.
|
|
103
|
+
|
|
104
|
+
**A documentation screen: the rail, the document, the contents and the pager.**
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
import { DocsShell, type DocsNavEntry } from '@nanisoft/prism-ui/pages/docs-shell'
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The shape the three consumer sites actually publish, taken from AlphaLens
|
|
111
|
+
* because it is the one that exercises every part of the interface at once: a
|
|
112
|
+
* status inside a section title, a rule between sections, and a section whose
|
|
113
|
+
* own index is a page a reader lands on.
|
|
114
|
+
*/
|
|
115
|
+
const NAV: DocsNavEntry[] = [
|
|
116
|
+
{ type: 'page', title: 'AlphaLens', href: '#alphalens' },
|
|
117
|
+
{ type: 'divider', title: 'Data platform (live)' },
|
|
118
|
+
{
|
|
119
|
+
type: 'group',
|
|
120
|
+
title: 'Data platform (live)',
|
|
121
|
+
href: '#data-platform',
|
|
122
|
+
items: [
|
|
123
|
+
{ type: 'page', title: 'Capture', href: '#capture' },
|
|
124
|
+
{ type: 'page', title: 'Storage', href: '#storage' },
|
|
125
|
+
{ type: 'page', title: 'Operations', href: '#platform-operations' },
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
{ type: 'divider', title: 'Unified data contract (approved)' },
|
|
129
|
+
{
|
|
130
|
+
type: 'group',
|
|
131
|
+
title: 'Unified data contract (approved)',
|
|
132
|
+
href: '#data-contract',
|
|
133
|
+
items: [
|
|
134
|
+
{ type: 'page', title: 'Data feed view', href: '#feed-view' },
|
|
135
|
+
{ type: 'page', title: 'Timestamps and symbols', href: '#timestamps' },
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
{ type: 'divider', title: 'Research pipeline (designed)' },
|
|
139
|
+
{
|
|
140
|
+
// No `href`: this group is a label, because its folder holds no index page.
|
|
141
|
+
type: 'group',
|
|
142
|
+
title: 'Research pipeline (designed)',
|
|
143
|
+
items: [
|
|
144
|
+
{ type: 'page', title: 'Anatomy', href: '#anatomy' },
|
|
145
|
+
{ type: 'page', title: 'NSE portability', href: '#nse-portability' },
|
|
146
|
+
],
|
|
147
|
+
},
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
/** The headings inside this page. Your own pipeline knows them; Prism does not. */
|
|
151
|
+
const TOC: DocsNavEntry[] = [
|
|
152
|
+
{ type: 'page', title: 'The capture path', href: '#the-capture-path' },
|
|
153
|
+
{ type: 'page', title: 'What the store holds', href: '#what-the-store-holds' },
|
|
154
|
+
{ type: 'page', title: 'Where this is heading', href: '#where-this-is-heading' },
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
/** A documentation screen: the rail, the document, the contents and the pager. */
|
|
158
|
+
export default function DocsShellDemo() {
|
|
159
|
+
return (
|
|
160
|
+
<DocsShell
|
|
161
|
+
title="Storage"
|
|
162
|
+
description="Where a full chain of bars lands, and how it is partitioned."
|
|
163
|
+
nav={NAV}
|
|
164
|
+
toc={TOC}
|
|
165
|
+
currentHref="#storage"
|
|
166
|
+
navLabel="AlphaLens documentation"
|
|
167
|
+
tocLabel="On this page"
|
|
168
|
+
pagerLabel="AlphaLens pages"
|
|
169
|
+
pagerLabels={{ previous: 'Previous', next: 'Next' }}
|
|
170
|
+
>
|
|
171
|
+
<p>
|
|
172
|
+
The chain is written in columnar blocks, one per session per symbol, and
|
|
173
|
+
nothing is rewritten to correct it. What lands is what the exchange sent.
|
|
174
|
+
</p>
|
|
175
|
+
<h2 id="the-capture-path">The capture path</h2>
|
|
176
|
+
<p>
|
|
177
|
+
A capture is a session and a symbol, never a whole day. A day is a
|
|
178
|
+
partition over sessions, which is what makes a backtest cheap to repeat
|
|
179
|
+
and expensive to store twice.
|
|
180
|
+
</p>
|
|
181
|
+
<h2 id="what-the-store-holds">What the store holds</h2>
|
|
182
|
+
<ul>
|
|
183
|
+
<li>Every strike, call and put, at the exchange clock.</li>
|
|
184
|
+
<li>Open interest and the implied volatility of each strike.</li>
|
|
185
|
+
<li>The index future and the spot it settled against.</li>
|
|
186
|
+
</ul>
|
|
187
|
+
<h2 id="where-this-is-heading">Where this is heading</h2>
|
|
188
|
+
<p>
|
|
189
|
+
The same path, ported to .NET, is designed rather than built. The stage it
|
|
190
|
+
is at is in its title, because a stage of a pipeline is not a topic a
|
|
191
|
+
reader may visit in any order.
|
|
192
|
+
</p>
|
|
193
|
+
</DocsShell>
|
|
194
|
+
)
|
|
195
|
+
}
|
|
196
|
+
```
|
|
10
197
|
|
|
11
198
|
## Props
|
|
12
199
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
200
|
+
**`title`** `string` · optional · default: — — The page's title, and the document's `h1`. It is optional because the three consumer sites do not agree about whether a documentation page has one: two render the frontmatter title as the page heading, and one lets the document's own Markdown own it. When it is absent the Page renders no heading at all rather than an empty one, so the document keeps exactly the outline its own content declares.
|
|
201
|
+
**`description`** `ReactNode` · optional · default: — — One or two sentences under the title: what this part of the documentation covers. A `ReactNode` because a site that files a page for a pipeline states the pipeline's stage as markup rather than as a sentence.
|
|
202
|
+
**`nav`** `readonly DocsNavEntry[]` · optional · default: — — The documentation tree, in the order a reader should meet it. The whole shape arrives here, so the Page holds no opinion about how many sections a site has, how deep they nest, or what a section is called.
|
|
203
|
+
**`toc`** `readonly DocsNavEntry[]` · optional · default: — — The headings inside this page, in document order, for the contents rail. It is the consumer's document that knows its own outline, because Prism does not parse Markdown and a Page that guessed at it would guess wrong on every document rather than on some. Pass the whole outline or none: a partial one is a contents list that lies about the page.
|
|
204
|
+
**`currentHref`** `string` · optional · default: — — The address of the page being rendered. The rail marks it with `aria-current="page"` and the pager derives its two neighbours from it, so the same navigation renders a different pager for every page without the caller deriving anything.
|
|
205
|
+
**`navLabel`** `string` · required · default: — — The accessible name of the rail. Required whenever `nav` is passed, because it is a word a reader hears and a Page that ships no copy ships no reader-facing copy either.
|
|
206
|
+
**`tocLabel`** `string` · required · default: — — The accessible name of the contents rail. Required whenever `toc` is passed, for the same reason `navLabel` is.
|
|
207
|
+
**`pagerLabel`** `string` · required · default: — — The accessible name of the pager. Required whenever there is a neighbour to reach, for the same reason `navLabel` is.
|
|
208
|
+
**`pagerLabels`** `DocsPagerLabels` · required · default: — — The two words the pager renders above the neighbouring pages' titles. Required whenever either neighbour exists, for the same reason `navLabel` is.
|
|
209
|
+
**`children`** `ReactNode` · required · default: — — The document's own body. Any flow content: paragraphs, headings, lists, code, images, tables. `Prose` holds it to the reading measure and to the block rhythm, and it is passed `fullWidth` so the document fills the column the frame gives it rather than sitting in a second measure inside one.
|
|
210
|
+
**`header`** `ReactNode` · optional · default: — — A slot above the frame, inside the container: a breadcrumb trail, a version picker, a search field. A slot rather than a prop because each of those is a Block, and a Page that took one per prop would be a Page whose interface lists the whole catalogue.
|
|
211
|
+
**`footer`** `ReactNode` · optional · default: — — A slot below the frame, inside the container: a feedback prompt, a link back to the section index, a support address.
|
|
212
|
+
**`className`** `string` · optional · default: — — Layout only, exactly as on every Component. Changing a Prism-owned visual property from here is prohibited.
|
|
213
|
+
|
|
214
|
+
## Composition
|
|
215
|
+
|
|
216
|
+
**`exports`** `DocsShell` — the public runtime names this Page promises
|
|
217
|
+
**`source`** `packages/ui/src/pages/docs-shell/index.tsx` — the file this Page is defined in
|
|
218
|
+
**`dependencies`** `Prose` — the public Prism exports this item composes
|