@sonicjs-cms/core 3.0.0-beta.24 → 3.0.0-beta.26

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 (163) hide show
  1. package/bin/db-reset.js +39 -22
  2. package/dist/admin-documents-form.template-JWV5GITD.js +6 -0
  3. package/dist/{admin-documents-form.template-55V2ZGWT.js.map → admin-documents-form.template-JWV5GITD.js.map} +1 -1
  4. package/dist/admin-documents-form.template-UWKGVAMW.cjs +19 -0
  5. package/dist/{admin-layout-catalyst.template-6UQGLCKI.js.map → admin-documents-form.template-UWKGVAMW.cjs.map} +1 -1
  6. package/dist/admin-layout-catalyst.template-MOQ3BBXA.cjs +21 -0
  7. package/dist/{admin-layout-catalyst.template-3XZXDGF7.cjs.map → admin-layout-catalyst.template-MOQ3BBXA.cjs.map} +1 -1
  8. package/dist/admin-layout-catalyst.template-WCYMQVTZ.js +7 -0
  9. package/dist/{admin-documents-form.template-YNAVMJCV.cjs.map → admin-layout-catalyst.template-WCYMQVTZ.js.map} +1 -1
  10. package/dist/{app-01M0dIwt.d.ts → app-BP5IlK94.d.ts} +7 -7
  11. package/dist/{app-aj39TGHB.d.cts → app-fdq4K3vw.d.cts} +7 -7
  12. package/dist/catalog-56DR6OXI.cjs +41 -0
  13. package/dist/catalog-56DR6OXI.cjs.map +1 -0
  14. package/dist/catalog-6MB37KY7.js +4 -0
  15. package/dist/catalog-6MB37KY7.js.map +1 -0
  16. package/dist/{chunk-QCJHCSOK.cjs → chunk-4DHPR7KR.cjs} +77 -17
  17. package/dist/chunk-4DHPR7KR.cjs.map +1 -0
  18. package/dist/{chunk-UIHIXTIS.js → chunk-5YSFQO7X.js} +40 -13
  19. package/dist/chunk-5YSFQO7X.js.map +1 -0
  20. package/dist/{chunk-GMMCCIQO.cjs → chunk-6UAI4SGN.cjs} +3 -3
  21. package/dist/{chunk-GMMCCIQO.cjs.map → chunk-6UAI4SGN.cjs.map} +1 -1
  22. package/dist/{chunk-2XAQTPAE.js → chunk-6X22VFEV.js} +8 -2
  23. package/dist/chunk-6X22VFEV.js.map +1 -0
  24. package/dist/{chunk-URIBTX27.js → chunk-73RTFFMX.js} +3 -3
  25. package/dist/{chunk-URIBTX27.js.map → chunk-73RTFFMX.js.map} +1 -1
  26. package/dist/{chunk-QJUJNTIU.cjs → chunk-A22RBHO7.cjs} +43 -12
  27. package/dist/chunk-A22RBHO7.cjs.map +1 -0
  28. package/dist/{chunk-QZGABF2M.js → chunk-AMP4BSJE.js} +18 -7
  29. package/dist/chunk-AMP4BSJE.js.map +1 -0
  30. package/dist/{chunk-37V3RET3.cjs → chunk-BRKXMRMB.cjs} +99 -98
  31. package/dist/chunk-BRKXMRMB.cjs.map +1 -0
  32. package/dist/{chunk-36Z3AKX3.cjs → chunk-C5LDQ3SH.cjs} +8 -2
  33. package/dist/chunk-C5LDQ3SH.cjs.map +1 -0
  34. package/dist/{chunk-BBEKHLTW.cjs → chunk-CN3T3TDI.cjs} +9 -9
  35. package/dist/{chunk-BBEKHLTW.cjs.map → chunk-CN3T3TDI.cjs.map} +1 -1
  36. package/dist/{chunk-BHND5PEV.js → chunk-E3TQG7AA.js} +3 -3
  37. package/dist/{chunk-BHND5PEV.js.map → chunk-E3TQG7AA.js.map} +1 -1
  38. package/dist/{chunk-FHPEM77Y.js → chunk-EEA476CJ.js} +88 -83
  39. package/dist/chunk-EEA476CJ.js.map +1 -0
  40. package/dist/chunk-F6BTBE4S.js +119 -0
  41. package/dist/chunk-F6BTBE4S.js.map +1 -0
  42. package/dist/chunk-FZGIU5AZ.cjs +128 -0
  43. package/dist/chunk-FZGIU5AZ.cjs.map +1 -0
  44. package/dist/{chunk-BJROXF4N.js → chunk-HSDJDWLV.js} +19 -4
  45. package/dist/chunk-HSDJDWLV.js.map +1 -0
  46. package/dist/{chunk-VGEZNFWH.js → chunk-JD7BZU3A.js} +5 -4
  47. package/dist/chunk-JD7BZU3A.js.map +1 -0
  48. package/dist/{chunk-SOZUG52O.js → chunk-JG5J434C.js} +3 -3
  49. package/dist/{chunk-SOZUG52O.js.map → chunk-JG5J434C.js.map} +1 -1
  50. package/dist/{chunk-BP52BFIV.cjs → chunk-KWQNB6UM.cjs} +6 -5
  51. package/dist/chunk-KWQNB6UM.cjs.map +1 -0
  52. package/dist/{chunk-UYJQDDEE.cjs → chunk-MI2YXCK4.cjs} +14 -8
  53. package/dist/chunk-MI2YXCK4.cjs.map +1 -0
  54. package/dist/{chunk-VC5XVPLM.js → chunk-OJFIQGZB.js} +512 -148
  55. package/dist/chunk-OJFIQGZB.js.map +1 -0
  56. package/dist/{chunk-LTZ5WYOK.cjs → chunk-OLEOKHDX.cjs} +25 -2
  57. package/dist/chunk-OLEOKHDX.cjs.map +1 -0
  58. package/dist/{chunk-E66UVONV.cjs → chunk-OUBUS74I.cjs} +24 -9
  59. package/dist/chunk-OUBUS74I.cjs.map +1 -0
  60. package/dist/{chunk-A2SN3RVL.cjs → chunk-PAS7GZBS.cjs} +40 -13
  61. package/dist/chunk-PAS7GZBS.cjs.map +1 -0
  62. package/dist/{chunk-RJ2O5IIE.js → chunk-RVOX2WH2.js} +74 -18
  63. package/dist/chunk-RVOX2WH2.js.map +1 -0
  64. package/dist/{chunk-3TMTYJAJ.js → chunk-RXLI3ADU.js} +25 -2
  65. package/dist/chunk-RXLI3ADU.js.map +1 -0
  66. package/dist/{chunk-I767LVN7.cjs → chunk-S2QN4LFD.cjs} +881 -515
  67. package/dist/chunk-S2QN4LFD.cjs.map +1 -0
  68. package/dist/{chunk-IXUHXTHW.cjs → chunk-SFGYZUWU.cjs} +18 -7
  69. package/dist/chunk-SFGYZUWU.cjs.map +1 -0
  70. package/dist/{chunk-THFZSDIU.js → chunk-SXC4HPK6.js} +14 -8
  71. package/dist/chunk-SXC4HPK6.js.map +1 -0
  72. package/dist/{chunk-JMJM7DMM.cjs → chunk-TT3TQSCZ.cjs} +5 -5
  73. package/dist/{chunk-JMJM7DMM.cjs.map → chunk-TT3TQSCZ.cjs.map} +1 -1
  74. package/dist/{chunk-LNI3FYSI.js → chunk-UB5QSRO7.js} +9 -14
  75. package/dist/chunk-UB5QSRO7.js.map +1 -0
  76. package/dist/{chunk-VYQVDL2M.js → chunk-UKIDWRA3.js} +36 -5
  77. package/dist/chunk-UKIDWRA3.js.map +1 -0
  78. package/dist/{chunk-KKNEYIZJ.cjs → chunk-XZUEGFXE.cjs} +9 -14
  79. package/dist/chunk-XZUEGFXE.cjs.map +1 -0
  80. package/dist/{collection-config-BTzAvKt2.d.cts → collection-config-U2dydD_O.d.cts} +14 -0
  81. package/dist/{collection-config-BTzAvKt2.d.ts → collection-config-U2dydD_O.d.ts} +14 -0
  82. package/dist/config-DOAWXZBG.js +6 -0
  83. package/dist/{config-6FB2BXMP.js.map → config-DOAWXZBG.js.map} +1 -1
  84. package/dist/{config-OCH7S4WK.cjs → config-VLU73ZW7.cjs} +5 -5
  85. package/dist/{config-OCH7S4WK.cjs.map → config-VLU73ZW7.cjs.map} +1 -1
  86. package/dist/{define-plugin-D_6D9vVZ.d.ts → define-plugin-DDe8a_bh.d.ts} +3 -0
  87. package/dist/{define-plugin-DMcvEy_C.d.cts → define-plugin-rjXmGOgu.d.cts} +3 -0
  88. package/dist/index.cjs +698 -392
  89. package/dist/index.cjs.map +1 -1
  90. package/dist/index.d.cts +27 -12
  91. package/dist/index.d.ts +27 -12
  92. package/dist/index.js +340 -35
  93. package/dist/index.js.map +1 -1
  94. package/dist/middleware.cjs +47 -47
  95. package/dist/middleware.d.cts +10 -10
  96. package/dist/middleware.d.ts +10 -10
  97. package/dist/middleware.js +6 -6
  98. package/dist/migrations-6M6772UC.cjs +13 -0
  99. package/dist/{migrations-FGXZPKDC.cjs.map → migrations-6M6772UC.cjs.map} +1 -1
  100. package/dist/migrations-GZ2HIB4I.js +4 -0
  101. package/dist/{migrations-Z6D27NAW.js.map → migrations-GZ2HIB4I.js.map} +1 -1
  102. package/dist/{plugin-bootstrap-BHWQ2df8.d.cts → plugin-bootstrap-CfVILQeP.d.ts} +1 -1
  103. package/dist/{plugin-bootstrap-Bj4fxX1q.d.ts → plugin-bootstrap-RY5pkoOT.d.cts} +1 -1
  104. package/dist/plugins.cjs +40 -40
  105. package/dist/plugins.d.cts +1 -1
  106. package/dist/plugins.d.ts +1 -1
  107. package/dist/plugins.js +3 -3
  108. package/dist/rbac-TFUOYIVN.cjs +14 -0
  109. package/dist/{rbac-7QZ4JZ2E.cjs.map → rbac-TFUOYIVN.cjs.map} +1 -1
  110. package/dist/rbac-XSNP76CV.js +5 -0
  111. package/dist/{rbac-Y43IEQOP.js.map → rbac-XSNP76CV.js.map} +1 -1
  112. package/dist/routes.cjs +33 -32
  113. package/dist/routes.d.cts +3 -5
  114. package/dist/routes.d.ts +3 -5
  115. package/dist/routes.js +13 -12
  116. package/dist/services.cjs +30 -30
  117. package/dist/services.d.cts +10 -3
  118. package/dist/services.d.ts +10 -3
  119. package/dist/services.js +3 -3
  120. package/dist/{telemetry-Cku1ax74.d.cts → telemetry-QFlTv9f8.d.cts} +1 -1
  121. package/dist/{telemetry-Cku1ax74.d.ts → telemetry-QFlTv9f8.d.ts} +1 -1
  122. package/dist/templates.cjs +17 -17
  123. package/dist/templates.js +3 -3
  124. package/dist/types.d.cts +2 -2
  125. package/dist/types.d.ts +2 -2
  126. package/dist/utils.cjs +12 -12
  127. package/dist/utils.d.cts +2 -2
  128. package/dist/utils.d.ts +2 -2
  129. package/dist/utils.js +2 -2
  130. package/package.json +7 -12
  131. package/dist/admin-documents-form.template-55V2ZGWT.js +0 -6
  132. package/dist/admin-documents-form.template-YNAVMJCV.cjs +0 -19
  133. package/dist/admin-layout-catalyst.template-3XZXDGF7.cjs +0 -21
  134. package/dist/admin-layout-catalyst.template-6UQGLCKI.js +0 -7
  135. package/dist/chunk-2XAQTPAE.js.map +0 -1
  136. package/dist/chunk-36Z3AKX3.cjs.map +0 -1
  137. package/dist/chunk-37V3RET3.cjs.map +0 -1
  138. package/dist/chunk-3TMTYJAJ.js.map +0 -1
  139. package/dist/chunk-A2SN3RVL.cjs.map +0 -1
  140. package/dist/chunk-BJROXF4N.js.map +0 -1
  141. package/dist/chunk-BP52BFIV.cjs.map +0 -1
  142. package/dist/chunk-E66UVONV.cjs.map +0 -1
  143. package/dist/chunk-FHPEM77Y.js.map +0 -1
  144. package/dist/chunk-I767LVN7.cjs.map +0 -1
  145. package/dist/chunk-IXUHXTHW.cjs.map +0 -1
  146. package/dist/chunk-KKNEYIZJ.cjs.map +0 -1
  147. package/dist/chunk-LNI3FYSI.js.map +0 -1
  148. package/dist/chunk-LTZ5WYOK.cjs.map +0 -1
  149. package/dist/chunk-QCJHCSOK.cjs.map +0 -1
  150. package/dist/chunk-QJUJNTIU.cjs.map +0 -1
  151. package/dist/chunk-QZGABF2M.js.map +0 -1
  152. package/dist/chunk-RJ2O5IIE.js.map +0 -1
  153. package/dist/chunk-THFZSDIU.js.map +0 -1
  154. package/dist/chunk-UIHIXTIS.js.map +0 -1
  155. package/dist/chunk-UYJQDDEE.cjs.map +0 -1
  156. package/dist/chunk-VC5XVPLM.js.map +0 -1
  157. package/dist/chunk-VGEZNFWH.js.map +0 -1
  158. package/dist/chunk-VYQVDL2M.js.map +0 -1
  159. package/dist/config-6FB2BXMP.js +0 -6
  160. package/dist/migrations-FGXZPKDC.cjs +0 -13
  161. package/dist/migrations-Z6D27NAW.js +0 -4
  162. package/dist/rbac-7QZ4JZ2E.cjs +0 -14
  163. package/dist/rbac-Y43IEQOP.js +0 -5
@@ -424,7 +424,7 @@ var QueryFilterBuilder = class {
424
424
  });
425
425
  }
426
426
  }
427
- const bracketFilterRegex = /^filter\[([^\]]+)\](?:\[([^\]]+)\])?$/;
427
+ const bracketFilterRegex = /^(?:filter|where)\[([^\]]+)\](?:\[([^\]]+)\])?$/;
428
428
  for (const [key, rawValue] of Object.entries(query)) {
429
429
  const match = key.match(bracketFilterRegex);
430
430
  if (!match) continue;
@@ -478,6 +478,11 @@ function getBlocksFieldConfig(fieldOptions) {
478
478
  discriminator
479
479
  };
480
480
  }
481
+ function generateBlockId() {
482
+ const bytes = new Uint8Array(6);
483
+ crypto.getRandomValues(bytes);
484
+ return "blk_" + Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
485
+ }
481
486
  function parseBlocksValue(value, config) {
482
487
  const errors = [];
483
488
  let rawValue = value;
@@ -499,13 +504,19 @@ function parseBlocksValue(value, config) {
499
504
  errors.push(`Block #${index + 1} must be an object`);
500
505
  return null;
501
506
  }
507
+ let block;
502
508
  if (item.blockType && item.data && typeof item.data === "object") {
503
- return { [config.discriminator]: item.blockType, ...item.data };
509
+ block = { [config.discriminator]: item.blockType, ...item.data };
510
+ } else {
511
+ if (!(config.discriminator in item)) {
512
+ errors.push(`Block #${index + 1} is missing "${config.discriminator}"`);
513
+ }
514
+ block = item;
504
515
  }
505
- if (!(config.discriminator in item)) {
506
- errors.push(`Block #${index + 1} is missing "${config.discriminator}"`);
516
+ if (!block.blockId) {
517
+ block = { blockId: generateBlockId(), ...block };
507
518
  }
508
- return item;
519
+ return block;
509
520
  }).filter((item) => item !== null);
510
521
  return { value: normalized, errors };
511
522
  }
@@ -518,5 +529,5 @@ exports.getBlocksFieldConfig = getBlocksFieldConfig;
518
529
  exports.parseBlocksValue = parseBlocksValue;
519
530
  exports.renderTemplate = renderTemplate;
520
531
  exports.templateRenderer = templateRenderer;
521
- //# sourceMappingURL=chunk-IXUHXTHW.cjs.map
522
- //# sourceMappingURL=chunk-IXUHXTHW.cjs.map
532
+ //# sourceMappingURL=chunk-SFGYZUWU.cjs.map
533
+ //# sourceMappingURL=chunk-SFGYZUWU.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/slug-utils.ts","../src/utils/template-renderer.ts","../src/utils/query-filter.ts","../src/utils/blocks.ts"],"names":[],"mappings":"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","file":"chunk-SFGYZUWU.cjs","sourcesContent":["/**\n * Slug generation utilities for creating URL-friendly slugs\n */\n\n/**\n * Generate URL-friendly slug from text\n * \n * Features:\n * - Converts to lowercase\n * - Handles accented characters (NFD normalization)\n * - Removes diacritics\n * - Keeps only alphanumeric, spaces, underscores, and hyphens\n * - Replaces spaces with hyphens\n * - Collapses multiple hyphens/underscores\n * - Trims leading/trailing hyphens/underscores\n * - Limits length to 100 characters\n * \n * @param text - Text to slugify\n * @returns URL-safe slug\n * \n * @example\n * generateSlug('Hello World!') // 'hello-world'\n * generateSlug('Café París 2024') // 'cafe-paris-2024'\n * generateSlug('Multiple Spaces') // 'multiple-spaces'\n */\nexport function generateSlug(text: string): string {\n if (!text) return '';\n \n return text\n .toLowerCase()\n .normalize('NFD') // Decompose combined characters (e.g., é -> e + ́)\n .replace(/[\\u0300-\\u036f]/g, '') // Remove diacritics\n .replace(/[^a-z0-9\\s_-]/g, '') // Keep only alphanumeric, spaces, underscores, hyphens\n .replace(/\\s+/g, '-') // Replace spaces with hyphens\n .replace(/[-_]+/g, '-') // Collapse multiple hyphens/underscores\n .replace(/^[-_]+|[-_]+$/g, '') // Trim leading/trailing hyphens/underscores\n .substring(0, 100); // Limit length for URL safety\n}\n","// Template renderer compatible with Cloudflare Workers\n// No filesystem access available\n\ninterface TemplateData {\n [key: string]: any\n}\n\nexport class TemplateRenderer {\n private templateCache = new Map<string, string>()\n\n constructor() {\n // Cloudflare Workers compatible - no filesystem access\n }\n\n /**\n * Simple Handlebars-like template engine\n */\n private renderTemplate(template: string, data: TemplateData): string {\n let rendered = template\n\n // Handle each loops - process outermost loops first for proper nesting\n rendered = rendered.replace(/\\{\\{#each\\s+([^}]+)\\}\\}([\\s\\S]*?)\\{\\{\\/each\\}\\}/g, (_match, arrayName, content) => {\n const array = this.getNestedValue(data, arrayName.trim())\n if (!Array.isArray(array)) return ''\n \n return array.map((item, index) => {\n // Create context with array item and special variables\n const itemContext = {\n ...data,\n // Handle primitive items (for {{.}} syntax)\n '.': item,\n // Spread item properties if it's an object\n ...(typeof item === 'object' && item !== null ? item : {}),\n '@index': index,\n '@first': index === 0,\n '@last': index === array.length - 1\n }\n return this.renderTemplate(content, itemContext)\n }).join('')\n })\n\n // Second pass: Handle conditionals\n let ifCount = 0\n while (rendered.includes('{{#if ') && ifCount < 100) {\n const previousRendered = rendered\n rendered = rendered.replace(/\\{\\{#if\\s+([^}]+)\\}\\}([\\s\\S]*?)\\{\\{\\/if\\}\\}/g, (_match, condition, content) => {\n const value = this.getNestedValue(data, condition.trim())\n // Handle boolean values properly - @first/@last are explicitly boolean\n const isTruthy = value === true || (value && value !== 0 && value !== '' && value !== null && value !== undefined)\n return isTruthy ? this.renderTemplate(content, data) : ''\n })\n if (previousRendered === rendered) break\n ifCount++\n }\n\n // Third pass: Handle triple braces for raw HTML {{{variable}}}\n rendered = rendered.replace(/\\{\\{\\{([^}]+)\\}\\}\\}/g, (_match, variable) => {\n const value = this.getNestedValue(data, variable.trim())\n return value !== undefined && value !== null ? String(value) : ''\n })\n\n // Fourth pass: Handle helper functions like {{titleCase field}}\n rendered = rendered.replace(/\\{\\{([^}#\\/]+)\\s+([^}]+)\\}\\}/g, (match, helper, variable) => {\n const helperName = helper.trim()\n const varName = variable.trim()\n \n if (helperName === 'titleCase') {\n const value = this.getNestedValue(data, varName)\n if (value !== undefined && value !== null) {\n return this.titleCase(String(value))\n }\n }\n \n return match // Return original if helper not found\n })\n\n // Final pass: Handle simple variables {{variable}}\n rendered = rendered.replace(/\\{\\{([^}#\\/]+)\\}\\}/g, (match, variable) => {\n const trimmed = variable.trim()\n \n // Skip if it's a helper function (has spaces)\n if (trimmed.includes(' ')) {\n return match\n }\n \n const value = this.getNestedValue(data, trimmed)\n if (value === null) return ''\n if (value === undefined) return ''\n return String(value)\n })\n\n return rendered\n }\n\n /**\n * Get nested value from object using dot notation\n */\n private getNestedValue(obj: any, path: string): any {\n if (!obj || path === '') return undefined\n \n return path.split('.').reduce((current, key) => {\n if (current === null || current === undefined) return undefined\n return current[key]\n }, obj)\n }\n\n /**\n * Title case helper function\n */\n private titleCase(str: string): string {\n return str\n .replace(/_/g, ' ')\n .replace(/\\b\\w/g, l => l.toUpperCase())\n }\n\n /**\n * Render a template string with data\n */\n render(template: string, data: TemplateData = {}): string {\n return this.renderTemplate(template, data)\n }\n\n /**\n * Clear template cache (useful for development)\n */\n clearCache(): void {\n this.templateCache.clear()\n }\n}\n\n// Export singleton instance\nexport const templateRenderer = new TemplateRenderer()\n\n// Utility function to render template strings directly\nexport function renderTemplate(template: string, data: TemplateData = {}): string {\n return templateRenderer.render(template, data)\n}","/**\n * Query Filter Builder for SonicJS AI\n * Supports comprehensive filtering with AND/OR logic\n * Compatible with D1 Database (SQLite)\n */\n\nexport type FilterOperator =\n | 'equals'\n | 'not_equals'\n | 'greater_than'\n | 'greater_than_equal'\n | 'less_than'\n | 'less_than_equal'\n | 'like'\n | 'contains'\n | 'starts_with'\n | 'ends_with'\n | 'in'\n | 'not_in'\n | 'all'\n | 'exists'\n | 'near'\n | 'within'\n | 'intersects'\n\nconst VALID_FILTER_OPERATORS: ReadonlySet<FilterOperator> = new Set<FilterOperator>([\n 'equals',\n 'not_equals',\n 'greater_than',\n 'greater_than_equal',\n 'less_than',\n 'less_than_equal',\n 'like',\n 'contains',\n 'starts_with',\n 'ends_with',\n 'in',\n 'not_in',\n 'all',\n 'exists',\n 'near',\n 'within',\n 'intersects'\n])\n\nexport interface FilterCondition {\n field: string\n operator: FilterOperator\n value: any\n}\n\nexport interface FilterGroup {\n and?: FilterCondition[]\n or?: FilterCondition[]\n}\n\nexport interface QueryFilter {\n where?: FilterGroup\n limit?: number\n offset?: number\n sort?: {\n field: string\n order: 'asc' | 'desc'\n }[]\n}\n\nexport interface QueryResult {\n sql: string\n params: any[]\n errors: string[]\n}\n\n/**\n * Validate sort order value - only 'asc' or 'desc' are allowed.\n * Returns the validated lowercase value, defaulting to 'asc' for invalid input.\n */\nexport function validateSortOrder(order: any): 'asc' | 'desc' {\n if (typeof order === 'string') {\n const normalized = order.toLowerCase().trim()\n if (normalized === 'asc' || normalized === 'desc') {\n return normalized\n }\n }\n return 'asc'\n}\n\n/**\n * Query Filter Builder\n * Converts filter objects into SQL WHERE clauses with parameterized queries\n */\nexport class QueryFilterBuilder {\n private params: any[] = []\n private errors: string[] = []\n\n /**\n * Build a complete SQL query from filter object\n */\n build(baseTable: string, filter: QueryFilter): QueryResult {\n this.params = []\n this.errors = []\n\n let sql = `SELECT * FROM ${baseTable}`\n\n // Build WHERE clause\n if (filter.where) {\n const whereClause = this.buildWhereClause(filter.where)\n if (whereClause) {\n sql += ` WHERE ${whereClause}`\n }\n }\n\n // Build ORDER BY clause\n if (filter.sort && filter.sort.length > 0) {\n const orderClauses = filter.sort\n .map(s => `${this.sanitizeFieldName(s.field)} ${this.sanitizeSortOrder(s.order)}`)\n .join(', ')\n sql += ` ORDER BY ${orderClauses}`\n }\n\n // Build LIMIT clause\n if (filter.limit) {\n sql += ` LIMIT ?`\n this.params.push(filter.limit)\n }\n\n // Build OFFSET clause\n if (filter.offset) {\n sql += ` OFFSET ?`\n this.params.push(filter.offset)\n }\n\n return {\n sql,\n params: this.params,\n errors: this.errors\n }\n }\n\n /**\n * Build WHERE clause from filter group\n */\n private buildWhereClause(group: FilterGroup): string {\n const clauses: string[] = []\n\n // Handle AND conditions\n if (group.and && group.and.length > 0) {\n const andClauses = group.and\n .map(condition => this.buildCondition(condition))\n .filter(clause => clause !== null)\n\n if (andClauses.length > 0) {\n clauses.push(`(${andClauses.join(' AND ')})`)\n }\n }\n\n // Handle OR conditions\n if (group.or && group.or.length > 0) {\n const orClauses = group.or\n .map(condition => this.buildCondition(condition))\n .filter(clause => clause !== null)\n\n if (orClauses.length > 0) {\n clauses.push(`(${orClauses.join(' OR ')})`)\n }\n }\n\n return clauses.join(' AND ')\n }\n\n /**\n * Build a single condition\n */\n private buildCondition(condition: FilterCondition): string | null {\n const field = this.sanitizeFieldName(condition.field)\n\n switch (condition.operator) {\n case 'equals':\n return this.buildEquals(field, condition.value)\n\n case 'not_equals':\n return this.buildNotEquals(field, condition.value)\n\n case 'greater_than':\n return this.buildComparison(field, '>', condition.value)\n\n case 'greater_than_equal':\n return this.buildComparison(field, '>=', condition.value)\n\n case 'less_than':\n return this.buildComparison(field, '<', condition.value)\n\n case 'less_than_equal':\n return this.buildComparison(field, '<=', condition.value)\n\n case 'like':\n return this.buildLike(field, condition.value)\n\n case 'contains':\n return this.buildContains(field, condition.value)\n\n case 'starts_with':\n return this.buildStartsWith(field, condition.value)\n\n case 'ends_with':\n return this.buildEndsWith(field, condition.value)\n\n case 'in':\n return this.buildIn(field, condition.value)\n\n case 'not_in':\n return this.buildNotIn(field, condition.value)\n\n case 'all':\n return this.buildAll(field, condition.value)\n\n case 'exists':\n return this.buildExists(field, condition.value)\n\n case 'near':\n this.errors.push(`'near' operator not supported in SQLite. Use spatial extension or application-level filtering.`)\n return null\n\n case 'within':\n this.errors.push(`'within' operator not supported in SQLite. Use spatial extension or application-level filtering.`)\n return null\n\n case 'intersects':\n this.errors.push(`'intersects' operator not supported in SQLite. Use spatial extension or application-level filtering.`)\n return null\n\n default:\n this.errors.push(`Unknown operator: ${condition.operator}`)\n return null\n }\n }\n\n /**\n * Build equals condition\n */\n private buildEquals(field: string, value: any): string {\n if (value === null) {\n return `${field} IS NULL`\n }\n this.params.push(value)\n return `${field} = ?`\n }\n\n /**\n * Build not equals condition\n */\n private buildNotEquals(field: string, value: any): string {\n if (value === null) {\n return `${field} IS NOT NULL`\n }\n this.params.push(value)\n return `${field} != ?`\n }\n\n /**\n * Build comparison condition (>, >=, <, <=)\n */\n private buildComparison(field: string, operator: string, value: any): string {\n this.params.push(value)\n return `${field} ${operator} ?`\n }\n\n /**\n * Build LIKE condition (case-insensitive, all words must be present)\n */\n private buildLike(field: string, value: string): string {\n const words = value.split(/\\s+/).filter(w => w.length > 0)\n\n if (words.length === 0) {\n return `1=1` // No-op condition\n }\n\n const conditions = words.map(word => {\n this.params.push(`%${word}%`)\n return `${field} LIKE ?`\n })\n\n return `(${conditions.join(' AND ')})`\n }\n\n /**\n * Build CONTAINS condition (case-insensitive substring)\n */\n private buildContains(field: string, value: string): string {\n this.params.push(`%${value}%`)\n return `${field} LIKE ?`\n }\n\n /**\n * Build STARTS_WITH condition (case-insensitive prefix match)\n */\n private buildStartsWith(field: string, value: string): string {\n this.params.push(`${value}%`)\n return `${field} LIKE ?`\n }\n\n /**\n * Build ENDS_WITH condition (case-insensitive suffix match)\n */\n private buildEndsWith(field: string, value: string): string {\n this.params.push(`%${value}`)\n return `${field} LIKE ?`\n }\n\n /**\n * Build IN condition\n */\n private buildIn(field: string, value: any): string {\n let values: any[]\n\n if (typeof value === 'string') {\n // Parse comma-delimited string\n values = value.split(',').map(v => v.trim()).filter(v => v.length > 0)\n } else if (Array.isArray(value)) {\n values = value\n } else {\n values = [value]\n }\n\n if (values.length === 0) {\n return `1=0` // No values means no matches\n }\n\n const placeholders = values.map(v => {\n this.params.push(v)\n return '?'\n }).join(', ')\n\n return `${field} IN (${placeholders})`\n }\n\n /**\n * Build NOT IN condition\n */\n private buildNotIn(field: string, value: any): string {\n let values: any[]\n\n if (typeof value === 'string') {\n // Parse comma-delimited string\n values = value.split(',').map(v => v.trim()).filter(v => v.length > 0)\n } else if (Array.isArray(value)) {\n values = value\n } else {\n values = [value]\n }\n\n if (values.length === 0) {\n return `1=1` // No values means all match\n }\n\n const placeholders = values.map(v => {\n this.params.push(v)\n return '?'\n }).join(', ')\n\n return `${field} NOT IN (${placeholders})`\n }\n\n /**\n * Build ALL condition (value must contain all items in list)\n * For SQLite, we'll check if a JSON array contains all values\n */\n private buildAll(field: string, value: any): string {\n let values: any[]\n\n if (typeof value === 'string') {\n values = value.split(',').map(v => v.trim()).filter(v => v.length > 0)\n } else if (Array.isArray(value)) {\n values = value\n } else {\n values = [value]\n }\n\n if (values.length === 0) {\n return `1=1`\n }\n\n // For SQLite, check if field contains all values using JSON functions\n // This assumes the field is a JSON array or comma-separated string\n const conditions = values.map(val => {\n this.params.push(`%${val}%`)\n return `${field} LIKE ?`\n })\n\n return `(${conditions.join(' AND ')})`\n }\n\n /**\n * Build EXISTS condition\n */\n private buildExists(field: string, value: boolean): string {\n if (value) {\n return `${field} IS NOT NULL AND ${field} != ''`\n } else {\n return `(${field} IS NULL OR ${field} = '')`\n }\n }\n\n /**\n * Sanitize field names to prevent SQL injection\n */\n private sanitizeFieldName(field: string): string {\n // Allow alphanumeric, underscores, dots (for JSON fields)\n const sanitized = field.replace(/[^a-zA-Z0-9_$.]/g, '')\n\n // Handle JSON field access (e.g., data.title -> json_extract(data, '$.title'))\n if (sanitized.includes('.')) {\n const [table, ...path] = sanitized.split('.')\n return `json_extract(${table}, '$.${path.join('.')}')`\n }\n\n return sanitized\n }\n\n /**\n * Sanitize sort order to prevent SQL injection\n * Only allows 'ASC' or 'DESC', defaults to 'ASC' for any other value\n */\n private sanitizeSortOrder(order: string): string {\n const normalized = String(order).toUpperCase().trim()\n if (normalized === 'ASC' || normalized === 'DESC') {\n return normalized\n }\n return 'ASC'\n }\n\n /**\n * Parse filter from query string\n */\n static parseFromQuery(query: Record<string, any>): QueryFilter {\n const filter: QueryFilter = {}\n\n // Parse where clause from 'where' parameter (JSON string)\n if (query.where) {\n try {\n filter.where = typeof query.where === 'string'\n ? JSON.parse(query.where)\n : query.where\n } catch (e) {\n console.error('Failed to parse where clause:', e)\n }\n }\n\n // Initialize where clause if not present\n if (!filter.where) {\n filter.where = { and: [] }\n }\n if (!filter.where.and) {\n filter.where.and = []\n }\n\n // Parse simple field filters (status, collection_id, etc.)\n // These are convenience parameters that get converted to WHERE conditions\n const simpleFieldMappings: Record<string, string> = {\n 'status': 'status',\n 'collection_id': 'collection_id'\n }\n\n for (const [queryParam, dbField] of Object.entries(simpleFieldMappings)) {\n if (query[queryParam]) {\n filter.where.and.push({\n field: dbField,\n operator: 'equals',\n value: query[queryParam]\n })\n }\n }\n\n // Parse bracket-syntax filters: filter[field][operator]=value or where[field][operator]=value\n const bracketFilterRegex = /^(?:filter|where)\\[([^\\]]+)\\](?:\\[([^\\]]+)\\])?$/\n for (const [key, rawValue] of Object.entries(query)) {\n const match = key.match(bracketFilterRegex)\n if (!match) continue\n\n const field = match[1]\n const operator = (match[2] || 'equals') as FilterOperator\n\n if (!field || !VALID_FILTER_OPERATORS.has(operator)) continue\n if (rawValue === undefined || rawValue === null) continue\n\n let value: any = rawValue\n if (operator === 'exists') {\n value = value === 'true' || value === true || value === '1' || value === 1\n }\n\n filter.where.and.push({ field, operator, value })\n }\n\n // Parse limit\n if (query.limit) {\n filter.limit = Math.min(parseInt(query.limit), 1000) // Max 1000\n }\n\n // Parse offset\n if (query.offset) {\n filter.offset = parseInt(query.offset)\n }\n\n // Parse sort\n if (query.sort) {\n try {\n const parsed = typeof query.sort === 'string'\n ? JSON.parse(query.sort)\n : query.sort\n // Validate and sanitize sort entries\n if (Array.isArray(parsed)) {\n filter.sort = parsed\n .filter((s: any) => s && typeof s.field === 'string')\n .map((s: any) => ({\n field: s.field,\n order: validateSortOrder(s.order)\n }))\n }\n } catch (e) {\n console.error('Failed to parse sort clause:', e)\n }\n }\n\n return filter\n }\n}\n\n/**\n * Helper function to build query from filter\n */\nexport function buildQuery(table: string, filter: QueryFilter): QueryResult {\n const builder = new QueryFilterBuilder()\n return builder.build(table, filter)\n}\n","import type { BlockDefinitions } from '../types/collection-config'\n\nexport type BlocksFieldConfig = {\n blocks: BlockDefinitions\n discriminator: string\n}\n\nexport function getBlocksFieldConfig(fieldOptions: any): BlocksFieldConfig | null {\n if (!fieldOptions || typeof fieldOptions !== 'object') return null\n\n const itemsConfig = fieldOptions.items && typeof fieldOptions.items === 'object'\n ? fieldOptions.items\n : null\n\n if (!itemsConfig || !itemsConfig.blocks || typeof itemsConfig.blocks !== 'object') {\n return null\n }\n\n const discriminator = typeof itemsConfig.discriminator === 'string' && itemsConfig.discriminator\n ? itemsConfig.discriminator\n : 'blockType'\n\n return {\n blocks: itemsConfig.blocks as BlockDefinitions,\n discriminator\n }\n}\n\nfunction generateBlockId(): string {\n const bytes = new Uint8Array(6)\n crypto.getRandomValues(bytes)\n return 'blk_' + Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('')\n}\n\nexport function parseBlocksValue(value: unknown, config: BlocksFieldConfig) {\n const errors: string[] = []\n let rawValue = value\n\n if (rawValue === null || rawValue === undefined || rawValue === '') {\n return { value: [] as any[], errors }\n }\n\n if (typeof rawValue === 'string') {\n try {\n rawValue = JSON.parse(rawValue)\n } catch {\n return { value: [] as any[], errors: ['Blocks value must be valid JSON'] }\n }\n }\n\n if (!Array.isArray(rawValue)) {\n return { value: [] as any[], errors: ['Blocks value must be an array'] }\n }\n\n const normalized = rawValue.map((item, index) => {\n if (!item || typeof item !== 'object') {\n errors.push(`Block #${index + 1} must be an object`)\n return null\n }\n\n let block: any\n if ((item as any).blockType && (item as any).data && typeof (item as any).data === 'object') {\n block = { [config.discriminator]: (item as any).blockType, ...(item as any).data }\n } else {\n if (!(config.discriminator in (item as any))) {\n errors.push(`Block #${index + 1} is missing \"${config.discriminator}\"`)\n }\n block = item as any\n }\n\n // Preserve existing blockId or generate a stable one for new blocks\n if (!block.blockId) {\n block = { blockId: generateBlockId(), ...block }\n }\n\n return block\n }).filter((item) => item !== null)\n\n return { value: normalized, errors }\n}\n"]}
@@ -539,6 +539,12 @@ function renderAdminLayoutCatalyst(data) {
539
539
  }
540
540
  function renderCatalystSidebar(currentPath = "", user, dynamicMenuItems, isMobile = false, version, enableExperimentalFeatures) {
541
541
  const resolvedMenuItems = dynamicMenuItems ?? [];
542
+ const userRole = user?.role ?? "viewer";
543
+ const isAdmin = userRole === "admin";
544
+ const isEditor = userRole === "editor";
545
+ const canManageUsers = isAdmin;
546
+ const canAccessSettings = isAdmin || isEditor;
547
+ const canAccessPlugins = isAdmin;
542
548
  let baseMenuItems = [
543
549
  {
544
550
  label: "Content",
@@ -554,13 +560,13 @@ function renderCatalystSidebar(currentPath = "", user, dynamicMenuItems, isMobil
554
560
  <path d="M7 3a1 1 0 000 2h6a1 1 0 100-2H7zM4 7a1 1 0 011-1h10a1 1 0 110 2H5a1 1 0 01-1-1zM2 11a2 2 0 012-2h12a2 2 0 012 2v4a2 2 0 01-2 2H4a2 2 0 01-2-2v-4z"/>
555
561
  </svg>`
556
562
  },
557
- {
563
+ ...canManageUsers ? [{
558
564
  label: "Users",
559
565
  path: "/admin/users",
560
566
  icon: `<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
561
567
  <path d="M9 6a3 3 0 11-6 0 3 3 0 016 0zM17 6a3 3 0 11-6 0 3 3 0 016 0zM12.93 17c.046-.327.07-.66.07-1a6.97 6.97 0 00-1.5-4.33A5 5 0 0119 16v1h-6.07zM6 11a5 5 0 015 5v1H1v-1a5 5 0 015-5z"/>
562
568
  </svg>`
563
- }
569
+ }] : []
564
570
  ];
565
571
  const pluginsIcon = `<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
566
572
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"/>
@@ -642,7 +648,7 @@ function renderCatalystSidebar(currentPath = "", user, dynamicMenuItems, isMobil
642
648
  </span>
643
649
  `;
644
650
  }).join("")}
645
- <!-- Plugins accordion -->
651
+ ${canAccessPlugins ? `<!-- Plugins accordion -->
646
652
  <div data-plugins-accordion class="relative">
647
653
  ${isPluginsActive ? '<span class="absolute inset-y-2 -left-4 w-0.5 rounded-full bg-cyan-500 dark:bg-cyan-400"></span>' : ""}
648
654
  <div class="flex w-full items-center">
@@ -669,7 +675,7 @@ function renderCatalystSidebar(currentPath = "", user, dynamicMenuItems, isMobil
669
675
  <div data-plugins-submenu class="pl-6 mt-0.5 flex flex-col gap-0.5">
670
676
  ${pluginsSubItems}
671
677
  </div>
672
- </div>
678
+ </div>` : ""}
673
679
  <!-- /ADMIN_SIDEBAR_NAV_ITEMS -->
674
680
  </div>
675
681
  </div>
@@ -715,7 +721,7 @@ function renderCatalystSidebar(currentPath = "", user, dynamicMenuItems, isMobil
715
721
  </div>
716
722
  </div>
717
723
 
718
- <!-- Settings Menu Item (Bottom) -->
724
+ ${canAccessSettings ? `<!-- Settings Menu Item (Bottom) -->
719
725
  <div class="border-t border-zinc-950/5 p-4 dark:border-white/5">
720
726
  ${(() => {
721
727
  const isActive = currentPath === settingsMenuItem.path || currentPath?.startsWith(settingsMenuItem.path);
@@ -737,7 +743,7 @@ function renderCatalystSidebar(currentPath = "", user, dynamicMenuItems, isMobil
737
743
  </span>
738
744
  `;
739
745
  })()}
740
- </div>
746
+ </div>` : ""}
741
747
 
742
748
  <!-- Sidebar Footer (User) -->
743
749
  ${user ? `
@@ -806,5 +812,5 @@ var init_admin_layout_catalyst_template = __esm({
806
812
  });
807
813
 
808
814
  export { admin_layout_catalyst_template_exports, init_admin_layout_catalyst_template, init_logo_template, renderAdminLayoutCatalyst, renderCatalystCheckbox, renderLogo, setBranchLabel };
809
- //# sourceMappingURL=chunk-THFZSDIU.js.map
810
- //# sourceMappingURL=chunk-THFZSDIU.js.map
815
+ //# sourceMappingURL=chunk-SXC4HPK6.js.map
816
+ //# sourceMappingURL=chunk-SXC4HPK6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/templates/components/logo.template.ts","../src/templates/layouts/admin-layout-catalyst.template.ts"],"names":[],"mappings":"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","file":"chunk-SXC4HPK6.js","sourcesContent":["export interface LogoData {\n size?: 'sm' | 'md' | 'lg' | 'xl'\n variant?: 'default' | 'white' | 'dark'\n showText?: boolean\n showVersion?: boolean\n version?: string\n className?: string\n href?: string // Optional link URL\n}\n\nconst sizeClasses = {\n sm: 'h-6 w-auto',\n md: 'h-8 w-auto',\n lg: 'h-12 w-auto',\n xl: 'h-16 w-auto'\n}\n\n\nexport function renderLogo(data: LogoData = {}): string {\n const {\n size = 'md',\n variant = 'default',\n showText = true,\n showVersion = true,\n version,\n className = '',\n href\n } = data\n\n const sizeClass = sizeClasses[size]\n\n // Official SonicJS logo SVG from sonicjs.com\n const logoSvg = `\n <svg class=\"${sizeClass} ${className}\" viewBox=\"380 1300 2250 400\" aria-hidden=\"true\">\n <path fill=\"${variant === 'white' ? '#ffffff' : variant === 'dark' ? '#1f2937' : '#F1F2F2'}\" d=\"M476.851,1404.673h168.536c4.714,0,8.695-1.618,11.944-4.866c3.241-3.241,4.866-7.222,4.866-11.943 c0-2.357-0.443-4.569-1.327-6.636c-0.885-2.06-2.067-3.829-3.539-5.308c-1.479-1.472-3.249-2.654-5.308-3.538 c-2.067-0.885-4.279-1.327-6.635-1.327H476.851c-20.057,0-37.158,7.154-51.313,21.454c-14.155,14.308-21.233,31.483-21.233,51.534 c0,20.058,7.078,37.234,21.233,51.534c14.155,14.308,31.255,21.454,51.313,21.454h112.357c10.907,0,20.196,3.837,27.868,11.502 c7.666,7.672,11.502,16.885,11.502,27.646c0,10.769-3.836,19.982-11.502,27.647c-7.672,7.673-16.961,11.502-27.868,11.502H421.115 c-4.721,0-8.702,1.624-11.944,4.865c-3.248,3.249-4.866,7.23-4.866,11.944c0,3.248,0.733,6.123,2.212,8.626 c1.472,2.509,3.462,4.499,5.971,5.972c2.502,1.472,5.378,2.212,8.626,2.212h168.094c20.052,0,37.227-7.078,51.534-21.234 c14.3-14.155,21.454-31.331,21.454-51.534c0-20.196-7.154-37.379-21.454-51.534c-14.308-14.156-31.483-21.234-51.534-21.234 H476.851c-10.616,0-19.76-3.905-27.426-11.721c-7.672-7.811-11.501-17.101-11.501-27.87c0-10.761,3.829-19.975,11.501-27.647 C457.091,1408.508,466.235,1404.673,476.851,1404.673z\"></path>\n <path fill=\"${variant === 'white' ? '#ffffff' : variant === 'dark' ? '#1f2937' : '#F1F2F2'}\" d=\"M974.78,1398.211c-5.016,6.574-10.034,13.146-15.048,19.721c-1.828,2.398-3.657,4.796-5.487,7.194 c1.994,1.719,3.958,3.51,5.873,5.424c18.724,18.731,28.089,41.216,28.089,67.459c0,26.251-9.366,48.658-28.089,67.237 c-18.731,18.579-41.215,27.868-67.459,27.868c-9.848,0-19.156-1.308-27.923-3.923l-4.185,3.354 c-8.587,6.885-17.154,13.796-25.725,20.702c17.52,8.967,36.86,13.487,58.054,13.487c35.533,0,65.91-12.608,91.124-37.821 c25.214-25.215,37.821-55.584,37.821-91.125c0-35.534-12.607-65.911-37.821-91.126 C981.004,1403.663,977.926,1400.854,974.78,1398.211z\"></path>\n <path fill=\"${variant === 'white' ? '#ffffff' : variant === 'dark' ? '#1f2937' : '#F1F2F2'}\" d=\"M1364.644,1439.619c-4.72,0-8.702,1.624-11.943,4.865c-3.249,3.249-4.866,7.23-4.866,11.944v138.014 l-167.651-211.003c-0.297-0.586-0.74-1.03-1.327-1.326c-4.721-4.714-10.249-7.742-16.588-9.069 c-6.346-1.326-12.608-0.732-18.801,1.77c-6.192,2.509-11.059,6.49-14.598,11.944c-3.539,5.46-5.308,11.577-5.308,18.357v208.348 c0,4.721,1.618,8.703,4.866,11.944c3.241,3.241,7.222,4.865,11.943,4.865c2.945,0,5.751-0.738,8.405-2.211 c2.654-1.472,4.713-3.463,6.193-5.971c1.473-2.503,2.212-5.378,2.212-8.627v-205.251l166.325,209.675 c2.06,2.654,4.423,4.865,7.078,6.635c5.308,3.829,11.349,5.75,18.137,5.75c5.308,0,10.464-1.182,15.482-3.538 c3.539-1.769,6.56-4.127,9.069-7.078c2.502-2.945,4.491-6.338,5.971-10.175c1.473-3.829,2.212-7.664,2.212-11.501v-141.552 c0-4.714-1.624-8.695-4.865-11.944C1373.339,1441.243,1369.359,1439.619,1364.644,1439.619z\"></path>\n <path fill=\"${variant === 'white' ? '#ffffff' : variant === 'dark' ? '#1f2937' : '#F1F2F2'}\" d=\"M1508.406,1432.983c-2.654-1.472-5.46-2.212-8.404-2.212c-4.721,0-8.703,1.7-11.944,5.087 c-3.249,3.395-4.865,7.3-4.865,11.723v163.228c0,4.721,1.616,8.702,4.865,11.943c3.241,3.249,7.223,4.866,11.944,4.866 c2.944,0,5.751-0.732,8.404-2.212c2.655-1.472,4.714-3.539,6.193-6.194c1.473-2.654,2.213-5.453,2.213-8.404V1447.58 c0-2.945-0.74-5.75-2.213-8.405C1513.12,1436.522,1511.06,1434.462,1508.406,1432.983z\"></path>\n <path fill=\"${variant === 'white' ? '#ffffff' : variant === 'dark' ? '#1f2937' : '#F1F2F2'}\" d=\"M1499.78,1367.957c-4.575,0-8.481,1.625-11.722,4.866c-3.249,3.249-4.865,7.23-4.865,11.943 c0,2.951,0.732,5.75,2.212,8.405c1.472,2.654,3.463,4.721,5.971,6.193c2.503,1.479,5.378,2.212,8.627,2.212 c4.423,0,8.328-1.618,11.721-4.865c3.387-3.243,5.088-7.224,5.088-11.944c0-4.713-1.701-8.694-5.088-11.943 C1508.33,1369.582,1504.349,1367.957,1499.78,1367.957z\"></path>\n <path fill=\"${variant === 'white' ? '#ffffff' : variant === 'dark' ? '#1f2937' : '#F1F2F2'}\" d=\"M1859.627,1369.727H1747.27c-35.388,0-65.69,12.607-90.904,37.821 c-25.213,25.215-37.82,55.591-37.82,91.125c0,35.54,12.607,65.911,37.82,91.125c25.215,25.215,55.516,37.821,90.904,37.821h56.178 c4.714,0,8.695-1.618,11.944-4.866c3.241-3.241,4.865-7.222,4.865-11.943c0-4.714-1.624-8.695-4.865-11.943 c-3.249-3.243-7.23-4.866-11.944-4.866h-56.178c-26.251,0-48.659-9.359-67.237-28.09c-18.579-18.723-27.868-41.207-27.868-67.459 c0-26.243,9.29-48.659,27.868-67.237c18.579-18.579,40.987-27.868,67.237-27.868h112.357c4.714,0,8.696-1.693,11.944-5.087 c3.241-3.387,4.865-7.368,4.865-11.943c0-4.569-1.624-8.475-4.865-11.723C1868.322,1371.351,1864.341,1369.727,1859.627,1369.727z \"></path>\n <path fill=\"#06b6d4\" d=\"M2219.256,1371.054h-112.357c-4.423,0-8.336,1.624-11.723,4.865c-3.393,3.249-5.087,7.23-5.087,11.944 c0,4.721,1.694,8.702,5.087,11.943c3.387,3.249,7.3,4.866,11.723,4.866h95.547v95.105c0,26.251-9.365,48.659-28.088,67.237 c-18.731,18.579-41.215,27.868-67.459,27.868c-26.251,0-48.659-9.289-67.237-27.868c-18.579-18.579-27.868-40.987-27.868-67.237 c0-4.713-1.701-8.771-5.088-12.165c-3.393-3.387-7.374-5.087-11.943-5.087c-4.575,0-8.481,1.7-11.722,5.087 c-3.249,3.393-4.865,7.451-4.865,12.165c0,35.388,12.607,65.69,37.82,90.904c25.215,25.213,55.584,37.82,91.126,37.82 c35.532,0,65.91-12.607,91.125-37.82c25.214-25.215,37.82-55.516,37.82-90.904v-111.915c0-4.714-1.624-8.695-4.865-11.944 C2227.951,1372.678,2223.971,1371.054,2219.256,1371.054z\"></path>\n <path fill=\"#06b6d4\" d=\"M2574.24,1502.875c-14.306-14.156-31.483-21.234-51.533-21.234H2410.35 c-10.617,0-19.762-3.829-27.426-11.501c-7.672-7.664-11.501-16.954-11.501-27.868c0-10.907,3.829-20.196,11.501-27.868 c7.664-7.664,16.809-11.501,27.426-11.501h112.357c4.714,0,8.695-1.617,11.944-4.866c3.241-3.241,4.865-7.222,4.865-11.943 c0-4.714-1.624-8.695-4.865-11.944c-3.249-3.241-7.23-4.865-11.944-4.865H2410.35c-20.058,0-37.158,7.154-51.313,21.454 c-14.156,14.308-21.232,31.483-21.232,51.534c0,20.058,7.077,37.234,21.232,51.534c14.156,14.308,31.255,21.454,51.313,21.454 h112.357c7.078,0,13.637,1.77,19.684,5.308c6.042,3.539,10.838,8.336,14.377,14.377c3.538,6.047,5.307,12.607,5.307,19.685 c0,10.616-3.835,19.76-11.501,27.425c-7.672,7.673-16.961,11.502-27.868,11.502h-168.094c-4.721,0-8.703,1.7-11.944,5.087 c-3.249,3.393-4.865,7.374-4.865,11.943c0,4.576,1.616,8.481,4.865,11.723c3.241,3.249,7.223,4.866,11.944,4.866h168.094 c20.051,0,37.227-7.078,51.533-21.234c14.302-14.155,21.454-31.331,21.454-51.534 C2595.695,1534.213,2588.542,1517.03,2574.24,1502.875z\"></path>\n <path fill=\"#06b6d4\" d=\"M854.024,1585.195l20.001-16.028c16.616-13.507,33.04-27.265,50.086-40.251 c1.13-0.861,2.9-1.686,2.003-3.516c-0.843-1.716-2.481-2.302-4.484-2.123c-8.514,0.765-17.016-0.538-25.537-0.353 c-1.124,0.024-2.768,0.221-3.163-1.25c-0.371-1.369,1.088-2.063,1.919-2.894c6.26-6.242,12.574-12.43,18.816-18.691 c9.303-9.327,18.565-18.714,27.851-28.066c1.848-1.859,3.701-3.713,5.549-5.572c2.655-2.661,5.309-5.315,7.958-7.982 c0.574-0.579,1.259-1.141,1.246-1.94c-0.004-0.257-0.078-0.538-0.254-0.853c-0.556-0.981-1.441-1.1-2.469-0.957 c-0.658,0.096-1.315,0.185-1.973,0.275c-3.844,0.538-7.689,1.076-11.533,1.608c-3.641,0.505-7.281,1.02-10.922,1.529 c-4.162,0.582-8.324,1.158-12.486,1.748c-1.142,0.161-2.409,1.662-3.354,0.508c-0.419-0.508-0.431-1.028-0.251-1.531 c0.269-0.741,0.957-1.441,1.387-2.021c3.414-4.58,6.882-9.124,10.356-13.662c1.74-2.272,3.48-4.544,5.214-6.822 c4.682-6.141,9.369-12.281,14.051-18.422c0.09-0.119,0.181-0.237,0.271-0.355c6.848-8.98,13.7-17.958,20.553-26.936 c0.488-0.64,0.977-1.28,1.465-1.92c2.159-2.828,4.315-5.658,6.476-8.486c4.197-5.501,8.454-10.954,12.67-16.442 c0.263-0.347,0.538-0.718,0.717-1.106c0.269-0.586,0.299-1.196-0.335-1.776c-0.825-0.753-1.8-0.15-2.595,0.419 c-0.67,0.472-1.333,0.957-1.955,1.489c-2.206,1.889-4.401,3.797-6.595,5.698c-3.958,3.438-7.922,6.876-11.976,10.194 c-2.443,2.003-4.865,4.028-7.301,6.038c-18.689-10.581-39.53-15.906-62.549-15.906c-35.54,0-65.911,12.607-91.125,37.82 c-25.214,25.215-37.821,55.592-37.821,91.126c0,35.54,12.607,65.91,37.821,91.125c4.146,4.146,8.445,7.916,12.87,11.381 c-9.015,11.14-18.036,22.277-27.034,33.429c-1.208,1.489-3.755,3.151-2.745,4.891c0.078,0.144,0.173,0.281,0.305,0.425 c1.321,1.429,3.492-1.303,4.933-2.457c6.673-5.333,13.333-10.685,19.982-16.042c3.707-2.984,7.417-5.965,11.124-8.952 c1.474-1.188,2.951-2.373,4.425-3.561c6.41-5.164,12.816-10.333,19.238-15.481L854.024,1585.195z M797.552,1498.009 c0-26.243,9.29-48.728,27.868-67.459c18.579-18.723,40.987-28.089,67.238-28.089c12.273,0,23.712,2.075,34.34,6.171 c-3.37,2.905-6.734,5.816-10.069,8.762c-6.075,5.351-12.365,10.469-18.667,15.564c-4.179,3.378-8.371,6.744-12.514,10.164 c-7.54,6.23-15.037,12.52-22.529,18.804c-7.091,5.955-14.182,11.904-21.19,17.949c-1.136,0.974-3.055,1.907-2.135,3.94 c0.831,1.836,2.774,1.417,4.341,1.578l12.145-0.599l14.151-0.698c1.031-0.102,2.192-0.257,2.89,0.632 c0.034,0.044,0.073,0.078,0.106,0.127c1.017,1.561-0.67,2.105-1.387,2.942c-6.308,7.318-12.616,14.637-18.978,21.907 c-8.161,9.339-16.353,18.649-24.544,27.958c-2.146,2.433-4.275,4.879-6.422,7.312c-1.034,1.172-2.129,2.272-1.238,3.922 c0.933,1.728,2.685,1.752,4.323,1.602c4.134-0.367,8.263-0.489,12.396-0.492c0.242,0,0.485-0.005,0.728-0.004 c2.711,0.009,5.422,0.068,8.134,0.145c2.582,0.074,5.166,0.165,7.752,0.249c0.275,1.62-0.879,2.356-1.62,3.259 c-1.333,1.626-2.667,3.247-4,4.867c-4.315,5.252-8.62,10.514-12.928,15.772c-3.562-2.725-7.007-5.733-10.324-9.051 C806.842,1546.667,797.552,1524.26,797.552,1498.009z\"></path>\n </svg>\n `\n\n const versionBadge = showVersion && version ? `\n <span class=\"inline-flex items-center rounded-md px-2 py-0.5 text-xs font-medium ring-1 ring-inset ${\n variant === 'white'\n ? 'bg-white/10 text-white/80 ring-white/20'\n : 'bg-cyan-50 text-cyan-700 ring-cyan-700/10 dark:bg-cyan-500/10 dark:text-cyan-400 dark:ring-cyan-500/20'\n }\">\n ${version}\n </span>\n ` : ''\n\n const logoContent = showText ? `\n <div class=\"flex items-center gap-2 ${className}\">\n ${logoSvg}\n ${versionBadge}\n </div>\n ` : logoSvg\n\n // Wrap in link if href is provided\n if (href) {\n return `<a href=\"${href}\" class=\"inline-block hover:opacity-80 transition-opacity\">${logoContent}</a>`\n }\n\n return logoContent\n}","import { HtmlEscapedString } from \"hono/utils/html\";\nimport { renderLogo } from \"../components/logo.template\";\n\n// Dev-only branch label — set via setBranchLabel() at bootstrap when BRANCH_LABEL env var is present\nlet _branchLabel: string | undefined;\n\nexport function setBranchLabel(label: string | undefined): void {\n _branchLabel = label;\n}\n\nconst BRANCH_COLORS = [\n { bg: \"bg-rose-500\", text: \"text-white\" },\n { bg: \"bg-orange-500\", text: \"text-white\" },\n { bg: \"bg-amber-400\", text: \"text-zinc-900\" },\n { bg: \"bg-lime-500\", text: \"text-zinc-900\" },\n { bg: \"bg-emerald-500\", text: \"text-white\" },\n { bg: \"bg-teal-500\", text: \"text-white\" },\n { bg: \"bg-cyan-500\", text: \"text-zinc-900\" },\n { bg: \"bg-sky-500\", text: \"text-white\" },\n { bg: \"bg-blue-600\", text: \"text-white\" },\n { bg: \"bg-violet-500\", text: \"text-white\" },\n { bg: \"bg-fuchsia-500\", text: \"text-white\" },\n { bg: \"bg-pink-500\", text: \"text-white\" },\n];\n\nfunction branchColor(label: string): { bg: string; text: string } {\n let hash = 5381;\n for (let i = 0; i < label.length; i++) {\n hash = ((hash << 5) + hash) ^ label.charCodeAt(i);\n }\n return BRANCH_COLORS[Math.abs(hash) % BRANCH_COLORS.length] ?? { bg: \"bg-zinc-500\", text: \"text-white\" };\n}\n\n// Catalyst Checkbox Component (HTML implementation)\nexport interface CatalystCheckboxProps {\n id: string;\n name: string;\n checked?: boolean;\n disabled?: boolean;\n label?: string;\n description?: string;\n color?:\n | \"dark/zinc\"\n | \"dark/white\"\n | \"white\"\n | \"dark\"\n | \"zinc\"\n | \"blue\"\n | \"green\"\n | \"red\";\n className?: string;\n}\n\nexport function renderCatalystCheckbox(props: CatalystCheckboxProps): string {\n const {\n id,\n name,\n checked = false,\n disabled = false,\n label,\n description,\n color = \"dark/zinc\",\n className = \"\",\n } = props;\n\n const colorConfig = {\n \"dark/zinc\": {\n bg: \"#18181b\",\n border: \"#09090b\",\n check: \"#ffffff\",\n darkBg: \"#52525b\",\n },\n \"dark/white\": {\n bg: \"#18181b\",\n border: \"#09090b\",\n check: \"#ffffff\",\n darkBg: \"#ffffff\",\n darkCheck: \"#18181b\",\n },\n white: { bg: \"#ffffff\", border: \"#09090b\", check: \"#18181b\" },\n dark: { bg: \"#18181b\", border: \"#09090b\", check: \"#ffffff\" },\n zinc: { bg: \"#52525b\", border: \"#3f3f46\", check: \"#ffffff\" },\n blue: { bg: \"#2563eb\", border: \"#1d4ed8\", check: \"#ffffff\" },\n green: { bg: \"#16a34a\", border: \"#15803d\", check: \"#ffffff\" },\n red: { bg: \"#dc2626\", border: \"#b91c1c\", check: \"#ffffff\" },\n };\n\n const _config = colorConfig[color] || colorConfig[\"dark/zinc\"];\n\n const colorClasses = {\n \"dark/zinc\":\n \"peer-checked:bg-zinc-900 peer-checked:before:bg-zinc-900 dark:peer-checked:bg-zinc-600\",\n \"dark/white\":\n \"peer-checked:bg-zinc-900 peer-checked:before:bg-zinc-900 dark:peer-checked:bg-white\",\n white: \"peer-checked:bg-white peer-checked:before:bg-white\",\n dark: \"peer-checked:bg-zinc-900 peer-checked:before:bg-zinc-900\",\n zinc: \"peer-checked:bg-zinc-600 peer-checked:before:bg-zinc-600\",\n blue: \"peer-checked:bg-blue-600 peer-checked:before:bg-blue-600\",\n green: \"peer-checked:bg-green-600 peer-checked:before:bg-green-600\",\n red: \"peer-checked:bg-red-600 peer-checked:before:bg-red-600\",\n };\n\n const checkColor =\n color === \"dark/white\" ? \"dark:text-zinc-900\" : \"text-white\";\n\n const baseClasses = `\n relative isolate flex w-4 h-4 items-center justify-center rounded-[0.3125rem]\n before:absolute before:inset-0 before:-z-10 before:rounded-[calc(0.3125rem-1px)] before:bg-white before:shadow-sm\n dark:before:hidden\n dark:bg-white/5\n border border-zinc-950/15 peer-checked:border-transparent\n dark:border-white/15 dark:peer-checked:border-white/5\n peer-focus:outline peer-focus:outline-2 peer-focus:outline-offset-2 peer-focus:outline-blue-500\n peer-disabled:opacity-50\n peer-disabled:border-zinc-950/25 peer-disabled:bg-zinc-950/5\n dark:peer-disabled:border-white/20 dark:peer-disabled:bg-white/2.5\n `\n .trim()\n .replace(/\\s+/g, \" \");\n\n const checkIconClasses = `\n w-4 h-4 opacity-0 peer-checked:opacity-100 pointer-events-none\n `\n .trim()\n .replace(/\\s+/g, \" \");\n\n if (description) {\n // Field layout with description\n return `\n <div class=\"grid grid-cols-[1.125rem_1fr] gap-x-4 gap-y-1 sm:grid-cols-[1rem_1fr] ${className}\">\n <div class=\"col-start-1 row-start-1 mt-0.75 sm:mt-1\">\n <input\n type=\"checkbox\"\n id=\"${id}\"\n name=\"${name}\"\n ${checked ? \"checked\" : \"\"}\n ${disabled ? \"disabled\" : \"\"}\n class=\"peer sr-only\"\n />\n <label for=\"${id}\" class=\"inline-flex cursor-pointer\">\n <span class=\"${baseClasses} ${colorClasses[color] || colorClasses[\"dark/zinc\"]}\">\n <svg class=\"${checkIconClasses} ${checkColor}\" viewBox=\"0 0 14 14\" fill=\"none\" stroke=\"currentColor\">\n <path d=\"M3 8L6 11L11 3.5\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n </label>\n </div>\n ${label ? `<label for=\"${id}\" class=\"col-start-2 row-start-1 text-sm/6 font-medium text-zinc-950 dark:text-white cursor-pointer\">${label}</label>` : \"\"}\n ${description ? `<p class=\"col-start-2 row-start-2 text-sm/6 text-zinc-500 dark:text-zinc-400\">${description}</p>` : \"\"}\n </div>\n `;\n } else {\n // Simple checkbox with optional label\n return `\n <label class=\"inline-flex items-center gap-3 cursor-pointer ${className}\">\n <input\n type=\"checkbox\"\n id=\"${id}\"\n name=\"${name}\"\n ${checked ? \"checked\" : \"\"}\n ${disabled ? \"disabled\" : \"\"}\n class=\"peer sr-only\"\n />\n <span class=\"${baseClasses} ${colorClasses[color] || colorClasses[\"dark/zinc\"]}\">\n <svg class=\"${checkIconClasses} ${checkColor}\" viewBox=\"0 0 14 14\" fill=\"none\" stroke=\"currentColor\">\n <path d=\"M3 8L6 11L11 3.5\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n ${label ? `<span class=\"text-sm/6 font-medium text-zinc-950 dark:text-white\">${label}</span>` : \"\"}\n </label>\n `;\n }\n}\n\nexport interface AdminLayoutCatalystData {\n title: string;\n pageTitle?: string;\n currentPath?: string;\n version?: string;\n enableExperimentalFeatures?: boolean;\n user?: {\n name: string;\n email: string;\n role: string;\n };\n scripts?: string[];\n styles?: string[];\n content: string | HtmlEscapedString;\n dynamicMenuItems?: Array<{\n label: string;\n path: string;\n icon: string;\n }>;\n}\n\nexport function renderAdminLayoutCatalyst(\n data: AdminLayoutCatalystData\n): string {\n return `<!DOCTYPE html>\n<html lang=\"en\" class=\"dark\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${data.title} - SonicJS AI Admin</title>\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"/favicon.svg\">\n\n <!-- Tailwind CSS -->\n <script src=\"https://cdn.tailwindcss.com\"></script>\n <script>\n tailwind.config = {\n darkMode: 'class',\n theme: {\n extend: {\n colors: {\n zinc: {\n 50: '#fafafa',\n 100: '#f4f4f5',\n 200: '#e4e4e7',\n 300: '#d4d4d8',\n 400: '#a1a1aa',\n 500: '#71717a',\n 600: '#52525b',\n 700: '#3f3f46',\n 800: '#27272a',\n 900: '#18181b',\n 950: '#09090b'\n }\n }\n }\n }\n }\n </script>\n\n <!-- Additional Styles -->\n <style>\n @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');\n\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n\n body {\n font-family: 'Inter', system-ui, -apple-system, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n /* Custom scrollbar */\n ::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n }\n\n ::-webkit-scrollbar-track {\n background: #27272a;\n }\n\n ::-webkit-scrollbar-thumb {\n background: #52525b;\n border-radius: 4px;\n }\n\n ::-webkit-scrollbar-thumb:hover {\n background: #71717a;\n }\n\n /* Smooth transitions */\n * {\n transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n }\n .plugins-closed [data-plugins-submenu] { display: none; }\n </style>\n <!-- Restore plugins submenu state before first paint (no flash) -->\n <script>(function(){try{var c=document.cookie.split(';').reduce(function(v,p){var t=p.trim().split('=');return t[0]==='plugins_menu_open'?t[1]:v;},null);if(c==='0'){document.documentElement.classList.add('plugins-closed');document.addEventListener('DOMContentLoaded',function(){var ch=document.querySelector('[data-plugins-chevron]');if(ch)ch.classList.remove('rotate-180');});};}catch(e){}})();</script>\n\n <!-- Scripts -->\n <script src=\"https://unpkg.com/htmx.org@2.0.3\"></script>\n <script src=\"https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js\" defer></script>\n <script src=\"https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js\"></script>\n\n <!-- CSRF: Auto-attach token to all HTMX and fetch requests -->\n <script>\n function getCsrfToken() {\n var cookie = document.cookie.split('; ')\n .find(function(row) { return row.startsWith('csrf_token='); });\n return cookie ? cookie.substring(cookie.indexOf('=') + 1) : '';\n }\n\n document.addEventListener('htmx:configRequest', function(event) {\n var token = getCsrfToken();\n if (token) {\n event.detail.headers['X-CSRF-Token'] = token;\n }\n });\n\n (function() {\n var originalFetch = window.fetch;\n window.fetch = function(url, options) {\n options = options || {};\n var method = (options.method || 'GET').toUpperCase();\n if (method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS') {\n options.headers = options.headers || {};\n if (options.headers instanceof Headers) {\n if (!options.headers.has('X-CSRF-Token')) {\n options.headers.set('X-CSRF-Token', getCsrfToken());\n }\n } else if (!Array.isArray(options.headers) && !options.headers['X-CSRF-Token']) {\n options.headers['X-CSRF-Token'] = getCsrfToken();\n }\n }\n return originalFetch.call(this, url, options);\n };\n })();\n\n // Inject _csrf hidden field into regular form submissions (non-HTMX)\n document.addEventListener('submit', function(event) {\n var form = event.target;\n if (!form || !form.tagName || form.tagName !== 'FORM') return;\n var method = (form.method || 'GET').toUpperCase();\n if (method === 'GET') return;\n if (form.hasAttribute('hx-post') || form.hasAttribute('hx-put') ||\n form.hasAttribute('hx-delete') || form.hasAttribute('hx-patch')) return;\n if (!form.querySelector('input[name=\"_csrf\"]')) {\n var input = document.createElement('input');\n input.type = 'hidden';\n input.name = '_csrf';\n input.value = getCsrfToken();\n form.appendChild(input);\n }\n });\n </script>\n\n ${\n data.styles\n ? data.styles\n .map((style) => `<link rel=\"stylesheet\" href=\"${style}\">`)\n .join(\"\\n \")\n : \"\"\n }\n ${\n data.scripts\n ? data.scripts\n .map((script) => `<script src=\"${script}\"></script>`)\n .join(\"\\n \")\n : \"\"\n }\n</head>\n<body class=\"min-h-screen bg-white dark:bg-zinc-900\">\n <div class=\"relative isolate flex min-h-svh w-full max-lg:flex-col lg:bg-zinc-100 dark:lg:bg-zinc-950\">\n <!-- Sidebar on desktop -->\n <div class=\"fixed inset-y-0 left-0 w-64 max-lg:hidden\">\n ${renderCatalystSidebar(\n data.currentPath,\n data.user,\n data.dynamicMenuItems,\n false,\n data.version,\n data.enableExperimentalFeatures\n )}\n </div>\n\n <!-- Mobile sidebar (hidden by default) -->\n <div id=\"mobile-sidebar-overlay\" class=\"fixed inset-0 bg-black/30 lg:hidden hidden z-40\" onclick=\"closeMobileSidebar()\"></div>\n <div id=\"mobile-sidebar\" class=\"fixed inset-y-0 left-0 w-80 transform -translate-x-full transition-transform duration-300 ease-in-out lg:hidden z-50\">\n ${renderCatalystSidebar(\n data.currentPath,\n data.user,\n data.dynamicMenuItems,\n true,\n data.version,\n data.enableExperimentalFeatures\n )}\n </div>\n\n <!-- Main content area -->\n <main class=\"flex flex-1 flex-col pb-2 lg:min-w-0 lg:pr-2 lg:pl-64\">\n <!-- Mobile header with menu toggle -->\n <header class=\"flex items-center px-4 py-2.5 lg:hidden border-b border-zinc-950/5 dark:border-white/5\">\n <button onclick=\"openMobileSidebar()\" class=\"relative flex items-center justify-center rounded-lg p-2 text-zinc-950 hover:bg-zinc-950/5 dark:text-white dark:hover:bg-white/5\" aria-label=\"Open navigation\">\n <svg class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path d=\"M2 6.75C2 6.33579 2.33579 6 2.75 6H17.25C17.6642 6 18 6.33579 18 6.75C18 7.16421 17.6642 7.5 17.25 7.5H2.75C2.33579 7.5 2 7.16421 2 6.75ZM2 13.25C2 12.8358 2.33579 12.5 2.75 12.5H17.25C17.6642 12.5 18 12.8358 18 13.25C18 13.6642 17.6642 14 17.25 14H2.75C2.33579 14 2 13.6642 2 13.25Z\" />\n </svg>\n </button>\n <div class=\"ml-4 flex-1\">\n ${renderLogo({ size: \"sm\", showText: true, variant: \"white\", version: data.version, href: \"/admin/content\" })}\n </div>\n </header>\n\n <!-- Content -->\n <div class=\"grow p-6 lg:rounded-lg lg:bg-white lg:p-10 lg:shadow-sm lg:ring-1 lg:ring-zinc-950/5 dark:lg:bg-zinc-900 dark:lg:ring-white/10\">\n ${data.content}\n </div>\n </main>\n </div>\n\n <!-- Notification Container -->\n <div id=\"notification-container\" class=\"fixed top-4 right-4 z-50 space-y-2\"></div>\n\n <!-- Migration Warning Banner (hidden by default) -->\n <div id=\"migration-banner\" class=\"hidden fixed top-0 left-0 right-0 z-50 bg-amber-500 dark:bg-amber-600 shadow-lg\">\n <div class=\"max-w-7xl mx-auto px-4 py-3 sm:px-6 lg:px-8\">\n <div class=\"flex items-center justify-between flex-wrap\">\n <div class=\"flex items-center flex-1\">\n <span class=\"flex p-2 rounded-lg bg-amber-600 dark:bg-amber-700\">\n <svg class=\"h-5 w-5 text-white\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"/>\n </svg>\n </span>\n <div class=\"ml-3\">\n <p class=\"text-sm font-medium text-white\">\n <span id=\"migration-count\"></span> pending database migration(s) detected\n </p>\n <p class=\"text-xs text-amber-100 dark:text-amber-200 mt-1\">\n Run: <code class=\"bg-amber-700 dark:bg-amber-800 px-2 py-0.5 rounded font-mono text-white\">wrangler d1 migrations apply DB --local</code>\n </p>\n </div>\n </div>\n <div class=\"flex items-center gap-2\">\n <a href=\"/admin/settings/migrations\" class=\"text-xs font-semibold text-white hover:text-amber-100 underline\">\n View Details\n </a>\n <button onclick=\"closeMigrationBanner()\" class=\"p-1 rounded-md text-white hover:bg-amber-600 dark:hover:bg-amber-700 focus:outline-none focus:ring-2 focus:ring-white\">\n <svg class=\"h-5 w-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"/>\n </svg>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <script>\n // Mobile sidebar toggle\n function openMobileSidebar() {\n const sidebar = document.getElementById('mobile-sidebar');\n const overlay = document.getElementById('mobile-sidebar-overlay');\n sidebar.classList.remove('-translate-x-full');\n overlay.classList.remove('hidden');\n }\n\n function closeMobileSidebar() {\n const sidebar = document.getElementById('mobile-sidebar');\n const overlay = document.getElementById('mobile-sidebar-overlay');\n sidebar.classList.add('-translate-x-full');\n overlay.classList.add('hidden');\n }\n\n // User dropdown toggle\n function toggleUserDropdown() {\n const dropDowns = document.querySelectorAll('.userDropdown');\n dropDowns.forEach(dropdown => {\n dropdown.classList.toggle('hidden');\n });\n }\n\n // Close dropdown when clicking outside\n document.addEventListener('click', function(event) {\n const dropdowns = document.querySelectorAll('.userDropdown');\n const button = event.target.closest('[data-user-menu]');\n if (!button) {\n dropdowns.forEach(function(dropdown) {\n if (!dropdown.contains(event.target)) {\n dropdown.classList.add('hidden');\n }\n });\n }\n });\n\n // Show notification\n function showNotification(message, type = 'info') {\n const container = document.getElementById('notification-container');\n const notification = document.createElement('div');\n const colors = {\n success: 'bg-green-50 dark:bg-green-500/10 text-green-700 dark:text-green-400 ring-green-600/20 dark:ring-green-500/20',\n error: 'bg-red-50 dark:bg-red-500/10 text-red-700 dark:text-red-400 ring-red-600/20 dark:ring-red-500/20',\n warning: 'bg-amber-50 dark:bg-amber-500/10 text-amber-700 dark:text-amber-400 ring-amber-600/20 dark:ring-amber-500/20',\n info: 'bg-blue-50 dark:bg-blue-500/10 text-blue-700 dark:text-blue-400 ring-blue-600/20 dark:ring-blue-500/20'\n };\n\n notification.className = \\`rounded-lg p-4 ring-1 \\${colors[type] || colors.info} max-w-sm shadow-lg\\`;\n notification.innerHTML = \\`\n <div class=\"flex items-center justify-between\">\n <span class=\"text-sm\">\\${message}</span>\n <button onclick=\"this.parentElement.parentElement.remove()\" class=\"ml-4 hover:opacity-70\">\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"></path>\n </svg>\n </button>\n </div>\n \\`;\n\n container.appendChild(notification);\n\n // Auto remove after 5 seconds\n setTimeout(() => {\n if (notification.parentElement) {\n notification.remove();\n }\n }, 5000);\n }\n\n // Initialize dark mode\n if (localStorage.getItem('darkMode') === 'false') {\n document.documentElement.classList.remove('dark');\n }\n\n // Migration banner functions\n function closeMigrationBanner() {\n const banner = document.getElementById('migration-banner');\n if (banner) {\n banner.classList.add('hidden');\n // Store in session storage so it doesn't show again during this session\n sessionStorage.setItem('migrationBannerDismissed', 'true');\n }\n }\n\n // Check for pending migrations on page load\n async function checkPendingMigrations() {\n // Don't check if user dismissed the banner in this session\n if (sessionStorage.getItem('migrationBannerDismissed') === 'true') {\n return;\n }\n\n try {\n const response = await fetch('/admin/api/migrations/status');\n if (response.ok) {\n const data = await response.json();\n if (data.success && data.data && data.data.pendingMigrations > 0) {\n const banner = document.getElementById('migration-banner');\n const countElement = document.getElementById('migration-count');\n if (banner && countElement) {\n countElement.textContent = data.data.pendingMigrations;\n banner.classList.remove('hidden');\n }\n }\n }\n } catch (error) {\n console.error('Failed to check migration status:', error);\n }\n }\n\n // Check for pending migrations when the page loads\n document.addEventListener('DOMContentLoaded', checkPendingMigrations);\n\n // Docs dropdown toggle\n function toggleDocsDropdown() {\n const dropDowns = document.querySelectorAll('.docsDropdown');\n dropDowns.forEach(dropdown => {\n dropdown.classList.toggle('hidden');\n });\n }\n\n // Close docs dropdown when clicking outside\n document.addEventListener('click', function(event) {\n const dropdowns = document.querySelectorAll('.docsDropdown');\n const button = event.target.closest('[data-docs-menu]');\n if (!button) {\n dropdowns.forEach(function(dropdown) {\n if (!dropdown.contains(event.target)) {\n dropdown.classList.add('hidden');\n }\n });\n }\n });\n\n // Plugins accordion toggle\n function togglePluginsMenu(btn) {\n var isNowClosed = document.documentElement.classList.toggle('plugins-closed');\n var chevron = btn.querySelector('[data-plugins-chevron]');\n if (chevron) chevron.classList.toggle('rotate-180');\n document.cookie = 'plugins_menu_open=' + (isNowClosed ? '0' : '1') + ';path=/;max-age=31536000';\n }\n\n // Auto-expand plugins submenu if a sub-item is currently active (overrides closed cookie)\n document.addEventListener('DOMContentLoaded', function() {\n document.querySelectorAll('[data-plugins-submenu]').forEach(function(submenu) {\n if (submenu.querySelector('[data-current=\"true\"]')) {\n document.documentElement.classList.remove('plugins-closed');\n var accordion = submenu.closest('[data-plugins-accordion]');\n if (accordion) {\n var chevron = accordion.querySelector('[data-plugins-chevron]');\n if (chevron) chevron.classList.add('rotate-180');\n }\n }\n });\n });\n </script>\n</body>\n</html>`;\n}\n\nfunction renderCatalystSidebar(\n currentPath: string = \"\",\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- user shape varies across admin pages; permissions read narrowly below\n user?: any,\n dynamicMenuItems?: Array<{ label: string; path: string; icon: string }>,\n isMobile: boolean = false,\n version?: string,\n enableExperimentalFeatures?: boolean\n): string {\n // Fall back to the declarative plugin menu singleton when no explicit\n // Active plugin nav items injected by pluginMenuMiddleware via dynamicMenuItems.\n // When not provided, the marker below is replaced by the middleware post-render.\n const resolvedMenuItems = dynamicMenuItems ?? [];\n const userRole: string = user?.role ?? 'viewer';\n const isAdmin = userRole === 'admin';\n const isEditor = userRole === 'editor';\n const canManageUsers = isAdmin;\n const canAccessSettings = isAdmin || isEditor;\n const canAccessPlugins = isAdmin;\n\n let baseMenuItems = [\n {\n label: \"Content\",\n path: \"/admin/content\",\n icon: `<svg class=\"h-5 w-5\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm2 6a1 1 0 011-1h6a1 1 0 110 2H7a1 1 0 01-1-1zm1 3a1 1 0 100 2h6a1 1 0 100-2H7z\" clip-rule=\"evenodd\"/>\n </svg>`,\n },\n {\n label: \"Collections\",\n path: \"/admin/collections\",\n icon: `<svg class=\"h-5 w-5\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path d=\"M7 3a1 1 0 000 2h6a1 1 0 100-2H7zM4 7a1 1 0 011-1h10a1 1 0 110 2H5a1 1 0 01-1-1zM2 11a2 2 0 012-2h12a2 2 0 012 2v4a2 2 0 01-2 2H4a2 2 0 01-2-2v-4z\"/>\n </svg>`,\n },\n ...(canManageUsers ? [{\n label: \"Users\",\n path: \"/admin/users\",\n icon: `<svg class=\"h-5 w-5\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path d=\"M9 6a3 3 0 11-6 0 3 3 0 016 0zM17 6a3 3 0 11-6 0 3 3 0 016 0zM12.93 17c.046-.327.07-.66.07-1a6.97 6.97 0 00-1.5-4.33A5 5 0 0119 16v1h-6.07zM6 11a5 5 0 015 5v1H1v-1a5 5 0 015-5z\"/>\n </svg>`,\n }] : []),\n ];\n\n const pluginsIcon = `<svg class=\"h-5 w-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10\"/>\n </svg>`;\n\n const settingsMenuItem = {\n label: \"Settings\",\n path: \"/admin/settings\",\n icon: `<svg class=\"h-5 w-5\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z\" clip-rule=\"evenodd\"/>\n </svg>`,\n };\n\n const allMenuItems = [...baseMenuItems];\n\n const isPluginsActive =\n currentPath === \"/admin/plugins\" ||\n (currentPath?.startsWith(\"/admin/plugins\") ?? false);\n\n const pluginsSubItems =\n resolvedMenuItems && resolvedMenuItems.length > 0\n ? resolvedMenuItems\n .map((item) => {\n const isActive =\n currentPath === item.path ||\n (item.path !== \"/admin\" && currentPath?.startsWith(item.path));\n return `\n <span class=\"relative\">\n ${isActive ? '<span class=\"absolute inset-y-2 -left-4 w-0.5 rounded-full bg-cyan-500 dark:bg-cyan-400\"></span>' : \"\"}\n <a\n href=\"${item.path}\"\n class=\"flex w-full items-center gap-3 rounded-lg px-2 py-2 text-left text-sm/5 font-medium ${\n isActive\n ? \"text-zinc-950 dark:text-white\"\n : \"text-zinc-600 hover:bg-zinc-950/5 dark:text-zinc-400 dark:hover:bg-white/5\"\n }\"\n ${isActive ? 'data-current=\"true\"' : \"\"}\n >\n <span class=\"shrink-0 ${isActive ? \"fill-zinc-950 dark:fill-white\" : \"fill-zinc-500 dark:fill-zinc-400\"}\">\n ${item.icon}\n </span>\n <span class=\"truncate\">${item.label}</span>\n </a>\n </span>`;\n })\n .join(\"\")\n : \"<!-- DYNAMIC_PLUGIN_MENU -->\";\n\n const closeButton = isMobile\n ? `\n <div class=\"-mb-3 px-4 pt-3\">\n <button onclick=\"closeMobileSidebar()\" class=\"relative flex w-full items-center gap-3 rounded-lg p-2 text-left text-base/6 font-medium text-zinc-950 hover:bg-zinc-950/5 dark:text-white dark:hover:bg-white/5 sm:text-sm/5\" aria-label=\"Close navigation\">\n <svg class=\"h-5 w-5 shrink-0 fill-zinc-500 dark:fill-zinc-400\" viewBox=\"0 0 20 20\">\n <path d=\"M6.28 5.22a.75.75 0 0 0-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 1 0 1.06 1.06L10 11.06l3.72 3.72a.75.75 0 1 0 1.06-1.06L11.06 10l3.72-3.72a.75.75 0 0 0-1.06-1.06L10 8.94 6.28 5.22Z\" />\n </svg>\n <span>Close menu</span>\n </button>\n </div>\n `\n : \"\";\n\n return `\n <nav class=\"flex h-full min-h-0 flex-col bg-white shadow-sm ring-1 ring-zinc-950/5 dark:bg-zinc-900 dark:ring-white/10 ${\n isMobile ? \"is-mobile rounded-lg p-2 m-2\" : \"\"\n }\">\n ${closeButton}\n\n <!-- Sidebar Header -->\n <div class=\"flex w-full flex-col border-b border-zinc-950/5 p-4 dark:border-white/5\">\n ${renderLogo({ size: \"md\", showText: true, variant: \"white\", version, href: \"/admin/content\" })}\n ${_branchLabel ? (() => { const col = branchColor(_branchLabel!); const short = _branchLabel!.split('/').pop() || _branchLabel!; return `<div class=\"mt-2 flex items-center justify-center\"><span class=\"inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${col.bg} ${col.text} max-w-full truncate\" title=\"${_branchLabel}\">${short}</span></div>`; })() : \"\"}\n </div>\n\n <!-- Tenant switcher (injected by tenantMiddleware when the multi-tenant plugin is active) -->\n <!-- TENANT_SWITCHER -->\n\n <!-- Sidebar Body -->\n <div class=\"flex flex-1 flex-col overflow-y-auto p-4\">\n <div class=\"flex flex-col gap-0.5\">\n <!-- ADMIN_SIDEBAR_NAV_ITEMS -->\n ${allMenuItems\n .map((item) => {\n const isActive =\n currentPath === item.path ||\n (item.path !== \"/admin\" && currentPath?.startsWith(item.path));\n return `\n <span class=\"relative\">\n ${\n isActive\n ? `\n <span class=\"absolute inset-y-2 -left-4 w-0.5 rounded-full bg-cyan-500 dark:bg-cyan-400\"></span>\n `\n : \"\"\n }\n <a\n href=\"${item.path}\"\n class=\"flex w-full items-center gap-3 rounded-lg px-2 py-2.5 text-left text-sm/5 font-medium ${\n isActive\n ? \"text-zinc-950 dark:text-white\"\n : \"text-zinc-950 hover:bg-zinc-950/5 dark:text-white dark:hover:bg-white/5\"\n }\"\n ${isActive ? 'data-current=\"true\"' : \"\"}\n >\n <span class=\"shrink-0 ${\n isActive\n ? \"fill-zinc-950 dark:fill-white\"\n : \"fill-zinc-500 dark:fill-zinc-400\"\n }\">\n ${item.icon}\n </span>\n <span class=\"truncate\">${item.label}</span>\n </a>\n </span>\n `;\n })\n .join(\"\")}\n ${canAccessPlugins ? `<!-- Plugins accordion -->\n <div data-plugins-accordion class=\"relative\">\n ${isPluginsActive ? '<span class=\"absolute inset-y-2 -left-4 w-0.5 rounded-full bg-cyan-500 dark:bg-cyan-400\"></span>' : \"\"}\n <div class=\"flex w-full items-center\">\n <a\n href=\"/admin/plugins\"\n class=\"flex flex-1 items-center gap-3 rounded-lg px-2 py-2.5 text-left text-sm/5 font-medium ${\n isPluginsActive\n ? \"text-zinc-950 dark:text-white\"\n : \"text-zinc-950 hover:bg-zinc-950/5 dark:text-white dark:hover:bg-white/5\"\n }\"\n ${isPluginsActive ? 'data-current=\"true\"' : \"\"}\n >\n <span class=\"shrink-0 ${isPluginsActive ? \"fill-zinc-950 dark:fill-white\" : \"fill-zinc-500 dark:fill-zinc-400\"}\">\n ${pluginsIcon}\n </span>\n <span class=\"truncate\">Plugins</span>\n </a>\n <button\n onclick=\"togglePluginsMenu(this)\"\n class=\"flex items-center justify-center rounded-lg p-2 text-zinc-500 hover:bg-zinc-950/5 dark:text-zinc-400 dark:hover:bg-white/5 flex-shrink-0\"\n aria-label=\"Toggle plugins submenu\"\n >\n <svg data-plugins-chevron class=\"h-4 w-4 rotate-180 transition-transform duration-200\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\"/>\n </svg>\n </button>\n </div>\n <div data-plugins-submenu class=\"pl-6 mt-0.5 flex flex-col gap-0.5\">\n ${pluginsSubItems}\n </div>\n </div>` : \"\"}\n <!-- /ADMIN_SIDEBAR_NAV_ITEMS -->\n </div>\n </div>\n\n <!-- Docs menu -->\n <div class=\"border-t border-zinc-950/5 p-4 dark:border-white/5\">\n <div class=\"relative\">\n <button\n data-docs-menu\n onclick=\"toggleDocsDropdown()\"\n class=\"flex w-full items-center gap-3 rounded-lg px-2 py-2.5 text-left text-sm/5 font-medium text-zinc-950 hover:bg-zinc-950/5 dark:text-white dark:hover:bg-white/5\"\n >\n <svg class=\"h-5 w-5 shrink-0 fill-zinc-500 dark:fill-zinc-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 6.042A8.967 8.967 0 006 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 016 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 016-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0018 18a8.967 8.967 0 00-6 2.292m0-14.25v14.25\"/>\n </svg>\n <span class=\"flex-1 truncate\">Docs</span>\n <svg class=\"h-4 w-4 shrink-0 fill-zinc-500 dark:fill-zinc-400\" viewBox=\"0 0 20 20\">\n <path d=\"M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z\" />\n </svg>\n </button>\n <div class=\"docsDropdown hidden absolute bottom-full mb-2 left-0 right-0 mx-2 rounded-xl bg-white shadow-lg ring-1 ring-zinc-950/10 dark:bg-zinc-800 dark:ring-white/10 z-50\">\n <div class=\"p-2\">\n <a href=\"/admin/api-reference\" class=\"flex items-center gap-2 rounded-lg px-3 py-2 text-sm text-zinc-950 hover:bg-zinc-950/5 dark:text-white dark:hover:bg-white/5\">\n <svg class=\"h-4 w-4 shrink-0 text-zinc-500 dark:text-zinc-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 6.042A8.967 8.967 0 006 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 016 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 016-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0018 18a8.967 8.967 0 00-6 2.292m0-14.25v14.25\"/>\n </svg>\n API Docs\n </a>\n <a href=\"https://sonicjs.com\" target=\"_blank\" class=\"flex items-center gap-2 rounded-lg px-3 py-2 text-sm text-zinc-950 hover:bg-zinc-950/5 dark:text-white dark:hover:bg-white/5\">\n <svg class=\"h-4 w-4 shrink-0 text-zinc-500 dark:text-zinc-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.26 10.147a60.436 60.436 0 00-.491 6.347A48.627 48.627 0 0112 20.904a48.627 48.627 0 018.232-4.41 60.46 60.46 0 00-.491-6.347m-15.482 0a50.57 50.57 0 00-2.658-.813A59.905 59.905 0 0112 3.493a59.902 59.902 0 0110.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.697 50.697 0 0112 13.489a50.702 50.702 0 017.74-3.342M6.75 15a.75.75 0 100-1.5.75.75 0 000 1.5zm0 0v-3.675A55.378 55.378 0 0112 8.443m-7.007 11.55A5.981 5.981 0 006.75 15.75v-1.5\"/>\n </svg>\n Developer Docs\n </a>\n <a href=\"/api\" target=\"_blank\" class=\"flex items-center gap-2 rounded-lg px-3 py-2 text-sm text-zinc-950 hover:bg-zinc-950/5 dark:text-white dark:hover:bg-white/5\">\n <svg class=\"h-4 w-4 shrink-0 text-zinc-500 dark:text-zinc-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M17.25 6.75L22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3l-4.5 16.5\"/>\n </svg>\n OpenAPI\n </a>\n </div>\n </div>\n </div>\n </div>\n\n ${canAccessSettings ? `<!-- Settings Menu Item (Bottom) -->\n <div class=\"border-t border-zinc-950/5 p-4 dark:border-white/5\">\n ${(() => {\n const isActive =\n currentPath === settingsMenuItem.path ||\n currentPath?.startsWith(settingsMenuItem.path);\n return `\n <span class=\"relative\">\n ${\n isActive\n ? `\n <span class=\"absolute inset-y-2 -left-4 w-0.5 rounded-full bg-cyan-500 dark:bg-cyan-400\"></span>\n `\n : \"\"\n }\n <a\n href=\"${settingsMenuItem.path}\"\n class=\"flex w-full items-center gap-3 rounded-lg px-2 py-2.5 text-left text-sm/5 font-medium ${\n isActive\n ? \"text-zinc-950 dark:text-white\"\n : \"text-zinc-950 hover:bg-zinc-950/5 dark:text-white dark:hover:bg-white/5\"\n }\"\n ${isActive ? 'data-current=\"true\"' : \"\"}\n >\n <span class=\"shrink-0 ${\n isActive\n ? \"fill-zinc-950 dark:fill-white\"\n : \"fill-zinc-500 dark:fill-zinc-400\"\n }\">\n ${settingsMenuItem.icon}\n </span>\n <span class=\"truncate\">${settingsMenuItem.label}</span>\n </a>\n </span>\n `;\n })()}\n </div>` : \"\"}\n\n <!-- Sidebar Footer (User) -->\n ${\n user\n ? `\n <div class=\"flex flex-col border-t border-zinc-950/5 p-4 dark:border-white/5\">\n <div class=\"relative\">\n <button\n data-user-menu\n onclick=\"toggleUserDropdown()\"\n class=\"flex w-full items-center gap-3 rounded-lg px-2 py-2.5 text-left text-sm/5 font-medium text-zinc-950 hover:bg-zinc-950/5 dark:text-white dark:hover:bg-white/5\"\n >\n <div class=\"flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-zinc-950 text-white dark:bg-white dark:text-zinc-950\">\n <span class=\"text-xs font-semibold\">${(\n user.name ||\n user.email ||\n \"U\"\n )\n .charAt(0)\n .toUpperCase()}</span>\n </div>\n <span class=\"flex-1 truncate\">${\n user.name || user.email || \"User\"\n }</span>\n <svg class=\"h-4 w-4 shrink-0 fill-zinc-500 dark:fill-zinc-400\" viewBox=\"0 0 20 20\">\n <path d=\"M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z\" />\n </svg>\n </button>\n\n <!-- User Dropdown -->\n <div class=\"userDropdown hidden absolute bottom-full mb-2 left-0 right-0 mx-2 rounded-xl bg-white shadow-lg ring-1 ring-zinc-950/10 dark:bg-zinc-800 dark:ring-white/10 z-50\">\n <div class=\"p-2\">\n <div class=\"px-3 py-2 border-b border-zinc-950/5 dark:border-white/5\">\n <p class=\"text-sm font-medium text-zinc-950 dark:text-white\">${\n user.name || user.email || \"User\"\n }</p>\n <p class=\"text-xs text-zinc-500 dark:text-zinc-400\">${\n user.email || \"\"\n }</p>\n </div>\n <a href=\"/admin/profile\" class=\"flex items-center gap-2 rounded-lg px-3 py-2 text-sm text-zinc-950 hover:bg-zinc-950/5 dark:text-white dark:hover:bg-white/5\">\n <svg class=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z\"/>\n </svg>\n My Profile\n </a>\n <a href=\"/auth/logout\" class=\"flex items-center gap-2 rounded-lg px-3 py-2 text-sm text-red-600 hover:bg-red-50 dark:text-red-400 dark:hover:bg-red-500/10\">\n <svg class=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1\"/>\n </svg>\n Sign Out\n </a>\n </div>\n </div>\n </div>\n </div>\n `\n : \"\"\n }\n </nav>\n `;\n}\n"]}
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
- var chunkUYJQDDEE_cjs = require('./chunk-UYJQDDEE.cjs');
3
+ var chunkMI2YXCK4_cjs = require('./chunk-MI2YXCK4.cjs');
4
4
  var chunkMNWKYY5E_cjs = require('./chunk-MNWKYY5E.cjs');
5
5
 
6
6
  // src/templates/pages/admin-documents-form.template.ts
7
- chunkUYJQDDEE_cjs.init_admin_layout_catalyst_template();
7
+ chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
8
8
 
9
9
  // src/templates/components/alert.template.ts
10
10
  function renderAlert(data) {
@@ -292,7 +292,7 @@ function renderDocumentFormPage(data) {
292
292
  </details>` : ""}
293
293
  </div>
294
294
  `;
295
- return chunkUYJQDDEE_cjs.renderAdminLayoutCatalyst({
295
+ return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst({
296
296
  title: `${isEdit ? "Edit" : "New"} ${docType.displayName} \u2014 Documents`,
297
297
  currentPath: "/admin/content",
298
298
  user: data.user,
@@ -323,5 +323,5 @@ function renderVersionHistoryFragment(data) {
323
323
  exports.renderAlert = renderAlert;
324
324
  exports.renderDocumentFormPage = renderDocumentFormPage;
325
325
  exports.renderVersionHistoryFragment = renderVersionHistoryFragment;
326
- //# sourceMappingURL=chunk-JMJM7DMM.cjs.map
327
- //# sourceMappingURL=chunk-JMJM7DMM.cjs.map
326
+ //# sourceMappingURL=chunk-TT3TQSCZ.cjs.map
327
+ //# sourceMappingURL=chunk-TT3TQSCZ.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/templates/pages/admin-documents-form.template.ts","../src/templates/components/alert.template.ts"],"names":["init_admin_layout_catalyst_template","escapeHtml","renderAdminLayoutCatalyst"],"mappings":"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","file":"chunk-JMJM7DMM.cjs","sourcesContent":["import { renderAdminLayoutCatalyst } from '../layouts/admin-layout-catalyst.template'\nimport { renderAlert } from '../components/alert.template'\nimport { escapeHtml } from '../../utils/sanitize'\nimport type { Document, DocumentType, QueryableField } from '../../schemas/document'\n\nexport interface DocumentFormData {\n docType: DocumentType\n doc?: Document\n publishedDoc?: Document | null // Published revision when different from current draft\n isEdit: boolean\n errors?: Record<string, string>\n message?: string\n messageType?: 'success' | 'error' | 'warning' | 'info'\n user?: { name: string; email: string; role: string }\n version?: string\n versioningEnabled?: boolean // Whether versioning is opt-in for this document type\n}\n\nfunction inputClass(error?: string): string {\n const base = 'block w-full rounded-lg border bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white placeholder:text-zinc-400 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-colors'\n return error\n ? `${base} border-red-400 dark:border-red-500`\n : `${base} border-zinc-300 dark:border-zinc-700`\n}\n\nfunction renderFieldInput(field: QueryableField, value: unknown, error?: string): string {\n const id = `data_${field.name}`\n const name = `data[${field.name}]`\n const label = field.name.replace(/([A-Z])/g, ' $1').replace(/^./, s => s.toUpperCase())\n const strVal = value != null ? String(value) : ''\n\n let input: string\n if (field.type === 'integer' || field.type === 'number') {\n input = `<input type=\"number\" id=\"${id}\" name=\"${name}\" value=\"${escapeHtml(strVal)}\"\n step=\"${field.type === 'integer' ? '1' : 'any'}\"\n class=\"${inputClass(error)}\">`\n } else if (field.type === 'boolean') {\n // Hidden 'false' before the checkbox: an unchecked checkbox submits nothing, so without this a\n // boolean could never be set back to false (D15). When checked, the checkbox value wins.\n input = `<div class=\"flex items-center gap-2\">\n <input type=\"hidden\" name=\"${name}\" value=\"false\">\n <input type=\"checkbox\" id=\"${id}\" name=\"${name}\" value=\"true\" ${strVal === 'true' ? 'checked' : ''}\n class=\"h-4 w-4 rounded border-zinc-300 dark:border-zinc-600 text-blue-600 focus:ring-blue-500\">\n <span class=\"text-sm text-zinc-700 dark:text-zinc-300\">${label}</span>\n </div>`\n return `\n <div>\n ${input}\n ${error ? `<p class=\"mt-1 text-xs text-red-500\">${escapeHtml(error)}</p>` : ''}\n </div>`\n } else if (field.kind === 'facet') {\n // Multi-value: comma-separated list\n const arrVal = Array.isArray(value) ? (value as string[]).join(', ') : strVal\n input = `<input type=\"text\" id=\"${id}\" name=\"${name}\" value=\"${escapeHtml(arrVal)}\"\n placeholder=\"Comma-separated values\"\n class=\"${inputClass(error)}\">`\n } else {\n input = `<input type=\"text\" id=\"${id}\" name=\"${name}\" value=\"${escapeHtml(strVal)}\"\n class=\"${inputClass(error)}\">`\n }\n\n return `\n <div>\n <label for=\"${id}\" class=\"block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1\">\n ${label}\n </label>\n ${input}\n ${error ? `<p class=\"mt-1 text-xs text-red-500\">${escapeHtml(error)}</p>` : ''}\n </div>`\n}\n\nfunction renderRemainingFields(\n allData: Record<string, unknown>,\n queryableFields: QueryableField[],\n errors: Record<string, string>,\n): string {\n const knownNames = new Set(queryableFields.map(f => f.name))\n const remainingKeys = Object.keys(allData).filter(k => !knownNames.has(k))\n if (remainingKeys.length === 0) return ''\n\n const inputs = remainingKeys.map(key => {\n const val = allData[key]\n const id = `data_${key}`\n const name = `data[${key}]`\n const label = key.replace(/([A-Z])/g, ' $1').replace(/^./, s => s.toUpperCase())\n const strVal = typeof val === 'object' ? JSON.stringify(val, null, 2) : String(val ?? '')\n const isMultiline = strVal.includes('\\n') || strVal.length > 100\n\n return `\n <div>\n <label for=\"${id}\" class=\"block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1\">${escapeHtml(label)}</label>\n ${isMultiline\n ? `<textarea id=\"${id}\" name=\"${name}\" rows=\"4\" class=\"${inputClass(errors[key])}\">${escapeHtml(strVal)}</textarea>`\n : `<input type=\"text\" id=\"${id}\" name=\"${name}\" value=\"${escapeHtml(strVal)}\" class=\"${inputClass(errors[key])}\">`\n }\n ${errors[key] ? `<p class=\"mt-1 text-xs text-red-500\">${escapeHtml(errors[key])}</p>` : ''}\n </div>`\n }).join('')\n\n return `\n <div class=\"border-t border-zinc-200 dark:border-zinc-700 pt-6\">\n <h3 class=\"text-sm font-medium text-zinc-500 dark:text-zinc-400 mb-4\">Additional Fields</h3>\n <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">${inputs}</div>\n </div>`\n}\n\nexport function renderDocumentFormPage(data: DocumentFormData): string {\n const { docType, doc, publishedDoc, isEdit, errors = {} } = data\n const queryableFields = docType.queryableFields ?? []\n const docData = (doc?.data ?? {}) as Record<string, unknown>\n\n const isAdmin = data.user?.role === 'admin'\n const isEditor = isAdmin || data.user?.role === 'editor'\n\n const hasNewerDraft = isEdit && doc && !doc.isPublished && publishedDoc\n const isPublishedAndDraft = isEdit && doc?.isPublished && doc?.isCurrentDraft\n\n // Real document CRUD lives under /admin/content/documents/:typeId/... (admin-content.ts), NOT\n // /admin/documents/ui (those are GET redirects only). Edit/save POSTs to :rootId; create to /new.\n const formAction = isEdit\n ? `/admin/content/documents/${escapeHtml(docType.id)}/${escapeHtml(doc!.rootId)}`\n : `/admin/content/documents/${escapeHtml(docType.id)}/new`\n\n const publishBannerHtml = (() => {\n if (!isEdit || !doc) return ''\n if (isPublishedAndDraft) {\n return renderAlert({\n type: 'success',\n message: 'This document is live. Saving creates a new draft. Use \"Publish\" to push changes live.',\n })\n }\n if (hasNewerDraft) {\n return renderAlert({\n type: 'info',\n message: `A published version (v${publishedDoc!.versionNumber}) is still live. This is an unpublished draft (v${doc.versionNumber}).`,\n })\n }\n return ''\n })()\n\n // Reference-kind fields are intentionally not rendered yet (D27) — fine for FAQ/testimonial, which\n // have none. When media references land (Phase 6), render a root-id picker here.\n const queryableInputs = queryableFields\n .filter(f => f.kind !== 'reference')\n .map(f => renderFieldInput(f, docData[f.name], errors[`data.${f.name}`]))\n .join('')\n\n const remainingHtml = renderRemainingFields(docData, queryableFields, errors)\n\n const content = `\n <div class=\"w-full px-4 sm:px-6 lg:px-8 py-6 space-y-6\">\n <!-- Header -->\n <div class=\"flex flex-col sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <div class=\"flex items-center gap-2 text-sm text-zinc-500 dark:text-zinc-400 mb-1\">\n <a href=\"/admin/content\" class=\"hover:text-zinc-950 dark:hover:text-white\">Content</a>\n <svg class=\"h-4 w-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z\" clip-rule=\"evenodd\"/></svg>\n <a href=\"/admin/content?model=doc:${escapeHtml(docType.id)}\" class=\"hover:text-zinc-950 dark:hover:text-white\">${escapeHtml(docType.displayName)}</a>\n <svg class=\"h-4 w-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z\" clip-rule=\"evenodd\"/></svg>\n <span class=\"text-zinc-950 dark:text-white font-medium\">${isEdit ? 'Edit' : 'New'}</span>\n </div>\n <h1 class=\"text-2xl/8 font-semibold text-zinc-950 dark:text-white sm:text-xl/8\">\n ${isEdit ? `Edit ${escapeHtml(docType.displayName)}` : `New ${escapeHtml(docType.displayName)}`}\n </h1>\n ${isEdit && doc ? `<p class=\"mt-1 text-xs text-zinc-500 dark:text-zinc-400\">v${doc.versionNumber} · root: <code class=\"font-mono\">${escapeHtml(doc.rootId)}</code></p>` : ''}\n </div>\n\n <!-- Publish controls (edit mode, versioning types only) -->\n ${isEdit && doc && isEditor && data.versioningEnabled ? `\n <div class=\"mt-4 sm:mt-0 flex gap-2\">\n ${!doc.isPublished ? `\n <form method=\"POST\" action=\"/admin/content/documents/${escapeHtml(docType.id)}/${escapeHtml(doc.id)}/publish\">\n <button type=\"submit\"\n class=\"inline-flex items-center rounded-lg bg-green-600 px-3.5 py-2.5 text-sm font-semibold text-white hover:bg-green-500 transition-colors shadow-sm\">\n Publish\n </button>\n </form>` : `\n <form method=\"POST\" action=\"/admin/content/documents/${escapeHtml(docType.id)}/${escapeHtml(doc.id)}/unpublish\">\n <button type=\"submit\"\n class=\"inline-flex items-center rounded-lg bg-amber-500 px-3.5 py-2.5 text-sm font-semibold text-white hover:bg-amber-400 transition-colors shadow-sm\">\n Unpublish\n </button>\n </form>`}\n </div>` : ''}\n </div>\n\n ${publishBannerHtml}\n ${data.message ? renderAlert({ type: data.messageType ?? 'info', message: data.message, dismissible: true }) : ''}\n\n <!-- Form -->\n <form method=\"POST\" action=\"${formAction}\">\n ${isEdit ? `<input type=\"hidden\" name=\"_method\" value=\"PUT\">` : ''}\n\n <div class=\"relative rounded-xl\">\n <div class=\"absolute inset-0 bg-gradient-to-br from-blue-500/5 to-purple-500/5 dark:from-blue-400/10 dark:to-purple-400/10 rounded-xl\"></div>\n <div class=\"relative bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl shadow-sm ring-1 ring-zinc-950/5 dark:ring-white/10 rounded-xl p-6 space-y-6\">\n\n <!-- Standard fields -->\n <div>\n <h3 class=\"text-sm font-semibold text-zinc-700 dark:text-zinc-200 mb-4\">Document</h3>\n <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label for=\"title\" class=\"block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1\">Title</label>\n <input type=\"text\" id=\"title\" name=\"title\" value=\"${escapeHtml(doc?.title ?? '')}\"\n class=\"${inputClass(errors.title)}\">\n ${errors.title ? `<p class=\"mt-1 text-xs text-red-500\">${escapeHtml(errors.title)}</p>` : ''}\n </div>\n <div>\n <label for=\"slug\" class=\"block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1\">Slug</label>\n <input type=\"text\" id=\"slug\" name=\"slug\" value=\"${escapeHtml(doc?.slug ?? '')}\"\n placeholder=\"auto-generated-if-empty\"\n class=\"${inputClass(errors.slug)}\">\n ${errors.slug ? `<p class=\"mt-1 text-xs text-red-500\">${escapeHtml(errors.slug)}</p>` : ''}\n </div>\n </div>\n </div>\n\n <!-- Queryable data fields -->\n ${queryableFields.length > 0 ? `\n <div class=\"border-t border-zinc-200 dark:border-zinc-700 pt-6\">\n <h3 class=\"text-sm font-semibold text-zinc-700 dark:text-zinc-200 mb-4\">Content</h3>\n <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n ${queryableInputs}\n </div>\n </div>` : ''}\n\n <!-- Remaining data fields not in queryable fields -->\n ${remainingHtml}\n\n <!-- Actions -->\n <div class=\"border-t border-zinc-200 dark:border-zinc-700 pt-6 flex items-center justify-between\">\n <a href=\"/admin/content?model=doc:${escapeHtml(docType.id)}\"\n class=\"inline-flex items-center rounded-lg bg-white dark:bg-zinc-800 px-3.5 py-2.5 text-sm font-semibold text-zinc-700 dark:text-zinc-200 ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors\">\n Cancel\n </a>\n <div class=\"flex gap-3\">\n <button type=\"submit\"\n class=\"inline-flex items-center rounded-lg bg-zinc-950 dark:bg-white px-3.5 py-2.5 text-sm font-semibold text-white dark:text-zinc-950 hover:bg-zinc-800 dark:hover:bg-zinc-100 transition-colors shadow-sm\">\n ${isEdit ? (data.versioningEnabled ? 'Save Draft' : 'Update') : 'Create'}\n </button>\n </div>\n </div>\n </div>\n </div>\n </form>\n\n <!-- Version history (edit mode, versioning opt-in only) -->\n ${isEdit && doc && data.versioningEnabled ? `\n <details class=\"group\">\n <summary class=\"cursor-pointer text-sm text-zinc-500 dark:text-zinc-400 hover:text-zinc-950 dark:hover:text-white flex items-center gap-2 py-2\">\n <svg class=\"h-4 w-4 transition-transform group-open:rotate-90\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fill-rule=\"evenodd\" d=\"M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z\" clip-rule=\"evenodd\"/>\n </svg>\n Version history\n </summary>\n <div class=\"mt-3 rounded-xl bg-white dark:bg-zinc-900 ring-1 ring-zinc-950/5 dark:ring-white/10 overflow-hidden\">\n <div id=\"version-history-placeholder\" class=\"px-6 py-4 text-sm text-zinc-500 dark:text-zinc-400\"\n hx-get=\"/admin/versioning/${escapeHtml(doc.rootId)}\"\n hx-trigger=\"revealed\"\n hx-swap=\"outerHTML\">\n Loading version history…\n </div>\n </div>\n </details>` : ''}\n </div>\n `\n\n return renderAdminLayoutCatalyst({\n title: `${isEdit ? 'Edit' : 'New'} ${docType.displayName} — Documents`,\n currentPath: '/admin/content',\n user: data.user,\n version: data.version,\n content,\n })\n}\n\n// ─── Version history fragment (HTMX target) ──────────────────────────────────\n\nexport interface VersionHistoryData {\n versions: Array<{\n id: string\n versionNumber: number\n isCurrentDraft: boolean\n isPublished: boolean\n status: string\n updatedAt: number\n createdBy: string | null\n }>\n docType: DocumentType\n rootId: string\n}\n\nexport function renderVersionHistoryFragment(data: VersionHistoryData): string {\n if (data.versions.length === 0) {\n return `<div class=\"px-6 py-4 text-sm text-zinc-500 dark:text-zinc-400\">No versions found.</div>`\n }\n\n const rows = data.versions.map(v => `\n <div class=\"flex items-center justify-between px-6 py-3 border-b border-zinc-100 dark:border-zinc-800 last:border-0\">\n <div class=\"flex items-center gap-3\">\n <span class=\"text-sm font-medium text-zinc-950 dark:text-white\">v${v.versionNumber}</span>\n ${v.isPublished ? `<span class=\"inline-flex items-center rounded-md bg-green-50 dark:bg-green-500/10 px-1.5 py-0.5 text-xs font-medium text-green-700 dark:text-green-400\">live</span>` : ''}\n ${v.isCurrentDraft ? `<span class=\"inline-flex items-center rounded-md bg-blue-50 dark:bg-blue-500/10 px-1.5 py-0.5 text-xs font-medium text-blue-700 dark:text-blue-400\">draft</span>` : ''}\n </div>\n <div class=\"flex items-center gap-4 text-xs text-zinc-500 dark:text-zinc-400\">\n <span>${v.createdBy ?? '—'}</span>\n <span>${new Date(v.updatedAt * 1000).toLocaleString('en-US', { dateStyle: 'short', timeStyle: 'short' })}</span>\n </div>\n </div>\n `).join('')\n\n return `<div>${rows}</div>`\n}\n","import { escapeHtml } from '../../utils/sanitize'\n\nexport type AlertType = 'success' | 'error' | 'warning' | 'info'\n\nexport interface AlertData {\n type: AlertType\n title?: string\n message: string\n dismissible?: boolean\n className?: string\n icon?: boolean\n}\n\nexport function renderAlert(data: AlertData): string {\n const typeClasses = {\n success: 'bg-green-50 dark:bg-green-500/10 border border-green-600/20 dark:border-green-500/20',\n error: 'bg-error/10 border border-red-600/20 dark:border-red-500/20',\n warning: 'bg-amber-50 dark:bg-amber-500/10 border border-amber-600/20 dark:border-amber-500/20',\n info: 'bg-blue-50 dark:bg-blue-500/10 border border-blue-600/20 dark:border-blue-500/20'\n }\n\n const iconClasses = {\n success: 'text-green-600 dark:text-green-400',\n error: 'text-red-600 dark:text-red-400',\n warning: 'text-amber-600 dark:text-amber-400',\n info: 'text-blue-600 dark:text-blue-400'\n }\n\n const textClasses = {\n success: 'text-green-900 dark:text-green-300',\n error: 'text-red-900 dark:text-red-300',\n warning: 'text-amber-900 dark:text-amber-300',\n info: 'text-blue-900 dark:text-blue-300'\n }\n\n const messageTextClasses = {\n success: 'text-green-700 dark:text-green-400',\n error: 'text-red-700 dark:text-red-400',\n warning: 'text-amber-700 dark:text-amber-400',\n info: 'text-blue-700 dark:text-blue-400'\n }\n\n const icons = {\n success: `<path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\" clip-rule=\"evenodd\" />`,\n error: `<path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z\" clip-rule=\"evenodd\" />`,\n warning: `<path fill-rule=\"evenodd\" d=\"M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z\" clip-rule=\"evenodd\" />`,\n info: `<path fill-rule=\"evenodd\" d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z\" clip-rule=\"evenodd\" />`\n }\n\n return `\n <div class=\"rounded-lg p-4 ${typeClasses[data.type]} ${data.className || ''}\" ${data.dismissible ? 'id=\"dismissible-alert\"' : ''}>\n <div class=\"flex\">\n ${data.icon !== false ? `\n <div class=\"flex-shrink-0\">\n <svg class=\"h-5 w-5 ${iconClasses[data.type]}\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n ${icons[data.type]}\n </svg>\n </div>\n ` : ''}\n <div class=\"${data.icon !== false ? 'ml-3' : ''}\">\n ${data.title ? `\n <h3 class=\"text-sm font-semibold ${textClasses[data.type]}\">\n ${escapeHtml(data.title)}\n </h3>\n ` : ''}\n <div class=\"${data.title ? 'mt-1 text-sm' : 'text-sm'} ${messageTextClasses[data.type]}\">\n <p>${escapeHtml(data.message)}</p>\n </div>\n </div>\n ${data.dismissible ? `\n <div class=\"ml-auto pl-3\">\n <div class=\"-mx-1.5 -my-1.5\">\n <button\n type=\"button\"\n class=\"inline-flex rounded-md p-1.5 ${iconClasses[data.type]} hover:bg-opacity-20 focus:outline-none focus:ring-2 focus:ring-offset-2\"\n onclick=\"document.getElementById('dismissible-alert').remove()\"\n >\n <span class=\"sr-only\">Dismiss</span>\n <svg class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fill-rule=\"evenodd\" d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\" clip-rule=\"evenodd\" />\n </svg>\n </button>\n </div>\n </div>\n ` : ''}\n </div>\n </div>\n `\n}\n\nexport function renderSuccessAlert(message: string, title?: string): string {\n return renderAlert({ type: 'success', message, title })\n}\n\nexport function renderErrorAlert(message: string, title?: string): string {\n return renderAlert({ type: 'error', message, title })\n}\n\nexport function renderWarningAlert(message: string, title?: string): string {\n return renderAlert({ type: 'warning', message, title })\n}\n\nexport function renderInfoAlert(message: string, title?: string): string {\n return renderAlert({ type: 'info', message, title })\n}\n"]}
1
+ {"version":3,"sources":["../src/templates/pages/admin-documents-form.template.ts","../src/templates/components/alert.template.ts"],"names":["init_admin_layout_catalyst_template","escapeHtml","renderAdminLayoutCatalyst"],"mappings":"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","file":"chunk-TT3TQSCZ.cjs","sourcesContent":["import { renderAdminLayoutCatalyst } from '../layouts/admin-layout-catalyst.template'\nimport { renderAlert } from '../components/alert.template'\nimport { escapeHtml } from '../../utils/sanitize'\nimport type { Document, DocumentType, QueryableField } from '../../schemas/document'\n\nexport interface DocumentFormData {\n docType: DocumentType\n doc?: Document\n publishedDoc?: Document | null // Published revision when different from current draft\n isEdit: boolean\n errors?: Record<string, string>\n message?: string\n messageType?: 'success' | 'error' | 'warning' | 'info'\n user?: { name: string; email: string; role: string }\n version?: string\n versioningEnabled?: boolean // Whether versioning is opt-in for this document type\n}\n\nfunction inputClass(error?: string): string {\n const base = 'block w-full rounded-lg border bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white placeholder:text-zinc-400 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-colors'\n return error\n ? `${base} border-red-400 dark:border-red-500`\n : `${base} border-zinc-300 dark:border-zinc-700`\n}\n\nfunction renderFieldInput(field: QueryableField, value: unknown, error?: string): string {\n const id = `data_${field.name}`\n const name = `data[${field.name}]`\n const label = field.name.replace(/([A-Z])/g, ' $1').replace(/^./, s => s.toUpperCase())\n const strVal = value != null ? String(value) : ''\n\n let input: string\n if (field.type === 'integer' || field.type === 'number') {\n input = `<input type=\"number\" id=\"${id}\" name=\"${name}\" value=\"${escapeHtml(strVal)}\"\n step=\"${field.type === 'integer' ? '1' : 'any'}\"\n class=\"${inputClass(error)}\">`\n } else if (field.type === 'boolean') {\n // Hidden 'false' before the checkbox: an unchecked checkbox submits nothing, so without this a\n // boolean could never be set back to false (D15). When checked, the checkbox value wins.\n input = `<div class=\"flex items-center gap-2\">\n <input type=\"hidden\" name=\"${name}\" value=\"false\">\n <input type=\"checkbox\" id=\"${id}\" name=\"${name}\" value=\"true\" ${strVal === 'true' ? 'checked' : ''}\n class=\"h-4 w-4 rounded border-zinc-300 dark:border-zinc-600 text-blue-600 focus:ring-blue-500\">\n <span class=\"text-sm text-zinc-700 dark:text-zinc-300\">${label}</span>\n </div>`\n return `\n <div>\n ${input}\n ${error ? `<p class=\"mt-1 text-xs text-red-500\">${escapeHtml(error)}</p>` : ''}\n </div>`\n } else if (field.kind === 'facet') {\n // Multi-value: comma-separated list\n const arrVal = Array.isArray(value) ? (value as string[]).join(', ') : strVal\n input = `<input type=\"text\" id=\"${id}\" name=\"${name}\" value=\"${escapeHtml(arrVal)}\"\n placeholder=\"Comma-separated values\"\n class=\"${inputClass(error)}\">`\n } else {\n input = `<input type=\"text\" id=\"${id}\" name=\"${name}\" value=\"${escapeHtml(strVal)}\"\n class=\"${inputClass(error)}\">`\n }\n\n return `\n <div>\n <label for=\"${id}\" class=\"block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1\">\n ${label}\n </label>\n ${input}\n ${error ? `<p class=\"mt-1 text-xs text-red-500\">${escapeHtml(error)}</p>` : ''}\n </div>`\n}\n\nfunction renderRemainingFields(\n allData: Record<string, unknown>,\n queryableFields: QueryableField[],\n errors: Record<string, string>,\n): string {\n const knownNames = new Set(queryableFields.map(f => f.name))\n const remainingKeys = Object.keys(allData).filter(k => !knownNames.has(k))\n if (remainingKeys.length === 0) return ''\n\n const inputs = remainingKeys.map(key => {\n const val = allData[key]\n const id = `data_${key}`\n const name = `data[${key}]`\n const label = key.replace(/([A-Z])/g, ' $1').replace(/^./, s => s.toUpperCase())\n const strVal = typeof val === 'object' ? JSON.stringify(val, null, 2) : String(val ?? '')\n const isMultiline = strVal.includes('\\n') || strVal.length > 100\n\n return `\n <div>\n <label for=\"${id}\" class=\"block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1\">${escapeHtml(label)}</label>\n ${isMultiline\n ? `<textarea id=\"${id}\" name=\"${name}\" rows=\"4\" class=\"${inputClass(errors[key])}\">${escapeHtml(strVal)}</textarea>`\n : `<input type=\"text\" id=\"${id}\" name=\"${name}\" value=\"${escapeHtml(strVal)}\" class=\"${inputClass(errors[key])}\">`\n }\n ${errors[key] ? `<p class=\"mt-1 text-xs text-red-500\">${escapeHtml(errors[key])}</p>` : ''}\n </div>`\n }).join('')\n\n return `\n <div class=\"border-t border-zinc-200 dark:border-zinc-700 pt-6\">\n <h3 class=\"text-sm font-medium text-zinc-500 dark:text-zinc-400 mb-4\">Additional Fields</h3>\n <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">${inputs}</div>\n </div>`\n}\n\nexport function renderDocumentFormPage(data: DocumentFormData): string {\n const { docType, doc, publishedDoc, isEdit, errors = {} } = data\n const queryableFields = docType.queryableFields ?? []\n const docData = (doc?.data ?? {}) as Record<string, unknown>\n\n const isAdmin = data.user?.role === 'admin'\n const isEditor = isAdmin || data.user?.role === 'editor'\n\n const hasNewerDraft = isEdit && doc && !doc.isPublished && publishedDoc\n const isPublishedAndDraft = isEdit && doc?.isPublished && doc?.isCurrentDraft\n\n // Real document CRUD lives under /admin/content/documents/:typeId/... (admin-content.ts), NOT\n // /admin/documents/ui (those are GET redirects only). Edit/save POSTs to :rootId; create to /new.\n const formAction = isEdit\n ? `/admin/content/documents/${escapeHtml(docType.id)}/${escapeHtml(doc!.rootId)}`\n : `/admin/content/documents/${escapeHtml(docType.id)}/new`\n\n const publishBannerHtml = (() => {\n if (!isEdit || !doc) return ''\n if (isPublishedAndDraft) {\n return renderAlert({\n type: 'success',\n message: 'This document is live. Saving creates a new draft. Use \"Publish\" to push changes live.',\n })\n }\n if (hasNewerDraft) {\n return renderAlert({\n type: 'info',\n message: `A published version (v${publishedDoc!.versionNumber}) is still live. This is an unpublished draft (v${doc.versionNumber}).`,\n })\n }\n return ''\n })()\n\n // Reference-kind fields are intentionally not rendered yet (D27) — fine for FAQ/testimonial, which\n // have none. When media references land (Phase 6), render a root-id picker here.\n const queryableInputs = queryableFields\n .filter(f => f.kind !== 'reference')\n .map(f => renderFieldInput(f, docData[f.name], errors[`data.${f.name}`]))\n .join('')\n\n const remainingHtml = renderRemainingFields(docData, queryableFields, errors)\n\n const content = `\n <div class=\"w-full px-4 sm:px-6 lg:px-8 py-6 space-y-6\">\n <!-- Header -->\n <div class=\"flex flex-col sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <div class=\"flex items-center gap-2 text-sm text-zinc-500 dark:text-zinc-400 mb-1\">\n <a href=\"/admin/content\" class=\"hover:text-zinc-950 dark:hover:text-white\">Content</a>\n <svg class=\"h-4 w-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z\" clip-rule=\"evenodd\"/></svg>\n <a href=\"/admin/content?model=doc:${escapeHtml(docType.id)}\" class=\"hover:text-zinc-950 dark:hover:text-white\">${escapeHtml(docType.displayName)}</a>\n <svg class=\"h-4 w-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z\" clip-rule=\"evenodd\"/></svg>\n <span class=\"text-zinc-950 dark:text-white font-medium\">${isEdit ? 'Edit' : 'New'}</span>\n </div>\n <h1 class=\"text-2xl/8 font-semibold text-zinc-950 dark:text-white sm:text-xl/8\">\n ${isEdit ? `Edit ${escapeHtml(docType.displayName)}` : `New ${escapeHtml(docType.displayName)}`}\n </h1>\n ${isEdit && doc ? `<p class=\"mt-1 text-xs text-zinc-500 dark:text-zinc-400\">v${doc.versionNumber} · root: <code class=\"font-mono\">${escapeHtml(doc.rootId)}</code></p>` : ''}\n </div>\n\n <!-- Publish controls (edit mode, versioning types only) -->\n ${isEdit && doc && isEditor && data.versioningEnabled ? `\n <div class=\"mt-4 sm:mt-0 flex gap-2\">\n ${!doc.isPublished ? `\n <form method=\"POST\" action=\"/admin/content/documents/${escapeHtml(docType.id)}/${escapeHtml(doc.id)}/publish\">\n <button type=\"submit\"\n class=\"inline-flex items-center rounded-lg bg-green-600 px-3.5 py-2.5 text-sm font-semibold text-white hover:bg-green-500 transition-colors shadow-sm\">\n Publish\n </button>\n </form>` : `\n <form method=\"POST\" action=\"/admin/content/documents/${escapeHtml(docType.id)}/${escapeHtml(doc.id)}/unpublish\">\n <button type=\"submit\"\n class=\"inline-flex items-center rounded-lg bg-amber-500 px-3.5 py-2.5 text-sm font-semibold text-white hover:bg-amber-400 transition-colors shadow-sm\">\n Unpublish\n </button>\n </form>`}\n </div>` : ''}\n </div>\n\n ${publishBannerHtml}\n ${data.message ? renderAlert({ type: data.messageType ?? 'info', message: data.message, dismissible: true }) : ''}\n\n <!-- Form -->\n <form method=\"POST\" action=\"${formAction}\">\n ${isEdit ? `<input type=\"hidden\" name=\"_method\" value=\"PUT\">` : ''}\n\n <div class=\"relative rounded-xl\">\n <div class=\"absolute inset-0 bg-gradient-to-br from-blue-500/5 to-purple-500/5 dark:from-blue-400/10 dark:to-purple-400/10 rounded-xl\"></div>\n <div class=\"relative bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl shadow-sm ring-1 ring-zinc-950/5 dark:ring-white/10 rounded-xl p-6 space-y-6\">\n\n <!-- Standard fields -->\n <div>\n <h3 class=\"text-sm font-semibold text-zinc-700 dark:text-zinc-200 mb-4\">Document</h3>\n <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label for=\"title\" class=\"block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1\">Title</label>\n <input type=\"text\" id=\"title\" name=\"title\" value=\"${escapeHtml(doc?.title ?? '')}\"\n class=\"${inputClass(errors.title)}\">\n ${errors.title ? `<p class=\"mt-1 text-xs text-red-500\">${escapeHtml(errors.title)}</p>` : ''}\n </div>\n <div>\n <label for=\"slug\" class=\"block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1\">Slug</label>\n <input type=\"text\" id=\"slug\" name=\"slug\" value=\"${escapeHtml(doc?.slug ?? '')}\"\n placeholder=\"auto-generated-if-empty\"\n class=\"${inputClass(errors.slug)}\">\n ${errors.slug ? `<p class=\"mt-1 text-xs text-red-500\">${escapeHtml(errors.slug)}</p>` : ''}\n </div>\n </div>\n </div>\n\n <!-- Queryable data fields -->\n ${queryableFields.length > 0 ? `\n <div class=\"border-t border-zinc-200 dark:border-zinc-700 pt-6\">\n <h3 class=\"text-sm font-semibold text-zinc-700 dark:text-zinc-200 mb-4\">Content</h3>\n <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n ${queryableInputs}\n </div>\n </div>` : ''}\n\n <!-- Remaining data fields not in queryable fields -->\n ${remainingHtml}\n\n <!-- Actions -->\n <div class=\"border-t border-zinc-200 dark:border-zinc-700 pt-6 flex items-center justify-between\">\n <a href=\"/admin/content?model=doc:${escapeHtml(docType.id)}\"\n class=\"inline-flex items-center rounded-lg bg-white dark:bg-zinc-800 px-3.5 py-2.5 text-sm font-semibold text-zinc-700 dark:text-zinc-200 ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors\">\n Cancel\n </a>\n <div class=\"flex gap-3\">\n <button type=\"submit\"\n class=\"inline-flex items-center rounded-lg bg-zinc-950 dark:bg-white px-3.5 py-2.5 text-sm font-semibold text-white dark:text-zinc-950 hover:bg-zinc-800 dark:hover:bg-zinc-100 transition-colors shadow-sm\">\n ${isEdit ? (data.versioningEnabled ? 'Save Draft' : 'Update') : 'Create'}\n </button>\n </div>\n </div>\n </div>\n </div>\n </form>\n\n <!-- Version history (edit mode, versioning opt-in only) -->\n ${isEdit && doc && data.versioningEnabled ? `\n <details class=\"group\">\n <summary class=\"cursor-pointer text-sm text-zinc-500 dark:text-zinc-400 hover:text-zinc-950 dark:hover:text-white flex items-center gap-2 py-2\">\n <svg class=\"h-4 w-4 transition-transform group-open:rotate-90\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fill-rule=\"evenodd\" d=\"M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z\" clip-rule=\"evenodd\"/>\n </svg>\n Version history\n </summary>\n <div class=\"mt-3 rounded-xl bg-white dark:bg-zinc-900 ring-1 ring-zinc-950/5 dark:ring-white/10 overflow-hidden\">\n <div id=\"version-history-placeholder\" class=\"px-6 py-4 text-sm text-zinc-500 dark:text-zinc-400\"\n hx-get=\"/admin/versioning/${escapeHtml(doc.rootId)}\"\n hx-trigger=\"revealed\"\n hx-swap=\"outerHTML\">\n Loading version history…\n </div>\n </div>\n </details>` : ''}\n </div>\n `\n\n return renderAdminLayoutCatalyst({\n title: `${isEdit ? 'Edit' : 'New'} ${docType.displayName} — Documents`,\n currentPath: '/admin/content',\n user: data.user,\n version: data.version,\n content,\n })\n}\n\n// ─── Version history fragment (HTMX target) ──────────────────────────────────\n\nexport interface VersionHistoryData {\n versions: Array<{\n id: string\n versionNumber: number\n isCurrentDraft: boolean\n isPublished: boolean\n status: string\n updatedAt: number\n createdBy: string | null\n }>\n docType: DocumentType\n rootId: string\n}\n\nexport function renderVersionHistoryFragment(data: VersionHistoryData): string {\n if (data.versions.length === 0) {\n return `<div class=\"px-6 py-4 text-sm text-zinc-500 dark:text-zinc-400\">No versions found.</div>`\n }\n\n const rows = data.versions.map(v => `\n <div class=\"flex items-center justify-between px-6 py-3 border-b border-zinc-100 dark:border-zinc-800 last:border-0\">\n <div class=\"flex items-center gap-3\">\n <span class=\"text-sm font-medium text-zinc-950 dark:text-white\">v${v.versionNumber}</span>\n ${v.isPublished ? `<span class=\"inline-flex items-center rounded-md bg-green-50 dark:bg-green-500/10 px-1.5 py-0.5 text-xs font-medium text-green-700 dark:text-green-400\">live</span>` : ''}\n ${v.isCurrentDraft ? `<span class=\"inline-flex items-center rounded-md bg-blue-50 dark:bg-blue-500/10 px-1.5 py-0.5 text-xs font-medium text-blue-700 dark:text-blue-400\">draft</span>` : ''}\n </div>\n <div class=\"flex items-center gap-4 text-xs text-zinc-500 dark:text-zinc-400\">\n <span>${v.createdBy ?? '—'}</span>\n <span>${new Date(v.updatedAt * 1000).toLocaleString('en-US', { dateStyle: 'short', timeStyle: 'short' })}</span>\n </div>\n </div>\n `).join('')\n\n return `<div>${rows}</div>`\n}\n","import { escapeHtml } from '../../utils/sanitize'\n\nexport type AlertType = 'success' | 'error' | 'warning' | 'info'\n\nexport interface AlertData {\n type: AlertType\n title?: string\n message: string\n dismissible?: boolean\n className?: string\n icon?: boolean\n}\n\nexport function renderAlert(data: AlertData): string {\n const typeClasses = {\n success: 'bg-green-50 dark:bg-green-500/10 border border-green-600/20 dark:border-green-500/20',\n error: 'bg-error/10 border border-red-600/20 dark:border-red-500/20',\n warning: 'bg-amber-50 dark:bg-amber-500/10 border border-amber-600/20 dark:border-amber-500/20',\n info: 'bg-blue-50 dark:bg-blue-500/10 border border-blue-600/20 dark:border-blue-500/20'\n }\n\n const iconClasses = {\n success: 'text-green-600 dark:text-green-400',\n error: 'text-red-600 dark:text-red-400',\n warning: 'text-amber-600 dark:text-amber-400',\n info: 'text-blue-600 dark:text-blue-400'\n }\n\n const textClasses = {\n success: 'text-green-900 dark:text-green-300',\n error: 'text-red-900 dark:text-red-300',\n warning: 'text-amber-900 dark:text-amber-300',\n info: 'text-blue-900 dark:text-blue-300'\n }\n\n const messageTextClasses = {\n success: 'text-green-700 dark:text-green-400',\n error: 'text-red-700 dark:text-red-400',\n warning: 'text-amber-700 dark:text-amber-400',\n info: 'text-blue-700 dark:text-blue-400'\n }\n\n const icons = {\n success: `<path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\" clip-rule=\"evenodd\" />`,\n error: `<path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z\" clip-rule=\"evenodd\" />`,\n warning: `<path fill-rule=\"evenodd\" d=\"M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z\" clip-rule=\"evenodd\" />`,\n info: `<path fill-rule=\"evenodd\" d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z\" clip-rule=\"evenodd\" />`\n }\n\n return `\n <div class=\"rounded-lg p-4 ${typeClasses[data.type]} ${data.className || ''}\" ${data.dismissible ? 'id=\"dismissible-alert\"' : ''}>\n <div class=\"flex\">\n ${data.icon !== false ? `\n <div class=\"flex-shrink-0\">\n <svg class=\"h-5 w-5 ${iconClasses[data.type]}\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n ${icons[data.type]}\n </svg>\n </div>\n ` : ''}\n <div class=\"${data.icon !== false ? 'ml-3' : ''}\">\n ${data.title ? `\n <h3 class=\"text-sm font-semibold ${textClasses[data.type]}\">\n ${escapeHtml(data.title)}\n </h3>\n ` : ''}\n <div class=\"${data.title ? 'mt-1 text-sm' : 'text-sm'} ${messageTextClasses[data.type]}\">\n <p>${escapeHtml(data.message)}</p>\n </div>\n </div>\n ${data.dismissible ? `\n <div class=\"ml-auto pl-3\">\n <div class=\"-mx-1.5 -my-1.5\">\n <button\n type=\"button\"\n class=\"inline-flex rounded-md p-1.5 ${iconClasses[data.type]} hover:bg-opacity-20 focus:outline-none focus:ring-2 focus:ring-offset-2\"\n onclick=\"document.getElementById('dismissible-alert').remove()\"\n >\n <span class=\"sr-only\">Dismiss</span>\n <svg class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fill-rule=\"evenodd\" d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\" clip-rule=\"evenodd\" />\n </svg>\n </button>\n </div>\n </div>\n ` : ''}\n </div>\n </div>\n `\n}\n\nexport function renderSuccessAlert(message: string, title?: string): string {\n return renderAlert({ type: 'success', message, title })\n}\n\nexport function renderErrorAlert(message: string, title?: string): string {\n return renderAlert({ type: 'error', message, title })\n}\n\nexport function renderWarningAlert(message: string, title?: string): string {\n return renderAlert({ type: 'warning', message, title })\n}\n\nexport function renderInfoAlert(message: string, title?: string): string {\n return renderAlert({ type: 'info', message, title })\n}\n"]}