create-newt-app 0.32.1 → 0.33.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/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1448 -176
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { existsSync, promises } from "fs";
|
|
|
11
11
|
import path from "path";
|
|
12
12
|
import https from "node:https";
|
|
13
13
|
//#region package.json
|
|
14
|
-
var version = "0.
|
|
14
|
+
var version = "0.33.1";
|
|
15
15
|
var engines = { "node": ">=24.0.0" };
|
|
16
16
|
//#endregion
|
|
17
17
|
//#region src/templates/root/index.ts
|
|
@@ -231,7 +231,7 @@ This version has breaking changes — APIs, conventions, and file structure may
|
|
|
231
231
|
const web$1 = {
|
|
232
232
|
templates: [
|
|
233
233
|
{
|
|
234
|
-
when: (s) => s.nest !== "di-only",
|
|
234
|
+
when: (s) => s.nest !== "di-only" && !s.stylex,
|
|
235
235
|
filename: "apps/web/package.json",
|
|
236
236
|
template: `{
|
|
237
237
|
"name": "web",
|
|
@@ -369,6 +369,7 @@ const nextConfig = {
|
|
|
369
369
|
export default nextConfig;`
|
|
370
370
|
},
|
|
371
371
|
{
|
|
372
|
+
when: (s) => !s.stylex,
|
|
372
373
|
filename: "apps/web/postcss.config.mjs",
|
|
373
374
|
template: `export { default } from "@<%= projectName %>/ui/postcss.config";`
|
|
374
375
|
},
|
|
@@ -399,7 +400,7 @@ export default nextConfig;`
|
|
|
399
400
|
}`
|
|
400
401
|
},
|
|
401
402
|
{
|
|
402
|
-
when: (s) => !s.shadcn,
|
|
403
|
+
when: (s) => !s.shadcn && !s.stylex,
|
|
403
404
|
filename: "apps/web/app/layout.tsx",
|
|
404
405
|
template: `import type { Metadata } from "next";
|
|
405
406
|
import localFont from "next/font/local";
|
|
@@ -442,7 +443,7 @@ export default function RootLayout({
|
|
|
442
443
|
}`
|
|
443
444
|
},
|
|
444
445
|
{
|
|
445
|
-
when: (s) => !s.todoExample && !s.shadcn,
|
|
446
|
+
when: (s) => !s.todoExample && !s.shadcn && !s.stylex,
|
|
446
447
|
filename: "apps/web/app/page.tsx",
|
|
447
448
|
template: `'use client';
|
|
448
449
|
|
|
@@ -543,7 +544,7 @@ export default function Providers({ children }: { children: React.ReactNode }) {
|
|
|
543
544
|
}`
|
|
544
545
|
},
|
|
545
546
|
{
|
|
546
|
-
when: (s) => !s.shadcn,
|
|
547
|
+
when: (s) => !s.shadcn && !s.stylex,
|
|
547
548
|
filename: "apps/web/app/auth-form.tsx",
|
|
548
549
|
template: `'use client';
|
|
549
550
|
|
|
@@ -1142,6 +1143,7 @@ var package_json_sqlite_default = {
|
|
|
1142
1143
|
"name": "@<%= projectName %>/db",
|
|
1143
1144
|
"version": "0.0.0",
|
|
1144
1145
|
"private": true,
|
|
1146
|
+
"type": "module",
|
|
1145
1147
|
"exports": {
|
|
1146
1148
|
".": "./src/index.ts"
|
|
1147
1149
|
},
|
|
@@ -1171,6 +1173,7 @@ var package_json_postgres_default = {
|
|
|
1171
1173
|
"name": "@<%= projectName %>/db",
|
|
1172
1174
|
"version": "0.0.0",
|
|
1173
1175
|
"private": true,
|
|
1176
|
+
"type": "module",
|
|
1174
1177
|
"exports": {
|
|
1175
1178
|
".": "./src/index.ts"
|
|
1176
1179
|
},
|
|
@@ -1258,11 +1261,10 @@ const dbPostgres = { templates: [
|
|
|
1258
1261
|
src_index_postgres_default
|
|
1259
1262
|
] };
|
|
1260
1263
|
//#endregion
|
|
1261
|
-
//#region src/templates/ui/
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
template: `{
|
|
1264
|
+
//#region src/templates/ui/templates/package-json.ts
|
|
1265
|
+
var package_json_default$4 = {
|
|
1266
|
+
filename: "packages/ui/package.json",
|
|
1267
|
+
template: `{
|
|
1266
1268
|
"name": "@<%= projectName %>/ui",
|
|
1267
1269
|
"version": "0.0.0",
|
|
1268
1270
|
"private": true,
|
|
@@ -1294,10 +1296,12 @@ const ui$1 = { templates: [
|
|
|
1294
1296
|
"tailwind-merge": "<%= versions["tailwind-merge"] %>"
|
|
1295
1297
|
}
|
|
1296
1298
|
}`
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1299
|
+
};
|
|
1300
|
+
//#endregion
|
|
1301
|
+
//#region src/templates/ui/templates/button.ts
|
|
1302
|
+
var button_default$2 = {
|
|
1303
|
+
filename: "packages/ui/src/button.tsx",
|
|
1304
|
+
template: `"use client";
|
|
1301
1305
|
|
|
1302
1306
|
import { ReactNode } from "react";
|
|
1303
1307
|
import { cn } from "./utils";
|
|
@@ -1329,10 +1333,12 @@ export const Button = ({ children, onClick, type = "button", disabled, className
|
|
|
1329
1333
|
</button>
|
|
1330
1334
|
);
|
|
1331
1335
|
};`
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
+
};
|
|
1337
|
+
//#endregion
|
|
1338
|
+
//#region src/templates/ui/templates/link.ts
|
|
1339
|
+
var link_default$2 = {
|
|
1340
|
+
filename: "packages/ui/src/link.tsx",
|
|
1341
|
+
template: `import NextLink, { type LinkProps } from "next/link";
|
|
1336
1342
|
import { type PropsWithChildren } from "react";
|
|
1337
1343
|
import { cn } from "./utils";
|
|
1338
1344
|
|
|
@@ -1355,10 +1361,12 @@ export function Link({
|
|
|
1355
1361
|
</NextLink>
|
|
1356
1362
|
);
|
|
1357
1363
|
}`
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1364
|
+
};
|
|
1365
|
+
//#endregion
|
|
1366
|
+
//#region src/templates/ui/templates/logo.ts
|
|
1367
|
+
var logo_default$2 = {
|
|
1368
|
+
filename: "packages/ui/src/logo.tsx",
|
|
1369
|
+
template: `import { cn } from "./utils";
|
|
1362
1370
|
|
|
1363
1371
|
interface LogoProps {
|
|
1364
1372
|
className?: string;
|
|
@@ -1381,19 +1389,23 @@ export function Logo({ className }: LogoProps) {
|
|
|
1381
1389
|
</svg>
|
|
1382
1390
|
);
|
|
1383
1391
|
}`
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1392
|
+
};
|
|
1393
|
+
//#endregion
|
|
1394
|
+
//#region src/templates/ui/templates/utils.ts
|
|
1395
|
+
var utils_default$1 = {
|
|
1396
|
+
filename: "packages/ui/src/utils.ts",
|
|
1397
|
+
template: `import { clsx, type ClassValue } from "clsx";
|
|
1388
1398
|
import { twMerge } from "tailwind-merge";
|
|
1389
1399
|
|
|
1390
1400
|
export function cn(...inputs: ClassValue[]) {
|
|
1391
1401
|
return twMerge(clsx(inputs));
|
|
1392
1402
|
}`
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1403
|
+
};
|
|
1404
|
+
//#endregion
|
|
1405
|
+
//#region src/templates/ui/templates/globals-css.ts
|
|
1406
|
+
var globals_css_default$2 = {
|
|
1407
|
+
filename: "packages/ui/src/globals.css",
|
|
1408
|
+
template: `@import 'tailwindcss';
|
|
1397
1409
|
@source "../../../apps/**/*.{ts,tsx}";
|
|
1398
1410
|
@source "../**/*.{ts,tsx}";
|
|
1399
1411
|
|
|
@@ -1430,20 +1442,24 @@ export function cn(...inputs: ClassValue[]) {
|
|
|
1430
1442
|
border-color: var(--border);
|
|
1431
1443
|
}
|
|
1432
1444
|
}`
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1445
|
+
};
|
|
1446
|
+
//#endregion
|
|
1447
|
+
//#region src/templates/ui/templates/postcss-config.ts
|
|
1448
|
+
var postcss_config_default$2 = {
|
|
1449
|
+
filename: "packages/ui/postcss.config.mjs",
|
|
1450
|
+
template: `const config = {
|
|
1437
1451
|
plugins: {
|
|
1438
1452
|
"@tailwindcss/postcss": {},
|
|
1439
1453
|
},
|
|
1440
1454
|
};
|
|
1441
1455
|
|
|
1442
1456
|
export default config;`
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1457
|
+
};
|
|
1458
|
+
//#endregion
|
|
1459
|
+
//#region src/templates/ui/templates/tsconfig.ts
|
|
1460
|
+
var tsconfig_default$1 = {
|
|
1461
|
+
filename: "packages/ui/tsconfig.json",
|
|
1462
|
+
template: `{
|
|
1447
1463
|
"extends": "@<%= projectName %>/typescript-config/react-library.json",
|
|
1448
1464
|
"compilerOptions": {
|
|
1449
1465
|
"outDir": "dist",
|
|
@@ -1452,11 +1468,24 @@ export default config;`
|
|
|
1452
1468
|
"include": ["src"],
|
|
1453
1469
|
"exclude": ["node_modules", "dist"]
|
|
1454
1470
|
}`
|
|
1455
|
-
|
|
1471
|
+
};
|
|
1472
|
+
//#endregion
|
|
1473
|
+
//#region src/templates/ui/index.ts
|
|
1474
|
+
const ui$1 = { templates: [
|
|
1475
|
+
package_json_default$4,
|
|
1476
|
+
button_default$2,
|
|
1477
|
+
link_default$2,
|
|
1478
|
+
logo_default$2,
|
|
1479
|
+
utils_default$1,
|
|
1480
|
+
globals_css_default$2,
|
|
1481
|
+
postcss_config_default$2,
|
|
1482
|
+
tsconfig_default$1
|
|
1456
1483
|
] };
|
|
1457
1484
|
//#endregion
|
|
1458
1485
|
//#region src/templates/versions.ts
|
|
1459
1486
|
const versions = {
|
|
1487
|
+
"@babel/plugin-proposal-decorators": "^8.0.2",
|
|
1488
|
+
"@babel/plugin-transform-class-properties": "^8.0.1",
|
|
1460
1489
|
"@base-ui/react": "^1.6.0",
|
|
1461
1490
|
"@eslint/js": "^9.39.1",
|
|
1462
1491
|
"@nestjs/cli": "^11.0.0",
|
|
@@ -1469,6 +1498,9 @@ const versions = {
|
|
|
1469
1498
|
"@next/eslint-plugin-next": "^16.3.4",
|
|
1470
1499
|
"@oxlint/plugins": "^1.74.0",
|
|
1471
1500
|
"@shadcn/react": "^0.2.1",
|
|
1501
|
+
"@stylexjs/babel-plugin": "0.19.0",
|
|
1502
|
+
"@stylexjs/postcss-plugin": "0.19.0",
|
|
1503
|
+
"@stylexjs/stylex": "0.19.0",
|
|
1472
1504
|
"@swc/core": "^1.10.0",
|
|
1473
1505
|
"@tailwindcss/postcss": "^4.2.1",
|
|
1474
1506
|
"@tanstack/react-form": "^1.28.5",
|
|
@@ -1484,6 +1516,7 @@ const versions = {
|
|
|
1484
1516
|
"@types/supertest": "^6.0.2",
|
|
1485
1517
|
"@vitest/coverage-v8": "^4.1.10",
|
|
1486
1518
|
auth: "^1.5.5",
|
|
1519
|
+
"babel-plugin-transform-typescript-metadata": "^0.4.0",
|
|
1487
1520
|
"better-auth": "^1.2.8",
|
|
1488
1521
|
"better-sqlite3": "^12.11.1",
|
|
1489
1522
|
"class-variance-authority": "^0.7.1",
|
|
@@ -9829,152 +9862,951 @@ export {
|
|
|
9829
9862
|
}]
|
|
9830
9863
|
};
|
|
9831
9864
|
//#endregion
|
|
9832
|
-
//#region src/templates/
|
|
9833
|
-
|
|
9834
|
-
|
|
9835
|
-
|
|
9836
|
-
|
|
9865
|
+
//#region src/templates/stylex-ui/index.ts
|
|
9866
|
+
const stylexUi = { templates: [
|
|
9867
|
+
{
|
|
9868
|
+
filename: "packages/ui/package.json",
|
|
9869
|
+
template: `{
|
|
9870
|
+
"name": "@<%= projectName %>/ui",
|
|
9837
9871
|
"version": "0.0.0",
|
|
9838
|
-
"type": "module",
|
|
9839
9872
|
"private": true,
|
|
9840
9873
|
"exports": {
|
|
9841
|
-
"./
|
|
9842
|
-
"./
|
|
9843
|
-
"
|
|
9874
|
+
"./globals.css": "./src/globals.css",
|
|
9875
|
+
"./tokens.stylex": "./src/tokens.stylex.ts",
|
|
9876
|
+
"./*": "./src/*.tsx"
|
|
9877
|
+
},
|
|
9878
|
+
"scripts": {
|
|
9879
|
+
"typecheck": "tsc --noEmit"
|
|
9844
9880
|
},
|
|
9845
9881
|
"devDependencies": {
|
|
9846
|
-
"
|
|
9847
|
-
"@
|
|
9848
|
-
"
|
|
9849
|
-
"
|
|
9850
|
-
"
|
|
9851
|
-
|
|
9852
|
-
|
|
9853
|
-
"
|
|
9854
|
-
"
|
|
9855
|
-
"
|
|
9856
|
-
|
|
9882
|
+
"@<%= projectName %>/typescript-config": "workspace:*",
|
|
9883
|
+
"@types/node": "<%= versions["@types/node"] %>",
|
|
9884
|
+
"@types/react": "<%= versions["@types/react"] %>",
|
|
9885
|
+
"@types/react-dom": "<%= versions["@types/react-dom"] %>",
|
|
9886
|
+
"typescript": "<%= versions.typescript %>"
|
|
9887
|
+
},
|
|
9888
|
+
"peerDependencies": {
|
|
9889
|
+
"next": ">=15.0.0",
|
|
9890
|
+
"react": ">=19.0.0",
|
|
9891
|
+
"react-dom": ">=19.0.0"
|
|
9892
|
+
},
|
|
9893
|
+
"dependencies": {
|
|
9894
|
+
"@stylexjs/stylex": "<%= versions["@stylexjs/stylex"] %>"
|
|
9857
9895
|
}
|
|
9858
9896
|
}`
|
|
9897
|
+
},
|
|
9898
|
+
{
|
|
9899
|
+
filename: "packages/ui/src/tokens.stylex.ts",
|
|
9900
|
+
template: `import * as stylex from "@stylexjs/stylex";
|
|
9901
|
+
|
|
9902
|
+
export const colors = stylex.defineVars({
|
|
9903
|
+
background: "oklch(0.145 0 0)",
|
|
9904
|
+
foreground: "oklch(0.985 0 0)",
|
|
9905
|
+
muted: "oklch(0.269 0 0)",
|
|
9906
|
+
mutedForeground: "oklch(0.708 0 0)",
|
|
9907
|
+
border: "oklch(0.469 0 0)",
|
|
9908
|
+
accent: "oklch(0.985 0 0)",
|
|
9909
|
+
accentForeground: "oklch(0.205 0 0)",
|
|
9910
|
+
danger: "oklch(0.637 0.237 25.331)",
|
|
9911
|
+
});
|
|
9912
|
+
|
|
9913
|
+
export const fonts = stylex.defineVars({
|
|
9914
|
+
sans: "var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif",
|
|
9915
|
+
mono: "var(--font-geist-mono), ui-monospace, monospace",
|
|
9916
|
+
});
|
|
9917
|
+
|
|
9918
|
+
export const radii = stylex.defineVars({
|
|
9919
|
+
sm: "6px",
|
|
9920
|
+
md: "8px",
|
|
9921
|
+
lg: "12px",
|
|
9922
|
+
});
|
|
9923
|
+
`
|
|
9924
|
+
},
|
|
9925
|
+
{
|
|
9926
|
+
filename: "packages/ui/src/button.tsx",
|
|
9927
|
+
template: `"use client";
|
|
9928
|
+
|
|
9929
|
+
import { ReactNode } from "react";
|
|
9930
|
+
import * as stylex from "@stylexjs/stylex";
|
|
9931
|
+
import type { StyleXStyles } from "@stylexjs/stylex";
|
|
9932
|
+
import { colors, fonts, radii } from "./tokens.stylex";
|
|
9933
|
+
|
|
9934
|
+
interface ButtonProps {
|
|
9935
|
+
children: ReactNode;
|
|
9936
|
+
onClick?: () => void;
|
|
9937
|
+
type?: "button" | "submit" | "reset";
|
|
9938
|
+
disabled?: boolean;
|
|
9939
|
+
style?: StyleXStyles;
|
|
9940
|
+
}
|
|
9941
|
+
|
|
9942
|
+
export const Button = ({ children, onClick, type = "button", disabled, style }: ButtonProps) => {
|
|
9943
|
+
return (
|
|
9944
|
+
<button
|
|
9945
|
+
type={type}
|
|
9946
|
+
onClick={onClick}
|
|
9947
|
+
disabled={disabled}
|
|
9948
|
+
{...stylex.props(styles.base, disabled && styles.disabled, style)}
|
|
9949
|
+
>
|
|
9950
|
+
{children}
|
|
9951
|
+
</button>
|
|
9952
|
+
);
|
|
9859
9953
|
};
|
|
9860
|
-
//#endregion
|
|
9861
|
-
//#region src/templates/eslint-config/templates/base.ts
|
|
9862
|
-
var base_default$1 = {
|
|
9863
|
-
filename: "packages/eslint-config/base.js",
|
|
9864
|
-
template: `import js from "@eslint/js";
|
|
9865
|
-
import eslintConfigPrettier from "eslint-config-prettier";
|
|
9866
|
-
import turboPlugin from "eslint-plugin-turbo";
|
|
9867
|
-
import tseslint from "typescript-eslint";
|
|
9868
|
-
import onlyWarn from "eslint-plugin-only-warn";
|
|
9869
9954
|
|
|
9870
|
-
|
|
9871
|
-
|
|
9872
|
-
|
|
9873
|
-
|
|
9874
|
-
|
|
9875
|
-
|
|
9876
|
-
|
|
9877
|
-
|
|
9878
|
-
|
|
9879
|
-
|
|
9880
|
-
|
|
9881
|
-
|
|
9882
|
-
|
|
9883
|
-
|
|
9884
|
-
|
|
9955
|
+
const styles = stylex.create({
|
|
9956
|
+
base: {
|
|
9957
|
+
display: "inline-flex",
|
|
9958
|
+
alignItems: "center",
|
|
9959
|
+
justifyContent: "center",
|
|
9960
|
+
gap: 8,
|
|
9961
|
+
height: 36,
|
|
9962
|
+
paddingBlock: 0,
|
|
9963
|
+
paddingInline: 16,
|
|
9964
|
+
fontFamily: fonts.sans,
|
|
9965
|
+
fontSize: 14,
|
|
9966
|
+
fontWeight: 500,
|
|
9967
|
+
whiteSpace: "nowrap",
|
|
9968
|
+
color: colors.accentForeground,
|
|
9969
|
+
backgroundColor: {
|
|
9970
|
+
default: colors.accent,
|
|
9971
|
+
":hover": "oklch(0.922 0 0)",
|
|
9885
9972
|
},
|
|
9886
|
-
|
|
9887
|
-
|
|
9888
|
-
|
|
9889
|
-
|
|
9973
|
+
borderStyle: "none",
|
|
9974
|
+
borderRadius: radii.sm,
|
|
9975
|
+
boxShadow: "0 1px 2px rgba(0, 0, 0, 0.3)",
|
|
9976
|
+
cursor: "pointer",
|
|
9977
|
+
transitionProperty: "background-color",
|
|
9978
|
+
transitionDuration: "150ms",
|
|
9979
|
+
outlineColor: "rgba(255, 255, 255, 0.5)",
|
|
9980
|
+
outlineOffset: 2,
|
|
9981
|
+
outlineStyle: {
|
|
9982
|
+
default: "none",
|
|
9983
|
+
":focus-visible": "solid",
|
|
9890
9984
|
},
|
|
9985
|
+
outlineWidth: 2,
|
|
9891
9986
|
},
|
|
9892
|
-
{
|
|
9893
|
-
|
|
9987
|
+
disabled: {
|
|
9988
|
+
opacity: 0.5,
|
|
9989
|
+
pointerEvents: "none",
|
|
9894
9990
|
},
|
|
9895
|
-
|
|
9896
|
-
|
|
9897
|
-
|
|
9898
|
-
|
|
9899
|
-
|
|
9900
|
-
|
|
9901
|
-
|
|
9902
|
-
import
|
|
9903
|
-
import
|
|
9904
|
-
import
|
|
9905
|
-
import pluginReactHooks from "eslint-plugin-react-hooks";
|
|
9906
|
-
import pluginReact from "eslint-plugin-react";
|
|
9907
|
-
import globals from "globals";
|
|
9908
|
-
import pluginNext from "@next/eslint-plugin-next";
|
|
9909
|
-
import { config as baseConfig } from "./base.js";
|
|
9991
|
+
});
|
|
9992
|
+
`
|
|
9993
|
+
},
|
|
9994
|
+
{
|
|
9995
|
+
filename: "packages/ui/src/link.tsx",
|
|
9996
|
+
template: `import NextLink, { type LinkProps } from "next/link";
|
|
9997
|
+
import { type PropsWithChildren } from "react";
|
|
9998
|
+
import * as stylex from "@stylexjs/stylex";
|
|
9999
|
+
import type { StyleXStyles } from "@stylexjs/stylex";
|
|
10000
|
+
import { colors } from "./tokens.stylex";
|
|
9910
10001
|
|
|
9911
|
-
|
|
9912
|
-
|
|
9913
|
-
|
|
9914
|
-
|
|
9915
|
-
|
|
9916
|
-
|
|
9917
|
-
|
|
9918
|
-
|
|
9919
|
-
|
|
9920
|
-
|
|
9921
|
-
|
|
9922
|
-
|
|
9923
|
-
|
|
9924
|
-
|
|
9925
|
-
|
|
9926
|
-
"
|
|
9927
|
-
|
|
9928
|
-
|
|
9929
|
-
|
|
9930
|
-
|
|
9931
|
-
...pluginReact.configs.flat.recommended.languageOptions,
|
|
9932
|
-
globals: {
|
|
9933
|
-
...globals.serviceworker,
|
|
9934
|
-
...globals.node,
|
|
9935
|
-
},
|
|
9936
|
-
},
|
|
9937
|
-
},
|
|
9938
|
-
{
|
|
9939
|
-
plugins: {
|
|
9940
|
-
"@next/next": pluginNext,
|
|
9941
|
-
},
|
|
9942
|
-
rules: {
|
|
9943
|
-
...pluginNext.configs.recommended.rules,
|
|
9944
|
-
...pluginNext.configs["core-web-vitals"].rules,
|
|
9945
|
-
},
|
|
9946
|
-
},
|
|
9947
|
-
{
|
|
9948
|
-
plugins: {
|
|
9949
|
-
"react-hooks": pluginReactHooks,
|
|
9950
|
-
},
|
|
9951
|
-
settings: { react: { version: "detect" } },
|
|
9952
|
-
rules: {
|
|
9953
|
-
...pluginReactHooks.configs.recommended.rules,
|
|
9954
|
-
// React scope no longer necessary with new JSX transform.
|
|
9955
|
-
"react/react-in-jsx-scope": "off",
|
|
10002
|
+
export function Link({
|
|
10003
|
+
href,
|
|
10004
|
+
children,
|
|
10005
|
+
style,
|
|
10006
|
+
...rest
|
|
10007
|
+
}: PropsWithChildren<LinkProps & { style?: StyleXStyles }>) {
|
|
10008
|
+
return (
|
|
10009
|
+
<NextLink href={href} {...rest} {...stylex.props(styles.link, style)}>
|
|
10010
|
+
{children}
|
|
10011
|
+
</NextLink>
|
|
10012
|
+
);
|
|
10013
|
+
}
|
|
10014
|
+
|
|
10015
|
+
const styles = stylex.create({
|
|
10016
|
+
link: {
|
|
10017
|
+
color: "inherit",
|
|
10018
|
+
textDecorationLine: "underline",
|
|
10019
|
+
textDecorationColor: {
|
|
10020
|
+
default: colors.mutedForeground,
|
|
10021
|
+
":hover": colors.foreground,
|
|
9956
10022
|
},
|
|
10023
|
+
transitionProperty: "text-decoration-color",
|
|
10024
|
+
transitionDuration: "150ms",
|
|
9957
10025
|
},
|
|
9958
|
-
|
|
9959
|
-
|
|
9960
|
-
|
|
9961
|
-
|
|
9962
|
-
|
|
9963
|
-
|
|
9964
|
-
|
|
9965
|
-
import
|
|
9966
|
-
import tseslint from "typescript-eslint";
|
|
9967
|
-
import pluginReactHooks from "eslint-plugin-react-hooks";
|
|
9968
|
-
import pluginReact from "eslint-plugin-react";
|
|
9969
|
-
import globals from "globals";
|
|
9970
|
-
import { config as baseConfig } from "./base.js";
|
|
10026
|
+
});
|
|
10027
|
+
`
|
|
10028
|
+
},
|
|
10029
|
+
{
|
|
10030
|
+
filename: "packages/ui/src/logo.tsx",
|
|
10031
|
+
template: `import * as stylex from "@stylexjs/stylex";
|
|
10032
|
+
import type { StyleXStyles } from "@stylexjs/stylex";
|
|
10033
|
+
import { colors } from "./tokens.stylex";
|
|
9971
10034
|
|
|
9972
|
-
|
|
9973
|
-
|
|
9974
|
-
|
|
9975
|
-
|
|
9976
|
-
export
|
|
9977
|
-
|
|
10035
|
+
interface LogoProps {
|
|
10036
|
+
style?: StyleXStyles;
|
|
10037
|
+
}
|
|
10038
|
+
|
|
10039
|
+
export function Logo({ style }: LogoProps) {
|
|
10040
|
+
return (
|
|
10041
|
+
<svg
|
|
10042
|
+
width="196"
|
|
10043
|
+
height="138"
|
|
10044
|
+
viewBox="0 0 196 138"
|
|
10045
|
+
fill="none"
|
|
10046
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
10047
|
+
{...stylex.props(styles.logo, style)}
|
|
10048
|
+
>
|
|
10049
|
+
<path
|
|
10050
|
+
d="M98 35C102.665 35 107.243 35.2232 111.707 35.6514C111.243 38.1972 111 40.8202 111 43.5C111 67.5244 130.476 87 154.5 87C165.156 87 174.914 83.1658 182.478 76.8057C183.476 79.9455 184 83.186 184 86.5C184 114.943 145.496 138 98 138C50.5035 138 12 114.943 12 86.5C12 83.1861 12.5228 79.9454 13.5215 76.8057C21.0851 83.1661 30.8441 87 41.5 87C65.5244 87 85 67.5244 85 43.5C85 40.8202 84.7559 38.1973 84.292 35.6514C88.7559 35.2232 93.3345 35 98 35ZM38.5 0C59.763 0 77 17.237 77 38.5C77 59.763 59.763 77 38.5 77C17.237 77 0 59.763 0 38.5C0 17.237 17.237 0 38.5 0ZM157.5 0C178.763 0 196 17.237 196 38.5C196 59.763 178.763 77 157.5 77C136.237 77 119 59.763 119 38.5C119 17.237 136.237 0 157.5 0Z"
|
|
10051
|
+
fill="currentColor"
|
|
10052
|
+
/>
|
|
10053
|
+
</svg>
|
|
10054
|
+
);
|
|
10055
|
+
}
|
|
10056
|
+
|
|
10057
|
+
const styles = stylex.create({
|
|
10058
|
+
logo: {
|
|
10059
|
+
color: colors.foreground,
|
|
10060
|
+
},
|
|
10061
|
+
});
|
|
10062
|
+
`
|
|
10063
|
+
},
|
|
10064
|
+
{
|
|
10065
|
+
filename: "packages/ui/src/globals.css",
|
|
10066
|
+
template: `@layer resets {
|
|
10067
|
+
*,
|
|
10068
|
+
*::before,
|
|
10069
|
+
*::after {
|
|
10070
|
+
box-sizing: border-box;
|
|
10071
|
+
}
|
|
10072
|
+
|
|
10073
|
+
* {
|
|
10074
|
+
margin: 0;
|
|
10075
|
+
padding: 0;
|
|
10076
|
+
}
|
|
10077
|
+
|
|
10078
|
+
html,
|
|
10079
|
+
body {
|
|
10080
|
+
height: 100%;
|
|
10081
|
+
}
|
|
10082
|
+
|
|
10083
|
+
html {
|
|
10084
|
+
-webkit-font-smoothing: antialiased;
|
|
10085
|
+
-moz-osx-font-smoothing: grayscale;
|
|
10086
|
+
}
|
|
10087
|
+
}
|
|
10088
|
+
|
|
10089
|
+
@stylex;
|
|
10090
|
+
`
|
|
10091
|
+
},
|
|
10092
|
+
tsconfig_default$1,
|
|
10093
|
+
{
|
|
10094
|
+
when: (s) => s.nest !== "di-only",
|
|
10095
|
+
filename: "apps/web/package.json",
|
|
10096
|
+
template: `{
|
|
10097
|
+
"name": "web",
|
|
10098
|
+
"version": "0.1.0",
|
|
10099
|
+
"type": "module",
|
|
10100
|
+
"private": true,
|
|
10101
|
+
"scripts": {
|
|
10102
|
+
"dev": "next dev --port 3000",
|
|
10103
|
+
"build": "next build",
|
|
10104
|
+
"start": "next start",
|
|
10105
|
+
"typecheck": "next typegen && tsc --noEmit"
|
|
10106
|
+
},
|
|
10107
|
+
"dependencies": {
|
|
10108
|
+
"@<%= projectName %>/auth": "workspace:*",
|
|
10109
|
+
"@<%= projectName %>/ui": "workspace:*",
|
|
10110
|
+
"@stylexjs/stylex": "<%= versions["@stylexjs/stylex"] %>",
|
|
10111
|
+
"dotenv": "<%= versions.dotenv %>",
|
|
10112
|
+
"@tanstack/react-form": "<%= versions["@tanstack/react-form"] %>",
|
|
10113
|
+
"@tanstack/react-query": "<%= versions["@tanstack/react-query"] %>",
|
|
10114
|
+
"better-auth": "<%= versions["better-auth"] %>",
|
|
10115
|
+
"next": "<%= versions.next %>",
|
|
10116
|
+
"react": "<%= versions.react %>",
|
|
10117
|
+
"react-dom": "<%= versions["react-dom"] %>"
|
|
10118
|
+
},
|
|
10119
|
+
"devDependencies": {
|
|
10120
|
+
"@<%= projectName %>/typescript-config": "workspace:*",
|
|
10121
|
+
"@stylexjs/babel-plugin": "<%= versions["@stylexjs/babel-plugin"] %>",
|
|
10122
|
+
"@stylexjs/postcss-plugin": "<%= versions["@stylexjs/postcss-plugin"] %>",
|
|
10123
|
+
"@types/node": "<%= versions["@types/node"] %>",
|
|
10124
|
+
"@types/react": "<%= versions["@types/react"] %>",
|
|
10125
|
+
"@types/react-dom": "<%= versions["@types/react-dom"] %>",
|
|
10126
|
+
"typescript": "<%= versions.typescript %>"
|
|
10127
|
+
}
|
|
10128
|
+
}`
|
|
10129
|
+
},
|
|
10130
|
+
{
|
|
10131
|
+
when: (s) => s.nest === "di-only",
|
|
10132
|
+
filename: "apps/web/package.json",
|
|
10133
|
+
template: `{
|
|
10134
|
+
"name": "web",
|
|
10135
|
+
"version": "0.1.0",
|
|
10136
|
+
"type": "module",
|
|
10137
|
+
"private": true,
|
|
10138
|
+
"scripts": {
|
|
10139
|
+
"dev": "next dev --port 3000",
|
|
10140
|
+
"build": "next build",
|
|
10141
|
+
"start": "next start"
|
|
10142
|
+
},
|
|
10143
|
+
"dependencies": {
|
|
10144
|
+
"@<%= projectName %>/api": "workspace:*",
|
|
10145
|
+
"@<%= projectName %>/auth": "workspace:*",
|
|
10146
|
+
"@<%= projectName %>/db": "workspace:*",
|
|
10147
|
+
"@<%= projectName %>/ui": "workspace:*",
|
|
10148
|
+
"@nestjs/common": "<%= versions["@nestjs/common"] %>",
|
|
10149
|
+
"@nestjs/core": "<%= versions["@nestjs/core"] %>",
|
|
10150
|
+
"reflect-metadata": "<%= versions["reflect-metadata"] %>",
|
|
10151
|
+
"@stylexjs/stylex": "<%= versions["@stylexjs/stylex"] %>",
|
|
10152
|
+
"dotenv": "<%= versions.dotenv %>",
|
|
10153
|
+
"@tanstack/react-form": "<%= versions["@tanstack/react-form"] %>",
|
|
10154
|
+
"@tanstack/react-query": "<%= versions["@tanstack/react-query"] %>",
|
|
10155
|
+
"better-auth": "<%= versions["better-auth"] %>",
|
|
10156
|
+
"next": "<%= versions.next %>",
|
|
10157
|
+
"react": "<%= versions.react %>",
|
|
10158
|
+
"react-dom": "<%= versions["react-dom"] %>"
|
|
10159
|
+
},
|
|
10160
|
+
"devDependencies": {
|
|
10161
|
+
"@<%= projectName %>/typescript-config": "workspace:*",
|
|
10162
|
+
"@babel/plugin-proposal-decorators": "<%= versions["@babel/plugin-proposal-decorators"] %>",
|
|
10163
|
+
"@babel/plugin-transform-class-properties": "<%= versions["@babel/plugin-transform-class-properties"] %>",
|
|
10164
|
+
"babel-plugin-transform-typescript-metadata": "<%= versions["babel-plugin-transform-typescript-metadata"] %>",
|
|
10165
|
+
"@stylexjs/babel-plugin": "<%= versions["@stylexjs/babel-plugin"] %>",
|
|
10166
|
+
"@stylexjs/postcss-plugin": "<%= versions["@stylexjs/postcss-plugin"] %>",
|
|
10167
|
+
"@types/node": "<%= versions["@types/node"] %>",
|
|
10168
|
+
"@types/react": "<%= versions["@types/react"] %>",
|
|
10169
|
+
"@types/react-dom": "<%= versions["@types/react-dom"] %>",
|
|
10170
|
+
"typescript": "<%= versions.typescript %>"
|
|
10171
|
+
}
|
|
10172
|
+
}`
|
|
10173
|
+
},
|
|
10174
|
+
{
|
|
10175
|
+
filename: "apps/web/babel.config.js",
|
|
10176
|
+
template: `import path from "node:path";
|
|
10177
|
+
import { fileURLToPath } from "node:url";
|
|
10178
|
+
|
|
10179
|
+
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10180
|
+
|
|
10181
|
+
const config = {
|
|
10182
|
+
presets: ["next/babel"],
|
|
10183
|
+
plugins: [
|
|
10184
|
+
<% if (nest === 'di-only') { %> "babel-plugin-transform-typescript-metadata",
|
|
10185
|
+
["@babel/plugin-proposal-decorators", { version: "legacy" }],
|
|
10186
|
+
["@babel/plugin-transform-class-properties", { loose: true }],
|
|
10187
|
+
<% } %> [
|
|
10188
|
+
"@stylexjs/babel-plugin",
|
|
10189
|
+
{
|
|
10190
|
+
dev: process.env.NODE_ENV !== "production",
|
|
10191
|
+
runtimeInjection: false,
|
|
10192
|
+
treeshakeCompensation: true,
|
|
10193
|
+
unstable_moduleResolution: {
|
|
10194
|
+
type: "commonJS",
|
|
10195
|
+
rootDir: path.join(dirname, "../.."),
|
|
10196
|
+
},
|
|
10197
|
+
},
|
|
10198
|
+
],
|
|
10199
|
+
],
|
|
10200
|
+
};
|
|
10201
|
+
|
|
10202
|
+
export default config;`
|
|
10203
|
+
},
|
|
10204
|
+
{
|
|
10205
|
+
filename: "apps/web/postcss.config.mjs",
|
|
10206
|
+
template: `import babelConfig from "./babel.config.js";
|
|
10207
|
+
|
|
10208
|
+
const config = {
|
|
10209
|
+
plugins: {
|
|
10210
|
+
"@stylexjs/postcss-plugin": {
|
|
10211
|
+
include: [
|
|
10212
|
+
"app/**/*.{js,jsx,ts,tsx}",
|
|
10213
|
+
"../../packages/ui/src/**/*.{js,jsx,ts,tsx}",
|
|
10214
|
+
],
|
|
10215
|
+
babelConfig: {
|
|
10216
|
+
babelrc: false,
|
|
10217
|
+
parserOpts: { plugins: ["typescript", "jsx"] },
|
|
10218
|
+
plugins: babelConfig.plugins,
|
|
10219
|
+
},
|
|
10220
|
+
useCSSLayers: true,
|
|
10221
|
+
},
|
|
10222
|
+
},
|
|
10223
|
+
};
|
|
10224
|
+
|
|
10225
|
+
export default config;`
|
|
10226
|
+
},
|
|
10227
|
+
{
|
|
10228
|
+
filename: "apps/web/app/layout.tsx",
|
|
10229
|
+
template: `import type { Metadata } from "next";
|
|
10230
|
+
import localFont from "next/font/local";
|
|
10231
|
+
import * as stylex from "@stylexjs/stylex";
|
|
10232
|
+
import Providers from "@/app/providers";
|
|
10233
|
+
import { colors, fonts } from "@<%= projectName %>/ui/tokens.stylex";
|
|
10234
|
+
import "@<%= projectName %>/ui/globals.css";
|
|
10235
|
+
|
|
10236
|
+
const geistSans = localFont({
|
|
10237
|
+
src: "./fonts/GeistVF.woff",
|
|
10238
|
+
variable: "--font-geist-sans",
|
|
10239
|
+
});
|
|
10240
|
+
const geistMono = localFont({
|
|
10241
|
+
src: "./fonts/GeistMonoVF.woff",
|
|
10242
|
+
variable: "--font-geist-mono",
|
|
10243
|
+
});
|
|
10244
|
+
|
|
10245
|
+
export const metadata: Metadata = {
|
|
10246
|
+
title: "<%= projectName %>",
|
|
10247
|
+
description: "Next + Nest = Newt",
|
|
10248
|
+
icons: {
|
|
10249
|
+
icon: [
|
|
10250
|
+
{ url: "/icon0.svg", type: "image/svg+xml" },
|
|
10251
|
+
{ url: "/icon1.png", type: "image/png" },
|
|
10252
|
+
],
|
|
10253
|
+
apple: "/apple-icon.png",
|
|
10254
|
+
},
|
|
10255
|
+
};
|
|
10256
|
+
|
|
10257
|
+
export default function RootLayout({
|
|
10258
|
+
children,
|
|
10259
|
+
}: Readonly<{
|
|
10260
|
+
children: React.ReactNode;
|
|
10261
|
+
}>) {
|
|
10262
|
+
return (
|
|
10263
|
+
<html lang="en" className={\`\${geistSans.variable} \${geistMono.variable}\`}>
|
|
10264
|
+
<body {...stylex.props(styles.body)}>
|
|
10265
|
+
<Providers>{children}</Providers>
|
|
10266
|
+
</body>
|
|
10267
|
+
</html>
|
|
10268
|
+
);
|
|
10269
|
+
}
|
|
10270
|
+
|
|
10271
|
+
const styles = stylex.create({
|
|
10272
|
+
body: {
|
|
10273
|
+
backgroundColor: colors.background,
|
|
10274
|
+
color: colors.foreground,
|
|
10275
|
+
fontFamily: fonts.sans,
|
|
10276
|
+
},
|
|
10277
|
+
});
|
|
10278
|
+
`
|
|
10279
|
+
},
|
|
10280
|
+
{
|
|
10281
|
+
when: (s) => !s.todoExample,
|
|
10282
|
+
filename: "apps/web/app/page.tsx",
|
|
10283
|
+
template: `'use client';
|
|
10284
|
+
|
|
10285
|
+
import { useQuery } from '@tanstack/react-query';
|
|
10286
|
+
import * as stylex from '@stylexjs/stylex';
|
|
10287
|
+
import { authClient } from '@/lib/auth-client';
|
|
10288
|
+
import { AuthForm } from '@/app/auth-form';
|
|
10289
|
+
import { Button } from '@<%= projectName %>/ui/button';
|
|
10290
|
+
import { Link } from '@<%= projectName %>/ui/link';
|
|
10291
|
+
import { Logo } from '@<%= projectName %>/ui/logo';
|
|
10292
|
+
import { colors, fonts, radii } from '@<%= projectName %>/ui/tokens.stylex';
|
|
10293
|
+
|
|
10294
|
+
export default function Home() {
|
|
10295
|
+
const { data: session, isPending } = authClient.useSession();
|
|
10296
|
+
|
|
10297
|
+
const { data: hello } = useQuery({
|
|
10298
|
+
queryKey: ['hello'],
|
|
10299
|
+
queryFn: () => fetch('/api/hello').then((r) => r.json()),
|
|
10300
|
+
});
|
|
10301
|
+
|
|
10302
|
+
return (
|
|
10303
|
+
<main {...stylex.props(styles.main)}>
|
|
10304
|
+
<div {...stylex.props(styles.header)}>
|
|
10305
|
+
<p {...stylex.props(styles.mono, styles.muted)}>apps/web/app/page.tsx</p>
|
|
10306
|
+
<p {...stylex.props(styles.muted)}>Delete me to get started!</p>
|
|
10307
|
+
</div>
|
|
10308
|
+
|
|
10309
|
+
<div {...stylex.props(styles.titleRow)}>
|
|
10310
|
+
<Logo style={styles.logo} />
|
|
10311
|
+
<div>
|
|
10312
|
+
<h1 {...stylex.props(styles.h1)}><%= projectName %></h1>
|
|
10313
|
+
<p {...stylex.props(styles.muted, styles.tagline)}>
|
|
10314
|
+
Next + Nest = Newt 💜
|
|
10315
|
+
</p>
|
|
10316
|
+
</div>
|
|
10317
|
+
</div>
|
|
10318
|
+
|
|
10319
|
+
<div {...stylex.props(styles.card)}>
|
|
10320
|
+
<p {...stylex.props(styles.eyebrow)}>next.js</p>
|
|
10321
|
+
<p {...stylex.props(styles.mono, styles.muted)}>apps/web/app/layout.tsx</p>
|
|
10322
|
+
<p {...stylex.props(styles.muted)}>Next.js rendering</p>
|
|
10323
|
+
</div>
|
|
10324
|
+
|
|
10325
|
+
<div {...stylex.props(styles.card)}>
|
|
10326
|
+
<p {...stylex.props(styles.eyebrow)}>nest.js</p>
|
|
10327
|
+
<p {...stylex.props(styles.mono, styles.muted)}>GET /api/hello</p>
|
|
10328
|
+
<pre {...stylex.props(styles.pre)}>
|
|
10329
|
+
<code>{JSON.stringify(hello, null, 2)}</code>
|
|
10330
|
+
</pre>
|
|
10331
|
+
</div>
|
|
10332
|
+
|
|
10333
|
+
<div {...stylex.props(styles.card)}>
|
|
10334
|
+
<p {...stylex.props(styles.eyebrow, styles.eyebrowSpaced)}>better-auth</p>
|
|
10335
|
+
{isPending ? (
|
|
10336
|
+
<p {...stylex.props(styles.muted)}>Loading…</p>
|
|
10337
|
+
) : session ? (
|
|
10338
|
+
<div {...stylex.props(styles.signedIn)}>
|
|
10339
|
+
<p>Signed in as {session.user.name}</p>
|
|
10340
|
+
<Button onClick={() => void authClient.signOut()}>
|
|
10341
|
+
Sign out
|
|
10342
|
+
</Button>
|
|
10343
|
+
</div>
|
|
10344
|
+
) : (
|
|
10345
|
+
<AuthForm />
|
|
10346
|
+
)}
|
|
10347
|
+
</div>
|
|
10348
|
+
|
|
10349
|
+
<div {...stylex.props(styles.footer)}>
|
|
10350
|
+
<p {...stylex.props(styles.muted)}>Learn more</p>
|
|
10351
|
+
<ul {...stylex.props(styles.list)}>
|
|
10352
|
+
<li>
|
|
10353
|
+
<Link href="https://newt-app.com">Documentation</Link>
|
|
10354
|
+
</li>
|
|
10355
|
+
<li>
|
|
10356
|
+
<Link href="https://github.com/zeevo/newt-app">GitHub</Link>
|
|
10357
|
+
</li>
|
|
10358
|
+
<li>
|
|
10359
|
+
<Link href="https://nextjs.org">Next.js</Link>
|
|
10360
|
+
</li>
|
|
10361
|
+
<li>
|
|
10362
|
+
<Link href="https://nestjs.com">NestJS</Link>
|
|
10363
|
+
</li>
|
|
10364
|
+
</ul>
|
|
10365
|
+
</div>
|
|
10366
|
+
</main>
|
|
10367
|
+
);
|
|
10368
|
+
}
|
|
10369
|
+
|
|
10370
|
+
const styles = stylex.create({
|
|
10371
|
+
main: {
|
|
10372
|
+
display: 'flex',
|
|
10373
|
+
flexDirection: 'column',
|
|
10374
|
+
gap: '1rem',
|
|
10375
|
+
maxWidth: '32rem',
|
|
10376
|
+
minHeight: '100%',
|
|
10377
|
+
marginInline: 'auto',
|
|
10378
|
+
paddingBlock: '2rem',
|
|
10379
|
+
paddingInline: '1rem',
|
|
10380
|
+
fontSize: '0.875rem',
|
|
10381
|
+
},
|
|
10382
|
+
header: {
|
|
10383
|
+
paddingBottom: '1rem',
|
|
10384
|
+
borderBottomColor: colors.border,
|
|
10385
|
+
borderBottomStyle: 'solid',
|
|
10386
|
+
borderBottomWidth: 1,
|
|
10387
|
+
},
|
|
10388
|
+
titleRow: {
|
|
10389
|
+
display: 'flex',
|
|
10390
|
+
alignItems: 'center',
|
|
10391
|
+
gap: '0.75rem',
|
|
10392
|
+
paddingBlock: '0.5rem',
|
|
10393
|
+
},
|
|
10394
|
+
logo: {
|
|
10395
|
+
width: '2.5rem',
|
|
10396
|
+
height: 'auto',
|
|
10397
|
+
},
|
|
10398
|
+
h1: {
|
|
10399
|
+
fontSize: '2.25rem',
|
|
10400
|
+
fontWeight: 900,
|
|
10401
|
+
letterSpacing: '-0.025em',
|
|
10402
|
+
},
|
|
10403
|
+
tagline: {
|
|
10404
|
+
letterSpacing: '0.1em',
|
|
10405
|
+
textTransform: 'uppercase',
|
|
10406
|
+
},
|
|
10407
|
+
card: {
|
|
10408
|
+
display: 'flex',
|
|
10409
|
+
flexDirection: 'column',
|
|
10410
|
+
gap: '0.25rem',
|
|
10411
|
+
padding: '1.5rem',
|
|
10412
|
+
borderColor: colors.border,
|
|
10413
|
+
borderRadius: radii.lg,
|
|
10414
|
+
borderStyle: 'solid',
|
|
10415
|
+
borderWidth: 1,
|
|
10416
|
+
},
|
|
10417
|
+
eyebrow: {
|
|
10418
|
+
fontFamily: fonts.mono,
|
|
10419
|
+
fontSize: '0.75rem',
|
|
10420
|
+
letterSpacing: '0.1em',
|
|
10421
|
+
textTransform: 'uppercase',
|
|
10422
|
+
color: colors.mutedForeground,
|
|
10423
|
+
},
|
|
10424
|
+
eyebrowSpaced: {
|
|
10425
|
+
marginBottom: '0.75rem',
|
|
10426
|
+
},
|
|
10427
|
+
pre: {
|
|
10428
|
+
marginTop: '0.5rem',
|
|
10429
|
+
padding: '0.75rem',
|
|
10430
|
+
fontFamily: fonts.mono,
|
|
10431
|
+
backgroundColor: 'oklch(0.269 0 0 / 0.5)',
|
|
10432
|
+
borderColor: colors.border,
|
|
10433
|
+
borderRadius: radii.sm,
|
|
10434
|
+
borderStyle: 'solid',
|
|
10435
|
+
borderWidth: 1,
|
|
10436
|
+
overflowX: 'auto',
|
|
10437
|
+
},
|
|
10438
|
+
signedIn: {
|
|
10439
|
+
display: 'flex',
|
|
10440
|
+
flexDirection: 'column',
|
|
10441
|
+
alignItems: 'flex-start',
|
|
10442
|
+
gap: '0.75rem',
|
|
10443
|
+
},
|
|
10444
|
+
footer: {
|
|
10445
|
+
display: 'flex',
|
|
10446
|
+
flexDirection: 'column',
|
|
10447
|
+
gap: '0.5rem',
|
|
10448
|
+
paddingBlock: '1rem',
|
|
10449
|
+
paddingInline: '0.5rem',
|
|
10450
|
+
},
|
|
10451
|
+
list: {
|
|
10452
|
+
display: 'flex',
|
|
10453
|
+
flexDirection: 'column',
|
|
10454
|
+
gap: '0.5rem',
|
|
10455
|
+
listStylePosition: 'inside',
|
|
10456
|
+
listStyleType: 'disc',
|
|
10457
|
+
},
|
|
10458
|
+
mono: {
|
|
10459
|
+
fontFamily: fonts.mono,
|
|
10460
|
+
},
|
|
10461
|
+
muted: {
|
|
10462
|
+
color: colors.mutedForeground,
|
|
10463
|
+
},
|
|
10464
|
+
});
|
|
10465
|
+
`
|
|
10466
|
+
},
|
|
10467
|
+
{
|
|
10468
|
+
filename: "apps/web/app/auth-form.tsx",
|
|
10469
|
+
template: `'use client';
|
|
10470
|
+
|
|
10471
|
+
import { useForm } from '@tanstack/react-form';
|
|
10472
|
+
import { useState } from 'react';
|
|
10473
|
+
import * as stylex from '@stylexjs/stylex';
|
|
10474
|
+
import { authClient } from '@/lib/auth-client';
|
|
10475
|
+
import { Button } from '@<%= projectName %>/ui/button';
|
|
10476
|
+
import { colors, radii } from '@<%= projectName %>/ui/tokens.stylex';
|
|
10477
|
+
|
|
10478
|
+
export function AuthForm() {
|
|
10479
|
+
const [tab, setTab] = useState<'signin' | 'signup'>('signup');
|
|
10480
|
+
const [error, setError] = useState('');
|
|
10481
|
+
|
|
10482
|
+
const form = useForm({
|
|
10483
|
+
defaultValues: { name: '', email: '', password: '' },
|
|
10484
|
+
onSubmit: async ({ value }) => {
|
|
10485
|
+
setError('');
|
|
10486
|
+
if (tab === 'signin') {
|
|
10487
|
+
const { error } = await authClient.signIn.email(value);
|
|
10488
|
+
if (error) setError(error.message ?? 'Sign in failed');
|
|
10489
|
+
} else {
|
|
10490
|
+
const { error } = await authClient.signUp.email(value);
|
|
10491
|
+
if (error) setError(error.message ?? 'Sign up failed');
|
|
10492
|
+
}
|
|
10493
|
+
},
|
|
10494
|
+
});
|
|
10495
|
+
|
|
10496
|
+
return (
|
|
10497
|
+
<>
|
|
10498
|
+
<div {...stylex.props(styles.tabs)}>
|
|
10499
|
+
<button
|
|
10500
|
+
onClick={() => setTab('signup')}
|
|
10501
|
+
{...stylex.props(styles.tab, tab === 'signup' && styles.tabActive)}
|
|
10502
|
+
>
|
|
10503
|
+
Sign up
|
|
10504
|
+
</button>
|
|
10505
|
+
<span {...stylex.props(styles.divider)}>|</span>
|
|
10506
|
+
<button
|
|
10507
|
+
onClick={() => setTab('signin')}
|
|
10508
|
+
{...stylex.props(styles.tab, tab === 'signin' && styles.tabActive)}
|
|
10509
|
+
>
|
|
10510
|
+
Sign in
|
|
10511
|
+
</button>
|
|
10512
|
+
</div>
|
|
10513
|
+
|
|
10514
|
+
<form
|
|
10515
|
+
onSubmit={(e) => {
|
|
10516
|
+
e.preventDefault();
|
|
10517
|
+
form.handleSubmit();
|
|
10518
|
+
}}
|
|
10519
|
+
{...stylex.props(styles.form)}
|
|
10520
|
+
>
|
|
10521
|
+
{tab === 'signup' && (
|
|
10522
|
+
<form.Field name="name">
|
|
10523
|
+
{(field) => (
|
|
10524
|
+
<div {...stylex.props(styles.field)}>
|
|
10525
|
+
<label {...stylex.props(styles.label)}>Name</label>
|
|
10526
|
+
<input
|
|
10527
|
+
type="text"
|
|
10528
|
+
autoComplete="name"
|
|
10529
|
+
value={field.state.value}
|
|
10530
|
+
onChange={(e) => field.handleChange(e.target.value)}
|
|
10531
|
+
required
|
|
10532
|
+
{...stylex.props(styles.input)}
|
|
10533
|
+
/>
|
|
10534
|
+
</div>
|
|
10535
|
+
)}
|
|
10536
|
+
</form.Field>
|
|
10537
|
+
)}
|
|
10538
|
+
|
|
10539
|
+
<form.Field name="email">
|
|
10540
|
+
{(field) => (
|
|
10541
|
+
<div {...stylex.props(styles.field)}>
|
|
10542
|
+
<label {...stylex.props(styles.label)}>Email</label>
|
|
10543
|
+
<input
|
|
10544
|
+
type="email"
|
|
10545
|
+
autoComplete="email"
|
|
10546
|
+
value={field.state.value}
|
|
10547
|
+
onChange={(e) => field.handleChange(e.target.value)}
|
|
10548
|
+
required
|
|
10549
|
+
{...stylex.props(styles.input)}
|
|
10550
|
+
/>
|
|
10551
|
+
</div>
|
|
10552
|
+
)}
|
|
10553
|
+
</form.Field>
|
|
10554
|
+
|
|
10555
|
+
<form.Field name="password">
|
|
10556
|
+
{(field) => (
|
|
10557
|
+
<div {...stylex.props(styles.field)}>
|
|
10558
|
+
<label {...stylex.props(styles.label)}>Password</label>
|
|
10559
|
+
<input
|
|
10560
|
+
type="password"
|
|
10561
|
+
autoComplete={
|
|
10562
|
+
tab === 'signin' ? 'current-password' : 'new-password'
|
|
10563
|
+
}
|
|
10564
|
+
value={field.state.value}
|
|
10565
|
+
onChange={(e) => field.handleChange(e.target.value)}
|
|
10566
|
+
required
|
|
10567
|
+
minLength={8}
|
|
10568
|
+
{...stylex.props(styles.input)}
|
|
10569
|
+
/>
|
|
10570
|
+
</div>
|
|
10571
|
+
)}
|
|
10572
|
+
</form.Field>
|
|
10573
|
+
|
|
10574
|
+
{error && <p {...stylex.props(styles.error)}>{error}</p>}
|
|
10575
|
+
|
|
10576
|
+
<form.Subscribe selector={(s) => s.isSubmitting}>
|
|
10577
|
+
{(isSubmitting) => (
|
|
10578
|
+
<Button type="submit" disabled={isSubmitting} style={styles.submit}>
|
|
10579
|
+
{isSubmitting
|
|
10580
|
+
? 'Loading…'
|
|
10581
|
+
: tab === 'signin'
|
|
10582
|
+
? 'Sign in'
|
|
10583
|
+
: 'Create account'}
|
|
10584
|
+
</Button>
|
|
10585
|
+
)}
|
|
10586
|
+
</form.Subscribe>
|
|
10587
|
+
</form>
|
|
10588
|
+
</>
|
|
10589
|
+
);
|
|
10590
|
+
}
|
|
10591
|
+
|
|
10592
|
+
const styles = stylex.create({
|
|
10593
|
+
tabs: {
|
|
10594
|
+
display: 'flex',
|
|
10595
|
+
gap: '0.5rem',
|
|
10596
|
+
marginBottom: '1.5rem',
|
|
10597
|
+
fontSize: '0.875rem',
|
|
10598
|
+
},
|
|
10599
|
+
tab: {
|
|
10600
|
+
color: {
|
|
10601
|
+
default: colors.mutedForeground,
|
|
10602
|
+
':hover': colors.foreground,
|
|
10603
|
+
},
|
|
10604
|
+
backgroundColor: 'transparent',
|
|
10605
|
+
borderStyle: 'none',
|
|
10606
|
+
cursor: 'pointer',
|
|
10607
|
+
padding: 0,
|
|
10608
|
+
fontFamily: 'inherit',
|
|
10609
|
+
fontSize: 'inherit',
|
|
10610
|
+
},
|
|
10611
|
+
tabActive: {
|
|
10612
|
+
color: colors.foreground,
|
|
10613
|
+
fontWeight: 600,
|
|
10614
|
+
},
|
|
10615
|
+
divider: {
|
|
10616
|
+
color: colors.border,
|
|
10617
|
+
},
|
|
10618
|
+
form: {
|
|
10619
|
+
display: 'flex',
|
|
10620
|
+
flexDirection: 'column',
|
|
10621
|
+
gap: '1rem',
|
|
10622
|
+
},
|
|
10623
|
+
field: {
|
|
10624
|
+
display: 'flex',
|
|
10625
|
+
flexDirection: 'column',
|
|
10626
|
+
gap: '0.25rem',
|
|
10627
|
+
},
|
|
10628
|
+
label: {
|
|
10629
|
+
fontSize: '0.875rem',
|
|
10630
|
+
fontWeight: 500,
|
|
10631
|
+
},
|
|
10632
|
+
input: {
|
|
10633
|
+
width: '100%',
|
|
10634
|
+
height: 36,
|
|
10635
|
+
paddingBlock: '0.25rem',
|
|
10636
|
+
paddingInline: '0.75rem',
|
|
10637
|
+
fontFamily: 'inherit',
|
|
10638
|
+
fontSize: '0.875rem',
|
|
10639
|
+
color: colors.foreground,
|
|
10640
|
+
backgroundColor: 'oklch(0.269 0 0 / 0.5)',
|
|
10641
|
+
borderColor: {
|
|
10642
|
+
default: colors.border,
|
|
10643
|
+
':focus-visible': colors.mutedForeground,
|
|
10644
|
+
},
|
|
10645
|
+
borderRadius: radii.sm,
|
|
10646
|
+
borderStyle: 'solid',
|
|
10647
|
+
borderWidth: 1,
|
|
10648
|
+
outlineStyle: 'none',
|
|
10649
|
+
transitionProperty: 'border-color',
|
|
10650
|
+
transitionDuration: '150ms',
|
|
10651
|
+
},
|
|
10652
|
+
error: {
|
|
10653
|
+
fontSize: '0.875rem',
|
|
10654
|
+
color: colors.danger,
|
|
10655
|
+
},
|
|
10656
|
+
submit: {
|
|
10657
|
+
width: '100%',
|
|
10658
|
+
},
|
|
10659
|
+
});
|
|
10660
|
+
`
|
|
10661
|
+
}
|
|
10662
|
+
] };
|
|
10663
|
+
//#endregion
|
|
10664
|
+
//#region src/templates/eslint-config/templates/package-json.ts
|
|
10665
|
+
var package_json_default$1 = {
|
|
10666
|
+
filename: "packages/eslint-config/package.json",
|
|
10667
|
+
template: `{
|
|
10668
|
+
"name": "@<%= projectName %>/eslint-config",
|
|
10669
|
+
"version": "0.0.0",
|
|
10670
|
+
"type": "module",
|
|
10671
|
+
"private": true,
|
|
10672
|
+
"exports": {
|
|
10673
|
+
"./base": "./base.js",
|
|
10674
|
+
"./next-js": "./next.js",
|
|
10675
|
+
"./react-internal": "./react-internal.js"
|
|
10676
|
+
},
|
|
10677
|
+
"devDependencies": {
|
|
10678
|
+
"@eslint/js": "<%= versions["@eslint/js"] %>",
|
|
10679
|
+
"@next/eslint-plugin-next": "<%= versions["@next/eslint-plugin-next"] %>",
|
|
10680
|
+
"eslint": "<%= versions.eslint %>",
|
|
10681
|
+
"eslint-config-prettier": "<%= versions["eslint-config-prettier"] %>",
|
|
10682
|
+
"eslint-plugin-only-warn": "<%= versions["eslint-plugin-only-warn"] %>",
|
|
10683
|
+
"eslint-plugin-react": "<%= versions["eslint-plugin-react"] %>",
|
|
10684
|
+
"eslint-plugin-react-hooks": "<%= versions["eslint-plugin-react-hooks"] %>",
|
|
10685
|
+
"eslint-plugin-turbo": "<%= versions["eslint-plugin-turbo"] %>",
|
|
10686
|
+
"globals": "<%= versions.globals %>",
|
|
10687
|
+
"typescript": "<%= versions.typescript %>",
|
|
10688
|
+
"typescript-eslint": "<%= versions["typescript-eslint"] %>"
|
|
10689
|
+
}
|
|
10690
|
+
}`
|
|
10691
|
+
};
|
|
10692
|
+
//#endregion
|
|
10693
|
+
//#region src/templates/eslint-config/templates/base.ts
|
|
10694
|
+
var base_default$1 = {
|
|
10695
|
+
filename: "packages/eslint-config/base.js",
|
|
10696
|
+
template: `import js from "@eslint/js";
|
|
10697
|
+
import eslintConfigPrettier from "eslint-config-prettier";
|
|
10698
|
+
import turboPlugin from "eslint-plugin-turbo";
|
|
10699
|
+
import tseslint from "typescript-eslint";
|
|
10700
|
+
import onlyWarn from "eslint-plugin-only-warn";
|
|
10701
|
+
|
|
10702
|
+
/**
|
|
10703
|
+
* A shared ESLint configuration for the repository.
|
|
10704
|
+
*
|
|
10705
|
+
* @type {import("eslint").Linter.Config[]}
|
|
10706
|
+
* */
|
|
10707
|
+
export const config = [
|
|
10708
|
+
js.configs.recommended,
|
|
10709
|
+
eslintConfigPrettier,
|
|
10710
|
+
...tseslint.configs.recommended,
|
|
10711
|
+
{
|
|
10712
|
+
plugins: {
|
|
10713
|
+
turbo: turboPlugin,
|
|
10714
|
+
},
|
|
10715
|
+
rules: {
|
|
10716
|
+
"turbo/no-undeclared-env-vars": "warn",
|
|
10717
|
+
},
|
|
10718
|
+
},
|
|
10719
|
+
{
|
|
10720
|
+
plugins: {
|
|
10721
|
+
onlyWarn,
|
|
10722
|
+
},
|
|
10723
|
+
},
|
|
10724
|
+
{
|
|
10725
|
+
ignores: ["dist/**"],
|
|
10726
|
+
},
|
|
10727
|
+
];`
|
|
10728
|
+
};
|
|
10729
|
+
//#endregion
|
|
10730
|
+
//#region src/templates/eslint-config/templates/next.ts
|
|
10731
|
+
var next_default = {
|
|
10732
|
+
filename: "packages/eslint-config/next.js",
|
|
10733
|
+
template: `import js from "@eslint/js";
|
|
10734
|
+
import { globalIgnores } from "eslint/config";
|
|
10735
|
+
import eslintConfigPrettier from "eslint-config-prettier";
|
|
10736
|
+
import tseslint from "typescript-eslint";
|
|
10737
|
+
import pluginReactHooks from "eslint-plugin-react-hooks";
|
|
10738
|
+
import pluginReact from "eslint-plugin-react";
|
|
10739
|
+
import globals from "globals";
|
|
10740
|
+
import pluginNext from "@next/eslint-plugin-next";
|
|
10741
|
+
import { config as baseConfig } from "./base.js";
|
|
10742
|
+
|
|
10743
|
+
/**
|
|
10744
|
+
* A custom ESLint configuration for libraries that use Next.js.
|
|
10745
|
+
*
|
|
10746
|
+
* @type {import("eslint").Linter.Config[]}
|
|
10747
|
+
* */
|
|
10748
|
+
export const nextJsConfig = [
|
|
10749
|
+
...baseConfig,
|
|
10750
|
+
js.configs.recommended,
|
|
10751
|
+
eslintConfigPrettier,
|
|
10752
|
+
...tseslint.configs.recommended,
|
|
10753
|
+
globalIgnores([
|
|
10754
|
+
// Default ignores of eslint-config-next:
|
|
10755
|
+
".next/**",
|
|
10756
|
+
"out/**",
|
|
10757
|
+
"build/**",
|
|
10758
|
+
"next-env.d.ts",
|
|
10759
|
+
]),
|
|
10760
|
+
{
|
|
10761
|
+
...pluginReact.configs.flat.recommended,
|
|
10762
|
+
languageOptions: {
|
|
10763
|
+
...pluginReact.configs.flat.recommended.languageOptions,
|
|
10764
|
+
globals: {
|
|
10765
|
+
...globals.serviceworker,
|
|
10766
|
+
...globals.node,
|
|
10767
|
+
},
|
|
10768
|
+
},
|
|
10769
|
+
},
|
|
10770
|
+
{
|
|
10771
|
+
plugins: {
|
|
10772
|
+
"@next/next": pluginNext,
|
|
10773
|
+
},
|
|
10774
|
+
rules: {
|
|
10775
|
+
...pluginNext.configs.recommended.rules,
|
|
10776
|
+
...pluginNext.configs["core-web-vitals"].rules,
|
|
10777
|
+
},
|
|
10778
|
+
},
|
|
10779
|
+
{
|
|
10780
|
+
plugins: {
|
|
10781
|
+
"react-hooks": pluginReactHooks,
|
|
10782
|
+
},
|
|
10783
|
+
settings: { react: { version: "detect" } },
|
|
10784
|
+
rules: {
|
|
10785
|
+
...pluginReactHooks.configs.recommended.rules,
|
|
10786
|
+
// React scope no longer necessary with new JSX transform.
|
|
10787
|
+
"react/react-in-jsx-scope": "off",
|
|
10788
|
+
},
|
|
10789
|
+
},
|
|
10790
|
+
];`
|
|
10791
|
+
};
|
|
10792
|
+
//#endregion
|
|
10793
|
+
//#region src/templates/eslint-config/templates/react-internal.ts
|
|
10794
|
+
var react_internal_default = {
|
|
10795
|
+
filename: "packages/eslint-config/react-internal.js",
|
|
10796
|
+
template: `import js from "@eslint/js";
|
|
10797
|
+
import eslintConfigPrettier from "eslint-config-prettier";
|
|
10798
|
+
import tseslint from "typescript-eslint";
|
|
10799
|
+
import pluginReactHooks from "eslint-plugin-react-hooks";
|
|
10800
|
+
import pluginReact from "eslint-plugin-react";
|
|
10801
|
+
import globals from "globals";
|
|
10802
|
+
import { config as baseConfig } from "./base.js";
|
|
10803
|
+
|
|
10804
|
+
/**
|
|
10805
|
+
* A custom ESLint configuration for libraries that use React.
|
|
10806
|
+
*
|
|
10807
|
+
* @type {import("eslint").Linter.Config[]} */
|
|
10808
|
+
export const config = [
|
|
10809
|
+
...baseConfig,
|
|
9978
10810
|
js.configs.recommended,
|
|
9979
10811
|
eslintConfigPrettier,
|
|
9980
10812
|
...tseslint.configs.recommended,
|
|
@@ -10500,7 +11332,9 @@ export default {
|
|
|
10500
11332
|
rootDir: 'src',
|
|
10501
11333
|
testRegex: '.*\\\\.spec\\\\.ts$',
|
|
10502
11334
|
transform: {
|
|
10503
|
-
|
|
11335
|
+
// Under nodenext ts-jest follows each package's "type", so it would emit
|
|
11336
|
+
// packages/db as ESM, which jest's CommonJS runtime can't require
|
|
11337
|
+
'^.+\\\\.(t|j)s$': ['ts-jest', { tsconfig: { module: 'commonjs' } }],
|
|
10504
11338
|
},
|
|
10505
11339
|
collectCoverageFrom: ['**/*.(t|j)s'],
|
|
10506
11340
|
coverageDirectory: '../coverage',
|
|
@@ -11095,6 +11929,7 @@ export async function GET() {
|
|
|
11095
11929
|
}`
|
|
11096
11930
|
},
|
|
11097
11931
|
{
|
|
11932
|
+
when: (s) => !s.stylex,
|
|
11098
11933
|
filename: "apps/web/package.json",
|
|
11099
11934
|
template: `{
|
|
11100
11935
|
"name": "web",
|
|
@@ -11408,7 +12243,7 @@ import { AppService } from './app.service';
|
|
|
11408
12243
|
// serves apps/web's static export; the api runs from apps/api
|
|
11409
12244
|
ServeStaticModule.forRoot({
|
|
11410
12245
|
rootPath: join(process.cwd(), '../web/out'),
|
|
11411
|
-
exclude: ['/api/{*splat}'],
|
|
12246
|
+
exclude: ['/api/{*splat}', '/{*path}.:ext'],
|
|
11412
12247
|
}),
|
|
11413
12248
|
AuthModule.forRoot({ auth }),
|
|
11414
12249
|
],
|
|
@@ -11722,7 +12557,7 @@ import { TodosModule } from './todos/todos.module';
|
|
|
11722
12557
|
// serves apps/web's static export; the api runs from apps/api
|
|
11723
12558
|
ServeStaticModule.forRoot({
|
|
11724
12559
|
rootPath: join(process.cwd(), '../web/out'),
|
|
11725
|
-
exclude: ['/api/{*splat}'],
|
|
12560
|
+
exclude: ['/api/{*splat}', '/{*path}.:ext'],
|
|
11726
12561
|
}),
|
|
11727
12562
|
AuthModule.forRoot({ auth }),
|
|
11728
12563
|
TodosModule,
|
|
@@ -11968,7 +12803,7 @@ export function TodoList({
|
|
|
11968
12803
|
//#endregion
|
|
11969
12804
|
//#region src/templates/todo-example/templates/web-page.ts
|
|
11970
12805
|
var web_page_default = {
|
|
11971
|
-
when: (s) => s.todoExample && !s.shadcn,
|
|
12806
|
+
when: (s) => s.todoExample && !s.shadcn && !s.stylex,
|
|
11972
12807
|
filename: "apps/web/app/page.tsx",
|
|
11973
12808
|
template: `'use client';
|
|
11974
12809
|
|
|
@@ -12306,6 +13141,424 @@ export default function Home() {
|
|
|
12306
13141
|
}`
|
|
12307
13142
|
};
|
|
12308
13143
|
//#endregion
|
|
13144
|
+
//#region src/templates/todo-example/templates/stylex-todo-list.ts
|
|
13145
|
+
var stylex_todo_list_default = {
|
|
13146
|
+
filename: "apps/web/app/todo-list.tsx",
|
|
13147
|
+
template: `'use client';
|
|
13148
|
+
|
|
13149
|
+
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
13150
|
+
import { useForm } from '@tanstack/react-form';
|
|
13151
|
+
import * as stylex from '@stylexjs/stylex';
|
|
13152
|
+
import { authClient } from '@/lib/auth-client';
|
|
13153
|
+
import { Button } from '@<%= projectName %>/ui/button';
|
|
13154
|
+
import { colors, radii } from '@<%= projectName %>/ui/tokens.stylex';
|
|
13155
|
+
|
|
13156
|
+
interface Todo {
|
|
13157
|
+
id: string;
|
|
13158
|
+
title: string;
|
|
13159
|
+
done: boolean;
|
|
13160
|
+
}
|
|
13161
|
+
|
|
13162
|
+
const api = {
|
|
13163
|
+
getTodos: (): Promise<Todo[]> => fetch('/api/todos').then((r) => r.json()),
|
|
13164
|
+
createTodo: (title: string): Promise<Todo> =>
|
|
13165
|
+
fetch('/api/todos', {
|
|
13166
|
+
method: 'POST',
|
|
13167
|
+
headers: { 'Content-Type': 'application/json' },
|
|
13168
|
+
body: JSON.stringify({ title }),
|
|
13169
|
+
}).then((r) => r.json()),
|
|
13170
|
+
toggleTodo: (id: string): Promise<Todo> =>
|
|
13171
|
+
fetch(\`/api/todos/\${id}/toggle\`, { method: 'PATCH' }).then((r) => r.json()),
|
|
13172
|
+
deleteTodo: (id: string): Promise<void> =>
|
|
13173
|
+
fetch(\`/api/todos/\${id}\`, { method: 'DELETE' }).then(() => undefined),
|
|
13174
|
+
};
|
|
13175
|
+
|
|
13176
|
+
export function TodoList({
|
|
13177
|
+
session,
|
|
13178
|
+
}: {
|
|
13179
|
+
session: { user: { email: string } };
|
|
13180
|
+
}) {
|
|
13181
|
+
const queryClient = useQueryClient();
|
|
13182
|
+
|
|
13183
|
+
const { data: todos = [], isPending } = useQuery({
|
|
13184
|
+
queryKey: ['todos'],
|
|
13185
|
+
queryFn: api.getTodos,
|
|
13186
|
+
});
|
|
13187
|
+
|
|
13188
|
+
const createMutation = useMutation({
|
|
13189
|
+
mutationFn: api.createTodo,
|
|
13190
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
13191
|
+
});
|
|
13192
|
+
|
|
13193
|
+
const toggleMutation = useMutation({
|
|
13194
|
+
mutationFn: api.toggleTodo,
|
|
13195
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
13196
|
+
});
|
|
13197
|
+
|
|
13198
|
+
const deleteMutation = useMutation({
|
|
13199
|
+
mutationFn: api.deleteTodo,
|
|
13200
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
13201
|
+
});
|
|
13202
|
+
|
|
13203
|
+
const form = useForm({
|
|
13204
|
+
defaultValues: { title: '' },
|
|
13205
|
+
onSubmit: async ({ value }) => {
|
|
13206
|
+
if (!value.title.trim()) return;
|
|
13207
|
+
createMutation.mutate(value.title.trim());
|
|
13208
|
+
form.reset();
|
|
13209
|
+
},
|
|
13210
|
+
});
|
|
13211
|
+
|
|
13212
|
+
return (
|
|
13213
|
+
<>
|
|
13214
|
+
<div {...stylex.props(styles.header)}>
|
|
13215
|
+
<h1 {...stylex.props(styles.h1)}>Todos</h1>
|
|
13216
|
+
<div {...stylex.props(styles.session)}>
|
|
13217
|
+
<span>{session.user.email}</span>
|
|
13218
|
+
<button
|
|
13219
|
+
{...stylex.props(styles.signOut)}
|
|
13220
|
+
onClick={() => authClient.signOut()}
|
|
13221
|
+
>
|
|
13222
|
+
Sign out
|
|
13223
|
+
</button>
|
|
13224
|
+
</div>
|
|
13225
|
+
</div>
|
|
13226
|
+
|
|
13227
|
+
<form
|
|
13228
|
+
onSubmit={(e) => {
|
|
13229
|
+
e.preventDefault();
|
|
13230
|
+
form.handleSubmit();
|
|
13231
|
+
}}
|
|
13232
|
+
{...stylex.props(styles.form)}
|
|
13233
|
+
>
|
|
13234
|
+
<form.Field name="title">
|
|
13235
|
+
{(field) => (
|
|
13236
|
+
<input
|
|
13237
|
+
value={field.state.value}
|
|
13238
|
+
onChange={(e) => field.handleChange(e.target.value)}
|
|
13239
|
+
placeholder="New todo…"
|
|
13240
|
+
{...stylex.props(styles.input)}
|
|
13241
|
+
/>
|
|
13242
|
+
)}
|
|
13243
|
+
</form.Field>
|
|
13244
|
+
|
|
13245
|
+
<form.Subscribe selector={(s) => s.isSubmitting}>
|
|
13246
|
+
{(isSubmitting) => (
|
|
13247
|
+
<Button type="submit" disabled={isSubmitting || createMutation.isPending}>
|
|
13248
|
+
Add
|
|
13249
|
+
</Button>
|
|
13250
|
+
)}
|
|
13251
|
+
</form.Subscribe>
|
|
13252
|
+
</form>
|
|
13253
|
+
|
|
13254
|
+
{isPending ? (
|
|
13255
|
+
<p {...stylex.props(styles.muted)}>Loading…</p>
|
|
13256
|
+
) : (
|
|
13257
|
+
<ul {...stylex.props(styles.list)}>
|
|
13258
|
+
{todos.map((todo) => (
|
|
13259
|
+
<li key={todo.id} {...stylex.props(styles.item)}>
|
|
13260
|
+
<input
|
|
13261
|
+
type="checkbox"
|
|
13262
|
+
checked={todo.done}
|
|
13263
|
+
onChange={() => toggleMutation.mutate(todo.id)}
|
|
13264
|
+
/>
|
|
13265
|
+
<span {...stylex.props(styles.title, todo.done && styles.titleDone)}>
|
|
13266
|
+
{todo.title}
|
|
13267
|
+
</span>
|
|
13268
|
+
<button
|
|
13269
|
+
onClick={() => deleteMutation.mutate(todo.id)}
|
|
13270
|
+
{...stylex.props(styles.remove)}
|
|
13271
|
+
>
|
|
13272
|
+
×
|
|
13273
|
+
</button>
|
|
13274
|
+
</li>
|
|
13275
|
+
))}
|
|
13276
|
+
</ul>
|
|
13277
|
+
)}
|
|
13278
|
+
|
|
13279
|
+
{!isPending && todos.length === 0 && (
|
|
13280
|
+
<p {...stylex.props(styles.muted)}>No todos yet.</p>
|
|
13281
|
+
)}
|
|
13282
|
+
</>
|
|
13283
|
+
);
|
|
13284
|
+
}
|
|
13285
|
+
|
|
13286
|
+
const styles = stylex.create({
|
|
13287
|
+
header: {
|
|
13288
|
+
display: 'flex',
|
|
13289
|
+
alignItems: 'center',
|
|
13290
|
+
justifyContent: 'space-between',
|
|
13291
|
+
marginBottom: '2rem',
|
|
13292
|
+
},
|
|
13293
|
+
h1: {
|
|
13294
|
+
fontSize: '1.5rem',
|
|
13295
|
+
fontWeight: 600,
|
|
13296
|
+
},
|
|
13297
|
+
session: {
|
|
13298
|
+
display: 'flex',
|
|
13299
|
+
alignItems: 'center',
|
|
13300
|
+
gap: '0.75rem',
|
|
13301
|
+
fontSize: '0.875rem',
|
|
13302
|
+
color: colors.mutedForeground,
|
|
13303
|
+
},
|
|
13304
|
+
signOut: {
|
|
13305
|
+
color: {
|
|
13306
|
+
default: 'inherit',
|
|
13307
|
+
':hover': colors.foreground,
|
|
13308
|
+
},
|
|
13309
|
+
backgroundColor: 'transparent',
|
|
13310
|
+
borderStyle: 'none',
|
|
13311
|
+
cursor: 'pointer',
|
|
13312
|
+
padding: 0,
|
|
13313
|
+
fontFamily: 'inherit',
|
|
13314
|
+
fontSize: 'inherit',
|
|
13315
|
+
},
|
|
13316
|
+
form: {
|
|
13317
|
+
display: 'flex',
|
|
13318
|
+
gap: '0.5rem',
|
|
13319
|
+
marginBottom: '1.5rem',
|
|
13320
|
+
},
|
|
13321
|
+
input: {
|
|
13322
|
+
flexGrow: 1,
|
|
13323
|
+
height: 36,
|
|
13324
|
+
paddingBlock: '0.25rem',
|
|
13325
|
+
paddingInline: '0.75rem',
|
|
13326
|
+
fontFamily: 'inherit',
|
|
13327
|
+
fontSize: '0.875rem',
|
|
13328
|
+
color: colors.foreground,
|
|
13329
|
+
backgroundColor: 'oklch(0.269 0 0 / 0.5)',
|
|
13330
|
+
borderColor: {
|
|
13331
|
+
default: colors.border,
|
|
13332
|
+
':focus-visible': colors.mutedForeground,
|
|
13333
|
+
},
|
|
13334
|
+
borderRadius: radii.sm,
|
|
13335
|
+
borderStyle: 'solid',
|
|
13336
|
+
borderWidth: 1,
|
|
13337
|
+
outlineStyle: 'none',
|
|
13338
|
+
transitionProperty: 'border-color',
|
|
13339
|
+
transitionDuration: '150ms',
|
|
13340
|
+
},
|
|
13341
|
+
list: {
|
|
13342
|
+
listStyleType: 'none',
|
|
13343
|
+
},
|
|
13344
|
+
item: {
|
|
13345
|
+
display: 'flex',
|
|
13346
|
+
alignItems: 'center',
|
|
13347
|
+
gap: '0.75rem',
|
|
13348
|
+
paddingBlock: '0.75rem',
|
|
13349
|
+
borderTopColor: colors.border,
|
|
13350
|
+
borderTopStyle: 'solid',
|
|
13351
|
+
borderTopWidth: {
|
|
13352
|
+
default: 1,
|
|
13353
|
+
':first-child': 0,
|
|
13354
|
+
},
|
|
13355
|
+
},
|
|
13356
|
+
title: {
|
|
13357
|
+
flexGrow: 1,
|
|
13358
|
+
fontSize: '0.875rem',
|
|
13359
|
+
},
|
|
13360
|
+
titleDone: {
|
|
13361
|
+
color: colors.mutedForeground,
|
|
13362
|
+
textDecorationLine: 'line-through',
|
|
13363
|
+
},
|
|
13364
|
+
remove: {
|
|
13365
|
+
color: {
|
|
13366
|
+
default: colors.mutedForeground,
|
|
13367
|
+
':hover': colors.danger,
|
|
13368
|
+
},
|
|
13369
|
+
backgroundColor: 'transparent',
|
|
13370
|
+
borderStyle: 'none',
|
|
13371
|
+
cursor: 'pointer',
|
|
13372
|
+
padding: 0,
|
|
13373
|
+
fontSize: '1.125rem',
|
|
13374
|
+
lineHeight: 1,
|
|
13375
|
+
},
|
|
13376
|
+
muted: {
|
|
13377
|
+
fontSize: '0.875rem',
|
|
13378
|
+
color: colors.mutedForeground,
|
|
13379
|
+
},
|
|
13380
|
+
});
|
|
13381
|
+
`
|
|
13382
|
+
};
|
|
13383
|
+
//#endregion
|
|
13384
|
+
//#region src/templates/todo-example/templates/stylex-page.ts
|
|
13385
|
+
var stylex_page_default = {
|
|
13386
|
+
when: (s) => s.todoExample && s.stylex,
|
|
13387
|
+
filename: "apps/web/app/page.tsx",
|
|
13388
|
+
template: `'use client';
|
|
13389
|
+
|
|
13390
|
+
import { useQuery } from '@tanstack/react-query';
|
|
13391
|
+
import * as stylex from '@stylexjs/stylex';
|
|
13392
|
+
import { authClient } from '@/lib/auth-client';
|
|
13393
|
+
import { AuthForm } from '@/app/auth-form';
|
|
13394
|
+
import { Link } from '@<%= projectName %>/ui/link';
|
|
13395
|
+
import { Logo } from '@<%= projectName %>/ui/logo';
|
|
13396
|
+
import { TodoList } from '@/app/todo-list';
|
|
13397
|
+
import { colors, fonts, radii } from '@<%= projectName %>/ui/tokens.stylex';
|
|
13398
|
+
|
|
13399
|
+
export default function Home() {
|
|
13400
|
+
const { data: session, isPending } = authClient.useSession();
|
|
13401
|
+
|
|
13402
|
+
const { data: hello } = useQuery({
|
|
13403
|
+
queryKey: ['hello'],
|
|
13404
|
+
queryFn: () => fetch('/api/hello').then((r) => r.json()),
|
|
13405
|
+
});
|
|
13406
|
+
|
|
13407
|
+
return (
|
|
13408
|
+
<main {...stylex.props(styles.main)}>
|
|
13409
|
+
<div {...stylex.props(styles.header)}>
|
|
13410
|
+
<p {...stylex.props(styles.mono, styles.muted)}>apps/web/app/page.tsx</p>
|
|
13411
|
+
<p {...stylex.props(styles.muted)}>Delete me to get started!</p>
|
|
13412
|
+
</div>
|
|
13413
|
+
|
|
13414
|
+
<div {...stylex.props(styles.titleRow)}>
|
|
13415
|
+
<Logo style={styles.logo} />
|
|
13416
|
+
<div>
|
|
13417
|
+
<h1 {...stylex.props(styles.h1)}><%= projectName %></h1>
|
|
13418
|
+
<p {...stylex.props(styles.muted, styles.tagline)}>
|
|
13419
|
+
Next + Nest = Newt 💜
|
|
13420
|
+
</p>
|
|
13421
|
+
</div>
|
|
13422
|
+
</div>
|
|
13423
|
+
|
|
13424
|
+
<div {...stylex.props(styles.card)}>
|
|
13425
|
+
<p {...stylex.props(styles.eyebrow)}>next.js</p>
|
|
13426
|
+
<p {...stylex.props(styles.mono, styles.muted)}>apps/web/app/layout.tsx</p>
|
|
13427
|
+
<p {...stylex.props(styles.muted)}>Next.js rendering</p>
|
|
13428
|
+
</div>
|
|
13429
|
+
|
|
13430
|
+
<div {...stylex.props(styles.card)}>
|
|
13431
|
+
<p {...stylex.props(styles.eyebrow)}>nest.js</p>
|
|
13432
|
+
<p {...stylex.props(styles.mono, styles.muted)}>GET /api/hello</p>
|
|
13433
|
+
<pre {...stylex.props(styles.pre)}>
|
|
13434
|
+
<code>{JSON.stringify(hello, null, 2)}</code>
|
|
13435
|
+
</pre>
|
|
13436
|
+
</div>
|
|
13437
|
+
|
|
13438
|
+
<div {...stylex.props(styles.card)}>
|
|
13439
|
+
<p {...stylex.props(styles.eyebrow, styles.eyebrowSpaced)}>better-auth</p>
|
|
13440
|
+
{isPending ? (
|
|
13441
|
+
<p {...stylex.props(styles.muted)}>Loading…</p>
|
|
13442
|
+
) : session ? (
|
|
13443
|
+
<TodoList session={session} />
|
|
13444
|
+
) : (
|
|
13445
|
+
<AuthForm />
|
|
13446
|
+
)}
|
|
13447
|
+
</div>
|
|
13448
|
+
|
|
13449
|
+
<div {...stylex.props(styles.footer)}>
|
|
13450
|
+
<p {...stylex.props(styles.muted)}>Learn more</p>
|
|
13451
|
+
<ul {...stylex.props(styles.list)}>
|
|
13452
|
+
<li>
|
|
13453
|
+
<Link href="https://newt-app.com">Documentation</Link>
|
|
13454
|
+
</li>
|
|
13455
|
+
<li>
|
|
13456
|
+
<Link href="https://github.com/zeevo/newt-app">GitHub</Link>
|
|
13457
|
+
</li>
|
|
13458
|
+
<li>
|
|
13459
|
+
<Link href="https://nextjs.org">Next.js</Link>
|
|
13460
|
+
</li>
|
|
13461
|
+
<li>
|
|
13462
|
+
<Link href="https://nestjs.com">NestJS</Link>
|
|
13463
|
+
</li>
|
|
13464
|
+
</ul>
|
|
13465
|
+
</div>
|
|
13466
|
+
</main>
|
|
13467
|
+
);
|
|
13468
|
+
}
|
|
13469
|
+
|
|
13470
|
+
const styles = stylex.create({
|
|
13471
|
+
main: {
|
|
13472
|
+
display: 'flex',
|
|
13473
|
+
flexDirection: 'column',
|
|
13474
|
+
gap: '1rem',
|
|
13475
|
+
maxWidth: '32rem',
|
|
13476
|
+
minHeight: '100%',
|
|
13477
|
+
marginInline: 'auto',
|
|
13478
|
+
paddingBlock: '2rem',
|
|
13479
|
+
paddingInline: '1rem',
|
|
13480
|
+
fontSize: '0.875rem',
|
|
13481
|
+
},
|
|
13482
|
+
header: {
|
|
13483
|
+
paddingBottom: '1rem',
|
|
13484
|
+
borderBottomColor: colors.border,
|
|
13485
|
+
borderBottomStyle: 'solid',
|
|
13486
|
+
borderBottomWidth: 1,
|
|
13487
|
+
},
|
|
13488
|
+
titleRow: {
|
|
13489
|
+
display: 'flex',
|
|
13490
|
+
alignItems: 'center',
|
|
13491
|
+
gap: '0.75rem',
|
|
13492
|
+
paddingBlock: '0.5rem',
|
|
13493
|
+
},
|
|
13494
|
+
logo: {
|
|
13495
|
+
width: '2.5rem',
|
|
13496
|
+
height: 'auto',
|
|
13497
|
+
},
|
|
13498
|
+
h1: {
|
|
13499
|
+
fontSize: '2.25rem',
|
|
13500
|
+
fontWeight: 900,
|
|
13501
|
+
letterSpacing: '-0.025em',
|
|
13502
|
+
},
|
|
13503
|
+
tagline: {
|
|
13504
|
+
letterSpacing: '0.1em',
|
|
13505
|
+
textTransform: 'uppercase',
|
|
13506
|
+
},
|
|
13507
|
+
card: {
|
|
13508
|
+
display: 'flex',
|
|
13509
|
+
flexDirection: 'column',
|
|
13510
|
+
gap: '0.25rem',
|
|
13511
|
+
padding: '1.5rem',
|
|
13512
|
+
borderColor: colors.border,
|
|
13513
|
+
borderRadius: radii.lg,
|
|
13514
|
+
borderStyle: 'solid',
|
|
13515
|
+
borderWidth: 1,
|
|
13516
|
+
},
|
|
13517
|
+
eyebrow: {
|
|
13518
|
+
fontFamily: fonts.mono,
|
|
13519
|
+
fontSize: '0.75rem',
|
|
13520
|
+
letterSpacing: '0.1em',
|
|
13521
|
+
textTransform: 'uppercase',
|
|
13522
|
+
color: colors.mutedForeground,
|
|
13523
|
+
},
|
|
13524
|
+
eyebrowSpaced: {
|
|
13525
|
+
marginBottom: '0.75rem',
|
|
13526
|
+
},
|
|
13527
|
+
pre: {
|
|
13528
|
+
marginTop: '0.5rem',
|
|
13529
|
+
padding: '0.75rem',
|
|
13530
|
+
fontFamily: fonts.mono,
|
|
13531
|
+
backgroundColor: 'oklch(0.269 0 0 / 0.5)',
|
|
13532
|
+
borderColor: colors.border,
|
|
13533
|
+
borderRadius: radii.sm,
|
|
13534
|
+
borderStyle: 'solid',
|
|
13535
|
+
borderWidth: 1,
|
|
13536
|
+
overflowX: 'auto',
|
|
13537
|
+
},
|
|
13538
|
+
footer: {
|
|
13539
|
+
display: 'flex',
|
|
13540
|
+
flexDirection: 'column',
|
|
13541
|
+
gap: '0.5rem',
|
|
13542
|
+
paddingBlock: '1rem',
|
|
13543
|
+
paddingInline: '0.5rem',
|
|
13544
|
+
},
|
|
13545
|
+
list: {
|
|
13546
|
+
display: 'flex',
|
|
13547
|
+
flexDirection: 'column',
|
|
13548
|
+
gap: '0.5rem',
|
|
13549
|
+
listStylePosition: 'inside',
|
|
13550
|
+
listStyleType: 'disc',
|
|
13551
|
+
},
|
|
13552
|
+
mono: {
|
|
13553
|
+
fontFamily: fonts.mono,
|
|
13554
|
+
},
|
|
13555
|
+
muted: {
|
|
13556
|
+
color: colors.mutedForeground,
|
|
13557
|
+
},
|
|
13558
|
+
});
|
|
13559
|
+
`
|
|
13560
|
+
};
|
|
13561
|
+
//#endregion
|
|
12309
13562
|
//#region src/templates/todo-example/index.ts
|
|
12310
13563
|
const todoExampleApi = { templates: [
|
|
12311
13564
|
todos_module_default,
|
|
@@ -12328,6 +13581,7 @@ const todoExampleDi = { templates: [
|
|
|
12328
13581
|
] };
|
|
12329
13582
|
const todoExampleWeb = { templates: [web_todo_list_default, web_page_default] };
|
|
12330
13583
|
const todoExampleShadcn = { templates: [shadcn_todo_list_default, shadcn_page_default] };
|
|
13584
|
+
const todoExampleStylex = { templates: [stylex_todo_list_default, stylex_page_default] };
|
|
12331
13585
|
//#endregion
|
|
12332
13586
|
//#region src/templates/index.ts
|
|
12333
13587
|
const staticDir = new URL("./static/", import.meta.url);
|
|
@@ -12341,7 +13595,7 @@ const E2E_FILES = [
|
|
|
12341
13595
|
"apps/api/vitest.config.e2e.mts"
|
|
12342
13596
|
];
|
|
12343
13597
|
function selectModules(selection) {
|
|
12344
|
-
const { deployment, nest, todoExample, shadcn, database, linter, testing, extras } = selection;
|
|
13598
|
+
const { deployment, nest, todoExample, shadcn, stylex, database, linter, testing, extras } = selection;
|
|
12345
13599
|
const deploymentModule = deployment === "standalone" ? deploymentStandalone : deployment === "spa" ? singleProcessStaticExport : null;
|
|
12346
13600
|
const webModule = deployment === "spa" ? {
|
|
12347
13601
|
...web$1,
|
|
@@ -12360,7 +13614,7 @@ function selectModules(selection) {
|
|
|
12360
13614
|
...nest === "off" ? [] : [api$1],
|
|
12361
13615
|
database === "postgres" ? dbPostgres : dbSqlite,
|
|
12362
13616
|
auth,
|
|
12363
|
-
shadcn ? shadcnUi : ui$1,
|
|
13617
|
+
shadcn ? shadcnUi : stylex ? stylexUi : ui$1,
|
|
12364
13618
|
linter === "oxc" ? oxc : eslintConfig,
|
|
12365
13619
|
...extras.includes("anti-slop") ? [antiSlop] : [],
|
|
12366
13620
|
typescriptConfig,
|
|
@@ -12371,7 +13625,7 @@ function selectModules(selection) {
|
|
|
12371
13625
|
...todoExample ? [
|
|
12372
13626
|
todoExampleApi,
|
|
12373
13627
|
...nest === "di-only" ? [todoExampleDi] : [todoExampleControllers],
|
|
12374
|
-
shadcn ? todoExampleShadcn : todoExampleWeb
|
|
13628
|
+
shadcn ? todoExampleShadcn : stylex ? todoExampleStylex : todoExampleWeb
|
|
12375
13629
|
] : []
|
|
12376
13630
|
];
|
|
12377
13631
|
}
|
|
@@ -12478,6 +13732,13 @@ function validateExtrasCombo(extras, linter) {
|
|
|
12478
13732
|
};
|
|
12479
13733
|
return { valid: true };
|
|
12480
13734
|
}
|
|
13735
|
+
function validateStylingCombo(shadcn, stylex) {
|
|
13736
|
+
if (shadcn && stylex) return {
|
|
13737
|
+
valid: false,
|
|
13738
|
+
error: "--shadcn cannot be combined with --stylex.\nshadcn/ui components are written in Tailwind utility classes, which StyleX does\nnot compile. Pick one styling system: drop --stylex for shadcn/ui, or drop\n--shadcn for StyleX."
|
|
13739
|
+
};
|
|
13740
|
+
return { valid: true };
|
|
13741
|
+
}
|
|
12481
13742
|
function validateDeploymentCombo(deployment, nest) {
|
|
12482
13743
|
if (deployment === "spa" && nest === "di-only") return {
|
|
12483
13744
|
valid: false,
|
|
@@ -12633,6 +13894,7 @@ function buildPayload(report) {
|
|
|
12633
13894
|
ci: detectCi(),
|
|
12634
13895
|
explicitFlags: [...report.explicitFlags].sort().join(","),
|
|
12635
13896
|
shadcn: selection.shadcn,
|
|
13897
|
+
stylex: selection.stylex,
|
|
12636
13898
|
testing: selection.testing,
|
|
12637
13899
|
database: selection.database,
|
|
12638
13900
|
linter: selection.linter,
|
|
@@ -12706,6 +13968,10 @@ async function doInit(options) {
|
|
|
12706
13968
|
message: "Use shadcn/ui?",
|
|
12707
13969
|
initialValue: true
|
|
12708
13970
|
}),
|
|
13971
|
+
stylex: ({ results }) => results.shadcn ? void 0 : p.confirm({
|
|
13972
|
+
message: "Use StyleX instead of Tailwind?",
|
|
13973
|
+
initialValue: false
|
|
13974
|
+
}),
|
|
12709
13975
|
nest: () => p.select({
|
|
12710
13976
|
message: "NestJS?",
|
|
12711
13977
|
options: [
|
|
@@ -12811,6 +14077,7 @@ async function doInit(options) {
|
|
|
12811
14077
|
process.exit(0);
|
|
12812
14078
|
} });
|
|
12813
14079
|
const useShadcn = options.nonInteractive ? options.shadcn : answers.shadcn ?? true;
|
|
14080
|
+
const useStylex = options.nonInteractive ? options.stylex : answers.stylex ?? false;
|
|
12814
14081
|
const testing = options.nonInteractive ? options.testing : answers.testing ?? "jest";
|
|
12815
14082
|
const database = options.nonInteractive ? options.database : answers.database ?? "sqlite";
|
|
12816
14083
|
const linter = options.nonInteractive ? options.linter : answers.linter ?? "eslint";
|
|
@@ -12818,6 +14085,8 @@ async function doInit(options) {
|
|
|
12818
14085
|
const nest = options.nonInteractive ? options.nest : answers.nest ?? "on";
|
|
12819
14086
|
const todoExample = options.nonInteractive ? options.includeExample : nest !== "off" && (answers.todoExample ?? true);
|
|
12820
14087
|
const extras = options.nonInteractive ? options.extras : answers.extras ?? [];
|
|
14088
|
+
const stylingCombo = validateStylingCombo(useShadcn, useStylex);
|
|
14089
|
+
if (!stylingCombo.valid) throw new Error(stylingCombo.error);
|
|
12821
14090
|
const deploymentCombo = validateDeploymentCombo(deployment, nest);
|
|
12822
14091
|
if (!deploymentCombo.valid) throw new Error(deploymentCombo.error);
|
|
12823
14092
|
const exampleCombo = validateExampleCombo(todoExample, nest);
|
|
@@ -12829,6 +14098,7 @@ async function doInit(options) {
|
|
|
12829
14098
|
nest,
|
|
12830
14099
|
todoExample,
|
|
12831
14100
|
shadcn: useShadcn,
|
|
14101
|
+
stylex: useStylex,
|
|
12832
14102
|
database,
|
|
12833
14103
|
linter,
|
|
12834
14104
|
testing,
|
|
@@ -12897,10 +14167,11 @@ async function doInit(options) {
|
|
|
12897
14167
|
}
|
|
12898
14168
|
}
|
|
12899
14169
|
const program = new Command();
|
|
12900
|
-
program.name("create-newt-app").version(version).description("Create a new newt-app monorepo").argument("[name]").option("-ni, --no-install", "Skip pnpm install", true).option("-ng, --no-git", "Skip git initialization", true).option("--shadcn", "Include shadcn/ui", false).option("--testing <framework>", "Testing framework: vitest or jest", "jest").option("--database <database>", "Database: sqlite or postgres", "sqlite").option("--linter <linter>", "Linter: eslint or oxc", "eslint").option("--deployment <strategy>", "Deployment: none, standalone, or spa", "none").option("--nest <mode>", "NestJS: on, off, or di-only", "on").option("--include-example", "Include the todo example", false).option("--extras <list>", "Extras, comma-separated: anti-slop", "").action(async (name, options, command) => {
|
|
14170
|
+
program.name("create-newt-app").version(version).description("Create a new newt-app monorepo").argument("[name]").option("-ni, --no-install", "Skip pnpm install", true).option("-ng, --no-git", "Skip git initialization", true).option("--shadcn", "Include shadcn/ui", false).option("--stylex", "Use StyleX instead of Tailwind", false).option("--testing <framework>", "Testing framework: vitest or jest", "jest").option("--database <database>", "Database: sqlite or postgres", "sqlite").option("--linter <linter>", "Linter: eslint or oxc", "eslint").option("--deployment <strategy>", "Deployment: none, standalone, or spa", "none").option("--nest <mode>", "NestJS: on, off, or di-only", "on").option("--include-example", "Include the todo example", false).option("--extras <list>", "Extras, comma-separated: anti-slop", "").action(async (name, options, command) => {
|
|
12901
14171
|
intro(`Create a ${chalk.blue("newt")} app.`);
|
|
12902
14172
|
const explicitFlags = Object.entries({
|
|
12903
14173
|
shadcn: "--shadcn",
|
|
14174
|
+
stylex: "--stylex",
|
|
12904
14175
|
testing: "--testing",
|
|
12905
14176
|
database: "--database",
|
|
12906
14177
|
linter: "--linter",
|
|
@@ -12953,6 +14224,7 @@ program.name("create-newt-app").version(version).description("Create a new newt-
|
|
|
12953
14224
|
git: options.git,
|
|
12954
14225
|
nonInteractive,
|
|
12955
14226
|
shadcn: options.shadcn,
|
|
14227
|
+
stylex: options.stylex,
|
|
12956
14228
|
testing: options.testing,
|
|
12957
14229
|
database: options.database,
|
|
12958
14230
|
linter: options.linter,
|