Dashboard Redesign — App Shell Implementation Plan

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: Transform the dashboard from a card grid into an app-shell experience where the existing sidebar gains a waitlist list section, and the main content area becomes a detail panel for the selected waitlist with KPIs, activity feed, and quick actions.

Architecture: The app.html layout already provides a sidebar, topbar, theme toggle, and mobile drawer. The dashboard page content (dashboard.html) renders inside <main class="app-main">. This plan adds a dynamic waitlist list section to the sidebar (populated by dashboard.js when on the dashboard page), replaces the main content with a detail panel, and adds CSS for new components. No backend changes needed.

Tech Stack: Vanilla JS (no framework), CSS custom properties (existing theme system), existing app.js utilities (buildStatCardV2, showEl, hideEl, escapeHtml, apiCall).

Design doc: docs/plans/2026-03-09-dashboard-redesign-design.md

Security note: All dynamic content uses textContent or escapeHtml() — no raw user data is inserted via innerHTML. Only static SVG markup and escaped IDs use innerHTML. This is consistent with the existing codebase patterns.


Task 1: Add Sidebar Waitlist List Section to app.html

Files:

Step 1: Add waitlist list placeholder to sidebar

Add a new section at the top of .app-sidebar-nav (before the first <div class="app-sidebar-section">), with an empty container that dashboard.js will populate:

<div class="app-sidebar-section app-sidebar-waitlists" id="sidebar-waitlists-section" style="display:none;">
  <div class="app-sidebar-heading">Waitlists</div>
  <div id="sidebar-waitlists-list"></div>
  <button class="app-sidebar-create-btn" id="sidebar-create-btn" title="Create waitlist">
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
    <span class="app-sidebar-label">Create Waitlist</span>
  </button>
</div>

This section starts hidden (style="display:none;") and is shown by dashboard.js after loading waitlists. On non-dashboard pages it stays hidden.

Step 2: Verify the layout loads correctly

Run: cd /Users/nonplus/Desktop/makeemwait/docs && bundle exec jekyll build 2>&1 | tail -5 Expected: No Liquid errors, clean build.

Step 3: Commit

git add docs/_layouts/app.html
git commit -m "Sidebar: add waitlist list placeholder section"

Task 2: CSS for Sidebar Waitlist Items

Files:

Step 1: Add sidebar waitlist item styles

Add the following CSS after the .app-sidebar-badge section (see plan for full CSS block):

Key classes to add:

Step 2: Verify build

Run: cd /Users/nonplus/Desktop/makeemwait/docs && bundle exec jekyll build 2>&1 | tail -5

Step 3: Commit

git add docs/assets/css/style.css
git commit -m "CSS: sidebar waitlist list items, selection, create button"

Task 3: CSS for Dashboard Detail Panel, Activity Feed, and Quick Actions

Files:

Step 1: Add detail panel, activity feed, and micro-interaction styles

Key CSS classes to add:

Step 2: Verify build

Step 3: Commit

git add docs/assets/css/style.css
git commit -m "CSS: detail panel, activity feed, quick actions, checklist, micro-interactions"

Task 4: Add Animated Counter Utility to app.js

Files:

Step 1: Add animateCounter function

function animateCounter(el, target, duration, suffix) {
  if (!el || typeof target !== "number") return;
  duration = duration || 600;
  suffix = suffix || "";
  if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
    el.textContent = target.toLocaleString() + suffix;
    return;
  }
  var start = performance.now();
  function step(now) {
    var elapsed = now - start;
    var progress = Math.min(elapsed / duration, 1);
    var eased = 1 - Math.pow(1 - progress, 3);
    var current = Math.round(eased * target);
    el.textContent = current.toLocaleString() + suffix;
    if (progress < 1) requestAnimationFrame(step);
  }
  requestAnimationFrame(step);
}

Key points: Respects prefers-reduced-motion. Ease-out cubic curve. Uses requestAnimationFrame for smooth 60fps animation. Handles both integers and decimals via toLocaleString().

Step 2: Commit

git add docs/assets/js/app.js
git commit -m "Add animateCounter utility for stat card number animation"

Task 5: Restructure dashboard.html for Detail Panel Layout

Files:

Step 1: Replace the main content area

Key changes from the original:

The HTML structure becomes:

<section class="dashboard">
  <div id="welcome-banner" ...>  <!-- welcome banner, unchanged -->
  <div id="dashboard-content">   <!-- NEW: JS renders overview or detail here -->
    <!-- skeleton placeholders -->
  </div>
  <!-- All modals preserved identically -->
</section>

Step 2: Verify build

Step 3: Commit

git add docs/dashboard.html
git commit -m "Dashboard HTML: restructure for sidebar+detail panel layout"

Task 6: Rewrite dashboard.js — Sidebar Population + View Rendering

This is the largest task. It rewrites loadWaitlists() and showDashboardSummary() to populate the sidebar, render overview/detail/empty views, and load an activity feed.

Files:

New global variables:

New functions to add:

  1. populateSidebarWaitlists(waitlists) — creates DOM elements for each waitlist in the sidebar, wires up click handlers to call selectWaitlist()
  2. selectWaitlist(waitlistId) — updates sidebar selection, updates URL via history.replaceState, calls renderDetail()
  3. renderEmptyState(container) — shows onboarding with checklist (Account created pre-checked), CTA button, 3-step flow
  4. renderOverview(container) — shows time-based greeting, 4 aggregate KPI cards with animated counters, top performers leaderboard (top 5 by signup count)
  5. renderDetail(container, wl) — shows header with name + status pill + kebab menu, 3 KPI cards with animated counters, 4 quick action buttons, activity feed section
  6. loadActivityFeed(waitlistId, container) — fetches GET /waitlists/{id}/admin/signups?limit=10, renders each signup as an activity item with anonymized email (first char + *** + @domain), action label, and relative timestamp
  7. timeAgo(dateStr) — converts ISO date to “2m ago”, “3h ago”, “5d ago” format

Updated functions:

DOMContentLoaded handler updates:

Security: All user-provided data (waitlist names, emails) uses textContent for rendering, never innerHTML. The kebab menu uses escaped waitlist IDs in onclick handlers via escapeHtml(), consistent with existing codebase patterns.

Step 1: Implement all new functions

Step 2: Verify build

Step 3: Commit

git add docs/assets/js/dashboard.js
git commit -m "Dashboard JS: sidebar waitlists, overview panel, detail view, activity feed"

Task 7: Verify Everything Works Together

Step 1: Run cd /Users/nonplus/Desktop/makeemwait/docs && bundle exec jekyll build 2>&1 | tail -5 — no errors

Step 2: Run cd /Users/nonplus/Desktop/makeemwait/terraform && terraform validate — “Success!”

Step 3: Check for regressions

Step 4: Verify modal element IDs still match Confirm these IDs exist in both dashboard.html and dashboard.js: share-modal, waitlist-modal, waitlist-form, blast-modal, preset-modal, welcome-banner

Step 5: Describe expected behavior at 3 viewports


Task 8: Push and Deploy

Step 1: git push origin main — deploys frontend via GitHub Pages

Step 2: No Terraform deploy needed — Lambda code untouched

Step 3: Verify at makeemwait.com/dashboard.html


Files Summary

File Changes Scope
docs/_layouts/app.html Add waitlist list placeholder to sidebar Low
docs/assets/css/style.css Sidebar waitlist items, detail panel, activity feed, quick actions, checklist, micro-interactions (~150 lines) High
docs/assets/js/app.js Add animateCounter() utility (~15 lines) Low
docs/dashboard.html Restructure: remove card grid, add dashboard-content container, preserve all modals High
docs/assets/js/dashboard.js Rewrite: sidebar population, overview/detail/empty views, activity feed, animated counters (~300 lines changed) High

Existing Utilities Reused