mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-13 20:08:05 +08:00
🎉 Sync 2026-10-13 02:34:41
This commit is contained in:
1 parent
b537a62e59
commit
72c44a6325
38 files changed
+3510
-1734
No files matched your search
@@ -10,8 +10,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-theme-vantage
|
||||
PKG_VERSION:=1.0.3
|
||||
PKG_RELEASE:=16
|
||||
PKG_VERSION:=1.0.4
|
||||
PKG_RELEASE:=17
|
||||
PKG_LICENSE:=GPL-3.0-or-later
|
||||
|
||||
LUCI_TITLE:=Vantage theme
|
||||
|
||||
@@ -46,7 +46,8 @@ const ICONS = {
|
||||
moon: [ [ 'path', { d: 'M19.5 14.5A7.5 7.5 0 0 1 9.5 4.5a7.5 7.5 0 1 0 10 10z' } ] ],
|
||||
auto: [ [ 'circle', { cx: '12', cy: '12', r: '8' } ], [ 'path', { d: 'M12 4a8 8 0 0 1 0 16z', 'class': 'vt-fill' } ] ],
|
||||
logout: [ [ 'path', { d: 'M14 4h4.5A1.5 1.5 0 0 1 20 5.5v13a1.5 1.5 0 0 1-1.5 1.5H14' } ], [ 'path', { d: 'M10 8l-4 4 4 4M6 12h10' } ] ],
|
||||
pin: [ [ 'path', { d: 'M4 5v14M9 12h11M15 7l5 5-5 5' } ] ]
|
||||
pin: [ [ 'path', { d: 'M4 5v14M9 12h11M15 7l5 5-5 5' } ] ],
|
||||
info: [ [ 'circle', { cx: '12', cy: '12', r: '8.5' } ], [ 'path', { d: 'M12 11v5.5' } ], [ 'circle', { cx: '12', cy: '7.75', r: '.6' } ] ]
|
||||
};
|
||||
|
||||
function iconFor(name) {
|
||||
@@ -180,6 +181,11 @@ function technical(text) {
|
||||
return /\d/.test(rest) && /^[\s0-9a-fA-F.:,\/%()+\-x[\]~=]*$/.test(rest);
|
||||
}
|
||||
|
||||
/* heading text as compared for repeats: case, spacing and a trailing colon don't count */
|
||||
function headingKey(text) {
|
||||
return String(text || '').replace(/\s+/g, ' ').replace(/[\s:]+$/, '').trim().toLowerCase();
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Stock-page enhancers, only where CSS cannot restructure LuCI's markup
|
||||
* (Status -> Overview: fused memory bar, per-mount storage bars, radio band
|
||||
@@ -410,11 +416,18 @@ function humpPath(points) {
|
||||
return 'M' + r(x0) + ',' + r(base) + 'C' + r(x0 + k) + ',' + r(cy) + ' ' + r(x3 - k) + ',' + r(cy) + ' ' + r(x3) + ',' + r(base) + 'Z';
|
||||
}
|
||||
|
||||
/* "#89cdb4" -> "rgb(137, 205, 180)", the form element.style reads back */
|
||||
function hexRgb(hex) {
|
||||
const m = /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(String(hex));
|
||||
return m ? 'rgb(' + [ m[1], m[2], m[3] ].map(h => parseInt(h, 16)).join(', ') + ')' : null;
|
||||
}
|
||||
|
||||
function setupChannelAnalysis() {
|
||||
const view = document.getElementById('view');
|
||||
const own = new Set();
|
||||
const slots = new Map();
|
||||
let next = 0;
|
||||
let colourOf = null;
|
||||
/* slot 1 (the accent) is the AP itself; neighbours take 2..6 in the order
|
||||
they first appear (the view sorts by channel, so neighbours differ) */
|
||||
const slotFor = (colour, mine) => {
|
||||
@@ -455,9 +468,17 @@ function setupChannelAnalysis() {
|
||||
const dot = tr.querySelector('span[style*="color"]');
|
||||
const cells = tr.querySelectorAll(':scope > td, :scope > .td');
|
||||
if (!cells.length) return;
|
||||
const bssid = cells[cells.length - 1].textContent.trim().toUpperCase();
|
||||
const printed = cells[cells.length - 1].textContent.trim();
|
||||
const bssid = printed.toUpperCase();
|
||||
const mine = own.has(bssid);
|
||||
if (tr.classList.contains('v-ca-own') !== mine) tr.classList.toggle('v-ca-own', mine);
|
||||
/* the view prints its own interface's row without the colour
|
||||
dot, so rebuild that colour the way the view made it: from
|
||||
the BSSID as printed (the derivation is case-sensitive) */
|
||||
if (mine && colourOf) {
|
||||
const derived = hexRgb(colourOf(printed));
|
||||
if (derived) mineByColour.set(derived, true);
|
||||
}
|
||||
if (!dot) return;
|
||||
const colour = dot.style.color;
|
||||
if (mine) mineByColour.set(colour, true);
|
||||
@@ -531,7 +552,15 @@ function setupChannelAnalysis() {
|
||||
busy = false;
|
||||
};
|
||||
|
||||
L.resolveDefault(callWirelessDevices(), {}).then(devs => {
|
||||
/* tools.prng is what the view colours networks with (it is loaded
|
||||
already); derive_color reseeds on every call, so calling it here
|
||||
leaves the view's colours as they are */
|
||||
Promise.all([
|
||||
L.resolveDefault(callWirelessDevices(), {}),
|
||||
L.resolveDefault(L.require('tools.prng'), null)
|
||||
]).then(([ devs, prng ]) => {
|
||||
if (prng && typeof prng.derive_color === 'function')
|
||||
colourOf = b => prng.derive_color(b);
|
||||
for (const r of Object.values(devs || {}))
|
||||
for (const i of (r && Array.isArray(r.interfaces)) ? r.interfaces : [])
|
||||
[ i.iwinfo && i.iwinfo.bssid, i.config && i.config.macaddr ].forEach(b => {
|
||||
@@ -558,10 +587,12 @@ return baseclass.extend({
|
||||
this.closeTimer = null;
|
||||
this.openTimer = null;
|
||||
this.entries = [];
|
||||
this.trailKeys = new Set();
|
||||
|
||||
this.setupTheme();
|
||||
this.setupIndicators();
|
||||
this.setupNumerals();
|
||||
this.setupForms();
|
||||
setupStockEnhancers();
|
||||
setupCharts();
|
||||
this.setupKeys();
|
||||
@@ -605,6 +636,7 @@ return baseclass.extend({
|
||||
this.renderCrumbs();
|
||||
this.renderTabs();
|
||||
this.buildIndex();
|
||||
this.queueForms();
|
||||
},
|
||||
|
||||
isPinned() {
|
||||
@@ -861,6 +893,7 @@ return baseclass.extend({
|
||||
});
|
||||
|
||||
this.pageTitle = parts[parts.length - 1].title;
|
||||
parts.forEach(p => this.trailKeys.add(headingKey(p.title)));
|
||||
this.updateTitle();
|
||||
},
|
||||
|
||||
@@ -1194,5 +1227,126 @@ return baseclass.extend({
|
||||
window.requestAnimationFrame(scan);
|
||||
}).observe(main, { childList: true, subtree: true, characterData: true });
|
||||
scan();
|
||||
},
|
||||
|
||||
/* ---------------------------------------------------- form chrome */
|
||||
|
||||
/* LuCI renders forms into #view and the modal, and renders them again
|
||||
after a save: watch the body and decorate what is new. This adds (i)
|
||||
buttons and sets classes and attributes; LuCI's text and the order of
|
||||
LuCI's nodes stay as they are. */
|
||||
setupForms() {
|
||||
this.formsQueued = false;
|
||||
this.helpSeq = 0;
|
||||
this.helpSizes = window.ResizeObserver ? new ResizeObserver(entries => entries.forEach(e => this.fitHelp(e.target))) : null;
|
||||
if (window.MutationObserver)
|
||||
new MutationObserver(() => this.queueForms()).observe(document.body, { childList: true, subtree: true });
|
||||
this.decorateForms();
|
||||
},
|
||||
|
||||
queueForms() {
|
||||
if (this.formsQueued) return;
|
||||
this.formsQueued = true;
|
||||
window.requestAnimationFrame(() => {
|
||||
this.formsQueued = false;
|
||||
this.decorateForms();
|
||||
});
|
||||
},
|
||||
|
||||
decorateForms() {
|
||||
document.querySelectorAll('.cbi-value > .cbi-value-title + .cbi-value-field > .cbi-value-description:not(.vt-help-text)')
|
||||
.forEach(desc => this.addFieldHelp(desc));
|
||||
document.querySelectorAll(':is(.cbi-map-descr, .cbi-section-descr):not(:has(> .vt-help))')
|
||||
.forEach(desc => this.addIntroHelp(desc));
|
||||
this.markRepeats();
|
||||
},
|
||||
|
||||
/* Help text shows its first line; (i) unfolds the rest. LuCI also puts
|
||||
warnings here, so none is hidden whole: its start stays visible.
|
||||
Field help: the button sits in the label column, after the field,
|
||||
because LuCI's label click handler finds the widget through
|
||||
nextElementSibling. */
|
||||
addFieldHelp(desc) {
|
||||
const row = desc.parentNode.parentNode;
|
||||
const title = row.querySelector(':scope > .cbi-value-title');
|
||||
row.appendChild(this.helpToggle(desc, row, _('Show full help: %s').format(title.textContent.trim()), _('Show full help')));
|
||||
},
|
||||
|
||||
/* Page and section intros: the button leads the first line, inside the
|
||||
description, since nothing may stand between LuCI's siblings (ui.tabs
|
||||
finds a tab menu as its pane group's previous sibling). The fold needs
|
||||
the button, so a view that rewrote the text would show it whole until
|
||||
the next pass adds the button again. The cut-off line unfolds on a
|
||||
click too, a bigger target on touch than the icon. */
|
||||
addIntroHelp(desc) {
|
||||
if (desc.closest('.vt-app') || !desc.textContent.trim()) return;
|
||||
desc.insertBefore(this.helpToggle(desc, desc, _('Show full description'), _('Show full description')), desc.firstChild);
|
||||
if (desc._vtIntroClick) return;
|
||||
desc._vtIntroClick = true;
|
||||
desc.addEventListener('click', ev => {
|
||||
const btn = desc.querySelector(':scope > .vt-help');
|
||||
if (!btn || btn.hidden || desc.getAttribute('data-v-help') !== 'closed') return;
|
||||
if (ev.target.closest('a, button') || String(window.getSelection())) return;
|
||||
btn.click();
|
||||
});
|
||||
},
|
||||
|
||||
/* The (i) button for desc. Its state lives on holder (the field row, or
|
||||
the intro itself) as data-v-help, which the CSS folds by. */
|
||||
helpToggle(desc, holder, label, title) {
|
||||
const state = holder.getAttribute('data-v-help') || 'closed';
|
||||
holder.setAttribute('data-v-help', state);
|
||||
desc.classList.add('vt-help-text');
|
||||
if (!desc.id) desc.id = 'vt-help-' + (++this.helpSeq);
|
||||
const btn = E('button', {
|
||||
'class': 'vt-help', 'type': 'button', 'hidden': '',
|
||||
'aria-expanded': String(state === 'open'), 'aria-controls': desc.id,
|
||||
'aria-label': label, 'title': title,
|
||||
'click': () => {
|
||||
const open = holder.getAttribute('data-v-help') !== 'open';
|
||||
holder.setAttribute('data-v-help', open ? 'open' : 'closed');
|
||||
btn.setAttribute('aria-expanded', String(open));
|
||||
this.fitHelp(desc);
|
||||
}
|
||||
}, [ svg('info', 16) ]);
|
||||
desc._vtHelp = { btn: btn, holder: holder };
|
||||
if (this.helpSizes) this.helpSizes.observe(desc);
|
||||
else btn.hidden = false;
|
||||
return btn;
|
||||
},
|
||||
|
||||
/* (i) shows only while the one-line clamp cuts the text. Text that is
|
||||
not displayed (another tab, an unmet dependency) measures 0 and waits
|
||||
for the next resize notification. */
|
||||
fitHelp(desc) {
|
||||
if (!desc.isConnected) {
|
||||
if (this.helpSizes) this.helpSizes.unobserve(desc);
|
||||
return;
|
||||
}
|
||||
const h = desc._vtHelp;
|
||||
if (!h || !h.btn.isConnected || !desc.clientHeight) return;
|
||||
const cut = desc.scrollHeight > desc.clientHeight + 1;
|
||||
h.btn.hidden = !cut && h.holder.getAttribute('data-v-help') !== 'open';
|
||||
},
|
||||
|
||||
/* A page title or card heading that only repeats the breadcrumb, the
|
||||
map title or its own tab's name is hidden visually; screen readers
|
||||
still get it as a heading. Headings that hold a control (Overview's
|
||||
Hide/Show label) always stay. */
|
||||
markRepeats() {
|
||||
/* template pages (Status -> Overview) print their title before #view */
|
||||
document.querySelectorAll('#maincontent > h2, #view h2, #view .cbi-section > h3:first-child').forEach(h => {
|
||||
if (h.closest('.vt-app') || h.querySelector('a, button, input, select, [data-clickable], [tabindex]')) return;
|
||||
const key = headingKey(h.textContent);
|
||||
let repeat = this.trailKeys.has(key);
|
||||
if (!repeat && h.tagName === 'H3') {
|
||||
const map = h.closest('.cbi-map');
|
||||
const mapTitle = map && map.querySelector(':scope > h2');
|
||||
const pane = h.closest('[data-tab-title]');
|
||||
repeat = (mapTitle && headingKey(mapTitle.textContent) === key) ||
|
||||
(pane && headingKey(pane.getAttribute('data-tab-title')) === key);
|
||||
}
|
||||
h.classList.toggle('vt-repeat', !!(key && repeat));
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -39,7 +39,9 @@
|
||||
--rail-w: 56px;
|
||||
--rail-w-pinned: 204px;
|
||||
--top-h: 52px;
|
||||
--ctl-h: 32px;
|
||||
--ctl-h: 36px; /* every control: inputs, selects, buttons, tabs, chips */
|
||||
--label-w: 180px; /* form label column */
|
||||
--field-max: 360px; /* widest single-line field */
|
||||
--content-max: 1320px;
|
||||
|
||||
/* light: cool paper grey, olive accent text */
|
||||
@@ -72,6 +74,9 @@
|
||||
--scrim: rgba(20, 23, 26, .38);
|
||||
--shadow-pop: 0 12px 32px rgba(20, 23, 26, .16), 0 2px 6px rgba(20, 23, 26, .08);
|
||||
--zone-mix: .22;
|
||||
--seg-bg: var(--s3); /* segmented control: track, selected segment */
|
||||
--seg-on: var(--s2);
|
||||
--seg-on-ring: 0 0 0 1px var(--line), var(--v-shadow);
|
||||
}
|
||||
|
||||
html[data-darkmode="true"] {
|
||||
@@ -107,6 +112,14 @@ html[data-darkmode="true"] {
|
||||
--scrim: rgba(0, 0, 0, .58);
|
||||
--shadow-pop: 0 16px 40px rgba(0, 0, 0, .55), 0 0 0 1px rgba(255, 255, 255, .02);
|
||||
--zone-mix: .2;
|
||||
--seg-bg: var(--bg);
|
||||
--seg-on: var(--s3);
|
||||
--seg-on-ring: 0 0 0 1px var(--line-2);
|
||||
}
|
||||
|
||||
/* touch: controls are sized by the pointer, not the screen width */
|
||||
@media (pointer: coarse) {
|
||||
:root { --ctl-h: 44px; }
|
||||
}
|
||||
|
||||
/* Shared Vantage tokens (--v-*): the stable contract other Vantage views
|
||||
@@ -136,9 +149,17 @@ html[data-darkmode="true"] {
|
||||
--v-info-soft: var(--info-soft);
|
||||
--v-font: var(--font);
|
||||
--v-mono: var(--mono);
|
||||
--v-fs-micro: var(--fs-micro); /* the type scale: 10.5 12 13 14 16 20 24 px */
|
||||
--v-fs-sm: var(--fs-sm);
|
||||
--v-fs-base: var(--fs-base);
|
||||
--v-fs-md: var(--fs-md);
|
||||
--v-fs-lg: var(--fs-lg);
|
||||
--v-fs-xl: var(--fs-xl);
|
||||
--v-fs-2xl: var(--fs-2xl);
|
||||
--v-r-sm: var(--r-sm);
|
||||
--v-r: var(--r);
|
||||
--v-r-lg: var(--r-lg);
|
||||
--v-ctl-h: var(--ctl-h); /* every control: 36px, 44px on touch */
|
||||
--v-shadow: 0 1px 2px rgba(20, 23, 26, .06), 0 1px 0 rgba(20, 23, 26, .03);
|
||||
/* where sticky content may start: below the top bar and page tabs */
|
||||
--v-stick-top: var(--stick-top);
|
||||
@@ -508,7 +529,7 @@ a.vt-crumb:hover { color: var(--text); }
|
||||
font-size: var(--fs-sm);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.vt-host b { color: var(--text); font-weight: 600; font-family: var(--mono); font-size: 11.5px; }
|
||||
.vt-host b { color: var(--text); font-weight: 600; font-family: var(--mono); font-size: var(--fs-micro); }
|
||||
.vt-host span { overflow: hidden; text-overflow: ellipsis; }
|
||||
.vt-host-sep { color: var(--text-3); }
|
||||
|
||||
@@ -555,7 +576,7 @@ a.vt-crumb:hover { color: var(--text); }
|
||||
min-width: 20px; height: 20px; padding: 0 6px;
|
||||
border-radius: 999px;
|
||||
background: var(--warn); color: #1a1200;
|
||||
font: 700 11.5px/1 var(--mono);
|
||||
font: 700 var(--fs-micro)/1 var(--mono);
|
||||
}
|
||||
#indicators > span[data-indicator="media_error"] { color: var(--err); border-color: var(--err); background: var(--err-soft); }
|
||||
|
||||
@@ -575,7 +596,7 @@ a.vt-crumb:hover { color: var(--text); }
|
||||
.vt-tab {
|
||||
position: relative;
|
||||
display: inline-flex; align-items: center;
|
||||
height: 40px; padding: 0 var(--sp-3);
|
||||
height: var(--ctl-h); padding: 0 var(--sp-3);
|
||||
color: var(--text-2);
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
@@ -691,7 +712,7 @@ a.vt-crumb:hover { color: var(--text); }
|
||||
/* page = title block + a stack of cards. Cards carry a full-bleed header
|
||||
row (h3) and full-bleed tables; nested sections lose their chrome. */
|
||||
:root { --card-px: 20px; --card-py: 16px; --stick-top: var(--top-h); }
|
||||
html:has(.vt-tabs:not([hidden])) { --stick-top: calc(var(--top-h) + 41px); }
|
||||
html:has(.vt-tabs:not([hidden])) { --stick-top: calc(var(--top-h) + var(--ctl-h) + 1px); }
|
||||
|
||||
.cbi-map { margin-bottom: var(--sp-6); }
|
||||
.cbi-map > h2, .vt-main > h2, #view > h2, #view > div > h2:first-child, .cbi-map > h2:first-child {
|
||||
@@ -704,18 +725,18 @@ html:has(.vt-tabs:not([hidden])) { --stick-top: calc(var(--top-h) + 41px); }
|
||||
max-width: 76ch;
|
||||
margin: 0 0 var(--sp-6);
|
||||
color: var(--text-2);
|
||||
font-size: 13.5px; line-height: 1.55;
|
||||
font-size: var(--fs-base); line-height: 1.55;
|
||||
}
|
||||
.cbi-section-descr { max-width: 80ch; margin: 0 0 var(--sp-4); color: var(--text-2); }
|
||||
.cbi-map-descr:empty, .cbi-section-descr:empty { display: none; }
|
||||
.cbi-map > h2 + .cbi-tabmenu, .cbi-map > h2 + .cbi-map-descr:empty + .cbi-tabmenu { margin-top: var(--sp-4); }
|
||||
.cbi-map > h2:not(.vt-repeat) + .cbi-tabmenu, .cbi-map > h2:not(.vt-repeat) + .cbi-map-descr:empty + .cbi-tabmenu { margin-top: var(--sp-4); }
|
||||
|
||||
.cbi-section, .cbi-map > fieldset {
|
||||
margin: 0 0 var(--sp-4);
|
||||
padding: var(--card-py) var(--card-px);
|
||||
background: var(--s1);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 10px;
|
||||
border-radius: var(--r-lg);
|
||||
box-shadow: var(--v-shadow);
|
||||
min-width: 0;
|
||||
background-clip: padding-box;
|
||||
@@ -754,22 +775,27 @@ html:has(.vt-tabs:not([hidden])) { --stick-top: calc(var(--top-h) + 41px); }
|
||||
}
|
||||
.cbi-section .cbi-section > h3:first-child { margin: 0 0 var(--sp-3); padding: 0; min-height: 0; border: 0; }
|
||||
.cbi-section .cbi-section + .cbi-section { margin-top: var(--sp-5); padding-top: var(--sp-5); border-top: 1px solid var(--line); }
|
||||
/* a nested table section scrolls its own table, so it takes the card bleed
|
||||
itself (out by --card-px, padded back in): the table's bleed then stays
|
||||
inside the scroll box instead of overflowing it by --card-px */
|
||||
.cbi-section .cbi-section.cbi-tblsection {
|
||||
margin-left: calc(-1 * var(--card-px)); margin-right: calc(-1 * var(--card-px));
|
||||
padding-left: var(--card-px); padding-right: var(--card-px);
|
||||
}
|
||||
|
||||
fieldset { border: 0; padding: 0; margin: 0; min-width: 0; }
|
||||
legend { font-size: var(--fs-md); font-weight: 600; padding: 0; margin-bottom: var(--sp-3); }
|
||||
|
||||
/* option rows: two aligned columns on desktop */
|
||||
/* option rows: label column + field, no rules between rows */
|
||||
.cbi-value {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(160px, 260px) minmax(0, 1fr);
|
||||
column-gap: var(--sp-8);
|
||||
grid-template-columns: var(--label-w) minmax(0, 1fr);
|
||||
column-gap: var(--sp-5);
|
||||
align-items: start;
|
||||
padding: 14px 0;
|
||||
border-bottom: 1px solid var(--line);
|
||||
padding: 6px 0;
|
||||
}
|
||||
.cbi-value:last-child, .cbi-value.cbi-value-last { border-bottom: 0; }
|
||||
.cbi-value > .cbi-value-title {
|
||||
padding-top: 7px;
|
||||
padding-top: calc((var(--ctl-h) - 1.5em) / 2); /* 1.5em: one line at line-height 1.5 */
|
||||
color: var(--text);
|
||||
font-weight: 500;
|
||||
overflow-wrap: anywhere;
|
||||
@@ -790,6 +816,64 @@ legend { font-size: var(--fs-md); font-weight: 600; padding: 0; margin-bottom: v
|
||||
line-height: 1.5;
|
||||
}
|
||||
.cbi-value-helpicon img { width: 14px; height: 14px; opacity: .6; }
|
||||
|
||||
/* folding help (menu-vantage.js): one line until (i) unfolds it; the
|
||||
button shares the label cell, so both are placed explicitly */
|
||||
.cbi-value[data-v-help="closed"] > .cbi-value-field > .vt-help-text {
|
||||
display: -webkit-box; -webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1; line-clamp: 1;
|
||||
max-height: 1.5em;
|
||||
overflow: hidden;
|
||||
}
|
||||
.cbi-value[data-v-help] > .cbi-value-title { grid-row: 1; grid-column: 1; }
|
||||
.cbi-value[data-v-help] > .cbi-value-field { grid-row: 1; }
|
||||
.cbi-value:has(> .vt-help:not([hidden])) > .cbi-value-title { padding-right: 32px; }
|
||||
.cbi-value > .vt-help {
|
||||
grid-row: 1; grid-column: 1;
|
||||
justify-self: end;
|
||||
display: grid; place-items: center;
|
||||
width: 28px; height: var(--ctl-h);
|
||||
padding: 0;
|
||||
background: none; border: 0; border-radius: var(--r);
|
||||
color: var(--text-3);
|
||||
cursor: pointer;
|
||||
}
|
||||
/* a title that opens with <br> (Wireless "Operating frequency", lined up
|
||||
with captioned selects) has its text on the second line: so has (i) */
|
||||
.cbi-value:has(> .cbi-value-title > br:first-child) > .vt-help { margin-top: 1.5em; }
|
||||
|
||||
/* page and section intros fold the same way, (i) leading the first line;
|
||||
the fold needs the button, so without it the text shows whole */
|
||||
:is(.cbi-map-descr, .cbi-section-descr)[data-v-help="closed"]:has(> .vt-help) {
|
||||
display: -webkit-box; -webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1; line-clamp: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
.cbi-map-descr[data-v-help="closed"]:has(> .vt-help) { max-height: 1.55em; } /* its line-height */
|
||||
.cbi-section-descr[data-v-help="closed"]:has(> .vt-help) { max-height: 1.5em; }
|
||||
:is(.cbi-map-descr, .cbi-section-descr)[data-v-help="closed"]:has(> .vt-help:not([hidden])) { cursor: pointer; }
|
||||
:is(.cbi-map-descr, .cbi-section-descr) > .vt-help {
|
||||
display: inline-grid; place-items: center;
|
||||
width: 1.5em; height: 1.5em;
|
||||
margin: 0 6px 0 -3px; padding: 0;
|
||||
vertical-align: top;
|
||||
background: none; border: 0; border-radius: var(--r-sm);
|
||||
color: var(--text-3);
|
||||
cursor: pointer;
|
||||
}
|
||||
/* both buttons, after their placement rules */
|
||||
.vt-help svg { fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
|
||||
.vt-help:hover { color: var(--text); background: var(--s3); }
|
||||
.vt-help[aria-expanded="true"] { color: var(--accent-text); }
|
||||
|
||||
/* a heading that repeats the breadcrumb or its tab (menu-vantage.js):
|
||||
gone from view, still a heading for screen readers */
|
||||
.vt-repeat {
|
||||
position: absolute !important;
|
||||
width: 1px; height: 1px; min-height: 0 !important;
|
||||
margin: -1px !important; padding: 0 !important; border: 0 !important;
|
||||
overflow: hidden; clip-path: inset(50%); white-space: nowrap;
|
||||
}
|
||||
.cbi-value.cbi-value-error .cbi-value-title,
|
||||
.cbi-value-field .cbi-input-invalid + .cbi-value-description { color: var(--err); }
|
||||
|
||||
@@ -812,7 +896,7 @@ legend { font-size: var(--fs-md); font-weight: 600; padding: 0; margin-bottom: v
|
||||
backdrop-filter: saturate(1.3) blur(14px);
|
||||
-webkit-backdrop-filter: saturate(1.3) blur(14px);
|
||||
border: 1px solid var(--line-2);
|
||||
border-radius: 12px;
|
||||
border-radius: var(--r-lg);
|
||||
box-shadow: var(--shadow-pop);
|
||||
}
|
||||
.cbi-page-actions > * { margin: 0 !important; }
|
||||
@@ -833,7 +917,7 @@ input, select, textarea, button { font: inherit; color: inherit; }
|
||||
.vt-main input[type="date"], .vt-main input[type="time"], .vt-main input[type="datetime-local"],
|
||||
.vt-main input:not([type]), .modal input[type="text"], .modal input[type="password"], .modal input:not([type]), .modal select, .modal textarea {
|
||||
width: 100%;
|
||||
max-width: 440px;
|
||||
max-width: var(--field-max);
|
||||
min-height: var(--ctl-h);
|
||||
padding: 5px 10px;
|
||||
background: var(--s2);
|
||||
@@ -844,7 +928,7 @@ input, select, textarea, button { font: inherit; color: inherit; }
|
||||
line-height: 20px;
|
||||
transition: border-color .12s, box-shadow .12s;
|
||||
}
|
||||
.vt-main textarea, .cbi-input-textarea, .modal textarea { max-width: none; min-height: 88px; font-family: var(--mono); font-size: var(--fs-sm); resize: vertical; }
|
||||
.vt-main textarea, .cbi-input-textarea, .modal textarea { max-width: calc(2 * var(--field-max)); min-height: 88px; font-family: var(--mono); font-size: var(--fs-sm); resize: vertical; }
|
||||
.vt-main select, .cbi-input-select, .modal select {
|
||||
appearance: none; -webkit-appearance: none;
|
||||
padding-right: 30px;
|
||||
@@ -853,6 +937,13 @@ input, select, textarea, button { font: inherit; color: inherit; }
|
||||
background-size: 5px 5px, 5px 5px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
/* a native select in a form row cuts a long choice off without an
|
||||
ellipsis: let it grow past --field-max to fit (field-sizing: the chosen
|
||||
value; elsewhere the widest option), never past its column */
|
||||
.cbi-value > .cbi-value-field > select:not([multiple]), .cbi-value > .cbi-value-field > div > select:not([multiple]) {
|
||||
field-sizing: content;
|
||||
width: auto; min-width: min(100%, var(--field-max)); max-width: 100%;
|
||||
}
|
||||
.vt-main select[multiple] { background-image: none; padding-right: 10px; }
|
||||
input::placeholder, textarea::placeholder { color: var(--text-3); opacity: 1; }
|
||||
input:hover, select:hover, textarea:hover { border-color: var(--text-3); }
|
||||
@@ -876,7 +967,7 @@ input[readonly] { cursor: default; }
|
||||
/* password + reveal and other control groups */
|
||||
.control-group {
|
||||
display: flex; align-items: stretch; flex-wrap: nowrap;
|
||||
max-width: 440px;
|
||||
max-width: var(--field-max);
|
||||
}
|
||||
.control-group > * { margin: 0 !important; }
|
||||
.control-group > :not(:first-child) { margin-left: -1px !important; }
|
||||
@@ -913,7 +1004,7 @@ input[type="checkbox"]:focus-visible, input[type="radio"]:focus-visible { outlin
|
||||
input[type="checkbox"][disabled]:checked { opacity: .5; }
|
||||
|
||||
/* range slider */
|
||||
.cbi-range-slider { display: flex; align-items: center; gap: var(--sp-3); max-width: 440px; min-height: var(--ctl-h); flex-wrap: wrap; }
|
||||
.cbi-range-slider { display: flex; align-items: center; gap: var(--sp-3); max-width: var(--field-max); min-height: var(--ctl-h); flex-wrap: wrap; }
|
||||
.cbi-range-slider input[type="range"] { flex: 1 1 160px; accent-color: var(--accent-text); }
|
||||
.cbi-range-slider-value, .cbi-range-slider-calc { font-family: var(--mono); color: var(--text-2); font-size: var(--fs-sm); }
|
||||
|
||||
@@ -942,7 +1033,7 @@ input[type="button"], input[type="reset"], input[type="submit"]) {
|
||||
opacity: .45; cursor: not-allowed; pointer-events: none;
|
||||
}
|
||||
|
||||
.cbi-button-up, .cbi-button-down { min-width: 28px; padding: 0 6px; }
|
||||
.cbi-button-up, .cbi-button-down { min-width: var(--ctl-h); padding: 0 6px; }
|
||||
|
||||
.button-row { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--sp-2); margin-top: var(--sp-4); }
|
||||
.right > .btn, .right > .cbi-button, .right > button { margin-left: var(--sp-2); }
|
||||
@@ -951,7 +1042,7 @@ input[type="button"], input[type="reset"], input[type="submit"]) {
|
||||
.cbi-dropdown {
|
||||
position: relative;
|
||||
display: inline-flex; align-items: stretch;
|
||||
width: 100%; max-width: 440px;
|
||||
width: 100%; max-width: var(--field-max);
|
||||
min-height: var(--ctl-h);
|
||||
padding: 0;
|
||||
background: var(--s2);
|
||||
@@ -1044,8 +1135,8 @@ input[type="button"], input[type="reset"], input[type="submit"]) {
|
||||
}
|
||||
.cbi-dropdown[open] > ul.dropdown[style*="bottom"] { top: auto; }
|
||||
.cbi-dropdown[open] > ul.dropdown > li {
|
||||
display: flex;
|
||||
min-height: 30px;
|
||||
display: flex; align-items: center;
|
||||
min-height: calc(var(--ctl-h) - 4px);
|
||||
padding: 4px 8px;
|
||||
border-radius: var(--r-sm);
|
||||
white-space: normal;
|
||||
@@ -1062,6 +1153,18 @@ input[type="button"], input[type="reset"], input[type="submit"]) {
|
||||
.cbi-dropdown[multiple][open] > ul.dropdown > li > form { display: inline-flex; }
|
||||
.cbi-dropdown[open] > ul.dropdown > li input.create-item-input { max-width: none; min-height: 28px; }
|
||||
.cbi-dropdown[open] > .open { color: var(--accent-text); }
|
||||
/* one arrow for every field: the select's triangle, drawn where LuCI puts
|
||||
its "▾" glyph (ComboButtons keep theirs) */
|
||||
.cbi-dropdown:not(.btn, .cbi-button) > .open {
|
||||
--arrow: var(--text-3);
|
||||
width: 30px; padding: 0;
|
||||
font-size: 0;
|
||||
background-image: linear-gradient(45deg, transparent 50%, var(--arrow) 50%), linear-gradient(135deg, var(--arrow) 50%, transparent 50%);
|
||||
background-position: calc(100% - 15px) 50%, calc(100% - 10px) 50%;
|
||||
background-size: 5px 5px, 5px 5px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.cbi-dropdown:not(.btn, .cbi-button)[open] > .open { --arrow: var(--accent-text); }
|
||||
|
||||
/* ComboButton: dropdown dressed as a split button */
|
||||
.cbi-dropdown.btn, .cbi-dropdown.cbi-button {
|
||||
@@ -1139,12 +1242,12 @@ input[type="button"], input[type="reset"], input[type="submit"]) {
|
||||
:is(.btn, .cbi-button).cbi-button-reset:hover { color: var(--text); }
|
||||
|
||||
/* dynamic list */
|
||||
.cbi-dynlist { display: flex; flex-direction: column; gap: 6px; max-width: 440px; }
|
||||
.cbi-dynlist { display: flex; flex-direction: column; gap: 6px; max-width: var(--field-max); }
|
||||
.cbi-dynlist > .item {
|
||||
position: relative;
|
||||
display: flex; align-items: center;
|
||||
min-height: 30px;
|
||||
padding: 4px 34px 4px 10px;
|
||||
min-height: var(--ctl-h);
|
||||
padding: 4px calc(var(--ctl-h) + 4px) 4px 10px;
|
||||
background: var(--s2);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--r);
|
||||
@@ -1155,11 +1258,11 @@ input[type="button"], input[type="reset"], input[type="submit"]) {
|
||||
.cbi-dynlist > .item::after {
|
||||
content: "\00d7";
|
||||
position: absolute; top: 0; right: 0; bottom: 0;
|
||||
width: 30px;
|
||||
width: var(--ctl-h);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
border-left: 1px solid var(--line);
|
||||
color: var(--text-3);
|
||||
font: 400 16px/1 var(--font);
|
||||
font: 400 var(--fs-lg)/1 var(--font);
|
||||
cursor: pointer;
|
||||
}
|
||||
.cbi-dynlist > .item:hover::after { color: var(--err); background: var(--err-soft); border-radius: 0 var(--r) var(--r) 0; }
|
||||
@@ -1168,7 +1271,7 @@ input[type="button"], input[type="reset"], input[type="submit"]) {
|
||||
.cbi-dynlist[disabled] > .item::after { display: none; }
|
||||
.cbi-dynlist > .add-item { max-width: none; }
|
||||
.cbi-dynlist > .add-item > .cbi-dropdown { max-width: none; }
|
||||
.cbi-dynlist > .add-item > .cbi-button-add { min-width: 34px; font-family: var(--mono); font-size: var(--fs-md); }
|
||||
.cbi-dynlist > .add-item > .cbi-button-add { min-width: var(--ctl-h); font-family: var(--mono); font-size: var(--fs-md); }
|
||||
/* add rows built without .control-group (e.g. System → SSH-Keys): input and button side by side */
|
||||
.cbi-dynlist > .add-item:not(.control-group) { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); max-width: 720px; }
|
||||
.cbi-dynlist > .add-item:not(.control-group) > input { flex: 1 1 320px; min-width: 0; margin: 0; }
|
||||
@@ -1242,13 +1345,13 @@ table { border-collapse: separate; border-spacing: 0; width: 100%; }
|
||||
.td:not(.cbi-value-field)[data-title*="Target" i], .td:not(.cbi-value-field)[data-title*="Source" i], .td:not(.cbi-value-field)[data-title*="DUID" i], .td:not(.cbi-value-field)[data-title="PID"],
|
||||
.td:not(.cbi-value-field)[data-title*="Metric" i], .td:not(.cbi-value-field)[data-title*="Priority" i], .td:not(.cbi-value-field)[data-title*="Remaining" i], .td:not(.cbi-value-field)[data-title*="Usage" i] {
|
||||
white-space: nowrap;
|
||||
font-family: var(--mono); font-size: 12.5px;
|
||||
font-family: var(--mono); font-size: var(--fs-sm);
|
||||
font-variant-numeric: tabular-nums slashed-zero;
|
||||
}
|
||||
.td > span:has(> span + br + span) { display: flex; flex-direction: column; gap: 1px; }
|
||||
.td > span:has(> span + br + span) > br { display: none; }
|
||||
.td > span:has(> span + br + span) > span { white-space: nowrap; font: 12px/1.5 var(--mono); }
|
||||
.td > span:has(> span + br + span) > span:not(:first-child) { color: var(--text-3); font-size: 11.5px; }
|
||||
.td > span:has(> span + br + span) > span { white-space: nowrap; font: var(--fs-sm)/1.5 var(--mono); }
|
||||
.td > span:has(> span + br + span) > span:not(:first-child) { color: var(--text-3); font-size: var(--fs-micro); }
|
||||
|
||||
/* badges inside cells are content, not pills: icon + text */
|
||||
.td .ifacebadge, .td .ifacebadge.large {
|
||||
@@ -1257,7 +1360,7 @@ table { border-collapse: separate; border-spacing: 0; width: 100%; }
|
||||
font-size: inherit; white-space: nowrap;
|
||||
}
|
||||
.td .ifacebadge img, .td .ifacebadge img[style] { width: 18px !important; height: 18px !important; flex: none; }
|
||||
.td .ifacebadge small { color: var(--text-3); font-family: var(--mono); font-size: 11.5px; }
|
||||
.td .ifacebadge small { color: var(--text-3); font-family: var(--mono); font-size: var(--fs-micro); }
|
||||
.td > .ifacebadge + .ifacebadge, .td > span + .ifacebadge { margin-left: 10px; }
|
||||
.cbi-section-table-descr > .th { font-weight: 400; text-transform: none; letter-spacing: 0; font-size: var(--fs-sm); }
|
||||
.cbi-section-table-cell, .cbi-section-table-row > .td { vertical-align: middle; }
|
||||
@@ -1273,7 +1376,7 @@ table { border-collapse: separate; border-spacing: 0; width: 100%; }
|
||||
.td.cbi-value-field.inactive { visibility: hidden; }
|
||||
.td.cbi-section-actions, .th.cbi-section-actions { text-align: right; white-space: nowrap; width: 1%; }
|
||||
.td.cbi-section-actions > div { display: inline-flex; gap: 4px; flex-wrap: nowrap; align-items: center; }
|
||||
.td.cbi-section-actions .btn, .td.cbi-section-actions .cbi-button { min-height: 28px; padding: 0 10px; font-size: var(--fs-sm); }
|
||||
.td.cbi-section-actions .btn, .td.cbi-section-actions .cbi-button { padding: 0 10px; }
|
||||
.drag-handle { cursor: grab; color: var(--text-3); padding: 0 6px; font-family: var(--mono); }
|
||||
.drag-over-above > .td, .drag-over-above > td { box-shadow: inset 0 2px 0 var(--accent-text); }
|
||||
.drag-over-below > .td, .drag-over-below > td { box-shadow: inset 0 -2px 0 var(--accent-text); }
|
||||
@@ -1294,38 +1397,120 @@ div.right, div.left { display: block; }
|
||||
div.right { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-4); }
|
||||
div.right > .btn, div.right > .cbi-button, div.right > button { margin-left: 0; }
|
||||
|
||||
/* in-map section tabs (ui.tabs) */
|
||||
/* Tabs inside a page (ui.tabs), one look per level:
|
||||
- tabs standing at page level (not inside a form section or another
|
||||
tab) are the page's sub-pages when the menu shows no page tabs: they
|
||||
take the page-tab underline, like .vt-tabs (Interfaces / Devices /
|
||||
..., DHCP's Leases / dnsmasq, Channel Analysis's radios). Under
|
||||
.vt-tabs they are the first level inside the page instead;
|
||||
- the first level inside a page, form or modal: a segmented control;
|
||||
- tabs inside a tab: a side list where the pane is wide enough
|
||||
(container query on the pane, so modals and pages alike), chips
|
||||
where it is not and at every deeper level.
|
||||
A level is a pane of a section's option tabs (.cbi-section-node-tabbed);
|
||||
map-level panes are not counted, so a page's sub-pages add no level. */
|
||||
.cbi-tabmenu {
|
||||
display: flex; flex-wrap: nowrap; gap: var(--sp-1);
|
||||
margin: 0 0 var(--sp-4); padding: 0;
|
||||
display: flex; flex-wrap: nowrap; align-items: center; gap: 2px;
|
||||
width: fit-content; max-width: 100%; min-height: var(--ctl-h);
|
||||
margin: 0 0 var(--sp-5); padding: 2px;
|
||||
list-style: none;
|
||||
border-bottom: 1px solid var(--line);
|
||||
background: var(--seg-bg);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--r-lg);
|
||||
overflow-x: auto;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
.cbi-tabmenu::-webkit-scrollbar { display: none; }
|
||||
.cbi-tabmenu > li { position: relative; flex: none; }
|
||||
.cbi-tabmenu > li > a {
|
||||
display: inline-flex; align-items: center; gap: 6px;
|
||||
height: 36px; padding: 0 var(--sp-3);
|
||||
display: flex; align-items: center; gap: 6px;
|
||||
height: calc(var(--ctl-h) - 6px); padding: 0 var(--sp-3);
|
||||
border-radius: var(--r);
|
||||
color: var(--text-2);
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
.cbi-tabmenu > li > a:hover { color: var(--text); }
|
||||
.cbi-tabmenu > li.cbi-tab > a { color: var(--text); font-weight: 600; }
|
||||
.cbi-tabmenu > li.cbi-tab::after {
|
||||
content: ""; position: absolute; left: var(--sp-3); right: var(--sp-3); bottom: -1px;
|
||||
.cbi-tabmenu > li.cbi-tab > a { background: var(--seg-on); color: var(--text); font-weight: 600; box-shadow: var(--seg-on-ring); }
|
||||
|
||||
html:not(:has(.vt-tabs:not([hidden]))) #view .cbi-tabmenu:not(.cbi-section *, [data-tab-title] *) {
|
||||
gap: var(--sp-1);
|
||||
width: auto; padding: 0;
|
||||
background: none; border: 0; border-bottom: 1px solid var(--line); border-radius: 0;
|
||||
}
|
||||
html:not(:has(.vt-tabs:not([hidden]))) #view .cbi-tabmenu:not(.cbi-section *, [data-tab-title] *) > li > a { height: var(--ctl-h); border-radius: 0; }
|
||||
html:not(:has(.vt-tabs:not([hidden]))) #view .cbi-tabmenu:not(.cbi-section *, [data-tab-title] *) > li.cbi-tab > a { background: none; box-shadow: none; }
|
||||
html:not(:has(.vt-tabs:not([hidden]))) #view .cbi-tabmenu:not(.cbi-section *, [data-tab-title] *) > li.cbi-tab::after {
|
||||
content: ""; position: absolute; left: var(--sp-3); right: var(--sp-3); bottom: 0;
|
||||
height: 2px; background: var(--accent-text); border-radius: 2px 2px 0 0;
|
||||
}
|
||||
|
||||
.cbi-section-node-tabbed > [data-tab-title] { container-type: inline-size; }
|
||||
.cbi-section-node-tabbed > [data-tab-title] .cbi-tabmenu {
|
||||
flex-wrap: wrap; gap: var(--sp-2);
|
||||
width: auto; margin-bottom: var(--sp-4); padding: 0;
|
||||
background: none; border: 0; border-radius: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
.cbi-section-node-tabbed > [data-tab-title] .cbi-tabmenu > li > a {
|
||||
height: var(--ctl-h); padding: 0 14px;
|
||||
border: 1px solid var(--line-2); border-radius: 999px;
|
||||
}
|
||||
.cbi-section-node-tabbed > [data-tab-title] .cbi-tabmenu > li.cbi-tab > a {
|
||||
background: var(--accent-soft); border-color: var(--accent-line);
|
||||
color: var(--accent-text); box-shadow: none;
|
||||
}
|
||||
@container (min-width: 640px) {
|
||||
.cbi-section-node-tabbed > [data-tab-title] :has(> .cbi-tabmenu) {
|
||||
display: grid;
|
||||
grid-template-columns: 168px minmax(0, 1fr);
|
||||
column-gap: var(--sp-6);
|
||||
align-items: start;
|
||||
}
|
||||
.cbi-section-node-tabbed > [data-tab-title] :has(> .cbi-tabmenu) > * { grid-column: 1 / -1; }
|
||||
.cbi-section-node-tabbed > [data-tab-title] :has(> .cbi-tabmenu) > .cbi-tabmenu + * { grid-column: 2; }
|
||||
.cbi-section-node-tabbed > [data-tab-title] .cbi-tabmenu {
|
||||
grid-column: 1;
|
||||
flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: 2px;
|
||||
margin: 0;
|
||||
}
|
||||
.cbi-section-node-tabbed > [data-tab-title] .cbi-tabmenu > li > a {
|
||||
justify-content: space-between;
|
||||
padding: 0 var(--sp-3);
|
||||
border: 0; border-radius: var(--r);
|
||||
white-space: normal; line-height: 1.25;
|
||||
}
|
||||
.cbi-section-node-tabbed > [data-tab-title] .cbi-tabmenu > li > a:hover { background: var(--s3); }
|
||||
.cbi-section-node-tabbed > [data-tab-title] .cbi-tabmenu > li.cbi-tab > a { background: var(--accent-soft); box-shadow: inset 2px 0 0 var(--accent-line); }
|
||||
/* beside the list there is no card edge to bleed to: table sections and
|
||||
tables fit the column */
|
||||
.cbi-section-node-tabbed > [data-tab-title] :has(> .cbi-tabmenu) > .cbi-tabmenu + * .cbi-tblsection { margin-left: 0; margin-right: 0; padding-left: 0; padding-right: 0; }
|
||||
.cbi-section-node-tabbed > [data-tab-title] :has(> .cbi-tabmenu) > .cbi-tabmenu + * .table { width: 100% !important; margin-left: 0; margin-right: 0; }
|
||||
.cbi-section-node-tabbed > [data-tab-title] :has(> .cbi-tabmenu) > .cbi-tabmenu + * .table .tr > :is(.th, .td):first-child { padding-left: 0; }
|
||||
.cbi-section-node-tabbed > [data-tab-title] :has(> .cbi-tabmenu) > .cbi-tabmenu + * .table .tr > :is(.th, .td):last-child { padding-right: 0; }
|
||||
/* deeper levels: back to the chips above */
|
||||
.cbi-section-node-tabbed > [data-tab-title] .cbi-section-node-tabbed > [data-tab-title] :has(> .cbi-tabmenu) { display: block; }
|
||||
.cbi-section-node-tabbed > [data-tab-title] .cbi-section-node-tabbed > [data-tab-title] .cbi-tabmenu {
|
||||
flex-direction: row; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
|
||||
margin: 0 0 var(--sp-4);
|
||||
}
|
||||
.cbi-section-node-tabbed > [data-tab-title] .cbi-section-node-tabbed > [data-tab-title] .cbi-tabmenu > li > a {
|
||||
justify-content: normal;
|
||||
padding: 0 14px;
|
||||
border: 1px solid var(--line-2); border-radius: 999px;
|
||||
white-space: nowrap; line-height: inherit;
|
||||
}
|
||||
.cbi-section-node-tabbed > [data-tab-title] .cbi-section-node-tabbed > [data-tab-title] .cbi-tabmenu > li > a:hover { background: none; }
|
||||
.cbi-section-node-tabbed > [data-tab-title] .cbi-section-node-tabbed > [data-tab-title] .cbi-tabmenu > li.cbi-tab > a { border-color: var(--accent-line); box-shadow: none; }
|
||||
}
|
||||
.cbi-tabmenu > li[data-errors] > a::after {
|
||||
content: attr(data-errors);
|
||||
display: inline-flex; align-items: center; justify-content: center;
|
||||
min-width: 18px; height: 18px; padding: 0 5px;
|
||||
border-radius: 999px;
|
||||
background: var(--err); color: #fff;
|
||||
font: 700 10.5px/1 var(--mono);
|
||||
font: 700 var(--fs-micro)/1 var(--mono);
|
||||
}
|
||||
.cbi-tabmenu > li.cbi-tab-disabled[data-errors] > a { color: var(--err); }
|
||||
[data-tab-title]:not([data-tab-active="true"]) { display: none; }
|
||||
@@ -1386,13 +1571,13 @@ div.right > .btn, div.right > .cbi-button, div.right > button { margin-left: 0;
|
||||
min-width: 0;
|
||||
white-space: normal; overflow-wrap: anywhere;
|
||||
color: var(--text);
|
||||
font: 400 12px/1.55 var(--mono);
|
||||
font: 400 var(--fs-sm)/1.55 var(--mono);
|
||||
font-variant-numeric: tabular-nums slashed-zero;
|
||||
}
|
||||
:is(.ifacebox-body, .ifacebadge) > span:has(> .nowrap) > .nowrap:not(:has(> strong)) { display: block; }
|
||||
:is(.ifacebox-body, .ifacebadge) > span:has(> .nowrap) > .nowrap > strong {
|
||||
color: var(--text-3);
|
||||
font: 600 10.5px/1.55 var(--font);
|
||||
font: 600 var(--fs-micro)/1.55 var(--font);
|
||||
letter-spacing: .06em; text-transform: uppercase;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -1452,7 +1637,7 @@ div.right > .btn, div.right > .cbi-button, div.right > button { margin-left: 0;
|
||||
padding: 2px 8px;
|
||||
border: 1px solid var(--line-2); border-radius: 999px;
|
||||
color: var(--text-2);
|
||||
font: 600 10.5px/1.5 var(--mono); letter-spacing: .02em;
|
||||
font: 600 var(--fs-micro)/1.5 var(--mono); letter-spacing: .02em;
|
||||
}
|
||||
.network-status-table .ifacebox-body { display: flex; flex-direction: column; gap: 14px; padding: 8px 16px 16px; }
|
||||
.network-status-table .ifacebox-body > div:not(:empty) {
|
||||
@@ -1474,7 +1659,7 @@ div.right > .btn, div.right > .cbi-button, div.right > button { margin-left: 0;
|
||||
white-space: normal;
|
||||
}
|
||||
.network-status-table .ifacebox .ifacebadge > img { width: 18px; height: 18px; margin-top: 1px; }
|
||||
.network-status-table .ifacebox .ifacebadge > span > .nowrap:first-child { display: block; margin-bottom: 4px; font: 600 13px/1.4 var(--font); }
|
||||
.network-status-table .ifacebox .ifacebadge > span > .nowrap:first-child { display: block; margin-bottom: 4px; font: 600 var(--fs-base)/1.4 var(--font); }
|
||||
.network-status-table .ifacebox .ifacebadge > span > .nowrap:first-child > strong { display: none; }
|
||||
|
||||
/* zone colours arrive inline (--zone-color-rgb + background-color): tint instead */
|
||||
@@ -1522,7 +1707,7 @@ div.right > .btn, div.right > .cbi-button, div.right > button { margin-left: 0;
|
||||
display: flex; align-items: center;
|
||||
padding: 0 8px;
|
||||
color: var(--text);
|
||||
font: 500 11.5px/1 var(--mono);
|
||||
font: 500 var(--fs-micro)/1 var(--mono);
|
||||
font-variant-numeric: tabular-nums;
|
||||
white-space: nowrap;
|
||||
z-index: 1;
|
||||
@@ -1551,7 +1736,6 @@ div.right > .btn, div.right > .cbi-button, div.right > button { margin-left: 0;
|
||||
.alert-message.success { border-left-color: var(--ok); background: color-mix(in srgb, var(--ok-soft) 60%, var(--s1)); }
|
||||
.alert-message.warning { border-left-color: var(--warn); background: color-mix(in srgb, var(--warn-soft) 70%, var(--s1)); }
|
||||
.alert-message.error, .alert-message.danger { border-left-color: var(--err); background: color-mix(in srgb, var(--err-soft) 70%, var(--s1)); }
|
||||
.alert-message .btn { min-height: 28px; }
|
||||
|
||||
/* spinners */
|
||||
.spinning { position: relative; }
|
||||
@@ -1743,7 +1927,7 @@ body.modal-overlay-active #modal_overlay { display: block; }
|
||||
margin: 0 0 var(--sp-4);
|
||||
background: var(--s1);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 10px;
|
||||
border-radius: var(--r-lg);
|
||||
box-shadow: var(--v-shadow);
|
||||
overflow: clip;
|
||||
}
|
||||
@@ -1755,7 +1939,8 @@ body.modal-overlay-active #modal_overlay { display: block; }
|
||||
.includes { margin-top: var(--sp-4); }
|
||||
#view > .cbi-section:first-child { margin-top: 0; }
|
||||
.cbi-section > div[style*="display: none"] + div { display: block; }
|
||||
.wifi-qr-code-content, .qr-code { background: #fff; padding: var(--sp-2); border-radius: var(--r); }
|
||||
/* the QR image gets a white tile; the "Generate QR" button (also .qr-code) stays a button */
|
||||
.wifi-qr-code-content, div.qr-code { background: #fff; padding: var(--sp-2); border-radius: var(--r); }
|
||||
iframe { border: 1px solid var(--line); border-radius: var(--r); }
|
||||
|
||||
/* ------------------------------------------------------ 7b. stock charts
|
||||
@@ -1798,7 +1983,7 @@ iframe { border: 1px solid var(--line); border-radius: var(--r); }
|
||||
#view div[style*="height:300px"][style*="background"] svg text, #view div[id="channel_graph"] svg text {
|
||||
fill: var(--v-chart-axis) !important;
|
||||
text-shadow: none !important;
|
||||
font: 500 10.5px/1 var(--v-mono) !important;
|
||||
font: 500 var(--fs-micro)/1 var(--v-mono) !important;
|
||||
font-variant-numeric: tabular-nums;
|
||||
letter-spacing: .02em;
|
||||
paint-order: stroke; /* halo: labels stay legible over areas */
|
||||
@@ -1821,7 +2006,7 @@ body[data-page^="admin-status-realtime"] #view svg polyline:is(#load05, #tx, #tc
|
||||
/* "(4 minute window, 3 second interval)" */
|
||||
body[data-page^="admin-status-realtime"] #view .cbi-section > br { display: none; }
|
||||
body[data-page^="admin-status-realtime"] #view .cbi-section > div.right:has(> small[id^="scale"]) { margin: 6px 0 0; }
|
||||
body[data-page^="admin-status-realtime"] #view small[id^="scale"] { color: var(--v-chart-axis); font: 10.5px/1.4 var(--v-mono); letter-spacing: .02em; }
|
||||
body[data-page^="admin-status-realtime"] #view small[id^="scale"] { color: var(--v-chart-axis); font: var(--fs-micro)/1.4 var(--v-mono); letter-spacing: .02em; }
|
||||
body[data-page^="admin-status-realtime"] #view .cbi-section > .table ~ div[style*="height:300px"] { margin-top: var(--sp-6); }
|
||||
body[data-page^="admin-status-realtime"] #view .cbi-section-create:empty { display: none; }
|
||||
|
||||
@@ -1868,11 +2053,11 @@ body[data-page^="admin-status-realtime"] #view .table:has(strong[style*="border-
|
||||
}
|
||||
body[data-page^="admin-status-realtime"] #view .table:has(strong[style*="border-bottom"]) > .tr > .td:is(:nth-child(2), :nth-child(4), :nth-child(6)) {
|
||||
font-family: var(--v-mono); font-variant-numeric: tabular-nums;
|
||||
color: var(--v-text-3); font-size: 11.5px;
|
||||
color: var(--v-text-3); font-size: var(--fs-micro);
|
||||
white-space: nowrap;
|
||||
}
|
||||
body[data-page^="admin-status-realtime"] #view .table:has(strong[style*="border-bottom"]) > .tr > .td:is(:nth-child(2), :nth-child(4), :nth-child(6))::first-line { color: var(--v-text-2); font-size: 12.5px; }
|
||||
body[data-page^="admin-status-realtime"] #view .table:has(strong[style*="border-bottom"]) > .tr > .td:nth-child(2)::first-line { color: var(--v-text); font-weight: 650; font-size: 14px; }
|
||||
body[data-page^="admin-status-realtime"] #view .table:has(strong[style*="border-bottom"]) > .tr > .td:is(:nth-child(2), :nth-child(4), :nth-child(6))::first-line { color: var(--v-text-2); font-size: var(--fs-sm); }
|
||||
body[data-page^="admin-status-realtime"] #view .table:has(strong[style*="border-bottom"]) > .tr > .td:nth-child(2)::first-line { color: var(--v-text); font-weight: 650; font-size: var(--fs-md); }
|
||||
body[data-page^="admin-status-realtime"] #view .tr:has(:is(#lb_load01_cur, #rx_bw_cur, #rssi_bw_cur, #lb_udp_cur)) { --key: var(--v-chart-1); }
|
||||
body[data-page^="admin-status-realtime"] #view .tr:has(:is(#lb_load05_cur, #tx_bw_cur, #rate_bw_cur, #lb_tcp_cur)) { --key: var(--v-chart-2); }
|
||||
body[data-page^="admin-status-realtime"] #view .tr:has(:is(#lb_load15_cur, #noise_bw_cur, #lb_otr_cur)) { --key: var(--v-chart-3); }
|
||||
@@ -1887,22 +2072,24 @@ body[data-page^="admin-status-realtime"] #view #settings-row input { max-width:
|
||||
#connections .tr > .th:first-child { padding-left: var(--card-px); }
|
||||
#connections .tr:not(.table-titles) > .td:is(:nth-child(1), :nth-child(2)) {
|
||||
color: var(--v-text-2);
|
||||
font: 600 10.5px/1.5 var(--v-mono); letter-spacing: .05em;
|
||||
font: 600 var(--fs-micro)/1.5 var(--v-mono); letter-spacing: .05em;
|
||||
}
|
||||
#connections .tr:not(.table-titles) > .td:is(:nth-child(3), :nth-child(4)) { font-family: var(--v-mono); font-size: 12px; overflow-wrap: break-word; }
|
||||
#connections .tr:not(.table-titles) > .td:is(:nth-child(3), :nth-child(4)) { font-family: var(--v-mono); font-size: var(--fs-sm); overflow-wrap: break-word; }
|
||||
#connections .tr > .th:is(:nth-child(1), :nth-child(2)) { width: 9%; }
|
||||
#connections .tr > .th:is(:nth-child(3), :nth-child(4)) { width: 31%; }
|
||||
#connections .tr > .th:nth-child(5) { width: 20%; }
|
||||
#connections .tr:not(.table-titles) > .td:last-child { font: 12px var(--v-mono); font-variant-numeric: tabular-nums; color: var(--v-text-2); }
|
||||
#connections .tr:not(.table-titles) > .td:last-child { font: var(--fs-sm) var(--v-mono); font-variant-numeric: tabular-nums; color: var(--v-text-2); }
|
||||
|
||||
/* channel analysis: each tab is one card (graph over table) */
|
||||
body[data-page^="admin-status-channel_analysis"] #view .cbi-title-section { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-3); margin-bottom: var(--sp-4); }
|
||||
body[data-page^="admin-status-channel_analysis"] #view .cbi-title-section > h2 { margin: 0; }
|
||||
/* the buttons keep the right edge when the title repeats the breadcrumb and is hidden */
|
||||
body[data-page^="admin-status-channel_analysis"] #view .cbi-title-section > .cbi-title-buttons { margin-left: auto; }
|
||||
body[data-page^="admin-status-channel_analysis"] #view [data-tab-title]:not(.cbi-section) {
|
||||
padding: var(--card-py) var(--card-px) 0;
|
||||
background: var(--s1);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 10px;
|
||||
border-radius: var(--r-lg);
|
||||
box-shadow: var(--v-shadow);
|
||||
overflow: clip;
|
||||
}
|
||||
@@ -1938,7 +2125,7 @@ body[data-page^="admin-status-channel_analysis"] #view [data-tab-title]:not([dat
|
||||
.v-ca-shape[data-v-own] { stroke-width: 2.25px; }
|
||||
#view div[id="channel_graph"] svg text.v-ca-label {
|
||||
fill: var(--v-text-2) !important;
|
||||
font: 500 11px/1 var(--v-font) !important;
|
||||
font: 500 var(--fs-micro)/1 var(--v-font) !important;
|
||||
letter-spacing: 0;
|
||||
paint-order: stroke;
|
||||
stroke: var(--s1); stroke-width: 3px; stroke-linejoin: round;
|
||||
@@ -2068,7 +2255,7 @@ html:not([data-darkmode="true"]) .vt-login-page::before {
|
||||
padding: 10px 12px;
|
||||
}
|
||||
.cbi-section-table .ifacebox-body > br { display: none; }
|
||||
.cbi-section-table .ifacebox-body > small { flex-basis: 100%; color: var(--text-2); font: 12px/1.3 var(--mono); }
|
||||
.cbi-section-table .ifacebox-body > small { flex-basis: 100%; color: var(--text-2); font: var(--fs-sm)/1.3 var(--mono); }
|
||||
/* "( dev dev dev )": drop the parentheses, group the member ports */
|
||||
.cbi-section-table .ifacebox-body > span:not(.cbi-tooltip-container) {
|
||||
display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px;
|
||||
@@ -2087,11 +2274,11 @@ html:not([data-darkmode="true"]) .vt-login-page::before {
|
||||
[id$="-ifc-description"] > .nowrap {
|
||||
display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 0 1 auto;
|
||||
white-space: normal; overflow-wrap: anywhere;
|
||||
font: 12.5px/1.45 var(--mono); font-variant-numeric: tabular-nums slashed-zero;
|
||||
font: var(--fs-sm)/1.45 var(--mono); font-variant-numeric: tabular-nums slashed-zero;
|
||||
}
|
||||
[id$="-ifc-description"] > .nowrap > strong, .td[data-name="_stat"] .nowrap > strong {
|
||||
color: var(--text-3);
|
||||
font: 600 11.5px/1.5 var(--font); letter-spacing: .06em; text-transform: uppercase;
|
||||
font: 600 var(--fs-micro)/1.5 var(--font); letter-spacing: .06em; text-transform: uppercase;
|
||||
}
|
||||
|
||||
/* Network -> Wireless: radios as group headers, networks as rows */
|
||||
@@ -2121,7 +2308,7 @@ html:not([data-darkmode="true"]) .vt-login-page::before {
|
||||
.cbi-progressbar::before {
|
||||
inset: auto 0 calc(100% + 5px) 0; padding: 0;
|
||||
color: var(--text-2);
|
||||
font: 500 11.5px/1.2 var(--mono);
|
||||
font: 500 var(--fs-micro)/1.2 var(--mono);
|
||||
}
|
||||
|
||||
/* fused memory / storage meters (built by menu-vantage.js) */
|
||||
@@ -2130,9 +2317,9 @@ html:not([data-darkmode="true"]) .vt-login-page::before {
|
||||
.v-meter + .v-meter { margin-top: var(--sp-3); padding-top: var(--sp-4); border-top: 1px solid var(--line); }
|
||||
.v-meter-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; }
|
||||
.v-meter-title { color: var(--text); font-weight: 600; }
|
||||
.v-meter-big { font: 650 22px/1 var(--mono); letter-spacing: -.02em; color: var(--text); }
|
||||
.v-meter-big { font: 650 var(--fs-xl)/1 var(--mono); letter-spacing: -.02em; color: var(--text); }
|
||||
.v-meter-big small { margin-left: 6px; font: 500 var(--fs-sm) var(--font); letter-spacing: 0; color: var(--text-2); }
|
||||
.v-meter-sub { margin-left: auto; color: var(--text-2); font: 12px/1.4 var(--mono); font-variant-numeric: tabular-nums; }
|
||||
.v-meter-sub { margin-left: auto; color: var(--text-2); font: var(--fs-sm)/1.4 var(--mono); font-variant-numeric: tabular-nums; }
|
||||
.v-meter-bar {
|
||||
position: relative;
|
||||
display: flex;
|
||||
@@ -2155,16 +2342,16 @@ html:not([data-darkmode="true"]) .vt-login-page::before {
|
||||
.v-seg.is-crit { background: var(--err); }
|
||||
.v-meter-legend { display: flex; flex-wrap: wrap; gap: 6px 20px; margin: 0; padding: 0; list-style: none; font-size: var(--fs-sm); color: var(--text-2); }
|
||||
.v-meter-legend li { display: inline-flex; align-items: center; gap: 7px; }
|
||||
.v-meter-legend b { color: var(--text); font: 600 12px var(--mono); font-variant-numeric: tabular-nums; }
|
||||
.v-meter-legend b { color: var(--text); font: 600 var(--fs-sm) var(--mono); font-variant-numeric: tabular-nums; }
|
||||
.v-meter-legend em { color: var(--text-3); font-style: normal; font-size: var(--fs-micro); }
|
||||
.v-key { width: 10px; height: 10px; border-radius: 2px; flex: none; }
|
||||
.v-key.v-seg-free { background: var(--s3); box-shadow: inset 0 0 0 1px var(--line-2); }
|
||||
.v-meter-rows { display: grid; grid-template-columns: minmax(120px, max-content) minmax(0, 1fr) max-content; gap: 14px 20px; padding: 4px 0 6px; }
|
||||
.v-meter-row { display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; grid-template-areas: "label bar val"; align-items: center; }
|
||||
.v-meter-row > .v-meter-label { grid-area: label; color: var(--text-2); overflow-wrap: anywhere; }
|
||||
.v-meter-row > .v-meter-label small { display: block; color: var(--text-3); font: 11px var(--mono); }
|
||||
.v-meter-row > .v-meter-label small { display: block; color: var(--text-3); font: var(--fs-micro) var(--mono); }
|
||||
.v-meter-row > .v-meter-bar { grid-area: bar; }
|
||||
.v-meter-row > .v-meter-val { grid-area: val; color: var(--text-2); font: 12px var(--mono); font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
|
||||
.v-meter-row > .v-meter-val { grid-area: val; color: var(--text-2); font: var(--fs-sm) var(--mono); font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
|
||||
.v-meter-row > .v-meter-val b { color: var(--text); font-weight: 600; }
|
||||
.v-sr { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
|
||||
|
||||
@@ -2230,7 +2417,7 @@ html:not([data-darkmode="true"]) .vt-login-page::before {
|
||||
.vt-rail-link .vt-rail-label, html[data-rail="pinned"] .vt-rail-link .vt-rail-label {
|
||||
display: block !important;
|
||||
max-width: 100%;
|
||||
font-size: 10.5px; font-weight: 500;
|
||||
font-size: var(--fs-micro); font-weight: 500;
|
||||
text-align: center;
|
||||
}
|
||||
.vt-rail-item.is-active > .vt-rail-link::before { left: 14px; right: 14px; top: -6px; bottom: auto; width: auto; height: 2px; border-radius: 0 0 2px 2px; }
|
||||
@@ -2286,7 +2473,31 @@ html:not([data-darkmode="true"]) .vt-login-page::before {
|
||||
.cbi-value { grid-template-columns: minmax(0, 1fr); row-gap: 6px; }
|
||||
.cbi-value > .cbi-value-title { padding-top: 0; }
|
||||
.cbi-value > .cbi-value-field { grid-column: 1; }
|
||||
.vt-main input, .vt-main select, .vt-main textarea, .cbi-dropdown, .modal input, .modal select { font-size: 16px !important; }
|
||||
.cbi-value[data-v-help] > .cbi-value-field { grid-row: 2; }
|
||||
.cbi-value:has(> .vt-help:not([hidden])) > .cbi-value-title { align-self: center; }
|
||||
/* stacked, there is nothing beside the title to line up with */
|
||||
.cbi-value > .cbi-value-title > br:first-child { display: none; }
|
||||
.cbi-value:has(> .cbi-value-title > br:first-child) > .vt-help { margin-top: 0; }
|
||||
/* checkbox rows: box, label and (i) on one line, help below. The field
|
||||
box dissolves so its children join the row grid; LuCI's nodes stay put. */
|
||||
.cbi-value:has(> .cbi-value-field > .cbi-checkbox) {
|
||||
grid-template-columns: auto minmax(0, 1fr) auto;
|
||||
column-gap: var(--sp-3);
|
||||
align-items: center;
|
||||
}
|
||||
.cbi-value:has(> .cbi-value-field > .cbi-checkbox) > .cbi-value-field { display: contents; }
|
||||
.cbi-value:has(> .cbi-value-field > .cbi-checkbox) > .cbi-value-field > .cbi-checkbox { grid-row: 1; grid-column: 1; }
|
||||
.cbi-value:has(> .cbi-value-field > .cbi-checkbox) > .cbi-value-title { grid-row: 1; grid-column: 2; padding: 0; }
|
||||
.cbi-value:has(> .cbi-value-field > .cbi-checkbox) > .vt-help { grid-row: 1; grid-column: 3; }
|
||||
.cbi-value:has(> .cbi-value-field > .cbi-checkbox) > .cbi-value-field > :not(.cbi-checkbox) { grid-column: 1 / -1; }
|
||||
/* a segmented control wraps its segments instead of hiding them */
|
||||
.cbi-tabmenu:not(.cbi-section-node-tabbed > [data-tab-title] *) { flex-wrap: wrap; width: auto; }
|
||||
.cbi-tabmenu:not(.cbi-section-node-tabbed > [data-tab-title] *) > li { flex: 1 1 auto; }
|
||||
.cbi-tabmenu:not(.cbi-section-node-tabbed > [data-tab-title] *) > li > a { justify-content: center; }
|
||||
/* ... while an underline strip scrolls, like the page tabs */
|
||||
html:not(:has(.vt-tabs:not([hidden]))) #view .cbi-tabmenu:not(.cbi-section *, [data-tab-title] *) { flex-wrap: nowrap; }
|
||||
html:not(:has(.vt-tabs:not([hidden]))) #view .cbi-tabmenu:not(.cbi-section *, [data-tab-title] *) > li { flex: none; }
|
||||
html:not(:has(.vt-tabs:not([hidden]))) #view .cbi-tabmenu:not(.cbi-section *, [data-tab-title] *) > li > a { justify-content: normal; }
|
||||
.cbi-dropdown, .vt-main input, .vt-main select, .control-group, .cbi-dynlist { max-width: none; }
|
||||
|
||||
/* tables become cards */
|
||||
@@ -2345,6 +2556,16 @@ html:not([data-darkmode="true"]) .vt-login-page::before {
|
||||
.vt-pal-foot > span:not(.vt-pal-count) { display: none; }
|
||||
}
|
||||
|
||||
/* touch, at any width: 16px text in fields (iOS zooms below that),
|
||||
bigger check marks, a little more air between rows */
|
||||
@media (pointer: coarse), (max-width: 720px) {
|
||||
.vt-main input, .vt-main select, .vt-main textarea, .cbi-dropdown:not(.btn, .cbi-button), .modal input, .modal select { font-size: 16px !important; }
|
||||
}
|
||||
@media (pointer: coarse) {
|
||||
input[type="checkbox"], input[type="radio"] { width: 20px; height: 20px; }
|
||||
.cbi-value { padding: 8px 0; }
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------- motion */
|
||||
|
||||
/* phones: content in cards wraps instead of pushing the card wider */
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:918
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:951
|
||||
msgid "Actions"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:914
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:915
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:916
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:947
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:948
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:949
|
||||
msgid "Appearance"
|
||||
msgstr ""
|
||||
|
||||
@@ -15,7 +15,7 @@ msgstr ""
|
||||
msgid "Authorization Required"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1092
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1125
|
||||
msgid "Auto"
|
||||
msgstr ""
|
||||
|
||||
@@ -23,52 +23,52 @@ msgstr ""
|
||||
msgid "Breadcrumb"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:263
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:269
|
||||
msgid "Buffered"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:274
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:284
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:288
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:280
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:290
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:294
|
||||
msgid "Cache"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:263
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:269
|
||||
msgid "Cached"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:344
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:350
|
||||
msgid "Channel"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:687
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:719
|
||||
msgid "Collapse navigation"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1093
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1126
|
||||
#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:81
|
||||
msgid "Colour theme"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:934
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:967
|
||||
msgid "Command palette"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1092
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1125
|
||||
msgid "Dark"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:687
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:719
|
||||
#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:54
|
||||
msgid "Expand navigation"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:916
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:949
|
||||
msgid "Follow system theme"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:275
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:289
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:281
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:295
|
||||
msgid "Free"
|
||||
msgstr ""
|
||||
|
||||
@@ -76,9 +76,9 @@ msgstr ""
|
||||
msgid "Home"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:274
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:283
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:287
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:280
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:289
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:293
|
||||
msgid "In use"
|
||||
msgstr ""
|
||||
|
||||
@@ -86,11 +86,11 @@ msgstr ""
|
||||
msgid "Invalid username and/or password! Please try again."
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:930
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:963
|
||||
msgid "Jump to a page or action…"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1092
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1125
|
||||
msgid "Light"
|
||||
msgstr ""
|
||||
|
||||
@@ -99,7 +99,7 @@ msgstr ""
|
||||
msgid "Log in"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:917
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:950
|
||||
#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:84
|
||||
msgid "Log out"
|
||||
msgstr ""
|
||||
@@ -108,12 +108,12 @@ msgstr ""
|
||||
msgid "Main navigation"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:258
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:273
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:264
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:279
|
||||
msgid "Memory"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1005
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1038
|
||||
msgid "No matching pages"
|
||||
msgstr ""
|
||||
|
||||
@@ -125,57 +125,69 @@ msgstr ""
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:793
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:825
|
||||
msgid "Press"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:932
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:965
|
||||
msgid "Results"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:930
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:963
|
||||
#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:74
|
||||
msgid "Search pages"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:917
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:950
|
||||
msgid "Session"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1283
|
||||
msgid "Show full description"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1272
|
||||
msgid "Show full help"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1272
|
||||
msgid "Show full help: %s"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/ucode/template/themes/vantage/header.ut:44
|
||||
msgid "Skip to content"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:310
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:316
|
||||
msgid "Storage"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:296
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:298
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:302
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:304
|
||||
msgid "Swap"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:263
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:269
|
||||
msgid "Swap free"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:275
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:281
|
||||
msgid "Total"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:262
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:268
|
||||
msgid "Total Available"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:914
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:947
|
||||
msgid "Use dark theme"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:915
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:948
|
||||
msgid "Use light theme"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:262
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:268
|
||||
msgid "Used"
|
||||
msgstr ""
|
||||
|
||||
@@ -183,54 +195,54 @@ msgstr ""
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:337
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:343
|
||||
msgid "Wireless"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:279
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:285
|
||||
msgid "available"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:940
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:973
|
||||
msgid "close"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:325
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:328
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:331
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:334
|
||||
msgid "free"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1007
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:1040
|
||||
msgid "items"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:938
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:971
|
||||
msgid "navigate"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:939
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:972
|
||||
msgid "open"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:773
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:805
|
||||
msgid "page"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:773
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:805
|
||||
msgid "pages"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:274
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:284
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:288
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:280
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:290
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:294
|
||||
msgid "reclaimable"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:793
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:825
|
||||
msgid "to search all pages"
|
||||
msgstr ""
|
||||
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:325
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:328
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:331
|
||||
#: luci-theme-vantage/htdocs/luci-static/resources/menu-vantage.js:334
|
||||
msgid "used"
|
||||
msgstr ""
|
||||
Reference in new issue
Block a user