feat: enhance CssClassBuilder with improved selected classes display and preview functionality

This commit is contained in:
2025-12-25 18:53:00 +00:00
parent a663e266e9
commit 1ea26ec556
4 changed files with 65 additions and 70 deletions

View File

@@ -159,9 +159,17 @@ export function CssClassBuilder({ open, onClose, initialValue = '', onSave }: Cs
)}
</div>
{selectedClasses.length > 0 && (
<div className="p-4 border rounded-lg bg-muted/50">
<Label className="text-xs uppercase tracking-wider mb-2 block">Selected Classes</Label>
{selectedClasses.length > 0 ? (
<div className="p-4 border rounded-lg bg-muted/50 space-y-3">
<div className="flex items-center justify-between">
<Label className="text-xs uppercase tracking-wider">Selected Classes</Label>
<div className="flex items-center gap-2">
<span className="text-xs text-muted-foreground">{selectedClasses.length} selected</span>
<Button size="sm" variant="ghost" onClick={clearSelectedClasses}>
Clear
</Button>
</div>
</div>
<div className="flex flex-wrap gap-2">
{selectedClasses.map(cls => (
<Badge key={cls} variant="secondary" className="gap-2">
@@ -175,15 +183,46 @@ export function CssClassBuilder({ open, onClose, initialValue = '', onSave }: Cs
</Badge>
))}
</div>
<div className="mt-3 p-2 bg-background rounded border font-mono text-sm">
<div className="rounded border bg-background p-2 font-mono text-sm">
{selectedClasses.join(' ')}
</div>
</div>
) : (
<div className="p-4 border rounded-lg bg-muted/30 text-sm text-muted-foreground">
No classes selected yet. Choose classes to preview and apply.
</div>
)}
<Tabs defaultValue={filteredCategories[0]?.name || 'custom'} className="flex-1">
<ScrollArea className="max-h-[50px]">
<TabsList className="w-full">
<div className="p-4 border rounded-lg bg-muted/30 space-y-2">
<Label className="text-xs uppercase tracking-wider">Preview</Label>
<div className="rounded-md border border-dashed bg-background p-3">
<div className={`rounded-md p-4 transition-all ${selectedClasses.join(' ')}`}>
<div className="text-sm font-semibold">Preview element</div>
<div className="text-xs text-muted-foreground">
This sample updates as you add or remove classes.
</div>
<div className="mt-3 inline-flex items-center rounded-md border px-3 py-1 text-xs">
Sample button
</div>
</div>
</div>
</div>
{filteredCategories.length === 0 && categories.length === 0 && (
<div className="rounded-lg border bg-muted/30 p-4 text-sm text-muted-foreground">
No CSS categories available yet. Add some in the CSS Classes tab.
</div>
)}
{filteredCategories.length === 0 && categories.length > 0 && normalizedSearch && (
<div className="rounded-lg border bg-muted/30 p-4 text-sm text-muted-foreground">
No classes match &quot;{searchQuery}&quot;.
</div>
)}
<Tabs value={activeTab} onValueChange={setActiveTab} className="flex-1">
<div className="overflow-x-auto">
<TabsList className="w-max">
{filteredCategories.map(category => (
<TabsTrigger key={category.name} value={category.name}>
{category.name}
@@ -191,7 +230,7 @@ export function CssClassBuilder({ open, onClose, initialValue = '', onSave }: Cs
))}
<TabsTrigger value="custom">Custom</TabsTrigger>
</TabsList>
</ScrollArea>
</div>
{filteredCategories.map(category => (
<TabsContent key={category.name} value={category.name}>

View File

@@ -1,63 +1,5 @@
import { componentCatalog } from './component-catalog'
import type { ComponentDefinition } from './builder-types'
export type { ComponentTypeDefinition } from './component-registry/types'
export interface ComponentTypeDefinition extends ComponentDefinition {
renderingLogic?: {
type: 'shadcn' | 'declarative' | 'custom'
componentName?: string
customRenderer?: string
}
}
export class ComponentRegistry {
private components: Map<string, ComponentTypeDefinition> = new Map()
constructor() {
this.loadFromCatalog()
}
private loadFromCatalog(): void {
componentCatalog.forEach(comp => {
this.registerComponent(comp as ComponentTypeDefinition)
})
}
registerComponent(component: ComponentTypeDefinition): void {
this.components.set(component.type, component)
}
registerComponents(components: ComponentTypeDefinition[]): void {
components.forEach(comp => this.registerComponent(comp))
}
getComponent(type: string): ComponentTypeDefinition | undefined {
return this.components.get(type)
}
getAllComponents(): ComponentTypeDefinition[] {
return Array.from(this.components.values())
}
getComponentsByCategory(category: string): ComponentTypeDefinition[] {
return Array.from(this.components.values()).filter(
comp => comp.category === category
)
}
hasComponent(type: string): boolean {
return this.components.has(type)
}
}
let registryInstance: ComponentRegistry | null = null
export function getComponentRegistry(): ComponentRegistry {
if (!registryInstance) {
registryInstance = new ComponentRegistry()
}
return registryInstance
}
export async function initializeComponentRegistry(): Promise<void> {
getComponentRegistry()
}
export { ComponentRegistry } from './component-registry/registry-class'
export { getComponentRegistry } from './component-registry/get-component-registry'
export { initializeComponentRegistry } from './component-registry/initialize-component-registry'

View File

@@ -0,0 +1,9 @@
import { ComponentRegistry } from './registry-class'
import { componentRegistryState } from './registry-singleton'
export function getComponentRegistry(): ComponentRegistry {
if (!componentRegistryState.instance) {
componentRegistryState.instance = new ComponentRegistry()
}
return componentRegistryState.instance
}

View File

@@ -0,0 +1,5 @@
import { getComponentRegistry } from './get-component-registry'
export async function initializeComponentRegistry(): Promise<void> {
getComponentRegistry()
}