@bitcobblers/wod-wiki-ui 0.45.2167 → 0.47.2169
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/{chunk-QCWASNQO.mjs → chunk-WI2IFNAU.mjs} +708 -327
- package/dist/chunk-WI2IFNAU.mjs.map +1 -0
- package/dist/extensions/index.cjs +709 -324
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.d.cts +1 -1
- package/dist/extensions/index.d.ts +1 -1
- package/dist/extensions/index.mjs +1 -1
- package/dist/{index-BPh_dUN3.d.cts → index--_wwHFvD.d.cts} +7 -2
- package/dist/{index-BPh_dUN3.d.ts → index--_wwHFvD.d.ts} +7 -2
- package/dist/index.cjs +715 -330
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -9
- package/dist/index.d.ts +9 -9
- package/dist/index.mjs +8 -8
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +4 -4
- package/package.json +4 -4
- package/dist/chunk-QCWASNQO.mjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -2447,7 +2447,9 @@ var CLAUSE_META = {
|
|
|
2447
2447
|
note: { label: "Note", inputType: "freetext", placeholder: "note id\u2026", placeholderText: "note: [id]", icon: "\u{1F4D3}", description: "Scope to one note", prefix: "note:" },
|
|
2448
2448
|
page: { label: "Page", inputType: "select", placeholder: "slug, date, true\u2026", placeholderText: "page: [slug|date]", icon: "\u{1F4C4}", description: "On :page \u2014 the page slug or YYYY-MM-DD date; on :note \u2014 page-ness (true/false)", prefix: "page:" },
|
|
2449
2449
|
plane: { label: "Output Plane", inputType: "select", placeholder: "segment, load, event\u2026", placeholderText: "plane: [type]", icon: "\u{1F4CB}", description: "Output-statement plane on :session", prefix: "plane:" },
|
|
2450
|
-
pipes: { label: "Pipes", inputType: "freetext", placeholder: "| order by date | limit 10", placeholderText: "| select | order | limit", icon: "\u21E5", description: "Presentation pipes \u2014 select/order/limit/offset" }
|
|
2450
|
+
pipes: { label: "Pipes", inputType: "freetext", placeholder: "| order by date | limit 10", placeholderText: "| select | order | limit", icon: "\u21E5", description: "Presentation pipes \u2014 select/order/limit/offset" },
|
|
2451
|
+
feed: { label: "Feed", inputType: "select", placeholder: "core, local, feed id\u2026", placeholderText: "feed: [id]", icon: "\u{1F4E1}", description: "Filter by publishing feed source", prefix: "feed:" },
|
|
2452
|
+
subscribed: { label: "Subscribed", inputType: "select", placeholder: "true, false", placeholderText: "subscribed: [true|false]", icon: "\u2B50", description: "Filter by notebook subscription state", prefix: "subscribed:" }
|
|
2451
2453
|
};
|
|
2452
2454
|
var CUSTOM_FALLBACK_ICON = "\u{1F9E9}";
|
|
2453
2455
|
function getClauseMeta(type) {
|
|
@@ -5743,9 +5745,51 @@ var referenceIndexReload = state.StateEffect.define();
|
|
|
5743
5745
|
var frontmatterVisibility = state.Facet.define({
|
|
5744
5746
|
combine: (values2) => values2[0] ?? true
|
|
5745
5747
|
});
|
|
5748
|
+
var setFrontmatterDetailed = state.StateEffect.define();
|
|
5749
|
+
var frontmatterDetailed = state.StateField.define({
|
|
5750
|
+
create: () => false,
|
|
5751
|
+
update(value, tr) {
|
|
5752
|
+
for (const effect of tr.effects) {
|
|
5753
|
+
if (effect.is(setFrontmatterDetailed)) return effect.value;
|
|
5754
|
+
}
|
|
5755
|
+
return value;
|
|
5756
|
+
}
|
|
5757
|
+
});
|
|
5758
|
+
var setFrontmatterSource = state.StateEffect.define();
|
|
5759
|
+
var frontmatterSource = state.StateField.define({
|
|
5760
|
+
create: () => false,
|
|
5761
|
+
update(value, tr) {
|
|
5762
|
+
let source = value;
|
|
5763
|
+
for (const effect of tr.effects) {
|
|
5764
|
+
if (effect.is(setFrontmatterSource)) source = effect.value;
|
|
5765
|
+
}
|
|
5766
|
+
if (source && tr.selection) {
|
|
5767
|
+
const section = tr.state.field(sectionField).sections.find((item) => item.type === "frontmatter");
|
|
5768
|
+
if (!section || !tr.state.selection.ranges.some((range) => range.from <= section.to && range.to >= section.from)) {
|
|
5769
|
+
source = false;
|
|
5770
|
+
}
|
|
5771
|
+
}
|
|
5772
|
+
return source;
|
|
5773
|
+
}
|
|
5774
|
+
});
|
|
5746
5775
|
var pendingFocus = /* @__PURE__ */ new WeakMap();
|
|
5747
5776
|
var widgetCleanup = /* @__PURE__ */ new WeakMap();
|
|
5748
5777
|
var helperId = 0;
|
|
5778
|
+
var TAG_CATEGORY_SUMMARY_KEYS = {
|
|
5779
|
+
tag: true,
|
|
5780
|
+
tags: true,
|
|
5781
|
+
category: true,
|
|
5782
|
+
domain: true,
|
|
5783
|
+
format: true,
|
|
5784
|
+
equipment: true,
|
|
5785
|
+
effort: true,
|
|
5786
|
+
quality: true,
|
|
5787
|
+
intent: true,
|
|
5788
|
+
discipline: true,
|
|
5789
|
+
intensity: true,
|
|
5790
|
+
intensitytier: true,
|
|
5791
|
+
sound: true
|
|
5792
|
+
};
|
|
5749
5793
|
function isTagProperty(key) {
|
|
5750
5794
|
return ["tag", "tags", "category"].includes(key.trim().toLowerCase());
|
|
5751
5795
|
}
|
|
@@ -5862,12 +5906,18 @@ function parseTagList(val) {
|
|
|
5862
5906
|
}
|
|
5863
5907
|
return [];
|
|
5864
5908
|
}
|
|
5865
|
-
function patchPropertyInView(view, _sectionId, path, value) {
|
|
5909
|
+
function patchPropertyInView(view, _sectionId, path, value, expandDetailed = false) {
|
|
5866
5910
|
if (view.state.readOnly) return;
|
|
5867
5911
|
const wholeDoc = view.state.doc.toString();
|
|
5868
5912
|
const next = wodWikiCore.patchFrontmatterProperty(wholeDoc, path, value);
|
|
5869
|
-
if (next === wholeDoc)
|
|
5870
|
-
|
|
5913
|
+
if (next === wholeDoc) {
|
|
5914
|
+
if (expandDetailed) view.dispatch({ effects: setFrontmatterDetailed.of(true) });
|
|
5915
|
+
return;
|
|
5916
|
+
}
|
|
5917
|
+
view.dispatch({
|
|
5918
|
+
changes: { from: 0, to: wholeDoc.length, insert: next },
|
|
5919
|
+
...expandDetailed ? { effects: setFrontmatterDetailed.of(true) } : {}
|
|
5920
|
+
});
|
|
5871
5921
|
}
|
|
5872
5922
|
function renamePropertyInView(view, _sectionId, fromKey, toKey, value) {
|
|
5873
5923
|
if (view.state.readOnly) return;
|
|
@@ -5887,12 +5937,22 @@ function detectDefinitionKind(meta) {
|
|
|
5887
5937
|
if (meta.registrySource !== void 0 || meta.baseAttributes !== void 0) return "effort";
|
|
5888
5938
|
return null;
|
|
5889
5939
|
}
|
|
5890
|
-
function readBaseAttributes(body) {
|
|
5940
|
+
function readBaseAttributes(body, meta = {}) {
|
|
5891
5941
|
const out = {};
|
|
5942
|
+
if (meta["metrics.met"] !== void 0 && !Array.isArray(meta["metrics.met"])) {
|
|
5943
|
+
out.met = String(meta["metrics.met"]);
|
|
5944
|
+
}
|
|
5945
|
+
if (meta["discipline"] !== void 0 && !Array.isArray(meta["discipline"])) {
|
|
5946
|
+
out.discipline = String(meta["discipline"]);
|
|
5947
|
+
}
|
|
5948
|
+
if (meta["intensityTier"] !== void 0 && !Array.isArray(meta["intensityTier"])) {
|
|
5949
|
+
out.intensityTier = String(meta["intensityTier"]);
|
|
5950
|
+
}
|
|
5892
5951
|
let inBase = false;
|
|
5893
5952
|
for (const line of body.split(/\r?\n/)) {
|
|
5894
5953
|
if (/^baseAttributes:\s*(#.*)?$/.test(line)) {
|
|
5895
5954
|
inBase = true;
|
|
5955
|
+
out.hasBaseBlock = true;
|
|
5896
5956
|
continue;
|
|
5897
5957
|
}
|
|
5898
5958
|
if (!inBase) continue;
|
|
@@ -6022,7 +6082,8 @@ function renderEffortValueDiagnostics(provider, token, onPick) {
|
|
|
6022
6082
|
var METRIC_DRAFT_KINDS = {
|
|
6023
6083
|
effort: { label: "Effort", path: "metrics.effort", kind: "effort" },
|
|
6024
6084
|
equipment: { label: "Equipment", path: "metrics.equipment", kind: "equipment" },
|
|
6025
|
-
rpe: { label: "RPE", path: "metrics.rpe", kind: "number" }
|
|
6085
|
+
rpe: { label: "RPE", path: "metrics.rpe", kind: "number" },
|
|
6086
|
+
custom: { label: "Custom / Equation", path: "metrics.", kind: "custom" }
|
|
6026
6087
|
};
|
|
6027
6088
|
function createMetricDraftRow(view, root, referenceProvider, commit) {
|
|
6028
6089
|
const row = document.createElement("div");
|
|
@@ -6041,6 +6102,7 @@ function createMetricDraftRow(view, root, referenceProvider, commit) {
|
|
|
6041
6102
|
row.appendChild(select);
|
|
6042
6103
|
const valCol = document.createElement("div");
|
|
6043
6104
|
valCol.className = "flex items-center flex-wrap gap-1.5 px-3 py-1.5 flex-1 min-w-0";
|
|
6105
|
+
let customKeyInput = null;
|
|
6044
6106
|
const input = document.createElement("input");
|
|
6045
6107
|
input.className = "flex-none w-44 max-w-full rounded-md border border-field-border bg-background/60 px-2 py-1 text-xs text-foreground outline-none placeholder:text-field-placeholder focus:border-ring focus:ring-1 focus:ring-ring";
|
|
6046
6108
|
input.placeholder = "Value\u2026";
|
|
@@ -6063,6 +6125,10 @@ function createMetricDraftRow(view, root, referenceProvider, commit) {
|
|
|
6063
6125
|
else if (spec.kind === "number") {
|
|
6064
6126
|
const num = Number(raw);
|
|
6065
6127
|
if (!Number.isNaN(num)) commit([spec.path], num);
|
|
6128
|
+
} else if (spec.kind === "custom") {
|
|
6129
|
+
const keyName = (customKeyInput?.value.trim() || "custom").replace(/^metrics\./i, "");
|
|
6130
|
+
const num = Number(raw);
|
|
6131
|
+
commit([`metrics.${keyName}`], !Number.isNaN(num) && raw !== "" ? num : raw);
|
|
6066
6132
|
} else commit([spec.path], raw);
|
|
6067
6133
|
}
|
|
6068
6134
|
row.remove();
|
|
@@ -6070,6 +6136,31 @@ function createMetricDraftRow(view, root, referenceProvider, commit) {
|
|
|
6070
6136
|
};
|
|
6071
6137
|
const attachFor = () => {
|
|
6072
6138
|
const spec = METRIC_DRAFT_KINDS[select.value];
|
|
6139
|
+
if (spec?.kind === "custom") {
|
|
6140
|
+
if (!customKeyInput) {
|
|
6141
|
+
customKeyInput = document.createElement("input");
|
|
6142
|
+
customKeyInput.className = "flex-none w-32 max-w-full rounded-md border border-field-border bg-background/60 px-2 py-1 text-xs text-foreground outline-none placeholder:text-field-placeholder focus:border-ring focus:ring-1 focus:ring-ring";
|
|
6143
|
+
customKeyInput.placeholder = "Metric key\u2026";
|
|
6144
|
+
customKeyInput.setAttribute("aria-label", "Metric key");
|
|
6145
|
+
customKeyInput.dataset.frontmatterField = "key";
|
|
6146
|
+
customKeyInput.addEventListener("keydown", (e) => {
|
|
6147
|
+
if (e.key === "Escape") {
|
|
6148
|
+
e.preventDefault();
|
|
6149
|
+
settle(false);
|
|
6150
|
+
} else if (e.key === "Enter") {
|
|
6151
|
+
e.preventDefault();
|
|
6152
|
+
if (input.value.trim()) settle(true);
|
|
6153
|
+
else input.focus();
|
|
6154
|
+
}
|
|
6155
|
+
});
|
|
6156
|
+
valCol.insertBefore(customKeyInput, input);
|
|
6157
|
+
}
|
|
6158
|
+
input.placeholder = "Value or equation\u2026";
|
|
6159
|
+
} else if (customKeyInput) {
|
|
6160
|
+
customKeyInput.remove();
|
|
6161
|
+
customKeyInput = null;
|
|
6162
|
+
input.placeholder = "Value\u2026";
|
|
6163
|
+
}
|
|
6073
6164
|
if (spec && (spec.kind === "effort" || spec.kind === "equipment") && referenceProvider) {
|
|
6074
6165
|
attachSuggestions(input, view, root, "value", spec.path, [], () => settle(true), spec.kind);
|
|
6075
6166
|
}
|
|
@@ -6090,6 +6181,7 @@ function createMetricDraftRow(view, root, referenceProvider, commit) {
|
|
|
6090
6181
|
});
|
|
6091
6182
|
input.addEventListener("blur", () => queueMicrotask(() => {
|
|
6092
6183
|
if (!input.isConnected) return;
|
|
6184
|
+
if (row.contains(document.activeElement)) return;
|
|
6093
6185
|
settle(input.value.trim().length > 0);
|
|
6094
6186
|
}));
|
|
6095
6187
|
select.addEventListener("keydown", (e) => {
|
|
@@ -6100,6 +6192,82 @@ function createMetricDraftRow(view, root, referenceProvider, commit) {
|
|
|
6100
6192
|
});
|
|
6101
6193
|
return row;
|
|
6102
6194
|
}
|
|
6195
|
+
function createSummaryDraftRow(view, commit) {
|
|
6196
|
+
const row = document.createElement("div");
|
|
6197
|
+
row.className = "flex items-center min-h-[34px] border-b border-dashed border-border last:border-b-0 group hover:bg-muted/10 transition-colors max-[479px]:flex-col max-[479px]:items-stretch";
|
|
6198
|
+
row.setAttribute("data-frontmatter-summary-draft", "true");
|
|
6199
|
+
row.dataset.frontmatterRow = "summary";
|
|
6200
|
+
const keyCol = document.createElement("div");
|
|
6201
|
+
keyCol.className = "flex items-center gap-2 px-3 py-1.5 w-36 shrink-0 border-r border-dashed border-border text-muted-foreground max-[479px]:w-auto max-[479px]:border-r-0 max-[479px]:border-b";
|
|
6202
|
+
keyCol.appendChild(createListIcon());
|
|
6203
|
+
const keyInput = document.createElement("input");
|
|
6204
|
+
keyInput.className = "w-full rounded-md border border-field-border bg-background/60 px-2 py-1 text-xs text-foreground outline-none placeholder:text-field-placeholder focus:border-ring focus:ring-1 focus:ring-ring";
|
|
6205
|
+
keyInput.placeholder = "Summary key\u2026";
|
|
6206
|
+
keyInput.setAttribute("aria-label", "Summary key");
|
|
6207
|
+
keyInput.dataset.frontmatterField = "key";
|
|
6208
|
+
keyInput.setAttribute(
|
|
6209
|
+
"aria-describedby",
|
|
6210
|
+
appendFieldHelper(keyCol, "Summary metric name. Press Enter to move to the equation.").id
|
|
6211
|
+
);
|
|
6212
|
+
keyCol.appendChild(keyInput);
|
|
6213
|
+
row.appendChild(keyCol);
|
|
6214
|
+
const valCol = document.createElement("div");
|
|
6215
|
+
valCol.className = "flex items-center flex-wrap gap-1.5 px-3 py-1.5 flex-1 min-w-0";
|
|
6216
|
+
const valInput = document.createElement("input");
|
|
6217
|
+
valInput.className = "flex-1 min-w-[160px] rounded-md border border-field-border bg-background/60 px-2 py-1 text-xs text-foreground outline-none placeholder:text-field-placeholder focus:border-ring focus:ring-1 focus:ring-ring";
|
|
6218
|
+
valInput.placeholder = "Equation (e.g. sum(work))\u2026";
|
|
6219
|
+
valInput.setAttribute("aria-label", "Summary equation");
|
|
6220
|
+
valInput.dataset.frontmatterField = "value";
|
|
6221
|
+
valInput.setAttribute(
|
|
6222
|
+
"aria-describedby",
|
|
6223
|
+
appendFieldHelper(valCol, "Summary equation. Press Enter to apply.").id
|
|
6224
|
+
);
|
|
6225
|
+
valCol.appendChild(valInput);
|
|
6226
|
+
row.appendChild(valCol);
|
|
6227
|
+
let settled = false;
|
|
6228
|
+
const settle = (doCommit) => {
|
|
6229
|
+
if (settled) return;
|
|
6230
|
+
settled = true;
|
|
6231
|
+
const rawKey = (keyInput.value.trim() || "summary").replace(/^summaries\./i, "");
|
|
6232
|
+
const rawExpr = valInput.value.trim();
|
|
6233
|
+
if (doCommit && rawExpr) {
|
|
6234
|
+
commit([`summaries.${rawKey}`], rawExpr);
|
|
6235
|
+
}
|
|
6236
|
+
row.remove();
|
|
6237
|
+
view.requestMeasure();
|
|
6238
|
+
};
|
|
6239
|
+
keyInput.addEventListener("keydown", (e) => {
|
|
6240
|
+
if (e.key === "Escape") {
|
|
6241
|
+
e.preventDefault();
|
|
6242
|
+
settle(false);
|
|
6243
|
+
return;
|
|
6244
|
+
}
|
|
6245
|
+
if (e.key === "Enter") {
|
|
6246
|
+
e.preventDefault();
|
|
6247
|
+
if (valInput.value.trim()) settle(true);
|
|
6248
|
+
else valInput.focus();
|
|
6249
|
+
}
|
|
6250
|
+
});
|
|
6251
|
+
valInput.addEventListener("keydown", (e) => {
|
|
6252
|
+
if (e.key === "Escape") {
|
|
6253
|
+
e.preventDefault();
|
|
6254
|
+
settle(false);
|
|
6255
|
+
return;
|
|
6256
|
+
}
|
|
6257
|
+
if (e.key === "Enter") {
|
|
6258
|
+
e.preventDefault();
|
|
6259
|
+
settle(true);
|
|
6260
|
+
}
|
|
6261
|
+
});
|
|
6262
|
+
const onBlur = () => queueMicrotask(() => {
|
|
6263
|
+
if (!row.isConnected) return;
|
|
6264
|
+
if (row.contains(document.activeElement)) return;
|
|
6265
|
+
settle(valInput.value.trim().length > 0);
|
|
6266
|
+
});
|
|
6267
|
+
keyInput.addEventListener("blur", onBlur);
|
|
6268
|
+
valInput.addEventListener("blur", onBlur);
|
|
6269
|
+
return row;
|
|
6270
|
+
}
|
|
6103
6271
|
function createTagIcon() {
|
|
6104
6272
|
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
6105
6273
|
svg.setAttribute("viewBox", "0 0 24 24");
|
|
@@ -6208,18 +6376,88 @@ function createCloseIcon(size = "md") {
|
|
|
6208
6376
|
svg.appendChild(l2);
|
|
6209
6377
|
return svg;
|
|
6210
6378
|
}
|
|
6379
|
+
function isAliasProperty(key) {
|
|
6380
|
+
return ["alias", "aliases"].includes(key.trim().toLowerCase());
|
|
6381
|
+
}
|
|
6382
|
+
function createSummaryPill(value, hash2) {
|
|
6383
|
+
const pill = document.createElement("span");
|
|
6384
|
+
pill.className = "inline-flex max-w-full items-center rounded-md border border-border/60 bg-muted/40 px-2 py-0.5 text-xs text-foreground";
|
|
6385
|
+
const label = document.createElement("span");
|
|
6386
|
+
label.className = "truncate";
|
|
6387
|
+
label.textContent = hash2 ? `#${value}` : value;
|
|
6388
|
+
pill.appendChild(label);
|
|
6389
|
+
return pill;
|
|
6390
|
+
}
|
|
6391
|
+
function createFrontmatterSummary(entries, onShowDetails) {
|
|
6392
|
+
const summary = document.createElement("div");
|
|
6393
|
+
summary.dataset.frontmatterSummary = "true";
|
|
6394
|
+
summary.className = "divide-y divide-border/60";
|
|
6395
|
+
const groups = [
|
|
6396
|
+
{ label: "Tags", entries: entries.filter(([key]) => TAG_CATEGORY_SUMMARY_KEYS[key.trim().toLowerCase()] === true), hash: true },
|
|
6397
|
+
{ label: "Aliases", entries: entries.filter(([key]) => isAliasProperty(key)), hash: false }
|
|
6398
|
+
];
|
|
6399
|
+
for (const group of groups) {
|
|
6400
|
+
const values2 = group.entries.flatMap(([, value]) => parseTagList(value));
|
|
6401
|
+
if (values2.length === 0) continue;
|
|
6402
|
+
const row = document.createElement("div");
|
|
6403
|
+
row.className = "flex flex-wrap items-center gap-1.5 px-3 py-2";
|
|
6404
|
+
const label = document.createElement("span");
|
|
6405
|
+
label.className = "mr-1 w-14 shrink-0 text-[11px] font-medium text-muted-foreground";
|
|
6406
|
+
label.textContent = group.label;
|
|
6407
|
+
row.appendChild(label);
|
|
6408
|
+
for (const value of values2) row.appendChild(createSummaryPill(value, group.hash));
|
|
6409
|
+
summary.appendChild(row);
|
|
6410
|
+
}
|
|
6411
|
+
const hidden = entries.filter(([key]) => TAG_CATEGORY_SUMMARY_KEYS[key.trim().toLowerCase()] !== true && !isAliasProperty(key));
|
|
6412
|
+
const metricCount = hidden.filter(([key]) => {
|
|
6413
|
+
const k = key.trim().toLowerCase();
|
|
6414
|
+
return k.startsWith("metrics.") || k === "metrics";
|
|
6415
|
+
}).length;
|
|
6416
|
+
const summaryCount = hidden.filter(([key]) => {
|
|
6417
|
+
const k = key.trim().toLowerCase();
|
|
6418
|
+
return k.startsWith("summaries.") || k === "summaries";
|
|
6419
|
+
}).length;
|
|
6420
|
+
const details = document.createElement("button");
|
|
6421
|
+
details.type = "button";
|
|
6422
|
+
details.setAttribute("aria-label", "Show property details");
|
|
6423
|
+
details.setAttribute("aria-expanded", "false");
|
|
6424
|
+
details.className = "flex w-full flex-wrap items-center gap-x-2 gap-y-1 px-3 py-2 text-left text-[11px] text-muted-foreground transition-colors hover:bg-muted/20 hover:text-foreground cursor-pointer";
|
|
6425
|
+
const count2 = document.createElement("span");
|
|
6426
|
+
count2.textContent = `${hidden.length} more ${hidden.length === 1 ? "property" : "properties"}`;
|
|
6427
|
+
details.appendChild(count2);
|
|
6428
|
+
if (metricCount > 0) {
|
|
6429
|
+
const metrics = document.createElement("span");
|
|
6430
|
+
metrics.textContent = `\xB7 ${metricCount} custom ${metricCount === 1 ? "metric" : "metrics"}`;
|
|
6431
|
+
details.appendChild(metrics);
|
|
6432
|
+
}
|
|
6433
|
+
if (summaryCount > 0) {
|
|
6434
|
+
const summaries = document.createElement("span");
|
|
6435
|
+
summaries.textContent = `\xB7 ${summaryCount} ${summaryCount === 1 ? "summary" : "summaries"}`;
|
|
6436
|
+
details.appendChild(summaries);
|
|
6437
|
+
}
|
|
6438
|
+
const disclosure = document.createElement("span");
|
|
6439
|
+
disclosure.className = "ml-auto";
|
|
6440
|
+
disclosure.setAttribute("aria-hidden", "true");
|
|
6441
|
+
disclosure.textContent = "\u25BE";
|
|
6442
|
+
details.appendChild(disclosure);
|
|
6443
|
+
details.addEventListener("click", onShowDetails);
|
|
6444
|
+
summary.appendChild(details);
|
|
6445
|
+
return summary;
|
|
6446
|
+
}
|
|
6211
6447
|
var DefaultFrontmatterWidget = class extends view.WidgetType {
|
|
6212
6448
|
sectionId;
|
|
6213
6449
|
rawContent;
|
|
6214
6450
|
readOnly;
|
|
6215
|
-
|
|
6451
|
+
detailed;
|
|
6452
|
+
constructor(sectionId, rawContent, readOnly = false, detailed = false) {
|
|
6216
6453
|
super();
|
|
6217
6454
|
this.sectionId = sectionId;
|
|
6218
6455
|
this.rawContent = rawContent ?? "";
|
|
6219
6456
|
this.readOnly = readOnly;
|
|
6457
|
+
this.detailed = detailed;
|
|
6220
6458
|
}
|
|
6221
6459
|
eq(other) {
|
|
6222
|
-
return this.sectionId === other.sectionId && this.rawContent === other.rawContent && this.readOnly === other.readOnly;
|
|
6460
|
+
return this.sectionId === other.sectionId && this.rawContent === other.rawContent && this.readOnly === other.readOnly && this.detailed === other.detailed;
|
|
6223
6461
|
}
|
|
6224
6462
|
ignoreEvent() {
|
|
6225
6463
|
return true;
|
|
@@ -6229,10 +6467,25 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
|
|
|
6229
6467
|
widgetCleanup.set(root, []);
|
|
6230
6468
|
root.className = "cm-frontmatter-preview py-2 font-sans select-none";
|
|
6231
6469
|
const heading = document.createElement("div");
|
|
6232
|
-
heading.className = "text-xs font-medium text-muted-foreground
|
|
6233
|
-
|
|
6470
|
+
heading.className = "mb-1.5 flex items-center px-0.5 text-xs font-medium text-muted-foreground";
|
|
6471
|
+
const headingLabel = document.createElement("span");
|
|
6472
|
+
headingLabel.textContent = "Properties";
|
|
6473
|
+
heading.appendChild(headingLabel);
|
|
6474
|
+
if (this.detailed) {
|
|
6475
|
+
const summaryButton = document.createElement("button");
|
|
6476
|
+
summaryButton.type = "button";
|
|
6477
|
+
summaryButton.setAttribute("aria-label", "Show property summary");
|
|
6478
|
+
summaryButton.setAttribute("aria-expanded", "true");
|
|
6479
|
+
summaryButton.className = "ml-auto px-1 py-0.5 text-[11px] font-normal hover:text-foreground cursor-pointer";
|
|
6480
|
+
summaryButton.textContent = "Hide details \u25B4";
|
|
6481
|
+
summaryButton.addEventListener("click", () => {
|
|
6482
|
+
view.dispatch({ effects: setFrontmatterDetailed.of(false) });
|
|
6483
|
+
});
|
|
6484
|
+
heading.appendChild(summaryButton);
|
|
6485
|
+
}
|
|
6234
6486
|
root.appendChild(heading);
|
|
6235
6487
|
const box = document.createElement("div");
|
|
6488
|
+
box.dataset.frontmatterProperties = "true";
|
|
6236
6489
|
box.className = "rounded-lg border border-border/80 bg-background/50 text-xs shadow-xs";
|
|
6237
6490
|
root.appendChild(box);
|
|
6238
6491
|
const body = this.rawContent.replace(/^---\r?\n?/, "").replace(/\r?\n?---\r?$/, "");
|
|
@@ -6240,329 +6493,335 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
|
|
|
6240
6493
|
const entries = Object.entries(meta);
|
|
6241
6494
|
const docKind = detectDefinitionKind(meta);
|
|
6242
6495
|
const referenceProvider = view.state.facet(frontmatterReferenceIndex)?.() ?? null;
|
|
6243
|
-
const base = docKind === "effort" ? readBaseAttributes(body) : {};
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
box.appendChild(
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
const
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
const
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
keyCol.appendChild(
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
);
|
|
6284
|
-
let currentKey = key;
|
|
6285
|
-
const commitKey = () => {
|
|
6286
|
-
const nextKey = keyInput.value.trim();
|
|
6287
|
-
if (!nextKey || nextKey === currentKey) {
|
|
6288
|
-
keyInput.value = currentKey;
|
|
6289
|
-
return;
|
|
6290
|
-
}
|
|
6291
|
-
if (!/^[A-Za-z_][\w.-]*$/.test(nextKey) || nextKey in meta) {
|
|
6292
|
-
keyInput.value = currentKey;
|
|
6293
|
-
return;
|
|
6294
|
-
}
|
|
6295
|
-
renamePropertyInView(view, this.sectionId, currentKey, nextKey, value);
|
|
6296
|
-
delete meta[currentKey];
|
|
6297
|
-
meta[nextKey] = value;
|
|
6298
|
-
currentKey = nextKey;
|
|
6299
|
-
};
|
|
6300
|
-
const commitKeyIfAttached = () => queueMicrotask(() => {
|
|
6301
|
-
if (keyInput.isConnected) commitKey();
|
|
6302
|
-
});
|
|
6303
|
-
keyInput.addEventListener("change", commitKeyIfAttached);
|
|
6304
|
-
keyCol.appendChild(keyInput);
|
|
6305
|
-
attachSuggestions(keyInput, view, root, "key", key, entries.map(([name]) => name), commitKey);
|
|
6306
|
-
keyInput.addEventListener("blur", commitKeyIfAttached);
|
|
6307
|
-
keyInput.addEventListener("keydown", (e) => {
|
|
6308
|
-
if (e.defaultPrevented) return;
|
|
6309
|
-
if (e.key === "Enter") {
|
|
6310
|
-
e.preventDefault();
|
|
6311
|
-
keyInput.blur();
|
|
6312
|
-
}
|
|
6313
|
-
});
|
|
6314
|
-
const focus = pendingFocus.get(view);
|
|
6315
|
-
if (focus?.kind === "key" && focus.key === key) {
|
|
6316
|
-
setTimeout(() => {
|
|
6317
|
-
if (!keyInput.isConnected) return;
|
|
6318
|
-
keyInput.focus();
|
|
6319
|
-
keyInput.select();
|
|
6320
|
-
}, 0);
|
|
6321
|
-
pendingFocus.delete(view);
|
|
6322
|
-
}
|
|
6323
|
-
}
|
|
6324
|
-
const valCol = document.createElement("div");
|
|
6325
|
-
valCol.className = "flex items-center flex-wrap gap-1.5 px-3 py-1.5 flex-1 min-w-0";
|
|
6326
|
-
row.appendChild(valCol);
|
|
6327
|
-
const commitList = (next) => {
|
|
6328
|
-
meta[key] = next;
|
|
6329
|
-
patchPropertyInView(view, this.sectionId, [key], next.length > 0 ? next : "");
|
|
6330
|
-
};
|
|
6331
|
-
const refMatch = (token) => {
|
|
6332
|
-
if (!referenceProvider) return null;
|
|
6333
|
-
return valueKind === "effort" ? referenceProvider.resolveEffort(token) : valueKind === "equipment" ? referenceProvider.resolveEquipment(token) : null;
|
|
6334
|
-
};
|
|
6335
|
-
if (isTags || isReferenceList) {
|
|
6336
|
-
const chips = parseTagList(value);
|
|
6337
|
-
const chipIsReference = valueKind !== "tags";
|
|
6338
|
-
for (let idx = 0; idx < chips.length; idx++) {
|
|
6339
|
-
const chip = chips[idx];
|
|
6340
|
-
const match = chipIsReference ? refMatch(chip) : null;
|
|
6341
|
-
const pill = document.createElement("span");
|
|
6342
|
-
pill.className = match ? "inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-xs font-medium bg-muted/60 text-foreground border border-border/60" : chipIsReference ? "inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-xs font-medium bg-destructive/10 text-destructive border border-destructive/30" : "inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-xs font-medium bg-amber-500/10 text-amber-800 dark:text-amber-300 border border-amber-500/20 dark:border-amber-500/30";
|
|
6343
|
-
const pillText = document.createElement("span");
|
|
6344
|
-
pillText.textContent = match ? match.label : chip;
|
|
6345
|
-
pill.appendChild(pillText);
|
|
6346
|
-
if (match && referenceProvider) {
|
|
6347
|
-
const openLink = document.createElement("a");
|
|
6348
|
-
openLink.href = referenceProvider.openHref(valueKind, match.slug);
|
|
6349
|
-
openLink.title = `Open ${match.label} page`;
|
|
6350
|
-
openLink.setAttribute("aria-label", `Open ${match.label} page`);
|
|
6351
|
-
openLink.className = "inline-flex items-center justify-center text-muted-foreground/60 hover:text-foreground cursor-pointer";
|
|
6352
|
-
openLink.appendChild(createExternalIcon());
|
|
6353
|
-
pill.appendChild(openLink);
|
|
6354
|
-
}
|
|
6355
|
-
if (!this.readOnly) {
|
|
6356
|
-
const rmBtn = document.createElement("button");
|
|
6357
|
-
rmBtn.type = "button";
|
|
6358
|
-
rmBtn.setAttribute("aria-label", isTags ? `Remove tag ${chip}` : `Remove ${chip}`);
|
|
6359
|
-
rmBtn.className = "inline-flex items-center justify-center text-muted-foreground/60 hover:text-foreground dark:hover:text-foreground cursor-pointer";
|
|
6360
|
-
rmBtn.appendChild(createCloseIcon("sm"));
|
|
6361
|
-
rmBtn.addEventListener("click", (e) => {
|
|
6362
|
-
e.preventDefault();
|
|
6363
|
-
e.stopPropagation();
|
|
6364
|
-
commitList(chips.filter((_, i) => i !== idx));
|
|
6365
|
-
});
|
|
6366
|
-
pill.appendChild(rmBtn);
|
|
6367
|
-
}
|
|
6368
|
-
valCol.appendChild(pill);
|
|
6369
|
-
}
|
|
6370
|
-
if (!this.readOnly) {
|
|
6371
|
-
const chipInput = document.createElement("input");
|
|
6372
|
-
chipInput.className = "flex-none w-44 max-w-full rounded-md border border-field-border bg-background/60 px-2 py-1 text-xs text-foreground outline-none placeholder:text-field-placeholder focus:border-ring focus:ring-1 focus:ring-ring";
|
|
6373
|
-
chipInput.placeholder = chips.length === 0 ? isReferenceList ? `Add ${valueKind === "effort" ? "effort" : "equipment"}\u2026` : "Add tags\u2026" : isTags ? "Add tag\u2026" : "Add\u2026";
|
|
6374
|
-
chipInput.setAttribute("aria-label", `Value for ${key}`);
|
|
6375
|
-
chipInput.dataset.frontmatterField = "value";
|
|
6376
|
-
chipInput.dataset.frontmatterProperty = key;
|
|
6377
|
-
chipInput.setAttribute(
|
|
6496
|
+
const base = docKind === "effort" ? readBaseAttributes(body, meta) : {};
|
|
6497
|
+
if (!this.detailed) {
|
|
6498
|
+
box.appendChild(createFrontmatterSummary(entries, () => {
|
|
6499
|
+
view.dispatch({ effects: setFrontmatterDetailed.of(true) });
|
|
6500
|
+
}));
|
|
6501
|
+
} else {
|
|
6502
|
+
box.appendChild(createColumnHeader());
|
|
6503
|
+
if (entries.length === 0) {
|
|
6504
|
+
const emptyRow = document.createElement("div");
|
|
6505
|
+
emptyRow.className = "px-3 py-2 text-xs text-muted-foreground/60 italic";
|
|
6506
|
+
emptyRow.textContent = "No properties";
|
|
6507
|
+
box.appendChild(emptyRow);
|
|
6508
|
+
}
|
|
6509
|
+
for (const [key, value] of entries) {
|
|
6510
|
+
const isTags = isTagProperty(key);
|
|
6511
|
+
const valueKind = referenceValueKind(key, docKind);
|
|
6512
|
+
const isReferenceList = (isReferenceKey(key, docKind) || key === "aliases") && Array.isArray(value);
|
|
6513
|
+
const nested = value === "" && ownsNestedBlock(body, key);
|
|
6514
|
+
const row = document.createElement("div");
|
|
6515
|
+
row.className = "flex items-center min-h-[34px] border-b border-dashed border-border last:border-b-0 group hover:bg-muted/10 transition-colors max-[479px]:flex-col max-[479px]:items-stretch";
|
|
6516
|
+
row.dataset.frontmatterRow = key;
|
|
6517
|
+
box.appendChild(row);
|
|
6518
|
+
const keyCol = document.createElement("div");
|
|
6519
|
+
keyCol.className = "flex items-center gap-2 px-3 py-1.5 w-36 shrink-0 border-r border-dashed border-border text-muted-foreground max-[479px]:w-auto max-[479px]:border-r-0 max-[479px]:border-b";
|
|
6520
|
+
row.appendChild(keyCol);
|
|
6521
|
+
keyCol.appendChild(isTags || isReferenceList ? createTagIcon() : createListIcon());
|
|
6522
|
+
if (this.readOnly || nested) {
|
|
6523
|
+
const keyLabel = document.createElement("span");
|
|
6524
|
+
keyLabel.className = "truncate font-medium text-foreground/90";
|
|
6525
|
+
keyLabel.textContent = key;
|
|
6526
|
+
keyCol.appendChild(keyLabel);
|
|
6527
|
+
} else {
|
|
6528
|
+
const keyInput = document.createElement("input");
|
|
6529
|
+
keyInput.className = "w-full bg-transparent text-xs text-foreground/90 font-medium outline-none truncate hover:bg-muted/30 focus:bg-background focus:ring-1 focus:ring-ring rounded px-1 -mx-1";
|
|
6530
|
+
keyInput.value = key;
|
|
6531
|
+
keyInput.spellcheck = false;
|
|
6532
|
+
keyInput.setAttribute("aria-label", `Property key: ${key}`);
|
|
6533
|
+
keyInput.dataset.frontmatterField = "key";
|
|
6534
|
+
keyInput.dataset.frontmatterProperty = key;
|
|
6535
|
+
keyInput.setAttribute(
|
|
6378
6536
|
"aria-describedby",
|
|
6379
6537
|
appendFieldHelper(
|
|
6380
|
-
|
|
6381
|
-
"Press Enter
|
|
6538
|
+
keyCol,
|
|
6539
|
+
"Property name. Press Enter to apply. Arrow keys browse suggested property names."
|
|
6382
6540
|
).id
|
|
6383
6541
|
);
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6542
|
+
let currentKey = key;
|
|
6543
|
+
const commitKey = () => {
|
|
6544
|
+
const nextKey = keyInput.value.trim();
|
|
6545
|
+
if (!nextKey || nextKey === currentKey) {
|
|
6546
|
+
keyInput.value = currentKey;
|
|
6547
|
+
return;
|
|
6548
|
+
}
|
|
6549
|
+
if (!/^[A-Za-z_][\w.-]*$/.test(nextKey) || nextKey in meta) {
|
|
6550
|
+
keyInput.value = currentKey;
|
|
6551
|
+
return;
|
|
6390
6552
|
}
|
|
6553
|
+
renamePropertyInView(view, this.sectionId, currentKey, nextKey, value);
|
|
6554
|
+
delete meta[currentKey];
|
|
6555
|
+
meta[nextKey] = value;
|
|
6556
|
+
currentKey = nextKey;
|
|
6391
6557
|
};
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6558
|
+
const commitKeyIfAttached = () => queueMicrotask(() => {
|
|
6559
|
+
if (keyInput.isConnected) commitKey();
|
|
6560
|
+
});
|
|
6561
|
+
keyInput.addEventListener("change", commitKeyIfAttached);
|
|
6562
|
+
keyCol.appendChild(keyInput);
|
|
6563
|
+
attachSuggestions(keyInput, view, root, "key", key, entries.map(([name]) => name), commitKey);
|
|
6564
|
+
keyInput.addEventListener("blur", commitKeyIfAttached);
|
|
6565
|
+
keyInput.addEventListener("keydown", (e) => {
|
|
6395
6566
|
if (e.defaultPrevented) return;
|
|
6396
|
-
if (e.key === "Enter"
|
|
6397
|
-
e.preventDefault();
|
|
6398
|
-
commitNewChip();
|
|
6399
|
-
} else if (e.key === "Backspace" && !chipInput.value && chips.length > 0) {
|
|
6567
|
+
if (e.key === "Enter") {
|
|
6400
6568
|
e.preventDefault();
|
|
6401
|
-
|
|
6402
|
-
commitList(chips.slice(0, -1));
|
|
6569
|
+
keyInput.blur();
|
|
6403
6570
|
}
|
|
6404
6571
|
});
|
|
6405
|
-
chipInput.addEventListener("blur", () => queueMicrotask(() => {
|
|
6406
|
-
if (chipInput.isConnected && chipInput.value.trim()) commitNewChip();
|
|
6407
|
-
}));
|
|
6408
6572
|
const focus = pendingFocus.get(view);
|
|
6409
|
-
if (focus?.kind === "
|
|
6573
|
+
if (focus?.kind === "key" && focus.key === key) {
|
|
6410
6574
|
setTimeout(() => {
|
|
6411
|
-
if (
|
|
6575
|
+
if (!keyInput.isConnected) return;
|
|
6576
|
+
keyInput.focus();
|
|
6577
|
+
keyInput.select();
|
|
6412
6578
|
}, 0);
|
|
6413
6579
|
pendingFocus.delete(view);
|
|
6414
6580
|
}
|
|
6415
|
-
if (chipIsReference && referenceProvider) {
|
|
6416
|
-
const unknown = chips.filter((chip) => !refMatch(chip));
|
|
6417
|
-
if (unknown.length > 0) {
|
|
6418
|
-
const diag = document.createElement("div");
|
|
6419
|
-
diag.setAttribute("data-testid", "editor-ref-unknown");
|
|
6420
|
-
diag.className = "w-full basis-full flex flex-wrap items-center gap-2 text-[10px] text-destructive";
|
|
6421
|
-
const label = document.createElement("span");
|
|
6422
|
-
label.textContent = `Unknown ${valueKind === "effort" ? "effort" : "equipment"}: ${unknown.join(", ")}`;
|
|
6423
|
-
diag.appendChild(label);
|
|
6424
|
-
const selectBtn = document.createElement("button");
|
|
6425
|
-
selectBtn.type = "button";
|
|
6426
|
-
selectBtn.textContent = "Select existing";
|
|
6427
|
-
selectBtn.className = "underline hover:text-foreground cursor-pointer";
|
|
6428
|
-
selectBtn.addEventListener("click", (e) => {
|
|
6429
|
-
e.preventDefault();
|
|
6430
|
-
chipInput.focus();
|
|
6431
|
-
});
|
|
6432
|
-
diag.appendChild(selectBtn);
|
|
6433
|
-
const createLink = document.createElement("a");
|
|
6434
|
-
createLink.href = referenceProvider.createHref(valueKind);
|
|
6435
|
-
createLink.textContent = "Create page";
|
|
6436
|
-
createLink.className = "underline hover:text-foreground";
|
|
6437
|
-
diag.appendChild(createLink);
|
|
6438
|
-
valCol.appendChild(diag);
|
|
6439
|
-
}
|
|
6440
|
-
}
|
|
6441
6581
|
}
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
|
|
6445
|
-
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
const
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
);
|
|
6466
|
-
let committedVal = strVal;
|
|
6467
|
-
const commitVal = () => {
|
|
6468
|
-
const cur = valInput.value.trim();
|
|
6469
|
-
if (cur !== committedVal) {
|
|
6470
|
-
committedVal = cur;
|
|
6471
|
-
const num = Number(cur);
|
|
6472
|
-
const next = cur !== "" && !isNaN(num) ? num : cur;
|
|
6473
|
-
meta[key] = next;
|
|
6474
|
-
patchPropertyInView(view, this.sectionId, [key], next);
|
|
6475
|
-
}
|
|
6476
|
-
};
|
|
6477
|
-
const commitValIfAttached = () => queueMicrotask(() => {
|
|
6478
|
-
if (valInput.isConnected) commitVal();
|
|
6479
|
-
});
|
|
6480
|
-
valInput.addEventListener("change", commitValIfAttached);
|
|
6481
|
-
valCol.appendChild(valInput);
|
|
6482
|
-
attachSuggestions(
|
|
6483
|
-
valInput,
|
|
6484
|
-
view,
|
|
6485
|
-
root,
|
|
6486
|
-
"value",
|
|
6487
|
-
key,
|
|
6488
|
-
[strVal],
|
|
6489
|
-
commitVal,
|
|
6490
|
-
key.trim().toLowerCase() === "metrics.effort" ? "effort" : "tags"
|
|
6491
|
-
);
|
|
6492
|
-
valInput.addEventListener("blur", commitValIfAttached);
|
|
6493
|
-
valInput.addEventListener("keydown", (e) => {
|
|
6494
|
-
if (e.defaultPrevented) return;
|
|
6495
|
-
if (e.key === "Enter") {
|
|
6496
|
-
e.preventDefault();
|
|
6497
|
-
valInput.blur();
|
|
6498
|
-
}
|
|
6499
|
-
});
|
|
6500
|
-
if (key.trim().toLowerCase() === "metrics.effort" && referenceProvider) {
|
|
6501
|
-
const match = referenceProvider.resolveEffort(strVal);
|
|
6502
|
-
if (match) {
|
|
6503
|
-
const pill = document.createElement("span");
|
|
6504
|
-
pill.className = "inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-xs font-medium bg-muted/60 text-foreground border border-border/60 shrink-0";
|
|
6505
|
-
const pillText = document.createElement("span");
|
|
6506
|
-
pillText.textContent = match.label;
|
|
6507
|
-
pill.appendChild(pillText);
|
|
6582
|
+
const valCol = document.createElement("div");
|
|
6583
|
+
valCol.className = "flex items-center flex-wrap gap-1.5 px-3 py-1.5 flex-1 min-w-0";
|
|
6584
|
+
row.appendChild(valCol);
|
|
6585
|
+
const commitList = (next) => {
|
|
6586
|
+
meta[key] = next;
|
|
6587
|
+
patchPropertyInView(view, this.sectionId, [key], next.length > 0 ? next : "");
|
|
6588
|
+
};
|
|
6589
|
+
const refMatch = (token) => {
|
|
6590
|
+
if (!referenceProvider) return null;
|
|
6591
|
+
return valueKind === "effort" ? referenceProvider.resolveEffort(token) : valueKind === "equipment" ? referenceProvider.resolveEquipment(token) : null;
|
|
6592
|
+
};
|
|
6593
|
+
if (isTags || isReferenceList) {
|
|
6594
|
+
const chips = parseTagList(value);
|
|
6595
|
+
const chipIsReference = valueKind !== "tags";
|
|
6596
|
+
for (let idx = 0; idx < chips.length; idx++) {
|
|
6597
|
+
const chip = chips[idx];
|
|
6598
|
+
const match = chipIsReference ? refMatch(chip) : null;
|
|
6599
|
+
const pill = document.createElement("span");
|
|
6600
|
+
pill.className = match ? "inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-xs font-medium bg-muted/60 text-foreground border border-border/60" : chipIsReference ? "inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-xs font-medium bg-destructive/10 text-destructive border border-destructive/30" : "inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-xs font-medium bg-amber-500/10 text-amber-800 dark:text-amber-300 border border-amber-500/20 dark:border-amber-500/30";
|
|
6601
|
+
const pillText = document.createElement("span");
|
|
6602
|
+
pillText.textContent = match ? match.label : chip;
|
|
6603
|
+
pill.appendChild(pillText);
|
|
6604
|
+
if (match && referenceProvider) {
|
|
6508
6605
|
const openLink = document.createElement("a");
|
|
6509
|
-
openLink.href = referenceProvider.openHref(
|
|
6606
|
+
openLink.href = referenceProvider.openHref(valueKind, match.slug);
|
|
6510
6607
|
openLink.title = `Open ${match.label} page`;
|
|
6511
6608
|
openLink.setAttribute("aria-label", `Open ${match.label} page`);
|
|
6512
6609
|
openLink.className = "inline-flex items-center justify-center text-muted-foreground/60 hover:text-foreground cursor-pointer";
|
|
6513
6610
|
openLink.appendChild(createExternalIcon());
|
|
6514
6611
|
pill.appendChild(openLink);
|
|
6515
|
-
valCol.insertBefore(pill, valInput);
|
|
6516
|
-
valInput.className = "flex-1 min-w-[70px] rounded-md border border-field-border bg-background/60 px-2 py-1 text-xs text-foreground outline-none placeholder:text-field-placeholder focus:border-ring focus:ring-1 focus:ring-ring transition-colors";
|
|
6517
6612
|
}
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
(
|
|
6522
|
-
|
|
6523
|
-
|
|
6613
|
+
if (!this.readOnly) {
|
|
6614
|
+
const rmBtn = document.createElement("button");
|
|
6615
|
+
rmBtn.type = "button";
|
|
6616
|
+
rmBtn.setAttribute("aria-label", isTags ? `Remove tag ${chip}` : `Remove ${chip}`);
|
|
6617
|
+
rmBtn.className = "inline-flex items-center justify-center text-muted-foreground/60 hover:text-foreground dark:hover:text-foreground cursor-pointer";
|
|
6618
|
+
rmBtn.appendChild(createCloseIcon("sm"));
|
|
6619
|
+
rmBtn.addEventListener("click", (e) => {
|
|
6620
|
+
e.preventDefault();
|
|
6621
|
+
e.stopPropagation();
|
|
6622
|
+
commitList(chips.filter((_, i) => i !== idx));
|
|
6623
|
+
});
|
|
6624
|
+
pill.appendChild(rmBtn);
|
|
6625
|
+
}
|
|
6626
|
+
valCol.appendChild(pill);
|
|
6627
|
+
}
|
|
6628
|
+
if (!this.readOnly) {
|
|
6629
|
+
const chipInput = document.createElement("input");
|
|
6630
|
+
chipInput.className = "flex-none w-44 max-w-full rounded-md border border-field-border bg-background/60 px-2 py-1 text-xs text-foreground outline-none placeholder:text-field-placeholder focus:border-ring focus:ring-1 focus:ring-ring";
|
|
6631
|
+
chipInput.placeholder = chips.length === 0 ? isReferenceList ? `Add ${valueKind === "effort" ? "effort" : "equipment"}\u2026` : "Add tags\u2026" : isTags ? "Add tag\u2026" : "Add\u2026";
|
|
6632
|
+
chipInput.setAttribute("aria-label", `Value for ${key}`);
|
|
6633
|
+
chipInput.dataset.frontmatterField = "value";
|
|
6634
|
+
chipInput.dataset.frontmatterProperty = key;
|
|
6635
|
+
chipInput.setAttribute(
|
|
6636
|
+
"aria-describedby",
|
|
6637
|
+
appendFieldHelper(
|
|
6638
|
+
valCol,
|
|
6639
|
+
"Press Enter or comma to add a value. Arrow keys browse the suggestions."
|
|
6640
|
+
).id
|
|
6641
|
+
);
|
|
6642
|
+
const commitNewChip = () => {
|
|
6643
|
+
const val = chipInput.value.trim().replace(/^,|,$/g, "");
|
|
6644
|
+
if (val && !chips.some((chip) => chip.toLowerCase() === val.toLowerCase())) {
|
|
6645
|
+
chipInput.value = "";
|
|
6646
|
+
pendingFocus.set(view, { kind: "tag", key });
|
|
6647
|
+
commitList([...chips, val]);
|
|
6648
|
+
}
|
|
6649
|
+
};
|
|
6650
|
+
valCol.appendChild(chipInput);
|
|
6651
|
+
attachSuggestions(chipInput, view, root, "value", key, chips, commitNewChip, valueKind);
|
|
6652
|
+
chipInput.addEventListener("keydown", (e) => {
|
|
6653
|
+
if (e.defaultPrevented) return;
|
|
6654
|
+
if (e.key === "Enter" || e.key === ",") {
|
|
6655
|
+
e.preventDefault();
|
|
6656
|
+
commitNewChip();
|
|
6657
|
+
} else if (e.key === "Backspace" && !chipInput.value && chips.length > 0) {
|
|
6658
|
+
e.preventDefault();
|
|
6659
|
+
pendingFocus.set(view, { kind: "tag", key });
|
|
6660
|
+
commitList(chips.slice(0, -1));
|
|
6524
6661
|
}
|
|
6662
|
+
});
|
|
6663
|
+
chipInput.addEventListener("blur", () => queueMicrotask(() => {
|
|
6664
|
+
if (chipInput.isConnected && chipInput.value.trim()) commitNewChip();
|
|
6665
|
+
}));
|
|
6666
|
+
const focus = pendingFocus.get(view);
|
|
6667
|
+
if (focus?.kind === "tag" && focus.key === key) {
|
|
6668
|
+
setTimeout(() => {
|
|
6669
|
+
if (chipInput.isConnected) chipInput.focus();
|
|
6670
|
+
}, 0);
|
|
6671
|
+
pendingFocus.delete(view);
|
|
6672
|
+
}
|
|
6673
|
+
if (chipIsReference && referenceProvider) {
|
|
6674
|
+
const unknown = chips.filter((chip) => !refMatch(chip));
|
|
6675
|
+
if (unknown.length > 0) {
|
|
6676
|
+
const diag = document.createElement("div");
|
|
6677
|
+
diag.setAttribute("data-testid", "editor-ref-unknown");
|
|
6678
|
+
diag.className = "w-full basis-full flex flex-wrap items-center gap-2 text-[10px] text-destructive";
|
|
6679
|
+
const label = document.createElement("span");
|
|
6680
|
+
label.textContent = `Unknown ${valueKind === "effort" ? "effort" : "equipment"}: ${unknown.join(", ")}`;
|
|
6681
|
+
diag.appendChild(label);
|
|
6682
|
+
const selectBtn = document.createElement("button");
|
|
6683
|
+
selectBtn.type = "button";
|
|
6684
|
+
selectBtn.textContent = "Select existing";
|
|
6685
|
+
selectBtn.className = "underline hover:text-foreground cursor-pointer";
|
|
6686
|
+
selectBtn.addEventListener("click", (e) => {
|
|
6687
|
+
e.preventDefault();
|
|
6688
|
+
chipInput.focus();
|
|
6689
|
+
});
|
|
6690
|
+
diag.appendChild(selectBtn);
|
|
6691
|
+
const createLink = document.createElement("a");
|
|
6692
|
+
createLink.href = referenceProvider.createHref(valueKind);
|
|
6693
|
+
createLink.textContent = "Create page";
|
|
6694
|
+
createLink.className = "underline hover:text-foreground";
|
|
6695
|
+
diag.appendChild(createLink);
|
|
6696
|
+
valCol.appendChild(diag);
|
|
6697
|
+
}
|
|
6698
|
+
}
|
|
6699
|
+
}
|
|
6700
|
+
} else if (nested) {
|
|
6701
|
+
const valSpan = document.createElement("span");
|
|
6702
|
+
valSpan.className = "text-xs text-muted-foreground/60 italic py-0.5 truncate";
|
|
6703
|
+
valSpan.textContent = "Nested block \u2014 edit in YAML";
|
|
6704
|
+
valCol.appendChild(valSpan);
|
|
6705
|
+
} else {
|
|
6706
|
+
const strVal = Array.isArray(value) ? value.join(", ") : String(value ?? "");
|
|
6707
|
+
if (this.readOnly) {
|
|
6708
|
+
const valSpan = document.createElement("span");
|
|
6709
|
+
valSpan.className = "text-xs text-foreground py-0.5 truncate";
|
|
6710
|
+
valSpan.textContent = strVal;
|
|
6711
|
+
valCol.appendChild(valSpan);
|
|
6712
|
+
} else {
|
|
6713
|
+
const valInput = document.createElement("input");
|
|
6714
|
+
valInput.className = "w-full rounded-md border border-field-border bg-background/60 px-2 py-1 text-xs text-foreground outline-none placeholder:text-field-placeholder focus:border-ring focus:ring-1 focus:ring-ring transition-colors";
|
|
6715
|
+
valInput.value = strVal;
|
|
6716
|
+
valInput.spellcheck = false;
|
|
6717
|
+
valInput.setAttribute("aria-label", `Value for ${key}`);
|
|
6718
|
+
valInput.dataset.frontmatterField = "value";
|
|
6719
|
+
valInput.dataset.frontmatterProperty = key;
|
|
6720
|
+
valInput.setAttribute(
|
|
6721
|
+
"aria-describedby",
|
|
6722
|
+
appendFieldHelper(valCol, "Property value. Press Enter to apply.").id
|
|
6723
|
+
);
|
|
6724
|
+
let committedVal = strVal;
|
|
6725
|
+
const commitVal = () => {
|
|
6726
|
+
const cur = valInput.value.trim();
|
|
6727
|
+
if (cur !== committedVal) {
|
|
6728
|
+
committedVal = cur;
|
|
6729
|
+
const num = Number(cur);
|
|
6730
|
+
const next = cur !== "" && !isNaN(num) ? num : cur;
|
|
6731
|
+
meta[key] = next;
|
|
6732
|
+
patchPropertyInView(view, this.sectionId, [key], next);
|
|
6733
|
+
}
|
|
6734
|
+
};
|
|
6735
|
+
const commitValIfAttached = () => queueMicrotask(() => {
|
|
6736
|
+
if (valInput.isConnected) commitVal();
|
|
6737
|
+
});
|
|
6738
|
+
valInput.addEventListener("change", commitValIfAttached);
|
|
6739
|
+
valCol.appendChild(valInput);
|
|
6740
|
+
attachSuggestions(
|
|
6741
|
+
valInput,
|
|
6742
|
+
view,
|
|
6743
|
+
root,
|
|
6744
|
+
"value",
|
|
6745
|
+
key,
|
|
6746
|
+
[strVal],
|
|
6747
|
+
commitVal,
|
|
6748
|
+
key.trim().toLowerCase() === "metrics.effort" ? "effort" : "tags"
|
|
6525
6749
|
);
|
|
6526
|
-
|
|
6750
|
+
valInput.addEventListener("blur", commitValIfAttached);
|
|
6751
|
+
valInput.addEventListener("keydown", (e) => {
|
|
6752
|
+
if (e.defaultPrevented) return;
|
|
6753
|
+
if (e.key === "Enter") {
|
|
6754
|
+
e.preventDefault();
|
|
6755
|
+
valInput.blur();
|
|
6756
|
+
}
|
|
6757
|
+
});
|
|
6758
|
+
if (key.trim().toLowerCase() === "metrics.effort" && referenceProvider) {
|
|
6759
|
+
const match = referenceProvider.resolveEffort(strVal);
|
|
6760
|
+
if (match) {
|
|
6761
|
+
const pill = document.createElement("span");
|
|
6762
|
+
pill.className = "inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-xs font-medium bg-muted/60 text-foreground border border-border/60 shrink-0";
|
|
6763
|
+
const pillText = document.createElement("span");
|
|
6764
|
+
pillText.textContent = match.label;
|
|
6765
|
+
pill.appendChild(pillText);
|
|
6766
|
+
const openLink = document.createElement("a");
|
|
6767
|
+
openLink.href = referenceProvider.openHref("effort", match.slug);
|
|
6768
|
+
openLink.title = `Open ${match.label} page`;
|
|
6769
|
+
openLink.setAttribute("aria-label", `Open ${match.label} page`);
|
|
6770
|
+
openLink.className = "inline-flex items-center justify-center text-muted-foreground/60 hover:text-foreground cursor-pointer";
|
|
6771
|
+
openLink.appendChild(createExternalIcon());
|
|
6772
|
+
pill.appendChild(openLink);
|
|
6773
|
+
valCol.insertBefore(pill, valInput);
|
|
6774
|
+
valInput.className = "flex-1 min-w-[70px] rounded-md border border-field-border bg-background/60 px-2 py-1 text-xs text-foreground outline-none placeholder:text-field-placeholder focus:border-ring focus:ring-1 focus:ring-ring transition-colors";
|
|
6775
|
+
}
|
|
6776
|
+
const diag = renderEffortValueDiagnostics(
|
|
6777
|
+
referenceProvider,
|
|
6778
|
+
strVal,
|
|
6779
|
+
(slug) => {
|
|
6780
|
+
meta[key] = slug;
|
|
6781
|
+
patchPropertyInView(view, this.sectionId, [key], slug);
|
|
6782
|
+
}
|
|
6783
|
+
);
|
|
6784
|
+
if (diag) valCol.appendChild(diag);
|
|
6785
|
+
}
|
|
6786
|
+
}
|
|
6787
|
+
if (/^https?:\/\/\S+$/i.test(strVal)) {
|
|
6788
|
+
const openLink = document.createElement("a");
|
|
6789
|
+
openLink.href = strVal;
|
|
6790
|
+
openLink.target = "_blank";
|
|
6791
|
+
openLink.rel = "noopener noreferrer";
|
|
6792
|
+
openLink.title = strVal;
|
|
6793
|
+
openLink.setAttribute("aria-label", `Open ${key} in new tab`);
|
|
6794
|
+
openLink.className = "shrink-0 inline-flex items-center justify-center text-muted-foreground/60 hover:text-foreground transition-colors cursor-pointer";
|
|
6795
|
+
openLink.appendChild(createExternalIcon());
|
|
6796
|
+
valCol.appendChild(openLink);
|
|
6527
6797
|
}
|
|
6528
6798
|
}
|
|
6529
|
-
if (
|
|
6530
|
-
const
|
|
6531
|
-
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6799
|
+
if (!this.readOnly && !nested) {
|
|
6800
|
+
const actionsCol = document.createElement("div");
|
|
6801
|
+
actionsCol.className = "flex items-center pr-2";
|
|
6802
|
+
const delBtn = document.createElement("button");
|
|
6803
|
+
delBtn.type = "button";
|
|
6804
|
+
delBtn.setAttribute("aria-label", `Remove property ${key}`);
|
|
6805
|
+
delBtn.className = "opacity-0 group-hover:opacity-100 focus-visible:opacity-100 text-muted-foreground/70 hover:text-destructive p-1 rounded transition-opacity cursor-pointer";
|
|
6806
|
+
delBtn.appendChild(createCloseIcon("md"));
|
|
6807
|
+
delBtn.addEventListener("click", (e) => {
|
|
6808
|
+
e.preventDefault();
|
|
6809
|
+
e.stopPropagation();
|
|
6810
|
+
delete meta[key];
|
|
6811
|
+
patchPropertyInView(view, this.sectionId, [key], null);
|
|
6812
|
+
});
|
|
6813
|
+
actionsCol.appendChild(delBtn);
|
|
6814
|
+
row.appendChild(actionsCol);
|
|
6539
6815
|
}
|
|
6540
6816
|
}
|
|
6541
|
-
if (!this.readOnly
|
|
6542
|
-
|
|
6543
|
-
actionsCol.className = "flex items-center pr-2";
|
|
6544
|
-
const delBtn = document.createElement("button");
|
|
6545
|
-
delBtn.type = "button";
|
|
6546
|
-
delBtn.setAttribute("aria-label", `Remove property ${key}`);
|
|
6547
|
-
delBtn.className = "opacity-0 group-hover:opacity-100 focus-visible:opacity-100 text-muted-foreground/70 hover:text-destructive p-1 rounded transition-opacity cursor-pointer";
|
|
6548
|
-
delBtn.appendChild(createCloseIcon("md"));
|
|
6549
|
-
delBtn.addEventListener("click", (e) => {
|
|
6550
|
-
e.preventDefault();
|
|
6551
|
-
e.stopPropagation();
|
|
6552
|
-
delete meta[key];
|
|
6553
|
-
patchPropertyInView(view, this.sectionId, [key], null);
|
|
6554
|
-
});
|
|
6555
|
-
actionsCol.appendChild(delBtn);
|
|
6556
|
-
row.appendChild(actionsCol);
|
|
6817
|
+
if (docKind === "effort" && !this.readOnly) {
|
|
6818
|
+
box.appendChild(this.buildDefinitionRows(view, base));
|
|
6557
6819
|
}
|
|
6558
6820
|
}
|
|
6559
|
-
if (docKind === "effort" && !this.readOnly) {
|
|
6560
|
-
box.appendChild(this.buildDefinitionRows(view, base));
|
|
6561
|
-
}
|
|
6562
6821
|
if (!this.readOnly) {
|
|
6563
6822
|
const existingTagKey = entries.find(([key]) => key.trim().toLowerCase() === "tags")?.[0] ?? entries.find(([key]) => isTagProperty(key))?.[0];
|
|
6564
6823
|
const actionsRow = document.createElement("div");
|
|
6565
|
-
actionsRow.className = "mt-2 flex items-center gap-3";
|
|
6824
|
+
actionsRow.className = "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1";
|
|
6566
6825
|
actionsRow.dataset.frontmatterActions = "true";
|
|
6567
6826
|
const addBtn = document.createElement("button");
|
|
6568
6827
|
addBtn.type = "button";
|
|
@@ -6582,7 +6841,12 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
|
|
|
6582
6841
|
newKey = `property_${count2}`;
|
|
6583
6842
|
}
|
|
6584
6843
|
pendingFocus.set(view, { kind: "key", key: newKey });
|
|
6585
|
-
patchPropertyInView(view, this.sectionId, [newKey], "");
|
|
6844
|
+
patchPropertyInView(view, this.sectionId, [newKey], "", !this.detailed);
|
|
6845
|
+
const keyField = view.dom.querySelector(
|
|
6846
|
+
`[data-frontmatter-row="${newKey}"] [data-frontmatter-field="key"]`
|
|
6847
|
+
);
|
|
6848
|
+
keyField?.focus();
|
|
6849
|
+
keyField?.select();
|
|
6586
6850
|
});
|
|
6587
6851
|
actionsRow.appendChild(addBtn);
|
|
6588
6852
|
{
|
|
@@ -6598,20 +6862,57 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
|
|
|
6598
6862
|
addMetricBtn.addEventListener("click", (e) => {
|
|
6599
6863
|
e.preventDefault();
|
|
6600
6864
|
e.stopPropagation();
|
|
6601
|
-
|
|
6865
|
+
if (!this.detailed) {
|
|
6866
|
+
view.dispatch({ effects: setFrontmatterDetailed.of(true) });
|
|
6867
|
+
}
|
|
6868
|
+
const activeRoot = view.dom.querySelector(".cm-frontmatter-preview") ?? root;
|
|
6869
|
+
const activeBox = activeRoot.querySelector("[data-frontmatter-properties]") ?? box;
|
|
6870
|
+
const existing = activeRoot.querySelector("[data-frontmatter-metric-draft] input");
|
|
6602
6871
|
if (existing) {
|
|
6603
6872
|
existing.focus();
|
|
6604
6873
|
return;
|
|
6605
6874
|
}
|
|
6606
|
-
const draftRow = createMetricDraftRow(view,
|
|
6875
|
+
const draftRow = createMetricDraftRow(view, activeRoot, referenceProvider, (path, value) => {
|
|
6607
6876
|
patchPropertyInView(view, this.sectionId, path, value);
|
|
6608
6877
|
});
|
|
6609
|
-
|
|
6878
|
+
activeBox.appendChild(draftRow);
|
|
6610
6879
|
draftRow.querySelector("input")?.focus();
|
|
6611
6880
|
view.requestMeasure();
|
|
6612
6881
|
});
|
|
6613
6882
|
actionsRow.appendChild(addMetricBtn);
|
|
6614
6883
|
}
|
|
6884
|
+
{
|
|
6885
|
+
const addSummaryBtn = document.createElement("button");
|
|
6886
|
+
addSummaryBtn.type = "button";
|
|
6887
|
+
addSummaryBtn.setAttribute("aria-label", "Add summary");
|
|
6888
|
+
addSummaryBtn.setAttribute("data-testid", "editor-add-summary-note");
|
|
6889
|
+
addSummaryBtn.className = "inline-flex items-center gap-1.5 text-xs font-medium text-muted-foreground hover:text-foreground px-1 py-1 cursor-pointer transition-colors select-none";
|
|
6890
|
+
addSummaryBtn.appendChild(createPlusIcon());
|
|
6891
|
+
const addSummaryLabel = document.createElement("span");
|
|
6892
|
+
addSummaryLabel.textContent = "Add summary";
|
|
6893
|
+
addSummaryBtn.appendChild(addSummaryLabel);
|
|
6894
|
+
addSummaryBtn.addEventListener("click", (e) => {
|
|
6895
|
+
e.preventDefault();
|
|
6896
|
+
e.stopPropagation();
|
|
6897
|
+
if (!this.detailed) {
|
|
6898
|
+
view.dispatch({ effects: setFrontmatterDetailed.of(true) });
|
|
6899
|
+
}
|
|
6900
|
+
const activeRoot = view.dom.querySelector(".cm-frontmatter-preview") ?? root;
|
|
6901
|
+
const activeBox = activeRoot.querySelector("[data-frontmatter-properties]") ?? box;
|
|
6902
|
+
const existing = activeRoot.querySelector("[data-frontmatter-summary-draft] input");
|
|
6903
|
+
if (existing) {
|
|
6904
|
+
existing.focus();
|
|
6905
|
+
return;
|
|
6906
|
+
}
|
|
6907
|
+
const draftRow = createSummaryDraftRow(view, (path, value) => {
|
|
6908
|
+
patchPropertyInView(view, this.sectionId, path, value);
|
|
6909
|
+
});
|
|
6910
|
+
activeBox.appendChild(draftRow);
|
|
6911
|
+
draftRow.querySelector("input")?.focus();
|
|
6912
|
+
view.requestMeasure();
|
|
6913
|
+
});
|
|
6914
|
+
actionsRow.appendChild(addSummaryBtn);
|
|
6915
|
+
}
|
|
6615
6916
|
{
|
|
6616
6917
|
const addTagBtn = document.createElement("button");
|
|
6617
6918
|
addTagBtn.type = "button";
|
|
@@ -6624,23 +6925,28 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
|
|
|
6624
6925
|
addTagBtn.addEventListener("click", (e) => {
|
|
6625
6926
|
e.preventDefault();
|
|
6626
6927
|
e.stopPropagation();
|
|
6928
|
+
if (!this.detailed) {
|
|
6929
|
+
view.dispatch({ effects: setFrontmatterDetailed.of(true) });
|
|
6930
|
+
}
|
|
6931
|
+
const activeRoot = view.dom.querySelector(".cm-frontmatter-preview") ?? root;
|
|
6932
|
+
const activeBox = activeRoot.querySelector("[data-frontmatter-properties]") ?? box;
|
|
6627
6933
|
if (existingTagKey) {
|
|
6628
|
-
const input = Array.from(
|
|
6934
|
+
const input = Array.from(activeRoot.querySelectorAll(
|
|
6629
6935
|
'[data-frontmatter-field="value"]'
|
|
6630
6936
|
)).find((element) => element.dataset.frontmatterProperty === existingTagKey);
|
|
6631
6937
|
input?.focus();
|
|
6632
6938
|
return;
|
|
6633
6939
|
}
|
|
6634
|
-
const existingDraft =
|
|
6940
|
+
const existingDraft = activeRoot.querySelector("[data-frontmatter-tag-draft] input");
|
|
6635
6941
|
if (existingDraft) {
|
|
6636
6942
|
existingDraft.focus();
|
|
6637
6943
|
return;
|
|
6638
6944
|
}
|
|
6639
|
-
const draftRow = createTagDraftRow(view,
|
|
6945
|
+
const draftRow = createTagDraftRow(view, activeRoot, "category", (val) => {
|
|
6640
6946
|
pendingFocus.set(view, { kind: "tag", key: "category" });
|
|
6641
6947
|
patchPropertyInView(view, this.sectionId, ["category"], [val]);
|
|
6642
6948
|
});
|
|
6643
|
-
|
|
6949
|
+
activeBox.appendChild(draftRow);
|
|
6644
6950
|
draftRow.querySelector("input")?.focus();
|
|
6645
6951
|
view.requestMeasure();
|
|
6646
6952
|
});
|
|
@@ -6661,7 +6967,11 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
|
|
|
6661
6967
|
const { sections: currentSections } = view.state.field(sectionField);
|
|
6662
6968
|
const section = currentSections.find((s) => s.id === this.sectionId && s.type === "frontmatter") || currentSections.find((s) => s.type === "frontmatter");
|
|
6663
6969
|
if (!section) return;
|
|
6664
|
-
view.dispatch({
|
|
6970
|
+
view.dispatch({
|
|
6971
|
+
selection: { anchor: section.from },
|
|
6972
|
+
effects: setFrontmatterSource.of(true),
|
|
6973
|
+
scrollIntoView: true
|
|
6974
|
+
});
|
|
6665
6975
|
view.focus();
|
|
6666
6976
|
});
|
|
6667
6977
|
actionsRow.appendChild(editYamlBtn);
|
|
@@ -6686,10 +6996,12 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
|
|
|
6686
6996
|
const commitField = (field, raw) => {
|
|
6687
6997
|
if (field === "met") {
|
|
6688
6998
|
const num = Number(raw);
|
|
6689
|
-
|
|
6999
|
+
const path2 = base.hasBaseBlock ? ["baseAttributes", "met"] : ["metrics.met"];
|
|
7000
|
+
patchPropertyInView(view, this.sectionId, path2, raw !== "" && !Number.isNaN(num) ? num : null);
|
|
6690
7001
|
return;
|
|
6691
7002
|
}
|
|
6692
|
-
|
|
7003
|
+
const path = base.hasBaseBlock ? ["baseAttributes", field] : [field];
|
|
7004
|
+
patchPropertyInView(view, this.sectionId, path, raw === "" ? null : raw);
|
|
6693
7005
|
};
|
|
6694
7006
|
const fieldRow = (label, child) => {
|
|
6695
7007
|
const row = document.createElement("label");
|
|
@@ -6752,8 +7064,13 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
|
|
|
6752
7064
|
}
|
|
6753
7065
|
};
|
|
6754
7066
|
var EmptyFrontmatterWidget = class extends view.WidgetType {
|
|
6755
|
-
|
|
6756
|
-
|
|
7067
|
+
constructor(detailed = false) {
|
|
7068
|
+
super();
|
|
7069
|
+
this.detailed = detailed;
|
|
7070
|
+
}
|
|
7071
|
+
detailed;
|
|
7072
|
+
eq(other) {
|
|
7073
|
+
return this.detailed === other.detailed;
|
|
6757
7074
|
}
|
|
6758
7075
|
ignoreEvent() {
|
|
6759
7076
|
return true;
|
|
@@ -6766,7 +7083,7 @@ var EmptyFrontmatterWidget = class extends view.WidgetType {
|
|
|
6766
7083
|
heading.textContent = "Properties";
|
|
6767
7084
|
root.appendChild(heading);
|
|
6768
7085
|
const actionsRow = document.createElement("div");
|
|
6769
|
-
actionsRow.className = "flex items-center gap-3";
|
|
7086
|
+
actionsRow.className = "flex flex-wrap items-center gap-x-3 gap-y-1";
|
|
6770
7087
|
actionsRow.dataset.frontmatterActions = "true";
|
|
6771
7088
|
const addBtn = document.createElement("button");
|
|
6772
7089
|
addBtn.type = "button";
|
|
@@ -6780,9 +7097,71 @@ var EmptyFrontmatterWidget = class extends view.WidgetType {
|
|
|
6780
7097
|
e.preventDefault();
|
|
6781
7098
|
e.stopPropagation();
|
|
6782
7099
|
pendingFocus.set(view, { kind: "key", key: "property" });
|
|
6783
|
-
patchPropertyInView(view, "new", ["property"], "");
|
|
7100
|
+
patchPropertyInView(view, "new", ["property"], "", true);
|
|
7101
|
+
const keyField = view.dom.querySelector(
|
|
7102
|
+
'[data-frontmatter-row="property"] [data-frontmatter-field="key"]'
|
|
7103
|
+
);
|
|
7104
|
+
keyField?.focus();
|
|
7105
|
+
keyField?.select();
|
|
6784
7106
|
});
|
|
6785
7107
|
actionsRow.appendChild(addBtn);
|
|
7108
|
+
const addMetricBtn = document.createElement("button");
|
|
7109
|
+
addMetricBtn.type = "button";
|
|
7110
|
+
addMetricBtn.setAttribute("aria-label", "Add metric");
|
|
7111
|
+
addMetricBtn.setAttribute("data-testid", "editor-add-metric-note");
|
|
7112
|
+
addMetricBtn.className = "inline-flex items-center gap-1.5 text-xs font-medium text-muted-foreground hover:text-foreground px-1 py-1 cursor-pointer transition-colors select-none";
|
|
7113
|
+
addMetricBtn.appendChild(createPlusIcon());
|
|
7114
|
+
const addMetricLabel = document.createElement("span");
|
|
7115
|
+
addMetricLabel.textContent = "Add metric";
|
|
7116
|
+
addMetricBtn.appendChild(addMetricLabel);
|
|
7117
|
+
addMetricBtn.addEventListener("click", (e) => {
|
|
7118
|
+
e.preventDefault();
|
|
7119
|
+
e.stopPropagation();
|
|
7120
|
+
if (!this.detailed) view.dispatch({ effects: setFrontmatterDetailed.of(true) });
|
|
7121
|
+
const activeRoot = view.dom.querySelector(".cm-frontmatter-preview") ?? root;
|
|
7122
|
+
const existing = activeRoot.querySelector("[data-frontmatter-metric-draft] input");
|
|
7123
|
+
if (existing) {
|
|
7124
|
+
existing.focus();
|
|
7125
|
+
return;
|
|
7126
|
+
}
|
|
7127
|
+
const referenceProvider = view.state.facet(frontmatterReferenceIndex)?.() ?? null;
|
|
7128
|
+
const draftRow = createMetricDraftRow(view, activeRoot, referenceProvider, (path, value) => {
|
|
7129
|
+
patchPropertyInView(view, "new", path, value, true);
|
|
7130
|
+
});
|
|
7131
|
+
activeRoot.appendChild(draftRow);
|
|
7132
|
+
ensureColumnHeader(activeRoot, draftRow);
|
|
7133
|
+
draftRow.querySelector("input")?.focus();
|
|
7134
|
+
view.requestMeasure();
|
|
7135
|
+
});
|
|
7136
|
+
actionsRow.appendChild(addMetricBtn);
|
|
7137
|
+
const addSummaryBtn = document.createElement("button");
|
|
7138
|
+
addSummaryBtn.type = "button";
|
|
7139
|
+
addSummaryBtn.setAttribute("aria-label", "Add summary");
|
|
7140
|
+
addSummaryBtn.setAttribute("data-testid", "editor-add-summary-note");
|
|
7141
|
+
addSummaryBtn.className = "inline-flex items-center gap-1.5 text-xs font-medium text-muted-foreground hover:text-foreground px-1 py-1 cursor-pointer transition-colors select-none";
|
|
7142
|
+
addSummaryBtn.appendChild(createPlusIcon());
|
|
7143
|
+
const addSummaryLabel = document.createElement("span");
|
|
7144
|
+
addSummaryLabel.textContent = "Add summary";
|
|
7145
|
+
addSummaryBtn.appendChild(addSummaryLabel);
|
|
7146
|
+
addSummaryBtn.addEventListener("click", (e) => {
|
|
7147
|
+
e.preventDefault();
|
|
7148
|
+
e.stopPropagation();
|
|
7149
|
+
if (!this.detailed) view.dispatch({ effects: setFrontmatterDetailed.of(true) });
|
|
7150
|
+
const activeRoot = view.dom.querySelector(".cm-frontmatter-preview") ?? root;
|
|
7151
|
+
const existing = activeRoot.querySelector("[data-frontmatter-summary-draft] input");
|
|
7152
|
+
if (existing) {
|
|
7153
|
+
existing.focus();
|
|
7154
|
+
return;
|
|
7155
|
+
}
|
|
7156
|
+
const draftRow = createSummaryDraftRow(view, (path, value) => {
|
|
7157
|
+
patchPropertyInView(view, "new", path, value, true);
|
|
7158
|
+
});
|
|
7159
|
+
activeRoot.appendChild(draftRow);
|
|
7160
|
+
ensureColumnHeader(activeRoot, draftRow);
|
|
7161
|
+
draftRow.querySelector("input")?.focus();
|
|
7162
|
+
view.requestMeasure();
|
|
7163
|
+
});
|
|
7164
|
+
actionsRow.appendChild(addSummaryBtn);
|
|
6786
7165
|
const addTagBtn = document.createElement("button");
|
|
6787
7166
|
addTagBtn.type = "button";
|
|
6788
7167
|
addTagBtn.setAttribute("aria-label", "Add tag");
|
|
@@ -6794,17 +7173,19 @@ var EmptyFrontmatterWidget = class extends view.WidgetType {
|
|
|
6794
7173
|
addTagBtn.addEventListener("click", (e) => {
|
|
6795
7174
|
e.preventDefault();
|
|
6796
7175
|
e.stopPropagation();
|
|
6797
|
-
|
|
7176
|
+
if (!this.detailed) view.dispatch({ effects: setFrontmatterDetailed.of(true) });
|
|
7177
|
+
const activeRoot = view.dom.querySelector(".cm-frontmatter-preview") ?? root;
|
|
7178
|
+
const existingDraft = activeRoot.querySelector("[data-frontmatter-tag-draft] input");
|
|
6798
7179
|
if (existingDraft) {
|
|
6799
7180
|
existingDraft.focus();
|
|
6800
7181
|
return;
|
|
6801
7182
|
}
|
|
6802
|
-
const draftRow = createTagDraftRow(view,
|
|
7183
|
+
const draftRow = createTagDraftRow(view, activeRoot, "category", (val) => {
|
|
6803
7184
|
pendingFocus.set(view, { kind: "tag", key: "category" });
|
|
6804
|
-
patchPropertyInView(view, "new", ["category"], [val]);
|
|
7185
|
+
patchPropertyInView(view, "new", ["category"], [val], true);
|
|
6805
7186
|
});
|
|
6806
|
-
|
|
6807
|
-
ensureColumnHeader(
|
|
7187
|
+
activeRoot.appendChild(draftRow);
|
|
7188
|
+
ensureColumnHeader(activeRoot, draftRow);
|
|
6808
7189
|
draftRow.querySelector("input")?.focus();
|
|
6809
7190
|
view.requestMeasure();
|
|
6810
7191
|
});
|
|
@@ -6826,14 +7207,14 @@ function buildFrontmatterDecos(state$1) {
|
|
|
6826
7207
|
builder.add(section.from, to, view.Decoration.replace({ block: true }));
|
|
6827
7208
|
continue;
|
|
6828
7209
|
}
|
|
6829
|
-
const selected = !state$1.readOnly && state$1.selection.ranges.some((range) => range.from < section.to && range.to > section.from);
|
|
7210
|
+
const selected = !state$1.readOnly && (state$1.field(frontmatterSource) || state$1.selection.ranges.some((range) => range.from < section.to && range.to > section.from));
|
|
6830
7211
|
if (selected) continue;
|
|
6831
7212
|
const rawContent = state$1.doc.sliceString(section.from, section.to);
|
|
6832
7213
|
builder.add(
|
|
6833
7214
|
section.from,
|
|
6834
7215
|
section.to,
|
|
6835
7216
|
view.Decoration.replace({
|
|
6836
|
-
widget: new DefaultFrontmatterWidget(section.id, rawContent, state$1.readOnly),
|
|
7217
|
+
widget: new DefaultFrontmatterWidget(section.id, rawContent, state$1.readOnly, state$1.field(frontmatterDetailed)),
|
|
6837
7218
|
block: true
|
|
6838
7219
|
})
|
|
6839
7220
|
);
|
|
@@ -6843,7 +7224,7 @@ function buildFrontmatterDecos(state$1) {
|
|
|
6843
7224
|
0,
|
|
6844
7225
|
0,
|
|
6845
7226
|
view.Decoration.widget({
|
|
6846
|
-
widget: new EmptyFrontmatterWidget(),
|
|
7227
|
+
widget: new EmptyFrontmatterWidget(state$1.field(frontmatterDetailed)),
|
|
6847
7228
|
side: -1,
|
|
6848
7229
|
block: true
|
|
6849
7230
|
})
|
|
@@ -6856,7 +7237,7 @@ var frontmatterPreviewField = state.StateField.define({
|
|
|
6856
7237
|
return buildFrontmatterDecos(state);
|
|
6857
7238
|
},
|
|
6858
7239
|
update(deco, tr) {
|
|
6859
|
-
if (tr.docChanged || tr.reconfigured || tr.selection || tr.effects.some((e) => e.is(referenceIndexReload))) {
|
|
7240
|
+
if (tr.docChanged || tr.reconfigured || tr.selection || tr.effects.some((e) => e.is(referenceIndexReload) || e.is(setFrontmatterDetailed) || e.is(setFrontmatterSource))) {
|
|
6860
7241
|
return buildFrontmatterDecos(tr.state);
|
|
6861
7242
|
}
|
|
6862
7243
|
return deco;
|
|
@@ -6868,7 +7249,7 @@ var frontmatterPreviewField = state.StateField.define({
|
|
|
6868
7249
|
)
|
|
6869
7250
|
]
|
|
6870
7251
|
});
|
|
6871
|
-
var frontmatterPreview = [frontmatterPreviewField];
|
|
7252
|
+
var frontmatterPreview = [frontmatterDetailed, frontmatterSource, frontmatterPreviewField];
|
|
6872
7253
|
var HEADING_RE = /^(#{1,6}) /;
|
|
6873
7254
|
var BOLD_RE = /\*\*([^*\n]+)\*\*/g;
|
|
6874
7255
|
var ITALIC_STAR_RE = /(?<!\*)\*([^*\n]+)\*(?!\*)/g;
|
|
@@ -13659,13 +14040,13 @@ function editorPreset(optionsOrDialect = "markdown") {
|
|
|
13659
14040
|
}
|
|
13660
14041
|
|
|
13661
14042
|
// src/version.ts
|
|
13662
|
-
var VERSION = "0.
|
|
13663
|
-
var GIT_SHA = "
|
|
13664
|
-
var BUILD_TIME = "2026-10-
|
|
14043
|
+
var VERSION = "0.47.2169";
|
|
14044
|
+
var GIT_SHA = "388d659";
|
|
14045
|
+
var BUILD_TIME = "2026-10-26T23:06:14.030Z";
|
|
13665
14046
|
var SEMVER = {
|
|
13666
|
-
version: "0.
|
|
13667
|
-
gitSha: "
|
|
13668
|
-
buildTime: "2026-10-
|
|
14047
|
+
version: "0.47.2169",
|
|
14048
|
+
gitSha: "388d659",
|
|
14049
|
+
buildTime: "2026-10-26T23:06:14.030Z"
|
|
13669
14050
|
};
|
|
13670
14051
|
|
|
13671
14052
|
Object.defineProperty(exports, "CONTENT_GROUPING_DIMENSIONS", {
|
|
@@ -13769,9 +14150,11 @@ exports.forceSectionParse = forceSectionParse;
|
|
|
13769
14150
|
exports.formatClockTime = formatClockTime;
|
|
13770
14151
|
exports.formatMMSS = formatMMSS;
|
|
13771
14152
|
exports.formatTimestamp = formatTimestamp;
|
|
14153
|
+
exports.frontmatterDetailed = frontmatterDetailed;
|
|
13772
14154
|
exports.frontmatterPreview = frontmatterPreview;
|
|
13773
14155
|
exports.frontmatterPreviewField = frontmatterPreviewField;
|
|
13774
14156
|
exports.frontmatterReferenceIndex = frontmatterReferenceIndex;
|
|
14157
|
+
exports.frontmatterSource = frontmatterSource;
|
|
13775
14158
|
exports.frontmatterSuggestions = frontmatterSuggestions;
|
|
13776
14159
|
exports.frontmatterVisibility = frontmatterVisibility;
|
|
13777
14160
|
exports.getClauseMeta = getClauseMeta;
|
|
@@ -13824,6 +14207,8 @@ exports.sectionRestore = sectionRestore;
|
|
|
13824
14207
|
exports.sectionSaved = sectionSaved;
|
|
13825
14208
|
exports.sessionQueryInsert = sessionQueryInsert;
|
|
13826
14209
|
exports.sessionQueryWql = sessionQueryWql;
|
|
14210
|
+
exports.setFrontmatterDetailed = setFrontmatterDetailed;
|
|
14211
|
+
exports.setFrontmatterSource = setFrontmatterSource;
|
|
13827
14212
|
exports.setGutterHighlights = setGutterHighlights;
|
|
13828
14213
|
exports.setSuggestionBinding = setSuggestionBinding;
|
|
13829
14214
|
exports.smartIncrement = smartIncrement;
|