Download 69 selfh.st icon files (34 PNG, 34 light SVG, unraid.svg) into assets/icons/ and add wallpaper to assets/. Update sidebar.js to serve icons from /custom/assets/icons/ instead of cdn.jsdelivr.net. Update style.css wallpaper path to /custom/assets/wallpaper.jpg. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
9.7 KiB
Unraid Glass — visionOS Glassmorphism Theme
Project
Custom CSS + JS theme for Unraid 7.2.3 WebGUI. B&W mountain wallpaper with frosted glass cards, collapsible sidebar, dashboard individual glass cards.
Gitea: https://git.xtrm-lab.org/jazzymc/unraid-glass
Local: ~/xtrm/unraid-glass/
Files
| File | Purpose | Deploy path (persistent) | Deploy path (live) |
|---|---|---|---|
style.css |
Main CSS theme | /boot/config/plugins/custom.css/style.css |
/usr/local/emhttp/plugins/custom.css/style.css |
sidebar.js |
Sidebar toggle + search overlay + icon replacement | /boot/config/plugins/custom.css/assets/sidebar.js |
/usr/local/emhttp/plugins/custom.css/assets/sidebar.js |
update-icons.sh |
Replace Docker/VM cached icons with selfh.st icons | /boot/config/plugins/custom.css/assets/update-icons.sh |
/usr/local/emhttp/plugins/custom.css/assets/update-icons.sh |
vm-icons.conf |
VM name → icon name mapping | /boot/config/plugins/custom.css/assets/vm-icons.conf |
— |
assets/icons/ |
Self-hosted selfh.st icons (34 PNG + 34 light SVG + unraid.svg) | /boot/config/plugins/custom.css/assets/icons/ |
/usr/local/emhttp/custom/assets/icons/ |
assets/wallpaper.jpg |
Mountain wallpaper background | /boot/config/plugins/custom.css/assets/wallpaper.jpg |
/usr/local/emhttp/custom/assets/wallpaper.jpg |
Web-Accessible Paths
Unraid nginx serves /usr/local/emhttp/ as document root. Key mapping:
/custom/→/usr/local/emhttp/custom/(NOTplugins/custom.css/!)/plugins/custom.css/→/usr/local/emhttp/plugins/custom.css/
Static assets (icons, wallpaper) that need HTTP access go to /usr/local/emhttp/custom/assets/.
JS/CSS loaded via plugin pages go to /usr/local/emhttp/plugins/custom.css/.
Deployment
Code files deploy to TWO paths — persistent (survives reboot) and live (active now):
scp -i ~/.ssh/id_ed25519_unraid -P 422 style.css root@192.168.10.20:/boot/config/plugins/custom.css/style.css
scp -i ~/.ssh/id_ed25519_unraid -P 422 style.css root@192.168.10.20:/usr/local/emhttp/plugins/custom.css/style.css
scp -i ~/.ssh/id_ed25519_unraid -P 422 sidebar.js root@192.168.10.20:/boot/config/plugins/custom.css/assets/sidebar.js
scp -i ~/.ssh/id_ed25519_unraid -P 422 sidebar.js root@192.168.10.20:/usr/local/emhttp/plugins/custom.css/assets/sidebar.js
scp -i ~/.ssh/id_ed25519_unraid -P 422 update-icons.sh root@192.168.10.20:/boot/config/plugins/custom.css/assets/update-icons.sh
scp -i ~/.ssh/id_ed25519_unraid -P 422 update-icons.sh root@192.168.10.20:/usr/local/emhttp/plugins/custom.css/assets/update-icons.sh
scp -i ~/.ssh/id_ed25519_unraid -P 422 vm-icons.conf root@192.168.10.20:/boot/config/plugins/custom.css/assets/vm-icons.conf
Static assets deploy to persistent + web-accessible paths:
# Icons
scp -i ~/.ssh/id_ed25519_unraid -P 422 -r assets/icons/ root@192.168.10.20:/boot/config/plugins/custom.css/assets/icons/
ssh -i ~/.ssh/id_ed25519_unraid root@192.168.10.20 -p 422 'mkdir -p /usr/local/emhttp/custom/assets && cp -r /boot/config/plugins/custom.css/assets/icons /usr/local/emhttp/custom/assets/'
# Wallpaper
scp -i ~/.ssh/id_ed25519_unraid -P 422 assets/wallpaper.jpg root@192.168.10.20:/boot/config/plugins/custom.css/assets/wallpaper.jpg
ssh -i ~/.ssh/id_ed25519_unraid root@192.168.10.20 -p 422 'cp /boot/config/plugins/custom.css/assets/wallpaper.jpg /usr/local/emhttp/custom/assets/'
Boot persistence is handled by /boot/config/go which copies icons/wallpaper to /usr/local/emhttp/custom/assets/ on startup.
JS injection is handled by CustomJS_Loader.page on the server (persisted via /boot/config/go).
Unraid Sidebar DOM Structure
#menu (position: fixed — Unraid's default, DO NOT override)
├── #sidebar-logo (injected by sidebar.js — absolute positioned)
├── #sidebar-toggle-btn (injected by sidebar.js — absolute positioned)
└── #nav-block (position: absolute; top:0; bottom:12px; width:100% — Unraid's default)
├── .nav-tile (main nav items — block flow)
│ └── .nav-item > a (display: inline-flex — Unraid's default)
│ ├── ::before (icon via font-family: docker-icon, fontawesome, unraid)
│ ├── bare text node (page name, not wrapped in span)
│ ├── <b> (only on utility items, display: none in our CSS)
│ └── <span> (only on utility items, display: none in collapsed)
└── .nav-tile.right (utility nav items)
└── .nav-item.CLASSNAME.util > a
├── ::before (icon code from page Code= property)
├── <b class="icon-u-XXX system"> (icon from page Icon= property)
└── <span>Label</span>
Critical CSS Lessons
DO NOT override position on #menu
Unraid sets position: fixed on #menu. Overriding with position: relative causes the sidebar to collapse and disappear.
DO NOT override display on .nav-item a
Unraid sets display: inline-flex on .Theme--sidebar .nav-item a. Fighting this with display: grid or display: block doesn't reliably work. Instead, work WITH inline-flex:
- Center inline elements via
text-align: centeron parent.nav-item - Center icon via
position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%)on::before
backdrop-filter creates a containing block
backdrop-filter on #menu creates a new containing block for position: fixed descendants. This means position: fixed inside the sidebar is relative to #menu, NOT the viewport. The search popup must be moved to document.body via JS to escape this.
Work WITH #nav-block, don't replace it
Unraid's #nav-block has position: absolute; top: 0; bottom: 12px; width: 100%; overflow-y: scroll. Only override top (to clear logo+toggle space) and padding-left. Don't add flex/grid layout.
Utility items have DOUBLE icons
Utility .nav-item elements have BOTH a ::before pseudo-element (from page Code= property) AND a <b> HTML element (from page Icon= property). Hide <b> with .nav-item a > * { display: none }.
font-size: 0 for hiding bare text nodes
Main nav items have bare text nodes (not wrapped in <span>). CSS display: none can't target text nodes. Use font-size: 0 on the a element, then explicit font-size on ::before.
gap affects invisible flex items
Even with font-size: 0, text nodes are still flex items. With gap: 25px (Unraid default), invisible text creates spacing. Override gap: 0 in collapsed mode.
Icon Fonts on Unraid
| Font | Family name | Used by |
|---|---|---|
| Unraid icons | unraid |
icon-u-* classes, utility nav ::before (thicker strokes) |
| Font Awesome 4 | FontAwesome |
.fa classes, single weight only |
| Docker icons | docker-icon |
Docker page nav icon |
| Combined | docker-icon, fontawesome, unraid |
Main nav ::before (set by Unraid CSS) |
Utility nav ::before icons use the unraid font which has heavier strokes. We replace them with FontAwesome equivalents for consistent thin appearance.
Utility Button Pages
| Class name | Title | FA4 replacement |
|---|---|---|
gui_search |
Search | \f002 |
LanguageButton |
Switch Language | \f0ac |
LogoutButton |
Logout | \f08b |
TerminalButton |
Terminal | \f120 |
BrowseButton |
File Manager | \f115 |
FeedbackButton |
Feedback | \f075 |
InfoButton |
Info | \f05a |
LogButton |
Log | \f0f6 |
HelpButton |
Help | \f059 |
LockButton |
Lock/Unlock | \f09c (no page Code=, needs manual ::before) |
Search Overlay
The dynamix.gui.search plugin uses hover-trigger in sidebar theme. We replace it with:
- Click-trigger on the search nav-item
gui_search()creates#guiSearchBoxSpaninside the sidebar- JS moves it to
document.body(escapes backdrop-filter containing block) - Backdrop overlay with blur
- Cmd+K / Ctrl+K keyboard shortcut
- Escape to close
Custom Docker/VM Icons
Icons are sourced from selfh.st/icons and self-hosted locally in assets/icons/ (no CDN dependency).
How it works
update-icons.sh reads a glass.icon Docker label from each container, downloads the matching PNG from https://cdn.jsdelivr.net/gh/selfhst/icons@main/png/{name}.png, and replaces Unraid's cached icon files. This works on Docker page, VM page, and Dashboard — no client-side JS needed.
Docker label convention
Add label glass.icon to containers:
- Short name:
glass.icon=plex→ fetches from selfh.st CDN - Full URL:
glass.icon=https://example.com/icon.png→ fetches from URL - No label: auto-detects from container name (lowercase + CDN HEAD check)
VM icons
Edit vm-icons.conf with VM_NAME=icon_name entries (one per line).
Running
# Dry run (show what would change)
ssh -i ~/.ssh/id_ed25519_unraid root@192.168.10.20 -p 422 'bash /boot/config/plugins/custom.css/assets/update-icons.sh --dry-run'
# Real run
ssh -i ~/.ssh/id_ed25519_unraid root@192.168.10.20 -p 422 'bash /boot/config/plugins/custom.css/assets/update-icons.sh'
# Force re-download all
ssh -i ~/.ssh/id_ed25519_unraid root@192.168.10.20 -p 422 'bash /boot/config/plugins/custom.css/assets/update-icons.sh --force'
Icon paths on Unraid
- RAM cache:
/usr/local/emhttp/state/plugins/dynamix.docker.manager/images/{Name}-icon.png - Persistent:
/var/lib/docker/unraid/images/{Name}-icon.png - VM templates:
/usr/local/emhttp/plugins/dynamix.vm.manager/templates/images/
Wallpaper
Source: Unsplash NuBvAE6VfSM (B&W mountains). Tracked in repo as assets/wallpaper.jpg.
- Persistent:
/boot/config/plugins/custom.css/assets/wallpaper.jpg - Web-accessible:
/usr/local/emhttp/custom/assets/wallpaper.jpg→/custom/assets/wallpaper.jpg