145 lines
6.1 KiB
HTML
145 lines
6.1 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>
|
|
<script src="/vendor/beer.min.js"></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>
|