@tanstack/create 0.68.0 → 0.68.1

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 (121) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/frameworks/react/add-ons/ai/assets/src/components/demo-AIAssistant.tsx +15 -15
  3. package/dist/frameworks/react/add-ons/ai/assets/src/components/demo-GuitarRecommendation.tsx +8 -6
  4. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/ai-chat.css +21 -21
  5. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/ai-chat.tsx +14 -18
  6. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/ai-image.tsx +20 -26
  7. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/ai-structured.tsx +56 -67
  8. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/guitars/$guitarId.tsx +17 -22
  9. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/guitars/index.tsx +21 -27
  10. package/dist/frameworks/react/add-ons/apollo-client/assets/src/routes/demo.apollo-client.tsx +35 -38
  11. package/dist/frameworks/react/add-ons/better-auth/assets/src/routes/demo/better-auth.tsx +64 -64
  12. package/dist/frameworks/react/add-ons/clerk/assets/src/routes/demo/clerk.tsx +17 -25
  13. package/dist/frameworks/react/add-ons/convex/assets/src/routes/demo/convex.tsx +30 -45
  14. package/dist/frameworks/react/add-ons/db/assets/src/components/demo.chat-area.tsx +5 -5
  15. package/dist/frameworks/react/add-ons/db/assets/src/components/demo.messages.tsx +7 -11
  16. package/dist/frameworks/react/add-ons/db/assets/src/routes/demo/db-chat.tsx +5 -3
  17. package/dist/frameworks/react/add-ons/drizzle/assets/src/routes/demo/drizzle.tsx.ejs +29 -79
  18. package/dist/frameworks/react/add-ons/form/assets/src/components/demo.FormComponents.tsx.ejs +12 -12
  19. package/dist/frameworks/react/add-ons/form/assets/src/routes/demo/form.address.tsx.ejs +11 -10
  20. package/dist/frameworks/react/add-ons/form/assets/src/routes/demo/form.simple.tsx.ejs +11 -10
  21. package/dist/frameworks/react/add-ons/mcp/assets/src/routes/demo/mcp-todos.tsx +10 -18
  22. package/dist/frameworks/react/add-ons/neon/assets/src/routes/demo/neon.tsx +38 -57
  23. package/dist/frameworks/react/add-ons/oRPC/assets/src/routes/demo/orpc-todo.tsx +10 -18
  24. package/dist/frameworks/react/add-ons/paraglide/assets/src/routes/demo.i18n.tsx.ejs +6 -7
  25. package/dist/frameworks/react/add-ons/posthog/assets/src/routes/demo/posthog.tsx +19 -22
  26. package/dist/frameworks/react/add-ons/powersync/assets/src/routes/demo/powersync.tsx +19 -18
  27. package/dist/frameworks/react/add-ons/prisma/assets/src/routes/demo/prisma.tsx.ejs +29 -79
  28. package/dist/frameworks/react/add-ons/sentry/assets/src/routes/demo/sentry.testing.tsx +71 -102
  29. package/dist/frameworks/react/add-ons/store/assets/src/lib/demo-store-devtools.tsx +3 -3
  30. package/dist/frameworks/react/add-ons/store/assets/src/routes/demo/store.tsx.ejs +9 -14
  31. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/button.tsx +23 -26
  32. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/dialog.tsx +12 -16
  33. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/input.tsx +14 -17
  34. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/radio-group.tsx +15 -15
  35. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/slider.tsx +17 -17
  36. package/dist/frameworks/react/add-ons/storybook/assets/src/routes/demo/storybook.tsx +25 -25
  37. package/dist/frameworks/react/add-ons/strapi/assets/src/components/blocks/media.tsx +9 -9
  38. package/dist/frameworks/react/add-ons/strapi/assets/src/components/blocks/quote.tsx +8 -8
  39. package/dist/frameworks/react/add-ons/strapi/assets/src/components/markdown-content.tsx +52 -35
  40. package/dist/frameworks/react/add-ons/strapi/assets/src/components/pagination.tsx +8 -14
  41. package/dist/frameworks/react/add-ons/strapi/assets/src/components/search.tsx +12 -12
  42. package/dist/frameworks/react/add-ons/strapi/assets/src/components/strapi-image.tsx +15 -15
  43. package/dist/frameworks/react/add-ons/strapi/assets/src/routes/demo/strapi.$articleId.tsx +52 -63
  44. package/dist/frameworks/react/add-ons/strapi/assets/src/routes/demo/strapi.tsx +46 -61
  45. package/dist/frameworks/react/add-ons/tRPC/assets/src/routes/demo/trpc-todo.tsx +10 -18
  46. package/dist/frameworks/react/add-ons/table/assets/src/routes/demo/table.tsx.ejs +23 -22
  47. package/dist/frameworks/react/add-ons/tanstack-query/assets/src/routes/demo/tanstack-query.tsx.ejs +21 -35
  48. package/dist/frameworks/react/add-ons/workos/assets/src/components/workos-user.tsx +1 -1
  49. package/dist/frameworks/react/add-ons/workos/assets/src/routes/demo/workos.tsx +33 -43
  50. package/dist/frameworks/react/project/base/_dot_gitignore +1 -0
  51. package/dist/frameworks/react/project/base/src/styles.css.ejs +203 -0
  52. package/dist/frameworks/solid/add-ons/better-auth/assets/src/routes/demo.better-auth.tsx +62 -64
  53. package/dist/frameworks/solid/add-ons/convex/assets/src/routes/demo/convex.tsx +30 -43
  54. package/dist/frameworks/solid/add-ons/form/assets/src/routes/demo.form.tsx.ejs +22 -22
  55. package/dist/frameworks/solid/add-ons/sentry/assets/src/routes/demo.sentry.bad-event-handler.tsx +15 -10
  56. package/dist/frameworks/solid/add-ons/store/assets/src/routes/demo.store.tsx.ejs +9 -14
  57. package/dist/frameworks/solid/add-ons/strapi/assets/src/routes/demo/strapi.tsx +11 -15
  58. package/dist/frameworks/solid/add-ons/strapi/assets/src/routes/demo/strapi_.$articleId.tsx +11 -18
  59. package/dist/frameworks/solid/project/base/_dot_gitignore +1 -0
  60. package/dist/frameworks/solid/project/base/src/styles.css.ejs +203 -0
  61. package/package.json +1 -1
  62. package/src/frameworks/react/add-ons/ai/assets/src/components/demo-AIAssistant.tsx +15 -15
  63. package/src/frameworks/react/add-ons/ai/assets/src/components/demo-GuitarRecommendation.tsx +8 -6
  64. package/src/frameworks/react/add-ons/ai/assets/src/routes/demo/ai-chat.css +21 -21
  65. package/src/frameworks/react/add-ons/ai/assets/src/routes/demo/ai-chat.tsx +14 -18
  66. package/src/frameworks/react/add-ons/ai/assets/src/routes/demo/ai-image.tsx +20 -26
  67. package/src/frameworks/react/add-ons/ai/assets/src/routes/demo/ai-structured.tsx +56 -67
  68. package/src/frameworks/react/add-ons/ai/assets/src/routes/demo/guitars/$guitarId.tsx +17 -22
  69. package/src/frameworks/react/add-ons/ai/assets/src/routes/demo/guitars/index.tsx +21 -27
  70. package/src/frameworks/react/add-ons/apollo-client/assets/src/routes/demo.apollo-client.tsx +35 -38
  71. package/src/frameworks/react/add-ons/better-auth/assets/src/routes/demo/better-auth.tsx +64 -64
  72. package/src/frameworks/react/add-ons/clerk/assets/src/routes/demo/clerk.tsx +17 -25
  73. package/src/frameworks/react/add-ons/convex/assets/src/routes/demo/convex.tsx +30 -45
  74. package/src/frameworks/react/add-ons/db/assets/src/components/demo.chat-area.tsx +5 -5
  75. package/src/frameworks/react/add-ons/db/assets/src/components/demo.messages.tsx +7 -11
  76. package/src/frameworks/react/add-ons/db/assets/src/routes/demo/db-chat.tsx +5 -3
  77. package/src/frameworks/react/add-ons/drizzle/assets/src/routes/demo/drizzle.tsx.ejs +29 -79
  78. package/src/frameworks/react/add-ons/form/assets/src/components/demo.FormComponents.tsx.ejs +12 -12
  79. package/src/frameworks/react/add-ons/form/assets/src/routes/demo/form.address.tsx.ejs +11 -10
  80. package/src/frameworks/react/add-ons/form/assets/src/routes/demo/form.simple.tsx.ejs +11 -10
  81. package/src/frameworks/react/add-ons/mcp/assets/src/routes/demo/mcp-todos.tsx +10 -18
  82. package/src/frameworks/react/add-ons/neon/assets/src/routes/demo/neon.tsx +38 -57
  83. package/src/frameworks/react/add-ons/oRPC/assets/src/routes/demo/orpc-todo.tsx +10 -18
  84. package/src/frameworks/react/add-ons/paraglide/assets/src/routes/demo.i18n.tsx.ejs +6 -7
  85. package/src/frameworks/react/add-ons/posthog/assets/src/routes/demo/posthog.tsx +19 -22
  86. package/src/frameworks/react/add-ons/powersync/assets/src/routes/demo/powersync.tsx +19 -18
  87. package/src/frameworks/react/add-ons/prisma/assets/src/routes/demo/prisma.tsx.ejs +29 -79
  88. package/src/frameworks/react/add-ons/sentry/assets/src/routes/demo/sentry.testing.tsx +71 -102
  89. package/src/frameworks/react/add-ons/store/assets/src/lib/demo-store-devtools.tsx +3 -3
  90. package/src/frameworks/react/add-ons/store/assets/src/routes/demo/store.tsx.ejs +9 -14
  91. package/src/frameworks/react/add-ons/storybook/assets/src/components/storybook/button.tsx +23 -26
  92. package/src/frameworks/react/add-ons/storybook/assets/src/components/storybook/dialog.tsx +12 -16
  93. package/src/frameworks/react/add-ons/storybook/assets/src/components/storybook/input.tsx +14 -17
  94. package/src/frameworks/react/add-ons/storybook/assets/src/components/storybook/radio-group.tsx +15 -15
  95. package/src/frameworks/react/add-ons/storybook/assets/src/components/storybook/slider.tsx +17 -17
  96. package/src/frameworks/react/add-ons/storybook/assets/src/routes/demo/storybook.tsx +25 -25
  97. package/src/frameworks/react/add-ons/strapi/assets/src/components/blocks/media.tsx +9 -9
  98. package/src/frameworks/react/add-ons/strapi/assets/src/components/blocks/quote.tsx +8 -8
  99. package/src/frameworks/react/add-ons/strapi/assets/src/components/markdown-content.tsx +52 -35
  100. package/src/frameworks/react/add-ons/strapi/assets/src/components/pagination.tsx +8 -14
  101. package/src/frameworks/react/add-ons/strapi/assets/src/components/search.tsx +12 -12
  102. package/src/frameworks/react/add-ons/strapi/assets/src/components/strapi-image.tsx +15 -15
  103. package/src/frameworks/react/add-ons/strapi/assets/src/routes/demo/strapi.$articleId.tsx +52 -63
  104. package/src/frameworks/react/add-ons/strapi/assets/src/routes/demo/strapi.tsx +46 -61
  105. package/src/frameworks/react/add-ons/tRPC/assets/src/routes/demo/trpc-todo.tsx +10 -18
  106. package/src/frameworks/react/add-ons/table/assets/src/routes/demo/table.tsx.ejs +23 -22
  107. package/src/frameworks/react/add-ons/tanstack-query/assets/src/routes/demo/tanstack-query.tsx.ejs +21 -35
  108. package/src/frameworks/react/add-ons/workos/assets/src/components/workos-user.tsx +1 -1
  109. package/src/frameworks/react/add-ons/workos/assets/src/routes/demo/workos.tsx +33 -43
  110. package/src/frameworks/react/project/base/_dot_gitignore +1 -0
  111. package/src/frameworks/react/project/base/src/styles.css.ejs +203 -0
  112. package/src/frameworks/solid/add-ons/better-auth/assets/src/routes/demo.better-auth.tsx +62 -64
  113. package/src/frameworks/solid/add-ons/convex/assets/src/routes/demo/convex.tsx +30 -43
  114. package/src/frameworks/solid/add-ons/form/assets/src/routes/demo.form.tsx.ejs +22 -22
  115. package/src/frameworks/solid/add-ons/sentry/assets/src/routes/demo.sentry.bad-event-handler.tsx +15 -10
  116. package/src/frameworks/solid/add-ons/store/assets/src/routes/demo.store.tsx.ejs +9 -14
  117. package/src/frameworks/solid/add-ons/strapi/assets/src/routes/demo/strapi.tsx +11 -15
  118. package/src/frameworks/solid/add-ons/strapi/assets/src/routes/demo/strapi_.$articleId.tsx +11 -18
  119. package/src/frameworks/solid/project/base/_dot_gitignore +1 -0
  120. package/src/frameworks/solid/project/base/src/styles.css.ejs +203 -0
  121. package/tests/framework-template.test.ts +15 -0
@@ -24,10 +24,8 @@ function InitialLayout({ children }: { children: React.ReactNode }) {
24
24
  return (
25
25
  <div className="flex-1 flex items-center justify-center px-4">
26
26
  <div className="text-center max-w-3xl mx-auto w-full">
27
- <h1 className="text-6xl font-bold mb-4 bg-linear-to-r from-orange-500 to-red-600 text-transparent bg-clip-text uppercase">
28
- <span className="text-white">TanStack</span> Chat
29
- </h1>
30
- <p className="text-gray-400 mb-6 w-2/3 mx-auto text-lg">
27
+ <h1 className="demo-title mb-4">TanStack Chat</h1>
28
+ <p className="demo-muted mb-6 mx-auto max-w-2xl text-lg">
31
29
  You can ask me about anything, I might or might not have a good
32
30
  answer, but you can still ask.
33
31
  </p>
@@ -39,7 +37,7 @@ function InitialLayout({ children }: { children: React.ReactNode }) {
39
37
 
40
38
  function ChattingLayout({ children }: { children: React.ReactNode }) {
41
39
  return (
42
- <div className="sticky bottom-0 left-0 right-0 bg-gray-900/80 backdrop-blur-sm border-t border-orange-500/10 z-10">
40
+ <div className="sticky bottom-0 left-0 right-0 z-10 border-t border-[var(--line)] bg-[var(--header-bg)] backdrop-blur-sm">
43
41
  <div className="max-w-3xl mx-auto w-full px-4 py-3">{children}</div>
44
42
  </div>
45
43
  )
@@ -96,17 +94,17 @@ function Messages({
96
94
  key={message.id}
97
95
  className={`p-4 ${
98
96
  message.role === 'assistant'
99
- ? 'bg-linear-to-r from-orange-500/5 to-red-600/5'
97
+ ? 'bg-[var(--chip-bg)]'
100
98
  : 'bg-transparent'
101
99
  }`}
102
100
  >
103
101
  <div className="flex items-start gap-4 max-w-3xl mx-auto w-full">
104
102
  {message.role === 'assistant' ? (
105
- <div className="w-8 h-8 rounded-lg bg-linear-to-r from-orange-500 to-red-600 mt-2 flex items-center justify-center text-sm font-medium text-white flex-shrink-0">
103
+ <div className="mt-2 flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-[var(--lagoon-deep)] text-sm font-medium text-white">
106
104
  AI
107
105
  </div>
108
106
  ) : (
109
- <div className="w-8 h-8 rounded-lg bg-gray-700 flex items-center justify-center text-sm font-medium text-white flex-shrink-0">
107
+ <div className="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-[var(--sea-ink-soft)] text-sm font-medium text-white">
110
108
  Y
111
109
  </div>
112
110
  )}
@@ -115,7 +113,7 @@ function Messages({
115
113
  if (part.type === 'text' && part.content) {
116
114
  return (
117
115
  <div
118
- className="flex-1 min-w-0 prose dark:prose-invert max-w-none prose-sm"
116
+ className="prose prose-sm min-w-0 max-w-none flex-1"
119
117
  key={index}
120
118
  >
121
119
  <Streamdown>{part.content}</Streamdown>
@@ -145,7 +143,7 @@ function Messages({
145
143
  ? onStopSpeak()
146
144
  : onSpeak(textContent, message.id)
147
145
  }
148
- className="flex-shrink-0 p-2 text-gray-400 hover:text-orange-400 transition-colors"
146
+ className="demo-muted flex-shrink-0 p-2 transition-colors hover:text-[var(--lagoon-deep)]"
149
147
  title={isPlaying ? 'Stop speaking' : 'Read aloud'}
150
148
  >
151
149
  {isPlaying ? (
@@ -190,7 +188,7 @@ function ChatPage() {
190
188
  const Layout = messages.length ? ChattingLayout : InitialLayout
191
189
 
192
190
  return (
193
- <div className="relative flex h-[calc(100vh-80px)] bg-gray-900">
191
+ <div className="relative flex h-[calc(100vh-12rem)] min-h-[32rem]">
194
192
  <div className="flex-1 flex flex-col min-h-0">
195
193
  <Messages
196
194
  messages={messages}
@@ -205,7 +203,7 @@ function ChatPage() {
205
203
  <div className="flex items-center justify-center">
206
204
  <button
207
205
  onClick={stop}
208
- className="px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg text-sm font-medium transition-colors flex items-center gap-2"
206
+ className="demo-button demo-button-danger"
209
207
  >
210
208
  <Square className="w-4 h-4 fill-current" />
211
209
  Stop
@@ -226,10 +224,8 @@ function ChatPage() {
226
224
  type="button"
227
225
  onClick={handleMicClick}
228
226
  disabled={isLoading || isTranscribing}
229
- className={`p-3 rounded-lg transition-colors ${
230
- isRecording
231
- ? 'bg-red-600 hover:bg-red-700 text-white'
232
- : 'bg-gray-800/50 text-gray-400 hover:text-orange-400 border border-orange-500/20'
227
+ className={`demo-button p-3 ${
228
+ isRecording ? 'demo-button-danger' : 'demo-button-secondary'
233
229
  } disabled:opacity-50`}
234
230
  title={isRecording ? 'Stop recording' : 'Start recording'}
235
231
  >
@@ -247,7 +243,7 @@ function ChatPage() {
247
243
  value={input}
248
244
  onChange={(e) => setInput(e.target.value)}
249
245
  placeholder="Type something clever..."
250
- className="w-full rounded-lg border border-orange-500/20 bg-gray-800/50 pl-4 pr-12 py-3 text-sm text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-orange-500/50 focus:border-transparent resize-none overflow-hidden shadow-lg"
246
+ className="demo-textarea pr-12 text-sm"
251
247
  rows={1}
252
248
  style={{ minHeight: '44px', maxHeight: '200px' }}
253
249
  disabled={isLoading}
@@ -268,7 +264,7 @@ function ChatPage() {
268
264
  <button
269
265
  type="submit"
270
266
  disabled={!input.trim() || isLoading}
271
- className="absolute right-2 top-1/2 -translate-y-1/2 p-2 text-orange-500 hover:text-orange-400 disabled:text-gray-500 transition-colors focus:outline-none"
267
+ className="absolute right-2 top-1/2 -translate-y-1/2 p-2 text-[var(--lagoon-deep)] transition-colors hover:text-[var(--sea-ink)] disabled:text-[var(--sea-ink-soft)]"
272
268
  >
273
269
  <Send className="w-4 h-4" />
274
270
  </button>
@@ -73,26 +73,25 @@ function ImagePage() {
73
73
  }
74
74
 
75
75
  return (
76
- <div className="min-h-[calc(100vh-80px)] bg-gray-900 p-6">
77
- <div className="max-w-6xl mx-auto">
76
+ <main className="demo-page demo-page-wide">
77
+ <div>
78
78
  <div className="flex items-center gap-3 mb-6">
79
- <ImageIcon className="w-8 h-8 text-orange-500" />
80
- <h1 className="text-2xl font-bold text-white">Image Generation</h1>
79
+ <ImageIcon className="w-8 h-8 text-[var(--lagoon-deep)]" />
80
+ <h1 className="demo-title">Image Generation</h1>
81
81
  </div>
82
82
 
83
83
  <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
84
- {/* Input Panel */}
85
84
  <div className="space-y-4">
86
85
  <div className="grid grid-cols-2 gap-4">
87
86
  <div>
88
- <label className="block text-sm font-medium text-gray-300 mb-2">
87
+ <label className="mb-2 block text-sm font-medium text-[var(--sea-ink)]">
89
88
  Size
90
89
  </label>
91
90
  <select
92
91
  value={size}
93
92
  onChange={(e) => setSize(e.target.value)}
94
93
  disabled={isLoading}
95
- className="w-full rounded-lg border border-orange-500/20 bg-gray-800 px-3 py-2 text-sm text-white focus:outline-none focus:ring-2 focus:ring-orange-500/50"
94
+ className="demo-select text-sm"
96
95
  >
97
96
  {SIZES.map((s) => (
98
97
  <option key={s} value={s}>
@@ -102,7 +101,7 @@ function ImagePage() {
102
101
  </select>
103
102
  </div>
104
103
  <div>
105
- <label className="block text-sm font-medium text-gray-300 mb-2">
104
+ <label className="mb-2 block text-sm font-medium text-[var(--sea-ink)]">
106
105
  Count
107
106
  </label>
108
107
  <input
@@ -116,13 +115,13 @@ function ImagePage() {
116
115
  min={1}
117
116
  max={4}
118
117
  disabled={isLoading}
119
- className="w-full rounded-lg border border-orange-500/20 bg-gray-800 px-3 py-2 text-sm text-white focus:outline-none focus:ring-2 focus:ring-orange-500/50"
118
+ className="demo-input text-sm"
120
119
  />
121
120
  </div>
122
121
  </div>
123
122
 
124
123
  <div>
125
- <label className="block text-sm font-medium text-gray-300 mb-2">
124
+ <label className="mb-2 block text-sm font-medium text-[var(--sea-ink)]">
126
125
  Prompt
127
126
  </label>
128
127
  <textarea
@@ -130,7 +129,7 @@ function ImagePage() {
130
129
  onChange={(e) => setPrompt(e.target.value)}
131
130
  disabled={isLoading}
132
131
  rows={6}
133
- className="w-full rounded-lg border border-orange-500/20 bg-gray-800 px-3 py-2 text-sm text-white focus:outline-none focus:ring-2 focus:ring-orange-500/50 resize-none"
132
+ className="demo-textarea text-sm"
134
133
  placeholder="Describe the image you want to generate..."
135
134
  />
136
135
  </div>
@@ -138,7 +137,7 @@ function ImagePage() {
138
137
  <button
139
138
  onClick={handleGenerate}
140
139
  disabled={isLoading || !prompt.trim()}
141
- className="w-full px-4 py-3 bg-orange-600 hover:bg-orange-700 disabled:bg-gray-600 text-white rounded-lg font-medium transition-colors flex items-center justify-center gap-2"
140
+ className="demo-button w-full"
142
141
  >
143
142
  {isLoading ? (
144
143
  <>
@@ -151,16 +150,11 @@ function ImagePage() {
151
150
  </button>
152
151
  </div>
153
152
 
154
- {/* Output Panel */}
155
- <div className="lg:col-span-2 bg-gray-800 rounded-lg p-6 border border-orange-500/20">
156
- <h2 className="text-lg font-semibold text-white mb-4">
157
- Generated Images
158
- </h2>
153
+ <div className="demo-panel lg:col-span-2">
154
+ <h2 className="demo-section-title mb-4">Generated Images</h2>
159
155
 
160
156
  {error && (
161
- <div className="p-4 bg-red-500/10 border border-red-500/20 rounded-lg text-red-400 mb-4">
162
- {error}
163
- </div>
157
+ <div className="demo-alert demo-alert-danger mb-4">{error}</div>
164
158
  )}
165
159
 
166
160
  {images.length > 0 ? (
@@ -171,17 +165,17 @@ function ImagePage() {
171
165
  <img
172
166
  src={getImageSrc(image)}
173
167
  alt={`Generated image ${index + 1}`}
174
- className="w-full rounded-lg border border-gray-700"
168
+ className="w-full rounded-lg border border-[var(--line)]"
175
169
  />
176
170
  <button
177
171
  onClick={() => handleDownload(image, index)}
178
- className="absolute top-2 right-2 p-2 bg-gray-900/80 hover:bg-gray-900 rounded-lg opacity-0 group-hover:opacity-100 transition-opacity"
172
+ className="demo-button absolute right-2 top-2 p-2 opacity-0 transition-opacity group-hover:opacity-100"
179
173
  title="Download image"
180
174
  >
181
- <Download className="w-4 h-4 text-white" />
175
+ <Download className="w-4 h-4" />
182
176
  </button>
183
177
  {image.revisedPrompt && (
184
- <p className="mt-2 text-xs text-gray-400 italic">
178
+ <p className="demo-muted mt-2 text-xs italic">
185
179
  Revised: {image.revisedPrompt}
186
180
  </p>
187
181
  )}
@@ -190,7 +184,7 @@ function ImagePage() {
190
184
  </div>
191
185
  </div>
192
186
  ) : !error && !isLoading ? (
193
- <div className="flex flex-col items-center justify-center h-64 text-gray-500">
187
+ <div className="demo-muted flex h-64 flex-col items-center justify-center">
194
188
  <ImageIcon className="w-16 h-16 mb-4 opacity-50" />
195
189
  <p>
196
190
  Enter a prompt and click "Generate Image" to create an image.
@@ -200,7 +194,7 @@ function ImagePage() {
200
194
  </div>
201
195
  </div>
202
196
  </div>
203
- </div>
197
+ </main>
204
198
  )
205
199
  }
206
200
 
@@ -20,35 +20,37 @@ const SAMPLE_RECIPES = [
20
20
 
21
21
  function RecipeCard({ recipe }: { recipe: Recipe }) {
22
22
  const difficultyColors = {
23
- easy: 'bg-green-500/20 text-green-400',
24
- medium: 'bg-yellow-500/20 text-yellow-400',
25
- hard: 'bg-red-500/20 text-red-400',
23
+ easy: 'demo-pill',
24
+ medium: 'demo-pill',
25
+ hard: 'demo-pill',
26
26
  }
27
27
 
28
28
  return (
29
29
  <div className="space-y-6">
30
30
  {/* Header */}
31
31
  <div>
32
- <h3 className="text-2xl font-bold text-white mb-2">{recipe.name}</h3>
33
- <p className="text-gray-400">{recipe.description}</p>
32
+ <h3 className="text-2xl font-bold text-[var(--sea-ink)] mb-2">
33
+ {recipe.name}
34
+ </h3>
35
+ <p className="demo-muted">{recipe.description}</p>
34
36
  </div>
35
37
 
36
38
  {/* Meta info */}
37
39
  <div className="flex flex-wrap gap-4">
38
- <div className="flex items-center gap-2 text-gray-300">
39
- <Clock className="w-4 h-4 text-orange-400" />
40
+ <div className="demo-muted flex items-center gap-2">
41
+ <Clock className="w-4 h-4 text-[var(--lagoon-deep)]" />
40
42
  <span className="text-sm">Prep: {recipe.prepTime}</span>
41
43
  </div>
42
- <div className="flex items-center gap-2 text-gray-300">
43
- <Clock className="w-4 h-4 text-orange-400" />
44
+ <div className="demo-muted flex items-center gap-2">
45
+ <Clock className="w-4 h-4 text-[var(--lagoon-deep)]" />
44
46
  <span className="text-sm">Cook: {recipe.cookTime}</span>
45
47
  </div>
46
- <div className="flex items-center gap-2 text-gray-300">
47
- <Users className="w-4 h-4 text-orange-400" />
48
+ <div className="demo-muted flex items-center gap-2">
49
+ <Users className="w-4 h-4 text-[var(--lagoon-deep)]" />
48
50
  <span className="text-sm">{recipe.servings} servings</span>
49
51
  </div>
50
52
  <div
51
- className={`flex items-center gap-2 px-2 py-1 rounded-full ${
53
+ className={`flex items-center gap-2 ${
52
54
  difficultyColors[recipe.difficulty]
53
55
  }`}
54
56
  >
@@ -59,16 +61,16 @@ function RecipeCard({ recipe }: { recipe: Recipe }) {
59
61
 
60
62
  {/* Ingredients */}
61
63
  <div>
62
- <h4 className="text-lg font-semibold text-white mb-3">Ingredients</h4>
64
+ <h4 className="text-lg font-semibold text-[var(--sea-ink)] mb-3">
65
+ Ingredients
66
+ </h4>
63
67
  <ul className="grid grid-cols-1 md:grid-cols-2 gap-2">
64
68
  {recipe.ingredients.map((ing, idx) => (
65
- <li key={idx} className="flex items-start gap-2 text-gray-300">
66
- <span className="text-orange-400">•</span>
69
+ <li key={idx} className="demo-muted flex items-start gap-2">
70
+ <span className="text-[var(--lagoon-deep)]">•</span>
67
71
  <span>
68
72
  <span className="font-medium">{ing.amount}</span> {ing.item}
69
- {ing.notes && (
70
- <span className="text-gray-500 text-sm"> ({ing.notes})</span>
71
- )}
73
+ {ing.notes && <span className="text-sm"> ({ing.notes})</span>}
72
74
  </span>
73
75
  </li>
74
76
  ))}
@@ -77,11 +79,13 @@ function RecipeCard({ recipe }: { recipe: Recipe }) {
77
79
 
78
80
  {/* Instructions */}
79
81
  <div>
80
- <h4 className="text-lg font-semibold text-white mb-3">Instructions</h4>
82
+ <h4 className="text-lg font-semibold text-[var(--sea-ink)] mb-3">
83
+ Instructions
84
+ </h4>
81
85
  <ol className="space-y-3">
82
86
  {recipe.instructions.map((step, idx) => (
83
- <li key={idx} className="flex gap-3 text-gray-300">
84
- <span className="flex-shrink-0 w-6 h-6 bg-orange-500/20 text-orange-400 rounded-full flex items-center justify-center text-sm font-medium">
87
+ <li key={idx} className="demo-muted flex gap-3">
88
+ <span className="flex-shrink-0 w-6 h-6 rounded-full border border-[var(--line)] bg-[var(--chip-bg)] text-[var(--sea-ink)] flex items-center justify-center text-sm font-medium">
85
89
  {idx + 1}
86
90
  </span>
87
91
  <span>{step}</span>
@@ -93,11 +97,13 @@ function RecipeCard({ recipe }: { recipe: Recipe }) {
93
97
  {/* Tips */}
94
98
  {recipe.tips && recipe.tips.length > 0 && (
95
99
  <div>
96
- <h4 className="text-lg font-semibold text-white mb-3">Tips</h4>
100
+ <h4 className="text-lg font-semibold text-[var(--sea-ink)] mb-3">
101
+ Tips
102
+ </h4>
97
103
  <ul className="space-y-2">
98
104
  {recipe.tips.map((tip, idx) => (
99
- <li key={idx} className="flex items-start gap-2 text-gray-300">
100
- <span className="text-yellow-400">*</span>
105
+ <li key={idx} className="demo-muted flex items-start gap-2">
106
+ <span className="text-[var(--lagoon-deep)]">*</span>
101
107
  <span>{tip}</span>
102
108
  </li>
103
109
  ))}
@@ -108,27 +114,27 @@ function RecipeCard({ recipe }: { recipe: Recipe }) {
108
114
  {/* Nutrition */}
109
115
  {recipe.nutritionPerServing && (
110
116
  <div>
111
- <h4 className="text-lg font-semibold text-white mb-3">
117
+ <h4 className="text-lg font-semibold text-[var(--sea-ink)] mb-3">
112
118
  Nutrition (per serving)
113
119
  </h4>
114
120
  <div className="flex flex-wrap gap-4 text-sm">
115
121
  {recipe.nutritionPerServing.calories && (
116
- <span className="px-3 py-1 bg-gray-700 rounded-full text-gray-300">
122
+ <span className="demo-pill">
117
123
  {recipe.nutritionPerServing.calories} cal
118
124
  </span>
119
125
  )}
120
126
  {recipe.nutritionPerServing.protein && (
121
- <span className="px-3 py-1 bg-gray-700 rounded-full text-gray-300">
127
+ <span className="demo-pill">
122
128
  Protein: {recipe.nutritionPerServing.protein}
123
129
  </span>
124
130
  )}
125
131
  {recipe.nutritionPerServing.carbs && (
126
- <span className="px-3 py-1 bg-gray-700 rounded-full text-gray-300">
132
+ <span className="demo-pill">
127
133
  Carbs: {recipe.nutritionPerServing.carbs}
128
134
  </span>
129
135
  )}
130
136
  {recipe.nutritionPerServing.fat && (
131
- <span className="px-3 py-1 bg-gray-700 rounded-full text-gray-300">
137
+ <span className="demo-pill">
132
138
  Fat: {recipe.nutritionPerServing.fat}
133
139
  </span>
134
140
  )}
@@ -182,26 +188,24 @@ function StructuredPage() {
182
188
  const canExecute = !!(!isLoading && recipeName.trim() && !error)
183
189
 
184
190
  return (
185
- <div className="min-h-[calc(100vh-80px)] bg-gray-900 p-6">
186
- <div className="max-w-6xl mx-auto">
191
+ <main className="demo-page demo-page-wide">
192
+ <div>
187
193
  <div className="flex items-center gap-3 mb-6">
188
- <ChefHat className="w-8 h-8 text-orange-500" />
189
- <h1 className="text-2xl font-bold text-white">
190
- One-Shot & Structured Output
191
- </h1>
194
+ <ChefHat className="w-8 h-8 text-[var(--lagoon-deep)]" />
195
+ <h1 className="demo-title">One-Shot & Structured Output</h1>
192
196
  </div>
193
197
 
194
- <p className="text-gray-400 mb-6">
198
+ <p className="demo-muted mb-6">
195
199
  Compare two output modes:{' '}
196
- <strong className="text-orange-400">One-Shot</strong> returns freeform
197
- markdown, while{' '}
198
- <strong className="text-orange-400">Structured</strong> returns
200
+ <strong className="text-[var(--sea-ink)]">One-Shot</strong> returns
201
+ freeform markdown, while{' '}
202
+ <strong className="text-[var(--sea-ink)]">Structured</strong> returns
199
203
  validated JSON conforming to a Zod schema.
200
204
  </p>
201
205
 
202
206
  <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
203
207
  <div>
204
- <label className="block text-sm font-medium text-gray-300 mb-2">
208
+ <label className="mb-2 block text-sm font-medium text-[var(--sea-ink)]">
205
209
  Recipe Name
206
210
  </label>
207
211
  <input
@@ -210,11 +214,11 @@ function StructuredPage() {
210
214
  onChange={(e) => setRecipeName(e.target.value)}
211
215
  disabled={isLoading}
212
216
  placeholder="e.g., Chocolate Chip Cookies"
213
- className="w-full rounded-lg border border-orange-500/20 bg-gray-800 px-3 py-2 text-sm text-white focus:outline-none focus:ring-2 focus:ring-orange-500/50"
217
+ className="demo-input text-sm"
214
218
  />
215
219
 
216
220
  <div className="mt-2">
217
- <label className="block text-sm font-medium text-gray-300 mb-2">
221
+ <label className="mb-2 block text-sm font-medium text-[var(--sea-ink)]">
218
222
  Quick Picks
219
223
  </label>
220
224
  <div className="flex flex-wrap gap-2">
@@ -223,7 +227,7 @@ function StructuredPage() {
223
227
  key={name}
224
228
  onClick={() => setRecipeName(name)}
225
229
  disabled={isLoading}
226
- className="px-2 py-1 text-xs bg-gray-800 hover:bg-gray-700 text-gray-300 rounded-lg border border-gray-700 transition-colors"
230
+ className="demo-button demo-button-secondary px-2 py-1 text-xs"
227
231
  >
228
232
  {name}
229
233
  </button>
@@ -237,18 +241,14 @@ function StructuredPage() {
237
241
  <button
238
242
  onClick={() => handleGenerate('oneshot')}
239
243
  disabled={!canExecute}
240
- className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors text-white ${
241
- !canExecute ? 'bg-gray-600' : 'bg-orange-500'
242
- }`}
244
+ className="demo-button"
243
245
  >
244
246
  One-Shot (Markdown)
245
247
  </button>
246
248
  <button
247
249
  onClick={() => handleGenerate('structured')}
248
250
  disabled={!canExecute}
249
- className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors text-white ${
250
- !canExecute ? 'bg-gray-600' : 'bg-blue-500'
251
- }`}
251
+ className="demo-button"
252
252
  >
253
253
  Structured (JSON)
254
254
  </button>
@@ -256,29 +256,18 @@ function StructuredPage() {
256
256
  </div>
257
257
  </div>
258
258
 
259
- {/* Output Panel */}
260
- <div className="mt-5 lg:col-span-2 bg-gray-800 rounded-lg p-6 border border-orange-500/20">
259
+ <div className="demo-panel mt-5 lg:col-span-2">
261
260
  <div className="flex items-center justify-between mb-4">
262
- <h2 className="text-lg font-semibold text-white">
263
- Generated Recipe
264
- </h2>
261
+ <h2 className="demo-section-title">Generated Recipe</h2>
265
262
  {result && (
266
- <span
267
- className={`px-2 py-1 rounded text-xs font-medium ${
268
- result.mode === 'structured'
269
- ? 'bg-purple-500/20 text-purple-400'
270
- : 'bg-blue-500/20 text-blue-400'
271
- }`}
272
- >
263
+ <span className="demo-pill">
273
264
  {result.mode === 'structured' ? 'Structured JSON' : 'Markdown'}
274
265
  </span>
275
266
  )}
276
267
  </div>
277
268
 
278
269
  {error && (
279
- <div className="p-4 bg-red-500/10 border border-red-500/20 rounded-lg text-red-400 mb-4">
280
- {error}
281
- </div>
270
+ <div className="demo-alert demo-alert-danger mb-4">{error}</div>
282
271
  )}
283
272
 
284
273
  {result ? (
@@ -286,13 +275,13 @@ function StructuredPage() {
286
275
  {result.mode === 'structured' && result.recipe ? (
287
276
  <RecipeCard recipe={result.recipe} />
288
277
  ) : result.markdown ? (
289
- <div className="prose prose-invert max-w-none">
278
+ <div className="max-w-none">
290
279
  <Streamdown>{result.markdown}</Streamdown>
291
280
  </div>
292
281
  ) : null}
293
282
  </div>
294
283
  ) : !error && !isLoading ? (
295
- <div className="flex flex-col items-center justify-center h-64 text-gray-500">
284
+ <div className="demo-muted flex h-64 flex-col items-center justify-center">
296
285
  <ChefHat className="w-16 h-16 mb-4 opacity-50" />
297
286
  <p>
298
287
  Enter a recipe name and click "Generate Recipe" to get started.
@@ -301,7 +290,7 @@ function StructuredPage() {
301
290
  ) : null}
302
291
  </div>
303
292
  </div>
304
- </div>
293
+ </main>
305
294
  )
306
295
  }
307
296
 
@@ -17,35 +17,30 @@ function RouteComponent() {
17
17
  const guitar = Route.useLoaderData()
18
18
 
19
19
  return (
20
- <div className="relative min-h-[100vh] flex items-center bg-black text-white p-5">
21
- <div className="relative z-10 w-[60%] bg-gray-900/60 backdrop-blur-md rounded-2xl p-8 border border-gray-800/50 shadow-xl">
22
- <Link
23
- to="/example/guitars"
24
- className="inline-block mb-4 text-emerald-400 hover:text-emerald-300"
25
- >
26
- &larr; Back to all guitars
27
- </Link>
28
- <h1 className="text-3xl font-bold mb-4">{guitar.name}</h1>
29
- <p className="text-gray-300 mb-6">{guitar.description}</p>
30
- <div className="flex items-center justify-between">
31
- <div className="text-2xl font-bold text-emerald-400">
32
- ${guitar.price}
20
+ <main className="demo-page">
21
+ <div className="grid gap-8 lg:grid-cols-[minmax(0,1fr)_minmax(20rem,28rem)] lg:items-center">
22
+ <section className="demo-panel">
23
+ <Link to="/demo/guitars/" className="mb-4 inline-block">
24
+ &larr; Back to all guitars
25
+ </Link>
26
+ <h1 className="demo-title mb-4">{guitar.name}</h1>
27
+ <p className="demo-muted mb-6">{guitar.description}</p>
28
+ <div className="flex items-center justify-between">
29
+ <div className="text-2xl font-bold text-[var(--lagoon-deep)]">
30
+ ${guitar.price}
31
+ </div>
32
+ <button className="demo-button">Add to Cart</button>
33
33
  </div>
34
- <button className="bg-emerald-600 hover:bg-emerald-500 text-white px-6 py-2 rounded-lg transition-colors">
35
- Add to Cart
36
- </button>
37
- </div>
38
- </div>
34
+ </section>
39
35
 
40
- <div className="absolute top-0 right-0 w-[55%] h-full z-0">
41
- <div className="w-full h-full overflow-hidden rounded-2xl border-4 border-gray-800 shadow-2xl">
36
+ <div className="demo-card overflow-hidden p-0">
42
37
  <img
43
38
  src={guitar.image}
44
39
  alt={guitar.name}
45
- className="w-full h-full object-cover guitar-image"
40
+ className="guitar-image h-full w-full object-cover"
46
41
  />
47
42
  </div>
48
43
  </div>
49
- </div>
44
+ </main>
50
45
  )
51
46
  }