@cloudgrid-io/ui 0.0.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +109 -0
- package/dist/blocks/agent-prompt.d.ts +37 -0
- package/dist/blocks/agent-prompt.d.ts.map +1 -0
- package/dist/blocks/agent-prompt.js +53 -0
- package/dist/blocks/agent-prompt.js.map +1 -0
- package/dist/blocks/card-grid.d.ts +38 -0
- package/dist/blocks/card-grid.d.ts.map +1 -0
- package/dist/blocks/card-grid.js +32 -0
- package/dist/blocks/card-grid.js.map +1 -0
- package/dist/blocks/compare-table.d.ts +13 -0
- package/dist/blocks/compare-table.d.ts.map +1 -0
- package/dist/blocks/compare-table.js +55 -0
- package/dist/blocks/compare-table.js.map +1 -0
- package/dist/blocks/creation-tile.d.ts +57 -0
- package/dist/blocks/creation-tile.d.ts.map +1 -0
- package/dist/blocks/creation-tile.js +32 -0
- package/dist/blocks/creation-tile.js.map +1 -0
- package/dist/blocks/cta-banner.d.ts +31 -0
- package/dist/blocks/cta-banner.d.ts.map +1 -0
- package/dist/blocks/cta-banner.js +31 -0
- package/dist/blocks/cta-banner.js.map +1 -0
- package/dist/blocks/drop-zone.d.ts +54 -0
- package/dist/blocks/drop-zone.d.ts.map +1 -0
- package/dist/blocks/drop-zone.js +121 -0
- package/dist/blocks/drop-zone.js.map +1 -0
- package/dist/blocks/feature-cells.d.ts +46 -0
- package/dist/blocks/feature-cells.d.ts.map +1 -0
- package/dist/blocks/feature-cells.js +46 -0
- package/dist/blocks/feature-cells.js.map +1 -0
- package/dist/blocks/hub-index.d.ts +55 -0
- package/dist/blocks/hub-index.d.ts.map +1 -0
- package/dist/blocks/hub-index.js +22 -0
- package/dist/blocks/hub-index.js.map +1 -0
- package/dist/blocks/logo.d.ts +24 -0
- package/dist/blocks/logo.d.ts.map +1 -0
- package/dist/blocks/logo.js +34 -0
- package/dist/blocks/logo.js.map +1 -0
- package/dist/blocks/option-card.d.ts +31 -0
- package/dist/blocks/option-card.d.ts.map +1 -0
- package/dist/blocks/option-card.js +32 -0
- package/dist/blocks/option-card.js.map +1 -0
- package/dist/blocks/page-heading.d.ts +33 -0
- package/dist/blocks/page-heading.d.ts.map +1 -0
- package/dist/blocks/page-heading.js +30 -0
- package/dist/blocks/page-heading.js.map +1 -0
- package/dist/blocks/plug-method.d.ts +76 -0
- package/dist/blocks/plug-method.d.ts.map +1 -0
- package/dist/blocks/plug-method.js +30 -0
- package/dist/blocks/plug-method.js.map +1 -0
- package/dist/blocks/pricing-tier-cards.d.ts +47 -0
- package/dist/blocks/pricing-tier-cards.d.ts.map +1 -0
- package/dist/blocks/pricing-tier-cards.js +12 -0
- package/dist/blocks/pricing-tier-cards.js.map +1 -0
- package/dist/blocks/pricing-tiers.d.ts +29 -0
- package/dist/blocks/pricing-tiers.d.ts.map +1 -0
- package/dist/blocks/pricing-tiers.js +30 -0
- package/dist/blocks/pricing-tiers.js.map +1 -0
- package/dist/blocks/quote.d.ts +27 -0
- package/dist/blocks/quote.d.ts.map +1 -0
- package/dist/blocks/quote.js +28 -0
- package/dist/blocks/quote.js.map +1 -0
- package/dist/blocks/rich-text.d.ts +38 -0
- package/dist/blocks/rich-text.d.ts.map +1 -0
- package/dist/blocks/rich-text.js +39 -0
- package/dist/blocks/rich-text.js.map +1 -0
- package/dist/blocks/stage-panel.d.ts +5 -0
- package/dist/blocks/stage-panel.d.ts.map +1 -0
- package/dist/blocks/stage-panel.js +30 -0
- package/dist/blocks/stage-panel.js.map +1 -0
- package/dist/blocks/step-item.d.ts +24 -0
- package/dist/blocks/step-item.d.ts.map +1 -0
- package/dist/blocks/step-item.js +34 -0
- package/dist/blocks/step-item.js.map +1 -0
- package/dist/blocks/tool-logo.d.ts +15 -0
- package/dist/blocks/tool-logo.d.ts.map +1 -0
- package/dist/blocks/tool-logo.js +59 -0
- package/dist/blocks/tool-logo.js.map +1 -0
- package/dist/blocks/tool-marks.d.ts +120 -0
- package/dist/blocks/tool-marks.d.ts.map +1 -0
- package/dist/blocks/tool-marks.js +94 -0
- package/dist/blocks/tool-marks.js.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/cloudgrid-cn.d.ts +65 -0
- package/dist/lib/cloudgrid-cn.d.ts.map +1 -0
- package/dist/lib/cloudgrid-cn.js +90 -0
- package/dist/lib/cloudgrid-cn.js.map +1 -0
- package/dist/tokens/base.json +119 -38
- package/dist/tokens/surface-ink.json +63 -0
- package/dist/tokens/surface-panel.json +63 -0
- package/dist/tokens.css +115 -19
- package/dist/tokens.json +20 -2
- package/dist/ui/accordion.d.ts +7 -0
- package/dist/ui/accordion.d.ts.map +1 -0
- package/dist/ui/accordion.js +19 -0
- package/dist/ui/accordion.js.map +1 -0
- package/dist/ui/badge.d.ts +8 -0
- package/dist/ui/badge.d.ts.map +1 -0
- package/dist/ui/badge.js +34 -0
- package/dist/ui/badge.js.map +1 -0
- package/dist/ui/button.d.ts +9 -0
- package/dist/ui/button.d.ts.map +1 -0
- package/dist/ui/button.js +35 -0
- package/dist/ui/button.js.map +1 -0
- package/dist/ui/card.d.ts +12 -0
- package/dist/ui/card.d.ts.map +1 -0
- package/dist/ui/card.js +26 -0
- package/dist/ui/card.js.map +1 -0
- package/dist/ui/carousel.d.ts +37 -0
- package/dist/ui/carousel.d.ts.map +1 -0
- package/dist/ui/carousel.js +34 -0
- package/dist/ui/carousel.js.map +1 -0
- package/dist/ui/checkbox.d.ts +4 -0
- package/dist/ui/checkbox.d.ts.map +1 -0
- package/dist/ui/checkbox.js +10 -0
- package/dist/ui/checkbox.js.map +1 -0
- package/dist/ui/code-block.d.ts +9 -0
- package/dist/ui/code-block.d.ts.map +1 -0
- package/dist/ui/code-block.js +57 -0
- package/dist/ui/code-block.js.map +1 -0
- package/dist/ui/combobox.d.ts +25 -0
- package/dist/ui/combobox.d.ts.map +1 -0
- package/dist/ui/combobox.js +59 -0
- package/dist/ui/combobox.js.map +1 -0
- package/dist/ui/dialog.d.ts +18 -0
- package/dist/ui/dialog.d.ts.map +1 -0
- package/dist/ui/dialog.js +39 -0
- package/dist/ui/dialog.js.map +1 -0
- package/dist/ui/dropdown-menu.d.ts +30 -0
- package/dist/ui/dropdown-menu.d.ts.map +1 -0
- package/dist/ui/dropdown-menu.js +53 -0
- package/dist/ui/dropdown-menu.js.map +1 -0
- package/dist/ui/input-group.d.ts +19 -0
- package/dist/ui/input-group.d.ts.map +1 -0
- package/dist/ui/input-group.js +59 -0
- package/dist/ui/input-group.js.map +1 -0
- package/dist/ui/input.d.ts +4 -0
- package/dist/ui/input.d.ts.map +1 -0
- package/dist/ui/input.js +9 -0
- package/dist/ui/input.js.map +1 -0
- package/dist/ui/number-field.d.ts +10 -0
- package/dist/ui/number-field.d.ts.map +1 -0
- package/dist/ui/number-field.js +39 -0
- package/dist/ui/number-field.js.map +1 -0
- package/dist/ui/panel.d.ts +36 -0
- package/dist/ui/panel.d.ts.map +1 -0
- package/dist/ui/panel.js +39 -0
- package/dist/ui/panel.js.map +1 -0
- package/dist/ui/select.d.ts +16 -0
- package/dist/ui/select.d.ts.map +1 -0
- package/dist/ui/select.js +36 -0
- package/dist/ui/select.js.map +1 -0
- package/dist/ui/separator.d.ts +4 -0
- package/dist/ui/separator.d.ts.map +1 -0
- package/dist/ui/separator.js +9 -0
- package/dist/ui/separator.js.map +1 -0
- package/dist/ui/skeleton.d.ts +3 -0
- package/dist/ui/skeleton.d.ts.map +1 -0
- package/dist/ui/skeleton.js +7 -0
- package/dist/ui/skeleton.js.map +1 -0
- package/dist/ui/sonner.d.ts +4 -0
- package/dist/ui/sonner.d.ts.map +1 -0
- package/dist/ui/sonner.js +36 -0
- package/dist/ui/sonner.js.map +1 -0
- package/dist/ui/switch.d.ts +6 -0
- package/dist/ui/switch.d.ts.map +1 -0
- package/dist/ui/switch.js +9 -0
- package/dist/ui/switch.js.map +1 -0
- package/dist/ui/table.d.ts +11 -0
- package/dist/ui/table.d.ts.map +1 -0
- package/dist/ui/table.js +30 -0
- package/dist/ui/table.js.map +1 -0
- package/dist/ui/tabs.d.ts +11 -0
- package/dist/ui/tabs.d.ts.map +1 -0
- package/dist/ui/tabs.js +38 -0
- package/dist/ui/tabs.js.map +1 -0
- package/dist/ui/textarea.d.ts +4 -0
- package/dist/ui/textarea.d.ts.map +1 -0
- package/dist/ui/textarea.js +8 -0
- package/dist/ui/textarea.js.map +1 -0
- package/dist/ui/tooltip.d.ts +8 -0
- package/dist/ui/tooltip.d.ts.map +1 -0
- package/dist/ui/tooltip.js +37 -0
- package/dist/ui/tooltip.js.map +1 -0
- package/package.json +42 -8
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { ArrowDownIcon, TriangleAlertIcon } from "lucide-react";
|
|
5
|
+
import { cn } from "../lib/cloudgrid-cn.js";
|
|
6
|
+
/**
|
|
7
|
+
* `accept` on the input governs the PICKER only. A drag and drop hands over
|
|
8
|
+
* whatever the pointer was carrying, so without this the attribute silently
|
|
9
|
+
* means nothing on the component's primary path.
|
|
10
|
+
*/
|
|
11
|
+
function matches(item, accept) {
|
|
12
|
+
if (!accept)
|
|
13
|
+
return true;
|
|
14
|
+
const patterns = accept.split(",").map((a) => a.trim().toLowerCase()).filter(Boolean);
|
|
15
|
+
if (patterns.length === 0)
|
|
16
|
+
return true;
|
|
17
|
+
const name = item.name.toLowerCase();
|
|
18
|
+
const type = item.type.toLowerCase();
|
|
19
|
+
return patterns.some((p) => {
|
|
20
|
+
if (p.startsWith("."))
|
|
21
|
+
return name.endsWith(p);
|
|
22
|
+
if (p.endsWith("/*"))
|
|
23
|
+
return type.startsWith(p.slice(0, -1));
|
|
24
|
+
return type === p;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function DropZone({ onDrop, onReject, accept, multiple = false, disabled = false, invalid = false, title = "Drop a folder or a zip", hint = "We figure out the rest.", prompt = "Drag it here, or click to choose", name, id, className, }) {
|
|
28
|
+
const [active, setActive] = React.useState(false);
|
|
29
|
+
const [taken, setTaken] = React.useState([]);
|
|
30
|
+
const [rejected, setRejected] = React.useState(0);
|
|
31
|
+
// dragenter and dragleave fire again every time the pointer crosses onto a
|
|
32
|
+
// CHILD element, so the naive handler clears `active` while the pointer is
|
|
33
|
+
// still well inside the zone and the border flickers on every word of the
|
|
34
|
+
// label. Counting depth is the fix; `relatedTarget` is unreliable across
|
|
35
|
+
// browsers for this.
|
|
36
|
+
const depth = React.useRef(0);
|
|
37
|
+
const base = id ?? "drop-zone";
|
|
38
|
+
// The NAME is the title, not the prompt.
|
|
39
|
+
//
|
|
40
|
+
// The label wraps only the target area, so without this the accessible name
|
|
41
|
+
// came out as "Drag it here, or click to choose": an instruction about a
|
|
42
|
+
// pointer gesture, read to someone who is not using one. The title says what
|
|
43
|
+
// the control is for, which is what a name is supposed to do. Verified with a
|
|
44
|
+
// real Tab press rather than a programmatic focus, since `.focus()` does not
|
|
45
|
+
// trigger :focus-visible and would have hidden the ring.
|
|
46
|
+
const describedBy = [hint ? `${base}-hint` : null, `${base}-prompt`, `${base}-status`]
|
|
47
|
+
.filter(Boolean)
|
|
48
|
+
.join(" ");
|
|
49
|
+
function accept_(incoming) {
|
|
50
|
+
const ok = accept ? incoming.filter((f) => matches(f, accept)) : incoming;
|
|
51
|
+
const no = incoming.length - ok.length;
|
|
52
|
+
const kept = multiple ? ok : ok.slice(0, 1);
|
|
53
|
+
setTaken(kept);
|
|
54
|
+
setRejected(no);
|
|
55
|
+
if (kept.length)
|
|
56
|
+
onDrop?.(kept);
|
|
57
|
+
if (no && onReject)
|
|
58
|
+
onReject(incoming.filter((f) => !matches(f, accept)));
|
|
59
|
+
}
|
|
60
|
+
const bad = invalid || (rejected > 0 && taken.length === 0);
|
|
61
|
+
return (_jsxs("div", { "data-slot": "drop-zone", className: cn("grid gap-2", className), children: [_jsxs("div", { className: "grid gap-1 text-center", children: [_jsx("span", { id: `${base}-title`, className: "font-display text-display-sm text-balance uppercase text-foreground", children: title }), hint ? (_jsx("span", { id: `${base}-hint`, className: "text-body-sm text-muted-foreground", children: hint })) : null] }), _jsxs("label", { "data-slot": "drop-zone-target", "data-active": active || undefined, "data-invalid": bad || undefined, "data-disabled": disabled || undefined, onDragEnter: (e) => {
|
|
62
|
+
if (disabled)
|
|
63
|
+
return;
|
|
64
|
+
e.preventDefault();
|
|
65
|
+
depth.current += 1;
|
|
66
|
+
setActive(true);
|
|
67
|
+
}, onDragOver: (e) => {
|
|
68
|
+
// Without preventDefault here the browser refuses the drop entirely
|
|
69
|
+
// and the cursor shows "no entry" over a zone that looks ready.
|
|
70
|
+
if (disabled)
|
|
71
|
+
return;
|
|
72
|
+
e.preventDefault();
|
|
73
|
+
}, onDragLeave: () => {
|
|
74
|
+
if (disabled)
|
|
75
|
+
return;
|
|
76
|
+
depth.current -= 1;
|
|
77
|
+
if (depth.current <= 0) {
|
|
78
|
+
depth.current = 0;
|
|
79
|
+
setActive(false);
|
|
80
|
+
}
|
|
81
|
+
}, onDrop: (e) => {
|
|
82
|
+
if (disabled)
|
|
83
|
+
return;
|
|
84
|
+
e.preventDefault();
|
|
85
|
+
depth.current = 0;
|
|
86
|
+
setActive(false);
|
|
87
|
+
accept_(Array.from(e.dataTransfer.files));
|
|
88
|
+
}, className: cn("group/drop relative grid cursor-pointer place-items-center gap-4 rounded-xl px-6 py-14 text-center",
|
|
89
|
+
// Brand at rest, quietly. `border-ring` is --cg-text-accent, so this is
|
|
90
|
+
// purple at 30% on white, white on the panel, lime on ink. A neutral grey
|
|
91
|
+
// hairline here is what made the first version read as an unstyled default:
|
|
92
|
+
// nothing on the component said which product it belonged to.
|
|
93
|
+
"border-2 border-dashed border-ring/30 bg-current/[0.02]", "transition-[background-color,border-color,transform] duration-200 motion-reduce:transition-none", "hover:border-ring/60 hover:bg-current/[0.04]", "has-[input:focus-visible]:border-ring has-[input:focus-visible]:ring-3 has-[input:focus-visible]:ring-ring",
|
|
94
|
+
// Dragging over is the moment the thing is about to land, so the target
|
|
95
|
+
// stops suggesting and commits: the dash closes into a solid rule and the
|
|
96
|
+
// fill steps up. A colour change alone did not read as a state change.
|
|
97
|
+
"data-active:border-solid data-active:border-ring data-active:bg-current/[0.07]", "data-invalid:border-destructive data-invalid:text-destructive", "data-disabled:cursor-not-allowed data-disabled:opacity-50",
|
|
98
|
+
// Tactile: the whole target gives under the press rather than only the
|
|
99
|
+
// cursor changing.
|
|
100
|
+
"active:scale-[0.995] data-disabled:active:scale-100"), children: [_jsx("input", { type: "file", name: name, id: id, accept: accept, multiple: multiple, disabled: disabled, "aria-labelledby": `${base}-title`, "aria-describedby": describedBy, "aria-invalid": bad || undefined, className: "sr-only", onChange: (e) => accept_(Array.from(e.target.files ?? [])) }), _jsx("span", { "aria-hidden": true, className: cn("grid size-12 place-items-center rounded-full transition-[background-color,transform] duration-200 motion-reduce:transition-none", "bg-current/[0.07] group-hover/drop:scale-105", "group-data-active/drop:scale-110 group-data-active/drop:bg-current/[0.14]",
|
|
101
|
+
// NOT `text-accent`. In shadcn's vocabulary `--accent` is a SURFACE
|
|
102
|
+
// (`--cg-surface-subtle`, #f2f1f7), so `text-accent` paints this glyph
|
|
103
|
+
// near-white on a white page. It shipped that way in the first pass and
|
|
104
|
+
// read as a washed-out grey arrow, which is what the operator spotted.
|
|
105
|
+
// Rule 4 in CLAUDE.md, met the hard way.
|
|
106
|
+
//
|
|
107
|
+
// The house form for the flipping accent is a direct reference, as in
|
|
108
|
+
// logo.tsx, option-card.tsx and card-grid.tsx: there is no `--color-*`
|
|
109
|
+
// utility for `--cg-text-accent`. `text-ring` resolves to the same value
|
|
110
|
+
// through the bridge and was used here first, but one spelling per
|
|
111
|
+
// concept is worth more than saving eight characters.
|
|
112
|
+
bad ? "text-destructive" : "text-(--cg-text-accent)"), children: bad ? _jsx(TriangleAlertIcon, { className: "size-5" }) : _jsx(ArrowDownIcon, { className: "size-5" }) }), _jsx("span", { id: `${base}-prompt`, className: "text-body-sm text-muted-foreground", children: prompt })] }), _jsx("span", { id: `${base}-status`, role: bad ? "alert" : undefined, "aria-live": "polite", className: cn("text-caption", bad ? "text-destructive" : "text-faint"), children: taken.length === 1
|
|
113
|
+
? taken[0].name
|
|
114
|
+
: taken.length > 1
|
|
115
|
+
? `${taken.length} ready`
|
|
116
|
+
: rejected > 0
|
|
117
|
+
? `${rejected} not the right kind`
|
|
118
|
+
: "" })] }));
|
|
119
|
+
}
|
|
120
|
+
export { DropZone };
|
|
121
|
+
//# sourceMappingURL=drop-zone.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drop-zone.js","sourceRoot":"","sources":["../../src/blocks/drop-zone.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Two kinds of q/a list, in two voices. Ported from v0's `core/FeatureCells`.
|
|
3
|
+
*
|
|
4
|
+
* `tiles` is for capabilities: tinted cells with a species glyph picked from the
|
|
5
|
+
* copy itself, so a database row wears a database and an AI row a spark.
|
|
6
|
+
* `ledger` is for promises: numbered cells over hairlines. The numbering is honest
|
|
7
|
+
* structure, because the copy reads as a sequence of commitments rather than a
|
|
8
|
+
* feature race.
|
|
9
|
+
*
|
|
10
|
+
* ## Icons are lucide here, not Phosphor
|
|
11
|
+
*
|
|
12
|
+
* v0 inlined ten Phosphor SVGs as raw strings, because Astro can import SVG via
|
|
13
|
+
* Vite's `?raw` and React bundlers cannot, and rendered them with
|
|
14
|
+
* `dangerouslySetInnerHTML`. Two reasons not to carry that over: this registry
|
|
15
|
+
* declares `iconLibrary: lucide` and already depends on `lucide-react`, so
|
|
16
|
+
* Phosphor strings would put a second icon vocabulary in the library; and
|
|
17
|
+
* `dangerouslySetInnerHTML` for decoration is a sharp tool used for nothing. The
|
|
18
|
+
* lucide equivalents are close in weight and monoline, which is the system's rule
|
|
19
|
+
* for icons.
|
|
20
|
+
*
|
|
21
|
+
* ## The matcher, and its escape hatch
|
|
22
|
+
*
|
|
23
|
+
* Matching English keywords in the copy to choose a glyph is the component's
|
|
24
|
+
* charm and it is `aria-hidden` decoration, so a wrong guess costs nothing. But it
|
|
25
|
+
* is unpredictable against a consumer's copy rather than the site's, so each item
|
|
26
|
+
* can name its own `icon` and skip the guessing.
|
|
27
|
+
*
|
|
28
|
+
* v0's `data-reveal-group="rise"` is dropped: it is the site's scroll-animation
|
|
29
|
+
* hook, and a registry component should not carry one consumer's animation
|
|
30
|
+
* vocabulary. Pass it through `...props` if you want it.
|
|
31
|
+
*/
|
|
32
|
+
type FeatureCellsItem = {
|
|
33
|
+
q: string;
|
|
34
|
+
a: string;
|
|
35
|
+
/** Skip the keyword matcher and name the glyph. */
|
|
36
|
+
icon?: React.ComponentType<{
|
|
37
|
+
className?: string;
|
|
38
|
+
}>;
|
|
39
|
+
};
|
|
40
|
+
declare function FeatureCells({ items, variant, className, ...props }: Omit<React.ComponentProps<"ul">, "ref"> & {
|
|
41
|
+
items: FeatureCellsItem[];
|
|
42
|
+
variant?: "tiles" | "ledger";
|
|
43
|
+
}): import("react").JSX.Element;
|
|
44
|
+
export { FeatureCells };
|
|
45
|
+
export type { FeatureCellsItem };
|
|
46
|
+
//# sourceMappingURL=feature-cells.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-cells.d.ts","sourceRoot":"","sources":["../../src/blocks/feature-cells.tsx"],"names":[],"mappings":"AAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,KAAK,gBAAgB,GAAG;IACtB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,mDAAmD;IACnD,IAAI,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACnD,CAAA;AA+BD,iBAAS,YAAY,CAAC,EACpB,KAAK,EACL,OAAiB,EACjB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,GAAG;IAC3C,KAAK,EAAE,gBAAgB,EAAE,CAAA;IACzB,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;CAC7B,+BA4DA;AAED,OAAO,EAAE,YAAY,EAAE,CAAA;AACvB,YAAY,EAAE,gBAAgB,EAAE,CAAA"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Brain, Clock, Database, Globe, HardDrive, KeyRound, Plug, Sparkles, Users, Zap, } from "lucide-react";
|
|
3
|
+
import { cn } from "../lib/cloudgrid-cn.js";
|
|
4
|
+
const MATCHERS = [
|
|
5
|
+
[/\bai\b|model|gateway/i, Sparkles],
|
|
6
|
+
[/database|postgres/i, Database],
|
|
7
|
+
[/storage|files?\b/i, HardDrive],
|
|
8
|
+
[/memory|brain/i, Brain],
|
|
9
|
+
[/live|url|domain/i, Globe],
|
|
10
|
+
[/key|sign-?in|auth|secret/i, KeyRound],
|
|
11
|
+
[/cron|schedule|clock/i, Clock],
|
|
12
|
+
[/found|shared|picked|player|people/i, Users],
|
|
13
|
+
[/cache|fast|instant/i, Zap],
|
|
14
|
+
];
|
|
15
|
+
function glyphFor(item) {
|
|
16
|
+
if (item.icon)
|
|
17
|
+
return item.icon;
|
|
18
|
+
const text = `${item.q} ${item.a}`;
|
|
19
|
+
return MATCHERS.find(([re]) => re.test(text))?.[1] ?? Plug;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The three-tint cycle. Tints are mixed against the page surface rather than
|
|
23
|
+
* declared as flat colours, so they stay tints of the brand rather than a fourth
|
|
24
|
+
* palette to maintain.
|
|
25
|
+
*/
|
|
26
|
+
const TINTS = [
|
|
27
|
+
{ cell: "bg-brand-tint", glyph: "text-brand" },
|
|
28
|
+
{ cell: "bg-[color-mix(in_srgb,var(--cg-tertiary)_14%,var(--cg-surface-page))]", glyph: "text-cyan" },
|
|
29
|
+
{ cell: "bg-[color-mix(in_srgb,var(--cg-secondary)_18%,var(--cg-surface-page))]", glyph: "text-lime" },
|
|
30
|
+
];
|
|
31
|
+
function FeatureCells({ items, variant = "tiles", className, ...props }) {
|
|
32
|
+
if (variant === "ledger") {
|
|
33
|
+
return (_jsx("ol", {
|
|
34
|
+
// role="list" is explicit for the same reason it is on StepList: WebKit
|
|
35
|
+
// drops the implicit list role when list-style is none, and here the
|
|
36
|
+
// numbering IS the content rather than decoration.
|
|
37
|
+
role: "list", "data-slot": "feature-cells", className: cn("m-0 list-none p-0", className), ...props, children: items.map((item, i) => (_jsxs("li", { className: "flex gap-4 border-t border-hairline py-5 first:border-t-0", children: [_jsx("span", { "aria-hidden": "true", className: "font-mono text-mono text-faint", children: String(i + 1).padStart(2, "0") }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("p", { className: "m-0 text-heading-sm font-medium text-ink", children: item.q }), _jsx("p", { className: "m-0 text-body-sm text-body", children: item.a })] })] }, item.q))) }));
|
|
38
|
+
}
|
|
39
|
+
return (_jsx("ul", { role: "list", "data-slot": "feature-cells", className: cn("m-0 grid list-none grid-cols-1 gap-5 p-0 sm:grid-cols-2 lg:grid-cols-3", className), ...props, children: items.map((item, i) => {
|
|
40
|
+
const Glyph = glyphFor(item);
|
|
41
|
+
const tint = TINTS[i % TINTS.length];
|
|
42
|
+
return (_jsxs("li", { className: cn("flex flex-col gap-3 rounded-xl border border-transparent p-6 transition-all", "hover:border-line-accent hover:shadow-hover", tint.cell), children: [_jsx("span", { "aria-hidden": "true", className: cn("inline-flex size-10 items-center", tint.glyph), children: _jsx(Glyph, { className: "size-[22px]" }) }), _jsx("p", { className: "m-0 text-heading-sm font-medium text-ink", children: item.q }), _jsx("p", { className: "m-0 text-body-sm text-body", children: item.a })] }, item.q));
|
|
43
|
+
}) }));
|
|
44
|
+
}
|
|
45
|
+
export { FeatureCells };
|
|
46
|
+
//# sourceMappingURL=feature-cells.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-cells.js","sourceRoot":"","sources":["../../src/blocks/feature-cells.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared renderer for hub index pages. Ported from v0's `site/HubIndex`.
|
|
3
|
+
*
|
|
4
|
+
* The layout is the least of it. What matters is the two rules it encodes, both of
|
|
5
|
+
* which are easy to lose in a rewrite and neither of which is obvious from the
|
|
6
|
+
* markup.
|
|
7
|
+
*
|
|
8
|
+
* **A group may name something that does not exist yet.** Groups list slugs;
|
|
9
|
+
* only slugs that actually built survive the filter, and a group left with nothing
|
|
10
|
+
* disappears. That is what makes launching one item a one-line change to the route
|
|
11
|
+
* filter rather than an edit here.
|
|
12
|
+
*
|
|
13
|
+
* **Nothing orphans.** Anything the groups do not claim is still rendered, in its
|
|
14
|
+
* own trailing group. Without that, adding an item and forgetting to list it in a
|
|
15
|
+
* group makes it silently unreachable, which is the exact failure this page exists
|
|
16
|
+
* to prevent.
|
|
17
|
+
*
|
|
18
|
+
* ## The tile mark is a render prop
|
|
19
|
+
*
|
|
20
|
+
* v0 called `<ToolLogo name={...} />` directly. That component is held pending a
|
|
21
|
+
* trademark question (#47), and the coupling was wrong regardless: the /make hub
|
|
22
|
+
* lists things rather than tools and wears species glyphs, while /from lists tools
|
|
23
|
+
* and wears brand marks. One component, two vocabularies, so the caller supplies
|
|
24
|
+
* it. Omit `renderMark` and the tiles are text, which reads fine.
|
|
25
|
+
*
|
|
26
|
+
* `data-cta` and `data-reveal-group` are dropped, as elsewhere.
|
|
27
|
+
*/
|
|
28
|
+
type HubGroup = {
|
|
29
|
+
title: string;
|
|
30
|
+
lead: string;
|
|
31
|
+
items: string[];
|
|
32
|
+
};
|
|
33
|
+
type Hub = {
|
|
34
|
+
h1: string;
|
|
35
|
+
intro: string;
|
|
36
|
+
groups?: HubGroup[];
|
|
37
|
+
/** Preferred order by slug. Anything absent sorts after, then alphabetically. */
|
|
38
|
+
order: string[];
|
|
39
|
+
/** Slug to display name. */
|
|
40
|
+
names: Record<string, string>;
|
|
41
|
+
};
|
|
42
|
+
declare function HubIndex({ hub, base, items, renderMark, className, ...props }: Omit<React.ComponentProps<"section">, "ref"> & {
|
|
43
|
+
hub: Hub;
|
|
44
|
+
/** URL prefix for a tile, joined as `${base}/${id}`. */
|
|
45
|
+
base: string;
|
|
46
|
+
items: {
|
|
47
|
+
id: string;
|
|
48
|
+
h1: string;
|
|
49
|
+
}[];
|
|
50
|
+
/** The mark for a tile, by display name. */
|
|
51
|
+
renderMark?: (name: string) => React.ReactNode;
|
|
52
|
+
}): import("react").JSX.Element;
|
|
53
|
+
export { HubIndex };
|
|
54
|
+
export type { Hub, HubGroup };
|
|
55
|
+
//# sourceMappingURL=hub-index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hub-index.d.ts","sourceRoot":"","sources":["../../src/blocks/hub-index.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,KAAK,QAAQ,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAAA;AAEhE,KAAK,GAAG,GAAG;IACT,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAA;IACnB,iFAAiF;IACjF,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC9B,CAAA;AAED,iBAAS,QAAQ,CAAC,EAChB,GAAG,EACH,IAAI,EACJ,KAAK,EACL,UAAU,EACV,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,GAAG;IAChD,GAAG,EAAE,GAAG,CAAA;IACR,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACnC,4CAA4C;IAC5C,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAA;CAC/C,+BAqDA;AAED,OAAO,EAAE,QAAQ,EAAE,CAAA;AACnB,YAAY,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { PageHeading } from "./page-heading.js";
|
|
3
|
+
import { cn } from "../lib/cloudgrid-cn.js";
|
|
4
|
+
function HubIndex({ hub, base, items, renderMark, className, ...props }) {
|
|
5
|
+
const rank = (id) => {
|
|
6
|
+
const i = hub.order.indexOf(id);
|
|
7
|
+
return i === -1 ? hub.order.length : i;
|
|
8
|
+
};
|
|
9
|
+
const sorted = [...items].sort((a, b) => rank(a.id) - rank(b.id) || a.id.localeCompare(b.id));
|
|
10
|
+
const label = (id) => hub.names[id] ?? id;
|
|
11
|
+
const built = new Set(sorted.map((item) => item.id));
|
|
12
|
+
const groups = (hub.groups ?? [])
|
|
13
|
+
.map((group) => ({ ...group, items: group.items.filter((id) => built.has(id)) }))
|
|
14
|
+
.filter((group) => group.items.length > 0);
|
|
15
|
+
const grouped = new Set(groups.flatMap((group) => group.items));
|
|
16
|
+
const ungrouped = sorted.filter((item) => !grouped.has(item.id)).map((item) => item.id);
|
|
17
|
+
const tile = (id) => (_jsxs("a", { href: `${base}/${id}`, className: "flex items-center gap-3 rounded-xl border border-hairline bg-card p-4 text-ink no-underline transition-colors hover:border-line-accent focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring focus-visible:outline-none", children: [renderMark?.(label(id)), _jsx("span", { className: "text-body-sm font-medium", children: label(id) })] }));
|
|
18
|
+
const list = (ids) => (_jsx("ul", { role: "list", className: "m-0 grid list-none grid-cols-1 gap-3 p-0 sm:grid-cols-2 lg:grid-cols-3", children: ids.map((id) => (_jsx("li", { children: tile(id) }, id))) }));
|
|
19
|
+
return (_jsxs("section", { "data-slot": "hub-index", className: cn("flex flex-col gap-10", className), ...props, children: [_jsx(PageHeading, { title: hub.h1, sub: hub.intro, size: "xl" }), _jsxs("div", { className: "flex flex-col gap-10", children: [groups.map((group) => (_jsxs("section", { className: "flex flex-col gap-3", children: [_jsx("h2", { className: "m-0 text-heading-md font-medium text-ink", children: group.title }), _jsx("p", { className: "m-0 text-body-sm text-body", children: group.lead }), list(group.items)] }, group.title))), ungrouped.length > 0 ? _jsx("section", { children: list(ungrouped) }) : null] })] }));
|
|
20
|
+
}
|
|
21
|
+
export { HubIndex };
|
|
22
|
+
//# sourceMappingURL=hub-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hub-index.js","sourceRoot":"","sources":["../../src/blocks/hub-index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The CloudGrid wordmark.
|
|
3
|
+
*
|
|
4
|
+
* Geometry is VERBATIM from the brand asset (`assets/logo/cloudgrid-color.svg`).
|
|
5
|
+
* The brand rule is **never redraw**: if the wordmark changes, replace these paths
|
|
6
|
+
* from that file rather than editing them.
|
|
7
|
+
*
|
|
8
|
+
* The one change from the source is `fill="currentColor"` in place of the
|
|
9
|
+
* hardcoded hex, so the mark follows the token system. It is purple on light
|
|
10
|
+
* surfaces and white inside a `data-cg-surface="panel"` container, with no second
|
|
11
|
+
* copy of the file to keep in sync. The design system sanctions exactly those two
|
|
12
|
+
* colourways, and `text-accent` is what selects between them per surface.
|
|
13
|
+
*
|
|
14
|
+
* That substitution is also what lets this pass the literal-colour gate. A brand
|
|
15
|
+
* asset pasted in unchanged would have carried #5A47F0 and failed it, correctly.
|
|
16
|
+
*/
|
|
17
|
+
declare function Logo({ height, label, className, ...props }: Omit<React.ComponentProps<"svg">, "ref"> & {
|
|
18
|
+
/** Rendered height in px. The mark scales from its 300x71 viewBox. */
|
|
19
|
+
height?: number;
|
|
20
|
+
/** Accessible name. Set to "" when an adjacent text label already names it. */
|
|
21
|
+
label?: string;
|
|
22
|
+
}): import("react").JSX.Element;
|
|
23
|
+
export { Logo };
|
|
24
|
+
//# sourceMappingURL=logo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logo.d.ts","sourceRoot":"","sources":["../../src/blocks/logo.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH,iBAAS,IAAI,CAAC,EACZ,MAAW,EACX,KAAmB,EACnB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,GAAG;IAC5C,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,+BAqCA;AAED,OAAO,EAAE,IAAI,EAAE,CAAA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/cloudgrid-cn.js";
|
|
3
|
+
/**
|
|
4
|
+
* The CloudGrid wordmark.
|
|
5
|
+
*
|
|
6
|
+
* Geometry is VERBATIM from the brand asset (`assets/logo/cloudgrid-color.svg`).
|
|
7
|
+
* The brand rule is **never redraw**: if the wordmark changes, replace these paths
|
|
8
|
+
* from that file rather than editing them.
|
|
9
|
+
*
|
|
10
|
+
* The one change from the source is `fill="currentColor"` in place of the
|
|
11
|
+
* hardcoded hex, so the mark follows the token system. It is purple on light
|
|
12
|
+
* surfaces and white inside a `data-cg-surface="panel"` container, with no second
|
|
13
|
+
* copy of the file to keep in sync. The design system sanctions exactly those two
|
|
14
|
+
* colourways, and `text-accent` is what selects between them per surface.
|
|
15
|
+
*
|
|
16
|
+
* That substitution is also what lets this pass the literal-colour gate. A brand
|
|
17
|
+
* asset pasted in unchanged would have carried #5A47F0 and failed it, correctly.
|
|
18
|
+
*/
|
|
19
|
+
function Logo({ height = 26, label = "CloudGrid", className, ...props }) {
|
|
20
|
+
// Width is derived rather than passed, so the mark cannot be squashed by a
|
|
21
|
+
// caller supplying a mismatched pair.
|
|
22
|
+
const width = Math.round((height * 300) / 71);
|
|
23
|
+
return (_jsxs("svg", { "data-slot": "logo",
|
|
24
|
+
// NOT `text-accent`. That is shadcn's accent *background* colour, and
|
|
25
|
+
// theme.css deliberately declines to claim the name for exactly this reason
|
|
26
|
+
// (rule 4): an earlier version mapped it to the accent text colour and
|
|
27
|
+
// `text-accent` rendered near-white on white. There is no --color-* utility
|
|
28
|
+
// for --cg-text-accent, so it is referenced directly. It flips purple ->
|
|
29
|
+
// white -> lime across the three surfaces, which is the logo's two
|
|
30
|
+
// sanctioned colourways plus ink.
|
|
31
|
+
className: cn("shrink-0 text-(--cg-text-accent)", className), width: width, height: height, viewBox: "0 0 300 71", fill: "currentColor", role: label ? "img" : "presentation", "aria-label": label || undefined, "aria-hidden": label ? undefined : "true", xmlns: "http://www.w3.org/2000/svg", ...props, children: [_jsx("path", { d: "M248.047 16.732H257.688V54.2679H248.047V16.732ZM252.868 0C256.057 0 258.726 2.5172 258.726 5.70072C258.726 8.95828 256.131 11.4014 252.868 11.4014C249.605 11.4014 247.009 8.95828 247.009 5.70072C247.009 2.5172 249.605 0 252.868 0Z" }), _jsx("path", { d: "M244.625 16.3623V25.9869C241.585 25.9869 239.063 26.7273 237.135 28.208C235.281 29.6887 234.243 31.9838 234.094 35.1673V54.2684H224.453V16.7325H232.759L233.649 22.7293C235.059 18.9535 238.692 16.3623 244.625 16.3623Z" }), _jsx("path", { d: "M198.628 24.9503C193.362 24.9503 189.654 28.9482 189.654 34.9451C189.654 40.9419 193.51 44.9398 198.628 44.9398C201.149 44.9398 203.374 44.0514 205.228 42.3486C207.082 40.5717 208.046 38.2026 208.12 35.2412V34.797C208.12 31.7615 207.156 29.3924 205.228 27.6156C203.374 25.8387 201.149 24.9503 198.628 24.9503ZM196.625 15.918C201.891 15.918 205.895 17.8429 208.565 21.7668L209.233 16.7324H217.613V53.3799C217.613 58.6364 215.833 62.8564 212.348 66.1139C208.862 69.3715 204.264 71.0003 198.702 71.0003C188.616 71.0003 181.274 66.188 180.31 56.4893H189.728C190.544 60.3392 193.51 62.2641 198.702 62.2641C204.561 62.2641 207.898 58.8585 207.898 53.602V49.0858C205.895 51.9732 201.742 54.0462 196.625 54.0462C191.731 54.0462 187.652 52.2693 184.463 48.7156C181.274 45.0879 179.716 40.4977 179.716 34.9451C179.716 29.3924 181.274 24.8022 184.463 21.2485C187.652 17.6948 191.656 15.918 196.625 15.918Z" }), _jsx("path", { d: "M18.8371 15.918C28.0332 15.918 34.7819 20.8043 36.191 29.9847H26.8466C25.7342 26.6531 22.8419 24.6541 19.0596 24.6541C16.4639 24.6541 14.2391 25.6906 12.5334 27.7636C10.8276 29.7626 9.93769 32.3538 9.93769 35.5373C9.93769 41.7563 13.8683 46.2725 19.2821 46.2725C23.0643 46.2725 26.0308 44.0514 26.9208 41.016H36.3393C34.5594 50.1223 27.8107 55.0827 18.8371 55.0827C13.275 55.0827 8.7511 53.3058 5.26549 49.6781C1.77988 46.0504 0 41.3121 0 35.5373C0 29.8366 1.77988 25.1724 5.26549 21.4706C8.82526 17.7689 13.3491 15.918 18.8371 15.918Z" }), _jsx("path", { d: "M40.3174 0.291016C42.9388 0.373933 48.0589 1.63074 49.958 6.14355V54.2676H40.3174V0.291016Z" }), _jsx("path", { d: "M166.282 0.296875C169.013 0.433575 174.118 1.79168 175.869 6.45312L175.924 6.31055V54.2676H167.617L166.876 49.2334C164.206 53.1572 160.201 55.082 154.936 55.082C149.967 55.0819 145.814 53.2308 142.477 49.4551C139.139 45.6794 137.508 41.0153 137.508 35.4629C137.508 29.9103 139.139 25.3197 142.477 21.5439C145.814 17.7682 149.967 15.9171 155.01 15.917C160.053 15.917 163.835 17.5462 166.282 20.8037V0.296875ZM156.938 24.9492C151.599 24.9492 147.445 29.2439 147.445 35.4629C147.445 41.7557 151.525 46.0498 156.938 46.0498C159.534 46.0498 161.759 45.1614 163.613 43.3105C165.467 41.4597 166.431 38.868 166.431 35.6846V35.2402C166.356 32.0569 165.393 29.6135 163.539 27.7627C161.685 25.9119 159.46 24.9493 156.938 24.9492Z" }), _jsx("path", { d: "M290.975 0.28418C293.179 0.284291 297.607 1.19024 300 4.5459V54.2686H291.694L290.952 49.2344C288.282 53.1581 284.277 55.083 279.012 55.083C274.043 55.0829 269.89 53.2317 266.553 49.4561C263.216 45.6804 261.584 41.0163 261.584 35.4639C261.584 29.9113 263.216 25.3207 266.553 21.5449C269.89 17.7692 274.043 15.9181 279.086 15.918C284.129 15.918 287.912 17.5471 290.359 20.8047V0.222656H290.939L290.975 0.28418ZM281.015 24.9502C275.675 24.9502 271.521 29.2449 271.521 35.4639C271.522 41.7567 275.601 46.0508 281.015 46.0508C283.61 46.0508 285.835 45.1624 287.689 43.3115C289.543 41.4606 290.507 38.869 290.507 35.6855V35.2412C290.433 32.0578 289.469 29.6145 287.615 27.7637C285.761 25.9128 283.536 24.9502 281.015 24.9502Z" }), _jsx("path", { d: "M97.3374 37.7892V16.9668H106.608V37.7892C106.608 42.4744 110.412 46.2725 115.105 46.2725C119.799 46.2725 123.603 42.4744 123.603 37.7892V16.9668H132.873V37.7892C132.873 47.5855 124.918 55.5269 115.105 55.5269C105.292 55.5269 97.3374 47.5855 97.3374 37.7892Z" }), _jsx("path", { d: "M73.507 15.918C79.2174 15.918 83.9637 17.7685 87.6718 21.3962C91.4541 25.0239 93.3088 29.6883 93.3088 35.4631C93.3088 41.2378 91.454 45.9761 87.6718 49.6038C85.0356 52.1829 81.8742 53.8602 78.215 54.6154C77.054 54.855 76.0252 53.9204 76.0252 52.7349V47.5482C76.0252 46.6336 76.6575 45.8569 77.493 45.4848C81.0368 43.9067 83.2962 40.1577 83.2962 35.4872C83.2962 34.0556 83.0947 32.7167 82.7167 31.5015C82.5932 31.1043 82.2168 30.8479 81.8008 30.8479H80.8927V27.1501C80.8923 25.785 79.7842 24.6784 78.4167 24.6783C77.0492 24.6783 75.941 25.785 75.9407 27.1501V30.8479H71.3901V27.1501C71.3897 25.785 70.2801 24.6783 68.9126 24.6783C67.5454 24.6787 66.4369 25.7852 66.4366 27.1501V30.8479H65.2899C64.88 30.8479 64.5075 31.0968 64.381 31.4867C63.9866 32.7028 63.7916 34.0384 63.7916 35.4872C63.7916 38.5967 64.6821 41.188 66.5362 43.261C67.4434 44.239 68.4572 44.9856 69.5949 45.4935C70.4337 45.868 71.0717 46.6457 71.0717 47.5643V52.7493C71.0717 53.9323 70.0469 54.8663 68.8877 54.6302C65.2186 53.8826 62.07 52.2003 59.416 49.6038C55.708 45.9761 53.8545 41.2377 53.8545 35.4631C53.8545 29.6884 55.708 25.0239 59.416 21.3962C63.1241 17.7685 67.7966 15.918 73.507 15.918Z" })] }));
|
|
32
|
+
}
|
|
33
|
+
export { Logo };
|
|
34
|
+
//# sourceMappingURL=logo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logo.js","sourceRoot":"","sources":["../../src/blocks/logo.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAA;AAEvC;;;;;;;;;;;;;;;GAeG;AACH,SAAS,IAAI,CAAC,EACZ,MAAM,GAAG,EAAE,EACX,KAAK,GAAG,WAAW,EACnB,SAAS,EACT,GAAG,KAAK,EAMT;IACC,2EAA2E;IAC3E,sCAAsC;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,EAAE,CAAC,CAAA;IAE7C,OAAO,CACL,4BACY,MAAM;QAChB,sEAAsE;QACtE,4EAA4E;QAC5E,uEAAuE;QACvE,4EAA4E;QAC5E,yEAAyE;QACzE,mEAAmE;QACnE,kCAAkC;QAClC,SAAS,EAAE,EAAE,CAAC,kCAAkC,EAAE,SAAS,CAAC,EAC5D,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,EAAC,YAAY,EACpB,IAAI,EAAC,cAAc,EACnB,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,gBACxB,KAAK,IAAI,SAAS,iBACjB,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,EACvC,KAAK,EAAC,4BAA4B,KAC9B,KAAK,aAET,eAAM,CAAC,EAAC,wOAAwO,GAAG,EACnP,eAAM,CAAC,EAAC,0NAA0N,GAAG,EACrO,eAAM,CAAC,EAAC,g4BAAg4B,GAAG,EAC34B,eAAM,CAAC,EAAC,yhBAAyhB,GAAG,EACpiB,eAAM,CAAC,EAAC,6FAA6F,GAAG,EACxG,eAAM,CAAC,EAAC,gtBAAgtB,GAAG,EAC3tB,eAAM,CAAC,EAAC,itBAAitB,GAAG,EAC5tB,eAAM,CAAC,EAAC,mQAAmQ,GAAG,EAC9Q,eAAM,CAAC,EAAC,+oCAA+oC,GAAG,IACtpC,CACP,CAAA;AACH,CAAC;AAED,OAAO,EAAE,IAAI,EAAE,CAAA"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An option card: lead glyph, title, a line or two of body, and the whole card is
|
|
3
|
+
* the target. Ported from v0's `core/OptionCard`.
|
|
4
|
+
*
|
|
5
|
+
* The `glyph` prop takes an outline SVG at 26 to 30px. Icons in this system are
|
|
6
|
+
* monoline: never filled, never purple, never on a background chip.
|
|
7
|
+
*
|
|
8
|
+
* Two changes from v0.
|
|
9
|
+
*
|
|
10
|
+
* `dataCta` is gone. It was an analytics hook named for the site's own tracking,
|
|
11
|
+
* and a registry component should not carry one consumer's telemetry vocabulary.
|
|
12
|
+
* Pass `data-cta` through `...props` if you want it; that works and does not put
|
|
13
|
+
* the name in the API.
|
|
14
|
+
*
|
|
15
|
+
* When `href` is set this renders an `<a>` wrapping block content, which is valid
|
|
16
|
+
* and is what "the whole card is the target" means. What v0 left implicit and this
|
|
17
|
+
* makes explicit is the focus ring: a card-sized link with no visible focus state
|
|
18
|
+
* is unusable by keyboard, and the ring here is the same token every other control
|
|
19
|
+
* uses so it flips per surface.
|
|
20
|
+
*/
|
|
21
|
+
declare function OptionCard({ title, body, href, note, glyph, className, children, ...props }: Omit<React.ComponentProps<"div">, "ref" | "href"> & {
|
|
22
|
+
title: string;
|
|
23
|
+
body?: string;
|
|
24
|
+
href?: string;
|
|
25
|
+
/** A small line under the body, for a qualifier like "Live in seconds". */
|
|
26
|
+
note?: string;
|
|
27
|
+
/** An outline SVG at 26 to 30px. */
|
|
28
|
+
glyph?: React.ReactNode;
|
|
29
|
+
}): import("react").JSX.Element;
|
|
30
|
+
export { OptionCard };
|
|
31
|
+
//# sourceMappingURL=option-card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"option-card.d.ts","sourceRoot":"","sources":["../../src/blocks/option-card.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,iBAAS,UAAU,CAAC,EAClB,KAAK,EACL,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,GAAG;IACrD,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,oCAAoC;IACpC,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACxB,+BA6BA;AAED,OAAO,EAAE,UAAU,EAAE,CAAA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/cloudgrid-cn.js";
|
|
3
|
+
/**
|
|
4
|
+
* An option card: lead glyph, title, a line or two of body, and the whole card is
|
|
5
|
+
* the target. Ported from v0's `core/OptionCard`.
|
|
6
|
+
*
|
|
7
|
+
* The `glyph` prop takes an outline SVG at 26 to 30px. Icons in this system are
|
|
8
|
+
* monoline: never filled, never purple, never on a background chip.
|
|
9
|
+
*
|
|
10
|
+
* Two changes from v0.
|
|
11
|
+
*
|
|
12
|
+
* `dataCta` is gone. It was an analytics hook named for the site's own tracking,
|
|
13
|
+
* and a registry component should not carry one consumer's telemetry vocabulary.
|
|
14
|
+
* Pass `data-cta` through `...props` if you want it; that works and does not put
|
|
15
|
+
* the name in the API.
|
|
16
|
+
*
|
|
17
|
+
* When `href` is set this renders an `<a>` wrapping block content, which is valid
|
|
18
|
+
* and is what "the whole card is the target" means. What v0 left implicit and this
|
|
19
|
+
* makes explicit is the focus ring: a card-sized link with no visible focus state
|
|
20
|
+
* is unusable by keyboard, and the ring here is the same token every other control
|
|
21
|
+
* uses so it flips per surface.
|
|
22
|
+
*/
|
|
23
|
+
function OptionCard({ title, body, href, note, glyph, className, children, ...props }) {
|
|
24
|
+
// Cast because the element type varies: div props are not assignable to anchor
|
|
25
|
+
// props and vice versa. The props this component accepts are already pinned by
|
|
26
|
+
// its own signature above, so the cast widens the tag, not the API.
|
|
27
|
+
const Tag = (href ? "a" : "div");
|
|
28
|
+
return (_jsxs(Tag, { "data-slot": "option-card", href: href, className: cn("flex flex-col gap-2 rounded-xl border border-hairline bg-card p-5 text-ink", href &&
|
|
29
|
+
"no-underline transition-colors hover:border-line-accent focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring focus-visible:outline-none", className), ...props, children: [glyph ? (_jsx("span", { "aria-hidden": "true", className: "[&>svg]:size-7 text-(--cg-text-accent)", children: glyph })) : null, _jsx("span", { className: "text-heading-sm font-medium", children: title }), body ? _jsx("span", { className: "text-body-sm text-body", children: body }) : null, children, note ? _jsx("span", { className: "text-caption text-faint", children: note }) : null] }));
|
|
30
|
+
}
|
|
31
|
+
export { OptionCard };
|
|
32
|
+
//# sourceMappingURL=option-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"option-card.js","sourceRoot":"","sources":["../../src/blocks/option-card.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAA;AAEvC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,SAAS,UAAU,CAAC,EAClB,KAAK,EACL,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EAST;IACC,+EAA+E;IAC/E,+EAA+E;IAC/E,oEAAoE;IACpE,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAsB,CAAA;IAErD,OAAO,CACL,MAAC,GAAG,iBACQ,aAAa,EACvB,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,EAAE,CACX,4EAA4E,EAC5E,IAAI;YACF,2JAA2J,EAC7J,SAAS,CACV,KACG,KAAK,aAER,KAAK,CAAC,CAAC,CAAC,CACP,8BAAkB,MAAM,EAAC,SAAS,EAAC,wCAAwC,YACxE,KAAK,GACD,CACR,CAAC,CAAC,CAAC,IAAI,EACR,eAAM,SAAS,EAAC,6BAA6B,YAAE,KAAK,GAAQ,EAC3D,IAAI,CAAC,CAAC,CAAC,eAAM,SAAS,EAAC,wBAAwB,YAAE,IAAI,GAAQ,CAAC,CAAC,CAAC,IAAI,EACpE,QAAQ,EACR,IAAI,CAAC,CAAC,CAAC,eAAM,SAAS,EAAC,yBAAyB,YAAE,IAAI,GAAQ,CAAC,CAAC,CAAC,IAAI,IAClE,CACP,CAAA;AACH,CAAC;AAED,OAAO,EAAE,UAAU,EAAE,CAAA"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The page lockup: optional eyebrow, display heading, optional subline.
|
|
3
|
+
*
|
|
4
|
+
* Ported from v0's `core/PageHeading`, keeping its two house rules. The title is
|
|
5
|
+
* authored in sentence case and rendered uppercase by CSS, so no string in a
|
|
6
|
+
* repo is ever written in caps. The subline is one sentence, which is why it
|
|
7
|
+
* takes a string rather than children.
|
|
8
|
+
*
|
|
9
|
+
* v0 sized the title with clamps between ramp steps, e.g.
|
|
10
|
+
* `clamp(var(--cg-display-sm), 5.5vw, var(--cg-display-lg))`. Those are
|
|
11
|
+
* expressed here as responsive pairs on the same steps. The viewport-relative
|
|
12
|
+
* middle is lost, so the growth is stepped rather than continuous; in exchange
|
|
13
|
+
* every size the component can render is a real step of the brand ramp, and the
|
|
14
|
+
* type-scale assertion can see it. An arbitrary `text-[clamp(...)]` would be
|
|
15
|
+
* caught by that assertion, which is the correct outcome rather than an obstacle.
|
|
16
|
+
*/
|
|
17
|
+
declare const SIZES: {
|
|
18
|
+
readonly sm: "text-display-sm";
|
|
19
|
+
readonly md: "text-display-sm md:text-display-md";
|
|
20
|
+
readonly lg: "text-display-sm md:text-display-lg";
|
|
21
|
+
readonly xl: "text-display-md md:text-display-xl";
|
|
22
|
+
};
|
|
23
|
+
declare function PageHeading({ eyebrow, title, sub, size, align, level, className, ...props }: React.ComponentProps<"header"> & {
|
|
24
|
+
eyebrow?: string;
|
|
25
|
+
title: string;
|
|
26
|
+
sub?: string;
|
|
27
|
+
size?: keyof typeof SIZES;
|
|
28
|
+
align?: "start" | "center";
|
|
29
|
+
/** Render as an `<h2>`, for a lockup that is not the page's first heading. */
|
|
30
|
+
level?: 1 | 2;
|
|
31
|
+
}): import("react").JSX.Element;
|
|
32
|
+
export { PageHeading };
|
|
33
|
+
//# sourceMappingURL=page-heading.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-heading.d.ts","sourceRoot":"","sources":["../../src/blocks/page-heading.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH,QAAA,MAAM,KAAK;;;;;CAKD,CAAA;AAEV,iBAAS,WAAW,CAAC,EACnB,OAAO,EACP,KAAK,EACL,GAAG,EACH,IAAW,EACX,KAAe,EACf,KAAS,EACT,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAG;IAClC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,OAAO,KAAK,CAAA;IACzB,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;IAC1B,8EAA8E;IAC9E,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;CACd,+BA8BA;AAED,OAAO,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/cloudgrid-cn.js";
|
|
3
|
+
/**
|
|
4
|
+
* The page lockup: optional eyebrow, display heading, optional subline.
|
|
5
|
+
*
|
|
6
|
+
* Ported from v0's `core/PageHeading`, keeping its two house rules. The title is
|
|
7
|
+
* authored in sentence case and rendered uppercase by CSS, so no string in a
|
|
8
|
+
* repo is ever written in caps. The subline is one sentence, which is why it
|
|
9
|
+
* takes a string rather than children.
|
|
10
|
+
*
|
|
11
|
+
* v0 sized the title with clamps between ramp steps, e.g.
|
|
12
|
+
* `clamp(var(--cg-display-sm), 5.5vw, var(--cg-display-lg))`. Those are
|
|
13
|
+
* expressed here as responsive pairs on the same steps. The viewport-relative
|
|
14
|
+
* middle is lost, so the growth is stepped rather than continuous; in exchange
|
|
15
|
+
* every size the component can render is a real step of the brand ramp, and the
|
|
16
|
+
* type-scale assertion can see it. An arbitrary `text-[clamp(...)]` would be
|
|
17
|
+
* caught by that assertion, which is the correct outcome rather than an obstacle.
|
|
18
|
+
*/
|
|
19
|
+
const SIZES = {
|
|
20
|
+
sm: "text-display-sm",
|
|
21
|
+
md: "text-display-sm md:text-display-md",
|
|
22
|
+
lg: "text-display-sm md:text-display-lg",
|
|
23
|
+
xl: "text-display-md md:text-display-xl",
|
|
24
|
+
};
|
|
25
|
+
function PageHeading({ eyebrow, title, sub, size = "lg", align = "start", level = 1, className, ...props }) {
|
|
26
|
+
const Heading = level === 1 ? "h1" : "h2";
|
|
27
|
+
return (_jsxs("header", { "data-slot": "page-heading", className: cn("flex flex-col gap-3", align === "center" && "items-center text-center", className), ...props, children: [eyebrow ? (_jsx("p", { className: "text-label font-medium text-faint", children: eyebrow })) : null, _jsx(Heading, { className: cn("font-display font-heavy tracking-display uppercase leading-display text-balance text-brand", SIZES[size]), children: title }), sub ? _jsx("p", { className: "text-body-lg text-body", children: sub }) : null] }));
|
|
28
|
+
}
|
|
29
|
+
export { PageHeading };
|
|
30
|
+
//# sourceMappingURL=page-heading.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-heading.js","sourceRoot":"","sources":["../../src/blocks/page-heading.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAA;AAEvC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,KAAK,GAAG;IACZ,EAAE,EAAE,iBAAiB;IACrB,EAAE,EAAE,oCAAoC;IACxC,EAAE,EAAE,oCAAoC;IACxC,EAAE,EAAE,oCAAoC;CAChC,CAAA;AAEV,SAAS,WAAW,CAAC,EACnB,OAAO,EACP,KAAK,EACL,GAAG,EACH,IAAI,GAAG,IAAI,EACX,KAAK,GAAG,OAAO,EACf,KAAK,GAAG,CAAC,EACT,SAAS,EACT,GAAG,KAAK,EAST;IACC,MAAM,OAAO,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;IAEzC,OAAO,CACL,+BACY,cAAc,EACxB,SAAS,EAAE,EAAE,CACX,qBAAqB,EACrB,KAAK,KAAK,QAAQ,IAAI,0BAA0B,EAChD,SAAS,CACV,KACG,KAAK,aAER,OAAO,CAAC,CAAC,CAAC,CACT,YAAG,SAAS,EAAC,mCAAmC,YAAE,OAAO,GAAK,CAC/D,CAAC,CAAC,CAAC,IAAI,EAIR,KAAC,OAAO,IACN,SAAS,EAAE,EAAE,CACX,4FAA4F,EAC5F,KAAK,CAAC,IAAI,CAAC,CACZ,YAEA,KAAK,GACE,EACT,GAAG,CAAC,CAAC,CAAC,YAAG,SAAS,EAAC,wBAAwB,YAAE,GAAG,GAAK,CAAC,CAAC,CAAC,IAAI,IACtD,CACV,CAAA;AACH,CAAC;AAED,OAAO,EAAE,WAAW,EAAE,CAAA"}
|