@tensorix/metahub 0.5.4 → 0.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +677 -155
- package/dist/cli.js.map +23 -17
- package/dist/core/copy-views.d.ts +3 -0
- package/dist/core/copy-views.d.ts.map +1 -0
- package/dist/core/csv-columns.d.ts +6 -0
- package/dist/core/csv-columns.d.ts.map +1 -0
- package/dist/core/databases.d.ts.map +1 -1
- package/dist/core/sync/auth.d.ts.map +1 -1
- package/dist/core/sync/cf-oauth.d.ts.map +1 -1
- package/dist/core/sync/files.d.ts.map +1 -1
- package/dist/core/sync/page-messages.d.ts +5 -0
- package/dist/core/sync/page-messages.d.ts.map +1 -1
- package/dist/core/sync/remote-shares-cache.d.ts.map +1 -1
- package/dist/core/sync/room-serve.d.ts.map +1 -1
- package/dist/core/sync/share-actions.d.ts.map +1 -1
- package/dist/core/sync/share-copy.d.ts +1 -1
- package/dist/core/sync/share-copy.d.ts.map +1 -1
- package/dist/core/sync/share-export.d.ts +4 -2
- package/dist/core/sync/share-export.d.ts.map +1 -1
- package/dist/core/sync/share-file-styles.d.ts +2 -0
- package/dist/core/sync/share-file-styles.d.ts.map +1 -0
- package/dist/core/sync/share-link.d.ts +27 -0
- package/dist/core/sync/share-link.d.ts.map +1 -0
- package/dist/core/sync/share-serve.d.ts.map +1 -1
- package/dist/core/sync/share-short-links.d.ts +8 -0
- package/dist/core/sync/share-short-links.d.ts.map +1 -0
- package/dist/core/sync/sites-serve.d.ts.map +1 -1
- package/dist/core/ui-theme.d.ts +44 -0
- package/dist/core/ui-theme.d.ts.map +1 -0
- package/dist/db-worker.js +64 -64
- package/dist/edge-worker.js +137 -8
- package/dist/index.js +630 -131
- package/dist/index.js.map +20 -15
- package/dist/metahub-sdk.js +4 -4
- package/dist/mh-runtime.js +2 -2
- package/dist/sw.js +9 -6
- package/dist/webui/server/assets.d.ts.map +1 -1
- package/dist/webui.js +130 -130
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1168,6 +1168,45 @@ var init_crdt = __esm(() => {
|
|
|
1168
1168
|
]);
|
|
1169
1169
|
});
|
|
1170
1170
|
|
|
1171
|
+
// src/core/copy-views.ts
|
|
1172
|
+
function copyViews(raw, props, records, selfRelations) {
|
|
1173
|
+
if (!Array.isArray(raw))
|
|
1174
|
+
return raw;
|
|
1175
|
+
const object = (x) => !!x && typeof x === "object" && !Array.isArray(x);
|
|
1176
|
+
const prop = (x) => typeof x === "string" ? props.get(x) ?? x : x;
|
|
1177
|
+
return raw.map((v) => {
|
|
1178
|
+
if (!object(v))
|
|
1179
|
+
return v;
|
|
1180
|
+
const out = { ...v };
|
|
1181
|
+
for (const key of ["group", "dateProp", "start", "end"])
|
|
1182
|
+
if (key in out)
|
|
1183
|
+
out[key] = prop(out[key]);
|
|
1184
|
+
if (Array.isArray(v.hidden))
|
|
1185
|
+
out.hidden = v.hidden.map(prop);
|
|
1186
|
+
if (Array.isArray(v.sort))
|
|
1187
|
+
out.sort = v.sort.map((s) => object(s) ? { ...s, prop: prop(s.prop) } : s);
|
|
1188
|
+
if (object(v.filter) && Array.isArray(v.filter.rules))
|
|
1189
|
+
out.filter = {
|
|
1190
|
+
...v.filter,
|
|
1191
|
+
rules: v.filter.rules.map((r) => {
|
|
1192
|
+
if (!object(r))
|
|
1193
|
+
return r;
|
|
1194
|
+
return {
|
|
1195
|
+
...r,
|
|
1196
|
+
prop: prop(r.prop),
|
|
1197
|
+
...typeof r.prop === "string" && selfRelations.has(r.prop) && Array.isArray(r.value) ? { value: r.value.map((id) => typeof id === "string" ? records.get(id) ?? id : id) } : {}
|
|
1198
|
+
};
|
|
1199
|
+
})
|
|
1200
|
+
};
|
|
1201
|
+
if (object(v.calc))
|
|
1202
|
+
out.calc = Object.fromEntries(Object.entries(v.calc).map(([id, value]) => [
|
|
1203
|
+
props.get(id) ?? id,
|
|
1204
|
+
value
|
|
1205
|
+
]));
|
|
1206
|
+
return out;
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1171
1210
|
// src/core/indexing.ts
|
|
1172
1211
|
function sanitize(s) {
|
|
1173
1212
|
return s.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
@@ -1458,10 +1497,6 @@ var init_databases = __esm(() => {
|
|
|
1458
1497
|
name: opts.name ?? src.name,
|
|
1459
1498
|
icon: opts.icon ?? src.icon ?? undefined
|
|
1460
1499
|
});
|
|
1461
|
-
if (src.meta !== null) {
|
|
1462
|
-
const { collapsed: _hidden, ...meta } = src.meta;
|
|
1463
|
-
emitMetaPatch(db, dup.id, null, meta);
|
|
1464
|
-
}
|
|
1465
1500
|
const propIdMap = new Map;
|
|
1466
1501
|
const selfRelNew = new Set;
|
|
1467
1502
|
for (const p of listProperties(db, id)) {
|
|
@@ -1496,6 +1531,12 @@ var init_databases = __esm(() => {
|
|
|
1496
1531
|
if (Object.keys(patch).length)
|
|
1497
1532
|
updateRecord(db, recIdMap.get(r.id), patch);
|
|
1498
1533
|
}
|
|
1534
|
+
if (src.meta !== null) {
|
|
1535
|
+
const { collapsed: _hidden, ...meta } = src.meta;
|
|
1536
|
+
if ("views" in meta)
|
|
1537
|
+
meta.views = copyViews(meta.views, propIdMap, recIdMap, new Set(listProperties(db, id).filter((p) => p.type === "relation" && p.config?.database === id).map((p) => p.id)));
|
|
1538
|
+
emitMetaPatch(db, dup.id, null, meta);
|
|
1539
|
+
}
|
|
1499
1540
|
return getDatabase(db, dup.id);
|
|
1500
1541
|
});
|
|
1501
1542
|
deleteDatabase = grouped(function deleteDatabase(db, id) {
|
|
@@ -9348,7 +9389,7 @@ var package_default;
|
|
|
9348
9389
|
var init_package = __esm(() => {
|
|
9349
9390
|
package_default = {
|
|
9350
9391
|
name: "@tensorix/metahub",
|
|
9351
|
-
version: "0.5.
|
|
9392
|
+
version: "0.5.7",
|
|
9352
9393
|
description: "Metahub core library and CLI",
|
|
9353
9394
|
license: "AGPL-3.0-only",
|
|
9354
9395
|
type: "module",
|
|
@@ -13282,6 +13323,11 @@ var init_page_messages = __esm(() => {
|
|
|
13282
13323
|
"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u8F93\u5165\u4EE4\u724C\u3002": "Session expired. Enter the token again.",
|
|
13283
13324
|
\u{9644}\u{4ef6}\u{5df2}\u{5931}\u{6548}: "Attachment unavailable",
|
|
13284
13325
|
\u{94fe}\u{63a5}\u{7f3a}\u{5c11}\u{5206}\u{4eab}\u{6570}\u{636e}: "The link is missing share data",
|
|
13326
|
+
\u{65e0}\u{6cd5}\u{6253}\u{5f00}\u{8fd9}\u{4efd}\u{5206}\u{4eab}: "Unable to open this share",
|
|
13327
|
+
"\u8BF7\u4ECE\u539F\u6D88\u606F\u4E2D\u91CD\u65B0\u590D\u5236\u5B8C\u6574\u94FE\u63A5\uFF0C\u518D\u6253\u5F00\u8BD5\u8BD5\u3002": "Copy the full link from the original message, then open it again.",
|
|
13328
|
+
"\u5982\u679C\u4ECD\u7136\u65E0\u6CD5\u6253\u5F00\uFF0C\u8BF7\u8054\u7CFB\u5206\u4EAB\u8005\u91CD\u65B0\u53D1\u9001\u94FE\u63A5\u3002": "If it still won't open, ask the sender for a new link.",
|
|
13329
|
+
"\u8BF7\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5\u540E\u91CD\u8BD5\uFF0C\u6216\u8054\u7CFB\u5206\u4EAB\u8005\u786E\u8BA4\u94FE\u63A5\u662F\u5426\u4ECD\u7136\u6709\u6548\u3002": "Check your connection and try again, or ask the sender whether the link is still valid.",
|
|
13330
|
+
\u{91cd}\u{65b0}\u{52a0}\u{8f7d}: "Reload",
|
|
13285
13331
|
\u{8bf7}\u{8f93}\u{5165}\u{5206}\u{4eab}\u{53e3}\u{4ee4}: "Enter the share passcode",
|
|
13286
13332
|
\u{94fe}\u{63a5}\u{7f3a}\u{5c11}\u{5bc6}\u{94a5}: "The link is missing its key",
|
|
13287
13333
|
\u{53e3}\u{4ee4}\u{9519}\u{8bef}\u{6216}\u{94fe}\u{63a5}\u{5df2}\u{5931}\u{6548}: "Wrong passcode or the link has expired",
|
|
@@ -13496,6 +13542,92 @@ function getDropKnobs(db, siteId) {
|
|
|
13496
13542
|
}
|
|
13497
13543
|
var EXPECTED_EDGE_WORKER_VERSION = "3", CONFIG_KEY = "edge_config", DEPLOY_KEY = "edge_deploy_progress", KNOBS_PREFIX = "drop_knobs:", R2_PROVISION_KEY = "edge_r2_provision_progress";
|
|
13498
13544
|
|
|
13545
|
+
// src/core/ui-theme.ts
|
|
13546
|
+
var LIGHT_THEME, DARK_THEME, declarations = (palette) => Object.entries(palette).map(([k, v]) => `--${k}:${v};`).join(""), THEME_CSS, THEME_INIT_SCRIPT;
|
|
13547
|
+
var init_ui_theme = __esm(() => {
|
|
13548
|
+
LIGHT_THEME = {
|
|
13549
|
+
bg: "#ffffff",
|
|
13550
|
+
paper: "#ffffff",
|
|
13551
|
+
surface: "#fafaf9",
|
|
13552
|
+
"surface-2": "#f1f1ef",
|
|
13553
|
+
sidebar: "#f7f7f5",
|
|
13554
|
+
fg: "#37352f",
|
|
13555
|
+
"fg-soft": "#595750",
|
|
13556
|
+
muted: "#6f6d66",
|
|
13557
|
+
line: "#eae9e6",
|
|
13558
|
+
"line-strong": "#d8d7d3",
|
|
13559
|
+
accent: "#3867b2",
|
|
13560
|
+
"accent-fg": "#ffffff",
|
|
13561
|
+
"accent-soft": "#edf2f9",
|
|
13562
|
+
hover: "rgba(55,53,47,.035)",
|
|
13563
|
+
"hover-2": "rgba(55,53,47,.07)",
|
|
13564
|
+
"code-bg": "#f6f5f3",
|
|
13565
|
+
"selected-bg": "#f7f9fc",
|
|
13566
|
+
"selected-border": "#a8b8ce",
|
|
13567
|
+
"selected-icon-bg": "#edf2f8",
|
|
13568
|
+
"selected-icon-fg": "#4d678b",
|
|
13569
|
+
"selected-muted": "#626b78",
|
|
13570
|
+
"selected-hover-bg": "#f1f5fa",
|
|
13571
|
+
"selected-hover-border": "#8199bb",
|
|
13572
|
+
danger: "#b6423a",
|
|
13573
|
+
"danger-fg": "#ffffff",
|
|
13574
|
+
"danger-soft": "#f9eeec",
|
|
13575
|
+
success: "#347653",
|
|
13576
|
+
warning: "#866022",
|
|
13577
|
+
"warning-soft": "#faf3e5",
|
|
13578
|
+
"brand-purple": "#79619d",
|
|
13579
|
+
"brand-teal": "#397d76",
|
|
13580
|
+
"brand-orange": "#a06436",
|
|
13581
|
+
"shadow-sm": "0 1px 2px rgba(35,32,25,.035)",
|
|
13582
|
+
"shadow-md": "0 4px 14px rgba(35,32,25,.08)",
|
|
13583
|
+
"shadow-lg": "0 16px 48px rgba(35,32,25,.13)",
|
|
13584
|
+
"brand-stripe": "linear-gradient(to right,#335cff 0% 25%,#8967ed 25% 50%,#18b7b6 50% 75%,#f28b55 75% 100%)"
|
|
13585
|
+
};
|
|
13586
|
+
DARK_THEME = {
|
|
13587
|
+
bg: "#191919",
|
|
13588
|
+
paper: "#191919",
|
|
13589
|
+
surface: "#222222",
|
|
13590
|
+
"surface-2": "#2c2c2b",
|
|
13591
|
+
sidebar: "#202020",
|
|
13592
|
+
fg: "#e8e7e4",
|
|
13593
|
+
"fg-soft": "#c0beb8",
|
|
13594
|
+
muted: "#aaa8a2",
|
|
13595
|
+
line: "#30302f",
|
|
13596
|
+
"line-strong": "#42423f",
|
|
13597
|
+
accent: "#8aaddb",
|
|
13598
|
+
"accent-fg": "#172235",
|
|
13599
|
+
"accent-soft": "#263242",
|
|
13600
|
+
hover: "rgba(255,255,255,.035)",
|
|
13601
|
+
"hover-2": "rgba(255,255,255,.065)",
|
|
13602
|
+
"code-bg": "#242423",
|
|
13603
|
+
"selected-bg": "#242a32",
|
|
13604
|
+
"selected-border": "#56657a",
|
|
13605
|
+
"selected-icon-bg": "#2d3745",
|
|
13606
|
+
"selected-icon-fg": "#afc5e2",
|
|
13607
|
+
"selected-muted": "#b5bfcd",
|
|
13608
|
+
"selected-hover-bg": "#2a313b",
|
|
13609
|
+
"selected-hover-border": "#7287a3",
|
|
13610
|
+
danger: "#e89890",
|
|
13611
|
+
"danger-fg": "#2b1716",
|
|
13612
|
+
"danger-soft": "#3b2927",
|
|
13613
|
+
success: "#92bd9b",
|
|
13614
|
+
warning: "#d6b578",
|
|
13615
|
+
"warning-soft": "#363024",
|
|
13616
|
+
"brand-purple": "#baa6d1",
|
|
13617
|
+
"brand-teal": "#8cbbb4",
|
|
13618
|
+
"brand-orange": "#d4a37d",
|
|
13619
|
+
"shadow-sm": "0 1px 2px rgba(0,0,0,.15)",
|
|
13620
|
+
"shadow-md": "0 4px 14px rgba(0,0,0,.25)",
|
|
13621
|
+
"shadow-lg": "0 16px 48px rgba(0,0,0,.35)",
|
|
13622
|
+
"brand-stripe": "linear-gradient(to right,#335cff 0% 25%,#8967ed 25% 50%,#18b7b6 50% 75%,#f28b55 75% 100%)"
|
|
13623
|
+
};
|
|
13624
|
+
THEME_CSS = `:root{color-scheme:light;${declarations(LIGHT_THEME)}--card:var(--surface-2);--ok:var(--success)}
|
|
13625
|
+
@media(prefers-color-scheme:dark){:root:not([data-resolved]){color-scheme:dark;${declarations(DARK_THEME)}}}
|
|
13626
|
+
:root[data-resolved="dark"]{color-scheme:dark;${declarations(DARK_THEME)}}
|
|
13627
|
+
::selection{background:var(--accent-soft);color:var(--accent)}`;
|
|
13628
|
+
THEME_INIT_SCRIPT = `(function(){var t;try{t=localStorage.getItem('mh-theme')}catch(e){}var d=t==='dark'||(t!=='light'&&matchMedia('(prefers-color-scheme: dark)').matches);document.documentElement.dataset.resolved=d?'dark':'light';var m=document.querySelector('meta[name="theme-color"]');if(m)m.content=d?'${DARK_THEME.bg}':'${LIGHT_THEME.bg}'})();`;
|
|
13629
|
+
});
|
|
13630
|
+
|
|
13499
13631
|
// src/core/inject-runtime.ts
|
|
13500
13632
|
function injectRuntimeTag(html) {
|
|
13501
13633
|
const i = html.toLowerCase().indexOf("<head>");
|
|
@@ -13606,17 +13738,9 @@ function unlockPage(locale = "zh-CN") {
|
|
|
13606
13738
|
return `<!doctype html><html lang="${locale}"><head>
|
|
13607
13739
|
<meta charset="utf-8">
|
|
13608
13740
|
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
|
|
13609
|
-
<meta name="theme-color" content="
|
|
13741
|
+
<meta name="theme-color" content="${LIGHT_THEME.bg}">
|
|
13610
13742
|
<title>${m("\u9A8C\u8BC1\u8BBF\u95EE\u4EE4\u724C \xB7 metahub")}</title>
|
|
13611
|
-
<script>
|
|
13612
|
-
// FOUC-guard theme resolution, same key/logic as src/webui/theme.ts.
|
|
13613
|
-
try {
|
|
13614
|
-
var mt = localStorage.getItem("mh-theme");
|
|
13615
|
-
var dark = mt === "dark" || (mt !== "light" && matchMedia("(prefers-color-scheme: dark)").matches);
|
|
13616
|
-
document.documentElement.dataset.resolved = dark ? "dark" : "light";
|
|
13617
|
-
document.head.querySelector('meta[name=theme-color]').setAttribute("content", dark ? "#1a1a1c" : "#ffffff");
|
|
13618
|
-
} catch (e) {}
|
|
13619
|
-
</script>
|
|
13743
|
+
<script>${THEME_INIT_SCRIPT}</script>
|
|
13620
13744
|
<style>${UNLOCK_CSS}</style></head><body>
|
|
13621
13745
|
<div class="boot" id="boot"><svg viewBox="0 0 24 24">${CUBE_SVG}</svg></div>
|
|
13622
13746
|
<form class="card" id="f" style="display:none" autocomplete="on">
|
|
@@ -13765,15 +13889,20 @@ function cookieMutationRejection(req, url, cfg) {
|
|
|
13765
13889
|
function unauthorized() {
|
|
13766
13890
|
return Response.json({ error: "unauthorized" }, { status: 401 });
|
|
13767
13891
|
}
|
|
13768
|
-
var COOKIE = "mh_token", COOKIE_ATTRS = "path=/; SameSite=Strict; Max-Age=31536000", HTML_HEADERS, CUBE_SVG = '<path d="M21 7.5 12 2 3 7.5v9L12 22l9-5.5z"/><path d="m3 7.5 9 5.5 9-5.5M12 22v-9"/>', EYE_SVG = '<path d="M2 12s3.6-7 10-7 10 7 10 7-3.6 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/>', EYE_OFF_SVG = '<path d="M4 4l16 16M9.5 9.5a3 3 0 0 0 4 4M6.5 6.7C4.5 8 3 10 2 12c2 4 6 7 10 7 1.6 0 3-.4 4.4-1.1M9.5 5.2A9.7 9.7 0 0 1 12 5c4 0 8 3 10 7-.6 1.3-1.5 2.5-2.5 3.5"/>', UNLOCK_CSS =
|
|
13769
|
-
|
|
13770
|
-
|
|
13771
|
-
|
|
13772
|
-
|
|
13773
|
-
|
|
13774
|
-
|
|
13775
|
-
|
|
13776
|
-
|
|
13892
|
+
var COOKIE = "mh_token", COOKIE_ATTRS = "path=/; SameSite=Strict; Max-Age=31536000", HTML_HEADERS, CUBE_SVG = '<path d="M21 7.5 12 2 3 7.5v9L12 22l9-5.5z"/><path d="m3 7.5 9 5.5 9-5.5M12 22v-9"/>', EYE_SVG = '<path d="M2 12s3.6-7 10-7 10 7 10 7-3.6 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/>', EYE_OFF_SVG = '<path d="M4 4l16 16M9.5 9.5a3 3 0 0 0 4 4M6.5 6.7C4.5 8 3 10 2 12c2 4 6 7 10 7 1.6 0 3-.4 4.4-1.1M9.5 5.2A9.7 9.7 0 0 1 12 5c4 0 8 3 10 7-.6 1.3-1.5 2.5-2.5 3.5"/>', UNLOCK_CSS, escapeAttr = (v) => v.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
13893
|
+
var init_auth = __esm(() => {
|
|
13894
|
+
init_ui_theme();
|
|
13895
|
+
init_page_messages();
|
|
13896
|
+
init_inject_runtime();
|
|
13897
|
+
init_token();
|
|
13898
|
+
init_pairing();
|
|
13899
|
+
init_protocol();
|
|
13900
|
+
HTML_HEADERS = {
|
|
13901
|
+
"content-type": "text/html; charset=utf-8",
|
|
13902
|
+
"referrer-policy": "same-origin"
|
|
13903
|
+
};
|
|
13904
|
+
UNLOCK_CSS = `
|
|
13905
|
+
${THEME_CSS}
|
|
13777
13906
|
*{box-sizing:border-box}
|
|
13778
13907
|
html,body{margin:0;min-height:100%}
|
|
13779
13908
|
body{font-family:"Hanken Grotesk",-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;
|
|
@@ -13838,17 +13967,7 @@ var COOKIE = "mh_token", COOKIE_ATTRS = "path=/; SameSite=Strict; Max-Age=315360
|
|
|
13838
13967
|
@keyframes spin{to{transform:rotate(360deg)}}
|
|
13839
13968
|
@media (prefers-reduced-motion:reduce){*{animation-duration:.01ms!important}
|
|
13840
13969
|
.brand path{stroke-dashoffset:0}}
|
|
13841
|
-
|
|
13842
|
-
var init_auth = __esm(() => {
|
|
13843
|
-
init_page_messages();
|
|
13844
|
-
init_inject_runtime();
|
|
13845
|
-
init_token();
|
|
13846
|
-
init_pairing();
|
|
13847
|
-
init_protocol();
|
|
13848
|
-
HTML_HEADERS = {
|
|
13849
|
-
"content-type": "text/html; charset=utf-8",
|
|
13850
|
-
"referrer-policy": "same-origin"
|
|
13851
|
-
};
|
|
13970
|
+
`;
|
|
13852
13971
|
});
|
|
13853
13972
|
|
|
13854
13973
|
// src/core/sync/http-status.ts
|
|
@@ -14732,8 +14851,7 @@ function notFoundResponse(locale, title, detail) {
|
|
|
14732
14851
|
<meta name="robots" content="noindex">
|
|
14733
14852
|
<title>${escapeHtml(title)}</title>
|
|
14734
14853
|
<style>
|
|
14735
|
-
|
|
14736
|
-
@media (prefers-color-scheme: dark){:root{--bg:#0d1117;--fg:#e6edf3;--muted:#8b949e;--line:#30363d;--accent:#4493f8;--card:#161b22}}
|
|
14854
|
+
${THEME_CSS}
|
|
14737
14855
|
*{box-sizing:border-box}
|
|
14738
14856
|
body{margin:0;background:var(--bg);color:var(--fg);font:16px/1.65 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"PingFang SC","Microsoft YaHei",sans-serif;
|
|
14739
14857
|
min-height:100dvh;display:flex;align-items:center;justify-content:center;padding:24px}
|
|
@@ -14757,6 +14875,7 @@ function notFoundResponse(locale, title, detail) {
|
|
|
14757
14875
|
});
|
|
14758
14876
|
}
|
|
14759
14877
|
var init_sites_serve = __esm(() => {
|
|
14878
|
+
init_ui_theme();
|
|
14760
14879
|
init_sites();
|
|
14761
14880
|
init_site_channel_store();
|
|
14762
14881
|
init_grants_core();
|
|
@@ -14819,6 +14938,20 @@ async function mintGuestSession(scope, opts) {
|
|
|
14819
14938
|
return { sub: opts.sub, exp, cookie };
|
|
14820
14939
|
}
|
|
14821
14940
|
|
|
14941
|
+
// src/core/sync/share-file-styles.ts
|
|
14942
|
+
var SHARE_FILE_CSS = `
|
|
14943
|
+
article.doc p.mh-file{margin:0}
|
|
14944
|
+
article.doc .mh-file+.mh-file{border-top:1px solid var(--line)}
|
|
14945
|
+
article.doc .mh-file a{display:block;position:relative;min-height:44px;max-width:100%;padding:11px 36px;border:0;border-radius:4px;background:transparent;color:var(--fg);font-size:14px;line-height:22px;text-decoration:none;overflow-wrap:anywhere}
|
|
14946
|
+
article.doc .mh-file a::before,article.doc .mh-file a::after{content:"";position:absolute;top:14px;width:16px;height:16px;background:currentColor;opacity:.65;mask:var(--file-icon) center/contain no-repeat}
|
|
14947
|
+
article.doc .mh-file a::before{left:10px;--file-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z'/%3E%3Cpath d='M14 2v6h6M8 13h8M8 17h5'/%3E%3C/svg%3E")}
|
|
14948
|
+
article.doc .mh-file a::after{right:10px;--file-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3v12m-4-4 4 4 4-4M5 16v4a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-4'/%3E%3C/svg%3E")}
|
|
14949
|
+
article.doc .mh-file a[href]:not([aria-disabled="true"]):hover{background:var(--card);color:var(--accent);text-decoration:underline;text-underline-offset:3px}
|
|
14950
|
+
article.doc .mh-file a:focus-visible{outline:2px solid var(--accent);outline-offset:-2px;background:var(--card);color:var(--accent)}
|
|
14951
|
+
article.doc .mh-file a[aria-disabled="true"]{color:var(--muted);pointer-events:none}
|
|
14952
|
+
article.doc .mh-file a[aria-disabled="true"]::after{display:none}
|
|
14953
|
+
`;
|
|
14954
|
+
|
|
14822
14955
|
// src/core/sync/share-copy.ts
|
|
14823
14956
|
function markdownTable(header, rows) {
|
|
14824
14957
|
const cell = (s) => s.replace(/\r?\n/g, " ").replace(/\|/g, "\\|").trim();
|
|
@@ -14852,12 +14985,11 @@ var ICON_COPY = '<svg class="ic-copy" viewBox="0 0 24 24" aria-hidden="true"><re
|
|
|
14852
14985
|
.copy-btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
|
|
14853
14986
|
.copy-btn svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;flex:none}
|
|
14854
14987
|
.copy-btn .ic-check{display:none}
|
|
14855
|
-
.copy-btn.done{color:var(--
|
|
14988
|
+
.copy-btn.done{color:var(--success);border-color:var(--success)}
|
|
14856
14989
|
.copy-btn.done .ic-copy{display:none}.copy-btn.done .ic-check{display:block}
|
|
14857
14990
|
.copy-btn.done .ic-check path{stroke-dasharray:24;stroke-dashoffset:24;animation:mh-draw .22s ease-out forwards}
|
|
14858
|
-
.copy-btn.fail{color
|
|
14991
|
+
.copy-btn.fail{color:var(--danger);border-color:var(--danger)}
|
|
14859
14992
|
@keyframes mh-draw{to{stroke-dashoffset:0}}
|
|
14860
|
-
@media (prefers-color-scheme:dark){:root{--ok:#3fb950}}
|
|
14861
14993
|
@media (max-width:480px){.copy-btn span{display:none}.copy-btn{padding:0 9px}}
|
|
14862
14994
|
@media (prefers-reduced-motion:reduce){.copy-btn .ic-check path{animation:none;stroke-dashoffset:0}}`;
|
|
14863
14995
|
var init_share_copy = __esm(() => {
|
|
@@ -15272,14 +15404,13 @@ function pageShell(title, inner, opts) {
|
|
|
15272
15404
|
<meta name="robots" content="noindex">
|
|
15273
15405
|
<title>${escapeHtml(title)}</title>
|
|
15274
15406
|
<style>
|
|
15275
|
-
|
|
15276
|
-
@media (prefers-color-scheme: dark){:root{--bg:#0d1117;--fg:#e6edf3;--muted:#8b949e;--line:#30363d;--accent:#4493f8;--card:#161b22}}
|
|
15407
|
+
${THEME_CSS}
|
|
15277
15408
|
*{box-sizing:border-box}
|
|
15278
15409
|
body{margin:0;background:var(--bg);color:var(--fg);font:16px/1.65 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"PingFang SC","Microsoft YaHei",sans-serif}
|
|
15279
15410
|
.wrap{max-width:820px;margin:0 auto;padding:32px 20px 80px}
|
|
15280
15411
|
header.mh{display:flex;align-items:center;gap:12px;justify-content:space-between;margin-bottom:20px;border-bottom:1px solid var(--line);padding-bottom:14px}
|
|
15281
15412
|
header.mh h1.title{font-size:22px;margin:0}
|
|
15282
|
-
.edit-btn{background:var(--accent);color
|
|
15413
|
+
.edit-btn{background:var(--accent);color:var(--accent-fg);border:0;border-radius:7px;height:32px;padding:0 14px;cursor:pointer;font-size:13px;font-weight:500;font-family:inherit}
|
|
15283
15414
|
${COPY_CSS}
|
|
15284
15415
|
.hint{color:var(--muted);font-size:13px;margin:0 0 14px}
|
|
15285
15416
|
article.doc h1,article.doc h2,article.doc h3{line-height:1.3;margin:1.4em 0 .5em}
|
|
@@ -15293,11 +15424,11 @@ function pageShell(title, inner, opts) {
|
|
|
15293
15424
|
article.doc td,article.doc th,table.db td,table.db th{border:1px solid var(--line);padding:7px 10px;text-align:left}
|
|
15294
15425
|
table.db th{background:var(--card)}
|
|
15295
15426
|
.table-wrap{overflow:auto}
|
|
15296
|
-
td[contenteditable]{outline:none} td.saving{opacity:.5} td.saved{background:
|
|
15427
|
+
td[contenteditable]{outline:none} td.saving{opacity:.5} td.saved{background:color-mix(in srgb,var(--success) 18%,transparent)}
|
|
15297
15428
|
.tag{display:inline-block;background:var(--card);border:1px solid var(--line);border-radius:999px;padding:1px 9px;font-size:12px}
|
|
15298
15429
|
.muted{color:var(--muted)} .mh-img{text-align:center}
|
|
15299
15430
|
.mh-media{text-align:center} .mh-media video,.mh-media audio{max-width:100%}
|
|
15300
|
-
|
|
15431
|
+
${SHARE_FILE_CSS}
|
|
15301
15432
|
.mh-doclink{background:var(--card);border:1px solid var(--line);border-radius:6px;padding:0 5px;white-space:nowrap}
|
|
15302
15433
|
.mh-doclink::before{content:"\uD83D\uDCC4";font-size:.85em;margin-right:3px}
|
|
15303
15434
|
iframe.mh-embed{width:100%;border:1px solid var(--line);border-radius:8px;min-height:240px}
|
|
@@ -15306,8 +15437,8 @@ function pageShell(title, inner, opts) {
|
|
|
15306
15437
|
.row{display:flex;gap:10px;align-items:center;margin:10px 0}
|
|
15307
15438
|
form.pw{max-width:320px;margin:12vh auto 0;display:flex;flex-direction:column;gap:12px}
|
|
15308
15439
|
form.pw input{padding:9px;border:1px solid var(--line);border-radius:7px;background:var(--card);color:var(--fg)}
|
|
15309
|
-
form.pw button{padding:9px;border:0;border-radius:7px;background:var(--accent);color
|
|
15310
|
-
form.pw .err{color
|
|
15440
|
+
form.pw button{padding:9px;border:0;border-radius:7px;background:var(--accent);color:var(--accent-fg);cursor:pointer}
|
|
15441
|
+
form.pw .err{color:var(--danger);font-size:13px;margin:0}
|
|
15311
15442
|
footer.mh{margin-top:48px;border-top:1px solid var(--line);padding-top:14px;color:var(--muted);font-size:12px;text-align:center}
|
|
15312
15443
|
</style></head><body>
|
|
15313
15444
|
${opts.bare ? `<div class="wrap">${inner}</div>` : `<div class="wrap">
|
|
@@ -15321,6 +15452,7 @@ ${script}
|
|
|
15321
15452
|
}
|
|
15322
15453
|
var HTML, HASH_RE2, SHARE_SESSION_TTL_MS;
|
|
15323
15454
|
var init_share_serve = __esm(() => {
|
|
15455
|
+
init_ui_theme();
|
|
15324
15456
|
init_ids();
|
|
15325
15457
|
init_shares();
|
|
15326
15458
|
init_documents();
|
|
@@ -16487,24 +16619,15 @@ function startServer(opts = {}) {
|
|
|
16487
16619
|
};
|
|
16488
16620
|
}
|
|
16489
16621
|
// src/webui/server/assets.ts
|
|
16622
|
+
init_ui_theme();
|
|
16490
16623
|
import { fileURLToPath } from "url";
|
|
16491
16624
|
import { readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
16492
16625
|
import { join as join5, dirname } from "path";
|
|
16493
16626
|
|
|
16494
16627
|
// src/webui/styles.css
|
|
16495
16628
|
var styles_default = ` :root {
|
|
16496
|
-
/*
|
|
16497
|
-
|
|
16498
|
-
data-resolved, so a manual theme toggle retunes it too. */
|
|
16499
|
-
color-scheme: light;
|
|
16500
|
-
--bg:#ffffff; --surface:#fbfbfa; --surface-2:#f1f1ef; --sidebar:#f7f7f5;
|
|
16501
|
-
--fg:#2c2c30; --fg-soft:#5b5b62; --muted:#75757f; --line:#ebebe8; --line-strong:#dededb;
|
|
16502
|
-
--accent:#4a55d6; --accent-fg:#ffffff; --accent-soft:#eef0ff; --danger:#d6473b; --danger-soft:#fdeceb;
|
|
16503
|
-
--success:#1f8f3e;
|
|
16504
|
-
--hover:rgba(45,45,55,.045); --hover-2:rgba(45,45,55,.08);
|
|
16505
|
-
--shadow-sm:0 1px 2px rgba(20,20,40,.06),0 1px 1px rgba(20,20,40,.04);
|
|
16506
|
-
--shadow-md:0 4px 12px rgba(20,20,40,.08),0 2px 4px rgba(20,20,40,.05);
|
|
16507
|
-
--shadow-lg:0 16px 48px rgba(20,20,40,.16),0 4px 12px rgba(20,20,40,.08);
|
|
16629
|
+
/* Palette comes from core/ui-theme.ts; dimensions and typography stay here. */
|
|
16630
|
+
|
|
16508
16631
|
--radius:8px; --radius-sm:6px; --radius-lg:14px; --radius-xl:16px;
|
|
16509
16632
|
--fs-body:14px; --fs-ui:13.5px; --fs-sm:12.5px; --fs-xs:11.5px; --fs-micro:11px;
|
|
16510
16633
|
--ui:"Hanken Grotesk",-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;
|
|
@@ -16512,23 +16635,12 @@ var styles_default = ` :root {
|
|
|
16512
16635
|
--kbd-font:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;
|
|
16513
16636
|
--tip-bg:#1f1f23; --tip-fg:#ffffff; --tip-kbd-bg:rgba(255,255,255,.14); --tip-kbd-fg:rgba(255,255,255,.92);
|
|
16514
16637
|
--note-lh:1.6;
|
|
16515
|
-
--code-bg:#f8f8f6;
|
|
16516
16638
|
--hl-cmt:#9a9aa2; --hl-key:#a626a4; --hl-str:#28823f; --hl-num:#b76a00;
|
|
16517
16639
|
--hl-fn:#3f51d6; --hl-type:#0a7ea4; --hl-var:#c2410c;
|
|
16518
16640
|
}
|
|
16519
|
-
/* Dark
|
|
16520
|
-
* "system" \u2192 the OS preference) to <html data-resolved="light|dark"> before
|
|
16521
|
-
* first paint (FOUC script in the shell) and on every change (theme.ts), so
|
|
16522
|
-
* CSS never needs a prefers-color-scheme duplicate of this block. */
|
|
16641
|
+
/* Dark tooltip and syntax tokens; shared UI colors/elevation live in core/ui-theme.ts. */
|
|
16523
16642
|
:root[data-resolved="dark"] {
|
|
16524
|
-
|
|
16525
|
-
--bg:#1a1a1c; --surface:#202022; --surface-2:#2a2a2d; --sidebar:#171719;
|
|
16526
|
-
--fg:#e6e6e9; --fg-soft:#b4b4bb; --muted:#8b8b95; --line:#2c2c30; --line-strong:#3a3a40;
|
|
16527
|
-
--accent:#7b86ff; --accent-fg:#14141a; --accent-soft:#23243a; --danger:#f87168; --danger-soft:#341e1c;
|
|
16528
|
-
--success:#3fb950;
|
|
16529
|
-
--hover:rgba(255,255,255,.05); --hover-2:rgba(255,255,255,.09);
|
|
16530
|
-
--shadow-sm:0 1px 2px rgba(0,0,0,.4); --shadow-md:0 4px 14px rgba(0,0,0,.45); --shadow-lg:0 20px 56px rgba(0,0,0,.6);
|
|
16531
|
-
--code-bg:#1d1d20;
|
|
16643
|
+
|
|
16532
16644
|
--tip-bg:#2e2e32; --tip-fg:var(--fg); --tip-kbd-bg:rgba(255,255,255,.08); --tip-kbd-fg:var(--fg-soft);
|
|
16533
16645
|
--hl-cmt:#7d7d86; --hl-key:#d291e4; --hl-str:#7ed492; --hl-num:#e0a566;
|
|
16534
16646
|
--hl-fn:#86a8ff; --hl-type:#5fc6e0; --hl-var:#f0936b;
|
|
@@ -16655,7 +16767,7 @@ var styles_default = ` :root {
|
|
|
16655
16767
|
.navitem { display:flex; align-items:center; gap:3px; width:100%; text-align:left; padding:5px 6px; margin-bottom:2px; border-radius:var(--radius-sm);
|
|
16656
16768
|
color:var(--fg-soft); font-size:var(--fs-ui); position:relative; white-space:nowrap; transition:background .1s; }
|
|
16657
16769
|
.navitem:hover { background:var(--hover-2); }
|
|
16658
|
-
.navitem.active { background:var(--
|
|
16770
|
+
.navitem.active { background:var(--hover-2); color:var(--fg); font-weight:600; box-shadow:none; }
|
|
16659
16771
|
.navitem .tw { width:18px; height:18px; display:grid; place-items:center; color:var(--muted); border-radius:4px; flex:none; }
|
|
16660
16772
|
.navitem .tw:hover { background:var(--hover-2); }
|
|
16661
16773
|
.navitem .tw svg { width:13px; height:13px; transition:transform .12s; }
|
|
@@ -16730,13 +16842,13 @@ var styles_default = ` :root {
|
|
|
16730
16842
|
(driven by --mark-y / --mark-h from JS, eased by CSS) */
|
|
16731
16843
|
.set-rail::before { content:""; position:absolute; left:0; top:4px; bottom:4px;
|
|
16732
16844
|
width:2px; border-radius:2px; background:var(--line); }
|
|
16733
|
-
.set-rail-mark { position:absolute; left:0; width:2px; border-radius:2px; background:var(--
|
|
16845
|
+
.set-rail-mark { position:absolute; left:0; width:2px; border-radius:2px; background:var(--fg-soft);
|
|
16734
16846
|
height:var(--mark-h,0); transform:translateY(var(--mark-y,0));
|
|
16735
16847
|
transition:transform .26s cubic-bezier(.4,0,.2,1), height .26s cubic-bezier(.4,0,.2,1); }
|
|
16736
16848
|
.set-rail-row { display:flex; align-items:center; gap:10px; padding:7px 10px; border-radius:var(--radius-sm);
|
|
16737
16849
|
color:var(--muted); text-align:left; cursor:pointer; transition:color .14s, background .14s; }
|
|
16738
16850
|
.set-rail-row:hover { background:var(--hover); color:var(--fg); }
|
|
16739
|
-
.set-rail-row.active { color:var(--
|
|
16851
|
+
.set-rail-row.active { color:var(--fg); }
|
|
16740
16852
|
.set-rail-ico { flex:none; display:grid; place-items:center; width:16px; height:16px; opacity:.85; }
|
|
16741
16853
|
.set-rail-ico svg { width:15px; height:15px; }
|
|
16742
16854
|
.set-rail-label { font-size:var(--fs-sm); font-weight:550; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
|
@@ -16793,7 +16905,7 @@ var styles_default = ` :root {
|
|
|
16793
16905
|
.set-row.dim > .set-row-line { opacity:.62; }
|
|
16794
16906
|
/* status dot in a caption: the only colour a row carries */
|
|
16795
16907
|
.cap-dot { display:inline-block; flex:none; width:7px; height:7px; border-radius:50%; background:var(--muted); }
|
|
16796
|
-
.cap-dot.ok { background:var(--success); } .cap-dot.warn { background:var(--warning
|
|
16908
|
+
.cap-dot.ok { background:var(--success); } .cap-dot.warn { background:var(--warning); } .cap-dot.err { background:var(--danger); }
|
|
16797
16909
|
.cap-err { color:var(--danger); }
|
|
16798
16910
|
/* tag variants next to a title: neutral outline (default), accent (roles), self (soft fill) */
|
|
16799
16911
|
.set-row-title .set-row-tag { margin-left:0; vertical-align:0; flex:none; }
|
|
@@ -16864,8 +16976,8 @@ var styles_default = ` :root {
|
|
|
16864
16976
|
.audit-actor { flex:none; font-size:11px; font-weight:600; padding:1px 7px; border-radius:999px;
|
|
16865
16977
|
background:var(--surface); border:1px solid var(--line); color:var(--fg-soft); max-width:110px;
|
|
16866
16978
|
overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
16867
|
-
.audit-actor.ai { background:color-mix(in srgb,
|
|
16868
|
-
border-color:color-mix(in srgb,
|
|
16979
|
+
.audit-actor.ai { background:color-mix(in srgb, var(--brand-purple) 14%, transparent);
|
|
16980
|
+
border-color:color-mix(in srgb, var(--brand-purple) 35%, transparent); color:var(--brand-purple); }
|
|
16869
16981
|
.audit-summary { font-size:var(--fs-ui); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
16870
16982
|
.audit-ent { color:inherit; font-weight:600; text-decoration:none; margin-left:2px; }
|
|
16871
16983
|
.audit-ent[href]:hover { color:var(--accent); text-decoration:underline; }
|
|
@@ -16884,7 +16996,7 @@ var styles_default = ` :root {
|
|
|
16884
16996
|
.audit-end { display:flex; align-items:center; gap:12px; margin:18px 0 0; color:var(--muted); font-size:var(--fs-xs); }
|
|
16885
16997
|
.audit-end::before, .audit-end::after { content:""; flex:1; height:1px; background:var(--line); }
|
|
16886
16998
|
@media (hover:none) { .audit-revert { opacity:1; } }
|
|
16887
|
-
.set-callout.warn { border-color:color-mix(in srgb,var(--warning
|
|
16999
|
+
.set-callout.warn { border-color:color-mix(in srgb,var(--warning) 32%,var(--line)); }
|
|
16888
17000
|
/* a quiet helper line under a field / chip group */
|
|
16889
17001
|
.set-hint { font-size:var(--fs-xs); color:var(--muted); line-height:1.5; margin:3px 0 4px; }
|
|
16890
17002
|
/* progressive disclosure ("\u5DE5\u4F5C\u539F\u7406" / "\u8FDB\u9636") \u2014 native details, themed */
|
|
@@ -16903,7 +17015,7 @@ var styles_default = ` :root {
|
|
|
16903
17015
|
.provider-chip { padding:6px 12px; border-radius:999px; border:1px solid var(--line-strong); background:var(--surface);
|
|
16904
17016
|
color:var(--fg-soft); font-size:var(--fs-sm); font-weight:550; transition:border-color .12s, background .12s, color .12s; }
|
|
16905
17017
|
.provider-chip:hover { border-color:var(--muted); color:var(--fg); }
|
|
16906
|
-
.provider-chip.sel { border-color:var(--
|
|
17018
|
+
.provider-chip.sel { border-color:var(--selected-border); background:var(--selected-bg); color:var(--accent); box-shadow:none; }
|
|
16907
17019
|
/* ---- \u5173\u4E8E page -----------------------------------------------------------
|
|
16908
17020
|
Product identity hero over the standard SetSection/SetRow stack. The cube
|
|
16909
17021
|
mark sizes to a nav-icon's proportions scaled up; the version line reuses
|
|
@@ -16943,8 +17055,8 @@ var styles_default = ` :root {
|
|
|
16943
17055
|
@keyframes ver-indet { 0% { left:-42%; } 100% { left:100%; } }
|
|
16944
17056
|
.theme-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:12px; }
|
|
16945
17057
|
.theme-card { position:relative; display:flex; flex-direction:column; align-items:flex-start; gap:10px;
|
|
16946
|
-
text-align:left; padding:16px; border:1px solid var(--line
|
|
16947
|
-
background:var(--
|
|
17058
|
+
text-align:left; padding:16px; border:1px solid var(--line); border-radius:var(--radius);
|
|
17059
|
+
background:var(--bg); color:var(--fg-soft); box-shadow:none;
|
|
16948
17060
|
transition:border-color .14s, background .14s, transform .14s, box-shadow .14s; }
|
|
16949
17061
|
.theme-card:hover { border-color:var(--muted); transform:translateY(-1px); }
|
|
16950
17062
|
.theme-card .tc-ico { width:34px; height:34px; display:grid; place-items:center; border-radius:9px;
|
|
@@ -16955,8 +17067,10 @@ var styles_default = ` :root {
|
|
|
16955
17067
|
.theme-card .tc-check { position:absolute; top:10px; right:10px; width:18px; height:18px; border-radius:50%;
|
|
16956
17068
|
background:var(--accent); color:var(--accent-fg); display:grid; place-items:center; opacity:0; transform:scale(.6); transition:opacity .14s, transform .14s; }
|
|
16957
17069
|
.theme-card .tc-check svg { width:12px; height:12px; stroke-width:2.6; }
|
|
16958
|
-
.theme-card.sel { border-color:var(--
|
|
16959
|
-
.theme-card.sel
|
|
17070
|
+
.theme-card.sel { border-color:var(--selected-border); background:var(--selected-bg); box-shadow:none; }
|
|
17071
|
+
.theme-card.sel:hover { background:var(--selected-hover-bg); border-color:var(--selected-hover-border); }
|
|
17072
|
+
.theme-card.sel .tc-desc { color:var(--selected-muted); }
|
|
17073
|
+
.theme-card.sel .tc-ico { background:var(--selected-icon-bg); color:var(--selected-icon-fg); }
|
|
16960
17074
|
.theme-card.sel .tc-check { opacity:1; transform:scale(1); }
|
|
16961
17075
|
@media (max-width:560px) { .theme-grid { grid-template-columns:1fr; } }
|
|
16962
17076
|
.brand-grid { grid-template-columns:repeat(auto-fit,minmax(min(100%,120px),1fr)); }
|
|
@@ -16973,7 +17087,7 @@ var styles_default = ` :root {
|
|
|
16973
17087
|
.sync-health-sub { display:inline-flex; align-items:center; gap:8px; max-width:100%; min-width:0; }
|
|
16974
17088
|
.sync-health-dot { flex:none; width:8px; height:8px; border-radius:50%; }
|
|
16975
17089
|
.sync-health-dot.dot-ok { background:var(--success); }
|
|
16976
|
-
.sync-health-dot.dot-warn { background:var(--warning
|
|
17090
|
+
.sync-health-dot.dot-warn { background:var(--warning); }
|
|
16977
17091
|
.sync-health-dot.dot-error { background:var(--danger); }
|
|
16978
17092
|
/* shared expander chevron (bucket + device roster rows) */
|
|
16979
17093
|
.row-chev { flex:none; color:var(--muted); display:flex; transition:transform .15s; }
|
|
@@ -17070,7 +17184,7 @@ var styles_default = ` :root {
|
|
|
17070
17184
|
.btn-secondary:hover { background:var(--surface-2); }
|
|
17071
17185
|
.btn-primary { background:var(--accent); color:var(--accent-fg); box-shadow:var(--shadow-sm); }
|
|
17072
17186
|
.btn-primary:hover { filter:brightness(1.07); }
|
|
17073
|
-
.btn-danger { background:var(--danger); color
|
|
17187
|
+
.btn-danger { background:var(--danger); color:var(--danger-fg); } .btn-danger:hover { filter:brightness(1.05); }
|
|
17074
17188
|
.btn.sm { padding:3px 8px; font-size:12px; }
|
|
17075
17189
|
/* Notion-style ambient sync indicator: a quiet ghost control living in the
|
|
17076
17190
|
topbar icon row. State reads through the *text/icon colour* \u2014 no filled pill
|
|
@@ -17943,7 +18057,7 @@ var styles_default = ` :root {
|
|
|
17943
18057
|
.shv-ico svg { width:19px; height:19px; }
|
|
17944
18058
|
.shv-ico.k-doc { color:var(--accent); background:var(--accent-soft); }
|
|
17945
18059
|
.shv-ico.k-database { color:var(--fg-soft); }
|
|
17946
|
-
.shv-ico.k-site { color
|
|
18060
|
+
.shv-ico.k-site { color:var(--brand-teal); }
|
|
17947
18061
|
.shv-main { min-width:0; }
|
|
17948
18062
|
.shv-title { display:block; max-width:100%; font-weight:600; color:var(--fg); letter-spacing:-.01em;
|
|
17949
18063
|
overflow:hidden; text-overflow:ellipsis; white-space:nowrap; text-align:left; }
|
|
@@ -17970,8 +18084,8 @@ var styles_default = ` :root {
|
|
|
17970
18084
|
font-variant-numeric:tabular-nums; white-space:nowrap; }
|
|
17971
18085
|
.shv-dot { width:8px; height:8px; border-radius:50%; background:var(--muted); flex:none; }
|
|
17972
18086
|
.shv-status.tone-ok .shv-dot { background:var(--success); }
|
|
17973
|
-
.shv-status.tone-warn { color:var(--warning
|
|
17974
|
-
.shv-status.tone-warn .shv-dot { background:var(--warning
|
|
18087
|
+
.shv-status.tone-warn { color:var(--warning); }
|
|
18088
|
+
.shv-status.tone-warn .shv-dot { background:var(--warning); }
|
|
17975
18089
|
.shv-status.tone-muted { color:var(--muted); }
|
|
17976
18090
|
.shv-status.tone-muted .shv-dot { background:transparent; border:1.5px solid var(--line-strong); }
|
|
17977
18091
|
.shv-status .sync-ring { width:10px; height:10px; }
|
|
@@ -18056,6 +18170,73 @@ var styles_default = ` :root {
|
|
|
18056
18170
|
.shv-group-head .btn { margin-left:0; width:100%; justify-content:center; padding:7px 10px; }
|
|
18057
18171
|
}
|
|
18058
18172
|
|
|
18173
|
+
/* Share workspace: quiet Notion-like controls and aligned document rows. */
|
|
18174
|
+
.shares-page { --shv-quiet:color-mix(in srgb,var(--fg) 4%,var(--bg)); --shv-rule:color-mix(in srgb,var(--fg) 8%,var(--bg)); container-type:inline-size; }
|
|
18175
|
+
.shares-page .db-head { margin-bottom:28px; }
|
|
18176
|
+
.shares-page .db-title { display:flex; align-items:center; gap:14px; margin:0; font-size:32px; line-height:1.35; }
|
|
18177
|
+
.shares-page .db-title > .ico { width:27px; height:27px; flex:none; }
|
|
18178
|
+
.shares-page .db-desc { max-width:none; margin-top:12px; line-height:1.7; }
|
|
18179
|
+
.shv-toolbar { margin-bottom:20px; padding:8px 0; }
|
|
18180
|
+
.shv-tools-right { display:flex; width:100%; gap:24px; margin:0; }
|
|
18181
|
+
.shv-seg { gap:8px; border:0; padding:0; background:none; flex:none; }
|
|
18182
|
+
.shv-seg-btn { min-height:34px; padding:7px 12px; border-radius:6px; gap:3px; transition:background .15s; }
|
|
18183
|
+
.shv-seg-btn:hover { background:var(--shv-quiet); }
|
|
18184
|
+
.shv-seg-btn.active { background:color-mix(in srgb,var(--fg) 6%,var(--bg)); box-shadow:none; }
|
|
18185
|
+
.shv-seg-btn .n { font-family:inherit; min-width:1ch; color:var(--fg-soft); }
|
|
18186
|
+
.shv-search { margin-left:auto; max-width:300px; padding:8px 12px; background:var(--shv-quiet); border:1px solid transparent; border-radius:7px; }
|
|
18187
|
+
.shv-search input::placeholder { color:var(--fg-soft); }
|
|
18188
|
+
.shv-search:focus-within { border-color:var(--accent); }
|
|
18189
|
+
.shv-src.btn { background:none; border-color:transparent; box-shadow:none; padding:7px 4px; white-space:nowrap; }
|
|
18190
|
+
.shv-columns { display:grid; grid-template-columns:minmax(0,1fr) 172px 142px; gap:20px; padding:10px 16px; border-radius:6px; background:var(--shv-quiet); color:var(--fg-soft); font-size:12px; }
|
|
18191
|
+
.shv-list { gap:0; }
|
|
18192
|
+
.shv-list[hidden] { display:none; }
|
|
18193
|
+
.shv-row { grid-template-columns:28px minmax(0,1fr) 172px 142px; gap:16px 20px; min-height:96px; padding:20px 16px; border:0; border-bottom:1px solid var(--shv-rule); border-radius:0; background:none; transition:background .15s; }
|
|
18194
|
+
.shv-row:hover { background:color-mix(in srgb,var(--fg) 2%,var(--bg)); box-shadow:none; border-color:var(--shv-rule); }
|
|
18195
|
+
.shv-ico, .shv-ico.k-doc, .shv-ico.k-site { width:28px; height:32px; border-radius:0; background:none; color:var(--fg-soft); }
|
|
18196
|
+
.shv-ico svg { width:24px; height:24px; stroke-width:1.5; }
|
|
18197
|
+
.shv-title { font-size:15px; font-weight:550; line-height:1.5; }
|
|
18198
|
+
.shv-sub { margin-top:5px; font-size:12px; color:var(--fg-soft); }
|
|
18199
|
+
.shv-status { justify-self:start; min-width:0; padding:5px 8px; gap:6px; border-radius:5px; font-size:12px; }
|
|
18200
|
+
.shv-status .ico { width:14px; height:14px; flex:none; }
|
|
18201
|
+
.shv-status.tone-ok { color:var(--success); background:color-mix(in srgb,var(--success) 8%,var(--bg)); }
|
|
18202
|
+
.shv-status.tone-warn { background:color-mix(in srgb,var(--warning) 8%,var(--bg)); }
|
|
18203
|
+
.shv-status.tone-muted { background:var(--shv-quiet); color:var(--fg-soft); }
|
|
18204
|
+
.shv-actions { justify-content:space-between; gap:12px; }
|
|
18205
|
+
.shv-actions .btn { min-height:30px; min-width:88px; border-radius:6px; }
|
|
18206
|
+
.shv-actions .shv-copy { background:none; border-color:transparent; box-shadow:none; }
|
|
18207
|
+
.shv-actions .ico { width:15px; height:15px; }
|
|
18208
|
+
.shv-group-head { margin:16px 0; font-weight:400; }
|
|
18209
|
+
.shv-group-toggle { display:flex; align-items:center; gap:10px; padding:6px; color:var(--fg); border-radius:6px; }
|
|
18210
|
+
.shv-group-toggle:hover { background:var(--shv-quiet); }
|
|
18211
|
+
.shv-group-toggle .ico { width:14px; height:14px; color:var(--fg-soft); }
|
|
18212
|
+
.shv-group-head .n { font-family:inherit; background:var(--shv-quiet); padding:2px 7px; border-radius:5px; color:var(--fg-soft); }
|
|
18213
|
+
.shv-group-head .btn { background:none; border-color:transparent; box-shadow:none; color:var(--fg-soft); }
|
|
18214
|
+
.shares-page button:focus-visible { outline:2px solid var(--accent); outline-offset:3px; }
|
|
18215
|
+
@container (max-width:850px) {
|
|
18216
|
+
.shv-tools-right { flex-wrap:wrap; gap:12px; }
|
|
18217
|
+
.shv-seg { width:100%; }
|
|
18218
|
+
.shv-search { margin-left:0; max-width:none; }
|
|
18219
|
+
.shv-columns { grid-template-columns:minmax(0,1fr) 145px 124px; gap:12px; }
|
|
18220
|
+
.shv-row { grid-template-columns:24px minmax(0,1fr) 145px 124px; gap:12px; }
|
|
18221
|
+
}
|
|
18222
|
+
@container (max-width:600px) {
|
|
18223
|
+
.shv-columns { display:none; }
|
|
18224
|
+
.shv-seg { gap:3px; }
|
|
18225
|
+
.shv-seg-btn { flex:1; min-width:0; justify-content:center; padding:8px 3px; font-size:12px; gap:2px; }
|
|
18226
|
+
.shv-seg-btn .n { margin-left:2px; font-size:11px; }
|
|
18227
|
+
.shv-src { flex:none; }
|
|
18228
|
+
.shv-toolbar { margin-bottom:8px; }
|
|
18229
|
+
.shv-row { grid-template-columns:24px minmax(0,1fr); padding:18px 4px; }
|
|
18230
|
+
.shv-title { white-space:normal; display:block; overflow-wrap:anywhere; }
|
|
18231
|
+
.shv-sub { flex-wrap:wrap; white-space:normal; overflow-wrap:anywhere; }
|
|
18232
|
+
.shv-sub > * { flex-shrink:1; min-width:0; }
|
|
18233
|
+
.shv-status { grid-column:2; }
|
|
18234
|
+
.shv-actions { grid-column:2; justify-content:flex-start; }
|
|
18235
|
+
.shv-actions .btn { flex:none; min-height:36px; }
|
|
18236
|
+
.shv-actions .iconbtn { margin-left:auto; }
|
|
18237
|
+
.shv-group-head .btn { width:auto; margin-left:auto; }
|
|
18238
|
+
}
|
|
18239
|
+
|
|
18059
18240
|
/* in-context "\u5DF2\u5206\u4EAB" badge on docs / tables / site cards */
|
|
18060
18241
|
.share-badge { display:inline-grid; place-items:center; width:22px; height:22px; border-radius:6px; color:var(--accent);
|
|
18061
18242
|
background:var(--accent-soft); flex:none; cursor:pointer; transition:filter .12s; }
|
|
@@ -18192,7 +18373,7 @@ var styles_default = ` :root {
|
|
|
18192
18373
|
.selbar .cnt { font-size:13px; font-weight:600; margin-right:6px; }
|
|
18193
18374
|
.selbar button { display:flex; align-items:center; gap:6px; color:var(--fg-soft); padding:6px 10px; border-radius:7px; font-size:13px; font-weight:500; }
|
|
18194
18375
|
.selbar button:hover { background:var(--hover-2); color:var(--fg); }
|
|
18195
|
-
.selbar .del:hover { background:var(--danger); color
|
|
18376
|
+
.selbar .del:hover { background:var(--danger); color:var(--danger-fg); }
|
|
18196
18377
|
|
|
18197
18378
|
/* record peek */
|
|
18198
18379
|
.scrim { position:fixed; inset:0; background:rgba(15,15,25,.32); z-index:70; opacity:0; pointer-events:none; transition:opacity .22s; }
|
|
@@ -18521,14 +18702,22 @@ var styles_default = ` :root {
|
|
|
18521
18702
|
.tmpl .tt { font-weight:600; font-size:var(--fs-ui); } .tmpl .td { font-size:var(--fs-xs); color:var(--muted); margin-top:2px; }
|
|
18522
18703
|
|
|
18523
18704
|
/* toast */
|
|
18524
|
-
.toasts { position:fixed; bottom:20px; left:20px; z-index:110; display:flex; flex-direction:column; gap:8px; }
|
|
18525
|
-
.toast { background:var(--fg); color:var(--bg); padding:10px 14px; border-radius:9px; font-size:13px; box-shadow:var(--shadow-lg);
|
|
18705
|
+
.toasts { position:fixed; bottom:20px; left:20px; max-width:calc(100vw - 40px); z-index:110; display:flex; flex-direction:column; gap:8px; }
|
|
18706
|
+
.toast { position:relative; box-sizing:border-box; touch-action:pan-y; user-select:none; transform:translateX(var(--toast-offset, 0px)); transition:transform .18s ease-out, opacity .16s ease; background:var(--fg); color:var(--bg); padding:10px 14px; border-radius:9px; font-size:13px; box-shadow:var(--shadow-lg);
|
|
18526
18707
|
display:flex; align-items:center; gap:8px; animation:slidein .2s ease; }
|
|
18527
18708
|
@keyframes slidein { from { opacity:0; transform:translateX(-12px); } }
|
|
18528
|
-
.toast.error { background:var(--danger); color
|
|
18709
|
+
.toast.error { background:var(--danger); color:var(--danger-fg); }
|
|
18529
18710
|
.toast.leaving { animation:toast-out .16s ease-in forwards; pointer-events:none; }
|
|
18530
18711
|
@keyframes toast-out { to { opacity:0; transform:translateX(-8px); } }
|
|
18531
|
-
.toast-msg { min-width:0; }
|
|
18712
|
+
.toast-msg { min-width:0; overflow-wrap:anywhere; }
|
|
18713
|
+
.toast > .ico, .toast-act { flex-shrink:0; }
|
|
18714
|
+
.toast.dragging { animation:none; transition:none; cursor:grabbing; }
|
|
18715
|
+
.toast.leaving.swipe-out { animation:none; transition:transform .16s ease-in, opacity .16s ease-in; }
|
|
18716
|
+
.toast-act:focus-visible { outline:2px solid currentColor; outline-offset:2px; }
|
|
18717
|
+
@media (prefers-reduced-motion:reduce) {
|
|
18718
|
+
.toast, .toast.dragging, .toast.leaving, .toast.leaving.swipe-out { animation:none; transition:none; transform:none; }
|
|
18719
|
+
.toast.leaving { opacity:0; }
|
|
18720
|
+
}
|
|
18532
18721
|
.toast-act { margin-left:4px; padding:3px 9px; border-radius:6px; font-weight:600; color:inherit; background:color-mix(in srgb, var(--bg) 16%, transparent); white-space:nowrap; }
|
|
18533
18722
|
.toast-act:hover { background:color-mix(in srgb, var(--bg) 28%, transparent); }
|
|
18534
18723
|
|
|
@@ -18611,6 +18800,93 @@ var styles_default = ` :root {
|
|
|
18611
18800
|
.doc-skel { max-width:720px; margin:40px auto; padding:0 24px; }
|
|
18612
18801
|
|
|
18613
18802
|
/* share / publish modal (share-modal.tsx) */
|
|
18803
|
+
/* Hosting-first object sharing: compact link rows and disclosed details. */
|
|
18804
|
+
.modal:has(.share-dialog) { border-radius:12px; }
|
|
18805
|
+
.modal:has(.share-dialog) .modal-head { position:relative; display:flex; align-items:baseline; gap:12px; padding:24px 56px 0 28px; min-width:0; }
|
|
18806
|
+
.modal:has(.share-dialog) .modal-head h3 { font-size:18px; font-weight:600; letter-spacing:0; padding:0; margin:0; flex:none; max-width:100%; }
|
|
18807
|
+
.modal:has(.share-dialog) .modal-head p { margin:0; font-size:var(--fs-ui); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
18808
|
+
.modal-close { position:absolute; right:16px; top:18px; color:var(--muted); }
|
|
18809
|
+
.modal:has(.share-dialog) .modal-body { padding:22px 28px 16px; }
|
|
18810
|
+
.modal:has(.share-dialog) .modal-foot { background:var(--bg); padding:12px 28px; justify-content:space-between; gap:12px; }
|
|
18811
|
+
.modal:has(.share-dialog) .modal-foot .btn { min-height:36px; font-weight:500; box-shadow:none; }
|
|
18812
|
+
.share-dialog { display:flex; flex-direction:column; gap:20px; font-size:var(--fs-ui); }
|
|
18813
|
+
.share-host { padding-bottom:20px; border-bottom:1px solid var(--line); }
|
|
18814
|
+
.share-host-label { display:block; margin-bottom:10px; color:var(--muted); font-size:var(--fs-sm); }
|
|
18815
|
+
.share-host-control { display:flex; align-items:center; gap:10px; min-width:0; }
|
|
18816
|
+
.share-host-control > .ico { width:20px; height:20px; color:var(--fg-soft); }
|
|
18817
|
+
.share-host-control select { flex:1; min-width:0; min-height:40px; padding:8px 10px; border:1px solid var(--line-strong); border-radius:var(--radius-sm); background:var(--bg); color:var(--fg); font:inherit; font-weight:500; }
|
|
18818
|
+
.share-host-behavior { margin:12px 0 0 30px; }
|
|
18819
|
+
.share-host-behavior strong { color:var(--fg-soft); font-size:var(--fs-sm); font-weight:500; }
|
|
18820
|
+
.share-host-behavior p { margin:5px 0 0; color:var(--muted); font-size:var(--fs-sm); line-height:1.65; }
|
|
18821
|
+
.share-list-heading { display:flex; align-items:center; gap:8px; color:var(--muted); font-size:var(--fs-sm); padding-bottom:8px; }
|
|
18822
|
+
.share-link-list { list-style:none; padding:0; margin:0; }
|
|
18823
|
+
.share-link-list > li + li { border-top:1px solid var(--line); }
|
|
18824
|
+
.share-link-row { display:flex; align-items:center; gap:12px; padding:16px 0; }
|
|
18825
|
+
.share-link-row > .ico { flex:none; width:20px; height:20px; color:var(--fg-soft); }
|
|
18826
|
+
.share-link-info { flex:1; min-width:0; }
|
|
18827
|
+
.share-link-name { display:flex; align-items:center; gap:4px; max-width:100%; color:var(--fg); font-size:var(--fs-ui); font-weight:600; text-align:left; border-radius:var(--radius-sm); }
|
|
18828
|
+
.share-link-name > span { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
18829
|
+
.share-link-name > .ico { flex:none; color:var(--muted); width:12px; }
|
|
18830
|
+
.share-link-meta { display:flex; flex-wrap:wrap; gap:2px 8px; margin-top:4px; font-variant-numeric:tabular-nums; font-size:var(--fs-xs); color:var(--muted); line-height:1.6; }
|
|
18831
|
+
.share-link-meta > span { white-space:nowrap; }
|
|
18832
|
+
.share-link-meta > span + span::before { content:"\xB7"; margin-right:8px; }
|
|
18833
|
+
.share-link-actions { display:flex; align-items:center; gap:6px; flex:none; }
|
|
18834
|
+
.share-link-actions .btn { min-height:32px; min-width:84px; justify-content:center; padding:5px 9px; font-size:var(--fs-sm); font-weight:500; box-shadow:none; white-space:nowrap; }
|
|
18835
|
+
.share-link-actions .iconbtn { width:32px; height:32px; color:var(--muted); }
|
|
18836
|
+
.share-link-detail { margin:0 0 16px 32px; }
|
|
18837
|
+
.share-link-detail > p, .share-link-warning { margin:0 0 12px; color:var(--muted); font-size:var(--fs-sm); line-height:1.65; }
|
|
18838
|
+
.share-link-warning { margin:4px 0 0; }
|
|
18839
|
+
.share-link-name:hover { background:var(--hover); }
|
|
18840
|
+
.share-link-name:focus-visible, .share-secondary:focus-visible { outline:2px solid var(--accent); outline-offset:3px; }
|
|
18841
|
+
@media (max-width:560px) {
|
|
18842
|
+
.share-link-row { flex-wrap:wrap; gap:8px; }
|
|
18843
|
+
.share-link-info { flex-basis:calc(100% - 32px); }
|
|
18844
|
+
.share-link-actions { margin-left:28px; }
|
|
18845
|
+
.share-link-actions .btn, .share-link-actions .iconbtn { min-height:40px; }
|
|
18846
|
+
}
|
|
18847
|
+
.share-facts { margin:0; display:flex; flex-direction:column; gap:12px; }
|
|
18848
|
+
.share-facts > div { display:flex; gap:20px; align-items:baseline; }
|
|
18849
|
+
.share-facts dt { flex:0 0 88px; color:var(--muted); font-size:var(--fs-sm); }
|
|
18850
|
+
.share-facts dd { margin:0; flex:1; text-align:right; color:var(--fg-soft); font-size:var(--fs-sm); overflow-wrap:anywhere; font-variant-numeric:tabular-nums; }
|
|
18851
|
+
.share-explanation { margin:-6px 0 0; font-size:var(--fs-sm); line-height:1.7; color:var(--muted); }
|
|
18852
|
+
.share-details { color:var(--fg-soft); font-size:var(--fs-sm); }
|
|
18853
|
+
.share-details summary { cursor:pointer; padding:4px 0; line-height:1.5; }
|
|
18854
|
+
.share-details summary:hover { color:var(--fg); }
|
|
18855
|
+
.share-details summary:focus-visible { outline:2px solid var(--accent); outline-offset:4px; border-radius:2px; }
|
|
18856
|
+
.share-details summary::marker { color:var(--muted); font-size:10px; }
|
|
18857
|
+
.share-details summary > span { margin-left:10px; color:var(--muted); font-size:var(--fs-xs); }
|
|
18858
|
+
.share-details > div, .share-details > dl { margin-top:16px; }
|
|
18859
|
+
.share-secondary { display:inline-flex; align-items:center; gap:6px; color:var(--muted); font-size:var(--fs-sm); border-radius:var(--radius-sm); }
|
|
18860
|
+
.share-secondary { padding:6px 0; }
|
|
18861
|
+
.share-secondary:hover { color:var(--fg); }
|
|
18862
|
+
.share-dialog button:disabled, .modal:has(.share-dialog) .modal-foot button:disabled { cursor:default; opacity:.5; }
|
|
18863
|
+
.share-settings { display:flex; flex-direction:column; gap:8px; }
|
|
18864
|
+
.share-setting { display:flex; align-items:center; gap:16px; min-height:38px; }
|
|
18865
|
+
.share-setting > span { flex:0 0 90px; color:var(--fg-soft); font-size:var(--fs-sm); }
|
|
18866
|
+
.share-setting select { flex:1; min-width:0; max-width:100%; min-height:34px; font:inherit; font-size:var(--fs-ui); color:var(--fg); border:1px solid var(--line); border-radius:var(--radius-sm); padding:5px 8px; background:var(--bg); }
|
|
18867
|
+
.share-setting select:disabled { color:var(--muted); background:var(--surface); opacity:1; }
|
|
18868
|
+
.share-setting input, .share-url { min-width:0; flex:1; min-height:34px; border:1px solid var(--line); border-radius:var(--radius-sm); padding:6px 9px; background:var(--bg); color:var(--fg); font-size:var(--fs-ui); }
|
|
18869
|
+
.share-setting input::placeholder { color:var(--muted); }
|
|
18870
|
+
.share-setting input:focus-visible, .share-url:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
|
|
18871
|
+
.share-dialog > .share-details { border-top:1px solid var(--line); padding-top:12px; }
|
|
18872
|
+
.share-url { display:block; width:100%; margin-top:12px; }
|
|
18873
|
+
.share-message { margin:0; padding:10px 12px; background:var(--surface); border-radius:var(--radius-sm); color:var(--fg-soft); font-size:var(--fs-sm); line-height:1.6; overflow-wrap:anywhere; }
|
|
18874
|
+
.share-message.error { color:var(--danger); background:var(--danger-soft); }
|
|
18875
|
+
.share-load-error p { margin-top:0; color:var(--muted); }
|
|
18876
|
+
.share-loading { display:grid; gap:14px; padding:4px 0; }
|
|
18877
|
+
.share-loading span { height:14px; background:var(--surface-2); border-radius:3px; }
|
|
18878
|
+
.share-loading span:first-child { width:55%; }
|
|
18879
|
+
.share-loading span:last-child { width:75%; }
|
|
18880
|
+
.share-sr-status { position:absolute; width:1px; height:1px; padding:0; overflow:hidden; clip-path:inset(50%); white-space:nowrap; }
|
|
18881
|
+
@media (max-width:560px) {
|
|
18882
|
+
.modal:has(.share-dialog) .modal-head { padding:22px 52px 0 20px; gap:10px; }
|
|
18883
|
+
.modal:has(.share-dialog) .modal-body { padding:20px 20px 12px; }
|
|
18884
|
+
.modal:has(.share-dialog) .modal-foot { padding:14px 20px; flex-wrap:wrap; }
|
|
18885
|
+
.modal:has(.share-dialog) .modal-foot .btn, .share-secondary { min-height:40px; }
|
|
18886
|
+
.share-setting { gap:12px; }
|
|
18887
|
+
.share-setting > span { flex-basis:80px; }
|
|
18888
|
+
.share-setting select, .share-setting input { min-height:40px; }
|
|
18889
|
+
}
|
|
18614
18890
|
.mhshare-body { display:flex; flex-direction:column; gap:10px; }
|
|
18615
18891
|
.mhshare-section { font-size:var(--fs-micro); font-weight:600; color:var(--muted); text-transform:uppercase; letter-spacing:.05em; margin-top:6px; }
|
|
18616
18892
|
.mhshare-field { display:flex; align-items:center; gap:12px; }
|
|
@@ -19188,22 +19464,31 @@ var styles_default = ` :root {
|
|
|
19188
19464
|
/* File-editor window (desktop, loaded at #file?path=\u2026 \u2014 the .txt/.md "open
|
|
19189
19465
|
with" surface). Same shell idiom as quicknote: top bar = drag region with
|
|
19190
19466
|
opted-out buttons, single full-bleed column, popups clamped below the bar. */
|
|
19191
|
-
body.file-window { --pop-top-inset:
|
|
19467
|
+
body.file-window { --pop-top-inset:48px; }
|
|
19192
19468
|
body.file-window #app { display:block; width:100vw; height:100vh; height:100dvh; }
|
|
19193
19469
|
.fw { display:flex; flex-direction:column; width:100%; height:100vh; height:100dvh; overflow:hidden; background:var(--bg); }
|
|
19194
|
-
.fw-bar { display:flex; align-items:center; gap:
|
|
19470
|
+
.fw-bar { display:flex; align-items:center; gap:12px; padding:0 16px; height:48px; flex:none;
|
|
19195
19471
|
user-select:none; -webkit-app-region:drag;
|
|
19196
19472
|
background:var(--surface); border-bottom:1px solid var(--line); }
|
|
19197
19473
|
/* macOS only: clear the inset traffic lights (frame is native elsewhere). */
|
|
19198
|
-
body.desktop-mac .fw-bar { padding-left:
|
|
19199
|
-
.fw-
|
|
19474
|
+
body.desktop-mac .fw-bar { padding-left:88px; }
|
|
19475
|
+
.fw-title { display:flex; align-items:center; gap:8px; flex:1; min-width:0; color:var(--muted); }
|
|
19476
|
+
.fw-name { min-width:0; font-size:var(--fs-sm); font-weight:500; color:var(--fg-soft);
|
|
19200
19477
|
white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
|
19201
|
-
.fw-dirty {
|
|
19202
|
-
.fw-
|
|
19203
|
-
.fw-
|
|
19478
|
+
.fw-dirty { width:6px; height:6px; flex:none; border-radius:50%; background:var(--accent); }
|
|
19479
|
+
.fw-status { display:flex; align-items:center; gap:6px; flex:none; color:var(--muted); font-size:var(--fs-xs); white-space:nowrap; }
|
|
19480
|
+
.fw-status:not(.is-dirty) .ico { color:var(--success); }
|
|
19481
|
+
.fw-actions { display:flex; align-items:center; gap:6px; flex:none; -webkit-app-region:no-drag; }
|
|
19482
|
+
.fw-actions .btn { min-height:30px; font-size:var(--fs-sm); }
|
|
19483
|
+
.fw-body .doc { padding-top:64px; padding-bottom:24vh; }
|
|
19204
19484
|
.fw-body { flex:1; overflow:auto; scrollbar-gutter:stable; scrollbar-width:thin; -webkit-app-region:no-drag; }
|
|
19205
|
-
|
|
19206
|
-
|
|
19485
|
+
body.file-window .find-bar { top:54px; }
|
|
19486
|
+
@media (max-width:720px) {
|
|
19487
|
+
.fw-bar { gap:8px; padding-right:12px; padding-left:12px; }
|
|
19488
|
+
.fw-status span, .fw-mode span, .fw-open span { display:none; }
|
|
19489
|
+
.fw-mode, .fw-open { width:30px; padding:0; justify-content:center; }
|
|
19490
|
+
.fw-body .doc { padding:36px 32px 24vh; }
|
|
19491
|
+
}
|
|
19207
19492
|
|
|
19208
19493
|
/* No-origin bootstrap: enroll screen + hydration splash (data-blind shell). */
|
|
19209
19494
|
.enroll-splash { min-height:100dvh; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:14px; padding:24px; }
|
|
@@ -19428,6 +19713,37 @@ var styles_default = ` :root {
|
|
|
19428
19713
|
.blob-mgr-row { grid-template-columns:26px 30px minmax(0,1fr) auto auto 28px; }
|
|
19429
19714
|
.blob-mgr-age { display:none; }
|
|
19430
19715
|
}
|
|
19716
|
+
|
|
19717
|
+
/* Standalone library document: the same editor, with a compact native shell. */
|
|
19718
|
+
.document-window { min-width:0; height:100dvh; }
|
|
19719
|
+
.document-window .dw-toolbar { padding:0 16px; height:48px; min-height:48px; flex:none;
|
|
19720
|
+
flex-wrap:nowrap; gap:12px; background:var(--surface); -webkit-app-region:drag; }
|
|
19721
|
+
body.desktop-mac .document-window .dw-toolbar { padding-left:88px; }
|
|
19722
|
+
.document-window .dw-toolbar button { -webkit-app-region:no-drag; }
|
|
19723
|
+
.dw-toolbar > button, .dw-toolbar .crumb > .ico { flex:none; }
|
|
19724
|
+
.dw-toolbar .crumb { min-width:0; color:var(--muted); font-size:var(--fs-sm); }
|
|
19725
|
+
.dw-path { display:flex; align-items:center; gap:8px; min-width:0; }
|
|
19726
|
+
.dw-path .crumb-link { max-width:160px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
19727
|
+
.dw-current { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--fg-soft); }
|
|
19728
|
+
.dw-save { display:flex; align-items:center; gap:6px; flex:none; font-size:var(--fs-xs); color:var(--muted);
|
|
19729
|
+
padding:6px 4px; border-radius:var(--radius-sm); }
|
|
19730
|
+
.dw-save:not(:disabled):hover { background:var(--hover); }
|
|
19731
|
+
.dw-save-saved .ico { color:var(--success); }
|
|
19732
|
+
.dw-save-error, .dw-save-conflict { color:var(--danger); }
|
|
19733
|
+
.dw-content .doc { padding-top:64px; padding-bottom:24vh; }
|
|
19734
|
+
.dw-content .doc-title { overflow-wrap:anywhere; }
|
|
19735
|
+
.dw-footer { display:flex; align-items:center; height:30px; flex:none; padding:0 18px;
|
|
19736
|
+
border-top:1px solid var(--line); color:var(--muted); font-size:var(--fs-xs); }
|
|
19737
|
+
.document-window .doc-wc { bottom:5px; right:16px; border:0; box-shadow:none; background:transparent; }
|
|
19738
|
+
.document-window .doc-toc { top:72px; }
|
|
19739
|
+
.document-window .find-bar { top:54px; }
|
|
19740
|
+
@media (max-width:720px) {
|
|
19741
|
+
.dw-save span { display:none; }
|
|
19742
|
+
.dw-path { display:none; }
|
|
19743
|
+
.document-window .dw-toolbar { gap:8px; padding:0 12px; }
|
|
19744
|
+
.dw-content .doc { padding:36px 32px 24vh; }
|
|
19745
|
+
.dw-content .doc-title { font-size:32px; }
|
|
19746
|
+
}
|
|
19431
19747
|
`;
|
|
19432
19748
|
|
|
19433
19749
|
// src/webui/server/icons.ts
|
|
@@ -19486,7 +19802,7 @@ var HTML2 = `<!doctype html>
|
|
|
19486
19802
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
19487
19803
|
<!-- Mobile browser chrome (status/address bar) tints to theme-color; app.tsx
|
|
19488
19804
|
keeps #theme-color-meta in sync with the active theme + visible surface. -->
|
|
19489
|
-
<meta name="theme-color" id="theme-color-meta" content="
|
|
19805
|
+
<meta name="theme-color" id="theme-color-meta" content="${LIGHT_THEME.bg}" />
|
|
19490
19806
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
19491
19807
|
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
|
19492
19808
|
<title>Metahub</title>
|
|
@@ -19501,9 +19817,10 @@ var HTML2 = `<!doctype html>
|
|
|
19501
19817
|
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"></noscript>
|
|
19502
19818
|
<!-- FOUC guard: resolve the stored choice (system \u2192 OS preference) to an
|
|
19503
19819
|
explicit data-resolved before first paint. CSS keys off data-resolved
|
|
19504
|
-
alone, so the dark palette exists exactly once \u2014 see
|
|
19820
|
+
alone, so the dark palette exists exactly once \u2014 see core/ui-theme.ts. Dark also
|
|
19505
19821
|
pre-tints the status bar (hex mirrors --bg) so the first frame isn't white. -->
|
|
19506
|
-
<
|
|
19822
|
+
<style>${THEME_CSS}html,body{background:var(--bg);color:var(--fg)}</style>
|
|
19823
|
+
<script>${THEME_INIT_SCRIPT}</script>
|
|
19507
19824
|
<!-- Same for the UI language: mirror src/webui/i18n/locale.ts so <html lang>
|
|
19508
19825
|
is right before the bundle runs. -->
|
|
19509
19826
|
<script>try{var l=localStorage.getItem('mh-lang');if(l!=='zh-CN'&&l!=='en'){var ls=navigator.languages&&navigator.languages.length?navigator.languages:[navigator.language];l='en';for(var i=0;i<ls.length;i++){var g=ls[i]||'';if(/^zh\\b/i.test(g)){l='zh-CN';break}if(/^en\\b/i.test(g))break}}document.documentElement.lang=l}catch(e){}</script>
|
|
@@ -19633,9 +19950,9 @@ var getRuntime = bundleGetter({ key: "runtime", entry: "../runtime.ts", dist: "m
|
|
|
19633
19950
|
var getSdk = bundleGetter({ key: "sdk", entry: "../../sdk/client.ts", dist: "metahub-sdk.js", extraDirs: ["../../sdk"] });
|
|
19634
19951
|
async function getCss() {
|
|
19635
19952
|
if (RUNNING_FROM_SOURCE) {
|
|
19636
|
-
return Bun.file(fileURLToPath(new URL("../styles.css", import.meta.url))).text();
|
|
19953
|
+
return THEME_CSS + await Bun.file(fileURLToPath(new URL("../styles.css", import.meta.url))).text();
|
|
19637
19954
|
}
|
|
19638
|
-
return styles_default;
|
|
19955
|
+
return THEME_CSS + styles_default;
|
|
19639
19956
|
}
|
|
19640
19957
|
async function getJsStamped() {
|
|
19641
19958
|
return (await getJs()).replaceAll("__MH_WEBUI_VERSION__", package_default.version);
|
|
@@ -19665,8 +19982,8 @@ var MANIFEST = JSON.stringify({
|
|
|
19665
19982
|
start_url: "/",
|
|
19666
19983
|
scope: "/",
|
|
19667
19984
|
display: "standalone",
|
|
19668
|
-
background_color:
|
|
19669
|
-
theme_color:
|
|
19985
|
+
background_color: LIGHT_THEME.bg,
|
|
19986
|
+
theme_color: LIGHT_THEME.bg,
|
|
19670
19987
|
icons: [
|
|
19671
19988
|
{ src: "/icons/icon-192.png", sizes: "192x192", type: "image/png" },
|
|
19672
19989
|
{ src: "/icons/icon-512.png", sizes: "512x512", type: "image/png" }
|
|
@@ -20979,6 +21296,162 @@ init_records();
|
|
|
20979
21296
|
init_blobs_core();
|
|
20980
21297
|
init_storage();
|
|
20981
21298
|
init_storage_s3_sign();
|
|
21299
|
+
|
|
21300
|
+
// src/core/sync/share-short-links.ts
|
|
21301
|
+
init_e2ee();
|
|
21302
|
+
init_storage();
|
|
21303
|
+
|
|
21304
|
+
// src/core/sync/share-link.ts
|
|
21305
|
+
init_e2ee();
|
|
21306
|
+
async function tokenHash(token) {
|
|
21307
|
+
return toB64url(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(token))));
|
|
21308
|
+
}
|
|
21309
|
+
async function linkId(token) {
|
|
21310
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(token));
|
|
21311
|
+
return toB64url(new Uint8Array(digest).slice(0, 16));
|
|
21312
|
+
}
|
|
21313
|
+
function signedUrlExpiry(value) {
|
|
21314
|
+
try {
|
|
21315
|
+
const u = new URL(value);
|
|
21316
|
+
if (u.protocol !== "https:" || u.username || u.password || u.hash || value.length > 8192)
|
|
21317
|
+
return null;
|
|
21318
|
+
const date = u.searchParams.get("X-Amz-Date") ?? "";
|
|
21319
|
+
const seconds = Number(u.searchParams.get("X-Amz-Expires"));
|
|
21320
|
+
if (!/^\d{8}T\d{6}Z$/.test(date) || !Number.isInteger(seconds) || seconds < 1 || seconds > 604800)
|
|
21321
|
+
return null;
|
|
21322
|
+
if (!/^[a-f0-9]{64}$/i.test(u.searchParams.get("X-Amz-Signature") ?? ""))
|
|
21323
|
+
return null;
|
|
21324
|
+
const iso = `${date.slice(0, 4)}-${date.slice(4, 6)}-${date.slice(6, 8)}T${date.slice(9, 11)}:${date.slice(11, 13)}:${date.slice(13, 15)}Z`;
|
|
21325
|
+
const start = Date.parse(iso);
|
|
21326
|
+
return Number.isFinite(start) ? start + seconds * 1000 : null;
|
|
21327
|
+
} catch {
|
|
21328
|
+
return null;
|
|
21329
|
+
}
|
|
21330
|
+
}
|
|
21331
|
+
function longShareUrl(base, link) {
|
|
21332
|
+
return `${base.replace(/\/+$/, "")}/#m=${encodeURIComponent(link.manifestUrl)}&${link.keyB64 ? `k=${link.keyB64}` : `s=${link.saltB64}`}`;
|
|
21333
|
+
}
|
|
21334
|
+
|
|
21335
|
+
// src/core/sync/share-short-links.ts
|
|
21336
|
+
var TIMEOUT = 8000;
|
|
21337
|
+
function root(config, slug) {
|
|
21338
|
+
return `${config.prefix.replace(/^\/+|\/+$/g, "") ? `${config.prefix.replace(/^\/+|\/+$/g, "")}/` : ""}shares/${slug}/links/`;
|
|
21339
|
+
}
|
|
21340
|
+
function viewerBase(base) {
|
|
21341
|
+
const url = new URL(base);
|
|
21342
|
+
if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash)
|
|
21343
|
+
throw new Error("invalid viewer");
|
|
21344
|
+
if (url.pathname !== "/")
|
|
21345
|
+
throw new Error("static subpath viewer");
|
|
21346
|
+
return url.origin;
|
|
21347
|
+
}
|
|
21348
|
+
async function unpack(config, bytes) {
|
|
21349
|
+
const raw = config.encrypt && config.masterKey ? await decryptBytes(fromB64(config.masterKey), bytes) : bytes;
|
|
21350
|
+
const value = JSON.parse(new TextDecoder().decode(raw));
|
|
21351
|
+
if (value.v !== 1 || !/^[A-Za-z0-9_-]{43}$/.test(value.token) || viewerBase(value.base) !== value.base)
|
|
21352
|
+
throw new Error("invalid short-link control");
|
|
21353
|
+
return value;
|
|
21354
|
+
}
|
|
21355
|
+
async function controlFor(config, slug, base) {
|
|
21356
|
+
const client = storageClientFor(config);
|
|
21357
|
+
const path = `${root(config, slug)}${await tokenHash(base)}.json`;
|
|
21358
|
+
const existing = await client.get(path);
|
|
21359
|
+
if (existing) {
|
|
21360
|
+
const control = await unpack(config, existing);
|
|
21361
|
+
if (control.base !== base)
|
|
21362
|
+
throw new Error("viewer mismatch");
|
|
21363
|
+
return control;
|
|
21364
|
+
}
|
|
21365
|
+
const control = { v: 1, base, token: toB64url(generateMasterKey()) };
|
|
21366
|
+
const plain = new TextEncoder().encode(JSON.stringify(control));
|
|
21367
|
+
const bytes = config.encrypt && config.masterKey ? await encryptBytes(fromB64(config.masterKey), plain) : plain;
|
|
21368
|
+
try {
|
|
21369
|
+
await client.put(path, bytes, {
|
|
21370
|
+
ifNoneMatch: true,
|
|
21371
|
+
contentType: "application/octet-stream"
|
|
21372
|
+
});
|
|
21373
|
+
} catch (error) {
|
|
21374
|
+
const winner = await client.get(path);
|
|
21375
|
+
if (!winner)
|
|
21376
|
+
throw error;
|
|
21377
|
+
const value = await unpack(config, winner);
|
|
21378
|
+
if (value.base !== base)
|
|
21379
|
+
throw new Error("viewer mismatch");
|
|
21380
|
+
return value;
|
|
21381
|
+
}
|
|
21382
|
+
return control;
|
|
21383
|
+
}
|
|
21384
|
+
function request(url, init = {}) {
|
|
21385
|
+
return fetch(url, {
|
|
21386
|
+
...init,
|
|
21387
|
+
redirect: "error",
|
|
21388
|
+
credentials: "omit",
|
|
21389
|
+
cache: "no-store",
|
|
21390
|
+
signal: AbortSignal.timeout(TIMEOUT)
|
|
21391
|
+
});
|
|
21392
|
+
}
|
|
21393
|
+
async function bucketShareUrl(config, slug, base, link) {
|
|
21394
|
+
const fallback = longShareUrl(base, link);
|
|
21395
|
+
try {
|
|
21396
|
+
const origin = viewerBase(base);
|
|
21397
|
+
const expiresAt = Math.min(link.presignExp, signedUrlExpiry(link.manifestUrl) ?? 0);
|
|
21398
|
+
if (expiresAt <= Date.now())
|
|
21399
|
+
return fallback;
|
|
21400
|
+
const probe = await request(`${origin}/api/links`);
|
|
21401
|
+
if (!probe.ok || (await probe.json()).service !== "metahub-share-links")
|
|
21402
|
+
throw new Error("static viewer");
|
|
21403
|
+
const control = await controlFor(config, slug, origin);
|
|
21404
|
+
const id = await linkId(control.token);
|
|
21405
|
+
const endpoint = `${origin}/api/links/${id}`;
|
|
21406
|
+
const authorization = `Bearer ${control.token}`;
|
|
21407
|
+
const descriptor = {
|
|
21408
|
+
v: 1,
|
|
21409
|
+
manifestUrl: link.manifestUrl,
|
|
21410
|
+
expiresAt,
|
|
21411
|
+
...link.saltB64 ? { salt: toB64url(fromB64(link.saltB64)) } : {}
|
|
21412
|
+
};
|
|
21413
|
+
const current = await request(endpoint, { headers: { authorization } });
|
|
21414
|
+
if (!current.ok && current.status !== 404)
|
|
21415
|
+
throw new Error("short-link lookup failed");
|
|
21416
|
+
const etag = current.headers.get("etag");
|
|
21417
|
+
if (current.ok && !etag)
|
|
21418
|
+
throw new Error("not a short-link API");
|
|
21419
|
+
const result = await request(endpoint, {
|
|
21420
|
+
method: "PUT",
|
|
21421
|
+
headers: {
|
|
21422
|
+
authorization,
|
|
21423
|
+
"content-type": "application/json",
|
|
21424
|
+
...current.ok ? { "if-match": etag } : { "if-none-match": "*" }
|
|
21425
|
+
},
|
|
21426
|
+
body: JSON.stringify(descriptor)
|
|
21427
|
+
});
|
|
21428
|
+
if (!result.ok || !result.headers.get("etag") || (await result.json()).ok !== true)
|
|
21429
|
+
throw new Error("short-link registration failed");
|
|
21430
|
+
return `${origin}/s/${id}${link.keyB64 ? `#k=${toB64url(fromB64(link.keyB64))}` : ""}`;
|
|
21431
|
+
} catch {
|
|
21432
|
+
console.warn("share: short-link service unavailable; using the original long link");
|
|
21433
|
+
return fallback;
|
|
21434
|
+
}
|
|
21435
|
+
}
|
|
21436
|
+
async function revokeBucketShortLinks(config, slug) {
|
|
21437
|
+
const client = storageClientFor(config);
|
|
21438
|
+
for (const object of await client.list(root(config, slug))) {
|
|
21439
|
+
if (!object.key.endsWith(".json"))
|
|
21440
|
+
continue;
|
|
21441
|
+
const raw = await client.get(object.key);
|
|
21442
|
+
if (!raw)
|
|
21443
|
+
continue;
|
|
21444
|
+
const control = await unpack(config, raw);
|
|
21445
|
+
const response = await request(`${control.base}/api/links/${await linkId(control.token)}`, {
|
|
21446
|
+
method: "DELETE",
|
|
21447
|
+
headers: { authorization: `Bearer ${control.token}` }
|
|
21448
|
+
});
|
|
21449
|
+
if (!response.ok || (await response.json()).ok !== true)
|
|
21450
|
+
throw new Error("short-link revocation has not been confirmed; retry later");
|
|
21451
|
+
}
|
|
21452
|
+
}
|
|
21453
|
+
|
|
21454
|
+
// src/core/sync/share-export.ts
|
|
20982
21455
|
init_e2ee();
|
|
20983
21456
|
function sharesRoot(prefix) {
|
|
20984
21457
|
const p = (prefix || "").replace(/^\/+|\/+$/g, "");
|
|
@@ -21119,6 +21592,8 @@ async function renewBucketShare(db, config, slug, expiresSec = MAX_PRESIGN_SECON
|
|
|
21119
21592
|
const meta = await readMeta2(config, slug);
|
|
21120
21593
|
if (!meta)
|
|
21121
21594
|
throw new MhError("not_found", `no such bucket share: ${slug}`);
|
|
21595
|
+
if (meta.revoking)
|
|
21596
|
+
throw new MhError("conflict", "share revocation is pending; retry revocation instead");
|
|
21122
21597
|
const shareKey = fromB64(meta.key);
|
|
21123
21598
|
const exp = clampExpiry(expiresSec);
|
|
21124
21599
|
const { manifestUrl, objects, title } = await writeShareObjects(db, {
|
|
@@ -21154,6 +21629,8 @@ async function represignBucketShare(config, slug, expiresSec = MAX_PRESIGN_SECON
|
|
|
21154
21629
|
const meta = await readMeta2(config, slug);
|
|
21155
21630
|
if (!meta)
|
|
21156
21631
|
throw new MhError("not_found", `no such bucket share: ${slug}`);
|
|
21632
|
+
if (meta.revoking)
|
|
21633
|
+
throw new MhError("conflict", "share revocation is pending; retry revocation instead");
|
|
21157
21634
|
const client = storageClientFor(config);
|
|
21158
21635
|
const root = sharesRoot(config.prefix);
|
|
21159
21636
|
const shareKey = fromB64(meta.key);
|
|
@@ -21193,15 +21670,19 @@ async function listBucketShares(config) {
|
|
|
21193
21670
|
async function deleteBucketShareObjects(config, slug) {
|
|
21194
21671
|
const client = storageClientFor(config);
|
|
21195
21672
|
const root = sharesRoot(config.prefix);
|
|
21196
|
-
await
|
|
21197
|
-
|
|
21198
|
-
|
|
21199
|
-
|
|
21200
|
-
const objs = meta?.objects ?? (await client.list(`${root}/${slug}/`)
|
|
21673
|
+
const meta = await readMeta2(config, slug);
|
|
21674
|
+
if (meta)
|
|
21675
|
+
await client.put(metaKey(root, slug), await metaBytes(config, { ...meta, revoking: true }), { contentType: "application/octet-stream" });
|
|
21676
|
+
await revokeBucketShortLinks(config, slug);
|
|
21677
|
+
const objs = new Set([...meta?.objects ?? [], ...(await client.list(`${root}/${slug}/`)).map((o) => o.key)]);
|
|
21678
|
+
const metaPath = metaKey(root, slug);
|
|
21201
21679
|
for (const key of objs)
|
|
21202
|
-
|
|
21203
|
-
|
|
21204
|
-
|
|
21680
|
+
if (key !== metaPath && !key.includes(`/links/`))
|
|
21681
|
+
await client.del(key);
|
|
21682
|
+
for (const key of objs)
|
|
21683
|
+
if (key.includes(`/links/`))
|
|
21684
|
+
await client.del(key);
|
|
21685
|
+
await client.del(metaPath);
|
|
21205
21686
|
}
|
|
21206
21687
|
function clampExpiry(sec) {
|
|
21207
21688
|
return Math.min(Math.max(60, Math.floor(sec)), MAX_PRESIGN_SECONDS);
|
|
@@ -21236,7 +21717,8 @@ function bucketShareItem(bucket, m) {
|
|
|
21236
21717
|
hosting: "s3",
|
|
21237
21718
|
expiresAt: m.presign_exp,
|
|
21238
21719
|
hasPassword: m.has_password,
|
|
21239
|
-
contentUpdatedAt: m.content_updated_at ?? m.created_at
|
|
21720
|
+
contentUpdatedAt: m.content_updated_at ?? m.created_at,
|
|
21721
|
+
...m.revoking ? { lifecycle: "cleanup_pending" } : {}
|
|
21240
21722
|
};
|
|
21241
21723
|
}
|
|
21242
21724
|
async function fetchPeerShares(url, token, targetId) {
|
|
@@ -21438,7 +21920,7 @@ function pickBucket(db, bucketUrl) {
|
|
|
21438
21920
|
throw new MhError("invalid_input", `multiple buckets \u2014 pass --bucket <url> (one of: ${buckets.map((b) => b.url).join(", ")})`);
|
|
21439
21921
|
return buckets[0].url;
|
|
21440
21922
|
}
|
|
21441
|
-
function
|
|
21923
|
+
function viewerBase2(db, override) {
|
|
21442
21924
|
if (override)
|
|
21443
21925
|
return override.replace(/\/+$/, "");
|
|
21444
21926
|
const row = db.query("SELECT value FROM meta WHERE key='cfg_share_viewer_url'").get();
|
|
@@ -21451,10 +21933,6 @@ function viewerOriginOf(base) {
|
|
|
21451
21933
|
return;
|
|
21452
21934
|
}
|
|
21453
21935
|
}
|
|
21454
|
-
function bucketLink(base, manifestUrl, keyB64, saltB64) {
|
|
21455
|
-
const frag = `m=${encodeURIComponent(manifestUrl)}&` + (keyB64 ? `k=${keyB64}` : `s=${saltB64}`);
|
|
21456
|
-
return `${base}/#${frag}`;
|
|
21457
|
-
}
|
|
21458
21936
|
function assertShareCombo(req) {
|
|
21459
21937
|
const fail = (msg) => {
|
|
21460
21938
|
throw new MhError("invalid_input", msg);
|
|
@@ -21481,7 +21959,7 @@ async function createShareAction(db, req) {
|
|
|
21481
21959
|
const target = resolveTarget(db, req.kind, req.ref);
|
|
21482
21960
|
const bucketUrl = pickBucket(db, req.bucketUrl);
|
|
21483
21961
|
const { config, label } = s3PeerConfig2(db, bucketUrl);
|
|
21484
|
-
const base =
|
|
21962
|
+
const base = viewerBase2(db, req.viewerBase);
|
|
21485
21963
|
const slug = freshSlug(db);
|
|
21486
21964
|
const out = await createBucketShare(db, {
|
|
21487
21965
|
slug,
|
|
@@ -21499,7 +21977,7 @@ async function createShareAction(db, req) {
|
|
|
21499
21977
|
permission: "view",
|
|
21500
21978
|
transport: "s3",
|
|
21501
21979
|
hosting: "s3",
|
|
21502
|
-
url:
|
|
21980
|
+
url: await bucketShareUrl(config, slug, base, out),
|
|
21503
21981
|
expiresAt: out.presignExp,
|
|
21504
21982
|
source: `\u6876 ${label}`
|
|
21505
21983
|
};
|
|
@@ -21784,7 +22262,13 @@ async function revokeShareAction(db, slug) {
|
|
|
21784
22262
|
const owner = await bucketOwning(db, slug);
|
|
21785
22263
|
if (!owner)
|
|
21786
22264
|
return { ok: false, status: "not_found" };
|
|
21787
|
-
|
|
22265
|
+
try {
|
|
22266
|
+
await deleteBucketShareObjects(JSON.parse(owner.peer.config), slug);
|
|
22267
|
+
} catch {
|
|
22268
|
+
if (owner.item)
|
|
22269
|
+
primeRemoteShare(db, owner.peer.url, { ...owner.item, lifecycle: "cleanup_pending" });
|
|
22270
|
+
return { ok: false, status: "cleanup_pending" };
|
|
22271
|
+
}
|
|
21788
22272
|
dropRemoteShare(db, owner.peer.url, slug);
|
|
21789
22273
|
return { ok: true, status: "revoked" };
|
|
21790
22274
|
}
|
|
@@ -21806,7 +22290,7 @@ async function renewShareAction(db, slug, viewerBaseOverride, opts) {
|
|
|
21806
22290
|
throw new MhError("not_found", `no such object-storage share: ${slug}`);
|
|
21807
22291
|
const { peer: p } = owner;
|
|
21808
22292
|
const config = JSON.parse(p.config);
|
|
21809
|
-
const base =
|
|
22293
|
+
const base = viewerBase2(db, viewerBaseOverride);
|
|
21810
22294
|
const out = opts?.refreshContent ? await renewBucketShare(db, config, slug) : await represignBucketShare(config, slug);
|
|
21811
22295
|
if (owner.item)
|
|
21812
22296
|
primeRemoteShare(db, p.url, {
|
|
@@ -21821,7 +22305,7 @@ async function renewShareAction(db, slug, viewerBaseOverride, opts) {
|
|
|
21821
22305
|
permission: "view",
|
|
21822
22306
|
transport: "s3",
|
|
21823
22307
|
hosting: "s3",
|
|
21824
|
-
url:
|
|
22308
|
+
url: await bucketShareUrl(config, slug, base, out),
|
|
21825
22309
|
expiresAt: out.presignExp,
|
|
21826
22310
|
source: `\u6876 ${p.label ?? p.url}`
|
|
21827
22311
|
};
|
|
@@ -22899,6 +23383,7 @@ async function enableWorkerSubdomain(cfg) {
|
|
|
22899
23383
|
}
|
|
22900
23384
|
|
|
22901
23385
|
// src/core/sync/room-serve.ts
|
|
23386
|
+
init_ui_theme();
|
|
22902
23387
|
init_errors();
|
|
22903
23388
|
init_http_status();
|
|
22904
23389
|
init_ids();
|
|
@@ -22910,6 +23395,19 @@ init_sites_core();
|
|
|
22910
23395
|
init_shares();
|
|
22911
23396
|
init_room_protocol();
|
|
22912
23397
|
var ROOM_SESSION_TTL_MS = 12 * 60 * 60 * 1000;
|
|
23398
|
+
var PAGE_CSS = `
|
|
23399
|
+
${THEME_CSS}
|
|
23400
|
+
*{box-sizing:border-box}
|
|
23401
|
+
body{margin:0;background:var(--bg);color:var(--fg);font:16px/1.65 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"PingFang SC","Microsoft YaHei",sans-serif;
|
|
23402
|
+
min-height:100dvh;display:flex;align-items:center;justify-content:center;padding:24px}
|
|
23403
|
+
main{max-width:420px;width:100%}
|
|
23404
|
+
form.pw{display:flex;flex-direction:column;gap:12px}
|
|
23405
|
+
form.pw input{padding:9px;border:1px solid var(--line);border-radius:7px;background:var(--card);color:var(--fg)}
|
|
23406
|
+
form.pw button{padding:9px;border:0;border-radius:7px;background:var(--accent);color:var(--accent-fg);cursor:pointer}
|
|
23407
|
+
.err{color:var(--danger);font-size:13px;margin:0}
|
|
23408
|
+
.muted{color:var(--muted);font-size:14px}
|
|
23409
|
+
h1{font-size:20px;margin:0 0 10px;text-align:center}
|
|
23410
|
+
footer{margin-top:34px;color:var(--muted);font-size:12px;text-align:center}`;
|
|
22913
23411
|
|
|
22914
23412
|
// src/workers/room.ts
|
|
22915
23413
|
init_room_protocol();
|
|
@@ -23384,6 +23882,7 @@ function disconnectEdge(db) {
|
|
|
23384
23882
|
}
|
|
23385
23883
|
|
|
23386
23884
|
// src/core/sync/cf-oauth.ts
|
|
23885
|
+
init_ui_theme();
|
|
23387
23886
|
init_errors();
|
|
23388
23887
|
init_page_messages();
|
|
23389
23888
|
init_e2ee();
|
|
@@ -23546,7 +24045,7 @@ async function startCfLogin(opts = {}) {
|
|
|
23546
24045
|
}
|
|
23547
24046
|
};
|
|
23548
24047
|
}
|
|
23549
|
-
var callbackHtml = (locale) => `<!doctype html><html lang="${locale}"><meta charset="utf-8"><title>MetaHub</title>
|
|
24048
|
+
var callbackHtml = (locale) => `<!doctype html><html lang="${locale}"><meta charset="utf-8"><title>MetaHub</title><style>${THEME_CSS}body{background:var(--bg);color:var(--fg)}h2{color:var(--success)}p{color:var(--muted)}</style>
|
|
23550
24049
|
<body style="font:15px system-ui;display:grid;place-items:center;height:100vh;margin:0">
|
|
23551
24050
|
<div style="text-align:center"><h2>${pm(locale, "\u2705 \u5DF2\u6388\u6743")}</h2><p>${pm(locale, "\u53EF\u4EE5\u5173\u95ED\u6B64\u6807\u7B7E\u9875\uFF0C\u56DE\u5230 MetaHub \u7EE7\u7EED\u90E8\u7F72\u3002")}</p></div>`;
|
|
23552
24051
|
|
|
@@ -24853,4 +25352,4 @@ export {
|
|
|
24853
25352
|
writeTx
|
|
24854
25353
|
};
|
|
24855
25354
|
|
|
24856
|
-
//# debugId=
|
|
25355
|
+
//# debugId=ACE65D6746A1B19864756E2164756E21
|