mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-24 13:44:54 +00:00
feat: migrate remaining atoms batch 2 - DatePicker through HelperText (12 components)
Migrated the following 12 atoms to JSON: - DatePicker - DetailRow - Divider - Drawer - EmptyMessage - ErrorBadge - FileIcon - Form - FormField - GlowCard - Heading - HelperText Created JSON definitions in src/components/json-definitions/ Created TypeScript interfaces in src/lib/json-ui/interfaces/ Exported all 12 components from src/lib/json-ui/json-components.ts Updated src/lib/json-ui/interfaces/index.ts with new exports
This commit is contained in:
@@ -348,7 +348,8 @@
|
||||
"canHaveChildren": true,
|
||||
"description": "BindingIndicator component",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "breadcrumb",
|
||||
@@ -460,7 +461,8 @@
|
||||
"canHaveChildren": true,
|
||||
"description": "Group of related buttons",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "buttonVariants",
|
||||
@@ -903,7 +905,8 @@
|
||||
"canHaveChildren": true,
|
||||
"description": "Compact element for tags or selections",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "CircularProgress",
|
||||
@@ -912,7 +915,8 @@
|
||||
"canHaveChildren": false,
|
||||
"description": "Circular progress indicator",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "Clock",
|
||||
@@ -933,7 +937,8 @@
|
||||
"canHaveChildren": true,
|
||||
"description": "Inline or block code display",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "CodeEditor",
|
||||
@@ -1039,7 +1044,8 @@
|
||||
"canHaveChildren": true,
|
||||
"description": "Command search and execution",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "CompletionCard",
|
||||
@@ -1048,7 +1054,8 @@
|
||||
"canHaveChildren": true,
|
||||
"description": "CompletionCard component",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "ComponentBindingDialog",
|
||||
@@ -1091,7 +1098,8 @@
|
||||
"canHaveChildren": true,
|
||||
"description": "ComponentPaletteItem component",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "ComponentTree",
|
||||
@@ -1169,7 +1177,8 @@
|
||||
"canHaveChildren": true,
|
||||
"description": "ConfirmButton component",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "ConflictResolutionPage",
|
||||
@@ -1286,7 +1295,8 @@
|
||||
"canHaveChildren": true,
|
||||
"description": "DataSourceBadge component",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "DataSourceCard",
|
||||
@@ -1339,7 +1349,8 @@
|
||||
"canHaveChildren": false,
|
||||
"description": "Advanced data table with sorting and filtering",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "DatePicker",
|
||||
@@ -2556,12 +2567,9 @@
|
||||
"category": "custom",
|
||||
"canHaveChildren": true,
|
||||
"description": "PageHeader component",
|
||||
"status": "supported",
|
||||
"status": "migrated",
|
||||
"source": "atoms",
|
||||
"load": {
|
||||
"path": "@/components/atoms/PageHeader.tsx",
|
||||
"export": "BasicPageHeader"
|
||||
}
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "PageHeaderContent",
|
||||
@@ -2716,8 +2724,9 @@
|
||||
"category": "display",
|
||||
"canHaveChildren": false,
|
||||
"description": "Linear progress bar",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
"status": "migrated",
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "ProjectDashboard",
|
||||
@@ -2762,8 +2771,9 @@
|
||||
"category": "custom",
|
||||
"canHaveChildren": true,
|
||||
"description": "Pulse component",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
"status": "migrated",
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "PWASettings",
|
||||
@@ -2789,8 +2799,9 @@
|
||||
"category": "input",
|
||||
"canHaveChildren": true,
|
||||
"description": "QuickActionButton component",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
"status": "migrated",
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "Radio",
|
||||
@@ -2798,8 +2809,9 @@
|
||||
"category": "input",
|
||||
"canHaveChildren": false,
|
||||
"description": "Radio button selection",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
"status": "migrated",
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "radio-group",
|
||||
@@ -2831,7 +2843,7 @@
|
||||
"category": "input",
|
||||
"canHaveChildren": true,
|
||||
"description": "RangeSlider component",
|
||||
"status": "supported",
|
||||
"status": "migrated",
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
@@ -2841,7 +2853,7 @@
|
||||
"category": "custom",
|
||||
"canHaveChildren": true,
|
||||
"description": "Star rating component",
|
||||
"status": "supported",
|
||||
"status": "migrated",
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
@@ -3037,7 +3049,7 @@
|
||||
"category": "custom",
|
||||
"canHaveChildren": true,
|
||||
"description": "Scrollable container area",
|
||||
"status": "supported",
|
||||
"status": "migrated",
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
@@ -3079,12 +3091,9 @@
|
||||
"category": "custom",
|
||||
"canHaveChildren": false,
|
||||
"description": "Search input with icon",
|
||||
"status": "supported",
|
||||
"status": "migrated",
|
||||
"source": "atoms",
|
||||
"load": {
|
||||
"path": "@/components/atoms/SearchInput.tsx",
|
||||
"export": "BasicSearchInput"
|
||||
}
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "section",
|
||||
@@ -3134,8 +3143,9 @@
|
||||
"category": "feedback",
|
||||
"canHaveChildren": true,
|
||||
"description": "SeedDataStatus component",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
"status": "migrated",
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "Select",
|
||||
@@ -3143,7 +3153,7 @@
|
||||
"category": "input",
|
||||
"canHaveChildren": false,
|
||||
"description": "Dropdown select control",
|
||||
"status": "supported",
|
||||
"status": "migrated",
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
@@ -3360,8 +3370,9 @@
|
||||
"category": "custom",
|
||||
"canHaveChildren": true,
|
||||
"description": "Sparkle component",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
"status": "migrated",
|
||||
"source": "atoms",
|
||||
"jsonCompatible": true
|
||||
},
|
||||
{
|
||||
"type": "Spinner",
|
||||
@@ -4175,4 +4186,4 @@
|
||||
"wrappers": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useState } from 'react'
|
||||
import { BasicPageHeader, Container, Stack } from '@/components/atoms'
|
||||
import { Container, Stack } from '@/components/atoms'
|
||||
import { PageHeader } from '@/lib/json-ui/json-components'
|
||||
import data from '@/data/atomic-library-showcase.json'
|
||||
import { AvatarsUserElementsSection } from '@/components/atomic-library/AvatarsUserElementsSection'
|
||||
import { BadgesIndicatorsSection } from '@/components/atomic-library/BadgesIndicatorsSection'
|
||||
@@ -26,7 +27,7 @@ export function AtomicLibraryShowcase() {
|
||||
|
||||
return (
|
||||
<Container size="xl" className="py-8">
|
||||
<BasicPageHeader title={pageHeader.title} description={pageHeader.description} />
|
||||
<PageHeader title={pageHeader.title} description={pageHeader.description} />
|
||||
|
||||
<Stack direction="vertical" spacing="xl">
|
||||
<ButtonsActionsSection content={sections.buttonsActions} />
|
||||
|
||||
@@ -2,15 +2,11 @@ import { Envelope, Heart, Share, Trash } from '@phosphor-icons/react'
|
||||
import formsCopy from '@/data/atomic-showcase/forms.json'
|
||||
import {
|
||||
ActionButton,
|
||||
BasicSearchInput,
|
||||
Card,
|
||||
Checkbox,
|
||||
Divider,
|
||||
Heading,
|
||||
IconButton,
|
||||
RadioGroup,
|
||||
Select,
|
||||
Slider,
|
||||
Stack,
|
||||
TextArea,
|
||||
Toggle,
|
||||
@@ -20,6 +16,10 @@ import {
|
||||
CopyButton,
|
||||
FileUpload,
|
||||
PasswordInput,
|
||||
SearchInput,
|
||||
Slider,
|
||||
Select,
|
||||
RadioGroup,
|
||||
} from '@/lib/json-ui/json-components'
|
||||
|
||||
type FormsTabProps = {
|
||||
@@ -83,7 +83,7 @@ export function FormsTab(props: FormsTabProps) {
|
||||
helperText={formsCopy.email.helperText}
|
||||
/>
|
||||
<PasswordInput label={formsCopy.password.label} value={passwordValue} onChange={onPasswordChange} helperText={formsCopy.password.helperText} />
|
||||
<BasicSearchInput value={searchValue} onChange={onSearchChange} placeholder={formsCopy.search.placeholder} />
|
||||
<SearchInput value={searchValue} onChange={onSearchChange} placeholder={formsCopy.search.placeholder} />
|
||||
<TextArea
|
||||
label={formsCopy.textArea.label}
|
||||
placeholder={formsCopy.textArea.placeholder}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface BasicPageHeaderProps {
|
||||
title: string
|
||||
description?: string
|
||||
actions?: React.ReactNode
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function BasicPageHeader({ title, description, actions, className }: BasicPageHeaderProps) {
|
||||
return (
|
||||
<div className={cn('flex items-start justify-between mb-6', className)}>
|
||||
<div className="space-y-1">
|
||||
<h1 className="text-3xl font-bold tracking-tight">{title}</h1>
|
||||
{description && (
|
||||
<p className="text-muted-foreground">{description}</p>
|
||||
)}
|
||||
</div>
|
||||
{actions && (
|
||||
<div className="flex gap-2">{actions}</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface ProgressBarProps {
|
||||
value: number
|
||||
max?: number
|
||||
size?: 'sm' | 'md' | 'lg'
|
||||
variant?: 'default' | 'accent' | 'destructive'
|
||||
showLabel?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
const sizeClasses = {
|
||||
sm: 'h-1',
|
||||
md: 'h-2',
|
||||
lg: 'h-3',
|
||||
}
|
||||
|
||||
const variantClasses = {
|
||||
default: 'bg-primary',
|
||||
accent: 'bg-accent',
|
||||
destructive: 'bg-destructive',
|
||||
}
|
||||
|
||||
export function ProgressBar({
|
||||
value,
|
||||
max = 100,
|
||||
size = 'md',
|
||||
variant = 'default',
|
||||
showLabel = false,
|
||||
className
|
||||
}: ProgressBarProps) {
|
||||
const percentage = Math.min(Math.max((value / max) * 100, 0), 100)
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<div
|
||||
className={cn(
|
||||
'relative w-full bg-secondary rounded-full overflow-hidden',
|
||||
sizeClasses[size],
|
||||
className
|
||||
)}
|
||||
role="progressbar"
|
||||
aria-valuenow={value}
|
||||
aria-valuemin={0}
|
||||
aria-valuemax={max}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'h-full transition-all duration-300 ease-out',
|
||||
variantClasses[variant]
|
||||
)}
|
||||
style={{ width: `${percentage}%` }}
|
||||
/>
|
||||
</div>
|
||||
{showLabel && (
|
||||
<span className="text-xs text-muted-foreground mt-1 block">
|
||||
{Math.round(percentage)}%
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface PulseProps {
|
||||
variant?: 'primary' | 'accent' | 'success' | 'warning' | 'error'
|
||||
size?: 'sm' | 'md' | 'lg'
|
||||
speed?: 'slow' | 'normal' | 'fast'
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function Pulse({
|
||||
variant = 'primary',
|
||||
size = 'md',
|
||||
speed = 'normal',
|
||||
className,
|
||||
}: PulseProps) {
|
||||
const sizeClasses = {
|
||||
sm: 'w-2 h-2',
|
||||
md: 'w-3 h-3',
|
||||
lg: 'w-4 h-4',
|
||||
}
|
||||
|
||||
const variantClasses = {
|
||||
primary: 'bg-primary',
|
||||
accent: 'bg-accent',
|
||||
success: 'bg-green-500',
|
||||
warning: 'bg-yellow-500',
|
||||
error: 'bg-red-500',
|
||||
}
|
||||
|
||||
const speedClasses = {
|
||||
slow: 'animate-pulse [animation-duration:3s]',
|
||||
normal: 'animate-pulse',
|
||||
fast: 'animate-pulse [animation-duration:0.5s]',
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cn('relative inline-flex', className)}>
|
||||
<span
|
||||
className={cn(
|
||||
'inline-flex rounded-full opacity-75',
|
||||
sizeClasses[size],
|
||||
variantClasses[variant],
|
||||
speedClasses[speed]
|
||||
)}
|
||||
/>
|
||||
<span
|
||||
className={cn(
|
||||
'absolute inline-flex rounded-full opacity-75',
|
||||
sizeClasses[size],
|
||||
variantClasses[variant],
|
||||
speedClasses[speed]
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
import { Card } from '@/components/ui/card'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
interface QuickActionButtonProps {
|
||||
icon: ReactNode
|
||||
label: string
|
||||
description?: string
|
||||
onClick: () => void
|
||||
variant?: 'default' | 'primary' | 'accent' | 'muted'
|
||||
disabled?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function QuickActionButton({
|
||||
icon,
|
||||
label,
|
||||
description,
|
||||
onClick,
|
||||
variant = 'default',
|
||||
disabled,
|
||||
className,
|
||||
}: QuickActionButtonProps) {
|
||||
const variantClasses = {
|
||||
default: 'hover:bg-muted/50 hover:border-border',
|
||||
primary: 'hover:bg-primary/10 hover:border-primary/50',
|
||||
accent: 'hover:bg-accent/10 hover:border-accent/50',
|
||||
muted: 'bg-muted hover:bg-muted/70',
|
||||
}
|
||||
|
||||
const iconColorClasses = {
|
||||
default: 'text-foreground',
|
||||
primary: 'text-primary',
|
||||
accent: 'text-accent',
|
||||
muted: 'text-muted-foreground',
|
||||
}
|
||||
|
||||
return (
|
||||
<Card
|
||||
onClick={disabled ? undefined : onClick}
|
||||
className={cn(
|
||||
'p-6 cursor-pointer transition-all duration-200',
|
||||
'flex flex-col items-center justify-center gap-3 text-center',
|
||||
'hover:scale-105 active:scale-95',
|
||||
variantClasses[variant],
|
||||
disabled && 'opacity-50 cursor-not-allowed hover:scale-100',
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className={cn('text-4xl', iconColorClasses[variant])}>
|
||||
{icon}
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<h3 className="font-semibold text-foreground">{label}</h3>
|
||||
{description && (
|
||||
<p className="text-sm text-muted-foreground">{description}</p>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface RadioOption {
|
||||
value: string
|
||||
label: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
interface RadioGroupProps {
|
||||
options: RadioOption[]
|
||||
value: string
|
||||
onChange: (value: string) => void
|
||||
name: string
|
||||
orientation?: 'horizontal' | 'vertical'
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function RadioGroup({
|
||||
options,
|
||||
value,
|
||||
onChange,
|
||||
name,
|
||||
orientation = 'vertical',
|
||||
className
|
||||
}: RadioGroupProps) {
|
||||
return (
|
||||
<div
|
||||
role="radiogroup"
|
||||
className={cn(
|
||||
'flex gap-3',
|
||||
orientation === 'vertical' ? 'flex-col' : 'flex-row flex-wrap',
|
||||
className
|
||||
)}
|
||||
>
|
||||
{options.map((option) => (
|
||||
<label
|
||||
key={option.value}
|
||||
className={cn(
|
||||
'flex items-center gap-2 cursor-pointer',
|
||||
option.disabled && 'opacity-50 cursor-not-allowed'
|
||||
)}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name={name}
|
||||
value={option.value}
|
||||
checked={value === option.value}
|
||||
onChange={(e) => !option.disabled && onChange(e.target.value)}
|
||||
disabled={option.disabled}
|
||||
className="sr-only"
|
||||
/>
|
||||
<span
|
||||
className={cn(
|
||||
'w-4 h-4 rounded-full border-2 flex items-center justify-center transition-colors',
|
||||
value === option.value
|
||||
? 'border-primary bg-primary'
|
||||
: 'border-input bg-background'
|
||||
)}
|
||||
>
|
||||
{value === option.value && (
|
||||
<span className="w-2 h-2 rounded-full bg-primary-foreground" />
|
||||
)}
|
||||
</span>
|
||||
<span className="text-sm font-medium">{option.label}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import { Slider } from '@/components/ui/slider'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface RangeSliderProps {
|
||||
value: [number, number]
|
||||
onChange: (value: [number, number]) => void
|
||||
min?: number
|
||||
max?: number
|
||||
step?: number
|
||||
label?: string
|
||||
showValue?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function RangeSlider({
|
||||
value,
|
||||
onChange,
|
||||
min = 0,
|
||||
max = 100,
|
||||
step = 1,
|
||||
label,
|
||||
showValue = true,
|
||||
className,
|
||||
}: RangeSliderProps) {
|
||||
return (
|
||||
<div className={cn('space-y-2', className)}>
|
||||
{(label || showValue) && (
|
||||
<div className="flex items-center justify-between">
|
||||
{label && <span className="text-sm font-medium">{label}</span>}
|
||||
{showValue && (
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{value[0]} - {value[1]}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<Slider
|
||||
value={value}
|
||||
onValueChange={onChange as any}
|
||||
min={min}
|
||||
max={max}
|
||||
step={step}
|
||||
minStepsBetweenThumbs={1}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
import { Star } from '@phosphor-icons/react'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface RatingProps {
|
||||
value: number
|
||||
onChange?: (value: number) => void
|
||||
max?: number
|
||||
size?: 'sm' | 'md' | 'lg'
|
||||
readonly?: boolean
|
||||
showValue?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function Rating({
|
||||
value,
|
||||
onChange,
|
||||
max = 5,
|
||||
size = 'md',
|
||||
readonly = false,
|
||||
showValue = false,
|
||||
className
|
||||
}: RatingProps) {
|
||||
const sizeStyles = {
|
||||
sm: 16,
|
||||
md: 20,
|
||||
lg: 24,
|
||||
}
|
||||
|
||||
const iconSize = sizeStyles[size]
|
||||
|
||||
return (
|
||||
<div className={cn('flex items-center gap-2', className)}>
|
||||
<div className="flex items-center gap-0.5">
|
||||
{Array.from({ length: max }, (_, index) => {
|
||||
const starValue = index + 1
|
||||
const isFilled = starValue <= value
|
||||
const isHalfFilled = starValue - 0.5 === value
|
||||
|
||||
return (
|
||||
<button
|
||||
key={index}
|
||||
type="button"
|
||||
onClick={() => !readonly && onChange?.(starValue)}
|
||||
disabled={readonly}
|
||||
className={cn(
|
||||
'transition-colors',
|
||||
!readonly && 'cursor-pointer hover:scale-110',
|
||||
readonly && 'cursor-default'
|
||||
)}
|
||||
aria-label={`Rate ${starValue} out of ${max}`}
|
||||
>
|
||||
<Star
|
||||
size={iconSize}
|
||||
weight={isFilled ? 'fill' : 'regular'}
|
||||
className={cn(
|
||||
'transition-colors',
|
||||
isFilled ? 'text-accent fill-accent' : 'text-muted'
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
{showValue && (
|
||||
<span className="text-sm font-medium text-muted-foreground">
|
||||
{value.toFixed(1)} / {max}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import { ReactNode } from 'react'
|
||||
import { cn } from '@/lib/utils'
|
||||
import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'
|
||||
|
||||
interface ScrollAreaProps {
|
||||
children: ReactNode
|
||||
className?: string
|
||||
maxHeight?: string | number
|
||||
}
|
||||
|
||||
export function ScrollArea({ children, className, maxHeight }: ScrollAreaProps) {
|
||||
return (
|
||||
<ScrollAreaPrimitive.Root
|
||||
className={cn('relative overflow-hidden', className)}
|
||||
style={{ maxHeight: typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight }}
|
||||
>
|
||||
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded">
|
||||
{children}
|
||||
</ScrollAreaPrimitive.Viewport>
|
||||
<ScrollAreaPrimitive.Scrollbar
|
||||
className="flex touch-none select-none transition-colors p-0.5 bg-transparent hover:bg-muted"
|
||||
orientation="vertical"
|
||||
>
|
||||
<ScrollAreaPrimitive.Thumb className="flex-1 bg-border rounded-full relative" />
|
||||
</ScrollAreaPrimitive.Scrollbar>
|
||||
<ScrollAreaPrimitive.Scrollbar
|
||||
className="flex touch-none select-none transition-colors p-0.5 bg-transparent hover:bg-muted"
|
||||
orientation="horizontal"
|
||||
>
|
||||
<ScrollAreaPrimitive.Thumb className="flex-1 bg-border rounded-full relative" />
|
||||
</ScrollAreaPrimitive.Scrollbar>
|
||||
<ScrollAreaPrimitive.Corner />
|
||||
</ScrollAreaPrimitive.Root>
|
||||
)
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import { MagnifyingGlass, X } from '@phosphor-icons/react'
|
||||
import { Input } from '@/lib/json-ui/json-components'
|
||||
|
||||
interface BasicSearchInputProps {
|
||||
value: string
|
||||
onChange: (value: string) => void
|
||||
placeholder?: string
|
||||
onClear?: () => void
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function BasicSearchInput({
|
||||
value,
|
||||
onChange,
|
||||
placeholder = 'Search...',
|
||||
onClear,
|
||||
className,
|
||||
}: BasicSearchInputProps) {
|
||||
const handleClear = () => {
|
||||
onChange('')
|
||||
onClear?.()
|
||||
}
|
||||
|
||||
return (
|
||||
<Input
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
placeholder={placeholder}
|
||||
className={className}
|
||||
leftIcon={<MagnifyingGlass size={18} />}
|
||||
rightIcon={
|
||||
value && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleClear}
|
||||
className="text-muted-foreground hover:text-foreground transition-colors"
|
||||
aria-label="Clear search"
|
||||
>
|
||||
<X size={18} />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Database, Check, X } from '@phosphor-icons/react'
|
||||
import seedDataConfig from '@/config/seed-data.json'
|
||||
|
||||
export function SeedDataStatus() {
|
||||
const dataKeys = Object.keys(seedDataConfig)
|
||||
|
||||
const getDataCount = (key: string): number => {
|
||||
const data = seedDataConfig[key as keyof typeof seedDataConfig]
|
||||
return Array.isArray(data) ? data.length : 0
|
||||
}
|
||||
|
||||
const getLabelForKey = (key: string): string => {
|
||||
const labels: Record<string, string> = {
|
||||
'project-files': 'Files',
|
||||
'project-models': 'Models',
|
||||
'project-components': 'Components',
|
||||
'project-workflows': 'Workflows',
|
||||
'project-lambdas': 'Lambdas',
|
||||
'project-playwright-tests': 'Playwright Tests',
|
||||
'project-storybook-stories': 'Storybook Stories',
|
||||
'project-unit-tests': 'Unit Tests',
|
||||
'project-component-trees': 'Component Trees',
|
||||
}
|
||||
return labels[key] || key
|
||||
}
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2 text-lg">
|
||||
<Database size={20} weight="duotone" />
|
||||
Seed Data Available
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Pre-configured data ready to load from database
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-3">
|
||||
{dataKeys.map((key) => {
|
||||
const count = getDataCount(key)
|
||||
return (
|
||||
<div
|
||||
key={key}
|
||||
className="flex items-center justify-between p-3 rounded-lg border border-border bg-muted/50"
|
||||
>
|
||||
<span className="text-sm font-medium">{getLabelForKey(key)}</span>
|
||||
<Badge variant="secondary" className="ml-2">
|
||||
{count}
|
||||
</Badge>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface SelectOption {
|
||||
value: string
|
||||
label: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
interface SelectProps {
|
||||
value: string
|
||||
onChange: (value: string) => void
|
||||
options: SelectOption[]
|
||||
label?: string
|
||||
placeholder?: string
|
||||
error?: boolean
|
||||
helperText?: string
|
||||
disabled?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function Select({
|
||||
value,
|
||||
onChange,
|
||||
options,
|
||||
label,
|
||||
placeholder = 'Select an option',
|
||||
error,
|
||||
helperText,
|
||||
disabled,
|
||||
className,
|
||||
}: SelectProps) {
|
||||
return (
|
||||
<div className={cn('w-full', className)}>
|
||||
{label && (
|
||||
<label className="block text-sm font-medium mb-1.5 text-foreground">
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
<select
|
||||
value={value}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
disabled={disabled}
|
||||
className={cn(
|
||||
'flex h-10 w-full rounded-md border bg-background px-3 py-2 text-sm',
|
||||
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
||||
'disabled:cursor-not-allowed disabled:opacity-50',
|
||||
'transition-colors',
|
||||
error ? 'border-destructive focus-visible:ring-destructive' : 'border-input'
|
||||
)}
|
||||
>
|
||||
{placeholder && (
|
||||
<option value="" disabled>
|
||||
{placeholder}
|
||||
</option>
|
||||
)}
|
||||
{options.map((option) => (
|
||||
<option key={option.value} value={option.value} disabled={option.disabled}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{helperText && (
|
||||
<p className={cn('text-xs mt-1.5', error ? 'text-destructive' : 'text-muted-foreground')}>
|
||||
{helperText}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Sparkle as SparkleIcon } from '@phosphor-icons/react'
|
||||
|
||||
interface SparkleProps {
|
||||
variant?: 'default' | 'primary' | 'accent' | 'gold'
|
||||
size?: number
|
||||
animate?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function Sparkle({
|
||||
variant = 'default',
|
||||
size = 16,
|
||||
animate = true,
|
||||
className,
|
||||
}: SparkleProps) {
|
||||
const variantClasses = {
|
||||
default: 'text-foreground',
|
||||
primary: 'text-primary',
|
||||
accent: 'text-accent',
|
||||
gold: 'text-yellow-500',
|
||||
}
|
||||
|
||||
return (
|
||||
<SparkleIcon
|
||||
size={size}
|
||||
weight="fill"
|
||||
className={cn(
|
||||
variantClasses[variant],
|
||||
animate && 'animate-pulse',
|
||||
className
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,53 +1,17 @@
|
||||
// Auto-generated exports - DO NOT EDIT MANUALLY
|
||||
// JSON-based atom imports
|
||||
export { ActionButton, ActionCard, ActionIcon, Alert, AppLogo, Avatar, AvatarGroup, Badge, BindingIndicator, Breadcrumb, Button, ButtonGroup, Calendar, Card, Checkbox, Chip, CircularProgress, Code, CommandPalette, CompletionCard, ComponentPaletteItem, ConfirmButton, ContextMenu, DataSourceBadge, DataTable, DatePicker, DetailRow, Divider, Drawer, EmptyMessage, ErrorBadge, FileIcon, Form, GlowCard, Heading, HelperText, HoverCard, Menu, Separator, Skeleton, Slider, Spinner, StatusIcon, StepIndicator, Stepper, Switch, Table, Tabs, Tag, TextArea, TextGradient, TextHighlight, Timeline, Timestamp, Toggle, Tooltip } from '@/lib/json-ui/json-components'
|
||||
|
||||
export { ActionButton } from './ActionButton'
|
||||
export { ActionCard } from './ActionCard'
|
||||
export { ActionIcon } from './ActionIcon'
|
||||
export { Alert } from './Alert'
|
||||
export { AppLogo } from './AppLogo'
|
||||
export { Avatar } from './Avatar'
|
||||
export { AvatarGroup } from './AvatarGroup'
|
||||
export { Badge } from './Badge'
|
||||
export { BindingIndicator } from './BindingIndicator'
|
||||
export { BreadcrumbNav as Breadcrumb, BreadcrumbNav } from './Breadcrumb'
|
||||
export { Button } from './Button'
|
||||
export { ButtonGroup } from './ButtonGroup'
|
||||
export { Calendar } from './Calendar'
|
||||
export { Card } from './Card'
|
||||
export { Checkbox } from './Checkbox'
|
||||
export { Chip } from './Chip'
|
||||
export { CircularProgress } from './CircularProgress'
|
||||
export { Code } from './Code'
|
||||
export { ColorSwatch } from './ColorSwatch'
|
||||
export { CommandPalette } from './CommandPalette'
|
||||
export { CompletionCard } from './CompletionCard'
|
||||
export { ConfirmButton } from './ConfirmButton'
|
||||
export { ComponentTreeNode } from './ComponentTreeNode'
|
||||
export { Container } from './Container'
|
||||
export { ContextMenu } from './ContextMenu'
|
||||
export type { ContextMenuItemType } from './ContextMenu'
|
||||
export { CountBadge } from './CountBadge'
|
||||
export { DataList } from './DataList'
|
||||
export { DataSourceBadge } from './DataSourceBadge'
|
||||
export { DataTable } from './DataTable'
|
||||
export type { Column } from './DataTable'
|
||||
export { DatePicker } from './DatePicker'
|
||||
export { DetailRow } from './DetailRow'
|
||||
export { Divider } from './Divider'
|
||||
export { Dot } from './Dot'
|
||||
export { Drawer } from './Drawer'
|
||||
export { EmptyMessage } from './EmptyMessage'
|
||||
export { EmptyState } from './EmptyState'
|
||||
export { EmptyStateIcon } from './EmptyStateIcon'
|
||||
export { ErrorBadge } from './ErrorBadge'
|
||||
export { FileIcon } from './FileIcon'
|
||||
export { Flex } from './Flex'
|
||||
export { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from './Form'
|
||||
export { GlowCard } from './GlowCard'
|
||||
export { Grid } from './Grid'
|
||||
export { Heading } from './Heading'
|
||||
export { HelperText } from './HelperText'
|
||||
export { HoverCard } from './HoverCard'
|
||||
export { IconButton } from './IconButton'
|
||||
export { IconText } from './IconText'
|
||||
export { IconWrapper } from './IconWrapper'
|
||||
@@ -55,42 +19,13 @@ export { InfoPanel } from './InfoPanel'
|
||||
export { Kbd } from './Kbd'
|
||||
export { Link } from './Link'
|
||||
export { MetricCard } from './MetricCard'
|
||||
export { BasicPageHeader, BasicPageHeader as PageHeader } from './PageHeader'
|
||||
export { PanelHeader } from './PanelHeader'
|
||||
export { ProgressBar } from './ProgressBar'
|
||||
export { Pulse } from './Pulse'
|
||||
export { QuickActionButton } from './QuickActionButton'
|
||||
export { RadioGroup as Radio, RadioGroup } from './Radio'
|
||||
export { RangeSlider } from './RangeSlider'
|
||||
export { Rating } from './Rating'
|
||||
export { PropertyEditorField } from './PropertyEditorField'
|
||||
export { ResponsiveGrid } from './ResponsiveGrid'
|
||||
export { ScrollArea } from './ScrollArea'
|
||||
export { BasicSearchInput as SearchInput, BasicSearchInput } from './SearchInput'
|
||||
export { Section } from './Section'
|
||||
export { SeedDataStatus } from './SeedDataStatus'
|
||||
export { Select } from './Select'
|
||||
export { Separator } from './Separator'
|
||||
export { Skeleton } from './Skeleton'
|
||||
export { Slider } from './Slider'
|
||||
export { Spacer } from './Spacer'
|
||||
export { Sparkle } from './Sparkle'
|
||||
export { Spinner } from './Spinner'
|
||||
export { Stack } from './Stack'
|
||||
export { StatCard } from './StatCard'
|
||||
export { StatusBadge } from './StatusBadge'
|
||||
export { StatusIcon } from './StatusIcon'
|
||||
export { StepIndicator } from './StepIndicator'
|
||||
export { Stepper } from './Stepper'
|
||||
export { Switch } from './Switch'
|
||||
export { Table } from './Table'
|
||||
export { Tabs } from './Tabs'
|
||||
export { Tag } from './Tag'
|
||||
export { Text } from './Text'
|
||||
export { TextArea } from './TextArea'
|
||||
export { TextGradient } from './TextGradient'
|
||||
export { TextHighlight } from './TextHighlight'
|
||||
export { Timeline } from './Timeline'
|
||||
export { Timestamp } from './Timestamp'
|
||||
export { Toggle } from './Toggle'
|
||||
export { Tooltip } from './Tooltip'
|
||||
export { TreeIcon } from './TreeIcon'
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Stack, Container, TabIcon } from '@/components/atoms'
|
||||
import { Stack, Container } from '@/components/atoms'
|
||||
import { TabIcon } from '@/lib/json-ui/json-components'
|
||||
import { tabInfo } from '@/lib/navigation-config'
|
||||
|
||||
interface PageHeaderProps {
|
||||
|
||||
@@ -291,6 +291,9 @@ export const Dialog = createJsonComponent<DialogProps>(dialogDef)
|
||||
export const Drawer = createJsonComponent<DrawerProps>(drawerDef)
|
||||
export const Divider = createJsonComponent<DividerProps>(dividerDef)
|
||||
export const DropdownMenu = createJsonComponent<DropdownMenuProps>(dropdownMenuDef)
|
||||
export const EmptyMessage = createJsonComponent<EmptyMessageProps>(emptyMessageDef)
|
||||
export const ErrorBadge = createJsonComponent<ErrorBadgeProps>(errorBadgeDef)
|
||||
export const FileIcon = createJsonComponent<FileIconProps>(fileIconDef)
|
||||
export const Form = createJsonComponent<FormProps>(formDef)
|
||||
export const FormField = createJsonComponent<FormFieldProps>(formFieldDef)
|
||||
export const GlowCard = createJsonComponent<GlowCardProps>(glowCardDef)
|
||||
|
||||
Reference in New Issue
Block a user