kaddidlehopper 0.1.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/CONTEXT.md +139 -0
- package/README.md +47 -0
- package/add-ons/ai/README.md +34 -0
- package/add-ons/ai/assets/_dot_env.local.append +13 -0
- package/add-ons/ai/assets/src/components/AIAssistant.tsx +149 -0
- package/add-ons/ai/assets/src/lib/ai-hook.ts +21 -0
- package/add-ons/ai/assets/src/lib/weather-tools.ts +30 -0
- package/add-ons/ai/assets/src/routes/api.chat.ts +94 -0
- package/add-ons/ai/assets/src/routes/chat.css +175 -0
- package/add-ons/ai/assets/src/routes/chat.tsx +141 -0
- package/add-ons/ai/info.json +27 -0
- package/add-ons/ai/package.json +17 -0
- package/add-ons/ai/small-logo.svg +8 -0
- package/dist/cli.js +251 -0
- package/dist/index.js +33 -0
- package/dist/types/cli.d.ts +8 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/types.d.ts +14 -0
- package/dist/types.js +1 -0
- package/examples/blog/README.md +60 -0
- package/examples/blog/assets/content/posts/beach.md +12 -0
- package/examples/blog/assets/content/posts/jungle.md.ejs +12 -0
- package/examples/blog/assets/content/posts/mountains.md.ejs +12 -0
- package/examples/blog/assets/content/posts/snorkeling.md.ejs +12 -0
- package/examples/blog/assets/content/posts/waterfall.md.ejs +12 -0
- package/examples/blog/assets/content-collections.ts +30 -0
- 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 +52 -0
- package/examples/blog/assets/src/components/VacayAssistant.tsx +205 -0
- package/examples/blog/assets/src/components/blog-posts.tsx +78 -0
- package/examples/blog/assets/src/components/ui/card.tsx +92 -0
- package/examples/blog/assets/src/lib/blog-ai-hook.ts +25 -0
- package/examples/blog/assets/src/lib/blog-tools.ts +111 -0
- package/examples/blog/assets/src/lib/utils.ts +6 -0
- package/examples/blog/assets/src/routes/__root.tsx +57 -0
- package/examples/blog/assets/src/routes/api.blog-chat.ts +117 -0
- package/examples/blog/assets/src/routes/category.$category.tsx +19 -0
- package/examples/blog/assets/src/routes/index.tsx +19 -0
- package/examples/blog/assets/src/routes/posts.$slug.tsx +63 -0
- package/examples/blog/assets/src/styles.css +138 -0
- package/examples/blog/info.json +43 -0
- package/examples/blog/package.json +23 -0
- package/examples/events/README.md +110 -0
- package/examples/events/assets/content/speakers/andre-costa.md +22 -0
- package/examples/events/assets/content/speakers/hans-mueller.md.ejs +22 -0
- package/examples/events/assets/content/speakers/isabella-martinez.md.ejs +22 -0
- package/examples/events/assets/content/speakers/kenji-nakamura.md.ejs +22 -0
- package/examples/events/assets/content/speakers/marie-dubois.md.ejs +20 -0
- package/examples/events/assets/content/speakers/priya-sharma.md.ejs +22 -0
- package/examples/events/assets/content/talks/croissant-lamination-secrets.md +39 -0
- package/examples/events/assets/content/talks/french-macaron-mastery.md.ejs +39 -0
- package/examples/events/assets/content/talks/neapolitan-pizza-tradition-meets-innovation.md.ejs +39 -0
- package/examples/events/assets/content/talks/savory-breads-of-the-mediterranean.md.ejs +39 -0
- package/examples/events/assets/content/talks/sourdough-from-starter-to-masterpiece.md.ejs +36 -0
- package/examples/events/assets/content/talks/the-art-of-the-perfect-tart.md.ejs +32 -0
- package/examples/events/assets/content/talks/the-science-of-sugar.md.ejs +39 -0
- package/examples/events/assets/content/talks/umami-in-pastry-east-meets-west.md.ejs +39 -0
- package/examples/events/assets/content-collections.ts +56 -0
- 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 +1 -0
- package/examples/events/assets/src/components/Header.tsx +59 -0
- package/examples/events/assets/src/components/HeaderNav.tsx +67 -0
- package/examples/events/assets/src/components/HeroCarousel.tsx +61 -0
- package/examples/events/assets/src/components/RemyAssistant.tsx +207 -0
- package/examples/events/assets/src/components/SpeakerCard.tsx +67 -0
- package/examples/events/assets/src/components/TalkCard.tsx +77 -0
- package/examples/events/assets/src/components/ui/card.tsx +92 -0
- package/examples/events/assets/src/lib/conference-ai-hook.ts +26 -0
- package/examples/events/assets/src/lib/conference-tools.ts +210 -0
- package/examples/events/assets/src/lib/model-selection.ts +1 -0
- package/examples/events/assets/src/lib/utils.ts +6 -0
- package/examples/events/assets/src/routes/__root.tsx +70 -0
- package/examples/events/assets/src/routes/api.remy-chat.ts +119 -0
- package/examples/events/assets/src/routes/index.tsx +192 -0
- package/examples/events/assets/src/routes/schedule.index.tsx +274 -0
- package/examples/events/assets/src/routes/speakers.$slug.tsx +122 -0
- package/examples/events/assets/src/routes/speakers.index.tsx +40 -0
- package/examples/events/assets/src/routes/talks.$slug.tsx +116 -0
- package/examples/events/assets/src/routes/talks.index.tsx +40 -0
- package/examples/events/assets/src/styles.css +182 -0
- package/examples/events/info.json +74 -0
- package/examples/events/package.json +23 -0
- package/examples/marketing/README.md +60 -0
- 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 +36 -0
- package/examples/marketing/assets/src/components/MotorcycleAIAssistant.tsx +162 -0
- package/examples/marketing/assets/src/components/MotorcycleRecommendation.tsx +53 -0
- package/examples/marketing/assets/src/data/motorcycles.ts.ejs +77 -0
- package/examples/marketing/assets/src/lib/motorcycle-ai-hook.ts +24 -0
- package/examples/marketing/assets/src/lib/motorcycle-tools.ts +42 -0
- package/examples/marketing/assets/src/routes/__root.tsx +57 -0
- package/examples/marketing/assets/src/routes/api.motorcycle-chat.ts +78 -0
- package/examples/marketing/assets/src/routes/index.tsx +72 -0
- package/examples/marketing/assets/src/routes/motorcycles/$motorcycleId.tsx +56 -0
- package/examples/marketing/assets/src/store/motorcycle-assistant.ts +3 -0
- package/examples/marketing/assets/src/styles.css +212 -0
- package/examples/marketing/info.json +38 -0
- package/examples/marketing/package.json +14 -0
- package/examples/resume/README.md +82 -0
- package/examples/resume/assets/content/education/code-school.md +17 -0
- package/examples/resume/assets/content/jobs/freelance.md.ejs +13 -0
- package/examples/resume/assets/content/jobs/initech-junior.md +20 -0
- package/examples/resume/assets/content/jobs/initech-lead.md.ejs +29 -0
- package/examples/resume/assets/content/jobs/initrode-senior.md.ejs +28 -0
- package/examples/resume/assets/content-collections.ts +36 -0
- package/examples/resume/assets/public/headshot-on-white.jpg +0 -0
- package/examples/resume/assets/src/components/Header.tsx +33 -0
- package/examples/resume/assets/src/components/ResumeAssistant.tsx +193 -0
- package/examples/resume/assets/src/components/ui/badge.tsx +46 -0
- package/examples/resume/assets/src/components/ui/card.tsx +92 -0
- package/examples/resume/assets/src/components/ui/checkbox.tsx +30 -0
- package/examples/resume/assets/src/components/ui/hover-card.tsx +44 -0
- package/examples/resume/assets/src/components/ui/separator.tsx +26 -0
- package/examples/resume/assets/src/lib/resume-ai-hook.ts +21 -0
- package/examples/resume/assets/src/lib/resume-tools.ts +165 -0
- package/examples/resume/assets/src/lib/utils.ts +6 -0
- package/examples/resume/assets/src/routes/api.resume-chat.ts +110 -0
- package/examples/resume/assets/src/routes/index.tsx +220 -0
- package/examples/resume/assets/src/styles.css +138 -0
- package/examples/resume/info.json +25 -0
- package/examples/resume/package.json +26 -0
- package/package.json +39 -0
- package/project/base/_dot_claude/skills/content-collections/SKILL.md +505 -0
- package/project/base/_dot_claude/skills/netlify-blobs/SKILL.md +410 -0
- package/project/base/_dot_claude/skills/netlify-db/SKILL.md +424 -0
- package/project/base/_dot_claude/skills/netlify-debugging/SKILL.md +419 -0
- package/project/base/_dot_claude/skills/netlify-forms/SKILL.md +243 -0
- package/project/base/_dot_claude/skills/netlify-functions/SKILL.md +372 -0
- package/project/base/_dot_claude/skills/tanstack-start-api-routes/SKILL.md +421 -0
- package/project/base/_dot_claude/skills/tanstack-start-loaders/SKILL.md +426 -0
- package/project/base/_dot_claude/skills/tanstack-start-project-setup/SKILL.md +493 -0
- package/project/base/_dot_claude/skills/tanstack-start-routes/SKILL.md +430 -0
- package/project/base/_dot_claude/skills/tanstack-start-server-functions/SKILL.md +445 -0
- package/project/base/_dot_claude/skills/tanstack-start-typesafe-routing/SKILL.md +494 -0
- package/project/base/_dot_gitignore +8 -0
- package/project/base/netlify.toml +7 -0
- package/project/base/package.json +33 -0
- 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 +1 -0
- package/project/base/src/components/Header.tsx +17 -0
- package/project/base/src/components/HeaderNav.tsx.ejs +179 -0
- package/project/base/src/router.tsx +15 -0
- package/project/base/src/routes/__root.tsx +57 -0
- package/project/base/src/routes/index.tsx +48 -0
- package/project/base/src/styles.css +15 -0
- package/project/base/tsconfig.json +28 -0
- package/project/base/vite.config.ts.ejs +25 -0
- package/project/packages.json +22 -0
- package/scripts/check-outdated-packages.js +421 -0
- package/src/cli.ts +343 -0
- package/src/index.ts +49 -0
- package/src/types.ts +15 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { createFileRoute, Link } from '@tanstack/react-router'
|
|
2
|
+
import { marked } from 'marked'
|
|
3
|
+
import { Clock, User, ArrowLeft, Tag } from 'lucide-react'
|
|
4
|
+
|
|
5
|
+
import { allTalks, allSpeakers } from 'content-collections'
|
|
6
|
+
|
|
7
|
+
import RemyAssistant from '@/components/RemyAssistant'
|
|
8
|
+
|
|
9
|
+
export const Route = createFileRoute('/talks/$slug')({
|
|
10
|
+
loader: async ({ params }) => {
|
|
11
|
+
const talk = allTalks.find((t) => t.slug === params.slug)
|
|
12
|
+
if (!talk) {
|
|
13
|
+
throw new Error('Talk not found')
|
|
14
|
+
}
|
|
15
|
+
const speaker = allSpeakers.find((s) => s.name === talk.speaker)
|
|
16
|
+
return { talk, speaker }
|
|
17
|
+
},
|
|
18
|
+
component: TalkDetailPage,
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
function TalkDetailPage() {
|
|
22
|
+
const { talk, speaker } = Route.useLoaderData()
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div className="min-h-screen">
|
|
26
|
+
<RemyAssistant />
|
|
27
|
+
|
|
28
|
+
{/* Back navigation */}
|
|
29
|
+
<div className="max-w-7xl mx-auto px-6 py-4">
|
|
30
|
+
<Link
|
|
31
|
+
to="/talks"
|
|
32
|
+
className="inline-flex items-center gap-2 text-cream/60 hover:text-gold transition-colors"
|
|
33
|
+
>
|
|
34
|
+
<ArrowLeft className="w-4 h-4" />
|
|
35
|
+
<span>All Sessions</span>
|
|
36
|
+
</Link>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
{/* Hero image */}
|
|
40
|
+
<div className="relative h-[40vh] max-w-7xl mx-auto px-6 mb-8">
|
|
41
|
+
<div className="w-full h-full rounded-2xl overflow-hidden border border-border/50">
|
|
42
|
+
<img
|
|
43
|
+
src={`/${talk.image}`}
|
|
44
|
+
alt={talk.title}
|
|
45
|
+
className="w-full h-full object-cover"
|
|
46
|
+
/>
|
|
47
|
+
</div>
|
|
48
|
+
<div className="absolute inset-6 bg-gradient-to-t from-charcoal/60 to-transparent rounded-2xl pointer-events-none" />
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
{/* Content */}
|
|
52
|
+
<div className="max-w-4xl mx-auto px-6">
|
|
53
|
+
{/* Topics */}
|
|
54
|
+
<div className="flex flex-wrap gap-2 mb-6">
|
|
55
|
+
{talk.topics.map((topic) => (
|
|
56
|
+
<span
|
|
57
|
+
key={topic}
|
|
58
|
+
className="inline-flex items-center gap-1.5 px-3 py-1 text-sm font-medium tracking-wide uppercase bg-gold/15 text-gold border border-gold/30 rounded-full"
|
|
59
|
+
>
|
|
60
|
+
<Tag className="w-3 h-3" />
|
|
61
|
+
{topic}
|
|
62
|
+
</span>
|
|
63
|
+
))}
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
{/* Title */}
|
|
67
|
+
<h1 className="font-display text-4xl md:text-5xl font-bold text-cream mb-6 leading-tight">
|
|
68
|
+
{talk.title}
|
|
69
|
+
</h1>
|
|
70
|
+
|
|
71
|
+
{/* Meta info */}
|
|
72
|
+
<div className="flex flex-wrap items-center gap-6 mb-10 pb-10 border-b border-border/50">
|
|
73
|
+
{/* Speaker link */}
|
|
74
|
+
{speaker ? (
|
|
75
|
+
<Link
|
|
76
|
+
to={`/speakers/${speaker.slug}`}
|
|
77
|
+
className="flex items-center gap-3 group"
|
|
78
|
+
>
|
|
79
|
+
<div className="w-12 h-12 rounded-full overflow-hidden border border-border/50">
|
|
80
|
+
<img
|
|
81
|
+
src={`/${speaker.headshot}`}
|
|
82
|
+
alt={speaker.name}
|
|
83
|
+
className="w-full h-full object-cover"
|
|
84
|
+
/>
|
|
85
|
+
</div>
|
|
86
|
+
<div>
|
|
87
|
+
<p className="text-cream group-hover:text-gold transition-colors font-medium">
|
|
88
|
+
{talk.speaker}
|
|
89
|
+
</p>
|
|
90
|
+
<p className="text-cream/50 text-sm">{speaker.restaurant}</p>
|
|
91
|
+
</div>
|
|
92
|
+
</Link>
|
|
93
|
+
) : (
|
|
94
|
+
<div className="flex items-center gap-2 text-cream/70">
|
|
95
|
+
<User className="w-5 h-5 text-copper" />
|
|
96
|
+
<span>{talk.speaker}</span>
|
|
97
|
+
</div>
|
|
98
|
+
)}
|
|
99
|
+
|
|
100
|
+
{/* Duration */}
|
|
101
|
+
<div className="flex items-center gap-2 text-cream/60">
|
|
102
|
+
<Clock className="w-5 h-5 text-copper" />
|
|
103
|
+
<span className="text-lg">{talk.duration}</span>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
{/* Description content */}
|
|
108
|
+
<div className="prose prose-lg max-w-none prose-invert prose-p:text-cream/80 prose-headings:text-cream prose-headings:font-display prose-strong:text-cream prose-a:text-gold prose-li:text-cream/80 prose-ul:text-cream/80 font-body text-lg leading-relaxed pb-20">
|
|
109
|
+
<div
|
|
110
|
+
dangerouslySetInnerHTML={{ __html: marked(talk.content) }}
|
|
111
|
+
/>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
)
|
|
116
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { createFileRoute } from '@tanstack/react-router'
|
|
2
|
+
|
|
3
|
+
import { allTalks } from 'content-collections'
|
|
4
|
+
|
|
5
|
+
import TalkCard from '@/components/TalkCard'
|
|
6
|
+
import RemyAssistant from '@/components/RemyAssistant'
|
|
7
|
+
|
|
8
|
+
export const Route = createFileRoute('/talks/')({
|
|
9
|
+
component: TalksPage,
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
function TalksPage() {
|
|
13
|
+
return (
|
|
14
|
+
<>
|
|
15
|
+
<RemyAssistant />
|
|
16
|
+
<div className="min-h-screen">
|
|
17
|
+
{/* Hero section */}
|
|
18
|
+
<div className="relative py-16 px-6">
|
|
19
|
+
<div className="max-w-7xl mx-auto text-center">
|
|
20
|
+
<h1 className="font-display text-5xl md:text-6xl font-bold text-cream mb-4">
|
|
21
|
+
Conference <span className="text-gold italic">Sessions</span>
|
|
22
|
+
</h1>
|
|
23
|
+
<p className="text-xl text-cream/70 max-w-2xl mx-auto font-body">
|
|
24
|
+
Immerse yourself in masterclasses and demonstrations covering every aspect of artisan baking and pastry.
|
|
25
|
+
</p>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
{/* Talks grid */}
|
|
30
|
+
<div className="max-w-7xl mx-auto px-6 pb-20">
|
|
31
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
|
32
|
+
{allTalks.map((talk) => (
|
|
33
|
+
<TalkCard key={talk.slug} talk={talk} />
|
|
34
|
+
))}
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,500;0,600;0,700;0,800;0,900;1,400;1,500;1,600;1,700&family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500&display=swap');
|
|
2
|
+
@import 'tailwindcss';
|
|
3
|
+
|
|
4
|
+
@plugin "tailwindcss-animate";
|
|
5
|
+
|
|
6
|
+
@custom-variant dark (&:is(.dark *));
|
|
7
|
+
|
|
8
|
+
body {
|
|
9
|
+
@apply m-0;
|
|
10
|
+
font-family: 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
|
|
11
|
+
-webkit-font-smoothing: antialiased;
|
|
12
|
+
-moz-osx-font-smoothing: grayscale;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
code {
|
|
16
|
+
font-family:
|
|
17
|
+
source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* Haute Patisserie Dark Theme */
|
|
21
|
+
:root {
|
|
22
|
+
/* Core colors - Dark elegant bakery */
|
|
23
|
+
--background: oklch(0.13 0.01 60);
|
|
24
|
+
--foreground: oklch(0.93 0.02 85);
|
|
25
|
+
|
|
26
|
+
/* Warm cream for cards */
|
|
27
|
+
--card: oklch(0.17 0.015 55);
|
|
28
|
+
--card-foreground: oklch(0.93 0.02 85);
|
|
29
|
+
|
|
30
|
+
/* Copper accent */
|
|
31
|
+
--primary: oklch(0.65 0.14 55);
|
|
32
|
+
--primary-foreground: oklch(0.13 0.01 60);
|
|
33
|
+
|
|
34
|
+
/* Antique gold */
|
|
35
|
+
--secondary: oklch(0.72 0.12 85);
|
|
36
|
+
--secondary-foreground: oklch(0.13 0.01 60);
|
|
37
|
+
|
|
38
|
+
/* Muted warm tones */
|
|
39
|
+
--muted: oklch(0.22 0.02 55);
|
|
40
|
+
--muted-foreground: oklch(0.65 0.03 85);
|
|
41
|
+
|
|
42
|
+
/* Accent - rich copper */
|
|
43
|
+
--accent: oklch(0.55 0.15 45);
|
|
44
|
+
--accent-foreground: oklch(0.95 0.02 85);
|
|
45
|
+
|
|
46
|
+
/* Destructive */
|
|
47
|
+
--destructive: oklch(0.55 0.2 25);
|
|
48
|
+
--destructive-foreground: oklch(0.95 0.02 85);
|
|
49
|
+
|
|
50
|
+
/* Borders and inputs */
|
|
51
|
+
--border: oklch(0.28 0.03 55);
|
|
52
|
+
--input: oklch(0.22 0.02 55);
|
|
53
|
+
--ring: oklch(0.65 0.14 55);
|
|
54
|
+
|
|
55
|
+
/* Chart colors - pastry inspired */
|
|
56
|
+
--chart-1: oklch(0.65 0.14 55);
|
|
57
|
+
--chart-2: oklch(0.72 0.12 85);
|
|
58
|
+
--chart-3: oklch(0.55 0.15 45);
|
|
59
|
+
--chart-4: oklch(0.60 0.10 30);
|
|
60
|
+
--chart-5: oklch(0.50 0.08 150);
|
|
61
|
+
|
|
62
|
+
--radius: 0.625rem;
|
|
63
|
+
|
|
64
|
+
/* Popover */
|
|
65
|
+
--popover: oklch(0.17 0.015 55);
|
|
66
|
+
--popover-foreground: oklch(0.93 0.02 85);
|
|
67
|
+
|
|
68
|
+
/* Sidebar */
|
|
69
|
+
--sidebar: oklch(0.15 0.01 55);
|
|
70
|
+
--sidebar-foreground: oklch(0.93 0.02 85);
|
|
71
|
+
--sidebar-primary: oklch(0.65 0.14 55);
|
|
72
|
+
--sidebar-primary-foreground: oklch(0.95 0.02 85);
|
|
73
|
+
--sidebar-accent: oklch(0.22 0.02 55);
|
|
74
|
+
--sidebar-accent-foreground: oklch(0.93 0.02 85);
|
|
75
|
+
--sidebar-border: oklch(0.28 0.03 55);
|
|
76
|
+
--sidebar-ring: oklch(0.65 0.14 55);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@theme inline {
|
|
80
|
+
--font-display: 'Playfair Display', Georgia, serif;
|
|
81
|
+
--font-body: 'Cormorant Garamond', Georgia, serif;
|
|
82
|
+
|
|
83
|
+
--color-background: var(--background);
|
|
84
|
+
--color-foreground: var(--foreground);
|
|
85
|
+
--color-card: var(--card);
|
|
86
|
+
--color-card-foreground: var(--card-foreground);
|
|
87
|
+
--color-popover: var(--popover);
|
|
88
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
89
|
+
--color-primary: var(--primary);
|
|
90
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
91
|
+
--color-secondary: var(--secondary);
|
|
92
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
93
|
+
--color-muted: var(--muted);
|
|
94
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
95
|
+
--color-accent: var(--accent);
|
|
96
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
97
|
+
--color-destructive: var(--destructive);
|
|
98
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
|
99
|
+
--color-border: var(--border);
|
|
100
|
+
--color-input: var(--input);
|
|
101
|
+
--color-ring: var(--ring);
|
|
102
|
+
--color-chart-1: var(--chart-1);
|
|
103
|
+
--color-chart-2: var(--chart-2);
|
|
104
|
+
--color-chart-3: var(--chart-3);
|
|
105
|
+
--color-chart-4: var(--chart-4);
|
|
106
|
+
--color-chart-5: var(--chart-5);
|
|
107
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
108
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
109
|
+
--radius-lg: var(--radius);
|
|
110
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
111
|
+
--color-sidebar: var(--sidebar);
|
|
112
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
113
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
114
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
115
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
116
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
117
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
118
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
119
|
+
|
|
120
|
+
/* Custom colors for the theme */
|
|
121
|
+
--color-copper: oklch(0.65 0.14 55);
|
|
122
|
+
--color-copper-light: oklch(0.75 0.12 55);
|
|
123
|
+
--color-copper-dark: oklch(0.50 0.15 50);
|
|
124
|
+
--color-gold: oklch(0.72 0.12 85);
|
|
125
|
+
--color-gold-light: oklch(0.82 0.10 85);
|
|
126
|
+
--color-cream: oklch(0.93 0.02 85);
|
|
127
|
+
--color-cream-dark: oklch(0.85 0.03 80);
|
|
128
|
+
--color-charcoal: oklch(0.13 0.01 60);
|
|
129
|
+
--color-charcoal-light: oklch(0.20 0.015 55);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@layer base {
|
|
133
|
+
* {
|
|
134
|
+
@apply border-border outline-ring/50;
|
|
135
|
+
}
|
|
136
|
+
body {
|
|
137
|
+
@apply bg-background text-foreground;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/* Custom utilities for the theme */
|
|
142
|
+
.font-display {
|
|
143
|
+
font-family: 'Playfair Display', Georgia, serif;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.font-body {
|
|
147
|
+
font-family: 'Cormorant Garamond', Georgia, serif;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* Elegant grain texture overlay */
|
|
151
|
+
.grain-texture {
|
|
152
|
+
position: relative;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.grain-texture::after {
|
|
156
|
+
content: '';
|
|
157
|
+
position: absolute;
|
|
158
|
+
inset: 0;
|
|
159
|
+
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%' height='100%' filter='url(%23noise)' opacity='0.08'/%3E%3C/svg%3E");
|
|
160
|
+
pointer-events: none;
|
|
161
|
+
opacity: 0.4;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* Golden border accent */
|
|
165
|
+
.border-gold-accent {
|
|
166
|
+
border-image: linear-gradient(135deg, oklch(0.72 0.12 85), oklch(0.65 0.14 55), oklch(0.72 0.12 85)) 1;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/* Copper glow effect */
|
|
170
|
+
.glow-copper {
|
|
171
|
+
box-shadow: 0 0 20px oklch(0.65 0.14 55 / 0.3), 0 0 40px oklch(0.65 0.14 55 / 0.1);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/* Elegant card hover effect */
|
|
175
|
+
.card-hover {
|
|
176
|
+
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.card-hover:hover {
|
|
180
|
+
transform: translateY(-4px);
|
|
181
|
+
box-shadow: 0 12px 40px oklch(0 0 0 / 0.4), 0 0 20px oklch(0.65 0.14 55 / 0.15);
|
|
182
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Events",
|
|
3
|
+
"description": "A pastry conference website with speakers, sessions, schedule, 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
|
+
{
|
|
11
|
+
"url": "/",
|
|
12
|
+
"path": "src/routes/index.tsx",
|
|
13
|
+
"jsName": "EventsHome"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"url": "/schedule",
|
|
17
|
+
"path": "src/routes/schedule.index.tsx",
|
|
18
|
+
"jsName": "SchedulePage"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"url": "/speakers",
|
|
22
|
+
"path": "src/routes/speakers.index.tsx",
|
|
23
|
+
"jsName": "SpeakersPage"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"url": "/speakers/$slug",
|
|
27
|
+
"path": "src/routes/speakers.$slug.tsx",
|
|
28
|
+
"jsName": "SpeakerDetail"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"url": "/talks",
|
|
32
|
+
"path": "src/routes/talks.index.tsx",
|
|
33
|
+
"jsName": "TalksPage"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"url": "/talks/$slug",
|
|
37
|
+
"path": "src/routes/talks.$slug.tsx",
|
|
38
|
+
"jsName": "TalkDetail"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"url": "/api/remy-chat",
|
|
42
|
+
"path": "src/routes/api.remy-chat.ts",
|
|
43
|
+
"jsName": "RemyChatAPI"
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"integrations": [
|
|
47
|
+
{
|
|
48
|
+
"type": "vite-plugin",
|
|
49
|
+
"import": "import contentCollections from '@content-collections/vite'",
|
|
50
|
+
"code": "contentCollections()"
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"dependsOn": [],
|
|
54
|
+
"variables": [],
|
|
55
|
+
"bareBones": {
|
|
56
|
+
"deleteFiles": [
|
|
57
|
+
"public/background-2.jpg",
|
|
58
|
+
"public/background-3.jpg",
|
|
59
|
+
"public/background-4.jpg",
|
|
60
|
+
"public/speakers/hans-mueller.jpg",
|
|
61
|
+
"public/speakers/isabella-martinez.jpg",
|
|
62
|
+
"public/speakers/kenji-nakamura.jpg",
|
|
63
|
+
"public/speakers/marie-dubois.jpg",
|
|
64
|
+
"public/speakers/priya-sharma.jpg",
|
|
65
|
+
"public/talks/french-macaron-mastery.jpg",
|
|
66
|
+
"public/talks/neapolitan-pizza-tradition-meets-innovation.jpg",
|
|
67
|
+
"public/talks/savory-breads-of-the-mediterranean.jpg",
|
|
68
|
+
"public/talks/sourdough-from-starter-to-masterpiece.jpg",
|
|
69
|
+
"public/talks/the-art-of-the-perfect-tart.jpg",
|
|
70
|
+
"public/talks/the-science-of-sugar.jpg",
|
|
71
|
+
"public/talks/umami-in-pastry-east-meets-west.jpg"
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"dependencies": {
|
|
3
|
+
"@tanstack/ai": "0.2.2",
|
|
4
|
+
"@tanstack/ai-anthropic": "0.2.0",
|
|
5
|
+
"@tanstack/ai-client": "0.2.2",
|
|
6
|
+
"@tanstack/ai-gemini": "0.3.2",
|
|
7
|
+
"@tanstack/ai-ollama": "0.3.0",
|
|
8
|
+
"@tanstack/ai-openai": "0.3.0",
|
|
9
|
+
"@tanstack/ai-react": "0.2.2",
|
|
10
|
+
"@tanstack/store": "^0.8.0",
|
|
11
|
+
"class-variance-authority": "^0.7.1",
|
|
12
|
+
"clsx": "^2.1.1",
|
|
13
|
+
"marked": "^17.0.1",
|
|
14
|
+
"streamdown": "^2.1.0",
|
|
15
|
+
"tailwind-merge": "^3.0.2",
|
|
16
|
+
"tailwindcss-animate": "^1.0.7",
|
|
17
|
+
"zod": "^4.3.5"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@content-collections/core": "^0.13.1",
|
|
21
|
+
"@content-collections/vite": "^0.2.8"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# E-commerce Example
|
|
2
|
+
|
|
3
|
+
An AI-powered motorcycle e-commerce store built with TanStack Start and TanStack AI for Netlify deployment.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **AI Chat Assistant**: Powered by TanStack AI with Anthropic Claude
|
|
8
|
+
- **Product Catalog**: Browse Luna-C motorcycle inventory
|
|
9
|
+
- **Smart Recommendations**: AI can recommend motorcycles based on your needs
|
|
10
|
+
- **SSR Ready**: Full server-side rendering with TanStack Start
|
|
11
|
+
|
|
12
|
+
## Project Structure
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
├── src/
|
|
16
|
+
│ ├── components/
|
|
17
|
+
│ │ ├── AIAssistant.tsx # Chat panel component
|
|
18
|
+
│ │ ├── Header.tsx # Navigation with AI button
|
|
19
|
+
│ │ └── MotorcycleRecommendation.tsx # Product card for AI
|
|
20
|
+
│ ├── data/
|
|
21
|
+
│ │ └── motorcycles.ts # Product inventory
|
|
22
|
+
│ ├── lib/
|
|
23
|
+
│ │ ├── ai-hook.ts # useMotorcycleChat hook
|
|
24
|
+
│ │ └── motorcycle-tools.ts # AI tool definitions
|
|
25
|
+
│ ├── store/
|
|
26
|
+
│ │ └── assistant.ts # UI state with TanStack Store
|
|
27
|
+
│ └── routes/
|
|
28
|
+
│ ├── __root.tsx # Root layout
|
|
29
|
+
│ ├── index.tsx # Product listing
|
|
30
|
+
│ ├── motorcycles/$motorcycleId.tsx # Product detail
|
|
31
|
+
│ └── api.motorcycle-chat.ts # Chat API endpoint
|
|
32
|
+
└── public/
|
|
33
|
+
└── *.jpg # Product images
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## AI Chat Features
|
|
37
|
+
|
|
38
|
+
The AI assistant can:
|
|
39
|
+
- Answer questions about motorcycles
|
|
40
|
+
- Recommend bikes based on your preferences (budget, experience level, riding style)
|
|
41
|
+
- Display product cards directly in the chat
|
|
42
|
+
- Help you find the perfect motorcycle
|
|
43
|
+
|
|
44
|
+
## Environment Variables
|
|
45
|
+
|
|
46
|
+
Create a `.env.local` file with your Anthropic API key:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
ANTHROPIC_API_KEY=your_api_key_here
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Development
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Start development server
|
|
56
|
+
npm run dev
|
|
57
|
+
|
|
58
|
+
# Build for production
|
|
59
|
+
npm run build
|
|
60
|
+
```
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Link } from '@tanstack/react-router'
|
|
2
|
+
|
|
3
|
+
import HeaderNav from './HeaderNav'
|
|
4
|
+
|
|
5
|
+
import MotorcycleAIAssistant from '@/components/MotorcycleAIAssistant'
|
|
6
|
+
|
|
7
|
+
export default function Header() {
|
|
8
|
+
return (
|
|
9
|
+
<>
|
|
10
|
+
<div className="z-40">
|
|
11
|
+
<HeaderNav />
|
|
12
|
+
</div>
|
|
13
|
+
<header className="p-4 flex gap-2 bg-black/30 text-white border-b border-orange-500/20 backdrop-blur-md sticky top-0 z-40">
|
|
14
|
+
<nav className="flex flex-row items-center">
|
|
15
|
+
<div className="px-4 font-extrabold text-lg">
|
|
16
|
+
<Link
|
|
17
|
+
to="/"
|
|
18
|
+
className="hover:text-orange-400 transition-colors flex flex-row items-center"
|
|
19
|
+
>
|
|
20
|
+
<img
|
|
21
|
+
src="/logo.png"
|
|
22
|
+
alt="Luna-C Motorcycles"
|
|
23
|
+
className="w-20 h-20"
|
|
24
|
+
/>
|
|
25
|
+
<span className="text-2xl font-bold">Luna-C Motorcycles</span>
|
|
26
|
+
</Link>
|
|
27
|
+
</div>
|
|
28
|
+
</nav>
|
|
29
|
+
|
|
30
|
+
<div className="ml-auto">
|
|
31
|
+
<MotorcycleAIAssistant />
|
|
32
|
+
</div>
|
|
33
|
+
</header>
|
|
34
|
+
</>
|
|
35
|
+
)
|
|
36
|
+
}
|