Skip to main content

Layout Patterns

Layout Patterns

Common layout patterns and page structures

Tags: pattern layout structure

This guide covers common layout patterns for building applications with the theme library.

Application Shells​

Dashboard Application​

<!-- +layout.svelte -->
<script>
  import { DashboardLayout } from '@classic-homes/theme-svelte';

  const navigation = [
    {
      id: 'main',
      items: [
        { id: 'dashboard', name: 'Dashboard', href: '/', icon: 'home' },
        { id: 'projects', name: 'Projects', href: '/projects', icon: 'folder' },
        { id: 'analytics', name: 'Analytics', href: '/analytics', icon: 'chart' },
      ],
    },
    {
      id: 'settings',
      title: 'Settings',
      items: [
        { id: 'profile', name: 'Profile', href: '/settings/profile' },
        { id: 'team', name: 'Team', href: '/settings/team' },
      ],
    },
  ];

  const user = {
    name: 'John Doe',
    email: 'john@example.com',
    initials: 'JD',
  };
</script>

<DashboardLayout {navigation} {user}>
  <slot />
</DashboardLayout>

Marketing Site​

<!-- +layout.svelte -->
<script>
  import { PublicLayout } from '@classic-homes/theme-svelte';

  const navigation = [
    { id: 'features', name: 'Features', href: '/features' },
    { id: 'pricing', name: 'Pricing', href: '/pricing' },
    { id: 'docs', name: 'Docs', href: '/docs' },
    { id: 'blog', name: 'Blog', href: '/blog' },
  ];

  const footerLinks = [
    {
      id: 'product',
      title: 'Product',
      items: [
        { id: 'features', name: 'Features', href: '/features' },
        { id: 'pricing', name: 'Pricing', href: '/pricing' },
      ],
    },
    {
      id: 'company',
      title: 'Company',
      items: [
        { id: 'about', name: 'About', href: '/about' },
        { id: 'blog', name: 'Blog', href: '/blog' },
      ],
    },
  ];
</script>

<PublicLayout {navigation} {footerLinks}>
  <slot />
</PublicLayout>

Page Patterns​

Dashboard Page​

<script>
  import { PageHeader, Section, Card, DataTable } from '@classic-homes/theme-svelte';
</script>

<div class="space-y-6">
  <PageHeader title="Dashboard" subtitle="Welcome back, John">
    {#snippet actions()}
      <Button>New Project</Button>
    {/snippet}
  </PageHeader>

  <!-- Stats Grid -->
  <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
    <Card>
      <Card.Header>
        <Card.Title>Total Revenue</Card.Title>
      </Card.Header>
      <Card.Content>
        <p class="text-3xl font-bold">$45,231</p>
        <p class="text-sm text-muted-foreground">+20% from last month</p>
      </Card.Content>
    </Card>
    <!-- More stat cards -->
  </div>

  <!-- Content Sections -->
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
    <Section title="Recent Activity">
      <DataTable data={activities} columns={activityColumns} />
    </Section>
    <Section title="Quick Actions">
      <!-- Action buttons -->
    </Section>
  </div>
</div>

Settings Page​

<script>
  import { Tabs, TabPanel, Section } from '@classic-homes/theme-svelte';

  const tabs = [
    { id: 'profile', label: 'Profile' },
    { id: 'security', label: 'Security' },
    { id: 'notifications', label: 'Notifications' },
  ];
</script>

<div class="max-w-4xl">
  <PageHeader title="Settings" subtitle="Manage your account settings" />

  <Tabs {tabs} class="mt-6">
    <TabPanel id="profile">
      <Section title="Personal Information">
        <!-- Profile form -->
      </Section>
    </TabPanel>

    <TabPanel id="security">
      <Section title="Password">
        <!-- Password form -->
      </Section>
      <Section title="Two-Factor Authentication" class="mt-6">
        <!-- 2FA settings -->
      </Section>
    </TabPanel>

    <TabPanel id="notifications">
      <Section title="Email Notifications">
        <!-- Notification toggles -->
      </Section>
    </TabPanel>
  </Tabs>
</div>

List/Detail Pattern​

<!-- List page -->
<div class="space-y-4">
  <PageHeader title="Projects">
    {#snippet actions()}
      <Button href="/projects/new">New Project</Button>
    {/snippet}
  </PageHeader>

  <Card>
    <DataTable
      data={projects}
      columns={projectColumns}
      onRowClick={(project) => goto(`/projects/${project.id}`)}
    />
  </Card>
</div>

<!-- Detail page -->
<div class="space-y-6">
  <PageHeader title={project.name} subtitle={`Created ${formatDate(project.createdAt)}`}>
    {#snippet actions()}
      <Button variant="outline" href="/projects">Back</Button>
      <Button href={`/projects/${project.id}/edit`}>Edit</Button>
    {/snippet}
  </PageHeader>

  <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
    <div class="lg:col-span-2 space-y-6">
      <Section title="Details">
        <!-- Project details -->
      </Section>
    </div>
    <div>
      <Section title="Activity">
        <!-- Activity timeline -->
      </Section>
    </div>
  </div>
</div>

Content Layouts​

Two Column with Sidebar​

<div class="grid grid-cols-1 lg:grid-cols-[1fr,300px] gap-6">
  <main>
    <!-- Main content -->
  </main>
  <aside>
    <!-- Sidebar content -->
  </aside>
</div>

Three Column​

<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
  <div>Column 1</div>
  <div>Column 2</div>
  <div>Column 3</div>
</div>

Masonry-style Grid​

<div class="columns-1 md:columns-2 lg:columns-3 gap-4 space-y-4">
  {#each items as item}
    <Card class="break-inside-avoid">
      <!-- Card content -->
    </Card>
  {/each}
</div>

Responsive Patterns​

Stack to Grid​

<div class="flex flex-col md:flex-row gap-4">
  <div class="md:w-1/3">Sidebar</div>
  <div class="md:w-2/3">Content</div>
</div>

Hide on Mobile​

<div class="hidden md:block">
  <!-- Desktop only content -->
</div>

<div class="md:hidden">
  <!-- Mobile only content -->
</div>

Responsive Navigation​

<nav class="flex items-center justify-between">
  <Logo />

  <!-- Desktop nav -->
  <div class="hidden md:flex gap-4">
    {#each navItems as item}
      <a href={item.href}>{item.name}</a>
    {/each}
  </div>

  <!-- Mobile menu button -->
  <Button class="md:hidden" variant="ghost" onclick={toggleMenu}>Menu</Button>
</nav>

Empty States​

<div class="flex flex-col items-center justify-center py-12">
  <svg class="h-16 w-16 text-muted-foreground/50 mb-4">
    <!-- Empty state icon -->
  </svg>
  <h3 class="text-lg font-semibold mb-2">No projects yet</h3>
  <p class="text-muted-foreground mb-4">Create your first project to get started.</p>
  <Button href="/projects/new">Create Project</Button>
</div>

Loading States​

{#if loading}
  <div class="space-y-4">
    <Skeleton class="h-8 w-48" />
    <div class="grid grid-cols-3 gap-4">
      <Skeleton class="h-32" />
      <Skeleton class="h-32" />
      <Skeleton class="h-32" />
    </div>
  </div>
{:else}
  <!-- Content -->
{/if}

Best Practices​

  1. Use layout components: DashboardLayout, PublicLayout, FormPageLayout
  2. Consistent spacing: Use space-y-* and gap-* utilities
  3. Responsive first: Design for mobile, enhance for desktop
  4. Logical grouping: Use Section and Card to organize content
  5. Clear hierarchy: Use PageHeader for page titles
On this page