When a card hits `accepted` the items section bumps base font to 1.25rem and modifier/note lines to 1.15rem + medium weight; the muted grey on modifiers drops to inherited color. All via Vue `:style` bindings — class-based CSS rules lose to lnbits' upstream `!important` on Quasar typography utilities (even with our own `!important`), so inline wins without an arms race. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
128 lines
5.4 KiB
Markdown
128 lines
5.4 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.
|
||
|
||
When a card transitions to `accepted` (driven by `cookingMode(order)`
|
||
in `kds.js`), three inline `:style` bindings kick in:
|
||
|
||
- the items `q-card-section` switches base font between `1rem` and
|
||
`1.25rem`,
|
||
- the modifier list (`.text-caption.text-grey-7`) bumps to `1.15rem`
|
||
+ medium weight + `color: inherit` (drops the muted grey),
|
||
- the per-line note (`.text-caption.text-amber-9`) bumps to `1.15rem`
|
||
+ medium weight; color is left alone so it stays amber.
|
||
|
||
All cooking-mode styling is inline because an upstream `!important`
|
||
rule (likely an lnbits theme override on Quasar's typography
|
||
utilities) defeats class-based CSS rules — even with `!important`
|
||
on our side. Inline `:style` wins without needing the arms race.
|
||
Card chrome and the age-based `bg-{color}-1` from `cardClass()`
|
||
are untouched. The amber
|
||
per-line note keeps its color because only `.text-grey-7` is
|
||
overridden. No background rules; card chrome and the age-based
|
||
`bg-{color}-1` from `cardClass()` are untouched.
|
||
|
||
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]]
|