From e881ec6cb51c973f65dc15bdd2b8bd036ffb40a2 Mon Sep 17 00:00:00 2001 From: Kaloyan Danchev Date: Fri, 6 Feb 2026 07:44:52 +0200 Subject: [PATCH] Add Unraid UI project documentation and research - Complete Unraid WebGUI inventory (~100 pages documented) - Unraid GraphQL API research and documentation - Homarr architecture documentation - Orchis GTK theme design tokens (TypeScript) - Project README with implementation plan Co-Authored-By: Claude Opus 4.5 --- docs/unraid-ui-project/README.md | 148 ++ .../WEBGUI-COMPLETE-INVENTORY.md | 1505 +++++++++++++++++ docs/unraid-ui-project/homarr-architecture.md | 60 + .../unraid-ui-project/orchis-design-system.ts | 1329 +++++++++++++++ docs/unraid-ui-project/unraid-api-research.md | 81 + 5 files changed, 3123 insertions(+) create mode 100644 docs/unraid-ui-project/README.md create mode 100644 docs/unraid-ui-project/WEBGUI-COMPLETE-INVENTORY.md create mode 100644 docs/unraid-ui-project/homarr-architecture.md create mode 100644 docs/unraid-ui-project/orchis-design-system.ts create mode 100644 docs/unraid-ui-project/unraid-api-research.md diff --git a/docs/unraid-ui-project/README.md b/docs/unraid-ui-project/README.md new file mode 100644 index 000000000..172dfea72 --- /dev/null +++ b/docs/unraid-ui-project/README.md @@ -0,0 +1,148 @@ +# Unraid Custom UI Project + +This project transforms the Homarr fork into a custom Unraid management UI with an Orchis GTK theme. + +## Project Goals + +1. **Step 1**: Recreate all current Unraid WebGUI pages using Homarr as a base, with data from the Unraid GraphQL API +2. **Step 2**: Apply a custom theme based on the Orchis GTK theme + +## Project Resources + +| Document | Description | +|----------|-------------| +| [WEBGUI-COMPLETE-INVENTORY.md](./WEBGUI-COMPLETE-INVENTORY.md) | Complete inventory of ~100 Unraid WebGUI pages | +| [unraid-api-research.md](./unraid-api-research.md) | Unraid GraphQL API documentation | +| [homarr-architecture.md](./homarr-architecture.md) | Homarr codebase architecture | +| [orchis-design-system.ts](./orchis-design-system.ts) | Orchis theme design tokens (TypeScript) | + +## Unraid Server Connection + +- **GraphQL Endpoint**: `http://192.168.10.20/graphql` +- **Auth**: `x-api-key` header +- **Socket**: `/var/run/unraid-api.sock` + +## Implementation Plan + +### Phase 1: Foundation Setup +- [ ] Create Unraid GraphQL client integration +- [ ] Set up API authentication layer +- [ ] Configure environment variables for Unraid connection +- [ ] Create base types for Unraid data models + +### Phase 2: Core Pages (Priority Order) +1. **Dashboard** - System overview with real-time metrics + - System info, CPU/RAM usage, array status + - Docker/VM summaries, network, UPS + +2. **Array Management** (Main) + - Array devices, pool devices, boot device + - Parity check, array operations + +3. **Docker Management** + - Container list, start/stop/restart + - Container details, logs + +4. **VM Management** + - VM list, power controls + - VM details, console access + +5. **Shares** + - User shares, disk shares + - Share settings, SMB/NFS security + +### Phase 3: Orchis Theme Integration +- [ ] Copy design tokens to `src/styles/` +- [ ] Create Mantine theme override with Orchis values +- [ ] Implement light/dark mode with Orchis palettes +- [ ] Replace default components with Orchis-styled versions + +### Phase 4: Settings & Tools +- Settings pages (identification, disk, network, etc.) +- Tools pages (syslog, diagnostics, system devices) +- User management +- Notifications system + +### Phase 5: Real-time Features +- GraphQL subscriptions for CPU/memory metrics +- Nchan integration for legacy real-time features +- WebSocket connections for live updates + +## Key Technical Decisions + +### Homarr Stack +- Next.js 13 (Pages Router in this version) +- Mantine UI v6 +- tRPC for type-safe API +- Zustand for state management +- React Query for server state + +### Data Sources +| Feature | Source | +|---------|--------| +| System info, array, shares | Unraid GraphQL API | +| Docker containers | Unraid GraphQL API | +| VMs | Unraid GraphQL API | +| Real-time CPU/RAM | GraphQL Subscriptions | +| Real-time disk I/O | Nchan WebSocket (`/sub/diskload`) | +| Legacy features | PHP endpoints where needed | + +### API Gaps (Require Legacy Endpoints) +- Docker create/delete/restart/logs +- VM create/delete +- Share CRUD, User CRUD +- System reboot/shutdown +- Mover operations + +## Directory Structure (New Files) + +``` +src/ +├── lib/ +│ └── unraid/ +│ ├── client.ts # GraphQL client +│ ├── types.ts # TypeScript types +│ └── queries/ # GraphQL queries +├── pages/ +│ └── unraid/ +│ ├── dashboard.tsx # Dashboard page +│ ├── array/ # Array pages +│ ├── docker/ # Docker pages +│ ├── vms/ # VM pages +│ ├── shares/ # Share pages +│ ├── settings/ # Settings pages +│ └── tools/ # Tools pages +├── components/ +│ └── unraid/ +│ ├── Dashboard/ # Dashboard components +│ ├── Array/ # Array components +│ ├── Docker/ # Docker components +│ └── ... +└── styles/ + └── orchis/ + ├── theme.ts # Mantine theme config + ├── variables.css # CSS custom properties + └── components.css # Component overrides +``` + +## Getting Started + +```bash +# Install dependencies +yarn install + +# Set up environment +cp .env.example .env.local +# Edit .env.local with your Unraid API key + +# Run development server +yarn dev +``` + +## Environment Variables + +```env +UNRAID_HOST=192.168.10.20 +UNRAID_API_KEY=your-api-key-here +UNRAID_USE_SSL=false +``` diff --git a/docs/unraid-ui-project/WEBGUI-COMPLETE-INVENTORY.md b/docs/unraid-ui-project/WEBGUI-COMPLETE-INVENTORY.md new file mode 100644 index 000000000..483c79abd --- /dev/null +++ b/docs/unraid-ui-project/WEBGUI-COMPLETE-INVENTORY.md @@ -0,0 +1,1505 @@ +# Unraid WebGUI - Complete Page & Feature Inventory + +**Source Repository:** https://github.com/unraid/webgui +**Technology Stack:** PHP (server-side), jQuery (client-side), Nchan (WebSocket real-time updates), nginx (web server) +**Document Root:** `/usr/local/emhttp` +**State Files:** `/var/local/emhttp/` (INI files generated by emhttp daemon) +**Configuration:** `/boot/config/` (persistent flash storage) + +--- + +## TABLE OF CONTENTS + +1. [Architecture Overview](#1-architecture-overview) +2. [Page System (.page files)](#2-page-system) +3. [Navigation Structure](#3-navigation-structure) +4. [Header Bar](#4-header-bar) +5. [Footer Bar](#5-footer-bar) +6. [Dashboard](#6-dashboard) +7. [Main (Array Devices)](#7-main-array-devices) +8. [Shares](#8-shares) +9. [Users](#9-users) +10. [Settings](#10-settings) +11. [Plugins](#11-plugins) +12. [Docker](#12-docker) +13. [VMs](#13-vms) +14. [Tools](#14-tools) +15. [About](#15-about) +16. [Apps](#16-apps) +17. [Favorites](#17-favorites) +18. [Device Detail Pages](#18-device-detail-pages) +19. [File Browser](#19-file-browser) +20. [Notification System](#20-notification-system) +21. [Real-Time Monitoring (Nchan)](#21-real-time-monitoring) +22. [Modal Dialogs & Wizards](#22-modal-dialogs--wizards) +23. [Themes](#23-themes) +24. [Authentication & Login](#24-authentication--login) +25. [Data Sources](#25-data-sources) +26. [JavaScript Libraries](#26-javascript-libraries) +27. [CSS Architecture](#27-css-architecture) + +--- + +## 1. Architecture Overview + +### Repository Structure +``` +emhttp/ + auth-request.php # Authentication request handler + login.php # Login page + update.htm # Form POST target (iframe progress frame) + update.php # Form POST handler (runs commands) + logging.htm # Logging iframe + manifest.json # PWA manifest + robots.txt # Search engine directives + plugins/ + dynamix/ # Core WebGUI plugin (main UI) + dynamix.docker.manager/ # Docker container management + dynamix.vm.manager/ # Virtual machine management + dynamix.plugin.manager/ # Plugin management + dynamix.gui.search/ # GUI search functionality + dynamix.apcupsd/ # APC UPS daemon integration + languages/ + en_US/ # English translations + webGui -> plugins/dynamix # Symlink: /webGui -> /plugins/dynamix + state -> /var/local/emhttp # Symlink to state files + boot -> /boot # Symlink to boot device + mnt -> /mnt # Symlink to mount points + log -> /var/log # Symlink to logs +``` + +### Page File Format (.page) +Each `.page` file is a self-contained page definition with a metadata header and PHP/HTML body: +``` +Menu="Tasks:1" # Menu placement (parent:order) +Type="xmenu" # Page type (xmenu=top-level, menu=sub-menu) +Title="Page Title" # Display title +Icon="icon-name" # Icon class +Tag="fa-icon" # FontAwesome icon +Code="eXXX" # Unicode icon code (for Unraid font) +Tabs="true" # Enable tabbed sub-pages +Cond="PHP expression" # Conditional display +Nchan="script1,script2" # Real-time update scripts to activate +Lock="true" # Enable drag-sort lock button +Load="30" # Auto-refresh interval (seconds) +--- + +``` + +### Data Flow +1. `emhttp` daemon monitors hardware and writes state to `/var/local/emhttp/*.ini` +2. PHP pages read INI files: `parse_ini_file('state/disks.ini', true)` +3. Nchan scripts poll state files and push updates via WebSocket +4. JavaScript receives updates and modifies DOM in real-time +5. Form submissions POST to `update.htm` / `update.php` which run shell commands + +### Key State Files (in `/var/local/emhttp/`) +| File | Content | +|------|---------| +| `var.ini` | System variables (array state, license, server name, etc.) | +| `disks.ini` | All disk information (serial, temp, size, status, errors) | +| `shares.ini` | Share definitions and status | +| `users.ini` | User accounts | +| `sec.ini` | SMB security settings per share | +| `sec_nfs.ini` | NFS security settings per share | +| `network.ini` | Network interface configuration | +| `nginx.ini` | Nginx/SSL status | +| `devs.ini` | Unassigned/open devices | +| `diskload.ini` | Real-time disk I/O rates | +| `cpuload.ini` | CPU load data | +| `wireless.ini` | WiFi status | + +--- + +## 2. Page System + +### Page Builder (`include/PageBuilder.php`) +- Scans all `.page` files across all plugin directories +- Parses metadata headers +- Builds navigation menu structure based on `Menu=` directives +- Handles conditional page display via `Cond=` directives +- Supports tabbed and tabless page layouts + +### Menu Hierarchy +- **Tasks** - Top navigation tabs (Dashboard, Main, Shares, Users, Settings, Plugins, Docker, VMs, Tools, About) +- **OtherSettings** - Settings sub-pages +- **NetworkSettings** - Network settings sub-pages +- **NetworkServices** - Network services sub-pages +- **UserPreferences** - User preference sub-pages +- **UNRAID-OS** - Tools > Unraid OS sub-pages +- **WebGui** - Tools > WebGui sub-pages +- **Buttons** - Header bar buttons (right side) + +--- + +## 3. Navigation Structure + +### Top Navigation / Sidebar (Navigation/Main.php) +The navigation renders differently based on theme: +- **Top Nav themes** (azure, gray): Horizontal tab bar at top +- **Sidebar themes** (black, white): Vertical sidebar on left + +**Main Navigation Items (in order):** +1. **Dashboard** (Menu="Tasks:1", Code=e943) +2. **Main** (Menu="Tasks:1", Code=e908) - Array devices +3. **Shares** (Menu="Tasks:2", Code=e92a) - User/disk shares +4. **Users** (Menu="Tasks:3", Code=e945) - Conditional on display setting +5. **Settings** (Menu="Tasks:4", Code=e924) +6. **Plugins** (Menu="Tasks:50", Code=e944) +7. **Docker** (Menu="Tasks:60") - Conditional on Docker enabled +8. **VMs** (Menu="Tasks:70") - Conditional on VMs enabled +9. **Apps** (Menu="Tasks:80", Code=e942) - Community Applications +10. **Favorites** (Menu="Tasks:2", Code=f08a) - Conditional on favorites existing +11. **Tools** (Menu="Tasks:90", Code=e909) +12. **About** (Menu="Tools:90") + +### Header Bar Buttons (right side) +- **Lock/Unlock** - Toggle drag-sort for Docker/VM containers +- **Array Usage Bar** - Visual bar showing array utilization % +- **Search** (gui_search) - Global page search +- **Terminal** - Open web terminal (ttyd) +- **Log** - Open syslog viewer +- **Help** - Toggle inline help text +- **Notifications** - Bell icon with alert counter +- **Feedback** - Bug report / feature request +- **Language** - Language selector +- **Logout** - User logout +- **Info** - System info popup + +--- + +## 4. Header Bar + +**File:** `include/DefaultPageLayout/Header.php` + +Components: +- **Banner Image** - Customizable PNG banner (`/boot/config/plugins/dynamix/banner.png`) +- **OS Version** - `` web component +- **Array Usage** - Progress bar (sidebar themes show it in header) +- **My Servers** - Unraid Connect cloud integration (`myservers2.php`) + +--- + +## 5. Footer Bar + +**File:** `include/DefaultPageLayout/Footer.php` + +Components: +- **Array Status Indicator** - Color-coded status (Started=green, Stopped=red, Starting/Stopping=orange) + - Shows progress text during parity operations +- **User Notice Area** - Red text notifications +- **Theme Switcher** - `` web component (azure/gray/black/white) +- **Copyright** - "Unraid webGui (c) YYYY, Lime Technology, Inc." +- **Manual Link** - Link to online documentation +- **WiFi Icon** - If wlan0 exists, shows WiFi status indicator + +--- + +## 6. Dashboard + +**Files:** `Dashboard.page` (menu container), `DashStats.page` (content) +**Nchan Scripts:** `update_1`, `update_2`, `update_3`, `ups_status`, `vm_dashusage`, `wg_poller` + +### Layout +The Dashboard is a drag-and-drop tile layout with 3 columns. Tiles can be rearranged and hidden. Configuration saved in cookie `dashboard_settings.json`. + +### Tiles/Sections + +#### 6.1 System Information Tile +- **Server Name & Description** +- **OS Version** with update notification +- **Uptime** +- **CPU Model** (model name, cores, threads, frequency) +- **Motherboard** (manufacturer, product) +- **License Type** (Basic/Plus/Pro/Lifetime) +- **Flash GUID** + +#### 6.2 CPU Tile +- **Real-time CPU usage graph** (ApexCharts donut) +- **Per-core utilization** bars +- **CPU temperature** (from `sensors`) +- **HT/Turbo status** +- Data source: `/proc/stat`, `sensors -uA` + +#### 6.3 RAM Tile +- **Memory usage donut chart** +- **Total/Used/Free** with percentage +- **Per-service breakdown** (System, Docker, VMs, etc.) +- Data source: `/proc/meminfo` + +#### 6.4 Array Tile +- **Array status** (Started/Stopped/Maintenance) +- **Parity status** (valid/invalid/building) +- **Parity check progress** (if running) +- **Next scheduled parity check** +- **Disk utilization** per disk with colored bars +- **Temperature** per disk +- **Start/Stop Array** button +- Data source: `state/var.ini`, `state/disks.ini` + +#### 6.5 Pool Tiles (one per pool) +- **Pool name & filesystem type** (btrfs/xfs/zfs) +- **Utilization bar** with used/free +- **Per-device status** +- **Temperature** per device + +#### 6.6 Network Tile +- **Interface list** (eth0, bond0, br0, wlan0, etc.) +- **IP addresses** (IPv4/IPv6) +- **Link speed** +- **Real-time throughput** (rx/tx bytes/sec) +- Data source: `/sys/class/net/`, `ip addr` + +#### 6.7 Docker Tile +- **Running/Stopped count** +- **Container list** with status indicators +- **Quick start/stop** actions +- **CPU/Memory** per container +- Data source: Docker API via `DockerClient.php` + +#### 6.8 VMs Tile +- **Running/Stopped count** +- **VM list** with status +- **Quick start/stop/pause** actions +- Data source: libvirt API via `libvirt.php` + +#### 6.9 UPS Tile (conditional) +- **UPS Model** +- **Status** (Online/On Battery) +- **Battery Charge %** +- **Runtime Left** +- **Load %** +- **Output Voltage** +- Data source: `apcaccess` command + +#### 6.10 WireGuard VPN Tile (conditional) +- **Tunnel status** (active/inactive) +- **Peer connections** +- **Handshake times** +- **Transfer statistics** +- Data source: `wg show` command + +#### 6.11 Shares Tile +- **Share list** with SMB/NFS export status +- **Size/Free** per share +- Data source: `state/shares.ini` + +#### 6.12 Custom Tiles +- Plugins can inject custom dashboard tiles via the tile API + +### Real-Time Updates +- **update_1**: RAM usage, system temps, fan speeds, flash/log/docker filesystem usage, share sizes +- **update_2**: Parity status, disk temps, disk I/O, array status, next parity check schedule +- **update_3**: CPU usage per core, CPU temperature +- **ups_status**: UPS power/battery status +- **vm_dashusage**: VM CPU/memory usage +- **wg_poller**: WireGuard tunnel status + +--- + +## 7. Main (Array Devices) + +**File:** `Main.page` (container) +**Sub-tabs:** + +### 7.1 Array Devices Tab +**File:** `ArrayDevices.page` +- **Table columns:** Device, Identification, Power/Temp, Reads, Writes, Errors, FS, Size, Used, Free +- **Per-disk rows:** Parity, Parity2, Disk1-DiskN +- **Status indicators:** Color orbs (green=normal, yellow=warning, red=error, grey=standby) +- **Click disk name** -> Device detail page +- **Totals row** at bottom (aggregate size/used/free) +- **Deprecated filesystem warnings** (reiserfs, etc.) +- **Data source:** `state/disks.ini`, `diskload.ini` +- **Nchan:** `device_list`, `disk_load`, `parity_list` + +### 7.2 Pool Devices Tab +**File:** `CacheDevices.page` +- **Same table structure** as array devices +- **Per-pool sections** with headers +- **Add Pool** button (dialog: pool name, filesystem type) +- **Add Bootable Pool** button +- **Add ZFS Subpool** button (special, logs, dedup, cache, spares) +- **Pool validation** (reserved names check, duplicate check) +- **Actions:** Format, Delete Pool, Balance, Scrub + +### 7.3 Boot Device Tab +**File:** `BootDevice.page` +- **Flash device info** (same columns as array devices) +- **Vendor, Product, GUID** + +### 7.4 Unassigned Devices Tab +**File:** `OpenDevices.page` +- **Lists all detected but unassigned storage devices** +- **Same table columns** as array devices +- **Conditional:** Only shows if unassigned devices exist + +### 7.5 Array Operation Tab +**File:** `ArrayOperation.page` +- **Start/Stop Array** buttons +- **Array status indicator** (orb color) +- **Maintenance Mode** checkbox +- **Encryption controls:** + - Passphrase input with show/hide toggle + - Keyfile upload + - Encryption status (Missing key, Wrong key) + - Reformat permission checkbox +- **Parity operations:** + - Start/Stop/Pause parity check + - Check/correct toggle + - Progress display with ETA + - Error count +- **Disk spin up/down** controls per disk and group +- **Clear statistics** button +- **Real-time I/O toggle** (reads/writes vs. throughput display) +- **Nchan:** `device_list`, `disk_load`, `parity_list` + +--- + +## 8. Shares + +**File:** `Shares.page` (container), conditional on array started +**Sub-tabs:** + +### 8.1 User Shares +**File:** `ShareList.page` +- **Table columns:** Name, Comment, SMB, NFS, Storage, Size, Free +- **Each share links** to ShareEdit page +- **SMB/NFS status** shows security level (Public/Secure/Private) +- **Compute All** button - calculates sizes for all shares +- **Add Share** button -> ShareEdit form +- **Clean Up** button - removes orphaned share configs +- **Data source:** `state/shares.ini`, computed via `ShareList.php` + +### 8.2 Disk Shares +**File:** `DiskList.page` +- **Table columns:** Name, Comment, SMB, NFS, Type, Size, Free +- **Per-disk share listing** +- **Compute All** button +- **Conditional:** Only if disk shares enabled + +### 8.3 Share Edit Page +**File:** `ShareEdit.page` (accessed via `Share?name=sharename`) +- **Share name** (immutable after creation) +- **Comment/description** +- **Allocation method:** High-water, Fill-up, Most-free +- **Minimum free space** (floor) +- **Split level** control +- **Included/Excluded disks** (multi-select dropdowns) +- **Primary storage:** Pool selection + use mode (Cache Yes/No/Only/Prefer) +- **Secondary storage:** Pool or Array selection +- **Copy-on-write** setting (Auto/Yes/No) + +### 8.4 Per-Share Security Settings +**SMB Security** (`SecuritySMB.page`): +- **Export:** Yes/No/Yes (Hidden) +- **Security:** Public/Secure/Private +- **Per-user access:** Read/Write, Read-only, No access +- **Clone settings** from another share + +**NFS Security** (`SecurityNFS.page`): +- **Export:** Yes/No +- **Security:** Public/Secure/Private +- **Host access list** (IP/subnet rules, multi-line textarea) +- **Clone settings** from another share + +--- + +## 9. Users + +**File:** `Users.page` (container), `UserList.page` (listing) + +### 9.1 User List +- **Two sections:** Management Access (root), Shares Access (regular users) +- **Per-user display:** Avatar image, username, description +- **Click user** -> UserEdit page +- **Add User** button -> UserAdd page +- **Data source:** `state/users.ini`, `/boot/config/plugins/dynamix/users/` + +### 9.2 Add User +**File:** `UserAdd.page` +- **Username** (lowercase, alphanumeric, underscores, dashes) +- **Description** +- **Custom image** (PNG drag-and-drop upload) +- **Password** with strength meter (zxcvbn.js) +- **Retype password** confirmation + +### 9.3 Edit User +**File:** `UserEdit.page` +- **Same fields** as Add User +- **Change password** +- **SSH Authorized Keys** textarea (for root user) + - Key format validation (RSA, DSA, ECDSA, Ed25519, SK keys) + - `from=` option validation (IP/hostname) +- **Delete user** capability + +--- + +## 10. Settings + +**File:** `Settings.page` (panel layout with icons) +**Layout:** Grid of icon panels linking to sub-pages +**Favorites support:** Heart icon to add settings pages to Favorites + +### 10.1 System Settings (Menu="OtherSettings") + +#### Identification +**File:** `Identification.page` +- Server name (NetBIOS compatible, max 15 chars) +- Description +- Model +- Requires array stopped to change + +#### Date and Time +**File:** `DateTime.page` +- Current date/time display +- Date format (7 formats) +- Time format (12h/24h) +- Time zone selection (from timezones.key) +- NTP server configuration (4 servers) +- PTP hardware clock selection per interface +- Use NTP/manual toggle + +#### Disk Settings +**File:** `DiskSettings.page` +- **Disk temperature warning/critical thresholds** (HDD and SSD separate) +- **Default filesystem** (xfs, btrfs, zfs, xfs encrypted, etc.) +- **Default allocation** (high-water, fill-up, most-free) +- **Spindown delay** (Never, 15min - 9hrs, 1-24hrs) +- **Spinup groups** (parallel spinup) +- **SMART monitoring:** Enable/disable, polling interval + - Event notification checkboxes per SMART attribute + - Custom attribute IDs + - Per-attribute thresholds +- **Encryption controls:** + - Current key status + - Change passphrase / keyfile + - Download keyfile + +#### Global Share Settings +**File:** `ShareSettings.page` +- **Enable user shares** (Yes/No) +- **Enable disk shares** (Yes/No/Auto) +- **Permitted disk shares** filter +- **Included/Excluded disks** (global) +- **Max open files** limit (from `/proc/sys/fs/file-max`) + +#### Network Settings +**File:** `NetworkSettings.page` (tabbed container) +- **Interface eth0** (`Eth0.page`) + - Enable bonding (modes: balance-rr, active-backup, balance-xor, broadcast, 802.3ad, balance-tlb, balance-alb) + - Enable bridging + - Interface members selection + - IPv4/IPv6 configuration (DHCP/Static) + - IP address, Netmask, Gateway + - Metric (gateway priority) + - DNS servers + - Jumbo frames (MTU 9000) + - VLANs (add VLAN interfaces) +- **Additional Interfaces** (`EthX.page`) - Dynamic per interface +- **Wireless wlan0** (`Wireless.page`) + - Enable WiFi + - Regulatory region + - SSID, Security (WPA2/WPA3) + - WiFi password + - IP configuration +- **Routing Table** (`RoutingTable.page`) + - Current routes display (auto-refreshing) + - Add static route (network, gateway, metric) + - Delete route +- **Interface Extra** (`NetworkExtra.page`) + - Include/Exclude specific interfaces +- **Interface Rules** (`NetworkRules.page`) + - MAC address to ethN mapping + - Persistent interface naming + +#### Management Access +**File:** `ManagementAccess.page` (tabbed) +- **Start page** selection +- **Port** (HTTP/HTTPS) +- **SSL certificate** management + - Self-signed certificate + - Let's Encrypt certificate (with auto-renewal) + - User-provided certificate + - Wildcard certificate support +- **Strict transport security** (HSTS) +- **Bind management** to specific interface +- **Telnet/SSH** enable/disable +- **Spin down/Spin up delay** for management operations + +#### Docker Settings +**File:** `DockerSettings.page` (in `dynamix.docker.manager`) +- **Enable Docker** (Yes/No) +- **Docker storage driver** (overlay2, btrfs, zfs) +- **Docker directory** path +- **Docker image** file location +- **Docker image size** +- **Docker custom networks** (bridge/macvlan/ipvlan) + - Subnet, Gateway, IP range + - IPv4/IPv6 configuration + - Parent interface selection +- **Docker log rotation** +- **Docker preservation mode** +- **Containers readmore** toggle + +#### VM Manager Settings +**File:** `VMSettings.page` (in `dynamix.vm.manager`) +- **Enable VMs** (Yes/No) +- **PCIe ACS override** (upstream/downstream/multifunction) +- **VFIO allow unsafe interrupts** +- **Libvirt storage** path +- **Default ISO/VirtIO** paths +- **Hugepages** configuration +- **Machine type** (i440fx/q35) +- **Hyper-V** enlightenments +- **OVMF UEFI** firmware path +- **VM usage statistics** enable +- **Network source** (virbr0/bridge/macvtap) +- **VM shutdown timeout** + +#### UPS Settings +**File:** `UPSsettings.page` (in `dynamix.apcupsd`) +- **Enable APC UPS daemon** +- **UPS cable** (USB/Simple/Smart/Ether/Custom) +- **UPS type** (USB/PCNET/SNMP) +- **Device** path +- **Battery level** for shutdown (%) +- **Minutes** for shutdown +- **Timeout** for shutdown +- **Kill on power back** delay +- **UPS Details** sub-tab: Full key-value status table (auto-refreshing every 3s) + +#### CPU Pinning +**File:** `CPUset.page` (tabbed container) +- **CPU Pinning VM** (`CPUvms.page`) - Per-VM CPU core assignment matrix +- **CPU Pinning Docker** (`CPUpin.page`) - Per-container CPU core assignment matrix +- **CPU Isolation** (`CPUisol.page`) - Isolate cores from system scheduler +- **Visual table** with checkboxes per CPU core per service +- **Intel hybrid core types** (P-core/E-core) display + +#### Power Mode +**File:** `PowerMode.page` +- **CPU governor selection:** + - Best power efficiency (powersave) + - Balanced performance (schedutil/ondemand) + - Best performance (performance) +- Shows unavailable modes +- Detects hypervisor environment + +### 10.2 Network Services (Menu="NetworkServices") + +#### SMB +**File:** `SMB.page` (tabbed container) +- **SMB Settings** (`SMBsettings.page`) + - Enable SMB (No/Yes Workgroup/Yes Active Directory) + - Hide dot files + - SMB Multi Channel + - Enhanced macOS interoperability + - NetBIOS + - Minimum/Maximum SMB protocol + - Fruit (macOS) support +- **Workgroup Settings** (`SMBWorkGroup.page`) + - Workgroup name + - Local master browser +- **SMB Extras** (`SMBExtras.page`) + - Extra smb.conf configuration (textarea) +- **Active Directory** (`SMBActiveDirectory.page`, conditional) + - AD domain name (FQDN) + - Short domain name + - Admin username/password + - Join/Leave domain + +#### NFS +**File:** `NFS.page` +- Enable NFS (Yes/No) +- NFS version (3/4) +- NFS threads count +- FUSE remember setting + +#### FTP Server +**File:** `FTP.page` +- Enable/Disable FTP server +- FTP user list + +#### Syslog Server +**File:** `SyslogSettings.page` +- Enable syslog server (receive remote logs) +- Server folder path +- Log rotation settings +- Remote syslog forwarding + +#### VPN Manager +**File:** `VPNmanager.page` (tabbed container) +- **WireGuard Tunnels** (`WG0.page`, `WGX.page`) + - Tunnel type (Remote access to LAN, Remote access to server, LAN-to-LAN, Remote tunneled) + - Local tunnel address, endpoint, DNS + - Peer configurations (name, public key, allowed IPs, persistent keepalive) + - Generate keys, QR codes + - Start/Stop tunnel + - Status: handshake time, transfer rx/tx + - Nchan: `wg_poller` + +#### Tailscale +**File:** `Tailscale.page` +- Install Tailscale plugin button +- (Full functionality added by plugin after install) + +#### Outgoing Proxy Manager +**File:** `OutgoingProxy.page` +- Up to 3 proxy configurations +- Proxy URL, username, password +- Active proxy selection +- No-proxy exclusion list + +### 10.3 User Preferences (Menu="UserPreferences") + +#### Display Settings +**File:** `DisplaySettings.page` +- **Language** selection +- **Number format** (1,000.00 vs 1.000,00) +- **Temperature unit** (Celsius/Fahrenheit) +- **Scale** (bytes display format) +- **Dashboard columns** layout +- **Show banner** (Yes/No) +- **Custom banner image** (PNG drag-and-drop upload) +- **Banner text color** / **background color** +- **Header custom text** +- **Font size** (slider/select) +- **Page viewer** refresh rate +- **Show array usage** in header +- **Show disk utilization** text/colors +- **Warning/Critical** usage thresholds +- **Tab mode** (all tabs / tabbed) +- **Favorites** feature enable + +#### Notification Settings +**File:** `Notifications.page` (tabbed) +- **System notifications** enable/disable +- **Per-category notification routing:** + - Categories: Array, Disk, Share, Docker, Network, Unraid, Plugin, Language, Report + - Channels: Browser, Email, Agents + - Levels: Normal, Warning, Alert +- **Browser notification** settings +- **Display position** (top-right, top-left, bottom-right, bottom-left) + +#### SMTP Settings +**File:** `SmtpSettings.page` +- Sending email address +- SMTP server, port +- Authentication (none, login, plain) +- Username, password +- SSL/TLS settings (None, SSL, STARTTLS) +- Send test email button + +#### Notification Agents +**File:** `NotificationAgents.page` +- **Built-in agents** (each with XML config): + - Discord, Slack, Telegram, Pushover, Pushbullet + - Gotify, ntfy.sh, Prowl, Join, Boxcar + - Bark, PushBits, Pushplus, ServerChan +- Per-agent: Enable/disable, API keys/webhooks, test button + +#### Scheduler +**File:** `Scheduler.page` (tabbed container) +- **Parity Check** (`ParityCheck.page`) + - Schedule (Disabled/Daily/Weekly/Monthly/Yearly/Custom) + - Day, day of month, time selection + - Custom: multi-day, week selection + - Write corrections (Yes/No) + - Cumulative (resume) option + - Frequency (every N scheduled runs) + - Pause/Resume during hours +- **Mover Settings** (`MoverSettings.page`) + - Mover schedule (Disabled/Hourly/Daily/Weekly/Monthly) + - Move Now button + - Mover logging + - Mover tuning action +- **TRIM Settings** (`TrimSettings.page`) + - SSD TRIM schedule + - TRIM Now button + - Per-pool/device include list + +#### Console Settings +**File:** `Console.page` +- Keyboard layout selection (40+ layouts) +- Console font +- Terminal shell + +--- + +## 11. Plugins + +**File:** `Plugins.page` (tabbed container, in `dynamix.plugin.manager`) +**Sub-tabs:** + +### 11.1 Installed Plugins +- **Plugin table:** Name, Author, Version, Status, Update available +- **Per-plugin actions:** + - Update (if available) + - Remove (checkbox for bulk) + - Show changelog +- **Update All** button +- **Remove Selected** button (bulk) +- **Check for Updates** button +- **Data source:** `/var/log/plugins/*.plg`, `/tmp/plugins/*.plg` + +### 11.2 Install Plugin +**File:** `PluginInstall.page` +- **URL input** for remote .plg file +- **Force Install** checkbox (allows same/older version) +- **Local file browser** (browse `/boot/` for .plg files) +- Opens plugin installation window + +### 11.3 Plugin Errors +**File:** `PluginsError.page` +- Shows plugins with errors/warnings + +### 11.4 Stale Plugins +**File:** `PluginsStale.page` +- Shows plugins not compatible with current OS version + +--- + +## 12. Docker + +**File:** `Docker.page` (container, in `dynamix.docker.manager`) +**Conditional:** Docker must be enabled and running + +### 12.1 Docker Containers +**File:** `DockerContainers.page` +- **Container table columns:** + - Application (icon + name, draggable order) + - Version (with update indicator) + - Network (bridge/host/macvlan/ipvlan/custom) + - Container IP + - Container Port(s) + - LAN IP:Port mappings + - Volume Mappings (App to Host) + - CPU & Memory load (advanced view) + - Autostart toggle (switch button) + - Uptime +- **Per-container context menu** (right-click): + - Start / Stop / Restart / Pause / Resume + - Logs (opens log viewer) + - Edit (opens template editor) + - Remove (with image option) + - WebUI link + - Console (shell into container) + - Update (if available) + - Force update + - Rebuild (advanced) +- **Global buttons:** + - Add Container + - Start All / Stop All + - Pause All / Resume All + - Check for Updates + - Update All (if updates available) + - Container Size (popup showing disk usage) +- **Drag-and-drop reorder** (when unlocked) +- **Basic/Advanced view toggle** +- **Auto-start wait time** (seconds between container starts) +- **Real-time Nchan:** `docker_load` (CPU/Memory per container) +- **Data source:** Docker API (`DockerClient.php`), container templates + +### 12.2 Add/Edit Container +**File:** `AddContainer.page`, `UpdateContainer.page` +- **Template system** (XML templates from Community Applications) +- **Basic mode / Advanced mode** toggle +- **Fields:** + - Container name + - Repository (Docker Hub image) + - Registry URL + - Icon URL + - Network type + - IP address (if macvlan/ipvlan) + - Privileged mode + - CPU pinning + - Console shell + - WebUI URL template + - Port mappings (container:host, TCP/UDP) + - Volume mappings (container:host, RW/RO) + - Environment variables + - Labels + - Extra parameters + - Post arguments +- **Apply button** (pulls image if needed, creates/updates container) + +### 12.3 Docker Settings +**File:** `DockerSettings.page` +(See Settings section 10.1 above) + +--- + +## 13. VMs + +**File:** `VMs.page` (container, in `dynamix.vm.manager`) +**Conditional:** libvirtd must be running + +### 13.1 Virtual Machines +**File:** `VMMachines.page` +- **VM table per machine:** + - Icon + Name + Description + - Status indicator (running/stopped/paused) + - CPU pinning display + - Memory allocation + - vDisks list with sizes + resize capability + - Graphics (VNC/SPICE) type + - CD-ROM media selection (ISO swap dialog) + - Autostart toggle + - Snapshots management +- **Per-VM context menu:** + - Start / Stop (graceful) / Force Stop + - Pause / Resume + - Restart + - Hibernate / Resume from hibernate + - VNC/SPICE remote viewer + - noVNC in browser + - Logs + - Edit VM + - Clone VM + - Remove VM (with vdisk option) + - Snapshot: Create / Revert / Delete + - XML: Edit raw XML +- **VM Operations:** + - Add VM + - Start/Stop libvirt service +- **Drag-and-drop reorder** (when unlocked) + +### 13.2 VM Templates +**File:** `VMTemplates.page` +- **Pre-configured OS templates:** + - Windows 11, Windows 10, Windows Server 2022/2019 + - Ubuntu, Debian, Fedora, CentOS, Arch Linux, OpenSUSE + - FreeBSD, TrueNAS, etc. +- **User-saved templates** (custom JSON) +- **Import/Upload template** buttons +- **Each template pre-fills** the AddVM form + +### 13.3 Add/Edit VM +**File:** `AddVM.page`, `UpdateVM.page` +- **VM configuration form:** + - Name + - Description + - CPU mode (Host Passthrough / Emulated) + - Logical CPUs (core/thread selection with visual grid) + - Initial Memory / Max Memory + - Machine type (i440fx / Q35) + - BIOS (OVMF / SeaBIOS) + - Hyper-V enlightenments + - USB controllers + - OS Install ISO + - VirtIO Drivers ISO + - vDisk Location, Size, Type, Bus (VirtIO/SATA/SCSI/IDE) + - Graphics Card (VNC/GPU passthrough) + - Sound Card + - Network Bridge/Source, MAC address, Model + - PCIe device passthrough (from System Devices) + - USB device passthrough +- **File tree picker** for ISO/vDisk paths +- **VNC viewer:** noVNC (HTML5) and native VNC client links +- **SPICE viewer:** spice.html + +### 13.4 VM Usage Statistics +**File:** `VMUsageStats.page` +- **Real-time table:** Name, Guest CPU%, Host CPU%, Memory (inuse/current/max), Disk IO, Network IO +- **Nchan:** `vm_usage` +- **Conditional:** Only if USAGE=Y in domain.cfg + +### 13.5 VM Settings +**File:** `VMSettings.page` +(See Settings section 10.1 above) + +--- + +## 14. Tools + +**File:** `Tools.page` (panel layout with icons) +**Layout:** Grid of icon panels, supports favorites + +### 14.1 Unraid OS Sub-menu (Menu="UNRAID-OS") + +#### System Log +**File:** `Syslog.page` +- **Live syslog viewer** in pre-formatted text area +- **Download syslog** as zip +- **Previous boot log** selector +- **Remote syslog server logs** (if configured) +- **Auto-scroll** to bottom +- **Max 5000 lines** display + +#### Log Viewer (new) +**File:** `LogViewer.page` +- **Web component:** `` +- Modern log viewer implementation + +#### Diagnostics +**File:** `Diagnostics.page` +- **Download diagnostics** zip bundle +- **Anonymize** option (remove sensitive data) +- **Progress display** via Nchan during collection +- Collects: syslog, SMART reports, configs, docker info, etc. + +#### New Config +**File:** `NewConfig.page` +- **Reset array configuration** (all disks appear as "New") +- **Preserve assignments:** All / Array slots / Pool slots (multi-select) +- **Confirmation checkbox** required +- **Warning:** Cannot be used to rebuild failed drives + +#### New Permissions +**File:** `NewPerms.page` +- **Reset file/directory ownership** to nobody/users (99/100) +- **Target selection:** By Disks or By Shares (multi-select) +- **Sets permissions:** + - Directories: drwxrwxrwx + - RW files: -rw-rw-rw- + - RO files: -r--r--r-- +- Opens background process window + +#### System Devices +**File:** `SysDevs.page` +- **PCI device listing** with filter toggles: + - Show All / Filtered + - Show GPUs/Audio + - Show Networks + - Show Storage + - Show USB + - Show all other devices + - Show SR-IOV +- **Per-device:** Vendor, Device, IOMMU group, Driver in use +- **VFIO bind/unbind** for GPU passthrough +- **SR-IOV virtual function** management +- **Apply button** for VFIO changes + +#### System Drivers +**File:** `SysDrivers.page` +- **Driver listing** with filter: + - Search box + - Filter: All / In Use +- **Table columns:** Module, Description, Status (System/Inuse/Custom/Disabled) +- **Per-driver:** Enable/Disable, Custom modprobe options +- **Rebuild database** button +- **Sortable/filterable** table (tablesorter.js) + +#### Hardware Profile +**File:** `HardwareProfile.page` +- **Upload hardware profile** to Lime Technology +- **Show/Hide details** (XML hardware data) +- **Last submitted** date display + +#### Processes +**File:** `Processes.page` +- **`ps -aux` output** in pre-formatted text + +#### Open Terminal +**File:** `Terminal.page` +- **Opens ttyd** web terminal in popup +- Auto-redirects back to previous page + +### 14.2 WebGui Sub-menu (Menu="WebGui") + +#### Vars (Debug) +**File:** `Vars.page` +- **Dumps all PHP variables:** `$_SERVER`, `$devs`, `$disks`, `$sec`, `$sec_nfs`, `$shares`, `$users`, `$var` +- **Environment variables** (proxy settings) +- Raw `print_r()` output in pre-formatted text + +#### PHP Settings +**File:** `PHPsettings.page` +- **Error reporting level** (Default / All Categories / Errors Only) +- **Display errors on screen** toggle +- **PHP Info** button (phpinfo() popup) +- **View Log** / **Clear Log** buttons +- **Log size** display + +### 14.3 Other Tools + +#### About +**File:** `About.page` +- **Credits and version information** +- **Unraid OS changelog** + +#### Registration / Install Key +**File:** `InstallKey.page` +- **Registration key URL** input +- **Install Key** button +- **Key file upload** + +--- + +## 15. About + +**File:** `About.page` +- Accessible from Tools menu +- Credits page with version information + +--- + +## 16. Apps (Community Applications) + +**File:** `Apps.page` +- **Default:** Shows install button for Community Applications plugin +- **After CA installed:** Full app store with categories: + - Containers (Docker templates) + - Plugins + - Language packs + - Search, Filter, Sort capabilities + - One-click install + +--- + +## 17. Favorites + +**File:** `Favorites.page`, `MyFavorites.page` +- **Favorites panel** appears when favorites exist +- **Add to favorites:** Heart icon on Settings/Tools panels +- **Remove from favorites** via MyFavorites management +- **Stored in:** `/boot/config/favorites.cfg` + +--- + +## 18. Device Detail Pages + +**Accessed via:** `/Main/Device?name=diskN` or `/Main/New?name=sdX` +**File:** `Device.page` (tabbed container) + +### 18.1 Device Settings Tab +**File:** `DeviceInfo.page` +- **Disk assignment** (slot selection for array) +- **File system type** (xfs/btrfs/zfs) +- **SMART settings** per disk: + - SMART monitoring schedule (Disabled/Hourly/Daily/Weekly/Monthly) + - Custom SMART attributes + - SMART notification thresholds +- **Partition layout** +- **Format** button (with confirmation) +- **Pool operations:** Balance, Scrub, Check +- **Spin Up/Down** controls +- **Clear statistics** +- **Previous/Next disk** navigation arrows + +### 18.2 SMART Attributes Tab +**File:** `DeviceAttributes.page` +- **Full SMART attribute table:** + - #, Attribute Name, Flag, Value, Worst, Threshold, Type, Updated, Failed, Raw Value +- **Data source:** `smartctl` via `SmartInfo.php` + +### 18.3 SMART Identity Tab +**File:** `DeviceIdentify.page` +- **Device identification** table (model, serial, firmware, capacity, etc.) +- **Custom notes** per disk (stored in DiskLog) + +### 18.4 SMART Capabilities Tab +**File:** `DeviceCapabilities.page` +- **SMART capability flags** and features + +### 18.5 Self-Test Tab +**File:** `Selftest.page` +- **Download SMART report** button +- **Self-test history** (show/hide) +- **Error log** (show/hide) +- **Short self-test** Start button +- **Extended self-test** Start button +- **Last test result** display (real-time) + +### 18.6 SMB Security Tab +**File:** `SecuritySMB.page` +(See Shares section) + +### 18.7 NFS Security Tab +**File:** `SecurityNFS.page` +(See Shares section) + +### 18.8 Flash Device Detail +**File:** `Flash.page` (tabbed) +- **Flash Device Settings** (`FlashInfo.page`) + - Flash Vendor, Product, GUID + - Registration Key Manager link + - Flash Backup download button +- **SMART/Identity** tabs +- **Syslinux Configuration** (`BootParameters.page`) + - Menu View / Raw View toggle + - Boot parameters GUI: + - VM Passthrough (PCIe ACS override, VFIO unsafe interrupts) + - GPU settings (efifb:off, video params) + - Power Management (C-states, ACPI) + - Boot Menu settings + - Raw syslinux.cfg editor + - Automatic backup on save +- **GRUB Configuration** (`Grub.page`, if GRUB boot) + - GRUB config editor textarea + - Default config restore button +- **Boot Mode** (`BootMode.page`) + - Current boot mode (UEFI/Legacy) + - UEFI boot mode toggle + +--- + +## 19. File Browser + +**File:** `Browse.page` +- **Accessed via:** `/Main/Browse?dir=/mnt/user/sharename` +- **Full file manager** with: + - **File tree** navigation (jQuery FileTree) + - **Breadcrumb** path navigation + - **File listing table:** Name, Size, Date Modified, Owner/Perms + - **Actions:** + - Upload files (drag-and-drop) + - Create new folder + - Create new file + - Rename + - Delete (with confirmation) + - Move/Copy (dialog with destination picker) + - Download + - Edit (inline text editor for configured file types) + - Change permissions/ownership + - **Context menu** (right-click) + - **Multiple selection** (checkboxes) + - **Real-time transfer stats** (upload/download speed) + - **Nchan:** `file_manager` (real-time file system monitoring) + - **Restricted to:** `/mnt/` and `/boot/` paths only + +--- + +## 20. Notification System + +### Architecture +- **Backend:** `scripts/notify` - Shell script for creating/reading notifications +- **Storage:** Notification files in `/tmp/notifications/` +- **Transport:** Nchan WebSocket (`nchan/notify_poller`) +- **Frontend:** Toast notifications + notification archive + +### Notification Types +- **Normal** (blue) - Informational +- **Warning** (yellow) - Warning conditions +- **Alert** (red) - Critical alerts + +### Notification Sources +- Array events (disk errors, parity issues) +- Docker container updates +- Plugin updates +- OS updates +- SMART disk warnings +- Temperature alerts +- UPS power events +- Custom plugin notifications +- Scheduled task completions + +### Notification Channels +1. **Browser** - Toast notifications in WebGUI +2. **Email** - Via SMTP settings +3. **Agents** - 14 supported services (Discord, Slack, Telegram, etc.) + +### Notification UI +- **Bell icon** in header with unread count badge +- **Click opens** notification panel/popup +- **Mark as read / Dismiss all** +- **Archive** access +- **Toast popup** for real-time alerts (configurable position) + +--- + +## 21. Real-Time Monitoring (Nchan/WebSocket) + +### Nchan Scripts (PHP long-running processes) +Located in `plugins/dynamix/nchan/`: + +| Script | Publishes To | Data | Update Interval | +|--------|-------------|------|-----------------| +| `update_1` | `/sub/update1` | RAM, system temps, fans, flash/log/docker df, shares | Varies | +| `update_2` | `/sub/update2` | Parity status, disk temps/IO, array status, scheduling | Varies | +| `update_3` | `/sub/update3` | CPU per-core usage, CPU temperature | ~2s | +| `device_list` | `/sub/device_list` | Disk device table rows (HTML) | On change | +| `disk_load` | `/sub/diskload` | Disk I/O rates (reads/writes bytes/sec) | 2s (bash) | +| `parity_list` | `/sub/parity_list` | Parity check progress, ETA | During check | +| `notify_poller` | `/sub/notify` | Notification messages | 3s poll | +| `session_check` | `/sub/session` | Session timeout check | Periodic | +| `ups_status` | `/sub/ups_status` | UPS battery/power status | Periodic | +| `vm_dashusage` | `/sub/vm_dashusage` | VM CPU/memory stats | Periodic | +| `wg_poller` | `/sub/wg_poller` | WireGuard tunnel status | Periodic | +| `wlan0` | `/sub/wlan0` | WiFi signal/connection status | Periodic | +| `file_manager` | `/sub/file_manager` | File system changes | On change | + +Located in `plugins/dynamix.docker.manager/nchan/`: + +| Script | Publishes To | Data | +|--------|-------------|------| +| `docker_load` | `/sub/dockerload` | Container CPU/memory/IO | + +Located in `plugins/dynamix.vm.manager/nchan/`: + +| Script | Publishes To | Data | +|--------|-------------|------| +| `vm_usage` | `/sub/vm_usage` | VM CPU/memory/disk/network stats | + +### Client-Side WebSocket +```javascript +var nchan = new NchanSubscriber('/sub/update1', {subscriber:'websocket'}); +nchan.on('message', function(data) { + // Parse JSON data and update DOM elements +}); +nchan.start(); +``` + +--- + +## 22. Modal Dialogs & Wizards + +### Dialog Framework +- **SweetAlert** (`jquery.sweetalert.css`) - Confirmation dialogs, alerts, warnings +- **jQuery UI Dialog** - Complex forms (file tree, pool creation, ISO selection) + +### Key Dialogs + +1. **Add Pool** - Pool name input + filesystem type selection +2. **Add Bootable Pool** - Like Add Pool with boot support +3. **Add ZFS Subpool** - Subpool type selection (special/logs/dedup/cache/spares) +4. **ISO Selection** - File tree browser for VM CD-ROM +5. **VM Disk Resize** - New capacity input +6. **Docker Container Log** - Real-time log viewer in iframe +7. **Plugin Install Progress** - Command output window +8. **Flash Backup Progress** - Spinner with status +9. **Diagnostics Collection** - Progress with Nchan updates +10. **Parity Check Confirmation** - Warning with options +11. **New Config Confirmation** - Safety confirmation +12. **Share Cleanup** - Confirmation + results +13. **Docker Container Size** - Popup with disk usage per container +14. **SMART Report Save** - Background zip + auto-download +15. **Array Start/Stop Confirmation** - Encryption key input if needed +16. **Plugin Alert Messages** - Pre-update alerts/changelogs + +### Progress Frame +- **`update.htm`** - Hidden iframe for form POST targets +- Shows command execution progress +- Auto-refreshes parent page on completion + +--- + +## 23. Themes + +**Available Themes:** +| Theme | Type | Description | +|-------|------|-------------| +| `azure` | Top Nav | Light theme (default), blue accents | +| `gray` | Top Nav | Dark theme, gray accents | +| `black` | Sidebar | Dark theme, sidebar navigation | +| `white` | Sidebar | Light theme, sidebar navigation | + +### Theme Files +- `styles/themes/azure.css` +- `styles/themes/gray.css` +- `styles/themes/black.css` +- `styles/themes/white.css` + +### Theme Switcher +- `` web component in footer +- Instant theme change without page reload +- Persisted in display settings + +### Theme Helper Class (`ThemeHelper.php`) +```php +$themeHelper = new ThemeHelper($display['theme'], $display['width']); +$themeHelper->isTopNavTheme(); // azure, gray +$themeHelper->isSidebarTheme(); // black, white +$themeHelper->isLightTheme(); // azure, white +$themeHelper->getThemeName(); +$themeHelper->getThemeHtmlClass(); +``` + +### Customization +- Custom banner image (PNG upload) +- Banner text color (hex) +- Banner background color (hex) +- Font size (percentage) + +--- + +## 24. Authentication & Login + +### Login Page +**File:** `login.php` +- Username/password form +- "Remember me" option +- SSL certificate info +- Redirect to requested page after login + +### Authentication +**File:** `auth-request.php` +- nginx auth_request sub-request handler +- Session-based authentication +- CSRF token validation (`$var['csrf_token']`) +- Session timeout with Nchan check + +### Password Management +**File:** `include/.set-password.php` +- Password hashing +- Base64 encoding for transmission +- zxcvbn.js strength meter (if installed) +- Max 128 characters + +--- + +## 25. Data Sources + +### State INI Files (`/var/local/emhttp/`) +Generated by `emhttp` daemon, read by PHP pages: + +| File | Key Variables | +|------|---------------| +| `var.ini` | `fsState`, `mdState`, `mdColor`, `mdNumDisks`, `mdResyncPos`, `mdResyncSize`, `mdResyncCorr`, `csrf_token`, `NAME`, `COMMENT`, `regTy`, `regFILE`, `flashGUID`, `flashProduct`, `flashVendor`, `timeZone`, `luksKeyfile`, `safeMode`, `SYS_ARRAY_SLOTS` | +| `disks.ini` | Per-disk sections: `name`, `device`, `id`, `type` (Parity/Data/Cache/Flash), `status`, `color`, `temp`, `numReads`, `numWrites`, `numErrors`, `fsType`, `fsSize`, `fsUsed`, `fsFree`, `fsStatus`, `transport`, `spindownDelay`, `smLevel`, `smEvents` | +| `shares.ini` | Per-share: `name`, `comment`, `allocator`, `floor`, `splitLevel`, `include`, `exclude`, `useCache`, `cachePool`, `cachePool2`, `cow`, `export`, `security` | +| `devs.ini` | Unassigned devices (same fields as disks) | +| `sec.ini` | SMB security per share (per-user access levels) | +| `sec_nfs.ini` | NFS security per share (host lists) | +| `network.ini` | Interface configs (bonding, bridging, VLANs) | +| `nginx.ini` | `NGINX_LANIP`, `NGINX_LANIP6`, `NGINX_WANIP`, `NGINX_BIND` | +| `diskload.ini` | `sdX=read_bytes write_bytes read_ops write_ops` per disk | +| `cpuload.ini` | CPU utilization data | +| `wireless.ini` | WiFi status | + +### System Files +| Source | Data | +|--------|------| +| `/proc/meminfo` | RAM Total/Available | +| `/proc/stat` | CPU usage per core | +| `/proc/diskstats` | Disk I/O counters | +| `/sys/class/net/` | Network interfaces | +| `/sys/devices/system/cpu/` | CPU frequency/governor | +| `sensors -uA` | Temperatures, fan speeds | +| `smartctl` | SMART disk attributes | +| `apcaccess` | UPS status | +| `wg show` | WireGuard tunnel status | +| `docker ps` / Docker API | Container status | +| `virsh` / libvirt API | VM status | + +### Configuration Files (`/boot/config/`) +| File | Purpose | +|------|---------| +| `plugins/dynamix/dynamix.cfg` | Display/UI settings | +| `shares/*.cfg` | Per-share configuration | +| `network-extra.cfg` | Extra network interfaces | +| `network-rules.cfg` | Interface MAC rules | +| `smb-extra.conf` | Extra Samba config | +| `rsyslog.cfg` | Syslog server settings | +| `wireless.cfg` | WiFi configuration | +| `domain.cfg` | VM Manager settings | +| `docker.cfg` | Docker settings | +| `ssh/root/authorized_keys` | SSH public keys | +| `favorites.cfg` | Dashboard favorites | +| `dashboard_settings.json` | Dashboard tile layout | +| `editor.cfg` | File browser editor extensions | + +--- + +## 26. JavaScript Libraries + +| Library | File | Purpose | +|---------|------|---------| +| dynamix.js | `javascript/dynamix.js` | Core WebGUI JavaScript (timers, navigation, helpers) | +| jQuery | (bundled) | DOM manipulation, AJAX | +| jQuery UI | (bundled) | Dialogs, sortable, tabs, dropdowns | +| jQuery TableSorter | `jquery.tablesorter.widgets.js` | Table sorting, filtering, sticky headers | +| jQuery SweetAlert | (CSS only) | Beautiful alert dialogs | +| jQuery FileTree | `jquery.filetree.js` | File/directory browser | +| jQuery FileDrop | `jquery.filedrop.js` | Drag-and-drop file upload | +| jQuery SwitchButton | `jquery.switchbutton.js` | Toggle switches | +| jQuery Base64 | `jquery.base64.js` | Base64 encoding | +| ApexCharts | `jquery.apexcharts.js` | Dashboard charts (donut, area) | +| SmoothieCharts | `smoothie.js` | Real-time streaming charts | +| ACE Editor | `javascript/ace/` | Code editor (for config files) | +| NchanSubscriber | (inline) | WebSocket pub/sub client | +| EZView | `EZView.js` | Image viewer | +| zxcvbn | (optional) | Password strength estimation | + +--- + +## 27. CSS Architecture + +### Base Styles +| File | Purpose | +|------|---------| +| `default-fonts.css` | Font face definitions (Clear Sans, Bitstream) | +| `default-cases.css` | Icon font definitions (font-cases.woff, font-unraid.woff) | +| `font-awesome.css` | FontAwesome 4.x icons | +| `default-color-palette.css` | CSS custom properties (colors) | +| `default-base.css` | Base layout, typography | +| `default-dynamix.css` | Component styles (tables, forms, panels) | +| `context.standalone.css` | Context menu styles | +| `jquery.sweetalert.css` | SweetAlert dialog styles | +| `jquery.ui.css` | jQuery UI component styles | +| `jquery.filetree.css` | File tree browser styles | +| `jquery.switchbutton.css` | Toggle switch styles | + +### Icon Fonts +| Font | File | Purpose | +|------|------|---------| +| font-cases | `font-cases.woff` | Device/disk icons | +| font-unraid | `font-unraid.woff` | Navigation icons (Unraid custom) | +| docker-icon | `docker-icon.woff` | Docker whale icon | +| FontAwesome | `font-awesome.woff` | General icons (FA 4.x) | + +### CSS Custom Properties +```css +:root { + --customer-header-background-image: url(banner.png); + --customer-header-text-color: #hex; + --customer-header-background-color: #hex; + --custom-font-size: 100%; +} +``` + +--- + +## Event System + +### Server Events (`plugins/dynamix/event/`) +Events triggered by system state changes: + +| Event Directory | Trigger | +|----------------|---------| +| `disks_mounted/` | After array disks are mounted | +| `docker_started/` | After Docker daemon starts | +| `driver_loaded/` | After a driver is loaded | +| `unmounting_disks/` | Before array disks are unmounted | + +### Service Management (`/etc/rc.d/`) +Key service scripts: +- `rc.docker` - Docker daemon control +- `rc.libvirt` - Libvirt/KVM control +- `rc.nginx` - Web server control +- `rc.php-fpm` - PHP-FPM control +- `rc.samba` - Samba/SMB control +- `rc.nfsd` - NFS server control +- `rc.sshd` - SSH daemon control +- `rc.apcupsd` - APC UPS daemon +- `rc.wireguard` - WireGuard VPN +- `rc.smartd` - SMART monitoring daemon +- `rc.crond` - Cron scheduler +- `rc.rsyslogd` - System logging +- `rc.ntpd` - NTP time sync +- `rc.avahidaemon` - mDNS/Avahi +- `rc.wireless` - WiFi management + +--- + +## Summary Statistics + +| Category | Count | +|----------|-------| +| **Total .page files (dynamix)** | ~85 | +| **Total .page files (docker.manager)** | 5 | +| **Total .page files (vm.manager)** | 7 | +| **Total .page files (plugin.manager)** | 5 | +| **Total .page files (apcupsd)** | 2 | +| **Total .page files (gui.search)** | 1 | +| **Total PHP include files** | ~80+ | +| **Total Nchan scripts** | ~15 | +| **Total JavaScript files** | ~12+ | +| **Total CSS files** | ~15+ | +| **Total notification agents** | 14 | +| **Available themes** | 4 | +| **State INI files** | ~12 | +| **RC service scripts** | ~40 | diff --git a/docs/unraid-ui-project/homarr-architecture.md b/docs/unraid-ui-project/homarr-architecture.md new file mode 100644 index 000000000..df6803462 --- /dev/null +++ b/docs/unraid-ui-project/homarr-architecture.md @@ -0,0 +1,60 @@ +# Homarr Architecture + +## Tech Stack +- Next.js 13+ (App Router), React 18, TypeScript +- Mantine UI (component library) +- Zustand (client state), React Query (server state) +- Prisma ORM (SQLite default / PostgreSQL) +- Turbo monorepo, pnpm workspaces + +## Project Structure +``` +homarr/ +├── apps/web/src/ # Main Next.js app +│ ├── app/ # App Router pages +│ ├── components/ # React components +│ ├── modules/ # Widgets & integrations +│ ├── stores/ # Zustand stores +│ └── styles/ # Themes & global CSS +├── packages/ +│ ├── api-client/ # API client lib +│ ├── common/ # Shared types/utils +│ ├── definitions/ # Widget/integration defs +│ ├── auth/ # Auth logic +│ └── ui/ # Shared UI components +├── prisma/ # DB schema & migrations +└── turbo.json +``` + +## Widget System +Each widget in `apps/web/src/modules/`: +- `definition.ts` - Metadata + Zod config schema +- `component.tsx` - React component +- `settings.tsx` - Config panel +- `server-actions.ts` - Backend operations +- Registered in module index, auto-discovered + +## Integration System +External service connectors with: +- API client abstraction, credential management +- URL/hostname config, SSL handling +- Error handling, retry, rate limiting, caching + +## Theming +- CSS variables + Mantine theming + Tailwind +- Light/dark mode, custom color palettes, accent colors +- Wallpaper/background, font size, border radius customization +- Theme persisted in database + +## Adding New Pages +1. Create in `apps/web/src/app/(group)/page-name/page.tsx` +2. Use Mantine UI components +3. Add API routes in `src/app/api/` +4. Create Zustand store or use React Query +5. Update navigation config + +## Key Patterns +- Server Components by default, `'use client'` for interactive +- TRPC for type-safe RPC +- Zod schemas for validation +- Prisma for DB operations diff --git a/docs/unraid-ui-project/orchis-design-system.ts b/docs/unraid-ui-project/orchis-design-system.ts new file mode 100644 index 000000000..3f686dc06 --- /dev/null +++ b/docs/unraid-ui-project/orchis-design-system.ts @@ -0,0 +1,1329 @@ +/** + * Orchis GTK Theme - Complete Design Token System + * ================================================ + * Extracted from: https://github.com/vinceliuice/Orchis-theme + * Based on Google Material Design with custom Orchis adaptations + * + * This file provides a complete CSS/design token system for a Next.js + * web application, faithfully representing the Orchis GTK theme. + */ + +// ============================================================================ +// 1. COLOR PALETTES - ALL VARIANTS +// ============================================================================ + +/** + * --- MATERIAL DESIGN BASE PALETTE --- + * Orchis uses the standard Material Design 2014 color palette as its foundation. + * Each color has shades from 50 (lightest) to 900 (darkest) plus accent variants. + */ +export const materialPalette = { + red: { + 50: "#FFEBEE", 100: "#FFCDD2", 200: "#EF9A9A", 300: "#E57373", + 400: "#EF5350", 500: "#F44336", 600: "#E53935", 700: "#D32F2F", + 800: "#C62828", 900: "#B71C1C", + a100: "#FF8A80", a200: "#FF5252", a400: "#FF1744", a700: "#D50000", + }, + pink: { + 50: "#FCE4EC", 100: "#F8BBD0", 200: "#F48FB1", 300: "#F06292", + 400: "#EC407A", 500: "#E91E63", 600: "#D81B60", 700: "#C2185B", + 800: "#AD1457", 900: "#880E4F", + a100: "#FF80AB", a200: "#FF4081", a400: "#F50057", a700: "#C51162", + }, + purple: { + 50: "#F3E5F5", 100: "#E1BEE7", 200: "#CE93D8", 300: "#BA68C8", + 400: "#AB47BC", 500: "#9C27B0", 600: "#8E24AA", 700: "#7B1FA2", + 800: "#6A1B9A", 900: "#4A148C", + a100: "#EA80FC", a200: "#E040FB", a400: "#D500F9", a700: "#AA00FF", + }, + deepPurple: { + 50: "#EDE7F6", 100: "#D1C4E9", 200: "#B39DDB", 300: "#9575CD", + 400: "#7E57C2", 500: "#673AB7", 600: "#5E35B1", 700: "#512DA8", + 800: "#4527A0", 900: "#311B92", + a100: "#B388FF", a200: "#7C4DFF", a400: "#651FFF", a700: "#6200EA", + }, + indigo: { + 50: "#E8EAF6", 100: "#C5CAE9", 200: "#9FA8DA", 300: "#7986CB", + 400: "#5C6BC0", 500: "#3F51B5", 600: "#3949AB", 700: "#303F9F", + 800: "#283593", 900: "#1A237E", + a100: "#8C9EFF", a200: "#536DFE", a400: "#3D5AFE", a700: "#304FFE", + }, + blue: { + 50: "#E3F2FD", 100: "#BBDEFB", 200: "#90CAF9", 300: "#64B5F6", + 400: "#42A5F5", 500: "#2196F3", 600: "#1E88E5", 700: "#1976D2", + 800: "#1565C0", 900: "#0D47A1", + a100: "#82B1FF", a200: "#448AFF", a400: "#2979FF", a700: "#2962FF", + }, + teal: { + 50: "#E0F2F1", 100: "#B2DFDB", 200: "#80CBC4", 300: "#4DB6AC", + 400: "#26A69A", 500: "#009688", 600: "#00897B", 700: "#00796B", + 800: "#00695C", 900: "#004D40", + a100: "#A7FFEB", a200: "#64FFDA", a400: "#1DE9B6", a700: "#00BFA5", + }, + green: { + 50: "#E8F5E9", 100: "#C8E6C9", 200: "#A5D6A7", 300: "#81C784", + 400: "#66BB6A", 500: "#4CAF50", 600: "#43A047", 700: "#388E3C", + 800: "#2E7D32", 900: "#1B5E20", + a100: "#B9F6CA", a200: "#69F0AE", a400: "#00E676", a700: "#00C853", + }, + yellow: { + 50: "#FFFDE7", 100: "#FFF9C4", 200: "#FFF59D", 300: "#FFF176", + 400: "#FFEE58", 500: "#FFEB3B", 600: "#FDD835", 700: "#FBC02D", + 800: "#F9A825", 900: "#F57F17", + a100: "#FFFF8D", a200: "#FFFF00", a400: "#FFEA00", a700: "#FFD600", + }, + orange: { + 50: "#FFF3E0", 100: "#FFE0B2", 200: "#FFCC80", 300: "#FFB74D", + 400: "#FFA726", 500: "#FF9800", 600: "#FB8C00", 700: "#F57C00", + 800: "#EF6C00", 900: "#E65100", + a100: "#FFD180", a200: "#FFAB40", a400: "#FF9100", a700: "#FF6D00", + }, + grey: { + 50: "#FAFAFA", 100: "#F5F5F5", 200: "#EEEEEE", 300: "#E0E0E0", + 400: "#BDBDBD", 500: "#9E9E9E", 600: "#757575", 700: "#616161", + 800: "#424242", 900: "#212121", + }, + blueGrey: { + 50: "#ECEFF1", 100: "#CFD8DC", 200: "#B0BEC5", 300: "#90A4AE", + 400: "#78909C", 500: "#607D8B", 600: "#546E7A", 700: "#455A64", + 800: "#37474F", 900: "#263238", + }, +} as const; + + +/** + * --- ORCHIS CUSTOM GREY SCALE --- + * Orchis defines a more granular grey scale (050 through 950) than + * standard Material Design. These are used for backgrounds and surfaces. + */ +export const orchisGrey = { + "050": "#FAFAFA", + "100": "#F2F2F2", + "150": "#EEEEEE", + "200": "#DDDDDD", + "250": "#CCCCCC", + "300": "#BFBFBF", + "350": "#A0A0A0", + "400": "#9E9E9E", + "450": "#868686", + "500": "#727272", + "550": "#555555", + "600": "#464646", + "650": "#3C3C3C", + "700": "#2C2C2C", + "750": "#242424", + "800": "#212121", + "850": "#121212", + "900": "#0F0F0F", + "950": "#030303", +} as const; + + +/** + * --- ACCENT COLOR VARIANTS --- + * Each accent has a "light" variant (used on dark backgrounds) + * and a "dark" variant (used on light backgrounds). + * + * The DEFAULT theme color is Blue (default). + */ +export const accentColors = { + default: { // Blue + light: "#3281EA", // used on dark backgrounds + dark: "#1A73E8", // used on light backgrounds + }, + purple: { + light: "#BA68C8", + dark: "#AB47BC", + }, + pink: { + light: "#F06292", + dark: "#EC407A", + }, + red: { + light: "#F44336", + dark: "#E53935", + }, + orange: { + light: "#FB8C00", + dark: "#F57C00", + }, + yellow: { + light: "#FBC02D", + dark: "#FFD600", + }, + green: { + light: "#66BB6A", + dark: "#4CAF50", + }, + teal: { + light: "#4DB6AC", + dark: "#009688", + }, + grey: { + light: "#DDDDDD", // $grey-200 for dark mode + dark: "#464646", // $grey-600 for light mode + }, +} as const; + +/** Success/sea green used for checkmarks and success states */ +export const successColors = { + light: "#81C995", + dark: "#0F9D58", +} as const; + + +/** + * --- THEME TOKENS: LIGHT MODE --- + * Resolved color values for the light color scheme. + * Primary defaults to Blue accent ($blue-dark = #1A73E8). + */ +export const lightTheme = { + // Primary accent (default = blue) + primary: "#1A73E8", + + // Backgrounds + background: "#F2F2F2", // grey-100 = background(c) + surface: "#FFFFFF", // white = background(a) => surface + base: "#FFFFFF", // white = background(a) => base + baseAlt: "#FAFAFA", // grey-050 = background(b) => base-alt + + // Text on background + text: { + primary: "rgba(0, 0, 0, 0.87)", + secondary: "rgba(0, 0, 0, 0.6)", + disabled: "rgba(0, 0, 0, 0.38)", + secondaryDisabled: "rgba(0, 0, 0, 0.26)", + }, + + // Text on primary (white text on blue bg) + onPrimary: { + primary: "#FFFFFF", + secondary: "rgba(255, 255, 255, 0.7)", + disabled: "rgba(255, 255, 255, 0.5)", + }, + + // Semantic colors + warning: "#FFD600", // $yellow-dark + error: "#E53935", // $red-dark + success: "#0F9D58", // $sea-dark + link: "#1A73E8", // same as primary + linkVisited: "#AB47BC", // $purple-dark + + // Borders and dividers + border: "rgba(0, 0, 0, 0.12)", + solidBorder: "#E2E2E2", // darken($background, 8%) + divider: "rgba(0, 0, 0, 0.12)", + frame: "rgba(0, 0, 0, 0.1)", + + // Overlay states (used on currentColor) + overlay: { + normal: "rgba(0, 0, 0, 0.05)", // 5% opacity + hover: "rgba(0, 0, 0, 0.08)", // 8% opacity + focus: "rgba(0, 0, 0, 0.08)", // 8% opacity + focusHover: "rgba(0, 0, 0, 0.16)", // 16% opacity + active: "rgba(0, 0, 0, 0.12)", // 12% opacity + checked: "rgba(0, 0, 0, 0.10)", // 10% opacity + selected: "rgba(0, 0, 0, 0.06)", // 6% opacity + }, + + // Track (for sliders, switches) + track: "rgba(0, 0, 0, 0.26)", + trackDisabled: "rgba(0, 0, 0, 0.15)", + + // Fill (subtle backgrounds) + fill: "rgba(0, 0, 0, 0.04)", + secondaryFill: "rgba(0, 0, 0, 0.08)", + + // Tooltip + tooltip: "rgba(0, 0, 0, 0.9)", // dark tooltip on light + + // Panel/titlebar + titlebar: "#FFFFFF", // background(a) when topbar=light + titlebarBackdrop: "#FAFAFA", + + // Window buttons (macOS style) + buttonClose: "#fd5f51", + buttonMaximize: "#38c76a", + buttonMinimize: "#fdbe04", + + // Popover/menu + popover: "#FFFFFF", + + // Sidebar + sidebar: "#FAFAFA", // $base-alt +} as const; + + +/** + * --- THEME TOKENS: DARK MODE --- + * Resolved color values for the dark color scheme. + * Primary defaults to Blue accent ($blue-light = #3281EA). + */ +export const darkTheme = { + // Primary accent (default = blue) + primary: "#3281EA", + + // Backgrounds + background: "#212121", // grey-800 = background(e) + surface: "#3C3C3C", // grey-650 = background(h) => surface + base: "#2C2C2C", // grey-700 = background(g) => base + baseAlt: "#242424", // grey-750 = background(f) => base-alt + + // Text on dark background + text: { + primary: "#FFFFFF", + secondary: "rgba(255, 255, 255, 0.7)", + disabled: "rgba(255, 255, 255, 0.5)", + secondaryDisabled: "rgba(255, 255, 255, 0.3)", + }, + + // Text on primary (white text on blue bg) + onPrimary: { + primary: "#FFFFFF", + secondary: "rgba(255, 255, 255, 0.7)", + disabled: "rgba(255, 255, 255, 0.5)", + }, + + // Semantic colors + warning: "#FBC02D", // $yellow-light + error: "#F44336", // $red-light + success: "#81C995", // $sea-light + link: "#3281EA", // same as primary + linkVisited: "#BA68C8", // $purple-light + + // Borders and dividers + border: "rgba(255, 255, 255, 0.12)", + solidBorder: "#3D3D3D", // lighten($background, 12%) + divider: "rgba(255, 255, 255, 0.12)", + frame: "rgba(0, 0, 0, 0.25)", + + // Overlay states + overlay: { + normal: "rgba(255, 255, 255, 0.05)", + hover: "rgba(255, 255, 255, 0.08)", + focus: "rgba(255, 255, 255, 0.08)", + focusHover: "rgba(255, 255, 255, 0.16)", + active: "rgba(255, 255, 255, 0.12)", + checked: "rgba(255, 255, 255, 0.10)", + selected: "rgba(255, 255, 255, 0.06)", + }, + + // Track + track: "rgba(255, 255, 255, 0.3)", + trackDisabled: "rgba(255, 255, 255, 0.15)", + + // Fill + fill: "rgba(255, 255, 255, 0.04)", + secondaryFill: "rgba(255, 255, 255, 0.08)", + + // Tooltip + tooltip: "rgba(0, 0, 0, 0.9)", + + // Panel/titlebar (dark topbar) + titlebar: "#2C2C2C", // background(g) + titlebarBackdrop: "#3C3C3C", + + // Window buttons + buttonClose: "#fd5f51", + buttonMaximize: "#38c76a", + buttonMinimize: "#fdbe04", + + // Popover/menu + popover: "#212121", // background(e) + + // Sidebar + sidebar: "#242424", // $base-alt +} as const; + + +/** + * --- BLACK VARIANT (tweaks: --black) --- + * Full black backgrounds for OLED-friendly dark mode. + */ +export const blackVariant = { + background: "#000000", // $black + surface: "#121212", // grey-850 + base: "#0F0F0F", // grey-900 + baseAlt: "#030303", // grey-950 +} as const; + + +/** + * --- NORD COLOR SCHEME VARIANT --- + * Activated with: --tweaks nord + */ +export const nordPalette = { + nord0: "#2e3440", nord1: "#3b4252", nord2: "#434c5e", nord3: "#4c566a", + nord4: "#d8dee9", nord5: "#e5e9f0", nord6: "#eceff4", + nord7: "#8fbcbb", nord8: "#88c0d0", nord9: "#81a1c1", nord10: "#5e81ac", + nord11: "#bf616a", nord12: "#d08770", nord13: "#ebcb8b", nord14: "#a3be8c", + nord15: "#b48ead", +} as const; + +export const nordAccents = { + default: { light: "#89a3c2", dark: "#5e81ac" }, + purple: { light: "#c89dbf", dark: "#b57daa" }, + pink: { light: "#dc98b1", dark: "#cd7092" }, + red: { light: "#d4878f", dark: "#c35b65" }, + orange: { light: "#dca493", dark: "#d08770" }, + yellow: { light: "#eac985", dark: "#e4b558" }, + green: { light: "#a0c082", dark: "#82ac5d" }, + teal: { light: "#83b9b8", dark: "#63a6a5" }, + grey: { light: "#d9dce3", dark: "#3a4150" }, +} as const; + +export const nordGrey = { + "050": "#f8fafc", "100": "#f0f1f4", "150": "#eaecf0", "200": "#d9dce3", + "250": "#c4c9d4", "300": "#b5bcc9", "350": "#929cb0", "400": "#8e99ae", + "450": "#74819a", "500": "#616d85", "550": "#464f62", "600": "#3a4150", + "650": "#333a47", "700": "#242932", "750": "#1e222a", "800": "#1c1f26", + "850": "#0f1115", "900": "#0d0e11", "950": "#020203", +} as const; + + +/** + * --- DRACULA COLOR SCHEME VARIANT --- + * Activated with: --tweaks dracula + */ +export const draculaAccents = { + default: { light: "#6272a4", dark: "#5d70ac" }, + purple: { light: "#bd93f9", dark: "#a679ec" }, + pink: { light: "#ff79c6", dark: "#f04cab" }, + red: { light: "#ff5555", dark: "#f44d4d" }, + orange: { light: "#ffb86c", dark: "#f8a854" }, + yellow: { light: "#f1fa8c", dark: "#e8f467" }, + green: { light: "#50fa7b", dark: "#4be772" }, + teal: { light: "#50fae9", dark: "#20eed9" }, + grey: { light: "#d9dae3", dark: "#3c3f51" }, +} as const; + +export const draculaGrey = { + "050": "#f9f9fb", "100": "#f0f1f4", "150": "#ebecf1", "200": "#d9dae3", + "250": "#c4c7d4", "300": "#b5b8c9", "350": "#9397af", "400": "#8f94ad", + "450": "#757a99", "500": "#626784", "550": "#474b61", "600": "#3c3f51", + "650": "#343746", "700": "#242632", "750": "#1f2029", "800": "#1c1e26", + "850": "#0f1015", "900": "#0d0d11", "950": "#020203", +} as const; + + +// ============================================================================ +// 2. TYPOGRAPHY +// ============================================================================ + +export const typography = { + /** Primary font stack - Orchis prefers M+ 1c and Roboto */ + fontFamily: '"M+ 1c", Roboto, Cantarell, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif', + + /** For large headings, Roboto is preferred first */ + largeFontFamily: 'Roboto, "M+ 1c", Cantarell, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif', + + /** Root font size */ + rootFontSize: "14px", + rootFontSizeCompact: "13px", + + /** Subheading font size */ + subheadingSize: "16px", + subheadingSizeCompact: "15px", + + /** + * Typography scale (from GTK4 type classes) + * Maps to CSS utility classes + */ + scale: { + largeTitle: { weight: 300, size: "24pt" }, // .large-title + title1: { weight: 800, size: "20pt" }, // .title-1 + title2: { weight: 800, size: "15pt" }, // .title-2 + title3: { weight: 700, size: "15pt" }, // .title-3 + title4: { weight: 700, size: "13pt" }, // .title-4 + heading: { weight: 700, size: "11pt" }, // .heading + body: { weight: 400, size: "11pt" }, // .body + caption: { weight: 400, size: "9pt" }, // .caption + captionHeading: { weight: 700, size: "9pt" }, // .caption-heading + }, + + /** Button text weight */ + buttonWeight: 500, + + /** Tab text weight */ + tabWeight: 500, + + /** Sidebar selected item weight */ + sidebarSelectedWeight: 500, +} as const; + + +// ============================================================================ +// 3. BORDER RADIUS / SHAPE LANGUAGE +// ============================================================================ + +/** + * Orchis uses a **rounded** design language by default. + * $default_corner = 12px (configurable via --round flag from 2px to 15px). + * + * All other radii are derived from this base value. + */ +export const borderRadius = { + /** Default corner radius (12px) */ + default: 12, + + /** Window radius: $default_corner + $space-size = 12 + 6 = 18px */ + window: 18, + + /** Standard corner radius (for buttons, entries, etc.): same as default = 12px + * In compact mode: max(0, $default_corner - 2px) = 10px */ + corner: 12, + cornerCompact: 10, + + /** Material radius: $default_corner / 2 + 4 = 10px */ + material: 10, + + /** Menu/popover radius: $default_corner / 4 + $space-size + 2 = 3 + 6 + 2 = 11px */ + menu: 11, + + /** Popup radius: $default_corner + $space-size * 2 - 4 = 12 + 12 - 4 = 20px */ + popup: 20, + + /** Menu item radius: $default_corner / 4 + 2 = 5px */ + menuItem: 5, + + /** Card/boxed list radius: $corner-radius - 1px = 11px */ + card: 11, + + /** Circular/pill radius (for pills, circular buttons) */ + circular: 9999, + + /** Tooltip radius: $corner-radius / 2 = 6px */ + tooltip: 6, + + /** Toolbar button radius: $corner-radius / 2 = 6px */ + toolbarButton: 6, + + /** Panel corner radius (gnome-shell): 0 */ + panel: 0, +} as const; + + +// ============================================================================ +// 4. SPACING SYSTEM +// ============================================================================ + +/** + * Orchis uses a base spacing unit of 6px (4px in compact mode). + * Margin is 4px (2px in compact). + * Sizes scale consistently based on these units. + */ +export const spacing = { + /** Base spacing unit: 6px */ + space: 6, + spaceCompact: 4, + + /** Base margin: 4px */ + margin: 4, + marginCompact: 2, + + /** Component sizes */ + small: 24, // 24px (compact: 22px) - small buttons, icons + smallCompact: 22, + medium: 36, // 36px (compact: 32px) - buttons, entries, tabs + mediumCompact: 32, + large: 48, // 48px (compact: 40px) - large buttons, headers + largeCompact: 40, + + /** Menu item height: 28px (compact: 24px) */ + menuItem: 28, + menuItemCompact: 24, + + /** Bar size (progress bars, level bars): 6px */ + bar: 6, + + /** Icon sizes */ + iconBase: 16, + iconMedium: 24, // 16 * 1.5 + iconLarge: 32, // 16 * 2 + + /** Derived spacing values frequently used */ + xs: 2, // half margin + sm: 4, // margin + md: 6, // space + lg: 12, // space * 2 + xl: 18, // space * 3 + xxl: 24, // space * 4 +} as const; + + +// ============================================================================ +// 5. COMPONENT STYLING PATTERNS +// ============================================================================ + +// --- 5.1 BUTTONS --- + +export const button = { + /** Standard button */ + standard: { + minHeight: 24, + minWidth: 24, + // padding: (medium-size - 24) / 2 = (36-24)/2 = 6px + padding: "6px", + borderRadius: 12, // $corner-radius + fontWeight: 500, + transition: "all 75ms cubic-bezier(0.0, 0.0, 0.2, 1)", + }, + + /** States for standard button (light mode) */ + states: { + normal: { + background: "rgba(0, 0, 0, 0.05)", // currentColor at 5% + color: "rgba(0, 0, 0, 0.87)", // $text primary + boxShadow: "inset 0 0 0 2px transparent", + }, + hover: { + background: "rgba(0, 0, 0, 0.08)", + }, + focus: { + boxShadow: "inset 0 0 0 2px rgba(0, 0, 0, 0.08)", + }, + active: { + // Ripple animation plays + background: "rgba(0, 0, 0, 0.08)", + }, + disabled: { + background: "rgba(0, 0, 0, 0.05)", + color: "rgba(0, 0, 0, 0.38)", + }, + checked: { + // PRIMARY colored button + background: "#1A73E8", // $primary + color: "#FFFFFF", // $primary-text + }, + }, + + /** Flat/text button */ + flat: { + normal: { + background: "transparent", + color: "rgba(0, 0, 0, 0.6)", // $text-secondary + }, + hover: { + background: "rgba(0, 0, 0, 0.08)", + color: "rgba(0, 0, 0, 0.87)", + }, + active: { + background: "rgba(0, 0, 0, 0.08)", + color: "rgba(0, 0, 0, 0.87)", + }, + disabled: { + background: "transparent", + color: "rgba(0, 0, 0, 0.26)", + }, + checked: { + background: "rgba(0, 0, 0, 0.10)", + color: "rgba(0, 0, 0, 0.87)", + }, + }, + + /** Suggested action (primary CTA) - uses primary color */ + suggested: { + background: "#1A73E8", + color: "#FFFFFF", + }, + + /** Destructive action */ + destructive: { + background: "#E53935", + color: "#FFFFFF", + }, + + /** Pill button (for dialog actions) */ + pill: { + borderRadius: 9999, + padding: "6px 32px", + }, + + /** Circular button */ + circular: { + borderRadius: 9999, + minWidth: 24, + minHeight: 24, + }, +} as const; + + +// --- 5.2 CARDS / PANELS --- + +export const card = { + borderRadius: 12, // $corner-radius (same as default) + border: "1px solid", // $divider color + // light: "rgba(0,0,0,0.12)", dark: "rgba(255,255,255,0.12)" + boxShadow: "none", + backgroundClip: "padding-box", + // light bg: $base = #FFFFFF, dark bg: $base = #2C2C2C + // color: $text-secondary + + /** Boxed list (grouped card rows) */ + boxedList: { + borderRadius: 11, // $corner-radius - 1px + rowBorderBottom: "1px solid", // $divider + transition: "200ms cubic-bezier(0.0, 0.0, 0.2, 1)", + }, +} as const; + + +// --- 5.3 NAVIGATION / SIDEBAR --- + +export const sidebar = { + // background: $base-alt (light: #FAFAFA, dark: #242424) + borderRight: "1px solid", // $divider + padding: "6px 0", // $space-size vertical only + + row: { + minHeight: 36, // $medium-size + padding: "0 9px", // 0 $space-size * 1.5 + // Navigation sidebar rows have special pill-shaped right side + borderRadius: "0 9999px 9999px 0", // 0 $circular 0 $circular + margin: "0 6px 0 0", + + selected: { + // background: overlay-checked = 10% currentColor + color: "#1A73E8", // $primary + }, + }, + + stackSidebar: { + rowPadding: "6px 9px", + rowRadius: 6, // $corner-radius / 2 + rowSelectedWeight: 500, + }, +} as const; + + +// --- 5.4 HEADERBAR / NAVIGATION BAR --- + +export const headerbar = { + // Light mode: background = #FFFFFF, dark mode: background = #2C2C2C + // Topbar can be independently dark even in light mode + minHeight: 48, // $large-size + padding: "0 6px", + borderSpacing: 6, + + /** Compact headerbar */ + compact: { + minHeight: 40, + padding: "0 4px", + borderSpacing: 4, + }, + + buttonStyle: { + // headerbar buttons are flat by default + color: "inherit", // uses titlebar text colors + fontWeight: 500, + }, +} as const; + + +// --- 5.5 INPUT FIELDS --- + +export const input = { + minHeight: 36, // $medium-size + padding: "0 8px", // 0 ($space-size + 2px) + borderRadius: 12, // $corner-radius + borderSpacing: 6, + + states: { + normal: { + background: "rgba(0, 0, 0, 0.05)", // currentColor 5% + outline: "0 solid transparent", + outlineOffset: "4px", + }, + hover: { + background: "rgba(0, 0, 0, 0.08)", + outline: "2px solid rgba(0, 0, 0, 0.08)", + outlineOffset: "-2px", + }, + focus: { + background: "rgba(0, 0, 0, 0.08)", + outline: "2px solid rgba(0, 0, 0, 0.26)", // $track color + outlineOffset: "-2px", + }, + checked: { + // When actively typing (focus + content) + outline: "2px solid #1A73E8", // $primary + outlineOffset: "-2px", + }, + disabled: { + background: "rgba(0, 0, 0, 0.05)", + color: "rgba(0, 0, 0, 0.38)", + }, + error: { + outline: "2px solid #E53935", // $error + }, + warning: { + outline: "2px solid #FFD600", // $warning + }, + success: { + outline: "2px solid #0F9D58", // $success + }, + }, + + /** Flat entry (no background) */ + flat: { + minHeight: "auto", + padding: "2px", + borderRadius: 0, + background: "transparent", + }, +} as const; + + +// --- 5.6 DROPDOWNS / COMBOBOX --- +// Orchis treats dropdowns as button + popover combinations + +export const dropdown = { + // Inherits button styling for the trigger + trigger: { + minHeight: 24, + borderRadius: 12, + fontWeight: 500, + }, + // Menu uses popover styling + menu: { + borderRadius: 11, // $menu-radius + boxShadow: "0 3px 3px -1px rgba(0,0,0,0.2), 0 6px 6px 0 rgba(0,0,0,0.14), 0 1px 11px 0 rgba(0,0,0,0.12)", // $shadow-z6 + padding: 6, + }, + menuItem: { + minHeight: 22, // $menuitem-size - $space-size + minWidth: 56, // $menuitem-size * 2 + padding: "3px 9px", // $space-size/2 $space-size*1.5 + borderRadius: 5, // $menuitem-radius + }, +} as const; + + +// --- 5.7 TOGGLES / SWITCHES --- + +export const toggle = { + // GTK switch is a sliding toggle + margin: "6px 0", + padding: "0 2px", + border: "5px solid transparent", + borderRadius: 9999, // $circular-radius + transition: "all 75ms cubic-bezier(0.0, 0.0, 0.2, 1)", + + // Track + track: { + unchecked: "rgba(0, 0, 0, 0.26)", // $track (light mode) + checked: "rgba(26, 115, 232, 0.5)", // color-mix($primary 50%) + disabled: { opacity: 0.5 }, + }, + + // Slider/thumb + slider: { + width: 20, + height: 20, + margin: "-3px -2px", + borderRadius: 9999, + backgroundColor: "#FFFFFF", // $surface (light) + boxShadow: "0 2px 2px -2px rgba(0,0,0,0.3), 0 1px 2px -1px rgba(0,0,0,0.24), 0 1px 2px -1px rgba(0,0,0,0.17)", // $shadow-z1 + }, + + // Checked slider + sliderChecked: { + backgroundColor: "#1A73E8", // $primary + }, + + // Hover ring + hoverRing: "0 0 0 10px rgba(0, 0, 0, 0.08)", + focusRing: "0 0 0 10px rgba(0, 0, 0, 0.08)", +} as const; + + +// --- 5.8 TABLES / TREE VIEWS --- + +export const table = { + background: "#FFFFFF", // $base + headerBackground: "#FFFFFF", // $base + headerColor: "rgba(0, 0, 0, 0.6)", // $text-secondary + headerPadding: "2px 6px", + headerBorder: "1px solid rgba(0, 0, 0, 0.12)", // $divider + headerFontWeight: "normal", + + row: { + padding: "2px", + color: "rgba(0, 0, 0, 0.6)", + borderBottom: "1px solid rgba(0, 0, 0, 0.12)", + }, + + /** Row hover (activatable rows) */ + rowHover: { + background: "rgba(0, 0, 0, 0.08)", + color: "rgba(0, 0, 0, 0.87)", + }, + + /** Row active (with ripple animation) */ + rowActive: { + background: "rgba(0, 0, 0, 0.08)", + }, + + /** Row selected */ + rowSelected: { + background: "rgba(0, 0, 0, 0.06)", // $overlay-selected + }, + + /** Progress bar in treeview */ + progressBar: "6px solid #1A73E8", // $bar-size solid $primary + progressTrough: "6px solid rgba(0, 0, 0, 0.15)", +} as const; + + +// --- 5.9 TABS / NOTEBOOK --- + +export const tabs = { + tab: { + minHeight: 24, // $small-size + minWidth: 24, + padding: "6px 12px", // $space-size $space-size*2 + fontWeight: 500, + transition: "all 75ms cubic-bezier(0.0, 0.0, 0.2, 1)", + }, + + states: { + normal: { + borderColor: "transparent", + background: "transparent", + color: "rgba(0, 0, 0, 0.6)", // $text-secondary + }, + hover: { + background: "#E2E2E2", // $solid-border (light) + color: "rgba(0, 0, 0, 0.87)", + }, + disabled: { + color: "rgba(0, 0, 0, 0.26)", + }, + checked: { + background: "#FFFFFF", // $base + borderColor: "#E2E2E2", // $solid-border + color: "rgba(0, 0, 0, 0.87)", + }, + }, + + /** Notebook container */ + notebook: { + background: "#FFFFFF", // $base + frameRadius: 12, // $corner-radius + }, + + /** Stack switcher (segmented control style) */ + stackSwitcher: { + borderRadius: 9999, // $circular-radius + background: "rgba(0, 0, 0, 0.05)", // $overlay-normal + buttonRadius: 9999, + // Checked: background = $primary, color = white + }, +} as const; + + +// --- 5.10 DIALOGS / MODALS --- + +export const dialog = { + background: "#3C3C3C", // $surface (or $surface in current mode) + borderRadius: 18, // $window-radius + boxShadow: "0 8px 6px -5px rgba(0,0,0,0.2), 0 16px 16px 2px rgba(0,0,0,0.14), 0 6px 18px 5px rgba(0,0,0,0.12)", // $shadow-z16 + borderSpacing: 10, + + /** Message dialog specific */ + messageDialog: { + actionPadding: 6, + actionButtonRadius: 9999, // $circular-radius (pill shaped) + actionButtonStyle: "flat", // flat buttons in dialogs + // Non-disabled buttons colored with $primary + // Destructive buttons colored with $destructive + }, + + /** About dialog */ + aboutDialog: { + iconSize: 128, + scrolledWindowRadius: 12, // $window-radius - $space-size + }, +} as const; + + +// --- 5.11 PROGRESS BARS --- + +export const progressBar = { + /** Bar height: $bar-size = 6px */ + height: 6, + borderRadius: 12, // $corner-radius + + /** Trough (background track) */ + trough: { + background: "rgba(0, 0, 0, 0.15)", // $track-disabled (light) + }, + + /** Progress (filled portion) */ + progress: { + background: "#1A73E8", // $primary + }, + + /** Level bar */ + levelBar: { + low: "#FFD600", // $warning + high: "#1A73E8", // $primary + full: "#0F9D58", // $success + empty: "rgba(0, 0, 0, 0.15)", + }, +} as const; + + +// --- 5.12 TOOLTIPS --- + +export const tooltipStyle = { + // Light mode: dark tooltip (darken(background(h), 3%) at 0.9 opacity) + // Dark mode: dark tooltip + background: "rgba(0, 0, 0, 0.9)", // $tooltip (light mode default) + color: "#FFFFFF", + borderRadius: 6, // $corner-radius / 2 + padding: "6px 12px", // $space-size $space-size*2 + boxShadow: "0 2px 2px -1px rgba(0,0,0,0.2), 0 4px 4px 0 rgba(0,0,0,0.14), 0 1px 6px 0 rgba(0,0,0,0.12)", // $shadow-z4 + margin: "2px 6px 8px 6px", +} as const; + + +// --- 5.13 SCROLLBARS --- + +export const scrollbar = { + background: "#FFFFFF", // $base + borderWidth: 1, + borderColor: "rgba(0, 0, 0, 0.12)", + + slider: { + minWidth: 8, + minHeight: 8, + border: "4px solid transparent", + borderRadius: 9999, + backgroundClip: "padding-box", + + normal: "rgba(0, 0, 0, 0.26)", // $text-secondary-disabled + hover: "rgba(0, 0, 0, 0.38)", // $text-disabled + active: "rgba(0, 0, 0, 0.6)", // $text-secondary + disabled: "rgba(0, 0, 0, 0.26)", + }, + + /** Overlay scrollbar (thin) */ + overlay: { + sliderWidth: 4, + sliderHeight: 4, + margin: 3, + }, +} as const; + + +// --- 5.14 POPOVERS / MENUS --- + +export const popover = { + borderRadius: 11, // $menu-radius + boxShadow: "0 3px 3px -1px rgba(0,0,0,0.2), 0 6px 6px 0 rgba(0,0,0,0.14), 0 1px 11px 0 rgba(0,0,0,0.12)", // $shadow-z6 + padding: 6, // $space-size + border: "none", + // Light: background = $surface = #FFFFFF + // Dark: background = $surface = #3C3C3C + + /** Menu item styling */ + menuItem: { + minHeight: 22, // $menuitem-size - $space-size + minWidth: 56, + padding: "3px 9px", + borderRadius: 5, // $menuitem-radius + transition: "background-color 75ms cubic-bezier(0.0, 0.0, 0.2, 1)", + }, + + /** Separator */ + separator: { + margin: "3px 0", // $space-size/2 0 + background: "rgba(0, 0, 0, 0.12)", + }, + + /** Backdrop state */ + backdrop: { + boxShadow: "0 3px 2px -3px rgba(0,0,0,0.3), 0 2px 2px -1px rgba(0,0,0,0.24), 0 1px 3px 0 rgba(0,0,0,0.12)", // $shadow-z2 + }, +} as const; + + +// --- 5.15 CALENDAR --- + +export const calendar = { + borderRadius: 12, + border: "1px solid rgba(0, 0, 0, 0.12)", + headerBorderBottom: "1px solid rgba(0, 0, 0, 0.12)", + headerPadding: 3, + gridMargin: 3, + dayPadding: 9, // $space-size * 1.5 + todayHighlight: "#1A73E8", // primary color + selectedBorder: 9999, // circular for selected days +} as const; + + +// ============================================================================ +// 6. SHADOW / ELEVATION SYSTEM +// ============================================================================ + +/** + * Based on Material Design elevation system. + * Values from material-components-web with Orchis adjustments. + */ +export const shadows = { + /** z1 - Subtle elevation (cards at rest, buttons) */ + z1: "0 2px 2px -2px rgba(0,0,0,0.3), 0 1px 2px -1px rgba(0,0,0,0.24), 0 1px 2px -1px rgba(0,0,0,0.17)", + + /** z2 - Low elevation (search bars, app bars) */ + z2: "0 3px 2px -3px rgba(0,0,0,0.3), 0 2px 2px -1px rgba(0,0,0,0.24), 0 1px 3px 0 rgba(0,0,0,0.12)", + + /** z3 - Medium elevation (cards on hover, FAB at rest) */ + z3: "0 3px 3px -2px rgba(0,0,0,0.2), 0 3px 3px 0 rgba(0,0,0,0.14), 0 1px 5px 0 rgba(0,0,0,0.12)", + + /** z4 - Medium-high elevation (menus, tooltips, backdrops) */ + z4: "0 2px 2px -1px rgba(0,0,0,0.2), 0 4px 4px 0 rgba(0,0,0,0.14), 0 1px 6px 0 rgba(0,0,0,0.12)", + + /** z6 - High elevation (popovers, dropdown menus) */ + z6: "0 3px 3px -1px rgba(0,0,0,0.2), 0 6px 6px 0 rgba(0,0,0,0.14), 0 1px 11px 0 rgba(0,0,0,0.12)", + + /** z8 - Higher elevation (bottom sheets, side sheets) */ + z8: "0 5px 5px -3px rgba(0,0,0,0.2), 0 8px 8px 1px rgba(0,0,0,0.14), 0 3px 9px 2px rgba(0,0,0,0.12)", + + /** z12 - Very high elevation (FAB pressed) */ + z12: "0 7px 7px -4px rgba(0,0,0,0.2), 0 12px 12px 2px rgba(0,0,0,0.14), 0 5px 13px 4px rgba(0,0,0,0.12)", + + /** z16 - Window elevation (dialogs, modal windows) */ + z16: "0 8px 6px -5px rgba(0,0,0,0.2), 0 16px 16px 2px rgba(0,0,0,0.14), 0 6px 18px 5px rgba(0,0,0,0.12)", + + /** z24 - Maximum elevation (full-screen dialogs) */ + z24: "0 11px 11px -7px rgba(0,0,0,0.2), 0 24px 24px 3px rgba(0,0,0,0.14), 0 9px 28px 8px rgba(0,0,0,0.12)", + + /** Text shadow */ + text: "0 1px 1px rgba(0,0,0,0.2), 0 1px 2px rgba(0,0,0,0.14), 0 1px 3px rgba(0,0,0,0.12)", + + /** Gnome Shell simplified shadows */ + shell: { + z1: "0 1px 2px rgba(0,0,0,0.25)", + z2: "0 3px 3px rgba(0,0,0,0.32)", + z3: "0 3px 8px rgba(0,0,0,0.2)", + z4: "0 6px 10px rgba(0,0,0,0.32)", + z5: "0 10px 15px rgba(0,0,0,0.45)", + z6: "0 12px 20px rgba(0,0,0,0.6)", + }, +} as const; + + +// ============================================================================ +// 7. ANIMATION / TRANSITION PATTERNS +// ============================================================================ + +export const animation = { + /** Durations */ + duration: { + shortest: "75ms", // $duration - micro interactions + shorter: "100ms", // $shorter-duration + short: "150ms", // $longer-duration + rippleFadeIn: "225ms", // $ripple-fade-in-duration + rippleFadeOut: "300ms", // $ripple-fade-out-duration + rippleOpacity: "1200ms", // $ripple-fade-out-opacity-duration + }, + + /** Timing functions (Material Design standard) */ + easing: { + /** Standard easing - for most transitions */ + standard: "cubic-bezier(0.4, 0.0, 0.2, 1)", + /** Decelerate - for elements entering the screen */ + decelerate: "cubic-bezier(0.0, 0.0, 0.2, 1)", + /** Accelerate - for elements leaving the screen */ + accelerate: "cubic-bezier(0.4, 0.0, 1, 1)", + /** Sharp - for elements that may return to screen */ + sharp: "cubic-bezier(0.4, 0.0, 0.6, 1)", + }, + + /** Predefined transition shorthands */ + transition: { + default: "all 75ms cubic-bezier(0.0, 0.0, 0.2, 1)", + shadow: "box-shadow 75ms cubic-bezier(0.0, 0.0, 0.2, 1)", + }, + + /** Ripple effect (Material Design signature interaction) */ + ripple: { + /** + * CSS keyframes for ripple effect: + * @keyframes ripple { + * from { background-image: radial-gradient(circle farthest-corner at center, rgba(0,0,0,0.10) 30%, transparent 0%); } + * to { background-image: radial-gradient(circle farthest-corner at center, rgba(0,0,0,0.10) 100%, transparent 0%); } + * } + */ + duration: "225ms", + easing: "cubic-bezier(0.0, 0.0, 0.2, 1)", + // The ripple circle starts at 30% and expands to 100% + overlayColor: "rgba(0, 0, 0, 0.10)", // $overlay-checked + }, + + /** Spinner animation: rotate 1 full turn, linear, infinite */ + spinner: { + animation: "spin 1s linear infinite", + }, + + /** Needs-attention pulse */ + needsAttention: { + // Radial gradient pulse from 0% to 95% with primary color + }, +} as const; + + +// ============================================================================ +// 8. ICON STYLE PREFERENCES +// ============================================================================ + +export const icons = { + /** Orchis uses symbolic (monochrome outline) icons in the GNOME style */ + style: "symbolic", // Monochrome, outline-based icons + + /** Base icon size */ + baseSize: 16, // $base-icon-size + mediumSize: 24, // $base-icon-size * 1.5 + largeSize: 32, // $base-icon-size * 2 + + /** Icon color follows text color (currentColor) */ + color: "currentColor", + + /** Check/radio icon size */ + checkRadioSize: 24, + + /** The Orchis icon set uses: + * - Papirus icons (recommended companion) + * - Symbolic SVG icons for UI elements + * - Material Design inspired icon shapes + * - Rounded/soft stroke style + */ + recommendation: "Use Material Symbols (Rounded variant) or Phosphor Icons for web", +} as const; + + +// ============================================================================ +// CSS CUSTOM PROPERTIES (ready for :root injection) +// ============================================================================ + +/** + * Generate CSS custom properties for a Next.js application. + * Usage: inject these into your global CSS or a ThemeProvider. + */ +export function generateCSSVariables(mode: "light" | "dark" = "light", accent: keyof typeof accentColors = "default"): string { + const theme = mode === "light" ? lightTheme : darkTheme; + const accentColor = mode === "light" ? accentColors[accent].dark : accentColors[accent].light; + + return ` +:root { + /* ---- Primary / Accent ---- */ + --orchis-primary: ${accentColor}; + --orchis-on-primary: ${theme.onPrimary.primary}; + --orchis-on-primary-secondary: ${theme.onPrimary.secondary}; + + /* ---- Backgrounds ---- */ + --orchis-background: ${theme.background}; + --orchis-surface: ${theme.surface}; + --orchis-base: ${theme.base}; + --orchis-base-alt: ${theme.baseAlt}; + + /* ---- Text ---- */ + --orchis-text: ${theme.text.primary}; + --orchis-text-secondary: ${theme.text.secondary}; + --orchis-text-disabled: ${theme.text.disabled}; + + /* ---- Semantic ---- */ + --orchis-error: ${theme.error}; + --orchis-warning: ${theme.warning}; + --orchis-success: ${theme.success}; + --orchis-link: ${accentColor}; + --orchis-link-visited: ${theme.linkVisited}; + --orchis-destructive: ${theme.error}; + + /* ---- Borders ---- */ + --orchis-border: ${theme.border}; + --orchis-border-solid: ${theme.solidBorder}; + --orchis-divider: ${theme.divider}; + + /* ---- Overlay States ---- */ + --orchis-overlay-hover: ${theme.overlay.hover}; + --orchis-overlay-focus: ${theme.overlay.focus}; + --orchis-overlay-active: ${theme.overlay.active}; + --orchis-overlay-checked: ${theme.overlay.checked}; + --orchis-overlay-selected: ${theme.overlay.selected}; + + /* ---- Track / Fill ---- */ + --orchis-track: ${theme.track}; + --orchis-track-disabled: ${theme.trackDisabled}; + --orchis-fill: ${theme.fill}; + --orchis-secondary-fill: ${theme.secondaryFill}; + + /* ---- Tooltip ---- */ + --orchis-tooltip-bg: ${theme.tooltip}; + + /* ---- Titlebar ---- */ + --orchis-titlebar: ${theme.titlebar}; + --orchis-titlebar-backdrop: ${theme.titlebarBackdrop}; + --orchis-sidebar: ${theme.sidebar}; + + /* ---- Window Buttons ---- */ + --orchis-btn-close: ${theme.buttonClose}; + --orchis-btn-maximize: ${theme.buttonMaximize}; + --orchis-btn-minimize: ${theme.buttonMinimize}; + + /* ---- Typography ---- */ + --orchis-font-family: ${typography.fontFamily}; + --orchis-font-size: ${typography.rootFontSize}; + --orchis-font-weight-button: ${typography.buttonWeight}; + + /* ---- Spacing ---- */ + --orchis-space: ${spacing.space}px; + --orchis-space-xs: ${spacing.xs}px; + --orchis-space-sm: ${spacing.sm}px; + --orchis-space-md: ${spacing.md}px; + --orchis-space-lg: ${spacing.lg}px; + --orchis-space-xl: ${spacing.xl}px; + --orchis-space-xxl: ${spacing.xxl}px; + + /* ---- Border Radius ---- */ + --orchis-radius: ${borderRadius.default}px; + --orchis-radius-window: ${borderRadius.window}px; + --orchis-radius-corner: ${borderRadius.corner}px; + --orchis-radius-menu: ${borderRadius.menu}px; + --orchis-radius-card: ${borderRadius.card}px; + --orchis-radius-tooltip: ${borderRadius.tooltip}px; + --orchis-radius-menuitem: ${borderRadius.menuItem}px; + --orchis-radius-circular: ${borderRadius.circular}px; + + /* ---- Shadows ---- */ + --orchis-shadow-z1: ${shadows.z1}; + --orchis-shadow-z2: ${shadows.z2}; + --orchis-shadow-z3: ${shadows.z3}; + --orchis-shadow-z4: ${shadows.z4}; + --orchis-shadow-z6: ${shadows.z6}; + --orchis-shadow-z8: ${shadows.z8}; + --orchis-shadow-z12: ${shadows.z12}; + --orchis-shadow-z16: ${shadows.z16}; + --orchis-shadow-z24: ${shadows.z24}; + + /* ---- Transitions ---- */ + --orchis-duration: ${animation.duration.shortest}; + --orchis-duration-short: ${animation.duration.short}; + --orchis-duration-ripple: ${animation.duration.rippleFadeIn}; + --orchis-ease: ${animation.easing.standard}; + --orchis-ease-out: ${animation.easing.decelerate}; + --orchis-ease-in: ${animation.easing.accelerate}; + --orchis-transition: ${animation.transition.default}; + + /* ---- Component Sizes ---- */ + --orchis-size-small: ${spacing.small}px; + --orchis-size-medium: ${spacing.medium}px; + --orchis-size-large: ${spacing.large}px; + --orchis-icon-size: ${icons.baseSize}px; + --orchis-icon-size-md: ${icons.mediumSize}px; + --orchis-icon-size-lg: ${icons.largeSize}px; + --orchis-bar-size: ${spacing.bar}px; +} + `.trim(); +} diff --git a/docs/unraid-ui-project/unraid-api-research.md b/docs/unraid-ui-project/unraid-api-research.md new file mode 100644 index 000000000..3186161ab --- /dev/null +++ b/docs/unraid-ui-project/unraid-api-research.md @@ -0,0 +1,81 @@ +# Unraid API Research (Live from XTRM-Unraid v7.2.3) + +## API: unraid-api v4.29.2 (NestJS + Apollo GraphQL) + +### Connection +- HTTP: `http://192.168.10.20/graphql` +- WebSocket: `ws://192.168.10.20/graphql` (graphql-ws protocol) +- Unix socket: `/var/run/unraid-api.sock` +- Auth: `x-api-key` header + +### GraphQL Queries +| Query | Description | +|-------|-------------| +| `info` | System info (cpu, memory, os, baseboard, devices, display, versions) | +| `array` | Array state, capacity, disks, parities, caches, parity check status | +| `disks` / `disk(id)` | Physical disks with SMART status, temp, serial | +| `docker` | Containers (id, names, state, status, image, ports, autoStart) + networks | +| `vms` | VMs (id, name, state) | +| `shares` | Shares (name, free, used, size, include, exclude, cache, color) | +| `notifications` | Notifications (title, subject, description, importance, type, timestamp) | +| `vars` | Server variables (version, name, timezone, network, SMB/NFS settings) | +| `services` | Running services (name, online, uptime, version) | +| `flash` | Flash drive (guid, vendor, product) | +| `registration` | License (type, state, keyFile, expiration) | +| `network` | Network info (accessUrls) | +| `server` | Server details (owner, guid, wanip, lanip, localurl, remoteurl) | +| `connect` | Connect status (dynamicRemoteAccess, settings) | +| `plugins` | Installed plugins (name, version) | +| `logFiles` / `logFile(path)` | Log file listing and content | +| `upsDevices` / `upsConfiguration` | UPS monitoring | +| `apiKeys` | API key management | +| `customization` | Theme + activation code | +| `me` / `owner` | Current user / server owner | + +### GraphQL Mutations +| Mutation | Description | +|----------|-------------| +| `array.setState` | Start/stop array | +| `array.addDiskToArray` / `removeDiskFromArray` | Disk management | +| `array.mountArrayDisk` / `unmountArrayDisk` | Mount/unmount | +| `docker.start(id)` / `docker.stop(id)` | Container start/stop | +| `vm.start/stop/pause/resume/forceStop/reboot/reset(id)` | VM power management | +| `parityCheck.start/pause/resume/cancel` | Parity check control | +| `notification.create/delete/archive/unread` | Notification CRUD | +| `apiKey.create/update/delete` | API key management | +| `customization.setTheme` | Theme switching | +| `connectSignIn/SignOut` | Unraid Connect | +| `setupRemoteAccess` | Remote access config | + +### GraphQL Subscriptions (Real-time) +- `systemMetricsCpu` / `systemMetricsCpuTelemetry` / `systemMetricsMemory` +- `arraySubscription` / `parityHistorySubscription` +- `notificationAdded` / `notificationsOverview` +- `logFile` (live log streaming) +- `upsUpdates` +- `ownerSubscription` / `serversSubscription` + +### Enums +- ArrayState: STARTED, STOPPED, NEW_ARRAY, RECON_DISK, DISABLE_DISK, etc. +- ArrayDiskStatus: DISK_NP, DISK_OK, DISK_INVALID, DISK_WRONG, DISK_DSBL, etc. +- ArrayDiskType: DATA, PARITY, FLASH, CACHE +- ContainerState: RUNNING, EXITED +- VmState: NOSTATE, RUNNING, IDLE, PAUSED, SHUTDOWN, SHUTOFF, CRASHED, PMSUSPENDED +- DiskFsType: XFS, BTRFS, VFAT, ZFS, EXT4, NTFS +- DiskInterfaceType: SAS, SATA, USB, PCIE, UNKNOWN +- ThemeName: azure, black, gray, white + +### Legacy PHP/Nchan Endpoints +- Nchan WebSocket channels: `/sub/var`, `/sub/docker`, `/sub/update1-3`, `/sub/diskload`, etc. +- PHP includes: DashboardApps.php, Control.php, SmartInfo.php, Syslog.php, etc. +- State INI files at `/var/local/emhttp/`: var.ini, disks.ini, shares.ini, etc. +- Legacy control: POST to `/update.htm` for commands + +### NOT Available via GraphQL +- Docker create/delete/restart/logs +- VM create/delete +- Share CRUD, User CRUD +- Detailed SMART attributes +- Disk format/clear, spin up/down +- System reboot/shutdown +- Mover operations