v_2.3
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
<!doctype html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<title>{% block title %}{{ brand_name }}{% endblock %} — {{ brand_name }}{% if is_backoffice %} · backoffice{% endif %}</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/app.css') }}">
|
||||
<link rel="icon" type="image/svg+xml" href="{{ url_for('static', filename='favicon.svg') }}">
|
||||
<script>
|
||||
// Theme bootstrap — set BEFORE first paint to avoid flash
|
||||
(function () {
|
||||
try {
|
||||
var saved = localStorage.getItem('alerthub-theme');
|
||||
var theme = saved || (matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark');
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
} catch (_) {}
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body class="{{ 'is-backoffice' if is_backoffice else 'is-frontoffice' }}">
|
||||
|
||||
<div class="grid-bg" aria-hidden="true"></div>
|
||||
|
||||
<header class="topbar">
|
||||
<div class="topbar-inner">
|
||||
<a class="brand" href="{{ url_for('main.index') if not is_backoffice else url_for('backoffice.dashboard') }}">
|
||||
<span class="brand-mark">▮▮</span>
|
||||
<span class="brand-name">{{ brand_name }}</span>
|
||||
<span class="brand-tag">{{ 'BACKOFFICE' if is_backoffice else 'FRONTOFFICE' }}</span>
|
||||
</a>
|
||||
|
||||
{% if current_user.is_authenticated and not session.get('mfa_pending') %}
|
||||
<nav class="topbar-nav">
|
||||
{% if not is_backoffice %}
|
||||
<a href="{{ url_for('main.index') }}" class="navlink {% if request.endpoint == 'main.index' %}active{% endif %}">
|
||||
<span class="dot"></span>View
|
||||
</a>
|
||||
<a href="{{ url_for('main.alerts_list') }}" class="navlink {% if request.endpoint and request.endpoint.startswith('main.alert') %}active{% endif %}">
|
||||
<span class="dot"></span>Manage Alerts
|
||||
</a>
|
||||
{% if current_user.is_admin %}
|
||||
<a href="{{ url_for('backoffice.dashboard') }}" class="navlink navlink-cross {% if is_backoffice %}active{% endif %}" title="Open the admin backoffice">
|
||||
<span class="dot dot-admin"></span>Backoffice
|
||||
</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<a href="{{ url_for('main.index') }}" class="navlink navlink-cross" title="Back to the alerts frontoffice">
|
||||
<span class="dot"></span>Frontoffice
|
||||
</a>
|
||||
<a href="{{ url_for('backoffice.dashboard') }}" class="navlink {% if request.endpoint == 'backoffice.dashboard' %}active{% endif %}">
|
||||
<span class="dot"></span>Dashboard
|
||||
</a>
|
||||
<a href="{{ url_for('backoffice.users_list') }}" class="navlink {% if request.endpoint and request.endpoint.startswith('backoffice.user') %}active{% endif %}">
|
||||
<span class="dot"></span>Users
|
||||
</a>
|
||||
<a href="{{ url_for('backoffice.mail_config') }}" class="navlink {% if request.endpoint and request.endpoint.startswith('backoffice.mail') %}active{% endif %}">
|
||||
<span class="dot"></span>Mail
|
||||
</a>
|
||||
<a href="{{ url_for('backoffice.settings') }}" class="navlink {% if request.endpoint == 'backoffice.settings' %}active{% endif %}">
|
||||
<span class="dot"></span>Settings
|
||||
</a>
|
||||
<a href="{{ url_for('backoffice.audit_log') }}" class="navlink {% if request.endpoint == 'backoffice.audit_log' %}active{% endif %}">
|
||||
<span class="dot"></span>Audit
|
||||
</a>
|
||||
<a href="{{ url_for('backoffice.mail_log') }}" class="navlink {% if request.endpoint == 'backoffice.mail_log' %}active{% endif %}">
|
||||
<span class="dot"></span>Mail Log
|
||||
</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
|
||||
<div class="topbar-right">
|
||||
<button type="button" id="theme-toggle" class="icon-btn" title="Toggle theme" aria-label="Toggle theme">
|
||||
<svg class="icon-sun" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="4"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3M4.9 4.9l2.1 2.1M17 17l2.1 2.1M4.9 19.1L7 17M17 7l2.1-2.1"/></svg>
|
||||
<svg class="icon-moon" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg>
|
||||
</button>
|
||||
|
||||
<a href="{{ url_for('auth.account') }}" class="user-chip" title="Account">
|
||||
{% if current_user.has_avatar %}
|
||||
<img class="user-avatar user-avatar-img" src="{{ url_for('auth.avatar', user_id=current_user.id) }}" alt="{{ current_user.username }}">
|
||||
{% else %}
|
||||
<span class="user-avatar">{{ current_user.initials }}</span>
|
||||
{% endif %}
|
||||
<span class="user-meta">
|
||||
<span class="user-name">{{ current_user.username }}</span>
|
||||
<span class="user-role role-{{ current_user.role }}">{{ current_user.role }}</span>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<form method="post" action="{{ url_for('auth.logout') }}" class="inline-form">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button class="btn btn-ghost" type="submit">Sign out</button>
|
||||
</form>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="topbar-right">
|
||||
<button type="button" id="theme-toggle" class="icon-btn" title="Toggle theme" aria-label="Toggle theme">
|
||||
<svg class="icon-sun" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="4"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3M4.9 4.9l2.1 2.1M17 17l2.1 2.1M4.9 19.1L7 17M17 7l2.1-2.1"/></svg>
|
||||
<svg class="icon-moon" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div class="flash-stack">
|
||||
{% for cat, msg in messages %}
|
||||
<div class="flash flash-{{ cat }}">
|
||||
<span class="flash-icon"></span>
|
||||
<span class="flash-text">{{ msg }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
{% if request.endpoint != 'auth.login' %}
|
||||
<footer class="footer">
|
||||
<span class="kbd">{{ brand_name }}</span>
|
||||
<span class="footer-sep">·</span>
|
||||
<span>{{ 'admin console' if is_backoffice else 'alert console' }}</span>
|
||||
<span class="footer-copy">{{ footer_text }}</span>
|
||||
<span class="status-pill"><span class="led"></span>operational</span>
|
||||
</footer>
|
||||
{% endif %}
|
||||
|
||||
<script src="{{ url_for('static', filename='js/app.js') }}"></script>
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user