@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
@@ -0,0 +1,101 @@
1
+ import React from "react";
2
+ import { cn } from "@/lib/utils";
3
+
4
+ export interface FilterTab {
5
+ id: string;
6
+ label: string;
7
+ count?: number;
8
+ }
9
+
10
+ /**
11
+ * A row of view filters under the page header, each with its count. On a
12
+ * phone the row scrolls sideways inside itself instead of widening the page.
13
+ *
14
+ * Each filter is a toggle button in a labelled group; ←/→ move between them
15
+ * and Home/End jump to the ends.
16
+ */
17
+ export function FilterTabs({
18
+ tabs,
19
+ value,
20
+ onChange,
21
+ label,
22
+ trailing,
23
+ className,
24
+ }: {
25
+ tabs: FilterTab[];
26
+ value: string;
27
+ onChange: (id: string) => void;
28
+ /** Accessible name for the group, such as "Ticket status". */
29
+ label: string;
30
+ /** Extra controls at the end of the row, such as a toggle. */
31
+ trailing?: React.ReactNode;
32
+ className?: string;
33
+ }) {
34
+ function onKeyDown(event: React.KeyboardEvent<HTMLButtonElement>, index: number) {
35
+ const target =
36
+ event.key === "ArrowRight"
37
+ ? (index + 1) % tabs.length
38
+ : event.key === "ArrowLeft"
39
+ ? (index - 1 + tabs.length) % tabs.length
40
+ : event.key === "Home"
41
+ ? 0
42
+ : event.key === "End"
43
+ ? tabs.length - 1
44
+ : -1;
45
+ if (target < 0) return;
46
+ event.preventDefault();
47
+ const next = tabs[target];
48
+ onChange(next.id);
49
+ const list = event.currentTarget.parentElement;
50
+ list?.querySelector<HTMLButtonElement>(`[data-tab="${next.id}"]`)?.focus();
51
+ }
52
+
53
+ return (
54
+ <div
55
+ className={cn(
56
+ "flex h-11 shrink-0 items-center gap-3 border-b border-border px-3 md:px-5",
57
+ className,
58
+ )}
59
+ >
60
+ <div
61
+ role="group"
62
+ aria-label={label}
63
+ className="-mx-1 flex min-w-0 flex-1 items-center gap-0.5 overflow-x-auto px-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
64
+ >
65
+ {tabs.map((tab, index) => {
66
+ const selected = tab.id === value;
67
+ return (
68
+ <button
69
+ key={tab.id}
70
+ type="button"
71
+ data-tab={tab.id}
72
+ aria-pressed={selected}
73
+ tabIndex={selected ? 0 : -1}
74
+ onClick={() => onChange(tab.id)}
75
+ onKeyDown={(event) => onKeyDown(event, index)}
76
+ className={cn(
77
+ "flex h-7 shrink-0 items-center gap-1.5 rounded-md px-2.5 text-[12.5px] transition-colors",
78
+ selected
79
+ ? "bg-foreground/[0.07] font-medium text-foreground"
80
+ : "text-muted-foreground hover:bg-foreground/[0.04] hover:text-foreground",
81
+ )}
82
+ >
83
+ {tab.label}
84
+ {typeof tab.count === "number" ? (
85
+ <span
86
+ className={cn(
87
+ "tabular text-[11.5px]",
88
+ selected ? "text-foreground/60" : "text-muted-foreground/80",
89
+ )}
90
+ >
91
+ {tab.count}
92
+ </span>
93
+ ) : null}
94
+ </button>
95
+ );
96
+ })}
97
+ </div>
98
+ {trailing ? <div className="flex shrink-0 items-center gap-2">{trailing}</div> : null}
99
+ </div>
100
+ );
101
+ }
@@ -8,7 +8,7 @@ import { metrics, money, percent, type Deal } from "@/lib/pipeline";
8
8
  export function MetricsBar({ deals }: { deals: Deal[] }) {
9
9
  const m = metrics(deals);
10
10
  return (
11
- <dl className="grid grid-cols-2 gap-px border-b border-border bg-border sm:grid-cols-4">
11
+ <dl className="grid shrink-0 grid-cols-2 gap-px border-b border-border bg-border lg:grid-cols-4">
12
12
  <Metric
13
13
  label="Open pipeline"
14
14
  value={money(m.open)}
@@ -19,7 +19,7 @@ export function MetricsBar({ deals }: { deals: Deal[] }) {
19
19
  value={money(m.weighted)}
20
20
  hint="by stage probability"
21
21
  />
22
- <Metric label="Won" value={money(m.won)} hint="closed" />
22
+ <Metric label="Won" value={money(m.won)} hint="closed won" />
23
23
  <Metric label="Win rate" value={percent(m.winRate)} hint="of closed deals" />
24
24
  </dl>
25
25
  );
@@ -35,12 +35,12 @@ function Metric({
35
35
  hint: string;
36
36
  }) {
37
37
  return (
38
- <div className="bg-background px-4 py-3">
39
- <dt className="text-[11px] text-muted-foreground">{label}</dt>
40
- <dd className="tabular mt-0.5 text-[18px] font-semibold tracking-tight">
38
+ <div className="min-w-0 bg-background px-4 py-2.5 md:px-5 md:py-3.5">
39
+ <dt className="truncate text-[12px] text-muted-foreground">{label}</dt>
40
+ <dd className="tabular mt-1 text-[18px] font-semibold leading-none tracking-[-0.02em] md:text-[22px]">
41
41
  {value}
42
42
  </dd>
43
- <p className="mt-0.5 text-[11px] text-muted-foreground">{hint}</p>
43
+ <p className="mt-1 truncate text-[11.5px] text-muted-foreground md:mt-1.5">{hint}</p>
44
44
  </div>
45
45
  );
46
46
  }
@@ -0,0 +1,15 @@
1
+ import React from "react";
2
+ import { Building2, KanbanSquare, Users } from "lucide-react";
3
+
4
+ export interface NavEntry {
5
+ href: string;
6
+ label: string;
7
+ icon: React.ReactNode;
8
+ }
9
+
10
+ /** The sidebar's links, top to bottom. Add a view here to put it in the nav. */
11
+ export const NAV: NavEntry[] = [
12
+ { href: "/", label: "Pipeline", icon: <KanbanSquare /> },
13
+ { href: "/companies", label: "Companies", icon: <Building2 /> },
14
+ { href: "/contacts", label: "Contacts", icon: <Users /> },
15
+ ];
@@ -1,36 +1,72 @@
1
+ "use client";
2
+
1
3
  import React from "react";
4
+ import { Menu, Search } from "lucide-react";
2
5
  import { cn } from "@/lib/utils";
6
+ import { useShell } from "@/components/app-shell";
3
7
 
4
8
  /**
5
9
  * The bar at the top of every view: title on the left, actions on the right.
6
- * Fixed height so switching pages doesn't shift the content below it.
10
+ * Fixed height, so switching pages doesn't shift the content below it.
11
+ *
12
+ * Below the `md` breakpoint it also carries the menu button that opens the
13
+ * navigation drawer and a search button, since the sidebar is hidden there.
7
14
  */
8
15
  export function PageHeader({
9
16
  title,
10
17
  count,
18
+ leading,
11
19
  children,
12
20
  className,
13
21
  }: {
14
22
  title: string;
15
- /** Shown beside the title — the number of rows in view. */
23
+ /** Shown beside the title. Pass the same number the sidebar shows. */
16
24
  count?: number;
25
+ /** Rendered before the title, such as a back link on a detail page. */
26
+ leading?: React.ReactNode;
17
27
  children?: React.ReactNode;
18
28
  className?: string;
19
29
  }) {
30
+ const shell = useShell();
20
31
  return (
21
32
  <header
22
33
  className={cn(
23
- "flex h-12 shrink-0 items-center justify-between gap-3 border-b border-border px-4",
34
+ "flex h-13 shrink-0 items-center justify-between gap-2 border-b border-border px-3 md:gap-3 md:px-5",
24
35
  className,
25
36
  )}
26
37
  >
27
- <div className="flex min-w-0 items-baseline gap-2">
28
- <h1 className="truncate text-[13px] font-semibold">{title}</h1>
38
+ <div className="flex min-w-0 items-center gap-1.5">
39
+ {shell ? (
40
+ <button
41
+ type="button"
42
+ onClick={shell.openNav}
43
+ aria-label="Open navigation"
44
+ className="-ml-1 rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-foreground/[0.05] hover:text-foreground md:hidden"
45
+ >
46
+ <Menu className="size-[18px]" />
47
+ </button>
48
+ ) : null}
49
+ {leading}
50
+ <h1 className="truncate text-[14px] font-semibold tracking-[-0.01em]">{title}</h1>
29
51
  {typeof count === "number" ? (
30
- <span className="tabular text-[12px] text-muted-foreground">{count}</span>
52
+ <span className="tabular ml-0.5 rounded-full bg-foreground/[0.06] px-1.5 py-px text-[11.5px] font-medium text-muted-foreground">
53
+ {count}
54
+ </span>
55
+ ) : null}
56
+ </div>
57
+ <div className="flex shrink-0 items-center gap-1.5 md:gap-2">
58
+ {shell ? (
59
+ <button
60
+ type="button"
61
+ onClick={shell.openCommand}
62
+ aria-label="Search"
63
+ className="rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-foreground/[0.05] hover:text-foreground md:hidden"
64
+ >
65
+ <Search className="size-[18px]" />
66
+ </button>
31
67
  ) : null}
68
+ {children}
32
69
  </div>
33
- <div className="flex items-center gap-2">{children}</div>
34
70
  </header>
35
71
  );
36
72
  }
@@ -2,6 +2,7 @@ import React, { useState } from "react";
2
2
  import { cn } from "@/lib/utils";
3
3
  import { DealCard } from "@/components/deal-card";
4
4
  import { BOARD_STAGES, groupByStage, money, type Deal } from "@/lib/pipeline";
5
+ import { STAGE_DOT } from "@/components/stage-badge";
5
6
 
6
7
  /**
7
8
  * The pipeline, as columns you can drag deals between.
@@ -29,7 +30,7 @@ export function PipelineBoard({
29
30
  const columns = groupByStage(deals, BOARD_STAGES);
30
31
 
31
32
  return (
32
- <div className="flex h-full gap-3 overflow-x-auto p-4">
33
+ <div className="flex h-full snap-x snap-mandatory scroll-px-4 gap-3 overflow-x-auto p-4 md:snap-none md:px-5">
33
34
  {columns.map((column) => {
34
35
  const isTarget = over === column.stage.id;
35
36
  return (
@@ -58,19 +59,24 @@ export function PipelineBoard({
58
59
  onMove(id, column.stage.id);
59
60
  }}
60
61
  className={cn(
61
- "flex w-[268px] shrink-0 flex-col rounded-xl border transition-colors",
62
+ "flex w-[84vw] shrink-0 snap-start flex-col rounded-xl border transition-colors",
63
+ "md:w-auto md:min-w-[208px] md:max-w-[340px] md:flex-1",
62
64
  isTarget
63
- ? "border-ring/60 bg-surface-2/60"
64
- : "border-border bg-surface-1/50",
65
+ ? "border-ring/50 bg-primary/[0.04]"
66
+ : "border-border/70 bg-surface-1",
65
67
  )}
66
68
  aria-label={column.stage.label}
67
69
  >
68
- <header className="flex items-center gap-2 px-3 py-2.5">
69
- <h2 className="text-[12px] font-medium">{column.stage.label}</h2>
70
- <span className="tabular text-[11px] text-muted-foreground">
70
+ <header className="flex items-center gap-2 px-3 pb-2 pt-3">
71
+ <span
72
+ aria-hidden="true"
73
+ className={cn("size-2 shrink-0 rounded-full", STAGE_DOT[column.stage.id])}
74
+ />
75
+ <h2 className="text-[12.5px] font-semibold">{column.stage.label}</h2>
76
+ <span className="tabular text-[12px] text-muted-foreground">
71
77
  {column.deals.length}
72
78
  </span>
73
- <span className="tabular ml-auto text-[11px] text-muted-foreground">
79
+ <span className="tabular ml-auto text-[12px] font-medium text-muted-foreground">
74
80
  {money(column.total)}
75
81
  </span>
76
82
  </header>
@@ -92,8 +98,8 @@ export function PipelineBoard({
92
98
  />
93
99
  ))}
94
100
  {column.deals.length === 0 ? (
95
- <p className="px-1 py-6 text-center text-[11px] text-muted-foreground">
96
- {isTarget ? "Drop here" : "Nothing here"}
101
+ <p className="rounded-lg border border-dashed border-border px-3 py-6 text-center text-[12px] text-muted-foreground">
102
+ {isTarget ? "Drop to move here" : `No deals in ${column.stage.label}`}
97
103
  </p>
98
104
  ) : null}
99
105
  </div>
@@ -1,8 +1,10 @@
1
1
  "use client";
2
2
 
3
- import React from "react";
3
+ import React, { useState } from "react";
4
4
  import { useAuth } from "@pylonsync/client";
5
- import { AuthForm } from "@/components/auth-form";
5
+ import { BRAND } from "@/lib/brand";
6
+ import { AuthForm, type AuthMode } from "@/components/auth-form";
7
+ import { BrandMark } from "@/components/brand-mark";
6
8
 
7
9
  /**
8
10
  * Client-side auth gate.
@@ -18,44 +20,40 @@ import { AuthForm } from "@/components/auth-form";
18
20
  * It also removes a full page load from the sign-in path: authenticating swaps
19
21
  * this component's children in place instead of navigating.
20
22
  */
21
- export function RequireAuth({
22
- title,
23
- description,
24
- children,
25
- }: {
26
- title: string;
27
- description: string;
28
- children: React.ReactNode;
29
- }) {
23
+ export function RequireAuth({ children }: { children: React.ReactNode }) {
30
24
  const { isSignedIn, isLoaded } = useAuth();
25
+ const [mode, setMode] = useState<AuthMode>("login");
31
26
 
32
27
  // `isLoaded` covers the beat before the engine has resolved the stored token.
33
28
  // Rendering the form during it would flash a sign-in screen at someone who is
34
29
  // already signed in.
35
30
  if (!isLoaded) {
36
31
  return (
37
- <main className="flex min-h-screen items-center justify-center">
38
- <span className="text-[13px] text-muted-foreground">Loading…</span>
32
+ <main className="flex min-h-dvh items-center justify-center" aria-busy="true">
33
+ <BrandMark className="size-8 animate-pulse" />
34
+ <span className="sr-only">Loading {BRAND.name}</span>
39
35
  </main>
40
36
  );
41
37
  }
42
38
 
43
39
  if (!isSignedIn) {
44
40
  return (
45
- <main className="flex min-h-screen items-center justify-center px-6">
46
- <div className="w-full max-w-[320px]">
47
- <div className="mb-7 flex items-center gap-2">
48
- <span className="flex size-7 items-center justify-center rounded-md bg-primary text-[12px] font-bold text-primary-foreground">
49
- {title.slice(0, 1).toUpperCase()}
50
- </span>
51
- <span className="text-[15px] font-semibold tracking-tight">{title}</span>
41
+ <main className="flex min-h-dvh items-center justify-center bg-surface-1 px-4 py-10">
42
+ <div className="w-full max-w-[380px]">
43
+ <div className="mb-6 flex items-center justify-center gap-2.5">
44
+ <BrandMark className="size-8 rounded-[9px]" />
45
+ <span className="text-[17px] font-semibold tracking-[-0.015em]">{BRAND.name}</span>
52
46
  </div>
53
- <h1 className="text-[19px] font-semibold tracking-tight">
54
- Sign in to your workspace
55
- </h1>
56
- <p className="mt-1 text-[13px] text-muted-foreground">{description}</p>
57
- <div className="mt-6">
58
- <AuthForm />
47
+ <div className="rounded-xl border border-border bg-background p-6 shadow-[0_1px_2px_rgb(0_0_0/0.04),0_12px_32px_-12px_rgb(0_0_0/0.12)] sm:p-7">
48
+ <h1 className="text-[18px] font-semibold tracking-[-0.015em]">
49
+ {mode === "login" ? `Sign in to ${BRAND.name}` : `Create your ${BRAND.name} account`}
50
+ </h1>
51
+ <p className="mt-1.5 text-[13px] leading-5 text-muted-foreground">
52
+ {BRAND.description}
53
+ </p>
54
+ <div className="mt-6">
55
+ <AuthForm mode={mode} onModeChange={setMode} />
56
+ </div>
59
57
  </div>
60
58
  </div>
61
59
  </main>
@@ -1,112 +1,117 @@
1
1
  import React from "react";
2
2
  import { Link } from "@pylonsync/react";
3
- import { Building2, Command, LayoutGrid, LogOut, Users } from "lucide-react";
3
+ import { LogOut, Search } from "lucide-react";
4
4
  import { cn } from "@/lib/utils";
5
+ import { BRAND } from "@/lib/brand";
6
+ import { NAV } from "@/components/nav";
5
7
  import { Avatar } from "@/components/avatar";
8
+ import { BrandMark } from "@/components/brand-mark";
6
9
  import { Kbd } from "@/components/kbd";
7
10
 
8
- export interface NavItem {
9
- href: string;
10
- label: string;
11
- icon: React.ReactNode;
12
- count?: number;
11
+ /** True when `href` is the section `pathname` belongs to. */
12
+ export function isActive(href: string, pathname: string): boolean {
13
+ if (href === "/") return pathname === "/";
14
+ return pathname === href || pathname.startsWith(`${href}/`);
13
15
  }
14
16
 
15
- export const NAV: Array<Omit<NavItem, "count">> = [
16
- { href: "/", label: "Pipeline", icon: <LayoutGrid /> },
17
- { href: "/companies", label: "Companies", icon: <Building2 /> },
18
- { href: "/contacts", label: "Contacts", icon: <Users /> },
19
- ];
20
-
21
17
  /**
22
- * The fixed left rail. Presentational: the active path, the counts, and the
23
- * sign-out handler all arrive as props, so it renders identically in a test.
18
+ * The navigation rail: brand, search, links with counts, and the signed-in
19
+ * person. The same component renders as the fixed rail on wide screens and
20
+ * inside the drawer on phones (see components/app-shell.tsx).
21
+ *
22
+ * Presentational: the path, counts, and handlers arrive as props, so it
23
+ * renders the same in a test.
24
24
  */
25
25
  export function Sidebar({
26
- workspace,
27
- email,
26
+ user,
28
27
  pathname,
29
28
  counts,
30
29
  onOpenCommand,
30
+ onNavigate,
31
31
  onSignOut,
32
+ className,
32
33
  }: {
33
- workspace: string;
34
- email: string;
34
+ user: { name: string; email: string };
35
35
  pathname: string;
36
+ /** Badge per nav href. Omit a key to show no number. */
36
37
  counts?: Record<string, number>;
37
38
  onOpenCommand: () => void;
39
+ /** Called after a link is chosen, so the phone drawer can close. */
40
+ onNavigate?: () => void;
38
41
  onSignOut: () => void;
42
+ className?: string;
39
43
  }) {
40
44
  return (
41
- <aside className="flex w-[224px] shrink-0 flex-col border-r border-border bg-surface-1">
42
- <div className="flex h-12 items-center gap-2 px-3">
43
- <span className="flex size-6 shrink-0 items-center justify-center rounded-md bg-primary text-[11px] font-bold text-primary-foreground">
44
- {workspace.slice(0, 1).toUpperCase()}
45
+ <div className={cn("flex h-full w-full flex-col bg-surface-1", className)}>
46
+ <div className="flex h-13 shrink-0 items-center gap-2.5 px-4">
47
+ <BrandMark />
48
+ <span className="truncate text-[14px] font-semibold tracking-[-0.01em]">
49
+ {BRAND.name}
45
50
  </span>
46
- <span className="truncate text-[13px] font-semibold">{workspace}</span>
47
51
  </div>
48
52
 
49
- <div className="px-2 pb-2">
53
+ <div className="px-3 pb-3">
50
54
  <button
51
55
  type="button"
52
56
  onClick={onOpenCommand}
53
57
  className={cn(
54
- "flex w-full items-center gap-2 rounded-md border border-border bg-background px-2 py-1.5",
55
- "text-[12px] text-muted-foreground transition-colors hover:border-ring/40 hover:text-foreground",
58
+ "flex h-8 w-full items-center gap-2 rounded-md border border-border bg-background px-2.5",
59
+ "text-[12.5px] text-muted-foreground shadow-[0_1px_1px_rgb(0_0_0/0.03)] transition-colors",
60
+ "hover:border-foreground/15 hover:text-foreground",
56
61
  )}
57
62
  >
58
- <Command className="size-3.5" />
59
- <span className="flex-1 text-left">Search…</span>
60
- <Kbd>⌘K</Kbd>
63
+ <Search className="size-3.5" />
64
+ <span className="flex-1 text-left">Search</span>
65
+ <Kbd className="max-md:hidden">⌘K</Kbd>
61
66
  </button>
62
67
  </div>
63
68
 
64
- <nav className="flex-1 space-y-0.5 px-2" aria-label="Main">
69
+ <nav className="flex-1 space-y-px overflow-y-auto px-3" aria-label="Main">
65
70
  {NAV.map((item) => {
66
- const active =
67
- item.href === "/" ? pathname === "/" : pathname.startsWith(item.href);
71
+ const active = isActive(item.href, pathname);
72
+ const count = counts?.[item.href];
68
73
  return (
69
74
  <Link
70
75
  key={item.href}
71
76
  href={item.href}
77
+ onClick={onNavigate}
72
78
  aria-current={active ? "page" : undefined}
73
79
  className={cn(
74
- "flex h-7 items-center gap-2 rounded-md px-2 text-[13px] transition-colors",
75
- "[&_svg]:size-3.5 [&_svg]:shrink-0",
80
+ "flex h-8 items-center gap-2.5 rounded-md px-2.5 text-[13px] transition-colors md:h-7.5",
81
+ "[&_svg]:size-4 [&_svg]:shrink-0",
76
82
  active
77
- ? "bg-surface-2 font-medium text-foreground"
78
- : "text-muted-foreground hover:bg-surface-2/60 hover:text-foreground",
83
+ ? "bg-foreground/[0.06] font-medium text-foreground [&_svg]:text-primary"
84
+ : "text-muted-foreground hover:bg-foreground/[0.04] hover:text-foreground",
79
85
  )}
80
86
  >
81
87
  {item.icon}
82
88
  <span className="flex-1 truncate">{item.label}</span>
83
- {counts?.[item.href] ? (
84
- <span className="tabular text-[11px] text-muted-foreground">
85
- {counts[item.href]}
86
- </span>
89
+ {typeof count === "number" ? (
90
+ <span className="tabular text-[11.5px] text-muted-foreground">{count}</span>
87
91
  ) : null}
88
92
  </Link>
89
93
  );
90
94
  })}
91
95
  </nav>
92
96
 
93
- <div className="border-t border-border p-2">
94
- <div className="flex items-center gap-2 rounded-md px-1.5 py-1">
95
- <Avatar name={email} size="sm" />
96
- <span className="min-w-0 flex-1 truncate text-[12px] text-muted-foreground">
97
- {email}
98
- </span>
97
+ <div className="border-t border-border p-3">
98
+ <div className="flex items-center gap-2.5">
99
+ <Avatar name={user.name || user.email} />
100
+ <div className="min-w-0 flex-1 leading-tight">
101
+ <p className="truncate text-[12.5px] font-medium">{user.name || "Signed in"}</p>
102
+ <p className="truncate text-[11.5px] text-muted-foreground">{user.email}</p>
103
+ </div>
99
104
  <button
100
105
  type="button"
101
106
  onClick={onSignOut}
102
107
  title="Sign out"
103
108
  aria-label="Sign out"
104
- className="rounded p-1 text-muted-foreground transition-colors hover:bg-surface-2 hover:text-foreground"
109
+ className="rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-foreground/[0.06] hover:text-foreground"
105
110
  >
106
- <LogOut className="size-3.5" />
111
+ <LogOut className="size-4" />
107
112
  </button>
108
113
  </div>
109
114
  </div>
110
- </aside>
115
+ </div>
111
116
  );
112
117
  }
@@ -2,10 +2,12 @@ import React from "react";
2
2
  import { cn } from "@/lib/utils";
3
3
  import { stageById } from "@/lib/pipeline";
4
4
 
5
- const DOT: Record<string, string> = {
5
+ /** The colour dot for each stage, shared by the badge and the board columns. */
6
+ export const STAGE_DOT: Record<string, string> = {
6
7
  lead: "bg-stage-lead",
7
8
  qualified: "bg-stage-qualified",
8
9
  proposal: "bg-stage-proposal",
10
+ negotiation: "bg-stage-negotiation",
9
11
  won: "bg-stage-won",
10
12
  lost: "bg-stage-lost",
11
13
  };
@@ -25,7 +27,7 @@ export function StageBadge({
25
27
  return (
26
28
  <span className={cn("inline-flex items-center gap-1.5 whitespace-nowrap", className)}>
27
29
  <span
28
- className={cn("size-1.5 shrink-0 rounded-full", DOT[stage] ?? "bg-muted-foreground")}
30
+ className={cn("size-1.5 shrink-0 rounded-full", STAGE_DOT[stage] ?? "bg-muted-foreground")}
29
31
  />
30
32
  <span className="text-muted-foreground">{meta?.label ?? stage}</span>
31
33
  </span>
@@ -5,15 +5,16 @@ import { cva, type VariantProps } from "class-variance-authority";
5
5
  import { cn } from "@/lib/utils";
6
6
 
7
7
  const buttonVariants = cva(
8
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
8
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-[13px] font-medium transition-[color,background-color,box-shadow,transform] duration-150 active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
9
9
  {
10
10
  variants: {
11
11
  variant: {
12
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
12
+ default:
13
+ "bg-primary text-primary-foreground shadow-[inset_0_1px_0_rgb(255_255_255/0.15),0_1px_2px_rgb(0_0_0/0.1)] hover:bg-primary/90",
13
14
  destructive:
14
15
  "bg-destructive text-white hover:bg-destructive/90",
15
16
  outline:
16
- "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
17
+ "border border-input bg-background shadow-[0_1px_1px_rgb(0_0_0/0.03)] hover:bg-accent hover:text-accent-foreground",
17
18
  secondary:
18
19
  "bg-secondary text-secondary-foreground hover:bg-secondary/80",
19
20
  ghost: "hover:bg-accent hover:text-accent-foreground",
@@ -21,7 +22,7 @@ const buttonVariants = cva(
21
22
  },
22
23
  size: {
23
24
  default: "h-9 px-4 py-2",
24
- sm: "h-8 rounded-md px-3 text-xs",
25
+ sm: "h-8 rounded-md px-3 text-[12.5px] md:h-7.5 [&_svg]:size-3.5",
25
26
  lg: "h-10 rounded-md px-8",
26
27
  icon: "h-9 w-9",
27
28
  },
@@ -35,7 +35,7 @@ const DialogContent = React.forwardRef<
35
35
  <DialogPrimitive.Content
36
36
  ref={ref}
37
37
  className={cn(
38
- "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 rounded-xl border bg-background p-6 shadow-lg duration-200",
38
+ "fixed left-[50%] top-[50%] z-50 grid max-h-[calc(100dvh-2rem)] w-[calc(100%-2rem)] max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 overflow-y-auto rounded-xl border bg-background p-5 shadow-[0_24px_48px_-12px_rgb(0_0_0/0.25)] duration-200 sm:p-6",
39
39
  "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
40
40
  className,
41
41
  )}
@@ -12,7 +12,7 @@ function Input({
12
12
  type={type}
13
13
  data-slot="input"
14
14
  className={cn(
15
- "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors",
15
+ "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm md:text-[13px] transition-colors",
16
16
  "placeholder:text-muted-foreground",
17
17
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
18
18
  "disabled:cursor-not-allowed disabled:opacity-50",
@@ -22,7 +22,7 @@ function Select({
22
22
  <select
23
23
  data-slot="select"
24
24
  className={cn(
25
- "flex h-9 w-full appearance-none rounded-md border border-input bg-transparent py-1 pl-3 pr-8 text-sm shadow-sm transition-colors",
25
+ "flex h-9 w-full appearance-none rounded-md border border-input bg-transparent py-1 pl-3 pr-8 text-base shadow-sm md:text-[13px] transition-colors",
26
26
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
27
27
  "disabled:cursor-not-allowed disabled:opacity-50",
28
28
  className,
@@ -10,7 +10,7 @@ function Textarea({
10
10
  <textarea
11
11
  data-slot="textarea"
12
12
  className={cn(
13
- "flex min-h-16 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm transition-colors",
13
+ "flex min-h-16 w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm md:text-[13px] transition-colors",
14
14
  "placeholder:text-muted-foreground",
15
15
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
16
16
  "disabled:cursor-not-allowed disabled:opacity-50",