@nanisoft/prism-ui 0.5.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/blocks/cta-01/cta.d.ts +66 -6
- package/dist/blocks/cta-01/cta.d.ts.map +1 -1
- package/dist/blocks/cta-01/cta.js +8 -3
- package/dist/blocks/cta-01/index.d.ts +1 -0
- package/dist/blocks/cta-01/index.d.ts.map +1 -1
- package/dist/blocks/feature-grid-01/feature-grid.d.ts +57 -6
- package/dist/blocks/feature-grid-01/feature-grid.d.ts.map +1 -1
- package/dist/blocks/feature-grid-01/feature-grid.js +12 -2
- package/dist/blocks/feature-grid-01/index.d.ts +1 -0
- package/dist/blocks/feature-grid-01/index.d.ts.map +1 -1
- package/dist/blocks/hero-01/hero.d.ts +30 -1
- package/dist/blocks/hero-01/hero.d.ts.map +1 -1
- package/dist/blocks/hero-01/hero.js +14 -2
- package/dist/blocks/index.d.ts +10 -0
- package/dist/blocks/index.d.ts.map +1 -1
- package/dist/blocks/index.js +9 -0
- package/dist/blocks/instrument-panel-01/index.d.ts +3 -0
- package/dist/blocks/instrument-panel-01/index.d.ts.map +1 -0
- package/dist/blocks/instrument-panel-01/index.js +1 -0
- package/dist/blocks/instrument-panel-01/instrument-panel.d.ts +114 -0
- package/dist/blocks/instrument-panel-01/instrument-panel.d.ts.map +1 -0
- package/dist/blocks/instrument-panel-01/instrument-panel.js +64 -0
- package/dist/blocks/logo-strip-01/index.d.ts +3 -0
- package/dist/blocks/logo-strip-01/index.d.ts.map +1 -0
- package/dist/blocks/logo-strip-01/index.js +1 -0
- package/dist/blocks/logo-strip-01/logo-strip.d.ts +84 -0
- package/dist/blocks/logo-strip-01/logo-strip.d.ts.map +1 -0
- package/dist/blocks/logo-strip-01/logo-strip.js +40 -0
- package/dist/blocks/note-grid-01/index.d.ts +3 -0
- package/dist/blocks/note-grid-01/index.d.ts.map +1 -0
- package/dist/blocks/note-grid-01/index.js +1 -0
- package/dist/blocks/note-grid-01/note-grid.d.ts +79 -0
- package/dist/blocks/note-grid-01/note-grid.d.ts.map +1 -0
- package/dist/blocks/note-grid-01/note-grid.js +37 -0
- package/dist/blocks/pricing-01/pricing.js +1 -1
- package/dist/blocks/process-rail-01/index.d.ts +3 -0
- package/dist/blocks/process-rail-01/index.d.ts.map +1 -0
- package/dist/blocks/process-rail-01/index.js +1 -0
- package/dist/blocks/process-rail-01/process-rail.d.ts +99 -0
- package/dist/blocks/process-rail-01/process-rail.d.ts.map +1 -0
- package/dist/blocks/process-rail-01/process-rail.js +58 -0
- package/dist/blocks/product-grid-01/index.d.ts +3 -0
- package/dist/blocks/product-grid-01/index.d.ts.map +1 -0
- package/dist/blocks/product-grid-01/index.js +1 -0
- package/dist/blocks/product-grid-01/product-grid.d.ts +114 -0
- package/dist/blocks/product-grid-01/product-grid.d.ts.map +1 -0
- package/dist/blocks/product-grid-01/product-grid.js +51 -0
- package/dist/blocks/site-footer/index.d.ts +3 -0
- package/dist/blocks/site-footer/index.d.ts.map +1 -0
- package/dist/blocks/site-footer/index.js +1 -0
- package/dist/blocks/site-footer/site-footer.d.ts +135 -0
- package/dist/blocks/site-footer/site-footer.d.ts.map +1 -0
- package/dist/blocks/site-footer/site-footer.js +41 -0
- package/dist/blocks/site-header/index.d.ts +3 -0
- package/dist/blocks/site-header/index.d.ts.map +1 -0
- package/dist/blocks/site-header/index.js +1 -0
- package/dist/blocks/site-header/site-header.d.ts +142 -0
- package/dist/blocks/site-header/site-header.d.ts.map +1 -0
- package/dist/blocks/site-header/site-header.js +46 -0
- package/dist/blocks/stack-grid-01/index.d.ts +3 -0
- package/dist/blocks/stack-grid-01/index.d.ts.map +1 -0
- package/dist/blocks/stack-grid-01/index.js +1 -0
- package/dist/blocks/stack-grid-01/stack-grid.d.ts +118 -0
- package/dist/blocks/stack-grid-01/stack-grid.d.ts.map +1 -0
- package/dist/blocks/stack-grid-01/stack-grid.js +49 -0
- package/dist/blocks/status-ledger-01/index.d.ts +3 -0
- package/dist/blocks/status-ledger-01/index.d.ts.map +1 -0
- package/dist/blocks/status-ledger-01/index.js +1 -0
- package/dist/blocks/status-ledger-01/status-ledger.d.ts +131 -0
- package/dist/blocks/status-ledger-01/status-ledger.d.ts.map +1 -0
- package/dist/blocks/status-ledger-01/status-ledger.js +80 -0
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +180 -0
- package/dist/components/index.d.ts +11 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +6 -0
- package/dist/components/ui/card.d.ts +25 -0
- package/dist/components/ui/card.d.ts.map +1 -1
- package/dist/components/ui/card.js +25 -0
- package/dist/components/ui/cta-link.d.ts +45 -0
- package/dist/components/ui/cta-link.d.ts.map +1 -0
- package/dist/components/ui/cta-link.js +81 -0
- package/dist/components/ui/diagram.d.ts +154 -0
- package/dist/components/ui/diagram.d.ts.map +1 -0
- package/dist/components/ui/diagram.js +150 -0
- package/dist/components/ui/fact-list.d.ts +90 -0
- package/dist/components/ui/fact-list.d.ts.map +1 -0
- package/dist/components/ui/fact-list.js +38 -0
- package/dist/components/ui/product-mark.d.ts +115 -0
- package/dist/components/ui/product-mark.d.ts.map +1 -0
- package/dist/components/ui/product-mark.js +82 -0
- package/dist/components/ui/product-switcher.d.ts +108 -0
- package/dist/components/ui/product-switcher.d.ts.map +1 -0
- package/dist/components/ui/product-switcher.js +47 -0
- package/dist/components/ui/prose.d.ts +88 -0
- package/dist/components/ui/prose.d.ts.map +1 -0
- package/dist/components/ui/prose.js +53 -0
- package/dist/components/ui/section.d.ts +24 -1
- package/dist/components/ui/section.d.ts.map +1 -1
- package/dist/components/ui/section.js +11 -2
- package/dist/components/ui/slider.d.ts.map +1 -1
- package/dist/components/ui/slider.js +7 -1
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -0
- package/dist/pages/blog-post-page/index.d.ts +174 -0
- package/dist/pages/blog-post-page/index.d.ts.map +1 -0
- package/dist/pages/blog-post-page/index.js +49 -0
- package/dist/pages/docs-shell/docs-shell.d.ts +250 -0
- package/dist/pages/docs-shell/docs-shell.d.ts.map +1 -0
- package/dist/pages/docs-shell/docs-shell.js +197 -0
- package/dist/pages/docs-shell/index.d.ts +3 -0
- package/dist/pages/docs-shell/index.d.ts.map +1 -0
- package/dist/pages/docs-shell/index.js +1 -0
- package/dist/pages/index.d.ts +13 -2
- package/dist/pages/index.d.ts.map +1 -1
- package/dist/pages/index.js +10 -2
- package/dist/pages/not-found-page/index.d.ts +112 -0
- package/dist/pages/not-found-page/index.d.ts.map +1 -0
- package/dist/pages/not-found-page/index.js +46 -0
- package/dist/provider/provider.d.ts +5 -0
- package/dist/provider/provider.d.ts.map +1 -1
- package/dist/provider/provider.js +129 -38
- package/dist/provider/theme-script.d.ts +41 -3
- package/dist/provider/theme-script.d.ts.map +1 -1
- package/dist/provider/theme-script.js +68 -17
- package/dist/styles.css +555 -12
- package/dist/theming/index.d.ts +132 -2
- package/dist/theming/index.d.ts.map +1 -1
- package/dist/theming/index.js +127 -1
- package/package.json +14 -4
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { type HeadingLevel } from '../../components/ui/section';
|
|
2
|
+
/**
|
|
3
|
+
* One item of the strip, as a string.
|
|
4
|
+
*
|
|
5
|
+
* A string rather than a node, because the strip is a run of short words and a
|
|
6
|
+
* node would let a caller put a paragraph in a slot whose whole job is to be
|
|
7
|
+
* scannable in one glance. A caller with more than a few words about one item
|
|
8
|
+
* wants a `NoteGrid01` row or a `StatusLedger01` row, not a longer strip.
|
|
9
|
+
*/
|
|
10
|
+
export type LogoStripItem = string;
|
|
11
|
+
/**
|
|
12
|
+
* The props a LogoStrip01 takes.
|
|
13
|
+
*
|
|
14
|
+
* Every string is a prop and the Block ships none. There is no default list of
|
|
15
|
+
* technologies, no default list of customers and no default list of words: a
|
|
16
|
+
* strip that hardcoded any of them would hand every consumer a claim about who
|
|
17
|
+
* uses their product.
|
|
18
|
+
*/
|
|
19
|
+
export type LogoStrip01Props = {
|
|
20
|
+
/**
|
|
21
|
+
* The items, in the order a reader should meet them. Order is the caller's
|
|
22
|
+
* because it is a claim about which item matters first.
|
|
23
|
+
*/
|
|
24
|
+
items: readonly LogoStripItem[];
|
|
25
|
+
/**
|
|
26
|
+
* The strip's accessible name, for a strip that is not inside a region the
|
|
27
|
+
* reader can already name. It is rendered as the list's name and as no visible
|
|
28
|
+
* text, because the items are the visible content and a heading above them would
|
|
29
|
+
* be a heading about a heading.
|
|
30
|
+
*
|
|
31
|
+
* It is required because it is a word a reader hears. A Block that ships no copy
|
|
32
|
+
* ships no reader-facing copy either, so "Highlights" is not this Block's to
|
|
33
|
+
* choose: on one site the strip is a list of data sources and on another it is a
|
|
34
|
+
* list of capabilities, and the word that says which is the caller's.
|
|
35
|
+
*/
|
|
36
|
+
label: string;
|
|
37
|
+
/** Optional label above the section title. See the No-Default-Eyebrow Rule. */
|
|
38
|
+
eyebrow?: string;
|
|
39
|
+
/** The section title. Omit it for a strip composed under its own heading. */
|
|
40
|
+
title?: string;
|
|
41
|
+
/** One or two sentences under the title. */
|
|
42
|
+
description?: string;
|
|
43
|
+
/** Heading level for the section title. See `HeadingLevel`. */
|
|
44
|
+
headingLevel?: HeadingLevel;
|
|
45
|
+
/**
|
|
46
|
+
* Layout only, exactly as on every Component. Changing a Prism-owned visual
|
|
47
|
+
* property from here is prohibited.
|
|
48
|
+
*/
|
|
49
|
+
className?: string;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* A single line of short items: the transition band between a hero and the
|
|
53
|
+
* section that follows it.
|
|
54
|
+
*
|
|
55
|
+
* All four NaniSoft sites compose this band, immediately after the hero and
|
|
56
|
+
* before the first numbered section, and each one wrote it as the same thing: a
|
|
57
|
+
* row of three to six short phrases, separated by a middot, in muted text, with
|
|
58
|
+
* no heading at all. Four hand-written strips, four sets of site CSS, and one
|
|
59
|
+
* question each of them answered differently - whether the strip is a list, a
|
|
60
|
+
* paragraph with separators, or a decorative row of spans.
|
|
61
|
+
*
|
|
62
|
+
* It is a `ul`, so a screen reader hears how many items there are before it
|
|
63
|
+
* hears the first one. That is the whole answer to the question: a strip whose
|
|
64
|
+
* items are spans in a `div` is announced as one run of text with no count, and a
|
|
65
|
+
* reader deciding whether to keep listening has nothing to weigh.
|
|
66
|
+
*
|
|
67
|
+
* **The strip does not move.** A band of items that slides is an entrance
|
|
68
|
+
* animation, and this system has none: motion is state feedback only, shortened
|
|
69
|
+
* rather than removed under reduced motion. What the four sites actually wanted
|
|
70
|
+
* from their strips was a second, quieter statement of what the product is, and
|
|
71
|
+
* repetition of the type does that without anything moving. A strip of more than
|
|
72
|
+
* about eight items wraps onto three lines on a phone and stops being a band, so
|
|
73
|
+
* a longer set belongs in a `StackGrid01`.
|
|
74
|
+
*
|
|
75
|
+
* The items are `text-balance` so a two-word item does not break across lines
|
|
76
|
+
* where a one-word item beside it does not. There is no separator glyph between
|
|
77
|
+
* them: a middot is punctuation a screen reader reads and a sighted reader parses
|
|
78
|
+
* as content, and the gap already separates two words from two words.
|
|
79
|
+
*
|
|
80
|
+
* It is a server Component: no hook, no state, no keyframes and no client code.
|
|
81
|
+
*/
|
|
82
|
+
export declare function LogoStrip01({ items, label, eyebrow, title, description, headingLevel, className, }: LogoStrip01Props): import("react").JSX.Element | null;
|
|
83
|
+
export default LogoStrip01;
|
|
84
|
+
//# sourceMappingURL=logo-strip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logo-strip.d.ts","sourceRoot":"","sources":["../../../src/blocks/logo-strip-01/logo-strip.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAGxF;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAA;AAElC;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;;OAGG;IACH,KAAK,EAAE,SAAS,aAAa,EAAE,CAAA;IAC/B;;;;;;;;;;OAUG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,KAAK,EACL,OAAO,EACP,KAAK,EACL,WAAW,EACX,YAAmB,EACnB,SAAS,GACV,EAAE,gBAAgB,sCA+BlB;AAED,eAAe,WAAW,CAAA"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Section, SectionHeading } from '../../components/ui/section';
|
|
3
|
+
import { cn } from '../../lib/utils';
|
|
4
|
+
/**
|
|
5
|
+
* A single line of short items: the transition band between a hero and the
|
|
6
|
+
* section that follows it.
|
|
7
|
+
*
|
|
8
|
+
* All four NaniSoft sites compose this band, immediately after the hero and
|
|
9
|
+
* before the first numbered section, and each one wrote it as the same thing: a
|
|
10
|
+
* row of three to six short phrases, separated by a middot, in muted text, with
|
|
11
|
+
* no heading at all. Four hand-written strips, four sets of site CSS, and one
|
|
12
|
+
* question each of them answered differently - whether the strip is a list, a
|
|
13
|
+
* paragraph with separators, or a decorative row of spans.
|
|
14
|
+
*
|
|
15
|
+
* It is a `ul`, so a screen reader hears how many items there are before it
|
|
16
|
+
* hears the first one. That is the whole answer to the question: a strip whose
|
|
17
|
+
* items are spans in a `div` is announced as one run of text with no count, and a
|
|
18
|
+
* reader deciding whether to keep listening has nothing to weigh.
|
|
19
|
+
*
|
|
20
|
+
* **The strip does not move.** A band of items that slides is an entrance
|
|
21
|
+
* animation, and this system has none: motion is state feedback only, shortened
|
|
22
|
+
* rather than removed under reduced motion. What the four sites actually wanted
|
|
23
|
+
* from their strips was a second, quieter statement of what the product is, and
|
|
24
|
+
* repetition of the type does that without anything moving. A strip of more than
|
|
25
|
+
* about eight items wraps onto three lines on a phone and stops being a band, so
|
|
26
|
+
* a longer set belongs in a `StackGrid01`.
|
|
27
|
+
*
|
|
28
|
+
* The items are `text-balance` so a two-word item does not break across lines
|
|
29
|
+
* where a one-word item beside it does not. There is no separator glyph between
|
|
30
|
+
* them: a middot is punctuation a screen reader reads and a sighted reader parses
|
|
31
|
+
* as content, and the gap already separates two words from two words.
|
|
32
|
+
*
|
|
33
|
+
* It is a server Component: no hook, no state, no keyframes and no client code.
|
|
34
|
+
*/
|
|
35
|
+
export function LogoStrip01({ items, label, eyebrow, title, description, headingLevel = 'h2', className, }) {
|
|
36
|
+
if (items.length === 0)
|
|
37
|
+
return null;
|
|
38
|
+
return (_jsxs(Section, { className: "py-10 sm:py-14", children: [title ? (_jsx(SectionHeading, { as: headingLevel, align: "left", eyebrow: eyebrow, title: title, description: description, className: "mb-10" })) : null, _jsx("ul", { "data-slot": "logo-strip", "aria-label": items.length > 1 ? label : undefined, className: cn('text-muted-foreground flex flex-wrap items-center justify-center gap-x-4 gap-y-2 text-center text-sm', className), children: items.map((item) => (_jsx("li", { "data-slot": "logo-strip-item", className: "text-balance", children: item }, item))) })] }));
|
|
39
|
+
}
|
|
40
|
+
export default LogoStrip01;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/blocks/note-grid-01/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AACjD,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { NoteGrid01, default } from './note-grid';
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { type HeadingLevel } from '../../components/ui/section';
|
|
2
|
+
/**
|
|
3
|
+
* One note in the grid: a title and one or two sentences under it.
|
|
4
|
+
*
|
|
5
|
+
* Both are required, and a note with no title is a bullet and a note with no
|
|
6
|
+
* body is a heading. The grid is a set of titled points, and each point is
|
|
7
|
+
* short enough that neither half is optional.
|
|
8
|
+
*/
|
|
9
|
+
export type NoteGrid01Note = {
|
|
10
|
+
/**
|
|
11
|
+
* The point's title: a short noun phrase, not a sentence. The grid is scanned
|
|
12
|
+
* down its left edge, so a title that wraps to two lines costs every other row
|
|
13
|
+
* its alignment.
|
|
14
|
+
*/
|
|
15
|
+
title: string;
|
|
16
|
+
/** One or two sentences about the point. */
|
|
17
|
+
body: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* The props a NoteGrid01 takes.
|
|
21
|
+
*
|
|
22
|
+
* Every string is a prop and the Block ships none: no note, no title and no
|
|
23
|
+
* default set of arguments. A grid that hardcoded its points would hand every
|
|
24
|
+
* consumer an argument for a product that is not theirs.
|
|
25
|
+
*/
|
|
26
|
+
export type NoteGrid01Props = {
|
|
27
|
+
/** Optional label above the section title. See the No-Default-Eyebrow Rule. */
|
|
28
|
+
eyebrow?: string;
|
|
29
|
+
/** The section title. Omit it for a grid composed under its own heading. */
|
|
30
|
+
title?: string;
|
|
31
|
+
/** One or two sentences under the title. */
|
|
32
|
+
description?: string;
|
|
33
|
+
/**
|
|
34
|
+
* The notes, in the order a reader should meet them. Order is the caller's
|
|
35
|
+
* because it is a claim about which point matters first.
|
|
36
|
+
*/
|
|
37
|
+
notes: readonly NoteGrid01Note[];
|
|
38
|
+
/**
|
|
39
|
+
* The line under the grid, for the sentence that qualifies it: what the points
|
|
40
|
+
* do not cover, or where to read more.
|
|
41
|
+
*/
|
|
42
|
+
caption?: string;
|
|
43
|
+
/** Heading level for the section title. See `HeadingLevel`. */
|
|
44
|
+
headingLevel?: HeadingLevel;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* A grid of short points: a title and a sentence or two, on a hairline above each
|
|
48
|
+
* one, with no tile and no icon.
|
|
49
|
+
*
|
|
50
|
+
* Three of the four NaniSoft sites compose this section, immediately after the
|
|
51
|
+
* process rail and before the next numbered band, and each one drew it as the
|
|
52
|
+
* same thing: a multi-column set of short points, each a bold title and a short
|
|
53
|
+
* paragraph, with no card and no icon. All three also composed it *twice* - once
|
|
54
|
+
* under the rail and once under a different section - so three hand-written grids
|
|
55
|
+
* became six, each with its own column count and its own spacing.
|
|
56
|
+
*
|
|
57
|
+
* It is a `dl` rather than a grid of `div`s, because each note is a term and its
|
|
58
|
+
* explanation and a definition list is what says so. The titles are `dt`s and the
|
|
59
|
+
* bodies are `dd`s, so a screen reader announces "the title, the body" for each
|
|
60
|
+
* point rather than reading six bold words and then six paragraphs and leaving a
|
|
61
|
+
* reader to pair them up.
|
|
62
|
+
*
|
|
63
|
+
* **No tile, no icon, no badge.** The point of this section is that it carries
|
|
64
|
+
* more words than a card does, and a card's job is to carry few. A note with an
|
|
65
|
+
* icon tile in front of it reads as a feature and is read as one, and a section of
|
|
66
|
+
* twelve features is a page that argues rather than explains. Where a point wants
|
|
67
|
+
* an icon and a card, that is `FeatureGrid01`, and the two Blocks are two
|
|
68
|
+
* different jobs rather than two densities of one.
|
|
69
|
+
*
|
|
70
|
+
* The column count is two on a wide viewport and three at the largest, with four
|
|
71
|
+
* notes as the comfortable case. A note whose body runs past three lines stops
|
|
72
|
+
* being a note, so the detail belongs in the row that needs it or above the grid
|
|
73
|
+
* in `description`.
|
|
74
|
+
*
|
|
75
|
+
* It is a server Component: no hook, no state and no client code.
|
|
76
|
+
*/
|
|
77
|
+
export declare function NoteGrid01({ eyebrow, title, description, notes, caption, headingLevel, }: NoteGrid01Props): import("react").JSX.Element;
|
|
78
|
+
export default NoteGrid01;
|
|
79
|
+
//# sourceMappingURL=note-grid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"note-grid.d.ts","sourceRoot":"","sources":["../../../src/blocks/note-grid-01/note-grid.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAExF;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,KAAK,EAAE,SAAS,cAAc,EAAE,CAAA;IAChC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,YAAY,CAAA;CAC5B,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,KAAK,EACL,WAAW,EACX,KAAK,EACL,OAAO,EACP,YAAmB,GACpB,EAAE,eAAe,+BA0BjB;AAED,eAAe,UAAU,CAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Section, SectionHeading } from '../../components/ui/section';
|
|
3
|
+
/**
|
|
4
|
+
* A grid of short points: a title and a sentence or two, on a hairline above each
|
|
5
|
+
* one, with no tile and no icon.
|
|
6
|
+
*
|
|
7
|
+
* Three of the four NaniSoft sites compose this section, immediately after the
|
|
8
|
+
* process rail and before the next numbered band, and each one drew it as the
|
|
9
|
+
* same thing: a multi-column set of short points, each a bold title and a short
|
|
10
|
+
* paragraph, with no card and no icon. All three also composed it *twice* - once
|
|
11
|
+
* under the rail and once under a different section - so three hand-written grids
|
|
12
|
+
* became six, each with its own column count and its own spacing.
|
|
13
|
+
*
|
|
14
|
+
* It is a `dl` rather than a grid of `div`s, because each note is a term and its
|
|
15
|
+
* explanation and a definition list is what says so. The titles are `dt`s and the
|
|
16
|
+
* bodies are `dd`s, so a screen reader announces "the title, the body" for each
|
|
17
|
+
* point rather than reading six bold words and then six paragraphs and leaving a
|
|
18
|
+
* reader to pair them up.
|
|
19
|
+
*
|
|
20
|
+
* **No tile, no icon, no badge.** The point of this section is that it carries
|
|
21
|
+
* more words than a card does, and a card's job is to carry few. A note with an
|
|
22
|
+
* icon tile in front of it reads as a feature and is read as one, and a section of
|
|
23
|
+
* twelve features is a page that argues rather than explains. Where a point wants
|
|
24
|
+
* an icon and a card, that is `FeatureGrid01`, and the two Blocks are two
|
|
25
|
+
* different jobs rather than two densities of one.
|
|
26
|
+
*
|
|
27
|
+
* The column count is two on a wide viewport and three at the largest, with four
|
|
28
|
+
* notes as the comfortable case. A note whose body runs past three lines stops
|
|
29
|
+
* being a note, so the detail belongs in the row that needs it or above the grid
|
|
30
|
+
* in `description`.
|
|
31
|
+
*
|
|
32
|
+
* It is a server Component: no hook, no state and no client code.
|
|
33
|
+
*/
|
|
34
|
+
export function NoteGrid01({ eyebrow, title, description, notes, caption, headingLevel = 'h2', }) {
|
|
35
|
+
return (_jsxs(Section, { children: [title ? (_jsx(SectionHeading, { as: headingLevel, align: "left", eyebrow: eyebrow, title: title, description: description, className: "mb-12" })) : null, _jsx("dl", { "data-slot": "note-grid", className: "grid gap-8 sm:grid-cols-2 lg:grid-cols-3", children: notes.map((note) => (_jsxs("div", { "data-slot": "note-grid-note", className: "border-border flex flex-col gap-2 border-t pt-4", children: [_jsx("dt", { className: "text-sm font-semibold", children: note.title }), _jsx("dd", { className: "text-muted-foreground text-pretty text-sm", children: note.body })] }, note.title))) }), caption ? _jsx("p", { className: "text-muted-foreground mt-6 text-pretty text-sm", children: caption }) : null] }));
|
|
36
|
+
}
|
|
37
|
+
export default NoteGrid01;
|
|
@@ -15,6 +15,6 @@ import { Section, SectionHeading } from '../../components/ui/section';
|
|
|
15
15
|
* inherited them.
|
|
16
16
|
*/
|
|
17
17
|
export function Pricing01({ eyebrow, title, description, plans, headingLevel = 'h2', }) {
|
|
18
|
-
return (_jsxs(Section, { children: [title ? (_jsx(SectionHeading, { as: headingLevel, eyebrow: eyebrow, title: title, description: description, className: "mb-12" })) : null, _jsx("div", { className: "grid gap-6 lg:grid-cols-3", children: plans.map((plan) => (_jsxs(Card, { className: plan.featured ? 'border-primary shadow-md' : undefined, children: [_jsxs(CardHeader, { children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx(CardTitle, { children: plan.name }), plan.featured ? _jsx(Badge, { children: plan.badge
|
|
18
|
+
return (_jsxs(Section, { children: [title ? (_jsx(SectionHeading, { as: headingLevel, eyebrow: eyebrow, title: title, description: description, className: "mb-12" })) : null, _jsx("div", { className: "grid gap-6 lg:grid-cols-3", children: plans.map((plan) => (_jsxs(Card, { className: plan.featured ? 'border-primary shadow-md' : undefined, children: [_jsxs(CardHeader, { children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx(CardTitle, { children: plan.name }), plan.featured && plan.badge ? _jsx(Badge, { children: plan.badge }) : null] }), plan.body ? _jsx(CardDescription, { children: plan.body }) : null, _jsxs("p", { className: "mt-2 text-3xl font-semibold tracking-tight", children: [plan.price, plan.period ? (_jsx("span", { className: "text-muted-foreground text-sm font-normal", children: plan.period })) : null] })] }), _jsx(CardContent, { className: "flex flex-col gap-3", children: plan.features.map((feature, index) => (_jsxs("p", { className: "flex items-start gap-2 text-sm", children: [_jsx(Check, { className: "text-success mt-0.5 size-4 shrink-0" }), feature] }, index))) }), _jsx(CardFooter, { className: "mt-auto", children: _jsx(Button, { className: "w-full", variant: plan.featured ? 'default' : 'outline', children: plan.cta }) })] }, plan.name))) })] }));
|
|
19
19
|
}
|
|
20
20
|
export default Pricing01;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/blocks/process-rail-01/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACvD,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ProcessRail01, default } from './process-rail';
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { type HeadingLevel } from '../../components/ui/section';
|
|
2
|
+
/**
|
|
3
|
+
* One step of a process, as the rail draws it.
|
|
4
|
+
*
|
|
5
|
+
* `name` is the step's own name and `description` is one line about what happens
|
|
6
|
+
* there. Both are required: a rail is a sequence, and a step with no name is a
|
|
7
|
+
* divider and a step with no description is a label.
|
|
8
|
+
*/
|
|
9
|
+
export type ProcessStep = {
|
|
10
|
+
/** The name of the step, as a reader would name it in conversation. */
|
|
11
|
+
name: string;
|
|
12
|
+
/** One line about what happens at this step. */
|
|
13
|
+
description: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The number of steps a ProcessRail01 admits, as a type rather than as a runtime
|
|
17
|
+
* check.
|
|
18
|
+
*
|
|
19
|
+
* Four, and the refusal of five is the type's own work: `steps` is declared as a
|
|
20
|
+
* tuple, so a five-element array is not assignable to any arm of the union below
|
|
21
|
+
* and a four-element array is. There is no length check at render and no list
|
|
22
|
+
* that silently truncates, because a rail that quietly dropped its fifth step
|
|
23
|
+
* would be a process diagram that lied about the process.
|
|
24
|
+
*
|
|
25
|
+
* Four is the measured number, not a round one. Every NaniSoft site states a
|
|
26
|
+
* process as a rail, and every one of them states four stages: the collection
|
|
27
|
+
* line, the lakehouse path, the agent loop and the research path are four steps
|
|
28
|
+
* each, and each site drew its rail from a list of four. A fifth step is a
|
|
29
|
+
* different shape of thing and would be a second Block, taken to the open with
|
|
30
|
+
* the same evidence rather than smuggled in as a wider tuple.
|
|
31
|
+
*/
|
|
32
|
+
export type ProcessRail01Steps = readonly [ProcessStep, ProcessStep] | readonly [ProcessStep, ProcessStep, ProcessStep] | readonly [ProcessStep, ProcessStep, ProcessStep, ProcessStep];
|
|
33
|
+
/**
|
|
34
|
+
* The props a ProcessRail01 takes.
|
|
35
|
+
*
|
|
36
|
+
* Every string and every number is a prop. The Block ships no step, no ordinal
|
|
37
|
+
* and no label for the end of the rail: a process rail that hardcoded a stage
|
|
38
|
+
* name would hand every consumer a diagram of somebody else's process.
|
|
39
|
+
*/
|
|
40
|
+
export type ProcessRail01Props = {
|
|
41
|
+
/** Optional label above the section title. See the No-Default-Eyebrow Rule. */
|
|
42
|
+
eyebrow?: string;
|
|
43
|
+
/** The section title. Omit it for a rail that is composed under its own heading. */
|
|
44
|
+
title?: string;
|
|
45
|
+
/** One or two sentences under the title. */
|
|
46
|
+
description?: string;
|
|
47
|
+
/**
|
|
48
|
+
* The label on the last step, for a rail that ends in a state worth naming:
|
|
49
|
+
* "serving", "merged", "verified". Omit it when the last step needs no label,
|
|
50
|
+
* which is the honest state for a rail that has not finished.
|
|
51
|
+
*/
|
|
52
|
+
finalLabel?: string;
|
|
53
|
+
/**
|
|
54
|
+
* The steps, in the order the process runs. Two, three or four; a fifth is a
|
|
55
|
+
* type error. See `ProcessRail01Steps`.
|
|
56
|
+
*/
|
|
57
|
+
steps: ProcessRail01Steps;
|
|
58
|
+
/** Heading level for the section title. See `HeadingLevel`. */
|
|
59
|
+
headingLevel?: HeadingLevel;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* A process drawn as a rail: the steps of a pipeline, in order, on one line.
|
|
63
|
+
*
|
|
64
|
+
* All four NaniSoft sites compose this section, and each one drew it by hand
|
|
65
|
+
* with the same three parts: an ordinal per step, a name, and one caption per
|
|
66
|
+
* step, separated by hairlines with a label on the last one. This is that
|
|
67
|
+
* section, once, with the ordinal and the separation owned here rather than by
|
|
68
|
+
* four sets of site CSS.
|
|
69
|
+
*
|
|
70
|
+
* **The rail admits four steps and refuses five, in the type.** `steps` is a
|
|
71
|
+
* tuple union rather than an array, so a fifth element is a compile error and
|
|
72
|
+
* not a fifth column. The reason is that a rail is a claim about a sequence, and
|
|
73
|
+
* a rail that quietly dropped a step to fit a width would be a diagram of a
|
|
74
|
+
* process that is not the process. Four is the number every one of the four
|
|
75
|
+
* sites actually states; a longer process is a different shape and earns its own
|
|
76
|
+
* Block.
|
|
77
|
+
*
|
|
78
|
+
* The ordinal is rendered here from the step's position, zero-padded to two
|
|
79
|
+
* digits, because a sequence is the one thing the Block knows that the caller
|
|
80
|
+
* cannot be asked to state twice. Nothing else is derived: a step's name and
|
|
81
|
+
* caption are the caller's words, and `finalLabel` is the caller's word for where
|
|
82
|
+
* the rail ends.
|
|
83
|
+
*
|
|
84
|
+
* The rail is a `Section` with the system container and padding, so a page built
|
|
85
|
+
* from this Block keeps the rhythm of the Blocks around it. The steps sit on one
|
|
86
|
+
* `grid-cols-N` row whose template is written from the tuple's own length, so a
|
|
87
|
+
* three-step rail has three tracks rather than four tracks with one empty, and
|
|
88
|
+
* the hairline between two steps sits on the track boundary rather than being
|
|
89
|
+
* drawn by each step.
|
|
90
|
+
*
|
|
91
|
+
* A caption of more than about twelve words wraps under a step and the row stops
|
|
92
|
+
* reading as a line, so the caption is a line and the detail belongs above the
|
|
93
|
+
* rail in `description`.
|
|
94
|
+
*
|
|
95
|
+
* It is a server Component: no hook, no state and no client code.
|
|
96
|
+
*/
|
|
97
|
+
export declare function ProcessRail01({ eyebrow, title, description, finalLabel, steps, headingLevel, }: ProcessRail01Props): import("react").JSX.Element;
|
|
98
|
+
export default ProcessRail01;
|
|
99
|
+
//# sourceMappingURL=process-rail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-rail.d.ts","sourceRoot":"","sources":["../../../src/blocks/process-rail-01/process-rail.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAGxF;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAA;IACZ,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,kBAAkB,GAC1B,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC,GACnC,SAAS,CAAC,WAAW,EAAE,WAAW,EAAE,WAAW,CAAC,GAChD,SAAS,CAAC,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,CAAC,CAAA;AAkBjE;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,oFAAoF;IACpF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,KAAK,EAAE,kBAAkB,CAAA;IACzB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,YAAY,CAAA;CAC5B,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,KAAK,EACL,WAAW,EACX,UAAU,EACV,KAAK,EACL,YAAmB,GACpB,EAAE,kBAAkB,+BAuCpB;AAED,eAAe,aAAa,CAAA"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Section, SectionHeading } from '../../components/ui/section';
|
|
3
|
+
import { cn } from '../../lib/utils';
|
|
4
|
+
/**
|
|
5
|
+
* The grid tracks each admissible length gets, keyed on the tuple's own length.
|
|
6
|
+
*
|
|
7
|
+
* Written as Tailwind classes rather than as an inline `gridTemplateColumns`,
|
|
8
|
+
* because an inline template is a layout value in the markup where every other
|
|
9
|
+
* layout value in this package is a class, and because a class is compiled into
|
|
10
|
+
* the stylesheet while an inline style is recomputed per render. Each length is
|
|
11
|
+
* spelled out, so a two-step rail has two tracks and a four-step rail has four,
|
|
12
|
+
* and neither has an empty track at the end of the row.
|
|
13
|
+
*/
|
|
14
|
+
const TRACKS = {
|
|
15
|
+
2: 'sm:grid-cols-2',
|
|
16
|
+
3: 'sm:grid-cols-3',
|
|
17
|
+
4: 'sm:grid-cols-2 lg:grid-cols-4',
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* A process drawn as a rail: the steps of a pipeline, in order, on one line.
|
|
21
|
+
*
|
|
22
|
+
* All four NaniSoft sites compose this section, and each one drew it by hand
|
|
23
|
+
* with the same three parts: an ordinal per step, a name, and one caption per
|
|
24
|
+
* step, separated by hairlines with a label on the last one. This is that
|
|
25
|
+
* section, once, with the ordinal and the separation owned here rather than by
|
|
26
|
+
* four sets of site CSS.
|
|
27
|
+
*
|
|
28
|
+
* **The rail admits four steps and refuses five, in the type.** `steps` is a
|
|
29
|
+
* tuple union rather than an array, so a fifth element is a compile error and
|
|
30
|
+
* not a fifth column. The reason is that a rail is a claim about a sequence, and
|
|
31
|
+
* a rail that quietly dropped a step to fit a width would be a diagram of a
|
|
32
|
+
* process that is not the process. Four is the number every one of the four
|
|
33
|
+
* sites actually states; a longer process is a different shape and earns its own
|
|
34
|
+
* Block.
|
|
35
|
+
*
|
|
36
|
+
* The ordinal is rendered here from the step's position, zero-padded to two
|
|
37
|
+
* digits, because a sequence is the one thing the Block knows that the caller
|
|
38
|
+
* cannot be asked to state twice. Nothing else is derived: a step's name and
|
|
39
|
+
* caption are the caller's words, and `finalLabel` is the caller's word for where
|
|
40
|
+
* the rail ends.
|
|
41
|
+
*
|
|
42
|
+
* The rail is a `Section` with the system container and padding, so a page built
|
|
43
|
+
* from this Block keeps the rhythm of the Blocks around it. The steps sit on one
|
|
44
|
+
* `grid-cols-N` row whose template is written from the tuple's own length, so a
|
|
45
|
+
* three-step rail has three tracks rather than four tracks with one empty, and
|
|
46
|
+
* the hairline between two steps sits on the track boundary rather than being
|
|
47
|
+
* drawn by each step.
|
|
48
|
+
*
|
|
49
|
+
* A caption of more than about twelve words wraps under a step and the row stops
|
|
50
|
+
* reading as a line, so the caption is a line and the detail belongs above the
|
|
51
|
+
* rail in `description`.
|
|
52
|
+
*
|
|
53
|
+
* It is a server Component: no hook, no state and no client code.
|
|
54
|
+
*/
|
|
55
|
+
export function ProcessRail01({ eyebrow, title, description, finalLabel, steps, headingLevel = 'h2', }) {
|
|
56
|
+
return (_jsxs(Section, { children: [title ? (_jsx(SectionHeading, { as: headingLevel, align: "left", eyebrow: eyebrow, title: title, description: description, className: "mb-12" })) : null, _jsx("ol", { "data-slot": "process-rail", className: cn('grid gap-6 sm:gap-px', TRACKS[steps.length]), children: steps.map((step, index) => (_jsxs("li", { "data-slot": "process-step", className: "border-border flex flex-col gap-2 border-t pt-4", children: [_jsxs("div", { className: "flex items-baseline justify-between gap-3", children: [_jsx("span", { className: "text-muted-foreground font-mono text-xs", children: String(index + 1).padStart(2, '0') }), finalLabel && index === steps.length - 1 ? (_jsx("span", { className: "text-muted-foreground font-mono text-xs", children: finalLabel })) : null] }), _jsx("span", { className: "text-sm font-semibold", children: step.name }), _jsx("span", { className: "text-muted-foreground text-pretty text-sm", children: step.description })] }, step.name))) })] }));
|
|
57
|
+
}
|
|
58
|
+
export default ProcessRail01;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/blocks/product-grid-01/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACvD,YAAY,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ProductGrid01, default } from './product-grid';
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { type ProductMarkProps } from '../../components/ui/product-mark';
|
|
2
|
+
import { type HeadingLevel } from '../../components/ui/section';
|
|
3
|
+
/**
|
|
4
|
+
* One product in the grid, as the row draws it.
|
|
5
|
+
*
|
|
6
|
+
* The three facts the mark is drawn from, the one line under the name, and where
|
|
7
|
+
* the row goes. The mark is `ProductMark`, so a product's two-part identity is
|
|
8
|
+
* the same two colours here as it is in a switcher and on a page header.
|
|
9
|
+
*/
|
|
10
|
+
export type ProductGrid01Product = {
|
|
11
|
+
/**
|
|
12
|
+
* The product's key within the set. Carried on the markup as `data-product`
|
|
13
|
+
* through `ProductMark`, so a test can name one product rather than the first
|
|
14
|
+
* one, and two products in one document are individually addressable.
|
|
15
|
+
*/
|
|
16
|
+
id: string;
|
|
17
|
+
/**
|
|
18
|
+
* The product's own name, which is the second part of its mark. It is the
|
|
19
|
+
* anchor of the row and the first thing a reader reads.
|
|
20
|
+
*/
|
|
21
|
+
name: string;
|
|
22
|
+
/**
|
|
23
|
+
* The product's pack, which is the hue of the mark's core. Omit it, or pass
|
|
24
|
+
* `null`, for the one member of a set that has no pack of its own: that member
|
|
25
|
+
* wears the full spectrum rather than a colourless mark.
|
|
26
|
+
*/
|
|
27
|
+
pack?: ProductMarkProps['pack'];
|
|
28
|
+
/** One line about what the product is. */
|
|
29
|
+
tagline: string;
|
|
30
|
+
/**
|
|
31
|
+
* Where the row goes. Rendered as a native anchor's `href`, so the row is a
|
|
32
|
+
* link with the browser's own affordances rather than a click handler.
|
|
33
|
+
*/
|
|
34
|
+
href: string;
|
|
35
|
+
/**
|
|
36
|
+
* Opens the destination in a new browsing context, which defaults the link
|
|
37
|
+
* relationship to `noopener noreferrer`. Prism does not decide what counts as
|
|
38
|
+
* external, so the caller declares it.
|
|
39
|
+
*/
|
|
40
|
+
newTab?: boolean;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* The props a ProductGrid01 takes.
|
|
44
|
+
*
|
|
45
|
+
* Every string is a prop and the Block ships none. There is no product list in
|
|
46
|
+
* this package, no default tagline and no "built on" heading: the set of products
|
|
47
|
+
* a page lists is the page's own fact, and Prism ships the row rather than the
|
|
48
|
+
* roster.
|
|
49
|
+
*/
|
|
50
|
+
export type ProductGrid01Props = {
|
|
51
|
+
/** Optional label above the section title. See the No-Default-Eyebrow Rule. */
|
|
52
|
+
eyebrow?: string;
|
|
53
|
+
/** The section title. Omit it for a grid composed under its own heading. */
|
|
54
|
+
title?: string;
|
|
55
|
+
/** One or two sentences under the title. */
|
|
56
|
+
description?: string;
|
|
57
|
+
/**
|
|
58
|
+
* The products, in the order a reader should meet them. Order is the caller's
|
|
59
|
+
* because it is a claim about which product matters first.
|
|
60
|
+
*/
|
|
61
|
+
products: readonly ProductGrid01Product[];
|
|
62
|
+
/**
|
|
63
|
+
* The line under the grid, for the sentence that qualifies it: what the set
|
|
64
|
+
* does not include, or where to read more.
|
|
65
|
+
*/
|
|
66
|
+
caption?: string;
|
|
67
|
+
/** Heading level for the section title. See `HeadingLevel`. */
|
|
68
|
+
headingLevel?: HeadingLevel;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* A set of products as a stack of hairline rows: a two-part mark, a name, one
|
|
72
|
+
* tagline and a destination per row.
|
|
73
|
+
*
|
|
74
|
+
* All four NaniSoft sites publish this section, and each one drew it by hand with
|
|
75
|
+
* the same three parts in the same order: a colour mark for the product, the
|
|
76
|
+
* product's name, and one line about what it is, on a hairline row with the whole
|
|
77
|
+
* row a link. Each site also resolved the mark's ink in JavaScript from the live
|
|
78
|
+
* mode, which is the part that is a second source of truth: four copies of the
|
|
79
|
+
* rule that a pastel is a fill and the name is an ink, and four copies of the
|
|
80
|
+
* arithmetic that a filled dot fails contrast on a light card.
|
|
81
|
+
*
|
|
82
|
+
* **The mark is two parts, and it is `ProductMark`.** The ring is `brand-ink` and
|
|
83
|
+
* the core is the product's own `primary`, with the name in the brand ink beside
|
|
84
|
+
* it. That split is the contested shape this Block ships, and it is settled by a
|
|
85
|
+
* measurement rather than by taste: a pastel brand value is a fill and never text,
|
|
86
|
+
* so the core may be `primary` and the name may not, and a *filled* mark on a
|
|
87
|
+
* light card measures under the threshold a mark has to clear, so the mark is a
|
|
88
|
+
* hairline ring around the fill rather than a disc of it. A product row that drew
|
|
89
|
+
* a single filled dot with the name in the same value would be wrong in both
|
|
90
|
+
* directions at once, and nothing in the rendered result would say which.
|
|
91
|
+
*
|
|
92
|
+
* The pack is carried through `ProductMark` rather than set here, so the mark's
|
|
93
|
+
* own `data-pack` boundary lands on the mark and the product's hue follows from
|
|
94
|
+
* the pack the caller passed rather than from whichever pack the page is wearing.
|
|
95
|
+
* That is the half of the pack-boundary law a hand-written mark gets wrong: it
|
|
96
|
+
* resolves a colour once, at mount, from one element's computed style, and it
|
|
97
|
+
* keeps showing the old pack's values when a boundary lands above it.
|
|
98
|
+
*
|
|
99
|
+
* The row is a link, not a click handler. The whole row is an `a` with the
|
|
100
|
+
* product's `href`, so a status bar shows the destination, a context menu copies
|
|
101
|
+
* it, and middle-click opens it in a new tab. The mark is `aria-hidden` inside
|
|
102
|
+
* it, so the link is announced once, by name, rather than as a shape and a word.
|
|
103
|
+
*
|
|
104
|
+
* A row carries one line of tagline. A second line is a second paragraph and
|
|
105
|
+
* belongs above the grid in `description`, where it applies to the set rather
|
|
106
|
+
* than to one member of it.
|
|
107
|
+
*
|
|
108
|
+
* It is a server Component: no hook, no state, no client code and no mode. The
|
|
109
|
+
* mark resolves its colour through the cascade, so a page that renders this in a
|
|
110
|
+
* server file needs nothing from the provider mounted.
|
|
111
|
+
*/
|
|
112
|
+
export declare function ProductGrid01({ eyebrow, title, description, products, caption, headingLevel, }: ProductGrid01Props): import("react").JSX.Element | null;
|
|
113
|
+
export default ProductGrid01;
|
|
114
|
+
//# sourceMappingURL=product-grid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product-grid.d.ts","sourceRoot":"","sources":["../../../src/blocks/product-grid-01/product-grid.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AACrF,OAAO,EAA2B,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAExF;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC;;;;OAIG;IACH,EAAE,EAAE,MAAM,CAAA;IACV;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;;;OAIG;IACH,IAAI,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAA;IAC/B,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,QAAQ,EAAE,SAAS,oBAAoB,EAAE,CAAA;IACzC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,YAAY,CAAA;CAC5B,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,KAAK,EACL,WAAW,EACX,QAAQ,EACR,OAAO,EACP,YAAmB,GACpB,EAAE,kBAAkB,sCAqCpB;AAED,eAAe,aAAa,CAAA"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ProductMark } from '../../components/ui/product-mark';
|
|
3
|
+
import { Section, SectionHeading } from '../../components/ui/section';
|
|
4
|
+
/**
|
|
5
|
+
* A set of products as a stack of hairline rows: a two-part mark, a name, one
|
|
6
|
+
* tagline and a destination per row.
|
|
7
|
+
*
|
|
8
|
+
* All four NaniSoft sites publish this section, and each one drew it by hand with
|
|
9
|
+
* the same three parts in the same order: a colour mark for the product, the
|
|
10
|
+
* product's name, and one line about what it is, on a hairline row with the whole
|
|
11
|
+
* row a link. Each site also resolved the mark's ink in JavaScript from the live
|
|
12
|
+
* mode, which is the part that is a second source of truth: four copies of the
|
|
13
|
+
* rule that a pastel is a fill and the name is an ink, and four copies of the
|
|
14
|
+
* arithmetic that a filled dot fails contrast on a light card.
|
|
15
|
+
*
|
|
16
|
+
* **The mark is two parts, and it is `ProductMark`.** The ring is `brand-ink` and
|
|
17
|
+
* the core is the product's own `primary`, with the name in the brand ink beside
|
|
18
|
+
* it. That split is the contested shape this Block ships, and it is settled by a
|
|
19
|
+
* measurement rather than by taste: a pastel brand value is a fill and never text,
|
|
20
|
+
* so the core may be `primary` and the name may not, and a *filled* mark on a
|
|
21
|
+
* light card measures under the threshold a mark has to clear, so the mark is a
|
|
22
|
+
* hairline ring around the fill rather than a disc of it. A product row that drew
|
|
23
|
+
* a single filled dot with the name in the same value would be wrong in both
|
|
24
|
+
* directions at once, and nothing in the rendered result would say which.
|
|
25
|
+
*
|
|
26
|
+
* The pack is carried through `ProductMark` rather than set here, so the mark's
|
|
27
|
+
* own `data-pack` boundary lands on the mark and the product's hue follows from
|
|
28
|
+
* the pack the caller passed rather than from whichever pack the page is wearing.
|
|
29
|
+
* That is the half of the pack-boundary law a hand-written mark gets wrong: it
|
|
30
|
+
* resolves a colour once, at mount, from one element's computed style, and it
|
|
31
|
+
* keeps showing the old pack's values when a boundary lands above it.
|
|
32
|
+
*
|
|
33
|
+
* The row is a link, not a click handler. The whole row is an `a` with the
|
|
34
|
+
* product's `href`, so a status bar shows the destination, a context menu copies
|
|
35
|
+
* it, and middle-click opens it in a new tab. The mark is `aria-hidden` inside
|
|
36
|
+
* it, so the link is announced once, by name, rather than as a shape and a word.
|
|
37
|
+
*
|
|
38
|
+
* A row carries one line of tagline. A second line is a second paragraph and
|
|
39
|
+
* belongs above the grid in `description`, where it applies to the set rather
|
|
40
|
+
* than to one member of it.
|
|
41
|
+
*
|
|
42
|
+
* It is a server Component: no hook, no state, no client code and no mode. The
|
|
43
|
+
* mark resolves its colour through the cascade, so a page that renders this in a
|
|
44
|
+
* server file needs nothing from the provider mounted.
|
|
45
|
+
*/
|
|
46
|
+
export function ProductGrid01({ eyebrow, title, description, products, caption, headingLevel = 'h2', }) {
|
|
47
|
+
if (products.length === 0)
|
|
48
|
+
return null;
|
|
49
|
+
return (_jsxs(Section, { children: [title ? (_jsx(SectionHeading, { as: headingLevel, align: "left", eyebrow: eyebrow, title: title, description: description, className: "mb-12" })) : null, _jsx("ul", { "data-slot": "product-grid", className: "flex flex-col", children: products.map((product) => (_jsx("li", { "data-slot": "product-grid-row", className: "border-b first:border-t", children: _jsxs("a", { href: product.href, rel: product.newTab ? 'noopener noreferrer' : undefined, target: product.newTab ? '_blank' : undefined, className: "hover:bg-accent/50 focus-visible:ring-ring flex flex-col gap-1 px-2 py-4 transition-colors duration-fast ease-out sm:flex-row sm:items-baseline sm:gap-6 focus-visible:ring-[3px] focus-visible:outline-none", children: [_jsx("span", { className: "flex shrink-0 items-center sm:w-64", children: _jsx(ProductMark, { id: product.id, name: product.name, pack: product.pack, size: "md" }) }), _jsx("span", { className: "text-muted-foreground text-pretty text-sm", children: product.tagline })] }) }, product.id))) }), caption ? _jsx("p", { className: "text-muted-foreground mt-6 text-pretty text-sm", children: caption }) : null] }));
|
|
50
|
+
}
|
|
51
|
+
export default ProductGrid01;
|