@flamingo-stack/openframe-frontend-core 0.0.575 → 0.0.577-1943.5293.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/dist/{chunk-BGE7CKXC.js → chunk-2YCUEUIZ.js} +8 -8
  2. package/dist/{chunk-42PQFBUS.js → chunk-4D2BR756.js} +3 -3
  3. package/dist/{chunk-BTZF3JRS.js → chunk-4KR7JWKB.js} +4 -4
  4. package/dist/{chunk-7G23ANVM.cjs → chunk-5DPCIIJ7.cjs} +95 -95
  5. package/dist/{chunk-7G23ANVM.cjs.map → chunk-5DPCIIJ7.cjs.map} +1 -1
  6. package/dist/{chunk-K3XONUML.cjs → chunk-6FJABKPX.cjs} +11 -11
  7. package/dist/{chunk-K3XONUML.cjs.map → chunk-6FJABKPX.cjs.map} +1 -1
  8. package/dist/{chunk-K574Y2QR.cjs → chunk-6GJBSIRU.cjs} +3 -3
  9. package/dist/{chunk-K574Y2QR.cjs.map → chunk-6GJBSIRU.cjs.map} +1 -1
  10. package/dist/{chunk-7Z64COGD.cjs → chunk-72OIVRPG.cjs} +7 -7
  11. package/dist/{chunk-7Z64COGD.cjs.map → chunk-72OIVRPG.cjs.map} +1 -1
  12. package/dist/{chunk-XC7WPYPJ.cjs → chunk-75X6BRID.cjs} +171 -171
  13. package/dist/{chunk-XC7WPYPJ.cjs.map → chunk-75X6BRID.cjs.map} +1 -1
  14. package/dist/{chunk-QF5B6V4L.cjs → chunk-APFGR2KK.cjs} +41 -41
  15. package/dist/{chunk-QF5B6V4L.cjs.map → chunk-APFGR2KK.cjs.map} +1 -1
  16. package/dist/{chunk-2EPUD2VR.js → chunk-AQ5MZVYN.js} +3 -3
  17. package/dist/{chunk-T5DAFFK7.js → chunk-BBZ6NQL2.js} +2 -2
  18. package/dist/{chunk-IRJQH7RJ.cjs → chunk-CFTZAZ7R.cjs} +28 -28
  19. package/dist/{chunk-IRJQH7RJ.cjs.map → chunk-CFTZAZ7R.cjs.map} +1 -1
  20. package/dist/{chunk-UILNZL6J.cjs → chunk-CIUYHBAY.cjs} +5 -5
  21. package/dist/{chunk-UILNZL6J.cjs.map → chunk-CIUYHBAY.cjs.map} +1 -1
  22. package/dist/{chunk-QTVW5XBL.cjs → chunk-ET3Q4FIZ.cjs} +12 -12
  23. package/dist/{chunk-QTVW5XBL.cjs.map → chunk-ET3Q4FIZ.cjs.map} +1 -1
  24. package/dist/{chunk-IWISKP3F.js → chunk-FCVAVOXS.js} +3 -3
  25. package/dist/{chunk-PUL6X6HY.cjs → chunk-GDWBJFMG.cjs} +32 -32
  26. package/dist/{chunk-PUL6X6HY.cjs.map → chunk-GDWBJFMG.cjs.map} +1 -1
  27. package/dist/{chunk-ZQE7HN4Q.cjs → chunk-GPWU3PPR.cjs} +37 -37
  28. package/dist/{chunk-ZQE7HN4Q.cjs.map → chunk-GPWU3PPR.cjs.map} +1 -1
  29. package/dist/{chunk-BGZCZ2JS.cjs → chunk-HSOMYCUG.cjs} +11 -11
  30. package/dist/{chunk-BGZCZ2JS.cjs.map → chunk-HSOMYCUG.cjs.map} +1 -1
  31. package/dist/{chunk-DTSRMQIY.js → chunk-IQFXDS5O.js} +9 -9
  32. package/dist/{chunk-6D4RVZZJ.js → chunk-JCH6HGQD.js} +3 -3
  33. package/dist/{chunk-SIRFPFBQ.js → chunk-JQI726T3.js} +2 -2
  34. package/dist/{chunk-QDOBY3TP.cjs → chunk-KE2TCUOH.cjs} +327 -324
  35. package/dist/chunk-KE2TCUOH.cjs.map +1 -0
  36. package/dist/{chunk-7GLY26JF.js → chunk-LHR6AA65.js} +33 -6
  37. package/dist/chunk-LHR6AA65.js.map +1 -0
  38. package/dist/{chunk-OE7NV7H3.js → chunk-LYOGSVFO.js} +4 -4
  39. package/dist/{chunk-SPAAKHQA.cjs → chunk-MIY5FYX3.cjs} +8 -8
  40. package/dist/{chunk-SPAAKHQA.cjs.map → chunk-MIY5FYX3.cjs.map} +1 -1
  41. package/dist/{chunk-UPEIX7VG.js → chunk-NEKT67O5.js} +6 -6
  42. package/dist/{chunk-PBS4F534.js → chunk-NP3XN6ZX.js} +8 -5
  43. package/dist/chunk-NP3XN6ZX.js.map +1 -0
  44. package/dist/{chunk-3IUQLB47.cjs → chunk-NQCGDZJ3.cjs} +3 -3
  45. package/dist/{chunk-3IUQLB47.cjs.map → chunk-NQCGDZJ3.cjs.map} +1 -1
  46. package/dist/{chunk-BKXL7OYT.cjs → chunk-RCLJSENK.cjs} +6 -6
  47. package/dist/{chunk-BKXL7OYT.cjs.map → chunk-RCLJSENK.cjs.map} +1 -1
  48. package/dist/{chunk-WVKRSC65.js → chunk-RNUH5IHZ.js} +3 -3
  49. package/dist/{chunk-2IK6SB6F.js → chunk-RSMUAAPW.js} +4 -4
  50. package/dist/{chunk-KSKCQ3ZN.js → chunk-RUJKOU5F.js} +2 -2
  51. package/dist/{chunk-VIAZWBZ2.cjs → chunk-S4CLML75.cjs} +7 -7
  52. package/dist/{chunk-VIAZWBZ2.cjs.map → chunk-S4CLML75.cjs.map} +1 -1
  53. package/dist/{chunk-WAWMZSCP.js → chunk-THDGDYJ3.js} +6 -6
  54. package/dist/{chunk-KG7D35RU.js → chunk-TU32TSAK.js} +5 -5
  55. package/dist/{chunk-5QDGP3RI.js → chunk-U3SDSA5K.js} +5 -5
  56. package/dist/{chunk-SVUZUFT4.cjs → chunk-WOHHZZJK.cjs} +65 -65
  57. package/dist/{chunk-SVUZUFT4.cjs.map → chunk-WOHHZZJK.cjs.map} +1 -1
  58. package/dist/{chunk-3U2P63NQ.cjs → chunk-XBBCUC32.cjs} +15 -15
  59. package/dist/{chunk-3U2P63NQ.cjs.map → chunk-XBBCUC32.cjs.map} +1 -1
  60. package/dist/{chunk-GFSJXRX7.cjs → chunk-XBSW7IF6.cjs} +23 -23
  61. package/dist/{chunk-GFSJXRX7.cjs.map → chunk-XBSW7IF6.cjs.map} +1 -1
  62. package/dist/{chunk-RXJZXMDZ.cjs → chunk-XG2WNF4L.cjs} +26 -26
  63. package/dist/{chunk-RXJZXMDZ.cjs.map → chunk-XG2WNF4L.cjs.map} +1 -1
  64. package/dist/{chunk-S6LZN66D.cjs → chunk-YHNIPSG6.cjs} +33 -6
  65. package/dist/chunk-YHNIPSG6.cjs.map +1 -0
  66. package/dist/{chunk-5DRCLGOX.js → chunk-YLNZPFDW.js} +2 -2
  67. package/dist/{chunk-QQ5ZVCD4.js → chunk-Z2FZ5HP2.js} +3 -3
  68. package/dist/{chunk-ISULYCGY.js → chunk-ZBJ6XSDO.js} +4 -4
  69. package/dist/components/calendar.cjs +4 -4
  70. package/dist/components/calendar.js +1 -1
  71. package/dist/components/case-studies/index.cjs +12 -12
  72. package/dist/components/case-studies/index.js +6 -6
  73. package/dist/components/chart.d.ts +18 -3
  74. package/dist/components/chart.d.ts.map +1 -1
  75. package/dist/components/chat/index.cjs +4 -4
  76. package/dist/components/chat/index.js +3 -3
  77. package/dist/components/contact/index.cjs +7 -7
  78. package/dist/components/contact/index.js +6 -6
  79. package/dist/components/docs/index.cjs +10 -10
  80. package/dist/components/docs/index.js +9 -9
  81. package/dist/components/embeds/index.cjs +7 -7
  82. package/dist/components/embeds/index.js +6 -6
  83. package/dist/components/faq/index.cjs +7 -7
  84. package/dist/components/faq/index.js +6 -6
  85. package/dist/components/features/index.cjs +6 -6
  86. package/dist/components/features/index.js +5 -5
  87. package/dist/components/help-center-pages/index.cjs +28 -28
  88. package/dist/components/help-center-pages/index.js +19 -19
  89. package/dist/components/index.cjs +153 -153
  90. package/dist/components/index.js +19 -19
  91. package/dist/components/meeting-scheduler/index.cjs +52 -48
  92. package/dist/components/meeting-scheduler/index.cjs.map +1 -1
  93. package/dist/components/meeting-scheduler/index.d.ts.map +1 -1
  94. package/dist/components/meeting-scheduler/index.js +17 -13
  95. package/dist/components/meeting-scheduler/index.js.map +1 -1
  96. package/dist/components/navigation/index.cjs +9 -9
  97. package/dist/components/navigation/index.js +8 -8
  98. package/dist/components/onboarding-guides/index.cjs +9 -9
  99. package/dist/components/onboarding-guides/index.js +8 -8
  100. package/dist/components/related-content/index.cjs +5 -5
  101. package/dist/components/related-content/index.js +4 -4
  102. package/dist/components/tickets/index.cjs +11 -11
  103. package/dist/components/tickets/index.js +10 -10
  104. package/dist/components/ui/button/button-styles.d.ts +4 -0
  105. package/dist/components/ui/button/button-styles.d.ts.map +1 -1
  106. package/dist/components/ui/button/button.d.ts.map +1 -1
  107. package/dist/components/ui/dropdown-button.d.ts +9 -1
  108. package/dist/components/ui/dropdown-button.d.ts.map +1 -1
  109. package/dist/components/ui/file-manager/index.cjs +11 -11
  110. package/dist/components/ui/file-manager/index.js +1 -1
  111. package/dist/components/ui/index.cjs +6 -6
  112. package/dist/components/ui/index.js +5 -5
  113. package/dist/index.cjs +10 -10
  114. package/dist/index.js +9 -9
  115. package/package.json +1 -1
  116. package/src/components/chart.tsx +21 -3
  117. package/src/components/meeting-scheduler/index.tsx +16 -14
  118. package/src/components/ui/button/button-styles.ts +14 -0
  119. package/src/components/ui/button/button.tsx +24 -5
  120. package/src/components/ui/dropdown-button.tsx +11 -0
  121. package/dist/chunk-7GLY26JF.js.map +0 -1
  122. package/dist/chunk-PBS4F534.js.map +0 -1
  123. package/dist/chunk-QDOBY3TP.cjs.map +0 -1
  124. package/dist/chunk-S6LZN66D.cjs.map +0 -1
  125. /package/dist/{chunk-BGE7CKXC.js.map → chunk-2YCUEUIZ.js.map} +0 -0
  126. /package/dist/{chunk-42PQFBUS.js.map → chunk-4D2BR756.js.map} +0 -0
  127. /package/dist/{chunk-BTZF3JRS.js.map → chunk-4KR7JWKB.js.map} +0 -0
  128. /package/dist/{chunk-2EPUD2VR.js.map → chunk-AQ5MZVYN.js.map} +0 -0
  129. /package/dist/{chunk-T5DAFFK7.js.map → chunk-BBZ6NQL2.js.map} +0 -0
  130. /package/dist/{chunk-IWISKP3F.js.map → chunk-FCVAVOXS.js.map} +0 -0
  131. /package/dist/{chunk-DTSRMQIY.js.map → chunk-IQFXDS5O.js.map} +0 -0
  132. /package/dist/{chunk-6D4RVZZJ.js.map → chunk-JCH6HGQD.js.map} +0 -0
  133. /package/dist/{chunk-SIRFPFBQ.js.map → chunk-JQI726T3.js.map} +0 -0
  134. /package/dist/{chunk-OE7NV7H3.js.map → chunk-LYOGSVFO.js.map} +0 -0
  135. /package/dist/{chunk-UPEIX7VG.js.map → chunk-NEKT67O5.js.map} +0 -0
  136. /package/dist/{chunk-WVKRSC65.js.map → chunk-RNUH5IHZ.js.map} +0 -0
  137. /package/dist/{chunk-2IK6SB6F.js.map → chunk-RSMUAAPW.js.map} +0 -0
  138. /package/dist/{chunk-KSKCQ3ZN.js.map → chunk-RUJKOU5F.js.map} +0 -0
  139. /package/dist/{chunk-WAWMZSCP.js.map → chunk-THDGDYJ3.js.map} +0 -0
  140. /package/dist/{chunk-KG7D35RU.js.map → chunk-TU32TSAK.js.map} +0 -0
  141. /package/dist/{chunk-5QDGP3RI.js.map → chunk-U3SDSA5K.js.map} +0 -0
  142. /package/dist/{chunk-5DRCLGOX.js.map → chunk-YLNZPFDW.js.map} +0 -0
  143. /package/dist/{chunk-QQ5ZVCD4.js.map → chunk-Z2FZ5HP2.js.map} +0 -0
  144. /package/dist/{chunk-ISULYCGY.js.map → chunk-ZBJ6XSDO.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
2
2
 
3
3
 
4
- var _chunkQDOBY3TPcjs = require('./chunk-QDOBY3TP.cjs');
4
+ var _chunkKE2TCUOHcjs = require('./chunk-KE2TCUOH.cjs');
5
5
 
6
6
 
7
7
  var _chunk36NFJULVcjs = require('./chunk-36NFJULV.cjs');
@@ -129,7 +129,7 @@ function useSectionNavigation(sections, options) {
129
129
  // src/components/navigation/multi-level-navigation.tsx
130
130
  var _lucidereact = require('lucide-react');
131
131
 
132
- var DEFAULT_FOLDER_INDEX_FILE2 = _chunkQDOBY3TPcjs.DEFAULT_FOLDER_INDEX_FILE;
132
+ var DEFAULT_FOLDER_INDEX_FILE2 = _chunkKE2TCUOHcjs.DEFAULT_FOLDER_INDEX_FILE;
133
133
  function isNodeVisuallySelected(node, selectedPath, folderIndexFile = DEFAULT_FOLDER_INDEX_FILE2) {
134
134
  const FOLDER_INDEX_FILE = folderIndexFile.toLowerCase();
135
135
  if (selectedPath === node.path) {
@@ -357,4 +357,4 @@ function MobileNavigationItem({
357
357
 
358
358
 
359
359
  exports.StickySectionNav = StickySectionNav; exports.useSectionNavigation = useSectionNavigation; exports.MultiLevelNavigation = MultiLevelNavigation; exports.MobileNavigationDropdown = MobileNavigationDropdown;
360
- //# sourceMappingURL=chunk-3IUQLB47.cjs.map
360
+ //# sourceMappingURL=chunk-NQCGDZJ3.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-3IUQLB47.cjs","../src/components/navigation/sticky-section-nav.tsx","../src/components/navigation/multi-level-navigation.tsx"],"names":["jsx","DEFAULT_FOLDER_INDEX_FILE"],"mappings":"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","file":"/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-3IUQLB47.cjs","sourcesContent":[null,"'use client';\n\nimport type React from 'react';\nimport { useEffect, useState, useCallback, useRef } from 'react';\nimport { cn } from '../../utils';\nimport { scrollElementIntoView } from '../../utils/scroll-into-view';\n\nexport interface StickyNavSection {\n id: string;\n label: string;\n}\n\ninterface StickySectionNavProps {\n sections: StickyNavSection[];\n activeSection: string;\n onSectionClick: (sectionId: string) => void;\n className?: string;\n ribbonPosition?: 'left' | 'right';\n ribbonColor?: string;\n}\n\n/**\n * Reusable sticky navigation component for section-based navigation\n * Used in vendor detail pages, knowledge base, documentation, etc.\n */\nexport function StickySectionNav({\n sections,\n activeSection,\n onSectionClick,\n className,\n ribbonPosition = 'left',\n ribbonColor = 'var(--color-accent-primary)',\n}: StickySectionNavProps) {\n const navHeight = sections.length * 40; // 40px per item (h-10)\n\n return (\n <nav className={cn('relative bg-ods-bg', className)}>\n {/* Background gray vertical line for all nav items */}\n <div\n className=\"absolute bg-ods-border\"\n style={{\n width: '1px',\n height: `${navHeight}px`,\n [ribbonPosition === 'left' ? 'left' : 'right']: '-2px',\n top: '0px',\n }}\n />\n\n {sections.map(section => (\n <div key={section.id} className=\"relative flex h-10 w-full items-stretch transition-all duration-200\">\n {/* Yellow ribbon for active state */}\n {activeSection === section.id && (\n <div\n className=\"absolute z-10 transition-all duration-200\"\n style={{\n backgroundColor: ribbonColor,\n width: '4px',\n height: '24px',\n [ribbonPosition === 'left' ? 'left' : 'right']: '-2px',\n top: '8px',\n borderRadius: '2px',\n }}\n />\n )}\n\n {/* Navigation button */}\n <button\n onClick={() => onSectionClick(section.id)}\n className=\"relative flex flex-1 cursor-pointer items-center gap-2 px-3 py-2\"\n >\n <span\n className={cn(\n 'text-left transition-all duration-200 text-h6',\n activeSection === section.id\n ? 'text-ods-text-primary'\n : 'text-ods-text-secondary hover:text-ods-text-primary',\n )}\n >\n {section.label}\n </span>\n </button>\n </div>\n ))}\n </nav>\n );\n}\n\n/**\n * SIMPLEST POSSIBLE IMPLEMENTATION - Just make it work\n */\nexport function useSectionNavigation(\n sections: { id: string; ref: React.RefObject<HTMLElement> }[],\n options?: {\n offset?: number;\n },\n) {\n const [activeSection, setActiveSection] = useState(sections[0]?.id || '');\n const isScrollingFromClick = useRef(false);\n const { offset = 100 } = options || {};\n\n // Handle click - scroll to the element via the canonical helper.\n // The `offset` prop maps to `headerOffset` (sticky chrome above the\n // section nav); same smooth-scroll mechanics every other anchor\n // surface in the app uses.\n const handleSectionClick = useCallback(\n (sectionId: string) => {\n const targetElement = document.getElementById(sectionId);\n if (!targetElement) return;\n\n // Prevent scroll spy while we're scrolling\n isScrollingFromClick.current = true;\n setActiveSection(sectionId);\n\n scrollElementIntoView(targetElement, { headerOffset: offset });\n\n // Allow scroll spy again after scroll completes\n setTimeout(() => {\n isScrollingFromClick.current = false;\n }, 500);\n },\n [offset],\n );\n\n // Make sure elements have IDs\n useEffect(() => {\n sections.forEach(section => {\n const el = section.ref.current;\n if (el && !el.id) {\n el.id = section.id;\n }\n });\n }, [sections]);\n\n // Simple scroll spy\n useEffect(() => {\n const handleScroll = () => {\n if (isScrollingFromClick.current) return;\n\n const scrollPosition = window.scrollY + offset + 50;\n\n // Find which section we're in\n let currentSection = sections[0]?.id || '';\n\n for (let i = sections.length - 1; i >= 0; i--) {\n const element = document.getElementById(sections[i].id);\n if (element && scrollPosition >= element.offsetTop) {\n currentSection = sections[i].id;\n break;\n }\n }\n\n setActiveSection(currentSection);\n };\n\n // Throttle the scroll handler\n let scrollTimer: NodeJS.Timeout;\n const throttledScroll = () => {\n clearTimeout(scrollTimer);\n scrollTimer = setTimeout(handleScroll, 100);\n };\n\n window.addEventListener('scroll', throttledScroll);\n handleScroll(); // Check initial position\n\n return () => {\n window.removeEventListener('scroll', throttledScroll);\n clearTimeout(scrollTimer);\n };\n }, [sections, offset]);\n\n return {\n activeSection,\n handleSectionClick,\n };\n}\n","'use client';\n\nimport { ChevronDown, ChevronUp, FileText, Folder, FolderOpen } from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport { DEFAULT_FOLDER_INDEX_FILE as CANONICAL_FOLDER_INDEX_FILE } from '../../utils/doc-tree-nav';\n\nexport interface NavigationNode {\n id: string;\n name: string;\n path: string;\n type: 'file' | 'folder';\n hasReadme?: boolean;\n children?: NavigationNode[];\n slug?: string;\n // Mirror DocNode's extra optional fields so a DocNode tree is structurally\n // assignable to NavigationNode[] without an `as` cast. NavigationNode\n // intentionally never reads these — they're carried for type-compat only.\n documentType?: 'markdown' | 'pdf' | 'google_sheet' | 'figma' | 'file';\n sortOrder?: number;\n}\n\ninterface MultiLevelNavigationProps {\n nodes: NavigationNode[];\n selectedPath: string;\n expandedNodes: Set<string>;\n onNodeClick: (node: NavigationNode) => void;\n onToggleExpand?: (nodeId: string) => void;\n isLoading?: boolean;\n className?: string;\n /** Folder-index filename (default `'README.md'`, case-insensitive). When the\n * selectedPath is a folder with this file, the visual ribbon moves to the\n * child file. */\n folderIndexFile?: string;\n}\n\n// SSOT lives in `doc-tree-nav` (canonical case `'README.md'`). The visual\n// comparator below lowercases both sides, so re-exporting the canonical\n// constant under the same local name preserves call-site syntax without\n// drifting from the SSOT.\nconst DEFAULT_FOLDER_INDEX_FILE = CANONICAL_FOLDER_INDEX_FILE;\n\n/**\n * Compute the visual \"selected\" state for a navigation node.\n *\n * Folder-with-README convention: when `selectedPath` is a folder that has a\n * README, the FOLDER doesn't get the ribbon — its README child does. The folder\n * is just a container; the README is the actual document being viewed.\n *\n * Mirror case: a README file whose parent folder is the `selectedPath` gets the\n * visual selection ribbon (implicit). This handles both the auto-select-first-\n * folder landing path AND the user-clicks-folder case.\n */\nfunction isNodeVisuallySelected(\n node: NavigationNode,\n selectedPath: string,\n folderIndexFile: string = DEFAULT_FOLDER_INDEX_FILE,\n): boolean {\n const FOLDER_INDEX_FILE = folderIndexFile.toLowerCase();\n // Path comparisons keyed on `node.path` (raw, includes `.md`). Do NOT use\n // `node.name` — the tree-builder runs it through `formatDocName` which strips\n // the `.md` extension, so `node.name.toLowerCase() === 'readme.md'` is always\n // false.\n if (selectedPath === node.path) {\n // Explicit match — but folder-with-README defers to its README child.\n return !(node.type === 'folder' && node.hasReadme);\n }\n if (node.type !== 'file') return false;\n const pathLower = node.path.toLowerCase();\n // Implicit: README child whose parent folder is the selectedPath.\n if (selectedPath !== '' && pathLower === `${selectedPath.toLowerCase()}/${FOLDER_INDEX_FILE}`) {\n return true;\n }\n // Implicit: ROOT README on the landing page (selectedPath === '' means\n // \"no explicit doc selected\" — the viewer falls back to the root folder-\n // index file, so that file IS the active document).\n if (selectedPath === '' && pathLower === FOLDER_INDEX_FILE) {\n return true;\n }\n return false;\n}\n\nexport function MultiLevelNavigation({\n nodes,\n selectedPath,\n expandedNodes,\n onNodeClick,\n onToggleExpand,\n isLoading,\n className,\n folderIndexFile = DEFAULT_FOLDER_INDEX_FILE,\n}: MultiLevelNavigationProps) {\n if (isLoading) {\n return (\n <div className={cn('space-y-2', className)}>\n {[1, 2, 3, 4].map(i => (\n <div key={i} className=\"h-12 animate-pulse rounded-lg bg-ods-skeleton p-3\" />\n ))}\n </div>\n );\n }\n\n return (\n <div className={cn('space-y-2', className)} role=\"list\" aria-label=\"Navigation list\">\n {nodes.map(node => (\n <NavigationItem\n key={node.id}\n node={node}\n selectedPath={selectedPath}\n expandedNodes={expandedNodes}\n onNodeClick={onNodeClick}\n onToggleExpand={onToggleExpand}\n level={0}\n folderIndexFile={folderIndexFile}\n />\n ))}\n </div>\n );\n}\n\ninterface NavigationItemProps {\n node: NavigationNode;\n selectedPath: string;\n expandedNodes: Set<string>;\n onNodeClick: (node: NavigationNode) => void;\n onToggleExpand?: (nodeId: string) => void;\n level: number;\n folderIndexFile: string;\n}\n\nfunction NavigationItem({\n node,\n selectedPath,\n expandedNodes,\n onNodeClick,\n onToggleExpand,\n level,\n folderIndexFile,\n}: NavigationItemProps) {\n const isExpanded = expandedNodes.has(node.id);\n const isSelected = isNodeVisuallySelected(node, selectedPath, folderIndexFile);\n // Bind the (optional) child list once so the render below maps a real array\n // rather than re-deriving `hasChildren` and asserting it away.\n const children = node.children ?? [];\n const hasChildren = children.length > 0;\n\n return (\n <div className=\"space-y-1\" role=\"listitem\">\n <div className={cn('px-2', level > 0 && 'ml-4')}>\n <div\n className={cn(\n 'relative w-full rounded-lg border transition-all duration-150',\n isSelected ? 'border-ods-border bg-ods-border' : 'border-ods-border bg-ods-card',\n )}\n >\n <div className=\"relative flex items-center\">\n <button\n className={cn(\n 'flex h-12 w-full items-center rounded-lg px-2 text-ods-text-primary transition-all duration-150 text-h6',\n !isSelected && 'hover:bg-ods-bg-hover',\n hasChildren && 'pr-12',\n )}\n onClick={() => onNodeClick(node)}\n aria-label={`${isSelected ? 'Selected' : 'Select'} ${node.name}`}\n >\n <span className=\"mr-2 flex-shrink-0\">\n {node.type === 'folder' ? (\n isExpanded ? (\n <FolderOpen className=\"h-4 w-4\" />\n ) : (\n <Folder className=\"h-4 w-4\" />\n )\n ) : (\n <FileText className=\"h-4 w-4\" />\n )}\n </span>\n <span className=\"min-w-0 flex-1 truncate text-left\">\n {node.name.endsWith('.md') ? node.name.replace('.md', '') : node.name}\n </span>\n {node.type === 'folder' && node.hasReadme && (\n <span className=\"mr-2 rounded bg-ods-bg-surface px-1.5 py-0.5 text-ods-text-secondary text-h6\">\n README\n </span>\n )}\n </button>\n\n {hasChildren && (\n <button\n className=\"absolute right-0 top-0 flex h-12 w-12 items-center justify-center text-ods-text-secondary transition-colors duration-150 hover:text-ods-text-primary\"\n onClick={e => {\n e.stopPropagation();\n if (onToggleExpand) {\n onToggleExpand(node.id);\n } else {\n onNodeClick(node);\n }\n }}\n aria-label={`${isExpanded ? 'Collapse' : 'Expand'} ${node.name}`}\n >\n {isExpanded ? <ChevronUp className=\"h-4 w-4\" /> : <ChevronDown className=\"h-4 w-4\" />}\n </button>\n )}\n </div>\n\n {isSelected && (\n <div className=\"absolute right-0 top-1/2 h-[calc(100%-8px)] w-1 -translate-y-1/2 rounded-l bg-ods-accent\" />\n )}\n </div>\n </div>\n\n {hasChildren && isExpanded && (\n <div className=\"space-y-1\">\n {children.map(child => (\n <NavigationItem\n key={child.id}\n node={child}\n selectedPath={selectedPath}\n expandedNodes={expandedNodes}\n onNodeClick={onNodeClick}\n onToggleExpand={onToggleExpand}\n level={level + 1}\n folderIndexFile={folderIndexFile}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\nexport function MobileNavigationDropdown({\n nodes,\n selectedPath,\n expandedNodes,\n onNodeClick,\n onToggleExpand,\n isLoading,\n className,\n folderIndexFile = DEFAULT_FOLDER_INDEX_FILE,\n}: MultiLevelNavigationProps) {\n if (isLoading) {\n return (\n <div className={cn('space-y-2', className)}>\n {[1, 2, 3].map(i => (\n <div key={i} className=\"h-10 animate-pulse rounded-lg bg-ods-skeleton p-3\" />\n ))}\n </div>\n );\n }\n\n return (\n <div className={cn('space-y-2', className)}>\n {nodes.map(node => (\n <MobileNavigationItem\n key={node.id}\n node={node}\n selectedPath={selectedPath}\n expandedNodes={expandedNodes}\n onNodeClick={onNodeClick}\n onToggleExpand={onToggleExpand}\n level={0}\n folderIndexFile={folderIndexFile}\n />\n ))}\n </div>\n );\n}\n\nfunction MobileNavigationItem({\n node,\n selectedPath,\n expandedNodes,\n onNodeClick,\n onToggleExpand,\n level,\n folderIndexFile,\n}: NavigationItemProps) {\n const isExpanded = expandedNodes.has(node.id);\n const isSelected = isNodeVisuallySelected(node, selectedPath, folderIndexFile);\n // Same binding as the desktop item above — a real array to map, no assertion.\n const children = node.children ?? [];\n const hasChildren = children.length > 0;\n\n return (\n <div className=\"space-y-1\">\n <div className={cn('px-2', level > 0 && 'ml-3')}>\n <div\n className={cn(\n 'relative w-full rounded-lg border transition-all duration-150',\n isSelected ? 'border-ods-border bg-ods-border' : 'border-ods-border bg-ods-card',\n )}\n >\n <div className=\"relative flex items-center\">\n <button\n className={cn(\n 'flex h-11 w-full items-center rounded-lg px-2 text-ods-text-primary transition-all duration-150 text-h6',\n !isSelected && 'hover:bg-ods-bg-hover',\n hasChildren && 'pr-11',\n )}\n onClick={() => onNodeClick(node)}\n >\n <span className=\"mr-2 flex-shrink-0\">\n {node.type === 'folder' ? (\n isExpanded ? (\n <FolderOpen className=\"h-4 w-4\" />\n ) : (\n <Folder className=\"h-4 w-4\" />\n )\n ) : (\n <FileText className=\"h-4 w-4\" />\n )}\n </span>\n <span className=\"min-w-0 flex-1 truncate text-left\">\n {node.name.endsWith('.md') ? node.name.replace('.md', '') : node.name}\n </span>\n {node.type === 'folder' && node.hasReadme && (\n <span className=\"mr-2 rounded bg-ods-bg-surface px-1.5 py-0.5 text-ods-text-secondary text-h6\">\n README\n </span>\n )}\n </button>\n\n {hasChildren && (\n <button\n className=\"absolute right-0 top-0 flex h-11 w-11 items-center justify-center text-ods-text-secondary transition-colors duration-150 hover:text-ods-text-primary\"\n onClick={e => {\n e.stopPropagation();\n if (onToggleExpand) {\n onToggleExpand(node.id);\n } else {\n onNodeClick(node);\n }\n }}\n aria-label={`${isExpanded ? 'Collapse' : 'Expand'} ${node.name}`}\n >\n {isExpanded ? <ChevronUp className=\"h-3.5 w-3.5\" /> : <ChevronDown className=\"h-3.5 w-3.5\" />}\n </button>\n )}\n </div>\n\n {isSelected && (\n <div className=\"absolute right-0 top-1/2 h-[calc(100%-8px)] w-1 -translate-y-1/2 rounded-l bg-ods-accent\" />\n )}\n </div>\n </div>\n\n {hasChildren && isExpanded && (\n <div className=\"space-y-1\">\n {children.map(child => (\n <MobileNavigationItem\n key={child.id}\n node={child}\n selectedPath={selectedPath}\n expandedNodes={expandedNodes}\n onNodeClick={onNodeClick}\n onToggleExpand={onToggleExpand}\n level={level + 1}\n folderIndexFile={folderIndexFile}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-NQCGDZJ3.cjs","../src/components/navigation/sticky-section-nav.tsx","../src/components/navigation/multi-level-navigation.tsx"],"names":["jsx","DEFAULT_FOLDER_INDEX_FILE"],"mappings":"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","file":"/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-NQCGDZJ3.cjs","sourcesContent":[null,"'use client';\n\nimport type React from 'react';\nimport { useEffect, useState, useCallback, useRef } from 'react';\nimport { cn } from '../../utils';\nimport { scrollElementIntoView } from '../../utils/scroll-into-view';\n\nexport interface StickyNavSection {\n id: string;\n label: string;\n}\n\ninterface StickySectionNavProps {\n sections: StickyNavSection[];\n activeSection: string;\n onSectionClick: (sectionId: string) => void;\n className?: string;\n ribbonPosition?: 'left' | 'right';\n ribbonColor?: string;\n}\n\n/**\n * Reusable sticky navigation component for section-based navigation\n * Used in vendor detail pages, knowledge base, documentation, etc.\n */\nexport function StickySectionNav({\n sections,\n activeSection,\n onSectionClick,\n className,\n ribbonPosition = 'left',\n ribbonColor = 'var(--color-accent-primary)',\n}: StickySectionNavProps) {\n const navHeight = sections.length * 40; // 40px per item (h-10)\n\n return (\n <nav className={cn('relative bg-ods-bg', className)}>\n {/* Background gray vertical line for all nav items */}\n <div\n className=\"absolute bg-ods-border\"\n style={{\n width: '1px',\n height: `${navHeight}px`,\n [ribbonPosition === 'left' ? 'left' : 'right']: '-2px',\n top: '0px',\n }}\n />\n\n {sections.map(section => (\n <div key={section.id} className=\"relative flex h-10 w-full items-stretch transition-all duration-200\">\n {/* Yellow ribbon for active state */}\n {activeSection === section.id && (\n <div\n className=\"absolute z-10 transition-all duration-200\"\n style={{\n backgroundColor: ribbonColor,\n width: '4px',\n height: '24px',\n [ribbonPosition === 'left' ? 'left' : 'right']: '-2px',\n top: '8px',\n borderRadius: '2px',\n }}\n />\n )}\n\n {/* Navigation button */}\n <button\n onClick={() => onSectionClick(section.id)}\n className=\"relative flex flex-1 cursor-pointer items-center gap-2 px-3 py-2\"\n >\n <span\n className={cn(\n 'text-left transition-all duration-200 text-h6',\n activeSection === section.id\n ? 'text-ods-text-primary'\n : 'text-ods-text-secondary hover:text-ods-text-primary',\n )}\n >\n {section.label}\n </span>\n </button>\n </div>\n ))}\n </nav>\n );\n}\n\n/**\n * SIMPLEST POSSIBLE IMPLEMENTATION - Just make it work\n */\nexport function useSectionNavigation(\n sections: { id: string; ref: React.RefObject<HTMLElement> }[],\n options?: {\n offset?: number;\n },\n) {\n const [activeSection, setActiveSection] = useState(sections[0]?.id || '');\n const isScrollingFromClick = useRef(false);\n const { offset = 100 } = options || {};\n\n // Handle click - scroll to the element via the canonical helper.\n // The `offset` prop maps to `headerOffset` (sticky chrome above the\n // section nav); same smooth-scroll mechanics every other anchor\n // surface in the app uses.\n const handleSectionClick = useCallback(\n (sectionId: string) => {\n const targetElement = document.getElementById(sectionId);\n if (!targetElement) return;\n\n // Prevent scroll spy while we're scrolling\n isScrollingFromClick.current = true;\n setActiveSection(sectionId);\n\n scrollElementIntoView(targetElement, { headerOffset: offset });\n\n // Allow scroll spy again after scroll completes\n setTimeout(() => {\n isScrollingFromClick.current = false;\n }, 500);\n },\n [offset],\n );\n\n // Make sure elements have IDs\n useEffect(() => {\n sections.forEach(section => {\n const el = section.ref.current;\n if (el && !el.id) {\n el.id = section.id;\n }\n });\n }, [sections]);\n\n // Simple scroll spy\n useEffect(() => {\n const handleScroll = () => {\n if (isScrollingFromClick.current) return;\n\n const scrollPosition = window.scrollY + offset + 50;\n\n // Find which section we're in\n let currentSection = sections[0]?.id || '';\n\n for (let i = sections.length - 1; i >= 0; i--) {\n const element = document.getElementById(sections[i].id);\n if (element && scrollPosition >= element.offsetTop) {\n currentSection = sections[i].id;\n break;\n }\n }\n\n setActiveSection(currentSection);\n };\n\n // Throttle the scroll handler\n let scrollTimer: NodeJS.Timeout;\n const throttledScroll = () => {\n clearTimeout(scrollTimer);\n scrollTimer = setTimeout(handleScroll, 100);\n };\n\n window.addEventListener('scroll', throttledScroll);\n handleScroll(); // Check initial position\n\n return () => {\n window.removeEventListener('scroll', throttledScroll);\n clearTimeout(scrollTimer);\n };\n }, [sections, offset]);\n\n return {\n activeSection,\n handleSectionClick,\n };\n}\n","'use client';\n\nimport { ChevronDown, ChevronUp, FileText, Folder, FolderOpen } from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport { DEFAULT_FOLDER_INDEX_FILE as CANONICAL_FOLDER_INDEX_FILE } from '../../utils/doc-tree-nav';\n\nexport interface NavigationNode {\n id: string;\n name: string;\n path: string;\n type: 'file' | 'folder';\n hasReadme?: boolean;\n children?: NavigationNode[];\n slug?: string;\n // Mirror DocNode's extra optional fields so a DocNode tree is structurally\n // assignable to NavigationNode[] without an `as` cast. NavigationNode\n // intentionally never reads these — they're carried for type-compat only.\n documentType?: 'markdown' | 'pdf' | 'google_sheet' | 'figma' | 'file';\n sortOrder?: number;\n}\n\ninterface MultiLevelNavigationProps {\n nodes: NavigationNode[];\n selectedPath: string;\n expandedNodes: Set<string>;\n onNodeClick: (node: NavigationNode) => void;\n onToggleExpand?: (nodeId: string) => void;\n isLoading?: boolean;\n className?: string;\n /** Folder-index filename (default `'README.md'`, case-insensitive). When the\n * selectedPath is a folder with this file, the visual ribbon moves to the\n * child file. */\n folderIndexFile?: string;\n}\n\n// SSOT lives in `doc-tree-nav` (canonical case `'README.md'`). The visual\n// comparator below lowercases both sides, so re-exporting the canonical\n// constant under the same local name preserves call-site syntax without\n// drifting from the SSOT.\nconst DEFAULT_FOLDER_INDEX_FILE = CANONICAL_FOLDER_INDEX_FILE;\n\n/**\n * Compute the visual \"selected\" state for a navigation node.\n *\n * Folder-with-README convention: when `selectedPath` is a folder that has a\n * README, the FOLDER doesn't get the ribbon — its README child does. The folder\n * is just a container; the README is the actual document being viewed.\n *\n * Mirror case: a README file whose parent folder is the `selectedPath` gets the\n * visual selection ribbon (implicit). This handles both the auto-select-first-\n * folder landing path AND the user-clicks-folder case.\n */\nfunction isNodeVisuallySelected(\n node: NavigationNode,\n selectedPath: string,\n folderIndexFile: string = DEFAULT_FOLDER_INDEX_FILE,\n): boolean {\n const FOLDER_INDEX_FILE = folderIndexFile.toLowerCase();\n // Path comparisons keyed on `node.path` (raw, includes `.md`). Do NOT use\n // `node.name` — the tree-builder runs it through `formatDocName` which strips\n // the `.md` extension, so `node.name.toLowerCase() === 'readme.md'` is always\n // false.\n if (selectedPath === node.path) {\n // Explicit match — but folder-with-README defers to its README child.\n return !(node.type === 'folder' && node.hasReadme);\n }\n if (node.type !== 'file') return false;\n const pathLower = node.path.toLowerCase();\n // Implicit: README child whose parent folder is the selectedPath.\n if (selectedPath !== '' && pathLower === `${selectedPath.toLowerCase()}/${FOLDER_INDEX_FILE}`) {\n return true;\n }\n // Implicit: ROOT README on the landing page (selectedPath === '' means\n // \"no explicit doc selected\" — the viewer falls back to the root folder-\n // index file, so that file IS the active document).\n if (selectedPath === '' && pathLower === FOLDER_INDEX_FILE) {\n return true;\n }\n return false;\n}\n\nexport function MultiLevelNavigation({\n nodes,\n selectedPath,\n expandedNodes,\n onNodeClick,\n onToggleExpand,\n isLoading,\n className,\n folderIndexFile = DEFAULT_FOLDER_INDEX_FILE,\n}: MultiLevelNavigationProps) {\n if (isLoading) {\n return (\n <div className={cn('space-y-2', className)}>\n {[1, 2, 3, 4].map(i => (\n <div key={i} className=\"h-12 animate-pulse rounded-lg bg-ods-skeleton p-3\" />\n ))}\n </div>\n );\n }\n\n return (\n <div className={cn('space-y-2', className)} role=\"list\" aria-label=\"Navigation list\">\n {nodes.map(node => (\n <NavigationItem\n key={node.id}\n node={node}\n selectedPath={selectedPath}\n expandedNodes={expandedNodes}\n onNodeClick={onNodeClick}\n onToggleExpand={onToggleExpand}\n level={0}\n folderIndexFile={folderIndexFile}\n />\n ))}\n </div>\n );\n}\n\ninterface NavigationItemProps {\n node: NavigationNode;\n selectedPath: string;\n expandedNodes: Set<string>;\n onNodeClick: (node: NavigationNode) => void;\n onToggleExpand?: (nodeId: string) => void;\n level: number;\n folderIndexFile: string;\n}\n\nfunction NavigationItem({\n node,\n selectedPath,\n expandedNodes,\n onNodeClick,\n onToggleExpand,\n level,\n folderIndexFile,\n}: NavigationItemProps) {\n const isExpanded = expandedNodes.has(node.id);\n const isSelected = isNodeVisuallySelected(node, selectedPath, folderIndexFile);\n // Bind the (optional) child list once so the render below maps a real array\n // rather than re-deriving `hasChildren` and asserting it away.\n const children = node.children ?? [];\n const hasChildren = children.length > 0;\n\n return (\n <div className=\"space-y-1\" role=\"listitem\">\n <div className={cn('px-2', level > 0 && 'ml-4')}>\n <div\n className={cn(\n 'relative w-full rounded-lg border transition-all duration-150',\n isSelected ? 'border-ods-border bg-ods-border' : 'border-ods-border bg-ods-card',\n )}\n >\n <div className=\"relative flex items-center\">\n <button\n className={cn(\n 'flex h-12 w-full items-center rounded-lg px-2 text-ods-text-primary transition-all duration-150 text-h6',\n !isSelected && 'hover:bg-ods-bg-hover',\n hasChildren && 'pr-12',\n )}\n onClick={() => onNodeClick(node)}\n aria-label={`${isSelected ? 'Selected' : 'Select'} ${node.name}`}\n >\n <span className=\"mr-2 flex-shrink-0\">\n {node.type === 'folder' ? (\n isExpanded ? (\n <FolderOpen className=\"h-4 w-4\" />\n ) : (\n <Folder className=\"h-4 w-4\" />\n )\n ) : (\n <FileText className=\"h-4 w-4\" />\n )}\n </span>\n <span className=\"min-w-0 flex-1 truncate text-left\">\n {node.name.endsWith('.md') ? node.name.replace('.md', '') : node.name}\n </span>\n {node.type === 'folder' && node.hasReadme && (\n <span className=\"mr-2 rounded bg-ods-bg-surface px-1.5 py-0.5 text-ods-text-secondary text-h6\">\n README\n </span>\n )}\n </button>\n\n {hasChildren && (\n <button\n className=\"absolute right-0 top-0 flex h-12 w-12 items-center justify-center text-ods-text-secondary transition-colors duration-150 hover:text-ods-text-primary\"\n onClick={e => {\n e.stopPropagation();\n if (onToggleExpand) {\n onToggleExpand(node.id);\n } else {\n onNodeClick(node);\n }\n }}\n aria-label={`${isExpanded ? 'Collapse' : 'Expand'} ${node.name}`}\n >\n {isExpanded ? <ChevronUp className=\"h-4 w-4\" /> : <ChevronDown className=\"h-4 w-4\" />}\n </button>\n )}\n </div>\n\n {isSelected && (\n <div className=\"absolute right-0 top-1/2 h-[calc(100%-8px)] w-1 -translate-y-1/2 rounded-l bg-ods-accent\" />\n )}\n </div>\n </div>\n\n {hasChildren && isExpanded && (\n <div className=\"space-y-1\">\n {children.map(child => (\n <NavigationItem\n key={child.id}\n node={child}\n selectedPath={selectedPath}\n expandedNodes={expandedNodes}\n onNodeClick={onNodeClick}\n onToggleExpand={onToggleExpand}\n level={level + 1}\n folderIndexFile={folderIndexFile}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\nexport function MobileNavigationDropdown({\n nodes,\n selectedPath,\n expandedNodes,\n onNodeClick,\n onToggleExpand,\n isLoading,\n className,\n folderIndexFile = DEFAULT_FOLDER_INDEX_FILE,\n}: MultiLevelNavigationProps) {\n if (isLoading) {\n return (\n <div className={cn('space-y-2', className)}>\n {[1, 2, 3].map(i => (\n <div key={i} className=\"h-10 animate-pulse rounded-lg bg-ods-skeleton p-3\" />\n ))}\n </div>\n );\n }\n\n return (\n <div className={cn('space-y-2', className)}>\n {nodes.map(node => (\n <MobileNavigationItem\n key={node.id}\n node={node}\n selectedPath={selectedPath}\n expandedNodes={expandedNodes}\n onNodeClick={onNodeClick}\n onToggleExpand={onToggleExpand}\n level={0}\n folderIndexFile={folderIndexFile}\n />\n ))}\n </div>\n );\n}\n\nfunction MobileNavigationItem({\n node,\n selectedPath,\n expandedNodes,\n onNodeClick,\n onToggleExpand,\n level,\n folderIndexFile,\n}: NavigationItemProps) {\n const isExpanded = expandedNodes.has(node.id);\n const isSelected = isNodeVisuallySelected(node, selectedPath, folderIndexFile);\n // Same binding as the desktop item above — a real array to map, no assertion.\n const children = node.children ?? [];\n const hasChildren = children.length > 0;\n\n return (\n <div className=\"space-y-1\">\n <div className={cn('px-2', level > 0 && 'ml-3')}>\n <div\n className={cn(\n 'relative w-full rounded-lg border transition-all duration-150',\n isSelected ? 'border-ods-border bg-ods-border' : 'border-ods-border bg-ods-card',\n )}\n >\n <div className=\"relative flex items-center\">\n <button\n className={cn(\n 'flex h-11 w-full items-center rounded-lg px-2 text-ods-text-primary transition-all duration-150 text-h6',\n !isSelected && 'hover:bg-ods-bg-hover',\n hasChildren && 'pr-11',\n )}\n onClick={() => onNodeClick(node)}\n >\n <span className=\"mr-2 flex-shrink-0\">\n {node.type === 'folder' ? (\n isExpanded ? (\n <FolderOpen className=\"h-4 w-4\" />\n ) : (\n <Folder className=\"h-4 w-4\" />\n )\n ) : (\n <FileText className=\"h-4 w-4\" />\n )}\n </span>\n <span className=\"min-w-0 flex-1 truncate text-left\">\n {node.name.endsWith('.md') ? node.name.replace('.md', '') : node.name}\n </span>\n {node.type === 'folder' && node.hasReadme && (\n <span className=\"mr-2 rounded bg-ods-bg-surface px-1.5 py-0.5 text-ods-text-secondary text-h6\">\n README\n </span>\n )}\n </button>\n\n {hasChildren && (\n <button\n className=\"absolute right-0 top-0 flex h-11 w-11 items-center justify-center text-ods-text-secondary transition-colors duration-150 hover:text-ods-text-primary\"\n onClick={e => {\n e.stopPropagation();\n if (onToggleExpand) {\n onToggleExpand(node.id);\n } else {\n onNodeClick(node);\n }\n }}\n aria-label={`${isExpanded ? 'Collapse' : 'Expand'} ${node.name}`}\n >\n {isExpanded ? <ChevronUp className=\"h-3.5 w-3.5\" /> : <ChevronDown className=\"h-3.5 w-3.5\" />}\n </button>\n )}\n </div>\n\n {isSelected && (\n <div className=\"absolute right-0 top-1/2 h-[calc(100%-8px)] w-1 -translate-y-1/2 rounded-l bg-ods-accent\" />\n )}\n </div>\n </div>\n\n {hasChildren && isExpanded && (\n <div className=\"space-y-1\">\n {children.map(child => (\n <MobileNavigationItem\n key={child.id}\n node={child}\n selectedPath={selectedPath}\n expandedNodes={expandedNodes}\n onNodeClick={onNodeClick}\n onToggleExpand={onToggleExpand}\n level={level + 1}\n folderIndexFile={folderIndexFile}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n"]}
@@ -1,11 +1,11 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
2
2
 
3
3
 
4
- var _chunkQDOBY3TPcjs = require('./chunk-QDOBY3TP.cjs');
4
+ var _chunkKE2TCUOHcjs = require('./chunk-KE2TCUOH.cjs');
5
5
 
6
6
 
7
7
 
8
- var _chunkSPAAKHQAcjs = require('./chunk-SPAAKHQA.cjs');
8
+ var _chunkMIY5FYX3cjs = require('./chunk-MIY5FYX3.cjs');
9
9
 
10
10
 
11
11
  var _chunkWLSFBRT5cjs = require('./chunk-WLSFBRT5.cjs');
@@ -55,7 +55,7 @@ function DetailPageSkeleton({
55
55
  ] }, section))
56
56
  ] });
57
57
  if (bare) return content;
58
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkQDOBY3TPcjs.PageLayout, { showHeader: false, className: "mx-auto max-w-[1280px] bg-ods-bg px-6 py-6 md:px-20 md:py-10", children: content });
58
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkKE2TCUOHcjs.PageLayout, { showHeader: false, className: "mx-auto max-w-[1280px] bg-ods-bg px-6 py-6 md:px-20 md:py-10", children: content });
59
59
  }
60
60
 
61
61
  // src/components/shared/article-author-byline.tsx
@@ -85,7 +85,7 @@ function ArticleAuthorByline({
85
85
  }) {
86
86
  const runtime = _chunkRDTOMWDNcjs.useChatRuntime.call(void 0, );
87
87
  if (!author) return null;
88
- const proxiedAvatar = avatar ? proxyImageUrl ? proxyImageUrl(avatar) : _nullishCoalesce(_chunkSPAAKHQAcjs.getProxiedImageUrl.call(void 0, avatar, {
88
+ const proxiedAvatar = avatar ? proxyImageUrl ? proxyImageUrl(avatar) : _nullishCoalesce(_chunkMIY5FYX3cjs.getProxiedImageUrl.call(void 0, avatar, {
89
89
  proxyPrefix: _optionalChain([runtime, 'optionalAccess', _2 => _2.endpoints, 'access', _3 => _3.imageProxyUrlPrefix]),
90
90
  skipDomains: _optionalChain([runtime, 'optionalAccess', _4 => _4.endpoints, 'access', _5 => _5.imageProxySkipDomains]),
91
91
  directHttps: true
@@ -93,7 +93,7 @@ function ArticleAuthorByline({
93
93
  const avatarSizeClass = size === "lg" ? "w-16 h-16" : "w-14 h-14";
94
94
  const avatarIconClass = size === "lg" ? "w-8 h-8" : "w-7 h-7";
95
95
  const avatarDim = size === "lg" ? 64 : 56;
96
- const formattedBio = _chunkSPAAKHQAcjs.formatBioText.call(void 0, _nullishCoalesce(bio, () => ( null)));
96
+ const formattedBio = _chunkMIY5FYX3cjs.formatBioText.call(void 0, _nullishCoalesce(bio, () => ( null)));
97
97
  const dateLabel = publishedAt ? formatDate(publishedAt) : "";
98
98
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
99
99
  "div",
@@ -143,4 +143,4 @@ function ArticleAuthorByline({
143
143
 
144
144
 
145
145
  exports.DetailPageSkeleton = DetailPageSkeleton; exports.ArticleAuthorByline = ArticleAuthorByline;
146
- //# sourceMappingURL=chunk-BKXL7OYT.cjs.map
146
+ //# sourceMappingURL=chunk-RCLJSENK.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-BKXL7OYT.cjs","../src/components/shared/detail-page-skeleton.tsx","../src/components/shared/article-author-byline.tsx"],"names":["jsxs","jsx"],"mappings":"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","file":"/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-BKXL7OYT.cjs","sourcesContent":[null,"'use client';\n\nimport { PageLayout } from '../layout/page-layout';\n\nexport interface DetailPageSkeletonProps {\n metadataColumns?: number; // Number of metadata grid columns (default 4)\n showImageGallery?: boolean; // Show horizontal image gallery (default true)\n /** Render only the skeleton blocks, WITHOUT the self-contained page wrapper\n * — the caller supplies its own (e.g. `<PageShell>`) so the loading state\n * matches the loaded page's width, padding, and min-height. Default false\n * (self-contained `<PageLayout>` at the hub article width). */\n bare?: boolean;\n}\n\nexport function DetailPageSkeleton({\n metadataColumns = 4,\n showImageGallery = true,\n bare = false,\n}: DetailPageSkeletonProps = {}) {\n const content = (\n <div className=\"animate-pulse space-y-6 md:space-y-10\">\n {/* Title Block */}\n <div className=\"flex w-full flex-col gap-6\">\n <div className=\"h-16 w-full max-w-3xl rounded bg-ods-card md:h-20\"></div>\n </div>\n\n {/* Category Tags Skeleton */}\n <div className=\"flex w-full flex-wrap gap-2\">\n <div className=\"h-8 w-32 rounded bg-ods-card\"></div>\n <div className=\"h-8 w-28 rounded bg-ods-card\"></div>\n <div className=\"h-8 w-36 rounded bg-ods-card\"></div>\n </div>\n\n {/* Metadata Grid Skeleton */}\n <div\n className={`grid grid-cols-1 md:grid-cols-${metadataColumns} w-full overflow-hidden rounded-md border border-ods-border`}\n >\n {Array.from({ length: metadataColumns }).map((_, i) => (\n <div key={i} className=\"border-b border-ods-border bg-ods-card p-4 last:border-r-0 md:border-b-0 md:border-r\">\n <div className=\"mb-2 h-6 w-24 rounded bg-ods-border\"></div>\n <div className=\"h-5 w-20 rounded bg-ods-border\"></div>\n </div>\n ))}\n </div>\n\n {/* Image Gallery Skeleton */}\n {showImageGallery && (\n <div className=\"flex w-full gap-6 overflow-x-auto\">\n {[1, 2, 3, 4, 5].map(i => (\n <div key={i} className=\"h-[200px] w-[240px] shrink-0 rounded-md border border-ods-border bg-ods-card\"></div>\n ))}\n </div>\n )}\n\n {/* Featured Image Skeleton (for case studies) */}\n {!showImageGallery && <div className=\"aspect-[2560/1366] w-full rounded-md bg-ods-card\"></div>}\n\n {/* Content Sections Skeleton */}\n {[1, 2, 3].map(section => (\n <div key={section} className=\"space-y-6\">\n <div className=\"h-16 w-64 rounded bg-ods-card\"></div>\n <div className=\"space-y-3\">\n <div className=\"h-6 w-full rounded bg-ods-card\"></div>\n <div className=\"h-6 w-full rounded bg-ods-card\"></div>\n <div className=\"h-6 w-4/5 rounded bg-ods-card\"></div>\n </div>\n </div>\n ))}\n </div>\n );\n if (bare) return content;\n return (\n <PageLayout showHeader={false} className=\"mx-auto max-w-[1280px] bg-ods-bg px-6 py-6 md:px-20 md:py-10\">\n {content}\n </PageLayout>\n );\n}\n","'use client';\n\n/**\n * Shared \"author byline\" card used by article-shaped detail pages\n * (blog post, product release, onboarding guide, investor update).\n *\n * MOVED from the hub so any consuming app can embed it; hub call sites\n * import it directly and pass their platform-aware copy explicitly\n * (`fallbackBio={defaultAuthorFallbackBio()}` from the hub's app-config).\n *\n * Embed-readiness contract:\n * - `Link` / `Image` render through the embed-shims (plain `<a>` / `<img>`\n * in non-Next hosts; the real Next primitives once the host registers\n * them at app init).\n * - The avatar is proxied through the OPTIONAL ambient `ChatRuntime`\n * (`endpoints.imageProxyUrlPrefix`, same config `useProxiedImageUrl`\n * reads) — when no runtime is mounted the raw URL renders as-is, so the\n * component never throws outside a provider. Hosts can also inject\n * `proxyImageUrl` to bypass the runtime entirely.\n * - `fallbackBio` is a PLAIN prop (no app-config import): the lib has no\n * platform awareness; pass copy or leave it absent to render nothing.\n *\n * Render order: avatar → name + job title + date → bio (when present).\n * Returns null when `author` is empty (no card rendered).\n */\n\nimport { Calendar, User } from 'lucide-react';\nimport { useChatRuntime } from '../../contexts/chat-runtime-context';\nimport Image from '../../embed-shims/next-image';\nimport Link from '../../embed-shims/next-link';\nimport { cn } from '../../utils/cn';\nimport { formatBioText } from '../../utils/format';\nimport { getProxiedImageUrl } from '../../utils/image-proxy';\n\nexport interface ArticleAuthorBylineProps {\n /** Author display name. Required — block is hidden when null/empty. */\n author: string | null;\n /** Avatar URL. Falls back to a placeholder when null. */\n avatar?: string | null;\n /** Optional bio paragraph rendered below the name. */\n bio?: string | null;\n /** Optional job title rendered immediately under the name. */\n jobTitle?: string | null;\n /** Optional published date (ISO string or Date). Rendered next to the name. */\n publishedAt?: string | Date | null;\n /** Optional link target for the author name (e.g. the author page). */\n href?: string | null;\n /**\n * Fallback paragraph when `bio` is empty. Plain copy — the lib has no\n * platform/config awareness, so hosts that want a branded default\n * (\"Contributing author on the {platform} platform\") pass it explicitly\n * (the hub wrapper derives it from `getAppConfig()`). Absent/null ⇒\n * nothing renders below the name when `bio` is empty.\n */\n fallbackBio?: string | null;\n /** Avatar size variant. `md` = 56px (default), `lg` = 64px. */\n size?: 'md' | 'lg';\n /**\n * Host-injected avatar-URL mapper. Wins over the ambient-runtime proxy\n * resolution. Use when the host proxies images outside the `ChatRuntime`\n * config (e.g. a bespoke CDN rewrite).\n */\n proxyImageUrl?: (url: string) => string;\n className?: string;\n}\n\nfunction formatDate(value: string | Date): string {\n const d = typeof value === 'string' ? new Date(value) : value;\n if (Number.isNaN(d.getTime())) return '';\n // `timeZone: 'UTC'` keeps the SSR (server = UTC) and client (user's local tz)\n // renders identical — without it a published_at near a midnight boundary\n // formats to a different day on each side, triggering a React #418 hydration\n // text mismatch. Matches the convention in blog-metadata.tsx / investor-update.\n return d.toLocaleDateString('en-US', {\n month: 'long',\n day: 'numeric',\n year: 'numeric',\n timeZone: 'UTC',\n });\n}\n\nexport function ArticleAuthorByline({\n author,\n avatar,\n bio,\n jobTitle,\n publishedAt,\n href,\n fallbackBio,\n size = 'md',\n proxyImageUrl,\n className,\n}: ArticleAuthorBylineProps) {\n // Optional runtime — `useChatRuntime` returns null outside a provider, so\n // the byline works in bare embeds (raw avatar URL) and proxies whenever the\n // host mounted a runtime with `imageProxyUrlPrefix` (the hub always does).\n const runtime = useChatRuntime();\n if (!author) return null;\n\n const proxiedAvatar = avatar\n ? proxyImageUrl\n ? proxyImageUrl(avatar)\n : (getProxiedImageUrl(avatar, {\n proxyPrefix: runtime?.endpoints.imageProxyUrlPrefix,\n skipDomains: runtime?.endpoints.imageProxySkipDomains,\n directHttps: true,\n }) ?? avatar)\n : '';\n\n // Class-driven sizing (md = 56px, lg = 64px). The numeric pair feeds only\n // the Image element's intrinsic width/height attributes (required by the\n // Next image shim) — layout comes from the classes.\n const avatarSizeClass = size === 'lg' ? 'w-16 h-16' : 'w-14 h-14';\n const avatarIconClass = size === 'lg' ? 'w-8 h-8' : 'w-7 h-7';\n const avatarDim = size === 'lg' ? 64 : 56;\n const formattedBio = formatBioText(bio ?? null);\n const dateLabel = publishedAt ? formatDate(publishedAt) : '';\n\n return (\n <div\n className={cn(\n 'rounded-lg border border-ods-border bg-ods-card p-6',\n 'flex flex-col items-start gap-4 md:flex-row',\n className,\n )}\n >\n {/* Avatar */}\n <div className=\"flex-shrink-0\">\n {avatar ? (\n <Image\n src={proxiedAvatar || avatar}\n alt={author}\n width={avatarDim}\n height={avatarDim}\n className={cn('rounded-full border-2 border-ods-border object-cover', avatarSizeClass)}\n />\n ) : (\n <div\n className={cn(\n 'flex items-center justify-center rounded-full border-2 border-ods-border bg-ods-bg',\n avatarSizeClass,\n )}\n >\n <User className={cn('text-ods-text-secondary', avatarIconClass)} />\n </div>\n )}\n </div>\n\n {/* Name + meta + bio */}\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-baseline gap-x-3 gap-y-1\">\n <h3 className=\"text-ods-text-primary text-h5\">\n {href ? (\n <Link href={href} className=\"transition-colors hover:text-ods-accent\">\n {author}\n </Link>\n ) : (\n author\n )}\n </h3>\n {dateLabel && (\n <span className=\"text-body-sm inline-flex items-center gap-1 font-body text-ods-text-secondary\">\n <Calendar className=\"h-3 w-3\" />\n {dateLabel}\n </span>\n )}\n </div>\n {jobTitle && <p className=\"text-body-sm mt-0.5 font-body text-ods-text-secondary\">{jobTitle}</p>}\n {formattedBio ? (\n <p className=\"text-body-md mt-2 font-body leading-relaxed text-ods-text-secondary\">{formattedBio}</p>\n ) : fallbackBio ? (\n <p className=\"text-body-md mt-2 font-body italic text-ods-text-secondary\">{fallbackBio}</p>\n ) : null}\n </div>\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-RCLJSENK.cjs","../src/components/shared/detail-page-skeleton.tsx","../src/components/shared/article-author-byline.tsx"],"names":["jsxs","jsx"],"mappings":"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","file":"/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-RCLJSENK.cjs","sourcesContent":[null,"'use client';\n\nimport { PageLayout } from '../layout/page-layout';\n\nexport interface DetailPageSkeletonProps {\n metadataColumns?: number; // Number of metadata grid columns (default 4)\n showImageGallery?: boolean; // Show horizontal image gallery (default true)\n /** Render only the skeleton blocks, WITHOUT the self-contained page wrapper\n * — the caller supplies its own (e.g. `<PageShell>`) so the loading state\n * matches the loaded page's width, padding, and min-height. Default false\n * (self-contained `<PageLayout>` at the hub article width). */\n bare?: boolean;\n}\n\nexport function DetailPageSkeleton({\n metadataColumns = 4,\n showImageGallery = true,\n bare = false,\n}: DetailPageSkeletonProps = {}) {\n const content = (\n <div className=\"animate-pulse space-y-6 md:space-y-10\">\n {/* Title Block */}\n <div className=\"flex w-full flex-col gap-6\">\n <div className=\"h-16 w-full max-w-3xl rounded bg-ods-card md:h-20\"></div>\n </div>\n\n {/* Category Tags Skeleton */}\n <div className=\"flex w-full flex-wrap gap-2\">\n <div className=\"h-8 w-32 rounded bg-ods-card\"></div>\n <div className=\"h-8 w-28 rounded bg-ods-card\"></div>\n <div className=\"h-8 w-36 rounded bg-ods-card\"></div>\n </div>\n\n {/* Metadata Grid Skeleton */}\n <div\n className={`grid grid-cols-1 md:grid-cols-${metadataColumns} w-full overflow-hidden rounded-md border border-ods-border`}\n >\n {Array.from({ length: metadataColumns }).map((_, i) => (\n <div key={i} className=\"border-b border-ods-border bg-ods-card p-4 last:border-r-0 md:border-b-0 md:border-r\">\n <div className=\"mb-2 h-6 w-24 rounded bg-ods-border\"></div>\n <div className=\"h-5 w-20 rounded bg-ods-border\"></div>\n </div>\n ))}\n </div>\n\n {/* Image Gallery Skeleton */}\n {showImageGallery && (\n <div className=\"flex w-full gap-6 overflow-x-auto\">\n {[1, 2, 3, 4, 5].map(i => (\n <div key={i} className=\"h-[200px] w-[240px] shrink-0 rounded-md border border-ods-border bg-ods-card\"></div>\n ))}\n </div>\n )}\n\n {/* Featured Image Skeleton (for case studies) */}\n {!showImageGallery && <div className=\"aspect-[2560/1366] w-full rounded-md bg-ods-card\"></div>}\n\n {/* Content Sections Skeleton */}\n {[1, 2, 3].map(section => (\n <div key={section} className=\"space-y-6\">\n <div className=\"h-16 w-64 rounded bg-ods-card\"></div>\n <div className=\"space-y-3\">\n <div className=\"h-6 w-full rounded bg-ods-card\"></div>\n <div className=\"h-6 w-full rounded bg-ods-card\"></div>\n <div className=\"h-6 w-4/5 rounded bg-ods-card\"></div>\n </div>\n </div>\n ))}\n </div>\n );\n if (bare) return content;\n return (\n <PageLayout showHeader={false} className=\"mx-auto max-w-[1280px] bg-ods-bg px-6 py-6 md:px-20 md:py-10\">\n {content}\n </PageLayout>\n );\n}\n","'use client';\n\n/**\n * Shared \"author byline\" card used by article-shaped detail pages\n * (blog post, product release, onboarding guide, investor update).\n *\n * MOVED from the hub so any consuming app can embed it; hub call sites\n * import it directly and pass their platform-aware copy explicitly\n * (`fallbackBio={defaultAuthorFallbackBio()}` from the hub's app-config).\n *\n * Embed-readiness contract:\n * - `Link` / `Image` render through the embed-shims (plain `<a>` / `<img>`\n * in non-Next hosts; the real Next primitives once the host registers\n * them at app init).\n * - The avatar is proxied through the OPTIONAL ambient `ChatRuntime`\n * (`endpoints.imageProxyUrlPrefix`, same config `useProxiedImageUrl`\n * reads) — when no runtime is mounted the raw URL renders as-is, so the\n * component never throws outside a provider. Hosts can also inject\n * `proxyImageUrl` to bypass the runtime entirely.\n * - `fallbackBio` is a PLAIN prop (no app-config import): the lib has no\n * platform awareness; pass copy or leave it absent to render nothing.\n *\n * Render order: avatar → name + job title + date → bio (when present).\n * Returns null when `author` is empty (no card rendered).\n */\n\nimport { Calendar, User } from 'lucide-react';\nimport { useChatRuntime } from '../../contexts/chat-runtime-context';\nimport Image from '../../embed-shims/next-image';\nimport Link from '../../embed-shims/next-link';\nimport { cn } from '../../utils/cn';\nimport { formatBioText } from '../../utils/format';\nimport { getProxiedImageUrl } from '../../utils/image-proxy';\n\nexport interface ArticleAuthorBylineProps {\n /** Author display name. Required — block is hidden when null/empty. */\n author: string | null;\n /** Avatar URL. Falls back to a placeholder when null. */\n avatar?: string | null;\n /** Optional bio paragraph rendered below the name. */\n bio?: string | null;\n /** Optional job title rendered immediately under the name. */\n jobTitle?: string | null;\n /** Optional published date (ISO string or Date). Rendered next to the name. */\n publishedAt?: string | Date | null;\n /** Optional link target for the author name (e.g. the author page). */\n href?: string | null;\n /**\n * Fallback paragraph when `bio` is empty. Plain copy — the lib has no\n * platform/config awareness, so hosts that want a branded default\n * (\"Contributing author on the {platform} platform\") pass it explicitly\n * (the hub wrapper derives it from `getAppConfig()`). Absent/null ⇒\n * nothing renders below the name when `bio` is empty.\n */\n fallbackBio?: string | null;\n /** Avatar size variant. `md` = 56px (default), `lg` = 64px. */\n size?: 'md' | 'lg';\n /**\n * Host-injected avatar-URL mapper. Wins over the ambient-runtime proxy\n * resolution. Use when the host proxies images outside the `ChatRuntime`\n * config (e.g. a bespoke CDN rewrite).\n */\n proxyImageUrl?: (url: string) => string;\n className?: string;\n}\n\nfunction formatDate(value: string | Date): string {\n const d = typeof value === 'string' ? new Date(value) : value;\n if (Number.isNaN(d.getTime())) return '';\n // `timeZone: 'UTC'` keeps the SSR (server = UTC) and client (user's local tz)\n // renders identical — without it a published_at near a midnight boundary\n // formats to a different day on each side, triggering a React #418 hydration\n // text mismatch. Matches the convention in blog-metadata.tsx / investor-update.\n return d.toLocaleDateString('en-US', {\n month: 'long',\n day: 'numeric',\n year: 'numeric',\n timeZone: 'UTC',\n });\n}\n\nexport function ArticleAuthorByline({\n author,\n avatar,\n bio,\n jobTitle,\n publishedAt,\n href,\n fallbackBio,\n size = 'md',\n proxyImageUrl,\n className,\n}: ArticleAuthorBylineProps) {\n // Optional runtime — `useChatRuntime` returns null outside a provider, so\n // the byline works in bare embeds (raw avatar URL) and proxies whenever the\n // host mounted a runtime with `imageProxyUrlPrefix` (the hub always does).\n const runtime = useChatRuntime();\n if (!author) return null;\n\n const proxiedAvatar = avatar\n ? proxyImageUrl\n ? proxyImageUrl(avatar)\n : (getProxiedImageUrl(avatar, {\n proxyPrefix: runtime?.endpoints.imageProxyUrlPrefix,\n skipDomains: runtime?.endpoints.imageProxySkipDomains,\n directHttps: true,\n }) ?? avatar)\n : '';\n\n // Class-driven sizing (md = 56px, lg = 64px). The numeric pair feeds only\n // the Image element's intrinsic width/height attributes (required by the\n // Next image shim) — layout comes from the classes.\n const avatarSizeClass = size === 'lg' ? 'w-16 h-16' : 'w-14 h-14';\n const avatarIconClass = size === 'lg' ? 'w-8 h-8' : 'w-7 h-7';\n const avatarDim = size === 'lg' ? 64 : 56;\n const formattedBio = formatBioText(bio ?? null);\n const dateLabel = publishedAt ? formatDate(publishedAt) : '';\n\n return (\n <div\n className={cn(\n 'rounded-lg border border-ods-border bg-ods-card p-6',\n 'flex flex-col items-start gap-4 md:flex-row',\n className,\n )}\n >\n {/* Avatar */}\n <div className=\"flex-shrink-0\">\n {avatar ? (\n <Image\n src={proxiedAvatar || avatar}\n alt={author}\n width={avatarDim}\n height={avatarDim}\n className={cn('rounded-full border-2 border-ods-border object-cover', avatarSizeClass)}\n />\n ) : (\n <div\n className={cn(\n 'flex items-center justify-center rounded-full border-2 border-ods-border bg-ods-bg',\n avatarSizeClass,\n )}\n >\n <User className={cn('text-ods-text-secondary', avatarIconClass)} />\n </div>\n )}\n </div>\n\n {/* Name + meta + bio */}\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-baseline gap-x-3 gap-y-1\">\n <h3 className=\"text-ods-text-primary text-h5\">\n {href ? (\n <Link href={href} className=\"transition-colors hover:text-ods-accent\">\n {author}\n </Link>\n ) : (\n author\n )}\n </h3>\n {dateLabel && (\n <span className=\"text-body-sm inline-flex items-center gap-1 font-body text-ods-text-secondary\">\n <Calendar className=\"h-3 w-3\" />\n {dateLabel}\n </span>\n )}\n </div>\n {jobTitle && <p className=\"text-body-sm mt-0.5 font-body text-ods-text-secondary\">{jobTitle}</p>}\n {formattedBio ? (\n <p className=\"text-body-md mt-2 font-body leading-relaxed text-ods-text-secondary\">{formattedBio}</p>\n ) : fallbackBio ? (\n <p className=\"text-body-md mt-2 font-body italic text-ods-text-secondary\">{fallbackBio}</p>\n ) : null}\n </div>\n </div>\n );\n}\n"]}
@@ -7,7 +7,7 @@ import {
7
7
  StatusFilterComponent,
8
8
  TASK_TYPE_LABELS,
9
9
  TASK_TYPE_TEXT_COLORS
10
- } from "./chunk-PBS4F534.js";
10
+ } from "./chunk-NP3XN6ZX.js";
11
11
  import {
12
12
  usePathname,
13
13
  useRouter,
@@ -17,7 +17,7 @@ import {
17
17
  AvatarStack,
18
18
  StatusBadge,
19
19
  getStatusColorScheme
20
- } from "./chunk-SIRFPFBQ.js";
20
+ } from "./chunk-JQI726T3.js";
21
21
  import {
22
22
  next_link_default
23
23
  } from "./chunk-BTROSBHF.js";
@@ -267,4 +267,4 @@ export {
267
267
  DevCardRowSkeletonList,
268
268
  DeliveryRow
269
269
  };
270
- //# sourceMappingURL=chunk-WVKRSC65.js.map
270
+ //# sourceMappingURL=chunk-RNUH5IHZ.js.map
@@ -7,7 +7,7 @@ import {
7
7
  SelectTrigger,
8
8
  SelectValue,
9
9
  Textarea
10
- } from "./chunk-PBS4F534.js";
10
+ } from "./chunk-NP3XN6ZX.js";
11
11
  import {
12
12
  useContactSubmission,
13
13
  useHumanitySignals
@@ -20,13 +20,13 @@ import {
20
20
  ChatAttachmentChipStrip,
21
21
  SECTION_HEADING_CLASS,
22
22
  useChatAttachments
23
- } from "./chunk-42PQFBUS.js";
23
+ } from "./chunk-4D2BR756.js";
24
24
  import {
25
25
  Label
26
26
  } from "./chunk-U5M5DXYT.js";
27
27
  import {
28
28
  Button
29
- } from "./chunk-7GLY26JF.js";
29
+ } from "./chunk-LHR6AA65.js";
30
30
 
31
31
  // src/components/contact/contact-form.tsx
32
32
  import { zodResolver } from "@hookform/resolvers/zod";
@@ -369,4 +369,4 @@ function ContactForm({
369
369
  export {
370
370
  ContactForm
371
371
  };
372
- //# sourceMappingURL=chunk-2IK6SB6F.js.map
372
+ //# sourceMappingURL=chunk-RSMUAAPW.js.map
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  DEFAULT_FOLDER_INDEX_FILE
4
- } from "./chunk-PBS4F534.js";
4
+ } from "./chunk-NP3XN6ZX.js";
5
5
  import {
6
6
  scrollElementIntoView
7
7
  } from "./chunk-W6JA6SFD.js";
@@ -357,4 +357,4 @@ export {
357
357
  MultiLevelNavigation,
358
358
  MobileNavigationDropdown
359
359
  };
360
- //# sourceMappingURL=chunk-KSKCQ3ZN.js.map
360
+ //# sourceMappingURL=chunk-RUJKOU5F.js.map
@@ -1,7 +1,7 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});"use client";
2
2
 
3
3
 
4
- var _chunk7Z64COGDcjs = require('./chunk-7Z64COGD.cjs');
4
+ var _chunk72OIVRPGcjs = require('./chunk-72OIVRPG.cjs');
5
5
 
6
6
 
7
7
 
@@ -9,7 +9,7 @@ var _chunk7Z64COGDcjs = require('./chunk-7Z64COGD.cjs');
9
9
  var _chunkSADRZ4YIcjs = require('./chunk-SADRZ4YI.cjs');
10
10
 
11
11
 
12
- var _chunkS6LZN66Dcjs = require('./chunk-S6LZN66D.cjs');
12
+ var _chunkYHNIPSG6cjs = require('./chunk-YHNIPSG6.cjs');
13
13
 
14
14
  // src/components/empty-state.tsx
15
15
  var _lucidereact = require('lucide-react');
@@ -127,10 +127,10 @@ function EmptyState({
127
127
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mb-3 flex items-center justify-center md:mb-6", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "rounded-full border border-ods-border bg-ods-card p-3 md:p-6", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-8 w-8 items-center justify-center text-ods-text-secondary md:h-16 md:w-16", children: defaultContent.icon }) }) }),
128
128
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "mb-2 text-ods-text-primary text-h3 md:mb-3", children: displayTitle }),
129
129
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "mb-4 max-w-md text-ods-text-secondary text-h6 md:mb-8", children: displayDescription }),
130
- showCTA && ctaHref && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mb-3 w-full max-w-xs", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkS6LZN66Dcjs.Button, { href: ctaHref, className: ctaClassName, children: ctaText || "Contact us" }) }),
131
- showCTA && !ctaHref && smartCTA && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mb-3 w-full max-w-xs", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkS6LZN66Dcjs.Button, { onClick: smartCTA.action, className: ctaClassName, children: smartCTA.text }) }),
130
+ showCTA && ctaHref && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mb-3 w-full max-w-xs", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYHNIPSG6cjs.Button, { href: ctaHref, className: ctaClassName, children: ctaText || "Contact us" }) }),
131
+ showCTA && !ctaHref && smartCTA && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mb-3 w-full max-w-xs", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYHNIPSG6cjs.Button, { onClick: smartCTA.action, className: ctaClassName, children: smartCTA.text }) }),
132
132
  showBackButton && onGoBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-full max-w-xs", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
133
- _chunkS6LZN66Dcjs.Button,
133
+ _chunkYHNIPSG6cjs.Button,
134
134
  {
135
135
  onClick: onGoBack,
136
136
  variant: "outline",
@@ -169,11 +169,11 @@ function UnifiedPagination({
169
169
  }, 0);
170
170
  };
171
171
  if (totalPages <= 1) return null;
172
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk7Z64COGDcjs.Pagination, { currentPage, totalPages, onPageChange: handlePageChange }) });
172
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk72OIVRPGcjs.Pagination, { currentPage, totalPages, onPageChange: handlePageChange }) });
173
173
  }
174
174
 
175
175
 
176
176
 
177
177
 
178
178
  exports.EmptyState = EmptyState; exports.UnifiedPagination = UnifiedPagination;
179
- //# sourceMappingURL=chunk-VIAZWBZ2.cjs.map
179
+ //# sourceMappingURL=chunk-S4CLML75.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-VIAZWBZ2.cjs","../src/components/empty-state.tsx","../src/components/unified-pagination.tsx"],"names":["jsx"],"mappings":"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","file":"/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-VIAZWBZ2.cjs","sourcesContent":[null,"'use client';\n\nimport { Search, FileText, Package } from 'lucide-react';\nimport { useRouter } from '../embed-shims/next-navigation';\nimport { Button } from './ui/button';\n\nexport interface EmptyStateProps {\n type: 'vendors' | 'posts' | 'search' | 'generic';\n title?: string;\n description?: string;\n showBackButton?: boolean;\n onGoBack?: () => void;\n backButtonText?: string;\n // New CTA properties\n showCTA?: boolean;\n ctaText?: string;\n onCtaClick?: () => void;\n /**\n * Link-CTA mode: render the CTA as a navigation link (`href` — plain or\n * `mailto:`). Wins over `onCtaClick`, and SHORT-CIRCUITS the smart-CTA\n * path-sniffing below (which reads `window.location.pathname` — an\n * SSR/client divergence server-rendered pages must never enter).\n */\n ctaHref?: string;\n ctaVariant?: 'primary' | 'secondary';\n}\n\nexport function EmptyState({\n type,\n title,\n description,\n showBackButton = false,\n onGoBack,\n backButtonText = 'Go Back',\n showCTA = true,\n ctaText,\n onCtaClick,\n ctaHref,\n ctaVariant = 'primary',\n}: EmptyStateProps) {\n const router = useRouter();\n\n // Default content based on type\n const getDefaultContent = () => {\n switch (type) {\n case 'vendors':\n return {\n icon: <Package className=\"h-full w-full\" />,\n title: 'No vendors found',\n description:\n \"We couldn't find any vendors matching your criteria. Try adjusting your filters or search terms.\",\n };\n case 'posts':\n return {\n icon: <FileText className=\"h-full w-full\" />,\n title: 'No articles found',\n description:\n \"We couldn't find any articles matching your criteria. Try different categories, tags, or search terms.\",\n };\n case 'search':\n return {\n icon: <Search className=\"h-full w-full\" />,\n title: 'No results found',\n description: \"Your search didn't return any results. Try different keywords or browse our categories.\",\n };\n default:\n return {\n icon: <Search className=\"h-full w-full\" />,\n title: 'Nothing found',\n description: \"We couldn't find what you're looking for. Try adjusting your search or filters.\",\n };\n }\n };\n\n // Smart CTA logic based on context\n const getSmartCTA = () => {\n // If custom CTA is provided, use it\n if (ctaText && onCtaClick) {\n return {\n text: ctaText,\n action: onCtaClick,\n };\n }\n\n // Check if we're on the client side\n const isClient = typeof window !== 'undefined';\n const currentPath = isClient ? window.location.pathname : '';\n\n // Surgical filter reset (promoted from the hub's diverged clone during\n // the EmptyState convergence): delete ONLY the filter params the surface\n // owns — nuking the whole query string threw away unrelated state — and\n // use `replace` with `scroll: false` so resetting filters neither adds a\n // history entry nor jumps the page.\n const resetParams = (paramsToDelete: string[]) => {\n if (!isClient) return;\n const params = new URLSearchParams(window.location.search);\n for (const p of paramsToDelete) params.delete(p);\n const queryString = params.toString();\n // Keep the hash — a filter reset must not clear an unrelated\n // deep-link anchor (e.g. #delivery-123).\n const hash = window.location.hash;\n router.replace(`${window.location.pathname}${queryString ? `?${queryString}` : ''}${hash}`, { scroll: false });\n };\n\n // Smart defaults based on type and context\n switch (type) {\n case 'search':\n return {\n text: 'Reset Filters',\n action: () => resetParams(['search', 'page']),\n };\n case 'posts':\n // Blog-style listing pages (blog, case studies) reset their filters\n if (currentPath.includes('/blog') || currentPath.includes('/case-studies')) {\n return {\n text: 'Reset Filters',\n action: () => resetParams(['search', 'page', 'category', 'tags']),\n };\n } else if (currentPath.includes('/profile')) {\n return {\n text: 'Browse Vendors',\n action: () => router.push('/vendors'),\n };\n }\n return {\n text: 'View All Posts',\n action: () => router.push('/blog'),\n };\n case 'vendors':\n // If we're in profile or other pages, direct to main content\n if (currentPath.includes('/profile')) {\n return {\n text: 'Browse Vendors',\n action: () => router.push('/vendors'),\n };\n } else if (currentPath.includes('/vendors') || currentPath.includes('/margin-increase/compare')) {\n return {\n text: 'Reset Filters',\n action: () => resetParams(['search', 'page', 'category', 'subcategory']),\n };\n }\n return {\n text: 'Browse Vendors',\n action: () => router.push('/vendors'),\n };\n default:\n return {\n text: 'Browse Vendors',\n action: () => router.push('/vendors'),\n };\n }\n };\n\n const defaultContent = getDefaultContent();\n const displayTitle = title || defaultContent.title;\n const displayDescription = description || defaultContent.description;\n // ctaHref short-circuits BEFORE getSmartCTA(): the smart defaults read\n // window.location.pathname (SSR-empty, client-real), so a server-rendered\n // page with a link CTA must never enter that branch. Existing callers\n // without ctaHref keep today's smart-default behavior unchanged.\n const smartCTA = ctaHref ? null : getSmartCTA();\n const ctaClassName =\n ctaVariant === 'primary'\n ? 'w-full bg-ods-accent text-ods-text-on-accent hover:bg-ods-accent-hover transition-all duration-150 font-body font-medium'\n : 'w-full bg-transparent border border-ods-border text-ods-text-primary hover:border-ods-accent hover:text-ods-accent transition-all duration-150 font-body font-medium';\n\n return (\n <div className=\"flex flex-col items-center justify-center px-6 py-6 text-center md:py-16\">\n {/* Icon */}\n <div className=\"mb-3 flex items-center justify-center md:mb-6\">\n <div className=\"rounded-full border border-ods-border bg-ods-card p-3 md:p-6\">\n <div className=\"flex h-8 w-8 items-center justify-center text-ods-text-secondary md:h-16 md:w-16\">\n {defaultContent.icon}\n </div>\n </div>\n </div>\n\n {/* Title */}\n <h2 className=\"mb-2 text-ods-text-primary text-h3 md:mb-3\">{displayTitle}</h2>\n\n {/* Description */}\n <p className=\"mb-4 max-w-md text-ods-text-secondary text-h6 md:mb-8\">{displayDescription}</p>\n\n {/* Link CTA (ctaHref) — SSR-safe, no path sniffing */}\n {showCTA && ctaHref && (\n <div className=\"mb-3 w-full max-w-xs\">\n <Button href={ctaHref} className={ctaClassName}>\n {ctaText || 'Contact us'}\n </Button>\n </div>\n )}\n\n {/* Smart CTA Button */}\n {showCTA && !ctaHref && smartCTA && (\n <div className=\"mb-3 w-full max-w-xs\">\n <Button onClick={smartCTA.action} className={ctaClassName}>\n {smartCTA.text}\n </Button>\n </div>\n )}\n\n {/* Optional Back Button */}\n {showBackButton && onGoBack && (\n <div className=\"w-full max-w-xs\">\n <Button\n onClick={onGoBack}\n variant=\"outline\"\n className=\"w-full font-body font-medium transition-all duration-150\"\n >\n {backButtonText}\n </Button>\n </div>\n )}\n </div>\n );\n}\n","'use client';\n\nimport { useSearchParams, usePathname } from '../embed-shims/next-navigation';\nimport { Pagination } from './pagination';\n\ninterface UnifiedPaginationProps {\n currentPage: number;\n totalPages: number;\n onPageChange?: (page: number) => void;\n className?: string;\n}\n\nexport function UnifiedPagination({\n currentPage,\n totalPages,\n onPageChange,\n className = 'mt-8 flex justify-center w-full',\n}: UnifiedPaginationProps) {\n const searchParams = useSearchParams();\n const pathname = usePathname();\n\n const handlePageChange = (page: number) => {\n // Preserve current scroll position\n const currentScrollY = window.scrollY;\n\n // Call the callback to update local state (prevents reload)\n if (onPageChange) {\n onPageChange(page);\n }\n\n // Update URL for bookmarking without navigation\n const params = new URLSearchParams(searchParams.toString());\n params.set('page', page.toString());\n\n // Update URL without navigation (for bookmarking support)\n const newUrl = `${pathname}?${params.toString()}`;\n window.history.replaceState(null, '', newUrl);\n\n // Restore scroll position after a brief delay to allow content to render\n setTimeout(() => {\n window.scrollTo({\n top: currentScrollY,\n behavior: 'instant', // Instant to prevent any scroll animation\n });\n }, 0);\n };\n\n // Don't render pagination if there's only one page\n if (totalPages <= 1) return null;\n\n return (\n <div className={className}>\n <Pagination currentPage={currentPage} totalPages={totalPages} onPageChange={handlePageChange} />\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-S4CLML75.cjs","../src/components/empty-state.tsx","../src/components/unified-pagination.tsx"],"names":["jsx"],"mappings":"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","file":"/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-S4CLML75.cjs","sourcesContent":[null,"'use client';\n\nimport { Search, FileText, Package } from 'lucide-react';\nimport { useRouter } from '../embed-shims/next-navigation';\nimport { Button } from './ui/button';\n\nexport interface EmptyStateProps {\n type: 'vendors' | 'posts' | 'search' | 'generic';\n title?: string;\n description?: string;\n showBackButton?: boolean;\n onGoBack?: () => void;\n backButtonText?: string;\n // New CTA properties\n showCTA?: boolean;\n ctaText?: string;\n onCtaClick?: () => void;\n /**\n * Link-CTA mode: render the CTA as a navigation link (`href` — plain or\n * `mailto:`). Wins over `onCtaClick`, and SHORT-CIRCUITS the smart-CTA\n * path-sniffing below (which reads `window.location.pathname` — an\n * SSR/client divergence server-rendered pages must never enter).\n */\n ctaHref?: string;\n ctaVariant?: 'primary' | 'secondary';\n}\n\nexport function EmptyState({\n type,\n title,\n description,\n showBackButton = false,\n onGoBack,\n backButtonText = 'Go Back',\n showCTA = true,\n ctaText,\n onCtaClick,\n ctaHref,\n ctaVariant = 'primary',\n}: EmptyStateProps) {\n const router = useRouter();\n\n // Default content based on type\n const getDefaultContent = () => {\n switch (type) {\n case 'vendors':\n return {\n icon: <Package className=\"h-full w-full\" />,\n title: 'No vendors found',\n description:\n \"We couldn't find any vendors matching your criteria. Try adjusting your filters or search terms.\",\n };\n case 'posts':\n return {\n icon: <FileText className=\"h-full w-full\" />,\n title: 'No articles found',\n description:\n \"We couldn't find any articles matching your criteria. Try different categories, tags, or search terms.\",\n };\n case 'search':\n return {\n icon: <Search className=\"h-full w-full\" />,\n title: 'No results found',\n description: \"Your search didn't return any results. Try different keywords or browse our categories.\",\n };\n default:\n return {\n icon: <Search className=\"h-full w-full\" />,\n title: 'Nothing found',\n description: \"We couldn't find what you're looking for. Try adjusting your search or filters.\",\n };\n }\n };\n\n // Smart CTA logic based on context\n const getSmartCTA = () => {\n // If custom CTA is provided, use it\n if (ctaText && onCtaClick) {\n return {\n text: ctaText,\n action: onCtaClick,\n };\n }\n\n // Check if we're on the client side\n const isClient = typeof window !== 'undefined';\n const currentPath = isClient ? window.location.pathname : '';\n\n // Surgical filter reset (promoted from the hub's diverged clone during\n // the EmptyState convergence): delete ONLY the filter params the surface\n // owns — nuking the whole query string threw away unrelated state — and\n // use `replace` with `scroll: false` so resetting filters neither adds a\n // history entry nor jumps the page.\n const resetParams = (paramsToDelete: string[]) => {\n if (!isClient) return;\n const params = new URLSearchParams(window.location.search);\n for (const p of paramsToDelete) params.delete(p);\n const queryString = params.toString();\n // Keep the hash — a filter reset must not clear an unrelated\n // deep-link anchor (e.g. #delivery-123).\n const hash = window.location.hash;\n router.replace(`${window.location.pathname}${queryString ? `?${queryString}` : ''}${hash}`, { scroll: false });\n };\n\n // Smart defaults based on type and context\n switch (type) {\n case 'search':\n return {\n text: 'Reset Filters',\n action: () => resetParams(['search', 'page']),\n };\n case 'posts':\n // Blog-style listing pages (blog, case studies) reset their filters\n if (currentPath.includes('/blog') || currentPath.includes('/case-studies')) {\n return {\n text: 'Reset Filters',\n action: () => resetParams(['search', 'page', 'category', 'tags']),\n };\n } else if (currentPath.includes('/profile')) {\n return {\n text: 'Browse Vendors',\n action: () => router.push('/vendors'),\n };\n }\n return {\n text: 'View All Posts',\n action: () => router.push('/blog'),\n };\n case 'vendors':\n // If we're in profile or other pages, direct to main content\n if (currentPath.includes('/profile')) {\n return {\n text: 'Browse Vendors',\n action: () => router.push('/vendors'),\n };\n } else if (currentPath.includes('/vendors') || currentPath.includes('/margin-increase/compare')) {\n return {\n text: 'Reset Filters',\n action: () => resetParams(['search', 'page', 'category', 'subcategory']),\n };\n }\n return {\n text: 'Browse Vendors',\n action: () => router.push('/vendors'),\n };\n default:\n return {\n text: 'Browse Vendors',\n action: () => router.push('/vendors'),\n };\n }\n };\n\n const defaultContent = getDefaultContent();\n const displayTitle = title || defaultContent.title;\n const displayDescription = description || defaultContent.description;\n // ctaHref short-circuits BEFORE getSmartCTA(): the smart defaults read\n // window.location.pathname (SSR-empty, client-real), so a server-rendered\n // page with a link CTA must never enter that branch. Existing callers\n // without ctaHref keep today's smart-default behavior unchanged.\n const smartCTA = ctaHref ? null : getSmartCTA();\n const ctaClassName =\n ctaVariant === 'primary'\n ? 'w-full bg-ods-accent text-ods-text-on-accent hover:bg-ods-accent-hover transition-all duration-150 font-body font-medium'\n : 'w-full bg-transparent border border-ods-border text-ods-text-primary hover:border-ods-accent hover:text-ods-accent transition-all duration-150 font-body font-medium';\n\n return (\n <div className=\"flex flex-col items-center justify-center px-6 py-6 text-center md:py-16\">\n {/* Icon */}\n <div className=\"mb-3 flex items-center justify-center md:mb-6\">\n <div className=\"rounded-full border border-ods-border bg-ods-card p-3 md:p-6\">\n <div className=\"flex h-8 w-8 items-center justify-center text-ods-text-secondary md:h-16 md:w-16\">\n {defaultContent.icon}\n </div>\n </div>\n </div>\n\n {/* Title */}\n <h2 className=\"mb-2 text-ods-text-primary text-h3 md:mb-3\">{displayTitle}</h2>\n\n {/* Description */}\n <p className=\"mb-4 max-w-md text-ods-text-secondary text-h6 md:mb-8\">{displayDescription}</p>\n\n {/* Link CTA (ctaHref) — SSR-safe, no path sniffing */}\n {showCTA && ctaHref && (\n <div className=\"mb-3 w-full max-w-xs\">\n <Button href={ctaHref} className={ctaClassName}>\n {ctaText || 'Contact us'}\n </Button>\n </div>\n )}\n\n {/* Smart CTA Button */}\n {showCTA && !ctaHref && smartCTA && (\n <div className=\"mb-3 w-full max-w-xs\">\n <Button onClick={smartCTA.action} className={ctaClassName}>\n {smartCTA.text}\n </Button>\n </div>\n )}\n\n {/* Optional Back Button */}\n {showBackButton && onGoBack && (\n <div className=\"w-full max-w-xs\">\n <Button\n onClick={onGoBack}\n variant=\"outline\"\n className=\"w-full font-body font-medium transition-all duration-150\"\n >\n {backButtonText}\n </Button>\n </div>\n )}\n </div>\n );\n}\n","'use client';\n\nimport { useSearchParams, usePathname } from '../embed-shims/next-navigation';\nimport { Pagination } from './pagination';\n\ninterface UnifiedPaginationProps {\n currentPage: number;\n totalPages: number;\n onPageChange?: (page: number) => void;\n className?: string;\n}\n\nexport function UnifiedPagination({\n currentPage,\n totalPages,\n onPageChange,\n className = 'mt-8 flex justify-center w-full',\n}: UnifiedPaginationProps) {\n const searchParams = useSearchParams();\n const pathname = usePathname();\n\n const handlePageChange = (page: number) => {\n // Preserve current scroll position\n const currentScrollY = window.scrollY;\n\n // Call the callback to update local state (prevents reload)\n if (onPageChange) {\n onPageChange(page);\n }\n\n // Update URL for bookmarking without navigation\n const params = new URLSearchParams(searchParams.toString());\n params.set('page', page.toString());\n\n // Update URL without navigation (for bookmarking support)\n const newUrl = `${pathname}?${params.toString()}`;\n window.history.replaceState(null, '', newUrl);\n\n // Restore scroll position after a brief delay to allow content to render\n setTimeout(() => {\n window.scrollTo({\n top: currentScrollY,\n behavior: 'instant', // Instant to prevent any scroll animation\n });\n }, 0);\n };\n\n // Don't render pagination if there's only one page\n if (totalPages <= 1) return null;\n\n return (\n <div className={className}>\n <Pagination currentPage={currentPage} totalPages={totalPages} onPageChange={handlePageChange} />\n </div>\n );\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  useOptionalTicketLive
4
- } from "./chunk-IWISKP3F.js";
4
+ } from "./chunk-FCVAVOXS.js";
5
5
  import {
6
6
  AppLayoutDrawerContainerContext,
7
7
  AppLayoutDrawerCoordinationContext,
@@ -12,7 +12,7 @@ import {
12
12
  UnreadDot,
13
13
  buildTicketOpenHref,
14
14
  useOptionalNotifications
15
- } from "./chunk-PBS4F534.js";
15
+ } from "./chunk-NP3XN6ZX.js";
16
16
  import {
17
17
  useFocusTrap,
18
18
  useLocalStorage
@@ -20,7 +20,7 @@ import {
20
20
  import {
21
21
  OVERLAY_BACKDROP_CLASS,
22
22
  useIsHydrated
23
- } from "./chunk-42PQFBUS.js";
23
+ } from "./chunk-4D2BR756.js";
24
24
  import {
25
25
  useHeaderHeight,
26
26
  useIsomorphicLayoutEffect,
@@ -46,7 +46,7 @@ import {
46
46
  } from "./chunk-IMDG23LW.js";
47
47
  import {
48
48
  SquareAvatar
49
- } from "./chunk-SIRFPFBQ.js";
49
+ } from "./chunk-JQI726T3.js";
50
50
  import {
51
51
  OpenFrameLogo
52
52
  } from "./chunk-OTX6XNSA.js";
@@ -61,7 +61,7 @@ import {
61
61
  } from "./chunk-6U3IUD57.js";
62
62
  import {
63
63
  Button
64
- } from "./chunk-7GLY26JF.js";
64
+ } from "./chunk-LHR6AA65.js";
65
65
  import {
66
66
  next_link_default
67
67
  } from "./chunk-BTROSBHF.js";
@@ -1878,4 +1878,4 @@ export {
1878
1878
  MobileBurgerMenu,
1879
1879
  AppLayout
1880
1880
  };
1881
- //# sourceMappingURL=chunk-WAWMZSCP.js.map
1881
+ //# sourceMappingURL=chunk-THDGDYJ3.js.map
@@ -3,16 +3,16 @@ import {
3
3
  FileDownloadCard,
4
4
  GoogleSheetsViewer,
5
5
  PdfViewer
6
- } from "./chunk-ISULYCGY.js";
6
+ } from "./chunk-ZBJ6XSDO.js";
7
7
  import {
8
8
  MobileNavigationDropdown,
9
9
  MultiLevelNavigation,
10
10
  StickySectionNav
11
- } from "./chunk-KSKCQ3ZN.js";
11
+ } from "./chunk-RUJKOU5F.js";
12
12
  import {
13
13
  DocSearchBar,
14
14
  useDocSearch
15
- } from "./chunk-BTZF3JRS.js";
15
+ } from "./chunk-4KR7JWKB.js";
16
16
  import {
17
17
  DEFAULT_FOLDER_INDEX_FILE,
18
18
  FigmaEmbed,
@@ -21,7 +21,7 @@ import {
21
21
  findDocNodeByPath,
22
22
  getDocAncestorNodeIds,
23
23
  stripFolderIndexFromPath
24
- } from "./chunk-PBS4F534.js";
24
+ } from "./chunk-NP3XN6ZX.js";
25
25
  import {
26
26
  apiErrorMessage
27
27
  } from "./chunk-HM2R5MDR.js";
@@ -1864,4 +1864,4 @@ export {
1864
1864
  EmbedSkeleton,
1865
1865
  DocsHubPage
1866
1866
  };
1867
- //# sourceMappingURL=chunk-KG7D35RU.js.map
1867
+ //# sourceMappingURL=chunk-TU32TSAK.js.map
@@ -4,7 +4,7 @@ import {
4
4
  getOSLabel,
5
5
  getShellLabel,
6
6
  getToolLabel
7
- } from "./chunk-PBS4F534.js";
7
+ } from "./chunk-NP3XN6ZX.js";
8
8
  import {
9
9
  cn as cn2,
10
10
  useOnboardingState
@@ -14,7 +14,7 @@ import {
14
14
  } from "./chunk-PQETCTJ4.js";
15
15
  import {
16
16
  SECTION_HEADING_CLASS
17
- } from "./chunk-42PQFBUS.js";
17
+ } from "./chunk-4D2BR756.js";
18
18
  import {
19
19
  ToolIcon
20
20
  } from "./chunk-W6JA6SFD.js";
@@ -38,7 +38,7 @@ import {
38
38
  import {
39
39
  InteractiveCard,
40
40
  StatusBadge
41
- } from "./chunk-SIRFPFBQ.js";
41
+ } from "./chunk-JQI726T3.js";
42
42
  import {
43
43
  next_image_default
44
44
  } from "./chunk-MDKCTSDS.js";
@@ -47,7 +47,7 @@ import {
47
47
  } from "./chunk-U5M5DXYT.js";
48
48
  import {
49
49
  Button
50
- } from "./chunk-7GLY26JF.js";
50
+ } from "./chunk-LHR6AA65.js";
51
51
  import {
52
52
  cn
53
53
  } from "./chunk-4CTHP7E5.js";
@@ -530,4 +530,4 @@ export {
530
530
  OnboardingStepCard,
531
531
  OnboardingWalkthrough
532
532
  };
533
- //# sourceMappingURL=chunk-5QDGP3RI.js.map
533
+ //# sourceMappingURL=chunk-U3SDSA5K.js.map