导航页现在会自动检测浏览历史插件是否已安装: - 扩展在用户配置的服务地址上动态注册 content script (Chrome: chrome.scripting.registerContentScripts, Firefox: browser.contentScripts.register), 于 document_start 给 <html> 打上 data-navi-ext 标记, 不在其他站点运行。 - history-server 始终把「安装浏览历史插件」放在「历史访问」第一条 (入口 url=/extension/install.html),启动时也会重建一次, 不再需要等下一次同步。 - web/navi.js 读到标记后隐藏该入口(连 .item-wrapper 一起隐藏, 避免留下空网格位)。 - 新增 /extension/install.html:自动识别浏览器,给出对应安装包与步骤; 支持在 data 卷放 extension-store.json 配置商店链接, 有商店链接时显示真正的「一键安装」。 - 段落名匹配同时兼容中英文(常用服务/Favorites、历史访问/History), 修掉了公开示例 conf.yml 用英文名时重建逻辑完全失效的问题。 - 扩展升到 1.1.0(新增 scripting 权限与 detect.js)。 Note: Chrome/Edge 不允许从网站直接安装非商店扩展, 因此自托管场景下只能下载后手动加载;发布到商店后才会出现一键安装。
151 lines
7.0 KiB
HTML
151 lines
7.0 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<link rel="icon" href="data:,">
|
||
<title>安装浏览历史插件</title>
|
||
<style>
|
||
*{box-sizing:border-box;margin:0;padding:0}
|
||
body{font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",sans-serif;
|
||
background:#0f172a;color:#e2e8f0;line-height:1.6;padding:32px 20px}
|
||
.wrap{max-width:720px;margin:0 auto}
|
||
h1{font-size:24px;font-weight:700;margin-bottom:8px}
|
||
.sub{color:#94a3b8;font-size:14px;margin-bottom:24px}
|
||
.card{background:#1e293b;border:1px solid #334155;border-radius:12px;padding:20px 22px;margin-bottom:16px}
|
||
.card h2{font-size:17px;font-weight:600;margin-bottom:12px;display:flex;align-items:center;gap:8px}
|
||
.badge{font-size:12px;font-weight:600;padding:2px 8px;border-radius:999px;
|
||
background:#1e3a5f;color:#93c5fd;border:1px solid #2563eb}
|
||
.card.current{border-color:#2563eb;box-shadow:0 0 0 1px #2563eb inset}
|
||
ol{margin:0 0 0 20px;font-size:14px;color:#cbd5e1}
|
||
ol li{margin-bottom:6px}
|
||
a{color:#60a5fa}
|
||
code{background:#0f172a;border:1px solid #334155;border-radius:4px;padding:1px 6px;font-size:13px}
|
||
.note{font-size:13px;color:#94a3b8;margin-top:12px;border-top:1px solid #334155;padding-top:12px}
|
||
.actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:14px}
|
||
.btn{display:inline-block;padding:9px 18px;border-radius:8px;font-size:14px;font-weight:600;
|
||
text-decoration:none;border:1px solid #334155;background:#0f172a;color:#e2e8f0;cursor:pointer}
|
||
.btn.primary{background:#2563eb;border-color:#2563eb;color:#fff}
|
||
.btn.primary:hover{background:#1d4ed8}
|
||
.btn:hover{border-color:#475569}
|
||
.site{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:10px}
|
||
.site input{flex:1;min-width:260px;background:#0f172a;border:1px solid #334155;border-radius:8px;
|
||
padding:9px 12px;color:#e2e8f0;font-size:14px}
|
||
.hint{font-size:13px;color:#94a3b8;margin-top:10px}
|
||
.steps-done{font-size:13px;color:#86efac;margin-top:10px}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="wrap">
|
||
<h1>安装浏览历史插件</h1>
|
||
<p class="sub">安装后浏览记录会自动同步到本站,并据此把最常访问的服务排到「常用服务」最前面。</p>
|
||
|
||
<div class="card">
|
||
<h2>第一步:填写本站地址</h2>
|
||
<p class="hint">在插件设置里粘贴下面这个地址(点「复制」)。同步令牌从部署方的 <code>NAVI_SYNC_TOKEN</code> 环境变量获取。</p>
|
||
<div class="site">
|
||
<input id="site-url" readonly>
|
||
<button class="btn" id="copy-btn" type="button">复制</button>
|
||
</div>
|
||
<div class="steps-done" id="copy-done" hidden>已复制</div>
|
||
</div>
|
||
|
||
<div class="card" id="card-chromium" hidden>
|
||
<h2>Chrome / Edge <span class="badge">已识别你的浏览器</span></h2>
|
||
<div class="actions">
|
||
<a class="btn primary" id="store-chromium" hidden>从商店一键安装</a>
|
||
<a class="btn" href="/extension/navi-chrome.zip" download>下载扩展包(zip)</a>
|
||
</div>
|
||
<ol>
|
||
<li>解压下载的 zip 到一个固定目录(不要删除)</li>
|
||
<li>地址栏打开 <code>chrome://extensions</code>,Edge 用 <code>edge://extensions</code></li>
|
||
<li>打开右上角「开发者模式」</li>
|
||
<li>点「加载已解压的扩展程序」,选择解压出来的目录</li>
|
||
<li>点扩展图标,填入上面的本站地址与同步令牌,保存</li>
|
||
</ol>
|
||
<p class="note">Chrome 不允许从网站直接安装非商店扩展,所以这里只能下载后手动加载。若已发布到商店,上面的「一键安装」按钮会自动出现。</p>
|
||
</div>
|
||
|
||
<div class="card" id="card-firefox" hidden>
|
||
<h2>Firefox <span class="badge">已识别你的浏览器</span></h2>
|
||
<div class="actions">
|
||
<a class="btn primary" id="store-firefox" hidden>从商店一键安装</a>
|
||
<a class="btn" href="/extension/navi-firefox.xpi" download>下载扩展包(xpi)</a>
|
||
</div>
|
||
<ol>
|
||
<li>地址栏打开 <code>about:debugging#/runtime/this-firefox</code></li>
|
||
<li>点「临时加载附加组件」,选择下载的 xpi</li>
|
||
<li>点扩展图标,填入上面的本站地址与同步令牌,保存</li>
|
||
</ol>
|
||
<p class="note">Firefox 正式版只接受签名附加组件;未签名的 xpi 只能在开发者版 / ESR 上加载,或在 <code>about:config</code> 关闭 <code>xpinstall.signatures.required</code>。发布到 AMO 后可用上面的「一键安装」。</p>
|
||
</div>
|
||
|
||
<div class="card" id="card-other" hidden>
|
||
<h2>其他浏览器</h2>
|
||
<p class="hint">未能识别具体浏览器。Chromium 内核(Brave、Vivaldi、Opera、Kiwi 等)请按上面 Chrome 的步骤操作;Firefox 请按 Firefox 的步骤操作。</p>
|
||
<div class="actions">
|
||
<a class="btn" href="/extension/navi-chrome.zip" download>下载 Chromium 版(zip)</a>
|
||
<a class="btn" href="/extension/navi-firefox.xpi" download>下载 Firefox 版(xpi)</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<h2>装好后</h2>
|
||
<ol>
|
||
<li>回到导航页并刷新,本次会话浏览几条页面</li>
|
||
<li>约 30 秒后历史会自动上报,「历史访问」开始按访问频次排序</li>
|
||
<li>检测到插件已安装后,本入口会自动隐藏</li>
|
||
</ol>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
(function () {
|
||
'use strict';
|
||
|
||
document.getElementById('site-url').value = location.origin;
|
||
|
||
var copyBtn = document.getElementById('copy-btn');
|
||
copyBtn.addEventListener('click', function () {
|
||
var input = document.getElementById('site-url');
|
||
input.select();
|
||
input.setSelectionRange(0, 999);
|
||
var done = document.getElementById('copy-done');
|
||
function ok() { done.hidden = false; setTimeout(function () { done.hidden = true; }, 2000); }
|
||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||
navigator.clipboard.writeText(input.value).then(ok, function () { document.execCommand('copy'); ok(); });
|
||
} else {
|
||
document.execCommand('copy'); ok();
|
||
}
|
||
});
|
||
|
||
// 浏览器识别:Firefox 用 UA 判断,其余按 Chromium 处理。
|
||
var ua = navigator.userAgent;
|
||
var isFirefox = /firefox\/|fxios\//i.test(ua);
|
||
var isChromium = /chrome\/|chromium\/|edg\//i.test(ua);
|
||
var card = document.getElementById(isFirefox ? 'card-firefox' : (isChromium ? 'card-chromium' : 'card-other'));
|
||
card.hidden = false;
|
||
card.classList.add('current');
|
||
|
||
// 可选:部署方在 /app/data/extension-store.json 放商店链接后,
|
||
// 对应平台的「一键安装」按钮会自动出现(无需重建镜像)。
|
||
fetch('/extension/store.json', { cache: 'no-store' })
|
||
.then(function (r) { return r.ok ? r.json() : null; })
|
||
.then(function (s) {
|
||
if (!s) return;
|
||
if (s.chrome) showStore('store-chromium', s.chrome);
|
||
if (s.firefox) showStore('store-firefox', s.firefox);
|
||
})
|
||
.catch(function () { /* 未配置商店链接,保持手动安装步骤 */ });
|
||
|
||
function showStore(id, url) {
|
||
var el = document.getElementById(id);
|
||
if (!el) return;
|
||
el.href = url;
|
||
el.hidden = false;
|
||
}
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|