diff --git a/luci-app-guest-wifi/Makefile b/luci-app-guest-wifi/Makefile index 3064d53f..22df899c 100644 --- a/luci-app-guest-wifi/Makefile +++ b/luci-app-guest-wifi/Makefile @@ -1,13 +1,19 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-guest-wifi +PKG_MAINTAINER:=kenzok8 PKG_VERSION:=2.0.1 -PKG_RELEASE:=1 +PKG_RELEASE:=2 LUCI_TITLE:=LuCI support for guest-wifi LUCI_DEPENDS:=+luci-base +luci-compat LUCI_PKGARCH:=all +LUCI_DESCRIPTION:=Simple guest WiFi configuration interface for LuCI + +define Package/$(PKG_NAME)/conffiles +/etc/config/wireless +endef include $(TOPDIR)/feeds/luci/luci.mk -# call BuildPackage - OpenWrt buildroot signature \ No newline at end of file +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-guest-wifi/README.md b/luci-app-guest-wifi/README.md index 6abbbbd7..def7b15d 100644 --- a/luci-app-guest-wifi/README.md +++ b/luci-app-guest-wifi/README.md @@ -1 +1,77 @@ -# luci-app-guest-wifi \ No newline at end of file +# luci-app-guest-wifi + +适用于 OpenWrt/LuCI 的访客 WiFi 配置插件。 + +## 功能特性 + +- **访客网络配置**: 通过 Web 界面配置独立的访客无线网络 +- **加密选项**: 支持无加密、WPA2-PSK、WPA3-SAE、WPA2/WPA3 混合模式 +- **AP 隔离**: 可选的客户端隔离功能,防止访客设备之间互相访问 +- **自动生效**: 保存配置后自动重新加载无线设置 + +## 依赖 + +- `luci` +- `luci-base` +- `luci-compat` (用于兼容旧版 LuCI CBI 模型) + +## 安装 + +```bash +# 添加 feed +echo 'src-git guestwifi https://github.com/kenzok78/luci-app-guest-wifi' >> feeds.conf.default +./scripts/feeds update -a +./scripts/feeds install -a -p guestwifi + +# 编译 +make package/luci-app-guest-wifi/compile V=s +``` + +## 使用说明 + +1. 访问 OpenWrt Web 管理界面 → 网络 → 访客WiFi +2. 添加访客 WiFi 配置段(如果没有自动创建) +3. 启用访客网络,设置 SSID 和加密方式 +4. 可选启用 AP 隔离功能 +5. 保存并应用 + +## 配置说明 + +| 选项 | 说明 | +|------|------| +| 启用 | 是否启用访客 WiFi | +| 网络名称(SSID) | 无线网络名称 | +| 加密方式 | 无/WPA2-PSK/WPA3-SAE/WPA2/WPA3混合 | +| 密码 | 无线连接密码(加密模式下必填)| +| AP 隔离 | 防止客户端之间互相通信 | + +## 目录结构 + +``` +luci-app-guest-wifi/ +├── Makefile +├── luasrc/ +│ ├── controller/ # LuCI 控制器 +│ └── model/cbi/ # CBI 模型 (兼容旧版) +├── htdocs/luci-static/resources/view/ +│ └── guest-wifi/wifi.js # JavaScript 视图 (现代 LuCI) +├── po/ # 翻译文件 +└── root/ + ├── etc/ + │ ├── config/ # UCI 配置 (通过 LuCI 管理) + │ ├── init.d/ # 启动脚本 + │ └── uci-defaults/ # 初始化脚本 + └── usr/share/ + ├── luci/menu.d/ # 菜单配置 + └── rpcd/acl.d/ # ACL 权限 +``` + +## 工作原理 + +- 插件通过 UCI 配置管理 `/etc/config/wireless` 中的 `wifi-iface` 段落 +- 通过在 `wifi-iface` 配置中添加 `option guest_wifi '1'` 来标识访客网络 +- 控制器和视图会自动过滤显示所有标记为访客的 WiFi 配置段 + +## 许可证 + +Apache-2.0 diff --git a/luci-app-guest-wifi/htdocs/luci-static/resources/view/guest-wifi.js b/luci-app-guest-wifi/htdocs/luci-static/resources/view/guest-wifi.js deleted file mode 100755 index 85123258..00000000 --- a/luci-app-guest-wifi/htdocs/luci-static/resources/view/guest-wifi.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict'; -'require form'; -'require view'; -'require uci'; -'require ui'; - -return view.extend({ - load: function() { - return Promise.all([ - uci.load('wireless') - ]); - }, - - render: function() { - const m = new form.Map('wireless', _('Guest WiFi'), - _('Guest WiFi provides a separate wireless network for guest access with isolated permissions.')); - - const s = m.section(form.TypedSection, 'wifi-iface', _('Guest WiFi Settings')); - s.anonymous = true; - s.addremove = true; - - s.option(form.Flag, 'guest_wifi', _('Enable'), - _('Enable guest WiFi network')); - - s.option(form.Value, 'ssid', _('Network Name (SSID)')); - - const o = s.option(form.ListValue, 'encryption', _('Encryption')); - o.value('none', _('No Encryption')); - o.value('psk2', _('WPA2-PSK')); - o.value('sae', _('WPA3-SAE')); - o.value('sae-mixed', _('WPA2/WPA3-Mixed')); - o.default = 'psk2'; - - const key = s.option(form.Value, 'key', _('Password')); - key.depends('encryption', 'psk2'); - key.depends('encryption', 'sae'); - key.depends('encryption', 'sae-mixed'); - key.datatype = 'wpakey'; - key.password = true; - - s.option(form.Flag, 'isolate', _('AP Isolation'), - _('Prevents wireless clients from communicating with each other')); - - return m.render(); - } -}); \ No newline at end of file diff --git a/luci-app-guest-wifi/htdocs/luci-static/resources/view/guest-wifi/wifi.js b/luci-app-guest-wifi/htdocs/luci-static/resources/view/guest-wifi/wifi.js index ead8f27e..f9bda8dd 100755 --- a/luci-app-guest-wifi/htdocs/luci-static/resources/view/guest-wifi/wifi.js +++ b/luci-app-guest-wifi/htdocs/luci-static/resources/view/guest-wifi/wifi.js @@ -2,57 +2,65 @@ 'require form'; 'require view'; 'require uci'; -'require ui'; return view.extend({ - load: function() { - return Promise.all([ - uci.load('wireless') - ]); - }, + load: function() { + return uci.load('wireless'); + }, - render: function() { - const m = new form.Map('wireless', _('Guest WiFi'), - _('Guest WiFi provides a separate wireless network for guest access with isolated permissions.')); + render: function() { + var m = new form.Map('wireless', _('Guest WiFi'), + _('Guest WiFi provides a separate wireless network for guest access with isolated permissions.')); - const s = m.section(form.TypedSection, 'wifi-iface', _('Guest WiFi Settings')); - s.anonymous = true; - s.addremove = true; - s.filter = function(section_id) { - return uci.get('wireless', section_id, 'guest_wifi') === '1'; - }; + var s = m.section(form.TypedSection, 'wifi-iface', _('Guest WiFi Settings')); + s.anonymous = true; + s.addremove = true; + s.filter = function(section_id) { + return uci.get('wireless', section_id, 'guest_wifi') === '1'; + }; + s.cfgvalue = function(section_id) { + return uci.get('wireless', section_id, 'guest_wifi'); + }; + s.handleApply = function(section, ev) { + uci.save(function() { + uci.apply(function() { + uci.load('wireless'); + XHR.poll(2); + }); + }); + }; - let o; + var o = null; - o = s.option(form.Flag, 'guest_wifi', _('Enable'), - _('Enable guest WiFi network')); - o.rmempty = false; - o.default = '0'; + o = s.option(form.Flag, 'guest_wifi', _('Enable'), + _('Enable guest WiFi network')); + o.rmempty = false; + o.default = '0'; - o = s.option(form.Value, 'ssid', _('Network Name (SSID)')); - o.rmempty = false; + o = s.option(form.Value, 'ssid', _('Network Name (SSID)')); + o.rmempty = false; - o = s.option(form.ListValue, 'encryption', _('Encryption')); - o.value('none', _('No Encryption')); - o.value('psk2', _('WPA2-PSK')); - o.value('sae', _('WPA3-SAE')); - o.value('sae-mixed', _('WPA2/WPA3-Mixed')); - o.rmempty = false; - o.default = 'psk2'; + o = s.option(form.ListValue, 'encryption', _('Encryption')); + o.value('none', _('No Encryption')); + o.value('psk2', _('WPA2-PSK')); + o.value('sae', _('WPA3-SAE')); + o.value('sae-mixed', _('WPA2/WPA3-Mixed')); + o.rmempty = false; + o.default = 'psk2'; - o = s.option(form.Value, 'key', _('Password')); - o.depends('encryption', 'psk2'); - o.depends('encryption', 'sae'); - o.depends('encryption', 'sae-mixed'); - o.datatype = 'wpakey'; - o.rmempty = false; - o.password = true; + o = s.option(form.Value, 'key', _('Password')); + o.depends('encryption', 'psk2'); + o.depends('encryption', 'sae'); + o.depends('encryption', 'sae-mixed'); + o.datatype = 'wpakey'; + o.rmempty = false; + o.password = true; - o = s.option(form.Flag, 'isolate', _('AP Isolation'), - _('Prevents wireless clients from communicating with each other')); - o.rmempty = false; - o.default = '1'; + o = s.option(form.Flag, 'isolate', _('AP Isolation'), + _('Prevents wireless clients from communicating with each other')); + o.rmempty = false; + o.default = '1'; - return m.render(); - } -}); \ No newline at end of file + return m.render(); + } +}); diff --git a/luci-app-guest-wifi/luasrc/controller/guest-wifi.lua b/luci-app-guest-wifi/luasrc/controller/guest-wifi.lua index 4f39cbba..a7624ed1 100755 --- a/luci-app-guest-wifi/luasrc/controller/guest-wifi.lua +++ b/luci-app-guest-wifi/luasrc/controller/guest-wifi.lua @@ -1,9 +1,11 @@ module("luci.controller.guest-wifi", package.seeall) -function index() - if not nixio.fs.access("/etc/config/wireless") then - return - end +local fs = require "nixio.fs" - entry({"admin", "network", "guest-wifi"}, view("guest-wifi/wifi"), _("Guest WiFi"), 60) -end \ No newline at end of file +function index() + if not fs.access("/etc/config/wireless") then + return + end + + entry({"admin", "network", "guest-wifi"}, view("guest-wifi/wifi"), _("Guest WiFi"), 60) +end diff --git a/luci-app-guest-wifi/luasrc/model/cbi/guest-wifi/wifi.lua b/luci-app-guest-wifi/luasrc/model/cbi/guest-wifi/wifi.lua index 4dfb58bb..b321aa86 100755 --- a/luci-app-guest-wifi/luasrc/model/cbi/guest-wifi/wifi.lua +++ b/luci-app-guest-wifi/luasrc/model/cbi/guest-wifi/wifi.lua @@ -1,21 +1,26 @@ +local form = require("form") local m, s, o m = Map("wireless", translate("Guest WiFi"), - translate("Guest WiFi provides a separate wireless network for guest access with isolated permissions.")) + translate("Guest WiFi provides a separate wireless network for guest access with isolated permissions.")) -s = m:section(TypedSection, "wifi-iface", translate("Guest WiFi Settings")) +s = m:section(form.TypedSection, "wifi-iface", translate("Guest WiFi Settings")) s.anonymous = true s.addremove = true +s.filter = function(section_id) + local val = uci:get("wireless", section_id, "guest_wifi") + return val == "1" +end -o = s:option(Flag, "guest_wifi", translate("Enable"), - translate("Enable guest WiFi network")) +o = s:option(form.Flag, "guest_wifi", translate("Enable"), + translate("Enable guest WiFi network")) o.rmempty = false o.default = "0" -o = s:option(Value, "ssid", translate("Network Name (SSID)")) +o = s:option(form.Value, "ssid", translate("Network Name (SSID)")) o.rmempty = false -o = s:option(ListValue, "encryption", translate("Encryption")) +o = s:option(form.ListValue, "encryption", translate("Encryption")) o:value("none", translate("No Encryption")) o:value("psk2", translate("WPA2-PSK")) o:value("sae", translate("WPA3-SAE")) @@ -23,7 +28,7 @@ o:value("sae-mixed", translate("WPA2/WPA3-Mixed")) o.rmempty = false o.default = "psk2" -o = s:option(Value, "key", translate("Password")) +o = s:option(form.Value, "key", translate("Password")) o:depends("encryption", "psk2") o:depends("encryption", "sae") o:depends("encryption", "sae-mixed") @@ -31,9 +36,9 @@ o.datatype = "wpakey" o.rmempty = false o.password = true -o = s:option(Flag, "isolate", translate("AP Isolation"), - translate("Prevents wireless clients from communicating with each other")) +o = s:option(form.Flag, "isolate", translate("AP Isolation"), + translate("Prevents wireless clients from communicating with each other")) o.rmempty = false o.default = "1" -return m \ No newline at end of file +return m diff --git a/luci-app-guest-wifi/po/templates/guest-wifi.pot b/luci-app-guest-wifi/po/templates/guest-wifi.pot index 5483d560..6a6d3417 100755 --- a/luci-app-guest-wifi/po/templates/guest-wifi.pot +++ b/luci-app-guest-wifi/po/templates/guest-wifi.pot @@ -1,5 +1,14 @@ msgid "" -msgstr "Content-Type: text/plain; charset=UTF-8" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: luci-app-guest-wifi\n" +"PO-Revision-Date: 2024\n" +"Last-Translator: kenzok8\n" +"Language-Team: Chinese\n" +"Language: zh_Hans\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" msgid "Guest WiFi" msgstr "" @@ -41,4 +50,4 @@ msgid "AP Isolation" msgstr "" msgid "Prevents wireless clients from communicating with each other" -msgstr "" \ No newline at end of file +msgstr "" diff --git a/luci-app-guest-wifi/po/zh-cn b/luci-app-guest-wifi/po/zh-cn new file mode 120000 index 00000000..8d69574d --- /dev/null +++ b/luci-app-guest-wifi/po/zh-cn @@ -0,0 +1 @@ +zh_Hans \ No newline at end of file diff --git a/luci-app-guest-wifi/po/zh_Hans b/luci-app-guest-wifi/po/zh_Hans deleted file mode 120000 index 41451e4a..00000000 --- a/luci-app-guest-wifi/po/zh_Hans +++ /dev/null @@ -1 +0,0 @@ -zh-cn \ No newline at end of file diff --git a/luci-app-guest-wifi/po/zh-cn/guest-wifi.po b/luci-app-guest-wifi/po/zh_Hans/guest-wifi.po similarity index 68% rename from luci-app-guest-wifi/po/zh-cn/guest-wifi.po rename to luci-app-guest-wifi/po/zh_Hans/guest-wifi.po index 46fc769e..6784b4a3 100755 --- a/luci-app-guest-wifi/po/zh-cn/guest-wifi.po +++ b/luci-app-guest-wifi/po/zh_Hans/guest-wifi.po @@ -1,3 +1,15 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: luci-app-guest-wifi\n" +"PO-Revision-Date: 2024\n" +"Last-Translator: kenzok8\n" +"Language-Team: Chinese\n" +"Language: zh_Hans\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + msgid "Guest WiFi" msgstr "访客WiFi" @@ -38,4 +50,4 @@ msgid "AP Isolation" msgstr "AP隔离" msgid "Prevents wireless clients from communicating with each other" -msgstr "防止无线客户端之间相互通信" \ No newline at end of file +msgstr "防止无线客户端之间相互通信" diff --git a/luci-app-guest-wifi/root/etc/config/guest-wifi b/luci-app-guest-wifi/root/etc/config/guest-wifi deleted file mode 100755 index 410be80e..00000000 --- a/luci-app-guest-wifi/root/etc/config/guest-wifi +++ /dev/null @@ -1,3 +0,0 @@ -config guest-wifi 'config' - option enabled '0' - option isolate '1' \ No newline at end of file diff --git a/luci-app-guest-wifi/root/etc/init.d/guest-wifi b/luci-app-guest-wifi/root/etc/init.d/guest-wifi index e83f3be4..4e321c06 100755 --- a/luci-app-guest-wifi/root/etc/init.d/guest-wifi +++ b/luci-app-guest-wifi/root/etc/init.d/guest-wifi @@ -4,13 +4,13 @@ START=99 USE_PROCD=1 reload_service() { - wifi reload + wifi reload >/dev/null 2>&1 } service_triggers() { - procd_add_reload_trigger "wireless" + procd_add_reload_trigger "wireless" } start_service() { - reload_service -} \ No newline at end of file + reload_service +} diff --git a/luci-app-guest-wifi/root/etc/uci-defaults/40_luci-guest-wifi b/luci-app-guest-wifi/root/etc/uci-defaults/40_luci-guest-wifi old mode 100644 new mode 100755 index 99e50aa0..42a0e48d --- a/luci-app-guest-wifi/root/etc/uci-defaults/40_luci-guest-wifi +++ b/luci-app-guest-wifi/root/etc/uci-defaults/40_luci-guest-wifi @@ -1,19 +1,6 @@ #!/bin/sh -[ ! -f "/usr/share/ucitrack/luci-app-guest-wifi.json" ] && { - cat > /usr/share/ucitrack/luci-app-guest-wifi.json << EEOF -{ - "config": "guest-wifi", - "init": "guest-wifi" -} -EEOF -} -uci -q batch <<-EOF >/dev/null - delete ucitrack.@guest-wifi[-1] - add ucitrack guest-wifi - set ucitrack.@guest-wifi[-1].init=guest-wifi - commit ucitrack -EOF +[ -z "${IPKG_INSTROOT}" ] || exit 0 -rm -f /tmp/luci-indexcache -exit 0 \ No newline at end of file +rm -f /tmp/luci-indexcache 2>/dev/null +exit 0 diff --git a/luci-app-guest-wifi/root/etc/uci-defaults/luci-i18n-guest-wifi-zh-cn b/luci-app-guest-wifi/root/etc/uci-defaults/luci-i18n-guest-wifi-zh-cn deleted file mode 100755 index 85dcbcf8..00000000 --- a/luci-app-guest-wifi/root/etc/uci-defaults/luci-i18n-guest-wifi-zh-cn +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -uci -q batch <<-EOF >/dev/null - set luci.languages.zh_cn='chinese' - commit luci -EOF - -exit 0 \ No newline at end of file diff --git a/luci-app-guest-wifi/root/usr/lib/lua/luci/controller/guest-wifi.lua b/luci-app-guest-wifi/root/usr/lib/lua/luci/controller/guest-wifi.lua deleted file mode 100755 index 88a79b50..00000000 --- a/luci-app-guest-wifi/root/usr/lib/lua/luci/controller/guest-wifi.lua +++ /dev/null @@ -1,9 +0,0 @@ -module("luci.controller.guest-wifi", package.seeall) - -function index() - if not nixio.fs.access("/etc/config/wireless") then - return - end - - entry({"admin", "network", "guest-wifi"}, view("guest-wifi/wifi"), _("Guest WiFi"), 60) -end \ No newline at end of file diff --git a/luci-app-guest-wifi/root/usr/sbin/guest-wifi b/luci-app-guest-wifi/root/usr/sbin/guest-wifi deleted file mode 100755 index 276879c5..00000000 --- a/luci-app-guest-wifi/root/usr/sbin/guest-wifi +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -# 检查无线配置 -check_wireless() { - local enabled - config_load wireless - config_get enabled guest_wifi enabled 0 - - if [ "$enabled" = "1" ]; then - # 应用guest wifi配置 - wifi reload - fi -} - -# 主循环 -while true; do - check_wireless - sleep 300 -done \ No newline at end of file diff --git a/luci-app-guest-wifi/root/usr/share/rpcd/acl.d/luci-app-guest-wifi.json b/luci-app-guest-wifi/root/usr/share/rpcd/acl.d/luci-app-guest-wifi.json index 1e93a90c..49b73ab8 100755 --- a/luci-app-guest-wifi/root/usr/share/rpcd/acl.d/luci-app-guest-wifi.json +++ b/luci-app-guest-wifi/root/usr/share/rpcd/acl.d/luci-app-guest-wifi.json @@ -1,14 +1,14 @@ { - "luci-app-guest-wifi": { - "description": "Grant access to guest-wifi configuration", - "read": { - "uci": [ "wireless", "guest-wifi" ], - "ubus": { - "iwinfo": [ "devices", "info", "assoclist" ] - } - }, - "write": { - "uci": [ "wireless", "guest-wifi" ] - } - } -} \ No newline at end of file + "luci-app-guest-wifi": { + "description": "Grant access to guest-wifi configuration", + "read": { + "uci": [ "wireless" ], + "ubus": { + "iwinfo": [ "devices", "info", "assoclist" ] + } + }, + "write": { + "uci": [ "wireless" ] + } + } +} diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua index c774e9ee..e2164b82 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua @@ -65,6 +65,9 @@ if singbox_tags:find("with_quic") then end o:value("anytls", "AnyTLS") o:value("ssh", "SSH") +if singbox_tags:find("with_naive_outbound") then + o:value("naive", "NaïveProxy") +end o:value("_urltest", translate("URLTest")) o:value("_shunt", translate("Shunt")) o:value("_iface", translate("Custom Interface")) @@ -224,6 +227,7 @@ o = s:option(Value, _n("username"), translate("Username")) o:depends({ [_n("protocol")] = "http" }) o:depends({ [_n("protocol")] = "socks" }) o:depends({ [_n("protocol")] = "ssh" }) +o:depends({ [_n("protocol")] = "naive" }) o = s:option(Value, _n("password"), translate("Password")) o.password = true @@ -234,6 +238,7 @@ o:depends({ [_n("protocol")] = "trojan" }) o:depends({ [_n("protocol")] = "tuic" }) o:depends({ [_n("protocol")] = "anytls" }) o:depends({ [_n("protocol")] = "ssh" }) +o:depends({ [_n("protocol")] = "naive" }) o = s:option(ListValue, _n("security"), translate("Encrypt Method")) for a, t in ipairs(security_list) do o:value(t) end @@ -248,6 +253,7 @@ o:depends({ [_n("protocol")] = "shadowsocks" }) o = s:option(Flag, _n("uot"), translate("UDP over TCP")) o:depends({ [_n("protocol")] = "socks" }) o:depends({ [_n("protocol")] = "shadowsocks" }) +o:depends({ [_n("protocol")] = "naive" }) o = s:option(Value, _n("alter_id"), "Alter ID") o.datatype = "uinteger" @@ -399,6 +405,26 @@ o = s:option(Value, _n("ssh_client_version"), translate("Client Version"), trans o:depends({ [_n("protocol")] = "ssh" }) -- [[ SSH config end ]] -- +-- [[ naive start ]] -- +o = s:option(Value, _n("naive_insecure_concurrency"), translate("Concurrent Tunnels")) +o.datatype = "uinteger" +o.placeholder = "0" +o.default = "0" +o:depends({ [_n("protocol")] = "naive" }) + +o = s:option(Flag, _n("naive_quic"), translate("QUIC")) +o.default = 0 +o:depends({ [_n("protocol")] = "naive" }) + +o = s:option(ListValue, _n("naive_congestion_control"), translate("Congestion control algorithm")) +o.default = "bbr" +o:value("bbr", translate("BBR")) +o:value("bbr2", translate("BBRv2")) +o:value("cubic", translate("CUBIC")) +o:value("reno", translate("New Reno")) +o:depends({ [_n("naive_quic")] = "1" }) +-- [[ naive end ]] -- + o = s:option(Flag, _n("tls"), translate("TLS")) o.default = 0 o:depends({ [_n("protocol")] = "vmess" }) @@ -432,6 +458,7 @@ o:depends({ [_n("tls")] = true }) o:depends({ [_n("protocol")] = "hysteria"}) o:depends({ [_n("protocol")] = "tuic" }) o:depends({ [_n("protocol")] = "hysteria2" }) +o:depends({ [_n("protocol")] = "naive" }) o = s:option(Flag, _n("tls_allowInsecure"), translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped.")) o.default = "0" @@ -446,6 +473,7 @@ o:depends({ [_n("tls")] = true, [_n("flow")] = "", [_n("reality")] = false }) o:depends({ [_n("protocol")] = "tuic" }) o:depends({ [_n("protocol")] = "hysteria" }) o:depends({ [_n("protocol")] = "hysteria2" }) +o:depends({ [_n("protocol")] = "naive" }) o = s:option(TextValue, _n("ech_config"), translate("ECH Config")) o.default = "" @@ -622,6 +650,7 @@ o:depends({ [_n("tcp_guise")] = "http" }) o:depends({ [_n("transport")] = "http" }) o:depends({ [_n("transport")] = "ws" }) o:depends({ [_n("transport")] = "httpupgrade" }) +o:depends({ [_n("protocol")] = "naive" }) -- [[ Mux ]]-- o = s:option(Flag, _n("mux"), translate("Mux")) diff --git a/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/luci-app-passwall/luasrc/passwall/util_sing-box.lua index 51e4309a..7df84979 100644 --- a/luci-app-passwall/luasrc/passwall/util_sing-box.lua +++ b/luci-app-passwall/luasrc/passwall/util_sing-box.lua @@ -154,7 +154,7 @@ function gen_outbound(flag, node, tag, proxy_table) } local tls = nil - if node.protocol == "hysteria" or node.protocol == "hysteria2" or node.protocol == "tuic" then + if node.protocol == "hysteria" or node.protocol == "hysteria2" or node.protocol == "tuic" or node.protocol == "naive" then node.tls = "1" end if node.tls == "1" then @@ -489,6 +489,23 @@ function gen_outbound(flag, node, tag, proxy_table) } end + if node.protocol == "naive" then + protocol_table = { + username = (node.username and node.username ~= "") and node.username or "", + password = (node.password and node.password ~= "") and node.password or "", + insecure_concurrency = tonumber(node.naive_insecure_concurrency or 0) > 0 and tonumber(node.naive_insecure_concurrency) or 0, + udp_over_tcp = node.uot == "1" and { + enabled = true, + version = 2 + } or false, + extra_headers = node.user_agent and { + ["User-Agent"] = node.user_agent + } or nil, + quic = node.naive_quic == "1" and true or false, + quic_congestion_control = (node.naive_quic == "1" and node.naive_congestion_control) and node.naive_congestion_control or nil + } + end + if protocol_table then for key, value in pairs(protocol_table) do result[key] = value diff --git a/luci-app-passwall/luasrc/view/passwall/node_config/link_share_man.htm b/luci-app-passwall/luasrc/view/passwall/node_config/link_share_man.htm index a1df843e..e179bc47 100644 --- a/luci-app-passwall/luasrc/view/passwall/node_config/link_share_man.htm +++ b/luci-app-passwall/luasrc/view/passwall/node_config/link_share_man.htm @@ -679,6 +679,31 @@ local current_node = map:get(section) params += opt.query("allowinsecure", dom_prefix + "tls_allowInsecure"); } + params += "#" + encodeURI(v_alias.value); + if (params[0] == "&") { + params = params.substring(1); + } + url += params; + } else if (v_type === "sing-box" && opt.get(dom_prefix + "protocol").value === "naive") { + protocol = "naive+https"; + var v_username = opt.get(dom_prefix + "username"); + var v_password = opt.get(dom_prefix + "password"); + var v_port = opt.get(dom_prefix + "port"); + url = encodeURIComponent(v_username.value) + + ":" + encodeURIComponent(v_password.value) + + "@" + _address + + ":" + v_port.value + "?"; + + var params = "security=tls"; + params += opt.query("sni", dom_prefix + "tls_serverName"); + params += opt.query("insecure-concurrency", dom_prefix + "naive_insecure_concurrency"); + params += opt.query("ech", dom_prefix + "ech_config"); + params += opt.query("uot", dom_prefix + "uot"); + if (opt.get(dom_prefix + "naive_quic")?.checked) { + protocol = "naive+quic"; + params += opt.query("congestion_control", dom_prefix + "naive_congestion_control"); + } + params += "#" + encodeURI(v_alias.value); if (params[0] == "&") { params = params.substring(1); @@ -1729,6 +1754,55 @@ local current_node = map:get(section) opt.set('remarks', decodeURIComponent(m.hash.substr(1))); } } + if (ssu[0] === "naive+https" || ssu[0] === "naive+quic") { + if (has_singbox) { + dom_prefix = "singbox_" + opt.set('type', "sing-box"); + } + opt.set(dom_prefix + 'protocol', "naive"); + var _parsedUrl = new URL("http://" + ssu[1]); + var username = _parsedUrl.username; + var password = _parsedUrl.password; + var hostname = _parsedUrl.hostname; + var port = _parsedUrl.port; + var search = _parsedUrl.search; + var hash = _parsedUrl.hash; + if (!username || !password) { //某些链接会把username和password之间的:进行编码 + const decoded = decodeURIComponent(username || password || ""); + const i = decoded.indexOf(":"); + if (i > -1) { + username = decoded.slice(0, i); + password = decoded.slice(i + 1); + } + } + opt.set(dom_prefix + 'username', decodeURIComponent(username)); + opt.set(dom_prefix + 'password', decodeURIComponent(password)); + opt.set(dom_prefix + 'address', unbracketIP(hostname)); + opt.set(dom_prefix + 'port', port || "443"); + var queryParam = {}; + if (search.length > 1) { + var query = search.split('?') + var queryParams = query[1]; + var queryArray = queryParams.split('&'); + var params; + for (i = 0; i < queryArray.length; i++) { + params = queryArray[i].split('='); + queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || ''); + } + } + opt.set(dom_prefix + 'naive_insecure_concurrency', queryParam['insecure-concurrency'] || '0'); + opt.set(dom_prefix + 'uot', (queryParam.uot ?? '0') === '1'); + opt.set(dom_prefix + 'tls_serverName', queryParam.sni || ''); + opt.set(dom_prefix + 'ech', !!queryParam.ech); + opt.set(dom_prefix + 'ech_config', queryParam.ech || ''); + if (ssu[0] === "naive+quic") { + opt.set(dom_prefix + 'naive_quic', true); + opt.set(dom_prefix + 'naive_congestion_control', queryParam.congestion_control || 'bbr'); + } + if (hash) { + opt.set('remarks', decodeURIComponent(hash.substr(1))); + } + } if (dom_prefix && dom_prefix != null) { if (opt.get(dom_prefix + 'port').value) { opt.get(dom_prefix + 'port').focus(); diff --git a/luci-app-passwall/po/zh-cn/passwall.po b/luci-app-passwall/po/zh-cn/passwall.po index b627d855..2d5f82cf 100644 --- a/luci-app-passwall/po/zh-cn/passwall.po +++ b/luci-app-passwall/po/zh-cn/passwall.po @@ -2107,3 +2107,6 @@ msgstr "当前使用的 %s 节点" msgid "Search nodes..." msgstr "搜索节点…" + +msgid "Concurrent Tunnels" +msgstr "并发隧道连接数" diff --git a/luci-app-passwall/root/usr/share/passwall/subscribe.lua b/luci-app-passwall/root/usr/share/passwall/subscribe.lua index 32fbcaa8..0733ccb6 100755 --- a/luci-app-passwall/root/usr/share/passwall/subscribe.lua +++ b/luci-app-passwall/root/usr/share/passwall/subscribe.lua @@ -1561,6 +1561,68 @@ local function processData(szType, content, add_mode, group) return nil end end + elseif szType == 'naive+https' or szType == 'naive+quic' then + if has_singbox then + result.type = 'sing-box' + result.protocol = "naive" + else + log("跳过 NaïveProxy 节点,因未安装 NaïveProxy 核心程序 Sing-box。") + return nil + end + + local alias = "" + if content:find("#") then + local idx_sp = content:find("#") + alias = content:sub(idx_sp + 1, -1) + content = content:sub(0, idx_sp - 1) + end + result.remarks = UrlDecode(alias) + local Info = content + if content:find("@", 1, true) then + local contents = split(content, "@") + local auth = contents[1] or "" + local idx = auth:find(":", 1, true) + if not idx then --修正某些链接会把username和password之间的:进行编码 + auth = UrlDecode(auth) + idx = auth:find(":", 1, true) + end + if idx then + result.username = UrlDecode(auth:sub(1, idx - 1)) + result.password = UrlDecode(auth:sub(idx + 1)) + end + Info = (contents[2] or ""):gsub("/%?", "?") + end + local query = split(Info, "%?") + local host_port = query[1] + local params = {} + for _, v in pairs(split(query[2], '&')) do + local t = split(v, '=') + if #t > 1 then + params[string.lower(t[1])] = UrlDecode(t[2]) + end + end + if host_port:find(":") then + local sp = split(host_port, ":") + result.port = sp[#sp] + if api.is_ipv6addrport(host_port) then + result.address = api.get_ipv6_only(host_port) + else + result.address = sp[1] + end + else + result.address = host_port + end + result.tls_serverName = params.sni + result.uot = params.uot + result.naive_insecure_concurrency = params["insecure-concurrency"] or "0" + if params.ech and params.ech ~= "" then + result.ech = "1" + result.ech_config = params.ech + end + if szType == "naive+quic" then + result.naive_quic = "1" + result.naive_congestion_control = params.congestion_control or "bbr" + end else log('暂时不支持' .. szType .. "类型的节点订阅,跳过此节点。") return nil diff --git a/luci-theme-alpha/Makefile b/luci-theme-alpha/Makefile index c5e78098..4076f5c9 100644 --- a/luci-theme-alpha/Makefile +++ b/luci-theme-alpha/Makefile @@ -10,8 +10,8 @@ THEME_NAME:=alpha THEME_TITLE:=Alpha PKG_NAME:=luci-theme-$(THEME_NAME) -PKG_VERSION:=3.9.6_beta -PKG_RELEASE:=2 +PKG_VERSION:=3.9.7_beta +PKG_RELEASE:=3 include $(INCLUDE_DIR)/package.mk diff --git a/luci-theme-alpha/js/menu-alpha.js b/luci-theme-alpha/js/menu-alpha.js index 62cae62e..1b8de894 100644 --- a/luci-theme-alpha/js/menu-alpha.js +++ b/luci-theme-alpha/js/menu-alpha.js @@ -30,29 +30,42 @@ return baseclass.extend({ ); document.querySelector(".main > .loading").style.opacity = "0"; document.querySelector(".main > .loading").style.visibility = "hidden"; - if (window.innerWidth <= 1152) - document.querySelector(".main-left").style.width = "0"; + if (window.innerWidth <= 1152) { + document.querySelector(".main-left").style.transform = "translateX(-20rem)"; + } window.addEventListener("resize", this.handleSidebarToggle, true); }, handleMenuExpand: function (ev) { var a = ev.target, ul1 = a.parentNode, - ul2 = a.nextElementSibling; + ul2 = a.nextElementSibling, + isActive = ul1.classList.contains("active"); document.querySelectorAll("li.slide.active").forEach(function (li) { if (li !== a.parentNode || li == ul1) { + var menu = li.querySelector("ul"); + if (menu) { + if (!menu.style.maxHeight || menu.style.maxHeight === "1200px") { + menu.style.maxHeight = menu.scrollHeight + "px"; + } + void menu.offsetHeight; // Force layout + menu.style.maxHeight = "0px"; + } li.classList.remove("active"); li.childNodes[0].classList.remove("active"); } if (li == ul1) return; }); if (!ul2) return; - if ( - ul2.parentNode.offsetLeft + ul2.offsetWidth <= - ul1.offsetLeft + ul1.offsetWidth - ) - ul2.classList.add("align-left"); - ul1.classList.add("active"); - a.classList.add("active"); + if (!isActive) { + if ( + ul2.parentNode.offsetLeft + ul2.offsetWidth <= + ul1.offsetLeft + ul1.offsetWidth + ) + ul2.classList.add("align-left"); + ul1.classList.add("active"); + a.classList.add("active"); + ul2.style.maxHeight = ul2.scrollHeight + "px"; + } a.blur(); ev.preventDefault(); ev.stopPropagation(); @@ -167,13 +180,38 @@ return baseclass.extend({ darkMask = document.querySelector(".darkMask"), mainRight = document.querySelector(".main-right"), mainLeft = document.querySelector(".main-left"), - open = mainLeft.style.width == ""; - if (width > 1152 || ev.type == "resize") open = true; - darkMask.style.visibility = open ? "" : "visible"; - darkMask.style.opacity = open ? "" : 1; - if (width <= 1152) mainLeft.style.width = open ? "0" : ""; - else mainLeft.style.width = ""; - mainLeft.style.visibility = open ? "" : "visible"; - mainRight.style["overflow-y"] = open ? "visible" : "hidden"; + open = mainLeft.style.transform === ""; // true if currently open + + // If it's a resize event, we simulate that the sidebar was "open" so the logic below closes it for mobile, and opens it for desktop + if (ev.type == "resize") { + open = true; + } + + // Logics: 'open' true means we want to CLOSE it on mobile, but OPEN it on desktop. + // Actually, let's make it clearer: we toggle the state. + var willOpen = !open; + if (ev.type == "resize") { + willOpen = width > 1152; + } + + if (width <= 1152) { + // Mobile behavior + mainLeft.style.width = ""; // Reset width + mainLeft.style.transform = willOpen ? "" : "translateX(-20rem)"; + mainLeft.style.visibility = willOpen ? "visible" : ""; + darkMask.style.visibility = willOpen ? "visible" : ""; + darkMask.style.opacity = willOpen ? 1 : ""; + mainRight.style.width = ""; + } else { + // Desktop behavior + mainLeft.style.width = ""; // Reset width + mainLeft.style.transform = willOpen ? "" : "translateX(-20rem)"; + mainLeft.style.visibility = willOpen ? "visible" : "hidden"; + mainRight.style.width = willOpen ? "" : "100%"; + darkMask.style.visibility = ""; + darkMask.style.opacity = ""; + } + if (ev && ev.preventDefault) ev.preventDefault(); + if (ev && ev.stopPropagation) ev.stopPropagation(); }, }); diff --git a/luci-theme-alpha/luasrc/gaya/gaya.css b/luci-theme-alpha/luasrc/gaya/gaya.css index e16a8e0d..f0978943 100755 --- a/luci-theme-alpha/luasrc/gaya/gaya.css +++ b/luci-theme-alpha/luasrc/gaya/gaya.css @@ -783,6 +783,7 @@ float: right; width: calc(100% - 16rem); height: 100%; + transition: width 450ms cubic-bezier(0.16, 1, 0.3, 1); } .nowrap:not(.td) { @@ -795,6 +796,17 @@ } /* Sidebar */ + .showSide { + position: -webkit-sticky; + position: sticky; + top: 0rem; + display: inline-flex; + align-items: center; + height: 100%; + margin-right: 0.7rem; + cursor: pointer; + } + .main>.main-left { position: fixed; top: 4.8rem; @@ -802,7 +814,7 @@ float: left; overflow-x: auto; background-color: #2222359a; - transition: visibility 400ms, width 400ms; + transition: visibility 450ms, transform 450ms cubic-bezier(0.16, 1, 0.3, 1); border-top-left-radius: 0px; border-top-right-radius: 20px; border-bottom-left-radius: 0px; @@ -2499,7 +2511,7 @@ width: 100%; height: 100%; content: ""; - transition: opacity 400ms, visibility 400ms; + transition: opacity 450ms cubic-bezier(0.16, 1, 0.3, 1), visibility 450ms; visibility: hidden; opacity: 0; background-color: #2222359a; @@ -2840,7 +2852,10 @@ .alert-message .btn, .modal .btn { - padding: 0.3rem 0.6rem; + padding: 0 1.2rem; + display: inline-flex; + align-items: center; + justify-content: center; } .container .alert, @@ -2866,14 +2881,8 @@ border-radius: 10px; } - .main>.main-left>.nav>.slide>ul, - .main>.main-left[style*="overflow: hidden"]>.nav>.slide>.menu::before, - .tr.placeholder .td[data-title]::before, - .cbi-dropdown>ul.preview, - .cbi-dropdown>ul>li .hide-close, .cbi-dropdown[open]>ul.dropdown>li .hide-open, .hidden, - .showSide, .node-main-login>.main>.main-left, [data-page^="admin-system-commands"] .panel-title, [data-page^="command-cfg"] .mobile-hide, @@ -2881,7 +2890,6 @@ display: none; } - .main>.main-left>.nav>.slide.active>ul, .cbi-dropdown[empty]>ul>li, .cbi-dropdown[optional][open]>ul.dropdown>li[placeholder], .cbi-dropdown[multiple][open]>ul.dropdown>li>form, @@ -2892,6 +2900,21 @@ display: block; } + .main>.main-left>.nav>.slide>ul { + display: block; + overflow: hidden; + max-height: 0; + opacity: 0; + visibility: hidden; + transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease-out, visibility 0.4s; + } + .main>.main-left>.nav>.slide.active>ul { + max-height: 1200px; /* Fallback for initial load */ + opacity: 1; + visibility: visible; + transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.4s ease-in, visibility 0s; + } + .main>.main-left>.nav>li:hover, .main>.main-left>.nav>.slide>.menu:hover, .main>.main-left>.nav>.slide>.slide-menu>li:hover { @@ -3194,16 +3217,26 @@ width: 100%; } - .showSide { - position: -webkit-sticky; - position: sticky; - top: 0rem; - display: inline-flex; - align-items: center; - height: 100%; - margin-right: 0.7rem; - cursor: pointer; - } + .showSide { + position: -webkit-sticky !important; + position: sticky !important; + top: 0rem; + display: inline-flex !important; + align-items: center; + min-width: 40px; + height: 100%; + margin-right: 0.7rem; + cursor: pointer; + flex-shrink: 0 !important; + z-index: 3000 !important; + } + .showSide img { + width: 30px !important; + height: auto !important; + display: block !important; + visibility: visible !important; + opacity: 1 !important; + } body:not(.logged-in) .showSide { visibility: hidden; diff --git a/luci-theme-alpha/luasrc/gaya/gaya.css.bak b/luci-theme-alpha/luasrc/gaya/gaya.css.bak deleted file mode 100644 index 0b9b3d54..00000000 --- a/luci-theme-alpha/luasrc/gaya/gaya.css.bak +++ /dev/null @@ -1,3625 +0,0 @@ - /* Base */ - @font-face { - font-family: "Inter-Regular"; - src: url('/luci-static/alpha/fonts/Inter-Regular.woff2'); - } - - @font-face { - font-family: "Inter-Medium"; - src: url('/luci-static/alpha/fonts/Inter-Medium.woff2'); - } - - @font-face { - font-family: "Inter-Black"; - src: url('/luci-static/alpha/fonts/Inter-Black.woff2'); - } - - @font-face { - font-family: "Inter-Bold"; - src: url('/luci-static/alpha/fonts/Inter-Bold.woff2'); - } - - @font-face { - font-family: "Quicksand-Bold"; - src: url('/luci-static/alpha/fonts/Quicksand-Bold.ttf'); - } - - @font-face { - font-family: argon; - src: url('/luci-static/alpha/fonts/argon.woff'); - - } - - [class^="icon-"], - [class*=" icon-"] { - font-family: argon !important; - font-style: normal; - font-weight: 400; - font-variant: normal; - text-transform: none; - line-height: 1; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - } - - a { - color: #5a8dee; - text-decoration: none; - background-color: transparent; - } - - b { - color: #5a8dee; - text-decoration: none; - background-color: transparent; - font-family: "Quicksand-Bold"; - - } - - ::-webkit-scrollbar:hover { - background-color: rgba(100, 100, 100, 0.09); - } - - ::-webkit-scrollbar-thumb:vertical { - background: rgba(100, 100, 100, 0.5); - -webkit-border-radius: 100px; - } - - ::-webkit-scrollbar-thumb:vertical:active { - background: rgba(100, 100, 100, 0.61); - -webkit-border-radius: 100px; - } - - ::-webkit-scrollbar { - width: 0.2em !important; - overflow: visible; - border-radius: 4px; - -webkit-border-radius: 4px; - } - - ::-webkit-scrollbar-track { - opacity: 0; - -webkit-transition: all 0.5s; - } - - ::-webkit-scrollbar-thumb { - overflow: visible; - border-radius: 4px; - background: rgba(100, 100, 100, 0.2); - } - - .icon-hello-world:before { - content: "\e90e"; - } - - .icon-expand_more:before { - content: "\e20b"; - } - - .icon-menu:before { - content: "\e20e"; - } - - .icon-favorite:before { - content: "\e291"; - } - - .icon-spinner:before { - content: "\e603"; - } - - .icon-delete:before { - content: "\e900"; - } - - .icon-edit:before { - content: "\e901"; - } - - .icon-use:before { - content: "\e902"; - } - - .icon-loading:before { - content: "\e903"; - } - - .icon-switch:before { - content: "\e904"; - } - - .icon-error:before { - content: "\e905"; - } - - .icon-dashboard:before { - content: "\e906"; - } - - .icon-logout:before { - content: "\e907"; - } - - .icon-Network:before { - content: "\e908"; - } - - .icon-services:before { - content: "\e909"; - } - - .icon-system:before { - content: "\e90a"; - } - - .icon-vpn:before { - content: "\e90b"; - } - - .icon-storage:before { - content: "\e90c"; - } - - .icon-statistics:before { - content: "\e90d"; - } - - .icon-angle-right:before { - content: "\e90f"; - } - - .icon-user:before { - content: "\e971"; - } - - .icon-question:before { - content: "\f059"; - } - - :root { - --main-color: #09c; - --header-bg: #161624; - --header-color: rgb(10, 10, 10); - --bar-bg: #3f3f3f69; - --menu-bg-color: #fff; - --menu-color: #5f6368; - --menu-color-hover: #202124; - --main-menu-color: #202124; - --submenu-bg-hover: #4d5ca5; - --submenu-bg-hover-active: #09c; - --font-body: 'Inter-Regular'; - } - - tt { - font-family: "Quicksand-Bold"; - color: #09c; - } - - em { - font-style: italic; - color: #fff - } - - p { - display: block; - margin-block-start: 1em; - margin-block-end: 1em; - margin-inline-start: 0px; - margin-inline-end: 0px; - color: #ffffff; - } - - li { - display: block; - list-style-type: disc; - margin-block-start: 5px; - margin-block-end: 5px; - margin-inline-start: 0px; - margin-inline-end: 0px; - color: #ffffff; - } - - small { - font-size: smaller; - color: #ffff; - } - - label { - cursor: default; - color: #ffffff; - } - - .table { - position: relative; - display: table; - } - - .tr { - display: table-row; - } - - .thead { - display: table-header-group; - } - - .tbody { - display: table-row-group; - } - - .tfoot { - display: table-footer-group; - } - - .td, - .th { - line-height: normal; - display: table-cell; - vertical-align: middle; - padding: 0.5em; - } - - .th { - font-weight: 700; - } - - .tr.placeholder { - height: 4em; - } - - .tr.placeholder>.td { - line-height: 3; - position: absolute; - right: 0; - bottom: 0; - left: 0; - text-align: center !important; - background: inherit; - } - - .table[width="33%"], - .th[width="33%"], - .td[width="33%"] { - width: 33%; - } - - .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; - } - - .col-7 { - flex: 7 7 210px !important; - } - - .col-8 { - flex: 8 8 240px !important; - } - - .col-9 { - flex: 9 9 270px !important; - } - - .col-10 { - flex: 10 10 300px !important; - } - - * { - box-sizing: border-box; - padding: 0; - } - - .h1, - .h2, - .h3, - .h4, - .h5, - .h6, - h1, - h2, - h3, - h4, - h5, - h6 { - font-family: inherit; - font-weight: 400; - line-height: 1.1 !important; - color: #fff; - } - - html { - overflow-y: hidden; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; - } - - body { - font-size: 0.8rem; - height: 100%; - background-position: center; - background-repeat: no-repeat; - background-size: cover; - background-attachment: fixed; - background-color: rgb(10, 10, 10); - } - - .text { - font-style: italic; - color: #fff; - } - - html, - body { - font-family: var(--font-body); - height: 100%; - margin: 0; - padding: 0; - } - - select { - color: #555; - border: thin solid #ccc; - background-color: #fff; - background-image: none; - padding: 0.36rem 0.8rem; - } - - .btn, - button, - select, - input, - .cbi-dropdown { - height: 2.3rem; - color: rgba(255, 255, 255, 0.87); - border: 0; - border-bottom: 2px solid #30304b; - border-radius: 10px; - border-radius: 20px; - outline: 0; - background-color: #222235; - background-image: none; - box-shadow: none; - padding: 0.5rem; - } - - select, - .cbi-dropdown { - width: inherit; - cursor: default; - } - - select:not([multiple="multiple"]):focus, - input:not(.cbi-button):focus, - .cbi-dropdown:focus { - border-color: var(--main-color); - } - - .cbi-dropdown, - select[multiple="multiple"] { - height: auto; - } - - pre { - overflow: auto; - color: #fff; - } - - code { - font-size: 1rem; - font-size-adjust: 0.35; - color: #101010; - border-radius: 0px; - background: #ddd; - padding: 1px 3px; - } - - abbr { - cursor: help; - text-decoration: underline; - color: #84d0ea; - } - - hr { - opacity: 0.1; - border-color: #eee; - margin: 1rem 0; - } - - /* End Base */ - - /* Header */ - header, - .main { - position: absolute; - width: 100%; - } - - header { - position: fixed; - z-index: 2000; - float: left; - height: 4rem; - transition: box-shadow 0.2s; - color: var(--header-color); - background: #2222359a; - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); - } - - header>.fill>.container { - margin-top: 0.5rem; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - padding: 0.5rem 1rem 0; - } - - header>.fill>.container>#logo { - padding: 0; - margin: 0 !important; - position: absolute; - left: 0; - top: 50%; - height: 100%; - transform: translateY(-50%); - padding: 1rem; - display: flex; - justify-content: center; - width: calc(16rem); - } - - header>.fill>.container>#logo>img { - width: auto; - height: 100%; - margin-top: -0.1rem; - } - - header>.fill>.container>.brand { - font-size: 1.4rem; - position: absolute; - cursor: default; - vertical-align: text-bottom; - text-decoration: none; - color: var(--header-color); - } - - header>.fill>.container>.status { - position: fixed; - top: 9px; - right: 1em; - float: right; - } - - header>.fill>.container>.status>* { - position: relative; - top: 0.2rem; - float: left; - left: -2.5rem; - margin-left: 0.3rem; - cursor: pointer; - } - - header>.fill>.container>.logout { - position: fixed; - top: 9px; - right: 1em; - float: right; - } - - header>.fill>.container>.logout>* { - position: relative; - top: 0.2rem; - float: left; - right: 0rem; - margin-left: 0.3rem; - cursor: pointer; - content: ""; - } - - .logout a { - position: absolute; - right: 14px; - width: 32px; - height: 32px; - content: ""; - background: url(./icon/logout.svg) no-repeat; - text-indent: -9999px; - background-size: 32px; - } - - /* End Header */ - - /* Footer */ - footer { - font-size: 0.8rem; - overflow: hidden; - text-align: center; - white-space: nowrap; - color: #000000; - padding: 1rem; - } - - footer>a { - text-decoration: none; - align-items: center; - color: #e6e6e696; - border-bottom: 0; - background-color: #2222359a; - border-radius: 10px; - padding: 9px; - padding-bottom: 3px; - padding-top: 3px; - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); - } - - small { - font-size: 90%; - line-height: 1.42857143; - white-space: normal; - } - - /* End Footer */ - - /* Navbar */ - @media screen and (min-width: 720px) { - .navbar { - position: fixed; - bottom: 50%; - transform: translateY(50%); - transition-duration: 200ms; - right: 30px; - border-top: var(--navBorder); - text-align: center; - background-color: #000000da; - box-shadow: 0 0 10px 0px #0000002d; - box-sizing: content-box; - border-radius: 10px; - } - - .navbar--hidden { - transform: translateY(60px); - box-shadow: none; - } - - .navbar .toggler { - transition-duration: 100ms; - position: absolute; - background: #ffffffb0; - box-shadow: 0 0 10px 0 #0000000f; - transform: translateY(50%); - bottom: 50%; - right: calc(100% + 10px); - width: 32px; - height: 32px; - padding: 8px; - border-radius: 100%; - content: ""; - box-sizing: border-box; - cursor: pointer; - } - - .navbar .toggler img { - transform: rotate(270deg); - } - - .navbar .dropdown { - display: flex; - flex-direction: column; - overflow: hidden; - width: 64px; - padding: 0.25rem; - } - - .navbar .dropdown a { - display: block; - text-align: center; - padding: 8px; - text-decoration: none; - max-width: 100px; - width: 100%; - } - - .navbar .dropdown a img { - width: 100%; - } - - .navbar.active { - right: -64px; - } - - .navbar.active .toggler { - right: calc(100% + 10px); - } - - .navbar.active .toggler img { - transform: rotate(90deg); - } - } - - @media screen and (max-width: 720px) { - .navbar { - - overflow: hidden; - position: fixed; - bottom: 5px; - top: auto; - left: 10px; - right: auto; - width: 95%; - align: center; - transition: transform 0.5s; - border-top: var(--navBorder); - text-align: center; - height: calc(50px + constant(safe-area-inset-bottom)); - height: calc(50px + env(safe-area-inset-bottom)); - background-color: #00000079; - border-radius: 20px; - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); - - } - - .navbar--hidden { - transform: translateY(60px); - box-shadow: none; - } - - .navbar a { - float: left; - text-align: center; - padding: 8px 0; - text-decoration: none; - } - - .navbar a img { - width: 28px; - } - } - - /* End Navbar */ - - .main { - position: relative; - top: 4rem; - bottom: 0; - overflow-y: auto; - height: calc(100% - 4rem); - } - - .main>.loading { - position: fixed; - z-index: 1000; - top: 0; - opacity: 1; - visibility: visible; - width: 100%; - height: 100%; - pointer-events: none; - background-color: rgba(0, 0, 0, 0.781); - transition: .4s ease-in-out; - border-radius: 10px; - } - - .main>.loading>span { - font-family: monospace; - font-size: 2rem; - font-size-adjust: 0.35; - position: relative; - top: 12.5%; - display: block; - text-align: center; - color: #888; - } - - .main>.loading>span>.loading-img { - display: inline-flex; - gap: 10px; - } - - .main>.loading>span>.loading-img:before, - .loading-img:after { - content: ""; - height: 20px; - aspect-ratio: 1; - border-radius: 50%; - background: - linear-gradient(#222 0 0) top/100% 0% no-repeat, - radial-gradient(farthest-side, #000 95%, #0000) 50%/8px 8px no-repeat #ffffff; - animation: l9 4s infinite ease-in; - } - - @keyframes l9 { - 0% { - background-size: 100% 0%, 8px 8px; - background-position: top, 50% 50% - } - - 80% { - background-size: 100% 70%, 8px 8px; - background-position: top, 50% 70% - } - - 84%, - 100% { - background-size: 100% 0%, 8px 8px; - background-position: top, 50% 50% - } - } - - .cbi-map { - margin-top: 10px; - } - - #cbi-shadowsocksr .cbi-map-descr { - display: none; - } - - strong { - font-weight: bold; - color: rgb(255, 255, 255); - } - - .main-right { - float: right; - width: calc(100% - 16rem); - height: 100%; - } - - .nowrap:not(.td) { - white-space: nowrap; - color: #ffffff; - } - - [disabled="disabled"] { - pointer-events: none; - } - - /* Sidebar */ - .main>.main-left { - position: fixed; - top: 4.8rem; - width: calc(0% + 16rem); - float: left; - overflow-x: auto; - background-color: #2222359a; - transition: visibility 400ms, width 400ms; - border-top-left-radius: 0px; - border-top-right-radius: 20px; - border-bottom-left-radius: 0px; - border-bottom-right-radius: 20px; - backdrop-filter: blur(20px); - -webkit-backdrop-filter: blur(20px); - height: calc(100% - 3.5rem); - - } - - .main>.main-left>.nav { - padding: 0.5rem 0.5rem 2rem; - } - - .main>.main-left>.nav>li { - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - } - - .main>.main-left>.nav>li>[data-title="Log out"], - .main>.main-left>.nav>li>[data-title="Logout"] { - display: flex; - padding: 0.5rem 1rem; - } - - .main>.main-left>.nav>li a { - display: block; - color: #cbcbcb; - } - - .main>.main-left>.nav>li>[data-title="Log out"], - .main>.main-left>.nav>li>[data-title="Logout"], - .main>.main-left>.nav>li>[data-title="iStore"] { - font-size: 1rem; - color: #fff; - } - - .main>.main-left>.nav>li.slide.active { - background-color: unset; - } - - .main>.main-left>.nav>.slide { - padding: 0; - } - - .main>.main-left>.nav>.slide>.menu, - .main>.main-left>.nav>li>[data-title="Logout"], - .main>.main-left>.nav>li>[data-title="iStore"], - .main>.main-left>.nav>li>[data-title="Dashboard"] { - font-size: 1rem; - font-weight: 500; - display: flex; - align-items: center; - width: 100%; - text-decoration: none; - color: #fff; - padding: 0.5rem 1rem; - transition-duration: 200ms; - margin-bottom: 5px; - } - - .main>.main-left>.nav>.slide>.menu::before { - position: absolute; - right: 14px; - width: 25px; - height: 25px; - content: ""; - background: url(./icon/sidebar-icon/app.svg) no-repeat; - background-size: 25px; - } - - .main>.main-left>.nav>.slide>.menu.active::before {} - - .main>.main-left>.nav>.slide>[data-title="Status"]:before { - position: absolute; - right: 14px; - width: 25px; - height: 25px; - content: ""; - background: url(./icon/sidebar-icon/status.svg) no-repeat; - background-size: 25px; - } - - .main>.main-left>.nav>.slide>[data-title="System"]:before { - position: absolute; - right: 14px; - width: 25px; - height: 25px; - content: ""; - background: url(./icon/sidebar-icon/system.svg) no-repeat; - background-size: 25px; - } - - .main>.main-left>.nav>.slide>[data-title="Services"]:before { - position: absolute; - right: 14px; - width: 25px; - height: 25px; - content: ""; - background: url(./icon/sidebar-icon/services.svg) no-repeat; - background-size: 25px; - } - - .main>.main-left>.nav>.slide>[data-title="NAS"]:before { - position: absolute; - right: 14px; - width: 25px; - height: 25px; - content: ""; - background: url(./icon/sidebar-icon/nas.svg) no-repeat; - background-size: 25px; - } - - .main>.main-left>.nav>.slide>[data-title="Modem"]:before { - position: absolute; - right: 14px; - width: 25px; - height: 25px; - content: ""; - background: url(./icon/sidebar-icon/modem.svg) no-repeat; - background-size: 25px; - } - - .main>.main-left>.nav>.slide>[data-title="Network"]:before { - position: absolute; - right: 14px; - width: 25px; - height: 25px; - content: ""; - background: url(./icon/sidebar-icon/network.svg) no-repeat; - background-size: 25px; - } - - .main>.main-left>.nav>.slide>[data-title="VPN"]:before { - position: absolute; - right: 14px; - width: 25px; - height: 25px; - content: ""; - background: url(./icon/sidebar-icon/vpn.svg) no-repeat; - background-size: 25px; - } - - .main>.main-left>.nav>.slide>[data-title="Docker"]:before { - position: absolute; - right: 14px; - width: 25px; - height: 25px; - content: ""; - background: url(./icon/sidebar-icon/docker.svg) no-repeat; - background-size: 25px; - } - - .main>.main-left>.nav>li>[data-title="iStore"]:before { - position: absolute; - right: 14px; - width: 25px; - height: 25px; - content: ""; - background: url(./icon/sidebar-icon/istore.svg) no-repeat; - background-size: 25px; - } - - /* End Sidebar */ - - .modemenu-buttons { - display: flex; - flex-wrap: wrap; - align-items: center; - color: var(--header-color); - background: var(--header-bg); - transition: box-shadow 0.2s; - box-shadow: 0 2px 5px rgb(0 0 0 / 26%); - padding: 0.5rem; - } - - #modemenu { - display: flex; - align-items: center; - flex-wrap: wrap; - margin: 0.25rem; - } - - #modemenu>li.divider { - margin-left: 0.25rem; - margin-right: 0.25rem; - border: 0.5rem solid var(--submenu-bg-hover); - border-left: 1px solid var(--submenu-bg-hover); - border-right: 1px solid var(--submenu-bg-hover); - border-radius: 1rem; - } - - .danger { - background-color: #ff7d60 !important; - } - - .warning { - background-color: #bebebe87 !important; - border-radius: 10px; - color: #fff; - } - - .success { - background-color: #5cb85c !important; - } - - .error { - color: red; - } - - .alert, - .alert-message { - font-weight: 700; - margin-bottom: 1em; - border: 0; - border-radius: 20px; - background-color: #2222359a; - padding: 1rem; - margin: 1rem; - } - - .alert-message>h4 { - font-size: 110%; - font-weight: 700; - } - - .alert-message>* { - margin: 0.5rem 0; - } - - body[class*="node-"]>.main>.main-left>.nav>.slide>.menu::before { - transition: transform 0.1s ease-in-out; - } - - body[class*="node-"]>.main>.main-left>.nav>.slide>.menu.active::before { - transition: transform 0.2s ease-in-out; - } - - .main>.main-left>.nav>li>[data-title="Logout"]::before, - .main>.main-left>.nav>li>[data-title="Log out"]::before { - position: absolute; - right: 14px; - width: 25px; - height: 25px; - content: ""; - background: url(./icon/logout.svg) no-repeat; - background-size: 25px; - } - - .main>.main-left>.nav>.slide:hover { - background: none; - } - - .main>.main-left>.nav>.slide>.slide-menu>li>a { - white-space: nowrap; - text-decoration: none; - padding: 0.4rem 2rem; - } - - .main>.main-left>.nav>.slide>.slide-menu>li:not(.active):hover>a { - color: #fff; - } - - .main>.main-left>.nav>.slide>.slide-menu>.active:hover { - background-color: var(--main-color); - } - - .main>.main-left>.nav>.slide>.menu, - .main>.main-left>.nav>.slide>.slide-menu>li, - .main>.main-left>.nav>li>[data-title="Logout"], - .main>.main-left>.nav>li>[data-title="Log out"], - .main>.main-left>.nav>li>[data-title="iStore"] { - position: relative; - overflow: hidden; - transform: translate3d(0, 0, 0); - } - - .main>.main-left>.nav>.slide>.menu::after, - .main>.main-left>.nav>.slide>.slide-menu>li::after, - .main>.main-left>.nav>li>[data-title="Logout"]::after, - .main>.main-left>.nav>li>[data-title="Log out"]::after, - .main>.main-left>.nav>li>[data-title="iStore"]::after { - position: absolute; - top: 0; - left: 0; - display: block; - width: 100%; - height: 100%; - content: ""; - transition: transform 0.5s, opacity 1s; - transform: scale(10, 10); - pointer-events: none; - opacity: 0; - background-image: radial-gradient(circle, #000 10%, transparent 10.01%); - background-repeat: no-repeat; - background-position: 50%; - } - - .main>.main-left>.nav>.slide>.menu:active::after, - .main>.main-left>.nav>.slide>.slide-menu>li:active::after, - .main>.main-left>.nav>li>[data-title="Logout"]:active::after, - .main>.main-left>.nav>li>[data-title="Log out"]:active::after, - .main>.main-left>.nav>li>[data-title="iStore"]:active::after { - transition: 0s; - transform: scale(0, 0); - opacity: 0.2; - } - - #maincontent>.container { - margin: 0 2rem 1rem; - } - - ul { - line-height: normal; - } - - li { - list-style-type: none; - } - - h1 { - font-size: 2rem; - padding-bottom: 10px; - border-bottom: thin solid #eee; - } - - h2 { - font-size: 1.8rem; - font-family: "Quicksand-Bold"; - letter-spacing: 5px; - text-align: center; - padding-bottom: 10px; - margin: 2rem 0 0; - color: #ffffff; - animation-duration: 1s; - animation-name: down; - } - - h3 { - font-size: 1.2rem; - font-family: 'Inter-Bold'; - letter-spacing: 2px; - padding-bottom: 10px; - margin: 2rem 0 0; - color: #ffffff; - } - - h4 { - font-size: 1.2rem; - color: #fff; - padding-bottom: 10px; - margin: 2rem 0 0; - } - - h5 { - font-size: 1rem; - padding-bottom: 10px; - margin: 2rem 0 0; - } - - .cbi-tab-descr { - color: #09c; - margin: 1em; - padding: 1rem; - } - - #tabmenu { - padding: 0; - } - - .cbi-section, - .cbi-section-error, - #iptables, - .Firewall form, - #cbi-network>.cbi-section-node, - #cbi-wireless>.cbi-section-node, - #cbi-wireless>#wifi_assoclist_table, - [data-tab-title], - [data-page^="admin-system-admin"]:not(.node-main-login) .cbi-map:not(#cbi-dropbear), - [data-page="admin-system-opkg"] #maincontent>.container { - font-family: inherit; - font-weight: 400; - font-style: normal; - line-height: normal; - min-width: inherit; - border: 0; - border-radius: 0; - background-color: #2222359a; - margin: 1rem 0 0; - padding: 2rem; - border-radius: 20px; - backdrop-filter: blur(20px); - -webkit-backdrop-filter: blur(20px); - } - - .cbi-modal .cbi-section, - .cbi-section .cbi-section {} - - .cbi-modal .cbi-tabmenu { - margin-left: 0; - } - - .cbi-map-descr, - .cbi-section-descr { - font-size: small; - text-align: center; - line-height: 1.42857143; - color: #999; - padding: 0.5rem; - } - - .cbi-section>legend { - display: none !important; - } - - fieldset>fieldset, - .cbi-section>.cbi-section { - border: 0; - box-shadow: none; - margin: 0; - padding: 0; - } - - .cbi-section>h3:first-child, - .panel-title { - font-size: 1.4rem; - line-height: 1; - display: block; - width: 100%; - padding-bottom: 1rem; - color: #e4e4e4; - border-bottom: thin solid #eeeeee00; - margin: 0 0 0.5rem; - } - - .cbi-section>h4:first-child, - .cbi-section>p:first-child, - [data-tab-title]>h3:first-child, - [data-tab-title]>h4:first-child, - [data-tab-title]>p:first-child { - padding-top: 1rem; - } - - table { - border-spacing: 0; - border-collapse: collapse; - } - - table, - .table { - overflow-y: hidden; - width: 100%; - border-radius: 10px; - } - - .container>.cbi-section:first-of-type>.table[width="100%"]>.tr>.td { - padding: 0.6rem; - } - - .cbi-section-table-cell { - line-height: 1.1; - align-self: flex-end; - flex: 1 1 auto; - } - - tr>td, - tr>th, - .tr>.td, - .tr>.th, - .cbi-section-table-row::before, - #cbi-wireless>#wifi_assoclist_table>.tr:nth-child(2) { - color: #ffffff; - border-top: thin solid rgba(255, 255, 255, 0); - } - - .table[width="100%"]>.tr:first-child>.td { - margin: auto 0; - } - - .cbi-section-table-row { - margin-bottom: 1rem; - text-align: center !important; - } - - .cbi-section-table-row:last-child { - margin-bottom: 0; - } - - .cbi-section-table-row>.cbi-value-field [data-dynlist]>input, - .cbi-section-table-row>.cbi-value-field input.cbi-input-password { - width: calc(100% - 1.5rem); - } - - table table, - .table .table, - .cbi-value-field table, - .cbi-value-field .table, - td>table>tbody>tr>td, - .td>.table>.tbody>.tr>.td, - .cbi-value-field>table>tbody>tr>td, - .cbi-value-field>.table>.tbody>.tr>.td { - border: 0; - } - - .btn, - .cbi-button, - .item::after { - font-size: 0.8rem; - display: inline-block; - width: auto !important; - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - transition: all 0.2s ease-in-out; - text-align: center; - vertical-align: middle; - white-space: nowrap; - text-decoration: none; - text-transform: uppercase; - color: rgba(0, 0, 0, 0.87); - border: 0; - background-color: #f0f0f0; - background-image: none; - -webkit-appearance: none; - -ms-touch-action: manipulation; - touch-action: manipulation; - padding: 0 0.8rem; - } - - .cbi-button-up { - transform: scaleY(-1); - } - - .cbi-button:not(select) { - -webkit-appearance: none !important; - } - - .cbi-button+.cbi-button { - margin-left: 0.6rem; - } - - .btn:hover, - .btn:focus, - .btn:active, - .cbi-button:hover, - .cbi-button:focus, - .cbi-button:active, - .item:hover::after, - .item:focus::after, - .item:active::after, - .cbi-page-actions .cbi-button-apply+.cbi-button-save:hover, - .cbi-page-actions .cbi-button-apply+.cbi-button-save:focus, - .cbi-page-actions .cbi-button-apply+.cbi-button-save:active { - text-decoration: none; - outline: 0; - } - - .btn:hover, - .btn:focus, - .cbi-button:hover, - .cbi-button:focus, - .item:hover::after, - .item:focus::after { - box-shadow: 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 2px rgba(0, 0, 0, 0.2); - } - - .btn:active, - .cbi-button:active, - .item:active::after { - box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); - } - - .cbi-button-up:hover, - .cbi-button-up:focus { - box-shadow: 0 0 2px rgba(0, 0, 0, 0.12), 0 -2px 2px rgba(0, 0, 0, 0.2); - } - - .cbi-button-up:active { - box-shadow: 0 -10px 20px rgba(0, 0, 0, 0.19), 0 -6px 6px rgba(0, 0, 0, 0.23); - } - - .btn:disabled, - .cbi-button:disabled { - cursor: not-allowed; - pointer-events: none; - opacity: 0.5; - box-shadow: none; - } - - .alert-message [class="btn"], - .modal div[class="btn"], - .cbi-button-find, - .cbi-button-link, - .cbi-button-up, - .cbi-button-down, - .cbi-button-neutral, - .cbi-button[name="zero"], - .cbi-button[name="restart"], - .cbi-button[onclick="hide_empty(this)"] { - font-weight: 700; - background-color: #d4d4d4; - } - - .btn.primary, - .cbi-page-actions .cbi-button-save, - .cbi-page-actions .cbi-button-apply+.cbi-button-save, - .cbi-button-add, - .cbi-button-save, - .cbi-button-positive, - .cbi-button-link, - .cbi-button[value="Enable"], - .cbi-button[value="Scan"], - .cbi-button[value^="Back"], - .cbi-button-neutral[onclick="handleConfig(event)"] { - font-weight: 400; - color: #fff; - background-color: rgba(0, 229, 255, 0.47); - border-radius: 20px; - } - - .cbi-page-actions .cbi-button-apply, - .cbi-section-actions .cbi-button-edit, - .cbi-button-edit, - .cbi-button-apply, - .cbi-button-reload, - .cbi-button-action, - .cbi-button[value="Submit"], - .cbi-button[value="Upload"], - .cbi-button[value$="Apply"], - .cbi-button[onclick="addKey(event)"] { - font-weight: 400; - color: #fff; - background-color: rgba(0, 229, 255, 0.47); - border-radius: 20px; - } - - .btn.danger, - .cbi-section-remove>.cbi-button, - .cbi-button-remove, - .cbi-button-reset, - .cbi-button-negative, - .cbi-button[value="Stop"], - .cbi-button[value="Kill"], - .cbi-button[onclick="reboot(this)"], - .cbi-button-neutral[value="Restart"] { - font-weight: 400; - color: #fff; - background-color: rgba(255, 0, 0, 0.47); - border-radius: 20px; - } - - .btn[value="Dismiss"], - .cbi-button[value="Terminate"], - .cbi-button[value="Reset"], - .cbi-button[value="Disabled"], - .cbi-button[onclick^="iface_reconnect"], - .cbi-button[onclick="handleReset(event)"], - .cbi-button-neutral[value="Disable"] { - font-weight: 400; - color: #fff; - border: thin solid #eea236; - background-color: #f0ad4e; - } - - .cbi-button-success, - .cbi-button-download, - .cbi-button[name="backup"], - .cbi-button[value="Download"], - .cbi-button[value="Save mtdblock"] { - font-weight: 400; - color: #fff; - border: thin solid #4cae4c; - background-color: #5cb85c; - } - - .a-to-btn { - text-decoration: none; - } - - .cbi-value-field .cbi-button-add { - font-weight: 700; - margin: 9px 0 4px 3px; - padding: 1px 6px; - } - - .tabs { - border-bottom: 0; - background-color: #2222359a; - border-radius: 20px; - padding: 9px; - padding-bottom: 3px; - padding-top: 3px; - backdrop-filter: blur(20px); - -webkit-backdrop-filter: blur(20px); - } - - .tabs>li, - .cbi-tabmenu>li { - display: inline-block; - cursor: pointer; - padding: 0.4rem; - margin: 0.3rem; - align-items: center; - - } - - .tool_label_span { - color: aqua; - } - - .tabs>li { - padding-bottom: 0.4rem; - } - - .tabs>li[class~="active"], - .tabs>li:hover { - border-bottom-color: var(--main-color); - } - - .tabs>li:hover { - cursor: pointer; - border-bottom-color: #c9c9c9; - } - - .tabs>li>a, - .cbi-tabmenu>li>a { - text-decoration: none; - color: #ffffff; - padding: 0.6rem 0.9rem; - - } - - .tabs>li[class~="active"]>a { - color: var(--main-color); - } - - .cbi-tabmenu { - border-bottom: 0; - background-color: #2222359a; - border-radius: 20px; - padding: 9px; - padding-bottom: 3px; - padding-top: 3px; - backdrop-filter: blur(20px); - -webkit-backdrop-filter: blur(20px); - } - - .cbi-tabmenu>li:hover { - background-color: #474747; - border-radius: 20px; - - - } - - .cbi-tabmenu>li[class~="cbi-tab"] { - background-color: #ff94946a; - border-radius: 20px; - } - - .cbi-tabmenu>li[class~=data-tab=] { - color: #ffffff; - } - - [data-tab-title] { - overflow: hidden; - height: 0; - opacity: 0; - margin: 0; - padding: 0rem 1rem !important; - } - - [data-tab-active="true"] { - overflow: visible; - height: auto; - opacity: 1; - transition: opacity 0.25s ease-in; - margin: inherit !important; - } - - .cbi-section-node-tabbed { - margin-top: 0; - border-top: 0; - padding: 0; - } - - .cbi-value-field, - .cbi-value-description { - line-height: 1.25; - display: table-cell; - } - - .cbi-value-description { - font-size: small; - padding-top: 0.4rem; - opacity: 0.5; - color: #fff; - } - - .cbi-value-title { - display: table-cell; - float: left; - width: 23rem; - padding-top: 0.35rem; - padding-right: 2rem; - text-align: right; - word-wrap: break-word; - } - - .cbi-value { - display: inline-block; - width: 100%; - padding: 0.35rem 1rem 0.2rem; - } - - .cbi-value ul { - line-height: 1.25; - } - - .cbi-value-field .cbi-dropdown, - .cbi-value-field .cbi-input-select, - .cbi-value input[type="text"], - .cbi-value input[type="password"] { - min-width: 25rem; - } - - #cbi-firewall-zone .cbi-input-select, - #cbi-network-switch_vlan .cbi-input-select { - min-width: 11rem; - } - - #cbi-network-switch_vlan .cbi-input-text { - max-width: 3rem; - } - - .cbi-input-invalid { - color: red; - border-bottom-color: red; - } - - .cbi-section-error { - font-weight: 700; - line-height: 1.42857143; - border: thin solid red; - border-radius: 3px; - background-color: #fce6e6; - margin: 18px; - padding: 6px; - } - - .cbi-section-error ul { - margin: 0 0 0 20px; - } - - .cbi-section-error ul li { - font-weight: 700; - color: red; - } - - .td[data-title]::before { - font-weight: 700; - display: none; - content: attr(data-title) ":\20"; - text-align: left; - white-space: nowrap; - padding: 0.25rem 0; - } - - .tr[data-title]::before, - .tr.cbi-section-table-titles.named::before { - font-weight: 700; - display: table-cell; - align-self: center; - flex: 1 1 5%; - content: attr(data-title) "\20"; - text-align: center; - vertical-align: middle; - white-space: normal; - word-wrap: break-word; - padding: 0.25rem; - } - - .cbi-rowstyle-2 .cbi-button-up, - .cbi-rowstyle-2 .cbi-button-down, - body:not(.Interfaces) .cbi-rowstyle-2:first-child {} - - .cbi-section-table .cbi-section-table-titles .cbi-section-table-cell { - width: auto !important; - } - - .td.cbi-section-actions { - text-align: right !important; - vertical-align: middle; - display: flex; - justify-content: center; - flex-wrap: wrap; - gap: 5px; - } - - .td.cbi-section-actions>* { - display: inline-flex; - } - - .td.cbi-section-actions>button { - display: block; - } - - .td.cbi-section-actions>*>*, - .td.cbi-section-actions>*>form>* { - margin: 0 5px; - } - - .td.cbi-section-actions>*>form { - display: inline-flex; - margin: 0; - } - - .cbi-dynlist { - line-height: 1.3; - flex-direction: column; - min-height: 30px; - cursor: text; - } - - .cbi-dynlist>.item { - position: relative; - max-width: 25rem; - margin-right: 2em; - pointer-events: none; - color: #666; - border-bottom: 2px solid rgba(0, 0, 0, 0.26); - outline: 0; - padding: 0.5em 0.25em 0.25em 0; - } - - .cbi-dynlist[name="sshkeys"]>.item { - max-width: none; - } - - .cbi-dynlist>.item::after { - font-weight: 700; - position: absolute; - right: -2em; - bottom: 0; - display: inline-flex; - min-height: 17px; - content: "\00D7"; - pointer-events: auto; - color: #fff; - border: thin solid #d43f3a; - background-color: #d9534f; - padding: 0 6px; - border-radius: 5px; - } - - .cbi-dynlist>.item>span { - white-space: normal; - word-break: break-word; - } - - .cbi-dynlist>.add-item { - display: inline-flex; - align-items: center; - width: 100%; - min-width: 16rem; - } - - .cbi-dynlist>.add-item:not([ondrop])>input { - overflow: hidden; - width: 100%; - min-width: 15rem; - white-space: nowrap; - text-overflow: ellipsis; - } - - .cbi-dynlist>.add-item[ondrop]>input { - min-width: 13rem; - } - - .cbi-dynlist, - .cbi-dropdown { - position: relative; - display: inline-flex; - padding: 0; - } - - .cbi-dropdown[placeholder*="select"] { - max-width: 25rem; - height: auto; - margin-top: -3px; - } - - .cbi-dropdown>ul { - display: flex; - overflow-x: hidden; - overflow-y: auto; - width: 100%; - list-style: none; - outline: 0; - margin: 0 !important; - padding: 0; - } - - .cbi-dropdown>.open { - flex-basis: 15px; - } - - .cbi-dropdown>.open, - .cbi-dropdown>.more { - font-size: 1rem; - font-weight: 900; - line-height: 2; - display: flex; - flex-direction: column; - flex-grow: 0; - flex-shrink: 0; - justify-content: center; - cursor: default; - text-align: center; - outline: 0; - padding: 0 0.25em; - } - - .cbi-dropdown.btn { - min-height: 1.8rem; - padding-top: 0px; - padding-bottom: 0px; - padding-right: 0px; - } - - .cbi-dropdown.btn>.open { - font-size: 0.8rem; - margin: 0 5px; - padding: 0px; - } - - .cbi-dropdown.btn>div { - margin: 0px; - } - - .cbi-dropdown>.more, - .cbi-dropdown>ul>li[placeholder] { - font-weight: 700; - display: none; - color: #777; - } - - .cbi-dropdown>ul>li { - display: none; - overflow: hidden; - align-items: center; - align-self: center; - flex-grow: 1; - flex-shrink: 1; - min-height: 20px; - white-space: nowrap; - text-overflow: ellipsis; - padding: 0.3rem 1rem 0.3rem 1rem; - } - - .cbi-dropdown>ul>li[display]:not([display="0"]) { - border-left: thin solid #ccc; - } - - .cbi-dropdown[empty]>ul { - max-width: 1px; - } - - .cbi-dropdown>ul>li>form { - display: none; - pointer-events: none; - margin: 0; - padding: 0; - } - - .cbi-dropdown>ul>li img { - margin-right: 0.25em; - vertical-align: middle; - } - - .cbi-dropdown>ul>li>form>input[type="checkbox"] { - height: auto; - margin: 0; - } - - .cbi-dropdown>ul>li input[type="text"] { - height: 20px; - } - - .cbi-dropdown[open]>ul.dropdown { - position: absolute; - z-index: 1100; - display: block; - width: auto; - min-width: 100%; - max-width: none; - max-height: 200px !important; - border: thin solid #918e8c; - background: #787878a8; - box-shadow: 0 0 4px #918e8c; - color: var(--main-menu-color); - } - - .cbi-dropdown>ul>li[display], - .cbi-dropdown[open]>ul.preview, - .cbi-dropdown[open]>ul.dropdown>li, - .cbi-dropdown[multiple]>ul>li>label, - .cbi-dropdown[multiple][open]>ul.dropdown>li, - .cbi-dropdown[multiple][more]>.more, - .cbi-dropdown[multiple][empty]>.more { - display: flex; - align-items: center; - flex-grow: 1; - justify-content: space-around; - } - - .cbi-dropdown[open]>ul.dropdown>li {} - - .cbi-dropdown[open]>ul.dropdown>li[selected] { - background: #b0d0f0; - } - - .cbi-dropdown[open]>ul.dropdown>li.focus { - background: linear-gradient(90deg, #a3c2e8 0%, #84aad9 100%); - } - - .cbi-dropdown[open]>ul.dropdown>li:last-child { - margin-bottom: 0; - } - - .cbi-dropdown[open]>ul.dropdown>li[unselectable] { - opacity: 0.7; - } - - .cbi-dropdown[disabled] { - pointer-events: none; - opacity: 0.6; - } - - .cbi-dropdown[open] .zonebadge { - width: auto; - } - - .cbi-progressbar { - border-radius: 15px; - overflow: hidden; - position: relative; - min-width: 170px; - height: 30px; - background: #11111d61; - margin: 6px 0; - } - - .cbi-progressbar title { - font-family: "Quicksand-Bold"; - letter-spacing: 5px; - text-align: center; - padding-bottom: 10px; - margin: 2rem 0 0; - color: #ffffff; - } - - .cbi-progressbar>div { - width: 0; - height: 100%; - transition: width 2s ease-in; - background: #0099cc; - padding: 0.5rem; - } - - .cbi-progressbar::after { - font-family: monospace; - font-size: 1.2em; - font-weight: 700; - font-size-adjust: 0.38; - line-height: normal; - position: absolute; - top: 50%; - transform: translateY(-50%); - right: 0; - left: 0; - overflow: hidden; - content: attr(title); - text-align: center; - white-space: pre; - text-overflow: ellipsis; - text-shadow: 0 0 2px #eee; - } - - #modal_overlay { - position: fixed; - z-index: 900; - top: 4rem; - right: 10000px; - bottom: 0; - left: -10000px; - overflow-y: scroll; - transition: opacity 0.125s ease-in; - opacity: 0; - background: rgba(0, 0, 0, 0.7); - -webkit-overflow-scrolling: touch; - } - - .modal { - display: flex; - align-items: center; - flex-wrap: wrap; - width: 90%; - min-width: 270px; - max-width: 600px; - min-height: 32px; - border-radius: 20px !important; - background: #8f8f8f75; - margin: 5em auto; - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); - padding: 1em; - - } - - .modal>* { - line-height: normal; - flex-basis: 100%; - margin-bottom: 0.5em; - max-width: 100%; - } - - .modal>pre, - .modal>textarea { - font-size: 1rem; - font-size-adjust: 0.35; - overflow: auto; - margin-bottom: 0.5em; - cursor: auto; - white-space: pre-wrap; - color: #eee; - outline: 0; - background-color: #101010; - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 2px 0 rgba(0, 0, 0, 0.12); - padding: 8.5px; - } - - .modal>h4 { - margin: 0.5em 0; - } - - .modal ul { - margin-left: 2.2em; - } - - .modal li { - list-style-type: square; - color: rgb(216, 216, 216); - } - - .modal p { - padding-left: 0.25rem; - word-break: break-word; - } - - .modal .label { - font-size: 0.6rem; - font-weight: 400; - cursor: default; - border-radius: 0; - padding: 0.1rem 0.3rem 0; - } - - .modal .label.warning { - background-color: #f0ad4e !important; - } - - .modal.cbi-modal { - max-width: 90%; - max-height: none; - } - - body.modal-overlay-active { - overflow: hidden; - height: 100vh; - } - - body.modal-overlay-active #modal_overlay { - right: 0; - left: 0; - opacity: 1; - } - - .spinning { - position: relative; - align-items: center; - padding-left: 32px !important; - color: #fff; - } - - .spinning::before { - position: absolute; - font-size: medium; - font-style: "Quicksand-Bold"; - left: 8px; - width: 16px; - height: 16px; - content: ""; - animation: anim-rotate 2s infinite cubic-bezier(0.18, 0.89, 0.32, 1.28); - background: url(./icon/loading.svg) no-repeat center; - background-size: 20px; - } - - .left, - .left::before { - text-align: left !important; - } - - .right, - .right::before { - text-align: right !important; - } - - .top { - align-self: flex-start !important; - vertical-align: top !important; - } - - .bottom { - align-self: flex-end !important; - vertical-align: bottom !important; - } - - .inline { - display: inline; - } - - .cbi-page-actions { - padding-top: 1rem; - text-align: center; - } - - .cbi-page-actions>form[method="post"] { - display: inline-block; - } - - .th[data-type="button"], - .td[data-type="button"], - .th[data-type="fvalue"], - .td[data-type="fvalue"] { - flex: 1 1 2em; - text-align: center; - } - - .ifacebadge { - display: inline-flex; - background: #ffffff33; - padding: 0.5rem 0.8rem; - border-radius: 10px; - } - - td>.ifacebadge, - .td>.ifacebadge { - font-size: 0.8rem; - background-color: #000000; - border-radius: 10px; - } - - .ifacebadge>em, - .ifacebadge>img { - display: inline-block; - align-self: flex-start; - margin: 0 0.2rem; - } - - .ifacebadge>img+img { - margin: 0 0.2rem 0 0; - } - - .network-status-table .ifacebox { - flex-grow: 1; - margin: 0.5em; - } - - .network-status-table .ifacebox-body { - display: flex; - flex-direction: column; - height: 100%; - } - - .network-status-table .ifacebox-body>span { - flex: 10 10 auto; - height: 100%; - } - - .network-status-table .ifacebox-body .ifacebadge { - align-items: center; - flex: 1 1 auto; - min-width: 220px; - background-color: #11111d; - margin: 0.5em 0.25em 0; - padding: 0.5em; - border-radius: 10px; - } - - .cbi-input-textarea { - font-family: monospace; - width: 100%; - min-height: 14rem; - color: #000; - padding: 0.8rem; - } - - #syslog { - font-size: small; - overflow-y: hidden; - width: 100%; - min-height: 15rem; - resize: none; - color: #eee; - border: 0; - border-radius: 20px; - background-color: #10101057; - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 2px 0 rgba(0, 0, 0, 0.12); - padding: 1rem; - } - - #syslog:focus { - outline: 0; - } - - .uci-change-list { - font-family: monospace; - } - - .uci-change-list ins, - .uci-change-legend-label ins { - display: block; - text-decoration: none; - border: thin solid #0f0; - background-color: #cfc; - padding: 2px; - } - - .uci-change-list del, - .uci-change-legend-label del { - font-style: normal; - display: block; - text-decoration: none; - border: thin solid red; - background-color: #fcc; - padding: 2px; - } - - .uci-change-list var, - .uci-change-legend-label var { - font-style: normal; - display: block; - text-decoration: none; - border: thin solid #ccc; - background-color: #eee; - padding: 2px; - } - - .uci-change-list var ins, - .uci-change-list var del { - font-style: normal; - white-space: pre; - border: 0; - padding: 0; - } - - .uci-change-legend { - padding: 5px; - } - - .uci-change-legend-label { - float: left; - width: 150px; - color: #fff; - } - - .uci-change-legend-label>ins, - .uci-change-legend-label>del, - .uci-change-legend-label>var { - display: block; - float: left; - width: 10px; - height: 10px; - margin-right: 4px; - } - - .uci-change-legend-label var ins, - .uci-change-legend-label var del { - line-height: 0.4; - border: 0; - } - - #iwsvg, - #iwsvg2, - #bwsvg { - border: thin solid #d4d4d4 !important; - } - - .ifacebox { - line-height: 1.25; - display: inline-flex; - flex-direction: column; - min-width: 100px; - background-color: #54545450; - border-radius: 20px; - flex-wrap: nowrap; - align-content: center; - justify-content: flex-start; - align-items: center; - color: #fff; - } - - div.ifacebox-head { - --zone-color-rgb: 144, 240, 144; - background-color: rgb(43, 79, 43); - } - - style attribute { - --zone-color-rgb: 144, 240, 144; - background-color: rgb(43, 79, 43); - } - - .ifacebox-head { - background: #939393; - padding: 0.25em; - color: #fff; - } - - .ifacebox-head.active { - background: var(--bar-bg); - } - - .ifacebox-body { - padding: 0.25em; - } - - .cbi-image-button { - margin-left: 0.5rem; - } - - .zonebadge { - display: inline-block; - padding: 0.2rem 0.5rem; - } - - .zonebadge .ifacebadge { - border: thin solid #6c6c6c; - margin: 0.1rem 0.2rem; - padding: 0.2rem 0.3rem; - } - - .zonebadge>input[type="text"] { - min-width: 10rem; - margin-top: 0.3rem; - padding: 0.16rem 1rem; - } - - .zonebadge>em, - .zonebadge>strong { - display: inline-block; - margin: 0 0.2rem; - } - - .cbi-value-field .cbi-input-checkbox, - .cbi-value-field .cbi-input-radio { - margin-top: 0.1rem; - } - - .cbi-value-field>ul>li .ifacebadge { - margin-top: -0.5rem; - margin-left: 0.4rem; - background-color: #eee; - } - - .cbi-section-table-row>.cbi-value-field .cbi-dropdown { - min-width: 7rem; - } - - .cbi-section-create { - display: inline-flex; - align-items: center; - margin: 0.5rem -3px; - } - - .cbi-section-create>* { - margin: 0.5rem; - } - - div.cbi-value var, - td.cbi-value-field var, - .td.cbi-value-field var { - font-style: italic; - color: #0069d6; - } - - .cbi-optionals { - border-top: thin solid #ccc; - padding: 1rem 1rem 0; - } - - .cbi-dropdown-container { - position: relative; - } - - .cbi-tooltip-container, - span[data-tooltip], - span[data-tooltip] .label { - cursor: help !important; - text-align: left !important; - font-size: 80% !important; - color: #fff !important; - } - - .cbi-tooltip { - position: absolute; - z-index: 1000; - left: -1000px; - transition: opacity 0.25s ease-out; - white-space: pre; - pointer-events: none; - opacity: 0; - border-radius: 20px; - background: #54545450; - box-shadow: 0 0 2px #444; - padding: 2px 5px; - -webkit-backdrop-filter: blur(20px); - backdrop-filter: blur(20px); - - } - - .cbi-tooltip-container:hover .cbi-tooltip { - left: auto; - transition: opacity 0.25s ease-in; - opacity: 1; - } - - .zonebadge .cbi-tooltip { - background: inherit; - margin: -1.5rem 0 0 -0.5rem; - padding: 0.25rem; - } - - .zonebadge-empty { - color: #404040; - background: repeating-linear-gradient(45deg, - rgba(204, 204, 204, 0.5), - rgba(204, 204, 204, 0.5) 5px, - rgba(255, 255, 255, 0.5) 5px, - rgba(255, 255, 255, 0.5) 10px); - } - - .zone-forwards { - display: flex; - min-width: 10rem; - } - - .zone-forwards>* { - flex: 1 1 45%; - } - - .zone-forwards>span { - flex-basis: 10%; - text-align: center; - padding: 0 0.25rem; - } - - .zone-forwards .zone-src, - .zone-forwards .zone-dest { - display: flex; - flex-direction: column; - } - - label>input[type="checkbox"], - label>input[type="radio"] { - position: relative; - top: 0.4rem; - right: 0.2rem; - vertical-align: bottom; - margin: 0; - } - - label[data-index][data-depends] { - padding-right: 2em; - } - - .darkMask { - position: fixed; - z-index: 99; - width: 100%; - height: 100%; - content: ""; - transition: opacity 400ms, visibility 400ms; - visibility: hidden; - opacity: 0; - background-color: #2222359a; - } - - #diag-rc-output>pre, - #command-rc-output>pre, - [data-page="admin-services-wol"] .notice code { - font-size: 1.2rem; - font-size-adjust: 0.35; - line-height: normal; - display: block; - overflow-y: hidden; - width: 100%; - white-space: pre; - color: #eee; - background-color: #101010; - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 2px 0 rgba(0, 0, 0, 0.12); - padding: 8.5px; - } - - input[name="ping"], - input[name="traceroute"], - input[name="nslookup"] { - width: 80%; - } - - .node-main-login>.main fieldset { - display: inline; - overflow: hidden; - margin-bottom: 1rem; - border: 0; - background: none; - box-shadow: none; - padding: 0.5rem; - } - - .node-main-login>.main .cbi-value-title { - width: 9.5rem; - } - - .node-main-login>.main #maincontent { - text-align: center; - } - - .node-main-login>.main .container { - display: inline-block; - margin-top: 2rem !important; - text-align: left; - background-color: #2e2b2b00; - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 2px 0 rgba(0, 0, 0, 0.12); - padding: 1rem 3.5rem 2rem; - } - - .node-main-login>.main .cbi-value>* { - display: inline-block !important; - } - - .node-main-login>.main .cbi-input-text { - width: 100% !important; - min-width: 15rem; - } - - .node-status-overview>.main fieldset:nth-child(4) .td:nth-child(2), - .node-status-processes>.main .table .tr .td:nth-child(3) { - white-space: normal; - } - - [data-page="admin-system-reboot"] p { - padding-left: 2rem; - } - - [data-page="admin-system-reboot"] p>span { - position: relative; - top: 0.1rem; - left: 1rem; - } - - #cbi-samba [data-tab="template"] .cbi-value-title { - width: auto; - padding-bottom: 0.6rem; - } - - .controls>*>.btn:not([aria-label$="page"]) { - flex-grow: initial !important; - margin-top: 0.1rem; - } - - .controls>#pager>.btn[aria-label$="page"] { - font-size: 1.4rem; - font-weight: 700; - } - - .controls>*>label { - margin-bottom: 0.2rem; - } - - [data-page="admin-system-opkg"] div.btn { - display: inline; - padding: 0.3rem 0.6rem; - } - - [data-page^="admin-system-admin"]:not(.node-main-login) .cbi-map:not(#cbi-dropbear), - [data-page="admin-system-opkg"] #maincontent>.container { - margin-top: 2rem; - padding-top: 0.1rem; - } - - [data-page="admin-system-opkg"] #maincontent>.container { - margin: 2rem 2rem 1rem; - } - - .td.version, - .td.size { - white-space: normal !important; - word-break: break-word; - } - - .cbi-tabmenu+.cbi-section { - margin-top: 0; - } - - #cbi-wireless>#wifi_assoclist_table>.tr { - box-shadow: inset 1px -1px 0 #ddd, inset -1px -1px 0 #ddd; - } - - #cbi-wireless>#wifi_assoclist_table>.tr.placeholder>.td { - right: 33px; - bottom: 33px; - left: 33px; - border-top: thin solid #ddd !important; - } - - #cbi-wireless>#wifi_assoclist_table>.tr.table-titles { - box-shadow: inset 1px 0 0 #ddd, inset -1px 0 0 #ddd; - } - - #cbi-wireless>#wifi_assoclist_table>.tr.table-titles>.th { - border-bottom: thin solid #ddd; - box-shadow: 0 -1px 0 0 #ddd; - } - - #wifi_assoclist_table>.tr>.td[data-title="RX Rate / TX Rate"] { - width: 23rem; - } - - #iptables { - margin: 0; - } - - .Firewall form { - box-shadow: none; - margin: 2rem 2rem 0 0; - padding: 0; - } - - #cbi-firewall-redirect table *, - #cbi-network-switch_vlan table *, - #cbi-firewall-zone table * { - font-size: small; - } - - #cbi-firewall-redirect table input[type="text"], - #cbi-network-switch_vlan table input[type="text"], - #cbi-firewall-zone table input[type="text"] { - width: 5rem; - } - - #cbi-firewall-redirect table select, - #cbi-network-switch_vlan table select, - #cbi-firewall-zone table select { - min-width: 3.5rem; - } - - #cbi-network-switch_vlan .th, - #cbi-network-switch_vlan .td { - flex-basis: 12%; - } - - #applyreboot-container { - margin: 2rem; - } - - #applyreboot-section { - line-height: 300%; - margin: 2rem; - } - - .OpenVPN a { - line-height: initial !important; - } - - .commandbox { - width: 24% !important; - border-bottom: thin solid #ccc; - background: #eee; - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), - 0 1px 2px rgba(0, 0, 0, 0.05); - margin: 10px 0 0 10px !important; - padding: 0.5rem 1rem; - } - - .commandbox h3 { - line-height: normal !important; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - margin: 6px 0 !important; - } - - .commandbox div { - left: auto !important; - } - - .commandbox code { - position: absolute; - overflow: hidden; - max-width: 60%; - margin-left: 4px; - white-space: nowrap; - text-overflow: ellipsis; - padding: 2px 3px; - } - - .commandbox code:hover { - overflow-y: auto; - max-height: 50px; - white-space: normal; - } - - .commandbox p:first-of-type { - margin-top: -6px; - } - - .commandbox p:nth-of-type(2) { - margin-top: 2px; - } - - #command-rc-output .alert-message { - line-height: 1.42857143; - position: absolute; - top: 40px; - right: 32px; - max-width: 40%; - animation: anim-fade-in 1.5s forwards; - word-break: break-word; - opacity: 0; - margin: 0; - } - - .table[width="100%"], - .th[width="100%"], - .td[width="100%"], - .cbi-section-table-row>.cbi-value-field .cbi-dropdown, - .cbi-section-table-row>.cbi-value-field .cbi-input-select, - .cbi-section-table-row>.cbi-value-field .cbi-input-text, - .cbi-section-table-row>.cbi-value-field .cbi-input-password, - .cbi-dropdown[open]>ul.dropdown>li>input.create-item-input:first-child:last-child, - .cbi-dropdown .zonebadge, - .node-main-login>.main>.main-right, - #cbi-firewall-zone .td, - #cbi-network-switch_vlan .td { - width: 100%; - min-width: 60px; - } - - .cbi-rowstyle-2 { - background-color: ; - } - - .pull-right, - .node-main-login>.main form>div:last-child { - float: right; - } - - .pull-left, - .cbi-page-actions .cbi-button-link:first-child { - float: left; - } - - #modemenu>li>a, - .label { - background-color: rgb(104, 104, 104); - color: #fff !important; - font-size: 0.8rem; - font-weight: 700; - text-decoration: none; - text-shadow: none; - text-transform: uppercase; - white-space: nowrap; - padding: 0.3rem 0.8rem; - border-radius: 10px; - } - - [data-indicator="poll-status"][data-style="active"] { - position: absolute; - right: 14px; - width: 32px; - height: 32px; - content: ""; - background: url(./icon/loading.svg) no-repeat; - text-indent: -9999px; - animation: anim-rotate 5s infinite ease-in-out; - background-size: 32px; - } - - [data-indicator="poll-status"][data-style="inactive"] { - position: absolute; - right: 14px; - width: 32px; - height: 32px; - content: ""; - background: url(./icon/pause.svg) no-repeat; - text-indent: -9999px; - background-size: 32px; - } - - - [data-indicator="uci-changes"][data-style="active"] { - position: absolute; - width: 32px; - height: 32px; - content: ""; - background: url(./icon/save.svg) no-repeat; - text-indent: -9999px; - background-size: 32px; - } - - #modemenu>li>a.active, - .notice { - background-color: rgb(66, 66, 66) !important; - } - - #xhr_poll_status, - .cbi-value-field>ul>li { - display: flex; - } - - .alert-message .btn, - .modal .btn { - padding: 0.3rem 0.6rem; - } - - .container .alert, - .container .alert-message, - .cbi-map-descr+fieldset { - margin-top: 1rem; - } - - .main>.main-left>.nav, - .cbi-value-field>ul>li>label { - margin-top: 0.5rem; - } - - .main>.main-left>.nav>li.active>a, - .main>.main-left>.nav>.slide>.slide-menu>.active>a { - color: #fff; - } - - .main>.main-left>.nav>li.active, - .main>.main-left>.nav>.slide>.slide-menu>.active { - - background-color: var(--submenu-bg-hover-active); - border-radius: 10px; - } - - .main>.main-left>.nav>.slide>ul, - .main>.main-left[style*="overflow: hidden"]>.nav>.slide>.menu::before, - .tr.placeholder .td[data-title]::before, - .cbi-dropdown>ul.preview, - .cbi-dropdown>ul>li .hide-close, - .cbi-dropdown[open]>ul.dropdown>li .hide-open, - .hidden, - .showSide, - .node-main-login>.main>.main-left, - [data-page^="admin-system-commands"] .panel-title, - [data-page^="command-cfg"] .mobile-hide, - [data-page^="command-cfg"] .showSide { - display: none; - } - - .main>.main-left>.nav>.slide.active>ul, - .cbi-dropdown[empty]>ul>li, - .cbi-dropdown[optional][open]>ul.dropdown>li[placeholder], - .cbi-dropdown[multiple][open]>ul.dropdown>li>form, - .node-main-login>.main .cbi-value, - #cbi-samba [data-tab="template"] .cbi-value-field, - #cbi-firewall-zone .table, - #cbi-network-switch_vlan .table { - display: block; - } - - .main>.main-left>.nav>li:hover, - .main>.main-left>.nav>.slide>.menu:hover, - .main>.main-left>.nav>.slide>.slide-menu>li:hover { - background: var(--submenu-bg-hover); - border-radius: 10px; - } - - table>tbody>tr>td, - table>tbody>tr>th, - table>tfoot>tr>td, - table>tfoot>tr>th, - table>thead>tr>td, - table>thead>tr>th, - .table>.tbody>.tr>.td, - .table>.tbody>.tr>.th, - .table>.tfoot>.tr>.td, - .table>.tfoot>.tr>.th, - .table>.thead>.tr>.td, - .table>.thead>.tr>.th, - .table>.tr>.td.cbi-value-field, - .table>.tr>.th.cbi-section-table-cell, - .uci-change-list var, - .uci-change-list del, - .uci-change-list ins, - .cbi-section-remove { - padding: 0.5rem; - } - - #cbi-wireless .td, - #cbi-network .tr:first-child>.td, - .table[width="100%"]>.tr:first-child>.td, - [data-page="admin-network-diagnostics"] .tr>.td, - .tr.table-titles>.th, - .tr.cbi-section-table-titles>.th, - #iwsvg, - [data-page="admin-status-realtime-bandwidth"] #bwsvg { - border-top: 0 !important; - } - - .cbi-section-table-row .td, - .center, - .center::before { - text-align: center !important; - } - - div>table>tbody>tr:nth-of-type(2n), - div>.table>.tr:nth-of-type(2n), - .cbi-section .cbi-section-remove:nth-of-type(2n), - .container>.cbi-section .cbi-section-node:nth-of-type(2n), - .cbi-section[id] .cbi-section-remove:nth-of-type(4n + 3), - .cbi-section[id] .cbi-section-node:nth-of-type(4n + 4), - .cbi-tabcontainer>.cbi-value:nth-of-type(2n), - .cbi-rowstyle-1 {} - - .cbi-dropdown>ul>li .hide-open, - .cbi-dropdown[open]>ul.dropdown>li .hide-close { - display: initial; - } - - .network-status-table, - .network-status-table .ifacebox-body>div { - display: flex; - flex-wrap: wrap; - } - - [data-page="admin-network-diagnostics"] .table, - .node-main-login .cbi-section { - box-shadow: none; - } - - @keyframes down { - from { - margin-left: 50%; - opacity: 0; - } - - to { - margin-left: 0%; - opacity: 1; - } - } - - @keyframes anim-rotate { - 0% { - -webkit-transform: rotate(0); - -ms-transform: rotate(0); - transform: rotate(0); - } - - 100% { - -webkit-transform: rotate(360deg); - -ms-transform: rotate(360deg); - transform: rotate(360deg); - } - } - - @media screen and (min-height: 585px) { - .node-main-login footer { - position: absolute; - bottom: 0; - width: 100%; - } - } - - @keyframes anim-fade-in { - 100% { - opacity: 1; - } - } - - @media all and (-ms-high-contrast: none) { - .main>.main-left>.nav>.slide>.menu::before { - top: 30.25%; - } - - .main>.main-left>.nav>li:last-child::before { - top: 20%; - } - - .showSide::before { - top: -12px; - } - } - - @media screen and (max-width: 1600px) { - header>.fill>.container { - display: flex; - align-items: center; - margin-top: 0; - } - - header>.fill>.container>#logo { - width: calc(13rem); - } - - .main>.main-left { - width: calc(0% + 13rem); - } - - .main>.main-right { - width: calc(100% - 13rem); - } - - .btn:not(button), - .cbi-button { - font-size: 0.8rem; - padding: 0.3rem 0.6rem; - position: relative; - /*bottom: -0.5rem;*/ - } - - .label, - [data-indicator] { - padding: 0.2rem 0.6rem; - } - - fieldset, - .cbi-section { - padding: 1rem; - } - - .cbi-value-title { - width: 15rem; - padding-right: 0.6rem; - } - - .cbi-value-field .cbi-dropdown, - .cbi-value-field .cbi-input-select, - .cbi-value input[type="text"], - .cbi-value input[type="password"] { - min-width: 22rem; - } - - #cbi-firewall-zone .cbi-input-select { - min-width: 9rem; - } - - .cbi-input-textarea { - font-size: small; - } - - .node-admin-status>.main fieldset li>a { - padding: 0.3rem 0.6rem; - } - } - - @media screen and (max-width: 2000000000px) { - header { - height: 3.5rem; - } - - header>.fill>.container { - margin-top: 0.25rem; - cursor: default; - padding: 0.5rem 1rem; - } - - .main { - top: 3.5rem; - height: calc(100% - 3.5rem); - } - - .main>.main-left { - top: 4.3rem; - width: calc(0% + 13rem); - height: calc(100% - 3.5rem); - } - - .main>.main-right { - width: calc(100% - 13rem); - } - - .tabs>li>a, - .cbi-tabmenu>li>a { - padding: 0.2rem 0.5rem; - } - - .cbi-section>h3:first-child, - .panel-title { - font-size: 1.1rem; - padding-bottom: 1rem; - } - - table { - font-size: 0.7rem !important; - width: 100% !important; - } - - .table .cbi-input-text { - width: 100%; - } - - .cbi-value-field .cbi-dropdown, - .cbi-value-field .cbi-input-select, - .cbi-value input[type="text"], - .cbi-value input[type="password"] { - min-width: 19rem; - } - - #cbi-firewall-zone .cbi-input-select { - min-width: 4rem; - } - - .main>.main-left>.nav>li, - .main>.main-left>.nav>li a, - .main>.main-left>.nav>.slide>.menu, - .main>.main-left>.nav>li>[data-title="Logout"], - .main>.main-left>.nav>li>[data-title="Logout"], - .main>.main-left>.nav>li>[data-title="iStore"] { - font-size: 1rem; - color: #fff; - } - - .main>.main-left>.nav>.slide>.slide-menu>li>a { - font-size: 0.7rem; - color: #fff; - } - - #modal_overlay { - top: 3.5rem; - } - - [data-page="admin-network-firewall-forwards"] .table:not(.cbi-section-table) { - display: block; - } - - [data-page="admin-network-firewall-forwards"] .table:not(.cbi-section-table), - [data-page="admin-network-firewall-rules"] .table:not(.cbi-section-table), - [data-page="admin-network-hosts"] .table, - [data-page="admin-network-routes"] .table { - overflow-y: visible; - } - - .commandbox { - width: 32% !important; - } - } - - @media screen and (max-width: 1152px) { - header>.fill>.container>.brand { - position: relative; - } - - html, - .main { - overflow-y: visible; - } - - .main>.loading>span { - top: 25%; - } - - .main>.main-left { - position: fixed; - z-index: 100; - visibility: hidden; - } - - .main>.main-right { - width: 100%; - } - - .showSide { - position: -webkit-sticky; - position: sticky; - top: 0rem; - display: inline-flex; - align-items: center; - height: 100%; - margin-right: 0.7rem; - cursor: pointer; - } - - body:not(.logged-in) .showSide { - visibility: hidden; - width: 0; - margin: 0; - } - - .cbi-value-title { - width: 12rem; - padding-right: 1rem; - } - - .cbi-value-field .cbi-dropdown, - .cbi-value-field .cbi-input-select, - .cbi-value input[type="text"] { - width: 16rem; - min-width: 16rem; - color: rgb(255, 255, 255); - } - - .cbi-value input[type="password"], - .cbi-value input[name^="pw"], - .cbi-value input[data-update="change"]:nth-child(2) { - width: 13rem !important; - min-width: 13rem; - color: #fff; - } - - #diag-rc-output>pre, - #command-rc-output>pre, - [data-page="admin-services-wol"] .notice code { - font-size: 1rem; - } - - .Interfaces .table { - overflow-x: hidden; - } - - #packages.table { - display: grid; - } - - .tr { - display: flex; - flex-direction: row; - flex-wrap: wrap; - } - - .Overview .table[width="100%"]>.tr { - flex-wrap: nowrap; - } - - .tr.placeholder { - border-bottom: thin solid #ddd; - } - - .tr.placeholder>.td, - #cbi-firewall .tr>.td, - #cbi-network .tr:nth-child(2)>.td, - .cbi-section #wifi_assoclist_table .tr>.td { - border-top: 0; - } - - .th, - .td { - display: inline-block; - align-self: flex-start; - flex: 2 2 25%; - text-overflow: ellipsis; - word-wrap: break-word; - } - - .td select, - .td input[type="text"] { - width: 100%; - word-wrap: normal; - } - - .td [data-dynlist]>input, - .td input.cbi-input-password { - width: calc(100% - 1.5rem); - } - - .td[data-type="button"], - .td[data-type="fvalue"] { - flex: 1 1 12.5%; - text-align: left; - } - - .th.cbi-value-field, - .td.cbi-value-field, - .th.cbi-section-table-cell, - .td.cbi-section-table-cell { - flex-basis: auto; - padding-top: 1rem; - } - - .cbi-section-table-row { - display: flex; - flex-direction: row; - flex-wrap: wrap; - justify-content: space-between; - } - - .td.cbi-value-field, - .cbi-section-table-cell { - display: inline-block; - flex: 10 10 auto; - flex-basis: 50%; - text-align: center; - } - - .td.cbi-section-actions { - vertical-align: bottom; - } - - .tr[data-title]::before, - .tr.cbi-section-table-titles.named::before { - font-size: 0.9rem; - display: block; - flex: 1 1 100%; - border-bottom: thin solid rgba(0, 0, 0, 0.26); - background: #90c0e0; - } - - .cbi-button+.cbi-button { - margin-left: 0; - } - - .td.cbi-section-actions>*>*, - .td.cbi-section-actions>*>form>* { - margin: 2.1px 3px; - } - - .Firewall form { - position: static !important; - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 2px 0 rgba(0, 0, 0, 0.12); - margin: 0 0 2rem; - padding: 2rem; - } - - .Firewall form input { - width: 100% !important; - margin: 1rem 0 0; - } - - .Firewall .center, - .Firewall .center::before { - text-align: left !important; - } - - .commandbox { - width: 100% !important; - margin-left: 0 !important; - } - - .tr.table-titles, - .tr.cbi-section-table-titles, - .tr.cbi-section-table-descr { - display: none; - } - - .node-main-login>.main .cbi-value-title, - .td[data-title], - [data-page^="admin-status-realtime"] .td[id] { - text-align: left; - color: #ffffff; - } - - .table, - .td[data-title]::before { - display: block; - } - } - - @media screen and (max-width: 600px) { - header>.fill>.container>#logo { - padding: 1rem; - margin: 0; - position: absolute; - left: 50%; - top: 0; - width: 100px; - transform: translateX(-50%); - } - - header>.fill>.container>#logo>img { - width: 100%; - margin-top: 0; - } - - .cbi-progressbar::after { - font-size: 0.95em; - line-height: 1.5; - } - - fieldset, - .cbi-section { - margin: 1rem 0 0; - } - - } - - #maincontent>.container { - margin: 0 0.5rem 1.5rem; - } - - .main>.main-left>.nav>.slide>.menu, - .main>.main-left>.nav>li>[data-title="Logout"], - .main>.main-left>.nav>li>[data-title="Log out"], - .main>.main-left>.nav>li>[data-title="iStore"] { - font-size: 1.1rem; - } - - .cbi-value-title { - display: block; - min-width: 0 !important; - text-align: left; - margin: 0.5rem 0; - } - - .cbi-value>.cbi-value-field { - display: inline-block; - } - - .tabs>li>a, - .cbi-tabmenu>li>a { - padding: 0.2rem 0.3rem; - } - - .cbi-page-actions>.cbi-button { - margin-top: 0.2rem; - } - - .node-main-login>.main .container { - margin: 2rem 1.2rem 1.5rem !important; - padding: 0.3rem 1.7rem 2rem 1.6rem; - } - - .node-main-login>.main .cbi-value { - padding: 0; - } - - .node-main-login>.main form>div:last-child { - margin-top: 2rem; - } - - .node-main-login>.main .cbi-value-title { - font-size: 1.2rem; - width: 100% !important; - } - - .node-main-login>.main fieldset { - margin: 0; - padding: 0.5rem; - } - - .commandbox p:first-of-type { - margin-top: -8px; - } - - #syslog, - #diag-rc-output>pre, - #command-rc-output>pre, - [data-page="admin-services-wol"] .notice code { - font-size: 0.8rem !important; - } - - h2 {} - - .cbi-section>h3:first-child, - .panel-title { - font-size: 1.2rem; - padding-bottom: 1rem; - } - - .node-system-packages>.main .cbi-value.cbi-value-last>div { - width: 100% !important; - } - - .th, - .td { - flex-basis: 50%; - color: #fff; - } - - .tr>.td[data-title="Sensor"] { - text-align: center; - } - - .tr>.td[data-title="Temperature"] { - text-align: center; - } - - .tr>.td[data-title="Hostname"] { - text-align: center; - } - - .tr>.td[data-title="IPv4 address"] { - text-align: center; - } - - .tr>.td[data-title="MAC address"] { - text-align: center; - } - - .tr>.td[data-title="Lease time remaining"] { - text-align: center; - } - - - .td.cbi-value-field { - flex-basis: 100%; - } - - .td.cbi-value-field[data-type="button"], - .td.cbi-value-field[data-type="fvalue"] { - flex-basis: 25%; - text-align: left; - } - - td>.ifacebadge, - .td>.ifacebadge { - font-size: 0.62rem; - } - - #cbi-wireless>#wifi_assoclist_table .td { - overflow: hidden; - } - - #cbi-wireless>.cbi-section-node .td, - .Interfaces .td.cbi-section-actions { - text-align: center !important; - } - - .cbi-modal { - padding: 0.5rem; - } - - .cbi-modal .cbi-value { - padding: 0 0 0.25rem; - } - - .cbi-modal [data-tab-title] { - padding: 0 0.25rem !important; - } - - [data-tab-title] { - padding: 0 0.5rem !important; - } - - body, - code { - font-size: 0.8rem; - } - - .main>.main-left>.nav>.slide>.slide-menu>li>a, - .tr[data-title]::before, - .tr.cbi-section-table-titles.named::before { - font-size: - } - - .cbi-value-title, - .cbi-value-description, - .cbi-value-field, - .cbi-value-field .cbi-dropdown, - .cbi-value-field .cbi-input-select, - .cbi-value input[type="text"], - .node-system-packages>.main .cbi-value .cbi-value-field input { - width: 100%; - display: flex; - color: #fff; - flex-direction: column-reverse; - flex-wrap: wrap; - align-content: stretch; - align-items: flex-start; -} - } - - .cbi-page-actions>div>input, - .mobile-hide, - [data-page="admin-status-processes"] .td[data-title="Hang Up"]::before, - [data-page="admin-status-processes"] .td[data-title="Terminate"]::before, - [data-page="admin-status-processes"] .td[data-title="Kill"]::before, - .hide-sm, - .hide-xs:not([data-title="MAC-Address"]) { - display: none; - } - - .tabs>li>a, - select, - input { - font-size: 0.9rem; - } - - - @media screen and (min-width: 600px) { - ::-webkit-scrollbar { - width: 10px; - height: 10px; - } - - ::-webkit-scrollbar, - ::-webkit-scrollbar-corner { - background: transparent; - } - - ::-webkit-scrollbar-thumb { - background: #9e9e9e; - } - - ::-webkit-scrollbar-thumb:hover { - background: #757575; - } - - ::-webkit-scrollbar-thumb:active { - background: #424242; - } - } diff --git a/luci-theme-alpha/luasrc/style/catatan.txt b/luci-theme-alpha/luasrc/style/catatan.txt deleted file mode 100644 index c74e132e..00000000 --- a/luci-theme-alpha/luasrc/style/catatan.txt +++ /dev/null @@ -1 +0,0 @@ -buat tambah login page disini diff --git a/luci-theme-alpha/luasrc/style/openwrt20thanniversary.png b/luci-theme-alpha/luasrc/style/openwrt20thanniversary.png index 18ae1ecd..b7d67556 100644 Binary files a/luci-theme-alpha/luasrc/style/openwrt20thanniversary.png and b/luci-theme-alpha/luasrc/style/openwrt20thanniversary.png differ diff --git a/luci-theme-alpha/luasrc/style/style.css b/luci-theme-alpha/luasrc/style/style.css index f43a7c52..0f650fd6 100644 --- a/luci-theme-alpha/luasrc/style/style.css +++ b/luci-theme-alpha/luasrc/style/style.css @@ -410,7 +410,8 @@ img.bawah { display: block; padding: 20px; text-decoration: none; - width: 25rem; + width: 14rem; + max-width: 80vw; } .icon-credits a { diff --git a/luci-theme-alpha/template/footer.htm b/luci-theme-alpha/template/footer.htm index 37d6091d..19ba1358 100644 --- a/luci-theme-alpha/template/footer.htm +++ b/luci-theme-alpha/template/footer.htm @@ -1,127 +1,108 @@ -<%# - Alpha os is made from me for all .. especially for indo wrt members and fan of OpenWrt or DBAI Community - luci-theme-alpha - Copyright 2024 derisamedia +<%# Alpha os is made from me for all .. especially for indo wrt members and fan of OpenWrt or DBAI Community + luci-theme-alpha Copyright 2024 derisamedia Have a bug? Please create an issue here on GitHub! luci-theme-material Copyright 2015 Lutty Yang - luci-theme-bootstrap: - Copyright 2008 Steven Barth - Copyright 2008 Jo-Philipp Wich - Copyright 2012 David Menting + luci-theme-bootstrap: + Copyright 2008 Steven Barth + Copyright 2008 Jo-Philipp Wich + Copyright 2012 David Menting - MUI: - https://github.com/muicss/mui + MUI: + https://github.com/muicss/mui - Licensed to the public under the Apache License 2.0 --%> -<% -local ver = require "luci.version" -local uci = require "luci.model.uci".cursor() -local config = uci:get_all("alpha", "theme") + Licensed to the public under the Apache License 2.0 + -%> + <% local ver=require "luci.version" local uci=require "luci.model.uci" .cursor() local + config=uci:get_all("alpha", "theme" ) -- Table to store navbar icons local icon={} -- Iterate + through all navbar entries uci:foreach("alpha", "navbar" , function(section) local + address=section.address local icon_url=section.icon if address and icon_url then -- + Remove '/www/luci-static/alpha/' from icon_url + icon_url=string.gsub(icon_url, "^/www/luci%-static/alpha/" , "" ) icon[address]=icon_url end + end) -- Check navbar enable status local navbar_enabled=config.navbar=="1" -- Calculate number + of enabled navbar links local num_links=0 uci:foreach("alpha", "navbar" , function(section) if + section.enable=="Enable" then num_links=num_links + 1 end end) -- Calculate link width for + responsive design local link_width=string.format("calc(100%% / %d)", num_links) -- Retrieve + theme properties local background_color=config.color or '#2222359a' local + blur_value=tonumber(config.blur) or 20 local link_blur=string.format("blur(%dpx)", blur_value) + %> --- Table to store navbar icons -local icon = {} + --- Calculate number of enabled navbar links -local num_links = 0 -uci:foreach("alpha", "navbar", function(section) - if section.enable == "Enable" then - num_links = num_links + 1 - end -end) + + + + + + + + + --- Calculate link width for responsive design -local link_width = string.format("calc(100%% / %d)", num_links) - --- Retrieve theme properties -local background_color = config.color or '#2222359a' -local blur_value = tonumber(config.blur) or 20 -local link_blur = string.format("blur(%dpx)", blur_value) -%> - - - - - - - - - - - - - + \ No newline at end of file diff --git a/luci-theme-alpha/template/footer.ut b/luci-theme-alpha/template/footer.ut index 888b0e55..f6740eb1 100644 --- a/luci-theme-alpha/template/footer.ut +++ b/luci-theme-alpha/template/footer.ut @@ -54,7 +54,7 @@