@pylonsync/create-pylon 0.19.1 → 0.21.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 (696) hide show
  1. package/bin/create-pylon.js +30 -7
  2. package/package.json +1 -1
  3. package/templates/_root/AGENTS.md +1 -1
  4. package/templates/agency/.env.example +7 -0
  5. package/templates/agency/AGENTS.md +1 -1
  6. package/templates/agency/README.md +28 -3
  7. package/templates/agency/app/(marketing)/contact-form.tsx +20 -18
  8. package/templates/agency/app/(marketing)/page.tsx +3 -3
  9. package/templates/agency/app/(marketing)/work/page.tsx +3 -3
  10. package/templates/agency/app/auth-form.tsx +4 -4
  11. package/templates/agency/app/dashboard/dashboard-client.tsx +110 -64
  12. package/templates/agency/app/dashboard/page.tsx +14 -16
  13. package/templates/agency/app/icon.svg +3 -0
  14. package/templates/agency/app/login/page.tsx +12 -14
  15. package/templates/agency/components/marketing.tsx +12 -5
  16. package/templates/agency/functions/seedStudioBackoffice.ts +42 -11
  17. package/templates/agency/lib/agency.ts +22 -0
  18. package/templates/agency/lib/demo.ts +118 -0
  19. package/templates/agency/lib/site.config.ts +19 -13
  20. package/templates/agency/public/favicon.ico +0 -0
  21. package/templates/agency/tests/agency.test.ts +57 -0
  22. package/templates/ai-chat/.env.example +13 -27
  23. package/templates/ai-chat/AGENTS.md +1 -1
  24. package/templates/ai-chat/README.md +53 -60
  25. package/templates/ai-chat/app/(chat)/c/[id]/page.tsx +19 -0
  26. package/templates/ai-chat/app/(chat)/chat-client.tsx +657 -622
  27. package/templates/ai-chat/app/(chat)/layout.tsx +6 -43
  28. package/templates/ai-chat/app/(chat)/not-found.tsx +6 -10
  29. package/templates/ai-chat/app/(chat)/page.tsx +7 -11
  30. package/templates/ai-chat/app/auth-form.tsx +45 -38
  31. package/templates/ai-chat/app/error.tsx +9 -12
  32. package/templates/ai-chat/app/globals.css +464 -102
  33. package/templates/ai-chat/app/layout.tsx +11 -19
  34. package/templates/ai-chat/app/login/page.tsx +39 -24
  35. package/templates/ai-chat/app.ts +118 -43
  36. package/templates/ai-chat/components/chat/composer.tsx +193 -0
  37. package/templates/ai-chat/components/chat/empty-state.tsx +65 -0
  38. package/templates/ai-chat/components/chat/icons.tsx +198 -0
  39. package/templates/ai-chat/components/chat/markdown.tsx +164 -0
  40. package/templates/ai-chat/components/chat/message.tsx +183 -0
  41. package/templates/ai-chat/components/chat/setup.tsx +71 -0
  42. package/templates/ai-chat/components/chat/sidebar.tsx +288 -0
  43. package/templates/ai-chat/functions/_beginTurn.ts +145 -0
  44. package/templates/ai-chat/functions/_finishTurn.ts +55 -0
  45. package/templates/ai-chat/functions/assistantStatus.ts +13 -0
  46. package/templates/ai-chat/functions/claimGuestHistory.ts +39 -0
  47. package/templates/ai-chat/functions/createConversation.ts +28 -0
  48. package/templates/ai-chat/functions/deleteConversation.ts +15 -20
  49. package/templates/ai-chat/functions/prepareGuestClaim.ts +32 -0
  50. package/templates/ai-chat/functions/renameConversation.ts +19 -0
  51. package/templates/ai-chat/functions/respond.ts +88 -0
  52. package/templates/ai-chat/functions/seedExamples.ts +46 -0
  53. package/templates/ai-chat/functions/stopResponse.ts +30 -0
  54. package/templates/ai-chat/lib/brand-icon.ts +7 -0
  55. package/templates/ai-chat/lib/chat.ts +277 -0
  56. package/templates/ai-chat/lib/claim.ts +15 -0
  57. package/templates/ai-chat/lib/examples.ts +179 -0
  58. package/templates/ai-chat/lib/highlight.ts +107 -0
  59. package/templates/ai-chat/lib/markdown.ts +317 -0
  60. package/templates/ai-chat/lib/provider.ts +38 -0
  61. package/templates/ai-chat/lib/site.config.ts +55 -39
  62. package/templates/ai-chat/tests/chat.test.ts +174 -0
  63. package/templates/ai-chat/tests/components.test.tsx +57 -0
  64. package/templates/ai-chat/tests/markdown.test.ts +88 -0
  65. package/templates/ai-chat/tests/provider.test.ts +32 -0
  66. package/templates/ai-studio/AGENTS.md +1 -1
  67. package/templates/backend/consumer/apps/api/app/layout.tsx +33 -0
  68. package/templates/backend/consumer/apps/api/app/page.tsx +54 -0
  69. package/templates/backend/consumer/apps/api/app.ts +166 -0
  70. package/templates/backend/consumer/apps/api/functions/addComment.ts +24 -0
  71. package/templates/backend/consumer/apps/api/functions/createPost.ts +19 -36
  72. package/templates/backend/consumer/apps/api/functions/deletePost.ts +15 -13
  73. package/templates/backend/consumer/apps/api/functions/myProfile.ts +5 -8
  74. package/templates/backend/consumer/apps/api/functions/seedDemo.ts +95 -0
  75. package/templates/backend/consumer/apps/api/functions/setFollow.ts +36 -0
  76. package/templates/backend/consumer/apps/api/functions/setLike.ts +36 -0
  77. package/templates/backend/consumer/apps/api/functions/upsertProfile.ts +43 -37
  78. package/templates/backend/consumer/apps/api/lib/seed.ts +89 -0
  79. package/templates/backend/consumer/apps/api/lib/social.ts +50 -0
  80. package/templates/backend/consumer/apps/api/package.json +8 -2
  81. package/templates/backend/consumer/apps/api/public/images/posts/arch.jpg +0 -0
  82. package/templates/backend/consumer/apps/api/public/images/posts/coffee.jpg +0 -0
  83. package/templates/backend/consumer/apps/api/public/images/posts/dog.jpg +0 -0
  84. package/templates/backend/consumer/apps/api/public/images/posts/lisbon.jpg +0 -0
  85. package/templates/backend/consumer/apps/api/public/images/posts/ramen.jpg +0 -0
  86. package/templates/backend/consumer/apps/api/public/images/posts/run.jpg +0 -0
  87. package/templates/backend/consumer/apps/api/public/images/posts/sunset.jpg +0 -0
  88. package/templates/backend/consumer/apps/api/tsconfig.json +12 -2
  89. package/templates/barebones/AGENTS.md +1 -1
  90. package/templates/chat/AGENTS.md +1 -1
  91. package/templates/chat/README.md +43 -21
  92. package/templates/chat/app/chat-client.tsx +495 -85
  93. package/templates/chat/app/error.tsx +1 -1
  94. package/templates/chat/app/globals.css +170 -54
  95. package/templates/chat/app/layout.tsx +12 -9
  96. package/templates/chat/app/not-found.tsx +4 -2
  97. package/templates/chat/app/page.tsx +9 -19
  98. package/templates/chat/app.ts +96 -17
  99. package/templates/chat/components/chat/avatar.tsx +45 -0
  100. package/templates/chat/components/chat/composer.tsx +110 -0
  101. package/templates/chat/components/chat/message-list.tsx +285 -0
  102. package/templates/chat/components/chat/sidebar.tsx +190 -0
  103. package/templates/chat/functions/joinChat.ts +83 -0
  104. package/templates/chat/functions/renameMember.ts +25 -0
  105. package/templates/chat/lib/chat.ts +188 -0
  106. package/templates/chat/lib/seed.ts +78 -0
  107. package/templates/chat/tests/chat.test.ts +159 -0
  108. package/templates/chat/tests/composer.test.tsx +54 -0
  109. package/templates/consumer/AGENTS.md +1 -1
  110. package/templates/consumer/README.md +3 -3
  111. package/templates/consumer/app/globals.css +10 -3
  112. package/templates/consumer/app/icon.svg +1 -0
  113. package/templates/consumer/components/social/avatar.tsx +25 -11
  114. package/templates/consumer/functions/seedFeed.ts +3 -3
  115. package/templates/consumer/lib/seed.ts +43 -85
  116. package/templates/consumer/public/favicon.ico +0 -0
  117. package/templates/consumer/public/images/posts/arch.jpg +0 -0
  118. package/templates/consumer/public/images/posts/coffee.jpg +0 -0
  119. package/templates/consumer/public/images/posts/dog.jpg +0 -0
  120. package/templates/consumer/public/images/posts/lisbon.jpg +0 -0
  121. package/templates/consumer/public/images/posts/ramen.jpg +0 -0
  122. package/templates/consumer/public/images/posts/run.jpg +0 -0
  123. package/templates/consumer/public/images/posts/sunset.jpg +0 -0
  124. package/templates/consumer/tests/seed.test.ts +39 -0
  125. package/templates/creator/.env.example +7 -0
  126. package/templates/creator/AGENTS.md +1 -1
  127. package/templates/creator/README.md +24 -5
  128. package/templates/creator/app/(marketing)/newsletter-signup.tsx +33 -12
  129. package/templates/creator/app/auth-form.tsx +7 -7
  130. package/templates/creator/app/dashboard/dashboard-client.tsx +137 -100
  131. package/templates/creator/app/dashboard/page.tsx +18 -18
  132. package/templates/creator/app/icon.svg +2 -0
  133. package/templates/creator/app/login/page.tsx +14 -14
  134. package/templates/creator/app.ts +4 -4
  135. package/templates/creator/functions/seedDemo.ts +32 -0
  136. package/templates/creator/functions/subscribe.ts +4 -15
  137. package/templates/creator/lib/demo.ts +94 -0
  138. package/templates/creator/lib/site.config.ts +15 -10
  139. package/templates/creator/lib/stats.ts +35 -0
  140. package/templates/creator/public/favicon.ico +0 -0
  141. package/templates/creator/tests/counter.test.ts +92 -0
  142. package/templates/creator/tests/live-count.test.tsx +45 -0
  143. package/templates/crm/AGENTS.md +1 -1
  144. package/templates/crm/README.md +22 -1
  145. package/templates/crm/app/apple-icon.png +0 -0
  146. package/templates/crm/app/companies/companies-view.tsx +32 -14
  147. package/templates/crm/app/companies/page.tsx +2 -1
  148. package/templates/crm/app/contacts/contacts-view.tsx +34 -10
  149. package/templates/crm/app/contacts/page.tsx +2 -1
  150. package/templates/crm/app/deals/[id]/deal-view.tsx +137 -98
  151. package/templates/crm/app/deals/[id]/page.tsx +2 -1
  152. package/templates/crm/app/globals.css +29 -14
  153. package/templates/crm/app/icon.svg +1 -0
  154. package/templates/crm/app/layout.tsx +7 -5
  155. package/templates/crm/app/page.tsx +2 -1
  156. package/templates/crm/app/pipeline-view.tsx +5 -5
  157. package/templates/crm/app/workspace.tsx +29 -17
  158. package/templates/crm/app.ts +5 -5
  159. package/templates/crm/components/activity-timeline.tsx +14 -4
  160. package/templates/crm/components/app-shell.tsx +94 -0
  161. package/templates/crm/components/auth-form.tsx +35 -5
  162. package/templates/crm/components/avatar.tsx +5 -1
  163. package/templates/crm/components/board-skeleton.tsx +5 -5
  164. package/templates/crm/components/brand-mark.tsx +25 -0
  165. package/templates/crm/components/command-palette.tsx +17 -17
  166. package/templates/crm/components/data-table.tsx +97 -36
  167. package/templates/crm/components/deal-card.tsx +23 -27
  168. package/templates/crm/components/filter-tabs.tsx +101 -0
  169. package/templates/crm/components/metrics-bar.tsx +6 -6
  170. package/templates/crm/components/nav.tsx +15 -0
  171. package/templates/crm/components/page-header.tsx +43 -7
  172. package/templates/crm/components/pipeline-board.tsx +16 -10
  173. package/templates/crm/components/require-auth.tsx +24 -26
  174. package/templates/crm/components/sidebar.tsx +54 -49
  175. package/templates/crm/components/stage-badge.tsx +4 -2
  176. package/templates/crm/components/ui/button.tsx +5 -4
  177. package/templates/crm/components/ui/dialog.tsx +1 -1
  178. package/templates/crm/components/ui/input.tsx +1 -1
  179. package/templates/crm/components/ui/select.tsx +1 -1
  180. package/templates/crm/components/ui/textarea.tsx +1 -1
  181. package/templates/crm/functions/seedWorkspace.ts +32 -17
  182. package/templates/crm/lib/brand.ts +9 -0
  183. package/templates/crm/lib/demo-team.ts +51 -0
  184. package/templates/crm/lib/pipeline.ts +37 -0
  185. package/templates/crm/lib/search.ts +4 -3
  186. package/templates/crm/lib/seed.ts +53 -8
  187. package/templates/crm/public/favicon.ico +0 -0
  188. package/templates/crm/tests/components.test.tsx +5 -5
  189. package/templates/crm/tests/demo-team.test.ts +18 -0
  190. package/templates/crm/tests/pipeline.test.ts +59 -3
  191. package/templates/directory/.env.example +7 -0
  192. package/templates/directory/AGENTS.md +1 -1
  193. package/templates/directory/README.md +22 -3
  194. package/templates/directory/app/(marketing)/directory-browse.tsx +30 -12
  195. package/templates/directory/app/(marketing)/page.tsx +6 -4
  196. package/templates/directory/app/auth-form.tsx +4 -4
  197. package/templates/directory/app/dashboard/dashboard-client.tsx +177 -90
  198. package/templates/directory/app/dashboard/page.tsx +16 -14
  199. package/templates/directory/app/icon.svg +4 -0
  200. package/templates/directory/app/login/page.tsx +16 -15
  201. package/templates/directory/functions/seedDemo.ts +43 -0
  202. package/templates/directory/lib/demo.ts +145 -0
  203. package/templates/directory/lib/directory.ts +27 -0
  204. package/templates/directory/lib/site.config.ts +21 -16
  205. package/templates/directory/public/favicon.ico +0 -0
  206. package/templates/directory/tests/directory.test.ts +46 -0
  207. package/templates/expo/consumer/apps/expo/App.tsx +360 -288
  208. package/templates/expo/consumer/apps/expo/app.json +9 -1
  209. package/templates/expo/consumer/apps/expo/package.json +2 -1
  210. package/templates/helpdesk/AGENTS.md +1 -1
  211. package/templates/helpdesk/README.md +21 -0
  212. package/templates/helpdesk/app/apple-icon.png +0 -0
  213. package/templates/helpdesk/app/customers/customers-view.tsx +23 -7
  214. package/templates/helpdesk/app/customers/page.tsx +2 -1
  215. package/templates/helpdesk/app/globals.css +29 -14
  216. package/templates/helpdesk/app/icon.svg +1 -0
  217. package/templates/helpdesk/app/inbox-view.tsx +66 -47
  218. package/templates/helpdesk/app/layout.tsx +7 -5
  219. package/templates/helpdesk/app/page.tsx +4 -7
  220. package/templates/helpdesk/app/tickets/[id]/page.tsx +2 -1
  221. package/templates/helpdesk/app/tickets/[id]/ticket-view.tsx +134 -97
  222. package/templates/helpdesk/app/workspace.tsx +33 -22
  223. package/templates/helpdesk/app.ts +2 -2
  224. package/templates/helpdesk/components/app-shell.tsx +94 -0
  225. package/templates/helpdesk/components/auth-form.tsx +35 -5
  226. package/templates/helpdesk/components/avatar.tsx +5 -1
  227. package/templates/helpdesk/components/brand-mark.tsx +28 -0
  228. package/templates/helpdesk/components/command-palette.tsx +17 -17
  229. package/templates/helpdesk/components/data-table.tsx +97 -36
  230. package/templates/helpdesk/components/filter-tabs.tsx +101 -0
  231. package/templates/helpdesk/components/nav.tsx +14 -0
  232. package/templates/helpdesk/components/page-header.tsx +43 -7
  233. package/templates/helpdesk/components/priority-badge.tsx +49 -6
  234. package/templates/helpdesk/components/require-auth.tsx +24 -26
  235. package/templates/helpdesk/components/sidebar.tsx +54 -48
  236. package/templates/helpdesk/components/sla-indicator.tsx +5 -8
  237. package/templates/helpdesk/components/thread.tsx +7 -7
  238. package/templates/helpdesk/components/ticket-list.tsx +79 -19
  239. package/templates/helpdesk/components/ui/button.tsx +5 -4
  240. package/templates/helpdesk/components/ui/dialog.tsx +1 -1
  241. package/templates/helpdesk/components/ui/input.tsx +1 -1
  242. package/templates/helpdesk/components/ui/select.tsx +1 -1
  243. package/templates/helpdesk/components/ui/textarea.tsx +1 -1
  244. package/templates/helpdesk/functions/seedWorkspace.ts +25 -15
  245. package/templates/helpdesk/lib/brand.ts +9 -0
  246. package/templates/helpdesk/lib/demo-team.ts +51 -0
  247. package/templates/helpdesk/lib/search.ts +4 -3
  248. package/templates/helpdesk/lib/seed.ts +43 -2
  249. package/templates/helpdesk/lib/tickets.ts +68 -20
  250. package/templates/helpdesk/public/favicon.ico +0 -0
  251. package/templates/helpdesk/tests/components.test.tsx +10 -0
  252. package/templates/helpdesk/tests/demo-team.test.ts +18 -0
  253. package/templates/helpdesk/tests/tickets.test.ts +70 -0
  254. package/templates/imessage/.env.example +49 -0
  255. package/templates/imessage/AGENTS.md +153 -0
  256. package/templates/imessage/CLAUDE.md +7 -0
  257. package/templates/imessage/README.md +187 -0
  258. package/templates/imessage/app/console.tsx +382 -0
  259. package/templates/imessage/app/contacts/page.tsx +13 -0
  260. package/templates/imessage/app/error.tsx +16 -0
  261. package/templates/imessage/app/gate.tsx +31 -0
  262. package/templates/imessage/app/globals.css +183 -0
  263. package/templates/imessage/app/layout.tsx +17 -0
  264. package/templates/imessage/app/login/login-form.tsx +115 -0
  265. package/templates/imessage/app/login/page.tsx +30 -0
  266. package/templates/imessage/app/not-found.tsx +13 -0
  267. package/templates/imessage/app/page.tsx +14 -0
  268. package/templates/imessage/app/robots.ts +6 -0
  269. package/templates/imessage/app/setup/page.tsx +13 -0
  270. package/templates/imessage/app/sign-out.tsx +20 -0
  271. package/templates/imessage/app.ts +299 -0
  272. package/templates/imessage/bunfig +4 -0
  273. package/templates/imessage/components/avatar.tsx +46 -0
  274. package/templates/imessage/components/contact-panel.tsx +263 -0
  275. package/templates/imessage/components/contacts-view.tsx +172 -0
  276. package/templates/imessage/components/conversation-list.tsx +129 -0
  277. package/templates/imessage/components/nav-rail.tsx +67 -0
  278. package/templates/imessage/components/setup-view.tsx +408 -0
  279. package/templates/imessage/components/thread.tsx +229 -0
  280. package/templates/imessage/components/ui/badge.tsx +37 -0
  281. package/templates/imessage/components/ui/button.tsx +56 -0
  282. package/templates/imessage/components/ui/card.tsx +90 -0
  283. package/templates/imessage/components/ui/dialog.tsx +110 -0
  284. package/templates/imessage/components/ui/input.tsx +30 -0
  285. package/templates/imessage/components/ui/label.tsx +21 -0
  286. package/templates/imessage/components/ui/select.tsx +39 -0
  287. package/templates/imessage/components/ui/table.tsx +124 -0
  288. package/templates/imessage/components/ui/textarea.tsx +24 -0
  289. package/templates/imessage/components.json +20 -0
  290. package/templates/imessage/functions/answerNow.ts +34 -0
  291. package/templates/imessage/functions/assistant.ts +96 -0
  292. package/templates/imessage/functions/beginTurn.ts +101 -0
  293. package/templates/imessage/functions/cancelReminder.ts +13 -0
  294. package/templates/imessage/functions/claimOutbound.ts +44 -0
  295. package/templates/imessage/functions/clearDemo.ts +18 -0
  296. package/templates/imessage/functions/deleteNote.ts +11 -0
  297. package/templates/imessage/functions/deliverOutbound.ts +55 -0
  298. package/templates/imessage/functions/finishTurn.ts +84 -0
  299. package/templates/imessage/functions/fireReminder.ts +42 -0
  300. package/templates/imessage/functions/ingestInbound.ts +22 -0
  301. package/templates/imessage/functions/ownerAccount.ts +13 -0
  302. package/templates/imessage/functions/processTurn.ts +74 -0
  303. package/templates/imessage/functions/relayApply.ts +102 -0
  304. package/templates/imessage/functions/relaySync.ts +63 -0
  305. package/templates/imessage/functions/releaseOutbound.ts +18 -0
  306. package/templates/imessage/functions/resolveTurn.ts +25 -0
  307. package/templates/imessage/functions/saveContact.ts +27 -0
  308. package/templates/imessage/functions/seedDemo.ts +70 -0
  309. package/templates/imessage/functions/sendOwnerMessage.ts +28 -0
  310. package/templates/imessage/functions/sendblueWebhook.ts +49 -0
  311. package/templates/imessage/functions/setContactStatus.ts +17 -0
  312. package/templates/imessage/functions/settleOutbound.ts +35 -0
  313. package/templates/imessage/functions/setupStatus.ts +33 -0
  314. package/templates/imessage/functions/sweep.ts +58 -0
  315. package/templates/imessage/functions/toolCancelReminder.ts +17 -0
  316. package/templates/imessage/functions/toolForgetNote.ts +15 -0
  317. package/templates/imessage/functions/toolListNotes.ts +16 -0
  318. package/templates/imessage/functions/toolListReminders.ts +17 -0
  319. package/templates/imessage/functions/toolSaveNote.ts +22 -0
  320. package/templates/imessage/functions/toolSetReminder.ts +55 -0
  321. package/templates/imessage/functions/updateSettings.ts +48 -0
  322. package/templates/imessage/gitignore +11 -0
  323. package/templates/imessage/lib/agent-call.ts +251 -0
  324. package/templates/imessage/lib/assistant.ts +74 -0
  325. package/templates/imessage/lib/chunk.ts +135 -0
  326. package/templates/imessage/lib/demo.ts +68 -0
  327. package/templates/imessage/lib/format.ts +170 -0
  328. package/templates/imessage/lib/gate.ts +104 -0
  329. package/templates/imessage/lib/handles.ts +67 -0
  330. package/templates/imessage/lib/provider.ts +38 -0
  331. package/templates/imessage/lib/relay-protocol.ts +95 -0
  332. package/templates/imessage/lib/reminders.ts +41 -0
  333. package/templates/imessage/lib/secrets.ts +59 -0
  334. package/templates/imessage/lib/sendblue.ts +173 -0
  335. package/templates/imessage/lib/store.ts +407 -0
  336. package/templates/imessage/lib/transport.ts +135 -0
  337. package/templates/imessage/lib/utils.ts +10 -0
  338. package/templates/imessage/package.json +40 -0
  339. package/templates/imessage/relay/.env.example +14 -0
  340. package/templates/imessage/relay/applescript.ts +70 -0
  341. package/templates/imessage/relay/chatdb.ts +165 -0
  342. package/templates/imessage/relay/client.ts +41 -0
  343. package/templates/imessage/relay/main.ts +137 -0
  344. package/templates/imessage/relay/state.ts +35 -0
  345. package/templates/imessage/tests/agent-call.test.ts +112 -0
  346. package/templates/imessage/tests/applescript.test.ts +88 -0
  347. package/templates/imessage/tests/chatdb.test.ts +139 -0
  348. package/templates/imessage/tests/chunk.test.ts +61 -0
  349. package/templates/imessage/tests/fake-ctx.ts +88 -0
  350. package/templates/imessage/tests/ingest.test.ts +141 -0
  351. package/templates/imessage/tests/lib.test.ts +99 -0
  352. package/templates/imessage/tests/review-fixes.test.ts +138 -0
  353. package/templates/imessage/tests/secrets.test.ts +36 -0
  354. package/templates/imessage/tests/sendblue.test.ts +143 -0
  355. package/templates/imessage/tests/setup.ts +5 -0
  356. package/templates/imessage/tsconfig.json +18 -0
  357. package/templates/inventory/AGENTS.md +1 -1
  358. package/templates/inventory/README.md +21 -0
  359. package/templates/inventory/app/apple-icon.png +0 -0
  360. package/templates/inventory/app/globals.css +29 -14
  361. package/templates/inventory/app/icon.svg +1 -0
  362. package/templates/inventory/app/layout.tsx +7 -5
  363. package/templates/inventory/app/movements/movements-view.tsx +32 -10
  364. package/templates/inventory/app/movements/page.tsx +2 -1
  365. package/templates/inventory/app/page.tsx +4 -6
  366. package/templates/inventory/app/products/[id]/page.tsx +2 -1
  367. package/templates/inventory/app/products/[id]/product-view.tsx +55 -25
  368. package/templates/inventory/app/products-view.tsx +74 -33
  369. package/templates/inventory/app/workspace.tsx +34 -16
  370. package/templates/inventory/app.ts +10 -2
  371. package/templates/inventory/components/app-shell.tsx +94 -0
  372. package/templates/inventory/components/auth-form.tsx +35 -5
  373. package/templates/inventory/components/avatar.tsx +5 -1
  374. package/templates/inventory/components/brand-mark.tsx +25 -0
  375. package/templates/inventory/components/category-tile.tsx +49 -0
  376. package/templates/inventory/components/command-palette.tsx +17 -17
  377. package/templates/inventory/components/data-table.tsx +97 -36
  378. package/templates/inventory/components/filter-tabs.tsx +101 -0
  379. package/templates/inventory/components/nav.tsx +14 -0
  380. package/templates/inventory/components/page-header.tsx +43 -7
  381. package/templates/inventory/components/require-auth.tsx +24 -26
  382. package/templates/inventory/components/sidebar.tsx +54 -48
  383. package/templates/inventory/components/stock-level.tsx +30 -14
  384. package/templates/inventory/components/summary-bar.tsx +8 -15
  385. package/templates/inventory/components/ui/button.tsx +5 -4
  386. package/templates/inventory/components/ui/dialog.tsx +1 -1
  387. package/templates/inventory/components/ui/input.tsx +1 -1
  388. package/templates/inventory/components/ui/select.tsx +1 -1
  389. package/templates/inventory/components/ui/textarea.tsx +1 -1
  390. package/templates/inventory/functions/seedWorkspace.ts +18 -8
  391. package/templates/inventory/lib/brand.ts +9 -0
  392. package/templates/inventory/lib/demo-team.ts +51 -0
  393. package/templates/inventory/lib/search.ts +4 -3
  394. package/templates/inventory/lib/seed.ts +29 -2
  395. package/templates/inventory/lib/stock.ts +32 -0
  396. package/templates/inventory/public/favicon.ico +0 -0
  397. package/templates/inventory/tests/demo-team.test.ts +18 -0
  398. package/templates/inventory/tests/stock.test.ts +29 -0
  399. package/templates/invoices/AGENTS.md +1 -1
  400. package/templates/invoices/README.md +16 -0
  401. package/templates/invoices/app/apple-icon.png +0 -0
  402. package/templates/invoices/app/clients/clients-view.tsx +18 -6
  403. package/templates/invoices/app/clients/page.tsx +2 -1
  404. package/templates/invoices/app/globals.css +29 -14
  405. package/templates/invoices/app/icon.svg +1 -0
  406. package/templates/invoices/app/invoices/[id]/invoice-view.tsx +72 -48
  407. package/templates/invoices/app/invoices/[id]/page.tsx +2 -1
  408. package/templates/invoices/app/invoices-view.tsx +81 -32
  409. package/templates/invoices/app/layout.tsx +7 -5
  410. package/templates/invoices/app/page.tsx +4 -6
  411. package/templates/invoices/app/workspace.tsx +26 -16
  412. package/templates/invoices/app.ts +2 -2
  413. package/templates/invoices/components/app-shell.tsx +94 -0
  414. package/templates/invoices/components/auth-form.tsx +35 -5
  415. package/templates/invoices/components/avatar.tsx +5 -1
  416. package/templates/invoices/components/brand-mark.tsx +26 -0
  417. package/templates/invoices/components/command-palette.tsx +17 -17
  418. package/templates/invoices/components/data-table.tsx +97 -36
  419. package/templates/invoices/components/filter-tabs.tsx +101 -0
  420. package/templates/invoices/components/line-items.tsx +19 -14
  421. package/templates/invoices/components/nav.tsx +14 -0
  422. package/templates/invoices/components/page-header.tsx +43 -7
  423. package/templates/invoices/components/require-auth.tsx +24 -26
  424. package/templates/invoices/components/sidebar.tsx +54 -48
  425. package/templates/invoices/components/status-badge.tsx +7 -7
  426. package/templates/invoices/components/summary-bar.tsx +5 -5
  427. package/templates/invoices/components/ui/button.tsx +5 -4
  428. package/templates/invoices/components/ui/dialog.tsx +1 -1
  429. package/templates/invoices/components/ui/input.tsx +1 -1
  430. package/templates/invoices/components/ui/select.tsx +1 -1
  431. package/templates/invoices/components/ui/textarea.tsx +1 -1
  432. package/templates/invoices/functions/recordPayment.ts +3 -0
  433. package/templates/invoices/lib/billing.ts +40 -0
  434. package/templates/invoices/lib/brand.ts +9 -0
  435. package/templates/invoices/lib/search.ts +4 -3
  436. package/templates/invoices/public/favicon.ico +0 -0
  437. package/templates/invoices/tests/billing.test.ts +27 -0
  438. package/templates/ios/consumer/apps/ios/Package.swift +4 -3
  439. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ActivityView.swift +107 -0
  440. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/AppModel.swift +171 -0
  441. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/AuthView.swift +182 -0
  442. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/CommentsView.swift +136 -0
  443. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ComposeView.swift +152 -0
  444. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ExploreView.swift +117 -0
  445. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/FeedView.swift +175 -159
  446. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/MainTabView.swift +54 -0
  447. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/Media.swift +271 -0
  448. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/Models.swift +101 -4
  449. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/PostCard.swift +245 -0
  450. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ProfileEditorView.swift +208 -0
  451. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ProfileView.swift +183 -0
  452. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/RootView.swift +25 -31
  453. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/SocialStore.swift +285 -0
  454. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/StoryViewer.swift +155 -0
  455. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/Theme.swift +82 -0
  456. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/__APP_NAME_PASCAL__App.swift +4 -47
  457. package/templates/ios/consumer/apps/ios/project.yml +13 -9
  458. package/templates/local-service/.env.example +7 -0
  459. package/templates/local-service/AGENTS.md +1 -1
  460. package/templates/local-service/README.md +26 -2
  461. package/templates/local-service/app/(marketing)/booking-widget.tsx +48 -9
  462. package/templates/local-service/app/(marketing)/page.tsx +66 -42
  463. package/templates/local-service/app/auth-form.tsx +8 -8
  464. package/templates/local-service/app/dashboard/dashboard-client.tsx +119 -92
  465. package/templates/local-service/app/dashboard/page.tsx +14 -14
  466. package/templates/local-service/app/icon.svg +2 -0
  467. package/templates/local-service/app/login/page.tsx +15 -15
  468. package/templates/local-service/functions/seedDemo.ts +49 -0
  469. package/templates/local-service/lib/demo.ts +135 -0
  470. package/templates/local-service/lib/hours.ts +44 -0
  471. package/templates/local-service/lib/site.config.ts +8 -3
  472. package/templates/local-service/lib/slots.ts +3 -0
  473. package/templates/local-service/public/favicon.ico +0 -0
  474. package/templates/local-service/tests/booking.test.ts +104 -0
  475. package/templates/marketplace/AGENTS.md +1 -1
  476. package/templates/marketplace/README.md +23 -15
  477. package/templates/marketplace/app/globals.css +172 -114
  478. package/templates/marketplace/app/layout.tsx +75 -30
  479. package/templates/marketplace/app/listing/[id]/page.tsx +210 -123
  480. package/templates/marketplace/app/me/page.tsx +4 -4
  481. package/templates/marketplace/app/page.tsx +221 -298
  482. package/templates/marketplace/app/sell/page.tsx +8 -11
  483. package/templates/marketplace/app.ts +32 -7
  484. package/templates/marketplace/client/ActivityFeed.tsx +311 -0
  485. package/templates/marketplace/client/AuthNav.tsx +24 -16
  486. package/templates/marketplace/client/ListingCard.tsx +118 -0
  487. package/templates/marketplace/client/LiveGrid.tsx +92 -0
  488. package/templates/marketplace/client/LiveListingStatus.tsx +32 -24
  489. package/templates/marketplace/client/LoginCard.tsx +114 -136
  490. package/templates/marketplace/client/MarketProvider.tsx +3 -5
  491. package/templates/marketplace/client/MyMarket.tsx +371 -185
  492. package/templates/marketplace/client/OfferPanel.tsx +421 -287
  493. package/templates/marketplace/client/SellForm.tsx +271 -192
  494. package/templates/marketplace/client/ThemeToggle.tsx +1 -0
  495. package/templates/marketplace/client/WatchButton.tsx +16 -16
  496. package/templates/marketplace/client/market.ts +61 -14
  497. package/templates/marketplace/functions/seedMarket.ts +143 -36
  498. package/templates/marketplace/functions/seedOffers.ts +101 -0
  499. package/templates/marketplace/lib/catalog.ts +72 -1
  500. package/templates/marketplace/public/images/listings/ceramic-lamp-640.webp +0 -0
  501. package/templates/marketplace/public/images/listings/ceramic-lamp.webp +0 -0
  502. package/templates/marketplace/public/images/listings/duffel-640.webp +0 -0
  503. package/templates/marketplace/public/images/listings/duffel.webp +0 -0
  504. package/templates/marketplace/public/images/listings/film-camera-640.webp +0 -0
  505. package/templates/marketplace/public/images/listings/film-camera.webp +0 -0
  506. package/templates/marketplace/public/images/listings/lounge-chair-640.webp +0 -0
  507. package/templates/marketplace/public/images/listings/lounge-chair.webp +0 -0
  508. package/templates/marketplace/public/images/listings/road-bike-640.webp +0 -0
  509. package/templates/marketplace/public/images/listings/road-bike.webp +0 -0
  510. package/templates/marketplace/public/images/listings/slipper-chair-640.webp +0 -0
  511. package/templates/marketplace/public/images/listings/slipper-chair.webp +0 -0
  512. package/templates/marketplace/public/images/listings/turntable-640.webp +0 -0
  513. package/templates/marketplace/public/images/listings/turntable.webp +0 -0
  514. package/templates/marketplace/public/images/listings/wardrobe-640.webp +0 -0
  515. package/templates/marketplace/public/images/listings/wardrobe.webp +0 -0
  516. package/templates/marketplace/public/images/listings/watch-640.webp +0 -0
  517. package/templates/marketplace/public/images/listings/watch.webp +0 -0
  518. package/templates/marketplace/public/images/listings/weekender-bag-640.webp +0 -0
  519. package/templates/marketplace/public/images/listings/weekender-bag.webp +0 -0
  520. package/templates/marketplace/tests/example.test.ts +64 -2
  521. package/templates/marketplace/tests/listing-card.test.tsx +61 -0
  522. package/templates/projects/AGENTS.md +1 -1
  523. package/templates/projects/README.md +24 -3
  524. package/templates/projects/app/apple-icon.png +0 -0
  525. package/templates/projects/app/clients/clients-view.tsx +20 -6
  526. package/templates/projects/app/clients/page.tsx +2 -1
  527. package/templates/projects/app/globals.css +29 -14
  528. package/templates/projects/app/icon.svg +1 -0
  529. package/templates/projects/app/layout.tsx +7 -5
  530. package/templates/projects/app/page.tsx +3 -5
  531. package/templates/projects/app/projects/[id]/page.tsx +2 -1
  532. package/templates/projects/app/projects/[id]/project-view.tsx +45 -30
  533. package/templates/projects/app/projects-view.tsx +105 -52
  534. package/templates/projects/app/workspace.tsx +41 -20
  535. package/templates/projects/app.ts +2 -2
  536. package/templates/projects/components/app-shell.tsx +94 -0
  537. package/templates/projects/components/auth-form.tsx +35 -5
  538. package/templates/projects/components/avatar.tsx +5 -1
  539. package/templates/projects/components/board-skeleton.tsx +3 -3
  540. package/templates/projects/components/brand-mark.tsx +25 -0
  541. package/templates/projects/components/command-palette.tsx +17 -17
  542. package/templates/projects/components/data-table.tsx +97 -36
  543. package/templates/projects/components/filter-tabs.tsx +101 -0
  544. package/templates/projects/components/meter.tsx +48 -0
  545. package/templates/projects/components/nav.tsx +14 -0
  546. package/templates/projects/components/page-header.tsx +43 -7
  547. package/templates/projects/components/require-auth.tsx +24 -26
  548. package/templates/projects/components/sidebar.tsx +54 -48
  549. package/templates/projects/components/summary-bar.tsx +49 -0
  550. package/templates/projects/components/task-board.tsx +10 -9
  551. package/templates/projects/components/time-dialog.tsx +29 -5
  552. package/templates/projects/components/ui/button.tsx +5 -4
  553. package/templates/projects/components/ui/dialog.tsx +1 -1
  554. package/templates/projects/components/ui/input.tsx +1 -1
  555. package/templates/projects/components/ui/select.tsx +1 -1
  556. package/templates/projects/components/ui/textarea.tsx +1 -1
  557. package/templates/projects/functions/seedWorkspace.ts +26 -12
  558. package/templates/projects/lib/brand.ts +9 -0
  559. package/templates/projects/lib/demo-team.ts +51 -0
  560. package/templates/projects/lib/search.ts +4 -3
  561. package/templates/projects/lib/seed.ts +35 -1
  562. package/templates/projects/lib/work.ts +63 -0
  563. package/templates/projects/public/favicon.ico +0 -0
  564. package/templates/projects/tests/demo-team.test.ts +18 -0
  565. package/templates/projects/tests/work.test.ts +65 -0
  566. package/templates/restaurant/.env.example +7 -0
  567. package/templates/restaurant/AGENTS.md +1 -1
  568. package/templates/restaurant/README.md +29 -3
  569. package/templates/restaurant/app/(marketing)/layout.tsx +4 -2
  570. package/templates/restaurant/app/(marketing)/page.tsx +47 -23
  571. package/templates/restaurant/app/(marketing)/reservation-widget.tsx +37 -7
  572. package/templates/restaurant/app/auth-form.tsx +8 -8
  573. package/templates/restaurant/app/dashboard/dashboard-client.tsx +241 -109
  574. package/templates/restaurant/app/dashboard/page.tsx +14 -14
  575. package/templates/restaurant/app/icon.svg +4 -0
  576. package/templates/restaurant/app/login/page.tsx +15 -15
  577. package/templates/restaurant/functions/seedDemo.ts +44 -0
  578. package/templates/restaurant/lib/demo.ts +144 -0
  579. package/templates/restaurant/lib/hours.ts +45 -0
  580. package/templates/restaurant/lib/site.config.ts +3 -3
  581. package/templates/restaurant/public/favicon.ico +0 -0
  582. package/templates/restaurant/tests/reservations.test.ts +67 -0
  583. package/templates/saas/AGENTS.md +1 -1
  584. package/templates/saas/README.md +54 -35
  585. package/templates/saas/app/(auth)/auth-form.tsx +25 -23
  586. package/templates/saas/app/(auth)/forgot-password/page.tsx +1 -1
  587. package/templates/saas/app/(auth)/layout.tsx +27 -33
  588. package/templates/saas/app/(auth)/login/page.tsx +1 -1
  589. package/templates/saas/app/(auth)/reset-password/page.tsx +1 -1
  590. package/templates/saas/app/(auth)/signup/page.tsx +1 -1
  591. package/templates/saas/app/(marketing)/layout.tsx +127 -253
  592. package/templates/saas/app/(marketing)/page.tsx +133 -372
  593. package/templates/saas/app/(marketing)/pricing/page.tsx +21 -19
  594. package/templates/saas/app/(marketing)/products/[slug]/page.tsx +40 -95
  595. package/templates/saas/app/dashboard/board-client.tsx +416 -0
  596. package/templates/saas/app/dashboard/dashboard-client.tsx +30 -615
  597. package/templates/saas/app/dashboard/layout.tsx +27 -13
  598. package/templates/saas/app/dashboard/overview-client.tsx +332 -0
  599. package/templates/saas/app/dashboard/page.tsx +29 -35
  600. package/templates/saas/app/dashboard/projects/[id]/page.tsx +29 -0
  601. package/templates/saas/app/dashboard/projects/page.tsx +11 -7
  602. package/templates/saas/app/dashboard/projects-client.tsx +398 -0
  603. package/templates/saas/app/globals.css +5 -4
  604. package/templates/saas/app/icon.svg +1 -0
  605. package/templates/saas/app/onboarding/onboarding-client.tsx +93 -26
  606. package/templates/saas/app/onboarding/page.tsx +6 -2
  607. package/templates/saas/app.ts +68 -13
  608. package/templates/saas/components/dashboard-shell.tsx +212 -132
  609. package/templates/saas/components/marketing.tsx +137 -274
  610. package/templates/saas/components/pricing-table.tsx +12 -11
  611. package/templates/saas/components/setup-checklist.tsx +31 -29
  612. package/templates/saas/components/task-ui.tsx +199 -0
  613. package/templates/saas/functions/createProject.ts +7 -13
  614. package/templates/saas/functions/createTask.ts +67 -0
  615. package/templates/saas/functions/deleteProject.ts +17 -0
  616. package/templates/saas/functions/deleteTask.ts +14 -0
  617. package/templates/saas/functions/seedWorkspace.ts +46 -0
  618. package/templates/saas/functions/setProjectStatus.ts +41 -0
  619. package/templates/saas/functions/updateProfile.ts +13 -0
  620. package/templates/saas/functions/updateProject.ts +4 -5
  621. package/templates/saas/functions/updateTask.ts +88 -0
  622. package/templates/saas/lib/members.ts +53 -0
  623. package/templates/saas/lib/names.ts +53 -0
  624. package/templates/saas/lib/plans.ts +11 -0
  625. package/templates/saas/lib/sample-workspace.ts +117 -0
  626. package/templates/saas/lib/site.config.ts +200 -463
  627. package/templates/saas/lib/tasks.ts +101 -0
  628. package/templates/saas/lib/use-live.ts +25 -0
  629. package/templates/saas/public/favicon.ico +0 -0
  630. package/templates/saas/public/screenshots/board.png +0 -0
  631. package/templates/saas/public/screenshots/members.png +0 -0
  632. package/templates/saas/public/screenshots/overview.png +0 -0
  633. package/templates/saas/public/screenshots/projects.png +0 -0
  634. package/templates/saas/scripts/capture-screenshots.mjs +156 -0
  635. package/templates/saas/tests/names.test.ts +35 -0
  636. package/templates/saas/tests/plans.test.ts +12 -0
  637. package/templates/saas/tests/sample-workspace.test.ts +46 -0
  638. package/templates/saas/tests/tasks.test.ts +81 -0
  639. package/templates/shop/AGENTS.md +1 -1
  640. package/templates/shop/README.md +25 -13
  641. package/templates/shop/app/(marketing)/layout.tsx +94 -67
  642. package/templates/shop/app/(marketing)/not-found.tsx +13 -12
  643. package/templates/shop/app/(marketing)/page.tsx +120 -59
  644. package/templates/shop/app/(marketing)/shop-client.tsx +364 -237
  645. package/templates/shop/app/(marketing)/success/page.tsx +75 -22
  646. package/templates/shop/app/globals.css +94 -1
  647. package/templates/shop/app/layout.tsx +4 -4
  648. package/templates/shop/app/login/page.tsx +4 -4
  649. package/templates/shop/app.ts +18 -6
  650. package/templates/shop/components/cart-button.tsx +33 -0
  651. package/templates/shop/components/marketing.tsx +17 -87
  652. package/templates/shop/components/shelf-count.tsx +36 -0
  653. package/templates/shop/functions/checkout.ts +17 -1
  654. package/templates/shop/lib/cart-store.ts +57 -0
  655. package/templates/shop/lib/shelf-store.ts +35 -0
  656. package/templates/shop/lib/shop.ts +27 -0
  657. package/templates/shop/lib/site.config.ts +108 -98
  658. package/templates/shop/public/images/hero.jpg +0 -0
  659. package/templates/shop/public/images/products/cedar-smoke.jpg +0 -0
  660. package/templates/shop/public/images/products/fig-leaf.jpg +0 -0
  661. package/templates/shop/public/images/products/linen.jpg +0 -0
  662. package/templates/shop/public/images/products/sea-salt.jpg +0 -0
  663. package/templates/shop/public/images/products/tobacco-oak.jpg +0 -0
  664. package/templates/shop/tests/shop.test.ts +64 -0
  665. package/templates/todo/AGENTS.md +1 -1
  666. package/templates/waitlist/.env.example +7 -0
  667. package/templates/waitlist/AGENTS.md +1 -1
  668. package/templates/waitlist/README.md +29 -13
  669. package/templates/waitlist/app/(marketing)/page.tsx +9 -7
  670. package/templates/waitlist/app/(marketing)/waitlist-hero.tsx +64 -31
  671. package/templates/waitlist/app/auth-form.tsx +8 -8
  672. package/templates/waitlist/app/dashboard/dashboard-client.tsx +132 -95
  673. package/templates/waitlist/app/dashboard/page.tsx +17 -16
  674. package/templates/waitlist/app/icon.svg +2 -0
  675. package/templates/waitlist/app/login/page.tsx +14 -14
  676. package/templates/waitlist/app.ts +6 -6
  677. package/templates/waitlist/functions/joinWaitlist.ts +6 -18
  678. package/templates/waitlist/functions/seedDemo.ts +32 -0
  679. package/templates/waitlist/lib/demo.ts +94 -0
  680. package/templates/waitlist/lib/launch.ts +19 -0
  681. package/templates/waitlist/lib/site.config.ts +14 -9
  682. package/templates/waitlist/lib/stats.ts +35 -0
  683. package/templates/waitlist/public/favicon.ico +0 -0
  684. package/templates/waitlist/tests/counter.test.ts +107 -0
  685. package/templates/waitlist/tests/live-count.test.tsx +48 -0
  686. package/templates/ai-chat/tests/example.test.ts +0 -12
  687. package/templates/backend/consumer/apps/api/functions/feed.ts +0 -57
  688. package/templates/backend/consumer/apps/api/functions/profilePosts.ts +0 -17
  689. package/templates/backend/consumer/apps/api/functions/toggleLike.ts +0 -48
  690. package/templates/backend/consumer/apps/api/schema.ts +0 -143
  691. package/templates/chat/functions/_keep.ts +0 -13
  692. package/templates/chat/tests/example.test.ts +0 -12
  693. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ProfileSetupView.swift +0 -68
  694. package/templates/marketplace/client/LiveTicker.tsx +0 -116
  695. package/templates/marketplace/client/ScrollToListingsLink.tsx +0 -29
  696. package/templates/marketplace/public/images/marketplace-hero.webp +0 -0
@@ -3,9 +3,11 @@
3
3
  import React, { useEffect, useMemo, useRef, useState } from "react";
4
4
  import { callFn, db, useRouter } from "@pylonsync/react";
5
5
  import { useAuth } from "@pylonsync/client";
6
- import { Sidebar } from "@/components/sidebar";
6
+ import { Building2, CircleDollarSign, User } from "lucide-react";
7
+ import { AppShell } from "@/components/app-shell";
7
8
  import { CommandPalette } from "@/components/command-palette";
8
9
  import type { SearchItem } from "@/lib/search";
10
+ import { isOpen } from "@/lib/pipeline";
9
11
 
10
12
  export interface CompanyRow {
11
13
  id: string;
@@ -58,6 +60,11 @@ export interface WorkspaceData {
58
60
  activities: ActivityRow[];
59
61
  companyName: (id: string | null | undefined) => string | null;
60
62
  ownerName: (id: string | null | undefined) => string | null;
63
+ /**
64
+ * The number beside each nav link, keyed by href. Page headers read the same
65
+ * map, so the sidebar and the page can't disagree.
66
+ */
67
+ navCounts: Record<string, number>;
61
68
  loading: boolean;
62
69
  }
63
70
 
@@ -94,8 +101,7 @@ export function Workspace({
94
101
 
95
102
  // Whoever is signed in, named from the synced User row rather than an
96
103
  // SSR prop — see the note on useAuth above.
97
- const signedInEmail =
98
- (users ?? []).find((user) => user.id === userId)?.email ?? "";
104
+ const me = (users ?? []).find((user) => user.id === userId);
99
105
 
100
106
  const [paletteOpen, setPaletteOpen] = useState(false);
101
107
  const seeded = useRef(false);
@@ -177,6 +183,12 @@ export function Workspace({
177
183
  [dealList, companyList, contactList, byId],
178
184
  );
179
185
 
186
+ const navCounts = {
187
+ "/": dealList.filter(isOpen).length,
188
+ "/companies": companyList.length,
189
+ "/contacts": contactList.length,
190
+ };
191
+
180
192
  const data: WorkspaceData = {
181
193
  companies: companyList,
182
194
  contacts: contactList,
@@ -187,23 +199,21 @@ export function Workspace({
187
199
  const user = byId.userById.get(id ?? "");
188
200
  return user?.displayName || user?.email || null;
189
201
  },
202
+ navCounts,
190
203
  loading: loadingCompanies,
191
204
  };
192
205
 
193
206
  return (
194
- <div className="flex h-screen overflow-hidden">
195
- <Sidebar
196
- workspace="CRM"
197
- email={signedInEmail}
198
- pathname={pathname}
199
- counts={{
200
- "/companies": companyList.length,
201
- "/contacts": contactList.length,
202
- }}
203
- onOpenCommand={() => setPaletteOpen(true)}
204
- onSignOut={() => void signOut()}
205
- />
206
- <main className="flex min-w-0 flex-1 flex-col">{children(data)}</main>
207
+ <AppShell
208
+ sidebar={{
209
+ user: { name: me?.displayName ?? "", email: me?.email ?? "" },
210
+ pathname,
211
+ counts: navCounts,
212
+ onOpenCommand: () => setPaletteOpen(true),
213
+ onSignOut: () => void signOut(),
214
+ }}
215
+ >
216
+ {children(data)}
207
217
 
208
218
  <CommandPalette
209
219
  open={paletteOpen}
@@ -225,9 +235,11 @@ export function Workspace({
225
235
  run: () => router.push("/contacts"),
226
236
  },
227
237
  ]}
238
+ placeholder="Search deals, companies, contacts…"
239
+ icons={{ deal: <CircleDollarSign />, company: <Building2 />, contact: <User /> }}
228
240
  onClose={() => setPaletteOpen(false)}
229
241
  onSelect={(item) => router.push(item.href)}
230
242
  />
231
- </div>
243
+ </AppShell>
232
244
  );
233
245
  }
@@ -10,7 +10,7 @@ import {
10
10
  } from "@pylonsync/sdk";
11
11
 
12
12
  // ---------------------------------------------------------------------------
13
- // crm — a sales CRM for a small team: companies, contacts, deals moving through
13
+ // Dealbook (the crm template) — a sales CRM for a small team: companies, contacts, deals moving through
14
14
  // a pipeline, and an activity log.
15
15
  //
16
16
  // The realtime hook: the board subscribes to Deal, so when a teammate drags a
@@ -156,12 +156,12 @@ const manifest = buildManifest({
156
156
  userPolicy,
157
157
  ],
158
158
  auth: auth(),
159
- // Self-hosted Inter: the build fetches the woff2, serves it same-origin (no
160
- // third-party request, no FOUT), preloads it, and synthesizes a size-adjusted
161
- // fallback so there's no layout shift.
159
+ // Self-hosted Instrument Sans: the build fetches the woff2, serves it
160
+ // same-origin, preloads it, and synthesizes a size-adjusted fallback so
161
+ // there's no layout shift.
162
162
  fonts: [
163
163
  font({
164
- family: "Inter",
164
+ family: "Instrument Sans",
165
165
  variable: "--font-sans",
166
166
  weights: ["400", "500", "600", "700"],
167
167
  subsets: ["latin"],
@@ -22,6 +22,13 @@ const ICON: Record<string, React.ReactNode> = {
22
22
  meeting: <CalendarDays />,
23
23
  };
24
24
 
25
+ const VERB: Record<string, string> = {
26
+ note: "added a note",
27
+ call: "logged a call",
28
+ email: "logged an email",
29
+ meeting: "logged a meeting",
30
+ };
31
+
25
32
  /**
26
33
  * What happened on this deal, newest first, with the composer on top so logging
27
34
  * a call takes one click from landing on the page.
@@ -100,7 +107,7 @@ export function ActivityTimeline({
100
107
  No activity yet. Log the first call or note above.
101
108
  </p>
102
109
  ) : (
103
- <ol className="space-y-3">
110
+ <ol className="space-y-4">
104
111
  {ordered.map((activity) => (
105
112
  <li key={activity.id} className="flex gap-2.5">
106
113
  <div
@@ -112,15 +119,18 @@ export function ActivityTimeline({
112
119
  {ICON[activity.kind] ?? ICON.note}
113
120
  </div>
114
121
  <div className="min-w-0 flex-1">
115
- <div className="flex items-center gap-1.5 text-[11px] text-muted-foreground">
122
+ <div className="flex items-center gap-1.5 text-[12px] text-muted-foreground">
116
123
  <Avatar name={ownerName(activity.ownerId) ?? "?"} size="sm" />
117
- <span className="capitalize">{activity.kind}</span>
124
+ <span className="truncate font-medium text-foreground">
125
+ {ownerName(activity.ownerId) ?? "Someone"}
126
+ </span>
127
+ <span className="shrink-0">{VERB[activity.kind] ?? "added a note"}</span>
118
128
  <span aria-hidden="true">·</span>
119
129
  <time dateTime={activity.createdAt ?? undefined}>
120
130
  {relativeTime(activity.createdAt)}
121
131
  </time>
122
132
  </div>
123
- <p className="mt-1 whitespace-pre-wrap text-[13px] leading-5">
133
+ <p className="mt-1 whitespace-pre-wrap text-[13px] leading-[1.55]">
124
134
  {activity.body}
125
135
  </p>
126
136
  </div>
@@ -0,0 +1,94 @@
1
+ "use client";
2
+
3
+ import React, { createContext, useContext, useEffect, useState } from "react";
4
+ import * as DialogPrimitive from "@radix-ui/react-dialog";
5
+ import { BRAND } from "@/lib/brand";
6
+ import { Sidebar } from "@/components/sidebar";
7
+
8
+ interface ShellControls {
9
+ /** Opens the navigation drawer. Only reachable on narrow screens. */
10
+ openNav: () => void;
11
+ openCommand: () => void;
12
+ }
13
+
14
+ const ShellContext = createContext<ShellControls | null>(null);
15
+
16
+ /** The shell's controls, or null outside a shell (a component test). */
17
+ export function useShell(): ShellControls | null {
18
+ return useContext(ShellContext);
19
+ }
20
+
21
+ type SidebarProps = React.ComponentProps<typeof Sidebar>;
22
+
23
+ /**
24
+ * The page frame. From the `md` breakpoint up, the sidebar is a fixed
25
+ * 240px rail and the main column scrolls on its own. Below it, the rail
26
+ * is hidden and the same sidebar opens as a drawer from the menu button
27
+ * in each page header, so a phone gets the full width for content.
28
+ */
29
+ export function AppShell({
30
+ sidebar,
31
+ children,
32
+ }: {
33
+ sidebar: Omit<SidebarProps, "onNavigate" | "className">;
34
+ children: React.ReactNode;
35
+ }) {
36
+ const [navOpen, setNavOpen] = useState(false);
37
+ const { pathname, onOpenCommand } = sidebar;
38
+
39
+ // A route change closes the drawer, including one made from ⌘K.
40
+ useEffect(() => {
41
+ setNavOpen(false);
42
+ }, [pathname]);
43
+
44
+ // Widening past md hides the drawer, so close it rather than leave an
45
+ // invisible modal holding focus.
46
+ useEffect(() => {
47
+ const wide = window.matchMedia("(min-width: 768px)");
48
+ const onChange = () => {
49
+ if (wide.matches) setNavOpen(false);
50
+ };
51
+ wide.addEventListener("change", onChange);
52
+ return () => wide.removeEventListener("change", onChange);
53
+ }, []);
54
+
55
+ return (
56
+ <ShellContext.Provider
57
+ value={{ openNav: () => setNavOpen(true), openCommand: onOpenCommand }}
58
+ >
59
+ <div className="flex h-dvh overflow-hidden bg-background">
60
+ <aside className="hidden w-[240px] shrink-0 border-r border-border md:flex">
61
+ <Sidebar {...sidebar} />
62
+ </aside>
63
+
64
+ <DialogPrimitive.Root open={navOpen} onOpenChange={setNavOpen}>
65
+ <DialogPrimitive.Portal>
66
+ <DialogPrimitive.Overlay className="fixed inset-0 z-40 bg-black/40 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 md:hidden" />
67
+ <DialogPrimitive.Content
68
+ className={
69
+ "fixed inset-y-0 left-0 z-40 flex w-[min(300px,86vw)] border-r border-border shadow-xl outline-none md:hidden " +
70
+ "duration-200 data-[state=open]:animate-in data-[state=open]:slide-in-from-left " +
71
+ "data-[state=closed]:animate-out data-[state=closed]:slide-out-to-left"
72
+ }
73
+ >
74
+ <DialogPrimitive.Title className="sr-only">{BRAND.name} navigation</DialogPrimitive.Title>
75
+ <DialogPrimitive.Description className="sr-only">
76
+ Links to every section, search, and your account.
77
+ </DialogPrimitive.Description>
78
+ <Sidebar
79
+ {...sidebar}
80
+ onNavigate={() => setNavOpen(false)}
81
+ onOpenCommand={() => {
82
+ setNavOpen(false);
83
+ onOpenCommand();
84
+ }}
85
+ />
86
+ </DialogPrimitive.Content>
87
+ </DialogPrimitive.Portal>
88
+ </DialogPrimitive.Root>
89
+
90
+ <main className="flex min-w-0 flex-1 flex-col">{children}</main>
91
+ </div>
92
+ </ShellContext.Provider>
93
+ );
94
+ }
@@ -21,8 +21,16 @@ import { Label } from "@/components/ui/label";
21
21
  * SSR cookie, which browsers withhold inside the builder's cross-site preview
22
22
  * iframe — that's the sign-in loop this avoids.
23
23
  */
24
- export function AuthForm() {
25
- const [mode, setMode] = useState<"login" | "signup">("login");
24
+ export type AuthMode = "login" | "signup";
25
+
26
+ export function AuthForm({
27
+ mode,
28
+ onModeChange,
29
+ }: {
30
+ mode: AuthMode;
31
+ onModeChange: (mode: AuthMode) => void;
32
+ }) {
33
+ const [name, setName] = useState("");
26
34
  const [email, setEmail] = useState("");
27
35
  const [password, setPassword] = useState("");
28
36
  const [error, setError] = useState<string | null>(null);
@@ -36,7 +44,11 @@ export function AuthForm() {
36
44
  const session =
37
45
  mode === "login"
38
46
  ? await passwordLogin({ email, password })
39
- : await passwordRegister({ email, password });
47
+ : await passwordRegister({
48
+ email,
49
+ password,
50
+ ...(name.trim() ? { displayName: name.trim() } : {}),
51
+ });
40
52
  // No navigation: persistSession notifies the sync engine, RequireAuth
41
53
  // re-renders, and the app appears in place. A full page load here would
42
54
  // depend on the SSR session cookie, which a cross-site iframe withholds.
@@ -50,6 +62,18 @@ export function AuthForm() {
50
62
  return (
51
63
  <div className="space-y-5">
52
64
  <form onSubmit={onSubmit} className="space-y-3.5">
65
+ {mode === "signup" ? (
66
+ <div className="space-y-1.5">
67
+ <Label htmlFor="name">Name</Label>
68
+ <Input
69
+ id="name"
70
+ value={name}
71
+ onChange={(event) => setName(event.target.value)}
72
+ autoComplete="name"
73
+ placeholder="Jordan Lee"
74
+ />
75
+ </div>
76
+ ) : null}
53
77
  <div className="space-y-1.5">
54
78
  <Label htmlFor="email">Email</Label>
55
79
  <Input
@@ -80,7 +104,13 @@ export function AuthForm() {
80
104
  </p>
81
105
  ) : null}
82
106
  <Button type="submit" disabled={pending} className="w-full">
83
- {pending ? "…" : mode === "login" ? "Sign in" : "Create account"}
107
+ {pending
108
+ ? mode === "login"
109
+ ? "Signing in…"
110
+ : "Creating account…"
111
+ : mode === "login"
112
+ ? "Sign in"
113
+ : "Create account"}
84
114
  </Button>
85
115
  </form>
86
116
 
@@ -89,7 +119,7 @@ export function AuthForm() {
89
119
  <button
90
120
  type="button"
91
121
  onClick={() => {
92
- setMode(mode === "login" ? "signup" : "login");
122
+ onModeChange(mode === "login" ? "signup" : "login");
93
123
  setError(null);
94
124
  }}
95
125
  className="font-medium text-foreground underline underline-offset-2"
@@ -17,10 +17,13 @@ const ACCENTS = [
17
17
  export function Avatar({
18
18
  name,
19
19
  size = "md",
20
+ shape = "round",
20
21
  className,
21
22
  }: {
22
23
  name: string | null | undefined;
23
24
  size?: "sm" | "md";
25
+ /** Square for an organisation, round for a person. */
26
+ shape?: "round" | "square";
24
27
  className?: string;
25
28
  }) {
26
29
  const label = initials(name);
@@ -28,7 +31,8 @@ export function Avatar({
28
31
  <span
29
32
  aria-hidden="true"
30
33
  className={cn(
31
- "inline-flex shrink-0 select-none items-center justify-center rounded-full font-medium",
34
+ "inline-flex shrink-0 select-none items-center justify-center font-semibold",
35
+ shape === "square" ? "rounded-md" : "rounded-full",
32
36
  size === "sm" ? "size-5 text-[9px]" : "size-6 text-[10px]",
33
37
  ACCENTS[accentIndex(name ?? "?", ACCENTS.length)],
34
38
  className,
@@ -12,14 +12,14 @@ import { BOARD_STAGES } from "@/lib/pipeline";
12
12
  */
13
13
  export function BoardSkeleton() {
14
14
  return (
15
- <div className="flex h-full gap-3 overflow-hidden p-4" aria-hidden="true">
15
+ <div className="flex h-full gap-3 overflow-hidden p-4 md:px-5" aria-hidden="true">
16
16
  {BOARD_STAGES.map((stage, column) => (
17
17
  <section
18
18
  key={stage.id}
19
- className="flex w-[268px] shrink-0 flex-col rounded-xl border border-border bg-surface-1/50"
19
+ className="flex w-[84vw] shrink-0 flex-col rounded-xl border border-border/70 bg-surface-1 md:w-auto md:min-w-[208px] md:max-w-[340px] md:flex-1"
20
20
  >
21
- <header className="flex items-center gap-2 px-3 py-2.5">
22
- <span className="text-[12px] font-medium text-muted-foreground">
21
+ <header className="flex items-center gap-2 px-3 pb-2 pt-3">
22
+ <span className="text-[12.5px] font-semibold text-muted-foreground">
23
23
  {stage.label}
24
24
  </span>
25
25
  </header>
@@ -29,7 +29,7 @@ export function BoardSkeleton() {
29
29
  {Array.from({ length: Math.max(1, 3 - column) }).map((_, card) => (
30
30
  <div
31
31
  key={card}
32
- className="animate-pulse rounded-lg border border-border bg-card p-2.5"
32
+ className="animate-pulse rounded-lg border border-border/80 bg-card p-3"
33
33
  >
34
34
  <div className="h-3 w-3/4 rounded bg-muted" />
35
35
  <div className="mt-2 h-2.5 w-1/2 rounded bg-muted" />
@@ -0,0 +1,25 @@
1
+ import React from "react";
2
+ import { cn } from "@/lib/utils";
3
+
4
+ /**
5
+ * The Dealbook mark: three stacked bars that narrow like a sales funnel, on
6
+ * the accent square. app/icon.svg draws the same shape for the favicon.
7
+ */
8
+ export function BrandMark({ className }: { className?: string }) {
9
+ return (
10
+ <span
11
+ aria-hidden="true"
12
+ className={cn(
13
+ "inline-flex size-6 shrink-0 items-center justify-center rounded-[7px] bg-primary text-primary-foreground",
14
+ "shadow-[inset_0_1px_0_rgb(255_255_255/0.18),0_1px_2px_rgb(0_0_0/0.12)]",
15
+ className,
16
+ )}
17
+ >
18
+ <svg viewBox="0 0 16 16" className="size-[62%]" fill="currentColor">
19
+ <rect x="1.5" y="2.5" width="13" height="2.6" rx="1.3" />
20
+ <rect x="3.5" y="6.7" width="9" height="2.6" rx="1.3" />
21
+ <rect x="5.5" y="10.9" width="5" height="2.6" rx="1.3" />
22
+ </svg>
23
+ </span>
24
+ );
25
+ }
@@ -1,15 +1,9 @@
1
1
  import React, { useEffect, useMemo, useRef, useState } from "react";
2
- import { Building2, Plus, Search, User } from "lucide-react";
2
+ import { ArrowRight, FileText, Search } from "lucide-react";
3
3
  import { cn } from "@/lib/utils";
4
4
  import { Kbd } from "@/components/kbd";
5
5
  import { moveSelection, searchItems, type SearchItem } from "@/lib/search";
6
6
 
7
- const TYPE_ICON: Record<SearchItem["type"], React.ReactNode> = {
8
- deal: <Search />,
9
- company: <Building2 />,
10
- contact: <User />,
11
- };
12
-
13
7
  export interface CommandAction {
14
8
  id: string;
15
9
  label: string;
@@ -28,12 +22,18 @@ export function CommandPalette({
28
22
  open,
29
23
  items,
30
24
  actions = [],
25
+ placeholder = "Search…",
26
+ icons = {},
31
27
  onClose,
32
28
  onSelect,
33
29
  }: {
34
30
  open: boolean;
35
31
  items: SearchItem[];
36
32
  actions?: CommandAction[];
33
+ /** Input placeholder naming what can be found, such as "Search deals…". */
34
+ placeholder?: string;
35
+ /** Icon per `SearchItem.type`. Unknown types get a document icon. */
36
+ icons?: Record<string, React.ReactNode>;
37
37
  onClose: () => void;
38
38
  onSelect: (item: SearchItem) => void;
39
39
  }) {
@@ -76,7 +76,7 @@ export function CommandPalette({
76
76
 
77
77
  return (
78
78
  <div
79
- className="fixed inset-0 z-50 flex items-start justify-center bg-black/50 pt-[12vh]"
79
+ className="fixed inset-0 z-50 flex items-start justify-center bg-black/40 px-3 pt-[10vh] md:pt-[14vh]"
80
80
  // Clicking the backdrop dismisses; clicks inside the panel must not.
81
81
  onMouseDown={(event) => {
82
82
  if (event.target === event.currentTarget) onClose();
@@ -85,8 +85,8 @@ export function CommandPalette({
85
85
  <div
86
86
  role="dialog"
87
87
  aria-modal="true"
88
- aria-label="Search"
89
- className="w-full max-w-lg overflow-hidden rounded-xl border border-border bg-popover shadow-2xl"
88
+ aria-label="Command menu"
89
+ className="w-full max-w-xl overflow-hidden rounded-xl border border-border bg-popover shadow-[0_24px_64px_-12px_rgb(0_0_0/0.3)]"
90
90
  onKeyDown={(event) => {
91
91
  if (event.key === "Escape") {
92
92
  event.preventDefault();
@@ -109,14 +109,14 @@ export function CommandPalette({
109
109
  ref={inputRef}
110
110
  value={query}
111
111
  onChange={(event) => setQuery(event.target.value)}
112
- placeholder="Search deals, companies, contacts…"
113
- aria-label="Search deals, companies and contacts"
114
- className="h-11 flex-1 bg-transparent text-[13px] outline-none placeholder:text-muted-foreground"
112
+ placeholder={placeholder}
113
+ aria-label={placeholder.replace(/…$/, "")}
114
+ className="h-12 flex-1 bg-transparent text-base outline-none placeholder:text-muted-foreground md:text-[14px]"
115
115
  />
116
- <Kbd>esc</Kbd>
116
+ <Kbd className="max-md:hidden">esc</Kbd>
117
117
  </div>
118
118
 
119
- <div className="max-h-80 overflow-y-auto p-1.5">
119
+ <div className="max-h-[min(360px,60dvh)] overflow-y-auto p-1.5">
120
120
  {rows.length === 0 ? (
121
121
  <p className="px-3 py-6 text-center text-[12px] text-muted-foreground">
122
122
  No matches for “{query}”
@@ -138,12 +138,12 @@ export function CommandPalette({
138
138
  >
139
139
  {row.kind === "action" ? (
140
140
  <>
141
- <Plus />
141
+ <ArrowRight />
142
142
  <span className="flex-1 truncate">{row.action.label}</span>
143
143
  </>
144
144
  ) : (
145
145
  <>
146
- {TYPE_ICON[row.item.type]}
146
+ {icons[row.item.type] ?? <FileText />}
147
147
  <span className="flex-1 truncate">{row.item.title}</span>
148
148
  {row.item.subtitle ? (
149
149
  <span className="truncate text-[12px] text-muted-foreground">