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:
716
base.html
Normal file
716
base.html
Normal file
@@ -0,0 +1,716 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
LOTUSGUILD TERMINAL DESIGN SYSTEM v1.0 — base.html
|
||||
Reference template showing every component and layout pattern.
|
||||
|
||||
This file is a STATIC DEMO. Framework-specific wiring is in:
|
||||
php/ → PHP / Tinker Tickets
|
||||
python/ → Flask / Jinja2 / GANDALF
|
||||
node/ → Express / EJS / PULSE
|
||||
|
||||
To build a new app, copy one of the framework skeletons from those
|
||||
sub-directories and reference base.css + base.js.
|
||||
-->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>MY APP — LotusGuild</title>
|
||||
<meta name="description" content="LotusGuild infrastructure application">
|
||||
|
||||
<!-- =========================================================
|
||||
Security headers are set server-side. CSP nonce is injected
|
||||
by SecurityHeadersMiddleware (PHP) / helmet (Node) / Flask.
|
||||
All <script> tags need: nonce="NONCE_PLACEHOLDER"
|
||||
========================================================= -->
|
||||
|
||||
<!-- Base design system CSS -->
|
||||
<link rel="stylesheet" href="/web_template/base.css">
|
||||
<!--
|
||||
App-specific CSS (override or extend after base.css):
|
||||
<link rel="stylesheet" href="/assets/css/app.css">
|
||||
-->
|
||||
|
||||
<link rel="icon" href="/assets/images/favicon.png" type="image/png">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- ===========================================================
|
||||
BOOT SEQUENCE OVERLAY
|
||||
Displays once per session. Remove if not desired.
|
||||
data-app-name → used in the boot text banner.
|
||||
=========================================================== -->
|
||||
<div id="lt-boot" class="lt-boot-overlay" data-app-name="MY APP" style="display:none">
|
||||
<pre id="lt-boot-text" class="lt-boot-text"></pre>
|
||||
</div>
|
||||
|
||||
<!-- ===========================================================
|
||||
HEADER
|
||||
=========================================================== -->
|
||||
<header class="lt-header">
|
||||
<div class="lt-header-left">
|
||||
|
||||
<!-- Brand -->
|
||||
<div class="lt-brand">
|
||||
<span class="lt-brand-title">MY APP</span>
|
||||
<span class="lt-brand-subtitle">LotusGuild Infrastructure</span>
|
||||
</div>
|
||||
|
||||
<!-- Horizontal nav links -->
|
||||
<nav class="lt-nav" aria-label="Main navigation">
|
||||
<a href="/" class="lt-nav-link active">Dashboard</a>
|
||||
<a href="/tickets" class="lt-nav-link">Tickets</a>
|
||||
<a href="/workers" class="lt-nav-link">Workers</a>
|
||||
|
||||
<!-- Dropdown example (admin menu) -->
|
||||
<div class="lt-nav-dropdown">
|
||||
<a href="#" class="lt-nav-link">Admin ▾</a>
|
||||
<ul class="lt-nav-dropdown-menu">
|
||||
<li><a href="/admin/templates">Templates</a></li>
|
||||
<li><a href="/admin/workflow">Workflow</a></li>
|
||||
<li><a href="/admin/audit-log">Audit Log</a></li>
|
||||
<li><a href="/admin/api-keys">API Keys</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="lt-header-right">
|
||||
<!-- Current user -->
|
||||
<span class="lt-header-user">operator</span>
|
||||
<!-- Admin badge (only show for admins) -->
|
||||
<span class="lt-badge-admin">admin</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- ===========================================================
|
||||
MAIN CONTENT AREA
|
||||
=========================================================== -->
|
||||
<main class="lt-main lt-container">
|
||||
|
||||
<!-- Page title bar -->
|
||||
<div class="lt-page-header">
|
||||
<h1 class="lt-page-title">Dashboard</h1>
|
||||
<div class="lt-btn-group">
|
||||
<a href="/create" class="lt-btn lt-btn-primary">New Ticket</a>
|
||||
<button class="lt-btn lt-btn-sm" data-modal-open="export-modal">Export</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==========================================================
|
||||
STATS WIDGETS
|
||||
data-filter-key / data-filter-val → wired by lt.statsFilter
|
||||
========================================================== -->
|
||||
<div class="lt-stats-grid">
|
||||
<div class="lt-stat-card active" data-filter-key="status" data-filter-val="Open">
|
||||
<span class="lt-stat-icon">📋</span>
|
||||
<div class="lt-stat-info">
|
||||
<span class="lt-stat-value">42</span>
|
||||
<span class="lt-stat-label">Open</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lt-stat-card" data-filter-key="priority" data-filter-val="1">
|
||||
<span class="lt-stat-icon">🔴</span>
|
||||
<div class="lt-stat-info">
|
||||
<span class="lt-stat-value">3</span>
|
||||
<span class="lt-stat-label">Critical</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lt-stat-card" data-filter-key="assigned_to" data-filter-val="0">
|
||||
<span class="lt-stat-icon">👤</span>
|
||||
<div class="lt-stat-info">
|
||||
<span class="lt-stat-value">11</span>
|
||||
<span class="lt-stat-label">Unassigned</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lt-stat-card" data-filter-key="created" data-filter-val="today">
|
||||
<span class="lt-stat-icon">📅</span>
|
||||
<div class="lt-stat-info">
|
||||
<span class="lt-stat-value">7</span>
|
||||
<span class="lt-stat-label">Today</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==========================================================
|
||||
TAB NAVIGATION
|
||||
========================================================== -->
|
||||
<div class="lt-tabs">
|
||||
<button class="lt-tab active" data-tab="tab-table">Table View</button>
|
||||
<button class="lt-tab" data-tab="tab-kanban">Kanban</button>
|
||||
<button class="lt-tab" data-tab="tab-workers">Workers</button>
|
||||
</div>
|
||||
|
||||
<!-- ==========================================================
|
||||
SIDEBAR + CONTENT LAYOUT
|
||||
========================================================== -->
|
||||
<div class="lt-layout">
|
||||
|
||||
<!-- Sidebar filter panel -->
|
||||
<aside class="lt-sidebar" id="lt-sidebar">
|
||||
<div class="lt-sidebar-header">
|
||||
Filters
|
||||
<button class="lt-sidebar-toggle" data-sidebar-toggle="lt-sidebar"
|
||||
aria-label="Collapse filters">◀</button>
|
||||
</div>
|
||||
<div class="lt-sidebar-body">
|
||||
|
||||
<div class="lt-filter-group">
|
||||
<span class="lt-filter-label">Status</span>
|
||||
<label class="lt-filter-option">
|
||||
<input type="checkbox" class="lt-checkbox" checked> Open
|
||||
</label>
|
||||
<label class="lt-filter-option">
|
||||
<input type="checkbox" class="lt-checkbox"> Pending
|
||||
</label>
|
||||
<label class="lt-filter-option">
|
||||
<input type="checkbox" class="lt-checkbox"> In Progress
|
||||
</label>
|
||||
<label class="lt-filter-option">
|
||||
<input type="checkbox" class="lt-checkbox"> Closed
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="lt-filter-group">
|
||||
<span class="lt-filter-label">Priority</span>
|
||||
<label class="lt-filter-option">
|
||||
<input type="checkbox" class="lt-checkbox"> P1 Critical
|
||||
</label>
|
||||
<label class="lt-filter-option">
|
||||
<input type="checkbox" class="lt-checkbox"> P2 High
|
||||
</label>
|
||||
<label class="lt-filter-option">
|
||||
<input type="checkbox" class="lt-checkbox"> P3 Medium
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="lt-filter-group">
|
||||
<span class="lt-filter-label">Assigned To</span>
|
||||
<div class="lt-form-group">
|
||||
<select class="lt-select lt-btn-sm">
|
||||
<option value="">All users</option>
|
||||
<option>operator</option>
|
||||
<option>admin</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lt-btn-group">
|
||||
<button class="lt-btn lt-btn-sm">Apply</button>
|
||||
<button class="lt-btn lt-btn-sm lt-btn-ghost">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- Main content -->
|
||||
<div class="lt-content">
|
||||
|
||||
<!-- Toolbar: search + actions -->
|
||||
<div class="lt-toolbar">
|
||||
<div class="lt-toolbar-left">
|
||||
<div class="lt-search">
|
||||
<input type="search" class="lt-input lt-search-input"
|
||||
placeholder="Search tickets..." aria-label="Search">
|
||||
</div>
|
||||
<button class="lt-btn lt-btn-sm">Advanced ▾</button>
|
||||
</div>
|
||||
<div class="lt-toolbar-right">
|
||||
<span class="lt-text-muted lt-text-xs">42 results</span>
|
||||
<button class="lt-btn lt-btn-sm lt-btn-ghost">Bulk Actions</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================================================
|
||||
TAB PANEL: TABLE VIEW
|
||||
================================================== -->
|
||||
<div id="tab-table" class="lt-tab-panel active">
|
||||
|
||||
<!-- Outer ASCII frame wrapping the table -->
|
||||
<div class="lt-frame">
|
||||
<span class="lt-frame-bl">╚</span>
|
||||
<span class="lt-frame-br">╝</span>
|
||||
|
||||
<div class="lt-section-header">Ticket Queue</div>
|
||||
|
||||
<div class="lt-table-wrap">
|
||||
<table class="lt-table" id="ticket-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><input type="checkbox" class="lt-checkbox" aria-label="Select all"></th>
|
||||
<th data-sort-key="id">ID</th>
|
||||
<th data-sort-key="priority">Priority</th>
|
||||
<th data-sort-key="title">Title</th>
|
||||
<th data-sort-key="status">Status</th>
|
||||
<th data-sort-key="assignee">Assignee</th>
|
||||
<th data-sort-key="created">Created</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<!-- P1 Critical row -->
|
||||
<tr class="lt-row-p1 lt-row-critical">
|
||||
<td><input type="checkbox" class="lt-checkbox"></td>
|
||||
<td><a href="/ticket/123456789">#123456789</a></td>
|
||||
<td><span class="lt-p1">P1 Critical</span></td>
|
||||
<td>Storage array link-down on compute-storage-01</td>
|
||||
<td><span class="lt-status lt-status-open">Open</span></td>
|
||||
<td class="lt-text-muted">Unassigned</td>
|
||||
<td class="lt-text-xs lt-text-muted">5m ago</td>
|
||||
<td>
|
||||
<div class="lt-btn-group">
|
||||
<a href="/ticket/123456789" class="lt-btn lt-btn-sm">View</a>
|
||||
<button class="lt-btn lt-btn-sm lt-btn-danger">Close</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- P2 High row -->
|
||||
<tr class="lt-row-p2 lt-row-warning">
|
||||
<td><input type="checkbox" class="lt-checkbox"></td>
|
||||
<td><a href="/ticket/987654321">#987654321</a></td>
|
||||
<td><span class="lt-p2">P2 High</span></td>
|
||||
<td>Switch port flapping on USW-Pro-24</td>
|
||||
<td><span class="lt-status lt-status-in-progress">In Progress</span></td>
|
||||
<td>operator</td>
|
||||
<td class="lt-text-xs lt-text-muted">2h ago</td>
|
||||
<td>
|
||||
<div class="lt-btn-group">
|
||||
<a href="/ticket/987654321" class="lt-btn lt-btn-sm">View</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- P3 Medium row -->
|
||||
<tr class="lt-row-p3">
|
||||
<td><input type="checkbox" class="lt-checkbox"></td>
|
||||
<td><a href="/ticket/111222333">#111222333</a></td>
|
||||
<td><span class="lt-p3">P3 Med</span></td>
|
||||
<td>Scheduled maintenance: replace SFP+ on large1</td>
|
||||
<td><span class="lt-status lt-status-pending">Pending</span></td>
|
||||
<td>admin</td>
|
||||
<td class="lt-text-xs lt-text-muted">1d ago</td>
|
||||
<td>
|
||||
<div class="lt-btn-group">
|
||||
<a href="/ticket/111222333" class="lt-btn lt-btn-sm">View</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- P4 closed -->
|
||||
<tr class="lt-row-p4">
|
||||
<td><input type="checkbox" class="lt-checkbox"></td>
|
||||
<td><a href="/ticket/444555666">#444555666</a></td>
|
||||
<td><span class="lt-p4">P4 Low</span></td>
|
||||
<td>Update SSL cert on wiki.lotusguild.org</td>
|
||||
<td><span class="lt-status lt-status-closed">Closed</span></td>
|
||||
<td>operator</td>
|
||||
<td class="lt-text-xs lt-text-muted">3d ago</td>
|
||||
<td>
|
||||
<div class="lt-btn-group">
|
||||
<a href="/ticket/444555666" class="lt-btn lt-btn-sm">View</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div><!-- /.lt-frame -->
|
||||
|
||||
</div><!-- /#tab-table -->
|
||||
|
||||
<!-- ==================================================
|
||||
TAB PANEL: KANBAN
|
||||
================================================== -->
|
||||
<div id="tab-kanban" class="lt-tab-panel">
|
||||
<div class="lt-grid-4">
|
||||
|
||||
<!-- Kanban column: Open -->
|
||||
<div class="lt-frame">
|
||||
<span class="lt-frame-bl">╚</span>
|
||||
<span class="lt-frame-br">╝</span>
|
||||
<div class="lt-section-header">Open</div>
|
||||
<div class="lt-section-body">
|
||||
|
||||
<div class="lt-card lt-mb-md lt-row-p1">
|
||||
<div class="lt-flex lt-flex-between lt-mb-md">
|
||||
<span class="lt-p1">P1</span>
|
||||
<span class="lt-dot lt-dot-up"></span>
|
||||
</div>
|
||||
<div class="lt-text-sm">Storage array link-down</div>
|
||||
<div class="lt-text-xs lt-text-muted lt-mt-sm">5m ago · Unassigned</div>
|
||||
</div>
|
||||
|
||||
<div class="lt-card lt-row-p3">
|
||||
<div class="lt-flex lt-flex-between lt-mb-md">
|
||||
<span class="lt-p3">P3</span>
|
||||
<span class="lt-dot lt-dot-up"></span>
|
||||
</div>
|
||||
<div class="lt-text-sm">Update node_exporter on micro1</div>
|
||||
<div class="lt-text-xs lt-text-muted lt-mt-sm">1d ago · operator</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Kanban column: Pending -->
|
||||
<div class="lt-frame">
|
||||
<span class="lt-frame-bl">╚</span>
|
||||
<span class="lt-frame-br">╝</span>
|
||||
<div class="lt-section-header">Pending</div>
|
||||
<div class="lt-section-body">
|
||||
<div class="lt-card lt-row-p2">
|
||||
<div class="lt-flex lt-flex-between lt-mb-md">
|
||||
<span class="lt-p2">P2</span>
|
||||
<span class="lt-dot lt-dot-warn"></span>
|
||||
</div>
|
||||
<div class="lt-text-sm">Scheduled maintenance window</div>
|
||||
<div class="lt-text-xs lt-text-muted lt-mt-sm">2d ago · admin</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Kanban column: In Progress -->
|
||||
<div class="lt-frame">
|
||||
<span class="lt-frame-bl">╚</span>
|
||||
<span class="lt-frame-br">╝</span>
|
||||
<div class="lt-section-header">In Progress</div>
|
||||
<div class="lt-section-body">
|
||||
<div class="lt-card lt-row-p2 lt-item-running">
|
||||
<div class="lt-flex lt-flex-between lt-mb-md">
|
||||
<span class="lt-p2">P2</span>
|
||||
<span class="lt-dot lt-dot-warn"></span>
|
||||
</div>
|
||||
<div class="lt-text-sm">Switch port flapping on USW-Pro</div>
|
||||
<div class="lt-text-xs lt-text-muted lt-mt-sm">2h ago · operator</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Kanban column: Closed -->
|
||||
<div class="lt-frame">
|
||||
<span class="lt-frame-bl">╚</span>
|
||||
<span class="lt-frame-br">╝</span>
|
||||
<div class="lt-section-header">Closed</div>
|
||||
<div class="lt-section-body">
|
||||
<div class="lt-card lt-row-p4" style="opacity:0.6">
|
||||
<div class="lt-flex lt-flex-between lt-mb-md">
|
||||
<span class="lt-p4">P4</span>
|
||||
<span class="lt-dot lt-dot-idle"></span>
|
||||
</div>
|
||||
<div class="lt-text-sm">Update SSL cert on wiki</div>
|
||||
<div class="lt-text-xs lt-text-muted lt-mt-sm">3d ago · operator</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div><!-- /.lt-grid-4 -->
|
||||
</div><!-- /#tab-kanban -->
|
||||
|
||||
<!-- ==================================================
|
||||
TAB PANEL: WORKERS
|
||||
================================================== -->
|
||||
<div id="tab-workers" class="lt-tab-panel">
|
||||
<div class="lt-grid-3">
|
||||
|
||||
<div class="lt-card">
|
||||
<div class="lt-flex lt-flex-between lt-mb-md">
|
||||
<span class="lt-text-amber lt-text-upper">pulse-worker-01</span>
|
||||
<span class="lt-status lt-status-online">Online</span>
|
||||
</div>
|
||||
<div class="lt-data-table-wrapper">
|
||||
<table class="lt-data-table">
|
||||
<tr><td class="lt-text-muted">CPU</td> <td>12%</td></tr>
|
||||
<tr><td class="lt-text-muted">Memory</td> <td>2.1 GB / 8 GB</td></tr>
|
||||
<tr><td class="lt-text-muted">Load</td> <td>0.42 / 0.51 / 0.48</td></tr>
|
||||
<tr><td class="lt-text-muted">Uptime</td> <td>14d 6h</td></tr>
|
||||
<tr><td class="lt-text-muted">Tasks</td> <td>2 / 5</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lt-card">
|
||||
<div class="lt-flex lt-flex-between lt-mb-md">
|
||||
<span class="lt-text-amber lt-text-upper">pulse-worker-02</span>
|
||||
<span class="lt-status lt-status-offline">Offline</span>
|
||||
</div>
|
||||
<div class="lt-msg lt-msg-warning">Last seen 14m ago</div>
|
||||
</div>
|
||||
|
||||
<div class="lt-card">
|
||||
<div class="lt-empty">No more workers registered.</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div><!-- /#tab-workers -->
|
||||
|
||||
</div><!-- /.lt-content -->
|
||||
</div><!-- /.lt-layout -->
|
||||
|
||||
|
||||
<!-- ==========================================================
|
||||
COMPONENT SHOWCASE (remove in production)
|
||||
========================================================== -->
|
||||
<div class="lt-divider"></div>
|
||||
|
||||
<!-- Inner frame + subsection example -->
|
||||
<div class="lt-frame">
|
||||
<span class="lt-frame-bl">╚</span>
|
||||
<span class="lt-frame-br">╝</span>
|
||||
<div class="lt-section-header">Component Reference</div>
|
||||
|
||||
<div class="lt-frame-inner">
|
||||
<div class="lt-subsection-header">Buttons</div>
|
||||
<div class="lt-section-body">
|
||||
<div class="lt-btn-group">
|
||||
<button class="lt-btn">Default</button>
|
||||
<button class="lt-btn lt-btn-primary">Primary</button>
|
||||
<button class="lt-btn lt-btn-danger">Danger</button>
|
||||
<button class="lt-btn lt-btn-sm">Small</button>
|
||||
<button class="lt-btn lt-btn-ghost">Ghost</button>
|
||||
<button class="lt-btn" disabled>Disabled</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lt-subsection-header">Status Badges</div>
|
||||
<div class="lt-section-body lt-flex lt-flex-wrap lt-gap-md">
|
||||
<span class="lt-status lt-status-open">Open</span>
|
||||
<span class="lt-status lt-status-pending">Pending</span>
|
||||
<span class="lt-status lt-status-in-progress">In Progress</span>
|
||||
<span class="lt-status lt-status-closed">Closed</span>
|
||||
<span class="lt-status lt-status-online">Online</span>
|
||||
<span class="lt-status lt-status-offline">Offline</span>
|
||||
<span class="lt-status lt-status-running">Running</span>
|
||||
<span class="lt-status lt-status-completed">Completed</span>
|
||||
<span class="lt-status lt-status-failed">Failed</span>
|
||||
</div>
|
||||
|
||||
<div class="lt-subsection-header">Priority Badges</div>
|
||||
<div class="lt-section-body lt-flex lt-flex-wrap lt-gap-md">
|
||||
<span class="lt-priority lt-p1">P1 Critical</span>
|
||||
<span class="lt-priority lt-p2">P2 High</span>
|
||||
<span class="lt-priority lt-p3">P3 Med</span>
|
||||
<span class="lt-priority lt-p4">P4 Low</span>
|
||||
<span class="lt-priority lt-p5">P5 Min</span>
|
||||
</div>
|
||||
|
||||
<div class="lt-subsection-header">Chips & Badges</div>
|
||||
<div class="lt-section-body lt-flex lt-flex-wrap lt-gap-sm">
|
||||
<span class="lt-chip lt-chip-ok">OK</span>
|
||||
<span class="lt-chip lt-chip-warn">Warning</span>
|
||||
<span class="lt-chip lt-chip-critical">Critical</span>
|
||||
<span class="lt-chip lt-chip-info">Info</span>
|
||||
<span class="lt-badge lt-badge-green">v1.0</span>
|
||||
<span class="lt-badge lt-badge-amber">Beta</span>
|
||||
<span class="lt-badge lt-badge-red">Deprecated</span>
|
||||
<span class="lt-badge-admin">admin</span>
|
||||
</div>
|
||||
|
||||
<div class="lt-subsection-header">Status Dots</div>
|
||||
<div class="lt-section-body lt-flex lt-gap-md">
|
||||
<span class="lt-flex lt-gap-sm"><span class="lt-dot lt-dot-up"></span> Up</span>
|
||||
<span class="lt-flex lt-gap-sm"><span class="lt-dot lt-dot-down"></span> Down</span>
|
||||
<span class="lt-flex lt-gap-sm"><span class="lt-dot lt-dot-warn"></span> Degraded</span>
|
||||
<span class="lt-flex lt-gap-sm"><span class="lt-dot lt-dot-idle"></span> Idle</span>
|
||||
</div>
|
||||
|
||||
<div class="lt-subsection-header">Inline Messages</div>
|
||||
<div class="lt-section-body">
|
||||
<div class="lt-msg lt-msg-error">Database connection refused on 10.10.10.50</div>
|
||||
<div class="lt-msg lt-msg-success">Ticket #123456789 updated successfully</div>
|
||||
<div class="lt-msg lt-msg-warning">Rate limit: 80% consumed (40/50 req/min)</div>
|
||||
<div class="lt-msg lt-msg-info">Auto-refresh active — updates every 30s</div>
|
||||
</div>
|
||||
|
||||
<div class="lt-subsection-header">Forms</div>
|
||||
<div class="lt-section-body">
|
||||
<div class="lt-grid-2">
|
||||
<div>
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label lt-label-required" for="eg-title">Ticket Title</label>
|
||||
<input id="eg-title" type="text" class="lt-input" placeholder="Describe the issue">
|
||||
</div>
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label" for="eg-priority">Priority</label>
|
||||
<select id="eg-priority" class="lt-select">
|
||||
<option>P1 — Critical</option>
|
||||
<option>P2 — High</option>
|
||||
<option selected>P3 — Medium</option>
|
||||
<option>P4 — Low</option>
|
||||
<option>P5 — Minimal</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label" for="eg-desc">Description</label>
|
||||
<textarea id="eg-desc" class="lt-textarea" placeholder="Markdown supported..."></textarea>
|
||||
<span class="lt-form-hint">Markdown supported. Use #123456789 to link tickets.</span>
|
||||
</div>
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label">
|
||||
<input type="checkbox" class="lt-checkbox"> Confidential ticket
|
||||
</label>
|
||||
</div>
|
||||
<div class="lt-btn-group">
|
||||
<button class="lt-btn lt-btn-primary">Submit</button>
|
||||
<button class="lt-btn lt-btn-ghost">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="lt-search lt-form-group">
|
||||
<label class="lt-label" for="eg-search">Search</label>
|
||||
<input id="eg-search" type="search" class="lt-input lt-search-input"
|
||||
placeholder="Ctrl+K to focus">
|
||||
</div>
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label">Loading state (skeleton)</label>
|
||||
<div class="lt-skeleton lt-p-md" style="height:40px"></div>
|
||||
</div>
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label">Empty state</label>
|
||||
<div class="lt-empty" style="padding:1rem">No results found</div>
|
||||
</div>
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label">Loading indicator</label>
|
||||
<div class="lt-loading" style="padding:1rem"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lt-subsection-header">Log / Timeline Entries</div>
|
||||
<div class="lt-section-body">
|
||||
<div class="lt-log-entry success">
|
||||
<div class="lt-log-ts">2026-03-14 09:12:33 EDT</div>
|
||||
<strong>Status changed:</strong> Open → In Progress by operator
|
||||
</div>
|
||||
<div class="lt-log-entry warning">
|
||||
<div class="lt-log-ts">2026-03-14 09:10:11 EDT</div>
|
||||
<strong>Priority escalated:</strong> P3 → P1 by GANDALF auto-alert
|
||||
</div>
|
||||
<div class="lt-log-entry error">
|
||||
<div class="lt-log-ts">2026-03-14 09:09:55 EDT</div>
|
||||
<strong>Alert triggered:</strong> NIC link-down on large1:enp35s0
|
||||
<div class="lt-log-output">node_exporter metric: node_network_up{interface="enp35s0"} = 0</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div><!-- /.lt-frame-inner -->
|
||||
</div><!-- /.lt-frame (component showcase) -->
|
||||
|
||||
</main><!-- /.lt-main -->
|
||||
|
||||
|
||||
<!-- ===========================================================
|
||||
TOAST DEMO BUTTONS (remove in production)
|
||||
=========================================================== -->
|
||||
<div style="position:fixed;bottom:1rem;left:1rem;display:flex;flex-direction:column;gap:0.5rem;z-index:900">
|
||||
<button class="lt-btn lt-btn-sm" onclick="lt.toast.success('Ticket saved successfully')">✓ Toast</button>
|
||||
<button class="lt-btn lt-btn-sm lt-btn-danger" onclick="lt.toast.error('Network error — retry in 5s', 5000)">✗ Error</button>
|
||||
<button class="lt-btn lt-btn-sm" onclick="lt.toast.warning('Rate limit 80% used')">! Warn</button>
|
||||
<button class="lt-btn lt-btn-sm lt-btn-ghost" onclick="lt.toast.info('Auto-refresh triggered')">i Info</button>
|
||||
</div>
|
||||
|
||||
<!-- ===========================================================
|
||||
MODAL EXAMPLE: Export
|
||||
=========================================================== -->
|
||||
<div id="export-modal" class="lt-modal-overlay" aria-hidden="true">
|
||||
<div class="lt-modal">
|
||||
<div class="lt-modal-header">
|
||||
<span class="lt-modal-title">Export Tickets</span>
|
||||
<button class="lt-modal-close" data-modal-close aria-label="Close">✕</button>
|
||||
</div>
|
||||
<div class="lt-modal-body">
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label" for="export-fmt">Format</label>
|
||||
<select id="export-fmt" class="lt-select">
|
||||
<option>CSV</option>
|
||||
<option>JSON</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label">
|
||||
<input type="checkbox" class="lt-checkbox" checked> Selected tickets only
|
||||
</label>
|
||||
</div>
|
||||
<div class="lt-msg lt-msg-info">Exports include all visible columns.</div>
|
||||
</div>
|
||||
<div class="lt-modal-footer">
|
||||
<button class="lt-btn lt-btn-ghost" data-modal-close>Cancel</button>
|
||||
<button class="lt-btn lt-btn-primary" onclick="lt.toast.success('Export started'); lt.modal.close('export-modal')">Export</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===========================================================
|
||||
MODAL EXAMPLE: Keyboard shortcuts help
|
||||
=========================================================== -->
|
||||
<div id="lt-keys-help" class="lt-modal-overlay" aria-hidden="true">
|
||||
<div class="lt-modal">
|
||||
<div class="lt-modal-header">
|
||||
<span class="lt-modal-title">Keyboard Shortcuts</span>
|
||||
<button class="lt-modal-close" data-modal-close aria-label="Close">✕</button>
|
||||
</div>
|
||||
<div class="lt-modal-body">
|
||||
<table class="lt-data-table" style="width:100%">
|
||||
<thead>
|
||||
<tr><th>Shortcut</th><th>Action</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Ctrl / ⌘ + K</td><td>Focus search box</td></tr>
|
||||
<tr><td>Ctrl / ⌘ + E</td><td>Toggle edit mode (ticket page)</td></tr>
|
||||
<tr><td>Ctrl / ⌘ + S</td><td>Save changes (ticket page)</td></tr>
|
||||
<tr><td>j / ↓</td><td>Select next row</td></tr>
|
||||
<tr><td>k / ↑</td><td>Select previous row</td></tr>
|
||||
<tr><td>Enter</td><td>Open selected ticket</td></tr>
|
||||
<tr><td>n</td><td>New ticket</td></tr>
|
||||
<tr><td>?</td><td>Show this help</td></tr>
|
||||
<tr><td>ESC</td><td>Close modal / cancel</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="lt-modal-footer">
|
||||
<button class="lt-btn" data-modal-close>Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===========================================================
|
||||
SCRIPTS
|
||||
=========================================================== -->
|
||||
|
||||
<!--
|
||||
PHP apps inject CSRF token + config here (with CSP nonce):
|
||||
<script nonce="<?php echo $nonce; ?>">
|
||||
window.CSRF_TOKEN = '<?php echo CsrfMiddleware::getToken(); ?>';
|
||||
window.APP_TIMEZONE = '<?php echo $config['TIMEZONE']; ?>';
|
||||
</script>
|
||||
|
||||
Node/Express (EJS):
|
||||
<script nonce="<%= nonce %>">
|
||||
window.CSRF_TOKEN = '<%= csrfToken %>';
|
||||
</script>
|
||||
|
||||
Flask/Jinja2:
|
||||
<script nonce="{{ nonce }}">
|
||||
window.CSRF_TOKEN = '{{ csrf_token() }}';
|
||||
</script>
|
||||
-->
|
||||
|
||||
<!-- Base design system JS -->
|
||||
<script src="/web_template/base.js"></script>
|
||||
|
||||
<!--
|
||||
App-specific JS:
|
||||
<script nonce="NONCE" src="/assets/js/app.js?v=20260314"></script>
|
||||
|
||||
Wire up sortable table after load:
|
||||
<script nonce="NONCE">
|
||||
lt.sortTable.init('ticket-table');
|
||||
lt.tableNav.init('ticket-table');
|
||||
lt.keys.on('n', () => window.location.href = '/create');
|
||||
</script>
|
||||
-->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user