From a257b5571cc9fb1a728f49c23bdfbabd47ab355d Mon Sep 17 00:00:00 2001 From: NixReaper Date: Sat, 25 Apr 2026 15:51:47 -0500 Subject: [PATCH] feat: redesign NixServer (WHM) and NixClient (cPanel) UIs NixServer now has a dark orange-accented WHM-style layout with collapsible sidebar grouped by function, stat bar, service manager table with actions, quick-action icon grid, server info bar, and a branded split-panel login page. NixClient now has a cPanel-style feature icon grid with category sections, live search, account sidebar with usage bars, and a blue-themed login page. --- nixclient/src/App.tsx | 539 +++++++++++++++++++++++++---- nixserver/src/App.tsx | 779 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 1162 insertions(+), 156 deletions(-) diff --git a/nixclient/src/App.tsx b/nixclient/src/App.tsx index d57da83..e28391e 100644 --- a/nixclient/src/App.tsx +++ b/nixclient/src/App.tsx @@ -1,107 +1,508 @@ import { useState } from 'react' -export default function App() { - const [email, setEmail] = useState('') - const [password, setPassword] = useState('') - const [isLoggedIn, setIsLoggedIn] = useState(false) +/* ── Types ──────────────────────────────────────────────────────────────── */ +type Page = + | 'home' | 'domains' | 'subdomains' | 'redirects' + | 'email' | 'emailAccounts' | 'webmail' | 'spamFilter' + | 'databases' | 'mysql' | 'phpmyadmin' + | 'files' | 'fileManager' | 'ftp' | 'backups' + | 'security' | 'ssl' | 'passwords' | 'ssh' + | 'software' | 'php' | 'wordpress' + | 'stats' | 'logs' - const handleLogin = (e: React.FormEvent) => { - e.preventDefault() - if (email && password) { - setIsLoggedIn(true) - } +/* ── Feature groups (cPanel icon grid style) ────────────────────────────── */ +type Feature = { id: Page; label: string; icon: string; desc: string } +type FeatureGroup = { label: string; color: string; features: Feature[] } + +const FEATURE_GROUPS: FeatureGroup[] = [ + { + label: 'Domains', + color: 'blue', + features: [ + { id: 'domains', label: 'Domains', icon: '🌐', desc: 'Addon & parked domains' }, + { id: 'subdomains', label: 'Subdomains', icon: '🔗', desc: 'Create subdomains' }, + { id: 'redirects', label: 'Redirects', icon: '↪️', desc: '301 / 302 redirects' }, + ], + }, + { + label: 'Email', + color: 'emerald', + features: [ + { id: 'emailAccounts', label: 'Email Accounts', icon: '✉️', desc: 'Create & manage mailboxes' }, + { id: 'webmail', label: 'Webmail', icon: '📬', desc: 'Open Roundcube webmail' }, + { id: 'spamFilter', label: 'Spam Filters', icon: '🚫', desc: 'SpamAssassin rules' }, + ], + }, + { + label: 'Databases', + color: 'purple', + features: [ + { id: 'mysql', label: 'MySQL Databases', icon: '🗄️', desc: 'Create & manage DBs' }, + { id: 'phpmyadmin', label: 'phpMyAdmin', icon: '🖥️', desc: 'Database admin GUI' }, + ], + }, + { + label: 'Files', + color: 'orange', + features: [ + { id: 'fileManager', label: 'File Manager', icon: '📁', desc: 'Browse & edit files' }, + { id: 'ftp', label: 'FTP Accounts', icon: '📡', desc: 'Manage FTP users' }, + { id: 'backups', label: 'Backups', icon: '💾', desc: 'Download & restore' }, + ], + }, + { + label: 'Security', + color: 'red', + features: [ + { id: 'ssl', label: 'SSL / TLS', icon: '🔒', desc: "Let's Encrypt certs" }, + { id: 'passwords', label: 'Password', icon: '🔑', desc: 'Change cPanel password' }, + { id: 'ssh', label: 'SSH Keys', icon: '🗝️', desc: 'Manage SSH key pairs' }, + ], + }, + { + label: 'Software', + color: 'cyan', + features: [ + { id: 'php', label: 'PHP Version', icon: '🐘', desc: 'Select PHP 8.x' }, + { id: 'wordpress', label: 'WordPress', icon: '🌀', desc: 'Auto-install WP' }, + ], + }, + { + label: 'Metrics', + color: 'yellow', + features: [ + { id: 'stats', label: 'Statistics', icon: '📊', desc: 'Bandwidth & visitors' }, + { id: 'logs', label: 'Logs', icon: '📜', desc: 'Error & access logs' }, + ], + }, +] + +const COLOR_MAP: Record = { + blue: { tile: 'hover:border-blue-500/40 hover:bg-blue-500/5', icon: 'bg-blue-500/15 text-blue-400', badge: 'bg-blue-500/20 text-blue-400 border-blue-500/30' }, + emerald: { tile: 'hover:border-emerald-500/40 hover:bg-emerald-500/5', icon: 'bg-emerald-500/15 text-emerald-400', badge: 'bg-emerald-500/20 text-emerald-400 border-emerald-500/30' }, + purple: { tile: 'hover:border-purple-500/40 hover:bg-purple-500/5', icon: 'bg-purple-500/15 text-purple-400', badge: 'bg-purple-500/20 text-purple-400 border-purple-500/30' }, + orange: { tile: 'hover:border-orange-500/40 hover:bg-orange-500/5', icon: 'bg-orange-500/15 text-orange-400', badge: 'bg-orange-500/20 text-orange-400 border-orange-500/30' }, + red: { tile: 'hover:border-red-500/40 hover:bg-red-500/5', icon: 'bg-red-500/15 text-red-400', badge: 'bg-red-500/20 text-red-400 border-red-500/30' }, + cyan: { tile: 'hover:border-cyan-500/40 hover:bg-cyan-500/5', icon: 'bg-cyan-500/15 text-cyan-400', badge: 'bg-cyan-500/20 text-cyan-400 border-cyan-500/30' }, + yellow: { tile: 'hover:border-yellow-500/40 hover:bg-yellow-500/5', icon: 'bg-yellow-500/15 text-yellow-400', badge: 'bg-yellow-500/20 text-yellow-400 border-yellow-500/30' }, +} + +/* ── Usage bar ──────────────────────────────────────────────────────────── */ +function UsageBar({ label, used, total, unit, color }: { label: string; used: number; total: number; unit: string; color: string }) { + const pct = total > 0 ? Math.min((used / total) * 100, 100) : 0 + const barColor = pct > 90 ? 'bg-red-500' : pct > 70 ? 'bg-yellow-500' : color + return ( +
+
+ {label} + {used === 0 ? '0' : used} / {total === 0 ? '∞' : total + ' ' + unit} +
+
+
+
+
+ ) +} + +/* ── Account info sidebar ───────────────────────────────────────────────── */ +function AccountSidebar({ domain }: { domain: string }) { + return ( + + ) +} + +/* ── Home / feature grid ────────────────────────────────────────────────── */ +function Home({ onNav }: { onNav: (p: Page) => void }) { + const [search, setSearch] = useState('') + + const allFeatures = FEATURE_GROUPS.flatMap(g => + g.features.map(f => ({ ...f, groupColor: g.color, groupLabel: g.label })) + ) + + const filtered = search.trim() + ? allFeatures.filter( + f => + f.label.toLowerCase().includes(search.toLowerCase()) || + f.desc.toLowerCase().includes(search.toLowerCase()) + ) + : null + + return ( +
+ {/* Search bar */} +
+ 🔍 + setSearch(e.target.value)} + placeholder="Search features…" + className="w-full bg-[#1a1f2e] border border-[#2a3044] focus:border-blue-500/60 text-white rounded-xl pl-9 pr-4 py-3 text-sm placeholder-gray-600 focus:outline-none focus:ring-1 focus:ring-blue-500/20 transition-all" + /> + {search && ( + + )} +
+ + {/* Search results */} + {filtered ? ( +
+

{filtered.length} result{filtered.length !== 1 ? 's' : ''} for "{search}"

+
+ {filtered.map(f => { + const c = COLOR_MAP[f.groupColor] + return ( + + ) + })} +
+ {filtered.length === 0 && ( +
No features found for "{search}"
+ )} +
+ ) : ( + /* Normal grouped view */ +
+ {FEATURE_GROUPS.map(group => { + const c = COLOR_MAP[group.color] + return ( +
+
+

{group.label}

+
+
+
+ {group.features.map(f => ( + + ))} +
+
+ ) + })} +
+ )} +
+ ) +} + +/* ── Placeholder ────────────────────────────────────────────────────────── */ +function Placeholder({ title, icon }: { title: string; icon: string }) { + return ( +
+
{icon}
+

{title}

+

+ This module is under active development and will be available in an upcoming release. +

+
+ Coming Soon +
+
+ ) +} + +/* ── Page meta ──────────────────────────────────────────────────────────── */ +const PAGE_META: Record = { + home: { title: 'My Control Panel', icon: '▦' }, + domains: { title: 'Domains', icon: '🌐' }, + subdomains: { title: 'Subdomains', icon: '🔗' }, + redirects: { title: 'Redirects', icon: '↪️' }, + email: { title: 'Email', icon: '✉️' }, + emailAccounts:{ title: 'Email Accounts', icon: '✉️' }, + webmail: { title: 'Webmail', icon: '📬' }, + spamFilter: { title: 'Spam Filters', icon: '🚫' }, + databases: { title: 'Databases', icon: '🗄️' }, + mysql: { title: 'MySQL Databases', icon: '🗄️' }, + phpmyadmin: { title: 'phpMyAdmin', icon: '🖥️' }, + files: { title: 'Files', icon: '📁' }, + fileManager: { title: 'File Manager', icon: '📁' }, + ftp: { title: 'FTP Accounts', icon: '📡' }, + backups: { title: 'Backups', icon: '💾' }, + security: { title: 'Security', icon: '🔒' }, + ssl: { title: 'SSL / TLS', icon: '🔒' }, + passwords: { title: 'Password', icon: '🔑' }, + ssh: { title: 'SSH Keys', icon: '🗝️' }, + software: { title: 'Software', icon: '🐘' }, + php: { title: 'PHP Version', icon: '🐘' }, + wordpress: { title: 'WordPress', icon: '🌀' }, + stats: { title: 'Statistics', icon: '📊' }, + logs: { title: 'Logs', icon: '📜' }, +} + +/* ── Client panel shell ─────────────────────────────────────────────────── */ +function ClientPanel() { + const [page, setPage] = useState('home') + const [loggedIn, setLoggedIn] = useState(true) + + if (!loggedIn) return null + + const meta = PAGE_META[page] + const domain = 'yourdomain.com' + + function renderPage() { + if (page === 'home') return + return } - if (isLoggedIn) { - return ( -
- - -
-
- {[ - { title: 'My Domains', icon: '🌐', count: '0' }, - { title: 'Email Accounts', icon: '📧', count: '0' }, - { title: 'Databases', icon: '💾', count: '0' }, - { title: 'Backups', icon: '💾', count: '0' }, - ].map((item) => ( -
-
{item.icon}
-

{item.title}

-

{item.count}

-
- ))} -
- -
-

Welcome to Your Account

-

- Manage your domains, emails, databases, and more — all from one dashboard. -

-
-
-
- ) - } - - return ( -
-
-
-

- NixClient -

-

Your Hosting Control Panel

-
-
+ {/* Breadcrumb */} + {page !== 'home' && ( +
+ + / + {meta.title} +
+ )} + + + {/* Body */} +
+ {/* Sidebar */} + + + {/* Main content */} +
+ {renderPage()} +
+
+ + {/* Footer */} +
+ NixPanel Client v0.1.0 · {domain} · Powered by NixServer +
+
+ ) +} + +/* ── Login ──────────────────────────────────────────────────────────────── */ +export default function App() { + const [username, setUsername] = useState('') + const [password, setPassword] = useState('') + const [isLoggedIn, setIsLoggedIn] = useState(false) + const [error, setError] = useState('') + const [loading, setLoading] = useState(false) + + const handleLogin = (e: React.FormEvent) => { + e.preventDefault() + if (!username || !password) { + setError('Please enter your username and password.') + return + } + setLoading(true) + setError('') + setTimeout(() => { + setLoading(false) + setIsLoggedIn(true) + }, 600) + } + + if (isLoggedIn) return + + return ( +
+ {/* Background radial */} +
+ +
+ {/* Logo */} +
+
+
N
+
+

NixClient

+

Hosting Control Panel

+
+
+
+ + {/* Card */} +
+ {/* Header band */} +
+

Sign in to your account

+

NixClient Hosting Control Panel

+
+ + + {error && ( +
+ ⚠️ {error} +
+ )} +
- + setEmail(e.target.value)} + value={username} + onChange={e => setUsername(e.target.value)} required - className="w-full bg-gray-900 border border-gray-700 text-white rounded-lg px-4 py-2.5 text-sm placeholder-gray-500 focus:outline-none focus:border-emerald-500 transition-colors" + autoFocus + autoComplete="username" placeholder="username" + className="w-full bg-[#0f1520] border border-[#2a3044] text-white rounded-lg px-4 py-2.5 text-sm placeholder-gray-700 focus:outline-none focus:border-blue-500/60 focus:ring-1 focus:ring-blue-500/20 transition-all" />
- + setPassword(e.target.value)} + onChange={e => setPassword(e.target.value)} required - className="w-full bg-gray-900 border border-gray-700 text-white rounded-lg px-4 py-2.5 text-sm placeholder-gray-500 focus:outline-none focus:border-emerald-500 transition-colors" + autoComplete="current-password" placeholder="••••••••" + className="w-full bg-[#0f1520] border border-[#2a3044] text-white rounded-lg px-4 py-2.5 text-sm placeholder-gray-700 focus:outline-none focus:border-blue-500/60 focus:ring-1 focus:ring-blue-500/20 transition-all" />
-
-

- NixPanel Client — Manage your hosting account -

+
+ NixPanel Client v0.1.0 · Manage your hosting account +
+
) diff --git a/nixserver/src/App.tsx b/nixserver/src/App.tsx index b1b749b..092d7f9 100644 --- a/nixserver/src/App.tsx +++ b/nixserver/src/App.tsx @@ -1,109 +1,714 @@ import { useState } from 'react' -export default function App() { - const [email, setEmail] = useState('') - const [password, setPassword] = useState('') - const [isLoggedIn, setIsLoggedIn] = useState(false) +/* ── Types ──────────────────────────────────────────────────────────────── */ +type Page = + | 'dashboard' | 'accounts' | 'createAccount' | 'listAccounts' + | 'domains' | 'dns' | 'databases' | 'email' + | 'ssl' | 'backups' | 'firewall' + | 'apache' | 'php' | 'services' + | 'settings' | 'logs' | 'packages' - const handleLogin = (e: React.FormEvent) => { - e.preventDefault() - if (email && password) { - setIsLoggedIn(true) - } - } +/* ── Sidebar nav definition ─────────────────────────────────────────────── */ +type NavGroup = { label: string; items: { id: Page; label: string; icon: string }[] } - if (isLoggedIn) { - return ( -
- +const NAV_GROUPS: NavGroup[] = [ + { + label: 'Overview', + items: [ + { id: 'dashboard', label: 'Dashboard', icon: '▦' }, + ], + }, + { + label: 'Account Management', + items: [ + { id: 'listAccounts', label: 'List Accounts', icon: '📋' }, + { id: 'createAccount',label: 'Create Account', icon: '➕' }, + { id: 'packages', label: 'Feature Packages', icon: '📦' }, + ], + }, + { + label: 'Domains & DNS', + items: [ + { id: 'domains', label: 'Zone Manager', icon: '🌐' }, + { id: 'dns', label: 'DNS Records', icon: '🔗' }, + ], + }, + { + label: 'Databases', + items: [ + { id: 'databases', label: 'MySQL / MariaDB', icon: '🗄️' }, + ], + }, + { + label: 'Email', + items: [ + { id: 'email', label: 'Email Routing', icon: '✉️' }, + ], + }, + { + label: 'Security', + items: [ + { id: 'ssl', label: 'SSL / TLS', icon: '🔒' }, + { id: 'firewall', label: 'Firewall (CSF)', icon: '🛡️' }, + ], + }, + { + label: 'Server', + items: [ + { id: 'apache', label: 'Apache Config', icon: '⚙️' }, + { id: 'php', label: 'PHP Manager', icon: '🐘' }, + { id: 'services', label: 'Service Manager', icon: '🔧' }, + { id: 'backups', label: 'Backup Manager', icon: '💾' }, + { id: 'logs', label: 'System Logs', icon: '📜' }, + { id: 'settings', label: 'Server Config', icon: '🔩' }, + ], + }, +] -
-
- {[ - { title: 'Accounts', icon: '👥', count: '0' }, - { title: 'Domains', icon: '🌐', count: '0' }, - { title: 'Databases', icon: '💾', count: '0' }, - { title: 'Email Accounts', icon: '📧', count: '0' }, - { title: 'SSL Certificates', icon: '🔒', count: '0' }, - { title: 'Backups', icon: '💾', count: '0' }, - ].map((item) => ( -
-
{item.icon}
-

{item.title}

-

{item.count}

-
+/* ── Sidebar ────────────────────────────────────────────────────────────── */ +function Sidebar({ + current, onNav, onLogout, collapsed, onToggle, +}: { + current: Page; onNav: (p: Page) => void; onLogout: () => void + collapsed: boolean; onToggle: () => void +}) { + return ( +
+ )} +
- ) - } + + ) +} +/* ── Stat bar (top of dashboard) ────────────────────────────────────────── */ +function StatBar() { + const stats = [ + { label: 'Hosting Accounts', value: '0', unit: '', color: 'text-orange-400' }, + { label: 'Domains', value: '0', unit: '', color: 'text-blue-400' }, + { label: 'Databases', value: '0', unit: '', color: 'text-purple-400' }, + { label: 'Email Accounts', value: '0', unit: '', color: 'text-cyan-400' }, + { label: 'Disk Used', value: '—', unit: '', color: 'text-emerald-400' }, + { label: 'RAM Used', value: '—', unit: '', color: 'text-yellow-400' }, + ] return ( -
-
-
-

- NixServer -

-

Admin Control Panel

+
+ {stats.map((s, i) => ( +
+

{s.label}

+

{s.value}{s.unit}

+ ))} +
+ ) +} -
-
-
- - setEmail(e.target.value)} - required - className="w-full bg-gray-900 border border-gray-700 text-white rounded-lg px-4 py-2.5 text-sm placeholder-gray-500 focus:outline-none focus:border-blue-500 transition-colors" - placeholder="admin" - /> -
+/* ── Service status table ───────────────────────────────────────────────── */ +type SvcStatus = 'running' | 'stopped' | 'warning' +function ServiceTable() { + const services: { name: string; status: SvcStatus; pid?: string; uptime?: string }[] = [ + { name: 'Apache HTTP Server', status: 'running', pid: '1234', uptime: '2d 4h' }, + { name: 'MariaDB', status: 'running', pid: '1238', uptime: '2d 4h' }, + { name: 'PowerDNS', status: 'running', pid: '1242', uptime: '2d 4h' }, + { name: 'Exim (SMTP)', status: 'running', pid: '1251', uptime: '2d 4h' }, + { name: 'Dovecot (IMAP)', status: 'running', pid: '1265', uptime: '2d 4h' }, + { name: 'SpamAssassin', status: 'running', pid: '1280', uptime: '2d 4h' }, + { name: 'Fail2ban', status: 'running', pid: '1291', uptime: '2d 4h' }, + { name: 'ProFTPD', status: 'stopped' }, + ] + const badge: Record = { + running: 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/30', + stopped: 'bg-red-500/20 text-red-400 border border-red-500/30', + warning: 'bg-yellow-500/20 text-yellow-400 border border-yellow-500/30', + } + return ( +
+
+

Service Manager

+ 7 / 8 running +
+ + + + + + + + + + + + {services.map(svc => ( + + + + + + + + ))} + +
ServiceStatusPIDUptimeActions
{svc.name} + + + {svc.status.charAt(0).toUpperCase() + svc.status.slice(1)} + + {svc.pid || '—'}{svc.uptime || '—'} +
+ + + +
+
+
+ ) +} +/* ── Quick action tiles (cPanel icon-grid style) ────────────────────────── */ +function QuickActions({ onNav }: { onNav: (p: Page) => void }) { + const actions: { label: string; icon: string; page: Page; desc: string }[] = [ + { label: 'Create Account', icon: '👤', page: 'createAccount', desc: 'Add hosting account' }, + { label: 'Zone Manager', icon: '🌐', page: 'domains', desc: 'Manage DNS zones' }, + { label: 'New Database', icon: '🗄️', page: 'databases', desc: 'Create MariaDB DB' }, + { label: 'Issue SSL', icon: '🔒', page: 'ssl', desc: "Let's Encrypt cert" }, + { label: 'Run Backup', icon: '💾', page: 'backups', desc: 'Full server backup' }, + { label: 'PHP Manager', icon: '🐘', page: 'php', desc: 'Switch PHP version' }, + { label: 'Firewall', icon: '🛡️', page: 'firewall', desc: 'Edit CSF rules' }, + { label: 'System Logs', icon: '📜', page: 'logs', desc: 'Apache, error logs' }, + ] + return ( +
+
+

Quick Actions

+
+
+ {actions.map((a, i) => ( + + ))} +
+
+ ) +} + +/* ── Server info bar ────────────────────────────────────────────────────── */ +function ServerInfoBar() { + const info = [ + { label: 'Hostname', value: 'server.example.com' }, + { label: 'OS', value: 'Ubuntu 24.04 LTS' }, + { label: 'Kernel', value: '6.8.0-51-generic' }, + { label: 'PHP', value: '8.3 / 8.2' }, + { label: 'MariaDB', value: '10.11' }, + { label: 'Apache', value: '2.4' }, + { label: 'NixPanel', value: 'v0.1.0' }, + ] + return ( +
+ {info.map(i => ( +
+ {i.label}: + {i.value} +
+ ))} +
+ ) +} + +/* ── Dashboard page ─────────────────────────────────────────────────────── */ +function Dashboard({ onNav }: { onNav: (p: Page) => void }) { + return ( +
+
+
+

Server Overview

+

Welcome back, admin — NixServer WHM

+
+ + + All systems operational + +
+ + + + +
+ + +
+
+ ) +} + +/* ── Account list page ──────────────────────────────────────────────────── */ +function ListAccounts() { + return ( +
+
+

Hosting Accounts

+ +
+ + {/* Filter bar */} +
+ + + +
+ + {/* Table */} +
+ + + + {['Username', 'Domain', 'Package', 'Disk', 'BW', 'Status', 'Actions'].map(h => ( + + ))} + + + + + + + +
{h}
+
👤
+

No accounts yet.

+
+
+
+ ) +} + +/* ── Create account form ────────────────────────────────────────────────── */ +function CreateAccount() { + return ( +
+

Create Hosting Account

+ +
+ {/* Domain */} +
+

Domain Information

+
+
+ + +
+
+
+ + {/* Credentials */} +
+

Account Credentials

+
+
+ + +
- - setPassword(e.target.value)} - required - className="w-full bg-gray-900 border border-gray-700 text-white rounded-lg px-4 py-2.5 text-sm placeholder-gray-500 focus:outline-none focus:border-blue-500 transition-colors" - placeholder="••••••••" - /> -
- -
+
+ + +
+
+
+ + {/* Package & limits */} +
+

Resource Limits

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ + +
+
+
+ ) +} + +/* ── Generic placeholder for unbuilt modules ────────────────────────────── */ +function Placeholder({ title, icon }: { title: string; icon: string }) { + return ( +
+
{icon}
+

{title}

+

+ This module is under active development and will be available in an upcoming release. +

+
+ Coming Soon +
+
+ ) +} + +/* ── Page icon map ──────────────────────────────────────────────────────── */ +const PAGE_META: Record = { + dashboard: { title: 'Server Dashboard', icon: '▦' }, + accounts: { title: 'Accounts', icon: '👤' }, + listAccounts: { title: 'List Accounts', icon: '📋' }, + createAccount: { title: 'Create Account', icon: '➕' }, + packages: { title: 'Feature Packages', icon: '📦' }, + domains: { title: 'Zone Manager', icon: '🌐' }, + dns: { title: 'DNS Records', icon: '🔗' }, + databases: { title: 'MySQL / MariaDB', icon: '🗄️' }, + email: { title: 'Email Routing', icon: '✉️' }, + ssl: { title: 'SSL / TLS Manager', icon: '🔒' }, + backups: { title: 'Backup Manager', icon: '💾' }, + firewall: { title: 'Firewall (CSF)', icon: '🛡️' }, + apache: { title: 'Apache Config', icon: '⚙️' }, + php: { title: 'PHP Manager', icon: '🐘' }, + services: { title: 'Service Manager', icon: '🔧' }, + settings: { title: 'Server Config', icon: '🔩' }, + logs: { title: 'System Logs', icon: '📜' }, +} + +/* ── Admin panel shell ──────────────────────────────────────────────────── */ +function AdminPanel() { + const [page, setPage] = useState('dashboard') + const [loggedIn, setLoggedIn] = useState(true) + const [collapsed, setCollapsed] = useState(false) + + if (!loggedIn) return null + + const meta = PAGE_META[page] + + function renderPage() { + switch (page) { + case 'dashboard': return + case 'listAccounts': return + case 'createAccount': return + default: return + } + } + + return ( +
+ setLoggedIn(false)} + collapsed={collapsed} + onToggle={() => setCollapsed(c => !c)} + /> + +
+ {/* Top bar */} +
+
+ {meta.icon} +

{meta.title}

+
+ +
+ {/* Server info pills */} +
+ + Ubuntu 24.04 + + + Apache 2.4 + + + PHP 8.3 + +
+ + {/* Alerts */} + - + + {/* Avatar */} +
+
A
+ admin +
+
+
+ + {/* Breadcrumb */} + {page !== 'dashboard' && ( +
+ + / + {meta.title} +
+ )} + + {/* Page content */} +
+ {renderPage()} +
+ + {/* Footer */} +
+ NixPanel WHM v0.1.0 · Ubuntu 24.04 LTS + © 2025 NixPanel +
+
+
+ ) +} + +/* ── Login page ─────────────────────────────────────────────────────────── */ +export default function App() { + const [username, setUsername] = useState('') + const [password, setPassword] = useState('') + const [isLoggedIn, setIsLoggedIn] = useState(false) + const [error, setError] = useState('') + const [loading, setLoading] = useState(false) + + const handleLogin = (e: React.FormEvent) => { + e.preventDefault() + if (!username || !password) { + setError('Username and password are required.') + return + } + setLoading(true) + setError('') + setTimeout(() => { + setLoading(false) + setIsLoggedIn(true) + }, 600) + } + + if (isLoggedIn) return + + return ( +
+ {/* Left branding panel */} +
+
+
+
N
+
+ NixServer +
WHM Control Panel
+
+
+ +
+ {[ + { icon: '🌐', title: 'Full DNS Control', desc: 'PowerDNS-backed zone management' }, + { icon: '🔒', title: 'Auto SSL/TLS', desc: "Let's Encrypt for all domains" }, + { icon: '🛡️', title: 'Built-in Firewall', desc: 'CSF/Fail2ban integration' }, + { icon: '💾', title: 'Automated Backups', desc: 'Scheduled full & incremental' }, + { icon: '🐘', title: 'Multi-PHP Support', desc: 'PHP 8.0 – 8.3 per account' }, + ].map(f => ( +
+ {f.icon} +
+

{f.title}

+

{f.desc}

+
+
+ ))} +
+ +

NixPanel WHM v0.1.0 · Secured by Fail2ban

+
+ + {/* Login form */} +
+
+ {/* Mobile logo */} +
+ NixServer +

WHM Control Panel

+
-

- NixPanel Server Admin — Login with your credentials -

+
+ {/* Card header */} +
+

Administrator Login

+

NixServer WHM · Root Access

+
+ +
+ {error && ( +
+ ⚠️ {error} +
+ )} + +
+ + setUsername(e.target.value)} + required + autoFocus + autoComplete="username" + placeholder="admin" + className="w-full bg-[#0f1520] border border-[#2a3044] text-white rounded-lg px-4 py-2.5 text-sm placeholder-gray-700 focus:outline-none focus:border-orange-500/60 focus:ring-1 focus:ring-orange-500/20 transition-all" + /> +
+ +
+ + setPassword(e.target.value)} + required + autoComplete="current-password" + placeholder="••••••••••••" + className="w-full bg-[#0f1520] border border-[#2a3044] text-white rounded-lg px-4 py-2.5 text-sm placeholder-gray-700 focus:outline-none focus:border-orange-500/60 focus:ring-1 focus:ring-orange-500/20 transition-all" + /> +
+ + +
+ +
+ Secured by Fail2ban + NixPanel v0.1 +
+
+
)