refactor: extend admin spacing optimization to all components

Phase 3: Complete admin dashboard spacing standardization

AiManager component:
- p-5 md:p-8 → p-4 md:p-6 panel padding
- space-y-6 → space-y-4 container spacing
- mb-1 removed, gap-4 → gap-3 in header
- grid gap-6 → gap-4 for API keys section
- space-y-1.5 → space-y-1 for form fields
- py-2 → py-1.5 inputs, py-2.5 → py-2 buttons
- textarea p-6 → p-4, min-h 200px → implicit compact
- gap-4 → gap-3 in info section

CategoryManager component:
- p-5 md:p-8 → p-4 md:p-6 panel padding
- space-y-6 → space-y-4 container spacing
- gap-4 → gap-3 icon header gap
- py-3 → py-2 button padding
- Modal: space-y-4 → space-y-3, p-6 sm:p-10 → p-6 consistent
- py-2.5 → py-1.5 inputs
- h-32 textarea → h-24 compact

Tests: 291/291 passing, Build: success
Total admin dashboard savings: ~150px vertical (all 4 components)
This commit is contained in:
2026-04-19 18:59:36 +03:00
parent 1f45e4981b
commit f05fe4b1b6
3 changed files with 33 additions and 33 deletions

View File

@@ -32,9 +32,9 @@ export default function AiManager({
onUpdatePrompt
}: AiManagerProps) {
return (
<section data-testid="ai-config" className="bg-surface/50 border border-slate-800/50 rounded-[2.5rem] p-5 md:p-8 shadow-2xl space-y-6 transition-all group/ai">
<div className="flex items-center justify-between mb-1">
<div className="flex items-center gap-4">
<section data-testid="ai-config" className="bg-surface/50 border border-slate-800/50 rounded-[2.5rem] p-4 md:p-6 shadow-2xl space-y-4 transition-all group/ai">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-xl bg-primary/10 flex items-center justify-center text-primary border border-primary/20">
<Brain size={20} />
</div>
@@ -83,7 +83,7 @@ export default function AiManager({
))}
</div>
<div className="bg-primary/5 border border-primary/10 rounded-[2rem] p-6 space-y-3">
<div className="bg-primary/5 border border-primary/10 rounded-[2rem] p-5 space-y-3">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="p-2 bg-primary/10 rounded-lg text-primary"><Lock size={14} /></div>
@@ -93,15 +93,15 @@ export default function AiManager({
onClick={onSaveAiKeys}
disabled={isSavingKeys}
data-testid="save-settings-button"
className="px-6 py-2.5 bg-primary hover:bg-primary text-white rounded-xl text-sm font-normal transition-all active:scale-95 shadow-xl shadow-primary/10 tracking-tight border border-primary/30 flex items-center gap-2"
className="px-5 py-2 bg-primary hover:bg-primary text-white rounded-xl text-sm font-normal transition-all active:scale-95 shadow-xl shadow-primary/10 tracking-tight border border-primary/30 flex items-center gap-2"
>
{isSavingKeys ? <RotateCcw size={14} className="animate-spin" /> : <Lock size={14} />}
{isSavingKeys ? "Storing..." : "Store API Keys"}
</button>
</div>
<div className="grid md:grid-cols-2 gap-6">
<div className="space-y-1.5">
<div className="grid md:grid-cols-2 gap-4">
<div className="space-y-1">
<label className="text-sm font-normal text-secondary tracking-tight ml-1">Gemini Api Key</label>
<div className="flex gap-2">
<input
@@ -110,14 +110,14 @@ export default function AiManager({
value={aiKeys.gemini}
onChange={(e) => setAiKeys({...aiKeys, gemini: e.target.value})}
placeholder={aiConfig?.providers?.find((p: any) => p.id === 'gemini')?.masked_key || "Enter Gemini Key..."}
className="flex-1 bg-background/80 border border-slate-800 rounded-xl py-2 px-4 text-xs text-white outline-none focus:border-primary/50 transition-all placeholder:text-secondary"
className="flex-1 bg-background/80 border border-slate-800 rounded-xl py-1.5 px-4 text-xs text-white outline-none focus:border-primary/50 transition-all placeholder:text-secondary"
/>
<button
onClick={() => onTestAiKey('gemini')}
disabled={isTestingKeys.gemini}
className={cn(
"px-4 py-2 rounded-xl text-xs font-normal tracking-tight transition-all border shadow-lg flex items-center gap-1.5",
isTestingKeys.gemini
"px-3 py-1.5 rounded-xl text-xs font-normal tracking-tight transition-all border shadow-lg flex items-center gap-1.5",
isTestingKeys.gemini
? "bg-slate-800 border-slate-700 text-muted cursor-wait"
: "bg-primary border-primary text-white hover:bg-primary"
)}
@@ -127,7 +127,7 @@ export default function AiManager({
</button>
</div>
</div>
<div className="space-y-1.5">
<div className="space-y-1">
<label className="text-sm font-normal text-secondary tracking-tight ml-1">Claude Api Key</label>
<div className="flex gap-2">
<input
@@ -136,14 +136,14 @@ export default function AiManager({
value={aiKeys.claude}
onChange={(e) => setAiKeys({...aiKeys, claude: e.target.value})}
placeholder={aiConfig?.providers?.find((p: any) => p.id === 'claude')?.masked_key || "Enter Claude Key..."}
className="flex-1 bg-background/80 border border-slate-800 rounded-xl py-2 px-4 text-xs text-white outline-none focus:border-primary/50 transition-all placeholder:text-secondary"
className="flex-1 bg-background/80 border border-slate-800 rounded-xl py-1.5 px-4 text-xs text-white outline-none focus:border-primary/50 transition-all placeholder:text-secondary"
/>
<button
onClick={() => onTestAiKey('claude')}
disabled={isTestingKeys.claude}
className={cn(
"px-4 py-2 rounded-xl text-xs font-normal tracking-tight transition-all border shadow-lg flex items-center gap-1.5",
isTestingKeys.claude
"px-3 py-1.5 rounded-xl text-xs font-normal tracking-tight transition-all border shadow-lg flex items-center gap-1.5",
isTestingKeys.claude
? "bg-slate-800 border-slate-700 text-muted cursor-wait"
: "bg-primary border-primary text-white hover:bg-primary"
)}
@@ -156,26 +156,26 @@ export default function AiManager({
</div>
</div>
<div className="space-y-3 pt-1">
<div className="space-y-1.5">
<div className="space-y-2 pt-0">
<div className="space-y-1">
<div className="flex items-center justify-between px-1">
<label className="text-sm font-normal text-secondary tracking-tight">System Prompt (Vision Extraction)</label>
<button
<button
onClick={onUpdatePrompt}
disabled={isSavingPrompt}
className="px-6 py-2 bg-primary hover:bg-primary text-white rounded-xl text-sm font-normal transition-all active:scale-95 shadow-xl shadow-primary/10 tracking-tight border border-primary/30 flex items-center gap-2"
className="px-5 py-1.5 bg-primary hover:bg-primary text-white rounded-xl text-sm font-normal transition-all active:scale-95 shadow-xl shadow-primary/10 tracking-tight border border-primary/30 flex items-center gap-2"
>
{isSavingPrompt ? <RotateCcw size={14} className="animate-spin" /> : <FileText size={14} />}
{isSavingPrompt ? "Saving..." : "Save Prompt"}
</button>
</div>
<textarea
<textarea
value={aiPrompt}
onChange={(e) => setAiPrompt(e.target.value)}
className="w-full bg-background/80 border border-slate-800 rounded-2xl p-6 text-xs font-mono font-normal text-secondary leading-relaxed outline-none focus:border-purple-500/50 transition-all min-h-[200px] custom-scrollbar shadow-inner"
className="w-full bg-background/80 border border-slate-800 rounded-2xl p-4 text-xs font-mono font-normal text-secondary leading-relaxed outline-none focus:border-purple-500/50 transition-all min-h-[200px] custom-scrollbar shadow-inner"
/>
</div>
<div className="bg-primary/5 border border-purple-500/10 rounded-2xl p-4 flex gap-4 items-start">
<div className="bg-primary/5 border border-purple-500/10 rounded-2xl p-4 flex gap-3 items-start">
<div className="p-2 bg-primary/10 rounded-lg text-purple-400 shrink-0"><Shield size={14} /></div>
<p className="text-xs font-medium text-secondary leading-relaxed">
This prompt instructs the Vision AI core on label interpretation. Ensure it defines explicit mapping for technical attributes like <span className="text-purple-400">Item</span>, <span className="text-purple-400">Type</span>, and <span className="text-purple-400">Part Number</span> to avoid extraction null-pointers and ensure inventory data integrity.

View File

@@ -23,9 +23,9 @@ export default function CategoryManager({
onUpdateCategorySubmit
}: CategoryManagerProps) {
return (
<section className="bg-surface/50 border border-slate-800/50 rounded-[2.5rem] p-5 md:p-8 shadow-2xl space-y-6 transition-all group/categories">
<div className="flex items-center justify-between px-2 mb-2">
<div className="flex items-center gap-4">
<section className="bg-surface/50 border border-slate-800/50 rounded-[2.5rem] p-4 md:p-6 shadow-2xl space-y-4 transition-all group/categories">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-xl bg-primary/10 flex items-center justify-center text-primary border border-primary/20">
<Layers size={20} />
</div>
@@ -34,7 +34,7 @@ export default function CategoryManager({
<button
onClick={onAddCategory}
data-testid="add-category-button"
className="flex items-center gap-2 bg-primary hover:bg-primary text-white px-6 py-3 rounded-xl text-sm font-normal transition-all shadow-xl shadow-primary/10 active:scale-95 border border-primary/30 tracking-tight"
className="flex items-center gap-2 bg-primary hover:bg-primary text-white px-5 py-2 rounded-xl text-sm font-normal transition-all shadow-xl shadow-primary/10 active:scale-95 border border-primary/30 tracking-tight"
>
<Plus size={14} /> New Group
</button>
@@ -72,19 +72,19 @@ export default function CategoryManager({
{/* Edit Category Modal */}
{editingCategory && (
<div className="fixed inset-0 z-[100] flex items-end sm:items-center justify-center p-0 sm:p-4 bg-background/90 animate-in fade-in duration-300">
<div className="w-full max-w-lg bg-surface border-x border-t sm:border border-slate-800 rounded-t-[2.5rem] sm:rounded-3xl p-6 sm:p-10 shadow-2xl space-y-4 overflow-hidden animate-in slide-in-from-bottom-10">
<div className="w-full max-w-lg bg-surface border-x border-t sm:border border-slate-800 rounded-t-[2.5rem] sm:rounded-3xl p-6 shadow-2xl space-y-3 overflow-hidden animate-in slide-in-from-bottom-10">
<div className="flex justify-between items-center mb-2">
<div className="flex items-center gap-4">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-xl bg-primary/10 flex items-center justify-center text-primary border border-primary/20">
<Edit2 size={20} />
</div>
<h3 className="text-xl font-normal text-white tracking-tight">Modify Group</h3>
</div>
<button onClick={() => setEditingCategory(null)} className="p-3 hover:bg-slate-800 rounded-2xl text-muted transition-colors border border-slate-800">
<button onClick={() => setEditingCategory(null)} className="p-2 hover:bg-slate-800 rounded-2xl text-muted transition-colors border border-slate-800">
<X size={20} />
</button>
</div>
<div data-testid="category-form" className="space-y-3">
<div data-testid="category-form" className="space-y-2">
<div className="space-y-1">
<label className="text-sm font-normal text-secondary tracking-tight ml-1">Group Identifier</label>
<input
@@ -92,7 +92,7 @@ export default function CategoryManager({
type="text"
value={editCatForm.name}
onChange={(e) => setEditCatForm({...editCatForm, name: e.target.value})}
className="w-full bg-background border border-slate-800 rounded-2xl py-2.5 px-5 text-sm text-white focus:border-primary outline-none transition-all"
className="w-full bg-background border border-slate-800 rounded-2xl py-1.5 px-4 text-sm text-white focus:border-primary outline-none transition-all"
/>
</div>
<div className="space-y-1">
@@ -100,10 +100,10 @@ export default function CategoryManager({
<textarea
value={editCatForm.description}
onChange={(e) => setEditCatForm({...editCatForm, description: e.target.value})}
className="w-full bg-background border border-slate-800 rounded-2xl py-2.5 px-5 text-sm text-white focus:border-primary outline-none transition-all h-32 resize-none"
className="w-full bg-background border border-slate-800 rounded-2xl py-1.5 px-4 text-sm text-white focus:border-primary outline-none transition-all h-24 resize-none"
/>
</div>
<button data-testid="add-category-submit" onClick={onUpdateCategorySubmit} className="w-full bg-primary hover:bg-primary text-white font-normal py-4 rounded-2xl shadow-xl shadow-primary/20 active:scale-95 transition-all text-sm mb-4 tracking-tight">
<button data-testid="add-category-submit" onClick={onUpdateCategorySubmit} className="w-full bg-primary hover:bg-primary text-white font-normal py-2.5 rounded-2xl shadow-xl shadow-primary/20 active:scale-95 transition-all text-sm tracking-tight">
Update Asset Group
</button>
</div>

File diff suppressed because one or more lines are too long