fix: accessibility & quality audit pass 4+5
CSS: - Add :active/:focus-visible to .lt-modal-close, .lt-drawer-right-close, .lt-notif-panel-clear, .lt-file-item-remove - Add :focus-visible to .lt-accordion-header, .lt-tag-remove, .lt-combobox-tag-remove - Add .lt-cmd-input-wrap:focus-within focus indicator (outline:none compensation) - Add will-change: stroke-dashoffset to .lt-gauge-fill - Add range slider :focus-visible thumb ring - Fix .tok-cmt hardcoded #5c8c6a → var(--color-tok-cmt) w/ light-mode override - Add .lt-skip-link component (visible on focus) - Fix .lt-filter-group fieldset UA border reset JS: - Fix infinite scroll: store throttled handler ref so removeEventListener works - Fix right drawer: remove close-button listeners in _rdClose (were never removed) - Fix right drawer: add Tab focus trap (matches modal behaviour) - Fix _cmdPaletteClose: restore focus to element that opened the palette - Fix initSortTable: set aria-sort="ascending"/"descending"/"none" on th elements - Fix switchTab: set aria-selected="true"/"false" on .lt-tab[data-tab] buttons - Fix copy button timeout: guard with document.contains() before DOM mutation - Fix combobox: add role=combobox, aria-expanded, aria-controls, role=listbox; toggle aria-expanded on open/close HTML: - Add skip nav link + id="main-content" on <main> - Primary tab nav: add role=tablist, role=tab, aria-selected, aria-controls, id attrs; tab panels get role=tabpanel + aria-labelledby - Tab bar demo: same ARIA wiring + aria-controls + role/labelledby on panels - Sidebar filters: convert div+span to fieldset+legend for proper grouping - Table sort headers: add aria-sort="none" (JS updates on click) - Accordion: add aria-controls on headers, IDs on bodies - Wizard: add aria-current="step" on active step indicator - Table th: scope="col" on all column headers - Row checkboxes: aria-label per ticket ID - Worker metrics table: add <tbody> - Progress bars: role=progressbar + aria-valuenow/min/max + aria-label - Export + keyboard shortcuts modals: role=dialog, aria-modal, aria-labelledby Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
LOTUSGUILD TERMINAL DESIGN SYSTEM v2.0 — base.html
|
||||
LOTUSGUILD TERMINAL DESIGN SYSTEM v1.2 — base.html
|
||||
Reference template showing every component and layout pattern.
|
||||
|
||||
This file is a STATIC DEMO. Framework-specific wiring is in:
|
||||
@@ -21,6 +21,7 @@
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
<title>MY APP — LotusGuild</title>
|
||||
<meta name="description" content="LotusGuild infrastructure application">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
|
||||
<!-- =========================================================
|
||||
Security headers are set server-side. CSP nonce is injected
|
||||
@@ -44,6 +45,8 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a class="lt-skip-link" href="#main-content">Skip to main content</a>
|
||||
|
||||
<!-- ===========================================================
|
||||
BOOT SEQUENCE OVERLAY
|
||||
Displays once per session. Remove if not desired.
|
||||
@@ -59,7 +62,7 @@
|
||||
<!-- ===========================================================
|
||||
MOBILE NAV DRAWER (hidden on desktop, slides in on mobile)
|
||||
=========================================================== -->
|
||||
<div id="lt-nav-drawer" class="lt-nav-drawer" aria-hidden="true" role="dialog" aria-label="Navigation menu">
|
||||
<div id="lt-nav-drawer" class="lt-nav-drawer" aria-hidden="true" role="dialog" aria-modal="true" aria-label="Navigation menu">
|
||||
<div class="lt-nav-drawer-header">
|
||||
<span class="lt-brand-title">MY APP</span>
|
||||
<button class="lt-nav-drawer-close" id="lt-nav-drawer-close" aria-label="Close menu">✕</button>
|
||||
@@ -168,7 +171,7 @@
|
||||
</header>
|
||||
|
||||
<!-- Right-side detail drawer -->
|
||||
<div id="lt-detail-drawer" class="lt-drawer-right" aria-hidden="true" role="dialog" aria-label="Detail panel" data-overlay="lt-detail-overlay">
|
||||
<div id="lt-detail-drawer" class="lt-drawer-right" aria-hidden="true" role="dialog" aria-modal="true" aria-label="Detail panel" data-overlay="lt-detail-overlay">
|
||||
<div class="lt-drawer-right-header">
|
||||
<span class="lt-drawer-right-title">// TICKET DETAIL</span>
|
||||
<button class="lt-drawer-right-close" data-drawer-close aria-label="Close detail panel">✕</button>
|
||||
@@ -224,7 +227,7 @@
|
||||
<div class="lt-form-group" style="margin-bottom:0.5rem">
|
||||
<textarea id="td-comment" class="lt-input lt-textarea" rows="2" placeholder="Leave a comment…" style="resize:vertical"></textarea>
|
||||
</div>
|
||||
<button class="lt-btn lt-btn-sm" onclick="
|
||||
<button type="button" class="lt-btn lt-btn-sm" onclick="
|
||||
const c=document.getElementById('td-comment');
|
||||
if(c.value.trim()){lt.toast.success('Comment posted');c.value='';}
|
||||
else lt.toast.warning('Comment is empty');
|
||||
@@ -248,8 +251,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="lt-drawer-right-footer">
|
||||
<button class="lt-btn lt-btn-sm" onclick="lt.rightDrawer.close('lt-detail-drawer')">Cancel</button>
|
||||
<button class="lt-btn lt-btn-primary lt-btn-sm" onclick="lt.toast.success('Ticket #123456789 updated')">Save Changes</button>
|
||||
<button type="button" class="lt-btn lt-btn-sm" onclick="lt.rightDrawer.close('lt-detail-drawer')">Cancel</button>
|
||||
<button type="button" class="lt-btn lt-btn-primary lt-btn-sm" onclick="lt.toast.success('Ticket #123456789 updated')">Save Changes</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="lt-detail-overlay" class="lt-drawer-right-overlay"></div>
|
||||
@@ -257,7 +260,7 @@
|
||||
<!-- ===========================================================
|
||||
MAIN CONTENT AREA
|
||||
=========================================================== -->
|
||||
<main class="lt-main lt-container">
|
||||
<main class="lt-main lt-container" id="main-content">
|
||||
|
||||
<!-- Page title bar -->
|
||||
<div class="lt-page-header">
|
||||
@@ -306,10 +309,10 @@
|
||||
<!-- ==========================================================
|
||||
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 class="lt-tabs" role="tablist" aria-label="Main views">
|
||||
<button class="lt-tab active" role="tab" data-tab="tab-table" aria-selected="true" aria-controls="tab-table" id="tab-btn-table">Table View</button>
|
||||
<button class="lt-tab" role="tab" data-tab="tab-kanban" aria-selected="false" aria-controls="tab-kanban" id="tab-btn-kanban">Kanban</button>
|
||||
<button class="lt-tab" role="tab" data-tab="tab-workers" aria-selected="false" aria-controls="tab-workers" id="tab-btn-workers">Workers</button>
|
||||
</div>
|
||||
|
||||
<!-- ==========================================================
|
||||
@@ -326,8 +329,8 @@
|
||||
</div>
|
||||
<div class="lt-sidebar-body">
|
||||
|
||||
<div class="lt-filter-group">
|
||||
<span class="lt-filter-label">Status</span>
|
||||
<fieldset class="lt-filter-group">
|
||||
<legend class="lt-filter-label">Status</legend>
|
||||
<label class="lt-filter-option">
|
||||
<input type="checkbox" class="lt-checkbox" checked> Open
|
||||
</label>
|
||||
@@ -340,10 +343,10 @@
|
||||
<label class="lt-filter-option">
|
||||
<input type="checkbox" class="lt-checkbox"> Closed
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="lt-filter-group">
|
||||
<span class="lt-filter-label">Priority</span>
|
||||
<fieldset class="lt-filter-group">
|
||||
<legend class="lt-filter-label">Priority</legend>
|
||||
<label class="lt-filter-option">
|
||||
<input type="checkbox" class="lt-checkbox"> P1 Critical
|
||||
</label>
|
||||
@@ -353,7 +356,7 @@
|
||||
<label class="lt-filter-option">
|
||||
<input type="checkbox" class="lt-checkbox"> P3 Medium
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="lt-filter-group">
|
||||
<span class="lt-filter-label">Assigned To</span>
|
||||
@@ -381,7 +384,7 @@
|
||||
<div class="lt-toolbar-left">
|
||||
<div class="lt-search">
|
||||
<input type="search" class="lt-input lt-search-input" id="ticket-search"
|
||||
placeholder="Search tickets..." aria-label="Search">
|
||||
placeholder="Search tickets..." aria-label="Search" autocomplete="off">
|
||||
</div>
|
||||
<!-- Advanced filter dropdown -->
|
||||
<div class="lt-dropdown-wrap" id="adv-filter-wrap">
|
||||
@@ -419,8 +422,8 @@
|
||||
</select>
|
||||
</div>
|
||||
<div style="display:flex;gap:0.5rem;margin-top:0.25rem">
|
||||
<button class="lt-btn lt-btn-sm lt-btn-primary" style="flex:1" onclick="lt.toast.info('Filters applied');document.getElementById('adv-filter-panel').setAttribute('aria-hidden','true');document.getElementById('adv-filter-btn').setAttribute('aria-expanded','false')">Apply</button>
|
||||
<button class="lt-btn lt-btn-sm lt-btn-ghost" onclick="lt.toast.info('Filters cleared')">Reset</button>
|
||||
<button type="button" class="lt-btn lt-btn-sm lt-btn-primary" style="flex:1" onclick="lt.toast.info('Filters applied');document.getElementById('adv-filter-panel').setAttribute('aria-hidden','true');document.getElementById('adv-filter-btn').setAttribute('aria-expanded','false')">Apply</button>
|
||||
<button type="button" class="lt-btn lt-btn-sm lt-btn-ghost" onclick="lt.toast.info('Filters cleared')">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -432,11 +435,11 @@
|
||||
<div class="lt-dropdown-wrap" id="bulk-action-wrap">
|
||||
<button class="lt-btn lt-btn-sm lt-btn-ghost lt-dropdown-trigger" id="bulk-action-btn" aria-expanded="false" aria-haspopup="true">Bulk Actions ▾</button>
|
||||
<div class="lt-dropdown-panel lt-dropdown-panel--right" id="bulk-action-panel" aria-hidden="true">
|
||||
<button class="lt-dropdown-item" onclick="lt.toast.success('Closed selected tickets');this.closest('.lt-dropdown-panel').setAttribute('aria-hidden','true')">✓ Close Selected</button>
|
||||
<button class="lt-dropdown-item" onclick="lt.toast.info('Reassign dialog…');this.closest('.lt-dropdown-panel').setAttribute('aria-hidden','true')">↩ Reassign…</button>
|
||||
<button class="lt-dropdown-item" onclick="lt.toast.info('Exporting selected…');this.closest('.lt-dropdown-panel').setAttribute('aria-hidden','true')">⤓ Export Selected</button>
|
||||
<button type="button" class="lt-dropdown-item" onclick="lt.toast.success('Closed selected tickets');this.closest('.lt-dropdown-panel').setAttribute('aria-hidden','true')">✓ Close Selected</button>
|
||||
<button type="button" class="lt-dropdown-item" onclick="lt.toast.info('Reassign dialog…');this.closest('.lt-dropdown-panel').setAttribute('aria-hidden','true')">↩ Reassign…</button>
|
||||
<button type="button" class="lt-dropdown-item" onclick="lt.toast.info('Exporting selected…');this.closest('.lt-dropdown-panel').setAttribute('aria-hidden','true')">⤓ Export Selected</button>
|
||||
<div class="lt-dropdown-divider"></div>
|
||||
<button class="lt-dropdown-item lt-dropdown-item--danger" onclick="lt.toast.error('Deleted selected');this.closest('.lt-dropdown-panel').setAttribute('aria-hidden','true')">🗑 Delete Selected</button>
|
||||
<button type="button" class="lt-dropdown-item lt-dropdown-item--danger" onclick="lt.toast.error('Deleted selected');this.closest('.lt-dropdown-panel').setAttribute('aria-hidden','true')">🗑 Delete Selected</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -445,7 +448,7 @@
|
||||
<!-- ==================================================
|
||||
TAB PANEL: TABLE VIEW
|
||||
================================================== -->
|
||||
<div id="tab-table" class="lt-tab-panel active">
|
||||
<div id="tab-table" class="lt-tab-panel active" role="tabpanel" aria-labelledby="tab-btn-table">
|
||||
|
||||
<!-- Outer ASCII frame wrapping the table -->
|
||||
<div class="lt-frame">
|
||||
@@ -459,21 +462,21 @@
|
||||
<caption class="lt-sr-only">Ticket queue — sorted by priority</caption>
|
||||
<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>
|
||||
<th scope="col"><input type="checkbox" class="lt-checkbox" aria-label="Select all"></th>
|
||||
<th scope="col" data-sort-key="id" aria-sort="none">ID</th>
|
||||
<th scope="col" data-sort-key="priority" aria-sort="none">Priority</th>
|
||||
<th scope="col" data-sort-key="title" aria-sort="none">Title</th>
|
||||
<th scope="col" data-sort-key="status" aria-sort="none">Status</th>
|
||||
<th scope="col" data-sort-key="assignee" aria-sort="none">Assignee</th>
|
||||
<th scope="col" data-sort-key="created" aria-sort="none">Created</th>
|
||||
<th scope="col">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<!-- P1 Critical row -->
|
||||
<tr class="lt-row-p1 lt-row-critical">
|
||||
<td data-label="Select"><input type="checkbox" class="lt-checkbox"></td>
|
||||
<td data-label="Select"><input type="checkbox" class="lt-checkbox" aria-label="Select ticket #123456789"></td>
|
||||
<td data-label="ID"><a href="/ticket/123456789">#123456789</a></td>
|
||||
<td data-label="Priority"><span class="lt-p1">P1 Critical</span></td>
|
||||
<td data-label="Title">Storage array link-down on compute-storage-01</td>
|
||||
@@ -490,7 +493,7 @@
|
||||
|
||||
<!-- P2 High row -->
|
||||
<tr class="lt-row-p2 lt-row-warning">
|
||||
<td data-label="Select"><input type="checkbox" class="lt-checkbox"></td>
|
||||
<td data-label="Select"><input type="checkbox" class="lt-checkbox" aria-label="Select ticket #987654321"></td>
|
||||
<td data-label="ID"><a href="/ticket/987654321">#987654321</a></td>
|
||||
<td data-label="Priority"><span class="lt-p2">P2 High</span></td>
|
||||
<td data-label="Title">Switch port flapping on USW-Pro-24</td>
|
||||
@@ -506,7 +509,7 @@
|
||||
|
||||
<!-- P3 Medium row -->
|
||||
<tr class="lt-row-p3">
|
||||
<td data-label="Select"><input type="checkbox" class="lt-checkbox"></td>
|
||||
<td data-label="Select"><input type="checkbox" class="lt-checkbox" aria-label="Select ticket #111222333"></td>
|
||||
<td data-label="ID"><a href="/ticket/111222333">#111222333</a></td>
|
||||
<td data-label="Priority"><span class="lt-p3">P3 Med</span></td>
|
||||
<td data-label="Title">Scheduled maintenance: replace SFP+ on large1</td>
|
||||
@@ -522,7 +525,7 @@
|
||||
|
||||
<!-- P4 closed -->
|
||||
<tr class="lt-row-p4">
|
||||
<td data-label="Select"><input type="checkbox" class="lt-checkbox"></td>
|
||||
<td data-label="Select"><input type="checkbox" class="lt-checkbox" aria-label="Select ticket #444555666"></td>
|
||||
<td data-label="ID"><a href="/ticket/444555666">#444555666</a></td>
|
||||
<td data-label="Priority"><span class="lt-p4">P4 Low</span></td>
|
||||
<td data-label="Title">Update SSL cert on wiki.lotusguild.org</td>
|
||||
@@ -546,7 +549,7 @@
|
||||
<!-- ==================================================
|
||||
TAB PANEL: KANBAN
|
||||
================================================== -->
|
||||
<div id="tab-kanban" class="lt-tab-panel">
|
||||
<div id="tab-kanban" class="lt-tab-panel" role="tabpanel" aria-labelledby="tab-btn-kanban">
|
||||
<div class="lt-grid-4">
|
||||
|
||||
<!-- Kanban column: Open -->
|
||||
@@ -634,7 +637,7 @@
|
||||
<!-- ==================================================
|
||||
TAB PANEL: WORKERS
|
||||
================================================== -->
|
||||
<div id="tab-workers" class="lt-tab-panel">
|
||||
<div id="tab-workers" class="lt-tab-panel" role="tabpanel" aria-labelledby="tab-btn-workers">
|
||||
<div class="lt-grid-3">
|
||||
|
||||
<div class="lt-card">
|
||||
@@ -644,11 +647,13 @@
|
||||
</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>
|
||||
<tbody>
|
||||
<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>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -783,7 +788,7 @@
|
||||
<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">
|
||||
placeholder="Ctrl+K to focus" autocomplete="off">
|
||||
</div>
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label">Loading state (skeleton)</label>
|
||||
@@ -834,19 +839,19 @@
|
||||
<div style="display:flex;flex-direction:column;gap:var(--space-md)">
|
||||
<div>
|
||||
<div class="lt-progress-label"><span>CPU LOAD</span><span>72%</span></div>
|
||||
<div class="lt-progress"><div class="lt-progress-bar" style="width:72%" data-width="72%"></div></div>
|
||||
<div class="lt-progress" role="progressbar" aria-valuenow="72" aria-valuemin="0" aria-valuemax="100" aria-label="CPU Load"><div class="lt-progress-bar" style="width:72%" data-width="72%"></div></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="lt-progress-label"><span>MEMORY</span><span>45%</span></div>
|
||||
<div class="lt-progress lt-progress--cyan"><div class="lt-progress-bar" style="width:45%" data-width="45%"></div></div>
|
||||
<div class="lt-progress lt-progress--cyan" role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100" aria-label="Memory"><div class="lt-progress-bar" style="width:45%" data-width="45%"></div></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="lt-progress-label"><span>DISK I/O</span><span>89%</span></div>
|
||||
<div class="lt-progress lt-progress--red lt-progress--lg"><div class="lt-progress-bar" style="width:89%" data-width="89%"></div></div>
|
||||
<div class="lt-progress lt-progress--red lt-progress--lg" role="progressbar" aria-valuenow="89" aria-valuemin="0" aria-valuemax="100" aria-label="Disk I/O"><div class="lt-progress-bar" style="width:89%" data-width="89%"></div></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="lt-progress-label"><span>UPTIME</span><span>100%</span></div>
|
||||
<div class="lt-progress lt-progress--green lt-progress--striped"><div class="lt-progress-bar" style="width:100%" data-width="100%"></div></div>
|
||||
<div class="lt-progress lt-progress--green lt-progress--striped" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" aria-label="Uptime"><div class="lt-progress-bar" style="width:100%" data-width="100%"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -871,25 +876,25 @@
|
||||
<div class="lt-section-body">
|
||||
<div>
|
||||
<div class="lt-accordion">
|
||||
<button class="lt-accordion-header" aria-expanded="false" data-accordion>
|
||||
<button class="lt-accordion-header" aria-expanded="false" aria-controls="acc-body-1" data-accordion>
|
||||
SYSTEM OVERVIEW
|
||||
<svg class="lt-accordion-icon" viewBox="0 0 10 6" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M1 1l4 4 4-4"/></svg>
|
||||
</button>
|
||||
<div class="lt-accordion-body"><div class="lt-accordion-content">Node running at 72% CPU. 12 active processes. Last restart: 3d ago.</div></div>
|
||||
<div class="lt-accordion-body" id="acc-body-1"><div class="lt-accordion-content">Node running at 72% CPU. 12 active processes. Last restart: 3d ago.</div></div>
|
||||
</div>
|
||||
<div class="lt-accordion">
|
||||
<button class="lt-accordion-header" aria-expanded="false" data-accordion>
|
||||
<button class="lt-accordion-header" aria-expanded="false" aria-controls="acc-body-2" data-accordion>
|
||||
NETWORK CONFIG
|
||||
<svg class="lt-accordion-icon" viewBox="0 0 10 6" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M1 1l4 4 4-4"/></svg>
|
||||
</button>
|
||||
<div class="lt-accordion-body"><div class="lt-accordion-content">eth0: 10.0.0.7 — MTU 1500 — RX 4.2 GB — TX 1.1 GB</div></div>
|
||||
<div class="lt-accordion-body" id="acc-body-2"><div class="lt-accordion-content">eth0: 10.0.0.7 — MTU 1500 — RX 4.2 GB — TX 1.1 GB</div></div>
|
||||
</div>
|
||||
<div class="lt-accordion">
|
||||
<button class="lt-accordion-header" aria-expanded="false" data-accordion>
|
||||
<button class="lt-accordion-header" aria-expanded="false" aria-controls="acc-body-3" data-accordion>
|
||||
FIREWALL RULES
|
||||
<svg class="lt-accordion-icon" viewBox="0 0 10 6" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M1 1l4 4 4-4"/></svg>
|
||||
</button>
|
||||
<div class="lt-accordion-body"><div class="lt-accordion-content">22/tcp ALLOW — 80/tcp ALLOW — 443/tcp ALLOW — */* DENY</div></div>
|
||||
<div class="lt-accordion-body" id="acc-body-3"><div class="lt-accordion-content">22/tcp ALLOW — 80/tcp ALLOW — 443/tcp ALLOW — */* DENY</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1059,20 +1064,20 @@
|
||||
<div class="lt-section-header">Tab Bar</div>
|
||||
<div class="lt-section-body">
|
||||
<div class="lt-tab-bar" role="tablist">
|
||||
<button class="lt-tab active" role="tab" data-tab-target="tab-overview" aria-selected="true">Overview</button>
|
||||
<button class="lt-tab" role="tab" data-tab-target="tab-logs" aria-selected="false">Logs</button>
|
||||
<button class="lt-tab" role="tab" data-tab-target="tab-metrics" aria-selected="false">Metrics</button>
|
||||
<button class="lt-tab" role="tab" data-tab-target="tab-config" aria-selected="false">Config</button>
|
||||
<button class="lt-tab active" role="tab" id="tab2-btn-overview" data-tab-target="tab-overview" aria-selected="true" aria-controls="tab-overview">Overview</button>
|
||||
<button class="lt-tab" role="tab" id="tab2-btn-logs" data-tab-target="tab-logs" aria-selected="false" aria-controls="tab-logs">Logs</button>
|
||||
<button class="lt-tab" role="tab" id="tab2-btn-metrics" data-tab-target="tab-metrics" aria-selected="false" aria-controls="tab-metrics">Metrics</button>
|
||||
<button class="lt-tab" role="tab" id="tab2-btn-config" data-tab-target="tab-config" aria-selected="false" aria-controls="tab-config">Config</button>
|
||||
</div>
|
||||
<div class="lt-tab-panels" style="padding:var(--space-md) 0">
|
||||
<div id="tab-overview" class="lt-tab-panel active">System overview: all nodes nominal. 14 active sessions.</div>
|
||||
<div id="tab-logs" class="lt-tab-panel">
|
||||
<div id="tab-overview" class="lt-tab-panel active" role="tabpanel" aria-labelledby="tab2-btn-overview">System overview: all nodes nominal. 14 active sessions.</div>
|
||||
<div id="tab-logs" class="lt-tab-panel" role="tabpanel" aria-labelledby="tab2-btn-logs">
|
||||
<pre style="font-family:var(--font-mono);font-size:0.75rem;color:var(--text-secondary);margin:0">[03:41:22] nginx: 200 GET /api/nodes (12ms)
|
||||
[03:41:23] cron: heartbeat OK
|
||||
[03:41:24] alert: disk 87% on node-03</pre>
|
||||
</div>
|
||||
<div id="tab-metrics" class="lt-tab-panel">CPU avg: 34% — Mem avg: 61% — Net TX: 4.2 Mbps</div>
|
||||
<div id="tab-config" class="lt-tab-panel">Config last updated: 2026-03-20 by admin@lotusguild.io</div>
|
||||
<div id="tab-metrics" class="lt-tab-panel" role="tabpanel" aria-labelledby="tab2-btn-metrics">CPU avg: 34% — Mem avg: 61% — Net TX: 4.2 Mbps</div>
|
||||
<div id="tab-config" class="lt-tab-panel" role="tabpanel" aria-labelledby="tab2-btn-config">Config last updated: 2026-03-20 by admin@lotusguild.io</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1107,7 +1112,7 @@
|
||||
<p style="font-family:var(--font-mono);font-size:0.8rem;color:var(--text-secondary);margin:0 0 var(--space-sm)">
|
||||
Press <kbd style="background:var(--bg-tertiary);border:1px solid var(--border-dim);padding:2px 6px;font-family:var(--font-mono)">Ctrl+K</kbd> or click the button below to open the command palette.
|
||||
</p>
|
||||
<button class="lt-btn lt-btn-ghost" onclick="lt.cmdPalette.open()">⌘ Open Command Palette</button>
|
||||
<button type="button" class="lt-btn lt-btn-ghost" onclick="lt.cmdPalette.open()">⌘ Open Command Palette</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.lt-frame-inner (v1.2 additions) -->
|
||||
@@ -1126,9 +1131,9 @@
|
||||
<div class="lt-section-body">
|
||||
<p style="font-size:0.78rem;color:var(--text-secondary);margin-bottom:1rem">Dark/light mode with OS preference detection and localStorage persistence.</p>
|
||||
<div class="lt-flex lt-gap-sm lt-align-center lt-wrap">
|
||||
<button class="lt-btn lt-btn-primary" onclick="lt.theme.toggle()">Toggle Theme</button>
|
||||
<button class="lt-btn" onclick="lt.theme.set('dark')">Force Dark</button>
|
||||
<button class="lt-btn" onclick="lt.theme.set('light')">Force Light</button>
|
||||
<button type="button" class="lt-btn lt-btn-primary" onclick="lt.theme.toggle()">Toggle Theme</button>
|
||||
<button type="button" class="lt-btn" onclick="lt.theme.set('dark')">Force Dark</button>
|
||||
<button type="button" class="lt-btn" onclick="lt.theme.set('light')">Force Light</button>
|
||||
<code style="font-size:0.72rem;color:var(--accent-cyan)">lt.theme.toggle() | .set('light') | .get()</code>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1171,7 +1176,7 @@
|
||||
<div class="lt-section-body">
|
||||
<div class="lt-grid lt-grid-3" style="gap:1rem">
|
||||
<div class="lt-card"><div class="lt-empty-state"><div class="lt-empty-state-icon">📭</div><div class="lt-empty-state-title">No Tickets Found</div><div class="lt-empty-state-body">No tickets match your current filters.</div><button class="lt-btn lt-btn-sm lt-btn-primary">Clear Filters</button></div></div>
|
||||
<div class="lt-card"><div class="lt-empty-state"><div class="lt-empty-state-icon">🔌</div><div class="lt-empty-state-title">No Workers Online</div><div class="lt-empty-state-body">All workers are offline or unreachable.</div><button class="lt-btn lt-btn-sm" onclick="lt.toast.warning('Checking workers…')">Retry</button></div></div>
|
||||
<div class="lt-card"><div class="lt-empty-state"><div class="lt-empty-state-icon">🔌</div><div class="lt-empty-state-title">No Workers Online</div><div class="lt-empty-state-body">All workers are offline or unreachable.</div><button type="button" class="lt-btn lt-btn-sm" onclick="lt.toast.warning('Checking workers…')">Retry</button></div></div>
|
||||
<div class="lt-card"><div class="lt-empty-state lt-empty-state--sm"><div class="lt-empty-state-icon">🗂</div><div class="lt-empty-state-title">No Results</div><div class="lt-empty-state-body">Try a different search term.</div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1200,9 +1205,9 @@
|
||||
</div>
|
||||
<div class="lt-flex lt-gap-md lt-align-center lt-wrap">
|
||||
<span class="lt-notif-wrap" id="demo-notif-btn"><button class="lt-btn lt-btn-sm">🔔 Alerts</button></span>
|
||||
<button class="lt-btn lt-btn-sm" onclick="lt.notif.inc('#demo-notif-btn')">+1 Badge</button>
|
||||
<button class="lt-btn lt-btn-sm" onclick="lt.notif.clear('#demo-notif-btn')">Clear</button>
|
||||
<button class="lt-btn lt-btn-sm" onclick="lt.notif.inc('#lt-notif-bell')">+1 Header Bell</button>
|
||||
<button type="button" class="lt-btn lt-btn-sm" onclick="lt.notif.inc('#demo-notif-btn')">+1 Badge</button>
|
||||
<button type="button" class="lt-btn lt-btn-sm" onclick="lt.notif.clear('#demo-notif-btn')">Clear</button>
|
||||
<button type="button" class="lt-btn lt-btn-sm" onclick="lt.notif.inc('#lt-notif-bell')">+1 Header Bell</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1380,8 +1385,8 @@
|
||||
<div class="lt-ws-status" data-state="disconnected"><span class="lt-dot"></span><span>Disconnected</span></div>
|
||||
</div>
|
||||
<div class="lt-flex lt-gap-sm lt-wrap">
|
||||
<button class="lt-btn lt-btn-sm" onclick="lt.offline.isOnline() ? lt.toast.success('Online ✓') : lt.toast.error('Offline ✗')">Check Online Status</button>
|
||||
<button class="lt-btn lt-btn-sm" onclick="lt.toast.info('lt.ws.connect(url, { reconnect:true, onMessage: fn })')">WS API Hint</button>
|
||||
<button type="button" class="lt-btn lt-btn-sm" onclick="lt.offline.isOnline() ? lt.toast.success('Online ✓') : lt.toast.error('Offline ✗')">Check Online Status</button>
|
||||
<button type="button" class="lt-btn lt-btn-sm" onclick="lt.toast.info('lt.ws.connect(url, { reconnect:true, onMessage: fn })')">WS API Hint</button>
|
||||
</div>
|
||||
<p style="font-size:0.72rem;color:var(--text-muted);margin-top:0.75rem">Offline banner + body class auto-applied on <code>navigator.onLine</code> change. WS manager has exponential backoff, event emitter, status indicator binding.</p>
|
||||
</div>
|
||||
@@ -1397,7 +1402,7 @@
|
||||
<div id="demo-wizard">
|
||||
<!-- Step indicators -->
|
||||
<div class="lt-wizard-steps">
|
||||
<div class="lt-wizard-step is-active" data-wizard-indicator>
|
||||
<div class="lt-wizard-step is-active" data-wizard-indicator aria-current="step">
|
||||
<div class="lt-wizard-num">1</div>
|
||||
<div class="lt-wizard-label">Details</div>
|
||||
</div>
|
||||
@@ -1574,24 +1579,36 @@ Storage array link-down on `compute-storage-01`.
|
||||
|
||||
</main><!-- /.lt-main -->
|
||||
|
||||
<!-- ================================================================
|
||||
FOOTER LANDMARK
|
||||
================================================================ -->
|
||||
<footer class="lt-footer" role="contentinfo" aria-label="Application footer">
|
||||
<span class="lt-text-muted lt-font-mono lt-text-xs">
|
||||
LotusGuild Terminal Design System v1.2 — Internal Use Only
|
||||
</span>
|
||||
<span class="lt-text-muted lt-font-mono lt-text-xs">
|
||||
© <span id="footer-year"></span> LotusGuild. All rights reserved.
|
||||
</span>
|
||||
</footer>
|
||||
|
||||
|
||||
<!-- ===========================================================
|
||||
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>
|
||||
<button type="button" class="lt-btn lt-btn-sm" onclick="lt.toast.success('Ticket saved successfully')">✓ Toast</button>
|
||||
<button type="button" class="lt-btn lt-btn-sm lt-btn-danger" onclick="lt.toast.error('Network error — retry in 5s', 5000)">✗ Error</button>
|
||||
<button type="button" class="lt-btn lt-btn-sm" onclick="lt.toast.warning('Rate limit 80% used')">! Warn</button>
|
||||
<button type="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" role="dialog" aria-modal="true" aria-labelledby="export-modal-title">
|
||||
<div class="lt-modal-header">
|
||||
<span class="lt-modal-title">Export Tickets</span>
|
||||
<span class="lt-modal-title" id="export-modal-title">Export Tickets</span>
|
||||
<button class="lt-modal-close" data-modal-close aria-label="Close">✕</button>
|
||||
</div>
|
||||
<div class="lt-modal-body">
|
||||
@@ -1610,8 +1627,8 @@ Storage array link-down on `compute-storage-01`.
|
||||
<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>
|
||||
<button type="button" class="lt-btn lt-btn-ghost" data-modal-close>Cancel</button>
|
||||
<button type="button" class="lt-btn lt-btn-primary" onclick="lt.toast.success('Export started'); lt.modal.close('export-modal')">Export</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1620,9 +1637,9 @@ Storage array link-down on `compute-storage-01`.
|
||||
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" role="dialog" aria-modal="true" aria-labelledby="keys-help-title">
|
||||
<div class="lt-modal-header">
|
||||
<span class="lt-modal-title">Keyboard Shortcuts</span>
|
||||
<span class="lt-modal-title" id="keys-help-title">Keyboard Shortcuts</span>
|
||||
<button class="lt-modal-close" data-modal-close aria-label="Close">✕</button>
|
||||
</div>
|
||||
<div class="lt-modal-body">
|
||||
@@ -1932,6 +1949,10 @@ Storage array link-down on `compute-storage-01`.
|
||||
});
|
||||
});
|
||||
|
||||
// Footer year
|
||||
const footerYear = document.getElementById('footer-year');
|
||||
if (footerYear) footerYear.textContent = new Date().getFullYear();
|
||||
|
||||
// Tab bar switching
|
||||
document.querySelectorAll('.lt-tab-bar').forEach(bar => {
|
||||
bar.addEventListener('click', e => {
|
||||
|
||||
Reference in New Issue
Block a user