mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-09-10 18:34:18 +08:00
🌴 Sync 2026-08-05 03:17:09
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
#
|
||||
# Copyright (C) 2026
|
||||
#
|
||||
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-theme-footstrap
|
||||
# luci.mk keys the Build/Prepare hook name on LUCI_NAME, which defaults to the checkout's
|
||||
# directory name — a differently-named checkout symlinked into the feed would silently skip
|
||||
# the CSS build. Pin it.
|
||||
LUCI_NAME:=luci-theme-footstrap
|
||||
|
||||
# Version is git-derived; never hardcode PKG_VERSION. CI injects FOOTSTRAP_VERSION from the
|
||||
# tag (an SDK build has no .git, so it cannot derive one).
|
||||
FOOTSTRAP_VERSION?=
|
||||
ifneq ($(FOOTSTRAP_VERSION),)
|
||||
PKG_VERSION:=$(FOOTSTRAP_VERSION)
|
||||
PKG_RELEASE:=1
|
||||
endif
|
||||
|
||||
LUCI_TITLE:=Footstrap Theme
|
||||
# +luci-base is the WHOLE list. The self-updater used to hard-require `curl`, which is NOT in
|
||||
# OpenWrt's default package set (the base image ships uclient-fetch), so the update button
|
||||
# failed on a stock router; it falls back to uclient-fetch rather than pull curl onto an 8 MB
|
||||
# device for one API call. jsonfilter and sha256sum ARE in the base image. Do not add a
|
||||
# runtime dep for a convenience tool — fall back instead.
|
||||
LUCI_DEPENDS:=+luci-base
|
||||
LUCI_PKGARCH:=all
|
||||
# Else luci.mk defaults these to LuCI's own, and the package claims MAINTAINER "OpenWrt LuCI
|
||||
# community" / URL openwrt/luci.
|
||||
LUCI_MAINTAINER:=VizzleTF <vizzletf47@gmail.com>
|
||||
LUCI_URL:=https://github.com/VizzleTF/luci-theme-footstrap
|
||||
|
||||
# CSS: ship verbatim. luci.mk would run csstidy over it, which is old enough to mangle
|
||||
# :has()/color-mix()/nested calc() and break the layout. build-css.sh minifies instead.
|
||||
LUCI_MINIFY_CSS:=0
|
||||
#
|
||||
# JS: TWO minify paths, chosen by who is building.
|
||||
#
|
||||
# CI (the released packages) pre-minifies with terser BEFORE the SDK build (tools/minify-js.mjs:
|
||||
# mangles top-level identifiers too, which jsmin cannot — ~41 KB against jsmin's ~57 KB, −27%)
|
||||
# and signals it with FOOTSTRAP_PREMIN=1. jsmin must then stay AWAY from the already-minified
|
||||
# output: terser legitimately emits `return/^v/.test(s)`, the exact one-character-lookback trap
|
||||
# below, so LUCI_MINIFY_JS goes to 0 for that build.
|
||||
#
|
||||
# Everyone else (an SDK user, the buildbot — no node) builds the untouched source and KEEPS
|
||||
# luci.mk's default jsmin (LUCI_MINIFY_JS=1): ~105 KB of this tree's JS is comments, and uhttpd
|
||||
# serves /www with NO compression, so those are wire AND flash bytes either way.
|
||||
#
|
||||
# The catch on the jsmin path, and why the gates exist: jsmin decides `/` = regex-or-division
|
||||
# from a ONE-character lookback, and `n` (of `return`) and `>` (of `=>`) are not on its
|
||||
# allow-list — so `return /re/` makes it eat the rest of the file AND EXIT 0
|
||||
# (openwrt/luci#8299). eslint's `wrap-regex` bans the shape in the SOURCE; tools/jsmin-verify.mjs
|
||||
# proves jsmin's output is TOKEN-IDENTICAL to it. Both keep guarding the non-CI path.
|
||||
FOOTSTRAP_PREMIN?=
|
||||
ifneq ($(FOOTSTRAP_PREMIN),)
|
||||
LUCI_MINIFY_JS:=0
|
||||
endif
|
||||
|
||||
# Apache-2.0, and not a free choice: styles/base began as a fork of luci-theme-bootstrap's
|
||||
# cascade.css, the ucode templates derive from LuCI's own, and a few JS helpers are verbatim
|
||||
# copies. The notices travel with it.
|
||||
#
|
||||
# THE OFL-1.1 HALF IS GONE WITH THE WEBFONTS. The theme carried subsetted Manrope and JetBrains
|
||||
# Mono and had to ship the OFL text beside them (§2 requires the notice and licence with every
|
||||
# copy of the Font Software). It ships no Font Software now, so declaring OFL would be a false
|
||||
# statement about the package's contents.
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
|
||||
# /etc/config/footstrap is SHIPPED as an empty stub and WRITTEN AT RUNTIME: Appearance -> "Save as
|
||||
# default" has rpcd uci-set the router-wide axes into that very file (fs-prefs.js saveAsDefault()).
|
||||
# Without this define the package manager owns it as an ordinary file and REPLACES it on upgrade —
|
||||
# so the admin's saved defaults were wiped by the theme's own one-click Update, silently, reported
|
||||
# as success. Measured on the dev router: eight options in the live file, package-owned, no
|
||||
# .conffiles entry beside base-files'/dnsmasq's. OpenWrt honours this for BOTH formats
|
||||
# (include/package-pack.mk: KEEP_$(1) -> apk .conffiles, ipk CONTROL/conffiles), so one define
|
||||
# covers 24.10's opkg and 25.12's apk alike. Any future root/etc/config/* must be listed here too.
|
||||
define Package/luci-theme-footstrap/conffiles
|
||||
/etc/config/footstrap
|
||||
endef
|
||||
|
||||
# RELOAD, NOT 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`; deleting our
|
||||
# acl.d file + `reload` flips `session access` for the self-update script from true to false.
|
||||
define Package/luci-theme-footstrap/postinst
|
||||
#!/bin/sh
|
||||
[ -n "$${IPKG_INSTROOT}" ] || {
|
||||
# uci-defaults registers the theme; refresh rpcd + drop caches so LuCI sees it without a
|
||||
# reboot. Calling it ourselves is belt-and-braces: OpenWrt's default_postinst also runs
|
||||
# (then deletes) every /etc/uci-defaults/* we ship, so it executes twice per install. It is
|
||||
# idempotent, and its fresh-vs-upgrade marker is written at the end of the first pass, so
|
||||
# that pass still sees a fresh install.
|
||||
[ -f /etc/uci-defaults/30_luci-theme-footstrap ] && \
|
||||
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
|
||||
}
|
||||
exit 0
|
||||
endef
|
||||
|
||||
define Package/luci-theme-footstrap/postrm
|
||||
#!/bin/sh
|
||||
# opkg runs the OLD package's postrm with arg "upgrade" during a version upgrade (proven on 24.10:
|
||||
# `prerm upgrade`, then `postrm upgrade`, then the new `postinst configure`) and "remove" on a real
|
||||
# removal. On upgrade this script MUST change nothing: reverting mediaurlbase to bootstrap, wiping
|
||||
# the theme registration and deleting the .installed marker here is what flipped every updating
|
||||
# 24.10 user back to bootstrap — and it defeated uci-defaults' own upgrade guard, because with the
|
||||
# marker gone uci-defaults treated the run as "fresh", yet postrm had already set mediaurlbase to
|
||||
# bootstrap, which no "fresh" branch re-activates. apk never runs this on upgrade (it uses the new
|
||||
# package's pre/post-upgrade), so guarding on the arg is correct for both managers; real removal
|
||||
# passes "remove" (opkg) or no arg and proceeds below.
|
||||
case "$$1" in *upgrade*) exit 0 ;; esac
|
||||
[ -n "$${IPKG_INSTROOT}" ] || {
|
||||
# Every theme name this package has ever registered. postrm runs when uci-defaults is
|
||||
# already deleted, so it cannot source the list: it is duplicated by necessity and
|
||||
# mirror-pinned so it cannot drift. Only the assignment is byte-identical — the `$$` is
|
||||
# make's escaping.
|
||||
# @mirror theme/legacy-names
|
||||
LEGACY_THEMES="Footstrap FootstrapDark FootstrapLight FootstrapTop FootstrapTopDark FootstrapTopLight FootstrapSidebar FootstrapOnTop"
|
||||
# @endmirror
|
||||
for t in $$LEGACY_THEMES; do
|
||||
uci -q delete "luci.themes.$$t"
|
||||
done
|
||||
# The router's DEFAULT layout, set by uci-defaults when migrating an old top-nav install.
|
||||
# It means nothing to any other theme, and left behind it would silently re-apply the top
|
||||
# bar on a later reinstall.
|
||||
uci -q delete luci.main.footstrap_layout
|
||||
# Don't leave the active theme pointing at the media dir we just removed. The same TWO-part
|
||||
# check uci-defaults uses: a theme needs its media dir AND its ucode template to render, so
|
||||
# a one-part check could hand the UI to a half-removed bootstrap — the blank page this
|
||||
# branch exists to avoid.
|
||||
case "$$(uci -q get luci.main.mediaurlbase)" in
|
||||
/luci-static/footstrap*)
|
||||
[ -d /www/luci-static/bootstrap ] && \
|
||||
[ -f /usr/share/ucode/luci/template/themes/bootstrap/header.ut ] && \
|
||||
uci set luci.main.mediaurlbase=/luci-static/bootstrap ;;
|
||||
esac
|
||||
uci commit luci
|
||||
# The "installed before" marker uci-defaults writes to tell fresh from upgrade. Removing it
|
||||
# makes uninstall-then-reinstall count as fresh again.
|
||||
rm -rf /usr/share/luci-theme-footstrap >/dev/null 2>&1 || true
|
||||
# The admin-uploaded login background (kept out of the package on purpose, so it survives an
|
||||
# upgrade). A real removal is the one time it should go — this branch never runs on upgrade.
|
||||
rm -rf /etc/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 postinst note: reload keeps sessions
|
||||
}
|
||||
endef
|
||||
|
||||
# Runs right after luci.mk copies luasrc/ucode/htdocs/root/src into PKG_BUILD_DIR, so it
|
||||
# rewrites the build copy, never the source tree.
|
||||
#
|
||||
# 1. cascade.css is generated, not committed — and styles/ is not in luci.mk's copy list, so
|
||||
# build-css.sh reads it from $(CURDIR) and writes into the build tree. cat/awk only, no host
|
||||
# toolchain: that is why it runs on an OpenWrt buildbot.
|
||||
# 2. Stamp the git-derived version into the theme JS (fs-version.js — the string the Appearance tab
|
||||
# shows). Skipped when PKG_VERSION is empty, leaving '0.0.0-dev'.
|
||||
#
|
||||
# THE CATALOGUE IS luci.mk's BUSINESS, and nothing here compiles it. `po/` is the directory
|
||||
# LUCI_LANGUAGES globs, so luci.mk emits one `luci-i18n-footstrap-<lang>` package per language the
|
||||
# way it does for every luci-app — which is what a package IN THE LUCI TREE has to look like, and
|
||||
# what Weblate can see (it translates `po/`, and only `po/`).
|
||||
#
|
||||
# It was `i18n/` here for a while, with a po2lmo loop in this hook bundling the catalogue into the
|
||||
# theme package, because a multi-package release was mis-picked by a self-updater that resolved the
|
||||
# theme by name and took `head -1` (issue #6). That updater is retired and the release is built by
|
||||
# owfeed, which packages this theme as exactly one artifact per format regardless of what luci.mk
|
||||
# would do — so the constraint that bought the rename is gone, and the cost of keeping it (a
|
||||
# catalogue invisible to the project's own translation platform) is not.
|
||||
define Build/Prepare/luci-theme-footstrap
|
||||
# luci.mk's Build/Prepare copies only src/ luasrc/ htdocs/ root/ ucode/ into
|
||||
# $(PKG_BUILD_DIR), and PKG_LICENSE_FILES resolves against THAT — so the Apache text has to
|
||||
# be put there by hand or the declaration points at nothing.
|
||||
$(CP) $(CURDIR)/LICENSE $(PKG_BUILD_DIR)/
|
||||
$(SHELL) $(CURDIR)/build-css.sh $(PKG_BUILD_DIR)/htdocs/luci-static/footstrap/cascade.css
|
||||
# The private `--fs-*` names are 16% of the sheet and mean nothing to a browser — the same trade
|
||||
# terser makes for the JS. BEFORE strip-templates.sh on purpose: the reserved set is derived by
|
||||
# reading the JS and the templates, so it must see them whole. Over-reserving costs bytes,
|
||||
# under-reserving breaks the theme silently.
|
||||
# The reserved set is read from $(CURDIR), the SOURCE, never from $(PKG_BUILD_DIR): in CI the
|
||||
# build tree's JS has already been through terser, so its comments are gone and five names that
|
||||
# are only MENTIONED in a comment stop being reserved. That made the shipped sheet depend on WHO
|
||||
# built it — 10 reserved names via CI, 15 via a plain SDK build, same source. Reading the source
|
||||
# over-reserves by ~1 KB and is the safe direction.
|
||||
$(SHELL) $(CURDIR)/mangle-tokens.sh \
|
||||
$(PKG_BUILD_DIR)/htdocs/luci-static/footstrap/cascade.css \
|
||||
$(CURDIR)/htdocs/luci-static/resources $(CURDIR)/ucode
|
||||
# Templates are 58% comments and shipped them all. jsmin/terser strip the JS, build-css.sh the
|
||||
# CSS; the .ut files were simply never included in that trade. Only `{# … #}` goes — see the
|
||||
# script for why the ucode-code `/* … */` deliberately stays. -16 KB of 39, git keeps every word,
|
||||
# and dev-sync.sh does NOT run this: a router you are debugging on keeps its comments.
|
||||
$(SHELL) $(CURDIR)/strip-templates.sh $(PKG_BUILD_DIR)/ucode
|
||||
# …and the same for the shell under root/ (71% and 95% comment lines). Whole-line `#` only.
|
||||
$(SHELL) $(CURDIR)/strip-shell.sh $(PKG_BUILD_DIR)/root
|
||||
$(SED) "s#const FS_VERSION *= *'[^']*'#const FS_VERSION = '$(if $(PKG_VERSION),$(PKG_VERSION),$(PKG_SRC_VERSION))'#" \
|
||||
$(PKG_BUILD_DIR)/htdocs/luci-static/resources/fs-version.js
|
||||
endef
|
||||
|
||||
# Absolute, not a relative path: CI rsyncs this package into package/, not into the feed.
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# THE LINE BELOW IS LOAD-BEARING AND IT IS NOT A SIGNATURE — do not delete it as boilerplate.
|
||||
#
|
||||
# include/scan.mk builds the package list by GREPPING the Makefiles, not by parsing them:
|
||||
# find -L package -name Makefile | xargs grep -aHE 'call (Build/DefaultTargets|BuildPackage|KernelPackage)'
|
||||
# A Makefile that does not match is not in the list, so it is never dumped, no
|
||||
# CONFIG_PACKAGE_* symbol is emitted for it, and `make package/<name>/compile` answers
|
||||
# "No rule to make target" — with no error naming the package anywhere in the build.
|
||||
#
|
||||
# This theme never calls BuildPackage itself; luci.mk does, at the include above. The grep
|
||||
# cannot see that. So the only thing that puts this package into the SDK's list is the literal
|
||||
# text on the next line — which is why every luci-* Makefile carries it.
|
||||
# Deleting it as a useless comment is exactly what broke the build (both formats, silently).
|
||||
# tools/scan-marker.sh re-derives the grep from scan.mk and fails the build if it goes missing.
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
||||
Reference in New Issue
Block a user