Files
jizhi/design/jizhi-theme-studio.html
2026-07-24 23:11:20 +08:00

125 lines
40 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">
<head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>记之 · 高保真配色实验室</title>
<style>
:root{--brand:#00b386;--deep:#009973;--soft:#e6f7f1;--bg:#f6f7f9;--card:#ffffff;--ink:#191f26;--muted:#5e6772;--faint:#9aa3ad;--line:#eef0f3;--ai:#5b6bf5;--aiSoft:#eef0fe;--expense:#f0642d;--expenseSoft:#fff3ec;--warning:#f5a623;--warningSoft:#fff7e8;--page:#edf0f2;--shadow:rgba(25,31,38,.12)}
*{box-sizing:border-box}body{margin:0;color:var(--ink);background:var(--page);font-family:"Noto Sans SC","Microsoft YaHei",sans-serif}.page{width:min(1380px,calc(100% - 32px));margin:auto;padding:52px 0 80px}.head{display:grid;grid-template-columns:1fr auto;align-items:end;gap:28px;margin:0 4px 34px}.kicker{margin-bottom:10px;color:var(--brand);font:800 11px "Noto Sans SC","Microsoft YaHei",sans-serif;letter-spacing:.16em}h1{margin:0;font-family:"Noto Serif SC","Songti SC",serif;font-size:clamp(38px,5vw,66px);line-height:1}.intro{max-width:700px;margin:17px 0 0;color:var(--muted);font-size:14px;line-height:1.75}.palette{display:flex;gap:9px;padding:13px;border:1px solid var(--line);border-radius:17px;background:#fff}.palette i{width:34px;height:34px;border:3px solid #fff;border-radius:50%;background:var(--c);box-shadow:0 0 0 1px var(--line)}
.grid{display:grid;grid-template-columns:repeat(3,minmax(360px,1fr));gap:26px 22px;align-items:start}.case{padding:17px 15px 21px;border:1px solid #dce3e0;border-radius:23px;background:#fff}.caseHead{display:flex;justify-content:space-between;width:min(100%,370px);margin:0 auto 14px}.idx{color:var(--brand);font:800 10px "Noto Sans SC","Microsoft YaHei",sans-serif;letter-spacing:.14em}.case h2{margin:5px 0 3px;font-size:20px}.note{color:var(--muted);font-size:11px}.tag{align-self:flex-start;padding:5px 9px;border:1px solid var(--brand);border-radius:999px;color:var(--brand);background:var(--soft);font-size:9px;font-weight:800}
.phone{position:relative;width:min(100%,370px);height:780px;margin:auto;overflow:hidden;border:7px solid #1d2422;border-radius:43px;background:var(--bg);box-shadow:0 18px 36px var(--shadow)}.status{display:flex;justify-content:space-between;height:34px;padding:8px 19px 0;font-size:10px;font-weight:800}.sys{letter-spacing:2px}.screen{height:calc(100% - 34px);overflow:hidden;padding:8px 16px 82px;background:var(--bg)}.top{display:flex;align-items:center;justify-content:space-between;min-height:42px;margin-bottom:12px}.title{font-size:16px;font-weight:800}.brand{display:flex;align-items:center;gap:9px}.logo{width:34px;height:34px;border:1px solid var(--line);border-radius:10px;object-fit:cover}.brand b{font-family:"Noto Serif SC","Songti SC",serif;font-size:18px}.micro,.sub{margin-top:2px;color:var(--muted);font-size:8px;line-height:1.45}.square{display:grid;width:31px;height:31px;place-items:center;border:1px solid var(--line);border-radius:10px;background:#fff;font-size:15px}.action{color:var(--brand);font-size:10px;font-weight:800}.panel{border:1px solid var(--line);border-radius:17px;background:#fff}.st{font-size:11px;font-weight:800}.link{color:var(--brand);font-size:8px;font-weight:800}.section{display:flex;justify-content:space-between;align-items:center;margin:13px 1px 4px}
.hero{padding:17px 18px;border-radius:19px;color:#fff;background:var(--brand)}.hero small{color:#d9efeb}.heroValue{margin:5px 0 14px;font:700 29px/1.1 "Noto Sans SC","Microsoft YaHei",sans-serif}.heroMeta{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.heroMeta span{color:#c9e6e0;font-size:8px}.heroMeta b{display:block;margin-top:3px;color:#fff;font:700 11px "Noto Sans SC","Microsoft YaHei",sans-serif}.quick{display:grid;grid-template-columns:repeat(4,1fr);gap:7px;margin:11px 0}.quick>div{padding:9px 2px 8px;border:1px solid var(--line);border-radius:14px;text-align:center;background:#fff}.qicon,.cicon,.ricon{display:grid;place-items:center;color:var(--brand);background:var(--soft)}.qicon{width:28px;height:28px;margin:0 auto 5px;border-radius:9px;font-size:13px}.quick span{font-size:8px;font-weight:700}.budget{display:grid;grid-template-columns:1fr auto;align-items:center;gap:12px;padding:12px 13px}.track{height:5px;margin-top:8px;overflow:hidden;border-radius:99px;background:var(--soft)}.track i{display:block;width:var(--w,63%);height:100%;background:var(--brand)}.budgetVal{color:var(--brand);font:800 16px "Noto Sans SC","Microsoft YaHei",sans-serif}
.tx{display:grid;grid-template-columns:34px 1fr auto;align-items:center;gap:9px;padding:9px 0;border-bottom:1px solid var(--line)}.cicon{width:34px;height:34px;border-radius:11px;font-size:12px;font-weight:800}.tx b{font-size:10px}.tx small{display:block;margin-top:2px;color:var(--muted);font-size:8px}.money{font:800 11px "Noto Sans SC","Microsoft YaHei",sans-serif}.out{color:var(--expense)}.income{color:var(--brand)}.nav{position:absolute;right:0;bottom:0;left:0;display:grid;grid-template-columns:repeat(4,1fr);height:68px;padding:8px 9px 9px;border-top:1px solid var(--line);background:#fff}.nav>div{display:grid;place-items:center;gap:2px;color:var(--faint);font-size:8px}.nav b{font-size:14px}.nav .on{color:var(--brand);font-weight:800}.nav .add{transform:translateY(-15px)}.fab{display:grid;width:42px;height:42px;place-items:center;border:4px solid var(--bg);border-radius:50%;color:#fff;background:var(--brand);box-shadow:0 7px 15px var(--shadow);font-size:20px}
.chat{display:grid;grid-template-rows:auto 1fr auto;padding:8px 13px 14px}.person{display:flex;align-items:center;gap:8px}.aiAvatar{display:grid;width:34px;height:34px;place-items:center;border-radius:11px;color:var(--ai);background:var(--aiSoft);font-size:16px}.online{color:var(--brand);font-size:8px}.log{overflow:hidden;padding:9px 3px}.stamp{margin-bottom:13px;color:var(--faint);font-size:8px;text-align:center}.msg{display:flex;gap:7px;margin-bottom:11px}.msg.me{justify-content:flex-end}.miniAI{display:grid;flex:0 0 25px;height:25px;place-items:center;border-radius:8px;color:var(--ai);background:var(--aiSoft);font-size:9px;font-weight:800}.bubble{max-width:77%;padding:10px 11px;border:1px solid var(--line);border-radius:6px 15px 15px 15px;background:#fff;font-size:10px;line-height:1.55}.me .bubble{border-color:var(--brand);border-radius:15px 6px 15px 15px;color:#fff;background:var(--brand)}.thinking{display:inline-flex;gap:6px;margin:0 0 11px 32px;padding:6px 9px;border-radius:99px;color:var(--ai);background:var(--aiSoft);font-size:8px;font-weight:700}.chatBill{margin:0 0 11px 32px;padding:11px;border-color:#cfd9e4}.billHead{display:flex;justify-content:space-between;margin-bottom:7px;color:var(--ai);font-size:8px;font-weight:800}.ok{padding:3px 7px;border-radius:99px;color:var(--brand);background:var(--soft)}.composer{display:grid;grid-template-columns:30px 1fr 30px 34px;align-items:center;gap:6px;padding:7px;border:1px solid var(--line);border-radius:18px;background:#fff}.composeBtn{display:grid;width:30px;height:30px;place-items:center;border:0;border-radius:10px;color:var(--muted);background:var(--bg)}.composeBtn.send{color:#fff;background:var(--brand)}.placeholder{color:var(--faint);font-size:9px}
.segments{display:grid;grid-template-columns:1fr 1fr;gap:4px;padding:4px;border:1px solid var(--line);border-radius:13px;background:#fff}.seg{padding:9px;border-radius:9px;color:var(--muted);text-align:center;font-size:10px;font-weight:800}.seg.on{color:#fff;background:var(--brand)}.amount{padding:24px 0 18px;text-align:center}.amount small{color:var(--muted)}.amount b{display:block;margin-top:4px;color:var(--expense);font:700 38px/1.1 "Noto Sans SC","Microsoft YaHei",sans-serif}.cats{display:grid;grid-template-columns:repeat(4,1fr);gap:8px 6px;margin-top:10px}.cat{padding:7px 2px;border:1px solid transparent;border-radius:12px;text-align:center}.cat.on{border-color:var(--brand);background:var(--soft)}.cat .cicon{margin:0 auto 5px}.cat span{font-size:8px;font-weight:700}.form{margin-top:13px;padding:2px 13px}.formRow{display:grid;grid-template-columns:20px 67px 1fr 15px;align-items:center;gap:5px;min-height:42px;border-bottom:1px solid var(--line);font-size:9px}.formRow:last-child{border:0}.lab{color:var(--muted)}.val{text-align:right;font-weight:700}.primary{display:grid;width:100%;min-height:44px;margin-top:14px;place-items:center;border:0;border-radius:14px;color:#fff;background:var(--brand);font-size:11px;font-weight:800}
.months{display:flex;justify-content:center;gap:18px;margin:1px 0 11px;color:var(--muted);font-size:9px}.months b{color:var(--ink);font-size:11px}.metrics{display:grid;grid-template-columns:repeat(3,1fr);gap:7px}.metric{padding:11px 9px}.metric span{color:var(--muted);font-size:8px}.metric b{display:block;margin-top:5px;font:700 14px "Noto Sans SC","Microsoft YaHei",sans-serif}.chartCard{margin-top:10px;padding:13px}.barRow{display:grid;grid-template-columns:44px 1fr 43px;align-items:center;gap:7px;margin-top:10px;font-size:8px}.bar{height:7px;overflow:hidden;border-radius:99px;background:var(--soft)}.bar i{display:block;width:var(--w);height:100%;background:var(--brand)}.barRow b{font:700 9px "Noto Sans SC","Microsoft YaHei",sans-serif;text-align:right}.aiReport{margin-top:10px;padding:13px;border-color:#cfd9e4;background:var(--aiSoft)}.aiHead{color:var(--ai);font-size:9px;font-weight:800}.aiReport strong{display:block;margin-top:8px;font-size:12px;line-height:1.45}.aiReport p{margin:5px 0 0;color:var(--muted);font-size:8px;line-height:1.55}
.profile{display:grid;grid-template-columns:50px 1fr auto;align-items:center;gap:11px;padding:14px}.avatar{display:grid;width:50px;height:50px;place-items:center;border-radius:16px;color:#fff;background:var(--brand);font:800 20px serif}.profileName{font-size:14px;font-weight:800}.ledger{margin-top:10px;padding:13px}.ledgerTop{display:flex;justify-content:space-between}.ledgerName{display:flex;align-items:center;gap:8px;font-size:10px;font-weight:800}.dot{width:9px;height:9px;border-radius:3px;background:var(--brand)}.ledgerStats{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:11px}.ledgerStat{padding:9px;border-radius:10px;background:var(--bg)}.ledgerStat span{color:var(--muted);font-size:8px}.ledgerStat b{display:block;margin-top:3px;font:700 12px "Noto Sans SC","Microsoft YaHei",sans-serif}.settings{margin-top:10px;padding:0 13px}.setting{display:grid;grid-template-columns:31px 1fr auto;align-items:center;gap:9px;min-height:49px;border-bottom:1px solid var(--line)}.setting:last-child{border:0}.ricon{width:31px;height:31px;border-radius:10px;font-size:12px;font-weight:800}.ricon.ai{color:var(--ai);background:var(--aiSoft)}.setting b{font-size:10px}.setting p{margin:2px 0 0;color:var(--muted);font-size:8px}.chev{color:var(--faint)}
.captureState{display:flex;align-items:center;gap:9px;margin-bottom:10px;padding:10px 11px;color:var(--deep);background:var(--soft)}.stateMark{display:grid;width:25px;height:25px;place-items:center;border-radius:50%;color:#fff;background:var(--brand)}.captureState b{font-size:9px}.captureState p{margin:2px 0 0;color:var(--muted);font-size:8px}.warning{display:flex;gap:7px;margin-bottom:9px;padding:9px 10px;border:1px solid #f1d79e;border-radius:12px;color:var(--warning);background:var(--warningSoft);font-size:8px;line-height:1.45}.parsed{margin-bottom:9px;padding:12px}.parsedHead{display:flex;justify-content:space-between;margin-bottom:9px;font-size:9px;font-weight:800}.confidence{color:var(--brand);font-size:8px}.parsedMain{display:grid;grid-template-columns:38px 1fr auto;align-items:center;gap:9px}.parsedMain .cicon{width:38px;height:38px}.parsedAmount{color:var(--expense);font:800 16px "Noto Sans SC","Microsoft YaHei",sans-serif}.chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}.chip{padding:5px 7px;border:1px solid var(--line);border-radius:9px;color:var(--muted);background:var(--bg);font-size:8px}.captureFooter{position:absolute;right:13px;bottom:13px;left:13px}.captureFooter .primary{margin:0}
@media(max-width:1180px){.grid{grid-template-columns:repeat(2,minmax(350px,1fr))}}@media(max-width:790px){.page{width:min(100% - 18px,430px);padding:30px 0 52px}.head{grid-template-columns:1fr;gap:18px}.palette{justify-self:start}.grid{grid-template-columns:1fr;gap:18px}.case{padding:15px 9px 18px}.phone{height:760px}}
/* Theme studio controls. App mockup geometry stays unchanged. */
body{padding-left:326px;transition:padding-left .22s ease}.page{width:min(1380px,calc(100% - 36px));padding-top:42px}.studio{position:fixed;z-index:20;inset:0 auto 0 0;width:326px;overflow:auto;border-right:1px solid #dfe3e7;background:#fff;color:#191f26;box-shadow:8px 0 24px rgba(25,31,38,.06)}.studioInner{padding:22px 18px 28px}.studioBrand{display:flex;align-items:center;gap:11px;padding-bottom:18px;border-bottom:1px solid #eef0f3}.studioBrand img{width:42px;height:42px;border:1px solid #e6e9ed;border-radius:12px}.studioBrand b{display:block;font-size:15px}.studioBrand span{display:block;margin-top:3px;color:#7b8490;font-size:10px}.studioTitle{display:flex;align-items:end;justify-content:space-between;margin:20px 0 10px}.studioTitle b{font-size:12px}.studioTitle span{color:#8a939e;font-size:9px}.presets{display:grid;grid-template-columns:1fr 1fr;gap:7px}.preset{display:flex;align-items:center;gap:7px;min-height:38px;padding:7px 8px;border:1px solid #e7eaee;border-radius:11px;background:#fff;color:#303741;font:700 10px inherit;cursor:pointer}.preset:hover,.preset.active{border-color:var(--preview,#00b386);box-shadow:inset 0 0 0 1px var(--preview,#00b386)}.presetDot{width:17px;height:17px;border:4px solid var(--softPreview,#e6f7f1);border-radius:6px;background:var(--preview,#00b386)}.tokenGroups{display:grid;gap:15px;margin-top:18px}.tokenGroup{display:grid;gap:7px}.tokenGroup h3{margin:0;color:#89919b;font-size:9px;font-weight:800;letter-spacing:.08em}.tokenRow{display:grid;grid-template-columns:78px 31px 1fr;align-items:center;gap:8px}.tokenRow label{font-size:10px;font-weight:700}.tokenRow input[type=color]{width:31px;height:31px;padding:2px;border:1px solid #dfe3e7;border-radius:9px;background:#fff;cursor:pointer}.tokenRow input[type=color]::-webkit-color-swatch{border:0;border-radius:6px}.tokenRow input[type=text]{min-width:0;height:31px;padding:0 8px;border:1px solid #e1e5e9;border-radius:9px;outline:0;color:#424a55;background:#f8f9fa;font:700 10px ui-monospace,Consolas,monospace;text-transform:uppercase}.tokenRow input[type=text]:focus{border-color:#98a2ad;background:#fff}.tokenBlock{margin-bottom:5px;padding:9px 10px;border:1px solid #eef0f3;border-radius:12px;background:#fafbfc}.tokenSliders{display:grid;grid-template-columns:28px 1fr 26px 28px 1fr 26px 28px 1fr 26px;align-items:center;gap:4px;margin-top:7px}.tokenSliders label{font-size:8px;color:#89919b;font-weight:700}.tokenSliders span{font-size:8px;color:#424a55;font-weight:700;text-align:right}.tokenSliders input[type=range]{width:100%;height:4px;-webkit-appearance:none;appearance:none;background:#e1e5e9;border-radius:2px;outline:none;cursor:pointer}.tokenSliders input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:15px;height:15px;border:2px solid #fff;border-radius:50%;background:#424a55;box-shadow:0 1px 3px rgba(0,0,0,.18);cursor:pointer}.contrast{display:grid;gap:7px;margin-top:18px;padding:12px;border:1px solid #e7eaee;border-radius:13px;background:#f8f9fa}.contrastHead{display:flex;justify-content:space-between;font-size:10px;font-weight:800}.contrastGrid{display:grid;grid-template-columns:1fr 1fr;gap:6px}.contrastItem{padding:7px;border-radius:8px;background:#fff;font-size:8px}.contrastItem b{display:block;margin-top:2px;font-size:11px}.contrastItem.pass b{color:#14805e}.contrastItem.fail b{color:#c23e35}.studioActions{display:grid;grid-template-columns:1fr 1fr;gap:7px;margin-top:13px}.studioButton{min-height:38px;border:1px solid #dfe3e7;border-radius:11px;background:#fff;color:#303741;font:800 10px inherit;cursor:pointer}.studioButton.primaryAction{border-color:#20252b;color:#fff;background:#20252b}.studioHint{margin:12px 2px 0;color:#8b949f;font-size:9px;line-height:1.55}.toast{position:fixed;z-index:40;left:344px;bottom:22px;padding:10px 14px;border-radius:11px;color:#fff;background:#20252b;font-size:11px;opacity:0;pointer-events:none;transform:translateY(8px);transition:.2s}.toast.show{opacity:1;transform:none}.studioToggle{display:none;position:fixed;z-index:30;right:14px;bottom:14px;width:48px;height:48px;border:0;border-radius:15px;color:#fff;background:#20252b;font-size:18px;box-shadow:0 10px 24px rgba(25,31,38,.2)}
.panel,.quick>div,.square,.composer,.segments,.nav,.case{background:var(--card)}.screen,.phone{background:var(--bg)}.hero small,.heroMeta span{color:rgba(255,255,255,.78)}.aiReport,.thinking,.miniAI,.aiAvatar,.ricon.ai{background:var(--aiSoft)}.chatBill,.aiReport{border-color:var(--ai)}.warning{border-color:var(--warning)}.cicon.food{color:#d85b37;background:#fff0e9}.cicon.transit{color:#168f8a;background:#e7f7f5}.cicon.salary{color:#17855f;background:#e8f7f0}.cicon.shopping{color:#4078c9;background:#edf3fc}.cicon.housing{color:#9b7138;background:#f8f0e3}.cicon.gift{color:#c25174;background:#fbeaf0}.cicon.fun{color:#7e5fc4;background:#f1edfb}.cicon.cardcat{color:#5a6877;background:#eef1f4}.livePalette i{background:var(--swatch)}
@media(max-width:1500px) and (min-width:981px){.grid{grid-template-columns:repeat(2,minmax(350px,1fr))}}@media(max-width:980px){body{padding-left:0}.studio{transform:translateX(-104%);transition:transform .22s ease}.studio.open{transform:none}.studioToggle{display:grid;place-items:center}.toast{left:16px;bottom:76px}.page{width:min(100% - 18px,760px)}.grid{grid-template-columns:1fr}.head{grid-template-columns:1fr}.palette{justify-self:start}}
</style></head>
<body>
<aside class="studio" id="studio"><div class="studioInner">
<div class="studioBrand"><img src="frontend/assets/branding/jizhi-app-icon-centered.png" alt="记之"><div><b>记之主题编辑器</b><span>实时预览 · 不修改 App</span></div></div>
<div class="studioTitle"><b>快速方案</b><span>全部为纯色</span></div>
<div class="presets" id="presets"></div>
<div class="tokenGroups" id="tokenGroups"></div>
<div class="contrast"><div class="contrastHead"><span>可读性检查</span><span>WCAG 对比度</span></div><div class="contrastGrid" id="contrastGrid"></div></div>
<div class="studioActions"><button class="studioButton" id="resetTheme">恢复当前配色</button><button class="studioButton primaryAction" id="copyTheme">复制色板 JSON</button></div>
<p class="studioHint">颜色只保存在当前浏览器。拖动 H/S/L 滑块可按色相、饱和度、明度微调每个色值。分类图标保留独立颜色,避免所有账单都变成同一种色块。</p>
</div></aside>
<button class="studioToggle" id="studioToggle" aria-label="打开配色编辑器">🎨</button>
<div class="toast" id="toast">色板已复制</div><main class="page"><header class="head"><div><div class="kicker">JIZHI THEME STUDIO · LIVE</div><h1>记之 · 高保真配色实验室</h1><p class="intro">保持当前 App 的页面结构,只调整颜色。使用左侧面板实时修改品牌色、AI 色、背景、卡片、文字和语义色,六个页面会同步预览。全稿只使用纯色。</p></div><div class="palette livePalette"><i data-swatch="bg"></i><i data-swatch="card"></i><i data-swatch="brand"></i><i data-swatch="ai"></i><i data-swatch="ink"></i></div></header><section class="grid">
<article class="case"><header class="caseHead"><div><div class="idx">SCREEN 01</div><h2>首页 · 明细</h2><div class="note">结余、预算和今日账单</div></div><span class="tag">主视觉</span></header><div class="phone"><div class="status"><span>9:41</span><span class="sys">◢ ▰</span></div><div class="screen"><div class="top"><div class="brand"><img class="logo" src="frontend/assets/branding/jizhi-app-icon-centered.png"><div><b>记之</b><div class="micro">日常账本</div></div></div><div class="square">•••</div></div><section class="hero"><small>七月结余</small><div class="heroValue">¥ 4,286.50</div><div class="heroMeta"><span>收入<b>¥ 8,640</b></span><span>支出<b>¥ 4,353</b></span><span>共计<b>48 笔</b></span></div></section><div class="quick"><div><i class="qicon"></i><span>语音记账</span></div><div><i class="qicon"></i><span>拍照识别</span></div><div><i class="qicon"></i><span>截屏记账</span></div><div><i class="qicon"></i><span>问一问</span></div></div><section class="panel budget"><div><b class="st">本月预算</b><div class="sub">已使用 63%,当前节奏正常</div><div class="track"><i></i></div></div><div class="budgetVal">¥ 1,847</div></section><div class="section"><b class="st">今天</b><span class="link">全部明细</span></div><div class="tx"><div class="cicon food"></div><div><b>午餐</b><small>餐饮 · 12:26</small></div><div class="money out">- ¥28</div></div><div class="tx"><div class="cicon transit"></div><div><b>地铁</b><small>交通 · 08:41</small></div><div class="money out">- ¥4</div></div><div class="tx"><div class="cicon salary"></div><div><b>稿费到账</b><small>兼职 · 07:30</small></div><div class="money income">+ ¥680</div></div></div><nav class="nav"><div class="on"><b></b><span>明细</span></div><div><b></b><span>统计</span></div><div class="add"><div class="fab"></div><span>记一笔</span></div><div><b></b><span>我的</span></div></nav></div></article>
<article class="case"><header class="caseHead"><div><div class="idx">SCREEN 02</div><h2>AI 聊天</h2><div class="note">AI 色仅标识 AI 身份与状态</div></div></header><div class="phone"><div class="status"><span>9:41</span><span class="sys">◢ ▰</span></div><div class="screen chat"><div class="top"><div class="person"><div class="square"></div><div class="aiAvatar"></div><div><b class="title">小记</b><div class="online">已连接 · 日常账本</div></div></div><div class="square">•••</div></div><div class="log"><div class="stamp">今天 14:28</div><div class="msg me"><div class="bubble">今天兼职赚了 680 元,午饭花了 28。</div></div><div class="thinking">● 正在核对账本分类</div><div class="msg"><div class="miniAI"></div><div class="bubble">已识别到 2 笔:兼职收入 680 元、餐饮支出 28 元。</div></div><section class="panel chatBill"><div class="billHead"><span>✦ AI 入账结果</span><span class="ok">已记录</span></div><div class="tx"><div class="cicon salary"></div><div><b>兼职收入</b><small>今天 14:28</small></div><div class="money income">+ ¥680</div></div><div class="tx"><div class="cicon food"></div><div><b>午饭</b><small>餐饮 · 14:28</small></div><div class="money out">- ¥28</div></div></section><div class="msg"><div class="miniAI"></div><div class="bubble">本月收入是 8,640 元,结余 4,286.50 元。</div></div></div><div class="composer"><button class="composeBtn"></button><div class="placeholder">说说今天的收入或支出...</div><button class="composeBtn"></button><button class="composeBtn send"></button></div></div></div></article>
<article class="case"><header class="caseHead"><div><div class="idx">SCREEN 03</div><h2>记一笔</h2><div class="note">纯色切换、分类和确认操作</div></div></header><div class="phone"><div class="status"><span>9:41</span><span class="sys">◢ ▰</span></div><div class="screen"><div class="top"><div class="square"></div><div class="title">记一笔</div><span class="action">日常账本</span></div><div class="segments"><div class="seg on">支出</div><div class="seg">收入</div></div><div class="amount"><small>金额</small><b>¥ 28.00</b></div><b class="st">选择分类</b><div class="cats"><div class="cat on"><div class="cicon food"></div><span>餐饮</span></div><div class="cat"><div class="cicon shopping"></div><span>购物</span></div><div class="cat"><div class="cicon transit"></div><span>交通</span></div><div class="cat"><div class="cicon housing"></div><span>居住</span></div><div class="cat"><div class="cicon gift"></div><span>人情</span></div><div class="cat"><div class="cicon cardcat"></div><span>账单</span></div><div class="cat"><div class="cicon fun"></div><span>娱乐</span></div><div class="cat"><div class="cicon">•••</div><span>其他</span></div></div><section class="panel form"><div class="formRow"><span></span><span class="lab">备注</span><span class="val">园区食堂</span><span class="chev"></span></div><div class="formRow"><span></span><span class="lab">支付方式</span><span class="val">微信支付</span><span class="chev"></span></div><div class="formRow"><span></span><span class="lab">时间</span><span class="val">今天 12:26</span><span class="chev"></span></div></section><button class="primary">确认记账</button></div></div></article>
<article class="case"><header class="caseHead"><div><div class="idx">SCREEN 04</div><h2>统计 · 月报</h2><div class="note">业务图表使用品牌色,AI 摘要使用 AI 色</div></div></header><div class="phone"><div class="status"><span>9:41</span><span class="sys">◢ ▰</span></div><div class="screen"><div class="top"><div class="title">统计</div><div class="square"></div></div><div class="months"><span>六月</span><b>2026 年 7 月</b><span>八月</span></div><div class="metrics"><section class="panel metric"><span>收入</span><b class="income">¥8,640</b></section><section class="panel metric"><span>支出</span><b class="out">¥4,353</b></section><section class="panel metric"><span>结余</span><b>¥4,286</b></section></div><section class="panel chartCard"><div class="section" style="margin-top:0"><b class="st">支出分类</b><span class="link">共 48 笔</span></div><div class="barRow"><span>餐饮</span><div class="bar"><i style="--w:78%"></i></div><b>¥1,420</b></div><div class="barRow"><span>购物</span><div class="bar"><i style="--w:54%"></i></div><b>¥986</b></div><div class="barRow"><span>交通</span><div class="bar"><i style="--w:34%"></i></div><b>¥628</b></div><div class="barRow"><span>居住</span><div class="bar"><i style="--w:26%"></i></div><b>¥480</b></div></section><section class="panel chartCard"><div class="section" style="margin-top:0"><b class="st">预算进度</b><span class="budgetVal">63%</span></div><div class="sub">本月预算 ¥6,200,剩余 ¥1,847</div><div class="track"><i></i></div></section><section class="panel aiReport"><div class="aiHead">✦ 小记月报</div><strong>这个月花得更稳了,结余比上月多 12%</strong><p>餐饮支出下降 186 元,交通预算仍有 372 元可用。以上金额均来自当前账本。</p></section></div><nav class="nav"><div><b></b><span>明细</span></div><div class="on"><b></b><span>统计</span></div><div class="add"><div class="fab"></div><span>记一笔</span></div><div><b></b><span>我的</span></div></nav></div></article>
<article class="case"><header class="caseHead"><div><div class="idx">SCREEN 05</div><h2>我的</h2><div class="note">账号、账本和数据入口</div></div></header><div class="phone"><div class="status"><span>9:41</span><span class="sys">◢ ▰</span></div><div class="screen"><div class="top"><div class="title">我的</div><div class="square"></div></div><section class="panel profile"><div class="avatar"></div><div><div class="profileName">南浔</div><div class="sub">已连续记账 26 天</div></div><span class="chev"></span></section><section class="panel ledger"><div class="ledgerTop"><div class="ledgerName"><i class="dot"></i>日常账本</div><span class="link">切换</span></div><div class="ledgerStats"><div class="ledgerStat"><span>本月结余</span><b>¥4,286</b></div><div class="ledgerStat"><span>本月账单</span><b>48 笔</b></div></div></section><section class="panel settings"><div class="setting"><div class="ricon"></div><div><b>预算管理</b><p>本月剩余 ¥1,847</p></div><span class="chev"></span></div><div class="setting"><div class="ricon"></div><div><b>分类管理</b><p>自定义图标与排序</p></div><span class="chev"></span></div><div class="setting"><div class="ricon ai">AI</div><div><b>AI 伙伴</b><p>小记 · 理性陪伴</p></div><span class="chev"></span></div></section><section class="panel settings"><div class="setting"><div class="ricon"></div><div><b>账本管理</b><p>新建、重命名和切换</p></div><span class="chev"></span></div><div class="setting"><div class="ricon"></div><div><b>账号与数据</b><p>导出、密码与账号管理</p></div><span class="chev"></span></div></section></div><nav class="nav"><div><b></b><span>明细</span></div><div><b></b><span>统计</span></div><div class="add"><div class="fab"></div><span>记一笔</span></div><div class="on"><b></b><span>我的</span></div></nav></div></article>
<article class="case"><header class="caseHead"><div><div class="idx">SCREEN 06</div><h2>截屏识别确认</h2><div class="note">多账单、时间和分类确认</div></div></header><div class="phone"><div class="status"><span>9:41</span><span class="sys">◢ ▰</span></div><div class="screen" style="padding-bottom:68px"><div class="top"><div class="square"></div><div class="title">确认识别结果</div><span class="action">2 笔</span></div><section class="panel captureState"><div class="stateMark"></div><div><b>图片解析完成</b><p>请核对金额、分类和原始交易时间</p></div></section><div class="warning"><span></span><span>第 2 笔只识别到日期,已使用当前时间,可点击时间重新选择。</span></div><section class="panel parsed"><div class="parsedHead"><span>账单 1</span><span class="confidence">识别可信</span></div><div class="parsedMain"><div class="cicon food"></div><div><b>午餐</b><div class="sub">美团支付 · 餐饮</div></div><div class="parsedAmount">- ¥32.80</div></div><div class="chips"><span class="chip">餐饮</span><span class="chip">7月18日 12:36</span><span class="chip">修改</span></div></section><section class="panel parsed"><div class="parsedHead"><span>账单 2</span><span class="confidence" style="color:var(--warning)">需核对时间</span></div><div class="parsedMain"><div class="cicon shopping"></div><div><b>生活用品</b><div class="sub">支付宝 · 购物</div></div><div class="parsedAmount">- ¥86.50</div></div><div class="chips"><span class="chip">购物</span><span class="chip">今天 14:41</span><span class="chip">修改</span></div></section></div><div class="captureFooter"><button class="primary">确认保存 2 笔账单</button></div></div></article>
</section></main><script>
const tokenMeta = {
brand:['主品牌色','品牌与操作'], deep:['品牌深色','强调文字'], soft:['品牌浅底','选中背景'],
ai:['AI 标识色','AI 身份'], aiSoft:['AI 浅底','AI 卡片'], bg:['页面背景','App 底色'],
card:['卡片颜色','内容承载'], ink:['正文颜色','主文字'], muted:['次级文字','说明文字'],
faint:['弱文字','占位与图标'], line:['边框颜色','分割线'], expense:['支出颜色','金额与错误'],
warning:['警告颜色','需核对状态'], warningSoft:['警告浅底','提示背景']
};
const groups = [
['品牌与 AI',['brand','deep','soft','ai','aiSoft']],
['界面基础',['bg','card','ink','muted','faint','line']],
['业务语义',['expense','warning','warningSoft']]
];
const currentTheme = {brand:'#00B386',deep:'#009973',soft:'#E6F7F1',ai:'#5B6BF5',aiSoft:'#EEF0FE',bg:'#F6F7F9',card:'#FFFFFF',ink:'#191F26',muted:'#5E6772',faint:'#9AA3AD',line:'#EEF0F3',expense:'#F0642D',warning:'#F5A623',warningSoft:'#FFF7E8'};
const presets = [
{name:'当前薄荷',brand:'#00B386',deep:'#009973',soft:'#E6F7F1',ai:'#5B6BF5',aiSoft:'#EEF0FE',bg:'#F6F7F9',card:'#FFFFFF',ink:'#191F26',muted:'#5E6772',faint:'#9AA3AD',line:'#EEF0F3',expense:'#F0642D',warning:'#F5A623',warningSoft:'#FFF7E8'},
{name:'清晰蓝白',brand:'#2F6BFF',deep:'#2456D8',soft:'#EAF0FF',ai:'#4859B8',aiSoft:'#EEF0FA',bg:'#F5F7FA',card:'#FFFFFF',ink:'#172033',muted:'#667085',faint:'#98A2B3',line:'#E5E9F0',expense:'#D95040',warning:'#C88412',warningSoft:'#FFF5E3'},
{name:'暖纸橙棕',brand:'#C45D26',deep:'#9E451B',soft:'#FBECE4',ai:'#416A8A',aiSoft:'#EAF0F4',bg:'#F5F2EC',card:'#FFFEFB',ink:'#28231F',muted:'#746B62',faint:'#A39A91',line:'#E8E1D8',expense:'#C6473A',warning:'#A96A12',warningSoft:'#F8EDD9'},
{name:'墨黑工具',brand:'#25282C',deep:'#111315',soft:'#ECEEF0',ai:'#4967A9',aiSoft:'#EBEFF7',bg:'#F3F4F5',card:'#FFFFFF',ink:'#181A1D',muted:'#626A73',faint:'#9AA1A9',line:'#E3E6E9',expense:'#D24B3C',warning:'#B47717',warningSoft:'#F6EEDC'},
{name:'湖蓝青灰',brand:'#147D89',deep:'#0E626C',soft:'#E5F2F3',ai:'#536AA6',aiSoft:'#ECEFF8',bg:'#F3F6F6',card:'#FFFFFF',ink:'#192326',muted:'#647276',faint:'#98A3A6',line:'#E1E7E8',expense:'#D25443',warning:'#B87917',warningSoft:'#F7EFDC'},
{name:'柔和莓红',brand:'#B44B68',deep:'#913A53',soft:'#F9EAF0',ai:'#5668A9',aiSoft:'#ECEFF8',bg:'#F7F4F5',card:'#FFFFFF',ink:'#271D21',muted:'#74656B',faint:'#A5979D',line:'#EAE1E4',expense:'#C73F35',warning:'#B47717',warningSoft:'#F8EFDC'}
];
const root = document.documentElement;
const normalize = value => /^#[0-9a-f]{6}$/i.test(value) ? value.toUpperCase() : null;
/* HSL helpers */
function rgb(hex){const v=parseInt(hex.slice(1),16);return [(v>>16)&255,(v>>8)&255,v&255]}
function hslFromHex(hex){const[r,g,b]=rgb(hex).map(v=>v/255);const max=Math.max(r,g,b),min=Math.min(r,g,b);let h=0;const l=(max+min)/2;if(max!==min){const d=max-min;const s=l>.5?d/(2-max-min):d/(max+min);h=r===max?((g-b)/d+(g<b?6:0))/6:g===max?((b-r)/d+2)/6:((r-g)/d+4)/6;return[Math.round(h*360),Math.round(s*100),Math.round(l*100)]}return[0,0,Math.round(l*100)]}
function hexFromHsl(h,s,l){h/=360;s/=100;l/=100;const a=s*Math.min(l,1-l);const f=n=>{n=(n+h*12)%12;const t=Math.round((l-a*Math.max(-1,Math.min(n-3,9-n,1)))*255);return Math.max(0,Math.min(255,t))};return'#'+[f(0),f(8),f(4)].map(v=>v.toString(16).padStart(2,'0').toUpperCase()).join('')}
function luminance(hex){return rgb(hex).map(v=>{v/=255;return v<=.03928?v/12.92:Math.pow((v+.055)/1.055,2.4)}).reduce((sum,v,i)=>sum+v*[.2126,.7152,.0722][i],0)}
function ratio(a,b){const x=luminance(a),y=luminance(b);return (Math.max(x,y)+.05)/(Math.min(x,y)+.05)}
/* Core */
function setToken(key,value,persist=true){const hex=normalize(value);if(!hex)return false;root.style.setProperty('--'+key,hex);const color=document.querySelector(`[data-color="${key}"]`);const text=document.querySelector(`[data-text="${key}"]`);if(color)color.value=hex;if(text)text.value=hex;document.querySelectorAll(`[data-swatch="${key}"]`).forEach(el=>el.style.setProperty('--swatch',hex));if(persist)save();updateContrast();return true}
function applyTheme(theme,persist=true){Object.keys(tokenMeta).forEach(key=>setToken(key,theme[key]||currentTheme[key],false));document.querySelectorAll('.preset').forEach(button=>button.classList.toggle('active',button.dataset.name===theme.name));updateAllSliders();if(persist)save()}
function readTheme(){return Object.fromEntries(Object.keys(tokenMeta).map(key=>[key,getComputedStyle(root).getPropertyValue('--'+key).trim().toUpperCase()]))}
function save(){localStorage.setItem('jizhi-theme-studio',JSON.stringify(readTheme()))}
/* Render controls with HSL sliders per token */
function renderControls(){
document.getElementById('presets').innerHTML=presets.map(p=>`<button class="preset" data-name="${p.name}" style="--preview:${p.brand};--softPreview:${p.soft}"><i class="presetDot"></i>${p.name}</button>`).join('');
document.getElementById('tokenGroups').innerHTML=groups.map(([name,keys])=>`<section class="tokenGroup"><h3>${name}</h3>${keys.map(key=>`<div class="tokenBlock"><div class="tokenRow"><label>${tokenMeta[key][0]}</label><input type="color" data-color="${key}" aria-label="${tokenMeta[key][0]}"><input type="text" data-text="${key}" maxlength="7" aria-label="${tokenMeta[key][0]} HEX"></div><div class="tokenSliders"><label>色相</label><input type="range" data-hue="${key}" min="0" max="360" value="0" aria-label="色相"><span data-hue-val="${key}">0</span><label>饱和度</label><input type="range" data-sat="${key}" min="0" max="100" value="0" aria-label="饱和度"><span data-sat-val="${key}">0</span><label>明度</label><input type="range" data-lit="${key}" min="0" max="100" value="0" aria-label="明度"><span data-lit-val="${key}">0</span></div></div>`).join('')}</section>`).join('');
}
function updateSliders(key){
const el = document.querySelector(`[data-text="${key}"]`); if (!el) return;
const hex = normalize(el.value); if (!hex) return;
const [h,s,l] = hslFromHex(hex);
const kinds = ['hue','sat','lit'];
[h,s,l].forEach((v,i) => {
const slider = document.querySelector(`[data-${kinds[i]}="${key}"]`);
const span = document.querySelector(`[data-${kinds[i]}-val="${key}"]`);
if (slider) slider.value = v;
if (span) span.textContent = v;
});
}
function updateAllSliders(){Object.keys(tokenMeta).forEach(key=>updateSliders(key))}
function updateContrast(){const t=readTheme();const checks=[['正文 / 卡片',t.ink,t.card,4.5],['次文 / 卡片',t.muted,t.card,4.5],['白字 / 主色','#FFFFFF',t.brand,4.5],['支出 / 卡片',t.expense,t.card,3]];document.getElementById('contrastGrid').innerHTML=checks.map(([name,a,b,min])=>{const value=ratio(a,b);return `<div class="contrastItem ${value>=min?'pass':'fail'}"><span>${name}</span><b>${value.toFixed(2)} : 1</b></div>`}).join('')}
function toast(message){const el=document.getElementById('toast');el.textContent=message;el.classList.add('show');clearTimeout(window.toastTimer);window.toastTimer=setTimeout(()=>el.classList.remove('show'),1600)}
renderControls();
/* Events */
document.getElementById('presets').addEventListener('click',event=>{const button=event.target.closest('.preset');if(!button)return;const preset=presets.find(item=>item.name===button.dataset.name);applyTheme(preset);toast('已应用 '+preset.name)});
// color picker / hex text
document.getElementById('tokenGroups').addEventListener('input',event=>{const key=event.target.dataset.color||event.target.dataset.text;if(!key)return;setToken(key,event.target.value);updateSliders(key)});
document.getElementById('tokenGroups').addEventListener('change',event=>{const key=event.target.dataset.text;if(key&&!setToken(key,event.target.value)){event.target.value=readTheme()[key];toast('请输入 6 位十六进制颜色')}});
// H / S / L sliders —— build hex on the fly
document.getElementById('tokenGroups').addEventListener('input',event=>{
const kind = event.target.dataset.hue !== undefined ? 'hue' : event.target.dataset.sat !== undefined ? 'sat' : event.target.dataset.lit !== undefined ? 'lit' : null;
if (!kind) return;
const key = event.target.dataset[kind]; if (!key) return;
const hue = document.querySelector(`[data-hue="${key}"]`);
const sat = document.querySelector(`[data-sat="${key}"]`);
const lit = document.querySelector(`[data-lit="${key}"]`);
if (!hue || !sat || !lit) return;
const h = parseInt(hue.value), s = parseInt(sat.value), l = parseInt(lit.value);
const hex = hexFromHsl(h, s, l); if (!hex) return;
setToken(key, hex);
document.querySelector(`[data-color="${key}"]`).value = hex;
document.querySelector(`[data-hue-val="${key}"]`).textContent = h;
document.querySelector(`[data-sat-val="${key}"]`).textContent = s;
document.querySelector(`[data-lit-val="${key}"]`).textContent = l;
});
document.getElementById('resetTheme').addEventListener('click',()=>{localStorage.removeItem('jizhi-theme-studio');applyTheme({...currentTheme,name:'当前薄荷'});toast('已恢复当前 App 配色')});
document.getElementById('copyTheme').addEventListener('click',async()=>{await navigator.clipboard.writeText(JSON.stringify(readTheme(),null,2));toast('色板 JSON 已复制')});
document.getElementById('studioToggle').addEventListener('click',()=>document.getElementById('studio').classList.toggle('open'));
let stored=null;try{stored=JSON.parse(localStorage.getItem('jizhi-theme-studio'))}catch(_){stored=null}applyTheme(stored&&Object.keys(stored).length?stored:{...currentTheme,name:'当前薄荷'},false);
</script></body></html>