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.
- package/dist/cli.js +104 -208
- package/dist/index.js +1 -31
- package/dist/types/cli.d.ts +1 -8
- package/dist/types/types.d.ts +7 -12
- package/package.json +1 -2
- package/src/cli.ts +129 -271
- package/src/index.ts +1 -47
- package/src/types.ts +7 -13
- package/CONTEXT.md +0 -139
- package/add-ons/ai/README.md +0 -34
- package/add-ons/ai/assets/AGENTS.md.append +0 -24
- package/add-ons/ai/assets/_dot_env.local.append +0 -13
- package/add-ons/ai/assets/src/components/AIAssistant.tsx +0 -149
- package/add-ons/ai/assets/src/lib/ai-hook.ts +0 -21
- package/add-ons/ai/assets/src/lib/weather-tools.ts +0 -30
- package/add-ons/ai/assets/src/routes/api.chat.ts +0 -94
- package/add-ons/ai/assets/src/routes/chat.css +0 -175
- package/add-ons/ai/assets/src/routes/chat.tsx +0 -141
- package/add-ons/ai/info.json +0 -22
- package/add-ons/ai/package.json +0 -17
- package/add-ons/ai/small-logo.svg +0 -8
- package/add-ons/db/assets/AGENTS.md.append +0 -22
- package/add-ons/db/assets/DB-SETUP.md +0 -65
- package/add-ons/db/assets/_dot_env.local.append +0 -2
- package/add-ons/db/assets/drizzle.config.ts +0 -10
- package/add-ons/db/assets/src/db/index.ts +0 -8
- package/add-ons/db/assets/src/db/schema.ts +0 -8
- package/add-ons/db/assets/src/routes/db-example.tsx +0 -118
- package/add-ons/db/assets/src/server/guestbook.functions.ts +0 -23
- package/add-ons/db/info.json +0 -22
- package/add-ons/db/package.json +0 -10
- package/add-ons/forms/assets/AGENTS.md.append +0 -13
- package/add-ons/forms/assets/public/form-example.html +0 -14
- package/add-ons/forms/assets/src/routes/form-example.tsx +0 -76
- package/add-ons/forms/info.json +0 -18
- package/add-ons/forms/package.json +0 -3
- package/examples/ai-chat/README.md +0 -36
- package/examples/ai-chat/assets/AGENTS.md.append +0 -24
- package/examples/ai-chat/assets/src/lib/ai-hook.ts +0 -21
- package/examples/ai-chat/assets/src/lib/weather-tools.ts +0 -30
- package/examples/ai-chat/assets/src/routes/__root.tsx +0 -57
- package/examples/ai-chat/assets/src/routes/api.chat.ts +0 -94
- package/examples/ai-chat/assets/src/routes/index.tsx +0 -141
- package/examples/ai-chat/assets/src/styles.css +0 -165
- package/examples/ai-chat/info.json +0 -25
- package/examples/ai-chat/package.json +0 -14
- package/examples/blog/README.md +0 -60
- package/examples/blog/assets/AGENTS.md.append +0 -18
- package/examples/blog/assets/content/posts/beach.md +0 -12
- package/examples/blog/assets/content/posts/jungle.md.ejs +0 -12
- package/examples/blog/assets/content/posts/mountains.md.ejs +0 -12
- package/examples/blog/assets/content/posts/snorkeling.md.ejs +0 -12
- package/examples/blog/assets/content/posts/waterfall.md.ejs +0 -12
- package/examples/blog/assets/content-collections.ts +0 -30
- package/examples/blog/assets/public/beach.jpg +0 -0
- package/examples/blog/assets/public/jungle.jpg +0 -0
- package/examples/blog/assets/public/mountains.jpg +0 -0
- package/examples/blog/assets/public/snorkeling.jpg +0 -0
- package/examples/blog/assets/public/waterfall.jpg +0 -0
- package/examples/blog/assets/src/components/Header.tsx +0 -52
- package/examples/blog/assets/src/components/VacayAssistant.tsx +0 -205
- package/examples/blog/assets/src/components/blog-posts.tsx +0 -78
- package/examples/blog/assets/src/components/ui/card.tsx +0 -92
- package/examples/blog/assets/src/lib/blog-ai-hook.ts +0 -25
- package/examples/blog/assets/src/lib/blog-tools.ts +0 -111
- package/examples/blog/assets/src/lib/utils.ts +0 -6
- package/examples/blog/assets/src/routes/__root.tsx +0 -57
- package/examples/blog/assets/src/routes/api.blog-chat.ts +0 -117
- package/examples/blog/assets/src/routes/category.$category.tsx +0 -19
- package/examples/blog/assets/src/routes/index.tsx +0 -19
- package/examples/blog/assets/src/routes/posts.$slug.tsx +0 -63
- package/examples/blog/assets/src/styles.css +0 -138
- package/examples/blog/info.json +0 -40
- package/examples/blog/package.json +0 -23
- package/examples/calculator/README.md +0 -16
- package/examples/calculator/assets/AGENTS.md.append +0 -9
- package/examples/calculator/assets/src/components/Calculator.tsx +0 -238
- package/examples/calculator/assets/src/components/Header.tsx +0 -17
- package/examples/calculator/assets/src/routes/__root.tsx +0 -57
- package/examples/calculator/assets/src/routes/index.tsx +0 -14
- package/examples/calculator/info.json +0 -20
- package/examples/calculator/package.json +0 -1
- package/examples/dashboard/README.md +0 -17
- package/examples/dashboard/assets/AGENTS.md.append +0 -12
- package/examples/dashboard/assets/src/components/Header.tsx +0 -17
- package/examples/dashboard/assets/src/routes/__root.tsx +0 -57
- package/examples/dashboard/assets/src/routes/index.tsx +0 -158
- package/examples/dashboard/info.json +0 -19
- package/examples/dashboard/package.json +0 -6
- package/examples/ecommerce/README.md +0 -48
- package/examples/ecommerce/assets/AGENTS.md.append +0 -22
- package/examples/ecommerce/assets/public/logo.png +0 -0
- package/examples/ecommerce/assets/public/motorcycle-scooter.jpg +0 -0
- package/examples/ecommerce/assets/src/components/BuyButton.tsx +0 -35
- package/examples/ecommerce/assets/src/components/Header.tsx +0 -36
- package/examples/ecommerce/assets/src/components/MotorcycleAIAssistant.tsx +0 -162
- package/examples/ecommerce/assets/src/components/MotorcycleRecommendation.tsx +0 -53
- package/examples/ecommerce/assets/src/data/motorcycles.ts +0 -27
- package/examples/ecommerce/assets/src/lib/motorcycle-ai-hook.ts +0 -24
- package/examples/ecommerce/assets/src/lib/motorcycle-tools.ts +0 -42
- package/examples/ecommerce/assets/src/lib/stripe.server.ts +0 -39
- package/examples/ecommerce/assets/src/routes/__root.tsx +0 -57
- package/examples/ecommerce/assets/src/routes/api.motorcycle-chat.ts +0 -78
- package/examples/ecommerce/assets/src/routes/checkout/cancel.tsx +0 -25
- package/examples/ecommerce/assets/src/routes/checkout/success.tsx +0 -25
- package/examples/ecommerce/assets/src/routes/index.tsx +0 -76
- package/examples/ecommerce/assets/src/routes/motorcycles/$motorcycleId.tsx +0 -55
- package/examples/ecommerce/assets/src/store/motorcycle-assistant.ts +0 -3
- package/examples/ecommerce/assets/src/styles.css +0 -212
- package/examples/ecommerce/info.json +0 -38
- package/examples/ecommerce/package.json +0 -13
- package/examples/events/README.md +0 -110
- package/examples/events/assets/AGENTS.md.append +0 -21
- package/examples/events/assets/content/speakers/andre-costa.md +0 -22
- package/examples/events/assets/content/speakers/hans-mueller.md.ejs +0 -22
- package/examples/events/assets/content/speakers/isabella-martinez.md.ejs +0 -22
- package/examples/events/assets/content/speakers/kenji-nakamura.md.ejs +0 -22
- package/examples/events/assets/content/speakers/marie-dubois.md.ejs +0 -20
- package/examples/events/assets/content/speakers/priya-sharma.md.ejs +0 -22
- package/examples/events/assets/content/talks/croissant-lamination-secrets.md +0 -39
- package/examples/events/assets/content/talks/french-macaron-mastery.md.ejs +0 -39
- package/examples/events/assets/content/talks/neapolitan-pizza-tradition-meets-innovation.md.ejs +0 -39
- package/examples/events/assets/content/talks/savory-breads-of-the-mediterranean.md.ejs +0 -39
- package/examples/events/assets/content/talks/sourdough-from-starter-to-masterpiece.md.ejs +0 -36
- package/examples/events/assets/content/talks/the-art-of-the-perfect-tart.md.ejs +0 -32
- package/examples/events/assets/content/talks/the-science-of-sugar.md.ejs +0 -39
- package/examples/events/assets/content/talks/umami-in-pastry-east-meets-west.md.ejs +0 -39
- package/examples/events/assets/content-collections.ts +0 -56
- package/examples/events/assets/public/background-1.jpg +0 -0
- package/examples/events/assets/public/background-2.jpg +0 -0
- package/examples/events/assets/public/background-3.jpg +0 -0
- package/examples/events/assets/public/background-4.jpg +0 -0
- package/examples/events/assets/public/conference-logo.png +0 -0
- package/examples/events/assets/public/favicon.ico +0 -0
- package/examples/events/assets/public/speakers/andre-costa.jpg +0 -0
- package/examples/events/assets/public/speakers/hans-mueller.jpg +0 -0
- package/examples/events/assets/public/speakers/isabella-martinez.jpg +0 -0
- package/examples/events/assets/public/speakers/kenji-nakamura.jpg +0 -0
- package/examples/events/assets/public/speakers/marie-dubois.jpg +0 -0
- package/examples/events/assets/public/speakers/priya-sharma.jpg +0 -0
- package/examples/events/assets/public/talks/croissant-lamination-secrets.jpg +0 -0
- package/examples/events/assets/public/talks/french-macaron-mastery.jpg +0 -0
- package/examples/events/assets/public/talks/neapolitan-pizza-tradition-meets-innovation.jpg +0 -0
- package/examples/events/assets/public/talks/savory-breads-of-the-mediterranean.jpg +0 -0
- package/examples/events/assets/public/talks/sourdough-from-starter-to-masterpiece.jpg +0 -0
- package/examples/events/assets/public/talks/the-art-of-the-perfect-tart.jpg +0 -0
- package/examples/events/assets/public/talks/the-science-of-sugar.jpg +0 -0
- package/examples/events/assets/public/talks/umami-in-pastry-east-meets-west.jpg +0 -0
- package/examples/events/assets/public/tanstack-circle-logo.png +0 -0
- package/examples/events/assets/public/tanstack-word-logo-white.svg +0 -1
- package/examples/events/assets/src/components/Header.tsx +0 -59
- package/examples/events/assets/src/components/HeaderNav.tsx +0 -67
- package/examples/events/assets/src/components/HeroCarousel.tsx +0 -61
- package/examples/events/assets/src/components/RemyAssistant.tsx +0 -207
- package/examples/events/assets/src/components/SpeakerCard.tsx +0 -67
- package/examples/events/assets/src/components/TalkCard.tsx +0 -77
- package/examples/events/assets/src/components/ui/card.tsx +0 -92
- package/examples/events/assets/src/lib/conference-ai-hook.ts +0 -26
- package/examples/events/assets/src/lib/conference-tools.ts +0 -210
- package/examples/events/assets/src/lib/model-selection.ts +0 -1
- package/examples/events/assets/src/lib/utils.ts +0 -6
- package/examples/events/assets/src/routes/__root.tsx +0 -70
- package/examples/events/assets/src/routes/api.remy-chat.ts +0 -119
- package/examples/events/assets/src/routes/index.tsx +0 -192
- package/examples/events/assets/src/routes/schedule.index.tsx +0 -274
- package/examples/events/assets/src/routes/speakers.$slug.tsx +0 -122
- package/examples/events/assets/src/routes/speakers.index.tsx +0 -40
- package/examples/events/assets/src/routes/talks.$slug.tsx +0 -116
- package/examples/events/assets/src/routes/talks.index.tsx +0 -40
- package/examples/events/assets/src/styles.css +0 -182
- package/examples/events/info.json +0 -61
- package/examples/events/package.json +0 -23
- package/examples/marketing/README.md +0 -60
- package/examples/marketing/assets/AGENTS.md.append +0 -15
- package/examples/marketing/assets/public/logo.png +0 -0
- package/examples/marketing/assets/public/motorcycle-adventure.jpg +0 -0
- package/examples/marketing/assets/public/motorcycle-cruiser.jpg +0 -0
- package/examples/marketing/assets/public/motorcycle-scooter.jpg +0 -0
- package/examples/marketing/assets/public/motorcycle-sport.jpg +0 -0
- package/examples/marketing/assets/public/motorcycle-supersport.jpg +0 -0
- package/examples/marketing/assets/src/components/Header.tsx +0 -36
- package/examples/marketing/assets/src/components/MotorcycleAIAssistant.tsx +0 -162
- package/examples/marketing/assets/src/components/MotorcycleRecommendation.tsx +0 -53
- package/examples/marketing/assets/src/data/motorcycles.ts.ejs +0 -77
- package/examples/marketing/assets/src/lib/motorcycle-ai-hook.ts +0 -24
- package/examples/marketing/assets/src/lib/motorcycle-tools.ts +0 -42
- package/examples/marketing/assets/src/routes/__root.tsx +0 -57
- package/examples/marketing/assets/src/routes/api.motorcycle-chat.ts +0 -78
- package/examples/marketing/assets/src/routes/index.tsx +0 -72
- package/examples/marketing/assets/src/routes/motorcycles/$motorcycleId.tsx +0 -56
- package/examples/marketing/assets/src/store/motorcycle-assistant.ts +0 -3
- package/examples/marketing/assets/src/styles.css +0 -212
- package/examples/marketing/info.json +0 -33
- package/examples/marketing/package.json +0 -14
- package/examples/portfolio/README.md +0 -49
- package/examples/portfolio/assets/AGENTS.md.append +0 -21
- package/examples/portfolio/assets/content/blog/getting-started-with-tanstack.md +0 -53
- package/examples/portfolio/assets/content/blog/react-19-features.md +0 -78
- package/examples/portfolio/assets/content/blog/tailwind-css-v4-guide.md +0 -60
- package/examples/portfolio/assets/content/education/code-school.md +0 -17
- package/examples/portfolio/assets/content/jobs/initech-junior.md +0 -20
- package/examples/portfolio/assets/content/projects/portfolio-site.md +0 -15
- package/examples/portfolio/assets/content/projects/task-manager.md +0 -15
- package/examples/portfolio/assets/content-collections.ts +0 -65
- package/examples/portfolio/assets/public/contact.html +0 -6
- package/examples/portfolio/assets/public/headshot-on-white.jpg +0 -0
- package/examples/portfolio/assets/src/components/Header.tsx +0 -33
- package/examples/portfolio/assets/src/components/ResumeAssistant.tsx +0 -193
- package/examples/portfolio/assets/src/components/ui/badge.tsx +0 -46
- package/examples/portfolio/assets/src/components/ui/card.tsx +0 -92
- package/examples/portfolio/assets/src/components/ui/checkbox.tsx +0 -30
- package/examples/portfolio/assets/src/components/ui/hover-card.tsx +0 -44
- package/examples/portfolio/assets/src/components/ui/separator.tsx +0 -26
- package/examples/portfolio/assets/src/lib/resume-ai-hook.ts +0 -21
- package/examples/portfolio/assets/src/lib/resume-tools.ts +0 -165
- package/examples/portfolio/assets/src/lib/utils.ts +0 -6
- package/examples/portfolio/assets/src/routes/__root.tsx +0 -57
- package/examples/portfolio/assets/src/routes/api.resume-chat.ts +0 -116
- package/examples/portfolio/assets/src/routes/blog/$slug.tsx +0 -73
- package/examples/portfolio/assets/src/routes/contact.tsx +0 -121
- package/examples/portfolio/assets/src/routes/index.tsx +0 -55
- package/examples/portfolio/assets/src/routes/projects.tsx +0 -62
- package/examples/portfolio/assets/src/routes/resume.tsx +0 -220
- package/examples/portfolio/assets/src/styles.css +0 -138
- package/examples/portfolio/info.json +0 -50
- package/examples/portfolio/package.json +0 -26
- package/examples/resume/README.md +0 -82
- package/examples/resume/assets/AGENTS.md.append +0 -19
- package/examples/resume/assets/content/education/code-school.md +0 -17
- package/examples/resume/assets/content/jobs/freelance.md.ejs +0 -13
- package/examples/resume/assets/content/jobs/initech-junior.md +0 -20
- package/examples/resume/assets/content/jobs/initech-lead.md.ejs +0 -29
- package/examples/resume/assets/content/jobs/initrode-senior.md.ejs +0 -28
- package/examples/resume/assets/content-collections.ts +0 -36
- package/examples/resume/assets/public/headshot-on-white.jpg +0 -0
- package/examples/resume/assets/src/components/Header.tsx +0 -33
- package/examples/resume/assets/src/components/ResumeAssistant.tsx +0 -193
- package/examples/resume/assets/src/components/ui/badge.tsx +0 -46
- package/examples/resume/assets/src/components/ui/card.tsx +0 -92
- package/examples/resume/assets/src/components/ui/checkbox.tsx +0 -30
- package/examples/resume/assets/src/components/ui/hover-card.tsx +0 -44
- package/examples/resume/assets/src/components/ui/separator.tsx +0 -26
- package/examples/resume/assets/src/lib/resume-ai-hook.ts +0 -21
- package/examples/resume/assets/src/lib/resume-tools.ts +0 -165
- package/examples/resume/assets/src/lib/utils.ts +0 -6
- package/examples/resume/assets/src/routes/api.resume-chat.ts +0 -110
- package/examples/resume/assets/src/routes/index.tsx +0 -220
- package/examples/resume/assets/src/styles.css +0 -138
- package/examples/resume/info.json +0 -35
- package/examples/resume/package.json +0 -26
- package/examples/saas/README.md +0 -16
- package/examples/saas/assets/AGENTS.md.append +0 -9
- package/examples/saas/assets/src/components/Header.tsx +0 -17
- package/examples/saas/assets/src/routes/__root.tsx +0 -57
- package/examples/saas/assets/src/routes/faq.tsx +0 -94
- package/examples/saas/assets/src/routes/index.tsx +0 -197
- package/examples/saas/info.json +0 -23
- package/examples/saas/package.json +0 -1
- package/examples/survey/README.md +0 -20
- package/examples/survey/assets/AGENTS.md.append +0 -9
- package/examples/survey/assets/public/form-survey.html +0 -15
- package/examples/survey/assets/src/components/SurveyForm.tsx +0 -128
- package/examples/survey/assets/src/routes/index.tsx +0 -14
- package/examples/survey/info.json +0 -19
- package/examples/survey/package.json +0 -1
- package/project/base/AGENTS.md +0 -86
- package/project/base/_dot_claude/skills/content-collections/SKILL.md +0 -505
- package/project/base/_dot_claude/skills/netlify-blobs/SKILL.md +0 -410
- package/project/base/_dot_claude/skills/netlify-db/SKILL.md +0 -424
- package/project/base/_dot_claude/skills/netlify-debugging/SKILL.md +0 -419
- package/project/base/_dot_claude/skills/netlify-forms/SKILL.md +0 -243
- package/project/base/_dot_claude/skills/netlify-functions/SKILL.md +0 -372
- package/project/base/_dot_claude/skills/tanstack-start-api-routes/SKILL.md +0 -421
- package/project/base/_dot_claude/skills/tanstack-start-loaders/SKILL.md +0 -426
- package/project/base/_dot_claude/skills/tanstack-start-project-setup/SKILL.md +0 -493
- package/project/base/_dot_claude/skills/tanstack-start-routes/SKILL.md +0 -430
- package/project/base/_dot_claude/skills/tanstack-start-server-functions/SKILL.md +0 -445
- package/project/base/_dot_claude/skills/tanstack-start-typesafe-routing/SKILL.md +0 -494
- package/project/base/_dot_gitignore +0 -8
- package/project/base/netlify.toml +0 -7
- package/project/base/package.json +0 -33
- package/project/base/public/favicon.ico +0 -0
- package/project/base/public/tanstack-circle-logo.png +0 -0
- package/project/base/public/tanstack-word-logo-white.svg +0 -1
- package/project/base/src/components/Header.tsx +0 -17
- package/project/base/src/components/HeaderNav.tsx.ejs +0 -179
- package/project/base/src/router.tsx +0 -15
- package/project/base/src/routes/__root.tsx +0 -57
- package/project/base/src/routes/index.tsx +0 -48
- package/project/base/src/styles.css +0 -15
- package/project/base/tsconfig.json +0 -28
- package/project/base/vite.config.ts.ejs +0 -25
- package/project/info.json +0 -17
- package/project/packages.json +0 -22
- package/scripts/check-outdated-packages.js +0 -421
- 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
|
-
}
|