create-start-app 0.6.11 → 0.7.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/dist/create-app.js +2 -2
- package/package.json +2 -11
- package/src/create-app.ts +2 -2
- package/templates/react/add-on/start/assets/src/router.tsx.ejs +2 -0
- package/templates/react/base/README.md.ejs +9 -3
- package/templates/react/code-router/src/main.tsx.ejs +1 -0
- package/templates/react/example/tanchat/assets/public/example-guitar-dune.jpg +0 -0
- package/templates/react/example/tanchat/assets/public/example-guitar-motherboard.jpg +0 -0
- package/templates/react/example/tanchat/assets/public/example-guitar-racing.jpg +0 -0
- package/templates/react/example/tanchat/assets/public/example-guitar-steamer-trunk.jpg +0 -0
- package/templates/react/example/tanchat/assets/public/example-guitar-steampunk.jpg +0 -0
- package/templates/react/example/tanchat/assets/public/example-guitar-underwater.jpg +0 -0
- package/templates/react/example/tanchat/assets/src/components/example-AIAssistant.tsx +173 -0
- package/templates/react/example/tanchat/assets/src/components/example-GuitarRecommendation.tsx +47 -0
- package/templates/react/example/tanchat/assets/src/data/example-guitars.ts +73 -0
- package/templates/react/example/tanchat/assets/src/integrations/tanchat/header-user.tsx +5 -0
- package/templates/react/example/tanchat/assets/src/routes/example.chat.tsx +119 -397
- package/templates/react/example/tanchat/assets/src/routes/example.guitars/$guitarId.tsx +50 -0
- package/templates/react/example/tanchat/assets/src/routes/example.guitars/index.tsx +54 -0
- package/templates/react/example/tanchat/assets/src/store/example-assistant.ts +3 -0
- package/templates/react/example/tanchat/assets/src/utils/demo.ai.ts +14 -70
- package/templates/react/example/tanchat/assets/src/utils/demo.tools.ts +43 -0
- package/templates/react/example/tanchat/info.json +4 -0
- package/templates/react/example/tanchat/package.json +4 -1
- package/templates/react/file-router/src/main.tsx.ejs +2 -1
- package/templates/react/file-router/src/routes/__root.tsx.ejs +8 -5
- package/templates/solid/file-router/src/main.tsx.ejs +1 -0
- package/tests/snapshots/cra/cr-js-npm.json +2 -2
- package/tests/snapshots/cra/cr-ts-npm.json +2 -2
- package/tests/snapshots/cra/fr-ts-npm.json +2 -2
- package/tests/snapshots/cra/fr-ts-tw-npm.json +2 -2
- package/.github/workflows/auto.yml +0 -46
- package/templates/react/example/tanchat/assets/src/components/demo.SettingsDialog.tsx +0 -148
- package/templates/react/example/tanchat/assets/src/store/demo.hooks.ts +0 -21
- package/templates/react/example/tanchat/assets/src/store/demo.store.ts +0 -133
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
name: auto
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- main
|
|
7
|
-
schedule:
|
|
8
|
-
- cron: '0 * * * *'
|
|
9
|
-
|
|
10
|
-
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
|
11
|
-
|
|
12
|
-
permissions:
|
|
13
|
-
contents: write
|
|
14
|
-
|
|
15
|
-
jobs:
|
|
16
|
-
update-templates:
|
|
17
|
-
runs-on: ubuntu-latest
|
|
18
|
-
steps:
|
|
19
|
-
- name: Checkout Repo
|
|
20
|
-
uses: actions/checkout@v4
|
|
21
|
-
with:
|
|
22
|
-
fetch-depth: 0
|
|
23
|
-
|
|
24
|
-
- name: Setup Bun
|
|
25
|
-
uses: oven-sh/setup-bun@v2
|
|
26
|
-
with:
|
|
27
|
-
bun-version: latest
|
|
28
|
-
|
|
29
|
-
- name: Setup Node
|
|
30
|
-
uses: actions/setup-node@v4
|
|
31
|
-
with:
|
|
32
|
-
node-version: 22
|
|
33
|
-
|
|
34
|
-
- name: Publish Packages
|
|
35
|
-
run: |
|
|
36
|
-
npm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN}"
|
|
37
|
-
# ~ alias create-tsrouter-app
|
|
38
|
-
bunx gitpick@latest https://github.com/TanStack/create-tsrouter-app . --overwrite
|
|
39
|
-
bun i && bun run build && rm -rf bun.lock
|
|
40
|
-
bunx json -I -f package.json -e 'this.name="create-router-app"'
|
|
41
|
-
npm publish || true
|
|
42
|
-
# ~ alias create-tsrouter-app
|
|
43
|
-
bunx json -I -f package.json -e 'this.name="create-start-app"'
|
|
44
|
-
npm publish || true
|
|
45
|
-
env:
|
|
46
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { useState } from 'react'
|
|
2
|
-
import { PlusCircle, Trash2 } from 'lucide-react'
|
|
3
|
-
import { useAppState } from '../store/demo.hooks'
|
|
4
|
-
|
|
5
|
-
interface SettingsDialogProps {
|
|
6
|
-
isOpen: boolean
|
|
7
|
-
onClose: () => void
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function SettingsDialog({ isOpen, onClose }: SettingsDialogProps) {
|
|
11
|
-
const [promptForm, setPromptForm] = useState({ name: '', content: '' })
|
|
12
|
-
const [isAddingPrompt, setIsAddingPrompt] = useState(false)
|
|
13
|
-
const { prompts, createPrompt, deletePrompt, setPromptActive } = useAppState()
|
|
14
|
-
|
|
15
|
-
const handleAddPrompt = () => {
|
|
16
|
-
if (!promptForm.name.trim() || !promptForm.content.trim()) return
|
|
17
|
-
createPrompt(promptForm.name, promptForm.content)
|
|
18
|
-
setPromptForm({ name: '', content: '' })
|
|
19
|
-
setIsAddingPrompt(false)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const handleClose = () => {
|
|
23
|
-
onClose()
|
|
24
|
-
setIsAddingPrompt(false)
|
|
25
|
-
setPromptForm({ name: '', content: '' })
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (!isOpen) return null
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center" onClick={(e) => {
|
|
32
|
-
if (e.target === e.currentTarget) handleClose()
|
|
33
|
-
}}>
|
|
34
|
-
<div className="bg-gray-800 rounded-lg shadow-xl max-w-2xl w-full mx-4 max-h-[90vh] overflow-y-auto" onClick={e => e.stopPropagation()}>
|
|
35
|
-
<div className="p-6">
|
|
36
|
-
<div className="flex items-center justify-between mb-4">
|
|
37
|
-
<h2 className="text-2xl font-semibold text-white">Settings</h2>
|
|
38
|
-
<button
|
|
39
|
-
onClick={handleClose}
|
|
40
|
-
className="text-gray-400 hover:text-white focus:outline-none"
|
|
41
|
-
>
|
|
42
|
-
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
43
|
-
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
|
44
|
-
</svg>
|
|
45
|
-
</button>
|
|
46
|
-
</div>
|
|
47
|
-
|
|
48
|
-
<div className="space-y-6">
|
|
49
|
-
{/* Prompts Management */}
|
|
50
|
-
<div className="space-y-2">
|
|
51
|
-
<div className="flex items-center justify-between mb-4">
|
|
52
|
-
<label className="block text-sm font-medium text-white">
|
|
53
|
-
System Prompts
|
|
54
|
-
</label>
|
|
55
|
-
<button
|
|
56
|
-
onClick={() => setIsAddingPrompt(true)}
|
|
57
|
-
className="flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-white bg-gradient-to-r from-orange-500 to-red-600 rounded-lg hover:opacity-90 focus:outline-none focus:ring-2 focus:ring-orange-500"
|
|
58
|
-
>
|
|
59
|
-
<PlusCircle className="w-4 h-4" />
|
|
60
|
-
Add Prompt
|
|
61
|
-
</button>
|
|
62
|
-
</div>
|
|
63
|
-
|
|
64
|
-
{isAddingPrompt && (
|
|
65
|
-
<div className="space-y-3 mb-4 p-3 bg-gray-700/50 rounded-lg">
|
|
66
|
-
<input
|
|
67
|
-
type="text"
|
|
68
|
-
value={promptForm.name}
|
|
69
|
-
onChange={(e) => setPromptForm(prev => ({ ...prev, name: e.target.value }))}
|
|
70
|
-
placeholder="Prompt name..."
|
|
71
|
-
className="w-full px-3 py-2 text-sm text-white bg-gray-700 rounded-lg border border-gray-600 focus:border-orange-500 focus:ring-1 focus:ring-orange-500"
|
|
72
|
-
/>
|
|
73
|
-
<textarea
|
|
74
|
-
value={promptForm.content}
|
|
75
|
-
onChange={(e) => setPromptForm(prev => ({ ...prev, content: e.target.value }))}
|
|
76
|
-
placeholder="Enter prompt content..."
|
|
77
|
-
className="w-full h-32 px-3 py-2 text-sm text-white bg-gray-700 rounded-lg border border-gray-600 focus:border-orange-500 focus:ring-1 focus:ring-orange-500"
|
|
78
|
-
/>
|
|
79
|
-
<div className="flex justify-end gap-2">
|
|
80
|
-
<button
|
|
81
|
-
onClick={() => setIsAddingPrompt(false)}
|
|
82
|
-
className="px-3 py-1.5 text-sm font-medium text-gray-300 hover:text-white focus:outline-none"
|
|
83
|
-
>
|
|
84
|
-
Cancel
|
|
85
|
-
</button>
|
|
86
|
-
<button
|
|
87
|
-
onClick={handleAddPrompt}
|
|
88
|
-
className="px-3 py-1.5 text-sm font-medium text-white bg-gradient-to-r from-orange-500 to-red-600 rounded-lg hover:opacity-90 focus:outline-none focus:ring-2 focus:ring-orange-500"
|
|
89
|
-
>
|
|
90
|
-
Save Prompt
|
|
91
|
-
</button>
|
|
92
|
-
</div>
|
|
93
|
-
</div>
|
|
94
|
-
)}
|
|
95
|
-
|
|
96
|
-
<div className="space-y-2">
|
|
97
|
-
{prompts.map((prompt) => (
|
|
98
|
-
<div key={prompt.id} className="flex items-center justify-between p-3 bg-gray-700/50 rounded-lg">
|
|
99
|
-
<div className="flex-1 min-w-0 mr-4">
|
|
100
|
-
<h4 className="text-sm font-medium text-white truncate">{prompt.name}</h4>
|
|
101
|
-
<p className="text-xs text-gray-400 truncate">{prompt.content}</p>
|
|
102
|
-
</div>
|
|
103
|
-
<div className="flex items-center gap-2">
|
|
104
|
-
<label className="relative inline-flex items-center cursor-pointer">
|
|
105
|
-
<input
|
|
106
|
-
type="checkbox"
|
|
107
|
-
className="sr-only peer"
|
|
108
|
-
checked={prompt.is_active}
|
|
109
|
-
onChange={() => setPromptActive(prompt.id, !prompt.is_active)}
|
|
110
|
-
/>
|
|
111
|
-
<div className="w-11 h-6 bg-gray-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-orange-500"></div>
|
|
112
|
-
</label>
|
|
113
|
-
<button
|
|
114
|
-
onClick={() => deletePrompt(prompt.id)}
|
|
115
|
-
className="p-1 text-gray-400 hover:text-red-500"
|
|
116
|
-
>
|
|
117
|
-
<Trash2 className="w-4 h-4" />
|
|
118
|
-
</button>
|
|
119
|
-
</div>
|
|
120
|
-
</div>
|
|
121
|
-
))}
|
|
122
|
-
</div>
|
|
123
|
-
<p className="text-xs text-gray-400">
|
|
124
|
-
Create and manage custom system prompts. Only one prompt can be active at a time.
|
|
125
|
-
</p>
|
|
126
|
-
</div>
|
|
127
|
-
|
|
128
|
-
</div>
|
|
129
|
-
|
|
130
|
-
<div className="mt-6 flex justify-end gap-3">
|
|
131
|
-
<button
|
|
132
|
-
onClick={handleClose}
|
|
133
|
-
className="px-4 py-2 text-sm font-medium text-gray-300 hover:text-white focus:outline-none"
|
|
134
|
-
>
|
|
135
|
-
Cancel
|
|
136
|
-
</button>
|
|
137
|
-
<button
|
|
138
|
-
onClick={handleClose}
|
|
139
|
-
className="px-4 py-2 text-sm font-medium text-white bg-gradient-to-r from-orange-500 to-red-600 rounded-lg hover:opacity-90 focus:outline-none focus:ring-2 focus:ring-orange-500"
|
|
140
|
-
>
|
|
141
|
-
Close
|
|
142
|
-
</button>
|
|
143
|
-
</div>
|
|
144
|
-
</div>
|
|
145
|
-
</div>
|
|
146
|
-
</div>
|
|
147
|
-
)
|
|
148
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { useStore } from '@tanstack/react-store'
|
|
2
|
-
import { store, actions, selectors } from './demo.store'
|
|
3
|
-
|
|
4
|
-
export type { State, Prompt, Conversation } from './demo.store'
|
|
5
|
-
|
|
6
|
-
export function useAppState() {
|
|
7
|
-
const state = useStore(store)
|
|
8
|
-
return {
|
|
9
|
-
...state,
|
|
10
|
-
...actions,
|
|
11
|
-
...selectors
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function useAppActions() {
|
|
16
|
-
return actions
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function useAppSelectors() {
|
|
20
|
-
return selectors
|
|
21
|
-
}
|
|
@@ -1,133 +0,0 @@
|
|
|
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
|
-
}
|