The age-escalation highlights (bg-amber-1 / bg-orange-1 / bg-red-1) are very pale Quasar shades. On LNbits dark mode the q-card inherits a near-white text color from the theme — paired with the pale background that's white-on-cream, which is what the user reported: the '1x Coffee' on a ready-card was barely visible. Pin an explicit text-grey-9 alongside each pale bg so dark text on light background renders in both themes. The 'no highlight' branch returns '' unchanged, so non-aged orders still use the q-card's theme-aware default text color.
108 lines
4.5 KiB
Markdown
108 lines
4.5 KiB
Markdown
# CMS
|
||
|
||
The operator-facing console — what the restaurant owner sees when
|
||
they enable the extension. Lives under `/restaurant/...` and uses
|
||
LNbits' built-in **Vue 3.5 + Quasar 2.18 UMD** runtime: no build
|
||
step, no bundler, just Jinja templates including a per-page JS file.
|
||
|
||
## Pages
|
||
|
||
All pages extend `base.html` (provided by LNbits core) and require a
|
||
logged-in user (`check_user_exists`).
|
||
|
||
| Path | Template | Script | Purpose |
|
||
|---|---|---|---|
|
||
| `/restaurant/` | `restaurant/index.html` | `static/js/index.js` | Restaurant list / dashboard |
|
||
| `/restaurant/{slug}` | `restaurant/menu.html` | `static/js/menu.js` | [[menu-tree\|menu]] builder (q-tree) |
|
||
| `/restaurant/{slug}/orders` | `restaurant/orders.html` | `static/js/orders.js` | Order monitor |
|
||
| `/restaurant/{slug}/kds` | `restaurant/kds.html` | `static/js/kds.js` | Kitchen Display |
|
||
| `/restaurant/{slug}/settings` | `restaurant/settings.html` | `static/js/settings.js` | Restaurant + extension settings |
|
||
|
||
## Conventions
|
||
|
||
- `{% extends "base.html" %}` and `{% from "macros.jinja" import window_vars with context %}`.
|
||
- Page content goes in `{% block page %}`. Scripts in `{% block scripts %}`, after `{{ window_vars(user) }}`.
|
||
- The page JS sets `window.app = Vue.createApp({mixins: [windowMixin], data, methods, created})`. LNbits' `init-app.js` runs after the extension scripts and finishes the mount with `app.use(Quasar)` + `app.mount('#vue')` — **don't call `.mount()` yourself**.
|
||
- Bootstrap data is injected via `<script>window.X = {{ thing | tojson | safe }}</script>` between the macro and the per-page script.
|
||
- The shared REST client is `static/js/api.js`, exposing `window.RestaurantAPI` (one method per resource).
|
||
|
||
## Menu builder (q-tree)
|
||
|
||
The menu page uses Quasar's `q-tree` directly off the hydrated tree
|
||
returned by `GET /api/v1/restaurants/{id}/menu`. Three-pane layout:
|
||
|
||
```
|
||
+--------------------+----------------+----------------------------+
|
||
| sidebar nav | q-tree | Items panel |
|
||
| (orders / KDS / | with inline | (filtered by selected |
|
||
| settings links) | edit buttons | tree node) |
|
||
+--------------------+----------------+----------------------------+
|
||
```
|
||
|
||
Custom `default-header` slot renders:
|
||
|
||
- node name + item-count badge + child-count hint
|
||
- inline buttons: `add` (disabled at depth 3), `edit`,
|
||
`drive_file_move`, `delete` (with cascade prompt)
|
||
|
||
Add-root button sits above the tree (`+ New top-level`).
|
||
|
||
The Move dialog uses a flat-indented `q-select` of all nodes,
|
||
filtered to exclude the moved node + its descendants and any
|
||
depth-3 candidate. (The server enforces both checks too — see
|
||
[[menu-tree]].)
|
||
|
||
Drag-drop reorder is **v2**; v1 uses the explicit Move dialog.
|
||
|
||
## Item dialog
|
||
|
||
The item dialog includes a flat-indented `q-select` for `node_id`,
|
||
populated by walking the tree with em-space indentation per depth
|
||
level. An item can land on any node, not just leaves.
|
||
|
||
Modifier groups + modifiers live in a separate dialog (a child of
|
||
the item dialog) with the `chooseOne / chooseMany / required /
|
||
optional` semantics from [[data-model|the data model]].
|
||
|
||
## Order monitor + KDS
|
||
|
||
Both use the same data source (`GET /restaurants/{id}/orders`)
|
||
filtered by status. The KDS view escalates color by age (`>5min`
|
||
orange, `>15min` red) and offers one-tap state transitions.
|
||
|
||
Today the monitor + KDS poll every 5–8 s. SSE / Nostr push is on
|
||
the roadmap.
|
||
|
||
### Dark-mode color discipline
|
||
|
||
Quasar's pale `bg-{color}-1` utility classes (e.g. `bg-orange-1`,
|
||
`bg-red-1`, `bg-amber-1`) pair fine with the default light theme
|
||
but render **white-on-cream** under LNbits' dark theme — the
|
||
q-card otherwise inherits the body's light text color. The KDS
|
||
cards pin a dark text class alongside every pale background so
|
||
the card stays legible regardless of theme:
|
||
|
||
```js
|
||
if (order.status === 'ready') return 'bg-amber-1 text-grey-9'
|
||
if (ageSec > 900) return 'bg-red-1 text-grey-9'
|
||
if (ageSec > 300) return 'bg-orange-1 text-grey-9'
|
||
return '' // theme-default branch keeps q-card's own text color
|
||
```
|
||
|
||
Any future surface that ages / escalates with `bg-{color}-1` must
|
||
do the same. Never assume a pale background "just works" on dark
|
||
theme.
|
||
|
||
## Settings
|
||
|
||
`settings.html` saves restaurant fields via
|
||
`PUT /restaurants/{id}` and (for LNbits admins) extension-wide
|
||
toggles via `PUT /settings`. NIP-17 orders toggle is currently
|
||
disabled because the unwrap step is stubbed — see [[nostr-layer]].
|
||
|
||
## See also
|
||
|
||
- [[architecture]]
|
||
- [[menu-tree]]
|
||
- [[order-flow]]
|
||
- [[api-reference]]
|