@slashclick/ui 0.1.16 → 0.2.0

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 (223) hide show
  1. package/README.md +108 -108
  2. package/dist/components/auth/providers.cjs.map +1 -1
  3. package/dist/components/auth/providers.js.map +1 -1
  4. package/dist/components/card/back-button.cjs.map +1 -1
  5. package/dist/components/card/back-button.js.map +1 -1
  6. package/dist/components/card/card-wrapper.cjs.map +1 -1
  7. package/dist/components/card/card-wrapper.js.map +1 -1
  8. package/dist/components/card/header.cjs.map +1 -1
  9. package/dist/components/card/header.js.map +1 -1
  10. package/dist/components/combobox/ComboList.cjs.map +1 -1
  11. package/dist/components/combobox/ComboList.js.map +1 -1
  12. package/dist/components/combobox/index.cjs.map +1 -1
  13. package/dist/components/combobox/index.js.map +1 -1
  14. package/dist/components/dashboard/account-select.cjs.map +1 -1
  15. package/dist/components/dashboard/account-select.js.map +1 -1
  16. package/dist/components/dashboard/account-switcher.cjs.map +1 -1
  17. package/dist/components/dashboard/account-switcher.js.map +1 -1
  18. package/dist/components/dashboard/sidebar/CollapsibleSection.cjs.map +1 -1
  19. package/dist/components/dashboard/sidebar/CollapsibleSection.js.map +1 -1
  20. package/dist/components/dashboard/sidebar/CollapsibleSection.styles.cjs.map +1 -1
  21. package/dist/components/dashboard/sidebar/CollapsibleSection.styles.js.map +1 -1
  22. package/dist/components/dashboard/sidebar/EntityList.cjs.map +1 -1
  23. package/dist/components/dashboard/sidebar/EntityList.js.map +1 -1
  24. package/dist/components/dashboard/sidebar/EntityList.styles.cjs.map +1 -1
  25. package/dist/components/dashboard/sidebar/EntityList.styles.js.map +1 -1
  26. package/dist/components/dashboard/sidebar/SectionHeader.cjs.map +1 -1
  27. package/dist/components/dashboard/sidebar/SectionHeader.js.map +1 -1
  28. package/dist/components/dashboard/sidebar/SectionHeader.styles.cjs.map +1 -1
  29. package/dist/components/dashboard/sidebar/SectionHeader.styles.js.map +1 -1
  30. package/dist/components/dashboard/sidebar/index.cjs.map +1 -1
  31. package/dist/components/dashboard/sidebar/index.js.map +1 -1
  32. package/dist/components/dashboard/sidebar/sidebar.cjs.map +1 -1
  33. package/dist/components/dashboard/sidebar/sidebar.js.map +1 -1
  34. package/dist/components/dashboard/sidebar/tabs.cjs.map +1 -1
  35. package/dist/components/dashboard/sidebar/tabs.js.map +1 -1
  36. package/dist/components/dashboard/sidebar/types.cjs.map +1 -1
  37. package/dist/components/dashboard/sidebar-nav.cjs.map +1 -1
  38. package/dist/components/dashboard/sidebar-nav.js.map +1 -1
  39. package/dist/components/dashboard/utils/build-nav.cjs.map +1 -1
  40. package/dist/components/dashboard/utils/build-nav.js.map +1 -1
  41. package/dist/components/dashboard/with-dashboard.cjs.map +1 -1
  42. package/dist/components/dashboard/with-dashboard.js.map +1 -1
  43. package/dist/components/detail/DetailLayout.styles.cjs.map +1 -1
  44. package/dist/components/detail/DetailLayout.styles.js.map +1 -1
  45. package/dist/components/detail/index.cjs.map +1 -1
  46. package/dist/components/detail/index.js.map +1 -1
  47. package/dist/components/flowbite/card-images.cjs.map +1 -1
  48. package/dist/components/flowbite/card-images.js.map +1 -1
  49. package/dist/components/flowbite/gallery.cjs.map +1 -1
  50. package/dist/components/flowbite/gallery.js.map +1 -1
  51. package/dist/components/flowbite/masonry.cjs.map +1 -1
  52. package/dist/components/flowbite/masonry.js.map +1 -1
  53. package/dist/components/flowbite/search-hero.cjs +3 -3
  54. package/dist/components/flowbite/search-hero.cjs.map +1 -1
  55. package/dist/components/flowbite/search-hero.js +3 -3
  56. package/dist/components/flowbite/search-hero.js.map +1 -1
  57. package/dist/components/generic/copyright.cjs.map +1 -1
  58. package/dist/components/generic/copyright.js.map +1 -1
  59. package/dist/components/generic/icons.cjs.map +1 -1
  60. package/dist/components/generic/icons.js.map +1 -1
  61. package/dist/components/generic/link.cjs.map +1 -1
  62. package/dist/components/generic/link.js.map +1 -1
  63. package/dist/components/header/header.cjs +8 -6
  64. package/dist/components/header/header.cjs.map +1 -1
  65. package/dist/components/header/header.d.ts +4 -1
  66. package/dist/components/header/header.d.ts.map +1 -1
  67. package/dist/components/header/header.js +8 -6
  68. package/dist/components/header/header.js.map +1 -1
  69. package/dist/components/header/internal/main-nav.cjs.map +1 -1
  70. package/dist/components/header/internal/main-nav.js.map +1 -1
  71. package/dist/components/header/internal/mobile-nav.cjs.map +1 -1
  72. package/dist/components/header/internal/mobile-nav.js.map +1 -1
  73. package/dist/components/header/internal/mode-toggle.cjs.map +1 -1
  74. package/dist/components/header/internal/mode-toggle.js.map +1 -1
  75. package/dist/components/header/internal/site-header.cjs.map +1 -1
  76. package/dist/components/header/internal/site-header.js.map +1 -1
  77. package/dist/components/header/langbutton/langbutton.cjs +17 -5
  78. package/dist/components/header/langbutton/langbutton.cjs.map +1 -1
  79. package/dist/components/header/langbutton/langbutton.d.ts +3 -1
  80. package/dist/components/header/langbutton/langbutton.d.ts.map +1 -1
  81. package/dist/components/header/langbutton/langbutton.js +17 -5
  82. package/dist/components/header/langbutton/langbutton.js.map +1 -1
  83. package/dist/components/header/userbutton/user-dropdown.cjs.map +1 -1
  84. package/dist/components/header/userbutton/user-dropdown.js.map +1 -1
  85. package/dist/components/header/userbutton/userbutton.cjs +14 -5
  86. package/dist/components/header/userbutton/userbutton.cjs.map +1 -1
  87. package/dist/components/header/userbutton/userbutton.d.ts +3 -1
  88. package/dist/components/header/userbutton/userbutton.d.ts.map +1 -1
  89. package/dist/components/header/userbutton/userbutton.js +14 -5
  90. package/dist/components/header/userbutton/userbutton.js.map +1 -1
  91. package/dist/components/hooks/use-page-nav.cjs.map +1 -1
  92. package/dist/components/hooks/use-page-nav.js.map +1 -1
  93. package/dist/components/hooks/use-user-entities.cjs.map +1 -1
  94. package/dist/components/hooks/use-user-entities.js.map +1 -1
  95. package/dist/components/icons/apple.cjs.map +1 -1
  96. package/dist/components/icons/apple.js.map +1 -1
  97. package/dist/components/icons/facebook.cjs.map +1 -1
  98. package/dist/components/icons/facebook.js.map +1 -1
  99. package/dist/components/icons/github.cjs.map +1 -1
  100. package/dist/components/icons/github.js.map +1 -1
  101. package/dist/components/icons/google.cjs.map +1 -1
  102. package/dist/components/icons/google.js.map +1 -1
  103. package/dist/components/icons/logo.cjs +6 -2
  104. package/dist/components/icons/logo.cjs.map +1 -1
  105. package/dist/components/icons/logo.d.ts +3 -1
  106. package/dist/components/icons/logo.d.ts.map +1 -1
  107. package/dist/components/icons/logo.js +6 -2
  108. package/dist/components/icons/logo.js.map +1 -1
  109. package/dist/components/lightbox/GallerySection.cjs.map +1 -1
  110. package/dist/components/lightbox/GallerySection.js.map +1 -1
  111. package/dist/components/lightbox/ImageLightbox.cjs.map +1 -1
  112. package/dist/components/lightbox/ImageLightbox.js.map +1 -1
  113. package/dist/components/lightbox/ImageLightbox.types.cjs.map +1 -1
  114. package/dist/components/lightbox/index.cjs.map +1 -1
  115. package/dist/components/lightbox/index.js.map +1 -1
  116. package/dist/components/lightbox/useEntityLightbox.cjs.map +1 -1
  117. package/dist/components/lightbox/useEntityLightbox.js.map +1 -1
  118. package/dist/components/lightbox/useLightbox.cjs.map +1 -1
  119. package/dist/components/lightbox/useLightbox.js.map +1 -1
  120. package/dist/components/search/search.cjs.map +1 -1
  121. package/dist/components/search/search.js.map +1 -1
  122. package/dist/components/tailwind/contact.cjs +6 -6
  123. package/dist/components/tailwind/contact.cjs.map +1 -1
  124. package/dist/components/tailwind/contact.js +6 -6
  125. package/dist/components/tailwind/contact.js.map +1 -1
  126. package/dist/components/tailwind/content-page.cjs.map +1 -1
  127. package/dist/components/tailwind/content-page.js.map +1 -1
  128. package/dist/components/tailwind/feature.cjs.map +1 -1
  129. package/dist/components/tailwind/feature.js.map +1 -1
  130. package/dist/components/tailwind/featurelist.cjs.map +1 -1
  131. package/dist/components/tailwind/featurelist.js.map +1 -1
  132. package/dist/components/tailwind/footer.cjs.map +1 -1
  133. package/dist/components/tailwind/footer.js.map +1 -1
  134. package/dist/components/tailwind/hero.cjs.map +1 -1
  135. package/dist/components/tailwind/hero.js.map +1 -1
  136. package/dist/components/tailwind/pricing.cjs +28 -28
  137. package/dist/components/tailwind/pricing.cjs.map +1 -1
  138. package/dist/components/tailwind/pricing.d.ts.map +1 -1
  139. package/dist/components/tailwind/pricing.js +28 -28
  140. package/dist/components/tailwind/pricing.js.map +1 -1
  141. package/dist/components/tailwind/privacy.cjs.map +1 -1
  142. package/dist/components/tailwind/privacy.js.map +1 -1
  143. package/dist/components/tailwind/providerIcons.cjs.map +1 -1
  144. package/dist/components/tailwind/providerIcons.js.map +1 -1
  145. package/dist/components/ui/avatar.cjs.map +1 -1
  146. package/dist/components/ui/avatar.js.map +1 -1
  147. package/dist/components/ui/breadcrumb.cjs.map +1 -1
  148. package/dist/components/ui/breadcrumb.js.map +1 -1
  149. package/dist/components/ui/button.cjs.map +1 -1
  150. package/dist/components/ui/button.js.map +1 -1
  151. package/dist/components/ui/card.cjs.map +1 -1
  152. package/dist/components/ui/card.js.map +1 -1
  153. package/dist/components/ui/checkbox.cjs.map +1 -1
  154. package/dist/components/ui/checkbox.js.map +1 -1
  155. package/dist/components/ui/command.cjs.map +1 -1
  156. package/dist/components/ui/command.d.ts.map +1 -1
  157. package/dist/components/ui/command.js.map +1 -1
  158. package/dist/components/ui/dialog.cjs.map +1 -1
  159. package/dist/components/ui/dialog.js.map +1 -1
  160. package/dist/components/ui/drawer.cjs.map +1 -1
  161. package/dist/components/ui/drawer.js.map +1 -1
  162. package/dist/components/ui/dropdown-menu.cjs.map +1 -1
  163. package/dist/components/ui/dropdown-menu.js.map +1 -1
  164. package/dist/components/ui/input.cjs.map +1 -1
  165. package/dist/components/ui/input.js.map +1 -1
  166. package/dist/components/ui/label.cjs.map +1 -1
  167. package/dist/components/ui/label.js.map +1 -1
  168. package/dist/components/ui/menubar.cjs.map +1 -1
  169. package/dist/components/ui/menubar.js.map +1 -1
  170. package/dist/components/ui/navigation-menu.cjs.map +1 -1
  171. package/dist/components/ui/navigation-menu.js.map +1 -1
  172. package/dist/components/ui/popover.cjs.map +1 -1
  173. package/dist/components/ui/popover.js.map +1 -1
  174. package/dist/components/ui/resizable.cjs.map +1 -1
  175. package/dist/components/ui/resizable.js.map +1 -1
  176. package/dist/components/ui/scroll-area.cjs.map +1 -1
  177. package/dist/components/ui/scroll-area.js.map +1 -1
  178. package/dist/components/ui/select.cjs.map +1 -1
  179. package/dist/components/ui/select.js.map +1 -1
  180. package/dist/components/ui/sheet.cjs.map +1 -1
  181. package/dist/components/ui/sheet.js.map +1 -1
  182. package/dist/components/ui/skeleton.cjs.map +1 -1
  183. package/dist/components/ui/skeleton.js.map +1 -1
  184. package/dist/components/ui/spinner.cjs.map +1 -1
  185. package/dist/components/ui/spinner.js.map +1 -1
  186. package/dist/components/ui/switch.cjs.map +1 -1
  187. package/dist/components/ui/switch.js.map +1 -1
  188. package/dist/components/ui/tabs.cjs.map +1 -1
  189. package/dist/components/ui/tabs.js.map +1 -1
  190. package/dist/components/ui/textarea.cjs.map +1 -1
  191. package/dist/components/ui/textarea.js.map +1 -1
  192. package/dist/components/ui/toast.cjs.map +1 -1
  193. package/dist/components/ui/toast.js.map +1 -1
  194. package/dist/components/ui/toaster.cjs.map +1 -1
  195. package/dist/components/ui/toaster.js.map +1 -1
  196. package/dist/components/ui/tooltip.cjs.map +1 -1
  197. package/dist/components/ui/tooltip.js.map +1 -1
  198. package/dist/components/ui/use-toast.cjs.map +1 -1
  199. package/dist/components/ui/use-toast.js.map +1 -1
  200. package/dist/components/upgrade-prompt/UpgradePrompt.cjs.map +1 -1
  201. package/dist/components/upgrade-prompt/UpgradePrompt.js.map +1 -1
  202. package/dist/components/upgrade-prompt/index.cjs.map +1 -1
  203. package/dist/components/upgrade-prompt/index.js.map +1 -1
  204. package/dist/hooks/useRecaptcha.cjs.map +1 -1
  205. package/dist/hooks/useRecaptcha.js.map +1 -1
  206. package/dist/lib/nav-theme.cjs +33 -0
  207. package/dist/lib/nav-theme.cjs.map +1 -0
  208. package/dist/lib/nav-theme.d.ts +3 -0
  209. package/dist/lib/nav-theme.d.ts.map +1 -0
  210. package/dist/lib/nav-theme.js +9 -0
  211. package/dist/lib/nav-theme.js.map +1 -0
  212. package/dist/lib/utils.cjs.map +1 -1
  213. package/dist/lib/utils.d.cjs +17 -0
  214. package/dist/lib/utils.d.cjs.map +1 -0
  215. package/dist/lib/utils.d.js +1 -0
  216. package/dist/lib/utils.d.js.map +1 -0
  217. package/dist/lib/utils.js.map +1 -1
  218. package/dist/styles.css +2 -2
  219. package/dist/types/nav.cjs.map +1 -1
  220. package/dist/types/sitemap.cjs.map +1 -1
  221. package/dist/types/unist.cjs.map +1 -1
  222. package/package.json +1 -1
  223. package/styles/theme.css +52 -52
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../components/icons/google.tsx"],"sourcesContent":["export const GoogleIcon = () => {\r\n return (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"18\"\r\n height=\"18\"\r\n fill=\"currentColor\"\r\n className=\"bi bi-google\"\r\n viewBox=\"0 0 16 16\"\r\n >\r\n <path\r\n d=\"M15.545 6.558a9.42 9.42 0 0 1 .139 1.626c0 2.434-.87 4.492-2.384 5.885h.002C11.978 15.292 10.158 16 8 16A8 8 0 1 1 8 0a7.689 7.689 0 0 1 5.352 2.082l-2.284 2.284A4.347 4.347 0 0 0 8 3.166c-2.087 0-3.86 1.408-4.492 3.304a4.792 4.792 0 0 0 0 3.063h.003c.635 1.893 2.405 3.301 4.492 3.301 1.078 0 2.004-.276 2.722-.764h-.003a3.702 3.702 0 0 0 1.599-2.431H8v-3.08h7.545z\"\r\n fill=\"#cbd5e1\"\r\n ></path>\r\n </svg>\r\n )\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAUM;AAVC,MAAM,aAAa,MAAM;AAC9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN,OAAM;AAAA,MACN,QAAO;AAAA,MACP,MAAK;AAAA,MACL,WAAU;AAAA,MACV,SAAQ;AAAA,MAER;AAAA,QAAC;AAAA;AAAA,UACC,GAAE;AAAA,UACF,MAAK;AAAA;AAAA,MACN;AAAA;AAAA,EACH;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../components/icons/google.tsx"],"sourcesContent":["export const GoogleIcon = () => {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"18\"\n height=\"18\"\n fill=\"currentColor\"\n className=\"bi bi-google\"\n viewBox=\"0 0 16 16\"\n >\n <path\n d=\"M15.545 6.558a9.42 9.42 0 0 1 .139 1.626c0 2.434-.87 4.492-2.384 5.885h.002C11.978 15.292 10.158 16 8 16A8 8 0 1 1 8 0a7.689 7.689 0 0 1 5.352 2.082l-2.284 2.284A4.347 4.347 0 0 0 8 3.166c-2.087 0-3.86 1.408-4.492 3.304a4.792 4.792 0 0 0 0 3.063h.003c.635 1.893 2.405 3.301 4.492 3.301 1.078 0 2.004-.276 2.722-.764h-.003a3.702 3.702 0 0 0 1.599-2.431H8v-3.08h7.545z\"\n fill=\"#cbd5e1\"\n ></path>\n </svg>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAUM;AAVC,MAAM,aAAa,MAAM;AAC9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN,OAAM;AAAA,MACN,QAAO;AAAA,MACP,MAAK;AAAA,MACL,WAAU;AAAA,MACV,SAAQ;AAAA,MAER;AAAA,QAAC;AAAA;AAAA,UACC,GAAE;AAAA,UACF,MAAK;AAAA;AAAA,MACN;AAAA;AAAA,EACH;AAEJ;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../components/icons/google.tsx"],"sourcesContent":["export const GoogleIcon = () => {\r\n return (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"18\"\r\n height=\"18\"\r\n fill=\"currentColor\"\r\n className=\"bi bi-google\"\r\n viewBox=\"0 0 16 16\"\r\n >\r\n <path\r\n d=\"M15.545 6.558a9.42 9.42 0 0 1 .139 1.626c0 2.434-.87 4.492-2.384 5.885h.002C11.978 15.292 10.158 16 8 16A8 8 0 1 1 8 0a7.689 7.689 0 0 1 5.352 2.082l-2.284 2.284A4.347 4.347 0 0 0 8 3.166c-2.087 0-3.86 1.408-4.492 3.304a4.792 4.792 0 0 0 0 3.063h.003c.635 1.893 2.405 3.301 4.492 3.301 1.078 0 2.004-.276 2.722-.764h-.003a3.702 3.702 0 0 0 1.599-2.431H8v-3.08h7.545z\"\r\n fill=\"#cbd5e1\"\r\n ></path>\r\n </svg>\r\n )\r\n}\r\n"],"mappings":"AAUM;AAVC,MAAM,aAAa,MAAM;AAC9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN,OAAM;AAAA,MACN,QAAO;AAAA,MACP,MAAK;AAAA,MACL,WAAU;AAAA,MACV,SAAQ;AAAA,MAER;AAAA,QAAC;AAAA;AAAA,UACC,GAAE;AAAA,UACF,MAAK;AAAA;AAAA,MACN;AAAA;AAAA,EACH;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../components/icons/google.tsx"],"sourcesContent":["export const GoogleIcon = () => {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"18\"\n height=\"18\"\n fill=\"currentColor\"\n className=\"bi bi-google\"\n viewBox=\"0 0 16 16\"\n >\n <path\n d=\"M15.545 6.558a9.42 9.42 0 0 1 .139 1.626c0 2.434-.87 4.492-2.384 5.885h.002C11.978 15.292 10.158 16 8 16A8 8 0 1 1 8 0a7.689 7.689 0 0 1 5.352 2.082l-2.284 2.284A4.347 4.347 0 0 0 8 3.166c-2.087 0-3.86 1.408-4.492 3.304a4.792 4.792 0 0 0 0 3.063h.003c.635 1.893 2.405 3.301 4.492 3.301 1.078 0 2.004-.276 2.722-.764h-.003a3.702 3.702 0 0 0 1.599-2.431H8v-3.08h7.545z\"\n fill=\"#cbd5e1\"\n ></path>\n </svg>\n )\n}\n"],"mappings":"AAUM;AAVC,MAAM,aAAa,MAAM;AAC9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN,OAAM;AAAA,MACN,QAAO;AAAA,MACP,MAAK;AAAA,MACL,WAAU;AAAA,MACV,SAAQ;AAAA,MAER;AAAA,QAAC;AAAA;AAAA,UACC,GAAE;AAAA,UACF,MAAK;AAAA;AAAA,MACN;AAAA;AAAA,EACH;AAEJ;","names":[]}
@@ -23,7 +23,11 @@ __export(logo_exports, {
23
23
  module.exports = __toCommonJS(logo_exports);
24
24
  var import_jsx_runtime = require("react/jsx-runtime");
25
25
  var import_utils = require("../../lib/utils");
26
- const Logo = ({ className }) => {
26
+ var import_nav_theme = require("../../lib/nav-theme");
27
+ const Logo = ({
28
+ className,
29
+ navTheme = "auto"
30
+ }) => {
27
31
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
28
32
  "svg",
29
33
  {
@@ -31,7 +35,7 @@ const Logo = ({ className }) => {
31
35
  "data-name": "Layer 1",
32
36
  xmlns: "http://www.w3.org/2000/svg",
33
37
  viewBox: "0 0 107.25 132.8",
34
- className: (0, import_utils.cn)("text-gray-900 dark:text-white", className),
38
+ className: (0, import_utils.cn)(import_nav_theme.NAV_TEXT_CLASSES[navTheme], className),
35
39
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
36
40
  "path",
37
41
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../components/icons/logo.tsx"],"sourcesContent":["import { cn } from '../../lib/utils'\r\n\r\nexport const Logo = ({ className }: { className?: string }) => {\r\n return (\r\n <svg\r\n id=\"Layer_1\"\r\n data-name=\"Layer 1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 107.25 132.8\"\r\n className={cn('text-gray-900 dark:text-white', className)}\r\n >\r\n <path\r\n d=\"M5.23,48.29A31.58,31.58,0,0,1,2.45,34.87c0-10.09,4.4-18.66,12.74-24.79C24.16,3.48,35.44,0,51.79,0a99.06,99.06,0,0,1,50.83,14L91.21,32.15c-13-7.22-28.55-11.34-41.82-11.34C24.58,20.81,7.84,30.07,5.23,48.29Zm72.17,56.3c-4.59,4.38-13.35,6.35-24.9,6.35-13.49,0-28-4.35-40.85-11.51L0,118.09c16.51,9.56,32.87,14.71,51.51,14.71,22.84,0,32.17-7.9,32.17-16C83.68,111.65,81.3,107.75,77.4,104.59Zm-17.73-49C47,51.11,36.52,45.66,31.93,40.3c-4.87,2.94-8.41,7.53-8.41,13,0,9.71,9.53,16,25.4,21.52,25.39,7.82,51.08,18.74,53.15,38.11a32.5,32.5,0,0,0,5.18-18.27C107.25,70.63,80.76,63,59.67,55.57Z\"\r\n fill=\"currentColor\"\r\n />\r\n </svg>\r\n )\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAWM;AAXN,mBAAmB;AAEZ,MAAM,OAAO,CAAC,EAAE,UAAU,MAA8B;AAC7D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,IAAG;AAAA,MACH,aAAU;AAAA,MACV,OAAM;AAAA,MACN,SAAQ;AAAA,MACR,eAAW,iBAAG,iCAAiC,SAAS;AAAA,MAExD;AAAA,QAAC;AAAA;AAAA,UACC,GAAE;AAAA,UACF,MAAK;AAAA;AAAA,MACP;AAAA;AAAA,EACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../components/icons/logo.tsx"],"sourcesContent":["import { cn } from '../../lib/utils'\nimport { NAV_TEXT_CLASSES, NavTheme } from '../../lib/nav-theme'\n\nexport const Logo = ({\n className,\n navTheme = 'auto',\n}: {\n className?: string\n navTheme?: NavTheme\n}) => {\n return (\n <svg\n id=\"Layer_1\"\n data-name=\"Layer 1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 107.25 132.8\"\n className={cn(NAV_TEXT_CLASSES[navTheme], className)}\n >\n <path\n d=\"M5.23,48.29A31.58,31.58,0,0,1,2.45,34.87c0-10.09,4.4-18.66,12.74-24.79C24.16,3.48,35.44,0,51.79,0a99.06,99.06,0,0,1,50.83,14L91.21,32.15c-13-7.22-28.55-11.34-41.82-11.34C24.58,20.81,7.84,30.07,5.23,48.29Zm72.17,56.3c-4.59,4.38-13.35,6.35-24.9,6.35-13.49,0-28-4.35-40.85-11.51L0,118.09c16.51,9.56,32.87,14.71,51.51,14.71,22.84,0,32.17-7.9,32.17-16C83.68,111.65,81.3,107.75,77.4,104.59Zm-17.73-49C47,51.11,36.52,45.66,31.93,40.3c-4.87,2.94-8.41,7.53-8.41,13,0,9.71,9.53,16,25.4,21.52,25.39,7.82,51.08,18.74,53.15,38.11a32.5,32.5,0,0,0,5.18-18.27C107.25,70.63,80.76,63,59.67,55.57Z\"\n fill=\"currentColor\"\n />\n </svg>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBM;AAlBN,mBAAmB;AACnB,uBAA2C;AAEpC,MAAM,OAAO,CAAC;AAAA,EACnB;AAAA,EACA,WAAW;AACb,MAGM;AACJ,SACE;AAAA,IAAC;AAAA;AAAA,MACC,IAAG;AAAA,MACH,aAAU;AAAA,MACV,OAAM;AAAA,MACN,SAAQ;AAAA,MACR,eAAW,iBAAG,kCAAiB,QAAQ,GAAG,SAAS;AAAA,MAEnD;AAAA,QAAC;AAAA;AAAA,UACC,GAAE;AAAA,UACF,MAAK;AAAA;AAAA,MACP;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -1,4 +1,6 @@
1
- export declare const Logo: ({ className }: {
1
+ import { NavTheme } from '../../lib/nav-theme';
2
+ export declare const Logo: ({ className, navTheme, }: {
2
3
  className?: string;
4
+ navTheme?: NavTheme;
3
5
  }) => import("react").JSX.Element;
4
6
  //# sourceMappingURL=logo.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logo.d.ts","sourceRoot":"","sources":["../../../components/icons/logo.tsx"],"names":[],"mappings":"AAEA,eAAO,MAAM,IAAI,GAAI,eAAe;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,gCAezD,CAAA"}
1
+ {"version":3,"file":"logo.d.ts","sourceRoot":"","sources":["../../../components/icons/logo.tsx"],"names":[],"mappings":"AACA,OAAO,EAAoB,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAEhE,eAAO,MAAM,IAAI,GAAI,0BAGlB;IACD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,QAAQ,CAAA;CACpB,gCAeA,CAAA"}
@@ -1,6 +1,10 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { cn } from "../../lib/utils";
3
- const Logo = ({ className }) => {
3
+ import { NAV_TEXT_CLASSES } from "../../lib/nav-theme";
4
+ const Logo = ({
5
+ className,
6
+ navTheme = "auto"
7
+ }) => {
4
8
  return /* @__PURE__ */ jsx(
5
9
  "svg",
6
10
  {
@@ -8,7 +12,7 @@ const Logo = ({ className }) => {
8
12
  "data-name": "Layer 1",
9
13
  xmlns: "http://www.w3.org/2000/svg",
10
14
  viewBox: "0 0 107.25 132.8",
11
- className: cn("text-gray-900 dark:text-white", className),
15
+ className: cn(NAV_TEXT_CLASSES[navTheme], className),
12
16
  children: /* @__PURE__ */ jsx(
13
17
  "path",
14
18
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../components/icons/logo.tsx"],"sourcesContent":["import { cn } from '../../lib/utils'\r\n\r\nexport const Logo = ({ className }: { className?: string }) => {\r\n return (\r\n <svg\r\n id=\"Layer_1\"\r\n data-name=\"Layer 1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 107.25 132.8\"\r\n className={cn('text-gray-900 dark:text-white', className)}\r\n >\r\n <path\r\n d=\"M5.23,48.29A31.58,31.58,0,0,1,2.45,34.87c0-10.09,4.4-18.66,12.74-24.79C24.16,3.48,35.44,0,51.79,0a99.06,99.06,0,0,1,50.83,14L91.21,32.15c-13-7.22-28.55-11.34-41.82-11.34C24.58,20.81,7.84,30.07,5.23,48.29Zm72.17,56.3c-4.59,4.38-13.35,6.35-24.9,6.35-13.49,0-28-4.35-40.85-11.51L0,118.09c16.51,9.56,32.87,14.71,51.51,14.71,22.84,0,32.17-7.9,32.17-16C83.68,111.65,81.3,107.75,77.4,104.59Zm-17.73-49C47,51.11,36.52,45.66,31.93,40.3c-4.87,2.94-8.41,7.53-8.41,13,0,9.71,9.53,16,25.4,21.52,25.39,7.82,51.08,18.74,53.15,38.11a32.5,32.5,0,0,0,5.18-18.27C107.25,70.63,80.76,63,59.67,55.57Z\"\r\n fill=\"currentColor\"\r\n />\r\n </svg>\r\n )\r\n}\r\n"],"mappings":"AAWM;AAXN,SAAS,UAAU;AAEZ,MAAM,OAAO,CAAC,EAAE,UAAU,MAA8B;AAC7D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,IAAG;AAAA,MACH,aAAU;AAAA,MACV,OAAM;AAAA,MACN,SAAQ;AAAA,MACR,WAAW,GAAG,iCAAiC,SAAS;AAAA,MAExD;AAAA,QAAC;AAAA;AAAA,UACC,GAAE;AAAA,UACF,MAAK;AAAA;AAAA,MACP;AAAA;AAAA,EACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../components/icons/logo.tsx"],"sourcesContent":["import { cn } from '../../lib/utils'\nimport { NAV_TEXT_CLASSES, NavTheme } from '../../lib/nav-theme'\n\nexport const Logo = ({\n className,\n navTheme = 'auto',\n}: {\n className?: string\n navTheme?: NavTheme\n}) => {\n return (\n <svg\n id=\"Layer_1\"\n data-name=\"Layer 1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 107.25 132.8\"\n className={cn(NAV_TEXT_CLASSES[navTheme], className)}\n >\n <path\n d=\"M5.23,48.29A31.58,31.58,0,0,1,2.45,34.87c0-10.09,4.4-18.66,12.74-24.79C24.16,3.48,35.44,0,51.79,0a99.06,99.06,0,0,1,50.83,14L91.21,32.15c-13-7.22-28.55-11.34-41.82-11.34C24.58,20.81,7.84,30.07,5.23,48.29Zm72.17,56.3c-4.59,4.38-13.35,6.35-24.9,6.35-13.49,0-28-4.35-40.85-11.51L0,118.09c16.51,9.56,32.87,14.71,51.51,14.71,22.84,0,32.17-7.9,32.17-16C83.68,111.65,81.3,107.75,77.4,104.59Zm-17.73-49C47,51.11,36.52,45.66,31.93,40.3c-4.87,2.94-8.41,7.53-8.41,13,0,9.71,9.53,16,25.4,21.52,25.39,7.82,51.08,18.74,53.15,38.11a32.5,32.5,0,0,0,5.18-18.27C107.25,70.63,80.76,63,59.67,55.57Z\"\n fill=\"currentColor\"\n />\n </svg>\n )\n}\n"],"mappings":"AAkBM;AAlBN,SAAS,UAAU;AACnB,SAAS,wBAAkC;AAEpC,MAAM,OAAO,CAAC;AAAA,EACnB;AAAA,EACA,WAAW;AACb,MAGM;AACJ,SACE;AAAA,IAAC;AAAA;AAAA,MACC,IAAG;AAAA,MACH,aAAU;AAAA,MACV,OAAM;AAAA,MACN,SAAQ;AAAA,MACR,WAAW,GAAG,iBAAiB,QAAQ,GAAG,SAAS;AAAA,MAEnD;AAAA,QAAC;AAAA;AAAA,UACC,GAAE;AAAA,UACF,MAAK;AAAA;AAAA,MACP;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../components/lightbox/GallerySection.tsx"],"sourcesContent":["'use client'\r\n\r\nimport type { EntityImage } from './ImageLightbox.types'\r\n\r\nexport interface GallerySectionProps {\r\n images: EntityImage[]\r\n onImageClick: (imageId: number) => void\r\n testId?: string\r\n}\r\n\r\n/**\r\n * Reusable gallery section component for entity detail pages.\r\n * Renders a grid of gallery thumbnails with click handlers for lightbox integration.\r\n */\r\nexport function GallerySection({\r\n images,\r\n onImageClick,\r\n testId = 'gallery-grid',\r\n}: GallerySectionProps) {\r\n if (images.length === 0) {\r\n return null\r\n }\r\n\r\n return (\r\n <aside className=\"w-64\">\r\n <h3 className=\"text-default dark:text-default-dark mb-3 text-sm font-semibold\">\r\n Gallery\r\n </h3>\r\n <div className=\"grid grid-cols-2 gap-2\" data-testid={testId}>\r\n {images.map((img) => (\r\n <img\r\n key={img.id}\r\n src={img.cloudinaryUrl}\r\n alt={`Gallery image ${img.displayOrder + 1}`}\r\n className=\"aspect-square w-full cursor-pointer rounded object-cover transition-opacity hover:opacity-80\"\r\n data-testid=\"gallery-thumbnail\"\r\n onClick={() => onImageClick(img.id)}\r\n />\r\n ))}\r\n </div>\r\n </aside>\r\n )\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBI;AAVG,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA,SAAS;AACX,GAAwB;AACtB,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO;AAAA,EACT;AAEA,SACE,6CAAC,WAAM,WAAU,QACf;AAAA,gDAAC,QAAG,WAAU,kEAAiE,qBAE/E;AAAA,IACA,4CAAC,SAAI,WAAU,0BAAyB,eAAa,QAClD,iBAAO,IAAI,CAAC,QACX;AAAA,MAAC;AAAA;AAAA,QAEC,KAAK,IAAI;AAAA,QACT,KAAK,iBAAiB,IAAI,eAAe,CAAC;AAAA,QAC1C,WAAU;AAAA,QACV,eAAY;AAAA,QACZ,SAAS,MAAM,aAAa,IAAI,EAAE;AAAA;AAAA,MAL7B,IAAI;AAAA,IAMX,CACD,GACH;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../components/lightbox/GallerySection.tsx"],"sourcesContent":["'use client'\n\nimport type { EntityImage } from './ImageLightbox.types'\n\nexport interface GallerySectionProps {\n images: EntityImage[]\n onImageClick: (imageId: number) => void\n testId?: string\n}\n\n/**\n * Reusable gallery section component for entity detail pages.\n * Renders a grid of gallery thumbnails with click handlers for lightbox integration.\n */\nexport function GallerySection({\n images,\n onImageClick,\n testId = 'gallery-grid',\n}: GallerySectionProps) {\n if (images.length === 0) {\n return null\n }\n\n return (\n <aside className=\"w-64\">\n <h3 className=\"text-default dark:text-default-dark mb-3 text-sm font-semibold\">\n Gallery\n </h3>\n <div className=\"grid grid-cols-2 gap-2\" data-testid={testId}>\n {images.map((img) => (\n <img\n key={img.id}\n src={img.cloudinaryUrl}\n alt={`Gallery image ${img.displayOrder + 1}`}\n className=\"aspect-square w-full cursor-pointer rounded object-cover transition-opacity hover:opacity-80\"\n data-testid=\"gallery-thumbnail\"\n onClick={() => onImageClick(img.id)}\n />\n ))}\n </div>\n </aside>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBI;AAVG,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA,SAAS;AACX,GAAwB;AACtB,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO;AAAA,EACT;AAEA,SACE,6CAAC,WAAM,WAAU,QACf;AAAA,gDAAC,QAAG,WAAU,kEAAiE,qBAE/E;AAAA,IACA,4CAAC,SAAI,WAAU,0BAAyB,eAAa,QAClD,iBAAO,IAAI,CAAC,QACX;AAAA,MAAC;AAAA;AAAA,QAEC,KAAK,IAAI;AAAA,QACT,KAAK,iBAAiB,IAAI,eAAe,CAAC;AAAA,QAC1C,WAAU;AAAA,QACV,eAAY;AAAA,QACZ,SAAS,MAAM,aAAa,IAAI,EAAE;AAAA;AAAA,MAL7B,IAAI;AAAA,IAMX,CACD,GACH;AAAA,KACF;AAEJ;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../components/lightbox/GallerySection.tsx"],"sourcesContent":["'use client'\r\n\r\nimport type { EntityImage } from './ImageLightbox.types'\r\n\r\nexport interface GallerySectionProps {\r\n images: EntityImage[]\r\n onImageClick: (imageId: number) => void\r\n testId?: string\r\n}\r\n\r\n/**\r\n * Reusable gallery section component for entity detail pages.\r\n * Renders a grid of gallery thumbnails with click handlers for lightbox integration.\r\n */\r\nexport function GallerySection({\r\n images,\r\n onImageClick,\r\n testId = 'gallery-grid',\r\n}: GallerySectionProps) {\r\n if (images.length === 0) {\r\n return null\r\n }\r\n\r\n return (\r\n <aside className=\"w-64\">\r\n <h3 className=\"text-default dark:text-default-dark mb-3 text-sm font-semibold\">\r\n Gallery\r\n </h3>\r\n <div className=\"grid grid-cols-2 gap-2\" data-testid={testId}>\r\n {images.map((img) => (\r\n <img\r\n key={img.id}\r\n src={img.cloudinaryUrl}\r\n alt={`Gallery image ${img.displayOrder + 1}`}\r\n className=\"aspect-square w-full cursor-pointer rounded object-cover transition-opacity hover:opacity-80\"\r\n data-testid=\"gallery-thumbnail\"\r\n onClick={() => onImageClick(img.id)}\r\n />\r\n ))}\r\n </div>\r\n </aside>\r\n )\r\n}\r\n"],"mappings":";AAwBI,SACE,KADF;AAVG,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA,SAAS;AACX,GAAwB;AACtB,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO;AAAA,EACT;AAEA,SACE,qBAAC,WAAM,WAAU,QACf;AAAA,wBAAC,QAAG,WAAU,kEAAiE,qBAE/E;AAAA,IACA,oBAAC,SAAI,WAAU,0BAAyB,eAAa,QAClD,iBAAO,IAAI,CAAC,QACX;AAAA,MAAC;AAAA;AAAA,QAEC,KAAK,IAAI;AAAA,QACT,KAAK,iBAAiB,IAAI,eAAe,CAAC;AAAA,QAC1C,WAAU;AAAA,QACV,eAAY;AAAA,QACZ,SAAS,MAAM,aAAa,IAAI,EAAE;AAAA;AAAA,MAL7B,IAAI;AAAA,IAMX,CACD,GACH;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../components/lightbox/GallerySection.tsx"],"sourcesContent":["'use client'\n\nimport type { EntityImage } from './ImageLightbox.types'\n\nexport interface GallerySectionProps {\n images: EntityImage[]\n onImageClick: (imageId: number) => void\n testId?: string\n}\n\n/**\n * Reusable gallery section component for entity detail pages.\n * Renders a grid of gallery thumbnails with click handlers for lightbox integration.\n */\nexport function GallerySection({\n images,\n onImageClick,\n testId = 'gallery-grid',\n}: GallerySectionProps) {\n if (images.length === 0) {\n return null\n }\n\n return (\n <aside className=\"w-64\">\n <h3 className=\"text-default dark:text-default-dark mb-3 text-sm font-semibold\">\n Gallery\n </h3>\n <div className=\"grid grid-cols-2 gap-2\" data-testid={testId}>\n {images.map((img) => (\n <img\n key={img.id}\n src={img.cloudinaryUrl}\n alt={`Gallery image ${img.displayOrder + 1}`}\n className=\"aspect-square w-full cursor-pointer rounded object-cover transition-opacity hover:opacity-80\"\n data-testid=\"gallery-thumbnail\"\n onClick={() => onImageClick(img.id)}\n />\n ))}\n </div>\n </aside>\n )\n}\n"],"mappings":";AAwBI,SACE,KADF;AAVG,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA,SAAS;AACX,GAAwB;AACtB,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO;AAAA,EACT;AAEA,SACE,qBAAC,WAAM,WAAU,QACf;AAAA,wBAAC,QAAG,WAAU,kEAAiE,qBAE/E;AAAA,IACA,oBAAC,SAAI,WAAU,0BAAyB,eAAa,QAClD,iBAAO,IAAI,CAAC,QACX;AAAA,MAAC;AAAA;AAAA,QAEC,KAAK,IAAI;AAAA,QACT,KAAK,iBAAiB,IAAI,eAAe,CAAC;AAAA,QAC1C,WAAU;AAAA,QACV,eAAY;AAAA,QACZ,SAAS,MAAM,aAAa,IAAI,EAAE;AAAA;AAAA,MAL7B,IAAI;AAAA,IAMX,CACD,GACH;AAAA,KACF;AAEJ;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../components/lightbox/ImageLightbox.tsx"],"sourcesContent":["'use client'\r\n\r\nimport { useEffect, useRef, useState, useCallback } from 'react'\r\nimport { createPortal } from 'react-dom'\r\nimport { Button } from '../ui/button'\r\nimport type { ImageLightboxProps } from './ImageLightbox.types'\r\n\r\nexport function ImageLightbox({\r\n images,\r\n isOpen,\r\n initialIndex,\r\n onClose,\r\n onNavigate,\r\n}: ImageLightboxProps) {\r\n const [currentIndex, setCurrentIndex] = useState(initialIndex)\r\n const [mounted, setMounted] = useState(false)\r\n const imageRef = useRef<HTMLImageElement>(null)\r\n\r\n // Track if component is mounted (client-side only)\r\n useEffect(() => {\r\n setMounted(true)\r\n return () => setMounted(false)\r\n }, [])\r\n\r\n // Sync with initialIndex when lightbox opens\r\n useEffect(() => {\r\n if (isOpen) {\r\n setCurrentIndex(initialIndex)\r\n }\r\n }, [isOpen, initialIndex])\r\n\r\n // Lock body scroll when open\r\n useEffect(() => {\r\n if (isOpen) {\r\n document.body.style.overflow = 'hidden'\r\n return () => {\r\n document.body.style.overflow = ''\r\n }\r\n }\r\n }, [isOpen])\r\n\r\n // Navigation handlers\r\n const next = useCallback(() => {\r\n setCurrentIndex((prev) => {\r\n const newIndex = Math.min(prev + 1, images.length - 1)\r\n if (onNavigate) onNavigate(newIndex)\r\n return newIndex\r\n })\r\n }, [images.length, onNavigate])\r\n\r\n const prev = useCallback(() => {\r\n setCurrentIndex((prev) => {\r\n const newIndex = Math.max(prev - 1, 0)\r\n if (onNavigate) onNavigate(newIndex)\r\n return newIndex\r\n })\r\n }, [onNavigate])\r\n\r\n // Keyboard navigation\r\n useEffect(() => {\r\n if (!isOpen) return\r\n\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape') onClose()\r\n if (e.key === 'ArrowLeft') prev()\r\n if (e.key === 'ArrowRight') next()\r\n }\r\n\r\n window.addEventListener('keydown', handleKeyDown)\r\n return () => window.removeEventListener('keydown', handleKeyDown)\r\n }, [isOpen, onClose, prev, next])\r\n\r\n // Handle image errors\r\n const handleImageError = (e: React.SyntheticEvent<HTMLImageElement>) => {\r\n e.currentTarget.src = '/placeholder-image.png'\r\n console.error('Failed to load image:', images[currentIndex]?.url)\r\n }\r\n\r\n // Handle swipe gestures\r\n useEffect(() => {\r\n if (!isOpen) return\r\n\r\n let touchStartX = 0\r\n let touchEndX = 0\r\n\r\n const handleTouchStart = (e: TouchEvent) => {\r\n touchStartX = e.changedTouches[0].screenX\r\n }\r\n\r\n const handleTouchEnd = (e: TouchEvent) => {\r\n touchEndX = e.changedTouches[0].screenX\r\n const swipeDistance = touchStartX - touchEndX\r\n const minSwipeDistance = 50\r\n\r\n if (Math.abs(swipeDistance) > minSwipeDistance) {\r\n if (swipeDistance > 0 && currentIndex < images.length - 1) {\r\n next()\r\n } else if (swipeDistance < 0 && currentIndex > 0) {\r\n prev()\r\n }\r\n }\r\n }\r\n\r\n window.addEventListener('touchstart', handleTouchStart, { passive: true })\r\n window.addEventListener('touchend', handleTouchEnd, { passive: true })\r\n\r\n return () => {\r\n window.removeEventListener('touchstart', handleTouchStart)\r\n window.removeEventListener('touchend', handleTouchEnd)\r\n }\r\n }, [isOpen, currentIndex, images.length, next, prev])\r\n\r\n // Handle backdrop click\r\n const handleBackdropClick = (e: React.MouseEvent) => {\r\n if (e.target === e.currentTarget) {\r\n onClose()\r\n }\r\n }\r\n\r\n // Empty gallery\r\n if (!images || images.length === 0) return null\r\n\r\n // Not open or not mounted (SSR safety)\r\n if (!mounted || !isOpen) return null\r\n\r\n const currentImage = images[currentIndex]\r\n const isFirstImage = currentIndex === 0\r\n const isLastImage = currentIndex === images.length - 1\r\n const isSingleImage = images.length === 1\r\n\r\n return createPortal(\r\n <div\r\n className=\"animate-in fade-in fixed inset-0 z-50 flex items-center justify-center bg-black/90 duration-200\"\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n aria-label=\"Image lightbox\"\r\n onClick={handleBackdropClick}\r\n >\r\n {/* Close button */}\r\n <Button\r\n onClick={onClose}\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"absolute right-4 top-4 z-10 rounded-full bg-white/10 text-white hover:bg-white/20 focus:ring-white md:h-8 md:w-8\"\r\n aria-label=\"Close lightbox\"\r\n >\r\n <svg\r\n className=\"h-6 w-6\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n viewBox=\"0 0 24 24\"\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n strokeWidth={2}\r\n d=\"M6 18L18 6M6 6l12 12\"\r\n />\r\n </svg>\r\n </Button>\r\n\r\n {/* Previous button */}\r\n {!isSingleImage && (\r\n <Button\r\n onClick={prev}\r\n disabled={isFirstImage}\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"absolute left-4 z-10 h-12 w-12 rounded-full bg-white/10 text-white hover:bg-white/20 focus:ring-white disabled:cursor-not-allowed disabled:opacity-50 md:left-8 md:opacity-0 md:hover:opacity-100\"\r\n aria-label=\"Previous image\"\r\n >\r\n <svg\r\n className=\"h-6 w-6\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n viewBox=\"0 0 24 24\"\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n strokeWidth={2}\r\n d=\"M15 19l-7-7 7-7\"\r\n />\r\n </svg>\r\n </Button>\r\n )}\r\n\r\n {/* Image container */}\r\n <div className=\"relative mx-4 flex max-h-[90vh] max-w-[90vw] items-center justify-center\">\r\n <img\r\n ref={imageRef}\r\n src={currentImage.url}\r\n alt={currentImage.alt}\r\n className=\"max-h-[90vh] max-w-[90vw] object-contain transition-opacity duration-150\"\r\n style={{ touchAction: 'pan-x pan-y pinch-zoom' }}\r\n onError={handleImageError}\r\n />\r\n </div>\r\n\r\n {/* Next button */}\r\n {!isSingleImage && (\r\n <Button\r\n onClick={next}\r\n disabled={isLastImage}\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"absolute right-4 z-10 h-12 w-12 rounded-full bg-white/10 text-white hover:bg-white/20 focus:ring-white disabled:cursor-not-allowed disabled:opacity-50 md:right-8 md:opacity-0 md:hover:opacity-100\"\r\n aria-label=\"Next image\"\r\n >\r\n <svg\r\n className=\"h-6 w-6\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n viewBox=\"0 0 24 24\"\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n strokeWidth={2}\r\n d=\"M9 5l7 7-7 7\"\r\n />\r\n </svg>\r\n </Button>\r\n )}\r\n\r\n {/* Image counter */}\r\n {!isSingleImage && (\r\n <div className=\"absolute bottom-4 left-1/2 -translate-x-1/2 rounded-full bg-black/50 px-4 py-2 text-sm text-white\">\r\n {currentIndex + 1} / {images.length}\r\n </div>\r\n )}\r\n </div>,\r\n document.body,\r\n )\r\n}\r\n"],"mappings":"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","names":["prev"]}
1
+ {"version":3,"sources":["../../../components/lightbox/ImageLightbox.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useRef, useState, useCallback } from 'react'\nimport { createPortal } from 'react-dom'\nimport { Button } from '../ui/button'\nimport type { ImageLightboxProps } from './ImageLightbox.types'\n\nexport function ImageLightbox({\n images,\n isOpen,\n initialIndex,\n onClose,\n onNavigate,\n}: ImageLightboxProps) {\n const [currentIndex, setCurrentIndex] = useState(initialIndex)\n const [mounted, setMounted] = useState(false)\n const imageRef = useRef<HTMLImageElement>(null)\n\n // Track if component is mounted (client-side only)\n useEffect(() => {\n setMounted(true)\n return () => setMounted(false)\n }, [])\n\n // Sync with initialIndex when lightbox opens\n useEffect(() => {\n if (isOpen) {\n setCurrentIndex(initialIndex)\n }\n }, [isOpen, initialIndex])\n\n // Lock body scroll when open\n useEffect(() => {\n if (isOpen) {\n document.body.style.overflow = 'hidden'\n return () => {\n document.body.style.overflow = ''\n }\n }\n }, [isOpen])\n\n // Navigation handlers\n const next = useCallback(() => {\n setCurrentIndex((prev) => {\n const newIndex = Math.min(prev + 1, images.length - 1)\n if (onNavigate) onNavigate(newIndex)\n return newIndex\n })\n }, [images.length, onNavigate])\n\n const prev = useCallback(() => {\n setCurrentIndex((prev) => {\n const newIndex = Math.max(prev - 1, 0)\n if (onNavigate) onNavigate(newIndex)\n return newIndex\n })\n }, [onNavigate])\n\n // Keyboard navigation\n useEffect(() => {\n if (!isOpen) return\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose()\n if (e.key === 'ArrowLeft') prev()\n if (e.key === 'ArrowRight') next()\n }\n\n window.addEventListener('keydown', handleKeyDown)\n return () => window.removeEventListener('keydown', handleKeyDown)\n }, [isOpen, onClose, prev, next])\n\n // Handle image errors\n const handleImageError = (e: React.SyntheticEvent<HTMLImageElement>) => {\n e.currentTarget.src = '/placeholder-image.png'\n console.error('Failed to load image:', images[currentIndex]?.url)\n }\n\n // Handle swipe gestures\n useEffect(() => {\n if (!isOpen) return\n\n let touchStartX = 0\n let touchEndX = 0\n\n const handleTouchStart = (e: TouchEvent) => {\n touchStartX = e.changedTouches[0].screenX\n }\n\n const handleTouchEnd = (e: TouchEvent) => {\n touchEndX = e.changedTouches[0].screenX\n const swipeDistance = touchStartX - touchEndX\n const minSwipeDistance = 50\n\n if (Math.abs(swipeDistance) > minSwipeDistance) {\n if (swipeDistance > 0 && currentIndex < images.length - 1) {\n next()\n } else if (swipeDistance < 0 && currentIndex > 0) {\n prev()\n }\n }\n }\n\n window.addEventListener('touchstart', handleTouchStart, { passive: true })\n window.addEventListener('touchend', handleTouchEnd, { passive: true })\n\n return () => {\n window.removeEventListener('touchstart', handleTouchStart)\n window.removeEventListener('touchend', handleTouchEnd)\n }\n }, [isOpen, currentIndex, images.length, next, prev])\n\n // Handle backdrop click\n const handleBackdropClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) {\n onClose()\n }\n }\n\n // Empty gallery\n if (!images || images.length === 0) return null\n\n // Not open or not mounted (SSR safety)\n if (!mounted || !isOpen) return null\n\n const currentImage = images[currentIndex]\n const isFirstImage = currentIndex === 0\n const isLastImage = currentIndex === images.length - 1\n const isSingleImage = images.length === 1\n\n return createPortal(\n <div\n className=\"animate-in fade-in fixed inset-0 z-50 flex items-center justify-center bg-black/90 duration-200\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Image lightbox\"\n onClick={handleBackdropClick}\n >\n {/* Close button */}\n <Button\n onClick={onClose}\n variant=\"ghost\"\n size=\"icon\"\n className=\"absolute right-4 top-4 z-10 rounded-full bg-white/10 text-white hover:bg-white/20 focus:ring-white md:h-8 md:w-8\"\n aria-label=\"Close lightbox\"\n >\n <svg\n className=\"h-6 w-6\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </Button>\n\n {/* Previous button */}\n {!isSingleImage && (\n <Button\n onClick={prev}\n disabled={isFirstImage}\n variant=\"ghost\"\n size=\"icon\"\n className=\"absolute left-4 z-10 h-12 w-12 rounded-full bg-white/10 text-white hover:bg-white/20 focus:ring-white disabled:cursor-not-allowed disabled:opacity-50 md:left-8 md:opacity-0 md:hover:opacity-100\"\n aria-label=\"Previous image\"\n >\n <svg\n className=\"h-6 w-6\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M15 19l-7-7 7-7\"\n />\n </svg>\n </Button>\n )}\n\n {/* Image container */}\n <div className=\"relative mx-4 flex max-h-[90vh] max-w-[90vw] items-center justify-center\">\n <img\n ref={imageRef}\n src={currentImage.url}\n alt={currentImage.alt}\n className=\"max-h-[90vh] max-w-[90vw] object-contain transition-opacity duration-150\"\n style={{ touchAction: 'pan-x pan-y pinch-zoom' }}\n onError={handleImageError}\n />\n </div>\n\n {/* Next button */}\n {!isSingleImage && (\n <Button\n onClick={next}\n disabled={isLastImage}\n variant=\"ghost\"\n size=\"icon\"\n className=\"absolute right-4 z-10 h-12 w-12 rounded-full bg-white/10 text-white hover:bg-white/20 focus:ring-white disabled:cursor-not-allowed disabled:opacity-50 md:right-8 md:opacity-0 md:hover:opacity-100\"\n aria-label=\"Next image\"\n >\n <svg\n className=\"h-6 w-6\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 5l7 7-7 7\"\n />\n </svg>\n </Button>\n )}\n\n {/* Image counter */}\n {!isSingleImage && (\n <div className=\"absolute bottom-4 left-1/2 -translate-x-1/2 rounded-full bg-black/50 px-4 py-2 text-sm text-white\">\n {currentIndex + 1} / {images.length}\n </div>\n )}\n </div>,\n document.body,\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAwJU;AAtJV,mBAAyD;AACzD,uBAA6B;AAC7B,oBAAuB;AAGhB,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAuB;AACrB,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAS,YAAY;AAC7D,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,KAAK;AAC5C,QAAM,eAAW,qBAAyB,IAAI;AAG9C,8BAAU,MAAM;AACd,eAAW,IAAI;AACf,WAAO,MAAM,WAAW,KAAK;AAAA,EAC/B,GAAG,CAAC,CAAC;AAGL,8BAAU,MAAM;AACd,QAAI,QAAQ;AACV,sBAAgB,YAAY;AAAA,IAC9B;AAAA,EACF,GAAG,CAAC,QAAQ,YAAY,CAAC;AAGzB,8BAAU,MAAM;AACd,QAAI,QAAQ;AACV,eAAS,KAAK,MAAM,WAAW;AAC/B,aAAO,MAAM;AACX,iBAAS,KAAK,MAAM,WAAW;AAAA,MACjC;AAAA,IACF;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAGX,QAAM,WAAO,0BAAY,MAAM;AAC7B,oBAAgB,CAACA,UAAS;AACxB,YAAM,WAAW,KAAK,IAAIA,QAAO,GAAG,OAAO,SAAS,CAAC;AACrD,UAAI,WAAY,YAAW,QAAQ;AACnC,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,OAAO,QAAQ,UAAU,CAAC;AAE9B,QAAM,WAAO,0BAAY,MAAM;AAC7B,oBAAgB,CAACA,UAAS;AACxB,YAAM,WAAW,KAAK,IAAIA,QAAO,GAAG,CAAC;AACrC,UAAI,WAAY,YAAW,QAAQ;AACnC,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,UAAU,CAAC;AAGf,8BAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AAEb,UAAM,gBAAgB,CAAC,MAAqB;AAC1C,UAAI,EAAE,QAAQ,SAAU,SAAQ;AAChC,UAAI,EAAE,QAAQ,YAAa,MAAK;AAChC,UAAI,EAAE,QAAQ,aAAc,MAAK;AAAA,IACnC;AAEA,WAAO,iBAAiB,WAAW,aAAa;AAChD,WAAO,MAAM,OAAO,oBAAoB,WAAW,aAAa;AAAA,EAClE,GAAG,CAAC,QAAQ,SAAS,MAAM,IAAI,CAAC;AAGhC,QAAM,mBAAmB,CAAC,MAA8C;AAzE1E;AA0EI,MAAE,cAAc,MAAM;AACtB,YAAQ,MAAM,0BAAyB,YAAO,YAAY,MAAnB,mBAAsB,GAAG;AAAA,EAClE;AAGA,8BAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AAEb,QAAI,cAAc;AAClB,QAAI,YAAY;AAEhB,UAAM,mBAAmB,CAAC,MAAkB;AAC1C,oBAAc,EAAE,eAAe,CAAC,EAAE;AAAA,IACpC;AAEA,UAAM,iBAAiB,CAAC,MAAkB;AACxC,kBAAY,EAAE,eAAe,CAAC,EAAE;AAChC,YAAM,gBAAgB,cAAc;AACpC,YAAM,mBAAmB;AAEzB,UAAI,KAAK,IAAI,aAAa,IAAI,kBAAkB;AAC9C,YAAI,gBAAgB,KAAK,eAAe,OAAO,SAAS,GAAG;AACzD,eAAK;AAAA,QACP,WAAW,gBAAgB,KAAK,eAAe,GAAG;AAChD,eAAK;AAAA,QACP;AAAA,MACF;AAAA,IACF;AAEA,WAAO,iBAAiB,cAAc,kBAAkB,EAAE,SAAS,KAAK,CAAC;AACzE,WAAO,iBAAiB,YAAY,gBAAgB,EAAE,SAAS,KAAK,CAAC;AAErE,WAAO,MAAM;AACX,aAAO,oBAAoB,cAAc,gBAAgB;AACzD,aAAO,oBAAoB,YAAY,cAAc;AAAA,IACvD;AAAA,EACF,GAAG,CAAC,QAAQ,cAAc,OAAO,QAAQ,MAAM,IAAI,CAAC;AAGpD,QAAM,sBAAsB,CAAC,MAAwB;AACnD,QAAI,EAAE,WAAW,EAAE,eAAe;AAChC,cAAQ;AAAA,IACV;AAAA,EACF;AAGA,MAAI,CAAC,UAAU,OAAO,WAAW,EAAG,QAAO;AAG3C,MAAI,CAAC,WAAW,CAAC,OAAQ,QAAO;AAEhC,QAAM,eAAe,OAAO,YAAY;AACxC,QAAM,eAAe,iBAAiB;AACtC,QAAM,cAAc,iBAAiB,OAAO,SAAS;AACrD,QAAM,gBAAgB,OAAO,WAAW;AAExC,aAAO;AAAA,IACL;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,MAAK;AAAA,QACL,cAAW;AAAA,QACX,cAAW;AAAA,QACX,SAAS;AAAA,QAGT;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS;AAAA,cACT,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,WAAU;AAAA,cACV,cAAW;AAAA,cAEX;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,MAAK;AAAA,kBACL,QAAO;AAAA,kBACP,SAAQ;AAAA,kBAER;AAAA,oBAAC;AAAA;AAAA,sBACC,eAAc;AAAA,sBACd,gBAAe;AAAA,sBACf,aAAa;AAAA,sBACb,GAAE;AAAA;AAAA,kBACJ;AAAA;AAAA,cACF;AAAA;AAAA,UACF;AAAA,UAGC,CAAC,iBACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS;AAAA,cACT,UAAU;AAAA,cACV,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,WAAU;AAAA,cACV,cAAW;AAAA,cAEX;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,MAAK;AAAA,kBACL,QAAO;AAAA,kBACP,SAAQ;AAAA,kBAER;AAAA,oBAAC;AAAA;AAAA,sBACC,eAAc;AAAA,sBACd,gBAAe;AAAA,sBACf,aAAa;AAAA,sBACb,GAAE;AAAA;AAAA,kBACJ;AAAA;AAAA,cACF;AAAA;AAAA,UACF;AAAA,UAIF,4CAAC,SAAI,WAAU,4EACb;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,KAAK,aAAa;AAAA,cAClB,KAAK,aAAa;AAAA,cAClB,WAAU;AAAA,cACV,OAAO,EAAE,aAAa,yBAAyB;AAAA,cAC/C,SAAS;AAAA;AAAA,UACX,GACF;AAAA,UAGC,CAAC,iBACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS;AAAA,cACT,UAAU;AAAA,cACV,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,WAAU;AAAA,cACV,cAAW;AAAA,cAEX;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,MAAK;AAAA,kBACL,QAAO;AAAA,kBACP,SAAQ;AAAA,kBAER;AAAA,oBAAC;AAAA;AAAA,sBACC,eAAc;AAAA,sBACd,gBAAe;AAAA,sBACf,aAAa;AAAA,sBACb,GAAE;AAAA;AAAA,kBACJ;AAAA;AAAA,cACF;AAAA;AAAA,UACF;AAAA,UAID,CAAC,iBACA,6CAAC,SAAI,WAAU,qGACZ;AAAA,2BAAe;AAAA,YAAE;AAAA,YAAI,OAAO;AAAA,aAC/B;AAAA;AAAA;AAAA,IAEJ;AAAA,IACA,SAAS;AAAA,EACX;AACF;","names":["prev"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../components/lightbox/ImageLightbox.tsx"],"sourcesContent":["'use client'\r\n\r\nimport { useEffect, useRef, useState, useCallback } from 'react'\r\nimport { createPortal } from 'react-dom'\r\nimport { Button } from '../ui/button'\r\nimport type { ImageLightboxProps } from './ImageLightbox.types'\r\n\r\nexport function ImageLightbox({\r\n images,\r\n isOpen,\r\n initialIndex,\r\n onClose,\r\n onNavigate,\r\n}: ImageLightboxProps) {\r\n const [currentIndex, setCurrentIndex] = useState(initialIndex)\r\n const [mounted, setMounted] = useState(false)\r\n const imageRef = useRef<HTMLImageElement>(null)\r\n\r\n // Track if component is mounted (client-side only)\r\n useEffect(() => {\r\n setMounted(true)\r\n return () => setMounted(false)\r\n }, [])\r\n\r\n // Sync with initialIndex when lightbox opens\r\n useEffect(() => {\r\n if (isOpen) {\r\n setCurrentIndex(initialIndex)\r\n }\r\n }, [isOpen, initialIndex])\r\n\r\n // Lock body scroll when open\r\n useEffect(() => {\r\n if (isOpen) {\r\n document.body.style.overflow = 'hidden'\r\n return () => {\r\n document.body.style.overflow = ''\r\n }\r\n }\r\n }, [isOpen])\r\n\r\n // Navigation handlers\r\n const next = useCallback(() => {\r\n setCurrentIndex((prev) => {\r\n const newIndex = Math.min(prev + 1, images.length - 1)\r\n if (onNavigate) onNavigate(newIndex)\r\n return newIndex\r\n })\r\n }, [images.length, onNavigate])\r\n\r\n const prev = useCallback(() => {\r\n setCurrentIndex((prev) => {\r\n const newIndex = Math.max(prev - 1, 0)\r\n if (onNavigate) onNavigate(newIndex)\r\n return newIndex\r\n })\r\n }, [onNavigate])\r\n\r\n // Keyboard navigation\r\n useEffect(() => {\r\n if (!isOpen) return\r\n\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape') onClose()\r\n if (e.key === 'ArrowLeft') prev()\r\n if (e.key === 'ArrowRight') next()\r\n }\r\n\r\n window.addEventListener('keydown', handleKeyDown)\r\n return () => window.removeEventListener('keydown', handleKeyDown)\r\n }, [isOpen, onClose, prev, next])\r\n\r\n // Handle image errors\r\n const handleImageError = (e: React.SyntheticEvent<HTMLImageElement>) => {\r\n e.currentTarget.src = '/placeholder-image.png'\r\n console.error('Failed to load image:', images[currentIndex]?.url)\r\n }\r\n\r\n // Handle swipe gestures\r\n useEffect(() => {\r\n if (!isOpen) return\r\n\r\n let touchStartX = 0\r\n let touchEndX = 0\r\n\r\n const handleTouchStart = (e: TouchEvent) => {\r\n touchStartX = e.changedTouches[0].screenX\r\n }\r\n\r\n const handleTouchEnd = (e: TouchEvent) => {\r\n touchEndX = e.changedTouches[0].screenX\r\n const swipeDistance = touchStartX - touchEndX\r\n const minSwipeDistance = 50\r\n\r\n if (Math.abs(swipeDistance) > minSwipeDistance) {\r\n if (swipeDistance > 0 && currentIndex < images.length - 1) {\r\n next()\r\n } else if (swipeDistance < 0 && currentIndex > 0) {\r\n prev()\r\n }\r\n }\r\n }\r\n\r\n window.addEventListener('touchstart', handleTouchStart, { passive: true })\r\n window.addEventListener('touchend', handleTouchEnd, { passive: true })\r\n\r\n return () => {\r\n window.removeEventListener('touchstart', handleTouchStart)\r\n window.removeEventListener('touchend', handleTouchEnd)\r\n }\r\n }, [isOpen, currentIndex, images.length, next, prev])\r\n\r\n // Handle backdrop click\r\n const handleBackdropClick = (e: React.MouseEvent) => {\r\n if (e.target === e.currentTarget) {\r\n onClose()\r\n }\r\n }\r\n\r\n // Empty gallery\r\n if (!images || images.length === 0) return null\r\n\r\n // Not open or not mounted (SSR safety)\r\n if (!mounted || !isOpen) return null\r\n\r\n const currentImage = images[currentIndex]\r\n const isFirstImage = currentIndex === 0\r\n const isLastImage = currentIndex === images.length - 1\r\n const isSingleImage = images.length === 1\r\n\r\n return createPortal(\r\n <div\r\n className=\"animate-in fade-in fixed inset-0 z-50 flex items-center justify-center bg-black/90 duration-200\"\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n aria-label=\"Image lightbox\"\r\n onClick={handleBackdropClick}\r\n >\r\n {/* Close button */}\r\n <Button\r\n onClick={onClose}\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"absolute right-4 top-4 z-10 rounded-full bg-white/10 text-white hover:bg-white/20 focus:ring-white md:h-8 md:w-8\"\r\n aria-label=\"Close lightbox\"\r\n >\r\n <svg\r\n className=\"h-6 w-6\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n viewBox=\"0 0 24 24\"\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n strokeWidth={2}\r\n d=\"M6 18L18 6M6 6l12 12\"\r\n />\r\n </svg>\r\n </Button>\r\n\r\n {/* Previous button */}\r\n {!isSingleImage && (\r\n <Button\r\n onClick={prev}\r\n disabled={isFirstImage}\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"absolute left-4 z-10 h-12 w-12 rounded-full bg-white/10 text-white hover:bg-white/20 focus:ring-white disabled:cursor-not-allowed disabled:opacity-50 md:left-8 md:opacity-0 md:hover:opacity-100\"\r\n aria-label=\"Previous image\"\r\n >\r\n <svg\r\n className=\"h-6 w-6\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n viewBox=\"0 0 24 24\"\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n strokeWidth={2}\r\n d=\"M15 19l-7-7 7-7\"\r\n />\r\n </svg>\r\n </Button>\r\n )}\r\n\r\n {/* Image container */}\r\n <div className=\"relative mx-4 flex max-h-[90vh] max-w-[90vw] items-center justify-center\">\r\n <img\r\n ref={imageRef}\r\n src={currentImage.url}\r\n alt={currentImage.alt}\r\n className=\"max-h-[90vh] max-w-[90vw] object-contain transition-opacity duration-150\"\r\n style={{ touchAction: 'pan-x pan-y pinch-zoom' }}\r\n onError={handleImageError}\r\n />\r\n </div>\r\n\r\n {/* Next button */}\r\n {!isSingleImage && (\r\n <Button\r\n onClick={next}\r\n disabled={isLastImage}\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"absolute right-4 z-10 h-12 w-12 rounded-full bg-white/10 text-white hover:bg-white/20 focus:ring-white disabled:cursor-not-allowed disabled:opacity-50 md:right-8 md:opacity-0 md:hover:opacity-100\"\r\n aria-label=\"Next image\"\r\n >\r\n <svg\r\n className=\"h-6 w-6\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n viewBox=\"0 0 24 24\"\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n strokeWidth={2}\r\n d=\"M9 5l7 7-7 7\"\r\n />\r\n </svg>\r\n </Button>\r\n )}\r\n\r\n {/* Image counter */}\r\n {!isSingleImage && (\r\n <div className=\"absolute bottom-4 left-1/2 -translate-x-1/2 rounded-full bg-black/50 px-4 py-2 text-sm text-white\">\r\n {currentIndex + 1} / {images.length}\r\n </div>\r\n )}\r\n </div>,\r\n document.body,\r\n )\r\n}\r\n"],"mappings":"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","names":["prev"]}
1
+ {"version":3,"sources":["../../../components/lightbox/ImageLightbox.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useRef, useState, useCallback } from 'react'\nimport { createPortal } from 'react-dom'\nimport { Button } from '../ui/button'\nimport type { ImageLightboxProps } from './ImageLightbox.types'\n\nexport function ImageLightbox({\n images,\n isOpen,\n initialIndex,\n onClose,\n onNavigate,\n}: ImageLightboxProps) {\n const [currentIndex, setCurrentIndex] = useState(initialIndex)\n const [mounted, setMounted] = useState(false)\n const imageRef = useRef<HTMLImageElement>(null)\n\n // Track if component is mounted (client-side only)\n useEffect(() => {\n setMounted(true)\n return () => setMounted(false)\n }, [])\n\n // Sync with initialIndex when lightbox opens\n useEffect(() => {\n if (isOpen) {\n setCurrentIndex(initialIndex)\n }\n }, [isOpen, initialIndex])\n\n // Lock body scroll when open\n useEffect(() => {\n if (isOpen) {\n document.body.style.overflow = 'hidden'\n return () => {\n document.body.style.overflow = ''\n }\n }\n }, [isOpen])\n\n // Navigation handlers\n const next = useCallback(() => {\n setCurrentIndex((prev) => {\n const newIndex = Math.min(prev + 1, images.length - 1)\n if (onNavigate) onNavigate(newIndex)\n return newIndex\n })\n }, [images.length, onNavigate])\n\n const prev = useCallback(() => {\n setCurrentIndex((prev) => {\n const newIndex = Math.max(prev - 1, 0)\n if (onNavigate) onNavigate(newIndex)\n return newIndex\n })\n }, [onNavigate])\n\n // Keyboard navigation\n useEffect(() => {\n if (!isOpen) return\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose()\n if (e.key === 'ArrowLeft') prev()\n if (e.key === 'ArrowRight') next()\n }\n\n window.addEventListener('keydown', handleKeyDown)\n return () => window.removeEventListener('keydown', handleKeyDown)\n }, [isOpen, onClose, prev, next])\n\n // Handle image errors\n const handleImageError = (e: React.SyntheticEvent<HTMLImageElement>) => {\n e.currentTarget.src = '/placeholder-image.png'\n console.error('Failed to load image:', images[currentIndex]?.url)\n }\n\n // Handle swipe gestures\n useEffect(() => {\n if (!isOpen) return\n\n let touchStartX = 0\n let touchEndX = 0\n\n const handleTouchStart = (e: TouchEvent) => {\n touchStartX = e.changedTouches[0].screenX\n }\n\n const handleTouchEnd = (e: TouchEvent) => {\n touchEndX = e.changedTouches[0].screenX\n const swipeDistance = touchStartX - touchEndX\n const minSwipeDistance = 50\n\n if (Math.abs(swipeDistance) > minSwipeDistance) {\n if (swipeDistance > 0 && currentIndex < images.length - 1) {\n next()\n } else if (swipeDistance < 0 && currentIndex > 0) {\n prev()\n }\n }\n }\n\n window.addEventListener('touchstart', handleTouchStart, { passive: true })\n window.addEventListener('touchend', handleTouchEnd, { passive: true })\n\n return () => {\n window.removeEventListener('touchstart', handleTouchStart)\n window.removeEventListener('touchend', handleTouchEnd)\n }\n }, [isOpen, currentIndex, images.length, next, prev])\n\n // Handle backdrop click\n const handleBackdropClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) {\n onClose()\n }\n }\n\n // Empty gallery\n if (!images || images.length === 0) return null\n\n // Not open or not mounted (SSR safety)\n if (!mounted || !isOpen) return null\n\n const currentImage = images[currentIndex]\n const isFirstImage = currentIndex === 0\n const isLastImage = currentIndex === images.length - 1\n const isSingleImage = images.length === 1\n\n return createPortal(\n <div\n className=\"animate-in fade-in fixed inset-0 z-50 flex items-center justify-center bg-black/90 duration-200\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Image lightbox\"\n onClick={handleBackdropClick}\n >\n {/* Close button */}\n <Button\n onClick={onClose}\n variant=\"ghost\"\n size=\"icon\"\n className=\"absolute right-4 top-4 z-10 rounded-full bg-white/10 text-white hover:bg-white/20 focus:ring-white md:h-8 md:w-8\"\n aria-label=\"Close lightbox\"\n >\n <svg\n className=\"h-6 w-6\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </Button>\n\n {/* Previous button */}\n {!isSingleImage && (\n <Button\n onClick={prev}\n disabled={isFirstImage}\n variant=\"ghost\"\n size=\"icon\"\n className=\"absolute left-4 z-10 h-12 w-12 rounded-full bg-white/10 text-white hover:bg-white/20 focus:ring-white disabled:cursor-not-allowed disabled:opacity-50 md:left-8 md:opacity-0 md:hover:opacity-100\"\n aria-label=\"Previous image\"\n >\n <svg\n className=\"h-6 w-6\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M15 19l-7-7 7-7\"\n />\n </svg>\n </Button>\n )}\n\n {/* Image container */}\n <div className=\"relative mx-4 flex max-h-[90vh] max-w-[90vw] items-center justify-center\">\n <img\n ref={imageRef}\n src={currentImage.url}\n alt={currentImage.alt}\n className=\"max-h-[90vh] max-w-[90vw] object-contain transition-opacity duration-150\"\n style={{ touchAction: 'pan-x pan-y pinch-zoom' }}\n onError={handleImageError}\n />\n </div>\n\n {/* Next button */}\n {!isSingleImage && (\n <Button\n onClick={next}\n disabled={isLastImage}\n variant=\"ghost\"\n size=\"icon\"\n className=\"absolute right-4 z-10 h-12 w-12 rounded-full bg-white/10 text-white hover:bg-white/20 focus:ring-white disabled:cursor-not-allowed disabled:opacity-50 md:right-8 md:opacity-0 md:hover:opacity-100\"\n aria-label=\"Next image\"\n >\n <svg\n className=\"h-6 w-6\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 5l7 7-7 7\"\n />\n </svg>\n </Button>\n )}\n\n {/* Image counter */}\n {!isSingleImage && (\n <div className=\"absolute bottom-4 left-1/2 -translate-x-1/2 rounded-full bg-black/50 px-4 py-2 text-sm text-white\">\n {currentIndex + 1} / {images.length}\n </div>\n )}\n </div>,\n document.body,\n )\n}\n"],"mappings":"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","names":["prev"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../components/lightbox/ImageLightbox.types.ts"],"sourcesContent":["export interface EntityImage {\r\n id: number\r\n entityType: 'story' | 'character' | 'location' | 'timeline'\r\n entityId: number\r\n cloudinaryPublicId: string\r\n cloudinaryUrl: string\r\n isPrimary: boolean\r\n displayOrder: number\r\n fileName: string\r\n fileSize: number\r\n width: number\r\n height: number\r\n createdAt: Date\r\n updatedAt: Date\r\n}\r\n\r\nexport interface LightboxImage {\r\n id: number\r\n url: string\r\n alt: string\r\n}\r\n\r\nexport interface ImageLightboxProps {\r\n images: LightboxImage[]\r\n isOpen: boolean\r\n initialIndex: number\r\n onClose: () => void\r\n onNavigate?: (index: number) => void\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../../../components/lightbox/ImageLightbox.types.ts"],"sourcesContent":["export interface EntityImage {\n id: number\n entityType: 'story' | 'character' | 'location' | 'timeline'\n entityId: number\n cloudinaryPublicId: string\n cloudinaryUrl: string\n isPrimary: boolean\n displayOrder: number\n fileName: string\n fileSize: number\n width: number\n height: number\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface LightboxImage {\n id: number\n url: string\n alt: string\n}\n\nexport interface ImageLightboxProps {\n images: LightboxImage[]\n isOpen: boolean\n initialIndex: number\n onClose: () => void\n onNavigate?: (index: number) => void\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../components/lightbox/index.ts"],"sourcesContent":["export type { LightboxImage, ImageLightboxProps } from './ImageLightbox.types'\r\nexport { ImageLightbox } from './ImageLightbox'\r\nexport { useLightbox } from './useLightbox'\r\nexport { useEntityLightbox } from './useEntityLightbox'\r\nexport { GallerySection } from './GallerySection'\r\nexport type {\r\n UseEntityLightboxProps,\r\n UseEntityLightboxReturn,\r\n} from './useEntityLightbox'\r\nexport type { GallerySectionProps } from './GallerySection'\r\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,2BAA8B;AAC9B,yBAA4B;AAC5B,+BAAkC;AAClC,4BAA+B;","names":[]}
1
+ {"version":3,"sources":["../../../components/lightbox/index.ts"],"sourcesContent":["export type { LightboxImage, ImageLightboxProps } from './ImageLightbox.types'\nexport { ImageLightbox } from './ImageLightbox'\nexport { useLightbox } from './useLightbox'\nexport { useEntityLightbox } from './useEntityLightbox'\nexport { GallerySection } from './GallerySection'\nexport type {\n UseEntityLightboxProps,\n UseEntityLightboxReturn,\n} from './useEntityLightbox'\nexport type { GallerySectionProps } from './GallerySection'\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,2BAA8B;AAC9B,yBAA4B;AAC5B,+BAAkC;AAClC,4BAA+B;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../components/lightbox/index.ts"],"sourcesContent":["export type { LightboxImage, ImageLightboxProps } from './ImageLightbox.types'\r\nexport { ImageLightbox } from './ImageLightbox'\r\nexport { useLightbox } from './useLightbox'\r\nexport { useEntityLightbox } from './useEntityLightbox'\r\nexport { GallerySection } from './GallerySection'\r\nexport type {\r\n UseEntityLightboxProps,\r\n UseEntityLightboxReturn,\r\n} from './useEntityLightbox'\r\nexport type { GallerySectionProps } from './GallerySection'\r\n"],"mappings":"AACA,SAAS,qBAAqB;AAC9B,SAAS,mBAAmB;AAC5B,SAAS,yBAAyB;AAClC,SAAS,sBAAsB;","names":[]}
1
+ {"version":3,"sources":["../../../components/lightbox/index.ts"],"sourcesContent":["export type { LightboxImage, ImageLightboxProps } from './ImageLightbox.types'\nexport { ImageLightbox } from './ImageLightbox'\nexport { useLightbox } from './useLightbox'\nexport { useEntityLightbox } from './useEntityLightbox'\nexport { GallerySection } from './GallerySection'\nexport type {\n UseEntityLightboxProps,\n UseEntityLightboxReturn,\n} from './useEntityLightbox'\nexport type { GallerySectionProps } from './GallerySection'\n"],"mappings":"AACA,SAAS,qBAAqB;AAC9B,SAAS,mBAAmB;AAC5B,SAAS,yBAAyB;AAClC,SAAS,sBAAsB;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../components/lightbox/useEntityLightbox.ts"],"sourcesContent":["import { useState } from 'react'\r\nimport type { EntityImage, LightboxImage } from './ImageLightbox.types'\r\n\r\nexport interface UseEntityLightboxProps {\r\n images?: EntityImage[]\r\n entityName: string\r\n}\r\n\r\nexport interface UseEntityLightboxReturn {\r\n lightboxState: {\r\n isOpen: boolean\r\n currentIndex: number\r\n }\r\n handleImageClick: (index: number) => void\r\n handleLightboxClose: () => void\r\n lightboxImages: LightboxImage[]\r\n allImages: EntityImage[]\r\n}\r\n\r\n/**\r\n * Custom hook for managing lightbox state in entity detail components.\r\n * Handles opening, closing, and image mapping for the ImageLightbox component.\r\n *\r\n * @param images - Array of entity images\r\n * @param entityName - Name of the entity (for alt text)\r\n * @returns Lightbox state and handlers\r\n */\r\nexport function useEntityLightbox({\r\n images,\r\n entityName,\r\n}: UseEntityLightboxProps): UseEntityLightboxReturn {\r\n const [lightboxState, setLightboxState] = useState({\r\n isOpen: false,\r\n currentIndex: 0,\r\n })\r\n\r\n const allImages = images || []\r\n\r\n const handleImageClick = (index: number) => {\r\n setLightboxState({ isOpen: true, currentIndex: index })\r\n }\r\n\r\n const handleLightboxClose = () => {\r\n setLightboxState({ isOpen: false, currentIndex: 0 })\r\n }\r\n\r\n const lightboxImages = allImages.map((img) => ({\r\n id: img.id,\r\n url: img.cloudinaryUrl,\r\n alt: `${entityName} - Image ${img.displayOrder + 1}`,\r\n }))\r\n\r\n return {\r\n lightboxState,\r\n handleImageClick,\r\n handleLightboxClose,\r\n lightboxImages,\r\n allImages,\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAyB;AA2BlB,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AACF,GAAoD;AAClD,QAAM,CAAC,eAAe,gBAAgB,QAAI,uBAAS;AAAA,IACjD,QAAQ;AAAA,IACR,cAAc;AAAA,EAChB,CAAC;AAED,QAAM,YAAY,UAAU,CAAC;AAE7B,QAAM,mBAAmB,CAAC,UAAkB;AAC1C,qBAAiB,EAAE,QAAQ,MAAM,cAAc,MAAM,CAAC;AAAA,EACxD;AAEA,QAAM,sBAAsB,MAAM;AAChC,qBAAiB,EAAE,QAAQ,OAAO,cAAc,EAAE,CAAC;AAAA,EACrD;AAEA,QAAM,iBAAiB,UAAU,IAAI,CAAC,SAAS;AAAA,IAC7C,IAAI,IAAI;AAAA,IACR,KAAK,IAAI;AAAA,IACT,KAAK,GAAG,UAAU,YAAY,IAAI,eAAe,CAAC;AAAA,EACpD,EAAE;AAEF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../components/lightbox/useEntityLightbox.ts"],"sourcesContent":["import { useState } from 'react'\nimport type { EntityImage, LightboxImage } from './ImageLightbox.types'\n\nexport interface UseEntityLightboxProps {\n images?: EntityImage[]\n entityName: string\n}\n\nexport interface UseEntityLightboxReturn {\n lightboxState: {\n isOpen: boolean\n currentIndex: number\n }\n handleImageClick: (index: number) => void\n handleLightboxClose: () => void\n lightboxImages: LightboxImage[]\n allImages: EntityImage[]\n}\n\n/**\n * Custom hook for managing lightbox state in entity detail components.\n * Handles opening, closing, and image mapping for the ImageLightbox component.\n *\n * @param images - Array of entity images\n * @param entityName - Name of the entity (for alt text)\n * @returns Lightbox state and handlers\n */\nexport function useEntityLightbox({\n images,\n entityName,\n}: UseEntityLightboxProps): UseEntityLightboxReturn {\n const [lightboxState, setLightboxState] = useState({\n isOpen: false,\n currentIndex: 0,\n })\n\n const allImages = images || []\n\n const handleImageClick = (index: number) => {\n setLightboxState({ isOpen: true, currentIndex: index })\n }\n\n const handleLightboxClose = () => {\n setLightboxState({ isOpen: false, currentIndex: 0 })\n }\n\n const lightboxImages = allImages.map((img) => ({\n id: img.id,\n url: img.cloudinaryUrl,\n alt: `${entityName} - Image ${img.displayOrder + 1}`,\n }))\n\n return {\n lightboxState,\n handleImageClick,\n handleLightboxClose,\n lightboxImages,\n allImages,\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAyB;AA2BlB,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AACF,GAAoD;AAClD,QAAM,CAAC,eAAe,gBAAgB,QAAI,uBAAS;AAAA,IACjD,QAAQ;AAAA,IACR,cAAc;AAAA,EAChB,CAAC;AAED,QAAM,YAAY,UAAU,CAAC;AAE7B,QAAM,mBAAmB,CAAC,UAAkB;AAC1C,qBAAiB,EAAE,QAAQ,MAAM,cAAc,MAAM,CAAC;AAAA,EACxD;AAEA,QAAM,sBAAsB,MAAM;AAChC,qBAAiB,EAAE,QAAQ,OAAO,cAAc,EAAE,CAAC;AAAA,EACrD;AAEA,QAAM,iBAAiB,UAAU,IAAI,CAAC,SAAS;AAAA,IAC7C,IAAI,IAAI;AAAA,IACR,KAAK,IAAI;AAAA,IACT,KAAK,GAAG,UAAU,YAAY,IAAI,eAAe,CAAC;AAAA,EACpD,EAAE;AAEF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../components/lightbox/useEntityLightbox.ts"],"sourcesContent":["import { useState } from 'react'\r\nimport type { EntityImage, LightboxImage } from './ImageLightbox.types'\r\n\r\nexport interface UseEntityLightboxProps {\r\n images?: EntityImage[]\r\n entityName: string\r\n}\r\n\r\nexport interface UseEntityLightboxReturn {\r\n lightboxState: {\r\n isOpen: boolean\r\n currentIndex: number\r\n }\r\n handleImageClick: (index: number) => void\r\n handleLightboxClose: () => void\r\n lightboxImages: LightboxImage[]\r\n allImages: EntityImage[]\r\n}\r\n\r\n/**\r\n * Custom hook for managing lightbox state in entity detail components.\r\n * Handles opening, closing, and image mapping for the ImageLightbox component.\r\n *\r\n * @param images - Array of entity images\r\n * @param entityName - Name of the entity (for alt text)\r\n * @returns Lightbox state and handlers\r\n */\r\nexport function useEntityLightbox({\r\n images,\r\n entityName,\r\n}: UseEntityLightboxProps): UseEntityLightboxReturn {\r\n const [lightboxState, setLightboxState] = useState({\r\n isOpen: false,\r\n currentIndex: 0,\r\n })\r\n\r\n const allImages = images || []\r\n\r\n const handleImageClick = (index: number) => {\r\n setLightboxState({ isOpen: true, currentIndex: index })\r\n }\r\n\r\n const handleLightboxClose = () => {\r\n setLightboxState({ isOpen: false, currentIndex: 0 })\r\n }\r\n\r\n const lightboxImages = allImages.map((img) => ({\r\n id: img.id,\r\n url: img.cloudinaryUrl,\r\n alt: `${entityName} - Image ${img.displayOrder + 1}`,\r\n }))\r\n\r\n return {\r\n lightboxState,\r\n handleImageClick,\r\n handleLightboxClose,\r\n lightboxImages,\r\n allImages,\r\n }\r\n}\r\n"],"mappings":"AAAA,SAAS,gBAAgB;AA2BlB,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AACF,GAAoD;AAClD,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS;AAAA,IACjD,QAAQ;AAAA,IACR,cAAc;AAAA,EAChB,CAAC;AAED,QAAM,YAAY,UAAU,CAAC;AAE7B,QAAM,mBAAmB,CAAC,UAAkB;AAC1C,qBAAiB,EAAE,QAAQ,MAAM,cAAc,MAAM,CAAC;AAAA,EACxD;AAEA,QAAM,sBAAsB,MAAM;AAChC,qBAAiB,EAAE,QAAQ,OAAO,cAAc,EAAE,CAAC;AAAA,EACrD;AAEA,QAAM,iBAAiB,UAAU,IAAI,CAAC,SAAS;AAAA,IAC7C,IAAI,IAAI;AAAA,IACR,KAAK,IAAI;AAAA,IACT,KAAK,GAAG,UAAU,YAAY,IAAI,eAAe,CAAC;AAAA,EACpD,EAAE;AAEF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../components/lightbox/useEntityLightbox.ts"],"sourcesContent":["import { useState } from 'react'\nimport type { EntityImage, LightboxImage } from './ImageLightbox.types'\n\nexport interface UseEntityLightboxProps {\n images?: EntityImage[]\n entityName: string\n}\n\nexport interface UseEntityLightboxReturn {\n lightboxState: {\n isOpen: boolean\n currentIndex: number\n }\n handleImageClick: (index: number) => void\n handleLightboxClose: () => void\n lightboxImages: LightboxImage[]\n allImages: EntityImage[]\n}\n\n/**\n * Custom hook for managing lightbox state in entity detail components.\n * Handles opening, closing, and image mapping for the ImageLightbox component.\n *\n * @param images - Array of entity images\n * @param entityName - Name of the entity (for alt text)\n * @returns Lightbox state and handlers\n */\nexport function useEntityLightbox({\n images,\n entityName,\n}: UseEntityLightboxProps): UseEntityLightboxReturn {\n const [lightboxState, setLightboxState] = useState({\n isOpen: false,\n currentIndex: 0,\n })\n\n const allImages = images || []\n\n const handleImageClick = (index: number) => {\n setLightboxState({ isOpen: true, currentIndex: index })\n }\n\n const handleLightboxClose = () => {\n setLightboxState({ isOpen: false, currentIndex: 0 })\n }\n\n const lightboxImages = allImages.map((img) => ({\n id: img.id,\n url: img.cloudinaryUrl,\n alt: `${entityName} - Image ${img.displayOrder + 1}`,\n }))\n\n return {\n lightboxState,\n handleImageClick,\n handleLightboxClose,\n lightboxImages,\n allImages,\n }\n}\n"],"mappings":"AAAA,SAAS,gBAAgB;AA2BlB,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AACF,GAAoD;AAClD,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS;AAAA,IACjD,QAAQ;AAAA,IACR,cAAc;AAAA,EAChB,CAAC;AAED,QAAM,YAAY,UAAU,CAAC;AAE7B,QAAM,mBAAmB,CAAC,UAAkB;AAC1C,qBAAiB,EAAE,QAAQ,MAAM,cAAc,MAAM,CAAC;AAAA,EACxD;AAEA,QAAM,sBAAsB,MAAM;AAChC,qBAAiB,EAAE,QAAQ,OAAO,cAAc,EAAE,CAAC;AAAA,EACrD;AAEA,QAAM,iBAAiB,UAAU,IAAI,CAAC,SAAS;AAAA,IAC7C,IAAI,IAAI;AAAA,IACR,KAAK,IAAI;AAAA,IACT,KAAK,GAAG,UAAU,YAAY,IAAI,eAAe,CAAC;AAAA,EACpD,EAAE;AAEF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../components/lightbox/useLightbox.ts"],"sourcesContent":["import { useState, useCallback, useEffect } from 'react'\r\n\r\nexport function useLightbox(totalImages: number) {\r\n const [isOpen, setIsOpen] = useState(false)\r\n const [currentIndex, setCurrentIndex] = useState(0)\r\n\r\n const open = useCallback((index: number) => {\r\n setCurrentIndex(index)\r\n setIsOpen(true)\r\n document.body.style.overflow = 'hidden'\r\n }, [])\r\n\r\n const close = useCallback(() => {\r\n setIsOpen(false)\r\n document.body.style.overflow = ''\r\n }, [])\r\n\r\n const next = useCallback(() => {\r\n setCurrentIndex((prev) => Math.min(prev + 1, totalImages - 1))\r\n }, [totalImages])\r\n\r\n const prev = useCallback(() => {\r\n setCurrentIndex((prev) => Math.max(prev - 1, 0))\r\n }, [])\r\n\r\n useEffect(() => {\r\n if (!isOpen) return\r\n\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape') close()\r\n if (e.key === 'ArrowLeft') prev()\r\n if (e.key === 'ArrowRight') next()\r\n }\r\n\r\n window.addEventListener('keydown', handleKeyDown)\r\n return () => window.removeEventListener('keydown', handleKeyDown)\r\n }, [isOpen, close, prev, next])\r\n\r\n return { isOpen, currentIndex, open, close, next, prev }\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAiD;AAE1C,SAAS,YAAY,aAAqB;AAC/C,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,KAAK;AAC1C,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAS,CAAC;AAElD,QAAM,WAAO,0BAAY,CAAC,UAAkB;AAC1C,oBAAgB,KAAK;AACrB,cAAU,IAAI;AACd,aAAS,KAAK,MAAM,WAAW;AAAA,EACjC,GAAG,CAAC,CAAC;AAEL,QAAM,YAAQ,0BAAY,MAAM;AAC9B,cAAU,KAAK;AACf,aAAS,KAAK,MAAM,WAAW;AAAA,EACjC,GAAG,CAAC,CAAC;AAEL,QAAM,WAAO,0BAAY,MAAM;AAC7B,oBAAgB,CAACA,UAAS,KAAK,IAAIA,QAAO,GAAG,cAAc,CAAC,CAAC;AAAA,EAC/D,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,WAAO,0BAAY,MAAM;AAC7B,oBAAgB,CAACA,UAAS,KAAK,IAAIA,QAAO,GAAG,CAAC,CAAC;AAAA,EACjD,GAAG,CAAC,CAAC;AAEL,8BAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AAEb,UAAM,gBAAgB,CAAC,MAAqB;AAC1C,UAAI,EAAE,QAAQ,SAAU,OAAM;AAC9B,UAAI,EAAE,QAAQ,YAAa,MAAK;AAChC,UAAI,EAAE,QAAQ,aAAc,MAAK;AAAA,IACnC;AAEA,WAAO,iBAAiB,WAAW,aAAa;AAChD,WAAO,MAAM,OAAO,oBAAoB,WAAW,aAAa;AAAA,EAClE,GAAG,CAAC,QAAQ,OAAO,MAAM,IAAI,CAAC;AAE9B,SAAO,EAAE,QAAQ,cAAc,MAAM,OAAO,MAAM,KAAK;AACzD;","names":["prev"]}
1
+ {"version":3,"sources":["../../../components/lightbox/useLightbox.ts"],"sourcesContent":["import { useState, useCallback, useEffect } from 'react'\n\nexport function useLightbox(totalImages: number) {\n const [isOpen, setIsOpen] = useState(false)\n const [currentIndex, setCurrentIndex] = useState(0)\n\n const open = useCallback((index: number) => {\n setCurrentIndex(index)\n setIsOpen(true)\n document.body.style.overflow = 'hidden'\n }, [])\n\n const close = useCallback(() => {\n setIsOpen(false)\n document.body.style.overflow = ''\n }, [])\n\n const next = useCallback(() => {\n setCurrentIndex((prev) => Math.min(prev + 1, totalImages - 1))\n }, [totalImages])\n\n const prev = useCallback(() => {\n setCurrentIndex((prev) => Math.max(prev - 1, 0))\n }, [])\n\n useEffect(() => {\n if (!isOpen) return\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') close()\n if (e.key === 'ArrowLeft') prev()\n if (e.key === 'ArrowRight') next()\n }\n\n window.addEventListener('keydown', handleKeyDown)\n return () => window.removeEventListener('keydown', handleKeyDown)\n }, [isOpen, close, prev, next])\n\n return { isOpen, currentIndex, open, close, next, prev }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAiD;AAE1C,SAAS,YAAY,aAAqB;AAC/C,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,KAAK;AAC1C,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAS,CAAC;AAElD,QAAM,WAAO,0BAAY,CAAC,UAAkB;AAC1C,oBAAgB,KAAK;AACrB,cAAU,IAAI;AACd,aAAS,KAAK,MAAM,WAAW;AAAA,EACjC,GAAG,CAAC,CAAC;AAEL,QAAM,YAAQ,0BAAY,MAAM;AAC9B,cAAU,KAAK;AACf,aAAS,KAAK,MAAM,WAAW;AAAA,EACjC,GAAG,CAAC,CAAC;AAEL,QAAM,WAAO,0BAAY,MAAM;AAC7B,oBAAgB,CAACA,UAAS,KAAK,IAAIA,QAAO,GAAG,cAAc,CAAC,CAAC;AAAA,EAC/D,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,WAAO,0BAAY,MAAM;AAC7B,oBAAgB,CAACA,UAAS,KAAK,IAAIA,QAAO,GAAG,CAAC,CAAC;AAAA,EACjD,GAAG,CAAC,CAAC;AAEL,8BAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AAEb,UAAM,gBAAgB,CAAC,MAAqB;AAC1C,UAAI,EAAE,QAAQ,SAAU,OAAM;AAC9B,UAAI,EAAE,QAAQ,YAAa,MAAK;AAChC,UAAI,EAAE,QAAQ,aAAc,MAAK;AAAA,IACnC;AAEA,WAAO,iBAAiB,WAAW,aAAa;AAChD,WAAO,MAAM,OAAO,oBAAoB,WAAW,aAAa;AAAA,EAClE,GAAG,CAAC,QAAQ,OAAO,MAAM,IAAI,CAAC;AAE9B,SAAO,EAAE,QAAQ,cAAc,MAAM,OAAO,MAAM,KAAK;AACzD;","names":["prev"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../components/lightbox/useLightbox.ts"],"sourcesContent":["import { useState, useCallback, useEffect } from 'react'\r\n\r\nexport function useLightbox(totalImages: number) {\r\n const [isOpen, setIsOpen] = useState(false)\r\n const [currentIndex, setCurrentIndex] = useState(0)\r\n\r\n const open = useCallback((index: number) => {\r\n setCurrentIndex(index)\r\n setIsOpen(true)\r\n document.body.style.overflow = 'hidden'\r\n }, [])\r\n\r\n const close = useCallback(() => {\r\n setIsOpen(false)\r\n document.body.style.overflow = ''\r\n }, [])\r\n\r\n const next = useCallback(() => {\r\n setCurrentIndex((prev) => Math.min(prev + 1, totalImages - 1))\r\n }, [totalImages])\r\n\r\n const prev = useCallback(() => {\r\n setCurrentIndex((prev) => Math.max(prev - 1, 0))\r\n }, [])\r\n\r\n useEffect(() => {\r\n if (!isOpen) return\r\n\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape') close()\r\n if (e.key === 'ArrowLeft') prev()\r\n if (e.key === 'ArrowRight') next()\r\n }\r\n\r\n window.addEventListener('keydown', handleKeyDown)\r\n return () => window.removeEventListener('keydown', handleKeyDown)\r\n }, [isOpen, close, prev, next])\r\n\r\n return { isOpen, currentIndex, open, close, next, prev }\r\n}\r\n"],"mappings":"AAAA,SAAS,UAAU,aAAa,iBAAiB;AAE1C,SAAS,YAAY,aAAqB;AAC/C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,CAAC;AAElD,QAAM,OAAO,YAAY,CAAC,UAAkB;AAC1C,oBAAgB,KAAK;AACrB,cAAU,IAAI;AACd,aAAS,KAAK,MAAM,WAAW;AAAA,EACjC,GAAG,CAAC,CAAC;AAEL,QAAM,QAAQ,YAAY,MAAM;AAC9B,cAAU,KAAK;AACf,aAAS,KAAK,MAAM,WAAW;AAAA,EACjC,GAAG,CAAC,CAAC;AAEL,QAAM,OAAO,YAAY,MAAM;AAC7B,oBAAgB,CAACA,UAAS,KAAK,IAAIA,QAAO,GAAG,cAAc,CAAC,CAAC;AAAA,EAC/D,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,OAAO,YAAY,MAAM;AAC7B,oBAAgB,CAACA,UAAS,KAAK,IAAIA,QAAO,GAAG,CAAC,CAAC;AAAA,EACjD,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AAEb,UAAM,gBAAgB,CAAC,MAAqB;AAC1C,UAAI,EAAE,QAAQ,SAAU,OAAM;AAC9B,UAAI,EAAE,QAAQ,YAAa,MAAK;AAChC,UAAI,EAAE,QAAQ,aAAc,MAAK;AAAA,IACnC;AAEA,WAAO,iBAAiB,WAAW,aAAa;AAChD,WAAO,MAAM,OAAO,oBAAoB,WAAW,aAAa;AAAA,EAClE,GAAG,CAAC,QAAQ,OAAO,MAAM,IAAI,CAAC;AAE9B,SAAO,EAAE,QAAQ,cAAc,MAAM,OAAO,MAAM,KAAK;AACzD;","names":["prev"]}
1
+ {"version":3,"sources":["../../../components/lightbox/useLightbox.ts"],"sourcesContent":["import { useState, useCallback, useEffect } from 'react'\n\nexport function useLightbox(totalImages: number) {\n const [isOpen, setIsOpen] = useState(false)\n const [currentIndex, setCurrentIndex] = useState(0)\n\n const open = useCallback((index: number) => {\n setCurrentIndex(index)\n setIsOpen(true)\n document.body.style.overflow = 'hidden'\n }, [])\n\n const close = useCallback(() => {\n setIsOpen(false)\n document.body.style.overflow = ''\n }, [])\n\n const next = useCallback(() => {\n setCurrentIndex((prev) => Math.min(prev + 1, totalImages - 1))\n }, [totalImages])\n\n const prev = useCallback(() => {\n setCurrentIndex((prev) => Math.max(prev - 1, 0))\n }, [])\n\n useEffect(() => {\n if (!isOpen) return\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') close()\n if (e.key === 'ArrowLeft') prev()\n if (e.key === 'ArrowRight') next()\n }\n\n window.addEventListener('keydown', handleKeyDown)\n return () => window.removeEventListener('keydown', handleKeyDown)\n }, [isOpen, close, prev, next])\n\n return { isOpen, currentIndex, open, close, next, prev }\n}\n"],"mappings":"AAAA,SAAS,UAAU,aAAa,iBAAiB;AAE1C,SAAS,YAAY,aAAqB;AAC/C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,CAAC;AAElD,QAAM,OAAO,YAAY,CAAC,UAAkB;AAC1C,oBAAgB,KAAK;AACrB,cAAU,IAAI;AACd,aAAS,KAAK,MAAM,WAAW;AAAA,EACjC,GAAG,CAAC,CAAC;AAEL,QAAM,QAAQ,YAAY,MAAM;AAC9B,cAAU,KAAK;AACf,aAAS,KAAK,MAAM,WAAW;AAAA,EACjC,GAAG,CAAC,CAAC;AAEL,QAAM,OAAO,YAAY,MAAM;AAC7B,oBAAgB,CAACA,UAAS,KAAK,IAAIA,QAAO,GAAG,cAAc,CAAC,CAAC;AAAA,EAC/D,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,OAAO,YAAY,MAAM;AAC7B,oBAAgB,CAACA,UAAS,KAAK,IAAIA,QAAO,GAAG,CAAC,CAAC;AAAA,EACjD,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AAEb,UAAM,gBAAgB,CAAC,MAAqB;AAC1C,UAAI,EAAE,QAAQ,SAAU,OAAM;AAC9B,UAAI,EAAE,QAAQ,YAAa,MAAK;AAChC,UAAI,EAAE,QAAQ,aAAc,MAAK;AAAA,IACnC;AAEA,WAAO,iBAAiB,WAAW,aAAa;AAChD,WAAO,MAAM,OAAO,oBAAoB,WAAW,aAAa;AAAA,EAClE,GAAG,CAAC,QAAQ,OAAO,MAAM,IAAI,CAAC;AAE9B,SAAO,EAAE,QAAQ,cAAc,MAAM,OAAO,MAAM,KAAK;AACzD;","names":["prev"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../components/search/search.tsx"],"sourcesContent":["import {\r\n Calculator,\r\n Calendar,\r\n CreditCard,\r\n Settings,\r\n Smile,\r\n User,\r\n} from 'lucide-react'\r\n\r\nimport {\r\n Command,\r\n CommandEmpty,\r\n CommandGroup,\r\n CommandInput,\r\n CommandItem,\r\n CommandList,\r\n CommandSeparator,\r\n CommandShortcut,\r\n} from '../ui/command'\r\n\r\nexport const Search = ({ className }: React.HTMLAttributes<HTMLDivElement>) => {\r\n return (\r\n <Command className={className}>\r\n <CommandInput placeholder=\"Type a command or search...\" />\r\n <CommandList>\r\n <CommandEmpty>No results found.</CommandEmpty>\r\n <CommandGroup heading=\"Suggestions\">\r\n <CommandItem>\r\n <Calendar className=\"mr-2 h-4 w-4\" />\r\n <span>Calendar</span>\r\n </CommandItem>\r\n <CommandItem>\r\n <Smile className=\"mr-2 h-4 w-4\" />\r\n <span>Search Emoji</span>\r\n </CommandItem>\r\n <CommandItem>\r\n <Calculator className=\"mr-2 h-4 w-4\" />\r\n <span>Calculator</span>\r\n </CommandItem>\r\n </CommandGroup>\r\n <CommandSeparator />\r\n <CommandGroup heading=\"Settings\">\r\n <CommandItem>\r\n <User className=\"mr-2 h-4 w-4\" />\r\n <span>Profile</span>\r\n <CommandShortcut>⌘P</CommandShortcut>\r\n </CommandItem>\r\n <CommandItem>\r\n <CreditCard className=\"mr-2 h-4 w-4\" />\r\n <span>Billing</span>\r\n <CommandShortcut>⌘B</CommandShortcut>\r\n </CommandItem>\r\n <CommandItem>\r\n <Settings className=\"mr-2 h-4 w-4\" />\r\n <span>Settings</span>\r\n <CommandShortcut>⌘S</CommandShortcut>\r\n </CommandItem>\r\n </CommandGroup>\r\n </CommandList>\r\n </Command>\r\n )\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBM;AAvBN,0BAOO;AAEP,qBASO;AAEA,MAAM,SAAS,CAAC,EAAE,UAAU,MAA4C;AAC7E,SACE,6CAAC,0BAAQ,WACP;AAAA,gDAAC,+BAAa,aAAY,+BAA8B;AAAA,IACxD,6CAAC,8BACC;AAAA,kDAAC,+BAAa,+BAAiB;AAAA,MAC/B,6CAAC,+BAAa,SAAQ,eACpB;AAAA,qDAAC,8BACC;AAAA,sDAAC,gCAAS,WAAU,gBAAe;AAAA,UACnC,4CAAC,UAAK,sBAAQ;AAAA,WAChB;AAAA,QACA,6CAAC,8BACC;AAAA,sDAAC,6BAAM,WAAU,gBAAe;AAAA,UAChC,4CAAC,UAAK,0BAAY;AAAA,WACpB;AAAA,QACA,6CAAC,8BACC;AAAA,sDAAC,kCAAW,WAAU,gBAAe;AAAA,UACrC,4CAAC,UAAK,wBAAU;AAAA,WAClB;AAAA,SACF;AAAA,MACA,4CAAC,mCAAiB;AAAA,MAClB,6CAAC,+BAAa,SAAQ,YACpB;AAAA,qDAAC,8BACC;AAAA,sDAAC,4BAAK,WAAU,gBAAe;AAAA,UAC/B,4CAAC,UAAK,qBAAO;AAAA,UACb,4CAAC,kCAAgB,qBAAE;AAAA,WACrB;AAAA,QACA,6CAAC,8BACC;AAAA,sDAAC,kCAAW,WAAU,gBAAe;AAAA,UACrC,4CAAC,UAAK,qBAAO;AAAA,UACb,4CAAC,kCAAgB,qBAAE;AAAA,WACrB;AAAA,QACA,6CAAC,8BACC;AAAA,sDAAC,gCAAS,WAAU,gBAAe;AAAA,UACnC,4CAAC,UAAK,sBAAQ;AAAA,UACd,4CAAC,kCAAgB,qBAAE;AAAA,WACrB;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../components/search/search.tsx"],"sourcesContent":["import {\n Calculator,\n Calendar,\n CreditCard,\n Settings,\n Smile,\n User,\n} from 'lucide-react'\n\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n CommandShortcut,\n} from '../ui/command'\n\nexport const Search = ({ className }: React.HTMLAttributes<HTMLDivElement>) => {\n return (\n <Command className={className}>\n <CommandInput placeholder=\"Type a command or search...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup heading=\"Suggestions\">\n <CommandItem>\n <Calendar className=\"mr-2 h-4 w-4\" />\n <span>Calendar</span>\n </CommandItem>\n <CommandItem>\n <Smile className=\"mr-2 h-4 w-4\" />\n <span>Search Emoji</span>\n </CommandItem>\n <CommandItem>\n <Calculator className=\"mr-2 h-4 w-4\" />\n <span>Calculator</span>\n </CommandItem>\n </CommandGroup>\n <CommandSeparator />\n <CommandGroup heading=\"Settings\">\n <CommandItem>\n <User className=\"mr-2 h-4 w-4\" />\n <span>Profile</span>\n <CommandShortcut>⌘P</CommandShortcut>\n </CommandItem>\n <CommandItem>\n <CreditCard className=\"mr-2 h-4 w-4\" />\n <span>Billing</span>\n <CommandShortcut>⌘B</CommandShortcut>\n </CommandItem>\n <CommandItem>\n <Settings className=\"mr-2 h-4 w-4\" />\n <span>Settings</span>\n <CommandShortcut>⌘S</CommandShortcut>\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBM;AAvBN,0BAOO;AAEP,qBASO;AAEA,MAAM,SAAS,CAAC,EAAE,UAAU,MAA4C;AAC7E,SACE,6CAAC,0BAAQ,WACP;AAAA,gDAAC,+BAAa,aAAY,+BAA8B;AAAA,IACxD,6CAAC,8BACC;AAAA,kDAAC,+BAAa,+BAAiB;AAAA,MAC/B,6CAAC,+BAAa,SAAQ,eACpB;AAAA,qDAAC,8BACC;AAAA,sDAAC,gCAAS,WAAU,gBAAe;AAAA,UACnC,4CAAC,UAAK,sBAAQ;AAAA,WAChB;AAAA,QACA,6CAAC,8BACC;AAAA,sDAAC,6BAAM,WAAU,gBAAe;AAAA,UAChC,4CAAC,UAAK,0BAAY;AAAA,WACpB;AAAA,QACA,6CAAC,8BACC;AAAA,sDAAC,kCAAW,WAAU,gBAAe;AAAA,UACrC,4CAAC,UAAK,wBAAU;AAAA,WAClB;AAAA,SACF;AAAA,MACA,4CAAC,mCAAiB;AAAA,MAClB,6CAAC,+BAAa,SAAQ,YACpB;AAAA,qDAAC,8BACC;AAAA,sDAAC,4BAAK,WAAU,gBAAe;AAAA,UAC/B,4CAAC,UAAK,qBAAO;AAAA,UACb,4CAAC,kCAAgB,qBAAE;AAAA,WACrB;AAAA,QACA,6CAAC,8BACC;AAAA,sDAAC,kCAAW,WAAU,gBAAe;AAAA,UACrC,4CAAC,UAAK,qBAAO;AAAA,UACb,4CAAC,kCAAgB,qBAAE;AAAA,WACrB;AAAA,QACA,6CAAC,8BACC;AAAA,sDAAC,gCAAS,WAAU,gBAAe;AAAA,UACnC,4CAAC,UAAK,sBAAQ;AAAA,UACd,4CAAC,kCAAgB,qBAAE;AAAA,WACrB;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAEJ;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../components/search/search.tsx"],"sourcesContent":["import {\r\n Calculator,\r\n Calendar,\r\n CreditCard,\r\n Settings,\r\n Smile,\r\n User,\r\n} from 'lucide-react'\r\n\r\nimport {\r\n Command,\r\n CommandEmpty,\r\n CommandGroup,\r\n CommandInput,\r\n CommandItem,\r\n CommandList,\r\n CommandSeparator,\r\n CommandShortcut,\r\n} from '../ui/command'\r\n\r\nexport const Search = ({ className }: React.HTMLAttributes<HTMLDivElement>) => {\r\n return (\r\n <Command className={className}>\r\n <CommandInput placeholder=\"Type a command or search...\" />\r\n <CommandList>\r\n <CommandEmpty>No results found.</CommandEmpty>\r\n <CommandGroup heading=\"Suggestions\">\r\n <CommandItem>\r\n <Calendar className=\"mr-2 h-4 w-4\" />\r\n <span>Calendar</span>\r\n </CommandItem>\r\n <CommandItem>\r\n <Smile className=\"mr-2 h-4 w-4\" />\r\n <span>Search Emoji</span>\r\n </CommandItem>\r\n <CommandItem>\r\n <Calculator className=\"mr-2 h-4 w-4\" />\r\n <span>Calculator</span>\r\n </CommandItem>\r\n </CommandGroup>\r\n <CommandSeparator />\r\n <CommandGroup heading=\"Settings\">\r\n <CommandItem>\r\n <User className=\"mr-2 h-4 w-4\" />\r\n <span>Profile</span>\r\n <CommandShortcut>⌘P</CommandShortcut>\r\n </CommandItem>\r\n <CommandItem>\r\n <CreditCard className=\"mr-2 h-4 w-4\" />\r\n <span>Billing</span>\r\n <CommandShortcut>⌘B</CommandShortcut>\r\n </CommandItem>\r\n <CommandItem>\r\n <Settings className=\"mr-2 h-4 w-4\" />\r\n <span>Settings</span>\r\n <CommandShortcut>⌘S</CommandShortcut>\r\n </CommandItem>\r\n </CommandGroup>\r\n </CommandList>\r\n </Command>\r\n )\r\n}\r\n"],"mappings":"AAuBM,cAII,YAJJ;AAvBN;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,MAAM,SAAS,CAAC,EAAE,UAAU,MAA4C;AAC7E,SACE,qBAAC,WAAQ,WACP;AAAA,wBAAC,gBAAa,aAAY,+BAA8B;AAAA,IACxD,qBAAC,eACC;AAAA,0BAAC,gBAAa,+BAAiB;AAAA,MAC/B,qBAAC,gBAAa,SAAQ,eACpB;AAAA,6BAAC,eACC;AAAA,8BAAC,YAAS,WAAU,gBAAe;AAAA,UACnC,oBAAC,UAAK,sBAAQ;AAAA,WAChB;AAAA,QACA,qBAAC,eACC;AAAA,8BAAC,SAAM,WAAU,gBAAe;AAAA,UAChC,oBAAC,UAAK,0BAAY;AAAA,WACpB;AAAA,QACA,qBAAC,eACC;AAAA,8BAAC,cAAW,WAAU,gBAAe;AAAA,UACrC,oBAAC,UAAK,wBAAU;AAAA,WAClB;AAAA,SACF;AAAA,MACA,oBAAC,oBAAiB;AAAA,MAClB,qBAAC,gBAAa,SAAQ,YACpB;AAAA,6BAAC,eACC;AAAA,8BAAC,QAAK,WAAU,gBAAe;AAAA,UAC/B,oBAAC,UAAK,qBAAO;AAAA,UACb,oBAAC,mBAAgB,qBAAE;AAAA,WACrB;AAAA,QACA,qBAAC,eACC;AAAA,8BAAC,cAAW,WAAU,gBAAe;AAAA,UACrC,oBAAC,UAAK,qBAAO;AAAA,UACb,oBAAC,mBAAgB,qBAAE;AAAA,WACrB;AAAA,QACA,qBAAC,eACC;AAAA,8BAAC,YAAS,WAAU,gBAAe;AAAA,UACnC,oBAAC,UAAK,sBAAQ;AAAA,UACd,oBAAC,mBAAgB,qBAAE;AAAA,WACrB;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../components/search/search.tsx"],"sourcesContent":["import {\n Calculator,\n Calendar,\n CreditCard,\n Settings,\n Smile,\n User,\n} from 'lucide-react'\n\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n CommandShortcut,\n} from '../ui/command'\n\nexport const Search = ({ className }: React.HTMLAttributes<HTMLDivElement>) => {\n return (\n <Command className={className}>\n <CommandInput placeholder=\"Type a command or search...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup heading=\"Suggestions\">\n <CommandItem>\n <Calendar className=\"mr-2 h-4 w-4\" />\n <span>Calendar</span>\n </CommandItem>\n <CommandItem>\n <Smile className=\"mr-2 h-4 w-4\" />\n <span>Search Emoji</span>\n </CommandItem>\n <CommandItem>\n <Calculator className=\"mr-2 h-4 w-4\" />\n <span>Calculator</span>\n </CommandItem>\n </CommandGroup>\n <CommandSeparator />\n <CommandGroup heading=\"Settings\">\n <CommandItem>\n <User className=\"mr-2 h-4 w-4\" />\n <span>Profile</span>\n <CommandShortcut>⌘P</CommandShortcut>\n </CommandItem>\n <CommandItem>\n <CreditCard className=\"mr-2 h-4 w-4\" />\n <span>Billing</span>\n <CommandShortcut>⌘B</CommandShortcut>\n </CommandItem>\n <CommandItem>\n <Settings className=\"mr-2 h-4 w-4\" />\n <span>Settings</span>\n <CommandShortcut>⌘S</CommandShortcut>\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n )\n}\n"],"mappings":"AAuBM,cAII,YAJJ;AAvBN;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,MAAM,SAAS,CAAC,EAAE,UAAU,MAA4C;AAC7E,SACE,qBAAC,WAAQ,WACP;AAAA,wBAAC,gBAAa,aAAY,+BAA8B;AAAA,IACxD,qBAAC,eACC;AAAA,0BAAC,gBAAa,+BAAiB;AAAA,MAC/B,qBAAC,gBAAa,SAAQ,eACpB;AAAA,6BAAC,eACC;AAAA,8BAAC,YAAS,WAAU,gBAAe;AAAA,UACnC,oBAAC,UAAK,sBAAQ;AAAA,WAChB;AAAA,QACA,qBAAC,eACC;AAAA,8BAAC,SAAM,WAAU,gBAAe;AAAA,UAChC,oBAAC,UAAK,0BAAY;AAAA,WACpB;AAAA,QACA,qBAAC,eACC;AAAA,8BAAC,cAAW,WAAU,gBAAe;AAAA,UACrC,oBAAC,UAAK,wBAAU;AAAA,WAClB;AAAA,SACF;AAAA,MACA,oBAAC,oBAAiB;AAAA,MAClB,qBAAC,gBAAa,SAAQ,YACpB;AAAA,6BAAC,eACC;AAAA,8BAAC,QAAK,WAAU,gBAAe;AAAA,UAC/B,oBAAC,UAAK,qBAAO;AAAA,UACb,oBAAC,mBAAgB,qBAAE;AAAA,WACrB;AAAA,QACA,qBAAC,eACC;AAAA,8BAAC,cAAW,WAAU,gBAAe;AAAA,UACrC,oBAAC,UAAK,qBAAO;AAAA,UACb,oBAAC,mBAAgB,qBAAE;AAAA,WACrB;AAAA,QACA,qBAAC,eACC;AAAA,8BAAC,YAAS,WAAU,gBAAe;AAAA,UACnC,oBAAC,UAAK,sBAAQ;AAAA,UACd,oBAAC,mBAAgB,qBAAE;AAAA,WACrB;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAEJ;","names":[]}
@@ -145,7 +145,7 @@ const Contact = () => {
145
145
  autoComplete: "given-name",
146
146
  required: true,
147
147
  disabled: status === "loading",
148
- className: "focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-white/5 px-3 py-1.5 text-base text-white ring-1 ring-inset ring-white/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full"
148
+ className: "focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-gray-900/5 px-3 py-1.5 text-base text-gray-900 ring-1 ring-inset ring-gray-900/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full dark:bg-white/5 dark:text-white dark:ring-white/10"
149
149
  }
150
150
  ) })
151
151
  ] }),
@@ -167,7 +167,7 @@ const Contact = () => {
167
167
  autoComplete: "family-name",
168
168
  required: true,
169
169
  disabled: status === "loading",
170
- className: "focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-white/5 px-3 py-1.5 text-base text-white ring-1 ring-inset ring-white/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full"
170
+ className: "focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-gray-900/5 px-3 py-1.5 text-base text-gray-900 ring-1 ring-inset ring-gray-900/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full dark:bg-white/5 dark:text-white dark:ring-white/10"
171
171
  }
172
172
  ) })
173
173
  ] }),
@@ -188,7 +188,7 @@ const Contact = () => {
188
188
  id: "company",
189
189
  autoComplete: "organization",
190
190
  disabled: status === "loading",
191
- className: "focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-white/5 px-3 py-1.5 text-base text-white ring-1 ring-inset ring-white/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full"
191
+ className: "focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-gray-900/5 px-3 py-1.5 text-base text-gray-900 ring-1 ring-inset ring-gray-900/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full dark:bg-white/5 dark:text-white dark:ring-white/10"
192
192
  }
193
193
  ) })
194
194
  ] }),
@@ -210,7 +210,7 @@ const Contact = () => {
210
210
  autoComplete: "email",
211
211
  required: true,
212
212
  disabled: status === "loading",
213
- className: "focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-white/5 px-3 py-1.5 text-base text-white ring-1 ring-inset ring-white/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full"
213
+ className: "focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-gray-900/5 px-3 py-1.5 text-base text-gray-900 ring-1 ring-inset ring-gray-900/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full dark:bg-white/5 dark:text-white dark:ring-white/10"
214
214
  }
215
215
  ) })
216
216
  ] }),
@@ -256,7 +256,7 @@ const Contact = () => {
256
256
  id: "phone-number",
257
257
  autoComplete: "tel",
258
258
  disabled: status === "loading",
259
- className: "focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-white/5 px-3 py-1.5 text-base text-white ring-1 ring-inset ring-white/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full"
259
+ className: "focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-gray-900/5 px-3 py-1.5 text-base text-gray-900 ring-1 ring-inset ring-gray-900/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full dark:bg-white/5 dark:text-white dark:ring-white/10"
260
260
  }
261
261
  )
262
262
  ] })
@@ -278,7 +278,7 @@ const Contact = () => {
278
278
  rows: 4,
279
279
  required: true,
280
280
  disabled: status === "loading",
281
- className: "focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-white/5 px-3 py-1.5 text-base text-white ring-1 ring-inset ring-white/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full",
281
+ className: "focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-gray-900/5 px-3 py-1.5 text-base text-gray-900 ring-1 ring-inset ring-gray-900/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full dark:bg-white/5 dark:text-white dark:ring-white/10",
282
282
  defaultValue: ""
283
283
  }
284
284
  ) })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../components/tailwind/contact.tsx"],"sourcesContent":["'use client'\r\nimport { useState } from 'react'\r\nimport { ChevronDownIcon } from '@heroicons/react/20/solid'\r\nimport { Switch } from '@headlessui/react'\r\nimport { Input } from '../ui/input'\r\nimport { useRecaptcha } from '../../hooks/useRecaptcha'\r\n\r\nfunction classNames(...classes: string[]) {\r\n return classes.filter(Boolean).join(' ')\r\n}\r\n\r\ntype Status = 'idle' | 'loading' | 'success' | 'error'\r\n\r\nexport const Contact = () => {\r\n const [agreed, setAgreed] = useState(false)\r\n const [status, setStatus] = useState<Status>('idle')\r\n const [errorMessage, setErrorMessage] = useState('')\r\n const { executeRecaptcha } = useRecaptcha()\r\n\r\n const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {\r\n e.preventDefault()\r\n\r\n if (!agreed) {\r\n setErrorMessage('You must agree to the privacy policy')\r\n return\r\n }\r\n\r\n const form = e.currentTarget\r\n const data = new FormData(form)\r\n\r\n const recaptchaToken = await executeRecaptcha('contact')\r\n\r\n const body = {\r\n firstName: data.get('first-name') as string,\r\n lastName: data.get('last-name') as string,\r\n company: data.get('company') as string,\r\n email: data.get('email') as string,\r\n phone: data.get('phone-number') as string,\r\n message: data.get('message') as string,\r\n agreed: true as const,\r\n recaptchaToken: recaptchaToken ?? undefined,\r\n }\r\n\r\n setStatus('loading')\r\n setErrorMessage('')\r\n\r\n try {\r\n const res = await fetch('/api/contact', {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(body),\r\n })\r\n\r\n if (!res.ok) {\r\n const json = await res.json()\r\n throw new Error(json.error ?? 'Something went wrong')\r\n }\r\n\r\n setStatus('success')\r\n form.reset()\r\n setAgreed(false)\r\n } catch (err) {\r\n setStatus('error')\r\n setErrorMessage(\r\n err instanceof Error ? err.message : 'Something went wrong',\r\n )\r\n }\r\n }\r\n\r\n if (status === 'success') {\r\n return (\r\n <div className=\"isolate bg-white px-6 py-24 sm:py-32 lg:px-8 dark:bg-gray-800 dark:text-white\">\r\n <div className=\"mx-auto max-w-2xl text-center\">\r\n <h2 className=\"text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl dark:text-gray-100\">\r\n Message sent\r\n </h2>\r\n <p className=\"mt-4 text-lg leading-8 text-gray-600 dark:text-gray-400\">\r\n Thanks for reaching out. We&apos;ll get back to you as soon as\r\n possible.\r\n </p>\r\n </div>\r\n </div>\r\n )\r\n }\r\n\r\n return (\r\n <div className=\"isolate bg-white px-6 py-24 sm:py-32 lg:px-8 dark:bg-gray-800 dark:text-white\">\r\n <div\r\n className=\"absolute inset-x-0 top-[-10rem] -z-10 transform-gpu overflow-hidden blur-3xl sm:top-[-20rem]\"\r\n aria-hidden=\"true\"\r\n >\r\n <div\r\n className=\"aspect-1155/678 bg-linear-to-tr relative left-1/2 -z-10 w-[36.125rem] max-w-none -translate-x-1/2 rotate-[30deg] from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-40rem)] sm:w-[72.1875rem]\"\r\n style={{\r\n clipPath:\r\n 'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',\r\n }}\r\n />\r\n </div>\r\n <div className=\"mx-auto max-w-2xl text-center\">\r\n <h2 className=\"text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl dark:text-gray-100\">\r\n Contact us\r\n </h2>\r\n <p className=\"mt-2 text-lg leading-8 text-gray-600 dark:text-gray-400\">\r\n Have a question or want to learn more? Send us a message.\r\n </p>\r\n </div>\r\n <form onSubmit={handleSubmit} className=\"mx-auto mt-16 max-w-xl sm:mt-20\">\r\n <div className=\"grid grid-cols-1 gap-x-8 gap-y-6 sm:grid-cols-2\">\r\n <div>\r\n <label\r\n htmlFor=\"first-name\"\r\n className=\"block text-sm font-semibold leading-6 text-gray-900 dark:text-white\"\r\n >\r\n First name\r\n </label>\r\n <div className=\"mt-2.5\">\r\n <Input\r\n type=\"text\"\r\n name=\"first-name\"\r\n id=\"first-name\"\r\n autoComplete=\"given-name\"\r\n required\r\n disabled={status === 'loading'}\r\n className=\"focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-white/5 px-3 py-1.5 text-base text-white ring-1 ring-inset ring-white/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full\"\r\n />\r\n </div>\r\n </div>\r\n <div>\r\n <label\r\n htmlFor=\"last-name\"\r\n className=\"block text-sm font-semibold leading-6 text-gray-900 dark:text-white\"\r\n >\r\n Last name\r\n </label>\r\n <div className=\"mt-2.5\">\r\n <Input\r\n type=\"text\"\r\n name=\"last-name\"\r\n id=\"last-name\"\r\n autoComplete=\"family-name\"\r\n required\r\n disabled={status === 'loading'}\r\n className=\"focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-white/5 px-3 py-1.5 text-base text-white ring-1 ring-inset ring-white/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full\"\r\n />\r\n </div>\r\n </div>\r\n <div className=\"sm:col-span-2\">\r\n <label\r\n htmlFor=\"company\"\r\n className=\"block text-sm font-semibold leading-6 text-gray-900 dark:text-white\"\r\n >\r\n Company\r\n </label>\r\n <div className=\"mt-2.5\">\r\n <Input\r\n type=\"text\"\r\n name=\"company\"\r\n id=\"company\"\r\n autoComplete=\"organization\"\r\n disabled={status === 'loading'}\r\n className=\"focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-white/5 px-3 py-1.5 text-base text-white ring-1 ring-inset ring-white/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full\"\r\n />\r\n </div>\r\n </div>\r\n <div className=\"sm:col-span-2\">\r\n <label\r\n htmlFor=\"email\"\r\n className=\"block text-sm font-semibold leading-6 text-gray-900 dark:text-white\"\r\n >\r\n Email\r\n </label>\r\n <div className=\"mt-2.5\">\r\n <Input\r\n type=\"email\"\r\n name=\"email\"\r\n id=\"email\"\r\n autoComplete=\"email\"\r\n required\r\n disabled={status === 'loading'}\r\n className=\"focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-white/5 px-3 py-1.5 text-base text-white ring-1 ring-inset ring-white/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full\"\r\n />\r\n </div>\r\n </div>\r\n <div className=\"sm:col-span-2\">\r\n <label\r\n htmlFor=\"phone-number\"\r\n className=\"block text-sm font-semibold leading-6 text-gray-900 dark:text-white\"\r\n >\r\n Phone number\r\n </label>\r\n <div className=\"relative mt-2.5\">\r\n <div className=\"absolute inset-y-0 left-0 flex items-center\">\r\n <label htmlFor=\"country\" className=\"sr-only\">\r\n Country\r\n </label>\r\n <select\r\n id=\"country\"\r\n name=\"country\"\r\n disabled={status === 'loading'}\r\n className=\"h-full rounded-md border-0 bg-transparent bg-none py-0 pl-4 pr-9 text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm\"\r\n >\r\n <option>US</option>\r\n <option>CA</option>\r\n <option>EU</option>\r\n </select>\r\n <ChevronDownIcon\r\n className=\"pointer-events-none absolute right-3 top-0 h-full w-5 text-gray-400\"\r\n aria-hidden=\"true\"\r\n />\r\n </div>\r\n <Input\r\n type=\"tel\"\r\n name=\"phone-number\"\r\n id=\"phone-number\"\r\n autoComplete=\"tel\"\r\n disabled={status === 'loading'}\r\n className=\"focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-white/5 px-3 py-1.5 text-base text-white ring-1 ring-inset ring-white/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full\"\r\n />\r\n </div>\r\n </div>\r\n <div className=\"sm:col-span-2\">\r\n <label\r\n htmlFor=\"message\"\r\n className=\"block text-sm font-semibold leading-6 text-gray-900 dark:text-white\"\r\n >\r\n Message\r\n </label>\r\n <div className=\"mt-2.5\">\r\n <textarea\r\n name=\"message\"\r\n id=\"message\"\r\n rows={4}\r\n required\r\n disabled={status === 'loading'}\r\n className=\"focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-white/5 px-3 py-1.5 text-base text-white ring-1 ring-inset ring-white/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full\"\r\n defaultValue={''}\r\n />\r\n </div>\r\n </div>\r\n <Switch.Group as=\"div\" className=\"flex gap-x-4 sm:col-span-2\">\r\n <div className=\"flex h-6 items-center\">\r\n <Switch\r\n checked={agreed}\r\n onChange={setAgreed}\r\n disabled={status === 'loading'}\r\n className={classNames(\r\n agreed ? 'bg-primary-600' : 'bg-gray-200',\r\n 'focus-visible:outline-primary-600 flex w-8 flex-none cursor-pointer rounded-full p-px ring-1 ring-inset ring-gray-900/5 transition-colors duration-200 ease-in-out focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2',\r\n )}\r\n >\r\n <span className=\"sr-only\">Agree to policies</span>\r\n <span\r\n aria-hidden=\"true\"\r\n className={classNames(\r\n agreed ? 'translate-x-3.5' : 'translate-x-0',\r\n 'shadow-2xs h-4 w-4 transform rounded-full bg-white ring-1 ring-gray-900/5 transition duration-200 ease-in-out',\r\n )}\r\n />\r\n </Switch>\r\n </div>\r\n <Switch.Label className=\"text-sm leading-6 text-gray-600 dark:text-white\">\r\n By selecting this, you agree to our{' '}\r\n <a\r\n href=\"/about/privacy\"\r\n className=\"text-primary-600 font-semibold\"\r\n >\r\n privacy&nbsp;policy\r\n </a>\r\n .\r\n </Switch.Label>\r\n </Switch.Group>\r\n </div>\r\n\r\n {errorMessage && (\r\n <p\r\n className=\"mt-4 text-sm text-red-600 dark:text-red-400\"\r\n role=\"alert\"\r\n >\r\n {errorMessage}\r\n </p>\r\n )}\r\n\r\n <div className=\"mt-10\">\r\n <button\r\n type=\"submit\"\r\n disabled={status === 'loading'}\r\n className=\"bg-primary-500 hover:bg-primary-400 focus-visible:outline-primary-500 shadow-2xs flex w-full items-center justify-center rounded-md px-3 py-2 text-sm font-semibold text-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 disabled:cursor-not-allowed disabled:opacity-60\"\r\n >\r\n {status === 'loading' ? 'Sending…' : 'Send message'}\r\n </button>\r\n </div>\r\n <p className=\"mt-4 text-center text-xs text-gray-400 dark:text-gray-500\">\r\n This site is protected by reCAPTCHA and the Google{' '}\r\n <a\r\n href=\"https://policies.google.com/privacy\"\r\n className=\"underline hover:text-gray-600 dark:hover:text-gray-300\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n >\r\n Privacy Policy\r\n </a>{' '}\r\n and{' '}\r\n <a\r\n href=\"https://policies.google.com/terms\"\r\n className=\"underline hover:text-gray-600 dark:hover:text-gray-300\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n >\r\n Terms of Service\r\n </a>{' '}\r\n apply.\r\n </p>\r\n </form>\r\n </div>\r\n )\r\n}\r\n"],"mappings":"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","names":["import_react"]}
1
+ {"version":3,"sources":["../../../components/tailwind/contact.tsx"],"sourcesContent":["'use client'\nimport { useState } from 'react'\nimport { ChevronDownIcon } from '@heroicons/react/20/solid'\nimport { Switch } from '@headlessui/react'\nimport { Input } from '../ui/input'\nimport { useRecaptcha } from '../../hooks/useRecaptcha'\n\nfunction classNames(...classes: string[]) {\n return classes.filter(Boolean).join(' ')\n}\n\ntype Status = 'idle' | 'loading' | 'success' | 'error'\n\nexport const Contact = () => {\n const [agreed, setAgreed] = useState(false)\n const [status, setStatus] = useState<Status>('idle')\n const [errorMessage, setErrorMessage] = useState('')\n const { executeRecaptcha } = useRecaptcha()\n\n const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {\n e.preventDefault()\n\n if (!agreed) {\n setErrorMessage('You must agree to the privacy policy')\n return\n }\n\n const form = e.currentTarget\n const data = new FormData(form)\n\n const recaptchaToken = await executeRecaptcha('contact')\n\n const body = {\n firstName: data.get('first-name') as string,\n lastName: data.get('last-name') as string,\n company: data.get('company') as string,\n email: data.get('email') as string,\n phone: data.get('phone-number') as string,\n message: data.get('message') as string,\n agreed: true as const,\n recaptchaToken: recaptchaToken ?? undefined,\n }\n\n setStatus('loading')\n setErrorMessage('')\n\n try {\n const res = await fetch('/api/contact', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n\n if (!res.ok) {\n const json = await res.json()\n throw new Error(json.error ?? 'Something went wrong')\n }\n\n setStatus('success')\n form.reset()\n setAgreed(false)\n } catch (err) {\n setStatus('error')\n setErrorMessage(\n err instanceof Error ? err.message : 'Something went wrong',\n )\n }\n }\n\n if (status === 'success') {\n return (\n <div className=\"isolate bg-white px-6 py-24 sm:py-32 lg:px-8 dark:bg-gray-800 dark:text-white\">\n <div className=\"mx-auto max-w-2xl text-center\">\n <h2 className=\"text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl dark:text-gray-100\">\n Message sent\n </h2>\n <p className=\"mt-4 text-lg leading-8 text-gray-600 dark:text-gray-400\">\n Thanks for reaching out. We&apos;ll get back to you as soon as\n possible.\n </p>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"isolate bg-white px-6 py-24 sm:py-32 lg:px-8 dark:bg-gray-800 dark:text-white\">\n <div\n className=\"absolute inset-x-0 top-[-10rem] -z-10 transform-gpu overflow-hidden blur-3xl sm:top-[-20rem]\"\n aria-hidden=\"true\"\n >\n <div\n className=\"aspect-1155/678 bg-linear-to-tr relative left-1/2 -z-10 w-[36.125rem] max-w-none -translate-x-1/2 rotate-[30deg] from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-40rem)] sm:w-[72.1875rem]\"\n style={{\n clipPath:\n 'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',\n }}\n />\n </div>\n <div className=\"mx-auto max-w-2xl text-center\">\n <h2 className=\"text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl dark:text-gray-100\">\n Contact us\n </h2>\n <p className=\"mt-2 text-lg leading-8 text-gray-600 dark:text-gray-400\">\n Have a question or want to learn more? Send us a message.\n </p>\n </div>\n <form onSubmit={handleSubmit} className=\"mx-auto mt-16 max-w-xl sm:mt-20\">\n <div className=\"grid grid-cols-1 gap-x-8 gap-y-6 sm:grid-cols-2\">\n <div>\n <label\n htmlFor=\"first-name\"\n className=\"block text-sm font-semibold leading-6 text-gray-900 dark:text-white\"\n >\n First name\n </label>\n <div className=\"mt-2.5\">\n <Input\n type=\"text\"\n name=\"first-name\"\n id=\"first-name\"\n autoComplete=\"given-name\"\n required\n disabled={status === 'loading'}\n className=\"focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-gray-900/5 px-3 py-1.5 text-base text-gray-900 ring-1 ring-inset ring-gray-900/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full dark:bg-white/5 dark:text-white dark:ring-white/10\"\n />\n </div>\n </div>\n <div>\n <label\n htmlFor=\"last-name\"\n className=\"block text-sm font-semibold leading-6 text-gray-900 dark:text-white\"\n >\n Last name\n </label>\n <div className=\"mt-2.5\">\n <Input\n type=\"text\"\n name=\"last-name\"\n id=\"last-name\"\n autoComplete=\"family-name\"\n required\n disabled={status === 'loading'}\n className=\"focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-gray-900/5 px-3 py-1.5 text-base text-gray-900 ring-1 ring-inset ring-gray-900/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full dark:bg-white/5 dark:text-white dark:ring-white/10\"\n />\n </div>\n </div>\n <div className=\"sm:col-span-2\">\n <label\n htmlFor=\"company\"\n className=\"block text-sm font-semibold leading-6 text-gray-900 dark:text-white\"\n >\n Company\n </label>\n <div className=\"mt-2.5\">\n <Input\n type=\"text\"\n name=\"company\"\n id=\"company\"\n autoComplete=\"organization\"\n disabled={status === 'loading'}\n className=\"focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-gray-900/5 px-3 py-1.5 text-base text-gray-900 ring-1 ring-inset ring-gray-900/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full dark:bg-white/5 dark:text-white dark:ring-white/10\"\n />\n </div>\n </div>\n <div className=\"sm:col-span-2\">\n <label\n htmlFor=\"email\"\n className=\"block text-sm font-semibold leading-6 text-gray-900 dark:text-white\"\n >\n Email\n </label>\n <div className=\"mt-2.5\">\n <Input\n type=\"email\"\n name=\"email\"\n id=\"email\"\n autoComplete=\"email\"\n required\n disabled={status === 'loading'}\n className=\"focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-gray-900/5 px-3 py-1.5 text-base text-gray-900 ring-1 ring-inset ring-gray-900/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full dark:bg-white/5 dark:text-white dark:ring-white/10\"\n />\n </div>\n </div>\n <div className=\"sm:col-span-2\">\n <label\n htmlFor=\"phone-number\"\n className=\"block text-sm font-semibold leading-6 text-gray-900 dark:text-white\"\n >\n Phone number\n </label>\n <div className=\"relative mt-2.5\">\n <div className=\"absolute inset-y-0 left-0 flex items-center\">\n <label htmlFor=\"country\" className=\"sr-only\">\n Country\n </label>\n <select\n id=\"country\"\n name=\"country\"\n disabled={status === 'loading'}\n className=\"h-full rounded-md border-0 bg-transparent bg-none py-0 pl-4 pr-9 text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm\"\n >\n <option>US</option>\n <option>CA</option>\n <option>EU</option>\n </select>\n <ChevronDownIcon\n className=\"pointer-events-none absolute right-3 top-0 h-full w-5 text-gray-400\"\n aria-hidden=\"true\"\n />\n </div>\n <Input\n type=\"tel\"\n name=\"phone-number\"\n id=\"phone-number\"\n autoComplete=\"tel\"\n disabled={status === 'loading'}\n className=\"focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-gray-900/5 px-3 py-1.5 text-base text-gray-900 ring-1 ring-inset ring-gray-900/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full dark:bg-white/5 dark:text-white dark:ring-white/10\"\n />\n </div>\n </div>\n <div className=\"sm:col-span-2\">\n <label\n htmlFor=\"message\"\n className=\"block text-sm font-semibold leading-6 text-gray-900 dark:text-white\"\n >\n Message\n </label>\n <div className=\"mt-2.5\">\n <textarea\n name=\"message\"\n id=\"message\"\n rows={4}\n required\n disabled={status === 'loading'}\n className=\"focus:ring-primary-500 shadow-2xs w-full min-w-0 appearance-none rounded-md border-0 bg-gray-900/5 px-3 py-1.5 text-base text-gray-900 ring-1 ring-inset ring-gray-900/10 placeholder:text-gray-500 focus:ring-2 focus:ring-inset sm:w-64 sm:text-sm sm:leading-6 xl:w-full dark:bg-white/5 dark:text-white dark:ring-white/10\"\n defaultValue={''}\n />\n </div>\n </div>\n <Switch.Group as=\"div\" className=\"flex gap-x-4 sm:col-span-2\">\n <div className=\"flex h-6 items-center\">\n <Switch\n checked={agreed}\n onChange={setAgreed}\n disabled={status === 'loading'}\n className={classNames(\n agreed ? 'bg-primary-600' : 'bg-gray-200',\n 'focus-visible:outline-primary-600 flex w-8 flex-none cursor-pointer rounded-full p-px ring-1 ring-inset ring-gray-900/5 transition-colors duration-200 ease-in-out focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2',\n )}\n >\n <span className=\"sr-only\">Agree to policies</span>\n <span\n aria-hidden=\"true\"\n className={classNames(\n agreed ? 'translate-x-3.5' : 'translate-x-0',\n 'shadow-2xs h-4 w-4 transform rounded-full bg-white ring-1 ring-gray-900/5 transition duration-200 ease-in-out',\n )}\n />\n </Switch>\n </div>\n <Switch.Label className=\"text-sm leading-6 text-gray-600 dark:text-white\">\n By selecting this, you agree to our{' '}\n <a\n href=\"/about/privacy\"\n className=\"text-primary-600 font-semibold\"\n >\n privacy&nbsp;policy\n </a>\n .\n </Switch.Label>\n </Switch.Group>\n </div>\n\n {errorMessage && (\n <p\n className=\"mt-4 text-sm text-red-600 dark:text-red-400\"\n role=\"alert\"\n >\n {errorMessage}\n </p>\n )}\n\n <div className=\"mt-10\">\n <button\n type=\"submit\"\n disabled={status === 'loading'}\n className=\"bg-primary-500 hover:bg-primary-400 focus-visible:outline-primary-500 shadow-2xs flex w-full items-center justify-center rounded-md px-3 py-2 text-sm font-semibold text-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 disabled:cursor-not-allowed disabled:opacity-60\"\n >\n {status === 'loading' ? 'Sending…' : 'Send message'}\n </button>\n </div>\n <p className=\"mt-4 text-center text-xs text-gray-400 dark:text-gray-500\">\n This site is protected by reCAPTCHA and the Google{' '}\n <a\n href=\"https://policies.google.com/privacy\"\n className=\"underline hover:text-gray-600 dark:hover:text-gray-300\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Privacy Policy\n </a>{' '}\n and{' '}\n <a\n href=\"https://policies.google.com/terms\"\n className=\"underline hover:text-gray-600 dark:hover:text-gray-300\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Terms of Service\n </a>{' '}\n apply.\n </p>\n </form>\n </div>\n )\n}\n"],"mappings":"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","names":["import_react"]}