dark mode

This commit is contained in:
fabio 2026-02-23 17:31:06 +01:00
parent fce8b9d4bb
commit e0ef48f6fd
26 changed files with 328 additions and 3714 deletions

View File

@ -22,6 +22,11 @@ make server
- copia di `flowbite-ui/node_modules/flowbite/dist/flowbite.min.js` in `web/static/vendor/flowbite.js`
- build Tailwind in `web/static/css/app.css`
Dark mode globale:
- toggle nel footer su tutte le pagine
- preferenza persistente in `localStorage` con chiave `theme` (`dark`/`light`)
- fallback automatico a `prefers-color-scheme` quando non c'e una preferenza salvata
## Quickstart SQLite
```bash

View File

@ -0,0 +1,79 @@
TASK: Aggiungere Dark Mode globale con toggle nel footer (Flowbite + Tailwind).
Vincoli:
- Usare Tailwind dark mode con strategia "class" (non media)
- Toggle nel footer visibile su tutte le pagine (layout globale)
- Stato persistente con localStorage
- Default: se non cè preferenza salvata, usare prefers-color-scheme
- Nessun framework JS aggiuntivo
- Non rompere HTMX e Flowbite
- Accessibile (aria-label, stato, focus)
1) Tailwind config
- Aggiornare tailwind.config.js:
- impostare `darkMode: 'class'`
- assicurarsi che content includa templates e node_modules/flowbite come già configurato
2) JS globale
- Creare file /web/static/vendor/theme.js (o /web/static/js/theme.js se preferisci) con:
- allavvio (prima del render visibile):
- leggere localStorage key `theme` ('dark'|'light')
- se non presente, leggere `window.matchMedia('(prefers-color-scheme: dark)')`
- applicare/rimuovere classe `dark` su <html> (document.documentElement)
- esporre funzione toggleTheme() che:
- toggla classe `dark`
- salva preferenza in localStorage
- aggiorna label testo del bottone e aria-pressed
- gestire aggiornamento se lutente non ha preferenza salvata e cambia prefers-color-scheme (listener matchMedia), opzionale ma gradito
3) Includere theme.js nel layout
- In /web/templates/layout.html:
- includere theme.js nel <head> prima del CSS per evitare FOUC:
<script src="/static/vendor/theme.js"></script>
- poi link CSS e script htmx/flowbite come già presenti
- aggiungere classi base al body per dark:
- bg-white dark:bg-gray-900
- text-gray-900 dark:text-gray-100
- min-h-screen flex flex-col
- contenuto in main con flex-1
4) Footer + toggle button (Flowbite style)
- Nel footer del layout aggiungere un bottone:
- posizionato a destra (o center se preferisci) con icona (testo va bene senza icone)
- classi Flowbite/Tailwind:
- px-3 py-2 text-sm font-medium rounded-lg
- bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700
- attributi accessibilità:
- id="themeToggle"
- type="button"
- aria-label="Toggle dark mode"
- aria-pressed="false" (aggiornato via JS)
- testo dinamico: "Dark mode" / "Light mode" o "Tema: Scuro/Chiaro"
- Aggiungere onclick:
- onclick="window.toggleTheme && window.toggleTheme()"
5) Aggiornare componenti base per dark
- Aggiornare /web/templates/components/navbar.html (se esiste) e altri partial principali con classi dark:
- Navbar: bg-white dark:bg-gray-900, border-gray-200 dark:border-gray-700
- Dropdown: bg-white dark:bg-gray-800, text colors
- Cards: bg-white dark:bg-gray-800
- Tables: dark divide colors
Non serve perfezione totale, ma assicurare leggibilità.
6) README
- Aggiornare README con nota:
- dark mode persistente in localStorage key "theme"
7) Criteri di accettazione
- Il toggle è visibile nel footer su tutte le pagine
- Il tema persiste al reload
- Default segue prefers-color-scheme se non impostato manualmente
- Nessun flash di tema sbagliato (FOUC minimizzato)
- Non rompe Flowbite JS, modals, dropdown e HTMX
- Accessibile: bottone focusable e aria-pressed aggiornato
Esegui:
- make tw-build (o make tw-watch per verificare)
- Avvia server e verifica cambio tema su /login e /users.
Correggi eventuali classi mancanti.

View File

@ -1,4 +1,5 @@
module.exports = {
darkMode: "class",
content: [
"../web/templates/**/*.{html,gohtml}",
"../web/static/**/*.js",

File diff suppressed because one or more lines are too long

78
web/static/vendor/theme.js vendored Normal file
View File

@ -0,0 +1,78 @@
(function () {
var STORAGE_KEY = "theme";
var root = document.documentElement;
var mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
function getStoredTheme() {
var value = null;
try {
value = localStorage.getItem(STORAGE_KEY);
} catch (e) {
value = null;
}
return value === "dark" || value === "light" ? value : null;
}
function getPreferredTheme() {
return mediaQuery.matches ? "dark" : "light";
}
function applyTheme(theme) {
root.classList.toggle("dark", theme === "dark");
}
function currentTheme() {
return root.classList.contains("dark") ? "dark" : "light";
}
function setStoredTheme(theme) {
try {
localStorage.setItem(STORAGE_KEY, theme);
} catch (e) {
// localStorage may be unavailable in private mode or blocked contexts.
}
}
function updateToggleState(theme) {
var button = document.getElementById("themeToggle");
if (!button) return;
var isDark = theme === "dark";
button.setAttribute("aria-pressed", isDark ? "true" : "false");
button.textContent = isDark ? "Light mode" : "Dark mode";
}
function applyInitialTheme() {
var stored = getStoredTheme();
applyTheme(stored || getPreferredTheme());
}
window.toggleTheme = function toggleTheme() {
var next = currentTheme() === "dark" ? "light" : "dark";
applyTheme(next);
setStoredTheme(next);
updateToggleState(next);
};
window.initThemeToggle = function initThemeToggle() {
updateToggleState(currentTheme());
};
if (typeof mediaQuery.addEventListener === "function") {
mediaQuery.addEventListener("change", function (event) {
if (getStoredTheme()) return;
var theme = event.matches ? "dark" : "light";
applyTheme(theme);
updateToggleState(theme);
});
} else if (typeof mediaQuery.addListener === "function") {
mediaQuery.addListener(function (event) {
if (getStoredTheme()) return;
var theme = event.matches ? "dark" : "light";
applyTheme(theme);
updateToggleState(theme);
});
}
applyInitialTheme();
})();

View File

@ -1,11 +1,11 @@
{{define "navbar"}}
<nav class="border-b border-gray-200 bg-white">
<nav class="border-b border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-900">
<div class="mx-auto flex max-w-7xl flex-wrap items-center justify-between p-4">
<a href="/" class="flex items-center space-x-3 rtl:space-x-reverse">
<span class="self-center whitespace-nowrap text-xl font-semibold">Trustcontact</span>
</a>
<button data-collapse-toggle="navbar-main" type="button" class="inline-flex h-10 w-10 items-center justify-center rounded-lg p-2 text-sm text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 md:hidden" aria-controls="navbar-main" aria-expanded="false">
<button data-collapse-toggle="navbar-main" type="button" class="inline-flex h-10 w-10 items-center justify-center rounded-lg p-2 text-sm text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-700 md:hidden" aria-controls="navbar-main" aria-expanded="false">
<span class="sr-only" data-i18n="nav.open_main_menu">Apri menu principale</span>
<svg class="h-5 w-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h15M1 7h15M1 13h15" />
@ -13,9 +13,9 @@
</button>
<div class="hidden w-full items-center justify-between md:order-1 md:flex md:w-auto" id="navbar-main">
<ul class="mt-4 flex flex-col gap-2 rounded-lg border border-gray-100 bg-gray-50 p-4 text-sm font-medium md:mt-0 md:flex-row md:items-center md:gap-1 md:border-0 md:bg-transparent md:p-0">
<li><a href="/admin" class="block rounded-lg px-3 py-2 text-gray-700 hover:bg-gray-100">Dashboard</a></li>
<li><a href="/admin/users" class="block rounded-lg px-3 py-2 text-gray-700 hover:bg-gray-100" data-i18n="nav.users">Users</a></li>
<ul class="mt-4 flex flex-col gap-2 rounded-lg border border-gray-100 bg-gray-50 p-4 text-sm font-medium md:mt-0 md:flex-row md:items-center md:gap-1 md:border-0 md:bg-transparent md:p-0 dark:border-gray-700 dark:bg-gray-800 md:dark:bg-transparent">
<li><a href="/admin" class="block rounded-lg px-3 py-2 text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700">Dashboard</a></li>
<li><a href="/admin/users" class="block rounded-lg px-3 py-2 text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700" data-i18n="nav.users">Users</a></li>
</ul>
<div class="mt-4 flex items-center gap-3 md:mt-0 md:ms-4">
@ -31,20 +31,20 @@
{{if .CurrentUser}}
<div class="relative">
<button type="button" class="flex items-center rounded-full bg-gray-800 text-sm focus:ring-4 focus:ring-gray-300" id="user-menu-button" aria-expanded="false" data-dropdown-toggle="user-dropdown" data-dropdown-placement="bottom">
<button type="button" class="flex items-center rounded-full bg-gray-800 text-sm focus:ring-4 focus:ring-gray-300 dark:bg-gray-700 dark:focus:ring-gray-700" id="user-menu-button" aria-expanded="false" data-dropdown-toggle="user-dropdown" data-dropdown-placement="bottom">
<span class="sr-only" data-i18n="nav.open_user_menu">Apri menu utente</span>
<span class="inline-flex h-9 w-9 items-center justify-center rounded-full bg-blue-600 font-semibold text-white">
{{if .CurrentUser.Name}}{{printf "%.1s" .CurrentUser.Name}}{{else}}{{printf "%.1s" .CurrentUser.Email}}{{end}}
</span>
</button>
<div class="z-50 my-4 hidden w-56 list-none divide-y divide-gray-100 rounded-lg bg-white text-base shadow-sm" id="user-dropdown">
<div class="z-50 my-4 hidden w-56 list-none divide-y divide-gray-100 rounded-lg bg-white text-base shadow-sm dark:divide-gray-700 dark:bg-gray-800" id="user-dropdown">
<div class="px-4 py-3">
<span class="block truncate text-sm text-gray-900">{{if .CurrentUser.Name}}{{.CurrentUser.Name}}{{else}}Utente{{end}}</span>
<span class="block truncate text-sm text-gray-500">{{.CurrentUser.Email}}</span>
<span class="block truncate text-sm text-gray-900 dark:text-gray-100">{{if .CurrentUser.Name}}{{.CurrentUser.Name}}{{else}}Utente{{end}}</span>
<span class="block truncate text-sm text-gray-500 dark:text-gray-400">{{.CurrentUser.Email}}</span>
</div>
<div class="py-2">
<form action="/logout" method="post" class="px-2">
<button type="submit" class="block w-full rounded-lg px-2 py-2 text-left text-sm text-red-700 hover:bg-red-50" data-i18n="nav.logout">Logout</button>
<button type="submit" class="block w-full rounded-lg px-2 py-2 text-left text-sm text-red-700 hover:bg-red-50 dark:text-red-300 dark:hover:bg-red-900/40" data-i18n="nav.logout">Logout</button>
</form>
</div>
</div>

View File

@ -1,35 +1,35 @@
{{define "content"}}
<section class="space-y-6">
<h1 class="text-3xl font-bold text-gray-900" data-i18n="audit.title">Audit Logs</h1>
<h1 class="text-3xl font-bold text-gray-900 dark:text-white" data-i18n="audit.title">Audit Logs</h1>
<div class="mb-4 border-b border-gray-200">
<div class="mb-4 border-b border-gray-200 dark:border-gray-700">
<ul class="-mb-px flex flex-wrap text-center text-sm font-medium" id="audit-tab" data-tabs-toggle="#audit-tab-content" role="tablist">
<li class="me-2" role="presentation">
<button class="inline-block rounded-t-lg border-b-2 p-4" id="activity-tab" data-tabs-target="#activity" type="button" role="tab" aria-controls="activity" aria-selected="true" data-i18n="audit.activity">Activity</button>
<button class="inline-block rounded-t-lg border-b-2 p-4 dark:text-gray-200" id="activity-tab" data-tabs-target="#activity" type="button" role="tab" aria-controls="activity" aria-selected="true" data-i18n="audit.activity">Activity</button>
</li>
<li class="me-2" role="presentation">
<button class="inline-block rounded-t-lg border-b-2 p-4" id="security-tab" data-tabs-target="#security" type="button" role="tab" aria-controls="security" aria-selected="false" data-i18n="audit.security">Security</button>
<button class="inline-block rounded-t-lg border-b-2 p-4 dark:text-gray-200" id="security-tab" data-tabs-target="#security" type="button" role="tab" aria-controls="security" aria-selected="false" data-i18n="audit.security">Security</button>
</li>
</ul>
</div>
<div id="audit-tab-content">
<div class="hidden rounded-lg border border-gray-200 bg-white p-4 shadow-sm" id="activity" role="tabpanel" aria-labelledby="activity-tab">
<div class="hidden rounded-lg border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-700 dark:bg-gray-800" id="activity" role="tabpanel" aria-labelledby="activity-tab">
<div class="relative overflow-x-auto">
<table class="w-full text-left text-sm text-gray-500">
<thead class="bg-gray-50 text-xs uppercase text-gray-700">
<table class="w-full text-left text-sm text-gray-500 dark:text-gray-400">
<thead class="bg-gray-50 text-xs uppercase text-gray-700 dark:bg-gray-700 dark:text-gray-300">
<tr>
<th class="px-6 py-3" data-i18n="audit.timestamp">Timestamp</th>
<th class="px-6 py-3" data-i18n="audit.actor">Actor</th>
<th class="px-6 py-3" data-i18n="audit.action">Action</th>
</tr>
</thead>
<tbody><tr class="border-b bg-white"><td class="px-6 py-4">-</td><td class="px-6 py-4">-</td><td class="px-6 py-4">-</td></tr></tbody>
<tbody><tr class="border-b bg-white dark:border-gray-700 dark:bg-gray-800"><td class="px-6 py-4">-</td><td class="px-6 py-4">-</td><td class="px-6 py-4">-</td></tr></tbody>
</table>
</div>
</div>
<div class="hidden rounded-lg border border-gray-200 bg-white p-4 shadow-sm" id="security" role="tabpanel" aria-labelledby="security-tab">
<p class="text-sm text-gray-600" data-i18n="audit.placeholder">Security logs placeholder.</p>
<div class="hidden rounded-lg border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-700 dark:bg-gray-800" id="security" role="tabpanel" aria-labelledby="security-tab">
<p class="text-sm text-gray-600 dark:text-gray-300" data-i18n="audit.placeholder">Security logs placeholder.</p>
</div>
</div>
</section>

View File

@ -1,17 +1,17 @@
{{define "content"}}
<section class="space-y-6">
<div>
<h1 class="text-3xl font-bold text-gray-900" data-i18n="admin.dashboard.title">Admin Dashboard</h1>
<p class="text-gray-600" data-i18n="admin.dashboard.area">Area amministrazione.</p>
<h1 class="text-3xl font-bold text-gray-900 dark:text-white" data-i18n="admin.dashboard.title">Admin Dashboard</h1>
<p class="text-gray-600 dark:text-gray-300" data-i18n="admin.dashboard.area">Area amministrazione.</p>
</div>
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
<article class="rounded-lg border border-gray-200 bg-white p-6 shadow-sm">
<p class="text-sm font-medium text-gray-500" data-i18n="admin.users_count">Utenti</p>
<p class="mt-2 text-3xl font-semibold text-gray-900">{{if .PageData}}{{.PageData.Total}}{{else}}-{{end}}</p>
<article class="rounded-lg border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-700 dark:bg-gray-800">
<p class="text-sm font-medium text-gray-500 dark:text-gray-400" data-i18n="admin.users_count">Utenti</p>
<p class="mt-2 text-3xl font-semibold text-gray-900 dark:text-white">{{if .PageData}}{{.PageData.Total}}{{else}}-{{end}}</p>
</article>
<article class="rounded-lg border border-gray-200 bg-white p-6 shadow-sm">
<p class="text-sm font-medium text-gray-500" data-i18n="admin.current_role">Ruolo corrente</p>
<article class="rounded-lg border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-700 dark:bg-gray-800">
<p class="text-sm font-medium text-gray-500 dark:text-gray-400" data-i18n="admin.current_role">Ruolo corrente</p>
<p class="mt-2">
{{if and .CurrentUser (eq .CurrentUser.Role "admin")}}
<span class="rounded-sm bg-red-100 px-2.5 py-0.5 text-xs font-medium text-red-800" data-i18n="user.role_admin">admin</span>
@ -20,8 +20,8 @@
{{end}}
</p>
</article>
<article class="rounded-lg border border-gray-200 bg-white p-6 shadow-sm">
<p class="text-sm font-medium text-gray-500" data-i18n="admin.navigation">Navigazione</p>
<article class="rounded-lg border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-700 dark:bg-gray-800">
<p class="text-sm font-medium text-gray-500 dark:text-gray-400" data-i18n="admin.navigation">Navigazione</p>
<a href="/admin/users" class="mt-2 inline-flex rounded-lg bg-blue-700 px-4 py-2 text-sm font-medium text-white hover:bg-blue-800" data-i18n="admin.manage_users">Gestione utenti</a>
</article>
</div>

View File

@ -1,8 +1,8 @@
{{define "content"}}
<section class="space-y-4">
<h1 class="text-3xl font-bold text-gray-900" data-i18n="users.title">Admin Users</h1>
<div class="rounded-lg border border-gray-200 bg-white p-4 shadow-sm">
<p class="text-gray-600" data-i18n="users.new_user_modal_placeholder">Template pagina utenti admin in stile Flowbite.</p>
<h1 class="text-3xl font-bold text-gray-900 dark:text-white" data-i18n="users.title">Admin Users</h1>
<div class="rounded-lg border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-700 dark:bg-gray-800">
<p class="text-gray-600 dark:text-gray-300" data-i18n="users.new_user_modal_placeholder">Template pagina utenti admin in stile Flowbite.</p>
</div>
</section>
{{end}}

View File

@ -1,11 +1,11 @@
{{define "users_modal"}}
<div class="grid gap-3 text-sm text-gray-700 sm:grid-cols-2">
<div class="grid gap-3 text-sm text-gray-700 dark:text-gray-200 sm:grid-cols-2">
<div>
<span class="font-semibold text-gray-900" data-i18n="table.id">ID</span>:
<span class="font-semibold text-gray-900 dark:text-white" data-i18n="table.id">ID</span>:
<span>{{.User.ID}}</span>
</div>
<div>
<span class="font-semibold text-gray-900" data-i18n="table.role">Role</span>:
<span class="font-semibold text-gray-900 dark:text-white" data-i18n="table.role">Role</span>:
{{if eq .User.Role "admin"}}
<span class="rounded-sm bg-red-100 px-2.5 py-0.5 text-xs font-medium text-red-800" data-i18n="user.role_admin">admin</span>
{{else}}
@ -13,19 +13,19 @@
{{end}}
</div>
<div class="sm:col-span-2">
<span class="font-semibold text-gray-900" data-i18n="table.name">Name</span>:
<span class="font-semibold text-gray-900 dark:text-white" data-i18n="table.name">Name</span>:
<span>{{if .User.Name}}{{.User.Name}}{{else}}-{{end}}</span>
</div>
<div class="sm:col-span-2">
<span class="font-semibold text-gray-900" data-i18n="table.email">Email</span>:
<span class="font-semibold text-gray-900 dark:text-white" data-i18n="table.email">Email</span>:
<span>{{.User.Email}}</span>
</div>
<div>
<span class="font-semibold text-gray-900" data-i18n="user.verified">Verified</span>:
<span class="font-semibold text-gray-900 dark:text-white" data-i18n="user.verified">Verified</span>:
<span>{{if .User.EmailVerified}}<span data-i18n="user.yes">yes</span>{{else}}<span data-i18n="user.no">no</span>{{end}}</span>
</div>
<div>
<span class="font-semibold text-gray-900" data-i18n="user.created">Created</span>:
<span class="font-semibold text-gray-900 dark:text-white" data-i18n="user.created">Created</span>:
<span data-localize-date="{{.User.CreatedAt.Format "2006-01-02T15:04:05Z07:00"}}">{{.User.CreatedAt}}</span>
</div>
</div>

View File

@ -1,8 +1,8 @@
{{define "users_table"}}
{{ $p := .PageData }}
<div class="relative overflow-x-auto">
<table class="w-full text-left text-sm text-gray-500 rtl:text-right">
<thead class="bg-gray-50 text-xs uppercase text-gray-700">
<table class="w-full text-left text-sm text-gray-500 rtl:text-right dark:text-gray-400">
<thead class="bg-gray-50 text-xs uppercase text-gray-700 dark:bg-gray-700 dark:text-gray-300">
<tr>
<th scope="col" class="px-6 py-3">
<button type="button" class="inline-flex items-center gap-1 hover:text-blue-700" hx-get="/admin/users/table?q={{$p.Q}}&sort=id&dir={{if and (eq $p.Sort "id") (eq $p.Dir "asc")}}desc{{else}}asc{{end}}&page=1&pageSize={{$p.PageSize}}" hx-target="#usersTableContainer" hx-swap="innerHTML" data-i18n="table.id">ID</button>
@ -19,9 +19,9 @@
</thead>
<tbody>
{{range $u := $p.Users}}
<tr class="border-b bg-white hover:bg-gray-50">
<tr class="border-b bg-white hover:bg-gray-50 dark:border-gray-700 dark:bg-gray-800 dark:hover:bg-gray-700/60">
<td class="px-6 py-4">{{$u.ID}}</td>
<td class="px-6 py-4 font-medium text-gray-900">{{if $u.Name}}{{$u.Name}}{{else}}-{{end}}</td>
<td class="px-6 py-4 font-medium text-gray-900 dark:text-white">{{if $u.Name}}{{$u.Name}}{{else}}-{{end}}</td>
<td class="px-6 py-4">{{$u.Email}}</td>
<td class="px-6 py-4">
{{if eq $u.Role "admin"}}
@ -35,8 +35,8 @@
</td>
</tr>
{{else}}
<tr class="bg-white">
<td colspan="5" class="px-6 py-4 text-center text-gray-500" data-i18n="users.none">Nessun utente trovato.</td>
<tr class="bg-white dark:bg-gray-800">
<td colspan="5" class="px-6 py-4 text-center text-gray-500 dark:text-gray-400" data-i18n="users.none">Nessun utente trovato.</td>
</tr>
{{end}}
</tbody>
@ -44,10 +44,10 @@
</div>
<div class="mt-4 flex flex-wrap items-center justify-between gap-3">
<div class="text-sm text-gray-600"><span data-i18n="users.total">Totale</span>: {{$p.Total}} <span data-i18n="users.users_label">utenti</span>. <span data-i18n="users.page">Pagina</span> {{$p.Page}}{{if gt $p.TotalPages 0}} / {{$p.TotalPages}}{{end}}</div>
<div class="text-sm text-gray-600 dark:text-gray-300"><span data-i18n="users.total">Totale</span>: {{$p.Total}} <span data-i18n="users.users_label">utenti</span>. <span data-i18n="users.page">Pagina</span> {{$p.Page}}{{if gt $p.TotalPages 0}} / {{$p.TotalPages}}{{end}}</div>
<div class="inline-flex gap-2">
<button type="button" class="rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-900 hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-50" {{if not $p.HasPrev}}disabled{{end}} hx-get="/admin/users/table?q={{$p.Q}}&sort={{$p.Sort}}&dir={{$p.Dir}}&page={{$p.PrevPage}}&pageSize={{$p.PageSize}}" hx-target="#usersTableContainer" hx-swap="innerHTML" data-i18n="users.prev">Prev</button>
<button type="button" class="rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-900 hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-50" {{if not $p.HasNext}}disabled{{end}} hx-get="/admin/users/table?q={{$p.Q}}&sort={{$p.Sort}}&dir={{$p.Dir}}&page={{$p.NextPage}}&pageSize={{$p.PageSize}}" hx-target="#usersTableContainer" hx-swap="innerHTML" data-i18n="users.next">Next</button>
<button type="button" class="rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-900 hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100 dark:hover:bg-gray-700" {{if not $p.HasPrev}}disabled{{end}} hx-get="/admin/users/table?q={{$p.Q}}&sort={{$p.Sort}}&dir={{$p.Dir}}&page={{$p.PrevPage}}&pageSize={{$p.PageSize}}" hx-target="#usersTableContainer" hx-swap="innerHTML" data-i18n="users.prev">Prev</button>
<button type="button" class="rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-900 hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100 dark:hover:bg-gray-700" {{if not $p.HasNext}}disabled{{end}} hx-get="/admin/users/table?q={{$p.Q}}&sort={{$p.Sort}}&dir={{$p.Dir}}&page={{$p.NextPage}}&pageSize={{$p.PageSize}}" hx-target="#usersTableContainer" hx-swap="innerHTML" data-i18n="users.next">Next</button>
</div>
</div>
{{end}}

View File

@ -2,22 +2,22 @@
<section class="space-y-6">
<div class="flex flex-wrap items-center justify-between gap-3">
<div>
<h1 class="text-3xl font-bold text-gray-900" data-i18n="users.title">Users</h1>
<p class="text-gray-600" data-i18n="users.subtitle">Ricerca, ordinamento e paging server-side via HTMX.</p>
<h1 class="text-3xl font-bold text-gray-900 dark:text-white" data-i18n="users.title">Users</h1>
<p class="text-gray-600 dark:text-gray-300" data-i18n="users.subtitle">Ricerca, ordinamento e paging server-side via HTMX.</p>
</div>
<button type="button" data-modal-target="newUserModal" data-modal-toggle="newUserModal" class="inline-flex items-center rounded-lg bg-blue-700 px-5 py-2.5 text-sm font-medium text-white hover:bg-blue-800 focus:outline-none focus:ring-4 focus:ring-blue-300" data-i18n="users.new_user">
Nuovo Utente
</button>
</div>
<form id="usersFilters" class="grid gap-3 rounded-lg border border-gray-200 bg-white p-4 shadow-sm md:grid-cols-4" hx-get="/admin/users/table" hx-target="#usersTableContainer" hx-swap="innerHTML">
<form id="usersFilters" class="grid gap-3 rounded-lg border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-700 dark:bg-gray-800 md:grid-cols-4" hx-get="/admin/users/table" hx-target="#usersTableContainer" hx-swap="innerHTML">
<div class="md:col-span-2">
<label for="users-q" class="mb-2 block text-sm font-medium text-gray-900" data-i18n="users.search">Search</label>
<input id="users-q" type="text" name="q" placeholder="Cerca nome o email" data-i18n-placeholder="users.search_placeholder" value="{{.PageData.Q}}" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500">
<label for="users-q" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white" data-i18n="users.search">Search</label>
<input id="users-q" type="text" name="q" placeholder="Cerca nome o email" data-i18n-placeholder="users.search_placeholder" value="{{.PageData.Q}}" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400">
</div>
<div>
<label for="users-size" class="mb-2 block text-sm font-medium text-gray-900" data-i18n="users.page_size">Page size</label>
<input id="users-size" type="number" name="pageSize" min="1" max="100" value="{{.PageData.PageSize}}" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500">
<label for="users-size" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white" data-i18n="users.page_size">Page size</label>
<input id="users-size" type="number" name="pageSize" min="1" max="100" value="{{.PageData.PageSize}}" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400">
</div>
<div class="flex items-end">
<button type="submit" class="w-full rounded-lg bg-blue-700 px-5 py-2.5 text-sm font-medium text-white hover:bg-blue-800 focus:outline-none focus:ring-4 focus:ring-blue-300" data-i18n="users.search_button">Cerca</button>
@ -27,17 +27,17 @@
<input type="hidden" name="page" value="1">
</form>
<div id="usersTableContainer" class="rounded-lg border border-gray-200 bg-white p-2 shadow-sm md:p-4" hx-get="/admin/users/table?q={{.PageData.Q}}&sort={{.PageData.Sort}}&dir={{.PageData.Dir}}&page={{.PageData.Page}}&pageSize={{.PageData.PageSize}}" hx-trigger="load" hx-swap="innerHTML">
<div id="usersTableContainer" class="rounded-lg border border-gray-200 bg-white p-2 shadow-sm dark:border-gray-700 dark:bg-gray-800 md:p-4" hx-get="/admin/users/table?q={{.PageData.Q}}&sort={{.PageData.Sort}}&dir={{.PageData.Dir}}&page={{.PageData.Page}}&pageSize={{.PageData.PageSize}}" hx-trigger="load" hx-swap="innerHTML">
{{template "users_table" .}}
</div>
</section>
<div id="userModal" tabindex="-1" aria-hidden="true" class="fixed left-0 right-0 top-0 z-50 hidden h-[calc(100%-1rem)] max-h-full w-full items-center justify-center overflow-y-auto overflow-x-hidden p-4 md:inset-0">
<div class="relative max-h-full w-full max-w-2xl">
<div class="relative rounded-lg bg-white shadow-sm">
<div class="flex items-start justify-between rounded-t border-b p-4 md:p-5">
<h3 class="text-xl font-semibold text-gray-900" data-i18n="users.user_detail">Dettaglio utente</h3>
<button type="button" class="ms-auto inline-flex h-8 w-8 items-center justify-center rounded-lg bg-transparent text-sm text-gray-400 hover:bg-gray-200 hover:text-gray-900" data-modal-hide="userModal" aria-label="Close modal">
<div class="relative rounded-lg bg-white shadow-sm dark:bg-gray-800">
<div class="flex items-start justify-between rounded-t border-b p-4 dark:border-gray-700 md:p-5">
<h3 class="text-xl font-semibold text-gray-900 dark:text-white" data-i18n="users.user_detail">Dettaglio utente</h3>
<button type="button" class="ms-auto inline-flex h-8 w-8 items-center justify-center rounded-lg bg-transparent text-sm text-gray-400 hover:bg-gray-200 hover:text-gray-900 dark:hover:bg-gray-700 dark:hover:text-white" data-modal-hide="userModal" aria-label="Close modal">
<span class="sr-only" data-i18n="users.close">Close modal</span>
<svg class="h-3 w-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" />
@ -51,10 +51,10 @@
<div id="newUserModal" tabindex="-1" aria-hidden="true" class="fixed left-0 right-0 top-0 z-50 hidden h-[calc(100%-1rem)] max-h-full w-full items-center justify-center overflow-y-auto overflow-x-hidden p-4 md:inset-0">
<div class="relative max-h-full w-full max-w-xl">
<div class="relative rounded-lg bg-white shadow-sm">
<div class="flex items-start justify-between rounded-t border-b p-4 md:p-5">
<h3 class="text-xl font-semibold text-gray-900" data-i18n="users.new_user_modal_title">Nuovo utente</h3>
<button type="button" class="ms-auto inline-flex h-8 w-8 items-center justify-center rounded-lg bg-transparent text-sm text-gray-400 hover:bg-gray-200 hover:text-gray-900" data-modal-hide="newUserModal" aria-label="Close modal">
<div class="relative rounded-lg bg-white shadow-sm dark:bg-gray-800">
<div class="flex items-start justify-between rounded-t border-b p-4 dark:border-gray-700 md:p-5">
<h3 class="text-xl font-semibold text-gray-900 dark:text-white" data-i18n="users.new_user_modal_title">Nuovo utente</h3>
<button type="button" class="ms-auto inline-flex h-8 w-8 items-center justify-center rounded-lg bg-transparent text-sm text-gray-400 hover:bg-gray-200 hover:text-gray-900 dark:hover:bg-gray-700 dark:hover:text-white" data-modal-hide="newUserModal" aria-label="Close modal">
<span class="sr-only" data-i18n="users.close">Close modal</span>
<svg class="h-3 w-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" />
@ -62,10 +62,10 @@
</button>
</div>
<div class="space-y-4 p-4 md:p-5">
<p class="text-sm text-gray-600" data-i18n="users.new_user_modal_placeholder">Placeholder UI Flowbite. La creazione utente può essere collegata a una route backend quando disponibile.</p>
<p class="text-sm text-gray-600 dark:text-gray-300" data-i18n="users.new_user_modal_placeholder">Placeholder UI Flowbite. La creazione utente può essere collegata a una route backend quando disponibile.</p>
<div>
<label for="new-user-email" class="mb-2 block text-sm font-medium text-gray-900" data-i18n="form.email">Email</label>
<input id="new-user-email" type="email" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900" placeholder="name@company.com" disabled>
<label for="new-user-email" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white" data-i18n="form.email">Email</label>
<input id="new-user-email" type="email" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400" placeholder="name@company.com" disabled>
</div>
</div>
</div>

View File

@ -1,19 +1,19 @@
{{define "flowbite_navbar"}}
<nav class="border-gray-200 bg-white">
<nav class="border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-900">
<div class="mx-auto flex max-w-screen-xl flex-wrap items-center justify-between p-4">
<a href="#" class="flex items-center space-x-3 rtl:space-x-reverse">
<span class="self-center whitespace-nowrap text-2xl font-semibold">Trustcontact</span>
</a>
<button data-collapse-toggle="navbar-default" type="button" class="inline-flex h-10 w-10 items-center justify-center rounded-lg p-2 text-sm text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 md:hidden" aria-controls="navbar-default" aria-expanded="false">
<button data-collapse-toggle="navbar-default" type="button" class="inline-flex h-10 w-10 items-center justify-center rounded-lg p-2 text-sm text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-700 md:hidden" aria-controls="navbar-default" aria-expanded="false">
<span class="sr-only">Open main menu</span>
<svg class="h-5 w-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h15M1 7h15M1 13h15"/>
</svg>
</button>
<div class="hidden w-full md:block md:w-auto" id="navbar-default">
<ul class="mt-4 flex flex-col rounded-lg border border-gray-100 bg-gray-50 p-4 font-medium md:mt-0 md:flex-row md:space-x-8 md:border-0 md:bg-white md:p-0 rtl:space-x-reverse">
<ul class="mt-4 flex flex-col rounded-lg border border-gray-100 bg-gray-50 p-4 font-medium md:mt-0 md:flex-row md:space-x-8 md:border-0 md:bg-white md:p-0 rtl:space-x-reverse dark:border-gray-700 dark:bg-gray-800 md:dark:bg-gray-900">
<li><a href="#" class="block rounded-sm bg-blue-700 px-3 py-2 text-white md:bg-transparent md:p-0 md:text-blue-700" aria-current="page">Home</a></li>
<li><a href="#" class="block rounded-sm px-3 py-2 text-gray-900 hover:bg-gray-100 md:p-0 md:hover:bg-transparent md:hover:text-blue-700">About</a></li>
<li><a href="#" class="block rounded-sm px-3 py-2 text-gray-900 hover:bg-gray-100 md:p-0 md:hover:bg-transparent md:hover:text-blue-700 dark:text-gray-100 dark:hover:bg-gray-700 md:dark:hover:bg-transparent">About</a></li>
</ul>
</div>
</div>

View File

@ -4,11 +4,12 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{.Title}}</title>
<script src="/static/vendor/theme.js"></script>
<link rel="stylesheet" href="/static/css/app.css?v={{.BuildHash}}">
<script src="/static/vendor/htmx.min.js"></script>
<script src="/static/vendor/flowbite.js"></script>
</head>
<body class="flex min-h-screen flex-col bg-gray-50 text-gray-900 antialiased">
<body class="flex min-h-screen flex-col bg-white text-gray-900 antialiased dark:bg-gray-900 dark:text-gray-100">
{{template "navbar" .}}
<main class="mx-auto w-full max-w-7xl flex-1 p-6">
@ -16,8 +17,13 @@
{{template "content" .}}
</main>
<footer class="border-t border-gray-200 bg-white">
<div class="mx-auto max-w-7xl px-6 py-4 text-sm text-gray-500">Trustcontact</div>
<footer class="border-t border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-900">
<div class="mx-auto flex max-w-7xl items-center justify-between gap-3 px-6 py-4 text-sm text-gray-500 dark:text-gray-400">
<span>Trustcontact</span>
<button id="themeToggle" type="button" aria-label="Toggle dark mode" aria-pressed="false" onclick="window.toggleTheme && window.toggleTheme()" class="rounded-lg bg-gray-100 px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-800 dark:text-gray-100 dark:hover:bg-gray-700">
Dark mode
</button>
</div>
</footer>
<script>
@ -217,9 +223,15 @@
reinitFlowbiteComponents();
applyTranslations(document);
if (typeof window.initThemeToggle === 'function') {
window.initThemeToggle();
}
document.body.addEventListener('htmx:afterSwap', function (evt) {
reinitFlowbiteComponents(evt.target || null);
applyTranslations(evt.target || document);
if (typeof window.initThemeToggle === 'function') {
window.initThemeToggle();
}
});
})();
</script>

View File

@ -1,18 +1,18 @@
{{define "language_dropdown"}}
<div class="relative flex items-center gap-2">
<img id="lang-flag" class="rounded object-cover" src="/static/vendor/flags/it.svg" alt="Italiano" style="width:48px;height:32px;">
<button id="lang-menu-button" data-dropdown-toggle="lang-dropdown" type="button" class="inline-flex h-10 items-center rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100 focus:outline-none focus:ring-4 focus:ring-gray-200" aria-expanded="false">
<button id="lang-menu-button" data-dropdown-toggle="lang-dropdown" type="button" class="inline-flex h-10 items-center rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100 dark:hover:bg-gray-700 dark:focus:ring-gray-700" aria-expanded="false">
<span id="lang-current" class="inline-block min-w-[95px]">Italiano</span>
</button>
<div id="lang-dropdown" class="z-50 my-2 hidden w-40 list-none divide-y divide-gray-100 rounded-lg bg-white text-sm shadow-sm">
<div id="lang-dropdown" class="z-50 my-2 hidden w-40 list-none divide-y divide-gray-100 rounded-lg bg-white text-sm shadow-sm dark:divide-gray-700 dark:bg-gray-800">
<ul class="py-1" aria-labelledby="lang-menu-button">
<li><button type="button" class="flex w-full items-center gap-2 px-4 py-2 text-left hover:bg-gray-100" data-lang-select="it"><div class="flex w-8 shrink-0 items-center justify-center"><img class="flag-lang rounded-sm object-cover" src="/static/vendor/flags/it.svg" alt=""></div><span class="leading-none">Italiano</span></button></li>
<li><button type="button" class="flex w-full items-center gap-2 px-4 py-2 text-left hover:bg-gray-100" data-lang-select="en"><div class="flex w-8 shrink-0 items-center justify-center"><img class="flag-lang rounded-sm object-cover" src="/static/vendor/flags/en.svg" alt=""></div><span class="leading-none">English</span></button></li>
<li><button type="button" class="flex w-full items-center gap-2 px-4 py-2 text-left hover:bg-gray-100" data-lang-select="en_us"><div class="flex w-8 shrink-0 items-center justify-center"><img class="flag-lang rounded-sm object-cover" src="/static/vendor/flags/en_us.svg" alt=""></div><span class="leading-none">English USA</span></button></li>
<li><button type="button" class="flex w-full items-center gap-2 px-4 py-2 text-left hover:bg-gray-100" data-lang-select="de"><div class="flex w-8 shrink-0 items-center justify-center"><img class="flag-lang rounded-sm object-cover" src="/static/vendor/flags/de.svg" alt=""></div><span class="leading-none">Deutsch</span></button></li>
<li><button type="button" class="flex w-full items-center gap-2 px-4 py-2 text-left hover:bg-gray-100" data-lang-select="de_ch"><div class="flex w-8 shrink-0 items-center justify-center"><img class="flag-lang-ch rounded-sm object-cover" src="/static/vendor/flags/ch.svg" alt=""></div><span class="leading-none">Deutsch CH</span></button></li>
<li><button type="button" class="flex w-full items-center gap-2 px-4 py-2 text-left hover:bg-gray-100" data-lang-select="fr"><div class="flex w-8 shrink-0 items-center justify-center"><img class="flag-lang rounded-sm object-cover" src="/static/vendor/flags/fr.svg" alt=""></div><span class="leading-none">Français</span></button></li>
<li><button type="button" class="flex w-full items-center gap-2 px-4 py-2 text-left hover:bg-gray-100" data-lang-select="fr_ch"><div class="flex w-8 shrink-0 items-center justify-center"><img class="flag-lang-ch rounded-sm object-cover" src="/static/vendor/flags/ch.svg" alt=""></div><span class="leading-none">Français CH</span></button></li>
<li><button type="button" class="flex w-full items-center gap-2 px-4 py-2 text-left text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700" data-lang-select="it"><div class="flex w-8 shrink-0 items-center justify-center"><img class="flag-lang rounded-sm object-cover" src="/static/vendor/flags/it.svg" alt=""></div><span class="leading-none">Italiano</span></button></li>
<li><button type="button" class="flex w-full items-center gap-2 px-4 py-2 text-left text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700" data-lang-select="en"><div class="flex w-8 shrink-0 items-center justify-center"><img class="flag-lang rounded-sm object-cover" src="/static/vendor/flags/en.svg" alt=""></div><span class="leading-none">English</span></button></li>
<li><button type="button" class="flex w-full items-center gap-2 px-4 py-2 text-left text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700" data-lang-select="en_us"><div class="flex w-8 shrink-0 items-center justify-center"><img class="flag-lang rounded-sm object-cover" src="/static/vendor/flags/en_us.svg" alt=""></div><span class="leading-none">English USA</span></button></li>
<li><button type="button" class="flex w-full items-center gap-2 px-4 py-2 text-left text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700" data-lang-select="de"><div class="flex w-8 shrink-0 items-center justify-center"><img class="flag-lang rounded-sm object-cover" src="/static/vendor/flags/de.svg" alt=""></div><span class="leading-none">Deutsch</span></button></li>
<li><button type="button" class="flex w-full items-center gap-2 px-4 py-2 text-left text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700" data-lang-select="de_ch"><div class="flex w-8 shrink-0 items-center justify-center"><img class="flag-lang-ch rounded-sm object-cover" src="/static/vendor/flags/ch.svg" alt=""></div><span class="leading-none">Deutsch CH</span></button></li>
<li><button type="button" class="flex w-full items-center gap-2 px-4 py-2 text-left text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700" data-lang-select="fr"><div class="flex w-8 shrink-0 items-center justify-center"><img class="flag-lang rounded-sm object-cover" src="/static/vendor/flags/fr.svg" alt=""></div><span class="leading-none">Français</span></button></li>
<li><button type="button" class="flex w-full items-center gap-2 px-4 py-2 text-left text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700" data-lang-select="fr_ch"><div class="flex w-8 shrink-0 items-center justify-center"><img class="flag-lang-ch rounded-sm object-cover" src="/static/vendor/flags/ch.svg" alt=""></div><span class="leading-none">Français CH</span></button></li>
</ul>
</div>
</div>

View File

@ -1,11 +1,11 @@
{{define "navbar"}}
<nav class="border-b border-gray-200 bg-white">
<nav class="border-b border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-900">
<div class="mx-auto flex max-w-7xl flex-wrap items-center justify-between p-4">
<a href="/" class="flex items-center space-x-3 rtl:space-x-reverse">
<span class="self-center whitespace-nowrap text-xl font-semibold">Trustcontact</span>
</a>
<button data-collapse-toggle="navbar-main" type="button" class="inline-flex h-10 w-10 items-center justify-center rounded-lg p-2 text-sm text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 md:hidden" aria-controls="navbar-main" aria-expanded="false">
<button data-collapse-toggle="navbar-main" type="button" class="inline-flex h-10 w-10 items-center justify-center rounded-lg p-2 text-sm text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-700 md:hidden" aria-controls="navbar-main" aria-expanded="false">
<span class="sr-only" data-i18n="nav.open_main_menu">Apri menu principale</span>
<svg class="h-5 w-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h15M1 7h15M1 13h15" />
@ -13,8 +13,8 @@
</button>
<div class="hidden w-full items-center justify-between md:order-1 md:flex md:w-auto" id="navbar-main">
<ul class="mt-4 flex flex-col gap-2 rounded-lg border border-gray-100 bg-gray-50 p-4 text-sm font-medium md:mt-0 md:flex-row md:items-center md:gap-1 md:border-0 md:bg-transparent md:p-0">
<li><a href="/welcome" class="block rounded-lg px-3 py-2 text-gray-700 hover:bg-gray-100">Welcome</a></li>
<ul class="mt-4 flex flex-col gap-2 rounded-lg border border-gray-100 bg-gray-50 p-4 text-sm font-medium md:mt-0 md:flex-row md:items-center md:gap-1 md:border-0 md:bg-transparent md:p-0 dark:border-gray-700 dark:bg-gray-800 md:dark:bg-transparent">
<li><a href="/welcome" class="block rounded-lg px-3 py-2 text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700">Welcome</a></li>
</ul>
<div class="mt-4 flex items-center gap-3 md:mt-0 md:ms-4">
@ -30,20 +30,20 @@
{{if .CurrentUser}}
<div class="relative">
<button type="button" class="flex items-center rounded-full bg-gray-800 text-sm focus:ring-4 focus:ring-gray-300" id="user-menu-button" aria-expanded="false" data-dropdown-toggle="user-dropdown" data-dropdown-placement="bottom">
<button type="button" class="flex items-center rounded-full bg-gray-800 text-sm focus:ring-4 focus:ring-gray-300 dark:bg-gray-700 dark:focus:ring-gray-700" id="user-menu-button" aria-expanded="false" data-dropdown-toggle="user-dropdown" data-dropdown-placement="bottom">
<span class="sr-only" data-i18n="nav.open_user_menu">Apri menu utente</span>
<span class="inline-flex h-9 w-9 items-center justify-center rounded-full bg-blue-600 font-semibold text-white">
{{if .CurrentUser.Name}}{{printf "%.1s" .CurrentUser.Name}}{{else}}{{printf "%.1s" .CurrentUser.Email}}{{end}}
</span>
</button>
<div class="z-50 my-4 hidden w-56 list-none divide-y divide-gray-100 rounded-lg bg-white text-base shadow-sm" id="user-dropdown">
<div class="z-50 my-4 hidden w-56 list-none divide-y divide-gray-100 rounded-lg bg-white text-base shadow-sm dark:divide-gray-700 dark:bg-gray-800" id="user-dropdown">
<div class="px-4 py-3">
<span class="block truncate text-sm text-gray-900">{{if .CurrentUser.Name}}{{.CurrentUser.Name}}{{else}}Utente{{end}}</span>
<span class="block truncate text-sm text-gray-500">{{.CurrentUser.Email}}</span>
<span class="block truncate text-sm text-gray-900 dark:text-gray-100">{{if .CurrentUser.Name}}{{.CurrentUser.Name}}{{else}}Utente{{end}}</span>
<span class="block truncate text-sm text-gray-500 dark:text-gray-400">{{.CurrentUser.Email}}</span>
</div>
<div class="py-2">
<form action="/logout" method="post" class="px-2">
<button type="submit" class="block w-full rounded-lg px-2 py-2 text-left text-sm text-red-700 hover:bg-red-50" data-i18n="nav.logout">Logout</button>
<button type="submit" class="block w-full rounded-lg px-2 py-2 text-left text-sm text-red-700 hover:bg-red-50 dark:text-red-300 dark:hover:bg-red-900/40" data-i18n="nav.logout">Logout</button>
</form>
</div>
</div>

View File

@ -1,20 +1,20 @@
{{define "content"}}
<section class="grid gap-6 md:grid-cols-3">
<article class="rounded-lg border border-gray-200 bg-white p-6 shadow-sm md:col-span-2">
<h1 class="mb-2 text-2xl font-bold text-gray-900">welcome</h1>
<article class="rounded-lg border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-700 dark:bg-gray-800 md:col-span-2">
<h1 class="mb-2 text-2xl font-bold text-gray-900 dark:text-white">welcome</h1>
{{if .CurrentUser}}
<p class="text-gray-600"><span data-i18n="welcome.back_prefix">Bentornato</span> {{if .CurrentUser.Name}}{{.CurrentUser.Name}}{{else}}{{.CurrentUser.Email}}{{end}}.</p>
<p class="text-gray-600 dark:text-gray-300"><span data-i18n="welcome.back_prefix">Bentornato</span> {{if .CurrentUser.Name}}{{.CurrentUser.Name}}{{else}}{{.CurrentUser.Email}}{{end}}.</p>
{{else}}
<p class="text-gray-600" data-i18n="welcome.generic">Benvenuto.</p>
<p class="text-gray-600 dark:text-gray-300" data-i18n="welcome.generic">Benvenuto.</p>
{{end}}
</article>
<article class="rounded-lg border border-gray-200 bg-white p-6 shadow-sm">
<h2 class="mb-3 text-lg font-semibold text-gray-900" data-i18n="welcome.quick_links">Quick Links</h2>
<article class="rounded-lg border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-700 dark:bg-gray-800">
<h2 class="mb-3 text-lg font-semibold text-gray-900 dark:text-white" data-i18n="welcome.quick_links">Quick Links</h2>
<div class="space-y-2">
<a href="/welcome" class="block rounded-lg px-3 py-2 text-sm text-gray-700 hover:bg-gray-100">welcome</a>
<a href="/welcome" class="block rounded-lg px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700">welcome</a>
{{if and .CurrentUser (eq .CurrentUser.Role "admin")}}
<a href="/admin/users" class="block rounded-lg px-3 py-2 text-sm text-gray-700 hover:bg-gray-100" data-i18n="nav.users">Users</a>
<a href="/admin/users" class="block rounded-lg px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700" data-i18n="nav.users">Users</a>
{{end}}
</div>
</article>

View File

@ -1,6 +1,6 @@
{{define "_flash.html"}}
{{if .FlashSuccess}}
<div class="mb-4 flex items-center rounded-lg border border-green-200 bg-green-50 p-4 text-green-800" role="alert">
<div class="mb-4 flex items-center rounded-lg border border-green-200 bg-green-50 p-4 text-green-800 dark:border-green-800 dark:bg-green-900/40 dark:text-green-300" role="alert">
<svg class="me-3 inline h-4 w-4 shrink-0" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
<path d="M10 0a10 10 0 1 0 10 10A10 10 0 0 0 10 0Zm3.707 8.707-4 4a1 1 0 0 1-1.414 0l-2-2 1.414-1.414L9 10.586l3.293-3.293Z"/>
</svg>
@ -8,7 +8,7 @@
</div>
{{end}}
{{if .FlashError}}
<div class="mb-4 flex items-center rounded-lg border border-red-200 bg-red-50 p-4 text-red-800" role="alert">
<div class="mb-4 flex items-center rounded-lg border border-red-200 bg-red-50 p-4 text-red-800 dark:border-red-800 dark:bg-red-900/40 dark:text-red-300" role="alert">
<svg class="me-3 inline h-4 w-4 shrink-0" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
<path d="M10 0a10 10 0 1 0 10 10A10 10 0 0 0 10 0Zm1 14H9v-2h2Zm0-4H9V5h2Z"/>
</svg>
@ -16,7 +16,7 @@
</div>
{{end}}
{{if .FlashWarning}}
<div class="mb-4 flex items-center rounded-lg border border-yellow-200 bg-yellow-50 p-4 text-yellow-800" role="alert">
<div class="mb-4 flex items-center rounded-lg border border-yellow-200 bg-yellow-50 p-4 text-yellow-800 dark:border-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-300" role="alert">
<svg class="me-3 inline h-4 w-4 shrink-0" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
<path d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l6.518 11.596c.75 1.334-.213 2.99-1.742 2.99H3.48c-1.53 0-2.492-1.656-1.743-2.99L8.257 3.1ZM11 13H9v2h2v-2Zm0-6H9v5h2V7Z"/>
</svg>

View File

@ -1,11 +1,11 @@
{{define "navbar"}}
<nav class="border-b border-gray-200 bg-white">
<nav class="border-b border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-900">
<div class="mx-auto flex max-w-7xl flex-wrap items-center justify-between p-4">
<a href="/" class="flex items-center space-x-3 rtl:space-x-reverse">
<span class="self-center whitespace-nowrap text-xl font-semibold">Trustcontact</span>
</a>
<button data-collapse-toggle="navbar-main" type="button" class="inline-flex h-10 w-10 items-center justify-center rounded-lg p-2 text-sm text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 md:hidden" aria-controls="navbar-main" aria-expanded="false">
<button data-collapse-toggle="navbar-main" type="button" class="inline-flex h-10 w-10 items-center justify-center rounded-lg p-2 text-sm text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-700 md:hidden" aria-controls="navbar-main" aria-expanded="false">
<span class="sr-only" data-i18n="nav.open_main_menu">Apri menu principale</span>
<svg class="h-5 w-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h15M1 7h15M1 13h15" />
@ -13,16 +13,16 @@
</button>
<div class="hidden w-full items-center justify-between md:order-1 md:flex md:w-auto" id="navbar-main">
<ul class="mt-4 flex flex-col gap-2 rounded-lg border border-gray-100 bg-gray-50 p-4 text-sm font-medium md:mt-0 md:flex-row md:items-center md:gap-1 md:border-0 md:bg-transparent md:p-0">
<ul class="mt-4 flex flex-col gap-2 rounded-lg border border-gray-100 bg-gray-50 p-4 text-sm font-medium md:mt-0 md:flex-row md:items-center md:gap-1 md:border-0 md:bg-transparent md:p-0 dark:border-gray-700 dark:bg-gray-800 md:dark:bg-transparent">
{{if eq .NavSection "home"}}
{{if .CurrentUser}}
<li><a href="/welcome" class="block rounded-lg px-3 py-2 text-gray-700 hover:bg-gray-100">Welcome</a></li>
<li><a href="/welcome" class="block rounded-lg px-3 py-2 text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700">Welcome</a></li>
{{else}}
<li><a href="/login" class="block rounded-lg px-3 py-2 text-gray-700 hover:bg-gray-100" data-i18n="nav.login">Login</a></li>
<li><a href="/login" class="block rounded-lg px-3 py-2 text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700" data-i18n="nav.login">Login</a></li>
{{end}}
{{else if not .CurrentUser}}
<li><a href="/login" class="block rounded-lg px-3 py-2 {{if eq .NavSection "login"}}bg-blue-100 text-blue-700{{else}}text-gray-700 hover:bg-gray-100{{end}}" data-i18n="nav.login">Login</a></li>
<li><a href="/signup" class="block rounded-lg px-3 py-2 {{if eq .NavSection "signup"}}bg-blue-100 text-blue-700{{else}}text-gray-700 hover:bg-gray-100{{end}}" data-i18n="nav.signup">Signup</a></li>
<li><a href="/login" class="block rounded-lg px-3 py-2 {{if eq .NavSection "login"}}bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300{{else}}text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700{{end}}" data-i18n="nav.login">Login</a></li>
<li><a href="/signup" class="block rounded-lg px-3 py-2 {{if eq .NavSection "signup"}}bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300{{else}}text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700{{end}}" data-i18n="nav.signup">Signup</a></li>
{{end}}
</ul>
@ -39,20 +39,20 @@
{{if .CurrentUser}}
<div class="relative">
<button type="button" class="flex items-center rounded-full bg-gray-800 text-sm focus:ring-4 focus:ring-gray-300" id="user-menu-button" aria-expanded="false" data-dropdown-toggle="user-dropdown" data-dropdown-placement="bottom">
<button type="button" class="flex items-center rounded-full bg-gray-800 text-sm focus:ring-4 focus:ring-gray-300 dark:bg-gray-700 dark:focus:ring-gray-700" id="user-menu-button" aria-expanded="false" data-dropdown-toggle="user-dropdown" data-dropdown-placement="bottom">
<span class="sr-only" data-i18n="nav.open_user_menu">Apri menu utente</span>
<span class="inline-flex h-9 w-9 items-center justify-center rounded-full bg-blue-600 font-semibold text-white">
{{if .CurrentUser.Name}}{{printf "%.1s" .CurrentUser.Name}}{{else}}{{printf "%.1s" .CurrentUser.Email}}{{end}}
</span>
</button>
<div class="z-50 my-4 hidden w-56 list-none divide-y divide-gray-100 rounded-lg bg-white text-base shadow-sm" id="user-dropdown">
<div class="z-50 my-4 hidden w-56 list-none divide-y divide-gray-100 rounded-lg bg-white text-base shadow-sm dark:divide-gray-700 dark:bg-gray-800" id="user-dropdown">
<div class="px-4 py-3">
<span class="block truncate text-sm text-gray-900">{{if .CurrentUser.Name}}{{.CurrentUser.Name}}{{else}}Utente{{end}}</span>
<span class="block truncate text-sm text-gray-500">{{.CurrentUser.Email}}</span>
<span class="block truncate text-sm text-gray-900 dark:text-gray-100">{{if .CurrentUser.Name}}{{.CurrentUser.Name}}{{else}}Utente{{end}}</span>
<span class="block truncate text-sm text-gray-500 dark:text-gray-400">{{.CurrentUser.Email}}</span>
</div>
<div class="py-2">
<form action="/logout" method="post" class="px-2">
<button type="submit" class="block w-full rounded-lg px-2 py-2 text-left text-sm text-red-700 hover:bg-red-50" data-i18n="nav.logout">Logout</button>
<button type="submit" class="block w-full rounded-lg px-2 py-2 text-left text-sm text-red-700 hover:bg-red-50 dark:text-red-300 dark:hover:bg-red-900/40" data-i18n="nav.logout">Logout</button>
</form>
</div>
</div>

View File

@ -1,8 +1,8 @@
{{define "content"}}
<div class="flex min-h-screen items-center justify-center">
<div class="w-full max-w-2xl rounded-lg border border-red-200 bg-white p-8 shadow-sm">
<h1 class="mb-3 text-2xl font-bold text-red-700">Accesso negato</h1>
<p class="mb-6 text-gray-700">Non hai i privilegi necessari per accedere a questa pagina.</p>
<div class="w-full max-w-2xl rounded-lg border border-red-200 bg-white p-8 shadow-sm dark:border-red-800 dark:bg-gray-800">
<h1 class="mb-3 text-2xl font-bold text-red-700 dark:text-red-300">Accesso negato</h1>
<p class="mb-6 text-gray-700 dark:text-gray-200">Non hai i privilegi necessari per accedere a questa pagina.</p>
<a href="/" class="inline-flex rounded-lg bg-blue-700 px-5 py-2.5 text-sm font-medium text-white hover:bg-blue-800">Torna alla home</a>
</div>
</div>

View File

@ -1,18 +1,18 @@
{{define "content"}}
<div class="flex min-h-screen items-center justify-center">
<div class="w-full max-w-md rounded-lg border border-gray-200 bg-white p-6 shadow-sm md:p-8">
<h1 class="mb-1 text-2xl font-bold text-gray-900" data-i18n="forgot.title">Forgot Password</h1>
<p class="mb-6 text-sm text-gray-500" data-i18n="forgot.subtitle">Inserisci la tua email per ricevere il link di reset.</p>
<div class="w-full max-w-md rounded-lg border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-700 dark:bg-gray-800 md:p-8">
<h1 class="mb-1 text-2xl font-bold text-gray-900 dark:text-white" data-i18n="forgot.title">Forgot Password</h1>
<p class="mb-6 text-sm text-gray-500 dark:text-gray-400" data-i18n="forgot.subtitle">Inserisci la tua email per ricevere il link di reset.</p>
<form action="/forgot-password" method="post" class="space-y-5">
<div>
<label for="forgot-email" class="mb-2 block text-sm font-medium text-gray-900" data-i18n="form.email">Email</label>
<input id="forgot-email" type="email" name="email" value="{{.Email}}" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500" required />
<label for="forgot-email" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white" data-i18n="form.email">Email</label>
<input id="forgot-email" type="email" name="email" value="{{.Email}}" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400" required />
</div>
<button type="submit" class="w-full rounded-lg bg-blue-700 px-5 py-2.5 text-center text-sm font-medium text-white hover:bg-blue-800 focus:outline-none focus:ring-4 focus:ring-blue-300" data-i18n="forgot.submit">Invia link reset</button>
<p class="text-center text-sm text-gray-600"><a href="/login" class="text-blue-700 hover:underline" data-i18n="forgot.back_login">Torna al login</a></p>
<p class="text-center text-sm text-gray-600 dark:text-gray-300"><a href="/login" class="text-blue-700 hover:underline dark:text-blue-400" data-i18n="forgot.back_login">Torna al login</a></p>
</form>
</div>
</div>

View File

@ -1,5 +1,5 @@
{{define "content"}}
<section class="rounded-lg border border-gray-200 bg-white p-8 shadow-sm">
<h1 class="text-3xl font-bold text-gray-900">Home Page</h1>
<section class="rounded-lg border border-gray-200 bg-white p-8 shadow-sm dark:border-gray-700 dark:bg-gray-800">
<h1 class="text-3xl font-bold text-gray-900 dark:text-white">Home Page</h1>
</section>
{{end}}

View File

@ -1,25 +1,25 @@
{{define "content"}}
<div class="flex min-h-screen items-center justify-center">
<div class="w-full max-w-md rounded-lg border border-gray-200 bg-white p-6 shadow-sm md:p-8">
<h1 class="mb-1 text-2xl font-bold text-gray-900" data-i18n="login.title">Login</h1>
<p class="mb-6 text-sm text-gray-500" data-i18n="login.subtitle">Accedi al tuo account.</p>
<div class="w-full max-w-md rounded-lg border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-700 dark:bg-gray-800 md:p-8">
<h1 class="mb-1 text-2xl font-bold text-gray-900 dark:text-white" data-i18n="login.title">Login</h1>
<p class="mb-6 text-sm text-gray-500 dark:text-gray-400" data-i18n="login.subtitle">Accedi al tuo account.</p>
<form action="/login" method="post" class="space-y-5">
<div>
<label for="email" class="mb-2 block text-sm font-medium text-gray-900" data-i18n="form.email">Email</label>
<input id="email" type="text" name="email" value="{{.Email}}" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500" required />
<label for="email" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white" data-i18n="form.email">Email</label>
<input id="email" type="text" name="email" value="{{.Email}}" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400" required />
</div>
<div>
<label for="password" class="mb-2 block text-sm font-medium text-gray-900" data-i18n="form.password">Password</label>
<input id="password" type="password" name="password" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500" required />
<label for="password" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white" data-i18n="form.password">Password</label>
<input id="password" type="password" name="password" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400" required />
</div>
<button type="submit" class="w-full rounded-lg bg-blue-700 px-5 py-2.5 text-center text-sm font-medium text-white hover:bg-blue-800 focus:outline-none focus:ring-4 focus:ring-blue-300" data-i18n="login.submit">Sign in</button>
<div class="flex items-center justify-between text-sm">
<a href="/forgot-password" class="text-blue-700 hover:underline" data-i18n="login.forgot">Forgot password?</a>
<a href="/signup" class="text-gray-600 hover:underline" data-i18n="login.create_account">Create account</a>
<a href="/signup" class="text-gray-600 hover:underline dark:text-gray-300" data-i18n="login.create_account">Create account</a>
</div>
</form>
</div>

View File

@ -1,20 +1,20 @@
{{define "content"}}
<div class="flex min-h-screen items-center justify-center">
<div class="w-full max-w-md rounded-lg border border-gray-200 bg-white p-6 shadow-sm md:p-8">
<h1 class="mb-1 text-2xl font-bold text-gray-900" data-i18n="reset.title">Reset Password</h1>
<p class="mb-6 text-sm text-gray-500" data-i18n="reset.subtitle">Imposta una nuova password.</p>
<div class="w-full max-w-md rounded-lg border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-700 dark:bg-gray-800 md:p-8">
<h1 class="mb-1 text-2xl font-bold text-gray-900 dark:text-white" data-i18n="reset.title">Reset Password</h1>
<p class="mb-6 text-sm text-gray-500 dark:text-gray-400" data-i18n="reset.subtitle">Imposta una nuova password.</p>
{{if .Token}}
<form action="/reset-password?token={{.Token}}" method="post" class="space-y-5">
<div>
<label for="reset-password" class="mb-2 block text-sm font-medium text-gray-900" data-i18n="reset.new_password">Nuova password</label>
<input id="reset-password" type="password" name="password" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500" required />
<label for="reset-password" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white" data-i18n="reset.new_password">Nuova password</label>
<input id="reset-password" type="password" name="password" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400" required />
</div>
<button type="submit" class="w-full rounded-lg bg-blue-700 px-5 py-2.5 text-center text-sm font-medium text-white hover:bg-blue-800 focus:outline-none focus:ring-4 focus:ring-blue-300" data-i18n="reset.submit">Aggiorna password</button>
</form>
{{else}}
<div class="rounded-lg border border-red-200 bg-red-50 p-4 text-sm text-red-800" role="alert" data-i18n="reset.invalid_token">Token mancante o non valido.</div>
<div class="rounded-lg border border-red-200 bg-red-50 p-4 text-sm text-red-800 dark:border-red-800 dark:bg-red-900/40 dark:text-red-300" role="alert" data-i18n="reset.invalid_token">Token mancante o non valido.</div>
{{end}}
</div>
</div>

View File

@ -1,23 +1,23 @@
{{define "content"}}
<div class="flex min-h-screen items-center justify-center">
<div class="w-full max-w-md rounded-lg border border-gray-200 bg-white p-6 shadow-sm md:p-8">
<h1 class="mb-1 text-2xl font-bold text-gray-900" data-i18n="signup.title">Signup</h1>
<p class="mb-6 text-sm text-gray-500" data-i18n="signup.subtitle">Crea il tuo account.</p>
<div class="w-full max-w-md rounded-lg border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-700 dark:bg-gray-800 md:p-8">
<h1 class="mb-1 text-2xl font-bold text-gray-900 dark:text-white" data-i18n="signup.title">Signup</h1>
<p class="mb-6 text-sm text-gray-500 dark:text-gray-400" data-i18n="signup.subtitle">Crea il tuo account.</p>
<form action="/signup" method="post" class="space-y-5">
<div>
<label for="signup-email" class="mb-2 block text-sm font-medium text-gray-900" data-i18n="form.email">Email</label>
<input id="signup-email" type="email" name="email" value="{{.Email}}" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500" required />
<label for="signup-email" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white" data-i18n="form.email">Email</label>
<input id="signup-email" type="email" name="email" value="{{.Email}}" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400" required />
</div>
<div>
<label for="signup-password" class="mb-2 block text-sm font-medium text-gray-900" data-i18n="form.password">Password</label>
<input id="signup-password" type="password" name="password" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500" required />
<label for="signup-password" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white" data-i18n="form.password">Password</label>
<input id="signup-password" type="password" name="password" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400" required />
</div>
<button type="submit" class="w-full rounded-lg bg-blue-700 px-5 py-2.5 text-center text-sm font-medium text-white hover:bg-blue-800 focus:outline-none focus:ring-4 focus:ring-blue-300" data-i18n="signup.submit">Sign up</button>
<p class="text-center text-sm text-gray-600"><span data-i18n="signup.has_account">Hai già un account?</span> <a href="/login" class="text-blue-700 hover:underline" data-i18n="signup.login">Accedi</a></p>
<p class="text-center text-sm text-gray-600 dark:text-gray-300"><span data-i18n="signup.has_account">Hai già un account?</span> <a href="/login" class="text-blue-700 hover:underline dark:text-blue-400" data-i18n="signup.login">Accedi</a></p>
</form>
</div>
</div>

View File

@ -1,8 +1,8 @@
{{define "content"}}
<section class="rounded-lg border border-blue-200 bg-blue-50 p-8 shadow-sm" role="status" aria-live="polite">
<h1 class="mb-2 text-2xl font-bold text-blue-900" data-i18n="verify.title">Verifica email</h1>
<p class="mb-2 text-blue-800" data-i18n="verify.p1">Controlla la casella di posta e apri il link di verifica ricevuto.</p>
<p class="mb-4 text-blue-800" data-i18n="verify.p2">Se il link è scaduto, ripeti la registrazione o contatta supporto.</p>
<section class="rounded-lg border border-blue-200 bg-blue-50 p-8 shadow-sm dark:border-blue-800 dark:bg-blue-900/30" role="status" aria-live="polite">
<h1 class="mb-2 text-2xl font-bold text-blue-900 dark:text-blue-100" data-i18n="verify.title">Verifica email</h1>
<p class="mb-2 text-blue-800 dark:text-blue-200" data-i18n="verify.p1">Controlla la casella di posta e apri il link di verifica ricevuto.</p>
<p class="mb-4 text-blue-800 dark:text-blue-200" data-i18n="verify.p2">Se il link è scaduto, ripeti la registrazione o contatta supporto.</p>
<a href="/login" class="inline-flex rounded-lg bg-blue-700 px-5 py-2.5 text-sm font-medium text-white hover:bg-blue-800" data-i18n="verify.go_login">Vai al login</a>
</section>
{{end}}