@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
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React from "react";
4
4
  import { Link, callFn, db, useRouter } from "@pylonsync/react";
5
- import { ArrowLeft, Trash2 } from "lucide-react";
5
+ import { ChevronRight, Trash2 } from "lucide-react";
6
6
  import { Button } from "@/components/ui/button";
7
7
  import { Select } from "@/components/ui/select";
8
8
  import { PageHeader } from "@/components/page-header";
@@ -10,7 +10,7 @@ import { EmptyState } from "@/components/empty-state";
10
10
  import { ActivityTimeline } from "@/components/activity-timeline";
11
11
  import { StageBadge } from "@/components/stage-badge";
12
12
  import { Avatar } from "@/components/avatar";
13
- import { PIPELINE, daysUntil, money, relativeTime } from "@/lib/pipeline";
13
+ import { PIPELINE, closeDue, money, relativeTime, shortDate } from "@/lib/pipeline";
14
14
  import { RequireAuth } from "@/components/require-auth";
15
15
  import { Workspace } from "../../workspace";
16
16
 
@@ -18,7 +18,7 @@ export function DealView({ dealId }: { dealId: string }) {
18
18
  const router = useRouter();
19
19
 
20
20
  return (
21
- <RequireAuth title="CRM" description="Your team shares one pipeline. Anyone with an account sees it.">
21
+ <RequireAuth>
22
22
  <Workspace pathname="/">
23
23
  {(data) => {
24
24
  const deal = data.deals.find((d) => d.id === dealId);
@@ -28,7 +28,7 @@ export function DealView({ dealId }: { dealId: string }) {
28
28
  <>
29
29
  <PageHeader title="Deal" />
30
30
  <EmptyState
31
- title={data.loading ? "Loading…" : "Deal not found"}
31
+ title={data.loading ? "Loading deal…" : "Deal not found"}
32
32
  description={
33
33
  data.loading
34
34
  ? undefined
@@ -48,11 +48,24 @@ export function DealView({ dealId }: { dealId: string }) {
48
48
 
49
49
  const contact = data.contacts.find((c) => c.id === deal.contactId);
50
50
  const activities = data.activities.filter((a) => a.dealId === deal.id);
51
- const days = daysUntil(deal.closeDate);
51
+ const due = closeDue(deal);
52
+ const owner = data.ownerName(deal.ownerId);
53
+ const company = data.companyName(deal.companyId);
52
54
 
53
55
  return (
54
56
  <>
55
- <PageHeader title={deal.title}>
57
+ <PageHeader
58
+ title={deal.title}
59
+ leading={
60
+ <Link
61
+ href="/"
62
+ className="hidden items-center gap-1 text-[13px] text-muted-foreground transition-colors hover:text-foreground md:inline-flex"
63
+ >
64
+ Pipeline
65
+ <ChevronRight className="size-3.5" />
66
+ </Link>
67
+ }
68
+ >
56
69
  <Button
57
70
  size="sm"
58
71
  variant="ghost"
@@ -63,109 +76,135 @@ export function DealView({ dealId }: { dealId: string }) {
63
76
  className="text-muted-foreground hover:text-destructive"
64
77
  >
65
78
  <Trash2 />
66
- Delete
79
+ <span className="max-sm:sr-only">Delete</span>
67
80
  </Button>
68
81
  </PageHeader>
69
82
 
70
83
  <div className="min-h-0 flex-1 overflow-y-auto">
71
- <div className="mx-auto flex max-w-3xl flex-col gap-6 px-6 py-6">
72
- <Link
73
- href="/"
74
- className="inline-flex w-fit items-center gap-1.5 text-[12px] text-muted-foreground transition-colors hover:text-foreground"
75
- >
76
- <ArrowLeft className="size-3.5" />
77
- Pipeline
78
- </Link>
79
-
80
- <div className="flex flex-wrap items-baseline gap-x-4 gap-y-2">
81
- <h1 className="text-[22px] font-semibold tracking-tight">
82
- {deal.title}
83
- </h1>
84
- <span className="tabular text-[18px] font-medium text-muted-foreground">
85
- {money(deal.value)}
86
- </span>
87
- </div>
84
+ <div className="mx-auto grid max-w-5xl gap-6 px-4 py-5 md:px-8 md:py-8 lg:grid-cols-[minmax(0,1fr)_280px] lg:gap-10">
85
+ <div className="min-w-0 space-y-6">
86
+ <div>
87
+ <div className="mb-2 flex items-center gap-2 text-[12.5px]">
88
+ <StageBadge stage={deal.stage} />
89
+ {company ? (
90
+ <>
91
+ <span aria-hidden="true" className="text-muted-foreground/60">·</span>
92
+ <span className="truncate text-muted-foreground">{company}</span>
93
+ </>
94
+ ) : null}
95
+ </div>
96
+ <h2 className="text-[22px] font-semibold leading-tight tracking-[-0.02em] md:text-[26px]">
97
+ {deal.title}
98
+ </h2>
99
+ <p className="tabular mt-1.5 text-[20px] font-medium tracking-[-0.01em] text-muted-foreground">
100
+ {money(deal.value)}
101
+ </p>
102
+ </div>
88
103
 
89
- <dl className="grid grid-cols-2 gap-x-6 gap-y-4 rounded-lg border border-border bg-card p-4 sm:grid-cols-4">
90
- <Field label="Stage">
91
- {/* Changing stage here goes through the same mutation the
92
- board uses, so it's logged identically. */}
93
- <Select
94
- aria-label="Stage"
95
- value={deal.stage}
96
- className="h-7 text-[12px]"
97
- onChange={(event) =>
98
- void callFn("moveDeal", {
104
+ <section aria-labelledby="activity-heading">
105
+ <h3 id="activity-heading" className="mb-3 text-[13px] font-semibold">
106
+ Activity
107
+ <span className="tabular ml-1.5 font-normal text-muted-foreground">
108
+ {activities.length}
109
+ </span>
110
+ </h3>
111
+ <ActivityTimeline
112
+ activities={activities}
113
+ ownerName={data.ownerName}
114
+ onLog={(kind, body) =>
115
+ callFn("logActivity", {
116
+ kind,
117
+ body,
99
118
  dealId: deal.id,
100
- stage: event.target.value,
119
+ ...(deal.companyId ? { companyId: deal.companyId } : {}),
101
120
  })
102
121
  }
103
- >
104
- {PIPELINE.map((stage) => (
105
- <option key={stage.id} value={stage.id}>
106
- {stage.label}
107
- </option>
108
- ))}
109
- </Select>
110
- </Field>
122
+ />
123
+ </section>
124
+ </div>
111
125
 
112
- <Field label="Company">
113
- {data.companyName(deal.companyId) ?? "—"}
114
- </Field>
126
+ <aside className="order-first lg:order-none">
127
+ <dl className="grid grid-cols-2 gap-x-4 gap-y-4 rounded-xl border border-border bg-surface-1 p-4 lg:grid-cols-1">
128
+ <Field label="Stage">
129
+ {/* The same mutation the board uses, so a change here
130
+ is logged the same way. */}
131
+ <Select
132
+ aria-label="Stage"
133
+ value={deal.stage}
134
+ className="h-8 bg-background md:h-7.5"
135
+ onChange={(event) =>
136
+ void callFn("moveDeal", {
137
+ dealId: deal.id,
138
+ stage: event.target.value,
139
+ })
140
+ }
141
+ >
142
+ {PIPELINE.map((stage) => (
143
+ <option key={stage.id} value={stage.id}>
144
+ {stage.label}
145
+ </option>
146
+ ))}
147
+ </Select>
148
+ </Field>
115
149
 
116
- <Field label="Contact">
117
- {contact ? (
118
- <span className="flex items-center gap-1.5">
119
- <Avatar name={contact.name} size="sm" />
120
- {contact.name}
121
- </span>
122
- ) : (
123
- "—"
124
- )}
125
- </Field>
150
+ <Field label="Owner">
151
+ {owner ? (
152
+ <span className="flex min-w-0 items-center gap-2">
153
+ <Avatar name={owner} size="sm" />
154
+ <span className="truncate">{owner}</span>
155
+ </span>
156
+ ) : (
157
+ "—"
158
+ )}
159
+ </Field>
126
160
 
127
- <Field label="Expected close">
128
- {deal.closeDate ? (
129
- <span className={days !== null && days < 0 ? "text-destructive" : ""}>
130
- {new Date(deal.closeDate).toLocaleDateString("en-US", {
131
- month: "short",
132
- day: "numeric",
133
- year: "numeric",
134
- })}
135
- </span>
136
- ) : (
137
- "—"
138
- )}
139
- </Field>
140
- </dl>
161
+ <Field label="Company">{company ?? "—"}</Field>
141
162
 
142
- <div className="flex items-center gap-3 text-[12px] text-muted-foreground">
143
- <StageBadge stage={deal.stage} />
144
- <span aria-hidden="true">·</span>
145
- <span>Created {relativeTime(deal.createdAt)}</span>
146
- {data.ownerName(deal.ownerId) ? (
147
- <>
148
- <span aria-hidden="true">·</span>
149
- <span>Owned by {data.ownerName(deal.ownerId)}</span>
150
- </>
151
- ) : null}
152
- </div>
163
+ <Field label="Contact">
164
+ {contact ? (
165
+ <span className="flex min-w-0 items-center gap-2">
166
+ <Avatar name={contact.name} size="sm" />
167
+ <span className="min-w-0">
168
+ <span className="block truncate">{contact.name}</span>
169
+ {contact.email ? (
170
+ <a
171
+ href={`mailto:${contact.email}`}
172
+ className="block truncate text-[12px] text-muted-foreground hover:text-foreground"
173
+ >
174
+ {contact.email}
175
+ </a>
176
+ ) : null}
177
+ </span>
178
+ </span>
179
+ ) : (
180
+ "—"
181
+ )}
182
+ </Field>
183
+
184
+ <Field label="Expected close">
185
+ {deal.closeDate ? (
186
+ <span className="flex items-center gap-2">
187
+ <span className="tabular">{shortDate(deal.closeDate)}</span>
188
+ {due ? (
189
+ <span
190
+ className={
191
+ due.tone === "overdue"
192
+ ? "text-[12px] font-medium text-destructive"
193
+ : "text-[12px] text-muted-foreground"
194
+ }
195
+ >
196
+ {due.label}
197
+ </span>
198
+ ) : null}
199
+ </span>
200
+ ) : (
201
+ "—"
202
+ )}
203
+ </Field>
153
204
 
154
- <section>
155
- <h2 className="mb-3 text-[13px] font-semibold">Activity</h2>
156
- <ActivityTimeline
157
- activities={activities}
158
- ownerName={data.ownerName}
159
- onLog={(kind, body) =>
160
- callFn("logActivity", {
161
- kind,
162
- body,
163
- dealId: deal.id,
164
- ...(deal.companyId ? { companyId: deal.companyId } : {}),
165
- })
166
- }
167
- />
168
- </section>
205
+ <Field label="Created">{relativeTime(deal.createdAt)}</Field>
206
+ </dl>
207
+ </aside>
169
208
  </div>
170
209
  </div>
171
210
  </>
@@ -185,8 +224,8 @@ function Field({
185
224
  }) {
186
225
  return (
187
226
  <div className="min-w-0">
188
- <dt className="text-[11px] text-muted-foreground">{label}</dt>
189
- <dd className="mt-1 truncate text-[13px]">{children}</dd>
227
+ <dt className="text-[11.5px] font-medium text-muted-foreground">{label}</dt>
228
+ <dd className="mt-1 min-w-0 truncate text-[13px]">{children}</dd>
190
229
  </div>
191
230
  );
192
231
  }
@@ -1,9 +1,10 @@
1
1
  import React from "react";
2
2
  import type { Metadata, PageProps } from "@pylonsync/react";
3
+ import { BRAND } from "@/lib/brand";
3
4
  import { DealView } from "./deal-view";
4
5
 
5
6
  export const metadata: Metadata = {
6
- title: "Deal",
7
+ title: `Deal · ${BRAND.name}`,
7
8
  robots: "noindex",
8
9
  };
9
10
 
@@ -9,15 +9,21 @@
9
9
  /* ---------------------------------------------------------------------------
10
10
  Design tokens.
11
11
 
12
- Tuned for a dense internal tool rather than a marketing page: a near-neutral
13
- surface ramp, hairline borders instead of shadows, and one accent used
14
- sparingly so status colour still means something. Dark is the primary theme —
15
- `app/layout.tsx` sets `class="dark"` — and light is a real, tested
16
- alternative, not an afterthought.
12
+ Tuned for a dense internal tool: a near-neutral surface ramp, hairline
13
+ borders instead of shadows, and one accent used sparingly so status colour
14
+ still means something. Light is the default; `.dark` holds a complete dark
15
+ set (add `class="dark"` to <html> in app/layout.tsx to switch).
17
16
 
18
- These are the same variable names shadcn/ui generates against, so
17
+ These are the variable names shadcn/ui generates against, so
19
18
  `npx shadcn@latest add <component>` drops in already themed.
20
19
  --------------------------------------------------------------------------- */
20
+ :root {
21
+ /* The brand accent: primary buttons, the brand mark, focus rings, and the
22
+ active nav icon. Change these two lines to re-colour the product. */
23
+ --brand: oklch(0.52 0.2 272);
24
+ --brand-dark: oklch(0.64 0.17 272);
25
+ }
26
+
21
27
  :root {
22
28
  --radius: 0.5rem;
23
29
 
@@ -28,7 +34,7 @@
28
34
  --popover: oklch(1 0 0);
29
35
  --popover-foreground: var(--foreground);
30
36
 
31
- --primary: oklch(0.55 0.204 274.5);
37
+ --primary: var(--brand);
32
38
  --primary-foreground: oklch(1 0 0);
33
39
  --secondary: oklch(0.968 0.002 286.4);
34
40
  --secondary-foreground: oklch(0.27 0.006 286);
@@ -40,7 +46,7 @@
40
46
 
41
47
  --border: oklch(0.918 0.004 286.3);
42
48
  --input: oklch(0.918 0.004 286.3);
43
- --ring: oklch(0.55 0.204 274.5);
49
+ --ring: var(--brand);
44
50
 
45
51
  /* Surfaces above the page: sidebar, popovers, hover rows. */
46
52
  --surface-1: oklch(0.985 0.001 286.4);
@@ -51,6 +57,7 @@
51
57
  --stage-lead: oklch(0.62 0.03 264);
52
58
  --stage-qualified: oklch(0.6 0.13 240);
53
59
  --stage-proposal: oklch(0.68 0.15 78);
60
+ --stage-negotiation: oklch(0.64 0.16 45);
54
61
  --stage-won: oklch(0.6 0.15 155);
55
62
  --stage-lost: oklch(0.6 0.11 25);
56
63
  }
@@ -63,7 +70,7 @@
63
70
  --popover: oklch(0.216 0.006 285.9);
64
71
  --popover-foreground: var(--foreground);
65
72
 
66
- --primary: oklch(0.62 0.19 274.5);
73
+ --primary: var(--brand-dark);
67
74
  --primary-foreground: oklch(1 0 0);
68
75
  --secondary: oklch(0.25 0.006 286);
69
76
  --secondary-foreground: oklch(0.93 0.002 286.3);
@@ -75,7 +82,7 @@
75
82
 
76
83
  --border: oklch(1 0 0 / 9%);
77
84
  --input: oklch(1 0 0 / 12%);
78
- --ring: oklch(0.62 0.19 274.5);
85
+ --ring: var(--brand-dark);
79
86
 
80
87
  --surface-1: oklch(0.186 0.004 285.9);
81
88
  --surface-2: oklch(0.216 0.006 285.9);
@@ -83,6 +90,7 @@
83
90
  --stage-lead: oklch(0.68 0.03 264);
84
91
  --stage-qualified: oklch(0.68 0.13 240);
85
92
  --stage-proposal: oklch(0.75 0.14 78);
93
+ --stage-negotiation: oklch(0.72 0.15 45);
86
94
  --stage-won: oklch(0.7 0.15 155);
87
95
  --stage-lost: oklch(0.68 0.14 25);
88
96
  }
@@ -118,6 +126,7 @@
118
126
  --color-stage-lead: var(--stage-lead);
119
127
  --color-stage-qualified: var(--stage-qualified);
120
128
  --color-stage-proposal: var(--stage-proposal);
129
+ --color-stage-negotiation: var(--stage-negotiation);
121
130
  --color-stage-won: var(--stage-won);
122
131
  --color-stage-lost: var(--stage-lost);
123
132
  }
@@ -143,15 +152,21 @@
143
152
  height: 100%;
144
153
  background-color: var(--color-background);
145
154
  color: var(--color-foreground);
146
- /* 13px is the density these screens are designed at; the slight negative
147
- tracking is what keeps Inter from looking loose at that size. */
148
- font-size: 13px;
155
+ /* 14px on phones, 13px from the md breakpoint up: the density these
156
+ screens are designed at on a desktop. */
157
+ font-size: 14px;
149
158
  line-height: 1.5;
150
- letter-spacing: -0.006em;
159
+ letter-spacing: -0.003em;
151
160
  -webkit-font-smoothing: antialiased;
152
161
  text-rendering: optimizeLegibility;
153
162
  }
154
163
 
164
+ @media (min-width: 768px) {
165
+ body {
166
+ font-size: 13px;
167
+ }
168
+ }
169
+
155
170
  button {
156
171
  cursor: pointer;
157
172
  }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect width="32" height="32" rx="8" fill="#4556d9"/><g fill="#fff"><rect x="6" y="7.5" width="20" height="4" rx="2"/><rect x="9" y="14" width="14" height="4" rx="2"/><rect x="12" y="20.5" width="8" height="4" rx="2"/></g></svg>
@@ -18,12 +18,14 @@ export default function RootLayout({ children }: LayoutProps) {
18
18
  <html lang="en">
19
19
  <head>
20
20
  <meta charSet="utf-8" />
21
- <meta name="viewport" content="width=device-width, initial-scale=1" />
22
- <title>__APP_NAME__</title>
21
+ <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
22
+ {/* No <title> here: each page's `metadata` sets "<Page> · <Brand>".
23
+ A title in the layout renders first and wins over the page's. */}
23
24
  {/* Tailwind is compiled by Pylon from app/globals.css and the
24
- stylesheet link is injected here automatically. Inter is declared in
25
- app.ts (fonts: [...]) and self-hosted by the build — @font-face, the
26
- preload link, and a size-adjusted fallback are injected too. */}
25
+ stylesheet link is injected here automatically. The typeface is
26
+ declared in app.ts (fonts: [...]) and self-hosted by the build;
27
+ @font-face, the preload link, and a size-adjusted fallback are
28
+ injected too. */}
27
29
  </head>
28
30
  <body className="h-full">{children}</body>
29
31
  </html>
@@ -1,9 +1,10 @@
1
1
  import React from "react";
2
2
  import type { Metadata, PageProps } from "@pylonsync/react";
3
+ import { BRAND } from "@/lib/brand";
3
4
  import { PipelineView } from "./pipeline-view";
4
5
 
5
6
  export const metadata: Metadata = {
6
- title: "Pipeline",
7
+ title: `Pipeline · ${BRAND.name}`,
7
8
  robots: "noindex",
8
9
  };
9
10
 
@@ -41,16 +41,16 @@ export function PipelineView({
41
41
  }, []);
42
42
 
43
43
  return (
44
- <RequireAuth title="CRM" description="Your team shares one pipeline. Anyone with an account sees it.">
44
+ <RequireAuth>
45
45
  <Workspace pathname="/">
46
46
  {(data) => (
47
47
  <>
48
- <PageHeader title="Pipeline" count={data.deals.length}>
49
- <Button size="sm" onClick={() => setDialogOpen(true)}>
48
+ <PageHeader title="Pipeline" count={data.navCounts["/"]}>
49
+ <Button size="sm" onClick={() => setDialogOpen(true)} title="New deal (c)">
50
50
  <Plus />
51
51
  New deal
52
- <Kbd className="ml-1 border-primary-foreground/25 bg-primary-foreground/10 text-primary-foreground/70">
53
- c
52
+ <Kbd className="ml-0.5 hidden border-primary-foreground/25 bg-primary-foreground/10 text-primary-foreground/75 md:inline-flex">
53
+ C
54
54
  </Kbd>
55
55
  </Button>
56
56
  </PageHeader>
@@ -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>