@isaiahiroko/tilmart-ngx-apps-admin 0.2.0 → 0.2.2

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.
Files changed (107) hide show
  1. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-articles.module-OeLRnPwN.mjs → isaiahiroko-tilmart-ngx-apps-admin-articles.module-Cpx9BZcg.mjs} +5 -5
  2. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-articles.module-OeLRnPwN.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-articles.module-Cpx9BZcg.mjs.map} +1 -1
  3. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-attribute-templates.module-CwQnW1cH.mjs +239 -0
  4. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-attribute-templates.module-CwQnW1cH.mjs.map +1 -0
  5. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-audit.module-C9gvw8X2.mjs → isaiahiroko-tilmart-ngx-apps-admin-audit.module-D5YaCThD.mjs} +6 -6
  6. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-audit.module-C9gvw8X2.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-audit.module-D5YaCThD.mjs.map} +1 -1
  7. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-banners.module-KSapnx6Y.mjs +76 -0
  8. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-banners.module-KSapnx6Y.mjs.map +1 -0
  9. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-brands.module-7I0ni-tQ.mjs +70 -0
  10. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-brands.module-7I0ni-tQ.mjs.map +1 -0
  11. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-catalog.module-DoxDNaNn.mjs +538 -0
  12. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-catalog.module-DoxDNaNn.mjs.map +1 -0
  13. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-categories.module-OTUfenf0.mjs +94 -0
  14. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-categories.module-OTUfenf0.mjs.map +1 -0
  15. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-claims.module-Dk9mz7Wj.mjs +137 -0
  16. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-claims.module-Dk9mz7Wj.mjs.map +1 -0
  17. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-xN-JUWwp.mjs → isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-JiFnNJj_.mjs} +6 -6
  18. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-xN-JUWwp.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-JiFnNJj_.mjs.map} +1 -1
  19. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-content.module-DLdKAUqc.mjs → isaiahiroko-tilmart-ngx-apps-admin-content.module-Bx6Zj0WX.mjs} +5 -5
  20. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-content.module-DLdKAUqc.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-content.module-Bx6Zj0WX.mjs.map} +1 -1
  21. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CoRh6Hxq.mjs +85 -0
  22. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CoRh6Hxq.mjs.map +1 -0
  23. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-customers.module-CslGiOdq.mjs +123 -0
  24. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-customers.module-CslGiOdq.mjs.map +1 -0
  25. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-data-quality.module-Bfgh3zE5.mjs → isaiahiroko-tilmart-ngx-apps-admin-data-quality.module-CvFmMoJe.mjs} +6 -6
  26. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-data-quality.module-Bfgh3zE5.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-data-quality.module-CvFmMoJe.mjs.map} +1 -1
  27. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-data-requests.module-C6tPNlup.mjs → isaiahiroko-tilmart-ngx-apps-admin-data-requests.module-CuZwNVPO.mjs} +6 -6
  28. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-data-requests.module-C6tPNlup.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-data-requests.module-CuZwNVPO.mjs.map} +1 -1
  29. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-flash-sales.module-BPRnC17l.mjs +83 -0
  30. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-flash-sales.module-BPRnC17l.mjs.map +1 -0
  31. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-homepage.module-BZ3UmxE3.mjs → isaiahiroko-tilmart-ngx-apps-admin-homepage.module-vtAoIwSu.mjs} +5 -5
  32. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-homepage.module-BZ3UmxE3.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-homepage.module-vtAoIwSu.mjs.map} +1 -1
  33. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-inbox.module-BZDTa1L-.mjs → isaiahiroko-tilmart-ngx-apps-admin-inbox.module-CRkfjWQT.mjs} +6 -6
  34. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-inbox.module-BZDTa1L-.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-inbox.module-CRkfjWQT.mjs.map} +1 -1
  35. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-list-page.base-Cl7JZ-Tp.mjs +66 -0
  36. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-list-page.base-Cl7JZ-Tp.mjs.map +1 -0
  37. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-macros.module-BO4bdER2.mjs → isaiahiroko-tilmart-ngx-apps-admin-macros.module-CElxL9W4.mjs} +5 -5
  38. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-macros.module-BO4bdER2.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-macros.module-CElxL9W4.mjs.map} +1 -1
  39. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-moderation.module-CZOCrias.mjs → isaiahiroko-tilmart-ngx-apps-admin-moderation.module-PGmFX7nk.mjs} +6 -6
  40. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-moderation.module-CZOCrias.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-moderation.module-PGmFX7nk.mjs.map} +1 -1
  41. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-navigation.module-DoKzzRgn.mjs → isaiahiroko-tilmart-ngx-apps-admin-navigation.module-De1Cvqqa.mjs} +6 -6
  42. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-navigation.module-DoKzzRgn.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-navigation.module-De1Cvqqa.mjs.map} +1 -1
  43. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-order-board.module-DIOjhptn.mjs → isaiahiroko-tilmart-ngx-apps-admin-order-board.module-CmLNiEEP.mjs} +4 -4
  44. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-order-board.module-DIOjhptn.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-order-board.module-CmLNiEEP.mjs.map} +1 -1
  45. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-orders.module-Ddw49QW0.mjs → isaiahiroko-tilmart-ngx-apps-admin-orders.module-Cfeb0QjH.mjs} +15 -33
  46. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-orders.module-Cfeb0QjH.mjs.map +1 -0
  47. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payments.module-DstLDYM7.mjs +114 -0
  48. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payments.module-DstLDYM7.mjs.map +1 -0
  49. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-promotions.module-DG03OY1q.mjs +94 -0
  50. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-promotions.module-DG03OY1q.mjs.map +1 -0
  51. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-queues.module-K-zYYVFy.mjs → isaiahiroko-tilmart-ngx-apps-admin-queues.module-D7iLwX0A.mjs} +6 -6
  52. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-queues.module-K-zYYVFy.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-queues.module-D7iLwX0A.mjs.map} +1 -1
  53. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-redirects.module-oQw5Xo5T.mjs +78 -0
  54. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-redirects.module-oQw5Xo5T.mjs.map +1 -0
  55. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-referrals.module-QLNhuh7q.mjs → isaiahiroko-tilmart-ngx-apps-admin-referrals.module-BIAY4L_u.mjs} +9 -34
  56. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-referrals.module-BIAY4L_u.mjs.map +1 -0
  57. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-reports.module-DBZov0We.mjs → isaiahiroko-tilmart-ngx-apps-admin-reports.module-DORiIVLQ.mjs} +5 -5
  58. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-reports.module-DBZov0We.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-reports.module-DORiIVLQ.mjs.map} +1 -1
  59. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-returns.module-C9Iu9CX6.mjs +163 -0
  60. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-returns.module-C9Iu9CX6.mjs.map +1 -0
  61. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-routes.module-CGBBHwId.mjs +81 -0
  62. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-routes.module-CGBBHwId.mjs.map +1 -0
  63. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-settings.module-Cz6xPNwB.mjs +318 -0
  64. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-settings.module-Cz6xPNwB.mjs.map +1 -0
  65. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-shipments.module-XuaOKr8v.mjs → isaiahiroko-tilmart-ngx-apps-admin-shipments.module-Cs5CLamm.mjs} +13 -32
  66. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-shipments.module-Cs5CLamm.mjs.map +1 -0
  67. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-simple-crud.base-C8SPw14H.mjs +140 -0
  68. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-simple-crud.base-C8SPw14H.mjs.map +1 -0
  69. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-stock.module-Bt9W1oGR.mjs +102 -0
  70. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-stock.module-Bt9W1oGR.mjs.map +1 -0
  71. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-trace.module-Pwr-82Rc.mjs → isaiahiroko-tilmart-ngx-apps-admin-trace.module-9sRlGZCC.mjs} +6 -6
  72. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-trace.module-Pwr-82Rc.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-trace.module-9sRlGZCC.mjs.map} +1 -1
  73. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-users.module-Bx_7fI2g.mjs → isaiahiroko-tilmart-ngx-apps-admin-users.module-C31RJJJ_.mjs} +9 -34
  74. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-users.module-C31RJJJ_.mjs.map +1 -0
  75. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin.mjs +96 -72
  76. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin.mjs.map +1 -1
  77. package/package.json +1 -1
  78. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-baskets.module-_lHPl1dT.mjs +0 -294
  79. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-baskets.module-_lHPl1dT.mjs.map +0 -1
  80. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-catalog.module-Bvx2tVOi.mjs +0 -224
  81. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-catalog.module-Bvx2tVOi.mjs.map +0 -1
  82. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-claims.module-Ccsd8Yx3.mjs +0 -106
  83. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-claims.module-Ccsd8Yx3.mjs.map +0 -1
  84. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CQNCSlsd.mjs +0 -106
  85. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CQNCSlsd.mjs.map +0 -1
  86. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-customers.module-12XdV9zo.mjs +0 -106
  87. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-customers.module-12XdV9zo.mjs.map +0 -1
  88. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-orders.module-Ddw49QW0.mjs.map +0 -1
  89. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payments.module-BhqAtTZs.mjs +0 -106
  90. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payments.module-BhqAtTZs.mjs.map +0 -1
  91. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-procurement.module-qXW-g0pf.mjs +0 -274
  92. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-procurement.module-qXW-g0pf.mjs.map +0 -1
  93. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-promotions.module-DG9uTDqX.mjs +0 -106
  94. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-promotions.module-DG9uTDqX.mjs.map +0 -1
  95. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-redirects.module-Hm2dO_bC.mjs +0 -106
  96. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-redirects.module-Hm2dO_bC.mjs.map +0 -1
  97. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-referrals.module-QLNhuh7q.mjs.map +0 -1
  98. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-returns.module-Bd2gdo6_.mjs +0 -106
  99. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-returns.module-Bd2gdo6_.mjs.map +0 -1
  100. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-routes.module-BkVY06ci.mjs +0 -105
  101. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-routes.module-BkVY06ci.mjs.map +0 -1
  102. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-settings.module-DKeZTldO.mjs +0 -222
  103. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-settings.module-DKeZTldO.mjs.map +0 -1
  104. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-shipments.module-XuaOKr8v.mjs.map +0 -1
  105. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-stock.module-DYiAkF7E.mjs +0 -107
  106. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-stock.module-DYiAkF7E.mjs.map +0 -1
  107. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-users.module-Bx_7fI2g.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-xN-JUWwp.mjs","sources":["../../../projects/admin/src/lib/pages/compatibility-rules/compatibility-rules.component.ts","../../../projects/admin/src/lib/pages/compatibility-rules/compatibility-rules.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { BaseDirective, notify, using } from '@thescaffold/ngx-core';\nimport { BehaviorSubject, takeUntil, map } from 'rxjs';\n\ninterface RuleRowVm {\n id: string;\n name: string;\n scope: string;\n kind: string;\n outcome: string;\n message: string;\n enabled: boolean;\n configText: string;\n saving: boolean;\n}\n\n// P1.16 — CAT-10's \"editable by ops without code\". P1.11 deliberately\n// implements a **fixed, named vocabulary** of rule kinds\n// (`CompatibilityRuleKind`) rather than a generic condition-expression\n// interpreter — see `pkg/catalog-workflow/compatibility.ts`'s own doc\n// comment for why. That architecture decision sets this editor's real\n// shape: ops can toggle a rule on/off, edit its ops-facing message/scope,\n// and tune its `config` (currently only\n// `array_power_vs_inverter_rating`'s `overSizingAllowancePct`) — not\n// build new conditions from scratch. `expression.kind` itself is shown\n// read-only for the same reason: changing it would point the row at a\n// different evaluator with a config shape it doesn't understand.\n//\n// `config` is edited as raw JSON text rather than a bespoke per-kind\n// form — six kinds, most with no config at all, doesn't yet justify a\n// dynamic form-per-kind generator; the field is validated as JSON before\n// save and the request is rejected client-side (with a clear message) if\n// it doesn't parse.\n@Component({\n standalone: false,\n selector: 'x-compatibility-rules',\n template: `\n <div class=\"x-page-head\">\n <div class=\"x-page-title\">Compatibility rules</div>\n <div class=\"x-page-subtitle\">\n CAT-10 — toggle, retitle and tune the rules\n <code>CatalogWorkflow.evaluateCompatibility</code> runs on every\n PDP/cart/kit-builder check. The rule <em>kind</em> is fixed per row;\n see the note in this page's source for why.\n </div>\n </div>\n\n @if (rules$ | async; as rules) {\n <div class=\"x-rules-table\">\n <div class=\"x-rules-row x-rules-head\">\n <div class=\"x-rules-col-name\">Rule</div>\n <div class=\"x-rules-col-kind\">Kind</div>\n <div class=\"x-rules-col-outcome\">Outcome</div>\n <div class=\"x-rules-col-config\">Config (JSON)</div>\n <div class=\"x-rules-col-enabled\">Enabled</div>\n <div class=\"x-rules-col-action\"></div>\n </div>\n @for (rule of rules; track rule.id) {\n <div class=\"x-rules-row\">\n <div class=\"x-rules-col-name\">\n <div class=\"x-rule-name\">{{ rule.name }}</div>\n <div class=\"x-rule-scope\">{{ rule.scope }}</div>\n <div class=\"x-rule-message\">{{ rule.message }}</div>\n </div>\n <div class=\"x-rules-col-kind\">\n <code>{{ rule.kind }}</code>\n </div>\n <div class=\"x-rules-col-outcome\">\n <span class=\"x-outcome-badge\" [class]=\"'x-outcome-' + rule.outcome\">{{\n rule.outcome\n }}</span>\n </div>\n <div class=\"x-rules-col-config\">\n <textarea\n class=\"x-config-input\"\n rows=\"2\"\n [value]=\"rule.configText\"\n (input)=\"onConfigChange(rule, $any($event.target).value)\"\n ></textarea>\n </div>\n <div class=\"x-rules-col-enabled\">\n <label class=\"x-toggle\">\n <input\n type=\"checkbox\"\n [checked]=\"rule.enabled\"\n (change)=\"onEnabledChange(rule, $any($event.target).checked)\"\n />\n <span></span>\n </label>\n </div>\n <div class=\"x-rules-col-action\">\n <button\n type=\"button\"\n class=\"x-save-btn\"\n [disabled]=\"rule.saving\"\n (click)=\"save(rule)\"\n >\n {{ rule.saving ? 'Saving…' : 'Save' }}\n </button>\n </div>\n </div>\n }\n @if (!rules.length) {\n <div class=\"x-rules-empty\">No compatibility rules seeded yet.</div>\n }\n </div>\n } @else {\n <x-element-loader></x-element-loader>\n }\n `,\n styles: [\n `\n .x-page-head {\n margin-bottom: 20px;\n }\n .x-page-title {\n font-size: 24px;\n font-weight: 800;\n color: var(--color-text);\n }\n .x-page-subtitle {\n font-size: 13.5px;\n color: var(--color-text-muted);\n margin-top: 2px;\n max-width: 640px;\n }\n .x-rules-table {\n background: var(--color-surface);\n border-radius: var(--radius-lg);\n overflow: hidden;\n }\n .x-rules-row {\n display: grid;\n grid-template-columns: 1.8fr 1.2fr 0.8fr 1.4fr 0.6fr auto;\n gap: 12px;\n align-items: start;\n padding: 14px 16px;\n border-bottom: 1px solid var(--color-border-muted);\n }\n .x-rules-row:last-child {\n border-bottom: 0;\n }\n .x-rules-head {\n font-size: 11px;\n font-weight: 800;\n text-transform: uppercase;\n letter-spacing: 0.4px;\n color: var(--color-text-muted);\n align-items: center;\n }\n .x-rule-name {\n font-size: 14px;\n font-weight: 700;\n color: var(--color-text);\n }\n .x-rule-scope {\n font-family: var(--font-mono);\n font-size: 11px;\n color: var(--color-text-muted);\n margin-top: 2px;\n }\n .x-rule-message {\n font-size: 12px;\n color: var(--color-text-muted);\n margin-top: 4px;\n line-height: 1.4;\n }\n .x-rules-col-kind code {\n font-size: 11.5px;\n color: var(--color-text-muted);\n }\n .x-outcome-badge {\n display: inline-block;\n font-size: 10.5px;\n font-weight: 800;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n padding: 2px 8px;\n border-radius: var(--radius-pill, 999px);\n border: 1px solid var(--color-border);\n color: var(--color-text-muted);\n }\n .x-outcome-block {\n color: color-mix(in srgb, var(--color-danger) 75%, black);\n border-color: var(--color-danger);\n }\n .x-outcome-warn {\n color: color-mix(in srgb, var(--color-warn) 70%, black);\n border-color: var(--color-warn);\n }\n .x-outcome-pass {\n color: color-mix(in srgb, var(--color-success) 70%, black);\n border-color: var(--color-success);\n }\n .x-config-input {\n width: 100%;\n box-sizing: border-box;\n padding: 6px 8px;\n border-radius: var(--radius-sm);\n border: 1px solid var(--color-border);\n background: var(--color-bg);\n color: var(--color-text);\n font-family: var(--font-mono);\n font-size: 11.5px;\n resize: vertical;\n }\n .x-toggle {\n position: relative;\n display: inline-block;\n width: 34px;\n height: 20px;\n }\n .x-toggle input {\n opacity: 0;\n width: 0;\n height: 0;\n }\n .x-toggle span {\n position: absolute;\n inset: 0;\n background: var(--color-border);\n border-radius: 999px;\n transition: background 0.15s ease;\n }\n .x-toggle span::before {\n content: '';\n position: absolute;\n width: 16px;\n height: 16px;\n left: 2px;\n top: 2px;\n background: var(--color-surface);\n border-radius: 50%;\n transition: transform 0.15s ease;\n }\n .x-toggle input:checked + span {\n background: var(--color-accent);\n }\n .x-toggle input:checked + span::before {\n transform: translateX(14px);\n }\n .x-save-btn {\n background: var(--color-accent);\n color: var(--color-accent-fg);\n border: 0;\n border-radius: var(--radius-sm);\n padding: 8px 12px;\n font-size: 12.5px;\n font-weight: 700;\n cursor: pointer;\n white-space: nowrap;\n }\n .x-save-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n .x-rules-empty {\n padding: 32px 16px;\n text-align: center;\n font-size: 13px;\n color: var(--color-text-muted);\n }\n `,\n ],\n})\nexport class CompatibilityRulesComponent extends BaseDirective {\n name = 'compatibility rule';\n pluralName = 'compatibility rules';\n private readonly ruleSource = this.apiService.on(\n 'apps/commerce/compatibility-rule',\n );\n\n rules$ = new BehaviorSubject<RuleRowVm[] | null>(null);\n\n override init = () => {\n this.load();\n };\n\n load() {\n this.ruleSource\n .getMany({ page: 1, perPage: 50 })\n .pipe(\n takeUntil(this.$),\n map((response: any) =>\n (response?.data ?? []).map((r: any): RuleRowVm => {\n const expression = r.expression ?? {};\n return {\n id: r.id,\n name: r.name,\n scope: r.scope ?? '',\n kind: expression.kind ?? '—',\n outcome: r.outcome,\n message: r.message,\n enabled: !!r.enabled,\n configText: JSON.stringify(expression.config ?? {}, null, 2),\n saving: false,\n };\n }),\n ),\n )\n .subscribe(using((rows) => this.rules$.next(rows)));\n }\n\n onConfigChange(rule: RuleRowVm, value: string) {\n rule.configText = value;\n }\n\n onEnabledChange(rule: RuleRowVm, checked: boolean) {\n rule.enabled = checked;\n this.save(rule);\n }\n\n save(rule: RuleRowVm) {\n let config: Record<string, unknown>;\n try {\n config = JSON.parse(rule.configText || '{}');\n } catch {\n notify(\n `${rule.name}: config isn't valid JSON — not saved`,\n 'apps.admin.compatibility-rules.config',\n 'error',\n );\n return;\n }\n\n rule.saving = true;\n this.ruleSource\n .update(rule.id, {\n enabled: rule.enabled,\n expression: { kind: rule.kind, config },\n } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using(() => {\n rule.saving = false;\n notify(\n `${rule.name} saved`,\n 'apps.admin.compatibility-rules.save',\n 'success',\n );\n }),\n );\n }\n}\n","import { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { SharedModule } from '@thescaffold/ngx-core';\nimport { ElementsModule } from '@thescaffold/ngx-ui';\nimport { CompatibilityRulesComponent } from './compatibility-rules.component';\n\n@NgModule({\n declarations: [CompatibilityRulesComponent],\n imports: [\n SharedModule,\n ElementsModule,\n RouterModule.forChild([{ path: '', component: CompatibilityRulesComponent }]),\n ],\n})\nexport class CompatibilityRulesModule {}\n"],"names":["i1"],"mappings":"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"}
1
+ {"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-JiFnNJj_.mjs","sources":["../../../projects/admin/src/lib/pages/compatibility-rules/compatibility-rules.component.ts","../../../projects/admin/src/lib/pages/compatibility-rules/compatibility-rules.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { BaseDirective, notify, using } from '@thescaffold/ngx-core';\nimport { BehaviorSubject, takeUntil, map } from 'rxjs';\n\ninterface RuleRowVm {\n id: string;\n name: string;\n scope: string;\n kind: string;\n outcome: string;\n message: string;\n enabled: boolean;\n configText: string;\n saving: boolean;\n}\n\n// P1.16 — CAT-10's \"editable by ops without code\". P1.11 deliberately\n// implements a **fixed, named vocabulary** of rule kinds\n// (`CompatibilityRuleKind`) rather than a generic condition-expression\n// interpreter — see `pkg/catalog-workflow/compatibility.ts`'s own doc\n// comment for why. That architecture decision sets this editor's real\n// shape: ops can toggle a rule on/off, edit its ops-facing message/scope,\n// and tune its `config` (currently only\n// `array_power_vs_inverter_rating`'s `overSizingAllowancePct`) — not\n// build new conditions from scratch. `expression.kind` itself is shown\n// read-only for the same reason: changing it would point the row at a\n// different evaluator with a config shape it doesn't understand.\n//\n// `config` is edited as raw JSON text rather than a bespoke per-kind\n// form — six kinds, most with no config at all, doesn't yet justify a\n// dynamic form-per-kind generator; the field is validated as JSON before\n// save and the request is rejected client-side (with a clear message) if\n// it doesn't parse.\n@Component({\n standalone: false,\n selector: 'x-compatibility-rules',\n template: `\n <div class=\"x-page-head\">\n <div class=\"x-page-title\">Compatibility rules</div>\n <div class=\"x-page-subtitle\">\n CAT-10 — toggle, retitle and tune the rules\n <code>CatalogWorkflow.evaluateCompatibility</code> runs on every\n PDP/cart/kit-builder check. The rule <em>kind</em> is fixed per row;\n see the note in this page's source for why.\n </div>\n </div>\n\n @if (rules$ | async; as rules) {\n <div class=\"x-rules-table\">\n <div class=\"x-rules-row x-rules-head\">\n <div class=\"x-rules-col-name\">Rule</div>\n <div class=\"x-rules-col-kind\">Kind</div>\n <div class=\"x-rules-col-outcome\">Outcome</div>\n <div class=\"x-rules-col-config\">Config (JSON)</div>\n <div class=\"x-rules-col-enabled\">Enabled</div>\n <div class=\"x-rules-col-action\"></div>\n </div>\n @for (rule of rules; track rule.id) {\n <div class=\"x-rules-row\">\n <div class=\"x-rules-col-name\">\n <div class=\"x-rule-name\">{{ rule.name }}</div>\n <div class=\"x-rule-scope\">{{ rule.scope }}</div>\n <div class=\"x-rule-message\">{{ rule.message }}</div>\n </div>\n <div class=\"x-rules-col-kind\">\n <code>{{ rule.kind }}</code>\n </div>\n <div class=\"x-rules-col-outcome\">\n <span class=\"x-outcome-badge\" [class]=\"'x-outcome-' + rule.outcome\">{{\n rule.outcome\n }}</span>\n </div>\n <div class=\"x-rules-col-config\">\n <textarea\n class=\"x-config-input\"\n rows=\"2\"\n [value]=\"rule.configText\"\n (input)=\"onConfigChange(rule, $any($event.target).value)\"\n ></textarea>\n </div>\n <div class=\"x-rules-col-enabled\">\n <label class=\"x-toggle\">\n <input\n type=\"checkbox\"\n [checked]=\"rule.enabled\"\n (change)=\"onEnabledChange(rule, $any($event.target).checked)\"\n />\n <span></span>\n </label>\n </div>\n <div class=\"x-rules-col-action\">\n <button\n type=\"button\"\n class=\"x-save-btn\"\n [disabled]=\"rule.saving\"\n (click)=\"save(rule)\"\n >\n {{ rule.saving ? 'Saving…' : 'Save' }}\n </button>\n </div>\n </div>\n }\n @if (!rules.length) {\n <div class=\"x-rules-empty\">No compatibility rules seeded yet.</div>\n }\n </div>\n } @else {\n <x-element-loader></x-element-loader>\n }\n `,\n styles: [\n `\n .x-page-head {\n margin-bottom: 20px;\n }\n .x-page-title {\n font-size: 24px;\n font-weight: 800;\n color: var(--color-text);\n }\n .x-page-subtitle {\n font-size: 13.5px;\n color: var(--color-text-muted);\n margin-top: 2px;\n max-width: 640px;\n }\n .x-rules-table {\n background: var(--color-surface);\n border-radius: var(--radius-lg);\n overflow: hidden;\n }\n .x-rules-row {\n display: grid;\n grid-template-columns: 1.8fr 1.2fr 0.8fr 1.4fr 0.6fr auto;\n gap: 12px;\n align-items: start;\n padding: 14px 16px;\n border-bottom: 1px solid var(--color-border-muted);\n }\n .x-rules-row:last-child {\n border-bottom: 0;\n }\n .x-rules-head {\n font-size: 11px;\n font-weight: 800;\n text-transform: uppercase;\n letter-spacing: 0.4px;\n color: var(--color-text-muted);\n align-items: center;\n }\n .x-rule-name {\n font-size: 14px;\n font-weight: 700;\n color: var(--color-text);\n }\n .x-rule-scope {\n font-family: var(--font-mono);\n font-size: 11px;\n color: var(--color-text-muted);\n margin-top: 2px;\n }\n .x-rule-message {\n font-size: 12px;\n color: var(--color-text-muted);\n margin-top: 4px;\n line-height: 1.4;\n }\n .x-rules-col-kind code {\n font-size: 11.5px;\n color: var(--color-text-muted);\n }\n .x-outcome-badge {\n display: inline-block;\n font-size: 10.5px;\n font-weight: 800;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n padding: 2px 8px;\n border-radius: var(--radius-pill, 999px);\n border: 1px solid var(--color-border);\n color: var(--color-text-muted);\n }\n .x-outcome-block {\n color: color-mix(in srgb, var(--color-danger) 75%, black);\n border-color: var(--color-danger);\n }\n .x-outcome-warn {\n color: color-mix(in srgb, var(--color-warn) 70%, black);\n border-color: var(--color-warn);\n }\n .x-outcome-pass {\n color: color-mix(in srgb, var(--color-success) 70%, black);\n border-color: var(--color-success);\n }\n .x-config-input {\n width: 100%;\n box-sizing: border-box;\n padding: 6px 8px;\n border-radius: var(--radius-sm);\n border: 1px solid var(--color-border);\n background: var(--color-bg);\n color: var(--color-text);\n font-family: var(--font-mono);\n font-size: 11.5px;\n resize: vertical;\n }\n .x-toggle {\n position: relative;\n display: inline-block;\n width: 34px;\n height: 20px;\n }\n .x-toggle input {\n opacity: 0;\n width: 0;\n height: 0;\n }\n .x-toggle span {\n position: absolute;\n inset: 0;\n background: var(--color-border);\n border-radius: 999px;\n transition: background 0.15s ease;\n }\n .x-toggle span::before {\n content: '';\n position: absolute;\n width: 16px;\n height: 16px;\n left: 2px;\n top: 2px;\n background: var(--color-surface);\n border-radius: 50%;\n transition: transform 0.15s ease;\n }\n .x-toggle input:checked + span {\n background: var(--color-accent);\n }\n .x-toggle input:checked + span::before {\n transform: translateX(14px);\n }\n .x-save-btn {\n background: var(--color-accent);\n color: var(--color-accent-fg);\n border: 0;\n border-radius: var(--radius-sm);\n padding: 8px 12px;\n font-size: 12.5px;\n font-weight: 700;\n cursor: pointer;\n white-space: nowrap;\n }\n .x-save-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n .x-rules-empty {\n padding: 32px 16px;\n text-align: center;\n font-size: 13px;\n color: var(--color-text-muted);\n }\n `,\n ],\n})\nexport class CompatibilityRulesComponent extends BaseDirective {\n name = 'compatibility rule';\n pluralName = 'compatibility rules';\n private readonly ruleSource = this.apiService.on(\n 'apps/commerce/compatibility-rule',\n );\n\n rules$ = new BehaviorSubject<RuleRowVm[] | null>(null);\n\n override init = () => {\n this.load();\n };\n\n load() {\n this.ruleSource\n .getMany({ page: 1, perPage: 50 })\n .pipe(\n takeUntil(this.$),\n map((response: any) =>\n (response?.data ?? []).map((r: any): RuleRowVm => {\n const expression = r.expression ?? {};\n return {\n id: r.id,\n name: r.name,\n scope: r.scope ?? '',\n kind: expression.kind ?? '—',\n outcome: r.outcome,\n message: r.message,\n enabled: !!r.enabled,\n configText: JSON.stringify(expression.config ?? {}, null, 2),\n saving: false,\n };\n }),\n ),\n )\n .subscribe(using((rows) => this.rules$.next(rows)));\n }\n\n onConfigChange(rule: RuleRowVm, value: string) {\n rule.configText = value;\n }\n\n onEnabledChange(rule: RuleRowVm, checked: boolean) {\n rule.enabled = checked;\n this.save(rule);\n }\n\n save(rule: RuleRowVm) {\n let config: Record<string, unknown>;\n try {\n config = JSON.parse(rule.configText || '{}');\n } catch {\n notify(\n `${rule.name}: config isn't valid JSON — not saved`,\n 'apps.admin.compatibility-rules.config',\n 'error',\n );\n return;\n }\n\n rule.saving = true;\n this.ruleSource\n .update(rule.id, {\n enabled: rule.enabled,\n expression: { kind: rule.kind, config },\n } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using(() => {\n rule.saving = false;\n notify(\n `${rule.name} saved`,\n 'apps.admin.compatibility-rules.save',\n 'success',\n );\n }),\n );\n }\n}\n","import { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { SharedModule } from '@thescaffold/ngx-core';\nimport { ElementsModule } from '@thescaffold/ngx-ui';\nimport { CompatibilityRulesComponent } from './compatibility-rules.component';\n\n@NgModule({\n declarations: [CompatibilityRulesComponent],\n imports: [\n SharedModule,\n ElementsModule,\n RouterModule.forChild([{ path: '', component: CompatibilityRulesComponent }]),\n ],\n})\nexport class CompatibilityRulesModule {}\n"],"names":["i1","i2"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Component, NgModule } from '@angular/core';
3
- import * as i1$2 from '@angular/router';
3
+ import * as i1$1 from '@angular/router';
4
4
  import { RouterModule } from '@angular/router';
5
5
  import { BaseDirective, using, notify, SharedModule } from '@thescaffold/ngx-core';
6
- import * as i1$1 from '@thescaffold/ngx-ui';
6
+ import * as i2 from '@thescaffold/ngx-ui';
7
7
  import { ElementsModule } from '@thescaffold/ngx-ui';
8
8
  import { R as RichEditorComponent, a as RichEditorModule } from './isaiahiroko-tilmart-ngx-apps-admin-rich-editor.module-DW9Gy_QQ.mjs';
9
9
  import { takeUntil, firstValueFrom } from 'rxjs';
@@ -331,7 +331,7 @@ class ContentComponent extends BaseDirective {
331
331
  this.blockModel[field] = html ?? '';
332
332
  }
333
333
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ContentComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
334
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: ContentComponent, isStandalone: false, selector: "x-content", usesInheritance: true, ngImport: i0, template: "<div class=\"x-cms-head\">\n <div class=\"x-cms-title\">Content pages</div>\n <div class=\"x-cms-sub\">Ops-authored storefront pages \u2014 metadata and a block list per page.</div>\n</div>\n\n@if (loading) {\n <x-element-loader></x-element-loader>\n} @else {\n <div class=\"x-cms-layout\">\n <aside class=\"x-cms-list\">\n <div class=\"x-cms-new\">\n <input type=\"text\" placeholder=\"slug\" [(ngModel)]=\"newPageSlug\" />\n <input type=\"text\" placeholder=\"Title\" [(ngModel)]=\"newPageTitle\" />\n <button type=\"button\" (click)=\"createPage()\">Add page</button>\n </div>\n @for (p of pages; track p.id) {\n <button\n type=\"button\"\n class=\"x-cms-list-item\"\n [class.x-cms-list-active]=\"selected?.id === p.id\"\n (click)=\"select(p)\"\n >\n <span class=\"x-cms-list-title\">{{ p.title }}</span>\n <span class=\"x-cms-list-meta\">/{{ p.slug }} \u00B7 {{ p.status }}</span>\n </button>\n } @empty {\n <div class=\"x-cms-empty\">No pages yet.</div>\n }\n </aside>\n\n <section class=\"x-cms-editor\">\n @if (!selected) {\n <div class=\"x-cms-empty\">Pick a page, or add one.</div>\n } @else {\n <div class=\"x-cms-meta\">\n <div class=\"x-cms-f-row\">\n <label class=\"x-cms-f\">\n Title\n <input type=\"text\" [(ngModel)]=\"selected.title\" />\n </label>\n <label class=\"x-cms-f\">\n Slug\n <input type=\"text\" [(ngModel)]=\"selected.slug\" />\n </label>\n </div>\n <label class=\"x-cms-f\">\n Excerpt\n <input type=\"text\" [(ngModel)]=\"selected.excerpt\" />\n </label>\n <div class=\"x-cms-f-row\">\n <label class=\"x-cms-f\">\n Status\n <select [(ngModel)]=\"selected.status\">\n @for (s of statuses; track s) { <option [value]=\"s\">{{ s }}</option> }\n </select>\n </label>\n <label class=\"x-cms-f\">\n Template\n <select [(ngModel)]=\"selected.template\">\n @for (t of templates; track t) { <option [value]=\"t\">{{ t }}</option> }\n </select>\n </label>\n <label class=\"x-cms-f\">\n Publish at\n <input type=\"datetime-local\" [(ngModel)]=\"selected.publishAt\" />\n </label>\n </div>\n <div class=\"x-cms-meta-actions\">\n <button type=\"button\" class=\"x-cms-btn x-cms-btn-primary\" (click)=\"savePage()\">Save page</button>\n <button type=\"button\" class=\"x-cms-btn x-cms-danger\" (click)=\"deletePage()\">Delete page</button>\n </div>\n </div>\n\n <div class=\"x-cms-blocks-head\">\n <span>Blocks</span>\n <span class=\"x-cms-add-block\">\n <select [(ngModel)]=\"newBlockType\">\n @for (t of blockTypes; track t.value) { <option [value]=\"t.value\">{{ t.label }}</option> }\n </select>\n <button type=\"button\" class=\"x-cms-btn\" (click)=\"addBlock()\">Add block</button>\n </span>\n </div>\n\n @if (blocksLoading) {\n <x-element-loader></x-element-loader>\n } @else if (!orderedBlocks.length) {\n <div class=\"x-cms-empty\">No blocks on this page yet.</div>\n } @else {\n <div class=\"x-cms-blocks\">\n @for (b of orderedBlocks; track b.id; let i = $index) {\n <div\n class=\"x-cms-block\"\n [class.x-cms-block-off]=\"!b.enabled\"\n draggable=\"true\"\n (dragstart)=\"onDragStart(i)\"\n (dragover)=\"onDragOver($event)\"\n (drop)=\"onDrop(i)\"\n >\n <div class=\"x-cms-block-head\">\n <span class=\"x-cms-grip\">\u283F</span>\n <div class=\"x-cms-block-order\">\n <button type=\"button\" (click)=\"moveBlock(i, -1)\" [disabled]=\"i === 0\">\u25B2</button>\n <button type=\"button\" (click)=\"moveBlock(i, 1)\" [disabled]=\"i === orderedBlocks.length - 1\">\u25BC</button>\n </div>\n <span class=\"x-cms-block-type\">{{ blockTypeLabel(b.type) }}</span>\n <span class=\"x-cms-block-actions\">\n <button type=\"button\" class=\"x-cms-toggle\" (click)=\"toggleBlock(b)\">{{ b.enabled ? 'On' : 'Off' }}</button>\n <button type=\"button\" class=\"x-cms-link\" (click)=\"editBlock(b)\">Edit</button>\n <button type=\"button\" class=\"x-cms-link x-cms-danger\" (click)=\"removeBlock(b)\">Delete</button>\n </span>\n </div>\n\n @if (editingBlock?.id === b.id) {\n <div class=\"x-cms-block-edit\">\n @for (field of blockTypeDef(b.type)?.fields ?? []; track field.key) {\n <label class=\"x-cms-f\">\n {{ field.label }}\n @if (field.kind === 'rich') {\n @if (rawHtml) {\n <textarea rows=\"6\" [(ngModel)]=\"blockModel[field.key]\"></textarea>\n } @else {\n <x-rich-editor\n [content]=\"blockModel[field.key]\"\n (contentChange)=\"onRichChange(field.key, $event)\"\n ></x-rich-editor>\n }\n <button type=\"button\" class=\"x-cms-link\" (click)=\"rawHtml = !rawHtml\">\n {{ rawHtml ? 'Use the editor' : 'Edit raw HTML' }}\n </button>\n } @else if (field.kind === 'json') {\n <textarea rows=\"5\" [(ngModel)]=\"blockModel[field.key]\"></textarea>\n } @else {\n <input\n [type]=\"field.kind === 'num' ? 'number' : 'text'\"\n [(ngModel)]=\"blockModel[field.key]\"\n />\n }\n </label>\n }\n <div class=\"x-cms-edit-actions\">\n <button type=\"button\" class=\"x-cms-btn x-cms-btn-primary\" (click)=\"saveBlock()\">Save block</button>\n <button type=\"button\" class=\"x-cms-btn\" (click)=\"cancelBlockEdit()\">Cancel</button>\n </div>\n </div>\n }\n </div>\n }\n </div>\n }\n }\n </section>\n </div>\n}\n\n<style>\n .x-cms-head { margin-bottom: 20px; }\n .x-cms-title { font-size: 24px; font-weight: 800; color: var(--color-text); }\n .x-cms-sub { font-size: 13.5px; color: var(--color-text-muted); margin-top: 2px; }\n .x-cms-empty { font-size: 14px; color: var(--color-text-muted); padding: 12px 0; }\n .x-cms-layout { display: grid; grid-template-columns: 260px 1fr; gap: 20px; align-items: start; }\n .x-cms-list { display: flex; flex-direction: column; gap: 6px; }\n .x-cms-new { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; }\n .x-cms-new input, .x-cms-f input, .x-cms-f select, .x-cms-f textarea,\n .x-cms-add-block select {\n border: 1px solid var(--color-border); border-radius: var(--radius-md);\n padding: 6px 10px; font-size: 13px; background: var(--color-surface); color: var(--color-text);\n }\n .x-cms-new button, .x-cms-btn {\n border: 1px solid var(--color-border); background: transparent; border-radius: var(--radius-md);\n padding: 6px 14px; font-size: 12.5px; font-weight: 700; cursor: pointer; color: var(--color-text-muted);\n }\n .x-cms-btn-primary { border-color: var(--color-accent); color: var(--color-accent-hover); }\n .x-cms-list-item {\n text-align: left; border: 1px solid var(--color-border); border-radius: var(--radius-md);\n background: var(--color-surface); padding: 8px 10px; cursor: pointer;\n display: flex; flex-direction: column; gap: 2px;\n }\n .x-cms-list-active { border-color: var(--color-accent); }\n .x-cms-list-title { font-size: 13px; font-weight: 700; color: var(--color-text); }\n .x-cms-list-meta { font-size: 11px; color: var(--color-text-muted); }\n .x-cms-editor { min-width: 0; }\n .x-cms-meta {\n background: var(--color-surface); border: 1px solid var(--color-border);\n border-radius: var(--radius-lg); padding: 16px; display: flex; flex-direction: column; gap: 10px;\n margin-bottom: 20px;\n }\n .x-cms-f { display: flex; flex-direction: column; gap: 4px; flex: 1; font-size: 11.5px; color: var(--color-text-muted); font-weight: 700; }\n .x-cms-f-row { display: flex; gap: 10px; }\n .x-cms-meta-actions, .x-cms-edit-actions { display: flex; gap: 8px; }\n .x-cms-blocks-head {\n display: flex; justify-content: space-between; align-items: center;\n font-size: 13px; font-weight: 800; color: var(--color-text); margin-bottom: 10px;\n }\n .x-cms-add-block { display: flex; gap: 8px; }\n .x-cms-blocks { display: flex; flex-direction: column; gap: 10px; }\n .x-cms-block { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); padding: 12px 14px; }\n .x-cms-block-off { opacity: 0.55; }\n .x-cms-block-head { display: flex; align-items: center; gap: 10px; }\n .x-cms-grip { cursor: grab; color: var(--color-text-muted); }\n .x-cms-block-order { display: flex; flex-direction: column; }\n .x-cms-block-order button { border: 0; background: transparent; cursor: pointer; color: var(--color-text-muted); font-size: 10px; line-height: 1.1; padding: 1px 3px; }\n .x-cms-block-order button:disabled { opacity: 0.3; cursor: default; }\n .x-cms-block-type { font-weight: 800; text-transform: uppercase; letter-spacing: 0.4px; font-size: 11px; color: var(--color-accent-hover); flex: 1; }\n .x-cms-block-actions { display: flex; gap: 8px; align-items: center; }\n .x-cms-toggle { border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: transparent; padding: 3px 10px; font-size: 11.5px; font-weight: 700; cursor: pointer; color: var(--color-text-muted); }\n .x-cms-link { border: 0; background: transparent; cursor: pointer; font-size: 12px; font-weight: 700; color: var(--color-accent-hover); }\n .x-cms-danger { color: var(--color-danger, #c0362c); }\n .x-cms-block-edit { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--color-border); display: flex; flex-direction: column; gap: 10px; }\n x-rich-editor { display: block; border: 1px solid var(--color-border); border-radius: var(--radius-md); min-height: 160px; }\n</style>\n", styles: [".x-cms-head{margin-bottom:20px}.x-cms-title{font-size:24px;font-weight:800;color:var(--color-text)}.x-cms-sub{font-size:13.5px;color:var(--color-text-muted);margin-top:2px}.x-cms-empty{font-size:14px;color:var(--color-text-muted);padding:12px 0}.x-cms-layout{display:grid;grid-template-columns:260px 1fr;gap:20px;align-items:start}.x-cms-list{display:flex;flex-direction:column;gap:6px}.x-cms-new{display:flex;flex-direction:column;gap:6px;margin-bottom:10px}.x-cms-new input,.x-cms-f input,.x-cms-f select,.x-cms-f textarea,.x-cms-add-block select{border:1px solid var(--color-border);border-radius:var(--radius-md);padding:6px 10px;font-size:13px;background:var(--color-surface);color:var(--color-text)}.x-cms-new button,.x-cms-btn{border:1px solid var(--color-border);background:transparent;border-radius:var(--radius-md);padding:6px 14px;font-size:12.5px;font-weight:700;cursor:pointer;color:var(--color-text-muted)}.x-cms-btn-primary{border-color:var(--color-accent);color:var(--color-accent-hover)}.x-cms-list-item{text-align:left;border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-surface);padding:8px 10px;cursor:pointer;display:flex;flex-direction:column;gap:2px}.x-cms-list-active{border-color:var(--color-accent)}.x-cms-list-title{font-size:13px;font-weight:700;color:var(--color-text)}.x-cms-list-meta{font-size:11px;color:var(--color-text-muted)}.x-cms-editor{min-width:0}.x-cms-meta{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:16px;display:flex;flex-direction:column;gap:10px;margin-bottom:20px}.x-cms-f{display:flex;flex-direction:column;gap:4px;flex:1;font-size:11.5px;color:var(--color-text-muted);font-weight:700}.x-cms-f-row{display:flex;gap:10px}.x-cms-meta-actions,.x-cms-edit-actions{display:flex;gap:8px}.x-cms-blocks-head{display:flex;justify-content:space-between;align-items:center;font-size:13px;font-weight:800;color:var(--color-text);margin-bottom:10px}.x-cms-add-block{display:flex;gap:8px}.x-cms-blocks{display:flex;flex-direction:column;gap:10px}.x-cms-block{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:12px 14px}.x-cms-block-off{opacity:.55}.x-cms-block-head{display:flex;align-items:center;gap:10px}.x-cms-grip{cursor:grab;color:var(--color-text-muted)}.x-cms-block-order{display:flex;flex-direction:column}.x-cms-block-order button{border:0;background:transparent;cursor:pointer;color:var(--color-text-muted);font-size:10px;line-height:1.1;padding:1px 3px}.x-cms-block-order button:disabled{opacity:.3;cursor:default}.x-cms-block-type{font-weight:800;text-transform:uppercase;letter-spacing:.4px;font-size:11px;color:var(--color-accent-hover);flex:1}.x-cms-block-actions{display:flex;gap:8px;align-items:center}.x-cms-toggle{border:1px solid var(--color-border);border-radius:var(--radius-sm);background:transparent;padding:3px 10px;font-size:11.5px;font-weight:700;cursor:pointer;color:var(--color-text-muted)}.x-cms-link{border:0;background:transparent;cursor:pointer;font-size:12px;font-weight:700;color:var(--color-accent-hover)}.x-cms-danger{color:var(--color-danger, #c0362c)}.x-cms-block-edit{margin-top:12px;padding-top:12px;border-top:1px solid var(--color-border);display:flex;flex-direction:column;gap:10px}x-rich-editor{display:block;border:1px solid var(--color-border);border-radius:var(--radius-md);min-height:160px}\n"], dependencies: [{ kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i1$1.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }, { kind: "component", type: RichEditorComponent, selector: "x-rich-editor", inputs: ["content"], outputs: ["contentChange"] }] }); }
334
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: ContentComponent, isStandalone: false, selector: "x-content", usesInheritance: true, ngImport: i0, template: "<div class=\"x-cms-head\">\n <div class=\"x-cms-title\">Content pages</div>\n <div class=\"x-cms-sub\">Ops-authored storefront pages \u2014 metadata and a block list per page.</div>\n</div>\n\n@if (loading) {\n <x-element-loader></x-element-loader>\n} @else {\n <div class=\"x-cms-layout\">\n <aside class=\"x-cms-list\">\n <div class=\"x-cms-new\">\n <input type=\"text\" placeholder=\"slug\" [(ngModel)]=\"newPageSlug\" />\n <input type=\"text\" placeholder=\"Title\" [(ngModel)]=\"newPageTitle\" />\n <button type=\"button\" (click)=\"createPage()\">Add page</button>\n </div>\n @for (p of pages; track p.id) {\n <button\n type=\"button\"\n class=\"x-cms-list-item\"\n [class.x-cms-list-active]=\"selected?.id === p.id\"\n (click)=\"select(p)\"\n >\n <span class=\"x-cms-list-title\">{{ p.title }}</span>\n <span class=\"x-cms-list-meta\">/{{ p.slug }} \u00B7 {{ p.status }}</span>\n </button>\n } @empty {\n <div class=\"x-cms-empty\">No pages yet.</div>\n }\n </aside>\n\n <section class=\"x-cms-editor\">\n @if (!selected) {\n <div class=\"x-cms-empty\">Pick a page, or add one.</div>\n } @else {\n <div class=\"x-cms-meta\">\n <div class=\"x-cms-f-row\">\n <label class=\"x-cms-f\">\n Title\n <input type=\"text\" [(ngModel)]=\"selected.title\" />\n </label>\n <label class=\"x-cms-f\">\n Slug\n <input type=\"text\" [(ngModel)]=\"selected.slug\" />\n </label>\n </div>\n <label class=\"x-cms-f\">\n Excerpt\n <input type=\"text\" [(ngModel)]=\"selected.excerpt\" />\n </label>\n <div class=\"x-cms-f-row\">\n <label class=\"x-cms-f\">\n Status\n <select [(ngModel)]=\"selected.status\">\n @for (s of statuses; track s) { <option [value]=\"s\">{{ s }}</option> }\n </select>\n </label>\n <label class=\"x-cms-f\">\n Template\n <select [(ngModel)]=\"selected.template\">\n @for (t of templates; track t) { <option [value]=\"t\">{{ t }}</option> }\n </select>\n </label>\n <label class=\"x-cms-f\">\n Publish at\n <input type=\"datetime-local\" [(ngModel)]=\"selected.publishAt\" />\n </label>\n </div>\n <div class=\"x-cms-meta-actions\">\n <button type=\"button\" class=\"x-cms-btn x-cms-btn-primary\" (click)=\"savePage()\">Save page</button>\n <button type=\"button\" class=\"x-cms-btn x-cms-danger\" (click)=\"deletePage()\">Delete page</button>\n </div>\n </div>\n\n <div class=\"x-cms-blocks-head\">\n <span>Blocks</span>\n <span class=\"x-cms-add-block\">\n <select [(ngModel)]=\"newBlockType\">\n @for (t of blockTypes; track t.value) { <option [value]=\"t.value\">{{ t.label }}</option> }\n </select>\n <button type=\"button\" class=\"x-cms-btn\" (click)=\"addBlock()\">Add block</button>\n </span>\n </div>\n\n @if (blocksLoading) {\n <x-element-loader></x-element-loader>\n } @else if (!orderedBlocks.length) {\n <div class=\"x-cms-empty\">No blocks on this page yet.</div>\n } @else {\n <div class=\"x-cms-blocks\">\n @for (b of orderedBlocks; track b.id; let i = $index) {\n <div\n class=\"x-cms-block\"\n [class.x-cms-block-off]=\"!b.enabled\"\n draggable=\"true\"\n (dragstart)=\"onDragStart(i)\"\n (dragover)=\"onDragOver($event)\"\n (drop)=\"onDrop(i)\"\n >\n <div class=\"x-cms-block-head\">\n <span class=\"x-cms-grip\">\u283F</span>\n <div class=\"x-cms-block-order\">\n <button type=\"button\" (click)=\"moveBlock(i, -1)\" [disabled]=\"i === 0\">\u25B2</button>\n <button type=\"button\" (click)=\"moveBlock(i, 1)\" [disabled]=\"i === orderedBlocks.length - 1\">\u25BC</button>\n </div>\n <span class=\"x-cms-block-type\">{{ blockTypeLabel(b.type) }}</span>\n <span class=\"x-cms-block-actions\">\n <button type=\"button\" class=\"x-cms-toggle\" (click)=\"toggleBlock(b)\">{{ b.enabled ? 'On' : 'Off' }}</button>\n <button type=\"button\" class=\"x-cms-link\" (click)=\"editBlock(b)\">Edit</button>\n <button type=\"button\" class=\"x-cms-link x-cms-danger\" (click)=\"removeBlock(b)\">Delete</button>\n </span>\n </div>\n\n @if (editingBlock?.id === b.id) {\n <div class=\"x-cms-block-edit\">\n @for (field of blockTypeDef(b.type)?.fields ?? []; track field.key) {\n <label class=\"x-cms-f\">\n {{ field.label }}\n @if (field.kind === 'rich') {\n @if (rawHtml) {\n <textarea rows=\"6\" [(ngModel)]=\"blockModel[field.key]\"></textarea>\n } @else {\n <x-rich-editor\n [content]=\"blockModel[field.key]\"\n (contentChange)=\"onRichChange(field.key, $event)\"\n ></x-rich-editor>\n }\n <button type=\"button\" class=\"x-cms-link\" (click)=\"rawHtml = !rawHtml\">\n {{ rawHtml ? 'Use the editor' : 'Edit raw HTML' }}\n </button>\n } @else if (field.kind === 'json') {\n <textarea rows=\"5\" [(ngModel)]=\"blockModel[field.key]\"></textarea>\n } @else {\n <input\n [type]=\"field.kind === 'num' ? 'number' : 'text'\"\n [(ngModel)]=\"blockModel[field.key]\"\n />\n }\n </label>\n }\n <div class=\"x-cms-edit-actions\">\n <button type=\"button\" class=\"x-cms-btn x-cms-btn-primary\" (click)=\"saveBlock()\">Save block</button>\n <button type=\"button\" class=\"x-cms-btn\" (click)=\"cancelBlockEdit()\">Cancel</button>\n </div>\n </div>\n }\n </div>\n }\n </div>\n }\n }\n </section>\n </div>\n}\n\n<style>\n .x-cms-head { margin-bottom: 20px; }\n .x-cms-title { font-size: 24px; font-weight: 800; color: var(--color-text); }\n .x-cms-sub { font-size: 13.5px; color: var(--color-text-muted); margin-top: 2px; }\n .x-cms-empty { font-size: 14px; color: var(--color-text-muted); padding: 12px 0; }\n .x-cms-layout { display: grid; grid-template-columns: 260px 1fr; gap: 20px; align-items: start; }\n .x-cms-list { display: flex; flex-direction: column; gap: 6px; }\n .x-cms-new { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; }\n .x-cms-new input, .x-cms-f input, .x-cms-f select, .x-cms-f textarea,\n .x-cms-add-block select {\n border: 1px solid var(--color-border); border-radius: var(--radius-md);\n padding: 6px 10px; font-size: 13px; background: var(--color-surface); color: var(--color-text);\n }\n .x-cms-new button, .x-cms-btn {\n border: 1px solid var(--color-border); background: transparent; border-radius: var(--radius-md);\n padding: 6px 14px; font-size: 12.5px; font-weight: 700; cursor: pointer; color: var(--color-text-muted);\n }\n .x-cms-btn-primary { border-color: var(--color-accent); color: var(--color-accent-hover); }\n .x-cms-list-item {\n text-align: left; border: 1px solid var(--color-border); border-radius: var(--radius-md);\n background: var(--color-surface); padding: 8px 10px; cursor: pointer;\n display: flex; flex-direction: column; gap: 2px;\n }\n .x-cms-list-active { border-color: var(--color-accent); }\n .x-cms-list-title { font-size: 13px; font-weight: 700; color: var(--color-text); }\n .x-cms-list-meta { font-size: 11px; color: var(--color-text-muted); }\n .x-cms-editor { min-width: 0; }\n .x-cms-meta {\n background: var(--color-surface); border: 1px solid var(--color-border);\n border-radius: var(--radius-lg); padding: 16px; display: flex; flex-direction: column; gap: 10px;\n margin-bottom: 20px;\n }\n .x-cms-f { display: flex; flex-direction: column; gap: 4px; flex: 1; font-size: 11.5px; color: var(--color-text-muted); font-weight: 700; }\n .x-cms-f-row { display: flex; gap: 10px; }\n .x-cms-meta-actions, .x-cms-edit-actions { display: flex; gap: 8px; }\n .x-cms-blocks-head {\n display: flex; justify-content: space-between; align-items: center;\n font-size: 13px; font-weight: 800; color: var(--color-text); margin-bottom: 10px;\n }\n .x-cms-add-block { display: flex; gap: 8px; }\n .x-cms-blocks { display: flex; flex-direction: column; gap: 10px; }\n .x-cms-block { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); padding: 12px 14px; }\n .x-cms-block-off { opacity: 0.55; }\n .x-cms-block-head { display: flex; align-items: center; gap: 10px; }\n .x-cms-grip { cursor: grab; color: var(--color-text-muted); }\n .x-cms-block-order { display: flex; flex-direction: column; }\n .x-cms-block-order button { border: 0; background: transparent; cursor: pointer; color: var(--color-text-muted); font-size: 10px; line-height: 1.1; padding: 1px 3px; }\n .x-cms-block-order button:disabled { opacity: 0.3; cursor: default; }\n .x-cms-block-type { font-weight: 800; text-transform: uppercase; letter-spacing: 0.4px; font-size: 11px; color: var(--color-accent-hover); flex: 1; }\n .x-cms-block-actions { display: flex; gap: 8px; align-items: center; }\n .x-cms-toggle { border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: transparent; padding: 3px 10px; font-size: 11.5px; font-weight: 700; cursor: pointer; color: var(--color-text-muted); }\n .x-cms-link { border: 0; background: transparent; cursor: pointer; font-size: 12px; font-weight: 700; color: var(--color-accent-hover); }\n .x-cms-danger { color: var(--color-danger, #c0362c); }\n .x-cms-block-edit { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--color-border); display: flex; flex-direction: column; gap: 10px; }\n x-rich-editor { display: block; border: 1px solid var(--color-border); border-radius: var(--radius-md); min-height: 160px; }\n</style>\n", styles: [".x-cms-head{margin-bottom:20px}.x-cms-title{font-size:24px;font-weight:800;color:var(--color-text)}.x-cms-sub{font-size:13.5px;color:var(--color-text-muted);margin-top:2px}.x-cms-empty{font-size:14px;color:var(--color-text-muted);padding:12px 0}.x-cms-layout{display:grid;grid-template-columns:260px 1fr;gap:20px;align-items:start}.x-cms-list{display:flex;flex-direction:column;gap:6px}.x-cms-new{display:flex;flex-direction:column;gap:6px;margin-bottom:10px}.x-cms-new input,.x-cms-f input,.x-cms-f select,.x-cms-f textarea,.x-cms-add-block select{border:1px solid var(--color-border);border-radius:var(--radius-md);padding:6px 10px;font-size:13px;background:var(--color-surface);color:var(--color-text)}.x-cms-new button,.x-cms-btn{border:1px solid var(--color-border);background:transparent;border-radius:var(--radius-md);padding:6px 14px;font-size:12.5px;font-weight:700;cursor:pointer;color:var(--color-text-muted)}.x-cms-btn-primary{border-color:var(--color-accent);color:var(--color-accent-hover)}.x-cms-list-item{text-align:left;border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-surface);padding:8px 10px;cursor:pointer;display:flex;flex-direction:column;gap:2px}.x-cms-list-active{border-color:var(--color-accent)}.x-cms-list-title{font-size:13px;font-weight:700;color:var(--color-text)}.x-cms-list-meta{font-size:11px;color:var(--color-text-muted)}.x-cms-editor{min-width:0}.x-cms-meta{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:16px;display:flex;flex-direction:column;gap:10px;margin-bottom:20px}.x-cms-f{display:flex;flex-direction:column;gap:4px;flex:1;font-size:11.5px;color:var(--color-text-muted);font-weight:700}.x-cms-f-row{display:flex;gap:10px}.x-cms-meta-actions,.x-cms-edit-actions{display:flex;gap:8px}.x-cms-blocks-head{display:flex;justify-content:space-between;align-items:center;font-size:13px;font-weight:800;color:var(--color-text);margin-bottom:10px}.x-cms-add-block{display:flex;gap:8px}.x-cms-blocks{display:flex;flex-direction:column;gap:10px}.x-cms-block{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:12px 14px}.x-cms-block-off{opacity:.55}.x-cms-block-head{display:flex;align-items:center;gap:10px}.x-cms-grip{cursor:grab;color:var(--color-text-muted)}.x-cms-block-order{display:flex;flex-direction:column}.x-cms-block-order button{border:0;background:transparent;cursor:pointer;color:var(--color-text-muted);font-size:10px;line-height:1.1;padding:1px 3px}.x-cms-block-order button:disabled{opacity:.3;cursor:default}.x-cms-block-type{font-weight:800;text-transform:uppercase;letter-spacing:.4px;font-size:11px;color:var(--color-accent-hover);flex:1}.x-cms-block-actions{display:flex;gap:8px;align-items:center}.x-cms-toggle{border:1px solid var(--color-border);border-radius:var(--radius-sm);background:transparent;padding:3px 10px;font-size:11.5px;font-weight:700;cursor:pointer;color:var(--color-text-muted)}.x-cms-link{border:0;background:transparent;cursor:pointer;font-size:12px;font-weight:700;color:var(--color-accent-hover)}.x-cms-danger{color:var(--color-danger, #c0362c)}.x-cms-block-edit{margin-top:12px;padding-top:12px;border-top:1px solid var(--color-border);display:flex;flex-direction:column;gap:10px}x-rich-editor{display:block;border:1px solid var(--color-border);border-radius:var(--radius-md);min-height:160px}\n"], dependencies: [{ kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i2.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }, { kind: "component", type: RichEditorComponent, selector: "x-rich-editor", inputs: ["content"], outputs: ["contentChange"] }] }); }
335
335
  }
336
336
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ContentComponent, decorators: [{
337
337
  type: Component,
@@ -342,7 +342,7 @@ class ContentModule {
342
342
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ContentModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
343
343
  static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.16", ngImport: i0, type: ContentModule, declarations: [ContentComponent], imports: [SharedModule,
344
344
  ElementsModule,
345
- RichEditorModule, i1$2.RouterModule] }); }
345
+ RichEditorModule, i1$1.RouterModule] }); }
346
346
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ContentModule, imports: [SharedModule,
347
347
  ElementsModule,
348
348
  RichEditorModule,
@@ -362,4 +362,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
362
362
  }] });
363
363
 
364
364
  export { ContentModule };
365
- //# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-content.module-DLdKAUqc.mjs.map
365
+ //# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-content.module-Bx6Zj0WX.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-content.module-DLdKAUqc.mjs","sources":["../../../projects/admin/src/lib/pages/content/content.component.ts","../../../projects/admin/src/lib/pages/content/content.component.html","../../../projects/admin/src/lib/pages/content/content.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { BaseDirective, notify, using } from '@thescaffold/ngx-core';\nimport { firstValueFrom, takeUntil } from 'rxjs';\n\ninterface PageVm {\n id: string;\n slug: string;\n title: string;\n excerpt?: string;\n status: string;\n template: string;\n publishAt?: string;\n seoMetaId?: string;\n}\n\ninterface BlockVm {\n id: string;\n pageId: string;\n type: string;\n position: number;\n config: Record<string, any>;\n enabled: boolean;\n}\n\ninterface BlockTypeDef {\n value: string;\n label: string;\n // 'rich' = the WYSIWYG editor; the rest are plain inputs / json.\n fields: { key: string; label: string; kind: 'rich' | 'text' | 'ids' | 'id' | 'num' | 'json' }[];\n}\n\nconst BLOCK_TYPES: BlockTypeDef[] = [\n { value: 'rich_text', label: 'Rich text', fields: [{ key: 'html', label: 'Body', kind: 'rich' }] },\n {\n value: 'hero',\n label: 'Hero',\n fields: [\n { key: 'heading', label: 'Heading', kind: 'text' },\n { key: 'subheading', label: 'Subheading', kind: 'text' },\n { key: 'imageUrl', label: 'Image URL', kind: 'text' },\n { key: 'ctaLabel', label: 'Button label', kind: 'text' },\n { key: 'ctaUrl', label: 'Button URL', kind: 'text' },\n ],\n },\n {\n value: 'cta',\n label: 'Call to action',\n fields: [\n { key: 'heading', label: 'Heading', kind: 'text' },\n { key: 'body', label: 'Body', kind: 'text' },\n { key: 'buttonLabel', label: 'Button label', kind: 'text' },\n { key: 'buttonUrl', label: 'Button URL', kind: 'text' },\n ],\n },\n {\n value: 'product_rail',\n label: 'Product rail',\n fields: [\n { key: 'categoryId', label: 'From category ID', kind: 'id' },\n { key: 'productIds', label: 'Or product IDs', kind: 'ids' },\n { key: 'limit', label: 'Max items', kind: 'num' },\n ],\n },\n {\n value: 'category_grid',\n label: 'Category grid',\n fields: [{ key: 'categoryIds', label: 'Category IDs', kind: 'ids' }],\n },\n {\n value: 'image',\n label: 'Image',\n fields: [\n { key: 'url', label: 'Image URL', kind: 'text' },\n { key: 'alt', label: 'Alt text', kind: 'text' },\n { key: 'linkUrl', label: 'Links to', kind: 'text' },\n ],\n },\n { value: 'gallery', label: 'Gallery', fields: [{ key: 'imageUrls', label: 'Image URLs', kind: 'ids' }] },\n { value: 'faq', label: 'FAQ', fields: [{ key: 'items', label: 'Items — [{\"q\":\"…\",\"a\":\"…\"}]', kind: 'json' }] },\n { value: 'columns', label: 'Columns', fields: [{ key: 'columns', label: 'Columns JSON', kind: 'json' }] },\n {\n value: 'embed',\n label: 'Embed',\n fields: [\n { key: 'url', label: 'Embed URL', kind: 'text' },\n { key: 'html', label: 'Or raw HTML', kind: 'text' },\n ],\n },\n];\n\nconst STATUSES = ['draft', 'published', 'archived'];\nconst TEMPLATES = ['default', 'landing', 'full-width'];\n\n// P6.10, CMS-01 — the CMS page builder. Left: the Page list. Right: the\n// selected page's metadata + its drag-ordered ContentBlock list, each\n// with a type-aware editor (`rich_text` uses the `@thescaffold/editor-*`\n// WYSIWYG). The storefront page renderer is a later task; ops CRUD is\n// covered by `admin:*:apps:commerce:*`.\n@Component({\n standalone: false,\n selector: 'x-content',\n templateUrl: './content.component.html',\n})\nexport class ContentComponent extends BaseDirective {\n private readonly pageSource = this.apiService.on('apps/commerce/page');\n private readonly blockSource = this.apiService.on('apps/commerce/content-block');\n\n readonly blockTypes = BLOCK_TYPES;\n readonly statuses = STATUSES;\n readonly templates = TEMPLATES;\n\n loading = true;\n pages: PageVm[] = [];\n selected?: PageVm;\n\n blocks: BlockVm[] = [];\n blocksLoading = false;\n newBlockType = BLOCK_TYPES[0].value;\n editingBlock?: BlockVm;\n blockModel: Record<string, string> = {};\n rawHtml = false;\n\n newPageSlug = '';\n newPageTitle = '';\n\n private dragIndex: number | null = null;\n\n override init = () => {\n this.loadPages();\n };\n\n blockTypeLabel(v: string): string {\n return BLOCK_TYPES.find((t) => t.value === v)?.label ?? v;\n }\n\n blockTypeDef(v: string): BlockTypeDef | undefined {\n return BLOCK_TYPES.find((t) => t.value === v);\n }\n\n get orderedBlocks(): BlockVm[] {\n return [...this.blocks].sort((a, b) => a.position - b.position);\n }\n\n // ── pages ─────────────────────────────────────────────────────────\n\n loadPages(): void {\n this.loading = true;\n this.pageSource\n .getMany({ perPage: 200 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n this.pages = (res?.data ?? []).sort((a: any, b: any) =>\n String(a.title).localeCompare(String(b.title)),\n );\n this.loading = false;\n if (this.selected) {\n this.selected = this.pages.find((p) => p.id === this.selected!.id);\n }\n }),\n );\n }\n\n async createPage(): Promise<void> {\n const slug = this.newPageSlug.trim().toLowerCase().replace(/\\s+/g, '-');\n const title = this.newPageTitle.trim();\n if (!slug || !title) return;\n try {\n const res: any = await firstValueFrom(\n this.pageSource.create({ slug, title, status: 'draft', template: 'default' } as any),\n );\n this.newPageSlug = '';\n this.newPageTitle = '';\n notify('Page created.', undefined, 'success');\n this.loadPages();\n if (res?.data?.id) setTimeout(() => this.select({ ...res.data }), 200);\n } catch {\n notify('Could not create the page (slug may be taken).', undefined, 'error');\n }\n }\n\n select(page: PageVm): void {\n this.selected = page;\n this.editingBlock = undefined;\n this.loadBlocks();\n }\n\n async savePage(): Promise<void> {\n if (!this.selected) return;\n const p = this.selected;\n try {\n await firstValueFrom(\n this.pageSource.update(p.id, {\n slug: p.slug,\n title: p.title,\n excerpt: p.excerpt || undefined,\n status: p.status,\n template: p.template,\n publishAt: p.publishAt ? new Date(p.publishAt).toISOString() : null,\n } as any),\n );\n notify('Page saved.', undefined, 'success');\n this.loadPages();\n } catch {\n notify('Could not save the page.', undefined, 'error');\n }\n }\n\n async deletePage(): Promise<void> {\n if (!this.selected) return;\n try {\n await firstValueFrom(this.pageSource.remove(this.selected.id));\n this.selected = undefined;\n this.blocks = [];\n notify('Page deleted.', undefined, 'success');\n this.loadPages();\n } catch {\n notify('Could not delete the page.', undefined, 'error');\n }\n }\n\n // ── blocks ────────────────────────────────────────────────────────\n\n private loadBlocks(): void {\n if (!this.selected) return;\n this.blocksLoading = true;\n this.blockSource\n .getMany({ pageId: this.selected.id, perPage: 200 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n this.blocks = ((res?.data ?? []) as BlockVm[])\n .filter((b) => b.pageId === this.selected!.id)\n .map((b) => ({ ...b, config: b.config ?? {} }))\n .sort((a, b) => a.position - b.position);\n this.blocksLoading = false;\n }),\n );\n }\n\n async addBlock(): Promise<void> {\n if (!this.selected) return;\n try {\n await firstValueFrom(\n this.blockSource.create({\n pageId: this.selected.id,\n type: this.newBlockType,\n position: this.blocks.length,\n config: {},\n enabled: true,\n } as any),\n );\n this.loadBlocks();\n } catch {\n notify('Could not add the block.', undefined, 'error');\n }\n }\n\n editBlock(b: BlockVm): void {\n this.editingBlock = b;\n this.rawHtml = false;\n this.blockModel = {};\n for (const field of this.blockTypeDef(b.type)?.fields ?? []) {\n const value = (b.config ?? {})[field.key];\n this.blockModel[field.key] =\n field.kind === 'json'\n ? JSON.stringify(value ?? (field.key === 'items' || field.key === 'columns' ? [] : {}), null, 2)\n : Array.isArray(value)\n ? value.join(', ')\n : value != null\n ? String(value)\n : '';\n }\n }\n\n cancelBlockEdit(): void {\n this.editingBlock = undefined;\n this.blockModel = {};\n }\n\n async saveBlock(): Promise<void> {\n if (!this.editingBlock) return;\n const def = this.blockTypeDef(this.editingBlock.type);\n const config: Record<string, any> = { ...(this.editingBlock.config ?? {}) };\n for (const field of def?.fields ?? []) {\n const raw = (this.blockModel[field.key] ?? '').trim();\n if (field.kind === 'ids') {\n config[field.key] = raw ? raw.split(',').map((s) => s.trim()).filter(Boolean) : [];\n } else if (field.kind === 'num') {\n config[field.key] = raw ? Number(raw) : undefined;\n } else if (field.kind === 'json') {\n try {\n config[field.key] = raw ? JSON.parse(raw) : [];\n } catch {\n notify(`\"${field.label}\" is not valid JSON.`, undefined, 'error');\n return;\n }\n } else {\n config[field.key] = raw || undefined;\n }\n }\n try {\n await firstValueFrom(this.blockSource.update(this.editingBlock.id, { config } as any));\n this.editingBlock.config = config;\n notify('Block saved.', undefined, 'success');\n this.cancelBlockEdit();\n } catch {\n notify('Could not save the block.', undefined, 'error');\n }\n }\n\n async toggleBlock(b: BlockVm): Promise<void> {\n const next = !b.enabled;\n try {\n await firstValueFrom(this.blockSource.update(b.id, { enabled: next } as any));\n b.enabled = next;\n } catch {\n notify('Could not update the block.', undefined, 'error');\n }\n }\n\n async removeBlock(b: BlockVm): Promise<void> {\n try {\n await firstValueFrom(this.blockSource.remove(b.id));\n this.blocks = this.blocks.filter((x) => x.id !== b.id);\n if (this.editingBlock?.id === b.id) this.cancelBlockEdit();\n notify('Block removed.', undefined, 'success');\n } catch {\n notify('Could not remove the block.', undefined, 'error');\n }\n }\n\n onDragStart(index: number): void {\n this.dragIndex = index;\n }\n\n onDragOver(event: DragEvent): void {\n event.preventDefault();\n }\n\n onDrop(targetIndex: number): void {\n if (this.dragIndex === null || this.dragIndex === targetIndex) return;\n const ordered = this.orderedBlocks;\n const [moved] = ordered.splice(this.dragIndex, 1);\n ordered.splice(targetIndex, 0, moved);\n this.dragIndex = null;\n void this.persistOrder(ordered);\n }\n\n moveBlock(index: number, dir: -1 | 1): void {\n const ordered = this.orderedBlocks;\n const target = index + dir;\n if (target < 0 || target >= ordered.length) return;\n [ordered[index], ordered[target]] = [ordered[target], ordered[index]];\n void this.persistOrder(ordered);\n }\n\n private async persistOrder(ordered: BlockVm[]): Promise<void> {\n const changed: BlockVm[] = [];\n ordered.forEach((b, i) => {\n if (b.position !== i) {\n b.position = i;\n changed.push(b);\n }\n });\n this.blocks = ordered;\n try {\n await Promise.all(\n changed.map((b) =>\n firstValueFrom(this.blockSource.update(b.id, { position: b.position } as any)),\n ),\n );\n } catch {\n notify('Could not save the new order.', undefined, 'error');\n this.loadBlocks();\n }\n }\n\n onRichChange(field: string, html: string): void {\n this.blockModel[field] = html ?? '';\n }\n}\n","<div class=\"x-cms-head\">\n <div class=\"x-cms-title\">Content pages</div>\n <div class=\"x-cms-sub\">Ops-authored storefront pages — metadata and a block list per page.</div>\n</div>\n\n@if (loading) {\n <x-element-loader></x-element-loader>\n} @else {\n <div class=\"x-cms-layout\">\n <aside class=\"x-cms-list\">\n <div class=\"x-cms-new\">\n <input type=\"text\" placeholder=\"slug\" [(ngModel)]=\"newPageSlug\" />\n <input type=\"text\" placeholder=\"Title\" [(ngModel)]=\"newPageTitle\" />\n <button type=\"button\" (click)=\"createPage()\">Add page</button>\n </div>\n @for (p of pages; track p.id) {\n <button\n type=\"button\"\n class=\"x-cms-list-item\"\n [class.x-cms-list-active]=\"selected?.id === p.id\"\n (click)=\"select(p)\"\n >\n <span class=\"x-cms-list-title\">{{ p.title }}</span>\n <span class=\"x-cms-list-meta\">/{{ p.slug }} · {{ p.status }}</span>\n </button>\n } @empty {\n <div class=\"x-cms-empty\">No pages yet.</div>\n }\n </aside>\n\n <section class=\"x-cms-editor\">\n @if (!selected) {\n <div class=\"x-cms-empty\">Pick a page, or add one.</div>\n } @else {\n <div class=\"x-cms-meta\">\n <div class=\"x-cms-f-row\">\n <label class=\"x-cms-f\">\n Title\n <input type=\"text\" [(ngModel)]=\"selected.title\" />\n </label>\n <label class=\"x-cms-f\">\n Slug\n <input type=\"text\" [(ngModel)]=\"selected.slug\" />\n </label>\n </div>\n <label class=\"x-cms-f\">\n Excerpt\n <input type=\"text\" [(ngModel)]=\"selected.excerpt\" />\n </label>\n <div class=\"x-cms-f-row\">\n <label class=\"x-cms-f\">\n Status\n <select [(ngModel)]=\"selected.status\">\n @for (s of statuses; track s) { <option [value]=\"s\">{{ s }}</option> }\n </select>\n </label>\n <label class=\"x-cms-f\">\n Template\n <select [(ngModel)]=\"selected.template\">\n @for (t of templates; track t) { <option [value]=\"t\">{{ t }}</option> }\n </select>\n </label>\n <label class=\"x-cms-f\">\n Publish at\n <input type=\"datetime-local\" [(ngModel)]=\"selected.publishAt\" />\n </label>\n </div>\n <div class=\"x-cms-meta-actions\">\n <button type=\"button\" class=\"x-cms-btn x-cms-btn-primary\" (click)=\"savePage()\">Save page</button>\n <button type=\"button\" class=\"x-cms-btn x-cms-danger\" (click)=\"deletePage()\">Delete page</button>\n </div>\n </div>\n\n <div class=\"x-cms-blocks-head\">\n <span>Blocks</span>\n <span class=\"x-cms-add-block\">\n <select [(ngModel)]=\"newBlockType\">\n @for (t of blockTypes; track t.value) { <option [value]=\"t.value\">{{ t.label }}</option> }\n </select>\n <button type=\"button\" class=\"x-cms-btn\" (click)=\"addBlock()\">Add block</button>\n </span>\n </div>\n\n @if (blocksLoading) {\n <x-element-loader></x-element-loader>\n } @else if (!orderedBlocks.length) {\n <div class=\"x-cms-empty\">No blocks on this page yet.</div>\n } @else {\n <div class=\"x-cms-blocks\">\n @for (b of orderedBlocks; track b.id; let i = $index) {\n <div\n class=\"x-cms-block\"\n [class.x-cms-block-off]=\"!b.enabled\"\n draggable=\"true\"\n (dragstart)=\"onDragStart(i)\"\n (dragover)=\"onDragOver($event)\"\n (drop)=\"onDrop(i)\"\n >\n <div class=\"x-cms-block-head\">\n <span class=\"x-cms-grip\">⠿</span>\n <div class=\"x-cms-block-order\">\n <button type=\"button\" (click)=\"moveBlock(i, -1)\" [disabled]=\"i === 0\">▲</button>\n <button type=\"button\" (click)=\"moveBlock(i, 1)\" [disabled]=\"i === orderedBlocks.length - 1\">▼</button>\n </div>\n <span class=\"x-cms-block-type\">{{ blockTypeLabel(b.type) }}</span>\n <span class=\"x-cms-block-actions\">\n <button type=\"button\" class=\"x-cms-toggle\" (click)=\"toggleBlock(b)\">{{ b.enabled ? 'On' : 'Off' }}</button>\n <button type=\"button\" class=\"x-cms-link\" (click)=\"editBlock(b)\">Edit</button>\n <button type=\"button\" class=\"x-cms-link x-cms-danger\" (click)=\"removeBlock(b)\">Delete</button>\n </span>\n </div>\n\n @if (editingBlock?.id === b.id) {\n <div class=\"x-cms-block-edit\">\n @for (field of blockTypeDef(b.type)?.fields ?? []; track field.key) {\n <label class=\"x-cms-f\">\n {{ field.label }}\n @if (field.kind === 'rich') {\n @if (rawHtml) {\n <textarea rows=\"6\" [(ngModel)]=\"blockModel[field.key]\"></textarea>\n } @else {\n <x-rich-editor\n [content]=\"blockModel[field.key]\"\n (contentChange)=\"onRichChange(field.key, $event)\"\n ></x-rich-editor>\n }\n <button type=\"button\" class=\"x-cms-link\" (click)=\"rawHtml = !rawHtml\">\n {{ rawHtml ? 'Use the editor' : 'Edit raw HTML' }}\n </button>\n } @else if (field.kind === 'json') {\n <textarea rows=\"5\" [(ngModel)]=\"blockModel[field.key]\"></textarea>\n } @else {\n <input\n [type]=\"field.kind === 'num' ? 'number' : 'text'\"\n [(ngModel)]=\"blockModel[field.key]\"\n />\n }\n </label>\n }\n <div class=\"x-cms-edit-actions\">\n <button type=\"button\" class=\"x-cms-btn x-cms-btn-primary\" (click)=\"saveBlock()\">Save block</button>\n <button type=\"button\" class=\"x-cms-btn\" (click)=\"cancelBlockEdit()\">Cancel</button>\n </div>\n </div>\n }\n </div>\n }\n </div>\n }\n }\n </section>\n </div>\n}\n\n<style>\n .x-cms-head { margin-bottom: 20px; }\n .x-cms-title { font-size: 24px; font-weight: 800; color: var(--color-text); }\n .x-cms-sub { font-size: 13.5px; color: var(--color-text-muted); margin-top: 2px; }\n .x-cms-empty { font-size: 14px; color: var(--color-text-muted); padding: 12px 0; }\n .x-cms-layout { display: grid; grid-template-columns: 260px 1fr; gap: 20px; align-items: start; }\n .x-cms-list { display: flex; flex-direction: column; gap: 6px; }\n .x-cms-new { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; }\n .x-cms-new input, .x-cms-f input, .x-cms-f select, .x-cms-f textarea,\n .x-cms-add-block select {\n border: 1px solid var(--color-border); border-radius: var(--radius-md);\n padding: 6px 10px; font-size: 13px; background: var(--color-surface); color: var(--color-text);\n }\n .x-cms-new button, .x-cms-btn {\n border: 1px solid var(--color-border); background: transparent; border-radius: var(--radius-md);\n padding: 6px 14px; font-size: 12.5px; font-weight: 700; cursor: pointer; color: var(--color-text-muted);\n }\n .x-cms-btn-primary { border-color: var(--color-accent); color: var(--color-accent-hover); }\n .x-cms-list-item {\n text-align: left; border: 1px solid var(--color-border); border-radius: var(--radius-md);\n background: var(--color-surface); padding: 8px 10px; cursor: pointer;\n display: flex; flex-direction: column; gap: 2px;\n }\n .x-cms-list-active { border-color: var(--color-accent); }\n .x-cms-list-title { font-size: 13px; font-weight: 700; color: var(--color-text); }\n .x-cms-list-meta { font-size: 11px; color: var(--color-text-muted); }\n .x-cms-editor { min-width: 0; }\n .x-cms-meta {\n background: var(--color-surface); border: 1px solid var(--color-border);\n border-radius: var(--radius-lg); padding: 16px; display: flex; flex-direction: column; gap: 10px;\n margin-bottom: 20px;\n }\n .x-cms-f { display: flex; flex-direction: column; gap: 4px; flex: 1; font-size: 11.5px; color: var(--color-text-muted); font-weight: 700; }\n .x-cms-f-row { display: flex; gap: 10px; }\n .x-cms-meta-actions, .x-cms-edit-actions { display: flex; gap: 8px; }\n .x-cms-blocks-head {\n display: flex; justify-content: space-between; align-items: center;\n font-size: 13px; font-weight: 800; color: var(--color-text); margin-bottom: 10px;\n }\n .x-cms-add-block { display: flex; gap: 8px; }\n .x-cms-blocks { display: flex; flex-direction: column; gap: 10px; }\n .x-cms-block { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); padding: 12px 14px; }\n .x-cms-block-off { opacity: 0.55; }\n .x-cms-block-head { display: flex; align-items: center; gap: 10px; }\n .x-cms-grip { cursor: grab; color: var(--color-text-muted); }\n .x-cms-block-order { display: flex; flex-direction: column; }\n .x-cms-block-order button { border: 0; background: transparent; cursor: pointer; color: var(--color-text-muted); font-size: 10px; line-height: 1.1; padding: 1px 3px; }\n .x-cms-block-order button:disabled { opacity: 0.3; cursor: default; }\n .x-cms-block-type { font-weight: 800; text-transform: uppercase; letter-spacing: 0.4px; font-size: 11px; color: var(--color-accent-hover); flex: 1; }\n .x-cms-block-actions { display: flex; gap: 8px; align-items: center; }\n .x-cms-toggle { border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: transparent; padding: 3px 10px; font-size: 11.5px; font-weight: 700; cursor: pointer; color: var(--color-text-muted); }\n .x-cms-link { border: 0; background: transparent; cursor: pointer; font-size: 12px; font-weight: 700; color: var(--color-accent-hover); }\n .x-cms-danger { color: var(--color-danger, #c0362c); }\n .x-cms-block-edit { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--color-border); display: flex; flex-direction: column; gap: 10px; }\n x-rich-editor { display: block; border: 1px solid var(--color-border); border-radius: var(--radius-md); min-height: 160px; }\n</style>\n","import { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { SharedModule } from '@thescaffold/ngx-core';\nimport { ElementsModule } from '@thescaffold/ngx-ui';\nimport { RichEditorModule } from '../_shared/rich-editor/rich-editor.module';\nimport { ContentComponent } from './content.component';\n\n@NgModule({\n declarations: [ContentComponent],\n imports: [\n SharedModule,\n ElementsModule,\n RichEditorModule,\n RouterModule.forChild([{ path: '', component: ContentComponent }]),\n ],\n})\nexport class ContentModule {}\n"],"names":["i2","i3.RichEditorComponent","i1"],"mappings":"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"}
1
+ {"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-content.module-Bx6Zj0WX.mjs","sources":["../../../projects/admin/src/lib/pages/content/content.component.ts","../../../projects/admin/src/lib/pages/content/content.component.html","../../../projects/admin/src/lib/pages/content/content.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { BaseDirective, notify, using } from '@thescaffold/ngx-core';\nimport { firstValueFrom, takeUntil } from 'rxjs';\n\ninterface PageVm {\n id: string;\n slug: string;\n title: string;\n excerpt?: string;\n status: string;\n template: string;\n publishAt?: string;\n seoMetaId?: string;\n}\n\ninterface BlockVm {\n id: string;\n pageId: string;\n type: string;\n position: number;\n config: Record<string, any>;\n enabled: boolean;\n}\n\ninterface BlockTypeDef {\n value: string;\n label: string;\n // 'rich' = the WYSIWYG editor; the rest are plain inputs / json.\n fields: { key: string; label: string; kind: 'rich' | 'text' | 'ids' | 'id' | 'num' | 'json' }[];\n}\n\nconst BLOCK_TYPES: BlockTypeDef[] = [\n { value: 'rich_text', label: 'Rich text', fields: [{ key: 'html', label: 'Body', kind: 'rich' }] },\n {\n value: 'hero',\n label: 'Hero',\n fields: [\n { key: 'heading', label: 'Heading', kind: 'text' },\n { key: 'subheading', label: 'Subheading', kind: 'text' },\n { key: 'imageUrl', label: 'Image URL', kind: 'text' },\n { key: 'ctaLabel', label: 'Button label', kind: 'text' },\n { key: 'ctaUrl', label: 'Button URL', kind: 'text' },\n ],\n },\n {\n value: 'cta',\n label: 'Call to action',\n fields: [\n { key: 'heading', label: 'Heading', kind: 'text' },\n { key: 'body', label: 'Body', kind: 'text' },\n { key: 'buttonLabel', label: 'Button label', kind: 'text' },\n { key: 'buttonUrl', label: 'Button URL', kind: 'text' },\n ],\n },\n {\n value: 'product_rail',\n label: 'Product rail',\n fields: [\n { key: 'categoryId', label: 'From category ID', kind: 'id' },\n { key: 'productIds', label: 'Or product IDs', kind: 'ids' },\n { key: 'limit', label: 'Max items', kind: 'num' },\n ],\n },\n {\n value: 'category_grid',\n label: 'Category grid',\n fields: [{ key: 'categoryIds', label: 'Category IDs', kind: 'ids' }],\n },\n {\n value: 'image',\n label: 'Image',\n fields: [\n { key: 'url', label: 'Image URL', kind: 'text' },\n { key: 'alt', label: 'Alt text', kind: 'text' },\n { key: 'linkUrl', label: 'Links to', kind: 'text' },\n ],\n },\n { value: 'gallery', label: 'Gallery', fields: [{ key: 'imageUrls', label: 'Image URLs', kind: 'ids' }] },\n { value: 'faq', label: 'FAQ', fields: [{ key: 'items', label: 'Items — [{\"q\":\"…\",\"a\":\"…\"}]', kind: 'json' }] },\n { value: 'columns', label: 'Columns', fields: [{ key: 'columns', label: 'Columns JSON', kind: 'json' }] },\n {\n value: 'embed',\n label: 'Embed',\n fields: [\n { key: 'url', label: 'Embed URL', kind: 'text' },\n { key: 'html', label: 'Or raw HTML', kind: 'text' },\n ],\n },\n];\n\nconst STATUSES = ['draft', 'published', 'archived'];\nconst TEMPLATES = ['default', 'landing', 'full-width'];\n\n// P6.10, CMS-01 — the CMS page builder. Left: the Page list. Right: the\n// selected page's metadata + its drag-ordered ContentBlock list, each\n// with a type-aware editor (`rich_text` uses the `@thescaffold/editor-*`\n// WYSIWYG). The storefront page renderer is a later task; ops CRUD is\n// covered by `admin:*:apps:commerce:*`.\n@Component({\n standalone: false,\n selector: 'x-content',\n templateUrl: './content.component.html',\n})\nexport class ContentComponent extends BaseDirective {\n private readonly pageSource = this.apiService.on('apps/commerce/page');\n private readonly blockSource = this.apiService.on('apps/commerce/content-block');\n\n readonly blockTypes = BLOCK_TYPES;\n readonly statuses = STATUSES;\n readonly templates = TEMPLATES;\n\n loading = true;\n pages: PageVm[] = [];\n selected?: PageVm;\n\n blocks: BlockVm[] = [];\n blocksLoading = false;\n newBlockType = BLOCK_TYPES[0].value;\n editingBlock?: BlockVm;\n blockModel: Record<string, string> = {};\n rawHtml = false;\n\n newPageSlug = '';\n newPageTitle = '';\n\n private dragIndex: number | null = null;\n\n override init = () => {\n this.loadPages();\n };\n\n blockTypeLabel(v: string): string {\n return BLOCK_TYPES.find((t) => t.value === v)?.label ?? v;\n }\n\n blockTypeDef(v: string): BlockTypeDef | undefined {\n return BLOCK_TYPES.find((t) => t.value === v);\n }\n\n get orderedBlocks(): BlockVm[] {\n return [...this.blocks].sort((a, b) => a.position - b.position);\n }\n\n // ── pages ─────────────────────────────────────────────────────────\n\n loadPages(): void {\n this.loading = true;\n this.pageSource\n .getMany({ perPage: 200 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n this.pages = (res?.data ?? []).sort((a: any, b: any) =>\n String(a.title).localeCompare(String(b.title)),\n );\n this.loading = false;\n if (this.selected) {\n this.selected = this.pages.find((p) => p.id === this.selected!.id);\n }\n }),\n );\n }\n\n async createPage(): Promise<void> {\n const slug = this.newPageSlug.trim().toLowerCase().replace(/\\s+/g, '-');\n const title = this.newPageTitle.trim();\n if (!slug || !title) return;\n try {\n const res: any = await firstValueFrom(\n this.pageSource.create({ slug, title, status: 'draft', template: 'default' } as any),\n );\n this.newPageSlug = '';\n this.newPageTitle = '';\n notify('Page created.', undefined, 'success');\n this.loadPages();\n if (res?.data?.id) setTimeout(() => this.select({ ...res.data }), 200);\n } catch {\n notify('Could not create the page (slug may be taken).', undefined, 'error');\n }\n }\n\n select(page: PageVm): void {\n this.selected = page;\n this.editingBlock = undefined;\n this.loadBlocks();\n }\n\n async savePage(): Promise<void> {\n if (!this.selected) return;\n const p = this.selected;\n try {\n await firstValueFrom(\n this.pageSource.update(p.id, {\n slug: p.slug,\n title: p.title,\n excerpt: p.excerpt || undefined,\n status: p.status,\n template: p.template,\n publishAt: p.publishAt ? new Date(p.publishAt).toISOString() : null,\n } as any),\n );\n notify('Page saved.', undefined, 'success');\n this.loadPages();\n } catch {\n notify('Could not save the page.', undefined, 'error');\n }\n }\n\n async deletePage(): Promise<void> {\n if (!this.selected) return;\n try {\n await firstValueFrom(this.pageSource.remove(this.selected.id));\n this.selected = undefined;\n this.blocks = [];\n notify('Page deleted.', undefined, 'success');\n this.loadPages();\n } catch {\n notify('Could not delete the page.', undefined, 'error');\n }\n }\n\n // ── blocks ────────────────────────────────────────────────────────\n\n private loadBlocks(): void {\n if (!this.selected) return;\n this.blocksLoading = true;\n this.blockSource\n .getMany({ pageId: this.selected.id, perPage: 200 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n this.blocks = ((res?.data ?? []) as BlockVm[])\n .filter((b) => b.pageId === this.selected!.id)\n .map((b) => ({ ...b, config: b.config ?? {} }))\n .sort((a, b) => a.position - b.position);\n this.blocksLoading = false;\n }),\n );\n }\n\n async addBlock(): Promise<void> {\n if (!this.selected) return;\n try {\n await firstValueFrom(\n this.blockSource.create({\n pageId: this.selected.id,\n type: this.newBlockType,\n position: this.blocks.length,\n config: {},\n enabled: true,\n } as any),\n );\n this.loadBlocks();\n } catch {\n notify('Could not add the block.', undefined, 'error');\n }\n }\n\n editBlock(b: BlockVm): void {\n this.editingBlock = b;\n this.rawHtml = false;\n this.blockModel = {};\n for (const field of this.blockTypeDef(b.type)?.fields ?? []) {\n const value = (b.config ?? {})[field.key];\n this.blockModel[field.key] =\n field.kind === 'json'\n ? JSON.stringify(value ?? (field.key === 'items' || field.key === 'columns' ? [] : {}), null, 2)\n : Array.isArray(value)\n ? value.join(', ')\n : value != null\n ? String(value)\n : '';\n }\n }\n\n cancelBlockEdit(): void {\n this.editingBlock = undefined;\n this.blockModel = {};\n }\n\n async saveBlock(): Promise<void> {\n if (!this.editingBlock) return;\n const def = this.blockTypeDef(this.editingBlock.type);\n const config: Record<string, any> = { ...(this.editingBlock.config ?? {}) };\n for (const field of def?.fields ?? []) {\n const raw = (this.blockModel[field.key] ?? '').trim();\n if (field.kind === 'ids') {\n config[field.key] = raw ? raw.split(',').map((s) => s.trim()).filter(Boolean) : [];\n } else if (field.kind === 'num') {\n config[field.key] = raw ? Number(raw) : undefined;\n } else if (field.kind === 'json') {\n try {\n config[field.key] = raw ? JSON.parse(raw) : [];\n } catch {\n notify(`\"${field.label}\" is not valid JSON.`, undefined, 'error');\n return;\n }\n } else {\n config[field.key] = raw || undefined;\n }\n }\n try {\n await firstValueFrom(this.blockSource.update(this.editingBlock.id, { config } as any));\n this.editingBlock.config = config;\n notify('Block saved.', undefined, 'success');\n this.cancelBlockEdit();\n } catch {\n notify('Could not save the block.', undefined, 'error');\n }\n }\n\n async toggleBlock(b: BlockVm): Promise<void> {\n const next = !b.enabled;\n try {\n await firstValueFrom(this.blockSource.update(b.id, { enabled: next } as any));\n b.enabled = next;\n } catch {\n notify('Could not update the block.', undefined, 'error');\n }\n }\n\n async removeBlock(b: BlockVm): Promise<void> {\n try {\n await firstValueFrom(this.blockSource.remove(b.id));\n this.blocks = this.blocks.filter((x) => x.id !== b.id);\n if (this.editingBlock?.id === b.id) this.cancelBlockEdit();\n notify('Block removed.', undefined, 'success');\n } catch {\n notify('Could not remove the block.', undefined, 'error');\n }\n }\n\n onDragStart(index: number): void {\n this.dragIndex = index;\n }\n\n onDragOver(event: DragEvent): void {\n event.preventDefault();\n }\n\n onDrop(targetIndex: number): void {\n if (this.dragIndex === null || this.dragIndex === targetIndex) return;\n const ordered = this.orderedBlocks;\n const [moved] = ordered.splice(this.dragIndex, 1);\n ordered.splice(targetIndex, 0, moved);\n this.dragIndex = null;\n void this.persistOrder(ordered);\n }\n\n moveBlock(index: number, dir: -1 | 1): void {\n const ordered = this.orderedBlocks;\n const target = index + dir;\n if (target < 0 || target >= ordered.length) return;\n [ordered[index], ordered[target]] = [ordered[target], ordered[index]];\n void this.persistOrder(ordered);\n }\n\n private async persistOrder(ordered: BlockVm[]): Promise<void> {\n const changed: BlockVm[] = [];\n ordered.forEach((b, i) => {\n if (b.position !== i) {\n b.position = i;\n changed.push(b);\n }\n });\n this.blocks = ordered;\n try {\n await Promise.all(\n changed.map((b) =>\n firstValueFrom(this.blockSource.update(b.id, { position: b.position } as any)),\n ),\n );\n } catch {\n notify('Could not save the new order.', undefined, 'error');\n this.loadBlocks();\n }\n }\n\n onRichChange(field: string, html: string): void {\n this.blockModel[field] = html ?? '';\n }\n}\n","<div class=\"x-cms-head\">\n <div class=\"x-cms-title\">Content pages</div>\n <div class=\"x-cms-sub\">Ops-authored storefront pages — metadata and a block list per page.</div>\n</div>\n\n@if (loading) {\n <x-element-loader></x-element-loader>\n} @else {\n <div class=\"x-cms-layout\">\n <aside class=\"x-cms-list\">\n <div class=\"x-cms-new\">\n <input type=\"text\" placeholder=\"slug\" [(ngModel)]=\"newPageSlug\" />\n <input type=\"text\" placeholder=\"Title\" [(ngModel)]=\"newPageTitle\" />\n <button type=\"button\" (click)=\"createPage()\">Add page</button>\n </div>\n @for (p of pages; track p.id) {\n <button\n type=\"button\"\n class=\"x-cms-list-item\"\n [class.x-cms-list-active]=\"selected?.id === p.id\"\n (click)=\"select(p)\"\n >\n <span class=\"x-cms-list-title\">{{ p.title }}</span>\n <span class=\"x-cms-list-meta\">/{{ p.slug }} · {{ p.status }}</span>\n </button>\n } @empty {\n <div class=\"x-cms-empty\">No pages yet.</div>\n }\n </aside>\n\n <section class=\"x-cms-editor\">\n @if (!selected) {\n <div class=\"x-cms-empty\">Pick a page, or add one.</div>\n } @else {\n <div class=\"x-cms-meta\">\n <div class=\"x-cms-f-row\">\n <label class=\"x-cms-f\">\n Title\n <input type=\"text\" [(ngModel)]=\"selected.title\" />\n </label>\n <label class=\"x-cms-f\">\n Slug\n <input type=\"text\" [(ngModel)]=\"selected.slug\" />\n </label>\n </div>\n <label class=\"x-cms-f\">\n Excerpt\n <input type=\"text\" [(ngModel)]=\"selected.excerpt\" />\n </label>\n <div class=\"x-cms-f-row\">\n <label class=\"x-cms-f\">\n Status\n <select [(ngModel)]=\"selected.status\">\n @for (s of statuses; track s) { <option [value]=\"s\">{{ s }}</option> }\n </select>\n </label>\n <label class=\"x-cms-f\">\n Template\n <select [(ngModel)]=\"selected.template\">\n @for (t of templates; track t) { <option [value]=\"t\">{{ t }}</option> }\n </select>\n </label>\n <label class=\"x-cms-f\">\n Publish at\n <input type=\"datetime-local\" [(ngModel)]=\"selected.publishAt\" />\n </label>\n </div>\n <div class=\"x-cms-meta-actions\">\n <button type=\"button\" class=\"x-cms-btn x-cms-btn-primary\" (click)=\"savePage()\">Save page</button>\n <button type=\"button\" class=\"x-cms-btn x-cms-danger\" (click)=\"deletePage()\">Delete page</button>\n </div>\n </div>\n\n <div class=\"x-cms-blocks-head\">\n <span>Blocks</span>\n <span class=\"x-cms-add-block\">\n <select [(ngModel)]=\"newBlockType\">\n @for (t of blockTypes; track t.value) { <option [value]=\"t.value\">{{ t.label }}</option> }\n </select>\n <button type=\"button\" class=\"x-cms-btn\" (click)=\"addBlock()\">Add block</button>\n </span>\n </div>\n\n @if (blocksLoading) {\n <x-element-loader></x-element-loader>\n } @else if (!orderedBlocks.length) {\n <div class=\"x-cms-empty\">No blocks on this page yet.</div>\n } @else {\n <div class=\"x-cms-blocks\">\n @for (b of orderedBlocks; track b.id; let i = $index) {\n <div\n class=\"x-cms-block\"\n [class.x-cms-block-off]=\"!b.enabled\"\n draggable=\"true\"\n (dragstart)=\"onDragStart(i)\"\n (dragover)=\"onDragOver($event)\"\n (drop)=\"onDrop(i)\"\n >\n <div class=\"x-cms-block-head\">\n <span class=\"x-cms-grip\">⠿</span>\n <div class=\"x-cms-block-order\">\n <button type=\"button\" (click)=\"moveBlock(i, -1)\" [disabled]=\"i === 0\">▲</button>\n <button type=\"button\" (click)=\"moveBlock(i, 1)\" [disabled]=\"i === orderedBlocks.length - 1\">▼</button>\n </div>\n <span class=\"x-cms-block-type\">{{ blockTypeLabel(b.type) }}</span>\n <span class=\"x-cms-block-actions\">\n <button type=\"button\" class=\"x-cms-toggle\" (click)=\"toggleBlock(b)\">{{ b.enabled ? 'On' : 'Off' }}</button>\n <button type=\"button\" class=\"x-cms-link\" (click)=\"editBlock(b)\">Edit</button>\n <button type=\"button\" class=\"x-cms-link x-cms-danger\" (click)=\"removeBlock(b)\">Delete</button>\n </span>\n </div>\n\n @if (editingBlock?.id === b.id) {\n <div class=\"x-cms-block-edit\">\n @for (field of blockTypeDef(b.type)?.fields ?? []; track field.key) {\n <label class=\"x-cms-f\">\n {{ field.label }}\n @if (field.kind === 'rich') {\n @if (rawHtml) {\n <textarea rows=\"6\" [(ngModel)]=\"blockModel[field.key]\"></textarea>\n } @else {\n <x-rich-editor\n [content]=\"blockModel[field.key]\"\n (contentChange)=\"onRichChange(field.key, $event)\"\n ></x-rich-editor>\n }\n <button type=\"button\" class=\"x-cms-link\" (click)=\"rawHtml = !rawHtml\">\n {{ rawHtml ? 'Use the editor' : 'Edit raw HTML' }}\n </button>\n } @else if (field.kind === 'json') {\n <textarea rows=\"5\" [(ngModel)]=\"blockModel[field.key]\"></textarea>\n } @else {\n <input\n [type]=\"field.kind === 'num' ? 'number' : 'text'\"\n [(ngModel)]=\"blockModel[field.key]\"\n />\n }\n </label>\n }\n <div class=\"x-cms-edit-actions\">\n <button type=\"button\" class=\"x-cms-btn x-cms-btn-primary\" (click)=\"saveBlock()\">Save block</button>\n <button type=\"button\" class=\"x-cms-btn\" (click)=\"cancelBlockEdit()\">Cancel</button>\n </div>\n </div>\n }\n </div>\n }\n </div>\n }\n }\n </section>\n </div>\n}\n\n<style>\n .x-cms-head { margin-bottom: 20px; }\n .x-cms-title { font-size: 24px; font-weight: 800; color: var(--color-text); }\n .x-cms-sub { font-size: 13.5px; color: var(--color-text-muted); margin-top: 2px; }\n .x-cms-empty { font-size: 14px; color: var(--color-text-muted); padding: 12px 0; }\n .x-cms-layout { display: grid; grid-template-columns: 260px 1fr; gap: 20px; align-items: start; }\n .x-cms-list { display: flex; flex-direction: column; gap: 6px; }\n .x-cms-new { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; }\n .x-cms-new input, .x-cms-f input, .x-cms-f select, .x-cms-f textarea,\n .x-cms-add-block select {\n border: 1px solid var(--color-border); border-radius: var(--radius-md);\n padding: 6px 10px; font-size: 13px; background: var(--color-surface); color: var(--color-text);\n }\n .x-cms-new button, .x-cms-btn {\n border: 1px solid var(--color-border); background: transparent; border-radius: var(--radius-md);\n padding: 6px 14px; font-size: 12.5px; font-weight: 700; cursor: pointer; color: var(--color-text-muted);\n }\n .x-cms-btn-primary { border-color: var(--color-accent); color: var(--color-accent-hover); }\n .x-cms-list-item {\n text-align: left; border: 1px solid var(--color-border); border-radius: var(--radius-md);\n background: var(--color-surface); padding: 8px 10px; cursor: pointer;\n display: flex; flex-direction: column; gap: 2px;\n }\n .x-cms-list-active { border-color: var(--color-accent); }\n .x-cms-list-title { font-size: 13px; font-weight: 700; color: var(--color-text); }\n .x-cms-list-meta { font-size: 11px; color: var(--color-text-muted); }\n .x-cms-editor { min-width: 0; }\n .x-cms-meta {\n background: var(--color-surface); border: 1px solid var(--color-border);\n border-radius: var(--radius-lg); padding: 16px; display: flex; flex-direction: column; gap: 10px;\n margin-bottom: 20px;\n }\n .x-cms-f { display: flex; flex-direction: column; gap: 4px; flex: 1; font-size: 11.5px; color: var(--color-text-muted); font-weight: 700; }\n .x-cms-f-row { display: flex; gap: 10px; }\n .x-cms-meta-actions, .x-cms-edit-actions { display: flex; gap: 8px; }\n .x-cms-blocks-head {\n display: flex; justify-content: space-between; align-items: center;\n font-size: 13px; font-weight: 800; color: var(--color-text); margin-bottom: 10px;\n }\n .x-cms-add-block { display: flex; gap: 8px; }\n .x-cms-blocks { display: flex; flex-direction: column; gap: 10px; }\n .x-cms-block { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); padding: 12px 14px; }\n .x-cms-block-off { opacity: 0.55; }\n .x-cms-block-head { display: flex; align-items: center; gap: 10px; }\n .x-cms-grip { cursor: grab; color: var(--color-text-muted); }\n .x-cms-block-order { display: flex; flex-direction: column; }\n .x-cms-block-order button { border: 0; background: transparent; cursor: pointer; color: var(--color-text-muted); font-size: 10px; line-height: 1.1; padding: 1px 3px; }\n .x-cms-block-order button:disabled { opacity: 0.3; cursor: default; }\n .x-cms-block-type { font-weight: 800; text-transform: uppercase; letter-spacing: 0.4px; font-size: 11px; color: var(--color-accent-hover); flex: 1; }\n .x-cms-block-actions { display: flex; gap: 8px; align-items: center; }\n .x-cms-toggle { border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: transparent; padding: 3px 10px; font-size: 11.5px; font-weight: 700; cursor: pointer; color: var(--color-text-muted); }\n .x-cms-link { border: 0; background: transparent; cursor: pointer; font-size: 12px; font-weight: 700; color: var(--color-accent-hover); }\n .x-cms-danger { color: var(--color-danger, #c0362c); }\n .x-cms-block-edit { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--color-border); display: flex; flex-direction: column; gap: 10px; }\n x-rich-editor { display: block; border: 1px solid var(--color-border); border-radius: var(--radius-md); min-height: 160px; }\n</style>\n","import { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { SharedModule } from '@thescaffold/ngx-core';\nimport { ElementsModule } from '@thescaffold/ngx-ui';\nimport { RichEditorModule } from '../_shared/rich-editor/rich-editor.module';\nimport { ContentComponent } from './content.component';\n\n@NgModule({\n declarations: [ContentComponent],\n imports: [\n SharedModule,\n ElementsModule,\n RichEditorModule,\n RouterModule.forChild([{ path: '', component: ContentComponent }]),\n ],\n})\nexport class ContentModule {}\n"],"names":["i3.RichEditorComponent","i1"],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Component, NgModule } from '@angular/core';
3
+ import * as i1$1 from '@angular/router';
4
+ import { RouterModule } from '@angular/router';
5
+ import { using, SharedModule } from '@thescaffold/ngx-core';
6
+ import * as i2 from '@thescaffold/ngx-ui';
7
+ import { ElementsModule, WebgetsModule } from '@thescaffold/ngx-ui';
8
+ import { takeUntil } from 'rxjs';
9
+ import { S as SimpleCrudDirective } from './isaiahiroko-tilmart-ngx-apps-admin-simple-crud.base-C8SPw14H.mjs';
10
+ import * as i1 from '@angular/forms';
11
+ import * as i3 from '@angular/common';
12
+
13
+ // R1 production-readiness pass — PROMO-03. Was list-only; ops had no way
14
+ // to generate a coupon code, set usage/spend limits, or bind one to a
15
+ // promotion.
16
+ class CouponsComponent extends SimpleCrudDirective {
17
+ constructor() {
18
+ super(...arguments);
19
+ this.promotionSource = this.apiService.on('apps/commerce/promotion');
20
+ this.pageTitle = 'Coupons';
21
+ this.pageSubtitle = 'Redeemable codes bound to a promotion, with usage and spend limits.';
22
+ this.singularLabel = 'coupon';
23
+ this.pluralName = 'coupons';
24
+ this.dataSource = this.apiService.on('apps/commerce/coupon');
25
+ this.columns = [
26
+ { key: 'code', value: 'Code' },
27
+ { key: 'usageCount', value: 'Used' },
28
+ { key: 'usageLimit', value: 'Limit' },
29
+ { key: 'enabled', value: 'Enabled', type: 'class', class: 'badge text-bg-light border' },
30
+ ];
31
+ this.fields = [
32
+ { key: 'code', label: 'Code', type: 'text', required: true, placeholder: 'e.g. SOLAR10' },
33
+ { key: 'promotionId', label: 'Promotion', type: 'select', optionsKey: 'promotions', required: true },
34
+ { key: 'usageLimit', label: 'Total usage limit', type: 'number' },
35
+ { key: 'perCustomerLimit', label: 'Per-customer limit', type: 'number' },
36
+ { key: 'minSpend', label: 'Minimum spend (₦)', type: 'number' },
37
+ { key: 'expiresAt', label: 'Expires at', type: 'date' },
38
+ { key: 'enabled', label: 'Enabled', type: 'boolean' },
39
+ ];
40
+ this.init = () => {
41
+ this.list();
42
+ this.promotionSource
43
+ .getMany({ page: 1, perPage: 200 })
44
+ .pipe(takeUntil(this.$))
45
+ .subscribe(using((response) => {
46
+ this.dynamicOptions['promotions'] = (response?.data ?? []).map((p) => ({
47
+ value: p.id,
48
+ label: p.name,
49
+ }));
50
+ }));
51
+ };
52
+ }
53
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: CouponsComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
54
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: CouponsComponent, isStandalone: false, selector: "x-coupons", usesInheritance: true, ngImport: i0, template: "<div class=\"x-page-head\">\n <div class=\"x-page-title\">{{ pageTitle }}</div>\n <div class=\"x-page-subtitle\">{{ pageSubtitle }}</div>\n</div>\n\n@if (!editing) {\n <div class=\"x-scrud-toolbar\">\n <button type=\"button\" class=\"x-scrud-btn x-scrud-btn-primary\" (click)=\"startCreate()\">+ New {{ singularLabel }}</button>\n </div>\n\n @if (list$ | async; as list) {\n <x-webget-collection [data]=\"list\"></x-webget-collection>\n } @else {\n <x-element-loader></x-element-loader>\n }\n} @else if (draft) {\n <div class=\"x-scrud-editor\">\n <div class=\"x-scrud-editor-head\">\n <div class=\"x-scrud-editor-title\">{{ draft['id'] ? 'Edit' : 'New' }} {{ singularLabel }}</div>\n <div class=\"x-scrud-editor-actions\">\n @if (draft['id'] && !hideDelete) {\n <button type=\"button\" class=\"x-scrud-btn x-scrud-danger\" (click)=\"remove(draft); cancelEdit()\">Delete</button>\n }\n <button type=\"button\" class=\"x-scrud-btn\" (click)=\"cancelEdit()\">Close</button>\n <button type=\"button\" class=\"x-scrud-btn x-scrud-btn-primary\" [disabled]=\"saving\" (click)=\"save()\">\n {{ saving ? 'Saving\u2026' : 'Save' }}\n </button>\n </div>\n </div>\n\n <div class=\"x-scrud-grid\">\n @for (f of fields; track f.key) {\n <label class=\"x-scrud-f\" [class.x-scrud-f-wide]=\"f.type === 'textarea' || f.type === 'json'\">\n {{ f.label }}\n @if (f.required) {\n <span class=\"x-scrud-required\">*</span>\n }\n @switch (f.type) {\n @case ('boolean') {\n <input type=\"checkbox\" [(ngModel)]=\"draft[f.key]\" />\n }\n @case ('select') {\n <select [(ngModel)]=\"draft[f.key]\">\n <option value=\"\">\u2014 choose \u2014</option>\n @for (opt of (f.optionsKey ? dynamicOptions[f.optionsKey] : f.options); track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @case ('textarea') {\n <textarea rows=\"3\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\"></textarea>\n }\n @case ('json') {\n <textarea rows=\"4\" class=\"x-scrud-json\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || '{}'\"></textarea>\n }\n @case ('number') {\n <input type=\"number\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\" />\n }\n @case ('date') {\n <input type=\"datetime-local\" [(ngModel)]=\"draft[f.key]\" />\n }\n @default {\n <input type=\"text\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\" />\n }\n }\n </label>\n }\n </div>\n </div>\n}\n", styles: [".x-page-head{margin-bottom:20px}.x-page-title{font-size:24px;font-weight:800;color:var(--color-text)}.x-page-subtitle{font-size:13.5px;color:var(--color-text-muted);margin-top:2px}.x-scrud-toolbar{display:flex;justify-content:flex-end;margin-bottom:14px}.x-scrud-btn{border:1px solid var(--color-border);background:transparent;border-radius:var(--radius-md);padding:6px 14px;font-size:12.5px;font-weight:700;cursor:pointer;color:var(--color-text-muted)}.x-scrud-btn:disabled{opacity:.5;cursor:default}.x-scrud-btn-primary{border-color:var(--color-accent);color:var(--color-accent-hover)}.x-scrud-danger{color:var(--color-danger, #c0362c)}.x-scrud-editor{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:16px;display:flex;flex-direction:column;gap:14px}.x-scrud-editor-head{display:flex;align-items:center;justify-content:space-between}.x-scrud-editor-title{font-size:16px;font-weight:800;color:var(--color-text)}.x-scrud-editor-actions{display:flex;gap:8px}.x-scrud-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}.x-scrud-f{display:flex;flex-direction:column;gap:4px;font-size:11.5px;color:var(--color-text-muted);font-weight:700}.x-scrud-f-wide{grid-column:1/-1}.x-scrud-f input,.x-scrud-f select,.x-scrud-f textarea{border:1px solid var(--color-border);border-radius:var(--radius-md);padding:6px 10px;font-size:13px;background:var(--color-surface);color:var(--color-text);font-weight:400}.x-scrud-f input[type=checkbox]{width:18px;height:18px}.x-scrud-json{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.x-scrud-required{color:var(--color-danger, #c0362c)}\n"], dependencies: [{ kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i2.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }, { kind: "component", type: i2.CollectionComponent, selector: "x-webget-collection", inputs: ["data"], outputs: ["search", "filter", "refresh", "select", "page", "show"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); }
55
+ }
56
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: CouponsComponent, decorators: [{
57
+ type: Component,
58
+ args: [{ standalone: false, selector: 'x-coupons', template: "<div class=\"x-page-head\">\n <div class=\"x-page-title\">{{ pageTitle }}</div>\n <div class=\"x-page-subtitle\">{{ pageSubtitle }}</div>\n</div>\n\n@if (!editing) {\n <div class=\"x-scrud-toolbar\">\n <button type=\"button\" class=\"x-scrud-btn x-scrud-btn-primary\" (click)=\"startCreate()\">+ New {{ singularLabel }}</button>\n </div>\n\n @if (list$ | async; as list) {\n <x-webget-collection [data]=\"list\"></x-webget-collection>\n } @else {\n <x-element-loader></x-element-loader>\n }\n} @else if (draft) {\n <div class=\"x-scrud-editor\">\n <div class=\"x-scrud-editor-head\">\n <div class=\"x-scrud-editor-title\">{{ draft['id'] ? 'Edit' : 'New' }} {{ singularLabel }}</div>\n <div class=\"x-scrud-editor-actions\">\n @if (draft['id'] && !hideDelete) {\n <button type=\"button\" class=\"x-scrud-btn x-scrud-danger\" (click)=\"remove(draft); cancelEdit()\">Delete</button>\n }\n <button type=\"button\" class=\"x-scrud-btn\" (click)=\"cancelEdit()\">Close</button>\n <button type=\"button\" class=\"x-scrud-btn x-scrud-btn-primary\" [disabled]=\"saving\" (click)=\"save()\">\n {{ saving ? 'Saving\u2026' : 'Save' }}\n </button>\n </div>\n </div>\n\n <div class=\"x-scrud-grid\">\n @for (f of fields; track f.key) {\n <label class=\"x-scrud-f\" [class.x-scrud-f-wide]=\"f.type === 'textarea' || f.type === 'json'\">\n {{ f.label }}\n @if (f.required) {\n <span class=\"x-scrud-required\">*</span>\n }\n @switch (f.type) {\n @case ('boolean') {\n <input type=\"checkbox\" [(ngModel)]=\"draft[f.key]\" />\n }\n @case ('select') {\n <select [(ngModel)]=\"draft[f.key]\">\n <option value=\"\">\u2014 choose \u2014</option>\n @for (opt of (f.optionsKey ? dynamicOptions[f.optionsKey] : f.options); track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @case ('textarea') {\n <textarea rows=\"3\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\"></textarea>\n }\n @case ('json') {\n <textarea rows=\"4\" class=\"x-scrud-json\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || '{}'\"></textarea>\n }\n @case ('number') {\n <input type=\"number\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\" />\n }\n @case ('date') {\n <input type=\"datetime-local\" [(ngModel)]=\"draft[f.key]\" />\n }\n @default {\n <input type=\"text\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\" />\n }\n }\n </label>\n }\n </div>\n </div>\n}\n", styles: [".x-page-head{margin-bottom:20px}.x-page-title{font-size:24px;font-weight:800;color:var(--color-text)}.x-page-subtitle{font-size:13.5px;color:var(--color-text-muted);margin-top:2px}.x-scrud-toolbar{display:flex;justify-content:flex-end;margin-bottom:14px}.x-scrud-btn{border:1px solid var(--color-border);background:transparent;border-radius:var(--radius-md);padding:6px 14px;font-size:12.5px;font-weight:700;cursor:pointer;color:var(--color-text-muted)}.x-scrud-btn:disabled{opacity:.5;cursor:default}.x-scrud-btn-primary{border-color:var(--color-accent);color:var(--color-accent-hover)}.x-scrud-danger{color:var(--color-danger, #c0362c)}.x-scrud-editor{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:16px;display:flex;flex-direction:column;gap:14px}.x-scrud-editor-head{display:flex;align-items:center;justify-content:space-between}.x-scrud-editor-title{font-size:16px;font-weight:800;color:var(--color-text)}.x-scrud-editor-actions{display:flex;gap:8px}.x-scrud-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}.x-scrud-f{display:flex;flex-direction:column;gap:4px;font-size:11.5px;color:var(--color-text-muted);font-weight:700}.x-scrud-f-wide{grid-column:1/-1}.x-scrud-f input,.x-scrud-f select,.x-scrud-f textarea{border:1px solid var(--color-border);border-radius:var(--radius-md);padding:6px 10px;font-size:13px;background:var(--color-surface);color:var(--color-text);font-weight:400}.x-scrud-f input[type=checkbox]{width:18px;height:18px}.x-scrud-json{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.x-scrud-required{color:var(--color-danger, #c0362c)}\n"] }]
59
+ }] });
60
+
61
+ class CouponsModule {
62
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: CouponsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
63
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.16", ngImport: i0, type: CouponsModule, declarations: [CouponsComponent], imports: [SharedModule,
64
+ ElementsModule,
65
+ WebgetsModule, i1$1.RouterModule] }); }
66
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: CouponsModule, imports: [SharedModule,
67
+ ElementsModule,
68
+ WebgetsModule,
69
+ RouterModule.forChild([{ path: '', component: CouponsComponent }])] }); }
70
+ }
71
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: CouponsModule, decorators: [{
72
+ type: NgModule,
73
+ args: [{
74
+ declarations: [CouponsComponent],
75
+ imports: [
76
+ SharedModule,
77
+ ElementsModule,
78
+ WebgetsModule,
79
+ RouterModule.forChild([{ path: '', component: CouponsComponent }]),
80
+ ],
81
+ }]
82
+ }] });
83
+
84
+ export { CouponsModule };
85
+ //# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CoRh6Hxq.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CoRh6Hxq.mjs","sources":["../../../projects/admin/src/lib/pages/coupons/coupons.component.ts","../../../projects/admin/src/lib/pages/_shared/simple-crud.component.html","../../../projects/admin/src/lib/pages/coupons/coupons.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { using } from '@thescaffold/ngx-core';\nimport { takeUntil } from 'rxjs';\nimport { CrudFieldSpec, SimpleCrudDirective } from '../_shared/simple-crud.base';\n\n// R1 production-readiness pass — PROMO-03. Was list-only; ops had no way\n// to generate a coupon code, set usage/spend limits, or bind one to a\n// promotion.\n@Component({\n standalone: false,\n selector: 'x-coupons',\n templateUrl: '../_shared/simple-crud.component.html',\n styleUrl: '../_shared/simple-crud.component.scss',\n})\nexport class CouponsComponent extends SimpleCrudDirective {\n private readonly promotionSource = this.apiService.on('apps/commerce/promotion');\n\n protected pageTitle = 'Coupons';\n protected pageSubtitle = 'Redeemable codes bound to a promotion, with usage and spend limits.';\n protected singularLabel = 'coupon';\n protected pluralName = 'coupons';\n protected dataSource = this.apiService.on('apps/commerce/coupon');\n\n protected columns = [\n { key: 'code', value: 'Code' },\n { key: 'usageCount', value: 'Used' },\n { key: 'usageLimit', value: 'Limit' },\n { key: 'enabled', value: 'Enabled', type: 'class', class: 'badge text-bg-light border' },\n ];\n\n protected fields: CrudFieldSpec[] = [\n { key: 'code', label: 'Code', type: 'text', required: true, placeholder: 'e.g. SOLAR10' },\n { key: 'promotionId', label: 'Promotion', type: 'select', optionsKey: 'promotions', required: true },\n { key: 'usageLimit', label: 'Total usage limit', type: 'number' },\n { key: 'perCustomerLimit', label: 'Per-customer limit', type: 'number' },\n { key: 'minSpend', label: 'Minimum spend (₦)', type: 'number' },\n { key: 'expiresAt', label: 'Expires at', type: 'date' },\n { key: 'enabled', label: 'Enabled', type: 'boolean' },\n ];\n\n override init = () => {\n this.list();\n this.promotionSource\n .getMany({ page: 1, perPage: 200 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((response: any) => {\n this.dynamicOptions['promotions'] = (response?.data ?? []).map((p: any) => ({\n value: p.id,\n label: p.name,\n }));\n }),\n );\n };\n}\n","<div class=\"x-page-head\">\n <div class=\"x-page-title\">{{ pageTitle }}</div>\n <div class=\"x-page-subtitle\">{{ pageSubtitle }}</div>\n</div>\n\n@if (!editing) {\n <div class=\"x-scrud-toolbar\">\n <button type=\"button\" class=\"x-scrud-btn x-scrud-btn-primary\" (click)=\"startCreate()\">+ New {{ singularLabel }}</button>\n </div>\n\n @if (list$ | async; as list) {\n <x-webget-collection [data]=\"list\"></x-webget-collection>\n } @else {\n <x-element-loader></x-element-loader>\n }\n} @else if (draft) {\n <div class=\"x-scrud-editor\">\n <div class=\"x-scrud-editor-head\">\n <div class=\"x-scrud-editor-title\">{{ draft['id'] ? 'Edit' : 'New' }} {{ singularLabel }}</div>\n <div class=\"x-scrud-editor-actions\">\n @if (draft['id'] && !hideDelete) {\n <button type=\"button\" class=\"x-scrud-btn x-scrud-danger\" (click)=\"remove(draft); cancelEdit()\">Delete</button>\n }\n <button type=\"button\" class=\"x-scrud-btn\" (click)=\"cancelEdit()\">Close</button>\n <button type=\"button\" class=\"x-scrud-btn x-scrud-btn-primary\" [disabled]=\"saving\" (click)=\"save()\">\n {{ saving ? 'Saving…' : 'Save' }}\n </button>\n </div>\n </div>\n\n <div class=\"x-scrud-grid\">\n @for (f of fields; track f.key) {\n <label class=\"x-scrud-f\" [class.x-scrud-f-wide]=\"f.type === 'textarea' || f.type === 'json'\">\n {{ f.label }}\n @if (f.required) {\n <span class=\"x-scrud-required\">*</span>\n }\n @switch (f.type) {\n @case ('boolean') {\n <input type=\"checkbox\" [(ngModel)]=\"draft[f.key]\" />\n }\n @case ('select') {\n <select [(ngModel)]=\"draft[f.key]\">\n <option value=\"\">— choose —</option>\n @for (opt of (f.optionsKey ? dynamicOptions[f.optionsKey] : f.options); track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @case ('textarea') {\n <textarea rows=\"3\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\"></textarea>\n }\n @case ('json') {\n <textarea rows=\"4\" class=\"x-scrud-json\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || '{}'\"></textarea>\n }\n @case ('number') {\n <input type=\"number\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\" />\n }\n @case ('date') {\n <input type=\"datetime-local\" [(ngModel)]=\"draft[f.key]\" />\n }\n @default {\n <input type=\"text\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\" />\n }\n }\n </label>\n }\n </div>\n </div>\n}\n","import { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { SharedModule } from '@thescaffold/ngx-core';\nimport { ElementsModule, WebgetsModule } from '@thescaffold/ngx-ui';\nimport { CouponsComponent } from './coupons.component';\n\n@NgModule({\n declarations: [CouponsComponent],\n imports: [\n SharedModule,\n ElementsModule,\n WebgetsModule,\n RouterModule.forChild([{ path: '', component: CouponsComponent }]),\n ],\n})\nexport class CouponsModule {}\n"],"names":["i1"],"mappings":"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"}