Sync 2026-03-22 20:18:41

This commit is contained in:
github-actions[bot] 2026-03-22 20:18:41 +08:00
parent 8d097e3078
commit a660863dba
38 changed files with 705 additions and 4060 deletions

View File

@ -1,13 +1,19 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-guest-wifi
PKG_MAINTAINER:=kenzok8 <https://github.com/kenzok78>
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
# call BuildPackage - OpenWrt buildroot signature

View File

@ -1 +1,77 @@
# luci-app-guest-wifi
# 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

View File

@ -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();
}
});

View File

@ -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();
}
});
return m.render();
}
});

View File

@ -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
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

View File

@ -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
return m

View File

@ -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 ""
msgstr ""

View File

@ -0,0 +1 @@
zh_Hans

View File

@ -1 +0,0 @@
zh-cn

View File

@ -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 "防止无线客户端之间相互通信"
msgstr "防止无线客户端之间相互通信"

View File

@ -1,3 +0,0 @@
config guest-wifi 'config'
option enabled '0'
option isolate '1'

View File

@ -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
}
reload_service
}

View File

@ -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
rm -f /tmp/luci-indexcache 2>/dev/null
exit 0

View File

@ -1,8 +0,0 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
set luci.languages.zh_cn='chinese'
commit luci
EOF
exit 0

View File

@ -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

View File

@ -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

View File

@ -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" ]
}
}
}
"luci-app-guest-wifi": {
"description": "Grant access to guest-wifi configuration",
"read": {
"uci": [ "wireless" ],
"ubus": {
"iwinfo": [ "devices", "info", "assoclist" ]
}
},
"write": {
"uci": [ "wireless" ]
}
}
}

View File

@ -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"))

View File

@ -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

View File

@ -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();

View File

@ -2107,3 +2107,6 @@ msgstr "当前使用的 %s 节点"
msgid "Search nodes..."
msgstr "搜索节点…"
msgid "Concurrent Tunnels"
msgstr "并发隧道连接数"

View File

@ -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

View File

@ -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

View File

@ -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();
},
});

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -1 +0,0 @@
buat tambah login page disini

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

After

Width:  |  Height:  |  Size: 124 KiB

View File

@ -410,7 +410,8 @@ img.bawah {
display: block;
padding: 20px;
text-decoration: none;
width: 25rem;
width: 14rem;
max-width: 80vw;
}
.icon-credits a {

View File

@ -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 <facebook.com/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 <facebook.com/derisamedia>
Have a bug? Please create an issue here on GitHub!
luci-theme-material
Copyright 2015 Lutty Yang <lutty@wcan.in>
luci-theme-bootstrap:
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
Copyright 2012 David Menting <david@nut-bolt.nl>
luci-theme-bootstrap:
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
Copyright 2012 David Menting <david@nut-bolt.nl>
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 = {}
<style>
.main>.main-left,
.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,
.tabs,
.cbi-tabmenu,
.cbi-tooltip {
background-color: <%=background_color%>;
backdrop-filter: <%=link_blur%>;
-webkit-backdrop-filter: <%=link_blur%>;
}
-- Iterate through all navbar entries
uci:foreach("alpha", "navbar", function(section)
local address = section.address
local icon_url = section.icon
@media screen and (max-width: 720px) {
.navbar a {
width: <%=link_width%>;
}
}
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)
<% if not navbar_enabled then %>.navbar {
display: none;
}
-- Check navbar enable status
local navbar_enabled = config.navbar == "1"
<% end %>
</style>
-- 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)
</div>
<footer class="mobile">
<a href="https://github.com/derisamedia/luci-theme-alpha">
<%=ver.luciname%> | Alpha OS Theme v3.9.7
</a>
</footer>
</div>
<div class="navbar active">
<% if navbar_enabled then %>
<div class="dropdown">
<% uci:foreach("alpha", "navbar" , function(section) local address=section.address
local icon_url=icon[address] or 'default/icon.png' local
target_blank=section.newtab=="Yes" and 'target="_blank"' or '' if
section.enable=="Enable" then %>
<a href="<%=address%>" <%=target_blank%>>
<img src="<%=media%>/<%=icon_url%>" />
</a>
<% end end) %>
</div>
<% end %>
<label class="toggler">
<img src="<%=media%>/gaya/icon/arrow.svg">
</label>
</div>
<script>
{
const nav = document.querySelector(".navbar");
let lastScrollY = window.scrollY;
window.addEventListener("scroll", () => {
if (lastScrollY < window.scrollY) {
nav.classList.add("navbar--hidden");
} else {
nav.classList.remove("navbar--hidden");
}
lastScrollY = window.scrollY;
});
}
</script>
</div>
<script type="text/javascript">L.require('menu-alpha')</script>
<script src="<%=media%>/app.js"></script>
</body>
-- 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)
%>
<style>
.main > .main-left, .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, .tabs, .cbi-tabmenu, .cbi-tooltip {
background-color: <%=background_color%>;
backdrop-filter: <%=link_blur%>;
-webkit-backdrop-filter: <%=link_blur%>;
}
@media screen and (max-width: 720px) {
.navbar a {
width: <%=link_width%>;
}
}
<% if not navbar_enabled then %>
.navbar {
display: none;
}
<% end %>
</style>
</div>
<footer class="mobile">
<a href="https://github.com/derisamedia/luci-theme-alpha"><%=ver.luciname%> | Alpha OS Theme v3.9.5</a>
</footer>
</div>
<div class="navbar active">
<% if navbar_enabled then %>
<div class="dropdown">
<%
uci:foreach("alpha", "navbar", function(section)
local address = section.address
local icon_url = icon[address] or 'default/icon.png'
local target_blank = section.newtab == "Yes" and 'target="_blank"' or ''
if section.enable == "Enable" then
%>
<a href="<%=address%>" <%=target_blank%>>
<img src="<%=media%>/<%=icon_url%>" />
</a>
<%
end
end)
%>
</div>
<% end %>
<label class="toggler">
<img src="<%=media%>/gaya/icon/arrow.svg">
</label>
</div>
<script>
{
const nav = document.querySelector(".navbar");
let lastScrollY = window.scrollY;
window.addEventListener("scroll", () => {
if (lastScrollY < window.scrollY) {
nav.classList.add("navbar--hidden");
} else {
nav.classList.remove("navbar--hidden");
}
lastScrollY = window.scrollY;
});
}
</script>
</div>
<script type="text/javascript">L.require('menu-alpha')</script>
<script src="<%=media%>/app.js"></script>
</body>
</html>
</html>

View File

@ -54,7 +54,7 @@
</div>
<footer class="mobile">
<a href="https://github.com/derisamedia/luci-theme-alpha">{{ version.luciname }} | Alpha OS Theme v3.9.5</a>
<a href="https://github.com/derisamedia/luci-theme-alpha">{{ version.luciname }} | Alpha OS Theme v3.9.7</a>
</footer>
</div>
<div class="navbar active">

View File

@ -1,96 +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 2022 derisamedia <facebook.com/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 2022 derisamedia <facebook.com/derisamedia>
Have a bug? Please create an issue here on GitHub!
luci-theme-material
Copyright 2015-2017 Lutty Yang <lutty@wcan.in>
luci-theme-bootstrap:
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008-2016 Jo-Philipp Wich <jow@openwrt.org>
Copyright 2012 David Menting <david@nut-bolt.nl>
luci-theme-bootstrap:
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008-2016 Jo-Philipp Wich <jow@openwrt.org>
Copyright 2012 David Menting <david@nut-bolt.nl>
MUI:
https://github.com/muicss/mui
MUI:
https://github.com/muicss/mui
Licensed to the public under the Apache License 2.0
-%>
Licensed to the public under the Apache License 2.0
-%>
<%
local sys = require "luci.sys"
local util = require "luci.util"
local http = require "luci.http"
local disp = require "luci.dispatcher"
local ver = require "luci.version"
<% local sys=require "luci.sys" local util=require "luci.util" local http=require "luci.http" local
disp=require "luci.dispatcher" local ver=require "luci.version" local
boardinfo=util.ubus("system", "board" ) or { } local node=disp.context.dispatched local
path=table.concat(disp.context.path, "-" ) http.prepare_content("text/html; charset=UTF-8") -%>
<!DOCTYPE html>
<html lang="<%=luci.i18n.context.lang%>">
local boardinfo = util.ubus("system", "board") or { }
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="dark">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
name="viewport" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="theme-color" content="#09c">
<meta name="msapplication-tap-highlight" content="no">
<meta name="msapplication-TileColor" content="#09c">
<meta name="application-name" content="<%=striptags( (boardinfo.hostname or " ?") ) %> -
LuCI">
<meta name="apple-mobile-web-app-title" content="<%=striptags( (boardinfo.hostname or " ?")
) %> - LuCI">
<link rel="stylesheet" href="<%=media%>/gaya/gaya.css">
<link rel="shortcut icon" href="<%=media%>/favicon.ico">
<% if node and node.css then %>
<link rel="stylesheet" href="<%=resource%>/<%=node.css%>">
<% end -%>
<script
src="<%=url('admin/translations', luci.i18n.context.lang)%>?v=git-21.295.66888-fc702bc"></script>
<script src="<%=resource%>/cbi.js?v=git-21.295.66888-fc702bc"></script>
<title>
<%=striptags( (boardinfo.hostname or "?" ) .. ( (node and node.title) and ' - '
.. translate(node.title) or '' )) %> - LuCI
</title>
<% if css then %>
<style title="text/css">
<%=css %>
</style>
<% end -%>
</head>
local node = disp.context.dispatched
local path = table.concat(disp.context.path, "-")
<body
class="lang_<%=luci.i18n.context.lang%> <% if luci.dispatcher.context.authsession then %>logged-in<% end %> <% if not (path == "") then %>node-<%= path %><% else %>node-main-login<% end %>"
data-page="<%= pcdata(path) %>"
style="background-image:url('/luci-static/alpha/background/dashboard.png')">
<header>
<div class="fill">
<div class="container">
<a id="logo"
href="<% if luci.dispatcher.context.authsession then %><%=url('admin/status/overview')%><% else %>#<% end %>">
<img src="<%=media%>/brand.png" alt="OpenWrt">
</a>
<div class="status" id="indicators"></div>
<div class="logout">
<a href="/cgi-bin/luci/admin/logout" data-title="Logout">Keluar</a>
</div>
<div class="showSide">
<img src="<%=media%>/gaya/icon/menu_icon.svg" alt="">
</div>
</div>
</div>
</header>
<div class="main">
<div style="" class="loading"><span>
<div class="loading-img"></div>
</span></div>
<div class="main-left" id="mainmenu" style="display:none"></div>
<div class="main-right">
<div class="modemenu-buttons" style="display:none">
<ul id="modemenu"></ul>
</div>
<div class="darkMask"></div>
<div id="maincontent">
<div class="container">
<%- if luci.sys.process.info("uid")==0 and luci.sys.user.getuser("root") and
not luci.sys.user.getpasswd("root") and path
~="admin-system-admin-password" then -%>
<%- end -%>
http.prepare_content("text/html; charset=UTF-8")
-%>
<!DOCTYPE html>
<html lang="<%=luci.i18n.context.lang%>">
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport"/>
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="theme-color" content="#09c">
<meta name="msapplication-tap-highlight" content="no">
<meta name="msapplication-TileColor" content="#09c">
<meta name="application-name" content="<%=striptags( (boardinfo.hostname or "?") ) %> - LuCI">
<meta name="apple-mobile-web-app-title" content="<%=striptags( (boardinfo.hostname or "?") ) %> - LuCI">
<link rel="stylesheet" href="<%=media%>/gaya/gaya.css">
<link rel="shortcut icon" href="<%=media%>/favicon.ico">
<% if node and node.css then %>
<link rel="stylesheet" href="<%=resource%>/<%=node.css%>">
<% end -%>
<script src="<%=url('admin/translations', luci.i18n.context.lang)%>?v=git-21.295.66888-fc702bc"></script>
<script src="<%=resource%>/cbi.js?v=git-21.295.66888-fc702bc"></script>
<title><%=striptags( (boardinfo.hostname or "?") .. ( (node and node.title) and ' - ' .. translate(node.title) or '')) %> - LuCI</title>
<% if css then %><style title="text/css">
<%= css %>
</style>
<% end -%>
</head>
<body class="lang_<%=luci.i18n.context.lang%> <% if luci.dispatcher.context.authsession then %>logged-in<% end %> <% if not (path == "") then %>node-<%= path %><% else %>node-main-login<% end %>" data-page="<%= pcdata(path) %>" style="background-image:url('/luci-static/alpha/background/dashboard.png')">
<header>
<div class="fill">
<div class="container">
<a id="logo" href="<% if luci.dispatcher.context.authsession then %><%=url('admin/status/overview')%><% else %>#<% end %>">
<img src="<%=media%>/brand.png" alt="OpenWrt">
</a>
<div class="status" id="indicators"></div>
<div class="logout" >
<a href="/cgi-bin/luci/admin/logout" data-title="Logout">Keluar</a>
</div>
<div class="showSide">
<img src="<%=media%>/gaya/icon/menu_icon.svg" alt="">
</div>
</div>
</div>
</header>
<div class="main">
<div style="" class="loading"><span><div class="loading-img"></div></span></div>
<div class="main-left" id="mainmenu" style="display:none"></div>
<div class="main-right">
<div class="modemenu-buttons" style="display:none">
<ul id="modemenu"></ul>
</div>
<div class="darkMask"></div>
<div id="maincontent">
<div class="container">
<%- if luci.sys.process.info("uid") == 0 and luci.sys.user.getuser("root") and not luci.sys.user.getpasswd("root") and path ~= "admin-system-admin-password" then -%>
<%- end -%>
<noscript>
<div class="alert-message warning">
<h4><%:JavaScript required!%></h4>
<p><%:You must enable JavaScript in your browser or LuCI will not work properly.%></p>
</div>
</noscript>
<div id="tabmenu" style="display:none"></div>
<noscript>
<div class="alert-message warning">
<h4>
<%:JavaScript required!%>
</h4>
<p>
<%:You must enable JavaScript in your browser or LuCI
will not work properly.%>
</p>
</div>
</noscript>
<div id="tabmenu" style="display:none"></div>

View File

@ -14,6 +14,7 @@
<html lang="{{ dispatcher.lang }}">
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="dark">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport"/>
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">

View File

@ -2,7 +2,7 @@
<!-- saved from url=(0014)about:internet -->
<html lang="en">
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="color-scheme" content="dark">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">

View File

@ -3,7 +3,7 @@
<html lang="{{ dispatcher.lang }}">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="color-scheme" content="dark">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">

View File

@ -1452,8 +1452,8 @@
}
@layer table {
.table,
table {
table.table,
.table {
@apply border-border max-md:bg-panel-bg/98 mb-3 w-full border-separate border-spacing-0 overflow-visible rounded-2xl border max-md:mx-0 max-md:block max-md:w-full max-md:overflow-visible max-md:border-0 max-md:shadow-none;
&[width="100%"] {

View File

@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk
LUCI_TITLE:=Aurora Theme (A modern browser theme built with Vite and Tailwind CSS)
LUCI_DEPENDS:=+luci-base
PKG_VERSION:=0.11.1
PKG_RELEASE:=2
PKG_VERSION:=0.11.2
PKG_RELEASE:=3
PKG_LICENSE:=Apache-2.0
LUCI_MINIFY_CSS:=

File diff suppressed because one or more lines are too long