@tanstack/create 0.61.6 → 0.62.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/CHANGELOG.md +13 -0
- package/dist/config-file.js +5 -2
- package/dist/custom-add-ons/starter.js +45 -28
- package/dist/file-helpers.js +1 -0
- package/dist/frameworks/react/add-ons/shadcn/assets/src/styles.css +224 -15
- package/dist/frameworks/react/add-ons/store/assets/src/lib/demo-store.ts +5 -6
- package/dist/frameworks/react/add-ons/store/assets/src/routes/demo/store.tsx.ejs +1 -1
- package/dist/frameworks/react/add-ons/store/package.json +2 -2
- package/dist/frameworks/react/index.js +2 -2
- package/dist/frameworks/react/project/base/content/blog/fifth-post.mdx.ejs +54 -0
- package/dist/frameworks/react/project/base/content/blog/first-post.md.ejs +47 -0
- package/dist/frameworks/react/project/base/content/blog/fourth-post.md.ejs +42 -0
- package/dist/frameworks/react/project/base/content/blog/second-post.mdx.ejs +46 -0
- package/dist/frameworks/react/project/base/content/blog/third-post.md.ejs +49 -0
- package/dist/frameworks/react/project/base/content-collections.ts.ejs +37 -0
- package/dist/frameworks/react/project/base/package.json +8 -1
- package/dist/frameworks/react/project/base/public/images/lagoon-1.svg +13 -0
- package/dist/frameworks/react/project/base/public/images/lagoon-2.svg +12 -0
- package/dist/frameworks/react/project/base/public/images/lagoon-3.svg +12 -0
- package/dist/frameworks/react/project/base/public/images/lagoon-4.svg +12 -0
- package/dist/frameworks/react/project/base/public/images/lagoon-5.svg +12 -0
- package/dist/frameworks/react/project/base/public/images/lagoon-about.svg +14 -0
- package/dist/frameworks/react/project/base/src/components/Footer.tsx.ejs +42 -0
- package/dist/frameworks/react/project/base/src/components/Header.tsx.ejs +92 -138
- package/dist/frameworks/react/project/base/src/components/MdxCallout.tsx.ejs +16 -0
- package/dist/frameworks/react/project/base/src/components/MdxMetrics.tsx.ejs +23 -0
- package/dist/frameworks/react/project/base/src/components/ThemeToggle.tsx.ejs +81 -0
- package/dist/frameworks/react/project/base/src/lib/site.ts.ejs +4 -0
- package/dist/frameworks/react/project/base/src/main.tsx.ejs +0 -1
- package/dist/frameworks/react/project/base/src/routes/__root.tsx.ejs +10 -6
- package/dist/frameworks/react/project/base/src/routes/about.tsx.ejs +27 -0
- package/dist/frameworks/react/project/base/src/routes/blog.$slug.tsx.ejs +71 -0
- package/dist/frameworks/react/project/base/src/routes/blog.index.tsx.ejs +93 -0
- package/dist/frameworks/react/project/base/src/routes/index.tsx.ejs +58 -91
- package/dist/frameworks/react/project/base/src/routes/rss[.]xml.ts.ejs +35 -0
- package/dist/frameworks/react/project/base/src/styles.css.ejs +268 -6
- package/dist/frameworks/react/project/base/tsconfig.json.ejs +2 -0
- package/dist/frameworks/react/project/base/vite.config.ts.ejs +2 -0
- package/dist/frameworks/solid/add-ons/store/assets/src/lib/demo-store.ts +5 -6
- package/dist/frameworks/solid/add-ons/store/assets/src/routes/demo.store.tsx.ejs +2 -2
- package/dist/frameworks/solid/examples/tanchat/assets/src/lib/demo-store.ts +5 -6
- package/dist/frameworks/solid/project/base/src/components/Header.tsx.ejs +8 -6
- package/dist/frameworks/solid/project/base/src/routes/__root.tsx.ejs +1 -1
- package/dist/frameworks/solid/project/base/src/routes/index.tsx.ejs +1 -1
- package/dist/frameworks.js +3 -0
- package/dist/package-json.js +1 -1
- package/dist/registry.js +21 -4
- package/dist/types/registry.d.ts +38 -0
- package/package.json +1 -1
- package/src/config-file.ts +6 -2
- package/src/custom-add-ons/starter.ts +30 -10
- package/src/file-helpers.ts +1 -0
- package/src/frameworks/react/add-ons/shadcn/assets/src/styles.css +224 -15
- package/src/frameworks/react/add-ons/store/assets/src/lib/demo-store.ts +5 -6
- package/src/frameworks/react/add-ons/store/assets/src/routes/demo/store.tsx.ejs +1 -1
- package/src/frameworks/react/add-ons/store/package.json +2 -2
- package/src/frameworks/react/index.ts +2 -2
- package/src/frameworks/react/project/base/content/blog/fifth-post.mdx.ejs +54 -0
- package/src/frameworks/react/project/base/content/blog/first-post.md.ejs +47 -0
- package/src/frameworks/react/project/base/content/blog/fourth-post.md.ejs +42 -0
- package/src/frameworks/react/project/base/content/blog/second-post.mdx.ejs +46 -0
- package/src/frameworks/react/project/base/content/blog/third-post.md.ejs +49 -0
- package/src/frameworks/react/project/base/content-collections.ts.ejs +37 -0
- package/src/frameworks/react/project/base/package.json +8 -1
- package/src/frameworks/react/project/base/public/images/lagoon-1.svg +13 -0
- package/src/frameworks/react/project/base/public/images/lagoon-2.svg +12 -0
- package/src/frameworks/react/project/base/public/images/lagoon-3.svg +12 -0
- package/src/frameworks/react/project/base/public/images/lagoon-4.svg +12 -0
- package/src/frameworks/react/project/base/public/images/lagoon-5.svg +12 -0
- package/src/frameworks/react/project/base/public/images/lagoon-about.svg +14 -0
- package/src/frameworks/react/project/base/src/components/Footer.tsx.ejs +42 -0
- package/src/frameworks/react/project/base/src/components/Header.tsx.ejs +92 -138
- package/src/frameworks/react/project/base/src/components/MdxCallout.tsx.ejs +16 -0
- package/src/frameworks/react/project/base/src/components/MdxMetrics.tsx.ejs +23 -0
- package/src/frameworks/react/project/base/src/components/ThemeToggle.tsx.ejs +81 -0
- package/src/frameworks/react/project/base/src/lib/site.ts.ejs +4 -0
- package/src/frameworks/react/project/base/src/main.tsx.ejs +0 -1
- package/src/frameworks/react/project/base/src/routes/__root.tsx.ejs +10 -6
- package/src/frameworks/react/project/base/src/routes/about.tsx.ejs +27 -0
- package/src/frameworks/react/project/base/src/routes/blog.$slug.tsx.ejs +71 -0
- package/src/frameworks/react/project/base/src/routes/blog.index.tsx.ejs +93 -0
- package/src/frameworks/react/project/base/src/routes/index.tsx.ejs +58 -91
- package/src/frameworks/react/project/base/src/routes/rss[.]xml.ts.ejs +35 -0
- package/src/frameworks/react/project/base/src/styles.css.ejs +268 -6
- package/src/frameworks/react/project/base/tsconfig.json.ejs +2 -0
- package/src/frameworks/react/project/base/vite.config.ts.ejs +2 -0
- package/src/frameworks/solid/add-ons/store/assets/src/lib/demo-store.ts +5 -6
- package/src/frameworks/solid/add-ons/store/assets/src/routes/demo.store.tsx.ejs +2 -2
- package/src/frameworks/solid/examples/tanchat/assets/src/lib/demo-store.ts +5 -6
- package/src/frameworks/solid/project/base/src/components/Header.tsx.ejs +8 -6
- package/src/frameworks/solid/project/base/src/routes/__root.tsx.ejs +1 -1
- package/src/frameworks/solid/project/base/src/routes/index.tsx.ejs +1 -1
- package/src/frameworks.ts +4 -0
- package/src/package-json.ts +1 -1
- package/src/registry.ts +28 -4
- package/tests/add-ons.test.ts +4 -4
- package/tests/config-file.test.ts +3 -3
- package/tests/custom-add-ons/starter.test.ts +34 -2
- package/tests/frameworks.test.ts +24 -0
- package/tests/options.test.ts +4 -4
- package/tests/utils.test.ts +2 -2
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Link, createFileRoute } from '@tanstack/react-router'
|
|
2
|
+
import { allBlogs } from 'content-collections'
|
|
3
|
+
import { SITE_DESCRIPTION, SITE_TITLE, SITE_URL } from '#/lib/site'
|
|
4
|
+
|
|
5
|
+
const canonical = `${SITE_URL}/blog`
|
|
6
|
+
const pageTitle = `Blog | ${SITE_TITLE}`
|
|
7
|
+
|
|
8
|
+
export const Route = createFileRoute('/blog/')({
|
|
9
|
+
head: () => ({
|
|
10
|
+
links: [{ rel: 'canonical', href: canonical }],
|
|
11
|
+
meta: [
|
|
12
|
+
{ title: pageTitle },
|
|
13
|
+
{ name: 'description', content: SITE_DESCRIPTION },
|
|
14
|
+
{ property: 'og:image', content: `${SITE_URL}/images/lagoon-1.svg` },
|
|
15
|
+
],
|
|
16
|
+
}),
|
|
17
|
+
component: BlogIndex,
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
function BlogIndex() {
|
|
21
|
+
const postsByDate = Array.from(
|
|
22
|
+
new Map(
|
|
23
|
+
[...allBlogs]
|
|
24
|
+
.sort((a, b) => new Date(b.pubDate).valueOf() - new Date(a.pubDate).valueOf())
|
|
25
|
+
.map((post) => [post.slug, post]),
|
|
26
|
+
).values(),
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
const featured = postsByDate[0]
|
|
30
|
+
const posts = postsByDate.slice(1)
|
|
31
|
+
return (
|
|
32
|
+
<main className="page-wrap px-4 pb-8 pt-14">
|
|
33
|
+
<section className="mb-4">
|
|
34
|
+
<p className="island-kicker mb-2">Latest Dispatches</p>
|
|
35
|
+
<h1 className="display-title m-0 text-4xl font-bold tracking-tight text-[var(--sea-ink)] sm:text-5xl">
|
|
36
|
+
Blog
|
|
37
|
+
</h1>
|
|
38
|
+
</section>
|
|
39
|
+
|
|
40
|
+
<section className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
41
|
+
<article className="island-shell rise-in rounded-2xl p-5 sm:p-6 lg:col-span-2">
|
|
42
|
+
{featured.heroImage ? (
|
|
43
|
+
<img
|
|
44
|
+
src={featured.heroImage}
|
|
45
|
+
alt=""
|
|
46
|
+
className="mb-4 h-44 w-full rounded-xl object-cover xl:h-60"
|
|
47
|
+
/>
|
|
48
|
+
) : null}
|
|
49
|
+
<h2 className="m-0 text-2xl font-semibold text-[var(--sea-ink)]">
|
|
50
|
+
<Link
|
|
51
|
+
to="/blog/$slug"
|
|
52
|
+
params={{ slug: featured.slug }}
|
|
53
|
+
className="no-underline"
|
|
54
|
+
>
|
|
55
|
+
{featured.title}
|
|
56
|
+
</Link>
|
|
57
|
+
</h2>
|
|
58
|
+
<p className="mb-2 mt-3 text-base text-[var(--sea-ink-soft)]">
|
|
59
|
+
{featured.description}
|
|
60
|
+
</p>
|
|
61
|
+
<p className="m-0 text-xs text-[var(--sea-ink-soft)]">
|
|
62
|
+
{new Date(featured.pubDate).toLocaleDateString()}
|
|
63
|
+
</p>
|
|
64
|
+
</article>
|
|
65
|
+
|
|
66
|
+
{posts.map((post, index) => (
|
|
67
|
+
<article
|
|
68
|
+
key={post.slug}
|
|
69
|
+
className="island-shell rise-in rounded-2xl p-5 sm:last:col-span-2 lg:last:col-span-1"
|
|
70
|
+
style={{ animationDelay: `${index * 80 + 120}ms` }}
|
|
71
|
+
>
|
|
72
|
+
{post.heroImage ? (
|
|
73
|
+
<img
|
|
74
|
+
src={post.heroImage}
|
|
75
|
+
alt=""
|
|
76
|
+
className="mb-4 h-44 w-full rounded-xl object-cover"
|
|
77
|
+
/>
|
|
78
|
+
) : null}
|
|
79
|
+
<h2 className="m-0 text-2xl font-semibold text-[var(--sea-ink)]">
|
|
80
|
+
<Link to="/blog/$slug" params={{ slug: post.slug }} className="no-underline">
|
|
81
|
+
{post.title}
|
|
82
|
+
</Link>
|
|
83
|
+
</h2>
|
|
84
|
+
<p className="mb-2 mt-2 text-sm text-[var(--sea-ink-soft)]">{post.description}</p>
|
|
85
|
+
<p className="m-0 text-xs text-[var(--sea-ink-soft)]">
|
|
86
|
+
{new Date(post.pubDate).toLocaleDateString()}
|
|
87
|
+
</p>
|
|
88
|
+
</article>
|
|
89
|
+
))}
|
|
90
|
+
</section>
|
|
91
|
+
</main>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
@@ -1,105 +1,72 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
|
-
import {
|
|
3
|
-
Zap, Server, Route as RouteIcon, Shield, Waves, Sparkles,
|
|
4
|
-
} from "lucide-react";
|
|
5
2
|
|
|
6
3
|
export const Route = createFileRoute("/")({ component: App });
|
|
7
4
|
|
|
8
5
|
function App() {
|
|
9
|
-
const features = [
|
|
10
|
-
{
|
|
11
|
-
icon: <Zap className="w-12 h-12 text-cyan-400" />,
|
|
12
|
-
title: "Powerful Server Functions",
|
|
13
|
-
description: "Write server-side code that seamlessly integrates with your client components. Type-safe, secure, and simple.",
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
icon: <Server className="w-12 h-12 text-cyan-400" />,
|
|
17
|
-
title: "Flexible Server Side Rendering",
|
|
18
|
-
description: "Full-document SSR, streaming, and progressive enhancement out of the box. Control exactly what renders where.",
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
icon: <RouteIcon className="w-12 h-12 text-cyan-400" />,
|
|
22
|
-
title: "API Routes",
|
|
23
|
-
description: "Build type-safe API endpoints alongside your application. No separate backend needed.",
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
icon: <Shield className="w-12 h-12 text-cyan-400" />,
|
|
27
|
-
title: "Strongly Typed Everything",
|
|
28
|
-
description: "End-to-end type safety from server to client. Catch errors before they reach production.",
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
icon: <Waves className="w-12 h-12 text-cyan-400" />,
|
|
32
|
-
title: "Full Streaming Support",
|
|
33
|
-
description: "Stream data from server to client progressively. Perfect for AI applications and real-time updates.",
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
icon: <Sparkles className="w-12 h-12 text-cyan-400" />,
|
|
37
|
-
title: "Next Generation Ready",
|
|
38
|
-
description: "Built from the ground up for modern web applications. Deploy anywhere JavaScript runs.",
|
|
39
|
-
},
|
|
40
|
-
];
|
|
41
|
-
|
|
42
6
|
return (
|
|
43
|
-
<
|
|
44
|
-
<section className="relative
|
|
45
|
-
<div className="absolute
|
|
46
|
-
<div className="
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
href="https://tanstack.com/start"
|
|
71
|
-
target="_blank"
|
|
72
|
-
rel="noopener noreferrer"
|
|
73
|
-
className="px-8 py-3 bg-cyan-500 hover:bg-cyan-600 text-white font-semibold rounded-lg transition-colors shadow-lg shadow-cyan-500/50"
|
|
74
|
-
>
|
|
75
|
-
Documentation
|
|
76
|
-
</a>
|
|
77
|
-
<p className="text-gray-400 text-sm mt-2">
|
|
78
|
-
Begin your TanStack Start journey by editing{" "}
|
|
79
|
-
<code className="px-2 py-1 bg-slate-700 rounded text-cyan-400">
|
|
80
|
-
/src/routes/index.tsx
|
|
81
|
-
</code>
|
|
82
|
-
</p>
|
|
83
|
-
</div>
|
|
7
|
+
<main className="page-wrap px-4 pb-8 pt-14">
|
|
8
|
+
<section className="island-shell rise-in relative overflow-hidden rounded-[2rem] px-6 py-10 sm:px-10 sm:py-14">
|
|
9
|
+
<div className="pointer-events-none absolute -left-20 -top-24 h-56 w-56 rounded-full bg-[radial-gradient(circle,rgba(79,184,178,0.32),transparent_66%)]" />
|
|
10
|
+
<div className="pointer-events-none absolute -bottom-20 -right-20 h-56 w-56 rounded-full bg-[radial-gradient(circle,rgba(47,106,74,0.18),transparent_66%)]" />
|
|
11
|
+
<p className="island-kicker mb-3">TanStack Start Base Template</p>
|
|
12
|
+
<h1 className="display-title mb-5 max-w-3xl text-4xl leading-[1.02] font-bold tracking-tight text-[var(--sea-ink)] sm:text-6xl">
|
|
13
|
+
Island hours, but for product teams.
|
|
14
|
+
</h1>
|
|
15
|
+
<p className="mb-8 max-w-2xl text-base text-[var(--sea-ink-soft)] sm:text-lg">
|
|
16
|
+
A tropical, breathable app starter with full-document SSR, server functions,
|
|
17
|
+
streaming, and type-safe routing. Calm on the eyes. Fast in production.
|
|
18
|
+
</p>
|
|
19
|
+
<div className="flex flex-wrap gap-3">
|
|
20
|
+
<a
|
|
21
|
+
href="/blog"
|
|
22
|
+
className="rounded-full border border-[rgba(50,143,151,0.3)] bg-[rgba(79,184,178,0.14)] px-5 py-2.5 text-sm font-semibold text-[var(--lagoon-deep)] no-underline transition hover:-translate-y-0.5 hover:bg-[rgba(79,184,178,0.24)]"
|
|
23
|
+
>
|
|
24
|
+
Explore Posts
|
|
25
|
+
</a>
|
|
26
|
+
<a
|
|
27
|
+
href="https://tanstack.com/router"
|
|
28
|
+
target="_blank"
|
|
29
|
+
rel="noopener noreferrer"
|
|
30
|
+
className="rounded-full border border-[rgba(23,58,64,0.2)] bg-white/50 px-5 py-2.5 text-sm font-semibold text-[var(--sea-ink)] no-underline transition hover:-translate-y-0.5 hover:border-[rgba(23,58,64,0.35)]"
|
|
31
|
+
>
|
|
32
|
+
Router Guide
|
|
33
|
+
</a>
|
|
84
34
|
</div>
|
|
85
35
|
</section>
|
|
86
36
|
|
|
87
|
-
<section className="
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
37
|
+
<section className="mt-8 grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
38
|
+
{[
|
|
39
|
+
['Type-Safe Routing', 'Routes and links stay in sync across every page.'],
|
|
40
|
+
['Server Functions', 'Call server code from your UI without creating API boilerplate.'],
|
|
41
|
+
['Streaming by Default', 'Ship progressively rendered responses for faster experiences.'],
|
|
42
|
+
['Tailwind Native', 'Design quickly with utility-first styling and custom tokens.'],
|
|
43
|
+
].map(([title, desc], index) => (
|
|
44
|
+
<article
|
|
45
|
+
key={title}
|
|
46
|
+
className="island-shell feature-card rise-in rounded-2xl p-5"
|
|
47
|
+
style={{ animationDelay: `${index * 90 + 80}ms` }}
|
|
93
48
|
>
|
|
94
|
-
<
|
|
95
|
-
<
|
|
96
|
-
|
|
97
|
-
</h3>
|
|
98
|
-
<p className="text-gray-400 leading-relaxed">{feature.description}</p>
|
|
99
|
-
</div>
|
|
49
|
+
<h2 className="mb-2 text-base font-semibold text-[var(--sea-ink)]">{title}</h2>
|
|
50
|
+
<p className="m-0 text-sm text-[var(--sea-ink-soft)]">{desc}</p>
|
|
51
|
+
</article>
|
|
100
52
|
))}
|
|
101
|
-
</div>
|
|
102
53
|
</section>
|
|
103
|
-
|
|
54
|
+
|
|
55
|
+
<section className="island-shell mt-8 rounded-2xl p-6">
|
|
56
|
+
<p className="island-kicker mb-2">Quick Start</p>
|
|
57
|
+
<ul className="m-0 list-disc space-y-2 pl-5 text-sm text-[var(--sea-ink-soft)]">
|
|
58
|
+
<li>
|
|
59
|
+
Edit <code>src/routes/index.tsx</code> to customize the hero and product narrative.
|
|
60
|
+
</li>
|
|
61
|
+
<li>
|
|
62
|
+
Update <code>src/components/Header.tsx</code> and <code>src/components/Footer.tsx</code>{' '}
|
|
63
|
+
for brand links.
|
|
64
|
+
</li>
|
|
65
|
+
<li>
|
|
66
|
+
Add routes in <code>src/routes</code> and tweak visual tokens in <code>src/styles.css</code>.
|
|
67
|
+
</li>
|
|
68
|
+
</ul>
|
|
69
|
+
</section>
|
|
70
|
+
</main>
|
|
104
71
|
);
|
|
105
72
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<% if (routerOnly) { ignoreFile() } %>
|
|
2
|
+
import { createFileRoute } from '@tanstack/react-router'
|
|
3
|
+
import { allBlogs } from 'content-collections'
|
|
4
|
+
import { SITE_DESCRIPTION, SITE_TITLE, SITE_URL } from '#/lib/site'
|
|
5
|
+
|
|
6
|
+
export const Route = createFileRoute('/rss.xml')({
|
|
7
|
+
server: {
|
|
8
|
+
handlers: {
|
|
9
|
+
GET: () => {
|
|
10
|
+
const posts = Array.from(
|
|
11
|
+
new Map(
|
|
12
|
+
[...allBlogs]
|
|
13
|
+
.sort((a, b) => new Date(b.pubDate).valueOf() - new Date(a.pubDate).valueOf())
|
|
14
|
+
.map((post) => [post.slug, post]),
|
|
15
|
+
).values(),
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
const items = posts
|
|
19
|
+
.map((post) => {
|
|
20
|
+
const url = `${SITE_URL}/blog/${post.slug}`
|
|
21
|
+
return `<item><title><![CDATA[${post.title}]]></title><description><![CDATA[${post.description}]]></description><link>${url}</link><guid>${url}</guid><pubDate>${new Date(post.pubDate).toUTCString()}</pubDate></item>`
|
|
22
|
+
})
|
|
23
|
+
.join('')
|
|
24
|
+
|
|
25
|
+
const xml = `<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title><![CDATA[${SITE_TITLE}]]></title><description><![CDATA[${SITE_DESCRIPTION}]]></description><link>${SITE_URL}</link>${items}</channel></rss>`
|
|
26
|
+
|
|
27
|
+
return new Response(xml, {
|
|
28
|
+
headers: {
|
|
29
|
+
'Content-Type': 'application/rss+xml; charset=utf-8',
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
})
|
|
@@ -1,15 +1,277 @@
|
|
|
1
|
+
@import url("https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500;9..144,700&family=Manrope:wght@400;500;600;700;800&display=swap");
|
|
1
2
|
@import "tailwindcss";
|
|
3
|
+
@plugin "@tailwindcss/typography";
|
|
4
|
+
|
|
5
|
+
@theme {
|
|
6
|
+
--font-sans: "Manrope", ui-sans-serif, system-ui, sans-serif;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
:root {
|
|
10
|
+
--sea-ink: #173a40;
|
|
11
|
+
--sea-ink-soft: #416166;
|
|
12
|
+
--lagoon: #4fb8b2;
|
|
13
|
+
--lagoon-deep: #328f97;
|
|
14
|
+
--palm: #2f6a4a;
|
|
15
|
+
--sand: #e7f0e8;
|
|
16
|
+
--foam: #f3faf5;
|
|
17
|
+
--surface: rgba(255, 255, 255, 0.74);
|
|
18
|
+
--surface-strong: rgba(255, 255, 255, 0.9);
|
|
19
|
+
--line: rgba(23, 58, 64, 0.14);
|
|
20
|
+
--inset-glint: rgba(255, 255, 255, 0.82);
|
|
21
|
+
--kicker: rgba(47, 106, 74, 0.9);
|
|
22
|
+
--bg-base: #e7f3ec;
|
|
23
|
+
--header-bg: rgba(251, 255, 248, 0.84);
|
|
24
|
+
--chip-bg: rgba(255, 255, 255, 0.8);
|
|
25
|
+
--chip-line: rgba(47, 106, 74, 0.18);
|
|
26
|
+
--link-bg-hover: rgba(255, 255, 255, 0.9);
|
|
27
|
+
--hero-a: rgba(79, 184, 178, 0.36);
|
|
28
|
+
--hero-b: rgba(47, 106, 74, 0.2);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
:root[data-theme="dark"] {
|
|
32
|
+
--sea-ink: #d7ece8;
|
|
33
|
+
--sea-ink-soft: #afcdc8;
|
|
34
|
+
--lagoon: #60d7cf;
|
|
35
|
+
--lagoon-deep: #8de5db;
|
|
36
|
+
--palm: #6ec89a;
|
|
37
|
+
--sand: #0f1a1e;
|
|
38
|
+
--foam: #101d22;
|
|
39
|
+
--surface: rgba(16, 30, 34, 0.8);
|
|
40
|
+
--surface-strong: rgba(15, 27, 31, 0.92);
|
|
41
|
+
--line: rgba(141, 229, 219, 0.18);
|
|
42
|
+
--inset-glint: rgba(194, 247, 238, 0.14);
|
|
43
|
+
--kicker: #b8efe5;
|
|
44
|
+
--bg-base: #0a1418;
|
|
45
|
+
--header-bg: rgba(10, 20, 24, 0.8);
|
|
46
|
+
--chip-bg: rgba(13, 28, 32, 0.9);
|
|
47
|
+
--chip-line: rgba(141, 229, 219, 0.24);
|
|
48
|
+
--link-bg-hover: rgba(24, 44, 49, 0.8);
|
|
49
|
+
--hero-a: rgba(96, 215, 207, 0.18);
|
|
50
|
+
--hero-b: rgba(110, 200, 154, 0.12);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@media (prefers-color-scheme: dark) {
|
|
54
|
+
:root:not([data-theme="light"]) {
|
|
55
|
+
--sea-ink: #d7ece8;
|
|
56
|
+
--sea-ink-soft: #afcdc8;
|
|
57
|
+
--lagoon: #60d7cf;
|
|
58
|
+
--lagoon-deep: #8de5db;
|
|
59
|
+
--palm: #6ec89a;
|
|
60
|
+
--sand: #0f1a1e;
|
|
61
|
+
--foam: #101d22;
|
|
62
|
+
--surface: rgba(16, 30, 34, 0.8);
|
|
63
|
+
--surface-strong: rgba(15, 27, 31, 0.92);
|
|
64
|
+
--line: rgba(141, 229, 219, 0.18);
|
|
65
|
+
--inset-glint: rgba(194, 247, 238, 0.14);
|
|
66
|
+
--kicker: #b8efe5;
|
|
67
|
+
--bg-base: #0a1418;
|
|
68
|
+
--header-bg: rgba(10, 20, 24, 0.8);
|
|
69
|
+
--chip-bg: rgba(13, 28, 32, 0.9);
|
|
70
|
+
--chip-line: rgba(141, 229, 219, 0.24);
|
|
71
|
+
--link-bg-hover: rgba(24, 44, 49, 0.8);
|
|
72
|
+
--hero-a: rgba(96, 215, 207, 0.18);
|
|
73
|
+
--hero-b: rgba(110, 200, 154, 0.12);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
* {
|
|
78
|
+
box-sizing: border-box;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
html,
|
|
82
|
+
body,
|
|
83
|
+
#app {
|
|
84
|
+
min-height: 100%;
|
|
85
|
+
}
|
|
2
86
|
|
|
3
87
|
body {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
88
|
+
margin: 0;
|
|
89
|
+
color: var(--sea-ink);
|
|
90
|
+
font-family: var(--font-sans);
|
|
91
|
+
background-color: var(--bg-base);
|
|
92
|
+
background:
|
|
93
|
+
radial-gradient(1100px 620px at -8% -10%, var(--hero-a), transparent 58%),
|
|
94
|
+
radial-gradient(1050px 620px at 112% -12%, var(--hero-b), transparent 62%),
|
|
95
|
+
radial-gradient(720px 380px at 50% 115%, rgba(79, 184, 178, 0.1), transparent 68%),
|
|
96
|
+
linear-gradient(180deg, color-mix(in oklab, var(--sand) 68%, white) 0%, var(--foam) 44%, var(--bg-base) 100%);
|
|
97
|
+
overflow-x: hidden;
|
|
8
98
|
-webkit-font-smoothing: antialiased;
|
|
9
99
|
-moz-osx-font-smoothing: grayscale;
|
|
10
100
|
}
|
|
11
101
|
|
|
102
|
+
body::before {
|
|
103
|
+
content: "";
|
|
104
|
+
position: fixed;
|
|
105
|
+
inset: 0;
|
|
106
|
+
pointer-events: none;
|
|
107
|
+
z-index: -1;
|
|
108
|
+
opacity: 0.28;
|
|
109
|
+
background:
|
|
110
|
+
radial-gradient(circle at 20% 15%, rgba(255, 255, 255, 0.8), transparent 34%),
|
|
111
|
+
radial-gradient(circle at 78% 26%, rgba(79, 184, 178, 0.2), transparent 42%),
|
|
112
|
+
radial-gradient(circle at 42% 82%, rgba(47, 106, 74, 0.14), transparent 36%);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
body::after {
|
|
116
|
+
content: "";
|
|
117
|
+
position: fixed;
|
|
118
|
+
inset: 0;
|
|
119
|
+
pointer-events: none;
|
|
120
|
+
z-index: -1;
|
|
121
|
+
opacity: 0.14;
|
|
122
|
+
background-image:
|
|
123
|
+
linear-gradient(rgba(255, 255, 255, 0.07) 1px, transparent 1px),
|
|
124
|
+
linear-gradient(90deg, rgba(255, 255, 255, 0.06) 1px, transparent 1px);
|
|
125
|
+
background-size: 28px 28px;
|
|
126
|
+
mask-image: radial-gradient(circle at 50% 30%, black, transparent 78%);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
a {
|
|
130
|
+
color: var(--lagoon-deep);
|
|
131
|
+
text-decoration-color: rgba(50, 143, 151, 0.4);
|
|
132
|
+
text-decoration-thickness: 1px;
|
|
133
|
+
text-underline-offset: 2px;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
a:hover {
|
|
137
|
+
color: #246f76;
|
|
138
|
+
}
|
|
139
|
+
|
|
12
140
|
code {
|
|
13
|
-
font-
|
|
14
|
-
|
|
141
|
+
font-size: 0.9em;
|
|
142
|
+
border: 1px solid var(--line);
|
|
143
|
+
background: color-mix(in oklab, var(--surface-strong) 82%, white 18%);
|
|
144
|
+
border-radius: 7px;
|
|
145
|
+
padding: 2px 7px;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
pre code {
|
|
149
|
+
border: 0;
|
|
150
|
+
background: transparent;
|
|
151
|
+
padding: 0;
|
|
152
|
+
border-radius: 0;
|
|
153
|
+
font-size: inherit;
|
|
154
|
+
color: inherit;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.prose pre {
|
|
158
|
+
border: 1px solid var(--line);
|
|
159
|
+
border-radius: 12px;
|
|
160
|
+
background: #1d2e45;
|
|
161
|
+
color: #e8efff;
|
|
162
|
+
overflow-x: auto;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.prose {
|
|
166
|
+
overflow-wrap: anywhere;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.prose table {
|
|
170
|
+
display: block;
|
|
171
|
+
width: 100%;
|
|
172
|
+
overflow-x: auto;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.page-wrap {
|
|
176
|
+
width: min(1080px, calc(100% - 2rem));
|
|
177
|
+
margin-inline: auto;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.display-title {
|
|
181
|
+
font-family: "Fraunces", Georgia, serif;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.island-shell {
|
|
185
|
+
border: 1px solid var(--line);
|
|
186
|
+
background: linear-gradient(165deg, var(--surface-strong), var(--surface));
|
|
187
|
+
box-shadow:
|
|
188
|
+
0 1px 0 var(--inset-glint) inset,
|
|
189
|
+
0 22px 44px rgba(30, 90, 72, 0.1),
|
|
190
|
+
0 6px 18px rgba(23, 58, 64, 0.08);
|
|
191
|
+
backdrop-filter: blur(4px);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.feature-card {
|
|
195
|
+
background: linear-gradient(165deg, color-mix(in oklab, var(--surface-strong) 93%, white 7%), var(--surface));
|
|
196
|
+
box-shadow:
|
|
197
|
+
0 1px 0 var(--inset-glint) inset,
|
|
198
|
+
0 18px 34px rgba(30, 90, 72, 0.1),
|
|
199
|
+
0 4px 14px rgba(23, 58, 64, 0.06);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.feature-card:hover {
|
|
203
|
+
transform: translateY(-2px);
|
|
204
|
+
border-color: color-mix(in oklab, var(--lagoon-deep) 35%, var(--line));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
button,
|
|
208
|
+
.island-shell,
|
|
209
|
+
a {
|
|
210
|
+
transition: background-color 180ms ease, color 180ms ease, border-color 180ms ease,
|
|
211
|
+
transform 180ms ease;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.island-kicker {
|
|
215
|
+
letter-spacing: 0.16em;
|
|
216
|
+
text-transform: uppercase;
|
|
217
|
+
font-weight: 700;
|
|
218
|
+
font-size: 0.69rem;
|
|
219
|
+
color: var(--kicker);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.nav-link {
|
|
223
|
+
position: relative;
|
|
224
|
+
display: inline-flex;
|
|
225
|
+
align-items: center;
|
|
226
|
+
text-decoration: none;
|
|
227
|
+
color: var(--sea-ink-soft);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.nav-link::after {
|
|
231
|
+
content: "";
|
|
232
|
+
position: absolute;
|
|
233
|
+
left: 0;
|
|
234
|
+
bottom: -6px;
|
|
235
|
+
width: 100%;
|
|
236
|
+
height: 2px;
|
|
237
|
+
transform: scaleX(0);
|
|
238
|
+
transform-origin: left;
|
|
239
|
+
background: linear-gradient(90deg, var(--lagoon), #7ed3bf);
|
|
240
|
+
transition: transform 170ms ease;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.nav-link:hover,
|
|
244
|
+
.nav-link.is-active {
|
|
245
|
+
color: var(--sea-ink);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.nav-link:hover::after,
|
|
249
|
+
.nav-link.is-active::after {
|
|
250
|
+
transform: scaleX(1);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
@media (max-width: 640px) {
|
|
254
|
+
.nav-link::after {
|
|
255
|
+
bottom: -4px;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.site-footer {
|
|
260
|
+
border-top: 1px solid var(--line);
|
|
261
|
+
background: color-mix(in oklab, var(--header-bg) 84%, transparent 16%);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.rise-in {
|
|
265
|
+
animation: rise-in 700ms cubic-bezier(0.16, 1, 0.3, 1) both;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
@keyframes rise-in {
|
|
269
|
+
from {
|
|
270
|
+
opacity: 0;
|
|
271
|
+
transform: translateY(12px);
|
|
272
|
+
}
|
|
273
|
+
to {
|
|
274
|
+
opacity: 1;
|
|
275
|
+
transform: translateY(0);
|
|
276
|
+
}
|
|
15
277
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defineConfig } from 'vite'
|
|
2
2
|
import { devtools } from '@tanstack/devtools-vite'
|
|
3
|
+
import contentCollections from '@content-collections/vite'
|
|
3
4
|
import tsconfigPaths from 'vite-tsconfig-paths'
|
|
4
5
|
<% if (addOnEnabled.paraglide) { -%>
|
|
5
6
|
import { paraglideVitePlugin } from "@inlang/paraglide-js"
|
|
@@ -20,6 +21,7 @@ const config = defineConfig({
|
|
|
20
21
|
outdir: './src/paraglide',
|
|
21
22
|
strategy: ['url', "baseLocale"],
|
|
22
23
|
}), <% } %><% for(const integration of integrations.filter(i => i.type === 'vite-plugin')) { %><%- integrationImportCode(integration) %>,<% } %>
|
|
24
|
+
contentCollections(),
|
|
23
25
|
tsconfigPaths({ projects: ['./tsconfig.json'] }),
|
|
24
26
|
tailwindcss(),
|
|
25
27
|
<% if (routerOnly) { %>tanstackRouter({ target: 'react', autoCodeSplitting: true }),<% } else { %>tanstackStart(),<% } %>
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Store } from '@tanstack/store'
|
|
2
2
|
|
|
3
3
|
export const store = new Store({
|
|
4
4
|
firstName: 'Jane',
|
|
5
5
|
lastName: 'Smith',
|
|
6
6
|
})
|
|
7
7
|
|
|
8
|
-
export const fullName = new
|
|
9
|
-
fn: () => `${store.state.firstName} ${store.state.lastName}`,
|
|
10
|
-
deps: [store],
|
|
11
|
-
})
|
|
8
|
+
export const fullName = new Store(`${store.state.firstName} ${store.state.lastName}`)
|
|
12
9
|
|
|
13
|
-
|
|
10
|
+
store.subscribe(() => {
|
|
11
|
+
fullName.setState(() => `${store.state.firstName} ${store.state.lastName}`)
|
|
12
|
+
})
|
|
@@ -43,7 +43,7 @@ function FullName() {
|
|
|
43
43
|
const fName = useStore(fullName)
|
|
44
44
|
return (
|
|
45
45
|
<div class="bg-white/10 rounded-lg px-4 py-2 outline-none ">
|
|
46
|
-
{fName}
|
|
46
|
+
{fName()}
|
|
47
47
|
</div>
|
|
48
48
|
)
|
|
49
49
|
}
|
|
@@ -74,4 +74,4 @@ export default (parentRoute: RootRoute) => createRoute({
|
|
|
74
74
|
getParentRoute: () => parentRoute,
|
|
75
75
|
})
|
|
76
76
|
<% } %>
|
|
77
|
-
|
|
77
|
+
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Store } from '@tanstack/store'
|
|
2
2
|
|
|
3
3
|
export const store = new Store({
|
|
4
4
|
firstName: 'Jane',
|
|
5
5
|
lastName: 'Smith',
|
|
6
6
|
})
|
|
7
7
|
|
|
8
|
-
export const fullName = new
|
|
9
|
-
fn: () => `${store.state.firstName} ${store.state.lastName}`,
|
|
10
|
-
deps: [store],
|
|
11
|
-
})
|
|
8
|
+
export const fullName = new Store(`${store.state.firstName} ${store.state.lastName}`)
|
|
12
9
|
|
|
13
|
-
|
|
10
|
+
store.subscribe(() => {
|
|
11
|
+
fullName.setState(() => `${store.state.firstName} ${store.state.lastName}`)
|
|
12
|
+
})
|