110 lines
5.9 KiB
Plaintext
110 lines
5.9 KiB
Plaintext
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title><%= title %> - <%= siteTitle %></title>
|
|
<link rel="stylesheet" href="/lumi-tokens.css?v=<%= assetVersion %>" />
|
|
<link rel="stylesheet" href="/styles.css?v=<%= assetVersion %>" />
|
|
<link rel="stylesheet" href="/lumi-layout.css?v=<%= assetVersion %>" />
|
|
<link rel="stylesheet" href="/lumi-components.css?v=<%= assetVersion %>" />
|
|
<%- include("theme-vars", { theme }) %>
|
|
</head>
|
|
<body data-theme-id="<%= theme ? theme.id : '' %>">
|
|
<% const icons = {
|
|
home: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 10.5L12 4l8 6.5V20a1 1 0 0 1-1 1h-5v-6H10v6H5a1 1 0 0 1-1-1z" fill="currentColor"/></svg>',
|
|
spark: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3l2.4 5.6L20 11l-5.6 2.4L12 19l-2.4-5.6L4 11l5.6-2.4z" fill="currentColor"/></svg>',
|
|
shield: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3l7 3v6c0 4.4-3 8.4-7 9-4-0.6-7-4.6-7-9V6z" fill="currentColor"/></svg>',
|
|
gear: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M19.4 13.5l1.7-1-1-1.8-2 0.4a5.9 5.9 0 0 0-1.1-0.6l-0.3-2h-2.1l-0.3 2c-0.4 0.1-0.8 0.3-1.1 0.6l-2-0.4-1 1.8 1.7 1c-0.1 0.4-0.1 0.9 0 1.3l-1.7 1 1 1.8 2-0.4c0.3 0.2 0.7 0.4 1.1 0.6l0.3 2h2.1l0.3-2c0.4-0.1 0.8-0.3 1.1-0.6l2 0.4 1-1.8-1.7-1c0.1-0.4 0.1-0.9 0-1.3zM12 15.4a3.4 3.4 0 1 1 0-6.8 3.4 3.4 0 0 1 0 6.8z" fill="currentColor"/></svg>',
|
|
blocks: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z" fill="currentColor"/></svg>'
|
|
}; %>
|
|
<div class="app-shell">
|
|
<aside class="sidebar">
|
|
<div class="sidebar-brand">
|
|
<a href="/" class="brand-link">
|
|
<span class="logo">
|
|
<% if (botAvatar) { %>
|
|
<img src="<%= botAvatar %>" alt="<%= siteTitle %> bot" class="logo-img" />
|
|
<% } else { %>
|
|
L
|
|
<% } %>
|
|
</span>
|
|
<span class="title"><%= siteTitle %></span>
|
|
</a>
|
|
<button class="icon-button sidebar-toggle" type="button" data-sidebar-toggle aria-label="Toggle sidebar">
|
|
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M8 5v14M16 8l-4 4 4 4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
</button>
|
|
</div>
|
|
<nav class="sidebar-nav">
|
|
<% (navSections || []).forEach((section) => { %>
|
|
<details class="nav-section" <%= section.open ? "open" : "" %>>
|
|
<summary title="<%= section.label %>">
|
|
<span class="nav-icon"><%- icons[section.icon] || "" %></span>
|
|
<span class="nav-text"><%= section.label %></span>
|
|
</summary>
|
|
<div class="nav-links">
|
|
<% section.items.forEach((item) => { %>
|
|
<a href="<%= item.path %>" class="nav-link <%= item.active ? 'active' : '' %>" title="<%= item.label %>">
|
|
<span class="nav-item-icon">
|
|
<% if (item.icon) { %>
|
|
<img src="<%= item.icon %>" alt="" aria-hidden="true" />
|
|
<% } else { %>
|
|
<span class="nav-dot" aria-hidden="true"></span>
|
|
<% } %>
|
|
</span>
|
|
<span class="nav-link-text"><%= item.label %></span>
|
|
</a>
|
|
<% }) %>
|
|
</div>
|
|
</details>
|
|
<% }) %>
|
|
</nav>
|
|
<div class="sidebar-assistant-panels" data-assistant-panel-slot></div>
|
|
<div class="sidebar-footer">
|
|
<% if (user) { %>
|
|
<a href="/profile" class="user-chip user-chip-link" title="View profile">
|
|
<span class="user-avatar <%= userAvatar ? 'has-image' : 'has-fallback' %>">
|
|
<% if (userAvatar) { %>
|
|
<img src="<%= userAvatar %>" alt="<%= user.username %>" />
|
|
<% } else { %>
|
|
<span class="user-initial"><%= userInitial || "?" %></span>
|
|
<% } %>
|
|
</span>
|
|
<span class="user-name"><%= user.username %></span>
|
|
</a>
|
|
<form method="post" action="/auth/logout">
|
|
<button type="submit" class="icon-button" title="Logout" aria-label="Logout">
|
|
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M16 17l5-5-5-5M21 12H9M12 5H5a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h7" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
</button>
|
|
</form>
|
|
<% } else { %>
|
|
<div class="login-actions">
|
|
<% const loginPlatforms = platformLogins || []; %>
|
|
<% if (!loginPlatforms.length) { %>
|
|
<span class="button subtle disabled" title="No platforms are enabled for login">No login platforms enabled</span>
|
|
<% } else { %>
|
|
<% loginPlatforms.forEach((platform, index) => { %>
|
|
<% if (platform.configured) { %>
|
|
<a href="<%= platform.loginPath %>" class="button <%= index === 0 ? '' : 'subtle' %>">Login <%= platform.label %></a>
|
|
<% } else { %>
|
|
<span class="button subtle disabled" title="<%= platform.label %> is not configured">Login <%= platform.label %></span>
|
|
<% } %>
|
|
<% }) %>
|
|
<% } %>
|
|
</div>
|
|
<% } %>
|
|
</div>
|
|
</aside>
|
|
<div class="page">
|
|
<div class="mobile-topbar">
|
|
<button class="icon-button" type="button" data-sidebar-toggle aria-label="Toggle menu">
|
|
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h16" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
|
|
</button>
|
|
<span class="mobile-title"><%= siteTitle %></span>
|
|
</div>
|
|
<main class="content">
|
|
<% if (flash) { %>
|
|
<div class="flash <%= flash.type %>"><%= flash.message %></div>
|
|
<% } %>
|
|
|