robodev 0.11.0 → 0.13.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 (329) hide show
  1. package/package.json +1 -1
  2. package/src/collect-files.test.ts +19 -0
  3. package/src/collect-files.ts +1 -0
  4. package/src/config.test.ts +26 -0
  5. package/src/config.ts +34 -5
  6. package/src/emit-starter.test.ts +68 -0
  7. package/src/emit-starter.ts +47 -13
  8. package/src/index.ts +45 -4
  9. package/templates/auth-chat/.config/local.spa.template.yml +27 -0
  10. package/templates/auth-chat/.oxlint-base.json +29 -0
  11. package/templates/auth-chat/.oxlintrc.json +78 -0
  12. package/templates/auth-chat/.rulesync/rules/frontend-api-boundary.md +36 -0
  13. package/templates/auth-chat/.rulesync/rules/frontend-component-structure.md +38 -0
  14. package/templates/auth-chat/.rulesync/rules/frontend-forms.md +32 -0
  15. package/templates/auth-chat/.rulesync/rules/frontend-notifications.md +24 -0
  16. package/templates/auth-chat/.rulesync/rules/frontend-povio-components.md +42 -0
  17. package/templates/auth-chat/.rulesync/rules/frontend-povio-ui.md +45 -0
  18. package/templates/auth-chat/.rulesync/rules/frontend-query-autocomplete.md +29 -0
  19. package/templates/auth-chat/.rulesync/rules/frontend-tables-and-lists.md +34 -0
  20. package/templates/auth-chat/.rulesync/rules/frontend-translations.md +26 -0
  21. package/templates/auth-chat/.rulesync/rules/project-overview.md +32 -0
  22. package/templates/auth-chat/.rulesync/rules/robodev-api.md +30 -0
  23. package/templates/auth-chat/.rulesync/rules/robodev-auth.md +40 -0
  24. package/templates/auth-chat/.rulesync/rules/robodev-database.md +22 -0
  25. package/templates/auth-chat/.rulesync/rules/role-based-app-structure.md +36 -0
  26. package/templates/auth-chat/.rulesync/skills/media-feature/SKILL.md +21 -0
  27. package/templates/auth-chat/.rulesync/skills/povio-ui-styling/SKILL.md +208 -0
  28. package/templates/auth-chat/.rulesync/skills/povio-ui-styling/agents/openai.yaml +4 -0
  29. package/templates/auth-chat/.rulesync/skills/robodev-api-route/SKILL.md +13 -0
  30. package/templates/auth-chat/.rulesync/skills/robodev-table/SKILL.md +12 -0
  31. package/templates/auth-chat/README.md +26 -7
  32. package/templates/auth-chat/api/invite.ts +43 -0
  33. package/templates/auth-chat/apps/fe/index.html +24 -0
  34. package/templates/auth-chat/apps/fe/openapi-codegen.config.ts +37 -0
  35. package/templates/auth-chat/apps/fe/package.json +82 -0
  36. package/templates/auth-chat/apps/fe/public/apple-touch-icon.png +0 -0
  37. package/templates/auth-chat/apps/fe/public/favicon-96x96.png +0 -0
  38. package/templates/auth-chat/apps/fe/public/favicon.ico +0 -0
  39. package/templates/auth-chat/apps/fe/public/favicon.svg +3 -0
  40. package/templates/auth-chat/apps/fe/public/site.webmanifest +21 -0
  41. package/templates/auth-chat/apps/fe/public/web-app-manifest-192x192.png +0 -0
  42. package/templates/auth-chat/apps/fe/public/web-app-manifest-512x512.png +0 -0
  43. package/templates/auth-chat/apps/fe/src/assets/fonts/GeneralSans-Bold.otf +0 -0
  44. package/templates/auth-chat/apps/fe/src/assets/fonts/GeneralSans-Medium.otf +0 -0
  45. package/templates/auth-chat/apps/fe/src/assets/fonts/GeneralSans-Regular.otf +0 -0
  46. package/templates/auth-chat/apps/fe/src/assets/fonts/GeneralSans-Semibold.otf +0 -0
  47. package/templates/auth-chat/apps/fe/src/assets/locales/en/translation.json +202 -0
  48. package/templates/auth-chat/apps/fe/src/assets/locales/sl/translation.json +202 -0
  49. package/templates/auth-chat/apps/fe/src/clients/app-rest-client.ts +15 -0
  50. package/templates/auth-chat/apps/fe/src/clients/auth-token-store.ts +101 -0
  51. package/templates/auth-chat/apps/fe/src/clients/rest/app-error-handler.ts +31 -0
  52. package/templates/auth-chat/apps/fe/src/clients/rest/interceptors/authorization-header.interceptor.ts +15 -0
  53. package/templates/auth-chat/apps/fe/src/clients/rest/interceptors/refresh-token.interceptor.ts +37 -0
  54. package/templates/auth-chat/apps/fe/src/clients/rest/interceptors/response.interceptor.ts +17 -0
  55. package/templates/auth-chat/apps/fe/src/components/404.tsx +18 -0
  56. package/templates/auth-chat/apps/fe/src/components/features/auth/AuthBrandPanel.tsx +60 -0
  57. package/templates/auth-chat/apps/fe/src/components/features/auth/AuthLayout.tsx +23 -0
  58. package/templates/auth-chat/apps/fe/src/components/features/auth/LoginPage.tsx +111 -0
  59. package/templates/auth-chat/apps/fe/src/components/features/auth/RegisterPage.tsx +143 -0
  60. package/templates/auth-chat/apps/fe/src/components/features/chat/ChatPage.tsx +105 -0
  61. package/templates/auth-chat/apps/fe/src/components/features/chat/InviteForm.tsx +84 -0
  62. package/templates/auth-chat/apps/fe/src/components/features/profile/ProfilePage.tsx +96 -0
  63. package/templates/auth-chat/apps/fe/src/components/googleAnalytics/GoogleAnalytics.tsx +35 -0
  64. package/templates/auth-chat/apps/fe/src/components/layout/AppLayout.tsx +19 -0
  65. package/templates/auth-chat/apps/fe/src/components/layout/app-header/AppHeader.tsx +91 -0
  66. package/templates/auth-chat/apps/fe/src/components/layout/app-header/MobileNavigation.tsx +51 -0
  67. package/templates/auth-chat/apps/fe/src/components/layout/app-header/NavLink.tsx +29 -0
  68. package/templates/auth-chat/apps/fe/src/components/shared/branding/BrandLogo.tsx +13 -0
  69. package/templates/auth-chat/apps/fe/src/components/shared/error/ErrorFallback.tsx +43 -0
  70. package/templates/auth-chat/apps/fe/src/components/shared/error/ErrorText.tsx +20 -0
  71. package/templates/auth-chat/apps/fe/src/components/shared/error/NotFound.tsx +36 -0
  72. package/templates/auth-chat/apps/fe/src/components/shared/forms/RequiredLabel.tsx +21 -0
  73. package/templates/auth-chat/apps/fe/src/components/shared/forms/RowInputWrapper.tsx +50 -0
  74. package/templates/auth-chat/apps/fe/src/components/shared/head/AppHead.tsx +32 -0
  75. package/templates/auth-chat/apps/fe/src/components/shared/head/DefaultAppHead.tsx +34 -0
  76. package/templates/auth-chat/apps/fe/src/components/shared/layout/LoadingState.tsx +9 -0
  77. package/templates/auth-chat/apps/fe/src/components/shared/layout/ThinPageWrapper.tsx +5 -0
  78. package/templates/auth-chat/apps/fe/src/components/shared/page/PageHeader.tsx +69 -0
  79. package/templates/auth-chat/apps/fe/src/components/shared/ui/Card.tsx +60 -0
  80. package/templates/auth-chat/apps/fe/src/components/shared/ui/GoogleLoginButton.tsx +19 -0
  81. package/templates/auth-chat/apps/fe/src/components/shared/ui/RequiredLabel.tsx +22 -0
  82. package/templates/auth-chat/apps/fe/src/components/shared/ui/TableActions.tsx +22 -0
  83. package/templates/auth-chat/apps/fe/src/config/app.config.ts +35 -0
  84. package/templates/auth-chat/apps/fe/src/config/i18n.ts +43 -0
  85. package/templates/auth-chat/apps/fe/src/config/inits/a11y.ts +14 -0
  86. package/templates/auth-chat/apps/fe/src/config/inits/logger.ts +7 -0
  87. package/templates/auth-chat/apps/fe/src/config/inits/sentry.ts +21 -0
  88. package/templates/auth-chat/apps/fe/src/config/jwt.config.ts +2 -0
  89. package/templates/auth-chat/apps/fe/src/config/query.config.ts +20 -0
  90. package/templates/auth-chat/apps/fe/src/hooks/useAuth.ts +5 -0
  91. package/templates/auth-chat/apps/fe/src/main.tsx +52 -0
  92. package/templates/auth-chat/apps/fe/src/pages/(guest)/login.tsx +23 -0
  93. package/templates/auth-chat/apps/fe/src/pages/(guest)/register.tsx +23 -0
  94. package/templates/auth-chat/apps/fe/src/pages/(guest)/route.tsx +18 -0
  95. package/templates/auth-chat/apps/fe/src/pages/(private)/index.tsx +23 -0
  96. package/templates/auth-chat/apps/fe/src/pages/(private)/profile.tsx +23 -0
  97. package/templates/auth-chat/apps/fe/src/pages/(private)/route.tsx +18 -0
  98. package/templates/auth-chat/apps/fe/src/pages/(public)/auth.tsx +37 -0
  99. package/templates/auth-chat/apps/fe/src/pages/(public)/route.tsx +9 -0
  100. package/templates/auth-chat/apps/fe/src/pages/__root.tsx +164 -0
  101. package/templates/auth-chat/apps/fe/src/providers/AppErrorBoundary.tsx +10 -0
  102. package/templates/auth-chat/apps/fe/src/providers/OpenApiRuntimeProvider.tsx +31 -0
  103. package/templates/auth-chat/apps/fe/src/providers/index.tsx +44 -0
  104. package/templates/auth-chat/apps/fe/src/providers/jwt.provider.tsx +95 -0
  105. package/templates/auth-chat/apps/fe/src/routeTree.gen.ts +225 -0
  106. package/templates/auth-chat/apps/fe/src/styles/base.css +103 -0
  107. package/templates/auth-chat/apps/fe/src/styles/fonts/fonts.tsx +10 -0
  108. package/templates/auth-chat/apps/fe/src/styles/fonts/general-sans.css +31 -0
  109. package/templates/auth-chat/apps/fe/src/styles/globals.css +28 -0
  110. package/templates/auth-chat/apps/fe/src/styles/overrides/defaults/button.override.ts +536 -0
  111. package/templates/auth-chat/apps/fe/src/styles/overrides/defaults/checkbox.override.ts +71 -0
  112. package/templates/auth-chat/apps/fe/src/styles/overrides/defaults/input.override.ts +252 -0
  113. package/templates/auth-chat/apps/fe/src/styles/overrides/defaults/label.override.ts +91 -0
  114. package/templates/auth-chat/apps/fe/src/styles/overrides/defaults/modal.override.ts +57 -0
  115. package/templates/auth-chat/apps/fe/src/styles/overrides/defaults/radio.override.ts +46 -0
  116. package/templates/auth-chat/apps/fe/src/styles/overrides/defaults/table.override.ts +104 -0
  117. package/templates/auth-chat/apps/fe/src/styles/overrides/defaults/tag.override.ts +66 -0
  118. package/templates/auth-chat/apps/fe/src/styles/overrides/defaults/typography.override.ts +115 -0
  119. package/templates/auth-chat/apps/fe/src/styles/overrides/outline.clsx.ts +10 -0
  120. package/templates/auth-chat/apps/fe/src/styles/overrides/uiOverrides.override.ts +60 -0
  121. package/templates/auth-chat/apps/fe/src/styles/theme.css +2177 -0
  122. package/templates/auth-chat/apps/fe/src/types/i18next.d.ts +12 -0
  123. package/templates/auth-chat/apps/fe/src/types/table.d.ts +17 -0
  124. package/templates/auth-chat/apps/fe/src/types/ui.d.ts +26 -0
  125. package/templates/auth-chat/apps/fe/src/types/vite-env.d.ts +20 -0
  126. package/templates/auth-chat/apps/fe/src/utils/date.utils.ts +17 -0
  127. package/templates/auth-chat/apps/fe/src/utils/number.utils.ts +12 -0
  128. package/templates/auth-chat/apps/fe/src/utils/string.utils.ts +5 -0
  129. package/templates/auth-chat/apps/fe/src/vite-env.d.ts +1 -0
  130. package/templates/auth-chat/apps/fe/tsconfig.app.json +32 -0
  131. package/templates/auth-chat/apps/fe/tsconfig.json +9 -0
  132. package/templates/auth-chat/apps/fe/tsconfig.node.json +31 -0
  133. package/templates/auth-chat/apps/fe/vite.config.ts +94 -0
  134. package/templates/auth-chat/openapi.json +1016 -0
  135. package/templates/auth-chat/oxfmt.config.js +23 -0
  136. package/templates/auth-chat/package.json +6 -13
  137. package/templates/auth-chat/rulesync.jsonc +18 -0
  138. package/templates/auth-chat/tsconfig.json +2 -4
  139. package/templates/backend/README.md +2 -2
  140. package/templates/backend/api/_lib.ts +359 -0
  141. package/templates/backend/api/aliens/labels.ts +19 -0
  142. package/templates/backend/api/files/presigned-url.ts +48 -0
  143. package/templates/backend/api/files/upload.ts +29 -0
  144. package/templates/backend/api/planets/[id]/like.ts +36 -0
  145. package/templates/backend/api/planets/[id].ts +56 -13
  146. package/templates/backend/api/planets/paginate.ts +36 -0
  147. package/templates/backend/api/planets.ts +52 -44
  148. package/templates/backend/database.ts +33 -13
  149. package/templates/backend/package.json +1 -1
  150. package/templates/catalog.json +3 -3
  151. package/templates/empty/package.json +1 -1
  152. package/templates/space/.config/local.spa.template.yml +27 -0
  153. package/templates/space/.oxlint-base.json +29 -0
  154. package/templates/space/.oxlintrc.json +78 -0
  155. package/templates/space/.rulesync/rules/frontend-api-boundary.md +36 -0
  156. package/templates/space/.rulesync/rules/frontend-component-structure.md +38 -0
  157. package/templates/space/.rulesync/rules/frontend-forms.md +32 -0
  158. package/templates/space/.rulesync/rules/frontend-notifications.md +24 -0
  159. package/templates/space/.rulesync/rules/frontend-povio-components.md +42 -0
  160. package/templates/space/.rulesync/rules/frontend-povio-ui.md +45 -0
  161. package/templates/space/.rulesync/rules/frontend-query-autocomplete.md +29 -0
  162. package/templates/space/.rulesync/rules/frontend-tables-and-lists.md +34 -0
  163. package/templates/space/.rulesync/rules/frontend-translations.md +26 -0
  164. package/templates/space/.rulesync/rules/project-overview.md +32 -0
  165. package/templates/space/.rulesync/rules/robodev-api.md +30 -0
  166. package/templates/space/.rulesync/rules/robodev-auth.md +40 -0
  167. package/templates/space/.rulesync/rules/robodev-database.md +22 -0
  168. package/templates/space/.rulesync/rules/role-based-app-structure.md +36 -0
  169. package/templates/space/.rulesync/skills/media-feature/SKILL.md +21 -0
  170. package/templates/space/.rulesync/skills/povio-ui-styling/SKILL.md +208 -0
  171. package/templates/space/.rulesync/skills/povio-ui-styling/agents/openai.yaml +4 -0
  172. package/templates/space/.rulesync/skills/robodev-api-route/SKILL.md +13 -0
  173. package/templates/space/.rulesync/skills/robodev-table/SKILL.md +12 -0
  174. package/templates/space/README.md +26 -7
  175. package/templates/space/api/_lib.ts +359 -0
  176. package/templates/space/api/aliens/labels.ts +19 -0
  177. package/templates/space/api/files/presigned-url.ts +48 -0
  178. package/templates/space/api/files/upload.ts +29 -0
  179. package/templates/space/api/planets/[id]/like.ts +36 -0
  180. package/templates/space/api/planets/[id].ts +56 -13
  181. package/templates/space/api/planets/paginate.ts +36 -0
  182. package/templates/space/api/planets.ts +52 -44
  183. package/templates/space/apps/fe/index.html +24 -0
  184. package/templates/space/apps/fe/openapi-codegen.config.ts +37 -0
  185. package/templates/space/apps/fe/package.json +82 -0
  186. package/templates/space/apps/fe/public/apple-touch-icon.png +0 -0
  187. package/templates/space/apps/fe/public/favicon-96x96.png +0 -0
  188. package/templates/space/apps/fe/public/favicon.ico +0 -0
  189. package/templates/space/apps/fe/public/favicon.svg +3 -0
  190. package/templates/space/apps/fe/public/site.webmanifest +21 -0
  191. package/templates/space/apps/fe/public/web-app-manifest-192x192.png +0 -0
  192. package/templates/space/apps/fe/public/web-app-manifest-512x512.png +0 -0
  193. package/templates/space/apps/fe/src/assets/fonts/GeneralSans-Bold.otf +0 -0
  194. package/templates/space/apps/fe/src/assets/fonts/GeneralSans-Medium.otf +0 -0
  195. package/templates/space/apps/fe/src/assets/fonts/GeneralSans-Regular.otf +0 -0
  196. package/templates/space/apps/fe/src/assets/fonts/GeneralSans-Semibold.otf +0 -0
  197. package/templates/space/apps/fe/src/assets/locales/en/translation.json +301 -0
  198. package/templates/space/apps/fe/src/assets/locales/sl/translation.json +301 -0
  199. package/templates/space/apps/fe/src/clients/app-rest-client.ts +15 -0
  200. package/templates/space/apps/fe/src/clients/auth-token-store.ts +101 -0
  201. package/templates/space/apps/fe/src/clients/rest/app-error-handler.ts +31 -0
  202. package/templates/space/apps/fe/src/clients/rest/interceptors/authorization-header.interceptor.ts +15 -0
  203. package/templates/space/apps/fe/src/clients/rest/interceptors/refresh-token.interceptor.ts +37 -0
  204. package/templates/space/apps/fe/src/clients/rest/interceptors/response.interceptor.ts +17 -0
  205. package/templates/space/apps/fe/src/components/404.tsx +18 -0
  206. package/templates/space/apps/fe/src/components/features/auth/AuthBrandPanel.tsx +60 -0
  207. package/templates/space/apps/fe/src/components/features/auth/AuthLayout.tsx +23 -0
  208. package/templates/space/apps/fe/src/components/features/auth/LoginPage.tsx +111 -0
  209. package/templates/space/apps/fe/src/components/features/auth/RegisterPage.tsx +143 -0
  210. package/templates/space/apps/fe/src/components/features/home/HomePage.tsx +21 -0
  211. package/templates/space/apps/fe/src/components/features/planets/details/PlanetDetailsPage.tsx +139 -0
  212. package/templates/space/apps/fe/src/components/features/planets/details/PlanetEditPage.tsx +266 -0
  213. package/templates/space/apps/fe/src/components/features/planets/feed/PlanetFeedCard.tsx +131 -0
  214. package/templates/space/apps/fe/src/components/features/planets/feed/PlanetsFeedPage.tsx +119 -0
  215. package/templates/space/apps/fe/src/components/features/planets/list/PlanetCard.tsx +89 -0
  216. package/templates/space/apps/fe/src/components/features/planets/list/PlanetCreateModal.tsx +179 -0
  217. package/templates/space/apps/fe/src/components/features/planets/list/PlanetsFilters.css +3 -0
  218. package/templates/space/apps/fe/src/components/features/planets/list/PlanetsFilters.tsx +73 -0
  219. package/templates/space/apps/fe/src/components/features/planets/list/PlanetsGridPage.tsx +51 -0
  220. package/templates/space/apps/fe/src/components/features/planets/list/PlanetsInfiniteTablePage.tsx +79 -0
  221. package/templates/space/apps/fe/src/components/features/planets/list/PlanetsPage.tsx +65 -0
  222. package/templates/space/apps/fe/src/components/features/planets/list/PlanetsTablePage.tsx +72 -0
  223. package/templates/space/apps/fe/src/components/features/planets/list/PlanetsTableSummary.tsx +29 -0
  224. package/templates/space/apps/fe/src/components/features/planets/list/PlanetsViewTabs.tsx +79 -0
  225. package/templates/space/apps/fe/src/components/features/planets/list/table/PlanetsTable.tsx +30 -0
  226. package/templates/space/apps/fe/src/components/features/planets/list/table/PlanetsTableActions.tsx +64 -0
  227. package/templates/space/apps/fe/src/components/features/planets/list/table/PlanetsTableInfinite.tsx +36 -0
  228. package/templates/space/apps/fe/src/components/features/planets/list/table/planetsTableColumns.tsx +72 -0
  229. package/templates/space/apps/fe/src/components/features/planets/list/table/usePlanetTableFilters.tsx +102 -0
  230. package/templates/space/apps/fe/src/components/features/profile/ProfilePage.tsx +96 -0
  231. package/templates/space/apps/fe/src/components/googleAnalytics/GoogleAnalytics.tsx +35 -0
  232. package/templates/space/apps/fe/src/components/layout/AppLayout.tsx +19 -0
  233. package/templates/space/apps/fe/src/components/layout/app-header/AppHeader.tsx +93 -0
  234. package/templates/space/apps/fe/src/components/layout/app-header/MobileNavigation.tsx +53 -0
  235. package/templates/space/apps/fe/src/components/layout/app-header/NavLink.tsx +29 -0
  236. package/templates/space/apps/fe/src/components/shared/branding/BrandLogo.tsx +13 -0
  237. package/templates/space/apps/fe/src/components/shared/error/ErrorFallback.tsx +43 -0
  238. package/templates/space/apps/fe/src/components/shared/error/ErrorText.tsx +20 -0
  239. package/templates/space/apps/fe/src/components/shared/error/NotFound.tsx +36 -0
  240. package/templates/space/apps/fe/src/components/shared/forms/RequiredLabel.tsx +21 -0
  241. package/templates/space/apps/fe/src/components/shared/forms/RowInputWrapper.tsx +50 -0
  242. package/templates/space/apps/fe/src/components/shared/head/AppHead.tsx +32 -0
  243. package/templates/space/apps/fe/src/components/shared/head/DefaultAppHead.tsx +34 -0
  244. package/templates/space/apps/fe/src/components/shared/layout/LoadingState.tsx +9 -0
  245. package/templates/space/apps/fe/src/components/shared/layout/ThinPageWrapper.tsx +5 -0
  246. package/templates/space/apps/fe/src/components/shared/page/PageHeader.tsx +69 -0
  247. package/templates/space/apps/fe/src/components/shared/ui/Card.tsx +60 -0
  248. package/templates/space/apps/fe/src/components/shared/ui/GoogleLoginButton.tsx +19 -0
  249. package/templates/space/apps/fe/src/components/shared/ui/RequiredLabel.tsx +22 -0
  250. package/templates/space/apps/fe/src/components/shared/ui/TableActions.tsx +22 -0
  251. package/templates/space/apps/fe/src/config/app.config.ts +35 -0
  252. package/templates/space/apps/fe/src/config/i18n.ts +43 -0
  253. package/templates/space/apps/fe/src/config/inits/a11y.ts +14 -0
  254. package/templates/space/apps/fe/src/config/inits/logger.ts +7 -0
  255. package/templates/space/apps/fe/src/config/inits/sentry.ts +21 -0
  256. package/templates/space/apps/fe/src/config/jwt.config.ts +2 -0
  257. package/templates/space/apps/fe/src/config/query.config.ts +20 -0
  258. package/templates/space/apps/fe/src/hooks/useAuth.ts +5 -0
  259. package/templates/space/apps/fe/src/main.tsx +52 -0
  260. package/templates/space/apps/fe/src/pages/(guest)/login.tsx +23 -0
  261. package/templates/space/apps/fe/src/pages/(guest)/register.tsx +23 -0
  262. package/templates/space/apps/fe/src/pages/(guest)/route.tsx +18 -0
  263. package/templates/space/apps/fe/src/pages/(private)/index.tsx +23 -0
  264. package/templates/space/apps/fe/src/pages/(private)/planets/$id/edit.tsx +53 -0
  265. package/templates/space/apps/fe/src/pages/(private)/planets/$id/index.tsx +41 -0
  266. package/templates/space/apps/fe/src/pages/(private)/planets/index.tsx +24 -0
  267. package/templates/space/apps/fe/src/pages/(private)/planets-feed.tsx +23 -0
  268. package/templates/space/apps/fe/src/pages/(private)/profile.tsx +23 -0
  269. package/templates/space/apps/fe/src/pages/(private)/route.tsx +18 -0
  270. package/templates/space/apps/fe/src/pages/(public)/auth.tsx +37 -0
  271. package/templates/space/apps/fe/src/pages/(public)/route.tsx +9 -0
  272. package/templates/space/apps/fe/src/pages/__root.tsx +164 -0
  273. package/templates/space/apps/fe/src/providers/AppErrorBoundary.tsx +10 -0
  274. package/templates/space/apps/fe/src/providers/OpenApiRuntimeProvider.tsx +31 -0
  275. package/templates/space/apps/fe/src/providers/index.tsx +44 -0
  276. package/templates/space/apps/fe/src/providers/jwt.provider.tsx +95 -0
  277. package/templates/space/apps/fe/src/routeTree.gen.ts +309 -0
  278. package/templates/space/apps/fe/src/styles/base.css +103 -0
  279. package/templates/space/apps/fe/src/styles/fonts/fonts.tsx +10 -0
  280. package/templates/space/apps/fe/src/styles/fonts/general-sans.css +31 -0
  281. package/templates/space/apps/fe/src/styles/globals.css +28 -0
  282. package/templates/space/apps/fe/src/styles/overrides/defaults/button.override.ts +536 -0
  283. package/templates/space/apps/fe/src/styles/overrides/defaults/checkbox.override.ts +71 -0
  284. package/templates/space/apps/fe/src/styles/overrides/defaults/input.override.ts +252 -0
  285. package/templates/space/apps/fe/src/styles/overrides/defaults/label.override.ts +91 -0
  286. package/templates/space/apps/fe/src/styles/overrides/defaults/modal.override.ts +57 -0
  287. package/templates/space/apps/fe/src/styles/overrides/defaults/radio.override.ts +46 -0
  288. package/templates/space/apps/fe/src/styles/overrides/defaults/table.override.ts +104 -0
  289. package/templates/space/apps/fe/src/styles/overrides/defaults/tag.override.ts +66 -0
  290. package/templates/space/apps/fe/src/styles/overrides/defaults/typography.override.ts +115 -0
  291. package/templates/space/apps/fe/src/styles/overrides/outline.clsx.ts +10 -0
  292. package/templates/space/apps/fe/src/styles/overrides/uiOverrides.override.ts +60 -0
  293. package/templates/space/apps/fe/src/styles/theme.css +2177 -0
  294. package/templates/space/apps/fe/src/types/i18next.d.ts +12 -0
  295. package/templates/space/apps/fe/src/types/table.d.ts +17 -0
  296. package/templates/space/apps/fe/src/types/ui.d.ts +26 -0
  297. package/templates/space/apps/fe/src/types/vite-env.d.ts +20 -0
  298. package/templates/space/apps/fe/src/utils/date.utils.ts +17 -0
  299. package/templates/space/apps/fe/src/utils/image-fallback.ts +9 -0
  300. package/templates/space/apps/fe/src/utils/media-upload.ts +63 -0
  301. package/templates/space/apps/fe/src/utils/number.utils.ts +12 -0
  302. package/templates/space/apps/fe/src/utils/string.utils.ts +5 -0
  303. package/templates/space/apps/fe/src/vite-env.d.ts +1 -0
  304. package/templates/space/apps/fe/tsconfig.app.json +32 -0
  305. package/templates/space/apps/fe/tsconfig.json +9 -0
  306. package/templates/space/apps/fe/tsconfig.node.json +31 -0
  307. package/templates/space/apps/fe/vite.config.ts +94 -0
  308. package/templates/space/database.ts +33 -13
  309. package/templates/space/openapi.json +1819 -0
  310. package/templates/space/oxfmt.config.js +23 -0
  311. package/templates/space/package.json +6 -13
  312. package/templates/space/rulesync.jsonc +18 -0
  313. package/templates/space/tsconfig.json +2 -4
  314. package/templates/auth-chat/index.html +0 -201
  315. package/templates/auth-chat/src/main.tsx +0 -282
  316. package/templates/auth-chat/vite.config.ts +0 -7
  317. package/templates/backend/api/health.ts +0 -7
  318. package/templates/backend/api/launch.ts +0 -29
  319. package/templates/backend/api/me.ts +0 -14
  320. package/templates/backend/api/motto.ts +0 -9
  321. package/templates/backend/api/rockets.ts +0 -43
  322. package/templates/space/api/health.ts +0 -7
  323. package/templates/space/api/launch.ts +0 -29
  324. package/templates/space/api/me.ts +0 -14
  325. package/templates/space/api/motto.ts +0 -9
  326. package/templates/space/api/rockets.ts +0 -43
  327. package/templates/space/index.html +0 -138
  328. package/templates/space/src/main.tsx +0 -229
  329. package/templates/space/vite.config.ts +0 -7
@@ -1,60 +1,68 @@
1
- /** GET/POST /api/planets — list (seeds sample rows on first GET) and create planets. */
2
- import { planets, rockets } from "../database";
3
1
  import { defineApi, z } from "@robodev-ai/sdk";
2
+ import {
3
+ ensureSeed,
4
+ enrichOne,
5
+ enrichPlanet,
6
+ fail,
7
+ filterPlanetRows,
8
+ loadLookups,
9
+ parseFilter,
10
+ planets,
11
+ sortPlanets,
12
+ validateAlien,
13
+ validateImage,
14
+ } from "./_lib";
4
15
 
5
- const EARTH = "11111111-1111-1111-1111-111111111111";
6
- const MARS = "22222222-2222-2222-2222-222222222222";
7
- const KEPLER = "33333333-3333-3333-3333-333333333333";
8
- const VOYAGER = "44444444-4444-4444-4444-444444444444";
9
- const ODYSSEY = "55555555-5555-5555-5555-555555555555";
16
+ const imageRequest = z.object({ id: z.string() }).nullish();
10
17
 
11
- const Planet = z.object({
12
- id: z.string(),
13
- name: z.string(),
14
- climate: z.string(),
15
- moons: z.coerce.number(),
18
+ const planetBody = z.object({
19
+ name: z.string().min(1),
20
+ alienId: z.string().nullish(),
21
+ discoveryDate: z.string().nullish(),
22
+ description: z.string().nullish(),
23
+ image: imageRequest,
16
24
  });
17
25
 
18
26
  export const get = defineApi({
19
- response: z.array(Planet),
20
- handler: async ({ db }) => {
21
- const existing = await db.select().from(planets).limit(1);
22
- if (existing.length === 0) {
23
- try {
24
- await db.insert(planets).values([
25
- { id: EARTH, name: "Earth", climate: "temperate", moons: 1 },
26
- { id: MARS, name: "Mars", climate: "arid", moons: 2 },
27
- { id: KEPLER, name: "Kepler-452b", climate: "unknown", moons: 0 },
28
- ]);
29
- await db.insert(rockets).values([
30
- { id: VOYAGER, name: "Voyager", destinationId: MARS, launched: false },
31
- { id: ODYSSEY, name: "Odyssey", destinationId: KEPLER, launched: true },
32
- ]);
33
- } catch {
34
- // First request won the seed race.
35
- }
36
- }
37
- const rows = await db.select().from(planets);
38
- return Planet.array().parse(rows);
27
+ auth: "required",
28
+ handler: async (ctx) => {
29
+ await ensureSeed(ctx.db, ctx.user!.id);
30
+ const rows = await ctx.db.select().from(planets);
31
+ const lookups = await loadLookups(ctx.db);
32
+ const query = ctx.query as Record<string, unknown>;
33
+ const filtered = filterPlanetRows(rows, lookups.alienById, parseFilter(query));
34
+ const order = typeof query.order === "string" ? query.order : undefined;
35
+ return Promise.all(
36
+ sortPlanets(filtered, order).map((row) =>
37
+ enrichPlanet(ctx, row, ctx.user!.id, lookups.alienById, lookups.likes),
38
+ ),
39
+ );
39
40
  },
40
41
  });
41
42
 
42
43
  export const post = defineApi({
43
- body: z.object({
44
- name: z.string().min(1),
45
- climate: z.string().min(1),
46
- moons: z.coerce.number().int().min(0).default(0),
47
- }),
48
- response: Planet,
49
- handler: async ({ db, body }) => {
50
- const [row] = await db
44
+ auth: "required",
45
+ body: planetBody,
46
+ handler: async (ctx) => {
47
+ const alienId = ctx.body.alienId || null;
48
+ if (alienId && !(await validateAlien(ctx.db, alienId))) {
49
+ return fail(404, "Alien not found");
50
+ }
51
+ const image = await validateImage(ctx.db, ctx.body.image, ctx.user!.id);
52
+ if (image && "error" in image) return image.error;
53
+
54
+ const [row] = await ctx.db
51
55
  .insert(planets)
52
56
  .values({
53
- name: body.name,
54
- climate: body.climate,
55
- moons: body.moons,
57
+ userId: ctx.user!.id,
58
+ creatorName: ctx.user!.name ?? ctx.user!.email,
59
+ alienId,
60
+ discoveryDate: ctx.body.discoveryDate ? new Date(ctx.body.discoveryDate) : null,
61
+ name: ctx.body.name,
62
+ description: ctx.body.description ?? null,
63
+ imageId: image?.id ?? null,
56
64
  })
57
65
  .returning();
58
- return Planet.parse(row);
66
+ return enrichOne(ctx, row!, ctx.user!.id);
59
67
  },
60
68
  });
@@ -0,0 +1,24 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link
6
+ rel="icon"
7
+ type="image/svg+xml"
8
+ href="/favicon.svg"
9
+ />
10
+ <meta
11
+ name="viewport"
12
+ content="width=device-width, initial-scale=1.0"
13
+ />
14
+ <title>Space</title>
15
+ </head>
16
+
17
+ <body class="bg-elevation-fill-default-2 text-text-default-1">
18
+ <div id="app"></div>
19
+ <script
20
+ type="module"
21
+ src="/src/main.tsx"
22
+ ></script>
23
+ </body>
24
+ </html>
@@ -0,0 +1,37 @@
1
+ /* oxlint-disable import/no-nodejs-modules */
2
+ import type { OpenAPICodegenConfig } from "@povio/openapi-codegen-cli";
3
+ import { resolveConfigSync } from "@povio/resolve-config";
4
+ import { resolve } from "node:path";
5
+
6
+ const COMPACT_OPENAPI_INPUT = "../../openapi.json";
7
+ const repoRoot = resolve(process.cwd(), "../..");
8
+ const env = resolveConfigSync({ cwd: repoRoot, module: "spa", target: "resolved" }) as Record<
9
+ string,
10
+ string | undefined
11
+ >;
12
+
13
+ function resolveLiveOpenApiInput(apiUrl = env.VITE_PUBLIC_API_URL) {
14
+ return `${apiUrl?.replace(/\/+$/, "")}/openapi.json`;
15
+ }
16
+
17
+ export function resolveOpenApiInput() {
18
+ return process.env.OPENAPI_INPUT || (process.env.OPENAPI_LIVE === "true" ? resolveLiveOpenApiInput() : COMPACT_OPENAPI_INPUT);
19
+ }
20
+
21
+ const config: OpenAPICodegenConfig = {
22
+ input: resolveOpenApiInput(),
23
+ output: "src/openapi",
24
+ tsPath: "@/openapi",
25
+ restClientImportPath: "@/clients/app-rest-client",
26
+ clearOutput: true,
27
+ excludeRedundantZodSchemas: false,
28
+ checkAcl: false,
29
+ acl: false,
30
+ replaceOptionalWithNullish: true,
31
+ infiniteQueries: true,
32
+ mutationDefaultOnError: true,
33
+ modelsInCommon: true,
34
+ axiosRequestConfig: true,
35
+ };
36
+
37
+ export default config;
@@ -0,0 +1,82 @@
1
+ {
2
+ "name": "fe",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "description": "Space starter frontend",
6
+ "type": "module",
7
+ "scripts": {
8
+ "dev": "bunx --bun vite",
9
+ "build": "bunx --bun vite build",
10
+ "clean": "rimraf dist src/openapi",
11
+ "lint": "oxlint --type-aware . ../../api ../../database.ts --fix",
12
+ "lint:check": "oxlint --type-aware . ../../api ../../database.ts --quiet",
13
+ "format": "oxfmt -c \"../../oxfmt.config.js\" . ../../api ../../database.ts",
14
+ "format:check": "oxfmt -c \"../../oxfmt.config.js\" --check . ../../api ../../database.ts",
15
+ "ts:check": "tsc -b --noEmit",
16
+ "test": "vitest run",
17
+ "check": "bun ts:check && bun lint:check && bun format:check",
18
+ "openapi:gen": "openapi-codegen generate && oxfmt -c \"../../oxfmt.config.js\" ./src/openapi",
19
+ "openapi:check": "openapi-codegen check"
20
+ },
21
+ "dependencies": {
22
+ "@casl/ability": "^6.8.1",
23
+ "@casl/react": "^5.0.1",
24
+ "@fontsource-variable/geist": "^5.2.8",
25
+ "@fontsource-variable/inter": "^5.2.8",
26
+ "@internationalized/date": "^3.11.0",
27
+ "@povio/openapi-codegen-cli": "3.1.0",
28
+ "@povio/resolve-config": "1.3.0",
29
+ "@povio/ui": "3.4.0-rc.12",
30
+ "@sentry/react": "^10.38.0",
31
+ "@tanstack/devtools-vite": "^0.3.11",
32
+ "@tanstack/react-devtools": "^0.8.1",
33
+ "@tanstack/react-form": "^1.33.2",
34
+ "@tanstack/react-query": "^5.90.21",
35
+ "@tanstack/react-query-devtools": "~5.90.0",
36
+ "@tanstack/react-router": "^1.136.8",
37
+ "@tanstack/react-router-devtools": "^1.136.8",
38
+ "@tanstack/react-table": "^8.21.3",
39
+ "@tanstack/router-core": "^1.136.8",
40
+ "@tanstack/router-plugin": "^1.136.8",
41
+ "axios": "^1.13.2",
42
+ "class-variance-authority": "^0.7.1",
43
+ "clsx": "^2.1.1",
44
+ "i18next": "^25.7.3",
45
+ "loglevel": "^1.9.2",
46
+ "lucide-react": "^1.28.0",
47
+ "luxon": "^3.7.2",
48
+ "react": "19.2.4",
49
+ "react-aria": "^3.46.0",
50
+ "react-aria-components": "^1.15.1",
51
+ "react-dom": "19.2.4",
52
+ "react-i18next": "^16.5.1",
53
+ "web-vitals": "^5.1.0",
54
+ "zod": "^4.4.3",
55
+ "zustand": "^5.0.9"
56
+ },
57
+ "devDependencies": {
58
+ "@axe-core/react": "^4.11.0",
59
+ "@povio/react-scan": "0.0.0",
60
+ "@povio/vite-plugin-react-scan": "0.0.2",
61
+ "@tailwindcss/vite": "^4.2.1",
62
+ "@types/luxon": "^3.7.1",
63
+ "@types/node": "^24.10.9",
64
+ "@types/react": "^19.2.7",
65
+ "@types/react-dom": "^19.2.3",
66
+ "@typescript/native": "npm:typescript@^7.0.2",
67
+ "@vitejs/plugin-react": "^5.1.2",
68
+ "babel-plugin-react-compiler": "1.0.0",
69
+ "oxfmt": "^0.45.0",
70
+ "oxlint": "1.60.0",
71
+ "oxlint-tsgolint": "0.21.0",
72
+ "react-icons-sprite": "^1.1.1",
73
+ "rimraf": "^6.1.2",
74
+ "tailwindcss": "^4.2.4",
75
+ "tailwindcss-react-aria-components": "^2.1.0",
76
+ "tsx": "^4.22.1",
77
+ "typescript": "npm:@typescript/typescript6@^6.0.2",
78
+ "vite": "^8.0.0",
79
+ "vite-plugin-devtools-json": "^1.0.0",
80
+ "vitest": "^3.2.4"
81
+ }
82
+ }
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="239.36" height="239.36"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="239.36" height="239.36"><svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 239.36 239.36"><defs><style>.cls-1{fill:#3c60ad;}.cls-2{fill:none;}.cls-3{clip-path:url(#clip-path);}.cls-4{mask:url(#mask);}.cls-5{fill:#fff;}</style><clipPath id="clip-path"><rect class="cls-2" width="239.36" height="239.36"></rect></clipPath><mask id="mask" x="0" y="0" width="239.36" height="239.36" maskUnits="userSpaceOnUse"><g id="mask0_21778_2258" data-name="mask0 21778 2258"><path class="cls-1" d="M0,29.92A29.93,29.93,0,0,1,29.92,0H209.44a29.93,29.93,0,0,1,29.92,29.92V209.44a29.93,29.93,0,0,1-29.92,29.92H29.92A29.93,29.93,0,0,1,0,209.44Z"></path></g></mask></defs><g class="cls-3"><g class="cls-4"><path class="cls-5" d="M0,29.92A29.93,29.93,0,0,1,29.92,0H209.44a29.93,29.93,0,0,1,29.92,29.92V209.44a29.93,29.93,0,0,1-29.92,29.92H29.92A29.93,29.93,0,0,1,0,209.44Z"></path><path d="M119.8,49.55c26.68,0,48.41,22.8,48.5,50.63,0,28.18-21.73,51.06-48.5,51.06A46.64,46.64,0,0,1,83.31,133.4v56.54h-12V100.27C71.29,72.35,93,49.55,119.8,49.55Zm0,12.29c-20.15,0-36.49,17.22-36.49,38.43,0,21.46,16.34,39,36.49,39s36.39-17.5,36.48-39C156.28,79.06,139.94,61.84,119.8,61.84Z"></path></g></g></svg></svg><style>@media (prefers-color-scheme: light) { :root { filter: none; } }
2
+ @media (prefers-color-scheme: dark) { :root { filter: none; } }
3
+ </style></svg>
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "Povio",
3
+ "short_name": "Povio",
4
+ "icons": [
5
+ {
6
+ "src": "/web-app-manifest-192x192.png",
7
+ "sizes": "192x192",
8
+ "type": "image/png",
9
+ "purpose": "maskable"
10
+ },
11
+ {
12
+ "src": "/web-app-manifest-512x512.png",
13
+ "sizes": "512x512",
14
+ "type": "image/png",
15
+ "purpose": "maskable"
16
+ }
17
+ ],
18
+ "theme_color": "#ffffff",
19
+ "background_color": "#ffffff",
20
+ "display": "standalone"
21
+ }
@@ -0,0 +1,301 @@
1
+ {
2
+ "appName": "Tiny Template",
3
+ "appDescription": "A template for building web applications",
4
+ "shared": {
5
+ "notFound": {
6
+ "head": {
7
+ "title": "Page not found",
8
+ "description": "The page you are looking for doesn't exist."
9
+ },
10
+ "heading": "Page not found",
11
+ "subheading": "The page you are looking for doesn't exist.",
12
+ "homeBtn": "Go to home"
13
+ },
14
+ "errorFallback": {
15
+ "heading": "Something went wrong",
16
+ "subheading": "Error: {{error}}",
17
+ "retryBtn": "Try again"
18
+ },
19
+ "apiErrors": {
20
+ "requestFailed": "Request failed: {{error}}",
21
+ "unknown": "An unknown error occurred."
22
+ },
23
+ "seedData": {
24
+ "actionButton": "Reset seed data",
25
+ "confirmation": {
26
+ "heading": "Reset seed data?",
27
+ "description": "This will reset all local data to the initial seed state.",
28
+ "confirm": "Reset",
29
+ "cancel": "Cancel"
30
+ }
31
+ },
32
+ "actions": {
33
+ "back": "Back"
34
+ },
35
+ "fakeMailbox": {
36
+ "title": "Fake mailbox",
37
+ "open": "Open fake mailbox",
38
+ "close": "Close fake mailbox",
39
+ "empty": "No emails yet.",
40
+ "from": "From",
41
+ "to": "To",
42
+ "cc": "Cc",
43
+ "bcc": "Bcc",
44
+ "replyTo": "Reply to",
45
+ "openPopup": "Open popup",
46
+ "popupBlocked": {
47
+ "heading": "Email popup was blocked",
48
+ "description": "Your browser blocked the automatic email window. Allow popups for this site or open this message now.",
49
+ "open": "Open email",
50
+ "cancel": "Keep unread"
51
+ }
52
+ }
53
+ },
54
+ "auth": {
55
+ "wrapper": {
56
+ "title": "Administration portal",
57
+ "description": "Tiny",
58
+ "watermark": "© {{year}} Tiny • Developed and maintained by Povio"
59
+ },
60
+ "shared": {
61
+ "errors": {
62
+ "invalidCredentials": "Invalid email or password.",
63
+ "userAlreadyExists": "An account with this email already exists.",
64
+ "identityNotFound": "We could not find this account.",
65
+ "notConfirmed": "This account has not been confirmed yet."
66
+ }
67
+ },
68
+ "login": {
69
+ "head": {
70
+ "title": "Login",
71
+ "description": "Login to your account"
72
+ },
73
+ "form": {
74
+ "title": "Login",
75
+ "email": "Email",
76
+ "emailPlaceholder": "Enter your email",
77
+ "password": "Password",
78
+ "passwordPlaceholder": "Enter your password",
79
+ "submit": "Login",
80
+ "submitLoading": "Logging in...",
81
+ "demoLogin": "Login as demo user",
82
+ "noAccount": "Don't have an account?",
83
+ "registerLink": "Register",
84
+ "loginFailed": "Login failed",
85
+ "resetSeedData": "Reset seed data"
86
+ },
87
+ "confirmations": {
88
+ "resetSeed": {
89
+ "heading": "Reset seed data?",
90
+ "description": "This will reset all local data to the initial seed state.",
91
+ "confirm": "Reset",
92
+ "cancel": "Cancel"
93
+ }
94
+ }
95
+ },
96
+ "register": {
97
+ "head": {
98
+ "title": "Register",
99
+ "description": "Create a new account"
100
+ },
101
+ "form": {
102
+ "title": "Register",
103
+ "description": "Create a new account",
104
+ "email": "Email",
105
+ "emailPlaceholder": "Enter your email",
106
+ "name": "Name",
107
+ "namePlaceholder": "Enter your name",
108
+ "password": "Password",
109
+ "passwordPlaceholder": "Enter your password",
110
+ "confirmPassword": "Confirm password",
111
+ "confirmPasswordPlaceholder": "Confirm your password",
112
+ "confirmPasswordRequired": "Confirm password is required",
113
+ "passwordsDoNotMatch": "Passwords do not match",
114
+ "passwordRequirements": "Password must be at least 12 characters long.",
115
+ "submit": "Register",
116
+ "registrationFailed": "Registration failed",
117
+ "hasAccount": "Already have an account?",
118
+ "loginLink": "Login"
119
+ }
120
+ },
121
+ "setPassword": {
122
+ "form": {
123
+ "title": "Set your password",
124
+ "welcome": "Welcome, {{firstName}} {{lastName}}. Please set your password to complete your account.",
125
+ "tokenNote": "Enter the invitation token you received by email.",
126
+ "token": "Invitation token",
127
+ "tokenPlaceholder": "Enter your invitation token",
128
+ "tokenChecking": "Checking token...",
129
+ "tokenError": "{{error}}",
130
+ "invalidToken": "Invalid or expired token",
131
+ "email": "Email",
132
+ "password": "Password",
133
+ "passwordPlaceholder": "Enter your password",
134
+ "confirmPassword": "Confirm password",
135
+ "confirmPasswordPlaceholder": "Confirm your password",
136
+ "passwordRequirements": "Password must be at least 8 characters long.",
137
+ "submit": "Set password",
138
+ "setPasswordFailed": "Setting password failed",
139
+ "hasPassword": "Already have a password?",
140
+ "loginLink": "Login"
141
+ }
142
+ }
143
+ },
144
+ "layout": {
145
+ "header": {
146
+ "logo": "Tiny",
147
+ "openMenu": "Open menu",
148
+ "closeMenu": "Close menu",
149
+ "nav": {
150
+ "home": "Home",
151
+ "planets": "Planets",
152
+ "planetsFeed": "Planets feed"
153
+ },
154
+ "profile": "Profile",
155
+ "logout": "Logout"
156
+ }
157
+ },
158
+ "home": {
159
+ "head": {
160
+ "title": "Home",
161
+ "description": "Welcome to the app!"
162
+ },
163
+ "title": "Home",
164
+ "message": "Welcome to the app!"
165
+ },
166
+ "planets": {
167
+ "detail": {
168
+ "back": "Back to Planets",
169
+ "notFound": "Planet not found.",
170
+ "description": "Description",
171
+ "details": "Details",
172
+ "created": "Created",
173
+ "updated": "Last updated",
174
+ "discoveryDate": "Discovery date",
175
+ "createdBy": "Created by"
176
+ },
177
+ "page": {
178
+ "title": "Planets",
179
+ "headTitle": "Planets",
180
+ "headDescription": "Manage your planets",
181
+ "addPlanet": "Add planet",
182
+ "empty": "No planets yet. Add your first one."
183
+ },
184
+ "views": {
185
+ "label": "Planet view",
186
+ "grid": "Grid",
187
+ "table": "Table",
188
+ "infinite": "Infinite table"
189
+ },
190
+ "filters": {
191
+ "search": "Search",
192
+ "alien": "Alien",
193
+ "alienPlaceholder": "All aliens",
194
+ "discoveryDate": "Discovery date",
195
+ "discoveryDatePlaceholder": "Any date",
196
+ "clearAll": "Clear all"
197
+ },
198
+ "create": {
199
+ "title": "Create planet",
200
+ "name": "Name",
201
+ "namePlaceholder": "Planet name",
202
+ "alien": "Alien",
203
+ "alienPlaceholder": "Select an alien",
204
+ "discoveryDate": "Discovery date",
205
+ "discoveryDatePlaceholder": "Select a discovery date",
206
+ "description": "Description",
207
+ "descriptionPlaceholder": "Optional description",
208
+ "image": "Image",
209
+ "imageEmptyText": "No image",
210
+ "imageUploadText": "Upload",
211
+ "imageBrowseText": "Browse",
212
+ "submit": "Create",
213
+ "cancel": "Cancel",
214
+ "success": "Planet created",
215
+ "error": "Failed to create planet"
216
+ },
217
+ "edit": {
218
+ "title": "Edit planet",
219
+ "name": "Name",
220
+ "namePlaceholder": "Planet name",
221
+ "alien": "Alien",
222
+ "alienPlaceholder": "Select an alien",
223
+ "discoveryDate": "Discovery date",
224
+ "discoveryDatePlaceholder": "Select a discovery date",
225
+ "description": "Description",
226
+ "descriptionPlaceholder": "Optional description",
227
+ "image": "Image",
228
+ "imageEmptyText": "No image",
229
+ "imageUploadText": "Upload",
230
+ "imageBrowseText": "Browse",
231
+ "submit": "Save",
232
+ "cancel": "Cancel",
233
+ "success": "Planet updated",
234
+ "error": "Failed to update planet"
235
+ },
236
+ "card": {
237
+ "createdBy": "Created by {{name}} on {{date}}",
238
+ "alien": "Alien: {{name}}",
239
+ "unknownCreator": "Unknown"
240
+ },
241
+ "table": {
242
+ "allLoaded": "All results are shown",
243
+ "showing": "Showing {{displayed}} of {{total}}",
244
+ "name": "Name",
245
+ "description": "Description",
246
+ "alien": "Alien",
247
+ "discoveryDate": "Discovery date",
248
+ "creator": "Creator",
249
+ "actions": "Actions"
250
+ },
251
+ "actions": {
252
+ "edit": "Edit",
253
+ "remove": "Remove"
254
+ },
255
+ "removeConfirm": {
256
+ "heading": "Remove planet?",
257
+ "description": "Are you sure you want to remove \"{{name}}\"? This cannot be undone.",
258
+ "confirm": "Remove",
259
+ "cancel": "Cancel",
260
+ "success": "Planet removed",
261
+ "error": "Failed to remove planet"
262
+ }
263
+ },
264
+ "planetsFeed": {
265
+ "page": {
266
+ "title": "Planets feed",
267
+ "headTitle": "Planets feed",
268
+ "headDescription": "Scroll through planets and their aliens",
269
+ "empty": "No planets to show.",
270
+ "end": "You reached the end."
271
+ },
272
+ "card": {
273
+ "like": "Like ({{count}})",
274
+ "liked": "Liked ({{count}})",
275
+ "discovered": "Discovered {{date}}",
276
+ "alienLabel": "Alien on this planet",
277
+ "creatorLabel": "Created by",
278
+ "noAlien": "No alien assigned"
279
+ }
280
+ },
281
+ "profile": {
282
+ "head": {
283
+ "title": "Profile",
284
+ "description": "Your profile"
285
+ },
286
+ "form": {
287
+ "title": "Profile",
288
+ "description": "Update your profile details",
289
+ "email": "Email",
290
+ "emailPlaceholder": "Enter your email",
291
+ "name": "Name",
292
+ "namePlaceholder": "Enter your name",
293
+ "submit": "Save",
294
+ "submitLoading": "Saving...",
295
+ "notifications": {
296
+ "success": "Profile updated",
297
+ "error": "Failed to update profile"
298
+ }
299
+ }
300
+ }
301
+ }