restaurant/static/js/kds.js
Padreug 42746d7321 fix(cms): KDS card text legible on dark mode
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.
2026-05-11 19:18:33 +02:00

80 lines
2.6 KiB
JavaScript

window.app = Vue.createApp({
el: '#vue',
mixins: [windowMixin],
data() {
return {
restaurant: window.RESTAURANT_BOOTSTRAP || {},
active: [],
pollHandle: null,
activeStatuses: ['paid', 'accepted', 'ready']
}
},
computed: {
invoicekey() {
const w = this.g.user.wallets.find((w) => w.id === this.restaurant.wallet)
return (w && w.inkey) || (this.g.user.wallets[0] && this.g.user.wallets[0].inkey)
},
adminkey() {
const w = this.g.user.wallets.find((w) => w.id === this.restaurant.wallet)
return (w && w.adminkey) || (this.g.user.wallets[0] && this.g.user.wallets[0].adminkey)
}
},
methods: {
statusColor(status) {
return {paid: 'positive', accepted: 'blue', ready: 'amber'}[status] || 'grey'
},
cardClass(order) {
// Visually escalate as orders age. >5min = highlight; >15min = alarm.
//
// Pair every pale `bg-{color}-1` with an explicit dark text color
// — otherwise on LNbits dark mode the q-card inherits light text
// and renders white-on-cream, which is unreadable. The non-
// highlighted branch (default theme) returns '' so the q-card
// keeps its theme-aware defaults.
const ageSec = (Date.now() - new Date(order.time).getTime()) / 1000
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 ''
},
async fetchActive() {
try {
const {data: orders} = await RestaurantAPI.listOrders(
this.invoicekey,
this.restaurant.id,
this.activeStatuses
)
// Hydrate items per card.
for (const o of orders) {
try {
const {data} = await RestaurantAPI.getOrder(o.id)
o._items = data.items
} catch (e) {
o._items = []
}
}
// Newest at the bottom-right (left-to-right reading order in kitchen).
this.active = orders.sort(
(a, b) => new Date(a.time).getTime() - new Date(b.time).getTime()
)
} catch (err) {
LNbits.utils.notifyApiError(err)
}
},
async transition(order, newStatus) {
try {
await RestaurantAPI.transitionOrder(this.adminkey, order.id, newStatus)
await this.fetchActive()
} catch (err) {
LNbits.utils.notifyApiError(err)
}
}
},
async created() {
await this.fetchActive()
this.pollHandle = setInterval(() => this.fetchActive(), 5000)
},
beforeUnmount() {
if (this.pollHandle) clearInterval(this.pollHandle)
}
})