@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/cli.js
CHANGED
|
@@ -801,7 +801,7 @@ var package_default;
|
|
|
801
801
|
var init_package = __esm(() => {
|
|
802
802
|
package_default = {
|
|
803
803
|
name: "@tensorix/metahub",
|
|
804
|
-
version: "0.5.
|
|
804
|
+
version: "0.5.7",
|
|
805
805
|
description: "Metahub core library and CLI",
|
|
806
806
|
license: "AGPL-3.0-only",
|
|
807
807
|
type: "module",
|
|
@@ -8160,6 +8160,45 @@ function removeSitePublishStates(db, siteId) {
|
|
|
8160
8160
|
}
|
|
8161
8161
|
var META_KEY = "site_publish_rollbacks", STATE_META_KEY = "site_publish_states";
|
|
8162
8162
|
|
|
8163
|
+
// src/core/copy-views.ts
|
|
8164
|
+
function copyViews(raw, props, records, selfRelations) {
|
|
8165
|
+
if (!Array.isArray(raw))
|
|
8166
|
+
return raw;
|
|
8167
|
+
const object = (x) => !!x && typeof x === "object" && !Array.isArray(x);
|
|
8168
|
+
const prop = (x) => typeof x === "string" ? props.get(x) ?? x : x;
|
|
8169
|
+
return raw.map((v) => {
|
|
8170
|
+
if (!object(v))
|
|
8171
|
+
return v;
|
|
8172
|
+
const out = { ...v };
|
|
8173
|
+
for (const key of ["group", "dateProp", "start", "end"])
|
|
8174
|
+
if (key in out)
|
|
8175
|
+
out[key] = prop(out[key]);
|
|
8176
|
+
if (Array.isArray(v.hidden))
|
|
8177
|
+
out.hidden = v.hidden.map(prop);
|
|
8178
|
+
if (Array.isArray(v.sort))
|
|
8179
|
+
out.sort = v.sort.map((s) => object(s) ? { ...s, prop: prop(s.prop) } : s);
|
|
8180
|
+
if (object(v.filter) && Array.isArray(v.filter.rules))
|
|
8181
|
+
out.filter = {
|
|
8182
|
+
...v.filter,
|
|
8183
|
+
rules: v.filter.rules.map((r) => {
|
|
8184
|
+
if (!object(r))
|
|
8185
|
+
return r;
|
|
8186
|
+
return {
|
|
8187
|
+
...r,
|
|
8188
|
+
prop: prop(r.prop),
|
|
8189
|
+
...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) } : {}
|
|
8190
|
+
};
|
|
8191
|
+
})
|
|
8192
|
+
};
|
|
8193
|
+
if (object(v.calc))
|
|
8194
|
+
out.calc = Object.fromEntries(Object.entries(v.calc).map(([id, value]) => [
|
|
8195
|
+
props.get(id) ?? id,
|
|
8196
|
+
value
|
|
8197
|
+
]));
|
|
8198
|
+
return out;
|
|
8199
|
+
});
|
|
8200
|
+
}
|
|
8201
|
+
|
|
8163
8202
|
// src/core/indexing.ts
|
|
8164
8203
|
function sanitize(s) {
|
|
8165
8204
|
return s.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
@@ -8971,10 +9010,6 @@ var init_databases = __esm(() => {
|
|
|
8971
9010
|
name: opts.name ?? src.name,
|
|
8972
9011
|
icon: opts.icon ?? src.icon ?? undefined
|
|
8973
9012
|
});
|
|
8974
|
-
if (src.meta !== null) {
|
|
8975
|
-
const { collapsed: _hidden, ...meta } = src.meta;
|
|
8976
|
-
emitMetaPatch(db, dup.id, null, meta);
|
|
8977
|
-
}
|
|
8978
9013
|
const propIdMap = new Map;
|
|
8979
9014
|
const selfRelNew = new Set;
|
|
8980
9015
|
for (const p of listProperties(db, id)) {
|
|
@@ -9009,6 +9044,12 @@ var init_databases = __esm(() => {
|
|
|
9009
9044
|
if (Object.keys(patch).length)
|
|
9010
9045
|
updateRecord(db, recIdMap.get(r.id), patch);
|
|
9011
9046
|
}
|
|
9047
|
+
if (src.meta !== null) {
|
|
9048
|
+
const { collapsed: _hidden, ...meta } = src.meta;
|
|
9049
|
+
if ("views" in meta)
|
|
9050
|
+
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)));
|
|
9051
|
+
emitMetaPatch(db, dup.id, null, meta);
|
|
9052
|
+
}
|
|
9012
9053
|
return getDatabase(db, dup.id);
|
|
9013
9054
|
});
|
|
9014
9055
|
deleteDatabase = grouped(function deleteDatabase(db, id) {
|
|
@@ -13768,6 +13809,92 @@ var init_devices = __esm(() => {
|
|
|
13768
13809
|
init_storage();
|
|
13769
13810
|
});
|
|
13770
13811
|
|
|
13812
|
+
// src/core/ui-theme.ts
|
|
13813
|
+
var LIGHT_THEME, DARK_THEME, declarations = (palette) => Object.entries(palette).map(([k, v]) => `--${k}:${v};`).join(""), THEME_CSS, THEME_INIT_SCRIPT;
|
|
13814
|
+
var init_ui_theme = __esm(() => {
|
|
13815
|
+
LIGHT_THEME = {
|
|
13816
|
+
bg: "#ffffff",
|
|
13817
|
+
paper: "#ffffff",
|
|
13818
|
+
surface: "#fafaf9",
|
|
13819
|
+
"surface-2": "#f1f1ef",
|
|
13820
|
+
sidebar: "#f7f7f5",
|
|
13821
|
+
fg: "#37352f",
|
|
13822
|
+
"fg-soft": "#595750",
|
|
13823
|
+
muted: "#6f6d66",
|
|
13824
|
+
line: "#eae9e6",
|
|
13825
|
+
"line-strong": "#d8d7d3",
|
|
13826
|
+
accent: "#3867b2",
|
|
13827
|
+
"accent-fg": "#ffffff",
|
|
13828
|
+
"accent-soft": "#edf2f9",
|
|
13829
|
+
hover: "rgba(55,53,47,.035)",
|
|
13830
|
+
"hover-2": "rgba(55,53,47,.07)",
|
|
13831
|
+
"code-bg": "#f6f5f3",
|
|
13832
|
+
"selected-bg": "#f7f9fc",
|
|
13833
|
+
"selected-border": "#a8b8ce",
|
|
13834
|
+
"selected-icon-bg": "#edf2f8",
|
|
13835
|
+
"selected-icon-fg": "#4d678b",
|
|
13836
|
+
"selected-muted": "#626b78",
|
|
13837
|
+
"selected-hover-bg": "#f1f5fa",
|
|
13838
|
+
"selected-hover-border": "#8199bb",
|
|
13839
|
+
danger: "#b6423a",
|
|
13840
|
+
"danger-fg": "#ffffff",
|
|
13841
|
+
"danger-soft": "#f9eeec",
|
|
13842
|
+
success: "#347653",
|
|
13843
|
+
warning: "#866022",
|
|
13844
|
+
"warning-soft": "#faf3e5",
|
|
13845
|
+
"brand-purple": "#79619d",
|
|
13846
|
+
"brand-teal": "#397d76",
|
|
13847
|
+
"brand-orange": "#a06436",
|
|
13848
|
+
"shadow-sm": "0 1px 2px rgba(35,32,25,.035)",
|
|
13849
|
+
"shadow-md": "0 4px 14px rgba(35,32,25,.08)",
|
|
13850
|
+
"shadow-lg": "0 16px 48px rgba(35,32,25,.13)",
|
|
13851
|
+
"brand-stripe": "linear-gradient(to right,#335cff 0% 25%,#8967ed 25% 50%,#18b7b6 50% 75%,#f28b55 75% 100%)"
|
|
13852
|
+
};
|
|
13853
|
+
DARK_THEME = {
|
|
13854
|
+
bg: "#191919",
|
|
13855
|
+
paper: "#191919",
|
|
13856
|
+
surface: "#222222",
|
|
13857
|
+
"surface-2": "#2c2c2b",
|
|
13858
|
+
sidebar: "#202020",
|
|
13859
|
+
fg: "#e8e7e4",
|
|
13860
|
+
"fg-soft": "#c0beb8",
|
|
13861
|
+
muted: "#aaa8a2",
|
|
13862
|
+
line: "#30302f",
|
|
13863
|
+
"line-strong": "#42423f",
|
|
13864
|
+
accent: "#8aaddb",
|
|
13865
|
+
"accent-fg": "#172235",
|
|
13866
|
+
"accent-soft": "#263242",
|
|
13867
|
+
hover: "rgba(255,255,255,.035)",
|
|
13868
|
+
"hover-2": "rgba(255,255,255,.065)",
|
|
13869
|
+
"code-bg": "#242423",
|
|
13870
|
+
"selected-bg": "#242a32",
|
|
13871
|
+
"selected-border": "#56657a",
|
|
13872
|
+
"selected-icon-bg": "#2d3745",
|
|
13873
|
+
"selected-icon-fg": "#afc5e2",
|
|
13874
|
+
"selected-muted": "#b5bfcd",
|
|
13875
|
+
"selected-hover-bg": "#2a313b",
|
|
13876
|
+
"selected-hover-border": "#7287a3",
|
|
13877
|
+
danger: "#e89890",
|
|
13878
|
+
"danger-fg": "#2b1716",
|
|
13879
|
+
"danger-soft": "#3b2927",
|
|
13880
|
+
success: "#92bd9b",
|
|
13881
|
+
warning: "#d6b578",
|
|
13882
|
+
"warning-soft": "#363024",
|
|
13883
|
+
"brand-purple": "#baa6d1",
|
|
13884
|
+
"brand-teal": "#8cbbb4",
|
|
13885
|
+
"brand-orange": "#d4a37d",
|
|
13886
|
+
"shadow-sm": "0 1px 2px rgba(0,0,0,.15)",
|
|
13887
|
+
"shadow-md": "0 4px 14px rgba(0,0,0,.25)",
|
|
13888
|
+
"shadow-lg": "0 16px 48px rgba(0,0,0,.35)",
|
|
13889
|
+
"brand-stripe": "linear-gradient(to right,#335cff 0% 25%,#8967ed 25% 50%,#18b7b6 50% 75%,#f28b55 75% 100%)"
|
|
13890
|
+
};
|
|
13891
|
+
THEME_CSS = `:root{color-scheme:light;${declarations(LIGHT_THEME)}--card:var(--surface-2);--ok:var(--success)}
|
|
13892
|
+
@media(prefers-color-scheme:dark){:root:not([data-resolved]){color-scheme:dark;${declarations(DARK_THEME)}}}
|
|
13893
|
+
:root[data-resolved="dark"]{color-scheme:dark;${declarations(DARK_THEME)}}
|
|
13894
|
+
::selection{background:var(--accent-soft);color:var(--accent)}`;
|
|
13895
|
+
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}'})();`;
|
|
13896
|
+
});
|
|
13897
|
+
|
|
13771
13898
|
// src/core/sync/http-status.ts
|
|
13772
13899
|
function httpStatusForCode(code) {
|
|
13773
13900
|
return code ? STATUS[code] ?? 400 : 400;
|
|
@@ -13915,6 +14042,11 @@ var init_page_messages = __esm(() => {
|
|
|
13915
14042
|
"\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u8F93\u5165\u4EE4\u724C\u3002": "Session expired. Enter the token again.",
|
|
13916
14043
|
\u{9644}\u{4ef6}\u{5df2}\u{5931}\u{6548}: "Attachment unavailable",
|
|
13917
14044
|
\u{94fe}\u{63a5}\u{7f3a}\u{5c11}\u{5206}\u{4eab}\u{6570}\u{636e}: "The link is missing share data",
|
|
14045
|
+
\u{65e0}\u{6cd5}\u{6253}\u{5f00}\u{8fd9}\u{4efd}\u{5206}\u{4eab}: "Unable to open this share",
|
|
14046
|
+
"\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.",
|
|
14047
|
+
"\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.",
|
|
14048
|
+
"\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.",
|
|
14049
|
+
\u{91cd}\u{65b0}\u{52a0}\u{8f7d}: "Reload",
|
|
13918
14050
|
\u{8bf7}\u{8f93}\u{5165}\u{5206}\u{4eab}\u{53e3}\u{4ee4}: "Enter the share passcode",
|
|
13919
14051
|
\u{94fe}\u{63a5}\u{7f3a}\u{5c11}\u{5bc6}\u{94a5}: "The link is missing its key",
|
|
13920
14052
|
\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",
|
|
@@ -15450,17 +15582,9 @@ function unlockPage(locale = "zh-CN") {
|
|
|
15450
15582
|
return `<!doctype html><html lang="${locale}"><head>
|
|
15451
15583
|
<meta charset="utf-8">
|
|
15452
15584
|
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
|
|
15453
|
-
<meta name="theme-color" content="
|
|
15585
|
+
<meta name="theme-color" content="${LIGHT_THEME.bg}">
|
|
15454
15586
|
<title>${m("\u9A8C\u8BC1\u8BBF\u95EE\u4EE4\u724C \xB7 metahub")}</title>
|
|
15455
|
-
<script>
|
|
15456
|
-
// FOUC-guard theme resolution, same key/logic as src/webui/theme.ts.
|
|
15457
|
-
try {
|
|
15458
|
-
var mt = localStorage.getItem("mh-theme");
|
|
15459
|
-
var dark = mt === "dark" || (mt !== "light" && matchMedia("(prefers-color-scheme: dark)").matches);
|
|
15460
|
-
document.documentElement.dataset.resolved = dark ? "dark" : "light";
|
|
15461
|
-
document.head.querySelector('meta[name=theme-color]').setAttribute("content", dark ? "#1a1a1c" : "#ffffff");
|
|
15462
|
-
} catch (e) {}
|
|
15463
|
-
</script>
|
|
15587
|
+
<script>${THEME_INIT_SCRIPT}</script>
|
|
15464
15588
|
<style>${UNLOCK_CSS}</style></head><body>
|
|
15465
15589
|
<div class="boot" id="boot"><svg viewBox="0 0 24 24">${CUBE_SVG}</svg></div>
|
|
15466
15590
|
<form class="card" id="f" style="display:none" autocomplete="on">
|
|
@@ -15609,15 +15733,20 @@ function cookieMutationRejection(req, url, cfg) {
|
|
|
15609
15733
|
function unauthorized() {
|
|
15610
15734
|
return Response.json({ error: "unauthorized" }, { status: 401 });
|
|
15611
15735
|
}
|
|
15612
|
-
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 =
|
|
15613
|
-
|
|
15614
|
-
|
|
15615
|
-
|
|
15616
|
-
|
|
15617
|
-
|
|
15618
|
-
|
|
15619
|
-
|
|
15620
|
-
|
|
15736
|
+
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, """);
|
|
15737
|
+
var init_auth = __esm(() => {
|
|
15738
|
+
init_ui_theme();
|
|
15739
|
+
init_page_messages();
|
|
15740
|
+
init_inject_runtime();
|
|
15741
|
+
init_token();
|
|
15742
|
+
init_pairing();
|
|
15743
|
+
init_protocol();
|
|
15744
|
+
HTML_HEADERS = {
|
|
15745
|
+
"content-type": "text/html; charset=utf-8",
|
|
15746
|
+
"referrer-policy": "same-origin"
|
|
15747
|
+
};
|
|
15748
|
+
UNLOCK_CSS = `
|
|
15749
|
+
${THEME_CSS}
|
|
15621
15750
|
*{box-sizing:border-box}
|
|
15622
15751
|
html,body{margin:0;min-height:100%}
|
|
15623
15752
|
body{font-family:"Hanken Grotesk",-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;
|
|
@@ -15682,17 +15811,7 @@ var COOKIE = "mh_token", COOKIE_ATTRS = "path=/; SameSite=Strict; Max-Age=315360
|
|
|
15682
15811
|
@keyframes spin{to{transform:rotate(360deg)}}
|
|
15683
15812
|
@media (prefers-reduced-motion:reduce){*{animation-duration:.01ms!important}
|
|
15684
15813
|
.brand path{stroke-dashoffset:0}}
|
|
15685
|
-
|
|
15686
|
-
var init_auth = __esm(() => {
|
|
15687
|
-
init_page_messages();
|
|
15688
|
-
init_inject_runtime();
|
|
15689
|
-
init_token();
|
|
15690
|
-
init_pairing();
|
|
15691
|
-
init_protocol();
|
|
15692
|
-
HTML_HEADERS = {
|
|
15693
|
-
"content-type": "text/html; charset=utf-8",
|
|
15694
|
-
"referrer-policy": "same-origin"
|
|
15695
|
-
};
|
|
15814
|
+
`;
|
|
15696
15815
|
});
|
|
15697
15816
|
|
|
15698
15817
|
// src/core/md/grammar.ts
|
|
@@ -16322,8 +16441,7 @@ function notFoundResponse(locale, title, detail) {
|
|
|
16322
16441
|
<meta name="robots" content="noindex">
|
|
16323
16442
|
<title>${escapeHtml(title)}</title>
|
|
16324
16443
|
<style>
|
|
16325
|
-
|
|
16326
|
-
@media (prefers-color-scheme: dark){:root{--bg:#0d1117;--fg:#e6edf3;--muted:#8b949e;--line:#30363d;--accent:#4493f8;--card:#161b22}}
|
|
16444
|
+
${THEME_CSS}
|
|
16327
16445
|
*{box-sizing:border-box}
|
|
16328
16446
|
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;
|
|
16329
16447
|
min-height:100dvh;display:flex;align-items:center;justify-content:center;padding:24px}
|
|
@@ -16347,6 +16465,7 @@ function notFoundResponse(locale, title, detail) {
|
|
|
16347
16465
|
});
|
|
16348
16466
|
}
|
|
16349
16467
|
var init_sites_serve = __esm(() => {
|
|
16468
|
+
init_ui_theme();
|
|
16350
16469
|
init_sites();
|
|
16351
16470
|
init_site_channel_store();
|
|
16352
16471
|
init_grants_core();
|
|
@@ -16358,6 +16477,20 @@ var init_sites_serve = __esm(() => {
|
|
|
16358
16477
|
init_auth();
|
|
16359
16478
|
});
|
|
16360
16479
|
|
|
16480
|
+
// src/core/sync/share-file-styles.ts
|
|
16481
|
+
var SHARE_FILE_CSS = `
|
|
16482
|
+
article.doc p.mh-file{margin:0}
|
|
16483
|
+
article.doc .mh-file+.mh-file{border-top:1px solid var(--line)}
|
|
16484
|
+
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}
|
|
16485
|
+
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}
|
|
16486
|
+
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")}
|
|
16487
|
+
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")}
|
|
16488
|
+
article.doc .mh-file a[href]:not([aria-disabled="true"]):hover{background:var(--card);color:var(--accent);text-decoration:underline;text-underline-offset:3px}
|
|
16489
|
+
article.doc .mh-file a:focus-visible{outline:2px solid var(--accent);outline-offset:-2px;background:var(--card);color:var(--accent)}
|
|
16490
|
+
article.doc .mh-file a[aria-disabled="true"]{color:var(--muted);pointer-events:none}
|
|
16491
|
+
article.doc .mh-file a[aria-disabled="true"]::after{display:none}
|
|
16492
|
+
`;
|
|
16493
|
+
|
|
16361
16494
|
// src/core/sync/share-copy.ts
|
|
16362
16495
|
function markdownTable(header, rows) {
|
|
16363
16496
|
const cell = (s) => s.replace(/\r?\n/g, " ").replace(/\|/g, "\\|").trim();
|
|
@@ -16391,12 +16524,11 @@ var ICON_COPY = '<svg class="ic-copy" viewBox="0 0 24 24" aria-hidden="true"><re
|
|
|
16391
16524
|
.copy-btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
|
|
16392
16525
|
.copy-btn svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;flex:none}
|
|
16393
16526
|
.copy-btn .ic-check{display:none}
|
|
16394
|
-
.copy-btn.done{color:var(--
|
|
16527
|
+
.copy-btn.done{color:var(--success);border-color:var(--success)}
|
|
16395
16528
|
.copy-btn.done .ic-copy{display:none}.copy-btn.done .ic-check{display:block}
|
|
16396
16529
|
.copy-btn.done .ic-check path{stroke-dasharray:24;stroke-dashoffset:24;animation:mh-draw .22s ease-out forwards}
|
|
16397
|
-
.copy-btn.fail{color
|
|
16530
|
+
.copy-btn.fail{color:var(--danger);border-color:var(--danger)}
|
|
16398
16531
|
@keyframes mh-draw{to{stroke-dashoffset:0}}
|
|
16399
|
-
@media (prefers-color-scheme:dark){:root{--ok:#3fb950}}
|
|
16400
16532
|
@media (max-width:480px){.copy-btn span{display:none}.copy-btn{padding:0 9px}}
|
|
16401
16533
|
@media (prefers-reduced-motion:reduce){.copy-btn .ic-check path{animation:none;stroke-dashoffset:0}}`;
|
|
16402
16534
|
var init_share_copy = __esm(() => {
|
|
@@ -16811,14 +16943,13 @@ function pageShell(title, inner, opts) {
|
|
|
16811
16943
|
<meta name="robots" content="noindex">
|
|
16812
16944
|
<title>${escapeHtml(title)}</title>
|
|
16813
16945
|
<style>
|
|
16814
|
-
|
|
16815
|
-
@media (prefers-color-scheme: dark){:root{--bg:#0d1117;--fg:#e6edf3;--muted:#8b949e;--line:#30363d;--accent:#4493f8;--card:#161b22}}
|
|
16946
|
+
${THEME_CSS}
|
|
16816
16947
|
*{box-sizing:border-box}
|
|
16817
16948
|
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}
|
|
16818
16949
|
.wrap{max-width:820px;margin:0 auto;padding:32px 20px 80px}
|
|
16819
16950
|
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}
|
|
16820
16951
|
header.mh h1.title{font-size:22px;margin:0}
|
|
16821
|
-
.edit-btn{background:var(--accent);color
|
|
16952
|
+
.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}
|
|
16822
16953
|
${COPY_CSS}
|
|
16823
16954
|
.hint{color:var(--muted);font-size:13px;margin:0 0 14px}
|
|
16824
16955
|
article.doc h1,article.doc h2,article.doc h3{line-height:1.3;margin:1.4em 0 .5em}
|
|
@@ -16832,11 +16963,11 @@ function pageShell(title, inner, opts) {
|
|
|
16832
16963
|
article.doc td,article.doc th,table.db td,table.db th{border:1px solid var(--line);padding:7px 10px;text-align:left}
|
|
16833
16964
|
table.db th{background:var(--card)}
|
|
16834
16965
|
.table-wrap{overflow:auto}
|
|
16835
|
-
td[contenteditable]{outline:none} td.saving{opacity:.5} td.saved{background:
|
|
16966
|
+
td[contenteditable]{outline:none} td.saving{opacity:.5} td.saved{background:color-mix(in srgb,var(--success) 18%,transparent)}
|
|
16836
16967
|
.tag{display:inline-block;background:var(--card);border:1px solid var(--line);border-radius:999px;padding:1px 9px;font-size:12px}
|
|
16837
16968
|
.muted{color:var(--muted)} .mh-img{text-align:center}
|
|
16838
16969
|
.mh-media{text-align:center} .mh-media video,.mh-media audio{max-width:100%}
|
|
16839
|
-
|
|
16970
|
+
${SHARE_FILE_CSS}
|
|
16840
16971
|
.mh-doclink{background:var(--card);border:1px solid var(--line);border-radius:6px;padding:0 5px;white-space:nowrap}
|
|
16841
16972
|
.mh-doclink::before{content:"\uD83D\uDCC4";font-size:.85em;margin-right:3px}
|
|
16842
16973
|
iframe.mh-embed{width:100%;border:1px solid var(--line);border-radius:8px;min-height:240px}
|
|
@@ -16845,8 +16976,8 @@ function pageShell(title, inner, opts) {
|
|
|
16845
16976
|
.row{display:flex;gap:10px;align-items:center;margin:10px 0}
|
|
16846
16977
|
form.pw{max-width:320px;margin:12vh auto 0;display:flex;flex-direction:column;gap:12px}
|
|
16847
16978
|
form.pw input{padding:9px;border:1px solid var(--line);border-radius:7px;background:var(--card);color:var(--fg)}
|
|
16848
|
-
form.pw button{padding:9px;border:0;border-radius:7px;background:var(--accent);color
|
|
16849
|
-
form.pw .err{color
|
|
16979
|
+
form.pw button{padding:9px;border:0;border-radius:7px;background:var(--accent);color:var(--accent-fg);cursor:pointer}
|
|
16980
|
+
form.pw .err{color:var(--danger);font-size:13px;margin:0}
|
|
16850
16981
|
footer.mh{margin-top:48px;border-top:1px solid var(--line);padding-top:14px;color:var(--muted);font-size:12px;text-align:center}
|
|
16851
16982
|
</style></head><body>
|
|
16852
16983
|
${opts.bare ? `<div class="wrap">${inner}</div>` : `<div class="wrap">
|
|
@@ -16860,6 +16991,7 @@ ${script}
|
|
|
16860
16991
|
}
|
|
16861
16992
|
var HTML, HASH_RE3, SHARE_SESSION_TTL_MS;
|
|
16862
16993
|
var init_share_serve = __esm(() => {
|
|
16994
|
+
init_ui_theme();
|
|
16863
16995
|
init_ids();
|
|
16864
16996
|
init_shares();
|
|
16865
16997
|
init_documents();
|
|
@@ -20903,6 +21035,162 @@ init_records();
|
|
|
20903
21035
|
init_blobs_core();
|
|
20904
21036
|
init_storage();
|
|
20905
21037
|
init_storage_s3_sign();
|
|
21038
|
+
|
|
21039
|
+
// src/core/sync/share-short-links.ts
|
|
21040
|
+
init_e2ee();
|
|
21041
|
+
init_storage();
|
|
21042
|
+
|
|
21043
|
+
// src/core/sync/share-link.ts
|
|
21044
|
+
init_e2ee();
|
|
21045
|
+
async function tokenHash(token) {
|
|
21046
|
+
return toB64url(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(token))));
|
|
21047
|
+
}
|
|
21048
|
+
async function linkId(token) {
|
|
21049
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(token));
|
|
21050
|
+
return toB64url(new Uint8Array(digest).slice(0, 16));
|
|
21051
|
+
}
|
|
21052
|
+
function signedUrlExpiry(value) {
|
|
21053
|
+
try {
|
|
21054
|
+
const u = new URL(value);
|
|
21055
|
+
if (u.protocol !== "https:" || u.username || u.password || u.hash || value.length > 8192)
|
|
21056
|
+
return null;
|
|
21057
|
+
const date = u.searchParams.get("X-Amz-Date") ?? "";
|
|
21058
|
+
const seconds = Number(u.searchParams.get("X-Amz-Expires"));
|
|
21059
|
+
if (!/^\d{8}T\d{6}Z$/.test(date) || !Number.isInteger(seconds) || seconds < 1 || seconds > 604800)
|
|
21060
|
+
return null;
|
|
21061
|
+
if (!/^[a-f0-9]{64}$/i.test(u.searchParams.get("X-Amz-Signature") ?? ""))
|
|
21062
|
+
return null;
|
|
21063
|
+
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`;
|
|
21064
|
+
const start = Date.parse(iso);
|
|
21065
|
+
return Number.isFinite(start) ? start + seconds * 1000 : null;
|
|
21066
|
+
} catch {
|
|
21067
|
+
return null;
|
|
21068
|
+
}
|
|
21069
|
+
}
|
|
21070
|
+
function longShareUrl(base, link) {
|
|
21071
|
+
return `${base.replace(/\/+$/, "")}/#m=${encodeURIComponent(link.manifestUrl)}&${link.keyB64 ? `k=${link.keyB64}` : `s=${link.saltB64}`}`;
|
|
21072
|
+
}
|
|
21073
|
+
|
|
21074
|
+
// src/core/sync/share-short-links.ts
|
|
21075
|
+
var TIMEOUT = 8000;
|
|
21076
|
+
function root(config, slug) {
|
|
21077
|
+
return `${config.prefix.replace(/^\/+|\/+$/g, "") ? `${config.prefix.replace(/^\/+|\/+$/g, "")}/` : ""}shares/${slug}/links/`;
|
|
21078
|
+
}
|
|
21079
|
+
function viewerBase(base) {
|
|
21080
|
+
const url = new URL(base);
|
|
21081
|
+
if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash)
|
|
21082
|
+
throw new Error("invalid viewer");
|
|
21083
|
+
if (url.pathname !== "/")
|
|
21084
|
+
throw new Error("static subpath viewer");
|
|
21085
|
+
return url.origin;
|
|
21086
|
+
}
|
|
21087
|
+
async function unpack(config, bytes) {
|
|
21088
|
+
const raw = config.encrypt && config.masterKey ? await decryptBytes(fromB64(config.masterKey), bytes) : bytes;
|
|
21089
|
+
const value = JSON.parse(new TextDecoder().decode(raw));
|
|
21090
|
+
if (value.v !== 1 || !/^[A-Za-z0-9_-]{43}$/.test(value.token) || viewerBase(value.base) !== value.base)
|
|
21091
|
+
throw new Error("invalid short-link control");
|
|
21092
|
+
return value;
|
|
21093
|
+
}
|
|
21094
|
+
async function controlFor(config, slug, base) {
|
|
21095
|
+
const client = storageClientFor(config);
|
|
21096
|
+
const path = `${root(config, slug)}${await tokenHash(base)}.json`;
|
|
21097
|
+
const existing = await client.get(path);
|
|
21098
|
+
if (existing) {
|
|
21099
|
+
const control = await unpack(config, existing);
|
|
21100
|
+
if (control.base !== base)
|
|
21101
|
+
throw new Error("viewer mismatch");
|
|
21102
|
+
return control;
|
|
21103
|
+
}
|
|
21104
|
+
const control = { v: 1, base, token: toB64url(generateMasterKey()) };
|
|
21105
|
+
const plain = new TextEncoder().encode(JSON.stringify(control));
|
|
21106
|
+
const bytes = config.encrypt && config.masterKey ? await encryptBytes(fromB64(config.masterKey), plain) : plain;
|
|
21107
|
+
try {
|
|
21108
|
+
await client.put(path, bytes, {
|
|
21109
|
+
ifNoneMatch: true,
|
|
21110
|
+
contentType: "application/octet-stream"
|
|
21111
|
+
});
|
|
21112
|
+
} catch (error) {
|
|
21113
|
+
const winner = await client.get(path);
|
|
21114
|
+
if (!winner)
|
|
21115
|
+
throw error;
|
|
21116
|
+
const value = await unpack(config, winner);
|
|
21117
|
+
if (value.base !== base)
|
|
21118
|
+
throw new Error("viewer mismatch");
|
|
21119
|
+
return value;
|
|
21120
|
+
}
|
|
21121
|
+
return control;
|
|
21122
|
+
}
|
|
21123
|
+
function request(url, init = {}) {
|
|
21124
|
+
return fetch(url, {
|
|
21125
|
+
...init,
|
|
21126
|
+
redirect: "error",
|
|
21127
|
+
credentials: "omit",
|
|
21128
|
+
cache: "no-store",
|
|
21129
|
+
signal: AbortSignal.timeout(TIMEOUT)
|
|
21130
|
+
});
|
|
21131
|
+
}
|
|
21132
|
+
async function bucketShareUrl(config, slug, base, link) {
|
|
21133
|
+
const fallback = longShareUrl(base, link);
|
|
21134
|
+
try {
|
|
21135
|
+
const origin = viewerBase(base);
|
|
21136
|
+
const expiresAt = Math.min(link.presignExp, signedUrlExpiry(link.manifestUrl) ?? 0);
|
|
21137
|
+
if (expiresAt <= Date.now())
|
|
21138
|
+
return fallback;
|
|
21139
|
+
const probe = await request(`${origin}/api/links`);
|
|
21140
|
+
if (!probe.ok || (await probe.json()).service !== "metahub-share-links")
|
|
21141
|
+
throw new Error("static viewer");
|
|
21142
|
+
const control = await controlFor(config, slug, origin);
|
|
21143
|
+
const id = await linkId(control.token);
|
|
21144
|
+
const endpoint = `${origin}/api/links/${id}`;
|
|
21145
|
+
const authorization = `Bearer ${control.token}`;
|
|
21146
|
+
const descriptor = {
|
|
21147
|
+
v: 1,
|
|
21148
|
+
manifestUrl: link.manifestUrl,
|
|
21149
|
+
expiresAt,
|
|
21150
|
+
...link.saltB64 ? { salt: toB64url(fromB64(link.saltB64)) } : {}
|
|
21151
|
+
};
|
|
21152
|
+
const current = await request(endpoint, { headers: { authorization } });
|
|
21153
|
+
if (!current.ok && current.status !== 404)
|
|
21154
|
+
throw new Error("short-link lookup failed");
|
|
21155
|
+
const etag = current.headers.get("etag");
|
|
21156
|
+
if (current.ok && !etag)
|
|
21157
|
+
throw new Error("not a short-link API");
|
|
21158
|
+
const result = await request(endpoint, {
|
|
21159
|
+
method: "PUT",
|
|
21160
|
+
headers: {
|
|
21161
|
+
authorization,
|
|
21162
|
+
"content-type": "application/json",
|
|
21163
|
+
...current.ok ? { "if-match": etag } : { "if-none-match": "*" }
|
|
21164
|
+
},
|
|
21165
|
+
body: JSON.stringify(descriptor)
|
|
21166
|
+
});
|
|
21167
|
+
if (!result.ok || !result.headers.get("etag") || (await result.json()).ok !== true)
|
|
21168
|
+
throw new Error("short-link registration failed");
|
|
21169
|
+
return `${origin}/s/${id}${link.keyB64 ? `#k=${toB64url(fromB64(link.keyB64))}` : ""}`;
|
|
21170
|
+
} catch {
|
|
21171
|
+
console.warn("share: short-link service unavailable; using the original long link");
|
|
21172
|
+
return fallback;
|
|
21173
|
+
}
|
|
21174
|
+
}
|
|
21175
|
+
async function revokeBucketShortLinks(config, slug) {
|
|
21176
|
+
const client = storageClientFor(config);
|
|
21177
|
+
for (const object of await client.list(root(config, slug))) {
|
|
21178
|
+
if (!object.key.endsWith(".json"))
|
|
21179
|
+
continue;
|
|
21180
|
+
const raw = await client.get(object.key);
|
|
21181
|
+
if (!raw)
|
|
21182
|
+
continue;
|
|
21183
|
+
const control = await unpack(config, raw);
|
|
21184
|
+
const response = await request(`${control.base}/api/links/${await linkId(control.token)}`, {
|
|
21185
|
+
method: "DELETE",
|
|
21186
|
+
headers: { authorization: `Bearer ${control.token}` }
|
|
21187
|
+
});
|
|
21188
|
+
if (!response.ok || (await response.json()).ok !== true)
|
|
21189
|
+
throw new Error("short-link revocation has not been confirmed; retry later");
|
|
21190
|
+
}
|
|
21191
|
+
}
|
|
21192
|
+
|
|
21193
|
+
// src/core/sync/share-export.ts
|
|
20906
21194
|
init_e2ee();
|
|
20907
21195
|
function sharesRoot(prefix) {
|
|
20908
21196
|
const p = (prefix || "").replace(/^\/+|\/+$/g, "");
|
|
@@ -21043,6 +21331,8 @@ async function renewBucketShare(db, config, slug, expiresSec = MAX_PRESIGN_SECON
|
|
|
21043
21331
|
const meta = await readMeta2(config, slug);
|
|
21044
21332
|
if (!meta)
|
|
21045
21333
|
throw new MhError("not_found", `no such bucket share: ${slug}`);
|
|
21334
|
+
if (meta.revoking)
|
|
21335
|
+
throw new MhError("conflict", "share revocation is pending; retry revocation instead");
|
|
21046
21336
|
const shareKey = fromB64(meta.key);
|
|
21047
21337
|
const exp = clampExpiry(expiresSec);
|
|
21048
21338
|
const { manifestUrl, objects, title } = await writeShareObjects(db, {
|
|
@@ -21078,6 +21368,8 @@ async function represignBucketShare(config, slug, expiresSec = MAX_PRESIGN_SECON
|
|
|
21078
21368
|
const meta = await readMeta2(config, slug);
|
|
21079
21369
|
if (!meta)
|
|
21080
21370
|
throw new MhError("not_found", `no such bucket share: ${slug}`);
|
|
21371
|
+
if (meta.revoking)
|
|
21372
|
+
throw new MhError("conflict", "share revocation is pending; retry revocation instead");
|
|
21081
21373
|
const client = storageClientFor(config);
|
|
21082
21374
|
const root = sharesRoot(config.prefix);
|
|
21083
21375
|
const shareKey = fromB64(meta.key);
|
|
@@ -21117,15 +21409,19 @@ async function listBucketShares(config) {
|
|
|
21117
21409
|
async function deleteBucketShareObjects(config, slug) {
|
|
21118
21410
|
const client = storageClientFor(config);
|
|
21119
21411
|
const root = sharesRoot(config.prefix);
|
|
21120
|
-
await
|
|
21121
|
-
|
|
21122
|
-
|
|
21123
|
-
|
|
21124
|
-
const objs = meta?.objects ?? (await client.list(`${root}/${slug}/`)
|
|
21412
|
+
const meta = await readMeta2(config, slug);
|
|
21413
|
+
if (meta)
|
|
21414
|
+
await client.put(metaKey(root, slug), await metaBytes(config, { ...meta, revoking: true }), { contentType: "application/octet-stream" });
|
|
21415
|
+
await revokeBucketShortLinks(config, slug);
|
|
21416
|
+
const objs = new Set([...meta?.objects ?? [], ...(await client.list(`${root}/${slug}/`)).map((o) => o.key)]);
|
|
21417
|
+
const metaPath = metaKey(root, slug);
|
|
21125
21418
|
for (const key of objs)
|
|
21126
|
-
|
|
21127
|
-
|
|
21128
|
-
|
|
21419
|
+
if (key !== metaPath && !key.includes(`/links/`))
|
|
21420
|
+
await client.del(key);
|
|
21421
|
+
for (const key of objs)
|
|
21422
|
+
if (key.includes(`/links/`))
|
|
21423
|
+
await client.del(key);
|
|
21424
|
+
await client.del(metaPath);
|
|
21129
21425
|
}
|
|
21130
21426
|
function clampExpiry(sec) {
|
|
21131
21427
|
return Math.min(Math.max(60, Math.floor(sec)), MAX_PRESIGN_SECONDS);
|
|
@@ -21160,7 +21456,8 @@ function bucketShareItem(bucket, m) {
|
|
|
21160
21456
|
hosting: "s3",
|
|
21161
21457
|
expiresAt: m.presign_exp,
|
|
21162
21458
|
hasPassword: m.has_password,
|
|
21163
|
-
contentUpdatedAt: m.content_updated_at ?? m.created_at
|
|
21459
|
+
contentUpdatedAt: m.content_updated_at ?? m.created_at,
|
|
21460
|
+
...m.revoking ? { lifecycle: "cleanup_pending" } : {}
|
|
21164
21461
|
};
|
|
21165
21462
|
}
|
|
21166
21463
|
async function fetchPeerShares(url, token, targetId) {
|
|
@@ -21371,7 +21668,7 @@ function pickBucket(db, bucketUrl) {
|
|
|
21371
21668
|
throw new MhError("invalid_input", `multiple buckets \u2014 pass --bucket <url> (one of: ${buckets.map((b) => b.url).join(", ")})`);
|
|
21372
21669
|
return buckets[0].url;
|
|
21373
21670
|
}
|
|
21374
|
-
function
|
|
21671
|
+
function viewerBase2(db, override) {
|
|
21375
21672
|
if (override)
|
|
21376
21673
|
return override.replace(/\/+$/, "");
|
|
21377
21674
|
const row = db.query("SELECT value FROM meta WHERE key='cfg_share_viewer_url'").get();
|
|
@@ -21384,10 +21681,6 @@ function viewerOriginOf(base) {
|
|
|
21384
21681
|
return;
|
|
21385
21682
|
}
|
|
21386
21683
|
}
|
|
21387
|
-
function bucketLink(base, manifestUrl, keyB64, saltB64) {
|
|
21388
|
-
const frag = `m=${encodeURIComponent(manifestUrl)}&` + (keyB64 ? `k=${keyB64}` : `s=${saltB64}`);
|
|
21389
|
-
return `${base}/#${frag}`;
|
|
21390
|
-
}
|
|
21391
21684
|
function assertShareCombo(req) {
|
|
21392
21685
|
const fail = (msg) => {
|
|
21393
21686
|
throw new MhError("invalid_input", msg);
|
|
@@ -21414,7 +21707,7 @@ async function createShareAction(db, req) {
|
|
|
21414
21707
|
const target = resolveTarget(db, req.kind, req.ref);
|
|
21415
21708
|
const bucketUrl = pickBucket(db, req.bucketUrl);
|
|
21416
21709
|
const { config, label } = s3PeerConfig(db, bucketUrl);
|
|
21417
|
-
const base =
|
|
21710
|
+
const base = viewerBase2(db, req.viewerBase);
|
|
21418
21711
|
const slug = freshSlug(db);
|
|
21419
21712
|
const out = await createBucketShare(db, {
|
|
21420
21713
|
slug,
|
|
@@ -21432,7 +21725,7 @@ async function createShareAction(db, req) {
|
|
|
21432
21725
|
permission: "view",
|
|
21433
21726
|
transport: "s3",
|
|
21434
21727
|
hosting: "s3",
|
|
21435
|
-
url:
|
|
21728
|
+
url: await bucketShareUrl(config, slug, base, out),
|
|
21436
21729
|
expiresAt: out.presignExp,
|
|
21437
21730
|
source: `\u6876 ${label}`
|
|
21438
21731
|
};
|
|
@@ -21717,7 +22010,13 @@ async function revokeShareAction(db, slug) {
|
|
|
21717
22010
|
const owner = await bucketOwning(db, slug);
|
|
21718
22011
|
if (!owner)
|
|
21719
22012
|
return { ok: false, status: "not_found" };
|
|
21720
|
-
|
|
22013
|
+
try {
|
|
22014
|
+
await deleteBucketShareObjects(JSON.parse(owner.peer.config), slug);
|
|
22015
|
+
} catch {
|
|
22016
|
+
if (owner.item)
|
|
22017
|
+
primeRemoteShare(db, owner.peer.url, { ...owner.item, lifecycle: "cleanup_pending" });
|
|
22018
|
+
return { ok: false, status: "cleanup_pending" };
|
|
22019
|
+
}
|
|
21721
22020
|
dropRemoteShare(db, owner.peer.url, slug);
|
|
21722
22021
|
return { ok: true, status: "revoked" };
|
|
21723
22022
|
}
|
|
@@ -21739,7 +22038,7 @@ async function renewShareAction(db, slug, viewerBaseOverride, opts) {
|
|
|
21739
22038
|
throw new MhError("not_found", `no such object-storage share: ${slug}`);
|
|
21740
22039
|
const { peer: p } = owner;
|
|
21741
22040
|
const config = JSON.parse(p.config);
|
|
21742
|
-
const base =
|
|
22041
|
+
const base = viewerBase2(db, viewerBaseOverride);
|
|
21743
22042
|
const out = opts?.refreshContent ? await renewBucketShare(db, config, slug) : await represignBucketShare(config, slug);
|
|
21744
22043
|
if (owner.item)
|
|
21745
22044
|
primeRemoteShare(db, p.url, {
|
|
@@ -21754,7 +22053,7 @@ async function renewShareAction(db, slug, viewerBaseOverride, opts) {
|
|
|
21754
22053
|
permission: "view",
|
|
21755
22054
|
transport: "s3",
|
|
21756
22055
|
hosting: "s3",
|
|
21757
|
-
url:
|
|
22056
|
+
url: await bucketShareUrl(config, slug, base, out),
|
|
21758
22057
|
expiresAt: out.presignExp,
|
|
21759
22058
|
source: `\u6876 ${p.label ?? p.url}`
|
|
21760
22059
|
};
|
|
@@ -22553,7 +22852,7 @@ var revoke = defineCommand({
|
|
|
22553
22852
|
return;
|
|
22554
22853
|
}
|
|
22555
22854
|
const result = await revokeShareAction(db, args.slug);
|
|
22556
|
-
print({ ...result, revoked: result.ok ? args.slug : null }, () => result.status === "cleanup_pending" ? `revocation pending:
|
|
22855
|
+
print({ ...result, revoked: result.ok ? args.slug : null }, () => result.status === "cleanup_pending" ? `revocation pending: remote cleanup has not been confirmed for ${args.slug}; retry revoke` : result.ok ? `revoked ${args.slug}` : `no such share: ${args.slug}`);
|
|
22557
22856
|
})
|
|
22558
22857
|
});
|
|
22559
22858
|
var renew = defineCommand({
|
|
@@ -22730,6 +23029,15 @@ var completion_default = defineCommand({
|
|
|
22730
23029
|
init_client();
|
|
22731
23030
|
init_peers();
|
|
22732
23031
|
|
|
23032
|
+
// src/core/csv-columns.ts
|
|
23033
|
+
function csvPropertyHeaders(props) {
|
|
23034
|
+
const ids = new Set(props.map((p) => p.id));
|
|
23035
|
+
const counts = new Map;
|
|
23036
|
+
for (const p of props)
|
|
23037
|
+
counts.set(p.name.toLowerCase(), (counts.get(p.name.toLowerCase()) ?? 0) + 1);
|
|
23038
|
+
return props.map((p) => p.name.toLowerCase() === "id" || counts.get(p.name.toLowerCase()) !== 1 || ids.has(p.name) ? p.id : p.name);
|
|
23039
|
+
}
|
|
23040
|
+
|
|
22733
23041
|
// src/core/sync/files.ts
|
|
22734
23042
|
init_resolve();
|
|
22735
23043
|
init_documents();
|
|
@@ -22901,10 +23209,10 @@ async function exportDb(db, id, path) {
|
|
|
22901
23209
|
}
|
|
22902
23210
|
const docTitles = props.some((p) => p.type === "doc") ? documentTitleMap(db) : new Map;
|
|
22903
23211
|
const titlesFor = (p) => p.type === "doc" ? docTitles : relTitles.get(p.config?.database ?? "") ?? new Map;
|
|
22904
|
-
const header = ["id", ...props
|
|
23212
|
+
const header = ["id", ...csvPropertyHeaders(props)];
|
|
22905
23213
|
const rows = recs.map((r) => [
|
|
22906
23214
|
r.id,
|
|
22907
|
-
...props.map((p) => p.type === "relation" || p.type === "doc" ? encodeRelationCell(r.cells[p.id], titlesFor(p)) : cellToString(r.
|
|
23215
|
+
...props.map((p) => p.type === "relation" || p.type === "doc" ? encodeRelationCell(r.cells[p.id], titlesFor(p)) : cellToString(r.cells[p.id]))
|
|
22908
23216
|
]);
|
|
22909
23217
|
const csv = toCsv([header, ...rows]);
|
|
22910
23218
|
await Bun.write(path, csv);
|
|
@@ -22921,29 +23229,43 @@ async function importDb(db, id, path) {
|
|
|
22921
23229
|
return { direction: "import", kind: "db", id, path, rows: 0 };
|
|
22922
23230
|
const header = grid[0];
|
|
22923
23231
|
const idCol = header.indexOf("id");
|
|
22924
|
-
|
|
22925
|
-
|
|
22926
|
-
|
|
22927
|
-
|
|
23232
|
+
if (header.filter((key) => key === "id").length > 1)
|
|
23233
|
+
throw new MhError("invalid_input", "duplicate CSV record id column");
|
|
23234
|
+
const props = listProperties(db, id);
|
|
23235
|
+
const seen = new Set;
|
|
23236
|
+
const columns = header.map((key, col) => {
|
|
23237
|
+
if (col === idCol)
|
|
23238
|
+
return null;
|
|
23239
|
+
const p = resolveData(props, { [key]: null })[0].prop;
|
|
23240
|
+
if (seen.has(p.id))
|
|
23241
|
+
throw new MhError("invalid_input", `duplicate CSV property: ${key}`);
|
|
23242
|
+
seen.add(p.id);
|
|
23243
|
+
return p;
|
|
23244
|
+
});
|
|
22928
23245
|
let count = 0;
|
|
22929
23246
|
for (let i = 1;i < grid.length; i++) {
|
|
22930
|
-
|
|
22931
|
-
|
|
22932
|
-
|
|
22933
|
-
|
|
22934
|
-
|
|
22935
|
-
|
|
22936
|
-
|
|
22937
|
-
|
|
22938
|
-
|
|
22939
|
-
|
|
22940
|
-
|
|
22941
|
-
|
|
22942
|
-
|
|
22943
|
-
|
|
22944
|
-
|
|
22945
|
-
|
|
22946
|
-
|
|
23247
|
+
writeTx(db, () => {
|
|
23248
|
+
const cells = grid[i];
|
|
23249
|
+
const data = {};
|
|
23250
|
+
for (let c = 0;c < header.length; c++) {
|
|
23251
|
+
if (c === idCol)
|
|
23252
|
+
continue;
|
|
23253
|
+
const raw = cells[c];
|
|
23254
|
+
if (raw == null || raw === "")
|
|
23255
|
+
continue;
|
|
23256
|
+
const colType = columns[c].type;
|
|
23257
|
+
data[columns[c].id] = colType === "relation" || colType === "doc" ? decodeRelationCell(raw) : parseCell(raw);
|
|
23258
|
+
}
|
|
23259
|
+
const rowId = idCol >= 0 ? cells[idCol]?.trim() : undefined;
|
|
23260
|
+
const existing = rowId ? getRecord(db, rowId) : null;
|
|
23261
|
+
if (existing && existing.database_id !== id)
|
|
23262
|
+
throw new MhError("invalid_input", `CSV row ${i + 1}: record ${rowId} belongs to another database`);
|
|
23263
|
+
if (existing)
|
|
23264
|
+
updateRecord(db, rowId, data);
|
|
23265
|
+
else
|
|
23266
|
+
createRecord(db, id, data);
|
|
23267
|
+
count++;
|
|
23268
|
+
});
|
|
22947
23269
|
}
|
|
22948
23270
|
return { direction: "import", kind: "db", id, path, rows: count };
|
|
22949
23271
|
}
|
|
@@ -25325,6 +25647,7 @@ async function enableWorkerSubdomain(cfg) {
|
|
|
25325
25647
|
}
|
|
25326
25648
|
|
|
25327
25649
|
// src/core/sync/room-serve.ts
|
|
25650
|
+
init_ui_theme();
|
|
25328
25651
|
init_errors();
|
|
25329
25652
|
init_http_status();
|
|
25330
25653
|
init_ids();
|
|
@@ -25336,6 +25659,19 @@ init_sites_core();
|
|
|
25336
25659
|
init_shares();
|
|
25337
25660
|
init_room_protocol();
|
|
25338
25661
|
var ROOM_SESSION_TTL_MS = 12 * 60 * 60 * 1000;
|
|
25662
|
+
var PAGE_CSS = `
|
|
25663
|
+
${THEME_CSS}
|
|
25664
|
+
*{box-sizing:border-box}
|
|
25665
|
+
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;
|
|
25666
|
+
min-height:100dvh;display:flex;align-items:center;justify-content:center;padding:24px}
|
|
25667
|
+
main{max-width:420px;width:100%}
|
|
25668
|
+
form.pw{display:flex;flex-direction:column;gap:12px}
|
|
25669
|
+
form.pw input{padding:9px;border:1px solid var(--line);border-radius:7px;background:var(--card);color:var(--fg)}
|
|
25670
|
+
form.pw button{padding:9px;border:0;border-radius:7px;background:var(--accent);color:var(--accent-fg);cursor:pointer}
|
|
25671
|
+
.err{color:var(--danger);font-size:13px;margin:0}
|
|
25672
|
+
.muted{color:var(--muted);font-size:14px}
|
|
25673
|
+
h1{font-size:20px;margin:0 0 10px;text-align:center}
|
|
25674
|
+
footer{margin-top:34px;color:var(--muted);font-size:12px;text-align:center}`;
|
|
25339
25675
|
|
|
25340
25676
|
// src/workers/room.ts
|
|
25341
25677
|
init_room_protocol();
|
|
@@ -25705,6 +26041,7 @@ function disconnectEdge(db) {
|
|
|
25705
26041
|
}
|
|
25706
26042
|
|
|
25707
26043
|
// src/core/sync/cf-oauth.ts
|
|
26044
|
+
init_ui_theme();
|
|
25708
26045
|
init_errors();
|
|
25709
26046
|
init_page_messages();
|
|
25710
26047
|
init_e2ee();
|
|
@@ -25873,7 +26210,7 @@ async function startCfLogin(opts = {}) {
|
|
|
25873
26210
|
}
|
|
25874
26211
|
};
|
|
25875
26212
|
}
|
|
25876
|
-
var callbackHtml = (locale) => `<!doctype html><html lang="${locale}"><meta charset="utf-8"><title>MetaHub</title>
|
|
26213
|
+
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>
|
|
25877
26214
|
<body style="font:15px system-ui;display:grid;place-items:center;height:100vh;margin:0">
|
|
25878
26215
|
<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>`;
|
|
25879
26216
|
|
|
@@ -28008,24 +28345,15 @@ function startServer(opts = {}) {
|
|
|
28008
28345
|
init_errors();
|
|
28009
28346
|
|
|
28010
28347
|
// src/webui/server/assets.ts
|
|
28348
|
+
init_ui_theme();
|
|
28011
28349
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
28012
28350
|
import { readdirSync as readdirSync4, statSync as statSync3 } from "fs";
|
|
28013
28351
|
import { join as join11, dirname as dirname2 } from "path";
|
|
28014
28352
|
|
|
28015
28353
|
// src/webui/styles.css
|
|
28016
28354
|
var styles_default = ` :root {
|
|
28017
|
-
/*
|
|
28018
|
-
|
|
28019
|
-
data-resolved, so a manual theme toggle retunes it too. */
|
|
28020
|
-
color-scheme: light;
|
|
28021
|
-
--bg:#ffffff; --surface:#fbfbfa; --surface-2:#f1f1ef; --sidebar:#f7f7f5;
|
|
28022
|
-
--fg:#2c2c30; --fg-soft:#5b5b62; --muted:#75757f; --line:#ebebe8; --line-strong:#dededb;
|
|
28023
|
-
--accent:#4a55d6; --accent-fg:#ffffff; --accent-soft:#eef0ff; --danger:#d6473b; --danger-soft:#fdeceb;
|
|
28024
|
-
--success:#1f8f3e;
|
|
28025
|
-
--hover:rgba(45,45,55,.045); --hover-2:rgba(45,45,55,.08);
|
|
28026
|
-
--shadow-sm:0 1px 2px rgba(20,20,40,.06),0 1px 1px rgba(20,20,40,.04);
|
|
28027
|
-
--shadow-md:0 4px 12px rgba(20,20,40,.08),0 2px 4px rgba(20,20,40,.05);
|
|
28028
|
-
--shadow-lg:0 16px 48px rgba(20,20,40,.16),0 4px 12px rgba(20,20,40,.08);
|
|
28355
|
+
/* Palette comes from core/ui-theme.ts; dimensions and typography stay here. */
|
|
28356
|
+
|
|
28029
28357
|
--radius:8px; --radius-sm:6px; --radius-lg:14px; --radius-xl:16px;
|
|
28030
28358
|
--fs-body:14px; --fs-ui:13.5px; --fs-sm:12.5px; --fs-xs:11.5px; --fs-micro:11px;
|
|
28031
28359
|
--ui:"Hanken Grotesk",-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;
|
|
@@ -28033,23 +28361,12 @@ var styles_default = ` :root {
|
|
|
28033
28361
|
--kbd-font:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;
|
|
28034
28362
|
--tip-bg:#1f1f23; --tip-fg:#ffffff; --tip-kbd-bg:rgba(255,255,255,.14); --tip-kbd-fg:rgba(255,255,255,.92);
|
|
28035
28363
|
--note-lh:1.6;
|
|
28036
|
-
--code-bg:#f8f8f6;
|
|
28037
28364
|
--hl-cmt:#9a9aa2; --hl-key:#a626a4; --hl-str:#28823f; --hl-num:#b76a00;
|
|
28038
28365
|
--hl-fn:#3f51d6; --hl-type:#0a7ea4; --hl-var:#c2410c;
|
|
28039
28366
|
}
|
|
28040
|
-
/* Dark
|
|
28041
|
-
* "system" \u2192 the OS preference) to <html data-resolved="light|dark"> before
|
|
28042
|
-
* first paint (FOUC script in the shell) and on every change (theme.ts), so
|
|
28043
|
-
* CSS never needs a prefers-color-scheme duplicate of this block. */
|
|
28367
|
+
/* Dark tooltip and syntax tokens; shared UI colors/elevation live in core/ui-theme.ts. */
|
|
28044
28368
|
:root[data-resolved="dark"] {
|
|
28045
|
-
|
|
28046
|
-
--bg:#1a1a1c; --surface:#202022; --surface-2:#2a2a2d; --sidebar:#171719;
|
|
28047
|
-
--fg:#e6e6e9; --fg-soft:#b4b4bb; --muted:#8b8b95; --line:#2c2c30; --line-strong:#3a3a40;
|
|
28048
|
-
--accent:#7b86ff; --accent-fg:#14141a; --accent-soft:#23243a; --danger:#f87168; --danger-soft:#341e1c;
|
|
28049
|
-
--success:#3fb950;
|
|
28050
|
-
--hover:rgba(255,255,255,.05); --hover-2:rgba(255,255,255,.09);
|
|
28051
|
-
--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);
|
|
28052
|
-
--code-bg:#1d1d20;
|
|
28369
|
+
|
|
28053
28370
|
--tip-bg:#2e2e32; --tip-fg:var(--fg); --tip-kbd-bg:rgba(255,255,255,.08); --tip-kbd-fg:var(--fg-soft);
|
|
28054
28371
|
--hl-cmt:#7d7d86; --hl-key:#d291e4; --hl-str:#7ed492; --hl-num:#e0a566;
|
|
28055
28372
|
--hl-fn:#86a8ff; --hl-type:#5fc6e0; --hl-var:#f0936b;
|
|
@@ -28176,7 +28493,7 @@ var styles_default = ` :root {
|
|
|
28176
28493
|
.navitem { display:flex; align-items:center; gap:3px; width:100%; text-align:left; padding:5px 6px; margin-bottom:2px; border-radius:var(--radius-sm);
|
|
28177
28494
|
color:var(--fg-soft); font-size:var(--fs-ui); position:relative; white-space:nowrap; transition:background .1s; }
|
|
28178
28495
|
.navitem:hover { background:var(--hover-2); }
|
|
28179
|
-
.navitem.active { background:var(--
|
|
28496
|
+
.navitem.active { background:var(--hover-2); color:var(--fg); font-weight:600; box-shadow:none; }
|
|
28180
28497
|
.navitem .tw { width:18px; height:18px; display:grid; place-items:center; color:var(--muted); border-radius:4px; flex:none; }
|
|
28181
28498
|
.navitem .tw:hover { background:var(--hover-2); }
|
|
28182
28499
|
.navitem .tw svg { width:13px; height:13px; transition:transform .12s; }
|
|
@@ -28251,13 +28568,13 @@ var styles_default = ` :root {
|
|
|
28251
28568
|
(driven by --mark-y / --mark-h from JS, eased by CSS) */
|
|
28252
28569
|
.set-rail::before { content:""; position:absolute; left:0; top:4px; bottom:4px;
|
|
28253
28570
|
width:2px; border-radius:2px; background:var(--line); }
|
|
28254
|
-
.set-rail-mark { position:absolute; left:0; width:2px; border-radius:2px; background:var(--
|
|
28571
|
+
.set-rail-mark { position:absolute; left:0; width:2px; border-radius:2px; background:var(--fg-soft);
|
|
28255
28572
|
height:var(--mark-h,0); transform:translateY(var(--mark-y,0));
|
|
28256
28573
|
transition:transform .26s cubic-bezier(.4,0,.2,1), height .26s cubic-bezier(.4,0,.2,1); }
|
|
28257
28574
|
.set-rail-row { display:flex; align-items:center; gap:10px; padding:7px 10px; border-radius:var(--radius-sm);
|
|
28258
28575
|
color:var(--muted); text-align:left; cursor:pointer; transition:color .14s, background .14s; }
|
|
28259
28576
|
.set-rail-row:hover { background:var(--hover); color:var(--fg); }
|
|
28260
|
-
.set-rail-row.active { color:var(--
|
|
28577
|
+
.set-rail-row.active { color:var(--fg); }
|
|
28261
28578
|
.set-rail-ico { flex:none; display:grid; place-items:center; width:16px; height:16px; opacity:.85; }
|
|
28262
28579
|
.set-rail-ico svg { width:15px; height:15px; }
|
|
28263
28580
|
.set-rail-label { font-size:var(--fs-sm); font-weight:550; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
|
@@ -28314,7 +28631,7 @@ var styles_default = ` :root {
|
|
|
28314
28631
|
.set-row.dim > .set-row-line { opacity:.62; }
|
|
28315
28632
|
/* status dot in a caption: the only colour a row carries */
|
|
28316
28633
|
.cap-dot { display:inline-block; flex:none; width:7px; height:7px; border-radius:50%; background:var(--muted); }
|
|
28317
|
-
.cap-dot.ok { background:var(--success); } .cap-dot.warn { background:var(--warning
|
|
28634
|
+
.cap-dot.ok { background:var(--success); } .cap-dot.warn { background:var(--warning); } .cap-dot.err { background:var(--danger); }
|
|
28318
28635
|
.cap-err { color:var(--danger); }
|
|
28319
28636
|
/* tag variants next to a title: neutral outline (default), accent (roles), self (soft fill) */
|
|
28320
28637
|
.set-row-title .set-row-tag { margin-left:0; vertical-align:0; flex:none; }
|
|
@@ -28385,8 +28702,8 @@ var styles_default = ` :root {
|
|
|
28385
28702
|
.audit-actor { flex:none; font-size:11px; font-weight:600; padding:1px 7px; border-radius:999px;
|
|
28386
28703
|
background:var(--surface); border:1px solid var(--line); color:var(--fg-soft); max-width:110px;
|
|
28387
28704
|
overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
28388
|
-
.audit-actor.ai { background:color-mix(in srgb,
|
|
28389
|
-
border-color:color-mix(in srgb,
|
|
28705
|
+
.audit-actor.ai { background:color-mix(in srgb, var(--brand-purple) 14%, transparent);
|
|
28706
|
+
border-color:color-mix(in srgb, var(--brand-purple) 35%, transparent); color:var(--brand-purple); }
|
|
28390
28707
|
.audit-summary { font-size:var(--fs-ui); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
28391
28708
|
.audit-ent { color:inherit; font-weight:600; text-decoration:none; margin-left:2px; }
|
|
28392
28709
|
.audit-ent[href]:hover { color:var(--accent); text-decoration:underline; }
|
|
@@ -28405,7 +28722,7 @@ var styles_default = ` :root {
|
|
|
28405
28722
|
.audit-end { display:flex; align-items:center; gap:12px; margin:18px 0 0; color:var(--muted); font-size:var(--fs-xs); }
|
|
28406
28723
|
.audit-end::before, .audit-end::after { content:""; flex:1; height:1px; background:var(--line); }
|
|
28407
28724
|
@media (hover:none) { .audit-revert { opacity:1; } }
|
|
28408
|
-
.set-callout.warn { border-color:color-mix(in srgb,var(--warning
|
|
28725
|
+
.set-callout.warn { border-color:color-mix(in srgb,var(--warning) 32%,var(--line)); }
|
|
28409
28726
|
/* a quiet helper line under a field / chip group */
|
|
28410
28727
|
.set-hint { font-size:var(--fs-xs); color:var(--muted); line-height:1.5; margin:3px 0 4px; }
|
|
28411
28728
|
/* progressive disclosure ("\u5DE5\u4F5C\u539F\u7406" / "\u8FDB\u9636") \u2014 native details, themed */
|
|
@@ -28424,7 +28741,7 @@ var styles_default = ` :root {
|
|
|
28424
28741
|
.provider-chip { padding:6px 12px; border-radius:999px; border:1px solid var(--line-strong); background:var(--surface);
|
|
28425
28742
|
color:var(--fg-soft); font-size:var(--fs-sm); font-weight:550; transition:border-color .12s, background .12s, color .12s; }
|
|
28426
28743
|
.provider-chip:hover { border-color:var(--muted); color:var(--fg); }
|
|
28427
|
-
.provider-chip.sel { border-color:var(--
|
|
28744
|
+
.provider-chip.sel { border-color:var(--selected-border); background:var(--selected-bg); color:var(--accent); box-shadow:none; }
|
|
28428
28745
|
/* ---- \u5173\u4E8E page -----------------------------------------------------------
|
|
28429
28746
|
Product identity hero over the standard SetSection/SetRow stack. The cube
|
|
28430
28747
|
mark sizes to a nav-icon's proportions scaled up; the version line reuses
|
|
@@ -28464,8 +28781,8 @@ var styles_default = ` :root {
|
|
|
28464
28781
|
@keyframes ver-indet { 0% { left:-42%; } 100% { left:100%; } }
|
|
28465
28782
|
.theme-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:12px; }
|
|
28466
28783
|
.theme-card { position:relative; display:flex; flex-direction:column; align-items:flex-start; gap:10px;
|
|
28467
|
-
text-align:left; padding:16px; border:1px solid var(--line
|
|
28468
|
-
background:var(--
|
|
28784
|
+
text-align:left; padding:16px; border:1px solid var(--line); border-radius:var(--radius);
|
|
28785
|
+
background:var(--bg); color:var(--fg-soft); box-shadow:none;
|
|
28469
28786
|
transition:border-color .14s, background .14s, transform .14s, box-shadow .14s; }
|
|
28470
28787
|
.theme-card:hover { border-color:var(--muted); transform:translateY(-1px); }
|
|
28471
28788
|
.theme-card .tc-ico { width:34px; height:34px; display:grid; place-items:center; border-radius:9px;
|
|
@@ -28476,8 +28793,10 @@ var styles_default = ` :root {
|
|
|
28476
28793
|
.theme-card .tc-check { position:absolute; top:10px; right:10px; width:18px; height:18px; border-radius:50%;
|
|
28477
28794
|
background:var(--accent); color:var(--accent-fg); display:grid; place-items:center; opacity:0; transform:scale(.6); transition:opacity .14s, transform .14s; }
|
|
28478
28795
|
.theme-card .tc-check svg { width:12px; height:12px; stroke-width:2.6; }
|
|
28479
|
-
.theme-card.sel { border-color:var(--
|
|
28480
|
-
.theme-card.sel
|
|
28796
|
+
.theme-card.sel { border-color:var(--selected-border); background:var(--selected-bg); box-shadow:none; }
|
|
28797
|
+
.theme-card.sel:hover { background:var(--selected-hover-bg); border-color:var(--selected-hover-border); }
|
|
28798
|
+
.theme-card.sel .tc-desc { color:var(--selected-muted); }
|
|
28799
|
+
.theme-card.sel .tc-ico { background:var(--selected-icon-bg); color:var(--selected-icon-fg); }
|
|
28481
28800
|
.theme-card.sel .tc-check { opacity:1; transform:scale(1); }
|
|
28482
28801
|
@media (max-width:560px) { .theme-grid { grid-template-columns:1fr; } }
|
|
28483
28802
|
.brand-grid { grid-template-columns:repeat(auto-fit,minmax(min(100%,120px),1fr)); }
|
|
@@ -28494,7 +28813,7 @@ var styles_default = ` :root {
|
|
|
28494
28813
|
.sync-health-sub { display:inline-flex; align-items:center; gap:8px; max-width:100%; min-width:0; }
|
|
28495
28814
|
.sync-health-dot { flex:none; width:8px; height:8px; border-radius:50%; }
|
|
28496
28815
|
.sync-health-dot.dot-ok { background:var(--success); }
|
|
28497
|
-
.sync-health-dot.dot-warn { background:var(--warning
|
|
28816
|
+
.sync-health-dot.dot-warn { background:var(--warning); }
|
|
28498
28817
|
.sync-health-dot.dot-error { background:var(--danger); }
|
|
28499
28818
|
/* shared expander chevron (bucket + device roster rows) */
|
|
28500
28819
|
.row-chev { flex:none; color:var(--muted); display:flex; transition:transform .15s; }
|
|
@@ -28591,7 +28910,7 @@ var styles_default = ` :root {
|
|
|
28591
28910
|
.btn-secondary:hover { background:var(--surface-2); }
|
|
28592
28911
|
.btn-primary { background:var(--accent); color:var(--accent-fg); box-shadow:var(--shadow-sm); }
|
|
28593
28912
|
.btn-primary:hover { filter:brightness(1.07); }
|
|
28594
|
-
.btn-danger { background:var(--danger); color
|
|
28913
|
+
.btn-danger { background:var(--danger); color:var(--danger-fg); } .btn-danger:hover { filter:brightness(1.05); }
|
|
28595
28914
|
.btn.sm { padding:3px 8px; font-size:12px; }
|
|
28596
28915
|
/* Notion-style ambient sync indicator: a quiet ghost control living in the
|
|
28597
28916
|
topbar icon row. State reads through the *text/icon colour* \u2014 no filled pill
|
|
@@ -29464,7 +29783,7 @@ var styles_default = ` :root {
|
|
|
29464
29783
|
.shv-ico svg { width:19px; height:19px; }
|
|
29465
29784
|
.shv-ico.k-doc { color:var(--accent); background:var(--accent-soft); }
|
|
29466
29785
|
.shv-ico.k-database { color:var(--fg-soft); }
|
|
29467
|
-
.shv-ico.k-site { color
|
|
29786
|
+
.shv-ico.k-site { color:var(--brand-teal); }
|
|
29468
29787
|
.shv-main { min-width:0; }
|
|
29469
29788
|
.shv-title { display:block; max-width:100%; font-weight:600; color:var(--fg); letter-spacing:-.01em;
|
|
29470
29789
|
overflow:hidden; text-overflow:ellipsis; white-space:nowrap; text-align:left; }
|
|
@@ -29491,8 +29810,8 @@ var styles_default = ` :root {
|
|
|
29491
29810
|
font-variant-numeric:tabular-nums; white-space:nowrap; }
|
|
29492
29811
|
.shv-dot { width:8px; height:8px; border-radius:50%; background:var(--muted); flex:none; }
|
|
29493
29812
|
.shv-status.tone-ok .shv-dot { background:var(--success); }
|
|
29494
|
-
.shv-status.tone-warn { color:var(--warning
|
|
29495
|
-
.shv-status.tone-warn .shv-dot { background:var(--warning
|
|
29813
|
+
.shv-status.tone-warn { color:var(--warning); }
|
|
29814
|
+
.shv-status.tone-warn .shv-dot { background:var(--warning); }
|
|
29496
29815
|
.shv-status.tone-muted { color:var(--muted); }
|
|
29497
29816
|
.shv-status.tone-muted .shv-dot { background:transparent; border:1.5px solid var(--line-strong); }
|
|
29498
29817
|
.shv-status .sync-ring { width:10px; height:10px; }
|
|
@@ -29577,6 +29896,73 @@ var styles_default = ` :root {
|
|
|
29577
29896
|
.shv-group-head .btn { margin-left:0; width:100%; justify-content:center; padding:7px 10px; }
|
|
29578
29897
|
}
|
|
29579
29898
|
|
|
29899
|
+
/* Share workspace: quiet Notion-like controls and aligned document rows. */
|
|
29900
|
+
.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; }
|
|
29901
|
+
.shares-page .db-head { margin-bottom:28px; }
|
|
29902
|
+
.shares-page .db-title { display:flex; align-items:center; gap:14px; margin:0; font-size:32px; line-height:1.35; }
|
|
29903
|
+
.shares-page .db-title > .ico { width:27px; height:27px; flex:none; }
|
|
29904
|
+
.shares-page .db-desc { max-width:none; margin-top:12px; line-height:1.7; }
|
|
29905
|
+
.shv-toolbar { margin-bottom:20px; padding:8px 0; }
|
|
29906
|
+
.shv-tools-right { display:flex; width:100%; gap:24px; margin:0; }
|
|
29907
|
+
.shv-seg { gap:8px; border:0; padding:0; background:none; flex:none; }
|
|
29908
|
+
.shv-seg-btn { min-height:34px; padding:7px 12px; border-radius:6px; gap:3px; transition:background .15s; }
|
|
29909
|
+
.shv-seg-btn:hover { background:var(--shv-quiet); }
|
|
29910
|
+
.shv-seg-btn.active { background:color-mix(in srgb,var(--fg) 6%,var(--bg)); box-shadow:none; }
|
|
29911
|
+
.shv-seg-btn .n { font-family:inherit; min-width:1ch; color:var(--fg-soft); }
|
|
29912
|
+
.shv-search { margin-left:auto; max-width:300px; padding:8px 12px; background:var(--shv-quiet); border:1px solid transparent; border-radius:7px; }
|
|
29913
|
+
.shv-search input::placeholder { color:var(--fg-soft); }
|
|
29914
|
+
.shv-search:focus-within { border-color:var(--accent); }
|
|
29915
|
+
.shv-src.btn { background:none; border-color:transparent; box-shadow:none; padding:7px 4px; white-space:nowrap; }
|
|
29916
|
+
.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; }
|
|
29917
|
+
.shv-list { gap:0; }
|
|
29918
|
+
.shv-list[hidden] { display:none; }
|
|
29919
|
+
.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; }
|
|
29920
|
+
.shv-row:hover { background:color-mix(in srgb,var(--fg) 2%,var(--bg)); box-shadow:none; border-color:var(--shv-rule); }
|
|
29921
|
+
.shv-ico, .shv-ico.k-doc, .shv-ico.k-site { width:28px; height:32px; border-radius:0; background:none; color:var(--fg-soft); }
|
|
29922
|
+
.shv-ico svg { width:24px; height:24px; stroke-width:1.5; }
|
|
29923
|
+
.shv-title { font-size:15px; font-weight:550; line-height:1.5; }
|
|
29924
|
+
.shv-sub { margin-top:5px; font-size:12px; color:var(--fg-soft); }
|
|
29925
|
+
.shv-status { justify-self:start; min-width:0; padding:5px 8px; gap:6px; border-radius:5px; font-size:12px; }
|
|
29926
|
+
.shv-status .ico { width:14px; height:14px; flex:none; }
|
|
29927
|
+
.shv-status.tone-ok { color:var(--success); background:color-mix(in srgb,var(--success) 8%,var(--bg)); }
|
|
29928
|
+
.shv-status.tone-warn { background:color-mix(in srgb,var(--warning) 8%,var(--bg)); }
|
|
29929
|
+
.shv-status.tone-muted { background:var(--shv-quiet); color:var(--fg-soft); }
|
|
29930
|
+
.shv-actions { justify-content:space-between; gap:12px; }
|
|
29931
|
+
.shv-actions .btn { min-height:30px; min-width:88px; border-radius:6px; }
|
|
29932
|
+
.shv-actions .shv-copy { background:none; border-color:transparent; box-shadow:none; }
|
|
29933
|
+
.shv-actions .ico { width:15px; height:15px; }
|
|
29934
|
+
.shv-group-head { margin:16px 0; font-weight:400; }
|
|
29935
|
+
.shv-group-toggle { display:flex; align-items:center; gap:10px; padding:6px; color:var(--fg); border-radius:6px; }
|
|
29936
|
+
.shv-group-toggle:hover { background:var(--shv-quiet); }
|
|
29937
|
+
.shv-group-toggle .ico { width:14px; height:14px; color:var(--fg-soft); }
|
|
29938
|
+
.shv-group-head .n { font-family:inherit; background:var(--shv-quiet); padding:2px 7px; border-radius:5px; color:var(--fg-soft); }
|
|
29939
|
+
.shv-group-head .btn { background:none; border-color:transparent; box-shadow:none; color:var(--fg-soft); }
|
|
29940
|
+
.shares-page button:focus-visible { outline:2px solid var(--accent); outline-offset:3px; }
|
|
29941
|
+
@container (max-width:850px) {
|
|
29942
|
+
.shv-tools-right { flex-wrap:wrap; gap:12px; }
|
|
29943
|
+
.shv-seg { width:100%; }
|
|
29944
|
+
.shv-search { margin-left:0; max-width:none; }
|
|
29945
|
+
.shv-columns { grid-template-columns:minmax(0,1fr) 145px 124px; gap:12px; }
|
|
29946
|
+
.shv-row { grid-template-columns:24px minmax(0,1fr) 145px 124px; gap:12px; }
|
|
29947
|
+
}
|
|
29948
|
+
@container (max-width:600px) {
|
|
29949
|
+
.shv-columns { display:none; }
|
|
29950
|
+
.shv-seg { gap:3px; }
|
|
29951
|
+
.shv-seg-btn { flex:1; min-width:0; justify-content:center; padding:8px 3px; font-size:12px; gap:2px; }
|
|
29952
|
+
.shv-seg-btn .n { margin-left:2px; font-size:11px; }
|
|
29953
|
+
.shv-src { flex:none; }
|
|
29954
|
+
.shv-toolbar { margin-bottom:8px; }
|
|
29955
|
+
.shv-row { grid-template-columns:24px minmax(0,1fr); padding:18px 4px; }
|
|
29956
|
+
.shv-title { white-space:normal; display:block; overflow-wrap:anywhere; }
|
|
29957
|
+
.shv-sub { flex-wrap:wrap; white-space:normal; overflow-wrap:anywhere; }
|
|
29958
|
+
.shv-sub > * { flex-shrink:1; min-width:0; }
|
|
29959
|
+
.shv-status { grid-column:2; }
|
|
29960
|
+
.shv-actions { grid-column:2; justify-content:flex-start; }
|
|
29961
|
+
.shv-actions .btn { flex:none; min-height:36px; }
|
|
29962
|
+
.shv-actions .iconbtn { margin-left:auto; }
|
|
29963
|
+
.shv-group-head .btn { width:auto; margin-left:auto; }
|
|
29964
|
+
}
|
|
29965
|
+
|
|
29580
29966
|
/* in-context "\u5DF2\u5206\u4EAB" badge on docs / tables / site cards */
|
|
29581
29967
|
.share-badge { display:inline-grid; place-items:center; width:22px; height:22px; border-radius:6px; color:var(--accent);
|
|
29582
29968
|
background:var(--accent-soft); flex:none; cursor:pointer; transition:filter .12s; }
|
|
@@ -29713,7 +30099,7 @@ var styles_default = ` :root {
|
|
|
29713
30099
|
.selbar .cnt { font-size:13px; font-weight:600; margin-right:6px; }
|
|
29714
30100
|
.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; }
|
|
29715
30101
|
.selbar button:hover { background:var(--hover-2); color:var(--fg); }
|
|
29716
|
-
.selbar .del:hover { background:var(--danger); color
|
|
30102
|
+
.selbar .del:hover { background:var(--danger); color:var(--danger-fg); }
|
|
29717
30103
|
|
|
29718
30104
|
/* record peek */
|
|
29719
30105
|
.scrim { position:fixed; inset:0; background:rgba(15,15,25,.32); z-index:70; opacity:0; pointer-events:none; transition:opacity .22s; }
|
|
@@ -30042,14 +30428,22 @@ var styles_default = ` :root {
|
|
|
30042
30428
|
.tmpl .tt { font-weight:600; font-size:var(--fs-ui); } .tmpl .td { font-size:var(--fs-xs); color:var(--muted); margin-top:2px; }
|
|
30043
30429
|
|
|
30044
30430
|
/* toast */
|
|
30045
|
-
.toasts { position:fixed; bottom:20px; left:20px; z-index:110; display:flex; flex-direction:column; gap:8px; }
|
|
30046
|
-
.toast { background:var(--fg); color:var(--bg); padding:10px 14px; border-radius:9px; font-size:13px; box-shadow:var(--shadow-lg);
|
|
30431
|
+
.toasts { position:fixed; bottom:20px; left:20px; max-width:calc(100vw - 40px); z-index:110; display:flex; flex-direction:column; gap:8px; }
|
|
30432
|
+
.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);
|
|
30047
30433
|
display:flex; align-items:center; gap:8px; animation:slidein .2s ease; }
|
|
30048
30434
|
@keyframes slidein { from { opacity:0; transform:translateX(-12px); } }
|
|
30049
|
-
.toast.error { background:var(--danger); color
|
|
30435
|
+
.toast.error { background:var(--danger); color:var(--danger-fg); }
|
|
30050
30436
|
.toast.leaving { animation:toast-out .16s ease-in forwards; pointer-events:none; }
|
|
30051
30437
|
@keyframes toast-out { to { opacity:0; transform:translateX(-8px); } }
|
|
30052
|
-
.toast-msg { min-width:0; }
|
|
30438
|
+
.toast-msg { min-width:0; overflow-wrap:anywhere; }
|
|
30439
|
+
.toast > .ico, .toast-act { flex-shrink:0; }
|
|
30440
|
+
.toast.dragging { animation:none; transition:none; cursor:grabbing; }
|
|
30441
|
+
.toast.leaving.swipe-out { animation:none; transition:transform .16s ease-in, opacity .16s ease-in; }
|
|
30442
|
+
.toast-act:focus-visible { outline:2px solid currentColor; outline-offset:2px; }
|
|
30443
|
+
@media (prefers-reduced-motion:reduce) {
|
|
30444
|
+
.toast, .toast.dragging, .toast.leaving, .toast.leaving.swipe-out { animation:none; transition:none; transform:none; }
|
|
30445
|
+
.toast.leaving { opacity:0; }
|
|
30446
|
+
}
|
|
30053
30447
|
.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; }
|
|
30054
30448
|
.toast-act:hover { background:color-mix(in srgb, var(--bg) 28%, transparent); }
|
|
30055
30449
|
|
|
@@ -30132,6 +30526,93 @@ var styles_default = ` :root {
|
|
|
30132
30526
|
.doc-skel { max-width:720px; margin:40px auto; padding:0 24px; }
|
|
30133
30527
|
|
|
30134
30528
|
/* share / publish modal (share-modal.tsx) */
|
|
30529
|
+
/* Hosting-first object sharing: compact link rows and disclosed details. */
|
|
30530
|
+
.modal:has(.share-dialog) { border-radius:12px; }
|
|
30531
|
+
.modal:has(.share-dialog) .modal-head { position:relative; display:flex; align-items:baseline; gap:12px; padding:24px 56px 0 28px; min-width:0; }
|
|
30532
|
+
.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%; }
|
|
30533
|
+
.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; }
|
|
30534
|
+
.modal-close { position:absolute; right:16px; top:18px; color:var(--muted); }
|
|
30535
|
+
.modal:has(.share-dialog) .modal-body { padding:22px 28px 16px; }
|
|
30536
|
+
.modal:has(.share-dialog) .modal-foot { background:var(--bg); padding:12px 28px; justify-content:space-between; gap:12px; }
|
|
30537
|
+
.modal:has(.share-dialog) .modal-foot .btn { min-height:36px; font-weight:500; box-shadow:none; }
|
|
30538
|
+
.share-dialog { display:flex; flex-direction:column; gap:20px; font-size:var(--fs-ui); }
|
|
30539
|
+
.share-host { padding-bottom:20px; border-bottom:1px solid var(--line); }
|
|
30540
|
+
.share-host-label { display:block; margin-bottom:10px; color:var(--muted); font-size:var(--fs-sm); }
|
|
30541
|
+
.share-host-control { display:flex; align-items:center; gap:10px; min-width:0; }
|
|
30542
|
+
.share-host-control > .ico { width:20px; height:20px; color:var(--fg-soft); }
|
|
30543
|
+
.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; }
|
|
30544
|
+
.share-host-behavior { margin:12px 0 0 30px; }
|
|
30545
|
+
.share-host-behavior strong { color:var(--fg-soft); font-size:var(--fs-sm); font-weight:500; }
|
|
30546
|
+
.share-host-behavior p { margin:5px 0 0; color:var(--muted); font-size:var(--fs-sm); line-height:1.65; }
|
|
30547
|
+
.share-list-heading { display:flex; align-items:center; gap:8px; color:var(--muted); font-size:var(--fs-sm); padding-bottom:8px; }
|
|
30548
|
+
.share-link-list { list-style:none; padding:0; margin:0; }
|
|
30549
|
+
.share-link-list > li + li { border-top:1px solid var(--line); }
|
|
30550
|
+
.share-link-row { display:flex; align-items:center; gap:12px; padding:16px 0; }
|
|
30551
|
+
.share-link-row > .ico { flex:none; width:20px; height:20px; color:var(--fg-soft); }
|
|
30552
|
+
.share-link-info { flex:1; min-width:0; }
|
|
30553
|
+
.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); }
|
|
30554
|
+
.share-link-name > span { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
30555
|
+
.share-link-name > .ico { flex:none; color:var(--muted); width:12px; }
|
|
30556
|
+
.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; }
|
|
30557
|
+
.share-link-meta > span { white-space:nowrap; }
|
|
30558
|
+
.share-link-meta > span + span::before { content:"\xB7"; margin-right:8px; }
|
|
30559
|
+
.share-link-actions { display:flex; align-items:center; gap:6px; flex:none; }
|
|
30560
|
+
.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; }
|
|
30561
|
+
.share-link-actions .iconbtn { width:32px; height:32px; color:var(--muted); }
|
|
30562
|
+
.share-link-detail { margin:0 0 16px 32px; }
|
|
30563
|
+
.share-link-detail > p, .share-link-warning { margin:0 0 12px; color:var(--muted); font-size:var(--fs-sm); line-height:1.65; }
|
|
30564
|
+
.share-link-warning { margin:4px 0 0; }
|
|
30565
|
+
.share-link-name:hover { background:var(--hover); }
|
|
30566
|
+
.share-link-name:focus-visible, .share-secondary:focus-visible { outline:2px solid var(--accent); outline-offset:3px; }
|
|
30567
|
+
@media (max-width:560px) {
|
|
30568
|
+
.share-link-row { flex-wrap:wrap; gap:8px; }
|
|
30569
|
+
.share-link-info { flex-basis:calc(100% - 32px); }
|
|
30570
|
+
.share-link-actions { margin-left:28px; }
|
|
30571
|
+
.share-link-actions .btn, .share-link-actions .iconbtn { min-height:40px; }
|
|
30572
|
+
}
|
|
30573
|
+
.share-facts { margin:0; display:flex; flex-direction:column; gap:12px; }
|
|
30574
|
+
.share-facts > div { display:flex; gap:20px; align-items:baseline; }
|
|
30575
|
+
.share-facts dt { flex:0 0 88px; color:var(--muted); font-size:var(--fs-sm); }
|
|
30576
|
+
.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; }
|
|
30577
|
+
.share-explanation { margin:-6px 0 0; font-size:var(--fs-sm); line-height:1.7; color:var(--muted); }
|
|
30578
|
+
.share-details { color:var(--fg-soft); font-size:var(--fs-sm); }
|
|
30579
|
+
.share-details summary { cursor:pointer; padding:4px 0; line-height:1.5; }
|
|
30580
|
+
.share-details summary:hover { color:var(--fg); }
|
|
30581
|
+
.share-details summary:focus-visible { outline:2px solid var(--accent); outline-offset:4px; border-radius:2px; }
|
|
30582
|
+
.share-details summary::marker { color:var(--muted); font-size:10px; }
|
|
30583
|
+
.share-details summary > span { margin-left:10px; color:var(--muted); font-size:var(--fs-xs); }
|
|
30584
|
+
.share-details > div, .share-details > dl { margin-top:16px; }
|
|
30585
|
+
.share-secondary { display:inline-flex; align-items:center; gap:6px; color:var(--muted); font-size:var(--fs-sm); border-radius:var(--radius-sm); }
|
|
30586
|
+
.share-secondary { padding:6px 0; }
|
|
30587
|
+
.share-secondary:hover { color:var(--fg); }
|
|
30588
|
+
.share-dialog button:disabled, .modal:has(.share-dialog) .modal-foot button:disabled { cursor:default; opacity:.5; }
|
|
30589
|
+
.share-settings { display:flex; flex-direction:column; gap:8px; }
|
|
30590
|
+
.share-setting { display:flex; align-items:center; gap:16px; min-height:38px; }
|
|
30591
|
+
.share-setting > span { flex:0 0 90px; color:var(--fg-soft); font-size:var(--fs-sm); }
|
|
30592
|
+
.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); }
|
|
30593
|
+
.share-setting select:disabled { color:var(--muted); background:var(--surface); opacity:1; }
|
|
30594
|
+
.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); }
|
|
30595
|
+
.share-setting input::placeholder { color:var(--muted); }
|
|
30596
|
+
.share-setting input:focus-visible, .share-url:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
|
|
30597
|
+
.share-dialog > .share-details { border-top:1px solid var(--line); padding-top:12px; }
|
|
30598
|
+
.share-url { display:block; width:100%; margin-top:12px; }
|
|
30599
|
+
.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; }
|
|
30600
|
+
.share-message.error { color:var(--danger); background:var(--danger-soft); }
|
|
30601
|
+
.share-load-error p { margin-top:0; color:var(--muted); }
|
|
30602
|
+
.share-loading { display:grid; gap:14px; padding:4px 0; }
|
|
30603
|
+
.share-loading span { height:14px; background:var(--surface-2); border-radius:3px; }
|
|
30604
|
+
.share-loading span:first-child { width:55%; }
|
|
30605
|
+
.share-loading span:last-child { width:75%; }
|
|
30606
|
+
.share-sr-status { position:absolute; width:1px; height:1px; padding:0; overflow:hidden; clip-path:inset(50%); white-space:nowrap; }
|
|
30607
|
+
@media (max-width:560px) {
|
|
30608
|
+
.modal:has(.share-dialog) .modal-head { padding:22px 52px 0 20px; gap:10px; }
|
|
30609
|
+
.modal:has(.share-dialog) .modal-body { padding:20px 20px 12px; }
|
|
30610
|
+
.modal:has(.share-dialog) .modal-foot { padding:14px 20px; flex-wrap:wrap; }
|
|
30611
|
+
.modal:has(.share-dialog) .modal-foot .btn, .share-secondary { min-height:40px; }
|
|
30612
|
+
.share-setting { gap:12px; }
|
|
30613
|
+
.share-setting > span { flex-basis:80px; }
|
|
30614
|
+
.share-setting select, .share-setting input { min-height:40px; }
|
|
30615
|
+
}
|
|
30135
30616
|
.mhshare-body { display:flex; flex-direction:column; gap:10px; }
|
|
30136
30617
|
.mhshare-section { font-size:var(--fs-micro); font-weight:600; color:var(--muted); text-transform:uppercase; letter-spacing:.05em; margin-top:6px; }
|
|
30137
30618
|
.mhshare-field { display:flex; align-items:center; gap:12px; }
|
|
@@ -30709,22 +31190,31 @@ var styles_default = ` :root {
|
|
|
30709
31190
|
/* File-editor window (desktop, loaded at #file?path=\u2026 \u2014 the .txt/.md "open
|
|
30710
31191
|
with" surface). Same shell idiom as quicknote: top bar = drag region with
|
|
30711
31192
|
opted-out buttons, single full-bleed column, popups clamped below the bar. */
|
|
30712
|
-
body.file-window { --pop-top-inset:
|
|
31193
|
+
body.file-window { --pop-top-inset:48px; }
|
|
30713
31194
|
body.file-window #app { display:block; width:100vw; height:100vh; height:100dvh; }
|
|
30714
31195
|
.fw { display:flex; flex-direction:column; width:100%; height:100vh; height:100dvh; overflow:hidden; background:var(--bg); }
|
|
30715
|
-
.fw-bar { display:flex; align-items:center; gap:
|
|
31196
|
+
.fw-bar { display:flex; align-items:center; gap:12px; padding:0 16px; height:48px; flex:none;
|
|
30716
31197
|
user-select:none; -webkit-app-region:drag;
|
|
30717
31198
|
background:var(--surface); border-bottom:1px solid var(--line); }
|
|
30718
31199
|
/* macOS only: clear the inset traffic lights (frame is native elsewhere). */
|
|
30719
|
-
body.desktop-mac .fw-bar { padding-left:
|
|
30720
|
-
.fw-
|
|
31200
|
+
body.desktop-mac .fw-bar { padding-left:88px; }
|
|
31201
|
+
.fw-title { display:flex; align-items:center; gap:8px; flex:1; min-width:0; color:var(--muted); }
|
|
31202
|
+
.fw-name { min-width:0; font-size:var(--fs-sm); font-weight:500; color:var(--fg-soft);
|
|
30721
31203
|
white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
|
30722
|
-
.fw-dirty {
|
|
30723
|
-
.fw-
|
|
30724
|
-
.fw-
|
|
31204
|
+
.fw-dirty { width:6px; height:6px; flex:none; border-radius:50%; background:var(--accent); }
|
|
31205
|
+
.fw-status { display:flex; align-items:center; gap:6px; flex:none; color:var(--muted); font-size:var(--fs-xs); white-space:nowrap; }
|
|
31206
|
+
.fw-status:not(.is-dirty) .ico { color:var(--success); }
|
|
31207
|
+
.fw-actions { display:flex; align-items:center; gap:6px; flex:none; -webkit-app-region:no-drag; }
|
|
31208
|
+
.fw-actions .btn { min-height:30px; font-size:var(--fs-sm); }
|
|
31209
|
+
.fw-body .doc { padding-top:64px; padding-bottom:24vh; }
|
|
30725
31210
|
.fw-body { flex:1; overflow:auto; scrollbar-gutter:stable; scrollbar-width:thin; -webkit-app-region:no-drag; }
|
|
30726
|
-
|
|
30727
|
-
|
|
31211
|
+
body.file-window .find-bar { top:54px; }
|
|
31212
|
+
@media (max-width:720px) {
|
|
31213
|
+
.fw-bar { gap:8px; padding-right:12px; padding-left:12px; }
|
|
31214
|
+
.fw-status span, .fw-mode span, .fw-open span { display:none; }
|
|
31215
|
+
.fw-mode, .fw-open { width:30px; padding:0; justify-content:center; }
|
|
31216
|
+
.fw-body .doc { padding:36px 32px 24vh; }
|
|
31217
|
+
}
|
|
30728
31218
|
|
|
30729
31219
|
/* No-origin bootstrap: enroll screen + hydration splash (data-blind shell). */
|
|
30730
31220
|
.enroll-splash { min-height:100dvh; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:14px; padding:24px; }
|
|
@@ -30949,6 +31439,37 @@ var styles_default = ` :root {
|
|
|
30949
31439
|
.blob-mgr-row { grid-template-columns:26px 30px minmax(0,1fr) auto auto 28px; }
|
|
30950
31440
|
.blob-mgr-age { display:none; }
|
|
30951
31441
|
}
|
|
31442
|
+
|
|
31443
|
+
/* Standalone library document: the same editor, with a compact native shell. */
|
|
31444
|
+
.document-window { min-width:0; height:100dvh; }
|
|
31445
|
+
.document-window .dw-toolbar { padding:0 16px; height:48px; min-height:48px; flex:none;
|
|
31446
|
+
flex-wrap:nowrap; gap:12px; background:var(--surface); -webkit-app-region:drag; }
|
|
31447
|
+
body.desktop-mac .document-window .dw-toolbar { padding-left:88px; }
|
|
31448
|
+
.document-window .dw-toolbar button { -webkit-app-region:no-drag; }
|
|
31449
|
+
.dw-toolbar > button, .dw-toolbar .crumb > .ico { flex:none; }
|
|
31450
|
+
.dw-toolbar .crumb { min-width:0; color:var(--muted); font-size:var(--fs-sm); }
|
|
31451
|
+
.dw-path { display:flex; align-items:center; gap:8px; min-width:0; }
|
|
31452
|
+
.dw-path .crumb-link { max-width:160px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
31453
|
+
.dw-current { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--fg-soft); }
|
|
31454
|
+
.dw-save { display:flex; align-items:center; gap:6px; flex:none; font-size:var(--fs-xs); color:var(--muted);
|
|
31455
|
+
padding:6px 4px; border-radius:var(--radius-sm); }
|
|
31456
|
+
.dw-save:not(:disabled):hover { background:var(--hover); }
|
|
31457
|
+
.dw-save-saved .ico { color:var(--success); }
|
|
31458
|
+
.dw-save-error, .dw-save-conflict { color:var(--danger); }
|
|
31459
|
+
.dw-content .doc { padding-top:64px; padding-bottom:24vh; }
|
|
31460
|
+
.dw-content .doc-title { overflow-wrap:anywhere; }
|
|
31461
|
+
.dw-footer { display:flex; align-items:center; height:30px; flex:none; padding:0 18px;
|
|
31462
|
+
border-top:1px solid var(--line); color:var(--muted); font-size:var(--fs-xs); }
|
|
31463
|
+
.document-window .doc-wc { bottom:5px; right:16px; border:0; box-shadow:none; background:transparent; }
|
|
31464
|
+
.document-window .doc-toc { top:72px; }
|
|
31465
|
+
.document-window .find-bar { top:54px; }
|
|
31466
|
+
@media (max-width:720px) {
|
|
31467
|
+
.dw-save span { display:none; }
|
|
31468
|
+
.dw-path { display:none; }
|
|
31469
|
+
.document-window .dw-toolbar { gap:8px; padding:0 12px; }
|
|
31470
|
+
.dw-content .doc { padding:36px 32px 24vh; }
|
|
31471
|
+
.dw-content .doc-title { font-size:32px; }
|
|
31472
|
+
}
|
|
30952
31473
|
`;
|
|
30953
31474
|
|
|
30954
31475
|
// src/webui/server/icons.ts
|
|
@@ -31007,7 +31528,7 @@ var HTML2 = `<!doctype html>
|
|
|
31007
31528
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
31008
31529
|
<!-- Mobile browser chrome (status/address bar) tints to theme-color; app.tsx
|
|
31009
31530
|
keeps #theme-color-meta in sync with the active theme + visible surface. -->
|
|
31010
|
-
<meta name="theme-color" id="theme-color-meta" content="
|
|
31531
|
+
<meta name="theme-color" id="theme-color-meta" content="${LIGHT_THEME.bg}" />
|
|
31011
31532
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
31012
31533
|
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
|
31013
31534
|
<title>Metahub</title>
|
|
@@ -31022,9 +31543,10 @@ var HTML2 = `<!doctype html>
|
|
|
31022
31543
|
<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>
|
|
31023
31544
|
<!-- FOUC guard: resolve the stored choice (system \u2192 OS preference) to an
|
|
31024
31545
|
explicit data-resolved before first paint. CSS keys off data-resolved
|
|
31025
|
-
alone, so the dark palette exists exactly once \u2014 see
|
|
31546
|
+
alone, so the dark palette exists exactly once \u2014 see core/ui-theme.ts. Dark also
|
|
31026
31547
|
pre-tints the status bar (hex mirrors --bg) so the first frame isn't white. -->
|
|
31027
|
-
<
|
|
31548
|
+
<style>${THEME_CSS}html,body{background:var(--bg);color:var(--fg)}</style>
|
|
31549
|
+
<script>${THEME_INIT_SCRIPT}</script>
|
|
31028
31550
|
<!-- Same for the UI language: mirror src/webui/i18n/locale.ts so <html lang>
|
|
31029
31551
|
is right before the bundle runs. -->
|
|
31030
31552
|
<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>
|
|
@@ -31132,9 +31654,9 @@ var getRuntime = bundleGetter({ key: "runtime", entry: "../runtime.ts", dist: "m
|
|
|
31132
31654
|
var getSdk = bundleGetter({ key: "sdk", entry: "../../sdk/client.ts", dist: "metahub-sdk.js", extraDirs: ["../../sdk"] });
|
|
31133
31655
|
async function getCss() {
|
|
31134
31656
|
if (RUNNING_FROM_SOURCE2) {
|
|
31135
|
-
return Bun.file(fileURLToPath2(new URL("../styles.css", import.meta.url))).text();
|
|
31657
|
+
return THEME_CSS + await Bun.file(fileURLToPath2(new URL("../styles.css", import.meta.url))).text();
|
|
31136
31658
|
}
|
|
31137
|
-
return styles_default;
|
|
31659
|
+
return THEME_CSS + styles_default;
|
|
31138
31660
|
}
|
|
31139
31661
|
async function getJsStamped() {
|
|
31140
31662
|
return (await getJs()).replaceAll("__MH_WEBUI_VERSION__", package_default.version);
|
|
@@ -31164,8 +31686,8 @@ var MANIFEST = JSON.stringify({
|
|
|
31164
31686
|
start_url: "/",
|
|
31165
31687
|
scope: "/",
|
|
31166
31688
|
display: "standalone",
|
|
31167
|
-
background_color:
|
|
31168
|
-
theme_color:
|
|
31689
|
+
background_color: LIGHT_THEME.bg,
|
|
31690
|
+
theme_color: LIGHT_THEME.bg,
|
|
31169
31691
|
icons: [
|
|
31170
31692
|
{ src: "/icons/icon-192.png", sizes: "192x192", type: "image/png" },
|
|
31171
31693
|
{ src: "/icons/icon-512.png", sizes: "512x512", type: "image/png" }
|
|
@@ -33887,4 +34409,4 @@ if (scopedConfigHelp) {
|
|
|
33887
34409
|
runMain(main, { showUsage: showUsage2 });
|
|
33888
34410
|
}
|
|
33889
34411
|
|
|
33890
|
-
//# debugId=
|
|
34412
|
+
//# debugId=D3711020F39376D264756E2164756E21
|