diff --git a/.design-sync/NOTES.md b/.design-sync/NOTES.md new file mode 100644 index 0000000..76740ad --- /dev/null +++ b/.design-sync/NOTES.md @@ -0,0 +1,157 @@ +# design-sync notes — Cloudrite + +Repo-specific gotchas for future syncs. Read this before re-running. + +## What this repo is + +Not a component library — a Next.js 16 marketing site (`private: true`, no `dist/`, +no `exports`, no `.d.ts` tree). The DS surface is `components/ui/*` (54 shadcn/ui +primitives, new-york style) plus 7 hand-built Cloudrite page sections. + +## The staging package (`.ds-pkg/`) + +The converter needs a package with a built entry and a `.d.ts` tree. Three scripts +under `.design-sync/` build one from source; run them **in this order** (this is +`cfg.buildCmd`): + +1. `node_modules/.bin/tsc -p .design-sync/tsconfig.dts.json` — declaration emit, + 69 `.d.ts` files. Exits 0; all three steps are chained with `&&`, so a real + failure stops the run. + **`../next-env.d.ts` must stay in that config's `include`.** It pulls in Next's + JSX augmentation for styled-jsx; without it the ` + + +); diff --git a/.design-sync/previews/Dialog.tsx b/.design-sync/previews/Dialog.tsx new file mode 100644 index 0000000..5fe4263 --- /dev/null +++ b/.design-sync/previews/Dialog.tsx @@ -0,0 +1,46 @@ +import type { ReactNode } from 'react'; +import { + Button, + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + Input, + Label, +} from 'cloudrite'; + +// Cloudrite is dark-only — the overlay surfaces read correctly only against the +// brand background, not the harness's white card body. +const Surface = ({ children }: { children: ReactNode }) => ( +
{children}
+); + +// `defaultOpen` is what makes the card worth looking at — a bare trigger shows +// none of Dialog's parts. Paired with cardMode:single in .design-sync/config.json. +export const Open = () => ( + + + e.preventDefault()}> + + Add a site + + We'll point the DNS and issue an SSL certificate automatically. + + +
+ + +
+ + + + + + +
+
+
+); diff --git a/.design-sync/previews/DropdownMenu.tsx b/.design-sync/previews/DropdownMenu.tsx new file mode 100644 index 0000000..061c0c9 --- /dev/null +++ b/.design-sync/previews/DropdownMenu.tsx @@ -0,0 +1,58 @@ +import type { ReactNode } from 'react'; +import { + Button, + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuTrigger, +} from 'cloudrite'; +import { Download, RefreshCw, Settings, Trash2 } from 'lucide-react'; + +// Cloudrite is dark-only — the overlay surfaces read correctly only against the +// brand background, not the harness's white card body. +const Surface = ({ children }: { children: ReactNode }) => ( +
{children}
+); + +export const Open = () => ( + +
+ + + + + + cloudrite.co.nz + + + + + Clear cache + ⌘R + + + + Download backup + + + + Settings + + + + Auto-renew SSL + + + + Delete site + + + +
+
+); diff --git a/.design-sync/previews/Empty.tsx b/.design-sync/previews/Empty.tsx new file mode 100644 index 0000000..16335b3 --- /dev/null +++ b/.design-sync/previews/Empty.tsx @@ -0,0 +1,40 @@ +import type { ReactNode } from 'react'; +import { + Button, + Empty, + EmptyContent, + EmptyDescription, + EmptyHeader, + EmptyMedia, + EmptyTitle, +} from 'cloudrite'; +import { CloudOff, Plus } from 'lucide-react'; + +// Cloudrite is dark-only — foreground-coloured text and `border-border` are +// invisible on the preview harness's white card body. Stories render on the +// brand surface, which is also how a real screen is built. +const Surface = ({ children }: { children: ReactNode }) => ( +
{children}
+); + +export const Default = () => ( + + + + + + + No sites yet + + Add your first site and we'll handle DNS, SSL and backups for you. + + + + + + + +); diff --git a/.design-sync/previews/Features.tsx b/.design-sync/previews/Features.tsx new file mode 100644 index 0000000..edf35da --- /dev/null +++ b/.design-sync/previews/Features.tsx @@ -0,0 +1,19 @@ +import { Features } from 'cloudrite'; + +// The "why Cloudrite" feature showcase. Rotates its active feature on a 4s interval; the still captures whichever is active on first paint. +// +// The section draws light-on-dark against the page background, which the preview +// card harness paints white — hence the surface wrapper. Transitions and +// animation delays are zeroed because the capture harness only waits on fonts +// and images, so an entrance animation would otherwise be screenshotted mid-flight. +const still = `*,*::before,*::after{ + transition-duration:0s !important;transition-delay:0s !important; + animation-duration:0s !important;animation-delay:0s !important; +}`; + +export const Default = () => ( +
+ + +
+); diff --git a/.design-sync/previews/Field.tsx b/.design-sync/previews/Field.tsx new file mode 100644 index 0000000..ed66c7b --- /dev/null +++ b/.design-sync/previews/Field.tsx @@ -0,0 +1,78 @@ +import type { ReactNode } from 'react'; +import { + Checkbox, + Field, + FieldContent, + FieldDescription, + FieldError, + FieldGroup, + FieldLabel, + FieldLegend, + FieldSeparator, + FieldSet, + Input, +} from 'cloudrite'; + +// Cloudrite is dark-only — foreground-coloured text and `border-border` are +// invisible on the preview harness's white card body. Stories render on the +// brand surface, which is also how a real screen is built. +const Surface = ({ children }: { children: ReactNode }) => ( +
{children}
+); + +export const Vertical = () => ( + + + + Domain + + We'll point the DNS for you at no charge. + + + +); + +export const Horizontal = () => ( + + + + + + Managed backups + Nightly snapshots kept for 30 days. + + + + +); + +export const WithError = () => ( + + + + Email + + Enter a valid email address. + + + +); + +export const Fieldset = () => ( + +
+ Hosting + + + Plan name + + + + + Site limit + + + +
+
+); diff --git a/.design-sync/previews/Footer.tsx b/.design-sync/previews/Footer.tsx new file mode 100644 index 0000000..4b0f9eb --- /dev/null +++ b/.design-sync/previews/Footer.tsx @@ -0,0 +1,19 @@ +import { Footer } from 'cloudrite'; + +// The site footer: service/company link columns, contact details and the Cloudrite mark. +// +// The section draws light-on-dark against the page background, which the preview +// card harness paints white — hence the surface wrapper. Transitions and +// animation delays are zeroed because the capture harness only waits on fonts +// and images, so an entrance animation would otherwise be screenshotted mid-flight. +const still = `*,*::before,*::after{ + transition-duration:0s !important;transition-delay:0s !important; + animation-duration:0s !important;animation-delay:0s !important; +}`; + +export const Default = () => ( +
+ +
+
+); diff --git a/.design-sync/previews/Form.tsx b/.design-sync/previews/Form.tsx new file mode 100644 index 0000000..55efc56 --- /dev/null +++ b/.design-sync/previews/Form.tsx @@ -0,0 +1,79 @@ +import type { ReactNode } from 'react'; +import { useForm } from 'react-hook-form'; +import { + Button, + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, + Input, + Textarea, +} from 'cloudrite'; + +// Cloudrite is dark-only — foreground-coloured text and `border-border` are +// invisible on the preview harness's white card body. Stories render on the +// brand surface, which is also how a real screen is built. +const Surface = ({ children }: { children: ReactNode }) => ( +
{children}
+); + +type Values = { name: string; email: string; message: string }; + +// `Form` is react-hook-form's FormProvider — it needs a useForm() instance, and +// FormField wires each control through Controller. This is the enquiry form on +// the Cloudrite contact section. +export const EnquiryForm = () => { + const form = useForm({ + defaultValues: { name: 'Jamie Lambert', email: 'jamie@cafe.co.nz', message: '' }, + }); + return ( + +
+ e.preventDefault()}> + ( + + Name + + + + + )} + /> + ( + + Email + + + + We reply within one business day. + + )} + /> + ( + + How can we help? + +