fix viz layout stability
This commit is contained in:
@@ -68,7 +68,7 @@ export default async function PatternDetailPage({ params }: PageProps) {
|
|||||||
: null;
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-4xl mx-auto space-y-8">
|
<div className="mx-auto space-y-8">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center gap-3 mb-2">
|
<div className="flex items-center gap-3 mb-2">
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export function MonotonicStackVisualization({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex items-end gap-6">
|
<div className="flex min-h-[180px] items-end gap-6">
|
||||||
{/* Stack (left side) */}
|
{/* Stack (left side) */}
|
||||||
{stack && <StackView stack={stack} />}
|
{stack && <StackView stack={stack} />}
|
||||||
|
|
||||||
|
|||||||
@@ -36,60 +36,50 @@ export function ExplanationPanel({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'h-28 overflow-y-auto rounded-lg border border-border bg-surface p-4',
|
'flex h-28 gap-4 rounded-lg border border-border bg-surface p-3',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="mb-3 flex items-center gap-2">
|
{/* Left side: phase badge + explanation */}
|
||||||
|
<div className="flex flex-1 flex-col overflow-hidden">
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
'rounded-full px-2.5 py-0.5 text-xs font-medium',
|
'mb-1.5 w-fit rounded-full px-2 py-0.5 text-xs font-medium',
|
||||||
PHASE_COLORS[phase]
|
PHASE_COLORS[phase]
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{PHASE_LABELS[phase]}
|
{PHASE_LABELS[phase]}
|
||||||
</span>
|
</span>
|
||||||
|
<AnimatePresence mode="wait">
|
||||||
|
<motion.p
|
||||||
|
key={explanation}
|
||||||
|
initial={{ opacity: 0, y: 5 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, y: -5 }}
|
||||||
|
transition={{ duration: 0.15 }}
|
||||||
|
className="text-sm leading-snug text-foreground"
|
||||||
|
>
|
||||||
|
{explanation}
|
||||||
|
</motion.p>
|
||||||
|
</AnimatePresence>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<AnimatePresence mode="wait">
|
{/* Right side: decision point (full height) */}
|
||||||
<motion.div
|
|
||||||
key={explanation}
|
|
||||||
initial={{ opacity: 0, y: 10 }}
|
|
||||||
animate={{ opacity: 1, y: 0 }}
|
|
||||||
exit={{ opacity: 0, y: -10 }}
|
|
||||||
transition={{ duration: 0.2 }}
|
|
||||||
>
|
|
||||||
<p className="text-base leading-relaxed text-foreground">
|
|
||||||
{explanation}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{decision && (
|
{decision && (
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, scale: 0.95 }}
|
key={decision.question}
|
||||||
animate={{ opacity: 1, scale: 1 }}
|
initial={{ opacity: 0, x: 10 }}
|
||||||
className="mt-4 rounded-lg border border-primary/30 bg-primary/5 p-4"
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
className="flex w-72 shrink-0 flex-col justify-center rounded-lg border border-primary/30 bg-primary/5 px-3 py-2 text-xs"
|
||||||
>
|
>
|
||||||
<div className="mb-2 text-sm font-medium text-primary">
|
<div className="mb-1 font-medium text-primary">Decision Point</div>
|
||||||
Decision Point
|
<div className="flex items-center gap-1">
|
||||||
</div>
|
|
||||||
<div className="space-y-2 text-sm">
|
|
||||||
<div className="flex items-start gap-2">
|
|
||||||
<span className="font-medium text-foreground-muted">Q:</span>
|
|
||||||
<span className="text-foreground">{decision.question}</span>
|
<span className="text-foreground">{decision.question}</span>
|
||||||
</div>
|
|
||||||
<div className="flex items-start gap-2">
|
|
||||||
<span className="font-medium text-foreground-muted">A:</span>
|
|
||||||
<span className="font-mono text-primary">{decision.answer}</span>
|
<span className="font-mono text-primary">{decision.answer}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-start gap-2">
|
<div className="mt-0.5 text-success">→ {decision.action}</div>
|
||||||
<span className="font-medium text-foreground-muted">→</span>
|
|
||||||
<span className="text-success">{decision.action}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)}
|
)}
|
||||||
</motion.div>
|
|
||||||
</AnimatePresence>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export function VisualizationContainer({
|
|||||||
</span>
|
</span>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div className="grid gap-3 lg:grid-cols-[1fr_1.5fr]">
|
<div className="grid gap-3 lg:grid-cols-[1fr_2fr]">
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
<CodePanel
|
<CodePanel
|
||||||
code={code}
|
code={code}
|
||||||
|
|||||||
Reference in New Issue
Block a user