feat(ui): light-mode sky palette for Caddy card, favicon, doc sync
- index.css: add :root.light overrides for the sky-* accent used only by the Caddy settings card (buttons, badges, hovers) + the missing red-950/30 hover - favicon: add public/favicon.svg (GhostGrid logo) and link it in index.html - ARCHITECTURE.md: GET /caddy/routes returns a plain array, document the Caddy startup import, https:// upstream, favicon/public dir, and the SPA-catch-all-last + Cache-Control: no-store invariant
This commit is contained in:
@ -374,7 +374,7 @@ All `/api/*` routes return JSON. Every route except the public auth/config endpo
|
||||
|
|
||||
+-- /caddy
|
||||
+-- GET /status # Caddy admin API reachable? [auth]
|
||||
+-- GET /routes # { system, custom } routes [auth]
|
||||
+-- GET /routes # Custom routes (plain array) [auth]
|
||||
+-- POST /routes # Add custom route + push config [auth]
|
||||
+-- PUT /routes/{id} # Update custom route + push config [auth]
|
||||
+-- DELETE /routes/{id} # Remove custom route + push config [auth]
|
||||
@ -481,15 +481,19 @@ pushCaddyConfig(): POST <caddy_admin_url>/load (Content-Type: text/caddyfile)
|
||||
|
||||
### 6.4 First-start Initialization
|
||||
|
||||
Runs in `startServer()` before any routes are registered, every startup — both operations
|
||||
are idempotent and only fire once on a blank database.
|
||||
Runs in `startServer()` on every startup — each step is idempotent.
|
||||
|
||||
```
|
||||
Default admin user:
|
||||
Default admin user (only on a blank database):
|
||||
if users table is empty:
|
||||
INSERT user (name='Admin', role='Admin', email='admin@ghostgrid.local', password=bcrypt('admin'))
|
||||
INSERT user (name='admin', role='admin', email='admin@ghostgrid.local', password=bcrypt('admin'))
|
||||
→ log "[Init] Default admin user created"
|
||||
|
||||
Caddy route import (re-deploy safety net):
|
||||
if caddy_enabled === 'true' AND caddy table is empty:
|
||||
importCaddyfileRoutes() → seed routes from /etc/caddy/Caddyfile
|
||||
(also runs in PUT /api/settings on the disabled → enabled transition)
|
||||
|
||||
Default settings:
|
||||
INSERT OR IGNORE all DEFAULT_SETTINGS keys from server-db.ts
|
||||
→ existing values in the settings table are never overwritten
|
||||
@ -577,7 +581,8 @@ Settings
|
||||
+-- CheckMK (API URL/user/secret, sync interval, "Run sync now")
|
||||
+-- Ansible Semaphore (API URL/token/project, "Test connection")
|
||||
+-- Caddy (admin URL, custom route management;
|
||||
auto-seeded from /etc/caddy/Caddyfile on first enable)
|
||||
auto-seeded from /etc/caddy/Caddyfile on first enable;
|
||||
https:// upstream → TLS proxy, certificate not verified)
|
||||
+-- Secret inputs use the __SET__ sentinel (blank = keep existing)
|
||||
```
|
||||
|
||||
@ -696,7 +701,9 @@ Backup : ghostgrid.db + ghostgrid.db-wal + ghostgrid.db-shm
|
||||
GhostGrid/
|
||||
+-- server.ts # Express app: all routes, auth, integrations, background jobs
|
||||
+-- server-db.ts # SQLite connection, full schema, settings/Caddy helpers
|
||||
+-- index.html # Vite HTML entry (#root > src/main.tsx)
|
||||
+-- index.html # Vite HTML entry (#root > src/main.tsx); links /favicon.svg
|
||||
+-- public/
|
||||
| +-- favicon.svg # app favicon (GhostGrid logo; served at site root by Vite)
|
||||
+-- vite.config.ts # Vite + React + Tailwind; '@' alias > repo root
|
||||
+-- tsconfig.json # noEmit, react-jsx, bundler resolution
|
||||
+-- package.json # scripts + deps (package name "react-example" is vestigial)
|
||||
@ -820,6 +827,7 @@ Express (server.ts) ──► better-sqlite3 (ghostgrid.db, WAL)
|
||||
- Booking boolean flags are 0/1 integers in SQLite, mapped on read.
|
||||
- A new settings key must be: **seeded** in `server-db.ts`, **allow-listed** in `PUT /api/settings`, and (if secret) added to `SECRET_KEYS`.
|
||||
- Schema changes go straight into the `CREATE TABLE` block in `server-db.ts` — fresh-install model, no migration helper.
|
||||
- The SPA catch-all (`app.get('*')`) + static serving are registered **last** in `startServer()`, after every `/api` route — otherwise GET `/api/*` falls through to `index.html`. All `/api` responses carry `Cache-Control: no-store`.
|
||||
- All user-facing strings are in **English**.
|
||||
|
||||
---
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="theme-color" content="#0b0f19" />
|
||||
<title>GhostGrid</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
24
public/favicon.svg
Normal file
24
public/favicon.svg
Normal file
@ -0,0 +1,24 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||
<rect width="100" height="100" rx="22" fill="#0b0f19"/>
|
||||
<!-- ghost body -->
|
||||
<path d="M 24,78 C 18,65 14,35 34,22 C 48,12 62,15 68,26" stroke="#06b6d4" stroke-width="4" stroke-linecap="round" fill="none"/>
|
||||
<path d="M 24,78 C 26,83 31,81 35,74 C 38,68 41,74 45,77 C 48,79 50,70 52,65" stroke="#06b6d4" stroke-width="4" stroke-linecap="round" fill="none"/>
|
||||
<!-- eyes -->
|
||||
<rect x="38" y="32" width="6" height="13" rx="3" fill="#00f0ff"/>
|
||||
<rect x="52" y="32" width="6" height="13" rx="3" fill="#00f0ff"/>
|
||||
<!-- network grid -->
|
||||
<line x1="56" y1="38" x2="88" y2="38" stroke="#06b6d4" stroke-width="2.5"/>
|
||||
<line x1="46" y1="62" x2="84" y2="62" stroke="#06b6d4" stroke-width="2.5"/>
|
||||
<line x1="56" y1="20" x2="56" y2="80" stroke="#06b6d4" stroke-width="2.5"/>
|
||||
<line x1="68" y1="15" x2="68" y2="76" stroke="#0891b2" stroke-width="2"/>
|
||||
<line x1="80" y1="26" x2="80" y2="62" stroke="#06b6d4" stroke-width="2"/>
|
||||
<!-- nodes -->
|
||||
<circle cx="56" cy="26" r="4" fill="#00f0ff"/>
|
||||
<circle cx="68" cy="26" r="4" fill="#00f0ff"/>
|
||||
<circle cx="80" cy="26" r="4" fill="#00f0ff"/>
|
||||
<circle cx="56" cy="38" r="4" fill="#00f0ff"/>
|
||||
<circle cx="80" cy="38" r="5" fill="#38bdf8"/>
|
||||
<circle cx="88" cy="38" r="4" fill="#00f0ff"/>
|
||||
<circle cx="68" cy="62" r="5" fill="#38bdf8"/>
|
||||
<circle cx="80" cy="62" r="4" fill="#00f0ff"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@ -872,3 +872,42 @@
|
||||
:root.light .group:hover .group-hover\:text-slate-300 {
|
||||
color: var(--text-muted) !important;
|
||||
}
|
||||
|
||||
/* ── Settings → Caddy section: sky accent ─────────────────────────── */
|
||||
/* sky-* is used only by the Caddy card; map its dark tokens to light. */
|
||||
:root.light .bg-sky-950\/60,
|
||||
:root.light .bg-sky-950\/40,
|
||||
:root.light .bg-sky-900\/40 {
|
||||
background-color: #e0f2fe !important;
|
||||
border-color: #7dd3fc !important;
|
||||
color: #0369a1 !important;
|
||||
}
|
||||
|
||||
:root.light .border-sky-900\/50,
|
||||
:root.light .border-sky-900\/40 {
|
||||
border-color: #7dd3fc !important;
|
||||
}
|
||||
|
||||
:root.light .text-sky-400,
|
||||
:root.light .text-sky-500 {
|
||||
color: #0284c7 !important;
|
||||
}
|
||||
|
||||
:root.light .bg-sky-950\/30,
|
||||
:root.light .hover\:bg-sky-950\/30:hover {
|
||||
background-color: #e0f2fe !important;
|
||||
}
|
||||
|
||||
:root.light .hover\:bg-sky-900\/40:hover {
|
||||
background-color: #bae6fd !important;
|
||||
}
|
||||
|
||||
:root.light .hover\:text-sky-400:hover {
|
||||
color: #0284c7 !important;
|
||||
}
|
||||
|
||||
/* Delete-icon hover (red-950/30 is the only red opacity not yet mapped) */
|
||||
:root.light .bg-red-950\/30,
|
||||
:root.light .hover\:bg-red-950\/30:hover {
|
||||
background-color: #fee2e2 !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user