Barazo default frontend barazo.forum
at main 86 lines 2.7 kB view raw
1/** 2 * PluginSettingsModal - Modal dialog for editing a plugin's settings. 3 * Dynamically renders fields from the plugin's settingsSchema. 4 * @see specs/prd-web.md Section M13 5 */ 6 7'use client' 8 9import { useState } from 'react' 10import { X } from '@phosphor-icons/react' 11import { SaveButton } from '@/components/admin/save-button' 12import { SettingsField } from '@/components/admin/plugins/settings-field' 13import type { Plugin } from '@/lib/api/types' 14import type { SaveStatus } from '@/hooks/use-save-state' 15 16interface PluginSettingsModalProps { 17 plugin: Plugin 18 onClose: () => void 19 onSave: (settings: Record<string, boolean | string | number>) => void 20 saveStatus: SaveStatus 21} 22 23export function PluginSettingsModal({ 24 plugin, 25 onClose, 26 onSave, 27 saveStatus, 28}: PluginSettingsModalProps) { 29 const [values, setValues] = useState<Record<string, boolean | string | number>>(() => ({ 30 ...plugin.settings, 31 })) 32 33 const handleChange = (key: string, value: boolean | string | number) => { 34 setValues((prev) => ({ ...prev, [key]: value })) 35 } 36 37 return ( 38 <div 39 className="fixed inset-0 z-50 flex items-center justify-center bg-black/50" 40 role="dialog" 41 aria-modal="true" 42 aria-label={`${plugin.displayName} settings`} 43 > 44 <div className="w-full max-w-md rounded-lg border border-border bg-card p-6 shadow-lg"> 45 <div className="mb-4 flex items-center justify-between"> 46 <h2 className="text-lg font-semibold text-foreground">{plugin.displayName} Settings</h2> 47 <button 48 type="button" 49 onClick={onClose} 50 className="rounded-md p-1 text-muted-foreground transition-colors hover:text-foreground" 51 aria-label="Close settings" 52 > 53 <X size={18} aria-hidden="true" /> 54 </button> 55 </div> 56 57 <div className="space-y-4"> 58 {Object.entries(plugin.settingsSchema ?? {}).map(([key, schema]) => ( 59 <SettingsField 60 key={key} 61 fieldKey={key} 62 schema={schema} 63 value={values[key] ?? schema.default} 64 onChange={(val) => handleChange(key, val)} 65 /> 66 ))} 67 68 <div className="flex justify-end gap-2 pt-2"> 69 <button 70 type="button" 71 onClick={onClose} 72 className="rounded-md border border-border px-3 py-1.5 text-sm text-foreground transition-colors hover:bg-muted" 73 > 74 Cancel 75 </button> 76 <SaveButton 77 status={saveStatus} 78 onClick={() => onSave(values)} 79 className="px-3 py-1.5" 80 /> 81 </div> 82 </div> 83 </div> 84 </div> 85 ) 86}