@bitcobblers/wod-wiki-ui 0.37.2137 → 0.37.2140
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-RAM3QIP4.mjs → chunk-SNG34RG2.mjs} +450 -126
- package/dist/chunk-SNG34RG2.mjs.map +1 -0
- package/dist/extensions/index.cjs +446 -120
- 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-WiNbi7d3.d.cts → index-D4mgqtvt.d.cts} +60 -3
- package/dist/{index-WiNbi7d3.d.ts → index-D4mgqtvt.d.ts} +60 -3
- package/dist/index.cjs +452 -126
- 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/package.json +4 -4
- package/dist/chunk-RAM3QIP4.mjs.map +0 -1
|
@@ -3,11 +3,11 @@ import { HighlightStyle, syntaxTree, sublanguageProp, LRLanguage, indentNodeProp
|
|
|
3
3
|
import { tags, styleTags, Tag as Tag$1 } from '@lezer/highlight';
|
|
4
4
|
import { RangeSetBuilder, Facet, StateEffect, StateField, Prec, EditorState, EditorSelection, countColumn } from '@codemirror/state';
|
|
5
5
|
import { linter, forEachDiagnostic } from '@codemirror/lint';
|
|
6
|
-
import { whiteboardScriptLanguage, createParser, metricPresentation,
|
|
7
|
-
import { mapNoteBlockChanges, validateNoteBlocks, reconcileNoteBlocks, parseDocumentSections, actionableSectionKind, MetricType } from '@bitcobblers/wod-wiki-core';
|
|
6
|
+
import { whiteboardScriptLanguage, EFFORT_DISCIPLINES, createParser, metricPresentation, whiteboardScript } from '@bitcobblers/wod-wiki-lang';
|
|
7
|
+
import { mapNoteBlockChanges, validateNoteBlocks, reconcileNoteBlocks, parseDocumentSections, actionableSectionKind, patchFrontmatterProperty, MetricType } from '@bitcobblers/wod-wiki-core';
|
|
8
8
|
export { blockContentId } from '@bitcobblers/wod-wiki-core';
|
|
9
9
|
import { invertedEffects, history, defaultKeymap, historyKeymap, indentWithTab, cursorPageUp, cursorPageDown, cursorDocStart, cursorDocEnd } from '@codemirror/commands';
|
|
10
|
-
import { WQL_FIND_TARGETS, WQL_SOURCE_VALUES, WQL_RESULT_PLANES, WQL_AGGREGATORS, WQL_VIRTUAL_DIMS, WQL_TAG_KEYS, WQL_METRIC_AGGREGATES, WQL_METRIC_FAMILIES, WQL_CALC_TARGETS, WQL_DISPLAY_UNITS, WQL_INTENSITY_TIERS, parseQueryWidgetSuffix,
|
|
10
|
+
import { WQL_FIND_TARGETS, WQL_SOURCE_VALUES, WQL_RESULT_PLANES, WQL_AGGREGATORS, WQL_VIRTUAL_DIMS, WQL_TAG_KEYS, WQL_METRIC_AGGREGATES, WQL_METRIC_FAMILIES, WQL_CALC_TARGETS, WQL_DISPLAY_UNITS, WQL_INTENSITY_TIERS, parseQueryWidgetSuffix, parseFrontmatterBody, parseQuery, isFindQuery, isDashboardWidgetType, unknownWidgetTypeMessage, resolveWidgetType, PLANNED_WIDGET_TYPES, catalogOfItem, isPipelineQuery, wqlGroupingDimensions, isAggregateQuery, serialize, allowedFilterTypesForTarget, CONTENT_GROUPING_DIMENSIONS, substituteTokens, unknownTokensMessage, wql, WQL_NOTE_DEFAULT_SOURCES, wqlCompletionSource, wqlLanguage, wqlHighlightStyle, supportsWqlFilterKey } from '@bitcobblers/wod-wiki-wql';
|
|
11
11
|
export { CONTENT_GROUPING_DIMENSIONS } from '@bitcobblers/wod-wiki-wql';
|
|
12
12
|
import { snippet, autocompletion, closeBrackets, closeBracketsKeymap, completionStatus, startCompletion, moveCompletionSelection, setSelectedCompletion, currentCompletions, acceptCompletion, closeCompletion, CompletionContext, ifNotIn, completeFromList, snippetCompletion } from '@codemirror/autocomplete';
|
|
13
13
|
import { createRoot } from 'react-dom/client';
|
|
@@ -1016,6 +1016,8 @@ var embedPreviewDecorations = [
|
|
|
1016
1016
|
embedPreviewField
|
|
1017
1017
|
];
|
|
1018
1018
|
var frontmatterSuggestions = Facet.define({ combine: (providers) => providers[0] ?? null });
|
|
1019
|
+
var frontmatterReferenceIndex = Facet.define({ combine: (providers) => providers[0] ?? null });
|
|
1020
|
+
var referenceIndexReload = StateEffect.define();
|
|
1019
1021
|
var frontmatterVisibility = Facet.define({
|
|
1020
1022
|
combine: (values2) => values2[0] ?? true
|
|
1021
1023
|
});
|
|
@@ -1025,7 +1027,7 @@ var suggestionId = 0;
|
|
|
1025
1027
|
function isTagProperty(key) {
|
|
1026
1028
|
return ["tag", "tags", "category"].includes(key.trim().toLowerCase());
|
|
1027
1029
|
}
|
|
1028
|
-
function attachSuggestions(input, view, root, kind, key, excluded, commit) {
|
|
1030
|
+
function attachSuggestions(input, view, root, kind, key, excluded, commit, valueKind = "tags") {
|
|
1029
1031
|
const provider = view.state.facet(frontmatterSuggestions);
|
|
1030
1032
|
if (!provider || !input.parentElement) return;
|
|
1031
1033
|
const parent = input.parentElement;
|
|
@@ -1051,8 +1053,8 @@ function attachSuggestions(input, view, root, kind, key, excluded, commit) {
|
|
|
1051
1053
|
input.setAttribute("aria-expanded", "false");
|
|
1052
1054
|
input.removeAttribute("aria-activedescendant");
|
|
1053
1055
|
};
|
|
1054
|
-
const select = (
|
|
1055
|
-
input.value =
|
|
1056
|
+
const select = (choice) => {
|
|
1057
|
+
input.value = choice.value;
|
|
1056
1058
|
close();
|
|
1057
1059
|
commit();
|
|
1058
1060
|
};
|
|
@@ -1075,21 +1077,35 @@ function attachSuggestions(input, view, root, kind, key, excluded, commit) {
|
|
|
1075
1077
|
try {
|
|
1076
1078
|
const catalog = await provider();
|
|
1077
1079
|
if (request !== generation || !input.isConnected || document.activeElement !== input) return;
|
|
1078
|
-
|
|
1080
|
+
let candidates;
|
|
1081
|
+
if (kind === "key") {
|
|
1082
|
+
candidates = catalog.types.map((name) => ({ value: name, label: name, haystack: name }));
|
|
1083
|
+
} else if (valueKind === "effort" || valueKind === "equipment") {
|
|
1084
|
+
const entries = valueKind === "effort" ? catalog.efforts ?? [] : catalog.equipment ?? [];
|
|
1085
|
+
candidates = entries.map((entry) => ({
|
|
1086
|
+
value: entry.slug,
|
|
1087
|
+
label: `${entry.label} (${entry.slug})`,
|
|
1088
|
+
haystack: [entry.label, entry.slug, ...entry.aliases].join(" ").toLowerCase()
|
|
1089
|
+
}));
|
|
1090
|
+
} else {
|
|
1091
|
+
candidates = catalog.tags.filter((tag) => isTagProperty(key) || tag.type?.toLowerCase() === key.trim().toLowerCase()).map((tag) => ({ value: tag.label, label: tag.label, haystack: tag.label.toLowerCase() }));
|
|
1092
|
+
}
|
|
1079
1093
|
const selected = new Set(excluded.map((label) => label.toLowerCase()));
|
|
1080
|
-
choices =
|
|
1094
|
+
choices = candidates.filter(
|
|
1095
|
+
(candidate) => (query === "" || candidate.haystack.includes(query)) && !selected.has(candidate.value.toLowerCase())
|
|
1096
|
+
);
|
|
1081
1097
|
active = -1;
|
|
1082
1098
|
input.removeAttribute("aria-activedescendant");
|
|
1083
1099
|
list.replaceChildren();
|
|
1084
|
-
choices.forEach((
|
|
1100
|
+
choices.forEach((choice, index) => {
|
|
1085
1101
|
const option = document.createElement("div");
|
|
1086
1102
|
option.id = `${list.id}-${index}`;
|
|
1087
1103
|
option.setAttribute("role", "option");
|
|
1088
1104
|
option.setAttribute("aria-selected", "false");
|
|
1089
1105
|
option.className = "cursor-pointer px-2 py-1.5 hover:bg-muted";
|
|
1090
|
-
option.textContent = label;
|
|
1106
|
+
option.textContent = choice.label;
|
|
1091
1107
|
option.addEventListener("mousedown", (event) => event.preventDefault());
|
|
1092
|
-
option.addEventListener("click", () => select(
|
|
1108
|
+
option.addEventListener("click", () => select(choice));
|
|
1093
1109
|
list.appendChild(option);
|
|
1094
1110
|
});
|
|
1095
1111
|
list.hidden = choices.length === 0;
|
|
@@ -1132,45 +1148,66 @@ function parseTagList(val) {
|
|
|
1132
1148
|
}
|
|
1133
1149
|
return [];
|
|
1134
1150
|
}
|
|
1135
|
-
function
|
|
1151
|
+
function patchPropertyInView(view, _sectionId, path, value) {
|
|
1136
1152
|
if (view.state.readOnly) return;
|
|
1137
|
-
const
|
|
1138
|
-
const
|
|
1139
|
-
if (
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
const
|
|
1155
|
-
if (
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1153
|
+
const wholeDoc = view.state.doc.toString();
|
|
1154
|
+
const next = patchFrontmatterProperty(wholeDoc, path, value);
|
|
1155
|
+
if (next === wholeDoc) return;
|
|
1156
|
+
view.dispatch({ changes: { from: 0, to: wholeDoc.length, insert: next } });
|
|
1157
|
+
}
|
|
1158
|
+
function renamePropertyInView(view, _sectionId, fromKey, toKey, value) {
|
|
1159
|
+
if (view.state.readOnly) return;
|
|
1160
|
+
const wholeDoc = view.state.doc.toString();
|
|
1161
|
+
const next = patchFrontmatterProperty(
|
|
1162
|
+
patchFrontmatterProperty(wholeDoc, [toKey], value),
|
|
1163
|
+
[fromKey],
|
|
1164
|
+
null
|
|
1165
|
+
);
|
|
1166
|
+
if (next === wholeDoc) return;
|
|
1167
|
+
view.dispatch({ changes: { from: 0, to: wholeDoc.length, insert: next } });
|
|
1168
|
+
}
|
|
1169
|
+
function detectDefinitionKind(meta) {
|
|
1170
|
+
const type = typeof meta.type === "string" ? meta.type.trim().toLowerCase() : "";
|
|
1171
|
+
if (type === "effort") return "effort";
|
|
1172
|
+
if (type === "equipment") return "equipment";
|
|
1173
|
+
if (meta.registrySource !== void 0 || meta.baseAttributes !== void 0) return "effort";
|
|
1174
|
+
return null;
|
|
1175
|
+
}
|
|
1176
|
+
function readBaseAttributes(body) {
|
|
1177
|
+
const out = {};
|
|
1178
|
+
let inBase = false;
|
|
1179
|
+
for (const line of body.split(/\r?\n/)) {
|
|
1180
|
+
if (/^baseAttributes:\s*(#.*)?$/.test(line)) {
|
|
1181
|
+
inBase = true;
|
|
1182
|
+
continue;
|
|
1183
|
+
}
|
|
1184
|
+
if (!inBase) continue;
|
|
1185
|
+
if (/^\S/.test(line)) break;
|
|
1186
|
+
const match = line.match(/^\s+([\w-]+):\s*(.*)$/);
|
|
1187
|
+
if (!match) continue;
|
|
1188
|
+
if (match[1] === "met" || match[1] === "discipline" || match[1] === "intensityTier") {
|
|
1189
|
+
out[match[1]] = unquoteYamlScalar(match[2].trim());
|
|
1190
|
+
}
|
|
1173
1191
|
}
|
|
1192
|
+
return out;
|
|
1193
|
+
}
|
|
1194
|
+
function unquoteYamlScalar(val) {
|
|
1195
|
+
if (val.startsWith('"') && val.endsWith('"')) return val.slice(1, -1).replace(/\\(["\\])/g, "$1");
|
|
1196
|
+
if (val.startsWith("'") && val.endsWith("'")) return val.slice(1, -1).replace(/\\'/g, "'");
|
|
1197
|
+
return val;
|
|
1198
|
+
}
|
|
1199
|
+
function referenceValueKind(key, docKind) {
|
|
1200
|
+
const normalized = key.trim().toLowerCase();
|
|
1201
|
+
if (normalized === "metrics.effort") return "effort";
|
|
1202
|
+
if (normalized === "metrics.equipment" || normalized === "equipment") return "equipment";
|
|
1203
|
+
if (normalized === "aliases" && docKind === "equipment") return "equipment";
|
|
1204
|
+
if (normalized === "aliases" && docKind === "effort") return "effort";
|
|
1205
|
+
return "tags";
|
|
1206
|
+
}
|
|
1207
|
+
function isReferenceKey(key, docKind) {
|
|
1208
|
+
const normalized = key.trim().toLowerCase();
|
|
1209
|
+
if (normalized === "metrics.effort" || normalized === "metrics.equipment") return true;
|
|
1210
|
+
return normalized === "equipment" && docKind === "effort";
|
|
1174
1211
|
}
|
|
1175
1212
|
function createTagDraftRow(view, root, key, onCommit) {
|
|
1176
1213
|
const row = document.createElement("div");
|
|
@@ -1225,6 +1262,117 @@ function createTagDraftRow(view, root, key, onCommit) {
|
|
|
1225
1262
|
}));
|
|
1226
1263
|
return row;
|
|
1227
1264
|
}
|
|
1265
|
+
function ownsNestedBlock(body, key) {
|
|
1266
|
+
const lines = body.split(/\r?\n/);
|
|
1267
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1268
|
+
if (!new RegExp(`^${key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}:\\s*$`).test(lines[i])) continue;
|
|
1269
|
+
return i + 1 < lines.length && /^\s+\S/.test(lines[i + 1]);
|
|
1270
|
+
}
|
|
1271
|
+
return false;
|
|
1272
|
+
}
|
|
1273
|
+
function renderEffortValueDiagnostics(provider, token, onPick) {
|
|
1274
|
+
const trimmed = token.trim();
|
|
1275
|
+
if (!trimmed || provider.resolveEffort(trimmed)) return null;
|
|
1276
|
+
const diagnostics = provider.resolve(trimmed).diagnostics;
|
|
1277
|
+
const box = document.createElement("div");
|
|
1278
|
+
box.setAttribute("data-testid", "editor-ref-unknown");
|
|
1279
|
+
box.className = "w-full basis-full flex flex-wrap items-center gap-2 text-[10px] text-destructive";
|
|
1280
|
+
const message = document.createElement("span");
|
|
1281
|
+
message.textContent = diagnostics[0]?.message || `Unknown effort: ${trimmed}`;
|
|
1282
|
+
box.appendChild(message);
|
|
1283
|
+
for (const candidate of diagnostics[0]?.candidates ?? []) {
|
|
1284
|
+
const pickBtn = document.createElement("button");
|
|
1285
|
+
pickBtn.type = "button";
|
|
1286
|
+
pickBtn.textContent = `Use ${candidate}`;
|
|
1287
|
+
pickBtn.className = "underline hover:text-foreground cursor-pointer";
|
|
1288
|
+
pickBtn.addEventListener("click", (e) => {
|
|
1289
|
+
e.preventDefault();
|
|
1290
|
+
onPick(candidate);
|
|
1291
|
+
});
|
|
1292
|
+
box.appendChild(pickBtn);
|
|
1293
|
+
}
|
|
1294
|
+
const createLink = document.createElement("a");
|
|
1295
|
+
createLink.href = provider.createHref("effort");
|
|
1296
|
+
createLink.textContent = "Create page";
|
|
1297
|
+
createLink.className = "underline hover:text-foreground";
|
|
1298
|
+
box.appendChild(createLink);
|
|
1299
|
+
return box;
|
|
1300
|
+
}
|
|
1301
|
+
var METRIC_DRAFT_KINDS = {
|
|
1302
|
+
effort: { label: "Effort", path: "metrics.effort", kind: "effort" },
|
|
1303
|
+
equipment: { label: "Equipment", path: "metrics.equipment", kind: "equipment" },
|
|
1304
|
+
rpe: { label: "RPE", path: "metrics.rpe", kind: "number" }
|
|
1305
|
+
};
|
|
1306
|
+
function createMetricDraftRow(view, root, referenceProvider, commit) {
|
|
1307
|
+
const row = document.createElement("div");
|
|
1308
|
+
row.className = "flex items-center min-h-[34px] border-b border-dashed border-border/60 last:border-b-0 group hover:bg-muted/10 transition-colors max-[479px]:flex-col max-[479px]:items-stretch";
|
|
1309
|
+
row.setAttribute("data-frontmatter-metric-draft", "true");
|
|
1310
|
+
const select = document.createElement("select");
|
|
1311
|
+
select.setAttribute("aria-label", "Metric kind");
|
|
1312
|
+
select.className = "mx-3 my-1.5 h-7 w-28 shrink-0 rounded-md border border-input bg-background px-1.5 text-[11px] text-muted-foreground outline-none";
|
|
1313
|
+
for (const [value, spec] of Object.entries(METRIC_DRAFT_KINDS)) {
|
|
1314
|
+
const option = document.createElement("option");
|
|
1315
|
+
option.value = value;
|
|
1316
|
+
option.textContent = spec.label;
|
|
1317
|
+
select.appendChild(option);
|
|
1318
|
+
}
|
|
1319
|
+
row.appendChild(select);
|
|
1320
|
+
const valCol = document.createElement("div");
|
|
1321
|
+
valCol.className = "flex items-center flex-wrap gap-1.5 px-3 py-1.5 flex-1 min-w-0";
|
|
1322
|
+
const input = document.createElement("input");
|
|
1323
|
+
input.className = "flex-1 min-w-[70px] bg-transparent text-xs text-foreground outline-none px-1 py-0.5 placeholder:text-muted-foreground/40";
|
|
1324
|
+
input.placeholder = "Value\u2026";
|
|
1325
|
+
input.setAttribute("aria-label", "Metric value");
|
|
1326
|
+
valCol.appendChild(input);
|
|
1327
|
+
row.appendChild(valCol);
|
|
1328
|
+
let settled = false;
|
|
1329
|
+
const settle = (doCommit) => {
|
|
1330
|
+
if (settled) return;
|
|
1331
|
+
settled = true;
|
|
1332
|
+
const spec = METRIC_DRAFT_KINDS[select.value];
|
|
1333
|
+
const raw = input.value.trim();
|
|
1334
|
+
if (doCommit && spec && raw) {
|
|
1335
|
+
if (spec.kind === "equipment") commit([spec.path], [raw]);
|
|
1336
|
+
else if (spec.kind === "number") {
|
|
1337
|
+
const num = Number(raw);
|
|
1338
|
+
if (!Number.isNaN(num)) commit([spec.path], num);
|
|
1339
|
+
} else commit([spec.path], raw);
|
|
1340
|
+
}
|
|
1341
|
+
row.remove();
|
|
1342
|
+
view.requestMeasure();
|
|
1343
|
+
};
|
|
1344
|
+
const attachFor = () => {
|
|
1345
|
+
const spec = METRIC_DRAFT_KINDS[select.value];
|
|
1346
|
+
if (spec && (spec.kind === "effort" || spec.kind === "equipment") && referenceProvider) {
|
|
1347
|
+
attachSuggestions(input, view, root, "value", spec.path, [], () => settle(true), spec.kind);
|
|
1348
|
+
}
|
|
1349
|
+
};
|
|
1350
|
+
attachFor();
|
|
1351
|
+
select.addEventListener("change", attachFor);
|
|
1352
|
+
input.addEventListener("keydown", (e) => {
|
|
1353
|
+
if (e.defaultPrevented && e.key !== "Escape") return;
|
|
1354
|
+
if (e.key === "Escape") {
|
|
1355
|
+
e.preventDefault();
|
|
1356
|
+
settle(false);
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
if (e.key === "Enter") {
|
|
1360
|
+
e.preventDefault();
|
|
1361
|
+
settle(true);
|
|
1362
|
+
}
|
|
1363
|
+
});
|
|
1364
|
+
input.addEventListener("blur", () => queueMicrotask(() => {
|
|
1365
|
+
if (!input.isConnected) return;
|
|
1366
|
+
settle(input.value.trim().length > 0);
|
|
1367
|
+
}));
|
|
1368
|
+
select.addEventListener("keydown", (e) => {
|
|
1369
|
+
if (e.key === "Escape") {
|
|
1370
|
+
e.preventDefault();
|
|
1371
|
+
settle(false);
|
|
1372
|
+
}
|
|
1373
|
+
});
|
|
1374
|
+
return row;
|
|
1375
|
+
}
|
|
1228
1376
|
function createTagIcon() {
|
|
1229
1377
|
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
1230
1378
|
svg.setAttribute("viewBox", "0 0 24 24");
|
|
@@ -1337,26 +1485,11 @@ var DefaultFrontmatterWidget = class extends WidgetType {
|
|
|
1337
1485
|
sectionId;
|
|
1338
1486
|
rawContent;
|
|
1339
1487
|
readOnly;
|
|
1340
|
-
constructor(
|
|
1488
|
+
constructor(sectionId, rawContent, readOnly = false) {
|
|
1341
1489
|
super();
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
this.readOnly = readOnly;
|
|
1346
|
-
} else {
|
|
1347
|
-
this.sectionId = "legacy";
|
|
1348
|
-
this.rawContent = serializeFrontmatter(sectionIdOrProps);
|
|
1349
|
-
this.readOnly = readOnly;
|
|
1350
|
-
}
|
|
1351
|
-
}
|
|
1352
|
-
get props() {
|
|
1353
|
-
const body = this.rawContent.replace(/^---\r?\n?/, "").replace(/\r?\n?---\r?$/, "");
|
|
1354
|
-
const meta = parseFrontmatterBody(body);
|
|
1355
|
-
const result = {};
|
|
1356
|
-
for (const [k, v] of Object.entries(meta)) {
|
|
1357
|
-
result[k] = Array.isArray(v) ? v.join(", ") : String(v ?? "");
|
|
1358
|
-
}
|
|
1359
|
-
return result;
|
|
1490
|
+
this.sectionId = sectionId;
|
|
1491
|
+
this.rawContent = rawContent ?? "";
|
|
1492
|
+
this.readOnly = readOnly;
|
|
1360
1493
|
}
|
|
1361
1494
|
eq(other) {
|
|
1362
1495
|
return this.sectionId === other.sectionId && this.rawContent === other.rawContent && this.readOnly === other.readOnly;
|
|
@@ -1378,6 +1511,9 @@ var DefaultFrontmatterWidget = class extends WidgetType {
|
|
|
1378
1511
|
const body = this.rawContent.replace(/^---\r?\n?/, "").replace(/\r?\n?---\r?$/, "");
|
|
1379
1512
|
const meta = parseFrontmatterBody(body);
|
|
1380
1513
|
const entries = Object.entries(meta);
|
|
1514
|
+
const docKind = detectDefinitionKind(meta);
|
|
1515
|
+
const referenceProvider = view.state.facet(frontmatterReferenceIndex)?.() ?? null;
|
|
1516
|
+
const base = docKind === "effort" ? readBaseAttributes(body) : {};
|
|
1381
1517
|
if (entries.length === 0) {
|
|
1382
1518
|
const emptyRow = document.createElement("div");
|
|
1383
1519
|
emptyRow.className = "px-3 py-2 text-xs text-muted-foreground/60 italic";
|
|
@@ -1386,13 +1522,16 @@ var DefaultFrontmatterWidget = class extends WidgetType {
|
|
|
1386
1522
|
}
|
|
1387
1523
|
for (const [key, value] of entries) {
|
|
1388
1524
|
const isTags = isTagProperty(key);
|
|
1525
|
+
const valueKind = referenceValueKind(key, docKind);
|
|
1526
|
+
const isReferenceList = (isReferenceKey(key, docKind) || key === "aliases") && Array.isArray(value);
|
|
1527
|
+
const nested = value === "" && ownsNestedBlock(body, key);
|
|
1389
1528
|
const row = document.createElement("div");
|
|
1390
1529
|
row.className = "flex items-center min-h-[34px] border-b border-dashed border-border/60 last:border-b-0 group hover:bg-muted/10 transition-colors max-[479px]:flex-col max-[479px]:items-stretch";
|
|
1391
1530
|
box.appendChild(row);
|
|
1392
1531
|
const keyCol = document.createElement("div");
|
|
1393
1532
|
keyCol.className = "flex items-center gap-2 px-3 py-1.5 w-36 shrink-0 border-r border-dashed border-border/60 text-muted-foreground max-[479px]:w-auto max-[479px]:border-r-0 max-[479px]:border-b";
|
|
1394
|
-
keyCol.appendChild(isTags ? createTagIcon() : createListIcon());
|
|
1395
|
-
if (this.readOnly) {
|
|
1533
|
+
keyCol.appendChild(isTags || isReferenceList ? createTagIcon() : createListIcon());
|
|
1534
|
+
if (this.readOnly || nested) {
|
|
1396
1535
|
const keyLabel = document.createElement("span");
|
|
1397
1536
|
keyLabel.className = "truncate font-medium text-foreground/90";
|
|
1398
1537
|
keyLabel.textContent = key;
|
|
@@ -1414,15 +1553,10 @@ var DefaultFrontmatterWidget = class extends WidgetType {
|
|
|
1414
1553
|
keyInput.value = currentKey;
|
|
1415
1554
|
return;
|
|
1416
1555
|
}
|
|
1417
|
-
|
|
1418
|
-
for (const [k, v] of Object.entries(meta)) {
|
|
1419
|
-
if (k === currentKey) newMeta[nextKey] = v;
|
|
1420
|
-
else newMeta[k] = v;
|
|
1421
|
-
}
|
|
1556
|
+
renamePropertyInView(view, this.sectionId, currentKey, nextKey, value);
|
|
1422
1557
|
delete meta[currentKey];
|
|
1423
|
-
meta[nextKey] =
|
|
1558
|
+
meta[nextKey] = value;
|
|
1424
1559
|
currentKey = nextKey;
|
|
1425
|
-
updateFrontmatter(view, this.sectionId, newMeta);
|
|
1426
1560
|
};
|
|
1427
1561
|
const commitKeyIfAttached = () => queueMicrotask(() => {
|
|
1428
1562
|
if (keyInput.isConnected) commitKey();
|
|
@@ -1451,71 +1585,117 @@ var DefaultFrontmatterWidget = class extends WidgetType {
|
|
|
1451
1585
|
row.appendChild(keyCol);
|
|
1452
1586
|
const valCol = document.createElement("div");
|
|
1453
1587
|
valCol.className = "flex items-center flex-wrap gap-1.5 px-3 py-1.5 flex-1 min-w-0";
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1588
|
+
const commitList = (next) => {
|
|
1589
|
+
meta[key] = next;
|
|
1590
|
+
patchPropertyInView(view, this.sectionId, [key], next.length > 0 ? next : "");
|
|
1591
|
+
};
|
|
1592
|
+
const refMatch = (token) => {
|
|
1593
|
+
if (!referenceProvider) return null;
|
|
1594
|
+
return valueKind === "effort" ? referenceProvider.resolveEffort(token) : valueKind === "equipment" ? referenceProvider.resolveEquipment(token) : null;
|
|
1595
|
+
};
|
|
1596
|
+
if (isTags || isReferenceList) {
|
|
1597
|
+
const chips = parseTagList(value);
|
|
1598
|
+
const chipIsReference = valueKind !== "tags";
|
|
1599
|
+
for (let idx = 0; idx < chips.length; idx++) {
|
|
1600
|
+
const chip = chips[idx];
|
|
1601
|
+
const match = chipIsReference ? refMatch(chip) : null;
|
|
1458
1602
|
const pill = document.createElement("span");
|
|
1459
|
-
pill.className = "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";
|
|
1460
|
-
const
|
|
1461
|
-
|
|
1462
|
-
pill.appendChild(
|
|
1603
|
+
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";
|
|
1604
|
+
const pillText = document.createElement("span");
|
|
1605
|
+
pillText.textContent = match ? match.label : chip;
|
|
1606
|
+
pill.appendChild(pillText);
|
|
1607
|
+
if (match && referenceProvider) {
|
|
1608
|
+
const openLink = document.createElement("a");
|
|
1609
|
+
openLink.href = referenceProvider.openHref(valueKind, match.slug);
|
|
1610
|
+
openLink.title = `Open ${match.label} page`;
|
|
1611
|
+
openLink.setAttribute("aria-label", `Open ${match.label} page`);
|
|
1612
|
+
openLink.className = "inline-flex items-center justify-center text-muted-foreground/60 hover:text-foreground cursor-pointer";
|
|
1613
|
+
openLink.appendChild(createExternalIcon());
|
|
1614
|
+
pill.appendChild(openLink);
|
|
1615
|
+
}
|
|
1463
1616
|
if (!this.readOnly) {
|
|
1464
1617
|
const rmBtn = document.createElement("button");
|
|
1465
1618
|
rmBtn.type = "button";
|
|
1466
|
-
rmBtn.setAttribute("aria-label", `Remove tag ${
|
|
1467
|
-
rmBtn.className = "inline-flex items-center justify-center text-
|
|
1619
|
+
rmBtn.setAttribute("aria-label", isTags ? `Remove tag ${chip}` : `Remove ${chip}`);
|
|
1620
|
+
rmBtn.className = "inline-flex items-center justify-center text-muted-foreground/60 hover:text-foreground dark:hover:text-foreground cursor-pointer";
|
|
1468
1621
|
rmBtn.appendChild(createCloseIcon("sm"));
|
|
1469
1622
|
rmBtn.addEventListener("click", (e) => {
|
|
1470
1623
|
e.preventDefault();
|
|
1471
1624
|
e.stopPropagation();
|
|
1472
|
-
|
|
1473
|
-
meta[key] = nextTags;
|
|
1474
|
-
updateFrontmatter(view, this.sectionId, meta);
|
|
1625
|
+
commitList(chips.filter((_, i) => i !== idx));
|
|
1475
1626
|
});
|
|
1476
1627
|
pill.appendChild(rmBtn);
|
|
1477
1628
|
}
|
|
1478
1629
|
valCol.appendChild(pill);
|
|
1479
1630
|
}
|
|
1480
1631
|
if (!this.readOnly) {
|
|
1481
|
-
const
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
const
|
|
1486
|
-
const val =
|
|
1487
|
-
if (val && !
|
|
1488
|
-
|
|
1489
|
-
tagInput.value = "";
|
|
1632
|
+
const chipInput = document.createElement("input");
|
|
1633
|
+
chipInput.className = "flex-1 min-w-[70px] bg-transparent text-xs text-foreground outline-none px-1 py-0.5 placeholder:text-muted-foreground/40";
|
|
1634
|
+
chipInput.placeholder = chips.length === 0 ? isReferenceList ? `Add ${valueKind === "effort" ? "effort" : "equipment"}\u2026` : "Add tags\u2026" : isTags ? "Add tag\u2026" : "Add\u2026";
|
|
1635
|
+
chipInput.setAttribute("aria-label", isTags ? `Add tag to ${key}` : `Add to ${key}`);
|
|
1636
|
+
const commitNewChip = () => {
|
|
1637
|
+
const val = chipInput.value.trim().replace(/^,|,$/g, "");
|
|
1638
|
+
if (val && !chips.some((chip) => chip.toLowerCase() === val.toLowerCase())) {
|
|
1639
|
+
chipInput.value = "";
|
|
1490
1640
|
pendingFocus.set(view, { kind: "tag", key });
|
|
1491
|
-
|
|
1641
|
+
commitList([...chips, val]);
|
|
1492
1642
|
}
|
|
1493
1643
|
};
|
|
1494
|
-
valCol.appendChild(
|
|
1495
|
-
attachSuggestions(
|
|
1496
|
-
|
|
1644
|
+
valCol.appendChild(chipInput);
|
|
1645
|
+
attachSuggestions(chipInput, view, root, "value", key, chips, commitNewChip, valueKind);
|
|
1646
|
+
chipInput.addEventListener("keydown", (e) => {
|
|
1497
1647
|
if (e.defaultPrevented) return;
|
|
1498
1648
|
if (e.key === "Enter" || e.key === ",") {
|
|
1499
1649
|
e.preventDefault();
|
|
1500
|
-
|
|
1501
|
-
} else if (e.key === "Backspace" && !
|
|
1650
|
+
commitNewChip();
|
|
1651
|
+
} else if (e.key === "Backspace" && !chipInput.value && chips.length > 0) {
|
|
1502
1652
|
e.preventDefault();
|
|
1503
|
-
meta[key] = tags7.slice(0, -1);
|
|
1504
1653
|
pendingFocus.set(view, { kind: "tag", key });
|
|
1505
|
-
|
|
1654
|
+
commitList(chips.slice(0, -1));
|
|
1506
1655
|
}
|
|
1507
1656
|
});
|
|
1508
|
-
|
|
1509
|
-
if (
|
|
1657
|
+
chipInput.addEventListener("blur", () => queueMicrotask(() => {
|
|
1658
|
+
if (chipInput.isConnected && chipInput.value.trim()) commitNewChip();
|
|
1510
1659
|
}));
|
|
1511
1660
|
const focus = pendingFocus.get(view);
|
|
1512
1661
|
if (focus?.kind === "tag" && focus.key === key) {
|
|
1513
1662
|
setTimeout(() => {
|
|
1514
|
-
if (
|
|
1663
|
+
if (chipInput.isConnected) chipInput.focus();
|
|
1515
1664
|
}, 0);
|
|
1516
1665
|
pendingFocus.delete(view);
|
|
1517
1666
|
}
|
|
1667
|
+
if (chipIsReference && referenceProvider) {
|
|
1668
|
+
const unknown = chips.filter((chip) => !refMatch(chip));
|
|
1669
|
+
if (unknown.length > 0) {
|
|
1670
|
+
const diag = document.createElement("div");
|
|
1671
|
+
diag.setAttribute("data-testid", "editor-ref-unknown");
|
|
1672
|
+
diag.className = "w-full basis-full flex flex-wrap items-center gap-2 text-[10px] text-destructive";
|
|
1673
|
+
const label = document.createElement("span");
|
|
1674
|
+
label.textContent = `Unknown ${valueKind === "effort" ? "effort" : "equipment"}: ${unknown.join(", ")}`;
|
|
1675
|
+
diag.appendChild(label);
|
|
1676
|
+
const selectBtn = document.createElement("button");
|
|
1677
|
+
selectBtn.type = "button";
|
|
1678
|
+
selectBtn.textContent = "Select existing";
|
|
1679
|
+
selectBtn.className = "underline hover:text-foreground cursor-pointer";
|
|
1680
|
+
selectBtn.addEventListener("click", (e) => {
|
|
1681
|
+
e.preventDefault();
|
|
1682
|
+
chipInput.focus();
|
|
1683
|
+
});
|
|
1684
|
+
diag.appendChild(selectBtn);
|
|
1685
|
+
const createLink = document.createElement("a");
|
|
1686
|
+
createLink.href = referenceProvider.createHref(valueKind);
|
|
1687
|
+
createLink.textContent = "Create page";
|
|
1688
|
+
createLink.className = "underline hover:text-foreground";
|
|
1689
|
+
diag.appendChild(createLink);
|
|
1690
|
+
valCol.appendChild(diag);
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1518
1693
|
}
|
|
1694
|
+
} else if (nested) {
|
|
1695
|
+
const valSpan = document.createElement("span");
|
|
1696
|
+
valSpan.className = "text-xs text-muted-foreground/60 italic py-0.5 truncate";
|
|
1697
|
+
valSpan.textContent = "Nested block \u2014 edit in YAML";
|
|
1698
|
+
valCol.appendChild(valSpan);
|
|
1519
1699
|
} else {
|
|
1520
1700
|
const strVal = Array.isArray(value) ? value.join(", ") : String(value ?? "");
|
|
1521
1701
|
if (this.readOnly) {
|
|
@@ -1535,8 +1715,9 @@ var DefaultFrontmatterWidget = class extends WidgetType {
|
|
|
1535
1715
|
if (cur !== committedVal) {
|
|
1536
1716
|
committedVal = cur;
|
|
1537
1717
|
const num = Number(cur);
|
|
1538
|
-
|
|
1539
|
-
|
|
1718
|
+
const next = cur !== "" && !isNaN(num) ? num : cur;
|
|
1719
|
+
meta[key] = next;
|
|
1720
|
+
patchPropertyInView(view, this.sectionId, [key], next);
|
|
1540
1721
|
}
|
|
1541
1722
|
};
|
|
1542
1723
|
const commitValIfAttached = () => queueMicrotask(() => {
|
|
@@ -1544,7 +1725,16 @@ var DefaultFrontmatterWidget = class extends WidgetType {
|
|
|
1544
1725
|
});
|
|
1545
1726
|
valInput.addEventListener("change", commitValIfAttached);
|
|
1546
1727
|
valCol.appendChild(valInput);
|
|
1547
|
-
attachSuggestions(
|
|
1728
|
+
attachSuggestions(
|
|
1729
|
+
valInput,
|
|
1730
|
+
view,
|
|
1731
|
+
root,
|
|
1732
|
+
"value",
|
|
1733
|
+
key,
|
|
1734
|
+
[strVal],
|
|
1735
|
+
commitVal,
|
|
1736
|
+
key.trim().toLowerCase() === "metrics.effort" ? "effort" : "tags"
|
|
1737
|
+
);
|
|
1548
1738
|
valInput.addEventListener("blur", commitValIfAttached);
|
|
1549
1739
|
valInput.addEventListener("keydown", (e) => {
|
|
1550
1740
|
if (e.defaultPrevented) return;
|
|
@@ -1553,6 +1743,34 @@ var DefaultFrontmatterWidget = class extends WidgetType {
|
|
|
1553
1743
|
valInput.blur();
|
|
1554
1744
|
}
|
|
1555
1745
|
});
|
|
1746
|
+
if (key.trim().toLowerCase() === "metrics.effort" && referenceProvider) {
|
|
1747
|
+
const match = referenceProvider.resolveEffort(strVal);
|
|
1748
|
+
if (match) {
|
|
1749
|
+
const pill = document.createElement("span");
|
|
1750
|
+
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";
|
|
1751
|
+
const pillText = document.createElement("span");
|
|
1752
|
+
pillText.textContent = match.label;
|
|
1753
|
+
pill.appendChild(pillText);
|
|
1754
|
+
const openLink = document.createElement("a");
|
|
1755
|
+
openLink.href = referenceProvider.openHref("effort", match.slug);
|
|
1756
|
+
openLink.title = `Open ${match.label} page`;
|
|
1757
|
+
openLink.setAttribute("aria-label", `Open ${match.label} page`);
|
|
1758
|
+
openLink.className = "inline-flex items-center justify-center text-muted-foreground/60 hover:text-foreground cursor-pointer";
|
|
1759
|
+
openLink.appendChild(createExternalIcon());
|
|
1760
|
+
pill.appendChild(openLink);
|
|
1761
|
+
valCol.insertBefore(pill, valInput);
|
|
1762
|
+
valInput.className = "flex-1 min-w-[70px] bg-transparent text-xs text-foreground outline-none py-0.5 hover:bg-muted/20 focus:bg-background focus:ring-1 focus:ring-ring rounded px-1 -mx-1 transition-colors";
|
|
1763
|
+
}
|
|
1764
|
+
const diag = renderEffortValueDiagnostics(
|
|
1765
|
+
referenceProvider,
|
|
1766
|
+
strVal,
|
|
1767
|
+
(slug) => {
|
|
1768
|
+
meta[key] = slug;
|
|
1769
|
+
patchPropertyInView(view, this.sectionId, [key], slug);
|
|
1770
|
+
}
|
|
1771
|
+
);
|
|
1772
|
+
if (diag) valCol.appendChild(diag);
|
|
1773
|
+
}
|
|
1556
1774
|
}
|
|
1557
1775
|
if (/^https?:\/\/\S+$/i.test(strVal)) {
|
|
1558
1776
|
const openLink = document.createElement("a");
|
|
@@ -1567,7 +1785,7 @@ var DefaultFrontmatterWidget = class extends WidgetType {
|
|
|
1567
1785
|
}
|
|
1568
1786
|
}
|
|
1569
1787
|
row.appendChild(valCol);
|
|
1570
|
-
if (!this.readOnly) {
|
|
1788
|
+
if (!this.readOnly && !nested) {
|
|
1571
1789
|
const actionsCol = document.createElement("div");
|
|
1572
1790
|
actionsCol.className = "flex items-center pr-2";
|
|
1573
1791
|
const delBtn = document.createElement("button");
|
|
@@ -1578,14 +1796,16 @@ var DefaultFrontmatterWidget = class extends WidgetType {
|
|
|
1578
1796
|
delBtn.addEventListener("click", (e) => {
|
|
1579
1797
|
e.preventDefault();
|
|
1580
1798
|
e.stopPropagation();
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
updateFrontmatter(view, this.sectionId, newMeta);
|
|
1799
|
+
delete meta[key];
|
|
1800
|
+
patchPropertyInView(view, this.sectionId, [key], null);
|
|
1584
1801
|
});
|
|
1585
1802
|
actionsCol.appendChild(delBtn);
|
|
1586
1803
|
row.appendChild(actionsCol);
|
|
1587
1804
|
}
|
|
1588
1805
|
}
|
|
1806
|
+
if (docKind === "effort" && !this.readOnly) {
|
|
1807
|
+
box.appendChild(this.buildDefinitionRows(view, base));
|
|
1808
|
+
}
|
|
1589
1809
|
if (!this.readOnly) {
|
|
1590
1810
|
const existingTagKey = entries.find(([key]) => isTagProperty(key))?.[0];
|
|
1591
1811
|
const actionsRow = document.createElement("div");
|
|
@@ -1608,10 +1828,36 @@ var DefaultFrontmatterWidget = class extends WidgetType {
|
|
|
1608
1828
|
newKey = `property_${count2}`;
|
|
1609
1829
|
}
|
|
1610
1830
|
pendingFocus.set(view, { kind: "key", key: newKey });
|
|
1611
|
-
|
|
1612
|
-
updateFrontmatter(view, this.sectionId, newMeta);
|
|
1831
|
+
patchPropertyInView(view, this.sectionId, [newKey], "");
|
|
1613
1832
|
});
|
|
1614
1833
|
actionsRow.appendChild(addBtn);
|
|
1834
|
+
{
|
|
1835
|
+
const addMetricBtn = document.createElement("button");
|
|
1836
|
+
addMetricBtn.type = "button";
|
|
1837
|
+
addMetricBtn.setAttribute("aria-label", "Add metric");
|
|
1838
|
+
addMetricBtn.setAttribute("data-testid", "editor-add-metric-note");
|
|
1839
|
+
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";
|
|
1840
|
+
addMetricBtn.appendChild(createPlusIcon());
|
|
1841
|
+
const addMetricLabel = document.createElement("span");
|
|
1842
|
+
addMetricLabel.textContent = "Add metric";
|
|
1843
|
+
addMetricBtn.appendChild(addMetricLabel);
|
|
1844
|
+
addMetricBtn.addEventListener("click", (e) => {
|
|
1845
|
+
e.preventDefault();
|
|
1846
|
+
e.stopPropagation();
|
|
1847
|
+
const existing = root.querySelector("[data-frontmatter-metric-draft] input");
|
|
1848
|
+
if (existing) {
|
|
1849
|
+
existing.focus();
|
|
1850
|
+
return;
|
|
1851
|
+
}
|
|
1852
|
+
const draftRow = createMetricDraftRow(view, root, referenceProvider, (path, value) => {
|
|
1853
|
+
patchPropertyInView(view, this.sectionId, path, value);
|
|
1854
|
+
});
|
|
1855
|
+
box.appendChild(draftRow);
|
|
1856
|
+
draftRow.querySelector("input")?.focus();
|
|
1857
|
+
view.requestMeasure();
|
|
1858
|
+
});
|
|
1859
|
+
actionsRow.appendChild(addMetricBtn);
|
|
1860
|
+
}
|
|
1615
1861
|
{
|
|
1616
1862
|
const addTagBtn = document.createElement("button");
|
|
1617
1863
|
addTagBtn.type = "button";
|
|
@@ -1636,7 +1882,7 @@ var DefaultFrontmatterWidget = class extends WidgetType {
|
|
|
1636
1882
|
}
|
|
1637
1883
|
const draftRow = createTagDraftRow(view, root, "tags", (val) => {
|
|
1638
1884
|
pendingFocus.set(view, { kind: "tag", key: "tags" });
|
|
1639
|
-
|
|
1885
|
+
patchPropertyInView(view, this.sectionId, ["tags"], [val]);
|
|
1640
1886
|
});
|
|
1641
1887
|
box.appendChild(draftRow);
|
|
1642
1888
|
draftRow.querySelector("input")?.focus();
|
|
@@ -1648,6 +1894,7 @@ var DefaultFrontmatterWidget = class extends WidgetType {
|
|
|
1648
1894
|
const editYamlBtn = document.createElement("button");
|
|
1649
1895
|
editYamlBtn.type = "button";
|
|
1650
1896
|
editYamlBtn.setAttribute("aria-label", "Edit YAML");
|
|
1897
|
+
editYamlBtn.setAttribute("data-testid", "editor-property-edit-yaml");
|
|
1651
1898
|
editYamlBtn.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";
|
|
1652
1899
|
const editYamlLabel = document.createElement("span");
|
|
1653
1900
|
editYamlLabel.textContent = "Edit YAML";
|
|
@@ -1667,6 +1914,82 @@ var DefaultFrontmatterWidget = class extends WidgetType {
|
|
|
1667
1914
|
}
|
|
1668
1915
|
return root;
|
|
1669
1916
|
}
|
|
1917
|
+
/**
|
|
1918
|
+
* Effort-definition attribute rows (MET / discipline / intensity tier).
|
|
1919
|
+
* Values live in the nested baseAttributes block; each edit patches that
|
|
1920
|
+
* one path, so unknown sibling keys and comments elsewhere survive.
|
|
1921
|
+
*/
|
|
1922
|
+
buildDefinitionRows(view, base) {
|
|
1923
|
+
const wrap = document.createElement("div");
|
|
1924
|
+
wrap.setAttribute("data-frontmatter-definition", "true");
|
|
1925
|
+
wrap.className = "border-t border-dashed border-border/60";
|
|
1926
|
+
const header = document.createElement("div");
|
|
1927
|
+
header.className = "px-3 pt-2 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground";
|
|
1928
|
+
header.textContent = "Definition";
|
|
1929
|
+
wrap.appendChild(header);
|
|
1930
|
+
const commitField = (field, raw) => {
|
|
1931
|
+
if (field === "met") {
|
|
1932
|
+
const num = Number(raw);
|
|
1933
|
+
patchPropertyInView(view, this.sectionId, ["baseAttributes", "met"], raw !== "" && !Number.isNaN(num) ? num : null);
|
|
1934
|
+
return;
|
|
1935
|
+
}
|
|
1936
|
+
patchPropertyInView(view, this.sectionId, ["baseAttributes", field], raw === "" ? null : raw);
|
|
1937
|
+
};
|
|
1938
|
+
const fieldRow = (label, child) => {
|
|
1939
|
+
const row = document.createElement("label");
|
|
1940
|
+
row.className = "flex items-center gap-2 px-3 py-1.5 min-h-[34px] border-b border-dashed border-border/60 last:border-b-0 max-[479px]:flex-col max-[479px]:items-stretch";
|
|
1941
|
+
const name = document.createElement("span");
|
|
1942
|
+
name.className = "w-28 shrink-0 text-muted-foreground";
|
|
1943
|
+
name.textContent = label;
|
|
1944
|
+
row.appendChild(name);
|
|
1945
|
+
child.className = "flex-1 min-w-0 bg-transparent text-xs text-foreground outline-none py-0.5";
|
|
1946
|
+
row.appendChild(child);
|
|
1947
|
+
wrap.appendChild(row);
|
|
1948
|
+
};
|
|
1949
|
+
const met = document.createElement("input");
|
|
1950
|
+
met.type = "number";
|
|
1951
|
+
met.step = "0.1";
|
|
1952
|
+
met.inputMode = "decimal";
|
|
1953
|
+
met.value = base.met ?? "";
|
|
1954
|
+
met.setAttribute("aria-label", "MET value");
|
|
1955
|
+
met.addEventListener("change", () => queueMicrotask(() => {
|
|
1956
|
+
if (met.isConnected) commitField("met", met.value.trim());
|
|
1957
|
+
}));
|
|
1958
|
+
fieldRow("MET", met);
|
|
1959
|
+
const discipline = document.createElement("select");
|
|
1960
|
+
discipline.setAttribute("aria-label", "Discipline");
|
|
1961
|
+
discipline.className = "flex-1 min-w-0 rounded-md border border-input bg-background px-1.5 text-[11px] text-muted-foreground outline-none";
|
|
1962
|
+
const unset = document.createElement("option");
|
|
1963
|
+
unset.value = "";
|
|
1964
|
+
unset.textContent = "Unset";
|
|
1965
|
+
discipline.appendChild(unset);
|
|
1966
|
+
for (const option of EFFORT_DISCIPLINES) {
|
|
1967
|
+
const opt = document.createElement("option");
|
|
1968
|
+
opt.value = option;
|
|
1969
|
+
opt.textContent = option;
|
|
1970
|
+
discipline.appendChild(opt);
|
|
1971
|
+
}
|
|
1972
|
+
discipline.value = base.discipline ?? "";
|
|
1973
|
+
discipline.addEventListener("change", () => commitField("discipline", discipline.value));
|
|
1974
|
+
fieldRow("Discipline", discipline);
|
|
1975
|
+
const tier = document.createElement("select");
|
|
1976
|
+
tier.setAttribute("aria-label", "Intensity tier");
|
|
1977
|
+
tier.className = "flex-1 min-w-0 rounded-md border border-input bg-background px-1.5 text-[11px] text-muted-foreground outline-none";
|
|
1978
|
+
const tierUnset = document.createElement("option");
|
|
1979
|
+
tierUnset.value = "";
|
|
1980
|
+
tierUnset.textContent = "Unset";
|
|
1981
|
+
tier.appendChild(tierUnset);
|
|
1982
|
+
for (const option of ["low", "moderate", "high"]) {
|
|
1983
|
+
const opt = document.createElement("option");
|
|
1984
|
+
opt.value = option;
|
|
1985
|
+
opt.textContent = option;
|
|
1986
|
+
tier.appendChild(opt);
|
|
1987
|
+
}
|
|
1988
|
+
tier.value = base.intensityTier ?? "";
|
|
1989
|
+
tier.addEventListener("change", () => commitField("intensityTier", tier.value));
|
|
1990
|
+
fieldRow("Intensity tier", tier);
|
|
1991
|
+
return wrap;
|
|
1992
|
+
}
|
|
1670
1993
|
destroy(dom) {
|
|
1671
1994
|
widgetCleanup.get(dom)?.forEach((close) => close());
|
|
1672
1995
|
widgetCleanup.delete(dom);
|
|
@@ -1700,7 +2023,7 @@ var EmptyFrontmatterWidget = class extends WidgetType {
|
|
|
1700
2023
|
e.preventDefault();
|
|
1701
2024
|
e.stopPropagation();
|
|
1702
2025
|
pendingFocus.set(view, { kind: "key", key: "property" });
|
|
1703
|
-
|
|
2026
|
+
patchPropertyInView(view, "new", ["property"], "");
|
|
1704
2027
|
});
|
|
1705
2028
|
actionsRow.appendChild(addBtn);
|
|
1706
2029
|
const addTagBtn = document.createElement("button");
|
|
@@ -1721,7 +2044,7 @@ var EmptyFrontmatterWidget = class extends WidgetType {
|
|
|
1721
2044
|
}
|
|
1722
2045
|
const draftRow = createTagDraftRow(view, root, "tags", (val) => {
|
|
1723
2046
|
pendingFocus.set(view, { kind: "tag", key: "tags" });
|
|
1724
|
-
|
|
2047
|
+
patchPropertyInView(view, "new", ["tags"], [val]);
|
|
1725
2048
|
});
|
|
1726
2049
|
root.appendChild(draftRow);
|
|
1727
2050
|
draftRow.querySelector("input")?.focus();
|
|
@@ -1775,7 +2098,7 @@ var frontmatterPreviewField = StateField.define({
|
|
|
1775
2098
|
return buildFrontmatterDecos(state);
|
|
1776
2099
|
},
|
|
1777
2100
|
update(deco, tr) {
|
|
1778
|
-
if (tr.docChanged || tr.reconfigured || tr.selection) {
|
|
2101
|
+
if (tr.docChanged || tr.reconfigured || tr.selection || tr.effects.some((e) => e.is(referenceIndexReload))) {
|
|
1779
2102
|
return buildFrontmatterDecos(tr.state);
|
|
1780
2103
|
}
|
|
1781
2104
|
return deco;
|
|
@@ -4291,7 +4614,8 @@ var SOURCE_OPTIONS = WQL_SOURCE_VALUES.map((s) => ({
|
|
|
4291
4614
|
guides: "Static guide pages",
|
|
4292
4615
|
playground: "Playground scratch pages",
|
|
4293
4616
|
dashboards: "Dashboard notes",
|
|
4294
|
-
efforts: "Exercise library notes"
|
|
4617
|
+
efforts: "Exercise library notes",
|
|
4618
|
+
equipment: "Equipment library notes"
|
|
4295
4619
|
}[s]
|
|
4296
4620
|
}));
|
|
4297
4621
|
var PLANE_OPTIONS = WQL_RESULT_PLANES.map((v) => ({ value: v, label: v }));
|
|
@@ -12333,6 +12657,6 @@ function editorPreset(optionsOrDialect = "markdown") {
|
|
|
12333
12657
|
return extensions;
|
|
12334
12658
|
}
|
|
12335
12659
|
|
|
12336
|
-
export { AGG_OPTIONS, CANONICAL_BLOCK_TYPES, CLAUSE_META, ComposerRegistry, DEFAULT_DIAGNOSTICS_DEBOUNCE_MS, DEFAULT_OUTPUT_FILTERS, DEFAULT_PRIMARY_FILTER, DefaultFrontmatterWidget, EditorDialog, GROUPBY_OPTIONS, GoalRings, KIND_OPTIONS, METRIC_OPTIONS, MULTI_VALUE_TYPES, MetricBadge, OUTPUT_TYPE_CLASS, OUTPUT_TYPE_DOT, OutputFilterPills, OutputStatementsTable, PLANE_OPTIONS, ProposedMetricBadge, QueryBlockView, QueryValue, ROLLUP_OPTIONS, RowsResultsChrome, RowsTable, SERIES_COLORS, SOURCE_OPTIONS, SUGGESTION_BINDINGS, StackedBar, TARGET_OPTIONS, TIME_OPTIONS, TONE_CLASS, TokenSlotPill, TopList, UNIT_OPTIONS, WHERE_AGGREGATORS, WHERE_METRICS, WidgetChart, WidgetProblemBadge, WqlBars, WqlComposer, WqlDiagnosticsStrip, WqlEmptyState, WqlQueryInspectorModal, WqlTable, WqlTimeseries, ZoneDistribution, activeCursorSection, addRuntimePanel, blockTypesFromBlocks, canonicalSuggestionItems, catalogIdsFromBlocks, cn, compactNumber, composerRegistry, configureOverlayActions, cursorFocusExtension, dateRangeSlot, dispatchAddRuntimePanel, dispatchExpandRuntimePanel, dispatchGutterHighlights, dispatchRemoveRuntimePanel, editQueryClause, editingWidgetsField, editorPreset, editorTheme, embedPreviewDecorations, expandRuntimePanel, extractBlockQueries, extractMetricsByCategory, fenceCompletion, findQueryBlockSection, findWorkoutErrors, forceSectionParse, formatClockTime, formatMMSS, formatTimestamp, frontmatterPreview, frontmatterPreviewField, frontmatterSuggestions, frontmatterVisibility, getClauseMeta, getCursorFocusState, getOverlayActions, getSuggestionBinding, gutterHighlightsField, gutterUnified, handleFenceAutoWrap, hashCode, inlineButtonDecoration, invalidateSuggestions, lineIdsExtension, linkOpen, linkPreview, loadSuggestions, markdownSyntaxHiding, markdownTablePreview, matchFilterTypeahead, mergeSeries, mergeSuggestionItems, mergeTagSuggestions, navigationFacet, normalizeOutputFilter, patchBlockQuery, presentBadges, previewDecorations, queryBlockPreview, readSessionRpe, registerCustomCompletionSource, registeredSectionWidgets, removeRuntimePanel, resolveQueryDraft, runtimePanelField, saveBlockQuerySource, sectionAtPos, sectionField, sectionGeometry, sectionIdentity, sectionIdentityHistory, sectionMove, sectionRestore, sectionSaved, sessionQueryInsert, sessionQueryWql, setGutterHighlights, setSuggestionBinding, smartIncrement, summarizeAggregate, summarizeFind, summarizePipeline, tagsFromStaticBlocks, toChartResult, toggleWidgetEdit, tooltipTimestamp, unregisterCustomCompletionSource, urlAtPos, useChartShape, useComposerSlots, useSuggestions, useVisualViewportRect, useWqlStageCounts, widgetBlockPreview, wodAutoWrap, wodAutocompletion, wodEditorKeymap, wodLinter, wodOverlayPanel, workoutLintSource, wqlToPills, wrapInTimeFence };
|
|
12337
|
-
//# sourceMappingURL=chunk-
|
|
12338
|
-
//# sourceMappingURL=chunk-
|
|
12660
|
+
export { AGG_OPTIONS, CANONICAL_BLOCK_TYPES, CLAUSE_META, ComposerRegistry, DEFAULT_DIAGNOSTICS_DEBOUNCE_MS, DEFAULT_OUTPUT_FILTERS, DEFAULT_PRIMARY_FILTER, DefaultFrontmatterWidget, EditorDialog, GROUPBY_OPTIONS, GoalRings, KIND_OPTIONS, METRIC_OPTIONS, MULTI_VALUE_TYPES, MetricBadge, OUTPUT_TYPE_CLASS, OUTPUT_TYPE_DOT, OutputFilterPills, OutputStatementsTable, PLANE_OPTIONS, ProposedMetricBadge, QueryBlockView, QueryValue, ROLLUP_OPTIONS, RowsResultsChrome, RowsTable, SERIES_COLORS, SOURCE_OPTIONS, SUGGESTION_BINDINGS, StackedBar, TARGET_OPTIONS, TIME_OPTIONS, TONE_CLASS, TokenSlotPill, TopList, UNIT_OPTIONS, WHERE_AGGREGATORS, WHERE_METRICS, WidgetChart, WidgetProblemBadge, WqlBars, WqlComposer, WqlDiagnosticsStrip, WqlEmptyState, WqlQueryInspectorModal, WqlTable, WqlTimeseries, ZoneDistribution, activeCursorSection, addRuntimePanel, blockTypesFromBlocks, canonicalSuggestionItems, catalogIdsFromBlocks, cn, compactNumber, composerRegistry, configureOverlayActions, cursorFocusExtension, dateRangeSlot, dispatchAddRuntimePanel, dispatchExpandRuntimePanel, dispatchGutterHighlights, dispatchRemoveRuntimePanel, editQueryClause, editingWidgetsField, editorPreset, editorTheme, embedPreviewDecorations, expandRuntimePanel, extractBlockQueries, extractMetricsByCategory, fenceCompletion, findQueryBlockSection, findWorkoutErrors, forceSectionParse, formatClockTime, formatMMSS, formatTimestamp, frontmatterPreview, frontmatterPreviewField, frontmatterReferenceIndex, frontmatterSuggestions, frontmatterVisibility, getClauseMeta, getCursorFocusState, getOverlayActions, getSuggestionBinding, gutterHighlightsField, gutterUnified, handleFenceAutoWrap, hashCode, inlineButtonDecoration, invalidateSuggestions, lineIdsExtension, linkOpen, linkPreview, loadSuggestions, markdownSyntaxHiding, markdownTablePreview, matchFilterTypeahead, mergeSeries, mergeSuggestionItems, mergeTagSuggestions, navigationFacet, normalizeOutputFilter, patchBlockQuery, presentBadges, previewDecorations, queryBlockPreview, readSessionRpe, referenceIndexReload, registerCustomCompletionSource, registeredSectionWidgets, removeRuntimePanel, resolveQueryDraft, runtimePanelField, saveBlockQuerySource, sectionAtPos, sectionField, sectionGeometry, sectionIdentity, sectionIdentityHistory, sectionMove, sectionRestore, sectionSaved, sessionQueryInsert, sessionQueryWql, setGutterHighlights, setSuggestionBinding, smartIncrement, summarizeAggregate, summarizeFind, summarizePipeline, tagsFromStaticBlocks, toChartResult, toggleWidgetEdit, tooltipTimestamp, unregisterCustomCompletionSource, urlAtPos, useChartShape, useComposerSlots, useSuggestions, useVisualViewportRect, useWqlStageCounts, widgetBlockPreview, wodAutoWrap, wodAutocompletion, wodEditorKeymap, wodLinter, wodOverlayPanel, workoutLintSource, wqlToPills, wrapInTimeFence };
|
|
12661
|
+
//# sourceMappingURL=chunk-SNG34RG2.mjs.map
|
|
12662
|
+
//# sourceMappingURL=chunk-SNG34RG2.mjs.map
|