From a1bc0a94d512c221b45047321332d581943b5e4a Mon Sep 17 00:00:00 2001 From: rcourtman Date: Fri, 24 Oct 2025 10:16:22 +0000 Subject: [PATCH] refactor: condense settings UI with tab navigation Replace large card-style buttons with compact tab navigation matching the Proxmox pages pattern. Remove redundant section headers that duplicated tab labels, significantly reducing visual bloat. --- .../src/components/Settings/Settings.tsx | 115 +----------------- .../Settings/SettingsSectionNav.tsx | 67 ++++++++++ 2 files changed, 72 insertions(+), 110 deletions(-) create mode 100644 frontend-modern/src/components/Settings/SettingsSectionNav.tsx diff --git a/frontend-modern/src/components/Settings/Settings.tsx b/frontend-modern/src/components/Settings/Settings.tsx index 6ad1e66..f685ebd 100644 --- a/frontend-modern/src/components/Settings/Settings.tsx +++ b/frontend-modern/src/components/Settings/Settings.tsx @@ -13,6 +13,7 @@ import { OIDCPanel } from './OIDCPanel'; import { QuickSecuritySetup } from './QuickSecuritySetup'; import { SecurityPostureSummary } from './SecurityPostureSummary'; import { PveNodesTable, PbsNodesTable, PmgNodesTable } from './ConfiguredNodeTables'; +import { SettingsSectionNav } from './SettingsSectionNav'; import { SettingsAPI } from '@/api/settings'; import { NodesAPI } from '@/api/nodes'; import { UpdatesAPI } from '@/api/updates'; @@ -394,37 +395,6 @@ const Settings: Component = (props) => { const [selectedAgent, setSelectedAgent] = createSignal('pve'); - const agentGroups: { - title: string; - description?: string; - agents: Array<{ id: AgentKey; label: string; description: string; icon: JSX.Element; disabled?: boolean }>; -}[] = [ - { - title: 'Proxmox Products', - description: 'Select which Proxmox product to configure', - agents: [ - { - id: 'pve', - label: 'Virtual Environment', - description: 'VMs, containers, clusters, and storage', - icon: , - }, - { - id: 'pbs', - label: 'Backup Server', - description: 'Backup jobs, datastores, and snapshots', - icon: , - }, - { - id: 'pmg', - label: 'Mail Gateway', - description: 'Mail flow, spam filtering, and queues', - icon: , - }, - ], - }, -]; - const agentPaths: Record = { pve: '/settings/pve', pbs: '/settings/pbs', @@ -2129,82 +2099,15 @@ const Settings: Component = (props) => {
- - - - {(group) => ( -
-
-
-

- {group.title} -

- -

- {group.description} -

-
-
-
-
- - {(card) => { - const isActive = () => selectedAgent() === card.id; - return ( - - ); - }} - -
-
- )} -
-
{/* PVE Nodes Tab */}
-
@@ -2482,10 +2385,6 @@ const Settings: Component = (props) => { {/* PBS Nodes Tab */}
-
@@ -2762,10 +2661,6 @@ const Settings: Component = (props) => { {/* PMG Nodes Tab */}
-
diff --git a/frontend-modern/src/components/Settings/SettingsSectionNav.tsx b/frontend-modern/src/components/Settings/SettingsSectionNav.tsx new file mode 100644 index 0000000..9c6e5f5 --- /dev/null +++ b/frontend-modern/src/components/Settings/SettingsSectionNav.tsx @@ -0,0 +1,67 @@ +import type { Component } from 'solid-js'; +import { For } from 'solid-js'; +import Server from 'lucide-solid/icons/server'; +import HardDrive from 'lucide-solid/icons/hard-drive'; +import Mail from 'lucide-solid/icons/mail'; + +type SettingsSection = 'pve' | 'pbs' | 'pmg' | 'docker' | 'host' | 'podman' | 'kubernetes'; + +interface SettingsSectionNavProps { + current: SettingsSection; + onSelect: (section: SettingsSection) => void; + class?: string; +} + +const allSections: Array<{ + id: SettingsSection; + label: string; + icon: typeof Server; +}> = [ + { + id: 'pve', + label: 'Virtual Environment', + icon: Server, + }, + { + id: 'pbs', + label: 'Backup Server', + icon: HardDrive, + }, + { + id: 'pmg', + label: 'Mail Gateway', + icon: Mail, + }, +]; + +export const SettingsSectionNav: Component = (props) => { + const baseClasses = + 'inline-flex items-center gap-2 px-2 sm:px-3 py-1 text-xs sm:text-sm font-medium border-b-2 border-transparent text-gray-600 dark:text-gray-400 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400/60 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-offset-gray-900'; + + return ( +
+ + {(section) => { + const isActive = section.id === props.current; + const classes = isActive + ? `${baseClasses} text-blue-600 dark:text-blue-300 border-blue-500 dark:border-blue-400` + : `${baseClasses} hover:text-blue-500 dark:hover:text-blue-300 hover:border-blue-300/70 dark:hover:border-blue-500/50`; + + const Icon = section.icon; + + return ( + + ); + }} + +
+ ); +};