| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8" /> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
| <title>DISPATCH // Admin</title> |
| <link rel="stylesheet" href="/admin/style.css" /> |
| </head> |
| <body> |
| <div id="root"> |
|
|
| |
| <div id="login-screen"> |
| <div id="login-box"> |
| <div id="login-logo">DISPATCH</div> |
| <div id="login-subtitle">ADMIN ACCESS</div> |
| <div id="login-form"> |
| <div class="form-group"> |
| <label for="login-password">ACCESS KEY</label> |
| <input id="login-password" type="password" placeholder="Enter key..." autocomplete="current-password" /> |
| </div> |
| <div id="login-error"></div> |
| <button id="login-btn" class="btn-create">AUTHENTICATE</button> |
| </div> |
| <div id="login-connecting" style="display:none"> |
| <div class="spinner"></div> |
| <span>Connecting...</span> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="app" style="display:none"> |
|
|
| |
| <header id="topbar"> |
| <div id="topbar-logo">DISPATCH</div> |
| <div id="topbar-status"> |
| <span id="ws-indicator" class="indicator offline"></span> |
| <span id="ws-label">OFFLINE</span> |
| <button id="logout-btn" class="btn-logout">LOGOUT</button> |
| </div> |
| </header> |
|
|
| |
| <nav id="tabs"> |
| <button class="tab-btn active" data-tab="notifications">NOTIFICATIONS</button> |
| <button class="tab-btn" data-tab="devices">DEVICES</button> |
| </nav> |
|
|
| |
| <div id="tab-notifications" class="tab-panel active"> |
| <div id="notif-layout"> |
|
|
| |
| <aside id="create-panel"> |
| <h2 class="panel-title">NEW NOTIFICATION</h2> |
| <div class="form-group"> |
| <label for="f-name">Internal Name</label> |
| <input id="f-name" type="text" placeholder="e.g. promo-sept-24" /> |
| </div> |
| <div class="form-group"> |
| <label for="f-heading">Heading</label> |
| <input id="f-heading" type="text" placeholder="Notification heading" /> |
| </div> |
| <div class="form-group"> |
| <label for="f-body">Body</label> |
| <textarea id="f-body" rows="4" placeholder="Notification body text..."></textarea> |
| </div> |
| <div class="form-group"> |
| <label for="f-hyperlink">Hyperlink</label> |
| <input id="f-hyperlink" type="url" placeholder="https://..." /> |
| </div> |
| <div class="form-group"> |
| <label for="f-sound">Sound</label> |
| <select id="f-sound"> |
| <option value="">β No Sound β</option> |
| </select> |
| </div> |
| <div class="form-group"> |
| <label>Upload Sound File</label> |
| <div id="sound-upload-area"> |
| <input id="f-sound-file" type="file" accept="audio/*" hidden /> |
| <button id="sound-upload-btn" class="btn-outline" type="button">β² UPLOAD AUDIO</button> |
| <span id="sound-file-name">No file chosen</span> |
| </div> |
| <input id="f-sound-name" type="text" placeholder="Sound name (required for upload)" style="margin-top:8px" /> |
| </div> |
| <button id="create-notif-btn" class="btn-create">CREATE NOTIFICATION</button> |
| </aside> |
|
|
| |
| <main id="notif-list-panel"> |
| <h2 class="panel-title">ALL NOTIFICATIONS <span id="notif-count" class="badge">0</span></h2> |
| <div id="notif-list"> |
| <div class="empty-state">No notifications yet.</div> |
| </div> |
| </main> |
|
|
| |
| <section id="schedule-panel"> |
| <div id="schedule-empty-state"> |
| <div class="select-hint"> |
| <div class="select-hint-icon">β</div> |
| <p>Select a notification<br>to schedule or play it</p> |
| </div> |
| </div> |
| <div id="schedule-active" style="display:none"> |
| <div id="selected-notif-info"> |
| <div id="selected-notif-name"></div> |
| </div> |
| <button id="play-now-btn" title="Play Now"><span>βΆ PLAY NOW</span></button> |
| <div id="schedule-controls"> |
| <div class="toggle-row"> |
| <label class="toggle-label" for="now-toggle">NOW</label> |
| <label class="toggle-switch"> |
| <input type="checkbox" id="now-toggle" /> |
| <span class="toggle-track"><span class="toggle-thumb"></span></span> |
| </label> |
| </div> |
| <div id="datetime-pickers"> |
| <div class="picker-group"> |
| <label>DATE</label> |
| <input type="date" id="sched-date" /> |
| </div> |
| <div class="picker-group"> |
| <label>TIME</label> |
| <input type="time" id="sched-time" /> |
| </div> |
| </div> |
| <button id="schedule-btn" class="btn-schedule">SCHEDULE</button> |
| </div> |
| </div> |
| </section> |
|
|
| </div> |
| </div> |
|
|
| |
| <div id="tab-devices" class="tab-panel"> |
| <div id="devices-layout"> |
| <aside id="device-list-panel"> |
| <h2 class="panel-title">DEVICES <span id="device-count" class="badge">0</span></h2> |
| <div id="device-list"> |
| <div class="empty-state">No devices connected yet.</div> |
| </div> |
| </aside> |
| <main id="device-detail-panel"> |
| <div id="device-empty-state" class="select-hint"> |
| <div class="select-hint-icon">β</div> |
| <p>Select a device<br>to manage it</p> |
| </div> |
| <div id="device-detail" style="display:none"> |
| <div id="device-header"> |
| <div id="device-status-indicator" class="indicator"></div> |
| <div> |
| <div id="detail-device-name-display" class="device-detail-name"></div> |
| <div id="detail-device-uuid" class="device-detail-uuid"></div> |
| </div> |
| <div id="device-name-edit-area"> |
| <input id="device-name-input" type="text" placeholder="Device name..." /> |
| <button id="device-name-save" class="btn-sm">SAVE NAME</button> |
| </div> |
| </div> |
| <div id="device-sections"> |
| <div class="device-section"> |
| <h3>CACHED SOUNDS</h3> |
| <div id="detail-sounds" class="tag-list"></div> |
| </div> |
| <div class="device-section"> |
| <h3>NOTIFICATIONS</h3> |
| <div id="detail-notifications" class="notif-table-wrap"></div> |
| </div> |
| <div class="device-section"> |
| <h3>SCHEDULE</h3> |
| <div id="detail-schedule" class="schedule-table-wrap"></div> |
| </div> |
| </div> |
| </div> |
| </main> |
| </div> |
| </div> |
|
|
| </div> |
|
|
| </div> |
|
|
| <script src="/admin/script.js"></script> |
| </body> |
| </html> |