/* 魂镜原型 · 共享交互脚本 主题切换 · 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; }); }); }); })();