Skip to content

Commit acc2cae

Browse files
committed
feat(website): demo screencasts
1 parent ec1eaf2 commit acc2cae

9 files changed

Lines changed: 68 additions & 61 deletions

File tree

apps/desktop/src/App.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -470,15 +470,25 @@ export default function App() {
470470
setSessionHotkeyPage((prev) => (prev + 1) % hotkeyPageCount);
471471
}, [hotkeyPageCount]);
472472

473+
const handleSelectSession = useCallback(
474+
(sessionId: string) => {
475+
if (sessionId !== activeSessionId && filter) {
476+
setFilter("");
477+
}
478+
setActiveSessionId(sessionId);
479+
},
480+
[activeSessionId, filter, setActiveSessionId, setFilter]
481+
);
482+
473483
const selectSessionByHotkeyIndex = useCallback(
474484
(index: number) => {
475485
const target = visualSessions[sessionHotkeyPage * 9 + index];
476486
if (!target) {
477487
return;
478488
}
479-
setActiveSessionId(target.id);
489+
handleSelectSession(target.id);
480490
},
481-
[sessionHotkeyPage, setActiveSessionId, visualSessions]
491+
[handleSelectSession, sessionHotkeyPage, visualSessions]
482492
);
483493

484494
const modifierHotkeys = useMemo<HotkeyBinding[]>(
@@ -820,7 +830,7 @@ export default function App() {
820830
sessionShortcuts={sessionShortcuts}
821831
activeSessionId={activeSessionId}
822832
onFilterChange={setFilter}
823-
onSelectSession={setActiveSessionId}
833+
onSelectSession={handleSelectSession}
824834
onNewSession={handleOpenDialog}
825835
onOpenSettings={openSettings}
826836
onRenameSession={openRename}

apps/website/index.html

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -71,23 +71,14 @@ <h1 class="hero-title">Codelegate</h1>
7171
<!-- Overview -->
7272
<div class="pv-tour active" data-tour-panel="overview">
7373
<div class="pv-tour-media">
74-
<div class="screencast-placeholder pv-screencast">
75-
<div class="screencast-inner">
76-
<svg class="play-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg>
77-
<span>Screencast coming soon</span>
78-
</div>
79-
</div>
74+
<video class="pv-video" autoplay muted playsinline src="/videos/overview.mp4"></video>
8075
</div>
8176
</div>
8277

8378
<!-- Agent Support -->
8479
<div class="pv-tour" data-tour-panel="agents">
8580
<div class="pv-tour-media">
86-
<div class="screencast-placeholder pv-screencast">
87-
<div class="screencast-inner">
88-
<svg class="play-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg>
89-
</div>
90-
</div>
81+
<video class="pv-video" muted playsinline src="/videos/agents.mp4"></video>
9182
</div>
9283
<div class="pv-tour-text">
9384
<h2 class="pv-tour-headline">Supports Claude Code and Codex CLI</h2>
@@ -98,11 +89,7 @@ <h2 class="pv-tour-headline">Supports Claude Code and Codex CLI</h2>
9889
<!-- Git Worktree -->
9990
<div class="pv-tour" data-tour-panel="worktree">
10091
<div class="pv-tour-media">
101-
<div class="screencast-placeholder pv-screencast">
102-
<div class="screencast-inner">
103-
<svg class="play-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg>
104-
</div>
105-
</div>
92+
<video class="pv-video" muted playsinline src="/videos/gitworktree.mp4"></video>
10693
</div>
10794
<div class="pv-tour-text">
10895
<h2 class="pv-tour-headline">Git Worktree Management</h2>
@@ -113,11 +100,7 @@ <h2 class="pv-tour-headline">Git Worktree Management</h2>
113100
<!-- Keyboard Navigation -->
114101
<div class="pv-tour" data-tour-panel="keyboard">
115102
<div class="pv-tour-media">
116-
<div class="screencast-placeholder pv-screencast">
117-
<div class="screencast-inner">
118-
<svg class="play-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg>
119-
</div>
120-
</div>
103+
<video class="pv-video" muted playsinline src="/videos/keyboard.mp4"></video>
121104
</div>
122105
<div class="pv-tour-text">
123106
<h2 class="pv-tour-headline">Full Keyboard Navigation</h2>
@@ -128,11 +111,7 @@ <h2 class="pv-tour-headline">Full Keyboard Navigation</h2>
128111
<!-- All TUI Tools -->
129112
<div class="pv-tour" data-tour-panel="tui">
130113
<div class="pv-tour-media">
131-
<div class="screencast-placeholder pv-screencast">
132-
<div class="screencast-inner">
133-
<svg class="play-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg>
134-
</div>
135-
</div>
114+
<video class="pv-video" muted playsinline src="/videos/cli.mp4"></video>
136115
</div>
137116
<div class="pv-tour-text">
138117
<h2 class="pv-tour-headline">Use Whatever All TUI Tools You Like</h2>
1.29 MB
Binary file not shown.

apps/website/public/videos/cli.mp4

1.7 MB
Binary file not shown.
1.06 MB
Binary file not shown.
1.04 MB
Binary file not shown.
2.74 MB
Binary file not shown.

apps/website/src/main.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,33 @@ navItems.forEach((btn) => {
3030
}
3131
});
3232

33+
// Play video in panel, pause all others; restart from beginning
34+
function playVideoInPanel(panel) {
35+
panels.forEach((p) => {
36+
const v = p.querySelector("video");
37+
if (v) v.pause();
38+
});
39+
const video = panel.querySelector("video");
40+
if (video) {
41+
video.currentTime = 0;
42+
video.play();
43+
}
44+
}
45+
46+
// 2-second delay before looping: pause at end, then restart after 2s
47+
document.querySelectorAll(".pv-video").forEach((video) => {
48+
video.loop = false; // we handle looping manually
49+
video.addEventListener("ended", () => {
50+
setTimeout(() => {
51+
// Only restart if this panel is still active
52+
if (video.closest(".pv-tour.active")) {
53+
video.currentTime = 0;
54+
video.play();
55+
}
56+
}, 2000);
57+
});
58+
});
59+
3360
function switchTour(key) {
3461
if (key === activeTour || isAnimating) return;
3562
isAnimating = true;
@@ -57,6 +84,7 @@ function switchTour(key) {
5784

5885
// Activate new
5986
newPanel.classList.add("active");
87+
playVideoInPanel(newPanel);
6088

6189
requestAnimationFrame(() => {
6290
newPanel.style.opacity = "";

apps/website/src/style.css

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ a:hover {
5858
}
5959

6060
.hero-content {
61-
max-width: 1104px;
61+
max-width: 1286px;
6262
width: 100%;
6363
}
6464

@@ -101,30 +101,13 @@ a:hover {
101101
line-height: 1.5;
102102
}
103103

104-
/* ── Screencast placeholder ── */
105-
.screencast-placeholder {
106-
background: var(--surface);
107-
border: 1px solid var(--border);
104+
/* ── Video ── */
105+
.pv-video {
106+
width: 100%;
108107
border-radius: 12px;
109-
display: flex;
110-
align-items: center;
111-
justify-content: center;
112-
overflow: hidden;
113-
}
114-
115-
.screencast-inner {
116-
display: flex;
117-
flex-direction: column;
118-
align-items: center;
119-
gap: 0.75rem;
120-
color: var(--muted);
121-
font-size: 0.875rem;
122-
}
123-
124-
.play-icon {
125-
width: 48px;
126-
height: 48px;
127-
opacity: 0.4;
108+
border: 1px solid var(--border);
109+
background: var(--bg);
110+
display: block;
128111
}
129112

130113
/* ── Buttons ── */
@@ -192,15 +175,15 @@ a:hover {
192175
/* ── Product Viewer (inline in hero) ── */
193176
.pv-container {
194177
display: grid;
195-
grid-template-columns: 230px 1fr;
178+
grid-template-columns: 268px 1fr;
196179
gap: 0;
197180
margin: 0 auto 2.5rem;
198181
border: 1px solid var(--border);
199182
border-radius: 16px;
200183
overflow: hidden;
201184
background: var(--surface);
202185
box-shadow: var(--shadow);
203-
height: 644px;
186+
height: 750px;
204187
}
205188

206189
/* Left Nav */
@@ -330,7 +313,7 @@ a:hover {
330313
align-items: center;
331314
justify-content: center;
332315
gap: 1.25rem;
333-
padding: 2rem 2.5rem;
316+
padding: 24px;
334317
opacity: 0;
335318
pointer-events: none;
336319
transition: opacity 0.4s ease, transform 0.4s ease;
@@ -343,16 +326,23 @@ a:hover {
343326
transform: translateY(0);
344327
}
345328

346-
.pv-tour-media {
329+
/* Overview: video fills stage with 24px margin */
330+
.pv-tour[data-tour-panel="overview"] {
331+
padding: 24px;
332+
}
333+
334+
.pv-tour[data-tour-panel="overview"] .pv-tour-media {
347335
width: 100%;
348-
max-width: 580px;
336+
max-width: none;
349337
}
350338

351-
.pv-screencast {
352-
aspect-ratio: 16 / 9;
339+
/* Feature tours */
340+
.pv-tour-media {
353341
width: 100%;
342+
max-width: 800px;
354343
}
355344

345+
356346
.pv-tour-text {
357347
text-align: center;
358348
max-width: 560px;
@@ -398,7 +388,7 @@ a:hover {
398388
.pv-container {
399389
grid-template-columns: 1fr;
400390
grid-template-rows: auto 1fr;
401-
height: 575px;
391+
height: 670px;
402392
}
403393

404394
.pv-nav {

0 commit comments

Comments
 (0)