mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-03 20:33:56 +08:00
🎁 Sync 2026-10-09 12:18:17
This commit is contained in:
1 parent
c43003617d
commit
1ee3366de6
139 files changed
+1934
-500
No files matched your search
@@ -9,9 +9,12 @@ include $(TOPDIR)/rules.mk
|
||||
LUCI_TITLE:=Argon Theme
|
||||
LUCI_DEPENDS:=+USE_APK:wget-any +!USE_APK:wget +jsonfilter
|
||||
PKG_VERSION:=2.4.8
|
||||
PKG_RELEASE:=27
|
||||
PKG_RELEASE:=28
|
||||
|
||||
CONFIG_LUCI_CSSTIDY:=
|
||||
# Ship template source across stable and snapshot runtimes. Precompiled
|
||||
# bytecode would require the SDK's ucode format (see issue #715).
|
||||
LUCI_MINIFY_UT:=0
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
|
||||
@@ -78,6 +78,14 @@ uci commit argon
|
||||
|
||||
Without a key, the login page uses a local background. Bing and Wallhaven wallpaper options are unaffected.
|
||||
|
||||
## Custom browser icon and login logo
|
||||
|
||||
Under **System → Argon Config → Custom branding**, upload a browser icon and login logo separately, or use one image for both. Each can be restored to its default. PNG images must be 16–1024 pixels per side and at most 1 MiB. Browser icons must be square; login logos retain their aspect ratio in both login layouts.
|
||||
|
||||
Update both the theme and configuration plugin. Uploads and resets apply immediately without saving other settings; reload open pages to update their icons. The custom browser icon also supplies the touch icon and web manifest. Existing home-screen shortcuts may need to be added again.
|
||||
|
||||
Files are stored in `/www/luci-static/argon/branding/` without replacing packaged assets. The configuration plugin includes this directory in `keep.d` backups for upgrades that preserve configuration. Upgrades without configuration preservation reset the icons.
|
||||
|
||||
## Compatibility
|
||||
|
||||
Only the `master` branch is maintained now.
|
||||
@@ -109,6 +117,8 @@ Choose the format used by the firmware's native package manager. The presence of
|
||||
|
||||
The APK assets use **APK v3 format**, which `apk-tools 2.x` (including `2.14.0`) cannot read. `--allow-untrusted` only bypasses signature trust checks; it does not add format support. `apk` cannot install IPK files either.
|
||||
|
||||
APK builds target the OpenWrt **25.12.5 stable SDK** and keep theme templates as source for runtime compatibility. The original v2.4.8 APK was built with a snapshot SDK and requires `ucode>=2026.02.27`, which OpenWrt 25.12.5 does not provide ([#715](https://github.com/jerrykuku/luci-theme-argon/issues/715)). That asset needs to be rebuilt with this fix; updating this repository does not replace already published packages. Do not bypass dependency checks to install incompatible bytecode.
|
||||
|
||||
For the GL.iNet / OpenWrt 23.05 environment in [#705](https://github.com/jerrykuku/luci-theme-argon/issues/705), download IPK files and install them with the firmware's existing `opkg`. There is no need to replace the system package manager.
|
||||
|
||||
Download `luci-theme-argon`, `luci-app-argon-config`, and any required `luci-i18n-argon-config-<language>` packages from [Releases][release]. Select the same format for all packages and use the actual asset filenames; do not construct version suffixes or rename file extensions.
|
||||
|
||||
@@ -78,6 +78,14 @@ uci commit argon
|
||||
|
||||
未配置密钥时,登录页会使用本地背景。Bing 和 Wallhaven 壁纸选项不受影响。
|
||||
|
||||
## 自定义网站图标与登录 Logo
|
||||
|
||||
在 **系统 → Argon 主题设置 → 自定义图标** 中,可以分别上传网站图标和登录页 Logo,也可以将同一张图片同时用于两处;每项都可恢复默认。支持 PNG 格式,每边 16–1024 像素,最大 1 MiB。网站图标需为正方形;登录 Logo 按原比例缩放,兼容经典侧栏和居中卡片。
|
||||
|
||||
请同时更新主题和配置插件。上传或恢复后立即生效,无需保存其他设置;已打开的页面需要刷新才能更新图标。自定义网站图标也用于手机桌面图标和 manifest,已添加到桌面的快捷方式可能需要重新添加。
|
||||
|
||||
自定义文件保存在 `/www/luci-static/argon/branding/`,不会覆盖主题内置图标。配置插件通过 `keep.d` 将此目录纳入保留配置升级的备份;不保留配置时不会保留自定义图标。
|
||||
|
||||
## 兼容性
|
||||
|
||||
目前仅维护 `master` 分支。
|
||||
@@ -109,6 +117,8 @@ make -j1 V=s
|
||||
|
||||
本项目的 APK 使用 **APK v3 格式**,`apk-tools 2.x`(包括 `2.14.0`)无法读取。`--allow-untrusted` 只跳过签名信任检查,不能解决格式不兼容;`apk` 也不能安装 IPK。
|
||||
|
||||
APK 构建使用 OpenWrt **25.12.5 稳定版 SDK**,主题模板保留源码以兼容目标运行时。原始 v2.4.8 APK 使用 snapshot SDK 构建,要求 `ucode>=2026.02.27`,而 OpenWrt 25.12.5 不提供该版本([#715](https://github.com/jerrykuku/luci-theme-argon/issues/715))。该附件需要包含本次修复后重新构建;更新仓库代码不会替换已经发布的安装包。请勿绕过依赖检查安装不兼容的字节码。
|
||||
|
||||
对于 [#705](https://github.com/jerrykuku/luci-theme-argon/issues/705) 中的 GL.iNet / OpenWrt 23.05 环境,应下载 IPK 并使用固件原有的 `opkg` 安装,无需替换系统包管理器。
|
||||
|
||||
从 [Release][release] 下载主题包 `luci-theme-argon`、配置插件包 `luci-app-argon-config`,以及需要的 `luci-i18n-argon-config-<语言>` 语言包。所有包必须选择相同格式,以附件的实际文件名为准,不要自行拼接版本号或修改扩展名。
|
||||
|
||||
@@ -2,6 +2,22 @@
|
||||
|
||||
## v2.4.8 [ 2026.10.08 ]
|
||||
|
||||
### v2.4.8 r2 rebuild / 修订版重发
|
||||
|
||||
Republished on 2026-10-09 with package revision 2: APK packages use `2.4.8-r2`; IPK packages use `2.4.8-2` so both package managers recognize the update.
|
||||
|
||||
2026-10-09 重发,主题及配置插件包修订号更新为 2:APK 版本为 `2.4.8-r2`,IPK 版本为 `2.4.8-2`,便于从旧包升级。
|
||||
|
||||
- Fix stable OpenWrt 25.12 APK installation (#715): build with SDK 25.12.5 and ship template source.
|
||||
- Improve dark sysupgrade dialog contrast and wrapping (`1055e79`).
|
||||
- Correct notification banner positioning and spacing (`c70ed6b`).
|
||||
- Keep the configuration plugin at `9bafffa`; login-page layout selection and custom favicon/Logo settings are not included.
|
||||
|
||||
- 修复稳定版 OpenWrt 25.12 的 APK 安装问题(#715):使用 25.12.5 SDK,模板保留源码。
|
||||
- 修复深色升级弹窗的对比度与换行(`1055e79`)。
|
||||
- 修复通知横幅位置和内部间距(`c70ed6b`)。
|
||||
- 配置插件固定为 `9bafffa`,不包含登录页样式切换及自定义网站图标/Logo 设置。
|
||||
|
||||
### Installation / 安装说明
|
||||
|
||||
| Firmware / 固件 | Package / 安装包 |
|
||||
@@ -13,6 +29,10 @@ APK assets use **APK v3** and cannot be read by `apk-tools 2.x`, including `2.14
|
||||
|
||||
APK 附件采用 **APK v3 格式**,`apk-tools 2.x`(包括 `2.14.0`)无法读取。在原生使用 opkg 的固件上额外安装 `apk`,并不会让固件兼容 APK v3;`--allow-untrusted` 不能解决格式不兼容,`apk` 也不能安装 IPK。
|
||||
|
||||
APK builds use the OpenWrt **25.12.5 stable SDK**. Theme templates are shipped as source to avoid snapshot-specific ucode bytecode requirements. If an older APK reports `ucode>=2026.02.27`, use a package rebuilt with the [#715 fix](https://github.com/jerrykuku/luci-theme-argon/issues/715); bypassing dependency checks does not make that bytecode compatible.
|
||||
|
||||
APK 使用 OpenWrt **25.12.5 稳定版 SDK** 构建,主题模板保留源码,避免 snapshot 的 ucode 字节码版本限制。若旧 APK 提示需要 `ucode>=2026.02.27`,请使用包含 [#715 修复](https://github.com/jerrykuku/luci-theme-argon/issues/715) 的重新构建包;绕过依赖检查不能解决字节码不兼容。
|
||||
|
||||
Download the theme, configuration plugin, and required language packages in the **same format**. Use the exact asset filenames below. For GL.iNet / OpenWrt 23.05, use IPK files with the firmware's existing `opkg`.
|
||||
|
||||
主题、配置插件和需要的语言包应选择**相同格式**,以本页附件实际文件名为准。GL.iNet / OpenWrt 23.05 请下载 IPK 并使用固件原有的 `opkg` 安装。
|
||||
|
||||
@@ -785,7 +785,9 @@ select[multiple="multiple"] {
|
||||
}
|
||||
.login-page .login-container .login-form .brand .icon {
|
||||
width: 50px;
|
||||
height: auto;
|
||||
height: 50px;
|
||||
object-fit: contain;
|
||||
flex-shrink: 0;
|
||||
margin-right: 25px;
|
||||
}
|
||||
.login-page .login-container .login-form .brand .brand-text {
|
||||
@@ -950,6 +952,7 @@ select[multiple="multiple"] {
|
||||
}
|
||||
.login-page[data-login-style="centered"] .login-container .login-form .brand .icon {
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
margin: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -126,7 +126,9 @@
|
||||
|
||||
.icon {
|
||||
width: 50px;
|
||||
height: auto;
|
||||
height: 50px;
|
||||
object-fit: contain;
|
||||
flex-shrink: 0;
|
||||
margin-right: 25px;
|
||||
}
|
||||
|
||||
@@ -315,6 +317,7 @@
|
||||
|
||||
.icon {
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
margin: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
'use strict';
|
||||
|
||||
import * as fs from 'fs';
|
||||
|
||||
// Read only package-managed names from the public branding directory.
|
||||
// Invalid, missing or linked files fall back to the built-in theme assets.
|
||||
export function get_branding() {
|
||||
const dir = '/www/luci-static/argon/branding/';
|
||||
let result = {};
|
||||
if (fs.lstat(rtrim(dir, '/'))?.type != 'directory')
|
||||
return result;
|
||||
const state = fs.lstat(dir + 'current.json');
|
||||
if (state?.type != 'file' || state.size > 1024)
|
||||
return result;
|
||||
let config;
|
||||
try { config = json(fs.readfile(dir + 'current.json')); }
|
||||
catch (e) { return result; }
|
||||
if (type(config) != 'object')
|
||||
return result;
|
||||
for (let kind in ['favicon', 'logo']) {
|
||||
let name = config?.[kind];
|
||||
if (type(name) != 'string' || !match(name, /^image-[0-9a-f]{64}\.png$/))
|
||||
continue;
|
||||
let info = fs.lstat(dir + name);
|
||||
if (info?.type != 'file' || info.size < 67 || info.size > 1048576)
|
||||
continue;
|
||||
result[kind] = name;
|
||||
}
|
||||
if (result.favicon) {
|
||||
let manifest = replace(result.favicon, /\.png$/, '.webmanifest');
|
||||
if (fs.lstat(dir + manifest)?.type == 'file')
|
||||
result.manifest = manifest;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('node:assert/strict');
|
||||
const { spawnSync, execFileSync } = require('node:child_process');
|
||||
const { mkdtempSync, readFileSync, writeFileSync, rmSync } = require('node:fs');
|
||||
const { tmpdir } = require('node:os');
|
||||
const path = require('node:path');
|
||||
const { test } = require('node:test');
|
||||
|
||||
const scripts = path.resolve(__dirname, '../.github/scripts');
|
||||
|
||||
function metadata(tag) {
|
||||
const output = execFileSync('python3', [path.join(scripts, 'release_metadata.py'), tag], { encoding: 'utf8' });
|
||||
return Object.fromEntries(output.trim().split('\n').map(line => line.split('=')));
|
||||
}
|
||||
|
||||
test('stable versions retain their package versions and preview suffixes use native package formats', () => {
|
||||
for (const tag of ['v2.4.8', '2.5.0']) {
|
||||
const result = metadata(tag);
|
||||
assert.equal(result.tag, tag);
|
||||
assert.equal(result.prerelease, 'false');
|
||||
assert.equal(result.apk_version, tag.replace(/^v/, ''));
|
||||
assert.equal(result.ipk_version, result.apk_version);
|
||||
}
|
||||
for (const stage of ['alpha', 'beta', 'rc']) {
|
||||
const result = metadata(`v2.5.0-${stage}.12`);
|
||||
assert.equal(result.prerelease, 'true');
|
||||
assert.equal(result.version, `2.5.0-${stage}.12`);
|
||||
assert.equal(result.apk_version, `2.5.0_${stage}12`);
|
||||
assert.equal(result.ipk_version, `2.5.0~${stage}12-1`);
|
||||
}
|
||||
});
|
||||
|
||||
test('invalid and unsupported tags fail before producing release outputs', () => {
|
||||
for (const tag of ['latest', 'v2.5.0-beta', 'v2.5.0-beta.0', 'v2.5.0-preview.1', 'v2.5.0+build', 'v2.5.0\nprerelease=false']) {
|
||||
const result = spawnSync('python3', [path.join(scripts, 'release_metadata.py'), tag], { encoding: 'utf8' });
|
||||
assert.notEqual(result.status, 0, tag);
|
||||
assert.equal(result.stdout, '', tag);
|
||||
}
|
||||
});
|
||||
|
||||
test('preview preparation and documentation sync cannot overwrite stable metadata', t => {
|
||||
const dir = mkdtempSync(path.join(tmpdir(), 'argon-preview-docs-'));
|
||||
t.after(() => rmSync(dir, { recursive: true, force: true }));
|
||||
const files = ['Makefile', 'README.md', 'README_ZH.md', 'RELEASE.md', 'RELEASE_ZH.md'];
|
||||
for (const file of files) writeFileSync(path.join(dir, file), 'stable v2.4.8\n');
|
||||
const env = { ...process.env, GITHUB_REPOSITORY: '', GITHUB_TOKEN: '' };
|
||||
const prepare = spawnSync('bash', [path.join(scripts, 'prepare_release_commit.sh'), 'v2.5.0-beta.1'], { cwd: dir, env });
|
||||
assert.equal(prepare.status, 1);
|
||||
assert.match(prepare.stderr.toString(), /matching tags/);
|
||||
const sync = spawnSync('bash', [path.join(scripts, 'update_release_docs.sh'), 'v2.5.0-beta.1'], { cwd: dir, env });
|
||||
assert.equal(sync.status, 0, sync.stderr.toString());
|
||||
for (const file of files) assert.equal(readFileSync(path.join(dir, file), 'utf8'), 'stable v2.4.8\n');
|
||||
});
|
||||
|
||||
test('config source resolves matching lightweight and annotated tags, and never falls back for previews', t => {
|
||||
const dir = mkdtempSync(path.join(tmpdir(), 'argon-preview-config-'));
|
||||
t.after(() => rmSync(dir, { recursive: true, force: true }));
|
||||
const git = (...args) => execFileSync('git', ['-C', dir, ...args], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trim();
|
||||
git('init', '-b', 'master');
|
||||
git('config', 'user.name', 'Release test');
|
||||
git('config', 'user.email', 'release-test@example.invalid');
|
||||
git('commit', '--allow-empty', '-m', 'config preview');
|
||||
const tagged = git('rev-parse', 'HEAD');
|
||||
git('tag', 'v2.5.0-beta.1');
|
||||
git('tag', '-a', 'v2.5.0-rc.1', '-m', 'annotated preview');
|
||||
git('tag', 'v2.5.0');
|
||||
git('commit', '--allow-empty', '-m', 'later master');
|
||||
const master = git('rev-parse', 'HEAD');
|
||||
const resolve = (tag, remote = dir) => spawnSync('bash', [path.join(scripts, 'resolve_config.sh'), remote, tag], { encoding: 'utf8' });
|
||||
for (const tag of ['v2.5.0-beta.1', 'v2.5.0-rc.1', 'v2.5.0']) {
|
||||
const result = resolve(tag);
|
||||
assert.equal(result.status, 0, result.stderr);
|
||||
assert.equal(result.stdout.trim(), `sha=${tagged}`);
|
||||
}
|
||||
assert.equal(resolve('v2.6.0').stdout.trim(), `sha=${master}`);
|
||||
const missing = resolve('v2.5.0-beta.2');
|
||||
assert.notEqual(missing.status, 0);
|
||||
assert.match(missing.stdout, /matching config tag/);
|
||||
assert.doesNotMatch(missing.stdout, /sha=/);
|
||||
const unavailable = resolve('v2.6.0', path.join(dir, 'missing.git'));
|
||||
assert.notEqual(unavailable.status, 0);
|
||||
assert.doesNotMatch(unavailable.stdout, /sha=/);
|
||||
});
|
||||
@@ -260,3 +260,67 @@ jsonfilter() { return 1; }
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
// Exercise the real filesystem module, including malformed state and stale files.
|
||||
test('custom branding accepts only published assets and safely falls back', () => {
|
||||
const dir = mkdtempSync(path.join(tmpdir(), 'argon-branding-test-'));
|
||||
const assets = path.join(dir, 'branding');
|
||||
const module = path.join(dir, 'luci', 'argon-branding.uc');
|
||||
fs.mkdirSync(path.dirname(module));
|
||||
const source = fs.readFileSync(path.join(root, 'root/usr/share/ucode/luci/argon-branding.uc'), 'utf8');
|
||||
writeFileSync(module, source.replace('/www/luci-static/argon/branding/', assets + '/'));
|
||||
const ucode = process.env.UCODE_BIN || 'ucode';
|
||||
const args = ['-L', path.join(path.dirname(ucode), '*.so'), '-L', path.join(dir, '*.uc')];
|
||||
const read = () => JSON.parse(execFileSync(ucode, [...args, '-e',
|
||||
"import { get_branding } from 'luci.argon-branding'; print(sprintf('%J', get_branding()));"
|
||||
], { encoding: 'utf8' }));
|
||||
const image = 'image-' + 'a'.repeat(64) + '.png';
|
||||
const manifest = image.replace('.png', '.webmanifest');
|
||||
const index = path.join(assets, 'current.json');
|
||||
try {
|
||||
assert.deepEqual(read(), {});
|
||||
fs.mkdirSync(assets);
|
||||
writeFileSync(path.join(assets, image), Buffer.alloc(100));
|
||||
writeFileSync(path.join(assets, manifest), '{}');
|
||||
writeFileSync(index, JSON.stringify({ favicon: image, logo: image }));
|
||||
assert.deepEqual(read(), { favicon: image, logo: image, manifest });
|
||||
for (const bad of ['broken', 'null', '[]', '123', '"text"', '{"logo":"../elsewhere.png"}', ' '.repeat(1025)]) {
|
||||
writeFileSync(index, bad);
|
||||
assert.deepEqual(read(), {});
|
||||
}
|
||||
writeFileSync(index, JSON.stringify({ logo: image, favicon: '../outside.png' }));
|
||||
assert.deepEqual(read(), { logo: image });
|
||||
fs.unlinkSync(path.join(assets, image));
|
||||
assert.deepEqual(read(), {});
|
||||
writeFileSync(path.join(dir, 'outside.png'), Buffer.alloc(100));
|
||||
fs.symlinkSync(path.join(dir, 'outside.png'), path.join(assets, image));
|
||||
assert.deepEqual(read(), {});
|
||||
fs.unlinkSync(index);
|
||||
fs.symlinkSync(path.join(dir, 'outside.png'), index);
|
||||
assert.deepEqual(read(), {});
|
||||
fs.renameSync(assets, path.join(dir, 'saved'));
|
||||
fs.symlinkSync(path.join(dir, 'saved'), assets);
|
||||
assert.deepEqual(read(), {});
|
||||
} finally { rmSync(dir, { recursive: true, force: true }); }
|
||||
});
|
||||
|
||||
test('custom head icons replace every default candidate and restore as a group', () => {
|
||||
const dir = mkdtempSync(path.join(tmpdir(), 'argon-head-test-'));
|
||||
const source = fs.readFileSync(path.join(root, 'ucode/template/themes/argon/head_meta.ut'), 'utf8')
|
||||
.replace("import { get_branding } from 'luci.argon-branding';", 'function get_branding() { return fixture; }');
|
||||
const file = path.join(dir, 'head.ut');
|
||||
writeFileSync(file, '{% let media="/luci-static/argon"; let hostname="Router"; let node={}; let bar_color="#123456"; %}' + source);
|
||||
const render = fixture => execFileSync(process.env.UCODE_BIN || 'ucode', ['-T,', '-Dfixture=' + JSON.stringify(fixture), file], { encoding: 'utf8' });
|
||||
try {
|
||||
const defaults = render({});
|
||||
assert.match(defaults, /favicon\.ico/);
|
||||
assert.match(defaults, /apple-icon-144x144\.png/);
|
||||
assert.match(defaults, /icon\/manifest\.json/);
|
||||
const custom = render({ favicon: 'custom.png', manifest: 'custom.webmanifest' });
|
||||
assert.match(custom, /rel="icon" type="image\/png" href="\/luci-static\/argon\/branding\/custom.png"/);
|
||||
assert.match(custom, /rel="apple-touch-icon" href="\/luci-static\/argon\/branding\/custom.png"/);
|
||||
assert.match(custom, /branding\/custom.webmanifest/);
|
||||
assert.doesNotMatch(custom, /favicon\.ico|icon\/favicon|icon\/android|icon\/apple|icon\/manifest/);
|
||||
assert.equal(render({ logo: 'custom.png' }), defaults);
|
||||
} finally { rmSync(dir, { recursive: true, force: true }); }
|
||||
});
|
||||
@@ -1,3 +1,7 @@
|
||||
{%
|
||||
import { get_branding } from 'luci.argon-branding';
|
||||
const branding = get_branding();
|
||||
%}
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{ hostname }}{{ node?.title ? ` - ${striptags(node.title)}` : '' }} - LuCI</title>
|
||||
@@ -15,9 +19,17 @@
|
||||
<meta name="theme-color" content="{{ bar_color }}">
|
||||
|
||||
<!-- Icons and Manifest -->
|
||||
{% if (branding.favicon): %}
|
||||
<link rel="icon" type="image/png" href="{{ media }}/branding/{{ branding.favicon }}">
|
||||
<link rel="apple-touch-icon" href="{{ media }}/branding/{{ branding.favicon }}">
|
||||
{% if (branding.manifest): %}
|
||||
<link rel="manifest" href="{{ media }}/branding/{{ branding.manifest }}">
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<link rel="icon" type="image/x-icon" href="{{ media }}/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="{{ media }}/icon/favicon-16x16.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{{ media }}/icon/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="{{ media }}/icon/android-icon-192x192.png">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="{{ media }}/icon/apple-icon-144x144.png">
|
||||
<link rel="manifest" href="{{ media }}/icon/manifest.json">
|
||||
{% endif %}
|
||||
@@ -25,6 +25,7 @@
|
||||
{%
|
||||
import * as fs from 'fs';
|
||||
import { cursor } from 'uci';
|
||||
import { get_branding } from 'luci.argon-branding';
|
||||
|
||||
let cfg = cursor();
|
||||
// Only known layouts may select login page styles; old configs stay classic.
|
||||
@@ -98,6 +99,8 @@
|
||||
const hostname = striptags(boardinfo?.hostname ?? '?');
|
||||
const themeDir = media + "/background/";
|
||||
const bgArry = selectBackground(themeDir);
|
||||
const branding = get_branding();
|
||||
const logo_url = branding.logo ? media + '/branding/' + branding.logo : media + '/img/argon.svg';
|
||||
|
||||
%}
|
||||
<!-- Login Page Start -->
|
||||
@@ -151,7 +154,7 @@
|
||||
<div class="login-container">
|
||||
<div class="login-form">
|
||||
<!-- Logo Start -->
|
||||
<a class="brand" href="/"><img src="{{ media }}/img/argon.svg" class="icon">
|
||||
<a class="brand" href="/"><img src="{{ logo_url }}" class="icon" alt="" data-fallback="{{ media }}/img/argon.svg" onerror="this.onerror=null;this.src=this.dataset.fallback">
|
||||
<span class="brand-text">{{ hostname }}</span>
|
||||
</a>
|
||||
<!-- Logo End -->
|
||||
|
||||
Reference in new issue
Block a user