init
This commit is contained in:
13
template/blocks/admin_menu.html.tmpl
Normal file
13
template/blocks/admin_menu.html.tmpl
Normal file
@ -0,0 +1,13 @@
|
||||
{{define "admin_menu"}}
|
||||
<aside class="asideAdmin mt-2">
|
||||
<h4>
|
||||
Administration
|
||||
</h4>
|
||||
<ul class="side-menu">
|
||||
<li><a href="/admin/settings" {{if eq . "config"}}class="is-active"{{end}}>Réglages</a></li>
|
||||
<li><a href="/admin/users" {{if eq . "users"}}class="is-active"{{end}}>Utilisateurs</a></li>
|
||||
<li><a href="/admin/apps" {{if eq . "apps"}}class="is-active"{{end}}>Applications</a></li>
|
||||
<li><a href="/admin/market" {{if eq . "market"}}class="is-active"{{end}}>Place de marché</a></li>
|
||||
</ul>
|
||||
</aside>
|
||||
{{end}}
|
53
template/blocks/app_tile.html.tmpl
Normal file
53
template/blocks/app_tile.html.tmpl
Normal file
@ -0,0 +1,53 @@
|
||||
{{define "app_tile" }}
|
||||
<div class="tile is-parent is-4">
|
||||
<article class="app-tile tile is-child" data-controller="app-tile">
|
||||
<div class="front notification">
|
||||
<p class="title">{{ .Manifest.Title }}</p>
|
||||
<p class="subtitle">{{ index .Manifest.Tags 0 }}</p>
|
||||
<div class="level is-mobile">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<div class="buttons">
|
||||
{{if .Manifest.Options.HighscoresEnabled}}
|
||||
<a class="button is-outlined is-link is-medium"
|
||||
href="highscores/{{ .Manifest.ID }}">
|
||||
<svg class="icon">
|
||||
<use xlink:href="#trophy"></use>
|
||||
</svg>
|
||||
</a>
|
||||
{{end}}
|
||||
{{ if .Manifest.Description }}
|
||||
<button data-action="click->app-tile#flip"
|
||||
class="button is-outlined is-info is-medium">
|
||||
<svg class="icon">
|
||||
<use xlink:href="#question"></use>
|
||||
</svg>
|
||||
</button>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<div class="level-item">
|
||||
<a class="button is-primary is-medium has-no-shadow"
|
||||
href="apps/{{ .Manifest.ID }}">
|
||||
<span>Ouvrir</span>
|
||||
<svg class="icon">
|
||||
<use xlink:href="#chevron-right"></use>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ if .Manifest.Description }}
|
||||
<div class="back notification" data-action="click->app-tile#flip">
|
||||
<div class="content">
|
||||
{{ markdown .Manifest.Description }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</article>
|
||||
</div>
|
||||
{{end}}
|
24
template/blocks/base.html.tmpl
Normal file
24
template/blocks/base.html.tmpl
Normal file
@ -0,0 +1,24 @@
|
||||
{{define "base"}}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{block "title" . -}}{{- end}}</title>
|
||||
<link rel="stylesheet" href="/css/server.css">
|
||||
<link rel="stylesheet" href="/css/form.css">
|
||||
<link rel="stylesheet" href="/css/custom.css">
|
||||
{{- block "head_style" . -}}{{end}}
|
||||
{{- block "head_script" . -}}
|
||||
{{template "js_config" .}}
|
||||
<script defer src="/server.js"></script>
|
||||
<script defer src="/server.js"></script>
|
||||
{{end}}
|
||||
</head>
|
||||
<body>
|
||||
{{- block "body" . -}}{{- end -}}
|
||||
{{- block "body_script" . -}}{{end}}
|
||||
</body>
|
||||
{{template "footer" .}}
|
||||
</html>
|
||||
{{end}}
|
23
template/blocks/flash.html.tmpl
Normal file
23
template/blocks/flash.html.tmpl
Normal file
@ -0,0 +1,23 @@
|
||||
{{define "flash"}}
|
||||
<div class="flash has-margin-top-small has-margin-bottom-small">
|
||||
{{- range .Flashes -}}
|
||||
{{- if eq .Type "error" -}}
|
||||
{{template "flash_message" map "Title" "Erreur" "MessageClass" "is-danger" "Message" .Message }}
|
||||
{{- else if eq .Type "warn" -}}
|
||||
{{template "flash_message" map "Title" "Attention" "MessageClass" "is-warning" "Message" .Message }}
|
||||
{{- else if eq .Type "success" -}}
|
||||
{{template "flash_message" map "Title" "Succès" "MessageClass" "is-success" "Message" .Message }}
|
||||
{{- else -}}
|
||||
{{template "flash_message" map "Title" "Information" "MessageClass" "is-info" "Message" .Message }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{define "flash_message" -}}
|
||||
<div class="message {{.MessageClass}}">
|
||||
<div class="message-body">
|
||||
<span class="has-text-weight-bold">{{.Title}}</span> {{.Message}}
|
||||
</div>
|
||||
</div>
|
||||
{{- end}}
|
15
template/blocks/footer.html.tmpl
Normal file
15
template/blocks/footer.html.tmpl
Normal file
@ -0,0 +1,15 @@
|
||||
{{define "footer"}}
|
||||
<footer>
|
||||
<p>
|
||||
<a href="/admin">Accéder au panneau d'administration</a>
|
||||
</p>
|
||||
<p>
|
||||
Propulsé par <a href="https://gitlab.com/arcadbox/arcad">Arcad</a> et publié sous licence <a class="has-text-primary" href="https://gitlab.com/arcadbox/arcad/-/blob/{{ .BuildInfo.GitRef }}/LICENSE">AGPL-3.0</a>.
|
||||
</p>
|
||||
<p>
|
||||
Version: {{ .BuildInfo.ProjectVersion }} -
|
||||
Réf.: {{ .BuildInfo.GitRef }} -
|
||||
Date de construction: {{ .BuildInfo.BuildDate }}
|
||||
</p>
|
||||
</footer>
|
||||
{{end}}
|
27
template/blocks/header.html.tmpl
Normal file
27
template/blocks/header.html.tmpl
Normal file
@ -0,0 +1,27 @@
|
||||
{{define "header"}}
|
||||
<header>
|
||||
<a id="logo" href="/"><img src="/assets/logo.svg"></a>
|
||||
<input type="checkbox" id="active">
|
||||
<label for="active" class="menu-btn"><span></span></label>
|
||||
<label for="active" class="close"></label>
|
||||
<div class="wrapper">
|
||||
<ul>
|
||||
<li class="flashlight"><a href="/"><img src="/assets/logo.svg"></a></li>
|
||||
{{if .IsAdmin}}
|
||||
<li>
|
||||
<a href="/admin/logout" class="button is-warning is-medium" style="font-size: 0.73em;">
|
||||
<svg class="icon" width="50" height="50">
|
||||
<use xlink:href="#sign-out-alt"></use>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
{{end}}
|
||||
<li>
|
||||
<a id="flash" href="/profile">Profile</a>
|
||||
</li>
|
||||
<li><a class="ligth" href="/admin">Admin</a></li>
|
||||
<li><a href="#">Feedback</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
{{end}}
|
3
template/blocks/js_config.html.tmpl
Normal file
3
template/blocks/js_config.html.tmpl
Normal file
@ -0,0 +1,3 @@
|
||||
{{define "js_config"}}
|
||||
<script type="text/javascript">(function() { window.__CONFIG__ = JSON.parse({{toJSON .JSConfig}}) }())</script>
|
||||
{{end}}
|
118
template/layouts/admin_app_edit.html.tmpl
Normal file
118
template/layouts/admin_app_edit.html.tmpl
Normal file
@ -0,0 +1,118 @@
|
||||
{{define "title"}}Modifier l'app - Administration - Arcad{{end}}
|
||||
{{define "body"}}
|
||||
{{template "header" .}}
|
||||
<section class="is-fullheight section">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column is-2">
|
||||
{{template "admin_menu" ""}}
|
||||
</div>
|
||||
<div class="column is-10">
|
||||
{{template "flash" .}}
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<a class="button level-item" href="/admin/apps">← Retour</a>
|
||||
</div>
|
||||
<div class="level-right"></div>
|
||||
</div>
|
||||
<form class="has-margin-top-small" action="/admin/apps/{{ .App.ID }}" method="post">
|
||||
<div class="columns">
|
||||
<div class="column is-12">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<h5 class="is-size-5 level-item">Informations de l'app</h5>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<div class="field level-item">
|
||||
<input id="publishedSwitch" type="checkbox" name="published" class="switch" {{if .IsPublished}}checked="checked"{{end}} />
|
||||
<label for="publishedSwitch">Publiée ?</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Identifiant</label>
|
||||
<div class="control">
|
||||
<p class="input">{{ .App.ID }}</p>
|
||||
<p class="helper">Non modifiable</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Titre</label>
|
||||
<div class="control">
|
||||
<input class="input" type="text"
|
||||
name="title"
|
||||
value="{{if .Form}}{{ .Form.Get "title" }}{{else}}{{ .App.Manifest.Title }}{{end}}">
|
||||
<label className="checkbox is-right">
|
||||
<input type="checkbox" name="resetTitle" />
|
||||
Réinitialiser la valeur par défaut ?
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Description</label>
|
||||
<div class="control">
|
||||
<textarea class="textarea"
|
||||
name="description">{{if .Form}}{{ .Form.Get "description" }}{{else}}{{ .App.Manifest.Description }}{{end}}</textarea>
|
||||
<label className="checkbox is-right">
|
||||
<input type="checkbox" name="resetDescription" />
|
||||
Réinitialiser la valeur par défaut ?
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Ordre d'affichage</label>
|
||||
<div class="control">
|
||||
<input class="input" type="number"
|
||||
step="1"
|
||||
min="0"
|
||||
name="order"
|
||||
value="{{if .Form}}{{ .Form.Get "order" }}{{else}}{{ .App.Order }}{{end}}">
|
||||
<label className="checkbox is-right">
|
||||
<input type="checkbox" name="resetOrder" />
|
||||
Réinitialiser la valeur par défaut ?
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field" data-controller="tags-editor">
|
||||
<label class="label">Tags</label>
|
||||
<div class="control">
|
||||
<div class="field has-addons">
|
||||
<div class="control">
|
||||
<input class="input is-small" type="text" placeholder="Nouveau tag" data-target="tags-editor.newTag">
|
||||
</div>
|
||||
<div class="control">
|
||||
<a class="button is-small is-info has-text-bold" data-action="click->tags-editor#onAddTag">
|
||||
+
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tags" data-target="tags-editor.tagsContainer"></div>
|
||||
<input class="input is-hidden" type="text"
|
||||
data-target="tags-editor.tagsSource"
|
||||
name="tags"
|
||||
value="{{if .Form}}{{ .Form.Get "tags" }}{{else}}{{range .App.Manifest.Tags}}{{.}},{{end}}{{end}}" />
|
||||
<label className="checkbox is-right">
|
||||
<input type="checkbox" name="resetOrder" />
|
||||
Réinitialiser la valeur par défaut ?
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{{ .csrfField }}
|
||||
<div class="buttons" style="justify-content:flex-end">
|
||||
<button type="submit" class="button is-primary is-normal">Modifier</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{template "footer" .}}
|
||||
</div>
|
||||
</section>
|
||||
{{end}}
|
||||
|
||||
{{define "body_script"}}
|
||||
<script defer src="/admin.js"></script>
|
||||
{{end}}
|
||||
|
||||
{{template "base" .}}
|
69
template/layouts/admin_apps_list.html.tmpl
Normal file
69
template/layouts/admin_apps_list.html.tmpl
Normal file
@ -0,0 +1,69 @@
|
||||
{{define "title"}}Applications - Administration - Arcad{{end}}
|
||||
{{define "body"}}
|
||||
{{template "header" .}}
|
||||
<section class="home is-fullheight section">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column is-2">
|
||||
{{template "admin_menu" "apps"}}
|
||||
</div>
|
||||
<div class="column is-10">
|
||||
{{template "flash" .}}
|
||||
<h4 class="is-size-4">Liste des applications installées</h4>
|
||||
<div class="has-text-right">
|
||||
<b>Total</b> {{ .AppsCount }}
|
||||
</div>
|
||||
<div class="table-container">
|
||||
<table class="table is-fullwidth is-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Titre</th>
|
||||
<th>Version</th>
|
||||
<th>Ordre d'affichage</th>
|
||||
<th>Publiée ?</th>
|
||||
<th>Tags</th>
|
||||
<th class="has-text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .Apps}}
|
||||
<tr>
|
||||
<td><code>{{ .ID }}</code></td>
|
||||
<td>{{ .Manifest.Title }}</td>
|
||||
<td>{{ if eq .Manifest.Version "" }}--{{else}}{{ .Manifest.Version }}{{end}}</td>
|
||||
<td>{{ .Order }}</td>
|
||||
<td>{{ if .Published }}oui{{else}}non{{end}}</td>
|
||||
<td>
|
||||
{{range .Manifest.Tags}}
|
||||
<span class="tag is-info">{{ . }}</span>
|
||||
{{end}}
|
||||
</td>
|
||||
<td>
|
||||
<div class="buttons are-small is-right">
|
||||
<a class="button is-link" href="/admin/apps/{{ .ID }}">Modifier</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{else}}
|
||||
<tr class="has-text-centered is-italic">
|
||||
<td colspan="7">
|
||||
Aucune application installée.
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{template "footer" .}}
|
||||
</div>
|
||||
</section>
|
||||
{{end}}
|
||||
|
||||
{{define "body_script"}}
|
||||
<script defer src="/admin.js"></script>
|
||||
{{end}}
|
||||
|
||||
{{template "base" .}}
|
22
template/layouts/admin_login.html.tmpl
Normal file
22
template/layouts/admin_login.html.tmpl
Normal file
@ -0,0 +1,22 @@
|
||||
{{define "title"}}Login - Administration - Arcad{{end}}
|
||||
{{define "body"}}
|
||||
{{template "header" .}}
|
||||
<section class="login is-fullheight section">
|
||||
<div class="container">
|
||||
{{template "flash" .}}
|
||||
<div class="loginForm">
|
||||
<h4>Administration</h4>
|
||||
<form method="POST">
|
||||
<input
|
||||
name="password" type="password"
|
||||
autocomplete="current-password"
|
||||
placeholder="Mot de passe">
|
||||
{{ .csrfField }}
|
||||
<button>S'identifier</button>
|
||||
</form>
|
||||
</div>
|
||||
{{template "footer" .}}
|
||||
</div>
|
||||
</section>
|
||||
{{end}}
|
||||
{{template "base" .}}
|
46
template/layouts/admin_market_app_install.html.tmpl
Normal file
46
template/layouts/admin_market_app_install.html.tmpl
Normal file
@ -0,0 +1,46 @@
|
||||
{{define "title"}}Installer une application - Administration - Arcad{{end}}
|
||||
{{define "body"}}
|
||||
{{template "header" .}}
|
||||
<section class="home is-fullheight section" data-controller="app-install">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column is-2">
|
||||
{{template "admin_menu" "market"}}
|
||||
</div>
|
||||
<div class="column is-10">
|
||||
{{template "flash" .}}
|
||||
{{if .App}}
|
||||
<article class="message is-info">
|
||||
<div class="message-header">
|
||||
<p>Installation d'une application</p>
|
||||
</div>
|
||||
<div class="message-body">
|
||||
<p data-target="app-install.message">Êtes vous sûr de vouloir installer l'application <code>{{ .App.Name }}</code> en version <code>{{ .App.LatestRelease.Version }}</code> développée par <b>{{ .App.Owner.Username }}</b> ?</p>
|
||||
<div class="buttons is-right">
|
||||
<a data-target="app-install.cancelButton" href="/admin/market" class="button is-outlined is-link">Annuler</a>
|
||||
<button data-target="app-install.installButton" data-action="click->app-install#onInstallClick" class="button is-primary">Confirmer</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{{else}}
|
||||
<article class="message is-danger">
|
||||
<div class="message-body">
|
||||
Impossible de trouver l'application correspondant à la demande d'installation.
|
||||
<div class="buttons is-right">
|
||||
<a href="/admin/market" class="button is-outlined is-danger">Retour</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{template "footer" .}}
|
||||
</div>
|
||||
</section>
|
||||
{{end}}
|
||||
|
||||
{{define "body_script"}}
|
||||
<script defer src="/admin.js"></script>
|
||||
{{end}}
|
||||
|
||||
{{template "base" .}}
|
74
template/layouts/admin_market_search.html.tmpl
Normal file
74
template/layouts/admin_market_search.html.tmpl
Normal file
@ -0,0 +1,74 @@
|
||||
{{define "title"}}Place de marché - Administration - Arcad{{end}}
|
||||
{{define "body"}}
|
||||
{{template "header" .}}
|
||||
<section class="home is-fullheight section">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column is-2">
|
||||
{{template "admin_menu" "market"}}
|
||||
</div>
|
||||
<div class="column is-10">
|
||||
{{template "flash" .}}
|
||||
<form action="/admin/market" methode="GET">
|
||||
<div class="field has-addons mt-5 mb-5">
|
||||
<div class="control is-expanded">
|
||||
<input class="input is-medium" type="text" name="search" placeholder="Rechercher une application..." value="{{ .Search }}">
|
||||
</div>
|
||||
<div class="control">
|
||||
<button type="submit" class="button is-medium">
|
||||
Rechercher
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="has-text-right">
|
||||
<b>Total</b> {{ .ResultsCount }}
|
||||
</div>
|
||||
<div class="table-container">
|
||||
<table class="table is-fullwidth is-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Description</th>
|
||||
<th>Développeur</th>
|
||||
<th>Dernière version</th>
|
||||
<th>Dernière mise à jour</th>
|
||||
<th class="has-text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .Results}}
|
||||
<tr>
|
||||
<td><code>{{ .Name }}</code></td>
|
||||
<td>{{ .LatestRelease.Description }}</td>
|
||||
<td>{{ .Owner.Username }}</td>
|
||||
<td>{{ .LatestRelease.Version }}</td>
|
||||
<td>{{ localeTimeFormat .LatestRelease.CreatedAt.Time "02/01/2006 15:04" "fr_FR" }}</td>
|
||||
<td>
|
||||
<div class="buttons are-small is-right">
|
||||
<a class="button is-link" href="/admin/market/{{ .ID }}/install">Installer</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{else}}
|
||||
<tr class="has-text-centered is-italic">
|
||||
<td colspan="6">
|
||||
Aucun résultat.
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{template "footer" .}}
|
||||
</div>
|
||||
</section>
|
||||
{{end}}
|
||||
|
||||
{{define "body_script"}}
|
||||
<script defer src="/admin.js"></script>
|
||||
{{end}}
|
||||
|
||||
{{template "base" .}}
|
40
template/layouts/admin_register.html.tmpl
Normal file
40
template/layouts/admin_register.html.tmpl
Normal file
@ -0,0 +1,40 @@
|
||||
{{define "title"}}Création du mot de passe - Administration - Arcad{{end}}
|
||||
{{define "body"}}
|
||||
{{template "header" .}}
|
||||
<section class="login is-fullheight section">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column is-offset-4 is-4">
|
||||
{{template "flash" .}}
|
||||
<div class="box">
|
||||
<h4 class="title is-size-4">Création du mot de passe de l'administrateur</h4>
|
||||
<form method="POST">
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input class="input is-normal"
|
||||
name="adminPassword" type="password"
|
||||
autocomplete="new-password"
|
||||
placeholder="Mot de passe">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input class="input is-normal"
|
||||
name="adminPassword-confirm" type="password"
|
||||
autocomplete="new-password"
|
||||
placeholder="Confirmation du mot de passe">
|
||||
</div>
|
||||
</div>
|
||||
{{ .csrfField }}
|
||||
<input type="submit"
|
||||
value="Enregister"
|
||||
class="button is-block is-primary is-normal is-fullwidth">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{template "footer" .}}
|
||||
</div>
|
||||
</section>
|
||||
{{end}}
|
||||
{{template "base" .}}
|
72
template/layouts/admin_settings.html.tmpl
Normal file
72
template/layouts/admin_settings.html.tmpl
Normal file
@ -0,0 +1,72 @@
|
||||
{{define "title"}}Configuration - Administration - Arcad{{end}}
|
||||
{{define "body"}}
|
||||
{{template "header" .}}
|
||||
<section class="home is-fullheight section" data-controller="clock-sync">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column is-2">
|
||||
{{template "admin_menu" "config"}}
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
{{template "flash" .}}
|
||||
<h4 class="is-size-4">Réglages</h4>
|
||||
<form id="adminSettings" method="post">
|
||||
{{ .csrfField }}
|
||||
{{ $settings := .Settings }}
|
||||
{{range $id, $meta := .Metadatas}}
|
||||
{{ $se := $settings.Get $id }}
|
||||
{{ $data := createMap "ID" $id "Setting" $se "Meta" $meta }}
|
||||
{{if eq $meta.ValueType "password"}}
|
||||
{{template "password_setting" $data}}
|
||||
{{else if eq $meta.ValueType "markdown"}}
|
||||
{{template "markdown_setting" $data}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
<div class="field is-grouped is-grouped-right">
|
||||
<p class="control">
|
||||
<input type="submit" class="button is-success" value="Enregistrer">
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{template "footer" .}}
|
||||
</div>
|
||||
</section>
|
||||
{{end}}
|
||||
|
||||
{{define "body_script"}}
|
||||
<script defer src="/admin.js"></script>
|
||||
{{end}}
|
||||
|
||||
{{template "base" .}}
|
||||
|
||||
{{define "password_setting"}}
|
||||
<div class="field">
|
||||
<label class="label">{{ .Meta.Label }}</label>
|
||||
<div class="control">
|
||||
<input class="input" name="{{ .ID }}"
|
||||
autocomplete="new-password"
|
||||
type="password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">{{ .Meta.Label }} (confirmation)</label>
|
||||
<div class="control">
|
||||
<input class="input" name="{{ .ID }}-confirm"
|
||||
autocomplete="new-password"
|
||||
type="password">
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{define "markdown_setting"}}
|
||||
<div class="field">
|
||||
<label class="label">{{ .Meta.Label }}</label>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<textarea class="textarea" placeholder="{{ .Meta.DefaultValue }}" name="{{ .ID }}">{{- if .Setting}}{{ .Setting.Value }}{{end -}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
41
template/layouts/admin_user_delete.html.tmpl
Normal file
41
template/layouts/admin_user_delete.html.tmpl
Normal file
@ -0,0 +1,41 @@
|
||||
{{define "title"}}Informations de l'utilisateur - Administration - Arcad{{end}}
|
||||
{{define "body"}}
|
||||
{{template "header" .}}
|
||||
<section class="home is-fullheight section">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column is-2">
|
||||
{{template "admin_menu" ""}}
|
||||
</div>
|
||||
<div class="column is-10">
|
||||
{{template "flash" .}}
|
||||
<form class="has-margin-top-small" action="/admin/users/{{ .User.ID }}/delete" method="post">
|
||||
{{ .csrfField }}
|
||||
<div class="message is-warning">
|
||||
<div class="message-body">
|
||||
Êtes vous sûr de vouloir supprimer le compte de l'utilisateur "{{ .User.Nickname }}" ({{ .User.ID }}) ?
|
||||
</div>
|
||||
</div>
|
||||
<div class="field is-grouped is-grouped-right">
|
||||
<p class="control">
|
||||
<a href="/admin/users/{{.User.ID}}" class="button is-light">
|
||||
Annuler
|
||||
</a>
|
||||
</p>
|
||||
<p class="control">
|
||||
<input type="submit" class="button is-danger" value="Supprimer">
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{template "footer" .}}
|
||||
</div>
|
||||
</section>
|
||||
{{end}}
|
||||
|
||||
{{define "body_script"}}
|
||||
<script defer src="/admin.js"></script>
|
||||
{{end}}
|
||||
|
||||
{{template "base" .}}
|
102
template/layouts/admin_user_info.html.tmpl
Normal file
102
template/layouts/admin_user_info.html.tmpl
Normal file
@ -0,0 +1,102 @@
|
||||
{{define "title"}}Informations de l'utilisateur - Administration - Arcad{{end}}
|
||||
{{define "body"}}
|
||||
{{template "header" .}}
|
||||
<section class="home is-fullheight section">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column is-2">
|
||||
{{template "admin_menu" ""}}
|
||||
</div>
|
||||
<div class="column is-10">
|
||||
{{template "flash" .}}
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<a class="button level-item" href="/admin/users">← Retour</a>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<a class="button level-item is-danger" href="/admin/users/{{ .User.ID }}/delete">Supprimer</a>
|
||||
</div>
|
||||
</div>
|
||||
<form class="has-margin-top-small" action="/admin/users/{{ .User.ID }}" method="post">
|
||||
<div class="columns">
|
||||
<div class="column is-6">
|
||||
<h5 class="is-size-5">Informations de l'utilisateur</h5>
|
||||
<div class="field">
|
||||
<label class="label">Pseudonyme</label>
|
||||
<div class="control">
|
||||
<input class="input" type="text"
|
||||
name="nickname"
|
||||
value="{{if .Form}}{{ .Form.Get "nickname" }}{{else}}{{ .User.Nickname }}{{end}}">
|
||||
</div>
|
||||
</div>
|
||||
{{ .csrfField }}
|
||||
<div class="buttons" style="justify-content:flex-end">
|
||||
<button type="submit" class="button is-primary is-normal">Modifier</button>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Date de création</label>
|
||||
<div class="control">
|
||||
<p class="input" readonly>
|
||||
{{ localeTimeFormat .User.CreationTime "02/01/2006 15:04" "fr_FR" }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Date de dernière connexion</label>
|
||||
<div class="control">
|
||||
<p class="input" readonly>
|
||||
{{ localeTimeFormat .User.LastSeenTime "02/01/2006 15:04" "fr_FR" }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{{with .User.LastUserAgent}}
|
||||
<div class="field">
|
||||
<label class="label">Dernier système d'exploitation utilisé</label>
|
||||
<div class="control">
|
||||
<p class="input" readonly>
|
||||
{{ .OS.Name.StringTrimPrefix }} {{ .OS.Version.Major }}.{{ .OS.Version.Minor }}.{{ .OS.Version.Patch }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Dernier navigateur utilisé</label>
|
||||
<div class="control">
|
||||
<p class="input" readonly>
|
||||
{{ .Browser.Name.StringTrimPrefix }} {{ .Browser.Version.Major }}.{{ .Browser.Version.Minor }}.{{ .Browser.Version.Patch }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Dernier type de terminal utilisé</label>
|
||||
<div class="control">
|
||||
<p class="input" readonly>
|
||||
{{ .DeviceType.StringTrimPrefix }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="column is-6">
|
||||
<h5 class="is-size-5">Carte de membre</h5>
|
||||
<div class="box has-margin-top-small">
|
||||
<figure class="image is-3by2">
|
||||
<a href="/admin/users/{{ .User.ID }}/card" rel="Member card" download="ArcadBox-Member-{{ .User.Nickname }}">
|
||||
<img src="/admin/users/{{ .User.ID }}/card" />
|
||||
</a>
|
||||
</figure>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{template "footer" .}}
|
||||
</div>
|
||||
</section>
|
||||
{{end}}
|
||||
|
||||
{{define "body_script"}}
|
||||
<script defer src="/admin.js"></script>
|
||||
{{end}}
|
||||
|
||||
{{template "base" .}}
|
58
template/layouts/admin_users_list.html.tmpl
Normal file
58
template/layouts/admin_users_list.html.tmpl
Normal file
@ -0,0 +1,58 @@
|
||||
{{define "title"}}Utilisateurs - Administration - Arcad{{end}}
|
||||
{{define "body"}}
|
||||
{{template "header" .}}
|
||||
<section class="home is-fullheight section">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column is-2">
|
||||
{{template "admin_menu" "users"}}
|
||||
</div>
|
||||
<div class="column is-10">
|
||||
{{template "flash" .}}
|
||||
<h4 class="is-size-4">Liste des utilisateurs</h4>
|
||||
<div class="has-text-right">
|
||||
<b>Total</b> {{ .UsersCount }}
|
||||
</div>
|
||||
<div class="table-container">
|
||||
<table class="table is-hovered is-fullwidth is-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Pseudonyme</th>
|
||||
<th>Date d'enregistrement</th>
|
||||
<th>Dernière connexion</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .Users}}
|
||||
<tr>
|
||||
<td>{{ .Nickname }}</td>
|
||||
<td>{{ localeTimeFormat .CreationTime "02/01/2006 15:04" "fr_FR" }}</td>
|
||||
<td>{{ localeTimeFormat .LastSeenTime "02/01/2006 15:04" "fr_FR" }}</td>
|
||||
<td>
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<a class="button is-danger is-small" href="/admin/users/{{ .ID }}/delete">Supprimer</a>
|
||||
</div>
|
||||
<div class="control">
|
||||
<a class="button is-info is-small" href="/admin/users/{{ .ID }}">Voir</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{template "footer" .}}
|
||||
</div>
|
||||
</section>
|
||||
{{end}}
|
||||
|
||||
{{define "body_script"}}
|
||||
<script defer src="/admin.js"></script>
|
||||
{{end}}
|
||||
|
||||
{{template "base" .}}
|
31
template/layouts/app.html.tmpl
Normal file
31
template/layouts/app.html.tmpl
Normal file
@ -0,0 +1,31 @@
|
||||
{{define "title"}}{{ .App.Manifest.Title }} - Arcad{{end}}
|
||||
{{define "body"}}
|
||||
<div class="app-wrapper" data-controller="app" data-app-frame-src="./{{ .App.Manifest.ID }}/">
|
||||
<div class="app-header">
|
||||
<div class="level is-marginless is-mobile">
|
||||
<div class="level-left">
|
||||
<a href="../" class="level-item button is-link is-small">
|
||||
<svg class="icon">
|
||||
<use xlink:href="#home"></use>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
{{if .App.Manifest.Options.HighscoresEnabled}}
|
||||
<a href="../highscores/{{ .App.Manifest.ID }}" class="level-item button is-link is-small">
|
||||
<span>Classement</span>
|
||||
<svg class="icon">
|
||||
<use xlink:href="#trophy"></use>
|
||||
</svg>
|
||||
</a>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<iframe class="app-frame" data-target="app.frame"
|
||||
scrolling="no" seamless="seamless"
|
||||
data-action="beforeunload->app#onFrameBeforeUnload load->app#onFrameLoad">
|
||||
</iframe>
|
||||
</div>
|
||||
{{end}}
|
||||
{{template "base" .}}
|
15
template/layouts/bad_gateway.html.tmpl
Normal file
15
template/layouts/bad_gateway.html.tmpl
Normal file
@ -0,0 +1,15 @@
|
||||
{{define "title"}}Borne non disponible - Arcad{{end}}
|
||||
{{define "body"}}
|
||||
<section class="is-fullheight section">
|
||||
<div class="is-flex is-justify-content-center is-align-content-center is-fullheight">
|
||||
<div class="message is-warning is-align-self-center">
|
||||
<div class="message-body">
|
||||
<h1 class="is-size-4">Arcad</h1>
|
||||
<p>Désolé mais aucune borne correspondant à ce domaine n'est actuellement en ligne.</p>
|
||||
<p>Veuillez réessayer plus tard et/ou vous assurer que la borne est correctement connectée à internet.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{{end}}
|
||||
{{template "base" .}}
|
29
template/layouts/captive_portal.html.tmpl
Normal file
29
template/layouts/captive_portal.html.tmpl
Normal file
@ -0,0 +1,29 @@
|
||||
{{define "title"}}Chargement en cours - Arcad{{end}}
|
||||
{{define "body"}}
|
||||
{{template "header" .}}
|
||||
{{ $redirectUrl := "/captive?escape=1" }}
|
||||
{{ if .IsAndroid }}
|
||||
{{ $redirectUrl := "intent://arcadbox.local/captive?escape=1#Intent;scheme=http;end" }}
|
||||
{{ end }}
|
||||
<section class="home is-fullheight section">
|
||||
<div class="container">
|
||||
<div class="message is-info">
|
||||
<div class="message-body">
|
||||
<div class="content">
|
||||
<p>Un instant s'il vous plaît, nous préparons votre espace...</p>
|
||||
<p>Si la page ne se recharge pas automatiquement, <a id="homepage-link" href="{{ $redirectUrl }}" target="_blank">cliquez ici.</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{template "footer" .}}
|
||||
</div>
|
||||
</section>
|
||||
{{end}}
|
||||
{{define "head_style"}}
|
||||
{{ $redirectUrl := "/captive?escape=1" }}
|
||||
{{ if .IsAndroid }}
|
||||
{{ $redirectUrl := "intent://arcadbox.local/captive?escape=1#Intent;scheme=http;end" }}
|
||||
{{ end }}
|
||||
<meta http-equiv="refresh" content="1;URL={{ $redirectUrl }}">
|
||||
{{end}}
|
||||
{{template "base" .}}
|
121
template/layouts/highscore.html.tmpl
Normal file
121
template/layouts/highscore.html.tmpl
Normal file
@ -0,0 +1,121 @@
|
||||
{{define "title"}}{{.App.Manifest.Title}} - Tableau des scores - Arcad{{end}}
|
||||
{{define "body"}}
|
||||
{{template "header" .}}
|
||||
<section class="home is-fullheight section">
|
||||
<div class="container">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<h1 class="title level-item">{{.App.Manifest.Title}}</h1>
|
||||
<h2 class="subtitle level-item">Tableau des scores</h2>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<a class="level-item button is-primary is-large" href="/apps/{{ .App.ID }}">
|
||||
<span>Ouvrir</span>
|
||||
<svg class="icon">
|
||||
<use xlink:href="#chevron-right"></use>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
{{template "podium" .}}
|
||||
</div>
|
||||
<div class="column">
|
||||
{{template "highscores" .}}
|
||||
</div>
|
||||
</div>
|
||||
{{template "footer" .}}
|
||||
</div>
|
||||
</section>
|
||||
{{end}}
|
||||
{{template "base" .}}
|
||||
|
||||
{{define "podium"}}
|
||||
<div class="podium-container">
|
||||
<div class="podium">
|
||||
<div class="pod second">
|
||||
{{ if gt (len .Highscores) 1 }}
|
||||
{{ $secondPlayerHighscore := index .Highscores 1 }}
|
||||
{{if $secondPlayerHighscore}}
|
||||
<div class="pod-player">
|
||||
{{ $secondPlayer := (index .Users $secondPlayerHighscore.UserID) }}
|
||||
<span class="player-nickname">{{with $secondPlayer}}{{ .Nickname }}{{else}}???{{end}}</span>
|
||||
<span class="player-score">{{ $secondPlayerHighscore.Score }}</span>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<div class="pod-stair">
|
||||
<span class="pod-position">2</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pod first">
|
||||
{{ if gt (len .Highscores) 0 }}
|
||||
{{ $firstPlayerHighscore := index .Highscores 0 }}
|
||||
{{if $firstPlayerHighscore}}
|
||||
<div class="pod-player">
|
||||
{{ $firstPlayer := (index .Users $firstPlayerHighscore.UserID) }}
|
||||
<svg class="icon player-crown">
|
||||
<use xlink:href="#crown"></use>
|
||||
</svg>
|
||||
<span class="player-nickname">{{with $firstPlayer}}{{ .Nickname }}{{else}}???{{end}}</span>
|
||||
<span class="player-score">{{ $firstPlayerHighscore.Score }}</span>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<div class="pod-stair">
|
||||
<span class="pod-position">1</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pod third">
|
||||
{{ if gt (len .Highscores) 2 }}
|
||||
{{ $thirdPlayerHighscore := index .Highscores 2 }}
|
||||
{{if $thirdPlayerHighscore}}
|
||||
<div class="pod-player">
|
||||
{{ $thirdPlayer := (index .Users $thirdPlayerHighscore.UserID) }}
|
||||
<span class="player-nickname">{{with $thirdPlayer}}{{ .Nickname }}{{else}}???{{end}}</span>
|
||||
<span class="player-score">{{ $thirdPlayerHighscore.Score }}</span>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<div class="pod-stair">
|
||||
<div class="pod-position">3</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
|
||||
{{define "highscores"}}
|
||||
{{ $users := .Users }}
|
||||
<div class="table-container">
|
||||
<table class="table is-fullwidth is-hoverable is-striped">
|
||||
<thead>
|
||||
<th>Position</th>
|
||||
<th>Pseudonyme</th>
|
||||
<th>Score</th>
|
||||
<th>Date</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range $i, $h := .Highscores}}
|
||||
{{ $user := (index $users $h.UserID) }}
|
||||
<tr>
|
||||
{{ $position := addInt $i 1 }}
|
||||
<td>{{ $position }}</td>
|
||||
<td>{{with $user}}{{ .Nickname }}{{else}}???{{end}}</td>
|
||||
<td>{{ $h.Score }}</td>
|
||||
<td>{{ localeTimeFormat $h.CreationTime "02/01/2006 15:04" "fr_FR" }}</td>
|
||||
</tr>
|
||||
{{else}}
|
||||
<tr>
|
||||
<td colspan="4" class="has-text-centered is-italic">Aucun score pour l'instant.</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{end}}
|
24
template/layouts/home.html.tmpl
Normal file
24
template/layouts/home.html.tmpl
Normal file
@ -0,0 +1,24 @@
|
||||
{{define "title"}}Accueil - Arcad{{end}}
|
||||
{{define "body"}}
|
||||
{{template "header" .}}
|
||||
<section class="home is-fullheight section">
|
||||
<div id="main" class="container">
|
||||
<img src="/assets/arcad.svg">
|
||||
{{if and .WelcomeMessage .WelcomeMessage.Value}}
|
||||
<div class="message is-info is-small">
|
||||
<div class="message-body">
|
||||
<div class="content">
|
||||
{{markdown .WelcomeMessage.Value}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="tile is-ancestor is-wrap tile-container">
|
||||
{{range .Apps}}
|
||||
{{- template "app_tile" . -}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{{end}}
|
||||
{{template "base" .}}
|
85
template/layouts/profile.html.tmpl
Normal file
85
template/layouts/profile.html.tmpl
Normal file
@ -0,0 +1,85 @@
|
||||
{{define "title"}}Profil - Arcad{{end}}
|
||||
{{define "body"}}
|
||||
{{template "header" .}}
|
||||
<section>
|
||||
<div>
|
||||
{{template "flash" .}}
|
||||
<form action="/login" method="POST" enctype="multipart/form-data">
|
||||
<div class="field" style="margin-bottom:0">
|
||||
<div class="file is-medium is-success" id="memberCard">
|
||||
<label class="file-label">
|
||||
<input class="file-input" type="file" name="memberCard">
|
||||
<span class="file-cta">
|
||||
<span class="file-icon">
|
||||
<svg class="icon" width="50" height="50">
|
||||
<use xlink:href="#address-card"></use>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="file-label">
|
||||
Se connecter
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{{ .csrfField }}
|
||||
</form>
|
||||
</div>
|
||||
<div class="level-item">
|
||||
<a href="/logout" class="button is-warning is-medium">
|
||||
<svg class="icon" width="50" height="50">
|
||||
<use xlink:href="#sign-out-alt"></use>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column is-6">
|
||||
<h5 class="is-size-5">Vos informations</h5>
|
||||
<form class="has-margin-top-small" action="/profile" method="post">
|
||||
<div class="field">
|
||||
<label class="label">Pseudonyme</label>
|
||||
<div class="control">
|
||||
<input class="input is-medium" type="text"
|
||||
name="nickname"
|
||||
value="{{if .Form}}{{ .Form.Get "nickname" }}{{else}}{{ .User.Nickname }}{{end}}">
|
||||
</div>
|
||||
</div>
|
||||
{{ .csrfField }}
|
||||
<div class="buttons" style="justify-content:flex-end">
|
||||
<button type="submit" class="button is-primary is-medium">
|
||||
<span>Modifier</span>
|
||||
<span class="icon">
|
||||
<svg class="icon" width="50" height="50">
|
||||
<use xlink:href="#edit"></use>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="column is-6">
|
||||
<h5 class="is-size-5">Carte de membre</h5>
|
||||
<article class="message is-info">
|
||||
<div class="message-body">
|
||||
Téléchargez et utilisez votre carte de membre afin de pouvoir vous authentifier la prochaine fois avec le même pseudonyme !
|
||||
</div>
|
||||
</article>
|
||||
<figure class="image is-3by2 has-margin-top-small">
|
||||
<a href="/profile/card" rel="Member card" download="ArcadBox-Member-{{ .User.Nickname }}">
|
||||
<img src="/profile/card" />
|
||||
</a>
|
||||
</figure>
|
||||
</div>
|
||||
</section>
|
||||
{{end}}
|
||||
{{define "body_script"}}
|
||||
<script>
|
||||
const fileInput = document.querySelector('#memberCard input[type=file]');
|
||||
fileInput.onchange = () => {
|
||||
fileInput.form.submit();
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
||||
{{template "base" .}}
|
Reference in New Issue
Block a user