@jxsuite/studio 0.16.1 → 0.18.0
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/studio.js +2072 -1588
- package/dist/studio.js.map +30 -21
- package/package.json +2 -2
- package/src/browse/browse.js +24 -3
- package/src/canvas/canvas-render.js +2 -2
- package/src/canvas/canvas-utils.js +1 -1
- package/src/editor/shortcuts.js +7 -0
- package/src/files/files.js +17 -2
- package/src/panels/activity-bar.js +12 -0
- package/src/panels/left-panel.js +2 -2
- package/src/panels/overlays.js +2 -2
- package/src/panels/quick-search.js +170 -0
- package/src/panels/style-panel.js +1 -1
- package/src/panels/stylebook-panel.js +30 -529
- package/src/panels/toolbar.js +69 -15
- package/src/platforms/devserver.js +12 -0
- package/src/recent-projects.js +57 -0
- package/src/settings/css-vars-editor.js +307 -0
- package/src/settings/general-settings.js +94 -0
- package/src/settings/head-editor.js +184 -0
- package/src/settings/settings-modal.js +117 -0
- package/src/studio.js +58 -9
- package/src/ui/spectrum.js +2 -0
package/dist/studio.js
CHANGED
|
@@ -47856,7 +47856,7 @@ function applyTransform() {
|
|
|
47856
47856
|
view.panzoomWrap.style.transform = `translate(${view.panX}px, ${view.panY}px) scale(${zoom})`;
|
|
47857
47857
|
renderZoomIndicator();
|
|
47858
47858
|
renderOnly("overlays");
|
|
47859
|
-
if (_ctx4.getCanvasMode() === "
|
|
47859
|
+
if (_ctx4.getCanvasMode() === "stylebook")
|
|
47860
47860
|
_ctx4.renderStylebookOverlays();
|
|
47861
47861
|
}
|
|
47862
47862
|
function fitToScreen() {
|
|
@@ -176998,12 +176998,6 @@ async function codeService(action, payload) {
|
|
|
176998
176998
|
return null;
|
|
176999
176999
|
return platform3.codeService(action, payload);
|
|
177000
177000
|
}
|
|
177001
|
-
async function locateDocument(name) {
|
|
177002
|
-
const platform3 = getPlatform();
|
|
177003
|
-
if (!platform3.locateFile)
|
|
177004
|
-
return null;
|
|
177005
|
-
return platform3.locateFile(name);
|
|
177006
|
-
}
|
|
177007
177001
|
var pluginSchemaCache = new Map;
|
|
177008
177002
|
async function fetchPluginSchema(def3, state) {
|
|
177009
177003
|
if (!def3.$src || !def3.$prototype)
|
|
@@ -177062,58 +177056,6 @@ function getFunctionArgs(editing, document4) {
|
|
|
177062
177056
|
// src/files/file-ops.js
|
|
177063
177057
|
init_platform();
|
|
177064
177058
|
init_workspace();
|
|
177065
|
-
async function openFile() {
|
|
177066
|
-
try {
|
|
177067
|
-
if ("showOpenFilePicker" in window) {
|
|
177068
|
-
const [handle2] = await window.showOpenFilePicker({
|
|
177069
|
-
types: [
|
|
177070
|
-
{ description: "Jx Component", accept: { "application/json": [".json"] } },
|
|
177071
|
-
{ description: "Markdown Content", accept: { "text/markdown": [".md"] } }
|
|
177072
|
-
]
|
|
177073
|
-
});
|
|
177074
|
-
const file = await handle2.getFile();
|
|
177075
|
-
const text6 = await file.text();
|
|
177076
|
-
const documentPath = await locateDocument(handle2.name);
|
|
177077
|
-
if (handle2.name.endsWith(".md")) {
|
|
177078
|
-
const { document: document4, frontmatter: frontmatter2 } = await loadMarkdown(text6);
|
|
177079
|
-
openTab({
|
|
177080
|
-
id: handle2.name,
|
|
177081
|
-
documentPath,
|
|
177082
|
-
fileHandle: handle2,
|
|
177083
|
-
document: document4,
|
|
177084
|
-
frontmatter: frontmatter2,
|
|
177085
|
-
sourceFormat: "md"
|
|
177086
|
-
});
|
|
177087
|
-
} else {
|
|
177088
|
-
const document4 = JSON.parse(text6);
|
|
177089
|
-
openTab({ id: handle2.name, documentPath, fileHandle: handle2, document: document4 });
|
|
177090
|
-
}
|
|
177091
|
-
statusMessage(`Opened ${handle2.name}`);
|
|
177092
|
-
} else {
|
|
177093
|
-
const input = document.createElement("input");
|
|
177094
|
-
input.type = "file";
|
|
177095
|
-
input.accept = ".json,.md";
|
|
177096
|
-
input.onchange = async () => {
|
|
177097
|
-
const file = input.files?.[0];
|
|
177098
|
-
if (!file)
|
|
177099
|
-
return;
|
|
177100
|
-
const text6 = await file.text();
|
|
177101
|
-
if (file.name.endsWith(".md")) {
|
|
177102
|
-
const { document: document4, frontmatter: frontmatter2 } = await loadMarkdown(text6);
|
|
177103
|
-
openTab({ id: file.name, document: document4, frontmatter: frontmatter2, sourceFormat: "md" });
|
|
177104
|
-
} else {
|
|
177105
|
-
const document4 = JSON.parse(text6);
|
|
177106
|
-
openTab({ id: file.name, document: document4 });
|
|
177107
|
-
}
|
|
177108
|
-
statusMessage(`Opened ${file.name}`);
|
|
177109
|
-
};
|
|
177110
|
-
input.click();
|
|
177111
|
-
}
|
|
177112
|
-
} catch (e) {
|
|
177113
|
-
if (e.name !== "AbortError")
|
|
177114
|
-
statusMessage(`Error: ${e.message}`);
|
|
177115
|
-
}
|
|
177116
|
-
}
|
|
177117
177059
|
async function loadMarkdown(source) {
|
|
177118
177060
|
const { transpileJxMarkdown: transpileJxMarkdown2 } = await Promise.resolve().then(() => (init_transpile(), exports_transpile));
|
|
177119
177061
|
const doc = transpileJxMarkdown2(source);
|
|
@@ -180158,1071 +180100,6 @@ init_components();
|
|
|
180158
180100
|
init_store();
|
|
180159
180101
|
init_workspace();
|
|
180160
180102
|
init_components();
|
|
180161
|
-
|
|
180162
|
-
// src/utils/studio-utils.js
|
|
180163
|
-
function camelToKebab2(str) {
|
|
180164
|
-
return str.replace(/[A-Z]/g, (c) => "-" + c.toLowerCase());
|
|
180165
|
-
}
|
|
180166
|
-
function camelToLabel(prop) {
|
|
180167
|
-
return prop.replace(/([A-Z])/g, " $1").replace(/^./, (c) => c.toUpperCase());
|
|
180168
|
-
}
|
|
180169
|
-
function kebabToLabel(val) {
|
|
180170
|
-
return val.replace(/(^|-)(\w)/g, (_, sep2, c) => (sep2 ? " " : "") + c.toUpperCase());
|
|
180171
|
-
}
|
|
180172
|
-
function propLabel(entry, prop) {
|
|
180173
|
-
return entry?.$label || camelToLabel(prop);
|
|
180174
|
-
}
|
|
180175
|
-
function attrLabel(entry, attr) {
|
|
180176
|
-
if (entry?.$label)
|
|
180177
|
-
return entry.$label;
|
|
180178
|
-
if (attr.includes("-"))
|
|
180179
|
-
return attr.replace(/(^|-)(\w)/g, (_, sep2, c) => (sep2 ? " " : "") + c.toUpperCase());
|
|
180180
|
-
return camelToLabel(attr);
|
|
180181
|
-
}
|
|
180182
|
-
function abbreviateValue(val) {
|
|
180183
|
-
const map6 = {
|
|
180184
|
-
inline: "inl",
|
|
180185
|
-
"inline-block": "i-blk",
|
|
180186
|
-
"inline-flex": "i-flx",
|
|
180187
|
-
"inline-grid": "i-grd",
|
|
180188
|
-
contents: "cnt",
|
|
180189
|
-
"flow-root": "flow",
|
|
180190
|
-
nowrap: "no-wr",
|
|
180191
|
-
"wrap-reverse": "wr-rev",
|
|
180192
|
-
"flex-start": "start",
|
|
180193
|
-
"flex-end": "end",
|
|
180194
|
-
"space-between": "betw",
|
|
180195
|
-
"space-around": "arnd",
|
|
180196
|
-
"space-evenly": "even",
|
|
180197
|
-
stretch: "str",
|
|
180198
|
-
baseline: "base",
|
|
180199
|
-
normal: "norm",
|
|
180200
|
-
"row-reverse": "row-r",
|
|
180201
|
-
"column-reverse": "col-r",
|
|
180202
|
-
column: "col"
|
|
180203
|
-
};
|
|
180204
|
-
return map6[val] || val;
|
|
180205
|
-
}
|
|
180206
|
-
function inferInputType(entry) {
|
|
180207
|
-
if (entry.$shorthand === true)
|
|
180208
|
-
return "shorthand";
|
|
180209
|
-
if (entry.$input === "button-group")
|
|
180210
|
-
return "button-group";
|
|
180211
|
-
if (entry.$input === "media")
|
|
180212
|
-
return "media";
|
|
180213
|
-
if (entry.format === "color")
|
|
180214
|
-
return "color";
|
|
180215
|
-
if (entry.format === "uri-reference")
|
|
180216
|
-
return "media";
|
|
180217
|
-
if (entry.$units !== undefined)
|
|
180218
|
-
return "number-unit";
|
|
180219
|
-
if (entry.type === "number")
|
|
180220
|
-
return "number";
|
|
180221
|
-
if (Array.isArray(entry.enum))
|
|
180222
|
-
return "select";
|
|
180223
|
-
if (Array.isArray(entry.examples) || Array.isArray(entry.presets))
|
|
180224
|
-
return "combobox";
|
|
180225
|
-
return "text";
|
|
180226
|
-
}
|
|
180227
|
-
function findContentTypeSchema(documentPath, projectConfig) {
|
|
180228
|
-
if (!documentPath || !projectConfig?.contentTypes)
|
|
180229
|
-
return null;
|
|
180230
|
-
for (const [name, def3] of Object.entries(projectConfig.contentTypes)) {
|
|
180231
|
-
if (!def3.source || !def3.schema)
|
|
180232
|
-
continue;
|
|
180233
|
-
const src = def3.source.replace(/^\.\//, "");
|
|
180234
|
-
const dir = src.split("/")[0];
|
|
180235
|
-
const ext = src.includes("*.md") ? ".md" : src.includes("*.json") ? ".json" : src.includes("*.csv") ? ".csv" : null;
|
|
180236
|
-
if (documentPath.startsWith(dir + "/") && (!ext || documentPath.endsWith(ext))) {
|
|
180237
|
-
return { name, schema: def3.schema };
|
|
180238
|
-
}
|
|
180239
|
-
}
|
|
180240
|
-
return null;
|
|
180241
|
-
}
|
|
180242
|
-
function friendlyNameToVar(name, prefix) {
|
|
180243
|
-
const slug = name.trim().toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
180244
|
-
if (!slug)
|
|
180245
|
-
return "";
|
|
180246
|
-
return `${prefix}${slug}`;
|
|
180247
|
-
}
|
|
180248
|
-
function varDisplayName(varName, prefix) {
|
|
180249
|
-
return varName.replace(new RegExp(`^${prefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`), "").replace(/^--/, "").replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()) || varName;
|
|
180250
|
-
}
|
|
180251
|
-
function parseCemType(typeText) {
|
|
180252
|
-
if (!typeText)
|
|
180253
|
-
return { kind: "text" };
|
|
180254
|
-
const t = typeText.trim().replace(/\s*\|\s*undefined\b/g, "").trim();
|
|
180255
|
-
if (t === "boolean")
|
|
180256
|
-
return { kind: "boolean" };
|
|
180257
|
-
if (t === "number")
|
|
180258
|
-
return { kind: "number" };
|
|
180259
|
-
const enumMatch = t.match(/^'[^']*'(\s*\|\s*'[^']*')+$/);
|
|
180260
|
-
if (enumMatch) {
|
|
180261
|
-
const options = [...t.matchAll(/'([^']*)'/g)].map((m) => m[1]);
|
|
180262
|
-
return { kind: "combobox", options };
|
|
180263
|
-
}
|
|
180264
|
-
return { kind: "text" };
|
|
180265
|
-
}
|
|
180266
|
-
|
|
180267
|
-
// src/settings/defs-editor.js
|
|
180268
|
-
init_platform();
|
|
180269
|
-
init_store();
|
|
180270
|
-
|
|
180271
|
-
// src/settings/schema-field-ui.js
|
|
180272
|
-
var FIELD_TYPES = ["string", "number", "boolean", "array", "object", "reference"];
|
|
180273
|
-
var FORMAT_OPTIONS = ["", "image", "date", "color"];
|
|
180274
|
-
function detectFieldType(schema4) {
|
|
180275
|
-
if (schema4.$ref)
|
|
180276
|
-
return "reference";
|
|
180277
|
-
return schema4.type || "string";
|
|
180278
|
-
}
|
|
180279
|
-
function detectFieldFormat(schema4) {
|
|
180280
|
-
if (schema4.type === "array" && schema4.items?.format)
|
|
180281
|
-
return schema4.items.format;
|
|
180282
|
-
return schema4.format || "";
|
|
180283
|
-
}
|
|
180284
|
-
function fieldCardTpl(fieldName, fieldSchema, isRequired, handlers, contentTypeNames = []) {
|
|
180285
|
-
const type = detectFieldType(fieldSchema);
|
|
180286
|
-
const format2 = detectFieldFormat(fieldSchema);
|
|
180287
|
-
const isNested = type === "object";
|
|
180288
|
-
const isRef2 = type === "reference";
|
|
180289
|
-
const nestedProps = fieldSchema.properties || {};
|
|
180290
|
-
const nestedRequired = fieldSchema.required || [];
|
|
180291
|
-
const refTarget = fieldSchema.$ref ? fieldSchema.$ref.replace("#/contentTypes/", "") : "";
|
|
180292
|
-
return html`
|
|
180293
|
-
<div class="schema-field-card">
|
|
180294
|
-
<div class="schema-field-row">
|
|
180295
|
-
<sp-textfield
|
|
180296
|
-
size="s"
|
|
180297
|
-
quiet
|
|
180298
|
-
value=${fieldName}
|
|
180299
|
-
class="schema-field-name-input"
|
|
180300
|
-
@change=${(e) => {
|
|
180301
|
-
const newName = e.target.value.trim();
|
|
180302
|
-
if (newName && newName !== fieldName)
|
|
180303
|
-
handlers.onRename(fieldName, newName);
|
|
180304
|
-
else
|
|
180305
|
-
e.target.value = fieldName;
|
|
180306
|
-
}}
|
|
180307
|
-
@keydown=${(e) => {
|
|
180308
|
-
if (e.key === "Enter")
|
|
180309
|
-
e.target.blur();
|
|
180310
|
-
if (e.key === "Escape") {
|
|
180311
|
-
e.target.value = fieldName;
|
|
180312
|
-
e.target.blur();
|
|
180313
|
-
}
|
|
180314
|
-
}}
|
|
180315
|
-
></sp-textfield>
|
|
180316
|
-
${typePickerTpl(type, (newType) => handlers.onChangeType(fieldName, newType))}
|
|
180317
|
-
${type === "string" || type === "array" ? formatPickerTpl(format2, (f) => {
|
|
180318
|
-
if (handlers.onChangeFormat)
|
|
180319
|
-
handlers.onChangeFormat(fieldName, f);
|
|
180320
|
-
}) : nothing}
|
|
180321
|
-
<sp-switch
|
|
180322
|
-
size="s"
|
|
180323
|
-
?checked=${isRequired}
|
|
180324
|
-
@change=${() => handlers.onToggleRequired(fieldName)}
|
|
180325
|
-
>
|
|
180326
|
-
Req
|
|
180327
|
-
</sp-switch>
|
|
180328
|
-
<sp-action-button
|
|
180329
|
-
size="xs"
|
|
180330
|
-
quiet
|
|
180331
|
-
title="Delete field"
|
|
180332
|
-
@click=${() => handlers.onDelete(fieldName)}
|
|
180333
|
-
>
|
|
180334
|
-
<sp-icon-delete slot="icon"></sp-icon-delete>
|
|
180335
|
-
</sp-action-button>
|
|
180336
|
-
</div>
|
|
180337
|
-
${isRef2 && contentTypeNames.length ? html`
|
|
180338
|
-
<div class="schema-field-ref-target">
|
|
180339
|
-
<sp-picker
|
|
180340
|
-
size="s"
|
|
180341
|
-
label="Target"
|
|
180342
|
-
value=${refTarget}
|
|
180343
|
-
@change=${(e) => {
|
|
180344
|
-
if (handlers.onChangeRefTarget)
|
|
180345
|
-
handlers.onChangeRefTarget(fieldName, e.target.value);
|
|
180346
|
-
}}
|
|
180347
|
-
>
|
|
180348
|
-
${contentTypeNames.map((n2) => html`<sp-menu-item value=${n2}>${n2}</sp-menu-item>`)}
|
|
180349
|
-
</sp-picker>
|
|
180350
|
-
</div>
|
|
180351
|
-
` : nothing}
|
|
180352
|
-
${isNested ? html`
|
|
180353
|
-
<div class="schema-field-nested">
|
|
180354
|
-
${Object.entries(nestedProps).map(([name, sub]) => nestedFieldCardTpl(fieldName, name, sub, nestedRequired.includes(name), handlers))}
|
|
180355
|
-
${nestedAddFieldTpl(fieldName, handlers)}
|
|
180356
|
-
</div>
|
|
180357
|
-
` : nothing}
|
|
180358
|
-
</div>
|
|
180359
|
-
`;
|
|
180360
|
-
}
|
|
180361
|
-
function nestedFieldCardTpl(parentName, childName, childSchema, isRequired, handlers) {
|
|
180362
|
-
const type = detectFieldType(childSchema);
|
|
180363
|
-
const format2 = detectFieldFormat(childSchema);
|
|
180364
|
-
return html`
|
|
180365
|
-
<div class="schema-field-card schema-field-card--nested">
|
|
180366
|
-
<div class="schema-field-row">
|
|
180367
|
-
<sp-textfield
|
|
180368
|
-
size="s"
|
|
180369
|
-
quiet
|
|
180370
|
-
value=${childName}
|
|
180371
|
-
class="schema-field-name-input"
|
|
180372
|
-
@change=${(e) => {
|
|
180373
|
-
const newName = e.target.value.trim();
|
|
180374
|
-
if (newName && newName !== childName && handlers.onRenameNested) {
|
|
180375
|
-
handlers.onRenameNested(parentName, childName, newName);
|
|
180376
|
-
} else {
|
|
180377
|
-
e.target.value = childName;
|
|
180378
|
-
}
|
|
180379
|
-
}}
|
|
180380
|
-
@keydown=${(e) => {
|
|
180381
|
-
if (e.key === "Enter")
|
|
180382
|
-
e.target.blur();
|
|
180383
|
-
if (e.key === "Escape") {
|
|
180384
|
-
e.target.value = childName;
|
|
180385
|
-
e.target.blur();
|
|
180386
|
-
}
|
|
180387
|
-
}}
|
|
180388
|
-
></sp-textfield>
|
|
180389
|
-
${typePickerTpl(type, (newType) => {
|
|
180390
|
-
if (handlers.onChangeNestedType)
|
|
180391
|
-
handlers.onChangeNestedType(parentName, childName, newType);
|
|
180392
|
-
})}
|
|
180393
|
-
${type === "string" || type === "array" ? formatPickerTpl(format2, (f) => {
|
|
180394
|
-
if (handlers.onChangeNestedFormat)
|
|
180395
|
-
handlers.onChangeNestedFormat(parentName, childName, f);
|
|
180396
|
-
}) : nothing}
|
|
180397
|
-
<sp-switch
|
|
180398
|
-
size="s"
|
|
180399
|
-
?checked=${isRequired}
|
|
180400
|
-
@change=${() => {
|
|
180401
|
-
if (handlers.onToggleNestedRequired)
|
|
180402
|
-
handlers.onToggleNestedRequired(parentName, childName);
|
|
180403
|
-
}}
|
|
180404
|
-
>
|
|
180405
|
-
Req
|
|
180406
|
-
</sp-switch>
|
|
180407
|
-
<sp-action-button
|
|
180408
|
-
size="xs"
|
|
180409
|
-
quiet
|
|
180410
|
-
title="Delete field"
|
|
180411
|
-
@click=${() => {
|
|
180412
|
-
if (handlers.onDeleteNested)
|
|
180413
|
-
handlers.onDeleteNested(parentName, childName);
|
|
180414
|
-
}}
|
|
180415
|
-
>
|
|
180416
|
-
<sp-icon-delete slot="icon"></sp-icon-delete>
|
|
180417
|
-
</sp-action-button>
|
|
180418
|
-
</div>
|
|
180419
|
-
</div>
|
|
180420
|
-
`;
|
|
180421
|
-
}
|
|
180422
|
-
function nestedAddFieldTpl(parentName, handlers) {
|
|
180423
|
-
return html`
|
|
180424
|
-
<div class="schema-nested-add">
|
|
180425
|
-
<sp-textfield
|
|
180426
|
-
size="s"
|
|
180427
|
-
placeholder="field name"
|
|
180428
|
-
class="schema-nested-add-name"
|
|
180429
|
-
@keydown=${(e) => {
|
|
180430
|
-
if (e.key === "Enter") {
|
|
180431
|
-
const row = e.target.closest(".schema-nested-add");
|
|
180432
|
-
const name = e.target.value.trim();
|
|
180433
|
-
const typePicker = row?.querySelector("sp-picker");
|
|
180434
|
-
const type = typePicker?.value || "string";
|
|
180435
|
-
if (name && handlers.onAddNestedField) {
|
|
180436
|
-
handlers.onAddNestedField(parentName, { name, type, required: false });
|
|
180437
|
-
e.target.value = "";
|
|
180438
|
-
}
|
|
180439
|
-
}
|
|
180440
|
-
}}
|
|
180441
|
-
></sp-textfield>
|
|
180442
|
-
${typePickerTpl("string", () => {})}
|
|
180443
|
-
<sp-action-button
|
|
180444
|
-
size="xs"
|
|
180445
|
-
quiet
|
|
180446
|
-
title="Add nested field"
|
|
180447
|
-
@click=${(e) => {
|
|
180448
|
-
const row = e.target.closest(".schema-nested-add");
|
|
180449
|
-
const nameInput = row?.querySelector(".schema-nested-add-name");
|
|
180450
|
-
const typePicker = row?.querySelector("sp-picker");
|
|
180451
|
-
const name = nameInput?.value?.trim();
|
|
180452
|
-
const type = typePicker?.value || "string";
|
|
180453
|
-
if (name && handlers.onAddNestedField) {
|
|
180454
|
-
handlers.onAddNestedField(parentName, { name, type, required: false });
|
|
180455
|
-
nameInput.value = "";
|
|
180456
|
-
}
|
|
180457
|
-
}}
|
|
180458
|
-
>
|
|
180459
|
-
<sp-icon-add slot="icon"></sp-icon-add>
|
|
180460
|
-
</sp-action-button>
|
|
180461
|
-
</div>
|
|
180462
|
-
`;
|
|
180463
|
-
}
|
|
180464
|
-
function typePickerTpl(value2, onChange) {
|
|
180465
|
-
return html`
|
|
180466
|
-
<sp-picker
|
|
180467
|
-
size="s"
|
|
180468
|
-
label="Type"
|
|
180469
|
-
value=${value2}
|
|
180470
|
-
@change=${(e) => onChange(e.target.value)}
|
|
180471
|
-
>
|
|
180472
|
-
${FIELD_TYPES.map((t) => html`<sp-menu-item value=${t}>${t}</sp-menu-item>`)}
|
|
180473
|
-
</sp-picker>
|
|
180474
|
-
`;
|
|
180475
|
-
}
|
|
180476
|
-
function formatPickerTpl(value2, onChange) {
|
|
180477
|
-
return html`
|
|
180478
|
-
<sp-picker
|
|
180479
|
-
size="s"
|
|
180480
|
-
label="Format"
|
|
180481
|
-
value=${value2}
|
|
180482
|
-
@change=${(e) => onChange(e.target.value)}
|
|
180483
|
-
>
|
|
180484
|
-
${FORMAT_OPTIONS.map((f) => html`<sp-menu-item value=${f}>${f || "(none)"}</sp-menu-item>`)}
|
|
180485
|
-
</sp-picker>
|
|
180486
|
-
`;
|
|
180487
|
-
}
|
|
180488
|
-
function addFieldFormTpl(state, handlers) {
|
|
180489
|
-
return html`
|
|
180490
|
-
<div class="schema-add-field">
|
|
180491
|
-
<sp-textfield
|
|
180492
|
-
size="s"
|
|
180493
|
-
placeholder="Field name"
|
|
180494
|
-
.value=${state.name}
|
|
180495
|
-
@input=${(e) => handlers.onInput("name", e.target.value)}
|
|
180496
|
-
@keydown=${(e) => {
|
|
180497
|
-
if (e.key === "Enter")
|
|
180498
|
-
handlers.onConfirm();
|
|
180499
|
-
if (e.key === "Escape")
|
|
180500
|
-
handlers.onCancel();
|
|
180501
|
-
}}
|
|
180502
|
-
></sp-textfield>
|
|
180503
|
-
${typePickerTpl(state.type, (t) => handlers.onInput("type", t))}
|
|
180504
|
-
${state.type === "string" || state.type === "array" ? formatPickerTpl(state.format || "", (f) => handlers.onInput("format", f)) : nothing}
|
|
180505
|
-
<sp-switch
|
|
180506
|
-
size="s"
|
|
180507
|
-
?checked=${state.required}
|
|
180508
|
-
@change=${(e) => handlers.onInput("required", e.target.checked)}
|
|
180509
|
-
>
|
|
180510
|
-
Required
|
|
180511
|
-
</sp-switch>
|
|
180512
|
-
<sp-action-button size="s" @click=${handlers.onConfirm}>Add</sp-action-button>
|
|
180513
|
-
<sp-action-button size="s" quiet @click=${handlers.onCancel}>Cancel</sp-action-button>
|
|
180514
|
-
</div>
|
|
180515
|
-
`;
|
|
180516
|
-
}
|
|
180517
|
-
function schemaForType(type, format2) {
|
|
180518
|
-
switch (type) {
|
|
180519
|
-
case "number":
|
|
180520
|
-
return { type: "number" };
|
|
180521
|
-
case "boolean":
|
|
180522
|
-
return { type: "boolean" };
|
|
180523
|
-
case "array":
|
|
180524
|
-
return format2 ? { type: "array", items: { type: "string", format: format2 } } : { type: "array", items: { type: "string" } };
|
|
180525
|
-
case "object":
|
|
180526
|
-
return { type: "object", properties: {}, required: [] };
|
|
180527
|
-
case "reference":
|
|
180528
|
-
return { $ref: "#/contentTypes/" };
|
|
180529
|
-
default:
|
|
180530
|
-
return format2 ? { type: "string", format: format2 } : { type: "string" };
|
|
180531
|
-
}
|
|
180532
|
-
}
|
|
180533
|
-
function yamlDefault(type, format2) {
|
|
180534
|
-
if (format2 === "date")
|
|
180535
|
-
return new Date().toISOString().split("T")[0];
|
|
180536
|
-
if (format2 === "image")
|
|
180537
|
-
return '""';
|
|
180538
|
-
switch (type) {
|
|
180539
|
-
case "boolean":
|
|
180540
|
-
return "false";
|
|
180541
|
-
case "number":
|
|
180542
|
-
return "0";
|
|
180543
|
-
case "array":
|
|
180544
|
-
return "[]";
|
|
180545
|
-
case "object":
|
|
180546
|
-
return "{}";
|
|
180547
|
-
default:
|
|
180548
|
-
return '""';
|
|
180549
|
-
}
|
|
180550
|
-
}
|
|
180551
|
-
|
|
180552
|
-
// src/settings/defs-editor.js
|
|
180553
|
-
var selectedDef = null;
|
|
180554
|
-
var showAddField = false;
|
|
180555
|
-
var newFieldState = { name: "", type: "string", format: "", required: false };
|
|
180556
|
-
var showNewDef = false;
|
|
180557
|
-
var newDefName = "";
|
|
180558
|
-
async function saveProjectConfig() {
|
|
180559
|
-
const platform3 = getPlatform();
|
|
180560
|
-
const config = projectState.projectConfig;
|
|
180561
|
-
await platform3.writeFile("project.json", JSON.stringify(config, null, "\t"));
|
|
180562
|
-
}
|
|
180563
|
-
function getSelectedDef() {
|
|
180564
|
-
const config = projectState?.projectConfig;
|
|
180565
|
-
return config?.$defs?.[selectedDef];
|
|
180566
|
-
}
|
|
180567
|
-
function handleNewDef(rerender) {
|
|
180568
|
-
const name = newDefName.trim();
|
|
180569
|
-
if (!name)
|
|
180570
|
-
return;
|
|
180571
|
-
const config = projectState?.projectConfig;
|
|
180572
|
-
if (!config)
|
|
180573
|
-
return;
|
|
180574
|
-
if (!config.$defs)
|
|
180575
|
-
config.$defs = {};
|
|
180576
|
-
if (config.$defs[name])
|
|
180577
|
-
return;
|
|
180578
|
-
config.$defs[name] = {
|
|
180579
|
-
type: "object",
|
|
180580
|
-
properties: {},
|
|
180581
|
-
required: []
|
|
180582
|
-
};
|
|
180583
|
-
selectedDef = name;
|
|
180584
|
-
showNewDef = false;
|
|
180585
|
-
newDefName = "";
|
|
180586
|
-
rerender();
|
|
180587
|
-
saveProjectConfig();
|
|
180588
|
-
}
|
|
180589
|
-
function handleAddField(rerender) {
|
|
180590
|
-
const name = newFieldState.name.trim();
|
|
180591
|
-
if (!name || !selectedDef)
|
|
180592
|
-
return;
|
|
180593
|
-
const def3 = getSelectedDef();
|
|
180594
|
-
if (!def3)
|
|
180595
|
-
return;
|
|
180596
|
-
if (!def3.properties)
|
|
180597
|
-
def3.properties = {};
|
|
180598
|
-
def3.properties[name] = schemaForType(newFieldState.type, newFieldState.format || undefined);
|
|
180599
|
-
if (newFieldState.required) {
|
|
180600
|
-
if (!def3.required)
|
|
180601
|
-
def3.required = [];
|
|
180602
|
-
if (!def3.required.includes(name))
|
|
180603
|
-
def3.required.push(name);
|
|
180604
|
-
}
|
|
180605
|
-
showAddField = false;
|
|
180606
|
-
newFieldState = { name: "", type: "string", format: "", required: false };
|
|
180607
|
-
rerender();
|
|
180608
|
-
saveProjectConfig();
|
|
180609
|
-
}
|
|
180610
|
-
function handleDeleteField(fieldName, rerender) {
|
|
180611
|
-
const def3 = getSelectedDef();
|
|
180612
|
-
if (!def3?.properties)
|
|
180613
|
-
return;
|
|
180614
|
-
delete def3.properties[fieldName];
|
|
180615
|
-
if (def3.required) {
|
|
180616
|
-
def3.required = def3.required.filter((r) => r !== fieldName);
|
|
180617
|
-
}
|
|
180618
|
-
rerender();
|
|
180619
|
-
saveProjectConfig();
|
|
180620
|
-
}
|
|
180621
|
-
function handleToggleRequired(fieldName, rerender) {
|
|
180622
|
-
const def3 = getSelectedDef();
|
|
180623
|
-
if (!def3)
|
|
180624
|
-
return;
|
|
180625
|
-
if (!def3.required)
|
|
180626
|
-
def3.required = [];
|
|
180627
|
-
const idx = def3.required.indexOf(fieldName);
|
|
180628
|
-
if (idx >= 0)
|
|
180629
|
-
def3.required.splice(idx, 1);
|
|
180630
|
-
else
|
|
180631
|
-
def3.required.push(fieldName);
|
|
180632
|
-
rerender();
|
|
180633
|
-
saveProjectConfig();
|
|
180634
|
-
}
|
|
180635
|
-
function handleRenameField(oldName, newName, rerender) {
|
|
180636
|
-
const def3 = getSelectedDef();
|
|
180637
|
-
if (!def3?.properties || !newName || def3.properties[newName])
|
|
180638
|
-
return;
|
|
180639
|
-
const newProps = {};
|
|
180640
|
-
for (const [key, val] of Object.entries(def3.properties)) {
|
|
180641
|
-
newProps[key === oldName ? newName : key] = val;
|
|
180642
|
-
}
|
|
180643
|
-
def3.properties = newProps;
|
|
180644
|
-
if (def3.required) {
|
|
180645
|
-
def3.required = def3.required.map((r) => r === oldName ? newName : r);
|
|
180646
|
-
}
|
|
180647
|
-
rerender();
|
|
180648
|
-
saveProjectConfig();
|
|
180649
|
-
}
|
|
180650
|
-
function handleChangeType(fieldName, newType, rerender) {
|
|
180651
|
-
const def3 = getSelectedDef();
|
|
180652
|
-
if (!def3?.properties?.[fieldName])
|
|
180653
|
-
return;
|
|
180654
|
-
const oldFormat = newType === "string" || newType === "array" ? detectFieldFormat(def3.properties[fieldName]) : undefined;
|
|
180655
|
-
def3.properties[fieldName] = schemaForType(newType, oldFormat || undefined);
|
|
180656
|
-
rerender();
|
|
180657
|
-
saveProjectConfig();
|
|
180658
|
-
}
|
|
180659
|
-
function handleChangeFormat(fieldName, format2, rerender) {
|
|
180660
|
-
const def3 = getSelectedDef();
|
|
180661
|
-
if (!def3?.properties?.[fieldName])
|
|
180662
|
-
return;
|
|
180663
|
-
const prop = def3.properties[fieldName];
|
|
180664
|
-
const type = prop.type || "string";
|
|
180665
|
-
def3.properties[fieldName] = schemaForType(type, format2 || undefined);
|
|
180666
|
-
rerender();
|
|
180667
|
-
saveProjectConfig();
|
|
180668
|
-
}
|
|
180669
|
-
function handleAddNestedField(parentName, fieldState, rerender) {
|
|
180670
|
-
const def3 = getSelectedDef();
|
|
180671
|
-
const parent = def3?.properties?.[parentName];
|
|
180672
|
-
if (!parent)
|
|
180673
|
-
return;
|
|
180674
|
-
if (!parent.properties)
|
|
180675
|
-
parent.properties = {};
|
|
180676
|
-
parent.properties[fieldState.name] = schemaForType(fieldState.type);
|
|
180677
|
-
if (fieldState.required) {
|
|
180678
|
-
if (!parent.required)
|
|
180679
|
-
parent.required = [];
|
|
180680
|
-
if (!parent.required.includes(fieldState.name))
|
|
180681
|
-
parent.required.push(fieldState.name);
|
|
180682
|
-
}
|
|
180683
|
-
rerender();
|
|
180684
|
-
saveProjectConfig();
|
|
180685
|
-
}
|
|
180686
|
-
function handleDeleteNested(parentName, childName, rerender) {
|
|
180687
|
-
const def3 = getSelectedDef();
|
|
180688
|
-
const parent = def3?.properties?.[parentName];
|
|
180689
|
-
if (!parent?.properties)
|
|
180690
|
-
return;
|
|
180691
|
-
delete parent.properties[childName];
|
|
180692
|
-
if (parent.required) {
|
|
180693
|
-
parent.required = parent.required.filter((r) => r !== childName);
|
|
180694
|
-
}
|
|
180695
|
-
rerender();
|
|
180696
|
-
saveProjectConfig();
|
|
180697
|
-
}
|
|
180698
|
-
function handleToggleNestedRequired(parentName, childName, rerender) {
|
|
180699
|
-
const def3 = getSelectedDef();
|
|
180700
|
-
const parent = def3?.properties?.[parentName];
|
|
180701
|
-
if (!parent)
|
|
180702
|
-
return;
|
|
180703
|
-
if (!parent.required)
|
|
180704
|
-
parent.required = [];
|
|
180705
|
-
const idx = parent.required.indexOf(childName);
|
|
180706
|
-
if (idx >= 0)
|
|
180707
|
-
parent.required.splice(idx, 1);
|
|
180708
|
-
else
|
|
180709
|
-
parent.required.push(childName);
|
|
180710
|
-
rerender();
|
|
180711
|
-
saveProjectConfig();
|
|
180712
|
-
}
|
|
180713
|
-
function handleRenameNested(parentName, oldChild, newChild, rerender) {
|
|
180714
|
-
const def3 = getSelectedDef();
|
|
180715
|
-
const parent = def3?.properties?.[parentName];
|
|
180716
|
-
if (!parent?.properties || !newChild || parent.properties[newChild])
|
|
180717
|
-
return;
|
|
180718
|
-
const newProps = {};
|
|
180719
|
-
for (const [key, val] of Object.entries(parent.properties)) {
|
|
180720
|
-
newProps[key === oldChild ? newChild : key] = val;
|
|
180721
|
-
}
|
|
180722
|
-
parent.properties = newProps;
|
|
180723
|
-
if (parent.required) {
|
|
180724
|
-
parent.required = parent.required.map((r) => r === oldChild ? newChild : r);
|
|
180725
|
-
}
|
|
180726
|
-
rerender();
|
|
180727
|
-
saveProjectConfig();
|
|
180728
|
-
}
|
|
180729
|
-
function handleChangeNestedType(parentName, childName, newType, rerender) {
|
|
180730
|
-
const def3 = getSelectedDef();
|
|
180731
|
-
const parent = def3?.properties?.[parentName];
|
|
180732
|
-
if (!parent?.properties?.[childName])
|
|
180733
|
-
return;
|
|
180734
|
-
const oldFormat = newType === "string" || newType === "array" ? detectFieldFormat(parent.properties[childName]) : undefined;
|
|
180735
|
-
parent.properties[childName] = schemaForType(newType, oldFormat || undefined);
|
|
180736
|
-
rerender();
|
|
180737
|
-
saveProjectConfig();
|
|
180738
|
-
}
|
|
180739
|
-
function handleChangeNestedFormat(parentName, childName, format2, rerender) {
|
|
180740
|
-
const def3 = getSelectedDef();
|
|
180741
|
-
const parent = def3?.properties?.[parentName];
|
|
180742
|
-
if (!parent?.properties?.[childName])
|
|
180743
|
-
return;
|
|
180744
|
-
const prop = parent.properties[childName];
|
|
180745
|
-
const type = prop.type || "string";
|
|
180746
|
-
parent.properties[childName] = schemaForType(type, format2 || undefined);
|
|
180747
|
-
rerender();
|
|
180748
|
-
saveProjectConfig();
|
|
180749
|
-
}
|
|
180750
|
-
function handleDeleteDef(rerender) {
|
|
180751
|
-
if (!selectedDef)
|
|
180752
|
-
return;
|
|
180753
|
-
const config = projectState?.projectConfig;
|
|
180754
|
-
if (!config?.$defs?.[selectedDef])
|
|
180755
|
-
return;
|
|
180756
|
-
delete config.$defs[selectedDef];
|
|
180757
|
-
selectedDef = null;
|
|
180758
|
-
rerender();
|
|
180759
|
-
saveProjectConfig();
|
|
180760
|
-
}
|
|
180761
|
-
function renderDefsEditor(container) {
|
|
180762
|
-
const rerender = () => renderDefsEditor(container);
|
|
180763
|
-
const config = projectState?.projectConfig;
|
|
180764
|
-
const defs = config?.$defs || {};
|
|
180765
|
-
const defNames = Object.keys(defs);
|
|
180766
|
-
const listTpl = html`
|
|
180767
|
-
<div class="settings-list-panel">
|
|
180768
|
-
${defNames.map((name) => html`
|
|
180769
|
-
<sp-action-button
|
|
180770
|
-
size="s"
|
|
180771
|
-
?selected=${selectedDef === name}
|
|
180772
|
-
@click=${() => {
|
|
180773
|
-
selectedDef = name;
|
|
180774
|
-
showAddField = false;
|
|
180775
|
-
rerender();
|
|
180776
|
-
}}
|
|
180777
|
-
>
|
|
180778
|
-
${name}
|
|
180779
|
-
</sp-action-button>
|
|
180780
|
-
`)}
|
|
180781
|
-
${showNewDef ? html`
|
|
180782
|
-
<div class="settings-inline-form">
|
|
180783
|
-
<sp-textfield
|
|
180784
|
-
size="s"
|
|
180785
|
-
placeholder="TypeName"
|
|
180786
|
-
.value=${newDefName}
|
|
180787
|
-
@input=${(e) => {
|
|
180788
|
-
newDefName = e.target.value;
|
|
180789
|
-
}}
|
|
180790
|
-
@keydown=${(e) => {
|
|
180791
|
-
if (e.key === "Enter")
|
|
180792
|
-
handleNewDef(rerender);
|
|
180793
|
-
if (e.key === "Escape") {
|
|
180794
|
-
showNewDef = false;
|
|
180795
|
-
rerender();
|
|
180796
|
-
}
|
|
180797
|
-
}}
|
|
180798
|
-
></sp-textfield>
|
|
180799
|
-
<sp-action-button size="s" @click=${() => handleNewDef(rerender)}>
|
|
180800
|
-
Create
|
|
180801
|
-
</sp-action-button>
|
|
180802
|
-
</div>
|
|
180803
|
-
` : html`
|
|
180804
|
-
<sp-action-button
|
|
180805
|
-
size="s"
|
|
180806
|
-
quiet
|
|
180807
|
-
@click=${() => {
|
|
180808
|
-
showNewDef = true;
|
|
180809
|
-
rerender();
|
|
180810
|
-
}}
|
|
180811
|
-
>
|
|
180812
|
-
<sp-icon-add slot="icon"></sp-icon-add> New Definition
|
|
180813
|
-
</sp-action-button>
|
|
180814
|
-
`}
|
|
180815
|
-
</div>
|
|
180816
|
-
`;
|
|
180817
|
-
let editorTpl;
|
|
180818
|
-
if (!selectedDef || !defs[selectedDef]) {
|
|
180819
|
-
editorTpl = html`<div class="settings-empty-state">Select or create a type definition</div>`;
|
|
180820
|
-
} else {
|
|
180821
|
-
const def3 = defs[selectedDef];
|
|
180822
|
-
const properties = def3.properties || {};
|
|
180823
|
-
const required = def3.required || [];
|
|
180824
|
-
const handlers = {
|
|
180825
|
-
onDelete: (n2) => handleDeleteField(n2, rerender),
|
|
180826
|
-
onToggleRequired: (n2) => handleToggleRequired(n2, rerender),
|
|
180827
|
-
onRename: (oldN, newN) => handleRenameField(oldN, newN, rerender),
|
|
180828
|
-
onChangeType: (n2, t) => handleChangeType(n2, t, rerender),
|
|
180829
|
-
onChangeFormat: (n2, f) => handleChangeFormat(n2, f, rerender),
|
|
180830
|
-
onAddNestedField: (p, s2) => handleAddNestedField(p, s2, rerender),
|
|
180831
|
-
onDeleteNested: (p, c) => handleDeleteNested(p, c, rerender),
|
|
180832
|
-
onToggleNestedRequired: (p, c) => handleToggleNestedRequired(p, c, rerender),
|
|
180833
|
-
onRenameNested: (p, o, n2) => handleRenameNested(p, o, n2, rerender),
|
|
180834
|
-
onChangeNestedType: (p, c, t) => handleChangeNestedType(p, c, t, rerender),
|
|
180835
|
-
onChangeNestedFormat: (p, c, f) => handleChangeNestedFormat(p, c, f, rerender)
|
|
180836
|
-
};
|
|
180837
|
-
const fieldCards = Object.entries(properties).map(([name, fieldDef]) => fieldCardTpl(name, fieldDef, required.includes(name), handlers));
|
|
180838
|
-
editorTpl = html`
|
|
180839
|
-
<div class="settings-editor-panel">
|
|
180840
|
-
<div class="settings-editor-header">
|
|
180841
|
-
<h3>${selectedDef}</h3>
|
|
180842
|
-
<sp-action-button
|
|
180843
|
-
size="xs"
|
|
180844
|
-
quiet
|
|
180845
|
-
title="Delete definition"
|
|
180846
|
-
@click=${() => handleDeleteDef(rerender)}
|
|
180847
|
-
>
|
|
180848
|
-
<sp-icon-delete slot="icon"></sp-icon-delete>
|
|
180849
|
-
</sp-action-button>
|
|
180850
|
-
</div>
|
|
180851
|
-
<div class="schema-field-list">${fieldCards}</div>
|
|
180852
|
-
${showAddField ? addFieldFormTpl(newFieldState, {
|
|
180853
|
-
onInput: (field, value2) => {
|
|
180854
|
-
newFieldState = { ...newFieldState, [field]: value2 };
|
|
180855
|
-
rerender();
|
|
180856
|
-
},
|
|
180857
|
-
onConfirm: () => handleAddField(rerender),
|
|
180858
|
-
onCancel: () => {
|
|
180859
|
-
showAddField = false;
|
|
180860
|
-
newFieldState = { name: "", type: "string", format: "", required: false };
|
|
180861
|
-
rerender();
|
|
180862
|
-
}
|
|
180863
|
-
}) : html`
|
|
180864
|
-
<sp-action-button
|
|
180865
|
-
size="s"
|
|
180866
|
-
quiet
|
|
180867
|
-
@click=${() => {
|
|
180868
|
-
showAddField = true;
|
|
180869
|
-
rerender();
|
|
180870
|
-
}}
|
|
180871
|
-
>
|
|
180872
|
-
<sp-icon-add slot="icon"></sp-icon-add> Add Field
|
|
180873
|
-
</sp-action-button>
|
|
180874
|
-
`}
|
|
180875
|
-
</div>
|
|
180876
|
-
`;
|
|
180877
|
-
}
|
|
180878
|
-
const tpl = html` <div class="settings-two-col">${listTpl} ${editorTpl}</div> `;
|
|
180879
|
-
render2(tpl, container);
|
|
180880
|
-
}
|
|
180881
|
-
|
|
180882
|
-
// src/settings/content-types-editor.js
|
|
180883
|
-
init_platform();
|
|
180884
|
-
init_store();
|
|
180885
|
-
var selectedContentType = null;
|
|
180886
|
-
var showAddField2 = false;
|
|
180887
|
-
var newFieldState2 = { name: "", type: "string", format: "", required: false };
|
|
180888
|
-
var showNewContentType = false;
|
|
180889
|
-
var newContentTypeName = "";
|
|
180890
|
-
async function saveProjectConfig2() {
|
|
180891
|
-
const platform3 = getPlatform();
|
|
180892
|
-
const config = projectState.projectConfig;
|
|
180893
|
-
await platform3.writeFile("project.json", JSON.stringify(config, null, "\t"));
|
|
180894
|
-
}
|
|
180895
|
-
function getSelectedSchema() {
|
|
180896
|
-
const config = projectState?.projectConfig;
|
|
180897
|
-
return config?.contentTypes?.[selectedContentType]?.schema;
|
|
180898
|
-
}
|
|
180899
|
-
function handleNewContentType(rerender) {
|
|
180900
|
-
const slug = newContentTypeName.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
|
|
180901
|
-
if (!slug)
|
|
180902
|
-
return;
|
|
180903
|
-
const config = projectState?.projectConfig;
|
|
180904
|
-
if (!config)
|
|
180905
|
-
return;
|
|
180906
|
-
if (!config.contentTypes)
|
|
180907
|
-
config.contentTypes = {};
|
|
180908
|
-
if (config.contentTypes[slug])
|
|
180909
|
-
return;
|
|
180910
|
-
config.contentTypes[slug] = {
|
|
180911
|
-
source: `./content/${slug}/**/*.md`,
|
|
180912
|
-
schema: { type: "object", properties: {}, required: [] }
|
|
180913
|
-
};
|
|
180914
|
-
selectedContentType = slug;
|
|
180915
|
-
showNewContentType = false;
|
|
180916
|
-
newContentTypeName = "";
|
|
180917
|
-
rerender();
|
|
180918
|
-
saveProjectConfig2().then(async () => {
|
|
180919
|
-
const platform3 = getPlatform();
|
|
180920
|
-
await platform3.writeFile(`content/${slug}/.gitkeep`, "");
|
|
180921
|
-
});
|
|
180922
|
-
}
|
|
180923
|
-
function handleAddField2(rerender) {
|
|
180924
|
-
const name = newFieldState2.name.trim();
|
|
180925
|
-
if (!name || !selectedContentType)
|
|
180926
|
-
return;
|
|
180927
|
-
const schema4 = getSelectedSchema();
|
|
180928
|
-
if (!schema4)
|
|
180929
|
-
return;
|
|
180930
|
-
if (!schema4.properties)
|
|
180931
|
-
schema4.properties = {};
|
|
180932
|
-
schema4.properties[name] = schemaForType(newFieldState2.type, newFieldState2.format || undefined);
|
|
180933
|
-
if (newFieldState2.required) {
|
|
180934
|
-
if (!schema4.required)
|
|
180935
|
-
schema4.required = [];
|
|
180936
|
-
if (!schema4.required.includes(name))
|
|
180937
|
-
schema4.required.push(name);
|
|
180938
|
-
}
|
|
180939
|
-
showAddField2 = false;
|
|
180940
|
-
newFieldState2 = { name: "", type: "string", format: "", required: false };
|
|
180941
|
-
rerender();
|
|
180942
|
-
saveProjectConfig2();
|
|
180943
|
-
}
|
|
180944
|
-
function handleDeleteField2(fieldName, rerender) {
|
|
180945
|
-
const schema4 = getSelectedSchema();
|
|
180946
|
-
if (!schema4?.properties)
|
|
180947
|
-
return;
|
|
180948
|
-
delete schema4.properties[fieldName];
|
|
180949
|
-
if (schema4.required) {
|
|
180950
|
-
schema4.required = schema4.required.filter((r) => r !== fieldName);
|
|
180951
|
-
}
|
|
180952
|
-
rerender();
|
|
180953
|
-
saveProjectConfig2();
|
|
180954
|
-
}
|
|
180955
|
-
function handleToggleRequired2(fieldName, rerender) {
|
|
180956
|
-
const schema4 = getSelectedSchema();
|
|
180957
|
-
if (!schema4)
|
|
180958
|
-
return;
|
|
180959
|
-
if (!schema4.required)
|
|
180960
|
-
schema4.required = [];
|
|
180961
|
-
const idx = schema4.required.indexOf(fieldName);
|
|
180962
|
-
if (idx >= 0)
|
|
180963
|
-
schema4.required.splice(idx, 1);
|
|
180964
|
-
else
|
|
180965
|
-
schema4.required.push(fieldName);
|
|
180966
|
-
rerender();
|
|
180967
|
-
saveProjectConfig2();
|
|
180968
|
-
}
|
|
180969
|
-
function handleRenameField2(oldName, newName, rerender) {
|
|
180970
|
-
const schema4 = getSelectedSchema();
|
|
180971
|
-
if (!schema4?.properties || !newName || schema4.properties[newName])
|
|
180972
|
-
return;
|
|
180973
|
-
const newProps = {};
|
|
180974
|
-
for (const [key, val] of Object.entries(schema4.properties)) {
|
|
180975
|
-
newProps[key === oldName ? newName : key] = val;
|
|
180976
|
-
}
|
|
180977
|
-
schema4.properties = newProps;
|
|
180978
|
-
if (schema4.required) {
|
|
180979
|
-
schema4.required = schema4.required.map((r) => r === oldName ? newName : r);
|
|
180980
|
-
}
|
|
180981
|
-
rerender();
|
|
180982
|
-
saveProjectConfig2();
|
|
180983
|
-
}
|
|
180984
|
-
function handleChangeType2(fieldName, newType, rerender) {
|
|
180985
|
-
const schema4 = getSelectedSchema();
|
|
180986
|
-
if (!schema4?.properties?.[fieldName])
|
|
180987
|
-
return;
|
|
180988
|
-
const oldFormat = newType === "string" || newType === "array" ? detectFieldFormat(schema4.properties[fieldName]) : undefined;
|
|
180989
|
-
schema4.properties[fieldName] = schemaForType(newType, oldFormat || undefined);
|
|
180990
|
-
rerender();
|
|
180991
|
-
saveProjectConfig2();
|
|
180992
|
-
}
|
|
180993
|
-
function handleChangeFormat2(fieldName, format2, rerender) {
|
|
180994
|
-
const schema4 = getSelectedSchema();
|
|
180995
|
-
if (!schema4?.properties?.[fieldName])
|
|
180996
|
-
return;
|
|
180997
|
-
const prop = schema4.properties[fieldName];
|
|
180998
|
-
const type = prop.type || "string";
|
|
180999
|
-
schema4.properties[fieldName] = schemaForType(type, format2 || undefined);
|
|
181000
|
-
rerender();
|
|
181001
|
-
saveProjectConfig2();
|
|
181002
|
-
}
|
|
181003
|
-
function handleChangeRefTarget(fieldName, target, rerender) {
|
|
181004
|
-
const schema4 = getSelectedSchema();
|
|
181005
|
-
if (!schema4?.properties)
|
|
181006
|
-
return;
|
|
181007
|
-
schema4.properties[fieldName] = { $ref: `#/contentTypes/${target}` };
|
|
181008
|
-
rerender();
|
|
181009
|
-
saveProjectConfig2();
|
|
181010
|
-
}
|
|
181011
|
-
function handleAddNestedField2(parentName, fieldState, rerender) {
|
|
181012
|
-
const schema4 = getSelectedSchema();
|
|
181013
|
-
const parent = schema4?.properties?.[parentName];
|
|
181014
|
-
if (!parent)
|
|
181015
|
-
return;
|
|
181016
|
-
if (!parent.properties)
|
|
181017
|
-
parent.properties = {};
|
|
181018
|
-
parent.properties[fieldState.name] = schemaForType(fieldState.type);
|
|
181019
|
-
if (fieldState.required) {
|
|
181020
|
-
if (!parent.required)
|
|
181021
|
-
parent.required = [];
|
|
181022
|
-
if (!parent.required.includes(fieldState.name))
|
|
181023
|
-
parent.required.push(fieldState.name);
|
|
181024
|
-
}
|
|
181025
|
-
rerender();
|
|
181026
|
-
saveProjectConfig2();
|
|
181027
|
-
}
|
|
181028
|
-
function handleDeleteNested2(parentName, childName, rerender) {
|
|
181029
|
-
const schema4 = getSelectedSchema();
|
|
181030
|
-
const parent = schema4?.properties?.[parentName];
|
|
181031
|
-
if (!parent?.properties)
|
|
181032
|
-
return;
|
|
181033
|
-
delete parent.properties[childName];
|
|
181034
|
-
if (parent.required) {
|
|
181035
|
-
parent.required = parent.required.filter((r) => r !== childName);
|
|
181036
|
-
}
|
|
181037
|
-
rerender();
|
|
181038
|
-
saveProjectConfig2();
|
|
181039
|
-
}
|
|
181040
|
-
function handleToggleNestedRequired2(parentName, childName, rerender) {
|
|
181041
|
-
const schema4 = getSelectedSchema();
|
|
181042
|
-
const parent = schema4?.properties?.[parentName];
|
|
181043
|
-
if (!parent)
|
|
181044
|
-
return;
|
|
181045
|
-
if (!parent.required)
|
|
181046
|
-
parent.required = [];
|
|
181047
|
-
const idx = parent.required.indexOf(childName);
|
|
181048
|
-
if (idx >= 0)
|
|
181049
|
-
parent.required.splice(idx, 1);
|
|
181050
|
-
else
|
|
181051
|
-
parent.required.push(childName);
|
|
181052
|
-
rerender();
|
|
181053
|
-
saveProjectConfig2();
|
|
181054
|
-
}
|
|
181055
|
-
function handleRenameNested2(parentName, oldChild, newChild, rerender) {
|
|
181056
|
-
const schema4 = getSelectedSchema();
|
|
181057
|
-
const parent = schema4?.properties?.[parentName];
|
|
181058
|
-
if (!parent?.properties || !newChild || parent.properties[newChild])
|
|
181059
|
-
return;
|
|
181060
|
-
const newProps = {};
|
|
181061
|
-
for (const [key, val] of Object.entries(parent.properties)) {
|
|
181062
|
-
newProps[key === oldChild ? newChild : key] = val;
|
|
181063
|
-
}
|
|
181064
|
-
parent.properties = newProps;
|
|
181065
|
-
if (parent.required) {
|
|
181066
|
-
parent.required = parent.required.map((r) => r === oldChild ? newChild : r);
|
|
181067
|
-
}
|
|
181068
|
-
rerender();
|
|
181069
|
-
saveProjectConfig2();
|
|
181070
|
-
}
|
|
181071
|
-
function handleChangeNestedType2(parentName, childName, newType, rerender) {
|
|
181072
|
-
const schema4 = getSelectedSchema();
|
|
181073
|
-
const parent = schema4?.properties?.[parentName];
|
|
181074
|
-
if (!parent?.properties?.[childName])
|
|
181075
|
-
return;
|
|
181076
|
-
const oldFormat = newType === "string" || newType === "array" ? detectFieldFormat(parent.properties[childName]) : undefined;
|
|
181077
|
-
parent.properties[childName] = schemaForType(newType, oldFormat || undefined);
|
|
181078
|
-
rerender();
|
|
181079
|
-
saveProjectConfig2();
|
|
181080
|
-
}
|
|
181081
|
-
function handleChangeNestedFormat2(parentName, childName, format2, rerender) {
|
|
181082
|
-
const schema4 = getSelectedSchema();
|
|
181083
|
-
const parent = schema4?.properties?.[parentName];
|
|
181084
|
-
if (!parent?.properties?.[childName])
|
|
181085
|
-
return;
|
|
181086
|
-
const prop = parent.properties[childName];
|
|
181087
|
-
const type = prop.type || "string";
|
|
181088
|
-
parent.properties[childName] = schemaForType(type, format2 || undefined);
|
|
181089
|
-
rerender();
|
|
181090
|
-
saveProjectConfig2();
|
|
181091
|
-
}
|
|
181092
|
-
function handleDeleteContentType(rerender) {
|
|
181093
|
-
if (!selectedContentType)
|
|
181094
|
-
return;
|
|
181095
|
-
const config = projectState?.projectConfig;
|
|
181096
|
-
if (!config?.contentTypes?.[selectedContentType])
|
|
181097
|
-
return;
|
|
181098
|
-
delete config.contentTypes[selectedContentType];
|
|
181099
|
-
selectedContentType = null;
|
|
181100
|
-
rerender();
|
|
181101
|
-
saveProjectConfig2();
|
|
181102
|
-
}
|
|
181103
|
-
function renderContentTypesEditor(container) {
|
|
181104
|
-
const rerender = () => renderContentTypesEditor(container);
|
|
181105
|
-
const config = projectState?.projectConfig;
|
|
181106
|
-
const contentTypes = config?.contentTypes || {};
|
|
181107
|
-
const contentTypeNames = Object.keys(contentTypes);
|
|
181108
|
-
const listTpl = html`
|
|
181109
|
-
<div class="settings-list-panel">
|
|
181110
|
-
${contentTypeNames.map((name) => html`
|
|
181111
|
-
<sp-action-button
|
|
181112
|
-
size="s"
|
|
181113
|
-
?selected=${selectedContentType === name}
|
|
181114
|
-
@click=${() => {
|
|
181115
|
-
selectedContentType = name;
|
|
181116
|
-
showAddField2 = false;
|
|
181117
|
-
rerender();
|
|
181118
|
-
}}
|
|
181119
|
-
>
|
|
181120
|
-
${name}
|
|
181121
|
-
</sp-action-button>
|
|
181122
|
-
`)}
|
|
181123
|
-
${showNewContentType ? html`
|
|
181124
|
-
<div class="settings-inline-form">
|
|
181125
|
-
<sp-textfield
|
|
181126
|
-
size="s"
|
|
181127
|
-
placeholder="content-type-name"
|
|
181128
|
-
.value=${newContentTypeName}
|
|
181129
|
-
@input=${(e) => {
|
|
181130
|
-
newContentTypeName = e.target.value;
|
|
181131
|
-
}}
|
|
181132
|
-
@keydown=${(e) => {
|
|
181133
|
-
if (e.key === "Enter")
|
|
181134
|
-
handleNewContentType(rerender);
|
|
181135
|
-
if (e.key === "Escape") {
|
|
181136
|
-
showNewContentType = false;
|
|
181137
|
-
rerender();
|
|
181138
|
-
}
|
|
181139
|
-
}}
|
|
181140
|
-
></sp-textfield>
|
|
181141
|
-
<sp-action-button size="s" @click=${() => handleNewContentType(rerender)}>
|
|
181142
|
-
Create
|
|
181143
|
-
</sp-action-button>
|
|
181144
|
-
</div>
|
|
181145
|
-
` : html`
|
|
181146
|
-
<sp-action-button
|
|
181147
|
-
size="s"
|
|
181148
|
-
quiet
|
|
181149
|
-
@click=${() => {
|
|
181150
|
-
showNewContentType = true;
|
|
181151
|
-
rerender();
|
|
181152
|
-
}}
|
|
181153
|
-
>
|
|
181154
|
-
<sp-icon-add slot="icon"></sp-icon-add> New Content Type
|
|
181155
|
-
</sp-action-button>
|
|
181156
|
-
`}
|
|
181157
|
-
</div>
|
|
181158
|
-
`;
|
|
181159
|
-
let editorTpl;
|
|
181160
|
-
if (!selectedContentType || !contentTypes[selectedContentType]) {
|
|
181161
|
-
editorTpl = html`<div class="settings-empty-state">Select or create a content type</div>`;
|
|
181162
|
-
} else {
|
|
181163
|
-
const col = contentTypes[selectedContentType];
|
|
181164
|
-
const schema4 = col.schema || {};
|
|
181165
|
-
const properties = schema4.properties || {};
|
|
181166
|
-
const required = schema4.required || [];
|
|
181167
|
-
const handlers = {
|
|
181168
|
-
onDelete: (n2) => handleDeleteField2(n2, rerender),
|
|
181169
|
-
onToggleRequired: (n2) => handleToggleRequired2(n2, rerender),
|
|
181170
|
-
onRename: (oldN, newN) => handleRenameField2(oldN, newN, rerender),
|
|
181171
|
-
onChangeType: (n2, t) => handleChangeType2(n2, t, rerender),
|
|
181172
|
-
onChangeFormat: (n2, f) => handleChangeFormat2(n2, f, rerender),
|
|
181173
|
-
onChangeRefTarget: (n2, target) => handleChangeRefTarget(n2, target, rerender),
|
|
181174
|
-
onAddNestedField: (p, s2) => handleAddNestedField2(p, s2, rerender),
|
|
181175
|
-
onDeleteNested: (p, c) => handleDeleteNested2(p, c, rerender),
|
|
181176
|
-
onToggleNestedRequired: (p, c) => handleToggleNestedRequired2(p, c, rerender),
|
|
181177
|
-
onRenameNested: (p, o, n2) => handleRenameNested2(p, o, n2, rerender),
|
|
181178
|
-
onChangeNestedType: (p, c, t) => handleChangeNestedType2(p, c, t, rerender),
|
|
181179
|
-
onChangeNestedFormat: (p, c, f) => handleChangeNestedFormat2(p, c, f, rerender)
|
|
181180
|
-
};
|
|
181181
|
-
const fieldCards = Object.entries(properties).map(([name, def3]) => fieldCardTpl(name, def3, required.includes(name), handlers, contentTypeNames));
|
|
181182
|
-
editorTpl = html`
|
|
181183
|
-
<div class="settings-editor-panel">
|
|
181184
|
-
<div class="settings-editor-header">
|
|
181185
|
-
<h3>${selectedContentType}</h3>
|
|
181186
|
-
<sp-field-label size="s">Source: ${col.source || "—"}</sp-field-label>
|
|
181187
|
-
<sp-action-button
|
|
181188
|
-
size="xs"
|
|
181189
|
-
quiet
|
|
181190
|
-
title="Delete content type"
|
|
181191
|
-
@click=${() => handleDeleteContentType(rerender)}
|
|
181192
|
-
>
|
|
181193
|
-
<sp-icon-delete slot="icon"></sp-icon-delete>
|
|
181194
|
-
</sp-action-button>
|
|
181195
|
-
</div>
|
|
181196
|
-
<div class="schema-field-list">${fieldCards}</div>
|
|
181197
|
-
${showAddField2 ? addFieldFormTpl(newFieldState2, {
|
|
181198
|
-
onInput: (field, value2) => {
|
|
181199
|
-
newFieldState2 = { ...newFieldState2, [field]: value2 };
|
|
181200
|
-
rerender();
|
|
181201
|
-
},
|
|
181202
|
-
onConfirm: () => handleAddField2(rerender),
|
|
181203
|
-
onCancel: () => {
|
|
181204
|
-
showAddField2 = false;
|
|
181205
|
-
newFieldState2 = { name: "", type: "string", format: "", required: false };
|
|
181206
|
-
rerender();
|
|
181207
|
-
}
|
|
181208
|
-
}) : html`
|
|
181209
|
-
<sp-action-button
|
|
181210
|
-
size="s"
|
|
181211
|
-
quiet
|
|
181212
|
-
@click=${() => {
|
|
181213
|
-
showAddField2 = true;
|
|
181214
|
-
rerender();
|
|
181215
|
-
}}
|
|
181216
|
-
>
|
|
181217
|
-
<sp-icon-add slot="icon"></sp-icon-add> Add Field
|
|
181218
|
-
</sp-action-button>
|
|
181219
|
-
`}
|
|
181220
|
-
</div>
|
|
181221
|
-
`;
|
|
181222
|
-
}
|
|
181223
|
-
const tpl = html` <div class="settings-two-col">${listTpl} ${editorTpl}</div> `;
|
|
181224
|
-
render2(tpl, container);
|
|
181225
|
-
}
|
|
181226
180103
|
// data/stylebook-meta.json
|
|
181227
180104
|
var stylebook_meta_default = {
|
|
181228
180105
|
$sections: [
|
|
@@ -181433,39 +180310,6 @@ registerBlockType( name, settings );`
|
|
|
181433
180310
|
var _ctx6 = null;
|
|
181434
180311
|
function renderStylebookMode(ctx) {
|
|
181435
180312
|
_ctx6 = ctx;
|
|
181436
|
-
const settingsTab = activeTab.value?.session.ui.settingsTab || "stylebook";
|
|
181437
|
-
const settingsChromeBarTpl = html`
|
|
181438
|
-
<div
|
|
181439
|
-
class="sb-chrome settings-top-chrome"
|
|
181440
|
-
style="position:absolute;top:0;left:0;right:0;z-index:16;background:var(--bg-panel);border-bottom:1px solid var(--border)"
|
|
181441
|
-
>
|
|
181442
|
-
<sp-tabs
|
|
181443
|
-
size="s"
|
|
181444
|
-
selected=${settingsTab}
|
|
181445
|
-
@change=${(e) => {
|
|
181446
|
-
updateUi("settingsTab", e.target.selected);
|
|
181447
|
-
}}
|
|
181448
|
-
>
|
|
181449
|
-
<sp-tab label="Stylebook" value="stylebook"></sp-tab>
|
|
181450
|
-
<sp-tab label="Definitions" value="definitions"></sp-tab>
|
|
181451
|
-
<sp-tab label="Content Types" value="contentTypes"></sp-tab>
|
|
181452
|
-
</sp-tabs>
|
|
181453
|
-
</div>
|
|
181454
|
-
`;
|
|
181455
|
-
if (settingsTab === "definitions" || settingsTab === "contentTypes") {
|
|
181456
|
-
canvasWrap.style.overflow = "hidden";
|
|
181457
|
-
render2(html`${settingsChromeBarTpl}
|
|
181458
|
-
<div
|
|
181459
|
-
class="settings-editor-container"
|
|
181460
|
-
style="position:absolute;inset:40px 0 0 0;overflow:auto"
|
|
181461
|
-
></div>`, canvasWrap);
|
|
181462
|
-
const container = canvasWrap.querySelector(".settings-editor-container");
|
|
181463
|
-
if (settingsTab === "definitions")
|
|
181464
|
-
renderDefsEditor(container);
|
|
181465
|
-
else
|
|
181466
|
-
renderContentTypesEditor(container);
|
|
181467
|
-
return;
|
|
181468
|
-
}
|
|
181469
180313
|
view.stylebookElToTag = new WeakMap;
|
|
181470
180314
|
const tab = activeTab.value;
|
|
181471
180315
|
const rootStyle = getEffectiveStyle(tab?.doc.document?.style);
|
|
@@ -181473,9 +180317,6 @@ function renderStylebookMode(ctx) {
|
|
|
181473
180317
|
const customizedOnly = tab?.session.ui.stylebookCustomizedOnly;
|
|
181474
180318
|
const { sizeBreakpoints, baseWidth } = parseMediaEntries(getEffectiveMedia(tab?.doc.document?.$media));
|
|
181475
180319
|
const hasMedia = sizeBreakpoints.length > 0;
|
|
181476
|
-
const onTabClick = (t) => {
|
|
181477
|
-
updateUi("stylebookTab", t);
|
|
181478
|
-
};
|
|
181479
180320
|
const onFilterInput2 = (e) => {
|
|
181480
180321
|
updateUi("stylebookFilter", e.target.value);
|
|
181481
180322
|
};
|
|
@@ -181483,38 +180324,25 @@ function renderStylebookMode(ctx) {
|
|
|
181483
180324
|
updateUi("stylebookCustomizedOnly", !tab?.session.ui.stylebookCustomizedOnly);
|
|
181484
180325
|
};
|
|
181485
180326
|
const chromeBarTpl = html`
|
|
181486
|
-
${settingsChromeBarTpl}
|
|
181487
180327
|
<div
|
|
181488
180328
|
class="sb-chrome"
|
|
181489
|
-
style="position:absolute;top:
|
|
180329
|
+
style="position:absolute;top:0;left:0;right:0;z-index:15;background:var(--bg-panel);border-bottom:1px solid var(--border)"
|
|
181490
180330
|
>
|
|
181491
|
-
<
|
|
181492
|
-
|
|
181493
|
-
|
|
181494
|
-
|
|
181495
|
-
|
|
181496
|
-
|
|
181497
|
-
|
|
181498
|
-
|
|
181499
|
-
|
|
181500
|
-
|
|
181501
|
-
|
|
181502
|
-
|
|
181503
|
-
|
|
181504
|
-
|
|
181505
|
-
|
|
181506
|
-
placeholder="Filter…"
|
|
181507
|
-
.value=${tab?.session.ui.stylebookFilter}
|
|
181508
|
-
@input=${onFilterInput2}
|
|
181509
|
-
/>
|
|
181510
|
-
<button
|
|
181511
|
-
class="tb-toggle${tab?.session.ui.stylebookCustomizedOnly ? " active" : ""}"
|
|
181512
|
-
style="margin-left:4px"
|
|
181513
|
-
@click=${onCustomizedToggle}
|
|
181514
|
-
>
|
|
181515
|
-
Customized
|
|
181516
|
-
</button>
|
|
181517
|
-
` : nothing}
|
|
180331
|
+
<div style="display:flex;align-items:center;padding:4px 8px;gap:4px">
|
|
180332
|
+
<input
|
|
180333
|
+
class="field-input"
|
|
180334
|
+
style="flex:1;max-width:200px"
|
|
180335
|
+
placeholder="Filter…"
|
|
180336
|
+
.value=${tab?.session.ui.stylebookFilter}
|
|
180337
|
+
@input=${onFilterInput2}
|
|
180338
|
+
/>
|
|
180339
|
+
<button
|
|
180340
|
+
class="tb-toggle${tab?.session.ui.stylebookCustomizedOnly ? " active" : ""}"
|
|
180341
|
+
@click=${onCustomizedToggle}
|
|
180342
|
+
>
|
|
180343
|
+
Customized
|
|
180344
|
+
</button>
|
|
180345
|
+
</div>
|
|
181518
180346
|
</div>
|
|
181519
180347
|
`;
|
|
181520
180348
|
canvasWrap.style.overflow = "hidden";
|
|
@@ -181537,16 +180365,11 @@ function renderStylebookMode(ctx) {
|
|
|
181537
180365
|
}
|
|
181538
180366
|
const renderIntoPanel = (panel, activeBreakpoints) => {
|
|
181539
180367
|
panel.canvas.classList.add("sb-canvas");
|
|
181540
|
-
|
|
181541
|
-
|
|
181542
|
-
|
|
181543
|
-
child.style.pointerEvents = "none";
|
|
181544
|
-
}
|
|
181545
|
-
registerStylebookPanelEvents(panel);
|
|
181546
|
-
} else {
|
|
181547
|
-
renderStylebookVarsIntoCanvas(panel.canvas, rootStyle);
|
|
181548
|
-
panel.overlayClk.style.pointerEvents = "none";
|
|
180368
|
+
renderStylebookElementsIntoCanvas(panel.canvas, rootStyle, filter, customizedOnly, activeBreakpoints);
|
|
180369
|
+
for (const child of panel.canvas.querySelectorAll("*")) {
|
|
180370
|
+
child.style.pointerEvents = "none";
|
|
181549
180371
|
}
|
|
180372
|
+
registerStylebookPanelEvents(panel);
|
|
181550
180373
|
};
|
|
181551
180374
|
let panelEntries;
|
|
181552
180375
|
if (!hasMedia) {
|
|
@@ -181566,7 +180389,7 @@ function renderStylebookMode(ctx) {
|
|
|
181566
180389
|
${chromeBarTpl}
|
|
181567
180390
|
<div
|
|
181568
180391
|
class="panzoom-wrap"
|
|
181569
|
-
style="transform-origin:0 0;padding-top:
|
|
180392
|
+
style="transform-origin:0 0;padding-top:40px"
|
|
181570
180393
|
${ref2((el) => {
|
|
181571
180394
|
if (el)
|
|
181572
180395
|
view.panzoomWrap = el;
|
|
@@ -181856,363 +180679,6 @@ function renderStylebookElementsIntoCanvas(canvasEl, rootStyle, filter, customiz
|
|
|
181856
180679
|
render2(html`${sectionTemplates}`, canvasEl);
|
|
181857
180680
|
}
|
|
181858
180681
|
}
|
|
181859
|
-
function renderStylebookVarsIntoCanvas(canvasEl, rootStyle) {
|
|
181860
|
-
const varCats = stylebook_meta_default.$variables;
|
|
181861
|
-
const groups = {};
|
|
181862
|
-
for (const key of Object.keys(varCats))
|
|
181863
|
-
groups[key] = [];
|
|
181864
|
-
for (const [k, v] of Object.entries(rootStyle)) {
|
|
181865
|
-
if (!k.startsWith("--"))
|
|
181866
|
-
continue;
|
|
181867
|
-
if (typeof v !== "string" && typeof v !== "number")
|
|
181868
|
-
continue;
|
|
181869
|
-
if (k.startsWith("--color"))
|
|
181870
|
-
groups.color.push([k, v]);
|
|
181871
|
-
else if (k.startsWith("--font"))
|
|
181872
|
-
groups.font.push([k, v]);
|
|
181873
|
-
else if (k.startsWith("--size") || k.startsWith("--spacing") || k.startsWith("--radius"))
|
|
181874
|
-
groups.size.push([k, v]);
|
|
181875
|
-
else
|
|
181876
|
-
groups.other.push([k, v]);
|
|
181877
|
-
}
|
|
181878
|
-
const bodyRefs = new Map;
|
|
181879
|
-
const sectionTemplates = Object.entries(varCats).map(([catKey, catMeta]) => {
|
|
181880
|
-
const vars = groups[catKey];
|
|
181881
|
-
const onAdd = () => {
|
|
181882
|
-
const bodyEl = bodyRefs.get(catKey);
|
|
181883
|
-
if (!bodyEl)
|
|
181884
|
-
return;
|
|
181885
|
-
const addBtn = bodyEl.querySelector(".sb-var-add-btn");
|
|
181886
|
-
const row = renderVarRow(catKey, catMeta, null, "", true);
|
|
181887
|
-
bodyEl.insertBefore(row, addBtn);
|
|
181888
|
-
if (addBtn)
|
|
181889
|
-
addBtn.style.display = "none";
|
|
181890
|
-
const nameField = row.querySelector("sp-textfield");
|
|
181891
|
-
if (nameField)
|
|
181892
|
-
requestAnimationFrame(() => nameField.focus());
|
|
181893
|
-
};
|
|
181894
|
-
return html`
|
|
181895
|
-
<div class="sb-section">
|
|
181896
|
-
<div class="sb-label">${catMeta.label}</div>
|
|
181897
|
-
<div
|
|
181898
|
-
class="sb-body"
|
|
181899
|
-
${ref2((el) => {
|
|
181900
|
-
if (el)
|
|
181901
|
-
bodyRefs.set(catKey, el);
|
|
181902
|
-
})}
|
|
181903
|
-
>
|
|
181904
|
-
${vars.length > 0 ? vars.map(([varName, varVal]) => renderVarRow(catKey, catMeta, varName, String(varVal), false)) : html`<div class="sb-var-empty">
|
|
181905
|
-
No ${catMeta.label.toLowerCase()} variables yet.
|
|
181906
|
-
</div>`}
|
|
181907
|
-
<button class="sb-var-add-btn" @click=${onAdd}>
|
|
181908
|
-
<span class="sb-var-add-icon">+</span> Add ${catMeta.label}
|
|
181909
|
-
</button>
|
|
181910
|
-
</div>
|
|
181911
|
-
</div>
|
|
181912
|
-
`;
|
|
181913
|
-
});
|
|
181914
|
-
render2(html`${sectionTemplates}`, canvasEl);
|
|
181915
|
-
}
|
|
181916
|
-
function renderVarRow(catKey, catMeta, varName, varVal, isNew) {
|
|
181917
|
-
const row = document.createElement("div");
|
|
181918
|
-
row.className = isNew ? "sb-var-row is-new" : "sb-var-row";
|
|
181919
|
-
let colorPicker = null;
|
|
181920
|
-
let nameField = null;
|
|
181921
|
-
let getValueFn;
|
|
181922
|
-
let hexField = null;
|
|
181923
|
-
const swatchTpl = catKey === "color" ? html`
|
|
181924
|
-
<div
|
|
181925
|
-
class="sb-var-swatch"
|
|
181926
|
-
style=${styleMap({ backgroundColor: varVal || "var(--accent)" })}
|
|
181927
|
-
>
|
|
181928
|
-
<input
|
|
181929
|
-
type="color"
|
|
181930
|
-
.value=${varVal && varVal.startsWith("#") ? varVal : "#007acc"}
|
|
181931
|
-
${ref2((el) => {
|
|
181932
|
-
if (el)
|
|
181933
|
-
colorPicker = el;
|
|
181934
|
-
})}
|
|
181935
|
-
@input=${() => {
|
|
181936
|
-
if (!colorPicker || !hexField)
|
|
181937
|
-
return;
|
|
181938
|
-
hexField.value = colorPicker.value;
|
|
181939
|
-
const swatch = row.querySelector(".sb-var-swatch");
|
|
181940
|
-
if (swatch)
|
|
181941
|
-
swatch.style.backgroundColor = colorPicker.value;
|
|
181942
|
-
if (!isNew && varName) {
|
|
181943
|
-
transactDoc(activeTab.value, (t) => mutateUpdateStyle(t, [], varName, colorPicker.value));
|
|
181944
|
-
}
|
|
181945
|
-
}}
|
|
181946
|
-
/>
|
|
181947
|
-
</div>
|
|
181948
|
-
` : nothing;
|
|
181949
|
-
const namePlaceholder = catKey === "color" ? "Primary Blue" : catKey === "font" ? "Body Serif" : catKey === "size" ? "Spacing Large" : "Border Radius";
|
|
181950
|
-
const nameColTpl = isNew ? html`
|
|
181951
|
-
<div class="sb-var-col-name">
|
|
181952
|
-
<div class="sb-var-col-label">Name</div>
|
|
181953
|
-
<sp-textfield
|
|
181954
|
-
size="s"
|
|
181955
|
-
placeholder=${namePlaceholder}
|
|
181956
|
-
style="pointer-events:auto"
|
|
181957
|
-
${ref2((el) => {
|
|
181958
|
-
if (el)
|
|
181959
|
-
nameField = el;
|
|
181960
|
-
})}
|
|
181961
|
-
></sp-textfield>
|
|
181962
|
-
</div>
|
|
181963
|
-
` : nothing;
|
|
181964
|
-
let valueContent;
|
|
181965
|
-
if (catKey === "color") {
|
|
181966
|
-
let debounce;
|
|
181967
|
-
valueContent = html`
|
|
181968
|
-
<sp-textfield
|
|
181969
|
-
size="s"
|
|
181970
|
-
.value=${varVal || "#007acc"}
|
|
181971
|
-
placeholder="#007acc"
|
|
181972
|
-
style="pointer-events:auto"
|
|
181973
|
-
${ref2((el) => {
|
|
181974
|
-
if (el)
|
|
181975
|
-
hexField = el;
|
|
181976
|
-
})}
|
|
181977
|
-
@input=${() => {
|
|
181978
|
-
clearTimeout(debounce);
|
|
181979
|
-
debounce = setTimeout(() => {
|
|
181980
|
-
if (!hexField)
|
|
181981
|
-
return;
|
|
181982
|
-
const v = hexField.value;
|
|
181983
|
-
try {
|
|
181984
|
-
if (colorPicker)
|
|
181985
|
-
colorPicker.value = v.startsWith("#") ? v : colorPicker.value;
|
|
181986
|
-
} catch {}
|
|
181987
|
-
const swatch = row.querySelector(".sb-var-swatch");
|
|
181988
|
-
if (swatch)
|
|
181989
|
-
swatch.style.backgroundColor = v;
|
|
181990
|
-
if (!isNew && varName) {
|
|
181991
|
-
transactDoc(activeTab.value, (t) => mutateUpdateStyle(t, [], varName, v));
|
|
181992
|
-
}
|
|
181993
|
-
}, 400);
|
|
181994
|
-
}}
|
|
181995
|
-
></sp-textfield>
|
|
181996
|
-
`;
|
|
181997
|
-
getValueFn = () => hexField?.value?.trim() || "";
|
|
181998
|
-
} else if (catKey === "size") {
|
|
181999
|
-
const ui = createUnitInput(varVal || "16px", {
|
|
182000
|
-
onChange: (newVal) => {
|
|
182001
|
-
const bar = row.querySelector(".sb-var-size-bar");
|
|
182002
|
-
if (bar)
|
|
182003
|
-
bar.style.width = newVal;
|
|
182004
|
-
if (!isNew && varName) {
|
|
182005
|
-
transactDoc(activeTab.value, (t) => mutateUpdateStyle(t, [], varName, newVal));
|
|
182006
|
-
}
|
|
182007
|
-
}
|
|
182008
|
-
});
|
|
182009
|
-
if (isNew)
|
|
182010
|
-
ui.textfield.value = "";
|
|
182011
|
-
valueContent = html`<div
|
|
182012
|
-
${ref2((el) => {
|
|
182013
|
-
if (el && !el.firstChild)
|
|
182014
|
-
el.appendChild(ui.wrap);
|
|
182015
|
-
})}
|
|
182016
|
-
></div>`;
|
|
182017
|
-
getValueFn = () => ui.getValue();
|
|
182018
|
-
} else {
|
|
182019
|
-
let textFieldEl = null;
|
|
182020
|
-
let debounce;
|
|
182021
|
-
valueContent = html`
|
|
182022
|
-
<sp-textfield
|
|
182023
|
-
size="s"
|
|
182024
|
-
.value=${varVal}
|
|
182025
|
-
placeholder=${catMeta.placeholder}
|
|
182026
|
-
style="pointer-events:auto"
|
|
182027
|
-
${ref2((el) => {
|
|
182028
|
-
if (el)
|
|
182029
|
-
textFieldEl = el;
|
|
182030
|
-
})}
|
|
182031
|
-
@input=${() => {
|
|
182032
|
-
if (!textFieldEl || isNew || !varName)
|
|
182033
|
-
return;
|
|
182034
|
-
clearTimeout(debounce);
|
|
182035
|
-
debounce = setTimeout(() => {
|
|
182036
|
-
const v = textFieldEl.value;
|
|
182037
|
-
const fontPrev = row.querySelector(".sb-var-font-preview");
|
|
182038
|
-
if (fontPrev)
|
|
182039
|
-
fontPrev.style.fontFamily = v;
|
|
182040
|
-
transactDoc(activeTab.value, (t) => mutateUpdateStyle(t, [], varName, v));
|
|
182041
|
-
}, 400);
|
|
182042
|
-
}}
|
|
182043
|
-
></sp-textfield>
|
|
182044
|
-
`;
|
|
182045
|
-
getValueFn = () => textFieldEl?.value?.trim() || "";
|
|
182046
|
-
}
|
|
182047
|
-
const valColTpl = html`
|
|
182048
|
-
<div class="sb-var-col-value">
|
|
182049
|
-
${isNew ? html`<div class="sb-var-col-label">Value</div>` : nothing} ${valueContent}
|
|
182050
|
-
</div>
|
|
182051
|
-
`;
|
|
182052
|
-
const actionsTpl = isNew ? html`
|
|
182053
|
-
<div class="sb-var-add-actions">
|
|
182054
|
-
<sp-action-button
|
|
182055
|
-
size="s"
|
|
182056
|
-
style="pointer-events:auto"
|
|
182057
|
-
@click=${() => {
|
|
182058
|
-
const name = (nameField?.value || "").trim();
|
|
182059
|
-
const val = getValueFn();
|
|
182060
|
-
const generatedVar = friendlyNameToVar(name, catMeta.prefix);
|
|
182061
|
-
if (!generatedVar || !val)
|
|
182062
|
-
return;
|
|
182063
|
-
transactDoc(activeTab.value, (t) => mutateUpdateStyle(t, [], generatedVar, val));
|
|
182064
|
-
}}
|
|
182065
|
-
>Add</sp-action-button
|
|
182066
|
-
>
|
|
182067
|
-
<sp-action-button
|
|
182068
|
-
size="s"
|
|
182069
|
-
quiet
|
|
182070
|
-
style="pointer-events:auto"
|
|
182071
|
-
@click=${() => {
|
|
182072
|
-
const body = row.parentElement;
|
|
182073
|
-
row.remove();
|
|
182074
|
-
const addBtn = body?.querySelector(".sb-var-add-btn");
|
|
182075
|
-
if (addBtn)
|
|
182076
|
-
addBtn.style.display = "";
|
|
182077
|
-
}}
|
|
182078
|
-
>
|
|
182079
|
-
<sp-icon-close slot="icon"></sp-icon-close>
|
|
182080
|
-
</sp-action-button>
|
|
182081
|
-
</div>
|
|
182082
|
-
` : nothing;
|
|
182083
|
-
const headerTpl = !isNew && varName ? html`
|
|
182084
|
-
<div class="sb-var-row-header">
|
|
182085
|
-
<span class="sb-var-row-title">${varDisplayName(varName, catMeta.prefix)}</span>
|
|
182086
|
-
<span class="sb-var-row-ref">${varName}</span>
|
|
182087
|
-
<sp-action-button
|
|
182088
|
-
size="s"
|
|
182089
|
-
quiet
|
|
182090
|
-
class="sb-var-del"
|
|
182091
|
-
style="pointer-events:auto"
|
|
182092
|
-
@click=${() => {
|
|
182093
|
-
transactDoc(activeTab.value, (t) => mutateUpdateStyle(t, [], varName, undefined));
|
|
182094
|
-
}}
|
|
182095
|
-
>
|
|
182096
|
-
<sp-icon-delete slot="icon"></sp-icon-delete>
|
|
182097
|
-
</sp-action-button>
|
|
182098
|
-
</div>
|
|
182099
|
-
` : nothing;
|
|
182100
|
-
const addPreviewTpl = isNew ? html`
|
|
182101
|
-
<div
|
|
182102
|
-
class="sb-var-add-preview"
|
|
182103
|
-
${ref2((el) => {
|
|
182104
|
-
if (!el || !nameField)
|
|
182105
|
-
return;
|
|
182106
|
-
nameField.addEventListener("input", () => {
|
|
182107
|
-
el.textContent = friendlyNameToVar(nameField.value || "", catMeta.prefix);
|
|
182108
|
-
});
|
|
182109
|
-
})}
|
|
182110
|
-
></div>
|
|
182111
|
-
` : nothing;
|
|
182112
|
-
const typePrevTpl = catKey === "font" && varVal ? html`
|
|
182113
|
-
<div class="sb-var-preview">
|
|
182114
|
-
<div class="sb-var-font-preview" style=${styleMap({ fontFamily: varVal })}>
|
|
182115
|
-
The quick brown fox jumps over the lazy dog
|
|
182116
|
-
</div>
|
|
182117
|
-
</div>
|
|
182118
|
-
` : catKey === "size" && varVal ? html`
|
|
182119
|
-
<div class="sb-var-preview">
|
|
182120
|
-
<div class="sb-var-size-track">
|
|
182121
|
-
<div class="sb-var-size-bar" style=${styleMap({ width: varVal })}></div>
|
|
182122
|
-
</div>
|
|
182123
|
-
</div>
|
|
182124
|
-
` : nothing;
|
|
182125
|
-
render2(html`
|
|
182126
|
-
${headerTpl}
|
|
182127
|
-
<div class="sb-var-input-row">${swatchTpl} ${nameColTpl} ${valColTpl} ${actionsTpl}</div>
|
|
182128
|
-
${addPreviewTpl} ${typePrevTpl}
|
|
182129
|
-
`, row);
|
|
182130
|
-
return row;
|
|
182131
|
-
}
|
|
182132
|
-
function createUnitInput(initialValue, { onChange, size = "s" } = {}) {
|
|
182133
|
-
const match2 = String(initialValue).match(/^(-?[\d.]+)\s*(px|em|rem|vw|vh|%|ch|ex|vmin|vmax|pt|cm|mm|in)?$/);
|
|
182134
|
-
let numVal = match2 ? match2[1] : initialValue;
|
|
182135
|
-
let unitVal = match2 ? match2[2] || "px" : "";
|
|
182136
|
-
const isNumeric = !!match2;
|
|
182137
|
-
const wrap4 = document.createElement("div");
|
|
182138
|
-
wrap4.className = "sb-unit-input";
|
|
182139
|
-
wrap4.style.pointerEvents = "auto";
|
|
182140
|
-
let textfield = null;
|
|
182141
|
-
let picker = null;
|
|
182142
|
-
const units = [
|
|
182143
|
-
{ value: "px", label: "px" },
|
|
182144
|
-
{ value: "rem", label: "rem" },
|
|
182145
|
-
{ value: "em", label: "em" },
|
|
182146
|
-
{ value: "%", label: "%" },
|
|
182147
|
-
{ value: "vw", label: "vw" },
|
|
182148
|
-
{ value: "vh", label: "vh" },
|
|
182149
|
-
{ value: "ch", label: "ch" },
|
|
182150
|
-
{ value: "pt", label: "pt" },
|
|
182151
|
-
{ divider: true },
|
|
182152
|
-
{ value: "auto", label: "auto" },
|
|
182153
|
-
{ value: "fit-content", label: "fit-content" }
|
|
182154
|
-
];
|
|
182155
|
-
let debounce;
|
|
182156
|
-
function getValue() {
|
|
182157
|
-
const num = textfield?.value;
|
|
182158
|
-
const unit = picker?.value;
|
|
182159
|
-
if (unit === "auto" || unit === "fit-content")
|
|
182160
|
-
return unit;
|
|
182161
|
-
return num ? `${num}${unit}` : "";
|
|
182162
|
-
}
|
|
182163
|
-
render2(html`
|
|
182164
|
-
<sp-textfield
|
|
182165
|
-
.value=${numVal}
|
|
182166
|
-
size=${size}
|
|
182167
|
-
${ref2((el) => {
|
|
182168
|
-
if (el)
|
|
182169
|
-
textfield = el;
|
|
182170
|
-
})}
|
|
182171
|
-
@input=${() => {
|
|
182172
|
-
clearTimeout(debounce);
|
|
182173
|
-
const raw = textfield?.value?.trim();
|
|
182174
|
-
const looksNumeric = /^-?[\d.]+$/.test(raw || "");
|
|
182175
|
-
if (picker)
|
|
182176
|
-
picker.style.display = looksNumeric ? "" : "none";
|
|
182177
|
-
debounce = setTimeout(() => {
|
|
182178
|
-
if (onChange)
|
|
182179
|
-
onChange(looksNumeric ? `${raw}${picker?.value}` : raw);
|
|
182180
|
-
}, 400);
|
|
182181
|
-
}}
|
|
182182
|
-
></sp-textfield>
|
|
182183
|
-
<sp-picker
|
|
182184
|
-
quiet
|
|
182185
|
-
size=${size}
|
|
182186
|
-
style=${styleMap({ display: isNumeric ? "" : "none" })}
|
|
182187
|
-
${ref2((el) => {
|
|
182188
|
-
if (el) {
|
|
182189
|
-
picker = el;
|
|
182190
|
-
requestAnimationFrame(() => {
|
|
182191
|
-
el.value = unitVal || "px";
|
|
182192
|
-
});
|
|
182193
|
-
}
|
|
182194
|
-
})}
|
|
182195
|
-
@change=${() => {
|
|
182196
|
-
const unit = picker?.value;
|
|
182197
|
-
if (unit === "auto" || unit === "fit-content") {
|
|
182198
|
-
if (textfield)
|
|
182199
|
-
textfield.value = unit;
|
|
182200
|
-
if (picker)
|
|
182201
|
-
picker.style.display = "none";
|
|
182202
|
-
if (onChange)
|
|
182203
|
-
onChange(unit);
|
|
182204
|
-
} else {
|
|
182205
|
-
unitVal = unit;
|
|
182206
|
-
if (onChange)
|
|
182207
|
-
onChange(getValue());
|
|
182208
|
-
}
|
|
182209
|
-
}}
|
|
182210
|
-
>
|
|
182211
|
-
${units.map((u) => u.divider ? html`<sp-menu-divider></sp-menu-divider>` : html`<sp-menu-item value=${u.value}>${u.label}</sp-menu-item>`)}
|
|
182212
|
-
</sp-picker>
|
|
182213
|
-
`, wrap4);
|
|
182214
|
-
return { wrap: wrap4, textfield, picker, getValue };
|
|
182215
|
-
}
|
|
182216
180682
|
function registerStylebookPanelEvents(panel) {
|
|
182217
180683
|
const { canvas, overlayClk } = panel;
|
|
182218
180684
|
overlayClk.addEventListener("click", (e) => {
|
|
@@ -183368,6 +181834,289 @@ function updateForcedPseudoPreview() {
|
|
|
183368
181834
|
// src/browse/browse.js
|
|
183369
181835
|
init_platform();
|
|
183370
181836
|
init_store();
|
|
181837
|
+
|
|
181838
|
+
// src/settings/schema-field-ui.js
|
|
181839
|
+
var FIELD_TYPES = ["string", "number", "boolean", "array", "object", "reference"];
|
|
181840
|
+
var FORMAT_OPTIONS = ["", "image", "date", "color"];
|
|
181841
|
+
function detectFieldType(schema4) {
|
|
181842
|
+
if (schema4.$ref)
|
|
181843
|
+
return "reference";
|
|
181844
|
+
return schema4.type || "string";
|
|
181845
|
+
}
|
|
181846
|
+
function detectFieldFormat(schema4) {
|
|
181847
|
+
if (schema4.type === "array" && schema4.items?.format)
|
|
181848
|
+
return schema4.items.format;
|
|
181849
|
+
return schema4.format || "";
|
|
181850
|
+
}
|
|
181851
|
+
function fieldCardTpl(fieldName, fieldSchema, isRequired, handlers, contentTypeNames = []) {
|
|
181852
|
+
const type = detectFieldType(fieldSchema);
|
|
181853
|
+
const format2 = detectFieldFormat(fieldSchema);
|
|
181854
|
+
const isNested = type === "object";
|
|
181855
|
+
const isRef2 = type === "reference";
|
|
181856
|
+
const nestedProps = fieldSchema.properties || {};
|
|
181857
|
+
const nestedRequired = fieldSchema.required || [];
|
|
181858
|
+
const refTarget = fieldSchema.$ref ? fieldSchema.$ref.replace("#/contentTypes/", "") : "";
|
|
181859
|
+
return html`
|
|
181860
|
+
<div class="schema-field-card">
|
|
181861
|
+
<div class="schema-field-row">
|
|
181862
|
+
<sp-textfield
|
|
181863
|
+
size="s"
|
|
181864
|
+
quiet
|
|
181865
|
+
value=${fieldName}
|
|
181866
|
+
class="schema-field-name-input"
|
|
181867
|
+
@change=${(e) => {
|
|
181868
|
+
const newName = e.target.value.trim();
|
|
181869
|
+
if (newName && newName !== fieldName)
|
|
181870
|
+
handlers.onRename(fieldName, newName);
|
|
181871
|
+
else
|
|
181872
|
+
e.target.value = fieldName;
|
|
181873
|
+
}}
|
|
181874
|
+
@keydown=${(e) => {
|
|
181875
|
+
if (e.key === "Enter")
|
|
181876
|
+
e.target.blur();
|
|
181877
|
+
if (e.key === "Escape") {
|
|
181878
|
+
e.target.value = fieldName;
|
|
181879
|
+
e.target.blur();
|
|
181880
|
+
}
|
|
181881
|
+
}}
|
|
181882
|
+
></sp-textfield>
|
|
181883
|
+
${typePickerTpl(type, (newType) => handlers.onChangeType(fieldName, newType))}
|
|
181884
|
+
${type === "string" || type === "array" ? formatPickerTpl(format2, (f) => {
|
|
181885
|
+
if (handlers.onChangeFormat)
|
|
181886
|
+
handlers.onChangeFormat(fieldName, f);
|
|
181887
|
+
}) : nothing}
|
|
181888
|
+
<sp-switch
|
|
181889
|
+
size="s"
|
|
181890
|
+
?checked=${isRequired}
|
|
181891
|
+
@change=${() => handlers.onToggleRequired(fieldName)}
|
|
181892
|
+
>
|
|
181893
|
+
Req
|
|
181894
|
+
</sp-switch>
|
|
181895
|
+
<sp-action-button
|
|
181896
|
+
size="xs"
|
|
181897
|
+
quiet
|
|
181898
|
+
title="Delete field"
|
|
181899
|
+
@click=${() => handlers.onDelete(fieldName)}
|
|
181900
|
+
>
|
|
181901
|
+
<sp-icon-delete slot="icon"></sp-icon-delete>
|
|
181902
|
+
</sp-action-button>
|
|
181903
|
+
</div>
|
|
181904
|
+
${isRef2 && contentTypeNames.length ? html`
|
|
181905
|
+
<div class="schema-field-ref-target">
|
|
181906
|
+
<sp-picker
|
|
181907
|
+
size="s"
|
|
181908
|
+
label="Target"
|
|
181909
|
+
value=${refTarget}
|
|
181910
|
+
@change=${(e) => {
|
|
181911
|
+
if (handlers.onChangeRefTarget)
|
|
181912
|
+
handlers.onChangeRefTarget(fieldName, e.target.value);
|
|
181913
|
+
}}
|
|
181914
|
+
>
|
|
181915
|
+
${contentTypeNames.map((n2) => html`<sp-menu-item value=${n2}>${n2}</sp-menu-item>`)}
|
|
181916
|
+
</sp-picker>
|
|
181917
|
+
</div>
|
|
181918
|
+
` : nothing}
|
|
181919
|
+
${isNested ? html`
|
|
181920
|
+
<div class="schema-field-nested">
|
|
181921
|
+
${Object.entries(nestedProps).map(([name, sub]) => nestedFieldCardTpl(fieldName, name, sub, nestedRequired.includes(name), handlers))}
|
|
181922
|
+
${nestedAddFieldTpl(fieldName, handlers)}
|
|
181923
|
+
</div>
|
|
181924
|
+
` : nothing}
|
|
181925
|
+
</div>
|
|
181926
|
+
`;
|
|
181927
|
+
}
|
|
181928
|
+
function nestedFieldCardTpl(parentName, childName, childSchema, isRequired, handlers) {
|
|
181929
|
+
const type = detectFieldType(childSchema);
|
|
181930
|
+
const format2 = detectFieldFormat(childSchema);
|
|
181931
|
+
return html`
|
|
181932
|
+
<div class="schema-field-card schema-field-card--nested">
|
|
181933
|
+
<div class="schema-field-row">
|
|
181934
|
+
<sp-textfield
|
|
181935
|
+
size="s"
|
|
181936
|
+
quiet
|
|
181937
|
+
value=${childName}
|
|
181938
|
+
class="schema-field-name-input"
|
|
181939
|
+
@change=${(e) => {
|
|
181940
|
+
const newName = e.target.value.trim();
|
|
181941
|
+
if (newName && newName !== childName && handlers.onRenameNested) {
|
|
181942
|
+
handlers.onRenameNested(parentName, childName, newName);
|
|
181943
|
+
} else {
|
|
181944
|
+
e.target.value = childName;
|
|
181945
|
+
}
|
|
181946
|
+
}}
|
|
181947
|
+
@keydown=${(e) => {
|
|
181948
|
+
if (e.key === "Enter")
|
|
181949
|
+
e.target.blur();
|
|
181950
|
+
if (e.key === "Escape") {
|
|
181951
|
+
e.target.value = childName;
|
|
181952
|
+
e.target.blur();
|
|
181953
|
+
}
|
|
181954
|
+
}}
|
|
181955
|
+
></sp-textfield>
|
|
181956
|
+
${typePickerTpl(type, (newType) => {
|
|
181957
|
+
if (handlers.onChangeNestedType)
|
|
181958
|
+
handlers.onChangeNestedType(parentName, childName, newType);
|
|
181959
|
+
})}
|
|
181960
|
+
${type === "string" || type === "array" ? formatPickerTpl(format2, (f) => {
|
|
181961
|
+
if (handlers.onChangeNestedFormat)
|
|
181962
|
+
handlers.onChangeNestedFormat(parentName, childName, f);
|
|
181963
|
+
}) : nothing}
|
|
181964
|
+
<sp-switch
|
|
181965
|
+
size="s"
|
|
181966
|
+
?checked=${isRequired}
|
|
181967
|
+
@change=${() => {
|
|
181968
|
+
if (handlers.onToggleNestedRequired)
|
|
181969
|
+
handlers.onToggleNestedRequired(parentName, childName);
|
|
181970
|
+
}}
|
|
181971
|
+
>
|
|
181972
|
+
Req
|
|
181973
|
+
</sp-switch>
|
|
181974
|
+
<sp-action-button
|
|
181975
|
+
size="xs"
|
|
181976
|
+
quiet
|
|
181977
|
+
title="Delete field"
|
|
181978
|
+
@click=${() => {
|
|
181979
|
+
if (handlers.onDeleteNested)
|
|
181980
|
+
handlers.onDeleteNested(parentName, childName);
|
|
181981
|
+
}}
|
|
181982
|
+
>
|
|
181983
|
+
<sp-icon-delete slot="icon"></sp-icon-delete>
|
|
181984
|
+
</sp-action-button>
|
|
181985
|
+
</div>
|
|
181986
|
+
</div>
|
|
181987
|
+
`;
|
|
181988
|
+
}
|
|
181989
|
+
function nestedAddFieldTpl(parentName, handlers) {
|
|
181990
|
+
return html`
|
|
181991
|
+
<div class="schema-nested-add">
|
|
181992
|
+
<sp-textfield
|
|
181993
|
+
size="s"
|
|
181994
|
+
placeholder="field name"
|
|
181995
|
+
class="schema-nested-add-name"
|
|
181996
|
+
@keydown=${(e) => {
|
|
181997
|
+
if (e.key === "Enter") {
|
|
181998
|
+
const row = e.target.closest(".schema-nested-add");
|
|
181999
|
+
const name = e.target.value.trim();
|
|
182000
|
+
const typePicker = row?.querySelector("sp-picker");
|
|
182001
|
+
const type = typePicker?.value || "string";
|
|
182002
|
+
if (name && handlers.onAddNestedField) {
|
|
182003
|
+
handlers.onAddNestedField(parentName, { name, type, required: false });
|
|
182004
|
+
e.target.value = "";
|
|
182005
|
+
}
|
|
182006
|
+
}
|
|
182007
|
+
}}
|
|
182008
|
+
></sp-textfield>
|
|
182009
|
+
${typePickerTpl("string", () => {})}
|
|
182010
|
+
<sp-action-button
|
|
182011
|
+
size="xs"
|
|
182012
|
+
quiet
|
|
182013
|
+
title="Add nested field"
|
|
182014
|
+
@click=${(e) => {
|
|
182015
|
+
const row = e.target.closest(".schema-nested-add");
|
|
182016
|
+
const nameInput = row?.querySelector(".schema-nested-add-name");
|
|
182017
|
+
const typePicker = row?.querySelector("sp-picker");
|
|
182018
|
+
const name = nameInput?.value?.trim();
|
|
182019
|
+
const type = typePicker?.value || "string";
|
|
182020
|
+
if (name && handlers.onAddNestedField) {
|
|
182021
|
+
handlers.onAddNestedField(parentName, { name, type, required: false });
|
|
182022
|
+
nameInput.value = "";
|
|
182023
|
+
}
|
|
182024
|
+
}}
|
|
182025
|
+
>
|
|
182026
|
+
<sp-icon-add slot="icon"></sp-icon-add>
|
|
182027
|
+
</sp-action-button>
|
|
182028
|
+
</div>
|
|
182029
|
+
`;
|
|
182030
|
+
}
|
|
182031
|
+
function typePickerTpl(value2, onChange) {
|
|
182032
|
+
return html`
|
|
182033
|
+
<sp-picker
|
|
182034
|
+
size="s"
|
|
182035
|
+
label="Type"
|
|
182036
|
+
value=${value2}
|
|
182037
|
+
@change=${(e) => onChange(e.target.value)}
|
|
182038
|
+
>
|
|
182039
|
+
${FIELD_TYPES.map((t) => html`<sp-menu-item value=${t}>${t}</sp-menu-item>`)}
|
|
182040
|
+
</sp-picker>
|
|
182041
|
+
`;
|
|
182042
|
+
}
|
|
182043
|
+
function formatPickerTpl(value2, onChange) {
|
|
182044
|
+
return html`
|
|
182045
|
+
<sp-picker
|
|
182046
|
+
size="s"
|
|
182047
|
+
label="Format"
|
|
182048
|
+
value=${value2}
|
|
182049
|
+
@change=${(e) => onChange(e.target.value)}
|
|
182050
|
+
>
|
|
182051
|
+
${FORMAT_OPTIONS.map((f) => html`<sp-menu-item value=${f}>${f || "(none)"}</sp-menu-item>`)}
|
|
182052
|
+
</sp-picker>
|
|
182053
|
+
`;
|
|
182054
|
+
}
|
|
182055
|
+
function addFieldFormTpl(state, handlers) {
|
|
182056
|
+
return html`
|
|
182057
|
+
<div class="schema-add-field">
|
|
182058
|
+
<sp-textfield
|
|
182059
|
+
size="s"
|
|
182060
|
+
placeholder="Field name"
|
|
182061
|
+
.value=${state.name}
|
|
182062
|
+
@input=${(e) => handlers.onInput("name", e.target.value)}
|
|
182063
|
+
@keydown=${(e) => {
|
|
182064
|
+
if (e.key === "Enter")
|
|
182065
|
+
handlers.onConfirm();
|
|
182066
|
+
if (e.key === "Escape")
|
|
182067
|
+
handlers.onCancel();
|
|
182068
|
+
}}
|
|
182069
|
+
></sp-textfield>
|
|
182070
|
+
${typePickerTpl(state.type, (t) => handlers.onInput("type", t))}
|
|
182071
|
+
${state.type === "string" || state.type === "array" ? formatPickerTpl(state.format || "", (f) => handlers.onInput("format", f)) : nothing}
|
|
182072
|
+
<sp-switch
|
|
182073
|
+
size="s"
|
|
182074
|
+
?checked=${state.required}
|
|
182075
|
+
@change=${(e) => handlers.onInput("required", e.target.checked)}
|
|
182076
|
+
>
|
|
182077
|
+
Required
|
|
182078
|
+
</sp-switch>
|
|
182079
|
+
<sp-action-button size="s" @click=${handlers.onConfirm}>Add</sp-action-button>
|
|
182080
|
+
<sp-action-button size="s" quiet @click=${handlers.onCancel}>Cancel</sp-action-button>
|
|
182081
|
+
</div>
|
|
182082
|
+
`;
|
|
182083
|
+
}
|
|
182084
|
+
function schemaForType(type, format2) {
|
|
182085
|
+
switch (type) {
|
|
182086
|
+
case "number":
|
|
182087
|
+
return { type: "number" };
|
|
182088
|
+
case "boolean":
|
|
182089
|
+
return { type: "boolean" };
|
|
182090
|
+
case "array":
|
|
182091
|
+
return format2 ? { type: "array", items: { type: "string", format: format2 } } : { type: "array", items: { type: "string" } };
|
|
182092
|
+
case "object":
|
|
182093
|
+
return { type: "object", properties: {}, required: [] };
|
|
182094
|
+
case "reference":
|
|
182095
|
+
return { $ref: "#/contentTypes/" };
|
|
182096
|
+
default:
|
|
182097
|
+
return format2 ? { type: "string", format: format2 } : { type: "string" };
|
|
182098
|
+
}
|
|
182099
|
+
}
|
|
182100
|
+
function yamlDefault(type, format2) {
|
|
182101
|
+
if (format2 === "date")
|
|
182102
|
+
return new Date().toISOString().split("T")[0];
|
|
182103
|
+
if (format2 === "image")
|
|
182104
|
+
return '""';
|
|
182105
|
+
switch (type) {
|
|
182106
|
+
case "boolean":
|
|
182107
|
+
return "false";
|
|
182108
|
+
case "number":
|
|
182109
|
+
return "0";
|
|
182110
|
+
case "array":
|
|
182111
|
+
return "[]";
|
|
182112
|
+
case "object":
|
|
182113
|
+
return "{}";
|
|
182114
|
+
default:
|
|
182115
|
+
return '""';
|
|
182116
|
+
}
|
|
182117
|
+
}
|
|
182118
|
+
|
|
182119
|
+
// src/browse/browse.js
|
|
183371
182120
|
var CATEGORIES = [
|
|
183372
182121
|
{ key: "all", label: "All" },
|
|
183373
182122
|
{ key: "pages", label: "Pages", dir: "pages" },
|
|
@@ -183405,6 +182154,19 @@ function extOf(name) {
|
|
|
183405
182154
|
const dot = name.lastIndexOf(".");
|
|
183406
182155
|
return dot > 0 ? name.slice(dot).toLowerCase() : "";
|
|
183407
182156
|
}
|
|
182157
|
+
var IMAGE_EXTENSIONS2 = new Set([
|
|
182158
|
+
".jpg",
|
|
182159
|
+
".jpeg",
|
|
182160
|
+
".png",
|
|
182161
|
+
".gif",
|
|
182162
|
+
".svg",
|
|
182163
|
+
".webp",
|
|
182164
|
+
".avif",
|
|
182165
|
+
".ico"
|
|
182166
|
+
]);
|
|
182167
|
+
function isImage(ext) {
|
|
182168
|
+
return IMAGE_EXTENSIONS2.has(ext);
|
|
182169
|
+
}
|
|
183408
182170
|
function categoryFor(dir, ext) {
|
|
183409
182171
|
if (ext && MEDIA_EXTENSIONS2.has(ext))
|
|
183410
182172
|
return "Media";
|
|
@@ -183662,9 +182424,12 @@ async function renderBrowse(container, ctx) {
|
|
|
183662
182424
|
<sp-table-row
|
|
183663
182425
|
value=${f.path}
|
|
183664
182426
|
class="browse-row"
|
|
183665
|
-
|
|
182427
|
+
style=${isImage(f.ext) ? "cursor:default" : ""}
|
|
182428
|
+
@click=${isImage(f.ext) ? nothing : () => ctx.openFile(f.path)}
|
|
183666
182429
|
>
|
|
183667
|
-
<sp-table-cell class="browse-name-cell"
|
|
182430
|
+
<sp-table-cell class="browse-name-cell"
|
|
182431
|
+
>${isImage(f.ext) ? html`<img class="browse-thumb" src="/${f.path}" />` : nothing}${f.name}</sp-table-cell
|
|
182432
|
+
>
|
|
183668
182433
|
<sp-table-cell>${f.category}</sp-table-cell>
|
|
183669
182434
|
<sp-table-cell>${f.type}</sp-table-cell>
|
|
183670
182435
|
<sp-table-cell class="browse-path-cell">${f.path}</sp-table-cell>
|
|
@@ -183892,7 +182657,7 @@ function _flush() {
|
|
|
183892
182657
|
const { selection, hover } = tab.session;
|
|
183893
182658
|
const { stylebookTab } = tab.session.ui;
|
|
183894
182659
|
const canvasMode = _ctx9.getCanvasMode();
|
|
183895
|
-
if (canvasMode !== "design" && canvasMode !== "edit" && canvasMode !== "
|
|
182660
|
+
if (canvasMode !== "design" && canvasMode !== "edit" && canvasMode !== "stylebook") {
|
|
183896
182661
|
for (const p of canvasPanels) {
|
|
183897
182662
|
render2(nothing, p.overlay);
|
|
183898
182663
|
p.overlayClk.style.pointerEvents = "none";
|
|
@@ -183903,7 +182668,7 @@ function _flush() {
|
|
|
183903
182668
|
}
|
|
183904
182669
|
return;
|
|
183905
182670
|
}
|
|
183906
|
-
if (canvasMode === "
|
|
182671
|
+
if (canvasMode === "stylebook") {
|
|
183907
182672
|
const enable = stylebookTab === "elements";
|
|
183908
182673
|
for (const p of canvasPanels) {
|
|
183909
182674
|
p.overlayClk.style.pointerEvents = enable ? "" : "none";
|
|
@@ -184048,7 +182813,7 @@ function renderCanvas() {
|
|
|
184048
182813
|
});
|
|
184049
182814
|
return;
|
|
184050
182815
|
}
|
|
184051
|
-
if (canvasMode === "
|
|
182816
|
+
if (canvasMode === "stylebook") {
|
|
184052
182817
|
renderStylebookMode({
|
|
184053
182818
|
canvasPanelTemplate,
|
|
184054
182819
|
applyTransform,
|
|
@@ -184355,6 +183120,48 @@ init_store();
|
|
|
184355
183120
|
init_platform();
|
|
184356
183121
|
init_components();
|
|
184357
183122
|
init_workspace();
|
|
183123
|
+
|
|
183124
|
+
// src/recent-projects.js
|
|
183125
|
+
var STORAGE_KEY = "jx-studio-recent-projects";
|
|
183126
|
+
var FILES_STORAGE_KEY = "jx-studio-recent-files";
|
|
183127
|
+
var MAX_RECENT = 8;
|
|
183128
|
+
var MAX_RECENT_FILES = 10;
|
|
183129
|
+
function getRecentProjects() {
|
|
183130
|
+
try {
|
|
183131
|
+
const raw = localStorage.getItem(STORAGE_KEY);
|
|
183132
|
+
if (!raw)
|
|
183133
|
+
return [];
|
|
183134
|
+
return JSON.parse(raw).sort((a, b) => b.timestamp - a.timestamp);
|
|
183135
|
+
} catch {
|
|
183136
|
+
return [];
|
|
183137
|
+
}
|
|
183138
|
+
}
|
|
183139
|
+
function addRecentProject(name, root2) {
|
|
183140
|
+
const projects = getRecentProjects().filter((p) => p.root !== root2);
|
|
183141
|
+
projects.unshift({ name, root: root2, timestamp: Date.now() });
|
|
183142
|
+
if (projects.length > MAX_RECENT)
|
|
183143
|
+
projects.length = MAX_RECENT;
|
|
183144
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(projects));
|
|
183145
|
+
}
|
|
183146
|
+
function getRecentFiles() {
|
|
183147
|
+
try {
|
|
183148
|
+
const raw = localStorage.getItem(FILES_STORAGE_KEY);
|
|
183149
|
+
if (!raw)
|
|
183150
|
+
return [];
|
|
183151
|
+
return JSON.parse(raw).sort((a, b) => b.timestamp - a.timestamp);
|
|
183152
|
+
} catch {
|
|
183153
|
+
return [];
|
|
183154
|
+
}
|
|
183155
|
+
}
|
|
183156
|
+
function trackRecentFile(file) {
|
|
183157
|
+
const recent = getRecentFiles().filter((f) => f.path !== file.path);
|
|
183158
|
+
recent.unshift({ path: file.path, name: file.name, timestamp: Date.now() });
|
|
183159
|
+
if (recent.length > MAX_RECENT_FILES)
|
|
183160
|
+
recent.length = MAX_RECENT_FILES;
|
|
183161
|
+
localStorage.setItem(FILES_STORAGE_KEY, JSON.stringify(recent));
|
|
183162
|
+
}
|
|
183163
|
+
|
|
183164
|
+
// src/files/files.js
|
|
184358
183165
|
var fileIconMap = {
|
|
184359
183166
|
"sp-icon-folder-open": html`<sp-icon-folder-open></sp-icon-folder-open>`,
|
|
184360
183167
|
"sp-icon-folder": html`<sp-icon-folder></sp-icon-folder>`,
|
|
@@ -184440,6 +183247,7 @@ async function openProject({ renderActivityBar, renderLeftPanel }) {
|
|
|
184440
183247
|
}
|
|
184441
183248
|
projectState.projectDirs = foundDirs;
|
|
184442
183249
|
view.leftTab = "files";
|
|
183250
|
+
addRecentProject(projectState.name, projectState.projectRoot);
|
|
184443
183251
|
renderActivityBar();
|
|
184444
183252
|
renderLeftPanel();
|
|
184445
183253
|
statusMessage(`Opened project: ${projectState.name}`);
|
|
@@ -184808,6 +183616,12 @@ async function openFileInTab(path2) {
|
|
|
184808
183616
|
sourceFormat: path2.endsWith(".md") ? "md" : null
|
|
184809
183617
|
});
|
|
184810
183618
|
projectState.selectedPath = path2;
|
|
183619
|
+
trackRecentFile({ path: path2, name: path2.split("/").pop() || path2 });
|
|
183620
|
+
if (path2 === "project.json") {
|
|
183621
|
+
const tab = activeTab.value;
|
|
183622
|
+
if (tab)
|
|
183623
|
+
tab.session.ui.canvasMode = "stylebook";
|
|
183624
|
+
}
|
|
184811
183625
|
statusMessage(`Opened ${path2.split("/").pop()}`);
|
|
184812
183626
|
} catch (e) {
|
|
184813
183627
|
statusMessage(`Error: ${e.message}`);
|
|
@@ -185771,6 +184585,16 @@ function createDevServerPlatform() {
|
|
|
185771
184585
|
} catch {}
|
|
185772
184586
|
return null;
|
|
185773
184587
|
},
|
|
184588
|
+
async searchFiles(query) {
|
|
184589
|
+
const glob = `**/*${query}*.{json,md}`;
|
|
184590
|
+
const res = await fetch(`/__studio/files?dir=${encodeURIComponent(serverPath("."))}&glob=${encodeURIComponent(glob)}`);
|
|
184591
|
+
if (!res.ok)
|
|
184592
|
+
return [];
|
|
184593
|
+
const entries2 = await res.json();
|
|
184594
|
+
for (const e of entries2)
|
|
184595
|
+
e.path = stripRoot(e.path);
|
|
184596
|
+
return entries2;
|
|
184597
|
+
},
|
|
185774
184598
|
async fetchPluginSchema(src, prototype, base2) {
|
|
185775
184599
|
const params = new URLSearchParams({ src });
|
|
185776
184600
|
if (prototype)
|
|
@@ -210032,6 +208856,67 @@ class IconRemove extends IconBase {
|
|
|
210032
208856
|
}
|
|
210033
208857
|
}
|
|
210034
208858
|
|
|
208859
|
+
// ../../node_modules/@spectrum-web-components/icons-workflow/src/elements/IconFullScreen.js
|
|
208860
|
+
init_index_dev();
|
|
208861
|
+
|
|
208862
|
+
// ../../node_modules/@spectrum-web-components/icons-workflow/src/icons-s2/FullScreen.js
|
|
208863
|
+
var FullScreenIcon = ({ width: l = 24, height: r8 = 24, hidden: t15 = false, title: c6 = "Full Screen" } = {}) => tag6`<svg
|
|
208864
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
208865
|
+
width="${l}"
|
|
208866
|
+
height="${r8}"
|
|
208867
|
+
viewBox="0 0 20 20"
|
|
208868
|
+
aria-hidden=${t15 ? "true" : "false"}
|
|
208869
|
+
role="img"
|
|
208870
|
+
fill="currentColor"
|
|
208871
|
+
aria-label="${c6}"
|
|
208872
|
+
>
|
|
208873
|
+
<path
|
|
208874
|
+
d="M12.75,14.93652h-5.5c-1.24072,0-2.25-1.00928-2.25-2.25v-5.5c0-1.24072,1.00928-2.25,2.25-2.25h5.5c1.24072,0,2.25,1.00928,2.25,2.25v5.5c0,1.24072-1.00928,2.25-2.25,2.25ZM7.25,6.43652c-.41357,0-.75.33643-.75.75v5.5c0,.41357.33643.75.75.75h5.5c.41357,0,.75-.33643.75-.75v-5.5c0-.41357-.33643-.75-.75-.75h-5.5Z"
|
|
208875
|
+
fill="currentColor"
|
|
208876
|
+
/>
|
|
208877
|
+
<path
|
|
208878
|
+
d="M4.5,19h-2.25c-.68945,0-1.25-.56055-1.25-1.25v-2.25c0-.41406.33594-.75.75-.75s.75.33594.75.75v2h2c.41406,0,.75.33594.75.75s-.33594.75-.75.75Z"
|
|
208879
|
+
fill="currentColor"
|
|
208880
|
+
/>
|
|
208881
|
+
<path
|
|
208882
|
+
d="M17.75,19h-2.25c-.41406,0-.75-.33594-.75-.75s.33594-.75.75-.75h2v-2c0-.41406.33594-.75.75-.75s.75.33594.75.75v2.25c0,.68945-.56055,1.25-1.25,1.25Z"
|
|
208883
|
+
fill="currentColor"
|
|
208884
|
+
stroke-width="0"
|
|
208885
|
+
/>
|
|
208886
|
+
<path
|
|
208887
|
+
d="M18.25,5.25c-.41406,0-.75-.33594-.75-.75v-2h-2c-.41406,0-.75-.33594-.75-.75s.33594-.75.75-.75h2.25c.68945,0,1.25.56055,1.25,1.25v2.25c0,.41406-.33594.75-.75.75ZM17.75,2.5h.00977-.00977Z"
|
|
208888
|
+
fill="currentColor"
|
|
208889
|
+
/>
|
|
208890
|
+
<path
|
|
208891
|
+
d="M1.75,5.25c-.41406,0-.75-.33594-.75-.75v-2.25c0-.68945.56055-1.25,1.25-1.25h2.25c.41406,0,.75.33594.75.75s-.33594.75-.75.75h-2v2c0,.41406-.33594.75-.75.75Z"
|
|
208892
|
+
fill="currentColor"
|
|
208893
|
+
/>
|
|
208894
|
+
</svg>`;
|
|
208895
|
+
|
|
208896
|
+
// ../../node_modules/@spectrum-web-components/icons-workflow/src/icons/FullScreen.js
|
|
208897
|
+
var FullScreenIcon2 = ({ width: a5 = 24, height: e20 = 24, hidden: t15 = false, title: r8 = "Full Screen" } = {}) => tag6`<svg
|
|
208898
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
208899
|
+
height="${e20}"
|
|
208900
|
+
viewBox="0 0 36 36"
|
|
208901
|
+
width="${a5}"
|
|
208902
|
+
aria-hidden=${t15 ? "true" : "false"}
|
|
208903
|
+
role="img"
|
|
208904
|
+
fill="currentColor"
|
|
208905
|
+
aria-label="${r8}"
|
|
208906
|
+
>
|
|
208907
|
+
<path
|
|
208908
|
+
d="M32 24.5V30h-5.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5H34v-7.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5ZM4 30v-5.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5V32h7.5a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5ZM26 4.5v1a.5.5 0 0 0 .5.5H32v5.5a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5V4h-7.5a.5.5 0 0 0-.5.5ZM4 6h5.5a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5H2v7.5a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5Z"
|
|
208909
|
+
/>
|
|
208910
|
+
<rect height="16" rx=".5" ry=".5" width="20" x="8" y="10" />
|
|
208911
|
+
</svg>`;
|
|
208912
|
+
|
|
208913
|
+
// ../../node_modules/@spectrum-web-components/icons-workflow/src/elements/IconFullScreen.js
|
|
208914
|
+
class IconFullScreen extends IconBase {
|
|
208915
|
+
render() {
|
|
208916
|
+
return setCustomTemplateLiteralTag2(html8), this.spectrumVersion === 2 ? FullScreenIcon({ hidden: !this.label, title: this.label }) : FullScreenIcon2({ hidden: !this.label, title: this.label });
|
|
208917
|
+
}
|
|
208918
|
+
}
|
|
208919
|
+
|
|
210035
208920
|
// ../../node_modules/@spectrum-web-components/icons-workflow/src/elements/IconViewColumn.js
|
|
210036
208921
|
init_index_dev();
|
|
210037
208922
|
|
|
@@ -210832,6 +209717,113 @@ class JxValueSelector extends LitElement {
|
|
|
210832
209717
|
init_lit();
|
|
210833
209718
|
init_store();
|
|
210834
209719
|
init_workspace();
|
|
209720
|
+
|
|
209721
|
+
// src/utils/studio-utils.js
|
|
209722
|
+
function camelToKebab2(str) {
|
|
209723
|
+
return str.replace(/[A-Z]/g, (c6) => "-" + c6.toLowerCase());
|
|
209724
|
+
}
|
|
209725
|
+
function camelToLabel(prop) {
|
|
209726
|
+
return prop.replace(/([A-Z])/g, " $1").replace(/^./, (c6) => c6.toUpperCase());
|
|
209727
|
+
}
|
|
209728
|
+
function kebabToLabel(val) {
|
|
209729
|
+
return val.replace(/(^|-)(\w)/g, (_, sep2, c6) => (sep2 ? " " : "") + c6.toUpperCase());
|
|
209730
|
+
}
|
|
209731
|
+
function propLabel(entry, prop) {
|
|
209732
|
+
return entry?.$label || camelToLabel(prop);
|
|
209733
|
+
}
|
|
209734
|
+
function attrLabel(entry, attr) {
|
|
209735
|
+
if (entry?.$label)
|
|
209736
|
+
return entry.$label;
|
|
209737
|
+
if (attr.includes("-"))
|
|
209738
|
+
return attr.replace(/(^|-)(\w)/g, (_, sep2, c6) => (sep2 ? " " : "") + c6.toUpperCase());
|
|
209739
|
+
return camelToLabel(attr);
|
|
209740
|
+
}
|
|
209741
|
+
function abbreviateValue(val) {
|
|
209742
|
+
const map6 = {
|
|
209743
|
+
inline: "inl",
|
|
209744
|
+
"inline-block": "i-blk",
|
|
209745
|
+
"inline-flex": "i-flx",
|
|
209746
|
+
"inline-grid": "i-grd",
|
|
209747
|
+
contents: "cnt",
|
|
209748
|
+
"flow-root": "flow",
|
|
209749
|
+
nowrap: "no-wr",
|
|
209750
|
+
"wrap-reverse": "wr-rev",
|
|
209751
|
+
"flex-start": "start",
|
|
209752
|
+
"flex-end": "end",
|
|
209753
|
+
"space-between": "betw",
|
|
209754
|
+
"space-around": "arnd",
|
|
209755
|
+
"space-evenly": "even",
|
|
209756
|
+
stretch: "str",
|
|
209757
|
+
baseline: "base",
|
|
209758
|
+
normal: "norm",
|
|
209759
|
+
"row-reverse": "row-r",
|
|
209760
|
+
"column-reverse": "col-r",
|
|
209761
|
+
column: "col"
|
|
209762
|
+
};
|
|
209763
|
+
return map6[val] || val;
|
|
209764
|
+
}
|
|
209765
|
+
function inferInputType(entry) {
|
|
209766
|
+
if (entry.$shorthand === true)
|
|
209767
|
+
return "shorthand";
|
|
209768
|
+
if (entry.$input === "button-group")
|
|
209769
|
+
return "button-group";
|
|
209770
|
+
if (entry.$input === "media")
|
|
209771
|
+
return "media";
|
|
209772
|
+
if (entry.format === "color")
|
|
209773
|
+
return "color";
|
|
209774
|
+
if (entry.format === "uri-reference")
|
|
209775
|
+
return "media";
|
|
209776
|
+
if (entry.$units !== undefined)
|
|
209777
|
+
return "number-unit";
|
|
209778
|
+
if (entry.type === "number")
|
|
209779
|
+
return "number";
|
|
209780
|
+
if (Array.isArray(entry.enum))
|
|
209781
|
+
return "select";
|
|
209782
|
+
if (Array.isArray(entry.examples) || Array.isArray(entry.presets))
|
|
209783
|
+
return "combobox";
|
|
209784
|
+
return "text";
|
|
209785
|
+
}
|
|
209786
|
+
function findContentTypeSchema(documentPath, projectConfig) {
|
|
209787
|
+
if (!documentPath || !projectConfig?.contentTypes)
|
|
209788
|
+
return null;
|
|
209789
|
+
for (const [name, def3] of Object.entries(projectConfig.contentTypes)) {
|
|
209790
|
+
if (!def3.source || !def3.schema)
|
|
209791
|
+
continue;
|
|
209792
|
+
const src = def3.source.replace(/^\.\//, "");
|
|
209793
|
+
const dir = src.split("/")[0];
|
|
209794
|
+
const ext = src.includes("*.md") ? ".md" : src.includes("*.json") ? ".json" : src.includes("*.csv") ? ".csv" : null;
|
|
209795
|
+
if (documentPath.startsWith(dir + "/") && (!ext || documentPath.endsWith(ext))) {
|
|
209796
|
+
return { name, schema: def3.schema };
|
|
209797
|
+
}
|
|
209798
|
+
}
|
|
209799
|
+
return null;
|
|
209800
|
+
}
|
|
209801
|
+
function friendlyNameToVar(name, prefix) {
|
|
209802
|
+
const slug = name.trim().toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
209803
|
+
if (!slug)
|
|
209804
|
+
return "";
|
|
209805
|
+
return `${prefix}${slug}`;
|
|
209806
|
+
}
|
|
209807
|
+
function varDisplayName(varName, prefix) {
|
|
209808
|
+
return varName.replace(new RegExp(`^${prefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`), "").replace(/^--/, "").replace(/-/g, " ").replace(/\b\w/g, (c6) => c6.toUpperCase()) || varName;
|
|
209809
|
+
}
|
|
209810
|
+
function parseCemType(typeText) {
|
|
209811
|
+
if (!typeText)
|
|
209812
|
+
return { kind: "text" };
|
|
209813
|
+
const t15 = typeText.trim().replace(/\s*\|\s*undefined\b/g, "").trim();
|
|
209814
|
+
if (t15 === "boolean")
|
|
209815
|
+
return { kind: "boolean" };
|
|
209816
|
+
if (t15 === "number")
|
|
209817
|
+
return { kind: "number" };
|
|
209818
|
+
const enumMatch = t15.match(/^'[^']*'(\s*\|\s*'[^']*')+$/);
|
|
209819
|
+
if (enumMatch) {
|
|
209820
|
+
const options = [...t15.matchAll(/'([^']*)'/g)].map((m3) => m3[1]);
|
|
209821
|
+
return { kind: "combobox", options };
|
|
209822
|
+
}
|
|
209823
|
+
return { kind: "text" };
|
|
209824
|
+
}
|
|
209825
|
+
|
|
209826
|
+
// src/ui/color-selector.js
|
|
210835
209827
|
function getColorVars() {
|
|
210836
209828
|
const style2 = getEffectiveStyle(activeTab.value?.doc.document?.style);
|
|
210837
209829
|
if (!style2)
|
|
@@ -211157,6 +210149,7 @@ var components = [
|
|
|
211157
210149
|
["sp-icon-text-baseline-shift", IconTextBaselineShift],
|
|
211158
210150
|
["sp-icon-flip-vertical", IconFlipVertical],
|
|
211159
210151
|
["sp-icon-remove", IconRemove],
|
|
210152
|
+
["sp-icon-full-screen", IconFullScreen],
|
|
211160
210153
|
["sp-icon-download", IconDownload],
|
|
211161
210154
|
["sp-icon-checkmark", IconCheckmark],
|
|
211162
210155
|
["sp-icon-view-column", IconViewColumn],
|
|
@@ -211185,14 +210178,14 @@ Theme.registerThemeFragment("dark", "color", theme_dark_css_default);
|
|
|
211185
210178
|
Theme.registerThemeFragment("medium", "scale", scale_medium_css_default);
|
|
211186
210179
|
|
|
211187
210180
|
// src/ui/panel-resize.js
|
|
211188
|
-
var
|
|
210181
|
+
var STORAGE_KEY2 = "jx-studio-panel-widths";
|
|
211189
210182
|
var MIN_WIDTH = 160;
|
|
211190
210183
|
var MAX_RATIO = 0.5;
|
|
211191
210184
|
var DEFAULT_LEFT = 240;
|
|
211192
210185
|
var DEFAULT_RIGHT = 280;
|
|
211193
210186
|
var root2 = document.documentElement;
|
|
211194
210187
|
try {
|
|
211195
|
-
const saved = JSON.parse(localStorage.getItem(
|
|
210188
|
+
const saved = JSON.parse(localStorage.getItem(STORAGE_KEY2) || "{}");
|
|
211196
210189
|
if (saved.left)
|
|
211197
210190
|
root2.style.setProperty("--panel-w-left", `${saved.left}px`);
|
|
211198
210191
|
if (saved.right)
|
|
@@ -211238,7 +210231,7 @@ function persistWidths() {
|
|
|
211238
210231
|
const left = parseInt(getComputedStyle(root2).getPropertyValue("--panel-w-left")) || DEFAULT_LEFT;
|
|
211239
210232
|
const right = parseInt(getComputedStyle(root2).getPropertyValue("--panel-w-right")) || DEFAULT_RIGHT;
|
|
211240
210233
|
try {
|
|
211241
|
-
localStorage.setItem(
|
|
210234
|
+
localStorage.setItem(STORAGE_KEY2, JSON.stringify({ left, right }));
|
|
211242
210235
|
} catch {}
|
|
211243
210236
|
}
|
|
211244
210237
|
var resizeLeft = document.getElementById("resize-left");
|
|
@@ -211251,11 +210244,162 @@ if (resizeRight)
|
|
|
211251
210244
|
// src/editor/shortcuts.js
|
|
211252
210245
|
init_store();
|
|
211253
210246
|
init_workspace();
|
|
210247
|
+
|
|
210248
|
+
// src/panels/quick-search.js
|
|
210249
|
+
init_platform();
|
|
210250
|
+
var _open = false;
|
|
210251
|
+
var _query = "";
|
|
210252
|
+
var _results = [];
|
|
210253
|
+
var _selectedIndex = 0;
|
|
210254
|
+
var _debounceTimer = 0;
|
|
210255
|
+
var _container = null;
|
|
210256
|
+
function initQuickSearch() {
|
|
210257
|
+
_container = document.createElement("div");
|
|
210258
|
+
_container.style.display = "contents";
|
|
210259
|
+
(document.querySelector("sp-theme") || document.body).appendChild(_container);
|
|
210260
|
+
}
|
|
210261
|
+
function openQuickSearch() {
|
|
210262
|
+
_open = true;
|
|
210263
|
+
_query = "";
|
|
210264
|
+
_results = [];
|
|
210265
|
+
_selectedIndex = 0;
|
|
210266
|
+
renderOverlay();
|
|
210267
|
+
requestAnimationFrame(() => {
|
|
210268
|
+
const input = _container?.querySelector(".quick-search-input");
|
|
210269
|
+
if (input)
|
|
210270
|
+
input.focus();
|
|
210271
|
+
});
|
|
210272
|
+
}
|
|
210273
|
+
function closeQuickSearch() {
|
|
210274
|
+
_open = false;
|
|
210275
|
+
renderOverlay();
|
|
210276
|
+
}
|
|
210277
|
+
async function doSearch(query3) {
|
|
210278
|
+
if (!query3.trim()) {
|
|
210279
|
+
_results = [];
|
|
210280
|
+
_selectedIndex = 0;
|
|
210281
|
+
renderOverlay();
|
|
210282
|
+
return;
|
|
210283
|
+
}
|
|
210284
|
+
try {
|
|
210285
|
+
const platform4 = getPlatform();
|
|
210286
|
+
_results = await platform4.searchFiles(query3.trim().toLowerCase());
|
|
210287
|
+
_selectedIndex = 0;
|
|
210288
|
+
renderOverlay();
|
|
210289
|
+
} catch {
|
|
210290
|
+
_results = [];
|
|
210291
|
+
renderOverlay();
|
|
210292
|
+
}
|
|
210293
|
+
}
|
|
210294
|
+
function onInput(e20) {
|
|
210295
|
+
_query = e20.target.value;
|
|
210296
|
+
clearTimeout(_debounceTimer);
|
|
210297
|
+
_debounceTimer = setTimeout(() => doSearch(_query), 150);
|
|
210298
|
+
renderOverlay();
|
|
210299
|
+
}
|
|
210300
|
+
function onKeydown2(e20) {
|
|
210301
|
+
const items = _query.trim() ? _results : getRecentFiles();
|
|
210302
|
+
switch (e20.key) {
|
|
210303
|
+
case "ArrowDown":
|
|
210304
|
+
e20.preventDefault();
|
|
210305
|
+
_selectedIndex = Math.min(_selectedIndex + 1, items.length - 1);
|
|
210306
|
+
renderOverlay();
|
|
210307
|
+
break;
|
|
210308
|
+
case "ArrowUp":
|
|
210309
|
+
e20.preventDefault();
|
|
210310
|
+
_selectedIndex = Math.max(_selectedIndex - 1, 0);
|
|
210311
|
+
renderOverlay();
|
|
210312
|
+
break;
|
|
210313
|
+
case "Enter":
|
|
210314
|
+
e20.preventDefault();
|
|
210315
|
+
if (items[_selectedIndex])
|
|
210316
|
+
selectItem(items[_selectedIndex]);
|
|
210317
|
+
break;
|
|
210318
|
+
case "Escape":
|
|
210319
|
+
e20.preventDefault();
|
|
210320
|
+
closeQuickSearch();
|
|
210321
|
+
break;
|
|
210322
|
+
}
|
|
210323
|
+
}
|
|
210324
|
+
function selectItem(item) {
|
|
210325
|
+
closeQuickSearch();
|
|
210326
|
+
const path2 = item.path;
|
|
210327
|
+
trackRecentFile({ path: path2, name: path2.split("/").pop() });
|
|
210328
|
+
openFileInTab(path2);
|
|
210329
|
+
}
|
|
210330
|
+
function fileIcon(name) {
|
|
210331
|
+
const ext = name.split(".").pop()?.toLowerCase();
|
|
210332
|
+
switch (ext) {
|
|
210333
|
+
case "json":
|
|
210334
|
+
return html`<sp-icon-file-code size="s"></sp-icon-file-code>`;
|
|
210335
|
+
case "md":
|
|
210336
|
+
return html`<sp-icon-file-txt size="s"></sp-icon-file-txt>`;
|
|
210337
|
+
default:
|
|
210338
|
+
return html`<sp-icon-document size="s"></sp-icon-document>`;
|
|
210339
|
+
}
|
|
210340
|
+
}
|
|
210341
|
+
function dirPart(path2) {
|
|
210342
|
+
const parts = path2.split("/");
|
|
210343
|
+
parts.pop();
|
|
210344
|
+
return parts.length ? parts.join("/") : "";
|
|
210345
|
+
}
|
|
210346
|
+
function renderOverlay() {
|
|
210347
|
+
if (!_container)
|
|
210348
|
+
return;
|
|
210349
|
+
if (!_open) {
|
|
210350
|
+
render2(nothing, _container);
|
|
210351
|
+
return;
|
|
210352
|
+
}
|
|
210353
|
+
const recentFiles = getRecentFiles();
|
|
210354
|
+
const showRecent = !_query.trim();
|
|
210355
|
+
const items = showRecent ? recentFiles : _results;
|
|
210356
|
+
const tpl = html`
|
|
210357
|
+
<div class="quick-search-overlay" @click=${closeQuickSearch}>
|
|
210358
|
+
<div class="quick-search-panel" @click=${(e20) => e20.stopPropagation()}>
|
|
210359
|
+
<input
|
|
210360
|
+
class="quick-search-input"
|
|
210361
|
+
type="text"
|
|
210362
|
+
placeholder="Search project files…"
|
|
210363
|
+
.value=${_query}
|
|
210364
|
+
@input=${onInput}
|
|
210365
|
+
@keydown=${onKeydown2}
|
|
210366
|
+
/>
|
|
210367
|
+
<div class="quick-search-results">
|
|
210368
|
+
${items.length === 0 && _query.trim() ? html`<div class="quick-search-empty">No results</div>` : nothing}
|
|
210369
|
+
${items.length === 0 && !_query.trim() && recentFiles.length === 0 ? html`<div class="quick-search-empty">Type to search project files</div>` : nothing}
|
|
210370
|
+
${showRecent && recentFiles.length ? html`<div class="quick-search-section-label">Recently opened</div>` : nothing}
|
|
210371
|
+
${items.map((item, i6) => html`
|
|
210372
|
+
<div
|
|
210373
|
+
class="quick-search-item ${i6 === _selectedIndex ? "selected" : ""}"
|
|
210374
|
+
@click=${() => selectItem(item)}
|
|
210375
|
+
@mouseenter=${() => {
|
|
210376
|
+
_selectedIndex = i6;
|
|
210377
|
+
renderOverlay();
|
|
210378
|
+
}}
|
|
210379
|
+
>
|
|
210380
|
+
<span class="quick-search-icon"
|
|
210381
|
+
>${fileIcon(item.name || item.path.split("/").pop())}</span
|
|
210382
|
+
>
|
|
210383
|
+
<span class="quick-search-name">${item.name || item.path.split("/").pop()}</span>
|
|
210384
|
+
<span class="quick-search-path">${dirPart(item.path)}</span>
|
|
210385
|
+
${showRecent ? html`<span class="quick-search-badge">recent</span>` : nothing}
|
|
210386
|
+
</div>
|
|
210387
|
+
`)}
|
|
210388
|
+
</div>
|
|
210389
|
+
</div>
|
|
210390
|
+
</div>
|
|
210391
|
+
`;
|
|
210392
|
+
render2(tpl, _container);
|
|
210393
|
+
}
|
|
210394
|
+
|
|
210395
|
+
// src/editor/shortcuts.js
|
|
211254
210396
|
function initShortcuts(getContext) {
|
|
211255
210397
|
canvasWrap.addEventListener("wheel", (e20) => {
|
|
211256
210398
|
const { canvasMode, panX, panY, setPan, applyTransform: applyTransform2 } = getContext();
|
|
211257
210399
|
if (canvasMode === "edit")
|
|
211258
210400
|
return;
|
|
210401
|
+
if (canvasMode === "manage")
|
|
210402
|
+
return;
|
|
211259
210403
|
e20.preventDefault();
|
|
211260
210404
|
if (e20.ctrlKey || e20.metaKey) {
|
|
211261
210405
|
const rect = canvasWrap.getBoundingClientRect();
|
|
@@ -211359,6 +210503,10 @@ function initShortcuts(getContext) {
|
|
|
211359
210503
|
e20.preventDefault();
|
|
211360
210504
|
openProject2();
|
|
211361
210505
|
break;
|
|
210506
|
+
case "p":
|
|
210507
|
+
e20.preventDefault();
|
|
210508
|
+
openQuickSearch();
|
|
210509
|
+
break;
|
|
211362
210510
|
case "s":
|
|
211363
210511
|
e20.preventDefault();
|
|
211364
210512
|
saveFile2();
|
|
@@ -211495,6 +210643,1237 @@ function navigateSelection(direction = -1) {
|
|
|
211495
210643
|
init_store();
|
|
211496
210644
|
init_reactivity();
|
|
211497
210645
|
init_workspace();
|
|
210646
|
+
|
|
210647
|
+
// src/settings/defs-editor.js
|
|
210648
|
+
init_platform();
|
|
210649
|
+
init_store();
|
|
210650
|
+
var selectedDef = null;
|
|
210651
|
+
var showAddField = false;
|
|
210652
|
+
var newFieldState = { name: "", type: "string", format: "", required: false };
|
|
210653
|
+
var showNewDef = false;
|
|
210654
|
+
var newDefName = "";
|
|
210655
|
+
async function saveProjectConfig() {
|
|
210656
|
+
const platform4 = getPlatform();
|
|
210657
|
+
const config = projectState.projectConfig;
|
|
210658
|
+
await platform4.writeFile("project.json", JSON.stringify(config, null, "\t"));
|
|
210659
|
+
}
|
|
210660
|
+
function getSelectedDef() {
|
|
210661
|
+
const config = projectState?.projectConfig;
|
|
210662
|
+
return config?.$defs?.[selectedDef];
|
|
210663
|
+
}
|
|
210664
|
+
function handleNewDef(rerender) {
|
|
210665
|
+
const name = newDefName.trim();
|
|
210666
|
+
if (!name)
|
|
210667
|
+
return;
|
|
210668
|
+
const config = projectState?.projectConfig;
|
|
210669
|
+
if (!config)
|
|
210670
|
+
return;
|
|
210671
|
+
if (!config.$defs)
|
|
210672
|
+
config.$defs = {};
|
|
210673
|
+
if (config.$defs[name])
|
|
210674
|
+
return;
|
|
210675
|
+
config.$defs[name] = {
|
|
210676
|
+
type: "object",
|
|
210677
|
+
properties: {},
|
|
210678
|
+
required: []
|
|
210679
|
+
};
|
|
210680
|
+
selectedDef = name;
|
|
210681
|
+
showNewDef = false;
|
|
210682
|
+
newDefName = "";
|
|
210683
|
+
rerender();
|
|
210684
|
+
saveProjectConfig();
|
|
210685
|
+
}
|
|
210686
|
+
function handleAddField(rerender) {
|
|
210687
|
+
const name = newFieldState.name.trim();
|
|
210688
|
+
if (!name || !selectedDef)
|
|
210689
|
+
return;
|
|
210690
|
+
const def3 = getSelectedDef();
|
|
210691
|
+
if (!def3)
|
|
210692
|
+
return;
|
|
210693
|
+
if (!def3.properties)
|
|
210694
|
+
def3.properties = {};
|
|
210695
|
+
def3.properties[name] = schemaForType(newFieldState.type, newFieldState.format || undefined);
|
|
210696
|
+
if (newFieldState.required) {
|
|
210697
|
+
if (!def3.required)
|
|
210698
|
+
def3.required = [];
|
|
210699
|
+
if (!def3.required.includes(name))
|
|
210700
|
+
def3.required.push(name);
|
|
210701
|
+
}
|
|
210702
|
+
showAddField = false;
|
|
210703
|
+
newFieldState = { name: "", type: "string", format: "", required: false };
|
|
210704
|
+
rerender();
|
|
210705
|
+
saveProjectConfig();
|
|
210706
|
+
}
|
|
210707
|
+
function handleDeleteField(fieldName, rerender) {
|
|
210708
|
+
const def3 = getSelectedDef();
|
|
210709
|
+
if (!def3?.properties)
|
|
210710
|
+
return;
|
|
210711
|
+
delete def3.properties[fieldName];
|
|
210712
|
+
if (def3.required) {
|
|
210713
|
+
def3.required = def3.required.filter((r8) => r8 !== fieldName);
|
|
210714
|
+
}
|
|
210715
|
+
rerender();
|
|
210716
|
+
saveProjectConfig();
|
|
210717
|
+
}
|
|
210718
|
+
function handleToggleRequired(fieldName, rerender) {
|
|
210719
|
+
const def3 = getSelectedDef();
|
|
210720
|
+
if (!def3)
|
|
210721
|
+
return;
|
|
210722
|
+
if (!def3.required)
|
|
210723
|
+
def3.required = [];
|
|
210724
|
+
const idx = def3.required.indexOf(fieldName);
|
|
210725
|
+
if (idx >= 0)
|
|
210726
|
+
def3.required.splice(idx, 1);
|
|
210727
|
+
else
|
|
210728
|
+
def3.required.push(fieldName);
|
|
210729
|
+
rerender();
|
|
210730
|
+
saveProjectConfig();
|
|
210731
|
+
}
|
|
210732
|
+
function handleRenameField(oldName, newName, rerender) {
|
|
210733
|
+
const def3 = getSelectedDef();
|
|
210734
|
+
if (!def3?.properties || !newName || def3.properties[newName])
|
|
210735
|
+
return;
|
|
210736
|
+
const newProps = {};
|
|
210737
|
+
for (const [key, val] of Object.entries(def3.properties)) {
|
|
210738
|
+
newProps[key === oldName ? newName : key] = val;
|
|
210739
|
+
}
|
|
210740
|
+
def3.properties = newProps;
|
|
210741
|
+
if (def3.required) {
|
|
210742
|
+
def3.required = def3.required.map((r8) => r8 === oldName ? newName : r8);
|
|
210743
|
+
}
|
|
210744
|
+
rerender();
|
|
210745
|
+
saveProjectConfig();
|
|
210746
|
+
}
|
|
210747
|
+
function handleChangeType(fieldName, newType, rerender) {
|
|
210748
|
+
const def3 = getSelectedDef();
|
|
210749
|
+
if (!def3?.properties?.[fieldName])
|
|
210750
|
+
return;
|
|
210751
|
+
const oldFormat = newType === "string" || newType === "array" ? detectFieldFormat(def3.properties[fieldName]) : undefined;
|
|
210752
|
+
def3.properties[fieldName] = schemaForType(newType, oldFormat || undefined);
|
|
210753
|
+
rerender();
|
|
210754
|
+
saveProjectConfig();
|
|
210755
|
+
}
|
|
210756
|
+
function handleChangeFormat(fieldName, format2, rerender) {
|
|
210757
|
+
const def3 = getSelectedDef();
|
|
210758
|
+
if (!def3?.properties?.[fieldName])
|
|
210759
|
+
return;
|
|
210760
|
+
const prop = def3.properties[fieldName];
|
|
210761
|
+
const type2 = prop.type || "string";
|
|
210762
|
+
def3.properties[fieldName] = schemaForType(type2, format2 || undefined);
|
|
210763
|
+
rerender();
|
|
210764
|
+
saveProjectConfig();
|
|
210765
|
+
}
|
|
210766
|
+
function handleAddNestedField(parentName, fieldState, rerender) {
|
|
210767
|
+
const def3 = getSelectedDef();
|
|
210768
|
+
const parent = def3?.properties?.[parentName];
|
|
210769
|
+
if (!parent)
|
|
210770
|
+
return;
|
|
210771
|
+
if (!parent.properties)
|
|
210772
|
+
parent.properties = {};
|
|
210773
|
+
parent.properties[fieldState.name] = schemaForType(fieldState.type);
|
|
210774
|
+
if (fieldState.required) {
|
|
210775
|
+
if (!parent.required)
|
|
210776
|
+
parent.required = [];
|
|
210777
|
+
if (!parent.required.includes(fieldState.name))
|
|
210778
|
+
parent.required.push(fieldState.name);
|
|
210779
|
+
}
|
|
210780
|
+
rerender();
|
|
210781
|
+
saveProjectConfig();
|
|
210782
|
+
}
|
|
210783
|
+
function handleDeleteNested(parentName, childName, rerender) {
|
|
210784
|
+
const def3 = getSelectedDef();
|
|
210785
|
+
const parent = def3?.properties?.[parentName];
|
|
210786
|
+
if (!parent?.properties)
|
|
210787
|
+
return;
|
|
210788
|
+
delete parent.properties[childName];
|
|
210789
|
+
if (parent.required) {
|
|
210790
|
+
parent.required = parent.required.filter((r8) => r8 !== childName);
|
|
210791
|
+
}
|
|
210792
|
+
rerender();
|
|
210793
|
+
saveProjectConfig();
|
|
210794
|
+
}
|
|
210795
|
+
function handleToggleNestedRequired(parentName, childName, rerender) {
|
|
210796
|
+
const def3 = getSelectedDef();
|
|
210797
|
+
const parent = def3?.properties?.[parentName];
|
|
210798
|
+
if (!parent)
|
|
210799
|
+
return;
|
|
210800
|
+
if (!parent.required)
|
|
210801
|
+
parent.required = [];
|
|
210802
|
+
const idx = parent.required.indexOf(childName);
|
|
210803
|
+
if (idx >= 0)
|
|
210804
|
+
parent.required.splice(idx, 1);
|
|
210805
|
+
else
|
|
210806
|
+
parent.required.push(childName);
|
|
210807
|
+
rerender();
|
|
210808
|
+
saveProjectConfig();
|
|
210809
|
+
}
|
|
210810
|
+
function handleRenameNested(parentName, oldChild, newChild, rerender) {
|
|
210811
|
+
const def3 = getSelectedDef();
|
|
210812
|
+
const parent = def3?.properties?.[parentName];
|
|
210813
|
+
if (!parent?.properties || !newChild || parent.properties[newChild])
|
|
210814
|
+
return;
|
|
210815
|
+
const newProps = {};
|
|
210816
|
+
for (const [key, val] of Object.entries(parent.properties)) {
|
|
210817
|
+
newProps[key === oldChild ? newChild : key] = val;
|
|
210818
|
+
}
|
|
210819
|
+
parent.properties = newProps;
|
|
210820
|
+
if (parent.required) {
|
|
210821
|
+
parent.required = parent.required.map((r8) => r8 === oldChild ? newChild : r8);
|
|
210822
|
+
}
|
|
210823
|
+
rerender();
|
|
210824
|
+
saveProjectConfig();
|
|
210825
|
+
}
|
|
210826
|
+
function handleChangeNestedType(parentName, childName, newType, rerender) {
|
|
210827
|
+
const def3 = getSelectedDef();
|
|
210828
|
+
const parent = def3?.properties?.[parentName];
|
|
210829
|
+
if (!parent?.properties?.[childName])
|
|
210830
|
+
return;
|
|
210831
|
+
const oldFormat = newType === "string" || newType === "array" ? detectFieldFormat(parent.properties[childName]) : undefined;
|
|
210832
|
+
parent.properties[childName] = schemaForType(newType, oldFormat || undefined);
|
|
210833
|
+
rerender();
|
|
210834
|
+
saveProjectConfig();
|
|
210835
|
+
}
|
|
210836
|
+
function handleChangeNestedFormat(parentName, childName, format2, rerender) {
|
|
210837
|
+
const def3 = getSelectedDef();
|
|
210838
|
+
const parent = def3?.properties?.[parentName];
|
|
210839
|
+
if (!parent?.properties?.[childName])
|
|
210840
|
+
return;
|
|
210841
|
+
const prop = parent.properties[childName];
|
|
210842
|
+
const type2 = prop.type || "string";
|
|
210843
|
+
parent.properties[childName] = schemaForType(type2, format2 || undefined);
|
|
210844
|
+
rerender();
|
|
210845
|
+
saveProjectConfig();
|
|
210846
|
+
}
|
|
210847
|
+
function handleDeleteDef(rerender) {
|
|
210848
|
+
if (!selectedDef)
|
|
210849
|
+
return;
|
|
210850
|
+
const config = projectState?.projectConfig;
|
|
210851
|
+
if (!config?.$defs?.[selectedDef])
|
|
210852
|
+
return;
|
|
210853
|
+
delete config.$defs[selectedDef];
|
|
210854
|
+
selectedDef = null;
|
|
210855
|
+
rerender();
|
|
210856
|
+
saveProjectConfig();
|
|
210857
|
+
}
|
|
210858
|
+
function renderDefsEditor(container) {
|
|
210859
|
+
const rerender = () => renderDefsEditor(container);
|
|
210860
|
+
const config = projectState?.projectConfig;
|
|
210861
|
+
const defs = config?.$defs || {};
|
|
210862
|
+
const defNames = Object.keys(defs);
|
|
210863
|
+
const listTpl = html`
|
|
210864
|
+
<div class="settings-list-panel">
|
|
210865
|
+
${defNames.map((name) => html`
|
|
210866
|
+
<sp-action-button
|
|
210867
|
+
size="s"
|
|
210868
|
+
?selected=${selectedDef === name}
|
|
210869
|
+
@click=${() => {
|
|
210870
|
+
selectedDef = name;
|
|
210871
|
+
showAddField = false;
|
|
210872
|
+
rerender();
|
|
210873
|
+
}}
|
|
210874
|
+
>
|
|
210875
|
+
${name}
|
|
210876
|
+
</sp-action-button>
|
|
210877
|
+
`)}
|
|
210878
|
+
${showNewDef ? html`
|
|
210879
|
+
<div class="settings-inline-form">
|
|
210880
|
+
<sp-textfield
|
|
210881
|
+
size="s"
|
|
210882
|
+
placeholder="TypeName"
|
|
210883
|
+
.value=${newDefName}
|
|
210884
|
+
@input=${(e20) => {
|
|
210885
|
+
newDefName = e20.target.value;
|
|
210886
|
+
}}
|
|
210887
|
+
@keydown=${(e20) => {
|
|
210888
|
+
if (e20.key === "Enter")
|
|
210889
|
+
handleNewDef(rerender);
|
|
210890
|
+
if (e20.key === "Escape") {
|
|
210891
|
+
showNewDef = false;
|
|
210892
|
+
rerender();
|
|
210893
|
+
}
|
|
210894
|
+
}}
|
|
210895
|
+
></sp-textfield>
|
|
210896
|
+
<sp-action-button size="s" @click=${() => handleNewDef(rerender)}>
|
|
210897
|
+
Create
|
|
210898
|
+
</sp-action-button>
|
|
210899
|
+
</div>
|
|
210900
|
+
` : html`
|
|
210901
|
+
<sp-action-button
|
|
210902
|
+
size="s"
|
|
210903
|
+
quiet
|
|
210904
|
+
@click=${() => {
|
|
210905
|
+
showNewDef = true;
|
|
210906
|
+
rerender();
|
|
210907
|
+
}}
|
|
210908
|
+
>
|
|
210909
|
+
<sp-icon-add slot="icon"></sp-icon-add> New Definition
|
|
210910
|
+
</sp-action-button>
|
|
210911
|
+
`}
|
|
210912
|
+
</div>
|
|
210913
|
+
`;
|
|
210914
|
+
let editorTpl;
|
|
210915
|
+
if (!selectedDef || !defs[selectedDef]) {
|
|
210916
|
+
editorTpl = html`<div class="settings-empty-state">Select or create a type definition</div>`;
|
|
210917
|
+
} else {
|
|
210918
|
+
const def3 = defs[selectedDef];
|
|
210919
|
+
const properties = def3.properties || {};
|
|
210920
|
+
const required = def3.required || [];
|
|
210921
|
+
const handlers = {
|
|
210922
|
+
onDelete: (n4) => handleDeleteField(n4, rerender),
|
|
210923
|
+
onToggleRequired: (n4) => handleToggleRequired(n4, rerender),
|
|
210924
|
+
onRename: (oldN, newN) => handleRenameField(oldN, newN, rerender),
|
|
210925
|
+
onChangeType: (n4, t15) => handleChangeType(n4, t15, rerender),
|
|
210926
|
+
onChangeFormat: (n4, f) => handleChangeFormat(n4, f, rerender),
|
|
210927
|
+
onAddNestedField: (p2, s2) => handleAddNestedField(p2, s2, rerender),
|
|
210928
|
+
onDeleteNested: (p2, c6) => handleDeleteNested(p2, c6, rerender),
|
|
210929
|
+
onToggleNestedRequired: (p2, c6) => handleToggleNestedRequired(p2, c6, rerender),
|
|
210930
|
+
onRenameNested: (p2, o19, n4) => handleRenameNested(p2, o19, n4, rerender),
|
|
210931
|
+
onChangeNestedType: (p2, c6, t15) => handleChangeNestedType(p2, c6, t15, rerender),
|
|
210932
|
+
onChangeNestedFormat: (p2, c6, f) => handleChangeNestedFormat(p2, c6, f, rerender)
|
|
210933
|
+
};
|
|
210934
|
+
const fieldCards = Object.entries(properties).map(([name, fieldDef]) => fieldCardTpl(name, fieldDef, required.includes(name), handlers));
|
|
210935
|
+
editorTpl = html`
|
|
210936
|
+
<div class="settings-editor-panel">
|
|
210937
|
+
<div class="settings-editor-header">
|
|
210938
|
+
<h3>${selectedDef}</h3>
|
|
210939
|
+
<sp-action-button
|
|
210940
|
+
size="xs"
|
|
210941
|
+
quiet
|
|
210942
|
+
title="Delete definition"
|
|
210943
|
+
@click=${() => handleDeleteDef(rerender)}
|
|
210944
|
+
>
|
|
210945
|
+
<sp-icon-delete slot="icon"></sp-icon-delete>
|
|
210946
|
+
</sp-action-button>
|
|
210947
|
+
</div>
|
|
210948
|
+
<div class="schema-field-list">${fieldCards}</div>
|
|
210949
|
+
${showAddField ? addFieldFormTpl(newFieldState, {
|
|
210950
|
+
onInput: (field, value2) => {
|
|
210951
|
+
newFieldState = { ...newFieldState, [field]: value2 };
|
|
210952
|
+
rerender();
|
|
210953
|
+
},
|
|
210954
|
+
onConfirm: () => handleAddField(rerender),
|
|
210955
|
+
onCancel: () => {
|
|
210956
|
+
showAddField = false;
|
|
210957
|
+
newFieldState = { name: "", type: "string", format: "", required: false };
|
|
210958
|
+
rerender();
|
|
210959
|
+
}
|
|
210960
|
+
}) : html`
|
|
210961
|
+
<sp-action-button
|
|
210962
|
+
size="s"
|
|
210963
|
+
quiet
|
|
210964
|
+
@click=${() => {
|
|
210965
|
+
showAddField = true;
|
|
210966
|
+
rerender();
|
|
210967
|
+
}}
|
|
210968
|
+
>
|
|
210969
|
+
<sp-icon-add slot="icon"></sp-icon-add> Add Field
|
|
210970
|
+
</sp-action-button>
|
|
210971
|
+
`}
|
|
210972
|
+
</div>
|
|
210973
|
+
`;
|
|
210974
|
+
}
|
|
210975
|
+
const tpl = html` <div class="settings-two-col">${listTpl} ${editorTpl}</div> `;
|
|
210976
|
+
render2(tpl, container);
|
|
210977
|
+
}
|
|
210978
|
+
|
|
210979
|
+
// src/settings/content-types-editor.js
|
|
210980
|
+
init_platform();
|
|
210981
|
+
init_store();
|
|
210982
|
+
var selectedContentType = null;
|
|
210983
|
+
var showAddField2 = false;
|
|
210984
|
+
var newFieldState2 = { name: "", type: "string", format: "", required: false };
|
|
210985
|
+
var showNewContentType = false;
|
|
210986
|
+
var newContentTypeName = "";
|
|
210987
|
+
async function saveProjectConfig2() {
|
|
210988
|
+
const platform4 = getPlatform();
|
|
210989
|
+
const config = projectState.projectConfig;
|
|
210990
|
+
await platform4.writeFile("project.json", JSON.stringify(config, null, "\t"));
|
|
210991
|
+
}
|
|
210992
|
+
function getSelectedSchema() {
|
|
210993
|
+
const config = projectState?.projectConfig;
|
|
210994
|
+
return config?.contentTypes?.[selectedContentType]?.schema;
|
|
210995
|
+
}
|
|
210996
|
+
function handleNewContentType(rerender) {
|
|
210997
|
+
const slug = newContentTypeName.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
|
|
210998
|
+
if (!slug)
|
|
210999
|
+
return;
|
|
211000
|
+
const config = projectState?.projectConfig;
|
|
211001
|
+
if (!config)
|
|
211002
|
+
return;
|
|
211003
|
+
if (!config.contentTypes)
|
|
211004
|
+
config.contentTypes = {};
|
|
211005
|
+
if (config.contentTypes[slug])
|
|
211006
|
+
return;
|
|
211007
|
+
config.contentTypes[slug] = {
|
|
211008
|
+
source: `./content/${slug}/**/*.md`,
|
|
211009
|
+
schema: { type: "object", properties: {}, required: [] }
|
|
211010
|
+
};
|
|
211011
|
+
selectedContentType = slug;
|
|
211012
|
+
showNewContentType = false;
|
|
211013
|
+
newContentTypeName = "";
|
|
211014
|
+
rerender();
|
|
211015
|
+
saveProjectConfig2().then(async () => {
|
|
211016
|
+
const platform4 = getPlatform();
|
|
211017
|
+
await platform4.writeFile(`content/${slug}/.gitkeep`, "");
|
|
211018
|
+
});
|
|
211019
|
+
}
|
|
211020
|
+
function handleAddField2(rerender) {
|
|
211021
|
+
const name = newFieldState2.name.trim();
|
|
211022
|
+
if (!name || !selectedContentType)
|
|
211023
|
+
return;
|
|
211024
|
+
const schema4 = getSelectedSchema();
|
|
211025
|
+
if (!schema4)
|
|
211026
|
+
return;
|
|
211027
|
+
if (!schema4.properties)
|
|
211028
|
+
schema4.properties = {};
|
|
211029
|
+
schema4.properties[name] = schemaForType(newFieldState2.type, newFieldState2.format || undefined);
|
|
211030
|
+
if (newFieldState2.required) {
|
|
211031
|
+
if (!schema4.required)
|
|
211032
|
+
schema4.required = [];
|
|
211033
|
+
if (!schema4.required.includes(name))
|
|
211034
|
+
schema4.required.push(name);
|
|
211035
|
+
}
|
|
211036
|
+
showAddField2 = false;
|
|
211037
|
+
newFieldState2 = { name: "", type: "string", format: "", required: false };
|
|
211038
|
+
rerender();
|
|
211039
|
+
saveProjectConfig2();
|
|
211040
|
+
}
|
|
211041
|
+
function handleDeleteField2(fieldName, rerender) {
|
|
211042
|
+
const schema4 = getSelectedSchema();
|
|
211043
|
+
if (!schema4?.properties)
|
|
211044
|
+
return;
|
|
211045
|
+
delete schema4.properties[fieldName];
|
|
211046
|
+
if (schema4.required) {
|
|
211047
|
+
schema4.required = schema4.required.filter((r8) => r8 !== fieldName);
|
|
211048
|
+
}
|
|
211049
|
+
rerender();
|
|
211050
|
+
saveProjectConfig2();
|
|
211051
|
+
}
|
|
211052
|
+
function handleToggleRequired2(fieldName, rerender) {
|
|
211053
|
+
const schema4 = getSelectedSchema();
|
|
211054
|
+
if (!schema4)
|
|
211055
|
+
return;
|
|
211056
|
+
if (!schema4.required)
|
|
211057
|
+
schema4.required = [];
|
|
211058
|
+
const idx = schema4.required.indexOf(fieldName);
|
|
211059
|
+
if (idx >= 0)
|
|
211060
|
+
schema4.required.splice(idx, 1);
|
|
211061
|
+
else
|
|
211062
|
+
schema4.required.push(fieldName);
|
|
211063
|
+
rerender();
|
|
211064
|
+
saveProjectConfig2();
|
|
211065
|
+
}
|
|
211066
|
+
function handleRenameField2(oldName, newName, rerender) {
|
|
211067
|
+
const schema4 = getSelectedSchema();
|
|
211068
|
+
if (!schema4?.properties || !newName || schema4.properties[newName])
|
|
211069
|
+
return;
|
|
211070
|
+
const newProps = {};
|
|
211071
|
+
for (const [key, val] of Object.entries(schema4.properties)) {
|
|
211072
|
+
newProps[key === oldName ? newName : key] = val;
|
|
211073
|
+
}
|
|
211074
|
+
schema4.properties = newProps;
|
|
211075
|
+
if (schema4.required) {
|
|
211076
|
+
schema4.required = schema4.required.map((r8) => r8 === oldName ? newName : r8);
|
|
211077
|
+
}
|
|
211078
|
+
rerender();
|
|
211079
|
+
saveProjectConfig2();
|
|
211080
|
+
}
|
|
211081
|
+
function handleChangeType2(fieldName, newType, rerender) {
|
|
211082
|
+
const schema4 = getSelectedSchema();
|
|
211083
|
+
if (!schema4?.properties?.[fieldName])
|
|
211084
|
+
return;
|
|
211085
|
+
const oldFormat = newType === "string" || newType === "array" ? detectFieldFormat(schema4.properties[fieldName]) : undefined;
|
|
211086
|
+
schema4.properties[fieldName] = schemaForType(newType, oldFormat || undefined);
|
|
211087
|
+
rerender();
|
|
211088
|
+
saveProjectConfig2();
|
|
211089
|
+
}
|
|
211090
|
+
function handleChangeFormat2(fieldName, format2, rerender) {
|
|
211091
|
+
const schema4 = getSelectedSchema();
|
|
211092
|
+
if (!schema4?.properties?.[fieldName])
|
|
211093
|
+
return;
|
|
211094
|
+
const prop = schema4.properties[fieldName];
|
|
211095
|
+
const type2 = prop.type || "string";
|
|
211096
|
+
schema4.properties[fieldName] = schemaForType(type2, format2 || undefined);
|
|
211097
|
+
rerender();
|
|
211098
|
+
saveProjectConfig2();
|
|
211099
|
+
}
|
|
211100
|
+
function handleChangeRefTarget(fieldName, target, rerender) {
|
|
211101
|
+
const schema4 = getSelectedSchema();
|
|
211102
|
+
if (!schema4?.properties)
|
|
211103
|
+
return;
|
|
211104
|
+
schema4.properties[fieldName] = { $ref: `#/contentTypes/${target}` };
|
|
211105
|
+
rerender();
|
|
211106
|
+
saveProjectConfig2();
|
|
211107
|
+
}
|
|
211108
|
+
function handleAddNestedField2(parentName, fieldState, rerender) {
|
|
211109
|
+
const schema4 = getSelectedSchema();
|
|
211110
|
+
const parent = schema4?.properties?.[parentName];
|
|
211111
|
+
if (!parent)
|
|
211112
|
+
return;
|
|
211113
|
+
if (!parent.properties)
|
|
211114
|
+
parent.properties = {};
|
|
211115
|
+
parent.properties[fieldState.name] = schemaForType(fieldState.type);
|
|
211116
|
+
if (fieldState.required) {
|
|
211117
|
+
if (!parent.required)
|
|
211118
|
+
parent.required = [];
|
|
211119
|
+
if (!parent.required.includes(fieldState.name))
|
|
211120
|
+
parent.required.push(fieldState.name);
|
|
211121
|
+
}
|
|
211122
|
+
rerender();
|
|
211123
|
+
saveProjectConfig2();
|
|
211124
|
+
}
|
|
211125
|
+
function handleDeleteNested2(parentName, childName, rerender) {
|
|
211126
|
+
const schema4 = getSelectedSchema();
|
|
211127
|
+
const parent = schema4?.properties?.[parentName];
|
|
211128
|
+
if (!parent?.properties)
|
|
211129
|
+
return;
|
|
211130
|
+
delete parent.properties[childName];
|
|
211131
|
+
if (parent.required) {
|
|
211132
|
+
parent.required = parent.required.filter((r8) => r8 !== childName);
|
|
211133
|
+
}
|
|
211134
|
+
rerender();
|
|
211135
|
+
saveProjectConfig2();
|
|
211136
|
+
}
|
|
211137
|
+
function handleToggleNestedRequired2(parentName, childName, rerender) {
|
|
211138
|
+
const schema4 = getSelectedSchema();
|
|
211139
|
+
const parent = schema4?.properties?.[parentName];
|
|
211140
|
+
if (!parent)
|
|
211141
|
+
return;
|
|
211142
|
+
if (!parent.required)
|
|
211143
|
+
parent.required = [];
|
|
211144
|
+
const idx = parent.required.indexOf(childName);
|
|
211145
|
+
if (idx >= 0)
|
|
211146
|
+
parent.required.splice(idx, 1);
|
|
211147
|
+
else
|
|
211148
|
+
parent.required.push(childName);
|
|
211149
|
+
rerender();
|
|
211150
|
+
saveProjectConfig2();
|
|
211151
|
+
}
|
|
211152
|
+
function handleRenameNested2(parentName, oldChild, newChild, rerender) {
|
|
211153
|
+
const schema4 = getSelectedSchema();
|
|
211154
|
+
const parent = schema4?.properties?.[parentName];
|
|
211155
|
+
if (!parent?.properties || !newChild || parent.properties[newChild])
|
|
211156
|
+
return;
|
|
211157
|
+
const newProps = {};
|
|
211158
|
+
for (const [key, val] of Object.entries(parent.properties)) {
|
|
211159
|
+
newProps[key === oldChild ? newChild : key] = val;
|
|
211160
|
+
}
|
|
211161
|
+
parent.properties = newProps;
|
|
211162
|
+
if (parent.required) {
|
|
211163
|
+
parent.required = parent.required.map((r8) => r8 === oldChild ? newChild : r8);
|
|
211164
|
+
}
|
|
211165
|
+
rerender();
|
|
211166
|
+
saveProjectConfig2();
|
|
211167
|
+
}
|
|
211168
|
+
function handleChangeNestedType2(parentName, childName, newType, rerender) {
|
|
211169
|
+
const schema4 = getSelectedSchema();
|
|
211170
|
+
const parent = schema4?.properties?.[parentName];
|
|
211171
|
+
if (!parent?.properties?.[childName])
|
|
211172
|
+
return;
|
|
211173
|
+
const oldFormat = newType === "string" || newType === "array" ? detectFieldFormat(parent.properties[childName]) : undefined;
|
|
211174
|
+
parent.properties[childName] = schemaForType(newType, oldFormat || undefined);
|
|
211175
|
+
rerender();
|
|
211176
|
+
saveProjectConfig2();
|
|
211177
|
+
}
|
|
211178
|
+
function handleChangeNestedFormat2(parentName, childName, format2, rerender) {
|
|
211179
|
+
const schema4 = getSelectedSchema();
|
|
211180
|
+
const parent = schema4?.properties?.[parentName];
|
|
211181
|
+
if (!parent?.properties?.[childName])
|
|
211182
|
+
return;
|
|
211183
|
+
const prop = parent.properties[childName];
|
|
211184
|
+
const type2 = prop.type || "string";
|
|
211185
|
+
parent.properties[childName] = schemaForType(type2, format2 || undefined);
|
|
211186
|
+
rerender();
|
|
211187
|
+
saveProjectConfig2();
|
|
211188
|
+
}
|
|
211189
|
+
function handleDeleteContentType(rerender) {
|
|
211190
|
+
if (!selectedContentType)
|
|
211191
|
+
return;
|
|
211192
|
+
const config = projectState?.projectConfig;
|
|
211193
|
+
if (!config?.contentTypes?.[selectedContentType])
|
|
211194
|
+
return;
|
|
211195
|
+
delete config.contentTypes[selectedContentType];
|
|
211196
|
+
selectedContentType = null;
|
|
211197
|
+
rerender();
|
|
211198
|
+
saveProjectConfig2();
|
|
211199
|
+
}
|
|
211200
|
+
function renderContentTypesEditor(container) {
|
|
211201
|
+
const rerender = () => renderContentTypesEditor(container);
|
|
211202
|
+
const config = projectState?.projectConfig;
|
|
211203
|
+
const contentTypes = config?.contentTypes || {};
|
|
211204
|
+
const contentTypeNames = Object.keys(contentTypes);
|
|
211205
|
+
const listTpl = html`
|
|
211206
|
+
<div class="settings-list-panel">
|
|
211207
|
+
${contentTypeNames.map((name) => html`
|
|
211208
|
+
<sp-action-button
|
|
211209
|
+
size="s"
|
|
211210
|
+
?selected=${selectedContentType === name}
|
|
211211
|
+
@click=${() => {
|
|
211212
|
+
selectedContentType = name;
|
|
211213
|
+
showAddField2 = false;
|
|
211214
|
+
rerender();
|
|
211215
|
+
}}
|
|
211216
|
+
>
|
|
211217
|
+
${name}
|
|
211218
|
+
</sp-action-button>
|
|
211219
|
+
`)}
|
|
211220
|
+
${showNewContentType ? html`
|
|
211221
|
+
<div class="settings-inline-form">
|
|
211222
|
+
<sp-textfield
|
|
211223
|
+
size="s"
|
|
211224
|
+
placeholder="content-type-name"
|
|
211225
|
+
.value=${newContentTypeName}
|
|
211226
|
+
@input=${(e20) => {
|
|
211227
|
+
newContentTypeName = e20.target.value;
|
|
211228
|
+
}}
|
|
211229
|
+
@keydown=${(e20) => {
|
|
211230
|
+
if (e20.key === "Enter")
|
|
211231
|
+
handleNewContentType(rerender);
|
|
211232
|
+
if (e20.key === "Escape") {
|
|
211233
|
+
showNewContentType = false;
|
|
211234
|
+
rerender();
|
|
211235
|
+
}
|
|
211236
|
+
}}
|
|
211237
|
+
></sp-textfield>
|
|
211238
|
+
<sp-action-button size="s" @click=${() => handleNewContentType(rerender)}>
|
|
211239
|
+
Create
|
|
211240
|
+
</sp-action-button>
|
|
211241
|
+
</div>
|
|
211242
|
+
` : html`
|
|
211243
|
+
<sp-action-button
|
|
211244
|
+
size="s"
|
|
211245
|
+
quiet
|
|
211246
|
+
@click=${() => {
|
|
211247
|
+
showNewContentType = true;
|
|
211248
|
+
rerender();
|
|
211249
|
+
}}
|
|
211250
|
+
>
|
|
211251
|
+
<sp-icon-add slot="icon"></sp-icon-add> New Content Type
|
|
211252
|
+
</sp-action-button>
|
|
211253
|
+
`}
|
|
211254
|
+
</div>
|
|
211255
|
+
`;
|
|
211256
|
+
let editorTpl;
|
|
211257
|
+
if (!selectedContentType || !contentTypes[selectedContentType]) {
|
|
211258
|
+
editorTpl = html`<div class="settings-empty-state">Select or create a content type</div>`;
|
|
211259
|
+
} else {
|
|
211260
|
+
const col = contentTypes[selectedContentType];
|
|
211261
|
+
const schema4 = col.schema || {};
|
|
211262
|
+
const properties = schema4.properties || {};
|
|
211263
|
+
const required = schema4.required || [];
|
|
211264
|
+
const handlers = {
|
|
211265
|
+
onDelete: (n4) => handleDeleteField2(n4, rerender),
|
|
211266
|
+
onToggleRequired: (n4) => handleToggleRequired2(n4, rerender),
|
|
211267
|
+
onRename: (oldN, newN) => handleRenameField2(oldN, newN, rerender),
|
|
211268
|
+
onChangeType: (n4, t15) => handleChangeType2(n4, t15, rerender),
|
|
211269
|
+
onChangeFormat: (n4, f) => handleChangeFormat2(n4, f, rerender),
|
|
211270
|
+
onChangeRefTarget: (n4, target) => handleChangeRefTarget(n4, target, rerender),
|
|
211271
|
+
onAddNestedField: (p2, s2) => handleAddNestedField2(p2, s2, rerender),
|
|
211272
|
+
onDeleteNested: (p2, c6) => handleDeleteNested2(p2, c6, rerender),
|
|
211273
|
+
onToggleNestedRequired: (p2, c6) => handleToggleNestedRequired2(p2, c6, rerender),
|
|
211274
|
+
onRenameNested: (p2, o19, n4) => handleRenameNested2(p2, o19, n4, rerender),
|
|
211275
|
+
onChangeNestedType: (p2, c6, t15) => handleChangeNestedType2(p2, c6, t15, rerender),
|
|
211276
|
+
onChangeNestedFormat: (p2, c6, f) => handleChangeNestedFormat2(p2, c6, f, rerender)
|
|
211277
|
+
};
|
|
211278
|
+
const fieldCards = Object.entries(properties).map(([name, def3]) => fieldCardTpl(name, def3, required.includes(name), handlers, contentTypeNames));
|
|
211279
|
+
editorTpl = html`
|
|
211280
|
+
<div class="settings-editor-panel">
|
|
211281
|
+
<div class="settings-editor-header">
|
|
211282
|
+
<h3>${selectedContentType}</h3>
|
|
211283
|
+
<sp-field-label size="s">Source: ${col.source || "—"}</sp-field-label>
|
|
211284
|
+
<sp-action-button
|
|
211285
|
+
size="xs"
|
|
211286
|
+
quiet
|
|
211287
|
+
title="Delete content type"
|
|
211288
|
+
@click=${() => handleDeleteContentType(rerender)}
|
|
211289
|
+
>
|
|
211290
|
+
<sp-icon-delete slot="icon"></sp-icon-delete>
|
|
211291
|
+
</sp-action-button>
|
|
211292
|
+
</div>
|
|
211293
|
+
<div class="schema-field-list">${fieldCards}</div>
|
|
211294
|
+
${showAddField2 ? addFieldFormTpl(newFieldState2, {
|
|
211295
|
+
onInput: (field, value2) => {
|
|
211296
|
+
newFieldState2 = { ...newFieldState2, [field]: value2 };
|
|
211297
|
+
rerender();
|
|
211298
|
+
},
|
|
211299
|
+
onConfirm: () => handleAddField2(rerender),
|
|
211300
|
+
onCancel: () => {
|
|
211301
|
+
showAddField2 = false;
|
|
211302
|
+
newFieldState2 = { name: "", type: "string", format: "", required: false };
|
|
211303
|
+
rerender();
|
|
211304
|
+
}
|
|
211305
|
+
}) : html`
|
|
211306
|
+
<sp-action-button
|
|
211307
|
+
size="s"
|
|
211308
|
+
quiet
|
|
211309
|
+
@click=${() => {
|
|
211310
|
+
showAddField2 = true;
|
|
211311
|
+
rerender();
|
|
211312
|
+
}}
|
|
211313
|
+
>
|
|
211314
|
+
<sp-icon-add slot="icon"></sp-icon-add> Add Field
|
|
211315
|
+
</sp-action-button>
|
|
211316
|
+
`}
|
|
211317
|
+
</div>
|
|
211318
|
+
`;
|
|
211319
|
+
}
|
|
211320
|
+
const tpl = html` <div class="settings-two-col">${listTpl} ${editorTpl}</div> `;
|
|
211321
|
+
render2(tpl, container);
|
|
211322
|
+
}
|
|
211323
|
+
|
|
211324
|
+
// src/settings/css-vars-editor.js
|
|
211325
|
+
init_store();
|
|
211326
|
+
function renderCssVarsEditor(container) {
|
|
211327
|
+
const config = projectState.projectConfig || {};
|
|
211328
|
+
const rootStyle = config.style || {};
|
|
211329
|
+
const media = getEffectiveMedia(config.$media);
|
|
211330
|
+
const groups = { color: [], font: [], size: [], other: [] };
|
|
211331
|
+
for (const [k, v] of Object.entries(rootStyle)) {
|
|
211332
|
+
if (!k.startsWith("--"))
|
|
211333
|
+
continue;
|
|
211334
|
+
if (typeof v !== "string" && typeof v !== "number")
|
|
211335
|
+
continue;
|
|
211336
|
+
if (k.startsWith("--color"))
|
|
211337
|
+
groups.color.push([k, v]);
|
|
211338
|
+
else if (k.startsWith("--font"))
|
|
211339
|
+
groups.font.push([k, v]);
|
|
211340
|
+
else if (k.startsWith("--size") || k.startsWith("--spacing") || k.startsWith("--radius"))
|
|
211341
|
+
groups.size.push([k, v]);
|
|
211342
|
+
else
|
|
211343
|
+
groups.other.push([k, v]);
|
|
211344
|
+
}
|
|
211345
|
+
const mediaNames = media ? Object.keys(media).filter((m3) => m3 !== "--") : [];
|
|
211346
|
+
const save = () => {
|
|
211347
|
+
updateSiteConfig({ style: { ...rootStyle } });
|
|
211348
|
+
};
|
|
211349
|
+
const updateVar = (name, val) => {
|
|
211350
|
+
rootStyle[name] = val;
|
|
211351
|
+
save();
|
|
211352
|
+
};
|
|
211353
|
+
const deleteVar = (name) => {
|
|
211354
|
+
delete rootStyle[name];
|
|
211355
|
+
save();
|
|
211356
|
+
renderCssVarsEditor(container);
|
|
211357
|
+
};
|
|
211358
|
+
const addVar = (prefix, friendlyName, val) => {
|
|
211359
|
+
const varName = friendlyNameToVar(friendlyName, prefix);
|
|
211360
|
+
if (!varName || !val)
|
|
211361
|
+
return;
|
|
211362
|
+
rootStyle[varName] = val;
|
|
211363
|
+
save();
|
|
211364
|
+
renderCssVarsEditor(container);
|
|
211365
|
+
};
|
|
211366
|
+
const tpl = html`
|
|
211367
|
+
<div class="settings-section">
|
|
211368
|
+
<h3 class="settings-section-title">CSS Variables</h3>
|
|
211369
|
+
|
|
211370
|
+
${renderColorSection(groups.color, updateVar, deleteVar, addVar)}
|
|
211371
|
+
${renderFontSection(groups.font, updateVar, deleteVar, addVar)}
|
|
211372
|
+
${renderSizeSection(groups.size, updateVar, deleteVar, addVar, rootStyle, mediaNames)}
|
|
211373
|
+
${groups.other.length > 0 ? renderOtherSection(groups.other, updateVar, deleteVar, addVar, rootStyle, mediaNames) : nothing}
|
|
211374
|
+
</div>
|
|
211375
|
+
`;
|
|
211376
|
+
render2(tpl, container);
|
|
211377
|
+
}
|
|
211378
|
+
function renderColorSection(vars, updateVar, deleteVar, addVar) {
|
|
211379
|
+
return html`
|
|
211380
|
+
<div class="css-vars-group">
|
|
211381
|
+
<h4 class="css-vars-group-title">Colors</h4>
|
|
211382
|
+
${vars.map(([name, val]) => html`
|
|
211383
|
+
<div class="css-var-row">
|
|
211384
|
+
<div class="css-var-swatch" style="background:${val}">
|
|
211385
|
+
<input
|
|
211386
|
+
type="color"
|
|
211387
|
+
.value=${val && val.startsWith("#") ? val : "#007acc"}
|
|
211388
|
+
@input=${(e20) => updateVar(name, e20.target.value)}
|
|
211389
|
+
/>
|
|
211390
|
+
</div>
|
|
211391
|
+
<span class="css-var-name">${varDisplayName(name, "--color-")}</span>
|
|
211392
|
+
<sp-textfield
|
|
211393
|
+
size="s"
|
|
211394
|
+
.value=${String(val)}
|
|
211395
|
+
@change=${(e20) => updateVar(name, e20.target.value)}
|
|
211396
|
+
style="flex:1;max-width:160px"
|
|
211397
|
+
></sp-textfield>
|
|
211398
|
+
<sp-action-button quiet size="s" @click=${() => deleteVar(name)}>
|
|
211399
|
+
<sp-icon-delete slot="icon"></sp-icon-delete>
|
|
211400
|
+
</sp-action-button>
|
|
211401
|
+
</div>
|
|
211402
|
+
`)}
|
|
211403
|
+
${renderAddRow("--color-", "Primary Blue", "#007acc", addVar)}
|
|
211404
|
+
</div>
|
|
211405
|
+
`;
|
|
211406
|
+
}
|
|
211407
|
+
function renderFontSection(vars, updateVar, deleteVar, addVar) {
|
|
211408
|
+
return html`
|
|
211409
|
+
<div class="css-vars-group">
|
|
211410
|
+
<h4 class="css-vars-group-title">Fonts</h4>
|
|
211411
|
+
${vars.map(([name, val]) => html`
|
|
211412
|
+
<div class="css-var-row">
|
|
211413
|
+
<span class="css-var-name">${varDisplayName(name, "--font-")}</span>
|
|
211414
|
+
<sp-textfield
|
|
211415
|
+
size="s"
|
|
211416
|
+
.value=${String(val)}
|
|
211417
|
+
@change=${(e20) => updateVar(name, e20.target.value)}
|
|
211418
|
+
style="flex:1"
|
|
211419
|
+
></sp-textfield>
|
|
211420
|
+
<sp-action-button quiet size="s" @click=${() => deleteVar(name)}>
|
|
211421
|
+
<sp-icon-delete slot="icon"></sp-icon-delete>
|
|
211422
|
+
</sp-action-button>
|
|
211423
|
+
</div>
|
|
211424
|
+
<div class="css-var-font-preview" style="font-family:${val}">
|
|
211425
|
+
The quick brown fox jumps over the lazy dog
|
|
211426
|
+
</div>
|
|
211427
|
+
`)}
|
|
211428
|
+
${renderAddRow("--font-", "Body Serif", "'Georgia', serif", addVar)}
|
|
211429
|
+
</div>
|
|
211430
|
+
`;
|
|
211431
|
+
}
|
|
211432
|
+
function renderSizeSection(vars, updateVar, deleteVar, addVar, rootStyle, mediaNames) {
|
|
211433
|
+
return html`
|
|
211434
|
+
<div class="css-vars-group">
|
|
211435
|
+
<h4 class="css-vars-group-title">Sizes & Spacing</h4>
|
|
211436
|
+
${vars.map(([name, val]) => html`
|
|
211437
|
+
<div class="css-var-row">
|
|
211438
|
+
<span class="css-var-name"
|
|
211439
|
+
>${varDisplayName(name, "--size-") || varDisplayName(name, "--spacing-") || varDisplayName(name, "--radius-") || name}</span
|
|
211440
|
+
>
|
|
211441
|
+
<sp-textfield
|
|
211442
|
+
size="s"
|
|
211443
|
+
.value=${String(val)}
|
|
211444
|
+
@change=${(e20) => updateVar(name, e20.target.value)}
|
|
211445
|
+
style="max-width:120px"
|
|
211446
|
+
></sp-textfield>
|
|
211447
|
+
<sp-action-button quiet size="s" @click=${() => deleteVar(name)}>
|
|
211448
|
+
<sp-icon-delete slot="icon"></sp-icon-delete>
|
|
211449
|
+
</sp-action-button>
|
|
211450
|
+
</div>
|
|
211451
|
+
${mediaNames.length > 0 ? renderMediaOverrides(name, rootStyle, mediaNames) : nothing}
|
|
211452
|
+
`)}
|
|
211453
|
+
${renderAddRow("--size-", "Spacing Large", "32px", addVar)}
|
|
211454
|
+
</div>
|
|
211455
|
+
`;
|
|
211456
|
+
}
|
|
211457
|
+
function renderOtherSection(vars, updateVar, deleteVar, addVar, rootStyle, mediaNames) {
|
|
211458
|
+
return html`
|
|
211459
|
+
<div class="css-vars-group">
|
|
211460
|
+
<h4 class="css-vars-group-title">Other</h4>
|
|
211461
|
+
${vars.map(([name, val]) => html`
|
|
211462
|
+
<div class="css-var-row">
|
|
211463
|
+
<span class="css-var-name">${name}</span>
|
|
211464
|
+
<sp-textfield
|
|
211465
|
+
size="s"
|
|
211466
|
+
.value=${String(val)}
|
|
211467
|
+
@change=${(e20) => updateVar(name, e20.target.value)}
|
|
211468
|
+
style="flex:1"
|
|
211469
|
+
></sp-textfield>
|
|
211470
|
+
<sp-action-button quiet size="s" @click=${() => deleteVar(name)}>
|
|
211471
|
+
<sp-icon-delete slot="icon"></sp-icon-delete>
|
|
211472
|
+
</sp-action-button>
|
|
211473
|
+
</div>
|
|
211474
|
+
${mediaNames.length > 0 ? renderMediaOverrides(name, rootStyle, mediaNames) : nothing}
|
|
211475
|
+
`)}
|
|
211476
|
+
${renderAddRow("--", "Custom Var", "value", addVar)}
|
|
211477
|
+
</div>
|
|
211478
|
+
`;
|
|
211479
|
+
}
|
|
211480
|
+
function renderMediaOverrides(varName, rootStyle, mediaNames) {
|
|
211481
|
+
const overrides = [];
|
|
211482
|
+
for (const mediaName of mediaNames) {
|
|
211483
|
+
const mediaKey = `@${mediaName}`;
|
|
211484
|
+
const mediaBlock = rootStyle[mediaKey];
|
|
211485
|
+
if (mediaBlock && typeof mediaBlock === "object" && mediaBlock[varName]) {
|
|
211486
|
+
overrides.push({ mediaName, value: mediaBlock[varName] });
|
|
211487
|
+
}
|
|
211488
|
+
}
|
|
211489
|
+
if (overrides.length === 0)
|
|
211490
|
+
return nothing;
|
|
211491
|
+
return html`
|
|
211492
|
+
<div class="css-var-media-overrides">
|
|
211493
|
+
${overrides.map((o19) => html`
|
|
211494
|
+
<div class="css-var-media-row">
|
|
211495
|
+
<span class="css-var-media-label">@${o19.mediaName}</span>
|
|
211496
|
+
<sp-textfield
|
|
211497
|
+
size="s"
|
|
211498
|
+
.value=${String(o19.value)}
|
|
211499
|
+
@change=${(e20) => {
|
|
211500
|
+
if (!rootStyle[`@${o19.mediaName}`])
|
|
211501
|
+
rootStyle[`@${o19.mediaName}`] = {};
|
|
211502
|
+
rootStyle[`@${o19.mediaName}`][varName] = e20.target.value;
|
|
211503
|
+
updateSiteConfig({ style: { ...rootStyle } });
|
|
211504
|
+
}}
|
|
211505
|
+
style="max-width:120px"
|
|
211506
|
+
></sp-textfield>
|
|
211507
|
+
</div>
|
|
211508
|
+
`)}
|
|
211509
|
+
</div>
|
|
211510
|
+
`;
|
|
211511
|
+
}
|
|
211512
|
+
function renderAddRow(prefix, placeholder, valuePlaceholder, addVar) {
|
|
211513
|
+
let nameEl = null;
|
|
211514
|
+
let valEl = null;
|
|
211515
|
+
return html`
|
|
211516
|
+
<div class="css-var-add-row">
|
|
211517
|
+
<sp-textfield
|
|
211518
|
+
size="s"
|
|
211519
|
+
placeholder=${placeholder}
|
|
211520
|
+
${ref2((el) => {
|
|
211521
|
+
if (el)
|
|
211522
|
+
nameEl = el;
|
|
211523
|
+
})}
|
|
211524
|
+
></sp-textfield>
|
|
211525
|
+
<sp-textfield
|
|
211526
|
+
size="s"
|
|
211527
|
+
placeholder=${valuePlaceholder}
|
|
211528
|
+
${ref2((el) => {
|
|
211529
|
+
if (el)
|
|
211530
|
+
valEl = el;
|
|
211531
|
+
})}
|
|
211532
|
+
></sp-textfield>
|
|
211533
|
+
<sp-action-button
|
|
211534
|
+
size="s"
|
|
211535
|
+
@click=${() => {
|
|
211536
|
+
if (nameEl && valEl) {
|
|
211537
|
+
addVar(prefix, nameEl.value, valEl.value);
|
|
211538
|
+
}
|
|
211539
|
+
}}
|
|
211540
|
+
>Add</sp-action-button
|
|
211541
|
+
>
|
|
211542
|
+
</div>
|
|
211543
|
+
`;
|
|
211544
|
+
}
|
|
211545
|
+
|
|
211546
|
+
// src/settings/head-editor.js
|
|
211547
|
+
init_store();
|
|
211548
|
+
function renderHeadEditor(container) {
|
|
211549
|
+
const config = projectState.projectConfig || {};
|
|
211550
|
+
const headEntries = config.$head || [];
|
|
211551
|
+
const save = () => {
|
|
211552
|
+
updateSiteConfig({ $head: headEntries });
|
|
211553
|
+
};
|
|
211554
|
+
const addEntry = (tag7) => {
|
|
211555
|
+
const entry = { tag: tag7 };
|
|
211556
|
+
if (tag7 === "link") {
|
|
211557
|
+
entry.rel = "stylesheet";
|
|
211558
|
+
entry.href = "";
|
|
211559
|
+
} else if (tag7 === "meta") {
|
|
211560
|
+
entry.name = "";
|
|
211561
|
+
entry.content = "";
|
|
211562
|
+
} else if (tag7 === "script") {
|
|
211563
|
+
entry.src = "";
|
|
211564
|
+
entry.body = "";
|
|
211565
|
+
} else if (tag7 === "style") {
|
|
211566
|
+
entry.body = "";
|
|
211567
|
+
}
|
|
211568
|
+
headEntries.push(entry);
|
|
211569
|
+
save();
|
|
211570
|
+
renderHeadEditor(container);
|
|
211571
|
+
};
|
|
211572
|
+
const removeEntry = (idx) => {
|
|
211573
|
+
headEntries.splice(idx, 1);
|
|
211574
|
+
save();
|
|
211575
|
+
renderHeadEditor(container);
|
|
211576
|
+
};
|
|
211577
|
+
const updateEntry = (idx, key, val) => {
|
|
211578
|
+
headEntries[idx][key] = val;
|
|
211579
|
+
save();
|
|
211580
|
+
};
|
|
211581
|
+
const tpl = html`
|
|
211582
|
+
<div class="settings-section">
|
|
211583
|
+
<h3 class="settings-section-title">Head</h3>
|
|
211584
|
+
<p class="settings-field-desc">
|
|
211585
|
+
Manage global <head> tags — stylesheets, meta tags, scripts, and inline styles.
|
|
211586
|
+
</p>
|
|
211587
|
+
|
|
211588
|
+
<div class="head-entries">
|
|
211589
|
+
${headEntries.map((entry, idx) => html`
|
|
211590
|
+
<div class="head-entry">
|
|
211591
|
+
<div class="head-entry-header">
|
|
211592
|
+
<span class="head-entry-tag"><${entry.tag}></span>
|
|
211593
|
+
<sp-action-button quiet size="s" @click=${() => removeEntry(idx)}>
|
|
211594
|
+
<sp-icon-delete slot="icon"></sp-icon-delete>
|
|
211595
|
+
</sp-action-button>
|
|
211596
|
+
</div>
|
|
211597
|
+
<div class="head-entry-fields">${renderEntryFields(entry, idx, updateEntry)}</div>
|
|
211598
|
+
</div>
|
|
211599
|
+
`)}
|
|
211600
|
+
</div>
|
|
211601
|
+
|
|
211602
|
+
<div class="head-add-actions" style="margin-top:12px;display:flex;gap:8px">
|
|
211603
|
+
<sp-action-button size="s" @click=${() => addEntry("link")}> + Link </sp-action-button>
|
|
211604
|
+
<sp-action-button size="s" @click=${() => addEntry("meta")}> + Meta </sp-action-button>
|
|
211605
|
+
<sp-action-button size="s" @click=${() => addEntry("script")}> + Script </sp-action-button>
|
|
211606
|
+
<sp-action-button size="s" @click=${() => addEntry("style")}> + Style </sp-action-button>
|
|
211607
|
+
</div>
|
|
211608
|
+
</div>
|
|
211609
|
+
`;
|
|
211610
|
+
render2(tpl, container);
|
|
211611
|
+
}
|
|
211612
|
+
function renderEntryFields(entry, idx, updateEntry) {
|
|
211613
|
+
let debounce;
|
|
211614
|
+
const onFieldChange = (key) => (e20) => {
|
|
211615
|
+
clearTimeout(debounce);
|
|
211616
|
+
debounce = setTimeout(() => {
|
|
211617
|
+
updateEntry(idx, key, e20.target.value);
|
|
211618
|
+
}, 300);
|
|
211619
|
+
};
|
|
211620
|
+
switch (entry.tag) {
|
|
211621
|
+
case "link":
|
|
211622
|
+
return html`
|
|
211623
|
+
<div class="settings-field-row">
|
|
211624
|
+
<sp-textfield
|
|
211625
|
+
size="s"
|
|
211626
|
+
label="rel"
|
|
211627
|
+
.value=${entry.rel || ""}
|
|
211628
|
+
@change=${onFieldChange("rel")}
|
|
211629
|
+
></sp-textfield>
|
|
211630
|
+
<sp-textfield
|
|
211631
|
+
size="s"
|
|
211632
|
+
label="href"
|
|
211633
|
+
.value=${entry.href || ""}
|
|
211634
|
+
@change=${onFieldChange("href")}
|
|
211635
|
+
style="flex:1"
|
|
211636
|
+
></sp-textfield>
|
|
211637
|
+
</div>
|
|
211638
|
+
`;
|
|
211639
|
+
case "meta":
|
|
211640
|
+
return html`
|
|
211641
|
+
<div class="settings-field-row">
|
|
211642
|
+
<sp-textfield
|
|
211643
|
+
size="s"
|
|
211644
|
+
label="name"
|
|
211645
|
+
.value=${entry.name || ""}
|
|
211646
|
+
@change=${onFieldChange("name")}
|
|
211647
|
+
></sp-textfield>
|
|
211648
|
+
<sp-textfield
|
|
211649
|
+
size="s"
|
|
211650
|
+
label="content"
|
|
211651
|
+
.value=${entry.content || ""}
|
|
211652
|
+
@change=${onFieldChange("content")}
|
|
211653
|
+
style="flex:1"
|
|
211654
|
+
></sp-textfield>
|
|
211655
|
+
</div>
|
|
211656
|
+
`;
|
|
211657
|
+
case "script":
|
|
211658
|
+
return html`
|
|
211659
|
+
<div class="settings-field-row">
|
|
211660
|
+
<sp-textfield
|
|
211661
|
+
size="s"
|
|
211662
|
+
label="src"
|
|
211663
|
+
.value=${entry.src || ""}
|
|
211664
|
+
@change=${onFieldChange("src")}
|
|
211665
|
+
placeholder="URL or leave empty for inline"
|
|
211666
|
+
style="flex:1"
|
|
211667
|
+
></sp-textfield>
|
|
211668
|
+
</div>
|
|
211669
|
+
${!entry.src ? html`
|
|
211670
|
+
<div class="head-entry-body">
|
|
211671
|
+
<label class="settings-field-label">Script body</label>
|
|
211672
|
+
<textarea
|
|
211673
|
+
class="head-code-editor"
|
|
211674
|
+
.value=${entry.body || ""}
|
|
211675
|
+
@input=${onFieldChange("body")}
|
|
211676
|
+
rows="6"
|
|
211677
|
+
spellcheck="false"
|
|
211678
|
+
></textarea>
|
|
211679
|
+
</div>
|
|
211680
|
+
` : nothing}
|
|
211681
|
+
`;
|
|
211682
|
+
case "style":
|
|
211683
|
+
return html`
|
|
211684
|
+
<div class="head-entry-body">
|
|
211685
|
+
<label class="settings-field-label">Style body</label>
|
|
211686
|
+
<textarea
|
|
211687
|
+
class="head-code-editor"
|
|
211688
|
+
.value=${entry.body || ""}
|
|
211689
|
+
@input=${onFieldChange("body")}
|
|
211690
|
+
rows="8"
|
|
211691
|
+
spellcheck="false"
|
|
211692
|
+
></textarea>
|
|
211693
|
+
</div>
|
|
211694
|
+
`;
|
|
211695
|
+
default:
|
|
211696
|
+
return nothing;
|
|
211697
|
+
}
|
|
211698
|
+
}
|
|
211699
|
+
|
|
211700
|
+
// src/settings/general-settings.js
|
|
211701
|
+
init_store();
|
|
211702
|
+
init_platform();
|
|
211703
|
+
function renderGeneralSettings(container) {
|
|
211704
|
+
const config = projectState.projectConfig || {};
|
|
211705
|
+
const onFaviconUpload = async () => {
|
|
211706
|
+
const input = document.createElement("input");
|
|
211707
|
+
input.type = "file";
|
|
211708
|
+
input.accept = "image/*,.ico,.svg";
|
|
211709
|
+
input.onchange = async () => {
|
|
211710
|
+
const file = input.files?.[0];
|
|
211711
|
+
if (!file)
|
|
211712
|
+
return;
|
|
211713
|
+
const platform4 = getPlatform();
|
|
211714
|
+
await platform4.uploadFile("public/favicon.ico", file);
|
|
211715
|
+
await updateSiteConfig({ favicon: "/favicon.ico" });
|
|
211716
|
+
renderGeneralSettings(container);
|
|
211717
|
+
};
|
|
211718
|
+
input.click();
|
|
211719
|
+
};
|
|
211720
|
+
const onAdapterChange = (e20) => {
|
|
211721
|
+
updateSiteConfig({ adapter: e20.target.value });
|
|
211722
|
+
};
|
|
211723
|
+
const onEditGlobalStyles = () => {
|
|
211724
|
+
closeSettingsModal();
|
|
211725
|
+
openFileInTab("project.json");
|
|
211726
|
+
};
|
|
211727
|
+
const currentFavicon = config.favicon;
|
|
211728
|
+
const tpl = html`
|
|
211729
|
+
<div class="settings-section">
|
|
211730
|
+
<h3 class="settings-section-title">General</h3>
|
|
211731
|
+
|
|
211732
|
+
<div class="settings-field">
|
|
211733
|
+
<label class="settings-field-label">Favicon</label>
|
|
211734
|
+
<p class="settings-field-desc">Upload an image to use as the site favicon.</p>
|
|
211735
|
+
<div style="display:flex;align-items:center;gap:12px">
|
|
211736
|
+
${currentFavicon ? html`<img
|
|
211737
|
+
src=${currentFavicon}
|
|
211738
|
+
alt="Current favicon"
|
|
211739
|
+
style="width:32px;height:32px;object-fit:contain;border:1px solid var(--border);border-radius:4px;padding:2px"
|
|
211740
|
+
/>` : html`<div
|
|
211741
|
+
style="width:32px;height:32px;border:1px dashed var(--border);border-radius:4px;display:flex;align-items:center;justify-content:center;color:var(--fg-dim);font-size:11px"
|
|
211742
|
+
>
|
|
211743
|
+
—
|
|
211744
|
+
</div>`}
|
|
211745
|
+
<sp-action-button size="s" @click=${onFaviconUpload}> Upload Favicon </sp-action-button>
|
|
211746
|
+
${currentFavicon ? html`<span style="font-size:11px;color:var(--fg-dim)">${currentFavicon}</span>` : nothing}
|
|
211747
|
+
</div>
|
|
211748
|
+
</div>
|
|
211749
|
+
|
|
211750
|
+
<div class="settings-field">
|
|
211751
|
+
<label class="settings-field-label">Platform Adapter</label>
|
|
211752
|
+
<p class="settings-field-desc">Build adapter for deployment target.</p>
|
|
211753
|
+
<sp-picker
|
|
211754
|
+
size="s"
|
|
211755
|
+
label="Platform Adapter"
|
|
211756
|
+
.value=${config.adapter || "static"}
|
|
211757
|
+
@change=${onAdapterChange}
|
|
211758
|
+
>
|
|
211759
|
+
<sp-menu-item value="static">Static</sp-menu-item>
|
|
211760
|
+
<sp-menu-item value="bun">Bun</sp-menu-item>
|
|
211761
|
+
<sp-menu-item value="node">Node</sp-menu-item>
|
|
211762
|
+
<sp-menu-item value="cloudflare-workers">Cloudflare Workers</sp-menu-item>
|
|
211763
|
+
<sp-menu-item value="cloudflare-pages">Cloudflare Pages</sp-menu-item>
|
|
211764
|
+
</sp-picker>
|
|
211765
|
+
</div>
|
|
211766
|
+
|
|
211767
|
+
<div class="settings-field">
|
|
211768
|
+
<label class="settings-field-label">Global Styles</label>
|
|
211769
|
+
<p class="settings-field-desc">Edit default element styles that apply across all pages.</p>
|
|
211770
|
+
<sp-action-button size="s" @click=${onEditGlobalStyles}>
|
|
211771
|
+
Edit Global Styles
|
|
211772
|
+
</sp-action-button>
|
|
211773
|
+
</div>
|
|
211774
|
+
</div>
|
|
211775
|
+
`;
|
|
211776
|
+
render2(tpl, container);
|
|
211777
|
+
}
|
|
211778
|
+
|
|
211779
|
+
// src/settings/settings-modal.js
|
|
211780
|
+
var _host = null;
|
|
211781
|
+
var _activeSection = "general";
|
|
211782
|
+
var sections = [
|
|
211783
|
+
{ key: "general", label: "General", icon: "sp-icon-properties" },
|
|
211784
|
+
{ key: "head", label: "Head", icon: "sp-icon-file-single-web-page" },
|
|
211785
|
+
{ key: "cssVars", label: "CSS Variables", icon: "sp-icon-brush" },
|
|
211786
|
+
{ key: "definitions", label: "Definitions", icon: "sp-icon-data" },
|
|
211787
|
+
{ key: "contentTypes", label: "Content Types", icon: "sp-icon-view-grid" }
|
|
211788
|
+
];
|
|
211789
|
+
function openSettingsModal() {
|
|
211790
|
+
if (_host)
|
|
211791
|
+
return;
|
|
211792
|
+
_host = document.createElement("div");
|
|
211793
|
+
_host.style.display = "contents";
|
|
211794
|
+
const themeRoot = document.querySelector("sp-theme") || document.body;
|
|
211795
|
+
themeRoot.appendChild(_host);
|
|
211796
|
+
_activeSection = "general";
|
|
211797
|
+
renderModal();
|
|
211798
|
+
}
|
|
211799
|
+
function closeSettingsModal() {
|
|
211800
|
+
if (!_host)
|
|
211801
|
+
return;
|
|
211802
|
+
_host.remove();
|
|
211803
|
+
_host = null;
|
|
211804
|
+
}
|
|
211805
|
+
function renderModal() {
|
|
211806
|
+
if (!_host)
|
|
211807
|
+
return;
|
|
211808
|
+
const onNavClick = (key) => {
|
|
211809
|
+
_activeSection = key;
|
|
211810
|
+
renderModal();
|
|
211811
|
+
renderActiveSection();
|
|
211812
|
+
};
|
|
211813
|
+
const tpl = html`
|
|
211814
|
+
<sp-underlay open @close=${closeSettingsModal}></sp-underlay>
|
|
211815
|
+
<div
|
|
211816
|
+
class="settings-modal"
|
|
211817
|
+
@keydown=${(e20) => {
|
|
211818
|
+
if (e20.key === "Escape")
|
|
211819
|
+
closeSettingsModal();
|
|
211820
|
+
}}
|
|
211821
|
+
>
|
|
211822
|
+
<div class="settings-modal-header">
|
|
211823
|
+
<h2 class="settings-modal-title">Settings</h2>
|
|
211824
|
+
<sp-action-button quiet size="s" @click=${closeSettingsModal} title="Close">
|
|
211825
|
+
<sp-icon-close slot="icon"></sp-icon-close>
|
|
211826
|
+
</sp-action-button>
|
|
211827
|
+
</div>
|
|
211828
|
+
<div class="settings-modal-body">
|
|
211829
|
+
<nav class="settings-modal-nav">
|
|
211830
|
+
${sections.map((s2) => html`
|
|
211831
|
+
<button
|
|
211832
|
+
class="settings-nav-item${_activeSection === s2.key ? " active" : ""}"
|
|
211833
|
+
@click=${() => onNavClick(s2.key)}
|
|
211834
|
+
>
|
|
211835
|
+
${s2.label}
|
|
211836
|
+
</button>
|
|
211837
|
+
`)}
|
|
211838
|
+
</nav>
|
|
211839
|
+
<div
|
|
211840
|
+
class="settings-modal-content"
|
|
211841
|
+
${ref2((el) => {
|
|
211842
|
+
if (el)
|
|
211843
|
+
requestAnimationFrame(() => renderActiveSection());
|
|
211844
|
+
})}
|
|
211845
|
+
></div>
|
|
211846
|
+
</div>
|
|
211847
|
+
</div>
|
|
211848
|
+
`;
|
|
211849
|
+
render2(tpl, _host);
|
|
211850
|
+
}
|
|
211851
|
+
function renderActiveSection() {
|
|
211852
|
+
if (!_host)
|
|
211853
|
+
return;
|
|
211854
|
+
const container = _host.querySelector(".settings-modal-content");
|
|
211855
|
+
if (!container)
|
|
211856
|
+
return;
|
|
211857
|
+
switch (_activeSection) {
|
|
211858
|
+
case "general":
|
|
211859
|
+
renderGeneralSettings(container);
|
|
211860
|
+
break;
|
|
211861
|
+
case "head":
|
|
211862
|
+
renderHeadEditor(container);
|
|
211863
|
+
break;
|
|
211864
|
+
case "cssVars":
|
|
211865
|
+
renderCssVarsEditor(container);
|
|
211866
|
+
break;
|
|
211867
|
+
case "definitions":
|
|
211868
|
+
renderDefsEditor(container);
|
|
211869
|
+
break;
|
|
211870
|
+
case "contentTypes":
|
|
211871
|
+
renderContentTypesEditor(container);
|
|
211872
|
+
break;
|
|
211873
|
+
}
|
|
211874
|
+
}
|
|
211875
|
+
|
|
211876
|
+
// src/panels/activity-bar.js
|
|
211498
211877
|
var _scope3 = null;
|
|
211499
211878
|
function mount4() {
|
|
211500
211879
|
_scope3 = effectScope();
|
|
@@ -211576,6 +211955,17 @@ function renderActivityBar() {
|
|
|
211576
211955
|
</sp-tab>
|
|
211577
211956
|
`)}
|
|
211578
211957
|
</sp-tabs>
|
|
211958
|
+
<div style="margin-top:auto;padding:8px 0;display:flex;justify-content:center">
|
|
211959
|
+
<sp-action-button
|
|
211960
|
+
quiet
|
|
211961
|
+
size="m"
|
|
211962
|
+
title="Settings"
|
|
211963
|
+
aria-label="Settings"
|
|
211964
|
+
@click=${() => openSettingsModal()}
|
|
211965
|
+
>
|
|
211966
|
+
<sp-icon-gears slot="icon"></sp-icon-gears>
|
|
211967
|
+
</sp-action-button>
|
|
211968
|
+
</div>
|
|
211579
211969
|
`;
|
|
211580
211970
|
render2(tpl, activityBar);
|
|
211581
211971
|
}
|
|
@@ -211614,6 +212004,9 @@ function tbBtnTpl(label4, onClick, iconTag) {
|
|
|
211614
212004
|
function mount5(rootEl, ctx) {
|
|
211615
212005
|
_rootEl = rootEl;
|
|
211616
212006
|
_ctx11 = ctx;
|
|
212007
|
+
if (globalThis.__jxPlatform?.windowControls) {
|
|
212008
|
+
rootEl.classList.add("electrobun-webkit-app-region-drag");
|
|
212009
|
+
}
|
|
211617
212010
|
_scope4 = effectScope();
|
|
211618
212011
|
_scope4.run(() => {
|
|
211619
212012
|
effect(() => {
|
|
@@ -211715,17 +212108,22 @@ function toolbarTemplate() {
|
|
|
211715
212108
|
{ key: "design", label: "Design", iconTag: "sp-icon-artboard" },
|
|
211716
212109
|
{ key: "preview", label: "Preview", iconTag: "sp-icon-preview" },
|
|
211717
212110
|
{ key: "source", label: "Code", iconTag: "sp-icon-code" },
|
|
211718
|
-
{ key: "
|
|
212111
|
+
{ key: "stylebook", label: "Stylebook", iconTag: "sp-icon-brush" }
|
|
211719
212112
|
];
|
|
212113
|
+
const isProjectFile = S.documentPath === "project.json";
|
|
212114
|
+
const allowedModes = isProjectFile ? new Set(["stylebook", "source"]) : null;
|
|
211720
212115
|
const modeSwitcherTpl = html`
|
|
211721
212116
|
<sp-action-group selects="single" size="s" compact>
|
|
211722
212117
|
${modes.map((m3) => html`
|
|
211723
212118
|
<sp-action-button
|
|
211724
212119
|
size="s"
|
|
211725
212120
|
?selected=${canvasMode === m3.key}
|
|
212121
|
+
?disabled=${allowedModes && !allowedModes.has(m3.key)}
|
|
211726
212122
|
@click=${() => {
|
|
211727
212123
|
if (canvasMode === m3.key)
|
|
211728
212124
|
return;
|
|
212125
|
+
if (allowedModes && !allowedModes.has(m3.key))
|
|
212126
|
+
return;
|
|
211729
212127
|
if (S.ui.editingFunction) {
|
|
211730
212128
|
if (view.functionEditor) {
|
|
211731
212129
|
view.functionEditor.dispose();
|
|
@@ -211736,7 +212134,7 @@ function toolbarTemplate() {
|
|
|
211736
212134
|
view.panX = 0;
|
|
211737
212135
|
view.panY = 0;
|
|
211738
212136
|
const uiPatch = { editingFunction: null };
|
|
211739
|
-
if (m3.key === "
|
|
212137
|
+
if (m3.key === "stylebook")
|
|
211740
212138
|
uiPatch.rightTab = "style";
|
|
211741
212139
|
if (m3.key === "manage")
|
|
211742
212140
|
view.leftTab = "files";
|
|
@@ -211750,10 +212148,52 @@ function toolbarTemplate() {
|
|
|
211750
212148
|
`)}
|
|
211751
212149
|
</sp-action-group>
|
|
211752
212150
|
`;
|
|
212151
|
+
const windowControls = globalThis.__jxPlatform?.windowControls;
|
|
212152
|
+
const csdTpl = windowControls ? html`
|
|
212153
|
+
<sp-action-group class="window-controls" size="s">
|
|
212154
|
+
<sp-action-button
|
|
212155
|
+
quiet
|
|
212156
|
+
size="s"
|
|
212157
|
+
title="Minimize"
|
|
212158
|
+
@click=${() => windowControls.minimize()}
|
|
212159
|
+
>
|
|
212160
|
+
<sp-icon-remove slot="icon"></sp-icon-remove>
|
|
212161
|
+
</sp-action-button>
|
|
212162
|
+
<sp-action-button
|
|
212163
|
+
quiet
|
|
212164
|
+
size="s"
|
|
212165
|
+
title="Maximize"
|
|
212166
|
+
@click=${() => windowControls.maximize()}
|
|
212167
|
+
>
|
|
212168
|
+
<sp-icon-full-screen slot="icon"></sp-icon-full-screen>
|
|
212169
|
+
</sp-action-button>
|
|
212170
|
+
<sp-action-button
|
|
212171
|
+
quiet
|
|
212172
|
+
size="s"
|
|
212173
|
+
title="Close"
|
|
212174
|
+
class="csd-close"
|
|
212175
|
+
@click=${() => windowControls.close()}
|
|
212176
|
+
>
|
|
212177
|
+
<sp-icon-close slot="icon"></sp-icon-close>
|
|
212178
|
+
</sp-action-button>
|
|
212179
|
+
</sp-action-group>
|
|
212180
|
+
` : nothing;
|
|
212181
|
+
const recentProjects = getRecentProjects();
|
|
212182
|
+
const recentProjectsTpl = recentProjects.length ? html`
|
|
212183
|
+
<overlay-trigger placement="bottom-start">
|
|
212184
|
+
<sp-action-button size="s" slot="trigger" title="Recent projects">
|
|
212185
|
+
<sp-icon-chevron-down slot="icon"></sp-icon-chevron-down>
|
|
212186
|
+
</sp-action-button>
|
|
212187
|
+
<sp-popover slot="click-content" tip>
|
|
212188
|
+
<sp-menu @change=${(e20) => _ctx11.openRecentProject(e20.target.value)}>
|
|
212189
|
+
${recentProjects.map((p2) => html`<sp-menu-item value=${p2.root}>${p2.name}</sp-menu-item>`)}
|
|
212190
|
+
</sp-menu>
|
|
212191
|
+
</sp-popover>
|
|
212192
|
+
</overlay-trigger>
|
|
212193
|
+
` : nothing;
|
|
211753
212194
|
return html`
|
|
211754
212195
|
<sp-action-group compact size="s">
|
|
211755
|
-
${tbBtnTpl("Open Project", _ctx11.openProject, "sp-icon-folder-open")}
|
|
211756
|
-
${tbBtnTpl("Open File", _ctx11.openFile, "sp-icon-document")}
|
|
212196
|
+
${tbBtnTpl("Open Project", _ctx11.openProject, "sp-icon-folder-open")} ${recentProjectsTpl}
|
|
211757
212197
|
${tbBtnTpl("Save", _ctx11.saveFile, "sp-icon-save-floppy")}
|
|
211758
212198
|
</sp-action-group>
|
|
211759
212199
|
<sp-action-group compact size="s">
|
|
@@ -211761,14 +212201,12 @@ function toolbarTemplate() {
|
|
|
211761
212201
|
${tbBtnTpl("Redo", () => redo(activeTab.value), "sp-icon-redo")}
|
|
211762
212202
|
</sp-action-group>
|
|
211763
212203
|
<div class="tb-spacer"></div>
|
|
211764
|
-
|
|
211765
|
-
|
|
211766
|
-
|
|
211767
|
-
|
|
211768
|
-
>` : nothing}
|
|
211769
|
-
${breadcrumbTpl}
|
|
212204
|
+
<sp-action-button class="tb-search-trigger" size="s" quiet @click=${openQuickSearch}>
|
|
212205
|
+
<sp-icon-search slot="icon"></sp-icon-search>
|
|
212206
|
+
<span class="tb-search-label">Search files… <kbd>⌘P</kbd></span>
|
|
212207
|
+
</sp-action-button>
|
|
211770
212208
|
<div class="tb-spacer"></div>
|
|
211771
|
-
${togglesTpl} ${modeSwitcherTpl}
|
|
212209
|
+
${breadcrumbTpl} ${togglesTpl} ${modeSwitcherTpl} ${csdTpl}
|
|
211772
212210
|
`;
|
|
211773
212211
|
}
|
|
211774
212212
|
|
|
@@ -214505,7 +214943,7 @@ function renderStylePanelTemplate(ctx) {
|
|
|
214505
214943
|
const tab = activeTab.value;
|
|
214506
214944
|
if (!tab)
|
|
214507
214945
|
return html`<div class="empty-state">No document loaded</div>`;
|
|
214508
|
-
if (ctx.getCanvasMode() === "
|
|
214946
|
+
if (ctx.getCanvasMode() === "stylebook" && tab.session.ui.stylebookSelection) {
|
|
214509
214947
|
const node3 = tab.doc.document;
|
|
214510
214948
|
if (!node3)
|
|
214511
214949
|
return html`<div class="empty-state">No document loaded</div>`;
|
|
@@ -214908,15 +215346,15 @@ function bindableFieldRow(label4, type2, rawValue, onChange, filterFn = null, ex
|
|
|
214908
215346
|
const isBound = typeof rawValue === "object" && rawValue !== null && rawValue.$ref;
|
|
214909
215347
|
const signalDefs = Object.entries(defs).filter(([, d5]) => filterFn ? filterFn(d5) : !d5.$handler && d5.$prototype !== "Function");
|
|
214910
215348
|
let debounce;
|
|
214911
|
-
const
|
|
215349
|
+
const onInput2 = (e20) => {
|
|
214912
215350
|
clearTimeout(debounce);
|
|
214913
215351
|
debounce = setTimeout(() => onChange(e20.target.value), 400);
|
|
214914
215352
|
};
|
|
214915
215353
|
const staticVal = isBound ? "" : rawValue ?? "";
|
|
214916
|
-
const staticTpl = type2 === "textarea" ? html`<sp-textfield multiline size="s" value=${staticVal} @input=${
|
|
215354
|
+
const staticTpl = type2 === "textarea" ? html`<sp-textfield multiline size="s" value=${staticVal} @input=${onInput2}></sp-textfield>` : type2 === "checkbox" ? html`<sp-checkbox
|
|
214917
215355
|
?checked=${!!staticVal}
|
|
214918
215356
|
@change=${(e20) => onChange(e20.target.checked)}
|
|
214919
|
-
></sp-checkbox>` : html`<sp-textfield size="s" value=${staticVal} @input=${
|
|
215357
|
+
></sp-checkbox>` : html`<sp-textfield size="s" value=${staticVal} @input=${onInput2}></sp-textfield>`;
|
|
214920
215358
|
const boundTpl = html`
|
|
214921
215359
|
<sp-picker
|
|
214922
215360
|
size="s"
|
|
@@ -216763,7 +217201,7 @@ function _render() {
|
|
|
216763
217201
|
const tab = view.leftTab;
|
|
216764
217202
|
let content3;
|
|
216765
217203
|
if (tab === "layers")
|
|
216766
|
-
content3 = ctx.getCanvasMode() === "
|
|
217204
|
+
content3 = ctx.getCanvasMode() === "stylebook" ? renderStylebookLayersTemplate({
|
|
216767
217205
|
selectStylebookTag,
|
|
216768
217206
|
stylebookMeta: stylebook_meta_default
|
|
216769
217207
|
}) : renderLayersTemplate({
|
|
@@ -216825,7 +217263,7 @@ function _render() {
|
|
|
216825
217263
|
else
|
|
216826
217264
|
content3 = nothing;
|
|
216827
217265
|
render2(html`<div class="panel-body">${content3}</div>`, leftPanel);
|
|
216828
|
-
if (tab === "layers" && ctx.getCanvasMode() !== "
|
|
217266
|
+
if (tab === "layers" && ctx.getCanvasMode() !== "stylebook")
|
|
216829
217267
|
ctx.registerLayersDnD();
|
|
216830
217268
|
else if (tab === "imports") {} else if (tab === "blocks") {
|
|
216831
217269
|
ctx.registerElementsDnD();
|
|
@@ -216840,10 +217278,10 @@ function _render() {
|
|
|
216840
217278
|
// src/panels/tab-strip.js
|
|
216841
217279
|
init_reactivity();
|
|
216842
217280
|
init_workspace();
|
|
216843
|
-
var
|
|
217281
|
+
var _host2 = null;
|
|
216844
217282
|
var _scope7 = null;
|
|
216845
217283
|
function mount8(host2) {
|
|
216846
|
-
|
|
217284
|
+
_host2 = host2;
|
|
216847
217285
|
_scope7 = effectScope();
|
|
216848
217286
|
_scope7.run(() => {
|
|
216849
217287
|
effect(() => {
|
|
@@ -216858,10 +217296,10 @@ function mount8(host2) {
|
|
|
216858
217296
|
});
|
|
216859
217297
|
}
|
|
216860
217298
|
function render10() {
|
|
216861
|
-
if (!
|
|
217299
|
+
if (!_host2)
|
|
216862
217300
|
return;
|
|
216863
217301
|
if (workspace.tabOrder.length <= 1) {
|
|
216864
|
-
render2(nothing,
|
|
217302
|
+
render2(nothing, _host2);
|
|
216865
217303
|
return;
|
|
216866
217304
|
}
|
|
216867
217305
|
render2(html`
|
|
@@ -216900,7 +217338,7 @@ function render10() {
|
|
|
216900
217338
|
`;
|
|
216901
217339
|
})}
|
|
216902
217340
|
</div>
|
|
216903
|
-
`,
|
|
217341
|
+
`, _host2);
|
|
216904
217342
|
}
|
|
216905
217343
|
function tabLabel(tab) {
|
|
216906
217344
|
const path2 = tab.documentPath;
|
|
@@ -217056,7 +217494,7 @@ mount5(toolbarEl, {
|
|
|
217056
217494
|
navigateBack: () => navigateBack(),
|
|
217057
217495
|
closeFunctionEditor: () => closeFunctionEditor(),
|
|
217058
217496
|
openProject: () => openProject2(),
|
|
217059
|
-
|
|
217497
|
+
openRecentProject: (root3) => openRecentProject(root3),
|
|
217060
217498
|
saveFile: () => saveFile(),
|
|
217061
217499
|
parseMediaEntries,
|
|
217062
217500
|
getCanvasMode,
|
|
@@ -217064,6 +217502,7 @@ mount5(toolbarEl, {
|
|
|
217064
217502
|
renderCanvas: () => renderCanvas(),
|
|
217065
217503
|
safeRenderRightPanel: () => safeRenderRightPanel()
|
|
217066
217504
|
});
|
|
217505
|
+
initQuickSearch();
|
|
217067
217506
|
mount8(document.querySelector("#tab-strip"));
|
|
217068
217507
|
mount3({
|
|
217069
217508
|
getCanvasMode,
|
|
@@ -217284,6 +217723,51 @@ function openProject2() {
|
|
|
217284
217723
|
renderLeftPanel
|
|
217285
217724
|
});
|
|
217286
217725
|
}
|
|
217726
|
+
async function openRecentProject(root3) {
|
|
217727
|
+
try {
|
|
217728
|
+
const platform4 = getPlatform();
|
|
217729
|
+
platform4.projectRoot = root3;
|
|
217730
|
+
const content3 = await platform4.readFile("project.json");
|
|
217731
|
+
const config = JSON.parse(content3);
|
|
217732
|
+
replaceAllTabs({ id: "initial", document: { tagName: "div", children: [] } });
|
|
217733
|
+
setProjectState({
|
|
217734
|
+
...projectState,
|
|
217735
|
+
projectRoot: root3,
|
|
217736
|
+
isSiteProject: true,
|
|
217737
|
+
projectConfig: config,
|
|
217738
|
+
name: config.name || root3.split("/").pop(),
|
|
217739
|
+
dirs: new Map,
|
|
217740
|
+
expanded: new Set,
|
|
217741
|
+
selectedPath: null,
|
|
217742
|
+
searchQuery: ""
|
|
217743
|
+
});
|
|
217744
|
+
await loadDirectory(".");
|
|
217745
|
+
await loadComponentRegistry();
|
|
217746
|
+
const conventionalDirs = [
|
|
217747
|
+
"pages",
|
|
217748
|
+
"layouts",
|
|
217749
|
+
"components",
|
|
217750
|
+
"content",
|
|
217751
|
+
"data",
|
|
217752
|
+
"public",
|
|
217753
|
+
"styles"
|
|
217754
|
+
];
|
|
217755
|
+
const entries2 = projectState.dirs.get(".") || [];
|
|
217756
|
+
for (const e20 of entries2) {
|
|
217757
|
+
if (e20.type === "directory" && conventionalDirs.includes(e20.name)) {
|
|
217758
|
+
projectState.expanded.add(e20.path || e20.name);
|
|
217759
|
+
await loadDirectory(e20.path || e20.name);
|
|
217760
|
+
}
|
|
217761
|
+
}
|
|
217762
|
+
addRecentProject(projectState.name, root3);
|
|
217763
|
+
view.leftTab = "files";
|
|
217764
|
+
renderActivityBar();
|
|
217765
|
+
renderLeftPanel();
|
|
217766
|
+
statusMessage(`Opened project: ${projectState.name}`);
|
|
217767
|
+
} catch (e20) {
|
|
217768
|
+
statusMessage(`Error: ${e20.message}`);
|
|
217769
|
+
}
|
|
217770
|
+
}
|
|
217287
217771
|
function renderFilesTemplate2() {
|
|
217288
217772
|
return renderFilesTemplate({ openProject: openProject2, openFileFromTree, renderLeftPanel });
|
|
217289
217773
|
}
|
|
@@ -217340,5 +217824,5 @@ effect(() => {
|
|
|
217340
217824
|
scheduleAutosave();
|
|
217341
217825
|
});
|
|
217342
217826
|
|
|
217343
|
-
//# debugId=
|
|
217827
|
+
//# debugId=2C5B0A9299ACFF5964756E2164756E21
|
|
217344
217828
|
//# sourceMappingURL=studio.js.map
|