create-kywi-app 0.6.5 → 0.6.6

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.
@@ -272,7 +272,7 @@ authored elsewhere in the admin).
272
272
  | `name` | Purpose |
273
273
  |---|---|
274
274
  | `variantContainer` | Module-level arms revealed client-side per audience — read §8 first |
275
- | `personalizationBadge` | Mount point for the "you're seeing X" transparency control |
275
+ | `personalizationBadge` | Optional inline status pill that opens the global transparency panel — not needed on ordinary pages (§8) |
276
276
  | `socialShare` | Share links for a URL/title across networks |
277
277
  | `map` | Embedded map at a lat/lng or address |
278
278
  | `cookieConsent` | Consent banner with message + privacy-policy link |
@@ -410,12 +410,44 @@ Four traps, each of which fails silently:
410
410
  audience arm first, so a visitor who matches an audience never enters the
411
411
  split. Don't run an experiment and an audience variant on the same container.
412
412
  4. **The client runtime needs `/kywi.js`.** Self-ID, behavioral re-evaluation
413
- and the transparency badge no-op silently unless the built
413
+ and the transparency panel no-op silently unless the built
414
414
  `@kywi-software/js` bundle is at `public/kywi.js`.
415
415
 
416
416
  Standing rule: **the default arm must be complete on its own.** It is what
417
417
  search engines, answer engines, and every opted-out visitor receive.
418
418
 
419
+ ### Transparency: automatic, not something you place
420
+
421
+ Once the client runtime is loaded, every personalized (or opted-out-with-a-
422
+ match) page grows a global transparency surface on its own — a small
423
+ collapsed pill, bottom of the page, that expands into a panel showing which
424
+ audience the page was personalized for, an audience switcher, reset-to-
425
+ automatic, and opt-out/opt-in. This is automatic and site-wide; you do not add
426
+ anything to a page to get it.
427
+
428
+ **Don't place the `personalizationBadge` module on ordinary pages.** It is a
429
+ second, optional entry point — a passive inline status pill that opens the
430
+ *same* global panel — for a spot where a deliberate, in-content link to
431
+ personalization settings makes sense (a privacy or preferences page). It
432
+ carries no opt-out controls of its own; switching audience and opting out
433
+ always happen in the one global panel, never in two places that could
434
+ disagree. Placing it on every page is redundant with the surface that's
435
+ already there automatically.
436
+
437
+ `personalization.transparencyNotice.enabled: false` (theme config) suppresses
438
+ the automatic panel from appearing on its own; the badge (or the panel's own
439
+ programmatic open) still works as a deliberate opt-in path.
440
+
441
+ ### Self-ID widget: all six display modes
442
+
443
+ The self-ID widget (Admin → Audiences) is authorable in six display modes:
444
+ `modal`, `inline`, `slide-in`, `hello_bar_top`, `hello_bar_bottom`, and
445
+ `drawer`. For `inline`, the client runtime mounts the widget into an element
446
+ matching `[data-kywi-selfid-mount]` when the page provides one; otherwise it
447
+ appends to the end of `<body>`. Give an inline placement its own mount point
448
+ when you want the widget to sit in a specific spot in the page flow rather
449
+ than wherever the runtime defaults to.
450
+
419
451
  ## 9. Editorial workflow: drafts, review, versions
420
452
 
421
453
  For any site with more than one author — or an owner who wants a safety net —
package/lib/templates.mjs CHANGED
@@ -779,6 +779,20 @@ export function clientRuntimeEnabled(): boolean {
779
779
  return theme?.personalization?.clientRuntime === true
780
780
  }
781
781
 
782
+ /**
783
+ * Is the global transparency surface (the automatic pill/panel showing which
784
+ * audience the page was personalized for, with a switcher and opt-out) enabled
785
+ * for this site's theme? \`personalization.transparencyNotice.enabled\` — unset
786
+ * defaults to true; only an explicit \`false\` suppresses the surface from
787
+ * appearing on its own. Even then a \`personalizationBadge\` module can still
788
+ * open it deliberately.
789
+ */
790
+ export function transparencyNoticeEnabled(): boolean {
791
+ const themeName = config.sites[0]?.theme
792
+ const theme = config.themes.find((t) => t.name === themeName) ?? config.themes[0]
793
+ return theme?.personalization?.transparencyNotice?.enabled !== false
794
+ }
795
+
782
796
  // ─── Self-ID widget (#50) ────────────────────────────────────────────────────
783
797
 
784
798
  /** The self-ID widget config in the serializable shape the client runtime reads. */
@@ -1236,6 +1250,7 @@ import {
1236
1250
  personalizeLayout,
1237
1251
  resolveSelfIdWidget,
1238
1252
  clientRuntimeEnabled,
1253
+ transparencyNoticeEnabled,
1239
1254
  buildFeedResolver,
1240
1255
  buildComponentResolver,
1241
1256
  buildSectionComponentResolver,
@@ -1368,6 +1383,7 @@ export default async function PublicPage({ params, searchParams }: Params & Sear
1368
1383
  audiences={perso.audiences}
1369
1384
  serverSignals={perso.signals}
1370
1385
  selfIdWidget={selfIdWidget}
1386
+ transparencyNotice={transparencyNoticeEnabled()}
1371
1387
  />
1372
1388
  ) : null}
1373
1389
  </>
@@ -1696,6 +1712,12 @@ interface PersonalizationRuntimeProps {
1696
1712
  serverSignals: Partial<VisitorSignals>
1697
1713
  /** Resolved self-ID widget config; when present its trigger/frequency mount it. */
1698
1714
  selfIdWidget?: PublicSelfIdWidget | null
1715
+ /**
1716
+ * \`personalization.transparencyNotice.enabled\` — false suppresses the
1717
+ * automatic global transparency panel; the visitor can still open it
1718
+ * deliberately through a \`personalizationBadge\` module. Defaults to true.
1719
+ */
1720
+ transparencyNotice?: boolean
1699
1721
  }
1700
1722
 
1701
1723
  /**
@@ -1704,7 +1726,7 @@ interface PersonalizationRuntimeProps {
1704
1726
  * experience, so opt-out is respected end to end. Rendered only when
1705
1727
  * theme.personalization.clientRuntime is on.
1706
1728
  */
1707
- export function PersonalizationRuntime({ audiences, serverSignals, selfIdWidget }: PersonalizationRuntimeProps) {
1729
+ export function PersonalizationRuntime({ audiences, serverSignals, selfIdWidget, transparencyNotice }: PersonalizationRuntimeProps) {
1708
1730
  useEffect(() => {
1709
1731
  let cancelled = false
1710
1732
  const ready = () => typeof window.Kywi?.bootAudienceEngine === 'function'
@@ -1720,6 +1742,7 @@ export function PersonalizationRuntime({ audiences, serverSignals, selfIdWidget
1720
1742
  ...(selfIdWidget
1721
1743
  ? { selfIdWidget: { ...selfIdWidget, audiences, currentPath } }
1722
1744
  : {}),
1745
+ ...(transparencyNotice === false ? { transparencyNotice: false } : {}),
1723
1746
  })
1724
1747
  .catch(() => {
1725
1748
  /* client personalization is best-effort; the server already rendered defaults */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-kywi-app",
3
- "version": "0.6.5",
3
+ "version": "0.6.6",
4
4
  "description": "Scaffold a new Kywi CMS project — npx create-kywi-app my-site",
5
5
  "type": "module",
6
6
  "homepage": "https://github.com/Kywi-Software/kywi-cms#readme",