Long strings without spaces caused the Add Source dialog to expand beyond the viewport due to field-sizing-content on textareas propagating width through CSS grid/flex layout. Add min-w-0 to Textarea, WizardContainer content layers, and the AddSourceDialog form to prevent flex/grid items from expanding to fit content. Add overflow-hidden to base DialogContent as a safeguard.
104 lines
3.1 KiB
TypeScript
104 lines
3.1 KiB
TypeScript
"use client"
|
|
|
|
import { ReactNode } from "react"
|
|
import { cn } from "@/lib/utils"
|
|
|
|
interface WizardStep {
|
|
number: number
|
|
title: string
|
|
description: string
|
|
}
|
|
|
|
interface WizardContainerProps {
|
|
children: ReactNode
|
|
currentStep: number
|
|
steps: readonly WizardStep[]
|
|
onStepClick?: (step: number) => void
|
|
className?: string
|
|
}
|
|
|
|
function StepIndicator({ currentStep, steps, onStepClick }: {
|
|
currentStep: number
|
|
steps: readonly WizardStep[]
|
|
onStepClick?: (step: number) => void
|
|
}) {
|
|
return (
|
|
<div className="flex items-center justify-between px-6 py-4 border-b border-border bg-muted">
|
|
{steps.map((step, index) => {
|
|
const isCompleted = currentStep > step.number
|
|
const isCurrent = currentStep === step.number
|
|
const isClickable = step.number <= currentStep && onStepClick
|
|
|
|
return (
|
|
<div key={step.number} className="flex items-center flex-1">
|
|
<div
|
|
className={cn('flex items-center', isClickable && 'cursor-pointer')}
|
|
onClick={isClickable ? () => onStepClick(step.number) : undefined}
|
|
>
|
|
<div
|
|
className={cn(
|
|
'flex items-center justify-center w-8 h-8 rounded-full border-2 text-sm font-medium transition-colors',
|
|
isCompleted
|
|
? 'bg-primary border-primary text-primary-foreground'
|
|
: isCurrent
|
|
? 'border-primary text-primary bg-primary/10'
|
|
: 'border-border text-muted-foreground bg-card'
|
|
)}
|
|
>
|
|
{isCompleted ? "✓" : step.number}
|
|
</div>
|
|
<div className="ml-3 min-w-0">
|
|
<p className={cn(
|
|
'text-sm font-medium',
|
|
isCurrent ? 'text-foreground' : 'text-muted-foreground'
|
|
)}>
|
|
{step.title}
|
|
</p>
|
|
<p className={cn(
|
|
'text-xs',
|
|
isCurrent ? 'text-muted-foreground' : 'text-muted-foreground/80'
|
|
)}>
|
|
{step.description}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
{index < steps.length - 1 && (
|
|
<div
|
|
className={cn(
|
|
'flex-1 border-t-2 mx-4 transition-colors',
|
|
isCompleted ? 'border-primary' : 'border-border/60'
|
|
)}
|
|
/>
|
|
)}
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function WizardContainer({
|
|
children,
|
|
currentStep,
|
|
steps,
|
|
onStepClick,
|
|
className
|
|
}: WizardContainerProps) {
|
|
return (
|
|
<div className={cn('flex flex-col h-[500px] min-w-0 overflow-hidden bg-card rounded-lg border border-border', className)}>
|
|
<StepIndicator
|
|
currentStep={currentStep}
|
|
steps={steps}
|
|
onStepClick={onStepClick}
|
|
/>
|
|
|
|
<div className="flex-1 min-w-0 overflow-hidden">
|
|
<div className="h-full min-w-0 overflow-y-auto px-6 py-4">
|
|
{children}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export type { WizardStep }
|