Commit
add council nodes motif to hero
commit
5f7e403
2 changed files with +56 and −1
Jump to a changed file
added src/components/debate/council-nodes.tsx +50 −0
| @@ -0,0 +1,50 @@ | ||
| 1 | +import { Gavel } from 'lucide-react'; | |
| 2 | +import { displayNameForModel, type Participant } from '@/core/types'; | |
| 3 | +import { participantColor, participantTag } from '@/lib/model-visuals'; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * The council as a row of colored nodes flowing into a chairman - a compact | |
| 7 | + * visual of the whole mechanism (members deliberate, a chairman decides). | |
| 8 | + */ | |
| 9 | +export function CouncilNodes({ | |
| 10 | + participants, | |
| 11 | + chairmanModel, | |
| 12 | +}: { | |
| 13 | + participants: Participant[]; | |
| 14 | + chairmanModel: string; | |
| 15 | +}) { | |
| 16 | + return ( | |
| 17 | + <div className="flex flex-wrap items-center justify-center gap-x-1.5 gap-y-3"> | |
| 18 | + {participants.map((p, i) => ( | |
| 19 | + <div key={p.id} className="flex items-center gap-1.5"> | |
| 20 | + {i > 0 && <Connector />} | |
| 21 | + <span className="flex items-center gap-1.5"> | |
| 22 | + <span | |
| 23 | + className="flex h-6 w-6 items-center justify-center rounded-full text-[10px] font-bold text-white shadow-sm" | |
| 24 | + style={{ backgroundColor: participantColor(i) }} | |
| 25 | + > | |
| 26 | + {participantTag(i)} | |
| 27 | + </span> | |
| 28 | + <span className="hidden text-xs text-muted-foreground sm:inline">{p.displayName}</span> | |
| 29 | + </span> | |
| 30 | + </div> | |
| 31 | + ))} | |
| 32 | + <Connector /> | |
| 33 | + <span className="flex items-center gap-1.5"> | |
| 34 | + <span | |
| 35 | + className="flex h-6 w-6 items-center justify-center rounded-full text-white shadow-sm" | |
| 36 | + style={{ backgroundColor: 'hsl(var(--stage-synthesis))' }} | |
| 37 | + > | |
| 38 | + <Gavel className="h-3 w-3" /> | |
| 39 | + </span> | |
| 40 | + <span className="hidden text-xs text-muted-foreground sm:inline"> | |
| 41 | + {displayNameForModel(chairmanModel)} | |
| 42 | + </span> | |
| 43 | + </span> | |
| 44 | + </div> | |
| 45 | + ); | |
| 46 | +} | |
| 47 | + | |
| 48 | +function Connector() { | |
| 49 | + return <span className="h-px w-5 bg-gradient-to-r from-transparent via-border to-transparent sm:w-8" />; | |
| 50 | +} |
modified src/components/landing-hero.tsx +6 −1
| @@ -3,6 +3,7 @@ | ||
| 3 | 3 | import { ArrowRight } from 'lucide-react'; |
| 4 | 4 | import Link from 'next/link'; |
| 5 | 5 | import { useEffect } from 'react'; |
| 6 | +import { CouncilNodes } from '@/components/debate/council-nodes'; | |
| 6 | 7 | import { DebateConsole } from '@/components/debate/debate-console'; |
| 7 | 8 | import { Button } from '@/components/ui/button'; |
| 8 | 9 | import type { DebateResult } from '@/core/types'; |
| @@ -70,7 +71,11 @@export function LandingHero({ result }: { result: DebateResult }) { | ||
| 70 | 71 | </div> |
| 71 | 72 | </div> |
| 72 | 73 | |
| 73 | - <div className="relative mx-auto max-w-5xl"> | |
| 74 | + <div className="reveal mb-6 flex justify-center" style={{ animationDelay: '320ms' }}> | |
| 75 | + <CouncilNodes participants={result.participants} chairmanModel={result.config.chairmanModel} /> | |
| 76 | + </div> | |
| 77 | + | |
| 78 | + <div className="reveal relative mx-auto max-w-5xl" style={{ animationDelay: '400ms' }}> | |
| 74 | 79 | <div className="pointer-events-none absolute -inset-x-4 -top-4 bottom-4 -z-10 rounded-[2.5rem] bg-primary/[0.07] blur-3xl" /> |
| 75 | 80 | <div className="relative overflow-hidden rounded-2xl border bg-card shadow-2xl"> |
| 76 | 81 | <div className="flex items-center gap-3 border-b px-4 py-2.5"> |