🎄 Sync 2026-05-06 19:35:12

This commit is contained in:
github-actions[bot] committed 2026-05-06 19:35:12 +08:00
1 parent b3aea13cdd
commit f58b6dd3a1
50 files changed
+1787 -626

No files matched your search

+45 -20
View File
@@ -3,7 +3,8 @@ A Material Design 3 theme for OpenWrt Luci.
This is a personal project based on the LuCI Bootstrap theme, imitating the Material Design 3 style.
**Nice to initiate an issue or PR!**
**Nice to initiate an issue or PR, and star! ⭐**
## ✨ Preview
<table>
<tr>
@@ -19,37 +20,61 @@ This is a personal project based on the LuCI Bootstrap theme, imitating the Mate
### 🎨 All color schemes
<table>
<tr>
<th>Baseline Purple</th>
<th>Trust Blue</th>
<th>Growth Green</th>
<th width="33.33%" align="center">Baseline Purple</th>
<th width="33.33%" align="center">Trust Blue</th>
<th width="33.33%" align="center">Growth Green</th>
</tr>
<tr>
<td><img src="imgs/baseline.jpg" /></td>
<td><img src="imgs/blue.jpg" /></td>
<td><img src="imgs/green.jpg" /></td>
<td width="33.33%" align="center">
<img src="imgs/baseline.jpg" width="100%" />
</td>
<td width="33.33%" align="center">
<img src="imgs/blue.jpg" width="100%" />
</td>
<td width="33.33%" align="center">
<img src="imgs/green.jpg" width="100%" />
</td>
</tr>
<tr>
<th>Calm Teal</th>
<th>Warm Orange</th>
<th>Vivid Orange</th>
<th width="33.33%" align="center">Calm Teal</th>
<th width="33.33%" align="center">Warm Orange</th>
<th width="33.33%" align="center">Vivid Orange</th>
</tr>
<tr>
<td><img src="imgs/teal.jpg" /></td>
<td><img src="imgs/orange.jpg" /></td>
<td><img src="imgs/vivid-orange.jpg" /></td>
<td width="33.33%" align="center">
<img src="imgs/teal.jpg" width="100%" />
</td>
<td width="33.33%" align="center">
<img src="imgs/orange.jpg" width="100%" />
</td>
<td width="33.33%" align="center">
<img src="imgs/vivid-orange.jpg" width="100%" />
</td>
</tr>
<tr>
<th>Sakura Red</th>
<th>Expressive Rose</th>
<th>Monochrome Gray</th>
<th width="33.33%" align="center">Sakura Red</th>
<th width="33.33%" align="center">Expressive Rose</th>
<th width="33.33%" align="center">Monochrome Gray</th>
</tr>
<tr>
<td><img src="imgs/sakura.jpg" /></td>
<td><img src="imgs/rose.jpg" /></td>
<td><img src="imgs/gray.jpg" /></td>
<td width="33.33%" align="center">
<img src="imgs/sakura.jpg" width="100%" />
</td>
<td width="33.33%" align="center">
<img src="imgs/rose.jpg" width="100%" />
</td>
<td width="33.33%" align="center">
<img src="imgs/gray.jpg" width="100%" />
</td>
</tr>
</table>
## 📦 Release
Download prebuilt packages from [GitHub Releases](https://github.com/KawaiiHachimi/luci-theme-material3/releases).
- `luci-theme-material3-*.apk` -> OpenWrt LuCI 25.12+
- `luci-theme-material3_*.ipk` -> OpenWrt LuCI 23.05~24.10
## 🙏 Credits
- [OpenWrt Luci](https://github.com/openwrt/luci)
- [Cursor](https://www.cursor.com/)
@@ -57,4 +82,4 @@ This is a personal project based on the LuCI Bootstrap theme, imitating the Mate
- [MDUI](https://www.mdui.org/zh-cn/)
- [Fluent UI System Icons](https://github.com/microsoft/fluentui-system-icons)
- [Material Design 3](https://m3.material.io/)
- [Reddit - LuCI theme bootstrap: Some modifications using userstyle](https://www.reddit.com/r/openwrt/comments/qmtmpf/lucithemebootstrap_some_modifications_using/)
- [Reddit - LuCI theme bootstrap: Some modifications using userstyle](https://www.reddit.com/r/openwrt/comments/qmtmpf/lucithemebootstrap_some_modifications_using/)
@@ -1,6 +1,6 @@
/*!
* LuCI Bootstrap Theme
* Material3 Mod
* Material3 Mod by KawaiiHachimi <bilibili@att.net>
* Copyright 2012 Nut & Bolt
* By David Menting <david@nut-bolt.nl>
* Based on Bootstrap v1.4.0
@@ -131,7 +131,8 @@
--material3-shell-background: var(--surface);
--material3-shell-foreground: var(--on-surface);
--material3-shell-state: var(--surface-container);
--material3-header-background: color-mix(in srgb, var(--material3-shell-background) 88%, transparent);
--material3-header-background: color-mix(in srgb, var(--material3-shell-background) 72%, transparent);
--material3-header-scrolled-background: color-mix(in srgb, var(--material3-card-background) 72%, transparent);
--material3-header-foreground: var(--material3-shell-foreground);
--material3-header-state: var(--material3-shell-state);
--material3-indicator-hover-background: var(--primary-container);
@@ -1512,7 +1513,8 @@ select {
.cbi-value {
display: flex;
flex-wrap: wrap;
margin-bottom: 18px;
margin: 0;
padding: 9px 0;
align-items: baseline;
}
@@ -2079,12 +2081,17 @@ header p {
header {
background: var(--material3-header-background);
box-shadow: none;
transition: box-shadow .3s;
transition: background-color .3s, box-shadow .3s;
padding: 0;
}
header.with-shadow {
box-shadow: none;
background: var(--material3-header-scrolled-background);
box-shadow: 0 .5px 1.5px 0 rgba(0, 0, 0, 19%), 0 0 1px 0 rgba(0, 0, 0, 3.9%);
}
body.sidebar-open header {
background: var(--material3-shell-background);
}
.menu-btn {
@@ -2166,7 +2173,7 @@ header.with-shadow {
top: var(--material3-header-height);
left: 0;
bottom: 0;
z-index: 760;
z-index: 820;
box-sizing: border-box;
width: var(--material3-sidebar-width);
padding: 0;
@@ -2246,6 +2253,17 @@ header.with-shadow {
opacity: 1;
visibility: visible;
}
.cbi-dropdown[open],
.cbi-dropdown[open]>ul.dropdown {
max-width: 100%;
}
.cbi-dropdown[open]>ul.dropdown {
box-sizing: border-box;
width: 100%;
min-width: 100%;
}
}
.nav {
@@ -2282,6 +2300,22 @@ header.with-shadow {
transition: .3s;
}
.nav-menu-title {
display: block;
flex: 1 1 auto;
min-width: 0;
overflow: hidden;
white-space: nowrap;
-webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 24px), transparent);
mask-image: linear-gradient(90deg, #000 calc(100% - 24px), transparent);
}
.nav a:hover>.nav-menu-title,
.nav a:focus>.nav-menu-title {
-webkit-mask-image: none;
mask-image: none;
}
.nav>li>a::before {
content: '';
width: 1.5rem;
@@ -2412,7 +2446,6 @@ header {
border: none;
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
box-shadow: none;
background: var(--md-sys-color-surface-translucent);
}
@@ -2443,7 +2476,8 @@ header {
transition: .3s;
padding: 1rem 1.5rem;
line-height: 18px;
display: block;
display: flex;
align-items: center;
border-radius: 2rem;
overflow: hidden;
text-shadow: none;
@@ -2786,6 +2820,7 @@ footer ul.breadcrumb {
white-space: pre-wrap;
overflow: auto;
width: 100%;
border-radius: var(--material3-card-radius);
}
.modal>.button-row {
@@ -2822,8 +2857,16 @@ body.modal-overlay-active #modal_overlay {
justify-content: center;
padding: 24px;
background:
radial-gradient(circle at top left, color-mix(in srgb, var(--primary-container) 64%, transparent), transparent 34rem),
radial-gradient(circle at top right, color-mix(in srgb, var(--tertiary-container) 58%, transparent), transparent 30rem),
radial-gradient(circle at 18% 8%,
color-mix(in srgb, var(--primary-container) 38%, transparent),
transparent 28rem),
linear-gradient(135deg,
color-mix(in srgb, var(--background) 78%, var(--primary-container)) 0%,
color-mix(in srgb, var(--background) 92%, var(--primary-container)) 46%,
color-mix(in srgb, var(--surface-container-low) 88%, var(--primary)) 100%),
linear-gradient(180deg,
color-mix(in srgb, var(--surface-container-low) 48%, transparent) 0%,
transparent 52%),
var(--background);
}
@@ -2833,10 +2876,14 @@ body.modal-overlay-active #modal_overlay {
max-width: 420px;
margin: 0;
padding: 32px;
border: 0;
border: 1px solid color-mix(in srgb, var(--outline-variant) 52%, transparent);
border-radius: 28px;
background: var(--material3-card-background);
box-shadow: var(--material3-card-shadow);
background: color-mix(in srgb, var(--material3-card-background) 78%, transparent);
backdrop-filter: blur(24px) saturate(1.12);
-webkit-backdrop-filter: blur(24px) saturate(1.12);
box-shadow:
0 12px 36px color-mix(in srgb, var(--outline) 18%, transparent),
0 1px 1px color-mix(in srgb, var(--outline) 10%, transparent);
color: var(--on-surface);
}
@@ -2954,8 +3001,8 @@ body.modal-overlay-active #modal_overlay {
}
.modal.login .material3-login-header img {
width: 48px;
height: 48px;
width: 64px;
height: 64px;
}
.modal.login .material3-login-header h2 {
@@ -3434,16 +3481,18 @@ body.modal-overlay-active #modal_overlay {
}
.cbi-progressbar {
border: 0;
border-radius: 3px;
position: relative;
min-width: 170px;
height: 4px;
margin: 1.4em 0 4px 0;
background: var(--background-color-medium);
background: var(--surface-container-high);
box-shadow: none;
}
.cbi-progressbar>div {
background: var(--primary-color-medium);
background: var(--primary);
height: 100%;
transition: width .25s ease-in;
width: 0%;
@@ -3605,7 +3654,7 @@ header [data-indicator] {
font-size: 12px;
font-weight: 600;
text-transform: none;
color: color-mix(in srgb, var(--material3-header-foreground) 80%, var(--material3-header-background));
color: color-mix(in srgb, var(--material3-header-foreground) 60%, var(--material3-header-background));
background: transparent;
transition: background-color .2s ease, color .2s ease;
}
@@ -3966,7 +4015,7 @@ th[data-sort-direction="desc"]::after {
background: var(--default-btn-background, var(--background-color-high));
color: var(--on-color, var(--text-color-high));
text-shadow: none;
border-radius: 16px;
border-radius: 12px;
box-shadow: none;
cursor: default;
line-height: 1.2em;
@@ -4413,8 +4462,9 @@ div.cbi-value var.cbi-tooltip-container,
.cbi-section-node,
.table {
margin: 0 1px 10px 1px;
width: calc(100% - 2px);
box-sizing: border-box;
margin: 0 0 10px;
width: 100%;
border-radius: var(--material3-card-radius);
background: var(--material3-card-background);
box-shadow: var(--material3-card-shadow);
@@ -4432,44 +4482,33 @@ div.cbi-value var.cbi-tooltip-container,
stroke: var(--text-color-highest) !important;
}
/* Status overview */
body[data-page="admin-status-overview"] .cbi-section {
/* Status overview and dashboard */
:is(body[data-page="admin-status-overview"], body[data-page=""]) .cbi-section,
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .cbi-section,
:is(body[data-page="admin-dashboard"], body[data-page="admin"]) .cbi-section-node {
border: 0;
background: transparent;
box-shadow: none;
}
:is(body[data-page="admin-status-overview"], body[data-page=""]) .cbi-section {
margin: 0 0 18px;
padding: 0;
width: auto;
border: 0;
border-radius: 0;
background: transparent;
box-shadow: none;
}
body[data-page="admin-status-overview"] .cbi-title h3 {
color: var(--on-surface);
font-size: 18px;
line-height: 36px;
}
body[data-page="admin-status-overview"] .cbi-section>.cbi-title+div {
margin: 1px;
width: calc(100% - 2px);
border-radius: 0;
background: transparent;
box-shadow: none;
}
body[data-page="admin-status-overview"] .cbi-section-descr,
body[data-page="admin-status-overview"] .cbi-map-descr,
body[data-page="admin-status-overview"] .cbi-section p,
body[data-page="admin-status-overview"] .cbi-section li,
body[data-page="admin-status-overview"] .table .td,
body[data-page="admin-status-overview"] .table .th {
:is(body[data-page="admin-status-overview"], body[data-page=""]) :is(.cbi-section-descr,
.cbi-map-descr,
.cbi-section p,
.cbi-section li) {
color: var(--on-surface-variant);
font-size: 13px;
font-weight: 400;
line-height: 18px;
}
body[data-page="admin-status-overview"] .cbi-title .label {
:is(body[data-page="admin-status-overview"], body[data-page=""]) .cbi-title .label {
display: inline-flex !important;
align-items: center;
justify-content: center;
@@ -4489,7 +4528,7 @@ body[data-page="admin-status-overview"] .cbi-title .label {
transition: background-color .2s ease, color .2s ease, opacity .2s ease;
}
body[data-page="admin-status-overview"] .cbi-title .label::before {
:is(body[data-page="admin-status-overview"], body[data-page=""]) .cbi-title .label::before {
content: '';
width: 17px;
height: 17px;
@@ -4498,70 +4537,65 @@ body[data-page="admin-status-overview"] .cbi-title .label::before {
mask: url("icons/eye-off.svg") center/contain no-repeat;
}
body[data-page="admin-status-overview"] .cbi-title .label:hover {
:is(body[data-page="admin-status-overview"], body[data-page=""]) .cbi-title .label:hover,
:is(body[data-page="admin-status-overview"], body[data-page=""]) .cbi-title .label.notice:hover {
background: var(--material3-menu-hover-background);
color: var(--on-surface);
}
body[data-page="admin-status-overview"] .cbi-title .label.notice {
:is(body[data-page="admin-status-overview"], body[data-page=""]) .cbi-title .label.notice {
background: transparent;
color: color-mix(in srgb, var(--on-surface-variant) 72%, transparent);
}
body[data-page="admin-status-overview"] .cbi-title .label.notice::before {
:is(body[data-page="admin-status-overview"], body[data-page=""]) .cbi-title .label.notice::before {
-webkit-mask-image: url("icons/eye.svg");
mask-image: url("icons/eye.svg");
}
body[data-page="admin-status-overview"] .cbi-title .label.notice:hover {
background: var(--material3-menu-hover-background);
color: var(--on-surface);
:is(body[data-page="admin-status-overview"], body[data-page=""]) .network-status-table {
gap: 10px;
margin: 0 0 10px;
}
body[data-page="admin-status-overview"] .network-status-table {
width: calc(100% + 16px);
margin: 0 -8px 8px;
}
body[data-page="admin-status-overview"] .network-status-table .ifacebox {
margin: 8px;
width: calc(100% - 16px);
:is(body[data-page="admin-status-overview"], body[data-page=""]) .network-status-table .ifacebox {
flex: 1 1 260px;
margin: 0;
padding: 8px;
border: 0;
border-radius: var(--material3-card-radius);
background: var(--material3-card-background);
box-shadow: var(--material3-card-shadow);
text-align: left;
white-space: normal;
}
body[data-page="admin-status-overview"] .ifacebox .ifacebox-head {
:is(body[data-page="admin-status-overview"], body[data-page=""]) .ifacebox .ifacebox-head {
padding: 2px 0 8px;
border: 0;
border-radius: 16px 16px 0 0;
background: transparent;
border-radius: 0;
background: transparent !important;
color: var(--on-surface-variant);
font-weight: 400;
opacity: .9;
text-shadow: none;
}
body[data-page="admin-status-overview"] .ifacebox .ifacebox-head strong {
:is(body[data-page="admin-status-overview"], body[data-page=""]) .ifacebox .ifacebox-head strong {
font-weight: 500;
}
body[data-page="admin-status-overview"] .ifacebox .ifacebox-head.active {
:is(body[data-page="admin-status-overview"], body[data-page=""]) .ifacebox .ifacebox-head.active {
border: 0;
background: transparent;
background: transparent !important;
color: var(--on-surface);
text-shadow: none;
}
body[data-page="admin-status-overview"] .ifacebox .ifacebox-body {
:is(body[data-page="admin-status-overview"], body[data-page=""]) .ifacebox .ifacebox-body {
padding: 0;
line-height: 1.35;
}
body[data-page="admin-status-overview"] .ifacebadge,
body[data-page="admin-status-overview"] .ifacebadge.large,
body[data-page="admin-status-overview"] .network-status-table .ifacebox-body .ifacebadge {
:is(body[data-page="admin-status-overview"], body[data-page=""]) .ifacebadge,
:is(body[data-page="admin-status-overview"], body[data-page=""]) .ifacebadge.large,
:is(body[data-page="admin-status-overview"], body[data-page=""]) .network-status-table .ifacebox-body .ifacebadge {
padding: 8px;
border: 1px solid color-mix(in srgb, var(--outline) 48%, transparent);
border-radius: 16px;
@@ -4570,55 +4604,19 @@ body[data-page="admin-status-overview"] .network-status-table .ifacebox-body .if
text-shadow: none;
}
body[data-page="admin-status-overview"] .table {
margin: 1px;
width: calc(100% - 2px);
border-radius: var(--material3-card-radius);
background: var(--material3-card-background);
box-shadow: var(--material3-card-shadow);
}
body[data-page="admin-status-overview"] .cbi-progressbar {
border: 0;
background: var(--surface-container-high);
box-shadow: none;
}
body[data-page="admin-status-overview"] .cbi-progressbar>div {
background: var(--primary);
}
body[data-page="admin-status-overview"] .table .td,
body[data-page="admin-status-overview"] .table .th,
body[data-page="admin-status-overview"] .tr.cbi-section-table-titles,
body[data-page="admin-status-overview"] .cbi-section-table-titles.named::before,
body[data-page="admin-status-overview"] .cbi-section-table-descr.named::before,
body[data-page="admin-status-overview"] .cbi-section-table-row[data-title]::before {
border-top: 0;
}
body[data-page="admin-status-overview"] .tr.cbi-section-table-titles {
background: transparent;
}
/* Dashboard cards */
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .cbi-section,
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .cbi-section-node {
border: 0;
background: transparent;
box-shadow: none;
}
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard .dashboard-bg.box-s1 {
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard .dashboard-bg.box-s1,
:is(body[data-page="admin-status-overview"], body[data-page=""]) .network-status-table .ifacebox {
border: 0;
border-radius: var(--material3-card-radius);
background: var(--material3-card-background);
box-shadow: var(--material3-card-shadow);
}
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard .thead.dashboard-bg,
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard .tr.dashboard-bg,
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard .tfoot.dashboard-bg {
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard :is(.thead.dashboard-bg,
.tr.dashboard-bg,
.tfoot.dashboard-bg,
.table) {
border-radius: 0;
background: transparent;
box-shadow: none;
@@ -4627,34 +4625,28 @@ body[data-page="admin-status-overview"] .tr.cbi-section-table-titles {
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard .table {
margin: 0;
width: auto;
border-radius: 0;
background: transparent;
box-shadow: none;
}
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard hr,
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard .table .td,
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard .table .th {
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard .router-status-wifi .assoclist.devices-info .tr> :nth-child(3) {
width: 30%;
}
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard .router-status-wifi .assoclist.devices-info .tr> :nth-child(4) {
width: 20%;
min-width: 85px;
white-space: normal;
word-break: keep-all;
overflow-wrap: normal;
}
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard hr {
border: 0;
}
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard h3,
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard .settings-info,
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard .table .td,
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard .table .th {
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard :is(h3, .settings-info) {
color: var(--on-surface-variant);
}
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard .cbi-progressbar {
border: 0;
background: var(--surface-container-high);
box-shadow: none;
}
:is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard .cbi-progressbar>div {
background: var(--primary);
}
:is(body[data-page="admin-status-iptables"], body[data-page="admin-status-nftables-iptables"]) .cbi-tabmenu {
margin-top: 28px;
}
@@ -4662,4 +4654,4 @@ body[data-page="admin-status-overview"] .tr.cbi-section-table-titles {
[data-darkmode="true"] :is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard img.svgmonotone,
[data-mode="dark"] :is(body[data-page="admin-dashboard"], body[data-page="admin"], body[data-page=""]) .Dashboard img.svgmonotone {
filter: invert(1) brightness(1.65) contrast(.82) opacity(.86);
}
}
@@ -2,10 +2,15 @@ header h3 a {
display: none !important;
}
footer {
width: 100%;
padding-left: 12px;
padding-right: 12px;
:is(body[data-page="admin-status-overview"], body[data-page=""]) .cbi-title .label {
width: 32px;
padding: 0;
font-size: 0 !important;
gap: 0;
}
:is(body[data-page="admin-status-overview"], body[data-page=""]) .cbi-title .label::before {
flex: 0 0 auto;
}
@media screen and (max-device-width: 600px) {
@@ -143,6 +148,7 @@ footer {
}
.tr.table-titles,
.tr.dashboard-table-titles,
.cbi-section-table-titles,
.cbi-section-table-descr {
display: none;
@@ -189,6 +195,7 @@ footer {
max-width: 100%;
padding: 3px 2px;
flex-basis: 100%;
text-align: left;
}
.hide-sm,
@@ -301,25 +308,41 @@ footer {
padding: 8px;
}
[data-page="admin-status-overview"] .td[width="33%"] {
:is([data-page="admin-status-overview"], [data-page=""]) .td[width="33%"] {
flex-basis: 33%;
}
[data-page="admin-status-overview"] .table {
margin: 4px;
width: calc(100% - 8px);
}
[data-page="admin-status-overview"] .table,
[data-page="admin-status-overview"] .tr,
[data-page="admin-status-overview"] .td,
[data-page="admin-status-overview"] .th,
[data-page="admin-status-overview"] .tr[data-title]::before,
[data-page="admin-status-overview"] .td[data-title]::before {
:is([data-page="admin-status-overview"], [data-page=""]) .table,
:is([data-page="admin-status-overview"], [data-page=""]) .tr,
:is([data-page="admin-status-overview"], [data-page=""]) .td,
:is([data-page="admin-status-overview"], [data-page=""]) .th,
:is([data-page="admin-status-overview"], [data-page=""]) .tr[data-title]::before,
:is([data-page="admin-status-overview"], [data-page=""]) .td[data-title]::before {
border-top: 0;
border-bottom: 0;
}
:is([data-page="admin-dashboard"], [data-page="admin"], [data-page=""]) :is(.Dashboard, .dashboard-bg.box-s1) .td[data-title]::before {
word-break: keep-all;
}
:is([data-page="admin-dashboard"], [data-page="admin"], [data-page=""]) .Dashboard .devices-list .devices-info .tr .td {
padding: 3px !important;
}
:is([data-page="admin-dashboard"], [data-page="admin"], [data-page=""]) .Dashboard .router-status-wifi.dashboard-bg.box-s1 .assoclist.devices-info.table>.tr:not(.dashboard-table-titles)>.td {
display: block;
flex: 0 0 50% !important;
width: 50% !important;
max-width: 50%;
min-width: 0;
}
:is([data-page="admin-dashboard"], [data-page="admin"], [data-page=""]) .Dashboard .router-status-wifi.dashboard-bg.box-s1 .assoclist.devices-info .cbi-progressbar {
width: 100% !important;
min-width: 0 !important;
}
header .pull-right .label {
white-space: normal;
display: inline-block;
@@ -530,4 +553,4 @@ footer {
.ifacebox .ifacebox-body>* {
margin: .125em;
}
}
}
@@ -6,6 +6,7 @@ return baseclass.extend({
__init__() {
ui.menu.load().then((tree) => this.render(tree));
this.initNavigationShell();
this.initDashboardTables();
},
createRipple(ev, target) {
@@ -64,11 +65,16 @@ return baseclass.extend({
const sidebar = document.querySelector('.sidebar');
const overlay = document.querySelector('.sidebar-overlay');
const header = document.querySelector('header');
const collapsedQuery = window.matchMedia('(max-width: 854px), (max-device-width: 854px)');
if (header) {
window.addEventListener('scroll', () => {
header.classList.toggle('with-shadow', window.scrollY > 8);
});
const updateHeaderShadow = () => {
header.classList.toggle('with-shadow', collapsedQuery.matches && window.scrollY > 8);
};
updateHeaderShadow();
window.addEventListener('scroll', updateHeaderShadow, { passive: true });
collapsedQuery.addEventListener('change', updateHeaderShadow);
}
if (!button || !sidebar || !overlay)
@@ -78,6 +84,7 @@ return baseclass.extend({
sidebar.classList.remove('active');
overlay.classList.remove('active');
button.classList.remove('active');
document.body.classList.remove('sidebar-open');
document.body.style.overflow = '';
button.setAttribute('aria-expanded', 'false');
};
@@ -88,6 +95,7 @@ return baseclass.extend({
const isOpen = sidebar.classList.contains('active');
button.classList.toggle('active', isOpen);
document.body.classList.toggle('sidebar-open', isOpen);
document.body.style.overflow = isOpen ? 'hidden' : '';
button.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
});
@@ -117,7 +125,87 @@ return baseclass.extend({
if (target)
this.createRipple(ev, target);
});
},
sidebar.addEventListener('mouseover', ev => {
const link = ev.target.closest('.nav a');
const title = link ? link.querySelector('.nav-menu-title') : null;
if (title && title.scrollWidth > title.clientWidth)
title.scrollTo({ left: title.scrollWidth - title.clientWidth, behavior: 'smooth' });
});
sidebar.addEventListener('mouseout', ev => {
const link = ev.target.closest('.nav a');
const title = link ? link.querySelector('.nav-menu-title') : null;
if (title && !link.contains(ev.relatedTarget))
title.scrollTo({ left: 0, behavior: 'smooth' });
});
},
isDashboardPage() {
const path = (L.env.requestpath || []).join('/');
return path == '' || path == 'admin' || path == 'admin/dashboard';
},
initDashboardTables() {
if (!this.isDashboardPage())
return;
const sync = () => this.updateDashboardTables();
if (document.readyState == 'loading')
document.addEventListener('DOMContentLoaded', sync, { once: true });
else
sync();
const target = document.querySelector('#maincontent') || document.body;
let queued = false;
const observer = new MutationObserver(() => {
if (queued)
return;
queued = true;
window.setTimeout(() => {
queued = false;
sync();
}, 100);
});
if (target)
observer.observe(target, { childList: true, subtree: true });
},
updateDashboardTables() {
document.querySelectorAll('.Dashboard, .dashboard-bg.box-s1').forEach(scope => {
scope.querySelectorAll('.table').forEach(table => {
const rows = Array.prototype.filter.call(table.children, child => child.classList && child.classList.contains('tr'));
const headerRow = rows.find(row => row.querySelector('.th'));
if (!headerRow)
return;
const titles = Array.prototype.map.call(headerRow.children, cell =>
cell.classList && cell.classList.contains('th') ? cell.textContent.trim() : '');
headerRow.classList.add('dashboard-table-titles');
rows.forEach(row => {
if (row === headerRow)
return;
Array.prototype.forEach.call(row.children, (cell, index) => {
if (!cell.classList || !cell.classList.contains('td') || !titles[index])
return;
if (!cell.getAttribute('data-title'))
cell.setAttribute('data-title', titles[index]);
});
});
});
});
},
render(tree) {
let node = tree;
@@ -148,7 +236,7 @@ return baseclass.extend({
const className = 'tabmenu-item-%s %s'.format(child.name, activeClass);
ul.appendChild(E('li', { 'class': className }, [
E('a', { 'href': L.url(url, child.name) }, [ _(child.title) ] )]));
E('a', { 'href': L.url(url, child.name) }, [_(child.title)])]));
if (isActive)
activeNode = child;
@@ -204,7 +292,7 @@ return baseclass.extend({
const li = E('li', attrs, [
E('a', linkAttrs, [
_(child.title),
E('span', { 'class': 'nav-menu-title' }, [_(child.title)]),
]),
submenu
]);
@@ -230,7 +318,7 @@ return baseclass.extend({
: index === 0;
ul.appendChild(E('li', { 'class': isActive ? 'active' : '' }, [
E('a', { 'href': L.url(child.name) }, [ _(child.title) ])
E('a', { 'href': L.url(child.name) }, [_(child.title)])
]));
if (isActive)
@@ -8,6 +8,9 @@
/
<a href="{{ entityencode(version.disturl ?? '#', true) }}" target="_blank" rel="noreferrer">
{{ version.distname }} {{ version.distversion }} ({{ version.distrevision }})</a>
/
<a href="https://github.com/KawaiiHachimi/luci-theme-material3" target="_blank" rel="noreferrer">
luci-theme-material3</a>
{% if (lua_active): %}
/ {{ _('Lua compatibility mode active') }}
{% endif %}
@@ -45,7 +45,7 @@
<meta name="darkreader-lock">
<link rel="stylesheet" href="{{ media }}/cascade.css">
<link rel="stylesheet" media="only screen and (max-device-width: 854px)" href="{{ media }}/mobile.css" />
<link rel="icon" href="{{ media }}/logo.svg" sizes="any">
<link rel="icon" href="{{ media }}/logo.svg" sizes="any">
{% if (node?.css): %}
<link rel="stylesheet" href="{{ resource }}/{{ node.css }}">
{% endif %}