diff --git a/docs/empty-state-guidelines.md b/docs/empty-state-guidelines.md new file mode 100644 index 0000000..fb69e2f --- /dev/null +++ b/docs/empty-state-guidelines.md @@ -0,0 +1,27 @@ +# Empty State Illustration Style + Copy Guidelines + +## Design goals + +- Help users understand slot availability, wallet readiness, and booking progress at a glance. +- Keep the primary action obvious without crowding the state with competing buttons. +- Use calm, trust-building language before asking for sensitive actions like wallet connection. + +## Illustration rules + +- Use abstract product-shaped panels instead of decorative mascots so the empty state still feels product-specific. +- Reserve the strongest accent for the most important action area. +- Keep illustrations non-essential for meaning; screen-reader users should get the same guidance from headings and body copy. + +## Copy rules + +- Headline: say what is missing in plain language. +- Body copy: explain why the state matters or what remains private. +- Guidance: use short supporting lines to reduce uncertainty. +- Action labels: start with a verb and match the next obvious step. + +## Reusable implementation notes + +- Shared shell: `src/app/components/dashboard-shell.tsx` +- Empty state card: `src/app/components/empty-state-card.tsx` +- Status chip: `src/app/components/ui/status-chip.tsx` +- Route-level states: `src/app/dashboard/loading.tsx`, `src/app/dashboard/error.tsx` diff --git a/src/app/components/dashboard-shell.tsx b/src/app/components/dashboard-shell.tsx new file mode 100644 index 0000000..a57d4ab --- /dev/null +++ b/src/app/components/dashboard-shell.tsx @@ -0,0 +1,38 @@ +import Link from "next/link"; + +type DashboardShellProps = { + children: React.ReactNode; +}; + +export function DashboardShell({ children }: DashboardShellProps) { + return ( +
+
+ +
+
{children}
+
+ ); +} diff --git a/src/app/components/empty-state-card.tsx b/src/app/components/empty-state-card.tsx new file mode 100644 index 0000000..8200999 --- /dev/null +++ b/src/app/components/empty-state-card.tsx @@ -0,0 +1,55 @@ +import type { ReactNode } from "react"; +import { EmptyStateIllustration } from "./empty-state-illustration"; +import { StatusChip } from "./ui/status-chip"; + +type EmptyStateCardProps = { + eyebrow: string; + title: string; + description: string; + accentLabel: string; + status: { + label: string; + tone?: "info" | "warning" | "success" | "danger" | "neutral"; + }; + guidance: string[]; + actions?: ReactNode; +}; + +export function EmptyStateCard({ + eyebrow, + title, + description, + accentLabel, + status, + guidance, + actions, +}: EmptyStateCardProps) { + return ( +
+
+

+ {eyebrow} +

+ {status.label} +
+
+ +
+
+

{title}

+

{description}

+ +
+ {actions ?
{actions}
: null} +
+ ); +} diff --git a/src/app/components/empty-state-illustration.tsx b/src/app/components/empty-state-illustration.tsx new file mode 100644 index 0000000..2151c41 --- /dev/null +++ b/src/app/components/empty-state-illustration.tsx @@ -0,0 +1,43 @@ +type EmptyStateIllustrationProps = { + accentLabel: string; +}; + +export function EmptyStateIllustration({ + accentLabel, +}: EmptyStateIllustrationProps) { + return ( +