index.astro

  1---
  2import { getCollection } from 'astro:content';
  3import Base from '../../layouts/Base.astro';
  4import '../../styles/sub-pages.css';
  5import {
  6  SKILL_CATEGORIES,
  7  CATEGORY_ORDER,
  8  CATEGORY_LABELS,
  9  CATEGORY_DESCRIPTIONS,
 10} from '../../data/sub-pages-data';
 11
 12const entries = await getCollection('skills');
 13
 14const grouped: Record<string, typeof entries> = {};
 15for (const cat of CATEGORY_ORDER) {
 16  grouped[cat] = entries
 17    .filter(e => SKILL_CATEGORIES[e.id] === cat)
 18    .sort((a, b) => a.id.localeCompare(b.id));
 19}
 20
 21const allCommands = entries.map(e => ({
 22  slug: e.id,
 23  category: SKILL_CATEGORIES[e.id] || 'system',
 24}));
 25
 26const sidebarGroups: Record<string, { slug: string }[]> = {};
 27for (const cat of CATEGORY_ORDER) {
 28  sidebarGroups[cat] = allCommands
 29    .filter(c => c.category === cat)
 30    .sort((a, b) => a.slug.localeCompare(b.slug));
 31}
 32---
 33
 34<Base
 35  title="Docs | Impeccable"
 36  description="23 commands for design fluency. Browse the full reference for every /impeccable sub-command."
 37  activeNav="docs"
 38  canonicalPath="/docs"
 39  bodyClass="sub-page skills-layout-page"
 40>
 41  <div class="skills-layout">
 42    <aside class="skills-sidebar" aria-label="Commands">
 43      <button class="skills-sidebar-toggle" type="button" aria-expanded="false" aria-controls="skills-sidebar-inner">
 44        <span class="skills-sidebar-toggle-label">Commands</span>
 45        <svg class="skills-sidebar-toggle-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
 46      </button>
 47      <div class="skills-sidebar-inner" id="skills-sidebar-inner">
 48        <p class="skills-sidebar-label">Commands</p>
 49        {CATEGORY_ORDER.map(cat => (
 50          <div class="skills-sidebar-group">
 51            <span class="skills-sidebar-category">{CATEGORY_LABELS[cat]}</span>
 52            <ul class="skills-sidebar-list">
 53              {sidebarGroups[cat].map(cmd => (
 54                <li>
 55                  <a href={`/docs/${cmd.slug}`}>
 56                    <span>{cmd.slug}</span>
 57                  </a>
 58                </li>
 59              ))}
 60            </ul>
 61          </div>
 62        ))}
 63      </div>
 64    </aside>
 65
 66    <div class="skills-main">
 67      <div class="docs-index">
 68        <header class="docs-index-header">
 69          <h1 class="sub-page-title">Commands</h1>
 70          <p class="sub-page-lede">23 commands for design fluency. One skill, six categories, from shaping a new feature to hardening it for production.</p>
 71        </header>
 72
 73        {CATEGORY_ORDER.map(cat => (
 74          <section class="docs-category-section" id={`category-${cat}`}>
 75            <header class="docs-category-header">
 76              <h2 class="docs-category-title">{CATEGORY_LABELS[cat]}</h2>
 77              <p class="docs-category-desc">{CATEGORY_DESCRIPTIONS[cat]}</p>
 78            </header>
 79            <div class="docs-card-grid">
 80              {grouped[cat].map(entry => (
 81                <a href={`/docs/${entry.id}`} class="docs-command-card">
 82                  <h3 class="docs-command-name">/impeccable {entry.id}</h3>
 83                  <p class="docs-command-tagline">{entry.data.tagline}</p>
 84                </a>
 85              ))}
 86            </div>
 87          </section>
 88        ))}
 89      </div>
 90    </div>
 91  </div>
 92
 93  <script is:inline>
 94    document.addEventListener('click', (e) => {
 95      const toggle = e.target.closest('.skills-sidebar-toggle');
 96      if (!toggle) return;
 97      const expanded = toggle.getAttribute('aria-expanded') === 'true';
 98      toggle.setAttribute('aria-expanded', String(!expanded));
 99    });
100  </script>
101
102  <style>
103    .docs-index { padding: 2rem 0 4rem; }
104    .docs-index-header { margin-bottom: 3rem; }
105    .docs-category-section { margin-bottom: 2.5rem; }
106    .docs-category-header { margin-bottom: 1rem; }
107    .docs-category-title { font-family: var(--font-display); font-size: 1.5rem; margin: 0 0 0.25rem; }
108    .docs-category-desc { color: var(--color-ash); font-size: 0.9375rem; margin: 0; }
109    .docs-card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 1rem; }
110    .docs-command-card {
111      display: block; padding: 1.25rem; border-radius: 8px;
112      border: 1px solid var(--color-mist); text-decoration: none; color: inherit;
113      transition: border-color 0.15s ease, box-shadow 0.15s ease;
114    }
115    .docs-command-card:hover { border-color: var(--color-accent); box-shadow: 0 2px 8px rgba(0,0,0,0.04); }
116    .docs-command-name { font-family: var(--font-mono); font-size: 0.9375rem; font-weight: 600; margin: 0 0 0.375rem; }
117    .docs-command-tagline { font-size: 0.8125rem; color: var(--color-ash); margin: 0; line-height: 1.5; }
118  </style>
119</Base>