v28 第 28 批(12 条):名册分组改标签 / 资源合并为两按钮 / 首页定位与主题色 / 笔记富文本双模式
其中 4 条是**上批遗漏的真 bug**(1/4/8/9),根因已逐条定位:
1. 首页日程没定位到红线 —— 真根因:刻度区间**不含当前时刻** → $showNow=false
→ 红线**整个不渲染**,而定位脚本用同一个越界比例算目标,被 clamp 到底部。
修:把当前小时并进区间端点(现在必然落在区间内)。
2. 「看整月」→「更多日程」+ 日程主题色;3. 「手头在做」→「近期任务」、
「任务看板」→「全部任务」+ 任务主题色(注入 --hd-c,不再写死白底)。
4. 任务复选框提示还在 —— 真根因:**JS 在点击后**给状态徽标挂 title
(`badge.setAttribute('title',…)`),上批只去了静态渲染,静态断言永远抓不到。
5. 名册「分组」→「标签」(用户:一个人可能既是小学同学又是初中同学,没法分组):
新增 person_tags(每人一份、一人多标签),名册改**平铺 + 顶部标签筛选**;
🔴 迁移用**一次性哨兵**(第一版用 NOT EXISTS,实测被"用户清空标签"绕过 → 旧分组名被灌回)。
6. 名册卡片按钮加语义底色。
7. 资源四按钮 → **编辑 / 删除**两颗:三块内容进一个带页签的弹框(信息/附件/共享)。
8. 财务多选数字不变 —— 真根因:前端发 `kinds=a,b`(逗号串),服务端 `(array)` 收成
单元素 → 求交为空 → **静默回落整本账**。修:两种形状都收。
9. 微信读书偶发很慢 —— 真根因:syncNow 扫 60 本 × 每本 1~3 次网关调用(单次超时 20s),
全同步阻塞在列表页请求里。修:总时长预算 + 单次超时 8s + 自动/手动分批。
10. 新增全局可见的联想接口库(6 个实测可用来源)+ 三种新解析类型。
11. 导航右上角「设置」:默认进"添加网址 + 全部网址",四类设置收进 ?set=1 视图。
12. 笔记:段落/清单支持 Markdown(自研渲染器,**不允许原始 HTML**),
实时预览走服务端(前后端只一份规则);底部附件上传;清单多级;
列表改**定尺寸卡片网格**(溢出显示摘要、图片缩放下方);按用户要求**去掉标签侧栏**。
This commit is contained in:
+74
-1
@@ -41,15 +41,40 @@ foreach ($engines as $e) {
|
||||
if ((int)$e['id'] === $eEng) { $editEngine = $e; }
|
||||
}
|
||||
$sc = static fn($k, $d = '') => (string)($navSet[$k] ?? $d);
|
||||
/* 🔴 v28 用户第 11 条:「导航模块,右上角增加设置按钮,和其他模块一样。
|
||||
把导航展示地址,放进去,把导航设置,放进去,把板块设置,放进去,
|
||||
把搜索引擎的设置,也放进去,你参考一下之前的导航系统 simplenav,
|
||||
把之前的那些设置,都放在设置中,进来之后,默认就是添加网址,和所有网址的列表。」
|
||||
|
||||
⇒ 两种视图,用 `?set=1` 切(服务端渲染,无 JS 也能切;刷新/回退都不丢状态):
|
||||
· 默认(`?set` 空):**只显示「新增站点」+「站点列表」** —— 日常真正要用的两件事;
|
||||
· 设置(`?set=1`):展示地址 / 导航设置 / 板块 / 搜索引擎 四块。
|
||||
|
||||
⚠️ 为什么用查询参数而不是 JS 折叠:设置项里有表单(保存后会 302 回本页),
|
||||
用 JS 折叠的话每次保存回来都会**自动摊开全部设置**,用户还要再收一次。
|
||||
用参数就能让"保存后回到设置页"(下面的表单里保留了 `set=1` 的隐藏域)。
|
||||
⚠️ 保留 `$editSite` 等编辑态:正在编辑某个站点/板块/引擎时,**强制显示设置视图**,
|
||||
否则用户点"编辑板块"会看到一个没有板块表单的页面(看起来像功能坏了)。 */
|
||||
$inSettings = !empty($_GET['set']) || $editGroup !== null || $editEngine !== null;
|
||||
?>
|
||||
<div class="page-head">
|
||||
<h1>导航</h1>
|
||||
<span class="sub">你个人用的网址导航 · 每人一份</span>
|
||||
<div class="actions">
|
||||
<a class="btn btn-ghost btn-sm" href="<?= e(url('nav')) ?>">刷新</a>
|
||||
<?php /* v28 用户第 11 条:右上角「设置」按钮,与其他模块的手指位置一致。
|
||||
⚠️ 它是个**链接**(服务端切换视图),不是 JS 开关 —— 理由见上面的注释。 */ ?>
|
||||
<?php if ($inSettings): ?>
|
||||
<a class="btn btn-sm" href="<?= e(url('nav')) ?>">完成</a>
|
||||
<?php else: ?>
|
||||
<a class="btn btn-ghost btn-sm" href="<?= e(url('nav', ['set' => 1])) ?>">设置</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php /* 设置视图里的四块(展示地址 / 导航设置 / 板块 / 搜索引擎)。
|
||||
只在设置态渲染 —— 默认进来看到的是"添加网址 + 网址列表"(用户原话)。 */ ?>
|
||||
<?php if ($inSettings): ?><?php /* ==== 设置视图开始 ==== */ ?>
|
||||
|
||||
<?php /* ==================== ① 展示页地址与短语(用户第 4 条的"特殊地址")====================
|
||||
用户原话:「给他一个非常特殊的地址…地址后面可以跟着用户添加的一个短语,就跟类似
|
||||
于一个密钥一样,他可以给自己起一个短语…这个页面是不需要登录的。」
|
||||
@@ -171,6 +196,8 @@ $sc = static fn($k, $d = '') => (string)($navSet[$k] ?? $d);
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php endif; ?><?php /* ==== 设置视图(前半:展示地址 + 导航设置)结束 ==== */ ?>
|
||||
|
||||
<?php /* ==================== ③ 站点:新增/编辑 ==================== */ ?>
|
||||
<?php if ($canWrite): ?>
|
||||
<div class="card card-pad">
|
||||
@@ -301,6 +328,7 @@ $sc = static fn($k, $d = '') => (string)($navSet[$k] ?? $d);
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($inSettings): ?><?php /* ==== 设置视图(后半:板块 + 搜索引擎)重新开始 ==== */ ?>
|
||||
<?php /* ==================== ⑤ 板块 ==================== */ ?>
|
||||
<div class="card card-pad">
|
||||
<h2 class="cinema-h2"><?= $editGroup ? '编辑板块' : '新增板块' ?></h2>
|
||||
@@ -406,6 +434,30 @@ $sc = static fn($k, $d = '') => (string)($navSet[$k] ?? $d);
|
||||
value="<?= e((string)($editEngine['suggest_type'] ?? '')) ?>"
|
||||
placeholder="bing_osjson / baidu_sugrec / so360">
|
||||
</div>
|
||||
<?php /* 🔴 v28 用户第 10 条:「联想接口还是不能用啊,需要你补充几个进去,
|
||||
让用户选择。搜索引擎列表,联想接口,是**对所有用户可见**的。」
|
||||
⇒ 这里列出内置的联想接口库(App\Nav::SUGGEST_LIBRARY,全局共享一份),
|
||||
**点一下就把地址与类型填进上面两个框** —— 用户不必去记
|
||||
"sugrec 还是 osjson"这种东西,也不必手抄 URL(抄错一位就永远空下拉)。
|
||||
⚠️ 这些只是"填入表单",仍要用户点保存才生效 ——
|
||||
静默改数据会在用户没注意时改掉他自己的配置。 */ ?>
|
||||
<div class="field">
|
||||
<label>内置联想接口 <span class="hint">点一下即可填入上面两项</span></label>
|
||||
<div class="sug-lib">
|
||||
<?php foreach (\App\Nav::suggestLibrary() as $sl): ?>
|
||||
<button type="button" class="sug-lib-item"
|
||||
data-sug-url="<?= e((string)$sl['url']) ?>"
|
||||
data-sug-type="<?= e((string)$sl['type']) ?>">
|
||||
<b><?= e((string)$sl['name']) ?></b>
|
||||
<span><?= e((string)$sl['note']) ?></span>
|
||||
</button>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<span class="tip">
|
||||
这些接口对**所有用户**都可见、可直接选用。国内网络下不可达的
|
||||
(谷歌 / DuckDuckGo)没有列进来 —— 选了也只会永远是空下拉。
|
||||
</span>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>颜色</label>
|
||||
<input class="input" type="color" name="color"
|
||||
@@ -468,6 +520,7 @@ $sc = static fn($k, $d = '') => (string)($navSet[$k] ?? $d);
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?><?php /* ==== 设置视图(后半:板块 + 搜索引擎)结束 ==== */ ?>
|
||||
|
||||
<script>
|
||||
/* 导航管理页的交互(v24 第 24 批)。
|
||||
@@ -672,5 +725,25 @@ $sc = static fn($k, $d = '') => (string)($navSet[$k] ?? $d);
|
||||
lastLookup = '';
|
||||
});
|
||||
}
|
||||
|
||||
/* 🔴 v28 用户第 10 条:内置联想接口库 —— 点一下把地址+类型填进**同一个表单**里。
|
||||
⚠️ 用 closest('form') 定位,而不是 document.querySelector:
|
||||
页面上可能同时有"新增引擎"和"编辑引擎"两个表单(后者是 ?edit_engine=… 带出来的),
|
||||
用全局查找会把内容填到**另一个**表单里 —— 用户点了没反应、或更糟:填错地方。 */
|
||||
Array.prototype.forEach.call(document.querySelectorAll('.sug-lib-item'), function (b) {
|
||||
b.addEventListener('click', function () {
|
||||
var form = b.closest('form');
|
||||
if (!form) { return; }
|
||||
var u = form.querySelector('input[name="suggest_url"]');
|
||||
var t = form.querySelector('input[name="suggest_type"]');
|
||||
if (u) { u.value = b.getAttribute('data-sug-url') || ''; }
|
||||
if (t) { t.value = b.getAttribute('data-sug-type') || ''; }
|
||||
// 反馈:让用户看到"填进去了"(否则一片安静,会以为没点上)
|
||||
b.classList.add('is-picked');
|
||||
Array.prototype.forEach.call(b.parentNode.children, function (sib) {
|
||||
if (sib !== b) { sib.classList.remove('is-picked'); }
|
||||
});
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
Reference in New Issue
Block a user