Skip to content

Commit 060f58b

Browse files
ofriwclaude
andcommitted
Add SpecCodeZoomDiagram visual component
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 8ca1d57 commit 060f58b

File tree

3 files changed

+685
-0
lines changed

3 files changed

+685
-0
lines changed

website/src/components/PresentationMode/RevealSlideshow.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import CompoundQualityVisualization from '../VisualElements/CompoundQualityVisua
2626
import KnowledgeExpansionDiamond from '../VisualElements/KnowledgeExpansionDiamond';
2727
import SystemFlowDiagram from '../VisualElements/SystemFlowDiagram';
2828
import SystemBoundaryDiagram from '../VisualElements/SystemBoundaryDiagram';
29+
import SpecCodeZoomDiagram from '../VisualElements/SpecCodeZoomDiagram';
2930

3031
interface SpeakerNotes {
3132
talkingPoints: string;
@@ -98,6 +99,7 @@ const VISUAL_COMPONENTS = {
9899
KnowledgeExpansionDiamond,
99100
SystemFlowDiagram,
100101
SystemBoundaryDiagram,
102+
SpecCodeZoomDiagram,
101103
};
102104

103105
export default function RevealSlideshow({
Lines changed: 365 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,365 @@
1+
.container {
2+
margin: 2.5rem auto;
3+
padding: 1.25rem;
4+
border-radius: 8px;
5+
background: var(--visual-bg-decision);
6+
border: 1px solid var(--visual-decision);
7+
max-width: 500px;
8+
animation: fadeIn 0.5s ease-out;
9+
}
10+
11+
/* Compact mode for presentations */
12+
.container.compact {
13+
margin: 0 auto;
14+
padding: 0;
15+
max-width: 100%;
16+
background: none;
17+
border: none;
18+
border-radius: 0;
19+
}
20+
21+
.container.compact .layerLabel {
22+
font-size: 16px;
23+
}
24+
25+
.container.compact .codeLabel {
26+
font-size: 18px;
27+
}
28+
29+
.container.compact .arrowLabel,
30+
.container.compact .arrowLabelExtract {
31+
font-size: 14px;
32+
}
33+
34+
.container.compact .iterateLabel {
35+
font-size: 13px;
36+
}
37+
38+
.container.compact .sourceLabel {
39+
font-size: 12px;
40+
}
41+
42+
@keyframes fadeIn {
43+
from {
44+
opacity: 0;
45+
transform: translateY(8px);
46+
}
47+
to {
48+
opacity: 1;
49+
transform: translateY(0);
50+
}
51+
}
52+
53+
.svg {
54+
width: 100%;
55+
height: auto;
56+
display: block;
57+
margin: 0 auto;
58+
overflow: visible;
59+
}
60+
61+
/* ===== BOX GROUPS (Staggered fade-in) ===== */
62+
63+
.specGroup {
64+
animation: fadeInSlide 0.35s ease-out backwards;
65+
}
66+
67+
.codeGroup {
68+
animation: fadeInScale 0.4s ease-out 0.15s backwards;
69+
}
70+
71+
@keyframes fadeInSlide {
72+
from {
73+
opacity: 0;
74+
transform: translateY(-8px);
75+
}
76+
to {
77+
opacity: 1;
78+
transform: translateY(0);
79+
}
80+
}
81+
82+
@keyframes fadeInScale {
83+
from {
84+
opacity: 0;
85+
transform: scale(0.97);
86+
}
87+
to {
88+
opacity: 1;
89+
transform: scale(1);
90+
}
91+
}
92+
93+
/* ===== BOX STYLES ===== */
94+
95+
.layerBox {
96+
fill: var(--ifm-background-surface-color);
97+
stroke: var(--visual-workflow);
98+
stroke-width: 1.5;
99+
}
100+
101+
.layerLabel {
102+
fill: var(--ifm-font-color-base);
103+
font-size: 14px;
104+
font-weight: 700;
105+
font-family: var(--ifm-font-family-base);
106+
letter-spacing: 0.4px;
107+
}
108+
109+
.subtitleLabel {
110+
fill: var(--ifm-color-emphasis-600);
111+
font-size: 11px;
112+
font-weight: 500;
113+
font-family: var(--ifm-font-family-base);
114+
font-style: italic;
115+
}
116+
117+
/* ===== CODE BOX (Emphasized) ===== */
118+
119+
.layerBoxCode {
120+
fill: var(--ifm-background-surface-color);
121+
stroke: url(#sczdCodeGradient);
122+
stroke-width: 2.5;
123+
}
124+
125+
.codeLabel {
126+
fill: var(--ifm-font-color-base);
127+
font-size: 16px;
128+
font-weight: 800;
129+
font-family: var(--ifm-font-family-base);
130+
letter-spacing: 1.5px;
131+
}
132+
133+
.sourceLabel {
134+
fill: var(--visual-capability);
135+
font-size: 10px;
136+
font-weight: 600;
137+
font-family: var(--ifm-font-family-base);
138+
text-transform: uppercase;
139+
letter-spacing: 0.8px;
140+
}
141+
142+
/* ===== GENERATE ARROW (Purple — Downward) ===== */
143+
144+
.generateGroup {
145+
animation: fadeIn 0.35s ease-out 0.3s backwards;
146+
}
147+
148+
.arrowGenerate {
149+
stroke: var(--visual-workflow);
150+
stroke-width: 2;
151+
stroke-linecap: round;
152+
stroke-dasharray: 180;
153+
stroke-dashoffset: 180;
154+
animation: drawArrow 0.7s ease-out 0.35s forwards;
155+
}
156+
157+
@keyframes drawArrow {
158+
to {
159+
stroke-dashoffset: 0;
160+
}
161+
}
162+
163+
.arrowMarkerGenerate polygon {
164+
fill: var(--visual-workflow);
165+
}
166+
167+
.arrowLabel {
168+
fill: var(--visual-workflow);
169+
font-size: 12px;
170+
font-weight: 600;
171+
font-family: var(--ifm-font-family-base);
172+
}
173+
174+
/* ===== EXTRACT ARROW (Cyan — Upward) ===== */
175+
176+
.extractGroup {
177+
animation: fadeIn 0.35s ease-out 0.55s backwards;
178+
}
179+
180+
.arrowExtract {
181+
stroke: var(--visual-capability);
182+
stroke-width: 2;
183+
stroke-linecap: round;
184+
stroke-dasharray: 180;
185+
stroke-dashoffset: 180;
186+
animation: drawArrow 0.7s ease-out 0.6s forwards;
187+
}
188+
189+
.arrowMarkerExtract polygon {
190+
fill: var(--visual-capability);
191+
}
192+
193+
.arrowLabelExtract {
194+
fill: var(--visual-capability);
195+
font-size: 12px;
196+
font-weight: 600;
197+
font-family: var(--ifm-font-family-base);
198+
}
199+
200+
/* ===== CENTER TEXT ===== */
201+
202+
.iterateLabel {
203+
fill: var(--ifm-color-emphasis-600);
204+
font-size: 11px;
205+
font-weight: 600;
206+
font-family: var(--ifm-font-family-base);
207+
font-style: italic;
208+
letter-spacing: 0.3px;
209+
}
210+
211+
/* ===== LEGEND ===== */
212+
213+
.legend {
214+
animation: fadeIn 0.3s ease-out 0.85s backwards;
215+
}
216+
217+
.legendLineGenerate {
218+
stroke: var(--visual-workflow);
219+
stroke-width: 2;
220+
}
221+
222+
.legendText {
223+
fill: var(--ifm-color-emphasis-600);
224+
font-size: 11px;
225+
font-family: var(--ifm-font-family-base);
226+
font-style: italic;
227+
}
228+
229+
/* ===== DESCRIPTION ===== */
230+
231+
.description {
232+
margin: 1.25rem 0 0 0;
233+
font-size: 0.85rem;
234+
line-height: 1.5;
235+
color: var(--ifm-color-emphasis-700);
236+
text-align: center;
237+
padding: 0 0.75rem;
238+
border-top: 1px solid var(--ifm-color-emphasis-300);
239+
padding-top: 0.875rem;
240+
}
241+
242+
.description strong {
243+
color: var(--ifm-font-color-base);
244+
font-weight: 600;
245+
}
246+
247+
/* ===== DARK MODE ===== */
248+
249+
[data-theme='dark'] .layerBox,
250+
[data-theme='dark'] .layerBoxCode {
251+
fill: var(--ifm-background-color);
252+
}
253+
254+
/* Reveal.js presentation dark mode */
255+
:global(.reveal) .layerBox,
256+
:global(.reveal) .layerBoxCode {
257+
fill: rgba(30, 30, 50, 0.9);
258+
}
259+
260+
:global(.reveal) .layerLabel,
261+
:global(.reveal) .codeLabel {
262+
fill: #e5e7eb;
263+
}
264+
265+
:global(.reveal) .subtitleLabel {
266+
fill: #9ca3af;
267+
}
268+
269+
:global(.reveal) .arrowLabel,
270+
:global(.reveal) .arrowLabelExtract {
271+
font-size: 15px;
272+
}
273+
274+
:global(.reveal) .iterateLabel {
275+
fill: #d1d5db;
276+
font-size: 14px;
277+
}
278+
279+
:global(.reveal) .sourceLabel {
280+
font-size: 12px;
281+
}
282+
283+
/* Size diagram for presentation — align to top so it respects h2 margin spacing */
284+
:global(.reveal) .container {
285+
align-self: flex-start;
286+
min-height: 280px;
287+
max-height: none;
288+
}
289+
290+
/* ===== RESPONSIVE ===== */
291+
292+
@media (max-width: 768px) {
293+
.container {
294+
padding: 1rem;
295+
margin: 2rem auto;
296+
}
297+
298+
.layerLabel {
299+
font-size: 12px;
300+
}
301+
302+
.codeLabel {
303+
font-size: 14px;
304+
}
305+
306+
.subtitleLabel {
307+
font-size: 10px;
308+
}
309+
310+
.arrowLabel,
311+
.arrowLabelExtract {
312+
font-size: 11px;
313+
}
314+
315+
.description {
316+
font-size: 0.8rem;
317+
padding: 0 0.5rem;
318+
padding-top: 0.75rem;
319+
}
320+
}
321+
322+
@media (max-width: 480px) {
323+
.layerLabel {
324+
font-size: 11px;
325+
letter-spacing: 0;
326+
}
327+
328+
.codeLabel {
329+
font-size: 12px;
330+
letter-spacing: 1px;
331+
}
332+
333+
.subtitleLabel {
334+
font-size: 10px;
335+
}
336+
337+
.arrowLabel,
338+
.arrowLabelExtract {
339+
font-size: 10px;
340+
}
341+
342+
.description {
343+
font-size: 0.75rem;
344+
}
345+
}
346+
347+
/* ===== REDUCED MOTION ===== */
348+
349+
@media (prefers-reduced-motion: reduce) {
350+
.container,
351+
.specGroup,
352+
.codeGroup,
353+
.generateGroup,
354+
.extractGroup,
355+
.legend {
356+
animation: none;
357+
}
358+
359+
.arrowGenerate,
360+
.arrowExtract {
361+
animation: none;
362+
stroke-dasharray: none;
363+
stroke-dashoffset: 0;
364+
}
365+
}

0 commit comments

Comments
 (0)