Initial commit: LotusGuild Terminal Design System v1.0

Unified CSS, JavaScript utilities, HTML template, and framework skeleton
files for Tinker Tickets (PHP), PULSE (Node.js), and GANDALF (Flask).

Includes aesthetic_diff.md documenting every divergence between the three
apps with prioritised recommendations for convergence.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-14 21:08:57 -04:00
commit 66538f9ad8
9 changed files with 4895 additions and 0 deletions

141
python/base.html Normal file
View File

@@ -0,0 +1,141 @@
{#
LOTUSGUILD TERMINAL DESIGN SYSTEM — Flask/Jinja2 Base Template
Extend this in every page template:
{% extends "base.html" %}
{% block title %}Dashboard{% endblock %}
{% block active_nav %}dashboard{% endblock %}
{% block content %}
… your page HTML …
{% endblock %}
{% block scripts %}
<script nonce="{{ nonce }}">
lt.sortTable.init('my-table');
</script>
{% endblock %}
Required Flask setup (app.py):
- Pass `nonce` into every render_template() call via a context processor
- Pass `user` dict from _get_user() helper
- Pass `config` dict with APP_NAME, etc.
Context processor example:
@app.context_processor
def inject_globals():
import base64, os
nonce = base64.b64encode(os.urandom(16)).decode()
return dict(nonce=nonce, user=_get_user(), config=_config())
#}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Dashboard{% endblock %} — {{ config.get('app_name', 'LotusGuild') }}</title>
<meta name="description" content="LotusGuild infrastructure management">
<!-- Unified design system CSS -->
<link rel="stylesheet" href="{{ url_for('static', filename='../web_template/base.css') }}">
<!-- App-specific CSS -->
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<link rel="icon" href="{{ url_for('static', filename='favicon.png') }}" type="image/png">
</head>
<body>
<!-- Boot overlay -->
<div id="lt-boot" class="lt-boot-overlay"
data-app-name="{{ config.get('app_name', 'APP') | upper }}"
style="display:none">
<pre id="lt-boot-text" class="lt-boot-text"></pre>
</div>
<!-- =========================================================
HEADER
========================================================= -->
<header class="lt-header">
<div class="lt-header-left">
<div class="lt-brand">
<a href="{{ url_for('index') }}" class="lt-brand-title" style="text-decoration:none">
{{ config.get('app_name', 'APP') | upper }}
</a>
<span class="lt-brand-subtitle">{{ config.get('app_subtitle', 'LotusGuild Infrastructure') }}</span>
</div>
<nav class="lt-nav" aria-label="Main navigation">
{# Each page sets {% block active_nav %}pagename{% endblock %} #}
{% set active = self.active_nav() | default('') %}
<a href="{{ url_for('index') }}"
class="lt-nav-link {% if active == 'dashboard' %}active{% endif %}">
Dashboard
</a>
<a href="{{ url_for('links_page') }}"
class="lt-nav-link {% if active == 'links' %}active{% endif %}">
Link Debug
</a>
<a href="{{ url_for('inspector') }}"
class="lt-nav-link {% if active == 'inspector' %}active{% endif %}">
Inspector
</a>
<a href="{{ url_for('suppressions_page') }}"
class="lt-nav-link {% if active == 'suppressions' %}active{% endif %}">
Suppressions
</a>
</nav>
</div>
<div class="lt-header-right">
{% if user.name or user.username %}
<span class="lt-header-user">{{ user.name or user.username }}</span>
{% endif %}
{% if 'admin' in user.groups %}
<span class="lt-badge-admin">admin</span>
{% endif %}
</div>
</header>
<!-- =========================================================
MAIN CONTENT
========================================================= -->
<main class="lt-main lt-container">
{% block content %}{% endblock %}
</main>
<!-- =========================================================
SCRIPTS
All <script> tags MUST carry the nonce attribute for CSP.
========================================================= -->
<!-- Runtime config (no CSRF needed for Gandalf — SameSite=Strict) -->
<script nonce="{{ nonce }}">
window.APP_CONFIG = {
ticketWebUrl: {{ config.get('ticket_api', {}).get('web_url', 'https://t.lotusguild.org/ticket/') | tojson }},
};
window.CURRENT_USER = {
username: {{ user.username | tojson }},
name: {{ (user.name or user.username) | tojson }},
groups: {{ user.groups | tojson }},
isAdmin: {{ ('admin' in user.groups) | lower }},
};
</script>
<!-- Unified design system JS -->
<script nonce="{{ nonce }}" src="{{ url_for('static', filename='../web_template/base.js') }}"></script>
<!-- App JS -->
<script nonce="{{ nonce }}" src="{{ url_for('static', filename='app.js') }}"></script>
{% block scripts %}{% endblock %}
</body>
</html>
{# ---------------------------------------------------------------
active_nav block — override in each page template:
{% block active_nav %}dashboard{% endblock %}
Values: dashboard | links | inspector | suppressions
--------------------------------------------------------------- #}
{% block active_nav %}{% endblock %}