Files
boilerplate_rust_web/templates/admin/layout.html
T
ab 16abe754af Initial commit: web-app boilerplate with auth, OIDC/SSO, admin panel, i18n
Rust (cot framework) + PostgreSQL boilerplate providing:

- Session-based auth with Admin/User roles
- OIDC/SSO login with PKCE, group-to-role mapping, auto-provisioning
- Admin panel: user management, settings, debug/config inspector
- 3-tier config system (compiled default → DB → FURU_* env vars)
- i18n (English + Russian) with compile-time translations macro
- JSON API skeleton (GET /api/me)
- DB-backed sessions (survive server restarts)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-21 14:22:33 +03:00

58 lines
3.3 KiB
HTML

{% extends "base.html" %}
{% block title %}{% block admin_title %}{{ t.nav_admin }}{% endblock admin_title %} | {{ t.site_name }}{% endblock title %}
{% block head_extra %}
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: system-ui, -apple-system, sans-serif; display: flex; min-height: 100vh; background: #f5f5f5; color: #333; }
nav.sidebar { width: 220px; background: #1a1a2e; color: #eee; padding: 1rem; }
nav.sidebar h2 { font-size: 1.1rem; margin-bottom: 1.5rem; }
nav.sidebar a { color: #ccc; text-decoration: none; display: block; padding: .4rem .6rem; border-radius: 4px; }
nav.sidebar a:hover { background: #16213e; color: #fff; }
.main-wrap { flex: 1; display: flex; flex-direction: column; }
.topbar { display: flex; justify-content: flex-end; align-items: center; gap: 1rem; padding: .5rem 1.5rem; background: #fff; border-bottom: 1px solid #e0e0e0; }
.user-info { font-size: .85rem; color: #555; }
.lang-switch { display: flex; gap: .25rem; }
.lang-switch a { text-decoration: none; padding: .25rem .5rem; border-radius: 4px; font-size: .9rem; color: #555; }
.lang-switch a:hover { background: #eee; color: #111; }
.lang-switch a.active { font-weight: 700; color: #111; }
.logout-link { text-decoration: none; font-size: .85rem; color: #555; padding: .25rem .5rem; border-radius: 4px; }
.logout-link:hover { background: #eee; color: #111; }
.main { flex: 1; padding: 2rem; overflow-x: auto; }
table { border-collapse: collapse; width: 100%; margin-bottom: 1.5rem; background: #fff; border-radius: 6px; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,.1); }
th, td { text-align: left; padding: .6rem .8rem; border-bottom: 1px solid #eee; }
th { background: #f0f0f0; font-weight: 600; }
h1 { margin-bottom: 1rem; }
h2 { margin: 1.5rem 0 .5rem; }
code { background: #f4f4f4; padding: .1rem .35rem; border-radius: 3px; font-size: .85em; }
.badge { display: inline-block; padding: .15rem .55rem; border-radius: 4px; font-size: .8rem; font-weight: 600; letter-spacing: .02em; }
.badge-default { background: #e9ecef; color: #555; }
.badge-database { background: #d1ecf1; color: #0c5460; }
.badge-env { background: #fff3cd; color: #856404; }
</style>
{% endblock head_extra %}
{% block body %}
<nav class="sidebar">
<h2>{{ t.site_name }} {{ t.nav_admin }}</h2>
<a href="/admin/">{{ t.nav_dashboard }}</a>
<a href="/admin/users">{{ t.nav_users }}</a>
<a href="/admin/settings">{{ t.nav_settings }}</a>
<a href="/admin/debug">{{ t.nav_debug }}</a>
</nav>
<div class="main-wrap">
<div class="topbar">
<span class="user-info">{{ user_name }} ({{ user_role }})</span>
<div class="lang-switch">
<a href="#"{% if t.lang.code() == "en" %} class="active"{% endif %} onclick="location.href='/set-lang?lang=en&next='+encodeURIComponent(location.pathname);return false">EN</a>
<a href="#"{% if t.lang.code() == "ru" %} class="active"{% endif %} onclick="location.href='/set-lang?lang=ru&next='+encodeURIComponent(location.pathname);return false">RU</a>
</div>
<a class="logout-link" href="/logout">{{ t.nav_logout }}</a>
</div>
<div class="main">
{% block content %}{% endblock content %}
</div>
</div>
{% endblock body %}