@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
package/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# @cloudgrid-io/ui
|
|
2
|
+
|
|
3
|
+
The CloudGrid design system: CSS custom properties, a Tailwind v4 theme, self-hosted
|
|
4
|
+
fonts, and the same values as machine-readable JSON.
|
|
5
|
+
|
|
6
|
+
43 React components, built on [Base UI](https://base-ui.com), styled only through tokens
|
|
7
|
+
and carrying no hardcoded colour.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @cloudgrid-io/ui
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The three font families come with it and are self-hosted, so there is no request to a font
|
|
16
|
+
CDN in your critical path.
|
|
17
|
+
|
|
18
|
+
## Use a component
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { Button, Card, PricingTiers } from "@cloudgrid-io/ui"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Components are shipped compiled, one module per component, with type declarations. The 20
|
|
25
|
+
that need it keep their `"use client"` directive, so a React Server Component app gets
|
|
26
|
+
exactly the client boundaries the source declares.
|
|
27
|
+
|
|
28
|
+
React is an **optional** peer dependency: take the stylesheets alone and nothing pulls in a
|
|
29
|
+
component tree.
|
|
30
|
+
|
|
31
|
+
## Import the CSS, in this order
|
|
32
|
+
|
|
33
|
+
```css
|
|
34
|
+
@import "tailwindcss";
|
|
35
|
+
|
|
36
|
+
@import "@cloudgrid-io/ui/fonts.css";
|
|
37
|
+
@import "@cloudgrid-io/ui/tokens.css";
|
|
38
|
+
@import "@cloudgrid-io/ui/theme.css";
|
|
39
|
+
@import "@cloudgrid-io/ui/shadcn.css";
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The order matters, and getting it wrong fails quietly rather than loudly.
|
|
43
|
+
|
|
44
|
+
- `theme.css` maps Tailwind utilities onto the tokens. Before `tokens.css` has run there is
|
|
45
|
+
nothing to map, so every utility resolves to nothing and the page renders unstyled
|
|
46
|
+
instead of erroring.
|
|
47
|
+
- `shadcn.css` must come after whatever `:root` your own `shadcn init` wrote, because it
|
|
48
|
+
overrides those values. Put it earlier and the stock grey palette wins.
|
|
49
|
+
|
|
50
|
+
Not using shadcn: skip the last line. Not using Tailwind: `tokens.css` alone gives you every
|
|
51
|
+
value as a custom property.
|
|
52
|
+
|
|
53
|
+
## Point Tailwind at the package
|
|
54
|
+
|
|
55
|
+
Tailwind v4 ignores `node_modules` when it scans for classes, so utilities used only inside
|
|
56
|
+
a component are never generated:
|
|
57
|
+
|
|
58
|
+
```css
|
|
59
|
+
@source "../node_modules/@cloudgrid-io/ui/dist";
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Adjust the path to your layout. **Skipping this fails quietly** — the build succeeds, the
|
|
63
|
+
page renders, and the components come out unstyled.
|
|
64
|
+
|
|
65
|
+
## Surfaces flip
|
|
66
|
+
|
|
67
|
+
Put `data-cg-surface` on a container and every semantic token inside it resolves to its
|
|
68
|
+
on-surface value. Borders, backgrounds, focus rings and component internals follow, with no
|
|
69
|
+
`dark:` variants and no second stylesheet.
|
|
70
|
+
|
|
71
|
+
```html
|
|
72
|
+
<div data-cg-surface="panel" class="bg-panel text-ink">
|
|
73
|
+
<!-- everything in here is now on brand purple -->
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<div data-cg-surface="ink" class="bg-code text-ink">
|
|
77
|
+
<!-- and everything in here is on near-black -->
|
|
78
|
+
</div>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Three surfaces: the default white page, `panel` on brand purple, and `ink` on near-black.
|
|
82
|
+
|
|
83
|
+
**Text is the exception.** Children inherit a colour their ancestor already resolved, so a
|
|
84
|
+
container that sets `data-cg-surface` must also declare a token-based text colour — that is
|
|
85
|
+
what `text-ink` is doing above. Borders and backgrounds flip on their own. Text does not.
|
|
86
|
+
|
|
87
|
+
There is no dark mode here, and this is not a substitute for one. Dark surfaces are a
|
|
88
|
+
property of a container, never a page-level theme.
|
|
89
|
+
|
|
90
|
+
## Entry points
|
|
91
|
+
|
|
92
|
+
| | |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `@cloudgrid-io/ui/tokens.css` | every value as a CSS custom property |
|
|
95
|
+
| `@cloudgrid-io/ui/theme.css` | maps Tailwind utilities onto the tokens |
|
|
96
|
+
| `@cloudgrid-io/ui/shadcn.css` | maps shadcn's variables onto the tokens |
|
|
97
|
+
| `@cloudgrid-io/ui/fonts.css` | the three self-hosted families |
|
|
98
|
+
| `@cloudgrid-io/ui/prose.css` | long-form text |
|
|
99
|
+
| `@cloudgrid-io/ui/tokens.json` | the same values, machine-readable |
|
|
100
|
+
|
|
101
|
+
The JSON sets under `tokens/` are DTCG and are the source the CSS is compiled from.
|
|
102
|
+
|
|
103
|
+
## Versioning
|
|
104
|
+
|
|
105
|
+
Semver. Token value changes are minor; removals are major.
|
|
106
|
+
|
|
107
|
+
## Licence
|
|
108
|
+
|
|
109
|
+
See the repository.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* The agent one-liner as an artifact: the sentence you hand to an agent, dressed
|
|
4
|
+
* as the terminal line it becomes and copyable in one press.
|
|
5
|
+
*
|
|
6
|
+
* Ported from v0's `site/AgentPrompt`. Ink pill, mono text behind a prompt mark, a
|
|
7
|
+
* caret, one copy button. Inside a purple panel the ink pill sits on the stage like
|
|
8
|
+
* the brand's own prompt surfaces.
|
|
9
|
+
*
|
|
10
|
+
* ## The caret uses `motion-safe:`, not a global rule
|
|
11
|
+
*
|
|
12
|
+
* v0's caret "stops under reduced motion via the global blanket rule" — a
|
|
13
|
+
* `prefers-reduced-motion` block in the site's `global.css`. **This repo has no
|
|
14
|
+
* such rule**, and adding one would not help: `globals.css` is not shipped to
|
|
15
|
+
* consumers, so a component relying on it animates against the user's stated
|
|
16
|
+
* preference in every app that pulls it. Same shape as the leading and the merge
|
|
17
|
+
* config before it. `motion-safe:` is per-utility and travels with the file.
|
|
18
|
+
*
|
|
19
|
+
* ## Copy feedback is announced, not just shown
|
|
20
|
+
*
|
|
21
|
+
* v0 flips the button's own text. That is invisible to a screen reader, which has
|
|
22
|
+
* already read the button and has no reason to read it again. The label still
|
|
23
|
+
* flips, and the result is also written to a polite live region, so the
|
|
24
|
+
* confirmation reaches someone who cannot see the button change.
|
|
25
|
+
*
|
|
26
|
+
* The failure path is honest rather than silent: `navigator.clipboard` rejects on
|
|
27
|
+
* insecure origins and without permission, and saying "copy blocked" beats a button
|
|
28
|
+
* that appears to do nothing.
|
|
29
|
+
*/
|
|
30
|
+
declare function AgentPrompt({ command, label, copyLabel, className, ...props }: Omit<React.ComponentProps<"div">, "ref"> & {
|
|
31
|
+
command: string;
|
|
32
|
+
/** Small lead-in above the pill, e.g. "Working with an agent? One line:" */
|
|
33
|
+
label?: string;
|
|
34
|
+
copyLabel?: string;
|
|
35
|
+
}): React.JSX.Element;
|
|
36
|
+
export { AgentPrompt };
|
|
37
|
+
//# sourceMappingURL=agent-prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-prompt.d.ts","sourceRoot":"","sources":["../../src/blocks/agent-prompt.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,iBAAS,WAAW,CAAC,EACnB,OAAO,EACP,KAAK,EACL,SAAkB,EAClB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,GAAG;IAC5C,OAAO,EAAE,MAAM,CAAA;IACf,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,qBAuDA;AAED,OAAO,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cn } from "../lib/cloudgrid-cn.js";
|
|
5
|
+
/**
|
|
6
|
+
* The agent one-liner as an artifact: the sentence you hand to an agent, dressed
|
|
7
|
+
* as the terminal line it becomes and copyable in one press.
|
|
8
|
+
*
|
|
9
|
+
* Ported from v0's `site/AgentPrompt`. Ink pill, mono text behind a prompt mark, a
|
|
10
|
+
* caret, one copy button. Inside a purple panel the ink pill sits on the stage like
|
|
11
|
+
* the brand's own prompt surfaces.
|
|
12
|
+
*
|
|
13
|
+
* ## The caret uses `motion-safe:`, not a global rule
|
|
14
|
+
*
|
|
15
|
+
* v0's caret "stops under reduced motion via the global blanket rule" — a
|
|
16
|
+
* `prefers-reduced-motion` block in the site's `global.css`. **This repo has no
|
|
17
|
+
* such rule**, and adding one would not help: `globals.css` is not shipped to
|
|
18
|
+
* consumers, so a component relying on it animates against the user's stated
|
|
19
|
+
* preference in every app that pulls it. Same shape as the leading and the merge
|
|
20
|
+
* config before it. `motion-safe:` is per-utility and travels with the file.
|
|
21
|
+
*
|
|
22
|
+
* ## Copy feedback is announced, not just shown
|
|
23
|
+
*
|
|
24
|
+
* v0 flips the button's own text. That is invisible to a screen reader, which has
|
|
25
|
+
* already read the button and has no reason to read it again. The label still
|
|
26
|
+
* flips, and the result is also written to a polite live region, so the
|
|
27
|
+
* confirmation reaches someone who cannot see the button change.
|
|
28
|
+
*
|
|
29
|
+
* The failure path is honest rather than silent: `navigator.clipboard` rejects on
|
|
30
|
+
* insecure origins and without permission, and saying "copy blocked" beats a button
|
|
31
|
+
* that appears to do nothing.
|
|
32
|
+
*/
|
|
33
|
+
function AgentPrompt({ command, label, copyLabel = "Copy", className, ...props }) {
|
|
34
|
+
const [feedback, setFeedback] = React.useState(null);
|
|
35
|
+
const timer = React.useRef(undefined);
|
|
36
|
+
// Cleared on unmount, or a state update fires against a component that is gone
|
|
37
|
+
// when someone navigates within the 1600ms window.
|
|
38
|
+
React.useEffect(() => () => clearTimeout(timer.current), []);
|
|
39
|
+
async function copy() {
|
|
40
|
+
try {
|
|
41
|
+
await navigator.clipboard.writeText(command);
|
|
42
|
+
setFeedback("copied ✓");
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
setFeedback("copy blocked by browser");
|
|
46
|
+
}
|
|
47
|
+
clearTimeout(timer.current);
|
|
48
|
+
timer.current = setTimeout(() => setFeedback(null), 1600);
|
|
49
|
+
}
|
|
50
|
+
return (_jsxs("div", { "data-slot": "agent-prompt", className: cn("flex flex-col gap-2", className), ...props, children: [label ? _jsx("p", { className: "m-0 text-body-sm text-body", children: label }) : null, _jsxs("div", { "data-cg-surface": "ink", className: "flex items-center gap-3 rounded-pill bg-code px-4 py-2.5 text-ink", children: [_jsx("span", { "aria-hidden": "true", className: "font-mono text-mono text-faint", children: ">" }), _jsxs("code", { className: "flex min-w-0 flex-1 items-center gap-1 font-mono text-mono break-all", children: [command, _jsx("span", { "aria-hidden": "true", className: "inline-block h-[1.1em] w-[0.5ch] shrink-0 bg-ink motion-safe:animate-pulse" })] }), _jsx("button", { type: "button", onClick: copy, className: "shrink-0 rounded-md px-2 py-1 font-mono text-caption text-body transition-colors hover:text-ink focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring", children: feedback ?? copyLabel })] }), _jsx("span", { "aria-live": "polite", className: "sr-only", children: feedback })] }));
|
|
51
|
+
}
|
|
52
|
+
export { AgentPrompt };
|
|
53
|
+
//# sourceMappingURL=agent-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-prompt.js","sourceRoot":"","sources":["../../src/blocks/agent-prompt.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAA;AAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,SAAS,WAAW,CAAC,EACnB,OAAO,EACP,KAAK,EACL,SAAS,GAAG,MAAM,EAClB,SAAS,EACT,GAAG,KAAK,EAMT;IACC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAgB,IAAI,CAAC,CAAA;IACnE,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAA4C,SAAS,CAAC,CAAA;IAEhF,+EAA+E;IAC/E,mDAAmD;IACnD,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAA;IAE5D,KAAK,UAAU,IAAI;QACjB,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;YAC5C,WAAW,CAAC,UAAU,CAAC,CAAA;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,WAAW,CAAC,yBAAyB,CAAC,CAAA;QACxC,CAAC;QACD,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAC3B,KAAK,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAA;IAC3D,CAAC;IAED,OAAO,CACL,4BAAe,cAAc,EAAC,SAAS,EAAE,EAAE,CAAC,qBAAqB,EAAE,SAAS,CAAC,KAAM,KAAK,aACrF,KAAK,CAAC,CAAC,CAAC,YAAG,SAAS,EAAC,4BAA4B,YAAE,KAAK,GAAK,CAAC,CAAC,CAAC,IAAI,EAErE,kCACkB,KAAK,EACrB,SAAS,EAAC,mEAAmE,aAE7E,8BAAkB,MAAM,EAAC,SAAS,EAAC,gCAAgC,kBAE5D,EAEP,gBAAM,SAAS,EAAC,sEAAsE,aACnF,OAAO,EACR,8BACc,MAAM,EAClB,SAAS,EAAC,4EAA4E,GACtF,IACG,EAEP,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,IAAI,EACb,SAAS,EAAC,mLAAmL,YAE5L,QAAQ,IAAI,SAAS,GACf,IACL,EAIN,4BAAgB,QAAQ,EAAC,SAAS,EAAC,SAAS,YACzC,QAAQ,GACJ,IACH,CACP,CAAA;AACH,CAAC;AAED,OAAO,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A grid of link cards. Ported from v0's `core/CardGrid`.
|
|
3
|
+
*
|
|
4
|
+
* v0's version reimplemented the card chrome, because it depended on a global
|
|
5
|
+
* `.card` recipe in the site's stylesheet. This composes **our** `card` instead,
|
|
6
|
+
* which is what #7 meant by rebuilding rather than copying: the cards inherit the
|
|
7
|
+
* token wiring, the surface flips and the focus ring for free, and there is one
|
|
8
|
+
* card in the library rather than two that drift.
|
|
9
|
+
*
|
|
10
|
+
* The `band` and `container` wrappers are dropped as everywhere else: page layout
|
|
11
|
+
* belongs to the page.
|
|
12
|
+
*
|
|
13
|
+
* v0's grid was `repeat(3, 1fr)` flat, which is three unreadable columns on a
|
|
14
|
+
* phone. Made responsive here, because a registry component has to stand on its
|
|
15
|
+
* own in a consumer's layout rather than rely on the site's media queries.
|
|
16
|
+
*/
|
|
17
|
+
declare const COLUMNS: {
|
|
18
|
+
readonly 2: "sm:grid-cols-2";
|
|
19
|
+
readonly 3: "sm:grid-cols-2 lg:grid-cols-3";
|
|
20
|
+
};
|
|
21
|
+
type CardGridCard = {
|
|
22
|
+
/** A short glyph or two letters set in mono. Decoration, so aria-hidden. */
|
|
23
|
+
icon?: string;
|
|
24
|
+
title: string;
|
|
25
|
+
body: string;
|
|
26
|
+
link?: {
|
|
27
|
+
href: string;
|
|
28
|
+
label: string;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
declare function CardGrid({ title, columns, cards, className, ...props }: Omit<React.ComponentProps<"section">, "ref"> & {
|
|
32
|
+
title?: string;
|
|
33
|
+
columns?: keyof typeof COLUMNS;
|
|
34
|
+
cards: CardGridCard[];
|
|
35
|
+
}): import("react").JSX.Element;
|
|
36
|
+
export { CardGrid };
|
|
37
|
+
export type { CardGridCard };
|
|
38
|
+
//# sourceMappingURL=card-grid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card-grid.d.ts","sourceRoot":"","sources":["../../src/blocks/card-grid.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;GAeG;AACH,QAAA,MAAM,OAAO;;;CAGH,CAAA;AAEV,KAAK,YAAY,GAAG;IAClB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CACvC,CAAA;AAED,iBAAS,QAAQ,CAAC,EAChB,KAAK,EACL,OAAW,EACX,KAAK,EACL,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,GAAG;IAChD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,OAAO,OAAO,CAAA;IAC9B,KAAK,EAAE,YAAY,EAAE,CAAA;CACtB,+BAmCA;AAED,OAAO,EAAE,QAAQ,EAAE,CAAA;AACnB,YAAY,EAAE,YAAY,EAAE,CAAA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Card, CardDescription, CardHeader, CardTitle } from "../ui/card.js";
|
|
3
|
+
import { cn } from "../lib/cloudgrid-cn.js";
|
|
4
|
+
/**
|
|
5
|
+
* A grid of link cards. Ported from v0's `core/CardGrid`.
|
|
6
|
+
*
|
|
7
|
+
* v0's version reimplemented the card chrome, because it depended on a global
|
|
8
|
+
* `.card` recipe in the site's stylesheet. This composes **our** `card` instead,
|
|
9
|
+
* which is what #7 meant by rebuilding rather than copying: the cards inherit the
|
|
10
|
+
* token wiring, the surface flips and the focus ring for free, and there is one
|
|
11
|
+
* card in the library rather than two that drift.
|
|
12
|
+
*
|
|
13
|
+
* The `band` and `container` wrappers are dropped as everywhere else: page layout
|
|
14
|
+
* belongs to the page.
|
|
15
|
+
*
|
|
16
|
+
* v0's grid was `repeat(3, 1fr)` flat, which is three unreadable columns on a
|
|
17
|
+
* phone. Made responsive here, because a registry component has to stand on its
|
|
18
|
+
* own in a consumer's layout rather than rely on the site's media queries.
|
|
19
|
+
*/
|
|
20
|
+
const COLUMNS = {
|
|
21
|
+
2: "sm:grid-cols-2",
|
|
22
|
+
3: "sm:grid-cols-2 lg:grid-cols-3",
|
|
23
|
+
};
|
|
24
|
+
function CardGrid({ title, columns = 3, cards, className, ...props }) {
|
|
25
|
+
return (_jsxs("section", { "data-slot": "card-grid", className: cn("flex flex-col gap-6", className), ...props, children: [title ? _jsx("h2", { className: "text-heading-lg font-medium text-ink", children: title }) : null, _jsx("div", { className: cn("grid grid-cols-1 gap-5", COLUMNS[columns]), children: cards.map((card) => (
|
|
26
|
+
// Keyed on the title rather than the index: an index key makes React
|
|
27
|
+
// reuse the wrong card when the list is filtered or reordered, which is
|
|
28
|
+
// the sort of thing that looks like a caching bug later.
|
|
29
|
+
_jsxs(Card, { children: [_jsxs(CardHeader, { children: [card.icon ? (_jsx("span", { "aria-hidden": "true", className: "font-mono text-mono text-(--cg-text-accent)", children: card.icon })) : null, _jsx(CardTitle, { className: "text-heading-md", children: card.title }), _jsx(CardDescription, { children: card.body })] }), card.link ? (_jsx("a", { href: card.link.href, className: "mx-6 -mt-2 w-fit font-mono text-mono text-ink underline-offset-4 hover:text-(--cg-text-accent) hover:underline focus-visible:rounded-xs focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring", children: card.link.label })) : null] }, card.title))) })] }));
|
|
30
|
+
}
|
|
31
|
+
export { CardGrid };
|
|
32
|
+
//# sourceMappingURL=card-grid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card-grid.js","sourceRoot":"","sources":["../../src/blocks/card-grid.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACjF,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAA;AAEvC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,GAAG;IACd,CAAC,EAAE,gBAAgB;IACnB,CAAC,EAAE,+BAA+B;CAC1B,CAAA;AAUV,SAAS,QAAQ,CAAC,EAChB,KAAK,EACL,OAAO,GAAG,CAAC,EACX,KAAK,EACL,SAAS,EACT,GAAG,KAAK,EAKT;IACC,OAAO,CACL,gCAAmB,WAAW,EAAC,SAAS,EAAE,EAAE,CAAC,qBAAqB,EAAE,SAAS,CAAC,KAAM,KAAK,aACtF,KAAK,CAAC,CAAC,CAAC,aAAI,SAAS,EAAC,sCAAsC,YAAE,KAAK,GAAM,CAAC,CAAC,CAAC,IAAI,EACjF,cAAK,SAAS,EAAE,EAAE,CAAC,wBAAwB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,YAC3D,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;gBACnB,qEAAqE;gBACrE,wEAAwE;gBACxE,yDAAyD;gBACzD,MAAC,IAAI,eACH,MAAC,UAAU,eACR,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CACX,8BACc,MAAM,EAClB,SAAS,EAAC,6CAA6C,YAEtD,IAAI,CAAC,IAAI,GACL,CACR,CAAC,CAAC,CAAC,IAAI,EACR,KAAC,SAAS,IAAC,SAAS,EAAC,iBAAiB,YAAE,IAAI,CAAC,KAAK,GAAa,EAC/D,KAAC,eAAe,cAAE,IAAI,CAAC,IAAI,GAAmB,IACnC,EACZ,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CACX,YACE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EACpB,SAAS,EAAC,2NAA2N,YAEpO,IAAI,CAAC,IAAI,CAAC,KAAK,GACd,CACL,CAAC,CAAC,CAAC,IAAI,KApBC,IAAI,CAAC,KAAK,CAqBd,CACR,CAAC,GACE,IACE,CACX,CAAA;AACH,CAAC;AAED,OAAO,EAAE,QAAQ,EAAE,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type CompareRow = {
|
|
2
|
+
q: string;
|
|
3
|
+
a: string;
|
|
4
|
+
};
|
|
5
|
+
declare function CompareTable({ rival, rivalLogo, rows, className, ...props }: Omit<React.ComponentProps<"div">, "ref"> & {
|
|
6
|
+
rival: string;
|
|
7
|
+
/** The rival's mark, if you have one to show beside its name. */
|
|
8
|
+
rivalLogo?: React.ReactNode;
|
|
9
|
+
rows: CompareRow[];
|
|
10
|
+
}): import("react").JSX.Element;
|
|
11
|
+
export { CompareTable };
|
|
12
|
+
export type { CompareRow };
|
|
13
|
+
//# sourceMappingURL=compare-table.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare-table.d.ts","sourceRoot":"","sources":["../../src/blocks/compare-table.tsx"],"names":[],"mappings":"AAqCA,KAAK,UAAU,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAe1C,iBAAS,YAAY,CAAC,EACpB,KAAK,EACL,SAAS,EACT,IAAI,EACJ,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,GAAG;IAC5C,KAAK,EAAE,MAAM,CAAA;IACb,iEAAiE;IACjE,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC3B,IAAI,EAAE,UAAU,EAAE,CAAA;CACnB,+BA+DA;AAED,OAAO,EAAE,YAAY,EAAE,CAAA;AACvB,YAAY,EAAE,UAAU,EAAE,CAAA"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { CircleCheck, CircleX } from "lucide-react";
|
|
3
|
+
import { Logo } from "./logo.js";
|
|
4
|
+
import { cn } from "../lib/cloudgrid-cn.js";
|
|
5
|
+
/**
|
|
6
|
+
* A check/X feature matrix for a compare page. Three columns: the feature line,
|
|
7
|
+
* the rival, CloudGrid. Ported from v0's `site/CompareTable`.
|
|
8
|
+
*
|
|
9
|
+
* The CloudGrid column is lifted by an accent ring, the way a pricing table lifts
|
|
10
|
+
* its recommended plan.
|
|
11
|
+
*
|
|
12
|
+
* ## The honesty rule is load-bearing, keep it
|
|
13
|
+
*
|
|
14
|
+
* A row's `a` value must be `both`, `us`, `them` or `neither`, and anything else
|
|
15
|
+
* **throws during render**. Under SSG that is a build failure, which is the point:
|
|
16
|
+
* a typo must break the build rather than quietly render a wrong claim about a
|
|
17
|
+
* competitor. v0's canon puts it plainly, and it is worth repeating here because
|
|
18
|
+
* the temptation is real: rivals get their checks, and a matrix of straight
|
|
19
|
+
* X-them/check-us rows reads as marketing noise and is worse than no table.
|
|
20
|
+
*
|
|
21
|
+
* ## The rival's mark is a slot
|
|
22
|
+
*
|
|
23
|
+
* v0 rendered `<ToolLogo name={rival} />`. That component is held pending a
|
|
24
|
+
* trademark question (#47), and the coupling was wrong anyway: which mark
|
|
25
|
+
* represents a rival is the caller's call, not this component's. Pass a
|
|
26
|
+
* `rivalLogo` if you have one. Without it the name alone reads fine.
|
|
27
|
+
*
|
|
28
|
+
* ## Marks are lucide, and they carry text
|
|
29
|
+
*
|
|
30
|
+
* Phosphor inlined strings become `CircleCheck` / `CircleX`, as elsewhere. The
|
|
31
|
+
* icons are `aria-hidden` and each cell carries visually-hidden "Included" or
|
|
32
|
+
* "Not included", so a screen reader hears the claim rather than nothing, and so
|
|
33
|
+
* does anything reading the markup.
|
|
34
|
+
*/
|
|
35
|
+
const VALID = ["both", "us", "them", "neither"];
|
|
36
|
+
function Mark({ yes }) {
|
|
37
|
+
const Icon = yes ? CircleCheck : CircleX;
|
|
38
|
+
return (_jsxs(_Fragment, { children: [_jsx(Icon, { "aria-hidden": "true", className: cn("inline-block size-[22px]", yes ? "text-brand" : "text-faint") }), _jsx("span", { className: "sr-only", children: yes ? "Included" : "Not included" })] }));
|
|
39
|
+
}
|
|
40
|
+
function CompareTable({ rival, rivalLogo, rows, className, ...props }) {
|
|
41
|
+
const parsed = rows.map((pair) => {
|
|
42
|
+
const who = pair.a.trim().toLowerCase();
|
|
43
|
+
if (!VALID.includes(who)) {
|
|
44
|
+
throw new Error(`CompareTable: matrix row "${pair.q}" has a="${pair.a}". ` +
|
|
45
|
+
`Allowed values: ${VALID.join(", ")}.`);
|
|
46
|
+
}
|
|
47
|
+
return { label: pair.q, us: who === "both" || who === "us", them: who === "both" || who === "them" };
|
|
48
|
+
});
|
|
49
|
+
return (_jsx("div", { "data-slot": "compare-table",
|
|
50
|
+
// The table scrolls inside its own box rather than pushing the page sideways
|
|
51
|
+
// on a narrow screen.
|
|
52
|
+
className: cn("w-full overflow-x-auto", className), ...props, children: _jsxs("table", { className: "w-full border-collapse text-body-sm", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("td", { "aria-hidden": "true" }), _jsx("th", { scope: "col", className: "p-3 text-left font-medium text-ink", children: _jsxs("span", { className: "inline-flex items-center gap-2", children: [rivalLogo, rival] }) }), _jsx("th", { scope: "col", className: "rounded-t-xl border border-b-0 border-line-accent bg-brand-tint p-3 text-left font-medium text-ink", children: _jsx(Logo, { height: 18, label: "CloudGrid" }) })] }) }), _jsx("tbody", { children: parsed.map((row, i) => (_jsxs("tr", { className: i % 2 === 0 ? "bg-subtle" : undefined, children: [_jsx("th", { scope: "row", className: "p-3 text-left font-normal text-body", children: row.label }), _jsx("td", { className: "p-3", children: _jsx(Mark, { yes: row.them }) }), _jsx("td", { className: cn("border-x border-line-accent bg-brand-tint p-3", i === parsed.length - 1 && "rounded-b-xl border-b"), children: _jsx(Mark, { yes: row.us }) })] }, row.label))) })] }) }));
|
|
53
|
+
}
|
|
54
|
+
export { CompareTable };
|
|
55
|
+
//# sourceMappingURL=compare-table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare-table.js","sourceRoot":"","sources":["../../src/blocks/compare-table.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEnD,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AACzC,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAA;AAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAU,CAAA;AAIxD,SAAS,IAAI,CAAC,EAAE,GAAG,EAAoB;IACrC,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAA;IACxC,OAAO,CACL,8BACE,KAAC,IAAI,mBACS,MAAM,EAClB,SAAS,EAAE,EAAE,CAAC,0BAA0B,EAAE,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,GAC5E,EACF,eAAM,SAAS,EAAC,SAAS,YAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,cAAc,GAAQ,IACnE,CACJ,CAAA;AACH,CAAC;AAED,SAAS,YAAY,CAAC,EACpB,KAAK,EACL,SAAS,EACT,IAAI,EACJ,SAAS,EACT,GAAG,KAAK,EAMT;IACC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;QACvC,IAAI,CAAE,KAA2B,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAChD,MAAM,IAAI,KAAK,CACb,6BAA6B,IAAI,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,KAAK;gBACxD,mBAAmB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACzC,CAAA;QACH,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE,IAAI,EAAE,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,MAAM,EAAE,CAAA;IACtG,CAAC,CAAC,CAAA;IAEF,OAAO,CACL,2BACY,eAAe;QACzB,6EAA6E;QAC7E,sBAAsB;QACtB,SAAS,EAAE,EAAE,CAAC,wBAAwB,EAAE,SAAS,CAAC,KAC9C,KAAK,YAET,iBAAO,SAAS,EAAC,qCAAqC,aACpD,0BACE,yBAGE,4BAAgB,MAAM,GAAG,EACzB,aAAI,KAAK,EAAC,KAAK,EAAC,SAAS,EAAC,oCAAoC,YAC5D,gBAAM,SAAS,EAAC,gCAAgC,aAC7C,SAAS,EACT,KAAK,IACD,GACJ,EACL,aACE,KAAK,EAAC,KAAK,EACX,SAAS,EAAC,oGAAoG,YAE9G,KAAC,IAAI,IAAC,MAAM,EAAE,EAAE,EAAE,KAAK,EAAC,WAAW,GAAG,GACnC,IACF,GACC,EACR,0BACG,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CACtB,cAAoB,SAAS,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,aAClE,aAAI,KAAK,EAAC,KAAK,EAAC,SAAS,EAAC,qCAAqC,YAC5D,GAAG,CAAC,KAAK,GACP,EACL,aAAI,SAAS,EAAC,KAAK,YACjB,KAAC,IAAI,IAAC,GAAG,EAAE,GAAG,CAAC,IAAI,GAAI,GACpB,EACL,aACE,SAAS,EAAE,EAAE,CACX,+CAA+C,EAC/C,CAAC,KAAK,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,uBAAuB,CACnD,YAED,KAAC,IAAI,IAAC,GAAG,EAAE,GAAG,CAAC,EAAE,GAAI,GAClB,KAdE,GAAG,CAAC,KAAK,CAeb,CACN,CAAC,GACI,IACF,GACJ,CACP,CAAA;AACH,CAAC;AAED,OAAO,EAAE,YAAY,EAAE,CAAA"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* One creation on the grid. Ported from v0's `site/CreationTile`.
|
|
4
|
+
*
|
|
5
|
+
* The tile shows the creation's real screen: a poster, with a silent loop played
|
|
6
|
+
* on hover. Server-rendered HTML is the poster alone, which is the honest state.
|
|
7
|
+
*
|
|
8
|
+
* The approved copy fixed the anatomy: thumbnail and name, and deliberately **no**
|
|
9
|
+
* maker caption and no one-liner. The grid is the content, and a caption under
|
|
10
|
+
* every tile turns a wall of work into a list of credits.
|
|
11
|
+
*
|
|
12
|
+
* Both actions are always in the markup rather than injected on hover: a crawler
|
|
13
|
+
* that never fires a pointer event still sees "Open it", and a touch device has no
|
|
14
|
+
* hover to give.
|
|
15
|
+
*
|
|
16
|
+
* ## Three changes from v0
|
|
17
|
+
*
|
|
18
|
+
* **The loop respects `prefers-reduced-motion`.** v0 plays on pointer enter
|
|
19
|
+
* unconditionally. Autoplaying video is close to the centre of what that setting
|
|
20
|
+
* exists for, and the poster is already the honest fallback, so the check costs
|
|
21
|
+
* nothing. Read at play time rather than at mount, so the setting can change.
|
|
22
|
+
*
|
|
23
|
+
* **`pickUpHref` is a required prop.** v0 hardcodes `/plug?door=drop`, a route on
|
|
24
|
+
* the CloudGrid site. A registry component cannot know a consumer's routes and one
|
|
25
|
+
* that guesses ships a dead link. v0's own comment notes that no pick-up flow
|
|
26
|
+
* exists yet and the destination is a placeholder, which is more reason for the
|
|
27
|
+
* caller to own it.
|
|
28
|
+
*
|
|
29
|
+
* **`data-cta` and `data-tilt` are dropped**, as elsewhere: the site's analytics
|
|
30
|
+
* and motion vocabulary, not a registry component's API. Both still work through
|
|
31
|
+
* `...props` on the wrapper.
|
|
32
|
+
*
|
|
33
|
+
* `CreationGrid` ships with it because this renders an `<li>`, and an `<li>`
|
|
34
|
+
* outside a list is invalid markup that nothing warns you about.
|
|
35
|
+
*/
|
|
36
|
+
type Creation = {
|
|
37
|
+
name: string;
|
|
38
|
+
maker: string;
|
|
39
|
+
species: string;
|
|
40
|
+
url: string;
|
|
41
|
+
image?: string;
|
|
42
|
+
video?: string;
|
|
43
|
+
pickedUp: boolean;
|
|
44
|
+
};
|
|
45
|
+
declare function CreationGrid({ className, ...props }: React.ComponentProps<"ul">): React.JSX.Element;
|
|
46
|
+
declare function CreationTile({ creation, pickUpHref, openLabel, pickUpLabel, eager, className, ...props }: Omit<React.ComponentProps<"li">, "ref"> & {
|
|
47
|
+
creation: Creation;
|
|
48
|
+
/** Where "pick it up" goes. Required: this component cannot know your routes. */
|
|
49
|
+
pickUpHref: string;
|
|
50
|
+
openLabel?: string;
|
|
51
|
+
pickUpLabel?: string;
|
|
52
|
+
/** Loads the poster eagerly. For the first row of a field. */
|
|
53
|
+
eager?: boolean;
|
|
54
|
+
}): React.JSX.Element;
|
|
55
|
+
export { CreationTile, CreationGrid };
|
|
56
|
+
export type { Creation };
|
|
57
|
+
//# sourceMappingURL=creation-tile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"creation-tile.d.ts","sourceRoot":"","sources":["../../src/blocks/creation-tile.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,KAAK,QAAQ,GAAG;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,iBAAS,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,qBAYxE;AAED,iBAAS,YAAY,CAAC,EACpB,QAAQ,EACR,UAAU,EACV,SAAqB,EACrB,WAA0B,EAC1B,KAAa,EACb,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,GAAG;IAC3C,QAAQ,EAAE,QAAQ,CAAA;IAClB,iFAAiF;IACjF,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,qBA4FA;AAED,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,CAAA;AACrC,YAAY,EAAE,QAAQ,EAAE,CAAA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cn } from "../lib/cloudgrid-cn.js";
|
|
5
|
+
function CreationGrid({ className, ...props }) {
|
|
6
|
+
return (_jsx("ul", { role: "list", "data-slot": "creation-grid", className: cn("m-0 grid list-none grid-cols-1 gap-5 p-0 sm:grid-cols-2 lg:grid-cols-3", className), ...props }));
|
|
7
|
+
}
|
|
8
|
+
function CreationTile({ creation, pickUpHref, openLabel = "Open it", pickUpLabel = "Pick it up", eager = false, className, ...props }) {
|
|
9
|
+
const loop = React.useRef(null);
|
|
10
|
+
function play() {
|
|
11
|
+
// Checked at play time, not at mount: someone can change the setting while
|
|
12
|
+
// the page is open, and a value captured in an effect would be stale.
|
|
13
|
+
if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches)
|
|
14
|
+
return;
|
|
15
|
+
loop.current?.play().catch(() => {
|
|
16
|
+
// Autoplay refusals leave the poster showing, which is the honest state.
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function rest() {
|
|
20
|
+
const video = loop.current;
|
|
21
|
+
if (!video)
|
|
22
|
+
return;
|
|
23
|
+
video.pause();
|
|
24
|
+
video.currentTime = 0;
|
|
25
|
+
}
|
|
26
|
+
return (_jsxs("li", { "data-slot": "creation-tile", onPointerEnter: play, onPointerLeave: rest, className: cn("group/tile flex flex-col gap-2", className), ...props, children: [_jsxs("span", { className: "relative block overflow-hidden rounded-xl border border-hairline bg-subtle", children: [creation.image ? (_jsxs(_Fragment, { children: [_jsx("img", { src: creation.image,
|
|
27
|
+
// The alt says what it is and whose it is, because a wall of these
|
|
28
|
+
// is unusable if every image announces only a name.
|
|
29
|
+
alt: `${creation.name}, a ${creation.species} by ${creation.maker}, live on the grid`, loading: eager ? "eager" : "lazy", decoding: "async", className: "block aspect-video w-full object-cover" }), creation.video ? (_jsx("video", { ref: loop, muted: true, loop: true, playsInline: true, preload: "none", poster: creation.image, "aria-hidden": "true", className: "absolute inset-0 block size-full object-cover opacity-0 transition-opacity group-hover/tile:opacity-100", children: _jsx("source", { src: creation.video }) })) : null] })) : (_jsx("span", { "aria-hidden": "true", className: "flex aspect-video items-center justify-center font-mono text-mono text-faint", children: creation.species })), _jsxs("span", { className: "absolute inset-x-0 bottom-0 flex gap-2 p-2 opacity-0 transition-opacity group-hover/tile:opacity-100 focus-within:opacity-100", children: [_jsxs("a", { href: creation.url, className: "rounded-md bg-code px-2 py-1 font-mono text-caption text-inverse no-underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring", children: [openLabel, _jsxs("span", { className: "sr-only", children: [": ", creation.name] })] }), _jsxs("a", { href: pickUpHref, className: "rounded-md bg-code px-2 py-1 font-mono text-caption text-inverse no-underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring", children: [pickUpLabel, _jsxs("span", { className: "sr-only", children: [": ", creation.name] })] })] }), creation.pickedUp ? (_jsx("span", { className: "absolute top-2 right-2 rounded-pill bg-lime px-2 py-0.5 font-mono text-caption text-on-accent", children: "picked up" })) : null] }), _jsx("span", { className: "text-body-sm font-medium text-ink", children: creation.name })] }));
|
|
30
|
+
}
|
|
31
|
+
export { CreationTile, CreationGrid };
|
|
32
|
+
//# sourceMappingURL=creation-tile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"creation-tile.js","sourceRoot":"","sources":["../../src/blocks/creation-tile.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A closing call to action: optional line of text, and an action.
|
|
3
|
+
*
|
|
4
|
+
* Ported from v0's `core/CtaBanner`, with the site coupling removed. v0's version
|
|
5
|
+
* rendered its own Button and defaulted the destination to `/plug?door=<door>`,
|
|
6
|
+
* which is a route on the CloudGrid site. A registry component cannot know a
|
|
7
|
+
* consumer's routes, and one that guesses produces a dead link in someone else's
|
|
8
|
+
* app, so the `door` and `href` props are gone and the action is a slot. The
|
|
9
|
+
* consumer passes their own Button, Link, or form.
|
|
10
|
+
*
|
|
11
|
+
* v0's `band band-alt` page wrapper is dropped for the same reason as Quote:
|
|
12
|
+
* page layout belongs to the page. What is kept is the surface, because that is
|
|
13
|
+
* the component's own look rather than the page's.
|
|
14
|
+
*
|
|
15
|
+
* `data-cg-surface="panel"` puts this on the brand purple. Per rule 3 the text
|
|
16
|
+
* colour has to be declared here: children inherit an already-resolved colour, so
|
|
17
|
+
* `text-ink` is what makes the flip reach the text rather than leaving it dark on
|
|
18
|
+
* purple.
|
|
19
|
+
*
|
|
20
|
+
* A `default` Button is correct in here. It was not until #41: primary rendered
|
|
21
|
+
* the brand purple in every scope, so on the purple panel the button and its
|
|
22
|
+
* ground were the same colour and the control had no shape. Primary is lime on
|
|
23
|
+
* both dark brand surfaces now, measured at 3.79:1 against the panel.
|
|
24
|
+
*/
|
|
25
|
+
declare function CtaBanner({ text, action, className, children, ...props }: React.ComponentProps<"section"> & {
|
|
26
|
+
text?: string;
|
|
27
|
+
/** The action. A Button, a link, whatever the consumer routes with. */
|
|
28
|
+
action?: React.ReactNode;
|
|
29
|
+
}): import("react").JSX.Element;
|
|
30
|
+
export { CtaBanner };
|
|
31
|
+
//# sourceMappingURL=cta-banner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cta-banner.d.ts","sourceRoot":"","sources":["../../src/blocks/cta-banner.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,iBAAS,SAAS,CAAC,EACjB,IAAI,EACJ,MAAM,EACN,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,GAAG;IACnC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uEAAuE;IACvE,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACzB,+BAkBA;AAED,OAAO,EAAE,SAAS,EAAE,CAAA"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/cloudgrid-cn.js";
|
|
3
|
+
/**
|
|
4
|
+
* A closing call to action: optional line of text, and an action.
|
|
5
|
+
*
|
|
6
|
+
* Ported from v0's `core/CtaBanner`, with the site coupling removed. v0's version
|
|
7
|
+
* rendered its own Button and defaulted the destination to `/plug?door=<door>`,
|
|
8
|
+
* which is a route on the CloudGrid site. A registry component cannot know a
|
|
9
|
+
* consumer's routes, and one that guesses produces a dead link in someone else's
|
|
10
|
+
* app, so the `door` and `href` props are gone and the action is a slot. The
|
|
11
|
+
* consumer passes their own Button, Link, or form.
|
|
12
|
+
*
|
|
13
|
+
* v0's `band band-alt` page wrapper is dropped for the same reason as Quote:
|
|
14
|
+
* page layout belongs to the page. What is kept is the surface, because that is
|
|
15
|
+
* the component's own look rather than the page's.
|
|
16
|
+
*
|
|
17
|
+
* `data-cg-surface="panel"` puts this on the brand purple. Per rule 3 the text
|
|
18
|
+
* colour has to be declared here: children inherit an already-resolved colour, so
|
|
19
|
+
* `text-ink` is what makes the flip reach the text rather than leaving it dark on
|
|
20
|
+
* purple.
|
|
21
|
+
*
|
|
22
|
+
* A `default` Button is correct in here. It was not until #41: primary rendered
|
|
23
|
+
* the brand purple in every scope, so on the purple panel the button and its
|
|
24
|
+
* ground were the same colour and the control had no shape. Primary is lime on
|
|
25
|
+
* both dark brand surfaces now, measured at 3.79:1 against the panel.
|
|
26
|
+
*/
|
|
27
|
+
function CtaBanner({ text, action, className, children, ...props }) {
|
|
28
|
+
return (_jsxs("section", { "data-slot": "cta-banner", "data-cg-surface": "panel", className: cn("flex flex-col items-start gap-6 rounded-2xl bg-panel px-6 py-10 text-ink", "sm:flex-row sm:items-center sm:justify-between", className), ...props, children: [text?.trim() ? (_jsx("p", { className: "max-w-(--cg-measure) text-body-lg text-balance", children: text })) : null, action ?? children] }));
|
|
29
|
+
}
|
|
30
|
+
export { CtaBanner };
|
|
31
|
+
//# sourceMappingURL=cta-banner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cta-banner.js","sourceRoot":"","sources":["../../src/blocks/cta-banner.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAA;AAEvC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,SAAS,SAAS,CAAC,EACjB,IAAI,EACJ,MAAM,EACN,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EAKT;IACC,OAAO,CACL,gCACY,YAAY,qBACN,OAAO,EACvB,SAAS,EAAE,EAAE,CACX,0EAA0E,EAC1E,gDAAgD,EAChD,SAAS,CACV,KACG,KAAK,aAER,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CACd,YAAG,SAAS,EAAC,gDAAgD,YAAE,IAAI,GAAK,CACzE,CAAC,CAAC,CAAC,IAAI,EACP,MAAM,IAAI,QAAQ,IACX,CACX,CAAA;AACH,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,CAAA"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* The drop target for the first of the three doors: drag something onto the grid.
|
|
4
|
+
*
|
|
5
|
+
* Built from scratch rather than on a Base UI primitive because there is not one.
|
|
6
|
+
* `@base-ui/react@1.7.0` exports 82 subpaths and none of them is file, drop or
|
|
7
|
+
* drag shaped, so this is the same category as PlugMethod.
|
|
8
|
+
*
|
|
9
|
+
* ## The keyboard path is a real file input
|
|
10
|
+
*
|
|
11
|
+
* The visible dashed area is decoration. Underneath is an actual
|
|
12
|
+
* `<input type="file">`, visually hidden but focusable, wrapped in a `<label>`.
|
|
13
|
+
* Tab order, Enter, Space, the native picker and the screen-reader announcement
|
|
14
|
+
* all come from the browser and cannot drift out of sync with the visuals.
|
|
15
|
+
*
|
|
16
|
+
* Drag and drop is an ENHANCEMENT layered on top, which is the correct shape:
|
|
17
|
+
* dragging is a pointer gesture with no keyboard equivalent, so it can never be
|
|
18
|
+
* the only way in. A `div` with `role="button"` and hand-rolled key handlers
|
|
19
|
+
* would have been the other option, and would have owned three bugs this does
|
|
20
|
+
* not have.
|
|
21
|
+
*
|
|
22
|
+
* ## Fills inherit rather than name a surface
|
|
23
|
+
*
|
|
24
|
+
* `bg-current/5` instead of `bg-accent`. `--cg-surface-subtle` is declared only
|
|
25
|
+
* in the base scope, so `bg-accent` paints lavender #f2f1f7 inside a purple
|
|
26
|
+
* panel. `currentColor` is the already-flipped text colour, so the wash is 5%
|
|
27
|
+
* ink on white and 5% white on both dark surfaces. Borders can safely use
|
|
28
|
+
* `border-ring`, which does flip per scope: purple at :root, white on panel,
|
|
29
|
+
* lime on ink.
|
|
30
|
+
*/
|
|
31
|
+
type DropZoneProps = {
|
|
32
|
+
/** Called with what survived the `accept` filter. */
|
|
33
|
+
onDrop?: (items: File[]) => void;
|
|
34
|
+
/** Called with what did not, so a caller can say why nothing happened. */
|
|
35
|
+
onReject?: (items: File[]) => void;
|
|
36
|
+
/** Same syntax as the native attribute. Enforced on BOTH paths, see below. */
|
|
37
|
+
accept?: string;
|
|
38
|
+
multiple?: boolean;
|
|
39
|
+
disabled?: boolean;
|
|
40
|
+
invalid?: boolean;
|
|
41
|
+
/** The headline. Defaults to the grid's own wording. */
|
|
42
|
+
title?: React.ReactNode;
|
|
43
|
+
/** One line under it. */
|
|
44
|
+
hint?: React.ReactNode;
|
|
45
|
+
/** The line inside the target area. */
|
|
46
|
+
prompt?: React.ReactNode;
|
|
47
|
+
name?: string;
|
|
48
|
+
id?: string;
|
|
49
|
+
className?: string;
|
|
50
|
+
};
|
|
51
|
+
declare function DropZone({ onDrop, onReject, accept, multiple, disabled, invalid, title, hint, prompt, name, id, className, }: DropZoneProps): React.JSX.Element;
|
|
52
|
+
export { DropZone };
|
|
53
|
+
export type { DropZoneProps };
|
|
54
|
+
//# sourceMappingURL=drop-zone.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drop-zone.d.ts","sourceRoot":"","sources":["../../src/blocks/drop-zone.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,KAAK,aAAa,GAAG;IACnB,qDAAqD;IACrD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAA;IAChC,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAA;IAClC,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,wDAAwD;IACxD,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,yBAAyB;IACzB,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,uCAAuC;IACvC,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAoBD,iBAAS,QAAQ,CAAC,EAChB,MAAM,EACN,QAAQ,EACR,MAAM,EACN,QAAgB,EAChB,QAAgB,EAChB,OAAe,EACf,KAAgC,EAChC,IAAgC,EAChC,MAA2C,EAC3C,IAAI,EACJ,EAAE,EACF,SAAS,GACV,EAAE,aAAa,qBA8Kf;AAED,OAAO,EAAE,QAAQ,EAAE,CAAA;AACnB,YAAY,EAAE,aAAa,EAAE,CAAA"}
|