# FolderView3 Custom CSS & JS Developer Guide ## Overview FolderView3 supports custom CSS and JavaScript extensions that load alongside the plugin on each tab. You can restyle folders, tooltips, container rows, and the dashboard — or add custom behavior via the JavaScript event system. **Custom file locations on Unraid:** - **CSS:** `/boot/config/plugins/folder.view3/styles/` - **JS:** `/boot/config/plugins/folder.view3/scripts/` These directories persist across reboots (they live on the USB flash drive). --- ## File Naming Files must follow the pattern: **`name.tab.ext`** | Part | Description | |------|-------------| | `name` | Any string (your theme name, a load-order prefix, etc.) | | `tab` | One or more of: `docker`, `vm`, `dashboard` (chain with `-`) | | `ext` | `.css` or `.js` | **Examples:** ``` mytheme.docker.css → Docker tab only mytheme.vm.css → VM tab only mytheme.dashboard.css → Dashboard only mytheme.docker-vm.css → Docker + VM tabs mytheme.dashboard-docker-vm.css → All three tabs 01-colors.docker-vm.css → Prefixed for load ordering ``` **Will NOT work:** ``` mytheme-docker.css → Hyphen instead of dot separator mytheme_docker.css → Underscore separator mytheme.css → Missing tab name ``` **Disabling:** Append `.disabled` to any file to skip loading without deleting it: ``` mytheme.docker.css.disabled ``` --- ## Load Order Custom files load **after** the plugin's built-in CSS, so your rules naturally override defaults. No `!important` should be needed for most overrides — use CSS variables where possible. ``` 1. customEvents.js (shared utilities: escapeHtml, CSRF, event bus) 2. shared.js (shared functions: debug, API, row separators, preview) 3. Custom JS files (your scripts) 4. Plugin JS (docker.js / vm.js / dashboard.js) 5. folder-common.css (shared CSS variables and rules) 6. Plugin CSS (docker.css / vm.css / dashboard.css) 7. Custom CSS files (your styles — loaded last, highest priority) ``` --- ## CSS Variables Reference Override these in your custom CSS by redefining them in `:root`. All are defined in `folder-common.css` (loaded on Docker and VM tabs). ### Layout | Variable | Default | Description | |----------|---------|-------------| | `--fv3-folder-name-width` | `220px` | Width of the folder name cell | | `--fv3-folder-preview-height` | `3.5em` | Height of the collapsed folder preview bar | | `--fv3-folder-preview-radius` | `4px` | Border radius of the preview bar | | `--fv3-folder-icon-spacing` | `4px` | Gap between container icons in preview | | `--fv3-folder-preview-wrapper-margin` | `10px` | Left margin of each preview icon wrapper | | `--fv3-folder-name-min-width` | `220px` | Minimum width of folder name cell | | `--fv3-folder-name-gap` | `4px` | Gap between folder name elements | | `--fv3-folder-row-padding` | `0` | Padding around folder rows | | `--fv3-folder-row-radius` | `0` | Border radius on folder rows | | `--fv3-folder-row-border-width` | `0` | Border width on folder rows | | `--fv3-row-padding` | `8px` | General row content padding | | `--tooltip-spacing` | `5px` | Spacing around tooltip content | ### Advanced Preview Tooltip | Variable | Default | Description | |----------|---------|-------------| | `--fv3-tooltip-min-width` | `700px` | Minimum width of the advanced preview popup | | `--fv3-tooltip-max-height` | `80vh` | Maximum height of the advanced preview popup | | `--fv3-tooltip-action-pane-width` | `220px` | Width of the action button sidebar | ### Colors — Global (all pages) | Variable | Default | Description | |----------|---------|-------------| | `--fv3-accent-color` | `var(--color-orange, #f0a30a)` | Accent color for panels and borders | | `--fv3-surface-tint` | `rgba(128, 128, 128, 0.1)` | Subtle background tint | | `--fv3-hover-bg` | `rgba(128, 128, 128, 0.2)` | Hover state background | | `--fv3-border` | `1px solid rgba(128, 128, 128, 0.3)` | Standard border style | | `--fv3-folder-name-bg` | `transparent` | Folder name cell background | | `--fv3-folder-name-color` | `inherit` | Folder name text color | | `--fv3-appname-color` | `inherit` | Container/VM name text color | | `--fv3-folder-icon-size` | `48px` | Folder icon size | | `--fv3-folder-name-size` | `inherit` | Folder name font size | | `--fv3-folder-name-weight` | `inherit` | Folder name font weight | ### Colors — Docker & VM tabs only | Variable | Default | Description | |----------|---------|-------------| | `--folder-view3-graph-cpu` | `#2b8da3` | CPU graph line color (Docker only) | | `--folder-view3-graph-mem` | `#5d6db6` | Memory graph line color (Docker only) | | `--fv3-toggle-color` | `#ff8c2f` | Folder chevron dropdown button color | | `--fv3-toggle-hover-color` | `#ffad5c` | Chevron button hover color | | `--fv3-chevron-color` | `inherit` | Expand/collapse chevron color | | `--fv3-preview-border-color` | `currentColor` | Preview area border color | | `--fv3-vertical-bars-color` | `currentColor` | Vertical divider bar color | | `--fv3-separator-color` | `rgba(128, 128, 128, 0.3)` | Row separator color (expand mode) | | `--fv3-separator-bg` | `rgba(128, 128, 128, 0.15)` | Row separator background | | `--fv3-folder-row-border-color` | `transparent` | Folder row border color | | `--fv3-preview-row-border-width` | `0` | Preview area row border width | | `--fv3-preview-row-border-color` | `transparent` | Preview area row border color | | `--fv3-scrollbar-color` | `rgba(255, 140, 47, 0.5)` | Scroll overflow scrollbar thumb | | `--fv3-folder-preview-bg` | `transparent` | Preview bar background color | | `--fv3-preview-icon-size` | `32px` | Container icon size in preview | | `--fv3-appname-max-width` | `120px` | Max width before container names truncate | | `--fv3-appname-size` | `inherit` | Container name font size in previews | | `--fv3-chevron-size` | `14px` | Chevron button font size | | `--fv3-row-bg` | `transparent` | Folder row background | | `--fv3-row-alt-bg` | Unraid's `--dynamix-tablesorter-tbody-row-alt-bg-color` | Alternating row background | ### Colors — Dashboard only | Variable | Default | Description | |----------|---------|-------------| | `--fv3-panel-border` | `rgba(128, 128, 128, 0.2)` | Fullwidth/accordion panel border | | `--fv3-panel-bg` | `rgba(128, 128, 128, 0.08)` | Panel background | | `--fv3-tab-active-bg` | `transparent` | Expanded tab background | | `--fv3-tab-active-border` | `transparent` | Expanded tab border | | `--fv3-showcase-bg` | `transparent` | Showcase (child area) background | | `--fv3-inset-bg` | `transparent` | Inset expanded outer wrapper bg | | `--fv3-inset-fill` | `none` | Inset SVG L-shape fill | | `--fv3-inset-border-color` | `rgba(128,128,128,0.3)` | Inset SVG outer border | | `--fv3-inset-showcase-fill` | `none` | Inset SVG inner box fill | | `--fv3-inset-showcase-border` | `rgba(128,128,128,0.2)` | Inset SVG inner box border | | `--fv3-embossed-border` | `rgba(128,128,128,0.3)` | Embossed outer border | | `--fv3-embossed-accent` | `var(--color-orange, #f0a30a)` | Embossed left accent border | | `--fv3-embossed-inner-border` | `rgba(128,128,128,0.2)` | Embossed inner showcase border | **Example override:** ```css :root { --fv3-accent-color: #e74c3c; --fv3-toggle-color: #e74c3c; --fv3-toggle-hover-color: #ff6b6b; --fv3-folder-preview-bg: rgba(0, 0, 0, 0.05); --fv3-row-bg: #191818; --fv3-row-alt-bg: #212121; } ``` --- ## Dashboard Layout Classes FolderView3 adds layout classes to the container `` when a non-classic dashboard layout is selected. These are useful for custom CSS targeting. | Class | Applied to | Description | |-------|-----------|-------------| | `.fv3-layout-classic` | Container `` | Classic mode — Unraid's native tile layout with `display: flex; flex-wrap: wrap` | | `.fv3-layout-inset` | Container `` | Inset panel mode — expanded folders shown with SVG L-shaped borders | | `.fv3-layout-embossed` | Container `` | Embossed mode — expanded folders shown with solid CSS borders and colored backgrounds | | `.fv3-layout-accordion` | Container `` | Accordion mode — all folders stacked vertically | | `.fv3-layout-fullwidth` | Container `` | Full-width panel mode — expanded children span the full row width | | `.fv3-fullwidth-panel` | Injected `
` | The full-width child panel (inserted after the last tile in the folder's row) | | `.folder-showcase-outer` | Wrapper `
` | Wraps each folder's tile + showcase + storage on the Dashboard | | `.fv3-greyscale-active` | Container `` | Applied when any folder is expanded and greyscale dimming is enabled — dims non-expanded folders and standalone tiles | | `.fv3-hidden` | `.folder-showcase-outer` | Applied when "Started only" hides a stopped folder | | `.fv3-standalone` | `span.outer` | Applied to containers/VMs on the Dashboard that are not inside any folder | | `.fv3-collapse-toggle` | `button` inside folder tile | The collapse chevron button shown on expanded folders (positioned absolutely via JS) | | `.fv3-expanded-tab` | `span.outer` folder tile | Applied to the folder tile when expanded — adds `position: relative` for collapse toggle positioning | | `.fv3-folder-hand` / `.fv3-folder-hand-docker` / `.fv3-folder-hand-vm` | `span` inside folder tile | Icon wrapper (clickable area around folder icon) | | `.fv3-folder-icon` / `.fv3-folder-icon-docker` / `.fv3-folder-icon-vm` | `img` inside `.fv3-folder-hand` | The folder icon image | | `.fv3-folder-inner` / `.fv3-folder-inner-docker` / `.fv3-folder-inner-vm` | `span` inside folder tile | Text wrapper containing name + state | | `.fv3-folder-appname` / `.fv3-folder-appname-docker` / `.fv3-folder-appname-vm` | `span` inside `.fv3-folder-inner` | The folder's name text — target with `[expanded="true"]` parent for expanded-only styling | | `.fv3-folder-status-icon` / `.fv3-folder-status-icon-docker` / `.fv3-folder-status-icon-vm` | `i.fa` inside `.fv3-folder-inner` | Play/square status icon | | `.fv3-folder-state` / `.fv3-folder-state-docker` / `.fv3-folder-state-vm` | `span` inside `.fv3-folder-inner` | The "X/Y started" or "stopped" status text | | `.fv3-folder-storage` | `div` inside folder tile | Hidden container for collapsed children | | `.fv3-folder-showcase` | `div` inside `.folder-showcase-outer` | Container for expanded children (inset/accordion/embossed) | | `.fv3-child-appname` | `span.inner` inside child tiles | The child container/VM name wrapper inside an expanded folder's showcase | | `.fv3-child-appname-text` | `span` inside `.fv3-child-appname` | The actual container/VM name text span — use this to style individual child names | | `.fv3-label-hidden` | Container `` | Applied when "Show folder name in expanded panel" is set to No | | `.fv3-inset-border` | SVG element | The SVG wrapper for the inset layout's L-shape + inner box borders | | `.fv3-inset-lshape` | SVG `path` | The L-shaped outer border path (tab + body) — styled via CSS custom properties | | `.fv3-inset-innerbox` | SVG `rect` | The inner container box border — styled via CSS custom properties | ### Dashboard CSS Custom Properties These variables can be set on the layout class (e.g., `.fv3-layout-inset`) or `:root` to customize dashboard panels. **Inset Panel (SVG borders):** | Variable | Default | Description | |----------|---------|-------------| | `--fv3-inset-border-color` | `rgba(128,128,128,0.3)` | SVG L-shape outer border stroke | | `--fv3-inset-fill` | `none` | SVG L-shape fill (tab + content area background) | | `--fv3-inset-showcase-border` | `rgba(128,128,128,0.2)` | SVG inner box stroke | | `--fv3-inset-showcase-fill` | `none` | SVG inner box fill (showcase area background) | | `--fv3-inset-bg` | `transparent` | CSS background of the expanded outer wrapper | | `--fv3-showcase-bg` | `transparent` | CSS background of the showcase (child area) | **Embossed Panel (two-box layout — outer wrapper + inner showcase):** | Variable | Default | Description | |----------|---------|-------------| | `--fv3-embossed-border` | `rgba(128,128,128,0.3)` | Outer wrapper border color | | `--fv3-embossed-accent` | `var(--color-orange, #f0a30a)` | Outer left accent border color | | `--fv3-embossed-bg` | `transparent` | Outer wrapper background color | | `--fv3-embossed-shadow` | `none` | Outer wrapper inset shadow | | `--fv3-embossed-inner-border` | `rgba(128,128,128,0.2)` | Inner showcase border color | | `--fv3-embossed-inner-bg` | `rgba(128,128,128,0.08)` | Inner showcase background color | **Example — custom Inset colors:** ```css .fv3-layout-inset { --fv3-inset-border-color: #cfcfcf; --fv3-inset-fill: rgba(235,235,235,0.5); --fv3-inset-showcase-border: #c1c1c1; --fv3-inset-showcase-fill: rgba(251,245,227,0.5); } ``` **Example — custom Embossed colors:** ```css .fv3-layout-embossed { --fv3-embossed-border: #cfcfcf; --fv3-embossed-accent: #bababa; --fv3-embossed-bg: #ebebeb; --fv3-embossed-shadow: inset 0 1px 3px rgba(0,0,0,0.1); --fv3-embossed-inner-border: #c1c1c1; --fv3-embossed-inner-bg: #fbf5e3; } ``` ### Dashboard Child Panel Styling Expanded folder children on the Dashboard are rendered inside `.folder-showcase` (inset/accordion) or `.fv3-fullwidth-panel` (fullwidth). The child `span.outer` tiles receive these overrides: ```css /* Remove tile chrome inside expansion panels */ .fv3-layout-inset .folder-showcase > span.outer.solid, .fv3-layout-embossed .folder-showcase > span.outer.solid, .fv3-layout-accordion .folder-showcase > span.outer.solid, .fv3-fullwidth-panel > span.outer.solid { transform: none; background: none; border: none; box-shadow: none; overflow: hidden; } ``` The `.solid` / `.apps` suffix provides enough specificity to override Unraid's base `span.outer` styles without `!important`. ### Dashboard Layout Override Examples ```css /* Change the expansion panel border color (accordion/fullwidth) */ .fv3-layout-accordion .folder-showcase:not(:empty), .fv3-fullwidth-panel { border-color: rgba(255, 165, 0, 0.3); } /* Change inset SVG border colors via CSS variables */ .fv3-layout-inset { --fv3-inset-border-color: rgba(255, 165, 0, 0.3); --fv3-inset-showcase-border: rgba(255, 165, 0, 0.2); } /* Change embossed border colors via CSS variables */ .fv3-layout-embossed { --fv3-embossed-border: rgba(255, 165, 0, 0.3); --fv3-embossed-accent: rgba(255, 165, 0, 0.5); } /* Hide the folder name label in expansion panels */ .fv3-layout-inset .folder-showcase::after, .fv3-layout-embossed .folder-showcase::after, .fv3-layout-accordion .folder-showcase::after, .fv3-fullwidth-panel::after { display: none !important; } /* Style accordion folder tiles to full width */ .fv3-layout-accordion .folder-showcase-outer > span.outer { width: 100%; } ``` --- ## DOM Structure ### Folder Row (Docker & VM Tabs) ```html
Folder Name stopped
...
0%
...
0 / 0 ... ``` ### Expanded Container Row ```html ``` ### Dashboard Folder (Tile Layout) ```html ...
Folder Name 2/5 started
Container Name
...
``` ### Advanced Preview Tooltip ```html
Folder Name
... ... ...
``` ### Container Status Indicator (Only icon preview, added 2026.05.21) When a folder's Preview is set to **Only icon** and Container/VM status is **Symbol**, each container icon in the preview row gets a small play/square indicator next to it on a second line (similar to how the icon-and-label preview shows them). ```html
data-fv3-state="running" data-fv3-name="qbittorrent"> ...
``` **Selectors:** | Selector | Purpose | |----------|---------| | `tr.folder[data-fv3-preview-status="symbol"]` | Folder row in icon-only mode with status icons enabled | | `tr.folder[data-fv3-preview-status="grayscale"]` | Folder row in icon-only mode with stopped-greyscale enabled (desaturates `span.hand` of stopped containers) | | `.folder-preview-wrapper[data-fv3-state="running"]` | Per-container preview wrapper, running state | | `.folder-preview-wrapper[data-fv3-state="stopped"]` | Per-container preview wrapper, stopped state | | `.fv3-status-icon` | The `` element. **Distinct from the folder-level `.fv3-folder-status-icon`** — this one lives per-container inside the preview row, not on the folder pill on Dashboard. Running uses `fa-play.started.green-text`, stopped uses `fa-square.stopped.red-text`. | | `.fv3-status-line` | The `
` element that pushes the status icon to a second line | **Example: Change the running indicator from green play to a checkmark** ```css .folder-preview-wrapper[data-fv3-state="running"] .fv3-status-icon::before { content: "\f00c"; /* fa-check */ color: limegreen; } .folder-preview-wrapper[data-fv3-state="running"] .fv3-status-icon { color: limegreen; } ``` **Example: Replace symbol with a colored dot** ```css .fv3-status-icon { font-size: 0; width: 8px; height: 8px; border-radius: 50%; } .folder-preview-wrapper[data-fv3-state="running"] .fv3-status-icon { background: #4caf50; } .folder-preview-wrapper[data-fv3-state="stopped"] .fv3-status-icon { background: #e53935; } ``` ### Folder Editor Form (added 2026.05.21) The folder editor page (`/Docker/Folder` or `/VMs/Folder`) gained a Delete button in the form footer. ```html
``` **Selectors:** | Selector | Purpose | |----------|---------| | `.fv3-form-actions` | Flex row holding the form's footer buttons (Submit/Cancel on left, Delete on right) | | `.fv3-form-actions-right` | Container for the right-aligned Delete button. Only rendered when editing an existing folder (not on create). | | `.fv3-delete-folder-btn` | The Delete button itself. Default red; override `background`, `color`, `border-color` to restyle. | ### Settings Page Constraint Engine (added 2026.05.21) The Settings → FolderView3 → Folder Defaults panel uses a declarative visibility system. Each setting row's `
` carries a `data-fv3-show-preview="..."` attribute listing the Preview values (0/1/2/3/4) for which it's relevant. JS toggles `display` accordingly. Customizers can target these conditionally: ```css /* Style settings rows that are currently hidden by the constraint engine */ .fv3-page-panel .basic[style*="display: none"] { /* won't normally apply since display:none hides */ } /* Style row when active for a specific preview mode */ .basic[data-fv3-show-preview~="2"] { /* matches rows shown in Only icon mode */ } ``` The Dashboard panel also adds: - `dashboard-context` select (Default / Advanced) — global toggle for the Dashboard advanced preview popup - `.fv3-dashboard-context-advanced` — sub-option rows visible only when context = Advanced ### Advanced Preview Tooltip Background (changed 2026.05.21) The popup background used to inherit (often resolving to transparent). It now resolves to `var(--background-color, rgb(29, 27, 27))` — Unraid's theme-aware page background. Customizers who were previously setting `.preview-outbox { background-color: ... }` continue to work; the change just gives a sensible default when no override is present. The outer `.tooltipster-base` is now `background: transparent;` so the tooltipster arrow appears clean without a surrounding box. The actual popup surface comes from `.preview-outbox`. --- ## Common Styling Recipes | Goal | CSS | |------|-----| | Change folder name width | `:root { --fv3-folder-name-width: 180px; }` | | Change preview bar height | `:root { --fv3-folder-preview-height: 2.5em; }` | | Style folder name text | `.folder-name-sub .folder-appname { font-size: 1.5rem; font-weight: bold; }` | | Style folder icon | `.folder-img { width: 36px; height: 36px; }` | | Style icon hover | `.folder-img:hover { transform: scale(1.2); }` | | Change preview icon spacing | `:root { --fv3-folder-icon-spacing: 8px; }` | | Style expanded container rows | `.folder-element { background-color: rgba(0,0,0,0.05); }` | | Style CPU/Memory text | `.folder-cpu { color: #00BCD4; } .folder-mem { color: #673AB7; }` | | Change graph colors | `:root { --folder-view3-graph-cpu: #00BCD4; --folder-view3-graph-mem: #673AB7; }` | | Style tooltip background | `.preview-outbox { background-color: #1c1b1b; }` | | Style preview dividers | `.folder-preview-divider { border-color: #444 !important; }` | | Style expanded folder name | `.folder-showcase-outer[expanded="true"] .fv3-folder-appname { font-weight: bold; color: #f0a30a; }` | | Style child container names | `.fv3-child-appname-text { font-weight: bold; color: #00698c; }` | | Hide folder start/stop text | `.folder-state { display: none; }` | | Style dropdown chevron | `.folder-dropdown { color: #607D8B; }` | --- ## JavaScript Extension Events The plugin dispatches custom events via `folderEvents` (a shared `EventTarget`). Listen in your custom JS: ```javascript folderEvents.addEventListener('docker-post-folder-creation', (e) => { const { id, folder } = e.detail; // DOM is ready — modify the folder row }); ``` ### Available Events **Docker tab:** | Event | Fired | Detail | |-------|-------|--------| | `docker-pre-folders-creation` | Before any folders render | `{ folders, containerInfo, order }` | | `docker-post-folders-creation` | After all folders render | `{ folders, containerInfo, order }` | | `docker-pre-folder-creation` | Before a single folder renders | `{ id, folder }` | | `docker-post-folder-creation` | After a single folder renders | `{ id, folder }` | | `docker-pre-folder-preview` | Before preview icons are built | `{ id, folder }` | | `docker-post-folder-preview` | After preview icons are built | `{ id, folder }` | | `docker-pre-folder-expansion` | Before folder expands/collapses | `{ id }` | | `docker-post-folder-expansion` | After folder expands/collapses | `{ id }` | | `docker-tooltip-before` | Before advanced preview opens | `{ id }` | | `docker-tooltip-ready-start` | Tooltip DOM created, before content | `{ id }` | | `docker-tooltip-ready-end` | Tooltip fully populated | `{ id }` | | `docker-tooltip-after` | After tooltip closes | `{ id }` | | `docker-folder-context` | Right-click context menu opens | `{ id, opts }` | **VM tab:** Same pattern with `vm-` prefix (no tooltip events). **Dashboard:** Dispatches both `docker-` and `vm-` events for their respective folder types. --- ## Theme Compatibility Tips 1. **Never use hardcoded colors.** Use `inherit`, `currentColor`, or `rgba()` so your theme works on both Unraid dark and light themes. 2. **Prefer CSS variables over `!important`.** Override `--fv3-*` variables in `:root` — this is the intended customization mechanism. 3. **Docker and VM share selectors.** `.folder-name-sub`, `.folder-outer`, `.folder-preview`, `.folder-dropdown` — if you style one, consider whether you need to style both. 4. **Dashboard has a different DOM structure** than Docker/VM tabs. Dashboard uses tile-based layout, not table rows. Test your theme on all three tabs. 5. **Scope your selectors.** Use `#docker_containers` or `#kvm_table` to target specific tabs and avoid accidentally styling other plugins' elements. 6. **Unraid theme variables** are available. For example, `--dynamix-tablesorter-tbody-row-alt-bg-color` provides the current theme's alternating row color. 7. **Cache busting.** Unraid's `autov()` appends a version hash to file URLs. If your changes aren't appearing, rename the file or clear your browser cache. --- ## Community Themes These community themes serve as working examples: - [hernandito/folder.view.custom](https://github.com/hernandito/folder.view.custom) — Compact and Midsize designs - [Mattaton/folder.view.custom.css](https://github.com/Tyree/folder.view.custom.css) — urblack, urgray, urwhite themes - [masterwishx/folder.view.custom.css](https://github.com/masterwishx/folder.view.custom.css) — urblack theme with extensive CSS variable system --- ## Default Styles The plugin's built-in stylesheets for reference: - [folder-common.css](../src/folder.view3/usr/local/emhttp/plugins/folder.view3/styles/folder-common.css) — shared variables and rules (Docker + VM) - [docker.css](../src/folder.view3/usr/local/emhttp/plugins/folder.view3/styles/docker.css) — Docker-specific (tooltips, context menu) - [vm.css](../src/folder.view3/usr/local/emhttp/plugins/folder.view3/styles/vm.css) — VM-specific - [dashboard.css](../src/folder.view3/usr/local/emhttp/plugins/folder.view3/styles/dashboard.css) — Dashboard layouts ## CSS Template A starter template for custom themes is available at [examples/custom-template.css](examples/custom-template.css). Copy it to `/boot/config/plugins/folder.view3/styles/` on your Unraid server and rename it following the naming convention above. ## CSS Tool & Theme Manager The FolderView3 settings page includes a built-in CSS Tool with: - **Themes** — Import community CSS themes from GitHub (`owner/repo`). One theme active at a time. Automatic update checking via GitHub API SHA comparison. - **Variables** — Edit all 27 CSS variables with color pickers and sliders. Per-page scope (Global/Dashboard/Docker/VM). - **Presets** — One-click preset themes (Default, Compact, Blue Accent, Muted). - **Advanced CSS** — Free-form CSS textarea for custom rules. ### Generated CSS File The CSS Tool generates `_fv3-generated.docker-vm-dashboard.css` in the styles directory. It loads before user CSS (underscore prefix sorts first) and contains: - `:root {}` block with overridden variable values - Custom CSS from the Advanced tab ### Theme File Convention Imported themes are stored as subdirectories in `/boot/config/plugins/folder.view3/styles/`: - `masterwishx/` — active theme folder - `masterwishx.disabled/` — disabled theme (`.disabled` suffix) - `.fv3-source` — JSON file inside theme folder with repo URL and file SHAs for update checking ### PHP Endpoints (CSS Tool) | Endpoint | Method | Purpose | |----------|--------|---------| | `read_css_config.php` | GET | Read CSS config | | `read_css_defaults.php` | GET | Get all variable defaults | | `update_css_config.php` | POST | Save CSS config + generate CSS | | `list_themes.php` | GET | List installed themes | | `toggle_theme.php` | POST | Enable/disable theme | | `import_theme.php` | POST | Import from GitHub | | `delete_theme.php` | POST | Delete theme | | `export_all.php` | GET | Full backup (all configs + CSS) | | `import_all.php` | POST | Restore full backup | ## Folder Defaults System Global defaults are stored in `settings.json` with keys like `default_preview`, `default_overflow`, `default_preview_hover`, etc. When rendering, `fv3ApplyDefaults()` in `shared.js` merges defaults into any folder whose settings are unset. New folders created via Folder.page are pre-filled from these defaults. The "Apply Defaults to All Folders" button on the settings page reads current defaults and writes them to every existing folder config. ## Theme Manager ### Import Flow 1. User enters `owner/repo` (or `owner/repo:branch`) → JS fetches GitHub Contents API (1 call) 2. If repo has subdirectories with CSS (e.g. masterwishx, hernandito) → directory picker shown with checkboxes for multi-select 3. Selected directories are sent to PHP `import_theme.php` which fetches file listing (1 API call per dir) and downloads via `raw.githubusercontent.com` (no API limit) 4. PHP scans downloaded CSS for security warnings, returns results to JS 5. If external URLs found → progress dialog shows warnings, user chooses Keep/Delete 6. `.fv3-source` JSON file stored in theme folder: `{ "repo": "owner/repo", "path": "subdir", "branch": "branch", "files": { "file.css": "sha" }, "updated": "ISO date" }` 7. Non-default branch names (not `main`/`master`) are appended to the theme folder name ### Update Checking On settings page load, each theme's SHAs are compared against GitHub API. Status shown per-theme: - Spinner while checking - Green checkmark + "up-to-date" if all SHAs match - Blue cloud + "update ready" if any file changed ### Security Scanning On every import/update, downloaded CSS files are scanned server-side by PHP (`fv3_scan_css_warnings()` in `lib.php`) for: - `url()` — external resource loading (could track users or load malicious content) - `@import` — external stylesheet loading - `expression()` — IE script execution - `javascript:` — script execution The scan happens **after download** on the Unraid server, not via the GitHub API. This is safe because CSS files on disk are inert — external URLs are only fetched when a browser renders the stylesheet. If external `url()` references are found, the progress dialog shows each flagged URL and prompts the user to **Keep** or **Delete** the theme. The CSS Tool's Advanced CSS textarea strips `@import`, `expression()`, and `javascript:` on save. ### PHP Endpoints (Theme Manager) | Endpoint | Method | Purpose | |----------|--------|---------| | `list_themes.php` | GET | Scan styles dir, return themes with source data | | `toggle_theme.php` | POST | Enable/disable (rename with `.disabled`), exclusive mode | | `import_theme.php` | POST | Fetch from GitHub API, supports `path` param for subdirs | | `delete_theme.php` | POST | Recursive delete, `_fv3-generated` protected | ### Full Backup | Endpoint | Method | Purpose | |----------|--------|---------| | `export_all.php` | GET | Returns JSON bundle: docker/vm folders, settings, CSS config, custom styles | | `import_all.php` | POST | Restores bundle with path traversal prevention | Custom styles over 2MB are excluded from export with a warning. The bundle format: ```json { "fv3_export_version": 1, "docker": {}, "vm": {}, "settings": {}, "css_config": {}, "custom_styles": { "theme-dir/file.css": "/* css content */" } } ``` ## Debug Mode Type **fv3debug** on any FolderView3 page to toggle debug logging. When enabled, the browser console shows folder creation, API calls, organizer sync, and stats updates with `[FV3]` prefix. State persists in localStorage across page loads.