@tensorix/metahub 0.5.4 → 0.5.6
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 +666 -152
- 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 +619 -128
- 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.6",
|
|
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; }
|
|
@@ -18525,7 +18706,7 @@ var styles_default = ` :root {
|
|
|
18525
18706
|
.toast { 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
18712
|
.toast-msg { min-width:0; }
|
|
@@ -18611,6 +18792,93 @@ var styles_default = ` :root {
|
|
|
18611
18792
|
.doc-skel { max-width:720px; margin:40px auto; padding:0 24px; }
|
|
18612
18793
|
|
|
18613
18794
|
/* share / publish modal (share-modal.tsx) */
|
|
18795
|
+
/* Hosting-first object sharing: compact link rows and disclosed details. */
|
|
18796
|
+
.modal:has(.share-dialog) { border-radius:12px; }
|
|
18797
|
+
.modal:has(.share-dialog) .modal-head { position:relative; display:flex; align-items:baseline; gap:12px; padding:24px 56px 0 28px; min-width:0; }
|
|
18798
|
+
.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%; }
|
|
18799
|
+
.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; }
|
|
18800
|
+
.modal-close { position:absolute; right:16px; top:18px; color:var(--muted); }
|
|
18801
|
+
.modal:has(.share-dialog) .modal-body { padding:22px 28px 16px; }
|
|
18802
|
+
.modal:has(.share-dialog) .modal-foot { background:var(--bg); padding:12px 28px; justify-content:space-between; gap:12px; }
|
|
18803
|
+
.modal:has(.share-dialog) .modal-foot .btn { min-height:36px; font-weight:500; box-shadow:none; }
|
|
18804
|
+
.share-dialog { display:flex; flex-direction:column; gap:20px; font-size:var(--fs-ui); }
|
|
18805
|
+
.share-host { padding-bottom:20px; border-bottom:1px solid var(--line); }
|
|
18806
|
+
.share-host-label { display:block; margin-bottom:10px; color:var(--muted); font-size:var(--fs-sm); }
|
|
18807
|
+
.share-host-control { display:flex; align-items:center; gap:10px; min-width:0; }
|
|
18808
|
+
.share-host-control > .ico { width:20px; height:20px; color:var(--fg-soft); }
|
|
18809
|
+
.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; }
|
|
18810
|
+
.share-host-behavior { margin:12px 0 0 30px; }
|
|
18811
|
+
.share-host-behavior strong { color:var(--fg-soft); font-size:var(--fs-sm); font-weight:500; }
|
|
18812
|
+
.share-host-behavior p { margin:5px 0 0; color:var(--muted); font-size:var(--fs-sm); line-height:1.65; }
|
|
18813
|
+
.share-list-heading { display:flex; align-items:center; gap:8px; color:var(--muted); font-size:var(--fs-sm); padding-bottom:8px; }
|
|
18814
|
+
.share-link-list { list-style:none; padding:0; margin:0; }
|
|
18815
|
+
.share-link-list > li + li { border-top:1px solid var(--line); }
|
|
18816
|
+
.share-link-row { display:flex; align-items:center; gap:12px; padding:16px 0; }
|
|
18817
|
+
.share-link-row > .ico { flex:none; width:20px; height:20px; color:var(--fg-soft); }
|
|
18818
|
+
.share-link-info { flex:1; min-width:0; }
|
|
18819
|
+
.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); }
|
|
18820
|
+
.share-link-name > span { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
18821
|
+
.share-link-name > .ico { flex:none; color:var(--muted); width:12px; }
|
|
18822
|
+
.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; }
|
|
18823
|
+
.share-link-meta > span { white-space:nowrap; }
|
|
18824
|
+
.share-link-meta > span + span::before { content:"\xB7"; margin-right:8px; }
|
|
18825
|
+
.share-link-actions { display:flex; align-items:center; gap:6px; flex:none; }
|
|
18826
|
+
.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; }
|
|
18827
|
+
.share-link-actions .iconbtn { width:32px; height:32px; color:var(--muted); }
|
|
18828
|
+
.share-link-detail { margin:0 0 16px 32px; }
|
|
18829
|
+
.share-link-detail > p, .share-link-warning { margin:0 0 12px; color:var(--muted); font-size:var(--fs-sm); line-height:1.65; }
|
|
18830
|
+
.share-link-warning { margin:4px 0 0; }
|
|
18831
|
+
.share-link-name:hover { background:var(--hover); }
|
|
18832
|
+
.share-link-name:focus-visible, .share-secondary:focus-visible { outline:2px solid var(--accent); outline-offset:3px; }
|
|
18833
|
+
@media (max-width:560px) {
|
|
18834
|
+
.share-link-row { flex-wrap:wrap; gap:8px; }
|
|
18835
|
+
.share-link-info { flex-basis:calc(100% - 32px); }
|
|
18836
|
+
.share-link-actions { margin-left:28px; }
|
|
18837
|
+
.share-link-actions .btn, .share-link-actions .iconbtn { min-height:40px; }
|
|
18838
|
+
}
|
|
18839
|
+
.share-facts { margin:0; display:flex; flex-direction:column; gap:12px; }
|
|
18840
|
+
.share-facts > div { display:flex; gap:20px; align-items:baseline; }
|
|
18841
|
+
.share-facts dt { flex:0 0 88px; color:var(--muted); font-size:var(--fs-sm); }
|
|
18842
|
+
.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; }
|
|
18843
|
+
.share-explanation { margin:-6px 0 0; font-size:var(--fs-sm); line-height:1.7; color:var(--muted); }
|
|
18844
|
+
.share-details { color:var(--fg-soft); font-size:var(--fs-sm); }
|
|
18845
|
+
.share-details summary { cursor:pointer; padding:4px 0; line-height:1.5; }
|
|
18846
|
+
.share-details summary:hover { color:var(--fg); }
|
|
18847
|
+
.share-details summary:focus-visible { outline:2px solid var(--accent); outline-offset:4px; border-radius:2px; }
|
|
18848
|
+
.share-details summary::marker { color:var(--muted); font-size:10px; }
|
|
18849
|
+
.share-details summary > span { margin-left:10px; color:var(--muted); font-size:var(--fs-xs); }
|
|
18850
|
+
.share-details > div, .share-details > dl { margin-top:16px; }
|
|
18851
|
+
.share-secondary { display:inline-flex; align-items:center; gap:6px; color:var(--muted); font-size:var(--fs-sm); border-radius:var(--radius-sm); }
|
|
18852
|
+
.share-secondary { padding:6px 0; }
|
|
18853
|
+
.share-secondary:hover { color:var(--fg); }
|
|
18854
|
+
.share-dialog button:disabled, .modal:has(.share-dialog) .modal-foot button:disabled { cursor:default; opacity:.5; }
|
|
18855
|
+
.share-settings { display:flex; flex-direction:column; gap:8px; }
|
|
18856
|
+
.share-setting { display:flex; align-items:center; gap:16px; min-height:38px; }
|
|
18857
|
+
.share-setting > span { flex:0 0 90px; color:var(--fg-soft); font-size:var(--fs-sm); }
|
|
18858
|
+
.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); }
|
|
18859
|
+
.share-setting select:disabled { color:var(--muted); background:var(--surface); opacity:1; }
|
|
18860
|
+
.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); }
|
|
18861
|
+
.share-setting input::placeholder { color:var(--muted); }
|
|
18862
|
+
.share-setting input:focus-visible, .share-url:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
|
|
18863
|
+
.share-dialog > .share-details { border-top:1px solid var(--line); padding-top:12px; }
|
|
18864
|
+
.share-url { display:block; width:100%; margin-top:12px; }
|
|
18865
|
+
.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; }
|
|
18866
|
+
.share-message.error { color:var(--danger); background:var(--danger-soft); }
|
|
18867
|
+
.share-load-error p { margin-top:0; color:var(--muted); }
|
|
18868
|
+
.share-loading { display:grid; gap:14px; padding:4px 0; }
|
|
18869
|
+
.share-loading span { height:14px; background:var(--surface-2); border-radius:3px; }
|
|
18870
|
+
.share-loading span:first-child { width:55%; }
|
|
18871
|
+
.share-loading span:last-child { width:75%; }
|
|
18872
|
+
.share-sr-status { position:absolute; width:1px; height:1px; padding:0; overflow:hidden; clip-path:inset(50%); white-space:nowrap; }
|
|
18873
|
+
@media (max-width:560px) {
|
|
18874
|
+
.modal:has(.share-dialog) .modal-head { padding:22px 52px 0 20px; gap:10px; }
|
|
18875
|
+
.modal:has(.share-dialog) .modal-body { padding:20px 20px 12px; }
|
|
18876
|
+
.modal:has(.share-dialog) .modal-foot { padding:14px 20px; flex-wrap:wrap; }
|
|
18877
|
+
.modal:has(.share-dialog) .modal-foot .btn, .share-secondary { min-height:40px; }
|
|
18878
|
+
.share-setting { gap:12px; }
|
|
18879
|
+
.share-setting > span { flex-basis:80px; }
|
|
18880
|
+
.share-setting select, .share-setting input { min-height:40px; }
|
|
18881
|
+
}
|
|
18614
18882
|
.mhshare-body { display:flex; flex-direction:column; gap:10px; }
|
|
18615
18883
|
.mhshare-section { font-size:var(--fs-micro); font-weight:600; color:var(--muted); text-transform:uppercase; letter-spacing:.05em; margin-top:6px; }
|
|
18616
18884
|
.mhshare-field { display:flex; align-items:center; gap:12px; }
|
|
@@ -19188,22 +19456,31 @@ var styles_default = ` :root {
|
|
|
19188
19456
|
/* File-editor window (desktop, loaded at #file?path=\u2026 \u2014 the .txt/.md "open
|
|
19189
19457
|
with" surface). Same shell idiom as quicknote: top bar = drag region with
|
|
19190
19458
|
opted-out buttons, single full-bleed column, popups clamped below the bar. */
|
|
19191
|
-
body.file-window { --pop-top-inset:
|
|
19459
|
+
body.file-window { --pop-top-inset:48px; }
|
|
19192
19460
|
body.file-window #app { display:block; width:100vw; height:100vh; height:100dvh; }
|
|
19193
19461
|
.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:
|
|
19462
|
+
.fw-bar { display:flex; align-items:center; gap:12px; padding:0 16px; height:48px; flex:none;
|
|
19195
19463
|
user-select:none; -webkit-app-region:drag;
|
|
19196
19464
|
background:var(--surface); border-bottom:1px solid var(--line); }
|
|
19197
19465
|
/* macOS only: clear the inset traffic lights (frame is native elsewhere). */
|
|
19198
|
-
body.desktop-mac .fw-bar { padding-left:
|
|
19199
|
-
.fw-
|
|
19466
|
+
body.desktop-mac .fw-bar { padding-left:88px; }
|
|
19467
|
+
.fw-title { display:flex; align-items:center; gap:8px; flex:1; min-width:0; color:var(--muted); }
|
|
19468
|
+
.fw-name { min-width:0; font-size:var(--fs-sm); font-weight:500; color:var(--fg-soft);
|
|
19200
19469
|
white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
|
19201
|
-
.fw-dirty {
|
|
19202
|
-
.fw-
|
|
19203
|
-
.fw-
|
|
19470
|
+
.fw-dirty { width:6px; height:6px; flex:none; border-radius:50%; background:var(--accent); }
|
|
19471
|
+
.fw-status { display:flex; align-items:center; gap:6px; flex:none; color:var(--muted); font-size:var(--fs-xs); white-space:nowrap; }
|
|
19472
|
+
.fw-status:not(.is-dirty) .ico { color:var(--success); }
|
|
19473
|
+
.fw-actions { display:flex; align-items:center; gap:6px; flex:none; -webkit-app-region:no-drag; }
|
|
19474
|
+
.fw-actions .btn { min-height:30px; font-size:var(--fs-sm); }
|
|
19475
|
+
.fw-body .doc { padding-top:64px; padding-bottom:24vh; }
|
|
19204
19476
|
.fw-body { flex:1; overflow:auto; scrollbar-gutter:stable; scrollbar-width:thin; -webkit-app-region:no-drag; }
|
|
19205
|
-
|
|
19206
|
-
|
|
19477
|
+
body.file-window .find-bar { top:54px; }
|
|
19478
|
+
@media (max-width:720px) {
|
|
19479
|
+
.fw-bar { gap:8px; padding-right:12px; padding-left:12px; }
|
|
19480
|
+
.fw-status span, .fw-mode span, .fw-open span { display:none; }
|
|
19481
|
+
.fw-mode, .fw-open { width:30px; padding:0; justify-content:center; }
|
|
19482
|
+
.fw-body .doc { padding:36px 32px 24vh; }
|
|
19483
|
+
}
|
|
19207
19484
|
|
|
19208
19485
|
/* No-origin bootstrap: enroll screen + hydration splash (data-blind shell). */
|
|
19209
19486
|
.enroll-splash { min-height:100dvh; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:14px; padding:24px; }
|
|
@@ -19428,6 +19705,37 @@ var styles_default = ` :root {
|
|
|
19428
19705
|
.blob-mgr-row { grid-template-columns:26px 30px minmax(0,1fr) auto auto 28px; }
|
|
19429
19706
|
.blob-mgr-age { display:none; }
|
|
19430
19707
|
}
|
|
19708
|
+
|
|
19709
|
+
/* Standalone library document: the same editor, with a compact native shell. */
|
|
19710
|
+
.document-window { min-width:0; height:100dvh; }
|
|
19711
|
+
.document-window .dw-toolbar { padding:0 16px; height:48px; min-height:48px; flex:none;
|
|
19712
|
+
flex-wrap:nowrap; gap:12px; background:var(--surface); -webkit-app-region:drag; }
|
|
19713
|
+
body.desktop-mac .document-window .dw-toolbar { padding-left:88px; }
|
|
19714
|
+
.document-window .dw-toolbar button { -webkit-app-region:no-drag; }
|
|
19715
|
+
.dw-toolbar > button, .dw-toolbar .crumb > .ico { flex:none; }
|
|
19716
|
+
.dw-toolbar .crumb { min-width:0; color:var(--muted); font-size:var(--fs-sm); }
|
|
19717
|
+
.dw-path { display:flex; align-items:center; gap:8px; min-width:0; }
|
|
19718
|
+
.dw-path .crumb-link { max-width:160px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
19719
|
+
.dw-current { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--fg-soft); }
|
|
19720
|
+
.dw-save { display:flex; align-items:center; gap:6px; flex:none; font-size:var(--fs-xs); color:var(--muted);
|
|
19721
|
+
padding:6px 4px; border-radius:var(--radius-sm); }
|
|
19722
|
+
.dw-save:not(:disabled):hover { background:var(--hover); }
|
|
19723
|
+
.dw-save-saved .ico { color:var(--success); }
|
|
19724
|
+
.dw-save-error, .dw-save-conflict { color:var(--danger); }
|
|
19725
|
+
.dw-content .doc { padding-top:64px; padding-bottom:24vh; }
|
|
19726
|
+
.dw-content .doc-title { overflow-wrap:anywhere; }
|
|
19727
|
+
.dw-footer { display:flex; align-items:center; height:30px; flex:none; padding:0 18px;
|
|
19728
|
+
border-top:1px solid var(--line); color:var(--muted); font-size:var(--fs-xs); }
|
|
19729
|
+
.document-window .doc-wc { bottom:5px; right:16px; border:0; box-shadow:none; background:transparent; }
|
|
19730
|
+
.document-window .doc-toc { top:72px; }
|
|
19731
|
+
.document-window .find-bar { top:54px; }
|
|
19732
|
+
@media (max-width:720px) {
|
|
19733
|
+
.dw-save span { display:none; }
|
|
19734
|
+
.dw-path { display:none; }
|
|
19735
|
+
.document-window .dw-toolbar { gap:8px; padding:0 12px; }
|
|
19736
|
+
.dw-content .doc { padding:36px 32px 24vh; }
|
|
19737
|
+
.dw-content .doc-title { font-size:32px; }
|
|
19738
|
+
}
|
|
19431
19739
|
`;
|
|
19432
19740
|
|
|
19433
19741
|
// src/webui/server/icons.ts
|
|
@@ -19486,7 +19794,7 @@ var HTML2 = `<!doctype html>
|
|
|
19486
19794
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
19487
19795
|
<!-- Mobile browser chrome (status/address bar) tints to theme-color; app.tsx
|
|
19488
19796
|
keeps #theme-color-meta in sync with the active theme + visible surface. -->
|
|
19489
|
-
<meta name="theme-color" id="theme-color-meta" content="
|
|
19797
|
+
<meta name="theme-color" id="theme-color-meta" content="${LIGHT_THEME.bg}" />
|
|
19490
19798
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
19491
19799
|
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
|
19492
19800
|
<title>Metahub</title>
|
|
@@ -19501,9 +19809,10 @@ var HTML2 = `<!doctype html>
|
|
|
19501
19809
|
<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
19810
|
<!-- FOUC guard: resolve the stored choice (system \u2192 OS preference) to an
|
|
19503
19811
|
explicit data-resolved before first paint. CSS keys off data-resolved
|
|
19504
|
-
alone, so the dark palette exists exactly once \u2014 see
|
|
19812
|
+
alone, so the dark palette exists exactly once \u2014 see core/ui-theme.ts. Dark also
|
|
19505
19813
|
pre-tints the status bar (hex mirrors --bg) so the first frame isn't white. -->
|
|
19506
|
-
<
|
|
19814
|
+
<style>${THEME_CSS}html,body{background:var(--bg);color:var(--fg)}</style>
|
|
19815
|
+
<script>${THEME_INIT_SCRIPT}</script>
|
|
19507
19816
|
<!-- Same for the UI language: mirror src/webui/i18n/locale.ts so <html lang>
|
|
19508
19817
|
is right before the bundle runs. -->
|
|
19509
19818
|
<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 +19942,9 @@ var getRuntime = bundleGetter({ key: "runtime", entry: "../runtime.ts", dist: "m
|
|
|
19633
19942
|
var getSdk = bundleGetter({ key: "sdk", entry: "../../sdk/client.ts", dist: "metahub-sdk.js", extraDirs: ["../../sdk"] });
|
|
19634
19943
|
async function getCss() {
|
|
19635
19944
|
if (RUNNING_FROM_SOURCE) {
|
|
19636
|
-
return Bun.file(fileURLToPath(new URL("../styles.css", import.meta.url))).text();
|
|
19945
|
+
return THEME_CSS + await Bun.file(fileURLToPath(new URL("../styles.css", import.meta.url))).text();
|
|
19637
19946
|
}
|
|
19638
|
-
return styles_default;
|
|
19947
|
+
return THEME_CSS + styles_default;
|
|
19639
19948
|
}
|
|
19640
19949
|
async function getJsStamped() {
|
|
19641
19950
|
return (await getJs()).replaceAll("__MH_WEBUI_VERSION__", package_default.version);
|
|
@@ -19665,8 +19974,8 @@ var MANIFEST = JSON.stringify({
|
|
|
19665
19974
|
start_url: "/",
|
|
19666
19975
|
scope: "/",
|
|
19667
19976
|
display: "standalone",
|
|
19668
|
-
background_color:
|
|
19669
|
-
theme_color:
|
|
19977
|
+
background_color: LIGHT_THEME.bg,
|
|
19978
|
+
theme_color: LIGHT_THEME.bg,
|
|
19670
19979
|
icons: [
|
|
19671
19980
|
{ src: "/icons/icon-192.png", sizes: "192x192", type: "image/png" },
|
|
19672
19981
|
{ src: "/icons/icon-512.png", sizes: "512x512", type: "image/png" }
|
|
@@ -20979,6 +21288,162 @@ init_records();
|
|
|
20979
21288
|
init_blobs_core();
|
|
20980
21289
|
init_storage();
|
|
20981
21290
|
init_storage_s3_sign();
|
|
21291
|
+
|
|
21292
|
+
// src/core/sync/share-short-links.ts
|
|
21293
|
+
init_e2ee();
|
|
21294
|
+
init_storage();
|
|
21295
|
+
|
|
21296
|
+
// src/core/sync/share-link.ts
|
|
21297
|
+
init_e2ee();
|
|
21298
|
+
async function tokenHash(token) {
|
|
21299
|
+
return toB64url(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(token))));
|
|
21300
|
+
}
|
|
21301
|
+
async function linkId(token) {
|
|
21302
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(token));
|
|
21303
|
+
return toB64url(new Uint8Array(digest).slice(0, 16));
|
|
21304
|
+
}
|
|
21305
|
+
function signedUrlExpiry(value) {
|
|
21306
|
+
try {
|
|
21307
|
+
const u = new URL(value);
|
|
21308
|
+
if (u.protocol !== "https:" || u.username || u.password || u.hash || value.length > 8192)
|
|
21309
|
+
return null;
|
|
21310
|
+
const date = u.searchParams.get("X-Amz-Date") ?? "";
|
|
21311
|
+
const seconds = Number(u.searchParams.get("X-Amz-Expires"));
|
|
21312
|
+
if (!/^\d{8}T\d{6}Z$/.test(date) || !Number.isInteger(seconds) || seconds < 1 || seconds > 604800)
|
|
21313
|
+
return null;
|
|
21314
|
+
if (!/^[a-f0-9]{64}$/i.test(u.searchParams.get("X-Amz-Signature") ?? ""))
|
|
21315
|
+
return null;
|
|
21316
|
+
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`;
|
|
21317
|
+
const start = Date.parse(iso);
|
|
21318
|
+
return Number.isFinite(start) ? start + seconds * 1000 : null;
|
|
21319
|
+
} catch {
|
|
21320
|
+
return null;
|
|
21321
|
+
}
|
|
21322
|
+
}
|
|
21323
|
+
function longShareUrl(base, link) {
|
|
21324
|
+
return `${base.replace(/\/+$/, "")}/#m=${encodeURIComponent(link.manifestUrl)}&${link.keyB64 ? `k=${link.keyB64}` : `s=${link.saltB64}`}`;
|
|
21325
|
+
}
|
|
21326
|
+
|
|
21327
|
+
// src/core/sync/share-short-links.ts
|
|
21328
|
+
var TIMEOUT = 8000;
|
|
21329
|
+
function root(config, slug) {
|
|
21330
|
+
return `${config.prefix.replace(/^\/+|\/+$/g, "") ? `${config.prefix.replace(/^\/+|\/+$/g, "")}/` : ""}shares/${slug}/links/`;
|
|
21331
|
+
}
|
|
21332
|
+
function viewerBase(base) {
|
|
21333
|
+
const url = new URL(base);
|
|
21334
|
+
if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash)
|
|
21335
|
+
throw new Error("invalid viewer");
|
|
21336
|
+
if (url.pathname !== "/")
|
|
21337
|
+
throw new Error("static subpath viewer");
|
|
21338
|
+
return url.origin;
|
|
21339
|
+
}
|
|
21340
|
+
async function unpack(config, bytes) {
|
|
21341
|
+
const raw = config.encrypt && config.masterKey ? await decryptBytes(fromB64(config.masterKey), bytes) : bytes;
|
|
21342
|
+
const value = JSON.parse(new TextDecoder().decode(raw));
|
|
21343
|
+
if (value.v !== 1 || !/^[A-Za-z0-9_-]{43}$/.test(value.token) || viewerBase(value.base) !== value.base)
|
|
21344
|
+
throw new Error("invalid short-link control");
|
|
21345
|
+
return value;
|
|
21346
|
+
}
|
|
21347
|
+
async function controlFor(config, slug, base) {
|
|
21348
|
+
const client = storageClientFor(config);
|
|
21349
|
+
const path = `${root(config, slug)}${await tokenHash(base)}.json`;
|
|
21350
|
+
const existing = await client.get(path);
|
|
21351
|
+
if (existing) {
|
|
21352
|
+
const control = await unpack(config, existing);
|
|
21353
|
+
if (control.base !== base)
|
|
21354
|
+
throw new Error("viewer mismatch");
|
|
21355
|
+
return control;
|
|
21356
|
+
}
|
|
21357
|
+
const control = { v: 1, base, token: toB64url(generateMasterKey()) };
|
|
21358
|
+
const plain = new TextEncoder().encode(JSON.stringify(control));
|
|
21359
|
+
const bytes = config.encrypt && config.masterKey ? await encryptBytes(fromB64(config.masterKey), plain) : plain;
|
|
21360
|
+
try {
|
|
21361
|
+
await client.put(path, bytes, {
|
|
21362
|
+
ifNoneMatch: true,
|
|
21363
|
+
contentType: "application/octet-stream"
|
|
21364
|
+
});
|
|
21365
|
+
} catch (error) {
|
|
21366
|
+
const winner = await client.get(path);
|
|
21367
|
+
if (!winner)
|
|
21368
|
+
throw error;
|
|
21369
|
+
const value = await unpack(config, winner);
|
|
21370
|
+
if (value.base !== base)
|
|
21371
|
+
throw new Error("viewer mismatch");
|
|
21372
|
+
return value;
|
|
21373
|
+
}
|
|
21374
|
+
return control;
|
|
21375
|
+
}
|
|
21376
|
+
function request(url, init = {}) {
|
|
21377
|
+
return fetch(url, {
|
|
21378
|
+
...init,
|
|
21379
|
+
redirect: "error",
|
|
21380
|
+
credentials: "omit",
|
|
21381
|
+
cache: "no-store",
|
|
21382
|
+
signal: AbortSignal.timeout(TIMEOUT)
|
|
21383
|
+
});
|
|
21384
|
+
}
|
|
21385
|
+
async function bucketShareUrl(config, slug, base, link) {
|
|
21386
|
+
const fallback = longShareUrl(base, link);
|
|
21387
|
+
try {
|
|
21388
|
+
const origin = viewerBase(base);
|
|
21389
|
+
const expiresAt = Math.min(link.presignExp, signedUrlExpiry(link.manifestUrl) ?? 0);
|
|
21390
|
+
if (expiresAt <= Date.now())
|
|
21391
|
+
return fallback;
|
|
21392
|
+
const probe = await request(`${origin}/api/links`);
|
|
21393
|
+
if (!probe.ok || (await probe.json()).service !== "metahub-share-links")
|
|
21394
|
+
throw new Error("static viewer");
|
|
21395
|
+
const control = await controlFor(config, slug, origin);
|
|
21396
|
+
const id = await linkId(control.token);
|
|
21397
|
+
const endpoint = `${origin}/api/links/${id}`;
|
|
21398
|
+
const authorization = `Bearer ${control.token}`;
|
|
21399
|
+
const descriptor = {
|
|
21400
|
+
v: 1,
|
|
21401
|
+
manifestUrl: link.manifestUrl,
|
|
21402
|
+
expiresAt,
|
|
21403
|
+
...link.saltB64 ? { salt: toB64url(fromB64(link.saltB64)) } : {}
|
|
21404
|
+
};
|
|
21405
|
+
const current = await request(endpoint, { headers: { authorization } });
|
|
21406
|
+
if (!current.ok && current.status !== 404)
|
|
21407
|
+
throw new Error("short-link lookup failed");
|
|
21408
|
+
const etag = current.headers.get("etag");
|
|
21409
|
+
if (current.ok && !etag)
|
|
21410
|
+
throw new Error("not a short-link API");
|
|
21411
|
+
const result = await request(endpoint, {
|
|
21412
|
+
method: "PUT",
|
|
21413
|
+
headers: {
|
|
21414
|
+
authorization,
|
|
21415
|
+
"content-type": "application/json",
|
|
21416
|
+
...current.ok ? { "if-match": etag } : { "if-none-match": "*" }
|
|
21417
|
+
},
|
|
21418
|
+
body: JSON.stringify(descriptor)
|
|
21419
|
+
});
|
|
21420
|
+
if (!result.ok || !result.headers.get("etag") || (await result.json()).ok !== true)
|
|
21421
|
+
throw new Error("short-link registration failed");
|
|
21422
|
+
return `${origin}/s/${id}${link.keyB64 ? `#k=${toB64url(fromB64(link.keyB64))}` : ""}`;
|
|
21423
|
+
} catch {
|
|
21424
|
+
console.warn("share: short-link service unavailable; using the original long link");
|
|
21425
|
+
return fallback;
|
|
21426
|
+
}
|
|
21427
|
+
}
|
|
21428
|
+
async function revokeBucketShortLinks(config, slug) {
|
|
21429
|
+
const client = storageClientFor(config);
|
|
21430
|
+
for (const object of await client.list(root(config, slug))) {
|
|
21431
|
+
if (!object.key.endsWith(".json"))
|
|
21432
|
+
continue;
|
|
21433
|
+
const raw = await client.get(object.key);
|
|
21434
|
+
if (!raw)
|
|
21435
|
+
continue;
|
|
21436
|
+
const control = await unpack(config, raw);
|
|
21437
|
+
const response = await request(`${control.base}/api/links/${await linkId(control.token)}`, {
|
|
21438
|
+
method: "DELETE",
|
|
21439
|
+
headers: { authorization: `Bearer ${control.token}` }
|
|
21440
|
+
});
|
|
21441
|
+
if (!response.ok || (await response.json()).ok !== true)
|
|
21442
|
+
throw new Error("short-link revocation has not been confirmed; retry later");
|
|
21443
|
+
}
|
|
21444
|
+
}
|
|
21445
|
+
|
|
21446
|
+
// src/core/sync/share-export.ts
|
|
20982
21447
|
init_e2ee();
|
|
20983
21448
|
function sharesRoot(prefix) {
|
|
20984
21449
|
const p = (prefix || "").replace(/^\/+|\/+$/g, "");
|
|
@@ -21119,6 +21584,8 @@ async function renewBucketShare(db, config, slug, expiresSec = MAX_PRESIGN_SECON
|
|
|
21119
21584
|
const meta = await readMeta2(config, slug);
|
|
21120
21585
|
if (!meta)
|
|
21121
21586
|
throw new MhError("not_found", `no such bucket share: ${slug}`);
|
|
21587
|
+
if (meta.revoking)
|
|
21588
|
+
throw new MhError("conflict", "share revocation is pending; retry revocation instead");
|
|
21122
21589
|
const shareKey = fromB64(meta.key);
|
|
21123
21590
|
const exp = clampExpiry(expiresSec);
|
|
21124
21591
|
const { manifestUrl, objects, title } = await writeShareObjects(db, {
|
|
@@ -21154,6 +21621,8 @@ async function represignBucketShare(config, slug, expiresSec = MAX_PRESIGN_SECON
|
|
|
21154
21621
|
const meta = await readMeta2(config, slug);
|
|
21155
21622
|
if (!meta)
|
|
21156
21623
|
throw new MhError("not_found", `no such bucket share: ${slug}`);
|
|
21624
|
+
if (meta.revoking)
|
|
21625
|
+
throw new MhError("conflict", "share revocation is pending; retry revocation instead");
|
|
21157
21626
|
const client = storageClientFor(config);
|
|
21158
21627
|
const root = sharesRoot(config.prefix);
|
|
21159
21628
|
const shareKey = fromB64(meta.key);
|
|
@@ -21193,15 +21662,19 @@ async function listBucketShares(config) {
|
|
|
21193
21662
|
async function deleteBucketShareObjects(config, slug) {
|
|
21194
21663
|
const client = storageClientFor(config);
|
|
21195
21664
|
const root = sharesRoot(config.prefix);
|
|
21196
|
-
await
|
|
21197
|
-
|
|
21198
|
-
|
|
21199
|
-
|
|
21200
|
-
const objs = meta?.objects ?? (await client.list(`${root}/${slug}/`)
|
|
21665
|
+
const meta = await readMeta2(config, slug);
|
|
21666
|
+
if (meta)
|
|
21667
|
+
await client.put(metaKey(root, slug), await metaBytes(config, { ...meta, revoking: true }), { contentType: "application/octet-stream" });
|
|
21668
|
+
await revokeBucketShortLinks(config, slug);
|
|
21669
|
+
const objs = new Set([...meta?.objects ?? [], ...(await client.list(`${root}/${slug}/`)).map((o) => o.key)]);
|
|
21670
|
+
const metaPath = metaKey(root, slug);
|
|
21201
21671
|
for (const key of objs)
|
|
21202
|
-
|
|
21203
|
-
|
|
21204
|
-
|
|
21672
|
+
if (key !== metaPath && !key.includes(`/links/`))
|
|
21673
|
+
await client.del(key);
|
|
21674
|
+
for (const key of objs)
|
|
21675
|
+
if (key.includes(`/links/`))
|
|
21676
|
+
await client.del(key);
|
|
21677
|
+
await client.del(metaPath);
|
|
21205
21678
|
}
|
|
21206
21679
|
function clampExpiry(sec) {
|
|
21207
21680
|
return Math.min(Math.max(60, Math.floor(sec)), MAX_PRESIGN_SECONDS);
|
|
@@ -21236,7 +21709,8 @@ function bucketShareItem(bucket, m) {
|
|
|
21236
21709
|
hosting: "s3",
|
|
21237
21710
|
expiresAt: m.presign_exp,
|
|
21238
21711
|
hasPassword: m.has_password,
|
|
21239
|
-
contentUpdatedAt: m.content_updated_at ?? m.created_at
|
|
21712
|
+
contentUpdatedAt: m.content_updated_at ?? m.created_at,
|
|
21713
|
+
...m.revoking ? { lifecycle: "cleanup_pending" } : {}
|
|
21240
21714
|
};
|
|
21241
21715
|
}
|
|
21242
21716
|
async function fetchPeerShares(url, token, targetId) {
|
|
@@ -21438,7 +21912,7 @@ function pickBucket(db, bucketUrl) {
|
|
|
21438
21912
|
throw new MhError("invalid_input", `multiple buckets \u2014 pass --bucket <url> (one of: ${buckets.map((b) => b.url).join(", ")})`);
|
|
21439
21913
|
return buckets[0].url;
|
|
21440
21914
|
}
|
|
21441
|
-
function
|
|
21915
|
+
function viewerBase2(db, override) {
|
|
21442
21916
|
if (override)
|
|
21443
21917
|
return override.replace(/\/+$/, "");
|
|
21444
21918
|
const row = db.query("SELECT value FROM meta WHERE key='cfg_share_viewer_url'").get();
|
|
@@ -21451,10 +21925,6 @@ function viewerOriginOf(base) {
|
|
|
21451
21925
|
return;
|
|
21452
21926
|
}
|
|
21453
21927
|
}
|
|
21454
|
-
function bucketLink(base, manifestUrl, keyB64, saltB64) {
|
|
21455
|
-
const frag = `m=${encodeURIComponent(manifestUrl)}&` + (keyB64 ? `k=${keyB64}` : `s=${saltB64}`);
|
|
21456
|
-
return `${base}/#${frag}`;
|
|
21457
|
-
}
|
|
21458
21928
|
function assertShareCombo(req) {
|
|
21459
21929
|
const fail = (msg) => {
|
|
21460
21930
|
throw new MhError("invalid_input", msg);
|
|
@@ -21481,7 +21951,7 @@ async function createShareAction(db, req) {
|
|
|
21481
21951
|
const target = resolveTarget(db, req.kind, req.ref);
|
|
21482
21952
|
const bucketUrl = pickBucket(db, req.bucketUrl);
|
|
21483
21953
|
const { config, label } = s3PeerConfig2(db, bucketUrl);
|
|
21484
|
-
const base =
|
|
21954
|
+
const base = viewerBase2(db, req.viewerBase);
|
|
21485
21955
|
const slug = freshSlug(db);
|
|
21486
21956
|
const out = await createBucketShare(db, {
|
|
21487
21957
|
slug,
|
|
@@ -21499,7 +21969,7 @@ async function createShareAction(db, req) {
|
|
|
21499
21969
|
permission: "view",
|
|
21500
21970
|
transport: "s3",
|
|
21501
21971
|
hosting: "s3",
|
|
21502
|
-
url:
|
|
21972
|
+
url: await bucketShareUrl(config, slug, base, out),
|
|
21503
21973
|
expiresAt: out.presignExp,
|
|
21504
21974
|
source: `\u6876 ${label}`
|
|
21505
21975
|
};
|
|
@@ -21784,7 +22254,13 @@ async function revokeShareAction(db, slug) {
|
|
|
21784
22254
|
const owner = await bucketOwning(db, slug);
|
|
21785
22255
|
if (!owner)
|
|
21786
22256
|
return { ok: false, status: "not_found" };
|
|
21787
|
-
|
|
22257
|
+
try {
|
|
22258
|
+
await deleteBucketShareObjects(JSON.parse(owner.peer.config), slug);
|
|
22259
|
+
} catch {
|
|
22260
|
+
if (owner.item)
|
|
22261
|
+
primeRemoteShare(db, owner.peer.url, { ...owner.item, lifecycle: "cleanup_pending" });
|
|
22262
|
+
return { ok: false, status: "cleanup_pending" };
|
|
22263
|
+
}
|
|
21788
22264
|
dropRemoteShare(db, owner.peer.url, slug);
|
|
21789
22265
|
return { ok: true, status: "revoked" };
|
|
21790
22266
|
}
|
|
@@ -21806,7 +22282,7 @@ async function renewShareAction(db, slug, viewerBaseOverride, opts) {
|
|
|
21806
22282
|
throw new MhError("not_found", `no such object-storage share: ${slug}`);
|
|
21807
22283
|
const { peer: p } = owner;
|
|
21808
22284
|
const config = JSON.parse(p.config);
|
|
21809
|
-
const base =
|
|
22285
|
+
const base = viewerBase2(db, viewerBaseOverride);
|
|
21810
22286
|
const out = opts?.refreshContent ? await renewBucketShare(db, config, slug) : await represignBucketShare(config, slug);
|
|
21811
22287
|
if (owner.item)
|
|
21812
22288
|
primeRemoteShare(db, p.url, {
|
|
@@ -21821,7 +22297,7 @@ async function renewShareAction(db, slug, viewerBaseOverride, opts) {
|
|
|
21821
22297
|
permission: "view",
|
|
21822
22298
|
transport: "s3",
|
|
21823
22299
|
hosting: "s3",
|
|
21824
|
-
url:
|
|
22300
|
+
url: await bucketShareUrl(config, slug, base, out),
|
|
21825
22301
|
expiresAt: out.presignExp,
|
|
21826
22302
|
source: `\u6876 ${p.label ?? p.url}`
|
|
21827
22303
|
};
|
|
@@ -22899,6 +23375,7 @@ async function enableWorkerSubdomain(cfg) {
|
|
|
22899
23375
|
}
|
|
22900
23376
|
|
|
22901
23377
|
// src/core/sync/room-serve.ts
|
|
23378
|
+
init_ui_theme();
|
|
22902
23379
|
init_errors();
|
|
22903
23380
|
init_http_status();
|
|
22904
23381
|
init_ids();
|
|
@@ -22910,6 +23387,19 @@ init_sites_core();
|
|
|
22910
23387
|
init_shares();
|
|
22911
23388
|
init_room_protocol();
|
|
22912
23389
|
var ROOM_SESSION_TTL_MS = 12 * 60 * 60 * 1000;
|
|
23390
|
+
var PAGE_CSS = `
|
|
23391
|
+
${THEME_CSS}
|
|
23392
|
+
*{box-sizing:border-box}
|
|
23393
|
+
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;
|
|
23394
|
+
min-height:100dvh;display:flex;align-items:center;justify-content:center;padding:24px}
|
|
23395
|
+
main{max-width:420px;width:100%}
|
|
23396
|
+
form.pw{display:flex;flex-direction:column;gap:12px}
|
|
23397
|
+
form.pw input{padding:9px;border:1px solid var(--line);border-radius:7px;background:var(--card);color:var(--fg)}
|
|
23398
|
+
form.pw button{padding:9px;border:0;border-radius:7px;background:var(--accent);color:var(--accent-fg);cursor:pointer}
|
|
23399
|
+
.err{color:var(--danger);font-size:13px;margin:0}
|
|
23400
|
+
.muted{color:var(--muted);font-size:14px}
|
|
23401
|
+
h1{font-size:20px;margin:0 0 10px;text-align:center}
|
|
23402
|
+
footer{margin-top:34px;color:var(--muted);font-size:12px;text-align:center}`;
|
|
22913
23403
|
|
|
22914
23404
|
// src/workers/room.ts
|
|
22915
23405
|
init_room_protocol();
|
|
@@ -23384,6 +23874,7 @@ function disconnectEdge(db) {
|
|
|
23384
23874
|
}
|
|
23385
23875
|
|
|
23386
23876
|
// src/core/sync/cf-oauth.ts
|
|
23877
|
+
init_ui_theme();
|
|
23387
23878
|
init_errors();
|
|
23388
23879
|
init_page_messages();
|
|
23389
23880
|
init_e2ee();
|
|
@@ -23546,7 +24037,7 @@ async function startCfLogin(opts = {}) {
|
|
|
23546
24037
|
}
|
|
23547
24038
|
};
|
|
23548
24039
|
}
|
|
23549
|
-
var callbackHtml = (locale) => `<!doctype html><html lang="${locale}"><meta charset="utf-8"><title>MetaHub</title>
|
|
24040
|
+
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
24041
|
<body style="font:15px system-ui;display:grid;place-items:center;height:100vh;margin:0">
|
|
23551
24042
|
<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
24043
|
|
|
@@ -24853,4 +25344,4 @@ export {
|
|
|
24853
25344
|
writeTx
|
|
24854
25345
|
};
|
|
24855
25346
|
|
|
24856
|
-
//# debugId=
|
|
25347
|
+
//# debugId=39484D6BDF841CDA64756E2164756E21
|