# App shell

The frame every screen composes into: an icon-collapsible sidebar with grouped nav, badges and a user footer, plus a topbar with breadcrumb that answers the collapsed state, and a stat-card content grid.

Copy-in: `bin/rails g poetry:block app-shell` - the source below is exactly what the generator writes. Composes: avatar, breadcrumb, button, card, icon, separator, sidebar.

## Template

```erb
<%= poetry_sidebar(collapsible: :icon) do |shell| %>
  <% shell.with_nav do %>
    <%= poetry_sidebar_header do %>
      <%# The collapse-aware header shape (a menu button, never a bare
          div): at icon width the button shrinks to the tile and the
          truncating spans disappear with it. %>
      <%= poetry_sidebar_menu do %>
        <%= poetry_sidebar_menu_item do %>
          <%= poetry_sidebar_menu_button(size: :lg) do %>
            <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
              <%= poetry_icon(name: :"audio-waveform", class: "size-4") %>
            </div>
            <div class="grid flex-1 text-left text-sm leading-tight">
              <span class="truncate font-semibold">Meridian</span>
              <span class="truncate text-xs">Operations</span>
            </div>
          <% end %>
        <% end %>
      <% end %>
    <% end %>
    <%= poetry_sidebar_content do %>
      <%= poetry_sidebar_group do %>
        <%= poetry_sidebar_group_label { "Platform" } %>
        <%= poetry_sidebar_menu do %>
          <%= poetry_sidebar_menu_item do %>
            <%= poetry_sidebar_menu_button(href: "/dashboard", active: true) do %>
              <%= poetry_icon(name: :"layout-dashboard") %><span>Dashboard</span>
            <% end %>
          <% end %>
          <%= poetry_sidebar_menu_item do %>
            <%= poetry_sidebar_menu_button(href: "/orders") do %>
              <%= poetry_icon(name: :package) %><span>Orders</span>
            <% end %>
            <%= poetry_sidebar_menu_badge do %>12<% end %>
          <% end %>
          <%= poetry_sidebar_menu_item do %>
            <%= poetry_sidebar_menu_button(href: "/customers") do %>
              <%= poetry_icon(name: :users) %><span>Customers</span>
            <% end %>
          <% end %>
        <% end %>
      <% end %>
      <%= poetry_sidebar_group do %>
        <%= poetry_sidebar_group_label { "Resources" } %>
        <%= poetry_sidebar_menu do %>
          <%= poetry_sidebar_menu_item do %>
            <%= poetry_sidebar_menu_button(href: "/docs") do %>
              <%= poetry_icon(name: :"book-open") %><span>Documentation</span>
            <% end %>
          <% end %>
          <%= poetry_sidebar_menu_item do %>
            <%= poetry_sidebar_menu_button(href: "/support") do %>
              <%= poetry_icon(name: :"life-buoy") %><span>Support</span>
            <% end %>
          <% end %>
        <% end %>
      <% end %>
    <% end %>
    <%= poetry_sidebar_footer do %>
      <%# The footer rides the same collapse-aware shape as the header: at
          icon width the menu button shrinks to the avatar tile and the
          truncating spans clip with it instead of spilling into the inset. %>
      <%= poetry_sidebar_menu do %>
        <%= poetry_sidebar_menu_item do %>
          <% profile = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2NCA2NCI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJnIiB4MT0iMCIgeTE9IjAiIHgyPSIxIiB5Mj0iMSI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjNjM2NmYxIi8+PHN0b3Agb2Zmc2V0PSIuNTUiIHN0b3AtY29sb3I9IiM4YjVjZjYiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNlYzQ4OTkiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48cmVjdCB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIGZpbGw9InVybCgjZykiLz48Y2lyY2xlIGN4PSIzMiIgY3k9IjI1IiByPSIxMCIgZmlsbD0iI2ZmZiIgb3BhY2l0eT0iLjkiLz48cGF0aCBkPSJNMTIgNjRjMi0xMyAxMC0xOSAyMC0xOXMxOCA2IDIwIDE5eiIgZmlsbD0iI2ZmZiIgb3BhY2l0eT0iLjkiLz48L3N2Zz4=" %>
          <%= poetry_sidebar_menu_button(size: :lg) do %>
            <%= poetry_avatar(src: profile, label: "Matt Solt", class: "size-8 rounded-lg") { "MS" } %>
            <div class="grid flex-1 text-left text-sm leading-tight">
              <span class="truncate font-semibold">Matt Solt</span>
              <span class="truncate text-xs">matt@roboruby.com</span>
            </div>
          <% end %>
        <% end %>
      <% end %>
    <% end %>
    <%= poetry_sidebar_rail %>
  <% end %>
  <% shell.with_inset do %>
    <header class="flex h-14 shrink-0 items-center gap-2 border-b px-4 transition-[height] group-has-data-[collapsible=icon]/sidebar-wrapper:h-12">
      <%= poetry_sidebar_trigger %>
      <%= poetry_separator(orientation: :vertical, class: "h-4") %>
      <%= poetry_breadcrumb do |crumb| %>
        <% crumb.with_item("Meridian", href: "/") %>
        <% crumb.with_item("Dashboard") %>
      <% end %>
    </header>
    <div class="flex flex-col gap-6 p-6">
      <div class="flex flex-wrap items-end justify-between gap-4">
        <div class="space-y-1">
          <h1 class="text-2xl font-semibold tracking-tight">Dashboard</h1>
          <p class="text-sm text-muted-foreground">Today across the Meridian workspace.</p>
        </div>
        <%= poetry_button(variant: :outline) do |button| %>
          <% button.with_leading { poetry_icon(name: :download) } %>
          Export
        <% end %>
      </div>
      <div class="grid gap-4 md:grid-cols-3">
        <%= poetry_card(title_tag: :h2) do |card| %>
          <% card.with_title { "Revenue" } %>
          <% card.with_description { "Last 30 days" } %>
          <div class="text-2xl font-semibold tabular-nums">$48,210</div>
          <p class="text-xs text-muted-foreground">+12.4% from the previous period</p>
        <% end %>
        <%= poetry_card(title_tag: :h2) do |card| %>
          <% card.with_title { "Open orders" } %>
          <% card.with_description { "Awaiting fulfillment" } %>
          <div class="text-2xl font-semibold tabular-nums">42</div>
          <p class="text-xs text-muted-foreground">12 due before Friday</p>
        <% end %>
        <%= poetry_card(title_tag: :h2) do |card| %>
          <% card.with_title { "On-time rate" } %>
          <% card.with_description { "Trailing quarter" } %>
          <div class="text-2xl font-semibold tabular-nums">98.2%</div>
          <p class="text-xs text-muted-foreground">Target is 97.5%</p>
        <% end %>
      </div>
      <%= poetry_card(title_tag: :h2) do |card| %>
        <% card.with_title { "Recent activity" } %>
        <% card.with_description { "The latest changes across orders and customers." } %>
        <ul class="space-y-3 text-sm">
          <li class="flex items-center justify-between gap-4">
            <span>ORD-1042 marked fulfilled by Matt</span>
            <span class="text-xs text-muted-foreground tabular-nums">2m ago</span>
          </li>
          <li class="flex items-center justify-between gap-4">
            <span>Northwind Traders added a shipping address</span>
            <span class="text-xs text-muted-foreground tabular-nums">18m ago</span>
          </li>
          <li class="flex items-center justify-between gap-4">
            <span>Refund approved for ORD-1040</span>
            <span class="text-xs text-muted-foreground tabular-nums">1h ago</span>
          </li>
        </ul>
      <% end %>
    </div>
  <% end %>
<% end %>
```
