2026-10-02 09:28:07 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 个人设置里的两块「模块」设置(用户 2026-10-01 第 10、11 条):
|
|
|
|
|
|
*
|
|
|
|
|
|
* ① **导航条上显示哪些模块、什么顺序** —— 每人一份(App\Module::navFor 读的就是它)。
|
|
|
|
|
|
* 勾选 = 出现在导航条上;拖动 / ▲▼ = 排序。
|
|
|
|
|
|
* ② **每个模块的主题色** —— **家庭一份**(settings('module_colors')),
|
|
|
|
|
|
* 所以只有管理员能改:一个家认同一套配色,不然同一个"观影"在爸爸那屏是紫的、
|
|
|
|
|
|
* 妈妈那屏是绿的,反而记不住。非管理员在这里只看得到色板。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 变量(require 前设好):
|
|
|
|
|
|
* $navKeys 我当前导航条上的顺序(只含显示的)
|
|
|
|
|
|
* $colors key => '#rrggbb'
|
|
|
|
|
|
*/
|
|
|
|
|
|
$allKeys = \App\Module::keys();
|
|
|
|
|
|
$onKeys = array_map('strval', (array)($navKeys ?? []));
|
|
|
|
|
|
// 显示顺序:已勾选的按现有顺序在前,未勾选的按 LIST 顺序在后(这样"关掉再打开"位置不跳)
|
|
|
|
|
|
$ordered = array_values(array_filter($allKeys, static fn($k) => in_array($k, $onKeys, true)));
|
|
|
|
|
|
foreach ($allKeys as $k) {
|
|
|
|
|
|
if (!in_array($k, $ordered, true)) {
|
|
|
|
|
|
$ordered[] = $k;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
$isAdmin = \App\Auth::isAdmin();
|
|
|
|
|
|
?>
|
|
|
|
|
|
<!-- ==================== 导航条上的模块 ==================== -->
|
|
|
|
|
|
<div class="card card-pad" id="modules" style="margin-top:20px">
|
|
|
|
|
|
<h2 class="section-title">
|
|
|
|
|
|
导航条上的模块
|
|
|
|
|
|
<span class="hint">勾上才会出现在顶部,拖动可改顺序</span>
|
|
|
|
|
|
</h2>
|
|
|
|
|
|
<p class="small muted" style="margin:0 0 16px">
|
|
|
|
|
|
模块越来越多,但每个人关心的不一样 —— 这里只挑你常用的几个上导航条,其余的仍然能
|
|
|
|
|
|
从别处进(比如观影里还能进影院管理)。关掉的模块<b>不会丢数据</b>,只是从顶栏收起来。
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<form method="post" action="<?= e(url('settings/nav_save')) ?>" id="navForm">
|
|
|
|
|
|
<?= csrf_field() ?>
|
|
|
|
|
|
<ol class="order-list mod-order" id="navOrderList">
|
|
|
|
|
|
<?php foreach ($ordered as $i => $k): ?>
|
|
|
|
|
|
<li class="order-row mod-row" draggable="true" data-key="<?= e($k) ?>">
|
|
|
|
|
|
<span class="drag-handle" title="拖我排序" aria-hidden="true">⋮⋮</span>
|
|
|
|
|
|
<?php /* ⚠️ 顺序就藏在 DOM 里:每个 <li> 自带一个 order[] 隐藏域,
|
|
|
|
|
|
拖动搬的是整个 <li>,所以提交上来的顺序天然就是屏幕上的顺序。
|
|
|
|
|
|
没有 JS 时 ▲▼ 按钮走同一份表单(服务端按 move 参数交换后再存)。 */ ?>
|
|
|
|
|
|
<input type="hidden" name="order[]" value="<?= e($k) ?>">
|
|
|
|
|
|
<label class="mod-pick">
|
|
|
|
|
|
<input type="checkbox" name="on[]" value="<?= e($k) ?>"
|
|
|
|
|
|
<?= in_array($k, $onKeys, true) ? 'checked' : '' ?>>
|
|
|
|
|
|
<span class="color-preview" style="background: <?= e((string)($colors[$k] ?? '#888')) ?>;"></span>
|
|
|
|
|
|
<span class="order-name"><?= e(\App\Module::name($k)) ?></span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<span class="order-move">
|
|
|
|
|
|
<button class="btn btn-ghost btn-sm" type="submit" name="move" value="up:<?= e($k) ?>"
|
|
|
|
|
|
title="上移" <?= $i === 0 ? 'disabled' : '' ?>>▲</button>
|
|
|
|
|
|
<button class="btn btn-ghost btn-sm" type="submit" name="move" value="down:<?= e($k) ?>"
|
|
|
|
|
|
title="下移" <?= $i === count($ordered) - 1 ? 'disabled' : '' ?>>▼</button>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</li>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</ol>
|
|
|
|
|
|
<div class="btn-row">
|
|
|
|
|
|
<button class="btn" type="submit" name="save" value="1">保存导航条</button>
|
|
|
|
|
|
<a class="btn btn-ghost" href="<?= e(url('settings/me')) ?>">重来</a>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ==================== 模块主题色 ==================== -->
|
|
|
|
|
|
<div class="card card-pad" style="margin-top:20px">
|
|
|
|
|
|
<h2 class="section-title">
|
|
|
|
|
|
模块主题色
|
|
|
|
|
|
<span class="hint"><?= $isAdmin ? '全家共用一套' : '由管理员设置' ?></span>
|
|
|
|
|
|
</h2>
|
|
|
|
|
|
<p class="small muted" style="margin:0 0 16px">
|
|
|
|
|
|
进到哪个模块,顶栏高亮与按钮就换成那个模块的颜色 —— 一眼就知道自己在哪儿。
|
|
|
|
|
|
<?php if (!$isAdmin): ?>
|
|
|
|
|
|
<br>这是<b>全家共用</b>的一套配色(不然同一个「观影」在两个人屏幕上两种颜色,反而记不住),
|
|
|
|
|
|
所以只有管理员能改。
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<?php if (!$isAdmin): ?>
|
|
|
|
|
|
<div class="mod-swatches">
|
|
|
|
|
|
<?php foreach ($allKeys as $k): ?>
|
|
|
|
|
|
<span class="mod-swatch">
|
|
|
|
|
|
<span class="color-preview" style="background: <?= e((string)($colors[$k] ?? '#888')) ?>;"></span>
|
|
|
|
|
|
<?= e(\App\Module::name($k)) ?>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<?php else: ?>
|
|
|
|
|
|
<form method="post" action="<?= e(url('settings/module_colors')) ?>">
|
|
|
|
|
|
<?= csrf_field() ?>
|
|
|
|
|
|
<div class="mod-colors">
|
|
|
|
|
|
<?php foreach ($allKeys as $k): ?>
|
|
|
|
|
|
<?php $cid = 'mc-' . $k; ?>
|
|
|
|
|
|
<div class="mod-color-row">
|
|
|
|
|
|
<span class="mod-color-name"><?= e(\App\Module::name($k)) ?></span>
|
|
|
|
|
|
<input type="color" class="color-picker" id="<?= e($cid) ?>" name="c[<?= e($k) ?>]"
|
|
|
|
|
|
value="<?= e((string)($colors[$k] ?? '#888888')) ?>">
|
|
|
|
|
|
<span class="mod-preset">
|
|
|
|
|
|
<?php foreach (\App\Module::PRESET_COLORS as $pc): ?>
|
|
|
|
|
|
<span class="preset-color" data-color="<?= $pc ?>" data-for="<?= e($cid) ?>"
|
|
|
|
|
|
style="background: <?= $pc ?>;" title="<?= $pc ?>"></span>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="btn-row">
|
|
|
|
|
|
<button class="btn" type="submit">保存主题色</button>
|
|
|
|
|
|
<button class="btn btn-ghost" type="submit" name="reset" value="1"
|
|
|
|
|
|
onclick="return confirm('恢复成默认配色?')">恢复默认</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
(function () {
|
2026-10-03 11:30:48 +08:00
|
|
|
|
/* ---- 拖动排序(▲▼ 是不用 JS 的兜底,两条路都能用)----
|
|
|
|
|
|
⚠️ 遍历**所有** `ol.order-list`,而不是只找 navOrderList:
|
|
|
|
|
|
本页现在有两块同构的清单(首页上的模块 / 导航条上的模块),
|
|
|
|
|
|
写死 id 的话第二块就没有拖动了 —— 而且看起来"功能好好的",
|
|
|
|
|
|
只是那一块拖不动,很难联想到是这里写死了 id。 */
|
|
|
|
|
|
function bindSort(list) {
|
2026-10-02 09:28:07 +08:00
|
|
|
|
if (!list) return;
|
|
|
|
|
|
var dragEl = null;
|
|
|
|
|
|
Array.prototype.forEach.call(list.querySelectorAll('.mod-row'), function (li) {
|
|
|
|
|
|
li.addEventListener('dragstart', function (ev) {
|
|
|
|
|
|
dragEl = li;
|
|
|
|
|
|
li.classList.add('is-dragged');
|
|
|
|
|
|
if (ev.dataTransfer) { ev.dataTransfer.effectAllowed = 'move'; }
|
|
|
|
|
|
});
|
|
|
|
|
|
li.addEventListener('dragend', function () {
|
|
|
|
|
|
li.classList.remove('is-dragged');
|
|
|
|
|
|
dragEl = null;
|
|
|
|
|
|
Array.prototype.forEach.call(list.querySelectorAll('.mod-row'), function (x) {
|
|
|
|
|
|
x.classList.remove('is-drop-before');
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
li.addEventListener('dragover', function (ev) {
|
|
|
|
|
|
if (!dragEl || dragEl === li) return;
|
|
|
|
|
|
ev.preventDefault();
|
|
|
|
|
|
var box = li.getBoundingClientRect();
|
|
|
|
|
|
var before = ev.clientY < box.top + box.height / 2;
|
|
|
|
|
|
li.classList.toggle('is-drop-before', before);
|
|
|
|
|
|
li.classList.toggle('is-drop-after', !before);
|
|
|
|
|
|
});
|
|
|
|
|
|
li.addEventListener('dragleave', function () {
|
|
|
|
|
|
li.classList.remove('is-drop-before', 'is-drop-after');
|
|
|
|
|
|
});
|
|
|
|
|
|
li.addEventListener('drop', function (ev) {
|
|
|
|
|
|
if (!dragEl || dragEl === li) return;
|
|
|
|
|
|
ev.preventDefault();
|
|
|
|
|
|
var box = li.getBoundingClientRect();
|
|
|
|
|
|
var before = ev.clientY < box.top + box.height / 2;
|
|
|
|
|
|
/* 搬的是整个 <li> —— 它自带的 order[] 隐藏域跟着走,
|
|
|
|
|
|
所以提交上来的顺序 = 屏幕上的顺序,不用再同步一遍。 */
|
|
|
|
|
|
if (before) { list.insertBefore(dragEl, li); } else { list.insertBefore(dragEl, li.nextSibling); }
|
|
|
|
|
|
li.classList.remove('is-drop-before', 'is-drop-after');
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
2026-10-03 11:30:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
Array.prototype.forEach.call(document.querySelectorAll('ol.order-list'), bindSort);
|
2026-10-02 09:28:07 +08:00
|
|
|
|
|
|
|
|
|
|
/* ---- 色板点一下就换 ---- */
|
|
|
|
|
|
Array.prototype.forEach.call(document.querySelectorAll('.preset-color[data-for]'), function (el) {
|
|
|
|
|
|
el.addEventListener('click', function () {
|
|
|
|
|
|
var target = document.getElementById(el.getAttribute('data-for'));
|
|
|
|
|
|
if (target) { target.value = el.getAttribute('data-color'); }
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
})();
|
|
|
|
|
|
</script>
|