mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
feat(theme): runtime custom theme ecosystem (graphics-only)
Runtime-loaded visual re-skin system (no client rebuild, real themes never hit git). A theme = a folder on the server (theme.base.url) with a manifest + CSS "pieces"; each piece is toggled from Settings > Themes (checkboxes). A broken/404 piece auto-falls back to the default (per piece). Hotel-wide default via ui-config theme.default (+ theme.default.pieces), per-user override in localStorage (same pattern as the catalog style toggle). - api/theme/ThemeManager: fetch index/manifest + inject/remove <link> + fallback - hooks/theme/useThemes: state + persist + default-from-config + live apply - components/theme/ThemeApplier: applies on boot (mounted in MainView) - UserSettings: General/Themes tabs with theme selector + per-piece checkboxes - custom-themes/: reference template (demo theme "Neon Viola" + README) - .gitignore: public/custom-themes/ (real themes are never committed)
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
# Custom themes (graphics-only)
|
||||
|
||||
Ecosistema temi caricati a **runtime** (niente rebuild del client). Un tema =
|
||||
una cartella con un manifest + "pezzi" CSS. Ogni pezzo è attivabile/disattivabile
|
||||
dall'utente da **Impostazioni → Temi** (checkbox). Se un pezzo è rotto/404 →
|
||||
fallback automatico al default (solo quel pezzo).
|
||||
|
||||
## Dove vivono
|
||||
- **Questa cartella (`custom-themes/`) è solo il TEMPLATE di riferimento**, versionata su git.
|
||||
- I temi **veri** stanno sul server in `public/nitro/custom-themes/` (serviti via
|
||||
l'url configurato in ui-config `theme.base.url`, es. `/client/nitro/custom-themes`).
|
||||
NON vanno su git → vedi `.gitignore` (`public/custom-themes/`).
|
||||
|
||||
## Struttura
|
||||
```
|
||||
custom-themes/
|
||||
index.json # { "themes": [ { "id", "name", "author?" } ] }
|
||||
<id>/
|
||||
theme.json # { "name", "pieces": [ { "id", "name", "file" } ] }
|
||||
cards.css chat.css ... # un file per "pezzo"
|
||||
assets/... # immagini referenziate dai CSS (url assoluti)
|
||||
```
|
||||
|
||||
## Creare un tema
|
||||
1. Copia `neon-viola/` in una nuova cartella `<id>/`.
|
||||
2. Modifica `theme.json` (nome + elenco pezzi).
|
||||
3. Scrivi i CSS dei pezzi (override con `!important`, caricati dopo il base).
|
||||
4. Aggiungi `{ "id": "<id>", "name": "..." }` a `index.json`.
|
||||
5. Carica la cartella in `public/nitro/custom-themes/` sul server. **Nessun rebuild.**
|
||||
|
||||
## Default hotel-wide (admin)
|
||||
In `ui-config.json`:
|
||||
- `theme.base.url` → dove sono serviti i temi
|
||||
- `theme.default` → id del tema attivo di default (vuoto = nessuno)
|
||||
- `theme.default.pieces` → array di id pezzi attivi di default
|
||||
|
||||
Ogni utente può comunque sovrascrivere da Impostazioni → Temi (salvato in localStorage).
|
||||
|
||||
> Nota: i temi ri-skinnano solo la **grafica** (CSS). Non cambiano la struttura
|
||||
> dei componenti né il comportamento.
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"themes": [
|
||||
{ "id": "neon-viola", "name": "Neon Viola", "author": "infinityhotel" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/* Tema Neon Viola — pezzo "cards" (finestre / NitroCard).
|
||||
Ricolora header + cornice delle finestre. Caricato DOPO il CSS base, quindi
|
||||
usa !important per vincere. Tocca solo la cornice/header (non lo sfondo del
|
||||
contenuto) per non rovinare la leggibilita' del testo. */
|
||||
|
||||
.nitro-card-shell:not(.nitro-wired) {
|
||||
border-color: #7c3aed !important;
|
||||
box-shadow: 0 0 14px rgba(124, 58, 237, .55), 0 8px 22px rgba(0, 0, 0, .4) !important;
|
||||
}
|
||||
|
||||
.nitro-card-shell:not(.nitro-wired) .nitro-card-header-shell {
|
||||
background: linear-gradient(180deg, #9333ea 0%, #6d28d9 100%) !important;
|
||||
border-color: #a855f7 !important;
|
||||
border-bottom-color: #2a0a4a !important;
|
||||
}
|
||||
|
||||
.nitro-card-shell:not(.nitro-wired) .nitro-card-title {
|
||||
color: #fff !important;
|
||||
text-shadow: 0 0 6px #c084fc, 0 1px 0 #3b0764 !important;
|
||||
}
|
||||
|
||||
.nitro-card-shell:not(.nitro-wired) .nitro-card-tabs-shell .nitro-card-tab-item-active {
|
||||
box-shadow: inset 0 -2px 0 #a855f7 !important;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/* Tema Neon Viola — pezzo "catalog" (catalogo Hippiehotel, .nitro-catalog). */
|
||||
|
||||
.nitro-catalog .nitro-card-header-shell {
|
||||
background: linear-gradient(180deg, #9333ea 0%, #6d28d9 100%) !important;
|
||||
}
|
||||
|
||||
.nitro-catalog .group\/rail {
|
||||
background: #1a1030 !important;
|
||||
border-right-color: #7c3aed !important;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/* Tema Neon Viola — pezzo "chat".
|
||||
Accento viola sulla bubble di default (bubble-0) e sull'input chat.
|
||||
(Le bubble custom hanno la loro grafica; qui tocchiamo solo l'accento base.) */
|
||||
|
||||
.chat-bubble.bubble-0 {
|
||||
filter: drop-shadow(0 0 5px rgba(168, 85, 247, .8));
|
||||
}
|
||||
|
||||
.nitro-chat-input-container,
|
||||
.chat-input-container {
|
||||
box-shadow: inset 0 0 0 1px #7c3aed !important;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "Neon Viola",
|
||||
"author": "infinityhotel",
|
||||
"pieces": [
|
||||
{ "id": "cards", "name": "Finestre / Card", "file": "cards.css" },
|
||||
{ "id": "chat", "name": "Chat", "file": "chat.css" },
|
||||
{ "id": "toolbar", "name": "Toolbar", "file": "toolbar.css" },
|
||||
{ "id": "catalog", "name": "Catalogo", "file": "catalog.css" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/* Tema Neon Viola — pezzo "toolbar".
|
||||
Best-effort: ricolora la barra strumenti in basso. Se i selettori non
|
||||
matchano nella tua build, il pezzo non ha effetto (fallback sicuro). */
|
||||
|
||||
.nitro-toolbar,
|
||||
[class*="toolbar-container"] {
|
||||
background: linear-gradient(180deg, #2a0a4a 0%, #1a0730 100%) !important;
|
||||
box-shadow: 0 -2px 10px rgba(124, 58, 237, .4) !important;
|
||||
}
|
||||
Reference in New Issue
Block a user