Files
hunjing/frontend/design/lorebook-preview.html
2026-08-21 16:00:13 +08:00

317 lines
17 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="zh-CN" data-theme="dark">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>魂镜 · 世谱管理页设计预览</title>
<link rel="stylesheet" href="tokens.css" />
<link rel="stylesheet" href="_base.css" />
<link rel="stylesheet" href="_chrome.css" />
<style>
/* ============================================================
* 铜镜鉴心 v2.1 — 世谱(Lorebook / World Info)管理页
* 功能融合:关键词触发的世界设定注入(融合设计 §7)
* ============================================================ */
.app-main { flex: 1; padding: 24px 28px 56px; max-width: 920px; width: 100%; margin: 0 auto; }
/* ── 卡片 ── */
.card-title .glyph { color: var(--patina); opacity: 0.8; }
/* ── 按钮 ── */
/* ── 书切换 tabs ── */
.book-tabs { display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: 18px; }
.book-tab { display: inline-flex; align-items: center; gap: 6px; padding: 7px 14px; border-radius: 999px; border: 1px solid var(--rule); background: var(--surface); color: var(--fg-dim); font-size: 12.5px; cursor: pointer; transition: all 0.12s; }
.book-tab:hover { color: var(--fg); border-color: var(--patina-dim); }
.book-tab.active { background: var(--patina-wash); color: var(--patina); border-color: var(--patina-dim); }
.book-tab .count { font-family: "JetBrains Mono", monospace; font-size: 10.5px; opacity: 0.8; }
.book-tab.add { border-style: dashed; color: var(--fg-faint); }
.book-tab.add:hover { color: var(--patina); }
/* ── 表单 ── */
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.field-label { display: block; font-family: "JetBrains Mono", monospace; font-size: 11px; letter-spacing: 0.04em; color: var(--muted); margin-bottom: 4px; }
.field input, .field textarea, .field select { width: 100%; padding: 8px 12px; border: 1px solid var(--rule); border-radius: 10px; background: var(--glass); color: var(--fg); font-family: inherit; font-size: 13px; transition: border-color 0.15s; }
.field input:focus, .field textarea:focus, .field select:focus { outline: none; border-color: var(--patina-dim); }
.field textarea { min-height: 80px; resize: vertical; }
.field-full { grid-column: 1 / -1; }
/* ── 条目 ── */
.section-label .count { font-size: 11px; color: var(--fg-dim); font-weight: 400; }
.entry-item { border: 1px solid var(--rule); border-radius: 12px; background: var(--surface); padding: 14px 16px; margin-bottom: 10px; }
.entry-item.constant { border-left: 3px solid var(--gilt); }
.entry-item.disabled { opacity: 0.5; }
.entry-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.entry-body { flex: 1; min-width: 0; }
.entry-keys { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 7px; }
.key-chip { display: inline-flex; align-items: center; padding: 2px 9px; border-radius: 6px; font-family: "JetBrains Mono", monospace; font-size: 11px; background: var(--patina-wash); color: var(--patina); border: 1px solid var(--patina-dim); }
.key-chip.secondary { background: var(--gilt-faint); color: var(--gilt); border-color: var(--gilt-dim); }
.entry-content { font-size: 13px; color: var(--fg); margin: 4px 0 8px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.entry-meta { font-family: "JetBrains Mono", monospace; font-size: 10.5px; color: var(--fg-faint); display: flex; gap: 12px; flex-wrap: wrap; }
.entry-meta span { display: inline-flex; align-items: center; gap: 3px; }
.entry-actions { display: flex; gap: 4px; flex-shrink: 0; align-items: center; }
/* ── 开关 ── */
.switch { position: relative; width: 32px; height: 18px; border-radius: 999px; background: var(--rule); cursor: pointer; transition: background 0.15s; flex-shrink: 0; }
.switch::after { content: ""; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: var(--fg-dim); transition: transform 0.15s, background 0.15s; }
.switch.on { background: var(--patina-dim); }
.switch.on::after { transform: translateX(14px); background: var(--patina); }
/* ── Tag ── */
.tag-constant { border-color: var(--gilt-dim); color: var(--gilt); background: var(--gilt-faint); }
.tag-selective { border-color: var(--cinnabar-dim); color: var(--cinnabar); background: var(--cinnabar-wash); }
.tag-global { border-color: var(--patina-dim); color: var(--patina); background: var(--patina-wash); }
/* ── 高级选项折叠 ── */
.advanced-toggle { font-family: "JetBrains Mono", monospace; font-size: 11px; color: var(--muted); cursor: pointer; display: inline-flex; align-items: center; gap: 4px; margin-top: 8px; }
.advanced-toggle:hover { color: var(--patina); }
.advanced-body { margin-top: 12px; padding-top: 12px; border-top: 1px dashed var(--rule); }
/* ── 说明卡 ── */
.note { font-size: 12.5px; color: var(--fg-dim); line-height: 1.7; }
.note code { font-family: "JetBrains Mono", monospace; font-size: 11.5px; background: var(--surface-hi); padding: 1px 6px; border-radius: 4px; color: var(--patina); }
.note strong { color: var(--fg); font-weight: 500; }
@media (max-width: 768px) {
.app-main { padding: 16px 14px 40px; }
.form-grid { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<div class="app-shell">
<div class="sidebar-mount" data-active="世谱"></div>
<div class="main-area">
<main class="app-main">
<!-- ═══ 页头 ═══ -->
<div class="page-head">
<div>
<h1 class="page-title">世谱 · Lorebook</h1>
<p class="page-sub">「时崎狂三」的世界设定谱——对话命中关键词时自动注入,<code style="font-family:JetBrains Mono,monospace;font-size:12px;color:var(--patina);">before_char</code> / <code style="font-family:JetBrains Mono,monospace;font-size:12px;color:var(--patina);">after_char</code> 定位于人格前后。</p>
</div>
<button class="btn btn-primary">+ 新建世谱</button>
</div>
<!-- ═══ 世谱书切换 ═══ -->
<div class="book-tabs">
<span class="book-tab active">狂三世谱 <span class="count">5</span></span>
<span class="book-tab">黑猫与日常 <span class="count">3</span></span>
<span class="book-tab">通用世界观 <span class="count">8 · global</span></span>
<span class="book-tab add">+ 新建</span>
</div>
<!-- ═══ 世谱书设置 ═══ -->
<div class="card">
<div class="card-header">
<h2 class="card-title"><span class="glyph">📖</span> 狂三世谱</h2>
<span class="tag tag-global">character · 5 条</span>
</div>
<div class="card-body">
<div class="form-grid">
<div class="field field-full">
<label class="field-label">书名</label>
<input type="text" value="狂三世谱" />
</div>
<div class="field field-full">
<label class="field-label">描述(可选)</label>
<input type="text" value="时崎狂三的能力、关系、背景设定,按对话关键词触发。" />
</div>
<div class="field">
<label class="field-label">扫描深度 scan_depth</label>
<input type="number" value="8" placeholder="扫描最近 N 条对话" />
</div>
<div class="field">
<label class="field-label">token 预算</label>
<input type="number" value="800" placeholder="注入上限" />
</div>
</div>
<div style="display:flex;align-items:center;gap:10px;margin-top:12px;">
<span class="switch on" id="recursive"></span>
<span style="font-size:12.5px;color:var(--fg-dim);">递归扫描 <span style="color:var(--fg-faint);font-size:11.5px;">— 已命中条目的内容可触发其他条目</span></span>
</div>
</div>
</div>
<!-- ═══ 条目列表 ═══ -->
<div class="section-label">
◇ 条目
<span class="count">(5 条 · 4 启用)</span>
<div style="flex:1;"></div>
<button class="btn btn-outline btn-sm">+ 新建条目</button>
</div>
<!-- 条目 1:常量(恒定注入) -->
<div class="entry-item constant">
<div class="entry-head">
<div class="entry-body">
<div class="entry-keys">
<span class="key-chip">刻刻帝</span>
<span class="key-chip">Zafkiel</span>
<span class="key-chip">天使</span>
<span class="tag tag-constant">constant · 恒定注入</span>
</div>
<div class="entry-content">狂三的天使「刻刻帝」外观为巨大古钟,时钟指针化为长短双枪。拥有十二种时间能力,每种消耗不同的"时间"代价。</div>
<div class="entry-meta">
<span>位置 after_char</span>
<span>顺序 10</span>
<span>优先级 5</span>
</div>
</div>
<div class="entry-actions">
<span class="switch on"></span>
<button class="btn btn-ghost btn-sm">编辑</button>
<button class="btn btn-ghost btn-sm">删</button>
</div>
</div>
</div>
<!-- 条目 2:selective(双键命中) -->
<div class="entry-item">
<div class="entry-head">
<div class="entry-body">
<div class="entry-keys">
<span class="key-chip">猫</span>
<span style="color:var(--fg-faint);font-size:11px;">+</span>
<span class="key-chip secondary">黑</span>
<span class="tag tag-selective">selective · 双键命中</span>
</div>
<div class="entry-content">狂三格外钟爱黑猫,常以「小可」称呼她在影子中豢养的黑猫分身,会为它留下红茶第三泡。</div>
<div class="entry-meta">
<span>位置 after_char</span>
<span>顺序 20</span>
<span>优先级 10</span>
<span>区分大小写 ✕</span>
</div>
</div>
<div class="entry-actions">
<span class="switch on"></span>
<button class="btn btn-ghost btn-sm">编辑</button>
<button class="btn btn-ghost btn-sm">删</button>
</div>
</div>
</div>
<!-- 条目 3:正则匹配 -->
<div class="entry-item">
<div class="entry-head">
<div class="entry-body">
<div class="entry-keys">
<span class="key-chip" style="font-family:'JetBrains Mono',monospace;">/\b(四之弹|七之弹|十二之弹)\b/</span>
<span class="tag" style="border-color:var(--cinnabar-dim);color:var(--cinnabar);background:var(--cinnabar-wash);">use_regex · 正则</span>
</div>
<div class="entry-content">十二之弹对应十二种时间能力:一之弹加速自身、四之弹回溯目标、七之弹停止时间、十二之弹时间旅行……每次使用消耗自身寿命。</div>
<div class="entry-meta">
<span>位置 before_char</span>
<span>顺序 30</span>
<span>优先级 10</span>
</div>
</div>
<div class="entry-actions">
<span class="switch on"></span>
<button class="btn btn-ghost btn-sm">编辑</button>
<button class="btn btn-ghost btn-sm">删</button>
</div>
</div>
</div>
<!-- 条目 4:已禁用 -->
<div class="entry-item disabled">
<div class="entry-head">
<div class="entry-body">
<div class="entry-keys">
<span class="key-chip">士道</span>
</div>
<div class="entry-content">与五河士道的关系:曾多次交手与合作,为他使用六之弹回到过去,经历 204 次时间回溯。</div>
<div class="entry-meta">
<span style="color:var(--cinnabar);">● 已禁用</span>
<span>位置 after_char</span>
</div>
</div>
<div class="entry-actions">
<span class="switch"></span>
<button class="btn btn-ghost btn-sm">编辑</button>
<button class="btn btn-ghost btn-sm">删</button>
</div>
</div>
</div>
<!-- ═══ 条目编辑表单(展开态示例) ═══ -->
<div class="card">
<div class="card-header">
<h2 class="card-title"><span class="glyph">✎</span> 编辑条目</h2>
<button class="btn btn-ghost btn-sm">取消</button>
</div>
<div class="card-body">
<div class="form-grid">
<div class="field field-full">
<label class="field-label">主关键词 keys(逗号分隔,命中任一即触发)</label>
<input type="text" value="刻刻帝, Zafkiel, 天使" />
</div>
<div class="field field-full">
<label class="field-label">注入内容 content *</label>
<textarea>狂三的天使「刻刻帝」外观为巨大古钟……</textarea>
</div>
<div class="field field-full">
<label class="field-label">次关键词 secondary_keys(selective 时需同时命中)</label>
<input type="text" placeholder="可选" />
</div>
<div class="field">
<label class="field-label">注入位置</label>
<select>
<option>after_char · 人格之后</option>
<option>before_char · 人格之前</option>
</select>
</div>
<div class="field">
<label class="field-label">插入顺序 / 优先级</label>
<div style="display:flex;gap:8px;">
<input type="number" value="10" placeholder="顺序" style="flex:1;" />
<input type="number" value="5" placeholder="优先级" style="flex:1;" />
</div>
</div>
</div>
<div class="advanced-toggle" onclick="this.nextElementSibling.style.display = this.nextElementSibling.style.display==='none' ? 'block' : 'none';">▸ 高级选项</div>
<div class="advanced-body" style="display:none;">
<div style="display:flex;flex-wrap:wrap;gap:18px;">
<label style="display:flex;align-items:center;gap:6px;font-size:12.5px;color:var(--fg-dim);cursor:pointer;"><span class="switch on"></span> 启用</label>
<label style="display:flex;align-items:center;gap:6px;font-size:12.5px;color:var(--fg-dim);cursor:pointer;"><span class="switch"></span> constant(恒定注入,无视关键词)</label>
<label style="display:flex;align-items:center;gap:6px;font-size:12.5px;color:var(--fg-dim);cursor:pointer;"><span class="switch"></span> selective(需双键命中)</label>
<label style="display:flex;align-items:center;gap:6px;font-size:12.5px;color:var(--fg-dim);cursor:pointer;"><span class="switch"></span> 区分大小写</label>
<label style="display:flex;align-items:center;gap:6px;font-size:12.5px;color:var(--fg-dim);cursor:pointer;"><span class="switch"></span> use_regex(关键词按正则)</label>
</div>
</div>
<div style="display:flex;justify-content:flex-end;gap:8px;margin-top:16px;">
<button class="btn btn-outline">取消</button>
<button class="btn btn-primary">保存条目</button>
</div>
</div>
</div>
<!-- ═══ 说明 ═══ -->
<div class="card">
<div class="card-body note">
<strong>世谱是什么。</strong>源自业界通用的 <code>World Info / Lorebook</code>——创作者预设的设定条目,对话命中 <code>keys</code> 时把 <code>content</code> 注入系统提示词,既丰富世界观又节省 token(按需注入而非全量塞入)。
<br/><br/>
<strong>与魂镜既有载体的区别。</strong>息壤记忆(自动抽取、会演化)、河图世界实体(结构化图谱)之外,世谱是<strong>手动预设的触发式设定</strong>,三者正交。魂镜增量:条目可 <code>bound_entity_id</code> 绑定河图实体,实现「关键词 + 实体」双引擎触发。
</div>
</div>
</main>
</div>
</div>
<script>
// 开关交互(设计稿示意)
document.querySelectorAll('.switch').forEach(s => s.addEventListener('click', () => s.classList.toggle('on')));
</script>
<script src="_theme.js" defer></script>
</body>
</html>