mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-30 11:25:13 +08:00
🌴 Sync 2026-03-05 23:51:42
This commit is contained in:
1 parent
97c049ed0a
commit
0acff03804
14253 files changed
+3893239
No files matched your search
@@ -0,0 +1 @@
|
||||
material3
|
||||
@@ -0,0 +1 @@
|
||||
material3
|
||||
@@ -0,0 +1 @@
|
||||
material3
|
||||
@@ -0,0 +1,20 @@
|
||||
{% if (!blank_page): %}
|
||||
</div>
|
||||
<footer>
|
||||
<span>
|
||||
Powered by
|
||||
<a href="https://github.com/openwrt/luci" target="_blank" rel="noreferrer">
|
||||
{{ version.luciname }} ({{ version.luciversion }})</a>
|
||||
/
|
||||
<a href="{{ entityencode(version.disturl ?? '#', true) }}" target="_blank" rel="noreferrer">
|
||||
{{ version.distname }} {{ version.distversion }} ({{ version.distrevision }})</a>
|
||||
{% if (lua_active): %}
|
||||
/ {{ _('Lua compatibility mode active') }}
|
||||
{% endif %}
|
||||
</span>
|
||||
<ul class="breadcrumb pull-right" id="modemenu" style="display:none"></ul>
|
||||
</footer>
|
||||
<script>L.require('menu-material3')</script>
|
||||
{% endif %}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,341 @@
|
||||
{#
|
||||
Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
Copyright 2012 David Menting <david@nut-bolt.nl>
|
||||
Copyright 2008-2022 Jo-Philipp Wich <jo@mein.io>
|
||||
Licensed to the public under the Apache License 2.0.
|
||||
-#}
|
||||
|
||||
{%
|
||||
import { getuid, getspnam } from 'luci.core';
|
||||
|
||||
const boardinfo = ubus.call('system', 'board');
|
||||
const darkpref = uci.get('luci', 'main', 'darkmode') || 'auto';
|
||||
let themepref = null;
|
||||
switch (theme) {
|
||||
case 'material3-blue': themepref = 'blue'; break;
|
||||
case 'material3-green': themepref = 'green'; break;
|
||||
case 'material3-red': themepref = 'red'; break;
|
||||
}
|
||||
|
||||
http.prepare_content('text/html; charset=UTF-8');
|
||||
-%}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ dispatcher.lang }}" data-darkmode="{{ darkpref }}" {{ themepref ? `data-theme="${themepref}"` : '' }}>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{{ striptags(`${boardinfo.hostname ?? '?'}${node ? ` - ${node.title}` : ''}`) }} - LuCI</title>
|
||||
<meta name="viewport" content="initial-scale=1.0">
|
||||
<link rel="stylesheet" href="{{ media }}/cascade.css">
|
||||
<link rel="stylesheet" media="screen and (max-width: 854px)" href="{{ media }}/mobile.css" />
|
||||
<link rel="icon" href="{{ media }}/logo.svg" sizes="any">
|
||||
{% if (node?.css): %}
|
||||
<link rel="stylesheet" href="{{ resource }}/{{ node.css }}">
|
||||
{% endif %}
|
||||
{% if (css): %}
|
||||
<style title="text/css">{{ css }}</style>
|
||||
{% endif %}
|
||||
<script src="{{ dispatcher.build_url('admin/translations', dispatcher.lang) }}"></script>
|
||||
<script src="{{ resource }}/cbi.js"></script>
|
||||
|
||||
|
||||
<style title="darkmode-support">
|
||||
/* Dark mode toggle styles */
|
||||
:root {
|
||||
--transition-duration: 0.3s;
|
||||
--theme-switch-size: 42px;
|
||||
--theme-switch-height: 24px;
|
||||
--theme-switch-handle-size: 16px;
|
||||
}
|
||||
|
||||
.theme-switch-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.header-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-left: auto;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.header-controls {
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.theme-switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: var(--theme-switch-size);
|
||||
height: var(--theme-switch-height);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.theme-switch input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
inset: 0;
|
||||
background-color: var(--switch-bg, #ccc);
|
||||
transition: all var(--transition-duration) cubic-bezier(0.4, 0, 0.2, 1);
|
||||
border-radius: var(--theme-switch-height);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: var(--theme-switch-handle-size);
|
||||
width: var(--theme-switch-handle-size);
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: var(--switch-handle, white);
|
||||
transition: all var(--transition-duration) cubic-bezier(0.4, 0, 0.2, 1);
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
input:checked + .slider {
|
||||
background-color: var(--primary);
|
||||
}
|
||||
|
||||
input:checked + .slider:before {
|
||||
transform: translateX(18px);
|
||||
}
|
||||
|
||||
/* Theme transition */
|
||||
html {
|
||||
transition: background-color var(--transition-duration) ease,
|
||||
color var(--transition-duration) ease;
|
||||
}
|
||||
|
||||
/* Theme toggle icon styles */
|
||||
.theme-toggle {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
transition: all var(--transition-duration) cubic-bezier(0.4, 0, 0.2, 1);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.theme-toggle:hover {
|
||||
background-color: var(--md-sys-color-surface-variant);
|
||||
}
|
||||
|
||||
.theme-toggle .icon {
|
||||
position: absolute;
|
||||
transition: all var(--transition-duration) cubic-bezier(0.4, 0, 0.2, 1);
|
||||
fill: var(--md-sys-color-refresh-button);
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.theme-toggle .moon-icon {
|
||||
opacity: 1;
|
||||
transform: scale(1) rotate(0);
|
||||
}
|
||||
|
||||
.theme-toggle .sun-icon {
|
||||
opacity: 0;
|
||||
transform: scale(0.5) rotate(90deg);
|
||||
}
|
||||
|
||||
html[data-darkmode="true"] .theme-toggle .moon-icon {
|
||||
opacity: 0;
|
||||
transform: scale(0.5) rotate(-90deg);
|
||||
}
|
||||
|
||||
html[data-darkmode="true"] .theme-toggle .sun-icon {
|
||||
opacity: 1;
|
||||
transform: scale(1) rotate(0);
|
||||
}
|
||||
|
||||
.theme-toggle:hover .icon {
|
||||
transform: rotate(15deg) scale(1.1);
|
||||
}
|
||||
|
||||
html[data-darkmode="true"] .theme-toggle:hover .icon {
|
||||
transform: rotate(-15deg) scale(1.1);
|
||||
}
|
||||
|
||||
/* 添加点击效果 */
|
||||
.theme-toggle:active .icon {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
/* System preference detection */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html[data-darkmode="auto"] {
|
||||
--primary: #bb86fc;
|
||||
--surface-1: #121212;
|
||||
--surface-2: #1e1e1e;
|
||||
--on-surface: #ffffff;
|
||||
--on-surface-variant: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body class="lang_{{ dispatcher.lang }} {{ entityencode(striptags(node?.title ?? ''), true) }}" data-page="{{ entityencode(join('-', ctx.request_path), true) }}">
|
||||
{% if (!blank_page): %}
|
||||
<header>
|
||||
<div class="menu-btn">
|
||||
<span aria-label="{{ _('Toggle navigation menu') }}"></span>
|
||||
</div>
|
||||
|
||||
<a class="brand" href="/">{{ striptags(boardinfo.hostname ?? '?') }}</a>
|
||||
|
||||
<div class="header-controls">
|
||||
<a href="#" class="header-icon theme-toggle" id="theme-toggle" title="{{ _('Toggle dark mode') }}">
|
||||
<svg class="icon moon-icon" width="20" height="25" viewBox="0 0 24 24">
|
||||
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1-8.313-12.454z"/>
|
||||
</svg>
|
||||
<svg class="icon sun-icon" width="20" height="25" viewBox="0 0 24 24">
|
||||
<path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<div id="indicators" class="pull-right"></div>
|
||||
</div>
|
||||
</header>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const toggle = document.getElementById('theme-toggle');
|
||||
const html = document.documentElement;
|
||||
const transitionDuration = 300; // ms
|
||||
|
||||
// 初始化主题(自动检测+记忆手动设置)
|
||||
function initTheme() {
|
||||
const manualMode = localStorage.getItem('luci-theme-manual');
|
||||
const autoMode = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'true' : 'false';
|
||||
const initMode = manualMode || autoMode;
|
||||
|
||||
// 添加过渡类
|
||||
html.classList.add('theme-transition');
|
||||
html.setAttribute('data-darkmode', initMode);
|
||||
updateToggleState(initMode);
|
||||
|
||||
// 移除过渡类
|
||||
setTimeout(() => {
|
||||
html.classList.remove('theme-transition');
|
||||
}, transitionDuration);
|
||||
}
|
||||
|
||||
// 更新开关状态
|
||||
function updateToggleState(isDark) {
|
||||
if (toggle) {
|
||||
toggle.checked = isDark === 'true';
|
||||
// 添加切换动画
|
||||
toggle.classList.add('theme-switching');
|
||||
setTimeout(() => {
|
||||
toggle.classList.remove('theme-switching');
|
||||
}, transitionDuration);
|
||||
}
|
||||
}
|
||||
|
||||
// 切换主题(单次点击)
|
||||
function toggleTheme() {
|
||||
const current = html.getAttribute('data-darkmode');
|
||||
const newMode = current === 'true' ? 'false' : 'true';
|
||||
|
||||
// 添加过渡类
|
||||
html.classList.add('theme-transition');
|
||||
|
||||
// 更新状态
|
||||
html.setAttribute('data-darkmode', newMode);
|
||||
localStorage.setItem('luci-theme-manual', newMode);
|
||||
updateToggleState(newMode);
|
||||
|
||||
// 移除过渡类
|
||||
setTimeout(() => {
|
||||
html.classList.remove('theme-transition');
|
||||
}, transitionDuration);
|
||||
|
||||
// 同步到服务端
|
||||
fetch('<%=url("admin/system/set-darkmode")%>', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
mode: newMode,
|
||||
source: 'manual'
|
||||
})
|
||||
}).catch(error => {
|
||||
console.error('Failed to sync theme preference:', error);
|
||||
});
|
||||
}
|
||||
|
||||
// 监听系统主题变化
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
|
||||
if (!localStorage.getItem('luci-theme-manual')) {
|
||||
const newMode = e.matches ? 'true' : 'false';
|
||||
html.classList.add('theme-transition');
|
||||
html.setAttribute('data-darkmode', newMode);
|
||||
updateToggleState(newMode);
|
||||
setTimeout(() => {
|
||||
html.classList.remove('theme-transition');
|
||||
}, transitionDuration);
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化
|
||||
initTheme();
|
||||
|
||||
// 点击事件
|
||||
if (toggle) {
|
||||
toggle.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
toggleTheme();
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<aside class="sidebar">
|
||||
<ul class="nav" id="topmenu" style="display:none"></ul>
|
||||
</aside>
|
||||
|
||||
<div id="maincontent" class="container">
|
||||
{% if (getuid() == 0 && getspnam('root')?.pwdp === ''): %}
|
||||
<div class="alert-message warning">
|
||||
<h4>{{ _('No password set!') }}</h4>
|
||||
<p>{{ _('There is no password set on this router. Please configure a root password to protect the web interface.') }}</p>
|
||||
{% if (dispatcher.lookup("admin/system/admin")): %}
|
||||
<div class="right"><a class="btn" href="{{ dispatcher.build_url("admin/system/admin") }}">{{ _('Go to password configuration...') }}</a></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if (boardinfo.rootfs_type == "initramfs"): %}
|
||||
<div class="alert-message warning">
|
||||
<h4>{{ _('System running in recovery (initramfs) mode.') }}</h4>
|
||||
<p>{{ _('No changes to settings will be stored and are lost after rebooting. This mode should only be used to install a firmware upgrade') }}</p>
|
||||
{% if (dispatcher.lookup("admin/system/flash")): %}
|
||||
<div class="right"><a class="btn" href="{{ dispatcher.build_url("admin/system/flash") }}">{{ _('Go to firmware upgrade...') }}</a></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<noscript>
|
||||
<div class="alert-message warning">
|
||||
<h4>{{ _('JavaScript required!') }}</h4>
|
||||
<p>{{ _('You must enable JavaScript in your browser or LuCI will not work properly.') }}</p>
|
||||
</div>
|
||||
</noscript>
|
||||
|
||||
<div id="tabmenu" style="display:none"></div>
|
||||
{% endif %}
|
||||
@@ -0,0 +1,48 @@
|
||||
{#
|
||||
Copyright 2022 Jo-Philipp Wich <jo@mein.io>
|
||||
Licensed to the public under the Apache License 2.0.
|
||||
-#}
|
||||
|
||||
{% include('header', { blank_page: true }) %}
|
||||
|
||||
<section hidden>
|
||||
<form method="post" class="cbi-map">
|
||||
<div class="cbi-section">
|
||||
<div class="cbi-section-node">
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title" for="luci_username">{{ _('Username') }}</label>
|
||||
<div class="cbi-value-field">
|
||||
<input name="luci_username" id="luci_username" type="text" autocomplete="username" value="{{ entityencode(duser, true) }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title" for="luci_password">{{ _('Password') }}</label>
|
||||
<div class="cbi-value-field">
|
||||
<input name="luci_password" id="luci_password" type="password" autocomplete="current-password">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
{% if (fuser): %}
|
||||
<div class="alert-message error">
|
||||
{{ _('Invalid username and/or password! Please try again.') }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<button class="btn cbi-button-positive important">{{ _('Log in') }}</button>
|
||||
</section>
|
||||
|
||||
<div id="view">
|
||||
<div class="spinning">{{ _('Loading view…') }}</div>
|
||||
<script>
|
||||
L.require('ui').then(function(ui) {
|
||||
ui.instantiateView('material3.sysauth');
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
|
||||
{% include('footer', { blank_page: true }) %}
|
||||
Reference in new issue
Block a user