singularity-forge/web/components/gsd/onboarding/wizard-stepper.tsx
Andrew 07d804588e feat(web): Dark mode contrast — raise token floor and flatten opacity tier system (#2734)
* feat: Raised four dark-mode tokens, converted five hardcoded oklch valu…

- "web/app/globals.css"
- "web/components/gsd/code-editor.tsx"

GSD-Task: S01/T01

* feat: Applied border-border 2-tier sweep across 21 component files: /20…

- "web/components/gsd/command-surface.tsx"
- "web/components/gsd/remaining-command-panels.tsx"
- "web/components/gsd/chat-mode.tsx"
- "web/components/gsd/settings-panels.tsx"
- "web/components/gsd/diagnostics-panels.tsx"
- "web/components/gsd/onboarding/step-authenticate.tsx"
- "web/components/gsd/knowledge-captures-panel.tsx"
- "web/components/gsd/projects-view.tsx"

GSD-Task: S02/T01

* feat: Swept text-foreground/muted-foreground/sidebar-foreground opacity…

- "web/components/gsd/command-surface.tsx"
- "web/components/gsd/remaining-command-panels.tsx"
- "web/components/gsd/chat-mode.tsx"
- "web/components/gsd/settings-panels.tsx"
- "web/components/gsd/diagnostics-panels.tsx"
- "web/components/gsd/knowledge-captures-panel.tsx"
- "web/components/gsd/projects-view.tsx"
- "web/components/gsd/visualizer-view.tsx"

GSD-Task: S02/T02

* feat: Applied background opacity mapping tables across all component fi…

- "web/components/gsd/remaining-command-panels.tsx"
- "web/components/gsd/command-surface.tsx"
- "web/components/gsd/visualizer-view.tsx"
- "web/components/gsd/chat-mode.tsx"
- "web/components/gsd/settings-panels.tsx"
- "web/components/gsd/diagnostics-panels.tsx"
- "web/components/gsd/onboarding/step-authenticate.tsx"
- "web/components/gsd/knowledge-captures-panel.tsx"

GSD-Task: S02/T03
2026-03-26 16:17:03 -06:00

88 lines
3.1 KiB
TypeScript

"use client"
import { cn } from "@/lib/utils"
import { Check } from "lucide-react"
export interface WizardStep {
id: string
label: string
shortLabel?: string
}
interface WizardStepperProps {
steps: WizardStep[]
currentIndex: number
onStepClick?: (index: number) => void
className?: string
}
export function WizardStepper({ steps, currentIndex, onStepClick, className }: WizardStepperProps) {
return (
<nav aria-label="Onboarding progress" className={cn("flex items-center gap-0", className)}>
{steps.map((step, index) => {
const isComplete = index < currentIndex
const isCurrent = index === currentIndex
const isClickable = onStepClick && index <= currentIndex
return (
<div key={step.id} className="flex items-center">
{/* Step node */}
<button
type="button"
onClick={() => isClickable && onStepClick(index)}
disabled={!isClickable}
aria-current={isCurrent ? "step" : undefined}
className={cn(
"group relative flex items-center gap-2.5 rounded-full px-1 py-1 transition-all duration-300",
isClickable && "cursor-pointer",
!isClickable && "cursor-default",
)}
>
{/* Circle indicator */}
<div
className={cn(
"relative flex h-8 w-8 shrink-0 items-center justify-center rounded-full border-2 transition-all duration-300",
isComplete && "border-foreground/80 bg-foreground/90 text-background",
isCurrent && "border-foreground bg-foreground text-background shadow-[0_0_12px_rgba(255,255,255,0.15)]",
!isComplete && !isCurrent && "border-border bg-background text-muted-foreground",
)}
>
{isComplete ? (
<Check className="h-3.5 w-3.5" strokeWidth={3} />
) : (
<span className={cn("text-xs font-semibold tabular-nums", isCurrent && "text-background")}>
{index + 1}
</span>
)}
</div>
{/* Label */}
<span
className={cn(
"hidden text-sm font-medium transition-colors duration-200 sm:inline",
isCurrent && "text-foreground",
isComplete && "text-muted-foreground",
!isComplete && !isCurrent && "text-muted-foreground",
)}
>
{step.shortLabel ?? step.label}
</span>
</button>
{/* Connector line */}
{index < steps.length - 1 && (
<div className="mx-1 hidden h-px w-8 sm:block lg:w-12">
<div
className={cn(
"h-full transition-all duration-500",
index < currentIndex ? "bg-foreground/50" : "bg-border",
)}
/>
</div>
)}
</div>
)
})}
</nav>
)
}