Files
skeleton-api/app/templates/_nav.html
T

237 lines
10 KiB
HTML

{% set su = user.is_superuser %}
{% set p = user.permissions %}
{% set can_admin = su or "users:read" in p or "roles:read" in p or "audit_log:read" in p %}
{% set can_connections = su or "clamp_connections:read" in p or "iso_threads:read" in p or "static_connections:read" in p or "unc_threads:read" in p %}
{% set can_labels = su or "attachment_point_names:read" in p or "manufacturers:read" in p or "part_colours:read" in p or "part_types:read" in p or "scope_models:read" in p or "sub_part_types:read" in p %}
{% set can_database = su or "imported_parts:read" in p or "augmented_parts:read" in p or "attachment_points:read" in p %}
{% set can_parts = can_connections or can_labels or can_database %}
{% set can_scopes = su or ("augmented_parts:read" in p and "fits:read" in p) %}
{# ── SVG icon sprite ───────────────────────────────────────────────────────── #}
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
<symbol id="icon-home" viewBox="0 0 24 24">
<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
<polyline points="9 22 9 12 15 12 15 22"/>
</symbol>
<symbol id="icon-shield" viewBox="0 0 24 24">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
</symbol>
<symbol id="icon-user" viewBox="0 0 24 24">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
<circle cx="12" cy="7" r="4"/>
</symbol>
<symbol id="icon-lock" viewBox="0 0 24 24">
<rect width="18" height="11" x="3" y="11" rx="2" ry="2"/>
<path d="M7 11V7a5 5 0 0 1 10 0v4"/>
</symbol>
<symbol id="icon-list-checks" viewBox="0 0 24 24">
<path d="m3 17 2 2 4-4"/><path d="m3 7 2 2 4-4"/>
<path d="M13 6h8"/><path d="M13 12h8"/><path d="M13 18h8"/>
</symbol>
<symbol id="icon-package" viewBox="0 0 24 24">
<path d="M16.5 9.4 7.55 4.24"/>
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/>
<polyline points="3.27 6.96 12 12.01 20.73 6.96"/>
<line x1="12" x2="12" y1="22.08" y2="12"/>
</symbol>
<symbol id="icon-link-2" viewBox="0 0 24 24">
<path d="M9 17H7A5 5 0 0 1 7 7h2"/>
<path d="M15 7h2a5 5 0 1 1 0 10h-2"/>
<line x1="8" x2="16" y1="12" y2="12"/>
</symbol>
<symbol id="icon-maximize-2" viewBox="0 0 24 24">
<polyline points="15 3 21 3 21 9"/>
<polyline points="9 21 3 21 3 15"/>
<line x1="21" x2="14" y1="3" y2="10"/>
<line x1="3" x2="10" y1="21" y2="14"/>
</symbol>
<symbol id="icon-settings-2" viewBox="0 0 24 24">
<path d="M20 7h-9"/><path d="M14 17H5"/>
<circle cx="17" cy="17" r="3"/><circle cx="7" cy="7" r="3"/>
</symbol>
<symbol id="icon-minus-circle" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="10"/>
<line x1="8" x2="16" y1="12" y2="12"/>
</symbol>
<symbol id="icon-wrench" viewBox="0 0 24 24">
<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>
</symbol>
<symbol id="icon-tag" viewBox="0 0 24 24">
<path d="M12 2H2v10l9.29 9.29c.94.94 2.48.94 3.42 0l6.58-6.58c.94-.94.94-2.48 0-3.42L12 2Z"/>
<path d="M7 7h.01"/>
</symbol>
<symbol id="icon-building-2" viewBox="0 0 24 24">
<path d="M6 22V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v18Z"/>
<path d="M6 12H4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2"/>
<path d="M18 9h2a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-2"/>
<path d="M10 6h4"/><path d="M10 10h4"/><path d="M10 14h4"/><path d="M10 18h4"/>
</symbol>
<symbol id="icon-droplet" viewBox="0 0 24 24">
<path d="M12 22a7 7 0 0 0 7-7c0-2-1-3.9-3-5.5s-3.5-4-4-6.5c-.5 2.5-2 4.9-4 6.5C6 11.1 5 13 5 15a7 7 0 0 0 7 7z"/>
</symbol>
<symbol id="icon-crosshair" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="10"/>
<line x1="22" x2="18" y1="12" y2="12"/>
<line x1="6" x2="2" y1="12" y2="12"/>
<line x1="12" x2="12" y1="6" y2="2"/>
<line x1="12" x2="12" y1="22" y2="18"/>
</symbol>
<symbol id="icon-corner-down-right" viewBox="0 0 24 24">
<polyline points="15 10 20 15 15 20"/>
<path d="M4 4v7a4 4 0 0 0 4 4h12"/>
</symbol>
<symbol id="icon-database" viewBox="0 0 24 24">
<ellipse cx="12" cy="5" rx="9" ry="3"/>
<path d="M3 5v14a9 3 0 0 0 18 0V5"/>
<path d="M3 12a9 3 0 0 0 18 0"/>
</symbol>
<symbol id="icon-download" viewBox="0 0 24 24">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="7 10 12 15 17 10"/>
<line x1="12" x2="12" y1="15" y2="3"/>
</symbol>
<symbol id="icon-layers" viewBox="0 0 24 24">
<polygon points="12 2 2 7 12 12 22 7 12 2"/>
<polyline points="2 17 12 22 22 17"/>
<polyline points="2 12 12 17 22 12"/>
</symbol>
<symbol id="icon-alert-circle" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="10"/>
<line x1="12" x2="12" y1="8" y2="12"/>
<line x1="12" x2="12.01" y1="16" y2="16"/>
</symbol>
<symbol id="icon-book-open" viewBox="0 0 24 24">
<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/>
<path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 0 3-3h7z"/>
</symbol>
<symbol id="icon-map-pin" viewBox="0 0 24 24">
<path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z"/>
<circle cx="12" cy="10" r="3"/>
</symbol>
<symbol id="icon-anchor" viewBox="0 0 24 24">
<circle cx="12" cy="5" r="3"/>
<line x1="12" x2="12" y1="8" y2="22"/>
<path d="M5 12H2a10 10 0 0 0 20 0h-3"/>
</symbol>
<symbol id="icon-upload" viewBox="0 0 24 24">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="17 8 12 3 7 8"/>
<line x1="12" x2="12" y1="3" y2="15"/>
</symbol>
</svg>
{# ── Nav macro for DRY icon use ────────────────────────────────────────────── #}
{% macro icon(id) %}<svg class="nav-icon"><use href="#icon-{{ id }}"/></svg>{% endmacro %}
<header class="topbar">
<div class="brand"><a href="/">{{ app_name }}</a></div>
<nav>
<a href="/">{{ icon("home") }} Dashboard</a>
{% if can_scopes %}
<a href="/scopes">{{ icon("crosshair") }} Scopes</a>
{% endif %}
{% if can_admin %}
<div class="nav-group">
<span class="nav-label">{{ icon("shield") }} Admin ▾</span>
<div class="nav-dropdown">
{% if su or "users:read" in p %}
<a href="/admin/users">{{ icon("user") }} Users</a>
{% endif %}
{% if su or "roles:read" in p %}
<a href="/admin/roles">{{ icon("lock") }} Roles</a>
{% endif %}
{% if su or "audit_log:read" in p %}
<a href="/admin/audit-log">{{ icon("list-checks") }} Audit Log</a>
{% endif %}
</div>
</div>
{% endif %}
{% if can_parts %}
<div class="nav-group">
<span class="nav-label">{{ icon("package") }} Parts ▾</span>
<div class="nav-dropdown">
{% if can_connections %}
<div class="nav-group">
<span class="nav-label">{{ icon("link-2") }} Connections <i class="nav-chevron">▶</i></span>
<div class="nav-dropdown">
{% if su or "clamp_connections:read" in p %}
<a href="/admin/clamp-connections">{{ icon("maximize-2") }} Clamp Connections</a>
{% endif %}
{% if su or "iso_threads:read" in p %}
<a href="/admin/iso-threads">{{ icon("settings-2") }} ISO Threads</a>
{% endif %}
{% if su or "static_connections:read" in p %}
<a href="/admin/static-connections">{{ icon("minus-circle") }} Static Connections</a>
{% endif %}
{% if su or "unc_threads:read" in p %}
<a href="/admin/unc-threads">{{ icon("wrench") }} UNC Threads</a>
{% endif %}
</div>
</div>
{% endif %}
{% if can_labels %}
<div class="nav-group">
<span class="nav-label">{{ icon("tag") }} Labels <i class="nav-chevron">▶</i></span>
<div class="nav-dropdown">
{% if su or "attachment_point_names:read" in p %}
<a href="/admin/attachment-point-names">{{ icon("map-pin") }} Attachment Point Names</a>
{% endif %}
{% if su or "manufacturers:read" in p %}
<a href="/admin/manufacturers">{{ icon("building-2") }} Manufacturers</a>
{% endif %}
{% if su or "part_colours:read" in p %}
<a href="/admin/part-colours">{{ icon("droplet") }} Part Colours</a>
{% endif %}
{% if su or "part_types:read" in p %}
<a href="/admin/part-types">{{ icon("tag") }} Part Types</a>
{% endif %}
{% if su or "scope_models:read" in p %}
<a href="/admin/scope-models">{{ icon("crosshair") }} Scope Models</a>
{% endif %}
{% if su or "sub_part_types:read" in p %}
<a href="/admin/sub-part-types">{{ icon("corner-down-right") }} Sub Part Types</a>
{% endif %}
</div>
</div>
{% endif %}
{% if can_database %}
<div class="nav-group">
<span class="nav-label">{{ icon("database") }} Database <i class="nav-chevron">▶</i></span>
<div class="nav-dropdown">
{% if su or "imported_parts:read" in p %}
<a href="/admin/imported-parts">{{ icon("download") }} Imported Parts</a>
{% endif %}
{% if su or "augmented_parts:read" in p %}
<a href="/admin/augmented-parts">{{ icon("layers") }} Augmented Parts</a>
{% endif %}
{% if su or "attachment_points:read" in p %}
<a href="/admin/attachment-points">{{ icon("anchor") }} Attachment Points</a>
{% endif %}
{% if su or "augmented_parts:write" in p %}
<a href="/admin/augmented-parts/skipped">{{ icon("alert-circle") }} Skipped Parts</a>
{% endif %}
{% if su or "augmented_parts:write" in p %}
<a href="/admin/scope-import">{{ icon("upload") }} Scope Import</a>
{% endif %}
</div>
</div>
{% endif %}
</div>
</div>
{% endif %}
<a href="/docs" target="_blank">{{ icon("book-open") }} API docs</a>
</nav>
<form method="post" action="/logout" class="logout">
<span class="muted">{{ user.email }}</span>
<button type="submit" class="btn btn-ghost">Sign out</button>
</form>
</header>