@tensorix/metahub 0.2.2 → 0.3.1
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 +1195 -267
- package/dist/cli.js.map +19 -15
- package/dist/core/databases.d.ts +5 -1
- package/dist/core/databases.d.ts.map +1 -1
- package/dist/core/documents.d.ts +19 -0
- package/dist/core/documents.d.ts.map +1 -1
- package/dist/core/md/grammar.d.ts +40 -0
- package/dist/core/md/grammar.d.ts.map +1 -0
- package/dist/core/md/heal.d.ts +2 -0
- package/dist/core/md/heal.d.ts.map +1 -0
- package/dist/core/md/inline.d.ts +20 -0
- package/dist/core/md/inline.d.ts.map +1 -0
- package/dist/core/schema-init.d.ts +13 -0
- package/dist/core/schema-init.d.ts.map +1 -1
- package/dist/core/schema.d.ts +1 -1
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/sync/auth.d.ts +3 -1
- package/dist/core/sync/auth.d.ts.map +1 -1
- package/dist/core/sync/share-render.d.ts +3 -1
- package/dist/core/sync/share-render.d.ts.map +1 -1
- package/dist/db-worker.js +51 -41
- package/dist/index.js +1094 -254
- package/dist/index.js.map +15 -11
- package/dist/mh-runtime.js +1 -1
- package/dist/sw.js +1 -1
- package/dist/webui/fmt/manifest.d.ts +17 -0
- package/dist/webui/fmt/manifest.d.ts.map +1 -0
- package/dist/webui/server/assets.d.ts +5 -0
- package/dist/webui/server/assets.d.ts.map +1 -1
- package/dist/webui-fmt-clang.js +1 -0
- package/dist/webui-fmt-clang.wasm +0 -0
- package/dist/webui-fmt-gofmt.js +1 -0
- package/dist/webui-fmt-gofmt.wasm +0 -0
- package/dist/webui-fmt-lua.js +2 -0
- package/dist/webui-fmt-lua.wasm +0 -0
- package/dist/webui-fmt-ruff.js +2 -0
- package/dist/webui-fmt-ruff.wasm +0 -0
- package/dist/webui-fmt-sh.js +8 -0
- package/dist/webui-fmt-taplo.js +2 -0
- package/dist/webui-fmt-taplo.wasm +0 -0
- package/dist/webui-fmt.js +425 -0
- package/dist/webui.js +148 -75
- package/package.json +15 -1
package/dist/cli.js
CHANGED
|
@@ -1443,7 +1443,7 @@ var init_crdt = __esm(() => {
|
|
|
1443
1443
|
DOMAIN = {
|
|
1444
1444
|
databases: {
|
|
1445
1445
|
table: "databases",
|
|
1446
|
-
cols: new Set(["name", "icon", "created_hlc", "__deleted"])
|
|
1446
|
+
cols: new Set(["name", "icon", "meta", "created_hlc", "__deleted"])
|
|
1447
1447
|
},
|
|
1448
1448
|
properties: {
|
|
1449
1449
|
table: "properties",
|
|
@@ -2283,11 +2283,17 @@ var init_properties = __esm(() => {
|
|
|
2283
2283
|
});
|
|
2284
2284
|
|
|
2285
2285
|
// src/core/databases.ts
|
|
2286
|
+
function rowOut(r3) {
|
|
2287
|
+
if (!r3)
|
|
2288
|
+
return null;
|
|
2289
|
+
return { ...r3, meta: r3.meta === null ? null : JSON.parse(r3.meta) };
|
|
2290
|
+
}
|
|
2286
2291
|
function getDatabase(db, id) {
|
|
2287
|
-
return db.query(`SELECT ${DATABASE_SELECT} FROM databases WHERE id = ? AND __deleted = 0`).get(id);
|
|
2292
|
+
return rowOut(db.query(`SELECT ${DATABASE_SELECT} FROM databases WHERE id = ? AND __deleted = 0`).get(id));
|
|
2288
2293
|
}
|
|
2289
2294
|
function listDatabases(db) {
|
|
2290
|
-
|
|
2295
|
+
const rows = db.query(`SELECT ${DATABASE_SELECT} FROM databases WHERE __deleted = 0 ORDER BY created_hlc`).all();
|
|
2296
|
+
return rows.map((r3) => rowOut(r3));
|
|
2291
2297
|
}
|
|
2292
2298
|
function liveChildren(db, table, col, parentId) {
|
|
2293
2299
|
return db.query(`SELECT id FROM ${table} WHERE ${col} = ? AND __deleted = 0`).all(parentId).map((r3) => r3.id);
|
|
@@ -2299,7 +2305,7 @@ var init_databases = __esm(() => {
|
|
|
2299
2305
|
init_errors();
|
|
2300
2306
|
init_properties();
|
|
2301
2307
|
init_records();
|
|
2302
|
-
DATABASE_COLS = ["id", "name", "icon", "created_hlc"];
|
|
2308
|
+
DATABASE_COLS = ["id", "name", "icon", "meta", "created_hlc"];
|
|
2303
2309
|
DATABASE_SELECT = DATABASE_COLS.join(", ");
|
|
2304
2310
|
createDatabase = grouped(function createDatabase2(db, opts) {
|
|
2305
2311
|
const id = newId("db", opts.name);
|
|
@@ -2316,6 +2322,11 @@ var init_databases = __esm(() => {
|
|
|
2316
2322
|
emit(db, "databases", id, "name", fields.name);
|
|
2317
2323
|
if (fields.icon !== undefined)
|
|
2318
2324
|
emit(db, "databases", id, "icon", fields.icon);
|
|
2325
|
+
if (fields.meta !== undefined) {
|
|
2326
|
+
if (fields.meta !== null && (typeof fields.meta !== "object" || Array.isArray(fields.meta)))
|
|
2327
|
+
throw new MhError("invalid_input", "meta must be a JSON object or null");
|
|
2328
|
+
emit(db, "databases", id, "meta", fields.meta);
|
|
2329
|
+
}
|
|
2319
2330
|
return getDatabase(db, id);
|
|
2320
2331
|
});
|
|
2321
2332
|
duplicateDatabase = grouped(function duplicateDatabase2(db, id, opts = {}) {
|
|
@@ -2326,6 +2337,11 @@ var init_databases = __esm(() => {
|
|
|
2326
2337
|
name: opts.name ?? src2.name,
|
|
2327
2338
|
icon: opts.icon ?? src2.icon ?? undefined
|
|
2328
2339
|
});
|
|
2340
|
+
if (src2.meta !== null) {
|
|
2341
|
+
const { collapsed: _hidden, ...meta } = src2.meta;
|
|
2342
|
+
if (Object.keys(meta).length)
|
|
2343
|
+
emit(db, "databases", dup.id, "meta", meta);
|
|
2344
|
+
}
|
|
2329
2345
|
const propIdMap = new Map;
|
|
2330
2346
|
for (const p of listProperties(db, id)) {
|
|
2331
2347
|
const config = p.config?.database === id ? { ...p.config, database: dup.id } : p.config ?? undefined;
|
|
@@ -2966,7 +2982,7 @@ function countOccurrences(haystack, needle) {
|
|
|
2966
2982
|
}
|
|
2967
2983
|
return n2;
|
|
2968
2984
|
}
|
|
2969
|
-
var DOCUMENT_COLS, DOCUMENT_SELECT, DOC_SUMMARY_COLS, DOC_SUMMARY_SELECT, createDocument, ORDER_BY = "ORDER BY order_key IS NULL, order_key, created_hlc, id", backfillDocumentOrderKeys, moveDocument, duplicateDocument, updateDocument, editDocument, appendDocument, prependDocument, deleteDocument;
|
|
2985
|
+
var DOCUMENT_COLS, DOCUMENT_SELECT, DOC_SUMMARY_COLS, DOC_SUMMARY_SELECT, createDocument, ORDER_BY = "ORDER BY order_key IS NULL, order_key, created_hlc, id", backfillDocumentOrderKeys, moveDocument, duplicateDocument, updateDocument, editDocument, editDocumentBatch, appendDocument, prependDocument, deleteDocument;
|
|
2970
2986
|
var init_documents = __esm(() => {
|
|
2971
2987
|
init_ids();
|
|
2972
2988
|
init_crdt();
|
|
@@ -3096,6 +3112,33 @@ var init_documents = __esm(() => {
|
|
|
3096
3112
|
reconcileBody(db, id, newBody);
|
|
3097
3113
|
return { id, changed: newBody !== body, replaced: opts.replaceAll ? count : 1, version: documentVersion(db, id) };
|
|
3098
3114
|
});
|
|
3115
|
+
editDocumentBatch = grouped(function editDocumentBatch2(db, id, opts) {
|
|
3116
|
+
if (!getDocument(db, id))
|
|
3117
|
+
throw new MhError("not_found", `no such document: ${id}`);
|
|
3118
|
+
if (opts.edits.length === 0)
|
|
3119
|
+
throw new MhError("invalid_input", "no edits given");
|
|
3120
|
+
if (opts.ifMatch !== undefined && documentVersion(db, id) !== opts.ifMatch)
|
|
3121
|
+
throw new MhError("stale", `stale: document changed since ${opts.ifMatch}; re-read first`);
|
|
3122
|
+
ensureBlocks(db, id);
|
|
3123
|
+
const orig = serializeDocBlocks(liveBlocks(db, id).map((b2) => ({ text: b2.text, blankAfter: b2.blank_after })));
|
|
3124
|
+
let body = orig;
|
|
3125
|
+
let total = 0;
|
|
3126
|
+
opts.edits.forEach((e2, i2) => {
|
|
3127
|
+
if (e2.old === "")
|
|
3128
|
+
throw new MhError("invalid_input", `edit[${i2}]: old must not be empty`);
|
|
3129
|
+
const count = countOccurrences(body, e2.old);
|
|
3130
|
+
if (count === 0)
|
|
3131
|
+
throw new MhError("invalid_input", `edit[${i2}]: anchor not found: no match for old`);
|
|
3132
|
+
if (count > 1 && !e2.replaceAll)
|
|
3133
|
+
throw new MhError("ambiguous", `edit[${i2}]: ${count} matches for old; add surrounding context or set replaceAll`);
|
|
3134
|
+
const repl = e2.new ?? "";
|
|
3135
|
+
body = e2.replaceAll ? body.replaceAll(e2.old, repl) : body.replace(e2.old, repl);
|
|
3136
|
+
total += e2.replaceAll ? count : 1;
|
|
3137
|
+
});
|
|
3138
|
+
if (body !== orig)
|
|
3139
|
+
reconcileBody(db, id, body);
|
|
3140
|
+
return { id, changed: body !== orig, replaced: total, version: documentVersion(db, id) };
|
|
3141
|
+
});
|
|
3099
3142
|
appendDocument = grouped(function appendDocument2(db, id, body) {
|
|
3100
3143
|
if (!getDocument(db, id))
|
|
3101
3144
|
throw new MhError("not_found", `no such document: ${id}`);
|
|
@@ -19646,29 +19689,280 @@ var init_sites_serve = __esm(() => {
|
|
|
19646
19689
|
init_sites();
|
|
19647
19690
|
});
|
|
19648
19691
|
|
|
19692
|
+
// src/core/md/grammar.ts
|
|
19693
|
+
function matchQuoteLine(text) {
|
|
19694
|
+
const m3 = text.match(RE.quote);
|
|
19695
|
+
return m3 ? m3[1] : null;
|
|
19696
|
+
}
|
|
19697
|
+
function matchListLine(line, minIndent) {
|
|
19698
|
+
const indent = leadingIndent(line);
|
|
19699
|
+
if (indent < minIndent)
|
|
19700
|
+
return null;
|
|
19701
|
+
const text = stripIndent(line, indent);
|
|
19702
|
+
let m3 = text.match(/^[-*+]\s+\[([ xX])\][ \t](.*)$/);
|
|
19703
|
+
if (m3) {
|
|
19704
|
+
return {
|
|
19705
|
+
indent,
|
|
19706
|
+
type: "todo",
|
|
19707
|
+
checked: m3[1].toLowerCase() === "x",
|
|
19708
|
+
content: m3[2]
|
|
19709
|
+
};
|
|
19710
|
+
}
|
|
19711
|
+
m3 = text.match(/^(\d+)[.)][ \t]+(.*)$/);
|
|
19712
|
+
if (m3)
|
|
19713
|
+
return { indent, type: "numbered", content: m3[2], num: parseInt(m3[1], 10) };
|
|
19714
|
+
m3 = text.match(/^[-*+][ \t]+(.*)$/);
|
|
19715
|
+
if (m3)
|
|
19716
|
+
return { indent, type: "bullet", content: m3[1] };
|
|
19717
|
+
return null;
|
|
19718
|
+
}
|
|
19719
|
+
function leadingIndent(line) {
|
|
19720
|
+
let indent = 0;
|
|
19721
|
+
for (const ch of line) {
|
|
19722
|
+
if (ch === " ")
|
|
19723
|
+
indent++;
|
|
19724
|
+
else if (ch === "\t")
|
|
19725
|
+
indent += 4;
|
|
19726
|
+
else
|
|
19727
|
+
break;
|
|
19728
|
+
}
|
|
19729
|
+
return indent;
|
|
19730
|
+
}
|
|
19731
|
+
function stripIndent(line, columns) {
|
|
19732
|
+
let indent = 0;
|
|
19733
|
+
let i2 = 0;
|
|
19734
|
+
for (;i2 < line.length && indent < columns; i2++) {
|
|
19735
|
+
const ch = line[i2];
|
|
19736
|
+
if (ch === " ")
|
|
19737
|
+
indent++;
|
|
19738
|
+
else if (ch === "\t")
|
|
19739
|
+
indent += 4;
|
|
19740
|
+
else
|
|
19741
|
+
break;
|
|
19742
|
+
}
|
|
19743
|
+
return line.slice(i2);
|
|
19744
|
+
}
|
|
19745
|
+
function isFenceClose(line, char, len) {
|
|
19746
|
+
const trimmed = line.trim();
|
|
19747
|
+
if (!trimmed || trimmed[0] !== char)
|
|
19748
|
+
return false;
|
|
19749
|
+
for (const ch of trimmed) {
|
|
19750
|
+
if (ch !== char)
|
|
19751
|
+
return false;
|
|
19752
|
+
}
|
|
19753
|
+
return trimmed.length >= len;
|
|
19754
|
+
}
|
|
19755
|
+
function cleanLang(lang) {
|
|
19756
|
+
return lang.trim().replace(/[^A-Za-z0-9_+.#-]/g, "");
|
|
19757
|
+
}
|
|
19758
|
+
function looksLikeTableAt(lines, i2, minIndent) {
|
|
19759
|
+
const head = lines[i2];
|
|
19760
|
+
const delim = lines[i2 + 1];
|
|
19761
|
+
if (head == null || delim == null)
|
|
19762
|
+
return false;
|
|
19763
|
+
if (leadingIndent(head) < minIndent || leadingIndent(delim) < minIndent)
|
|
19764
|
+
return false;
|
|
19765
|
+
const headText = stripIndent(head, minIndent);
|
|
19766
|
+
const delimText = stripIndent(delim, minIndent);
|
|
19767
|
+
if (!headText.includes("|") || !delimText.includes("|"))
|
|
19768
|
+
return false;
|
|
19769
|
+
const cells = splitTableRow(delimText);
|
|
19770
|
+
return cells.length > 0 && cells.every((c3) => RE_DELIM_CELL.test(c3));
|
|
19771
|
+
}
|
|
19772
|
+
function splitTableRow(line) {
|
|
19773
|
+
const cells = [];
|
|
19774
|
+
let cur = "";
|
|
19775
|
+
for (let i2 = 0;i2 < line.length; i2++) {
|
|
19776
|
+
const ch = line[i2];
|
|
19777
|
+
if (ch === "\\" && line[i2 + 1] === "|") {
|
|
19778
|
+
cur += "|";
|
|
19779
|
+
i2++;
|
|
19780
|
+
continue;
|
|
19781
|
+
}
|
|
19782
|
+
if (ch === "|") {
|
|
19783
|
+
cells.push(cur);
|
|
19784
|
+
cur = "";
|
|
19785
|
+
continue;
|
|
19786
|
+
}
|
|
19787
|
+
cur += ch;
|
|
19788
|
+
}
|
|
19789
|
+
cells.push(cur);
|
|
19790
|
+
if (cells.length && cells[0].trim() === "")
|
|
19791
|
+
cells.shift();
|
|
19792
|
+
if (cells.length && cells[cells.length - 1].trim() === "")
|
|
19793
|
+
cells.pop();
|
|
19794
|
+
return cells.map((c3) => c3.trim());
|
|
19795
|
+
}
|
|
19796
|
+
var HTML_FENCE = "mh-html", RE, RE_DELIM_CELL;
|
|
19797
|
+
var init_grammar = __esm(() => {
|
|
19798
|
+
RE = {
|
|
19799
|
+
fenceOpen: /^\s*(`{3,}|~{3,})\s*([^\s`]*)?.*$/,
|
|
19800
|
+
h: /^(#{1,6})\s+(.*)$/,
|
|
19801
|
+
todo: /^\s*[-*+]\s+\[([ xX])\][ \t](.*)$/,
|
|
19802
|
+
bullet: /^\s*[-*+]\s+(.*)$/,
|
|
19803
|
+
numbered: /^\s*(\d+)[.)]\s+(.*)$/,
|
|
19804
|
+
quote: /^>[ \t](.*)$/,
|
|
19805
|
+
divider: /^\s*(?:-{3,}|\*{3,}|_{3,})\s*$/
|
|
19806
|
+
};
|
|
19807
|
+
RE_DELIM_CELL = /^\s*:?-+:?\s*$/;
|
|
19808
|
+
});
|
|
19809
|
+
|
|
19810
|
+
// src/core/md/inline.ts
|
|
19811
|
+
function tokenizeInline(text) {
|
|
19812
|
+
if (!text)
|
|
19813
|
+
return [];
|
|
19814
|
+
const cands = [];
|
|
19815
|
+
for (const p2 of PATTERNS) {
|
|
19816
|
+
p2.re.lastIndex = 0;
|
|
19817
|
+
let m3;
|
|
19818
|
+
while (m3 = p2.re.exec(text)) {
|
|
19819
|
+
const start = m3.index;
|
|
19820
|
+
const end = start + m3[0].length;
|
|
19821
|
+
let innerFrom;
|
|
19822
|
+
let innerTo;
|
|
19823
|
+
let url2;
|
|
19824
|
+
let alt;
|
|
19825
|
+
if (p2.kind === "link") {
|
|
19826
|
+
innerFrom = start + 1;
|
|
19827
|
+
innerTo = start + 1 + m3[1].length;
|
|
19828
|
+
url2 = m3[2];
|
|
19829
|
+
} else if (p2.kind === "image") {
|
|
19830
|
+
innerFrom = start + 2;
|
|
19831
|
+
innerTo = start + 2 + m3[1].length;
|
|
19832
|
+
url2 = m3[2];
|
|
19833
|
+
alt = m3[1];
|
|
19834
|
+
} else {
|
|
19835
|
+
innerFrom = start + p2.delim;
|
|
19836
|
+
innerTo = end - p2.delim;
|
|
19837
|
+
if (innerTo <= innerFrom)
|
|
19838
|
+
continue;
|
|
19839
|
+
}
|
|
19840
|
+
cands.push({ kind: p2.kind, start, end, innerFrom, innerTo, url: url2, alt, rank: p2.rank });
|
|
19841
|
+
}
|
|
19842
|
+
}
|
|
19843
|
+
cands.sort((a2, b3) => a2.start - b3.start || a2.rank - b3.rank || b3.end - a2.end);
|
|
19844
|
+
const out = [];
|
|
19845
|
+
let cursor = 0;
|
|
19846
|
+
for (const c3 of cands) {
|
|
19847
|
+
if (c3.start < cursor)
|
|
19848
|
+
continue;
|
|
19849
|
+
cursor = c3.end;
|
|
19850
|
+
out.push({
|
|
19851
|
+
kind: c3.kind,
|
|
19852
|
+
start: c3.start,
|
|
19853
|
+
end: c3.end,
|
|
19854
|
+
innerFrom: c3.innerFrom,
|
|
19855
|
+
innerTo: c3.innerTo,
|
|
19856
|
+
...c3.url !== undefined ? { url: c3.url } : {},
|
|
19857
|
+
...c3.alt !== undefined ? { alt: c3.alt } : {}
|
|
19858
|
+
});
|
|
19859
|
+
}
|
|
19860
|
+
return out;
|
|
19861
|
+
}
|
|
19862
|
+
var PATTERNS;
|
|
19863
|
+
var init_inline = __esm(() => {
|
|
19864
|
+
PATTERNS = [
|
|
19865
|
+
{ kind: "code", re: /(?<!\\)`([^`\n]+)`/g, delim: 1, rank: 0 },
|
|
19866
|
+
{ kind: "image", re: /(?<!\\)!\[([^\]\n]*)\]\(([^)\s]+)\)/g, delim: 0, rank: 1 },
|
|
19867
|
+
{ kind: "strong", re: /(?<!\\)\*\*([^*\n]+?)(?<!\\)\*\*/g, delim: 2, rank: 2 },
|
|
19868
|
+
{ kind: "strong", re: /(?<!\\)__([^_\n]+?)(?<!\\)__/g, delim: 2, rank: 2 },
|
|
19869
|
+
{ kind: "del", re: /(?<!\\)~~([^~\n]+?)(?<!\\)~~/g, delim: 2, rank: 3 },
|
|
19870
|
+
{ kind: "em", re: /(?<![*\w])(?<!\\)\*([^*\n]+?)(?<!\\)\*(?!\*)/g, delim: 1, rank: 4 },
|
|
19871
|
+
{ kind: "em", re: /(?<![_\w])(?<!\\)_([^_\n]+?)(?<!\\)_(?!_)/g, delim: 1, rank: 4 },
|
|
19872
|
+
{ kind: "link", re: /(?<!\\)\[([^\]\n]+)\]\(([^)\s]+)\)/g, delim: 0, rank: 5 }
|
|
19873
|
+
];
|
|
19874
|
+
});
|
|
19875
|
+
|
|
19876
|
+
// src/core/md/heal.ts
|
|
19877
|
+
function fenceMask(lines) {
|
|
19878
|
+
const mask = new Array(lines.length).fill(false);
|
|
19879
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
19880
|
+
const m3 = lines[i2].match(RE.fenceOpen);
|
|
19881
|
+
if (!m3)
|
|
19882
|
+
continue;
|
|
19883
|
+
const ch = m3[1][0];
|
|
19884
|
+
const len = m3[1].length;
|
|
19885
|
+
let close = -1;
|
|
19886
|
+
for (let j2 = i2 + 1;j2 < lines.length; j2++) {
|
|
19887
|
+
if (isFenceClose(lines[j2], ch, len)) {
|
|
19888
|
+
close = j2;
|
|
19889
|
+
break;
|
|
19890
|
+
}
|
|
19891
|
+
}
|
|
19892
|
+
if (close === -1)
|
|
19893
|
+
continue;
|
|
19894
|
+
for (let j2 = i2;j2 <= close; j2++)
|
|
19895
|
+
mask[j2] = true;
|
|
19896
|
+
i2 = close;
|
|
19897
|
+
}
|
|
19898
|
+
return mask;
|
|
19899
|
+
}
|
|
19900
|
+
function healLegacyMarkdown(src2) {
|
|
19901
|
+
if (!MAYBE_LEGACY.test(src2))
|
|
19902
|
+
return src2;
|
|
19903
|
+
const lines = src2.split(`
|
|
19904
|
+
`);
|
|
19905
|
+
const inFence = fenceMask(lines);
|
|
19906
|
+
const quoteish = (i2) => i2 >= 0 && i2 < lines.length && !inFence[i2] && matchQuoteLine(lines[i2].replace(/^[ \t]*/, "")) !== null;
|
|
19907
|
+
let changed = false;
|
|
19908
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
19909
|
+
if (inFence[i2])
|
|
19910
|
+
continue;
|
|
19911
|
+
const line = lines[i2];
|
|
19912
|
+
if (LEGACY_EMPTY_TODO.test(line)) {
|
|
19913
|
+
lines[i2] = line + " ";
|
|
19914
|
+
changed = true;
|
|
19915
|
+
} else if (BARE_QUOTE.test(line) && (quoteish(i2 - 1) || quoteish(i2 + 1))) {
|
|
19916
|
+
lines[i2] = line + " ";
|
|
19917
|
+
changed = true;
|
|
19918
|
+
}
|
|
19919
|
+
}
|
|
19920
|
+
return changed ? lines.join(`
|
|
19921
|
+
`) : src2;
|
|
19922
|
+
}
|
|
19923
|
+
var LEGACY_EMPTY_TODO, BARE_QUOTE, MAYBE_LEGACY;
|
|
19924
|
+
var init_heal = __esm(() => {
|
|
19925
|
+
init_grammar();
|
|
19926
|
+
LEGACY_EMPTY_TODO = /^[ \t]*[-*+][ \t]+\[[ xX]\]$/;
|
|
19927
|
+
BARE_QUOTE = /^[ \t]*>$/;
|
|
19928
|
+
MAYBE_LEGACY = /^[ \t]*(?:[-*+][ \t]+\[[ xX]\]|>)$/m;
|
|
19929
|
+
});
|
|
19930
|
+
|
|
19649
19931
|
// src/core/sync/share-render.ts
|
|
19650
19932
|
function escapeHtml(s2) {
|
|
19651
19933
|
return s2.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
19652
19934
|
}
|
|
19653
19935
|
function renderInline(src2, opts = {}) {
|
|
19654
|
-
const
|
|
19655
|
-
let
|
|
19656
|
-
|
|
19657
|
-
|
|
19658
|
-
|
|
19659
|
-
|
|
19660
|
-
|
|
19661
|
-
|
|
19662
|
-
|
|
19663
|
-
|
|
19664
|
-
|
|
19665
|
-
|
|
19666
|
-
|
|
19667
|
-
|
|
19668
|
-
|
|
19669
|
-
|
|
19670
|
-
|
|
19671
|
-
|
|
19936
|
+
const tokens = tokenizeInline(src2);
|
|
19937
|
+
let out = "";
|
|
19938
|
+
let pos = 0;
|
|
19939
|
+
for (const t2 of tokens) {
|
|
19940
|
+
out += escapeHtml(src2.slice(pos, t2.start));
|
|
19941
|
+
const inner = src2.slice(t2.innerFrom, t2.innerTo);
|
|
19942
|
+
const url2 = rewrite(t2.url ?? "", opts).replace(/"/g, """);
|
|
19943
|
+
switch (t2.kind) {
|
|
19944
|
+
case "code":
|
|
19945
|
+
out += `<code>${escapeHtml(inner)}</code>`;
|
|
19946
|
+
break;
|
|
19947
|
+
case "strong":
|
|
19948
|
+
out += `<strong>${escapeHtml(inner)}</strong>`;
|
|
19949
|
+
break;
|
|
19950
|
+
case "em":
|
|
19951
|
+
out += `<em>${escapeHtml(inner)}</em>`;
|
|
19952
|
+
break;
|
|
19953
|
+
case "del":
|
|
19954
|
+
out += `<del>${escapeHtml(inner)}</del>`;
|
|
19955
|
+
break;
|
|
19956
|
+
case "link":
|
|
19957
|
+
out += `<a href="${url2}" target="_blank" rel="noreferrer noopener">${escapeHtml(inner)}</a>`;
|
|
19958
|
+
break;
|
|
19959
|
+
case "image":
|
|
19960
|
+
out += `<img src="${url2}" alt="${escapeHtml(t2.alt ?? "")}" loading="lazy">`;
|
|
19961
|
+
break;
|
|
19962
|
+
}
|
|
19963
|
+
pos = t2.end;
|
|
19964
|
+
}
|
|
19965
|
+
return out + escapeHtml(src2.slice(pos));
|
|
19672
19966
|
}
|
|
19673
19967
|
function rewrite(url2, opts) {
|
|
19674
19968
|
if (opts.rewriteBlob && url2.startsWith("/blob/"))
|
|
@@ -19676,8 +19970,9 @@ function rewrite(url2, opts) {
|
|
|
19676
19970
|
return url2;
|
|
19677
19971
|
}
|
|
19678
19972
|
function renderMarkdown(md, opts = {}) {
|
|
19679
|
-
const
|
|
19680
|
-
`)
|
|
19973
|
+
const healed = healLegacyMarkdown((md ?? "").replace(/\r\n?/g, `
|
|
19974
|
+
`));
|
|
19975
|
+
const lines = healed.split(`
|
|
19681
19976
|
`);
|
|
19682
19977
|
const out = [];
|
|
19683
19978
|
let i2 = 0;
|
|
@@ -19690,38 +19985,39 @@ function renderMarkdown(md, opts = {}) {
|
|
|
19690
19985
|
};
|
|
19691
19986
|
while (i2 < lines.length) {
|
|
19692
19987
|
const line = lines[i2];
|
|
19693
|
-
const fence = line.match(
|
|
19988
|
+
const fence = line.match(RE.fenceOpen);
|
|
19694
19989
|
if (fence) {
|
|
19695
|
-
flushPara();
|
|
19696
19990
|
const marker = fence[1][0];
|
|
19697
|
-
const
|
|
19698
|
-
|
|
19699
|
-
i2
|
|
19700
|
-
|
|
19701
|
-
|
|
19702
|
-
if (m3 && m3[1][0] === marker) {
|
|
19703
|
-
i2++;
|
|
19991
|
+
const len = fence[1].length;
|
|
19992
|
+
let close = -1;
|
|
19993
|
+
for (let j2 = i2 + 1;j2 < lines.length; j2++) {
|
|
19994
|
+
if (isFenceClose(lines[j2], marker, len)) {
|
|
19995
|
+
close = j2;
|
|
19704
19996
|
break;
|
|
19705
19997
|
}
|
|
19706
|
-
body.push(lines[i2]);
|
|
19707
|
-
i2++;
|
|
19708
19998
|
}
|
|
19709
|
-
if (
|
|
19710
|
-
|
|
19999
|
+
if (close !== -1) {
|
|
20000
|
+
flushPara();
|
|
20001
|
+
const info = cleanLang(fence[2] ?? "");
|
|
20002
|
+
const body = lines.slice(i2 + 1, close);
|
|
20003
|
+
i2 = close + 1;
|
|
20004
|
+
if (info === HTML_FENCE) {
|
|
20005
|
+
out.push(`<iframe class="mh-embed" sandbox="allow-scripts allow-popups" srcdoc="${escapeHtml(body.join(`
|
|
19711
20006
|
`))}"></iframe>`);
|
|
19712
|
-
|
|
19713
|
-
|
|
19714
|
-
|
|
20007
|
+
} else {
|
|
20008
|
+
const cls = info ? ` class="language-${escapeHtml(info)}"` : "";
|
|
20009
|
+
out.push(`<pre><code${cls}>${escapeHtml(body.join(`
|
|
19715
20010
|
`))}</code></pre>`);
|
|
20011
|
+
}
|
|
20012
|
+
continue;
|
|
19716
20013
|
}
|
|
19717
|
-
continue;
|
|
19718
20014
|
}
|
|
19719
20015
|
if (line.trim() === "") {
|
|
19720
20016
|
flushPara();
|
|
19721
20017
|
i2++;
|
|
19722
20018
|
continue;
|
|
19723
20019
|
}
|
|
19724
|
-
const h3 = line.match(
|
|
20020
|
+
const h3 = stripLead(line).match(RE.h);
|
|
19725
20021
|
if (h3) {
|
|
19726
20022
|
flushPara();
|
|
19727
20023
|
const level = h3[1].length;
|
|
@@ -19729,30 +20025,33 @@ function renderMarkdown(md, opts = {}) {
|
|
|
19729
20025
|
i2++;
|
|
19730
20026
|
continue;
|
|
19731
20027
|
}
|
|
19732
|
-
if (
|
|
20028
|
+
if (RE.divider.test(line)) {
|
|
19733
20029
|
flushPara();
|
|
19734
20030
|
out.push("<hr>");
|
|
19735
20031
|
i2++;
|
|
19736
20032
|
continue;
|
|
19737
20033
|
}
|
|
19738
|
-
if (
|
|
20034
|
+
if (matchQuoteLine(stripLead(line)) !== null) {
|
|
19739
20035
|
flushPara();
|
|
19740
20036
|
const q3 = [];
|
|
19741
|
-
while (i2 < lines.length
|
|
19742
|
-
|
|
20037
|
+
while (i2 < lines.length) {
|
|
20038
|
+
const content = matchQuoteLine(stripLead(lines[i2]));
|
|
20039
|
+
if (content === null)
|
|
20040
|
+
break;
|
|
20041
|
+
q3.push(content);
|
|
19743
20042
|
i2++;
|
|
19744
20043
|
}
|
|
19745
20044
|
out.push(`<blockquote>${renderMarkdown(q3.join(`
|
|
19746
20045
|
`), opts)}</blockquote>`);
|
|
19747
20046
|
continue;
|
|
19748
20047
|
}
|
|
19749
|
-
if (
|
|
20048
|
+
if (looksLikeTableAt(lines, i2, 0)) {
|
|
19750
20049
|
flushPara();
|
|
19751
20050
|
const rows = [];
|
|
19752
|
-
const head =
|
|
20051
|
+
const head = splitTableRow(stripLead(lines[i2]));
|
|
19753
20052
|
i2 += 2;
|
|
19754
20053
|
while (i2 < lines.length && lines[i2].includes("|") && lines[i2].trim() !== "") {
|
|
19755
|
-
rows.push(
|
|
20054
|
+
rows.push(splitTableRow(stripLead(lines[i2])));
|
|
19756
20055
|
i2++;
|
|
19757
20056
|
}
|
|
19758
20057
|
const th = head.map((c3) => `<th>${renderInline(c3, opts)}</th>`).join("");
|
|
@@ -19760,19 +20059,25 @@ function renderMarkdown(md, opts = {}) {
|
|
|
19760
20059
|
out.push(`<table><thead><tr>${th}</tr></thead><tbody>${body}</tbody></table>`);
|
|
19761
20060
|
continue;
|
|
19762
20061
|
}
|
|
19763
|
-
const
|
|
19764
|
-
|
|
19765
|
-
if (ul || ol) {
|
|
20062
|
+
const first = matchListLine(line, 0);
|
|
20063
|
+
if (first) {
|
|
19766
20064
|
flushPara();
|
|
19767
|
-
const ordered =
|
|
19768
|
-
const
|
|
19769
|
-
|
|
19770
|
-
|
|
19771
|
-
|
|
20065
|
+
const ordered = first.type === "numbered";
|
|
20066
|
+
const lis = [];
|
|
20067
|
+
while (i2 < lines.length) {
|
|
20068
|
+
const it3 = matchListLine(lines[i2], 0);
|
|
20069
|
+
if (!it3 || it3.type === "numbered" !== ordered)
|
|
20070
|
+
break;
|
|
20071
|
+
if (it3.type === "todo") {
|
|
20072
|
+
lis.push(`<li class="todo"><input type="checkbox" disabled${it3.checked ? " checked" : ""}> ${renderInline(it3.content, opts)}</li>`);
|
|
20073
|
+
} else if (it3.type === "numbered" && it3.num !== undefined) {
|
|
20074
|
+
lis.push(`<li value="${it3.num}">${renderInline(it3.content, opts)}</li>`);
|
|
20075
|
+
} else {
|
|
20076
|
+
lis.push(`<li>${renderInline(it3.content, opts)}</li>`);
|
|
20077
|
+
}
|
|
19772
20078
|
i2++;
|
|
19773
20079
|
}
|
|
19774
|
-
|
|
19775
|
-
out.push(ordered ? `<ol>${lis}</ol>` : `<ul>${lis}</ul>`);
|
|
20080
|
+
out.push(ordered ? `<ol>${lis.join("")}</ol>` : `<ul>${lis.join("")}</ul>`);
|
|
19776
20081
|
continue;
|
|
19777
20082
|
}
|
|
19778
20083
|
if (/^\s*!\[[^\]]*\]\([^)\s]+\)\s*$/.test(line)) {
|
|
@@ -19788,20 +20093,13 @@ function renderMarkdown(md, opts = {}) {
|
|
|
19788
20093
|
return out.join(`
|
|
19789
20094
|
`);
|
|
19790
20095
|
}
|
|
19791
|
-
function
|
|
19792
|
-
|
|
19793
|
-
if (s2.startsWith("|"))
|
|
19794
|
-
s2 = s2.slice(1);
|
|
19795
|
-
if (s2.endsWith("|"))
|
|
19796
|
-
s2 = s2.slice(0, -1);
|
|
19797
|
-
return s2.split("|").map((c3) => c3.trim());
|
|
20096
|
+
function stripLead(line) {
|
|
20097
|
+
return stripIndent(line, Number.MAX_SAFE_INTEGER);
|
|
19798
20098
|
}
|
|
19799
|
-
var A4, B3, RESTORE, FENCE;
|
|
19800
20099
|
var init_share_render = __esm(() => {
|
|
19801
|
-
|
|
19802
|
-
|
|
19803
|
-
|
|
19804
|
-
FENCE = /^\s*(`{3,}|~{3,})(.*)$/;
|
|
20100
|
+
init_grammar();
|
|
20101
|
+
init_inline();
|
|
20102
|
+
init_heal();
|
|
19805
20103
|
});
|
|
19806
20104
|
|
|
19807
20105
|
// src/core/sync/share-serve.ts
|
|
@@ -21657,7 +21955,7 @@ async function runMain(cmd, opts = {}) {
|
|
|
21657
21955
|
// package.json
|
|
21658
21956
|
var package_default = {
|
|
21659
21957
|
name: "@tensorix/metahub",
|
|
21660
|
-
version: "0.
|
|
21958
|
+
version: "0.3.1",
|
|
21661
21959
|
description: "Metahub core library and CLI",
|
|
21662
21960
|
license: "AGPL-3.0-only",
|
|
21663
21961
|
type: "module",
|
|
@@ -21687,16 +21985,21 @@ var package_default = {
|
|
|
21687
21985
|
"build:shell": "bun run scripts/build-shell.ts",
|
|
21688
21986
|
"build:share-viewer": "bun run scripts/build-share-viewer.ts",
|
|
21689
21987
|
"build:binaries": "bun run scripts/compile-binaries.ts",
|
|
21988
|
+
"build:binaries:host": "HOST_ONLY=1 bun run scripts/compile-binaries.ts",
|
|
21690
21989
|
prepublishOnly: "bun run build",
|
|
21691
21990
|
test: "bun test",
|
|
21692
21991
|
release: "bun run scripts/tag-release.ts"
|
|
21693
21992
|
},
|
|
21694
21993
|
dependencies: {
|
|
21695
21994
|
"@clack/prompts": "^1.5.0",
|
|
21995
|
+
"@codemirror/commands": "6.10.4",
|
|
21996
|
+
"@codemirror/state": "6.7.0",
|
|
21997
|
+
"@codemirror/view": "6.43.4",
|
|
21696
21998
|
"@sqlite.org/sqlite-wasm": "^3.53.0-build1",
|
|
21697
21999
|
aws4fetch: "^1.0.20",
|
|
21698
22000
|
citty: "^0.1.6",
|
|
21699
22001
|
"highlight.js": "^11.11.1",
|
|
22002
|
+
jsqr: "^1.4.0",
|
|
21700
22003
|
preact: "^10.29.2",
|
|
21701
22004
|
"qrcode-generator": "^2.0.4",
|
|
21702
22005
|
turndown: "^7.2.4",
|
|
@@ -21705,8 +22008,17 @@ var package_default = {
|
|
|
21705
22008
|
},
|
|
21706
22009
|
devDependencies: {
|
|
21707
22010
|
"@happy-dom/global-registrator": "^20.10.2",
|
|
22011
|
+
"@prettier/plugin-php": "^0.25.0",
|
|
21708
22012
|
"@types/bun": "latest",
|
|
21709
22013
|
"@types/turndown": "^5.0.6",
|
|
22014
|
+
"@wasm-fmt/clang-format": "^22.1.8",
|
|
22015
|
+
"@wasm-fmt/gofmt": "^0.7.3",
|
|
22016
|
+
"@wasm-fmt/lua_fmt": "^0.3.3",
|
|
22017
|
+
"@wasm-fmt/ruff_fmt": "^0.15.20",
|
|
22018
|
+
"@wasm-fmt/taplo_fmt": "^0.2.5",
|
|
22019
|
+
"mvdan-sh": "^0.10.1",
|
|
22020
|
+
prettier: "^3.6",
|
|
22021
|
+
"sql-formatter": "^15",
|
|
21710
22022
|
typescript: "^5"
|
|
21711
22023
|
}
|
|
21712
22024
|
};
|
|
@@ -21850,6 +22162,7 @@ CREATE TABLE IF NOT EXISTS databases (
|
|
|
21850
22162
|
id TEXT PRIMARY KEY,
|
|
21851
22163
|
name TEXT,
|
|
21852
22164
|
icon TEXT,
|
|
22165
|
+
meta TEXT, -- JSON: generic replicated metadata (e.g. UI flags), one LWW register
|
|
21853
22166
|
created_hlc TEXT,
|
|
21854
22167
|
__deleted INTEGER NOT NULL DEFAULT 0
|
|
21855
22168
|
);
|
|
@@ -22132,9 +22445,25 @@ function migrateStoragePeerUrls(db) {
|
|
|
22132
22445
|
});
|
|
22133
22446
|
tx();
|
|
22134
22447
|
}
|
|
22448
|
+
function migrateDatabases(db) {
|
|
22449
|
+
if (hasColumn(db, "databases", "meta"))
|
|
22450
|
+
return;
|
|
22451
|
+
db.exec("ALTER TABLE databases ADD COLUMN meta TEXT");
|
|
22452
|
+
db.exec(`
|
|
22453
|
+
UPDATE databases SET meta = (
|
|
22454
|
+
SELECT c.value FROM crdt_changes c
|
|
22455
|
+
WHERE c.dataset = 'databases' AND c.col = 'meta' AND c.row_id = databases.id
|
|
22456
|
+
ORDER BY c.hlc DESC LIMIT 1
|
|
22457
|
+
)
|
|
22458
|
+
WHERE id IN (
|
|
22459
|
+
SELECT DISTINCT row_id FROM crdt_changes WHERE dataset = 'databases' AND col = 'meta'
|
|
22460
|
+
)
|
|
22461
|
+
`);
|
|
22462
|
+
}
|
|
22135
22463
|
function initSchema(db) {
|
|
22136
22464
|
runSchema(db);
|
|
22137
22465
|
migrateOplog(db);
|
|
22466
|
+
migrateDatabases(db);
|
|
22138
22467
|
migrateCrdtChangesSeq(db);
|
|
22139
22468
|
migrateRecords(db);
|
|
22140
22469
|
migratePeers(db);
|
|
@@ -22378,6 +22707,18 @@ mh doc edit <ref> --old "old text" --new "new text"
|
|
|
22378
22707
|
mh doc edit <ref> --old "TODO" --new "DONE" --replace-all
|
|
22379
22708
|
mh doc edit <ref> --old "..." --new "..." --if-match <version-from-read>
|
|
22380
22709
|
|
|
22710
|
+
# EDIT (batch): apply several pairs in ONE atomic call \u2014 prefer this for many
|
|
22711
|
+
# scattered deltas. One --if-match check, one revision, no re-read between edits.
|
|
22712
|
+
# Pairs fold in order (a later "old" can match an earlier "new"); if ANY pair's
|
|
22713
|
+
# anchor is missing/ambiguous the whole batch aborts and the doc is untouched.
|
|
22714
|
+
mh doc edit <ref> --if-match <version> --edits @- <<'JSON'
|
|
22715
|
+
[{"old":"(draft)","new":""},
|
|
22716
|
+
{"old":"status: todo","new":"status: done"},
|
|
22717
|
+
{"old":"FIXME","new":"FIXED","replaceAll":true}]
|
|
22718
|
+
JSON
|
|
22719
|
+
# Keep anchors in prose. Don't let --old/--new (or a batch pair) cut into the
|
|
22720
|
+
# interior of a table, code fence, or media block, or the block won't round-trip.
|
|
22721
|
+
|
|
22381
22722
|
# WRITE more: add blocks at the tail or head
|
|
22382
22723
|
mh doc append <ref> --body "a new paragraph"
|
|
22383
22724
|
mh doc prepend <ref> --body "## Summary"
|
|
@@ -22393,8 +22734,11 @@ Required agent loop for revising a document (treat \`--if-match\` as mandatory \
|
|
|
22393
22734
|
without it a concurrent edit from another session/the WebUI is silently
|
|
22394
22735
|
clobbered):
|
|
22395
22736
|
1. \`mh doc read <ref>\` \u2192 capture \`body\` and \`version\`.
|
|
22396
|
-
2. Compute
|
|
22397
|
-
|
|
22737
|
+
2. Compute the minimal \`--old\`/\`--new\` pair(s) (unique anchor text). Revising
|
|
22738
|
+
several spots at once? Collect them into one \`--edits\` batch instead of
|
|
22739
|
+
editing serially \u2014 the version bumps on the whole doc after any edit, so
|
|
22740
|
+
serial \`--if-match\` edits force a re-read between each.
|
|
22741
|
+
3. \`mh doc edit <ref> --old ... --new ... --if-match <version>\` (or \`--edits\`).
|
|
22398
22742
|
4. On exit 5 (\`stale\`), re-read and retry from step 1.
|
|
22399
22743
|
|
|
22400
22744
|
## Media & attachments (images / video / audio / files)
|
|
@@ -22554,24 +22898,45 @@ will prompt interactively** \u2014 always pass their flags explicitly:
|
|
|
22554
22898
|
- **JSON by default** when piped; add \`--pretty\` only when a human will read it.
|
|
22555
22899
|
`;
|
|
22556
22900
|
|
|
22557
|
-
// src/cli/
|
|
22901
|
+
// src/cli/agent-skill.ts
|
|
22558
22902
|
import { mkdirSync as mkdirSync2 } from "fs";
|
|
22559
22903
|
import { homedir as homedir2 } from "os";
|
|
22560
22904
|
import { join as join2 } from "path";
|
|
22905
|
+
var CODEX_OPENAI_YAML = `interface:
|
|
22906
|
+
display_name: "Metahub"
|
|
22907
|
+
short_description: "Use mh for durable agent memory"
|
|
22908
|
+
default_prompt: "Use $mh to store, recall, search, and edit durable working memory with metahub."
|
|
22909
|
+
`;
|
|
22561
22910
|
function claudeHome() {
|
|
22562
22911
|
return process.env.CLAUDE_CONFIG_DIR ?? join2(homedir2(), ".claude");
|
|
22563
22912
|
}
|
|
22913
|
+
function codexHome() {
|
|
22914
|
+
return process.env.CODEX_HOME ?? join2(homedir2(), ".codex");
|
|
22915
|
+
}
|
|
22916
|
+
async function writeIfChanged(path, content) {
|
|
22917
|
+
const prev = await Bun.file(path).exists() ? await Bun.file(path).text() : null;
|
|
22918
|
+
if (prev === content)
|
|
22919
|
+
return false;
|
|
22920
|
+
await Bun.write(path, content);
|
|
22921
|
+
return true;
|
|
22922
|
+
}
|
|
22564
22923
|
async function scaffoldClaudeSkill() {
|
|
22565
22924
|
const dir = join2(claudeHome(), "skills", "mh");
|
|
22566
22925
|
const path = join2(dir, "SKILL.md");
|
|
22567
|
-
|
|
22568
|
-
const changed =
|
|
22569
|
-
if (changed) {
|
|
22570
|
-
mkdirSync2(dir, { recursive: true });
|
|
22571
|
-
await Bun.write(path, SKILL_default);
|
|
22572
|
-
}
|
|
22926
|
+
mkdirSync2(dir, { recursive: true });
|
|
22927
|
+
const changed = await writeIfChanged(path, SKILL_default);
|
|
22573
22928
|
return { path, changed };
|
|
22574
22929
|
}
|
|
22930
|
+
async function scaffoldCodexSkill() {
|
|
22931
|
+
const dir = join2(codexHome(), "skills", "mh");
|
|
22932
|
+
const path = join2(dir, "SKILL.md");
|
|
22933
|
+
const metadataDir = join2(dir, "agents");
|
|
22934
|
+
const metadataPath = join2(metadataDir, "openai.yaml");
|
|
22935
|
+
mkdirSync2(metadataDir, { recursive: true });
|
|
22936
|
+
const skillChanged = await writeIfChanged(path, SKILL_default);
|
|
22937
|
+
const metadataChanged = await writeIfChanged(metadataPath, CODEX_OPENAI_YAML);
|
|
22938
|
+
return { path, metadataPath, changed: skillChanged || metadataChanged };
|
|
22939
|
+
}
|
|
22575
22940
|
|
|
22576
22941
|
// src/cli/commands/init.ts
|
|
22577
22942
|
var init_default = defineCommand({
|
|
@@ -22583,13 +22948,43 @@ var init_default = defineCommand({
|
|
|
22583
22948
|
claude: {
|
|
22584
22949
|
type: "boolean",
|
|
22585
22950
|
description: "Install a Claude Code /mh skill into ~/.claude (does not touch ~/.metahub)"
|
|
22951
|
+
},
|
|
22952
|
+
codex: {
|
|
22953
|
+
type: "boolean",
|
|
22954
|
+
description: "Install a Codex $mh skill into ~/.codex (does not touch ~/.metahub)"
|
|
22586
22955
|
}
|
|
22587
22956
|
},
|
|
22588
22957
|
async run({ args }) {
|
|
22589
|
-
if (args.claude) {
|
|
22590
|
-
const
|
|
22591
|
-
|
|
22958
|
+
if (args.claude || args.codex) {
|
|
22959
|
+
const claude = args.claude ? await scaffoldClaudeSkill() : null;
|
|
22960
|
+
const codex = args.codex ? await scaffoldCodexSkill() : null;
|
|
22961
|
+
if (claude && !codex) {
|
|
22962
|
+
print({ changed: claude.changed, skill: claude.path }, () => (claude.changed ? `Installed ${claude.path}` : `Up to date: ${claude.path}`) + `
|
|
22963
|
+
Use /mh in Claude Code (any project).`);
|
|
22964
|
+
return;
|
|
22965
|
+
}
|
|
22966
|
+
if (codex && !claude) {
|
|
22967
|
+
print({ changed: codex.changed, skill: codex.path, metadata: codex.metadataPath }, () => (codex.changed ? `Installed ${codex.path}` : `Up to date: ${codex.path}`) + `
|
|
22968
|
+
Use $mh in Codex (restart Codex if it was already running).`);
|
|
22969
|
+
return;
|
|
22970
|
+
}
|
|
22971
|
+
print({
|
|
22972
|
+
changed: !!claude?.changed || !!codex?.changed,
|
|
22973
|
+
claude: claude ? { changed: claude.changed, skill: claude.path } : null,
|
|
22974
|
+
codex: codex ? { changed: codex.changed, skill: codex.path, metadata: codex.metadataPath } : null
|
|
22975
|
+
}, () => {
|
|
22976
|
+
const lines = [];
|
|
22977
|
+
if (claude) {
|
|
22978
|
+
lines.push((claude.changed ? `Installed ${claude.path}` : `Up to date: ${claude.path}`) + `
|
|
22592
22979
|
Use /mh in Claude Code (any project).`);
|
|
22980
|
+
}
|
|
22981
|
+
if (codex) {
|
|
22982
|
+
lines.push((codex.changed ? `Installed ${codex.path}` : `Up to date: ${codex.path}`) + `
|
|
22983
|
+
Use $mh in Codex (restart Codex if it was already running).`);
|
|
22984
|
+
}
|
|
22985
|
+
return lines.join(`
|
|
22986
|
+
`);
|
|
22987
|
+
});
|
|
22593
22988
|
return;
|
|
22594
22989
|
}
|
|
22595
22990
|
const db = openMetahub();
|
|
@@ -23756,23 +24151,54 @@ var read = defineCommand({
|
|
|
23756
24151
|
}, () => body);
|
|
23757
24152
|
})
|
|
23758
24153
|
});
|
|
24154
|
+
function parseEditPairs(raw) {
|
|
24155
|
+
if (!Array.isArray(raw) || raw.length === 0)
|
|
24156
|
+
throw new MhError("invalid_input", "--edits must be a non-empty JSON array");
|
|
24157
|
+
return raw.map((e2, i2) => {
|
|
24158
|
+
if (typeof e2 !== "object" || e2 === null)
|
|
24159
|
+
throw new MhError("invalid_input", `--edits[${i2}] must be an object`);
|
|
24160
|
+
const { old, new: repl, replaceAll } = e2;
|
|
24161
|
+
if (typeof old !== "string" || old === "")
|
|
24162
|
+
throw new MhError("invalid_input", `--edits[${i2}].old must be a non-empty string`);
|
|
24163
|
+
if (repl !== undefined && typeof repl !== "string")
|
|
24164
|
+
throw new MhError("invalid_input", `--edits[${i2}].new must be a string`);
|
|
24165
|
+
if (replaceAll !== undefined && typeof replaceAll !== "boolean")
|
|
24166
|
+
throw new MhError("invalid_input", `--edits[${i2}].replaceAll must be a boolean`);
|
|
24167
|
+
return { old, new: repl, replaceAll };
|
|
24168
|
+
});
|
|
24169
|
+
}
|
|
23759
24170
|
var edit = defineCommand({
|
|
23760
24171
|
meta: {
|
|
23761
24172
|
name: "edit",
|
|
23762
|
-
description: "Anchored find/replace; --old must match exactly once unless --replace-all"
|
|
24173
|
+
description: "Anchored find/replace; --old must match exactly once unless --replace-all. --edits applies a JSON batch of pairs atomically"
|
|
23763
24174
|
},
|
|
23764
24175
|
args: {
|
|
23765
24176
|
id: { type: "positional", required: true, description: "Document ref (id/prefix/title)" },
|
|
23766
|
-
old: { type: "string",
|
|
24177
|
+
old: { type: "string", description: "Exact text to find (@file/@- ok)" },
|
|
23767
24178
|
new: { type: "string", description: "Replacement text (@file/@- ok)" },
|
|
23768
24179
|
"replace-all": { type: "boolean", description: "Replace every occurrence" },
|
|
24180
|
+
edits: {
|
|
24181
|
+
type: "string",
|
|
24182
|
+
description: 'Batch JSON: [{"old","new"?,"replaceAll"?}], applied in order (@file/@- ok)'
|
|
24183
|
+
},
|
|
23769
24184
|
"if-match": { type: "string", description: "Version from `doc read`; reject if changed" }
|
|
23770
24185
|
},
|
|
23771
24186
|
run: guard(async (args) => {
|
|
23772
24187
|
const db = openMetahub();
|
|
24188
|
+
const id = docId(db, args.id);
|
|
24189
|
+
if (args.edits != null) {
|
|
24190
|
+
if (args.old != null || args.new != null || args["replace-all"])
|
|
24191
|
+
throw new MhError("invalid_input", "use --old/--new/--replace-all or --edits, not both");
|
|
24192
|
+
const edits = parseEditPairs(await resolveJson(args.edits));
|
|
24193
|
+
const r4 = editDocumentBatch(db, id, { edits, ifMatch: args["if-match"] });
|
|
24194
|
+
print(r4, () => `edited ${r4.id} (${r4.replaced} replaced across ${edits.length} edit(s))`);
|
|
24195
|
+
return;
|
|
24196
|
+
}
|
|
24197
|
+
if (args.old == null)
|
|
24198
|
+
throw new MhError("invalid_input", "need --old or --edits");
|
|
23773
24199
|
const oldText = await resolveValue2(args.old);
|
|
23774
24200
|
const newText = await resolveValue2(args.new) ?? "";
|
|
23775
|
-
const r3 = editDocument(db,
|
|
24201
|
+
const r3 = editDocument(db, id, {
|
|
23776
24202
|
old: oldText,
|
|
23777
24203
|
new: newText,
|
|
23778
24204
|
replaceAll: args["replace-all"],
|
|
@@ -28356,56 +28782,196 @@ function wantsHtml(req) {
|
|
|
28356
28782
|
return req.method === "GET" && (req.headers.get("accept") ?? "").includes("text/html");
|
|
28357
28783
|
}
|
|
28358
28784
|
var HTML_HEADERS = { "content-type": "text/html; charset=utf-8" };
|
|
28785
|
+
var 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"/>';
|
|
28786
|
+
var 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"/>';
|
|
28787
|
+
var 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"/>';
|
|
28788
|
+
var UNLOCK_CSS = `
|
|
28789
|
+
:root{color-scheme:light;
|
|
28790
|
+
--bg:#ffffff;--surface:#fbfbfa;--surface-2:#f1f1ef;--fg:#2c2c30;--fg-soft:#5b5b62;
|
|
28791
|
+
--muted:#75757f;--line:#ebebe8;--line-strong:#dededb;--accent:#4a55d6;--accent-fg:#ffffff;
|
|
28792
|
+
--accent-soft:#eef0ff;--danger:#d6473b;--danger-soft:#fdeceb;--code-bg:#f8f8f6}
|
|
28793
|
+
:root[data-resolved="dark"]{color-scheme:dark;
|
|
28794
|
+
--bg:#1a1a1c;--surface:#202022;--surface-2:#2a2a2d;--fg:#e6e6e9;--fg-soft:#b4b4bb;
|
|
28795
|
+
--muted:#8b8b95;--line:#2c2c30;--line-strong:#3a3a40;--accent:#7b86ff;--accent-fg:#14141a;
|
|
28796
|
+
--accent-soft:#23243a;--danger:#f87168;--danger-soft:#341e1c;--code-bg:#26262a}
|
|
28797
|
+
*{box-sizing:border-box}
|
|
28798
|
+
html,body{margin:0;min-height:100%}
|
|
28799
|
+
body{font-family:"Hanken Grotesk",-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;
|
|
28800
|
+
color:var(--fg);background:var(--bg);line-height:1.55;
|
|
28801
|
+
display:flex;align-items:center;justify-content:center;min-height:100dvh;
|
|
28802
|
+
padding:calc(24px + env(safe-area-inset-top)) calc(20px + env(safe-area-inset-right)) calc(24px + env(safe-area-inset-bottom)) calc(20px + env(safe-area-inset-left));
|
|
28803
|
+
-webkit-font-smoothing:antialiased;-webkit-tap-highlight-color:transparent;overflow:hidden}
|
|
28804
|
+
/* Ambient wash: two faint accent blooms behind the card. */
|
|
28805
|
+
body::before{content:"";position:fixed;inset:0;pointer-events:none;z-index:0;
|
|
28806
|
+
background:
|
|
28807
|
+
radial-gradient(58vmax 58vmax at 14% -8%,color-mix(in srgb,var(--accent) 13%,transparent),transparent 60%),
|
|
28808
|
+
radial-gradient(50vmax 50vmax at 108% 112%,color-mix(in srgb,var(--accent) 10%,transparent),transparent 55%)}
|
|
28809
|
+
.card{position:relative;z-index:1;width:100%;max-width:420px;background:var(--surface);
|
|
28810
|
+
border:1px solid var(--line);border-radius:18px;padding:32px 26px 26px;
|
|
28811
|
+
box-shadow:0 24px 60px rgba(20,20,40,.14),0 4px 14px rgba(20,20,40,.06);
|
|
28812
|
+
animation:rise .45s cubic-bezier(.2,.7,.3,1) both}
|
|
28813
|
+
@keyframes rise{from{opacity:0;transform:translateY(12px) scale(.985)}to{opacity:1;transform:none}}
|
|
28814
|
+
.brand{width:52px;height:52px;border-radius:14px;display:flex;align-items:center;justify-content:center;
|
|
28815
|
+
background:var(--accent-soft);color:var(--accent);margin-bottom:18px}
|
|
28816
|
+
.brand svg{width:28px;height:28px;fill:none;stroke:currentColor;stroke-width:1.6;
|
|
28817
|
+
stroke-linecap:round;stroke-linejoin:round}
|
|
28818
|
+
.brand path{stroke-dasharray:120;stroke-dashoffset:120;animation:draw .9s .12s ease forwards}
|
|
28819
|
+
@keyframes draw{to{stroke-dashoffset:0}}
|
|
28820
|
+
h1{font-size:21px;font-weight:650;letter-spacing:-.01em;margin:0 0 8px}
|
|
28821
|
+
.sub{color:var(--muted);font-size:13.5px;margin:0 0 22px;line-height:1.6}
|
|
28822
|
+
.sub code{font-family:"JetBrains Mono",ui-monospace,SFMono-Regular,monospace;font-size:12.5px;
|
|
28823
|
+
background:var(--code-bg);border:1px solid var(--line);border-radius:5px;padding:1px 6px;color:var(--fg-soft);
|
|
28824
|
+
white-space:nowrap}
|
|
28825
|
+
.field{position:relative;display:flex;align-items:center}
|
|
28826
|
+
input{width:100%;height:50px;padding:0 48px 0 15px;font-size:16px; /* 16px: never let iOS Safari zoom on focus */
|
|
28827
|
+
font-family:"JetBrains Mono",ui-monospace,SFMono-Regular,monospace;letter-spacing:.01em;
|
|
28828
|
+
color:var(--fg);background:var(--bg);border:1.5px solid var(--line-strong);border-radius:12px;
|
|
28829
|
+
outline:none;transition:border-color .15s,box-shadow .15s}
|
|
28830
|
+
input::placeholder{font-family:var(--ui,inherit);letter-spacing:normal;color:var(--muted);opacity:.8}
|
|
28831
|
+
input:focus{border-color:var(--accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 22%,transparent)}
|
|
28832
|
+
.card.bad input{border-color:var(--danger);box-shadow:0 0 0 3px color-mix(in srgb,var(--danger) 20%,transparent)}
|
|
28833
|
+
.card.bad .field{animation:shake .34s cubic-bezier(.36,.07,.19,.97)}
|
|
28834
|
+
@keyframes shake{10%,90%{transform:translateX(-1px)}20%,80%{transform:translateX(2px)}
|
|
28835
|
+
30%,50%,70%{transform:translateX(-5px)}40%,60%{transform:translateX(5px)}}
|
|
28836
|
+
.peek{position:absolute;right:6px;width:40px;height:40px;border:0;background:none;cursor:pointer;
|
|
28837
|
+
color:var(--muted);display:flex;align-items:center;justify-content:center;border-radius:9px}
|
|
28838
|
+
.peek:hover{color:var(--fg-soft)}
|
|
28839
|
+
.peek svg{width:19px;height:19px;fill:none;stroke:currentColor;stroke-width:1.7;
|
|
28840
|
+
stroke-linecap:round;stroke-linejoin:round}
|
|
28841
|
+
.err{color:var(--danger);font-size:13px;font-weight:500;margin:11px 2px 0;
|
|
28842
|
+
display:flex;gap:6px;align-items:center;animation:fade .2s ease both}
|
|
28843
|
+
@keyframes fade{from{opacity:0}to{opacity:1}}
|
|
28844
|
+
button.go{width:100%;height:48px;margin-top:20px;border:0;border-radius:12px;cursor:pointer;
|
|
28845
|
+
background:var(--accent);color:var(--accent-fg);font-size:15px;font-weight:600;font-family:inherit;
|
|
28846
|
+
display:flex;align-items:center;justify-content:center;gap:9px;
|
|
28847
|
+
transition:filter .15s,transform .05s}
|
|
28848
|
+
button.go:hover{filter:brightness(1.06)}
|
|
28849
|
+
button.go:active{transform:translateY(1px)}
|
|
28850
|
+
button.go:disabled{opacity:.7;cursor:default}
|
|
28851
|
+
.spin{width:17px;height:17px;border:2px solid color-mix(in srgb,var(--accent-fg) 45%,transparent);
|
|
28852
|
+
border-top-color:var(--accent-fg);border-radius:50%;animation:spin .7s linear infinite}
|
|
28853
|
+
/* Full-page loader shown while a silent renewal is in flight. */
|
|
28854
|
+
.boot{position:fixed;inset:0;z-index:2;display:flex;align-items:center;justify-content:center;background:var(--bg)}
|
|
28855
|
+
.boot svg{width:40px;height:40px;fill:none;stroke:var(--accent);stroke-width:1.4;
|
|
28856
|
+
stroke-linecap:round;stroke-linejoin:round;animation:breathe 1.5s ease-in-out infinite}
|
|
28857
|
+
@keyframes breathe{0%,100%{opacity:.35;transform:scale(.94)}50%{opacity:1;transform:scale(1)}}
|
|
28858
|
+
@keyframes spin{to{transform:rotate(360deg)}}
|
|
28859
|
+
@media (prefers-reduced-motion:reduce){*{animation-duration:.01ms!important}
|
|
28860
|
+
.brand path{stroke-dashoffset:0}}
|
|
28861
|
+
`;
|
|
28359
28862
|
function unlockPage() {
|
|
28360
|
-
return `<!doctype html><html lang="
|
|
28361
|
-
<meta charset="utf-8"
|
|
28362
|
-
<
|
|
28363
|
-
<
|
|
28364
|
-
|
|
28365
|
-
|
|
28366
|
-
|
|
28367
|
-
|
|
28368
|
-
|
|
28369
|
-
|
|
28370
|
-
|
|
28371
|
-
|
|
28372
|
-
|
|
28373
|
-
</
|
|
28374
|
-
<
|
|
28375
|
-
|
|
28376
|
-
|
|
28377
|
-
<
|
|
28378
|
-
<
|
|
28863
|
+
return `<!doctype html><html lang="zh-CN"><head>
|
|
28864
|
+
<meta charset="utf-8">
|
|
28865
|
+
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
|
|
28866
|
+
<meta name="theme-color" content="#ffffff">
|
|
28867
|
+
<title>\u9A8C\u8BC1\u8BBF\u95EE\u4EE4\u724C \xB7 metahub</title>
|
|
28868
|
+
<script>
|
|
28869
|
+
// FOUC-guard theme resolution, same key/logic as src/webui/theme.ts.
|
|
28870
|
+
try {
|
|
28871
|
+
var mt = localStorage.getItem("mh-theme");
|
|
28872
|
+
var dark = mt === "dark" || (mt !== "light" && matchMedia("(prefers-color-scheme: dark)").matches);
|
|
28873
|
+
document.documentElement.dataset.resolved = dark ? "dark" : "light";
|
|
28874
|
+
document.head.querySelector('meta[name=theme-color]').setAttribute("content", dark ? "#1a1a1c" : "#ffffff");
|
|
28875
|
+
} catch (e) {}
|
|
28876
|
+
</script>
|
|
28877
|
+
<style>${UNLOCK_CSS}</style></head><body>
|
|
28878
|
+
<div class="boot" id="boot"><svg viewBox="0 0 24 24">${CUBE_SVG}</svg></div>
|
|
28879
|
+
<form class="card" id="f" style="display:none" autocomplete="on">
|
|
28880
|
+
<div class="brand"><svg viewBox="0 0 24 24">${CUBE_SVG}</svg></div>
|
|
28881
|
+
<h1>\u8F93\u5165\u8BBF\u95EE\u4EE4\u724C</h1>
|
|
28882
|
+
<p class="sub">\u6B64\u670D\u52A1\u5668\u5DF2\u5F00\u542F\u8BBF\u95EE\u4FDD\u62A4\u3002\u5728\u5DF2\u767B\u5F55\u8BBE\u5907\u7684\u300C\u8BBE\u7F6E \u2192 \u8BBE\u5907\u4E0E\u6388\u6743\u300D\u83B7\u53D6\u767B\u5F55\u94FE\u63A5\u6216\u4E8C\u7EF4\u7801,\u6216\u5728\u670D\u52A1\u5668\u4E0A\u8FD0\u884C <code>mh token show</code>\u3002</p>
|
|
28883
|
+
<div class="field">
|
|
28884
|
+
<input id="t" type="password" placeholder="\u7C98\u8D34\u8BBF\u95EE\u4EE4\u724C\u6216\u767B\u5F55\u94FE\u63A5"
|
|
28885
|
+
autocomplete="current-password" autocapitalize="off" autocorrect="off" spellcheck="false" enterkeyhint="go">
|
|
28886
|
+
<button type="button" class="peek" id="peek" aria-label="\u663E\u793A\u4EE4\u724C"><svg viewBox="0 0 24 24">${EYE_SVG}</svg></button>
|
|
28887
|
+
</div>
|
|
28888
|
+
<p class="err" id="e" style="display:none"></p>
|
|
28889
|
+
<button type="submit" class="go" id="go">\u89E3\u9501\u5E76\u8FDB\u5165</button>
|
|
28379
28890
|
</form>
|
|
28380
28891
|
<script>
|
|
28381
28892
|
var KEY = "mh_token";
|
|
28893
|
+
var form = document.getElementById("f"), boot = document.getElementById("boot");
|
|
28894
|
+
var input = document.getElementById("t"), errEl = document.getElementById("e");
|
|
28895
|
+
var goBtn = document.getElementById("go"), peek = document.getElementById("peek");
|
|
28896
|
+
|
|
28382
28897
|
function save(t) {
|
|
28383
28898
|
localStorage.setItem(KEY, t);
|
|
28384
28899
|
document.cookie = "${COOKIE}=" + encodeURIComponent(t) + "; ${COOKIE_ATTRS}" +
|
|
28385
28900
|
(location.protocol === "https:" ? "; Secure" : "");
|
|
28386
28901
|
}
|
|
28387
|
-
|
|
28388
|
-
|
|
28389
|
-
|
|
28390
|
-
|
|
28391
|
-
|
|
28392
|
-
|
|
28393
|
-
|
|
28902
|
+
// Accept a pasted "\u2026/?token=xxx" login link, not just the bare token.
|
|
28903
|
+
function normalize(v) {
|
|
28904
|
+
v = (v || "").trim();
|
|
28905
|
+
var m = /[?&#]token=([^&\\s]+)/.exec(v);
|
|
28906
|
+
if (m) { try { return decodeURIComponent(m[1]); } catch (e) { return m[1]; } }
|
|
28907
|
+
return v;
|
|
28908
|
+
}
|
|
28909
|
+
function showForm(msg) {
|
|
28910
|
+
boot.style.display = "none";
|
|
28911
|
+
form.style.display = "block";
|
|
28912
|
+
if (msg) { errEl.textContent = msg; errEl.style.display = "flex"; }
|
|
28913
|
+
input.focus();
|
|
28914
|
+
}
|
|
28915
|
+
function fail(msg) {
|
|
28916
|
+
goBtn.disabled = false;
|
|
28917
|
+
goBtn.innerHTML = "\u89E3\u9501\u5E76\u8FDB\u5165";
|
|
28918
|
+
errEl.textContent = msg;
|
|
28919
|
+
errEl.style.display = "flex";
|
|
28920
|
+
form.classList.remove("bad");
|
|
28921
|
+
void form.offsetWidth; // reflow so the shake animation restarts
|
|
28922
|
+
form.classList.add("bad");
|
|
28923
|
+
input.focus();
|
|
28924
|
+
input.select();
|
|
28925
|
+
}
|
|
28926
|
+
peek.addEventListener("click", function () {
|
|
28927
|
+
var pw = input.type === "password";
|
|
28928
|
+
input.type = pw ? "text" : "password";
|
|
28929
|
+
peek.innerHTML = '<svg viewBox="0 0 24 24">' + (pw ? ${JSON.stringify(EYE_OFF_SVG)} : ${JSON.stringify(EYE_SVG)}) + "</svg>";
|
|
28930
|
+
peek.setAttribute("aria-label", pw ? "\u9690\u85CF\u4EE4\u724C" : "\u663E\u793A\u4EE4\u724C");
|
|
28931
|
+
input.focus();
|
|
28932
|
+
});
|
|
28933
|
+
input.addEventListener("input", function () {
|
|
28934
|
+
if (errEl.style.display !== "none") { errEl.style.display = "none"; form.classList.remove("bad"); }
|
|
28935
|
+
});
|
|
28936
|
+
|
|
28937
|
+
form.addEventListener("submit", function (ev) {
|
|
28394
28938
|
ev.preventDefault();
|
|
28395
|
-
|
|
28396
|
-
|
|
28939
|
+
var token = normalize(input.value);
|
|
28940
|
+
if (!token) { fail("\u8BF7\u8F93\u5165\u8BBF\u95EE\u4EE4\u724C\u3002"); return; }
|
|
28941
|
+
goBtn.disabled = true;
|
|
28942
|
+
goBtn.innerHTML = '<span class="spin"></span>\u9A8C\u8BC1\u4E2D\u2026';
|
|
28943
|
+
var hdr = { headers: { authorization: "Bearer " + token } };
|
|
28944
|
+
// Prefer the renewal endpoint (managed mode returns the canonical token,
|
|
28945
|
+
// also upgrading a pasted in-grace token). Fall back to a cheap
|
|
28946
|
+
// authenticated probe so we can reject a bad token *inline* instead of
|
|
28947
|
+
// storing it and reloading into another gate.
|
|
28948
|
+
fetch("${RENEW_PATH}", hdr)
|
|
28949
|
+
.then(function (r) { return r.ok ? r.json() : null; })
|
|
28950
|
+
.then(function (d) {
|
|
28951
|
+
if (d && d.token) { save(d.token); location.reload(); return; }
|
|
28952
|
+
return fetch("/api/version", hdr).then(function (r) {
|
|
28953
|
+
if (r.status === 401) { fail("\u4EE4\u724C\u65E0\u6548,\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002"); return; }
|
|
28954
|
+
// 200 (static-token mode) or no UI (404) \u2192 trust it and reload.
|
|
28955
|
+
save(token); location.reload();
|
|
28956
|
+
});
|
|
28957
|
+
})
|
|
28958
|
+
.catch(function () { save(token); location.reload(); }); // network hiccup \u2192 old behavior
|
|
28397
28959
|
});
|
|
28398
|
-
|
|
28399
|
-
//
|
|
28400
|
-
//
|
|
28960
|
+
|
|
28961
|
+
// Silent renewal on load: a held token may just need swapping for the current
|
|
28962
|
+
// one (rotation while this browser held the in-grace previous). Show the boot
|
|
28963
|
+
// loader meanwhile; drop to the form (with a hint) if it can't be renewed.
|
|
28401
28964
|
var stored = localStorage.getItem(KEY);
|
|
28402
28965
|
if (stored) {
|
|
28403
28966
|
fetch("${RENEW_PATH}", { headers: { authorization: "Bearer " + stored } })
|
|
28404
28967
|
.then(function (r) { return r.ok ? r.json() : null; })
|
|
28405
|
-
.then(function (d) {
|
|
28406
|
-
|
|
28968
|
+
.then(function (d) {
|
|
28969
|
+
if (d && d.token) { save(d.token); location.reload(); }
|
|
28970
|
+
else showForm("\u767B\u5F55\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u8F93\u5165\u4EE4\u724C\u3002");
|
|
28971
|
+
})
|
|
28972
|
+
.catch(function () { showForm(""); });
|
|
28407
28973
|
} else {
|
|
28408
|
-
showForm();
|
|
28974
|
+
showForm("");
|
|
28409
28975
|
}
|
|
28410
28976
|
</script>
|
|
28411
28977
|
</body></html>`;
|
|
@@ -28681,6 +29247,11 @@ var styles_default = ` :root {
|
|
|
28681
29247
|
svg { display: block; }
|
|
28682
29248
|
.ico { width:16px; height:16px; stroke:currentColor; fill:none; stroke-width:1.75; stroke-linecap:round; stroke-linejoin:round; flex:none; }
|
|
28683
29249
|
.ico.sm { width:14px; height:14px; }
|
|
29250
|
+
/* Every window (incl. quicknote) gets the same thin translucent scrollbar:
|
|
29251
|
+
transparent track, rounded translucent thumb. In Chromium 121+ the
|
|
29252
|
+
inherited html scrollbar-width/color renders it; the ::-webkit rules
|
|
29253
|
+
cover Safari. Both force classic (layout-consuming) mode \u2014 tight layouts
|
|
29254
|
+
pair scrollbar-gutter:stable with rebalanced insets (see .qn-body). */
|
|
28684
29255
|
::-webkit-scrollbar { width:10px; height:10px; }
|
|
28685
29256
|
::-webkit-scrollbar-thumb { background:var(--line-strong); border-radius:8px; border:3px solid transparent; background-clip:padding-box; }
|
|
28686
29257
|
::-webkit-scrollbar-thumb:hover { background:var(--muted); background-clip:padding-box; border:3px solid transparent; }
|
|
@@ -28729,12 +29300,45 @@ var styles_default = ` :root {
|
|
|
28729
29300
|
.sb-search input { border:0; background:none; outline:none; color:var(--fg); width:100%; }
|
|
28730
29301
|
.sb-search kbd { font-family:var(--mono); font-size:10px; color:var(--muted); border:1px solid var(--line-strong); border-radius:4px; padding:1px 4px; }
|
|
28731
29302
|
.sb-scroll { flex:1; overflow-y:auto; padding:4px 8px 24px; }
|
|
28732
|
-
|
|
28733
|
-
|
|
28734
|
-
|
|
28735
|
-
|
|
28736
|
-
.sb-
|
|
28737
|
-
.sb-
|
|
29303
|
+
/* Notion-style list switcher: the active tab is an icon+label pill, inactive
|
|
29304
|
+
tabs are icon-only. One absolutely-positioned indicator slides & stretches
|
|
29305
|
+
under the active button; JS keeps it in sync via ResizeObserver so it
|
|
29306
|
+
chases the label's 0fr\u21921fr expansion instead of jumping to a stale width. */
|
|
29307
|
+
.sb-tabs { position:relative; display:flex; align-items:center; gap:2px; margin:2px 12px 8px; }
|
|
29308
|
+
.sb-tab { position:relative; z-index:1; display:flex; align-items:center;
|
|
29309
|
+
padding:5px 7px; border-radius:var(--radius-sm); color:var(--muted); cursor:pointer;
|
|
29310
|
+
font-size:var(--fs-ui); transition:color .18s; }
|
|
29311
|
+
.sb-tab:hover { color:var(--fg-soft); }
|
|
29312
|
+
.sb-tab.on { color:var(--fg); font-weight:600; }
|
|
29313
|
+
/* Label expansion: animating the grid track times correctly for any label
|
|
29314
|
+
width (max-width can't); the inner span clips during the ride. The
|
|
29315
|
+
icon-text gap rides the same curve so collapsing leaves no seam. */
|
|
29316
|
+
.sb-tab .tab-label { display:grid; grid-template-columns:0fr; opacity:0;
|
|
29317
|
+
transition:grid-template-columns .24s cubic-bezier(.22,1,.36,1), opacity .18s ease; }
|
|
29318
|
+
.sb-tab .tab-label > span { overflow:hidden; white-space:nowrap; min-width:0;
|
|
29319
|
+
transition:padding-left .24s cubic-bezier(.22,1,.36,1); }
|
|
29320
|
+
.sb-tab.on .tab-label { grid-template-columns:1fr; opacity:1; }
|
|
29321
|
+
.sb-tab.on .tab-label > span { padding-left:6px; }
|
|
29322
|
+
.sb-tab-ind { position:absolute; left:0; top:0; bottom:0; z-index:0; width:0;
|
|
29323
|
+
border-radius:var(--radius-sm); background:var(--hover-2);
|
|
29324
|
+
transition:transform .24s cubic-bezier(.22,1,.36,1), width .24s cubic-bezier(.22,1,.36,1); }
|
|
29325
|
+
.sb-tabs .add { margin-left:auto; padding:3px; border-radius:5px; color:var(--muted); }
|
|
29326
|
+
.sb-tabs .add:hover { background:var(--hover-2); color:var(--fg); }
|
|
29327
|
+
/* Pane swap: the entering list slides in from the side its tab lives on. */
|
|
29328
|
+
.sb-pane { margin-top:4px; }
|
|
29329
|
+
.sb-pane.in-r { animation:sb-pane-r .2s cubic-bezier(.22,1,.36,1); }
|
|
29330
|
+
.sb-pane.in-l { animation:sb-pane-l .2s cubic-bezier(.22,1,.36,1); }
|
|
29331
|
+
@keyframes sb-pane-r { from { opacity:0; transform:translateX(14px); } }
|
|
29332
|
+
@keyframes sb-pane-l { from { opacity:0; transform:translateX(-14px); } }
|
|
29333
|
+
.sb-subfold .chev { transition:transform .12s; }
|
|
29334
|
+
.sb-subfold .chev.open { transform:rotate(90deg); }
|
|
29335
|
+
/* Collapsed-databases group: a quiet tail row inside the \u6570\u636E\u8868 list for
|
|
29336
|
+
tables flagged meta.collapsed (site-facing / rarely browsed). */
|
|
29337
|
+
.sb-subfold { display:flex; align-items:center; gap:2px; width:100%; text-align:left;
|
|
29338
|
+
padding:4px 6px; margin-top:2px; border-radius:var(--radius-sm);
|
|
29339
|
+
color:var(--muted); font-size:var(--fs-micro); cursor:pointer; }
|
|
29340
|
+
.sb-subfold:hover { background:var(--hover-2); color:var(--fg-soft); }
|
|
29341
|
+
.navitem.dim { opacity:.62; }
|
|
28738
29342
|
.navitem { display:flex; align-items:center; gap:3px; width:100%; text-align:left; padding:5px 6px; margin-bottom:2px; border-radius:var(--radius-sm);
|
|
28739
29343
|
color:var(--fg-soft); font-size:var(--fs-ui); position:relative; white-space:nowrap; transition:background .1s; }
|
|
28740
29344
|
.navitem:hover { background:var(--hover-2); }
|
|
@@ -28824,6 +29428,23 @@ var styles_default = ` :root {
|
|
|
28824
29428
|
.set-block-title { font-size:14px; font-weight:650; color:var(--fg); letter-spacing:-.005em; }
|
|
28825
29429
|
.set-block-desc { color:var(--fg-soft); font-size:var(--fs-sm); line-height:1.55; margin-bottom:14px; max-width:56ch; }
|
|
28826
29430
|
.set-block-desc:last-child { margin-bottom:0; }
|
|
29431
|
+
/* title+desc on the left, a control (e.g. a switch) pinned right \u2014 used for
|
|
29432
|
+
single boolean settings where a whole card of chrome would be overkill */
|
|
29433
|
+
.set-toggle-row { display:flex; align-items:center; justify-content:space-between; gap:24px; }
|
|
29434
|
+
.set-toggle-text { min-width:0; }
|
|
29435
|
+
.set-toggle-text .set-block-head { margin-bottom:4px; }
|
|
29436
|
+
.set-toggle-text .set-block-desc { margin-bottom:0; }
|
|
29437
|
+
/* iOS-style switch: a hidden checkbox drives a sliding track+thumb */
|
|
29438
|
+
.set-switch { position:relative; flex:none; display:inline-flex; align-items:center; cursor:pointer; }
|
|
29439
|
+
.set-switch input { position:absolute; width:1px; height:1px; opacity:0; margin:0; }
|
|
29440
|
+
.set-switch-track { display:inline-flex; align-items:center; width:40px; height:23px; padding:0 2px;
|
|
29441
|
+
border-radius:999px; background:var(--line-strong); transition:background .2s ease; }
|
|
29442
|
+
.set-switch-thumb { width:19px; height:19px; border-radius:50%; background:#fff;
|
|
29443
|
+
box-shadow:0 1px 3px rgba(20,20,40,.28); transition:transform .2s cubic-bezier(.4,0,.2,1); }
|
|
29444
|
+
.set-switch input:checked + .set-switch-track { background:var(--accent); }
|
|
29445
|
+
.set-switch input:checked + .set-switch-track .set-switch-thumb { transform:translateX(17px); }
|
|
29446
|
+
.set-switch:hover .set-switch-track { filter:brightness(.97); }
|
|
29447
|
+
.set-switch input:focus-visible + .set-switch-track { outline:2px solid var(--accent); outline-offset:2px; }
|
|
28827
29448
|
/* two-fact meta line under a block title (who publishes \xB7 where creds live) \u2014
|
|
28828
29449
|
answers the questions hiding under "is this bucket for server or browser?" */
|
|
28829
29450
|
.set-meta { display:flex; flex-wrap:wrap; gap:8px 16px; margin:0 0 12px; }
|
|
@@ -29023,10 +29644,19 @@ var styles_default = ` :root {
|
|
|
29023
29644
|
.sidebar.collapsed { overflow:hidden; }
|
|
29024
29645
|
.sidebar.collapsed .sb-resizer { pointer-events:none; }
|
|
29025
29646
|
.crumb { display:flex; align-items:center; gap:7px; flex:1; min-width:0; font-size:var(--fs-ui); color:var(--fg); font-weight:500; }
|
|
29026
|
-
|
|
29647
|
+
/* Long titles ellipsize on one line \u2014 never wrap and grow the topbar. */
|
|
29648
|
+
.crumb > span:not(.emoji) { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
29649
|
+
.crumb .emoji { font-size:15px; flex:none; } .crumb .sub { color:var(--muted); font-weight:400; }
|
|
29027
29650
|
.iconbtn { width:30px; height:30px; display:grid; place-items:center; border-radius:var(--radius-sm); color:var(--fg-soft); transition:background .12s; }
|
|
29028
29651
|
.iconbtn:hover { background:var(--hover-2); color:var(--fg); }
|
|
29029
|
-
|
|
29652
|
+
/* Reserve the classic-scrollbar gutter up front: view width never changes
|
|
29653
|
+
when content grows past one screen \u2014 no jump / rewrap flicker. stable
|
|
29654
|
+
ONLY (never both-edges): a left-edge gutter desyncs Chromium's composited
|
|
29655
|
+
scroll cull rect by the gutter width, leaving a permanent unpainted
|
|
29656
|
+
stripe over the rightmost 15px of the scrollport (content reaching into
|
|
29657
|
+
it gets visibly sliced \u2014 first seen slicing the quicknote file card).
|
|
29658
|
+
Inert on mobile, where .content becomes overflow:visible. */
|
|
29659
|
+
.content { flex:1; overflow:auto; scrollbar-gutter:stable; }
|
|
29030
29660
|
.btn { display:inline-flex; align-items:center; gap:6px; padding:6px 12px; border-radius:var(--radius-sm); font-size:13px; font-weight:500; transition:all .12s; white-space:nowrap; }
|
|
29031
29661
|
.btn-ghost { color:var(--fg-soft); } .btn-ghost:hover { background:var(--hover-2); color:var(--fg); }
|
|
29032
29662
|
.btn-secondary { background:var(--bg); border:1px solid var(--line-strong); color:var(--fg); box-shadow:var(--shadow-sm); }
|
|
@@ -29091,9 +29721,9 @@ var styles_default = ` :root {
|
|
|
29091
29721
|
.doc-conflict { display:flex; align-items:center; gap:10px; flex-wrap:wrap; padding:10px 14px; margin-bottom:16px; border:1px solid var(--danger); border-radius:var(--radius-sm); background:var(--danger-soft); font-size:13px; }
|
|
29092
29722
|
.doc-conflict-msg { color:var(--danger); font-weight:600; flex:1; min-width:180px; }
|
|
29093
29723
|
.doc.source-mode { min-height:100%; }
|
|
29094
|
-
|
|
29095
|
-
|
|
29096
|
-
|
|
29724
|
+
/* wide mode (\u22EF menu): lift the column cap; the 60px side padding stays as the
|
|
29725
|
+
reading gutter and keeps the fixed .doc-toc ticks off the text. */
|
|
29726
|
+
.doc.wide-mode { max-width:none; }
|
|
29097
29727
|
/* floating table of contents: a column of indented tick marks in the right
|
|
29098
29728
|
gutter that expands to a labelled list on hover (Notion / Vercel-docs style).
|
|
29099
29729
|
Fixed to the viewport so it never disturbs the centred .doc column. */
|
|
@@ -29132,49 +29762,33 @@ var styles_default = ` :root {
|
|
|
29132
29762
|
/* not enough room for the gutter \u2192 hide entirely (also covers mobile) */
|
|
29133
29763
|
@media (max-width:1100px) { .doc-toc { display:none; } }
|
|
29134
29764
|
|
|
29135
|
-
|
|
29136
|
-
|
|
29137
|
-
|
|
29138
|
-
|
|
29139
|
-
|
|
29140
|
-
|
|
29141
|
-
|
|
29142
|
-
|
|
29143
|
-
|
|
29144
|
-
|
|
29145
|
-
|
|
29146
|
-
.
|
|
29147
|
-
|
|
29148
|
-
.
|
|
29149
|
-
|
|
29150
|
-
.
|
|
29151
|
-
|
|
29152
|
-
|
|
29153
|
-
.
|
|
29154
|
-
|
|
29155
|
-
|
|
29156
|
-
.
|
|
29157
|
-
.
|
|
29158
|
-
|
|
29159
|
-
|
|
29160
|
-
code block's own gutter (it would overlap the list marker on the same row). */
|
|
29161
|
-
.block.list-code-host + .block-wrap.nested .gutter { display:none; }
|
|
29162
|
-
.editable { outline:none; flex:1; min-width:0; padding:3px 2px; line-height:var(--note-lh); }
|
|
29163
|
-
.editable:empty::before { content:attr(data-ph); color:var(--muted); pointer-events:none; }
|
|
29164
|
-
/* The generic "/" prompt only shows on the focused line; idle blank lines (paragraphs and list items, any depth) stay blank. */
|
|
29165
|
-
.editable[data-ph-hint="slash"]:empty:not(:focus)::before { content:""; }
|
|
29166
|
-
.b-h1 .editable { font-size:28px; font-weight:700; letter-spacing:-.02em; padding-top:12px; }
|
|
29167
|
-
.b-h2 .editable { font-size:22px; font-weight:650; letter-spacing:-.01em; padding-top:8px; }
|
|
29168
|
-
.b-h3 .editable { font-size:18px; font-weight:600; padding-top:4px; }
|
|
29169
|
-
.b-h4 .editable { font-size:16px; font-weight:600; padding-top:2px; }
|
|
29170
|
-
.b-h5 .editable { font-size:14px; font-weight:600; }
|
|
29171
|
-
.b-h6 .editable { font-size:13px; font-weight:600; color:var(--fg-soft); }
|
|
29172
|
-
.b-h1 .gutter { top:22px; } .b-h2 .gutter { top:14px; } .b-h3 .gutter { top:7px; }
|
|
29173
|
-
.b-h4 .gutter { top:4px; } .b-h5 .gutter { top:3px; } .b-h6 .gutter { top:2px; }
|
|
29174
|
-
.b-quote .editable { border-left:3px solid var(--line-strong); padding:1px 0 1px 16px; color:var(--fg-soft); font-style:italic; }
|
|
29765
|
+
/* floating word count: a small pill in the bottom-right gutter (fixed to the
|
|
29766
|
+
viewport, aligned with .doc-toc's right edge). Collapsed it hugs the \u5B57\u6570;
|
|
29767
|
+
hover expands the whole pill (square-off + surface bg) and reveals the char
|
|
29768
|
+
count + reading estimate. Centre-aligned throughout, and the collapsed detail
|
|
29769
|
+
is width:0 so its wider text can't stretch the pill. Purely client-side. */
|
|
29770
|
+
.doc-wc { position:fixed; right:18px; bottom:calc(16px + env(safe-area-inset-bottom)); z-index:40;
|
|
29771
|
+
display:flex; flex-direction:column; align-items:center; justify-content:center;
|
|
29772
|
+
padding:4px 12px; border:1px solid var(--line); border-radius:999px; background:var(--bg);
|
|
29773
|
+
color:var(--muted); font-size:var(--fs-sm); line-height:1.2; user-select:none;
|
|
29774
|
+
box-shadow:var(--shadow-sm); opacity:.66;
|
|
29775
|
+
transition:opacity .18s ease, border-radius .2s ease, background .18s ease, box-shadow .2s ease, color .18s ease; }
|
|
29776
|
+
.doc-wc:hover { opacity:1; border-radius:var(--radius); background:var(--surface); border-color:var(--line-strong);
|
|
29777
|
+
box-shadow:var(--shadow-md); color:var(--fg-soft); }
|
|
29778
|
+
.doc-wc-num { font-variant-numeric:tabular-nums; white-space:nowrap; }
|
|
29779
|
+
.doc-wc.sel .doc-wc-num { color:var(--accent); font-weight:550; }
|
|
29780
|
+
/* detail rows: collapsed to zero size until hover. width:0 keeps them from
|
|
29781
|
+
widening the pill; no container gap (a phantom gap would push the collapsed
|
|
29782
|
+
count off-centre) \u2014 the spacing comes from margin-top only when expanded. */
|
|
29783
|
+
.doc-wc-detail { display:flex; flex-direction:column; align-items:center; gap:2px;
|
|
29784
|
+
width:0; max-height:0; margin-top:0; overflow:hidden; opacity:0; font-size:12px; color:var(--muted);
|
|
29785
|
+
transition:max-height .2s ease, opacity .18s ease, margin-top .2s ease; }
|
|
29786
|
+
.doc-wc-detail span { font-variant-numeric:tabular-nums; white-space:nowrap; }
|
|
29787
|
+
.doc-wc:hover .doc-wc-detail { width:auto; max-height:40px; margin-top:4px; opacity:1; }
|
|
29788
|
+
/* quick-note mini window has no room for it */
|
|
29789
|
+
.qn-body .doc-wc { display:none; }
|
|
29175
29790
|
|
|
29176
29791
|
/* code block: transparent textarea over a highlight.js mirror */
|
|
29177
|
-
.b-code .codeblock { flex:1; min-width:0; }
|
|
29178
29792
|
.codeblock { position:relative; --code-fs:12.5px; --code-lh:1.55; --code-pad:8px; margin:2px 0;
|
|
29179
29793
|
background:var(--code-bg); border:1px solid var(--line); border-radius:8px; overflow:hidden; box-shadow:var(--shadow-sm); }
|
|
29180
29794
|
/* lang + copy float bottom-right, revealed on hover */
|
|
@@ -29183,27 +29797,57 @@ var styles_default = ` :root {
|
|
|
29183
29797
|
background:color-mix(in srgb,var(--code-bg) 82%,transparent); backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
|
|
29184
29798
|
opacity:0; transform:translateY(3px); pointer-events:none; transition:opacity .12s,transform .12s; }
|
|
29185
29799
|
.codeblock:hover .code-tools, .code-tools:focus-within { opacity:1; transform:none; pointer-events:auto; }
|
|
29800
|
+
/* hidden while editing (textarea focused) or whole-block selected \u2014 the pill would cover the
|
|
29801
|
+
bottom-right of the editing area; keep it if focus is on the pill itself (lang dropdown open) */
|
|
29802
|
+
.cm-void-code:focus-within .code-tools:not(:focus-within),
|
|
29803
|
+
.codeblock.ci-selected .code-tools:not(:focus-within) { opacity:0; transform:translateY(3px); pointer-events:none; }
|
|
29186
29804
|
.code-lang { position:relative; display:inline-flex; align-items:center; }
|
|
29187
29805
|
.code-lang select { appearance:none; -webkit-appearance:none; border:0; outline:none; background:none; cursor:pointer;
|
|
29188
29806
|
font-family:var(--mono); font-size:10.5px; font-weight:500; color:var(--fg-soft); padding:3px 17px 3px 7px; border-radius:5px; }
|
|
29189
29807
|
.code-lang select:hover { background:var(--hover-2); }
|
|
29190
29808
|
.code-lang svg { position:absolute; right:3px; width:12px; height:12px; pointer-events:none; color:var(--muted); }
|
|
29191
|
-
.code-copy { display:inline-flex; align-items:center; gap:4px; font-size:10.5px; font-weight:500; color:var(--muted);
|
|
29192
|
-
padding:3px 7px; border-radius:5px; transition:background .12s,color .12s; }
|
|
29193
|
-
.code-copy:hover { background:var(--hover-2); color:var(--fg-soft); }
|
|
29194
|
-
.code-copy.ok { color:var(--accent); }
|
|
29195
|
-
.code-
|
|
29809
|
+
.code-copy, .code-fmt, .code-wrap-btn { display:inline-flex; align-items:center; gap:4px; font-size:10.5px; font-weight:500; color:var(--muted);
|
|
29810
|
+
padding:3px 7px; border-radius:5px; transition:background .12s,color .12s; white-space:nowrap; }
|
|
29811
|
+
.code-copy:hover, .code-fmt:hover, .code-wrap-btn:hover { background:var(--hover-2); color:var(--fg-soft); }
|
|
29812
|
+
.code-copy.ok, .code-fmt.ok, .code-wrap-btn.on { color:var(--accent); }
|
|
29813
|
+
.code-fmt.err { color:var(--danger); }
|
|
29814
|
+
/* Default (no wrap): lines run long, the textarea scrolls horizontally and
|
|
29815
|
+
mirrors its scrollLeft onto the highlight layer; the gutter is a separate
|
|
29816
|
+
flex column of "1\\n2\\n3" (every logical line is exactly one row high). */
|
|
29817
|
+
.code-body { display:flex; align-items:stretch; font-family:var(--mono); font-size:var(--code-fs); line-height:var(--code-lh);
|
|
29818
|
+
--code-ln-ch:1ch; --code-gutter-w:calc(var(--code-ln-ch) + 20px); }
|
|
29196
29819
|
.code-gutter { flex:none; text-align:right; white-space:pre; user-select:none; color:var(--muted); opacity:.55;
|
|
29197
29820
|
padding:var(--code-pad) 8px var(--code-pad) 12px; border-right:1px solid var(--line); font-variant-numeric:tabular-nums; }
|
|
29198
29821
|
.code-scroll { position:relative; flex:1; min-width:0; }
|
|
29199
29822
|
.code-hl, .code-input { margin:0; font-family:var(--mono); font-size:var(--code-fs); line-height:var(--code-lh);
|
|
29200
29823
|
padding:var(--code-pad) 16px; tab-size:2; -moz-tab-size:2; white-space:pre; letter-spacing:0; }
|
|
29201
29824
|
.code-hl { position:absolute; inset:0; z-index:0; overflow:hidden; pointer-events:none; background:none; color:var(--fg); }
|
|
29202
|
-
.code-hl code { display:block; font:inherit; background:none; padding:0; }
|
|
29825
|
+
.code-hl code { display:block; font:inherit; background:none; padding:0; counter-reset:code-ln; }
|
|
29826
|
+
.code-hl-line { counter-increment:code-ln;
|
|
29827
|
+
min-height:calc(var(--code-fs) * var(--code-lh)); /* empty logical line still occupies its row */ }
|
|
29203
29828
|
.code-input { display:block; position:relative; z-index:1; width:100%; border:0; outline:none; resize:none;
|
|
29204
29829
|
overflow-x:auto; overflow-y:hidden; background:transparent; color:transparent; caret-color:var(--fg);
|
|
29205
29830
|
min-height:calc(var(--code-fs) * var(--code-lh) + var(--code-pad) * 2); }
|
|
29206
29831
|
.code-input::placeholder { color:var(--muted); }
|
|
29832
|
+
/* Wrap mode (.wrap, global toggle in the tools pill, persisted): textarea and
|
|
29833
|
+
mirror share pre-wrap + break-word (the UA textarea wrap rules), so their
|
|
29834
|
+
wrap points match and the caret stays on the glyphs. The flex gutter would
|
|
29835
|
+
misalign (a logical line can span several visual rows), so it hides and
|
|
29836
|
+
line numbers become CSS counters on the mirror's per-logical-line blocks \u2014
|
|
29837
|
+
a wrapped line grows its block and the next number moves with it, no JS
|
|
29838
|
+
height sync. --code-ln-ch (digit count) is set by paint(). */
|
|
29839
|
+
.code-body.wrap { display:block; position:relative; }
|
|
29840
|
+
.code-body.wrap::before { content:""; position:absolute; left:var(--code-gutter-w); top:0; bottom:0;
|
|
29841
|
+
width:1px; background:var(--line); }
|
|
29842
|
+
.code-body.wrap .code-gutter { display:none; }
|
|
29843
|
+
.code-body.wrap .code-hl, .code-body.wrap .code-input {
|
|
29844
|
+
padding-left:calc(var(--code-gutter-w) + 17px);
|
|
29845
|
+
white-space:pre-wrap; overflow-wrap:break-word; }
|
|
29846
|
+
.code-body.wrap .code-input { overflow:hidden; }
|
|
29847
|
+
.code-body.wrap .code-hl-line { position:relative; }
|
|
29848
|
+
.code-body.wrap .code-hl-line::before { content:counter(code-ln); position:absolute; top:0;
|
|
29849
|
+
left:calc(-17px - var(--code-gutter-w)); width:calc(var(--code-gutter-w) - 8px);
|
|
29850
|
+
text-align:right; color:var(--muted); opacity:.55; font-variant-numeric:tabular-nums; }
|
|
29207
29851
|
|
|
29208
29852
|
/* highlight.js token theme (cohesive with the app palette) */
|
|
29209
29853
|
.hljs-comment, .hljs-quote { color:var(--hl-cmt); font-style:italic; }
|
|
@@ -29217,24 +29861,50 @@ var styles_default = ` :root {
|
|
|
29217
29861
|
.hljs-params, .hljs-subst { color:var(--fg); }
|
|
29218
29862
|
.hljs-emphasis { font-style:italic; }
|
|
29219
29863
|
.hljs-strong { font-weight:700; }
|
|
29220
|
-
.marker { width:24px; flex:none; text-align:center; color:var(--fg-soft); user-select:none; padding-top:4px; }
|
|
29221
|
-
.b-todo .marker { box-sizing:content-box; padding-top:3px; height:calc(1em * var(--note-lh));
|
|
29222
|
-
display:flex; align-items:center; justify-content:center; }
|
|
29223
|
-
.b-todo .marker input { width:15px; height:15px; accent-color:var(--accent); cursor:pointer; }
|
|
29224
|
-
.b-divider { padding:10px 0; }
|
|
29225
|
-
.b-divider hr { border:0; border-top:1px solid var(--line-strong); margin:0; width:100%; }
|
|
29226
|
-
.b-done .editable { color:var(--muted); text-decoration:line-through; }
|
|
29227
|
-
.editable b, .editable strong { font-weight:700; }
|
|
29228
|
-
.editable code { font-family:var(--mono); background:var(--surface-2); padding:1px 5px; border-radius:4px; font-size:.9em; }
|
|
29229
|
-
.editable a { color:var(--accent); }
|
|
29230
|
-
/* document images (pasted/dropped \u2192 /blob/<hash>); fetched on demand */
|
|
29231
|
-
.editable img.doc-img { max-width:100%; height:auto; border-radius:8px; margin:6px 0; display:block; vertical-align:bottom; }
|
|
29232
29864
|
|
|
29233
|
-
/*
|
|
29234
|
-
|
|
29235
|
-
|
|
29236
|
-
|
|
29865
|
+
/* CodeIsland (CM6 void widget): the tools pill (lang + copy) is the only
|
|
29866
|
+
focus-state chrome \u2014 an absolute overlay, so revealing it never changes the
|
|
29867
|
+
block's height (no layout shift on click). .ci-selected marks the island
|
|
29868
|
+
when the CM selection spans the whole void (Escape from inside / Backspace
|
|
29869
|
+
from the line below). */
|
|
29870
|
+
.cm-void-code .codeblock.ci-selected { box-shadow:0 0 0 2px var(--accent); }
|
|
29871
|
+
|
|
29872
|
+
/* Whole-void selected (the CM selection spans the block \u2014 click-to-select on
|
|
29873
|
+
media, Backspace-from-below, select-all): 2px accent ring, the old editor's
|
|
29874
|
+
\`.block.selected .void-block\` treatment. Code draws its own via .ci-selected. */
|
|
29875
|
+
/* Intrinsic-width firewall (same problem the doc table solved with
|
|
29876
|
+
contain:inline-size on .doc-table-wrap): a void widget's max-content \u2014
|
|
29877
|
+
e.g. a file card whose nowrap filename caps at 480px \u2014 must not propagate
|
|
29878
|
+
into .cm-content and push the whole editor wider than a narrow window
|
|
29879
|
+
(quick notes), shoving the card's right edge offscreen. width:0 zeroes the
|
|
29880
|
+
host's intrinsic contribution; min-width:100% restores the line width at
|
|
29881
|
+
layout time; the card's own min-width:0 + ellipsis then get to run.
|
|
29882
|
+
NOT contain:inline-size: Chromium 130's ink-overflow culling clips a
|
|
29883
|
+
size-contained host's paint at a stale boundary on 2x displays \u2014 the
|
|
29884
|
+
card's right border and selection ring were visibly sliced off. */
|
|
29885
|
+
.cm-void { box-sizing:border-box; width:0; min-width:100%; }
|
|
29886
|
+
.cm-void.selected .void-block { box-shadow:0 0 0 2px var(--accent); }
|
|
29887
|
+
.cm-void.selected table.doc-table { box-shadow:0 0 0 2px var(--accent), var(--shadow-sm); }
|
|
29888
|
+
|
|
29889
|
+
/* Editor text selection: one accent tint for BOTH the native ::selection and
|
|
29890
|
+
.cm-mk-sel, the class block-deco puts on marker widgets (bullet / ordered
|
|
29891
|
+
number / checkbox) whose marker range the selection covers. Native selection
|
|
29892
|
+
cannot paint replaced widgets, which left holes in the marker column during
|
|
29893
|
+
drag-select / select-all; unifying the two colors makes the line read as one
|
|
29894
|
+
continuous highlight (and tracks the theme in dark mode). */
|
|
29895
|
+
.cm-content ::selection { background: color-mix(in srgb, var(--accent) 24%, transparent); }
|
|
29896
|
+
.cm-content .cm-mk-sel { background: color-mix(in srgb, var(--accent) 24%, transparent); }
|
|
29897
|
+
/* bullet/number boxes are 24px + 2px margin-right; the margin can't take a
|
|
29898
|
+
background, so a same-color shadow fills the seam up to the content column */
|
|
29899
|
+
.cm-content .cm-bullet.cm-mk-sel, .cm-content .cm-ol-num.cm-mk-sel {
|
|
29900
|
+
box-shadow: 2px 0 0 color-mix(in srgb, var(--accent) 24%, transparent);
|
|
29901
|
+
}
|
|
29902
|
+
/* the glyph/number text inside a painted marker also sits in the DOM selection;
|
|
29903
|
+
without this it gets the ::selection tint ON TOP of the span background and
|
|
29904
|
+
reads darker than the rest of the line */
|
|
29905
|
+
.cm-content .cm-mk-sel::selection, .cm-content .cm-mk-sel ::selection { background: transparent; }
|
|
29237
29906
|
|
|
29907
|
+
/* ---- block-level void embeds: image / video / audio / file / html ---- */
|
|
29238
29908
|
.void-image { position:relative; display:inline-block; max-width:100%; border-radius:8px; line-height:0; }
|
|
29239
29909
|
.void-image img { display:block; width:100%; max-width:100%; height:auto; border-radius:8px; user-select:none; }
|
|
29240
29910
|
.void-image .void-expand { position:absolute; top:8px; right:8px; width:28px; height:28px; display:grid; place-items:center;
|
|
@@ -29272,7 +29942,6 @@ var styles_default = ` :root {
|
|
|
29272
29942
|
color:var(--fg-soft); font-size:var(--fs-micro); transition:background .12s; }
|
|
29273
29943
|
.void-html .html-toggle:hover { background:var(--hover-2); color:var(--fg); }
|
|
29274
29944
|
.void-html .html-toggle.on { background:var(--accent-soft); color:var(--accent); }
|
|
29275
|
-
.void-html .html-source { width:100%; min-height:120px; padding:12px; border:0; background:var(--bg); resize:vertical; }
|
|
29276
29945
|
.void-html .html-frame { display:block; width:100%; border:0; background:var(--bg); }
|
|
29277
29946
|
.void-html .html-empty { padding:24px; text-align:center; color:var(--muted); cursor:text; font-size:var(--fs-ui); }
|
|
29278
29947
|
|
|
@@ -29283,30 +29952,47 @@ var styles_default = ` :root {
|
|
|
29283
29952
|
.lightbox-toolbar { flex:none; display:flex; align-items:center; gap:6px; padding:10px 14px; color:#fff; }
|
|
29284
29953
|
.lightbox-toolbar .lightbox-name { font-size:var(--fs-ui); opacity:.85; max-width:40vw; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
29285
29954
|
.lightbox-toolbar .lightbox-spacer { flex:1; }
|
|
29286
|
-
.lightbox-toolbar button { width:34px; height:34px; display:grid; place-items:center; border-radius:8px; color:#fff;
|
|
29955
|
+
.lightbox-toolbar > button { width:34px; height:34px; display:grid; place-items:center; border-radius:8px; color:#fff;
|
|
29287
29956
|
background:rgba(255,255,255,.08); transition:background .12s; }
|
|
29288
|
-
.lightbox-toolbar button:hover { background:rgba(255,255,255,.2); }
|
|
29957
|
+
.lightbox-toolbar > button:hover { background:rgba(255,255,255,.2); }
|
|
29289
29958
|
.lightbox-toolbar .lightbox-pct { width:auto; min-width:52px; font-size:var(--fs-micro); font-variant-numeric:tabular-nums; }
|
|
29959
|
+
.lightbox-toolbar .ico { width:16px; height:16px; stroke-width:2; }
|
|
29290
29960
|
.lightbox-stage { flex:1; min-height:0; overflow:hidden; display:grid; place-items:center; }
|
|
29291
29961
|
.lightbox-stage img { max-width:94vw; max-height:100%; will-change:transform; -webkit-user-drag:none; user-select:none; }
|
|
29292
29962
|
|
|
29293
29963
|
/* ---- image annotator ---- */
|
|
29294
29964
|
.annot { flex:1; min-height:0; display:flex; flex-direction:column; }
|
|
29295
|
-
|
|
29296
|
-
|
|
29297
|
-
.annot-
|
|
29298
|
-
.annot-
|
|
29299
|
-
.annot-
|
|
29300
|
-
|
|
29301
|
-
.annot-
|
|
29302
|
-
.annot-
|
|
29303
|
-
.annot-
|
|
29965
|
+
/* Single-row chrome: filename \xB7 segmented tools \xB7 colors \xB7 undo/redo \xB7
|
|
29966
|
+
cancel/save \xB7 close. Wraps only as a narrow-window fallback. */
|
|
29967
|
+
.annot-bar { flex-wrap:wrap; row-gap:6px; }
|
|
29968
|
+
.annot-seg { display:flex; align-items:center; gap:2px; padding:2px; border-radius:9px; background:rgba(255,255,255,.1); }
|
|
29969
|
+
.annot-seg-btn { width:30px; height:26px; display:grid; place-items:center; border-radius:7px;
|
|
29970
|
+
color:rgba(255,255,255,.72); transition:background .12s, color .12s; }
|
|
29971
|
+
.annot-seg-btn:hover { color:#fff; background:rgba(255,255,255,.12); }
|
|
29972
|
+
.annot-seg-btn.on { background:#fff; color:#1c1c26; box-shadow:0 1px 2px rgba(0,0,0,.3); }
|
|
29973
|
+
.annot-div { flex:none; width:1px; height:18px; margin:0 5px; background:rgba(255,255,255,.18); }
|
|
29974
|
+
.annot-colors { display:flex; align-items:center; gap:8px; padding:0 2px; }
|
|
29975
|
+
.annot-swatch { width:15px; height:15px; border-radius:50%; box-shadow:inset 0 0 0 1px rgba(255,255,255,.3);
|
|
29976
|
+
transition:transform .12s, box-shadow .12s; }
|
|
29977
|
+
.annot-swatch:hover { transform:scale(1.18); }
|
|
29978
|
+
.annot-swatch.on { box-shadow:inset 0 0 0 1px rgba(255,255,255,.3), 0 0 0 2px rgba(12,12,18,.9), 0 0 0 3.5px rgba(255,255,255,.92); }
|
|
29979
|
+
.annot-bar .annot-icon-btn { width:30px; height:30px; display:grid; place-items:center; border-radius:7px;
|
|
29980
|
+
color:rgba(255,255,255,.85); background:none; transition:background .12s; }
|
|
29981
|
+
.annot-bar .annot-icon-btn:hover { background:rgba(255,255,255,.14); }
|
|
29982
|
+
.annot-bar .annot-icon-btn:disabled { opacity:.35; cursor:default; background:none; }
|
|
29983
|
+
.annot-actions { display:flex; align-items:center; gap:8px; margin:0 2px 0 4px; }
|
|
29304
29984
|
.annot-stage { flex:1; min-height:0; overflow:auto; display:grid; place-items:center; padding:8px 14px 18px; }
|
|
29305
29985
|
.annot-img-wrap { position:relative; line-height:0; }
|
|
29306
29986
|
.annot-img-wrap img { display:block; max-width:90vw; max-height:78vh; width:auto; height:auto; -webkit-user-drag:none; user-select:none; }
|
|
29307
|
-
.annot-canvas { position:absolute; inset:0; width:100%; height:100%; }
|
|
29987
|
+
.annot-canvas { position:absolute; inset:0; width:100%; height:100%; touch-action:none; }
|
|
29308
29988
|
.annot-canvas.tool-text { cursor:text; }
|
|
29309
29989
|
.annot-canvas.tool-rect, .annot-canvas.tool-arrow { cursor:crosshair; }
|
|
29990
|
+
/* Inline text overlay: WYSIWYG twin of the flattened canvas text (same font,
|
|
29991
|
+
line-height and halo), plus an accent ring so the edit region reads. */
|
|
29992
|
+
.annot-text-input { position:absolute; z-index:2; min-width:60px; padding:2px 4px; margin:0; border:0; outline:none;
|
|
29993
|
+
resize:none; overflow:hidden; white-space:pre; background:transparent; border-radius:4px; caret-color:currentColor;
|
|
29994
|
+
font:600 20px/1.3 system-ui, -apple-system, sans-serif; text-shadow:0 1px 2px rgba(0,0,0,.55);
|
|
29995
|
+
box-shadow:0 0 0 1.5px var(--accent), 0 0 0 4px color-mix(in srgb, var(--accent) 25%, transparent); }
|
|
29310
29996
|
|
|
29311
29997
|
/* ---- transient "uploading" placeholder + unavailable fallback ---- */
|
|
29312
29998
|
.ico.spin { animation:mh-spin .8s linear infinite; }
|
|
@@ -29315,7 +30001,10 @@ var styles_default = ` :root {
|
|
|
29315
30001
|
display:flex; align-items:center; gap:12px; margin:2px 0; max-width:480px; padding:12px 14px;
|
|
29316
30002
|
border:1px solid var(--line-strong); border-radius:var(--radius); background:var(--surface); color:var(--fg-soft); }
|
|
29317
30003
|
.void-uploading { border-style:dashed; }
|
|
29318
|
-
|
|
30004
|
+
/* min-width:0: .void-uploading's vu-name is a direct flex item \u2014 without it a
|
|
30005
|
+
long nowrap filename sets the item's min-content floor and the placeholder
|
|
30006
|
+
card overflows a narrow window instead of ellipsizing. */
|
|
30007
|
+
.void-uploading .vu-name, .void-unavailable .vu-name { font-weight:600; color:var(--fg); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; min-width:0; }
|
|
29319
30008
|
.void-uploading .vu-sub, .void-unavailable .vu-sub { font-size:var(--fs-micro); color:var(--muted); }
|
|
29320
30009
|
.void-unavailable { border-color:var(--danger-soft); color:var(--danger); }
|
|
29321
30010
|
.void-unavailable .ico { color:var(--danger); flex:none; }
|
|
@@ -29361,24 +30050,53 @@ var styles_default = ` :root {
|
|
|
29361
30050
|
/* Chrome rides the theme-tinted glass \u2192 theme-aware (var(--fg)), readable on a
|
|
29362
30051
|
light or dark tint alike. */
|
|
29363
30052
|
body.preview-window .lightbox-toolbar { color:var(--fg); }
|
|
29364
|
-
body.preview-window .lightbox-toolbar button,
|
|
29365
|
-
body.preview-window .
|
|
29366
|
-
body.preview-window .
|
|
29367
|
-
body.preview-window .annot-
|
|
29368
|
-
body.preview-window .annot-
|
|
29369
|
-
body.preview-window .annot-
|
|
30053
|
+
body.preview-window .lightbox-toolbar > button { color:var(--fg); background:color-mix(in srgb, var(--fg) 10%, transparent); }
|
|
30054
|
+
body.preview-window .lightbox-toolbar > button:hover { background:color-mix(in srgb, var(--fg) 20%, transparent); }
|
|
30055
|
+
body.preview-window .annot-seg { background:color-mix(in srgb, var(--fg) 8%, transparent); }
|
|
30056
|
+
body.preview-window .annot-seg-btn { color:color-mix(in srgb, var(--fg) 65%, transparent); }
|
|
30057
|
+
body.preview-window .annot-seg-btn:hover { color:var(--fg); background:color-mix(in srgb, var(--fg) 10%, transparent); }
|
|
30058
|
+
body.preview-window .annot-seg-btn.on { background:var(--bg); color:var(--fg); box-shadow:var(--shadow-sm); }
|
|
30059
|
+
body.preview-window .annot-div { background:color-mix(in srgb, var(--fg) 15%, transparent); }
|
|
30060
|
+
body.preview-window .annot-swatch { box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--fg) 25%, transparent); }
|
|
30061
|
+
body.preview-window .annot-swatch.on { box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--fg) 25%, transparent),
|
|
30062
|
+
0 0 0 2px var(--bg), 0 0 0 3.5px color-mix(in srgb, var(--fg) 78%, transparent); }
|
|
30063
|
+
body.preview-window .annot-bar .annot-icon-btn { color:var(--fg); background:none; }
|
|
30064
|
+
body.preview-window .annot-bar .annot-icon-btn:hover { background:color-mix(in srgb, var(--fg) 12%, transparent); }
|
|
30065
|
+
body.preview-window .annot-bar .annot-icon-btn:disabled { background:none; }
|
|
29370
30066
|
/* In the frameless window the toolbar doubles as the OS drag region; its
|
|
29371
30067
|
buttons opt back out so they stay clickable. */
|
|
29372
30068
|
.lightbox-toolbar.app-drag { -webkit-app-region:drag; }
|
|
29373
30069
|
.lightbox-toolbar.app-drag button { -webkit-app-region:no-drag; }
|
|
29374
30070
|
|
|
29375
|
-
/* document table (GFM pipe table block)
|
|
29376
|
-
|
|
30071
|
+
/* document table (GFM pipe table block). contain:inline-size zeroes the
|
|
30072
|
+
widget's intrinsic-width contribution \u2014 otherwise the inner
|
|
30073
|
+
width:max-content propagates through overflow-x:auto into .cm-content's
|
|
30074
|
+
min-width:auto floor (intrinsic sizing ignores overflow) and pushes the
|
|
30075
|
+
whole page wider than the viewport on narrow screens. With the intrinsic
|
|
30076
|
+
loop broken, .doc-table-wrap resolves to the doc column width and the
|
|
30077
|
+
scroll box below finally gets to scroll. container-type additionally
|
|
30078
|
+
unlocks cqw for the sticky add-row bar (old engines fall back to contain);
|
|
30079
|
+
position:relative anchors the gutter row handle explicitly rather than
|
|
30080
|
+
leaning on container-type's implied containing block. */
|
|
30081
|
+
.doc-table-wrap { position:relative; contain:inline-size; container-type:inline-size; }
|
|
29377
30082
|
.doc-table-scroll { overflow-x:auto; padding:2px 0; }
|
|
29378
|
-
.doc-table-inner { width:max-content; }
|
|
30083
|
+
.doc-table-inner { position:relative; width:max-content; } /* anchors the drag outline / drop lines so they track horizontal scroll */
|
|
29379
30084
|
.doc-table-row { display:flex; align-items:stretch; }
|
|
29380
30085
|
table.doc-table { border-collapse:separate; border-spacing:0; table-layout:fixed; width:max-content;
|
|
29381
30086
|
border:1px solid var(--line); border-radius:var(--radius-sm); overflow:hidden; box-shadow:var(--shadow-sm); }
|
|
30087
|
+
/* Default (no manual widths yet): browser auto table layout sizes columns by
|
|
30088
|
+
content, capped to the wrap (cqw works despite the max-content .doc-table-inner;
|
|
30089
|
+
26px keeps the add-col button inside) so it wraps instead of scrolling. The
|
|
30090
|
+
first resizer drag freezes measured widths and drops this class (table-block.tsx). */
|
|
30091
|
+
table.doc-table.autofit { table-layout:auto; width:auto; max-width:calc(100cqw - 26px); }
|
|
30092
|
+
table.doc-table.autofit .doc-td { min-width:48px; } /* empty columns don't collapse */
|
|
30093
|
+
/* Code tokens are atomic: raising the column's min-content makes the auto
|
|
30094
|
+
algorithm shed width into wrappable prose columns instead of breaking
|
|
30095
|
+
\`file-names.md\` at hyphens; an over-long token falls back to the scroll
|
|
30096
|
+
box. Autofit only \u2014 in manual fixed layout nowrap can't grow the column,
|
|
30097
|
+
it would overflow the cell. Phones relax this (see the 560px block):
|
|
30098
|
+
there the atom IS the cap, and it crushes prose columns to their floor. */
|
|
30099
|
+
table.doc-table.autofit .doc-td code { white-space:nowrap; }
|
|
29382
30100
|
table.doc-table td { position:relative; vertical-align:top; padding:0;
|
|
29383
30101
|
border-right:1px solid var(--line); border-bottom:1px solid var(--line); }
|
|
29384
30102
|
table.doc-table tr td:last-child { border-right:0; }
|
|
@@ -29390,24 +30108,59 @@ var styles_default = ` :root {
|
|
|
29390
30108
|
.doc-td b, .doc-td strong { font-weight:700; }
|
|
29391
30109
|
.doc-td code { font-family:var(--mono); background:var(--surface-2); padding:1px 5px; border-radius:4px; font-size:.9em; }
|
|
29392
30110
|
.doc-td a { color:var(--accent); }
|
|
29393
|
-
/* header cell: column menu + resize handle */
|
|
29394
|
-
.doc-col-menu { position:absolute; top:4px; right:4px; width:18px; height:18px; display:grid; place-items:center;
|
|
29395
|
-
color:var(--muted); border-radius:4px; opacity:0; transition:opacity .12s,background .12s; }
|
|
29396
|
-
.doc-th:hover .doc-col-menu { opacity:1; }
|
|
29397
|
-
.doc-col-menu:hover { background:var(--hover-2); color:var(--fg); }
|
|
29398
30111
|
.doc-col-resizer { position:absolute; top:0; right:-4px; width:7px; height:100%; cursor:col-resize; z-index:3; touch-action:none; }
|
|
29399
|
-
/*
|
|
29400
|
-
|
|
29401
|
-
|
|
29402
|
-
|
|
29403
|
-
|
|
29404
|
-
|
|
30112
|
+
/* Row/column pill handles (Notion-style): one per axis, tracked onto the
|
|
30113
|
+
active cell (hovered on desktop, focused on touch) by JS. They live on
|
|
30114
|
+
.doc-table-wrap OUTSIDE .doc-table-scroll so overflow-x can't clip them,
|
|
30115
|
+
straddling the table's left/top border \u2014 never on cell text. Resting =
|
|
30116
|
+
quiet grey pill; pressed/dragging (.grab) = accent pill with light dots
|
|
30117
|
+
plus the source outline + drop line below. touch-action:none so a finger
|
|
30118
|
+
drag on the handle reorders instead of scrolling. Data rows only get a
|
|
30119
|
+
row pill (the block gutter's +/grip pins at the header row's y). */
|
|
30120
|
+
.doc-row-handle, .doc-col-handle { position:absolute; display:grid; place-items:center; z-index:7;
|
|
30121
|
+
color:var(--muted); background:var(--bg); border:1px solid var(--line); box-shadow:var(--shadow-sm);
|
|
30122
|
+
cursor:grab; touch-action:none; animation:gripFade .12s ease both;
|
|
30123
|
+
transition:background .12s,color .12s,border-color .12s; }
|
|
30124
|
+
.doc-row-handle { left:-8px; width:15px; height:28px; border-radius:8px; }
|
|
30125
|
+
.doc-col-handle { top:-6px; width:28px; height:15px; border-radius:8px; transform:translateX(-50%); }
|
|
30126
|
+
.doc-row-handle svg, .doc-col-handle svg { width:13px; height:13px; }
|
|
30127
|
+
.doc-row-handle:hover, .doc-col-handle:hover { background:var(--surface); color:var(--fg); }
|
|
30128
|
+
.doc-row-handle.grab, .doc-col-handle.grab { background:var(--accent); color:var(--accent-fg,#fff);
|
|
30129
|
+
border-color:var(--accent); cursor:grabbing; }
|
|
30130
|
+
.doc-row-handle::after { content:""; position:absolute; inset:-4px; }
|
|
30131
|
+
.doc-col-handle::after { content:""; position:absolute; inset:-4px; }
|
|
30132
|
+
/* drag-reorder overlays (inside .doc-table-inner, so they scroll with the
|
|
30133
|
+
table): accent outline on the source row/column, 2px line at the drop
|
|
30134
|
+
boundary (grid .rowdrop's cousin) */
|
|
30135
|
+
.doc-drag-outline { position:absolute; border:2px solid var(--accent); border-radius:6px;
|
|
30136
|
+
pointer-events:none; z-index:6; box-sizing:border-box; }
|
|
30137
|
+
.doc-rowdrop { position:absolute; height:2px; margin-top:-1px; background:var(--accent); border-radius:1px; pointer-events:none; z-index:6; }
|
|
30138
|
+
.doc-coldrop { position:absolute; width:2px; margin-left:-1px; background:var(--accent); border-radius:1px; pointer-events:none; z-index:6; }
|
|
30139
|
+
/* touch selection action bar: the OSK has no Delete/\u2318C, so the cell
|
|
30140
|
+
rectangle gets on-screen verbs; sits on the wrap layer above the selection */
|
|
30141
|
+
.doc-sel-bar { position:absolute; z-index:8; display:flex; gap:2px; padding:3px;
|
|
30142
|
+
background:var(--accent); border-radius:9px; box-shadow:var(--shadow-sm); animation:gripFade .12s ease both; }
|
|
30143
|
+
.doc-sel-bar button { color:var(--accent-fg,#fff); font-size:13px; line-height:1; padding:5px 9px; border-radius:6px; }
|
|
30144
|
+
.doc-sel-bar button:active { background:color-mix(in srgb, #000 18%, transparent); }
|
|
29405
30145
|
/* add-column (right edge) and add-row (bottom edge) buttons */
|
|
29406
30146
|
.doc-table-addcol { width:22px; margin-left:4px; flex:none; display:grid; place-items:center; color:var(--muted);
|
|
29407
|
-
border:1px dashed var(--line-strong); border-radius:var(--radius-sm); background:var(--surface); transition:background .12s,color .12s,border-color .12s; }
|
|
29408
|
-
|
|
29409
|
-
|
|
30147
|
+
border:1px dashed var(--line-strong); border-radius:var(--radius-sm); background:var(--surface); transition:background .12s,color .12s,border-color .12s,opacity .12s; }
|
|
30148
|
+
/* sticky + 100cqw (the wrap is the container): on a wide table the bar pins
|
|
30149
|
+
to the scrollport at any horizontal offset; narrow tables never hit the
|
|
30150
|
+
max-width and keep their table-wide bar. Engines without cqw just ignore
|
|
30151
|
+
the cap and fall back to scrolling with the table. */
|
|
30152
|
+
.doc-table-addrow { width:100%; max-width:100cqw; position:sticky; left:0; height:22px; margin-top:4px; display:grid; place-items:center; color:var(--muted);
|
|
30153
|
+
border:1px dashed var(--line-strong); border-radius:var(--radius-sm); background:var(--surface); transition:background .12s,color .12s,border-color .12s,opacity .12s; }
|
|
29410
30154
|
.doc-table-addcol:hover, .doc-table-addrow:hover { background:var(--accent-soft); color:var(--accent); border-color:var(--accent); }
|
|
30155
|
+
/* Notion-style: the add bars only materialize while the table is active \u2014
|
|
30156
|
+
hover or keyboard focus on desktop, an editing (focused) cell on touch.
|
|
30157
|
+
Opacity-only so nothing shifts; pointer-events gates off the invisible
|
|
30158
|
+
bars (a touch tap must not hit a bar it can't see). */
|
|
30159
|
+
.doc-table-addrow, .doc-table-addcol { opacity:0; pointer-events:none; }
|
|
30160
|
+
.doc-table-wrap:focus-within :is(.doc-table-addrow, .doc-table-addcol) { opacity:1; pointer-events:auto; }
|
|
30161
|
+
@media (hover:hover) and (pointer:fine) {
|
|
30162
|
+
.doc-table-wrap:hover :is(.doc-table-addrow, .doc-table-addcol) { opacity:1; pointer-events:auto; }
|
|
30163
|
+
}
|
|
29411
30164
|
/* cell range selection (box select): soft fill per cell; the accent rectangle
|
|
29412
30165
|
outline is drawn via inline inset box-shadow on the edge cells (see
|
|
29413
30166
|
cell-select.ts edgeShadow). While selecting, suppress the caret + native
|
|
@@ -29602,7 +30355,7 @@ var styles_default = ` :root {
|
|
|
29602
30355
|
.shv-search { display:flex; align-items:center; gap:6px; background:var(--bg); border:1px solid var(--line-strong); border-radius:var(--radius-sm); padding:5px 10px; color:var(--muted); }
|
|
29603
30356
|
.shv-search input { border:0; background:none; outline:none; color:var(--fg); font-size:13px; width:180px; }
|
|
29604
30357
|
|
|
29605
|
-
.shv-list { display:flex; flex-direction:column; gap:8px; }
|
|
30358
|
+
.shv-list { display:flex; flex-direction:column; gap:8px; list-style:none; padding:0; margin:0; }
|
|
29606
30359
|
.shv-row { display:flex; align-items:center; gap:13px; padding:13px 15px; background:var(--bg); border:1px solid var(--line);
|
|
29607
30360
|
border-radius:var(--radius-lg); transition:border-color .12s, box-shadow .12s; }
|
|
29608
30361
|
.shv-row:hover { border-color:var(--line-strong); box-shadow:var(--shadow-sm); }
|
|
@@ -29624,7 +30377,25 @@ var styles_default = ` :root {
|
|
|
29624
30377
|
.shv-exp.dead { text-decoration:line-through; }
|
|
29625
30378
|
.shv-actions { display:flex; align-items:center; gap:6px; flex:none; }
|
|
29626
30379
|
.shv-actions .btn { padding:5px 10px; font-size:12px; }
|
|
29627
|
-
@media (max-width:640px){
|
|
30380
|
+
@media (max-width:640px){
|
|
30381
|
+
/* head stacks: title/desc full row, then segmented tabs, then search */
|
|
30382
|
+
.shares-page .db-head { flex-direction:column; align-items:stretch; gap:12px; }
|
|
30383
|
+
.shv-tools { margin-left:0; width:100%; }
|
|
30384
|
+
.shv-seg { display:flex; width:100%; }
|
|
30385
|
+
.shv-seg-btn { flex:1; text-align:center; }
|
|
30386
|
+
.shv-search { flex:1; }
|
|
30387
|
+
.shv-search input { width:100%; flex:1; }
|
|
30388
|
+
|
|
30389
|
+
/* cards: title clamps to two lines, meta wraps naturally */
|
|
30390
|
+
.shv-row { flex-wrap:wrap; }
|
|
30391
|
+
.shv-title { max-width:100%; white-space:normal; display:-webkit-box;
|
|
30392
|
+
-webkit-line-clamp:2; -webkit-box-orient:vertical; text-align:left; }
|
|
30393
|
+
.shv-meta { white-space:normal; overflow:visible; text-overflow:clip; }
|
|
30394
|
+
|
|
30395
|
+
/* actions: full row of evenly stretched touch targets */
|
|
30396
|
+
.shv-actions { width:100%; }
|
|
30397
|
+
.shv-actions .btn { flex:1; justify-content:center; padding:7px 10px; }
|
|
30398
|
+
}
|
|
29628
30399
|
|
|
29629
30400
|
/* in-context "\u5DF2\u5206\u4EAB" badge on docs / tables / site cards */
|
|
29630
30401
|
.share-badge { display:inline-grid; place-items:center; width:22px; height:22px; border-radius:6px; color:var(--accent);
|
|
@@ -29701,7 +30472,9 @@ var styles_default = ` :root {
|
|
|
29701
30472
|
box-shadow:var(--shadow-lg); z-index:71; transform:translateX(100%); transition:transform .24s cubic-bezier(.32,.72,0,1); display:flex; flex-direction:column; }
|
|
29702
30473
|
.peek.open { transform:none; }
|
|
29703
30474
|
.peek-head { display:flex; align-items:center; gap:4px; padding:12px 16px; border-bottom:1px solid var(--line); }
|
|
29704
|
-
|
|
30475
|
+
/* Same stable-gutter treatment as .content (stable only \u2014 see .content on
|
|
30476
|
+
why both-edges is forbidden). */
|
|
30477
|
+
.peek-body { overflow:auto; scrollbar-gutter:stable; padding:28px 32px; }
|
|
29705
30478
|
.peek h2 { font-size:27px; font-weight:700; letter-spacing:-.02em; margin:0 0 20px; outline:none; }
|
|
29706
30479
|
.proprow { display:flex; gap:8px; align-items:flex-start; margin:1px 0; }
|
|
29707
30480
|
.proprow .k { width:160px; flex:none; color:var(--muted); display:flex; align-items:center; gap:7px; font-size:13px; padding:7px 8px; border-radius:var(--radius-sm); }
|
|
@@ -29758,7 +30531,7 @@ var styles_default = ` :root {
|
|
|
29758
30531
|
.hist-restore { margin-top:8px; align-self:flex-start; }
|
|
29759
30532
|
|
|
29760
30533
|
/* menu / popover */
|
|
29761
|
-
.menu-layer { position:fixed; inset:0; z-index:
|
|
30534
|
+
.menu-layer { position:fixed; inset:0; z-index:115; }
|
|
29762
30535
|
.pop { position:fixed; background:var(--bg); border:1px solid var(--line); border-radius:var(--radius); box-shadow:var(--shadow-lg);
|
|
29763
30536
|
padding:6px; min-width:232px; max-height:70vh; overflow:auto; animation:pop .12s ease; }
|
|
29764
30537
|
@keyframes pop { from { opacity:0; transform:translateY(-4px); } }
|
|
@@ -29776,6 +30549,9 @@ var styles_default = ` :root {
|
|
|
29776
30549
|
.pop .item .meta { flex:1; min-width:0; }
|
|
29777
30550
|
.pop .item .t { font-size:var(--fs-ui); } .pop .item .d { font-size:var(--fs-xs); color:var(--muted); display:block; }
|
|
29778
30551
|
.pop .item .chk { color:var(--accent); margin-left:auto; }
|
|
30552
|
+
/* shortcut badge, mirrors .sb-search kbd; margin-left:auto pins it right (and
|
|
30553
|
+
a trailing .chk, whose own auto then collapses, rides the gap beside it) */
|
|
30554
|
+
.pop .item kbd { margin-left:auto; font-family:var(--mono); font-size:10px; color:var(--muted); border:1px solid var(--line-strong); border-radius:4px; padding:1px 4px; }
|
|
29779
30555
|
.pop .item.danger { color:var(--danger); } .pop .item.danger .lico { color:var(--danger); }
|
|
29780
30556
|
.pop .sep { height:1px; background:var(--line); margin:5px 4px; }
|
|
29781
30557
|
.pop .typegrid { display:grid; grid-template-columns:repeat(4,1fr); gap:4px; padding:2px 2px 4px; }
|
|
@@ -29895,24 +30671,28 @@ var styles_default = ` :root {
|
|
|
29895
30671
|
.view-placeholder { padding:40px; text-align:center; border:1px dashed var(--line-strong); border-radius:var(--radius); color:var(--muted); margin-top:8px; }
|
|
29896
30672
|
.ico.flip { transform:scaleX(-1); }
|
|
29897
30673
|
|
|
29898
|
-
/* ---- find in document (Ctrl-F) ---- */
|
|
29899
|
-
/*
|
|
29900
|
-
|
|
29901
|
-
|
|
30674
|
+
/* ---- find in document (Ctrl-F, CM6 bar) ---- */
|
|
30675
|
+
/* Match highlights are CM6 Decoration.marks (.cm-find/.cm-find-cur, editor-theme.ts).
|
|
30676
|
+
Matches INSIDE void widgets (code mirror, table cells) can't be mark
|
|
30677
|
+
decorations \u2014 the block replace widget swallows them \u2014 so those paint via
|
|
30678
|
+
the CSS Custom Highlight API (find.ts collectMatches/applyHighlights). */
|
|
30679
|
+
::highlight(mh-find-all) { background: color-mix(in srgb, var(--accent) 26%, transparent); border-radius: 2px; }
|
|
30680
|
+
::highlight(mh-find-current) { background: var(--accent); color: var(--accent-fg); }
|
|
29902
30681
|
.find-bar {
|
|
29903
|
-
position:fixed; top:58px; right:18px; z-index:
|
|
30682
|
+
position:fixed; top:58px; right:18px; z-index:96; /* below the ~50px topbar */
|
|
29904
30683
|
display:flex; align-items:center; gap:4px;
|
|
29905
30684
|
padding:5px 6px; background:var(--bg); border:1px solid var(--line-strong);
|
|
29906
30685
|
border-radius:var(--radius); box-shadow:var(--shadow-lg);
|
|
29907
30686
|
}
|
|
29908
30687
|
.find-bar .find-ico { color:var(--muted); margin:0 2px; flex:none; }
|
|
29909
30688
|
.find-bar input {
|
|
29910
|
-
width:200px; max-width:42vw; border:0; outline:0; background:transparent;
|
|
30689
|
+
width:200px; max-width:42vw; min-width:0; border:0; outline:0; background:transparent;
|
|
29911
30690
|
color:var(--fg); font-size:13px; padding:3px 2px;
|
|
29912
30691
|
}
|
|
29913
30692
|
.find-bar input::placeholder { color:var(--muted); }
|
|
29914
|
-
.find-count { font-size:12px; color:var(--muted); min-width:48px; text-align:right; padding:0 2px; font-variant-numeric:tabular-nums; }
|
|
30693
|
+
.find-count { font-size:12px; color:var(--muted); min-width:48px; text-align:right; padding:0 2px; font-variant-numeric:tabular-nums; flex:none; }
|
|
29915
30694
|
.find-opt {
|
|
30695
|
+
flex:none; white-space:nowrap;
|
|
29916
30696
|
border:1px solid var(--line-strong); background:transparent; color:var(--fg-soft);
|
|
29917
30697
|
border-radius:var(--radius-sm); font-size:12px; line-height:1; padding:4px 6px; cursor:pointer;
|
|
29918
30698
|
transition:background .12s, color .12s, border-color .12s;
|
|
@@ -29932,6 +30712,14 @@ var styles_default = ` :root {
|
|
|
29932
30712
|
.find-bar { left:12px; right:12px; }
|
|
29933
30713
|
.find-bar input { width:auto; flex:1; max-width:none; }
|
|
29934
30714
|
}
|
|
30715
|
+
/* Very narrow windows (quicknote resizes down to 280px): drop the reserved
|
|
30716
|
+
count width and tighten gaps so the option buttons never get crushed. */
|
|
30717
|
+
@media (max-width:360px) {
|
|
30718
|
+
.find-bar { gap:2px; padding:5px 4px; }
|
|
30719
|
+
.find-count { min-width:0; }
|
|
30720
|
+
}
|
|
30721
|
+
/* Quicknote window: its qn-bar is ~34px, not the main ~50px topbar. */
|
|
30722
|
+
body.quicknote .find-bar { top:42px; }
|
|
29935
30723
|
|
|
29936
30724
|
/* ---- board (kanban) view ---- */
|
|
29937
30725
|
.board-wrap { margin-top:4px; }
|
|
@@ -30088,8 +30876,7 @@ var styles_default = ` :root {
|
|
|
30088
30876
|
.navitem { padding:9px 8px; font-size:16px; }
|
|
30089
30877
|
.navitem .emoji { font-size:18px; }
|
|
30090
30878
|
.navitem .tw { width:26px; height:26px; }
|
|
30091
|
-
.sb-
|
|
30092
|
-
.sb-search kbd { display:none; } /* no hardware keyboard, no shortcut hint */
|
|
30879
|
+
.sb-search kbd, .pop .item kbd { display:none; } /* no hardware keyboard, no shortcut hint */
|
|
30093
30880
|
/* Search box is hidden until the header search button reveals it; it then
|
|
30094
30881
|
slides+fades down in. Desktop base (.sb-search{display:flex}) is untouched,
|
|
30095
30882
|
so search stays always-on there. reduced-motion is handled globally. */
|
|
@@ -30104,17 +30891,26 @@ var styles_default = ` :root {
|
|
|
30104
30891
|
/* Document: bigger body text, tighter side padding for narrow screens. */
|
|
30105
30892
|
.doc { padding:24px 18px calc(36vh + env(safe-area-inset-bottom)); }
|
|
30106
30893
|
.doc-title { font-size:30px; }
|
|
30107
|
-
|
|
30894
|
+
/* CM6 editor (single-document): its .cm-editor inherits from here, so the whole
|
|
30895
|
+
body incl. table cells gets 16px on mobile \u2014 same iOS anti-zoom reason. */
|
|
30896
|
+
.doc .cm-doc-body { font-size:16px; }
|
|
30108
30897
|
/* 16px (not 14): a focused code textarea below 16px makes iOS auto-zoom. */
|
|
30109
30898
|
.codeblock { --code-fs:16px; }
|
|
30110
|
-
|
|
30111
|
-
|
|
30112
|
-
|
|
30113
|
-
|
|
30899
|
+
/* CM6 hover gutter: no hover on touch, and -52px overlays would overflow
|
|
30900
|
+
the tight mobile margins \u2014 hide. */
|
|
30901
|
+
.cm-gutter-layer { display:none; }
|
|
30902
|
+
/* Autofit tables: on phones the atomic code span IS the width cap \u2014 one
|
|
30903
|
+
long \`file-name.md\` becomes the column's min-content, eats the whole
|
|
30904
|
+
100cqw budget and crushes prose columns to their 48px floor. Let code
|
|
30905
|
+
wrap at its natural break points (hyphens/slashes) instead; wider
|
|
30906
|
+
layouts keep the atomic-code tradeoff (see the autofit rules). */
|
|
30907
|
+
table.doc-table.autofit .doc-td code { white-space:pre-wrap; overflow-wrap:normal; word-break:normal; }
|
|
30114
30908
|
/* Find bar clears the taller mobile topbar (49px min + notch inset). */
|
|
30115
30909
|
.find-bar { top:calc(49px + env(safe-area-inset-top) + 8px); }
|
|
30116
30910
|
/* narrower handle gutter on phones; .db left padding must be \u2265 --grip-gutter */
|
|
30117
30911
|
.db { padding:16px 14px 90px 24px; }
|
|
30912
|
+
/* pages reusing .db without row grips don't need the left gutter \u2014 keep padding symmetric */
|
|
30913
|
+
.shares-page.db { padding-left:14px; }
|
|
30118
30914
|
.gridhost { --grip-gutter:24px; }
|
|
30119
30915
|
.peek { width:100%; }
|
|
30120
30916
|
/* history drawer: the side-by-side list/preview doesn't fit a phone \u2014 stack. */
|
|
@@ -30149,13 +30945,19 @@ var styles_default = ` :root {
|
|
|
30149
30945
|
@media (pointer: coarse) {
|
|
30150
30946
|
/* iOS Safari auto-zooms the page when a focused field is below 16px; the
|
|
30151
30947
|
class selectors out-specify the element-level sizes set on these. */
|
|
30152
|
-
input, textarea, .text-input,
|
|
30948
|
+
input, textarea, .text-input, input.inlineedit { font-size:16px; }
|
|
30153
30949
|
.navitem .acts button { width:34px; height:34px; }
|
|
30950
|
+
.sb-tab { min-height:40px; padding:8px 10px; }
|
|
30951
|
+
.sb-tabs .add { width:40px; height:40px; display:grid; place-items:center; padding:0; }
|
|
30154
30952
|
.iconbtn { width:40px; height:40px; }
|
|
30155
30953
|
.btn { padding:9px 14px; min-height:40px; }
|
|
30156
30954
|
.pop .item { padding:11px 10px; }
|
|
30157
30955
|
/* Column/sidebar resize handles: 7px is a mouse affordance, not a finger's. */
|
|
30158
30956
|
.col-resizer, .doc-col-resizer, .sb-resizer { width:16px; right:-8px; }
|
|
30957
|
+
/* cell-rectangle corner handle: big enough to grab with a finger (it is the
|
|
30958
|
+
only way to grow a touch selection \u2014 pan gestures stay scrolls) */
|
|
30959
|
+
.doc-cell-handle { width:12px; height:12px; right:-6px; bottom:-6px; }
|
|
30960
|
+
.doc-cell-handle::after { inset:-10px; }
|
|
30159
30961
|
}
|
|
30160
30962
|
|
|
30161
30963
|
/* No hover available (touch): controls that only materialize on :hover are
|
|
@@ -30164,9 +30966,11 @@ var styles_default = ` :root {
|
|
|
30164
30966
|
@media (hover: none) {
|
|
30165
30967
|
.code-tools { opacity:1; transform:none; pointer-events:auto; }
|
|
30166
30968
|
.rowactions { opacity:1; pointer-events:auto; }
|
|
30167
|
-
.
|
|
30168
|
-
.navitem .acts
|
|
30169
|
-
|
|
30969
|
+
.cal-add, .filerow .facts,
|
|
30970
|
+
.navitem .acts { opacity:1; }
|
|
30971
|
+
/* the pill handles survive on touch (focus-driven, not hover-driven), but
|
|
30972
|
+
sticky tap-hover must not tint them */
|
|
30973
|
+
.doc-row-handle:hover, .doc-col-handle:hover { background:var(--bg); color:var(--muted); }
|
|
30170
30974
|
.selcell input { opacity:1; }
|
|
30171
30975
|
.tl-item .tl-h { opacity:1; }
|
|
30172
30976
|
/* Neutralize the stickiest tap-residue tints (a tap "hovers" until the
|
|
@@ -30178,12 +30982,16 @@ var styles_default = ` :root {
|
|
|
30178
30982
|
.filerow:hover { background:none; }
|
|
30179
30983
|
.cal-day:hover { background:none; }
|
|
30180
30984
|
.cal-day.dim:hover { background:var(--surface); }
|
|
30985
|
+
.doc-table-addcol:hover, .doc-table-addrow:hover { background:var(--surface); color:var(--muted); border-color:var(--line-strong); }
|
|
30181
30986
|
}
|
|
30182
30987
|
|
|
30183
30988
|
/* Quick Notes window (desktop, loaded at #quick). A transparent body lets the
|
|
30184
30989
|
macOS vibrancy blur show through; a translucent panel keeps text readable.
|
|
30185
30990
|
The top bar is the window drag region; its buttons opt back out. */
|
|
30186
|
-
|
|
30991
|
+
/* --pop-top-inset: editor popups (slash menu) clamp their upward growth below
|
|
30992
|
+
this line, so they never cover the drag bar / macOS traffic lights (bar =
|
|
30993
|
+
26px actions + 2\xD74px padding). */
|
|
30994
|
+
body.quicknote { background:transparent; --pop-top-inset:38px; }
|
|
30187
30995
|
/* html carries an opaque bg for the iOS 26 Safari toolbar tint; the vibrancy
|
|
30188
30996
|
window needs the root transparent again or the blur is walled off. */
|
|
30189
30997
|
html:has(body.quicknote) { background:transparent; }
|
|
@@ -30203,22 +31011,32 @@ var styles_default = ` :root {
|
|
|
30203
31011
|
.qn-actions { display:flex; gap:2px; -webkit-app-region:no-drag; }
|
|
30204
31012
|
.qn-actions .iconbtn { width:26px; height:26px; }
|
|
30205
31013
|
.qn-actions .iconbtn.active { color:var(--accent); background:var(--hover-2); }
|
|
30206
|
-
|
|
30207
|
-
|
|
31014
|
+
/* Quicknote scrolling: the app-wide thin translucent scrollbar (transparent
|
|
31015
|
+
track, so the reserved lane just reads as right margin). stable reserves
|
|
31016
|
+
the lane up front so width never jumps when the doc grows past one
|
|
31017
|
+
screen; the doc's right padding + lane \u2248 left padding, keeping the prose
|
|
31018
|
+
visually centered. stable only, NEVER both-edges \u2014 see .content: a left
|
|
31019
|
+
gutter desyncs Chromium's scroll cull rect and paints a blank stripe over
|
|
31020
|
+
the rightmost 15px of content (it sliced this window's file cards). */
|
|
31021
|
+
/* scrollbar-width does NOT inherit (unlike scrollbar-color): without an
|
|
31022
|
+
explicit thin here the lane is the classic 15px. thin = 11px, so the
|
|
31023
|
+
doc's 1px right padding + 11px lane mirrors the 12px left padding. */
|
|
31024
|
+
.qn-body { flex:1; overflow:auto; scrollbar-gutter:stable; scrollbar-width:thin; -webkit-app-region:no-drag; }
|
|
31025
|
+
.qn-body .doc { max-width:none; margin:0; padding:14px 1px 30vh 12px; }
|
|
30208
31026
|
.qn-body .doc-title { font-size:24px; margin-bottom:2px; }
|
|
30209
31027
|
.qn-body .doc-meta { display:none; }
|
|
30210
|
-
/* The
|
|
30211
|
-
desktop window never matches \u2014 re-hide explicitly: quick notes offer no
|
|
31028
|
+
/* The CM6 hover gutter never fits the compact window: quick notes offer no
|
|
30212
31029
|
block insert/drag handles (Enter / slash commands cover insertion). */
|
|
30213
|
-
body.quicknote .
|
|
31030
|
+
body.quicknote .cm-gutter-layer { display:none; }
|
|
30214
31031
|
/* A native checkbox paints an opaque white box when unchecked, which breaks
|
|
30215
31032
|
the window's vibrancy blur. Draw a custom box so the unchecked background
|
|
30216
|
-
stays transparent; checked falls back to the accent fill + checkmark.
|
|
30217
|
-
|
|
31033
|
+
stays transparent; checked falls back to the accent fill + checkmark.
|
|
31034
|
+
(Same treatment main gave \`.b-todo .marker input\`.) */
|
|
31035
|
+
body.quicknote .cm-todo-box {
|
|
30218
31036
|
appearance:none; -webkit-appearance:none; box-sizing:border-box;
|
|
30219
31037
|
border:1.5px solid color-mix(in srgb, var(--fg-soft) 55%, transparent);
|
|
30220
31038
|
border-radius:4px; background:transparent; }
|
|
30221
|
-
body.quicknote .
|
|
31039
|
+
body.quicknote .cm-todo-box:checked {
|
|
30222
31040
|
border-color:var(--accent);
|
|
30223
31041
|
background:var(--accent) center/10px no-repeat
|
|
30224
31042
|
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12l5 5L20 7'/%3E%3C/svg%3E"); }
|
|
@@ -30240,8 +31058,11 @@ var styles_default = ` :root {
|
|
|
30240
31058
|
.qn-set-main { flex:1; min-width:0; }
|
|
30241
31059
|
.qn-set-name { font-weight:600; }
|
|
30242
31060
|
.qn-set-desc { color:var(--muted); font-size:13px; margin-top:2px; }
|
|
30243
|
-
.qn-shortcut { min-width:140px; justify-content:center; font-family
|
|
31061
|
+
.qn-shortcut { min-width:140px; justify-content:center; font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC",sans-serif; }
|
|
30244
31062
|
.qn-shortcut.capturing { outline:2px solid var(--accent); color:var(--accent); }
|
|
31063
|
+
.qn-keys { display:inline-flex; align-items:center; gap:6px; }
|
|
31064
|
+
.qn-key { line-height:1; }
|
|
31065
|
+
.qn-key.sym { font-size:1.15em; line-height:1; } /* \u2318 \u21E7 glyphs render smaller \u2014 bump to match letters */
|
|
30245
31066
|
|
|
30246
31067
|
/* No-origin bootstrap: enroll screen + hydration splash (data-blind shell). */
|
|
30247
31068
|
.enroll-splash { min-height:100dvh; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:14px; padding:24px; }
|
|
@@ -30255,6 +31076,44 @@ var styles_default = ` :root {
|
|
|
30255
31076
|
.enroll-err { color:var(--danger); font-size:13px; margin-top:12px; }
|
|
30256
31077
|
.enroll-go { width:100%; justify-content:center; margin-top:18px; }
|
|
30257
31078
|
.enroll-hint { font-size:12px; margin-top:14px; line-height:1.5; }
|
|
31079
|
+
.enroll-card { animation:enroll-in .35s ease both; }
|
|
31080
|
+
@keyframes enroll-in { from { opacity:0; transform:translateY(8px); } to { opacity:1; transform:none; } }
|
|
31081
|
+
|
|
31082
|
+
/* Scan-first enroll: square viewfinder (corner frame + sweeping accent beam)
|
|
31083
|
+
over the live camera feed. The chip stays black in both themes \u2014 the feed
|
|
31084
|
+
brings its own colors; accent carries the beam and the success flash. */
|
|
31085
|
+
.enroll-scan { position:relative; aspect-ratio:1/1; margin:2px 0 12px; border-radius:16px; overflow:hidden; background:#0b0b0e; }
|
|
31086
|
+
.enroll-scan video { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
|
|
31087
|
+
.enroll-scan::after { content:""; position:absolute; inset:0; border-radius:inherit; pointer-events:none; box-shadow:inset 0 0 44px rgba(0,0,0,.35); }
|
|
31088
|
+
.enroll-scan-frame { position:absolute; inset:0; width:100%; height:100%; fill:none; stroke:rgba(255,255,255,.92); stroke-width:2.5; stroke-linecap:round; pointer-events:none; }
|
|
31089
|
+
.enroll-scan-beam { position:absolute; left:9%; right:9%; top:12%; height:2px; border-radius:2px; pointer-events:none; opacity:.85;
|
|
31090
|
+
background:linear-gradient(90deg, transparent, var(--accent), transparent);
|
|
31091
|
+
animation:enroll-beam 2.4s ease-in-out infinite alternate; }
|
|
31092
|
+
@keyframes enroll-beam { to { top:86%; } }
|
|
31093
|
+
.enroll-scan.hit .enroll-scan-frame { stroke:var(--accent); }
|
|
31094
|
+
.enroll-scan.hit::after { animation:enroll-hit .38s ease-out; }
|
|
31095
|
+
@keyframes enroll-hit { from { box-shadow:inset 0 0 0 3px var(--accent), inset 0 0 60px rgba(0,0,0,.2); } to { box-shadow:inset 0 0 44px rgba(0,0,0,.35); } }
|
|
31096
|
+
.enroll-scan-wait { position:absolute; inset:0; display:flex; align-items:center; justify-content:center; color:rgba(255,255,255,.45); }
|
|
31097
|
+
.enroll-scan-waitico { width:30px; height:30px; animation:enroll-wait 1.6s ease-in-out infinite; }
|
|
31098
|
+
@keyframes enroll-wait { 0%,100% { opacity:.4; } 50% { opacity:.9; } }
|
|
31099
|
+
.enroll-cam-err { position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:6px; padding:20px; text-align:center; color:rgba(255,255,255,.9); font-size:13px; }
|
|
31100
|
+
.enroll-cam-err .muted { color:rgba(255,255,255,.55); font-size:12px; }
|
|
31101
|
+
.enroll-cam-errico { width:26px; height:26px; opacity:.7; }
|
|
31102
|
+
.enroll-cam-err .btn { margin-top:8px; }
|
|
31103
|
+
.enroll-paste { width:100%; font-size:13px; }
|
|
31104
|
+
.enroll-switch { display:flex; justify-content:center; align-items:center; gap:10px; margin-top:14px; }
|
|
31105
|
+
.enroll-switch-dot { color:var(--muted); }
|
|
31106
|
+
.enroll-link { background:none; border:0; padding:0; font:inherit; font-size:13px; color:var(--accent); cursor:pointer; }
|
|
31107
|
+
.enroll-link:hover { text-decoration:underline; }
|
|
31108
|
+
/* Unlock step: compact bucket summary chip above the passphrase field. */
|
|
31109
|
+
.enroll-bucket-card { display:flex; align-items:center; gap:10px; padding:12px 14px; margin:2px 0 14px; border:1px solid var(--line); border-radius:12px; background:var(--bg); }
|
|
31110
|
+
.enroll-bucket-ico { width:18px; height:18px; color:var(--muted); }
|
|
31111
|
+
.enroll-bucket-meta { flex:1; min-width:0; }
|
|
31112
|
+
.enroll-bucket-name { font-weight:600; font-size:14px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
31113
|
+
.enroll-bucket-host { font-family:var(--mono); font-size:12px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
31114
|
+
.enroll-bucket-badge { display:inline-flex; align-items:center; gap:4px; flex:none; font-size:11px; color:var(--accent); padding:3px 8px; border-radius:999px;
|
|
31115
|
+
border:1px solid color-mix(in srgb, var(--accent) 35%, transparent); }
|
|
31116
|
+
.enroll-bucket-badge .ico { width:12px; height:12px; }
|
|
30258
31117
|
|
|
30259
31118
|
/* Enroll QR (settings \u2192 \u540C\u6B65\u5B58\u50A8 \u2192 \u5728\u624B\u673A\u4E0A\u6253\u5F00). The QR inverts with the
|
|
30260
31119
|
theme: light = dark modules on a light chip, dark = light modules on a dark
|
|
@@ -30457,6 +31316,42 @@ var ICON_192 = "iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAYAAABS3GwHAAAAAXNSR0IArs4c6QAA
|
|
|
30457
31316
|
var ICON_512 = "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";
|
|
30458
31317
|
var ICON_180 = "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";
|
|
30459
31318
|
|
|
31319
|
+
// src/webui/fmt/manifest.ts
|
|
31320
|
+
var FMT_PROVIDERS = [
|
|
31321
|
+
{ id: "core", js: "/webui-fmt.js", entry: "fmt/fmt-core.ts" },
|
|
31322
|
+
{
|
|
31323
|
+
id: "ruff",
|
|
31324
|
+
js: "/webui-fmt-ruff.js",
|
|
31325
|
+
entry: "fmt/fmt-ruff.ts",
|
|
31326
|
+
wasm: { route: "/webui-fmt-ruff.wasm", pkg: "@wasm-fmt/ruff_fmt", file: "ruff_fmt_bg.wasm" }
|
|
31327
|
+
},
|
|
31328
|
+
{
|
|
31329
|
+
id: "gofmt",
|
|
31330
|
+
js: "/webui-fmt-gofmt.js",
|
|
31331
|
+
entry: "fmt/fmt-gofmt.ts",
|
|
31332
|
+
wasm: { route: "/webui-fmt-gofmt.wasm", pkg: "@wasm-fmt/gofmt", file: "gofmt.wasm" }
|
|
31333
|
+
},
|
|
31334
|
+
{
|
|
31335
|
+
id: "clang",
|
|
31336
|
+
js: "/webui-fmt-clang.js",
|
|
31337
|
+
entry: "fmt/fmt-clang.ts",
|
|
31338
|
+
wasm: { route: "/webui-fmt-clang.wasm", pkg: "@wasm-fmt/clang-format", file: "clang-format.wasm" }
|
|
31339
|
+
},
|
|
31340
|
+
{
|
|
31341
|
+
id: "lua",
|
|
31342
|
+
js: "/webui-fmt-lua.js",
|
|
31343
|
+
entry: "fmt/fmt-lua.ts",
|
|
31344
|
+
wasm: { route: "/webui-fmt-lua.wasm", pkg: "@wasm-fmt/lua_fmt", file: "lua_fmt_bg.wasm" }
|
|
31345
|
+
},
|
|
31346
|
+
{
|
|
31347
|
+
id: "taplo",
|
|
31348
|
+
js: "/webui-fmt-taplo.js",
|
|
31349
|
+
entry: "fmt/fmt-taplo.ts",
|
|
31350
|
+
wasm: { route: "/webui-fmt-taplo.wasm", pkg: "@wasm-fmt/taplo_fmt", file: "taplo_fmt_bg.wasm" }
|
|
31351
|
+
},
|
|
31352
|
+
{ id: "sh", js: "/webui-fmt-sh.js", entry: "fmt/fmt-sh.ts" }
|
|
31353
|
+
];
|
|
31354
|
+
|
|
30460
31355
|
// src/webui/server/assets.ts
|
|
30461
31356
|
var RUNNING_FROM_SOURCE = import.meta.url.includes("/src/webui/");
|
|
30462
31357
|
var HTML2 = `<!doctype html>
|
|
@@ -30501,6 +31396,7 @@ var injected = {
|
|
|
30501
31396
|
sdk: null
|
|
30502
31397
|
};
|
|
30503
31398
|
var injectedWasm = null;
|
|
31399
|
+
var injectedFmtWasm = {};
|
|
30504
31400
|
function newestSourceMtime(dir) {
|
|
30505
31401
|
let newest = 0;
|
|
30506
31402
|
for (const e3 of readdirSync4(dir, { withFileTypes: true })) {
|
|
@@ -30549,6 +31445,24 @@ function bundleGetter(opts) {
|
|
|
30549
31445
|
}
|
|
30550
31446
|
var getJs = bundleGetter({ key: "js", entry: "../app.tsx", dist: "webui.js" });
|
|
30551
31447
|
var getSwRaw = bundleGetter({ key: "sw", entry: "../sw.ts", dist: "sw.js" });
|
|
31448
|
+
var fmtJs = {};
|
|
31449
|
+
for (const p2 of FMT_PROVIDERS) {
|
|
31450
|
+
injected[`fmt_${p2.id}`] = null;
|
|
31451
|
+
fmtJs[p2.js] = bundleGetter({ key: `fmt_${p2.id}`, entry: `../${p2.entry}`, dist: p2.js.slice(1) });
|
|
31452
|
+
}
|
|
31453
|
+
var fmtWasmByRoute = Object.fromEntries(FMT_PROVIDERS.filter((p2) => p2.wasm).map((p2) => [p2.wasm.route, p2]));
|
|
31454
|
+
async function getFmtWasm(p2) {
|
|
31455
|
+
const w4 = p2.wasm;
|
|
31456
|
+
const embedded = injectedFmtWasm[w4.route];
|
|
31457
|
+
if (embedded != null)
|
|
31458
|
+
return embedded;
|
|
31459
|
+
const path = RUNNING_FROM_SOURCE ? join9(dirname(Bun.resolveSync(w4.pkg, fileURLToPath(new URL(".", import.meta.url)))), w4.file) : fileURLToPath(new URL(`.${w4.route}`, import.meta.url));
|
|
31460
|
+
const f4 = Bun.file(path);
|
|
31461
|
+
if (!await f4.exists()) {
|
|
31462
|
+
throw new Error(`${w4.route} missing at ${path} \u2014 run \`bun install\` / \`bun run build\``);
|
|
31463
|
+
}
|
|
31464
|
+
return f4.arrayBuffer();
|
|
31465
|
+
}
|
|
30552
31466
|
var getDbWorker = bundleGetter({ key: "dbWorker", entry: "../data/db-worker.ts", dist: "db-worker.js" });
|
|
30553
31467
|
var getRuntime = bundleGetter({ key: "runtime", entry: "../runtime.ts", dist: "mh-runtime.js" });
|
|
30554
31468
|
var getSdk = bundleGetter({ key: "sdk", entry: "../../sdk/client.ts", dist: "metahub-sdk.js", extraDirs: ["../../sdk"] });
|
|
@@ -30630,12 +31544,24 @@ async function serveWebui(req) {
|
|
|
30630
31544
|
return new Response(`sqlite3.wasm unavailable: ${e3}`, { status: 500 });
|
|
30631
31545
|
}
|
|
30632
31546
|
}
|
|
31547
|
+
const fmtWasmProvider = fmtWasmByRoute[pathname];
|
|
31548
|
+
if (fmtWasmProvider) {
|
|
31549
|
+
try {
|
|
31550
|
+
return new Response(await getFmtWasm(fmtWasmProvider), {
|
|
31551
|
+
headers: { "content-type": "application/wasm", "cache-control": "public, max-age=86400" }
|
|
31552
|
+
});
|
|
31553
|
+
} catch (e3) {
|
|
31554
|
+
console.error(`[webui] failed to serve ${pathname} \u2014`, e3);
|
|
31555
|
+
return new Response(`${pathname} unavailable: ${e3}`, { status: 500 });
|
|
31556
|
+
}
|
|
31557
|
+
}
|
|
30633
31558
|
const script = {
|
|
30634
31559
|
"/webui.js": getJsStamped,
|
|
30635
31560
|
"/sw.js": getSw,
|
|
30636
31561
|
"/db-worker.js": getDbWorker,
|
|
30637
31562
|
"/mh-runtime.js": getRuntime,
|
|
30638
|
-
"/metahub-sdk.js": getSdk
|
|
31563
|
+
"/metahub-sdk.js": getSdk,
|
|
31564
|
+
...fmtJs
|
|
30639
31565
|
};
|
|
30640
31566
|
const getter = script[pathname];
|
|
30641
31567
|
if (getter) {
|
|
@@ -31800,6 +32726,7 @@ COMMANDS
|
|
|
31800
32726
|
setup
|
|
31801
32727
|
init Create ~/.metahub (SQLite db + cache dir)
|
|
31802
32728
|
init --claude Install the /mh skill into ~/.claude (Claude Code)
|
|
32729
|
+
init --codex Install the $mh skill into ~/.codex (Codex)
|
|
31803
32730
|
databases
|
|
31804
32731
|
db create <name> [--icon] Create a database (table)
|
|
31805
32732
|
db list | get <ref> | delete <ref>
|
|
@@ -31879,6 +32806,7 @@ var EXAMPLES = {
|
|
|
31879
32806
|
init: [
|
|
31880
32807
|
"mh init",
|
|
31881
32808
|
"mh init --claude # install the /mh skill into ~/.claude (Claude Code)",
|
|
32809
|
+
"mh init --codex # install the $mh skill into ~/.codex (Codex)",
|
|
31882
32810
|
"METAHUB_HOME=/tmp/mh mh init # use an alternate home"
|
|
31883
32811
|
],
|
|
31884
32812
|
"db create": ['mh db create "Tasks"', 'mh db create "Notes" --icon \uD83D\uDCD3'],
|
|
@@ -32077,4 +33005,4 @@ if (argv2.includes("--server")) {
|
|
|
32077
33005
|
runMain(main, { showUsage: showUsage2 });
|
|
32078
33006
|
}
|
|
32079
33007
|
|
|
32080
|
-
//# debugId=
|
|
33008
|
+
//# debugId=6B3DFB027376050D64756E2164756E21
|