singularity-forge/web/components/sf/onboarding/wizard-stepper.tsx
ace-pm 172753c3b2 refactor(forge): complete gsd → forge rebrand across native, logging, and build system
- Rename native Rust crates: gsd-engine → forge-engine, gsd-ast → forge-ast, gsd-grep → forge-grep
- Update all crate dependencies (Cargo.toml, .rs source) and N-API artifacts
- Mass rename log prefix [gsd] → [forge] across 81 files (scripts, src/, extensions, tests)
- Rename log prefix "gsd-db:" → "forge-db:" in template literals
- Update nix flake: add sf-run-native devShell with Rust toolchain for native addon builds
- Update CI workflow artifact names (build-native.yml)
- Verify only packages/native/* touched (no upstream pi-* packages renamed)

Rationale: Complete gsd-2 → singularity-forge rebrand (2026-04-15). Native addon is
sf-run-specific; all gsd-prefixed logging and crate names must align with new identity.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 14:11:45 +02: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>
)
}