Estimate: 12m · Depends on: 1.0.5.2
Every screen in Motir will eventually have an empty state ("you don't have any projects yet — create your first one") and at least one error state ("we couldn't load this — try again"). If each screen invents its own version, the product feels inconsistent. This Subtask produces two reusable React components — EmptyState and ErrorState — that every screen composes when it needs them.
Why these are separate from the primitives: primitives (1.0.5.2) are atoms — Button, Input, Card. Empty / error states are compositions — they use a primitive (Card) plus an icon, headline, body text, and a CTA. They're closer to "patterns" than "atoms." Keeping them in their own Subtask gives them the focused design attention they deserve (they're the screens users see when something's wrong; the polish bar is high).
What you'll do: Create /components/ui/EmptyState.tsx and /components/ui/ErrorState.tsx. Each takes title, description, optional icon, optional action (a Button or button-shaped link), and renders inside a Card. Add minimum-viable illustrations — even a single nice SVG icon per state is enough for v1. Add them to the specimen page from 1.0.5.2 with at least 2 sample uses each.
<EmptyState title description? icon? action? /> renders a centered, padded card with an icon (default: a friendly placeholder SVG), a title (h2-equivalent), an optional description (muted text), and an optional CTA (typically a Button).<ErrorState title description? error? retry? /> renders similarly but with a warning/error visual treatment. error can be an Error object whose message is shown when in dev mode; retry is an optional callback that shows a "Try again" button.role="alert"; both have semantic heading./components/ui/Card.tsx, Button.tsx (from 1.0.5.2) — the building blocks/app/_tokens/page.tsx (from 1.0.5.1, extended in 1.0.5.2) — to add specimens to