@pylonsync/create-pylon 0.19.0 → 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,17 +1,20 @@
1
1
  import React from "react";
2
- import { Link } from "@pylonsync/react";
3
- import { Button } from "@/components/ui/button";
4
- import { Separator } from "@/components/ui/separator";
2
+ import { Link, type PageProps } from "@pylonsync/react";
3
+ import { Plus, Search } from "lucide-react";
5
4
  import { AuthNav } from "../client/AuthNav";
6
5
  import { ThemeToggle } from "../client/ThemeToggle";
7
6
 
8
7
  // Root layout. Server-rendered shell; Pylon's SSR head adapter injects the
9
- // compiled Tailwind <link> from app/globals.css automatically.
8
+ // compiled Tailwind <link> from app/globals.css and the fonts from app.ts.
10
9
  export default function RootLayout({
11
10
  children,
11
+ searchParams,
12
12
  }: {
13
13
  children: React.ReactNode;
14
- }) {
14
+ } & Partial<Pick<PageProps, "searchParams">>) {
15
+ const query =
16
+ typeof searchParams?.q === "string" ? searchParams.q.trim() : "";
17
+
15
18
  return (
16
19
  <html lang="en" suppressHydrationWarning>
17
20
  <head>
@@ -25,63 +28,105 @@ export default function RootLayout({
25
28
  />
26
29
  <meta
27
30
  name="theme-color"
28
- content="#f8f6f2"
31
+ content="#f5f2ed"
29
32
  media="(prefers-color-scheme: light)"
30
33
  />
31
34
  <meta
32
35
  name="theme-color"
33
- content="#181817"
36
+ content="#191714"
34
37
  media="(prefers-color-scheme: dark)"
35
38
  />
36
- <link rel="preconnect" href="https://images.unsplash.com" />
37
39
  </head>
38
40
  <body className="min-h-screen bg-background text-foreground antialiased">
39
41
  <a
40
42
  href="#main-content"
41
- className="fixed left-4 top-4 z-50 -translate-y-20 rounded-lg bg-foreground px-4 py-2 text-sm font-medium text-background shadow-lg transition-transform focus:translate-y-0"
43
+ className="fixed left-4 top-4 z-50 -translate-y-20 rounded-lg bg-foreground px-4 py-2 text-sm font-medium text-background transition-transform focus:translate-y-0"
42
44
  >
43
45
  Skip to content
44
46
  </a>
45
- <header className="sticky top-0 z-20 h-16 border-b bg-background/85 backdrop-blur-xl">
46
- <div className="mx-auto flex h-full max-w-6xl items-center justify-between gap-3 px-5">
47
+ <header className="sticky top-0 z-30 border-b border-border/70 bg-background/85 backdrop-blur-xl">
48
+ <div className="mx-auto flex h-16 max-w-[1440px] items-center gap-3 px-4 sm:gap-6 sm:px-8">
47
49
  <Link
48
50
  href="/"
49
51
  translate="no"
50
- className="flex min-h-11 items-center gap-2.5 text-sm font-semibold tracking-[-0.01em]"
52
+ className="flex min-h-11 shrink-0 items-center gap-2"
53
+ aria-label="Reprise home"
51
54
  >
52
- <span className="grid size-8 place-items-center rounded-lg bg-foreground text-sm font-semibold text-background shadow-sm">
53
- R
55
+ <span
56
+ aria-hidden="true"
57
+ className="grid size-8 place-items-center rounded-full bg-foreground pb-0.5 font-display text-[22px] leading-none text-background"
58
+ >
59
+ r
60
+ </span>
61
+ <span className="font-display text-[26px] leading-none tracking-[-0.01em]">
62
+ Reprise
54
63
  </span>
55
- Reprise
56
64
  </Link>
65
+
66
+ <form
67
+ method="get"
68
+ action="/"
69
+ role="search"
70
+ className="relative hidden max-w-xl flex-1 md:block"
71
+ >
72
+ <label htmlFor="header-search" className="sr-only">
73
+ Search listings
74
+ </label>
75
+ <Search
76
+ aria-hidden="true"
77
+ strokeWidth={1.75}
78
+ className="pointer-events-none absolute left-3.5 top-1/2 size-4 -translate-y-1/2 text-muted-foreground"
79
+ />
80
+ <input
81
+ id="header-search"
82
+ name="q"
83
+ type="search"
84
+ autoComplete="off"
85
+ defaultValue={query}
86
+ placeholder="Search chairs, cameras, sellers, cities"
87
+ className="h-10 w-full rounded-full border-0 bg-muted pl-10 pr-4 text-sm outline-none ring-1 ring-transparent transition-[box-shadow,background-color] duration-200 placeholder:text-muted-foreground focus:bg-card focus:ring-border focus-visible:outline-none"
88
+ />
89
+ </form>
90
+
57
91
  <nav
58
92
  aria-label="Primary navigation"
59
- className="flex items-center gap-0.5 text-sm sm:gap-1"
93
+ className="ml-auto flex items-center gap-1 text-sm"
60
94
  >
61
- <Button asChild variant="ghost" size="sm" className="hidden sm:inline-flex">
62
- <Link href="/">Browse</Link>
63
- </Button>
64
- <Button asChild variant="ghost" size="sm">
65
- <Link href="/sell">Sell</Link>
66
- </Button>
67
- <Button asChild variant="ghost" size="sm" className="hidden md:inline-flex">
68
- <Link href="/me">Dashboard</Link>
69
- </Button>
95
+ <Link
96
+ href="/me"
97
+ className="hidden min-h-10 items-center rounded-full px-3 font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground sm:inline-flex"
98
+ >
99
+ Dashboard
100
+ </Link>
70
101
  <ThemeToggle />
71
102
  <AuthNav />
103
+ <Link
104
+ href="/sell"
105
+ className="ml-1 inline-flex min-h-10 items-center gap-1.5 rounded-full bg-primary pl-3 pr-4 text-sm font-medium text-primary-foreground transition-[background-color,scale] duration-150 hover:bg-primary/85 active:scale-[0.97]"
106
+ >
107
+ <Plus aria-hidden="true" className="size-4" strokeWidth={2} />
108
+ Sell
109
+ </Link>
72
110
  </nav>
73
111
  </div>
74
112
  </header>
75
113
  <main
76
114
  id="main-content"
77
- className="mx-auto min-h-[calc(100dvh-8rem)] max-w-6xl px-5 py-6 sm:py-8"
115
+ className="mx-auto min-h-[calc(100dvh-8rem)] max-w-[1440px] px-4 sm:px-8"
78
116
  >
79
117
  {children}
80
118
  </main>
81
- <Separator />
82
- <footer className="px-5 py-7 text-center text-xs text-muted-foreground">
83
- Reprise, built with Pylon. Server-rendered listings and realtime offers
84
- from one binary.
119
+ <footer className="mt-16 border-t border-border/70">
120
+ <div className="mx-auto flex max-w-[1440px] flex-col gap-2 px-4 py-8 text-sm text-muted-foreground sm:flex-row sm:items-center sm:justify-between sm:px-8">
121
+ <p>
122
+ <span className="font-display text-lg text-foreground">Reprise</span>{" "}
123
+ · Pre-owned goods from independent sellers
124
+ </p>
125
+ <p className="text-xs">
126
+ Built with Pylon. Listings are server-rendered; offers and sold
127
+ status sync live.
128
+ </p>
129
+ </div>
85
130
  </footer>
86
131
  </body>
87
132
  </html>
@@ -8,32 +8,27 @@ import {
8
8
  type ServerData,
9
9
  type SsrResponse,
10
10
  } from "@pylonsync/react";
11
- import { Button } from "@/components/ui/button";
12
- import { Card } from "@/components/ui/card";
13
- import {
14
- Empty,
15
- EmptyContent,
16
- EmptyDescription,
17
- EmptyHeader,
18
- EmptyTitle,
19
- } from "@/components/ui/empty";
20
- import { Separator } from "@/components/ui/separator";
21
- import { Skeleton } from "@/components/ui/skeleton";
11
+ import { ChevronRight, MapPin } from "lucide-react";
22
12
  import { OfferPanel } from "../../../client/OfferPanel";
23
13
  import { CategoryIcon } from "../../_components/CategoryIcon";
24
14
  import { WatchButton } from "../../../client/WatchButton";
25
15
  import { LiveListingStatus } from "../../../client/LiveListingStatus";
16
+ import { ListingCard } from "../../../client/ListingCard";
26
17
  import {
18
+ avatarColor,
19
+ conditionLabel,
27
20
  gradient,
21
+ initials,
28
22
  money,
29
- conditionLabel,
23
+ timeAgo,
30
24
  type Listing,
31
25
  type Offer,
32
26
  } from "../../../client/market";
27
+ import { categoryLabel, listingSrcSet } from "../../../lib/catalog";
33
28
 
34
29
  // Resolve a listing from the URL segment, which is its slug
35
- // ("herman-miller-aeron-a1f3"). Falls back to a raw id lookup so older
36
- // id-shaped links keep working.
30
+ // ("danish-teak-lounge-chair-oatmeal-wool-a1f3"). Falls back to a raw id
31
+ // lookup so id-shaped links keep working.
37
32
  async function resolveListing(
38
33
  serverData: ServerData,
39
34
  key: string,
@@ -44,17 +39,13 @@ async function resolveListing(
44
39
  );
45
40
  }
46
41
 
47
- // The listing page is anonymous + public (the watch button + offer panel are
48
- // client islands with their own auth), so its SSR output is shared across
49
- // visitors — an ISR candidate. `revalidate` serves it from cache, emits
50
- // stale-while-revalidate, and makes <Link>'s prefetch reusable so a click hits
51
- // cache instead of a live render. Short TTL because a listing's sold status is
52
- // time-sensitive; the realtime offer panel keeps the live bits fresh regardless.
42
+ // The listing page is anonymous + public (the watch button and offer panel
43
+ // are client islands with their own auth), so its SSR output is shared across
44
+ // visitors. `revalidate` serves it from cache with stale-while-revalidate.
45
+ // The TTL is short because sold status is time-sensitive; the live islands
46
+ // keep offers and status current regardless.
53
47
  export const revalidate = 60;
54
48
 
55
- // Data-driven SEO: the title + description come from the listing itself,
56
- // fetched on the server. `generateMetadata` is handed the same PageProps as
57
- // the page (params + serverData), so it reads the row directly.
58
49
  export const generateMetadata: GenerateMetadata = async ({
59
50
  params,
60
51
  serverData,
@@ -79,9 +70,8 @@ function Detail({
79
70
  id: string;
80
71
  }) {
81
72
  // Listing cards seed this route with the row they already rendered.
82
- // useRouteData paints that real content immediately, resets scroll at the
83
- // start of navigation, then upgrades it to the authoritative server row in
84
- // place. Direct loads still suspend for SSR as normal.
73
+ // useRouteData paints that row immediately, then upgrades it to the
74
+ // server row in place. Direct loads suspend for SSR as normal.
85
75
  const listing = useRouteData<Listing | null>(
86
76
  () => resolveListing(serverData, id),
87
77
  [serverData, id],
@@ -90,108 +80,137 @@ function Detail({
90
80
  if (!listing) {
91
81
  response.setStatus(404);
92
82
  return (
93
- <Empty className="mx-auto min-h-[60vh] max-w-xl border-0">
94
- <EmptyHeader>
95
- <p className="text-sm font-medium text-muted-foreground">Unavailable</p>
96
- <EmptyTitle className="text-3xl tracking-[-0.03em]">
97
- This listing is no longer available
98
- </EmptyTitle>
99
- <EmptyDescription className="max-w-md">
100
- It may have sold or been removed by the seller. Browse the latest
101
- finds to discover something similar.
102
- </EmptyDescription>
103
- </EmptyHeader>
104
- <EmptyContent>
105
- <Button asChild size="lg">
106
- <Link href="/">Browse latest finds</Link>
107
- </Button>
108
- </EmptyContent>
109
- </Empty>
83
+ <div className="mx-auto flex min-h-[60vh] max-w-xl flex-col items-center justify-center text-center">
84
+ <h1 className="font-display text-5xl">This listing is gone</h1>
85
+ <p className="mt-3 text-muted-foreground">
86
+ The seller removed it, or the link is wrong.
87
+ </p>
88
+ <Link
89
+ href="/"
90
+ className="mt-6 inline-flex min-h-11 items-center rounded-full bg-primary px-5 text-sm font-medium text-primary-foreground"
91
+ >
92
+ Browse listings
93
+ </Link>
94
+ </div>
110
95
  );
111
96
  }
112
97
 
98
+ const facts: Array<[string, string]> = [
99
+ ["Condition", conditionLabel(listing.condition)],
100
+ ["Category", categoryLabel(listing.category)],
101
+ ["Location", listing.location || "Not given"],
102
+ ["Listed", timeAgo(listing.createdAt)],
103
+ ];
104
+
113
105
  return (
114
- <div className="flex flex-col gap-6 pb-10">
115
- <Link
116
- href="/"
117
- className="inline-flex min-h-10 items-center text-sm text-muted-foreground transition-colors hover:text-foreground"
118
- >
119
- ← Back to browse
120
- </Link>
106
+ <div className="pb-6">
107
+ <nav aria-label="Breadcrumb" className="py-4 text-[13px] text-muted-foreground">
108
+ <ol className="flex min-w-0 items-center gap-1.5 whitespace-nowrap">
109
+ <li>
110
+ <Link href="/" className="hover:text-foreground">
111
+ All listings
112
+ </Link>
113
+ </li>
114
+ <ChevronRight aria-hidden="true" className="size-3.5" />
115
+ <li>
116
+ <a
117
+ href={`/?category=${listing.category}`}
118
+ className="hover:text-foreground"
119
+ >
120
+ {categoryLabel(listing.category)}
121
+ </a>
122
+ </li>
123
+ <ChevronRight aria-hidden="true" className="size-3.5" />
124
+ <li className="min-w-0 truncate text-foreground" aria-current="page">
125
+ {listing.title}
126
+ </li>
127
+ </ol>
128
+ </nav>
121
129
 
122
- <div className="grid gap-8 lg:grid-cols-[minmax(0,1.16fr)_minmax(360px,.84fr)] lg:gap-12">
123
- <div className="relative aspect-[4/5] overflow-hidden rounded-[24px] bg-muted shadow-[var(--shadow-border)] sm:aspect-[6/5] lg:aspect-[4/5]">
124
- {listing.imageUrl ? (
125
- <img
126
- src={listing.imageUrl}
127
- alt={listing.title}
128
- width="1200"
129
- height="1500"
130
- fetchPriority="high"
131
- decoding="async"
132
- className="h-full w-full object-cover outline outline-1 -outline-offset-1 outline-border"
130
+ <div className="grid gap-8 lg:grid-cols-[minmax(0,560px)_minmax(0,1fr)] lg:gap-12 xl:gap-16">
131
+ <div className="lg:sticky lg:top-20 lg:self-start">
132
+ <div className="relative aspect-[4/5] overflow-hidden rounded-2xl bg-muted">
133
+ {listing.imageUrl ? (
134
+ <img
135
+ src={listing.imageUrl}
136
+ srcSet={listingSrcSet(listing.imageUrl)}
137
+ sizes="(min-width: 1024px) 560px, 100vw"
138
+ alt={listing.title}
139
+ width="1120"
140
+ height="1400"
141
+ fetchPriority="high"
142
+ decoding="async"
143
+ className="size-full object-cover"
144
+ />
145
+ ) : (
146
+ <div
147
+ className="flex size-full items-center justify-center text-white/85"
148
+ style={{ background: gradient(listing.seed || listing.id) }}
149
+ >
150
+ <CategoryIcon category={listing.category} className="size-24" />
151
+ </div>
152
+ )}
153
+ <span
154
+ aria-hidden="true"
155
+ className="pointer-events-none absolute inset-0 rounded-2xl ring-1 ring-inset ring-black/5"
133
156
  />
134
- ) : (
135
- <div
136
- className="flex h-full w-full items-center justify-center text-white/90"
137
- style={{ background: gradient(listing.seed || listing.id) }}
138
- >
139
- <CategoryIcon category={listing.category} className="size-28" />
140
- </div>
141
- )}
142
- <WatchButton
143
- listingId={listing.id}
144
- listingTitle={listing.title}
145
- className="absolute right-4 top-4"
146
- />
147
- <LiveListingStatus
148
- listingId={listing.id}
149
- initialStatus={listing.status}
150
- mode="overlay"
151
- />
157
+ <WatchButton
158
+ listingId={listing.id}
159
+ listingTitle={listing.title}
160
+ className="absolute right-4 top-4 size-10"
161
+ />
162
+ <LiveListingStatus
163
+ listingId={listing.id}
164
+ initialStatus={listing.status}
165
+ mode="overlay"
166
+ />
167
+ </div>
152
168
  </div>
153
169
 
154
- <div className="flex min-w-0 flex-col">
155
- <div>
156
- <p className="text-sm capitalize text-muted-foreground">
157
- {listing.category} / {conditionLabel(listing.condition)}
158
- </p>
159
- <h1 className="mt-2 text-balance text-3xl font-semibold leading-tight tracking-[-0.035em] sm:text-4xl">
160
- {listing.title}
161
- </h1>
162
- <p className="mt-3 text-4xl font-semibold tracking-[-0.03em] tabular-nums">
170
+ <div className="flex min-w-0 max-w-[660px] flex-col">
171
+ <h1 className="font-display text-[38px] leading-[1.04] tracking-[-0.01em] sm:text-[46px]">
172
+ {listing.title}
173
+ </h1>
174
+ <div className="mt-4 flex flex-wrap items-center gap-3">
175
+ <p className="text-[30px] font-semibold leading-none tabular-nums tracking-[-0.02em]">
163
176
  {money(listing.price)}
164
177
  </p>
165
- <p className="mt-2 text-sm text-muted-foreground">
166
- Listed by{" "}
167
- <span className="font-medium text-foreground">{listing.sellerName}</span>
168
- </p>
178
+ <LiveListingStatus
179
+ listingId={listing.id}
180
+ initialStatus={listing.status}
181
+ mode="pill"
182
+ />
169
183
  </div>
184
+ <p className="mt-3 flex flex-wrap items-center gap-x-2 text-sm text-muted-foreground">
185
+ <span>{conditionLabel(listing.condition)}</span>
186
+ <span aria-hidden="true">·</span>
187
+ {listing.location ? (
188
+ <>
189
+ <span className="inline-flex items-center gap-1">
190
+ <MapPin aria-hidden="true" className="size-3.5" strokeWidth={1.75} />
191
+ {listing.location}
192
+ </span>
193
+ <span aria-hidden="true">·</span>
194
+ </>
195
+ ) : null}
196
+ <span suppressHydrationWarning>Listed {timeAgo(listing.createdAt)}</span>
197
+ </p>
170
198
 
171
- <Separator className="my-6" />
172
-
173
- <section>
174
- <h2 className="text-sm font-medium">About this item</h2>
175
- <p className="mt-2 whitespace-pre-wrap text-pretty text-sm leading-6 text-muted-foreground">
176
- {listing.description || "The seller has not added a description yet."}
177
- </p>
178
- </section>
179
-
180
- <Card className="my-6 grid grid-cols-2 gap-px overflow-hidden rounded-xl bg-border">
181
- <div className="bg-card p-4">
182
- <p className="text-xs text-muted-foreground">Condition</p>
183
- <p className="mt-1 text-sm font-medium">{conditionLabel(listing.condition)}</p>
184
- </div>
185
- <div className="bg-card p-4">
186
- <p className="text-xs text-muted-foreground">Offer status</p>
187
- <p className="mt-1 text-sm font-medium">
188
- <LiveListingStatus
189
- listingId={listing.id}
190
- initialStatus={listing.status}
191
- />
199
+ <div className="mt-6 flex items-center gap-3 rounded-2xl bg-card p-3 shadow-[var(--shadow-border)]">
200
+ <span
201
+ aria-hidden="true"
202
+ className="grid size-11 shrink-0 place-items-center rounded-full text-sm font-semibold text-white"
203
+ style={{ background: avatarColor(listing.sellerName) }}
204
+ >
205
+ {initials(listing.sellerName)}
206
+ </span>
207
+ <div className="min-w-0">
208
+ <p className="truncate text-sm font-medium">{listing.sellerName}</p>
209
+ <p className="truncate text-[13px] text-muted-foreground">
210
+ Seller{listing.location ? ` in ${listing.location}` : ""}
192
211
  </p>
193
212
  </div>
194
- </Card>
213
+ </div>
195
214
 
196
215
  <div className="mt-6">
197
216
  <Suspense fallback={<ListingOffers listing={listing} />}>
@@ -199,12 +218,34 @@ function Detail({
199
218
  </Suspense>
200
219
  </div>
201
220
 
202
- <p className="mt-4 text-pretty text-xs leading-5 text-muted-foreground">
203
- Reprise keeps offers and listing status in sync. Confirm payment and
204
- delivery details with the seller before completing a transaction.
221
+ <section className="mt-10">
222
+ <h2 className="text-base font-semibold">Description</h2>
223
+ <p className="mt-2 whitespace-pre-wrap text-[15px] leading-7 text-foreground/80">
224
+ {listing.description || "The seller has not added a description."}
225
+ </p>
226
+ </section>
227
+
228
+ <dl className="mt-6 grid grid-cols-2 gap-px overflow-hidden rounded-2xl bg-border shadow-[var(--shadow-border)]">
229
+ {facts.map(([label, value]) => (
230
+ <div key={label} className="bg-card px-4 py-3">
231
+ <dt className="text-xs text-muted-foreground">{label}</dt>
232
+ <dd className="mt-0.5 text-sm font-medium" suppressHydrationWarning>
233
+ {value}
234
+ </dd>
235
+ </div>
236
+ ))}
237
+ </dl>
238
+
239
+ <p className="mt-6 text-xs leading-5 text-muted-foreground">
240
+ Offers and sold status sync live. Arrange payment and pickup
241
+ directly with the seller.
205
242
  </p>
206
243
  </div>
207
244
  </div>
245
+
246
+ <Suspense fallback={null}>
247
+ <MoreListings serverData={serverData} listing={listing} />
248
+ </Suspense>
208
249
  </div>
209
250
  );
210
251
  }
@@ -242,6 +283,52 @@ function LoadedListingOffers({
242
283
  return <ListingOffers listing={listing} initialOffers={initialOffers} />;
243
284
  }
244
285
 
286
+ // Four more active listings: same category first, then the newest others.
287
+ function MoreListings({
288
+ serverData,
289
+ listing,
290
+ }: {
291
+ serverData: ServerData;
292
+ listing: Listing;
293
+ }) {
294
+ const active = use(
295
+ serverData.query<Listing>("Listing", { status: "active" }),
296
+ );
297
+ const others = active
298
+ .filter((l) => l.id !== listing.id)
299
+ .sort((a, b) => {
300
+ const sameA = a.category === listing.category ? 0 : 1;
301
+ const sameB = b.category === listing.category ? 0 : 1;
302
+ return sameA - sameB || b.createdAt.localeCompare(a.createdAt);
303
+ })
304
+ .slice(0, 5);
305
+ if (others.length === 0) return null;
306
+
307
+ return (
308
+ <section className="mt-16 border-t border-border/70 pt-8">
309
+ <div className="flex items-end justify-between gap-4">
310
+ <h2 className="font-display text-3xl">More to look at</h2>
311
+ <Link
312
+ href="/"
313
+ className="text-sm font-medium text-muted-foreground hover:text-foreground"
314
+ >
315
+ All listings
316
+ </Link>
317
+ </div>
318
+ <div className="mt-5 grid grid-cols-2 gap-x-3 gap-y-6 sm:gap-x-4 md:grid-cols-3 lg:grid-cols-5">
319
+ {others.map((l, index) => (
320
+ <ListingCard
321
+ key={l.id}
322
+ listing={l}
323
+ sizes="(min-width: 1024px) 18vw, 50vw"
324
+ className={index === 4 ? "hidden lg:block" : undefined}
325
+ />
326
+ ))}
327
+ </div>
328
+ </section>
329
+ );
330
+ }
331
+
245
332
  export default function ListingPage({
246
333
  params,
247
334
  serverData,
@@ -250,12 +337,12 @@ export default function ListingPage({
250
337
  return (
251
338
  <Suspense
252
339
  fallback={
253
- <div className="grid gap-8 md:grid-cols-2">
254
- <Skeleton className="aspect-[4/5] rounded-[24px]" />
255
- <div className="flex flex-col gap-3">
256
- <Skeleton className="h-6 w-2/3" />
257
- <Skeleton className="h-8 w-1/3" />
258
- <Skeleton className="h-24" />
340
+ <div className="grid gap-10 pt-14 lg:grid-cols-[580px_1fr]">
341
+ <div className="aspect-[4/5] rounded-2xl bg-muted" />
342
+ <div className="flex flex-col gap-4">
343
+ <div className="h-12 w-3/4 rounded-lg bg-muted" />
344
+ <div className="h-8 w-1/4 rounded-lg bg-muted" />
345
+ <div className="h-40 rounded-2xl bg-muted" />
259
346
  </div>
260
347
  </div>
261
348
  }
@@ -3,13 +3,13 @@ import { type Metadata } from "@pylonsync/react";
3
3
  import { MyMarket } from "../../client/MyMarket";
4
4
 
5
5
  export const metadata: Metadata = {
6
- title: "Dashboard | Reprise",
7
- description: "Your listings, saved finds, and offers.",
6
+ title: "Your market | Reprise",
7
+ description: "Your listings, offers, and saved items.",
8
8
  robots: "noindex", // personal dashboard; keep it out of search
9
9
  };
10
10
 
11
- // Fully interactive dashboard (three live queries scoped to you), so the
12
- // whole page is the client island.
11
+ // The dashboard is three live queries scoped to the signed-in user, so the
12
+ // whole page is one client island.
13
13
  export default function MePage() {
14
14
  return <MyMarket />;
15
15
  }