Sync 2026-07-08 08:32:44

This commit is contained in:
github-actions[bot] 2026-07-08 08:32:44 +08:00
parent 399e8100fc
commit bd8d184870
10 changed files with 123 additions and 26 deletions

View File

@ -193,6 +193,14 @@ header {
.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;
[data-nav-type="sidebar"] & {
@apply md:hidden;
}
[data-nav-type="sidebar"].sidebar-collapsed & {
@apply md:inline-block md:transition-opacity md:duration-150 md:starting:opacity-0;
}
}
.nav {
@ -255,6 +263,14 @@ header {
@apply md:flex;
}
/* D1 底线呼吸展开态沿用短底线汉堡折叠后底线伸满三线齐整 =
侧栏收纳完毕dasharray 只改可见长度线帽形状不受影响 */
[data-nav-type="sidebar"].sidebar-collapsed
&
.navigation-toggle-line-bottom {
@apply md:[stroke-dasharray:15_15];
}
& .navigation-toggle {
@apply cursor-pointer rounded-none border-0 bg-transparent p-0 shadow-none transition-transform duration-150 hover:scale-105 active:scale-95;
@ -264,7 +280,15 @@ header {
& .navigation-toggle-line {
transform-box: fill-box;
@apply origin-center transition-[transform,opacity] duration-150 ease-in-out;
@apply origin-center transition-[transform,opacity,stroke-dasharray] duration-150 ease-in-out;
}
/* Tabler menu-2 geometry: all three lines are full-length equals.
The signature short bottom line is a stroke-dasharray crop, not a
shorter segment or a scaleX scaling distorts the round caps and
makes the "equal" collapsed state read as uneven lengths. */
& .navigation-toggle-line-bottom {
@apply [stroke-dasharray:7.5_15];
}
&.is-expanded {
@ -278,7 +302,8 @@ header {
}
& .navigation-toggle-line-bottom {
transform: translate(3.75px, -5px) rotate(-45deg) scaleX(2);
transform: translateY(-5px) rotate(-45deg);
@apply [stroke-dasharray:15_15];
}
}
}
@ -316,8 +341,10 @@ header {
}
body[data-nav-type="sidebar"] {
/* Desktop header + sidebar form one flush, L-shaped application frame: a
full-width header on top, a sidebar pinned to the left edge below it.
/* T4 shell: the sidebar is a full-height first column (brand menu
logout in one run), and the header spans only the content column so
the sidebar's right border runs viewport top to bottom and the header
reads as the content area's toolbar, not a page-wide bar.
A CSS grid (not flex-wrap) keeps the header row at its natural height
so collapsing the sidebar never stretches it lets the sidebar column
animate to zero, and lets #maincontent fluidly reclaim the freed space.
@ -329,11 +356,11 @@ body[data-nav-type="sidebar"] {
}
& > header {
@apply md:border-hairline md:col-span-full md:row-start-1 md:mb-0 md:border-b;
@apply md:border-hairline md:col-start-2 md:row-start-1 md:mb-0 md:border-b;
}
& > .sidebar-panel {
@apply md:col-start-1 md:row-start-2;
@apply md:col-start-1 md:row-span-2 md:row-start-1;
}
& > #maincontent {
@ -341,7 +368,10 @@ body[data-nav-type="sidebar"] {
}
& .header-crumb {
@apply text-text-muted my-0 mr-auto ml-6 hidden min-w-0 list-none items-center gap-2 overflow-hidden p-0 text-sm md:flex;
/* Expanded: the crumb is the header's leftmost element (brand lives in
the sidebar head), so it sits on the header's own padding. Collapsed:
burger + brand reappear before it and it takes back its old offset. */
@apply text-text-muted my-0 mr-auto ml-0 hidden min-w-0 list-none items-center gap-2 overflow-hidden p-0 text-sm md:flex;
& li {
@apply m-0 list-none whitespace-nowrap;
@ -356,8 +386,12 @@ body[data-nav-type="sidebar"] {
}
}
&.sidebar-collapsed .header-crumb {
@apply md:ml-6;
}
& .sidebar-panel {
@apply border-hairline sticky top-14 hidden h-[calc(100vh-3.5rem)] w-full overflow-hidden rounded-none border-r transition-[visibility] duration-[250ms] md:block;
@apply border-hairline sticky top-0 hidden h-dvh w-full overflow-hidden rounded-none border-r transition-[visibility] duration-[250ms] md:block;
}
/* Visibility flips at the end of the slide so collapsed controls leave the
@ -374,6 +408,21 @@ body[data-nav-type="sidebar"] {
@apply -translate-x-full opacity-0;
}
/* Sidebar head: logo + hostname. h-14 matches the header row so its
bottom hairline continues the header's border in one unbroken line
across the viewport. */
& .sidebar-head {
@apply border-hairline flex h-14 shrink-0 items-center gap-2.5 border-b px-4;
& .sidebar-logo {
@apply size-5 shrink-0 rounded-md;
}
& .sidebar-brand {
@apply text-text hover:text-brand min-w-0 flex-1 truncate text-lg font-semibold tracking-tight no-underline transition-colors duration-150;
}
}
& .sidebar-list {
@apply m-0 flex-1 list-none space-y-0.5 overflow-y-auto p-3;
@ -397,10 +446,11 @@ body[data-nav-type="sidebar"] {
& .sidebar-footer {
@apply border-hairline shrink-0 border-t p-3;
/* Logout: muted at rest; on hover the base .nav-link pill background
plus error-colored text is the intended compound state (matches v1). */
/* Logout: muted at rest, standard row treatment on hover same
vocabulary as every other sidebar row (the v1 danger-red hover read
as unrelated to the rest of the menu). */
& .nav-link {
@apply text-text-muted hover:text-danger;
@apply text-text-muted hover:text-text;
}
}
}

View File

@ -8,7 +8,10 @@
*/
.nav-link {
@apply text-text hover:bg-hover-faint block rounded-xl px-3 py-1.5 no-underline transition-all duration-150;
/* hover:no-underline: the global `a:hover { underline }` in _elements.css
outranks a bare class (a:hover is 0,1,1), so nav rows must opt out at
the same specificity tier. */
@apply text-text hover:bg-hover-faint block rounded-xl px-3 py-1.5 no-underline transition-all duration-150 hover:no-underline;
}
.navigation-direct {

View File

@ -1,8 +1,11 @@
.mobile-menu-overlay {
@apply max-md:bg-mega-menu-bg max-md:invisible max-md:fixed max-md:inset-0 max-md:z-60 max-md:opacity-0 max-md:backdrop-blur-lg max-md:backdrop-saturate-150 max-md:transition-[visibility,opacity] max-md:duration-[250ms] md:hidden;
@apply max-md:bg-mega-menu-bg max-md:invisible max-md:fixed max-md:inset-0 max-md:z-60 max-md:opacity-0 max-md:backdrop-blur-lg max-md:backdrop-saturate-150 md:hidden;
/* Transitions live on the OPEN state only: opening fades in, closing cuts
instantly. Link taps close into a full-page navigation, and any close
fade racing the document swap freezes mid-frame as a ghost. */
&.mobile-menu-open {
@apply max-md:visible max-md:opacity-100;
@apply max-md:visible max-md:opacity-100 max-md:transition-[visibility,opacity] max-md:duration-[250ms];
}
.mobile-nav {
@ -17,7 +20,7 @@
}
& .mobile-nav-list {
@apply max-md:m-0 max-md:flex max-md:min-h-0 max-md:flex-1 max-md:-translate-y-2 max-md:list-none max-md:flex-col max-md:overflow-y-auto max-md:overscroll-contain max-md:p-0 max-md:pb-5 max-md:opacity-0 max-md:transition-[translate,opacity] max-md:duration-[250ms] max-md:ease-out;
@apply max-md:m-0 max-md:flex max-md:min-h-0 max-md:flex-1 max-md:-translate-y-2 max-md:list-none max-md:flex-col max-md:overflow-y-auto max-md:overscroll-contain max-md:p-0 max-md:pb-5 max-md:opacity-0;
& .mobile-nav-item {
@apply max-md:shrink-0;
@ -60,7 +63,7 @@
}
&.mobile-menu-open .mobile-nav-list {
@apply max-md:translate-y-0 max-md:opacity-100;
@apply max-md:translate-y-0 max-md:opacity-100 max-md:transition-[translate,opacity] max-md:duration-[250ms] max-md:ease-out;
}
}

View File

@ -469,7 +469,10 @@ return baseclass.extend({
items.forEach((item) => {
if (item.isActiveGroup || item.isActivePage) {
crumb.push(item.title);
if (item.activePage) crumb.push(item.activePage.title);
// Same-named group/page pairs ("System System") collapse to one
// level — the duplicate adds no information.
if (item.activePage && item.activePage.title !== item.title)
crumb.push(item.activePage.title);
}
if (item.isLogout) {
@ -485,7 +488,7 @@ return baseclass.extend({
this.bindNavigationAccordion(list);
crumb.forEach((title, i) => {
if (i) crumbEl?.appendChild(E("li", { class: "crumb-sep" }, ["/"]));
if (i) crumbEl?.appendChild(E("li", { class: "crumb-sep" }, [""]));
crumbEl?.appendChild(
E("li", { class: i === crumb.length - 1 ? "current" : "" }, [title]),
);

View File

@ -729,13 +729,47 @@ test("renders sidebar items, logout, and translated crumbs without duplication",
assert.equal(crumb.children.length, 3);
assert.deepEqual(
crumb.children.map((child) => textContent(child)),
["translated:Network", "/", "translated:Wireless"],
["translated:Network", "", "translated:Wireless"],
);
assert.equal(crumb.children[2].getAttribute("class"), "current");
assert.equal(list.dataset.accordionBound, "true");
assert.equal(list.listenerCount("click"), 1);
});
test("collapses same-named group/page crumbs to a single level", () => {
const crumb = new FakeElement("ol", {}, [new FakeElement("li")]);
const document = createFakeDocument({
elements: {
"#header-crumb": crumb,
"#sidebar-list": new FakeElement("ul"),
},
navType: "sidebar",
});
const menu = loadMenuModule({
dispatchpath: ["admin", "system", "system"],
document,
translate: (value) => `translated:${value}`,
});
const tree = {
children: {
system: {
title: "System",
children: {
system: { title: "System" },
},
},
},
};
menu.renderSidebar(menu.buildNavigationModel(getMenuChildren(tree), "admin"));
assert.deepEqual(
crumb.children.map((child) => textContent(child)),
["translated:System"],
);
assert.equal(crumb.children[0].getAttribute("class"), "current");
});
test("renders an active group expanded when an open mobile list was initially empty", () => {
const list = new FakeElement("ul");
const overlay = new FakeElement("div", { class: "mobile-menu-open" }, [list]);

View File

@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk
LUCI_TITLE:=Aurora Theme (A modern browser theme built with Vite and Tailwind CSS)
LUCI_DEPENDS:=+luci-base
PKG_VERSION:=1.0.8
PKG_RELEASE:=44
PKG_VERSION:=1.0.10
PKG_RELEASE:=45
PKG_LICENSE:=Apache-2.0
LUCI_MINIFY_CSS:=

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -208,7 +208,7 @@
<svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<line class="navigation-toggle-line navigation-toggle-line-top" x1="2.5" y1="5" x2="17.5" y2="5"/>
<line class="navigation-toggle-line navigation-toggle-line-middle" x1="2.5" y1="10" x2="17.5" y2="10"/>
<line class="navigation-toggle-line navigation-toggle-line-bottom" x1="2.5" y1="15" x2="10" y2="15"/>
<line class="navigation-toggle-line navigation-toggle-line-bottom" x1="2.5" y1="15" x2="17.5" y2="15"/>
</svg>
</button>
</div>
@ -261,6 +261,10 @@
{% if (nav_type == 'sidebar'): %}
<aside class="sidebar-panel" id="sidebar-panel" aria-label="{{ _('Navigation') }}">
<nav class="sidebar-panel-inner">
<div class="sidebar-head">
<img class="sidebar-logo" src="{{ media }}/images/{{ logo_svg }}?v={{ icon_cache_version }}" alt="" aria-hidden="true">
<a class="sidebar-brand" href="/">{{ hostname }}</a>
</div>
<ul class="sidebar-list" id="sidebar-list"></ul>
<div class="sidebar-footer" id="sidebar-footer"></div>
</nav>

View File

@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=qBittorrent
PKG_VERSION:=5.2.2
PKG_RELEASE:=3
PKG_VERSION:=5.2.3
PKG_RELEASE:=4
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/qbittorrent/qBittorrent/tar.gz/release-$(PKG_VERSION)?