luci-theme-footstrap: add new theme - #8903
Conversation
|
I like it. Could be a spiritual successor of the OpenWrt 2020 theme. Ideally I'd like to apply the same improvements to the bootstrap default theme too, while keeping its current style. |
|
Thanks for a feedback @jow- !
Palettes are templated by design: adding one is a matter of filling in a set of variables, not touching the chrome. So a palette matching bootstrap's current look is a small amount of work.
That might cover the "same improvements, current style" case without backporting client-side navigation logic into bootstrap itself. Also theme can be much faster if this will be merged |
|
I love this @VizzleTF . 👍 Just out of curiosity, should/could we minify some files? The ones that are more generic (never changes). |
Thank you for feedback! I minified it in my repo, its saves around 15% (65kb instead of 75kb) i can do it here also, if it doesn’t need to be readable 😄 |
Ah okey. :) I'll let @jow- make that decision 👍 |
openwrt-ai
left a comment
There was a problem hiding this comment.
Reviewed 1 new commit (3985204). The commit message matches the diff, so no commit-check notes.
Two functional findings (login-form parity with the base sysauth.ut, and a layout-default that is stated three times and disagrees once) plus four nits are inline. CI on 39852045 is green across all three FormalityCheck runs, so nothing here is CI-grounded.
Generated by Claude Code
3985204 to
4251198
Compare
…default once The theme-local sysauth.ut dropped auth_fields, auth_message, auth_html and auth_assets, which the dispatcher hands every sysauth template. With luci-plugin-2fa installed the OTP input was never drawn, so luci_otp was never posted and a router with 2FA enabled could not be logged into while this theme was active. The template exists only to pass blank_page: true and now stays a superset of the generic one; each conditional attribute carries a leading space because ucode emits none of its own. _resolvedDefault() still answered 'sidebar' after the built-in layout flipped to the top bar, so on a fresh install matchesSavedDefault() was false before the user touched anything and Reset-to-saved landed on the wrong layout. Three comments described an Appearance page at admin/system/appearance that the package never shipped, counted fourteen axes against AXIS_KEYS' twenty-one, and listed a po/ that luci.mk's Build/Prepare does not copy. Found by the review on openwrt/luci#8903; verified on all four owlab routers.
4251198 to
b7402d3
Compare
|
this theme is awesome, much much better than others like proton2025/aurora. |
|
The three more or less official themes are:
I'm inclined to take this but given that maintaining non-default themes is effort no one is willing to spend, one of the other themes likely has to be deprecated. I'd lean towards deprecating 2020 in favor to this but maybe let's hear the takes from @feckert @systemcrash @hnyman |
I'll be glad to keep maintaining the theme. If something changes in luci-base and it breaks, I also have a few other pet projects I've kept going for a couple of years now, like |
|
If a new theme is added, I would drop at least the 2020, but maybe also the legacy theme, which is likely not used by many. (Personally I use bootstrap, which works well) |
|
Been testing this since PR, and I am a fan. Clean, fast, simple and refreshing. |
openwrt-ai
left a comment
There was a problem hiding this comment.
Reviewed the force-push 39852045 → b7402d3. The commit message is unchanged and still matches the diff, so no commit-check notes.
All six threads from the last round are addressed: sysauth.ut now carries auth_message / auth_fields / auth_html / auth_assets and is a proper superset of the generic template; _resolvedDefault().layout is top; the Makefile, header.ut and fs-prefs.js header comments and the menu-footstrap.js indentation are all corrected.
The new work in this revision is the third palette. The list is consistently extended across all five places that need it — cascade.css (light + dark blocks, same token set as the other palettes), head.ut's _sd_pal whitelist, head.ut's pre-paint, fs-prefs.js's new PALETTES array, and the fs-appearance.js select — and swapping enumAxis for the wallpaper/density validate-against-a-list shape is the right call for a three-valued axis.
One functional finding inline, in the factory that palette just moved out of: enumAxis derives its window.__fsSD field name as key.slice(3), which is wrong for its one remaining instance (fs-pattern-ink → pattern-ink, but the field is pattern_ink). Plus three nits. CI on b7402d3 is green across all three FormalityCheck runs, so nothing here is CI-grounded.
Generated by Claude Code
…rver sends enumAxis derived its window.__fsSD field name as the localStorage key minus 'fs-', giving 'pattern-ink' where head.ut emits 'pattern_ink'. sd() answered undefined for good, so the axis reported the built-in 'theme' whatever the router had saved: the page was pre-painted data-pattern-ink="original" while the Ink control read Theme, and pressing Save-as-default wrote 'theme' over the stored value. Reproduced and fixed on 25.12/apk and 24.10/opkg. colorAxis folds the hyphen too, where every key is one word today and the failure would be as silent tomorrow. Also corrected the comments that had stopped describing the code: the uci-defaults fall-through called the built-in layout "the sidebar default", the axis-shape inventory named a hueAxis that does not exist, omitted surfaceAxis, counted five instances against fifteen, and still listed updateCheck and a wallpaper that persists to the router; four CSS comments and the file tree in docs/css.md pointed at styles/01-fonts.css, deleted with the webfonts in 0.12.1. The sysauth whitespace rationale now states what ucode actually does. Found by the review on openwrt/luci#8903.
7273c92 to
98201ff
Compare
openwrt-ai
left a comment
There was a problem hiding this comment.
Reviewed the force-push b7402d3 → 98201ff. The commit message is unchanged and still matches the diff, so no commit-check notes.
First, my ucode whitespace nit from the last round was wrong and your measurement is right — I checked the source rather than my recollection. lstrip_blocks/trim_blocks are not off by default the way I assumed: both the ucode CLI (main.c:531-532) and, more to the point, uhttpd's ucode plugin (ucode.c:197-201) set both to true, and loadfile() inherits the running VM's config and only overrides the keys it is handed (lib.c:5522) — so LuCI's loadfile(path, { raw_mode: false }) keeps them on. The lexer then strips \t\v\f\r before {% and the newline after %} with plain tags (lexer.c:992, lexer.c:1076), which reproduces your A\nBCD exactly. The leading spaces are load-bearing and the comment now states the rule correctly.
The enumAxis/colorAxis sdKey fold, the uci-defaults layout comment and the keep.d inventory are all correct against the tree — pattern_ink is what head.ut:119`` emits and what header.ut's `FS_AXES` reads back, and both `/etc/footstrap` uploads are listed with matching symlinks in the uci-defaults script.
One functional finding inline, in the sysauth.ut block this revision rewrote: the new unconditional auth_message precedence fixes the second dispatcher branch but breaks the first one, where a wrong password on a 2FA router now shows only the plugin's boilerplate. Plus two nits. CI on 98201ff is green across all three FormalityCheck runs, so nothing here is CI-grounded.
Generated by Claude Code
`auth_message` is not "the credentials were accepted". The dispatcher's first branch copies it out of get_challenges() BEFORE the password is checked (dispatcher.uc:956), and that call answers with a message on every pending result -- the literal 'Additional verification required' when the plugin has none of its own (authplugins.uc:312). So on a router running luci-plugin-2fa both it and `fuser` are set whenever a password is rejected, and the message-first spelling this theme took from luci-theme-bootstrap then rendered only the plugin's boilerplate: the user is never told the password was wrong. The generic template's `auth_message && !fuser` gets that case right and the other one wrong -- on the OTP step the credentials were correct. `auth_plugin` separates the two dispatcher branches: it is set only in the second (dispatcher.uc:1018), i.e. exactly when session_setup() accepted the credentials. The credentials alert is now gated on !auth_plugin and the backend's message renders beside it rather than instead of it, so all four states are distinct. The credentials alert also moves to .alert-message.error, the danger variant bootstrap uses here, because once both can appear together an amber box for each reads a rejected password as a routine notice. Measured on owrt2512 (25.12.4/apk) and owrt2410 (24.10.8/opkg): the template compiles under `ucode -T -c` on all four dev routers, the four scopes render through LuCI's own loadfile/render path with the expected alerts and no throw for the absent auth_plugin, and a real wrong-password POST returns 403 with .alert-message.error on both package managers. Patching the dispatcher's sysauth scope reproduces the bug on the shipped spelling: wrong password with a challenge pending rendered no credentials error at all. Also in this commit, all found by the same review round on openwrt/luci#8903: * tools/axes.mjs now holds the window.__fsSD field name every axis reads, running the deriving factories' own formula lifted out of fs-prefs.js rather than restating it -- a restated copy stays green while the JS says something else, which was measured. surfaceAxis joins the key scan too (21 -> 25). * three stale comments corrected: the "Appearance -> Background image" label, propAxis's worked example, and fs-sheets.js's page-ownership rationale, which named a LuCI file that exists on none of the four dev routers. Re-measured against what actually injects a sheet there.
98201ff to
717de96
Compare
717de96 to
247891c
Compare
openwrt-ai
left a comment
There was a problem hiding this comment.
Reviewed the force-push 98201ff → 247891c.
All three threads from the last round are addressed and correct against the tree. sysauth.ut now renders the two alerts independently with the credentials one gated on !auth_plugin, which covers all four dispatcher states; the propAxis header comment matches the hyphen fold; and the keep.d / uci-defaults wording now uses the "Appearance -> Wallpaper -> File" spelling that fs-appearance.js actually builds.
The new work is a router-side webfont opt-in (font_sans / font_mono / fonts, the /etc/footstrap/fonts symlink and keep.d entry, a conditional fonts/fonts.css link and an unlayered <style>) plus one CSS narrowing. Two things I checked and found sound, since they are the parts most likely to be wrong: /etc/footstrap/fonts works as a directory in keep.d — sysupgrade's list_static_conffiles() passes the keep.d lines to find … \( -type f -o -type l \), which recurses — and the new <style data-fs-shell> cannot be mistaken for a view sheet or disturb the layer order, because VIEW_SHEETS exempts [data-fs-shell] on style as well as link and both new tags sit after the cascade.css anchor reassertLayerOrder() measures against. The .cbi-page-actions .cbi-dropdown:not(.btn):not(.cbi-button) narrowing also lines up with the real markup: luci.js:2197-2207 gives the Save & Apply combo cbi-dropdown btn cbi-button cbi-button-apply, so the reset no longer flattens it in the Apply unchecked state where .cbi-button-apply has dropped off.
One finding and two nits inline. CI on 247891c is green across all eight checks (three FormalityCheck runs, eslint, CodeQL, build / Test x86_64), so nothing here is CI-grounded.
Commit checks
- 247891c "luci-theme-footstrap: add new theme" — the message's font paragraph is now a description of only half of what the diff does. It says "The theme carries no webfonts: the font stacks name Manrope and JetBrains Mono first and the system stack after, so a machine with either installed uses it and one without falls through silently" — still true of the package contents, but this revision adds a router-side opt-in on top of that fallback: three new UCI options in
footstrap.settings(font_sans,font_mono,fonts) read byheader.ut/head.ut, a new/www/luci-static/footstrap/fontssymlink created by uci-defaults, a newkeep.dpath, and a conditional@font-facestylesheet link. A UCI contract and a new sysupgrade-preserved path are the kind of thing worth a sentence in the message, since the message is what a bisect or agit logsearch lands on. (The.cbi-page-actions .cbi-dropdownnarrowing is a detail, not worth a line.)
Generated by Claude Code
I feel exactly the same way. If a modern upstream gets merged I will use this instead of my current used theme https://github.com/jerrykuku/luci-theme-argon @VizzleTF Unless this is just a one-time "fire-and-forget" operation. Then I would say @jow- 👍 |
font_sans and font_mono are printed unescaped into one <style>, and the
charset whitelist has to admit both quote characters -- the shipped default
is `"Manrope",system-ui,...`. A quote does not END anything, it EXTENDS:
`font_sans=My"Font` opens a CSS string that runs to the end of the sheet and
swallows `; --fs-font-mono: ...; }` with it, so a router that set only the
mono font correctly lost it because of a typo in the other option.
Measured on owrt2512 with that value in place. Before: the element renders
`:root {--fs-font-sans: My"Font; --fs-font-mono: JetBrains Mono; }` as one
open string and neither property survives. After: the malformed value is
refused and `--fs-font-mono: JetBrains Mono` is printed alone, while
`"Manrope",system-ui` still renders in full. head.ut compiles under
`ucode -T -c` on all four dev routers and the behaviour was checked on both
package managers.
Also in this commit, from the same review round on openwrt/luci#8903:
* the webfont comments say what the package does -- read the three uci
options, serve /etc/footstrap/fonts, keep it across sysupgrade -- and where
the one-line installer lives, since it is in this repository and not in the
package: it names third-party font hosts, which the theme must not carry.
The manual path is spelled out beside it.
* fs-sheets.js's ownership example is corrected against the in-tree app: only
HexEditor's injector runs at module eval, the view's own sheet comes from
render(), and what makes either invasive is the bare selectors, not the
ones pinned to #file-manager-container.
Not fully, but my current reasoning is roughly:
So I guess it's 60% drop 2020, 40% drop OpenWrt classic for me. In the end I only use bootstrap, and bootstrap was the only theme I seriously spent effort in, so I am not emotionally attached to either 2020 or classic. |
openwrt-ai
left a comment
There was a problem hiding this comment.
Reviewed the force-push 0b99fa49 → 5a3d8730. Same base (1c70b2b), one commit. The message gained a paragraph on scroll anchoring and changed "its app icons" to "one app icon"; both describe hunks that are in the diff, so no commit-check notes. The delta is 282 added / 149 removed across eleven files.
All three threads from the last round are addressed. tokenPad is gone and git grep tokenPad now returns nothing in the package, with contentPad left carrying the fallback role on its own. --fs-content-max is in the model: the token resolves to 1280px, .fs-content is box-sizing: border-box (the * reset in @layer base), so max-width includes the gutter and Math.min(outerW - cut, contentMax) - contentPad is the right arithmetic — the old form answered ~2280 for a 1224px column at 2560px. And the router's contract-break line now names a URL that resolves from inside openwrt/luci.
The cascade.css delta is worth saying explicitly: I diffed it declaration by declaration, and every one of the 144 changed lines is 1px solid var(--fs-border) → var(--fs-hairline) or the field transition pair → var(--fs-field-transition). Nothing else moved, including the overflow-anchor: none on .table.fs-dt that the new anchoring code depends on.
The anchoring rewrite holds up on its two load-bearing choices. Asking CSS.supports('overflow-anchor', 'auto') rather than a browser name is the right shape, and the localStorage.fsEngineAnchor switch is what makes the WebKit branch reachable without a Mac. The hit test is a real improvement over the frame walk for the reason given — a poll tick that grows something inside the frame the fold cuts through leaves that frame's own top at drift 0 — and the [data-fs-chrome] step down past the sticky bar is safe on the elements that carry the mark: .fs-pattern is pointer-events: none, .fs-skip:not(:focus) is a 1×1 clip at left: 8px and #fs-nav-progress is pointer-events: none, so none of them can swallow the hit test at x = the centre of #view; in the desktop sidebar layout nav.fs-sidebar is position: static beside .fs-main, so it is never under that x either. _rest cannot leak a drifted reference into a correction: run() writes it before scheduleAnchor() sets _anchorPending, but a second mutation batch in that window is discarded by scheduleAnchor's own if (_anchorPending) return, and the rAF re-takes it after applyAnchor(). The > innerHeight + 200 clamp is the right guard for a subtree replacement.
The icon consolidation checks out: app-icon-512.png is a valid 512×512 PNG (indexed, 4679 bytes, down from 15709), nothing in the Makefile or root/ enumerates the two deleted files, and manifest.json still parses with one any maskable entry — which clears Chromium's installability bar, since that asks for one icon of 144px or larger rather than for a 192/512 pair. Pointing apple-touch-icon at the same 512 raster is fine; iOS scales it and never reads the manifest's array.
One finding and one nit inline, neither a merge blocker. The finding is the one worth a look: moving fs-overview out of the prologue also moved the guarantee that its three template globals exist before a view can render, and three comments in the tree still state that guarantee as a fact.
CI on 5a3d8730 is green across all eight checks, so nothing here is CI-grounded.
Generated by Claude Code
5a3d873 to
3dd9f2d
Compare
openwrt-ai
left a comment
There was a problem hiding this comment.
Reviewed the force-push 5a3d8730 → 3dd9f2de. Same base (1c70b2b), one commit, message byte-identical and still matching the diff, so no commit-check notes. The delta is 210 added / 71 removed across six files, and it is two themes: the last round's ordering finding, and a second front against the poll tick moving the page under the reader.
The ordering finding is addressed at the cause. The three template globals now live in menu-footstrap-common.js, which the footer requires on every page and which evaluates them at module scope — before wirePageModules() can require fs-overview and before the chrome wires the router, so the guarantee that progressbar/renderBox/renderBadge exist before any view can render is back, and it no longer depends on which of two require() chains wins. The typeof guards still make a full page load a no-op, so the template's own copies keep winning where they exist. fs-menutree.js and fs-router.js were repointed for the move; the file header of fs-overview.js was not (nit inline).
measureShell()'s third key term is right and the reasoning for it is the file's own: .fs-content carries no chrome mark, sheets.scopeToCurrentPage() flips foreign sheets on and off on every client navigation, and neither the width nor the density moves when it does — so a memo keyed on those two alone really would stay pinned at the previous page's gutter. body[data-page] is the one attribute the router always restamps, and it restamps it before the staged render, so the term is stamped by the time anything reads the memo on the incoming page.
Two findings and one nit inline. The one worth a look before merge is the by branch: the clamp receipt is guarded by a page stamp the router writes after it resets the scrollers, and across a promise boundary, so the forward-navigation reset sits inside the window where a clamp and a reset look identical. The other is swapContent(), which measures a height and restores the pin in the same statement sequence — no layout ever runs with the pin applied, so it cannot be doing the work its comment credits it with.
CI on 3dd9f2de: three FormalityCheck runs completed green, the rest not yet reported. Nothing failed, so nothing here is CI-grounded.
Generated by Claude Code
3dd9f2d to
407c9b7
Compare
A standalone theme for OpenWrt 24.10 and newer. It ships no CSS framework and depends on nothing but luci-base: the package is the server chrome (ucode templates), one stylesheet and a set of theme JS modules, while every page is still rendered by luci-base's own view JS. One chrome morphs between a collapsible sidebar and a top bar, chosen by the user and remembered client-side. Light and dark modes, a palette and a density axis are applied before the first paint, so a reload never flashes the previous colours. A menu search covers the rendered tree, and a client-side router swaps the view without a full document load, refusing to reuse a document an app's own stylesheet has invaded. Third-party luci-app-* packages are the constraint it is built around: the chrome is namespaced (fs-*, --fs-*, [data-fs-chrome]) and is defended by not matching an app's selectors, while .cbi-* and #view stay shared surfaces an app is entitled to win on. The theme's own settings page is drawn with stock .cbi-value rows, ui.Select and ui.RangeSlider. The stylesheet is generated from a layered source kept in the theme's own repository and committed here as one file, the way the other themes carry theirs. The theme carries no webfonts: the font stacks name Manrope and JetBrains Mono first and the system stack after, so a machine with either installed uses it and one without falls through silently. A router may name fonts of its own on top of that fallback, through three UCI options in footstrap.settings that the templates read back: font_sans and font_mono are font-family stacks printed into an unlayered <style>, and `fonts` is the md5 of an @font-face sheet the admin installs under /etc/footstrap/fonts, which uci-defaults links under /www and keep.d preserves across sysupgrade. The package installs no faces and fetches nothing at run time; it only serves what is already there. A web manifest and one app icon ship with the theme, so the interface can be installed to a phone's home screen. Both are static files — a theme may not register a dispatcher node — which fixes start_url at uhttpd's default /cgi-bin/luci/ and the splash colour at the default palette's; the manifest is served as .json because uhttpd's compiled-in MIME map has no entry for .webmanifest. The client router looks up every luci-base surface it calls before it wires anything, and on a miss logs which name is gone and stays off, leaving the plain server-dispatched interface rather than a half-working client one. Where the browser has no scroll anchoring of its own, the theme keeps the reader's place itself: a poll tick that changes the height of anything above the reader moves the page under them on WebKit, which never implemented it. The capability decides, never a browser name, so where the engine already anchors, this stays out of the way and nothing is corrected twice. The two page-specific modules are required on the pages that use them rather than on every page. Signed-off-by: Ivan Kvashonkin <vizzlef@gmail.com>
407c9b7 to
f3f0ab7
Compare
|
Based on your comment:
I suggest that we
Ps. The AI based tweaking seems to be continued forever, so getting all minor points addressed like a never-ending story. Let's merge it now. |
@hnyman i got reviews by users and fix small SPA bugs on some browsers (safari, firefox) - thats why its looks like that. |
@castillofrancodamian did it |
|
I merged this in. |
|
@VizzleTF Your current uci-defaults file is quite verbose and makes lots of cleanup actions based on assumption that there might have been old Footstrap versions. In the next few weeks (by mid-September or so), you should clean up the uci-defaults file in the main LuCI repo, and start from assumption that the users of the officially downloadable package have started from the current now published first version. There may naturally be a few old initial early adopters / test users, but even most of them will have upgraded to the new "official" version by then. So, please cleanup and shorten the uci-defaults file to be more in line with the other themes, and remove/shorten most of the verbose commentary. |
luci-theme-openwrt-2020 is one colour scheme and no dark mode: the CI cyan #00B5E2 on the navy #002B49, white content, and #5CB85C / #CC8800 / #CC1111 for the semantic three. This adds that identity to footstrap as a palette, which is the form suggested in the discussion on #8903 for keeping the look if the theme itself is retired. The pair splits the work along the reason it exists. Dark IS 2020's own scheme — the navy is the canvas and the cyan is nearly untouched. Light keeps the hue and darkens it, because #00B5E2 measures 2.09:1 on white, and every level of this theme's exported colour tier has to pass WCAG AA as text on all three surfaces: apps read those names as color: about as often as background:. The semantic three move for the same reason — on white 2020's green is 2.28:1 and its amber 3.42:1 — while its red at 5.25:1 is kept where it was. The palette is registered in the four places the theme requires: the palette axis in fs-prefs.js, the server-default whitelist and the pre-paint switch in partials/head.ut, and the label in fs-appearance.js. It is opt-in through Appearance; nothing changes for anyone who does not pick it. Contrast was measured across the whole matrix rather than by eye: 56 palette x mode x tint combinations, 4352 checks, every level clear of AA on background, panel and panel2, and every ink clear on the fill it sits on. axe-core reports no serious or critical violations on the widget gallery in either mode. Signed-off-by: Ivan Kvashonkin <vizzlef@gmail.com>
luci-theme-openwrt-2020 is one colour scheme and no dark mode: the CI cyan #00B5E2 on the navy #002B49, white content, and #5CB85C / #CC8800 / #CC1111 for the semantic three. This adds that identity to footstrap as a palette, which is the form suggested in the discussion on openwrt#8903 for keeping the look if the theme itself is retired. The pair splits the work along the reason it exists. Dark IS 2020's own scheme — the navy is the canvas and the cyan is nearly untouched. Light keeps the hue and darkens it, because #00B5E2 measures 2.09:1 on white, and every level of this theme's exported colour tier has to pass WCAG AA as text on all three surfaces: apps read those names as color: about as often as background:. The semantic three move for the same reason — on white 2020's green is 2.28:1 and its amber 3.42:1 — while its red at 5.25:1 is kept where it was. The palette is registered in the four places the theme requires: the palette axis in fs-prefs.js, the server-default whitelist and the pre-paint switch in partials/head.ut, and the label in fs-appearance.js. It is opt-in through Appearance; nothing changes for anyone who does not pick it. Contrast was measured across the whole matrix rather than by eye: 56 palette x mode x tint combinations, 4352 checks, every level clear of AA on background, panel and panel2, and every ink clear on the fill it sits on. axe-core reports no serious or critical violations on the widget gallery in either mode. Signed-off-by: Ivan Kvashonkin <vizzlef@gmail.com>
|
@VizzleTF clicked back through all pages on v0.14 and few comments. First some compliments: love the Status -> Overview layout. Love the "Port status" icons just being green lights rather than icons. Love the OpenWrt 2020 colorway option as homage. Just a few suggestions for improvement (observed using Chrome 151):
Fun idea if you get time: "Forum" palette, which would match the openwrt forum colorway (e.g. blue bar at the top, dark grey bg, white text, etc). Again, congrats on the merge! Take care. |
|
Thanks for the detailed list — went through all four on a test router. 1 and 4 were mine and are fixed — both on luci-base classes, so every app gets it. For anything further: either here, tagging me, or — preferred — an issue at https://github.com/VizzleTF/luci-theme-footstrap/issues |
Because it has no section ( bare ui.Textarea) Give any block 16px gap in .cbi-map - will be delivered in next PR (or 0.14.2 from my repo) |
If you feel that the more correct fix would be to fix the irqbalance app itself to have a section around the textarea, please propose it in the same PR in a separate commit. Not all LuCI apps are perfect... |
|
@hnyman if you like it i can send it: |
|
@VizzleTF I installed v0.14.2, issues 1, 3, and 4 are resolved, nice fixes! Having the router hostname in the browser tab is a great addition too. Regarding my issue 2 with the button disappearing - it's still happening, even in Incognito (clean browser cache). Strangly it doesn't always disappear, only sometimes. Router: GL-MT6000 Attempt to reproduce by going to: System -> System -> Footstrap: change the Palette or Density from dropdown then click Save (not Save & Apply, just Save), the page refreshes then the Footstrap tab button is gone, until you click System again to refresh it. Example below: iPhone, using 2020 palette, I switch to Bootstrap palette from the dropdown, hit Save at the bottom, and then then Footstrap button disappears: |
|
Regarding the irqbalance and your comment:
Please place the commit somewhere available, or just do a separate PR about it, so that I could test your idea. The commit(s) obviously develop the app from the current status, by splitting the IRQs table by IRQ nature, right? |
Saving on System -> System redraws the map: the old tab group goes, a new one is built, and ui.tabs marks it ready by setting an attribute. The theme's observer watched childList only, so when that attribute landed after the last change to the group's children, the mount had already returned with no group to attach to and nothing woke it again -- the tab was missing until the next navigation. Reported on 25.12.5 from Chrome and from iOS as "sometimes it disappears after Save" (openwrt#8903). Modelled as a deterministic race: remove the pane, drop data-initialized, restore it 400ms later with no other mutation. Three failures out of three before, three passes out of three after, on 25.12 and 24.10. The observer now watches that attribute, and a miss retries on a widening delay, since the attribute alone would still rely on ui.tabs setting it that way. The sliders on that tab also drop a calcunits option they passed to ui.RangeSlider: the widget renders that span only when a calculate function produced a value, and no axis here passes one. Signed-off-by: Ivan Kvashonkin <vizzlef@gmail.com>
Saving on System -> System redraws the map: the old tab group goes, a new one is built, and ui.tabs marks it ready by setting an attribute. The theme's observer watched childList only, so when that attribute landed after the last change to the group's children, the mount had already returned with no group to attach to and nothing woke it again -- the tab was missing until the next navigation. Reported on 25.12.5 from Chrome and from iOS as "sometimes it disappears after Save" (openwrt#8903). Modelled as a deterministic race: remove the pane, drop data-initialized, restore it 400ms later with no other mutation. Three failures out of three before, three passes out of three after, on 25.12 and 24.10. The observer now watches that attribute, and a miss retries on a widening delay, since the attribute alone would still rely on ui.tabs setting it that way. The sliders on that tab also drop a calcunits option they passed to ui.RangeSlider: the widget renders that span only when a calculate function produced a value, and no axis here passes one. Signed-off-by: Ivan Kvashonkin <vizzlef@gmail.com>







Pull request details
Description
Add Footstrap, a standalone theme for OpenWrt 24.10 and newer. It depends on
luci-baseand nothing else and ships no CSS framework; pages are rendered by luci-base's own view JS..cbi-valuerows,ui.Selectandui.RangeSlider.Developed at https://github.com/VizzleTF/luci-theme-footstrap
Navigation is client-side: a click swaps the view rather than reloading the document, so a page opens without the full-load round trip. Measured against bootstrap on a Netcore N60 Pro running 25.12.2, five runs, medians:
Method and per-page results:
https://github.com/VizzleTF/luci-theme-footstrap/blob/main/docs/benchmark.md
Discussed on the forum since July:
https://forum.openwrt.org/t/footstrap-new-theme-for-luci-2x-faster-than-bootstrap/251930
Screenshot or video of changes (if applicable)
Desktop
Mobile
Maintainer (preferred)
@VizzleTF
Tested on
OpenWrt version: OpenWrt 25.12.4 and OpenWrt 24.10.8 (aarch64_generic containers), plus OpenWrt 25.12.2 (r32802-f505120278) on a Netcore N60 Pro
LuCI version: this branch, built with the x86_64 master and 24.10 SDKs
Web browser(s): Chromium 151, Firefox 145, Safari 26
And a single release is downloaded 200–240 times