@tanstack/create 0.61.6 → 0.62.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -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
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @tanstack/create
|
|
2
2
|
|
|
3
|
+
## 0.62.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Bump `@content-collections/mdx` in the React base template to `^0.2.2` so new projects install cleanly with React 19. ([`b54e202`](https://github.com/TanStack/cli/commit/b54e202ce56f2aa78a416634155bc22f0cb5cc46))
|
|
8
|
+
|
|
9
|
+
## 0.62.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- This release pulls together a large batch of improvements across the CLI and scaffolding engine since the last versioning pass. ([`154b25e`](https://github.com/TanStack/cli/commit/154b25eec9a13b9718c44cbed6cb3c8566f2fb11))
|
|
14
|
+
|
|
15
|
+
- Modernizes and refreshes the generated React/Solid template experience, including updated starter content and stronger defaults.
|
|
16
|
+
- Improves create flows with better option normalization, stronger guardrails around target directories, and clearer compatibility behavior in router-only mode.
|
|
17
|
+
- Expands scaffolding ergonomics with examples toggles, improved add-on/config handling, and reliability fixes across package-manager and cross-platform paths.
|
|
18
|
+
- Strengthens test and release confidence via e2e/release workflow hardening and broader smoke coverage.
|
|
19
|
+
- Streamlines product surface area by removing the local `create-ui` package and `--ui` command paths from the CLI; visual setup now lives at `https://tanstack.com/builder`.
|
|
20
|
+
- Cleans up docs and custom CLI examples to match the current terminal-first workflow and Builder guidance.
|
|
21
|
+
|
|
3
22
|
## 0.61.6
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/dist/config-file.js
CHANGED
|
@@ -23,8 +23,8 @@ export async function readConfigFileFromEnvironment(environment, targetDir) {
|
|
|
23
23
|
const originalJSON = JSON.parse(config);
|
|
24
24
|
// Look for markers out outdated config files and upgrade the format on the fly (it will be written in the updated version after we add add-ons)
|
|
25
25
|
if (originalJSON.existingAddOns) {
|
|
26
|
-
if (originalJSON.framework === 'react') {
|
|
27
|
-
originalJSON.framework = 'react
|
|
26
|
+
if (originalJSON.framework === 'react-cra') {
|
|
27
|
+
originalJSON.framework = 'react';
|
|
28
28
|
}
|
|
29
29
|
originalJSON.chosenAddOns = originalJSON.existingAddOns;
|
|
30
30
|
delete originalJSON.existingAddOns;
|
|
@@ -35,6 +35,9 @@ export async function readConfigFileFromEnvironment(environment, targetDir) {
|
|
|
35
35
|
delete originalJSON.toolchain;
|
|
36
36
|
delete originalJSON.variableValues;
|
|
37
37
|
}
|
|
38
|
+
if (originalJSON.framework === 'react-cra') {
|
|
39
|
+
originalJSON.framework = 'react';
|
|
40
|
+
}
|
|
38
41
|
return originalJSON;
|
|
39
42
|
}
|
|
40
43
|
catch {
|
|
@@ -4,33 +4,37 @@ import { resolve } from 'node:path';
|
|
|
4
4
|
import { StarterCompiledSchema } from '../types.js';
|
|
5
5
|
import { createIgnore } from '../file-helpers.js';
|
|
6
6
|
import { compareFilesRecursively, createAppOptionsFromPersisted, createPackageAdditions, readCurrentProjectOptions, runCreateApp, } from './shared.js';
|
|
7
|
-
const INFO_FILE = '
|
|
8
|
-
const
|
|
7
|
+
const INFO_FILE = 'template-info.json';
|
|
8
|
+
const LEGACY_INFO_FILE = 'starter-info.json';
|
|
9
|
+
const COMPILED_FILE = 'template.json';
|
|
10
|
+
const LEGACY_COMPILED_FILE = 'starter.json';
|
|
9
11
|
export async function readOrGenerateStarterInfo(options) {
|
|
10
12
|
const info = existsSync(INFO_FILE)
|
|
11
13
|
? JSON.parse((await readFile(INFO_FILE)).toString())
|
|
12
|
-
:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
14
|
+
: existsSync(LEGACY_INFO_FILE)
|
|
15
|
+
? JSON.parse((await readFile(LEGACY_INFO_FILE)).toString())
|
|
16
|
+
: {
|
|
17
|
+
id: `${options.projectName}-template`,
|
|
18
|
+
name: `${options.projectName} Template`,
|
|
19
|
+
version: '0.0.1',
|
|
20
|
+
description: 'Project template',
|
|
21
|
+
author: 'Jane Smith <jane.smith@example.com>',
|
|
22
|
+
license: 'MIT',
|
|
23
|
+
link: `https://github.com/jane-smith/${options.projectName}-template`,
|
|
24
|
+
shadcnComponents: [],
|
|
25
|
+
framework: options.framework,
|
|
26
|
+
mode: options.mode,
|
|
27
|
+
routes: [],
|
|
28
|
+
warning: '',
|
|
29
|
+
type: 'starter',
|
|
30
|
+
packageAdditions: {
|
|
31
|
+
scripts: {},
|
|
32
|
+
dependencies: {},
|
|
33
|
+
devDependencies: {},
|
|
34
|
+
},
|
|
35
|
+
dependsOn: options.chosenAddOns,
|
|
36
|
+
typescript: true,
|
|
37
|
+
};
|
|
34
38
|
if (!info.version) {
|
|
35
39
|
info.version = '0.0.1';
|
|
36
40
|
}
|
|
@@ -44,8 +48,13 @@ async function loadCurrentStarterInfo(environment) {
|
|
|
44
48
|
}
|
|
45
49
|
export async function updateStarterInfo(environment) {
|
|
46
50
|
const { info, output } = await loadCurrentStarterInfo(environment);
|
|
47
|
-
|
|
51
|
+
const generatedPackageJson = output.files['./package.json'] ?? output.files['package.json'];
|
|
52
|
+
if (!generatedPackageJson) {
|
|
53
|
+
throw new Error('Unable to find generated package.json in template output');
|
|
54
|
+
}
|
|
55
|
+
info.packageAdditions = createPackageAdditions(JSON.parse(generatedPackageJson), JSON.parse((await readFile('package.json')).toString()));
|
|
48
56
|
writeFileSync(INFO_FILE, JSON.stringify(info, null, 2));
|
|
57
|
+
writeFileSync(LEGACY_INFO_FILE, JSON.stringify(info, null, 2));
|
|
49
58
|
}
|
|
50
59
|
export async function compileStarter(environment) {
|
|
51
60
|
const { info, output } = await loadCurrentStarterInfo(environment);
|
|
@@ -64,20 +73,28 @@ export async function compileStarter(environment) {
|
|
|
64
73
|
deletedFiles,
|
|
65
74
|
};
|
|
66
75
|
writeFileSync(COMPILED_FILE, JSON.stringify(compiledInfo, null, 2));
|
|
76
|
+
writeFileSync(LEGACY_COMPILED_FILE, JSON.stringify(compiledInfo, null, 2));
|
|
67
77
|
}
|
|
68
78
|
export async function initStarter(environment) {
|
|
69
79
|
await updateStarterInfo(environment);
|
|
70
80
|
await compileStarter(environment);
|
|
71
81
|
}
|
|
72
82
|
export async function loadStarter(url) {
|
|
73
|
-
const
|
|
74
|
-
const
|
|
83
|
+
const absoluteLocalPath = resolve(process.cwd(), url);
|
|
84
|
+
const localPath = existsSync(url)
|
|
85
|
+
? url
|
|
86
|
+
: existsSync(absoluteLocalPath)
|
|
87
|
+
? absoluteLocalPath
|
|
88
|
+
: undefined;
|
|
89
|
+
const jsonContent = localPath
|
|
90
|
+
? JSON.parse((await readFile(localPath)).toString())
|
|
91
|
+
: await (await fetch(url)).json();
|
|
75
92
|
const checked = StarterCompiledSchema.safeParse(jsonContent);
|
|
76
93
|
if (!checked.success) {
|
|
77
94
|
throw new Error(`Invalid starter: ${url}`);
|
|
78
95
|
}
|
|
79
96
|
const starter = checked.data;
|
|
80
|
-
starter.id = url;
|
|
97
|
+
starter.id = localPath ?? url;
|
|
81
98
|
return {
|
|
82
99
|
...starter,
|
|
83
100
|
getFiles: () => Promise.resolve(Object.keys(starter.files)),
|
package/dist/file-helpers.js
CHANGED
|
@@ -1,24 +1,32 @@
|
|
|
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';
|
|
2
4
|
|
|
3
5
|
@import 'tw-animate-css';
|
|
4
6
|
|
|
5
7
|
@custom-variant dark (&:is(.dark *));
|
|
6
8
|
|
|
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
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
|
+
|
|
22
30
|
--background: oklch(1 0 0);
|
|
23
31
|
--foreground: oklch(0.141 0.005 285.823);
|
|
24
32
|
--card: oklch(1 0 0);
|
|
@@ -55,6 +63,26 @@ code {
|
|
|
55
63
|
}
|
|
56
64
|
|
|
57
65
|
.dark {
|
|
66
|
+
--sea-ink: #d7ece8;
|
|
67
|
+
--sea-ink-soft: #afcdc8;
|
|
68
|
+
--lagoon: #60d7cf;
|
|
69
|
+
--lagoon-deep: #8de5db;
|
|
70
|
+
--palm: #6ec89a;
|
|
71
|
+
--sand: #0f1a1e;
|
|
72
|
+
--foam: #101d22;
|
|
73
|
+
--surface: rgba(16, 30, 34, 0.8);
|
|
74
|
+
--surface-strong: rgba(15, 27, 31, 0.92);
|
|
75
|
+
--line: rgba(141, 229, 219, 0.18);
|
|
76
|
+
--inset-glint: rgba(194, 247, 238, 0.14);
|
|
77
|
+
--kicker: #b8efe5;
|
|
78
|
+
--bg-base: #0a1418;
|
|
79
|
+
--header-bg: rgba(10, 20, 24, 0.8);
|
|
80
|
+
--chip-bg: rgba(13, 28, 32, 0.9);
|
|
81
|
+
--chip-line: rgba(141, 229, 219, 0.24);
|
|
82
|
+
--link-bg-hover: rgba(24, 44, 49, 0.8);
|
|
83
|
+
--hero-a: rgba(96, 215, 207, 0.18);
|
|
84
|
+
--hero-b: rgba(110, 200, 154, 0.12);
|
|
85
|
+
|
|
58
86
|
--background: oklch(0.141 0.005 285.823);
|
|
59
87
|
--foreground: oklch(0.985 0 0);
|
|
60
88
|
--card: oklch(0.141 0.005 285.823);
|
|
@@ -90,6 +118,7 @@ code {
|
|
|
90
118
|
}
|
|
91
119
|
|
|
92
120
|
@theme inline {
|
|
121
|
+
--font-sans: 'Manrope', ui-sans-serif, system-ui, sans-serif;
|
|
93
122
|
--color-background: var(--background);
|
|
94
123
|
--color-foreground: var(--foreground);
|
|
95
124
|
--color-card: var(--card);
|
|
@@ -128,11 +157,191 @@ code {
|
|
|
128
157
|
--color-sidebar-ring: var(--sidebar-ring);
|
|
129
158
|
}
|
|
130
159
|
|
|
160
|
+
html,
|
|
161
|
+
body,
|
|
162
|
+
#app {
|
|
163
|
+
min-height: 100%;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
body {
|
|
167
|
+
margin: 0;
|
|
168
|
+
color: var(--sea-ink);
|
|
169
|
+
font-family: var(--font-sans);
|
|
170
|
+
background-color: var(--bg-base);
|
|
171
|
+
background:
|
|
172
|
+
radial-gradient(1100px 620px at -8% -10%, var(--hero-a), transparent 58%),
|
|
173
|
+
radial-gradient(1050px 620px at 112% -12%, var(--hero-b), transparent 62%),
|
|
174
|
+
radial-gradient(720px 380px at 50% 115%, rgba(79, 184, 178, 0.1), transparent 68%),
|
|
175
|
+
linear-gradient(180deg, color-mix(in oklab, var(--sand) 68%, white) 0%, var(--foam) 44%, var(--bg-base) 100%);
|
|
176
|
+
overflow-x: hidden;
|
|
177
|
+
-webkit-font-smoothing: antialiased;
|
|
178
|
+
-moz-osx-font-smoothing: grayscale;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
body::before {
|
|
182
|
+
content: '';
|
|
183
|
+
position: fixed;
|
|
184
|
+
inset: 0;
|
|
185
|
+
pointer-events: none;
|
|
186
|
+
z-index: -1;
|
|
187
|
+
opacity: 0.28;
|
|
188
|
+
background:
|
|
189
|
+
radial-gradient(circle at 20% 15%, rgba(255, 255, 255, 0.8), transparent 34%),
|
|
190
|
+
radial-gradient(circle at 78% 26%, rgba(79, 184, 178, 0.2), transparent 42%),
|
|
191
|
+
radial-gradient(circle at 42% 82%, rgba(47, 106, 74, 0.14), transparent 36%);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
body::after {
|
|
195
|
+
content: '';
|
|
196
|
+
position: fixed;
|
|
197
|
+
inset: 0;
|
|
198
|
+
pointer-events: none;
|
|
199
|
+
z-index: -1;
|
|
200
|
+
opacity: 0.14;
|
|
201
|
+
background-image:
|
|
202
|
+
linear-gradient(rgba(255, 255, 255, 0.07) 1px, transparent 1px),
|
|
203
|
+
linear-gradient(90deg, rgba(255, 255, 255, 0.06) 1px, transparent 1px);
|
|
204
|
+
background-size: 28px 28px;
|
|
205
|
+
mask-image: radial-gradient(circle at 50% 30%, black, transparent 78%);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
a {
|
|
209
|
+
color: var(--lagoon-deep);
|
|
210
|
+
text-decoration-color: rgba(50, 143, 151, 0.4);
|
|
211
|
+
text-decoration-thickness: 1px;
|
|
212
|
+
text-underline-offset: 2px;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
a:hover {
|
|
216
|
+
color: #246f76;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
code {
|
|
220
|
+
font-size: 0.9em;
|
|
221
|
+
border: 1px solid var(--line);
|
|
222
|
+
background: color-mix(in oklab, var(--surface-strong) 82%, white 18%);
|
|
223
|
+
border-radius: 7px;
|
|
224
|
+
padding: 2px 7px;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
pre code {
|
|
228
|
+
border: 0;
|
|
229
|
+
background: transparent;
|
|
230
|
+
padding: 0;
|
|
231
|
+
border-radius: 0;
|
|
232
|
+
font-size: inherit;
|
|
233
|
+
color: inherit;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.prose pre {
|
|
237
|
+
border: 1px solid var(--line);
|
|
238
|
+
border-radius: 12px;
|
|
239
|
+
background: #1d2e45;
|
|
240
|
+
color: #e8efff;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.page-wrap {
|
|
244
|
+
width: min(1080px, calc(100% - 2rem));
|
|
245
|
+
margin-inline: auto;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.display-title {
|
|
249
|
+
font-family: 'Fraunces', Georgia, serif;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.island-shell {
|
|
253
|
+
border: 1px solid var(--line);
|
|
254
|
+
background: linear-gradient(165deg, var(--surface-strong), var(--surface));
|
|
255
|
+
box-shadow:
|
|
256
|
+
0 1px 0 var(--inset-glint) inset,
|
|
257
|
+
0 22px 44px rgba(30, 90, 72, 0.1),
|
|
258
|
+
0 6px 18px rgba(23, 58, 64, 0.08);
|
|
259
|
+
backdrop-filter: blur(4px);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.feature-card {
|
|
263
|
+
background: linear-gradient(165deg, color-mix(in oklab, var(--surface-strong) 93%, white 7%), var(--surface));
|
|
264
|
+
box-shadow:
|
|
265
|
+
0 1px 0 var(--inset-glint) inset,
|
|
266
|
+
0 18px 34px rgba(30, 90, 72, 0.1),
|
|
267
|
+
0 4px 14px rgba(23, 58, 64, 0.06);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.feature-card:hover {
|
|
271
|
+
transform: translateY(-2px);
|
|
272
|
+
border-color: color-mix(in oklab, var(--lagoon-deep) 35%, var(--line));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
button,
|
|
276
|
+
.island-shell,
|
|
277
|
+
a {
|
|
278
|
+
transition: background-color 180ms ease, color 180ms ease, border-color 180ms ease,
|
|
279
|
+
transform 180ms ease;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.island-kicker {
|
|
283
|
+
letter-spacing: 0.16em;
|
|
284
|
+
text-transform: uppercase;
|
|
285
|
+
font-weight: 700;
|
|
286
|
+
font-size: 0.69rem;
|
|
287
|
+
color: var(--kicker);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.nav-link {
|
|
291
|
+
position: relative;
|
|
292
|
+
text-decoration: none;
|
|
293
|
+
color: var(--sea-ink-soft);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.nav-link::after {
|
|
297
|
+
content: '';
|
|
298
|
+
position: absolute;
|
|
299
|
+
left: 0;
|
|
300
|
+
bottom: -8px;
|
|
301
|
+
width: 100%;
|
|
302
|
+
height: 2px;
|
|
303
|
+
transform: scaleX(0);
|
|
304
|
+
transform-origin: left;
|
|
305
|
+
background: linear-gradient(90deg, var(--lagoon), #7ed3bf);
|
|
306
|
+
transition: transform 170ms ease;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.nav-link:hover,
|
|
310
|
+
.nav-link.is-active {
|
|
311
|
+
color: var(--sea-ink);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.nav-link:hover::after,
|
|
315
|
+
.nav-link.is-active::after {
|
|
316
|
+
transform: scaleX(1);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.rise-in {
|
|
320
|
+
animation: rise-in 700ms cubic-bezier(0.16, 1, 0.3, 1) both;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
@keyframes rise-in {
|
|
324
|
+
from {
|
|
325
|
+
opacity: 0;
|
|
326
|
+
transform: translateY(12px);
|
|
327
|
+
}
|
|
328
|
+
to {
|
|
329
|
+
opacity: 1;
|
|
330
|
+
transform: translateY(0);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.site-footer {
|
|
335
|
+
border-top: 1px solid var(--line);
|
|
336
|
+
background: color-mix(in oklab, var(--header-bg) 84%, transparent 16%);
|
|
337
|
+
}
|
|
338
|
+
|
|
131
339
|
@layer base {
|
|
132
340
|
* {
|
|
133
341
|
@apply border-border outline-ring/50;
|
|
134
342
|
}
|
|
135
343
|
body {
|
|
136
|
-
|
|
344
|
+
background-color: var(--background);
|
|
345
|
+
color: var(--foreground);
|
|
137
346
|
}
|
|
138
347
|
}
|
|
@@ -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
|
+
})
|
|
@@ -11,9 +11,9 @@ export function createFrameworkDefinition() {
|
|
|
11
11
|
]);
|
|
12
12
|
const { files, basePackageJSON, optionalPackages } = scanProjectDirectory(join(baseDirectory, 'project'), join(baseDirectory, 'project/base'));
|
|
13
13
|
return {
|
|
14
|
-
id: 'react
|
|
14
|
+
id: 'react',
|
|
15
15
|
name: 'React',
|
|
16
|
-
description: 'Templates for React
|
|
16
|
+
description: 'Templates for React',
|
|
17
17
|
version: '0.1.0',
|
|
18
18
|
base: files,
|
|
19
19
|
addOns,
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'Velvet Runtime Notes'
|
|
3
|
+
description: 'Use color tokens to keep light and dark themes aligned.'
|
|
4
|
+
pubDate: 'Aug 05 2024'
|
|
5
|
+
heroImage: '/images/lagoon-5.svg'
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Semantic tokens keep your UI stable while the brand evolves.
|
|
9
|
+
|
|
10
|
+
Instead of hard-coding one-off colors in components, shape a small set of
|
|
11
|
+
variables and map all surfaces to those variables.
|
|
12
|
+
|
|
13
|
+
## Why this matters
|
|
14
|
+
|
|
15
|
+
- You can restyle the app in minutes instead of days
|
|
16
|
+
- Light and dark themes stay behaviorally consistent
|
|
17
|
+
- Add-on pages inherit your visual identity by default
|
|
18
|
+
|
|
19
|
+
<MdxCallout title="MDX Component Demo">
|
|
20
|
+
This callout is rendered from JSX inside an MDX post. It is useful for
|
|
21
|
+
release notes, warnings, and migration tips where you want stronger visual
|
|
22
|
+
emphasis than plain markdown blocks.
|
|
23
|
+
</MdxCallout>
|
|
24
|
+
|
|
25
|
+
<MdxMetrics
|
|
26
|
+
items={[
|
|
27
|
+
{ label: 'Token count', value: '12 core vars' },
|
|
28
|
+
{ label: 'Theme modes', value: 'light + dark + auto' },
|
|
29
|
+
{ label: 'Restyle time', value: '< 30 min' },
|
|
30
|
+
]}
|
|
31
|
+
/>
|
|
32
|
+
|
|
33
|
+
### Token-to-component mapping
|
|
34
|
+
|
|
35
|
+
| Token | Typical usage |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| `--surface` | Card backgrounds |
|
|
38
|
+
| `--line` | Borders and separators |
|
|
39
|
+
| `--lagoon-deep` | Links and active nav |
|
|
40
|
+
|
|
41
|
+
Keep the mapping documented and your team will make fewer ad-hoc styling calls.
|
|
42
|
+
|
|
43
|
+
### Example: deriving UI from semantic tokens
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
const button = {
|
|
47
|
+
color: 'var(--sea-ink)',
|
|
48
|
+
background: 'var(--surface)',
|
|
49
|
+
borderColor: 'var(--line)',
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
MDX is useful here because you can interleave narrative, tables, code blocks,
|
|
54
|
+
and custom JSX components in one authoring surface.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'Neon Mango Protocol'
|
|
3
|
+
description: 'A quick walkthrough of the starter foundations.'
|
|
4
|
+
pubDate: 'Jul 08 2024'
|
|
5
|
+
heroImage: '/images/lagoon-3.svg'
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
This starter ships with routes, SSR, and a calm visual system out of the box.
|
|
9
|
+
|
|
10
|
+
Start by editing route files, then layer in add-ons as needed.
|
|
11
|
+
|
|
12
|
+
## What you get on day one
|
|
13
|
+
|
|
14
|
+
- Full-document SSR using TanStack Start
|
|
15
|
+
- Type-safe file routing with generated route types
|
|
16
|
+
- A reusable design token system for light and dark themes
|
|
17
|
+
|
|
18
|
+
The goal is simple: let teams ship product pages and APIs without spending the
|
|
19
|
+
first week wiring framework internals.
|
|
20
|
+
|
|
21
|
+
### Suggested order of operations
|
|
22
|
+
|
|
23
|
+
1. Make the home route feel like your product
|
|
24
|
+
2. Add one feature route and one API route
|
|
25
|
+
3. Introduce add-ons only after your core UX is clear
|
|
26
|
+
|
|
27
|
+
> Keep the first commit boring. Reliable defaults beat clever setup code.
|
|
28
|
+
|
|
29
|
+
## Baseline delivery checklist
|
|
30
|
+
|
|
31
|
+
Before introducing custom infra, confirm these are green:
|
|
32
|
+
|
|
33
|
+
- `pnpm dev` starts cleanly
|
|
34
|
+
- one server route returns typed data
|
|
35
|
+
- one API route validates input/output
|
|
36
|
+
- one integration test exercises a full page render
|
|
37
|
+
|
|
38
|
+
When these are in place, you can iterate quickly without losing confidence.
|
|
39
|
+
|
|
40
|
+
### Example request flow
|
|
41
|
+
|
|
42
|
+
1. Client navigation enters route loader
|
|
43
|
+
2. Loader calls server function
|
|
44
|
+
3. Server function reads data source and returns typed payload
|
|
45
|
+
4. Route component renders immediately with stable shape
|
|
46
|
+
|
|
47
|
+
That flow is simple, predictable, and easy to debug.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'Static Tide Almanac'
|
|
3
|
+
description: 'Dial in layout polish and image rhythm across cards.'
|
|
4
|
+
pubDate: 'Jul 29 2024'
|
|
5
|
+
heroImage: '/images/lagoon-1.svg'
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
As your app grows, visual rhythm matters as much as feature scope.
|
|
9
|
+
|
|
10
|
+
Use larger feature cards to call attention to primary content, then support with
|
|
11
|
+
smaller cards for secondary updates.
|
|
12
|
+
|
|
13
|
+
## Practical layout pattern
|
|
14
|
+
|
|
15
|
+
Use one featured card followed by standard cards in a responsive grid:
|
|
16
|
+
|
|
17
|
+
- `lg:col-span-2` for the featured story
|
|
18
|
+
- regular span for supporting posts
|
|
19
|
+
- consistent card media height below `lg`
|
|
20
|
+
|
|
21
|
+
That gives you hierarchy without reinventing every breakpoint.
|
|
22
|
+
|
|
23
|
+
### A quick spacing rule
|
|
24
|
+
|
|
25
|
+
Pair spacing in steps of 4 (`p-4`, `p-8`, `gap-4`, `gap-8`) and only break that
|
|
26
|
+
rule for hero sections.
|
|
27
|
+
|
|
28
|
+
## Card hierarchy recipe
|
|
29
|
+
|
|
30
|
+
For content-heavy indexes, this sequence works well:
|
|
31
|
+
|
|
32
|
+
1. One featured card with expanded width
|
|
33
|
+
2. Three to six standard cards for breadth
|
|
34
|
+
3. Optional utility card for onboarding links
|
|
35
|
+
|
|
36
|
+
Keep title sizes mostly consistent and let width + image treatment carry
|
|
37
|
+
hierarchy. That avoids jarring jumps as breakpoints shift.
|
|
38
|
+
|
|
39
|
+
### Avoiding layout drift
|
|
40
|
+
|
|
41
|
+
If cards start to look uneven, check image heights first, then paragraph length.
|
|
42
|
+
Consistency there usually fixes 80% of visual noise.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'Paper Lantern Cache'
|
|
3
|
+
description: 'How to shape navigation and page structure.'
|
|
4
|
+
pubDate: 'Jul 15 2024'
|
|
5
|
+
heroImage: '/images/lagoon-4.svg'
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Use file-based routes in `src/routes` to grow the app.
|
|
9
|
+
|
|
10
|
+
Keep shared UI in `src/components` and tune visual tokens in `src/styles.css`.
|
|
11
|
+
|
|
12
|
+
## Route design tips
|
|
13
|
+
|
|
14
|
+
Treat routes like product domains, not technical buckets.
|
|
15
|
+
|
|
16
|
+
- `routes/settings.*` for account surfaces
|
|
17
|
+
- `routes/billing.*` for payment and plan logic
|
|
18
|
+
- `routes/api.*` for server handlers that belong to the same domain
|
|
19
|
+
|
|
20
|
+
When route trees map to business intent, onboarding gets faster and refactors
|
|
21
|
+
hurt less.
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
// src/routes/billing.index.tsx
|
|
25
|
+
export const Route = createFileRoute('/billing/')({
|
|
26
|
+
component: BillingPage,
|
|
27
|
+
})
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
<MdxMetrics
|
|
31
|
+
items={[
|
|
32
|
+
{ label: 'Route setup', value: '~10 min' },
|
|
33
|
+
{ label: 'Type safety', value: 'end-to-end' },
|
|
34
|
+
{ label: 'Refactor risk', value: 'lowered' },
|
|
35
|
+
]}
|
|
36
|
+
/>
|
|
37
|
+
|
|
38
|
+
### Collaboration pattern
|
|
39
|
+
|
|
40
|
+
Use this lightweight ownership split:
|
|
41
|
+
|
|
42
|
+
1. Product owns route naming and URL intent
|
|
43
|
+
2. Design owns shared layout primitives and tokens
|
|
44
|
+
3. Engineering owns loaders, actions, and caching
|
|
45
|
+
|
|
46
|
+
This pattern keeps URL design, data loading, and UI composition in one place.
|