3d958d0411
- Home Assistant administrators are admins: Dashboard, Builder and Admin screens - Everyone else only sees the dashboards an admin chose, always in kiosk mode; the server enforces it (saving, people, devices, history are admin-only, and the websocket only allows reading states and controlling devices) - Admin screen: dashboards, people and what each sees (with preview), devices, messages to the screens, the Haven app, activity, about - Haven: new Android app (haven/) that only shows dashboards; replaces the Dashboard Studio Android app and signs in through Home Assistant's page - Screens pick up dashboard and access changes within a minute - Version history records who made each change; panel visible to all users Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
106 lines
6.7 KiB
HTML
106 lines
6.7 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||
<meta name="theme-color" content="#f2f2f7" media="(prefers-color-scheme: light)">
|
||
<meta name="theme-color" content="#0f0f11" media="(prefers-color-scheme: dark)">
|
||
<meta name="ds-version" content="__VERSION__">
|
||
<title>Dashboard Studio</title>
|
||
<link rel="icon" type="image/png" href="static/favicon.png">
|
||
<link rel="stylesheet" href="static/style.css">
|
||
<!-- Home Assistant only serves this app to a signed-in browser: the manifest has to be fetched with the cookie -->
|
||
<link rel="manifest" href="manifest.webmanifest" crossorigin="use-credentials">
|
||
<link rel="apple-touch-icon" href="static/apple-touch-icon.png">
|
||
<meta name="theme-color" content="#0f1526">
|
||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||
<meta name="mobile-web-app-capable" content="yes">
|
||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||
<meta name="apple-mobile-web-app-title" content="Dashboards">
|
||
</head>
|
||
<body>
|
||
<div id="app">
|
||
<header id="topbar" role="toolbar" aria-label="Dashboard">
|
||
<div class="tb-group">
|
||
<label class="picker">
|
||
<span class="sr-only" data-i18n>Dashboard</span>
|
||
<select id="dash-select"></select>
|
||
<svg class="i" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
|
||
</label>
|
||
<button id="btn-new" class="btn icon" aria-label="New dashboard" title="New dashboard"></button>
|
||
</div>
|
||
<div class="tb-group">
|
||
<span id="conn" class="conn" role="status" data-i18n>Offline</span>
|
||
<span id="save-status" class="save-status edit-only" role="status"></span>
|
||
<span class="edit-only tb-group">
|
||
<button id="btn-undo" class="btn icon" aria-label="Undo" title="Undo (⌘Z)"></button>
|
||
<button id="btn-redo" class="btn icon" aria-label="Redo" title="Redo (⇧⌘Z)"></button>
|
||
<button id="btn-menu" class="btn icon" aria-label="More actions" aria-haspopup="menu" aria-expanded="false" title="More actions"></button>
|
||
</span>
|
||
<button id="btn-guest" class="btn view-only" hidden><span data-i18n>Guest mode</span></button>
|
||
<button id="btn-app" class="btn icon view-only" aria-label="Install as an app" title="Install as an app"></button>
|
||
<button id="btn-kiosk" class="btn view-only label-wide" aria-label="Kiosk" title="Kiosk mode"><span data-i18n>Kiosk</span></button>
|
||
<div id="mode-seg" class="mode-seg" role="tablist" aria-label="Screen" hidden>
|
||
<button role="tab" data-mode="dashboard" data-icon="layout"><span data-i18n>Dashboard</span></button>
|
||
<button role="tab" data-mode="builder" data-icon="edit"><span data-i18n>Builder</span></button>
|
||
<button role="tab" data-mode="admin" data-icon="shield"><span data-i18n>Admin</span></button>
|
||
</div>
|
||
</div>
|
||
<div id="menu" class="menu" role="menu" hidden>
|
||
<button role="menuitem" data-menu="rename" data-icon="edit" data-i18n>Rename…</button>
|
||
<button role="menuitem" data-menu="suggest" data-icon="search" data-i18n>Devices not on a dashboard…</button>
|
||
<button role="menuitem" data-menu="history" data-icon="history" data-i18n>Version history…</button>
|
||
<button role="menuitem" data-menu="undo-history" data-icon="undo" data-i18n>Undo history…</button>
|
||
<button role="menuitem" data-menu="share" data-icon="share" data-i18n>Share…</button>
|
||
<button role="menuitem" data-menu="export" data-icon="exit" data-i18n>Export as JSON</button>
|
||
</div>
|
||
</header>
|
||
|
||
<div id="workspace">
|
||
<aside id="palette" class="edit-only" aria-label="Widgets">
|
||
<button class="sheet-close btn icon" aria-label="Close" title="Close">×</button>
|
||
<div class="panel-title" data-i18n>Add widget</div>
|
||
<input id="palette-search" class="input" type="search" aria-label="Search widgets" autocomplete="off" spellcheck="false">
|
||
<div id="palette-list"></div>
|
||
<p class="hint" data-i18n>Click to add. Drag to move, drag the corner to resize. Shift-click to select several. Arrow keys move the selected widget, Shift+arrows resize, ⌘D duplicates, Delete removes.</p>
|
||
</aside>
|
||
|
||
<main id="stage">
|
||
<nav id="tabnav" aria-label="Tabs" hidden></nav>
|
||
<div id="canvas"><div id="grid"></div></div>
|
||
</main>
|
||
|
||
<aside id="inspector" class="edit-only" aria-label="Inspector"></aside>
|
||
</div>
|
||
|
||
<!-- Admin: dashboards, people, devices, the Haven app, activity -->
|
||
<section id="admin" hidden aria-label="Admin">
|
||
<nav class="adm-nav" role="tablist" aria-label="Admin"></nav>
|
||
<div class="adm-body"></div>
|
||
</section>
|
||
</div>
|
||
|
||
<div id="edit-bar" class="edit-only"><button class="btn" id="eb-add"><span data-i18n>Add</span></button><button class="btn primary" id="eb-insp"></button></div>
|
||
<div id="sheet-backdrop" hidden></div>
|
||
<div id="saver" hidden aria-hidden="true"><div class="photos"><img class="ph-layer" alt=""><img class="ph-layer" alt=""><div class="ph-msg"></div></div><div class="saver-clock"><div class="time num"></div><div class="date"></div></div></div>
|
||
<div id="doorbell" hidden role="alertdialog" aria-modal="true" aria-labelledby="db-title"><div class="db-cam"></div><div class="db-bar"><div class="db-title" id="db-title"></div><button class="btn db-close">Close</button></div></div>
|
||
<div id="night-dim" aria-hidden="true"></div>
|
||
<div id="preview-bar" hidden role="status"><span class="pv-text"></span><button class="btn" id="pv-stop"><span data-i18n>Stop preview</span></button></div>
|
||
<div id="empty-note" hidden role="status"><div class="en-card"><div class="en-ico"></div><h2 data-i18n>Nothing to show yet</h2><p class="en-text"></p></div></div>
|
||
<button id="phone-menu" class="btn icon" aria-label="Menu" title="Menu"></button>
|
||
<div id="offline-note" hidden role="status"></div>
|
||
<div id="ptr" hidden aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M20 11a8 8 0 1 0-2.3 5.7M20 4v7h-7"/></svg></div>
|
||
<div id="announce" hidden role="alertdialog" aria-modal="true" aria-labelledby="an-title"><div class="an-card"><div class="an-ico"></div><div class="an-title" id="an-title"></div><div class="an-msg"></div><button class="btn primary an-ok">OK</button></div></div>
|
||
|
||
<div id="modal" class="modal" hidden><div class="modal-card" role="dialog" aria-modal="true"></div></div>
|
||
<div id="toasts" aria-live="polite"></div>
|
||
<input type="file" id="import-file" accept="application/json,.json" hidden>
|
||
|
||
<script src="static/i18n.js"></script>
|
||
<script src="static/icons.js"></script>
|
||
<script src="static/qr.js"></script>
|
||
<script src="static/widgets.js"></script>
|
||
<script src="static/app.js"></script>
|
||
</body>
|
||
</html>
|