@nextsparkjs/core 0.1.0-beta.91 → 0.1.0-beta.94

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 (341) hide show
  1. package/dist/components/dashboard/block-editor/array-field.d.ts.map +1 -1
  2. package/dist/components/dashboard/block-editor/array-field.js +55 -3
  3. package/dist/components/dashboard/block-editor/dynamic-form.d.ts.map +1 -1
  4. package/dist/components/dashboard/block-editor/dynamic-form.js +82 -2
  5. package/dist/components/dashboard/navigation/DynamicNavigation.d.ts.map +1 -1
  6. package/dist/components/dashboard/navigation/DynamicNavigation.js +7 -1
  7. package/dist/components/devtools/scheduled-actions/actions-table.d.ts +1 -0
  8. package/dist/components/devtools/scheduled-actions/actions-table.d.ts.map +1 -1
  9. package/dist/components/devtools/scheduled-actions/actions-table.js +182 -46
  10. package/dist/components/devtools/scheduled-actions/types.d.ts +1 -0
  11. package/dist/components/devtools/scheduled-actions/types.d.ts.map +1 -1
  12. package/dist/components/media/MediaCard.d.ts +23 -0
  13. package/dist/components/media/MediaCard.d.ts.map +1 -0
  14. package/dist/components/media/MediaCard.js +154 -0
  15. package/dist/components/media/MediaDetailPanel.d.ts +17 -0
  16. package/dist/components/media/MediaDetailPanel.d.ts.map +1 -0
  17. package/dist/components/media/MediaDetailPanel.js +331 -0
  18. package/dist/components/media/MediaGrid.d.ts +26 -0
  19. package/dist/components/media/MediaGrid.d.ts.map +1 -0
  20. package/dist/components/media/MediaGrid.js +77 -0
  21. package/dist/components/media/MediaLibrary.d.ts +20 -0
  22. package/dist/components/media/MediaLibrary.d.ts.map +1 -0
  23. package/dist/components/media/MediaLibrary.js +229 -0
  24. package/dist/components/media/MediaList.d.ts +24 -0
  25. package/dist/components/media/MediaList.d.ts.map +1 -0
  26. package/dist/components/media/MediaList.js +181 -0
  27. package/dist/components/media/MediaSelector.d.ts +19 -0
  28. package/dist/components/media/MediaSelector.d.ts.map +1 -0
  29. package/dist/components/media/MediaSelector.js +145 -0
  30. package/dist/components/media/MediaTagFilter.d.ts +16 -0
  31. package/dist/components/media/MediaTagFilter.d.ts.map +1 -0
  32. package/dist/components/media/MediaTagFilter.js +122 -0
  33. package/dist/components/media/MediaToolbar.d.ts +25 -0
  34. package/dist/components/media/MediaToolbar.d.ts.map +1 -0
  35. package/dist/components/media/MediaToolbar.js +136 -0
  36. package/dist/components/media/MediaUploadZone.d.ts +19 -0
  37. package/dist/components/media/MediaUploadZone.d.ts.map +1 -0
  38. package/dist/components/media/MediaUploadZone.js +248 -0
  39. package/dist/components/media/index.d.ts +15 -0
  40. package/dist/components/media/index.d.ts.map +1 -0
  41. package/dist/components/media/index.js +20 -0
  42. package/dist/contexts/TeamContext.js +1 -1
  43. package/dist/hooks/index.d.ts +2 -0
  44. package/dist/hooks/index.d.ts.map +1 -1
  45. package/dist/hooks/index.js +2 -0
  46. package/dist/hooks/useEnsureUserMetadata.d.ts +4 -0
  47. package/dist/hooks/useEnsureUserMetadata.d.ts.map +1 -1
  48. package/dist/hooks/useEnsureUserMetadata.js +85 -60
  49. package/dist/hooks/useEntityMutations.d.ts.map +1 -1
  50. package/dist/hooks/useEntityMutations.js +5 -9
  51. package/dist/hooks/useMedia.d.ts +56 -0
  52. package/dist/hooks/useMedia.d.ts.map +1 -0
  53. package/dist/hooks/useMedia.js +181 -0
  54. package/dist/hooks/useMediaUpload.d.ts +27 -0
  55. package/dist/hooks/useMediaUpload.d.ts.map +1 -0
  56. package/dist/hooks/useMediaUpload.js +36 -0
  57. package/dist/hooks/useUserSettings.d.ts +5 -4
  58. package/dist/hooks/useUserSettings.d.ts.map +1 -1
  59. package/dist/hooks/useUserSettings.js +42 -40
  60. package/dist/index.d.ts +1 -1
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +2 -3
  63. package/dist/lib/api/auth/dual-auth.d.ts +6 -2
  64. package/dist/lib/api/auth/dual-auth.d.ts.map +1 -1
  65. package/dist/lib/api/auth/dual-auth.js +5 -9
  66. package/dist/lib/api/entity/generic-handler.d.ts.map +1 -1
  67. package/dist/lib/api/entity/generic-handler.js +3 -3
  68. package/dist/lib/config/app.config.d.ts.map +1 -1
  69. package/dist/lib/config/app.config.js +37 -0
  70. package/dist/lib/config/config-sync.d.ts +1 -0
  71. package/dist/lib/config/config-sync.d.ts.map +1 -1
  72. package/dist/lib/config/config-sync.js +2 -0
  73. package/dist/lib/config/types.d.ts +29 -0
  74. package/dist/lib/config/types.d.ts.map +1 -1
  75. package/dist/lib/media/schemas.d.ts +39 -0
  76. package/dist/lib/media/schemas.d.ts.map +1 -0
  77. package/dist/lib/media/schemas.js +32 -0
  78. package/dist/lib/media/types.d.ts +69 -0
  79. package/dist/lib/media/types.d.ts.map +1 -0
  80. package/dist/lib/media/types.js +0 -0
  81. package/dist/lib/media/utils.d.ts +26 -0
  82. package/dist/lib/media/utils.d.ts.map +1 -0
  83. package/dist/lib/media/utils.js +33 -0
  84. package/dist/lib/rate-limit-redis.d.ts.map +1 -1
  85. package/dist/lib/rate-limit-redis.js +13 -4
  86. package/dist/lib/scheduled-actions/initializer.d.ts +6 -3
  87. package/dist/lib/scheduled-actions/initializer.d.ts.map +1 -1
  88. package/dist/lib/scheduled-actions/initializer.js +11 -6
  89. package/dist/lib/scheduled-actions/processor.d.ts +20 -4
  90. package/dist/lib/scheduled-actions/processor.d.ts.map +1 -1
  91. package/dist/lib/scheduled-actions/processor.js +128 -34
  92. package/dist/lib/scheduled-actions/registry.d.ts +3 -0
  93. package/dist/lib/scheduled-actions/registry.d.ts.map +1 -1
  94. package/dist/lib/scheduled-actions/registry.js +2 -1
  95. package/dist/lib/scheduled-actions/scheduler.d.ts +1 -1
  96. package/dist/lib/scheduled-actions/scheduler.d.ts.map +1 -1
  97. package/dist/lib/scheduled-actions/scheduler.js +76 -38
  98. package/dist/lib/scheduled-actions/types.d.ts +73 -0
  99. package/dist/lib/scheduled-actions/types.d.ts.map +1 -1
  100. package/dist/lib/selectors/core-selectors.d.ts +102 -0
  101. package/dist/lib/selectors/core-selectors.d.ts.map +1 -1
  102. package/dist/lib/selectors/core-selectors.js +3 -1
  103. package/dist/lib/selectors/domains/block-editor.selectors.d.ts +8 -0
  104. package/dist/lib/selectors/domains/block-editor.selectors.d.ts.map +1 -1
  105. package/dist/lib/selectors/domains/block-editor.selectors.js +9 -0
  106. package/dist/lib/selectors/domains/devtools.selectors.d.ts +6 -0
  107. package/dist/lib/selectors/domains/devtools.selectors.d.ts.map +1 -1
  108. package/dist/lib/selectors/domains/devtools.selectors.js +6 -0
  109. package/dist/lib/selectors/domains/index.d.ts +1 -0
  110. package/dist/lib/selectors/domains/index.d.ts.map +1 -1
  111. package/dist/lib/selectors/domains/index.js +2 -0
  112. package/dist/lib/selectors/domains/media.selectors.d.ts +96 -0
  113. package/dist/lib/selectors/domains/media.selectors.d.ts.map +1 -0
  114. package/dist/lib/selectors/domains/media.selectors.js +103 -0
  115. package/dist/lib/selectors/selectors.d.ts +204 -0
  116. package/dist/lib/selectors/selectors.d.ts.map +1 -1
  117. package/dist/lib/services/index.d.ts +2 -0
  118. package/dist/lib/services/index.d.ts.map +1 -1
  119. package/dist/lib/services/index.js +2 -0
  120. package/dist/lib/services/media.service.d.ts +158 -0
  121. package/dist/lib/services/media.service.d.ts.map +1 -0
  122. package/dist/lib/services/media.service.js +410 -0
  123. package/dist/messages/de/devtools.json +16 -0
  124. package/dist/messages/de/index.d.ts +16 -0
  125. package/dist/messages/de/index.d.ts.map +1 -1
  126. package/dist/messages/en/admin.json +4 -1
  127. package/dist/messages/en/devtools.json +16 -0
  128. package/dist/messages/en/index.d.ts +167 -0
  129. package/dist/messages/en/index.d.ts.map +1 -1
  130. package/dist/messages/en/index.js +2 -0
  131. package/dist/messages/en/index.ts +2 -0
  132. package/dist/messages/en/media.json +147 -0
  133. package/dist/messages/en/navigation.json +1 -0
  134. package/dist/messages/es/admin.json +4 -1
  135. package/dist/messages/es/devtools.json +16 -0
  136. package/dist/messages/es/index.d.ts +167 -0
  137. package/dist/messages/es/index.d.ts.map +1 -1
  138. package/dist/messages/es/index.js +2 -0
  139. package/dist/messages/es/index.ts +2 -0
  140. package/dist/messages/es/media.json +147 -0
  141. package/dist/messages/es/navigation.json +1 -0
  142. package/dist/messages/fr/devtools.json +16 -0
  143. package/dist/messages/fr/index.d.ts +16 -0
  144. package/dist/messages/fr/index.d.ts.map +1 -1
  145. package/dist/messages/it/devtools.json +16 -0
  146. package/dist/messages/it/index.d.ts +16 -0
  147. package/dist/messages/it/index.d.ts.map +1 -1
  148. package/dist/messages/pt/devtools.json +16 -0
  149. package/dist/messages/pt/index.d.ts +16 -0
  150. package/dist/messages/pt/index.d.ts.map +1 -1
  151. package/dist/migrations/017_scheduled_actions_table.sql +21 -0
  152. package/dist/migrations/021_media.sql +154 -0
  153. package/dist/migrations/090_sample_data.sql +53 -0
  154. package/dist/styles/classes.json +36 -3
  155. package/dist/styles/ui.css +1 -1
  156. package/dist/templates/app/api/devtools/config/entities/route.ts +18 -11
  157. package/dist/templates/app/api/devtools/config/theme/route.ts +5 -4
  158. package/dist/templates/app/api/devtools/tests/[...path]/route.ts +6 -5
  159. package/dist/templates/app/api/devtools/tests/route.ts +5 -4
  160. package/dist/templates/app/api/health/route.ts +6 -4
  161. package/dist/templates/app/api/internal/user-metadata/route.ts +3 -2
  162. package/dist/templates/app/api/superadmin/subscriptions/route.ts +5 -6
  163. package/dist/templates/app/api/superadmin/teams/[teamId]/route.ts +6 -7
  164. package/dist/templates/app/api/superadmin/teams/route.ts +5 -6
  165. package/dist/templates/app/api/superadmin/users/[userId]/route.ts +11 -16
  166. package/dist/templates/app/api/superadmin/users/route.ts +9 -10
  167. package/dist/templates/app/api/user/delete-account/route.ts +3 -2
  168. package/dist/templates/app/api/user/plan-flags/route.ts +11 -24
  169. package/dist/templates/app/api/user/profile/route.ts +7 -6
  170. package/dist/templates/app/api/v1/[entity]/[id]/child/[childType]/[childId]/route.ts +16 -18
  171. package/dist/templates/app/api/v1/[entity]/[id]/child/[childType]/route.ts +17 -19
  172. package/dist/templates/app/api/v1/[entity]/[id]/route.ts +10 -12
  173. package/dist/templates/app/api/v1/[entity]/route.ts +9 -11
  174. package/dist/templates/app/api/v1/api-keys/[id]/route.ts +9 -8
  175. package/dist/templates/app/api/v1/api-keys/route.ts +7 -6
  176. package/dist/templates/app/api/v1/auth/signup-with-invite/route.ts +3 -2
  177. package/dist/templates/app/api/v1/billing/cancel/route.ts +15 -14
  178. package/dist/templates/app/api/v1/billing/change-plan/route.ts +10 -9
  179. package/dist/templates/app/api/v1/billing/check-action/route.ts +8 -7
  180. package/dist/templates/app/api/v1/billing/checkout/route.ts +10 -9
  181. package/dist/templates/app/api/v1/billing/plans/route.ts +5 -4
  182. package/dist/templates/app/api/v1/billing/portal/route.ts +9 -8
  183. package/dist/templates/app/api/v1/blocks/[slug]/route.ts +4 -3
  184. package/dist/templates/app/api/v1/blocks/route.ts +3 -2
  185. package/dist/templates/app/api/v1/blocks/validate/route.ts +5 -3
  186. package/dist/templates/app/api/v1/cron/process/route.ts +4 -6
  187. package/dist/templates/app/api/v1/devtools/blocks/route.ts +3 -2
  188. package/dist/templates/app/api/v1/devtools/docs/route.ts +3 -2
  189. package/dist/templates/app/api/v1/devtools/features/route.ts +3 -2
  190. package/dist/templates/app/api/v1/devtools/flows/route.ts +3 -2
  191. package/dist/templates/app/api/v1/devtools/scheduled-actions/route.ts +125 -3
  192. package/dist/templates/app/api/v1/devtools/scheduled-actions/run/route.ts +110 -0
  193. package/dist/templates/app/api/v1/devtools/testing/route.ts +3 -2
  194. package/dist/templates/app/api/v1/media/[id]/route.ts +144 -0
  195. package/dist/templates/app/api/v1/media/[id]/tags/route.ts +154 -0
  196. package/dist/templates/app/api/v1/media/check-duplicates/route.ts +56 -0
  197. package/dist/templates/app/api/v1/media/route.ts +56 -0
  198. package/dist/templates/app/api/v1/media/upload/route.ts +157 -33
  199. package/dist/templates/app/api/v1/media-tags/route.ts +65 -0
  200. package/dist/templates/app/api/v1/plugin/[...path]/route.ts +16 -15
  201. package/dist/templates/app/api/v1/plugin/route.ts +3 -2
  202. package/dist/templates/app/api/v1/post-categories/[id]/route.ts +10 -9
  203. package/dist/templates/app/api/v1/post-categories/route.ts +5 -4
  204. package/dist/templates/app/api/v1/team-invitations/[token]/accept/route.ts +3 -3
  205. package/dist/templates/app/api/v1/team-invitations/[token]/decline/route.ts +3 -3
  206. package/dist/templates/app/api/v1/team-invitations/[token]/route.ts +3 -2
  207. package/dist/templates/app/api/v1/team-invitations/route.ts +3 -2
  208. package/dist/templates/app/api/v1/teams/[teamId]/invitations/route.ts +5 -4
  209. package/dist/templates/app/api/v1/teams/[teamId]/invoices/[invoiceNumber]/route.ts +3 -2
  210. package/dist/templates/app/api/v1/teams/[teamId]/invoices/route.ts +3 -2
  211. package/dist/templates/app/api/v1/teams/[teamId]/members/[memberId]/route.ts +5 -4
  212. package/dist/templates/app/api/v1/teams/[teamId]/members/route.ts +5 -5
  213. package/dist/templates/app/api/v1/teams/[teamId]/route.ts +31 -58
  214. package/dist/templates/app/api/v1/teams/[teamId]/subscription/route.ts +3 -2
  215. package/dist/templates/app/api/v1/teams/[teamId]/usage/[limitSlug]/route.ts +5 -4
  216. package/dist/templates/app/api/v1/teams/route.ts +18 -17
  217. package/dist/templates/app/api/v1/teams/switch/route.ts +3 -2
  218. package/dist/templates/app/api/v1/theme/[...path]/route.ts +16 -15
  219. package/dist/templates/app/api/v1/theme/route.ts +3 -2
  220. package/dist/templates/app/api/v1/users/[id]/meta/[key]/route.ts +7 -6
  221. package/dist/templates/app/api/v1/users/[id]/route.ts +9 -8
  222. package/dist/templates/app/api/v1/users/route.ts +7 -6
  223. package/dist/templates/app/dashboard/(main)/media/page.tsx +607 -0
  224. package/dist/templates/contents/themes/starter/messages/de/dev.json +106 -0
  225. package/dist/templates/contents/themes/starter/messages/de/index.ts +2 -0
  226. package/dist/templates/contents/themes/starter/messages/en/dev.json +106 -0
  227. package/dist/templates/contents/themes/starter/messages/en/index.ts +2 -0
  228. package/dist/templates/contents/themes/starter/messages/es/dev.json +106 -0
  229. package/dist/templates/contents/themes/starter/messages/es/index.ts +2 -0
  230. package/dist/templates/contents/themes/starter/messages/fr/dev.json +106 -0
  231. package/dist/templates/contents/themes/starter/messages/fr/index.ts +2 -0
  232. package/dist/templates/contents/themes/starter/messages/it/dev.json +106 -0
  233. package/dist/templates/contents/themes/starter/messages/it/index.ts +2 -0
  234. package/dist/templates/contents/themes/starter/messages/pt/dev.json +106 -0
  235. package/dist/templates/contents/themes/starter/messages/pt/index.ts +2 -0
  236. package/dist/templates/contents/themes/starter/styles/globals.css +14 -0
  237. package/dist/templates/instrumentation.ts +33 -0
  238. package/dist/types/blocks.d.ts +1 -1
  239. package/dist/types/blocks.d.ts.map +1 -1
  240. package/migrations/017_scheduled_actions_table.sql +21 -0
  241. package/migrations/021_media.sql +154 -0
  242. package/migrations/090_sample_data.sql +53 -0
  243. package/package.json +3 -2
  244. package/scripts/build/registry/config.mjs +41 -0
  245. package/scripts/build/registry/discovery/templates.mjs +0 -1
  246. package/scripts/build/registry/generators/entity-registry.mjs +16 -6
  247. package/scripts/build/registry/generators/route-handlers.mjs +8 -2
  248. package/scripts/build/registry/generators/template-registry.mjs +16 -4
  249. package/scripts/build/registry/post-build/route-cleanup.mjs +0 -1
  250. package/scripts/build/registry/validate-env.test.mjs +92 -0
  251. package/scripts/build/registry.mjs +18 -1
  252. package/scripts/deploy/vercel-deploy.mjs +1 -1
  253. package/templates/app/api/devtools/config/entities/route.ts +18 -11
  254. package/templates/app/api/devtools/config/theme/route.ts +5 -4
  255. package/templates/app/api/devtools/tests/[...path]/route.ts +6 -5
  256. package/templates/app/api/devtools/tests/route.ts +5 -4
  257. package/templates/app/api/health/route.ts +6 -4
  258. package/templates/app/api/internal/user-metadata/route.ts +3 -2
  259. package/templates/app/api/superadmin/subscriptions/route.ts +5 -6
  260. package/templates/app/api/superadmin/teams/[teamId]/route.ts +6 -7
  261. package/templates/app/api/superadmin/teams/route.ts +5 -6
  262. package/templates/app/api/superadmin/users/[userId]/route.ts +11 -16
  263. package/templates/app/api/superadmin/users/route.ts +9 -10
  264. package/templates/app/api/user/delete-account/route.ts +3 -2
  265. package/templates/app/api/user/plan-flags/route.ts +11 -24
  266. package/templates/app/api/user/profile/route.ts +7 -6
  267. package/templates/app/api/v1/[entity]/[id]/child/[childType]/[childId]/route.ts +16 -18
  268. package/templates/app/api/v1/[entity]/[id]/child/[childType]/route.ts +17 -19
  269. package/templates/app/api/v1/[entity]/[id]/route.ts +10 -12
  270. package/templates/app/api/v1/[entity]/route.ts +9 -11
  271. package/templates/app/api/v1/api-keys/[id]/route.ts +9 -8
  272. package/templates/app/api/v1/api-keys/route.ts +7 -6
  273. package/templates/app/api/v1/auth/signup-with-invite/route.ts +3 -2
  274. package/templates/app/api/v1/billing/cancel/route.ts +15 -14
  275. package/templates/app/api/v1/billing/change-plan/route.ts +10 -9
  276. package/templates/app/api/v1/billing/check-action/route.ts +8 -7
  277. package/templates/app/api/v1/billing/checkout/route.ts +10 -9
  278. package/templates/app/api/v1/billing/plans/route.ts +5 -4
  279. package/templates/app/api/v1/billing/portal/route.ts +9 -8
  280. package/templates/app/api/v1/blocks/[slug]/route.ts +4 -3
  281. package/templates/app/api/v1/blocks/route.ts +3 -2
  282. package/templates/app/api/v1/blocks/validate/route.ts +5 -3
  283. package/templates/app/api/v1/cron/process/route.ts +4 -6
  284. package/templates/app/api/v1/devtools/blocks/route.ts +3 -2
  285. package/templates/app/api/v1/devtools/docs/route.ts +3 -2
  286. package/templates/app/api/v1/devtools/features/route.ts +3 -2
  287. package/templates/app/api/v1/devtools/flows/route.ts +3 -2
  288. package/templates/app/api/v1/devtools/scheduled-actions/route.ts +125 -3
  289. package/templates/app/api/v1/devtools/scheduled-actions/run/route.ts +110 -0
  290. package/templates/app/api/v1/devtools/testing/route.ts +3 -2
  291. package/templates/app/api/v1/media/[id]/route.ts +144 -0
  292. package/templates/app/api/v1/media/[id]/tags/route.ts +154 -0
  293. package/templates/app/api/v1/media/check-duplicates/route.ts +56 -0
  294. package/templates/app/api/v1/media/route.ts +56 -0
  295. package/templates/app/api/v1/media/upload/route.ts +157 -33
  296. package/templates/app/api/v1/media-tags/route.ts +65 -0
  297. package/templates/app/api/v1/plugin/[...path]/route.ts +16 -15
  298. package/templates/app/api/v1/plugin/route.ts +3 -2
  299. package/templates/app/api/v1/post-categories/[id]/route.ts +10 -9
  300. package/templates/app/api/v1/post-categories/route.ts +5 -4
  301. package/templates/app/api/v1/team-invitations/[token]/accept/route.ts +3 -3
  302. package/templates/app/api/v1/team-invitations/[token]/decline/route.ts +3 -3
  303. package/templates/app/api/v1/team-invitations/[token]/route.ts +3 -2
  304. package/templates/app/api/v1/team-invitations/route.ts +3 -2
  305. package/templates/app/api/v1/teams/[teamId]/invitations/route.ts +5 -4
  306. package/templates/app/api/v1/teams/[teamId]/invoices/[invoiceNumber]/route.ts +3 -2
  307. package/templates/app/api/v1/teams/[teamId]/invoices/route.ts +3 -2
  308. package/templates/app/api/v1/teams/[teamId]/members/[memberId]/route.ts +5 -4
  309. package/templates/app/api/v1/teams/[teamId]/members/route.ts +5 -5
  310. package/templates/app/api/v1/teams/[teamId]/route.ts +31 -58
  311. package/templates/app/api/v1/teams/[teamId]/subscription/route.ts +3 -2
  312. package/templates/app/api/v1/teams/[teamId]/usage/[limitSlug]/route.ts +5 -4
  313. package/templates/app/api/v1/teams/route.ts +18 -17
  314. package/templates/app/api/v1/teams/switch/route.ts +3 -2
  315. package/templates/app/api/v1/theme/[...path]/route.ts +16 -15
  316. package/templates/app/api/v1/theme/route.ts +3 -2
  317. package/templates/app/api/v1/users/[id]/meta/[key]/route.ts +7 -6
  318. package/templates/app/api/v1/users/[id]/route.ts +9 -8
  319. package/templates/app/api/v1/users/route.ts +7 -6
  320. package/templates/app/dashboard/(main)/media/page.tsx +607 -0
  321. package/templates/contents/themes/starter/messages/de/dev.json +106 -0
  322. package/templates/contents/themes/starter/messages/de/index.ts +2 -0
  323. package/templates/contents/themes/starter/messages/en/dev.json +106 -0
  324. package/templates/contents/themes/starter/messages/en/index.ts +2 -0
  325. package/templates/contents/themes/starter/messages/es/dev.json +106 -0
  326. package/templates/contents/themes/starter/messages/es/index.ts +2 -0
  327. package/templates/contents/themes/starter/messages/fr/dev.json +106 -0
  328. package/templates/contents/themes/starter/messages/fr/index.ts +2 -0
  329. package/templates/contents/themes/starter/messages/it/dev.json +106 -0
  330. package/templates/contents/themes/starter/messages/it/index.ts +2 -0
  331. package/templates/contents/themes/starter/messages/pt/dev.json +106 -0
  332. package/templates/contents/themes/starter/messages/pt/index.ts +2 -0
  333. package/templates/contents/themes/starter/styles/globals.css +14 -0
  334. package/templates/instrumentation.ts +33 -0
  335. package/dist/presets/plugin/.env.example.template +0 -19
  336. package/dist/presets/plugin/entities/.gitkeep +0 -18
  337. package/dist/presets/theme/blocks/.gitkeep +0 -17
  338. package/dist/presets/theme/public/brand/.gitkeep +0 -8
  339. package/dist/presets/theme/tests/cypress/.gitkeep +0 -10
  340. package/dist/templates/contents/plugins/starter/plugin/.env.example.template +0 -19
  341. package/templates/contents/plugins/starter/plugin/.env.example.template +0 -19
@@ -0,0 +1,122 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { memo, useState, useMemo, useCallback } from "react";
4
+ import { useTranslations } from "next-intl";
5
+ import { TagIcon, XIcon } from "lucide-react";
6
+ import { Badge } from "../ui/badge.js";
7
+ import { Button } from "../ui/button.js";
8
+ import {
9
+ Popover,
10
+ PopoverContent,
11
+ PopoverTrigger
12
+ } from "../ui/popover.js";
13
+ import { cn } from "../../lib/utils/index.js";
14
+ import { sel } from "../../lib/selectors/index.js";
15
+ import { useMediaTags } from "../../hooks/useMedia.js";
16
+ const MediaTagFilter = memo(function MediaTagFilter2({
17
+ selectedTagIds,
18
+ onTagsChange,
19
+ className
20
+ }) {
21
+ const t = useTranslations("media");
22
+ const { data: tags = [], isLoading } = useMediaTags();
23
+ const [isOpen, setIsOpen] = useState(false);
24
+ const selectedIdSet = useMemo(() => new Set(selectedTagIds), [selectedTagIds]);
25
+ const selectedTags = useMemo(
26
+ () => tags.filter((tag) => selectedIdSet.has(tag.id)),
27
+ [tags, selectedIdSet]
28
+ );
29
+ const toggleTag = useCallback((tagId) => {
30
+ if (selectedIdSet.has(tagId)) {
31
+ onTagsChange(selectedTagIds.filter((id) => id !== tagId));
32
+ } else {
33
+ onTagsChange([...selectedTagIds, tagId]);
34
+ }
35
+ }, [selectedIdSet, selectedTagIds, onTagsChange]);
36
+ const clearTags = useCallback(() => {
37
+ onTagsChange([]);
38
+ }, [onTagsChange]);
39
+ if (isLoading) return null;
40
+ return /* @__PURE__ */ jsxs(
41
+ "div",
42
+ {
43
+ "data-cy": sel("media.tagFilter.container"),
44
+ className: cn("flex items-center gap-2 flex-wrap", className),
45
+ children: [
46
+ /* @__PURE__ */ jsxs(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
47
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
48
+ Button,
49
+ {
50
+ "data-cy": sel("media.tagFilter.trigger"),
51
+ variant: "outline",
52
+ size: "sm",
53
+ className: "h-8 gap-1",
54
+ children: [
55
+ /* @__PURE__ */ jsx(TagIcon, { className: "h-3.5 w-3.5" }),
56
+ t("dashboard.tags"),
57
+ selectedTagIds.length > 0 && /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "ml-1 h-5 px-1 text-xs", children: selectedTagIds.length })
58
+ ]
59
+ }
60
+ ) }),
61
+ /* @__PURE__ */ jsx(
62
+ PopoverContent,
63
+ {
64
+ "data-cy": sel("media.tagFilter.popover"),
65
+ className: "w-64 p-3",
66
+ align: "start",
67
+ children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
68
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: t("dashboard.filterByTag") }),
69
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: tags.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("dashboard.noTags") }) : tags.map((tag) => {
70
+ const isSelected = selectedIdSet.has(tag.id);
71
+ return /* @__PURE__ */ jsx(
72
+ Badge,
73
+ {
74
+ "data-cy": sel("media.tagFilter.tag", { id: tag.id }),
75
+ variant: isSelected ? "default" : "outline",
76
+ className: cn(
77
+ "cursor-pointer transition-colors",
78
+ isSelected && tag.color && "border-transparent"
79
+ ),
80
+ style: isSelected && tag.color ? { backgroundColor: tag.color, color: "#fff" } : void 0,
81
+ onClick: () => toggleTag(tag.id),
82
+ children: tag.name
83
+ },
84
+ tag.id
85
+ );
86
+ }) }),
87
+ selectedTagIds.length > 0 && /* @__PURE__ */ jsx(
88
+ Button,
89
+ {
90
+ variant: "ghost",
91
+ size: "sm",
92
+ className: "w-full h-7 text-xs",
93
+ onClick: clearTags,
94
+ children: t("dashboard.clearSelection")
95
+ }
96
+ )
97
+ ] })
98
+ }
99
+ )
100
+ ] }),
101
+ selectedTags.map((tag) => /* @__PURE__ */ jsxs(
102
+ Badge,
103
+ {
104
+ "data-cy": sel("media.tagFilter.activeTag", { id: tag.id }),
105
+ variant: "secondary",
106
+ className: "gap-1 cursor-pointer hover:bg-destructive/20",
107
+ style: tag.color ? { borderColor: tag.color } : void 0,
108
+ onClick: () => toggleTag(tag.id),
109
+ children: [
110
+ tag.name,
111
+ /* @__PURE__ */ jsx(XIcon, { className: "h-3 w-3" })
112
+ ]
113
+ },
114
+ tag.id
115
+ ))
116
+ ]
117
+ }
118
+ );
119
+ });
120
+ export {
121
+ MediaTagFilter
122
+ };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * MediaToolbar Component
3
+ *
4
+ * Toolbar with upload button, search input, filters, sort, and view toggle.
5
+ *
6
+ * Performance: Wrapped with memo. Sort options memoized.
7
+ */
8
+ import type { MediaListOptions } from '../../lib/media/types';
9
+ type ViewMode = 'grid' | 'list';
10
+ interface MediaToolbarProps {
11
+ onUploadClick?: () => void;
12
+ searchQuery: string;
13
+ onSearchChange: (query: string) => void;
14
+ typeFilter: 'all' | 'image' | 'video';
15
+ onTypeFilterChange: (type: 'all' | 'image' | 'video') => void;
16
+ sortBy: MediaListOptions['orderBy'];
17
+ sortDir: MediaListOptions['orderDir'];
18
+ onSortChange: (orderBy: MediaListOptions['orderBy'], orderDir: MediaListOptions['orderDir']) => void;
19
+ viewMode: ViewMode;
20
+ onViewModeChange: (mode: ViewMode) => void;
21
+ className?: string;
22
+ }
23
+ export declare const MediaToolbar: import("react").NamedExoticComponent<MediaToolbarProps>;
24
+ export {};
25
+ //# sourceMappingURL=MediaToolbar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaToolbar.d.ts","sourceRoot":"","sources":["../../../src/components/media/MediaToolbar.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAkBH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAE7D,KAAK,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAA;AAE/B,UAAU,iBAAiB;IACzB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAC1B,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,UAAU,EAAE,KAAK,GAAG,OAAO,GAAG,OAAO,CAAA;IACrC,kBAAkB,EAAE,CAAC,IAAI,EAAE,KAAK,GAAG,OAAO,GAAG,OAAO,KAAK,IAAI,CAAA;IAC7D,MAAM,EAAE,gBAAgB,CAAC,SAAS,CAAC,CAAA;IACnC,OAAO,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAA;IACrC,YAAY,EAAE,CAAC,OAAO,EAAE,gBAAgB,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,gBAAgB,CAAC,UAAU,CAAC,KAAK,IAAI,CAAA;IACpG,QAAQ,EAAE,QAAQ,CAAA;IAClB,gBAAgB,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAA;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,eAAO,MAAM,YAAY,yDAwHvB,CAAA"}
@@ -0,0 +1,136 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { memo, useMemo, useCallback } from "react";
4
+ import { useTranslations } from "next-intl";
5
+ import { UploadIcon, SearchIcon, GridIcon, ListIcon } from "lucide-react";
6
+ import { Button } from "../ui/button.js";
7
+ import { Input } from "../ui/input.js";
8
+ import {
9
+ Select,
10
+ SelectContent,
11
+ SelectItem,
12
+ SelectTrigger,
13
+ SelectValue
14
+ } from "../ui/select.js";
15
+ import { cn } from "../../lib/utils/index.js";
16
+ import { sel } from "../../lib/selectors/index.js";
17
+ const MediaToolbar = memo(function MediaToolbar2({
18
+ onUploadClick,
19
+ searchQuery,
20
+ onSearchChange,
21
+ typeFilter,
22
+ onTypeFilterChange,
23
+ sortBy = "createdAt",
24
+ sortDir = "desc",
25
+ onSortChange,
26
+ viewMode,
27
+ onViewModeChange,
28
+ className
29
+ }) {
30
+ const t = useTranslations("media");
31
+ const sortOptions = useMemo(() => [
32
+ { value: "createdAt:desc", label: t("toolbar.sort.newest"), orderBy: "createdAt", orderDir: "desc" },
33
+ { value: "createdAt:asc", label: t("toolbar.sort.oldest"), orderBy: "createdAt", orderDir: "asc" },
34
+ { value: "filename:asc", label: t("toolbar.sort.nameAsc"), orderBy: "filename", orderDir: "asc" },
35
+ { value: "filename:desc", label: t("toolbar.sort.nameDesc"), orderBy: "filename", orderDir: "desc" },
36
+ { value: "fileSize:desc", label: t("toolbar.sort.sizeDesc"), orderBy: "fileSize", orderDir: "desc" },
37
+ { value: "fileSize:asc", label: t("toolbar.sort.sizeAsc"), orderBy: "fileSize", orderDir: "asc" }
38
+ ], [t]);
39
+ const currentSortValue = `${sortBy}:${sortDir}`;
40
+ const handleSortChange = useCallback((value) => {
41
+ const option = sortOptions.find((opt) => opt.value === value);
42
+ if (option) {
43
+ onSortChange(option.orderBy, option.orderDir);
44
+ }
45
+ }, [sortOptions, onSortChange]);
46
+ return /* @__PURE__ */ jsxs(
47
+ "div",
48
+ {
49
+ "data-cy": sel("media.toolbar.container"),
50
+ className: cn("flex flex-col sm:flex-row gap-2 sm:items-center", className),
51
+ children: [
52
+ onUploadClick && /* @__PURE__ */ jsxs(
53
+ Button,
54
+ {
55
+ "data-cy": sel("media.toolbar.uploadBtn"),
56
+ onClick: onUploadClick,
57
+ className: "shrink-0",
58
+ children: [
59
+ /* @__PURE__ */ jsx(UploadIcon, { className: "mr-2 h-4 w-4" }),
60
+ t("toolbar.upload")
61
+ ]
62
+ }
63
+ ),
64
+ /* @__PURE__ */ jsxs("div", { className: "relative flex-1 min-w-[200px]", children: [
65
+ /* @__PURE__ */ jsx(SearchIcon, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground pointer-events-none" }),
66
+ /* @__PURE__ */ jsx(
67
+ Input,
68
+ {
69
+ "data-cy": sel("media.toolbar.searchInput"),
70
+ type: "text",
71
+ placeholder: t("toolbar.search"),
72
+ value: searchQuery,
73
+ onChange: (e) => onSearchChange(e.target.value),
74
+ className: "pl-9"
75
+ }
76
+ )
77
+ ] }),
78
+ /* @__PURE__ */ jsxs(Select, { value: typeFilter, onValueChange: (value) => onTypeFilterChange(value), children: [
79
+ /* @__PURE__ */ jsx(
80
+ SelectTrigger,
81
+ {
82
+ "data-cy": sel("media.toolbar.typeFilter"),
83
+ className: "w-full sm:w-[150px]",
84
+ children: /* @__PURE__ */ jsx(SelectValue, {})
85
+ }
86
+ ),
87
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
88
+ /* @__PURE__ */ jsx(SelectItem, { value: "all", children: t("toolbar.typeFilter.all") }),
89
+ /* @__PURE__ */ jsx(SelectItem, { value: "image", children: t("toolbar.typeFilter.images") }),
90
+ /* @__PURE__ */ jsx(SelectItem, { value: "video", children: t("toolbar.typeFilter.videos") })
91
+ ] })
92
+ ] }),
93
+ /* @__PURE__ */ jsxs(Select, { value: currentSortValue, onValueChange: handleSortChange, children: [
94
+ /* @__PURE__ */ jsx(
95
+ SelectTrigger,
96
+ {
97
+ "data-cy": sel("media.toolbar.sortSelect"),
98
+ className: "w-full sm:w-[180px]",
99
+ children: /* @__PURE__ */ jsx(SelectValue, {})
100
+ }
101
+ ),
102
+ /* @__PURE__ */ jsx(SelectContent, { children: sortOptions.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.value, children: option.label }, option.value)) })
103
+ ] }),
104
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-1 shrink-0", children: [
105
+ /* @__PURE__ */ jsx(
106
+ Button,
107
+ {
108
+ "data-cy": sel("media.toolbar.viewToggle.grid"),
109
+ variant: viewMode === "grid" ? "default" : "outline",
110
+ size: "icon",
111
+ onClick: () => onViewModeChange("grid"),
112
+ "aria-label": t("toolbar.viewGrid"),
113
+ title: t("toolbar.viewGrid"),
114
+ children: /* @__PURE__ */ jsx(GridIcon, { className: "h-4 w-4" })
115
+ }
116
+ ),
117
+ /* @__PURE__ */ jsx(
118
+ Button,
119
+ {
120
+ "data-cy": sel("media.toolbar.viewToggle.list"),
121
+ variant: viewMode === "list" ? "default" : "outline",
122
+ size: "icon",
123
+ onClick: () => onViewModeChange("list"),
124
+ "aria-label": t("toolbar.viewList"),
125
+ title: t("toolbar.viewList"),
126
+ children: /* @__PURE__ */ jsx(ListIcon, { className: "h-4 w-4" })
127
+ }
128
+ )
129
+ ] })
130
+ ]
131
+ }
132
+ );
133
+ });
134
+ export {
135
+ MediaToolbar
136
+ };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * MediaUploadZone Component
3
+ *
4
+ * Drag-and-drop file upload area with progress indicators.
5
+ * Uses useMediaUpload hook for upload mutations.
6
+ *
7
+ * Performance: Uses ref-based drag counter to avoid excessive setState
8
+ * on dragEnter/dragLeave events from nested elements.
9
+ */
10
+ import type { Media } from '../../lib/media/types';
11
+ interface MediaUploadZoneProps {
12
+ onUploadComplete?: (uploadedMedia: Media[]) => void;
13
+ maxSizeMB?: number;
14
+ acceptedTypes?: string[];
15
+ className?: string;
16
+ }
17
+ export declare function MediaUploadZone({ onUploadComplete, maxSizeMB, acceptedTypes, className, }: MediaUploadZoneProps): import("react/jsx-runtime").JSX.Element;
18
+ export {};
19
+ //# sourceMappingURL=MediaUploadZone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaUploadZone.d.ts","sourceRoot":"","sources":["../../../src/components/media/MediaUploadZone.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAcH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAQlD,UAAU,oBAAoB;IAC5B,gBAAgB,CAAC,EAAE,CAAC,aAAa,EAAE,KAAK,EAAE,KAAK,IAAI,CAAA;IACnD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,eAAe,CAAC,EAC9B,gBAAgB,EAChB,SAAc,EACd,aAAsC,EACtC,SAAS,GACV,EAAE,oBAAoB,2CAgQtB"}
@@ -0,0 +1,248 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState, useRef, useCallback } from "react";
4
+ import { useTranslations } from "next-intl";
5
+ import { UploadCloudIcon, LoaderIcon, XCircleIcon, AlertTriangleIcon } from "lucide-react";
6
+ import { Button } from "../ui/button.js";
7
+ import { Progress } from "../ui/progress.js";
8
+ import { Alert, AlertDescription } from "../ui/alert.js";
9
+ import { cn } from "../../lib/utils/index.js";
10
+ import { sel } from "../../lib/selectors/index.js";
11
+ import { useMediaUpload } from "../../hooks/useMediaUpload.js";
12
+ import { useToast } from "../../hooks/useToast.js";
13
+ function MediaUploadZone({
14
+ onUploadComplete,
15
+ maxSizeMB = 10,
16
+ acceptedTypes = ["image/*", "video/*"],
17
+ className
18
+ }) {
19
+ const t = useTranslations("media");
20
+ const { toast } = useToast();
21
+ const [isDragging, setIsDragging] = useState(false);
22
+ const [isChecking, setIsChecking] = useState(false);
23
+ const [pendingFiles, setPendingFiles] = useState(null);
24
+ const [duplicates, setDuplicates] = useState([]);
25
+ const fileInputRef = useRef(null);
26
+ const dragCounterRef = useRef(0);
27
+ const uploadMutation = useMediaUpload();
28
+ const checkForDuplicates = async (files) => {
29
+ var _a;
30
+ try {
31
+ const res = await fetch("/api/v1/media/check-duplicates", {
32
+ method: "POST",
33
+ headers: { "Content-Type": "application/json" },
34
+ body: JSON.stringify({
35
+ files: files.map((f) => ({ filename: f.name, fileSize: f.size }))
36
+ })
37
+ });
38
+ if (!res.ok) return [];
39
+ const json = await res.json();
40
+ return ((_a = json.data) == null ? void 0 : _a.duplicates) || [];
41
+ } catch {
42
+ return [];
43
+ }
44
+ };
45
+ const doUpload = async (files) => {
46
+ try {
47
+ const result = await uploadMutation.mutateAsync(files);
48
+ toast({
49
+ title: t("upload.success"),
50
+ description: files.length === 1 ? t("upload.success") : t("upload.successMultiple", { count: files.length })
51
+ });
52
+ onUploadComplete == null ? void 0 : onUploadComplete(result.media || []);
53
+ } catch (error) {
54
+ toast({
55
+ title: t("upload.error"),
56
+ description: error instanceof Error ? error.message : t("upload.error"),
57
+ variant: "destructive"
58
+ });
59
+ }
60
+ };
61
+ const handleFiles = async (files) => {
62
+ if (!files || files.length === 0) return;
63
+ const fileArray = Array.from(files);
64
+ const maxSizeBytes = maxSizeMB * 1024 * 1024;
65
+ const oversizedFiles = fileArray.filter((f) => f.size > maxSizeBytes);
66
+ if (oversizedFiles.length > 0) {
67
+ toast({
68
+ title: t("upload.error"),
69
+ description: t("upload.tooLarge"),
70
+ variant: "destructive"
71
+ });
72
+ return;
73
+ }
74
+ setIsChecking(true);
75
+ const dupes = await checkForDuplicates(fileArray);
76
+ setIsChecking(false);
77
+ if (dupes.length > 0) {
78
+ setDuplicates(dupes);
79
+ setPendingFiles(fileArray);
80
+ return;
81
+ }
82
+ await doUpload(fileArray);
83
+ };
84
+ const handleUploadAll = async () => {
85
+ if (!pendingFiles) return;
86
+ setDuplicates([]);
87
+ const files = pendingFiles;
88
+ setPendingFiles(null);
89
+ await doUpload(files);
90
+ };
91
+ const handleSkipDuplicates = async () => {
92
+ if (!pendingFiles) return;
93
+ const dupeNames = new Set(duplicates.map((d) => `${d.filename}:${d.fileSize}`));
94
+ const nonDuplicates = pendingFiles.filter((f) => !dupeNames.has(`${f.name}:${f.size}`));
95
+ setDuplicates([]);
96
+ setPendingFiles(null);
97
+ if (nonDuplicates.length > 0) {
98
+ await doUpload(nonDuplicates);
99
+ } else {
100
+ toast({ title: t("upload.error"), description: t("upload.duplicateFound", { count: duplicates.length }) });
101
+ }
102
+ };
103
+ const handleDismissDuplicates = () => {
104
+ setDuplicates([]);
105
+ setPendingFiles(null);
106
+ };
107
+ const handleDragEnter = useCallback((e) => {
108
+ e.preventDefault();
109
+ e.stopPropagation();
110
+ dragCounterRef.current++;
111
+ if (dragCounterRef.current === 1) {
112
+ setIsDragging(true);
113
+ }
114
+ }, []);
115
+ const handleDragOver = useCallback((e) => {
116
+ e.preventDefault();
117
+ e.stopPropagation();
118
+ }, []);
119
+ const handleDragLeave = useCallback((e) => {
120
+ e.preventDefault();
121
+ e.stopPropagation();
122
+ dragCounterRef.current--;
123
+ if (dragCounterRef.current === 0) {
124
+ setIsDragging(false);
125
+ }
126
+ }, []);
127
+ const handleDrop = async (e) => {
128
+ e.preventDefault();
129
+ e.stopPropagation();
130
+ dragCounterRef.current = 0;
131
+ setIsDragging(false);
132
+ await handleFiles(e.dataTransfer.files);
133
+ };
134
+ const handleFileInputChange = (e) => {
135
+ handleFiles(e.target.files);
136
+ };
137
+ const handleBrowseClick = () => {
138
+ var _a;
139
+ (_a = fileInputRef.current) == null ? void 0 : _a.click();
140
+ };
141
+ const isBusy = uploadMutation.isPending || isChecking;
142
+ return /* @__PURE__ */ jsxs("div", { className: cn("w-full space-y-3", className), children: [
143
+ duplicates.length > 0 && /* @__PURE__ */ jsxs(Alert, { variant: "destructive", className: "border-amber-500/50 bg-amber-50 text-amber-900 dark:bg-amber-950/30 dark:text-amber-200 [&>svg]:text-amber-600", children: [
144
+ /* @__PURE__ */ jsx(AlertTriangleIcon, { className: "h-4 w-4" }),
145
+ /* @__PURE__ */ jsxs(AlertDescription, { className: "flex items-center justify-between gap-4", children: [
146
+ /* @__PURE__ */ jsxs("div", { children: [
147
+ /* @__PURE__ */ jsx("p", { className: "font-medium", children: t("upload.duplicateFound", { count: duplicates.length }) }),
148
+ /* @__PURE__ */ jsx("p", { className: "text-xs mt-0.5 opacity-80", children: duplicates.map((d) => d.filename).join(", ") })
149
+ ] }),
150
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [
151
+ /* @__PURE__ */ jsx(
152
+ Button,
153
+ {
154
+ size: "sm",
155
+ variant: "outline",
156
+ className: "border-amber-500/50 hover:bg-amber-100 dark:hover:bg-amber-900/30",
157
+ onClick: handleSkipDuplicates,
158
+ children: t("upload.duplicateSkip")
159
+ }
160
+ ),
161
+ /* @__PURE__ */ jsx(
162
+ Button,
163
+ {
164
+ size: "sm",
165
+ onClick: handleUploadAll,
166
+ children: t("upload.duplicateUploadAll")
167
+ }
168
+ ),
169
+ /* @__PURE__ */ jsx(
170
+ Button,
171
+ {
172
+ size: "sm",
173
+ variant: "ghost",
174
+ onClick: handleDismissDuplicates,
175
+ children: /* @__PURE__ */ jsx(XCircleIcon, { className: "h-4 w-4" })
176
+ }
177
+ )
178
+ ] })
179
+ ] })
180
+ ] }),
181
+ /* @__PURE__ */ jsxs(
182
+ "div",
183
+ {
184
+ "data-cy": sel("media.upload.dropzone"),
185
+ className: cn(
186
+ "border-2 border-dashed rounded-lg p-8 text-center transition-all duration-200",
187
+ isDragging ? "border-primary bg-primary/5 scale-[1.01]" : "border-muted-foreground/25 hover:border-muted-foreground/50",
188
+ isBusy && "opacity-50 pointer-events-none"
189
+ ),
190
+ onDragEnter: handleDragEnter,
191
+ onDragOver: handleDragOver,
192
+ onDragLeave: handleDragLeave,
193
+ onDrop: handleDrop,
194
+ children: [
195
+ uploadMutation.isPending || isChecking ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-4", children: [
196
+ /* @__PURE__ */ jsx(LoaderIcon, { className: "h-12 w-12 animate-spin text-primary" }),
197
+ /* @__PURE__ */ jsxs("div", { className: "w-full max-w-xs", children: [
198
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-2", children: t("upload.uploading") }),
199
+ /* @__PURE__ */ jsx(
200
+ Progress,
201
+ {
202
+ "data-cy": sel("media.upload.progressBar"),
203
+ value: void 0,
204
+ className: "w-full"
205
+ }
206
+ )
207
+ ] })
208
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-4", children: [
209
+ /* @__PURE__ */ jsx(UploadCloudIcon, { className: "h-12 w-12 text-muted-foreground" }),
210
+ /* @__PURE__ */ jsxs("div", { children: [
211
+ /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
212
+ t("upload.dragDrop"),
213
+ " ",
214
+ /* @__PURE__ */ jsx(
215
+ Button,
216
+ {
217
+ type: "button",
218
+ variant: "link",
219
+ className: "p-0 h-auto text-primary",
220
+ onClick: handleBrowseClick,
221
+ children: t("upload.browse")
222
+ }
223
+ )
224
+ ] }),
225
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: t("upload.maxSize", { maxSize: maxSizeMB }) })
226
+ ] })
227
+ ] }),
228
+ /* @__PURE__ */ jsx(
229
+ "input",
230
+ {
231
+ "data-cy": sel("media.upload.fileInput"),
232
+ ref: fileInputRef,
233
+ type: "file",
234
+ multiple: true,
235
+ accept: acceptedTypes.join(","),
236
+ onChange: handleFileInputChange,
237
+ className: "hidden",
238
+ "aria-label": t("toolbar.upload")
239
+ }
240
+ )
241
+ ]
242
+ }
243
+ )
244
+ ] });
245
+ }
246
+ export {
247
+ MediaUploadZone
248
+ };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Media Components - Barrel Export
3
+ *
4
+ * All media library components for easy importing.
5
+ */
6
+ export { MediaCard } from './MediaCard';
7
+ export { MediaDetailPanel } from './MediaDetailPanel';
8
+ export { MediaGrid } from './MediaGrid';
9
+ export { MediaLibrary } from './MediaLibrary';
10
+ export { MediaList } from './MediaList';
11
+ export { MediaSelector } from './MediaSelector';
12
+ export { MediaTagFilter } from './MediaTagFilter';
13
+ export { MediaToolbar } from './MediaToolbar';
14
+ export { MediaUploadZone } from './MediaUploadZone';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/media/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA"}
@@ -0,0 +1,20 @@
1
+ import { MediaCard } from "./MediaCard.js";
2
+ import { MediaDetailPanel } from "./MediaDetailPanel.js";
3
+ import { MediaGrid } from "./MediaGrid.js";
4
+ import { MediaLibrary } from "./MediaLibrary.js";
5
+ import { MediaList } from "./MediaList.js";
6
+ import { MediaSelector } from "./MediaSelector.js";
7
+ import { MediaTagFilter } from "./MediaTagFilter.js";
8
+ import { MediaToolbar } from "./MediaToolbar.js";
9
+ import { MediaUploadZone } from "./MediaUploadZone.js";
10
+ export {
11
+ MediaCard,
12
+ MediaDetailPanel,
13
+ MediaGrid,
14
+ MediaLibrary,
15
+ MediaList,
16
+ MediaSelector,
17
+ MediaTagFilter,
18
+ MediaToolbar,
19
+ MediaUploadZone
20
+ };
@@ -72,7 +72,7 @@ function TeamProvider({ children }) {
72
72
  const activeTeam = storedTeam || userTeams[0];
73
73
  if (activeTeam) {
74
74
  setCurrentTeam(activeTeam.team);
75
- if (typeof window !== "undefined" && storedTeamId !== activeTeam.team.id) {
75
+ if (typeof window !== "undefined") {
76
76
  localStorage.setItem("activeTeamId", activeTeam.team.id);
77
77
  }
78
78
  if (typeof window !== "undefined") {
@@ -18,6 +18,8 @@ export * from './useInvoice';
18
18
  export * from './useInvoices';
19
19
  export * from './useLastAuthMethod';
20
20
  export * from './useLocale';
21
+ export * from './useMedia';
22
+ export * from './useMediaUpload';
21
23
  export * from './useMembership';
22
24
  export * from './useNotifications';
23
25
  export * from './useOrigin';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAGA,cAAc,4BAA4B,CAAA;AAC1C,cAAc,WAAW,CAAA;AACzB,cAAc,yBAAyB,CAAA;AACvC,cAAc,yBAAyB,CAAA;AACvC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,eAAe,CAAA;AAC7B,cAAc,sBAAsB,CAAA;AACpC,cAAc,yBAAyB,CAAA;AACvC,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,cAAc,sBAAsB,CAAA;AACpC,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,qBAAqB,CAAA;AACnC,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,aAAa,CAAA;AAC3B,cAAc,oBAAoB,CAAA;AAClC,cAAc,0BAA0B,CAAA;AACxC,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,WAAW,CAAA;AACzB,cAAc,sBAAsB,CAAA;AACpC,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA;AAC1B,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,wBAAwB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAGA,cAAc,4BAA4B,CAAA;AAC1C,cAAc,WAAW,CAAA;AACzB,cAAc,yBAAyB,CAAA;AACvC,cAAc,yBAAyB,CAAA;AACvC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,eAAe,CAAA;AAC7B,cAAc,sBAAsB,CAAA;AACpC,cAAc,yBAAyB,CAAA;AACvC,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,cAAc,sBAAsB,CAAA;AACpC,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,qBAAqB,CAAA;AACnC,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,aAAa,CAAA;AAC3B,cAAc,oBAAoB,CAAA;AAClC,cAAc,0BAA0B,CAAA;AACxC,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,WAAW,CAAA;AACzB,cAAc,sBAAsB,CAAA;AACpC,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA;AAC1B,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,wBAAwB,CAAA"}
@@ -18,6 +18,8 @@ export * from "./useInvoice.js";
18
18
  export * from "./useInvoices.js";
19
19
  export * from "./useLastAuthMethod.js";
20
20
  export * from "./useLocale.js";
21
+ export * from "./useMedia.js";
22
+ export * from "./useMediaUpload.js";
21
23
  export * from "./useMembership.js";
22
24
  export * from "./useNotifications.js";
23
25
  export * from "./useOrigin.js";
@@ -1,2 +1,6 @@
1
+ /**
2
+ * Hook to ensure user has default metadata
3
+ * Uses TanStack Query for proper caching and deduplication
4
+ */
1
5
  export declare function useEnsureUserMetadata(): void;
2
6
  //# sourceMappingURL=useEnsureUserMetadata.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useEnsureUserMetadata.d.ts","sourceRoot":"","sources":["../../src/hooks/useEnsureUserMetadata.ts"],"names":[],"mappings":"AAMA,wBAAgB,qBAAqB,SAuEpC"}
1
+ {"version":3,"file":"useEnsureUserMetadata.d.ts","sourceRoot":"","sources":["../../src/hooks/useEnsureUserMetadata.ts"],"names":[],"mappings":"AAsDA;;;GAGG;AACH,wBAAgB,qBAAqB,SA+DpC"}