Storybook (#328)
* feat(docs): add interactive examples and API references for Button, Card, and LoadingFallback components - Updated dependencies - Set `retries` to a fixed value of 3 for consistent test retries across environments. - Increased `timeout` from 60 seconds to 120 seconds to allow more time for tests to complete. - Reduced `expect` timeout from 10 seconds to 5 seconds for quicker feedback on assertions.
This commit is contained in:
committed by
GitHub
parent
360ea30f4b
commit
ad427365c9
165
apps/dev-tool/app/components/components/story-select.tsx
Normal file
165
apps/dev-tool/app/components/components/story-select.tsx
Normal file
@@ -0,0 +1,165 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
} from '@kit/ui/select';
|
||||
import { cn } from '@kit/ui/utils';
|
||||
|
||||
import type { SelectOption } from '../lib/story-utils';
|
||||
|
||||
interface StorySelectProps<T = string> {
|
||||
value: T;
|
||||
onValueChange: (value: T) => void;
|
||||
options: SelectOption<T>[];
|
||||
placeholder?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function StorySelect<T extends string = string>({
|
||||
value,
|
||||
onValueChange,
|
||||
options,
|
||||
placeholder,
|
||||
className,
|
||||
}: StorySelectProps<T>) {
|
||||
const selectedOption = options.find((opt) => opt.value === value);
|
||||
|
||||
return (
|
||||
<Select value={value} onValueChange={onValueChange}>
|
||||
<SelectTrigger className={cn('min-h-[3.5rem] py-2', className)}>
|
||||
<div className="flex w-full items-center">
|
||||
{selectedOption ? (
|
||||
<div
|
||||
className={cn(
|
||||
'flex w-full',
|
||||
selectedOption.icon ? 'gap-3' : 'gap-0',
|
||||
)}
|
||||
>
|
||||
{selectedOption.icon && (
|
||||
<selectedOption.icon
|
||||
className={cn(
|
||||
'mt-0.5 h-4 w-4 flex-shrink-0',
|
||||
selectedOption.color && `text-${selectedOption.color}`,
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<div className="flex min-w-0 flex-col gap-0.5">
|
||||
<span className="text-sm leading-none font-medium">
|
||||
{selectedOption.label}
|
||||
</span>
|
||||
<span className="text-muted-foreground text-xs leading-tight">
|
||||
{selectedOption.description}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<span className="text-muted-foreground">{placeholder}</span>
|
||||
)}
|
||||
</div>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{options.map((option) => {
|
||||
const Icon = option.icon;
|
||||
return (
|
||||
<SelectItem
|
||||
key={option.value}
|
||||
value={option.value}
|
||||
className="min-h-[3.5rem] items-start py-2"
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'flex w-full',
|
||||
Icon ? 'items-start gap-3' : 'items-center gap-0',
|
||||
)}
|
||||
>
|
||||
{Icon && (
|
||||
<Icon
|
||||
className={cn(
|
||||
'mt-0.5 h-4 w-4 flex-shrink-0',
|
||||
option.color && `text-${option.color}`,
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<div className="flex min-w-0 flex-col gap-0.5">
|
||||
<span className="text-sm leading-none font-medium">
|
||||
{option.label}
|
||||
</span>
|
||||
<span className="text-muted-foreground text-xs leading-tight">
|
||||
{option.description}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SelectItem>
|
||||
);
|
||||
})}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
|
||||
interface SimpleStorySelectProps<T = string> {
|
||||
value: T;
|
||||
onValueChange: (value: T) => void;
|
||||
options: Array<{
|
||||
value: T;
|
||||
label: string;
|
||||
description: string;
|
||||
}>;
|
||||
placeholder?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function SimpleStorySelect<T extends string = string>({
|
||||
value,
|
||||
onValueChange,
|
||||
options,
|
||||
placeholder,
|
||||
className,
|
||||
}: SimpleStorySelectProps<T>) {
|
||||
const selectedOption = options.find((opt) => opt.value === value);
|
||||
|
||||
return (
|
||||
<Select value={value} onValueChange={onValueChange}>
|
||||
<SelectTrigger className={cn('min-h-[3rem] py-2', className)}>
|
||||
<div className="flex w-full items-center">
|
||||
{selectedOption ? (
|
||||
<div className="flex flex-col items-start gap-0.5">
|
||||
<span className="text-sm leading-none font-medium">
|
||||
{selectedOption.label}
|
||||
</span>
|
||||
|
||||
<span className="text-muted-foreground text-xs leading-tight">
|
||||
{selectedOption.description}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<span className="text-muted-foreground">{placeholder}</span>
|
||||
)}
|
||||
</div>
|
||||
</SelectTrigger>
|
||||
|
||||
<SelectContent>
|
||||
{options.map((option) => (
|
||||
<SelectItem
|
||||
key={option.value}
|
||||
value={option.value}
|
||||
className="min-h-[3rem] items-start py-2"
|
||||
>
|
||||
<div className="flex flex-col items-start gap-0.5">
|
||||
<span className="text-sm leading-none font-medium">
|
||||
{option.label}
|
||||
</span>
|
||||
|
||||
<span className="text-muted-foreground text-xs leading-tight">
|
||||
{option.description}
|
||||
</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user