@pylonsync/create-pylon 0.19.1 → 0.20.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 (675) hide show
  1. package/bin/create-pylon.js +30 -7
  2. package/package.json +1 -1
  3. package/templates/agency/.env.example +7 -0
  4. package/templates/agency/README.md +28 -3
  5. package/templates/agency/app/(marketing)/contact-form.tsx +20 -18
  6. package/templates/agency/app/(marketing)/page.tsx +3 -3
  7. package/templates/agency/app/(marketing)/work/page.tsx +3 -3
  8. package/templates/agency/app/auth-form.tsx +4 -4
  9. package/templates/agency/app/dashboard/dashboard-client.tsx +110 -64
  10. package/templates/agency/app/dashboard/page.tsx +14 -16
  11. package/templates/agency/app/icon.svg +3 -0
  12. package/templates/agency/app/login/page.tsx +12 -14
  13. package/templates/agency/components/marketing.tsx +12 -5
  14. package/templates/agency/functions/seedStudioBackoffice.ts +42 -11
  15. package/templates/agency/lib/agency.ts +22 -0
  16. package/templates/agency/lib/demo.ts +118 -0
  17. package/templates/agency/lib/site.config.ts +19 -13
  18. package/templates/agency/public/favicon.ico +0 -0
  19. package/templates/agency/tests/agency.test.ts +57 -0
  20. package/templates/ai-chat/.env.example +13 -27
  21. package/templates/ai-chat/README.md +53 -60
  22. package/templates/ai-chat/app/(chat)/c/[id]/page.tsx +19 -0
  23. package/templates/ai-chat/app/(chat)/chat-client.tsx +657 -622
  24. package/templates/ai-chat/app/(chat)/layout.tsx +6 -43
  25. package/templates/ai-chat/app/(chat)/not-found.tsx +6 -10
  26. package/templates/ai-chat/app/(chat)/page.tsx +7 -11
  27. package/templates/ai-chat/app/auth-form.tsx +45 -38
  28. package/templates/ai-chat/app/error.tsx +9 -12
  29. package/templates/ai-chat/app/globals.css +464 -102
  30. package/templates/ai-chat/app/layout.tsx +11 -19
  31. package/templates/ai-chat/app/login/page.tsx +39 -24
  32. package/templates/ai-chat/app.ts +118 -43
  33. package/templates/ai-chat/components/chat/composer.tsx +193 -0
  34. package/templates/ai-chat/components/chat/empty-state.tsx +65 -0
  35. package/templates/ai-chat/components/chat/icons.tsx +198 -0
  36. package/templates/ai-chat/components/chat/markdown.tsx +164 -0
  37. package/templates/ai-chat/components/chat/message.tsx +183 -0
  38. package/templates/ai-chat/components/chat/setup.tsx +71 -0
  39. package/templates/ai-chat/components/chat/sidebar.tsx +288 -0
  40. package/templates/ai-chat/functions/_beginTurn.ts +145 -0
  41. package/templates/ai-chat/functions/_finishTurn.ts +55 -0
  42. package/templates/ai-chat/functions/assistantStatus.ts +13 -0
  43. package/templates/ai-chat/functions/claimGuestHistory.ts +39 -0
  44. package/templates/ai-chat/functions/createConversation.ts +28 -0
  45. package/templates/ai-chat/functions/deleteConversation.ts +15 -20
  46. package/templates/ai-chat/functions/prepareGuestClaim.ts +32 -0
  47. package/templates/ai-chat/functions/renameConversation.ts +19 -0
  48. package/templates/ai-chat/functions/respond.ts +88 -0
  49. package/templates/ai-chat/functions/seedExamples.ts +46 -0
  50. package/templates/ai-chat/functions/stopResponse.ts +30 -0
  51. package/templates/ai-chat/lib/brand-icon.ts +7 -0
  52. package/templates/ai-chat/lib/chat.ts +277 -0
  53. package/templates/ai-chat/lib/claim.ts +15 -0
  54. package/templates/ai-chat/lib/examples.ts +179 -0
  55. package/templates/ai-chat/lib/highlight.ts +107 -0
  56. package/templates/ai-chat/lib/markdown.ts +317 -0
  57. package/templates/ai-chat/lib/provider.ts +38 -0
  58. package/templates/ai-chat/lib/site.config.ts +55 -39
  59. package/templates/ai-chat/tests/chat.test.ts +174 -0
  60. package/templates/ai-chat/tests/components.test.tsx +57 -0
  61. package/templates/ai-chat/tests/markdown.test.ts +88 -0
  62. package/templates/ai-chat/tests/provider.test.ts +32 -0
  63. package/templates/backend/consumer/apps/api/app/layout.tsx +33 -0
  64. package/templates/backend/consumer/apps/api/app/page.tsx +54 -0
  65. package/templates/backend/consumer/apps/api/app.ts +166 -0
  66. package/templates/backend/consumer/apps/api/functions/addComment.ts +24 -0
  67. package/templates/backend/consumer/apps/api/functions/createPost.ts +19 -36
  68. package/templates/backend/consumer/apps/api/functions/deletePost.ts +15 -13
  69. package/templates/backend/consumer/apps/api/functions/myProfile.ts +5 -8
  70. package/templates/backend/consumer/apps/api/functions/seedDemo.ts +95 -0
  71. package/templates/backend/consumer/apps/api/functions/setFollow.ts +36 -0
  72. package/templates/backend/consumer/apps/api/functions/setLike.ts +36 -0
  73. package/templates/backend/consumer/apps/api/functions/upsertProfile.ts +43 -37
  74. package/templates/backend/consumer/apps/api/lib/seed.ts +89 -0
  75. package/templates/backend/consumer/apps/api/lib/social.ts +50 -0
  76. package/templates/backend/consumer/apps/api/package.json +8 -2
  77. package/templates/backend/consumer/apps/api/public/images/posts/arch.jpg +0 -0
  78. package/templates/backend/consumer/apps/api/public/images/posts/coffee.jpg +0 -0
  79. package/templates/backend/consumer/apps/api/public/images/posts/dog.jpg +0 -0
  80. package/templates/backend/consumer/apps/api/public/images/posts/lisbon.jpg +0 -0
  81. package/templates/backend/consumer/apps/api/public/images/posts/ramen.jpg +0 -0
  82. package/templates/backend/consumer/apps/api/public/images/posts/run.jpg +0 -0
  83. package/templates/backend/consumer/apps/api/public/images/posts/sunset.jpg +0 -0
  84. package/templates/backend/consumer/apps/api/tsconfig.json +12 -2
  85. package/templates/chat/README.md +43 -21
  86. package/templates/chat/app/chat-client.tsx +495 -85
  87. package/templates/chat/app/error.tsx +1 -1
  88. package/templates/chat/app/globals.css +170 -54
  89. package/templates/chat/app/layout.tsx +12 -9
  90. package/templates/chat/app/not-found.tsx +4 -2
  91. package/templates/chat/app/page.tsx +9 -19
  92. package/templates/chat/app.ts +96 -17
  93. package/templates/chat/components/chat/avatar.tsx +45 -0
  94. package/templates/chat/components/chat/composer.tsx +110 -0
  95. package/templates/chat/components/chat/message-list.tsx +285 -0
  96. package/templates/chat/components/chat/sidebar.tsx +190 -0
  97. package/templates/chat/functions/joinChat.ts +83 -0
  98. package/templates/chat/functions/renameMember.ts +25 -0
  99. package/templates/chat/lib/chat.ts +188 -0
  100. package/templates/chat/lib/seed.ts +78 -0
  101. package/templates/chat/tests/chat.test.ts +159 -0
  102. package/templates/chat/tests/composer.test.tsx +54 -0
  103. package/templates/consumer/README.md +3 -3
  104. package/templates/consumer/app/globals.css +10 -3
  105. package/templates/consumer/app/icon.svg +1 -0
  106. package/templates/consumer/components/social/avatar.tsx +25 -11
  107. package/templates/consumer/functions/seedFeed.ts +3 -3
  108. package/templates/consumer/lib/seed.ts +43 -85
  109. package/templates/consumer/public/favicon.ico +0 -0
  110. package/templates/consumer/public/images/posts/arch.jpg +0 -0
  111. package/templates/consumer/public/images/posts/coffee.jpg +0 -0
  112. package/templates/consumer/public/images/posts/dog.jpg +0 -0
  113. package/templates/consumer/public/images/posts/lisbon.jpg +0 -0
  114. package/templates/consumer/public/images/posts/ramen.jpg +0 -0
  115. package/templates/consumer/public/images/posts/run.jpg +0 -0
  116. package/templates/consumer/public/images/posts/sunset.jpg +0 -0
  117. package/templates/consumer/tests/seed.test.ts +39 -0
  118. package/templates/creator/.env.example +7 -0
  119. package/templates/creator/README.md +24 -5
  120. package/templates/creator/app/(marketing)/newsletter-signup.tsx +33 -12
  121. package/templates/creator/app/auth-form.tsx +7 -7
  122. package/templates/creator/app/dashboard/dashboard-client.tsx +137 -100
  123. package/templates/creator/app/dashboard/page.tsx +18 -18
  124. package/templates/creator/app/icon.svg +2 -0
  125. package/templates/creator/app/login/page.tsx +14 -14
  126. package/templates/creator/app.ts +4 -4
  127. package/templates/creator/functions/seedDemo.ts +32 -0
  128. package/templates/creator/functions/subscribe.ts +4 -15
  129. package/templates/creator/lib/demo.ts +94 -0
  130. package/templates/creator/lib/site.config.ts +15 -10
  131. package/templates/creator/lib/stats.ts +35 -0
  132. package/templates/creator/public/favicon.ico +0 -0
  133. package/templates/creator/tests/counter.test.ts +92 -0
  134. package/templates/creator/tests/live-count.test.tsx +45 -0
  135. package/templates/crm/README.md +22 -1
  136. package/templates/crm/app/apple-icon.png +0 -0
  137. package/templates/crm/app/companies/companies-view.tsx +32 -14
  138. package/templates/crm/app/companies/page.tsx +2 -1
  139. package/templates/crm/app/contacts/contacts-view.tsx +34 -10
  140. package/templates/crm/app/contacts/page.tsx +2 -1
  141. package/templates/crm/app/deals/[id]/deal-view.tsx +137 -98
  142. package/templates/crm/app/deals/[id]/page.tsx +2 -1
  143. package/templates/crm/app/globals.css +29 -14
  144. package/templates/crm/app/icon.svg +1 -0
  145. package/templates/crm/app/layout.tsx +7 -5
  146. package/templates/crm/app/page.tsx +2 -1
  147. package/templates/crm/app/pipeline-view.tsx +5 -5
  148. package/templates/crm/app/workspace.tsx +29 -17
  149. package/templates/crm/app.ts +5 -5
  150. package/templates/crm/components/activity-timeline.tsx +14 -4
  151. package/templates/crm/components/app-shell.tsx +94 -0
  152. package/templates/crm/components/auth-form.tsx +35 -5
  153. package/templates/crm/components/avatar.tsx +5 -1
  154. package/templates/crm/components/board-skeleton.tsx +5 -5
  155. package/templates/crm/components/brand-mark.tsx +25 -0
  156. package/templates/crm/components/command-palette.tsx +17 -17
  157. package/templates/crm/components/data-table.tsx +97 -36
  158. package/templates/crm/components/deal-card.tsx +23 -27
  159. package/templates/crm/components/filter-tabs.tsx +101 -0
  160. package/templates/crm/components/metrics-bar.tsx +6 -6
  161. package/templates/crm/components/nav.tsx +15 -0
  162. package/templates/crm/components/page-header.tsx +43 -7
  163. package/templates/crm/components/pipeline-board.tsx +16 -10
  164. package/templates/crm/components/require-auth.tsx +24 -26
  165. package/templates/crm/components/sidebar.tsx +54 -49
  166. package/templates/crm/components/stage-badge.tsx +4 -2
  167. package/templates/crm/components/ui/button.tsx +5 -4
  168. package/templates/crm/components/ui/dialog.tsx +1 -1
  169. package/templates/crm/components/ui/input.tsx +1 -1
  170. package/templates/crm/components/ui/select.tsx +1 -1
  171. package/templates/crm/components/ui/textarea.tsx +1 -1
  172. package/templates/crm/functions/seedWorkspace.ts +32 -17
  173. package/templates/crm/lib/brand.ts +9 -0
  174. package/templates/crm/lib/demo-team.ts +51 -0
  175. package/templates/crm/lib/pipeline.ts +37 -0
  176. package/templates/crm/lib/search.ts +4 -3
  177. package/templates/crm/lib/seed.ts +53 -8
  178. package/templates/crm/public/favicon.ico +0 -0
  179. package/templates/crm/tests/components.test.tsx +5 -5
  180. package/templates/crm/tests/demo-team.test.ts +18 -0
  181. package/templates/crm/tests/pipeline.test.ts +59 -3
  182. package/templates/directory/.env.example +7 -0
  183. package/templates/directory/README.md +22 -3
  184. package/templates/directory/app/(marketing)/directory-browse.tsx +30 -12
  185. package/templates/directory/app/(marketing)/page.tsx +6 -4
  186. package/templates/directory/app/auth-form.tsx +4 -4
  187. package/templates/directory/app/dashboard/dashboard-client.tsx +177 -90
  188. package/templates/directory/app/dashboard/page.tsx +16 -14
  189. package/templates/directory/app/icon.svg +4 -0
  190. package/templates/directory/app/login/page.tsx +16 -15
  191. package/templates/directory/functions/seedDemo.ts +43 -0
  192. package/templates/directory/lib/demo.ts +145 -0
  193. package/templates/directory/lib/directory.ts +27 -0
  194. package/templates/directory/lib/site.config.ts +21 -16
  195. package/templates/directory/public/favicon.ico +0 -0
  196. package/templates/directory/tests/directory.test.ts +46 -0
  197. package/templates/expo/consumer/apps/expo/App.tsx +360 -288
  198. package/templates/expo/consumer/apps/expo/app.json +9 -1
  199. package/templates/expo/consumer/apps/expo/package.json +2 -1
  200. package/templates/helpdesk/README.md +21 -0
  201. package/templates/helpdesk/app/apple-icon.png +0 -0
  202. package/templates/helpdesk/app/customers/customers-view.tsx +23 -7
  203. package/templates/helpdesk/app/customers/page.tsx +2 -1
  204. package/templates/helpdesk/app/globals.css +29 -14
  205. package/templates/helpdesk/app/icon.svg +1 -0
  206. package/templates/helpdesk/app/inbox-view.tsx +66 -47
  207. package/templates/helpdesk/app/layout.tsx +7 -5
  208. package/templates/helpdesk/app/page.tsx +4 -7
  209. package/templates/helpdesk/app/tickets/[id]/page.tsx +2 -1
  210. package/templates/helpdesk/app/tickets/[id]/ticket-view.tsx +134 -97
  211. package/templates/helpdesk/app/workspace.tsx +33 -22
  212. package/templates/helpdesk/app.ts +2 -2
  213. package/templates/helpdesk/components/app-shell.tsx +94 -0
  214. package/templates/helpdesk/components/auth-form.tsx +35 -5
  215. package/templates/helpdesk/components/avatar.tsx +5 -1
  216. package/templates/helpdesk/components/brand-mark.tsx +28 -0
  217. package/templates/helpdesk/components/command-palette.tsx +17 -17
  218. package/templates/helpdesk/components/data-table.tsx +97 -36
  219. package/templates/helpdesk/components/filter-tabs.tsx +101 -0
  220. package/templates/helpdesk/components/nav.tsx +14 -0
  221. package/templates/helpdesk/components/page-header.tsx +43 -7
  222. package/templates/helpdesk/components/priority-badge.tsx +49 -6
  223. package/templates/helpdesk/components/require-auth.tsx +24 -26
  224. package/templates/helpdesk/components/sidebar.tsx +54 -48
  225. package/templates/helpdesk/components/sla-indicator.tsx +5 -8
  226. package/templates/helpdesk/components/thread.tsx +7 -7
  227. package/templates/helpdesk/components/ticket-list.tsx +79 -19
  228. package/templates/helpdesk/components/ui/button.tsx +5 -4
  229. package/templates/helpdesk/components/ui/dialog.tsx +1 -1
  230. package/templates/helpdesk/components/ui/input.tsx +1 -1
  231. package/templates/helpdesk/components/ui/select.tsx +1 -1
  232. package/templates/helpdesk/components/ui/textarea.tsx +1 -1
  233. package/templates/helpdesk/functions/seedWorkspace.ts +25 -15
  234. package/templates/helpdesk/lib/brand.ts +9 -0
  235. package/templates/helpdesk/lib/demo-team.ts +51 -0
  236. package/templates/helpdesk/lib/search.ts +4 -3
  237. package/templates/helpdesk/lib/seed.ts +43 -2
  238. package/templates/helpdesk/lib/tickets.ts +68 -20
  239. package/templates/helpdesk/public/favicon.ico +0 -0
  240. package/templates/helpdesk/tests/components.test.tsx +10 -0
  241. package/templates/helpdesk/tests/demo-team.test.ts +18 -0
  242. package/templates/helpdesk/tests/tickets.test.ts +70 -0
  243. package/templates/imessage/.env.example +49 -0
  244. package/templates/imessage/AGENTS.md +153 -0
  245. package/templates/imessage/CLAUDE.md +7 -0
  246. package/templates/imessage/README.md +187 -0
  247. package/templates/imessage/app/console.tsx +382 -0
  248. package/templates/imessage/app/contacts/page.tsx +13 -0
  249. package/templates/imessage/app/error.tsx +16 -0
  250. package/templates/imessage/app/gate.tsx +31 -0
  251. package/templates/imessage/app/globals.css +183 -0
  252. package/templates/imessage/app/layout.tsx +17 -0
  253. package/templates/imessage/app/login/login-form.tsx +115 -0
  254. package/templates/imessage/app/login/page.tsx +30 -0
  255. package/templates/imessage/app/not-found.tsx +13 -0
  256. package/templates/imessage/app/page.tsx +14 -0
  257. package/templates/imessage/app/robots.ts +6 -0
  258. package/templates/imessage/app/setup/page.tsx +13 -0
  259. package/templates/imessage/app/sign-out.tsx +20 -0
  260. package/templates/imessage/app.ts +299 -0
  261. package/templates/imessage/bunfig +4 -0
  262. package/templates/imessage/components/avatar.tsx +46 -0
  263. package/templates/imessage/components/contact-panel.tsx +263 -0
  264. package/templates/imessage/components/contacts-view.tsx +172 -0
  265. package/templates/imessage/components/conversation-list.tsx +129 -0
  266. package/templates/imessage/components/nav-rail.tsx +67 -0
  267. package/templates/imessage/components/setup-view.tsx +408 -0
  268. package/templates/imessage/components/thread.tsx +229 -0
  269. package/templates/imessage/components/ui/badge.tsx +37 -0
  270. package/templates/imessage/components/ui/button.tsx +56 -0
  271. package/templates/imessage/components/ui/card.tsx +90 -0
  272. package/templates/imessage/components/ui/dialog.tsx +110 -0
  273. package/templates/imessage/components/ui/input.tsx +30 -0
  274. package/templates/imessage/components/ui/label.tsx +21 -0
  275. package/templates/imessage/components/ui/select.tsx +39 -0
  276. package/templates/imessage/components/ui/table.tsx +124 -0
  277. package/templates/imessage/components/ui/textarea.tsx +24 -0
  278. package/templates/imessage/components.json +20 -0
  279. package/templates/imessage/functions/answerNow.ts +34 -0
  280. package/templates/imessage/functions/assistant.ts +96 -0
  281. package/templates/imessage/functions/beginTurn.ts +101 -0
  282. package/templates/imessage/functions/cancelReminder.ts +13 -0
  283. package/templates/imessage/functions/claimOutbound.ts +44 -0
  284. package/templates/imessage/functions/clearDemo.ts +18 -0
  285. package/templates/imessage/functions/deleteNote.ts +11 -0
  286. package/templates/imessage/functions/deliverOutbound.ts +55 -0
  287. package/templates/imessage/functions/finishTurn.ts +84 -0
  288. package/templates/imessage/functions/fireReminder.ts +42 -0
  289. package/templates/imessage/functions/ingestInbound.ts +22 -0
  290. package/templates/imessage/functions/ownerAccount.ts +13 -0
  291. package/templates/imessage/functions/processTurn.ts +74 -0
  292. package/templates/imessage/functions/relayApply.ts +102 -0
  293. package/templates/imessage/functions/relaySync.ts +63 -0
  294. package/templates/imessage/functions/releaseOutbound.ts +18 -0
  295. package/templates/imessage/functions/resolveTurn.ts +25 -0
  296. package/templates/imessage/functions/saveContact.ts +27 -0
  297. package/templates/imessage/functions/seedDemo.ts +70 -0
  298. package/templates/imessage/functions/sendOwnerMessage.ts +28 -0
  299. package/templates/imessage/functions/sendblueWebhook.ts +49 -0
  300. package/templates/imessage/functions/setContactStatus.ts +17 -0
  301. package/templates/imessage/functions/settleOutbound.ts +35 -0
  302. package/templates/imessage/functions/setupStatus.ts +33 -0
  303. package/templates/imessage/functions/sweep.ts +58 -0
  304. package/templates/imessage/functions/toolCancelReminder.ts +17 -0
  305. package/templates/imessage/functions/toolForgetNote.ts +15 -0
  306. package/templates/imessage/functions/toolListNotes.ts +16 -0
  307. package/templates/imessage/functions/toolListReminders.ts +17 -0
  308. package/templates/imessage/functions/toolSaveNote.ts +22 -0
  309. package/templates/imessage/functions/toolSetReminder.ts +55 -0
  310. package/templates/imessage/functions/updateSettings.ts +48 -0
  311. package/templates/imessage/gitignore +11 -0
  312. package/templates/imessage/lib/agent-call.ts +251 -0
  313. package/templates/imessage/lib/assistant.ts +74 -0
  314. package/templates/imessage/lib/chunk.ts +135 -0
  315. package/templates/imessage/lib/demo.ts +68 -0
  316. package/templates/imessage/lib/format.ts +170 -0
  317. package/templates/imessage/lib/gate.ts +104 -0
  318. package/templates/imessage/lib/handles.ts +67 -0
  319. package/templates/imessage/lib/provider.ts +38 -0
  320. package/templates/imessage/lib/relay-protocol.ts +95 -0
  321. package/templates/imessage/lib/reminders.ts +41 -0
  322. package/templates/imessage/lib/secrets.ts +59 -0
  323. package/templates/imessage/lib/sendblue.ts +173 -0
  324. package/templates/imessage/lib/store.ts +407 -0
  325. package/templates/imessage/lib/transport.ts +135 -0
  326. package/templates/imessage/lib/utils.ts +10 -0
  327. package/templates/imessage/package.json +40 -0
  328. package/templates/imessage/relay/.env.example +14 -0
  329. package/templates/imessage/relay/applescript.ts +70 -0
  330. package/templates/imessage/relay/chatdb.ts +165 -0
  331. package/templates/imessage/relay/client.ts +41 -0
  332. package/templates/imessage/relay/main.ts +137 -0
  333. package/templates/imessage/relay/state.ts +35 -0
  334. package/templates/imessage/tests/agent-call.test.ts +112 -0
  335. package/templates/imessage/tests/applescript.test.ts +88 -0
  336. package/templates/imessage/tests/chatdb.test.ts +139 -0
  337. package/templates/imessage/tests/chunk.test.ts +61 -0
  338. package/templates/imessage/tests/fake-ctx.ts +88 -0
  339. package/templates/imessage/tests/ingest.test.ts +141 -0
  340. package/templates/imessage/tests/lib.test.ts +99 -0
  341. package/templates/imessage/tests/review-fixes.test.ts +138 -0
  342. package/templates/imessage/tests/secrets.test.ts +36 -0
  343. package/templates/imessage/tests/sendblue.test.ts +143 -0
  344. package/templates/imessage/tests/setup.ts +5 -0
  345. package/templates/imessage/tsconfig.json +18 -0
  346. package/templates/inventory/README.md +21 -0
  347. package/templates/inventory/app/apple-icon.png +0 -0
  348. package/templates/inventory/app/globals.css +29 -14
  349. package/templates/inventory/app/icon.svg +1 -0
  350. package/templates/inventory/app/layout.tsx +7 -5
  351. package/templates/inventory/app/movements/movements-view.tsx +32 -10
  352. package/templates/inventory/app/movements/page.tsx +2 -1
  353. package/templates/inventory/app/page.tsx +4 -6
  354. package/templates/inventory/app/products/[id]/page.tsx +2 -1
  355. package/templates/inventory/app/products/[id]/product-view.tsx +55 -25
  356. package/templates/inventory/app/products-view.tsx +74 -33
  357. package/templates/inventory/app/workspace.tsx +34 -16
  358. package/templates/inventory/app.ts +10 -2
  359. package/templates/inventory/components/app-shell.tsx +94 -0
  360. package/templates/inventory/components/auth-form.tsx +35 -5
  361. package/templates/inventory/components/avatar.tsx +5 -1
  362. package/templates/inventory/components/brand-mark.tsx +25 -0
  363. package/templates/inventory/components/category-tile.tsx +49 -0
  364. package/templates/inventory/components/command-palette.tsx +17 -17
  365. package/templates/inventory/components/data-table.tsx +97 -36
  366. package/templates/inventory/components/filter-tabs.tsx +101 -0
  367. package/templates/inventory/components/nav.tsx +14 -0
  368. package/templates/inventory/components/page-header.tsx +43 -7
  369. package/templates/inventory/components/require-auth.tsx +24 -26
  370. package/templates/inventory/components/sidebar.tsx +54 -48
  371. package/templates/inventory/components/stock-level.tsx +30 -14
  372. package/templates/inventory/components/summary-bar.tsx +8 -15
  373. package/templates/inventory/components/ui/button.tsx +5 -4
  374. package/templates/inventory/components/ui/dialog.tsx +1 -1
  375. package/templates/inventory/components/ui/input.tsx +1 -1
  376. package/templates/inventory/components/ui/select.tsx +1 -1
  377. package/templates/inventory/components/ui/textarea.tsx +1 -1
  378. package/templates/inventory/functions/seedWorkspace.ts +18 -8
  379. package/templates/inventory/lib/brand.ts +9 -0
  380. package/templates/inventory/lib/demo-team.ts +51 -0
  381. package/templates/inventory/lib/search.ts +4 -3
  382. package/templates/inventory/lib/seed.ts +29 -2
  383. package/templates/inventory/lib/stock.ts +32 -0
  384. package/templates/inventory/public/favicon.ico +0 -0
  385. package/templates/inventory/tests/demo-team.test.ts +18 -0
  386. package/templates/inventory/tests/stock.test.ts +29 -0
  387. package/templates/invoices/README.md +16 -0
  388. package/templates/invoices/app/apple-icon.png +0 -0
  389. package/templates/invoices/app/clients/clients-view.tsx +18 -6
  390. package/templates/invoices/app/clients/page.tsx +2 -1
  391. package/templates/invoices/app/globals.css +29 -14
  392. package/templates/invoices/app/icon.svg +1 -0
  393. package/templates/invoices/app/invoices/[id]/invoice-view.tsx +72 -48
  394. package/templates/invoices/app/invoices/[id]/page.tsx +2 -1
  395. package/templates/invoices/app/invoices-view.tsx +81 -32
  396. package/templates/invoices/app/layout.tsx +7 -5
  397. package/templates/invoices/app/page.tsx +4 -6
  398. package/templates/invoices/app/workspace.tsx +26 -16
  399. package/templates/invoices/app.ts +2 -2
  400. package/templates/invoices/components/app-shell.tsx +94 -0
  401. package/templates/invoices/components/auth-form.tsx +35 -5
  402. package/templates/invoices/components/avatar.tsx +5 -1
  403. package/templates/invoices/components/brand-mark.tsx +26 -0
  404. package/templates/invoices/components/command-palette.tsx +17 -17
  405. package/templates/invoices/components/data-table.tsx +97 -36
  406. package/templates/invoices/components/filter-tabs.tsx +101 -0
  407. package/templates/invoices/components/line-items.tsx +19 -14
  408. package/templates/invoices/components/nav.tsx +14 -0
  409. package/templates/invoices/components/page-header.tsx +43 -7
  410. package/templates/invoices/components/require-auth.tsx +24 -26
  411. package/templates/invoices/components/sidebar.tsx +54 -48
  412. package/templates/invoices/components/status-badge.tsx +7 -7
  413. package/templates/invoices/components/summary-bar.tsx +5 -5
  414. package/templates/invoices/components/ui/button.tsx +5 -4
  415. package/templates/invoices/components/ui/dialog.tsx +1 -1
  416. package/templates/invoices/components/ui/input.tsx +1 -1
  417. package/templates/invoices/components/ui/select.tsx +1 -1
  418. package/templates/invoices/components/ui/textarea.tsx +1 -1
  419. package/templates/invoices/functions/recordPayment.ts +3 -0
  420. package/templates/invoices/lib/billing.ts +40 -0
  421. package/templates/invoices/lib/brand.ts +9 -0
  422. package/templates/invoices/lib/search.ts +4 -3
  423. package/templates/invoices/public/favicon.ico +0 -0
  424. package/templates/invoices/tests/billing.test.ts +27 -0
  425. package/templates/ios/consumer/apps/ios/Package.swift +4 -3
  426. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ActivityView.swift +107 -0
  427. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/AppModel.swift +171 -0
  428. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/AuthView.swift +182 -0
  429. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/CommentsView.swift +136 -0
  430. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ComposeView.swift +152 -0
  431. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ExploreView.swift +117 -0
  432. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/FeedView.swift +175 -159
  433. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/MainTabView.swift +54 -0
  434. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/Media.swift +271 -0
  435. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/Models.swift +101 -4
  436. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/PostCard.swift +245 -0
  437. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ProfileEditorView.swift +208 -0
  438. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ProfileView.swift +183 -0
  439. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/RootView.swift +25 -31
  440. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/SocialStore.swift +285 -0
  441. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/StoryViewer.swift +155 -0
  442. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/Theme.swift +82 -0
  443. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/__APP_NAME_PASCAL__App.swift +4 -47
  444. package/templates/ios/consumer/apps/ios/project.yml +13 -9
  445. package/templates/local-service/.env.example +7 -0
  446. package/templates/local-service/README.md +26 -2
  447. package/templates/local-service/app/(marketing)/booking-widget.tsx +48 -9
  448. package/templates/local-service/app/(marketing)/page.tsx +66 -42
  449. package/templates/local-service/app/auth-form.tsx +8 -8
  450. package/templates/local-service/app/dashboard/dashboard-client.tsx +119 -92
  451. package/templates/local-service/app/dashboard/page.tsx +14 -14
  452. package/templates/local-service/app/icon.svg +2 -0
  453. package/templates/local-service/app/login/page.tsx +15 -15
  454. package/templates/local-service/functions/seedDemo.ts +49 -0
  455. package/templates/local-service/lib/demo.ts +135 -0
  456. package/templates/local-service/lib/hours.ts +44 -0
  457. package/templates/local-service/lib/site.config.ts +8 -3
  458. package/templates/local-service/lib/slots.ts +3 -0
  459. package/templates/local-service/public/favicon.ico +0 -0
  460. package/templates/local-service/tests/booking.test.ts +104 -0
  461. package/templates/marketplace/README.md +23 -15
  462. package/templates/marketplace/app/globals.css +172 -114
  463. package/templates/marketplace/app/layout.tsx +75 -30
  464. package/templates/marketplace/app/listing/[id]/page.tsx +210 -123
  465. package/templates/marketplace/app/me/page.tsx +4 -4
  466. package/templates/marketplace/app/page.tsx +221 -298
  467. package/templates/marketplace/app/sell/page.tsx +8 -11
  468. package/templates/marketplace/app.ts +32 -7
  469. package/templates/marketplace/client/ActivityFeed.tsx +311 -0
  470. package/templates/marketplace/client/AuthNav.tsx +24 -16
  471. package/templates/marketplace/client/ListingCard.tsx +118 -0
  472. package/templates/marketplace/client/LiveGrid.tsx +92 -0
  473. package/templates/marketplace/client/LiveListingStatus.tsx +32 -24
  474. package/templates/marketplace/client/LoginCard.tsx +114 -136
  475. package/templates/marketplace/client/MarketProvider.tsx +3 -5
  476. package/templates/marketplace/client/MyMarket.tsx +371 -185
  477. package/templates/marketplace/client/OfferPanel.tsx +421 -287
  478. package/templates/marketplace/client/SellForm.tsx +271 -192
  479. package/templates/marketplace/client/ThemeToggle.tsx +1 -0
  480. package/templates/marketplace/client/WatchButton.tsx +16 -16
  481. package/templates/marketplace/client/market.ts +61 -14
  482. package/templates/marketplace/functions/seedMarket.ts +143 -36
  483. package/templates/marketplace/functions/seedOffers.ts +101 -0
  484. package/templates/marketplace/lib/catalog.ts +72 -1
  485. package/templates/marketplace/public/images/listings/ceramic-lamp-640.webp +0 -0
  486. package/templates/marketplace/public/images/listings/ceramic-lamp.webp +0 -0
  487. package/templates/marketplace/public/images/listings/duffel-640.webp +0 -0
  488. package/templates/marketplace/public/images/listings/duffel.webp +0 -0
  489. package/templates/marketplace/public/images/listings/film-camera-640.webp +0 -0
  490. package/templates/marketplace/public/images/listings/film-camera.webp +0 -0
  491. package/templates/marketplace/public/images/listings/lounge-chair-640.webp +0 -0
  492. package/templates/marketplace/public/images/listings/lounge-chair.webp +0 -0
  493. package/templates/marketplace/public/images/listings/road-bike-640.webp +0 -0
  494. package/templates/marketplace/public/images/listings/road-bike.webp +0 -0
  495. package/templates/marketplace/public/images/listings/slipper-chair-640.webp +0 -0
  496. package/templates/marketplace/public/images/listings/slipper-chair.webp +0 -0
  497. package/templates/marketplace/public/images/listings/turntable-640.webp +0 -0
  498. package/templates/marketplace/public/images/listings/turntable.webp +0 -0
  499. package/templates/marketplace/public/images/listings/wardrobe-640.webp +0 -0
  500. package/templates/marketplace/public/images/listings/wardrobe.webp +0 -0
  501. package/templates/marketplace/public/images/listings/watch-640.webp +0 -0
  502. package/templates/marketplace/public/images/listings/watch.webp +0 -0
  503. package/templates/marketplace/public/images/listings/weekender-bag-640.webp +0 -0
  504. package/templates/marketplace/public/images/listings/weekender-bag.webp +0 -0
  505. package/templates/marketplace/tests/example.test.ts +64 -2
  506. package/templates/marketplace/tests/listing-card.test.tsx +61 -0
  507. package/templates/projects/README.md +24 -3
  508. package/templates/projects/app/apple-icon.png +0 -0
  509. package/templates/projects/app/clients/clients-view.tsx +20 -6
  510. package/templates/projects/app/clients/page.tsx +2 -1
  511. package/templates/projects/app/globals.css +29 -14
  512. package/templates/projects/app/icon.svg +1 -0
  513. package/templates/projects/app/layout.tsx +7 -5
  514. package/templates/projects/app/page.tsx +3 -5
  515. package/templates/projects/app/projects/[id]/page.tsx +2 -1
  516. package/templates/projects/app/projects/[id]/project-view.tsx +45 -30
  517. package/templates/projects/app/projects-view.tsx +105 -52
  518. package/templates/projects/app/workspace.tsx +41 -20
  519. package/templates/projects/app.ts +2 -2
  520. package/templates/projects/components/app-shell.tsx +94 -0
  521. package/templates/projects/components/auth-form.tsx +35 -5
  522. package/templates/projects/components/avatar.tsx +5 -1
  523. package/templates/projects/components/board-skeleton.tsx +3 -3
  524. package/templates/projects/components/brand-mark.tsx +25 -0
  525. package/templates/projects/components/command-palette.tsx +17 -17
  526. package/templates/projects/components/data-table.tsx +97 -36
  527. package/templates/projects/components/filter-tabs.tsx +101 -0
  528. package/templates/projects/components/meter.tsx +48 -0
  529. package/templates/projects/components/nav.tsx +14 -0
  530. package/templates/projects/components/page-header.tsx +43 -7
  531. package/templates/projects/components/require-auth.tsx +24 -26
  532. package/templates/projects/components/sidebar.tsx +54 -48
  533. package/templates/projects/components/summary-bar.tsx +49 -0
  534. package/templates/projects/components/task-board.tsx +10 -9
  535. package/templates/projects/components/time-dialog.tsx +29 -5
  536. package/templates/projects/components/ui/button.tsx +5 -4
  537. package/templates/projects/components/ui/dialog.tsx +1 -1
  538. package/templates/projects/components/ui/input.tsx +1 -1
  539. package/templates/projects/components/ui/select.tsx +1 -1
  540. package/templates/projects/components/ui/textarea.tsx +1 -1
  541. package/templates/projects/functions/seedWorkspace.ts +26 -12
  542. package/templates/projects/lib/brand.ts +9 -0
  543. package/templates/projects/lib/demo-team.ts +51 -0
  544. package/templates/projects/lib/search.ts +4 -3
  545. package/templates/projects/lib/seed.ts +35 -1
  546. package/templates/projects/lib/work.ts +63 -0
  547. package/templates/projects/public/favicon.ico +0 -0
  548. package/templates/projects/tests/demo-team.test.ts +18 -0
  549. package/templates/projects/tests/work.test.ts +65 -0
  550. package/templates/restaurant/.env.example +7 -0
  551. package/templates/restaurant/README.md +29 -3
  552. package/templates/restaurant/app/(marketing)/layout.tsx +4 -2
  553. package/templates/restaurant/app/(marketing)/page.tsx +47 -23
  554. package/templates/restaurant/app/(marketing)/reservation-widget.tsx +37 -7
  555. package/templates/restaurant/app/auth-form.tsx +8 -8
  556. package/templates/restaurant/app/dashboard/dashboard-client.tsx +241 -109
  557. package/templates/restaurant/app/dashboard/page.tsx +14 -14
  558. package/templates/restaurant/app/icon.svg +4 -0
  559. package/templates/restaurant/app/login/page.tsx +15 -15
  560. package/templates/restaurant/functions/seedDemo.ts +44 -0
  561. package/templates/restaurant/lib/demo.ts +144 -0
  562. package/templates/restaurant/lib/hours.ts +45 -0
  563. package/templates/restaurant/lib/site.config.ts +3 -3
  564. package/templates/restaurant/public/favicon.ico +0 -0
  565. package/templates/restaurant/tests/reservations.test.ts +67 -0
  566. package/templates/saas/README.md +54 -35
  567. package/templates/saas/app/(auth)/auth-form.tsx +25 -23
  568. package/templates/saas/app/(auth)/forgot-password/page.tsx +1 -1
  569. package/templates/saas/app/(auth)/layout.tsx +27 -33
  570. package/templates/saas/app/(auth)/login/page.tsx +1 -1
  571. package/templates/saas/app/(auth)/reset-password/page.tsx +1 -1
  572. package/templates/saas/app/(auth)/signup/page.tsx +1 -1
  573. package/templates/saas/app/(marketing)/layout.tsx +127 -253
  574. package/templates/saas/app/(marketing)/page.tsx +133 -372
  575. package/templates/saas/app/(marketing)/pricing/page.tsx +21 -19
  576. package/templates/saas/app/(marketing)/products/[slug]/page.tsx +40 -95
  577. package/templates/saas/app/dashboard/board-client.tsx +416 -0
  578. package/templates/saas/app/dashboard/dashboard-client.tsx +30 -615
  579. package/templates/saas/app/dashboard/layout.tsx +27 -13
  580. package/templates/saas/app/dashboard/overview-client.tsx +332 -0
  581. package/templates/saas/app/dashboard/page.tsx +29 -35
  582. package/templates/saas/app/dashboard/projects/[id]/page.tsx +29 -0
  583. package/templates/saas/app/dashboard/projects/page.tsx +11 -7
  584. package/templates/saas/app/dashboard/projects-client.tsx +398 -0
  585. package/templates/saas/app/globals.css +5 -4
  586. package/templates/saas/app/icon.svg +1 -0
  587. package/templates/saas/app/onboarding/onboarding-client.tsx +93 -26
  588. package/templates/saas/app/onboarding/page.tsx +6 -2
  589. package/templates/saas/app.ts +68 -13
  590. package/templates/saas/components/dashboard-shell.tsx +212 -132
  591. package/templates/saas/components/marketing.tsx +137 -274
  592. package/templates/saas/components/pricing-table.tsx +12 -11
  593. package/templates/saas/components/setup-checklist.tsx +31 -29
  594. package/templates/saas/components/task-ui.tsx +199 -0
  595. package/templates/saas/functions/createProject.ts +7 -13
  596. package/templates/saas/functions/createTask.ts +67 -0
  597. package/templates/saas/functions/deleteProject.ts +17 -0
  598. package/templates/saas/functions/deleteTask.ts +14 -0
  599. package/templates/saas/functions/seedWorkspace.ts +46 -0
  600. package/templates/saas/functions/setProjectStatus.ts +41 -0
  601. package/templates/saas/functions/updateProfile.ts +13 -0
  602. package/templates/saas/functions/updateProject.ts +4 -5
  603. package/templates/saas/functions/updateTask.ts +88 -0
  604. package/templates/saas/lib/members.ts +53 -0
  605. package/templates/saas/lib/names.ts +53 -0
  606. package/templates/saas/lib/plans.ts +11 -0
  607. package/templates/saas/lib/sample-workspace.ts +117 -0
  608. package/templates/saas/lib/site.config.ts +200 -463
  609. package/templates/saas/lib/tasks.ts +101 -0
  610. package/templates/saas/lib/use-live.ts +25 -0
  611. package/templates/saas/public/favicon.ico +0 -0
  612. package/templates/saas/public/screenshots/board.png +0 -0
  613. package/templates/saas/public/screenshots/members.png +0 -0
  614. package/templates/saas/public/screenshots/overview.png +0 -0
  615. package/templates/saas/public/screenshots/projects.png +0 -0
  616. package/templates/saas/scripts/capture-screenshots.mjs +156 -0
  617. package/templates/saas/tests/names.test.ts +35 -0
  618. package/templates/saas/tests/plans.test.ts +12 -0
  619. package/templates/saas/tests/sample-workspace.test.ts +46 -0
  620. package/templates/saas/tests/tasks.test.ts +81 -0
  621. package/templates/shop/README.md +25 -13
  622. package/templates/shop/app/(marketing)/layout.tsx +94 -67
  623. package/templates/shop/app/(marketing)/not-found.tsx +13 -12
  624. package/templates/shop/app/(marketing)/page.tsx +120 -59
  625. package/templates/shop/app/(marketing)/shop-client.tsx +364 -237
  626. package/templates/shop/app/(marketing)/success/page.tsx +75 -22
  627. package/templates/shop/app/globals.css +94 -1
  628. package/templates/shop/app/layout.tsx +4 -4
  629. package/templates/shop/app/login/page.tsx +4 -4
  630. package/templates/shop/app.ts +18 -6
  631. package/templates/shop/components/cart-button.tsx +33 -0
  632. package/templates/shop/components/marketing.tsx +17 -87
  633. package/templates/shop/components/shelf-count.tsx +36 -0
  634. package/templates/shop/functions/checkout.ts +17 -1
  635. package/templates/shop/lib/cart-store.ts +57 -0
  636. package/templates/shop/lib/shelf-store.ts +35 -0
  637. package/templates/shop/lib/shop.ts +27 -0
  638. package/templates/shop/lib/site.config.ts +108 -98
  639. package/templates/shop/public/images/hero.jpg +0 -0
  640. package/templates/shop/public/images/products/cedar-smoke.jpg +0 -0
  641. package/templates/shop/public/images/products/fig-leaf.jpg +0 -0
  642. package/templates/shop/public/images/products/linen.jpg +0 -0
  643. package/templates/shop/public/images/products/sea-salt.jpg +0 -0
  644. package/templates/shop/public/images/products/tobacco-oak.jpg +0 -0
  645. package/templates/shop/tests/shop.test.ts +64 -0
  646. package/templates/waitlist/.env.example +7 -0
  647. package/templates/waitlist/README.md +29 -13
  648. package/templates/waitlist/app/(marketing)/page.tsx +9 -7
  649. package/templates/waitlist/app/(marketing)/waitlist-hero.tsx +64 -31
  650. package/templates/waitlist/app/auth-form.tsx +8 -8
  651. package/templates/waitlist/app/dashboard/dashboard-client.tsx +132 -95
  652. package/templates/waitlist/app/dashboard/page.tsx +17 -16
  653. package/templates/waitlist/app/icon.svg +2 -0
  654. package/templates/waitlist/app/login/page.tsx +14 -14
  655. package/templates/waitlist/app.ts +6 -6
  656. package/templates/waitlist/functions/joinWaitlist.ts +6 -18
  657. package/templates/waitlist/functions/seedDemo.ts +32 -0
  658. package/templates/waitlist/lib/demo.ts +94 -0
  659. package/templates/waitlist/lib/launch.ts +19 -0
  660. package/templates/waitlist/lib/site.config.ts +14 -9
  661. package/templates/waitlist/lib/stats.ts +35 -0
  662. package/templates/waitlist/public/favicon.ico +0 -0
  663. package/templates/waitlist/tests/counter.test.ts +107 -0
  664. package/templates/waitlist/tests/live-count.test.tsx +48 -0
  665. package/templates/ai-chat/tests/example.test.ts +0 -12
  666. package/templates/backend/consumer/apps/api/functions/feed.ts +0 -57
  667. package/templates/backend/consumer/apps/api/functions/profilePosts.ts +0 -17
  668. package/templates/backend/consumer/apps/api/functions/toggleLike.ts +0 -48
  669. package/templates/backend/consumer/apps/api/schema.ts +0 -143
  670. package/templates/chat/functions/_keep.ts +0 -13
  671. package/templates/chat/tests/example.test.ts +0 -12
  672. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ProfileSetupView.swift +0 -68
  673. package/templates/marketplace/client/LiveTicker.tsx +0 -116
  674. package/templates/marketplace/client/ScrollToListingsLink.tsx +0 -29
  675. package/templates/marketplace/public/images/marketplace-hero.webp +0 -0
@@ -1,8 +1,10 @@
1
- // Demo data for a new app: twelve people who post, follow each other, like,
2
- // and comment, so the first visit opens on a feed that looks lived in.
1
+ // Demo data for a new app: eight people who post, follow each other, like,
2
+ // and comment, so the first visit opens on a feed with content in it.
3
3
  //
4
- // Photos live in public/images (avatars/ and posts/). Demo user ids start
5
- // with "demo_" so they never collide with a real or guest account.
4
+ // Post photos live in public/images/posts and the server serves them at
5
+ // /images/posts/<key>.jpg. Demo people have no profile photo, so the app
6
+ // draws their initial. Demo user ids start with "demo_" so they never
7
+ // collide with a real or guest account.
6
8
  // Pure data + pure shaping; functions/seedFeed.ts is a thin wrapper.
7
9
 
8
10
  export interface SeedProfile {
@@ -12,6 +14,7 @@ export interface SeedProfile {
12
14
  }
13
15
 
14
16
  export interface SeedPost {
17
+ /** File name under public/images/posts, without `.jpg`. */
15
18
  key: string;
16
19
  author: string;
17
20
  caption: string;
@@ -29,99 +32,54 @@ export interface SeedComment {
29
32
  }
30
33
 
31
34
  export const SEED_PROFILES: SeedProfile[] = [
32
- { username: "mara.bakes", displayName: "Mara Lindqvist", bio: "Sourdough, mostly. Stockholm." },
33
- { username: "theo.climbs", displayName: "Theo Adeyemi", bio: "Bouldering most evenings. Route setter at Blocworks." },
34
- { username: "ines.clay", displayName: "Inés Moreno", bio: "Wheel-thrown stoneware from a small studio in Valencia." },
35
- { username: "kenji.rides", displayName: "Kenji Watanabe", bio: "Gravel on weekends, commuting on weekdays." },
36
- { username: "lou.streets", displayName: "Louise Carter", bio: "35mm film, mostly Brooklyn." },
37
- { username: "sam.grows", displayName: "Sam Okafor", bio: "Allotment 14B. Tomatoes, beans, too many courgettes." },
38
- { username: "rosa.roasts", displayName: "Rosa Delgado", bio: "Head roaster at a small shop in Oakland." },
39
- { username: "biscuit.corgi", displayName: "Biscuit", bio: "Corgi. Professional napper. Managed by @nora.h" },
40
- { username: "nora.h", displayName: "Nora Hughes", bio: "Product designer. Biscuit's person." },
41
- { username: "ari.wanders", displayName: "Ari Cohen", bio: "Trains over planes." },
42
- { username: "dev.draws", displayName: "Dev Patel", bio: "Architect. A sketch every morning before work." },
43
- { username: "june.surfs", displayName: "June Tanaka", bio: "Cold water surfer on the Oregon coast." },
35
+ { username: "maya.rivera", displayName: "Maya Rivera", bio: "Travel photographer. Currently in Lisbon." },
36
+ { username: "jordan.eats", displayName: "Jordan Brooks", bio: "Cooking at home, eating out, writing it all down." },
37
+ { username: "priya.home", displayName: "Priya Shah", bio: "Interior designer. Small rooms, good light." },
38
+ { username: "kenji.mori", displayName: "Kenji Mori", bio: "Architecture and night walks. Tokyo." },
39
+ { username: "elena.runs", displayName: "Elena Berg", bio: "Trail runner. Mountains most weekends." },
40
+ { username: "sam.and.juno", displayName: "Sam Whitaker", bio: "Juno is the golden one." },
41
+ { username: "amara.o", displayName: "Amara Okafor", bio: "Coffee, markets, and early mornings." },
42
+ { username: "leo.haddad", displayName: "Leo Haddad", bio: "Road trips and sunsets. Film when I can." },
44
43
  ];
45
44
 
46
45
  export const SEED_POSTS: SeedPost[] = [
47
- { key: "mara-loaf", author: "mara.bakes", caption: "Sunday loaf. 78% hydration and finally an ear I am happy with.", shape: "portrait", age: 3 },
48
- { key: "june-dawn", author: "june.surfs", caption: "Glassy at 6am and nobody else out. Worth the cold hands.", shape: "portrait", age: 5 },
49
- { key: "biscuit-couch", author: "biscuit.corgi", caption: "Guarding the couch from nothing in particular.", shape: "square", age: 8 },
50
- { key: "rosa-roaster", author: "rosa.roasts", caption: "New Ethiopia lot on the roaster today. Blueberry and jasmine in the cup.", shape: "square", age: 11 },
51
- { key: "ines-glaze", author: "ines.clay", caption: "Out of the kiln: the speckled oat glaze on a batch of mugs. Shop update Friday.", shape: "portrait", age: 14 },
52
- { key: "lou-crosswalk", author: "lou.streets", caption: "Bedford Ave, late afternoon. Portra 400.", shape: "portrait", age: 20 },
53
- { key: "dev-sketch", author: "dev.draws", caption: "Morning sketch of the old library stairs. Twenty minutes, one pen.", shape: "square", age: 26 },
54
- { key: "kenji-gravel", author: "kenji.rides", caption: "82 km, 1,400 m of climbing, one flat. Good day.", shape: "portrait", age: 30 },
55
- { key: "sam-tomatoes", author: "sam.grows", caption: "First proper harvest of the year. The yellow ones are Sungold.", shape: "square", age: 34 },
56
- { key: "theo-boulder", author: "theo.climbs", caption: "Set a new blue circuit this week. This one is the crux of number 6.", shape: "portrait", age: 40 },
57
- { key: "ari-train", author: "ari.wanders", caption: "Night train from Vienna to Venice. Woke up to this.", shape: "portrait", age: 46 },
58
- { key: "nora-desk", author: "nora.h", caption: "New desk setup. @biscuit.corgi approved the rug.", shape: "square", age: 52 },
59
- { key: "mara-buns", author: "mara.bakes", caption: "Cardamom buns for the neighbours. Kept two.", shape: "square", age: 60 },
60
- { key: "june-board", author: "june.surfs", caption: "Waxed and ready for tomorrow.", shape: "square", age: 70 },
61
- { key: "rosa-latte", author: "rosa.roasts", caption: "Tuesday latte art practice. Getting there.", shape: "square", age: 78 },
62
- { key: "ines-wheel", author: "ines.clay", caption: "Trimming feet on a batch of bowls. The quiet part of the week.", shape: "portrait", age: 90 },
63
- { key: "lou-diner", author: "lou.streets", caption: "Counter seats at the diner on Graham. Coffee refills forever.", shape: "square", age: 100 },
64
- { key: "biscuit-beach", author: "biscuit.corgi", caption: "First time at the beach. Sand everywhere. No regrets.", shape: "portrait", age: 110 },
65
- { key: "dev-model", author: "dev.draws", caption: "Card model for the community centre competition entry.", shape: "square", age: 124 },
66
- { key: "kenji-coffee", author: "kenji.rides", caption: "Mid-ride coffee stop. The bike rests too.", shape: "square", age: 140 },
67
- { key: "sam-shed", author: "sam.grows", caption: "Seed trays in the shed. Kale, chard, and far too much basil.", shape: "portrait", age: 155 },
68
- { key: "theo-chalk", author: "theo.climbs", caption: "Chalk bag, tape, and a very tired pair of shoes.", shape: "square", age: 170 },
69
- { key: "ari-market", author: "ari.wanders", caption: "Morning market in Palermo. I bought too many lemons.", shape: "square", age: 190 },
70
- { key: "nora-sketches", author: "nora.h", caption: "Paper first, screens later. Wireframes for the booking flow.", shape: "square", age: 210 },
71
- { key: "mara-starter", author: "mara.bakes", caption: "Meet Olof, the starter. Eleven years old this month.", shape: "portrait", age: 240 },
72
- { key: "june-van", author: "june.surfs", caption: "Home for the weekend.", shape: "square", age: 280 },
73
- { key: "ines-studio", author: "ines.clay", caption: "The studio shelves on a good week.", shape: "portrait", age: 320 },
74
- { key: "lou-rain", author: "lou.streets", caption: "Rain on the J train platform.", shape: "portrait", age: 360 },
46
+ { key: "lisbon", author: "maya.rivera", caption: "Tram 28 at golden hour. Waited twenty minutes for this one and it was worth it.", shape: "square", age: 1.5 },
47
+ { key: "coffee", author: "amara.o", caption: "Flat white and a croissant before the market opens.", shape: "square", age: 3 },
48
+ { key: "dog", author: "sam.and.juno", caption: "Juno found the tall grass again.", shape: "square", age: 5 },
49
+ { key: "run", author: "elena.runs", caption: "Sunrise on the ridge. 18 km, 900 m up, legs gone.", shape: "square", age: 8 },
50
+ { key: "ramen", author: "jordan.eats", caption: "Tonkotsu from the new place on 5th. Broth cooked for 14 hours and you can tell.", shape: "square", age: 11 },
51
+ { key: "arch", author: "kenji.mori", caption: "Curves and shadows. The museum extension at noon.", shape: "square", age: 14 },
52
+ { key: "sunset", author: "leo.haddad", caption: "Big Sur, last light. 30 second exposure.", shape: "square", age: 20 },
75
53
  ];
76
54
 
77
55
  export const SEED_COMMENTS: SeedComment[] = [
78
- { post: "mara-loaf", author: "rosa.roasts", text: "That crumb. Trading you a bag of the new Ethiopia for one.", after: 0.5 },
79
- { post: "mara-loaf", author: "sam.grows", text: "What flour are you using?", after: 1 },
80
- { post: "mara-loaf", author: "mara.bakes", text: "@sam.grows 80% bread flour, 20% whole wheat from the mill down the road.", after: 1.5 },
81
- { post: "june-dawn", author: "kenji.rides", text: "Unreal colours.", after: 1 },
82
- { post: "june-dawn", author: "ari.wanders", text: "Which beach is this?", after: 2 },
83
- { post: "biscuit-couch", author: "nora.h", text: "He has not moved in three hours.", after: 0.2 },
84
- { post: "biscuit-couch", author: "lou.streets", text: "A very serious job.", after: 2 },
85
- { post: "biscuit-couch", author: "theo.climbs", text: "Those ears.", after: 3 },
86
- { post: "rosa-roaster", author: "mara.bakes", text: "Saving me a bag?", after: 1 },
87
- { post: "rosa-roaster", author: "rosa.roasts", text: "@mara.bakes already set aside.", after: 1.2 },
88
- { post: "ines-glaze", author: "dev.draws", text: "The speckle on that glaze is lovely.", after: 2 },
89
- { post: "ines-glaze", author: "nora.h", text: "Setting an alarm for Friday.", after: 3 },
90
- { post: "lou-crosswalk", author: "ari.wanders", text: "The light in this one.", after: 4 },
91
- { post: "dev-sketch", author: "ines.clay", text: "Twenty minutes? Show-off.", after: 1 },
92
- { post: "kenji-gravel", author: "june.surfs", text: "Where was the flat?", after: 2 },
93
- { post: "kenji-gravel", author: "kenji.rides", text: "@june.surfs about 5 km from the end, of course.", after: 3 },
94
- { post: "sam-tomatoes", author: "mara.bakes", text: "Tomato and bread season.", after: 1 },
95
- { post: "theo-boulder", author: "kenji.rides", text: "Looks sandbagged.", after: 2 },
96
- { post: "theo-boulder", author: "theo.climbs", text: "@kenji.rides it is a fair blue. Mostly.", after: 2.5 },
97
- { post: "ari-train", author: "lou.streets", text: "Adding this to the list.", after: 5 },
98
- { post: "nora-desk", author: "dev.draws", text: "Where is the lamp from?", after: 1 },
99
- { post: "mara-buns", author: "rosa.roasts", text: "Recipe please.", after: 2 },
100
- { post: "biscuit-beach", author: "june.surfs", text: "Surf lessons next.", after: 1 },
101
- { post: "dev-model", author: "ines.clay", text: "Good luck with the entry.", after: 3 },
102
- { post: "sam-shed", author: "mara.bakes", text: "Pesto for the whole street then.", after: 4 },
103
- { post: "mara-starter", author: "biscuit.corgi", text: "Can I eat Olof.", after: 2 },
104
- { post: "mara-starter", author: "mara.bakes", text: "@biscuit.corgi no.", after: 2.2 },
56
+ { post: "lisbon", author: "leo.haddad", text: "The light on those tiles. Which street is this?", after: 0.3 },
57
+ { post: "lisbon", author: "maya.rivera", text: "@leo.haddad Rua da Conceição, just before it turns up to the cathedral.", after: 0.6 },
58
+ { post: "lisbon", author: "amara.o", text: "Adding this to the list for May.", after: 0.9 },
59
+ { post: "coffee", author: "jordan.eats", text: "That rosetta is perfect.", after: 0.5 },
60
+ { post: "coffee", author: "priya.home", text: "Where is this? I need that table.", after: 1 },
61
+ { post: "dog", author: "elena.runs", text: "Juno looks so happy.", after: 0.4 },
62
+ { post: "dog", author: "amara.o", text: "Best dog on this app.", after: 1.2 },
63
+ { post: "run", author: "kenji.mori", text: "Incredible view. How early did you start?", after: 1 },
64
+ { post: "run", author: "elena.runs", text: "@kenji.mori headlamps on at 4:30.", after: 1.5 },
65
+ { post: "ramen", author: "maya.rivera", text: "Going this week.", after: 2 },
66
+ { post: "arch", author: "priya.home", text: "Those shadows are unreal.", after: 1 },
67
+ { post: "sunset", author: "sam.and.juno", text: "Colors like this make me want to drive up the coast tonight.", after: 2 },
105
68
  ];
106
69
 
107
70
  /** Who each demo user follows, as username → usernames. */
108
71
  export const SEED_FOLLOWS: Record<string, string[]> = {
109
- "mara.bakes": ["rosa.roasts", "sam.grows", "ines.clay", "biscuit.corgi", "lou.streets"],
110
- "theo.climbs": ["kenji.rides", "june.surfs", "ari.wanders", "biscuit.corgi"],
111
- "ines.clay": ["dev.draws", "mara.bakes", "nora.h", "lou.streets"],
112
- "kenji.rides": ["theo.climbs", "june.surfs", "rosa.roasts", "ari.wanders"],
113
- "lou.streets": ["ari.wanders", "dev.draws", "biscuit.corgi", "ines.clay"],
114
- "sam.grows": ["mara.bakes", "rosa.roasts", "biscuit.corgi"],
115
- "rosa.roasts": ["mara.bakes", "kenji.rides", "ines.clay", "sam.grows"],
116
- "biscuit.corgi": ["nora.h", "june.surfs"],
117
- "nora.h": ["biscuit.corgi", "dev.draws", "ines.clay", "lou.streets", "mara.bakes"],
118
- "ari.wanders": ["lou.streets", "june.surfs", "kenji.rides", "theo.climbs"],
119
- "dev.draws": ["ines.clay", "nora.h", "lou.streets"],
120
- "june.surfs": ["kenji.rides", "biscuit.corgi", "ari.wanders", "theo.climbs"],
72
+ "maya.rivera": ["leo.haddad", "amara.o", "priya.home", "kenji.mori"],
73
+ "jordan.eats": ["amara.o", "maya.rivera", "sam.and.juno"],
74
+ "priya.home": ["kenji.mori", "maya.rivera", "amara.o", "elena.runs"],
75
+ "kenji.mori": ["priya.home", "leo.haddad", "elena.runs"],
76
+ "elena.runs": ["sam.and.juno", "leo.haddad", "maya.rivera", "kenji.mori"],
77
+ "sam.and.juno": ["elena.runs", "jordan.eats", "amara.o"],
78
+ "amara.o": ["jordan.eats", "maya.rivera", "priya.home", "sam.and.juno", "elena.runs"],
79
+ "leo.haddad": ["maya.rivera", "elena.runs", "kenji.mori"],
121
80
  };
122
81
 
123
82
  export const demoUserId = (username: string) => `demo_${username.replace(/\./g, "_")}`;
124
- export const avatarPath = (username: string) => `/images/avatars/${username}.jpg`;
125
83
  export const postImagePath = (key: string) => `/images/posts/${key}.jpg`;
126
84
 
127
85
  /**
@@ -158,7 +116,7 @@ export function shapeSeed(now: number = Date.now()): ShapedSeed {
158
116
  username: p.username,
159
117
  displayName: p.displayName,
160
118
  bio: p.bio,
161
- avatarUrl: avatarPath(p.username),
119
+ avatarUrl: null,
162
120
  createdAt: hoursAgo(2000 - i * 40),
163
121
  })),
164
122
  posts: SEED_POSTS.map((p) => ({
@@ -0,0 +1,39 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { existsSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { SEED_COMMENTS, SEED_FOLLOWS, SEED_POSTS, SEED_PROFILES, shapeSeed } from "../lib/seed";
5
+
6
+ const PUBLIC = join(import.meta.dir, "..", "public");
7
+
8
+ /** Every image path the seed writes that the server must serve from public/. */
9
+ function localImages(): string[] {
10
+ const seed = shapeSeed(0);
11
+ const urls = [
12
+ ...seed.posts.map((p) => p.row.imageUrl),
13
+ ...seed.profiles.map((p) => p.avatarUrl),
14
+ ];
15
+ return urls.filter((u): u is string => typeof u === "string" && u.startsWith("/"));
16
+ }
17
+
18
+ describe("demo seed", () => {
19
+ test("every local image it references exists in public/", () => {
20
+ const images = localImages();
21
+ expect(images.length).toBeGreaterThan(0);
22
+ const missing = images.filter((url) => !existsSync(join(PUBLIC, url)));
23
+ expect(missing).toEqual([]);
24
+ });
25
+
26
+ test("posts, comments, and follows only name demo people", () => {
27
+ const people = new Set(SEED_PROFILES.map((p) => p.username));
28
+ const posts = new Set(SEED_POSTS.map((p) => p.key));
29
+ for (const p of SEED_POSTS) expect(people.has(p.author)).toBe(true);
30
+ for (const c of SEED_COMMENTS) {
31
+ expect(people.has(c.author)).toBe(true);
32
+ expect(posts.has(c.post)).toBe(true);
33
+ }
34
+ for (const [from, tos] of Object.entries(SEED_FOLLOWS)) {
35
+ expect(people.has(from)).toBe(true);
36
+ for (const to of tos) expect(people.has(to)).toBe(true);
37
+ }
38
+ });
39
+ });
@@ -10,3 +10,10 @@ PYLON_OWNER_EMAIL=you@yourbusiness.com
10
10
  # ── Site URL (optional) ──────────────────────────────────────────────────────
11
11
  # Used by robots.txt + sitemap.xml. Point it at your real domain in production.
12
12
  # SITE_URL=https://yourbusiness.com
13
+
14
+ # ── Demo data ────────────────────────────────────────────────────────────────
15
+ # `pylon dev` fills an empty subscriber list with fictional rows. Seeding runs
16
+ # only under `pylon dev` (it checks PYLON_DEV_MODE and PYLON_DEV_WATCH_DIR), so
17
+ # `pylon start`, Docker, and Pylon Cloud deploys never seed. Set 0 to start
18
+ # empty in development. Never set 1 on a deploy.
19
+ # PYLON_DEMO_DATA=0
@@ -18,11 +18,23 @@ increment in another without refreshing.
18
18
  ## How the realtime works
19
19
 
20
20
  - `functions/subscribe.ts`: a public **mutation** that validates, lowercases,
21
- and dedupes the email, inserts one `Subscriber` row, and bumps a public,
22
- PII-free `SubscriberCount` row.
23
- - `app/newsletter-signup.tsx` subscribes to `SubscriberCount` with
21
+ and dedupes the email, inserts one `Subscriber` row, and recounts into the
22
+ public, PII-free `SubscriberCount` row.
23
+ - `app/(marketing)/newsletter-signup.tsx` reads `SubscriberCount` with
24
24
  `db.useQuery`, so the live count syncs to every open tab. No polling.
25
25
 
26
+ The counter is the `Subscriber` table's row count, and it is hidden while the
27
+ list is empty. `newsletter.importedCount` in `lib/site.config.ts` adds
28
+ subscribers you are moving over from another tool. It ships as 0.
29
+
30
+ ## Demo data
31
+
32
+ In `pylon dev`, an empty list gets about 180 fictional subscribers from the last
33
+ 30 days, so the counter, chart, and list have data (`functions/seedDemo.ts`,
34
+ `lib/demo.ts`). Seeding runs only when `PYLON_DEMO_DATA` is on, or when it is unset and the app runs under `pylon dev`, and only while the `Subscriber` table is
35
+ empty. `pylon start`, Docker, and Pylon Cloud deploys do not seed, because only `pylon dev` sets `PYLON_DEV_WATCH_DIR`. Set `PYLON_DEMO_DATA=0`
36
+ to start empty in development. Delete both files once you have real subscribers.
37
+
26
38
  ## Privacy
27
39
 
28
40
  The `Subscriber` entity holds reader emails (PII), so its policy in `app.ts`
@@ -44,6 +56,10 @@ Your name, colors, bio, offerings, testimonials, newsletter copy, and links
44
56
  live in **`lib/site.config.ts`**. Edit that file, or generate it, to re-theme
45
57
  the page.
46
58
 
59
+ The tab icon is `app/icon.svg` (with `public/favicon.ico` for browsers that
60
+ request `/favicon.ico`). Both carry this brand's letter and colors; replace
61
+ them when you rename the brand.
62
+
47
63
  ## Layout
48
64
 
49
65
  ```
@@ -51,8 +67,11 @@ app.ts Subscriber + SubscriberCount + User + policies
51
67
  lib/site.config.ts ALL copy + brand + offerings + newsletter (edit this)
52
68
  functions/subscribe.ts public mutation: validate + dedupe + count
53
69
  functions/subscriberStats.ts owner-only query: subscribers + emails
54
- app/page.tsx the landing page (server-rendered)
55
- app/newsletter-signup.tsx client island: signup form + live counter
70
+ functions/seedDemo.ts dev-only demo subscribers (see Demo data)
71
+ lib/stats.ts dashboard types + the public count
72
+ lib/demo.ts demo subscribers + the dev-only gate
73
+ app/(marketing)/page.tsx the landing page (server-rendered)
74
+ app/(marketing)/newsletter-signup.tsx client island: signup form + live counter
56
75
  app/dashboard/ owner dashboard (auth-gated, live)
57
76
  ```
58
77
 
@@ -4,6 +4,7 @@ import React, { useEffect, useRef, useState } from "react";
4
4
  import { db, callFn } from "@pylonsync/react";
5
5
  import { EnsureGuest } from "@pylonsync/client";
6
6
  import type { CreatorConfig } from "@/lib/site.config";
7
+ import { publicCount } from "@/lib/stats";
7
8
 
8
9
  // The newsletter signup — email capture plus a LIVE subscriber counter. This is
9
10
  // the realtime proof: the counter is a live `db.useQuery("SubscriberCount")`
@@ -23,7 +24,11 @@ export function NewsletterSignup({ newsletter }: Props) {
23
24
  <div>
24
25
  <SubscribeForm newsletter={newsletter} />
25
26
  <div className="mt-3">
26
- <LiveCounter seed={newsletter.seedCount ?? 0} label={newsletter.counterLabel} />
27
+ <LiveCounter
28
+ importedCount={newsletter.importedCount}
29
+ label={newsletter.counterLabel}
30
+ labelOne={newsletter.counterLabelOne}
31
+ />
27
32
  </div>
28
33
  </div>
29
34
  );
@@ -100,27 +105,43 @@ interface SubscriberCountRow {
100
105
  count: number;
101
106
  }
102
107
 
103
- function LiveCounter({ seed, label }: { seed: number; label: string }) {
108
+ type CounterProps = { importedCount: number; label: string; labelOne: string };
109
+
110
+ export function LiveCounter(props: CounterProps) {
104
111
  return (
105
- <EnsureGuest fallback={<CounterView value={seed} label={label} />}>
106
- <LiveCounterInner seed={seed} label={label} />
112
+ <EnsureGuest fallback={null}>
113
+ <LiveCounterInner {...props} />
107
114
  </EnsureGuest>
108
115
  );
109
116
  }
110
117
 
111
- function LiveCounterInner({ seed, label }: { seed: number; label: string }) {
118
+ function LiveCounterInner({ importedCount, label, labelOne }: CounterProps) {
112
119
  const { data, loading } = db.useQuery<SubscriberCountRow>("SubscriberCount");
113
- const real = data.length > 0 ? data[0].count : 0;
114
- return <CounterView value={seed + real} label={label} live={!loading} />;
120
+
121
+ // In `pylon dev` an empty list gets demo subscribers (functions/seedDemo.ts).
122
+ // The call goes out only when the synced count is empty, so a live site with
123
+ // subscribers never makes it.
124
+ const empty = !loading && data.length === 0;
125
+ const sent = useRef(false);
126
+ useEffect(() => {
127
+ if (!empty || sent.current) return;
128
+ sent.current = true;
129
+ void callFn("seedDemo", {}).catch(() => {});
130
+ }, [empty]);
131
+
132
+ if (loading) return null;
133
+ const value = publicCount(data, importedCount);
134
+ // A new newsletter has no subscribers yet; show nothing rather than "0".
135
+ if (value === 0) return null;
136
+ return <CounterView value={value} label={value === 1 ? labelOne : label} />;
115
137
  }
116
138
 
117
- // Plain text under the form. The fallback shows the seed until the guest
118
- // session connects; `live` is set once the count is synced.
119
- function CounterView({ value, label, live }: { value: number; label: string; live?: boolean }) {
139
+ // Plain text under the form, shown once the count has synced.
140
+ function CounterView({ value, label }: { value: number; label: string }) {
120
141
  const shown = useCountUp(value);
121
142
  return (
122
- <p className="text-[15px] text-ink-2" data-live={live ? "true" : undefined}>
123
- <span className="tabular-nums text-ink">{shown.toLocaleString()}</span> {label}
143
+ <p className="text-[15px] text-ink-2" data-testid="live-count">
144
+ <span className="tabular-nums text-ink">{shown.toLocaleString("en-US")}</span> {label}
124
145
  </p>
125
146
  );
126
147
  }
@@ -51,7 +51,7 @@ export function AuthForm() {
51
51
  <div className="space-y-5">
52
52
  <form onSubmit={onSubmit} className="space-y-4">
53
53
  <label className="block">
54
- <span className="mb-1.5 block text-[13px] font-medium text-zinc-700">Email</span>
54
+ <span className="mb-1.5 block text-[15px] text-ink-2">Email</span>
55
55
  <input
56
56
  type="email"
57
57
  value={email}
@@ -59,11 +59,11 @@ export function AuthForm() {
59
59
  required
60
60
  autoComplete="email"
61
61
  placeholder="you@yourbusiness.com"
62
- className="h-10 w-full rounded-lg border border-zinc-300 bg-white px-3 text-sm text-zinc-900 outline-none transition placeholder:text-zinc-400 focus:border-brand focus:ring-2 focus:ring-brand/20"
62
+ className="h-11 w-full rounded-md border border-rule bg-white px-3.5 text-[16px] text-ink outline-none transition placeholder:text-ink-2/60 focus:border-brand focus:ring-2 focus:ring-brand/20"
63
63
  />
64
64
  </label>
65
65
  <label className="block">
66
- <span className="mb-1.5 block text-[13px] font-medium text-zinc-700">Password</span>
66
+ <span className="mb-1.5 block text-[15px] text-ink-2">Password</span>
67
67
  <input
68
68
  type="password"
69
69
  value={password}
@@ -71,7 +71,7 @@ export function AuthForm() {
71
71
  required
72
72
  autoComplete={mode === "login" ? "current-password" : "new-password"}
73
73
  placeholder={mode === "login" ? "Your password" : "At least 10 characters"}
74
- className="h-10 w-full rounded-lg border border-zinc-300 bg-white px-3 text-sm text-zinc-900 outline-none transition placeholder:text-zinc-400 focus:border-brand focus:ring-2 focus:ring-brand/20"
74
+ className="h-11 w-full rounded-md border border-rule bg-white px-3.5 text-[16px] text-ink outline-none transition placeholder:text-ink-2/60 focus:border-brand focus:ring-2 focus:ring-brand/20"
75
75
  />
76
76
  </label>
77
77
  {error ? (
@@ -82,13 +82,13 @@ export function AuthForm() {
82
82
  <button
83
83
  type="submit"
84
84
  disabled={pending}
85
- className="inline-flex h-10 w-full items-center justify-center rounded-lg bg-zinc-900 text-sm font-medium text-white transition-colors hover:bg-zinc-700 disabled:opacity-60"
85
+ className="inline-flex h-11 w-full items-center justify-center rounded-md bg-brand text-[16px] font-medium text-white transition-opacity hover:opacity-90 disabled:opacity-60"
86
86
  >
87
87
  {pending ? "…" : mode === "login" ? "Sign in" : "Create account"}
88
88
  </button>
89
89
  </form>
90
90
 
91
- <p className="text-center text-[13px] text-zinc-500">
91
+ <p className="text-center text-[15px] text-ink-2">
92
92
  {mode === "login" ? "First time here?" : "Already have an account?"}{" "}
93
93
  <button
94
94
  type="button"
@@ -96,7 +96,7 @@ export function AuthForm() {
96
96
  setMode(mode === "login" ? "subscriber" : "login");
97
97
  setError(null);
98
98
  }}
99
- className="font-medium text-zinc-900 underline underline-offset-2"
99
+ className="font-medium text-ink underline decoration-brand/50 underline-offset-4"
100
100
  >
101
101
  {mode === "login" ? "Create the owner account" : "Sign in"}
102
102
  </button>