t193:daemon UI 換 Wails——CIS 是硬要求,fyne 做不到
leo 2026-08-04 看過 v0.16.0 畫面後:
「功能都有了,但美感非常糟糕⋯⋯跟 CIS 完全無關,每個功能都開一個小小的 popup 視窗,
非常缺乏整體感,這要理解的是原始的技術選擇是否出錯?」
「我的要求是符合 CIS,在風格上跟 portal 一樣」
「CIS 已經提供規範,你做的連 Logo 都沒放上去,這跟美不美有關係嗎?
要求放進 CIS 是硬要求,你做為檢查有嗎?沒有怎麼交貨?」
## 我的兩個錯
1. **動工前沒提醒做不到**——decisions-summary.md:314 的 D-daemon-UI
是我 07-27 自己寫的調研(結論:fyne 全自繪、CSS 套不進去),寫完就沒再看。
今天動工前該查它卻直接開寫,浪費 leo 的時間與 token。
2. **沒做 CIS 檢查就交貨**——連 logo 都沒放。
## 換 Wails(WebView 殼)
前端就是 HTML/CSS ⇒ 可以直接用 portal 那份色票與 lockup。
- style.css 的色票/字體/紙張紋理**逐字取自** portal 的 :root
(matrix/arcrun:console-ui/public/portal/index.html),不自創任何顏色
- CIS lockup 官方 PNG,淺色 ink 版/深色 paper 版,切換規則同 portal
(避開 08-01 作廢的自產 SVG——字腔缺失)
- 對話框改**內嵌覆蓋層**,不再每個功能開一個小 popup
- 原生資料夾選擇器(macOS powerbox 會自動授予該資料夾存取權,
fyne 自繪 picker 拿不到;未來上 Mac App Store 是硬需求)
- 同步中的圓點會呼吸 ⇒ 看得出來在動(issue #17)
- 無帳號時是 onboarding 引導,不是空白面板
## 連線邏輯逐字沿用,不重寫
connect.go 的 normalizePortalURL/fetchConfigByLogin 取自 arcrun-tray/main.go,
含 t86 個資外洩事故的防線(不同實例=新增帳號,絕不覆蓋舊帳號的資料夾)。
今天已犯過一次「重寫別人修好的東西還修得更差」,不再犯第二次。
## 新增 check-cis.sh(交貨前必跑)
機械檢查六類:官方色票逐個到齊/**不准出現非 CIS 色**/logo 真的放進去/
不可用作廢 SVG/深色模式/字體與紙張紋理同 portal/app icon。
實跑 14 項全過。以後「沒跑過就不准交」。
⚠️ 未驗:實際畫面要 leo 開來看(我開不了視窗)。
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
@@ -0,0 +1,93 @@
|
||||
Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com),
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 136 KiB |
@@ -0,0 +1,163 @@
|
||||
// Arcrun 桌面 App — 前端(t193)
|
||||
//
|
||||
// 全部畫面都在**同一個視窗**裡:狀態、清單、設定都用內嵌覆蓋層,
|
||||
// 不再像 fyne 版那樣「每個功能開一個小小的 popup」(leo 08-04 點破)。
|
||||
import './style.css';
|
||||
|
||||
const go = window.go.main.App;
|
||||
const $ = (id) => document.getElementById(id);
|
||||
|
||||
// 跟隨系統深淺色——CIS 兩套色票都定義好了,這裡只負責切 data-theme
|
||||
const mq = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
const applyTheme = () =>
|
||||
document.documentElement.setAttribute('data-theme', mq.matches ? 'dark' : 'light');
|
||||
mq.addEventListener('change', applyTheme);
|
||||
applyTheme();
|
||||
|
||||
// ── 覆蓋層(取代 popup 視窗)──
|
||||
function openSheet(html, wire) {
|
||||
$('sheet').innerHTML = html;
|
||||
$('overlay').classList.add('on');
|
||||
if (wire) wire();
|
||||
}
|
||||
function closeSheet() { $('overlay').classList.remove('on'); }
|
||||
$('overlay').addEventListener('click', (e) => { if (e.target.id === 'overlay') closeSheet(); });
|
||||
document.addEventListener('keydown', (e) => { if (e.key === 'Escape') closeSheet(); });
|
||||
|
||||
const esc = (s) => String(s).replace(/[&<>"]/g, (c) =>
|
||||
({ '&': '&', '<': '<', '>': '>', '"': '"' }[c]));
|
||||
|
||||
// ── 主畫面渲染 ──
|
||||
let state = null;
|
||||
|
||||
function render(s) {
|
||||
state = s;
|
||||
$('ver').textContent = s.version ? '版本 ' + s.version : '';
|
||||
$('statusBig').textContent = s.statusBig;
|
||||
$('statusBig').classList.toggle('syncing', !!s.syncing);
|
||||
$('statusSub').textContent = s.statusSub;
|
||||
|
||||
const list = $('list');
|
||||
if (!s.accounts || s.accounts.length === 0) {
|
||||
// 空狀態=onboarding,不是空白面板
|
||||
list.innerHTML = `
|
||||
<div class="empty">
|
||||
<div class="t">先連上你的知識庫</div>
|
||||
<div class="d">
|
||||
Arcrun 會看守你指定的資料夾,<br/>
|
||||
自動把文件整理成 AI 查得到的知識卡。<br/>
|
||||
還沒有知識庫?先到 install.arcrun.dev 裝一個(免費)。
|
||||
</div>
|
||||
<button class="primary" id="obConnect">新增知識庫帳號</button>
|
||||
<button id="obInstall">我還沒有知識庫</button>
|
||||
</div>`;
|
||||
$('obConnect').onclick = showConnect;
|
||||
$('obInstall').onclick = () => go.OpenURL('https://install.arcrun.dev/');
|
||||
return;
|
||||
}
|
||||
|
||||
list.innerHTML = s.accounts.map((a) => `
|
||||
<div class="acct"><span class="name">${esc(a.name)}</span><span class="host">${esc(a.host)}</span></div>
|
||||
${(a.folders || []).map((f) => `
|
||||
<div class="folder">
|
||||
<span class="path" title="${esc(f.path)}">${esc(f.path)}</span>
|
||||
<span class="tag">自動同步中</span>
|
||||
<button class="ghost" data-rm="${esc(f.path)}" data-acc="${f.accIdx}">移除</button>
|
||||
</div>`).join('')
|
||||
|| `<div class="folder"><span class="path dim">還沒有資料夾——按下面的「加入資料夾」</span></div>`}
|
||||
`).join('');
|
||||
|
||||
list.querySelectorAll('[data-rm]').forEach((b) => {
|
||||
b.onclick = () => confirmRemove(Number(b.dataset.acc), b.dataset.rm);
|
||||
});
|
||||
}
|
||||
|
||||
async function tick() {
|
||||
try { render(await go.GetState()); } catch (e) { /* 後端還沒起來,下一輪再試 */ }
|
||||
}
|
||||
|
||||
// ── 動作 ──
|
||||
$('btnSync').onclick = async () => { await go.SyncNow(); tick(); };
|
||||
|
||||
$('btnAddFolder').onclick = async () => {
|
||||
if (!state || !state.accounts.length) { showConnect(); return; }
|
||||
const p = await go.PickFolder(); // 系統原生面板(macOS powerbox 會授權)
|
||||
if (!p) return;
|
||||
await go.AddFolder(0, p);
|
||||
tick();
|
||||
};
|
||||
|
||||
function confirmRemove(accIdx, path) {
|
||||
openSheet(`
|
||||
<h2>移除這個資料夾?</h2>
|
||||
<p>「${esc(path)}」不再自動同步。<br/>已經上傳的知識卡不會被刪除。</p>
|
||||
<div class="acts">
|
||||
<button id="c1">取消</button>
|
||||
<button class="primary" id="c2">移除</button>
|
||||
</div>`, () => {
|
||||
$('c1').onclick = closeSheet;
|
||||
$('c2').onclick = async () => { await go.RemoveFolder(accIdx, path); closeSheet(); tick(); };
|
||||
});
|
||||
}
|
||||
|
||||
function showConnect() {
|
||||
openSheet(`
|
||||
<h2>連上你的知識庫</h2>
|
||||
<p>貼上你的知識庫網址,再輸入你在網站上設定的帳號密碼。</p>
|
||||
<label>知識庫網址</label>
|
||||
<input type="text" id="u" placeholder="https://arcrun-cypher-executor.xxxx.workers.dev"/>
|
||||
<label>帳號(Email)</label>
|
||||
<input type="text" id="e" placeholder="you@example.com"/>
|
||||
<label>密碼</label>
|
||||
<input type="password" id="p"/>
|
||||
<div class="err" id="err" style="display:none"></div>
|
||||
<div class="acts">
|
||||
<button id="c1">取消</button>
|
||||
<button class="primary" id="c2">連線</button>
|
||||
</div>`, () => {
|
||||
$('c1').onclick = closeSheet;
|
||||
$('c2').onclick = async () => {
|
||||
const err = $('err');
|
||||
try {
|
||||
await go.Connect($('u').value.trim(), $('e').value.trim(), $('p').value);
|
||||
closeSheet(); tick();
|
||||
} catch (ex) {
|
||||
err.textContent = String(ex); err.style.display = 'block';
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
$('btnAddAccount').onclick = showConnect;
|
||||
|
||||
$('btnAI').onclick = () => {
|
||||
const gem = state && state.engine === 'gemma';
|
||||
openSheet(`
|
||||
<h2>用哪個 AI 幫你整理文件?</h2>
|
||||
<label class="radio"><input type="radio" name="ai" value="cloud" ${gem ? '' : 'checked'}/>
|
||||
<span><b>雲端 AI</b>(推薦・不必申請任何金鑰)<br/>
|
||||
<span class="muted">用你自己 Cloudflare 帳號內建的 AI,不需要任何金鑰。</span></span></label>
|
||||
<label class="radio"><input type="radio" name="ai" value="gemini" ${gem ? 'checked' : ''}/>
|
||||
<span><b>Google Gemini</b>(需要自己申請金鑰)</span></label>
|
||||
<label>Gemini 金鑰${state && state.geminiKey ? '(目前已設定,清空即可刪除)' : ''}</label>
|
||||
<input type="text" id="k" placeholder="貼上你的 Gemini API Key"/>
|
||||
<div class="err" id="err" style="display:none"></div>
|
||||
<div class="acts">
|
||||
<button id="c1">取消</button>
|
||||
<button class="primary" id="c2">儲存</button>
|
||||
</div>`, () => {
|
||||
$('c1').onclick = closeSheet;
|
||||
$('c2').onclick = async () => {
|
||||
const useGemini = document.querySelector('input[name=ai]:checked').value === 'gemini';
|
||||
const err = $('err');
|
||||
try {
|
||||
await go.SetAI(useGemini, $('k').value.trim());
|
||||
closeSheet(); tick();
|
||||
} catch (ex) { err.textContent = String(ex); err.style.display = 'block'; }
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
$('btnUpdate').onclick = () => go.OpenURL('https://rag.arcrun.dev/docs/use/update/');
|
||||
|
||||
tick();
|
||||
setInterval(tick, 1000); // 每秒刷新 ⇒ 同步中看得到在動
|
||||
@@ -0,0 +1,150 @@
|
||||
/* Arcrun 桌面 App — 樣式(t193)
|
||||
*
|
||||
* 🔴 leo 2026-08-04:「我的要求是**符合 CIS**,在風格上**跟 portal 一樣**」
|
||||
* 「CIS 已經提供規範,你做的**連 Logo 都沒放上去**,這跟美不美有關係嗎?
|
||||
* 要求放進 CIS 是**硬要求**,你做為檢查有嗎?沒有怎麼交貨?」
|
||||
*
|
||||
* ⇒ 本檔的色票/字體/背景紋理**逐字取自 portal**
|
||||
* (matrix/arcrun:console-ui/public/portal/index.html 的 :root 區塊),
|
||||
* **不自創任何顏色**。要改就去改 portal 那份、再同步過來。
|
||||
*
|
||||
* 這也是換掉 fyne 的理由:fyne 全自繪、CSS 套不進去,
|
||||
* 換成 Wails(WebView)後 daemon 與 portal 才可能是**同一套視覺**。
|
||||
*/
|
||||
|
||||
:root {
|
||||
--paper-a: #FDFCFB; --paper-b: #F2F1ED;
|
||||
--ink: #17181A; --ink-rgb: 23,24,26;
|
||||
--amber: #B04A2F; --amber-rgb: 176,74,47;
|
||||
--ok: #1d7a48; --ok-rgb: 29,122,72;
|
||||
--err: #b03a26; --err-rgb: 176,58,38;
|
||||
--well: rgba(23,24,26,.06); --well2: rgba(23,24,26,.08);
|
||||
}
|
||||
:root[data-theme="dark"] {
|
||||
--paper-a: #1b1c1e; --paper-b: #1e1f21;
|
||||
--ink: #FDFCFB; --ink-rgb: 253,252,251;
|
||||
--amber: #D9784F; --amber-rgb: 217,120,79;
|
||||
--ok: #7fe0a8; --ok-rgb: 63,190,120;
|
||||
--err: #e58575; --err-rgb: 217,95,76;
|
||||
--well: rgba(0,0,0,.25); --well2: rgba(0,0,0,.3);
|
||||
}
|
||||
|
||||
/* portal 的紙張紋理背景——三站一致的識別(不是裝飾,是 CIS 的一部分) */
|
||||
html, body {
|
||||
margin: 0; height: 100%;
|
||||
background: repeating-linear-gradient(0deg,
|
||||
var(--paper-a) 0px, var(--paper-a) 3px,
|
||||
var(--paper-b) 3px, var(--paper-b) 4px);
|
||||
color: var(--ink);
|
||||
font-family: -apple-system, "IBM Plex Sans", "PingFang TC", "Noto Sans TC",
|
||||
"Microsoft JhengHei", system-ui, sans-serif;
|
||||
font-size: 16px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
overflow: hidden;
|
||||
}
|
||||
input, textarea, button, select { font-family: inherit; }
|
||||
::placeholder { color: rgba(var(--ink-rgb), .35); }
|
||||
input:focus, select:focus { outline: 2px solid rgba(var(--amber-rgb), .5); outline-offset: 1px; }
|
||||
a { color: var(--amber); }
|
||||
.muted { color: rgba(var(--ink-rgb), .55); }
|
||||
.dim { color: rgba(var(--ink-rgb), .4); }
|
||||
|
||||
/* ── 版面:上(品牌+狀態)/中(可捲清單)/下(動作列)── */
|
||||
#app { display: flex; flex-direction: column; height: 100vh; }
|
||||
|
||||
header {
|
||||
padding: 18px 24px 14px;
|
||||
border-bottom: 1px solid rgba(var(--ink-rgb), .1);
|
||||
display: flex; align-items: flex-start; gap: 20px;
|
||||
}
|
||||
/* CIS lockup:淺色用 ink 版、深色用 paper 版(與 portal 同一組 PNG、同一套切換規則)。
|
||||
⚠️ 不可用自產的 SVG 描邊版(字腔會缺,08-01 已作廢,見 arcrun-cis/README.md)。 */
|
||||
.brand img { height: 26px; display: block; }
|
||||
.brand .wm-paper { display: none; }
|
||||
:root[data-theme="dark"] .brand .wm-ink { display: none; }
|
||||
:root[data-theme="dark"] .brand .wm-paper { display: block; }
|
||||
|
||||
.status { flex: 1; min-width: 0; }
|
||||
.status .big { font-size: 17px; font-weight: 600; letter-spacing: .02em; }
|
||||
.status .sub { margin-top: 4px; font-size: 13.5px; color: rgba(var(--ink-rgb), .5); }
|
||||
/* 同步中會呼吸——「看得出來在動」(issue #17) */
|
||||
.status .big.syncing::after {
|
||||
content: ""; display: inline-block; width: 7px; height: 7px; margin-left: 9px;
|
||||
border-radius: 50%; background: var(--amber); vertical-align: middle;
|
||||
animation: pulse 1.1s ease-in-out infinite;
|
||||
}
|
||||
@keyframes pulse { 0%,100% { opacity: .25 } 50% { opacity: 1 } }
|
||||
|
||||
/* 按鈕:Relation 是**唯一重點色**,CIS 規定 ≤ 一個畫面的 5% ⇒ 只有主要動作用它 */
|
||||
button {
|
||||
border: 1px solid rgba(var(--ink-rgb), .16);
|
||||
background: transparent; color: var(--ink);
|
||||
padding: 8px 14px; border-radius: 8px; font-size: 14px; cursor: pointer;
|
||||
transition: background .12s, border-color .12s;
|
||||
}
|
||||
button:hover { background: var(--well); }
|
||||
button.primary {
|
||||
background: var(--amber); border-color: var(--amber);
|
||||
color: #FDFCFB; font-weight: 600;
|
||||
}
|
||||
button.primary:hover { filter: brightness(1.06); }
|
||||
button.ghost { border-color: transparent; color: rgba(var(--ink-rgb), .5); padding: 6px 8px; }
|
||||
button.ghost:hover { color: var(--err); background: transparent; }
|
||||
|
||||
/* ── 中:資料夾清單(leo:「幾十個,根本塞不下」⇒ 這一區才捲動)── */
|
||||
main { flex: 1; overflow-y: auto; padding: 6px 0; }
|
||||
|
||||
.acct {
|
||||
padding: 16px 24px 6px;
|
||||
display: flex; align-items: baseline; gap: 10px;
|
||||
}
|
||||
.acct .name { font-size: 15px; font-weight: 600; }
|
||||
.acct .host { font-size: 12.5px; color: rgba(var(--ink-rgb), .4); font-family: ui-monospace, Menlo, monospace; }
|
||||
|
||||
.folder {
|
||||
margin: 0 16px 6px; padding: 11px 14px;
|
||||
background: var(--well); border-radius: 10px;
|
||||
display: flex; align-items: center; gap: 12px;
|
||||
}
|
||||
.folder .path { flex: 1; min-width: 0; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.folder .tag { font-size: 12px; color: var(--ok); white-space: nowrap; }
|
||||
|
||||
/* 空狀態=onboarding(不是空白面板) */
|
||||
.empty { padding: 56px 32px; text-align: center; }
|
||||
.empty .t { font-size: 17px; font-weight: 600; margin-bottom: 10px; }
|
||||
.empty .d { font-size: 14px; color: rgba(var(--ink-rgb), .55); line-height: 1.9; margin-bottom: 22px; }
|
||||
|
||||
footer {
|
||||
padding: 12px 24px; border-top: 1px solid rgba(var(--ink-rgb), .1);
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
}
|
||||
footer .spacer { flex: 1; }
|
||||
footer .ver { font-size: 12.5px; color: rgba(var(--ink-rgb), .35); font-family: ui-monospace, Menlo, monospace; }
|
||||
|
||||
/* 對話框:**內嵌覆蓋層**,不是另開一個小 popup 視窗
|
||||
(leo:「每個功能都開一個小小的 popup 視窗,非常缺乏整體感」) */
|
||||
.overlay {
|
||||
position: fixed; inset: 0; background: rgba(0,0,0,.42);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
opacity: 0; pointer-events: none; transition: opacity .14s;
|
||||
}
|
||||
.overlay.on { opacity: 1; pointer-events: auto; }
|
||||
.sheet {
|
||||
width: min(520px, calc(100vw - 64px));
|
||||
background: var(--paper-a); color: var(--ink);
|
||||
border: 1px solid rgba(var(--ink-rgb), .12);
|
||||
border-radius: 14px; padding: 24px;
|
||||
box-shadow: 0 18px 50px rgba(0,0,0,.28);
|
||||
}
|
||||
.sheet h2 { margin: 0 0 6px; font-size: 17px; }
|
||||
.sheet p { margin: 0 0 16px; font-size: 14px; color: rgba(var(--ink-rgb), .55); line-height: 1.7; }
|
||||
.sheet label { display: block; font-size: 13px; margin: 12px 0 5px; color: rgba(var(--ink-rgb), .6); }
|
||||
.sheet input[type=text], .sheet input[type=password] {
|
||||
width: 100%; box-sizing: border-box; padding: 9px 11px; font-size: 14px;
|
||||
border: 1px solid rgba(var(--ink-rgb), .18); border-radius: 8px;
|
||||
background: var(--paper-b); color: var(--ink);
|
||||
}
|
||||
.sheet .radio { display: flex; align-items: flex-start; gap: 9px; margin: 10px 0; font-size: 14px; cursor: pointer; }
|
||||
.sheet .radio input { margin-top: 3px; }
|
||||
.sheet .acts { display: flex; justify-content: flex-end; gap: 8px; margin-top: 22px; }
|
||||
.sheet .err { color: var(--err); font-size: 13px; margin-top: 10px; }
|
||||
Reference in New Issue
Block a user