Import brand dialog
Reads a design system from a company's website, shows what it found on a sample section, and applies it to the workspace.
import ImportBrandDialog from "@/pages/library/ImportBrandDialog";
import "@/pages/library/library.css";ImportBrandDialog sets up a workspace's design system from its website, so pages and ad creatives match the brand from the first draft. It is one large dialog with three steps: where the site is, the reading of it, and what was found, shown on a sample section before anything changes. Nothing is applied until the last step is confirmed.
The reading is scripted, like the rest of the mock. No request is made to the site. Any address containing "petavue" returns Petavue's own brand; any other address is hashed to one of four sample brands, so the same address always gives the same result.
The flow
Type an address such as meridian.com and press Enter or "Read my website". The checklist ticks off one line at a time, then the review opens. "Apply to design system" writes the result to the workspace and closes the dialog. Use "Reset design system" to go back to the defaults.
{importing && (
<ImportBrandDialog
onClose={() => setImporting(false)}
onApplied={(brand, host) => {
setImporting(false);
setTab("design");
toast.success(`${brand}'s design system imported from ${host}.`);
}}
/>
)}The dialog reads and writes the design store itself (useDesignStore in src/pages/library/useDesignStore.js). The caller only opens it and reacts once it is applied.
Steps
| Step | Body | Cancel | Confirm |
|---|---|---|---|
| Form | A lead sentence, Website address, Company name and a note: "Nothing changes until you have seen what was found and applied it." | Cancel: closes | Read my website |
| Reading | The address, then five lines that tick off every 620ms: opening the homepage, colours, fonts, corners and spacing, the logo, header and footer. The review opens 450ms after the last one. | Cancel: closes | Reading…, which does nothing |
| Review | On the left, what was found: five colours with their hex values, the heading and body fonts drawn in themselves, a sample button with its corner radius, and the Library components it was matched to. On the right, a hero and a call-to-action banner drawn in the new brand at 330px tall. | Back: returns to the form | Apply to design system |
Form
- Website address is required. Once
https://,www.and any path are removed, it must be letters, digits and hyphens in two or more parts separated by dots;Meridian.com/pricingreads asmeridian.com. Otherwise the field shows "Enter an address like yourcompany.com." after the first try. - Company name is optional. Its placeholder, and the name used when it is left empty, is the first part of the host with a capital letter:
meridian.comgives "Meridian". - Enter in either field starts the reading.
What Apply changes
setDesign({ brand, colors, headFont, bodyFont, radius }). The logo and the heading and body sizes are kept. The two fonts are loaded from Google Fonts when the reading starts, so the review can draw them.
States
| State | What shows |
|---|---|
| Address not valid | The address field's error, after "Read my website" or Enter. The reading does not start. |
| Reading, current line | Primary text with a spinning CircleNotch in --color-primary-500. With reduced motion, the spinner stops. |
| Reading, done line | Secondary text with a filled CheckCircle in --color-green. |
| Reading, waiting line | --color-grey-300 text with a still CircleNotch. |
Layout
| Part | Style |
|---|---|
| Panel | Dialog at lg, 800px, with .lib-import. The body scrolls past min(64vh, 620px). |
| Lead | 14px secondary text on a 21px line. |
| Checklist | 14px lines with a 14px gap and 16px icons, at least 250px tall so the dialog keeps its height. |
| Review | Two columns: 260px for what was found, the rest for the sample, 24px apart. |
| Section labels | 12px uppercase semibold secondary text. |
| Colour rows | A 22px chip with 6px corners, the role in 13px and the hex in 12px monospace --color-grey-500. |
| Fonts | The heading font at 22px semibold and the body font at 15px, each with a 12px label in --color-grey-500. |
| Sample | ScaledPreview at 330px inside a 1px --color-grey-100 frame with 10px corners. |
The colours, fonts and button in the review are the imported brand's, not Petavue's. That is the point of the step.
Props
| Prop | Type | Default | Notes |
|---|---|---|---|
onClose | () => void | Escape, scrim click, the close icon, and Cancel in the form and reading steps. | |
onApplied | (brand: string, host: string) => void | Called after the design store is updated. It does not close the dialog, so close it here. |
Accessibility
- The wrapper has
role="dialog",aria-modal="true"andaria-label="Import from your website". - The address field has
autoFocus, so typing can start at once. Its error is announced withrole="alert". - The reading checklist is a plain list with no live region. A screen reader is not told as lines tick off or when the review opens.
- "Reading…" looks like an enabled primary button but does nothing while the site is read. The Dialog panel has no way to disable it.
- Escape closes the dialog at any step, including the review, and the reading is lost.
- Focus is not kept inside the dialog and is not returned to the button that opened it.
Do and don't
- Do let people see the result on a real section before anything changes. That is why the review comes before Apply.
- Do tell people after applying where the result went. The Library switches to the Design system tab and says which site it came from.
- Don't apply anything during the reading step.
- Don't use this dialog to edit single values. Colours, fonts and corners are changed one at a time on the Design system tab.
When to use it
Use it wherever a workspace has no brand yet, or wants to start again from its website. It is self-contained: render it, and handle onClose and onApplied. For other multi-step setups, build on a large Dialog from @/ui in the same way: one dialog, the confirm label naming the next step, and Back in place of Cancel after the first step.
Where it is used
| File | What |
|---|---|
src/pages/library/LibraryPage.jsx, LibraryPage | Opened by "Import from website" in the Library header, and by the same button at the top of the Design system tab (DesignSystemTab). On apply, the Library switches to the Design system tab and shows a toast. |