docs(design): §7 UI 改真实 token 视觉稿(替换字符画)
用 design/colors_and_type.css 真实色值(clay/sand 暖色浅色主题)做 HTML/CSS 还原稿,替换粗糙 ASCII:A 设备列表(在线绿点光晕/离线灰点+最后登录/本机标) + B 行尾 ⋯ 操作菜单(强制退出/清除登录信息危险红) + C 清除危险二次确认弹窗。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -43,6 +43,45 @@
|
||||
.back{display:inline-block;margin-bottom:24px;font-size:13px}
|
||||
.lvl{font-weight:700}
|
||||
.phase{font-weight:700;color:var(--accent)}
|
||||
/* —— UI 视觉稿:还原 app 暖色 token(浅色主题),嵌在暗色文档中作截图式预览 —— */
|
||||
.mock-wrap{display:flex;flex-wrap:wrap;gap:20px;margin:18px 0 6px}
|
||||
.mock{--m-bg:#FAF8F4;--m-surface:#FFFFFF;--m-sub:#F2EEE7;--m-fg1:#1F1C18;--m-fg2:#6B6253;--m-fg3:#8C8270;
|
||||
--m-accent:#B96A3D;--m-accentsub:#FAF3ED;--m-accentbd:#E6C7AC;--m-border:#E6DFD3;--m-ok:#5B8C5A;--m-danger:#C0533B;
|
||||
background:var(--m-bg);border-radius:20px;padding:18px;width:344px;box-shadow:0 10px 34px rgba(0,0,0,.4);border:1px solid rgba(0,0,0,.15)}
|
||||
.mock *{box-sizing:border-box}
|
||||
.mock .cap{font-size:11px;font-weight:700;letter-spacing:.05em;color:#b0a491;margin:0 0 11px;text-transform:uppercase}
|
||||
.mock .panel{background:var(--m-surface);border:1px solid var(--m-border);border-radius:14px;overflow:hidden}
|
||||
.mock .row{display:flex;align-items:center;gap:12px;padding:13px 14px;border-bottom:1px solid var(--m-border)}
|
||||
.mock .row:last-child{border-bottom:none}
|
||||
.mock .ava{width:38px;height:38px;border-radius:10px;background:var(--m-accentsub);display:flex;align-items:center;justify-content:center;font-size:18px;flex:none}
|
||||
.mock .meta{flex:1;min-width:0}
|
||||
.mock .nm{display:flex;align-items:center;gap:7px;font-size:14.5px;font-weight:600;color:var(--m-fg1)}
|
||||
.mock .badge{font-size:10px;font-weight:700;padding:1px 7px;border-radius:6px;background:var(--m-accentsub);color:var(--m-accent);border:1px solid var(--m-accentbd)}
|
||||
.mock .sub2{font-size:12px;color:var(--m-fg3);margin-top:3px}
|
||||
.mock .stat{display:flex;align-items:center;gap:5px;font-size:12px;font-weight:600;flex:none}
|
||||
.mock .dot{width:7px;height:7px;border-radius:50%}
|
||||
.mock .on{color:var(--m-ok)} .mock .on .dot{background:var(--m-ok);box-shadow:0 0 0 3px rgba(91,140,90,.18)}
|
||||
.mock .off{color:#a89e8e} .mock .off .dot{background:#cfc6b8}
|
||||
.mock .kebab{flex:none;width:28px;height:28px;border-radius:8px;display:flex;align-items:center;justify-content:center;color:var(--m-fg3);font-size:17px}
|
||||
.mock .kebab.act{background:var(--m-sub);color:var(--m-fg1)}
|
||||
.mock .foot{font-size:12px;color:var(--m-fg3);margin-top:12px;padding-left:2px}
|
||||
.mock .foot b{color:var(--m-accent);font-weight:700}
|
||||
.mock .menu{background:var(--m-surface);border:1px solid var(--m-border);border-radius:13px;padding:6px;box-shadow:0 12px 30px rgba(0,0,0,.16);width:216px;margin-top:6px}
|
||||
.mock .mi{display:flex;align-items:center;gap:11px;padding:10px 11px;border-radius:9px;font-size:13.5px;font-weight:500;color:var(--m-fg1)}
|
||||
.mock .mi .ic{font-size:14px;width:17px;text-align:center}
|
||||
.mock .mi.danger{color:var(--m-danger)}
|
||||
.mock .mi.sel{background:var(--m-sub)}
|
||||
.mock.dlg{display:flex;flex-direction:column;justify-content:center;background:linear-gradient(160deg,#efe7dc,#e6dccf)}
|
||||
.mock .sheet{background:var(--m-surface);border-radius:18px;padding:22px 20px;text-align:center;box-shadow:0 18px 50px rgba(31,28,24,.22)}
|
||||
.mock .warnico{width:48px;height:48px;border-radius:50%;background:rgba(192,83,59,.12);color:var(--m-danger);display:flex;align-items:center;justify-content:center;font-size:22px;margin:2px auto 13px}
|
||||
.mock .dt{font-size:16px;font-weight:700;color:var(--m-fg1)}
|
||||
.mock .dd{font-size:12.5px;color:var(--m-fg2);margin:9px 4px 18px;line-height:1.55}
|
||||
.mock .dd b{color:var(--m-fg1)}
|
||||
.mock .btns{display:flex;gap:10px}
|
||||
.mock .btn{flex:1;padding:11px;border-radius:999px;font-size:13.5px;font-weight:600;text-align:center}
|
||||
.mock .btn.ghost{background:var(--m-sub);color:var(--m-fg2)}
|
||||
.mock .btn.danger{background:var(--m-danger);color:#fff}
|
||||
.mock .pin{display:inline-block;font-size:10px;color:#b0a491;margin-left:6px}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -287,19 +326,78 @@ usage_device_daily(user_id, device_id, date, bytes_up, bytes_down, minutes_used)
|
||||
|
||||
<h2>7. 前端 UI(「我的 → 我的设备」)</h2>
|
||||
<p>沿用既有 <code>DevicesScreen</code> 卡片列表,行内信息扩展 + 行尾操作。颜色/字号/间距全走唯一真相源 token(<code>pangolin_theme</code>),不硬编码。</p>
|
||||
<pre>
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ [▦] MacBook Pro ● 在线 [ ⋯ ] │ ⋯ 菜单:
|
||||
│ macOS · v1.0.10 · 本机 │ ├ 强制退出
|
||||
├─────────────────────────────────────────────────────────────┤ └ 清除登录信息
|
||||
│ [▦] iPhone 15 ○ 离线 [ ⋯ ] │
|
||||
│ iOS · v1.0.9 · 最后登录 2 小时前 │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ [▦] Windows-PC ○ 离线 [ ⋯ ] │
|
||||
│ windows · v1.0.10 · 最后登录 3 天前 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
PRO 套餐最多 5 台设备同时在线 · 已用 3 / 5
|
||||
</pre>
|
||||
<div class="mock-wrap">
|
||||
|
||||
<!-- A · 设备列表 -->
|
||||
<div class="mock">
|
||||
<div class="cap">我的设备 · 列表</div>
|
||||
<div class="panel">
|
||||
<div class="row">
|
||||
<div class="ava">💻</div>
|
||||
<div class="meta">
|
||||
<div class="nm">MacBook Pro <span class="badge">本机</span></div>
|
||||
<div class="sub2">macOS · v1.0.10</div>
|
||||
</div>
|
||||
<div class="stat on"><span class="dot"></span>在线</div>
|
||||
<div class="kebab">⋯</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="ava">📱</div>
|
||||
<div class="meta">
|
||||
<div class="nm">iPhone 15</div>
|
||||
<div class="sub2">iOS · v1.0.9 · 最后登录 2 小时前</div>
|
||||
</div>
|
||||
<div class="stat off"><span class="dot"></span>离线</div>
|
||||
<div class="kebab act">⋯</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="ava">🖥️</div>
|
||||
<div class="meta">
|
||||
<div class="nm">DESKTOP-7F3K</div>
|
||||
<div class="sub2">windows · v1.0.10 · 最后登录 3 天前</div>
|
||||
</div>
|
||||
<div class="stat off"><span class="dot"></span>离线</div>
|
||||
<div class="kebab">⋯</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="foot">PRO 套餐最多 5 台同时在线 · 已用 <b>3 / 5</b></div>
|
||||
</div>
|
||||
|
||||
<!-- B · 行尾操作菜单 -->
|
||||
<div class="mock">
|
||||
<div class="cap">行尾 ⋯ 操作菜单</div>
|
||||
<div class="panel" style="border-radius:13px">
|
||||
<div class="row" style="border-bottom:none;background:#FAF3ED55">
|
||||
<div class="ava">📱</div>
|
||||
<div class="meta">
|
||||
<div class="nm">iPhone 15</div>
|
||||
<div class="sub2">iOS · v1.0.9</div>
|
||||
</div>
|
||||
<div class="kebab act">⋯</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="menu">
|
||||
<div class="mi"><span class="ic">⤴</span>强制退出<span class="pin">踢下线,设备留存</span></div>
|
||||
<div class="mi danger sel"><span class="ic">🗑</span>清除登录信息<span class="pin" style="color:#d09c8c">彻底移除</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- C · 危险二次确认 -->
|
||||
<div class="mock dlg">
|
||||
<div class="cap">清除登录信息 · 二次确认</div>
|
||||
<div class="sheet">
|
||||
<div class="warnico">⚠️</div>
|
||||
<div class="dt">清除「iPhone 15」?</div>
|
||||
<div class="dd">将从设备列表<b>彻底移除</b>此设备,并吊销其登录会话与数据面凭证。该设备需<b>重新登录</b>才能再次使用。</div>
|
||||
<div class="btns">
|
||||
<div class="btn ghost">取消</div>
|
||||
<div class="btn danger">清除</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<p class="small">↑ 用项目真实 token 配色(clay/sand 暖色浅色主题)的还原稿。三态:<b>A</b> 列表(在线=绿点光晕 / 离线=灰点 + 最后登录;本机带「本机」标)→ <b>B</b> 行尾 ⋯ 弹出菜单(强制退出 / 清除登录信息·危险红)→ <b>C</b> 清除前危险二次确认。强制退出走相同弹窗、文案改为「踢下线、设备保留」。</p>
|
||||
<ul>
|
||||
<li><b>model</b> <code>Device</code> 加 <code>clientVersion</code> / <code>online</code>(bool) / <code>lastLogin</code>(DateTime?)。</li>
|
||||
<li><b>设备身份</b>:弃用 <code>_kDeviceId='mac-001'</code>,首启生成 UUID v4 存 <code>flutter_secure_storage</code>;登录/注册请求体带 <code>device:{id,name,platform,client_version}</code>。</li>
|
||||
|
||||
Reference in New Issue
Block a user