NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name 聊天助手大纲
// @namespace http://tampermonkey.net/
// @version 0.1.5
// @author xzhao
// @description 为多个AI聊天平台生成智能对话大纲,支持实时更新、层级结构、主题切换,提升聊天体验和内容导航效率
// @license MIT
// @match *://chatgpt.com/*
// @match *://chat.deepseek.com/*
// @match *://grok.com/*
// @match *://www.qianwen.com/*
// @match *://chat.qwen.ai/*
// @match *://www.doubao.com/*
// @match *://www.kimi.com/*
// @match *://yuanbao.tencent.com/*
// @grant GM.getValue
// @grant GM.setValue
// @grant GM_addStyle
// ==/UserScript==
(function () {
'use strict';
const d=new Set;const importCSS = async e=>{d.has(e)||(d.add(e),(t=>{typeof GM_addStyle=="function"?GM_addStyle(t):(document.head||document.documentElement).appendChild(document.createElement("style")).append(t);})(e));};
importCSS(" .modal-overlay.svelte-lmj43v{position:fixed;inset:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:10000}.modal-content.svelte-lmj43v{background:var(--outline-bg);border:1px solid var(--outline-border);border-radius:8px;width:400px;max-width:90vw;max-height:80vh;overflow-y:auto;box-shadow:0 4px 12px #0000004d}.modal-header.svelte-lmj43v{display:flex;justify-content:space-between;align-items:center;padding:15px;border-bottom:1px solid var(--outline-border)}.modal-header.svelte-lmj43v h3:where(.svelte-lmj43v){margin:0;color:var(--outline-text);font-size:18px}.close-btn.svelte-lmj43v{background:none;border:none;font-size:20px;cursor:pointer;color:var(--outline-text);padding:0;width:24px;height:24px}.close-btn.svelte-lmj43v:hover{opacity:.7}.modal-body.svelte-lmj43v{padding:15px;display:flex;flex-direction:column;gap:16px}.setting-section.svelte-lmj43v{display:flex;flex-direction:column;gap:10px}.section-title.svelte-lmj43v{margin:0;padding-bottom:6px;border-bottom:1px solid var(--outline-border);color:var(--outline-text);font-size:14px;font-weight:600;opacity:.8}label.svelte-lmj43v{display:flex;align-items:center;gap:10px;color:var(--outline-text);font-size:14px}input[type=checkbox].svelte-lmj43v{cursor:pointer}input[type=number].svelte-lmj43v{width:80px;padding:4px 8px;border:1px solid var(--outline-border);border-radius:4px;background:var(--outline-header-bg);color:var(--outline-text);font-size:14px}select.svelte-lmj43v{padding:4px 8px;border:1px solid var(--outline-border);border-radius:4px;background:var(--outline-header-bg);color:var(--outline-text);font-size:14px;cursor:pointer}.chat-outline-header.svelte-zptf9e{display:flex;flex-direction:column;gap:6px;padding:10px 15px;border-bottom:1px solid var(--outline-border);background:var(--outline-header-bg);border-radius:var(--outline-radius) var(--outline-radius) 0 0}.title-row.svelte-zptf9e{display:flex;justify-content:space-between;align-items:center}.chat-outline-title.svelte-zptf9e{margin:0;color:var(--outline-text);font-size:16px;font-weight:700}.title-controls.svelte-zptf9e{display:flex;gap:8px;align-items:center}.tab-container.svelte-zptf9e{display:flex;gap:2px;background:var(--outline-border);border-radius:4px;padding:2px}.tab-btn.svelte-zptf9e{flex:1;padding:5px 10px;border:none;background:transparent;color:var(--outline-text);font-size:12px;cursor:pointer;border-radius:3px;transition:all .2s;display:flex;align-items:center;justify-content:center;gap:4px}.tab-btn.active.svelte-zptf9e{background:var(--outline-bg);font-weight:500}.tab-btn.svelte-zptf9e:hover:not(.active){opacity:.8}.controls-row.svelte-zptf9e{display:flex;gap:8px;align-items:center;justify-content:space-between}.controls-left.svelte-zptf9e,.controls-right.svelte-zptf9e{display:flex;gap:8px;align-items:center}.filter-row.svelte-zptf9e{display:flex;gap:4px}.filter-input.svelte-zptf9e{flex:1;padding:4px 8px;border:1px solid var(--outline-border);border-radius:4px;background:var(--outline-bg);color:var(--outline-text);font-size:14px}.outline-btn.svelte-zptf9e{background:none;border:1px solid var(--outline-border);border-radius:4px;padding:4px 8px;cursor:pointer;font-size:12px;color:var(--outline-text);transition:all .2s ease}.outline-btn.svelte-zptf9e:hover{background:var(--outline-border);transform:scale(1.05)}.outline-btn.active.svelte-zptf9e,.regex-btn.active.svelte-zptf9e{background:var(--outline-border);font-weight:700}.tree-container.svelte-2xi3vq{display:flex;flex-direction:column;gap:4px}.tree-node.svelte-2xi3vq{display:flex;justify-content:space-between;align-items:center;padding:4px 8px;border-radius:3px;cursor:pointer;transition:background-color .2s}.tree-node.svelte-2xi3vq:hover{background-color:var(--outline-node-hover-bg)}.tree-node.has-bookmark.svelte-2xi3vq{border-left:2px solid var(--outline-bookmark-border, #ffc107)}.node-text.svelte-2xi3vq{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--outline-text)}.bookmark-indicator.svelte-2xi3vq{margin-right:4px;font-size:12px}.toggle-btn.svelte-2xi3vq{background:none;border:none;cursor:pointer;font-size:14px;color:var(--outline-text);padding:4px;border-radius:3px;transition:transform .2s,background-color .2s}.toggle-btn.svelte-2xi3vq:hover{background-color:var(--outline-border);transform:scale(1.1)}.header-level-1.svelte-2xi3vq{border-left:2px solid var(--header-h1)}.header-level-2.svelte-2xi3vq{border-left:2px solid var(--header-h2)}.header-level-3.svelte-2xi3vq{border-left:2px solid var(--header-h3)}.header-level-4.svelte-2xi3vq{border-left:2px solid var(--header-h4)}.header-level-5.svelte-2xi3vq{border-left:2px solid var(--header-h5)}.header-level-6.svelte-2xi3vq{border-left:2px solid var(--header-h6)}.outline-user-item.svelte-1iqb61w{margin:8px 15px;padding:8px;background:var(--outline-user-bg);border-left:3px solid var(--outline-user-border);border-radius:4px;cursor:pointer;transition:background-color .2s;color:var(--outline-text);font-size:14px;position:relative}.outline-user-item.svelte-1iqb61w:hover{background:var(--outline-user-hover-bg)}.has-bookmark.svelte-1iqb61w{border-left-color:var(--outline-bookmark-border, #ffc107)}.bookmark-indicator.svelte-1iqb61w{margin-right:4px;font-size:12px}.outline-ai-container.svelte-1iqb61w{margin:8px 15px;border-left:3px solid var(--outline-ai-border);border-radius:4px;background:var(--outline-ai-bg);transition:background-color .2s}.outline-ai-header.svelte-1iqb61w{padding:8px;cursor:pointer;font-weight:700;display:flex;justify-content:space-between;align-items:center;transition:background-color .2s;color:var(--outline-text)}.outline-ai-header.svelte-1iqb61w:hover{background:var(--outline-ai-hover-bg)}.outline-ai-header.has-bookmark.svelte-1iqb61w{border-left-color:var(--outline-bookmark-border, #ffc107)}.header-text.svelte-1iqb61w{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.outline-ai-content.svelte-1iqb61w{padding:0 8px 8px}.outline-ai-item.svelte-1iqb61w{margin:8px 15px;padding:8px;background:var(--outline-ai-bg);border-left:3px solid var(--outline-ai-border);border-radius:4px;cursor:pointer;transition:background-color .2s;color:var(--outline-text);font-size:14px}.outline-ai-item.svelte-1iqb61w:hover{background:var(--outline-ai-hover-bg)}.outline-ai-item.has-bookmark.svelte-1iqb61w{border-left-color:var(--outline-bookmark-border, #ffc107)}.toggle-btn.svelte-1iqb61w{background:none;border:none;cursor:pointer;font-size:14px;color:var(--outline-text);padding:4px;border-radius:3px;transition:transform .2s,background-color .2s;margin-left:8px}.toggle-btn.svelte-1iqb61w:hover{background-color:var(--outline-border);transform:scale(1.1)}.outline-active{background:var(--outline-active-bg)!important;outline:2px solid var(--outline-active-border);outline-offset:-1px}.outline-content.svelte-13g9af{overflow-y:auto;flex:1;padding-bottom:15px;position:relative;scroll-behavior:smooth}.draggable-toggle-button.svelte-nihy1m{position:fixed;right:2px;background:var(--outline-bg);border:1px solid var(--outline-border);border-radius:50%;width:40px;height:40px;cursor:pointer;font-size:16px;color:var(--outline-text);box-shadow:0 2px 8px var(--outline-shadow);transition:transform .3s ease,background-color .3s ease,box-shadow .3s ease;z-index:9999;display:flex;align-items:center;justify-content:center;user-select:none;-webkit-user-select:none;touch-action:none}.draggable-toggle-button.svelte-nihy1m:hover{background:var(--outline-border);box-shadow:0 4px 12px var(--outline-shadow)}.draggable-toggle-button.is-dragging.svelte-nihy1m{cursor:grabbing;box-shadow:0 6px 16px var(--outline-shadow);transition:none}.draggable-toggle-button.svelte-nihy1m:not(.is-dragging):hover{transform:translateY(-50%) scale(1.1)}.draggable-toggle-button.svelte-nihy1m:active{cursor:grabbing}.panel-notice-stack.svelte-1xjbolr{position:absolute;left:12px;right:12px;bottom:42px;z-index:2;display:flex;flex-direction:column;gap:8px;pointer-events:none}.panel-notice.svelte-1xjbolr{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:10px 12px;border-radius:10px;border:1px solid var(--outline-border);box-shadow:0 8px 20px var(--outline-shadow);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);pointer-events:auto}.notice-info.svelte-1xjbolr{background:color-mix(in srgb,#3b82f6 18%,var(--outline-bg))}.notice-success.svelte-1xjbolr{background:color-mix(in srgb,#22c55e 18%,var(--outline-bg))}.notice-warning.svelte-1xjbolr{background:color-mix(in srgb,#f59e0b 18%,var(--outline-bg))}.notice-error.svelte-1xjbolr{background:color-mix(in srgb,#ef4444 18%,var(--outline-bg))}.notice-text.svelte-1xjbolr{color:var(--outline-text);font-size:13px;line-height:1.4}.notice-close.svelte-1xjbolr{flex:none;width:24px;height:24px;border:none;border-radius:50%;background:transparent;color:var(--outline-text);cursor:pointer}.service-status-bar.svelte-5fnl0z{display:flex;align-items:center;justify-content:flex-end;gap:12px;padding:8px 12px 10px;border-top:1px solid var(--outline-border);background:color-mix(in srgb,var(--outline-header-bg) 70%,transparent)}.status-dot-button.svelte-5fnl0z{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;padding:0;border:none;background:transparent;cursor:pointer}.status-dot-button.svelte-5fnl0z:hover .status-light:where(.svelte-5fnl0z){transform:scale(1.12)}.status-light.svelte-5fnl0z{width:10px;height:10px;border-radius:50%;background:var(--status-color);box-shadow:0 0 0 3px color-mix(in srgb,var(--status-color) 20%,transparent);transition:transform .2s ease}.empty-state.svelte-1dp0ytt{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:30px 20px;color:var(--outline-text);opacity:.6}.empty-icon.svelte-1dp0ytt{font-size:32px;margin-bottom:12px}.empty-state.svelte-1dp0ytt p:where(.svelte-1dp0ytt){margin:2px 0;font-size:13px}.hint.svelte-1dp0ytt{font-size:11px!important;opacity:.7}.bookmark-list.svelte-1dp0ytt{display:flex;flex-direction:column;gap:2px;padding:4px 8px}.bookmark-item.svelte-1dp0ytt{display:flex;align-items:center;gap:6px;padding:6px 8px;background:var(--outline-bg);border-radius:4px;cursor:pointer;transition:background-color .15s;font-size:12px}.bookmark-item.svelte-1dp0ytt:hover{background:var(--outline-node-hover-bg)}.bookmark-item.svelte-1dp0ytt:focus{outline:1px solid var(--outline-primary, #007acc);outline-offset:-1px}.bookmark-icon.svelte-1dp0ytt{font-size:12px;flex-shrink:0;opacity:.8}.bookmark-name.svelte-1dp0ytt{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--outline-text)}.bookmark-meta.svelte-1dp0ytt{flex-shrink:0;font-size:10px;color:var(--outline-text);opacity:.5}.bookmark-panel.svelte-19r7ywj{display:flex;flex-direction:column;height:100%;overflow:hidden}.bookmark-toolbar.svelte-19r7ywj{display:flex;flex-direction:column;gap:6px;padding:8px 12px;border-bottom:1px solid var(--outline-border);background:var(--outline-header-bg)}.view-toggle.svelte-19r7ywj{display:flex;gap:2px;background:var(--outline-border);border-radius:4px;padding:2px}.toggle-btn.svelte-19r7ywj{flex:1;padding:5px 10px;border:none;background:transparent;color:var(--outline-text);font-size:12px;cursor:pointer;border-radius:3px;transition:all .2s}.toggle-btn.active.svelte-19r7ywj{background:var(--outline-bg);font-weight:500}.toggle-btn.svelte-19r7ywj:hover:not(.active){opacity:.8}.search-input.svelte-19r7ywj{width:100%;padding:6px 10px;border:1px solid var(--outline-border);border-radius:4px;background:var(--outline-bg);color:var(--outline-text);font-size:12px;box-sizing:border-box}.search-input.svelte-19r7ywj:focus{outline:none;border-color:var(--outline-primary, #007acc)}.search-input.svelte-19r7ywj::placeholder{color:var(--outline-text);opacity:.5}.bookmark-content.svelte-19r7ywj{flex:1;overflow-y:auto;overflow-x:hidden}.empty-state.svelte-19r7ywj{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:30px 20px;color:var(--outline-text);opacity:.6}.empty-icon.svelte-19r7ywj{font-size:32px;margin-bottom:12px}.empty-state.svelte-19r7ywj p:where(.svelte-19r7ywj){margin:2px 0;font-size:13px}.hint.svelte-19r7ywj{font-size:11px!important;opacity:.7}.conversation-group.svelte-19r7ywj{border-bottom:1px solid var(--outline-border)}.conversation-group.svelte-19r7ywj:last-child{border-bottom:none}.conversation-header.svelte-19r7ywj{display:flex;align-items:center;gap:6px;padding:6px 10px;background:var(--outline-header-bg);cursor:pointer;font-size:12px;color:var(--outline-text);transition:background-color .15s}.conversation-header.svelte-19r7ywj:hover{background:var(--outline-node-hover-bg)}.toggle-icon.svelte-19r7ywj{font-size:10px;opacity:.6}.conversation-name.svelte-19r7ywj{flex:1;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.conversation-count.svelte-19r7ywj{min-width:18px;height:18px;font-size:10px;opacity:.8;background:var(--outline-border);border-radius:50%;display:inline-flex;align-items:center;justify-content:center}.bookmark-footer.svelte-19r7ywj{padding:6px 12px;border-top:1px solid var(--outline-border);background:var(--outline-header-bg)}.bookmark-count.svelte-19r7ywj{font-size:11px;color:var(--outline-text);opacity:.6}.context-menu.svelte-aof35l{position:fixed;z-index:100000;min-width:150px;background:var(--outline-bg);border:1px solid var(--outline-border);border-radius:6px;box-shadow:0 4px 12px var(--outline-shadow);padding:4px 0;animation:svelte-aof35l-fadeIn .15s ease-out}@keyframes svelte-aof35l-fadeIn{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.menu-item.svelte-aof35l{display:flex;align-items:center;gap:8px;width:100%;padding:8px 12px;border:none;background:none;color:var(--outline-text);font-size:14px;cursor:pointer;text-align:left;transition:background-color .15s}.menu-item.svelte-aof35l:hover:not(.disabled){background:var(--outline-border)}.menu-item.disabled.svelte-aof35l{opacity:.5;cursor:not-allowed}.menu-item.danger.svelte-aof35l{color:#dc3545}.menu-icon.svelte-aof35l{width:16px;text-align:center}.menu-label.svelte-aof35l{flex:1}.modal-overlay.svelte-7qu2ih{position:fixed;inset:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:100000;animation:svelte-7qu2ih-fadeIn .15s ease-out}@keyframes svelte-7qu2ih-fadeIn{0%{opacity:0}to{opacity:1}}.modal-content.svelte-7qu2ih{background:var(--outline-bg);border:1px solid var(--outline-border);border-radius:8px;width:380px;max-width:90vw;box-shadow:0 4px 12px #0000004d;animation:svelte-7qu2ih-slideIn .15s ease-out}@keyframes svelte-7qu2ih-slideIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.modal-header.svelte-7qu2ih{display:flex;justify-content:space-between;align-items:center;padding:15px;border-bottom:1px solid var(--outline-border)}.modal-header.svelte-7qu2ih h3:where(.svelte-7qu2ih){margin:0;color:var(--outline-text);font-size:16px}.close-btn.svelte-7qu2ih{background:none;border:none;font-size:18px;cursor:pointer;color:var(--outline-text);padding:0;width:24px;height:24px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:background-color .15s}.close-btn.svelte-7qu2ih:hover{background:var(--outline-border)}.modal-body.svelte-7qu2ih{padding:20px}.form-group.svelte-7qu2ih{display:flex;flex-direction:column;gap:6px}.form-group.svelte-7qu2ih label:where(.svelte-7qu2ih){color:var(--outline-text);font-size:14px;font-weight:500}.form-group.svelte-7qu2ih input:where(.svelte-7qu2ih){padding:8px 12px;border:1px solid var(--outline-border);border-radius:4px;background:var(--outline-bg);color:var(--outline-text);font-size:14px;transition:border-color .15s}.form-group.svelte-7qu2ih input:where(.svelte-7qu2ih):focus{outline:none;border-color:var(--outline-primary, #007acc)}.hint.svelte-7qu2ih{font-size:12px;color:var(--outline-text);opacity:.7}.preview.svelte-7qu2ih{margin-top:15px;padding:10px;background:var(--outline-header-bg);border-radius:4px;display:flex;align-items:center;gap:8px}.preview-label.svelte-7qu2ih{font-size:12px;color:var(--outline-text);opacity:.7}.preview-name.svelte-7qu2ih{font-size:14px;color:var(--outline-text);font-weight:500;word-break:break-all}.warning-message.svelte-7qu2ih{padding:12px;background:#ffc10726;border:1px solid rgba(255,193,7,.3);border-radius:4px;color:var(--outline-text);font-size:14px}.modal-footer.svelte-7qu2ih{display:flex;justify-content:flex-end;gap:10px;padding:15px;border-top:1px solid var(--outline-border)}.btn.svelte-7qu2ih{padding:8px 16px;border-radius:4px;font-size:14px;cursor:pointer;transition:all .15s}.btn-secondary.svelte-7qu2ih{background:none;border:1px solid var(--outline-border);color:var(--outline-text)}.btn-secondary.svelte-7qu2ih:hover{background:var(--outline-border)}.btn-primary.svelte-7qu2ih{background:var(--outline-primary, #007acc);border:1px solid var(--outline-primary, #007acc);color:#fff}.btn-primary.svelte-7qu2ih:hover{opacity:.9}.btn-primary.svelte-7qu2ih:disabled{opacity:.6;cursor:not-allowed}.modal-overlay.svelte-9ypatm{position:fixed;inset:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:100000;animation:svelte-9ypatm-fadeIn .15s ease-out}@keyframes svelte-9ypatm-fadeIn{0%{opacity:0}to{opacity:1}}.modal-content.svelte-9ypatm{background:var(--outline-bg);border:1px solid var(--outline-border);border-radius:8px;width:340px;max-width:90vw;box-shadow:0 4px 12px #0000004d;animation:svelte-9ypatm-slideIn .15s ease-out}@keyframes svelte-9ypatm-slideIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.modal-header.svelte-9ypatm{display:flex;justify-content:space-between;align-items:center;padding:12px 15px;border-bottom:1px solid var(--outline-border)}.modal-header.svelte-9ypatm h3:where(.svelte-9ypatm){margin:0;color:var(--outline-text);font-size:14px}.close-btn.svelte-9ypatm{background:none;border:none;font-size:16px;cursor:pointer;color:var(--outline-text);padding:0;width:24px;height:24px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:background-color .15s}.close-btn.svelte-9ypatm:hover{background:var(--outline-border)}.modal-body.svelte-9ypatm{padding:15px}.form-group.svelte-9ypatm{display:flex;flex-direction:column;gap:6px}.form-group.svelte-9ypatm label:where(.svelte-9ypatm){color:var(--outline-text);font-size:13px;font-weight:500}.form-group.svelte-9ypatm input:where(.svelte-9ypatm){padding:8px 10px;border:1px solid var(--outline-border);border-radius:4px;background:var(--outline-bg);color:var(--outline-text);font-size:13px;transition:border-color .15s}.form-group.svelte-9ypatm input:where(.svelte-9ypatm):focus{outline:none;border-color:var(--outline-primary, #007acc)}.modal-footer.svelte-9ypatm{display:flex;justify-content:flex-end;gap:8px;padding:12px 15px;border-top:1px solid var(--outline-border)}.btn.svelte-9ypatm{padding:6px 14px;border-radius:4px;font-size:13px;cursor:pointer;transition:all .15s}.btn-secondary.svelte-9ypatm{background:none;border:1px solid var(--outline-border);color:var(--outline-text)}.btn-secondary.svelte-9ypatm:hover{background:var(--outline-border)}.btn-primary.svelte-9ypatm{background:var(--outline-primary, #007acc);border:1px solid var(--outline-primary, #007acc);color:#fff}.btn-primary.svelte-9ypatm:hover{opacity:.9}.btn-primary.svelte-9ypatm:disabled{opacity:.6;cursor:not-allowed}.chat-outline.svelte-n2r6vx{width:var(--outline-width);background:var(--outline-bg);border-radius:var(--outline-radius);padding:0;box-shadow:0 4px 12px var(--outline-shadow);font-size:var(--outline-font-size);transition:background-color .3s ease;height:100dvh;z-index:9999;display:flex;flex-direction:column;position:relative;overflow:hidden}.outline-fixed-right.svelte-n2r6vx{position:fixed;top:0;right:0;z-index:10000;height:100vh;border-radius:var(--outline-radius) 0 0 var(--outline-radius);border-right:none;box-shadow:-4px 0 12px var(--outline-shadow)} ");
const DEV = false;
var is_array = Array.isArray;
var index_of = Array.prototype.indexOf;
var includes = Array.prototype.includes;
var array_from = Array.from;
var define_property = Object.defineProperty;
var get_descriptor = Object.getOwnPropertyDescriptor;
var get_descriptors = Object.getOwnPropertyDescriptors;
var object_prototype = Object.prototype;
var array_prototype = Array.prototype;
var get_prototype_of = Object.getPrototypeOf;
var is_extensible = Object.isExtensible;
const noop = () => {
};
function run_all(arr) {
for (var i = 0; i < arr.length; i++) {
arr[i]();
}
}
function deferred() {
var resolve;
var reject;
var promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve, reject };
}
const DERIVED = 1 << 1;
const EFFECT = 1 << 2;
const RENDER_EFFECT = 1 << 3;
const MANAGED_EFFECT = 1 << 24;
const BLOCK_EFFECT = 1 << 4;
const BRANCH_EFFECT = 1 << 5;
const ROOT_EFFECT = 1 << 6;
const BOUNDARY_EFFECT = 1 << 7;
const CONNECTED = 1 << 9;
const CLEAN = 1 << 10;
const DIRTY = 1 << 11;
const MAYBE_DIRTY = 1 << 12;
const INERT = 1 << 13;
const DESTROYED = 1 << 14;
const REACTION_RAN = 1 << 15;
const EFFECT_TRANSPARENT = 1 << 16;
const EAGER_EFFECT = 1 << 17;
const HEAD_EFFECT = 1 << 18;
const EFFECT_PRESERVED = 1 << 19;
const USER_EFFECT = 1 << 20;
const EFFECT_OFFSCREEN = 1 << 25;
const WAS_MARKED = 1 << 16;
const REACTION_IS_UPDATING = 1 << 21;
const ASYNC = 1 << 22;
const ERROR_VALUE = 1 << 23;
const STATE_SYMBOL = Symbol("$state");
const LEGACY_PROPS = Symbol("legacy props");
const LOADING_ATTR_SYMBOL = Symbol("");
const STALE_REACTION = new class StaleReactionError extends Error {
name = "StaleReactionError";
message = "The reaction that called `getAbortSignal()` was re-run or destroyed";
}();
const IS_XHTML = (
!!globalThis.document?.contentType && globalThis.document.contentType.includes("xml")
);
function lifecycle_outside_component(name) {
{
throw new Error(`https://svelte.dev/e/lifecycle_outside_component`);
}
}
function async_derived_orphan() {
{
throw new Error(`https://svelte.dev/e/async_derived_orphan`);
}
}
function each_key_duplicate(a, b, value) {
{
throw new Error(`https://svelte.dev/e/each_key_duplicate`);
}
}
function effect_in_teardown(rune) {
{
throw new Error(`https://svelte.dev/e/effect_in_teardown`);
}
}
function effect_in_unowned_derived() {
{
throw new Error(`https://svelte.dev/e/effect_in_unowned_derived`);
}
}
function effect_orphan(rune) {
{
throw new Error(`https://svelte.dev/e/effect_orphan`);
}
}
function effect_update_depth_exceeded() {
{
throw new Error(`https://svelte.dev/e/effect_update_depth_exceeded`);
}
}
function props_invalid_value(key) {
{
throw new Error(`https://svelte.dev/e/props_invalid_value`);
}
}
function state_descriptors_fixed() {
{
throw new Error(`https://svelte.dev/e/state_descriptors_fixed`);
}
}
function state_prototype_fixed() {
{
throw new Error(`https://svelte.dev/e/state_prototype_fixed`);
}
}
function state_unsafe_mutation() {
{
throw new Error(`https://svelte.dev/e/state_unsafe_mutation`);
}
}
function svelte_boundary_reset_onerror() {
{
throw new Error(`https://svelte.dev/e/svelte_boundary_reset_onerror`);
}
}
const EACH_ITEM_REACTIVE = 1;
const EACH_INDEX_REACTIVE = 1 << 1;
const EACH_IS_CONTROLLED = 1 << 2;
const EACH_IS_ANIMATED = 1 << 3;
const EACH_ITEM_IMMUTABLE = 1 << 4;
const PROPS_IS_IMMUTABLE = 1;
const PROPS_IS_UPDATED = 1 << 2;
const PROPS_IS_BINDABLE = 1 << 3;
const PROPS_IS_LAZY_INITIAL = 1 << 4;
const TEMPLATE_FRAGMENT = 1;
const TEMPLATE_USE_IMPORT_NODE = 1 << 1;
const UNINITIALIZED = Symbol();
const NAMESPACE_HTML = "http://www.w3.org/1999/xhtml";
function select_multiple_invalid_value() {
{
console.warn(`https://svelte.dev/e/select_multiple_invalid_value`);
}
}
function svelte_boundary_reset_noop() {
{
console.warn(`https://svelte.dev/e/svelte_boundary_reset_noop`);
}
}
function equals(value) {
return value === this.v;
}
function safe_not_equal(a, b) {
return a != a ? b == b : a !== b || a !== null && typeof a === "object" || typeof a === "function";
}
function safe_equals(value) {
return !safe_not_equal(value, this.v);
}
let tracing_mode_flag = false;
let component_context = null;
function set_component_context(context) {
component_context = context;
}
function push(props, runes = false, fn) {
component_context = {
p: component_context,
i: false,
c: null,
e: null,
s: props,
x: null,
l: null
};
}
function pop(component) {
var context = (
component_context
);
var effects = context.e;
if (effects !== null) {
context.e = null;
for (var fn of effects) {
create_user_effect(fn);
}
}
context.i = true;
component_context = context.p;
return (
{}
);
}
function is_runes() {
return true;
}
let micro_tasks = [];
function run_micro_tasks() {
var tasks = micro_tasks;
micro_tasks = [];
run_all(tasks);
}
function queue_micro_task(fn) {
if (micro_tasks.length === 0 && !is_flushing_sync) {
var tasks = micro_tasks;
queueMicrotask(() => {
if (tasks === micro_tasks) run_micro_tasks();
});
}
micro_tasks.push(fn);
}
function flush_tasks() {
while (micro_tasks.length > 0) {
run_micro_tasks();
}
}
function handle_error(error) {
var effect2 = active_effect;
if (effect2 === null) {
active_reaction.f |= ERROR_VALUE;
return error;
}
if ((effect2.f & REACTION_RAN) === 0 && (effect2.f & EFFECT) === 0) {
throw error;
}
invoke_error_boundary(error, effect2);
}
function invoke_error_boundary(error, effect2) {
while (effect2 !== null) {
if ((effect2.f & BOUNDARY_EFFECT) !== 0) {
if ((effect2.f & REACTION_RAN) === 0) {
throw error;
}
try {
effect2.b.error(error);
return;
} catch (e) {
error = e;
}
}
effect2 = effect2.parent;
}
throw error;
}
const STATUS_MASK = -7169;
function set_signal_status(signal, status) {
signal.f = signal.f & STATUS_MASK | status;
}
function update_derived_status(derived2) {
if ((derived2.f & CONNECTED) !== 0 || derived2.deps === null) {
set_signal_status(derived2, CLEAN);
} else {
set_signal_status(derived2, MAYBE_DIRTY);
}
}
function clear_marked(deps) {
if (deps === null) return;
for (const dep of deps) {
if ((dep.f & DERIVED) === 0 || (dep.f & WAS_MARKED) === 0) {
continue;
}
dep.f ^= WAS_MARKED;
clear_marked(
dep.deps
);
}
}
function defer_effect(effect2, dirty_effects, maybe_dirty_effects) {
if ((effect2.f & DIRTY) !== 0) {
dirty_effects.add(effect2);
} else if ((effect2.f & MAYBE_DIRTY) !== 0) {
maybe_dirty_effects.add(effect2);
}
clear_marked(effect2.deps);
set_signal_status(effect2, CLEAN);
}
const batches = new Set();
let current_batch = null;
let previous_batch = null;
let batch_values = null;
let queued_root_effects = [];
let last_scheduled_effect = null;
let is_flushing_sync = false;
let collected_effects = null;
class Batch {
current = new Map();
previous = new Map();
#commit_callbacks = new Set();
#discard_callbacks = new Set();
#pending = 0;
#blocking_pending = 0;
#deferred = null;
#dirty_effects = new Set();
#maybe_dirty_effects = new Set();
#skipped_branches = new Map();
is_fork = false;
#decrement_queued = false;
#is_deferred() {
return this.is_fork || this.#blocking_pending > 0;
}
skip_effect(effect2) {
if (!this.#skipped_branches.has(effect2)) {
this.#skipped_branches.set(effect2, { d: [], m: [] });
}
}
unskip_effect(effect2) {
var tracked = this.#skipped_branches.get(effect2);
if (tracked) {
this.#skipped_branches.delete(effect2);
for (var e of tracked.d) {
set_signal_status(e, DIRTY);
schedule_effect(e);
}
for (e of tracked.m) {
set_signal_status(e, MAYBE_DIRTY);
schedule_effect(e);
}
}
}
process(root_effects) {
queued_root_effects = [];
this.apply();
var effects = collected_effects = [];
var render_effects = [];
for (const root2 of root_effects) {
this.#traverse_effect_tree(root2, effects, render_effects);
}
collected_effects = null;
if (this.#is_deferred()) {
this.#defer_effects(render_effects);
this.#defer_effects(effects);
for (const [e, t] of this.#skipped_branches) {
reset_branch(e, t);
}
} else {
previous_batch = this;
current_batch = null;
for (const fn of this.#commit_callbacks) fn(this);
this.#commit_callbacks.clear();
if (this.#pending === 0) {
this.#commit();
}
flush_queued_effects(render_effects);
flush_queued_effects(effects);
this.#dirty_effects.clear();
this.#maybe_dirty_effects.clear();
previous_batch = null;
this.#deferred?.resolve();
}
batch_values = null;
}
#traverse_effect_tree(root2, effects, render_effects) {
root2.f ^= CLEAN;
var effect2 = root2.first;
while (effect2 !== null) {
var flags2 = effect2.f;
var is_branch = (flags2 & (BRANCH_EFFECT | ROOT_EFFECT)) !== 0;
var is_skippable_branch = is_branch && (flags2 & CLEAN) !== 0;
var skip = is_skippable_branch || (flags2 & INERT) !== 0 || this.#skipped_branches.has(effect2);
if (!skip && effect2.fn !== null) {
if (is_branch) {
effect2.f ^= CLEAN;
} else if ((flags2 & EFFECT) !== 0) {
effects.push(effect2);
} else if (is_dirty(effect2)) {
if ((flags2 & BLOCK_EFFECT) !== 0) this.#maybe_dirty_effects.add(effect2);
update_effect(effect2);
}
var child2 = effect2.first;
if (child2 !== null) {
effect2 = child2;
continue;
}
}
while (effect2 !== null) {
var next = effect2.next;
if (next !== null) {
effect2 = next;
break;
}
effect2 = effect2.parent;
}
}
}
#defer_effects(effects) {
for (var i = 0; i < effects.length; i += 1) {
defer_effect(effects[i], this.#dirty_effects, this.#maybe_dirty_effects);
}
}
capture(source2, value) {
if (value !== UNINITIALIZED && !this.previous.has(source2)) {
this.previous.set(source2, value);
}
if ((source2.f & ERROR_VALUE) === 0) {
this.current.set(source2, source2.v);
batch_values?.set(source2, source2.v);
}
}
activate() {
current_batch = this;
this.apply();
}
deactivate() {
if (current_batch !== this) return;
current_batch = null;
batch_values = null;
}
flush() {
if (queued_root_effects.length > 0) {
current_batch = this;
flush_effects();
} else if (this.#pending === 0 && !this.is_fork) {
for (const fn of this.#commit_callbacks) fn(this);
this.#commit_callbacks.clear();
this.#commit();
this.#deferred?.resolve();
}
this.deactivate();
}
discard() {
for (const fn of this.#discard_callbacks) fn(this);
this.#discard_callbacks.clear();
}
#commit() {
if (batches.size > 1) {
this.previous.clear();
var previous_batch2 = current_batch;
var previous_batch_values = batch_values;
var is_earlier = true;
for (const batch of batches) {
if (batch === this) {
is_earlier = false;
continue;
}
const sources = [];
for (const [source2, value] of this.current) {
if (batch.current.has(source2)) {
if (is_earlier && value !== batch.current.get(source2)) {
batch.current.set(source2, value);
} else {
continue;
}
}
sources.push(source2);
}
if (sources.length === 0) {
continue;
}
const others = [...batch.current.keys()].filter((s) => !this.current.has(s));
if (others.length > 0) {
var prev_queued_root_effects = queued_root_effects;
queued_root_effects = [];
const marked = new Set();
const checked = new Map();
for (const source2 of sources) {
mark_effects(source2, others, marked, checked);
}
if (queued_root_effects.length > 0) {
current_batch = batch;
batch.apply();
for (const root2 of queued_root_effects) {
batch.#traverse_effect_tree(root2, [], []);
}
batch.deactivate();
}
queued_root_effects = prev_queued_root_effects;
}
}
current_batch = previous_batch2;
batch_values = previous_batch_values;
}
this.#skipped_branches.clear();
batches.delete(this);
}
increment(blocking) {
this.#pending += 1;
if (blocking) this.#blocking_pending += 1;
}
decrement(blocking) {
this.#pending -= 1;
if (blocking) this.#blocking_pending -= 1;
if (this.#decrement_queued) return;
this.#decrement_queued = true;
queue_micro_task(() => {
this.#decrement_queued = false;
if (!this.#is_deferred()) {
this.revive();
} else if (queued_root_effects.length > 0) {
this.flush();
}
});
}
revive() {
for (const e of this.#dirty_effects) {
this.#maybe_dirty_effects.delete(e);
set_signal_status(e, DIRTY);
schedule_effect(e);
}
for (const e of this.#maybe_dirty_effects) {
set_signal_status(e, MAYBE_DIRTY);
schedule_effect(e);
}
this.flush();
}
oncommit(fn) {
this.#commit_callbacks.add(fn);
}
ondiscard(fn) {
this.#discard_callbacks.add(fn);
}
settled() {
return (this.#deferred ??= deferred()).promise;
}
static ensure() {
if (current_batch === null) {
const batch = current_batch = new Batch();
batches.add(current_batch);
if (!is_flushing_sync) {
queue_micro_task(() => {
if (current_batch !== batch) {
return;
}
batch.flush();
});
}
}
return current_batch;
}
apply() {
return;
}
}
function flushSync(fn) {
var was_flushing_sync = is_flushing_sync;
is_flushing_sync = true;
try {
var result;
if (fn) ;
while (true) {
flush_tasks();
if (queued_root_effects.length === 0) {
current_batch?.flush();
if (queued_root_effects.length === 0) {
last_scheduled_effect = null;
return (
result
);
}
}
flush_effects();
}
} finally {
is_flushing_sync = was_flushing_sync;
}
}
function flush_effects() {
try {
var flush_count = 0;
while (queued_root_effects.length > 0) {
var batch = Batch.ensure();
if (flush_count++ > 1e3) {
var updates, entry;
if (DEV) ;
infinite_loop_guard();
}
batch.process(queued_root_effects);
old_values.clear();
if (DEV) ;
}
} finally {
queued_root_effects = [];
last_scheduled_effect = null;
collected_effects = null;
}
}
function infinite_loop_guard() {
try {
effect_update_depth_exceeded();
} catch (error) {
invoke_error_boundary(error, last_scheduled_effect);
}
}
let eager_block_effects = null;
function flush_queued_effects(effects) {
var length = effects.length;
if (length === 0) return;
var i = 0;
while (i < length) {
var effect2 = effects[i++];
if ((effect2.f & (DESTROYED | INERT)) === 0 && is_dirty(effect2)) {
eager_block_effects = new Set();
update_effect(effect2);
if (effect2.deps === null && effect2.first === null && effect2.nodes === null && effect2.teardown === null && effect2.ac === null) {
unlink_effect(effect2);
}
if (eager_block_effects?.size > 0) {
old_values.clear();
for (const e of eager_block_effects) {
if ((e.f & (DESTROYED | INERT)) !== 0) continue;
const ordered_effects = [e];
let ancestor = e.parent;
while (ancestor !== null) {
if (eager_block_effects.has(ancestor)) {
eager_block_effects.delete(ancestor);
ordered_effects.push(ancestor);
}
ancestor = ancestor.parent;
}
for (let j = ordered_effects.length - 1; j >= 0; j--) {
const e2 = ordered_effects[j];
if ((e2.f & (DESTROYED | INERT)) !== 0) continue;
update_effect(e2);
}
}
eager_block_effects.clear();
}
}
}
eager_block_effects = null;
}
function mark_effects(value, sources, marked, checked) {
if (marked.has(value)) return;
marked.add(value);
if (value.reactions !== null) {
for (const reaction of value.reactions) {
const flags2 = reaction.f;
if ((flags2 & DERIVED) !== 0) {
mark_effects(
reaction,
sources,
marked,
checked
);
} else if ((flags2 & (ASYNC | BLOCK_EFFECT)) !== 0 && (flags2 & DIRTY) === 0 && depends_on(reaction, sources, checked)) {
set_signal_status(reaction, DIRTY);
schedule_effect(
reaction
);
}
}
}
}
function depends_on(reaction, sources, checked) {
const depends = checked.get(reaction);
if (depends !== void 0) return depends;
if (reaction.deps !== null) {
for (const dep of reaction.deps) {
if (includes.call(sources, dep)) {
return true;
}
if ((dep.f & DERIVED) !== 0 && depends_on(
dep,
sources,
checked
)) {
checked.set(
dep,
true
);
return true;
}
}
}
checked.set(reaction, false);
return false;
}
function schedule_effect(signal) {
var effect2 = last_scheduled_effect = signal;
var boundary2 = effect2.b;
if (boundary2?.is_pending && (signal.f & (EFFECT | RENDER_EFFECT | MANAGED_EFFECT)) !== 0 && (signal.f & REACTION_RAN) === 0) {
boundary2.defer_effect(signal);
return;
}
while (effect2.parent !== null) {
effect2 = effect2.parent;
var flags2 = effect2.f;
if (collected_effects !== null && effect2 === active_effect) {
if ((signal.f & RENDER_EFFECT) === 0) {
return;
}
}
if ((flags2 & (ROOT_EFFECT | BRANCH_EFFECT)) !== 0) {
if ((flags2 & CLEAN) === 0) {
return;
}
effect2.f ^= CLEAN;
}
}
queued_root_effects.push(effect2);
}
function reset_branch(effect2, tracked) {
if ((effect2.f & BRANCH_EFFECT) !== 0 && (effect2.f & CLEAN) !== 0) {
return;
}
if ((effect2.f & DIRTY) !== 0) {
tracked.d.push(effect2);
} else if ((effect2.f & MAYBE_DIRTY) !== 0) {
tracked.m.push(effect2);
}
set_signal_status(effect2, CLEAN);
var e = effect2.first;
while (e !== null) {
reset_branch(e, tracked);
e = e.next;
}
}
function createSubscriber(start) {
let subscribers = 0;
let version = source(0);
let stop;
return () => {
if (effect_tracking()) {
get$1(version);
render_effect(() => {
if (subscribers === 0) {
stop = untrack(() => start(() => increment(version)));
}
subscribers += 1;
return () => {
queue_micro_task(() => {
subscribers -= 1;
if (subscribers === 0) {
stop?.();
stop = void 0;
increment(version);
}
});
};
});
}
};
}
var flags = EFFECT_TRANSPARENT | EFFECT_PRESERVED;
function boundary(node, props, children, transform_error) {
new Boundary(node, props, children, transform_error);
}
class Boundary {
parent;
is_pending = false;
transform_error;
#anchor;
#hydrate_open = null;
#props;
#children;
#effect;
#main_effect = null;
#pending_effect = null;
#failed_effect = null;
#offscreen_fragment = null;
#local_pending_count = 0;
#pending_count = 0;
#pending_count_update_queued = false;
#dirty_effects = new Set();
#maybe_dirty_effects = new Set();
#effect_pending = null;
#effect_pending_subscriber = createSubscriber(() => {
this.#effect_pending = source(this.#local_pending_count);
return () => {
this.#effect_pending = null;
};
});
constructor(node, props, children, transform_error) {
this.#anchor = node;
this.#props = props;
this.#children = (anchor) => {
var effect2 = (
active_effect
);
effect2.b = this;
effect2.f |= BOUNDARY_EFFECT;
children(anchor);
};
this.parent =
active_effect.b;
this.transform_error = transform_error ?? this.parent?.transform_error ?? ((e) => e);
this.#effect = block(() => {
{
this.#render();
}
}, flags);
}
#hydrate_resolved_content() {
try {
this.#main_effect = branch(() => this.#children(this.#anchor));
} catch (error) {
this.error(error);
}
}
#hydrate_failed_content(error) {
const failed = this.#props.failed;
if (!failed) return;
this.#failed_effect = branch(() => {
failed(
this.#anchor,
() => error,
() => () => {
}
);
});
}
#hydrate_pending_content() {
const pending = this.#props.pending;
if (!pending) return;
this.is_pending = true;
this.#pending_effect = branch(() => pending(this.#anchor));
queue_micro_task(() => {
var fragment = this.#offscreen_fragment = document.createDocumentFragment();
var anchor = create_text();
fragment.append(anchor);
this.#main_effect = this.#run(() => {
Batch.ensure();
return branch(() => this.#children(anchor));
});
if (this.#pending_count === 0) {
this.#anchor.before(fragment);
this.#offscreen_fragment = null;
pause_effect(
this.#pending_effect,
() => {
this.#pending_effect = null;
}
);
this.#resolve();
}
});
}
#render() {
try {
this.is_pending = this.has_pending_snippet();
this.#pending_count = 0;
this.#local_pending_count = 0;
this.#main_effect = branch(() => {
this.#children(this.#anchor);
});
if (this.#pending_count > 0) {
var fragment = this.#offscreen_fragment = document.createDocumentFragment();
move_effect(this.#main_effect, fragment);
const pending = (
this.#props.pending
);
this.#pending_effect = branch(() => pending(this.#anchor));
} else {
this.#resolve();
}
} catch (error) {
this.error(error);
}
}
#resolve() {
this.is_pending = false;
for (const e of this.#dirty_effects) {
set_signal_status(e, DIRTY);
schedule_effect(e);
}
for (const e of this.#maybe_dirty_effects) {
set_signal_status(e, MAYBE_DIRTY);
schedule_effect(e);
}
this.#dirty_effects.clear();
this.#maybe_dirty_effects.clear();
}
defer_effect(effect2) {
defer_effect(effect2, this.#dirty_effects, this.#maybe_dirty_effects);
}
is_rendered() {
return !this.is_pending && (!this.parent || this.parent.is_rendered());
}
has_pending_snippet() {
return !!this.#props.pending;
}
#run(fn) {
var previous_effect = active_effect;
var previous_reaction = active_reaction;
var previous_ctx = component_context;
set_active_effect(this.#effect);
set_active_reaction(this.#effect);
set_component_context(this.#effect.ctx);
try {
return fn();
} catch (e) {
handle_error(e);
return null;
} finally {
set_active_effect(previous_effect);
set_active_reaction(previous_reaction);
set_component_context(previous_ctx);
}
}
#update_pending_count(d) {
if (!this.has_pending_snippet()) {
if (this.parent) {
this.parent.#update_pending_count(d);
}
return;
}
this.#pending_count += d;
if (this.#pending_count === 0) {
this.#resolve();
if (this.#pending_effect) {
pause_effect(this.#pending_effect, () => {
this.#pending_effect = null;
});
}
if (this.#offscreen_fragment) {
this.#anchor.before(this.#offscreen_fragment);
this.#offscreen_fragment = null;
}
}
}
update_pending_count(d) {
this.#update_pending_count(d);
this.#local_pending_count += d;
if (!this.#effect_pending || this.#pending_count_update_queued) return;
this.#pending_count_update_queued = true;
queue_micro_task(() => {
this.#pending_count_update_queued = false;
if (this.#effect_pending) {
internal_set(this.#effect_pending, this.#local_pending_count);
}
});
}
get_effect_pending() {
this.#effect_pending_subscriber();
return get$1(
this.#effect_pending
);
}
error(error) {
var onerror = this.#props.onerror;
let failed = this.#props.failed;
if (!onerror && !failed) {
throw error;
}
if (this.#main_effect) {
destroy_effect(this.#main_effect);
this.#main_effect = null;
}
if (this.#pending_effect) {
destroy_effect(this.#pending_effect);
this.#pending_effect = null;
}
if (this.#failed_effect) {
destroy_effect(this.#failed_effect);
this.#failed_effect = null;
}
var did_reset = false;
var calling_on_error = false;
const reset = () => {
if (did_reset) {
svelte_boundary_reset_noop();
return;
}
did_reset = true;
if (calling_on_error) {
svelte_boundary_reset_onerror();
}
if (this.#failed_effect !== null) {
pause_effect(this.#failed_effect, () => {
this.#failed_effect = null;
});
}
this.#run(() => {
Batch.ensure();
this.#render();
});
};
const handle_error_result = (transformed_error) => {
try {
calling_on_error = true;
onerror?.(transformed_error, reset);
calling_on_error = false;
} catch (error2) {
invoke_error_boundary(error2, this.#effect && this.#effect.parent);
}
if (failed) {
this.#failed_effect = this.#run(() => {
Batch.ensure();
try {
return branch(() => {
var effect2 = (
active_effect
);
effect2.b = this;
effect2.f |= BOUNDARY_EFFECT;
failed(
this.#anchor,
() => transformed_error,
() => reset
);
});
} catch (error2) {
invoke_error_boundary(
error2,
this.#effect.parent
);
return null;
}
});
}
};
queue_micro_task(() => {
var result;
try {
result = this.transform_error(error);
} catch (e) {
invoke_error_boundary(e, this.#effect && this.#effect.parent);
return;
}
if (result !== null && typeof result === "object" && typeof
result.then === "function") {
result.then(
handle_error_result,
(e) => invoke_error_boundary(e, this.#effect && this.#effect.parent)
);
} else {
handle_error_result(result);
}
});
}
}
function flatten(blockers, sync, async, fn) {
const d = derived$1;
var pending = blockers.filter((b) => !b.settled);
if (async.length === 0 && pending.length === 0) {
fn(sync.map(d));
return;
}
var parent = (
active_effect
);
var restore = capture();
var blocker_promise = pending.length === 1 ? pending[0].promise : pending.length > 1 ? Promise.all(pending.map((b) => b.promise)) : null;
function finish(values) {
restore();
try {
fn(values);
} catch (error) {
if ((parent.f & DESTROYED) === 0) {
invoke_error_boundary(error, parent);
}
}
unset_context();
}
if (async.length === 0) {
blocker_promise.then(() => finish(sync.map(d)));
return;
}
function run() {
restore();
Promise.all(async.map((expression) => async_derived(expression))).then((result) => finish([...sync.map(d), ...result])).catch((error) => invoke_error_boundary(error, parent));
}
if (blocker_promise) {
blocker_promise.then(run);
} else {
run();
}
}
function capture() {
var previous_effect = active_effect;
var previous_reaction = active_reaction;
var previous_component_context = component_context;
var previous_batch2 = current_batch;
return function restore(activate_batch = true) {
set_active_effect(previous_effect);
set_active_reaction(previous_reaction);
set_component_context(previous_component_context);
if (activate_batch) previous_batch2?.activate();
};
}
function unset_context(deactivate_batch = true) {
set_active_effect(null);
set_active_reaction(null);
set_component_context(null);
if (deactivate_batch) current_batch?.deactivate();
}
function increment_pending() {
var boundary2 = (
active_effect.b
);
var batch = (
current_batch
);
var blocking = boundary2.is_rendered();
boundary2.update_pending_count(1);
batch.increment(blocking);
return () => {
boundary2.update_pending_count(-1);
batch.decrement(blocking);
};
}
function derived$1(fn) {
var flags2 = DERIVED | DIRTY;
var parent_derived = active_reaction !== null && (active_reaction.f & DERIVED) !== 0 ? (
active_reaction
) : null;
if (active_effect !== null) {
active_effect.f |= EFFECT_PRESERVED;
}
const signal = {
ctx: component_context,
deps: null,
effects: null,
equals,
f: flags2,
fn,
reactions: null,
rv: 0,
v: (
UNINITIALIZED
),
wv: 0,
parent: parent_derived ?? active_effect,
ac: null
};
return signal;
}
function async_derived(fn, label, location) {
let parent = (
active_effect
);
if (parent === null) {
async_derived_orphan();
}
var promise = (
void 0
);
var signal = source(
UNINITIALIZED
);
var should_suspend = !active_reaction;
var deferreds = new Map();
async_effect(() => {
var d = deferred();
promise = d.promise;
try {
Promise.resolve(fn()).then(d.resolve, d.reject).finally(unset_context);
} catch (error) {
d.reject(error);
unset_context();
}
var batch = (
current_batch
);
if (should_suspend) {
var decrement_pending = increment_pending();
deferreds.get(batch)?.reject(STALE_REACTION);
deferreds.delete(batch);
deferreds.set(batch, d);
}
const handler = (value, error = void 0) => {
batch.activate();
if (error) {
if (error !== STALE_REACTION) {
signal.f |= ERROR_VALUE;
internal_set(signal, error);
}
} else {
if ((signal.f & ERROR_VALUE) !== 0) {
signal.f ^= ERROR_VALUE;
}
internal_set(signal, value);
for (const [b, d2] of deferreds) {
deferreds.delete(b);
if (b === batch) break;
d2.reject(STALE_REACTION);
}
}
if (decrement_pending) {
decrement_pending();
}
};
d.promise.then(handler, (e) => handler(null, e || "unknown"));
});
teardown(() => {
for (const d of deferreds.values()) {
d.reject(STALE_REACTION);
}
});
return new Promise((fulfil) => {
function next(p) {
function go() {
if (p === promise) {
fulfil(signal);
} else {
next(promise);
}
}
p.then(go, go);
}
next(promise);
});
}
function user_derived(fn) {
const d = derived$1(fn);
push_reaction_value(d);
return d;
}
function derived_safe_equal(fn) {
const signal = derived$1(fn);
signal.equals = safe_equals;
return signal;
}
function destroy_derived_effects(derived2) {
var effects = derived2.effects;
if (effects !== null) {
derived2.effects = null;
for (var i = 0; i < effects.length; i += 1) {
destroy_effect(
effects[i]
);
}
}
}
function get_derived_parent_effect(derived2) {
var parent = derived2.parent;
while (parent !== null) {
if ((parent.f & DERIVED) === 0) {
return (parent.f & DESTROYED) === 0 ? (
parent
) : null;
}
parent = parent.parent;
}
return null;
}
function execute_derived(derived2) {
var value;
var prev_active_effect = active_effect;
set_active_effect(get_derived_parent_effect(derived2));
{
try {
derived2.f &= ~WAS_MARKED;
destroy_derived_effects(derived2);
value = update_reaction(derived2);
} finally {
set_active_effect(prev_active_effect);
}
}
return value;
}
function update_derived(derived2) {
var value = execute_derived(derived2);
if (!derived2.equals(value)) {
derived2.wv = increment_write_version();
if (!current_batch?.is_fork || derived2.deps === null) {
derived2.v = value;
if (derived2.deps === null) {
set_signal_status(derived2, CLEAN);
return;
}
}
}
if (is_destroying_effect) {
return;
}
if (batch_values !== null) {
if (effect_tracking() || current_batch?.is_fork) {
batch_values.set(derived2, value);
}
} else {
update_derived_status(derived2);
}
}
function freeze_derived_effects(derived2) {
if (derived2.effects === null) return;
for (const e of derived2.effects) {
if (e.teardown || e.ac) {
e.teardown?.();
e.ac?.abort(STALE_REACTION);
e.teardown = noop;
e.ac = null;
remove_reactions(e, 0);
destroy_effect_children(e);
}
}
}
function unfreeze_derived_effects(derived2) {
if (derived2.effects === null) return;
for (const e of derived2.effects) {
if (e.teardown) {
update_effect(e);
}
}
}
let eager_effects = new Set();
const old_values = new Map();
let eager_effects_deferred = false;
function source(v, stack) {
var signal = {
f: 0,
v,
reactions: null,
equals,
rv: 0,
wv: 0
};
return signal;
}
function state(v, stack) {
const s = source(v);
push_reaction_value(s);
return s;
}
function mutable_source(initial_value, immutable = false, trackable = true) {
const s = source(initial_value);
if (!immutable) {
s.equals = safe_equals;
}
return s;
}
function set(source2, value, should_proxy = false) {
if (active_reaction !== null &&
(!untracking || (active_reaction.f & EAGER_EFFECT) !== 0) && is_runes() && (active_reaction.f & (DERIVED | BLOCK_EFFECT | ASYNC | EAGER_EFFECT)) !== 0 && (current_sources === null || !includes.call(current_sources, source2))) {
state_unsafe_mutation();
}
let new_value = should_proxy ? proxy(value) : value;
return internal_set(source2, new_value);
}
function internal_set(source2, value) {
if (!source2.equals(value)) {
var old_value = source2.v;
if (is_destroying_effect) {
old_values.set(source2, value);
} else {
old_values.set(source2, old_value);
}
source2.v = value;
var batch = Batch.ensure();
batch.capture(source2, old_value);
if ((source2.f & DERIVED) !== 0) {
const derived2 = (
source2
);
if ((source2.f & DIRTY) !== 0) {
execute_derived(derived2);
}
update_derived_status(derived2);
}
source2.wv = increment_write_version();
mark_reactions(source2, DIRTY);
if (active_effect !== null && (active_effect.f & CLEAN) !== 0 && (active_effect.f & (BRANCH_EFFECT | ROOT_EFFECT)) === 0) {
if (untracked_writes === null) {
set_untracked_writes([source2]);
} else {
untracked_writes.push(source2);
}
}
if (!batch.is_fork && eager_effects.size > 0 && !eager_effects_deferred) {
flush_eager_effects();
}
}
return value;
}
function flush_eager_effects() {
eager_effects_deferred = false;
for (const effect2 of eager_effects) {
if ((effect2.f & CLEAN) !== 0) {
set_signal_status(effect2, MAYBE_DIRTY);
}
if (is_dirty(effect2)) {
update_effect(effect2);
}
}
eager_effects.clear();
}
function increment(source2) {
set(source2, source2.v + 1);
}
function mark_reactions(signal, status) {
var reactions = signal.reactions;
if (reactions === null) return;
var length = reactions.length;
for (var i = 0; i < length; i++) {
var reaction = reactions[i];
var flags2 = reaction.f;
var not_dirty = (flags2 & DIRTY) === 0;
if (not_dirty) {
set_signal_status(reaction, status);
}
if ((flags2 & DERIVED) !== 0) {
var derived2 = (
reaction
);
batch_values?.delete(derived2);
if ((flags2 & WAS_MARKED) === 0) {
if (flags2 & CONNECTED) {
reaction.f |= WAS_MARKED;
}
mark_reactions(derived2, MAYBE_DIRTY);
}
} else if (not_dirty) {
if ((flags2 & BLOCK_EFFECT) !== 0 && eager_block_effects !== null) {
eager_block_effects.add(
reaction
);
}
schedule_effect(
reaction
);
}
}
}
function proxy(value) {
if (typeof value !== "object" || value === null || STATE_SYMBOL in value) {
return value;
}
const prototype = get_prototype_of(value);
if (prototype !== object_prototype && prototype !== array_prototype) {
return value;
}
var sources = new Map();
var is_proxied_array = is_array(value);
var version = state(0);
var parent_version = update_version;
var with_parent = (fn) => {
if (update_version === parent_version) {
return fn();
}
var reaction = active_reaction;
var version2 = update_version;
set_active_reaction(null);
set_update_version(parent_version);
var result = fn();
set_active_reaction(reaction);
set_update_version(version2);
return result;
};
if (is_proxied_array) {
sources.set("length", state(
value.length
));
}
return new Proxy(
value,
{
defineProperty(_, prop2, descriptor) {
if (!("value" in descriptor) || descriptor.configurable === false || descriptor.enumerable === false || descriptor.writable === false) {
state_descriptors_fixed();
}
var s = sources.get(prop2);
if (s === void 0) {
with_parent(() => {
var s2 = state(descriptor.value);
sources.set(prop2, s2);
return s2;
});
} else {
set(s, descriptor.value, true);
}
return true;
},
deleteProperty(target, prop2) {
var s = sources.get(prop2);
if (s === void 0) {
if (prop2 in target) {
const s2 = with_parent(() => state(UNINITIALIZED));
sources.set(prop2, s2);
increment(version);
}
} else {
set(s, UNINITIALIZED);
increment(version);
}
return true;
},
get(target, prop2, receiver) {
if (prop2 === STATE_SYMBOL) {
return value;
}
var s = sources.get(prop2);
var exists = prop2 in target;
if (s === void 0 && (!exists || get_descriptor(target, prop2)?.writable)) {
s = with_parent(() => {
var p = proxy(exists ? target[prop2] : UNINITIALIZED);
var s2 = state(p);
return s2;
});
sources.set(prop2, s);
}
if (s !== void 0) {
var v = get$1(s);
return v === UNINITIALIZED ? void 0 : v;
}
return Reflect.get(target, prop2, receiver);
},
getOwnPropertyDescriptor(target, prop2) {
var descriptor = Reflect.getOwnPropertyDescriptor(target, prop2);
if (descriptor && "value" in descriptor) {
var s = sources.get(prop2);
if (s) descriptor.value = get$1(s);
} else if (descriptor === void 0) {
var source2 = sources.get(prop2);
var value2 = source2?.v;
if (source2 !== void 0 && value2 !== UNINITIALIZED) {
return {
enumerable: true,
configurable: true,
value: value2,
writable: true
};
}
}
return descriptor;
},
has(target, prop2) {
if (prop2 === STATE_SYMBOL) {
return true;
}
var s = sources.get(prop2);
var has = s !== void 0 && s.v !== UNINITIALIZED || Reflect.has(target, prop2);
if (s !== void 0 || active_effect !== null && (!has || get_descriptor(target, prop2)?.writable)) {
if (s === void 0) {
s = with_parent(() => {
var p = has ? proxy(target[prop2]) : UNINITIALIZED;
var s2 = state(p);
return s2;
});
sources.set(prop2, s);
}
var value2 = get$1(s);
if (value2 === UNINITIALIZED) {
return false;
}
}
return has;
},
set(target, prop2, value2, receiver) {
var s = sources.get(prop2);
var has = prop2 in target;
if (is_proxied_array && prop2 === "length") {
for (var i = value2; i <
s.v; i += 1) {
var other_s = sources.get(i + "");
if (other_s !== void 0) {
set(other_s, UNINITIALIZED);
} else if (i in target) {
other_s = with_parent(() => state(UNINITIALIZED));
sources.set(i + "", other_s);
}
}
}
if (s === void 0) {
if (!has || get_descriptor(target, prop2)?.writable) {
s = with_parent(() => state(void 0));
set(s, proxy(value2));
sources.set(prop2, s);
}
} else {
has = s.v !== UNINITIALIZED;
var p = with_parent(() => proxy(value2));
set(s, p);
}
var descriptor = Reflect.getOwnPropertyDescriptor(target, prop2);
if (descriptor?.set) {
descriptor.set.call(receiver, value2);
}
if (!has) {
if (is_proxied_array && typeof prop2 === "string") {
var ls = (
sources.get("length")
);
var n = Number(prop2);
if (Number.isInteger(n) && n >= ls.v) {
set(ls, n + 1);
}
}
increment(version);
}
return true;
},
ownKeys(target) {
get$1(version);
var own_keys = Reflect.ownKeys(target).filter((key2) => {
var source3 = sources.get(key2);
return source3 === void 0 || source3.v !== UNINITIALIZED;
});
for (var [key, source2] of sources) {
if (source2.v !== UNINITIALIZED && !(key in target)) {
own_keys.push(key);
}
}
return own_keys;
},
setPrototypeOf() {
state_prototype_fixed();
}
}
);
}
function get_proxied_value(value) {
try {
if (value !== null && typeof value === "object" && STATE_SYMBOL in value) {
return value[STATE_SYMBOL];
}
} catch {
}
return value;
}
function is(a, b) {
return Object.is(get_proxied_value(a), get_proxied_value(b));
}
var $window;
var is_firefox;
var first_child_getter;
var next_sibling_getter;
function init_operations() {
if ($window !== void 0) {
return;
}
$window = window;
is_firefox = /Firefox/.test(navigator.userAgent);
var element_prototype = Element.prototype;
var node_prototype = Node.prototype;
var text_prototype = Text.prototype;
first_child_getter = get_descriptor(node_prototype, "firstChild").get;
next_sibling_getter = get_descriptor(node_prototype, "nextSibling").get;
if (is_extensible(element_prototype)) {
element_prototype.__click = void 0;
element_prototype.__className = void 0;
element_prototype.__attributes = null;
element_prototype.__style = void 0;
element_prototype.__e = void 0;
}
if (is_extensible(text_prototype)) {
text_prototype.__t = void 0;
}
}
function create_text(value = "") {
return document.createTextNode(value);
}
function get_first_child(node) {
return (
first_child_getter.call(node)
);
}
function get_next_sibling(node) {
return (
next_sibling_getter.call(node)
);
}
function child(node, is_text) {
{
return get_first_child(node);
}
}
function first_child(node, is_text = false) {
{
var first = get_first_child(node);
if (first instanceof Comment && first.data === "") return get_next_sibling(first);
return first;
}
}
function sibling(node, count = 1, is_text = false) {
let next_sibling = node;
while (count--) {
next_sibling =
get_next_sibling(next_sibling);
}
{
return next_sibling;
}
}
function clear_text_content(node) {
node.textContent = "";
}
function create_element(tag, namespace, is2) {
let options = void 0;
return (
document.createElementNS(NAMESPACE_HTML, tag, options)
);
}
let listening_to_form_reset = false;
function add_form_reset_listener() {
if (!listening_to_form_reset) {
listening_to_form_reset = true;
document.addEventListener(
"reset",
(evt) => {
Promise.resolve().then(() => {
if (!evt.defaultPrevented) {
for (
const e of
evt.target.elements
) {
e.__on_r?.();
}
}
});
},
{ capture: true }
);
}
}
function without_reactive_context(fn) {
var previous_reaction = active_reaction;
var previous_effect = active_effect;
set_active_reaction(null);
set_active_effect(null);
try {
return fn();
} finally {
set_active_reaction(previous_reaction);
set_active_effect(previous_effect);
}
}
function listen_to_event_and_reset_event(element, event2, handler, on_reset = handler) {
element.addEventListener(event2, () => without_reactive_context(handler));
const prev = element.__on_r;
if (prev) {
element.__on_r = () => {
prev();
on_reset(true);
};
} else {
element.__on_r = () => on_reset(true);
}
add_form_reset_listener();
}
function validate_effect(rune) {
if (active_effect === null) {
if (active_reaction === null) {
effect_orphan();
}
effect_in_unowned_derived();
}
if (is_destroying_effect) {
effect_in_teardown();
}
}
function push_effect(effect2, parent_effect) {
var parent_last = parent_effect.last;
if (parent_last === null) {
parent_effect.last = parent_effect.first = effect2;
} else {
parent_last.next = effect2;
effect2.prev = parent_last;
parent_effect.last = effect2;
}
}
function create_effect(type, fn) {
var parent = active_effect;
if (parent !== null && (parent.f & INERT) !== 0) {
type |= INERT;
}
var effect2 = {
ctx: component_context,
deps: null,
nodes: null,
f: type | DIRTY | CONNECTED,
first: null,
fn,
last: null,
next: null,
parent,
b: parent && parent.b,
prev: null,
teardown: null,
wv: 0,
ac: null
};
var e = effect2;
if ((type & EFFECT) !== 0) {
if (collected_effects !== null) {
collected_effects.push(effect2);
} else {
schedule_effect(effect2);
}
} else if (fn !== null) {
try {
update_effect(effect2);
} catch (e2) {
destroy_effect(effect2);
throw e2;
}
if (e.deps === null && e.teardown === null && e.nodes === null && e.first === e.last &&
(e.f & EFFECT_PRESERVED) === 0) {
e = e.first;
if ((type & BLOCK_EFFECT) !== 0 && (type & EFFECT_TRANSPARENT) !== 0 && e !== null) {
e.f |= EFFECT_TRANSPARENT;
}
}
}
if (e !== null) {
e.parent = parent;
if (parent !== null) {
push_effect(e, parent);
}
if (active_reaction !== null && (active_reaction.f & DERIVED) !== 0 && (type & ROOT_EFFECT) === 0) {
var derived2 = (
active_reaction
);
(derived2.effects ??= []).push(e);
}
}
return effect2;
}
function effect_tracking() {
return active_reaction !== null && !untracking;
}
function teardown(fn) {
const effect2 = create_effect(RENDER_EFFECT, null);
set_signal_status(effect2, CLEAN);
effect2.teardown = fn;
return effect2;
}
function user_effect(fn) {
validate_effect();
var flags2 = (
active_effect.f
);
var defer = !active_reaction && (flags2 & BRANCH_EFFECT) !== 0 && (flags2 & REACTION_RAN) === 0;
if (defer) {
var context = (
component_context
);
(context.e ??= []).push(fn);
} else {
return create_user_effect(fn);
}
}
function create_user_effect(fn) {
return create_effect(EFFECT | USER_EFFECT, fn);
}
function component_root(fn) {
Batch.ensure();
const effect2 = create_effect(ROOT_EFFECT | EFFECT_PRESERVED, fn);
return (options = {}) => {
return new Promise((fulfil) => {
if (options.outro) {
pause_effect(effect2, () => {
destroy_effect(effect2);
fulfil(void 0);
});
} else {
destroy_effect(effect2);
fulfil(void 0);
}
});
};
}
function effect(fn) {
return create_effect(EFFECT, fn);
}
function async_effect(fn) {
return create_effect(ASYNC | EFFECT_PRESERVED, fn);
}
function render_effect(fn, flags2 = 0) {
return create_effect(RENDER_EFFECT | flags2, fn);
}
function template_effect(fn, sync = [], async = [], blockers = []) {
flatten(blockers, sync, async, (values) => {
create_effect(RENDER_EFFECT, () => fn(...values.map(get$1)));
});
}
function block(fn, flags2 = 0) {
var effect2 = create_effect(BLOCK_EFFECT | flags2, fn);
return effect2;
}
function branch(fn) {
return create_effect(BRANCH_EFFECT | EFFECT_PRESERVED, fn);
}
function execute_effect_teardown(effect2) {
var teardown2 = effect2.teardown;
if (teardown2 !== null) {
const previously_destroying_effect = is_destroying_effect;
const previous_reaction = active_reaction;
set_is_destroying_effect(true);
set_active_reaction(null);
try {
teardown2.call(null);
} finally {
set_is_destroying_effect(previously_destroying_effect);
set_active_reaction(previous_reaction);
}
}
}
function destroy_effect_children(signal, remove_dom = false) {
var effect2 = signal.first;
signal.first = signal.last = null;
while (effect2 !== null) {
const controller = effect2.ac;
if (controller !== null) {
without_reactive_context(() => {
controller.abort(STALE_REACTION);
});
}
var next = effect2.next;
if ((effect2.f & ROOT_EFFECT) !== 0) {
effect2.parent = null;
} else {
destroy_effect(effect2, remove_dom);
}
effect2 = next;
}
}
function destroy_block_effect_children(signal) {
var effect2 = signal.first;
while (effect2 !== null) {
var next = effect2.next;
if ((effect2.f & BRANCH_EFFECT) === 0) {
destroy_effect(effect2);
}
effect2 = next;
}
}
function destroy_effect(effect2, remove_dom = true) {
var removed = false;
if ((remove_dom || (effect2.f & HEAD_EFFECT) !== 0) && effect2.nodes !== null && effect2.nodes.end !== null) {
remove_effect_dom(
effect2.nodes.start,
effect2.nodes.end
);
removed = true;
}
destroy_effect_children(effect2, remove_dom && !removed);
remove_reactions(effect2, 0);
set_signal_status(effect2, DESTROYED);
var transitions = effect2.nodes && effect2.nodes.t;
if (transitions !== null) {
for (const transition of transitions) {
transition.stop();
}
}
execute_effect_teardown(effect2);
var parent = effect2.parent;
if (parent !== null && parent.first !== null) {
unlink_effect(effect2);
}
effect2.next = effect2.prev = effect2.teardown = effect2.ctx = effect2.deps = effect2.fn = effect2.nodes = effect2.ac = null;
}
function remove_effect_dom(node, end) {
while (node !== null) {
var next = node === end ? null : get_next_sibling(node);
node.remove();
node = next;
}
}
function unlink_effect(effect2) {
var parent = effect2.parent;
var prev = effect2.prev;
var next = effect2.next;
if (prev !== null) prev.next = next;
if (next !== null) next.prev = prev;
if (parent !== null) {
if (parent.first === effect2) parent.first = next;
if (parent.last === effect2) parent.last = prev;
}
}
function pause_effect(effect2, callback, destroy = true) {
var transitions = [];
pause_children(effect2, transitions, true);
var fn = () => {
if (destroy) destroy_effect(effect2);
if (callback) callback();
};
var remaining = transitions.length;
if (remaining > 0) {
var check = () => --remaining || fn();
for (var transition of transitions) {
transition.out(check);
}
} else {
fn();
}
}
function pause_children(effect2, transitions, local) {
if ((effect2.f & INERT) !== 0) return;
effect2.f ^= INERT;
var t = effect2.nodes && effect2.nodes.t;
if (t !== null) {
for (const transition of t) {
if (transition.is_global || local) {
transitions.push(transition);
}
}
}
var child2 = effect2.first;
while (child2 !== null) {
var sibling2 = child2.next;
var transparent = (child2.f & EFFECT_TRANSPARENT) !== 0 ||
(child2.f & BRANCH_EFFECT) !== 0 && (effect2.f & BLOCK_EFFECT) !== 0;
pause_children(child2, transitions, transparent ? local : false);
child2 = sibling2;
}
}
function resume_effect(effect2) {
resume_children(effect2, true);
}
function resume_children(effect2, local) {
if ((effect2.f & INERT) === 0) return;
effect2.f ^= INERT;
if ((effect2.f & CLEAN) === 0) {
set_signal_status(effect2, DIRTY);
schedule_effect(effect2);
}
var child2 = effect2.first;
while (child2 !== null) {
var sibling2 = child2.next;
var transparent = (child2.f & EFFECT_TRANSPARENT) !== 0 || (child2.f & BRANCH_EFFECT) !== 0;
resume_children(child2, transparent ? local : false);
child2 = sibling2;
}
var t = effect2.nodes && effect2.nodes.t;
if (t !== null) {
for (const transition of t) {
if (transition.is_global || local) {
transition.in();
}
}
}
}
function move_effect(effect2, fragment) {
if (!effect2.nodes) return;
var node = effect2.nodes.start;
var end = effect2.nodes.end;
while (node !== null) {
var next = node === end ? null : get_next_sibling(node);
fragment.append(node);
node = next;
}
}
let is_updating_effect = false;
let is_destroying_effect = false;
function set_is_destroying_effect(value) {
is_destroying_effect = value;
}
let active_reaction = null;
let untracking = false;
function set_active_reaction(reaction) {
active_reaction = reaction;
}
let active_effect = null;
function set_active_effect(effect2) {
active_effect = effect2;
}
let current_sources = null;
function push_reaction_value(value) {
if (active_reaction !== null && true) {
if (current_sources === null) {
current_sources = [value];
} else {
current_sources.push(value);
}
}
}
let new_deps = null;
let skipped_deps = 0;
let untracked_writes = null;
function set_untracked_writes(value) {
untracked_writes = value;
}
let write_version = 1;
let read_version = 0;
let update_version = read_version;
function set_update_version(value) {
update_version = value;
}
function increment_write_version() {
return ++write_version;
}
function is_dirty(reaction) {
var flags2 = reaction.f;
if ((flags2 & DIRTY) !== 0) {
return true;
}
if (flags2 & DERIVED) {
reaction.f &= ~WAS_MARKED;
}
if ((flags2 & MAYBE_DIRTY) !== 0) {
var dependencies = (
reaction.deps
);
var length = dependencies.length;
for (var i = 0; i < length; i++) {
var dependency = dependencies[i];
if (is_dirty(
dependency
)) {
update_derived(
dependency
);
}
if (dependency.wv > reaction.wv) {
return true;
}
}
if ((flags2 & CONNECTED) !== 0 &&
batch_values === null) {
set_signal_status(reaction, CLEAN);
}
}
return false;
}
function schedule_possible_effect_self_invalidation(signal, effect2, root2 = true) {
var reactions = signal.reactions;
if (reactions === null) return;
if (current_sources !== null && includes.call(current_sources, signal)) {
return;
}
for (var i = 0; i < reactions.length; i++) {
var reaction = reactions[i];
if ((reaction.f & DERIVED) !== 0) {
schedule_possible_effect_self_invalidation(
reaction,
effect2,
false
);
} else if (effect2 === reaction) {
if (root2) {
set_signal_status(reaction, DIRTY);
} else if ((reaction.f & CLEAN) !== 0) {
set_signal_status(reaction, MAYBE_DIRTY);
}
schedule_effect(
reaction
);
}
}
}
function update_reaction(reaction) {
var previous_deps = new_deps;
var previous_skipped_deps = skipped_deps;
var previous_untracked_writes = untracked_writes;
var previous_reaction = active_reaction;
var previous_sources = current_sources;
var previous_component_context = component_context;
var previous_untracking = untracking;
var previous_update_version = update_version;
var flags2 = reaction.f;
new_deps =
null;
skipped_deps = 0;
untracked_writes = null;
active_reaction = (flags2 & (BRANCH_EFFECT | ROOT_EFFECT)) === 0 ? reaction : null;
current_sources = null;
set_component_context(reaction.ctx);
untracking = false;
update_version = ++read_version;
if (reaction.ac !== null) {
without_reactive_context(() => {
reaction.ac.abort(STALE_REACTION);
});
reaction.ac = null;
}
try {
reaction.f |= REACTION_IS_UPDATING;
var fn = (
reaction.fn
);
var result = fn();
reaction.f |= REACTION_RAN;
var deps = reaction.deps;
var is_fork = current_batch?.is_fork;
if (new_deps !== null) {
var i;
if (!is_fork) {
remove_reactions(reaction, skipped_deps);
}
if (deps !== null && skipped_deps > 0) {
deps.length = skipped_deps + new_deps.length;
for (i = 0; i < new_deps.length; i++) {
deps[skipped_deps + i] = new_deps[i];
}
} else {
reaction.deps = deps = new_deps;
}
if (effect_tracking() && (reaction.f & CONNECTED) !== 0) {
for (i = skipped_deps; i < deps.length; i++) {
(deps[i].reactions ??= []).push(reaction);
}
}
} else if (!is_fork && deps !== null && skipped_deps < deps.length) {
remove_reactions(reaction, skipped_deps);
deps.length = skipped_deps;
}
if (is_runes() && untracked_writes !== null && !untracking && deps !== null && (reaction.f & (DERIVED | MAYBE_DIRTY | DIRTY)) === 0) {
for (i = 0; i <
untracked_writes.length; i++) {
schedule_possible_effect_self_invalidation(
untracked_writes[i],
reaction
);
}
}
if (previous_reaction !== null && previous_reaction !== reaction) {
read_version++;
if (previous_reaction.deps !== null) {
for (let i2 = 0; i2 < previous_skipped_deps; i2 += 1) {
previous_reaction.deps[i2].rv = read_version;
}
}
if (previous_deps !== null) {
for (const dep of previous_deps) {
dep.rv = read_version;
}
}
if (untracked_writes !== null) {
if (previous_untracked_writes === null) {
previous_untracked_writes = untracked_writes;
} else {
previous_untracked_writes.push(...
untracked_writes);
}
}
}
if ((reaction.f & ERROR_VALUE) !== 0) {
reaction.f ^= ERROR_VALUE;
}
return result;
} catch (error) {
return handle_error(error);
} finally {
reaction.f ^= REACTION_IS_UPDATING;
new_deps = previous_deps;
skipped_deps = previous_skipped_deps;
untracked_writes = previous_untracked_writes;
active_reaction = previous_reaction;
current_sources = previous_sources;
set_component_context(previous_component_context);
untracking = previous_untracking;
update_version = previous_update_version;
}
}
function remove_reaction(signal, dependency) {
let reactions = dependency.reactions;
if (reactions !== null) {
var index2 = index_of.call(reactions, signal);
if (index2 !== -1) {
var new_length = reactions.length - 1;
if (new_length === 0) {
reactions = dependency.reactions = null;
} else {
reactions[index2] = reactions[new_length];
reactions.pop();
}
}
}
if (reactions === null && (dependency.f & DERIVED) !== 0 &&
(new_deps === null || !includes.call(new_deps, dependency))) {
var derived2 = (
dependency
);
if ((derived2.f & CONNECTED) !== 0) {
derived2.f ^= CONNECTED;
derived2.f &= ~WAS_MARKED;
}
update_derived_status(derived2);
freeze_derived_effects(derived2);
remove_reactions(derived2, 0);
}
}
function remove_reactions(signal, start_index) {
var dependencies = signal.deps;
if (dependencies === null) return;
for (var i = start_index; i < dependencies.length; i++) {
remove_reaction(signal, dependencies[i]);
}
}
function update_effect(effect2) {
var flags2 = effect2.f;
if ((flags2 & DESTROYED) !== 0) {
return;
}
set_signal_status(effect2, CLEAN);
var previous_effect = active_effect;
var was_updating_effect = is_updating_effect;
active_effect = effect2;
is_updating_effect = true;
try {
if ((flags2 & (BLOCK_EFFECT | MANAGED_EFFECT)) !== 0) {
destroy_block_effect_children(effect2);
} else {
destroy_effect_children(effect2);
}
execute_effect_teardown(effect2);
var teardown2 = update_reaction(effect2);
effect2.teardown = typeof teardown2 === "function" ? teardown2 : null;
effect2.wv = write_version;
var dep;
if (DEV && tracing_mode_flag && (effect2.f & DIRTY) !== 0 && effect2.deps !== null) ;
} finally {
is_updating_effect = was_updating_effect;
active_effect = previous_effect;
}
}
async function tick() {
await Promise.resolve();
flushSync();
}
function get$1(signal) {
var flags2 = signal.f;
var is_derived = (flags2 & DERIVED) !== 0;
if (active_reaction !== null && !untracking) {
var destroyed = active_effect !== null && (active_effect.f & DESTROYED) !== 0;
if (!destroyed && (current_sources === null || !includes.call(current_sources, signal))) {
var deps = active_reaction.deps;
if ((active_reaction.f & REACTION_IS_UPDATING) !== 0) {
if (signal.rv < read_version) {
signal.rv = read_version;
if (new_deps === null && deps !== null && deps[skipped_deps] === signal) {
skipped_deps++;
} else if (new_deps === null) {
new_deps = [signal];
} else {
new_deps.push(signal);
}
}
} else {
(active_reaction.deps ??= []).push(signal);
var reactions = signal.reactions;
if (reactions === null) {
signal.reactions = [active_reaction];
} else if (!includes.call(reactions, active_reaction)) {
reactions.push(active_reaction);
}
}
}
}
if (is_destroying_effect && old_values.has(signal)) {
return old_values.get(signal);
}
if (is_derived) {
var derived2 = (
signal
);
if (is_destroying_effect) {
var value = derived2.v;
if ((derived2.f & CLEAN) === 0 && derived2.reactions !== null || depends_on_old_values(derived2)) {
value = execute_derived(derived2);
}
old_values.set(derived2, value);
return value;
}
var should_connect = (derived2.f & CONNECTED) === 0 && !untracking && active_reaction !== null && (is_updating_effect || (active_reaction.f & CONNECTED) !== 0);
var is_new = (derived2.f & REACTION_RAN) === 0;
if (is_dirty(derived2)) {
if (should_connect) {
derived2.f |= CONNECTED;
}
update_derived(derived2);
}
if (should_connect && !is_new) {
unfreeze_derived_effects(derived2);
reconnect(derived2);
}
}
if (batch_values?.has(signal)) {
return batch_values.get(signal);
}
if ((signal.f & ERROR_VALUE) !== 0) {
throw signal.v;
}
return signal.v;
}
function reconnect(derived2) {
derived2.f |= CONNECTED;
if (derived2.deps === null) return;
for (const dep of derived2.deps) {
(dep.reactions ??= []).push(derived2);
if ((dep.f & DERIVED) !== 0 && (dep.f & CONNECTED) === 0) {
unfreeze_derived_effects(
dep
);
reconnect(
dep
);
}
}
}
function depends_on_old_values(derived2) {
if (derived2.v === UNINITIALIZED) return true;
if (derived2.deps === null) return false;
for (const dep of derived2.deps) {
if (old_values.has(dep)) {
return true;
}
if ((dep.f & DERIVED) !== 0 && depends_on_old_values(
dep
)) {
return true;
}
}
return false;
}
function untrack(fn) {
var previous_untracking = untracking;
try {
untracking = true;
return fn();
} finally {
untracking = previous_untracking;
}
}
function deep_read_state(value) {
if (typeof value !== "object" || !value || value instanceof EventTarget) {
return;
}
if (STATE_SYMBOL in value) {
deep_read(value);
} else if (!Array.isArray(value)) {
for (let key in value) {
const prop2 = value[key];
if (typeof prop2 === "object" && prop2 && STATE_SYMBOL in prop2) {
deep_read(prop2);
}
}
}
}
function deep_read(value, visited = new Set()) {
if (typeof value === "object" && value !== null &&
!(value instanceof EventTarget) && !visited.has(value)) {
visited.add(value);
if (value instanceof Date) {
value.getTime();
}
for (let key in value) {
try {
deep_read(value[key], visited);
} catch (e) {
}
}
const proto = get_prototype_of(value);
if (proto !== Object.prototype && proto !== Array.prototype && proto !== Map.prototype && proto !== Set.prototype && proto !== Date.prototype) {
const descriptors = get_descriptors(proto);
for (let key in descriptors) {
const get2 = descriptors[key].get;
if (get2) {
try {
get2.call(value);
} catch (e) {
}
}
}
}
}
}
const PASSIVE_EVENTS = ["touchstart", "touchmove"];
function is_passive_event(name) {
return PASSIVE_EVENTS.includes(name);
}
const event_symbol = Symbol("events");
const all_registered_events = new Set();
const root_event_handles = new Set();
function create_event(event_name, dom, handler, options = {}) {
function target_handler(event2) {
if (!options.capture) {
handle_event_propagation.call(dom, event2);
}
if (!event2.cancelBubble) {
return without_reactive_context(() => {
return handler?.call(this, event2);
});
}
}
if (event_name.startsWith("pointer") || event_name.startsWith("touch") || event_name === "wheel") {
queue_micro_task(() => {
dom.addEventListener(event_name, target_handler, options);
});
} else {
dom.addEventListener(event_name, target_handler, options);
}
return target_handler;
}
function event(event_name, dom, handler, capture2, passive) {
var options = { capture: capture2, passive };
var target_handler = create_event(event_name, dom, handler, options);
if (dom === document.body ||
dom === window ||
dom === document ||
dom instanceof HTMLMediaElement) {
teardown(() => {
dom.removeEventListener(event_name, target_handler, options);
});
}
}
function delegated(event_name, element, handler) {
(element[event_symbol] ??= {})[event_name] = handler;
}
function delegate(events) {
for (var i = 0; i < events.length; i++) {
all_registered_events.add(events[i]);
}
for (var fn of root_event_handles) {
fn(events);
}
}
let last_propagated_event = null;
function handle_event_propagation(event2) {
var handler_element = this;
var owner_document = (
handler_element.ownerDocument
);
var event_name = event2.type;
var path = event2.composedPath?.() || [];
var current_target = (
path[0] || event2.target
);
last_propagated_event = event2;
var path_idx = 0;
var handled_at = last_propagated_event === event2 && event2[event_symbol];
if (handled_at) {
var at_idx = path.indexOf(handled_at);
if (at_idx !== -1 && (handler_element === document || handler_element ===
window)) {
event2[event_symbol] = handler_element;
return;
}
var handler_idx = path.indexOf(handler_element);
if (handler_idx === -1) {
return;
}
if (at_idx <= handler_idx) {
path_idx = at_idx;
}
}
current_target =
path[path_idx] || event2.target;
if (current_target === handler_element) return;
define_property(event2, "currentTarget", {
configurable: true,
get() {
return current_target || owner_document;
}
});
var previous_reaction = active_reaction;
var previous_effect = active_effect;
set_active_reaction(null);
set_active_effect(null);
try {
var throw_error;
var other_errors = [];
while (current_target !== null) {
var parent_element = current_target.assignedSlot || current_target.parentNode ||
current_target.host || null;
try {
var delegated2 = current_target[event_symbol]?.[event_name];
if (delegated2 != null && (!
current_target.disabled ||
event2.target === current_target)) {
delegated2.call(current_target, event2);
}
} catch (error) {
if (throw_error) {
other_errors.push(error);
} else {
throw_error = error;
}
}
if (event2.cancelBubble || parent_element === handler_element || parent_element === null) {
break;
}
current_target = parent_element;
}
if (throw_error) {
for (let error of other_errors) {
queueMicrotask(() => {
throw error;
});
}
throw throw_error;
}
} finally {
event2[event_symbol] = handler_element;
delete event2.currentTarget;
set_active_reaction(previous_reaction);
set_active_effect(previous_effect);
}
}
const policy = (
globalThis?.window?.trustedTypes && globalThis.window.trustedTypes.createPolicy("svelte-trusted-html", {
createHTML: (html) => {
return html;
}
})
);
function create_trusted_html(html) {
return (
policy?.createHTML(html) ?? html
);
}
function create_fragment_from_html(html) {
var elem = create_element("template");
elem.innerHTML = create_trusted_html(html.replaceAll("<!>", "<!---->"));
return elem.content;
}
function assign_nodes(start, end) {
var effect2 = (
active_effect
);
if (effect2.nodes === null) {
effect2.nodes = { start, end, a: null, t: null };
}
}
function from_html(content, flags2) {
var is_fragment = (flags2 & TEMPLATE_FRAGMENT) !== 0;
var use_import_node = (flags2 & TEMPLATE_USE_IMPORT_NODE) !== 0;
var node;
var has_start = !content.startsWith("<!>");
return () => {
if (node === void 0) {
node = create_fragment_from_html(has_start ? content : "<!>" + content);
if (!is_fragment) node =
get_first_child(node);
}
var clone = (
use_import_node || is_firefox ? document.importNode(node, true) : node.cloneNode(true)
);
if (is_fragment) {
var start = (
get_first_child(clone)
);
var end = (
clone.lastChild
);
assign_nodes(start, end);
} else {
assign_nodes(clone, clone);
}
return clone;
};
}
function text(value = "") {
{
var t = create_text(value + "");
assign_nodes(t, t);
return t;
}
}
function comment() {
var frag = document.createDocumentFragment();
var start = document.createComment("");
var anchor = create_text();
frag.append(start, anchor);
assign_nodes(start, anchor);
return frag;
}
function append(anchor, dom) {
if (anchor === null) {
return;
}
anchor.before(
dom
);
}
function set_text(text2, value) {
var str = value == null ? "" : typeof value === "object" ? `${value}` : value;
if (str !== (text2.__t ??= text2.nodeValue)) {
text2.__t = str;
text2.nodeValue = `${str}`;
}
}
function mount(component, options) {
return _mount(component, options);
}
const listeners = new Map();
function _mount(Component, { target, anchor, props = {}, events, context, intro = true, transformError }) {
init_operations();
var component = void 0;
var unmount2 = component_root(() => {
var anchor_node = anchor ?? target.appendChild(create_text());
boundary(
anchor_node,
{
pending: () => {
}
},
(anchor_node2) => {
push({});
var ctx = (
component_context
);
if (context) ctx.c = context;
if (events) {
props.$$events = events;
}
component = Component(anchor_node2, props) || {};
pop();
},
transformError
);
var registered_events = new Set();
var event_handle = (events2) => {
for (var i = 0; i < events2.length; i++) {
var event_name = events2[i];
if (registered_events.has(event_name)) continue;
registered_events.add(event_name);
var passive = is_passive_event(event_name);
for (const node of [target, document]) {
var counts = listeners.get(node);
if (counts === void 0) {
counts = new Map();
listeners.set(node, counts);
}
var count = counts.get(event_name);
if (count === void 0) {
node.addEventListener(event_name, handle_event_propagation, { passive });
counts.set(event_name, 1);
} else {
counts.set(event_name, count + 1);
}
}
}
};
event_handle(array_from(all_registered_events));
root_event_handles.add(event_handle);
return () => {
for (var event_name of registered_events) {
for (const node of [target, document]) {
var counts = (
listeners.get(node)
);
var count = (
counts.get(event_name)
);
if (--count == 0) {
node.removeEventListener(event_name, handle_event_propagation);
counts.delete(event_name);
if (counts.size === 0) {
listeners.delete(node);
}
} else {
counts.set(event_name, count);
}
}
}
root_event_handles.delete(event_handle);
if (anchor_node !== anchor) {
anchor_node.parentNode?.removeChild(anchor_node);
}
};
});
mounted_components.set(component, unmount2);
return component;
}
let mounted_components = new WeakMap();
function unmount(component, options) {
const fn = mounted_components.get(component);
if (fn) {
mounted_components.delete(component);
return fn(options);
}
return Promise.resolve();
}
class BranchManager {
anchor;
#batches = new Map();
#onscreen = new Map();
#offscreen = new Map();
#outroing = new Set();
#transition = true;
constructor(anchor, transition = true) {
this.anchor = anchor;
this.#transition = transition;
}
#commit = (batch) => {
if (!this.#batches.has(batch)) return;
var key = (
this.#batches.get(batch)
);
var onscreen = this.#onscreen.get(key);
if (onscreen) {
resume_effect(onscreen);
this.#outroing.delete(key);
} else {
var offscreen = this.#offscreen.get(key);
if (offscreen) {
this.#onscreen.set(key, offscreen.effect);
this.#offscreen.delete(key);
offscreen.fragment.lastChild.remove();
this.anchor.before(offscreen.fragment);
onscreen = offscreen.effect;
}
}
for (const [b, k] of this.#batches) {
this.#batches.delete(b);
if (b === batch) {
break;
}
const offscreen2 = this.#offscreen.get(k);
if (offscreen2) {
destroy_effect(offscreen2.effect);
this.#offscreen.delete(k);
}
}
for (const [k, effect2] of this.#onscreen) {
if (k === key || this.#outroing.has(k)) continue;
const on_destroy = () => {
const keys = Array.from(this.#batches.values());
if (keys.includes(k)) {
var fragment = document.createDocumentFragment();
move_effect(effect2, fragment);
fragment.append(create_text());
this.#offscreen.set(k, { effect: effect2, fragment });
} else {
destroy_effect(effect2);
}
this.#outroing.delete(k);
this.#onscreen.delete(k);
};
if (this.#transition || !onscreen) {
this.#outroing.add(k);
pause_effect(effect2, on_destroy, false);
} else {
on_destroy();
}
}
};
#discard = (batch) => {
this.#batches.delete(batch);
const keys = Array.from(this.#batches.values());
for (const [k, branch2] of this.#offscreen) {
if (!keys.includes(k)) {
destroy_effect(branch2.effect);
this.#offscreen.delete(k);
}
}
};
ensure(key, fn) {
var batch = (
current_batch
);
if (fn && !this.#onscreen.has(key) && !this.#offscreen.has(key)) {
{
this.#onscreen.set(
key,
branch(() => fn(this.anchor))
);
}
}
this.#batches.set(batch, key);
{
this.#commit(batch);
}
}
}
function if_block(node, fn, elseif = false) {
var branches = new BranchManager(node);
var flags2 = elseif ? EFFECT_TRANSPARENT : 0;
function update_branch(key, fn2) {
branches.ensure(key, fn2);
}
block(() => {
var has_branch = false;
fn((fn2, key = 0) => {
has_branch = true;
update_branch(key, fn2);
});
if (!has_branch) {
update_branch(false, null);
}
}, flags2);
}
function index(_, i) {
return i;
}
function pause_effects(state2, to_destroy, controlled_anchor) {
var transitions = [];
var length = to_destroy.length;
var group;
var remaining = to_destroy.length;
for (var i = 0; i < length; i++) {
let effect2 = to_destroy[i];
pause_effect(
effect2,
() => {
if (group) {
group.pending.delete(effect2);
group.done.add(effect2);
if (group.pending.size === 0) {
var groups = (
state2.outrogroups
);
destroy_effects(array_from(group.done));
groups.delete(group);
if (groups.size === 0) {
state2.outrogroups = null;
}
}
} else {
remaining -= 1;
}
},
false
);
}
if (remaining === 0) {
var fast_path = transitions.length === 0 && controlled_anchor !== null;
if (fast_path) {
var anchor = (
controlled_anchor
);
var parent_node = (
anchor.parentNode
);
clear_text_content(parent_node);
parent_node.append(anchor);
state2.items.clear();
}
destroy_effects(to_destroy, !fast_path);
} else {
group = {
pending: new Set(to_destroy),
done: new Set()
};
(state2.outrogroups ??= new Set()).add(group);
}
}
function destroy_effects(to_destroy, remove_dom = true) {
for (var i = 0; i < to_destroy.length; i++) {
destroy_effect(to_destroy[i], remove_dom);
}
}
var offscreen_anchor;
function each(node, flags2, get_collection, get_key, render_fn, fallback_fn = null) {
var anchor = node;
var items = new Map();
var is_controlled = (flags2 & EACH_IS_CONTROLLED) !== 0;
if (is_controlled) {
var parent_node = (
node
);
anchor = parent_node.appendChild(create_text());
}
var fallback = null;
var each_array = derived_safe_equal(() => {
var collection = get_collection();
return is_array(collection) ? collection : collection == null ? [] : array_from(collection);
});
var array;
var first_run = true;
function commit() {
state2.fallback = fallback;
reconcile(state2, array, anchor, flags2, get_key);
if (fallback !== null) {
if (array.length === 0) {
if ((fallback.f & EFFECT_OFFSCREEN) === 0) {
resume_effect(fallback);
} else {
fallback.f ^= EFFECT_OFFSCREEN;
move(fallback, null, anchor);
}
} else {
pause_effect(fallback, () => {
fallback = null;
});
}
}
}
var effect2 = block(() => {
array =
get$1(each_array);
var length = array.length;
var keys = new Set();
for (var index2 = 0; index2 < length; index2 += 1) {
var value = array[index2];
var key = get_key(value, index2);
var item = first_run ? null : items.get(key);
if (item) {
if (item.v) internal_set(item.v, value);
if (item.i) internal_set(item.i, index2);
} else {
item = create_item(
items,
first_run ? anchor : offscreen_anchor ??= create_text(),
value,
key,
index2,
render_fn,
flags2,
get_collection
);
if (!first_run) {
item.e.f |= EFFECT_OFFSCREEN;
}
items.set(key, item);
}
keys.add(key);
}
if (length === 0 && fallback_fn && !fallback) {
if (first_run) {
fallback = branch(() => fallback_fn(anchor));
} else {
fallback = branch(() => fallback_fn(offscreen_anchor ??= create_text()));
fallback.f |= EFFECT_OFFSCREEN;
}
}
if (length > keys.size) {
{
each_key_duplicate();
}
}
if (!first_run) {
{
commit();
}
}
get$1(each_array);
});
var state2 = { effect: effect2, items, outrogroups: null, fallback };
first_run = false;
}
function skip_to_branch(effect2) {
while (effect2 !== null && (effect2.f & BRANCH_EFFECT) === 0) {
effect2 = effect2.next;
}
return effect2;
}
function reconcile(state2, array, anchor, flags2, get_key) {
var is_animated = (flags2 & EACH_IS_ANIMATED) !== 0;
var length = array.length;
var items = state2.items;
var current = skip_to_branch(state2.effect.first);
var seen;
var prev = null;
var to_animate;
var matched = [];
var stashed = [];
var value;
var key;
var effect2;
var i;
if (is_animated) {
for (i = 0; i < length; i += 1) {
value = array[i];
key = get_key(value, i);
effect2 =
items.get(key).e;
if ((effect2.f & EFFECT_OFFSCREEN) === 0) {
effect2.nodes?.a?.measure();
(to_animate ??= new Set()).add(effect2);
}
}
}
for (i = 0; i < length; i += 1) {
value = array[i];
key = get_key(value, i);
effect2 =
items.get(key).e;
if (state2.outrogroups !== null) {
for (const group of state2.outrogroups) {
group.pending.delete(effect2);
group.done.delete(effect2);
}
}
if ((effect2.f & EFFECT_OFFSCREEN) !== 0) {
effect2.f ^= EFFECT_OFFSCREEN;
if (effect2 === current) {
move(effect2, null, anchor);
} else {
var next = prev ? prev.next : current;
if (effect2 === state2.effect.last) {
state2.effect.last = effect2.prev;
}
if (effect2.prev) effect2.prev.next = effect2.next;
if (effect2.next) effect2.next.prev = effect2.prev;
link(state2, prev, effect2);
link(state2, effect2, next);
move(effect2, next, anchor);
prev = effect2;
matched = [];
stashed = [];
current = skip_to_branch(prev.next);
continue;
}
}
if ((effect2.f & INERT) !== 0) {
resume_effect(effect2);
if (is_animated) {
effect2.nodes?.a?.unfix();
(to_animate ??= new Set()).delete(effect2);
}
}
if (effect2 !== current) {
if (seen !== void 0 && seen.has(effect2)) {
if (matched.length < stashed.length) {
var start = stashed[0];
var j;
prev = start.prev;
var a = matched[0];
var b = matched[matched.length - 1];
for (j = 0; j < matched.length; j += 1) {
move(matched[j], start, anchor);
}
for (j = 0; j < stashed.length; j += 1) {
seen.delete(stashed[j]);
}
link(state2, a.prev, b.next);
link(state2, prev, a);
link(state2, b, start);
current = start;
prev = b;
i -= 1;
matched = [];
stashed = [];
} else {
seen.delete(effect2);
move(effect2, current, anchor);
link(state2, effect2.prev, effect2.next);
link(state2, effect2, prev === null ? state2.effect.first : prev.next);
link(state2, prev, effect2);
prev = effect2;
}
continue;
}
matched = [];
stashed = [];
while (current !== null && current !== effect2) {
(seen ??= new Set()).add(current);
stashed.push(current);
current = skip_to_branch(current.next);
}
if (current === null) {
continue;
}
}
if ((effect2.f & EFFECT_OFFSCREEN) === 0) {
matched.push(effect2);
}
prev = effect2;
current = skip_to_branch(effect2.next);
}
if (state2.outrogroups !== null) {
for (const group of state2.outrogroups) {
if (group.pending.size === 0) {
destroy_effects(array_from(group.done));
state2.outrogroups?.delete(group);
}
}
if (state2.outrogroups.size === 0) {
state2.outrogroups = null;
}
}
if (current !== null || seen !== void 0) {
var to_destroy = [];
if (seen !== void 0) {
for (effect2 of seen) {
if ((effect2.f & INERT) === 0) {
to_destroy.push(effect2);
}
}
}
while (current !== null) {
if ((current.f & INERT) === 0 && current !== state2.fallback) {
to_destroy.push(current);
}
current = skip_to_branch(current.next);
}
var destroy_length = to_destroy.length;
if (destroy_length > 0) {
var controlled_anchor = (flags2 & EACH_IS_CONTROLLED) !== 0 && length === 0 ? anchor : null;
if (is_animated) {
for (i = 0; i < destroy_length; i += 1) {
to_destroy[i].nodes?.a?.measure();
}
for (i = 0; i < destroy_length; i += 1) {
to_destroy[i].nodes?.a?.fix();
}
}
pause_effects(state2, to_destroy, controlled_anchor);
}
}
if (is_animated) {
queue_micro_task(() => {
if (to_animate === void 0) return;
for (effect2 of to_animate) {
effect2.nodes?.a?.apply();
}
});
}
}
function create_item(items, anchor, value, key, index2, render_fn, flags2, get_collection) {
var v = (flags2 & EACH_ITEM_REACTIVE) !== 0 ? (flags2 & EACH_ITEM_IMMUTABLE) === 0 ? mutable_source(value, false, false) : source(value) : null;
var i = (flags2 & EACH_INDEX_REACTIVE) !== 0 ? source(index2) : null;
return {
v,
i,
e: branch(() => {
render_fn(anchor, v ?? value, i ?? index2, get_collection);
return () => {
items.delete(key);
};
})
};
}
function move(effect2, next, anchor) {
if (!effect2.nodes) return;
var node = effect2.nodes.start;
var end = effect2.nodes.end;
var dest = next && (next.f & EFFECT_OFFSCREEN) === 0 ? (
next.nodes.start
) : anchor;
while (node !== null) {
var next_node = (
get_next_sibling(node)
);
dest.before(node);
if (node === end) {
return;
}
node = next_node;
}
}
function link(state2, prev, next) {
if (prev === null) {
state2.effect.first = next;
} else {
prev.next = next;
}
if (next === null) {
state2.effect.last = prev;
} else {
next.prev = prev;
}
}
function action(dom, action2, get_value) {
effect(() => {
var payload = untrack(() => action2(dom, get_value?.()) || {});
if (get_value && payload?.update) {
var inited = false;
var prev = (
{}
);
render_effect(() => {
var value = get_value();
deep_read_state(value);
if (inited && safe_not_equal(prev, value)) {
prev = value;
payload.update(value);
}
});
inited = true;
}
if (payload?.destroy) {
return () => (
payload.destroy()
);
}
});
}
const whitespace = [..." \n\r\f \v\uFEFF"];
function to_class(value, hash, directives) {
var classname = value == null ? "" : "" + value;
if (hash) {
classname = classname ? classname + " " + hash : hash;
}
if (directives) {
for (var key of Object.keys(directives)) {
if (directives[key]) {
classname = classname ? classname + " " + key : key;
} else if (classname.length) {
var len = key.length;
var a = 0;
while ((a = classname.indexOf(key, a)) >= 0) {
var b = a + len;
if ((a === 0 || whitespace.includes(classname[a - 1])) && (b === classname.length || whitespace.includes(classname[b]))) {
classname = (a === 0 ? "" : classname.substring(0, a)) + classname.substring(b + 1);
} else {
a = b;
}
}
}
}
}
return classname === "" ? null : classname;
}
function to_style(value, styles) {
return value == null ? null : String(value);
}
function set_class(dom, is_html, value, hash, prev_classes, next_classes) {
var prev = dom.__className;
if (prev !== value || prev === void 0) {
var next_class_name = to_class(value, hash, next_classes);
{
if (next_class_name == null) {
dom.removeAttribute("class");
} else {
dom.className = next_class_name;
}
}
dom.__className = value;
} else if (next_classes && prev_classes !== next_classes) {
for (var key in next_classes) {
var is_present = !!next_classes[key];
if (prev_classes == null || is_present !== !!prev_classes[key]) {
dom.classList.toggle(key, is_present);
}
}
}
return next_classes;
}
function set_style(dom, value, prev_styles, next_styles) {
var prev = dom.__style;
if (prev !== value) {
var next_style_attr = to_style(value);
{
if (next_style_attr == null) {
dom.removeAttribute("style");
} else {
dom.style.cssText = next_style_attr;
}
}
dom.__style = value;
}
return next_styles;
}
function select_option(select, value, mounting = false) {
if (select.multiple) {
if (value == void 0) {
return;
}
if (!is_array(value)) {
return select_multiple_invalid_value();
}
for (var option of select.options) {
option.selected = value.includes(get_option_value(option));
}
return;
}
for (option of select.options) {
var option_value = get_option_value(option);
if (is(option_value, value)) {
option.selected = true;
return;
}
}
if (!mounting || value !== void 0) {
select.selectedIndex = -1;
}
}
function init_select(select) {
var observer = new MutationObserver(() => {
select_option(select, select.__value);
});
observer.observe(select, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ["value"]
});
teardown(() => {
observer.disconnect();
});
}
function get_option_value(option) {
if ("__value" in option) {
return option.__value;
} else {
return option.value;
}
}
const IS_CUSTOM_ELEMENT = Symbol("is custom element");
const IS_HTML = Symbol("is html");
const PROGRESS_TAG = IS_XHTML ? "progress" : "PROGRESS";
function set_value(element, value) {
var attributes = get_attributes(element);
if (attributes.value === (attributes.value =
value ?? void 0) ||
element.value === value && (value !== 0 || element.nodeName !== PROGRESS_TAG)) {
return;
}
element.value = value ?? "";
}
function set_checked(element, checked) {
var attributes = get_attributes(element);
if (attributes.checked === (attributes.checked =
checked ?? void 0)) {
return;
}
element.checked = checked;
}
function set_attribute(element, attribute, value, skip_warning) {
var attributes = get_attributes(element);
if (attributes[attribute] === (attributes[attribute] = value)) return;
if (attribute === "loading") {
element[LOADING_ATTR_SYMBOL] = value;
}
if (value == null) {
element.removeAttribute(attribute);
} else if (typeof value !== "string" && get_setters(element).includes(attribute)) {
element[attribute] = value;
} else {
element.setAttribute(attribute, value);
}
}
function get_attributes(element) {
return (
element.__attributes ??= {
[IS_CUSTOM_ELEMENT]: element.nodeName.includes("-"),
[IS_HTML]: element.namespaceURI === NAMESPACE_HTML
}
);
}
var setters_cache = new Map();
function get_setters(element) {
var cache_key = element.getAttribute("is") || element.nodeName;
var setters = setters_cache.get(cache_key);
if (setters) return setters;
setters_cache.set(cache_key, setters = []);
var descriptors;
var proto = element;
var element_proto = Element.prototype;
while (element_proto !== proto) {
descriptors = get_descriptors(proto);
for (var key in descriptors) {
if (descriptors[key].set) {
setters.push(key);
}
}
proto = get_prototype_of(proto);
}
return setters;
}
function bind_value(input, get2, set2 = get2) {
var batches2 = new WeakSet();
listen_to_event_and_reset_event(input, "input", async (is_reset) => {
var value = is_reset ? input.defaultValue : input.value;
value = is_numberlike_input(input) ? to_number(value) : value;
set2(value);
if (current_batch !== null) {
batches2.add(current_batch);
}
await tick();
if (value !== (value = get2())) {
var start = input.selectionStart;
var end = input.selectionEnd;
var length = input.value.length;
input.value = value ?? "";
if (end !== null) {
var new_length = input.value.length;
if (start === end && end === length && new_length > length) {
input.selectionStart = new_length;
input.selectionEnd = new_length;
} else {
input.selectionStart = start;
input.selectionEnd = Math.min(end, new_length);
}
}
}
});
if (
untrack(get2) == null && input.value
) {
set2(is_numberlike_input(input) ? to_number(input.value) : input.value);
if (current_batch !== null) {
batches2.add(current_batch);
}
}
render_effect(() => {
var value = get2();
if (input === document.activeElement) {
var batch = (
previous_batch ?? current_batch
);
if (batches2.has(batch)) {
return;
}
}
if (is_numberlike_input(input) && value === to_number(input.value)) {
return;
}
if (input.type === "date" && !value && !input.value) {
return;
}
if (value !== input.value) {
input.value = value ?? "";
}
});
}
function is_numberlike_input(input) {
var type = input.type;
return type === "number" || type === "range";
}
function to_number(value) {
return value === "" ? null : +value;
}
function is_bound_this(bound_value, element_or_component) {
return bound_value === element_or_component || bound_value?.[STATE_SYMBOL] === element_or_component;
}
function bind_this(element_or_component = {}, update, get_value, get_parts) {
effect(() => {
var old_parts;
var parts;
render_effect(() => {
old_parts = parts;
parts = [];
untrack(() => {
if (element_or_component !== get_value(...parts)) {
update(element_or_component, ...parts);
if (old_parts && is_bound_this(get_value(...old_parts), element_or_component)) {
update(null, ...old_parts);
}
}
});
});
return () => {
queue_micro_task(() => {
if (parts && is_bound_this(get_value(...parts), element_or_component)) {
update(null, ...parts);
}
});
};
});
return element_or_component;
}
function subscribe_to_store(store, run, invalidate) {
if (store == null) {
run(void 0);
if (invalidate) invalidate(void 0);
return noop;
}
const unsub = untrack(
() => store.subscribe(
run,
invalidate
)
);
return unsub.unsubscribe ? () => unsub.unsubscribe() : unsub;
}
const subscriber_queue = [];
function readable(value, start) {
return {
subscribe: writable(value, start).subscribe
};
}
function writable(value, start = noop) {
let stop = null;
const subscribers = new Set();
function set2(new_value) {
if (safe_not_equal(value, new_value)) {
value = new_value;
if (stop) {
const run_queue = !subscriber_queue.length;
for (const subscriber of subscribers) {
subscriber[1]();
subscriber_queue.push(subscriber, value);
}
if (run_queue) {
for (let i = 0; i < subscriber_queue.length; i += 2) {
subscriber_queue[i][0](subscriber_queue[i + 1]);
}
subscriber_queue.length = 0;
}
}
}
}
function update(fn) {
set2(fn(
value
));
}
function subscribe(run, invalidate = noop) {
const subscriber = [run, invalidate];
subscribers.add(subscriber);
if (subscribers.size === 1) {
stop = start(set2, update) || noop;
}
run(
value
);
return () => {
subscribers.delete(subscriber);
if (subscribers.size === 0 && stop) {
stop();
stop = null;
}
};
}
return { set: set2, update, subscribe };
}
function derived(stores, fn, initial_value) {
const single = !Array.isArray(stores);
const stores_array = single ? [stores] : stores;
if (!stores_array.every(Boolean)) {
throw new Error("derived() expects stores as input, got a falsy value");
}
const auto = fn.length < 2;
return readable(initial_value, (set2, update) => {
let started = false;
const values = [];
let pending = 0;
let cleanup = noop;
const sync = () => {
if (pending) {
return;
}
cleanup();
const result = fn(single ? values[0] : values, set2, update);
if (auto) {
set2(result);
} else {
cleanup = typeof result === "function" ? result : noop;
}
};
const unsubscribers = stores_array.map(
(store, i) => subscribe_to_store(
store,
(value) => {
values[i] = value;
pending &= ~(1 << i);
if (started) {
sync();
}
},
() => {
pending |= 1 << i;
}
)
);
started = true;
sync();
return function stop() {
run_all(unsubscribers);
cleanup();
started = false;
};
});
}
function get(store) {
let value;
subscribe_to_store(store, (_) => value = _)();
return value;
}
let is_store_binding = false;
let IS_UNMOUNTED = Symbol();
function store_get(store, store_name, stores) {
const entry = stores[store_name] ??= {
store: null,
source: mutable_source(void 0),
unsubscribe: noop
};
if (entry.store !== store && !(IS_UNMOUNTED in stores)) {
entry.unsubscribe();
entry.store = store ?? null;
if (store == null) {
entry.source.v = void 0;
entry.unsubscribe = noop;
} else {
var is_synchronous_callback = true;
entry.unsubscribe = subscribe_to_store(store, (v) => {
if (is_synchronous_callback) {
entry.source.v = v;
} else {
set(entry.source, v);
}
});
is_synchronous_callback = false;
}
}
if (store && IS_UNMOUNTED in stores) {
return get(store);
}
return get$1(entry.source);
}
function setup_stores() {
const stores = {};
function cleanup() {
teardown(() => {
for (var store_name in stores) {
const ref = stores[store_name];
ref.unsubscribe();
}
define_property(stores, IS_UNMOUNTED, {
enumerable: false,
value: true
});
});
}
return [stores, cleanup];
}
function capture_store_binding(fn) {
var previous_is_store_binding = is_store_binding;
try {
is_store_binding = false;
return [fn(), is_store_binding];
} finally {
is_store_binding = previous_is_store_binding;
}
}
function prop(props, key, flags2, fallback) {
var bindable = (flags2 & PROPS_IS_BINDABLE) !== 0;
var lazy = (flags2 & PROPS_IS_LAZY_INITIAL) !== 0;
var fallback_value = (
fallback
);
var fallback_dirty = true;
var get_fallback = () => {
if (fallback_dirty) {
fallback_dirty = false;
fallback_value = lazy ? untrack(
fallback
) : (
fallback
);
}
return fallback_value;
};
var setter;
if (bindable) {
var is_entry_props = STATE_SYMBOL in props || LEGACY_PROPS in props;
setter = get_descriptor(props, key)?.set ?? (is_entry_props && key in props ? (v) => props[key] = v : void 0);
}
var initial_value;
var is_store_sub = false;
if (bindable) {
[initial_value, is_store_sub] = capture_store_binding(() => (
props[key]
));
} else {
initial_value =
props[key];
}
if (initial_value === void 0 && fallback !== void 0) {
initial_value = get_fallback();
if (setter) {
props_invalid_value();
setter(initial_value);
}
}
var getter;
{
getter = () => {
var value = (
props[key]
);
if (value === void 0) return get_fallback();
fallback_dirty = true;
return value;
};
}
if ((flags2 & PROPS_IS_UPDATED) === 0) {
return getter;
}
if (setter) {
var legacy_parent = props.$$legacy;
return (
(function(value, mutation) {
if (arguments.length > 0) {
if (!mutation || legacy_parent || is_store_sub) {
setter(mutation ? getter() : value);
}
return value;
}
return getter();
})
);
}
var overridden = false;
var d = ((flags2 & PROPS_IS_IMMUTABLE) !== 0 ? derived$1 : derived_safe_equal)(() => {
overridden = false;
return getter();
});
if (bindable) get$1(d);
var parent_effect = (
active_effect
);
return (
(function(value, mutation) {
if (arguments.length > 0) {
const new_value = mutation ? get$1(d) : bindable ? proxy(value) : value;
set(d, new_value);
overridden = true;
if (fallback_value !== void 0) {
fallback_value = new_value;
}
return value;
}
if (is_destroying_effect && overridden || (parent_effect.f & DESTROYED) !== 0) {
return d.v;
}
return get$1(d);
})
);
}
function onMount(fn) {
if (component_context === null) {
lifecycle_outside_component();
}
{
user_effect(() => {
const cleanup = untrack(fn);
if (typeof cleanup === "function") return (
cleanup
);
});
}
}
function onDestroy(fn) {
if (component_context === null) {
lifecycle_outside_component();
}
onMount(() => () => untrack(fn));
}
const appCss = ":root{--outline-bg: #ffffff;--outline-text: #333333;--outline-border: #dddddd;--outline-shadow: rgba(0, 0, 0, .15);--outline-header-bg: #ffffff;--outline-user-bg: #f0f8ff;--outline-user-hover-bg: #e6f3ff;--outline-user-border: #007acc;--outline-ai-bg: #f8f8f8;--outline-ai-hover-bg: #f0f0f0;--outline-ai-border: #28a745;--outline-node-hover-bg: #e9ecef;--header-h1: #dc3545;--header-h2: #fd7e14;--header-h3: #ffc107;--header-h4: #28a745;--header-h5: #17a2b8;--header-h6: #6f42c1;--outline-width: 300px;--outline-radius: 8px;--outline-padding: 15px;--outline-font-size: 14px;--outline-highlight-color: rgba(131, 218, 255, .16);--outline-active-bg: rgba(0, 122, 204, .15);--outline-active-border: #007acc;--outline-primary: #007acc;--outline-bookmark-border: #ffc107;--outline-bookmark-bg: rgba(255, 193, 7, .1)}[cbe-data-theme=dark]{--outline-bg: #2d2d2d;--outline-text: #e0e0e0;--outline-border: #555555;--outline-shadow: rgba(0, 0, 0, .3);--outline-header-bg: #2d2d2d;--outline-user-bg: #3a3a3a;--outline-user-hover-bg: #4a4a4a;--outline-user-border: #64b5f6;--outline-ai-bg: #3a3a3a;--outline-ai-hover-bg: #4a4a4a;--outline-ai-border: #4caf50;--outline-node-hover-bg: #4a4a4a;--header-h1: #f48fb1;--header-h2: #ffab91;--header-h3: #fff176;--header-h4: #81c784;--header-h5: #4dd0e1;--header-h6: #b39ddb;--outline-active-bg: rgba(100, 181, 246, .2);--outline-active-border: #64b5f6;--outline-primary: #64b5f6;--outline-bookmark-border: #ffc107;--outline-bookmark-bg: rgba(255, 193, 7, .15)}.highlight-animation{animation:highlight 1s ease-in-out}@keyframes highlight{0%{background-color:transparent}50%{background-color:var(--outline-highlight-color)}to{background-color:transparent}}.tree-node,.outline-user-item,.outline-ai-item,.outline-ai-header{will-change:transform;backface-visibility:hidden}";
importCSS(appCss);
const PUBLIC_VERSION = "5";
if (typeof window !== "undefined") {
((window.__svelte ??= {}).v ??= new Set()).add(PUBLIC_VERSION);
}
const defaultThemeConfig = {
highlightColor: "#83daff2a",
highlightTime: 2e3,
currentTheme: "light",
colors: {
light: {
primary: "#28a745",
user: "#007acc",
background: "#ffffff",
border: "#ddd",
shadow: "rgba(0,0,0,0.15)",
text: "#333",
headerBg: "#ffffff",
headers: {
h1: "#dc3545",
h2: "#fd7e14",
h3: "#ffc107",
h4: "#28a745",
h5: "#17a2b8",
h6: "#6f42c1"
}
},
dark: {
primary: "#4caf50",
user: "#64b5f6",
background: "#2d2d2d",
border: "#555",
shadow: "rgba(0,0,0,0.3)",
text: "#e0e0e0",
headerBg: "#2d2d2d",
headers: {
h1: "#f48fb1",
h2: "#ffab91",
h3: "#fff176",
h4: "#81c784",
h5: "#4dd0e1",
h6: "#b39ddb"
}
}
},
sizes: {
outlineWidth: "300px",
borderRadius: "8px",
padding: "15px",
fontSize: "14px",
indentSize: 15
}
};
function loadThemeFromStorage() {
const saved = localStorage.getItem("chat-outline-theme");
if (saved === "light" || saved === "dark") {
return saved;
}
return "light";
}
const themeStore = writable({
...defaultThemeConfig,
currentTheme: loadThemeFromStorage()
});
derived(themeStore, ($theme) => {
return $theme.colors[$theme.currentTheme];
});
function toggleTheme() {
themeStore.update((theme) => {
const newTheme = theme.currentTheme === "light" ? "dark" : "light";
localStorage.setItem("chat-outline-theme", newTheme);
return { ...theme, currentTheme: newTheme };
});
}
function getCurrentColors() {
const theme = get(themeStore);
return theme.colors[theme.currentTheme];
}
const LOG_LEVELS = {
debug: 0,
info: 1,
warn: 2,
error: 3
};
let currentLevel = "info";
function setLogLevel(level) {
currentLevel = level;
}
function shouldLog(level) {
return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];
}
function formatTaggedArgs(tag, args) {
return [`[${tag}]`, ...args];
}
const logger$1 = {
debug: (...args) => {
if (shouldLog("debug")) console.log("[DEBUG]", ...args);
},
info: (...args) => {
if (shouldLog("info")) console.log("[INFO]", ...args);
},
warn: (...args) => {
if (shouldLog("warn")) console.warn("[WARN]", ...args);
},
error: (...args) => {
if (shouldLog("error")) console.error("[ERROR]", ...args);
}
};
function createTaggedLogger(tag) {
return {
debug: (...args) => {
logger$1.debug(...formatTaggedArgs(tag, args));
},
info: (...args) => {
logger$1.info(...formatTaggedArgs(tag, args));
},
warn: (...args) => {
logger$1.warn(...formatTaggedArgs(tag, args));
},
error: (...args) => {
logger$1.error(...formatTaggedArgs(tag, args));
}
};
}
const defaultFeatures = {
autoExpand: true,
showUserMessages: true,
showAIMessages: true,
isVisible: true,
textLength: 50,
debouncedInterval: 500,
syncScroll: true,
logLevel: "info",
bookmarkGetTextLength: 20
};
const STORAGE_KEY$1 = "chat-outline-features";
const gmLogger$1 = createTaggedLogger("GM");
function loadFeaturesFromLocalStorage() {
try {
const saved = window.localStorage.getItem(STORAGE_KEY$1);
gmLogger$1.debug("loadFeaturesFromLocalStorage result", {
hasSavedFeatures: Boolean(saved),
storageKey: STORAGE_KEY$1
});
if (!saved) {
return defaultFeatures;
}
return { ...defaultFeatures, ...JSON.parse(saved) };
} catch (error) {
gmLogger$1.warn("Failed to load features from localStorage, fallback to default", error);
return defaultFeatures;
}
}
function saveFeaturesToLocalStorage(features) {
try {
window.localStorage.setItem(STORAGE_KEY$1, JSON.stringify(features));
gmLogger$1.debug("Features persisted to localStorage", {
storageKey: STORAGE_KEY$1,
logLevel: features.logLevel,
syncScroll: features.syncScroll
});
} catch (error) {
gmLogger$1.warn("Failed to persist features to localStorage", error);
}
}
function getSafeGMGetValue() {
if (typeof GM !== "undefined" && typeof GM.getValue === "function") {
gmLogger$1.debug("GM.getValue is available");
return GM.getValue.bind(GM);
}
gmLogger$1.warn("GM.getValue is unavailable, fallback to default features", {
href: window.location.href,
readyState: document.readyState,
topWindow: window.top === window
});
return null;
}
function getSafeGMSetValue() {
if (typeof GM !== "undefined" && typeof GM.setValue === "function") {
gmLogger$1.debug("GM.setValue is available");
return GM.setValue.bind(GM);
}
gmLogger$1.warn("GM.setValue is unavailable, skip persisting features", {
href: window.location.href,
readyState: document.readyState,
topWindow: window.top === window
});
return null;
}
function loadFeaturesFromStorage() {
const safeGetValue = getSafeGMGetValue();
if (!safeGetValue) {
gmLogger$1.debug("Fallback to localStorage for loading features");
return loadFeaturesFromLocalStorage();
}
try {
const saved = safeGetValue(STORAGE_KEY$1, null);
gmLogger$1.debug("loadFeaturesFromStorage result", {
hasSavedFeatures: Boolean(saved),
storageKey: STORAGE_KEY$1
});
if (!saved) {
return defaultFeatures;
}
return { ...defaultFeatures, ...saved };
} catch (error) {
gmLogger$1.warn("Failed to load features from GM storage, fallback to default", error);
gmLogger$1.debug("Fallback to localStorage after GM storage read failure");
return loadFeaturesFromLocalStorage();
}
}
function saveFeaturesToStorage(features) {
const safeSetValue = getSafeGMSetValue();
if (!safeSetValue) {
gmLogger$1.debug("Fallback to localStorage for persisting features");
saveFeaturesToLocalStorage(features);
return;
}
try {
safeSetValue(STORAGE_KEY$1, features);
gmLogger$1.debug("Features persisted to GM storage", {
storageKey: STORAGE_KEY$1,
logLevel: features.logLevel,
syncScroll: features.syncScroll
});
} catch (error) {
gmLogger$1.warn("Failed to persist features to GM storage", error);
gmLogger$1.debug("Fallback to localStorage after GM storage write failure");
saveFeaturesToLocalStorage(features);
}
}
const featuresStore = writable(loadFeaturesFromStorage());
featuresStore.subscribe((features) => {
saveFeaturesToStorage(features);
setLogLevel(features.logLevel);
});
function toggleVisibility() {
featuresStore.update((features) => ({
...features,
isVisible: !features.isVisible
}));
}
const allExpandedStore = writable(true);
function toggleAllExpanded() {
allExpandedStore.update((expanded) => !expanded);
}
const outlineStore = writable([]);
var MessageOwner = ((MessageOwner2) => {
MessageOwner2["User"] = "user";
MessageOwner2["Assistant"] = "assistant";
MessageOwner2["Other"] = "other";
return MessageOwner2;
})(MessageOwner || {});
const deepseekConfig = {
selectChatArea: function() {
const ele = document.querySelectorAll(".ds-scroll-area")[2];
if (ele.tagName == "TEXTAREA") {
return ele.parentElement?.parentElement?.parentElement?.parentElement;
} else {
return ele;
}
},
getMessageList: function(root2) {
const items = root2.querySelectorAll(".ds-virtual-list-visible-items")[0];
if (items === void 0) {
return [];
}
return items.children;
},
determineMessageOwner: function(messageEle) {
if (messageEle.style[0]) {
return MessageOwner.Assistant;
}
return MessageOwner.User;
},
getOutlineContainer: function() {
let b1 = document.querySelectorAll(".ds-scroll-area")[0]?.parentElement?.parentElement?.parentElement;
return b1 || null;
},
getScrollContainer: function(chatArea) {
return chatArea.querySelector(".ds-virtual-list");
},
getConversationId: function() {
const pathname = window.location.pathname;
const parts = pathname.split("/").filter(Boolean);
if (parts.length >= 4 && parts[0] === "a" && parts[1] === "chat" && parts[2] === "s") {
return parts[3];
}
return null;
},
getConversationName: function() {
const ele = document.querySelectorAll(".ds-scroll-area")[2];
return ele.children[0].textContent;
},
buildConversationUrl: function(conversationId) {
return `/a/chat/s/${conversationId}`;
}
};
const doubaoConfig = {
selectChatArea: function() {
return document.querySelector('[data-testid="scroll_view"]')?.parentElement?.parentElement;
},
getMessageList: function(root2) {
if (!root2 || !root2.querySelector) {
return null;
}
const children = root2.querySelectorAll(".container-PvPoAn");
if (!children) {
return null;
}
return children;
},
determineMessageOwner: function(messageEle) {
if (messageEle.querySelector('[data-testid*="send_message"]') || messageEle.querySelector('[data-testid="send_message"]')) {
return MessageOwner.User;
}
if (messageEle.querySelector('[data-testid*="receive_message"]') || messageEle.querySelector('[data-testid="receive_message"]')) {
return MessageOwner.Assistant;
}
return MessageOwner.Other;
},
getOutlineContainer: function() {
return document.querySelector("main") || null;
},
getScrollContainer(chatArea) {
return chatArea.querySelector('[class^="scrollable"]');
},
getConversationId: function() {
const pathname = window.location.pathname;
const parts = pathname.split("/").filter(Boolean);
if (parts.length >= 2 && parts[0] === "chat") {
return parts[1];
}
return null;
},
getConversationName: function() {
const titleElement = document.querySelector("main")?.firstElementChild?.firstElementChild?.children[1]?.firstChild?.firstChild?.firstChild;
return titleElement?.textContent?.trim() || null;
},
buildConversationUrl: function(conversationId) {
return `/chat/${conversationId}`;
}
};
const chatgptConfig = {
selectChatArea: function() {
return document.querySelector("#main") || document.querySelector("main");
},
getMessageList: function(root2) {
if (!root2 || !root2.querySelectorAll) {
return null;
}
const messages = root2.querySelectorAll("[data-message-author-role]");
if (messages) {
return messages;
}
const articles = root2.querySelectorAll("article");
if (articles && articles.length > 0) {
return articles;
}
return null;
},
determineMessageOwner: function(messageEle) {
const authorRole = messageEle.getAttribute("data-message-author-role");
if (authorRole === "user") {
return MessageOwner.User;
}
if (authorRole === "assistant") {
return MessageOwner.Assistant;
}
if (messageEle.querySelector('[data-message-author-role="user"]')) {
return MessageOwner.User;
}
if (messageEle.querySelector('[data-message-author-role="assistant"]')) {
return MessageOwner.Assistant;
}
return MessageOwner.Other;
},
getOutlineContainer: function() {
const mainContainer = document.querySelector("#main")?.parentElement?.parentElement?.parentElement;
return mainContainer || null;
},
getScrollContainer(chatArea) {
return document.querySelector("[data-scroll-root]");
},
timeout: 5e3,
getConversationId: function() {
const pathname = window.location.pathname;
const parts = pathname.split("/").filter(Boolean);
if (parts.length >= 2 && parts[0] === "c") {
return parts[1];
}
return null;
},
getConversationName: function() {
const titleElement = document.querySelector("#history a[data-active]");
return titleElement?.textContent?.trim() || null;
},
buildConversationUrl: function(conversationId) {
return `/c/${conversationId}`;
}
};
const grokConfig = {
selectChatArea: function() {
return document.querySelector("#last-reply-container")?.parentElement;
},
getMessageList: function(root2) {
if (!root2 || !root2.querySelectorAll) {
return null;
}
let messages = root2.querySelectorAll(":scope > .relative");
return Array.from(messages).concat(Array.from(root2.querySelectorAll(":scope > #last-reply-container > div > .relative")));
},
determineMessageOwner: function(messageEle) {
const l = messageEle.children[2].firstChild.children.length;
if (l < 5) {
return MessageOwner.User;
}
return MessageOwner.Assistant;
},
getOutlineContainer: function() {
const chatContainer = document.querySelector("main");
return chatContainer?.parentElement ?? null;
},
getScrollContainer(chatArea) {
return chatArea.querySelector(".scrollbar-gutter-stable");
},
getConversationId: function() {
const pathname = window.location.pathname;
const parts = pathname.split("/").filter(Boolean);
if (parts.length >= 2 && parts[0] === "c") {
return parts[1];
}
return null;
},
getConversationName: function() {
let title = document.title.trim();
title = title.substring(0, title.length - 7);
return title || null;
},
buildConversationUrl: function(conversationId) {
return `/c/${conversationId}`;
}
};
const tongyiConfig = {
selectChatArea: function() {
return document.querySelector('[class^="scrollOutWrapper"]');
},
getMessageList: function(root2) {
if (!root2 || !root2.querySelectorAll) {
return null;
}
let messages = root2.querySelectorAll('div[class^="content-"]');
return messages;
},
determineMessageOwner: function(messageEle) {
let className = messageEle.parentElement.parentElement.className;
if (className.includes("questionItem")) {
return MessageOwner.User;
}
className = messageEle.parentElement.parentElement.parentElement.className;
if (className.includes("answerItem")) {
return MessageOwner.Assistant;
}
return MessageOwner.Other;
},
getOutlineContainer: function() {
const tongyiContainer = document.querySelector("[class^=mainContent]").parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement;
return tongyiContainer;
},
getScrollContainer: function(chatArea) {
return chatArea.parentElement;
},
getConversationId: function() {
const pathname = window.location.pathname;
const parts = pathname.split("/").filter(Boolean);
if (parts.length >= 2 && parts[0] === "chat") {
return parts[1];
}
return null;
},
getConversationName: function() {
const titleElement = document.querySelector(".mobile\\:pr-3 > div.hover\\:\\!bg-tag > .space-x-1");
return titleElement?.textContent?.trim() || null;
},
buildConversationUrl: function(conversationId) {
return `/chat/${conversationId}`;
}
};
const qwenConfig = {
selectChatArea: function() {
return document.querySelector("#chat-message-container");
},
getMessageList: function(root2) {
if (!root2 || !root2.querySelectorAll) {
return null;
}
let messages = root2.querySelectorAll(".response-message-content, .chat-user-message");
return messages;
},
determineMessageOwner: function(messageEle) {
if (messageEle.className.includes("chat-user-message")) {
return MessageOwner.User;
}
return MessageOwner.Assistant;
},
getOutlineContainer: function() {
const mainContainer = document.querySelector(".desktop-layout");
mainContainer.style.backgroundColor = getCurrentColors().background;
return mainContainer;
},
getScrollContainer(chatArea) {
return chatArea.parentElement;
},
getConversationId: function() {
const pathname = window.location.pathname;
const parts = pathname.split("/").filter(Boolean);
if (parts.length >= 2 && parts[0] === "c") {
return parts[1];
}
return null;
},
getConversationName: function() {
const titleElement = document.querySelector(".folder-content .chat-item-drag-active");
return titleElement?.textContent?.trim() || null;
},
buildConversationUrl: function(conversationId) {
return `/c/${conversationId}`;
}
};
const kimiConfig = {
selectChatArea: function() {
return document.querySelector(".layout-content-main");
},
getMessageList: function(root2) {
if (!root2 || !root2.querySelectorAll) {
return null;
}
let messages = root2.querySelectorAll(".chat-content-item");
return messages;
},
determineMessageOwner: function(messageEle) {
if (messageEle.className.includes("chat-content-item-user")) {
return MessageOwner.User;
} else if (messageEle.className.includes("chat-content-item-assistant")) {
return MessageOwner.Assistant;
}
return MessageOwner.Other;
},
getOutlineContainer: function() {
const mainContainer = document.querySelector(".main");
return mainContainer;
},
getScrollContainer(chatArea) {
return chatArea.querySelector(".chat-detail-main");
},
timeout: 5e3,
getConversationId: function() {
const pathname = window.location.pathname;
const parts = pathname.split("/").filter(Boolean);
if (parts.length >= 2 && parts[0] === "chat") {
return parts[1];
}
return null;
},
getConversationName: function() {
const titleElement = document.querySelector(".chat-header-content");
return titleElement?.textContent?.trim() || null;
},
buildConversationUrl: function(conversationId) {
return `/chat/${conversationId}`;
}
};
const yuanbaoConfig = {
selectChatArea: function() {
return document.querySelector(".agent-chat__list__content");
},
getMessageList: function(root2) {
if (!root2 || !root2.querySelectorAll) {
return null;
}
return root2.querySelectorAll(".agent-chat__bubble__content");
},
determineMessageOwner: function(messageEle) {
const className = messageEle.firstElementChild?.className;
if (typeof className !== "string") {
return MessageOwner.Other;
}
if (className.includes("-ai_")) {
return MessageOwner.Assistant;
} else {
return MessageOwner.User;
}
},
getOutlineContainer: function() {
return document.querySelector(".agent-dialogue");
},
getScrollContainer: function(chatArea) {
return chatArea.parentElement;
},
getConversationId: function() {
const parts = window.location.pathname.split("/").filter(Boolean);
if (parts.length >= 3 && parts[0] === "chat") {
return `${parts[1]}/${parts[2]}`;
}
return null;
},
getConversationName: function() {
const title = document.title.trim();
return title || null;
},
buildConversationUrl: function(conversationId) {
return `/chat/${conversationId}`;
}
};
const platformStore = writable("unknown");
const parserConfigStore = writable(null);
function judgePlatform() {
const hostname = window.location.hostname;
if (hostname.includes("deepseek.com")) return "deepseek";
if (hostname.includes("doubao.com")) return "doubao";
if (hostname.includes("chatgpt.com")) return "chatgpt";
if (hostname.includes("grok.com")) return "grok";
if (hostname.includes("qianwen.com")) return "tongyi";
if (hostname.includes("qwen.ai")) return "qwen";
if (hostname.includes("kimi.com")) return "kimi";
if (hostname.includes("yuanbao.tencent.com")) return "yuanbao";
return "unknown";
}
function setPlatform(platform) {
platformStore.set(platform);
const config = getParserConfigForPlatform(platform);
parserConfigStore.set(config);
}
function getParserConfigForPlatform(platform) {
switch (platform) {
case "deepseek":
return deepseekConfig;
case "doubao":
return doubaoConfig;
case "chatgpt":
return chatgptConfig;
case "grok":
return grokConfig;
case "tongyi":
return tongyiConfig;
case "qwen":
return qwenConfig;
case "kimi":
return kimiConfig;
case "yuanbao":
return yuanbaoConfig;
default:
return null;
}
}
let idCounter = 0;
function generateUniqueId() {
return `${Date.now()}-${++idCounter}`;
}
const defaultServiceStatus = {
outlineRuntime: {
key: "outlineRuntime",
label: "大纲运行时",
state: "idle",
message: "大纲运行时尚未初始化",
updatedAt: Date.now()
},
scrollSync: {
key: "scrollSync",
label: "滚动监听",
state: "idle",
message: "滚动监听尚未初始化",
updatedAt: Date.now()
}
};
const serviceStatusStore = writable(defaultServiceStatus);
const panelNoticeStore = writable([]);
let noticeId = 0;
function setServiceStatus(key, patch) {
serviceStatusStore.update((status) => ({
...status,
[key]: {
...status[key],
...patch,
updatedAt: Date.now()
}
}));
}
function resetServiceStatus() {
serviceStatusStore.set({
outlineRuntime: { ...defaultServiceStatus.outlineRuntime, updatedAt: Date.now() },
scrollSync: { ...defaultServiceStatus.scrollSync, updatedAt: Date.now() }
});
}
function pushPanelNotice(message, level = "info", duration = 3e3) {
const id = ++noticeId;
const notice = {
id,
level,
message,
createdAt: Date.now()
};
panelNoticeStore.update((list) => [...list, notice]);
if (duration > 0) {
window.setTimeout(() => {
removePanelNotice(id);
}, duration);
}
return id;
}
function removePanelNotice(id) {
panelNoticeStore.update((list) => list.filter((notice) => notice.id !== id));
}
const DEFAULT_CONVERSATION_ID = "default";
function getConversationId() {
const config = get(parserConfigStore);
if (config?.getConversationId) {
const id = config.getConversationId();
return id ?? DEFAULT_CONVERSATION_ID;
}
return DEFAULT_CONVERSATION_ID;
}
function getConversationName() {
const config = get(parserConfigStore);
if (config?.getConversationName) {
const name = config.getConversationName();
return name ?? getConversationId();
}
return getConversationId();
}
function isInConversation(targetConversationId) {
return getConversationId() === targetConversationId;
}
const STORAGE_KEY = "chat-outline-bookmarks";
const EXPORT_VERSION = "2.0.0";
const gmLogger = createTaggedLogger("Bookmarks");
function generateBookmarkId() {
return `bm_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
}
function loadBookmarksFromStorage() {
try {
const saved = window.localStorage.getItem(STORAGE_KEY);
if (!saved) {
return {};
}
const parsed = JSON.parse(saved);
const data = {};
for (const [conversationId, value] of Object.entries(parsed)) {
if (Array.isArray(value)) {
data[conversationId] = {
name: null,
bookmarks: value.map((b) => ({
id: b.id,
name: b.name,
outlineItemType: b.outlineItemType,
messageIndex: b.messageIndex,
messageHash: b.messageHash,
headerPath: b.headerPath,
createdAt: b.createdAt
}))
};
} else {
data[conversationId] = value;
}
}
gmLogger.debug("从 localStorage 加载书签", { conversationCount: Object.keys(data).length });
return data;
} catch (error) {
gmLogger.warn("加载书签失败", error);
return {};
}
}
function saveBookmarksToStorage(data) {
try {
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
gmLogger.debug("书签已保存到 localStorage");
} catch (error) {
gmLogger.error("保存书签失败", error);
}
}
function createBookmarksStore() {
const { subscribe, set: set2, update } = writable(loadBookmarksFromStorage());
subscribe((data) => {
saveBookmarksToStorage(data);
});
return {
subscribe,
addBookmark(params) {
const bookmark = {
id: generateBookmarkId(),
name: params.name,
outlineItemType: params.outlineItemType,
messageHash: params.messageHash,
messageIndex: params.messageIndex,
headerPath: params.headerPath,
createdAt: Date.now()
};
update((data) => {
if (!data[params.conversationId]) {
const convName = getConversationName();
data[params.conversationId] = {
name: convName,
bookmarks: []
};
}
data[params.conversationId].bookmarks.push(bookmark);
return { ...data };
});
gmLogger.info("添加书签", { id: bookmark.id, name: bookmark.name, headerPath: params.headerPath });
return bookmark;
},
removeBookmark(bookmarkId) {
update((data) => {
for (const conversationId of Object.keys(data)) {
const index2 = data[conversationId].bookmarks.findIndex((b) => b.id === bookmarkId);
if (index2 !== -1) {
data[conversationId].bookmarks.splice(index2, 1);
if (data[conversationId].bookmarks.length === 0) {
delete data[conversationId];
}
gmLogger.info("删除书签", { id: bookmarkId });
break;
}
}
return { ...data };
});
},
updateBookmarkName(bookmarkId, newName) {
update((data) => {
for (const conversationId of Object.keys(data)) {
const bookmark = data[conversationId].bookmarks.find((b) => b.id === bookmarkId);
if (bookmark) {
bookmark.name = newName;
gmLogger.info("更新书签名称", { id: bookmarkId, newName });
break;
}
}
return { ...data };
});
},
getBookmarksByConversation(conversationId) {
const data = get({ subscribe });
return data[conversationId]?.bookmarks || [];
},
getConversationData(conversationId) {
const data = get({ subscribe });
return data[conversationId];
},
getCurrentConversationBookmarks() {
const conversationId = getConversationId();
return this.getBookmarksByConversation(conversationId);
},
getAllBookmarks() {
const data = get({ subscribe });
const result = [];
for (const [conversationId, convData] of Object.entries(data)) {
for (const bookmark of convData.bookmarks) {
result.push({ ...bookmark, conversationId });
}
}
return result;
},
getAllBookmarksGrouped() {
return get({ subscribe });
},
getAllConversations() {
const data = get({ subscribe });
return Object.entries(data).map(([conversationId, convData]) => ({
conversationId,
name: convData.name,
bookmarkCount: convData.bookmarks.length
}));
},
searchBookmarks(query, conversationId) {
const data = get({ subscribe });
const lowerQuery = query.toLowerCase();
const result = [];
const searchInConv = (convId, bookmarks) => {
for (const b of bookmarks) {
if (b.name.toLowerCase().includes(lowerQuery)) {
result.push({ ...b, conversationId: convId });
}
}
};
if (conversationId) {
const convData = data[conversationId];
if (convData) {
searchInConv(conversationId, convData.bookmarks);
}
} else {
for (const [convId, convData] of Object.entries(data)) {
searchInConv(convId, convData.bookmarks);
}
}
return result;
},
hasBookmarkForMessageIndex(messageIndex, conversationId) {
const data = get({ subscribe });
const convId = conversationId || getConversationId();
const bookmarks = data[convId]?.bookmarks || [];
return bookmarks.some((b) => b.messageIndex === messageIndex && b.outlineItemType === "message");
},
hasBookmarkForHeader(messageIndex, headerPath, conversationId) {
const data = get({ subscribe });
const convId = conversationId || getConversationId();
const bookmarks = data[convId]?.bookmarks || [];
return bookmarks.some(
(b) => b.messageIndex === messageIndex && b.outlineItemType === "header" && b.headerPath === headerPath
);
},
getBookmarkByMessageIndex(messageIndex, conversationId) {
const data = get({ subscribe });
const convId = conversationId || getConversationId();
const bookmarks = data[convId]?.bookmarks || [];
return bookmarks.find((b) => b.messageIndex === messageIndex && b.outlineItemType === "message");
},
getBookmarkByHeaderPath(messageIndex, headerPath, conversationId) {
const data = get({ subscribe });
const convId = conversationId || getConversationId();
const bookmarks = data[convId]?.bookmarks || [];
return bookmarks.find(
(b) => b.messageIndex === messageIndex && b.outlineItemType === "header" && b.headerPath === headerPath
);
},
getBookmarksForMessage(messageIndex, conversationId) {
const data = get({ subscribe });
const convId = conversationId || getConversationId();
const bookmarks = data[convId]?.bookmarks || [];
return bookmarks.filter((b) => b.messageIndex === messageIndex);
},
hasAnyBookmarkForMessage(messageIndex, conversationId) {
const data = get({ subscribe });
const convId = conversationId || getConversationId();
const bookmarks = data[convId]?.bookmarks || [];
return bookmarks.some((b) => b.messageIndex === messageIndex);
},
getBookmarkById(bookmarkId) {
const data = get({ subscribe });
for (const [conversationId, convData] of Object.entries(data)) {
const bookmark = convData.bookmarks.find((b) => b.id === bookmarkId);
if (bookmark) {
return { ...bookmark, conversationId };
}
}
return void 0;
},
exportBookmarks() {
const data = get({ subscribe });
return {
version: EXPORT_VERSION,
exportedAt: Date.now(),
data: { ...data }
};
},
importBookmarks(exportData, merge = true) {
let importedCount = 0;
update((data) => {
for (const [conversationId, convData] of Object.entries(exportData.data)) {
if (!merge) {
data[conversationId] = convData;
importedCount += convData.bookmarks.length;
} else {
if (!data[conversationId]) {
data[conversationId] = convData;
importedCount += convData.bookmarks.length;
} else {
for (const bookmark of convData.bookmarks) {
const exists = data[conversationId].bookmarks.some(
(b) => b.messageIndex === bookmark.messageIndex && b.outlineItemType === bookmark.outlineItemType && b.headerPath === bookmark.headerPath
);
if (!exists) {
data[conversationId].bookmarks.push(bookmark);
importedCount++;
}
}
}
}
}
return { ...data };
});
gmLogger.info("导入书签", { count: importedCount, merge });
return importedCount;
},
clearAll() {
set2({});
gmLogger.info("清空所有书签");
},
clearConversation(conversationId) {
update((data) => {
delete data[conversationId];
return { ...data };
});
gmLogger.info("清空会话书签", { conversationId });
}
};
}
const bookmarksStore = createBookmarksStore();
var root$9 = from_html(`<div class="modal-overlay svelte-lmj43v" role="button" tabindex="0"><div class="modal-content svelte-lmj43v" role="dialog" aria-modal="true" tabindex="-1"><div class="modal-header svelte-lmj43v"><h3 class="svelte-lmj43v">设置</h3> <button class="close-btn svelte-lmj43v">✕</button></div> <div class="modal-body svelte-lmj43v"><div class="setting-section svelte-lmj43v"><h4 class="section-title svelte-lmj43v">显示设置</h4> <label class="svelte-lmj43v"><input type="checkbox" class="svelte-lmj43v"/> 自动展开节点</label> <label class="svelte-lmj43v"><input type="checkbox" class="svelte-lmj43v"/> 显示用户消息</label> <label class="svelte-lmj43v"><input type="checkbox" class="svelte-lmj43v"/> 显示AI回复</label> <label class="svelte-lmj43v"><input type="checkbox" class="svelte-lmj43v"/> 同步滚动</label></div> <div class="setting-section svelte-lmj43v"><h4 class="section-title svelte-lmj43v">书签设置</h4> <label class="svelte-lmj43v">书签默认名称长度 <input type="number" min="10" max="100" class="svelte-lmj43v"/></label></div> <div class="setting-section svelte-lmj43v"><h4 class="section-title svelte-lmj43v">高级设置</h4> <label class="svelte-lmj43v">文本长度限制 <input type="number" min="10" max="200" class="svelte-lmj43v"/></label> <label class="svelte-lmj43v">更新间隔 (ms) <input type="number" min="100" max="2000" step="100" class="svelte-lmj43v"/></label> <label class="svelte-lmj43v">日志级别 <select class="svelte-lmj43v"><option>Debug</option><option>Info</option><option>Warn</option><option>Error</option></select></label></div></div></div></div>`);
function SettingsModal($$anchor, $$props) {
push($$props, true);
const $featuresStore = () => store_get(featuresStore, "$featuresStore", $$stores);
const [$$stores, $$cleanup] = setup_stores();
let features = state(proxy($featuresStore()));
user_effect(() => {
set(features, $featuresStore(), true);
});
function updateFeature(key, value) {
featuresStore.update((f) => ({ ...f, [key]: value }));
}
var div = root$9();
var div_1 = child(div);
var div_2 = child(div_1);
var button = sibling(child(div_2), 2);
var div_3 = sibling(div_2, 2);
var div_4 = child(div_3);
var label = sibling(child(div_4), 2);
var input = child(label);
var label_1 = sibling(label, 2);
var input_1 = child(label_1);
var label_2 = sibling(label_1, 2);
var input_2 = child(label_2);
var label_3 = sibling(label_2, 2);
var input_3 = child(label_3);
var div_5 = sibling(div_4, 2);
var label_4 = sibling(child(div_5), 2);
var input_4 = sibling(child(label_4));
var div_6 = sibling(div_5, 2);
var label_5 = sibling(child(div_6), 2);
var input_5 = sibling(child(label_5));
var label_6 = sibling(label_5, 2);
var input_6 = sibling(child(label_6));
var label_7 = sibling(label_6, 2);
var select = sibling(child(label_7));
var option = child(select);
option.value = option.__value = "debug";
var option_1 = sibling(option);
option_1.value = option_1.__value = "info";
var option_2 = sibling(option_1);
option_2.value = option_2.__value = "warn";
var option_3 = sibling(option_2);
option_3.value = option_3.__value = "error";
var select_value;
init_select(select);
template_effect(() => {
set_checked(input, get$1(features).autoExpand);
set_checked(input_1, get$1(features).showUserMessages);
set_checked(input_2, get$1(features).showAIMessages);
set_checked(input_3, get$1(features).syncScroll);
set_value(input_4, get$1(features).bookmarkGetTextLength);
set_value(input_5, get$1(features).textLength);
set_value(input_6, get$1(features).debouncedInterval);
if (select_value !== (select_value = get$1(features).logLevel)) {
select.value = (select.__value = get$1(features).logLevel) ?? "", select_option(select, get$1(features).logLevel);
}
});
delegated("click", div, function(...$$args) {
$$props.onClose?.apply(this, $$args);
});
delegated("keydown", div, (e) => e.key === "Escape" && $$props.onClose());
delegated("click", div_1, (e) => e.stopPropagation());
delegated("keydown", div_1, (e) => e.stopPropagation());
delegated("click", button, function(...$$args) {
$$props.onClose?.apply(this, $$args);
});
delegated("change", input, (e) => updateFeature("autoExpand", e.currentTarget.checked));
delegated("change", input_1, (e) => updateFeature("showUserMessages", e.currentTarget.checked));
delegated("change", input_2, (e) => updateFeature("showAIMessages", e.currentTarget.checked));
delegated("change", input_3, (e) => updateFeature("syncScroll", e.currentTarget.checked));
delegated("change", input_4, (e) => updateFeature("bookmarkGetTextLength", parseInt(e.currentTarget.value)));
delegated("change", input_5, (e) => updateFeature("textLength", parseInt(e.currentTarget.value)));
delegated("change", input_6, (e) => updateFeature("debouncedInterval", parseInt(e.currentTarget.value)));
delegated("change", select, (e) => updateFeature("logLevel", e.currentTarget.value));
append($$anchor, div);
pop();
$$cleanup();
}
delegate(["click", "keydown", "change"]);
function debounce(func, wait) {
let timeout = null;
return function executedFunction(...args) {
const later = () => {
timeout = null;
func(...args);
};
if (timeout !== null) {
clearTimeout(timeout);
}
timeout = setTimeout(later, wait);
};
}
async function getEleWithRetry(getFunc, args = [], judgeRes = true, maxRetries = 10, retryDelay = 1e3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const res = getFunc(...args);
if (!judgeRes) return true;
if (res) {
logger$1.info(`调用 ${getFunc.name} 获取目标成功,尝试次数: ${attempt + 1}`);
return res;
}
if (attempt < maxRetries - 1) {
logger$1.debug(`第 ${attempt + 1} 次调用 ${getFunc.name} 获取目标失败,${retryDelay}ms 后重试...`);
await new Promise((resolve) => setTimeout(resolve, retryDelay));
}
} catch (error) {
logger$1.error(`调用 ${getFunc.name} 获取目标时发生错误 (尝试 ${attempt + 1}):`, error);
if (attempt < maxRetries - 1) {
await new Promise((resolve) => setTimeout(resolve, retryDelay));
}
}
}
logger$1.error(`经过 ${maxRetries} 次尝试后仍无法获取到目标`);
return null;
}
function highlightElement(element) {
element.classList.remove("highlight-animation");
element.offsetHeight;
element.classList.add("highlight-animation");
const theme = get(themeStore);
setTimeout(() => {
element.classList.remove("highlight-animation");
}, theme.highlightTime);
}
var root_1$9 = from_html(`<button class="outline-btn svelte-zptf9e" title="强制刷新大纲" aria-label="强制刷新大纲">🔄</button> <button class="outline-btn svelte-zptf9e" title="同步大纲位置" aria-label="同步大纲位置">📍</button> <button class="outline-btn svelte-zptf9e"> </button>`, 1);
var root_2$6 = from_html(`<div class="filter-row svelte-zptf9e"><input type="text" class="filter-input svelte-zptf9e" placeholder="筛选..."/> <button>.*</button></div>`);
var root$8 = from_html(`<header class="chat-outline-header svelte-zptf9e"><div class="title-row svelte-zptf9e"><h3 class="chat-outline-title svelte-zptf9e"></h3> <div class="title-controls svelte-zptf9e"><button class="outline-btn svelte-zptf9e" title="设置" aria-label="设置">⚙️</button> <button class="outline-btn svelte-zptf9e" title="隐藏大纲" aria-label="隐藏大纲">✕</button></div></div> <div class="tab-container svelte-zptf9e"><button>📋 大纲</button> <button>📚 书签</button></div> <div class="controls-row svelte-zptf9e"><div class="controls-left svelte-zptf9e"><!></div> <div class="controls-right svelte-zptf9e"><button class="outline-btn svelte-zptf9e" title="切换主题" aria-label="切换主题"> </button></div></div> <!></header> <!>`, 1);
function OutlineHeader($$anchor, $$props) {
push($$props, true);
let filterText = state("");
let useRegex = state(false);
let showSettings = state(false);
const emitFilterChange = debounce(
(filter, regex) => {
$$props.onFilterChange(filter, regex);
},
150
);
function handleFilterInput(e) {
set(filterText, e.target.value, true);
emitFilterChange(get$1(filterText), get$1(useRegex));
}
function toggleRegex() {
set(useRegex, !get$1(useRegex));
$$props.onFilterChange(get$1(filterText), get$1(useRegex));
}
var fragment = root$8();
var header = first_child(fragment);
var div = child(header);
var h3 = child(div);
h3.textContent = "对话大纲";
var div_1 = sibling(h3, 2);
var button = child(div_1);
var button_1 = sibling(button, 2);
var div_2 = sibling(div, 2);
var button_2 = child(div_2);
let classes;
var button_3 = sibling(button_2, 2);
let classes_1;
var div_3 = sibling(div_2, 2);
var div_4 = child(div_3);
var node = child(div_4);
{
var consequent = ($$anchor2) => {
var fragment_1 = root_1$9();
var button_4 = first_child(fragment_1);
var button_5 = sibling(button_4, 2);
var button_6 = sibling(button_5, 2);
var text2 = child(button_6);
template_effect(() => {
set_attribute(button_6, "title", $$props.allExpanded ? "收起所有节点" : "展开所有节点");
set_attribute(button_6, "aria-label", $$props.allExpanded ? "收起所有节点" : "展开所有节点");
set_text(text2, $$props.allExpanded ? "📂" : "📁");
});
delegated("click", button_4, function(...$$args) {
$$props.onRefresh?.apply(this, $$args);
});
delegated("click", button_5, function(...$$args) {
$$props.onSync?.apply(this, $$args);
});
delegated("click", button_6, function(...$$args) {
$$props.onToggleAll?.apply(this, $$args);
});
append($$anchor2, fragment_1);
};
if_block(node, ($$render) => {
if ($$props.viewMode === "outline") $$render(consequent);
});
}
var div_5 = sibling(div_4, 2);
var button_7 = child(div_5);
var text_1 = child(button_7);
var node_1 = sibling(div_3, 2);
{
var consequent_1 = ($$anchor2) => {
var div_6 = root_2$6();
var input = child(div_6);
var button_8 = sibling(input, 2);
let classes_2;
template_effect(() => {
set_value(input, get$1(filterText));
classes_2 = set_class(button_8, 1, "outline-btn regex-btn svelte-zptf9e", null, classes_2, { active: get$1(useRegex) });
set_attribute(button_8, "title", get$1(useRegex) ? "关闭正则表达式" : "启用正则表达式");
});
delegated("input", input, handleFilterInput);
delegated("click", button_8, toggleRegex);
append($$anchor2, div_6);
};
if_block(node_1, ($$render) => {
if ($$props.viewMode === "outline") $$render(consequent_1);
});
}
var node_2 = sibling(header, 2);
{
var consequent_2 = ($$anchor2) => {
SettingsModal($$anchor2, { onClose: () => set(showSettings, false) });
};
if_block(node_2, ($$render) => {
if (get$1(showSettings)) $$render(consequent_2);
});
}
template_effect(() => {
classes = set_class(button_2, 1, "tab-btn svelte-zptf9e", null, classes, { active: $$props.viewMode === "outline" });
classes_1 = set_class(button_3, 1, "tab-btn svelte-zptf9e", null, classes_1, { active: $$props.viewMode === "bookmark" });
set_text(text_1, $$props.currentTheme === "light" ? "🌙" : "☀️");
});
delegated("click", button, () => set(showSettings, true));
delegated("click", button_1, function(...$$args) {
$$props.onHide?.apply(this, $$args);
});
delegated("click", button_2, () => $$props.onTabChange("outline"));
delegated("click", button_3, () => $$props.onTabChange("bookmark"));
delegated("click", button_7, function(...$$args) {
$$props.onToggleTheme?.apply(this, $$args);
});
append($$anchor, fragment);
pop();
}
delegate(["click", "input"]);
const HEADER_SELECTOR = "h1, h2, h3, h4, h5, h6";
function getMessageText(messageElement) {
return messageElement.textContent || "";
}
function buildMessageHash(index2, text2) {
const idLength = 10;
if (text2.length <= idLength * 2) {
return `${index2}${text2}`;
}
const res = [];
const step = Math.max(1, Math.ceil((text2.length - idLength) / idLength));
for (let i = 0; i < text2.length - idLength && res.length < idLength; i += step) {
res.push(text2[i]);
}
return `${index2}${res.join("")}${text2.substring(text2.length - idLength)}`;
}
function buildHeaderTreeWithPrefix(headers, prefix) {
const tree = [];
const stack = [];
headers.forEach((header) => {
const level = Number.parseInt(header.tagName.charAt(1), 10);
const node = {
id: "",
element: header,
level,
text: header.textContent || "",
children: []
};
while (stack.length > 0 && stack[stack.length - 1].level >= level) {
stack.pop();
}
const parent = stack[stack.length - 1];
const localId = parent ? `${parent.id}.${parent.children.length}` : `${tree.length}`;
node.id = prefix ? `${prefix}:${localId}` : localId;
if (parent) {
parent.children.push(node);
} else {
tree.push(node);
}
stack.push(node);
});
return tree;
}
function buildOutlineData(messageElement, type, textLength, headerIdPrefix = "") {
const searchText = getMessageText(messageElement);
const text2 = searchText.substring(0, textLength) + (searchText.length > textLength ? "..." : "");
if (type !== MessageOwner.Assistant) {
return { text: text2, searchText };
}
const headers = messageElement.querySelectorAll(HEADER_SELECTOR);
return {
text: text2,
searchText,
headers: headers.length > 0 ? buildHeaderTreeWithPrefix(Array.from(headers), headerIdPrefix) : void 0
};
}
function createOutlineViewItem(params) {
const { id, index: index2, type, element, textLength } = params;
const built = buildOutlineData(element, type, textLength, id);
return {
id,
index: index2,
type,
text: built.text,
searchText: built.searchText,
element,
headers: built.headers,
isExpanded: true
};
}
class MessageCacheManager {
cache = [];
cacheByMessageId = new Map();
cacheByOutlineId = new Map();
getCache() {
return this.cache;
}
setCache(cache) {
this.cache = cache;
this.rebuildIndexes();
}
clearCache() {
this.cache = [];
this.cacheByMessageId.clear();
this.cacheByOutlineId.clear();
}
get length() {
return this.cache.length;
}
get(index2) {
return this.cache[index2];
}
ensureMessageId(messageElement) {
let messageId = messageElement.getAttribute("cbe-message-id");
if (!messageId) {
messageId = generateUniqueId();
messageElement.setAttribute("cbe-message-id", messageId);
}
return messageId;
}
checkLastMessage(messageElements) {
if (this.cache.length === 0 || messageElements.length === 0) {
return { shouldRefreshAll: true, lastMessageNeedsUpdate: true, lastIndex: -1 };
}
const lastIndex = messageElements.length - 1;
const lastMessage = messageElements[lastIndex];
const lastCached = this.cache[this.cache.length - 1];
const messageId = this.ensureMessageId(lastMessage);
if (messageId !== lastCached.messageId) {
return { shouldRefreshAll: true, lastMessageNeedsUpdate: true, lastIndex };
}
const currentHash = buildMessageHash(lastIndex, lastMessage.textContent || "");
return {
shouldRefreshAll: false,
lastMessageNeedsUpdate: currentHash !== lastCached.messageHash,
lastIndex
};
}
updateLastCache(messageElement, index2, outlineItem, outlineElement) {
const messageId = this.ensureMessageId(messageElement);
const newCacheItem = {
messageId,
messageHash: buildMessageHash(index2, messageElement.textContent || ""),
textLength: messageElement.textContent?.length || 0,
outlineElement,
outlineItem,
timestamp: Date.now()
};
this.cache[this.cache.length - 1] = newCacheItem;
this.cacheByMessageId.set(messageId, newCacheItem);
this.cacheByOutlineId.set(outlineItem.id, newCacheItem);
}
rebuildCache(messageElements, parserConfig, options) {
const nextCache = [];
const outlineItems = [];
const changedIndices = [];
let displayIndex = 0;
for (let rawIndex = 0; rawIndex < messageElements.length; rawIndex++) {
const messageElement = messageElements[rawIndex];
const messageType = parserConfig.determineMessageOwner(messageElement);
const shouldShow = messageType === MessageOwner.User && options.features.showUserMessages || messageType === MessageOwner.Assistant && options.features.showAIMessages;
if (!shouldShow) {
continue;
}
const messageId = this.ensureMessageId(messageElement);
const messageHash = buildMessageHash(rawIndex, messageElement.textContent || "");
const oldCached = this.cacheByMessageId.get(messageId);
let nextCached;
if (oldCached && oldCached.messageHash === messageHash) {
nextCached = oldCached;
if (nextCached.outlineItem.index !== displayIndex) {
nextCached.outlineItem.index = displayIndex;
changedIndices.push(displayIndex);
}
nextCached.outlineItem.element = messageElement;
} else {
const stableOutlineId = oldCached?.outlineItem.id || generateUniqueId();
const outlineItem = createOutlineViewItem({
id: stableOutlineId,
index: displayIndex,
type: messageType,
element: messageElement,
textLength: options.features.textLength
});
nextCached = {
messageId,
messageHash,
textLength: messageElement.textContent?.length || 0,
outlineElement: oldCached?.outlineElement || null,
outlineItem,
timestamp: Date.now()
};
changedIndices.push(displayIndex);
}
nextCache.push(nextCached);
outlineItems.push(nextCached.outlineItem);
displayIndex += 1;
}
const addedCount = Math.max(0, nextCache.length - this.cache.length);
const removedCount = Math.max(0, this.cache.length - nextCache.length);
const hasChanges = changedIndices.length > 0 || addedCount > 0 || removedCount > 0 || nextCache.length !== this.cache.length;
this.cache = nextCache;
this.rebuildIndexes();
const changes = {
hasChanges,
changedIndices: [...new Set(changedIndices)],
addedCount,
removedCount
};
logger$1.debug("Cache 重建完成:", changes);
return { changes, outlineItems };
}
updateOutlineElement(outlineItemId, outlineElement) {
const cachedItem = this.cacheByOutlineId.get(outlineItemId);
if (!cachedItem || cachedItem.outlineElement === outlineElement) {
return;
}
cachedItem.outlineElement = outlineElement;
}
getOutlineElementByIndex(messageIndex) {
const element = this.cache[messageIndex]?.outlineElement;
return element ?? void 0;
}
getCacheIndexByMessageId(messageId) {
if (!messageId) {
return -1;
}
for (let index2 = 0; index2 < this.cache.length; index2++) {
if (this.cache[index2].messageId === messageId) {
return index2;
}
}
return -1;
}
scrollOutlineToMessage(messageIndex) {
const outlineElement = this.getOutlineElementByIndex(messageIndex);
outlineElement?.scrollIntoView({ behavior: "smooth", block: "center" });
}
rebuildIndexes() {
this.cacheByMessageId.clear();
this.cacheByOutlineId.clear();
for (const item of this.cache) {
this.cacheByMessageId.set(item.messageId, item);
this.cacheByOutlineId.set(item.outlineItem.id, item);
}
}
}
const messageCacheManager = new MessageCacheManager();
const BIND_RETRY_COUNT = 5;
const BIND_RETRY_DELAY = 1e3;
const MAX_AUTO_RETRY_COUNT = 5;
class ScrollSyncService {
scrollContainer = null;
scrollHandler = null;
isSyncing = false;
debounceTimer = null;
outlineContainer = null;
chatArea = null;
parserConfig = null;
currentHighlightedElement = null;
highlightTimer = null;
lastHighlightElement = null;
autoRetryTimer = null;
postRefreshCheckTimer = null;
isBinding = false;
retryGeneration = 0;
autoRetryCount = 0;
lastSyncScrollEnabled = null;
lastVisibleIndex = -1;
intersectionObserver = null;
visibleMessageMetrics = new Map();
manualNavigationUntil = 0;
headerOutlineElements = new Map();
scrollAnchors = [];
anchorOffsetsDirty = true;
rebuildScrollAnchorsTimer = null;
focusOutlineElement(outlineElement) {
if (!outlineElement) {
return;
}
this.manualNavigationUntil = Date.now() + 800;
this.lastHighlightElement = outlineElement;
}
registerHeaderOutlineElement(nodeId, outlineElement) {
this.headerOutlineElements.set(nodeId, outlineElement);
this.scheduleRebuildScrollAnchors();
}
unregisterHeaderOutlineElement(nodeId) {
if (this.headerOutlineElements.delete(nodeId)) {
this.scheduleRebuildScrollAnchors();
}
}
getHeaderOutlineElement(nodeId) {
return this.headerOutlineElements.get(nodeId) || null;
}
scheduleRebuildScrollAnchors() {
if (this.rebuildScrollAnchorsTimer) {
return;
}
this.rebuildScrollAnchorsTimer = setTimeout(() => {
this.rebuildScrollAnchorsTimer = null;
this.rebuildScrollAnchors();
}, 0);
}
markAnchorOffsetsDirty() {
this.anchorOffsetsDirty = true;
}
constructor() {
featuresStore.subscribe((features) => {
if (this.lastSyncScrollEnabled === features.syncScroll) {
return;
}
this.lastSyncScrollEnabled = features.syncScroll;
if (features.syncScroll) {
void this.bindScrollListenerWithRetry("sync-toggle", true);
} else {
this.clearAutoRetryTimer();
this.unbindScrollListener();
this.autoRetryCount = 0;
this.updateStatus("idle", "滚动监听开关已关闭");
}
});
}
init(chatArea, parserConfig) {
this.chatArea = chatArea;
this.parserConfig = parserConfig;
this.scrollContainer = null;
this.autoRetryCount = 0;
this.updateStatus("syncing", "正在获取滚动容器并绑定监听");
void this.bindScrollListenerWithRetry("init", true);
}
setOutlineContainer(container) {
this.outlineContainer = container;
if (!this.chatArea) {
this.handleAbnormalState("warning", "大纲容器已就绪,但聊天区域尚未绑定", false);
return;
}
if (this.scrollHandler) {
this.updateStatus("ready", "滚动监听已成功绑定");
this.triggerInitialSync();
return;
}
this.updateStatus("syncing", "大纲容器已就绪,等待滚动监听绑定");
void this.bindScrollListenerWithRetry("outline-ready", true);
}
manualSync() {
logger$1.info("手动同步大纲滚动");
this.lastHighlightElement = null;
this.lastVisibleIndex = -1;
this.visibleMessageMetrics.clear();
this.markAnchorOffsetsDirty();
this.syncOutlineScroll();
}
schedulePostRefreshCheck() {
if (!get(featuresStore).syncScroll) {
return;
}
if (this.postRefreshCheckTimer) {
clearTimeout(this.postRefreshCheckTimer);
}
this.postRefreshCheckTimer = setTimeout(() => {
this.postRefreshCheckTimer = null;
void this.performPostRefreshCheck();
}, 500);
}
async forceRebind() {
if (!this.parserConfig) {
this.handleAbnormalState("error", "未找到解析配置,无法重新绑定滚动监听", false);
pushPanelNotice("滚动监听重新绑定失败:解析配置不存在", "error");
return false;
}
const nextChatArea = await getEleWithRetry(
this.parserConfig.selectChatArea,
[],
true,
BIND_RETRY_COUNT,
BIND_RETRY_DELAY
);
if (!nextChatArea) {
this.handleAbnormalState("error", "未找到聊天区域,无法重新绑定滚动监听", false);
pushPanelNotice("滚动监听重新绑定失败:未找到聊天区域", "error");
return false;
}
this.chatArea = nextChatArea;
this.autoRetryCount = 0;
this.updateStatus("syncing", "正在重新获取滚动容器并绑定监听");
const isBound = await this.bindScrollListenerWithRetry("manual-rebind", false, false);
if (!isBound) {
pushPanelNotice("滚动监听重新绑定失败,请检查页面是否已稳定", "error");
return false;
}
pushPanelNotice("滚动监听重新绑定完成", "success");
return true;
}
rebind(chatArea, parserConfig) {
this.lastHighlightElement = null;
this.chatArea = chatArea;
this.parserConfig = parserConfig;
this.scrollContainer = null;
this.autoRetryCount = 0;
this.disconnectIntersectionObserver();
this.scrollAnchors = [];
this.unbindScrollListener();
if (!get(featuresStore).syncScroll) {
this.updateStatus("idle", "滚动监听开关已关闭");
return;
}
this.updateStatus("syncing", "正在重新获取滚动容器并绑定监听");
void this.bindScrollListenerWithRetry("rebind", true);
}
destroy(resetStatus = true) {
this.clearAutoRetryTimer();
this.clearPostRefreshCheckTimer();
this.disconnectIntersectionObserver();
this.unbindScrollListener();
if (this.highlightTimer) {
clearTimeout(this.highlightTimer);
this.highlightTimer = null;
}
this.scrollContainer = null;
this.outlineContainer = null;
this.chatArea = null;
this.parserConfig = null;
this.currentHighlightedElement = null;
this.lastHighlightElement = null;
this.lastVisibleIndex = -1;
this.visibleMessageMetrics.clear();
this.headerOutlineElements.clear();
this.scrollAnchors = [];
this.manualNavigationUntil = 0;
this.isBinding = false;
this.retryGeneration += 1;
this.autoRetryCount = 0;
if (resetStatus) {
this.updateStatus("idle", "滚动监听尚未初始化");
}
}
syncOutlineScroll() {
if (!this.scrollContainer || !this.outlineContainer) {
this.handleAbnormalState("warning", "缺少滚动容器或大纲容器,无法执行同步", false);
return;
}
if (Date.now() < this.manualNavigationUntil) {
return;
}
if (!this.scrollHandler) {
this.handleAbnormalState("warning", "滚动监听未绑定,正在尝试自动重试");
return;
}
const activeAnchor = this.findActiveAnchor();
if (activeAnchor) {
this.scrollToOutlineAnchor(activeAnchor);
return;
}
const visibleIndex = this.findVisibleMessageIndex();
if (visibleIndex === -1) {
this.updateStatus("warning", "未找到当前可见消息,滚动监听暂不可用");
return;
}
this.scrollToOutlineItem(visibleIndex);
}
async bindScrollListenerWithRetry(reason, allowAutoRetry, shouldTriggerInitialSync = true) {
if (this.isBinding) {
return false;
}
if (!get(featuresStore).syncScroll) {
this.updateStatus("idle", "滚动监听开关已关闭");
return false;
}
if (!this.chatArea || !this.parserConfig) {
this.handleAbnormalState("warning", "聊天区域或解析配置未就绪,无法绑定滚动监听", false);
return false;
}
this.isBinding = true;
this.retryGeneration += 1;
const generation = this.retryGeneration;
this.clearAutoRetryTimer();
this.unbindScrollListener();
this.updateStatus("syncing", `正在绑定滚动监听(${reason})`);
try {
const resolvedContainer = await this.resolveScrollContainerWithRetry();
if (generation !== this.retryGeneration) {
return false;
}
if (!resolvedContainer) {
this.handleAbnormalState("warning", "未找到滚动容器,已进入自动重试", allowAutoRetry);
return false;
}
this.scrollContainer = resolvedContainer;
this.scrollHandler = () => {
if (this.isSyncing) {
return;
}
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
}
this.debounceTimer = setTimeout(() => {
this.syncOutlineScroll();
}, 300);
};
this.scrollContainer.addEventListener("scroll", this.scrollHandler, {
passive: true
});
logger$1.info("绑定滚动监听成功,容器:", this.scrollContainer);
this.autoRetryCount = 0;
this.updateStatus("ready", "滚动监听已成功绑定");
this.observeVisibleMessages();
if (shouldTriggerInitialSync) {
this.triggerInitialSync();
}
return true;
} catch (error) {
logger$1.error("绑定滚动监听时发生异常:", error);
this.handleAbnormalState("error", "绑定滚动监听时发生异常,已进入自动重试", allowAutoRetry);
return false;
} finally {
if (generation === this.retryGeneration) {
this.isBinding = false;
}
}
}
async resolveScrollContainerWithRetry() {
if (!this.chatArea || !this.parserConfig) {
return null;
}
if (!this.parserConfig.getScrollContainer) {
return this.chatArea;
}
return getEleWithRetry(
() => this.parserConfig?.getScrollContainer?.(this.chatArea) ?? null,
[],
true,
BIND_RETRY_COUNT,
BIND_RETRY_DELAY
);
}
handleAbnormalState(state2, message, allowAutoRetry = true) {
this.updateStatus(state2, message);
if (allowAutoRetry) {
this.scheduleAutoRetry(message);
}
}
scheduleAutoRetry(message) {
if (!get(featuresStore).syncScroll || !this.chatArea || !this.parserConfig) {
return;
}
if (this.autoRetryTimer || this.isBinding) {
return;
}
if (this.autoRetryCount >= MAX_AUTO_RETRY_COUNT) {
this.updateStatus("error", `滚动监听自动重试失败,已达 ${MAX_AUTO_RETRY_COUNT} 次上限`);
pushPanelNotice(`滚动监听自动重试失败:${message}`, "error");
return;
}
this.autoRetryCount += 1;
this.autoRetryTimer = setTimeout(async () => {
this.autoRetryTimer = null;
const isBound = await this.bindScrollListenerWithRetry(
`auto-retry-${this.autoRetryCount}`,
true,
true
);
if (!isBound && this.autoRetryCount >= MAX_AUTO_RETRY_COUNT) {
this.updateStatus("error", `滚动监听自动重试失败,已达 ${MAX_AUTO_RETRY_COUNT} 次上限`);
pushPanelNotice(`滚动监听自动重试失败:${message}`, "error");
}
}, BIND_RETRY_DELAY);
}
clearAutoRetryTimer() {
if (this.autoRetryTimer) {
clearTimeout(this.autoRetryTimer);
this.autoRetryTimer = null;
}
}
clearPostRefreshCheckTimer() {
if (this.postRefreshCheckTimer) {
clearTimeout(this.postRefreshCheckTimer);
this.postRefreshCheckTimer = null;
}
}
async performPostRefreshCheck() {
if (!get(featuresStore).syncScroll) {
return;
}
if (!this.chatArea || !this.parserConfig) {
this.updateStatus("warning", "等待聊天区域初始化完成");
return;
}
if (!this.isOutlineReady()) {
this.updateStatus("syncing", "等待大纲初始化完成");
return;
}
this.rebuildScrollAnchors();
this.observeVisibleMessages();
if (this.needsRebind()) {
this.updateStatus("syncing", "大纲已刷新,正在校正滚动监听绑定");
await this.bindScrollListenerWithRetry("post-refresh", true, false);
return;
}
this.syncOutlineScroll();
}
isOutlineReady() {
if (!this.outlineContainer) {
return false;
}
if (messageCacheManager.getCache().length === 0) {
return false;
}
return messageCacheManager.getCache().some((item) => Boolean(item.outlineElement));
}
needsRebind() {
return !this.scrollContainer || !this.scrollHandler || this.isBinding;
}
triggerInitialSync() {
if (!this.outlineContainer || !this.scrollContainer || !this.scrollHandler) {
return;
}
setTimeout(() => {
if (!this.outlineContainer || !this.scrollContainer || !this.scrollHandler) {
return;
}
this.syncOutlineScroll();
}, 0);
}
rebuildScrollAnchors() {
if (!this.scrollContainer) {
this.scrollAnchors = [];
this.anchorOffsetsDirty = true;
return;
}
const nextAnchors = [];
for (const cachedItem of messageCacheManager.getCache()) {
if (cachedItem.outlineElement) {
nextAnchors.push({
id: cachedItem.outlineItem.id,
type: "message",
targetElement: cachedItem.outlineItem.element,
outlineElement: cachedItem.outlineElement,
topOffset: 0,
depth: 0
});
}
if (cachedItem.outlineItem.headers) {
this.appendHeaderAnchors(cachedItem.outlineItem.headers, nextAnchors);
}
}
this.scrollAnchors = nextAnchors;
this.anchorOffsetsDirty = true;
this.refreshAnchorOffsets();
}
refreshAnchorOffsets() {
if (!this.scrollContainer || this.scrollAnchors.length === 0 || !this.anchorOffsetsDirty) {
return;
}
const containerRect = this.scrollContainer.getBoundingClientRect();
const scrollTop = this.getScrollTop();
for (const anchor of this.scrollAnchors) {
const rect = anchor.targetElement.getBoundingClientRect();
anchor.topOffset = rect.top - containerRect.top + scrollTop;
}
this.scrollAnchors.sort((left, right) => {
if (left.topOffset !== right.topOffset) {
return left.topOffset - right.topOffset;
}
if (left.depth !== right.depth) {
return left.depth - right.depth;
}
return left.type === right.type ? 0 : left.type === "message" ? -1 : 1;
});
this.anchorOffsetsDirty = false;
}
appendHeaderAnchors(headers, anchors) {
for (const header of headers) {
const outlineElement = this.headerOutlineElements.get(header.id);
if (outlineElement) {
anchors.push({
id: header.id,
type: "header",
targetElement: header.element,
outlineElement,
topOffset: 0,
depth: header.level
});
}
if (header.children.length > 0) {
this.appendHeaderAnchors(header.children, anchors);
}
}
}
observeVisibleMessages() {
if (!this.scrollContainer || typeof IntersectionObserver === "undefined") {
return;
}
this.disconnectIntersectionObserver();
this.visibleMessageMetrics.clear();
const cache = messageCacheManager.getCache();
if (cache.length === 0) {
return;
}
this.intersectionObserver = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
const messageId = entry.target.getAttribute("cbe-message-id");
if (!messageId) {
continue;
}
if (!entry.isIntersecting) {
this.visibleMessageMetrics.delete(messageId);
continue;
}
this.visibleMessageMetrics.set(messageId, {
top: entry.boundingClientRect.top,
bottom: entry.boundingClientRect.bottom
});
}
},
{
root: this.scrollContainer,
threshold: [0, 0.1, 0.5],
rootMargin: "0px 0px -60% 0px"
}
);
for (const item of cache) {
this.intersectionObserver.observe(item.outlineItem.element);
}
}
disconnectIntersectionObserver() {
if (this.intersectionObserver) {
this.intersectionObserver.disconnect();
this.intersectionObserver = null;
}
this.visibleMessageMetrics.clear();
}
unbindScrollListener() {
if (this.scrollHandler && this.scrollContainer) {
this.scrollContainer.removeEventListener("scroll", this.scrollHandler);
logger$1.debug("解绑滚动监听");
}
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
this.debounceTimer = null;
}
if (this.rebuildScrollAnchorsTimer) {
clearTimeout(this.rebuildScrollAnchorsTimer);
this.rebuildScrollAnchorsTimer = null;
}
this.scrollHandler = null;
}
findVisibleMessageIndex() {
const observedIndex = this.findVisibleMessageIndexFromObserver();
if (observedIndex !== -1) {
this.lastVisibleIndex = observedIndex;
return observedIndex;
}
if (!this.scrollContainer) {
return -1;
}
const containerTop = this.scrollContainer.getBoundingClientRect().top + 10;
const cache = messageCacheManager.getCache();
if (cache.length === 0) {
this.lastVisibleIndex = -1;
return -1;
}
const nearIndex = this.findVisibleMessageIndexNear(cache, containerTop);
if (nearIndex !== -1) {
this.lastVisibleIndex = nearIndex;
return nearIndex;
}
const fallbackIndex = this.findVisibleMessageIndexFull(cache, containerTop);
this.lastVisibleIndex = fallbackIndex;
return fallbackIndex;
}
findActiveAnchor() {
if (!this.scrollContainer || this.scrollAnchors.length === 0) {
return null;
}
this.refreshAnchorOffsets();
const currentTop = this.getScrollTop() + Math.max(24, this.getContainerClientHeight() * 0.18);
let left = 0;
let right = this.scrollAnchors.length - 1;
let answer = -1;
while (left <= right) {
const middle = Math.floor((left + right) / 2);
if (this.scrollAnchors[middle].topOffset <= currentTop) {
answer = middle;
left = middle + 1;
} else {
right = middle - 1;
}
}
if (answer === -1) {
return this.scrollAnchors[0] || null;
}
return this.refineActiveAnchor(answer, currentTop);
}
refineActiveAnchor(index2, currentTop) {
let bestAnchor = this.scrollAnchors[index2] || null;
if (!bestAnchor) {
return null;
}
const tolerance = 36;
for (let current = index2 + 1; current < this.scrollAnchors.length; current++) {
const candidate = this.scrollAnchors[current];
if (candidate.topOffset > currentTop + tolerance) {
break;
}
if (candidate.type === "header" && candidate.depth >= bestAnchor.depth) {
bestAnchor = candidate;
}
}
return bestAnchor;
}
findVisibleMessageIndexFromObserver() {
if (!this.scrollContainer || this.visibleMessageMetrics.size === 0) {
return -1;
}
const rootTop = this.scrollContainer.getBoundingClientRect().top + 10;
let targetMessageId = null;
let targetTop = Number.POSITIVE_INFINITY;
for (const [messageId, metrics] of this.visibleMessageMetrics.entries()) {
if (metrics.bottom <= rootTop) {
continue;
}
if (metrics.top < targetTop) {
targetTop = metrics.top;
targetMessageId = messageId;
}
}
return messageCacheManager.getCacheIndexByMessageId(targetMessageId);
}
findVisibleMessageIndexNear(cache, containerTop) {
if (this.lastVisibleIndex < 0 || this.lastVisibleIndex >= cache.length) {
return -1;
}
const maxOffset = 5;
const start = Math.max(0, this.lastVisibleIndex - maxOffset);
const end = Math.min(cache.length - 1, this.lastVisibleIndex + maxOffset);
for (let index2 = start; index2 <= end; index2++) {
const rect = cache[index2].outlineItem.element.getBoundingClientRect();
if (rect.top >= containerTop || rect.bottom > containerTop) {
return index2;
}
}
return -1;
}
findVisibleMessageIndexFull(cache, containerTop) {
for (let index2 = 0; index2 < cache.length; index2++) {
const rect = cache[index2].outlineItem.element.getBoundingClientRect();
if (rect.top >= containerTop || rect.bottom > containerTop) {
return index2;
}
}
return -1;
}
scrollToOutlineItem(index2) {
const outlineElement = messageCacheManager.getOutlineElementByIndex(index2);
if (!outlineElement || !this.outlineContainer) {
return;
}
if (this.lastHighlightElement === outlineElement) {
this.updateStatus("ready", `滚动监听已成功绑定,最近同步到第 ${index2 + 1} 条消息`);
return;
}
logger$1.debug("scroll to ", outlineElement);
this.isSyncing = true;
this.updateStatus("syncing", `滚动监听已触发,正在同步第 ${index2 + 1} 条消息`);
this.applyOutlineFocus(outlineElement);
setTimeout(() => {
this.isSyncing = false;
this.updateStatus("ready", `滚动监听已成功绑定,最近同步到第 ${index2 + 1} 条消息`);
}, 300);
}
scrollToOutlineAnchor(anchor) {
if (this.lastHighlightElement === anchor.outlineElement) {
this.updateStatus("ready", `滚动监听已成功绑定,最近同步到${anchor.type === "header" ? "标题" : "消息"}锚点`);
return;
}
this.isSyncing = true;
this.updateStatus("syncing", `滚动监听已触发,正在同步到${anchor.type === "header" ? "标题" : "消息"}锚点`);
this.applyOutlineFocus(anchor.outlineElement);
setTimeout(() => {
this.isSyncing = false;
this.updateStatus("ready", `滚动监听已成功绑定,最近同步到${anchor.type === "header" ? "标题" : "消息"}锚点`);
}, 300);
}
applyOutlineFocus(outlineElement) {
this.lastHighlightElement = outlineElement;
if (this.highlightTimer) {
clearTimeout(this.highlightTimer);
}
if (this.currentHighlightedElement) {
this.currentHighlightedElement.classList.remove("outline-active");
}
outlineElement.classList.add("outline-active");
this.currentHighlightedElement = outlineElement;
this.highlightTimer = setTimeout(() => {
if (this.currentHighlightedElement) {
this.currentHighlightedElement.classList.remove("outline-active");
this.currentHighlightedElement = null;
}
}, 1e3);
outlineElement.scrollIntoView({ behavior: "smooth", block: "center" });
}
getScrollTop() {
return this.scrollContainer?.scrollTop || 0;
}
getContainerClientHeight() {
return this.scrollContainer?.clientHeight || 0;
}
updateStatus(state2, message) {
setServiceStatus("scrollSync", {
state: state2,
message
});
}
}
const scrollSyncService = new ScrollSyncService();
var root_2$5 = from_html(`<span class="bookmark-indicator svelte-2xi3vq">🔖</span>`);
var root_3$3 = from_html(`<button class="toggle-btn svelte-2xi3vq"> </button>`);
var root_1$8 = from_html(`<div class="tree-node-wrapper"><div role="button" tabindex="0"><span class="node-text svelte-2xi3vq"><!> </span> <!></div> <!></div>`);
var root$7 = from_html(`<div class="tree-container svelte-2xi3vq"></div>`);
function HeaderTree_1($$anchor, $$props) {
push($$props, true);
let depth = prop($$props, "depth", 3, 0), allExpanded = prop($$props, "allExpanded", 3, true), parentMessageIndex = prop($$props, "parentMessageIndex", 3, 0), parentMessageText = prop($$props, "parentMessageText", 3, ""), parentMessageHash = prop($$props, "parentMessageHash", 3, ""), currentPath = prop($$props, "currentPath", 3, ""), headerBookmarks = prop($$props, "headerBookmarks", 19, () => new Set());
let expandedStates = proxy({});
user_effect(() => {
if (allExpanded() !== void 0) {
$$props.nodes.forEach((node) => {
if (expandedStates[node.id] !== allExpanded()) {
expandedStates[node.id] = allExpanded();
}
});
}
});
function toggleExpand(nodeId, e) {
e.stopPropagation();
expandedStates[nodeId] = !expandedStates[nodeId];
}
function scrollToElement(element, e) {
e.stopPropagation();
scrollSyncService.focusOutlineElement(e.currentTarget);
element.scrollIntoView({ behavior: "smooth", block: "start" });
highlightElement(element);
}
function handleContextMenu(e, node, nodePath) {
e.preventDefault();
if ($$props.onContextMenu) {
$$props.onContextMenu(e, {
outlineItemType: "header",
messageIndex: parentMessageIndex(),
messageText: parentMessageText(),
messageHash: parentMessageHash(),
headerPath: nodePath,
headerText: node.text
});
}
}
function registerNode(element, nodeId) {
scrollSyncService.registerHeaderOutlineElement(nodeId, element);
return {
destroy() {
scrollSyncService.unregisterHeaderOutlineElement(nodeId);
}
};
}
function hasHeaderBookmark(nodePath) {
return headerBookmarks().has(nodePath);
}
function buildChildPath(index2) {
if (currentPath()) {
return `${currentPath()}.${index2}`;
}
return `${index2}`;
}
var div = root$7();
each(div, 21, () => $$props.nodes, index, ($$anchor2, node, index2) => {
const nodePath = user_derived(() => buildChildPath(index2));
var div_1 = root_1$8();
var div_2 = child(div_1);
let classes;
var span = child(div_2);
var node_1 = child(span);
{
var consequent = ($$anchor3) => {
var span_1 = root_2$5();
append($$anchor3, span_1);
};
var d = user_derived(() => hasHeaderBookmark(get$1(nodePath)));
if_block(node_1, ($$render) => {
if (get$1(d)) $$render(consequent);
});
}
var text2 = sibling(node_1);
var node_2 = sibling(span, 2);
{
var consequent_1 = ($$anchor3) => {
var button = root_3$3();
var text_1 = child(button);
template_effect(() => {
set_attribute(button, "aria-label", expandedStates[get$1(node).id] ? "收起" : "展开");
set_text(text_1, expandedStates[get$1(node).id] ? "▼" : "▶");
});
delegated("click", button, (e) => toggleExpand(get$1(node).id, e));
append($$anchor3, button);
};
if_block(node_2, ($$render) => {
if (get$1(node).children.length > 0) $$render(consequent_1);
});
}
action(div_2, ($$node, $$action_arg) => registerNode?.($$node, $$action_arg), () => get$1(node).id);
var node_3 = sibling(div_2, 2);
{
var consequent_2 = ($$anchor3) => {
{
let $0 = user_derived(() => depth() + 1);
HeaderTree_1($$anchor3, {
get nodes() {
return get$1(node).children;
},
get depth() {
return get$1($0);
},
get allExpanded() {
return allExpanded();
},
get onContextMenu() {
return $$props.onContextMenu;
},
get parentMessageIndex() {
return parentMessageIndex();
},
get parentMessageText() {
return parentMessageText();
},
get parentMessageHash() {
return parentMessageHash();
},
get currentPath() {
return get$1(nodePath);
},
get headerBookmarks() {
return headerBookmarks();
}
});
}
};
if_block(node_3, ($$render) => {
if (get$1(node).children.length > 0 && expandedStates[get$1(node).id]) $$render(consequent_2);
});
}
template_effect(
($0) => {
classes = set_class(div_2, 1, `tree-node header-level-${get$1(node).level ?? ""}`, "svelte-2xi3vq", classes, $0);
set_text(text2, ` ${get$1(node).text ?? ""}`);
},
[
() => ({ "has-bookmark": hasHeaderBookmark(get$1(nodePath)) })
]
);
delegated("click", div_2, (e) => scrollToElement(get$1(node).element, e));
delegated("contextmenu", div_2, (e) => handleContextMenu(e, get$1(node), get$1(nodePath)));
delegated("keydown", div_2, (e) => e.key === "Enter" && scrollToElement(get$1(node).element, e));
append($$anchor2, div_1);
});
template_effect(() => set_style(div, `margin-left: ${depth() * 15}px;`));
append($$anchor, div);
pop();
}
delegate(["click", "contextmenu", "keydown"]);
var root_2$4 = from_html(`<span class="bookmark-indicator svelte-1iqb61w">🔖</span>`);
var root_1$7 = from_html(`<div role="button" tabindex="0"><!> </div>`);
var root_5 = from_html(`<span class="bookmark-indicator svelte-1iqb61w">🔖</span>`);
var root_6 = from_html(`<div class="outline-ai-content svelte-1iqb61w"><!></div>`);
var root_4$1 = from_html(`<div class="outline-ai-container svelte-1iqb61w"><div role="button" tabindex="0"><span class="header-text svelte-1iqb61w"><!> </span> <button class="toggle-btn svelte-1iqb61w"> </button></div> <!></div>`);
var root_8 = from_html(`<span class="bookmark-indicator svelte-1iqb61w">🔖</span>`);
var root_7 = from_html(`<div role="button" tabindex="0"><!> </div>`);
function OutlineItem($$anchor, $$props) {
push($$props, true);
let allExpanded = prop($$props, "allExpanded", 3, true), hasBookmark = prop($$props, "hasBookmark", 3, false), headerBookmarks = prop($$props, "headerBookmarks", 19, () => new Set());
let isExpanded = state(true);
let containerElement = state(void 0);
function scrollToElement() {
scrollSyncService.focusOutlineElement(get$1(containerElement));
$$props.item.element.scrollIntoView({ behavior: "smooth", block: "start" });
highlightElement($$props.item.element);
}
function handleKeydown(e) {
if (e.key === "Enter") {
scrollToElement();
}
}
function toggleExpand(e) {
e.stopPropagation();
set(isExpanded, !get$1(isExpanded));
}
function handleContextMenu(e) {
e.preventDefault();
if ($$props.onContextMenu) {
const hash = buildMessageHash($$props.item.index, $$props.item.searchText);
$$props.onContextMenu(e, {
outlineItemType: "message",
messageIndex: $$props.item.index,
messageText: $$props.item.searchText,
messageHash: hash
});
}
}
user_effect(() => {
set(isExpanded, allExpanded());
});
user_effect(() => {
if (get$1(containerElement) && $$props.item.id) {
messageCacheManager.updateOutlineElement($$props.item.id, get$1(containerElement));
scrollSyncService.scheduleRebuildScrollAnchors();
}
});
var fragment = comment();
var node = first_child(fragment);
{
var consequent_1 = ($$anchor2) => {
var div = root_1$7();
let classes;
var node_1 = child(div);
{
var consequent = ($$anchor3) => {
var span = root_2$4();
append($$anchor3, span);
};
if_block(node_1, ($$render) => {
if (hasBookmark()) $$render(consequent);
});
}
var text2 = sibling(node_1);
bind_this(div, ($$value) => set(containerElement, $$value), () => get$1(containerElement));
template_effect(() => {
classes = set_class(div, 1, "outline-user-item svelte-1iqb61w", null, classes, { "has-bookmark": hasBookmark() });
set_text(text2, ` 👤 ${$$props.item.index + 1}. ${$$props.item.text ?? ""}`);
});
delegated("click", div, scrollToElement);
delegated("keydown", div, handleKeydown);
delegated("contextmenu", div, handleContextMenu);
append($$anchor2, div);
};
var consequent_6 = ($$anchor2) => {
var fragment_1 = comment();
var node_2 = first_child(fragment_1);
{
var consequent_4 = ($$anchor3) => {
var div_1 = root_4$1();
var div_2 = child(div_1);
let classes_1;
var span_1 = child(div_2);
var node_3 = child(span_1);
{
var consequent_2 = ($$anchor4) => {
var span_2 = root_5();
append($$anchor4, span_2);
};
if_block(node_3, ($$render) => {
if (hasBookmark()) $$render(consequent_2);
});
}
var text_1 = sibling(node_3);
var button = sibling(span_1, 2);
var text_2 = child(button);
var node_4 = sibling(div_2, 2);
{
var consequent_3 = ($$anchor4) => {
var div_3 = root_6();
var node_5 = child(div_3);
{
let $0 = user_derived(() => buildMessageHash($$props.item.index, $$props.item.searchText));
HeaderTree_1(node_5, {
get nodes() {
return $$props.item.headers;
},
get allExpanded() {
return allExpanded();
},
get onContextMenu() {
return $$props.onContextMenu;
},
get parentMessageIndex() {
return $$props.item.index;
},
get parentMessageText() {
return $$props.item.searchText;
},
get parentMessageHash() {
return get$1($0);
},
get headerBookmarks() {
return headerBookmarks();
}
});
}
append($$anchor4, div_3);
};
if_block(node_4, ($$render) => {
if (get$1(isExpanded)) $$render(consequent_3);
});
}
bind_this(div_1, ($$value) => set(containerElement, $$value), () => get$1(containerElement));
template_effect(() => {
classes_1 = set_class(div_2, 1, "outline-ai-header svelte-1iqb61w", null, classes_1, { "has-bookmark": hasBookmark() });
set_text(text_1, ` 🤖 ${$$props.item.index + 1}. ${$$props.item.text ?? ""}`);
set_attribute(button, "aria-label", get$1(isExpanded) ? "收起" : "展开");
set_text(text_2, get$1(isExpanded) ? "▼" : "▶");
});
delegated("click", div_2, scrollToElement);
delegated("keydown", div_2, handleKeydown);
delegated("contextmenu", div_2, handleContextMenu);
delegated("click", button, toggleExpand);
append($$anchor3, div_1);
};
var alternate = ($$anchor3) => {
var div_4 = root_7();
let classes_2;
var node_6 = child(div_4);
{
var consequent_5 = ($$anchor4) => {
var span_3 = root_8();
append($$anchor4, span_3);
};
if_block(node_6, ($$render) => {
if (hasBookmark()) $$render(consequent_5);
});
}
var text_3 = sibling(node_6);
bind_this(div_4, ($$value) => set(containerElement, $$value), () => get$1(containerElement));
template_effect(() => {
classes_2 = set_class(div_4, 1, "outline-ai-item svelte-1iqb61w", null, classes_2, { "has-bookmark": hasBookmark() });
set_text(text_3, ` 🤖 ${$$props.item.index ?? ""}. ${$$props.item.text ?? ""}`);
});
delegated("click", div_4, scrollToElement);
delegated("keydown", div_4, handleKeydown);
delegated("contextmenu", div_4, handleContextMenu);
append($$anchor3, div_4);
};
if_block(node_2, ($$render) => {
if ($$props.item.headers && $$props.item.headers.length > 0) $$render(consequent_4);
else $$render(alternate, false);
});
}
append($$anchor2, fragment_1);
};
if_block(node, ($$render) => {
if ($$props.item.type === MessageOwner.User) $$render(consequent_1);
else if ($$props.item.type === MessageOwner.Assistant) $$render(consequent_6, 1);
});
}
append($$anchor, fragment);
pop();
}
delegate(["click", "keydown", "contextmenu"]);
var root$6 = from_html(`<div class="outline-content svelte-13g9af" id="outline-content"></div>`);
function OutlineList($$anchor, $$props) {
push($$props, true);
const $bookmarksStore = () => store_get(bookmarksStore, "$bookmarksStore", $$stores);
const [$$stores, $$cleanup] = setup_stores();
let filterText = prop($$props, "filterText", 3, ""), useRegex = prop($$props, "useRegex", 3, false);
let items = state(proxy([]));
let allExpanded = state(true);
let outlineContainer;
let messageBookmarks = state(proxy( new Set()));
let headerBookmarks = state(proxy( new Map()));
user_effect(() => {
const storeData = $bookmarksStore();
const conversationId = getConversationId();
const convData = conversationId ? storeData[conversationId] : void 0;
const bookmarks = convData?.bookmarks || [];
const msgBookmarks = new Set();
const hdrBookmarks = new Map();
for (const bookmark of bookmarks) {
if (bookmark.outlineItemType === "message") {
msgBookmarks.add(bookmark.messageIndex);
} else if (bookmark.outlineItemType === "header" && bookmark.headerPath) {
let headerSet = hdrBookmarks.get(bookmark.messageIndex);
if (!headerSet) {
headerSet = new Set();
hdrBookmarks.set(bookmark.messageIndex, headerSet);
}
headerSet.add(bookmark.headerPath);
}
}
set(messageBookmarks, msgBookmarks, true);
set(headerBookmarks, hdrBookmarks, true);
});
function filterItems(items2, filter, regex) {
if (!filter) return items2;
if (regex) {
try {
const reg = new RegExp(filter, "i");
return items2.filter((item) => reg.test(item.searchText));
} catch {
return items2;
}
}
return items2.filter((item) => {
return item.searchText.toLocaleLowerCase().includes(filter.toLocaleLowerCase());
});
}
let showItems = user_derived(() => {
return filterItems(get$1(items), filterText(), useRegex());
});
onMount(() => {
const unsubscribeOutline = outlineStore.subscribe((value) => {
set(items, value, true);
});
const unsubscribeAllExpanded = allExpandedStore.subscribe((value) => {
set(allExpanded, value, true);
});
set(items, get(outlineStore), true);
set(allExpanded, get(allExpandedStore), true);
if (outlineContainer) {
scrollSyncService.setOutlineContainer(outlineContainer);
}
return () => {
unsubscribeOutline();
unsubscribeAllExpanded();
};
});
var div = root$6();
each(div, 21, () => get$1(showItems), (item) => item.id, ($$anchor2, item) => {
{
let $0 = user_derived(() => get$1(messageBookmarks).has(get$1(item).index));
let $1 = user_derived(() => get$1(headerBookmarks).get(get$1(item).index) || new Set());
OutlineItem($$anchor2, {
get item() {
return get$1(item);
},
get allExpanded() {
return get$1(allExpanded);
},
get onContextMenu() {
return $$props.onContextMenu;
},
get hasBookmark() {
return get$1($0);
},
get headerBookmarks() {
return get$1($1);
}
});
}
});
bind_this(div, ($$value) => outlineContainer = $$value, () => outlineContainer);
append($$anchor, div);
pop();
$$cleanup();
}
var root$5 = from_html(`<button id="show-outline-btn">📋</button>`);
function DraggableToggleButton($$anchor, $$props) {
push($$props, true);
let title = prop($$props, "title", 3, "显示对话大纲"), ariaLabel = prop($$props, "ariaLabel", 3, "显示对话大纲");
const STORAGE_KEY2 = "chat_outline_button_position";
const BUTTON_SIZE = 40;
let positionY = state(
50
);
let isDragging = state(false);
let dragStartY = state(0);
let initialPositionY = state(0);
function loadPosition() {
try {
const saved = localStorage.getItem(STORAGE_KEY2);
if (saved) {
const parsed = JSON.parse(saved);
if (typeof parsed.y === "number") {
set(positionY, Math.max(0, Math.min(100, parsed.y)), true);
}
}
} catch (e) {
logger$1.warn("Failed to load button position:", e);
}
}
function savePosition() {
try {
localStorage.setItem(STORAGE_KEY2, JSON.stringify({ y: get$1(positionY) }));
} catch (e) {
logger$1.warn("Failed to save button position:", e);
}
}
function handleMouseDown(event2) {
set(isDragging, true);
set(dragStartY, event2.clientY, true);
set(initialPositionY, get$1(positionY), true);
window.addEventListener("mousemove", handleMouseMove);
window.addEventListener("mouseup", handleMouseUp);
event2.preventDefault();
}
function handleTouchStart(event2) {
set(isDragging, true);
set(dragStartY, event2.touches[0].clientY, true);
set(initialPositionY, get$1(positionY), true);
window.addEventListener("touchmove", handleTouchMove, { passive: false });
window.addEventListener("touchend", handleTouchEnd);
event2.preventDefault();
}
function handleMouseMove(event2) {
if (!get$1(isDragging)) return;
updatePosition(event2.clientY);
}
function handleTouchMove(event2) {
if (!get$1(isDragging)) return;
updatePosition(event2.touches[0].clientY);
event2.preventDefault();
}
function updatePosition(clientY) {
const deltaY = clientY - get$1(dragStartY);
const viewportHeight = window.innerHeight;
const deltaPercent = deltaY / viewportHeight * 100;
let newPosition = get$1(initialPositionY) + deltaPercent;
const minPosition = BUTTON_SIZE / 2 / viewportHeight * 100;
const maxPosition = 100 - BUTTON_SIZE / 2 / viewportHeight * 100;
set(positionY, Math.max(minPosition, Math.min(maxPosition, newPosition)), true);
}
function handleMouseUp() {
if (get$1(isDragging)) {
set(isDragging, false);
savePosition();
cleanupListeners();
}
}
function handleTouchEnd() {
if (get$1(isDragging)) {
set(isDragging, false);
savePosition();
cleanupListeners();
}
}
function cleanupListeners() {
window.removeEventListener("mousemove", handleMouseMove);
window.removeEventListener("mouseup", handleMouseUp);
window.removeEventListener("touchmove", handleTouchMove);
window.removeEventListener("touchend", handleTouchEnd);
}
let dragThreshold = 5;
let hasDragged = state(false);
function handleClick() {
if (!get$1(hasDragged)) {
$$props.onClick();
}
}
user_effect(() => {
if (get$1(isDragging)) {
set(hasDragged, false);
}
});
user_effect(() => {
if (get$1(isDragging) && Math.abs(get$1(positionY) - get$1(initialPositionY)) > dragThreshold) {
set(hasDragged, true);
}
});
function handleResize() {
const viewportHeight = window.innerHeight;
const minPosition = BUTTON_SIZE / 2 / viewportHeight * 100;
const maxPosition = 100 - BUTTON_SIZE / 2 / viewportHeight * 100;
if (get$1(positionY) < minPosition) {
set(positionY, minPosition);
savePosition();
} else if (get$1(positionY) > maxPosition) {
set(positionY, maxPosition);
savePosition();
}
}
onMount(() => {
loadPosition();
window.addEventListener("resize", handleResize);
});
onDestroy(() => {
cleanupListeners();
window.removeEventListener("resize", handleResize);
});
var button = root$5();
let classes;
template_effect(() => {
classes = set_class(button, 1, "draggable-toggle-button svelte-nihy1m", null, classes, { "is-dragging": get$1(isDragging) });
set_style(button, `top: ${get$1(positionY) ?? ""}%; transform: translateY(-50%)`);
set_attribute(button, "title", title());
set_attribute(button, "aria-label", ariaLabel());
});
delegated("click", button, handleClick);
delegated("mousedown", button, handleMouseDown);
delegated("touchstart", button, handleTouchStart);
append($$anchor, button);
pop();
}
delegate(["click", "mousedown", "touchstart"]);
var root_2$3 = from_html(`<div role="status" aria-live="polite"><span class="notice-text svelte-1xjbolr"> </span> <button class="notice-close svelte-1xjbolr" type="button" aria-label="关闭提示">×</button></div>`);
var root_1$6 = from_html(`<div class="panel-notice-stack svelte-1xjbolr"></div>`);
function PanelNoticeStack($$anchor, $$props) {
push($$props, true);
let notices = state(proxy([]));
const classMap = {
info: "notice-info",
success: "notice-success",
warning: "notice-warning",
error: "notice-error"
};
onMount(() => {
const unsubscribe = panelNoticeStore.subscribe((value) => {
set(notices, value, true);
});
set(notices, get(panelNoticeStore), true);
return () => {
unsubscribe();
};
});
var fragment = comment();
var node = first_child(fragment);
{
var consequent = ($$anchor2) => {
var div = root_1$6();
each(div, 21, () => get$1(notices), (notice) => notice.id, ($$anchor3, notice) => {
var div_1 = root_2$3();
var span = child(div_1);
var text2 = child(span);
var button = sibling(span, 2);
template_effect(() => {
set_class(div_1, 1, `panel-notice ${classMap[get$1(notice).level]}`, "svelte-1xjbolr");
set_text(text2, get$1(notice).message);
});
delegated("click", button, () => removePanelNotice(get$1(notice).id));
append($$anchor3, div_1);
});
append($$anchor2, div);
};
if_block(node, ($$render) => {
if (get$1(notices).length > 0) $$render(consequent);
});
}
append($$anchor, fragment);
pop();
}
delegate(["click"]);
var root_1$5 = from_html(`<button class="status-dot-button svelte-5fnl0z" type="button"><span class="status-light svelte-5fnl0z"></span></button>`);
var root$4 = from_html(`<div class="service-status-bar svelte-5fnl0z" aria-label="服务状态栏"></div>`);
function ServiceStatusBar($$anchor, $$props) {
push($$props, true);
let items = state(proxy([]));
const colorMap = {
idle: "#94a3b8",
ready: "#22c55e",
warning: "#f59e0b",
error: "#ef4444",
syncing: "#3b82f6"
};
onMount(() => {
const unsubscribe = serviceStatusStore.subscribe((status) => {
set(items, [status.outlineRuntime, status.scrollSync], true);
});
const current = get(serviceStatusStore);
set(items, [current.outlineRuntime, current.scrollSync], true);
return () => {
unsubscribe();
};
});
function getTooltip(item) {
const time = new Date(item.updatedAt).toLocaleTimeString();
return `${item.label}:${item.message}(最近更新 ${time},点击可重新获取并绑定)`;
}
async function handleClick(item) {
if (item.key === "outlineRuntime") {
await outlineRuntimeService.forceRebind();
return;
}
scrollSyncService.forceRebind();
}
var div = root$4();
each(div, 21, () => get$1(items), (item) => item.key, ($$anchor2, item) => {
var button = root_1$5();
var span = child(button);
template_effect(
($0, $1) => {
set_attribute(button, "title", $0);
set_attribute(button, "aria-label", $1);
set_style(span, `--status-color: ${colorMap[get$1(item).state]}`);
},
[() => getTooltip(get$1(item)), () => getTooltip(get$1(item))]
);
delegated("click", button, () => handleClick(get$1(item)));
append($$anchor2, button);
});
append($$anchor, div);
pop();
}
delegate(["click"]);
var root_1$4 = from_html(`<div class="empty-state svelte-1dp0ytt"><span class="empty-icon svelte-1dp0ytt">📚</span> <p class="svelte-1dp0ytt">暂无书签</p> <p class="hint svelte-1dp0ytt">在大纲上右键可添加书签</p></div>`);
var root_3$2 = from_html(`<div class="bookmark-item svelte-1dp0ytt" role="button" tabindex="0"><span class="bookmark-icon svelte-1dp0ytt"><!></span> <span class="bookmark-name svelte-1dp0ytt"> </span> <span class="bookmark-meta svelte-1dp0ytt"> </span></div>`);
var root_2$2 = from_html(`<div class="bookmark-list svelte-1dp0ytt"></div>`);
function BookmarkList($$anchor, $$props) {
push($$props, true);
function formatDate(timestamp) {
const date = new Date(timestamp);
const now = new Date();
const diffMs = now.getTime() - date.getTime();
const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
if (diffDays === 0) {
return date.toLocaleTimeString("zh-CN", { hour: "2-digit", minute: "2-digit" });
} else if (diffDays === 1) {
return "昨天";
} else if (diffDays < 7) {
return `${diffDays}天前`;
} else {
return date.toLocaleDateString("zh-CN", { month: "short", day: "numeric" });
}
}
function handleClick(bookmark) {
$$props.onNavigate?.(bookmark, $$props.conversationId);
}
function handleContextMenu(e, bookmark) {
e.preventDefault();
$$props.onContextMenu?.(e, bookmark, $$props.conversationId);
}
function handleKeydown(e, bookmark) {
if (e.key === "Enter") {
handleClick(bookmark);
}
}
var fragment = comment();
var node = first_child(fragment);
{
var consequent = ($$anchor2) => {
var div = root_1$4();
append($$anchor2, div);
};
var alternate_1 = ($$anchor2) => {
var div_1 = root_2$2();
each(div_1, 21, () => $$props.bookmarks, (bookmark) => bookmark.id, ($$anchor3, bookmark) => {
var div_2 = root_3$2();
var span = child(div_2);
var node_1 = child(span);
{
var consequent_1 = ($$anchor4) => {
var text$1 = text("📑");
append($$anchor4, text$1);
};
var alternate = ($$anchor4) => {
var text_1 = text("🔖");
append($$anchor4, text_1);
};
if_block(node_1, ($$render) => {
if (get$1(bookmark).outlineItemType === "header") $$render(consequent_1);
else $$render(alternate, false);
});
}
var span_1 = sibling(span, 2);
var text_2 = child(span_1);
var span_2 = sibling(span_1, 2);
var text_3 = child(span_2);
template_effect(
($0) => {
set_text(text_2, get$1(bookmark).name);
set_text(text_3, `#${get$1(bookmark).messageIndex + 1} · ${$0 ?? ""}`);
},
[() => formatDate(get$1(bookmark).createdAt)]
);
delegated("click", div_2, () => handleClick(get$1(bookmark)));
delegated("contextmenu", div_2, (e) => handleContextMenu(e, get$1(bookmark)));
delegated("keydown", div_2, (e) => handleKeydown(e, get$1(bookmark)));
append($$anchor3, div_2);
});
append($$anchor2, div_1);
};
if_block(node, ($$render) => {
if ($$props.bookmarks.length === 0) $$render(consequent);
else $$render(alternate_1, false);
});
}
append($$anchor, fragment);
pop();
}
delegate(["click", "contextmenu", "keydown"]);
const contextMenuState = writable({
visible: false,
x: 0,
y: 0,
items: [],
context: null,
bookmark: null,
conversationId: null
});
const addBookmarkModalState = writable({
visible: false,
context: null
});
const renameBookmarkModalState = writable({
visible: false,
bookmark: null
});
function showContextMenu(event2, context) {
event2.preventDefault();
event2.stopPropagation();
let hasBookmark = false;
let existingBookmark;
if (context.outlineItemType === "header") {
hasBookmark = bookmarksStore.hasBookmarkForHeader(context.messageIndex, context.headerPath || "");
existingBookmark = bookmarksStore.getBookmarkByHeaderPath(context.messageIndex, context.headerPath || "");
} else {
hasBookmark = bookmarksStore.hasBookmarkForMessageIndex(context.messageIndex);
existingBookmark = bookmarksStore.getBookmarkByMessageIndex(context.messageIndex);
}
const items = [];
if (hasBookmark && existingBookmark) {
items.push({
id: "delete",
label: "删除书签",
icon: "🗑️",
danger: true
});
items.push({
id: "rename",
label: "重命名",
icon: "✏️"
});
} else {
items.push({
id: "add",
label: "添加书签",
icon: "🔖"
});
}
contextMenuState.set({
visible: true,
x: event2.clientX,
y: event2.clientY,
items,
context,
bookmark: existingBookmark ?? null,
conversationId: getConversationId()
});
}
function showBookmarkContextMenu(event2, bookmark, conversationId) {
event2.preventDefault();
event2.stopPropagation();
const items = [
{
id: "navigate",
label: "跳转到书签",
icon: "📍"
},
{
id: "rename",
label: "重命名",
icon: "✏️"
},
{
id: "delete",
label: "删除书签",
icon: "🗑️",
danger: true
}
];
contextMenuState.set({
visible: true,
x: event2.clientX,
y: event2.clientY,
items,
context: null,
bookmark,
conversationId
});
}
function hideContextMenu() {
contextMenuState.set({
visible: false,
x: 0,
y: 0,
items: [],
context: null,
bookmark: null,
conversationId: null
});
}
function handleMenuSelect(itemId) {
const state2 = get(contextMenuState);
const resultBookmark = state2.bookmark ? state2.bookmark : void 0;
const result = {
action: itemId,
bookmark: resultBookmark,
conversationId: state2.conversationId ?? void 0
};
switch (itemId) {
case "add":
if (state2.context) {
addBookmarkModalState.set({
visible: true,
context: state2.context
});
}
break;
case "delete":
if (state2.bookmark) {
bookmarksStore.removeBookmark(state2.bookmark.id);
} else if (state2.context) {
let bookmark;
if (state2.context.outlineItemType === "header") {
bookmark = bookmarksStore.getBookmarkByHeaderPath(state2.context.messageIndex, state2.context.headerPath || "");
} else {
bookmark = bookmarksStore.getBookmarkByMessageIndex(state2.context.messageIndex);
}
if (bookmark) {
bookmarksStore.removeBookmark(bookmark.id);
}
}
break;
case "rename":
if (state2.bookmark) {
renameBookmarkModalState.set({
visible: true,
bookmark: state2.bookmark
});
} else if (state2.context) {
let bookmark;
if (state2.context.outlineItemType === "header") {
bookmark = bookmarksStore.getBookmarkByHeaderPath(state2.context.messageIndex, state2.context.headerPath || "");
} else {
bookmark = bookmarksStore.getBookmarkByMessageIndex(state2.context.messageIndex);
}
if (bookmark) {
renameBookmarkModalState.set({
visible: true,
bookmark
});
}
}
break;
}
hideContextMenu();
return result;
}
function hideAddBookmarkModal() {
addBookmarkModalState.set({
visible: false,
context: null
});
}
function hideRenameBookmarkModal() {
renameBookmarkModalState.set({
visible: false,
bookmark: null
});
}
function getDefaultNameLength() {
return get(featuresStore).bookmarkGetTextLength || 20;
}
function buildOutlineItemContext(outlineItemType, messageIndex, messageText, messageHash, element, headerPath, headerText) {
return {
outlineItemType,
messageIndex,
messageText,
messageHash,
headerPath,
headerText,
element
};
}
var root_1$3 = from_html(`<div class="empty-state svelte-19r7ywj"><span class="empty-icon svelte-19r7ywj">📚</span> <p class="svelte-19r7ywj">暂无书签</p> <p class="hint svelte-19r7ywj">在大纲上右键可添加书签</p></div>`);
var root_4 = from_html(`<div class="conversation-header svelte-19r7ywj" role="button" tabindex="0"><span class="toggle-icon svelte-19r7ywj"> </span> <span class="conversation-name svelte-19r7ywj"> </span> <span class="conversation-count svelte-19r7ywj"> </span></div>`);
var root_3$1 = from_html(`<div class="conversation-group svelte-19r7ywj"><!> <!></div>`);
var root$3 = from_html(`<div class="bookmark-panel svelte-19r7ywj"><div class="bookmark-toolbar svelte-19r7ywj"><div class="view-toggle svelte-19r7ywj"><button>当前</button> <button>全部</button></div> <input type="text" class="search-input svelte-19r7ywj" placeholder="搜索书签..."/></div> <div class="bookmark-content svelte-19r7ywj"><!></div> <div class="bookmark-footer svelte-19r7ywj"><span class="bookmark-count svelte-19r7ywj"> </span></div></div>`);
function BookmarkPanel($$anchor, $$props) {
push($$props, true);
let viewMode = state("current");
let searchQuery = state("");
let bookmarksData = state(proxy({}));
let collapsedConversations = state(proxy( new Set()));
let currentConversationId = state("");
function getConversationDisplayName(conversationId, convData) {
if (conversationId === get$1(currentConversationId)) {
return "当前会话";
}
if (convData?.name) {
return convData.name;
}
return conversationId.length > 12 ? conversationId.substring(0, 12) + "..." : conversationId;
}
let filteredData = user_derived(() => () => {
const result = [];
if (get$1(viewMode) === "current") {
const convData = get$1(bookmarksData)[get$1(currentConversationId)];
if (convData) {
const filtered = filterBookmarks(convData.bookmarks);
if (filtered.length > 0) {
result.push({
conversationId: get$1(currentConversationId),
convData,
bookmarks: filtered
});
}
}
} else {
for (const [conversationId, convData] of Object.entries(get$1(bookmarksData))) {
const filtered = filterBookmarks(convData.bookmarks);
if (filtered.length > 0) {
result.push({ conversationId, convData, bookmarks: filtered });
}
}
result.sort((a, b) => {
const aLatest = Math.max(...a.bookmarks.map((b2) => b2.createdAt));
const bLatest = Math.max(...b.bookmarks.map((b2) => b2.createdAt));
return bLatest - aLatest;
});
}
return result;
});
function filterBookmarks(bookmarks) {
if (!get$1(searchQuery).trim()) return bookmarks;
const query = get$1(searchQuery).toLowerCase();
return bookmarks.filter((b) => b.name.toLowerCase().includes(query));
}
let totalBookmarks = user_derived(() => () => {
let count = 0;
for (const item of get$1(filteredData)()) {
count += item.bookmarks.length;
}
return count;
});
let unsubscribe = null;
onMount(() => {
set(currentConversationId, getConversationId(), true);
unsubscribe = bookmarksStore.subscribe((data) => {
set(bookmarksData, data, true);
});
return () => {
unsubscribe?.();
};
});
function handleNavigate(bookmark, conversationId) {
$$props.onNavigate?.({ ...bookmark, conversationId });
}
function handleContextMenu(e, bookmark, conversationId) {
showBookmarkContextMenu(e, bookmark, conversationId);
}
function handleSearchInput(e) {
set(searchQuery, e.target.value, true);
}
function toggleConversation(conversationId) {
const newCollapsed = new Set(get$1(collapsedConversations));
if (newCollapsed.has(conversationId)) {
newCollapsed.delete(conversationId);
} else {
newCollapsed.add(conversationId);
}
set(collapsedConversations, newCollapsed, true);
}
function isCollapsed(conversationId) {
return get$1(collapsedConversations).has(conversationId);
}
var div = root$3();
var div_1 = child(div);
var div_2 = child(div_1);
var button = child(div_2);
let classes;
var button_1 = sibling(button, 2);
let classes_1;
var input = sibling(div_2, 2);
var div_3 = sibling(div_1, 2);
var node = child(div_3);
{
var consequent = ($$anchor2) => {
var div_4 = root_1$3();
append($$anchor2, div_4);
};
var d = user_derived(() => get$1(filteredData)().length === 0);
var alternate = ($$anchor2) => {
var fragment = comment();
var node_1 = first_child(fragment);
each(node_1, 17, () => get$1(filteredData)(), (group) => group.conversationId, ($$anchor3, group) => {
var div_5 = root_3$1();
var node_2 = child(div_5);
{
var consequent_1 = ($$anchor4) => {
var div_6 = root_4();
var span = child(div_6);
var text2 = child(span);
var span_1 = sibling(span, 2);
var text_1 = child(span_1);
var span_2 = sibling(span_1, 2);
var text_2 = child(span_2);
template_effect(
($0, $1) => {
set_text(text2, $0);
set_text(text_1, $1);
set_text(text_2, get$1(group).bookmarks.length);
},
[
() => isCollapsed(get$1(group).conversationId) ? "▶" : "▼",
() => getConversationDisplayName(get$1(group).conversationId, get$1(group).convData)
]
);
delegated("click", div_6, () => toggleConversation(get$1(group).conversationId));
delegated("keydown", div_6, (e) => e.key === "Enter" && toggleConversation(get$1(group).conversationId));
append($$anchor4, div_6);
};
if_block(node_2, ($$render) => {
if (get$1(viewMode) === "all") $$render(consequent_1);
});
}
var node_3 = sibling(node_2, 2);
{
var consequent_2 = ($$anchor4) => {
BookmarkList($$anchor4, {
get bookmarks() {
return get$1(group).bookmarks;
},
get conversationId() {
return get$1(group).conversationId;
},
onNavigate: handleNavigate,
onContextMenu: handleContextMenu
});
};
var d_1 = user_derived(() => !isCollapsed(get$1(group).conversationId));
if_block(node_3, ($$render) => {
if (get$1(d_1)) $$render(consequent_2);
});
}
append($$anchor3, div_5);
});
append($$anchor2, fragment);
};
if_block(node, ($$render) => {
if (get$1(d)) $$render(consequent);
else $$render(alternate, false);
});
}
var div_7 = sibling(div_3, 2);
var span_3 = child(div_7);
var text_3 = child(span_3);
template_effect(
($0) => {
classes = set_class(button, 1, "toggle-btn svelte-19r7ywj", null, classes, { active: get$1(viewMode) === "current" });
classes_1 = set_class(button_1, 1, "toggle-btn svelte-19r7ywj", null, classes_1, { active: get$1(viewMode) === "all" });
set_value(input, get$1(searchQuery));
set_text(text_3, `共 ${$0 ?? ""} 个书签`);
},
[() => get$1(totalBookmarks)()]
);
delegated("click", button, () => set(viewMode, "current"));
delegated("click", button_1, () => set(viewMode, "all"));
delegated("input", input, handleSearchInput);
append($$anchor, div);
pop();
}
delegate(["click", "input", "keydown"]);
var root_2$1 = from_html(`<span class="menu-icon svelte-aof35l"> </span>`);
var root_1$2 = from_html(`<button role="menuitem"><!> <span class="menu-label svelte-aof35l"> </span></button>`);
var root$2 = from_html(`<div class="context-menu svelte-aof35l" role="menu"></div>`);
function ContextMenu($$anchor, $$props) {
push($$props, true);
let menuElement = state(void 0);
let adjustedX = user_derived(() => {
if (!get$1(menuElement)) return $$props.x;
const rect = get$1(menuElement).getBoundingClientRect();
const padding = 8;
if (rect.right > window.innerWidth - padding) {
return window.innerWidth - rect.width - padding;
}
return $$props.x;
});
let adjustedY = user_derived(() => {
if (!get$1(menuElement)) return $$props.y;
const rect = get$1(menuElement).getBoundingClientRect();
const padding = 8;
if (rect.bottom > window.innerHeight - padding) {
return window.innerHeight - rect.height - padding;
}
return $$props.y;
});
function handleItemClick(item) {
if (!item.disabled) {
$$props.onSelect(item.id);
$$props.onClose();
}
}
function handleKeydown(e) {
if (e.key === "Escape") {
$$props.onClose();
}
}
onMount(() => {
const handleClickOutside = (e) => {
if (get$1(menuElement) && !get$1(menuElement).contains(e.target)) {
$$props.onClose();
}
};
const timer = setTimeout(
() => {
document.addEventListener("click", handleClickOutside);
document.addEventListener("contextmenu", handleClickOutside);
document.addEventListener("mousedown", handleClickOutside);
},
100
);
return () => {
clearTimeout(timer);
document.removeEventListener("click", handleClickOutside);
document.removeEventListener("contextmenu", handleClickOutside);
document.removeEventListener("mousedown", handleClickOutside);
};
});
var div = root$2();
event("keydown", $window, handleKeydown);
each(div, 21, () => $$props.items, index, ($$anchor2, item) => {
var button = root_1$2();
let classes;
var node = child(button);
{
var consequent = ($$anchor3) => {
var span = root_2$1();
var text2 = child(span);
template_effect(() => set_text(text2, get$1(item).icon));
append($$anchor3, span);
};
if_block(node, ($$render) => {
if (get$1(item).icon) $$render(consequent);
});
}
var span_1 = sibling(node, 2);
var text_1 = child(span_1);
template_effect(() => {
classes = set_class(button, 1, "menu-item svelte-aof35l", null, classes, { disabled: get$1(item).disabled, danger: get$1(item).danger });
button.disabled = get$1(item).disabled;
set_text(text_1, get$1(item).label);
});
delegated("click", button, () => handleItemClick(get$1(item)));
append($$anchor2, button);
});
bind_this(div, ($$value) => set(menuElement, $$value), () => get$1(menuElement));
template_effect(() => set_style(div, `left: ${get$1(adjustedX) ?? ""}px; top: ${get$1(adjustedY) ?? ""}px;`));
append($$anchor, div);
pop();
}
delegate(["click"]);
var root_1$1 = from_html(`<div class="warning-message svelte-7qu2ih">⚠️ 该位置已存在书签,无法重复添加</div>`);
var root_2 = from_html(`<div class="form-group svelte-7qu2ih"><label for="bookmark-name" class="svelte-7qu2ih">书签名称</label> <input id="bookmark-name" type="text" maxlength="100" class="svelte-7qu2ih"/> <span class="hint svelte-7qu2ih"> </span></div> <div class="preview svelte-7qu2ih"><span class="preview-label svelte-7qu2ih">预览:</span> <span class="preview-name svelte-7qu2ih"> </span></div>`, 1);
var root_3 = from_html(`<button class="btn btn-primary svelte-7qu2ih"> </button>`);
var root$1 = from_html(`<div class="modal-overlay svelte-7qu2ih" role="dialog" aria-modal="true" tabindex="-1"><div class="modal-content svelte-7qu2ih" role="document"><div class="modal-header svelte-7qu2ih"><h3 class="svelte-7qu2ih">🔖 添加书签</h3> <button class="close-btn svelte-7qu2ih">✕</button></div> <div class="modal-body svelte-7qu2ih"><!></div> <div class="modal-footer svelte-7qu2ih"><button class="btn btn-secondary svelte-7qu2ih">取消</button> <!></div></div></div>`);
function AddBookmarkModal($$anchor, $$props) {
push($$props, true);
let nameSourceText = user_derived(() => $$props.context.outlineItemType === "header" && $$props.context.headerText ? $$props.context.headerText : $$props.context.messageText);
let defaultName = user_derived(() => get$1(nameSourceText).substring(0, $$props.defaultNameLength) + (get$1(nameSourceText).length > $$props.defaultNameLength ? "..." : ""));
let customName = state("");
let isSubmitting = state(false);
let hasExistingBookmark = user_derived(() => bookmarksStore.hasBookmarkForMessageIndex($$props.context.messageIndex));
let finalName = user_derived(() => get$1(customName).trim() || get$1(defaultName));
function handleSubmit() {
if (get$1(isSubmitting) || get$1(hasExistingBookmark)) return;
set(isSubmitting, true);
const conversationId = getConversationId();
bookmarksStore.addBookmark({
name: get$1(finalName),
conversationId,
outlineItemType: $$props.context.outlineItemType,
messageHash: $$props.context.messageHash,
messageIndex: $$props.context.messageIndex,
headerPath: $$props.context.headerPath
});
set(isSubmitting, false);
$$props.onAdded?.();
$$props.onClose();
}
function handleKeydown(e) {
if (e.key === "Enter" && !get$1(hasExistingBookmark)) {
handleSubmit();
} else if (e.key === "Escape") {
$$props.onClose();
}
}
function handleOverlayClick(e) {
if (e.target === e.currentTarget) {
$$props.onClose();
}
}
function handleOverlayKeydown(e) {
if (e.key === "Escape") {
$$props.onClose();
}
}
var div = root$1();
event("keydown", $window, handleKeydown);
var div_1 = child(div);
var div_2 = child(div_1);
var button = sibling(child(div_2), 2);
var div_3 = sibling(div_2, 2);
var node = child(div_3);
{
var consequent = ($$anchor2) => {
var div_4 = root_1$1();
append($$anchor2, div_4);
};
var alternate = ($$anchor2) => {
var fragment = root_2();
var div_5 = first_child(fragment);
var input = sibling(child(div_5), 2);
var span = sibling(input, 2);
var text2 = child(span);
var div_6 = sibling(div_5, 2);
var span_1 = sibling(child(div_6), 2);
var text_1 = child(span_1);
template_effect(() => {
set_attribute(input, "placeholder", get$1(defaultName));
set_text(text2, `留空则使用默认名称:${get$1(defaultName) ?? ""}`);
set_text(text_1, get$1(finalName));
});
bind_value(input, () => get$1(customName), ($$value) => set(customName, $$value));
append($$anchor2, fragment);
};
if_block(node, ($$render) => {
if (get$1(hasExistingBookmark)) $$render(consequent);
else $$render(alternate, false);
});
}
var div_7 = sibling(div_3, 2);
var button_1 = child(div_7);
var node_1 = sibling(button_1, 2);
{
var consequent_1 = ($$anchor2) => {
var button_2 = root_3();
var text_2 = child(button_2);
template_effect(() => {
button_2.disabled = get$1(isSubmitting);
set_text(text_2, get$1(isSubmitting) ? "添加中..." : "确定");
});
delegated("click", button_2, handleSubmit);
append($$anchor2, button_2);
};
if_block(node_1, ($$render) => {
if (!get$1(hasExistingBookmark)) $$render(consequent_1);
});
}
delegated("click", div, handleOverlayClick);
delegated("keydown", div, handleOverlayKeydown);
delegated("click", div_1, (e) => e.stopPropagation());
delegated("keydown", div_1, (e) => e.stopPropagation());
delegated("click", button, function(...$$args) {
$$props.onClose?.apply(this, $$args);
});
delegated("click", button_1, function(...$$args) {
$$props.onClose?.apply(this, $$args);
});
append($$anchor, div);
pop();
}
delegate(["click", "keydown"]);
var root = from_html(`<div class="modal-overlay svelte-9ypatm" role="dialog" aria-modal="true" tabindex="-1"><div class="modal-content svelte-9ypatm" role="document"><div class="modal-header svelte-9ypatm"><h3 class="svelte-9ypatm">✏️ 重命名书签</h3> <button class="close-btn svelte-9ypatm">✕</button></div> <div class="modal-body svelte-9ypatm"><div class="form-group svelte-9ypatm"><label for="bookmark-name" class="svelte-9ypatm">书签名称</label> <input id="bookmark-name" type="text" maxlength="100" class="svelte-9ypatm"/></div></div> <div class="modal-footer svelte-9ypatm"><button class="btn btn-secondary svelte-9ypatm">取消</button> <button class="btn btn-primary svelte-9ypatm"> </button></div></div></div>`);
function RenameBookmarkModal($$anchor, $$props) {
push($$props, true);
let newName = state("");
let isSubmitting = state(false);
user_effect(() => {
set(newName, $$props.bookmark.name, true);
});
function handleSubmit() {
if (get$1(isSubmitting) || !get$1(newName).trim()) return;
set(isSubmitting, true);
bookmarksStore.updateBookmarkName($$props.bookmark.id, get$1(newName).trim());
set(isSubmitting, false);
$$props.onClose();
}
function handleKeydown(e) {
if (e.key === "Enter" && get$1(newName).trim()) {
handleSubmit();
} else if (e.key === "Escape") {
$$props.onClose();
}
}
function handleOverlayClick(e) {
if (e.target === e.currentTarget) {
$$props.onClose();
}
}
function handleOverlayKeydown(e) {
if (e.key === "Escape") {
$$props.onClose();
}
}
var div = root();
event("keydown", $window, handleKeydown);
var div_1 = child(div);
var div_2 = child(div_1);
var button = sibling(child(div_2), 2);
var div_3 = sibling(div_2, 2);
var div_4 = child(div_3);
var input = sibling(child(div_4), 2);
var div_5 = sibling(div_3, 2);
var button_1 = child(div_5);
var button_2 = sibling(button_1, 2);
var text2 = child(button_2);
template_effect(
($0) => {
button_2.disabled = $0;
set_text(text2, get$1(isSubmitting) ? "保存中..." : "保存");
},
[() => get$1(isSubmitting) || !get$1(newName).trim()]
);
delegated("click", div, handleOverlayClick);
delegated("keydown", div, handleOverlayKeydown);
delegated("click", div_1, (e) => e.stopPropagation());
delegated("keydown", div_1, (e) => e.stopPropagation());
delegated("click", button, function(...$$args) {
$$props.onClose?.apply(this, $$args);
});
bind_value(input, () => get$1(newName), ($$value) => set(newName, $$value));
delegated("click", button_1, function(...$$args) {
$$props.onClose?.apply(this, $$args);
});
delegated("click", button_2, handleSubmit);
append($$anchor, div);
pop();
}
delegate(["click", "keydown"]);
const logger = createTaggedLogger("BookmarkNav");
const PENDING_NAV_KEY = "chat-outline-pending-nav";
const NAV_TIMEOUT = 3e4;
class BookmarkNavigationService {
async navigateToBookmark(bookmark) {
if (!isInConversation(bookmark.conversationId)) {
return this.handleCrossConversationNavigation(bookmark);
}
return this.executeNavigation(bookmark);
}
handleCrossConversationNavigation(bookmark) {
const config = get(parserConfigStore);
if (!config?.buildConversationUrl) {
return {
success: false,
message: "当前平台不支持跨会话跳转"
};
}
const targetUrl = config.buildConversationUrl(bookmark.conversationId);
if (!targetUrl) {
return {
success: false,
message: "无法构建目标会话URL"
};
}
const pendingNav = {
bookmarkId: bookmark.id,
conversationId: bookmark.conversationId,
timestamp: Date.now()
};
try {
sessionStorage.setItem(PENDING_NAV_KEY, JSON.stringify(pendingNav));
logger.info("保存待跳转书签", { bookmarkId: bookmark.id, conversationId: bookmark.conversationId });
return {
success: true,
message: "正在跳转到目标会话...",
needsRedirect: true,
redirectUrl: targetUrl
};
} catch (error) {
logger.error("保存待跳转信息失败", error);
return {
success: false,
message: "保存跳转信息失败"
};
}
}
async executeNavigation(bookmark) {
const cache = messageCacheManager.getCache();
const cachedItem = cache[bookmark.messageIndex];
if (cachedItem) {
const currentHash = cachedItem.messageHash;
if (currentHash !== bookmark.messageHash) {
pushPanelNotice("内容已变更,书签位置可能不准确", "warning", 3e3);
}
if (bookmark.outlineItemType === "header" && bookmark.headerPath) {
const headerNode = this.findHeaderByPath(
cachedItem.outlineItem.headers || [],
bookmark.headerPath
);
if (headerNode) {
const headerOutlineElement = scrollSyncService.getHeaderOutlineElement(headerNode.id);
return this.scrollToElement(headerNode.element, headerOutlineElement || cachedItem.outlineElement);
}
pushPanelNotice("标题结构已变更,跳转到消息位置", "warning", 3e3);
}
return this.scrollToElement(cachedItem.outlineItem.element, cachedItem.outlineElement);
}
if (cache.length > 0) {
const lastItem = cache[cache.length - 1];
pushPanelNotice("消息索引超出范围,跳转到最近位置", "warning", 3e3);
return this.scrollToElement(lastItem.outlineItem.element, lastItem.outlineElement);
}
return {
success: false,
message: "未找到对应内容,书签可能已失效"
};
}
findHeaderByPath(headers, headerPath) {
if (!headerPath) return null;
const indices = headerPath.split(".").map((s) => parseInt(s, 10));
let currentNodes = headers;
let targetNode = null;
for (let i = 0; i < indices.length; i++) {
const index2 = indices[i];
if (index2 < 0 || index2 >= currentNodes.length) {
logger.warn("标题路径索引越界", { headerPath, index: index2, level: i });
return null;
}
targetNode = currentNodes[index2];
currentNodes = targetNode.children;
}
return targetNode;
}
scrollToElement(targetElement, outlineElement) {
targetElement.scrollIntoView({ behavior: "smooth", block: "start" });
highlightElement(targetElement);
if (outlineElement) {
scrollSyncService.focusOutlineElement(outlineElement);
scrollSyncService.applyOutlineFocus(outlineElement);
}
return {
success: true,
message: "已跳转到书签位置"
};
}
checkAndResumePendingNavigation() {
try {
const saved = sessionStorage.getItem(PENDING_NAV_KEY);
if (!saved) {
return null;
}
const pendingNav = JSON.parse(saved);
if (Date.now() - pendingNav.timestamp > NAV_TIMEOUT) {
logger.warn("待跳转书签已超时");
sessionStorage.removeItem(PENDING_NAV_KEY);
return null;
}
sessionStorage.removeItem(PENDING_NAV_KEY);
const bookmark = bookmarksStore.getBookmarkById(pendingNav.bookmarkId);
if (!bookmark) {
logger.warn("未找到待跳转的书签", { bookmarkId: pendingNav.bookmarkId });
return null;
}
logger.info("恢复待跳转书签", {
bookmarkId: bookmark.id,
name: bookmark.name,
conversationId: bookmark.conversationId,
headerPath: bookmark.headerPath
});
return bookmark;
} catch (error) {
logger.error("检查待跳转书签失败", error);
return null;
}
}
async resumeNavigation(bookmark) {
await this.waitForOutlineReady();
const result = await this.executeNavigation(bookmark);
if (result.success) {
pushPanelNotice(result.message, "success", 2e3);
} else {
pushPanelNotice(result.message, "error", 3e3);
}
}
waitForOutlineReady(timeout = 5e3) {
return new Promise((resolve) => {
const startTime = Date.now();
const check = () => {
const cache = messageCacheManager.getCache();
if (cache.length > 0 && cache.some((item) => item.outlineElement !== null)) {
resolve();
return;
}
if (Date.now() - startTime > timeout) {
logger.warn("等待大纲超时");
resolve();
return;
}
setTimeout(check, 100);
};
check();
});
}
executeRedirect(url) {
logger.info("执行跨会话跳转", { url });
window.location.href = url;
}
}
const bookmarkNavigationService = new BookmarkNavigationService();
var root_1 = from_html(`<div id="chat-outline"><!> <!> <!> <!></div> <!> <!> <!>`, 1);
function OutlinePanel($$anchor, $$props) {
push($$props, true);
let isFixedRight = prop($$props, "isFixedRight", 3, false);
let currentTheme = state("light");
let allExpanded = state(true);
let isVisible = state(true);
let filterText = state("");
let useRegex = state(false);
let viewMode = state("outline");
let menuState = state(proxy(get(contextMenuState)));
let addModalState = state(proxy(get(addBookmarkModalState)));
let renameModalState = state(proxy(get(renameBookmarkModalState)));
onMount(() => {
const unsubscribeTheme = themeStore.subscribe((theme2) => {
set(currentTheme, theme2.currentTheme, true);
});
const unsubscribeAllExpanded = allExpandedStore.subscribe((value) => {
set(allExpanded, value, true);
});
const unsubscribeFeatures = featuresStore.subscribe((features) => {
set(isVisible, features.isVisible, true);
});
const unsubscribeMenu = contextMenuState.subscribe((state2) => {
set(menuState, state2, true);
});
const unsubscribeAddModal = addBookmarkModalState.subscribe((state2) => {
set(addModalState, state2, true);
});
const unsubscribeRenameModal = renameBookmarkModalState.subscribe((state2) => {
set(renameModalState, state2, true);
});
const theme = get(themeStore);
set(currentTheme, theme.currentTheme, true);
set(allExpanded, get(allExpandedStore), true);
set(isVisible, get(featuresStore).isVisible, true);
const pendingBookmark = bookmarkNavigationService.checkAndResumePendingNavigation();
if (pendingBookmark) {
setTimeout(
() => {
bookmarkNavigationService.resumeNavigation(pendingBookmark);
},
500
);
}
return () => {
unsubscribeTheme();
unsubscribeAllExpanded();
unsubscribeFeatures();
unsubscribeMenu();
unsubscribeAddModal();
unsubscribeRenameModal();
};
});
function handleToggleAll() {
toggleAllExpanded();
}
function handleToggleTheme() {
toggleTheme();
}
function handleHide() {
toggleVisibility();
}
function handleSync() {
scrollSyncService.manualSync();
}
function handleFilterChange(filter, regex) {
set(filterText, filter, true);
set(useRegex, regex, true);
}
function handleTabChange(tab) {
set(viewMode, tab, true);
}
function handleContextMenu(e, context) {
const fullContext = buildOutlineItemContext(context.outlineItemType, context.messageIndex, context.messageText, context.messageHash, e.target, context.headerPath, context.headerText);
showContextMenu(e, fullContext);
}
async function handleBookmarkNavigate(bookmark) {
set(viewMode, "outline");
await new Promise((resolve) => setTimeout(resolve, 50));
const result = await bookmarkNavigationService.navigateToBookmark(bookmark);
if (result.needsRedirect && result.redirectUrl) {
bookmarkNavigationService.executeRedirect(result.redirectUrl);
}
}
function handleMenuSelectWrapper(itemId) {
const result = handleMenuSelect(itemId);
if (itemId === "navigate" && result.bookmark && result.conversationId) {
handleBookmarkNavigate({ ...result.bookmark, conversationId: result.conversationId });
}
}
var fragment = comment();
var node = first_child(fragment);
{
var consequent_4 = ($$anchor2) => {
var fragment_1 = root_1();
var div = first_child(fragment_1);
let classes;
var node_1 = child(div);
OutlineHeader(node_1, {
get onRefresh() {
return $$props.onRefresh;
},
onToggleAll: handleToggleAll,
onToggleTheme: handleToggleTheme,
onHide: handleHide,
onSync: handleSync,
onFilterChange: handleFilterChange,
get viewMode() {
return get$1(viewMode);
},
onTabChange: handleTabChange,
get allExpanded() {
return get$1(allExpanded);
},
get currentTheme() {
return get$1(currentTheme);
}
});
var node_2 = sibling(node_1, 2);
PanelNoticeStack(node_2, {});
var node_3 = sibling(node_2, 2);
{
var consequent = ($$anchor3) => {
OutlineList($$anchor3, {
get filterText() {
return get$1(filterText);
},
get useRegex() {
return get$1(useRegex);
},
onContextMenu: handleContextMenu
});
};
var alternate = ($$anchor3) => {
BookmarkPanel($$anchor3, { onNavigate: handleBookmarkNavigate });
};
if_block(node_3, ($$render) => {
if (get$1(viewMode) === "outline") $$render(consequent);
else $$render(alternate, false);
});
}
var node_4 = sibling(node_3, 2);
ServiceStatusBar(node_4, {});
var node_5 = sibling(div, 2);
{
var consequent_1 = ($$anchor3) => {
ContextMenu($$anchor3, {
get x() {
return get$1(menuState).x;
},
get y() {
return get$1(menuState).y;
},
get items() {
return get$1(menuState).items;
},
onSelect: handleMenuSelectWrapper,
get onClose() {
return hideContextMenu;
}
});
};
if_block(node_5, ($$render) => {
if (get$1(menuState).visible) $$render(consequent_1);
});
}
var node_6 = sibling(node_5, 2);
{
var consequent_2 = ($$anchor3) => {
{
let $0 = user_derived(getDefaultNameLength);
AddBookmarkModal($$anchor3, {
get context() {
return get$1(addModalState).context;
},
get defaultNameLength() {
return get$1($0);
},
get onClose() {
return hideAddBookmarkModal;
}
});
}
};
if_block(node_6, ($$render) => {
if (get$1(addModalState).visible && get$1(addModalState).context) $$render(consequent_2);
});
}
var node_7 = sibling(node_6, 2);
{
var consequent_3 = ($$anchor3) => {
RenameBookmarkModal($$anchor3, {
get bookmark() {
return get$1(renameModalState).bookmark;
},
get onClose() {
return hideRenameBookmarkModal;
}
});
};
if_block(node_7, ($$render) => {
if (get$1(renameModalState).visible && get$1(renameModalState).bookmark) $$render(consequent_3);
});
}
template_effect(() => classes = set_class(div, 1, "chat-outline svelte-n2r6vx", null, classes, { "outline-fixed-right": isFixedRight() }));
append($$anchor2, fragment_1);
};
var alternate_1 = ($$anchor2) => {
DraggableToggleButton($$anchor2, {
get onClick() {
return toggleVisibility;
}
});
};
if_block(node, ($$render) => {
if (get$1(isVisible)) $$render(consequent_4);
else $$render(alternate_1, false);
});
}
append($$anchor, fragment);
pop();
}
let currentObserver = null;
let debouncedRefresh = null;
function getMessageHost(node) {
if (node instanceof Element) {
return node.closest("[cbe-message-id]");
}
return node.parentElement?.closest("[cbe-message-id]") || null;
}
function hasRelevantMutation(mutations) {
let lastMessageHost = null;
for (const mutation of mutations) {
if (mutation.type === "childList") {
if (mutation.addedNodes.length > 0 || mutation.removedNodes.length > 0) {
return true;
}
continue;
}
if (mutation.type !== "characterData") {
continue;
}
const messageHost = getMessageHost(mutation.target);
if (!messageHost) {
continue;
}
if (!lastMessageHost) {
const messageList = messageHost.parentElement?.querySelectorAll?.("[cbe-message-id]");
lastMessageHost = messageList && messageList.length > 0 ? messageList[messageList.length - 1] : null;
}
if (!lastMessageHost || messageHost === lastMessageHost) {
return true;
}
}
return false;
}
function setupMutationObserver(chatArea, onRefresh) {
if (currentObserver) {
currentObserver.disconnect();
logger$1.debug("已断开原有的 MutationObserver");
}
const features = get(featuresStore);
debouncedRefresh = debounce(onRefresh, features.debouncedInterval);
const observer = new MutationObserver((mutations) => {
if (hasRelevantMutation(mutations) && debouncedRefresh) {
debouncedRefresh();
}
});
observer.observe(chatArea, {
childList: true,
subtree: true,
attributes: false,
characterData: true
});
currentObserver = observer;
logger$1.info("已设置新的 MutationObserver 监听:", chatArea);
return observer;
}
function disconnectObserver() {
if (currentObserver) {
currentObserver.disconnect();
currentObserver = null;
logger$1.debug("已断开 MutationObserver");
}
}
const observerService = {
setup: setupMutationObserver,
disconnect: disconnectObserver
};
class MessageSourceService {
cachedChatArea = null;
getCachedChatArea(parserConfig, forceRefresh = false) {
if (forceRefresh || !this.cachedChatArea) {
this.cachedChatArea = parserConfig?.selectChatArea() || null;
logger$1.debug("get chatArea:", this.cachedChatArea);
}
return this.cachedChatArea;
}
clearChatAreaCache() {
this.cachedChatArea = null;
}
collect(parserConfig) {
const chatArea = this.getCachedChatArea(parserConfig);
if (!chatArea) {
return {
chatArea: null,
messageElements: []
};
}
const messageListResult = parserConfig.getMessageList(chatArea);
if (messageListResult == null) {
return {
chatArea,
messageElements: []
};
}
const messageElements = Array.from(messageListResult);
for (const messageElement of messageElements) {
messageCacheManager.ensureMessageId(messageElement);
}
return {
chatArea,
messageElements
};
}
}
const messageSourceService = new MessageSourceService();
class OutlineRefreshService {
getCachedChatArea(parserConfig, forceRefresh = false) {
return messageSourceService.getCachedChatArea(parserConfig, forceRefresh);
}
refresh(parserConfig) {
const { chatArea, messageElements } = messageSourceService.collect(parserConfig);
if (!chatArea) {
logger$1.warn("无法定位到对话区域");
return;
}
if (messageElements.length === 0) {
const messageListResult = parserConfig.getMessageList(chatArea);
if (messageListResult == null) {
logger$1.warn("对话区域无效,大纲生成失败, chatArea:", chatArea);
return;
}
}
const features = get(featuresStore);
logger$1.debug("刷新大纲, 消息数量:", messageElements.length, "缓存数量:", messageCacheManager.length);
if (messageElements.length === 0) {
messageCacheManager.clearCache();
outlineStore.set([]);
scrollSyncService.schedulePostRefreshCheck();
return;
}
const lastCheck = messageCacheManager.checkLastMessage(messageElements);
if (!lastCheck.shouldRefreshAll && !lastCheck.lastMessageNeedsUpdate) {
logger$1.debug("没有变化,跳过更新");
return;
}
if (!lastCheck.shouldRefreshAll && lastCheck.lastMessageNeedsUpdate) {
this.refreshLastMessage(messageElements, lastCheck.lastIndex, parserConfig);
return;
}
const result = messageCacheManager.rebuildCache(messageElements, parserConfig, {
features: {
showUserMessages: features.showUserMessages,
showAIMessages: features.showAIMessages,
textLength: features.textLength
}
});
if (result.changes.hasChanges) {
outlineStore.set(result.outlineItems);
logger$1.info("大纲刷新完成,共", result.outlineItems.length, "项,变更:", result.changes);
} else {
logger$1.debug("缓存完全命中,跳过store更新");
}
scrollSyncService.schedulePostRefreshCheck();
}
forceRefresh(parserConfig) {
logger$1.info("执行强制刷新...");
messageCacheManager.clearCache();
messageSourceService.clearChatAreaCache();
const newChatArea = this.getCachedChatArea(parserConfig, true);
if (!newChatArea) {
logger$1.error("强制刷新失败:无法获取到chatArea");
return;
}
this.refresh(parserConfig);
scrollSyncService.rebind(newChatArea, parserConfig);
logger$1.info("强制刷新完成");
}
refreshLastMessage(messageElements, lastIndex, parserConfig) {
const features = get(featuresStore);
const lastMessage = messageElements[lastIndex];
const lastMessageType = parserConfig.determineMessageOwner(lastMessage);
const shouldShow = lastMessageType === MessageOwner.User && features.showUserMessages || lastMessageType === MessageOwner.Assistant && features.showAIMessages;
if (!shouldShow) {
return;
}
const lastCached = messageCacheManager.get(messageCacheManager.length - 1);
const newOutlineItem = createOutlineViewItem({
id: lastCached?.outlineItem.id || generateUniqueId(),
index: messageCacheManager.length - 1,
type: lastMessageType,
element: lastMessage,
textLength: features.textLength
});
messageCacheManager.updateLastCache(
lastMessage,
messageElements.length - 1,
newOutlineItem,
lastCached?.outlineElement || null
);
outlineStore.set(messageCacheManager.getCache().map((item) => item.outlineItem));
scrollSyncService.schedulePostRefreshCheck();
}
}
const outlineRefreshService = new OutlineRefreshService();
class OutlineRuntimeService {
parserConfig = null;
outlineContainer = null;
outlineInstance = null;
isFixedRight = false;
destroyed = false;
async start(parserConfig) {
setServiceStatus("outlineRuntime", {
state: "syncing",
message: "正在初始化大纲运行时"
});
this.destroy(false);
this.destroyed = false;
this.parserConfig = parserConfig;
this.isFixedRight = false;
parserConfig.init?.();
const timeout = parserConfig.timeout || 0;
if (timeout > 0) {
await this.delay(timeout);
}
if (this.destroyed) {
setServiceStatus("outlineRuntime", {
state: "warning",
message: "初始化被中断"
});
return { isFixedRight: this.isFixedRight, isReady: false };
}
setServiceStatus("outlineRuntime", {
state: "syncing",
message: "正在获取大纲挂载容器"
});
await this.resolveOutlineContainer();
if (this.destroyed) {
setServiceStatus("outlineRuntime", {
state: "warning",
message: "挂载前初始化被中断"
});
return { isFixedRight: this.isFixedRight, isReady: false };
}
this.mountOutlinePanel();
setServiceStatus("outlineRuntime", {
state: "syncing",
message: "正在获取 chatArea"
});
const chatArea = await this.resolveChatArea();
if (!chatArea || this.destroyed) {
setServiceStatus("outlineRuntime", {
state: "error",
message: "chatArea 获取失败,无法完成绑定"
});
return { isFixedRight: this.isFixedRight, isReady: false };
}
setServiceStatus("outlineRuntime", {
state: "syncing",
message: "chatArea 已获取,正在绑定监听"
});
this.initializeOutlineRuntime(chatArea);
setServiceStatus("outlineRuntime", {
state: "ready",
message: this.isFixedRight ? "chatArea 已获取,监听已绑定,当前使用右侧固定模式" : "chatArea 已获取,MutationObserver 已绑定"
});
logger$1.info("对话大纲脚本已启动");
return { isFixedRight: this.isFixedRight, isReady: true };
}
refresh() {
if (!this.parserConfig) {
logger$1.warn("刷新大纲失败:parserConfig 不存在");
return;
}
outlineRefreshService.refresh(this.parserConfig);
}
forceRefresh() {
if (!this.parserConfig) {
logger$1.warn("强制刷新失败:parserConfig 不存在");
setServiceStatus("outlineRuntime", {
state: "error",
message: "运行时未初始化,无法刷新大纲"
});
return;
}
outlineRefreshService.forceRefresh(this.parserConfig);
setServiceStatus("outlineRuntime", {
state: "ready",
message: "chatArea 已获取,监听保持绑定,大纲已刷新"
});
}
async forceRebind() {
if (!this.parserConfig) {
setServiceStatus("outlineRuntime", {
state: "error",
message: "运行时未初始化,无法重新获取并绑定监听"
});
pushPanelNotice("运行时未初始化,无法重新绑定", "error");
return false;
}
const parserConfig = this.parserConfig;
setServiceStatus("outlineRuntime", {
state: "syncing",
message: "正在重新获取 chatArea 并绑定监听"
});
pushPanelNotice("正在重新获取 chatArea 并绑定监听...", "info", 2e3);
const result = await this.start(parserConfig);
if (result.isReady) {
pushPanelNotice("大纲运行时重新绑定完成", "success");
return true;
}
setServiceStatus("outlineRuntime", {
state: "error",
message: "重新获取 chatArea 或绑定监听失败"
});
pushPanelNotice("大纲运行时重新绑定失败", "error");
return false;
}
destroy(resetStatus = true) {
this.destroyed = true;
observerService.disconnect();
scrollSyncService.destroy(false);
if (this.outlineInstance) {
unmount(this.outlineInstance);
this.outlineInstance = null;
}
this.outlineContainer = null;
this.parserConfig = null;
this.isFixedRight = false;
if (resetStatus) {
resetServiceStatus();
}
}
async resolveOutlineContainer() {
try {
this.outlineContainer = await getEleWithRetry(
this.parserConfig.getOutlineContainer,
[],
true,
5,
1e3
);
if (!this.outlineContainer) {
throw new Error("未找到大纲挂载容器");
}
logger$1.info("成功获取大纲挂载目标:", this.outlineContainer);
this.parserConfig?.afterGetContainer?.(this.outlineContainer);
} catch (error) {
logger$1.error("大纲挂载失败,回退到 body 右侧固定模式:", error);
this.isFixedRight = true;
this.outlineContainer = document.body;
setServiceStatus("outlineRuntime", {
state: "warning",
message: "未找到宿主容器,已回退到右侧固定模式"
});
}
}
mountOutlinePanel() {
if (!this.outlineContainer) {
return;
}
const existingOutline = this.outlineContainer.querySelector(".chat-outline");
if (existingOutline) {
logger$1.debug("已存在大纲组件,跳过重复挂载");
return;
}
this.outlineInstance = mount(OutlinePanel, {
target: this.outlineContainer,
props: {
onRefresh: () => this.forceRefresh(),
isFixedRight: this.isFixedRight
}
});
}
async resolveChatArea() {
logger$1.info("开始获取 chatArea...");
const chatArea = await getEleWithRetry(this.parserConfig.selectChatArea);
if (!chatArea) {
logger$1.error("多次重试后仍未找到聊天区域,初始化失败");
setServiceStatus("outlineRuntime", {
state: "error",
message: "未找到 chatArea,请检查页面是否加载完成"
});
return null;
}
logger$1.info("成功定位 chatArea:", chatArea);
this.parserConfig?.afterGetChatArea?.(chatArea);
return chatArea;
}
initializeOutlineRuntime(chatArea) {
this.refresh();
scrollSyncService.init(chatArea, this.parserConfig);
observerService.setup(chatArea, () => {
this.refresh();
});
}
delay(ms) {
return new Promise((resolve) => {
window.setTimeout(resolve, ms);
});
}
}
const outlineRuntimeService = new OutlineRuntimeService();
function App($$anchor, $$props) {
push($$props, true);
const $themeStore = () => store_get(themeStore, "$themeStore", $$stores);
const [$$stores, $$cleanup] = setup_stores();
let parserConfig = state(null);
user_effect(() => {
document.documentElement.setAttribute("cbe-data-theme", $themeStore().currentTheme);
});
onMount(() => {
const platform = judgePlatform();
if (platform === "unknown") {
logger$1.warn("不支持的平台");
return;
}
setPlatform(platform);
set(parserConfig, get(parserConfigStore), true);
if (!get$1(parserConfig)) {
logger$1.error("无法获取解析配置");
return;
}
void outlineRuntimeService.start(get$1(parserConfig));
return () => {
outlineRuntimeService.destroy();
};
});
pop();
$$cleanup();
}
mount(App, {
target: (() => {
const container = document.createElement("div");
document.body.append(container);
return container;
})()
});
})();