diff --git a/base.css b/base.css index 25dab36..8596f8e 100644 --- a/base.css +++ b/base.css @@ -3649,9 +3649,9 @@ html[data-theme="light"] .lt-textarea { color: var(--text-primary); box-shadow: inset 0 1px 3px rgba(0,0,0,0.05); } -html[data-theme="light"] .lt-input:focus, -html[data-theme="light"] .lt-select:focus, -html[data-theme="light"] .lt-textarea:focus { +html[data-theme="light"] .lt-input:focus-visible, +html[data-theme="light"] .lt-select:focus-visible, +html[data-theme="light"] .lt-textarea:focus-visible { border-color: var(--accent-cyan); box-shadow: var(--box-glow-cyan); } diff --git a/base.html b/base.html index 34e01c5..b3d2062 100644 --- a/base.html +++ b/base.html @@ -559,7 +559,7 @@
Open
-
+
@@ -568,7 +568,7 @@
5m ago · Unassigned
-
+
@@ -586,7 +586,7 @@
Pending
-
+
@@ -603,7 +603,7 @@
In Progress
-
+
@@ -620,7 +620,7 @@
Closed
-
+
@@ -646,13 +646,13 @@ Online
- +
- - - - - + + + + +
CPU 12%
Memory 2.1 GB / 8 GB
Load 0.42 / 0.51 / 0.48
Uptime 14d 6h
Tasks 2 / 5
CPU 12%
Memory 2.1 GB / 8 GB
Load 0.42 / 0.51 / 0.48
Uptime 14d 6h
Tasks 2 / 5
@@ -1311,7 +1311,7 @@
- + @@ -1645,7 +1645,7 @@ Storage array link-down on `compute-storage-01`.
IDPriorityTitleStatusAssignee
IDPriorityTitleStatusAssignee
#001P1Link-down on compute-storage-01Openjdoe
#002P2Switch port flapping USW-Pro-24In Progresssmith
- + diff --git a/base.js b/base.js index 2bdc9b9..8f34c0d 100644 --- a/base.js +++ b/base.js @@ -558,7 +558,8 @@ ths.forEach((th, colIdx) => { let dir = 'asc'; th.setAttribute('aria-sort', 'none'); - th.addEventListener('click', () => { + th.setAttribute('tabindex', '0'); + const _sort = () => { ths.forEach(h => { h.removeAttribute('data-sort'); h.setAttribute('aria-sort', 'none'); }); th.setAttribute('data-sort', dir); th.setAttribute('aria-sort', dir === 'asc' ? 'ascending' : 'descending'); @@ -573,7 +574,9 @@ }); rows.forEach(r => tbody.appendChild(r)); dir = dir === 'asc' ? 'desc' : 'asc'; - }); + }; + th.addEventListener('click', _sort); + th.addEventListener('keydown', e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); _sort(); } }); }); } @@ -993,6 +996,7 @@ function _validateField(el) { const val = el.value || '', type = (el.type || '').toLowerCase(); if ((type === 'checkbox' || type === 'radio') && el.required && !el.checked) return { valid: false, message: 'This field is required' }; + if (el.tagName === 'SELECT' && el.multiple && el.required && el.selectedOptions.length === 0) return { valid: false, message: 'Please select at least one option' }; if (el.required && !val.trim()) return { valid: false, message: 'This field is required' }; if (el.minLength > 0 && val.length < el.minLength) return { valid: false, message: 'Minimum ' + el.minLength + ' characters' }; if (el.maxLength > 0 && val.length > el.maxLength) return { valid: false, message: 'Maximum ' + el.maxLength + ' characters' }; @@ -2133,6 +2137,25 @@ }); divider.addEventListener('pointerup', () => { dragging = false; divider.classList.remove('is-dragging'); }); + // Keyboard resize support + divider.setAttribute('tabindex', '0'); + divider.setAttribute('role', 'separator'); + divider.setAttribute('aria-label', 'Resize panes'); + divider.addEventListener('keydown', e => { + const step = 0.05; + const total = vertical ? container.clientHeight : container.clientWidth; + const divSize = vertical ? divider.offsetHeight : divider.offsetWidth; + const available = total - divSize; + const currentSize = vertical ? panes[0].offsetHeight : panes[0].offsetWidth; + const currentRatio = currentSize / available; + if ((e.key === 'ArrowRight' && !vertical) || (e.key === 'ArrowDown' && vertical)) { + e.preventDefault(); _setRatio(Math.min(1, currentRatio + step)); + } else if ((e.key === 'ArrowLeft' && !vertical) || (e.key === 'ArrowUp' && vertical)) { + e.preventDefault(); _setRatio(Math.max(0, currentRatio - step)); + } else if (e.key === 'Home') { e.preventDefault(); _setRatio(0); } + else if (e.key === 'End') { e.preventDefault(); _setRatio(1); } + }); + _setRatio(initial); return { setRatio: _setRatio }; }, @@ -2477,7 +2500,7 @@ const lightbox = { init(selector, opts = {}) { const { caption = 'alt', loop = true } = opts; - let _images = [], _current = 0, _overlay = null; + let _images = [], _current = 0, _overlay = null, _lbKeyBound = null, _lbTrigger = null; function _getCaption(img) { if (typeof caption === 'function') return caption(img); @@ -2507,7 +2530,8 @@ _overlay.querySelector('.lt-lightbox-prev').addEventListener('click', () => lightbox.prev()); _overlay.querySelector('.lt-lightbox-next').addEventListener('click', () => lightbox.next()); _overlay.addEventListener('click', e => { if (e.target === _overlay) lightbox.close(); }); - document.addEventListener('keydown', _lbKey); + _lbKeyBound = _lbKey.bind(null); + document.addEventListener('keydown', _lbKeyBound); } function _lbKey(e) { @@ -2519,6 +2543,9 @@ function _show(idx) { if (!_overlay) _buildOverlay(); + if (!_overlay.classList.contains('is-open')) { + _lbTrigger = (document.activeElement && document.activeElement !== document.body) ? document.activeElement : null; + } _current = idx; const img = _images[idx]; const el = _overlay.querySelector('.lt-lightbox-img'); @@ -2554,6 +2581,8 @@ if (!_overlay) return; _overlay.classList.remove('is-open'); _unlockScroll(); + if (_lbTrigger && document.contains(_lbTrigger)) { _lbTrigger.focus(); } + _lbTrigger = null; }, prev() { _show(loop ? (_current - 1 + _images.length) % _images.length : Math.max(0, _current - 1)); }, next() { _show(loop ? (_current + 1) % _images.length : Math.min(_images.length - 1, _current + 1)); },
ShortcutAction
ShortcutAction
Ctrl / ⌘ + KFocus search box