🎈 Sync 2026-06-16 01:15:58
No files matched your search
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=luci-app-daede
|
PKG_NAME:=luci-app-daede
|
||||||
PKG_VERSION:=1.12.0
|
PKG_VERSION:=1.12.0
|
||||||
PKG_RELEASE:=9
|
PKG_RELEASE:=10
|
||||||
PKG_MAINTAINER:=kenzok8
|
PKG_MAINTAINER:=kenzok8
|
||||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
|
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
|
||||||
|
|
||||||
|
|||||||
@@ -139,9 +139,9 @@ return view.extend({
|
|||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
// run a backgrounded script, stream its log, then toast the result.
|
// run a backgrounded script and stream its log into the log pane until it
|
||||||
// Scripts end their log with "done (rc=N)"; poll until that appears.
|
// logs "done (rc=N)"; then refresh the badges. Result shows inline (no popup).
|
||||||
const runJob = function(script, arg, btn, logPath, label) {
|
const runJob = function(script, arg, btn, logPath) {
|
||||||
const orig = btn.textContent;
|
const orig = btn.textContent;
|
||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
btn.textContent = '...';
|
btn.textContent = '...';
|
||||||
@@ -149,20 +149,13 @@ return view.extend({
|
|||||||
const poll = function() {
|
const poll = function() {
|
||||||
return L.resolveDefault(fs.read_direct(logPath, 'text'), '').then(function(c) {
|
return L.resolveDefault(fs.read_direct(logPath, 'text'), '').then(function(c) {
|
||||||
if (c) { logPane.textContent = c; logPane.classList.add('show'); }
|
if (c) { logPane.textContent = c; logPane.classList.add('show'); }
|
||||||
const m = c.match(/done \(rc=(\d+)\)/);
|
if (/done \(rc=\d+\)/.test(c)) { refresh(); return; }
|
||||||
if (m) {
|
|
||||||
const ok = m[1] === '0';
|
|
||||||
ui.addNotification(null, E('p', label + ' · ' + (ok ? _('done') : _('failed'))), ok ? null : 'danger');
|
|
||||||
refresh();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (tries++ > 90) return;
|
if (tries++ > 90) return;
|
||||||
return new Promise(function(r) { setTimeout(r, 2000); }).then(poll);
|
return new Promise(function(r) { setTimeout(r, 2000); }).then(poll);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
return fs.exec('/usr/share/luci-app-daede/' + script, [arg]).then(function(res) {
|
return fs.exec('/usr/share/luci-app-daede/' + script, [arg]).then(function(res) {
|
||||||
if (res.code !== 0) { ui.addNotification(null, E('p', label + ' · ' + _('failed to start')), 'danger'); return; }
|
if (res.code === 0) return poll();
|
||||||
return poll();
|
|
||||||
}).catch(function() {}).finally(function() {
|
}).catch(function() {}).finally(function() {
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
btn.textContent = orig;
|
btn.textContent = orig;
|
||||||
@@ -171,16 +164,12 @@ return view.extend({
|
|||||||
|
|
||||||
// === Data updates (GeoIP / GeoSite) ===
|
// === Data updates (GeoIP / GeoSite) ===
|
||||||
const updateGeo = function(kind, btn) {
|
const updateGeo = function(kind, btn) {
|
||||||
return runJob('update-geo.sh', kind, btn,
|
return runJob('update-geo.sh', kind, btn, '/tmp/luci-app-daede.' + kind + '.log');
|
||||||
'/tmp/luci-app-daede.' + kind + '.log', kind === 'geoip' ? 'GeoIP' : 'GeoSite');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// === Package updates (dae|daed / luci-app-daede) ===
|
// === Package updates (dae|daed / luci-app-daede) ===
|
||||||
const upgradePkg = function(pkg, btn) {
|
const upgradePkg = function(pkg, btn) {
|
||||||
if (!confirm(_('Upgrade %s now? This may restart the active backend.').format(pkg)))
|
return runJob('update-pkg.sh', pkg, btn, '/tmp/luci-app-daede.pkg-' + pkg + '.log');
|
||||||
return;
|
|
||||||
return runJob('update-pkg.sh', pkg, btn,
|
|
||||||
'/tmp/luci-app-daede.pkg-' + pkg + '.log', pkg);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const refresh = function() {
|
const refresh = function() {
|
||||||
|
|||||||
@@ -10,8 +10,9 @@ fi
|
|||||||
: > "$LOCK"
|
: > "$LOCK"
|
||||||
|
|
||||||
(
|
(
|
||||||
|
# -n: skip if a package op holds the shared apk lock (no need to refresh then)
|
||||||
if command -v apk >/dev/null 2>&1; then
|
if command -v apk >/dev/null 2>&1; then
|
||||||
apk update
|
flock -n /tmp/luci-app-daede.apk.lock apk update
|
||||||
elif command -v opkg >/dev/null 2>&1; then
|
elif command -v opkg >/dev/null 2>&1; then
|
||||||
opkg update
|
opkg update
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -38,15 +38,22 @@ fi
|
|||||||
echo "$(date '+%F %T') begin upgrade: $PKG"
|
echo "$(date '+%F %T') begin upgrade: $PKG"
|
||||||
|
|
||||||
if command -v apk >/dev/null 2>&1; then
|
if command -v apk >/dev/null 2>&1; then
|
||||||
echo "--- apk update ---"
|
# shared apk lock with the bg index refresh (avoid "Unable to lock database")
|
||||||
apk update 2>&1
|
(
|
||||||
echo "--- apk add $PKG ---"
|
flock 9
|
||||||
# Target only $PKG (not `apk upgrade`, which re-solves the whole world).
|
apk update 2>&1
|
||||||
apk add "$PKG" 2>&1
|
# pin exact latest version + --force-broken-world so unrelated broken
|
||||||
# Don't trust apk's exit code: apk-tools 3 returns non-zero whenever ANY
|
# packages can't block this upgrade (cf. clashoo component_update)
|
||||||
# unrelated installed package has an unavailable .apk in the configured
|
ver=$(apk list "$PKG" 2>/dev/null | awk -v p="$PKG" '$1 ~ "^" p "-[0-9]" { v=$1; sub("^" p "-", "", v); print v }' | sort -V | tail -1)
|
||||||
# feeds, even when $PKG itself upgraded fine. Judge success by state —
|
if [ -n "$ver" ]; then
|
||||||
# $PKG must be installed and have no pending upgrade left.
|
echo "--- apk add $PKG=$ver ---"
|
||||||
|
apk add "$PKG=$ver" --force-broken-world 2>&1
|
||||||
|
else
|
||||||
|
echo "--- apk add $PKG ---"
|
||||||
|
apk add "$PKG" --force-broken-world 2>&1
|
||||||
|
fi
|
||||||
|
) 9>/tmp/luci-app-daede.apk.lock
|
||||||
|
# apk's exit code is unreliable (broken-world noise); judge by state instead
|
||||||
if ! apk list --installed 2>/dev/null | grep -q "^${PKG}-"; then
|
if ! apk list --installed 2>/dev/null | grep -q "^${PKG}-"; then
|
||||||
echo "result: $PKG is not installed"
|
echo "result: $PKG is not installed"
|
||||||
rc=1
|
rc=1
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l3 8l4 -16l3 8h4" /></svg>
|
||||||
|
After Width: | Height: | Size: 224 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 10a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" /><path d="M6 4v4" /><path d="M6 12v8" /><path d="M10 16a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" /><path d="M12 4v10" /><path d="M12 18v2" /><path d="M16 7a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" /><path d="M18 4v1" /><path d="M18 9v11" /></svg>
|
||||||
|
After Width: | Height: | Size: 452 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 5a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4" /><path d="M4 15a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4" /><path d="M14 15a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4" /><path d="M14 7l6 0" /><path d="M17 4l0 6" /></svg>
|
||||||
|
After Width: | Height: | Size: 502 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h6v6h-6l0 -6" /><path d="M14 4h6v6h-6l0 -6" /><path d="M4 14h6v6h-6l0 -6" /><path d="M14 17a3 3 0 1 0 6 0a3 3 0 1 0 -6 0" /></svg>
|
||||||
|
After Width: | Height: | Size: 325 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 6a1 1 0 0 1 1 -1h12a1 1 0 0 1 1 1v12a1 1 0 0 1 -1 1h-12a1 1 0 0 1 -1 -1l0 -12" /><path d="M9 9h6v6h-6l0 -6" /><path d="M3 10h2" /><path d="M3 14h2" /><path d="M10 3v2" /><path d="M14 3v2" /><path d="M21 10h-2" /><path d="M21 14h-2" /><path d="M14 21v-2" /><path d="M10 21v-2" /></svg>
|
||||||
|
After Width: | Height: | Size: 478 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3l8 4.5l0 9l-8 4.5l-8 -4.5l0 -9l8 -4.5" /><path d="M12 12l8 -4.5" /><path d="M12 12l0 9" /><path d="M12 12l-8 -4.5" /><path d="M16 5.25l-8 4.5" /></svg>
|
||||||
|
After Width: | Height: | Size: 347 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 15a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v4a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2l0 -4" /><path d="M17 17l0 .01" /><path d="M13 17l0 .01" /><path d="M15 13l0 -2" /><path d="M11.75 8.75a4 4 0 0 1 6.5 0" /><path d="M8.5 6.5a8 8 0 0 1 13 0" /></svg>
|
||||||
|
After Width: | Height: | Size: 430 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3v-2" /><path d="M3 15a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3l0 -2" /><path d="M7 8l0 .01" /><path d="M7 16l0 .01" /><path d="M11 8h6" /><path d="M11 16h6" /></svg>
|
||||||
|
After Width: | Height: | Size: 457 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065" /><path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" /></svg>
|
||||||
|
After Width: | Height: | Size: 770 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6.5 7.5a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" /><path d="M3 6v5.172a2 2 0 0 0 .586 1.414l7.71 7.71a2.41 2.41 0 0 0 3.408 0l5.592 -5.592a2.41 2.41 0 0 0 0 -3.408l-7.71 -7.71a2 2 0 0 0 -1.414 -.586h-5.172a3 3 0 0 0 -3 3" /></svg>
|
||||||
|
After Width: | Height: | Size: 411 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0" /><path d="M3.6 9h16.8" /><path d="M3.6 15h16.8" /><path d="M11.5 3a17 17 0 0 0 0 18" /><path d="M12.5 3a17 17 0 0 1 0 18" /></svg>
|
||||||
|
After Width: | Height: | Size: 360 B |
@@ -1,5 +1,5 @@
|
|||||||
header {
|
header {
|
||||||
@apply bg-bg sticky top-0 z-60 mb-2;
|
@apply bg-bg sticky top-0 z-40 mb-2;
|
||||||
|
|
||||||
& .header-content {
|
& .header-content {
|
||||||
@apply relative flex h-14 items-center justify-between px-6 py-3 max-md:px-4 max-md:py-2;
|
@apply relative flex h-14 items-center justify-between px-6 py-3 max-md:px-4 max-md:py-2;
|
||||||
@@ -16,84 +16,130 @@ header {
|
|||||||
/* Category panels live inside the container, not the nav items: the
|
/* Category panels live inside the container, not the nav items: the
|
||||||
transformed #topmenu would otherwise become the containing block of
|
transformed #topmenu would otherwise become the containing block of
|
||||||
a position:fixed panel and shrink the canvas to the menu's width.
|
a position:fixed panel and shrink the canvas to the menu's width.
|
||||||
Fixed coordinates shared by every category, so switching panels
|
Each panel is the same centered three-column grid (max-width fixed),
|
||||||
never shifts anything: link columns start at 50% - 13rem (just
|
so switching categories is a pure cross-fade with no width shift.
|
||||||
under the centered nav triggers), the anchor column sits at a
|
The entering panel floats up 6px — transform + opacity only. */
|
||||||
fixed slot left of them. The entering panel floats up 6px —
|
/* The server-rendered board is only a template that menu-aurora.js
|
||||||
transform + opacity only. */
|
clones into each panel's right column — the original stays hidden. */
|
||||||
|
& > .desktop-menu-board {
|
||||||
|
@apply hidden;
|
||||||
|
}
|
||||||
|
|
||||||
& .desktop-nav {
|
& .desktop-nav {
|
||||||
@apply pointer-events-none absolute inset-x-0 top-14 min-h-60 translate-y-1.5 pt-7 pb-8 pl-[calc(50%-13rem)] opacity-0 transition-[opacity,transform] duration-[250ms] ease-out;
|
/* Centered three-column canvas: anchor / links / device board.
|
||||||
|
Fixed max-width keeps every category the same width, so switching
|
||||||
|
is a pure cross-fade. Below lg the side tracks drop and only the
|
||||||
|
links column remains (tablet → just the submenu). The panel scrolls
|
||||||
|
internally when its content exceeds the viewport below the header. */
|
||||||
|
@apply pointer-events-none absolute inset-x-0 top-14 mx-auto grid max-h-[calc(100dvh-3.5rem)] max-w-[72rem] translate-y-1.5 grid-cols-[12rem_minmax(0,1fr)_13rem] gap-x-8 overflow-y-auto overscroll-contain px-10 pt-7 pb-8 opacity-0 transition-[opacity,transform] duration-[250ms] ease-out max-lg:max-w-[44rem] max-lg:grid-cols-1 max-lg:px-8;
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
@apply pointer-events-auto translate-y-0 opacity-100;
|
@apply pointer-events-auto translate-y-0 opacity-100;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .desktop-nav-anchor {
|
& .desktop-nav-anchor {
|
||||||
@apply absolute top-7 left-[calc(50%-30rem)] w-56 max-lg:hidden;
|
@apply self-start max-lg:hidden;
|
||||||
|
|
||||||
& .desktop-nav-title {
|
& .desktop-nav-title {
|
||||||
@apply text-text text-2xl font-semibold tracking-tight;
|
@apply text-text flex items-center gap-2.5 text-2xl font-semibold tracking-tight;
|
||||||
|
|
||||||
|
/* First-level icon: mask + currentColor so it follows the theme.
|
||||||
|
--menu-icon is set per node name below; unmapped → default. */
|
||||||
|
&::before {
|
||||||
|
@apply size-6 shrink-0 bg-current content-[''] [mask:var(--menu-icon,url('@assets/icons/category.svg'))_center/contain_no-repeat];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* name → icon map (the only maintenance point). Keyed on the LuCI
|
||||||
|
node name, not the translated title. Add new first-level
|
||||||
|
sections here; anything unmapped keeps the default icon. */
|
||||||
|
& .desktop-nav-title[data-section="status"] {
|
||||||
|
@apply [--menu-icon:url('@assets/icons/activity.svg')];
|
||||||
|
}
|
||||||
|
& .desktop-nav-title[data-section="system"] {
|
||||||
|
@apply [--menu-icon:url('@assets/icons/settings.svg')];
|
||||||
|
}
|
||||||
|
& .desktop-nav-title[data-section="services"] {
|
||||||
|
@apply [--menu-icon:url('@assets/icons/apps.svg')];
|
||||||
|
}
|
||||||
|
& .desktop-nav-title[data-section="nas"] {
|
||||||
|
@apply [--menu-icon:url('@assets/icons/server-2.svg')];
|
||||||
|
}
|
||||||
|
& .desktop-nav-title[data-section="control"] {
|
||||||
|
@apply [--menu-icon:url('@assets/icons/adjustments.svg')];
|
||||||
|
}
|
||||||
|
& .desktop-nav-title[data-section="network"] {
|
||||||
|
@apply [--menu-icon:url('@assets/icons/world.svg')];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& .desktop-nav-list {
|
& .desktop-nav-list {
|
||||||
/* Vertical fill: columns of equal height, no orphan rows. Row
|
/* Vertical fill, content-width columns. Row count per submenu via
|
||||||
count is set per submenu via --menu-rows in menu-aurora.js.
|
--menu-rows (menu-aurora.js); more items grow rows, not width,
|
||||||
w-max is load-bearing: without it the block-level list fills
|
so the list stays inside the middle track. */
|
||||||
the viewport and justify-content:normal stretches the auto
|
@apply grid grid-flow-col grid-rows-[repeat(var(--menu-rows,6),auto)] content-start justify-start gap-x-8 gap-y-1;
|
||||||
column tracks across all of it. */
|
|
||||||
@apply grid w-max grid-flow-col grid-rows-[repeat(var(--menu-rows,6),auto)] content-start gap-x-8 gap-y-1;
|
|
||||||
|
|
||||||
& > li {
|
& > li {
|
||||||
@apply m-0 list-none;
|
@apply m-0 list-none;
|
||||||
|
|
||||||
& > a {
|
& > a {
|
||||||
@apply text-text block w-fit py-2.5 text-sm whitespace-nowrap no-underline hover:underline hover:decoration-2 hover:underline-offset-4;
|
@apply text-text hover:bg-hover-faint block w-fit rounded-lg px-3 py-2 text-sm whitespace-nowrap no-underline transition-colors duration-150;
|
||||||
|
|
||||||
|
&.is-active-page {
|
||||||
|
@apply bg-brand-subtle text-brand font-medium;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Constant part of the canvas, Apple-flyout style: the device
|
/* Right column: device summary, cloned per panel. self-start so it
|
||||||
summary lives once at container level, pinned just below the
|
sits at the top regardless of how tall the links column grows. */
|
||||||
fixed category-title slot (header 3.5rem + panel pt 1.75rem +
|
& .desktop-menu-board {
|
||||||
title line 2rem + 1.25rem gap = top-34). Its position never
|
@apply border-hairline flex flex-col gap-2 self-start border-l pl-7 max-lg:hidden;
|
||||||
depends on an individual panel's height, and switching categories
|
|
||||||
never re-fades it. */
|
|
||||||
& .desktop-menu-board {
|
|
||||||
@apply absolute top-34 left-[calc(50%-30rem)] flex w-56 flex-col gap-2 max-lg:hidden;
|
|
||||||
|
|
||||||
& .board-line {
|
& .board-label {
|
||||||
@apply text-text-muted flex max-w-full items-center gap-2.5 text-xs;
|
@apply text-text-subtle mb-0.5 text-[11px] font-medium tracking-wide uppercase;
|
||||||
|
|
||||||
&::before {
|
|
||||||
@apply size-4 shrink-0 bg-current content-[''];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
& .board-text {
|
& .board-line {
|
||||||
@apply min-w-0 truncate;
|
/* items-start keeps the icon aligned to the FIRST text line when a
|
||||||
|
long value wraps. Icon height (size-4) == text leading (leading-4)
|
||||||
|
so a single line still reads as vertically centered. */
|
||||||
|
@apply text-text-muted flex max-w-full items-start gap-2.5 text-xs;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
@apply size-4 shrink-0 bg-current content-[''];
|
||||||
|
}
|
||||||
|
|
||||||
|
& .board-text {
|
||||||
|
@apply min-w-0 leading-4 [overflow-wrap:anywhere];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
& .board-line-host::before {
|
& .board-line-host::before {
|
||||||
@apply [mask:url('@assets/icons/server.svg')_center/contain_no-repeat];
|
@apply [mask:url('@assets/icons/router.svg')_center/contain_no-repeat];
|
||||||
}
|
}
|
||||||
|
|
||||||
& .board-line-model::before {
|
& .board-line-model::before {
|
||||||
@apply [mask:url('@assets/icons/cpu-chip.svg')_center/contain_no-repeat];
|
@apply [mask:url('@assets/icons/cpu.svg')_center/contain_no-repeat];
|
||||||
}
|
}
|
||||||
|
|
||||||
& .board-line-firmware::before {
|
& .board-line-firmware::before {
|
||||||
@apply [mask:url('@assets/icons/cube.svg')_center/contain_no-repeat];
|
@apply [mask:url('@assets/icons/package.svg')_center/contain_no-repeat];
|
||||||
}
|
}
|
||||||
|
|
||||||
& .board-line-kernel::before {
|
& .board-line-kernel::before {
|
||||||
@apply [mask:url('@assets/icons/cog.svg')_center/contain_no-repeat];
|
@apply [mask:url('@assets/icons/tag.svg')_center/contain_no-repeat];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-nav-type="mega-menu"] &:has(.desktop-menu-container.active) {
|
||||||
|
@apply z-70;
|
||||||
|
}
|
||||||
|
|
||||||
.brand {
|
.brand {
|
||||||
@apply hover:text-brand text-text inline-block shrink-0 text-xl font-semibold tracking-tight no-underline transition-[color,transform] duration-150 hover:-translate-y-0.5 max-md:flex-1 max-md:text-lg;
|
@apply hover:text-brand text-text inline-block shrink-0 text-xl font-semibold tracking-tight no-underline transition-[color,transform] duration-150 hover:-translate-y-0.5 max-md:flex-1 max-md:text-lg;
|
||||||
}
|
}
|
||||||
@@ -105,16 +151,12 @@ header {
|
|||||||
@apply relative;
|
@apply relative;
|
||||||
|
|
||||||
.menu {
|
.menu {
|
||||||
@apply text-text block rounded-xl px-3.5 py-1.5 font-medium no-underline transition-colors duration-150;
|
@apply text-text hover:bg-hover-faint block rounded-xl px-3.5 py-1.5 font-medium no-underline transition-colors duration-150;
|
||||||
|
|
||||||
|
/* Unified pill for both dropdown modes — the open/active category is a
|
||||||
|
filled brand pill, matching the submenu links and the sidebar. */
|
||||||
&.menu-active {
|
&.menu-active {
|
||||||
@apply text-text;
|
@apply bg-brand-subtle text-brand;
|
||||||
[data-nav-type="mega-menu"] & {
|
|
||||||
@apply underline decoration-2 underline-offset-4;
|
|
||||||
}
|
|
||||||
[data-nav-type="boxed-dropdown"] & {
|
|
||||||
@apply bg-brand-subtle text-brand;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +182,13 @@ header {
|
|||||||
@apply text-text block whitespace-nowrap no-underline;
|
@apply text-text block whitespace-nowrap no-underline;
|
||||||
|
|
||||||
[data-nav-type="boxed-dropdown"] & {
|
[data-nav-type="boxed-dropdown"] & {
|
||||||
@apply hover:bg-hover-faint mx-2 rounded-xl px-4 py-2;
|
@apply hover:bg-hover-faint mx-2 rounded-xl px-4 py-2 transition-colors duration-150;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Same active pill as the mega submenu and the top-level
|
||||||
|
trigger — one unified vocabulary across both dropdown modes. */
|
||||||
|
&.is-active-page {
|
||||||
|
@apply bg-brand-subtle text-brand font-medium;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -310,7 +358,7 @@ body[data-nav-type="sidebar"] {
|
|||||||
@apply max-w-max-width mx-auto min-h-[calc(100vh-4rem)] w-23/24 px-4 max-md:w-full max-md:px-3;
|
@apply max-w-max-width mx-auto min-h-[calc(100vh-4rem)] w-23/24 px-4 max-md:w-full max-md:px-3;
|
||||||
|
|
||||||
#view {
|
#view {
|
||||||
@apply animate-in fade-in-0 slide-in-from-top-2 fill-mode-both mx-0 w-full bg-transparent p-0 shadow-none empty:hidden md:p-0;
|
@apply mx-0 w-full bg-transparent p-0 shadow-none empty:hidden md:p-0;
|
||||||
|
|
||||||
.cbi-title-section {
|
.cbi-title-section {
|
||||||
@apply mb-6 leading-relaxed max-md:mx-2 max-md:mb-3;
|
@apply mb-6 leading-relaxed max-md:mx-2 max-md:mb-3;
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* Reduced-transparency fallback.
|
||||||
|
*
|
||||||
|
* When the user asks for less transparency, drop the most expensive layer —
|
||||||
|
* backdrop-filter blur — everywhere, and turn the one surface that relies on
|
||||||
|
* "translucent + blur" to stay readable (the mega-menu backdrop) opaque, so
|
||||||
|
* removing the blur doesn't let the page content bleed through it.
|
||||||
|
*
|
||||||
|
* surface-overlay / surface are already opaque, so dropping their blur is
|
||||||
|
* harmless; scrim keeps its translucency on purpose (it's a dimming layer).
|
||||||
|
* --mega-menu-bg points at surface-overlay via var() so it tracks light/dark
|
||||||
|
* automatically (resolved at the point of use, not here).
|
||||||
|
*/
|
||||||
|
@media (prefers-reduced-transparency: reduce) {
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
/* standard property only — lightningcss adds the -webkit- prefix per browserslist */
|
||||||
|
@apply [backdrop-filter:none]!;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--mega-menu-bg: var(--surface-overlay);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.dropdown {
|
&.dropdown {
|
||||||
@apply border-hairline bg-surface-overlay absolute left-0 z-60 w-fit min-w-full overflow-y-auto rounded-lg border shadow-xl backdrop-blur-md backdrop-saturate-150;
|
@apply border-hairline bg-surface-overlay absolute left-0 z-50 w-fit min-w-full overflow-y-auto rounded-lg border shadow-xl backdrop-blur-md backdrop-saturate-150;
|
||||||
|
|
||||||
& > li {
|
& > li {
|
||||||
@apply text-text-muted hover:bg-brand-subtle min-h-9 w-full cursor-pointer px-3 py-1.5 font-medium;
|
@apply text-text-muted hover:bg-brand-subtle min-h-9 w-full cursor-pointer px-3 py-1.5 font-medium;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.alert-message {
|
.alert-message {
|
||||||
@apply bg-surface-sunken text-text border-hairline sticky top-14 z-40 mb-4 rounded-4xl border p-6 max-md:mx-0 max-md:mb-3 max-md:rounded-3xl max-md:p-4;
|
@apply bg-surface-sunken text-text border-hairline sticky top-14 z-30 mb-4 rounded-4xl border p-6 max-md:mx-0 max-md:mb-3 max-md:rounded-3xl max-md:p-4;
|
||||||
|
|
||||||
&.modal {
|
&.modal {
|
||||||
@apply static top-auto;
|
@apply static top-auto;
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ body.mobile-navigation-open > header {
|
|||||||
|
|
||||||
[data-nav-type="mega-menu"] {
|
[data-nav-type="mega-menu"] {
|
||||||
& .desktop-menu-overlay {
|
& .desktop-menu-overlay {
|
||||||
@apply bg-scrim pointer-events-none fixed inset-0 z-50 opacity-0 transition-opacity duration-[250ms] max-md:hidden;
|
@apply bg-scrim pointer-events-none fixed inset-0 z-60 opacity-0 transition-opacity duration-[250ms] max-md:hidden;
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
@apply pointer-events-auto opacity-100 backdrop-blur-lg backdrop-saturate-150;
|
@apply pointer-events-auto opacity-100 backdrop-blur-lg backdrop-saturate-150;
|
||||||
|
|||||||
@@ -42,3 +42,4 @@
|
|||||||
@import "./_utilities.css";
|
@import "./_utilities.css";
|
||||||
@import "./_patches.css";
|
@import "./_patches.css";
|
||||||
@import "./_reduced-motion.css";
|
@import "./_reduced-motion.css";
|
||||||
|
@import "./_reduced-transparency.css";
|
||||||
@@ -255,11 +255,17 @@ return baseclass.extend({
|
|||||||
if (!children.length) return E([]);
|
if (!children.length) return E([]);
|
||||||
|
|
||||||
children.forEach((child) => {
|
children.forEach((child) => {
|
||||||
ul.appendChild(
|
// Mark the current page so it gets the active pill — same vocabulary
|
||||||
E("li", {}, [
|
// as the top-level trigger (.menu-active). tree is the section node,
|
||||||
E("a", { href: L.url(url, child.name) }, [_(child.title)]),
|
// so tree.name is its dispatch segment.
|
||||||
]),
|
const isActive = this.isActivePath(tree.name, child.name);
|
||||||
);
|
const attributes = {
|
||||||
|
class: isActive ? "is-active-page" : "",
|
||||||
|
href: L.url(url, child.name),
|
||||||
|
};
|
||||||
|
if (isActive) attributes["aria-current"] = "page";
|
||||||
|
|
||||||
|
ul.appendChild(E("li", {}, [E("a", attributes, [_(child.title)])]));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,17 +521,32 @@ return baseclass.extend({
|
|||||||
const children = [list];
|
const children = [list];
|
||||||
|
|
||||||
if (document.body?.dataset?.navType === "mega-menu") {
|
if (document.body?.dataset?.navType === "mega-menu") {
|
||||||
// Constant canvas: links fill top-to-bottom; capping at 4 columns
|
// Constant canvas: links fill top-to-bottom. Base column count is 4;
|
||||||
// keeps the canvas height stable until a submenu exceeds 24 items.
|
// more items grow the row count, not the width, so the list stays
|
||||||
|
// inside the three-column canvas middle track.
|
||||||
list.style.setProperty(
|
list.style.setProperty(
|
||||||
"--menu-rows",
|
"--menu-rows",
|
||||||
Math.max(6, Math.ceil(submenu.length / 4)),
|
Math.max(6, Math.ceil(submenu.length / 4)),
|
||||||
);
|
);
|
||||||
|
// data-section keys the first-level icon off the node name (stable,
|
||||||
|
// language-independent) — see _layout.css. Unmapped names fall back
|
||||||
|
// to the default icon via var(--menu-icon, …).
|
||||||
children.unshift(
|
children.unshift(
|
||||||
E("div", { class: "desktop-nav-anchor" }, [
|
E("div", { class: "desktop-nav-anchor" }, [
|
||||||
E("span", { class: "desktop-nav-title" }, [_(child.title)]),
|
E(
|
||||||
|
"span",
|
||||||
|
{ class: "desktop-nav-title", "data-section": child.name },
|
||||||
|
[_(child.title)],
|
||||||
|
),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
// Right column: clone the server-rendered device board into each
|
||||||
|
// panel so the grid can lay it out as the third track. The original
|
||||||
|
// stays hidden as the template (see _layout.css).
|
||||||
|
const board = document.querySelector(
|
||||||
|
".desktop-menu-container > .desktop-menu-board",
|
||||||
|
);
|
||||||
|
if (board) children.push(board.cloneNode(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
nav = E("div", { class: "desktop-nav" }, children);
|
nav = E("div", { class: "desktop-nav" }, children);
|
||||||
@@ -570,7 +591,7 @@ return baseclass.extend({
|
|||||||
let maxPanel = 0;
|
let maxPanel = 0;
|
||||||
header
|
header
|
||||||
.querySelectorAll(".desktop-nav")
|
.querySelectorAll(".desktop-nav")
|
||||||
.forEach((nav) => (maxPanel = Math.max(maxPanel, nav.scrollHeight)));
|
.forEach((nav) => (maxPanel = Math.max(maxPanel, nav.offsetHeight)));
|
||||||
canvasHeight = headerHeight + maxPanel;
|
canvasHeight = headerHeight + maxPanel;
|
||||||
}
|
}
|
||||||
container?.style.setProperty("--mega-menu-height", `${canvasHeight}px`);
|
container?.style.setProperty("--mega-menu-height", `${canvasHeight}px`);
|
||||||
|
|||||||
@@ -385,6 +385,30 @@ test("renders an active group expanded with active page semantics", () => {
|
|||||||
assert.equal(activeLink.getAttribute("aria-current"), "page");
|
assert.equal(activeLink.getAttribute("aria-current"), "page");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("renders the active desktop submenu link with current-page semantics", () => {
|
||||||
|
const menu = loadMenuModule({
|
||||||
|
dispatchpath: ["admin", "network", "wireless"],
|
||||||
|
});
|
||||||
|
const list = menu.renderMainMenu(
|
||||||
|
{
|
||||||
|
name: "network",
|
||||||
|
children: {
|
||||||
|
interfaces: { title: "Interfaces" },
|
||||||
|
wireless: { title: "Wireless" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"admin/network",
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
const [inactiveItem, activeItem] = list.children;
|
||||||
|
const inactiveLink = inactiveItem.children[0];
|
||||||
|
const activeLink = activeItem.children[0];
|
||||||
|
|
||||||
|
assert.equal(inactiveLink.hasAttribute("aria-current"), false);
|
||||||
|
assert.equal(activeLink.getAttribute("class"), "is-active-page");
|
||||||
|
assert.equal(activeLink.getAttribute("aria-current"), "page");
|
||||||
|
});
|
||||||
|
|
||||||
test("renders an inactive group collapsed and inert", () => {
|
test("renders an inactive group collapsed and inert", () => {
|
||||||
const menu = loadMenuModule();
|
const menu = loadMenuModule();
|
||||||
const item = menu.renderNavigationItem(
|
const item = menu.renderNavigationItem(
|
||||||
@@ -506,6 +530,13 @@ test("skips mega-menu initialization when the top menu is missing", () => {
|
|||||||
assert.ok(result instanceof FakeElement);
|
assert.ok(result instanceof FakeElement);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("measures mega-menu canvas from the viewport-bounded panel height", () => {
|
||||||
|
const initMegaMenu = getMethodSource("initMegaMenu");
|
||||||
|
|
||||||
|
assert.match(initMegaMenu, /nav\.offsetHeight/);
|
||||||
|
assert.doesNotMatch(initMegaMenu, /nav\.scrollHeight/);
|
||||||
|
});
|
||||||
|
|
||||||
test("skips boxed-dropdown initialization when the top menu is missing", () => {
|
test("skips boxed-dropdown initialization when the top menu is missing", () => {
|
||||||
const menu = loadMenuModule({
|
const menu = loadMenuModule({
|
||||||
document: createFakeDocument({ navType: "boxed-dropdown" }),
|
document: createFakeDocument({ navType: "boxed-dropdown" }),
|
||||||
|
|||||||
@@ -157,3 +157,22 @@ test("mobile drawer styles only provide mobile navigation density", () => {
|
|||||||
);
|
);
|
||||||
assert.doesNotMatch(drawer, /bg-brand-subtle/);
|
assert.doesNotMatch(drawer, /bg-brand-subtle/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("mega-menu panels scroll within the viewport", () => {
|
||||||
|
const megaMenu = getBlock(layoutStyles, '[data-nav-type="mega-menu"] &');
|
||||||
|
const panel = getBlock(megaMenu, "& .desktop-nav");
|
||||||
|
|
||||||
|
assert.ok(panel.includes("max-h-[calc(100dvh-3.5rem)]"));
|
||||||
|
assertIncludesUtilities(panel, ["overflow-y-auto", "overscroll-contain"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("mega-menu category masks use Tailwind arbitrary utilities", () => {
|
||||||
|
const title = getBlock(layoutStyles, "& .desktop-nav-title");
|
||||||
|
const icon = getBlock(title, "&::before");
|
||||||
|
|
||||||
|
assert.match(
|
||||||
|
icon,
|
||||||
|
/@apply[^;]*\[mask:var\(--menu-icon,url\(["']@assets\/icons\/category\.svg["']\)\)_center\/contain_no-repeat\]/,
|
||||||
|
);
|
||||||
|
assert.doesNotMatch(layoutStyles, /^\s*mask\s*:/m);
|
||||||
|
});
|
||||||
@@ -70,6 +70,47 @@ test("maincontent cards use a hairline border, not heavy shadow", () => {
|
|||||||
assert.ok(!rule.includes("shadow-lg"), `still shadow-lg: ${rule}`);
|
assert.ok(!rule.includes("shadow-lg"), `still shadow-lg: ${rule}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("main view does not create an animation stacking context", () => {
|
||||||
|
const layout = read("../src/media/_layout.css");
|
||||||
|
const rule = layout.match(/#view\s*\{\s*@apply\s+([^;]+);/)?.[1] ?? "";
|
||||||
|
|
||||||
|
for (const utility of [
|
||||||
|
"animate-in",
|
||||||
|
"fade-in-0",
|
||||||
|
"slide-in-from-top-2",
|
||||||
|
"fill-mode-backwards",
|
||||||
|
"fill-mode-both",
|
||||||
|
]) {
|
||||||
|
assert.ok(!rule.includes(utility), `view still uses ${utility}: ${rule}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("content dropdowns stay above the closed header and below the open mega-menu", () => {
|
||||||
|
const layer = (value) => ["z", value].join("-");
|
||||||
|
const layout = read("../src/media/_layout.css");
|
||||||
|
const dropdown = read("../src/media/components/_dropdown.css");
|
||||||
|
const message = read("../src/media/components/_message.css");
|
||||||
|
const overlay = read("../src/media/components/_overlay.css");
|
||||||
|
const headerRule = layout.match(/^header\s*\{\s*@apply\s+([^;]+);/m)?.[1] ?? "";
|
||||||
|
const activeHeaderRule =
|
||||||
|
layout.match(
|
||||||
|
/\[data-nav-type="mega-menu"\] &:has\(\.desktop-menu-container\.active\)\s*\{\s*@apply\s+([^;]+);/,
|
||||||
|
)?.[1] ?? "";
|
||||||
|
const dropdownRule = dropdown.match(/&\.dropdown\s*\{\s*@apply\s+([^;]+);/)?.[1] ?? "";
|
||||||
|
const messageRule = message.match(/\.alert-message\s*\{\s*@apply\s+([^;]+);/)?.[1] ?? "";
|
||||||
|
const overlayRule =
|
||||||
|
overlay.match(/& \.desktop-menu-overlay\s*\{\s*@apply\s+([^;]+);/)?.[1] ?? "";
|
||||||
|
|
||||||
|
assert.ok(messageRule.includes(layer(30)), `message layer changed: ${messageRule}`);
|
||||||
|
assert.ok(headerRule.includes(layer(40)), `closed header layer changed: ${headerRule}`);
|
||||||
|
assert.ok(dropdownRule.includes(layer(50)), `dropdown layer changed: ${dropdownRule}`);
|
||||||
|
assert.ok(overlayRule.includes(layer(60)), `menu overlay layer changed: ${overlayRule}`);
|
||||||
|
assert.ok(
|
||||||
|
activeHeaderRule.includes(layer(70)),
|
||||||
|
`open mega-menu layer changed: ${activeHeaderRule}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test("tables get a hairline frame + sunken header, body stays unclipped", () => {
|
test("tables get a hairline frame + sunken header, body stays unclipped", () => {
|
||||||
const t = read("../src/media/components/_table.css");
|
const t = read("../src/media/components/_table.css");
|
||||||
const root = t.match(/table\.table,\s*\.table\s*\{\s*@apply\s+([^;]+);/)?.[1] ?? "";
|
const root = t.match(/table\.table,\s*\.table\s*\{\s*@apply\s+([^;]+);/)?.[1] ?? "";
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk
|
|||||||
LUCI_TITLE:=Aurora Theme (A modern browser theme built with Vite and Tailwind CSS)
|
LUCI_TITLE:=Aurora Theme (A modern browser theme built with Vite and Tailwind CSS)
|
||||||
LUCI_DEPENDS:=+luci-base
|
LUCI_DEPENDS:=+luci-base
|
||||||
|
|
||||||
PKG_VERSION:=0.12.10
|
PKG_VERSION:=0.12.11
|
||||||
PKG_RELEASE:=27
|
PKG_RELEASE:=28
|
||||||
PKG_LICENSE:=Apache-2.0
|
PKG_LICENSE:=Apache-2.0
|
||||||
|
|
||||||
LUCI_MINIFY_CSS:=
|
LUCI_MINIFY_CSS:=
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
|
/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
|
||||||
@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-content:"";--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-tracking:initial}}:root,:host{--font-sans:var(--font-sans);--font-mono:var(--font-mono);--spacing:var(--spacing);--container-md:28rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height:calc(1.5/1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--tracking-widest:.1em;--radius-sm:calc(var(--radius-base)*.25);--radius-md:calc(var(--radius-base)*.75);--radius-lg:var(--radius-base);--radius-xl:calc(var(--radius-base)*1.5);--radius-2xl:calc(var(--radius-base)*2);--radius-3xl:calc(var(--radius-base)*3);--radius-4xl:calc(var(--radius-base)*4);--shadow-sm:var(--app-shadow-sm);--shadow-md:var(--app-shadow-md);--shadow-lg:var(--app-shadow-md);--shadow-xl:var(--app-shadow-lg);--shadow-2xl:var(--app-shadow-lg);--animate-spin:spin 1s linear infinite;--blur-lg:16px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--radius:calc(var(--radius-base)*.5);--container-max-width:var(--container-max-width)}*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:wheLine truncated
|
@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-content:"";--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-tracking:initial}}:root,:host{--font-sans:var(--font-sans);--font-mono:var(--font-mono);--spacing:var(--spacing);--container-md:28rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height:calc(1.5/1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--tracking-widest:.1em;--radius-sm:calc(var(--radius-base)*.25);--radius-md:calc(var(--radius-base)*.75);--radius-lg:var(--radius-base);--radius-xl:calc(var(--radius-base)*1.5);--radius-2xl:calc(var(--radius-base)*2);--radius-3xl:calc(var(--radius-base)*3);--radius-4xl:calc(var(--radius-base)*4);--shadow-sm:var(--app-shadow-sm);--shadow-md:var(--app-shadow-md);--shadow-lg:var(--app-shadow-md);--shadow-xl:var(--app-shadow-lg);--shadow-2xl:var(--app-shadow-lg);--animate-spin:spin 1s linear infinite;--blur-lg:16px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--radius:calc(var(--radius-base)*.5);--container-max-width:var(--container-max-width)}*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:wheLine truncated
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
|
/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
|
||||||
@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-content:"";--tw-animation-delay:0s;--tw-animation-direction:normal;--tw-animation-duration:initial;--tw-animation-fill-mode:none;--tw-animation-iteration-count:1;--tw-enter-blur:0;--tw-enter-opacity:1;--tw-enter-rotate:0;--tw-enter-scale:1;--tw-enter-translate-x:0;--tw-enter-translate-y:0;--tw-exit-blur:0;--tw-exit-opacity:1;--tw-exit-rotate:0;--tw-exit-scale:1;--tw-exit-translate-x:0;--tw-exit-translate-y:0;--tw-leading:initial;--tw-tracking:initial;--tw-ease:initial;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-space-y-reverse:0;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-border-spacing-x:0;--tw-border-spacing-y:0}}:root,:host{--font-sans:var(--font-sans);--font-mono:var(--font-mono);--spacing:var(--spacing);--container-xs:20rem;--container-5xl:64rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height:calc(1.5/1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25/1.875);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wide:.025em;--tracking-wider:.05em;--leading-tight:1.25;--leading-snug:1.375;--leading-normal:1.5;--leading-relaxed:1.625;--radius-sm:calc(var(--radius-base)*.25);--radius-md:calc(var(--radius-base)*.75);--radius-lg:var(--radius-base);--radius-xl:calc(var(--radius-base)*1.5);--radius-2xl:calc(var(--radius-base)*2);--radius-3xl:calc(var(--radius-base)*3);--radius-4xl:calc(var(--radius-base)*4);--shadow-sm:var(--app-shadow-sm);--shadow-md:var(--app-shadow-md);--shadow-lg:var(--app-shadow-md);--shadow-xl:var(--app-shadow-lg);--shadow-2xl:var(--app-shadow-lg);--ease-out:cubic-bezier(0,0,.2,1);--ease-in-out:cubic-bezier(.4,0,.2,1);--animate-spin:spin 1s linear infinite;--blur-md:12px;--blur-lg:16px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--radius:calc(var(--radius-base)*.5);--container-max-width:var(--container-max-width)}*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feLine truncated
|
@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-content:"";--tw-animation-delay:0s;--tw-animation-direction:normal;--tw-animation-duration:initial;--tw-animation-fill-mode:none;--tw-animation-iteration-count:1;--tw-enter-blur:0;--tw-enter-opacity:1;--tw-enter-rotate:0;--tw-enter-scale:1;--tw-enter-translate-x:0;--tw-enter-translate-y:0;--tw-exit-blur:0;--tw-exit-opacity:1;--tw-exit-rotate:0;--tw-exit-scale:1;--tw-exit-translate-x:0;--tw-exit-translate-y:0;--tw-leading:initial;--tw-tracking:initial;--tw-ease:initial;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-space-y-reverse:0;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-border-spacing-x:0;--tw-border-spacing-y:0}}:root,:host{--font-sans:var(--font-sans);--font-mono:var(--font-mono);--spacing:var(--spacing);--container-xs:20rem;--container-5xl:64rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height:calc(1.5/1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25/1.875);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wide:.025em;--tracking-wider:.05em;--leading-tight:1.25;--leading-snug:1.375;--leading-normal:1.5;--leading-relaxed:1.625;--radius-sm:calc(var(--radius-base)*.25);--radius-md:calc(var(--radius-base)*.75);--radius-lg:var(--radius-base);--radius-xl:calc(var(--radius-base)*1.5);--radius-2xl:calc(var(--radius-base)*2);--radius-3xl:calc(var(--radius-base)*3);--radius-4xl:calc(var(--radius-base)*4);--shadow-sm:var(--app-shadow-sm);--shadow-md:var(--app-shadow-md);--shadow-lg:var(--app-shadow-md);--shadow-xl:var(--app-shadow-lg);--shadow-2xl:var(--app-shadow-lg);--ease-out:cubic-bezier(0,0,.2,1);--ease-in-out:cubic-bezier(.4,0,.2,1);--animate-spin:spin 1s linear infinite;--blur-md:12px;--blur-lg:16px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--radius:calc(var(--radius-base)*.5);--container-max-width:var(--container-max-width)}*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feLine truncated
|
||||||
@@ -1 +1 @@
|
|||||||
"use strict";"require baseclass";"require ui";return baseclass.extend({__init__(){ui.menu.load().then(tree=>this.render(tree));this.initNavigationControls();this.initUciIndicator()},initUciIndicator(){const original=ui.changes?.setIndicator;if(!original)return;ui.changes.setIndicator=function(n){original.call(this,n);document.querySelector('[data-indicator="uci-changes"]')?.setAttribute("data-count",n||0)}},initNavigationControls(){const overlay=document.querySelector("#mobile-menu-overlay");const navigationToggle=document.querySelector("#navigation-toggle");if(!navigationToggle||!overlay)return;const mobileList=overlay.querySelector("#mobile-nav-list");const desktop=window.matchMedia("(min-width: 768px)");const SIDEBAR_COLLAPSED_KEY="aurora.sidebarCollapsed";const isDesktopSidebar=()=>desktop.matches&&document.body.dataset.navType==="sidebar";const updateToggleState=expanded=>{const desktopSidebar=isDesktopSidebar();navigationToggle.classList.toggle("is-expanded",expanded&&!desktop.matches);navigationToggle.setAttribute("aria-expanded",expanded?"true":"false");navigationToggle.setAttribute("aria-controls",desktopSidebar?"sidebar-panel":"mobile-menu-overlay");const label=expanded&&!desktopSidebar?_("Close"):_("Navigation");navigationToggle.setAttribute("title",label);navigationToggle.setAttribute("aria-label",label)};const closeMobileNavigation=()=>{overlay.classList.remove("mobile-menu-open");document.body.classList.remove("mobile-navigation-open");document.body.style.overflow="";this.resetNavigationGroups(mobileList)};const getNavigationExpanded=()=>{if(isDesktopSidebar()){return!document.body.classList.contains("sidebar-collapsed")}return!desktop.matches&&overlay.classList.contains("mobile-menu-open")};const setNavigationExpanded=expanded=>{if(isDesktopSidebar()){closeMobileNavigation();const collapsed=!expanded;document.body.classList.toggle("sidebar-collapsed",collapsed);localStorage.setItem(SIDEBAR_COLLAPSED_KEY,collapsed);updateToggleState(expanded);return}if(desktop.matches){closeMobileNavigation();updateToggleState(false);return}overlay.classList.toggle("mobile-menu-open",expanded);document.body.classList.toggle("mobile-navigation-open",expanded);document.body.style.overflow=expanded?"hidden":"";if(expanded)this.expandActiveNavigationGroup(mobileList);else this.resetNavigationGroups(mobileList);updateToggleState(expanded)};const toggleNavigation=()=>setNavigationExpanded(!getNavigationExpanded());const syncNavigationState=()=>{closeMobileNavigation();if(isDesktopSidebar()){const collapsed=localStorage.getItem(SIDEBAR_COLLAPSED_KEY)==="true";document.body.classList.toggle("sidebar-collapsed",collapsed);updateToggleState(!collapsed);return}updateToggleState(false)};navigationToggle.addEventListener("click",e=>{e.stopPropagation();toggleNavigation()});overlay.addEventListener("click",e=>{if(e.target===overlay)setNavigationExpanded(false)});document.addEventListener("keydown",e=>{if(e.key==="Escape"&&overlay.classList.contains("mobile-menu-open")){setNavigationExpanded(false)}});desktop.addEventListener("change",syncNavigationState);syncNavigationState();document.addEventListener("click",e=>{const destination=e.target?.closest?.(".navigation-direct, .navigation-sublink, .mobile-nav-logout");if(destination&&overlay.contains(destination)){setNavigationExpanded(false)}})},renderMobileMenu(items){const list=document.querySelector("#mobile-nav-list");const footerAction=document.querySelector("#mobile-nav-footer-action");if(list)list.innerHTML="";if(footerAction)footerAction.innerHTML="";if(!list)return;items.forEach(item=>{if(item.isLogout){if(footerAction){footerAction.appendChild(E("a",{class:"mobile-nav-logout",href:item.href},[item.title]))}return}list.appendChild(this.renderNavigationItem(item,"mobile"))});this.bindNavigationAccordion(list)},render(tree){this.renderModeMenu(tree);if(L.env.dispatchpath.length>=3){let node=tree;let url="";for(let i=0;i<3&&node;i++){const segment=L.env.dispatchpath[i];node=node.children?.[segment];url+=(url?"/":"")+segment}if(node)this.renderTabMenu(node,url)}},renderTabMenu(tree,url,level=0){const container=document.querySelector("#tabmenu");const ul=E("ul",{class:"tabs"});const children=ui.menu.getChildren(tree);let activeNode=null;children.forEach(child=>{const isActive=L.env.dispatchpath[3+level]===child.name;ul.appendChild(E("li",{class:`tabmenu-item-${child.name}${isActive?" active":""}`},[E("a",{href:L.url(url,child.name)},[_(child.title)])]));if(isActive)activeNode=child});if(!ul.children.length)return E([]);container.appendChild(ul);container.style.display="";if(activeNode){this.renderTabMenu(activeNode,`${url}/${activeNode.name}`,level+1)}return ul},renderMainMenu(tree,url,level=0,navigationItems=null){const ul=level?E("ul",{class:"desktop-nav-list"}):document.querySelector("#topmenu");const children=ui.menu.getChildren(tree);if(level>1)return E([]);if(level===0){const navType=document.body?.dataset?.navType||"mega-menu";if(navType==="sidebar"){this.renderSidebLine truncated
|
"use strict";"require baseclass";"require ui";return baseclass.extend({__init__(){ui.menu.load().then(tree=>this.render(tree));this.initNavigationControls();this.initUciIndicator()},initUciIndicator(){const original=ui.changes?.setIndicator;if(!original)return;ui.changes.setIndicator=function(n){original.call(this,n);document.querySelector('[data-indicator="uci-changes"]')?.setAttribute("data-count",n||0)}},initNavigationControls(){const overlay=document.querySelector("#mobile-menu-overlay");const navigationToggle=document.querySelector("#navigation-toggle");if(!navigationToggle||!overlay)return;const mobileList=overlay.querySelector("#mobile-nav-list");const desktop=window.matchMedia("(min-width: 768px)");const SIDEBAR_COLLAPSED_KEY="aurora.sidebarCollapsed";const isDesktopSidebar=()=>desktop.matches&&document.body.dataset.navType==="sidebar";const updateToggleState=expanded=>{const desktopSidebar=isDesktopSidebar();navigationToggle.classList.toggle("is-expanded",expanded&&!desktop.matches);navigationToggle.setAttribute("aria-expanded",expanded?"true":"false");navigationToggle.setAttribute("aria-controls",desktopSidebar?"sidebar-panel":"mobile-menu-overlay");const label=expanded&&!desktopSidebar?_("Close"):_("Navigation");navigationToggle.setAttribute("title",label);navigationToggle.setAttribute("aria-label",label)};const closeMobileNavigation=()=>{overlay.classList.remove("mobile-menu-open");document.body.classList.remove("mobile-navigation-open");document.body.style.overflow="";this.resetNavigationGroups(mobileList)};const getNavigationExpanded=()=>{if(isDesktopSidebar()){return!document.body.classList.contains("sidebar-collapsed")}return!desktop.matches&&overlay.classList.contains("mobile-menu-open")};const setNavigationExpanded=expanded=>{if(isDesktopSidebar()){closeMobileNavigation();const collapsed=!expanded;document.body.classList.toggle("sidebar-collapsed",collapsed);localStorage.setItem(SIDEBAR_COLLAPSED_KEY,collapsed);updateToggleState(expanded);return}if(desktop.matches){closeMobileNavigation();updateToggleState(false);return}overlay.classList.toggle("mobile-menu-open",expanded);document.body.classList.toggle("mobile-navigation-open",expanded);document.body.style.overflow=expanded?"hidden":"";if(expanded)this.expandActiveNavigationGroup(mobileList);else this.resetNavigationGroups(mobileList);updateToggleState(expanded)};const toggleNavigation=()=>setNavigationExpanded(!getNavigationExpanded());const syncNavigationState=()=>{closeMobileNavigation();if(isDesktopSidebar()){const collapsed=localStorage.getItem(SIDEBAR_COLLAPSED_KEY)==="true";document.body.classList.toggle("sidebar-collapsed",collapsed);updateToggleState(!collapsed);return}updateToggleState(false)};navigationToggle.addEventListener("click",e=>{e.stopPropagation();toggleNavigation()});overlay.addEventListener("click",e=>{if(e.target===overlay)setNavigationExpanded(false)});document.addEventListener("keydown",e=>{if(e.key==="Escape"&&overlay.classList.contains("mobile-menu-open")){setNavigationExpanded(false)}});desktop.addEventListener("change",syncNavigationState);syncNavigationState();document.addEventListener("click",e=>{const destination=e.target?.closest?.(".navigation-direct, .navigation-sublink, .mobile-nav-logout");if(destination&&overlay.contains(destination)){setNavigationExpanded(false)}})},renderMobileMenu(items){const list=document.querySelector("#mobile-nav-list");const footerAction=document.querySelector("#mobile-nav-footer-action");if(list)list.innerHTML="";if(footerAction)footerAction.innerHTML="";if(!list)return;items.forEach(item=>{if(item.isLogout){if(footerAction){footerAction.appendChild(E("a",{class:"mobile-nav-logout",href:item.href},[item.title]))}return}list.appendChild(this.renderNavigationItem(item,"mobile"))});this.bindNavigationAccordion(list)},render(tree){this.renderModeMenu(tree);if(L.env.dispatchpath.length>=3){let node=tree;let url="";for(let i=0;i<3&&node;i++){const segment=L.env.dispatchpath[i];node=node.children?.[segment];url+=(url?"/":"")+segment}if(node)this.renderTabMenu(node,url)}},renderTabMenu(tree,url,level=0){const container=document.querySelector("#tabmenu");const ul=E("ul",{class:"tabs"});const children=ui.menu.getChildren(tree);let activeNode=null;children.forEach(child=>{const isActive=L.env.dispatchpath[3+level]===child.name;ul.appendChild(E("li",{class:`tabmenu-item-${child.name}${isActive?" active":""}`},[E("a",{href:L.url(url,child.name)},[_(child.title)])]));if(isActive)activeNode=child});if(!ul.children.length)return E([]);container.appendChild(ul);container.style.display="";if(activeNode){this.renderTabMenu(activeNode,`${url}/${activeNode.name}`,level+1)}return ul},renderMainMenu(tree,url,level=0,navigationItems=null){const ul=level?E("ul",{class:"desktop-nav-list"}):document.querySelector("#topmenu");const children=ui.menu.getChildren(tree);if(level>1)return E([]);if(level===0){const navType=document.body?.dataset?.navType||"mega-menu";if(navType==="sidebar"){this.renderSidebLine truncated
|
||||||
@@ -213,7 +213,7 @@
|
|||||||
trim(`${boardinfo.release?.distribution ?? ''} ${boardinfo.release?.version ?? ''}`);
|
trim(`${boardinfo.release?.distribution ?? ''} ${boardinfo.release?.version ?? ''}`);
|
||||||
-%}
|
-%}
|
||||||
<div class="desktop-menu-container">
|
<div class="desktop-menu-container">
|
||||||
<div class="desktop-menu-board" aria-hidden="true">
|
<div class="desktop-menu-board" aria-hidden="true"><span class="board-label">{{ _('Device') }}</span>
|
||||||
<span class="board-line board-line-host" title="{{ entityencode(striptags(boardinfo.hostname ?? '?'), true) }}"><span class="board-text">{{ striptags(boardinfo.hostname ?? '?') }}</span></span>
|
<span class="board-line board-line-host" title="{{ entityencode(striptags(boardinfo.hostname ?? '?'), true) }}"><span class="board-text">{{ striptags(boardinfo.hostname ?? '?') }}</span></span>
|
||||||
{% if (board_model): %}
|
{% if (board_model): %}
|
||||||
<span class="board-line board-line-model" title="{{ entityencode(striptags(board_model), true) }}"><span class="board-text">{{ striptags(board_model) }}</span></span>
|
<span class="board-line board-line-model" title="{{ entityencode(striptags(board_model), true) }}"><span class="board-text">{{ striptags(board_model) }}</span></span>
|
||||||
|
|||||||