kaddidlehopper 0.5.0 → 0.6.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 (296) hide show
  1. package/dist/cli.js +104 -208
  2. package/dist/index.js +1 -31
  3. package/dist/types/cli.d.ts +1 -8
  4. package/dist/types/types.d.ts +7 -12
  5. package/package.json +1 -2
  6. package/src/cli.ts +129 -271
  7. package/src/index.ts +1 -47
  8. package/src/types.ts +7 -13
  9. package/CONTEXT.md +0 -139
  10. package/add-ons/ai/README.md +0 -34
  11. package/add-ons/ai/assets/AGENTS.md.append +0 -24
  12. package/add-ons/ai/assets/_dot_env.local.append +0 -13
  13. package/add-ons/ai/assets/src/components/AIAssistant.tsx +0 -149
  14. package/add-ons/ai/assets/src/lib/ai-hook.ts +0 -21
  15. package/add-ons/ai/assets/src/lib/weather-tools.ts +0 -30
  16. package/add-ons/ai/assets/src/routes/api.chat.ts +0 -94
  17. package/add-ons/ai/assets/src/routes/chat.css +0 -175
  18. package/add-ons/ai/assets/src/routes/chat.tsx +0 -141
  19. package/add-ons/ai/info.json +0 -22
  20. package/add-ons/ai/package.json +0 -17
  21. package/add-ons/ai/small-logo.svg +0 -8
  22. package/add-ons/db/assets/AGENTS.md.append +0 -22
  23. package/add-ons/db/assets/DB-SETUP.md +0 -65
  24. package/add-ons/db/assets/_dot_env.local.append +0 -2
  25. package/add-ons/db/assets/drizzle.config.ts +0 -10
  26. package/add-ons/db/assets/src/db/index.ts +0 -8
  27. package/add-ons/db/assets/src/db/schema.ts +0 -8
  28. package/add-ons/db/assets/src/routes/db-example.tsx +0 -118
  29. package/add-ons/db/assets/src/server/guestbook.functions.ts +0 -23
  30. package/add-ons/db/info.json +0 -22
  31. package/add-ons/db/package.json +0 -10
  32. package/add-ons/forms/assets/AGENTS.md.append +0 -13
  33. package/add-ons/forms/assets/public/form-example.html +0 -14
  34. package/add-ons/forms/assets/src/routes/form-example.tsx +0 -76
  35. package/add-ons/forms/info.json +0 -18
  36. package/add-ons/forms/package.json +0 -3
  37. package/examples/ai-chat/README.md +0 -36
  38. package/examples/ai-chat/assets/AGENTS.md.append +0 -24
  39. package/examples/ai-chat/assets/src/lib/ai-hook.ts +0 -21
  40. package/examples/ai-chat/assets/src/lib/weather-tools.ts +0 -30
  41. package/examples/ai-chat/assets/src/routes/__root.tsx +0 -57
  42. package/examples/ai-chat/assets/src/routes/api.chat.ts +0 -94
  43. package/examples/ai-chat/assets/src/routes/index.tsx +0 -141
  44. package/examples/ai-chat/assets/src/styles.css +0 -165
  45. package/examples/ai-chat/info.json +0 -25
  46. package/examples/ai-chat/package.json +0 -14
  47. package/examples/blog/README.md +0 -60
  48. package/examples/blog/assets/AGENTS.md.append +0 -18
  49. package/examples/blog/assets/content/posts/beach.md +0 -12
  50. package/examples/blog/assets/content/posts/jungle.md.ejs +0 -12
  51. package/examples/blog/assets/content/posts/mountains.md.ejs +0 -12
  52. package/examples/blog/assets/content/posts/snorkeling.md.ejs +0 -12
  53. package/examples/blog/assets/content/posts/waterfall.md.ejs +0 -12
  54. package/examples/blog/assets/content-collections.ts +0 -30
  55. package/examples/blog/assets/public/beach.jpg +0 -0
  56. package/examples/blog/assets/public/jungle.jpg +0 -0
  57. package/examples/blog/assets/public/mountains.jpg +0 -0
  58. package/examples/blog/assets/public/snorkeling.jpg +0 -0
  59. package/examples/blog/assets/public/waterfall.jpg +0 -0
  60. package/examples/blog/assets/src/components/Header.tsx +0 -52
  61. package/examples/blog/assets/src/components/VacayAssistant.tsx +0 -205
  62. package/examples/blog/assets/src/components/blog-posts.tsx +0 -78
  63. package/examples/blog/assets/src/components/ui/card.tsx +0 -92
  64. package/examples/blog/assets/src/lib/blog-ai-hook.ts +0 -25
  65. package/examples/blog/assets/src/lib/blog-tools.ts +0 -111
  66. package/examples/blog/assets/src/lib/utils.ts +0 -6
  67. package/examples/blog/assets/src/routes/__root.tsx +0 -57
  68. package/examples/blog/assets/src/routes/api.blog-chat.ts +0 -117
  69. package/examples/blog/assets/src/routes/category.$category.tsx +0 -19
  70. package/examples/blog/assets/src/routes/index.tsx +0 -19
  71. package/examples/blog/assets/src/routes/posts.$slug.tsx +0 -63
  72. package/examples/blog/assets/src/styles.css +0 -138
  73. package/examples/blog/info.json +0 -40
  74. package/examples/blog/package.json +0 -23
  75. package/examples/calculator/README.md +0 -16
  76. package/examples/calculator/assets/AGENTS.md.append +0 -9
  77. package/examples/calculator/assets/src/components/Calculator.tsx +0 -238
  78. package/examples/calculator/assets/src/components/Header.tsx +0 -17
  79. package/examples/calculator/assets/src/routes/__root.tsx +0 -57
  80. package/examples/calculator/assets/src/routes/index.tsx +0 -14
  81. package/examples/calculator/info.json +0 -20
  82. package/examples/calculator/package.json +0 -1
  83. package/examples/dashboard/README.md +0 -17
  84. package/examples/dashboard/assets/AGENTS.md.append +0 -12
  85. package/examples/dashboard/assets/src/components/Header.tsx +0 -17
  86. package/examples/dashboard/assets/src/routes/__root.tsx +0 -57
  87. package/examples/dashboard/assets/src/routes/index.tsx +0 -158
  88. package/examples/dashboard/info.json +0 -19
  89. package/examples/dashboard/package.json +0 -6
  90. package/examples/ecommerce/README.md +0 -48
  91. package/examples/ecommerce/assets/AGENTS.md.append +0 -22
  92. package/examples/ecommerce/assets/public/logo.png +0 -0
  93. package/examples/ecommerce/assets/public/motorcycle-scooter.jpg +0 -0
  94. package/examples/ecommerce/assets/src/components/BuyButton.tsx +0 -35
  95. package/examples/ecommerce/assets/src/components/Header.tsx +0 -36
  96. package/examples/ecommerce/assets/src/components/MotorcycleAIAssistant.tsx +0 -162
  97. package/examples/ecommerce/assets/src/components/MotorcycleRecommendation.tsx +0 -53
  98. package/examples/ecommerce/assets/src/data/motorcycles.ts +0 -27
  99. package/examples/ecommerce/assets/src/lib/motorcycle-ai-hook.ts +0 -24
  100. package/examples/ecommerce/assets/src/lib/motorcycle-tools.ts +0 -42
  101. package/examples/ecommerce/assets/src/lib/stripe.server.ts +0 -39
  102. package/examples/ecommerce/assets/src/routes/__root.tsx +0 -57
  103. package/examples/ecommerce/assets/src/routes/api.motorcycle-chat.ts +0 -78
  104. package/examples/ecommerce/assets/src/routes/checkout/cancel.tsx +0 -25
  105. package/examples/ecommerce/assets/src/routes/checkout/success.tsx +0 -25
  106. package/examples/ecommerce/assets/src/routes/index.tsx +0 -76
  107. package/examples/ecommerce/assets/src/routes/motorcycles/$motorcycleId.tsx +0 -55
  108. package/examples/ecommerce/assets/src/store/motorcycle-assistant.ts +0 -3
  109. package/examples/ecommerce/assets/src/styles.css +0 -212
  110. package/examples/ecommerce/info.json +0 -38
  111. package/examples/ecommerce/package.json +0 -13
  112. package/examples/events/README.md +0 -110
  113. package/examples/events/assets/AGENTS.md.append +0 -21
  114. package/examples/events/assets/content/speakers/andre-costa.md +0 -22
  115. package/examples/events/assets/content/speakers/hans-mueller.md.ejs +0 -22
  116. package/examples/events/assets/content/speakers/isabella-martinez.md.ejs +0 -22
  117. package/examples/events/assets/content/speakers/kenji-nakamura.md.ejs +0 -22
  118. package/examples/events/assets/content/speakers/marie-dubois.md.ejs +0 -20
  119. package/examples/events/assets/content/speakers/priya-sharma.md.ejs +0 -22
  120. package/examples/events/assets/content/talks/croissant-lamination-secrets.md +0 -39
  121. package/examples/events/assets/content/talks/french-macaron-mastery.md.ejs +0 -39
  122. package/examples/events/assets/content/talks/neapolitan-pizza-tradition-meets-innovation.md.ejs +0 -39
  123. package/examples/events/assets/content/talks/savory-breads-of-the-mediterranean.md.ejs +0 -39
  124. package/examples/events/assets/content/talks/sourdough-from-starter-to-masterpiece.md.ejs +0 -36
  125. package/examples/events/assets/content/talks/the-art-of-the-perfect-tart.md.ejs +0 -32
  126. package/examples/events/assets/content/talks/the-science-of-sugar.md.ejs +0 -39
  127. package/examples/events/assets/content/talks/umami-in-pastry-east-meets-west.md.ejs +0 -39
  128. package/examples/events/assets/content-collections.ts +0 -56
  129. package/examples/events/assets/public/background-1.jpg +0 -0
  130. package/examples/events/assets/public/background-2.jpg +0 -0
  131. package/examples/events/assets/public/background-3.jpg +0 -0
  132. package/examples/events/assets/public/background-4.jpg +0 -0
  133. package/examples/events/assets/public/conference-logo.png +0 -0
  134. package/examples/events/assets/public/favicon.ico +0 -0
  135. package/examples/events/assets/public/speakers/andre-costa.jpg +0 -0
  136. package/examples/events/assets/public/speakers/hans-mueller.jpg +0 -0
  137. package/examples/events/assets/public/speakers/isabella-martinez.jpg +0 -0
  138. package/examples/events/assets/public/speakers/kenji-nakamura.jpg +0 -0
  139. package/examples/events/assets/public/speakers/marie-dubois.jpg +0 -0
  140. package/examples/events/assets/public/speakers/priya-sharma.jpg +0 -0
  141. package/examples/events/assets/public/talks/croissant-lamination-secrets.jpg +0 -0
  142. package/examples/events/assets/public/talks/french-macaron-mastery.jpg +0 -0
  143. package/examples/events/assets/public/talks/neapolitan-pizza-tradition-meets-innovation.jpg +0 -0
  144. package/examples/events/assets/public/talks/savory-breads-of-the-mediterranean.jpg +0 -0
  145. package/examples/events/assets/public/talks/sourdough-from-starter-to-masterpiece.jpg +0 -0
  146. package/examples/events/assets/public/talks/the-art-of-the-perfect-tart.jpg +0 -0
  147. package/examples/events/assets/public/talks/the-science-of-sugar.jpg +0 -0
  148. package/examples/events/assets/public/talks/umami-in-pastry-east-meets-west.jpg +0 -0
  149. package/examples/events/assets/public/tanstack-circle-logo.png +0 -0
  150. package/examples/events/assets/public/tanstack-word-logo-white.svg +0 -1
  151. package/examples/events/assets/src/components/Header.tsx +0 -59
  152. package/examples/events/assets/src/components/HeaderNav.tsx +0 -67
  153. package/examples/events/assets/src/components/HeroCarousel.tsx +0 -61
  154. package/examples/events/assets/src/components/RemyAssistant.tsx +0 -207
  155. package/examples/events/assets/src/components/SpeakerCard.tsx +0 -67
  156. package/examples/events/assets/src/components/TalkCard.tsx +0 -77
  157. package/examples/events/assets/src/components/ui/card.tsx +0 -92
  158. package/examples/events/assets/src/lib/conference-ai-hook.ts +0 -26
  159. package/examples/events/assets/src/lib/conference-tools.ts +0 -210
  160. package/examples/events/assets/src/lib/model-selection.ts +0 -1
  161. package/examples/events/assets/src/lib/utils.ts +0 -6
  162. package/examples/events/assets/src/routes/__root.tsx +0 -70
  163. package/examples/events/assets/src/routes/api.remy-chat.ts +0 -119
  164. package/examples/events/assets/src/routes/index.tsx +0 -192
  165. package/examples/events/assets/src/routes/schedule.index.tsx +0 -274
  166. package/examples/events/assets/src/routes/speakers.$slug.tsx +0 -122
  167. package/examples/events/assets/src/routes/speakers.index.tsx +0 -40
  168. package/examples/events/assets/src/routes/talks.$slug.tsx +0 -116
  169. package/examples/events/assets/src/routes/talks.index.tsx +0 -40
  170. package/examples/events/assets/src/styles.css +0 -182
  171. package/examples/events/info.json +0 -61
  172. package/examples/events/package.json +0 -23
  173. package/examples/marketing/README.md +0 -60
  174. package/examples/marketing/assets/AGENTS.md.append +0 -15
  175. package/examples/marketing/assets/public/logo.png +0 -0
  176. package/examples/marketing/assets/public/motorcycle-adventure.jpg +0 -0
  177. package/examples/marketing/assets/public/motorcycle-cruiser.jpg +0 -0
  178. package/examples/marketing/assets/public/motorcycle-scooter.jpg +0 -0
  179. package/examples/marketing/assets/public/motorcycle-sport.jpg +0 -0
  180. package/examples/marketing/assets/public/motorcycle-supersport.jpg +0 -0
  181. package/examples/marketing/assets/src/components/Header.tsx +0 -36
  182. package/examples/marketing/assets/src/components/MotorcycleAIAssistant.tsx +0 -162
  183. package/examples/marketing/assets/src/components/MotorcycleRecommendation.tsx +0 -53
  184. package/examples/marketing/assets/src/data/motorcycles.ts.ejs +0 -77
  185. package/examples/marketing/assets/src/lib/motorcycle-ai-hook.ts +0 -24
  186. package/examples/marketing/assets/src/lib/motorcycle-tools.ts +0 -42
  187. package/examples/marketing/assets/src/routes/__root.tsx +0 -57
  188. package/examples/marketing/assets/src/routes/api.motorcycle-chat.ts +0 -78
  189. package/examples/marketing/assets/src/routes/index.tsx +0 -72
  190. package/examples/marketing/assets/src/routes/motorcycles/$motorcycleId.tsx +0 -56
  191. package/examples/marketing/assets/src/store/motorcycle-assistant.ts +0 -3
  192. package/examples/marketing/assets/src/styles.css +0 -212
  193. package/examples/marketing/info.json +0 -33
  194. package/examples/marketing/package.json +0 -14
  195. package/examples/portfolio/README.md +0 -49
  196. package/examples/portfolio/assets/AGENTS.md.append +0 -21
  197. package/examples/portfolio/assets/content/blog/getting-started-with-tanstack.md +0 -53
  198. package/examples/portfolio/assets/content/blog/react-19-features.md +0 -78
  199. package/examples/portfolio/assets/content/blog/tailwind-css-v4-guide.md +0 -60
  200. package/examples/portfolio/assets/content/education/code-school.md +0 -17
  201. package/examples/portfolio/assets/content/jobs/initech-junior.md +0 -20
  202. package/examples/portfolio/assets/content/projects/portfolio-site.md +0 -15
  203. package/examples/portfolio/assets/content/projects/task-manager.md +0 -15
  204. package/examples/portfolio/assets/content-collections.ts +0 -65
  205. package/examples/portfolio/assets/public/contact.html +0 -6
  206. package/examples/portfolio/assets/public/headshot-on-white.jpg +0 -0
  207. package/examples/portfolio/assets/src/components/Header.tsx +0 -33
  208. package/examples/portfolio/assets/src/components/ResumeAssistant.tsx +0 -193
  209. package/examples/portfolio/assets/src/components/ui/badge.tsx +0 -46
  210. package/examples/portfolio/assets/src/components/ui/card.tsx +0 -92
  211. package/examples/portfolio/assets/src/components/ui/checkbox.tsx +0 -30
  212. package/examples/portfolio/assets/src/components/ui/hover-card.tsx +0 -44
  213. package/examples/portfolio/assets/src/components/ui/separator.tsx +0 -26
  214. package/examples/portfolio/assets/src/lib/resume-ai-hook.ts +0 -21
  215. package/examples/portfolio/assets/src/lib/resume-tools.ts +0 -165
  216. package/examples/portfolio/assets/src/lib/utils.ts +0 -6
  217. package/examples/portfolio/assets/src/routes/__root.tsx +0 -57
  218. package/examples/portfolio/assets/src/routes/api.resume-chat.ts +0 -116
  219. package/examples/portfolio/assets/src/routes/blog/$slug.tsx +0 -73
  220. package/examples/portfolio/assets/src/routes/contact.tsx +0 -121
  221. package/examples/portfolio/assets/src/routes/index.tsx +0 -55
  222. package/examples/portfolio/assets/src/routes/projects.tsx +0 -62
  223. package/examples/portfolio/assets/src/routes/resume.tsx +0 -220
  224. package/examples/portfolio/assets/src/styles.css +0 -138
  225. package/examples/portfolio/info.json +0 -50
  226. package/examples/portfolio/package.json +0 -26
  227. package/examples/resume/README.md +0 -82
  228. package/examples/resume/assets/AGENTS.md.append +0 -19
  229. package/examples/resume/assets/content/education/code-school.md +0 -17
  230. package/examples/resume/assets/content/jobs/freelance.md.ejs +0 -13
  231. package/examples/resume/assets/content/jobs/initech-junior.md +0 -20
  232. package/examples/resume/assets/content/jobs/initech-lead.md.ejs +0 -29
  233. package/examples/resume/assets/content/jobs/initrode-senior.md.ejs +0 -28
  234. package/examples/resume/assets/content-collections.ts +0 -36
  235. package/examples/resume/assets/public/headshot-on-white.jpg +0 -0
  236. package/examples/resume/assets/src/components/Header.tsx +0 -33
  237. package/examples/resume/assets/src/components/ResumeAssistant.tsx +0 -193
  238. package/examples/resume/assets/src/components/ui/badge.tsx +0 -46
  239. package/examples/resume/assets/src/components/ui/card.tsx +0 -92
  240. package/examples/resume/assets/src/components/ui/checkbox.tsx +0 -30
  241. package/examples/resume/assets/src/components/ui/hover-card.tsx +0 -44
  242. package/examples/resume/assets/src/components/ui/separator.tsx +0 -26
  243. package/examples/resume/assets/src/lib/resume-ai-hook.ts +0 -21
  244. package/examples/resume/assets/src/lib/resume-tools.ts +0 -165
  245. package/examples/resume/assets/src/lib/utils.ts +0 -6
  246. package/examples/resume/assets/src/routes/api.resume-chat.ts +0 -110
  247. package/examples/resume/assets/src/routes/index.tsx +0 -220
  248. package/examples/resume/assets/src/styles.css +0 -138
  249. package/examples/resume/info.json +0 -35
  250. package/examples/resume/package.json +0 -26
  251. package/examples/saas/README.md +0 -16
  252. package/examples/saas/assets/AGENTS.md.append +0 -9
  253. package/examples/saas/assets/src/components/Header.tsx +0 -17
  254. package/examples/saas/assets/src/routes/__root.tsx +0 -57
  255. package/examples/saas/assets/src/routes/faq.tsx +0 -94
  256. package/examples/saas/assets/src/routes/index.tsx +0 -197
  257. package/examples/saas/info.json +0 -23
  258. package/examples/saas/package.json +0 -1
  259. package/examples/survey/README.md +0 -20
  260. package/examples/survey/assets/AGENTS.md.append +0 -9
  261. package/examples/survey/assets/public/form-survey.html +0 -15
  262. package/examples/survey/assets/src/components/SurveyForm.tsx +0 -128
  263. package/examples/survey/assets/src/routes/index.tsx +0 -14
  264. package/examples/survey/info.json +0 -19
  265. package/examples/survey/package.json +0 -1
  266. package/project/base/AGENTS.md +0 -86
  267. package/project/base/_dot_claude/skills/content-collections/SKILL.md +0 -505
  268. package/project/base/_dot_claude/skills/netlify-blobs/SKILL.md +0 -410
  269. package/project/base/_dot_claude/skills/netlify-db/SKILL.md +0 -424
  270. package/project/base/_dot_claude/skills/netlify-debugging/SKILL.md +0 -419
  271. package/project/base/_dot_claude/skills/netlify-forms/SKILL.md +0 -243
  272. package/project/base/_dot_claude/skills/netlify-functions/SKILL.md +0 -372
  273. package/project/base/_dot_claude/skills/tanstack-start-api-routes/SKILL.md +0 -421
  274. package/project/base/_dot_claude/skills/tanstack-start-loaders/SKILL.md +0 -426
  275. package/project/base/_dot_claude/skills/tanstack-start-project-setup/SKILL.md +0 -493
  276. package/project/base/_dot_claude/skills/tanstack-start-routes/SKILL.md +0 -430
  277. package/project/base/_dot_claude/skills/tanstack-start-server-functions/SKILL.md +0 -445
  278. package/project/base/_dot_claude/skills/tanstack-start-typesafe-routing/SKILL.md +0 -494
  279. package/project/base/_dot_gitignore +0 -8
  280. package/project/base/netlify.toml +0 -7
  281. package/project/base/package.json +0 -33
  282. package/project/base/public/favicon.ico +0 -0
  283. package/project/base/public/tanstack-circle-logo.png +0 -0
  284. package/project/base/public/tanstack-word-logo-white.svg +0 -1
  285. package/project/base/src/components/Header.tsx +0 -17
  286. package/project/base/src/components/HeaderNav.tsx.ejs +0 -179
  287. package/project/base/src/router.tsx +0 -15
  288. package/project/base/src/routes/__root.tsx +0 -57
  289. package/project/base/src/routes/index.tsx +0 -48
  290. package/project/base/src/styles.css +0 -15
  291. package/project/base/tsconfig.json +0 -28
  292. package/project/base/vite.config.ts.ejs +0 -25
  293. package/project/info.json +0 -17
  294. package/project/packages.json +0 -22
  295. package/scripts/check-outdated-packages.js +0 -421
  296. package/src/agents-md.ts +0 -139
@@ -1,121 +0,0 @@
1
- import { createFileRoute } from '@tanstack/react-router'
2
- import { useState } from 'react'
3
- import { Mail, Send } from 'lucide-react'
4
-
5
- export const Route = createFileRoute('/contact')({
6
- component: Contact,
7
- })
8
-
9
- function Contact() {
10
- const [submitted, setSubmitted] = useState(false)
11
-
12
- if (submitted) {
13
- return (
14
- <div className="min-h-screen bg-gray-50 flex items-center justify-center">
15
- <div className="text-center max-w-md mx-auto px-4">
16
- <div className="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-4">
17
- <Mail className="w-8 h-8 text-green-600" />
18
- </div>
19
- <h2 className="text-2xl font-bold text-gray-900 mb-2">Message Sent!</h2>
20
- <p className="text-gray-600 mb-6">
21
- Thanks for reaching out. I'll get back to you as soon as possible.
22
- </p>
23
- <button
24
- onClick={() => setSubmitted(false)}
25
- className="px-6 py-2 bg-gray-900 text-white rounded-lg hover:bg-gray-800 transition-colors"
26
- >
27
- Send Another Message
28
- </button>
29
- </div>
30
- </div>
31
- )
32
- }
33
-
34
- return (
35
- <div className="min-h-screen bg-gray-50">
36
- <div className="max-w-2xl mx-auto px-4 py-12">
37
- <h1 className="text-4xl font-bold text-gray-900 mb-2">Contact</h1>
38
- <p className="text-gray-600 mb-8">
39
- Have a question or want to work together? Drop me a message.
40
- </p>
41
-
42
- <form
43
- name="contact"
44
- method="POST"
45
- data-netlify="true"
46
- netlify-honeypot="bot-field"
47
- onSubmit={(e) => {
48
- e.preventDefault()
49
- const form = e.currentTarget
50
- const formData = new FormData(form)
51
- fetch('/', {
52
- method: 'POST',
53
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
54
- body: new URLSearchParams(formData as unknown as Record<string, string>).toString(),
55
- })
56
- .then(() => setSubmitted(true))
57
- .catch(() => setSubmitted(true))
58
- }}
59
- className="space-y-6"
60
- >
61
- <input type="hidden" name="form-name" value="contact" />
62
- <p hidden>
63
- <label>
64
- Don't fill this out: <input name="bot-field" />
65
- </label>
66
- </p>
67
-
68
- <div>
69
- <label htmlFor="name" className="block text-sm font-medium text-gray-700 mb-1">
70
- Name
71
- </label>
72
- <input
73
- type="text"
74
- id="name"
75
- name="name"
76
- required
77
- className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
78
- placeholder="Your name"
79
- />
80
- </div>
81
-
82
- <div>
83
- <label htmlFor="email" className="block text-sm font-medium text-gray-700 mb-1">
84
- Email
85
- </label>
86
- <input
87
- type="email"
88
- id="email"
89
- name="email"
90
- required
91
- className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
92
- placeholder="your@email.com"
93
- />
94
- </div>
95
-
96
- <div>
97
- <label htmlFor="message" className="block text-sm font-medium text-gray-700 mb-1">
98
- Message
99
- </label>
100
- <textarea
101
- id="message"
102
- name="message"
103
- required
104
- rows={6}
105
- className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors resize-none"
106
- placeholder="Your message..."
107
- />
108
- </div>
109
-
110
- <button
111
- type="submit"
112
- className="inline-flex items-center gap-2 px-6 py-3 bg-gray-900 text-white rounded-lg hover:bg-gray-800 transition-colors font-medium"
113
- >
114
- <Send size={16} />
115
- Send Message
116
- </button>
117
- </form>
118
- </div>
119
- </div>
120
- )
121
- }
@@ -1,55 +0,0 @@
1
- import { createFileRoute, Link } from '@tanstack/react-router'
2
- import { allBlogs } from 'content-collections'
3
- import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
4
- import { Badge } from '@/components/ui/badge'
5
- import { Calendar } from 'lucide-react'
6
-
7
- export const Route = createFileRoute('/')({
8
- component: BlogIndex,
9
- })
10
-
11
- function BlogIndex() {
12
- const posts = [...allBlogs].sort(
13
- (a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()
14
- )
15
-
16
- return (
17
- <div className="min-h-screen bg-gray-50">
18
- <div className="max-w-4xl mx-auto px-4 py-12">
19
- <h1 className="text-4xl font-bold text-gray-900 mb-2">Blog</h1>
20
- <p className="text-gray-600 mb-8">Thoughts on web development, design, and technology.</p>
21
-
22
- <div className="space-y-6">
23
- {posts.map((post) => (
24
- <Link
25
- key={post._meta.path}
26
- to="/blog/$slug"
27
- params={{ slug: post._meta.path }}
28
- className="block"
29
- >
30
- <Card className="hover:shadow-md transition-shadow cursor-pointer">
31
- <CardHeader>
32
- <CardTitle className="text-xl">{post.title}</CardTitle>
33
- <div className="flex items-center gap-2 text-sm text-gray-500">
34
- <Calendar size={14} />
35
- <time>{new Date(post.date).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })}</time>
36
- <span>·</span>
37
- <span>{post.author}</span>
38
- </div>
39
- </CardHeader>
40
- <CardContent>
41
- <p className="text-gray-600 mb-4">{post.summary}</p>
42
- <div className="flex flex-wrap gap-2">
43
- {post.tags.map((tag) => (
44
- <Badge key={tag} variant="secondary">{tag}</Badge>
45
- ))}
46
- </div>
47
- </CardContent>
48
- </Card>
49
- </Link>
50
- ))}
51
- </div>
52
- </div>
53
- </div>
54
- )
55
- }
@@ -1,62 +0,0 @@
1
- import { createFileRoute } from '@tanstack/react-router'
2
- import { allProjects } from 'content-collections'
3
- import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
4
- import { Badge } from '@/components/ui/badge'
5
- import { ExternalLink, Github } from 'lucide-react'
6
-
7
- export const Route = createFileRoute('/projects')({
8
- component: Projects,
9
- })
10
-
11
- function Projects() {
12
- return (
13
- <div className="min-h-screen bg-gray-50">
14
- <div className="max-w-4xl mx-auto px-4 py-12">
15
- <h1 className="text-4xl font-bold text-gray-900 mb-2">Projects</h1>
16
- <p className="text-gray-600 mb-8">A selection of projects I've built and contributed to.</p>
17
-
18
- <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
19
- {allProjects.map((project) => (
20
- <Card key={project._meta.path} className="flex flex-col">
21
- <CardHeader>
22
- <CardTitle className="text-xl">{project.title}</CardTitle>
23
- </CardHeader>
24
- <CardContent className="flex-1 flex flex-col">
25
- <p className="text-gray-600 mb-4 flex-1">{project.description}</p>
26
- <div className="flex flex-wrap gap-2 mb-4">
27
- {project.tags.map((tag) => (
28
- <Badge key={tag} variant="secondary">{tag}</Badge>
29
- ))}
30
- </div>
31
- <div className="flex gap-3">
32
- {project.github && (
33
- <a
34
- href={project.github}
35
- target="_blank"
36
- rel="noopener noreferrer"
37
- className="inline-flex items-center gap-2 text-sm text-gray-600 hover:text-gray-900 transition-colors"
38
- >
39
- <Github size={16} />
40
- GitHub
41
- </a>
42
- )}
43
- {project.liveUrl && (
44
- <a
45
- href={project.liveUrl}
46
- target="_blank"
47
- rel="noopener noreferrer"
48
- className="inline-flex items-center gap-2 text-sm text-blue-600 hover:text-blue-800 transition-colors"
49
- >
50
- <ExternalLink size={16} />
51
- Live Demo
52
- </a>
53
- )}
54
- </div>
55
- </CardContent>
56
- </Card>
57
- ))}
58
- </div>
59
- </div>
60
- </div>
61
- )
62
- }
@@ -1,220 +0,0 @@
1
- import { useState, useMemo } from 'react'
2
- import { marked } from 'marked'
3
-
4
- import { createFileRoute } from '@tanstack/react-router'
5
- import { allJobs, allEducations } from 'content-collections'
6
- import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
7
- import { Checkbox } from '@/components/ui/checkbox'
8
- import { Badge } from '@/components/ui/badge'
9
- import { Separator } from '@/components/ui/separator'
10
- import {
11
- HoverCard,
12
- HoverCardContent,
13
- HoverCardTrigger,
14
- } from '@/components/ui/hover-card'
15
-
16
- import ResumeAssistant from '@/components/ResumeAssistant'
17
-
18
- export const Route = createFileRoute('/resume')({
19
- component: App,
20
- })
21
-
22
- function App() {
23
- const [selectedTags, setSelectedTags] = useState<string[]>([])
24
-
25
- // Get unique tags from all jobs
26
- const allTags = useMemo(() => {
27
- const tags = new Set<string>()
28
- allJobs.forEach((job) => {
29
- job.tags.forEach((tag) => tags.add(tag))
30
- })
31
- return Array.from(tags).sort()
32
- }, [])
33
-
34
- // Filter jobs based on selected tags
35
- const filteredJobs = useMemo(() => {
36
- if (selectedTags.length === 0) return allJobs
37
- return allJobs.filter((job) =>
38
- selectedTags.some((tag) => job.tags.includes(tag)),
39
- )
40
- }, [selectedTags])
41
-
42
- return (
43
- <>
44
- <ResumeAssistant />
45
- <div className="min-h-screen bg-linear-to-b from-gray-50 to-gray-100">
46
- <div className="flex">
47
- {/* Sidebar with filters */}
48
- <div className="w-72 min-h-screen bg-white border-r shadow-sm p-8 sticky top-0">
49
- <h3 className="text-lg font-semibold mb-6 text-gray-900">
50
- Skills & Technologies
51
- </h3>
52
- <div className="space-y-4">
53
- {allTags.map((tag) => (
54
- <div key={tag} className="flex items-center space-x-3 group">
55
- <Checkbox
56
- id={tag}
57
- checked={selectedTags.includes(tag)}
58
- onCheckedChange={(checked) => {
59
- if (checked) {
60
- setSelectedTags([...selectedTags, tag])
61
- } else {
62
- setSelectedTags(selectedTags.filter((t) => t !== tag))
63
- }
64
- }}
65
- className="data-[state=checked]:bg-blue-600"
66
- />
67
- <label
68
- htmlFor={tag}
69
- className="text-sm font-medium leading-none text-gray-700 group-hover:text-gray-900 transition-colors cursor-pointer"
70
- >
71
- {tag}
72
- </label>
73
- </div>
74
- ))}
75
- </div>
76
- </div>
77
-
78
- {/* Main content */}
79
- <div className="flex-1 p-8 lg:p-12">
80
- <div className="max-w-4xl mx-auto space-y-12">
81
- <div className="text-center space-y-4">
82
- <h1 className="text-5xl font-bold bg-linear-to-r from-gray-900 via-gray-800 to-gray-900 bg-clip-text text-transparent">
83
- My Resume
84
- </h1>
85
- <p className="text-gray-600 text-lg">
86
- Professional Experience & Education
87
- </p>
88
- <Separator className="mt-8" />
89
- </div>
90
-
91
- {/* Career Summary */}
92
- <Card className="border-0 shadow-lg bg-white/50 backdrop-blur-sm">
93
- <CardHeader>
94
- <CardTitle className="text-2xl text-gray-900">
95
- Career Summary
96
- </CardTitle>
97
- </CardHeader>
98
- <CardContent>
99
- <div className="flex items-center gap-8">
100
- <p className="text-gray-700 flex-1 leading-relaxed">
101
- I am a passionate and driven professional seeking
102
- opportunities that will leverage my extensive experience
103
- in frontend development while providing continuous growth
104
- and learning opportunities. My goal is to contribute to
105
- innovative projects that challenge me to expand my skill
106
- set and make meaningful impacts through technology.
107
- </p>
108
- <img
109
- src="/headshot-on-white.jpg"
110
- alt="Professional headshot"
111
- className="w-44 h-52 rounded-2xl object-cover shadow-md transition-transform hover:scale-105"
112
- />
113
- </div>
114
- </CardContent>
115
- </Card>
116
-
117
- {/* Work Experience */}
118
- <section className="space-y-6">
119
- <h2 className="text-3xl font-semibold text-gray-900">
120
- Work Experience
121
- </h2>
122
- <div className="space-y-6">
123
- {filteredJobs.map((job) => (
124
- <Card
125
- key={job.jobTitle}
126
- className="border-0 shadow-md hover:shadow-lg transition-shadow"
127
- >
128
- <CardHeader>
129
- <div className="flex justify-between items-start">
130
- <div className="space-y-2">
131
- <CardTitle className="text-xl text-gray-900">
132
- {job.jobTitle}
133
- </CardTitle>
134
- <p className="text-blue-600 font-medium">
135
- {job.company} - {job.location}
136
- </p>
137
- </div>
138
- <Badge variant="secondary" className="text-sm">
139
- {job.startDate} - {job.endDate || 'Present'}
140
- </Badge>
141
- </div>
142
- </CardHeader>
143
- <CardContent>
144
- <p className="text-gray-700 mb-6 leading-relaxed">
145
- {job.summary}
146
- </p>
147
- <div className="flex flex-wrap gap-2">
148
- {job.tags.map((tag) => (
149
- <HoverCard key={tag}>
150
- <HoverCardTrigger>
151
- <Badge
152
- variant="outline"
153
- className="hover:bg-gray-100 transition-colors cursor-pointer"
154
- >
155
- {tag}
156
- </Badge>
157
- </HoverCardTrigger>
158
- <HoverCardContent className="w-64">
159
- <p className="text-sm text-gray-600">
160
- Experience with {tag} in professional
161
- development
162
- </p>
163
- </HoverCardContent>
164
- </HoverCard>
165
- ))}
166
- </div>
167
- {job.content && (
168
- <div
169
- className="mt-6 text-gray-700 prose prose-sm max-w-none"
170
- dangerouslySetInnerHTML={{
171
- __html: marked(job.content),
172
- }}
173
- />
174
- )}
175
- </CardContent>
176
- </Card>
177
- ))}
178
- </div>
179
- </section>
180
-
181
- {/* Education */}
182
- <section className="space-y-6">
183
- <h2 className="text-3xl font-semibold text-gray-900">
184
- Education
185
- </h2>
186
- <div className="space-y-6">
187
- {allEducations.map((education) => (
188
- <Card
189
- key={education.school}
190
- className="border-0 shadow-md hover:shadow-lg transition-shadow"
191
- >
192
- <CardHeader>
193
- <CardTitle className="text-xl text-gray-900">
194
- {education.school}
195
- </CardTitle>
196
- </CardHeader>
197
- <CardContent>
198
- <p className="text-gray-700 leading-relaxed">
199
- {education.summary}
200
- </p>
201
- {education.content && (
202
- <div
203
- className="mt-6 text-gray-700 prose prose-sm max-w-none"
204
- dangerouslySetInnerHTML={{
205
- __html: marked(education.content),
206
- }}
207
- />
208
- )}
209
- </CardContent>
210
- </Card>
211
- ))}
212
- </div>
213
- </section>
214
- </div>
215
- </div>
216
- </div>
217
- </div>
218
- </>
219
- )
220
- }
@@ -1,138 +0,0 @@
1
- @import 'tailwindcss';
2
-
3
- @plugin "tailwindcss-animate";
4
-
5
- @custom-variant dark (&:is(.dark *));
6
-
7
- body {
8
- @apply m-0;
9
- font-family:
10
- -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
11
- 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
12
- -webkit-font-smoothing: antialiased;
13
- -moz-osx-font-smoothing: grayscale;
14
- }
15
-
16
- code {
17
- font-family:
18
- source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
19
- }
20
-
21
- :root {
22
- --background: oklch(1 0 0);
23
- --foreground: oklch(0.141 0.005 285.823);
24
- --card: oklch(1 0 0);
25
- --card-foreground: oklch(0.141 0.005 285.823);
26
- --popover: oklch(1 0 0);
27
- --popover-foreground: oklch(0.141 0.005 285.823);
28
- --primary: oklch(0.21 0.006 285.885);
29
- --primary-foreground: oklch(0.985 0 0);
30
- --secondary: oklch(0.967 0.001 286.375);
31
- --secondary-foreground: oklch(0.21 0.006 285.885);
32
- --muted: oklch(0.967 0.001 286.375);
33
- --muted-foreground: oklch(0.552 0.016 285.938);
34
- --accent: oklch(0.967 0.001 286.375);
35
- --accent-foreground: oklch(0.21 0.006 285.885);
36
- --destructive: oklch(0.577 0.245 27.325);
37
- --destructive-foreground: oklch(0.577 0.245 27.325);
38
- --border: oklch(0.92 0.004 286.32);
39
- --input: oklch(0.92 0.004 286.32);
40
- --ring: oklch(0.871 0.006 286.286);
41
- --chart-1: oklch(0.646 0.222 41.116);
42
- --chart-2: oklch(0.6 0.118 184.704);
43
- --chart-3: oklch(0.398 0.07 227.392);
44
- --chart-4: oklch(0.828 0.189 84.429);
45
- --chart-5: oklch(0.769 0.188 70.08);
46
- --radius: 0.625rem;
47
- --sidebar: oklch(0.985 0 0);
48
- --sidebar-foreground: oklch(0.141 0.005 285.823);
49
- --sidebar-primary: oklch(0.21 0.006 285.885);
50
- --sidebar-primary-foreground: oklch(0.985 0 0);
51
- --sidebar-accent: oklch(0.967 0.001 286.375);
52
- --sidebar-accent-foreground: oklch(0.21 0.006 285.885);
53
- --sidebar-border: oklch(0.92 0.004 286.32);
54
- --sidebar-ring: oklch(0.871 0.006 286.286);
55
- }
56
-
57
- .dark {
58
- --background: oklch(0.141 0.005 285.823);
59
- --foreground: oklch(0.985 0 0);
60
- --card: oklch(0.141 0.005 285.823);
61
- --card-foreground: oklch(0.985 0 0);
62
- --popover: oklch(0.141 0.005 285.823);
63
- --popover-foreground: oklch(0.985 0 0);
64
- --primary: oklch(0.985 0 0);
65
- --primary-foreground: oklch(0.21 0.006 285.885);
66
- --secondary: oklch(0.274 0.006 286.033);
67
- --secondary-foreground: oklch(0.985 0 0);
68
- --muted: oklch(0.274 0.006 286.033);
69
- --muted-foreground: oklch(0.705 0.015 286.067);
70
- --accent: oklch(0.274 0.006 286.033);
71
- --accent-foreground: oklch(0.985 0 0);
72
- --destructive: oklch(0.396 0.141 25.723);
73
- --destructive-foreground: oklch(0.637 0.237 25.331);
74
- --border: oklch(0.274 0.006 286.033);
75
- --input: oklch(0.274 0.006 286.033);
76
- --ring: oklch(0.442 0.017 285.786);
77
- --chart-1: oklch(0.488 0.243 264.376);
78
- --chart-2: oklch(0.696 0.17 162.48);
79
- --chart-3: oklch(0.769 0.188 70.08);
80
- --chart-4: oklch(0.627 0.265 303.9);
81
- --chart-5: oklch(0.645 0.246 16.439);
82
- --sidebar: oklch(0.21 0.006 285.885);
83
- --sidebar-foreground: oklch(0.985 0 0);
84
- --sidebar-primary: oklch(0.488 0.243 264.376);
85
- --sidebar-primary-foreground: oklch(0.985 0 0);
86
- --sidebar-accent: oklch(0.274 0.006 286.033);
87
- --sidebar-accent-foreground: oklch(0.985 0 0);
88
- --sidebar-border: oklch(0.274 0.006 286.033);
89
- --sidebar-ring: oklch(0.442 0.017 285.786);
90
- }
91
-
92
- @theme inline {
93
- --color-background: var(--background);
94
- --color-foreground: var(--foreground);
95
- --color-card: var(--card);
96
- --color-card-foreground: var(--card-foreground);
97
- --color-popover: var(--popover);
98
- --color-popover-foreground: var(--popover-foreground);
99
- --color-primary: var(--primary);
100
- --color-primary-foreground: var(--primary-foreground);
101
- --color-secondary: var(--secondary);
102
- --color-secondary-foreground: var(--secondary-foreground);
103
- --color-muted: var(--muted);
104
- --color-muted-foreground: var(--muted-foreground);
105
- --color-accent: var(--accent);
106
- --color-accent-foreground: var(--accent-foreground);
107
- --color-destructive: var(--destructive);
108
- --color-destructive-foreground: var(--destructive-foreground);
109
- --color-border: var(--border);
110
- --color-input: var(--input);
111
- --color-ring: var(--ring);
112
- --color-chart-1: var(--chart-1);
113
- --color-chart-2: var(--chart-2);
114
- --color-chart-3: var(--chart-3);
115
- --color-chart-4: var(--chart-4);
116
- --color-chart-5: var(--chart-5);
117
- --radius-sm: calc(var(--radius) - 4px);
118
- --radius-md: calc(var(--radius) - 2px);
119
- --radius-lg: var(--radius);
120
- --radius-xl: calc(var(--radius) + 4px);
121
- --color-sidebar: var(--sidebar);
122
- --color-sidebar-foreground: var(--sidebar-foreground);
123
- --color-sidebar-primary: var(--sidebar-primary);
124
- --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
125
- --color-sidebar-accent: var(--sidebar-accent);
126
- --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
127
- --color-sidebar-border: var(--sidebar-border);
128
- --color-sidebar-ring: var(--sidebar-ring);
129
- }
130
-
131
- @layer base {
132
- * {
133
- @apply border-border outline-ring/50;
134
- }
135
- body {
136
- @apply bg-background text-foreground;
137
- }
138
- }
@@ -1,50 +0,0 @@
1
- {
2
- "name": "Portfolio",
3
- "description": "A developer portfolio with resume, blog, projects, and AI assistant built with content-collections and TanStack Start for Netlify.",
4
- "phase": "example",
5
- "modes": ["file-router"],
6
- "type": "example",
7
- "priority": 10,
8
- "link": "",
9
- "routes": [
10
- {"url": "/", "path": "src/routes/index.tsx", "jsName": "BlogIndex"},
11
- {"url": "/resume", "name": "Resume", "icon": "FileText", "path": "src/routes/resume.tsx", "jsName": "Resume"},
12
- {"url": "/projects", "name": "Projects", "icon": "FolderGit2", "path": "src/routes/projects.tsx", "jsName": "Projects"},
13
- {"url": "/contact", "name": "Contact", "icon": "Mail", "path": "src/routes/contact.tsx", "jsName": "Contact"},
14
- {"url": "/blog/$slug", "path": "src/routes/blog/$slug.tsx", "jsName": "BlogPost"},
15
- {"url": "/api/resume-chat", "path": "src/routes/api.resume-chat.ts", "jsName": "ResumeChatAPI"}
16
- ],
17
- "features": ["tanstack-start", "content-collections", "netlify-forms"],
18
- "integrations": [{"type": "vite-plugin", "import": "import contentCollections from '@content-collections/vite'", "code": "contentCollections()"}],
19
- "dependsOn": [],
20
- "variables": [],
21
- "packageFileDescriptions": {
22
- "content-collections.ts": "Content Collections: jobs, education, blog, projects schemas.",
23
- "content/jobs/initech-junior.md": "Job content: Initech Junior.",
24
- "content/education/code-school.md": "Education content: Code School.",
25
- "content/blog/getting-started-with-tanstack.md": "Blog post.",
26
- "content/blog/react-19-features.md": "Blog post.",
27
- "content/blog/tailwind-css-v4-guide.md": "Blog post.",
28
- "content/projects/portfolio-site.md": "Project content.",
29
- "content/projects/task-manager.md": "Project content.",
30
- "src/styles.css": "Global styles.",
31
- "src/routes/index.tsx": "Portfolio home: blog index.",
32
- "src/routes/resume.tsx": "Resume page with ResumeAssistant.",
33
- "src/routes/projects.tsx": "Projects page.",
34
- "src/routes/contact.tsx": "Contact page.",
35
- "src/routes/blog/$slug.tsx": "Blog post detail.",
36
- "src/routes/api.resume-chat.ts": "POST handler for resume AI chat with getJobsBySkill, getAllJobs, etc.",
37
- "src/routes/__root.tsx": "Root layout.",
38
- "src/lib/utils.ts": "cn() helper.",
39
- "src/lib/resume-tools.ts": "AI tools: getJobsBySkill, getAllJobs, getAllEducation, searchExperience.",
40
- "src/lib/resume-ai-hook.ts": "useResumeChat hook.",
41
- "src/components/Header.tsx": "Header.",
42
- "src/components/ResumeAssistant.tsx": "Resume AI assistant.",
43
- "src/components/ui/badge.tsx": "Badge component.",
44
- "src/components/ui/card.tsx": "Card component.",
45
- "src/components/ui/checkbox.tsx": "Checkbox component.",
46
- "src/components/ui/hover-card.tsx": "HoverCard component.",
47
- "src/components/ui/separator.tsx": "Separator component.",
48
- "public/contact.html": "Static contact form."
49
- }
50
- }
@@ -1,26 +0,0 @@
1
- {
2
- "dependencies": {
3
- "@radix-ui/react-checkbox": "^1.2.2",
4
- "@radix-ui/react-hover-card": "^1.1.10",
5
- "@radix-ui/react-separator": "^1.1.4",
6
- "@radix-ui/react-slot": "^1.2.0",
7
- "@tanstack/ai": "0.2.2",
8
- "@tanstack/ai-anthropic": "0.2.0",
9
- "@tanstack/ai-client": "0.2.2",
10
- "@tanstack/ai-gemini": "0.3.2",
11
- "@tanstack/ai-ollama": "0.3.0",
12
- "@tanstack/ai-openai": "0.3.0",
13
- "@tanstack/ai-react": "0.2.2",
14
- "class-variance-authority": "^0.7.1",
15
- "clsx": "^2.1.1",
16
- "marked": "^17.0.1",
17
- "streamdown": "^2.1.0",
18
- "tailwind-merge": "^3.0.2",
19
- "tailwindcss-animate": "^1.0.7",
20
- "zod": "^4.3.5"
21
- },
22
- "devDependencies": {
23
- "@content-collections/core": "^0.13.1",
24
- "@content-collections/vite": "^0.2.8"
25
- }
26
- }