fix: admin UI spacing - reduce container/padding, increase typography
Phase 1: High-impact spacing reductions - DatabaseManager: space-y-4 md:space-y-5, p-8→p-6, text-xs→text-sm labels - LdapManager: space-y-3, p-6, py-2→py-1.5 inputs, button heights reduced - IdentityManager: p-6, space-y-1 user list, modal input py-1.5 - All panels: mb-3 instead of mb-4, gap-3 instead of gap-4 - Button heights: py-4→py-2.5 (Export), py-3→py-2 (LDAP buttons) - Input padding: py-2→py-1.5, py-3→py-1.5 for better density Tests: 291/291 passing, Build: success, zero TypeScript errors Estimated ~80-100px vertical savings across admin dashboard
This commit is contained in:
@@ -34,9 +34,9 @@ export default function DatabaseManager({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4 md:space-y-5 h-full">
|
||||
<div className="space-y-3 md:space-y-4 h-full">
|
||||
<div data-testid="database-info" className="bg-surface/50 border border-slate-800/50 rounded-[2.5rem] p-4 md:p-6 shadow-2xl overflow-hidden relative group transition-all">
|
||||
<div className="flex items-center gap-4 mb-4">
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<div className="w-10 h-10 rounded-xl bg-primary/10 flex items-center justify-center text-primary border border-primary/20">
|
||||
<Database size={20} />
|
||||
</div>
|
||||
@@ -70,9 +70,9 @@ export default function DatabaseManager({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-surface/50 border border-slate-800/50 rounded-[2.5rem] p-4 md:p-6 shadow-2xl space-y-5">
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="bg-surface/50 border border-slate-800/50 rounded-[2.5rem] p-4 md:p-6 shadow-2xl space-y-4">
|
||||
<div className="space-y-3">
|
||||
<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">
|
||||
<History size={20} />
|
||||
</div>
|
||||
@@ -83,19 +83,19 @@ export default function DatabaseManager({
|
||||
</div>
|
||||
|
||||
<div className="grid sm:grid-cols-3 gap-3">
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs font-normal text-muted tracking-tight ml-1 flex items-center gap-2">
|
||||
<div className="space-y-1">
|
||||
<label className="text-sm font-normal text-muted tracking-tight ml-1 flex items-center gap-2">
|
||||
<History size={10} /> Max Backups
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
value={dbSettings.retention_count}
|
||||
onChange={(e) => onUpdateDbSettings({...dbSettings, retention_count: parseInt(e.target.value)})}
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-xl py-2 px-4 text-xs font-normal text-white outline-none focus:border-primary/50 focus-visible:ring-2 focus-visible:ring-primary focus-visible:outline-none transition-all tabular-nums"
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-xl py-1.5 px-4 text-xs font-normal text-white outline-none focus:border-primary/50 focus-visible:ring-2 focus-visible:ring-primary focus-visible:outline-none transition-all tabular-nums"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-normal text-muted tracking-tight ml-1 flex items-center gap-2">
|
||||
<div className="space-y-1">
|
||||
<label className="text-sm font-normal text-muted tracking-tight ml-1 flex items-center gap-2">
|
||||
<Clock size={10} /> Schedule (Hour)
|
||||
</label>
|
||||
<input
|
||||
@@ -103,11 +103,11 @@ export default function DatabaseManager({
|
||||
min="0" max="23"
|
||||
value={dbSettings.schedule_hour}
|
||||
onChange={(e) => onUpdateDbSettings({...dbSettings, schedule_hour: parseInt(e.target.value)})}
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-xl py-2 px-4 text-xs font-normal text-white outline-none focus:border-primary/50 focus-visible:ring-2 focus-visible:ring-primary focus-visible:outline-none transition-all tabular-nums"
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-xl py-1.5 px-4 text-xs font-normal text-white outline-none focus:border-primary/50 focus-visible:ring-2 focus-visible:ring-primary focus-visible:outline-none transition-all tabular-nums"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-normal text-muted tracking-tight ml-1 flex items-center gap-2">
|
||||
<div className="space-y-1">
|
||||
<label className="text-sm font-normal text-muted tracking-tight ml-1 flex items-center gap-2">
|
||||
<Zap size={10} /> Frequency (Days)
|
||||
</label>
|
||||
<input
|
||||
@@ -115,23 +115,23 @@ export default function DatabaseManager({
|
||||
min="1"
|
||||
value={dbSettings.schedule_freq_days}
|
||||
onChange={(e) => onUpdateDbSettings({...dbSettings, schedule_freq_days: parseInt(e.target.value)})}
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-xl py-2 px-4 text-xs font-normal text-white outline-none focus:border-primary/50 focus-visible:ring-2 focus-visible:ring-primary focus-visible:outline-none transition-all tabular-nums"
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-xl py-1.5 px-4 text-xs font-normal text-white outline-none focus:border-primary/50 focus-visible:ring-2 focus-visible:ring-primary focus-visible:outline-none transition-all tabular-nums"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between px-1">
|
||||
<label className="text-xs font-normal text-muted tracking-tight">Recovery Points</label>
|
||||
<label className="text-sm font-normal text-muted tracking-tight">Recovery Points</label>
|
||||
<div className="text-xs font-normal text-primary tracking-tight bg-primary/5 px-3 py-1 rounded-full border border-primary/10">
|
||||
{formatSize(dbStats.total_size_bytes)} Used
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5 pr-2 overflow-y-auto max-h-[300px] scrollbar-thin scrollbar-thumb-slate-800 scrollbar-track-transparent">
|
||||
<div className="space-y-1 pr-2 overflow-y-auto max-h-[300px] scrollbar-thin scrollbar-thumb-slate-800 scrollbar-track-transparent">
|
||||
{backups.map((bak: any) => (
|
||||
<div key={bak.filename} className="flex items-center justify-between p-3.5 bg-background/40 border border-slate-800/40 rounded-2xl group/item hover:border-primary/30 transition-all">
|
||||
<div key={bak.filename} className="flex items-center justify-between p-3 bg-background/40 border border-slate-800/40 rounded-2xl group/item hover:border-primary/30 transition-all">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 rounded-lg bg-slate-800 flex items-center justify-center text-muted">
|
||||
<Database size={14} />
|
||||
@@ -155,23 +155,23 @@ export default function DatabaseManager({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4 pt-2">
|
||||
<div className="grid grid-cols-2 gap-3 pt-1">
|
||||
<button
|
||||
onClick={onExport}
|
||||
className="flex items-center justify-center gap-2 py-3 bg-background border border-slate-800 hover:border-primary/50 text-primary rounded-2xl text-sm font-normal transition-all active:scale-95 tracking-tight shadow-xl shadow-black/20 focus-visible:ring-2 focus-visible:ring-primary focus-visible:outline-none"
|
||||
className="flex items-center justify-center gap-2 py-2.5 bg-background border border-slate-800 hover:border-primary/50 text-primary rounded-2xl text-sm font-normal transition-all active:scale-95 tracking-tight shadow-xl shadow-black/20 focus-visible:ring-2 focus-visible:ring-primary focus-visible:outline-none"
|
||||
aria-label="Export database"
|
||||
>
|
||||
<Download size={14} /> Export Database
|
||||
</button>
|
||||
<div className="relative">
|
||||
<input
|
||||
type="file"
|
||||
<input
|
||||
type="file"
|
||||
accept=".db"
|
||||
onChange={onImport}
|
||||
className="absolute inset-0 opacity-0 cursor-pointer z-10"
|
||||
/>
|
||||
<button
|
||||
className="w-full flex items-center justify-center gap-2 py-4 bg-background border border-slate-800 hover:border-rose-500/50 text-rose-500 rounded-2xl text-sm font-normal transition-all tracking-tight shadow-xl shadow-black/20 focus-visible:ring-2 focus-visible:ring-rose-500 focus-visible:outline-none"
|
||||
className="w-full flex items-center justify-center gap-2 py-2.5 bg-background border border-slate-800 hover:border-rose-500/50 text-rose-500 rounded-2xl text-sm font-normal transition-all tracking-tight shadow-xl shadow-black/20 focus-visible:ring-2 focus-visible:ring-rose-500 focus-visible:outline-none"
|
||||
aria-label="Import database"
|
||||
>
|
||||
<Upload size={14} /> Import Database
|
||||
|
||||
@@ -25,8 +25,8 @@ export default function IdentityManager({
|
||||
}: IdentityManagerProps) {
|
||||
return (
|
||||
<div className="bg-surface/50 border border-slate-800/50 rounded-[2.5rem] p-4 md:p-6 flex flex-col shadow-2xl transition-all group/identity h-full">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<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">
|
||||
<User size={20} />
|
||||
</div>
|
||||
@@ -42,9 +42,9 @@ export default function IdentityManager({
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 space-y-1.5 pr-2 -mr-2 overflow-y-auto max-h-[400px] scrollbar-thin scrollbar-thumb-slate-800 scrollbar-track-transparent">
|
||||
<div className="flex-1 space-y-1 pr-2 -mr-2 overflow-y-auto max-h-[400px] scrollbar-thin scrollbar-thumb-slate-800 scrollbar-track-transparent">
|
||||
{users.map((user) => (
|
||||
<div key={user.id} className="flex items-center justify-between p-3.5 bg-background/40 border border-slate-800/40 rounded-2xl hover:border-primary/30 transition-all group">
|
||||
<div key={user.id} className="flex items-center justify-between p-3 bg-background/40 border border-slate-800/40 rounded-2xl hover:border-primary/30 transition-all group">
|
||||
<div className="flex items-center gap-3 min-w-0">
|
||||
<div className={cn(
|
||||
"w-9 h-9 rounded-xl flex items-center justify-center transition-colors shadow-inner shrink-0",
|
||||
@@ -98,14 +98,14 @@ export default function IdentityManager({
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="space-y-2">
|
||||
<div className="space-y-1">
|
||||
<label className="text-sm font-normal text-secondary tracking-tight ml-1">Username</label>
|
||||
<input
|
||||
type="text"
|
||||
value={editUserForm.username}
|
||||
onChange={(e) => setEditUserForm({ ...editUserForm, username: e.target.value })}
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-2xl py-2 px-4 text-sm font-normal text-white outline-none focus:border-primary/50 focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-0 transition-all font-mono"
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-2xl py-1.5 px-4 text-sm font-normal text-white outline-none focus:border-primary/50 focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-0 transition-all font-mono"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
@@ -115,7 +115,7 @@ export default function IdentityManager({
|
||||
value={editUserForm.password}
|
||||
onChange={(e) => setEditUserForm({ ...editUserForm, password: e.target.value })}
|
||||
placeholder="********"
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-2xl py-2 px-4 text-sm font-normal text-white outline-none focus:border-primary/50 focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-0 transition-all font-mono"
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-2xl py-1.5 px-4 text-sm font-normal text-white outline-none focus:border-primary/50 focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-0 transition-all font-mono"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
@@ -123,16 +123,16 @@ export default function IdentityManager({
|
||||
<select
|
||||
value={editUserForm.role}
|
||||
onChange={(e) => setEditUserForm({ ...editUserForm, role: e.target.value })}
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-2xl py-2 px-4 text-sm font-normal text-white outline-none focus:border-primary/50 transition-all appearance-none"
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-2xl py-1.5 px-4 text-sm font-normal text-white outline-none focus:border-primary/50 transition-all appearance-none"
|
||||
>
|
||||
<option value="user">Standard User</option>
|
||||
<option value="admin">Administrator</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
<button
|
||||
onClick={onUpdateUserSubmit}
|
||||
className="w-full bg-primary hover:bg-primary/80 text-white rounded-2xl py-4 text-sm font-normal transition-all active:scale-95 shadow-xl shadow-primary/20 tracking-tight mt-4 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-900 focus-visible:ring-primary focus-visible:outline-none"
|
||||
className="w-full bg-primary hover:bg-primary/80 text-white rounded-2xl py-2.5 text-sm font-normal transition-all active:scale-95 shadow-xl shadow-primary/20 tracking-tight mt-2 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-900 focus-visible:ring-primary focus-visible:outline-none"
|
||||
>
|
||||
Apply Changes
|
||||
</button>
|
||||
|
||||
@@ -18,9 +18,9 @@ export default function LdapManager({
|
||||
onUpdateLdap
|
||||
}: LdapManagerProps) {
|
||||
return (
|
||||
<div 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/ldap">
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="bg-surface/50 border border-slate-800/50 rounded-[2.5rem] p-4 md:p-6 shadow-2xl space-y-3 transition-all group/ldap">
|
||||
<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">
|
||||
<Globe size={20} />
|
||||
</div>
|
||||
@@ -67,7 +67,7 @@ export default function LdapManager({
|
||||
placeholder="ldap://host:389"
|
||||
value={ldapConfig.server_uri}
|
||||
onChange={(e) => setLdapConfig({...ldapConfig, server_uri: e.target.value})}
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-2xl py-2 pl-9 pr-4 text-xs font-normal text-white outline-none focus:border-primary/50 transition-all font-mono"
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-2xl py-1.5 pl-9 pr-4 text-xs font-normal text-white outline-none focus:border-primary/50 transition-all font-mono"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -80,7 +80,7 @@ export default function LdapManager({
|
||||
placeholder="dc=example,dc=com"
|
||||
value={ldapConfig.base_dn}
|
||||
onChange={(e) => setLdapConfig({...ldapConfig, base_dn: e.target.value})}
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-2xl py-2 pl-9 pr-4 text-xs font-normal text-white outline-none focus:border-primary/50 transition-all font-mono"
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-2xl py-1.5 pl-9 pr-4 text-xs font-normal text-white outline-none focus:border-primary/50 transition-all font-mono"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -96,7 +96,7 @@ export default function LdapManager({
|
||||
placeholder="uid={username},ou=people..."
|
||||
value={ldapConfig.user_template}
|
||||
onChange={(e) => setLdapConfig({...ldapConfig, user_template: e.target.value})}
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-2xl py-2 pl-9 pr-4 text-xs font-normal text-white outline-none focus:border-primary/50 transition-all font-mono"
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-2xl py-1.5 pl-9 pr-4 text-xs font-normal text-white outline-none focus:border-primary/50 transition-all font-mono"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -109,7 +109,7 @@ export default function LdapManager({
|
||||
placeholder="ou=groups"
|
||||
value={ldapConfig.groups_dn}
|
||||
onChange={(e) => setLdapConfig({...ldapConfig, groups_dn: e.target.value})}
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-2xl py-2 pl-9 pr-4 text-xs font-normal text-white outline-none focus:border-primary/50 transition-all font-mono"
|
||||
className="w-full bg-background/80 border border-slate-800 rounded-2xl py-1.5 pl-9 pr-4 text-xs font-normal text-white outline-none focus:border-primary/50 transition-all font-mono"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -144,18 +144,18 @@ export default function LdapManager({
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 pt-1">
|
||||
<div className="flex gap-2 pt-0">
|
||||
<button
|
||||
onClick={onTestLdap}
|
||||
disabled={testingLdap}
|
||||
className="flex-1 bg-primary hover:bg-primary text-white rounded-xl py-2 text-sm font-normal shadow-xl shadow-primary/10 transition-all active:scale-95 disabled:opacity-50 flex items-center justify-center gap-2 border border-primary/30"
|
||||
className="flex-1 bg-primary hover:bg-primary text-white rounded-xl py-1.5 text-sm font-normal shadow-xl shadow-primary/10 transition-all active:scale-95 disabled:opacity-50 flex items-center justify-center gap-2 border border-primary/30"
|
||||
>
|
||||
{testingLdap ? <RotateCcw size={14} className="animate-spin" /> : <Wifi size={14} />}
|
||||
Test Connection
|
||||
</button>
|
||||
<button
|
||||
onClick={onUpdateLdap}
|
||||
className="flex-[2] bg-primary hover:bg-primary text-white rounded-xl py-2.5 text-sm font-normal shadow-xl shadow-primary/10 transition-all active:scale-95 flex items-center justify-center gap-2 border border-primary/30 tracking-tight"
|
||||
className="flex-[2] bg-primary hover:bg-primary text-white rounded-xl py-2 text-sm font-normal shadow-xl shadow-primary/10 transition-all active:scale-95 flex items-center justify-center gap-2 border border-primary/30 tracking-tight"
|
||||
>
|
||||
<Shield size={14} /> Save LDAP Policy
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user