- aria-guide "Mostrami dov'è": ora aggancia le voci del menu IN ALTO V3 (data-nav aggiunto in topnav-v3.js su voci dirette + mega-link). Se la voce è in un mega-menu, lo apre (.aria-guide-open) e ci punta lo spotlight; coach "menu in alto". Fallback navigazione invariato. (Prima cercava .sidebar-nav V2.) - segnala-anonimo.html: CSP font-src 'self' → 'self' data: (sbloccato il font data: embeddato, niente più violazione CSP). - Cache-buster: topnav-v3.js/common.js ?v=20260627t, aria-guide.js ?v=20260627t. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
343 lines
22 KiB
JavaScript
343 lines
22 KiB
JavaScript
/* ═══════════════════════════════════════════════════════════════════════════
|
||
* topnav-v3.js — Chrome V3 (appbar + mega-menu) data-driven dalla mappa IA (§6).
|
||
* ───────────────────────────────────────────────────────────────────────────
|
||
* Sostituisce la sidebar V2 (common-bi.js) con la top-nav del mockup
|
||
* "docs/mockup Ui/index.html". REGOLE:
|
||
* - SOLO UI. Riusa gli helper di common.js: _loadUserInfo, _loadVersionFooter,
|
||
* _loadConsultantOrgSwitcher (via _loadUserInfo), _loadFirmBranding,
|
||
* _renderImpersonateBanner, switchLang, _getSavedLang, api.logout.
|
||
* - Stessi ID DOM degli helper V2 (#sidebar-user-name/-avatar/-role,
|
||
* #sidebar-org-switcher, #sidebar-version, .lang-btn) → gli helper esistenti
|
||
* funzionano invariati senza toccare api.js.
|
||
* - Espone window.loadSidebar = loadTopnavV3 → l'init delle pagine resta invariato.
|
||
* - I 3 FAB reali (campana notifiche + bug-reporter + ARIA) restano quelli di
|
||
* common.js (qui NON si reimplementano: si applica solo lo stile .fab-stack/.fab
|
||
* al trittico già montato, per fedeltà al mockup).
|
||
* - aria-current sulla voce/gruppo attivo (da location.pathname).
|
||
* - Icone Lucide via <i data-lucide> + lucide.createIcons() (chiamato dall'init pagina).
|
||
* ═══════════════════════════════════════════════════════════════════════════ */
|
||
(function () {
|
||
'use strict';
|
||
|
||
// ── Mappa IA (§6 dello spec). 9 gruppi → voci/href reali. ───────────────
|
||
// top-level: voce diretta (href) oppure gruppo con mega-menu (cols).
|
||
var NAV_GROUPS = [
|
||
{ label: 'Dashboard', i18n: 'nav.dashboard', icon: 'layout-dashboard', href: 'dashboard.html' },
|
||
{ label: 'Calendario', i18n: 'nav.calendar', icon: 'calendar', href: 'calendario.html' },
|
||
{
|
||
label: 'Stakeholders', icon: 'users',
|
||
cols: [{ head: 'RELAZIONI', links: [
|
||
{ b: 'Stakeholders', s: 'Soggetti interni ed esterni rilevanti', href: 'stakeholders.html', ic: 'handshake' },
|
||
{ b: 'Supply-Chain', s: 'Rischio fornitori e terze parti', href: 'supply-chain.html', ic: 'link' },
|
||
{ b: 'Attività su Stakeholders', s: 'Interazioni, richieste e impegni', href: 'stakeholder-activities.html', ic: 'activity' }
|
||
]}]
|
||
},
|
||
{
|
||
label: 'Struttura interna', icon: 'building-2',
|
||
cols: [{ head: 'RUOLI E COMPETENZE', links: [
|
||
{ b: 'Organigramma', s: 'Ruoli, deleghe e responsabilità', href: 'organigramma.html', ic: 'network' },
|
||
{ b: 'Competenze', s: 'Skill matrix e copertura dei ruoli', href: 'competenze.html', ic: 'award' },
|
||
{ b: 'GAP Analysis', s: 'Scostamento tra stato attuale e atteso', href: 'assessment.html', ic: 'git-compare' },
|
||
{ b: 'Matrice RACI', s: 'Responsabilità per attività (R/A/C/I)', href: 'raci.html', ic: 'grid-3x3' },
|
||
{ b: 'Formazione', s: 'Piani formativi e completamento', href: 'training.html', ic: 'graduation-cap' }
|
||
]}]
|
||
},
|
||
{
|
||
label: 'Rischi', icon: 'shield-alert',
|
||
cols: [{ head: 'GESTIONE RISCHIO', links: [
|
||
{ b: 'Mappa dei rischi', s: 'Registro rischi e piani di trattamento', href: 'risks.html', ic: 'map' },
|
||
{ b: 'Inventario', s: 'Asset e perimetro tecnico', href: 'assets.html', ic: 'boxes' },
|
||
{ b: 'Policy', s: 'Politiche approvate e in revisione', href: 'policies.html', ic: 'file-text' },
|
||
{ b: 'Connettori Discovery', s: 'Scansione rete/cloud → inventario', href: 'connettori-discovery.html', ic: 'plug-zap' }
|
||
]}]
|
||
},
|
||
{
|
||
label: 'Monitoraggio', icon: 'radar',
|
||
cols: [{ head: 'VIGILANZA E AUDIT', links: [
|
||
{ b: 'Segnalazioni ricevute', s: 'Whistleblowing e segnalazioni interne', href: 'whistleblowing.html', ic: 'megaphone' },
|
||
{ b: 'Audit interni', s: 'Programma e esiti degli audit', href: 'internal-audits.html', ic: 'clipboard-check' },
|
||
{ b: 'Audit ACN', s: 'Verifiche e ispezioni dell’autorità', href: 'reports.html', ic: 'file-check' },
|
||
{ b: 'Controlli periodici', s: 'Verifiche ricorrenti e check-list', href: 'controlli-periodici.html', ic: 'list-checks' },
|
||
{ b: 'Riesame di Direzione', s: 'Esiti del riesame §9.3', href: 'management-review.html', ic: 'gauge' },
|
||
{ b: 'Scadenziario', s: 'Revisioni e adempimenti ricorrenti', href: 'review-schedule.html', ic: 'calendar-clock' }
|
||
]}]
|
||
},
|
||
{
|
||
label: 'Lex e ISO', icon: 'scale',
|
||
cols: [{ head: 'NORMATIVA E ISO', links: [
|
||
{ b: 'Normative', s: 'Direttiva, decreto e riferimenti applicabili', href: 'normative.html', ic: 'scroll-text' },
|
||
{ b: 'Modello SGSI (ISO 27001)', s: 'Sistema di gestione sicurezza informazioni', href: 'isms.html', ic: 'shield-check' },
|
||
{ b: 'Misure e requisiti ACN', s: 'Misure tecniche e organizzative Art. 21', href: 'misure-requisiti.html', ic: 'list-checks' }
|
||
]}]
|
||
},
|
||
{
|
||
label: 'AI', icon: 'sparkles',
|
||
cols: [{ head: 'ASSISTENTE', links: [
|
||
{ b: 'AI Cross-Analysis', s: 'Analisi trasversale di rischi e misure', href: 'cross-analysis.html', ic: 'sparkles' },
|
||
{ b: 'Knowledge Base', s: 'Procedure, linee guida e riferimenti', href: 'kb.html', ic: 'book-open' }
|
||
]}]
|
||
},
|
||
{
|
||
label: 'Guida', icon: 'life-buoy',
|
||
cols: [
|
||
{ head: 'GUIDA', links: [
|
||
{ b: 'Guida all’uso', s: 'Manuale e istruzioni della piattaforma', href: 'guida.html', ic: 'life-buoy' },
|
||
{ b: 'Compliance Journey', s: 'Percorso guidato di conformità', href: 'workflow.html', ic: 'route' },
|
||
{ b: 'Integrazioni Esterne', s: 'Connettori e servizi collegati', href: 'integrazioniext.html', ic: 'plug' }
|
||
]},
|
||
{ head: 'SISTEMA', links: [
|
||
{ b: 'Impostazioni', s: 'Configurazione del workspace', href: 'settings.html', ic: 'settings' },
|
||
{ b: 'Architettura', s: 'Modello dati e struttura del sistema', href: 'architecture.html', ic: 'layers' },
|
||
{ b: 'Simulazione Demo', s: 'Scenari guidati di prova', href: 'simulate.html', ic: 'play-circle' }
|
||
]}
|
||
]
|
||
}
|
||
];
|
||
|
||
// ── i18n: traduzione voci nav (IT/EN) come nel V2. Chiave per href/gruppo. ──
|
||
var I18N_BY_HREF = {
|
||
'dashboard.html': 'nav.dashboard', 'calendario.html': 'nav.calendar',
|
||
'stakeholders.html': 'nav.stakeholders', 'supply-chain.html': 'nav.supply_chain', 'stakeholder-activities.html': 'nav.stk_activities',
|
||
'organigramma.html': 'nav.org_chart', 'competenze.html': 'nav.competences', 'assessment.html': 'nav.gap_analysis', 'raci.html': 'nav.raci', 'training.html': 'nav.training',
|
||
'risks.html': 'nav.risks', 'assets.html': 'nav.assets', 'policies.html': 'nav.policies', 'connettori-discovery.html': 'nav.connectors',
|
||
'whistleblowing.html': 'nav.whistleblowing', 'internal-audits.html': 'nav.internal_audits', 'reports.html': 'nav.audit_acn', 'controlli-periodici.html': 'nav.periodic_controls', 'management-review.html': 'nav.management_review', 'review-schedule.html': 'nav.review_schedule',
|
||
'normative.html': 'nav.normative', 'isms.html': 'nav.isms', 'misure-requisiti.html': 'nav.framework',
|
||
'cross-analysis.html': 'nav.cross_analysis', 'kb.html': 'nav.kb',
|
||
'guida.html': 'nav.help', 'workflow.html': 'nav.workflow', 'integrazioniext.html': 'nav.integrations', 'settings.html': 'nav.settings', 'architecture.html': 'nav.architecture', 'simulate.html': 'nav.simulate'
|
||
};
|
||
var GROUP_I18N = {
|
||
'Stakeholders': 'nav.grp_stakeholders', 'Struttura interna': 'nav.grp_internal', 'Rischi': 'nav.grp_risks',
|
||
'Monitoraggio': 'nav.grp_monitoring', 'Lex e ISO': 'nav.grp_lexiso', 'AI': 'nav.grp_ai', 'Guida': 'nav.grp_guide'
|
||
};
|
||
function i18nAttr(key) { return key ? ' data-i18n="' + key + '"' : ''; }
|
||
// data-nav = href senza .html → aggancio per il puntatore guida ARIA (aria-guide.js).
|
||
function navAttr(href) { return ' data-nav="' + esc(String(href).replace(/\.html$/, '')) + '"'; }
|
||
|
||
function esc(s) {
|
||
return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) {
|
||
return ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[c];
|
||
});
|
||
}
|
||
|
||
function currentPage() {
|
||
return (window.location.pathname.split('/').pop() || 'dashboard.html');
|
||
}
|
||
|
||
// È attivo il gruppo che contiene la pagina corrente (direct href o una delle links).
|
||
function isGroupActive(g, page) {
|
||
if (g.href) return g.href === page;
|
||
if (g.cols) {
|
||
for (var i = 0; i < g.cols.length; i++) {
|
||
var lk = g.cols[i].links;
|
||
for (var j = 0; j < lk.length; j++) if (lk[j].href === page) return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
function renderMega(g) {
|
||
var colsHtml = g.cols.map(function (col) {
|
||
var links = col.links.map(function (l) {
|
||
return '<a class="mega-link"' + navAttr(l.href) + ' href="' + esc(l.href) + '">' +
|
||
'<span class="mega-ic"><i data-lucide="' + esc(l.ic) + '" class="ic"></i></span>' +
|
||
'<span><b' + i18nAttr(I18N_BY_HREF[l.href]) + '>' + esc(l.b) + '</b><span>' + esc(l.s) + '</span></span></a>';
|
||
}).join('');
|
||
return '<div class="mega-col"><p class="mega-head">' + esc(col.head) + '</p>' + links + '</div>';
|
||
}).join('');
|
||
return '<div class="mega no-promo">' + colsHtml + '</div>';
|
||
}
|
||
|
||
function renderNavItem(g, page) {
|
||
var active = isGroupActive(g, page);
|
||
var cls = 'nav-link' + (active ? ' active' : '');
|
||
var aria = active ? ' aria-current="page"' : '';
|
||
var i18n = i18nAttr(g.i18n || GROUP_I18N[g.label]);
|
||
|
||
if (g.href && !g.cols) {
|
||
// Voce diretta (Dashboard, Calendario)
|
||
return '<div class="nav-item">' +
|
||
'<a class="' + cls + '"' + aria + navAttr(g.href) + ' href="' + esc(g.href) + '">' +
|
||
'<i data-lucide="' + esc(g.icon) + '" class="ic"></i>' +
|
||
'<span' + i18n + '>' + esc(g.label) + '</span></a></div>';
|
||
}
|
||
// Gruppo con mega-menu. Il link "testa" punta alla prima voce del gruppo.
|
||
var firstHref = g.cols[0].links[0].href;
|
||
return '<div class="nav-item">' +
|
||
'<a class="' + cls + '"' + aria + navAttr(firstHref) + ' href="' + esc(firstHref) + '">' +
|
||
'<i data-lucide="' + esc(g.icon) + '" class="ic"></i>' +
|
||
'<span' + i18n + '>' + esc(g.label) + '</span>' +
|
||
'<i data-lucide="chevron-down" class="caret"></i></a>' +
|
||
renderMega(g) + '</div>';
|
||
}
|
||
|
||
function loadTopnavV3() {
|
||
// Container: usa #topnav se presente, altrimenti riusa #sidebar (compat),
|
||
// altrimenti crea un host e lo prepende al body.
|
||
var host = document.getElementById('topnav') || document.getElementById('sidebar');
|
||
if (!host) {
|
||
host = document.createElement('div');
|
||
host.id = 'topnav';
|
||
document.body.insertBefore(host, document.body.firstChild);
|
||
}
|
||
// Se riusiamo #sidebar (aside), neutralizziamo eventuali stili layout V2.
|
||
host.removeAttribute('class');
|
||
host.id = 'topnav';
|
||
|
||
var page = currentPage();
|
||
var lang = (typeof _getSavedLang === 'function') ? _getSavedLang() : 'it';
|
||
|
||
var navItems = NAV_GROUPS.map(function (g) { return renderNavItem(g, page); }).join('');
|
||
|
||
host.innerHTML =
|
||
'<header class="appbar">' +
|
||
'<div class="bar-top"><div class="bar-top-in">' +
|
||
'<span class="flag" aria-hidden="true"><i class="g"></i><i class="w"></i><i class="r"></i></span>' +
|
||
'<a class="logo-mark" href="dashboard.html" aria-label="NIS2 Agile — Dashboard">N2</a>' +
|
||
'<div class="brand-txt"><b class="sidebar-logo-text">NIS2 Agile</b>' +
|
||
'<span>Conformità Direttiva (UE) 2022/2555 · D.Lgs. 138/2024</span></div>' +
|
||
'<label class="search"><i data-lucide="search" class="ic"></i>' +
|
||
'<input id="topnav-search" placeholder="Cerca misura, rischio, incidente…" aria-label="Cerca"></label>' +
|
||
'<span class="spacer"></span>' +
|
||
// Org-switcher (consulenti / multi-org) — popolato da _loadUserInfo() via stesso id.
|
||
'<span id="sidebar-org-switcher" style="display:none"></span>' +
|
||
// Lingua IT/EN (riusa switchLang di common.js)
|
||
'<span id="sidebar-lang-toggle" class="topnav-lang" role="group" aria-label="Lingua">' +
|
||
'<button class="lang-btn ' + (lang === 'it' ? 'active' : '') + '" onclick="switchLang(\'it\')" title="Italiano" aria-label="Italiano">IT</button>' +
|
||
'<button class="lang-btn ' + (lang === 'en' ? 'active' : '') + '" onclick="switchLang(\'en\')" title="English" aria-label="English">EN</button>' +
|
||
'</span>' +
|
||
'<a class="btn-incident" href="incidents.html"><i data-lucide="siren" class="ic"></i><span data-i18n="nav.register_incident">Registra incidente</span></a>' +
|
||
// User menu (avatar+nome+ruolo via _loadUserInfo; click = menu)
|
||
'<span class="user" id="topnav-user" tabindex="0" role="button" aria-haspopup="true" aria-expanded="false">' +
|
||
'<span class="avatar" id="sidebar-user-avatar">--</span>' +
|
||
'<span class="sidebar-user-name" id="sidebar-user-name" style="max-width:140px;overflow:hidden;text-overflow:ellipsis">…</span>' +
|
||
'<span id="sidebar-user-role" hidden></span>' +
|
||
'<i data-lucide="chevron-down" class="ic"></i>' +
|
||
'</span>' +
|
||
'<button class="nav-toggle" id="topnav-toggle" aria-label="Apri menu" aria-expanded="false"><i data-lucide="menu" class="ic"></i></button>' +
|
||
'</div></div>' +
|
||
'<nav class="bar-nav" id="topnav-bar" aria-label="Navigazione principale"><div class="bar-nav-in">' +
|
||
navItems +
|
||
'</div></nav>' +
|
||
'</header>';
|
||
|
||
// ── Riuso helper common.js (utente/avatar/ruolo + org-switcher + versione + branding + impersonate) ──
|
||
if (typeof _loadUserInfo === 'function') _loadUserInfo();
|
||
if (typeof _loadVersionFooter === 'function') _loadVersionFooter();
|
||
if (typeof _loadFirmBranding === 'function') _loadFirmBranding();
|
||
if (typeof _renderImpersonateBanner === 'function') _renderImpersonateBanner();
|
||
|
||
// ── Menu utente: dropdown con versione + logout (riusa api.logout) ──
|
||
_wireUserMenu();
|
||
// ── Mobile: toggle nav + accordion mega ──
|
||
_wireMobileNav();
|
||
// ── Stile + montaggio del trittico FAB reale dentro .fab-stack ──
|
||
_styleRealFabs();
|
||
|
||
// Lucide: prova subito (se già caricato) — l'init pagina lo richiama comunque.
|
||
if (window.lucide && typeof lucide.createIcons === 'function') {
|
||
try { lucide.createIcons(); } catch (e) {}
|
||
}
|
||
}
|
||
|
||
// Dropdown del menu utente: versione (changelog) + logout.
|
||
function _wireUserMenu() {
|
||
var u = document.getElementById('topnav-user');
|
||
if (!u) return;
|
||
var menu = document.createElement('div');
|
||
menu.id = 'topnav-user-menu';
|
||
menu.style.cssText = 'position:fixed;display:none;min-width:200px;background:#fff;color:var(--ink);' +
|
||
'border:1px solid var(--line);border-radius:10px;box-shadow:0 14px 36px rgba(11,40,80,.20);' +
|
||
'padding:6px;z-index:90';
|
||
menu.innerHTML =
|
||
'<div id="sidebar-version" role="button" tabindex="0" title="Versione applicazione" ' +
|
||
'style="padding:8px 10px;font-size:12px;color:var(--muted);cursor:pointer;border-radius:8px">v—</div>' +
|
||
'<a href="settings.html" style="display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:8px;font-size:13px;font-weight:600">' +
|
||
'<i data-lucide="settings" style="width:15px;height:15px"></i>Impostazioni</a>' +
|
||
'<button type="button" id="topnav-logout" style="display:flex;align-items:center;gap:8px;width:100%;text-align:left;' +
|
||
'border:0;background:none;font:inherit;font-size:13px;font-weight:600;color:var(--c-red);padding:9px 10px;border-radius:8px;cursor:pointer">' +
|
||
'<i data-lucide="log-out" style="width:15px;height:15px"></i>Esci</button>';
|
||
document.body.appendChild(menu);
|
||
|
||
function place() {
|
||
var r = u.getBoundingClientRect();
|
||
menu.style.top = (r.bottom + 8) + 'px';
|
||
menu.style.right = Math.max(8, window.innerWidth - r.right) + 'px';
|
||
}
|
||
function open() { place(); menu.style.display = 'block'; u.setAttribute('aria-expanded', 'true'); if (window.lucide) try { lucide.createIcons(); } catch (e) {} }
|
||
function close() { menu.style.display = 'none'; u.setAttribute('aria-expanded', 'false'); }
|
||
function toggle() { (menu.style.display === 'block') ? close() : open(); }
|
||
|
||
u.addEventListener('click', toggle);
|
||
u.addEventListener('keydown', function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggle(); } });
|
||
document.addEventListener('click', function (e) { if (!u.contains(e.target) && !menu.contains(e.target)) close(); });
|
||
document.addEventListener('keydown', function (e) { if (e.key === 'Escape') close(); });
|
||
|
||
var lo = menu.querySelector('#topnav-logout');
|
||
if (lo) lo.addEventListener('click', function () { if (typeof api !== 'undefined' && api.logout) api.logout(); });
|
||
var ver = menu.querySelector('#sidebar-version');
|
||
if (ver) {
|
||
ver.addEventListener('click', function () { if (typeof _showVersionChangelog === 'function') _showVersionChangelog(); });
|
||
ver.addEventListener('keydown', function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); if (typeof _showVersionChangelog === 'function') _showVersionChangelog(); } });
|
||
}
|
||
}
|
||
|
||
// Mobile (≤900): hamburger apre/chiude la nav; tap su un gruppo apre l'accordion mega.
|
||
function _wireMobileNav() {
|
||
var toggle = document.getElementById('topnav-toggle');
|
||
var bar = document.getElementById('topnav-bar');
|
||
if (toggle && bar) {
|
||
toggle.addEventListener('click', function () {
|
||
var open = bar.classList.toggle('open');
|
||
toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
|
||
});
|
||
}
|
||
// Accordion per i gruppi con mega (solo in modalità mobile via CSS).
|
||
document.querySelectorAll('#topnav-bar .nav-item').forEach(function (item) {
|
||
var hasMega = item.querySelector('.mega');
|
||
if (!hasMega) return;
|
||
var link = item.querySelector('.nav-link');
|
||
if (!link) return;
|
||
link.addEventListener('click', function (e) {
|
||
// Solo in layout mobile (nav-toggle visibile) intercettiamo il tap per aprire l'accordion.
|
||
if (toggle && getComputedStyle(toggle).display !== 'none') {
|
||
e.preventDefault();
|
||
item.classList.toggle('open');
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
// Trittico FAB reale (campana/bug-reporter ARIA) montato da common.js: lo
|
||
// raggruppiamo in .fab-stack e gli diamo la veste V3, senza reimplementarlo.
|
||
// common.js crea: #nx-bar (bug-reporter widget) e #ai-chat-fab (ARIA viola).
|
||
// Qui aggiungiamo SOLO un contenitore visivo se non presente; gli elementi
|
||
// restano gestiti dal loro codice (eventi/voce/puntatore invariati).
|
||
function _styleRealFabs() {
|
||
// I FAB reali sono position:fixed indipendenti (z-index alti). Non li
|
||
// spostiamo nel DOM per non romperne gli handler; il loro look resta
|
||
// quello di common.js. Questa funzione è un hook no-op di compatibilità
|
||
// mantenuto per chiarezza: la veste .fab del mockup NON deve sovrascrivere
|
||
// i FAB funzionanti (ARIA con voce + bug-reporter widget).
|
||
return;
|
||
}
|
||
|
||
// CSS one-shot per il lang-toggle e user menu nella appbar (token V3).
|
||
(function injectChromeCss() {
|
||
if (document.getElementById('topnav-v3-css')) return;
|
||
var s = document.createElement('style');
|
||
s.id = 'topnav-v3-css';
|
||
s.textContent =
|
||
'.topnav-lang{display:inline-flex;gap:3px;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.16);border-radius:8px;padding:3px}' +
|
||
'.topnav-lang .lang-btn{border:0;background:transparent;color:#cfe0f1;font:inherit;font-size:11px;font-weight:700;padding:4px 8px;border-radius:6px;cursor:pointer}' +
|
||
'.topnav-lang .lang-btn:hover{background:rgba(255,255,255,.12);color:#fff}' +
|
||
'.topnav-lang .lang-btn.active{background:var(--gold);color:#1a1a1a}' +
|
||
'#topnav-user .sidebar-user-name{font-size:12px;font-weight:600}' +
|
||
'@media (max-width:560px){#topnav-user .sidebar-user-name{display:none}.topnav-lang{display:none}}';
|
||
document.head.appendChild(s);
|
||
})();
|
||
|
||
// Override globale: l'init delle pagine chiama loadSidebar() invariato.
|
||
window.loadTopnavV3 = loadTopnavV3;
|
||
window.loadSidebar = loadTopnavV3;
|
||
})();
|