Files
ladill-queue/resources/views/qms/display/public.blade.php
T
isaaccladandCursor 2243ccf95a
Deploy Ladill Queue / deploy (push) Successful in 33s
Redesign display admin show page and public waiting-area screen.
Add corporate layout, live preview, URL copy, queue details, and a polished TV display with clock, stats sidebar, and branded now-serving cards.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 22:42:02 +00:00

152 lines
9.2 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en" class="h-full">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ $screen->name }} · Queue Display</title>
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body
class="qms-display qms-display__grid-bg"
x-data="displayBoard({ dataUrl: '{{ $dataUrl }}', playedUrl: '{{ $playedUrl }}', pollMs: {{ $pollMs }}, csrf: '{{ csrf_token() }}' })"
x-init="init()"
>
{{-- Voice unlock required by browsers before TTS --}}
<div
x-cloak
x-show="!speechReady"
@click="unlockSpeech()"
@keydown.enter.prevent="unlockSpeech()"
tabindex="0"
class="qms-display__unlock fixed inset-0 z-50 flex cursor-pointer items-center justify-center p-8 text-center outline-none"
role="button"
aria-label="Enable voice announcements"
>
<div class="max-w-lg">
<div class="mx-auto flex h-16 w-16 items-center justify-center rounded-2xl bg-indigo-500/20 ring-1 ring-indigo-400/30">
<svg class="h-8 w-8 text-indigo-300" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.114 5.636a9 9 0 0 1 0 12.728M16.463 8.288a5.25 5.25 0 0 1 0 7.424M6.75 8.25l4.72-4.72a.75.75 0 0 1 1.28.53v15.88a.75.75 0 0 1-1.28.53l-4.72-4.72H4.51c-.88 0-1.704-.507-1.938-1.354A9.01 9.01 0 0 1 2.25 12c0-.83.112-1.633.322-2.396C2.806 8.756 3.63 8.25 4.51 8.25H6.75Z" />
</svg>
</div>
<p class="mt-6 text-3xl font-semibold tracking-tight text-white">Tap to enable announcements</p>
<p class="mt-3 text-base text-slate-400">Your browser needs one interaction before this screen can call tickets aloud.</p>
</div>
</div>
<div class="flex min-h-screen flex-col">
{{-- Header --}}
<header class="border-b border-white/10 bg-slate-950/60 backdrop-blur-md">
<div class="mx-auto flex max-w-7xl flex-wrap items-center justify-between gap-4 px-6 py-5 lg:px-10">
<div class="min-w-0">
<p
class="text-xs font-semibold uppercase tracking-[0.2em] text-indigo-300"
x-text="payload?.screen?.organization_name ?? '{{ $screen->organization?->name ?? 'Queue display' }}'"
></p>
<h1
class="mt-1 truncate text-2xl font-semibold tracking-tight text-white lg:text-3xl"
x-text="payload?.screen?.name ?? '{{ $screen->name }}'"
></h1>
<p
class="mt-1 text-sm text-slate-400"
x-show="payload?.screen?.branch_name"
x-text="payload?.screen?.branch_name"
></p>
</div>
<div class="text-right">
<div class="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-3 py-1.5 text-xs font-medium text-emerald-300">
<span class="qms-display__live-dot h-2 w-2 rounded-full bg-emerald-400"></span>
Live
</div>
<p class="mt-2 font-mono text-4xl font-semibold tabular-nums tracking-tight text-white" x-text="clock"></p>
<p class="text-sm text-slate-400" x-text="dateLabel"></p>
</div>
</div>
</header>
{{-- Main --}}
<main class="mx-auto flex w-full max-w-7xl flex-1 flex-col gap-6 px-6 py-8 lg:flex-row lg:gap-8 lg:px-10 lg:py-10">
{{-- Now serving --}}
<section class="flex flex-1 flex-col lg:min-h-[28rem]">
<div class="mb-4 flex items-end justify-between gap-4">
<div>
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-indigo-300">Now serving</p>
<p class="mt-1 text-sm text-slate-400">Please proceed to your counter when called</p>
</div>
</div>
<div class="flex flex-1 flex-col gap-4" x-show="(payload?.now_serving ?? []).length">
<template x-for="item in (payload?.now_serving ?? [])" :key="item.ticket_number + (item.counter ?? '')">
<article class="qms-display__ticket flex flex-1 flex-col items-center justify-center rounded-3xl px-8 py-10 text-center">
<p class="text-sm font-semibold uppercase tracking-[0.25em] text-indigo-200">Ticket number</p>
<p class="qms-display__ticket-number mt-3 text-6xl font-bold text-white sm:text-7xl lg:text-8xl" x-text="item.ticket_number"></p>
<p class="mt-4 text-xl text-indigo-100" x-text="item.queue_name"></p>
<div class="mt-8 inline-flex items-center gap-3 rounded-full bg-black/20 px-6 py-3 ring-1 ring-white/10">
<span class="text-sm font-medium uppercase tracking-widest text-indigo-200">Proceed to</span>
<span class="text-2xl font-semibold text-white" x-text="item.counter ?? '—'"></span>
</div>
</article>
</template>
</div>
<div
class="qms-display__stat flex flex-1 flex-col items-center justify-center rounded-3xl px-8 py-16 text-center"
x-show="!(payload?.now_serving ?? []).length"
>
<div class="flex h-14 w-14 items-center justify-center rounded-2xl bg-white/5 ring-1 ring-white/10">
<svg class="h-7 w-7 text-slate-400" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
</svg>
</div>
<p class="mt-5 text-2xl font-semibold text-white">Please wait</p>
<p class="mt-2 max-w-sm text-slate-400">Your ticket number will appear here when it is called.</p>
</div>
</section>
{{-- Stats sidebar --}}
<aside class="grid w-full gap-4 lg:w-80 lg:shrink-0">
<div class="qms-display__stat rounded-2xl p-6 text-center">
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-slate-400">Waiting</p>
<p class="mt-2 text-5xl font-bold tabular-nums text-white" x-text="payload?.waiting_count ?? '—'"></p>
<p class="mt-1 text-sm text-slate-500">customers in queue</p>
</div>
<div class="qms-display__stat rounded-2xl p-6 text-center">
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-slate-400">Estimated wait</p>
<p class="mt-2 text-5xl font-bold tabular-nums text-white">
<span x-text="payload?.estimated_wait_minutes ? payload.estimated_wait_minutes : '—'"></span>
<span class="text-2xl font-medium text-slate-400" x-show="payload?.estimated_wait_minutes">min</span>
</p>
<p class="mt-1 text-sm text-slate-500">based on todays average</p>
</div>
<div class="qms-display__stat rounded-2xl p-6">
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-slate-400">Service queues</p>
<ul class="mt-4 space-y-2">
<template x-for="q in (payload?.queues ?? [])" :key="q.name">
<li class="flex items-center justify-between gap-3 rounded-xl bg-white/5 px-3 py-2.5 ring-1 ring-white/5">
<span class="truncate font-medium text-white" x-text="q.name"></span>
<span
class="shrink-0 rounded-full px-2 py-0.5 text-xs font-semibold"
:class="q.is_paused ? 'bg-amber-500/15 text-amber-300' : 'bg-emerald-500/15 text-emerald-300'"
x-text="q.is_paused ? 'Paused' : 'Open'"
></span>
</li>
</template>
</ul>
<p class="mt-4 text-xs text-slate-500" x-show="!(payload?.queues ?? []).length">No queues configured for this display.</p>
</div>
</aside>
</main>
{{-- Footer --}}
<footer class="border-t border-white/10 bg-slate-950/60 px-6 py-4 lg:px-10">
<div class="mx-auto flex max-w-7xl flex-wrap items-center justify-between gap-3 text-xs text-slate-500">
<p>Powered by Ladill Queue</p>
<p x-show="payload?.updated_at" x-text="payload?.updated_at ? 'Updated ' + new Date(payload.updated_at).toLocaleTimeString() : ''"></p>
</div>
</footer>
</div>
</body>
</html>