diff --git a/src/App.tsx b/src/App.tsx
index ced66cc..e66c51b 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -5,6 +5,7 @@ import TopBar from './components/TopBar'
import Glance from './pages/Glance'
import Infrastructure from './pages/Infrastructure'
import BookNest from './pages/BookNest'
+import Settings from './pages/Settings'
function App() {
const [sidebarCollapsed, setSidebarCollapsed] = useState(false)
@@ -60,6 +61,7 @@ function App() {
} />
} />
} />
+ } />
diff --git a/src/pages/Settings.tsx b/src/pages/Settings.tsx
new file mode 100644
index 0000000..8522658
--- /dev/null
+++ b/src/pages/Settings.tsx
@@ -0,0 +1,509 @@
+import { useState } from 'react'
+import {
+ User,
+ Palette,
+ Plug,
+ Bell,
+ Database,
+ Info,
+ Eye,
+ EyeOff,
+ Check,
+ Download,
+ Upload,
+ Trash2,
+ RotateCcw,
+} from 'lucide-react'
+
+const navSections = [
+ { id: 'profile', label: 'Profile', icon: User },
+ { id: 'appearance', label: 'Appearance', icon: Palette },
+ { id: 'integrations', label: 'Integrations', icon: Plug },
+ { id: 'notifications', label: 'Notifications', icon: Bell },
+ { id: 'data', label: 'Data & Backup', icon: Database },
+ { id: 'about', label: 'About', icon: Info },
+]
+
+const accentColors = [
+ { name: 'Gold', color: '#C8A434' },
+ { name: 'Teal', color: '#2DD4BF' },
+ { name: 'Purple', color: '#A855F7' },
+ { name: 'Blue', color: '#3B82F6' },
+ { name: 'Green', color: '#2ECC71' },
+ { name: 'Red', color: '#E74C3C' },
+]
+
+type IntegrationField = { label: string; value: string; secret?: boolean }
+
+const integrations: { name: string; online: boolean; fields: IntegrationField[] }[] = [
+ { name: 'Proxmox', online: true, fields: [{ label: 'Host URL', value: 'https://pve1.local:8006' }, { label: 'API Token', value: '••••••••••••', secret: true }] },
+ { name: 'Docker', online: true, fields: [{ label: 'Socket / Remote URL', value: 'unix:///var/run/docker.sock' }] },
+ { name: 'NetBird', online: true, fields: [{ label: 'API Key', value: '••••••••••••', secret: true }] },
+ { name: 'Cloudflare', online: true, fields: [{ label: 'API Token', value: '••••••••••••', secret: true }, { label: 'Zone ID', value: 'a1b2c3d4e5f6' }] },
+ { name: 'AWS', online: true, fields: [{ label: 'Access Key', value: 'AKIA••••••••' }, { label: 'Secret', value: '••••••••••••', secret: true }, { label: 'Region', value: 'us-east-1' }] },
+ { name: 'Uptime Kuma', online: false, fields: [{ label: 'URL', value: '' }, { label: 'API Key', value: '', secret: true }] },
+ { name: 'Weather API', online: true, fields: [{ label: 'Location', value: 'Charlotte, NC' }, { label: 'Units', value: 'Imperial' }] },
+]
+
+const cardBase: React.CSSProperties = {
+ backgroundColor: 'rgba(10, 10, 12, 0.92)',
+ border: '1px solid rgba(200, 164, 52, 0.08)',
+ borderRadius: '12px',
+ padding: '22px',
+ position: 'relative',
+}
+
+const sectionTitle: React.CSSProperties = {
+ fontSize: '11px',
+ textTransform: 'uppercase',
+ letterSpacing: '1.5px',
+ color: '#7A7D85',
+ fontWeight: 500,
+ marginBottom: '16px',
+}
+
+const labelStyle: React.CSSProperties = {
+ fontSize: '11px',
+ color: '#7A7D85',
+ marginBottom: '6px',
+ display: 'block',
+}
+
+const inputStyle: React.CSSProperties = {
+ width: '100%',
+ height: '34px',
+ borderRadius: '8px',
+ border: '1px solid rgba(200,164,52,0.12)',
+ backgroundColor: 'rgba(255,255,255,0.03)',
+ color: '#E8E6E0',
+ fontSize: '12px',
+ padding: '0 12px',
+ outline: 'none',
+}
+
+function Toggle({ on, onClick }: { on: boolean; onClick: () => void }) {
+ return (
+
+ )
+}
+
+function GoldButton({ children, danger }: { children: React.ReactNode; danger?: boolean }) {
+ return (
+
+ )
+}
+
+function ProfileSection() {
+ return (
+
+
Profile
+
+
+ AO
+
+
+
+ ArchNest Ops
+
+ Administrator
+
+
+
admin@archnest.io
+
+
+
+
+
+ Save Changes
+
+
+ )
+}
+
+function AppearanceSection() {
+ const [theme, setTheme] = useState<'dark' | 'light'>('dark')
+ const [accent, setAccent] = useState('Gold')
+ const [fontSize, setFontSize] = useState(13)
+ const [radius, setRadius] = useState(12)
+ const [sidebarExpanded, setSidebarExpanded] = useState(true)
+ const [animations, setAnimations] = useState(true)
+
+ return (
+
+
Appearance
+
+
+
Theme
+
+ {(['dark', 'light'] as const).map((t) => (
+
+ ))}
+
+
+
+
+
Accent Color
+
+ {accentColors.map((a) => (
+
+ ))}
+
+
+
+
+
+ Font Size
+ {fontSize}px
+
+
setFontSize(Number(e.target.value))}
+ className="w-full"
+ style={{ accentColor: '#C8A434' }}
+ />
+
+
+
+
+ Card Border Radius
+ {radius}px
+
+
setRadius(Number(e.target.value))}
+ className="w-full"
+ style={{ accentColor: '#C8A434' }}
+ />
+
+
+
+ Sidebar Expanded by Default
+ setSidebarExpanded((v) => !v)} />
+
+
+
+ Animations
+ setAnimations((v) => !v)} />
+
+
+ )
+}
+
+function IntegrationsSection() {
+ const [revealed, setRevealed] = useState>(new Set())
+
+ function toggleReveal(key: string) {
+ setRevealed((prev) => {
+ const next = new Set(prev)
+ if (next.has(key)) next.delete(key)
+ else next.add(key)
+ return next
+ })
+ }
+
+ return (
+
+ {integrations.map((integ) => (
+
+
+
+
+ {integ.name}
+
+
+
+
+ {integ.fields.map((f) => {
+ const key = `${integ.name}-${f.label}`
+ const isRevealed = revealed.has(key)
+ return (
+
+
+
+
+ {f.secret && (
+
+ )}
+
+
+ )
+ })}
+
+
+ ))}
+
+ )
+}
+
+function NotificationsSection() {
+ const [enabled, setEnabled] = useState(true)
+ const [email, setEmail] = useState(true)
+ const [push, setPush] = useState(false)
+ const [sound, setSound] = useState(true)
+
+ return (
+
+
Notifications
+
+
+ Enable Notifications
+ setEnabled((v) => !v)} />
+
+
+
+
+
+
+
+
+ Email Notifications
+ setEmail((v) => !v)} />
+
+
+
+ Browser Push
+ setPush((v) => !v)} />
+
+
+
+ Sound
+ setSound((v) => !v)} />
+
+ {sound && (
+
+ )}
+
+ )
+}
+
+function DataBackupSection() {
+ return (
+
+
Data & Backup
+
+
+ Export Bookmarks (JSON)
+ Export
+
+
+ Import Bookmarks (JSON)
+ Import
+
+
+ Export Settings
+ Export
+
+
+
+ Clear Cache
+ Clear
+
+
+ Reset to Defaults
+ Reset
+
+
+
+ )
+}
+
+function AboutSection() {
+ const rows: [string, string][] = [
+ ['App', 'ArchNest Dashboard v1.0.0'],
+ ['Author', 'Samuel James'],
+ ['Repo', 'github.com/SamuelSJames/archnest'],
+ ['Stack', 'React 19, Vite, TypeScript'],
+ ['License', 'MIT'],
+ ]
+ return (
+
+
About
+
+ {rows.map(([label, value]) => (
+
+ {label}
+ {value}
+
+ ))}
+
+
+ )
+}
+
+const sectionComponents: Record JSX.Element> = {
+ profile: ProfileSection,
+ appearance: AppearanceSection,
+ integrations: IntegrationsSection,
+ notifications: NotificationsSection,
+ data: DataBackupSection,
+ about: AboutSection,
+}
+
+export default function Settings() {
+ const [active, setActive] = useState('profile')
+ const ActiveSection = sectionComponents[active]
+
+ return (
+
+ {/* Settings nav */}
+
+ {navSections.map((s) => {
+ const Icon = s.icon
+ const isActive = active === s.id
+ return (
+
+ )
+ })}
+
+
+ {/* Content */}
+
+
+ )
+}