diff --git a/docs/guides/docusaurus-site-guide.md b/docs/guides/docusaurus-site-guide.md index ae404f4d..3dea82c3 100644 --- a/docs/guides/docusaurus-site-guide.md +++ b/docs/guides/docusaurus-site-guide.md @@ -243,6 +243,17 @@ The site deploys automatically via GitHub Actions when changes to `website/` are **First-time setup**: Enable GitHub Pages in repo Settings → Pages → Source: GitHub Actions +## Style Guidelines + +**No emoji**: Do not use emoji in the site content, components, or documentation. Use icon fonts (Lucide) for visual indicators instead. + +**Icons**: The site uses [Lucide](https://lucide.dev) icon font. Use CSS classes like `icon-copy`, `icon-check`, `icon-arrow-right`. Example: +```jsx + +``` + +**Terminal aesthetic**: Maintain the TUI/terminal visual style. Use monospace fonts, muted colors with bright accents, and clean 1px borders. + ## Common Tasks ### Add a new docs section diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 11b429c0..b5985405 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -30,6 +30,10 @@ const config = { projectName: 'sidecar', trailingSlash: false, + customFields: { + githubUrl: 'https://github.com/marcus/sidecar', + }, + onBrokenLinks: 'throw', // Even if you don't use internationalization, you can use this field to set @@ -40,6 +44,35 @@ const config = { locales: ['en'], }, + headTags: [ + { + tagName: 'link', + attributes: { + rel: 'preconnect', + href: 'https://fonts.googleapis.com', + }, + }, + { + tagName: 'link', + attributes: { + rel: 'preconnect', + href: 'https://fonts.gstatic.com', + crossorigin: 'anonymous', + }, + }, + ], + + stylesheets: [ + { + href: 'https://fonts.googleapis.com/css2?family=Google+Sans+Code:ital,wght@0,300..800;1,300..800&family=JetBrains+Mono:wght@400;500;600;700&display=swap', + type: 'text/css', + }, + { + href: 'https://cdn.jsdelivr.net/npm/lucide-static@latest/font/lucide.css', + type: 'text/css', + }, + ], + presets: [ [ 'classic', @@ -73,7 +106,9 @@ const config = { // Replace with your project's social card image: 'img/docusaurus-social-card.jpg', colorMode: { - respectPrefersColorScheme: true, + defaultMode: 'dark', + disableSwitch: true, + respectPrefersColorScheme: false, }, navbar: { title: 'Sidecar', diff --git a/website/src/css/custom.css b/website/src/css/custom.css index 2bc6a4cf..d350db7a 100644 --- a/website/src/css/custom.css +++ b/website/src/css/custom.css @@ -1,30 +1,986 @@ +/* External fonts - @import must be at top */ +@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap'); +@import url('https://cdn.jsdelivr.net/npm/lucide-static@latest/font/lucide.css'); + /** - * Any CSS included here will be global. The classic template - * bundles Infima by default. Infima is a CSS framework designed to - * work well for content-centric websites. + * Sidecar TUI-themed Docusaurus styles + * Monokai-ish dark base with bright terminal accents */ -/* You can override the default Infima variables here. */ :root { - --ifm-color-primary: #2e8555; - --ifm-color-primary-dark: #29784c; - --ifm-color-primary-darker: #277148; - --ifm-color-primary-darkest: #205d3b; - --ifm-color-primary-light: #33925d; - --ifm-color-primary-lighter: #359962; - --ifm-color-primary-lightest: #3cad6e; - --ifm-code-font-size: 95%; - --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); -} - -/* For readability concerns, you should choose a lighter palette in dark mode. */ + /* Docusaurus base - monokai green */ + --ifm-color-primary: #a6e22e; + --ifm-color-primary-dark: #92d521; + --ifm-color-primary-darker: #86c81e; + --ifm-color-primary-darkest: #6aa314; + --ifm-color-primary-light: #b4f042; + --ifm-color-primary-lighter: #baf24d; + --ifm-color-primary-lightest: #c8f66a; + + --ifm-background-color: #121417; + --ifm-background-surface-color: #171a1f; + --ifm-font-color-base: #e8e8e3; + --ifm-font-color-secondary: rgba(232, 232, 227, 0.78); + + --ifm-code-font-size: 92%; + /* Primary: Google Sans Code (self-host if needed), Secondary: JetBrains Mono */ + --ifm-font-family-base: "Google Sans Code", "JetBrains Mono", ui-monospace, + SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; + --ifm-heading-font-family: var(--ifm-font-family-base); + + /* Sidecar-ish accents */ + --sc-pink: #f92672; + --sc-blue: #66d9ef; + --sc-purple: #ae81ff; + --sc-yellow: #e6db74; + --sc-orange: #fd971f; + + /* TUI surfaces */ + --sc-panel: #171a1f; + --sc-panel-2: #1b1f26; + --sc-border: rgba(255, 255, 255, 0.08); + --sc-border-2: rgba(255, 255, 255, 0.12); + --sc-glow: rgba(102, 217, 239, 0.08); + + --sc-radius: 14px; + --sc-shadow: 0 18px 60px rgba(0, 0, 0, 0.45); + + --docusaurus-highlighted-code-line-bg: rgba(166, 226, 46, 0.15); +} + +/* Dark theme overrides */ [data-theme='dark'] { - --ifm-color-primary: #25c2a0; - --ifm-color-primary-dark: #21af90; - --ifm-color-primary-darker: #1fa588; - --ifm-color-primary-darkest: #1a8870; - --ifm-color-primary-light: #29d5b0; - --ifm-color-primary-lighter: #32d8b4; - --ifm-color-primary-lightest: #4fddbf; - --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); + --ifm-color-primary: #a6e22e; + --ifm-color-primary-dark: #92d521; + --ifm-color-primary-darker: #86c81e; + --ifm-color-primary-darkest: #6aa314; + --ifm-color-primary-light: #b4f042; + --ifm-color-primary-lighter: #baf24d; + --ifm-color-primary-lightest: #c8f66a; + --ifm-background-color: #121417; + --ifm-background-surface-color: #171a1f; + --docusaurus-highlighted-code-line-bg: rgba(166, 226, 46, 0.15); +} + +/* Navbar styling */ +html[data-theme="dark"] .navbar { + background: rgba(18, 20, 23, 0.7); + backdrop-filter: blur(10px); + border-bottom: 1px solid var(--sc-border); +} + +html[data-theme="dark"] .navbar__brand { + font-weight: 700; + letter-spacing: 0.2px; +} + +html[data-theme="dark"] .footer { + border-top: 1px solid var(--sc-border); + background: #0f1114; +} + +/* Full-page gradient background */ +html[data-theme="dark"]::before { + content: ""; + position: fixed; + inset: 0; + z-index: -1; + background: + radial-gradient(ellipse 1200px 600px at 15% 5%, rgba(249, 38, 114, 0.12), transparent 50%), + radial-gradient(ellipse 1200px 600px at 85% 8%, rgba(102, 217, 239, 0.10), transparent 50%), + radial-gradient(ellipse 1400px 800px at 50% 40%, rgba(166, 226, 46, 0.06), transparent 50%), + radial-gradient(ellipse 1200px 600px at 20% 70%, rgba(174, 129, 255, 0.08), transparent 50%), + radial-gradient(ellipse 1200px 600px at 80% 90%, rgba(230, 219, 116, 0.06), transparent 50%); + pointer-events: none; +} + +/* Terminal-bright links */ +a { + text-decoration-thickness: 1px; + text-underline-offset: 3px; +} + +a:hover { + text-decoration-thickness: 2px; +} + +/* ---------- Homepage layout ---------- */ + +.sc-hero { + position: relative; + padding: 56px 0 22px; + overflow: hidden; +} + +.sc-hero::before { + content: ""; + position: absolute; + inset: -60px; + background: + radial-gradient(900px 420px at 20% 10%, rgba(249, 38, 114, 0.14), transparent 60%), + radial-gradient(900px 420px at 80% 5%, rgba(102, 217, 239, 0.12), transparent 60%), + radial-gradient(900px 520px at 55% 85%, rgba(166, 226, 46, 0.10), transparent 60%); + pointer-events: none; +} + +.sc-hero::after { + /* subtle scanlines */ + content: ""; + position: absolute; + inset: 0; + background: linear-gradient( + to bottom, + rgba(255, 255, 255, 0.03), + rgba(255, 255, 255, 0.0) 2px + ); + background-size: 100% 10px; + opacity: 0.07; + mix-blend-mode: overlay; + pointer-events: none; +} + +.sc-heroInner { + position: relative; + display: grid; + grid-template-columns: 1.05fr 1fr; + gap: 28px; + align-items: start; +} + +@media (max-width: 996px) { + .sc-heroInner { + grid-template-columns: 1fr; + } +} + +.sc-title { + font-size: clamp(34px, 4.2vw, 52px); + line-height: 1.03; + letter-spacing: -0.7px; + margin: 0 0 12px; +} + +.sc-subtitle { + margin: 0 0 18px; + font-size: 15px; + line-height: 1.55; + color: var(--ifm-font-color-secondary); + max-width: 58ch; +} + +.sc-badges { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin: 0 0 18px; +} + +.sc-badge { + border: 1px solid var(--sc-border); + background: rgba(23, 26, 31, 0.6); + border-radius: 999px; + padding: 6px 10px; + font-size: 12px; + color: rgba(232, 232, 227, 0.86); +} + +.sc-actions { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-top: 6px; +} + +.sc-btn { + display: inline-flex; + align-items: center; + gap: 10px; + border-radius: 12px; + padding: 10px 12px; + border: 1px solid var(--sc-border-2); + background: rgba(23, 26, 31, 0.8); + box-shadow: 0 10px 30px rgba(0,0,0,0.35); + font-weight: 650; + letter-spacing: 0.2px; + color: var(--ifm-font-color-base); +} + +.sc-btnPrimary { + border-color: rgba(166, 226, 46, 0.35); + background: + linear-gradient(180deg, rgba(166, 226, 46, 0.16), rgba(23, 26, 31, 0.86)); +} + +.sc-btn:hover { + transform: translateY(-1px); + transition: transform 160ms ease, border-color 160ms ease; + border-color: rgba(255,255,255,0.18); + text-decoration: none; + color: var(--ifm-font-color-base); +} + +.sc-codeInline { + font-size: 12px; + padding: 3px 8px; + border-radius: 999px; + border: 1px solid var(--sc-border); + background: rgba(0,0,0,0.35); + color: var(--sc-yellow); +} + +/* ---------- TUI frame ---------- */ + +.sc-frame { + border-radius: var(--sc-radius); + background: linear-gradient(180deg, rgba(27, 31, 38, 0.92), rgba(23, 26, 31, 0.92)); + border: 1px solid var(--sc-border); + box-shadow: var(--sc-shadow); + overflow: hidden; +} + +.sc-frameTop { + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px 12px; + border-bottom: 1px solid var(--sc-border); + background: rgba(18, 20, 23, 0.55); +} + +.sc-dots { + display: inline-flex; + gap: 6px; + align-items: center; +} + +.sc-dot { + width: 10px; + height: 10px; + border-radius: 999px; + border: 1px solid var(--sc-border); + background: rgba(255,255,255,0.06); +} + +.sc-topRight { + display: inline-flex; + gap: 8px; + align-items: center; + color: rgba(232,232,227,0.6); + font-size: 12px; +} + +.sc-tabs { + display: flex; + gap: 8px; + padding: 10px 12px; + border-bottom: 1px solid var(--sc-border); + background: rgba(23, 26, 31, 0.55); +} + +.sc-tab { + font-size: 12px; + padding: 6px 10px; + border-radius: 999px; + border: 1px solid var(--sc-border); + color: rgba(232,232,227,0.78); + background: rgba(0,0,0,0.15); + cursor: pointer; + font-family: var(--ifm-font-family-base); + transition: border-color 120ms ease, background 120ms ease; +} + +.sc-tab:hover { + border-color: rgba(255,255,255,0.15); + background: rgba(255,255,255,0.04); +} + +.sc-tabActive { + color: rgba(232,232,227,0.92); + border-color: rgba(102, 217, 239, 0.35); + background: rgba(102, 217, 239, 0.08); + box-shadow: 0 0 0 3px rgba(102, 217, 239, 0.06); +} + +.sc-tabActive:hover { + border-color: rgba(102, 217, 239, 0.5); + background: rgba(102, 217, 239, 0.12); +} + +.sc-frameBody { + display: grid; + grid-template-columns: 220px 1fr; + min-height: 360px; +} + +@media (max-width: 996px) { + .sc-frameBody { + grid-template-columns: 1fr; + } +} + +.sc-frameBodySingle { + height: 380px; + overflow: hidden; +} + +.sc-frameBodySingle .sc-pane { + height: 100%; + overflow-y: auto; + animation: fadeIn 150ms ease; +} + +@keyframes fadeIn { + from { opacity: 0; transform: translateY(4px); } + to { opacity: 1; transform: translateY(0); } +} + +.sc-frameFooter { + padding: 8px 12px; + border-top: 1px solid var(--sc-border); + background: rgba(18, 20, 23, 0.55); + font-size: 12px; +} + +.sc-sidebar { + border-right: 1px solid var(--sc-border); + background: rgba(18, 20, 23, 0.30); + padding: 12px; +} + +.sc-pane { + padding: 12px; +} + +.sc-sectionTitle { + font-size: 12px; + color: rgba(232,232,227,0.68); + margin: 0 0 8px; + letter-spacing: 0.35px; +} + +.sc-list { + display: grid; + gap: 6px; +} + +.sc-item { + display: flex; + align-items: center; + gap: 8px; + border: 1px solid transparent; + border-radius: 10px; + padding: 8px 8px; + color: rgba(232,232,227,0.78); + background: rgba(0,0,0,0.12); + font-size: 13px; +} + +.sc-itemActive { + border-color: rgba(174, 129, 255, 0.35); + background: rgba(174, 129, 255, 0.08); +} + +.sc-bullet { + width: 8px; + height: 8px; + border-radius: 999px; + background: rgba(255,255,255,0.18); + border: 1px solid var(--sc-border); + flex-shrink: 0; +} + +.sc-bulletGreen { background: rgba(166, 226, 46, 0.45); } +.sc-bulletPink { background: rgba(249, 38, 114, 0.45); } +.sc-bulletBlue { background: rgba(102, 217, 239, 0.45); } + +.sc-codeBlock { + border-radius: 12px; + border: 1px solid var(--sc-border); + background: rgba(0,0,0,0.28); + padding: 10px 12px; + overflow: auto; + font-size: 12px; + line-height: 1.45; + color: rgba(232,232,227,0.88); + box-shadow: 0 0 0 1px rgba(255,255,255,0.02) inset; +} + +.sc-lineDim { color: rgba(232,232,227,0.55); } +.sc-lineGreen { color: var(--ifm-color-primary); } +.sc-linePink { color: var(--sc-pink); } +.sc-lineBlue { color: var(--sc-blue); } +.sc-lineYellow { color: var(--sc-yellow); } + +/* ---------- Feature grid ---------- */ + +.sc-grid { + padding: 26px 0 46px; +} + +.sc-gridInner { + display: grid; + grid-template-columns: repeat(12, 1fr); + gap: 16px; +} + +.sc-card { + grid-column: span 6; + border-radius: var(--sc-radius); + border: 1px solid var(--sc-border); + background: linear-gradient(180deg, rgba(23, 26, 31, 0.88), rgba(15, 17, 20, 0.88)); + box-shadow: 0 12px 40px rgba(0,0,0,0.35); + padding: 18px 18px 16px; +} + +@media (max-width: 996px) { + .sc-card { grid-column: span 12; } +} + +.sc-cardHeader { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + margin-bottom: 8px; +} + +.sc-cardTitle { + font-size: 13px; + margin: 0; + letter-spacing: 0.2px; +} + +.sc-chip { + font-size: 11px; + border-radius: 999px; + padding: 3px 8px; + border: 1px solid var(--sc-border); + color: rgba(232,232,227,0.7); + background: rgba(0,0,0,0.22); +} + +.sc-cardBody { + margin: 0; + color: rgba(232,232,227,0.72); + font-size: 13px; + line-height: 1.65; +} + +/* ---------- Copy button ---------- */ + +.sc-copyBtn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + border-radius: 6px; + border: 1px solid var(--sc-border); + background: rgba(0,0,0,0.25); + color: rgba(232,232,227,0.6); + cursor: pointer; + font-family: 'lucide'; + font-size: 14px; + transition: all 120ms ease; +} + +.sc-copyBtn:hover { + border-color: rgba(255,255,255,0.2); + color: rgba(232,232,227,0.9); + background: rgba(255,255,255,0.05); +} + +.sc-copyBtn .icon-check { + color: var(--ifm-color-primary); +} + +/* ---------- Install block ---------- */ + +.sc-installBlock { + position: relative; +} + +.sc-installHeader { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 6px; +} + +.sc-installCommand { + word-break: break-all; +} + +/* ---------- Feature cards enhanced ---------- */ + +.sc-gridFeatures { + grid-template-columns: repeat(12, 1fr); +} + +.sc-card { + grid-column: span 6; + cursor: pointer; + transition: all 200ms ease; +} + +.sc-card:hover { + border-color: rgba(255,255,255,0.15); + transform: translateY(-2px); +} + +/* Hero card - double wide, accent colors */ +.sc-cardHero { + grid-column: span 12; + background: linear-gradient(135deg, + rgba(166, 226, 46, 0.08) 0%, + rgba(23, 26, 31, 0.92) 50%, + rgba(102, 217, 239, 0.06) 100%); + border-color: rgba(166, 226, 46, 0.2); + padding: 22px 22px 20px; +} + +.sc-cardHero .sc-cardTitle { + font-size: 15px; +} + +.sc-cardHero .sc-cardBody { + font-size: 14px; + max-width: 80ch; +} + +.sc-cardHero .sc-chip { + background: rgba(166, 226, 46, 0.12); + border-color: rgba(166, 226, 46, 0.25); + color: var(--ifm-color-primary); +} + +/* Highlighted card animation */ +.sc-cardHighlighted { + border-color: rgba(102, 217, 239, 0.4); + box-shadow: + 0 12px 40px rgba(0,0,0,0.35), + 0 0 0 1px rgba(102, 217, 239, 0.15), + 0 0 20px rgba(102, 217, 239, 0.1); + animation: cardPulse 600ms ease; +} + +.sc-cardHero.sc-cardHighlighted { + border-color: rgba(166, 226, 46, 0.5); + box-shadow: + 0 12px 40px rgba(0,0,0,0.35), + 0 0 0 1px rgba(166, 226, 46, 0.2), + 0 0 20px rgba(166, 226, 46, 0.12); +} + +@keyframes cardPulse { + 0% { transform: scale(1); } + 50% { transform: scale(1.01); } + 100% { transform: scale(1); } +} + +@media (max-width: 996px) { + .sc-card, + .sc-cardHero { + grid-column: span 12; + } +} + +/* ---------- Main sections ---------- */ + +.sc-main { + position: relative; +} + +/* ---------- Component showcase section ---------- */ + +.sc-showcase { + padding: 48px 0; + background: linear-gradient(180deg, rgba(15, 17, 20, 0.5), transparent); +} + +.sc-showcaseTitle { + font-size: 24px; + margin: 0 0 8px; + letter-spacing: -0.3px; +} + +.sc-showcaseSubtitle { + font-size: 14px; + color: var(--ifm-font-color-secondary); + margin: 0 0 32px; +} + +.sc-showcaseFullWidth { + display: flex; + flex-direction: column; + gap: 24px; +} + +.sc-componentSection { + border-radius: var(--sc-radius); + border: 1px solid var(--sc-border); + padding: 24px; + margin: 0 auto; + width: 100%; + max-width: 1400px; +} + +/* Gradient variants */ +.sc-gradientGreen { + background: linear-gradient(30deg, + rgba(166, 226, 46, 0.12) 0%, + rgba(23, 26, 31, 0.95) 40%, + rgba(23, 26, 31, 0.95) 100%); + border-color: rgba(166, 226, 46, 0.2); +} + +.sc-gradientBlue { + background: linear-gradient(30deg, + rgba(102, 217, 239, 0.12) 0%, + rgba(23, 26, 31, 0.95) 40%, + rgba(23, 26, 31, 0.95) 100%); + border-color: rgba(102, 217, 239, 0.2); +} + +.sc-gradientPurple { + background: linear-gradient(30deg, + rgba(174, 129, 255, 0.12) 0%, + rgba(23, 26, 31, 0.95) 40%, + rgba(23, 26, 31, 0.95) 100%); + border-color: rgba(174, 129, 255, 0.2); +} + +.sc-gradientPink { + background: linear-gradient(30deg, + rgba(249, 38, 114, 0.12) 0%, + rgba(23, 26, 31, 0.95) 40%, + rgba(23, 26, 31, 0.95) 100%); + border-color: rgba(249, 38, 114, 0.2); +} + +.sc-gradientYellow { + background: linear-gradient(30deg, + rgba(230, 219, 116, 0.12) 0%, + rgba(23, 26, 31, 0.95) 40%, + rgba(23, 26, 31, 0.95) 100%); + border-color: rgba(230, 219, 116, 0.2); +} + +.sc-componentContent { + display: grid; + grid-template-columns: 1fr 1.5fr; + gap: 32px; + align-items: start; +} + +@media (max-width: 996px) { + .sc-componentContent { + grid-template-columns: 1fr; + } +} + +.sc-componentInfo { + position: sticky; + top: 80px; +} + +.sc-componentTitle { + font-size: 18px; + margin: 0 0 16px; + color: var(--ifm-font-color-base); + letter-spacing: 0.2px; +} + +.sc-componentFeatures { + display: grid; + gap: 10px; +} + +.sc-componentFeature { + display: flex; + align-items: flex-start; + gap: 10px; + font-size: 13px; + color: rgba(232,232,227,0.72); + line-height: 1.5; +} + +.sc-featureIcon { + color: var(--ifm-color-primary); + font-size: 12px; + margin-top: 3px; + flex-shrink: 0; +} + +.sc-componentMockup { + flex: 1; +} + +/* ---------- Mockup styles ---------- */ + +.sc-mockup { + border-radius: 12px; + border: 1px solid var(--sc-border); + background: rgba(0, 0, 0, 0.4); + overflow: hidden; + font-size: 13px; +} + +.sc-mockupHeader { + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px 14px; + border-bottom: 1px solid var(--sc-border); + background: rgba(18, 20, 23, 0.6); +} + +.sc-mockupTitle { + font-weight: 600; + color: rgba(232,232,227,0.9); +} + +.sc-mockupBody { + display: grid; + grid-template-columns: 180px 1fr; + min-height: 280px; +} + +@media (max-width: 768px) { + .sc-mockupBody { + grid-template-columns: 1fr; + } +} + +.sc-mockupSidebar { + padding: 12px; + border-right: 1px solid var(--sc-border); + background: rgba(18, 20, 23, 0.3); + display: flex; + flex-direction: column; + gap: 6px; +} + +.sc-mockupMain { + padding: 12px; +} + +.sc-mockupItem { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 10px; + border-radius: 8px; + background: rgba(0,0,0,0.2); + border: 1px solid transparent; + font-size: 12px; + color: rgba(232,232,227,0.78); +} + +.sc-mockupItemActive { + border-color: rgba(174, 129, 255, 0.35); + background: rgba(174, 129, 255, 0.1); +} + +.sc-mockupFooter { + padding: 8px 14px; + border-top: 1px solid var(--sc-border); + background: rgba(18, 20, 23, 0.6); + font-size: 11px; +} + +.sc-mockupDetail, +.sc-mockupDiff, +.sc-mockupPreview, +.sc-mockupConvo, +.sc-mockupWorktree { + background: rgba(0, 0, 0, 0.25); + border-radius: 8px; + border: 1px solid var(--sc-border); + padding: 12px; +} + +.sc-bulletYellow { background: rgba(230, 219, 116, 0.45); } + +/* ---------- Features section ---------- */ + +.sc-features { + padding: 48px 0; +} + +.sc-featuresTitle { + font-size: 24px; + margin: 0 0 24px; + letter-spacing: -0.3px; +} + +.sc-featuresGrid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 16px; +} + +.sc-featureListItem { + display: flex; + flex-direction: column; + gap: 10px; + padding: 16px; + border-radius: 12px; + border: 1px solid var(--sc-border); + background: rgba(23, 26, 31, 0.4); + transition: border-color 150ms ease; +} + +.sc-featureListItem:hover { + border-color: rgba(255,255,255,0.12); +} + +.sc-featureListHeader { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 12px; +} + +.sc-featureListIcon { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + border-radius: 8px; + background: rgba(255, 255, 255, 0.04); + border: 1px solid var(--sc-border); + color: rgba(232, 232, 227, 0.5); + font-size: 14px; + flex-shrink: 0; +} + +.sc-featureListTitle { + font-size: 15px; + font-weight: 600; + margin: 0; + line-height: 1.3; +} + +/* Feature title color variants */ +.sc-featureColor-green { color: var(--ifm-color-primary); } +.sc-featureColor-blue { color: var(--sc-blue); } +.sc-featureColor-pink { color: var(--sc-pink); } +.sc-featureColor-purple { color: var(--sc-purple); } +.sc-featureColor-yellow { color: var(--sc-yellow); } +.sc-featureColor-orange { color: var(--sc-orange); } + +.sc-featureListDesc { + font-size: 13px; + margin: 0; + color: rgba(232,232,227,0.65); + line-height: 1.5; +} + +/* ---------- Agents section ---------- */ + +.sc-agents { + padding: 48px 0 64px; + background: linear-gradient(180deg, transparent, rgba(15, 17, 20, 0.4)); +} + +.sc-agentsTitle { + font-size: 24px; + margin: 0 0 8px; + letter-spacing: -0.3px; + text-align: center; +} + +.sc-agentsSubtitle { + font-size: 14px; + color: var(--ifm-font-color-secondary); + margin: 0 0 32px; + text-align: center; + max-width: 60ch; + margin-left: auto; + margin-right: auto; +} + +.sc-agentsGrid { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 16px; + max-width: 1200px; + margin: 0 auto; +} + +@media (max-width: 1100px) { + .sc-agentsGrid { + grid-template-columns: repeat(3, 1fr); + } +} + +@media (max-width: 768px) { + .sc-agentsGrid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 500px) { + .sc-agentsGrid { + grid-template-columns: 1fr; + } +} + +.sc-agentCard { + display: flex; + flex-direction: column; + align-items: center; + gap: 12px; + padding: 20px 16px; + border-radius: var(--sc-radius); + border: 1px solid var(--sc-border); + background: rgba(23, 26, 31, 0.5); + transition: all 200ms ease; + text-align: center; +} + +.sc-agentCard:hover { + border-color: rgba(255,255,255,0.15); + transform: translateY(-2px); + box-shadow: 0 8px 24px rgba(0,0,0,0.25); +} + +.sc-agentLogo { + width: 48px; + height: 48px; + flex-shrink: 0; +} + +.sc-agentLogo svg { + width: 100%; + height: 100%; +} + +.sc-agentInfo { + flex: 1; + min-width: 0; +} + +.sc-agentName { + font-size: 14px; + margin: 0 0 4px; + color: var(--ifm-font-color-base); + font-weight: 600; +} + +.sc-agentDesc { + font-size: 12px; + margin: 0; + color: rgba(232,232,227,0.6); + line-height: 1.4; +} + +.sc-agentsNote { + font-size: 13px; + color: var(--ifm-font-color-secondary); + text-align: center; + margin: 24px auto 0; + max-width: 60ch; } diff --git a/website/src/pages/index.js b/website/src/pages/index.js index 971662be..b21b2fc1 100644 --- a/website/src/pages/index.js +++ b/website/src/pages/index.js @@ -1,48 +1,1041 @@ +import { useState, useCallback, useEffect } from 'react'; import Link from '@docusaurus/Link'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import Layout from '@theme/Layout'; -import Heading from '@theme/Heading'; -import styles from './index.module.css'; +const TABS = ['td', 'git', 'files', 'conversations', 'worktrees']; -function HomepageHeader() { - const {siteConfig} = useDocusaurusContext(); +const INSTALL_COMMAND = 'curl -fsSL https://raw.githubusercontent.com/marcus/sidecar/main/scripts/setup.sh | bash'; + +function CopyButton({ text }) { + const [copied, setCopied] = useState(false); + + const handleCopy = useCallback(async () => { + try { + await navigator.clipboard.writeText(text); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } catch (err) { + console.error('Failed to copy:', err); + } + }, [text]); + + return ( + + ); +} + +function TdPane() { + return ( + <> +

Tasks

+
+
+ + td-a1b2c3 Implement auth flow +
+
+ + td-d4e5f6 Add rate limiting +
+
+ + td-g7h8i9 Fix memory leak +
+
+
+
+
td-a1b2c3 | in_progress
+
+
Title: Implement auth flow
+
Status: in_progress
+
Created: 2h ago
+
+
Subtasks:
+
[x] Create auth middleware
+
[x] Add JWT validation
+
[ ] Write integration tests
+
+ + ); +} + +function GitPane() { + return ( + <> +

Changes

+
+
+ + M internal/auth/middleware.go +
+
+ + A internal/auth/jwt.go +
+
+ + D internal/auth/old_auth.go +
+
+
+
+
internal/auth/middleware.go
+
+
@@ -42,6 +42,18 @@
+
+ func AuthMiddleware(next http.Handler) http.Handler {'{'}
+
+ return http.HandlerFunc(func(w, r) {'{'}
+
+ token := r.Header.Get("Authorization")
+
+ if !ValidateJWT(token) {'{'}
+
+ http.Error(w, "Unauthorized", 401)
+
+ return
+
+ {'}'}
+
+ next.ServeHTTP(w, r)
+
+ {'}'})
+
+ {'}'}
+
+ + ); +} + +function FilesPane() { + return ( + <> +

Project Files

+
+
+ [v] + internal/ +
+
+ [v] + auth/ +
+
+ + middleware.go +
+
+ + jwt.go +
+
+ [>] + plugins/ +
+
+
+
+
middleware.go | 156 lines
+
+
package auth
+
+
import (
+
"net/http"
+
"strings"
+
)
+
+
// AuthMiddleware validates JWT tokens
+
func AuthMiddleware(next http.Handler)...
+
+ + ); +} + +function ConversationsPane() { return ( -
-
- - Welcome to {siteConfig.title} - -

{siteConfig.tagline}

-
- - Get Started - + <> +

All Sessions chronological

+
+
+ + auth-flow | Claude | 24m
+
+ + rate-limit | Cursor | 2h +
+
+ + refactor | Gemini | 1d +
+
+
+
+
auth-flow | Claude Code
+
+
User: Add JWT auth to the API
+
+
Claude: I'll implement JWT authentication.
+
First, let me check the existing auth...
+
+
-> Read internal/auth/middleware.go
+
-> Edit internal/auth/jwt.go
+
+
12.4k tokens | 24 minutes
+
+ + ); +} + +function WorktreesPane() { + return ( + <> +

Worktrees zero commands

+
+
+ + main +
+
+ + feature/auth PR #47 +
+
+ + fix/memory PR #52 +
+
+
+
+
feature/auth | Ready to merge
+
+
Task: td-a1b2c3 from td
+
Prompts: 3 configured
+
+
Actions:
+
[n] New worktree + agent
+
[s] Send task from td
+
[p] Run prompt sequence
+
+
* 3 commits ahead | checks passing
-
+ + ); +} + +function Frame({ activeTab, onTabChange }) { + const [time, setTime] = useState(() => { + const now = new Date(); + return now.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: false }); + }); + + useEffect(() => { + const updateTime = () => { + const now = new Date(); + setTime(now.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: false })); + }; + const interval = setInterval(updateTime, 1000); + return () => clearInterval(interval); + }, []); + + const renderPane = () => { + switch (activeTab) { + case 'td': return ; + case 'git': return ; + case 'files': return ; + case 'conversations': return ; + case 'worktrees': return ; + default: return ; + } + }; + + return ( +
+
+ +
+ sidecar + {time} +
+
+ +
+ {TABS.map((tab) => ( + + ))} +
+ +
+
+ {renderPane()} +
+
+ +
+ tab + switch | + enter + select | + ? + help | + q + quit +
+
+ ); +} + +function FeatureCard({ id, title, chip, children, isHighlighted, isHero, onClick }) { + return ( +
e.key === 'Enter' && onClick?.()} + > +
+

{title}

+ {chip} +
+

{children}

+
+ ); +} + +// Mockup screens for component deep dive +function TdMockup() { + return ( +
+
+ Task Management + 3 tasks | 1 in progress +
+
+
+
+ +
+
td-a1b2c3
+
Implement auth
+
+
+
+ +
+
td-d4e5f6
+
Rate limiting
+
+
+
+ +
+
td-g7h8i9
+
Memory leak
+
+
+
+
+
+
Implement auth flow
+
+
Status: in_progress
+
Created: 2h ago
+
Epic: td-epic-auth
+
+
+
Subtasks
+
+
[x] Create auth middleware
+
[x] Add JWT validation
+
[ ] Write integration tests
+
[ ] Update API docs
+
+
+
+
+
+
+ n new | + e edit | + s status | + / search +
+
+ ); +} + +function GitMockup() { + return ( +
+
+ Git Status + feature/auth-flow | 3 changed +
+
+
+
Staged
+
+ M + middleware.go +
+
+ A + jwt.go +
+
Unstaged
+
+ D + old_auth.go +
+
+
+
+
internal/auth/middleware.go
+
+
@@ -42,6 +42,14 @@
+
+func AuthMiddleware(next http.Handler) {'{'}
+
+ return http.HandlerFunc(func(w, r) {'{'}
+
+ token := r.Header.Get("Auth")
+
+ if !ValidateJWT(token) {'{'}
+
+ http.Error(w, "Unauth", 401)
+
+ {'}'}
+
+ {'}'})
+
+{'}'}
+
+
+
+
+
+ a stage | + u unstage | + c commit | + d diff +
+
+ ); +} + +function FilesMockup() { + return ( +
+
+ File Browser + sidecar/internal +
+
+
+
+ [v] + internal/ +
+
+ [v] + auth/ +
+
+ + middleware.go +
+
+ + jwt.go +
+
+ [>] + plugins/ +
+
+ [>] + app/ +
+
+
+
+
middleware.go | 156 lines | Go
+
+
package auth
+
+
import (
+
"net/http"
+
"strings"
+
)
+
+
// AuthMiddleware validates requests
+
func AuthMiddleware(next)...
+
+
+
+
+
+ enter open | + / search | + e editor | + g goto +
+
+ ); +} + +function ConversationsMockup() { + return ( +
+
+ Conversations + 18 sessions | all agents +
+
+
+
+ +
+
auth-flow Claude
+
24m ago | 12.4k
+
+
+
+ +
+
rate-limit Cursor
+
2h ago | 8.2k
+
+
+
+ +
+
refactor Gemini
+
1d ago | 24.1k
+
+
+
+
+
+
+
User
+
Add JWT authentication to the API endpoints
+
+
+
Claude
+
I'll implement JWT authentication for your API.
+
Let me check the existing auth setup...
+
+
+
-> Read middleware.go
+
-> Edit jwt.go
+
-> Write tests/auth_test.go
+
+
+
+
+
+ enter expand | + / search | + y copy | + j/k nav +
+
+ ); +} + +function WorktreesMockup() { + return ( +
+
+ Worktrees + zero commands | auto everything +
+
+
+
+ +
+
main
+
default
+
+
+
+ +
+
feature/auth
+
PR #47 | ready
+
+
+
+ +
+
fix/memory
+
td-g7h8i9
+
+
+
+
+
+
feature/auth
+
+
PR: #47 Add JWT auth
+
Task: td-a1b2c3 from td
+
Status: Ready to merge
+
+
+
Quick actions
+
[n] New worktree + start agent
+
[s] Send task from td
+
[p] Run prompt sequence
+
[m] Merge & cleanup
+
+
+
+
+
+ n new | + s send task | + p prompts | + m merge +
+
+ ); +} + +function ComponentSection({ id, title, features, gradient, MockupComponent }) { + return ( +
+
+
+

{title}

+
+ {features.map((feature, idx) => ( +
+ + {feature} +
+ ))} +
+
+
+ +
+
+
+ ); +} + +function FeatureListItem({ icon, title, description, color }) { + return ( +
+
+

{title}

+
+ +
+
+

{description}

+
); } export default function Home() { - const {siteConfig} = useDocusaurusContext(); + const { siteConfig } = useDocusaurusContext(); + const [activeTab, setActiveTab] = useState('td'); + + const handleTabChange = (tab) => { + setActiveTab(tab); + }; + + const handleCardClick = (tab) => { + setActiveTab(tab); + }; + return ( - -
-
-
-

- Sidecar provides a unified terminal interface for viewing Claude Code - conversations, git status, and task progress. Built for developers who - want visibility into their AI coding sessions without leaving the terminal. -

+ title="Terminal UI for AI coding sessions" + description="Sidecar is a unified terminal interface for monitoring AI coding agent sessions: tasks, git status, files, conversations." + > +
+
+
+
+

+ Sidecar + | + a terminal cockpit for AI coding +

+ +

+ Monitor agent sessions without leaving the terminal: task flow, git diffs, file browsing, + and conversation history--designed for the "split the terminal and ship" workflow. +

+ +
+ +
+ + Get started curl | bash + + + Read docs ? + + + GitHub + +
+ +
+ +
+
+ Quick install + +
+
+ $ + {INSTALL_COMMAND} +
+
+ $ + sidecar +
+
+
+ +
+ +
+
+ +
+ {/* Feature Cards */} +
+
+
+ {/* TD Hero Card - double wide */} + handleCardClick('td')} + > + Give agents structured work so they can operate autonomously for longer. Tasks persist across + context windows, keeping agents on track with clear objectives. Built-in review workflow + lets you verify work before moving to the next task. + + + {/* Regular feature cards */} + handleCardClick('git')} + > + Split-pane diffs, commit context, and a fast loop for staging/review--without bouncing to an IDE. + + + handleCardClick('files')} + > + Navigate your codebase with a tree view, preview file contents, and jump to any file instantly. + + + handleCardClick('conversations')} + > + Chronological view across Claude, Cursor, Gemini, and all adapters. See every session in one place, + search across agents, and pick up exactly where any agent left off. + + + handleCardClick('worktrees')} + > + Create worktrees, pass tasks from td, or kick off with configured prompts--all without typing git commands. + Everything is automatic: create, switch, merge, delete. + +
+
+
+ + {/* Component Showcase Sections */} +
+
+

Component Deep Dive

+

Each plugin is designed for the AI-assisted development workflow

+
+ +
+ + + + + + + + + +
+
+ + {/* Comprehensive Features Section */} +
+
+

Features

+ +
+ + + + + + + + + + + + +
+
+
+ + {/* Supported Agents */} +
+
+

Works with your favorite coding agents

+

+ Sidecar reads session data from multiple AI coding tools, giving you a unified view of agent activity +

+ +
+
+
+ + + + +
+
+

Claude Code

+

Anthropic's official CLI for Claude

+
+
+ +
+
+ + + + + +
+
+

Codex

+

OpenAI's code generation model

+
+
+ +
+
+ + + + + + +
+
+

Gemini CLI

+

Google's multimodal AI assistant

+
+
+ +
+
+ + + + + +
+
+

Opencode

+

Terminal-first AI coding assistant

+
+
+ +
+
+ + + + + + +
+
+

Cursor

+

AI-first code editor (cursor-agent)

+
+
+
+ +

+ Each agent stores session data in its own format. Sidecar normalizes and displays them in a unified interface. +

+
+
);