@cloudgrid-io/ui 0.0.1 → 0.1.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.
Files changed (184) hide show
  1. package/README.md +109 -0
  2. package/dist/blocks/agent-prompt.d.ts +37 -0
  3. package/dist/blocks/agent-prompt.d.ts.map +1 -0
  4. package/dist/blocks/agent-prompt.js +53 -0
  5. package/dist/blocks/agent-prompt.js.map +1 -0
  6. package/dist/blocks/card-grid.d.ts +38 -0
  7. package/dist/blocks/card-grid.d.ts.map +1 -0
  8. package/dist/blocks/card-grid.js +32 -0
  9. package/dist/blocks/card-grid.js.map +1 -0
  10. package/dist/blocks/compare-table.d.ts +13 -0
  11. package/dist/blocks/compare-table.d.ts.map +1 -0
  12. package/dist/blocks/compare-table.js +55 -0
  13. package/dist/blocks/compare-table.js.map +1 -0
  14. package/dist/blocks/creation-tile.d.ts +57 -0
  15. package/dist/blocks/creation-tile.d.ts.map +1 -0
  16. package/dist/blocks/creation-tile.js +32 -0
  17. package/dist/blocks/creation-tile.js.map +1 -0
  18. package/dist/blocks/cta-banner.d.ts +31 -0
  19. package/dist/blocks/cta-banner.d.ts.map +1 -0
  20. package/dist/blocks/cta-banner.js +31 -0
  21. package/dist/blocks/cta-banner.js.map +1 -0
  22. package/dist/blocks/drop-zone.d.ts +54 -0
  23. package/dist/blocks/drop-zone.d.ts.map +1 -0
  24. package/dist/blocks/drop-zone.js +121 -0
  25. package/dist/blocks/drop-zone.js.map +1 -0
  26. package/dist/blocks/feature-cells.d.ts +46 -0
  27. package/dist/blocks/feature-cells.d.ts.map +1 -0
  28. package/dist/blocks/feature-cells.js +46 -0
  29. package/dist/blocks/feature-cells.js.map +1 -0
  30. package/dist/blocks/hub-index.d.ts +55 -0
  31. package/dist/blocks/hub-index.d.ts.map +1 -0
  32. package/dist/blocks/hub-index.js +22 -0
  33. package/dist/blocks/hub-index.js.map +1 -0
  34. package/dist/blocks/logo.d.ts +24 -0
  35. package/dist/blocks/logo.d.ts.map +1 -0
  36. package/dist/blocks/logo.js +34 -0
  37. package/dist/blocks/logo.js.map +1 -0
  38. package/dist/blocks/option-card.d.ts +31 -0
  39. package/dist/blocks/option-card.d.ts.map +1 -0
  40. package/dist/blocks/option-card.js +32 -0
  41. package/dist/blocks/option-card.js.map +1 -0
  42. package/dist/blocks/page-heading.d.ts +33 -0
  43. package/dist/blocks/page-heading.d.ts.map +1 -0
  44. package/dist/blocks/page-heading.js +30 -0
  45. package/dist/blocks/page-heading.js.map +1 -0
  46. package/dist/blocks/plug-method.d.ts +76 -0
  47. package/dist/blocks/plug-method.d.ts.map +1 -0
  48. package/dist/blocks/plug-method.js +30 -0
  49. package/dist/blocks/plug-method.js.map +1 -0
  50. package/dist/blocks/pricing-tier-cards.d.ts +47 -0
  51. package/dist/blocks/pricing-tier-cards.d.ts.map +1 -0
  52. package/dist/blocks/pricing-tier-cards.js +12 -0
  53. package/dist/blocks/pricing-tier-cards.js.map +1 -0
  54. package/dist/blocks/pricing-tiers.d.ts +29 -0
  55. package/dist/blocks/pricing-tiers.d.ts.map +1 -0
  56. package/dist/blocks/pricing-tiers.js +30 -0
  57. package/dist/blocks/pricing-tiers.js.map +1 -0
  58. package/dist/blocks/quote.d.ts +27 -0
  59. package/dist/blocks/quote.d.ts.map +1 -0
  60. package/dist/blocks/quote.js +28 -0
  61. package/dist/blocks/quote.js.map +1 -0
  62. package/dist/blocks/rich-text.d.ts +38 -0
  63. package/dist/blocks/rich-text.d.ts.map +1 -0
  64. package/dist/blocks/rich-text.js +39 -0
  65. package/dist/blocks/rich-text.js.map +1 -0
  66. package/dist/blocks/stage-panel.d.ts +5 -0
  67. package/dist/blocks/stage-panel.d.ts.map +1 -0
  68. package/dist/blocks/stage-panel.js +30 -0
  69. package/dist/blocks/stage-panel.js.map +1 -0
  70. package/dist/blocks/step-item.d.ts +24 -0
  71. package/dist/blocks/step-item.d.ts.map +1 -0
  72. package/dist/blocks/step-item.js +34 -0
  73. package/dist/blocks/step-item.js.map +1 -0
  74. package/dist/blocks/tool-logo.d.ts +15 -0
  75. package/dist/blocks/tool-logo.d.ts.map +1 -0
  76. package/dist/blocks/tool-logo.js +59 -0
  77. package/dist/blocks/tool-logo.js.map +1 -0
  78. package/dist/blocks/tool-marks.d.ts +120 -0
  79. package/dist/blocks/tool-marks.d.ts.map +1 -0
  80. package/dist/blocks/tool-marks.js +94 -0
  81. package/dist/blocks/tool-marks.js.map +1 -0
  82. package/dist/index.d.ts +45 -0
  83. package/dist/index.d.ts.map +1 -0
  84. package/dist/index.js +63 -0
  85. package/dist/index.js.map +1 -0
  86. package/dist/lib/cloudgrid-cn.d.ts +65 -0
  87. package/dist/lib/cloudgrid-cn.d.ts.map +1 -0
  88. package/dist/lib/cloudgrid-cn.js +90 -0
  89. package/dist/lib/cloudgrid-cn.js.map +1 -0
  90. package/dist/tokens/base.json +57 -38
  91. package/dist/tokens.css +38 -19
  92. package/dist/ui/accordion.d.ts +7 -0
  93. package/dist/ui/accordion.d.ts.map +1 -0
  94. package/dist/ui/accordion.js +19 -0
  95. package/dist/ui/accordion.js.map +1 -0
  96. package/dist/ui/badge.d.ts +8 -0
  97. package/dist/ui/badge.d.ts.map +1 -0
  98. package/dist/ui/badge.js +34 -0
  99. package/dist/ui/badge.js.map +1 -0
  100. package/dist/ui/button.d.ts +9 -0
  101. package/dist/ui/button.d.ts.map +1 -0
  102. package/dist/ui/button.js +35 -0
  103. package/dist/ui/button.js.map +1 -0
  104. package/dist/ui/card.d.ts +12 -0
  105. package/dist/ui/card.d.ts.map +1 -0
  106. package/dist/ui/card.js +26 -0
  107. package/dist/ui/card.js.map +1 -0
  108. package/dist/ui/carousel.d.ts +37 -0
  109. package/dist/ui/carousel.d.ts.map +1 -0
  110. package/dist/ui/carousel.js +34 -0
  111. package/dist/ui/carousel.js.map +1 -0
  112. package/dist/ui/checkbox.d.ts +4 -0
  113. package/dist/ui/checkbox.d.ts.map +1 -0
  114. package/dist/ui/checkbox.js +10 -0
  115. package/dist/ui/checkbox.js.map +1 -0
  116. package/dist/ui/code-block.d.ts +9 -0
  117. package/dist/ui/code-block.d.ts.map +1 -0
  118. package/dist/ui/code-block.js +57 -0
  119. package/dist/ui/code-block.js.map +1 -0
  120. package/dist/ui/combobox.d.ts +25 -0
  121. package/dist/ui/combobox.d.ts.map +1 -0
  122. package/dist/ui/combobox.js +59 -0
  123. package/dist/ui/combobox.js.map +1 -0
  124. package/dist/ui/dialog.d.ts +18 -0
  125. package/dist/ui/dialog.d.ts.map +1 -0
  126. package/dist/ui/dialog.js +39 -0
  127. package/dist/ui/dialog.js.map +1 -0
  128. package/dist/ui/dropdown-menu.d.ts +30 -0
  129. package/dist/ui/dropdown-menu.d.ts.map +1 -0
  130. package/dist/ui/dropdown-menu.js +53 -0
  131. package/dist/ui/dropdown-menu.js.map +1 -0
  132. package/dist/ui/input-group.d.ts +19 -0
  133. package/dist/ui/input-group.d.ts.map +1 -0
  134. package/dist/ui/input-group.js +59 -0
  135. package/dist/ui/input-group.js.map +1 -0
  136. package/dist/ui/input.d.ts +4 -0
  137. package/dist/ui/input.d.ts.map +1 -0
  138. package/dist/ui/input.js +9 -0
  139. package/dist/ui/input.js.map +1 -0
  140. package/dist/ui/number-field.d.ts +10 -0
  141. package/dist/ui/number-field.d.ts.map +1 -0
  142. package/dist/ui/number-field.js +39 -0
  143. package/dist/ui/number-field.js.map +1 -0
  144. package/dist/ui/panel.d.ts +36 -0
  145. package/dist/ui/panel.d.ts.map +1 -0
  146. package/dist/ui/panel.js +39 -0
  147. package/dist/ui/panel.js.map +1 -0
  148. package/dist/ui/select.d.ts +16 -0
  149. package/dist/ui/select.d.ts.map +1 -0
  150. package/dist/ui/select.js +36 -0
  151. package/dist/ui/select.js.map +1 -0
  152. package/dist/ui/separator.d.ts +4 -0
  153. package/dist/ui/separator.d.ts.map +1 -0
  154. package/dist/ui/separator.js +9 -0
  155. package/dist/ui/separator.js.map +1 -0
  156. package/dist/ui/skeleton.d.ts +3 -0
  157. package/dist/ui/skeleton.d.ts.map +1 -0
  158. package/dist/ui/skeleton.js +7 -0
  159. package/dist/ui/skeleton.js.map +1 -0
  160. package/dist/ui/sonner.d.ts +4 -0
  161. package/dist/ui/sonner.d.ts.map +1 -0
  162. package/dist/ui/sonner.js +36 -0
  163. package/dist/ui/sonner.js.map +1 -0
  164. package/dist/ui/switch.d.ts +6 -0
  165. package/dist/ui/switch.d.ts.map +1 -0
  166. package/dist/ui/switch.js +9 -0
  167. package/dist/ui/switch.js.map +1 -0
  168. package/dist/ui/table.d.ts +11 -0
  169. package/dist/ui/table.d.ts.map +1 -0
  170. package/dist/ui/table.js +30 -0
  171. package/dist/ui/table.js.map +1 -0
  172. package/dist/ui/tabs.d.ts +11 -0
  173. package/dist/ui/tabs.d.ts.map +1 -0
  174. package/dist/ui/tabs.js +38 -0
  175. package/dist/ui/tabs.js.map +1 -0
  176. package/dist/ui/textarea.d.ts +4 -0
  177. package/dist/ui/textarea.d.ts.map +1 -0
  178. package/dist/ui/textarea.js +8 -0
  179. package/dist/ui/textarea.js.map +1 -0
  180. package/dist/ui/tooltip.d.ts +8 -0
  181. package/dist/ui/tooltip.d.ts.map +1 -0
  182. package/dist/ui/tooltip.js +37 -0
  183. package/dist/ui/tooltip.js.map +1 -0
  184. package/package.json +47 -14
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,wBAAwB,CAAA;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;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,eAAe,CAAA;AAC5E,OAAO,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAA;AAE3C;;;;;;;;;;;;;;;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":"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"}
@@ -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,wBAAwB,CAAA;AAE3C;;;;;;;;;;;;;;;;;;;;;;;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"}