Unclassified

UI Design Guide — IntegrateWise Platform

Design system, components, and patterns for building workbenches on top of IntegrateWise.


Design Language

Forest · Paper · Combo

TokenValueUsage
Canvas#1A1A1ASidebar, nav foundation (dark earthy)
Paper#F7F6F2Main content (warm white)
Accent#5B814FForest green — highlights, active states
Gold#B8943FInsight, premium, wayfinding

Typography

FontUsage
Bebas NeueDisplay / hero headlines ONLY
DM Serif Displayh1–h3 (serif headings)
Instrument Sansh4–h6, body, UI (default sans)
IBM Plex MonoCode, technical labels, data

Design Tokens

:root {
  /* Surfaces */
  --iw-surface-canvas: #f4f0e8;
  --iw-surface-default: #ebe5d8;
  --iw-surface-subtle: #e0d9c8;
  --iw-surface-raised: #f9f6ef;
  --iw-surface-inverse: #0c0c0c;

  /* Text */
  --iw-text-strong: #0c0c0c;
  --iw-text-default: #0c0c0c;
  --iw-text-muted: #5a5550;
  --iw-text-faint: #8a8580;
  --iw-text-inverse: #f4f0e8;
  --iw-text-accent: #2d5a3d;
  --iw-text-highlight: #b8943f;

  /* Borders */
  --iw-border-subtle: #d8d0c0;
  --iw-border-default: #c4baa8;
  --iw-border-strong: #a89a88;
  --iw-border-accent: #b8943f;

  /* Status */
  --iw-status-success: #3d7a50;
  --iw-status-warning: #b8943f;
  --iw-status-danger: #8b2020;
  --iw-status-info: #3d5247;
}

Layout Structure

App Shell

┌─────────────────────────────────────────────────────────────┐
│  Sidebar (240px)  │           Main Content                  │
├───────────────────┼─────────────────────────────────────────┤
│  Logo             │  Header (breadcrumb, actions)           │
│  Navigation       │  ┌─────────────────────────────────┐   │
│  - Dashboard      │  │                                 │   │
│  - Entities       │  │         Page Content             │   │
│  - Integrations   │  │                                 │   │
│  - Capabilities   │  │                                 │   │
│  - Settings       │  └─────────────────────────────────┘   │
│                   │  Footer (optional)                      │
└───────────────────┴─────────────────────────────────────────┘

Sidebar

<Sidebar>
  <Logo />
  <Navigation>
    <NavItem icon="dashboard" label="Dashboard" href="/app/work/dashboard" />
    <NavItem icon="entities" label="Entities" href="/app/work/entities" />
    <NavItem icon="integrations" label="Integrations" href="/app/work/integrations" />
    <NavItem icon="capabilities" label="Capabilities" href="/app/work/capabilities" />
    <NavItem icon="settings" label="Settings" href="/app/work/settings" />
  </Navigation>
  <UserProfile />
</Sidebar>

Core Components

1. Entity Card

Displays a single entity (account, contact, deal, etc.).

<EntityCard
  entity={{
    id: "acc_001",
    name: "Acme Corp",
    entity_type: "account",
    status: "active",
    metadata: { industry: "Technology", ARR: 120000 },
  }}
  onClick={() => navigate(`/app/work/entities/acc_001`)}
/>

Props:

interface EntityCardProps {
  entity: SpineEntity;
  onClick?: () => void;
  selected?: boolean;
  showActions?: boolean;
}

2. Entity List

Displays a list of entities with filtering and sorting.

<EntityList
  entities={workbench.entities.deal}
  filters={[
    { key: "status", label: "Status", options: ["open", "won", "lost"] },
    { key: "source_tool", label: "Source", options: ["salesforce", "hubspot"] },
  ]}
  sortBy="updated_at"
  sortOrder="desc"
  onEntityClick={(entity) => navigate(`/app/work/entities/${entity.id}`)}
/>

3. Connector Card

Displays a connector with status and connect button.

<ConnectorCard
  connector={{
    id: "salesforce",
    name: "Salesforce",
    category: "crm",
    status: "available",
    capabilities: { auth: true, webhook: true },
  }}
  onConnect={() => connectConnector("salesforce")}
/>

4. Capability Card

Displays a capability with execute button.

<CapabilityCard
  capability={{
    name: "salesforce:read-accounts",
    description: "Read accounts from Salesforce",
    min_tier: "free",
    channel: "sync",
  }}
  onExecute={(params) => executeCapability("salesforce:read-accounts", params)}
/>

5. Signal Card

Displays a signal (insight, alert, notification).

<SignalCard
  signal={{
    id: "sig_001",
    severity: "warning",
    title: "Deal at risk",
    description: "Acme Corp deal hasn't been updated in 14 days",
    timestamp: "2026-07-21T10:30:00Z",
  }}
  onDismiss={() => dismissSignal("sig_001")}
/>

6. Readiness Meter

Displays department readiness score.

<ReadinessMeter
  readiness={{
    overall_score: 0.85,
    overall_state: "live",
    buckets: [
      { capability: "accounts", state: "live", score: 0.9 },
      { capability: "deals", state: "live", score: 0.85 },
    ],
  }}
/>

7. Timeline

Displays activity timeline.

<Timeline
  events={[
    { id: "evt_001", type: "created", title: "Deal created", timestamp: "2026-07-21T10:00:00Z" },
    { id: "evt_002", type: "updated", title: "Stage changed", timestamp: "2026-07-21T11:00:00Z" },
  ]}
/>

Page Templates

Dashboard Page

function DashboardPage() {
  const { workbench, loading } = useWorkbench(token, tenantId, "SALES");

  if (loading) return <Spinner />;

  return (
    <Page>
      <Header>
        <Title>Sales Dashboard</Title>
        <Actions>
          <Button onClick={refresh}>Refresh</Button>
        </Actions>
      </Header>

      <Metrics>
        <MetricCard label="Accounts" value={workbench.entities.account.length} />
        <MetricCard label="Deals" value={workbench.entities.deal.length} />
        <MetricCard label="People" value={workbench.entities.person.length} />
        <MetricCard label="Signals" value={workbench.signals.length} />
      </Metrics>

      <ReadinessMeter readiness={workbench.readiness} />

      <Grid>
        <Section title="Recent Deals">
          <EntityList entities={workbench.entities.deal.slice(0, 5)} />
        </Section>

        <Section title="Signals">
          <SignalList signals={workbench.signals.slice(0, 5)} />
        </Section>
      </Grid>
    </Page>
  );
}

Entities Page

function EntitiesPage() {
  const { workbench, loading } = useWorkbench(token, tenantId, "SALES");
  const [entityType, setEntityType] = useState("deal");

  return (
    <Page>
      <Header>
        <Title>Entities</Title>
        
      </Header>

      <EntityList
        entities={workbench.entities[entityType] || []}
        filters={[...]}
        sortBy="updated_at"
        onEntityClick={(entity) => navigate(`/app/work/entities/${entity.id}`)}
      />
    </Page>
  );
}

Integrations Page

function IntegrationsPage() {
  const { connectors, loading, connect } = useConnectors(token, tenantId);
  const { integrations } = useIntegrations(token, tenantId);

  return (
    <Page>
      <Header>
        <Title>Integrations</Title>
      </Header>

      <Section title="Connected">
        {integrations.map((integration) => (
          <ConnectorCard
            key={integration.provider}
            connector={integration}
            status="connected"
            onDisconnect={() => disconnect(integration.provider)}
          />
        ))}
      </Section>

      <Section title="Available">
        {connectors
          .filter((c) => c.status === "available")
          .map((connector) => (
            <ConnectorCard
              key={connector.id}
              connector={connector}
              onConnect={() => connect(connector.id)}
            />
          ))}
      </Section>
    </Page>
  );
}

Capabilities Page

function CapabilitiesPage() {
  const { capabilities, loading, execute } = useCapabilities(token, tenantId);

  return (
    <Page>
      <Header>
        <Title>Capabilities</Title>
      </Header>

      <Grid>
        {capabilities.map((capability) => (
          <CapabilityCard
            key={capability.name}
            capability={capability}
            onExecute={(params) => execute(capability.name, params)}
          />
        ))}
      </Grid>
    </Page>
  );
}

Entity Detail Page

function EntityDetailPage({ entityId }) {
  const { workbench } = useWorkbench(token, tenantId, "SALES");
  const entity = findEntity(workbench, entityId);

  return (
    <Page>
      <Header>
        <BackButton onClick={() => navigate(-1)} />
        <Title>{entity.name}</Title>
        <Actions>
          <Button onClick={() => editEntity(entity)}>Edit</Button>
          <Button onClick={() => deleteEntity(entity)} variant="danger">
            Delete
          </Button>
        </Actions>
      </Header>

      <Grid>
        <Section title="Details">
          <EntityDetails entity={entity} />
        </Section>

        <Section title="Relationships">
          <RelationshipList
            relationships={workbench.relationships.filter(
              (r) => r.source === entity.id || r.target === entity.id
            )}
          />
        </Section>

        <Section title="Timeline">
          <Timeline events={workbench.timeline.filter((e) => e.entity_id === entity.id)} />
        </Section>

        <Section title="Signals">
          <SignalList signals={workbench.signals.filter((s) => s.entity_id === entity.id)} />
        </Section>
      </Grid>
    </Page>
  );
}

Responsive Design

Breakpoints

/* Mobile */
@media (max-width: 640px) {
  .sidebar {
    display: none;
  }
  .main-content {
    padding: 16px;
  }
}

/* Tablet */
@media (min-width: 641px) and (max-width: 1024px) {
  .sidebar {
    width: 64px;
  }
  .sidebar-label {
    display: none;
  }
}

/* Desktop */
@media (min-width: 1025px) {
  .sidebar {
    width: 240px;
  }
  .main-content {
    padding: 24px;
  }
}

Dark Mode

@media (prefers-color-scheme: dark) {
  :root {
    --iw-surface-canvas: #1a1a1a;
    --iw-surface-default: #2a2a2a;
    --iw-surface-subtle: #3a3a3a;
    --iw-surface-raised: #4a4a4a;
    --iw-surface-inverse: #f4f0e8;

    --iw-text-strong: #f4f0e8;
    --iw-text-default: #e0e0e0;
    --iw-text-muted: #a0a0a0;
    --iw-text-faint: #707070;
    --iw-text-inverse: #1a1a1a;

    --iw-border-subtle: #3a3a3a;
    --iw-border-default: #4a4a4a;
    --iw-border-strong: #5a5a5a;
  }
}

Accessibility

Color Contrast

TokenLight ModeDark ModeRatio
Text on Paper#0c0c0c on #f4f0e8#f4f0e8 on #1a1a1a15.4:1
Text on Canvas#f4f0e8 on #1a1a1a#0c0c0c on #f4f0e815.4:1
Accent on Paper#2d5a3d on #f4f0e8#3d7a50 on #1a1a1a7.2:1

Keyboard Navigation

  • All interactive elements must be focusable
  • Focus order follows visual layout
  • Skip links for main content

ARIA Labels

<button aria-label="Connect Salesforce" onClick={connect}>
  Connect
</button>

<nav aria-label="Main navigation">
  <a href="/dashboard" aria-current="page">Dashboard</a>
</nav>

Component Library

Available Components

ComponentLocationDescription
Button@/components/common/buttonPrimary, secondary, danger variants
Card@/components/common/cardContainer with header, body, footer
Input@/components/common/inputText, number, search inputs
Select@/components/common/selectDropdown selection
Modal@/components/common/modalDialog overlay
Toast@/components/common/toastNotification messages
Spinner@/components/common/spinnerLoading indicator
Tabs@/components/common/tabsTab navigation
Badge@/components/common/badgeStatus indicators
Avatar@/components/common/avatarUser/entity avatars

Import Pattern


Resources

  • Design Tokens: apps/web/src/styles/design-tokens.css
  • Components: apps/web/src/components/
  • API Reference: docs/api/PLATFORM_API.md
  • Service Topology: docs/api/SERVICE_TOPOLOGY.md