Area riservata: menu essenziale e veste grafica del sito
Il menu in alto si riduce alle voci che servono davvero — Articoli, Contenuti, Utenti, Sito, Esci — con la voce corrente evidenziata; ognuna resta visibile solo a chi ha il ruolo per aprirla, e in pagina di login la barra mostra il solo marchio. "Nuovo" esce dal menu perché il pulsante per creare un articolo è già in cima all'elenco Articoli. Il pannello smette di essere un foglio di stile a sé: adotta i font e la palette del sito, come Campus e Stress Index, con tabelle, pulsanti, campi e pillole di stato riportati allo stesso linguaggio. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+123
-33
@@ -1,7 +1,28 @@
|
|||||||
---
|
---
|
||||||
|
// Layout dell'area riservata. Usa i token e i font del sito, come il Campus e Stress Index:
|
||||||
|
// il pannello non è più un foglio di stile a sé, così chi passa dal sito all'amministrazione
|
||||||
|
// resta nello stesso mondo visivo.
|
||||||
|
import '@fontsource/montserrat/400.css';
|
||||||
|
import '@fontsource/montserrat/500.css';
|
||||||
|
import '@fontsource/montserrat/600.css';
|
||||||
|
import '@fontsource/open-sans/400.css';
|
||||||
|
import '@fontsource/open-sans/600.css';
|
||||||
|
import '../styles/global.css';
|
||||||
|
|
||||||
interface Props { title: string }
|
interface Props { title: string }
|
||||||
const { title } = Astro.props;
|
const { title } = Astro.props;
|
||||||
const user = Astro.locals.user;
|
const user = Astro.locals.user;
|
||||||
|
const path = Astro.url.pathname;
|
||||||
|
const isManager = user?.role === 'superuser' || user?.role === 'admin';
|
||||||
|
|
||||||
|
// Voci del menu: ognuna compare solo a chi può davvero aprirla.
|
||||||
|
const VOCI = [
|
||||||
|
{ href: '/admin', label: 'Articoli', visibile: true, exact: true },
|
||||||
|
{ href: '/admin/content', label: 'Contenuti', visibile: isManager },
|
||||||
|
{ href: '/admin/users', label: 'Utenti', visibile: user?.role === 'admin' },
|
||||||
|
];
|
||||||
|
const attiva = (v: { href: string; exact?: boolean }) =>
|
||||||
|
v.exact ? path === v.href : path.startsWith(v.href);
|
||||||
---
|
---
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="it">
|
<html lang="it">
|
||||||
@@ -10,41 +31,110 @@ const user = Astro.locals.user;
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>{title} — Admin InsanityLab</title>
|
<title>{title} — Admin InsanityLab</title>
|
||||||
<meta name="robots" content="noindex" />
|
<meta name="robots" content="noindex" />
|
||||||
<style is:global>
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||||
body { font-family: system-ui, sans-serif; margin: 0; background: #f4f2ef; color: #333; }
|
|
||||||
.abar { background: #3a2d26; color: #fff; padding: 12px 24px; display: flex; justify-content: space-between; align-items: center; }
|
|
||||||
.abar a { color: #d9cfc4; text-decoration: none; margin-left: 16px; }
|
|
||||||
.awrap { max-width: 960px; margin: 30px auto; padding: 0 20px; }
|
|
||||||
.abtn { background: #b5a48b; color: #fff; border: 0; padding: 10px 18px; cursor: pointer; font-size: .9rem; text-decoration: none; display: inline-block; }
|
|
||||||
.abtn--danger { background: #a33; }
|
|
||||||
.afield { width: 100%; padding: 10px; margin-bottom: 14px; border: 1px solid #ccc; box-sizing: border-box; font: inherit; }
|
|
||||||
table { width: 100%; border-collapse: collapse; background: #fff; }
|
|
||||||
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid #eee; font-size: .92rem; }
|
|
||||||
.pill { font-size: .75rem; padding: 2px 10px; border-radius: 10px; background: #e5decf; }
|
|
||||||
.pill--draft { background: #f3d9a4; }
|
|
||||||
.form-msg { font-size: .9rem; margin-top: 8px; }
|
|
||||||
.form-msg--ok { color: #3c7a3c; }
|
|
||||||
.form-msg--err { color: #b03030; }
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body class="ad">
|
||||||
<div class="abar">
|
<header class="abar">
|
||||||
<strong>InsanityLab · Admin</strong>
|
<a class="abar__brand" href="/admin">
|
||||||
<span>
|
<span class="abar__eyebrow">InsanityLab</span>
|
||||||
|
Area riservata
|
||||||
|
</a>
|
||||||
|
|
||||||
{user && (
|
{user && (
|
||||||
<>
|
<nav class="abar__nav" aria-label="pannello">
|
||||||
{`Ciao, ${user.username}`}
|
{VOCI.filter((v) => v.visibile).map((v) => (
|
||||||
<a href="/admin">Articoli</a>
|
<a href={v.href} class:list={['abar__link', { 'is-active': attiva(v) }]}>{v.label}</a>
|
||||||
{(user.role === 'superuser' || user.role === 'admin') && <a href="/admin/content">Contenuti</a>}
|
))}
|
||||||
{user.role === 'admin' && <a href="/admin/users">Utenti</a>}
|
<a class="abar__link" href="/" target="_blank" rel="noopener">Sito</a>
|
||||||
{user.role === 'admin' && <a href="/piattaforme">Piattaforme</a>}
|
<a class="abar__link abar__link--out" href="/admin/logout">Esci</a>
|
||||||
<a href="/admin/new">Nuovo</a>
|
</nav>
|
||||||
<a href="/admin/logout">Esci</a>
|
|
||||||
<a href="/blog" target="_blank">Vedi sito ↗</a>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
</span>
|
|
||||||
</div>
|
{user && <p class="abar__user">{user.username}</p>}
|
||||||
<div class="awrap"><slot /></div>
|
</header>
|
||||||
|
|
||||||
|
<main class="awrap"><slot /></main>
|
||||||
|
|
||||||
|
<style is:global>
|
||||||
|
body.ad { background: var(--c-bg-alt); }
|
||||||
|
|
||||||
|
/* --- barra --- */
|
||||||
|
.abar {
|
||||||
|
display: flex; align-items: center; gap: 28px; flex-wrap: wrap;
|
||||||
|
background: var(--c-dark); color: #cfc6bd; padding: 16px 32px;
|
||||||
|
}
|
||||||
|
.abar__brand {
|
||||||
|
font-family: var(--font-heading); font-size: 1rem; font-weight: 600; letter-spacing: .12em;
|
||||||
|
text-transform: uppercase; color: #fff; text-decoration: none; line-height: 1.15;
|
||||||
|
}
|
||||||
|
.abar__eyebrow { display: block; font-size: .62rem; letter-spacing: .2em; color: var(--c-accent); }
|
||||||
|
.abar__nav { display: flex; align-items: center; gap: 26px; flex-wrap: wrap; }
|
||||||
|
.abar__link {
|
||||||
|
font-family: var(--font-heading); font-size: .72rem; font-weight: 600; letter-spacing: .16em;
|
||||||
|
text-transform: uppercase; color: #b6ada3; text-decoration: none; padding: 4px 0;
|
||||||
|
border-bottom: 1px solid transparent;
|
||||||
|
}
|
||||||
|
.abar__link:hover { color: #fff; }
|
||||||
|
.abar__link.is-active { color: #fff; border-bottom-color: var(--c-accent); }
|
||||||
|
.abar__link--out { color: var(--c-accent); }
|
||||||
|
.abar__user {
|
||||||
|
margin: 0 0 0 auto; font-size: .74rem; letter-spacing: .12em; text-transform: uppercase; color: #8d8379;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- contenuto --- */
|
||||||
|
.awrap { max-width: 1080px; margin: 40px auto 80px; padding: 0 24px; }
|
||||||
|
.awrap h1 {
|
||||||
|
font-size: clamp(1.6rem, 3vw, 2.1rem); text-transform: none; letter-spacing: .02em; margin-bottom: .6em;
|
||||||
|
}
|
||||||
|
.awrap h2 { font-size: 1.15rem; text-transform: none; letter-spacing: .02em; }
|
||||||
|
|
||||||
|
/* --- comandi --- */
|
||||||
|
.abtn {
|
||||||
|
display: inline-block; background: var(--c-dark); color: #fff; border: 1px solid var(--c-dark);
|
||||||
|
padding: 10px 20px; cursor: pointer; text-decoration: none; font-family: var(--font-heading);
|
||||||
|
font-size: .7rem; font-weight: 600; letter-spacing: .14em; text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.abtn:hover { background: var(--c-dark-2); border-color: var(--c-dark-2); }
|
||||||
|
.abtn--danger { background: none; color: #a4544a; border-color: #ddcfc9; }
|
||||||
|
.abtn--danger:hover { background: #a4544a; border-color: #a4544a; color: #fff; }
|
||||||
|
|
||||||
|
.afield {
|
||||||
|
width: 100%; padding: 11px 13px; margin-bottom: 14px; border: 1px solid #ddd6cb;
|
||||||
|
box-sizing: border-box; font: inherit; font-size: .92rem; background: #fff; border-radius: 0;
|
||||||
|
}
|
||||||
|
.afield:focus { outline: 2px solid var(--c-accent); outline-offset: -2px; }
|
||||||
|
|
||||||
|
/* --- tabelle --- */
|
||||||
|
table { width: 100%; border-collapse: collapse; background: #fff; border: 1px solid #e4dfd7; }
|
||||||
|
th, td { text-align: left; padding: 12px 14px; border-bottom: 1px solid #efeae2; font-size: .9rem; }
|
||||||
|
th {
|
||||||
|
font-family: var(--font-heading); font-size: .68rem; font-weight: 600; letter-spacing: .14em;
|
||||||
|
text-transform: uppercase; color: var(--c-text-light); background: #faf8f5;
|
||||||
|
}
|
||||||
|
tbody tr:last-child td { border-bottom: 0; }
|
||||||
|
tbody tr:hover { background: #faf8f5; }
|
||||||
|
td a { color: var(--c-accent-dark); font-weight: 600; text-decoration: none; }
|
||||||
|
td a:hover { text-decoration: underline; }
|
||||||
|
|
||||||
|
.pill {
|
||||||
|
display: inline-block; font-family: var(--font-heading); font-size: .64rem; font-weight: 600;
|
||||||
|
letter-spacing: .1em; text-transform: uppercase; padding: 3px 10px;
|
||||||
|
background: rgba(111,143,106,.16); color: #5f7c5a;
|
||||||
|
}
|
||||||
|
.pill--draft { background: rgba(192,138,62,.18); color: #96682a; }
|
||||||
|
|
||||||
|
.aform { max-width: 380px; background: #fff; border: 1px solid #e4dfd7; padding: 26px 24px; }
|
||||||
|
|
||||||
|
.form-msg { font-size: .88rem; margin-top: 8px; }
|
||||||
|
.form-msg--ok { color: #5f7c5a; }
|
||||||
|
.form-msg--err { color: #a4544a; }
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.abar { padding: 14px 20px; gap: 14px; }
|
||||||
|
.abar__nav { gap: 16px; width: 100%; }
|
||||||
|
.abar__user { margin-left: 0; }
|
||||||
|
.awrap { margin-top: 26px; padding: 0 20px; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -109,22 +109,26 @@ const allStyles = STYLE_GROUPS as Record<string, readonly string[]>;
|
|||||||
|
|
||||||
<style is:global>
|
<style is:global>
|
||||||
.chead { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; flex-wrap: wrap; }
|
.chead { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; flex-wrap: wrap; }
|
||||||
.chead a { color: #7a6a55; }
|
.chead a { color: var(--c-accent-dark); font-weight: 600; text-decoration: none; }
|
||||||
.cgroup { background: #fff; border: 1px solid #ddd; margin-bottom: 14px; }
|
.cgroup { background: #fff; border: 1px solid #e4dfd7; margin-bottom: 14px; }
|
||||||
.cgroup > summary { padding: 12px 16px; cursor: pointer; background: #eee9e1; font-size: 1.05rem; }
|
.cgroup > summary {
|
||||||
.crow { border-top: 1px solid #eee; }
|
padding: 13px 16px; cursor: pointer; background: #faf8f5; border-bottom: 1px solid #efeae2;
|
||||||
|
font-family: var(--font-heading); font-size: .78rem; font-weight: 600; letter-spacing: .14em;
|
||||||
|
text-transform: uppercase; color: var(--c-heading);
|
||||||
|
}
|
||||||
|
.crow { border-top: 1px solid #efeae2; }
|
||||||
.crow > summary { padding: 8px 16px; cursor: pointer; display: flex; gap: 12px; align-items: baseline; }
|
.crow > summary { padding: 8px 16px; cursor: pointer; display: flex; gap: 12px; align-items: baseline; }
|
||||||
.crow > summary code { background: #f0ece5; padding: 1px 6px; font-size: .82rem; white-space: nowrap; }
|
.crow > summary code { background: #f2ede5; padding: 2px 7px; font-size: .78rem; white-space: nowrap; color: #6f6357; }
|
||||||
.crow-snippet { color: #888; font-size: .85rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
.crow-snippet { color: #888; font-size: .85rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
.crow-body { padding: 6px 16px 12px; }
|
.crow-body { padding: 6px 16px 12px; }
|
||||||
.crow-body .afield { margin-bottom: 8px; }
|
.crow-body .afield { margin-bottom: 8px; }
|
||||||
.cstyles { display: flex; gap: 14px; flex-wrap: wrap; margin: 0 0 8px; }
|
.cstyles { display: flex; gap: 14px; flex-wrap: wrap; margin: 0 0 8px; }
|
||||||
.cstyles label { font-size: .85rem; color: #555; }
|
.cstyles label { font-size: .82rem; color: var(--c-text-light); }
|
||||||
.cstyles select { margin-left: 4px; padding: 4px; font: inherit; }
|
.cstyles select { margin-left: 4px; padding: 4px; font: inherit; }
|
||||||
.cactions { margin: 0 0 4px; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
.cactions { margin: 0 0 4px; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
||||||
.cimg-preview img { max-width: 240px; max-height: 140px; display: block; border: 1px solid #ddd; }
|
.cimg-preview img { max-width: 240px; max-height: 140px; display: block; border: 1px solid #e4dfd7; }
|
||||||
.cmeta { color: #999; font-size: .78rem; margin: 4px 0 0; }
|
.cmeta { color: var(--c-text-light); font-size: .76rem; margin: 4px 0 0; }
|
||||||
.crow--hl { outline: 2px solid #b5a48b; }
|
.crow--hl { outline: 2px solid var(--c-accent); }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ if (Astro.request.method === 'POST') {
|
|||||||
---
|
---
|
||||||
<Admin title="Login">
|
<Admin title="Login">
|
||||||
<h1>Accesso</h1>
|
<h1>Accesso</h1>
|
||||||
{error && <p style="color:#a33">{error}</p>}
|
{error && <p class="form-msg form-msg--err">{error}</p>}
|
||||||
<form method="post" style="max-width:360px">
|
<form class="aform" method="post">
|
||||||
<input class="afield" name="username" placeholder="Utente" required autocomplete="username" />
|
<input class="afield" name="username" placeholder="Utente" required autocomplete="username" />
|
||||||
<input class="afield" type="password" name="password" placeholder="Password" required autocomplete="current-password" />
|
<input class="afield" type="password" name="password" placeholder="Password" required autocomplete="current-password" />
|
||||||
<button class="abtn" type="submit">Entra</button>
|
<button class="abtn" type="submit">Entra</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user