@pylonsync/create-pylon 0.19.1 → 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.
- package/bin/create-pylon.js +30 -7
- package/package.json +1 -1
- package/templates/agency/.env.example +7 -0
- 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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/waitlist/.env.example +7 -0
- 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,8 +1,10 @@
|
|
|
1
|
-
// Demo data for a new app:
|
|
2
|
-
// and comment, so the first visit opens on a feed
|
|
1
|
+
// Demo data for a new app: eight people who post, follow each other, like,
|
|
2
|
+
// and comment, so the first visit opens on a feed with content in it.
|
|
3
3
|
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
4
|
+
// Post photos live in public/images/posts and the server serves them at
|
|
5
|
+
// /images/posts/<key>.jpg. Demo people have no profile photo, so the app
|
|
6
|
+
// draws their initial. Demo user ids start with "demo_" so they never
|
|
7
|
+
// collide with a real or guest account.
|
|
6
8
|
// Pure data + pure shaping; functions/seedFeed.ts is a thin wrapper.
|
|
7
9
|
|
|
8
10
|
export interface SeedProfile {
|
|
@@ -12,6 +14,7 @@ export interface SeedProfile {
|
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
export interface SeedPost {
|
|
17
|
+
/** File name under public/images/posts, without `.jpg`. */
|
|
15
18
|
key: string;
|
|
16
19
|
author: string;
|
|
17
20
|
caption: string;
|
|
@@ -29,99 +32,54 @@ export interface SeedComment {
|
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
export const SEED_PROFILES: SeedProfile[] = [
|
|
32
|
-
{ username: "
|
|
33
|
-
{ username: "
|
|
34
|
-
{ username: "
|
|
35
|
-
{ username: "kenji.
|
|
36
|
-
{ username: "
|
|
37
|
-
{ username: "sam.
|
|
38
|
-
{ username: "
|
|
39
|
-
{ username: "
|
|
40
|
-
{ username: "nora.h", displayName: "Nora Hughes", bio: "Product designer. Biscuit's person." },
|
|
41
|
-
{ username: "ari.wanders", displayName: "Ari Cohen", bio: "Trains over planes." },
|
|
42
|
-
{ username: "dev.draws", displayName: "Dev Patel", bio: "Architect. A sketch every morning before work." },
|
|
43
|
-
{ username: "june.surfs", displayName: "June Tanaka", bio: "Cold water surfer on the Oregon coast." },
|
|
35
|
+
{ username: "maya.rivera", displayName: "Maya Rivera", bio: "Travel photographer. Currently in Lisbon." },
|
|
36
|
+
{ username: "jordan.eats", displayName: "Jordan Brooks", bio: "Cooking at home, eating out, writing it all down." },
|
|
37
|
+
{ username: "priya.home", displayName: "Priya Shah", bio: "Interior designer. Small rooms, good light." },
|
|
38
|
+
{ username: "kenji.mori", displayName: "Kenji Mori", bio: "Architecture and night walks. Tokyo." },
|
|
39
|
+
{ username: "elena.runs", displayName: "Elena Berg", bio: "Trail runner. Mountains most weekends." },
|
|
40
|
+
{ username: "sam.and.juno", displayName: "Sam Whitaker", bio: "Juno is the golden one." },
|
|
41
|
+
{ username: "amara.o", displayName: "Amara Okafor", bio: "Coffee, markets, and early mornings." },
|
|
42
|
+
{ username: "leo.haddad", displayName: "Leo Haddad", bio: "Road trips and sunsets. Film when I can." },
|
|
44
43
|
];
|
|
45
44
|
|
|
46
45
|
export const SEED_POSTS: SeedPost[] = [
|
|
47
|
-
{ key: "
|
|
48
|
-
{ key: "
|
|
49
|
-
{ key: "
|
|
50
|
-
{ key: "
|
|
51
|
-
{ key: "
|
|
52
|
-
{ key: "
|
|
53
|
-
{ key: "
|
|
54
|
-
{ key: "kenji-gravel", author: "kenji.rides", caption: "82 km, 1,400 m of climbing, one flat. Good day.", shape: "portrait", age: 30 },
|
|
55
|
-
{ key: "sam-tomatoes", author: "sam.grows", caption: "First proper harvest of the year. The yellow ones are Sungold.", shape: "square", age: 34 },
|
|
56
|
-
{ key: "theo-boulder", author: "theo.climbs", caption: "Set a new blue circuit this week. This one is the crux of number 6.", shape: "portrait", age: 40 },
|
|
57
|
-
{ key: "ari-train", author: "ari.wanders", caption: "Night train from Vienna to Venice. Woke up to this.", shape: "portrait", age: 46 },
|
|
58
|
-
{ key: "nora-desk", author: "nora.h", caption: "New desk setup. @biscuit.corgi approved the rug.", shape: "square", age: 52 },
|
|
59
|
-
{ key: "mara-buns", author: "mara.bakes", caption: "Cardamom buns for the neighbours. Kept two.", shape: "square", age: 60 },
|
|
60
|
-
{ key: "june-board", author: "june.surfs", caption: "Waxed and ready for tomorrow.", shape: "square", age: 70 },
|
|
61
|
-
{ key: "rosa-latte", author: "rosa.roasts", caption: "Tuesday latte art practice. Getting there.", shape: "square", age: 78 },
|
|
62
|
-
{ key: "ines-wheel", author: "ines.clay", caption: "Trimming feet on a batch of bowls. The quiet part of the week.", shape: "portrait", age: 90 },
|
|
63
|
-
{ key: "lou-diner", author: "lou.streets", caption: "Counter seats at the diner on Graham. Coffee refills forever.", shape: "square", age: 100 },
|
|
64
|
-
{ key: "biscuit-beach", author: "biscuit.corgi", caption: "First time at the beach. Sand everywhere. No regrets.", shape: "portrait", age: 110 },
|
|
65
|
-
{ key: "dev-model", author: "dev.draws", caption: "Card model for the community centre competition entry.", shape: "square", age: 124 },
|
|
66
|
-
{ key: "kenji-coffee", author: "kenji.rides", caption: "Mid-ride coffee stop. The bike rests too.", shape: "square", age: 140 },
|
|
67
|
-
{ key: "sam-shed", author: "sam.grows", caption: "Seed trays in the shed. Kale, chard, and far too much basil.", shape: "portrait", age: 155 },
|
|
68
|
-
{ key: "theo-chalk", author: "theo.climbs", caption: "Chalk bag, tape, and a very tired pair of shoes.", shape: "square", age: 170 },
|
|
69
|
-
{ key: "ari-market", author: "ari.wanders", caption: "Morning market in Palermo. I bought too many lemons.", shape: "square", age: 190 },
|
|
70
|
-
{ key: "nora-sketches", author: "nora.h", caption: "Paper first, screens later. Wireframes for the booking flow.", shape: "square", age: 210 },
|
|
71
|
-
{ key: "mara-starter", author: "mara.bakes", caption: "Meet Olof, the starter. Eleven years old this month.", shape: "portrait", age: 240 },
|
|
72
|
-
{ key: "june-van", author: "june.surfs", caption: "Home for the weekend.", shape: "square", age: 280 },
|
|
73
|
-
{ key: "ines-studio", author: "ines.clay", caption: "The studio shelves on a good week.", shape: "portrait", age: 320 },
|
|
74
|
-
{ key: "lou-rain", author: "lou.streets", caption: "Rain on the J train platform.", shape: "portrait", age: 360 },
|
|
46
|
+
{ key: "lisbon", author: "maya.rivera", caption: "Tram 28 at golden hour. Waited twenty minutes for this one and it was worth it.", shape: "square", age: 1.5 },
|
|
47
|
+
{ key: "coffee", author: "amara.o", caption: "Flat white and a croissant before the market opens.", shape: "square", age: 3 },
|
|
48
|
+
{ key: "dog", author: "sam.and.juno", caption: "Juno found the tall grass again.", shape: "square", age: 5 },
|
|
49
|
+
{ key: "run", author: "elena.runs", caption: "Sunrise on the ridge. 18 km, 900 m up, legs gone.", shape: "square", age: 8 },
|
|
50
|
+
{ key: "ramen", author: "jordan.eats", caption: "Tonkotsu from the new place on 5th. Broth cooked for 14 hours and you can tell.", shape: "square", age: 11 },
|
|
51
|
+
{ key: "arch", author: "kenji.mori", caption: "Curves and shadows. The museum extension at noon.", shape: "square", age: 14 },
|
|
52
|
+
{ key: "sunset", author: "leo.haddad", caption: "Big Sur, last light. 30 second exposure.", shape: "square", age: 20 },
|
|
75
53
|
];
|
|
76
54
|
|
|
77
55
|
export const SEED_COMMENTS: SeedComment[] = [
|
|
78
|
-
{ post: "
|
|
79
|
-
{ post: "
|
|
80
|
-
{ post: "
|
|
81
|
-
{ post: "
|
|
82
|
-
{ post: "
|
|
83
|
-
{ post: "
|
|
84
|
-
{ post: "
|
|
85
|
-
{ post: "
|
|
86
|
-
{ post: "
|
|
87
|
-
{ post: "
|
|
88
|
-
{ post: "
|
|
89
|
-
{ post: "
|
|
90
|
-
{ post: "lou-crosswalk", author: "ari.wanders", text: "The light in this one.", after: 4 },
|
|
91
|
-
{ post: "dev-sketch", author: "ines.clay", text: "Twenty minutes? Show-off.", after: 1 },
|
|
92
|
-
{ post: "kenji-gravel", author: "june.surfs", text: "Where was the flat?", after: 2 },
|
|
93
|
-
{ post: "kenji-gravel", author: "kenji.rides", text: "@june.surfs about 5 km from the end, of course.", after: 3 },
|
|
94
|
-
{ post: "sam-tomatoes", author: "mara.bakes", text: "Tomato and bread season.", after: 1 },
|
|
95
|
-
{ post: "theo-boulder", author: "kenji.rides", text: "Looks sandbagged.", after: 2 },
|
|
96
|
-
{ post: "theo-boulder", author: "theo.climbs", text: "@kenji.rides it is a fair blue. Mostly.", after: 2.5 },
|
|
97
|
-
{ post: "ari-train", author: "lou.streets", text: "Adding this to the list.", after: 5 },
|
|
98
|
-
{ post: "nora-desk", author: "dev.draws", text: "Where is the lamp from?", after: 1 },
|
|
99
|
-
{ post: "mara-buns", author: "rosa.roasts", text: "Recipe please.", after: 2 },
|
|
100
|
-
{ post: "biscuit-beach", author: "june.surfs", text: "Surf lessons next.", after: 1 },
|
|
101
|
-
{ post: "dev-model", author: "ines.clay", text: "Good luck with the entry.", after: 3 },
|
|
102
|
-
{ post: "sam-shed", author: "mara.bakes", text: "Pesto for the whole street then.", after: 4 },
|
|
103
|
-
{ post: "mara-starter", author: "biscuit.corgi", text: "Can I eat Olof.", after: 2 },
|
|
104
|
-
{ post: "mara-starter", author: "mara.bakes", text: "@biscuit.corgi no.", after: 2.2 },
|
|
56
|
+
{ post: "lisbon", author: "leo.haddad", text: "The light on those tiles. Which street is this?", after: 0.3 },
|
|
57
|
+
{ post: "lisbon", author: "maya.rivera", text: "@leo.haddad Rua da Conceição, just before it turns up to the cathedral.", after: 0.6 },
|
|
58
|
+
{ post: "lisbon", author: "amara.o", text: "Adding this to the list for May.", after: 0.9 },
|
|
59
|
+
{ post: "coffee", author: "jordan.eats", text: "That rosetta is perfect.", after: 0.5 },
|
|
60
|
+
{ post: "coffee", author: "priya.home", text: "Where is this? I need that table.", after: 1 },
|
|
61
|
+
{ post: "dog", author: "elena.runs", text: "Juno looks so happy.", after: 0.4 },
|
|
62
|
+
{ post: "dog", author: "amara.o", text: "Best dog on this app.", after: 1.2 },
|
|
63
|
+
{ post: "run", author: "kenji.mori", text: "Incredible view. How early did you start?", after: 1 },
|
|
64
|
+
{ post: "run", author: "elena.runs", text: "@kenji.mori headlamps on at 4:30.", after: 1.5 },
|
|
65
|
+
{ post: "ramen", author: "maya.rivera", text: "Going this week.", after: 2 },
|
|
66
|
+
{ post: "arch", author: "priya.home", text: "Those shadows are unreal.", after: 1 },
|
|
67
|
+
{ post: "sunset", author: "sam.and.juno", text: "Colors like this make me want to drive up the coast tonight.", after: 2 },
|
|
105
68
|
];
|
|
106
69
|
|
|
107
70
|
/** Who each demo user follows, as username → usernames. */
|
|
108
71
|
export const SEED_FOLLOWS: Record<string, string[]> = {
|
|
109
|
-
"
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
"kenji.
|
|
113
|
-
"
|
|
114
|
-
"sam.
|
|
115
|
-
"
|
|
116
|
-
"
|
|
117
|
-
"nora.h": ["biscuit.corgi", "dev.draws", "ines.clay", "lou.streets", "mara.bakes"],
|
|
118
|
-
"ari.wanders": ["lou.streets", "june.surfs", "kenji.rides", "theo.climbs"],
|
|
119
|
-
"dev.draws": ["ines.clay", "nora.h", "lou.streets"],
|
|
120
|
-
"june.surfs": ["kenji.rides", "biscuit.corgi", "ari.wanders", "theo.climbs"],
|
|
72
|
+
"maya.rivera": ["leo.haddad", "amara.o", "priya.home", "kenji.mori"],
|
|
73
|
+
"jordan.eats": ["amara.o", "maya.rivera", "sam.and.juno"],
|
|
74
|
+
"priya.home": ["kenji.mori", "maya.rivera", "amara.o", "elena.runs"],
|
|
75
|
+
"kenji.mori": ["priya.home", "leo.haddad", "elena.runs"],
|
|
76
|
+
"elena.runs": ["sam.and.juno", "leo.haddad", "maya.rivera", "kenji.mori"],
|
|
77
|
+
"sam.and.juno": ["elena.runs", "jordan.eats", "amara.o"],
|
|
78
|
+
"amara.o": ["jordan.eats", "maya.rivera", "priya.home", "sam.and.juno", "elena.runs"],
|
|
79
|
+
"leo.haddad": ["maya.rivera", "elena.runs", "kenji.mori"],
|
|
121
80
|
};
|
|
122
81
|
|
|
123
82
|
export const demoUserId = (username: string) => `demo_${username.replace(/\./g, "_")}`;
|
|
124
|
-
export const avatarPath = (username: string) => `/images/avatars/${username}.jpg`;
|
|
125
83
|
export const postImagePath = (key: string) => `/images/posts/${key}.jpg`;
|
|
126
84
|
|
|
127
85
|
/**
|
|
@@ -158,7 +116,7 @@ export function shapeSeed(now: number = Date.now()): ShapedSeed {
|
|
|
158
116
|
username: p.username,
|
|
159
117
|
displayName: p.displayName,
|
|
160
118
|
bio: p.bio,
|
|
161
|
-
avatarUrl:
|
|
119
|
+
avatarUrl: null,
|
|
162
120
|
createdAt: hoursAgo(2000 - i * 40),
|
|
163
121
|
})),
|
|
164
122
|
posts: SEED_POSTS.map((p) => ({
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { SEED_COMMENTS, SEED_FOLLOWS, SEED_POSTS, SEED_PROFILES, shapeSeed } from "../lib/seed";
|
|
5
|
+
|
|
6
|
+
const PUBLIC = join(import.meta.dir, "..", "public");
|
|
7
|
+
|
|
8
|
+
/** Every image path the seed writes that the server must serve from public/. */
|
|
9
|
+
function localImages(): string[] {
|
|
10
|
+
const seed = shapeSeed(0);
|
|
11
|
+
const urls = [
|
|
12
|
+
...seed.posts.map((p) => p.row.imageUrl),
|
|
13
|
+
...seed.profiles.map((p) => p.avatarUrl),
|
|
14
|
+
];
|
|
15
|
+
return urls.filter((u): u is string => typeof u === "string" && u.startsWith("/"));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
describe("demo seed", () => {
|
|
19
|
+
test("every local image it references exists in public/", () => {
|
|
20
|
+
const images = localImages();
|
|
21
|
+
expect(images.length).toBeGreaterThan(0);
|
|
22
|
+
const missing = images.filter((url) => !existsSync(join(PUBLIC, url)));
|
|
23
|
+
expect(missing).toEqual([]);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("posts, comments, and follows only name demo people", () => {
|
|
27
|
+
const people = new Set(SEED_PROFILES.map((p) => p.username));
|
|
28
|
+
const posts = new Set(SEED_POSTS.map((p) => p.key));
|
|
29
|
+
for (const p of SEED_POSTS) expect(people.has(p.author)).toBe(true);
|
|
30
|
+
for (const c of SEED_COMMENTS) {
|
|
31
|
+
expect(people.has(c.author)).toBe(true);
|
|
32
|
+
expect(posts.has(c.post)).toBe(true);
|
|
33
|
+
}
|
|
34
|
+
for (const [from, tos] of Object.entries(SEED_FOLLOWS)) {
|
|
35
|
+
expect(people.has(from)).toBe(true);
|
|
36
|
+
for (const to of tos) expect(people.has(to)).toBe(true);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -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 subscriber list with fictional rows. Seeding runs
|
|
16
|
+
# only 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
|
|
@@ -18,11 +18,23 @@ increment in another without refreshing.
|
|
|
18
18
|
## How the realtime works
|
|
19
19
|
|
|
20
20
|
- `functions/subscribe.ts`: a public **mutation** that validates, lowercases,
|
|
21
|
-
and dedupes the email, inserts one `Subscriber` row, and
|
|
22
|
-
PII-free `SubscriberCount` row.
|
|
23
|
-
- `app/newsletter-signup.tsx`
|
|
21
|
+
and dedupes the email, inserts one `Subscriber` row, and recounts into the
|
|
22
|
+
public, PII-free `SubscriberCount` row.
|
|
23
|
+
- `app/(marketing)/newsletter-signup.tsx` reads `SubscriberCount` with
|
|
24
24
|
`db.useQuery`, so the live count syncs to every open tab. No polling.
|
|
25
25
|
|
|
26
|
+
The counter is the `Subscriber` table's row count, and it is hidden while the
|
|
27
|
+
list is empty. `newsletter.importedCount` in `lib/site.config.ts` adds
|
|
28
|
+
subscribers you are moving over from another tool. It ships as 0.
|
|
29
|
+
|
|
30
|
+
## Demo data
|
|
31
|
+
|
|
32
|
+
In `pylon dev`, an empty list gets about 180 fictional subscribers from the last
|
|
33
|
+
30 days, so the counter, chart, and list have data (`functions/seedDemo.ts`,
|
|
34
|
+
`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 `Subscriber` table is
|
|
35
|
+
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`
|
|
36
|
+
to start empty in development. Delete both files once you have real subscribers.
|
|
37
|
+
|
|
26
38
|
## Privacy
|
|
27
39
|
|
|
28
40
|
The `Subscriber` entity holds reader emails (PII), so its policy in `app.ts`
|
|
@@ -44,6 +56,10 @@ Your name, colors, bio, offerings, testimonials, newsletter copy, and links
|
|
|
44
56
|
live in **`lib/site.config.ts`**. Edit that file, or generate it, to re-theme
|
|
45
57
|
the page.
|
|
46
58
|
|
|
59
|
+
The tab icon is `app/icon.svg` (with `public/favicon.ico` for browsers that
|
|
60
|
+
request `/favicon.ico`). Both carry this brand's letter and colors; replace
|
|
61
|
+
them when you rename the brand.
|
|
62
|
+
|
|
47
63
|
## Layout
|
|
48
64
|
|
|
49
65
|
```
|
|
@@ -51,8 +67,11 @@ app.ts Subscriber + SubscriberCount + User + policies
|
|
|
51
67
|
lib/site.config.ts ALL copy + brand + offerings + newsletter (edit this)
|
|
52
68
|
functions/subscribe.ts public mutation: validate + dedupe + count
|
|
53
69
|
functions/subscriberStats.ts owner-only query: subscribers + emails
|
|
54
|
-
|
|
55
|
-
|
|
70
|
+
functions/seedDemo.ts dev-only demo subscribers (see Demo data)
|
|
71
|
+
lib/stats.ts dashboard types + the public count
|
|
72
|
+
lib/demo.ts demo subscribers + the dev-only gate
|
|
73
|
+
app/(marketing)/page.tsx the landing page (server-rendered)
|
|
74
|
+
app/(marketing)/newsletter-signup.tsx client island: signup form + live counter
|
|
56
75
|
app/dashboard/ owner dashboard (auth-gated, live)
|
|
57
76
|
```
|
|
58
77
|
|
|
@@ -4,6 +4,7 @@ import React, { useEffect, useRef, useState } from "react";
|
|
|
4
4
|
import { db, callFn } from "@pylonsync/react";
|
|
5
5
|
import { EnsureGuest } from "@pylonsync/client";
|
|
6
6
|
import type { CreatorConfig } from "@/lib/site.config";
|
|
7
|
+
import { publicCount } from "@/lib/stats";
|
|
7
8
|
|
|
8
9
|
// The newsletter signup — email capture plus a LIVE subscriber counter. This is
|
|
9
10
|
// the realtime proof: the counter is a live `db.useQuery("SubscriberCount")`
|
|
@@ -23,7 +24,11 @@ export function NewsletterSignup({ newsletter }: Props) {
|
|
|
23
24
|
<div>
|
|
24
25
|
<SubscribeForm newsletter={newsletter} />
|
|
25
26
|
<div className="mt-3">
|
|
26
|
-
<LiveCounter
|
|
27
|
+
<LiveCounter
|
|
28
|
+
importedCount={newsletter.importedCount}
|
|
29
|
+
label={newsletter.counterLabel}
|
|
30
|
+
labelOne={newsletter.counterLabelOne}
|
|
31
|
+
/>
|
|
27
32
|
</div>
|
|
28
33
|
</div>
|
|
29
34
|
);
|
|
@@ -100,27 +105,43 @@ interface SubscriberCountRow {
|
|
|
100
105
|
count: number;
|
|
101
106
|
}
|
|
102
107
|
|
|
103
|
-
|
|
108
|
+
type CounterProps = { importedCount: number; label: string; labelOne: string };
|
|
109
|
+
|
|
110
|
+
export function LiveCounter(props: CounterProps) {
|
|
104
111
|
return (
|
|
105
|
-
<EnsureGuest fallback={
|
|
106
|
-
<LiveCounterInner
|
|
112
|
+
<EnsureGuest fallback={null}>
|
|
113
|
+
<LiveCounterInner {...props} />
|
|
107
114
|
</EnsureGuest>
|
|
108
115
|
);
|
|
109
116
|
}
|
|
110
117
|
|
|
111
|
-
function LiveCounterInner({
|
|
118
|
+
function LiveCounterInner({ importedCount, label, labelOne }: CounterProps) {
|
|
112
119
|
const { data, loading } = db.useQuery<SubscriberCountRow>("SubscriberCount");
|
|
113
|
-
|
|
114
|
-
|
|
120
|
+
|
|
121
|
+
// In `pylon dev` an empty list gets demo subscribers (functions/seedDemo.ts).
|
|
122
|
+
// The call goes out only when the synced count is empty, so a live site with
|
|
123
|
+
// subscribers never makes it.
|
|
124
|
+
const empty = !loading && data.length === 0;
|
|
125
|
+
const sent = useRef(false);
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
if (!empty || sent.current) return;
|
|
128
|
+
sent.current = true;
|
|
129
|
+
void callFn("seedDemo", {}).catch(() => {});
|
|
130
|
+
}, [empty]);
|
|
131
|
+
|
|
132
|
+
if (loading) return null;
|
|
133
|
+
const value = publicCount(data, importedCount);
|
|
134
|
+
// A new newsletter has no subscribers yet; show nothing rather than "0".
|
|
135
|
+
if (value === 0) return null;
|
|
136
|
+
return <CounterView value={value} label={value === 1 ? labelOne : label} />;
|
|
115
137
|
}
|
|
116
138
|
|
|
117
|
-
// Plain text under the form
|
|
118
|
-
|
|
119
|
-
function CounterView({ value, label, live }: { value: number; label: string; live?: boolean }) {
|
|
139
|
+
// Plain text under the form, shown once the count has synced.
|
|
140
|
+
function CounterView({ value, label }: { value: number; label: string }) {
|
|
120
141
|
const shown = useCountUp(value);
|
|
121
142
|
return (
|
|
122
|
-
<p className="text-[15px] text-ink-2" data-
|
|
123
|
-
<span className="tabular-nums text-ink">{shown.toLocaleString()}</span> {label}
|
|
143
|
+
<p className="text-[15px] text-ink-2" data-testid="live-count">
|
|
144
|
+
<span className="tabular-nums text-ink">{shown.toLocaleString("en-US")}</span> {label}
|
|
124
145
|
</p>
|
|
125
146
|
);
|
|
126
147
|
}
|
|
@@ -51,7 +51,7 @@ export function AuthForm() {
|
|
|
51
51
|
<div className="space-y-5">
|
|
52
52
|
<form onSubmit={onSubmit} className="space-y-4">
|
|
53
53
|
<label className="block">
|
|
54
|
-
<span className="mb-1.5 block text-[
|
|
54
|
+
<span className="mb-1.5 block text-[15px] text-ink-2">Email</span>
|
|
55
55
|
<input
|
|
56
56
|
type="email"
|
|
57
57
|
value={email}
|
|
@@ -59,11 +59,11 @@ export function AuthForm() {
|
|
|
59
59
|
required
|
|
60
60
|
autoComplete="email"
|
|
61
61
|
placeholder="you@yourbusiness.com"
|
|
62
|
-
className="h-
|
|
62
|
+
className="h-11 w-full rounded-md border border-rule bg-white px-3.5 text-[16px] text-ink outline-none transition placeholder:text-ink-2/60 focus:border-brand focus:ring-2 focus:ring-brand/20"
|
|
63
63
|
/>
|
|
64
64
|
</label>
|
|
65
65
|
<label className="block">
|
|
66
|
-
<span className="mb-1.5 block text-[
|
|
66
|
+
<span className="mb-1.5 block text-[15px] text-ink-2">Password</span>
|
|
67
67
|
<input
|
|
68
68
|
type="password"
|
|
69
69
|
value={password}
|
|
@@ -71,7 +71,7 @@ export function AuthForm() {
|
|
|
71
71
|
required
|
|
72
72
|
autoComplete={mode === "login" ? "current-password" : "new-password"}
|
|
73
73
|
placeholder={mode === "login" ? "Your password" : "At least 10 characters"}
|
|
74
|
-
className="h-
|
|
74
|
+
className="h-11 w-full rounded-md border border-rule bg-white px-3.5 text-[16px] text-ink outline-none transition placeholder:text-ink-2/60 focus:border-brand focus:ring-2 focus:ring-brand/20"
|
|
75
75
|
/>
|
|
76
76
|
</label>
|
|
77
77
|
{error ? (
|
|
@@ -82,13 +82,13 @@ export function AuthForm() {
|
|
|
82
82
|
<button
|
|
83
83
|
type="submit"
|
|
84
84
|
disabled={pending}
|
|
85
|
-
className="inline-flex h-
|
|
85
|
+
className="inline-flex h-11 w-full items-center justify-center rounded-md bg-brand text-[16px] font-medium text-white transition-opacity hover:opacity-90 disabled:opacity-60"
|
|
86
86
|
>
|
|
87
87
|
{pending ? "…" : mode === "login" ? "Sign in" : "Create account"}
|
|
88
88
|
</button>
|
|
89
89
|
</form>
|
|
90
90
|
|
|
91
|
-
<p className="text-center text-[
|
|
91
|
+
<p className="text-center text-[15px] text-ink-2">
|
|
92
92
|
{mode === "login" ? "First time here?" : "Already have an account?"}{" "}
|
|
93
93
|
<button
|
|
94
94
|
type="button"
|
|
@@ -96,7 +96,7 @@ export function AuthForm() {
|
|
|
96
96
|
setMode(mode === "login" ? "subscriber" : "login");
|
|
97
97
|
setError(null);
|
|
98
98
|
}}
|
|
99
|
-
className="font-medium text-
|
|
99
|
+
className="font-medium text-ink underline decoration-brand/50 underline-offset-4"
|
|
100
100
|
>
|
|
101
101
|
{mode === "login" ? "Create the owner account" : "Sign in"}
|
|
102
102
|
</button>
|