🤞 Sync 2026-08-30 21:23:32

This commit is contained in:
github-actions[bot] committed 2026-08-30 21:23:32 +08:00
1 parent f997fa51e8
commit 60c4eca90c
116 files changed
+86852 -58

No files matched your search

+30 -4
View File
@@ -17,7 +17,7 @@ LUCI_NAME:=luci-theme-footstrap
FOOTSTRAP_VERSION?=
ifneq ($(FOOTSTRAP_VERSION),)
PKG_VERSION:=$(FOOTSTRAP_VERSION)
PKG_RELEASE:=44
PKG_RELEASE:=45
endif
LUCI_TITLE:=Footstrap Theme
@@ -79,9 +79,29 @@ define Package/luci-theme-footstrap/conffiles
endef
# reload, never restart: rpcd holds sessions in memory, so `restart` logs out every LuCI user,
# including the admin who just clicked Update. `reload` sends SIGHUP, which re-reads
# /usr/share/rpcd/acl.d/*, and that ACL refresh is the only thing this package needs from rpcd.
# Verified on a live router: a session survives `reload` and dies across `restart`.
# including the admin who just clicked Update. A session survives `reload` and dies across
# `restart` — verified on a live router.
#
# AND RELOAD RE-READS THE PLUGINS, not only /usr/share/rpcd/acl.d/*. That correction matters,
# because it is what makes the check below necessary rather than decorative. Measured on a
# SNAPSHOT stand, where the `luci` object comes from the ucode plugin
# /usr/share/rpcd/ucode/luci (24.10 and 25.12 use /usr/libexec/rpcd/luci):
#
# file removed + reload -> `ubus list` loses `luci` (and it does NOT come back on its own)
# file removed + restart -> still gone
# file restored + reload -> back
#
# So a reload that lands while another package is replacing that file leaves rpcd without the
# object, and every luci/getFeatures, luci/getTimezones and luci/getMountPoints call answers
# `-32000 Object not found` until something reloads it again — the page then renders with the
# system time blank and an RPCError box per call. Reported from the field on a SNAPSHOT router,
# cleared by a reboot; nine days of uptime before it, so it was an upgrade that did it.
#
# Hence: reload, then ASK whether the object is there, and reload once more if it is not. A second
# reload and not a restart, because the table above is the whole argument — reload already does
# everything restart would do to the plugin set, and restart adds only the logout. If the object is
# still missing after that, it is not this package's reload that removed it, and throwing every
# admin out of LuCI would not bring it back.
define Package/luci-theme-footstrap/postinst
#!/bin/sh
[ -n "$${IPKG_INSTROOT}" ] || {
@@ -93,6 +113,12 @@ define Package/luci-theme-footstrap/postinst
sh /etc/uci-defaults/30_luci-theme-footstrap >/dev/null 2>&1 || true
rm -f /tmp/luci-indexcache* /tmp/luci-modulecache/* >/dev/null 2>&1 || true
/etc/init.d/rpcd reload >/dev/null 2>&1 || true
# see the note above the define: a reload that raced another package's file replacement leaves
# rpcd without the `luci` object, and nothing brings it back on its own
ubus list 2>/dev/null | grep -qx luci || {
sleep 1
/etc/init.d/rpcd reload >/dev/null 2>&1 || true
}
}
exit 0
endef
@@ -242,14 +242,23 @@
body[data-page="admin-status-overview"] .ifacebox:has(img[src*="/port_"]) > .ifacebox-body:nth-child(2) {
order: 2; /* below the zone-colour line (child 3, order 1) */
font-size: var(--fs-type); font-weight: var(--fs-weight); color: var(--fs-good); text-align: start;
/* Two halves of one mechanism.
* `nowrap` with no `min-width: 0` means "I do not give way": a flex item's automatic minimum
* size is its min-content, which for nowrap text is the whole string, so the speed cannot be
* squeezed and the TRAFFIC is what wraps.
* `flex-grow: 1` means "I take the slack", which pushes the traffic to the right edge while
/* `flex-grow: 1` means "I take the slack", which pushes the traffic to the right edge while
* the two share a row. `margin-left: auto` on the traffic is wrong: Chrome counts it when
* breaking lines, so the figures take a row of their own even on a card they fit. */
flex: 1 1 auto; white-space: nowrap;
* breaking lines, so the figures take a row of their own even on a card they fit.
*
* The text WRAPS, and the automatic minimum size is what keeps the wrap tidy. This field used
* to be `nowrap`, which holds for the speeds themselves (`1GbE`, `10 GbE`) and breaks on the
* no-link label — one short word in English, three in most other languages. `нет соединения`
* measured 127px in a card that gives it 127 and was CLIPPED, not ellipsised: the reader saw
* `нет соедине`. A label that cannot be read is worse than a card one line taller.
*
* NO `min-width: 0` with it. That would let the flex line squeeze this box to 77px — the
* width left beside the port image, which shares this box — and the label then broke mid-word
* (`соедине` / `ния`). Left at `auto` the box keeps its min-content, which for wrapping text
* is the longest WORD, so the label breaks between words and the short speeds, having nothing
* to wrap at, do not move at all. `overflow-wrap` is the last resort for a language whose
* single word is wider than the card. */
flex: 1 1 auto; white-space: normal; overflow-wrap: break-word;
}
body[data-page="admin-status-overview"] .ifacebox:has(img[src*="/port_"]) > .ifacebox-body:nth-child(2) br { display: none; }
body[data-page="admin-status-overview"] .ifacebox:has(img[src*="/port_"]):has(img[src*="_down.svg"]) > .ifacebox-body:nth-child(2) { color: var(--fs-dim); }
@@ -3,6 +3,39 @@
* viewport is silently CUT on the right rather than scrolled to. A device sweep found the
* offenders below; each fix lets the control or table shrink or wrap. Tablets were already
* clean. */
/* A pair of buttons an app packs into one `inline-flex` must be allowed to wrap its labels.
*
* `white-space: pre` on a button is stock — luci-theme-bootstrap sets it too — and it holds
* while the label is short. Ours are wider than stock at the same job: measured on
* ssclash's split button at 320, `Сохранить и перезагрузить конфигурацию` is 295px against
* stock's 245, because this theme's face is wider than the system stack even at a smaller
* size (13px vs 14px), and the 14px side padding adds 12 of the 50. The app's wrapper is
* `inline-flex`, so it takes the buttons' max-content — 324px inside a 288px column — and
* overflows by 36. Stock fits only because its buttons are narrower.
*
* Narrowing the buttons would be re-typesetting the theme to suit one app. Letting the label
* wrap costs nothing where it already fits — a short label has no wrap point — and turns the
* one case that does not into two lines. Scoped to the width where it happens: at 390 the
* same page is clean.
*
* `min-width: 0` with it, or the automatic minimum keeps the button at its longest word and
* the flex line cannot shrink it at all.
*
* `word-break: normal` is the third half of it. base/10-reset.css gives every button
* `break-all` — carried over from the fork, and inert while the label cannot wrap at all. The
* moment it can, `break-all` takes precedence over word boundaries and the label breaks mid-word
* (`Сохранить и перезагрузить ко` / `нфиг`). `overflow-wrap: break-word` keeps the escape hatch
* for a single word wider than the button, which is what `break-all` was there for. */
@container fs-view (max-width: 360px) {
#view .cbi-button, #view .btn,
#view input[type="button"], #view input[type="submit"], #view input[type="reset"] {
white-space: normal;
min-width: 0;
word-break: normal;
overflow-wrap: break-word;
}
}
@media (max-width: 767px) {
/* The foreign-<table> scroll fallback used to live here, guarded by this query. It does not
* any more: whether a table fits is a property of its CONTENT and its COLUMN, never of the