初始化提交

This commit is contained in:
chenxin committed 2026-08-21 16:00:13 +08:00
commit 887c1f449e
963 files changed
+166869

No files matched your search

@@ -0,0 +1,365 @@
<!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 — 人物详情页
* ============================================================ */
/* ── 通用布局 ── */
.app-main { flex: 1; padding: 24px 28px 56px; max-width: 920px; width: 100%; margin: 0 auto; }
@media (max-width: 900px) { .sidebar-wrap { display: none; } }
/* ── 操作栏 ── */
.action-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 14px 0 18px; }
.badge { display: inline-flex; align-items: center; gap: 5px; padding: 4px 12px; border-radius: 999px; font-family: "JetBrains Mono", monospace; font-size: 11px; border: 1px solid var(--rule); background: var(--surface); color: var(--fg-dim); }
.badge.active { border-color: var(--patina-dim); color: var(--patina); background: var(--patina-wash); }
.badge.paused { border-color: var(--gilt-dim); color: var(--gilt); background: var(--gilt-faint); }
.badge.wuji { border-color: var(--rule); color: var(--fg-faint); }
/* ── 生命周期条 ── */
.lifecycle-bar { display: flex; align-items: center; gap: 3px; font-family: "JetBrains Mono", monospace; font-size: 10.5px; }
.lifecycle-step { display: inline-flex; align-items: center; gap: 4px; padding: 3px 9px; border-radius: 999px; color: var(--fg-faint); border: 1px solid transparent; }
.lifecycle-step.past { color: var(--patina); border-color: var(--patina-dim); background: var(--patina-wash); }
.lifecycle-step.current { color: var(--gilt); border-color: var(--gilt-dim); background: var(--gilt-faint); }
.lifecycle-arrow { color: var(--fg-faint); font-size: 12px; opacity: 0.5; }
.action-link { margin-left: auto; display: inline-flex; align-items: center; gap: 5px; padding: 6px 14px; border-radius: 10px; font-size: 12px; color: var(--patina); border: 1px solid var(--patina-dim); background: var(--patina-wash); text-decoration: none; transition: background 0.12s; cursor: pointer; }
.action-link:hover { background: var(--patina-dim); color: var(--fg); }
/* ── 卡片 ── */
.card-banner { height: 72px; background: linear-gradient(135deg, var(--patina-wash), var(--glass), var(--gilt-faint)); }
/* ── 铜镜头像 ── */
.avatar-section { position: relative; width: 88px; height: 88px; margin-top: -48px; margin-bottom: 12px; }
.avatar-img { width: 88px; height: 88px; border-radius: 50%; border: 3px solid var(--gilt); box-shadow: 0 0 0 3px var(--surface), 0 0 16px rgba(201,162,74,0.25); overflow: hidden; display: flex; align-items: center; justify-content: center; background: conic-gradient(from 0deg, var(--ink), var(--night-bronze), var(--patina-dim), var(--gilt-dim), var(--ink)); position: relative; cursor: pointer; transition: filter 0.2s; }
.avatar-img:hover { filter: brightness(1.15); }
.avatar-img .placeholder { font-size: 28px; opacity: 0.6; }
.avatar-img img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
.avatar-overlay { position: absolute; inset: 0; border-radius: 50%; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; opacity: 0; transition: opacity 0.2s; }
.avatar-section:hover .avatar-overlay { opacity: 1; }
.avatar-overlay .upload-label { display: flex; align-items: center; gap: 3px; color: #fff; font-size: 10px; cursor: pointer; }
.avatar-overlay .upload-icon { font-size: 20px; }
.avatar-name-badge { flex: 1; }
.identity-header { display: flex; align-items: flex-end; justify-content: space-between; }
.char-name { font-family: "Songti SC", serif; font-size: 20px; font-weight: 700; color: var(--fg); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.char-inner-name { font-size: 12px; color: var(--fg-dim); margin-top: 1px; }
/* ── 档案信息网格 ── */
.info-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 20px; margin-top: 14px; }
.info-item .label { font-size: 12px; color: var(--muted); }
.info-item .value { font-size: 14px; font-weight: 500; color: var(--fg); }
.quote { font-style: italic; color: var(--fg-dim); font-size: 14px; margin-top: 12px; padding-left: 10px; border-left: 2px solid var(--gilt-dim); }
.bio-section { margin-top: 14px; border-top: 1px solid var(--rule); padding-top: 14px; }
.bio-section .label { font-size: 12px; color: var(--muted); margin-bottom: 4px; }
.bio-section .text { font-size: 14px; line-height: 1.7; color: var(--fg); white-space: pre-wrap; }
/* ── 双列布局 ── */
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
/* ── 表单 ── */
.form-card .card-header { display: flex; align-items: center; justify-content: space-between; padding: 14px 20px 0; }
.form-card .card-title { font-family: "Songti SC", serif; font-size: 15px; font-weight: 600; color: var(--fg); display: flex; align-items: center; gap: 6px; }
.form-card .card-title .glyph { color: var(--cinnabar); opacity: 0.7; }
.form-body { padding: 14px 20px 20px; }
.field { margin-bottom: 12px; }
.field-row { 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: 64px; resize: vertical; }
.field-hint { font-size: 11px; color: var(--fg-faint); margin-top: 3px; }
.btn-save { display: inline-flex; align-items: center; gap: 5px; padding: 6px 16px; border-radius: 10px; font-size: 12px; font-weight: 500; border: 1px solid var(--patina-dim); background: var(--patina-wash); color: var(--patina); cursor: pointer; transition: background 0.12s; font-family: inherit; }
.btn-save:hover { background: var(--patina-dim); color: var(--fg); }
.btn-save:disabled { opacity: 0.4; cursor: default; }
/* ── Tag 输入模拟 ── */
.tag-input-mock { display: flex; flex-wrap: wrap; gap: 4px; padding: 6px 10px; border: 1px solid var(--rule); border-radius: 10px; background: var(--glass); min-height: 34px; align-items: center; }
/* ── Modal ── */
.modal-overlay { position: fixed; inset: 0; z-index: 100; background: rgba(0,0,0,0.55); backdrop-filter: blur(6px); display: flex; align-items: center; justify-content: center; padding: 20px; }
.modal { background: var(--ink); border: 1px solid var(--rule); border-radius: 18px; width: 100%; max-width: 420px; box-shadow: 0 12px 60px rgba(0,0,0,0.6); }
.modal-header { display: flex; align-items: center; gap: 12px; padding: 18px 22px 10px; border-bottom: 1px solid var(--rule); }
.modal-title { font-family: "Songti SC", serif; font-size: 16px; font-weight: 600; color: var(--fg); flex: 1; }
.modal-close { width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; border-radius: 8px; cursor: pointer; border: none; background: none; color: var(--fg-faint); font-size: 18px; transition: background 0.12s; }
.modal-close:hover { background: var(--surface-hi); color: var(--fg); }
.modal-body { padding: 18px 22px 22px; }
/* ── Toast ── */
.toast { position: fixed; bottom: 24px; right: 24px; z-index: 200; display: flex; align-items: center; gap: 8px; padding: 10px 16px; border-radius: 12px; border: 1px solid var(--patina-dim); background: var(--surface); backdrop-filter: blur(12px); font-size: 13px; color: var(--patina); box-shadow: 0 4px 24px rgba(0,0,0,0.5); }
/* ── Responsive ── */
@media (max-width: 768px) {
.app-main { padding: 16px 14px 40px; }
.two-col { grid-template-columns: 1fr; }
.info-grid { grid-template-columns: 1fr; }
.field-row { 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">
<!-- ═══ 面包屑 ═══ -->
<a class="back-link" href="characters-preview.html">← 返回人物列表</a>
<!-- ═══ 页头 ═══ -->
<h1 class="page-title">时崎狂三</h1>
<p class="page-sub">内部名称:tokisaki_kurumi · 创建于 2026-07-09 14:32:18</p>
<!-- ═══ 操作栏 ═══ -->
<div class="action-bar">
<span class="badge active">● active</span>
<span class="lifecycle-bar">
<span class="lifecycle-step past">无极</span><span class="lifecycle-arrow">→</span>
<span class="lifecycle-step past">立名</span><span class="lifecycle-arrow">→</span>
<span class="lifecycle-step past">设定</span><span class="lifecycle-arrow">→</span>
<span class="lifecycle-step past">初识</span><span class="lifecycle-arrow">→</span>
<span class="lifecycle-step current">太极</span><span class="lifecycle-arrow">→</span>
<span class="lifecycle-step">归档</span>
</span>
<a class="action-link" href="#">资料与沉淀 →</a>
</div>
<!-- ═══ 角色身份卡 ═══ -->
<div class="card">
<div class="card-banner"></div>
<div class="card-body">
<!-- 头像:预留图片 -->
<div class="avatar-section" onclick="document.getElementById('modal-upload').style.display='flex'">
<div class="avatar-img">
<span class="placeholder">☯</span>
</div>
<div class="avatar-overlay">
<span class="upload-label">
<span class="upload-icon">📷</span>
更换头像
</span>
</div>
</div>
<div class="identity-header">
<div>
<div class="char-name">时崎狂三</div>
<div class="char-inner-name">内部名称:tokisaki_kurumi</div>
</div>
<span class="badge active">● active</span>
</div>
<div class="info-grid">
<div class="info-item"><div class="label">生日</div><div class="value">2000-12-25</div></div>
<div class="info-item"><div class="label">身高</div><div class="value">157 cm</div></div>
<div class="info-item"><div class="label">体重</div><div class="value">43 kg</div></div>
<div class="info-item"><div class="label">当前心情</div><div class="value">平静(42%)</div></div>
<div class="info-item"><div class="label">语言</div><div class="value">zh-CN</div></div>
<div class="info-item"><div class="label">创建时间</div><div class="value">2026-07-09 14:32</div></div>
</div>
<div class="quote">「优雅从容的大小姐口气,语速中等偏慢…」</div>
<div class="bio-section">
<div class="label">背景</div>
<div class="text">
拥有时间之力的精灵「Nightmare(梦魇)」。
为了某个终极目标在时间洪流中独自前行,通过吞噬他人的时间维持自己的存在。
她的过去充满了失去与痛苦,但她从不后悔自己选择的道路。
</div>
</div>
<div class="bio-section">
<div class="label">兴趣爱好</div>
<div class="tag-input-mock" style="margin-top:4px;">
<span class="tag">与猫相处</span>
<span class="tag">阅读</span>
<span class="tag">钢琴</span>
<span class="tag">收藏古董时钟</span>
<span class="tag">摄影</span>
<span class="tag">品尝红茶与甜点</span>
</div>
</div>
<div class="bio-section">
<div class="label">价值观</div>
<div class="tag-input-mock" style="margin-top:4px;">
<span class="tag">自由</span>
<span class="tag">尊严</span>
<span class="tag">独立</span>
<span class="tag">记忆</span>
</div>
</div>
</div>
</div>
<!-- ═══ 双列:档案编辑 + 模型策略 ═══ -->
<div class="two-col">
<!-- 左:人物档案编辑 -->
<div class="card form-card">
<div class="card-header">
<h2 class="card-title"><span class="glyph">📋</span> 人物档案</h2>
<button class="btn-save">✎ 保存</button>
</div>
<div class="form-body">
<div class="field">
<label class="field-label">显示名</label>
<input type="text" value="时崎狂三" />
</div>
<div class="field-row">
<div class="field">
<label class="field-label">生日</label>
<input type="date" value="2000-12-25" />
</div>
<div class="field">
<label class="field-label">身高</label>
<input type="text" value="157" />
</div>
</div>
<div class="field-row">
<div class="field">
<label class="field-label">体重</label>
<input type="text" value="43" />
</div>
<div class="field">
<label class="field-label">性情气质</label>
<input type="text" value="优雅腹黑、孤独偏执" />
</div>
</div>
<div class="field">
<label class="field-label">表达风格</label>
<input type="text" value="优雅从容的大小姐口气,语速中等偏慢" />
</div>
<div class="field">
<label class="field-label">背景</label>
<textarea>拥有时间之力的精灵「Nightmare(梦魇)」。</textarea>
</div>
</div>
</div>
<!-- 右:模型策略编辑 -->
<div class="card form-card">
<div class="card-header">
<h2 class="card-title"><span class="glyph">⚙</span> 模型策略</h2>
<button class="btn-save">✎ 保存</button>
</div>
<div class="form-body">
<div class="field">
<label class="field-label">对话模型</label>
<select>
<option>— 不设置(使用系统默认)</option>
<option selected>deepseek-v4-flash</option>
<option>deepseek-v3</option>
<option>gpt-4o</option>
</select>
<span class="field-hint">留空则使用 DEFAULT_MODEL_HINT</span>
</div>
<div class="field">
<label class="field-label">记忆提取模型</label>
<select>
<option>— 不设置(空)</option>
<option selected>memory-extraction</option>
<option>deepseek-v4-flash</option>
</select>
</div>
<div class="field">
<label class="field-label">人格分析模型</label>
<select>
<option>— 不设置(空)</option>
<option selected>personality-analysis</option>
<option>deepseek-v4-flash</option>
</select>
</div>
<div class="field">
<label class="field-label">向量嵌入模型</label>
<select>
<option>— 不设置(空)</option>
<option selected>embedding</option>
<option>text-embedding-3-small</option>
</select>
</div>
<div class="field">
<label class="field-label">私隐等级</label>
<select>
<option selected>normal</option>
<option>sensitive</option>
<option>local_only</option>
</select>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
<!-- ═══ 上传头像 Modal ═══ -->
<div class="modal-overlay" id="modal-upload" style="display:none;" onclick="if(event.target===this)this.style.display='none'">
<div class="modal">
<div class="modal-header">
<h3 class="modal-title">📷 上传头像</h3>
<button class="modal-close" onclick="document.getElementById('modal-upload').style.display='none'">✕</button>
</div>
<div class="modal-body" style="text-align:center;">
<!-- 预览区 -->
<div style="width:120px;height:120px;border-radius:50%;border:3px dashed var(--rule);margin:0 auto 16px;display:flex;align-items:center;justify-content:center;background:var(--glass);overflow:hidden;" id="preview-area">
<span style="font-size:36px;opacity:0.25;color:var(--fg-faint);">+</span>
</div>
<!-- 上传按钮 -->
<label class="btn btn-primary" style="display:inline-flex;cursor:pointer;">
📁 选择图片
<input type="file" accept="image/*" style="display:none;" onchange="previewFile(this)" />
</label>
<p style="font-size:11px;color:var(--fg-faint);margin-top:10px;">支持 JPG / PNG / WebP,建议 512×512 以上,最大 5MB</p>
<div style="display:flex;gap:8px;justify-content:center;margin-top:16px;">
<button class="btn btn-outline" onclick="document.getElementById('modal-upload').style.display='none'">取消</button>
<button class="btn btn-primary" onclick="showToast('✔ 头像已更新');document.getElementById('modal-upload').style.display='none'">✚ 上传</button>
</div>
</div>
</div>
</div>
<div class="toast" id="toast" style="display:none;">✔ 已保存</div>
<script>
function previewFile(input) {
const file = input.files && input.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(e) {
const area = document.getElementById('preview-area');
area.innerHTML = '<img src="' + e.target.result + '" style="width:100%;height:100%;object-fit:cover;" />';
};
reader.readAsDataURL(file);
}
function showToast(msg) {
const t = document.getElementById('toast');
t.textContent = msg;
t.style.display = 'flex';
setTimeout(function() { t.style.display = 'none'; }, 2500);
}
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') document.querySelectorAll('.modal-overlay').forEach(function(m) { m.style.display = 'none'; });
});
</script>
<script src="_theme.js" defer></script>
</body>
</html>