@cosmicdrift/kumiko-bundled-features 0.182.0 → 0.182.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-bundled-features",
3
- "version": "0.182.0",
3
+ "version": "0.182.1",
4
4
  "description": "Built-in features — tenant, user, auth, delivery. The stuff you'd rewrite anyway, already typed.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -121,12 +121,12 @@
121
121
  "./step-dispatcher": "./src/step-dispatcher/index.ts"
122
122
  },
123
123
  "dependencies": {
124
- "@cosmicdrift/kumiko-dispatcher-live": "0.182.0",
125
- "@cosmicdrift/kumiko-framework": "0.182.0",
126
- "@cosmicdrift/kumiko-headless": "0.182.0",
127
- "@cosmicdrift/kumiko-renderer": "0.182.0",
128
- "@cosmicdrift/kumiko-renderer-web": "0.182.0",
129
- "@cosmicdrift/kumiko-types": "0.182.0",
124
+ "@cosmicdrift/kumiko-dispatcher-live": "0.182.1",
125
+ "@cosmicdrift/kumiko-framework": "0.182.1",
126
+ "@cosmicdrift/kumiko-headless": "0.182.1",
127
+ "@cosmicdrift/kumiko-renderer": "0.182.1",
128
+ "@cosmicdrift/kumiko-renderer-web": "0.182.1",
129
+ "@cosmicdrift/kumiko-types": "0.182.1",
130
130
  "@mollie/api-client": "^4.5.0",
131
131
  "imapflow": "^1.3.3",
132
132
  "mailparser": "^3.9.8",
@@ -19,6 +19,7 @@ import type {
19
19
  } from "@cosmicdrift/kumiko-framework/engine";
20
20
  import {
21
21
  CONTENT_EDITOR_ELEMENT_ID,
22
+ ContentPreview,
22
23
  type FeatureSchema,
23
24
  useAppFeatures,
24
25
  useContentEditor,
@@ -224,12 +225,21 @@ function findVariableSchema(
224
225
  features: readonly FeatureSchema[],
225
226
  collectionId?: string,
226
227
  ): readonly string[] {
227
- if (collectionId === undefined) return [];
228
+ return Object.keys(findVariableExamples(features, collectionId));
229
+ }
230
+
231
+ // Same lookup, for the example values the Preview substitutes in for
232
+ // `{{name}}` — the values half of the same variableSchema map.
233
+ function findVariableExamples(
234
+ features: readonly FeatureSchema[],
235
+ collectionId?: string,
236
+ ): Readonly<Record<string, string>> {
237
+ if (collectionId === undefined) return {};
228
238
  for (const feature of features) {
229
239
  const match = feature.contentCollections?.find((c) => c.id === collectionId);
230
- if (match !== undefined) return Object.keys(match.variableSchema ?? {});
240
+ if (match !== undefined) return match.variableSchema ?? {};
231
241
  }
232
- return [];
242
+ return {};
233
243
  }
234
244
 
235
245
  // Edit form: loads the current values via by-slug, lets TenantAdmin and
@@ -278,6 +288,7 @@ function TextBlockEditor({
278
288
  const features = useAppFeatures();
279
289
  const contentFormat = findContentFormat(features, collectionId);
280
290
  const variables = findVariableSchema(features, collectionId);
291
+ const variableExamples = findVariableExamples(features, collectionId);
281
292
  const ContentEditor = useContentEditor(contentFormat);
282
293
  const canWrite =
283
294
  user?.roles.includes("TenantAdmin") === true || user?.roles.includes("SystemAdmin") === true;
@@ -302,6 +313,7 @@ function TextBlockEditor({
302
313
 
303
314
  const [title, setTitle] = useState("");
304
315
  const [content, setContent] = useState("");
316
+ const [previewing, setPreviewing] = useState(false);
305
317
  const [submitting, setSubmitting] = useState(false);
306
318
  const [saveError, setSaveError] = useState<string | null>(null);
307
319
  const [savedMsg, setSavedMsg] = useState<string | null>(null);
@@ -390,13 +402,34 @@ function TextBlockEditor({
390
402
  required
391
403
  />
392
404
  </Field>
393
- <Field id={CONTENT_EDITOR_ELEMENT_ID} label={t("template-resolver.editor.contentLabel")}>
394
- <ContentEditor
395
- value={content}
396
- onChange={setContent}
397
- variables={variables}
398
- readOnly={disabled}
399
- />
405
+ <Field
406
+ id={CONTENT_EDITOR_ELEMENT_ID}
407
+ label={t("template-resolver.editor.contentLabel")}
408
+ labelAppendix={
409
+ <Button
410
+ type="button"
411
+ variant="secondary"
412
+ size="sm"
413
+ onClick={() => setPreviewing((p) => !p)}
414
+ >
415
+ {previewing ? t("kumiko.contentEditor.editMode") : t("kumiko.contentEditor.preview")}
416
+ </Button>
417
+ }
418
+ >
419
+ {previewing ? (
420
+ <ContentPreview
421
+ content={content}
422
+ variables={variableExamples}
423
+ contentFormat={contentFormat}
424
+ />
425
+ ) : (
426
+ <ContentEditor
427
+ value={content}
428
+ onChange={setContent}
429
+ variables={variables}
430
+ readOnly={disabled}
431
+ />
432
+ )}
400
433
  </Field>
401
434
  {saveError !== null && <Banner variant="error">{saveError}</Banner>}
402
435
  {savedMsg !== null && <Banner variant="info">{savedMsg}</Banner>}