223 lines
8.1 KiB
JavaScript
223 lines
8.1 KiB
JavaScript
/* 魂镜原型 · 共享交互脚本
|
|
主题切换 · logo 彩蛋(镜启)· 主侧栏折叠 · 对话页面板折叠 · 演示态切换 */
|
|
(function () {
|
|
"use strict";
|
|
|
|
/* ---------- 主题切换(localStorage 持久化,仅原型演示用) ---------- */
|
|
var saved = null;
|
|
try { saved = localStorage.getItem("hunjing-prototype-theme"); } catch (e) { /* 忽略 */ }
|
|
if (saved === "light" || saved === "dark") {
|
|
document.documentElement.setAttribute("data-theme", saved);
|
|
}
|
|
window.hjSetTheme = function (theme) {
|
|
document.documentElement.setAttribute("data-theme", theme);
|
|
try { localStorage.setItem("hunjing-prototype-theme", theme); } catch (e) { /* 忽略 */ }
|
|
document.querySelectorAll("[data-theme-toggle]").forEach(function (btn) {
|
|
btn.setAttribute("aria-label", theme === "dark" ? "切换到月白主题" : "切换到墨色主题");
|
|
});
|
|
};
|
|
|
|
document.addEventListener("click", function (ev) {
|
|
var btn = ev.target.closest("[data-theme-toggle]");
|
|
if (!btn) return;
|
|
var cur = document.documentElement.getAttribute("data-theme") === "light" ? "light" : "dark";
|
|
window.hjSetTheme(cur === "dark" ? "light" : "dark");
|
|
});
|
|
|
|
/* ---------- logo:单击回目录;350ms 内连点 5 次触发「镜启」彩蛋 ----------
|
|
承接 main 分支旧版设计:镜启不跳转,随机呈上一句镜铭。 */
|
|
var EGG_VERSES = [
|
|
"镜中有镜,心外无心。",
|
|
"汝来看此镜时,此镜亦照汝。",
|
|
"一念起,万镜生。",
|
|
"镜非鉴物,乃鉴心也。",
|
|
"幻由心生,镜随心转。",
|
|
"铜镜本无字,照尽往来人。",
|
|
"且向镜中看,那个是谁?",
|
|
];
|
|
var logoClickSeq = 0;
|
|
var lastLogoTime = 0;
|
|
var jumpTimer = null;
|
|
|
|
function showEggToast(msg) {
|
|
var toast = document.createElement("div");
|
|
toast.className = "egg-toast";
|
|
toast.textContent = msg;
|
|
document.body.appendChild(toast);
|
|
requestAnimationFrame(function () { toast.classList.add("is-on"); });
|
|
setTimeout(function () {
|
|
toast.classList.remove("is-on");
|
|
setTimeout(function () { toast.remove(); }, 450);
|
|
}, 2400);
|
|
}
|
|
|
|
function onBrandClick(brandEl) {
|
|
clearTimeout(jumpTimer);
|
|
var now = Date.now();
|
|
var fast = now - lastLogoTime < 380; /* 380ms 内视为连点 */
|
|
lastLogoTime = now;
|
|
if (brandEl) {
|
|
brandEl.classList.add("tick");
|
|
setTimeout(function () { brandEl.classList.remove("tick"); }, 300);
|
|
}
|
|
if (fast) {
|
|
logoClickSeq += 1;
|
|
if (logoClickSeq >= 4) {
|
|
/* 首击 + 4 次连点 = 共 5 次点击:镜启彩蛋,不跳转 */
|
|
logoClickSeq = 0;
|
|
var v = EGG_VERSES[Math.floor(Math.random() * EGG_VERSES.length)];
|
|
if (brandEl) {
|
|
brandEl.classList.add("egg-pulse");
|
|
setTimeout(function () { brandEl.classList.remove("egg-pulse"); }, 1400);
|
|
}
|
|
showEggToast("镜启 · " + v);
|
|
}
|
|
return; /* 连点不跳转 */
|
|
}
|
|
logoClickSeq = 0;
|
|
/* 单击延迟跳转,为连点留出窗口 */
|
|
jumpTimer = setTimeout(function () { location.href = "index.html"; }, 380);
|
|
}
|
|
|
|
/* ---------- 主侧栏折叠(localStorage 持久化) ---------- */
|
|
function applySidebarFold(collapsed) {
|
|
document.querySelectorAll(".app").forEach(function (app) {
|
|
app.classList.toggle("app--fold", collapsed);
|
|
});
|
|
}
|
|
function sidebarFolded() {
|
|
var app = document.querySelector(".app");
|
|
return !!(app && app.classList.contains("app--fold"));
|
|
}
|
|
|
|
/* ---------- 对话页左右面板折叠 ---------- */
|
|
function panelFold(which) {
|
|
var layout = document.querySelector(".conv-layout");
|
|
if (!layout) return;
|
|
layout.classList.toggle("no-" + which);
|
|
}
|
|
|
|
/* ---------- 事件委托 ---------- */
|
|
document.addEventListener("click", function (ev) {
|
|
var t = ev.target;
|
|
if (!t || !t.closest) return;
|
|
|
|
var foldBtn = t.closest("[data-sidebar-fold]");
|
|
if (foldBtn) {
|
|
ev.preventDefault();
|
|
var collapsed = !sidebarFolded();
|
|
applySidebarFold(collapsed);
|
|
try { localStorage.setItem("hunjing-prototype-sidebar", collapsed ? "collapsed" : "expanded"); } catch (e) { /* 忽略 */ }
|
|
return;
|
|
}
|
|
|
|
var panelBtn = t.closest("[data-panel-fold]");
|
|
if (panelBtn) {
|
|
ev.preventDefault();
|
|
panelFold(panelBtn.getAttribute("data-panel-fold"));
|
|
return;
|
|
}
|
|
|
|
var brand = t.closest(".brand");
|
|
if (brand) {
|
|
ev.preventDefault();
|
|
onBrandClick(brand);
|
|
return;
|
|
}
|
|
});
|
|
|
|
/* 恢复折叠状态 */
|
|
try {
|
|
var foldSaved = localStorage.getItem("hunjing-prototype-sidebar");
|
|
if (foldSaved === "collapsed") applySidebarFold(true);
|
|
} catch (e) { /* 忽略 */ }
|
|
|
|
/* ---------- 深虑:点击 = 开启深度思考(右侧伴随力度选项);再次点击 = 关闭并隐藏选项 ---------- */
|
|
function setEffortHint(on, val) {
|
|
var hint = document.querySelector("[data-effort-hint]");
|
|
if (hint) hint.textContent = on ? "深虑 · " + val : "深虑 · 关";
|
|
}
|
|
|
|
document.addEventListener("click", function (ev) {
|
|
var t = ev.target;
|
|
if (!t || !t.closest) return;
|
|
|
|
/* 力度选项:独立控件,只调档,与深虑开关动作无关(关闭态隐藏时不响应) */
|
|
var opt = t.closest("[data-effort-seg] button[data-effort]");
|
|
if (opt) {
|
|
ev.preventDefault();
|
|
ev.stopPropagation();
|
|
if (opt.closest("[data-effort-seg]").hidden) return;
|
|
document.querySelectorAll("[data-effort-seg] button").forEach(function (b) {
|
|
b.setAttribute("aria-checked", String(b === opt));
|
|
});
|
|
setEffortHint(true, opt.getAttribute("data-effort"));
|
|
return;
|
|
}
|
|
|
|
/* 深虑按钮:开 ⇄ 关 */
|
|
var pill = t.closest('[data-pill="effort"]');
|
|
if (pill) {
|
|
ev.preventDefault();
|
|
var on = !pill.classList.contains("is-on");
|
|
pill.classList.toggle("is-on", on);
|
|
pill.setAttribute("aria-pressed", String(on));
|
|
pill.title = on
|
|
? "深虑 · 深度思考已开启,再次点击关闭"
|
|
: "深虑 · 已关闭:本条消息不思考,直出答复(推理型模型不可关)";
|
|
var seg = document.querySelector("[data-effort-seg]");
|
|
if (seg) seg.hidden = !on;
|
|
var val = "关";
|
|
if (on) {
|
|
var checked = document.querySelector('[data-effort-seg] button[aria-checked="true"]');
|
|
val = checked ? checked.getAttribute("data-effort") : "中";
|
|
}
|
|
setEffortHint(on, val);
|
|
return;
|
|
}
|
|
});
|
|
|
|
/* ---------- 博闻药丸(关→开) ---------- */
|
|
document.addEventListener("click", function (ev) {
|
|
var pill = ev.target.closest('[data-pill="search"]');
|
|
if (!pill) return;
|
|
ev.preventDefault();
|
|
var small = pill.querySelector("small");
|
|
if (!small) return;
|
|
var on = small.textContent.trim() === "开";
|
|
small.textContent = on ? "关" : "开";
|
|
pill.classList.toggle("is-on", !on);
|
|
pill.setAttribute("aria-pressed", String(!on));
|
|
});
|
|
|
|
/* ---------- 候答切换(静态演示) ---------- */
|
|
document.querySelectorAll("[data-cand-group]").forEach(function (group) {
|
|
group.querySelectorAll(".cand-tag").forEach(function (tag) {
|
|
tag.addEventListener("click", function () {
|
|
group.querySelectorAll(".cand-tag").forEach(function (tt) { tt.classList.remove("is-on"); });
|
|
tag.classList.add("is-on");
|
|
});
|
|
});
|
|
});
|
|
|
|
/* ---------- 界域分段控件:切换提示条文案 ---------- */
|
|
document.querySelectorAll("[data-realm]").forEach(function (seg) {
|
|
seg.querySelectorAll(".seg__item").forEach(function (item) {
|
|
item.addEventListener("click", function () {
|
|
seg.querySelectorAll(".seg__item").forEach(function (tt) { tt.classList.remove("is-on"); });
|
|
item.classList.add("is-on");
|
|
var banner = document.querySelector("[data-realm-banner]");
|
|
if (!banner) return;
|
|
var realm = item.getAttribute("data-realm");
|
|
if (realm === "sim") {
|
|
banner.className = "realm-banner realm-banner--sim";
|
|
} else {
|
|
banner.className = "realm-banner";
|
|
}
|
|
var html = item.getAttribute("data-banner-html");
|
|
if (html) banner.textContent = html;
|
|
});
|
|
});
|
|
});
|
|
})();
|