Crawler-Factory

Design-Language/01-design-language.md

Crawler Dashboard Design Language

Portable design pack. Drop this file (plus tokens.css and 02-component-recipes.md) into any Claude Code project, any Claude.ai chat, any Cursor session, any future module of Algolia Central. The 200-line system below produces UIs that match the live Algolia dashboard on day one.

Source: distilled from 32 screenshots of dashboard.algolia.com (Wellington crawler, app 0EXRPAXB56, captured 2026-05-03). Findings live in 00-findings.md. Token CSS lives in tokens.css. Component recipes live in 02-component-recipes.md.

Version: 1.1 — 2026-05-03 (added §2.5 Run-control surface as our value-add)


0. The 7-line summary (read this first)

  1. Two chrome modes: outer dashboard for browsing, focused workspace for operating one asset.
  2. Vertical left rail with three small-caps sections; subtle blue left-bar for active.
  3. Page = H1 + optional description + optional underlined tabs.
  4. Setting cards are the workhorse — icon + title + description + value + Edit; one per row; expand inline to edit.
  5. Edit existing → inline expansion. Create new → modal. Never mix.
  6. Persistent top-right run-control cluster (CTA + per-crawler controls); close X exits the workspace.
  7. Restraint everywhere: no gradients, no toasts, no animations, generous whitespace, blue is the only accent color.

Where we differ from Algolia: Algolia's dashboard treats crawls as fire-and-forget. We're building Crawler Factory as a control plane for long-running, multi-domain ingestion. Pause / Resume / Re-crawl / Stop are our value-add primitives — see §2.5. Visually they fit Algolia's vocabulary; functionally they go further.


1. Foundations

1.1 Color — the four-bucket rule

Bucket Tokens When
Surface --surface-canvas, --surface-card, --surface-elevated Backgrounds. Canvas is the page; card is the white container; elevated is a modal.
Ink --ink-primary, --ink-secondary, --ink-muted, --ink-disabled Text. ~80%, ~60%, ~40%, ~25% perceptual lightness on white.
Line --line-default, --line-strong Borders, dividers, hairlines.
Accent --accent (blue) — and only blue Links, active states, primary buttons, focus rings, active nav, active tab underline.
Status (pill badges only — never as raw text or backgrounds) --status-success, --status-warning, --status-neutral, --status-danger Each has a foreground + soft fill. Used only inside small rounded badges.

Hard rules: - One accent color. Never use another hue for emphasis. - Status colors live inside pills only, never as page-level fills. - No gradients. Anywhere. (The Crawler Factory mockups had a blue→purple gradient on the root tree node — remove it.) - Dark mode is reserved for code editor surfaces only.

1.2 Type — three sizes do most of the work

Use Size / weight / case
Page H1 24px / 700 / sentence
Card title 15px / 600 / sentence
Body / table cell / button label 14px / 400 (600 for buttons) / sentence
Description / muted helper 13px / 400 / sentence / --ink-secondary
Small-caps label / section header 11px / 700 / letter-spacing 0.08em / --ink-muted
Code / monospace 12-13px / 400 / monospace stack

Stack: Inter / system-ui fallback. No display fonts. No serifs.

1.3 Space — multiples of 4, with two anchors

  • 4 / 8 / 12 / 16 / 20 / 24 / 32 / 48 / 64.
  • Card internal padding: 28px. This is the most repeated value.
  • Card-to-card gap: 16px in vertical stacks.

1.4 Radius

  • 12px → cards, buttons.
  • 8px → inputs, small chips.
  • 999px (full pill) → status badges, toggle tracks.
  • 16px → modals.

1.5 Shadow

  • Cards: no shadow, only borders.
  • Modals: 0 8px 24px rgba(15, 23, 42, 0.06).
  • Hovered button: 0 1px 2px rgba(15, 23, 42, 0.04).

1.6 Motion

  • Transitions on color and background only, 150ms ease-out.
  • Inline edit expansion: height transition, 200ms ease-out.
  • Modal: opacity fade, 150ms.
  • No spring physics, no parallax, no entrance animations on lists. The dashboard is calm.

2. Information architecture pattern

2.1 Two chrome modes (mandatory)

┌──────────────────────────────────────────────────────────────────────────┐
│  Outer dashboard chrome                                                  │
│  ┌─Algolia mark + product rail (left)                                    │
│  ├─Section sub-nav (e.g. Data sources → Crawler)                         │
│  └─Top bar (app picker, search, Upgrade, AI Assist, avatar)              │
│  ── Main content: Lists, summaries, dashboards across assets ──          │
└──────────────────────────────────────────────────────────────────────────┘

         User clicks an asset (e.g. a crawler row in the list)
                                   ↓
┌──────────────────────────────────────────────────────────────────────────┐
│  Focused workspace chrome (replaces outer chrome)                        │
│  ┌─Module wordmark (top-left)         ┌─Persistent CTA + close X (top-right)│
│  ├─Scope indicator (top-center)       │                                   │
│  └─Vertical sectioned nav (left)      └─Tabs / page content (right)       │
└──────────────────────────────────────────────────────────────────────────┘

Rule: entering a focused workspace fully replaces the outer chrome. Don't keep both. Exit only via the close X (top-right) or by pressing Escape.

2.2 Three-section left nav (focused workspace only)

SETUP ▼            ← create / configure the asset
  Overview
  Configuration
  Editor (advanced)
  Suggestions

STATUS ▼           ← what is happening / what happened
  URL inspector
  Monitoring
  Data Analysis
  Path Explorer
  Logs Explorer

CONFIGURATION ▼    ← admin / metadata / danger
  External Data
  Settings

Rules: - Section headers are 11px / 700 / 0.08em letter-spacing / --ink-muted with a small leading icon. - Items are 14px / 400 / sentence case. - Active item: 2px blue left bar + blue text. No filled pill background. - Hover: text color brightens. No pill, no underline. - Sections are independently collapsible (chevron next to header). - Use this same SETUP / STATUS / CONFIGURATION grouping for all future modules unless the model genuinely demands different (most won't).

2.3 Page header (mandatory shape)

<H1 page title>                             [optional secondary control]
<optional 1-line description>

[optional tabs (bottom-border underline, blue active)]   [optional badge counts]

────────────────────────────────────────────────────────────────────────
<page body — usually a vertical stack of cards or one big table>

Tabs: never pills, never boxes. Bottom-border underline only. 14px / 600 / blue when active, muted when not.

2.4 Persistent CTA model

  • Top-right of the focused workspace always has one primary action that represents the next obvious step for this asset. Algolia stops here. We extend it (see §2.5).
  • Examples: Start Crawling (pre-first-run), Crawl now (post-first-run, idle), Pause (running), Resume (paused), Review and Publish (when the Editor is dirty).
  • Next to it: a close X to exit the workspace.
  • The CTA's label is always stateful — it reflects the current state and the most useful next action.

2.5 Run-control surface — our value-add (extends Algolia)

This is the largest functional differentiator between Crawler Factory and the base Algolia crawler. We add granular runtime control because operators ingesting many domains, on schedules they don't fully control, need it. The surface lives in two places:

(a) The persistent top-right CTA cluster — single-asset workspace

Replace Algolia's single CTA with a stateful cluster: a primary action + an overflow menu. The primary button changes label based on current run state. The overflow menu surfaces secondary controls.

Run state Primary button Overflow menu items
idle (never run, or last run finished) Crawl now (filled blue) Edit configuration · Re-crawl from scratch · Settings
running Pause (ghost outline, blue) Stop crawl · View live log · Settings
paused Resume (filled blue) Stop crawl · Edit configuration · Re-crawl from scratch
stopped (user stopped manually) Crawl now (filled blue) Re-crawl from scratch · Edit configuration · Settings
failed Retry (filled blue) View error log · Edit configuration · Settings

Rules: - The primary button label is the mode change verb, not the noun. "Pause" not "Pause crawler". - Pause is reversible mid-run — the partial index stays; resuming continues from the last URL. - Re-crawl from scratch is destructive of the records (not the crawler config or the index) — needs a confirm dialog with a scope statement, not the full typed-confirm pattern. - Stop ends the current run cleanly, finalizes whatever was indexed so far, and moves the asset to stopped. Different from Pause (which preserves resumable state).

(b) The per-row control on the crawler list — multi-asset overview

In the outer-dashboard list of crawlers, each row gets a small status pill + a 3-dot overflow menu. The overflow menu exposes: Crawl now, Pause / Resume, Stop, Open, Settings, Delete. The user can manage multiple crawlers without entering each one.

Rules: - The overflow menu's contents are stateful — paused crawlers show "Resume", running ones show "Pause". - Bulk actions on the list (select multiple → Pause all / Resume all / Crawl all) are scoped to the current page of the table — never silent across pages. - The destructive Delete always opens the typed-confirm modal (Recipe 10 in 02-component-recipes.md), regardless of how it's invoked.

Component implication: add <RunControlCluster /> (CTA + overflow) and <RunStatePill /> (the row-level status indicator). Both must appear in 02-component-recipes.md as numbered recipes when this section is implemented.


3. Component vocabulary

3.1 The setting card — <SettingCard />

The single most repeated atom. Every Configuration / setting screen is a vertical stack of these.

┌──────────────────────────────────────────────────────────────────────┐
│ [icon-tile]  Setting name                        <value>     [Edit]  │
│              One-line description, muted.                            │
└──────────────────────────────────────────────────────────────────────┘

Specs: white surface, 1px line-default border, 12px radius, 28px padding, full content-width, stack with 16px gap. Left icon tile is 32px squared, light grey fill, 8px radius, dark icon glyph. Title 15px/600, description 13px/muted. Right side: muted current-value text + secondary "Edit" button. The Edit button is the only affordance — clicking the card body does nothing.

Edit-mode (inline): the right value+Edit disappear, controls render below the description, and a Save (primary, dirty-state) + Cancel (ghost) row sits at card bottom. Never open a modal for editing.

3.2 The form card row library

Inside a card-in-edit-mode, use these proven row patterns:

  1. Toggle + visible label ("Enabled" / "Disabled" to the right of the switch).
  2. Toggle → conditional fields revealed below, indented or in a labelled fieldset.
  3. Number stepper + unit ([ 100 ]▲▼ URLs).
  4. Repeating row + add + delete (icon trash on each, ghost "+ Add X" below).
  5. Scheme + path duo (small dropdown + wide URL input).
  6. Read-only with copy (greyed input + copy icon button).
  7. Masked secret + reveal + copy (mask + eye icon + copy icon).

3.3 Modal for create — <CreateEntityDialog />

Used only when adding a new sub-entity (a new index, a new exclusion rule that needs more than one input, a new auth method).

┌─────────────── Add Markdown Index ──────────────[×]┐
│                                                    │
│  Index Name *                                      │
│  [ Enter index name (e.g., markdown-index)      ]  │
│                                                    │
│  Content Tag *                                     │
│  [ main                                         ]  │
│                                                    │
│  Template *                                        │
│  [ Non-DocSearch (Generic)                  ▾ ]    │
│  Choose the template that matches…                 │
│                                                    │
│                          [ Cancel ]  [ Add Index ] │
└────────────────────────────────────────────────────┘

Specs: centered, ~480px width, 16px radius, soft shadow, dim backdrop. Required asterisks. Right-aligned action footer. Cancel = ghost, primary = blue.

3.4 Destructive confirm — <DestructiveTypedConfirm />

Delete crawler                                                 [×]

Are you sure you want to delete this crawler? This action is
irreversible. We will delete X, Y, Z.

[scope statement: what is NOT deleted]

Enter "DELETE" to confirm.

[ ____________________________________________ ]

[ Delete ]   ← red, disabled until "DELETE" typed exactly

Use for any irreversible operation. The scope statement (what's not affected) is required — don't omit it.

3.5 Status pill — <StatusPill />

Variants: success, warning, neutral, danger, running (blue tint with optional dot). Always 11px / 600 / sentence / 999px radius / soft fill + darker foreground.

3.6 KPI tile — <KpiTile />

Used at the top of data-rich pages (Path Explorer, Data Analysis post-run). Anatomy: huge number (24-28px / 700) + small all-caps label below + optional unit-value icon top-right. Sit in a horizontal row of 3-5 tiles, equal width.

3.7 Empty / locked / gated states — <EmptyState variant="..." />

Three variants: - data → centered grey small text inside the table/card frame. - gated → centered illustration + bold heading + 2-line explanation + primary CTA + "Learn more" link, occupying the full content area. - edit-empty → centered grey text + a single ghost "+ Add" button just above the form's Save/Cancel row.

3.8 Tabs — <Tabs underline />

Always bottom-border underline. Never pills, never boxed. 14px / 600. Active: blue text + 2px blue underline. Inactive: muted text. Optional count badge to the right of the label.

3.9 Toolbar — <Toolbar />

Stretches above tables. Search input (left, with icon) + filter dropdowns + right-aligned secondary actions + far-right primary action.

3.10 Side info banner — <InfoBanner />

Light blue/grey background, info icon, single line of text, optional inline "Learn more" link. Used for safety rails inline within edit cards (e.g., Record Loss Policy: "won't update until you check and confirm").


4. State semantics

State Visual treatment
Default As specified above
Hover Color lifts; cursor pointer; no scale, no shadow
Focus 4px ring of --accent at 25% alpha
Active / pressed Color darkens 10%
Disabled 40% opacity; cursor not-allowed; no hover
Dirty (unsaved form) Save button gains accent fill (was disabled grey)
Loading Replace label with a thin 14px circular spinner of the same color; do not change layout
Empty See <EmptyState /> variants
Error Red 12px text below the input; input border turns --status-danger. No global red banner unless system-level.
Success after save Inline collapse back to read-mode. No toast.

5. Voice and microcopy

  • Plain. "Tell the crawler when to crawl your site" beats "Configure cron schedule expression."
  • Active. "Start crawling" not "Crawler will be started."
  • No marketing energy. The original Crawler Factory mockup said "Turn any website into a searchable index — in minutes." Algolia's dashboard would never write that. They'd say "Crawler / Wellington / Configuration."
  • Explain consequences. Destructive copy explicitly states what will and will not be affected.
  • Numbers over adjectives. "Affects 3 records out of 13 (23.08%)" beats "A few records may be affected."
  • Sentence case. Even buttons: "Add new crawler", not "Add New Crawler". Title case is reserved for the page-level H1 only when the noun warrants ("Crawler Configuration").
  • No emoji. None observed. None to be added.

6. Accessibility floor

  • Focus visible everywhere. 4px ring at 25% accent alpha.
  • Tab order follows visual reading order.
  • Active link/nav state never conveyed by color alone — the 2px left bar + bold weight carry it too.
  • Status pills never carry information by color alone — always paired with a label ("Success", "Canceled").
  • Touch targets ≥ 44px, including small icon buttons (use 44px hit area even on a 16px icon).
  • Modals trap focus and return focus to the trigger on close.
  • Every input has a <label>. Help text is aria-describedby-linked.
  • Color contrast ≥ 4.5:1 for text, ≥ 3:1 for large/UI.

7. The "what's banned" list (matches dashboard restraint)

  • ❌ Gradients
  • ❌ Drop shadows on cards (modals only, soft)
  • ❌ Toasts on save
  • ❌ Spring/bounce/parallax animation
  • ❌ Entrance animations on lists
  • ❌ Multi-color palettes (one accent only)
  • ❌ Dark mode (except code editor surfaces)
  • ❌ Filled pills for nav active state (use the left-bar treatment)
  • ❌ Icon-only buttons without aria-label or tooltip
  • ❌ Modal-on-modal stacking
  • ❌ Auto-saving without an explicit Save button (be deterministic)
  • ❌ Live polling counters / animated number tickers (the dashboard is request-response)
  • ❌ Decorative emoji
  • ❌ Marketing-style hero copy

8. The decision tree (when in doubt)

Need to show the user some configuration?
├─ Is it a setting on an existing asset?      → SettingCard, edit inline
├─ Is it creating a new sub-entity?           → CreateEntityDialog (modal)
└─ Is it a destructive operation?             → DestructiveTypedConfirm

Need to show the user some data?
├─ Is it a list of similar items?             → Table with toolbar
├─ Is it grouped by something?                → Grouped subtables (one per group)
├─ Is it a single big number?                 → KpiTile (in a row of peers)
└─ Is it the empty / locked state?            → EmptyState (pick the variant)

Need a primary action on the page?
├─ Is it the "next step" for this asset?         → Persistent top-right CTA
├─ Is it a runtime mode change (pause/stop/etc)? → RunControlCluster (§2.5)
└─ Is it on a card?                              → Edit / Save / Cancel inside the card

Need to communicate a state?
├─ Is it an item's lifecycle state?           → StatusPill
├─ Is it a warning before user proceeds?      → InfoBanner inline
└─ Is it after-the-fact feedback?             → Inline collapse back. No toast.

9. Portability checklist (use this when forking)

When dropping this pack into a new project / agent / repo:

  • [ ] Copy tokens.css into the project and import it before any other styles.
  • [ ] Copy 00-findings.md, 01-design-language.md, 02-component-recipes.md.
  • [ ] Confirm the project uses Inter / system-ui or fallback to it.
  • [ ] Confirm the chrome model: list view in outer dashboard, asset operation in focused workspace.
  • [ ] Confirm the left nav is sectioned (SETUP / STATUS / CONFIGURATION) for asset-focused workspaces.
  • [ ] Confirm the persistent top-right CTA represents the next step for the current asset.
  • [ ] Confirm no gradients / no toasts / no entrance animations / no decorative color.
  • [ ] Run 02-component-recipes.md against any new component to find a prebuilt match before authoring a new one.

10. What this pack does NOT cover (explicitly)

  • The marketing surface around the dashboard (algolia.com itself).
  • Email templates.
  • Mobile-native (iOS / Android) — the dashboard is desktop-first; mobile is a long-tail concern.
  • Dark mode (except code editor).
  • Accessibility audit beyond WCAG 2.2 AA floor.
  • Localization (RTL, long-string allowances) — designs are generous-spaced enough but not formally tested.

Living document. When the dashboard adds a new pattern or we observe a violation of these rules in production, edit this file and bump the version.