bowler-chart/public/admin.html

149 lines
6.3 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Admin · Bowler Chart</title>
<link rel="stylesheet" href="/vendor/beer.min.css" />
<link rel="stylesheet" href="/css/app.css" />
<script src="/vendor/material-dynamic-colors.min.js"></script>
<!-- Beer CSS is an ES module that only exports `ui`; expose it as the global our code calls. -->
<script type="module">
import { ui } from '/vendor/beer.min.js';
window.ui = ui;
</script>
<script src="/js/api.js"></script>
<script src="/js/theme.js"></script>
<script src="/js/admin.js" defer></script>
<script src="/vendor/alpine.min.js" defer></script>
</head>
<body class="light" x-data="adminApp()" x-init="init()" x-cloak>
<nav class="top fill">
<button class="circle transparent" @click="location.href='/'" title="Back to chart"><i>arrow_back</i></button>
<h6 class="app-bar-title max">Administration</h6>
<span class="chip"><i>shield_person</i><span x-text="me?.username"></span></span>
</nav>
<main class="responsive">
<div class="tabs">
<a :class="tab === 'users' ? 'active' : ''" @click="tab='users'"><i>group</i><span>Users</span></a>
<a :class="tab === 'schemes' ? 'active' : ''" @click="tab='schemes'"><i>palette</i><span>Color schemes</span></a>
</div>
<!-- USERS -->
<div x-show="tab === 'users'" class="page active">
<div class="row middle-align" style="margin: 1rem 0;">
<h6 class="max">Users</h6>
<button @click="openNewUser()"><i>person_add</i><span>New user</span></button>
</div>
<table class="border stripes">
<thead><tr><th>Username</th><th>Email</th><th>Role</th><th>Status</th><th></th></tr></thead>
<tbody>
<template x-for="u in users" :key="u.id">
<tr>
<td x-text="u.username"></td>
<td class="muted" x-text="u.email || '—'"></td>
<td><span class="chip small" x-text="u.role"></span></td>
<td><span :class="u.active ? 'green-text' : 'red-text'" x-text="u.active ? 'Active' : 'Disabled'"></span></td>
<td class="right-align nowrap">
<button class="circle small transparent" @click="openEditUser(u)"><i>edit</i></button>
<button class="circle small transparent" @click="deleteUser(u)"><i>delete</i></button>
</td>
</tr>
</template>
</tbody>
</table>
</div>
<!-- SCHEMES -->
<div x-show="tab === 'schemes'" class="page active">
<div class="row middle-align" style="margin: 1rem 0;">
<h6 class="max">Color schemes</h6>
<button @click="openNewScheme()"><i>add</i><span>New scheme</span></button>
</div>
<div class="grid">
<template x-for="s in schemes" :key="s.id">
<article class="s12 m6 l4 border round">
<div class="row middle-align">
<div class="square round" :style="`background:${s.seed_color}`"></div>
<div class="max">
<h6 class="small" x-text="s.name"></h6>
<span class="muted small-text" x-text="`${s.seed_color} · ${s.mode}`"></span>
</div>
<template x-if="s.is_default"><span class="chip small primary">Default</span></template>
</div>
<nav class="right-align">
<button class="circle small transparent" @click="openEditScheme(s)"><i>edit</i></button>
<button class="circle small transparent" @click="deleteScheme(s)" :disabled="s.is_default"><i>delete</i></button>
</nav>
</article>
</template>
</div>
</div>
</main>
<!-- User dialog -->
<dialog class="modal" x-ref="userDialog">
<h6 x-text="user.id ? 'Edit user' : 'New user'"></h6>
<div class="field label border round" x-show="!user.id">
<input type="text" x-model="user.username" autocomplete="off" />
<label>Username</label>
</div>
<div class="field label border round">
<input type="email" x-model="user.email" autocomplete="off" />
<label>Email</label>
</div>
<div class="field label border round">
<input type="password" x-model="user.password" autocomplete="new-password" />
<label x-text="user.id ? 'New password (leave blank to keep)' : 'Password'"></label>
</div>
<div class="grid">
<div class="field label border round s6">
<select x-model="user.role"><option value="user">User</option><option value="admin">Admin</option></select>
<label>Role</label>
</div>
<label class="checkbox s6" style="align-self:center;">
<input type="checkbox" x-model="user.active" /><span>Active</span>
</label>
</div>
<nav class="right-align">
<button class="border" @click="$refs.userDialog.close()">Cancel</button>
<button @click="saveUser()"><i>save</i><span>Save</span></button>
</nav>
</dialog>
<!-- Scheme dialog -->
<dialog class="modal" x-ref="schemeDialog">
<h6 x-text="scheme.id ? 'Edit scheme' : 'New scheme'"></h6>
<div class="field label border round">
<input type="text" x-model="scheme.name" />
<label>Name</label>
</div>
<div class="grid">
<div class="field label border round s6">
<input type="color" x-model="scheme.seed_color" @input="previewScheme()" style="height:3rem;" />
<label>Seed color</label>
</div>
<div class="field label border round s6">
<select x-model="scheme.mode" @change="previewScheme()">
<option value="light">Light</option><option value="dark">Dark</option>
</select>
<label>Mode</label>
</div>
</div>
<label class="checkbox">
<input type="checkbox" x-model="scheme.is_default" /><span>Use as default for new users</span>
</label>
<p class="muted small-text">Tip: the live UI previews this color as you adjust it.</p>
<nav class="right-align">
<button class="border" @click="$refs.schemeDialog.close(); Theme.apply(Theme.resolve(schemes, me?.preferred_scheme_id))">Cancel</button>
<button @click="saveScheme()"><i>save</i><span>Save</span></button>
</nav>
</dialog>
<div class="snackbar error" id="snackbar"><span x-text="error"></span></div>
<style>[x-cloak]{display:none!important;}</style>
</body>
</html>