fix(luci-theme-secubox): Add ucode templates for LuCI 24.10 compatibility

- Add header.ut and footer.ut ucode templates (required by modern LuCI)
- Remove old Lua templates (incompatible with OpenWrt 24.10)
- Add mobile.css for responsive styling
- Update UCI defaults to register theme in luci.themes section
- Bump PKG_RELEASE to 3

The theme now properly loads via LuCI's theme system with:
- CRT P31 phosphor green cascade.css
- crt-engine.js for scanline effects
- Proper ucode template integration

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-03-26 07:29:55 +01:00
parent 1140221f4a
commit 5294d26375
5 changed files with 238 additions and 5 deletions

View File

@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-theme-secubox
PKG_VERSION:=1.0.0
PKG_RELEASE:=2
PKG_RELEASE:=3
PKG_MAINTAINER:=Gerald KERMA <devel@cybermind.fr>
PKG_LICENSE:=MIT
@ -26,9 +26,9 @@ define Package/luci-theme-secubox/install
# KISS theme helper for individual modules
$(INSTALL_DIR) $(1)/www/luci-static/resources/secubox
$(CP) ./htdocs/luci-static/resources/secubox/* $(1)/www/luci-static/resources/secubox/
# Lua view templates
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/view/themes/secubox
$(CP) ./luasrc/luci/view/themes/secubox/* $(1)/usr/lib/lua/luci/view/themes/secubox/
# Ucode templates (required for LuCI theme selection)
$(INSTALL_DIR) $(1)/usr/share/ucode/luci/template/themes/secubox
$(CP) ./ucode/luci/template/themes/secubox/*.ut $(1)/usr/share/ucode/luci/template/themes/secubox/
# UCI defaults
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) ./root/etc/uci-defaults/90-luci-theme-secubox $(1)/etc/uci-defaults/

View File

@ -0,0 +1,141 @@
/* SecuBox CRT P31 Theme - Mobile Styles */
/* Mobile header */
header h3 a, header .brand {
display: none !important;
}
@media screen and (max-device-width: 600px) {
.modal {
margin: 1.5em auto;
}
/* Table responsiveness */
.table {
display: flex;
flex-direction: column;
width: 100%;
}
.tr {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: flex-end;
border-top: 1px solid var(--p31-ghost);
margin: 0 -3px;
padding: 5px 0;
}
.table .th, .table .td, .table .tr::before {
flex: 1 1 50%;
align-self: flex-start;
overflow: hidden;
text-overflow: ellipsis;
word-wrap: break-word;
display: inline-block;
border-top: none;
box-sizing: border-box;
padding: 3px;
}
/* Column sizing */
.col-1 { flex: 1 1 30px !important; }
.col-2 { flex: 2 2 60px !important; }
.col-3 { flex: 3 3 90px !important; }
.col-4 { flex: 4 4 120px !important; }
.col-5 { flex: 5 5 150px !important; }
.col-6 { flex: 6 6 180px !important; }
/* Form controls */
input, textarea, select, .cbi-dropdown > ul > li {
font-size: 16px !important;
height: auto;
}
select, input[type="text"], input[type="password"] {
width: 100%;
height: 30px;
}
/* Buttons */
button, .btn, .cbi-button {
font-size: 14px !important;
padding: 0 8px;
}
/* Hide elements */
.hide-sm, .hide-xs {
display: none !important;
}
/* CBI values */
.cbi-value {
padding-bottom: .5em;
border-bottom: 1px solid var(--p31-ghost);
margin-bottom: .5em;
display: block;
align-items: baseline;
}
.cbi-value label.cbi-value-title {
font-weight: 700;
}
.cbi-value-field, .cbi-select, .cbi-dynlist {
width: 100%;
margin: 0;
}
/* Header nav */
header > .fill > .container {
display: flex;
flex-direction: row;
}
header .nav {
flex: 3 3 80%;
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
margin: 2px 5px 2px 0;
}
header .nav a {
padding: 2px 6px;
}
header .pull-right {
flex: 0 1 20%;
display: flex;
flex-direction: column;
justify-content: space-around;
margin: .2em 5px .2em auto;
padding: 0;
}
/* Table titles */
.tr.table-titles, .cbi-section-table-titles, .cbi-section-table-descr {
display: none;
}
}
@media screen and (max-device-width: 375px) {
.cbi-page-actions {
display: flex;
justify-content: space-between;
margin: 0 -1px;
padding: 0;
}
.cbi-page-actions button {
overflow: hidden;
text-overflow: ellipsis;
}
.cbi-page-actions .cbi-button {
flex: 1;
line-height: 2em;
margin: 1px !important;
}
}

View File

@ -1,8 +1,9 @@
#!/bin/sh
# SecuBox CRT P31 Theme - UCI Defaults
# Set SecuBox theme as default LuCI theme
# Register and set SecuBox theme as default LuCI theme
uci -q batch <<-EOF
set luci.themes.SecuBox='/luci-static/secubox'
set luci.main.mediaurlbase='/luci-static/secubox'
commit luci
EOF

View File

@ -0,0 +1,20 @@
{% if (!blank_page): %}
</div>
<footer class="crt-footer">
<span>
Powered by
<a href="https://github.com/CyberMindTech/secubox" target="_blank" rel="noreferrer">
SecuBox</a>
/
<a href="https://github.com/openwrt/luci" target="_blank" rel="noreferrer">
{{ version.luciname }} ({{ version.luciversion }})</a>
/
<a href="{{ entityencode(version.disturl ?? '#', true) }}" target="_blank" rel="noreferrer">
{{ version.distname }} {{ version.distversion }}</a>
</span>
<ul class="breadcrumb pull-right" id="modemenu" style="display:none"></ul>
</footer>
<script>L.require('menu-bootstrap')</script>
{% endif %}
</body>
</html>

View File

@ -0,0 +1,71 @@
{#
SecuBox CRT P31 Phosphor Theme - Header Template
CyberMind - SecuBox - 2026
Licensed under MIT
-#}
{%
import { getuid, getspnam } from 'luci.core';
const boardinfo = ubus.call('system', 'board');
http.prepare_content('text/html; charset=UTF-8');
-%}
<!DOCTYPE html>
<html lang="{{ dispatcher.lang }}" data-secubox-theme="crt-p31">
<head>
<meta charset="utf-8">
<title>{{ striptags(`${boardinfo.hostname ?? '?'}${node ? ` - ${node.title}` : ''}`) }} - SecuBox</title>
<meta name="viewport" content="initial-scale=1.0">
<link rel="stylesheet" href="{{ media }}/cascade.css">
<link rel="stylesheet" media="only screen and (max-device-width: 854px)" href="{{ media }}/mobile.css" />
{% if (node?.css): %}
<link rel="stylesheet" href="{{ resource }}/{{ node.css }}">
{% endif %}
{% if (css): %}
<style title="text/css">{{ css }}</style>
{% endif %}
<script src="{{ dispatcher.build_url('admin/translations', dispatcher.lang) }}"></script>
<script src="{{ resource }}/cbi.js"></script>
<script src="{{ media }}/crt-engine.js"></script>
<script src="/luci-static/resources/secubox/secubox-auth-hook.js"></script></head>
<body class="lang_{{ dispatcher.lang }} {{ entityencode(striptags(node?.title ?? ''), true) }} crt-p31-theme" data-page="{{ entityencode(join('-', ctx.request_path ?? []), true) }}">
{% if (!blank_page): %}
<header class="crt-header">
<a class="brand" href="/">{{ striptags(boardinfo.hostname ?? '?') }}</a>
<ul class="nav" id="topmenu" style="display:none"></ul>
<div id="indicators" class="pull-right"></div>
</header>
<div id="maincontent" class="container">
{% if (getuid() == 0 && getspnam('root')?.pwdp === ''): %}
<div class="alert-message warning">
<h4>{{ _('No password set!') }}</h4>
<p>{{ _('There is no password set on this router. Please configure a root password to protect the web interface.') }}</p>
{% if (dispatcher.lookup("admin/system/admin")): %}
<div class="right"><a class="btn" href="{{ dispatcher.build_url("admin/system/admin") }}">{{ _('Go to password configuration...') }}</a></div>
{% endif %}
</div>
{% endif %}
{% if (boardinfo.rootfs_type == "initramfs"): %}
<div class="alert-message warning">
<h4>{{ _('System running in recovery (initramfs) mode.') }}</h4>
<p>{{ _('No changes to settings will be stored and are lost after rebooting. This mode should only be used to install a firmware upgrade') }}</p>
{% if (dispatcher.lookup("admin/system/flash")): %}
<div class="right"><a class="btn" href="{{ dispatcher.build_url("admin/system/flash") }}">{{ _('Go to firmware upgrade...') }}</a></div>
{% endif %}
</div>
{% endif %}
<noscript>
<div class="alert-message warning">
<h4>{{ _('JavaScript required!') }}</h4>
<p>{{ _('You must enable JavaScript in your browser or LuCI will not work properly.') }}</p>
</div>
</noscript>
<div id="tabmenu" style="display:none"></div>
{% endif %}