@pylonsync/create-pylon 0.19.1 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/create-pylon.js +30 -7
- package/package.json +1 -1
- package/templates/_root/AGENTS.md +1 -1
- package/templates/agency/.env.example +7 -0
- package/templates/agency/AGENTS.md +1 -1
- package/templates/agency/README.md +28 -3
- package/templates/agency/app/(marketing)/contact-form.tsx +20 -18
- package/templates/agency/app/(marketing)/page.tsx +3 -3
- package/templates/agency/app/(marketing)/work/page.tsx +3 -3
- package/templates/agency/app/auth-form.tsx +4 -4
- package/templates/agency/app/dashboard/dashboard-client.tsx +110 -64
- package/templates/agency/app/dashboard/page.tsx +14 -16
- package/templates/agency/app/icon.svg +3 -0
- package/templates/agency/app/login/page.tsx +12 -14
- package/templates/agency/components/marketing.tsx +12 -5
- package/templates/agency/functions/seedStudioBackoffice.ts +42 -11
- package/templates/agency/lib/agency.ts +22 -0
- package/templates/agency/lib/demo.ts +118 -0
- package/templates/agency/lib/site.config.ts +19 -13
- package/templates/agency/public/favicon.ico +0 -0
- package/templates/agency/tests/agency.test.ts +57 -0
- package/templates/ai-chat/.env.example +13 -27
- package/templates/ai-chat/AGENTS.md +1 -1
- package/templates/ai-chat/README.md +53 -60
- package/templates/ai-chat/app/(chat)/c/[id]/page.tsx +19 -0
- package/templates/ai-chat/app/(chat)/chat-client.tsx +657 -622
- package/templates/ai-chat/app/(chat)/layout.tsx +6 -43
- package/templates/ai-chat/app/(chat)/not-found.tsx +6 -10
- package/templates/ai-chat/app/(chat)/page.tsx +7 -11
- package/templates/ai-chat/app/auth-form.tsx +45 -38
- package/templates/ai-chat/app/error.tsx +9 -12
- package/templates/ai-chat/app/globals.css +464 -102
- package/templates/ai-chat/app/layout.tsx +11 -19
- package/templates/ai-chat/app/login/page.tsx +39 -24
- package/templates/ai-chat/app.ts +118 -43
- package/templates/ai-chat/components/chat/composer.tsx +193 -0
- package/templates/ai-chat/components/chat/empty-state.tsx +65 -0
- package/templates/ai-chat/components/chat/icons.tsx +198 -0
- package/templates/ai-chat/components/chat/markdown.tsx +164 -0
- package/templates/ai-chat/components/chat/message.tsx +183 -0
- package/templates/ai-chat/components/chat/setup.tsx +71 -0
- package/templates/ai-chat/components/chat/sidebar.tsx +288 -0
- package/templates/ai-chat/functions/_beginTurn.ts +145 -0
- package/templates/ai-chat/functions/_finishTurn.ts +55 -0
- package/templates/ai-chat/functions/assistantStatus.ts +13 -0
- package/templates/ai-chat/functions/claimGuestHistory.ts +39 -0
- package/templates/ai-chat/functions/createConversation.ts +28 -0
- package/templates/ai-chat/functions/deleteConversation.ts +15 -20
- package/templates/ai-chat/functions/prepareGuestClaim.ts +32 -0
- package/templates/ai-chat/functions/renameConversation.ts +19 -0
- package/templates/ai-chat/functions/respond.ts +88 -0
- package/templates/ai-chat/functions/seedExamples.ts +46 -0
- package/templates/ai-chat/functions/stopResponse.ts +30 -0
- package/templates/ai-chat/lib/brand-icon.ts +7 -0
- package/templates/ai-chat/lib/chat.ts +277 -0
- package/templates/ai-chat/lib/claim.ts +15 -0
- package/templates/ai-chat/lib/examples.ts +179 -0
- package/templates/ai-chat/lib/highlight.ts +107 -0
- package/templates/ai-chat/lib/markdown.ts +317 -0
- package/templates/ai-chat/lib/provider.ts +38 -0
- package/templates/ai-chat/lib/site.config.ts +55 -39
- package/templates/ai-chat/tests/chat.test.ts +174 -0
- package/templates/ai-chat/tests/components.test.tsx +57 -0
- package/templates/ai-chat/tests/markdown.test.ts +88 -0
- package/templates/ai-chat/tests/provider.test.ts +32 -0
- package/templates/ai-studio/AGENTS.md +1 -1
- package/templates/backend/consumer/apps/api/app/layout.tsx +33 -0
- package/templates/backend/consumer/apps/api/app/page.tsx +54 -0
- package/templates/backend/consumer/apps/api/app.ts +166 -0
- package/templates/backend/consumer/apps/api/functions/addComment.ts +24 -0
- package/templates/backend/consumer/apps/api/functions/createPost.ts +19 -36
- package/templates/backend/consumer/apps/api/functions/deletePost.ts +15 -13
- package/templates/backend/consumer/apps/api/functions/myProfile.ts +5 -8
- package/templates/backend/consumer/apps/api/functions/seedDemo.ts +95 -0
- package/templates/backend/consumer/apps/api/functions/setFollow.ts +36 -0
- package/templates/backend/consumer/apps/api/functions/setLike.ts +36 -0
- package/templates/backend/consumer/apps/api/functions/upsertProfile.ts +43 -37
- package/templates/backend/consumer/apps/api/lib/seed.ts +89 -0
- package/templates/backend/consumer/apps/api/lib/social.ts +50 -0
- package/templates/backend/consumer/apps/api/package.json +8 -2
- package/templates/backend/consumer/apps/api/public/images/posts/arch.jpg +0 -0
- package/templates/backend/consumer/apps/api/public/images/posts/coffee.jpg +0 -0
- package/templates/backend/consumer/apps/api/public/images/posts/dog.jpg +0 -0
- package/templates/backend/consumer/apps/api/public/images/posts/lisbon.jpg +0 -0
- package/templates/backend/consumer/apps/api/public/images/posts/ramen.jpg +0 -0
- package/templates/backend/consumer/apps/api/public/images/posts/run.jpg +0 -0
- package/templates/backend/consumer/apps/api/public/images/posts/sunset.jpg +0 -0
- package/templates/backend/consumer/apps/api/tsconfig.json +12 -2
- package/templates/barebones/AGENTS.md +1 -1
- package/templates/chat/AGENTS.md +1 -1
- package/templates/chat/README.md +43 -21
- package/templates/chat/app/chat-client.tsx +495 -85
- package/templates/chat/app/error.tsx +1 -1
- package/templates/chat/app/globals.css +170 -54
- package/templates/chat/app/layout.tsx +12 -9
- package/templates/chat/app/not-found.tsx +4 -2
- package/templates/chat/app/page.tsx +9 -19
- package/templates/chat/app.ts +96 -17
- package/templates/chat/components/chat/avatar.tsx +45 -0
- package/templates/chat/components/chat/composer.tsx +110 -0
- package/templates/chat/components/chat/message-list.tsx +285 -0
- package/templates/chat/components/chat/sidebar.tsx +190 -0
- package/templates/chat/functions/joinChat.ts +83 -0
- package/templates/chat/functions/renameMember.ts +25 -0
- package/templates/chat/lib/chat.ts +188 -0
- package/templates/chat/lib/seed.ts +78 -0
- package/templates/chat/tests/chat.test.ts +159 -0
- package/templates/chat/tests/composer.test.tsx +54 -0
- package/templates/consumer/AGENTS.md +1 -1
- package/templates/consumer/README.md +3 -3
- package/templates/consumer/app/globals.css +10 -3
- package/templates/consumer/app/icon.svg +1 -0
- package/templates/consumer/components/social/avatar.tsx +25 -11
- package/templates/consumer/functions/seedFeed.ts +3 -3
- package/templates/consumer/lib/seed.ts +43 -85
- package/templates/consumer/public/favicon.ico +0 -0
- package/templates/consumer/public/images/posts/arch.jpg +0 -0
- package/templates/consumer/public/images/posts/coffee.jpg +0 -0
- package/templates/consumer/public/images/posts/dog.jpg +0 -0
- package/templates/consumer/public/images/posts/lisbon.jpg +0 -0
- package/templates/consumer/public/images/posts/ramen.jpg +0 -0
- package/templates/consumer/public/images/posts/run.jpg +0 -0
- package/templates/consumer/public/images/posts/sunset.jpg +0 -0
- package/templates/consumer/tests/seed.test.ts +39 -0
- package/templates/creator/.env.example +7 -0
- package/templates/creator/AGENTS.md +1 -1
- package/templates/creator/README.md +24 -5
- package/templates/creator/app/(marketing)/newsletter-signup.tsx +33 -12
- package/templates/creator/app/auth-form.tsx +7 -7
- package/templates/creator/app/dashboard/dashboard-client.tsx +137 -100
- package/templates/creator/app/dashboard/page.tsx +18 -18
- package/templates/creator/app/icon.svg +2 -0
- package/templates/creator/app/login/page.tsx +14 -14
- package/templates/creator/app.ts +4 -4
- package/templates/creator/functions/seedDemo.ts +32 -0
- package/templates/creator/functions/subscribe.ts +4 -15
- package/templates/creator/lib/demo.ts +94 -0
- package/templates/creator/lib/site.config.ts +15 -10
- package/templates/creator/lib/stats.ts +35 -0
- package/templates/creator/public/favicon.ico +0 -0
- package/templates/creator/tests/counter.test.ts +92 -0
- package/templates/creator/tests/live-count.test.tsx +45 -0
- package/templates/crm/AGENTS.md +1 -1
- package/templates/crm/README.md +22 -1
- package/templates/crm/app/apple-icon.png +0 -0
- package/templates/crm/app/companies/companies-view.tsx +32 -14
- package/templates/crm/app/companies/page.tsx +2 -1
- package/templates/crm/app/contacts/contacts-view.tsx +34 -10
- package/templates/crm/app/contacts/page.tsx +2 -1
- package/templates/crm/app/deals/[id]/deal-view.tsx +137 -98
- package/templates/crm/app/deals/[id]/page.tsx +2 -1
- package/templates/crm/app/globals.css +29 -14
- package/templates/crm/app/icon.svg +1 -0
- package/templates/crm/app/layout.tsx +7 -5
- package/templates/crm/app/page.tsx +2 -1
- package/templates/crm/app/pipeline-view.tsx +5 -5
- package/templates/crm/app/workspace.tsx +29 -17
- package/templates/crm/app.ts +5 -5
- package/templates/crm/components/activity-timeline.tsx +14 -4
- package/templates/crm/components/app-shell.tsx +94 -0
- package/templates/crm/components/auth-form.tsx +35 -5
- package/templates/crm/components/avatar.tsx +5 -1
- package/templates/crm/components/board-skeleton.tsx +5 -5
- package/templates/crm/components/brand-mark.tsx +25 -0
- package/templates/crm/components/command-palette.tsx +17 -17
- package/templates/crm/components/data-table.tsx +97 -36
- package/templates/crm/components/deal-card.tsx +23 -27
- package/templates/crm/components/filter-tabs.tsx +101 -0
- package/templates/crm/components/metrics-bar.tsx +6 -6
- package/templates/crm/components/nav.tsx +15 -0
- package/templates/crm/components/page-header.tsx +43 -7
- package/templates/crm/components/pipeline-board.tsx +16 -10
- package/templates/crm/components/require-auth.tsx +24 -26
- package/templates/crm/components/sidebar.tsx +54 -49
- package/templates/crm/components/stage-badge.tsx +4 -2
- package/templates/crm/components/ui/button.tsx +5 -4
- package/templates/crm/components/ui/dialog.tsx +1 -1
- package/templates/crm/components/ui/input.tsx +1 -1
- package/templates/crm/components/ui/select.tsx +1 -1
- package/templates/crm/components/ui/textarea.tsx +1 -1
- package/templates/crm/functions/seedWorkspace.ts +32 -17
- package/templates/crm/lib/brand.ts +9 -0
- package/templates/crm/lib/demo-team.ts +51 -0
- package/templates/crm/lib/pipeline.ts +37 -0
- package/templates/crm/lib/search.ts +4 -3
- package/templates/crm/lib/seed.ts +53 -8
- package/templates/crm/public/favicon.ico +0 -0
- package/templates/crm/tests/components.test.tsx +5 -5
- package/templates/crm/tests/demo-team.test.ts +18 -0
- package/templates/crm/tests/pipeline.test.ts +59 -3
- package/templates/directory/.env.example +7 -0
- package/templates/directory/AGENTS.md +1 -1
- package/templates/directory/README.md +22 -3
- package/templates/directory/app/(marketing)/directory-browse.tsx +30 -12
- package/templates/directory/app/(marketing)/page.tsx +6 -4
- package/templates/directory/app/auth-form.tsx +4 -4
- package/templates/directory/app/dashboard/dashboard-client.tsx +177 -90
- package/templates/directory/app/dashboard/page.tsx +16 -14
- package/templates/directory/app/icon.svg +4 -0
- package/templates/directory/app/login/page.tsx +16 -15
- package/templates/directory/functions/seedDemo.ts +43 -0
- package/templates/directory/lib/demo.ts +145 -0
- package/templates/directory/lib/directory.ts +27 -0
- package/templates/directory/lib/site.config.ts +21 -16
- package/templates/directory/public/favicon.ico +0 -0
- package/templates/directory/tests/directory.test.ts +46 -0
- package/templates/expo/consumer/apps/expo/App.tsx +360 -288
- package/templates/expo/consumer/apps/expo/app.json +9 -1
- package/templates/expo/consumer/apps/expo/package.json +2 -1
- package/templates/helpdesk/AGENTS.md +1 -1
- package/templates/helpdesk/README.md +21 -0
- package/templates/helpdesk/app/apple-icon.png +0 -0
- package/templates/helpdesk/app/customers/customers-view.tsx +23 -7
- package/templates/helpdesk/app/customers/page.tsx +2 -1
- package/templates/helpdesk/app/globals.css +29 -14
- package/templates/helpdesk/app/icon.svg +1 -0
- package/templates/helpdesk/app/inbox-view.tsx +66 -47
- package/templates/helpdesk/app/layout.tsx +7 -5
- package/templates/helpdesk/app/page.tsx +4 -7
- package/templates/helpdesk/app/tickets/[id]/page.tsx +2 -1
- package/templates/helpdesk/app/tickets/[id]/ticket-view.tsx +134 -97
- package/templates/helpdesk/app/workspace.tsx +33 -22
- package/templates/helpdesk/app.ts +2 -2
- package/templates/helpdesk/components/app-shell.tsx +94 -0
- package/templates/helpdesk/components/auth-form.tsx +35 -5
- package/templates/helpdesk/components/avatar.tsx +5 -1
- package/templates/helpdesk/components/brand-mark.tsx +28 -0
- package/templates/helpdesk/components/command-palette.tsx +17 -17
- package/templates/helpdesk/components/data-table.tsx +97 -36
- package/templates/helpdesk/components/filter-tabs.tsx +101 -0
- package/templates/helpdesk/components/nav.tsx +14 -0
- package/templates/helpdesk/components/page-header.tsx +43 -7
- package/templates/helpdesk/components/priority-badge.tsx +49 -6
- package/templates/helpdesk/components/require-auth.tsx +24 -26
- package/templates/helpdesk/components/sidebar.tsx +54 -48
- package/templates/helpdesk/components/sla-indicator.tsx +5 -8
- package/templates/helpdesk/components/thread.tsx +7 -7
- package/templates/helpdesk/components/ticket-list.tsx +79 -19
- package/templates/helpdesk/components/ui/button.tsx +5 -4
- package/templates/helpdesk/components/ui/dialog.tsx +1 -1
- package/templates/helpdesk/components/ui/input.tsx +1 -1
- package/templates/helpdesk/components/ui/select.tsx +1 -1
- package/templates/helpdesk/components/ui/textarea.tsx +1 -1
- package/templates/helpdesk/functions/seedWorkspace.ts +25 -15
- package/templates/helpdesk/lib/brand.ts +9 -0
- package/templates/helpdesk/lib/demo-team.ts +51 -0
- package/templates/helpdesk/lib/search.ts +4 -3
- package/templates/helpdesk/lib/seed.ts +43 -2
- package/templates/helpdesk/lib/tickets.ts +68 -20
- package/templates/helpdesk/public/favicon.ico +0 -0
- package/templates/helpdesk/tests/components.test.tsx +10 -0
- package/templates/helpdesk/tests/demo-team.test.ts +18 -0
- package/templates/helpdesk/tests/tickets.test.ts +70 -0
- package/templates/imessage/.env.example +49 -0
- package/templates/imessage/AGENTS.md +153 -0
- package/templates/imessage/CLAUDE.md +7 -0
- package/templates/imessage/README.md +187 -0
- package/templates/imessage/app/console.tsx +382 -0
- package/templates/imessage/app/contacts/page.tsx +13 -0
- package/templates/imessage/app/error.tsx +16 -0
- package/templates/imessage/app/gate.tsx +31 -0
- package/templates/imessage/app/globals.css +183 -0
- package/templates/imessage/app/layout.tsx +17 -0
- package/templates/imessage/app/login/login-form.tsx +115 -0
- package/templates/imessage/app/login/page.tsx +30 -0
- package/templates/imessage/app/not-found.tsx +13 -0
- package/templates/imessage/app/page.tsx +14 -0
- package/templates/imessage/app/robots.ts +6 -0
- package/templates/imessage/app/setup/page.tsx +13 -0
- package/templates/imessage/app/sign-out.tsx +20 -0
- package/templates/imessage/app.ts +299 -0
- package/templates/imessage/bunfig +4 -0
- package/templates/imessage/components/avatar.tsx +46 -0
- package/templates/imessage/components/contact-panel.tsx +263 -0
- package/templates/imessage/components/contacts-view.tsx +172 -0
- package/templates/imessage/components/conversation-list.tsx +129 -0
- package/templates/imessage/components/nav-rail.tsx +67 -0
- package/templates/imessage/components/setup-view.tsx +408 -0
- package/templates/imessage/components/thread.tsx +229 -0
- package/templates/imessage/components/ui/badge.tsx +37 -0
- package/templates/imessage/components/ui/button.tsx +56 -0
- package/templates/imessage/components/ui/card.tsx +90 -0
- package/templates/imessage/components/ui/dialog.tsx +110 -0
- package/templates/imessage/components/ui/input.tsx +30 -0
- package/templates/imessage/components/ui/label.tsx +21 -0
- package/templates/imessage/components/ui/select.tsx +39 -0
- package/templates/imessage/components/ui/table.tsx +124 -0
- package/templates/imessage/components/ui/textarea.tsx +24 -0
- package/templates/imessage/components.json +20 -0
- package/templates/imessage/functions/answerNow.ts +34 -0
- package/templates/imessage/functions/assistant.ts +96 -0
- package/templates/imessage/functions/beginTurn.ts +101 -0
- package/templates/imessage/functions/cancelReminder.ts +13 -0
- package/templates/imessage/functions/claimOutbound.ts +44 -0
- package/templates/imessage/functions/clearDemo.ts +18 -0
- package/templates/imessage/functions/deleteNote.ts +11 -0
- package/templates/imessage/functions/deliverOutbound.ts +55 -0
- package/templates/imessage/functions/finishTurn.ts +84 -0
- package/templates/imessage/functions/fireReminder.ts +42 -0
- package/templates/imessage/functions/ingestInbound.ts +22 -0
- package/templates/imessage/functions/ownerAccount.ts +13 -0
- package/templates/imessage/functions/processTurn.ts +74 -0
- package/templates/imessage/functions/relayApply.ts +102 -0
- package/templates/imessage/functions/relaySync.ts +63 -0
- package/templates/imessage/functions/releaseOutbound.ts +18 -0
- package/templates/imessage/functions/resolveTurn.ts +25 -0
- package/templates/imessage/functions/saveContact.ts +27 -0
- package/templates/imessage/functions/seedDemo.ts +70 -0
- package/templates/imessage/functions/sendOwnerMessage.ts +28 -0
- package/templates/imessage/functions/sendblueWebhook.ts +49 -0
- package/templates/imessage/functions/setContactStatus.ts +17 -0
- package/templates/imessage/functions/settleOutbound.ts +35 -0
- package/templates/imessage/functions/setupStatus.ts +33 -0
- package/templates/imessage/functions/sweep.ts +58 -0
- package/templates/imessage/functions/toolCancelReminder.ts +17 -0
- package/templates/imessage/functions/toolForgetNote.ts +15 -0
- package/templates/imessage/functions/toolListNotes.ts +16 -0
- package/templates/imessage/functions/toolListReminders.ts +17 -0
- package/templates/imessage/functions/toolSaveNote.ts +22 -0
- package/templates/imessage/functions/toolSetReminder.ts +55 -0
- package/templates/imessage/functions/updateSettings.ts +48 -0
- package/templates/imessage/gitignore +11 -0
- package/templates/imessage/lib/agent-call.ts +251 -0
- package/templates/imessage/lib/assistant.ts +74 -0
- package/templates/imessage/lib/chunk.ts +135 -0
- package/templates/imessage/lib/demo.ts +68 -0
- package/templates/imessage/lib/format.ts +170 -0
- package/templates/imessage/lib/gate.ts +104 -0
- package/templates/imessage/lib/handles.ts +67 -0
- package/templates/imessage/lib/provider.ts +38 -0
- package/templates/imessage/lib/relay-protocol.ts +95 -0
- package/templates/imessage/lib/reminders.ts +41 -0
- package/templates/imessage/lib/secrets.ts +59 -0
- package/templates/imessage/lib/sendblue.ts +173 -0
- package/templates/imessage/lib/store.ts +407 -0
- package/templates/imessage/lib/transport.ts +135 -0
- package/templates/imessage/lib/utils.ts +10 -0
- package/templates/imessage/package.json +40 -0
- package/templates/imessage/relay/.env.example +14 -0
- package/templates/imessage/relay/applescript.ts +70 -0
- package/templates/imessage/relay/chatdb.ts +165 -0
- package/templates/imessage/relay/client.ts +41 -0
- package/templates/imessage/relay/main.ts +137 -0
- package/templates/imessage/relay/state.ts +35 -0
- package/templates/imessage/tests/agent-call.test.ts +112 -0
- package/templates/imessage/tests/applescript.test.ts +88 -0
- package/templates/imessage/tests/chatdb.test.ts +139 -0
- package/templates/imessage/tests/chunk.test.ts +61 -0
- package/templates/imessage/tests/fake-ctx.ts +88 -0
- package/templates/imessage/tests/ingest.test.ts +141 -0
- package/templates/imessage/tests/lib.test.ts +99 -0
- package/templates/imessage/tests/review-fixes.test.ts +138 -0
- package/templates/imessage/tests/secrets.test.ts +36 -0
- package/templates/imessage/tests/sendblue.test.ts +143 -0
- package/templates/imessage/tests/setup.ts +5 -0
- package/templates/imessage/tsconfig.json +18 -0
- package/templates/inventory/AGENTS.md +1 -1
- package/templates/inventory/README.md +21 -0
- package/templates/inventory/app/apple-icon.png +0 -0
- package/templates/inventory/app/globals.css +29 -14
- package/templates/inventory/app/icon.svg +1 -0
- package/templates/inventory/app/layout.tsx +7 -5
- package/templates/inventory/app/movements/movements-view.tsx +32 -10
- package/templates/inventory/app/movements/page.tsx +2 -1
- package/templates/inventory/app/page.tsx +4 -6
- package/templates/inventory/app/products/[id]/page.tsx +2 -1
- package/templates/inventory/app/products/[id]/product-view.tsx +55 -25
- package/templates/inventory/app/products-view.tsx +74 -33
- package/templates/inventory/app/workspace.tsx +34 -16
- package/templates/inventory/app.ts +10 -2
- package/templates/inventory/components/app-shell.tsx +94 -0
- package/templates/inventory/components/auth-form.tsx +35 -5
- package/templates/inventory/components/avatar.tsx +5 -1
- package/templates/inventory/components/brand-mark.tsx +25 -0
- package/templates/inventory/components/category-tile.tsx +49 -0
- package/templates/inventory/components/command-palette.tsx +17 -17
- package/templates/inventory/components/data-table.tsx +97 -36
- package/templates/inventory/components/filter-tabs.tsx +101 -0
- package/templates/inventory/components/nav.tsx +14 -0
- package/templates/inventory/components/page-header.tsx +43 -7
- package/templates/inventory/components/require-auth.tsx +24 -26
- package/templates/inventory/components/sidebar.tsx +54 -48
- package/templates/inventory/components/stock-level.tsx +30 -14
- package/templates/inventory/components/summary-bar.tsx +8 -15
- package/templates/inventory/components/ui/button.tsx +5 -4
- package/templates/inventory/components/ui/dialog.tsx +1 -1
- package/templates/inventory/components/ui/input.tsx +1 -1
- package/templates/inventory/components/ui/select.tsx +1 -1
- package/templates/inventory/components/ui/textarea.tsx +1 -1
- package/templates/inventory/functions/seedWorkspace.ts +18 -8
- package/templates/inventory/lib/brand.ts +9 -0
- package/templates/inventory/lib/demo-team.ts +51 -0
- package/templates/inventory/lib/search.ts +4 -3
- package/templates/inventory/lib/seed.ts +29 -2
- package/templates/inventory/lib/stock.ts +32 -0
- package/templates/inventory/public/favicon.ico +0 -0
- package/templates/inventory/tests/demo-team.test.ts +18 -0
- package/templates/inventory/tests/stock.test.ts +29 -0
- package/templates/invoices/AGENTS.md +1 -1
- package/templates/invoices/README.md +16 -0
- package/templates/invoices/app/apple-icon.png +0 -0
- package/templates/invoices/app/clients/clients-view.tsx +18 -6
- package/templates/invoices/app/clients/page.tsx +2 -1
- package/templates/invoices/app/globals.css +29 -14
- package/templates/invoices/app/icon.svg +1 -0
- package/templates/invoices/app/invoices/[id]/invoice-view.tsx +72 -48
- package/templates/invoices/app/invoices/[id]/page.tsx +2 -1
- package/templates/invoices/app/invoices-view.tsx +81 -32
- package/templates/invoices/app/layout.tsx +7 -5
- package/templates/invoices/app/page.tsx +4 -6
- package/templates/invoices/app/workspace.tsx +26 -16
- package/templates/invoices/app.ts +2 -2
- package/templates/invoices/components/app-shell.tsx +94 -0
- package/templates/invoices/components/auth-form.tsx +35 -5
- package/templates/invoices/components/avatar.tsx +5 -1
- package/templates/invoices/components/brand-mark.tsx +26 -0
- package/templates/invoices/components/command-palette.tsx +17 -17
- package/templates/invoices/components/data-table.tsx +97 -36
- package/templates/invoices/components/filter-tabs.tsx +101 -0
- package/templates/invoices/components/line-items.tsx +19 -14
- package/templates/invoices/components/nav.tsx +14 -0
- package/templates/invoices/components/page-header.tsx +43 -7
- package/templates/invoices/components/require-auth.tsx +24 -26
- package/templates/invoices/components/sidebar.tsx +54 -48
- package/templates/invoices/components/status-badge.tsx +7 -7
- package/templates/invoices/components/summary-bar.tsx +5 -5
- package/templates/invoices/components/ui/button.tsx +5 -4
- package/templates/invoices/components/ui/dialog.tsx +1 -1
- package/templates/invoices/components/ui/input.tsx +1 -1
- package/templates/invoices/components/ui/select.tsx +1 -1
- package/templates/invoices/components/ui/textarea.tsx +1 -1
- package/templates/invoices/functions/recordPayment.ts +3 -0
- package/templates/invoices/lib/billing.ts +40 -0
- package/templates/invoices/lib/brand.ts +9 -0
- package/templates/invoices/lib/search.ts +4 -3
- package/templates/invoices/public/favicon.ico +0 -0
- package/templates/invoices/tests/billing.test.ts +27 -0
- package/templates/ios/consumer/apps/ios/Package.swift +4 -3
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ActivityView.swift +107 -0
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/AppModel.swift +171 -0
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/AuthView.swift +182 -0
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/CommentsView.swift +136 -0
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ComposeView.swift +152 -0
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ExploreView.swift +117 -0
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/FeedView.swift +175 -159
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/MainTabView.swift +54 -0
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/Media.swift +271 -0
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/Models.swift +101 -4
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/PostCard.swift +245 -0
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ProfileEditorView.swift +208 -0
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ProfileView.swift +183 -0
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/RootView.swift +25 -31
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/SocialStore.swift +285 -0
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/StoryViewer.swift +155 -0
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/Theme.swift +82 -0
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/__APP_NAME_PASCAL__App.swift +4 -47
- package/templates/ios/consumer/apps/ios/project.yml +13 -9
- package/templates/local-service/.env.example +7 -0
- package/templates/local-service/AGENTS.md +1 -1
- package/templates/local-service/README.md +26 -2
- package/templates/local-service/app/(marketing)/booking-widget.tsx +48 -9
- package/templates/local-service/app/(marketing)/page.tsx +66 -42
- package/templates/local-service/app/auth-form.tsx +8 -8
- package/templates/local-service/app/dashboard/dashboard-client.tsx +119 -92
- package/templates/local-service/app/dashboard/page.tsx +14 -14
- package/templates/local-service/app/icon.svg +2 -0
- package/templates/local-service/app/login/page.tsx +15 -15
- package/templates/local-service/functions/seedDemo.ts +49 -0
- package/templates/local-service/lib/demo.ts +135 -0
- package/templates/local-service/lib/hours.ts +44 -0
- package/templates/local-service/lib/site.config.ts +8 -3
- package/templates/local-service/lib/slots.ts +3 -0
- package/templates/local-service/public/favicon.ico +0 -0
- package/templates/local-service/tests/booking.test.ts +104 -0
- package/templates/marketplace/AGENTS.md +1 -1
- package/templates/marketplace/README.md +23 -15
- package/templates/marketplace/app/globals.css +172 -114
- package/templates/marketplace/app/layout.tsx +75 -30
- package/templates/marketplace/app/listing/[id]/page.tsx +210 -123
- package/templates/marketplace/app/me/page.tsx +4 -4
- package/templates/marketplace/app/page.tsx +221 -298
- package/templates/marketplace/app/sell/page.tsx +8 -11
- package/templates/marketplace/app.ts +32 -7
- package/templates/marketplace/client/ActivityFeed.tsx +311 -0
- package/templates/marketplace/client/AuthNav.tsx +24 -16
- package/templates/marketplace/client/ListingCard.tsx +118 -0
- package/templates/marketplace/client/LiveGrid.tsx +92 -0
- package/templates/marketplace/client/LiveListingStatus.tsx +32 -24
- package/templates/marketplace/client/LoginCard.tsx +114 -136
- package/templates/marketplace/client/MarketProvider.tsx +3 -5
- package/templates/marketplace/client/MyMarket.tsx +371 -185
- package/templates/marketplace/client/OfferPanel.tsx +421 -287
- package/templates/marketplace/client/SellForm.tsx +271 -192
- package/templates/marketplace/client/ThemeToggle.tsx +1 -0
- package/templates/marketplace/client/WatchButton.tsx +16 -16
- package/templates/marketplace/client/market.ts +61 -14
- package/templates/marketplace/functions/seedMarket.ts +143 -36
- package/templates/marketplace/functions/seedOffers.ts +101 -0
- package/templates/marketplace/lib/catalog.ts +72 -1
- package/templates/marketplace/public/images/listings/ceramic-lamp-640.webp +0 -0
- package/templates/marketplace/public/images/listings/ceramic-lamp.webp +0 -0
- package/templates/marketplace/public/images/listings/duffel-640.webp +0 -0
- package/templates/marketplace/public/images/listings/duffel.webp +0 -0
- package/templates/marketplace/public/images/listings/film-camera-640.webp +0 -0
- package/templates/marketplace/public/images/listings/film-camera.webp +0 -0
- package/templates/marketplace/public/images/listings/lounge-chair-640.webp +0 -0
- package/templates/marketplace/public/images/listings/lounge-chair.webp +0 -0
- package/templates/marketplace/public/images/listings/road-bike-640.webp +0 -0
- package/templates/marketplace/public/images/listings/road-bike.webp +0 -0
- package/templates/marketplace/public/images/listings/slipper-chair-640.webp +0 -0
- package/templates/marketplace/public/images/listings/slipper-chair.webp +0 -0
- package/templates/marketplace/public/images/listings/turntable-640.webp +0 -0
- package/templates/marketplace/public/images/listings/turntable.webp +0 -0
- package/templates/marketplace/public/images/listings/wardrobe-640.webp +0 -0
- package/templates/marketplace/public/images/listings/wardrobe.webp +0 -0
- package/templates/marketplace/public/images/listings/watch-640.webp +0 -0
- package/templates/marketplace/public/images/listings/watch.webp +0 -0
- package/templates/marketplace/public/images/listings/weekender-bag-640.webp +0 -0
- package/templates/marketplace/public/images/listings/weekender-bag.webp +0 -0
- package/templates/marketplace/tests/example.test.ts +64 -2
- package/templates/marketplace/tests/listing-card.test.tsx +61 -0
- package/templates/projects/AGENTS.md +1 -1
- package/templates/projects/README.md +24 -3
- package/templates/projects/app/apple-icon.png +0 -0
- package/templates/projects/app/clients/clients-view.tsx +20 -6
- package/templates/projects/app/clients/page.tsx +2 -1
- package/templates/projects/app/globals.css +29 -14
- package/templates/projects/app/icon.svg +1 -0
- package/templates/projects/app/layout.tsx +7 -5
- package/templates/projects/app/page.tsx +3 -5
- package/templates/projects/app/projects/[id]/page.tsx +2 -1
- package/templates/projects/app/projects/[id]/project-view.tsx +45 -30
- package/templates/projects/app/projects-view.tsx +105 -52
- package/templates/projects/app/workspace.tsx +41 -20
- package/templates/projects/app.ts +2 -2
- package/templates/projects/components/app-shell.tsx +94 -0
- package/templates/projects/components/auth-form.tsx +35 -5
- package/templates/projects/components/avatar.tsx +5 -1
- package/templates/projects/components/board-skeleton.tsx +3 -3
- package/templates/projects/components/brand-mark.tsx +25 -0
- package/templates/projects/components/command-palette.tsx +17 -17
- package/templates/projects/components/data-table.tsx +97 -36
- package/templates/projects/components/filter-tabs.tsx +101 -0
- package/templates/projects/components/meter.tsx +48 -0
- package/templates/projects/components/nav.tsx +14 -0
- package/templates/projects/components/page-header.tsx +43 -7
- package/templates/projects/components/require-auth.tsx +24 -26
- package/templates/projects/components/sidebar.tsx +54 -48
- package/templates/projects/components/summary-bar.tsx +49 -0
- package/templates/projects/components/task-board.tsx +10 -9
- package/templates/projects/components/time-dialog.tsx +29 -5
- package/templates/projects/components/ui/button.tsx +5 -4
- package/templates/projects/components/ui/dialog.tsx +1 -1
- package/templates/projects/components/ui/input.tsx +1 -1
- package/templates/projects/components/ui/select.tsx +1 -1
- package/templates/projects/components/ui/textarea.tsx +1 -1
- package/templates/projects/functions/seedWorkspace.ts +26 -12
- package/templates/projects/lib/brand.ts +9 -0
- package/templates/projects/lib/demo-team.ts +51 -0
- package/templates/projects/lib/search.ts +4 -3
- package/templates/projects/lib/seed.ts +35 -1
- package/templates/projects/lib/work.ts +63 -0
- package/templates/projects/public/favicon.ico +0 -0
- package/templates/projects/tests/demo-team.test.ts +18 -0
- package/templates/projects/tests/work.test.ts +65 -0
- package/templates/restaurant/.env.example +7 -0
- package/templates/restaurant/AGENTS.md +1 -1
- package/templates/restaurant/README.md +29 -3
- package/templates/restaurant/app/(marketing)/layout.tsx +4 -2
- package/templates/restaurant/app/(marketing)/page.tsx +47 -23
- package/templates/restaurant/app/(marketing)/reservation-widget.tsx +37 -7
- package/templates/restaurant/app/auth-form.tsx +8 -8
- package/templates/restaurant/app/dashboard/dashboard-client.tsx +241 -109
- package/templates/restaurant/app/dashboard/page.tsx +14 -14
- package/templates/restaurant/app/icon.svg +4 -0
- package/templates/restaurant/app/login/page.tsx +15 -15
- package/templates/restaurant/functions/seedDemo.ts +44 -0
- package/templates/restaurant/lib/demo.ts +144 -0
- package/templates/restaurant/lib/hours.ts +45 -0
- package/templates/restaurant/lib/site.config.ts +3 -3
- package/templates/restaurant/public/favicon.ico +0 -0
- package/templates/restaurant/tests/reservations.test.ts +67 -0
- package/templates/saas/AGENTS.md +1 -1
- package/templates/saas/README.md +54 -35
- package/templates/saas/app/(auth)/auth-form.tsx +25 -23
- package/templates/saas/app/(auth)/forgot-password/page.tsx +1 -1
- package/templates/saas/app/(auth)/layout.tsx +27 -33
- package/templates/saas/app/(auth)/login/page.tsx +1 -1
- package/templates/saas/app/(auth)/reset-password/page.tsx +1 -1
- package/templates/saas/app/(auth)/signup/page.tsx +1 -1
- package/templates/saas/app/(marketing)/layout.tsx +127 -253
- package/templates/saas/app/(marketing)/page.tsx +133 -372
- package/templates/saas/app/(marketing)/pricing/page.tsx +21 -19
- package/templates/saas/app/(marketing)/products/[slug]/page.tsx +40 -95
- package/templates/saas/app/dashboard/board-client.tsx +416 -0
- package/templates/saas/app/dashboard/dashboard-client.tsx +30 -615
- package/templates/saas/app/dashboard/layout.tsx +27 -13
- package/templates/saas/app/dashboard/overview-client.tsx +332 -0
- package/templates/saas/app/dashboard/page.tsx +29 -35
- package/templates/saas/app/dashboard/projects/[id]/page.tsx +29 -0
- package/templates/saas/app/dashboard/projects/page.tsx +11 -7
- package/templates/saas/app/dashboard/projects-client.tsx +398 -0
- package/templates/saas/app/globals.css +5 -4
- package/templates/saas/app/icon.svg +1 -0
- package/templates/saas/app/onboarding/onboarding-client.tsx +93 -26
- package/templates/saas/app/onboarding/page.tsx +6 -2
- package/templates/saas/app.ts +68 -13
- package/templates/saas/components/dashboard-shell.tsx +212 -132
- package/templates/saas/components/marketing.tsx +137 -274
- package/templates/saas/components/pricing-table.tsx +12 -11
- package/templates/saas/components/setup-checklist.tsx +31 -29
- package/templates/saas/components/task-ui.tsx +199 -0
- package/templates/saas/functions/createProject.ts +7 -13
- package/templates/saas/functions/createTask.ts +67 -0
- package/templates/saas/functions/deleteProject.ts +17 -0
- package/templates/saas/functions/deleteTask.ts +14 -0
- package/templates/saas/functions/seedWorkspace.ts +46 -0
- package/templates/saas/functions/setProjectStatus.ts +41 -0
- package/templates/saas/functions/updateProfile.ts +13 -0
- package/templates/saas/functions/updateProject.ts +4 -5
- package/templates/saas/functions/updateTask.ts +88 -0
- package/templates/saas/lib/members.ts +53 -0
- package/templates/saas/lib/names.ts +53 -0
- package/templates/saas/lib/plans.ts +11 -0
- package/templates/saas/lib/sample-workspace.ts +117 -0
- package/templates/saas/lib/site.config.ts +200 -463
- package/templates/saas/lib/tasks.ts +101 -0
- package/templates/saas/lib/use-live.ts +25 -0
- package/templates/saas/public/favicon.ico +0 -0
- package/templates/saas/public/screenshots/board.png +0 -0
- package/templates/saas/public/screenshots/members.png +0 -0
- package/templates/saas/public/screenshots/overview.png +0 -0
- package/templates/saas/public/screenshots/projects.png +0 -0
- package/templates/saas/scripts/capture-screenshots.mjs +156 -0
- package/templates/saas/tests/names.test.ts +35 -0
- package/templates/saas/tests/plans.test.ts +12 -0
- package/templates/saas/tests/sample-workspace.test.ts +46 -0
- package/templates/saas/tests/tasks.test.ts +81 -0
- package/templates/shop/AGENTS.md +1 -1
- package/templates/shop/README.md +25 -13
- package/templates/shop/app/(marketing)/layout.tsx +94 -67
- package/templates/shop/app/(marketing)/not-found.tsx +13 -12
- package/templates/shop/app/(marketing)/page.tsx +120 -59
- package/templates/shop/app/(marketing)/shop-client.tsx +364 -237
- package/templates/shop/app/(marketing)/success/page.tsx +75 -22
- package/templates/shop/app/globals.css +94 -1
- package/templates/shop/app/layout.tsx +4 -4
- package/templates/shop/app/login/page.tsx +4 -4
- package/templates/shop/app.ts +18 -6
- package/templates/shop/components/cart-button.tsx +33 -0
- package/templates/shop/components/marketing.tsx +17 -87
- package/templates/shop/components/shelf-count.tsx +36 -0
- package/templates/shop/functions/checkout.ts +17 -1
- package/templates/shop/lib/cart-store.ts +57 -0
- package/templates/shop/lib/shelf-store.ts +35 -0
- package/templates/shop/lib/shop.ts +27 -0
- package/templates/shop/lib/site.config.ts +108 -98
- package/templates/shop/public/images/hero.jpg +0 -0
- package/templates/shop/public/images/products/cedar-smoke.jpg +0 -0
- package/templates/shop/public/images/products/fig-leaf.jpg +0 -0
- package/templates/shop/public/images/products/linen.jpg +0 -0
- package/templates/shop/public/images/products/sea-salt.jpg +0 -0
- package/templates/shop/public/images/products/tobacco-oak.jpg +0 -0
- package/templates/shop/tests/shop.test.ts +64 -0
- package/templates/todo/AGENTS.md +1 -1
- package/templates/waitlist/.env.example +7 -0
- package/templates/waitlist/AGENTS.md +1 -1
- package/templates/waitlist/README.md +29 -13
- package/templates/waitlist/app/(marketing)/page.tsx +9 -7
- package/templates/waitlist/app/(marketing)/waitlist-hero.tsx +64 -31
- package/templates/waitlist/app/auth-form.tsx +8 -8
- package/templates/waitlist/app/dashboard/dashboard-client.tsx +132 -95
- package/templates/waitlist/app/dashboard/page.tsx +17 -16
- package/templates/waitlist/app/icon.svg +2 -0
- package/templates/waitlist/app/login/page.tsx +14 -14
- package/templates/waitlist/app.ts +6 -6
- package/templates/waitlist/functions/joinWaitlist.ts +6 -18
- package/templates/waitlist/functions/seedDemo.ts +32 -0
- package/templates/waitlist/lib/demo.ts +94 -0
- package/templates/waitlist/lib/launch.ts +19 -0
- package/templates/waitlist/lib/site.config.ts +14 -9
- package/templates/waitlist/lib/stats.ts +35 -0
- package/templates/waitlist/public/favicon.ico +0 -0
- package/templates/waitlist/tests/counter.test.ts +107 -0
- package/templates/waitlist/tests/live-count.test.tsx +48 -0
- package/templates/ai-chat/tests/example.test.ts +0 -12
- package/templates/backend/consumer/apps/api/functions/feed.ts +0 -57
- package/templates/backend/consumer/apps/api/functions/profilePosts.ts +0 -17
- package/templates/backend/consumer/apps/api/functions/toggleLike.ts +0 -48
- package/templates/backend/consumer/apps/api/schema.ts +0 -143
- package/templates/chat/functions/_keep.ts +0 -13
- package/templates/chat/tests/example.test.ts +0 -12
- package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ProfileSetupView.swift +0 -68
- package/templates/marketplace/client/LiveTicker.tsx +0 -116
- package/templates/marketplace/client/ScrollToListingsLink.tsx +0 -29
- package/templates/marketplace/public/images/marketplace-hero.webp +0 -0
|
@@ -1,21 +1,26 @@
|
|
|
1
|
-
// Business-specific copy and settings live here. The
|
|
2
|
-
// read this file. The product list, including starting stock, seeds the
|
|
3
|
-
// first visit; after that, stock lives in the database and
|
|
1
|
+
// Business-specific copy and settings live here. The storefront pages and
|
|
2
|
+
// layout read this file. The product list, including starting stock, seeds the
|
|
3
|
+
// Product table on first visit; after that, stock lives in the database and
|
|
4
|
+
// updates live.
|
|
4
5
|
//
|
|
5
6
|
// Colors live here (applied as CSS variables on <html> in app/layout.tsx).
|
|
6
7
|
// Fictional demo copy. Replace the values and keep the shape.
|
|
7
8
|
|
|
8
9
|
/* ----------------------------- types ----------------------------- */
|
|
9
10
|
|
|
11
|
+
import type { ShippingTerms } from "./shop";
|
|
12
|
+
|
|
10
13
|
export type Social = { label: string; href: string; path: string };
|
|
11
14
|
|
|
12
15
|
export type BaseConfig = {
|
|
13
16
|
brand: {
|
|
14
17
|
name: string;
|
|
15
|
-
letter: string;
|
|
18
|
+
letter: string; // the monogram on the sign-in and dashboard screens
|
|
16
19
|
domain: string;
|
|
17
20
|
email: string;
|
|
21
|
+
announcement: string;
|
|
18
22
|
footerBlurb: string;
|
|
23
|
+
address: string[];
|
|
19
24
|
copyrightName: string;
|
|
20
25
|
socials: Social[];
|
|
21
26
|
};
|
|
@@ -28,21 +33,29 @@ export type ProductItem = {
|
|
|
28
33
|
name: string;
|
|
29
34
|
priceCents: number;
|
|
30
35
|
description?: string;
|
|
31
|
-
|
|
32
|
-
|
|
36
|
+
size?: string; // one short line under the name, e.g. "8 oz, 60-hour burn"
|
|
37
|
+
image: string; // a product photo URL or /public path (4:5 portrait works best)
|
|
38
|
+
stock: number; // STARTING stock, seeded once, then live in the DB
|
|
33
39
|
};
|
|
34
40
|
|
|
35
|
-
export type
|
|
36
|
-
export type Review = { quote: string; name: string;
|
|
41
|
+
export type Fact = { value: string; label: string };
|
|
42
|
+
export type Review = { quote: string; name: string; product?: string };
|
|
37
43
|
export type Policy = { title: string; body: string };
|
|
38
44
|
|
|
39
45
|
export type ShopConfig = BaseConfig & {
|
|
40
|
-
hero: {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
hero: {
|
|
47
|
+
headline: string;
|
|
48
|
+
subcopy: string;
|
|
49
|
+
ctaLabel: string;
|
|
50
|
+
secondaryLabel: string;
|
|
51
|
+
image: string;
|
|
52
|
+
imageAlt: string;
|
|
53
|
+
};
|
|
54
|
+
products: { headline: string; subcopy: string; items: ProductItem[] };
|
|
55
|
+
studio: { headline: string; body: string[]; facts: Fact[] };
|
|
56
|
+
checkout: { shipping: ShippingTerms; reservedMessage: string; paidMessage: string; image: string };
|
|
57
|
+
reviews?: { headline: string; items: Review[] };
|
|
58
|
+
policies: { headline: string; items: Policy[] };
|
|
46
59
|
};
|
|
47
60
|
|
|
48
61
|
/* ----------------------------- config ---------------------------- */
|
|
@@ -53,145 +66,142 @@ export const siteConfig: ShopConfig = {
|
|
|
53
66
|
letter: "E",
|
|
54
67
|
domain: "embergoods.com",
|
|
55
68
|
email: "hello@embergoods.example",
|
|
56
|
-
|
|
57
|
-
|
|
69
|
+
announcement: "Free shipping on orders over $50. Ships from Dallas in two business days.",
|
|
70
|
+
footerBlurb: "Candles poured by hand in small batches in Dallas, Texas.",
|
|
71
|
+
address: ["2809 Elm Street", "Dallas, TX 75226", "Studio open Saturdays, 10 to 4"],
|
|
58
72
|
copyrightName: "Ember Goods",
|
|
59
73
|
socials: [
|
|
60
74
|
{
|
|
61
75
|
label: "Instagram",
|
|
62
76
|
href: "https://instagram.com",
|
|
63
|
-
path: "M12 2.2c3.2 0 3.6 0 4.85.07 1.17.05 1.8.25 2.23.41.56.22.96.48 1.38.9.42.42.68.82.9 1.38.16.42.36 1.06.41 2.23.06 1.27.07 1.65.07 4.85s0 3.58-.07 4.85c-.05 1.17-.25 1.8-.41 2.23-.22.56-.48.96-.9 1.38-.42.42-.82.68-1.38.9-.42.16-1.06.36-2.23.41-1.27.06-1.65.07-4.85.07s-3.58 0-4.85-.07c-1.17-.05-1.8-.25-2.23-.41a3.7 3.7 0 0 1-1.38-.9 3.7 3.7 0 0 1-.9-1.38c-.16-.42-.36-1.06-.41-2.23C2.2 15.58 2.2 15.2 2.2 12s0-3.58.07-4.85c.05-1.17.25-1.8.41-2.23.22-.56.48-.96.9-1.38.42-.42.82-.68 1.38-.9.42-.16 1.06-.36 2.23-.41C8.42 2.2 8.8 2.2 12 2.2zm0 1.8c-3.15 0-3.5 0-4.74.07-.9.04-1.38.19-1.7.32-.43.16-.74.36-1.06.68-.32.32-.52.63-.68 1.06-.13.32-.28.8-.32 1.7C3.8 8.5 3.8 8.85 3.8 12s0 3.5.07 4.74c.04.9.19 1.38.32 1.7.16.43.36.74.68 1.06.32.32.63.52 1.06.68.32.13.8.28 1.7.32 1.24.07 1.59.07 4.74.07s3.5 0 4.74-.07c.9-.04 1.38-.19 1.7-.32.43-.16.74-.36 1.06-.68.32-.32.52-.63.68-1.06.13-.32.28-.8.32-1.7.07-1.24.07-1.59.07-4.74s0-3.5-.07-4.74c-.04-.9-.19-1.38-.32-1.7a2.85 2.85 0 0 0-.68-1.06 2.85 2.85 0 0 0-1.06-.68c-.32-.13-.8-.28-1.7-.32C15.5 4 15.15 4 12 4zm0 3.06A4.94 4.94 0 1 0 12 16.94 4.94 4.94 0 0 0 12 7.06zm0 8.15A3.21 3.21 0 1 1 12 8.8a3.21 3.21 0 0 1 0 6.4zm6.3-8.35a1.15 1.15 0 1 1-2.3 0 1.15 1.15 0 0 1 2.3 0z",
|
|
64
|
-
},
|
|
77
|
+
path: "M12 2.2c3.2 0 3.6 0 4.85.07 1.17.05 1.8.25 2.23.41.56.22.96.48 1.38.9.42.42.68.82.9 1.38.16.42.36 1.06.41 2.23.06 1.27.07 1.65.07 4.85s0 3.58-.07 4.85c-.05 1.17-.25 1.8-.41 2.23-.22.56-.48.96-.9 1.38-.42.42-.82.68-1.38.9-.42.16-1.06.36-2.23.41-1.27.06-1.65.07-4.85.07s-3.58 0-4.85-.07c-1.17-.05-1.8-.25-2.23-.41a3.7 3.7 0 0 1-1.38-.9 3.7 3.7 0 0 1-.9-1.38c-.16-.42-.36-1.06-.41-2.23C2.2 15.58 2.2 15.2 2.2 12s0-3.58.07-4.85c.05-1.17.25-1.8.41-2.23.22-.56.48-.96.9-1.38.42-.42.82-.68 1.38-.9.42-.16 1.06-.36 2.23-.41C8.42 2.2 8.8 2.2 12 2.2zm0 1.8c-3.15 0-3.5 0-4.74.07-.9.04-1.38.19-1.7.32-.43.16-.74.36-1.06.68-.32.32-.52.63-.68 1.06-.13.32-.28.8-.32 1.7C3.8 8.5 3.8 8.85 3.8 12s0 3.5.07 4.74c.04.9.19 1.38.32 1.7.16.43.36.74.68 1.06.32.32.63.52 1.06.68.32.13.8.28 1.7.32 1.24.07 1.59.07 4.74.07s3.5 0 4.74-.07c.9-.04 1.38-.19 1.7-.32.43-.16.74-.36 1.06-.68.32-.32.52-.63.68-1.06.13-.32.28-.8.32-1.7.07-1.24.07-1.59.07-4.74s0-3.5-.07-4.74c-.04-.9-.19-1.38-.32-1.7a2.85 2.85 0 0 0-.68-1.06 2.85 2.85 0 0 0-1.06-.68c-.32-.13-.8-.28-1.7-.32C15.5 4 15.15 4 12 4zm0 3.06A4.94 4.94 0 1 0 12 16.94 4.94 4.94 0 0 0 12 7.06zm0 8.15A3.21 3.21 0 1 1 12 8.8a3.21 3.21 0 0 1 0 6.4zm6.3-8.35a1.15 1.15 0 1 1-2.3 0 1.15 1.15 0 0 1 2.3 0z", },
|
|
65
78
|
],
|
|
66
79
|
},
|
|
67
80
|
|
|
68
|
-
colors: { brand: "#
|
|
81
|
+
colors: { brand: "#8b4a2b", brandSoft: "#efe3d6", paper: "#e9e1d5" },
|
|
69
82
|
|
|
70
83
|
seo: {
|
|
71
|
-
title: "Ember Goods
|
|
84
|
+
title: "Ember Goods: candles poured by hand in Dallas",
|
|
72
85
|
description:
|
|
73
|
-
"Small-batch candles and
|
|
86
|
+
"Small-batch candles poured in Dallas. Soy and coconut wax, cotton wicks, 60-hour burn. Stock counts match the studio shelf. Free shipping over $50.",
|
|
74
87
|
},
|
|
75
88
|
|
|
76
89
|
hero: {
|
|
77
|
-
|
|
78
|
-
headline: "Hand-poured candles, made to last.",
|
|
90
|
+
headline: "Candles poured by hand in Dallas.",
|
|
79
91
|
subcopy:
|
|
80
|
-
"
|
|
81
|
-
ctaLabel: "Shop
|
|
92
|
+
"Soy and coconut wax, cotton wicks, and scents we blend ourselves. We pour forty at a time, so the stock counts are the real shelf.",
|
|
93
|
+
ctaLabel: "Shop candles",
|
|
94
|
+
secondaryLabel: "See the studio",
|
|
95
|
+
image: "/images/hero.jpg",
|
|
96
|
+
imageAlt: "Three amber glass candles on a travertine shelf, the middle one lit, in late afternoon light.",
|
|
82
97
|
},
|
|
83
98
|
|
|
84
99
|
products: {
|
|
85
|
-
|
|
86
|
-
|
|
100
|
+
headline: "The shelf",
|
|
101
|
+
subcopy: "Stock updates live. When a batch sells out, it is gone until the next pour.",
|
|
87
102
|
items: [
|
|
103
|
+
{
|
|
104
|
+
slug: "tobacco-oak",
|
|
105
|
+
name: "Tobacco & Oak",
|
|
106
|
+
priceCents: 4200,
|
|
107
|
+
description: "Cured tobacco leaf, oak barrel, and amber. Our darkest scent, poured once a season.",
|
|
108
|
+
size: "8 oz, 60-hour burn",
|
|
109
|
+
image: "/images/products/tobacco-oak.jpg",
|
|
110
|
+
stock: 2,
|
|
111
|
+
},
|
|
88
112
|
{
|
|
89
113
|
slug: "cedar-smoke",
|
|
90
114
|
name: "Cedar & Smoke",
|
|
91
|
-
priceCents:
|
|
92
|
-
description: "Cedarwood, smoked vanilla, a little leather.
|
|
93
|
-
|
|
115
|
+
priceCents: 3800,
|
|
116
|
+
description: "Cedarwood, smoked vanilla, and a little leather.",
|
|
117
|
+
size: "8 oz, 60-hour burn",
|
|
118
|
+
image: "/images/products/cedar-smoke.jpg",
|
|
94
119
|
stock: 8,
|
|
95
120
|
},
|
|
96
121
|
{
|
|
97
122
|
slug: "linen",
|
|
98
|
-
name: "
|
|
99
|
-
priceCents:
|
|
100
|
-
description: "Clean cotton
|
|
101
|
-
|
|
123
|
+
name: "Linen",
|
|
124
|
+
priceCents: 3800,
|
|
125
|
+
description: "Clean cotton, white musk, and iris.",
|
|
126
|
+
size: "8 oz, 60-hour burn",
|
|
127
|
+
image: "/images/products/linen.jpg",
|
|
102
128
|
stock: 3,
|
|
103
129
|
},
|
|
104
130
|
{
|
|
105
|
-
slug: "
|
|
106
|
-
name: "
|
|
107
|
-
priceCents:
|
|
108
|
-
description: "
|
|
109
|
-
|
|
110
|
-
|
|
131
|
+
slug: "fig-leaf",
|
|
132
|
+
name: "Fig Leaf",
|
|
133
|
+
priceCents: 3800,
|
|
134
|
+
description: "Green fig, cedar, and coconut.",
|
|
135
|
+
size: "8 oz, 60-hour burn",
|
|
136
|
+
image: "/images/products/fig-leaf.jpg",
|
|
137
|
+
stock: 11,
|
|
111
138
|
},
|
|
112
139
|
{
|
|
113
|
-
slug: "
|
|
114
|
-
name: "
|
|
115
|
-
priceCents:
|
|
116
|
-
description: "
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
{
|
|
121
|
-
slug: "wick-trimmer",
|
|
122
|
-
name: "Wick trimmer",
|
|
123
|
-
priceCents: 1800,
|
|
124
|
-
description: "The one tool that makes a candle last. Matte black.",
|
|
125
|
-
image: "✂️",
|
|
126
|
-
stock: 0,
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
slug: "gift-set",
|
|
130
|
-
name: "The trio gift set",
|
|
131
|
-
priceCents: 8400,
|
|
132
|
-
description: "Three minis, boxed and ready to give.",
|
|
133
|
-
image: "🎁",
|
|
134
|
-
stock: 6,
|
|
140
|
+
slug: "sea-salt",
|
|
141
|
+
name: "Sea Salt & Sage",
|
|
142
|
+
priceCents: 3800,
|
|
143
|
+
description: "Salt air, sage, and driftwood.",
|
|
144
|
+
size: "8 oz, 60-hour burn",
|
|
145
|
+
image: "/images/products/sea-salt.jpg",
|
|
146
|
+
stock: 9,
|
|
135
147
|
},
|
|
136
148
|
],
|
|
137
149
|
},
|
|
138
150
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
151
|
+
studio: {
|
|
152
|
+
headline: "Poured in small batches, cured for two weeks.",
|
|
153
|
+
body: [
|
|
154
|
+
"Every candle is poured, cured, and trimmed by hand in our studio in Deep Ellum. We use a soy and coconut wax blend, cotton wicks, and phthalate-free fragrance oils.",
|
|
155
|
+
"Each batch cures for fourteen days before it goes on the shelf, so the scent carries across the room from the first burn.",
|
|
156
|
+
],
|
|
157
|
+
facts: [
|
|
158
|
+
{ value: "40", label: "candles per batch" },
|
|
159
|
+
{ value: "14 days", label: "cure before sale" },
|
|
160
|
+
{ value: "60 hr", label: "burn time, 8 oz" },
|
|
161
|
+
],
|
|
142
162
|
},
|
|
143
163
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
body: "Every candle is poured, wicked, and labelled by hand in our Dallas studio.",
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
icon: "◇",
|
|
155
|
-
title: "Real small batch",
|
|
156
|
-
body: "We make what we can do well. When the shelf says 3 left, there are 3 left.",
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
icon: "✦",
|
|
160
|
-
title: "Free shipping over $50",
|
|
161
|
-
body: "Carbon-neutral shipping, plastic-free packaging, and easy returns.",
|
|
162
|
-
},
|
|
163
|
-
],
|
|
164
|
+
checkout: {
|
|
165
|
+
shipping: { flatCents: 600, freeOverCents: 5000 },
|
|
166
|
+
reservedMessage:
|
|
167
|
+
"We are holding your items and will email a payment link within one business day. Orders ship from Dallas within two business days of payment.",
|
|
168
|
+
paidMessage:
|
|
169
|
+
"Your payment went through and the receipt is on its way to your inbox. Orders ship from Dallas within two business days.",
|
|
170
|
+
image: "/images/products/tobacco-oak.jpg", // shown on /success
|
|
164
171
|
},
|
|
165
172
|
|
|
166
173
|
reviews: {
|
|
167
|
-
|
|
168
|
-
headline: "What people say.",
|
|
174
|
+
headline: "Reviews",
|
|
169
175
|
items: [
|
|
170
176
|
{
|
|
171
|
-
quote: "Cedar & Smoke
|
|
177
|
+
quote: "Cedar & Smoke fills the whole living room without being loud about it. On my third one.",
|
|
172
178
|
name: "Maya C.",
|
|
173
|
-
|
|
179
|
+
product: "Cedar & Smoke",
|
|
174
180
|
},
|
|
175
181
|
{
|
|
176
|
-
quote: "
|
|
182
|
+
quote: "Bought Linen for my mom. It arrived in two days, packed in paper, no plastic anywhere.",
|
|
177
183
|
name: "Daniel R.",
|
|
178
|
-
|
|
184
|
+
product: "Linen",
|
|
179
185
|
},
|
|
180
186
|
{
|
|
181
|
-
quote: "
|
|
187
|
+
quote: "Fig Leaf burned evenly all the way to the bottom of the jar. I kept the jar for pens.",
|
|
182
188
|
name: "Hannah K.",
|
|
183
|
-
|
|
189
|
+
product: "Fig Leaf",
|
|
184
190
|
},
|
|
185
191
|
],
|
|
186
192
|
},
|
|
187
193
|
|
|
188
194
|
policies: {
|
|
189
|
-
|
|
190
|
-
headline: "Shipping & returns.",
|
|
195
|
+
headline: "Shipping and returns",
|
|
191
196
|
items: [
|
|
192
|
-
{ title: "Shipping", body: "Ships in
|
|
193
|
-
{ title: "Returns", body: "
|
|
194
|
-
{ title: "
|
|
197
|
+
{ title: "Shipping", body: "Ships from Dallas in two business days. Free over $50, $6 flat otherwise." },
|
|
198
|
+
{ title: "Returns", body: "Return unused and unburned items within 30 days for a full refund." },
|
|
199
|
+
{ title: "Local pickup", body: "Pick up at the studio on Saturdays. Reply to your order email to switch to pickup." },
|
|
200
|
+
{ title: "Wholesale", body: "Email us for the line sheet and wholesale pricing." },
|
|
195
201
|
],
|
|
196
202
|
},
|
|
197
203
|
};
|
|
204
|
+
|
|
205
|
+
export function productBySlug(slug: string): ProductItem | undefined {
|
|
206
|
+
return siteConfig.products.items.find((p) => p.slug === slug);
|
|
207
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { formatPrice, freeShippingRemaining, shippingCents, stockStatus } from "../lib/shop";
|
|
5
|
+
import { productBySlug, siteConfig } from "../lib/site.config";
|
|
6
|
+
|
|
7
|
+
const terms = { flatCents: 600, freeOverCents: 5000 };
|
|
8
|
+
|
|
9
|
+
describe("stockStatus", () => {
|
|
10
|
+
test("zero or less is sold out", () => {
|
|
11
|
+
expect(stockStatus(0)).toEqual({ kind: "sold_out", label: "Sold out" });
|
|
12
|
+
expect(stockStatus(-2).kind).toBe("sold_out");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("three or fewer is low", () => {
|
|
16
|
+
expect(stockStatus(1)).toEqual({ kind: "low", label: "Last one" });
|
|
17
|
+
expect(stockStatus(3)).toEqual({ kind: "low", label: "Only 3 left" });
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("more than three shows the count", () => {
|
|
21
|
+
expect(stockStatus(4)).toEqual({ kind: "in_stock", label: "4 in stock" });
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe("shipping", () => {
|
|
26
|
+
test("flat rate below the threshold", () => {
|
|
27
|
+
expect(shippingCents(4999, terms)).toBe(600);
|
|
28
|
+
expect(freeShippingRemaining(3800, terms)).toBe(1200);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("free at and above the threshold", () => {
|
|
32
|
+
expect(shippingCents(5000, terms)).toBe(0);
|
|
33
|
+
expect(freeShippingRemaining(8400, terms)).toBe(0);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("formatPrice drops zero cents", () => {
|
|
38
|
+
expect(formatPrice(3800)).toBe("$38");
|
|
39
|
+
expect(formatPrice(1850)).toBe("$18.50");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe("catalog config", () => {
|
|
43
|
+
const items = siteConfig.products.items;
|
|
44
|
+
|
|
45
|
+
test("slugs are unique", () => {
|
|
46
|
+
expect(new Set(items.map((p) => p.slug)).size).toBe(items.length);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("productBySlug finds a product and misses an unknown slug", () => {
|
|
50
|
+
expect(productBySlug(items[0].slug)?.name).toBe(items[0].name);
|
|
51
|
+
expect(productBySlug("nope")).toBeUndefined();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Every local image the storefront references must ship in public/.
|
|
55
|
+
test("every local image exists in public/", () => {
|
|
56
|
+
const paths = [
|
|
57
|
+
siteConfig.hero.image,
|
|
58
|
+
siteConfig.checkout.image,
|
|
59
|
+
...items.map((p) => p.image),
|
|
60
|
+
].filter((src) => src.startsWith("/"));
|
|
61
|
+
const missing = paths.filter((src) => !existsSync(join(import.meta.dir, "..", "public", src)));
|
|
62
|
+
expect(missing).toEqual([]);
|
|
63
|
+
});
|
|
64
|
+
});
|
package/templates/todo/AGENTS.md
CHANGED
|
@@ -62,7 +62,7 @@ this pass before the user has to ask.
|
|
|
62
62
|
- **`serverData` (SSR) is READ-ONLY.** No write methods; the runtime rejects write frames (`SSR_WRITE_FORBIDDEN`). Mutations belong in actions/functions, never in a page render.
|
|
63
63
|
- **`response.*` / `response.redirect()` / `response.notFound()` must fire in the synchronous shell render**, before any `await` / `<Suspense>`. The HTTP head commits when the shell is ready; status/headers/cookies set from a suspended subtree are lost, and `redirect`/`notFound` thrown below a Suspense boundary are swallowed.
|
|
64
64
|
- **`ctx.llm`, `ctx.rooms`, and `ctx.connections` are on mutation + action only, NOT query** (reactive purity). `action` has no direct `ctx.db`; use `ctx.runQuery` / `ctx.runMutation`.
|
|
65
|
-
- **`ctx.llm.stream(request, onEvent)` streams tokens as they generate** and still resolves with the full response, so `stop_reason === "tool_use"` drives an agent tool loop. Events are `text_delta` / `tool_use_start` / `tool_input_delta` / `done`. Same auth + model-allowlist gating as `ctx.llm.complete`.
|
|
65
|
+
- **`ctx.llm.stream(request, onEvent)` streams tokens as they generate** and still resolves with the full response, so `stop_reason === "tool_use"` drives an agent tool loop. Events are `text_delta` / `tool_use_start` / `tool_input_delta` / `done`. Same auth + model-allowlist gating as `ctx.llm.complete`. The call timeout is an idle timeout (`PYLON_FN_CALL_TIMEOUT`, 30s default; Stack0 Cloud 300s): each stream event resets it, and the total run is capped at 10× the timeout. Set `timeout: <secs>` on the def when a step (a slow tool call) can be silent longer than that.
|
|
66
66
|
- **`ctx.stream.write(text)` streams to the caller — and every fn stream is RESUMABLE**: the server buffers frames under a stream id (`streamFn`'s `onStreamId`), so a dropped connection or closed tab catches up via `resumeStream(id)`, including the final result after the handler finished. `ctx.rooms.broadcast(room, topic, data)` fans out to every CURRENTLY-CONNECTED subscriber (second device, second tab) but does not replay missed messages — use the stream id for anything that must survive a gap. Broadcast resolves `{ delivered: false }` when the room has no members — a no-op, not an error. Clients receive with `useRoomMessages(room, cb)` from `@pylonsync/react`; `useRoom` is the send side.
|
|
67
67
|
- **It's `db.useQueryOne`, not `useOne`.** Validators and field types have aliases: `v.bool`/`v.boolean`, `v.float`/`v.number`.
|
|
68
68
|
- **Use the supported file and scheduling APIs.** Files go through `<FileUpload>` and `/api/files/*`; an upload is readable by its uploader only, so pass `visibility: "public"` to `uploadFile` or `<FileUpload>` for files every visitor sees; there is no `ctx.files`. One-shot work uses `ctx.scheduler.runAfter`, `runAt`, or `cancel`; there is no `defineWorkflow` or `defineJob`. Recurring work uses `cron("0 * * * *", "fnName")` in `buildManifest({ crons: [...] })`, imported from `@pylonsync/sdk`. Make the target function `internal: true`. It runs with anonymous auth, but its own `ctx.db.*` calls are server-side and bypass policies. Use `ctx.auth.elevate({ admin: true, reason: "..." })`, with a mandatory reason, only when chaining another internal function through `ctx.scheduler`.
|
|
@@ -10,3 +10,10 @@ PYLON_OWNER_EMAIL=you@yourbusiness.com
|
|
|
10
10
|
# ── Site URL (optional) ──────────────────────────────────────────────────────
|
|
11
11
|
# Used by robots.txt + sitemap.xml. Point it at your real domain in production.
|
|
12
12
|
# SITE_URL=https://yourbusiness.com
|
|
13
|
+
|
|
14
|
+
# ── Demo data ────────────────────────────────────────────────────────────────
|
|
15
|
+
# `pylon dev` fills an empty waitlist with fictional signups. Seeding runs only
|
|
16
|
+
# under `pylon dev` (it checks PYLON_DEV_MODE and PYLON_DEV_WATCH_DIR), so
|
|
17
|
+
# `pylon start`, Docker, and Pylon Cloud deploys never seed. Set 0 to start
|
|
18
|
+
# empty in development. Never set 1 on a deploy.
|
|
19
|
+
# PYLON_DEMO_DATA=0
|
|
@@ -62,7 +62,7 @@ this pass before the user has to ask.
|
|
|
62
62
|
- **`serverData` (SSR) is READ-ONLY.** No write methods; the runtime rejects write frames (`SSR_WRITE_FORBIDDEN`). Mutations belong in actions/functions, never in a page render.
|
|
63
63
|
- **`response.*` / `response.redirect()` / `response.notFound()` must fire in the synchronous shell render**, before any `await` / `<Suspense>`. The HTTP head commits when the shell is ready; status/headers/cookies set from a suspended subtree are lost, and `redirect`/`notFound` thrown below a Suspense boundary are swallowed.
|
|
64
64
|
- **`ctx.llm`, `ctx.rooms`, and `ctx.connections` are on mutation + action only, NOT query** (reactive purity). `action` has no direct `ctx.db`; use `ctx.runQuery` / `ctx.runMutation`.
|
|
65
|
-
- **`ctx.llm.stream(request, onEvent)` streams tokens as they generate** and still resolves with the full response, so `stop_reason === "tool_use"` drives an agent tool loop. Events are `text_delta` / `tool_use_start` / `tool_input_delta` / `done`. Same auth + model-allowlist gating as `ctx.llm.complete`.
|
|
65
|
+
- **`ctx.llm.stream(request, onEvent)` streams tokens as they generate** and still resolves with the full response, so `stop_reason === "tool_use"` drives an agent tool loop. Events are `text_delta` / `tool_use_start` / `tool_input_delta` / `done`. Same auth + model-allowlist gating as `ctx.llm.complete`. The call timeout is an idle timeout (`PYLON_FN_CALL_TIMEOUT`, 30s default; Stack0 Cloud 300s): each stream event resets it, and the total run is capped at 10× the timeout. Set `timeout: <secs>` on the def when a step (a slow tool call) can be silent longer than that.
|
|
66
66
|
- **`ctx.stream.write(text)` streams to the caller — and every fn stream is RESUMABLE**: the server buffers frames under a stream id (`streamFn`'s `onStreamId`), so a dropped connection or closed tab catches up via `resumeStream(id)`, including the final result after the handler finished. `ctx.rooms.broadcast(room, topic, data)` fans out to every CURRENTLY-CONNECTED subscriber (second device, second tab) but does not replay missed messages — use the stream id for anything that must survive a gap. Broadcast resolves `{ delivered: false }` when the room has no members — a no-op, not an error. Clients receive with `useRoomMessages(room, cb)` from `@pylonsync/react`; `useRoom` is the send side.
|
|
67
67
|
- **It's `db.useQueryOne`, not `useOne`.** Validators and field types have aliases: `v.bool`/`v.boolean`, `v.float`/`v.number`.
|
|
68
68
|
- **Use the supported file and scheduling APIs.** Files go through `<FileUpload>` and `/api/files/*`; an upload is readable by its uploader only, so pass `visibility: "public"` to `uploadFile` or `<FileUpload>` for files every visitor sees; there is no `ctx.files`. One-shot work uses `ctx.scheduler.runAfter`, `runAt`, or `cancel`; there is no `defineWorkflow` or `defineJob`. Recurring work uses `cron("0 * * * *", "fnName")` in `buildManifest({ crons: [...] })`, imported from `@pylonsync/sdk`. Make the target function `internal: true`. It runs with anonymous auth, but its own `ctx.db.*` calls are server-side and bypass policies. Use `ctx.auth.elevate({ admin: true, reason: "..." })`, with a mandatory reason, only when chaining another internal function through `ctx.scheduler`.
|
|
@@ -18,14 +18,24 @@ increment in another without refreshing.
|
|
|
18
18
|
## How the realtime works
|
|
19
19
|
|
|
20
20
|
- `functions/joinWaitlist.ts`: a public **mutation** that validates, lowercases,
|
|
21
|
-
and dedupes the email,
|
|
22
|
-
|
|
23
|
-
- `
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
and dedupes the email, inserts one `Signup` row, and rewrites the PII-free
|
|
22
|
+
`WaitlistStat` row with the new count.
|
|
23
|
+
- The landing page reads `WaitlistStat` with `db.useQuery`. The row syncs to
|
|
24
|
+
every open tab, so the counter moves as soon as anyone joins. No polling.
|
|
25
|
+
- The counter island (`app/(marketing)/waitlist-hero.tsx`) is wrapped in
|
|
26
|
+
`<EnsureGuest>`, which mints an anonymous session so the live connection can
|
|
27
|
+
open.
|
|
28
|
+
|
|
29
|
+
The counter is the `Signup` table's row count. `counter.importedCount` in
|
|
30
|
+
`lib/site.config.ts` adds signups you collected somewhere else before this site
|
|
31
|
+
(an old form, a spreadsheet). It ships as 0.
|
|
32
|
+
|
|
33
|
+
## Demo data
|
|
34
|
+
|
|
35
|
+
In `pylon dev`, an empty waitlist gets about 180 fictional signups from the last
|
|
36
|
+
30 days, so the counter, chart, and list have data (`functions/seedDemo.ts`,
|
|
37
|
+
`lib/demo.ts`). Seeding runs only when `PYLON_DEMO_DATA` is on, or when it is unset and the app runs under `pylon dev`, and only while the `Signup` table is empty. `pylon start`, Docker, and Pylon Cloud deploys do not seed, because only `pylon dev` sets `PYLON_DEV_WATCH_DIR`. Set `PYLON_DEMO_DATA=0` to start
|
|
38
|
+
empty in development. Delete both files once you have real signups.
|
|
29
39
|
|
|
30
40
|
## Privacy
|
|
31
41
|
|
|
@@ -47,22 +57,28 @@ account can see signups; anyone else gets a locked screen.
|
|
|
47
57
|
|
|
48
58
|
## Rebrand it
|
|
49
59
|
|
|
50
|
-
Brand, colors, hero copy,
|
|
60
|
+
Brand, colors, hero copy, the launch date, value props, and FAQ content live in
|
|
51
61
|
**`lib/site.config.ts`**. Edit or generate that file to update the page without
|
|
52
62
|
changing JSX or CSS.
|
|
53
63
|
|
|
64
|
+
The tab icon is `app/icon.svg` (with `public/favicon.ico` for browsers that
|
|
65
|
+
request `/favicon.ico`). Both carry this brand's letter and colors; replace
|
|
66
|
+
them when you rename the brand.
|
|
67
|
+
|
|
54
68
|
## Layout
|
|
55
69
|
|
|
56
70
|
```
|
|
57
71
|
app.ts data model + manifest (Signup, User, policies, auth)
|
|
58
72
|
lib/site.config.ts ALL business copy + brand + colors (edit this)
|
|
59
73
|
lib/owner.ts owner-email gate (PYLON_OWNER_EMAIL)
|
|
60
|
-
lib/stats.ts
|
|
74
|
+
lib/stats.ts dashboard types + the public count
|
|
75
|
+
lib/launch.ts the launch line from hero.launchDate
|
|
76
|
+
lib/demo.ts demo signups + the dev-only gate
|
|
61
77
|
functions/joinWaitlist.ts public mutation: validate + dedupe + insert
|
|
62
|
-
functions/
|
|
78
|
+
functions/seedDemo.ts dev-only demo signups (see Demo data)
|
|
63
79
|
functions/waitlistStats.ts owner-only reactive query: total + chart + list
|
|
64
|
-
app/page.tsx
|
|
65
|
-
app/waitlist-hero.tsx
|
|
80
|
+
app/(marketing)/page.tsx the landing page (server-rendered)
|
|
81
|
+
app/(marketing)/waitlist-hero.tsx client island: signup form + live counter
|
|
66
82
|
app/login/page.tsx owner sign-in
|
|
67
83
|
app/dashboard/ owner dashboard (auth-gated, live)
|
|
68
84
|
app/globals.css Tailwind entrypoint (compiled by Pylon)
|
|
@@ -3,6 +3,7 @@ import { type Metadata } from "@pylonsync/react";
|
|
|
3
3
|
import { WRAP, FactList, ProductMock } from "@/components/marketing";
|
|
4
4
|
import { SignupForm, LiveCount } from "./waitlist-hero";
|
|
5
5
|
import { siteConfig } from "@/lib/site.config";
|
|
6
|
+
import { launchLabel } from "@/lib/launch";
|
|
6
7
|
|
|
7
8
|
// SEO metadata: server-rendered into <head>, so the page is fully indexable.
|
|
8
9
|
// All copy lives in lib/site.config.ts; edit it there to rebrand.
|
|
@@ -25,6 +26,7 @@ export const metadata: Metadata = {
|
|
|
25
26
|
// Signed-in state (the nav's "Dashboard" link) is resolved in the layout.
|
|
26
27
|
export default function LandingPage() {
|
|
27
28
|
const { hero, counter, mock, facts, faq } = siteConfig;
|
|
29
|
+
const launch = launchLabel(hero.launchDate, Date.now());
|
|
28
30
|
|
|
29
31
|
return (
|
|
30
32
|
<div>
|
|
@@ -36,9 +38,14 @@ export default function LandingPage() {
|
|
|
36
38
|
</h1>
|
|
37
39
|
<p className="mt-6 max-w-md text-[17px] leading-relaxed text-chalk-2">{hero.subcopy}</p>
|
|
38
40
|
<div className="mt-8 max-w-md">
|
|
39
|
-
<SignupForm hero={hero} />
|
|
41
|
+
<SignupForm hero={hero} showCountNote={counter.enabled} />
|
|
42
|
+
</div>
|
|
43
|
+
<div className="mt-8 flex flex-col gap-2 border-t border-line pt-5">
|
|
44
|
+
{counter.enabled ? (
|
|
45
|
+
<LiveCount importedCount={counter.importedCount} label={counter.label} labelOne={counter.labelOne} />
|
|
46
|
+
) : null}
|
|
47
|
+
{launch ? <p className="font-mono-ui text-[13px] text-brand">{launch}</p> : null}
|
|
40
48
|
</div>
|
|
41
|
-
<p className="font-mono-ui mt-6 text-[13px] text-brand">{hero.launchNote}</p>
|
|
42
49
|
</div>
|
|
43
50
|
<ProductMock
|
|
44
51
|
windowTitle={mock.windowTitle}
|
|
@@ -56,11 +63,6 @@ export default function LandingPage() {
|
|
|
56
63
|
<div className="mt-8">
|
|
57
64
|
<FactList items={facts.items} />
|
|
58
65
|
</div>
|
|
59
|
-
{counter.enabled ? (
|
|
60
|
-
<div className="mt-12 border-t border-line pt-5">
|
|
61
|
-
<LiveCount seed={counter.seedCount ?? 0} label={counter.label} />
|
|
62
|
-
</div>
|
|
63
|
-
) : null}
|
|
64
66
|
</section>
|
|
65
67
|
|
|
66
68
|
{/* ============================== FAQ ============================= */}
|