create-start-app 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/README.md +41 -9
  2. package/dist/add-ons.js +69 -0
  3. package/dist/cli.js +78 -0
  4. package/dist/constants.js +4 -0
  5. package/dist/create-app.js +371 -0
  6. package/dist/index.js +2 -347
  7. package/dist/mcp.js +169 -0
  8. package/dist/options.js +260 -0
  9. package/dist/{utils/getPackageManager.js → package-manager.js} +1 -0
  10. package/dist/types.js +1 -0
  11. package/package.json +8 -4
  12. package/src/add-ons.ts +156 -0
  13. package/src/cli.ts +114 -0
  14. package/src/constants.ts +7 -0
  15. package/src/create-app.ts +582 -0
  16. package/src/index.ts +2 -507
  17. package/src/mcp.ts +205 -0
  18. package/src/options.ts +308 -0
  19. package/src/{utils/getPackageManager.ts → package-manager.ts} +1 -0
  20. package/src/types.ts +30 -0
  21. package/templates/react/add-on/clerk/README.md +3 -0
  22. package/templates/react/add-on/clerk/assets/_dot_env.local.append +2 -0
  23. package/templates/react/add-on/clerk/assets/src/integrations/clerk/header-user.tsx +19 -0
  24. package/templates/react/add-on/clerk/assets/src/integrations/clerk/provider.tsx +18 -0
  25. package/templates/react/add-on/clerk/assets/src/routes/demo.clerk.tsx +20 -0
  26. package/templates/react/add-on/clerk/info.json +13 -0
  27. package/templates/react/add-on/clerk/package.json +5 -0
  28. package/templates/react/add-on/convex/README.md +4 -0
  29. package/templates/react/add-on/convex/assets/_dot_cursorrules.append +93 -0
  30. package/templates/react/add-on/convex/assets/_dot_env.local.append +3 -0
  31. package/templates/react/add-on/convex/assets/convex/products.ts +8 -0
  32. package/templates/react/add-on/convex/assets/convex/schema.ts +10 -0
  33. package/templates/react/add-on/convex/assets/src/integrations/convex/provider.tsx +20 -0
  34. package/templates/react/add-on/convex/assets/src/routes/demo.convex.tsx +33 -0
  35. package/templates/react/add-on/convex/info.json +13 -0
  36. package/templates/react/add-on/convex/package.json +6 -0
  37. package/templates/react/add-on/form/assets/src/routes/demo.form.tsx.ejs +62 -0
  38. package/templates/react/add-on/form/info.json +13 -0
  39. package/templates/react/add-on/form/package.json +5 -0
  40. package/templates/react/add-on/module-federation/assets/module-federation.config.js.ejs +31 -0
  41. package/templates/react/add-on/module-federation/assets/src/demo-mf-component.tsx +3 -0
  42. package/templates/react/add-on/module-federation/assets/src/demo-mf-self-contained.tsx +11 -0
  43. package/templates/react/add-on/module-federation/info.json +7 -0
  44. package/templates/react/add-on/module-federation/package.json +5 -0
  45. package/templates/react/add-on/netlify/README.md +11 -0
  46. package/templates/react/add-on/netlify/info.json +7 -0
  47. package/templates/react/add-on/sentry/assets/_dot_cursorrules.append +22 -0
  48. package/templates/react/add-on/sentry/assets/_dot_env.local.append +2 -0
  49. package/templates/react/add-on/sentry/assets/src/app/global-middleware.ts +25 -0
  50. package/templates/react/add-on/sentry/assets/src/routes/demo.sentry.testing.tsx +480 -0
  51. package/templates/react/add-on/sentry/info.json +14 -0
  52. package/templates/react/add-on/sentry/package.json +7 -0
  53. package/templates/react/add-on/shadcn/README.md +7 -0
  54. package/templates/react/add-on/shadcn/assets/_dot_cursorrules.append +7 -0
  55. package/templates/react/add-on/shadcn/info.json +11 -0
  56. package/templates/react/add-on/start/assets/app.config.ts +16 -0
  57. package/templates/react/add-on/start/assets/postcss.config.ts +5 -0
  58. package/templates/react/add-on/start/assets/src/api.ts +6 -0
  59. package/templates/react/add-on/start/assets/src/client.tsx +10 -0
  60. package/templates/react/add-on/start/assets/src/router.tsx.ejs +51 -0
  61. package/templates/react/add-on/start/assets/src/routes/api.demo-names.ts +11 -0
  62. package/templates/react/add-on/start/assets/src/routes/demo.start.api-request.tsx.ejs +33 -0
  63. package/templates/react/add-on/start/assets/src/routes/demo.start.server-funcs.tsx +49 -0
  64. package/templates/react/add-on/start/assets/src/ssr.tsx +12 -0
  65. package/templates/react/add-on/start/info.json +19 -0
  66. package/templates/react/add-on/start/package.json +14 -0
  67. package/templates/react/add-on/store/assets/src/lib/demo-store.ts +13 -0
  68. package/templates/react/add-on/store/assets/src/routes/demo.store.tsx.ejs +75 -0
  69. package/templates/react/add-on/store/info.json +13 -0
  70. package/templates/react/add-on/store/package.json +6 -0
  71. package/templates/react/add-on/tanstack-query/assets/src/integrations/tanstack-query/layout.tsx +5 -0
  72. package/templates/react/add-on/tanstack-query/assets/src/integrations/tanstack-query/provider.tsx +9 -0
  73. package/templates/react/add-on/tanstack-query/assets/src/routes/demo.tanstack-query.tsx.ejs +38 -0
  74. package/templates/react/add-on/tanstack-query/info.json +13 -0
  75. package/templates/react/add-on/tanstack-query/package.json +6 -0
  76. package/templates/{base → react/base}/README.md.ejs +9 -0
  77. package/templates/react/base/_dot_vscode/settings.json +11 -0
  78. package/templates/react/base/src/components/Header.tsx.ejs +25 -0
  79. package/templates/{base/tsconfig.json → react/base/tsconfig.json.ejs} +5 -1
  80. package/templates/react/base/vite.config.js.ejs +24 -0
  81. package/templates/{code-router → react/code-router}/src/main.tsx.ejs +17 -1
  82. package/templates/react/example/tanchat/README.md +37 -0
  83. package/templates/react/example/tanchat/assets/_dot_env.local.append +2 -0
  84. package/templates/react/example/tanchat/assets/src/components/demo.SettingsDialog.tsx +148 -0
  85. package/templates/react/example/tanchat/assets/src/demo.index.css +220 -0
  86. package/templates/react/example/tanchat/assets/src/routes/example.chat.tsx.ejs +375 -0
  87. package/templates/react/example/tanchat/assets/src/store/demo.hooks.ts +21 -0
  88. package/templates/react/example/tanchat/assets/src/store/demo.store.ts +133 -0
  89. package/templates/react/example/tanchat/assets/src/utils/demo.ai.ts +108 -0
  90. package/templates/react/example/tanchat/info.json +15 -0
  91. package/templates/react/example/tanchat/package.json +10 -0
  92. package/templates/react/file-router/src/routes/__root.tsx.ejs +71 -0
  93. package/templates/solid/add-on/form/assets/src/routes/demo.form.tsx.ejs +148 -0
  94. package/templates/solid/add-on/form/info.json +13 -0
  95. package/templates/solid/add-on/form/package.json +5 -0
  96. package/templates/solid/add-on/module-federation/assets/module-federation.config.js.ejs +27 -0
  97. package/templates/solid/add-on/module-federation/assets/src/demo-mf-component.tsx +3 -0
  98. package/templates/solid/add-on/module-federation/assets/src/demo-mf-self-contained.tsx +9 -0
  99. package/templates/solid/add-on/module-federation/info.json +7 -0
  100. package/templates/solid/add-on/module-federation/package.json +5 -0
  101. package/templates/solid/add-on/sentry/assets/_dot_cursorrules.append +22 -0
  102. package/templates/solid/add-on/sentry/assets/_dot_env.local.append +2 -0
  103. package/templates/solid/add-on/sentry/assets/src/routes/demo.sentry.bad-event-handler.tsx +20 -0
  104. package/templates/solid/add-on/sentry/info.json +13 -0
  105. package/templates/solid/add-on/sentry/package.json +5 -0
  106. package/templates/solid/add-on/solid-ui/README.md +9 -0
  107. package/templates/solid/add-on/solid-ui/assets/src/lib/utils.ts +6 -0
  108. package/templates/solid/add-on/solid-ui/assets/src/styles.css +138 -0
  109. package/templates/solid/add-on/solid-ui/assets/ui.config.json +13 -0
  110. package/templates/solid/add-on/solid-ui/info.json +11 -0
  111. package/templates/solid/add-on/solid-ui/package.json +9 -0
  112. package/templates/solid/add-on/store/assets/src/lib/demo-store.ts +13 -0
  113. package/templates/solid/add-on/store/assets/src/routes/demo.store.tsx.ejs +77 -0
  114. package/templates/solid/add-on/store/info.json +13 -0
  115. package/templates/solid/add-on/store/package.json +6 -0
  116. package/templates/solid/add-on/tanstack-query/assets/src/integrations/tanstack-query/header-user.tsx +5 -0
  117. package/templates/solid/add-on/tanstack-query/assets/src/integrations/tanstack-query/provider.tsx +15 -0
  118. package/templates/solid/add-on/tanstack-query/assets/src/routes/demo.tanstack-query.tsx +30 -0
  119. package/templates/solid/add-on/tanstack-query/info.json +13 -0
  120. package/templates/solid/add-on/tanstack-query/package.json +6 -0
  121. package/templates/solid/base/README.md.ejs +200 -0
  122. package/templates/solid/base/_dot_cursorrules.append +35 -0
  123. package/templates/solid/base/_dot_gitignore +5 -0
  124. package/templates/solid/base/_dot_vscode/settings.json +11 -0
  125. package/templates/solid/base/index.html.ejs +20 -0
  126. package/templates/solid/base/package.json +22 -0
  127. package/templates/solid/base/package.ts.json +5 -0
  128. package/templates/solid/base/package.tw.json +6 -0
  129. package/templates/solid/base/public/favicon.ico +0 -0
  130. package/templates/solid/base/public/logo192.png +0 -0
  131. package/templates/solid/base/public/logo512.png +0 -0
  132. package/templates/solid/base/public/manifest.json +25 -0
  133. package/templates/solid/base/public/robots.txt +3 -0
  134. package/templates/solid/base/src/App.css +0 -0
  135. package/templates/solid/base/src/App.tsx.ejs +47 -0
  136. package/templates/solid/base/src/components/Header.tsx.ejs +26 -0
  137. package/templates/solid/base/src/logo.svg +120 -0
  138. package/templates/solid/base/src/styles.css.ejs +15 -0
  139. package/templates/solid/base/tsconfig.json.ejs +30 -0
  140. package/templates/solid/base/vite.config.js.ejs +22 -0
  141. package/templates/solid/code-router/src/main.tsx.ejs +69 -0
  142. package/templates/solid/file-router/package.fr.json +5 -0
  143. package/templates/solid/file-router/src/main.tsx.ejs +44 -0
  144. package/templates/solid/file-router/src/routes/__root.tsx.ejs +41 -0
  145. package/templates/solid/file-router/src/routes/index.tsx +43 -0
  146. package/templates/base/vite.config.js.ejs +0 -15
  147. package/templates/file-router/src/routes/__root.tsx +0 -11
  148. /package/templates/{base/gitignore → react/base/_dot_gitignore} +0 -0
  149. /package/templates/{base → react/base}/index.html.ejs +0 -0
  150. /package/templates/{base → react/base}/package.json +0 -0
  151. /package/templates/{base → react/base}/package.ts.json +0 -0
  152. /package/templates/{base → react/base}/package.tw.json +0 -0
  153. /package/templates/{base → react/base}/public/favicon.ico +0 -0
  154. /package/templates/{base → react/base}/public/logo192.png +0 -0
  155. /package/templates/{base → react/base}/public/logo512.png +0 -0
  156. /package/templates/{base → react/base}/public/manifest.json +0 -0
  157. /package/templates/{base → react/base}/public/robots.txt +0 -0
  158. /package/templates/{base → react/base}/src/App.css +0 -0
  159. /package/templates/{base → react/base}/src/App.test.tsx.ejs +0 -0
  160. /package/templates/{base → react/base}/src/App.tsx.ejs +0 -0
  161. /package/templates/{base → react/base}/src/logo.svg +0 -0
  162. /package/templates/{base → react/base}/src/reportWebVitals.ts.ejs +0 -0
  163. /package/templates/{base → react/base}/src/styles.css.ejs +0 -0
  164. /package/templates/{file-router → react/file-router}/package.fr.json +0 -0
  165. /package/templates/{file-router → react/file-router}/src/main.tsx.ejs +0 -0
@@ -0,0 +1,133 @@
1
+ import { Store } from '@tanstack/store'
2
+ import type { Message } from '../utils/demo.ai'
3
+
4
+ // Types
5
+ export interface Prompt {
6
+ id: string
7
+ name: string
8
+ content: string
9
+ is_active: boolean
10
+ created_at: number
11
+ }
12
+
13
+ export interface Conversation {
14
+ id: string
15
+ title: string
16
+ messages: Message[]
17
+ }
18
+
19
+ export interface State {
20
+ prompts: Prompt[]
21
+ conversations: Conversation[]
22
+ currentConversationId: string | null
23
+ isLoading: boolean
24
+ }
25
+
26
+ const initialState: State = {
27
+ prompts: [],
28
+ conversations: [],
29
+ currentConversationId: null,
30
+ isLoading: false
31
+ }
32
+
33
+ export const store = new Store<State>(initialState)
34
+
35
+ export const actions = {
36
+ // Prompt actions
37
+ createPrompt: (name: string, content: string) => {
38
+ const id = Date.now().toString()
39
+ store.setState(state => {
40
+ const updatedPrompts = state.prompts.map(p => ({ ...p, is_active: false }))
41
+ return {
42
+ ...state,
43
+ prompts: [
44
+ ...updatedPrompts,
45
+ {
46
+ id,
47
+ name,
48
+ content,
49
+ is_active: true,
50
+ created_at: Date.now()
51
+ }
52
+ ]
53
+ }
54
+ })
55
+ },
56
+
57
+ deletePrompt: (id: string) => {
58
+ store.setState(state => ({
59
+ ...state,
60
+ prompts: state.prompts.filter(p => p.id !== id)
61
+ }))
62
+ },
63
+
64
+ setPromptActive: (id: string, shouldActivate: boolean) => {
65
+ store.setState(state => ({
66
+ ...state,
67
+ prompts: state.prompts.map(p => ({
68
+ ...p,
69
+ is_active: p.id === id ? shouldActivate : false
70
+ }))
71
+ }))
72
+ },
73
+
74
+ // Chat actions
75
+ setConversations: (conversations: Conversation[]) => {
76
+ store.setState(state => ({ ...state, conversations }))
77
+ },
78
+
79
+ setCurrentConversationId: (id: string | null) => {
80
+ store.setState(state => ({ ...state, currentConversationId: id }))
81
+ },
82
+
83
+ addConversation: (conversation: Conversation) => {
84
+ store.setState(state => ({
85
+ ...state,
86
+ conversations: [...state.conversations, conversation],
87
+ currentConversationId: conversation.id
88
+ }))
89
+ },
90
+
91
+ updateConversationTitle: (id: string, title: string) => {
92
+ store.setState(state => ({
93
+ ...state,
94
+ conversations: state.conversations.map(conv =>
95
+ conv.id === id ? { ...conv, title } : conv
96
+ )
97
+ }))
98
+ },
99
+
100
+ deleteConversation: (id: string) => {
101
+ store.setState(state => ({
102
+ ...state,
103
+ conversations: state.conversations.filter(conv => conv.id !== id),
104
+ currentConversationId: state.currentConversationId === id ? null : state.currentConversationId
105
+ }))
106
+ },
107
+
108
+ addMessage: (conversationId: string, message: Message) => {
109
+ store.setState(state => ({
110
+ ...state,
111
+ conversations: state.conversations.map(conv =>
112
+ conv.id === conversationId
113
+ ? { ...conv, messages: [...conv.messages, message] }
114
+ : conv
115
+ )
116
+ }))
117
+ },
118
+
119
+ setLoading: (isLoading: boolean) => {
120
+ store.setState(state => ({ ...state, isLoading }))
121
+ }
122
+ }
123
+
124
+ // Selectors
125
+ export const selectors = {
126
+ getActivePrompt: (state: State) => state.prompts.find(p => p.is_active),
127
+ getCurrentConversation: (state: State) =>
128
+ state.conversations.find(c => c.id === state.currentConversationId),
129
+ getPrompts: (state: State) => state.prompts,
130
+ getConversations: (state: State) => state.conversations,
131
+ getCurrentConversationId: (state: State) => state.currentConversationId,
132
+ getIsLoading: (state: State) => state.isLoading
133
+ }
@@ -0,0 +1,108 @@
1
+ import { createServerFn } from '@tanstack/start'
2
+ import { Anthropic } from '@anthropic-ai/sdk'
3
+
4
+ export interface Message {
5
+ id: string
6
+ role: 'user' | 'assistant'
7
+ content: string
8
+ }
9
+
10
+ const DEFAULT_SYSTEM_PROMPT = `You are TanStack Chat, an AI assistant using Markdown for clear and structured responses. Format your responses following these guidelines:
11
+
12
+ 1. Use headers for sections:
13
+ # For main topics
14
+ ## For subtopics
15
+ ### For subsections
16
+
17
+ 2. For lists and steps:
18
+ - Use bullet points for unordered lists
19
+ - Number steps when sequence matters
20
+
21
+ 3. For code:
22
+ - Use inline \`code\` for short snippets
23
+ - Use triple backticks with language for blocks:
24
+ \`\`\`python
25
+ def example():
26
+ return "like this"
27
+ \`\`\`
28
+
29
+ 4. For emphasis:
30
+ - Use **bold** for important points
31
+ - Use *italics* for emphasis
32
+ - Use > for important quotes or callouts
33
+
34
+ 5. For structured data:
35
+ | Use | Tables |
36
+ |-----|---------|
37
+ | When | Needed |
38
+
39
+ 6. Break up long responses with:
40
+ - Clear section headers
41
+ - Appropriate spacing between sections
42
+ - Bullet points for better readability
43
+ - Short, focused paragraphs
44
+
45
+ 7. For technical content:
46
+ - Always specify language for code blocks
47
+ - Use inline \`code\` for technical terms
48
+ - Include example usage where helpful
49
+
50
+ Keep responses concise and well-structured. Use appropriate Markdown formatting to enhance readability and understanding.`;
51
+
52
+ // Non-streaming implementation
53
+ export const genAIResponse = createServerFn({ method: 'GET' })
54
+
55
+ .validator((d: {
56
+ messages: Message[],
57
+ systemPrompt?: { value: string, enabled: boolean },
58
+ streamEnabled?: boolean
59
+ }) => d)
60
+ // .middleware([loggingMiddleware])
61
+ .handler(async ({ data }) => {
62
+ const anthropic = new Anthropic({
63
+ apiKey: import.meta.env.VITE_ANTHROPIC_API_KEY || '',
64
+ });
65
+
66
+ // Filter out error messages and empty messages
67
+ const formattedMessages = data.messages
68
+ .filter(msg => msg.content.trim() !== '' && !msg.content.startsWith('Sorry, I encountered an error'))
69
+ .map(msg => ({
70
+ role: msg.role,
71
+ content: msg.content.trim()
72
+ }));
73
+
74
+ if (formattedMessages.length === 0) {
75
+ return { error: 'No valid messages to send' };
76
+ }
77
+
78
+ const systemPrompt = data.systemPrompt?.enabled
79
+ ? `${DEFAULT_SYSTEM_PROMPT}\n\n${data.systemPrompt.value}`
80
+ : DEFAULT_SYSTEM_PROMPT;
81
+
82
+ // Debug log to verify prompt layering
83
+ console.log('System Prompt Configuration:', {
84
+ hasCustomPrompt: data.systemPrompt?.enabled,
85
+ customPromptValue: data.systemPrompt?.value,
86
+ finalPrompt: systemPrompt
87
+ });
88
+
89
+ try {
90
+ const response = await anthropic.messages.create({
91
+ model: "claude-3-5-sonnet-20241022",
92
+ max_tokens: 4096,
93
+ system: systemPrompt,
94
+ messages: formattedMessages,
95
+ });
96
+
97
+ if (response.content[0].type === 'text') {
98
+ return { text: response.content[0].text };
99
+ }
100
+ return { error: 'Unexpected response type' };
101
+ } catch (error) {
102
+ console.error('Error in genAIResponse:', error);
103
+ if (error instanceof Error && error.message.includes('rate limit')) {
104
+ return { error: 'Rate limit exceeded. Please try again in a moment.' };
105
+ }
106
+ return { error: error instanceof Error ? error.message : 'Failed to get AI response' };
107
+ }
108
+ });
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "TanStack Chat",
3
+ "description": "A chat example that uses TanStack Start and TanStack Store. Features chat with Antrhopic Sonnet, chat history and custom prompts.",
4
+ "phase": "example",
5
+ "templates": ["file-router"],
6
+ "link": "",
7
+ "routes": [
8
+ {
9
+ "url": "/example/chat",
10
+ "name": "Chat"
11
+ }
12
+ ],
13
+ "dependsOn": ["start", "store"],
14
+ "variables": []
15
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "dependencies": {
3
+ "@anthropic-ai/sdk": "^0.14.1",
4
+ "react-markdown": "^9.0.1",
5
+ "rehype-highlight": "^7.0.0",
6
+ "rehype-raw": "^7.0.0",
7
+ "rehype-sanitize": "^6.0.0",
8
+ "lucide-react": "^0.475.0"
9
+ }
10
+ }
@@ -0,0 +1,71 @@
1
+ import { createRootRoute, Outlet<% if (addOnEnabled.start) { %>
2
+ ,HeadContent, Scripts<% } %> } from '@tanstack/react-router'
3
+ import { TanStackRouterDevtools } from '@tanstack/router-devtools'
4
+ <% if (addOns.length) { %>
5
+ import Header from '../components/Header'
6
+ <% } %><% for(const integration of integrations.filter(i => i.type === 'layout' || i.type === 'provider')) { %>
7
+ import <%= integration.name %> from "../<%= integration.path %>";
8
+ <% } %>
9
+
10
+ <% if (addOnEnabled.start) { %>
11
+ import appCss from '../styles.css?url'
12
+ <% } %>
13
+
14
+ export const Route = createRootRoute({
15
+ <% if (addOnEnabled.start) { %>
16
+ head: () => ({
17
+ meta: [
18
+ {
19
+ charSet: 'utf-8',
20
+ },
21
+ {
22
+ name: 'viewport',
23
+ content: 'width=device-width, initial-scale=1',
24
+ },
25
+ {
26
+ title: 'TanStack Start Starter',
27
+ },
28
+ ],
29
+ links: [
30
+ {
31
+ rel: 'stylesheet',
32
+ href: appCss,
33
+ },
34
+ ],
35
+ }),
36
+ <% } %>
37
+ component: () => (
38
+ <% if (addOnEnabled.start) { %><RootDocument><% } else { %><><% } %>
39
+ <% for(const integration of integrations.filter(i => i.type === 'provider')) { %>
40
+ <<%= integration.name %>>
41
+ <% } %>
42
+ <% if (addOns.length) { %>
43
+ <Header />
44
+ <% } %>
45
+ <Outlet />
46
+ <TanStackRouterDevtools />
47
+ <% for(const integration of integrations.filter(i => i.type === 'layout')) { %>
48
+ <<%= integration.name %> />
49
+ <% } %>
50
+ <% for(const integration of integrations.filter(i => i.type === 'provider').toReversed()) { %>
51
+ </<%= integration.name %>>
52
+ <% } %>
53
+ <% if (addOnEnabled.start) { %></RootDocument><% } else { %></><% } %>
54
+ ),
55
+ })
56
+
57
+ <% if (addOnEnabled.start) { %>
58
+ function RootDocument({ children }: { children: React.ReactNode }) {
59
+ return (
60
+ <html>
61
+ <head>
62
+ <HeadContent />
63
+ </head>
64
+ <body>
65
+ {children}
66
+ <Scripts />
67
+ </body>
68
+ </html>
69
+ )
70
+ }
71
+ <% } %>
@@ -0,0 +1,148 @@
1
+ import { <% if (fileRouter) { %>createFileRoute<% } else { %>createRoute<% } %> } from '@tanstack/solid-router'
2
+
3
+ import { createForm } from '@tanstack/solid-form'
4
+ import type { AnyFieldApi } from '@tanstack/solid-form'
5
+
6
+ interface FieldInfoProps {
7
+ field: AnyFieldApi
8
+ }
9
+
10
+ <% if (codeRouter) { %>
11
+ import type { RootRoute } from '@tanstack/react-router'
12
+ <% } else { %>
13
+ export const Route = createFileRoute('/demo/form')({
14
+ component: FormExample,
15
+ })
16
+ <% } %>
17
+ function FieldInfo(props: FieldInfoProps) {
18
+ return (
19
+ <>
20
+ {props.field.state.meta.isTouched &&
21
+ props.field.state.meta.errors.length ? (
22
+ <em>{props.field.state.meta.errors.join(',')}</em>
23
+ ) : null}
24
+ {props.field.state.meta.isValidating ? 'Validating...' : null}
25
+ </>
26
+ )
27
+ }
28
+
29
+ function FormExample() {
30
+ const form = createForm(() => ({
31
+ defaultValues: {
32
+ firstName: '',
33
+ lastName: '',
34
+ },
35
+ onSubmit: async ({ value }) => {
36
+ // Do something with form data
37
+ console.log(value)
38
+ },
39
+ }))
40
+
41
+ return (
42
+ <div class="max-w-md mx-auto mt-10 p-6 bg-white rounded-lg shadow-md">
43
+ <h1 class="text-2xl font-bold mb-8 text-gray-800 leading-tight">
44
+ Simple Form Example
45
+ </h1>
46
+ <form
47
+ class="space-y-6"
48
+ onSubmit={(e) => {
49
+ e.preventDefault()
50
+ e.stopPropagation()
51
+ form.handleSubmit()
52
+ }}
53
+ >
54
+ <div class="space-y-1">
55
+ <form.Field
56
+ name="firstName"
57
+ validators={{
58
+ onChange: ({ value }) =>
59
+ !value
60
+ ? 'A first name is required'
61
+ : value.length < 3
62
+ ? 'First name must be at least 3 characters'
63
+ : undefined,
64
+ onChangeAsyncDebounceMs: 500,
65
+ onChangeAsync: async ({ value }) => {
66
+ await new Promise((resolve) => setTimeout(resolve, 1000))
67
+ return (
68
+ value.includes('error') && 'No "error" allowed in first name'
69
+ )
70
+ },
71
+ }}
72
+ children={(field) => {
73
+ return (
74
+ <>
75
+ <label
76
+ for={field().name}
77
+ class="block text-sm font-medium text-gray-700 mb-1 leading-tight"
78
+ >
79
+ First Name:
80
+ </label>
81
+ <input
82
+ id={field().name}
83
+ name={field().name}
84
+ value={field().state.value}
85
+ onBlur={field().handleBlur}
86
+ onInput={(e) => field().handleChange(e.target.value)}
87
+ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm leading-relaxed p-2"
88
+ />
89
+ <FieldInfo field={field()} />
90
+ </>
91
+ )
92
+ }}
93
+ />
94
+ </div>
95
+ <div class="space-y-1">
96
+ <form.Field
97
+ name="lastName"
98
+ children={(field) => (
99
+ <>
100
+ <label
101
+ for={field().name}
102
+ class="block text-sm font-medium text-gray-700 mb-1 leading-tight"
103
+ >
104
+ Last Name:
105
+ </label>
106
+ <input
107
+ id={field().name}
108
+ name={field().name}
109
+ value={field().state.value}
110
+ onBlur={field().handleBlur}
111
+ onInput={(e) => field().handleChange(e.target.value)}
112
+ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm leading-relaxed p-2"
113
+ />
114
+ <FieldInfo field={field()} />
115
+ </>
116
+ )}
117
+ />
118
+ </div>
119
+ <form.Subscribe
120
+ selector={(state) => ({
121
+ canSubmit: state.canSubmit,
122
+ isSubmitting: state.isSubmitting,
123
+ })}
124
+ children={(state) => {
125
+ return (
126
+ <button
127
+ type="submit"
128
+ disabled={!state().canSubmit}
129
+ class="w-full flex justify-center py-2.5 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50 disabled:cursor-not-allowed leading-tight"
130
+ >
131
+ {state().isSubmitting ? '...' : 'Submit'}
132
+ </button>
133
+ )
134
+ }}
135
+ />
136
+ </form>
137
+ </div>
138
+ )
139
+ }
140
+
141
+ <% if (codeRouter) { %>
142
+ export default (parentRoute: RootRoute) => createRoute({
143
+ path: '/demo/form',
144
+ component: FormExample,
145
+ getParentRoute: () => parentRoute,
146
+ })
147
+ <% } %>
148
+
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "Form",
3
+ "description": "TansStack Form",
4
+ "phase": "add-on",
5
+ "link": "https://tanstack.com/form/latest",
6
+ "templates": ["file-router", "code-router"],
7
+ "routes": [
8
+ {
9
+ "url": "/demo/form",
10
+ "name": "Form"
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "dependencies": {
3
+ "@tanstack/solid-form": "^0.43.2"
4
+ }
5
+ }
@@ -0,0 +1,27 @@
1
+ import packageJSON from './package.json'
2
+
3
+ function remoteConfig(name, url) {
4
+ return {
5
+ type: 'module',
6
+ name,
7
+ entry: url,
8
+ entryGlobalName: 'remote',
9
+ shareScope: 'default',
10
+ }
11
+ }
12
+
13
+ export default {
14
+ filename: 'remoteEntry.js',
15
+ name: '<%= projectName %>',
16
+ exposes: {
17
+ './DemoMfComponent': './src/demo-mf-component.tsx',
18
+ './DemoMfSelfContained': './src/demo-mf-self-contained.tsx',
19
+ },
20
+ remotes: {},
21
+ shared: {
22
+ 'solid-js': {
23
+ singleton: true,
24
+ requiredVersion: packageJSON.dependencies['solid-js'],
25
+ },
26
+ },
27
+ }
@@ -0,0 +1,3 @@
1
+ export function DemoMfComponent() {
2
+ return <div>Solid Federated Component</div>
3
+ }
@@ -0,0 +1,9 @@
1
+ import { render } from 'solid-js/web'
2
+
3
+ function App() {
4
+ return <div>Hello from Solid Self Contained</div>
5
+ }
6
+
7
+ export function DemoMfSelfContained(rootElement: HTMLElement) {
8
+ render(() => <App />, rootElement)
9
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "Module Federation",
3
+ "description": "Module Federation",
4
+ "phase": "add-on",
5
+ "templates": ["code-router"],
6
+ "link": "https://module-federation.io/"
7
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "dependencies": {
3
+ "@module-federation/vite": "^1.1.9"
4
+ }
5
+ }
@@ -0,0 +1,22 @@
1
+ We use Sentry for watching for errors in our deployed application, as well as for instrumentation of our application.
2
+
3
+ ## Error collection
4
+
5
+ Error collection is automatic and configured in `src/router.tsx`.
6
+
7
+ ## Instrumentation
8
+
9
+ We want our server functions intstrumented. So if you see a function name like `createServerFn`, you can instrument it with Sentry. You'll need to import `Sentry`:
10
+
11
+ ```tsx
12
+ import * as Sentry from '@sentry/browser'
13
+ ```
14
+
15
+ And then wrap the implementation of the server function with `Sentry.startSpan`, liks so:
16
+
17
+ ```tsx
18
+ Sentry.startSpan({ name: 'Requesting all the pokemon' }, async () => {
19
+ // Some lengthy operation here
20
+ await fetch('https://api.pokemon.com/data/')
21
+ })
22
+ ```
@@ -0,0 +1,2 @@
1
+ # Your Sentry DSN (from your Sentry account)
2
+ VITE_SENTRY_DSN=
@@ -0,0 +1,20 @@
1
+ import { createFileRoute } from '@tanstack/solid-router'
2
+
3
+ export const Route = createFileRoute('/demo/sentry/bad-event-handler')({
4
+ component: RouteComponent,
5
+ })
6
+
7
+ function RouteComponent() {
8
+ return (
9
+ <div className="p-4">
10
+ <button
11
+ type="button"
12
+ onClick={() => {
13
+ throw new Error('Sentry Frontend Error')
14
+ }}
15
+ >
16
+ Throw error
17
+ </button>
18
+ </div>
19
+ )
20
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "Sentry",
3
+ "phase": "setup",
4
+ "description": "Add Sentry for error monitoring and crash reporting (requires Start).",
5
+ "link": "https://sentry.com/",
6
+ "templates": ["file-router"],
7
+ "routes": [
8
+ {
9
+ "url": "/demo/sentry/bad-event-handler",
10
+ "name": "Sentry"
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "dependencies": {
3
+ "@sentry/solid": "^9.1.0"
4
+ }
5
+ }
@@ -0,0 +1,9 @@
1
+ ## Solid-UI
2
+
3
+ This installation of Solid-UI follows the manual instructions but was modified to work with Tailwind V4.
4
+
5
+ To install the components, run the following command (this install button):
6
+
7
+ ```bash
8
+ npx solidui-cli@latest add button
9
+ ```
@@ -0,0 +1,6 @@
1
+ import { type ClassValue, clsx } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }