create-fate 1.5.2 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/README.md +1 -2
  2. package/bin/create-fate.mjs +14 -50
  3. package/package.json +1 -1
  4. package/templates/fate/README.md +1 -2
  5. package/templates/fate/_shared/vue-app/package.json +4 -3
  6. package/templates/fate/_shared/vue-app/vite.config.ts +18 -11
  7. package/templates/fate/drizzle/client/package.json +6 -6
  8. package/templates/fate/graphql/client/package.json +6 -6
  9. package/templates/fate/graphql/server/.gitignore +5 -0
  10. package/templates/fate/graphql/server/node_modules/.bin/esbuild +22 -0
  11. package/templates/fate/graphql/server/node_modules/.bin/eslint +22 -0
  12. package/templates/fate/graphql/server/node_modules/.bin/fate +22 -0
  13. package/templates/fate/graphql/server/node_modules/.bin/intent +22 -0
  14. package/templates/fate/graphql/server/node_modules/.bin/jiti +22 -0
  15. package/templates/fate/graphql/server/node_modules/.bin/nft +22 -0
  16. package/templates/fate/graphql/server/node_modules/.bin/nodemon +22 -0
  17. package/templates/fate/graphql/server/node_modules/.bin/oxfmt +22 -0
  18. package/templates/fate/graphql/server/node_modules/.bin/oxlint +22 -0
  19. package/templates/fate/graphql/server/node_modules/.bin/prisma +22 -0
  20. package/templates/fate/graphql/server/node_modules/.bin/prisma-json-types-generator +22 -0
  21. package/templates/fate/graphql/server/node_modules/.bin/prisma-pothos-types +22 -0
  22. package/templates/fate/graphql/server/node_modules/.bin/tsc +22 -0
  23. package/templates/fate/graphql/server/node_modules/.bin/tsgolint +22 -0
  24. package/templates/fate/graphql/server/node_modules/.bin/tsx +22 -0
  25. package/templates/fate/graphql/server/node_modules/.bin/vitest +22 -0
  26. package/templates/fate/graphql/server/node_modules/.bin/vp +22 -0
  27. package/templates/fate/graphql/server/node_modules/.bin/vpr +22 -0
  28. package/templates/fate/graphql/server/node_modules/.bin/yaml +22 -0
  29. package/templates/fate/graphql-client/README.md +11 -1
  30. package/templates/fate/graphql-client/env.ts +6 -0
  31. package/templates/fate/graphql-client/package.json +6 -6
  32. package/templates/fate/http/client/package.json +6 -6
  33. package/templates/fate/prisma/client/package.json +6 -6
  34. package/templates/fate/void/README.md +12 -0
  35. package/templates/fate/void/db/migrations/20260918045815_legal_dragon_lord.sql +15 -0
  36. package/templates/fate/{cloudflare/server/db/migrations/meta/20260508073357_snapshot.json → void/db/migrations/meta/20260918045815_snapshot.json} +174 -124
  37. package/templates/fate/void/db/migrations/meta/_journal.json +7 -0
  38. package/templates/fate/void/package.json +6 -7
  39. package/templates/fate/cloudflare/.github/workflows/push.yml +0 -27
  40. package/templates/fate/cloudflare/.vite-hooks/pre-commit +0 -1
  41. package/templates/fate/cloudflare/.vscode/extensions.json +0 -12
  42. package/templates/fate/cloudflare/.vscode/settings.json +0 -25
  43. package/templates/fate/cloudflare/AGENTS.md +0 -55
  44. package/templates/fate/cloudflare/README.md +0 -137
  45. package/templates/fate/cloudflare/_gitignore +0 -20
  46. package/templates/fate/cloudflare/client/node_modules/.bin/browserslist +0 -22
  47. package/templates/fate/cloudflare/client/node_modules/.bin/cf-wrangler +0 -22
  48. package/templates/fate/cloudflare/client/node_modules/.bin/drizzle-kit +0 -22
  49. package/templates/fate/cloudflare/client/node_modules/.bin/esbuild +0 -22
  50. package/templates/fate/cloudflare/client/node_modules/.bin/fate +0 -22
  51. package/templates/fate/cloudflare/client/node_modules/.bin/fbtee +0 -22
  52. package/templates/fate/cloudflare/client/node_modules/.bin/intent +0 -22
  53. package/templates/fate/cloudflare/client/node_modules/.bin/jiti +0 -22
  54. package/templates/fate/cloudflare/client/node_modules/.bin/oxfmt +0 -22
  55. package/templates/fate/cloudflare/client/node_modules/.bin/oxlint +0 -22
  56. package/templates/fate/cloudflare/client/node_modules/.bin/rolldown +0 -22
  57. package/templates/fate/cloudflare/client/node_modules/.bin/tsc +0 -22
  58. package/templates/fate/cloudflare/client/node_modules/.bin/tsx +0 -22
  59. package/templates/fate/cloudflare/client/node_modules/.bin/vitest +0 -22
  60. package/templates/fate/cloudflare/client/node_modules/.bin/void +0 -22
  61. package/templates/fate/cloudflare/client/node_modules/.bin/vp +0 -22
  62. package/templates/fate/cloudflare/client/node_modules/.bin/vpr +0 -22
  63. package/templates/fate/cloudflare/client/node_modules/.bin/workerd +0 -22
  64. package/templates/fate/cloudflare/client/node_modules/.bin/wrangler +0 -22
  65. package/templates/fate/cloudflare/client/node_modules/.bin/wrangler2 +0 -22
  66. package/templates/fate/cloudflare/client/package.json +0 -62
  67. package/templates/fate/cloudflare/client/pages/index.tsx +0 -96
  68. package/templates/fate/cloudflare/client/pages/layout.tsx +0 -68
  69. package/templates/fate/cloudflare/client/pages/login.tsx +0 -107
  70. package/templates/fate/cloudflare/client/pages/post/[id].tsx +0 -22
  71. package/templates/fate/cloudflare/client/pages/search.tsx +0 -99
  72. package/templates/fate/cloudflare/client/public/icon.svg +0 -1
  73. package/templates/fate/cloudflare/client/src/App.css +0 -153
  74. package/templates/fate/cloudflare/client/src/lib/AvailableLanguages.tsx +0 -5
  75. package/templates/fate/cloudflare/client/src/lib/LocaleContext.tsx +0 -61
  76. package/templates/fate/cloudflare/client/src/lib/cx.tsx +0 -6
  77. package/templates/fate/cloudflare/client/src/lib/env.tsx +0 -5
  78. package/templates/fate/cloudflare/client/src/ui/Badge.tsx +0 -31
  79. package/templates/fate/cloudflare/client/src/ui/Button.tsx +0 -108
  80. package/templates/fate/cloudflare/client/src/ui/Card.tsx +0 -32
  81. package/templates/fate/cloudflare/client/src/ui/CommentCard.tsx +0 -75
  82. package/templates/fate/cloudflare/client/src/ui/Error.tsx +0 -19
  83. package/templates/fate/cloudflare/client/src/ui/H2.tsx +0 -15
  84. package/templates/fate/cloudflare/client/src/ui/H3.tsx +0 -20
  85. package/templates/fate/cloudflare/client/src/ui/Header.tsx +0 -98
  86. package/templates/fate/cloudflare/client/src/ui/Input.tsx +0 -17
  87. package/templates/fate/cloudflare/client/src/ui/Link.tsx +0 -11
  88. package/templates/fate/cloudflare/client/src/ui/LocaleSwitcher.tsx +0 -34
  89. package/templates/fate/cloudflare/client/src/ui/PostCard.tsx +0 -303
  90. package/templates/fate/cloudflare/client/src/ui/Section.tsx +0 -23
  91. package/templates/fate/cloudflare/client/src/ui/UserCard.tsx +0 -131
  92. package/templates/fate/cloudflare/client/src/user/AuthClient.tsx +0 -6
  93. package/templates/fate/cloudflare/client/start.mjs +0 -11
  94. package/templates/fate/cloudflare/client/translations/de-DE.json +0 -632
  95. package/templates/fate/cloudflare/client/translations/ja-JP.json +0 -632
  96. package/templates/fate/cloudflare/client/vite.config.ts +0 -41
  97. package/templates/fate/cloudflare/client/void.json +0 -29
  98. package/templates/fate/cloudflare/package.json +0 -42
  99. package/templates/fate/cloudflare/pnpm-workspace.yaml +0 -41
  100. package/templates/fate/cloudflare/server/.env.example +0 -1
  101. package/templates/fate/cloudflare/server/db/db.ts +0 -30
  102. package/templates/fate/cloudflare/server/db/migrations/20260508073357_initial_schema.sql +0 -134
  103. package/templates/fate/cloudflare/server/db/migrations/20260508120500_seed_cloudflare_demo.sql +0 -170
  104. package/templates/fate/cloudflare/server/db/migrations/meta/_journal.json +0 -20
  105. package/templates/fate/cloudflare/server/db/queries.ts +0 -211
  106. package/templates/fate/cloudflare/server/db/schema.ts +0 -331
  107. package/templates/fate/cloudflare/server/node_modules/.bin/cf-wrangler +0 -22
  108. package/templates/fate/cloudflare/server/node_modules/.bin/drizzle-kit +0 -22
  109. package/templates/fate/cloudflare/server/node_modules/.bin/esbuild +0 -22
  110. package/templates/fate/cloudflare/server/node_modules/.bin/fate +0 -22
  111. package/templates/fate/cloudflare/server/node_modules/.bin/intent +0 -22
  112. package/templates/fate/cloudflare/server/node_modules/.bin/jiti +0 -22
  113. package/templates/fate/cloudflare/server/node_modules/.bin/oxfmt +0 -22
  114. package/templates/fate/cloudflare/server/node_modules/.bin/oxlint +0 -22
  115. package/templates/fate/cloudflare/server/node_modules/.bin/tsc +0 -22
  116. package/templates/fate/cloudflare/server/node_modules/.bin/tsx +0 -22
  117. package/templates/fate/cloudflare/server/node_modules/.bin/vitest +0 -22
  118. package/templates/fate/cloudflare/server/node_modules/.bin/vp +0 -22
  119. package/templates/fate/cloudflare/server/node_modules/.bin/vpr +0 -22
  120. package/templates/fate/cloudflare/server/node_modules/.bin/workerd +0 -22
  121. package/templates/fate/cloudflare/server/node_modules/.bin/wrangler +0 -22
  122. package/templates/fate/cloudflare/server/node_modules/.bin/wrangler2 +0 -22
  123. package/templates/fate/cloudflare/server/package.json +0 -34
  124. package/templates/fate/cloudflare/server/src/fate/commentPermissions.ts +0 -17
  125. package/templates/fate/cloudflare/server/src/fate/context.ts +0 -15
  126. package/templates/fate/cloudflare/server/src/fate/live.ts +0 -7
  127. package/templates/fate/cloudflare/server/src/fate/server.ts +0 -414
  128. package/templates/fate/cloudflare/server/src/fate/views.ts +0 -164
  129. package/templates/fate/cloudflare/server/src/index.ts +0 -80
  130. package/templates/fate/cloudflare/server/src/lib/auth.ts +0 -64
  131. package/templates/fate/cloudflare/server/src/lib/origins.ts +0 -17
  132. package/templates/fate/cloudflare/server/src/router.ts +0 -2
  133. package/templates/fate/cloudflare/server/src/user/SessionUser.tsx +0 -17
  134. package/templates/fate/cloudflare/server/tsconfig.json +0 -10
  135. package/templates/fate/cloudflare/server/wrangler.jsonc +0 -29
  136. package/templates/fate/cloudflare/tsconfig.json +0 -24
  137. package/templates/fate/cloudflare/vite.config.ts +0 -75
  138. package/templates/fate/graphql-client/.env.example +0 -3
@@ -1,22 +0,0 @@
1
- #!/bin/sh
2
- basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
-
4
- case `uname` in
5
- *CYGWIN*|*MINGW*|*MSYS*)
6
- if command -v cygpath > /dev/null 2>&1; then
7
- basedir=`cygpath -w "$basedir"`
8
- fi
9
- ;;
10
- esac
11
-
12
- if [ -z "$NODE_PATH" ]; then
13
- export NODE_PATH="/Users/cpojer/Projects/fate/packages/create-fate/templates/fate/cloudflare/node_modules/.pnpm/wrangler@4.126.0_@cloudflare+workers-types@4.20260702.1/node_modules/wrangler/node_modules:/Users/cpojer/Projects/fate/packages/create-fate/templates/fate/cloudflare/node_modules/.pnpm/wrangler@4.126.0_@cloudflare+workers-types@4.20260702.1/node_modules:/Users/cpojer/Projects/fate/packages/create-fate/templates/fate/cloudflare/node_modules/.pnpm/node_modules"
14
- else
15
- export NODE_PATH="/Users/cpojer/Projects/fate/packages/create-fate/templates/fate/cloudflare/node_modules/.pnpm/wrangler@4.126.0_@cloudflare+workers-types@4.20260702.1/node_modules/wrangler/node_modules:/Users/cpojer/Projects/fate/packages/create-fate/templates/fate/cloudflare/node_modules/.pnpm/wrangler@4.126.0_@cloudflare+workers-types@4.20260702.1/node_modules:/Users/cpojer/Projects/fate/packages/create-fate/templates/fate/cloudflare/node_modules/.pnpm/node_modules:$NODE_PATH"
16
- fi
17
- if [ -x "$basedir/node" ]; then
18
- exec "$basedir/node" "$basedir/../../../node_modules/.pnpm/wrangler@4.126.0_@cloudflare+workers-types@4.20260702.1/node_modules/wrangler/bin/wrangler.js" "$@"
19
- else
20
- exec node "$basedir/../../../node_modules/.pnpm/wrangler@4.126.0_@cloudflare+workers-types@4.20260702.1/node_modules/wrangler/bin/wrangler.js" "$@"
21
- fi
22
- # cmd-shim-target=/Users/cpojer/Projects/fate/packages/create-fate/templates/fate/cloudflare/node_modules/.pnpm/wrangler@4.126.0_@cloudflare+workers-types@4.20260702.1/node_modules/wrangler/bin/wrangler.js
@@ -1,22 +0,0 @@
1
- #!/bin/sh
2
- basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
-
4
- case `uname` in
5
- *CYGWIN*|*MINGW*|*MSYS*)
6
- if command -v cygpath > /dev/null 2>&1; then
7
- basedir=`cygpath -w "$basedir"`
8
- fi
9
- ;;
10
- esac
11
-
12
- if [ -z "$NODE_PATH" ]; then
13
- export NODE_PATH="/Users/cpojer/Projects/fate/packages/create-fate/templates/fate/cloudflare/node_modules/.pnpm/wrangler@4.126.0_@cloudflare+workers-types@4.20260702.1/node_modules/wrangler/node_modules:/Users/cpojer/Projects/fate/packages/create-fate/templates/fate/cloudflare/node_modules/.pnpm/wrangler@4.126.0_@cloudflare+workers-types@4.20260702.1/node_modules:/Users/cpojer/Projects/fate/packages/create-fate/templates/fate/cloudflare/node_modules/.pnpm/node_modules"
14
- else
15
- export NODE_PATH="/Users/cpojer/Projects/fate/packages/create-fate/templates/fate/cloudflare/node_modules/.pnpm/wrangler@4.126.0_@cloudflare+workers-types@4.20260702.1/node_modules/wrangler/node_modules:/Users/cpojer/Projects/fate/packages/create-fate/templates/fate/cloudflare/node_modules/.pnpm/wrangler@4.126.0_@cloudflare+workers-types@4.20260702.1/node_modules:/Users/cpojer/Projects/fate/packages/create-fate/templates/fate/cloudflare/node_modules/.pnpm/node_modules:$NODE_PATH"
16
- fi
17
- if [ -x "$basedir/node" ]; then
18
- exec "$basedir/node" "$basedir/../../../node_modules/.pnpm/wrangler@4.126.0_@cloudflare+workers-types@4.20260702.1/node_modules/wrangler/bin/wrangler.js" "$@"
19
- else
20
- exec node "$basedir/../../../node_modules/.pnpm/wrangler@4.126.0_@cloudflare+workers-types@4.20260702.1/node_modules/wrangler/bin/wrangler.js" "$@"
21
- fi
22
- # cmd-shim-target=/Users/cpojer/Projects/fate/packages/create-fate/templates/fate/cloudflare/node_modules/.pnpm/wrangler@4.126.0_@cloudflare+workers-types@4.20260702.1/node_modules/wrangler/bin/wrangler.js
@@ -1,62 +0,0 @@
1
- {
2
- "name": "@app/client",
3
- "version": "0.0.1",
4
- "private": true,
5
- "author": "Christoph Nakazawa <christoph.pojer@gmail.com>",
6
- "repository": {
7
- "type": "git",
8
- "url": "git://github.com/nkzw-tech/fate.git"
9
- },
10
- "type": "module",
11
- "scripts": {
12
- "build": "vp run fbtee:all && vp build",
13
- "dev": "vp dev",
14
- "dev:setup": "vp run fbtee:all",
15
- "fate:generate": "vp exec fate generate",
16
- "fbtee:all": "vp run fbtee:collect && vp run fbtee:translate",
17
- "fbtee:collect": "vp exec fbtee collect",
18
- "fbtee:prepare": "vp run fbtee:collect && vp exec fbtee prepare-translations --source-strings source_strings.json --output-dir translations --locales de-DE ja-JP",
19
- "fbtee:translate": "vp exec fbtee translate --source-strings source_strings.json --output-dir src/translations --output-locale-style=bcp47",
20
- "start": "node start.mjs"
21
- },
22
- "dependencies": {
23
- "@app/server": "workspace:*",
24
- "@hono/node-server": "^2.1.1",
25
- "@nkzw/core": "^1.3.1",
26
- "@nkzw/define-env": "^1.1.0",
27
- "@nkzw/fate": "latest",
28
- "@nkzw/stack": "^2.3.2",
29
- "@radix-ui/react-slot": "^1.3.3",
30
- "@void/react": "^0.10.12",
31
- "better-auth": "1.7.2",
32
- "cf-fate": "latest",
33
- "class-variance-authority": "^0.7.1",
34
- "clsx": "^2.1.1",
35
- "fbtee": "^5.0.0",
36
- "lucide-react": "^1.34.0",
37
- "react": "^19.2.8",
38
- "react-dom": "^19.2.8",
39
- "react-error-boundary": "^6.1.3",
40
- "react-fate": "latest",
41
- "tailwind-merge": "^3.6.0",
42
- "void": "^0.10.12"
43
- },
44
- "devDependencies": {
45
- "@nkzw/fbtee-compiler": "^5.0.0",
46
- "@nkzw/vite-plugin-fbtee": "^5.0.0",
47
- "@tailwindcss/vite": "^4.3.3",
48
- "@types/node": "^26.4.0",
49
- "@types/react": "^19.2.18",
50
- "@types/react-dom": "^19.2.5",
51
- "@vitejs/plugin-react": "^6.1.0",
52
- "oxc-transform-react": "^0.147.0",
53
- "tailwindcss": "^4.3.3",
54
- "vite": "catalog:",
55
- "vite-plus": "catalog:"
56
- },
57
- "browserslist": [
58
- ">0.2%",
59
- "not dead",
60
- "not op_mini all"
61
- ]
62
- }
@@ -1,96 +0,0 @@
1
- import Stack, { VStack } from '@nkzw/stack';
2
- import { ConnectionRef, useListView, useRequest } from 'react-fate';
3
- import cx from '../src/lib/cx.tsx';
4
- import { Button } from '../src/ui/Button.tsx';
5
- import Card from '../src/ui/Card.tsx';
6
- import H2 from '../src/ui/H2.tsx';
7
- import Link from '../src/ui/Link.tsx';
8
- import { PostCard, PostView } from '../src/ui/PostCard.tsx';
9
- import Section from '../src/ui/Section.tsx';
10
- import UserCard, { UserView } from '../src/ui/UserCard.tsx';
11
-
12
- const PostConnectionView = {
13
- args: { first: 3 },
14
- items: {
15
- node: PostView,
16
- },
17
- pagination: {
18
- hasNext: true,
19
- },
20
- };
21
-
22
- const PostFeed = ({ posts: postsRef }: { posts: ConnectionRef<'Post'> }) => {
23
- const [posts, loadNext] = useListView(PostConnectionView, postsRef);
24
-
25
- return posts.length ? (
26
- <VStack gap={16}>
27
- <H2 className="pl-5">
28
- <fbt desc="Latest posts header">Latest posts</fbt>
29
- </H2>
30
- <VStack gap={32}>
31
- {posts.map(({ node }) => (
32
- <PostCard key={node.id} post={node} />
33
- ))}
34
- {loadNext ? (
35
- <Stack center>
36
- <Button onClick={loadNext} variant="ghost">
37
- <fbt desc="Load more posts button">Load more posts</fbt>
38
- </Button>
39
- </Stack>
40
- ) : null}
41
- </VStack>
42
- </VStack>
43
- ) : null;
44
- };
45
-
46
- export default function HomePage() {
47
- const { posts, viewer } = useRequest({
48
- posts: { list: PostConnectionView },
49
- viewer: { view: UserView },
50
- });
51
-
52
- return (
53
- <Section gap={32}>
54
- <div
55
- className={cx('grid gap-8 lg:items-stretch', viewer?.id ? 'lg:grid-cols-[1.6fr_1fr]' : '')}
56
- >
57
- <Card className="border border-white/20 bg-linear-to-r from-blue-500 to-sky-500 text-white dark:from-blue-600 dark:to-sky-600">
58
- <Stack alignCenter gap={12} wrap>
59
- <span className="squircle bg-white/20 px-2 py-1 text-xs font-semibold tracking-widest uppercase">
60
- <span className="lowercase italic">fate</span> demo
61
- </span>
62
- </Stack>
63
- <div className="space-y-3">
64
- <h1 className="text-3xl leading-tight font-semibold text-balance lg:text-4xl">
65
- <fbt desc="Description of fate">
66
- fate is a modern data client for React inspired by Relay and GraphQL.
67
- </fbt>
68
- </h1>
69
- <p className="text-sm text-white/80 lg:text-base">
70
- <fbt desc="Tagline for fate">
71
- fate combines view composition, normalized caching, data masking, Async React
72
- features, and type-safe data fetching.
73
- </fbt>
74
- </p>
75
- </div>
76
- <Stack alignCenter gap={12} wrap>
77
- {!viewer?.id && (
78
- <>
79
- <Button asChild size="sm" variant="secondary">
80
- <Link className="squircle px-4 py-2 text-sm font-semibold" to="/login">
81
- <fbt desc="Login button">Login</fbt>
82
- </Link>
83
- </Button>
84
- <span className="text-sm text-white/80">
85
- <fbt desc="Login button label">Sign in to post comments.</fbt>
86
- </span>
87
- </>
88
- )}
89
- </Stack>
90
- </Card>
91
- {viewer?.id && <UserCard user={viewer} />}
92
- </div>
93
- <PostFeed posts={posts} />
94
- </Section>
95
- );
96
- }
@@ -1,68 +0,0 @@
1
- import Stack from '@nkzw/stack';
2
- /// <reference types="fbtee/ReactTypes.d.ts" />
3
- import '../src/App.css';
4
- import { ReactNode, Suspense, useMemo } from 'react';
5
- import { ErrorBoundary } from 'react-error-boundary';
6
- import { FateClient } from 'react-fate';
7
- import { createFateClient } from 'react-fate/client';
8
- import env from '../src/lib/env.tsx';
9
- import LocaleContext from '../src/lib/LocaleContext.tsx';
10
- import Card from '../src/ui/Card.tsx';
11
- import Error from '../src/ui/Error.tsx';
12
- import Header from '../src/ui/Header.tsx';
13
- import Section from '../src/ui/Section.tsx';
14
- import AuthClient from '../src/user/AuthClient.tsx';
15
-
16
- const Thinking = () => (
17
- <Section>
18
- <Stack center className="animate-pulse text-gray-500 italic" verticalPadding={48}>
19
- <fbt desc="Text for thinking/loading screen">Thinking...</fbt>
20
- </Stack>
21
- </Section>
22
- );
23
-
24
- export default function Layout({ children }: { children: ReactNode }) {
25
- const { data: session } = AuthClient.useSession();
26
- const userId = session?.user.id;
27
-
28
- const fate = useMemo(
29
- () =>
30
- createFateClient({
31
- fetch: (input, init) =>
32
- fetch(input, {
33
- ...init,
34
- credentials: userId ? 'include' : undefined,
35
- }),
36
- liveUrl: `${env('SERVER_URL')}/fate-live`,
37
- url: `${env('SERVER_URL')}/fate`,
38
- }),
39
- [userId],
40
- );
41
-
42
- return (
43
- <LocaleContext>
44
- <div className="min-h-screen bg-background text-foreground">
45
- <div className="min-h-screen bg-[radial-gradient(circle_at_20%_20%,rgba(59,130,246,0.08),transparent_35%),radial-gradient(circle_at_80%_0,rgba(99,102,241,0.08),transparent_28%)]">
46
- <Header />
47
- {session ? (
48
- <Thinking />
49
- ) : (
50
- <FateClient client={fate} key={userId}>
51
- <ErrorBoundary
52
- fallbackRender={({ error }) => (
53
- <Section>
54
- <Card>
55
- <Error error={error} />
56
- </Card>
57
- </Section>
58
- )}
59
- >
60
- <Suspense fallback={<Thinking />}>{children}</Suspense>
61
- </ErrorBoundary>
62
- </FateClient>
63
- )}
64
- </div>
65
- </div>
66
- </LocaleContext>
67
- );
68
- }
@@ -1,107 +0,0 @@
1
- import Stack, { VStack } from '@nkzw/stack';
2
- import { useRouter } from '@void/react';
3
- import { fbs } from 'fbtee';
4
- import { ExternalLinkIcon } from 'lucide-react';
5
- import { useActionState, useEffect, useState } from 'react';
6
- import { AsyncButton } from '../src/ui/Button.tsx';
7
- import Card from '../src/ui/Card.tsx';
8
- import H2 from '../src/ui/H2.tsx';
9
- import Input from '../src/ui/Input.tsx';
10
- import Section from '../src/ui/Section.tsx';
11
- import AuthClient from '../src/user/AuthClient.tsx';
12
-
13
- export default function LoginPage() {
14
- const [email, setEmail] = useState('');
15
- const [password, setPassword] = useState('');
16
- const router = useRouter();
17
- const { data: session } = AuthClient.useSession();
18
-
19
- const [, signInAction] = useActionState(async () => {
20
- await AuthClient.signIn.email(
21
- {
22
- email,
23
- password,
24
- },
25
- {
26
- onError: () => {},
27
- onRequest: () => {},
28
- onSuccess: () => {
29
- router.flushAll();
30
- void router.visit('/', { replace: true });
31
- },
32
- },
33
- );
34
-
35
- return null;
36
- }, null);
37
-
38
- useEffect(() => {
39
- if (session) {
40
- router.flushAll();
41
- void router.visit('/', { replace: true });
42
- }
43
- }, [router, session]);
44
-
45
- if (session) {
46
- return null;
47
- }
48
-
49
- return (
50
- <Section>
51
- <VStack center gap={16}>
52
- <H2 className="pl-5">
53
- <fbt desc="Sign In headline">Sign In</fbt>
54
- </H2>
55
- <Stack gap={32} wrap>
56
- <Card className="w-84">
57
- <Stack gap vertical>
58
- <VStack action={signInAction} as="form" gap={12}>
59
- <Input
60
- className="w-48"
61
- name="email"
62
- onChange={(e) => setEmail(e.target.value)}
63
- placeholder={fbs('email', 'Email placeholder')}
64
- type="email"
65
- value={email}
66
- />
67
- <Input
68
- className="w-48"
69
- name="password"
70
- onChange={(e) => setPassword(e.target.value)}
71
- placeholder={fbs('password', 'Password placeholder')}
72
- type="password"
73
- value={password}
74
- />
75
- <div>
76
- <AsyncButton type="submit" variant="outline">
77
- <fbt desc="Sign in button">Sign In</fbt>
78
- </AsyncButton>
79
- </div>
80
- </VStack>
81
- </Stack>
82
- </Card>
83
- <Card className="w-84">
84
- <p>
85
- <fbt desc="Login details">
86
- Try one of the
87
- <Stack
88
- alignCenter
89
- as="a"
90
- className="inline-flex! px-1 underline hover:no-underline"
91
- gap={4}
92
- href="https://github.com/nkzw-tech/fate/blob/main/packages/create-fate/templates/fate/cloudflare/server/db/migrations/20260508120500_seed_cloudflare_demo.sql#L1"
93
- rel="noreferrer"
94
- target="_blank"
95
- >
96
- Example Accounts
97
- <ExternalLinkIcon className="h-4 w-4" />
98
- </Stack>{' '}
99
- in the seed data.
100
- </fbt>
101
- </p>
102
- </Card>
103
- </Stack>
104
- </VStack>
105
- </Section>
106
- );
107
- }
@@ -1,22 +0,0 @@
1
- import { useParams } from '@void/react';
2
- import { useRequest } from 'react-fate';
3
- import { PostCard, PostView } from '../../src/ui/PostCard.tsx';
4
- import Section from '../../src/ui/Section.tsx';
5
-
6
- export default function PostPage() {
7
- const { id } = useParams<{ id: string }>();
8
-
9
- if (!id) {
10
- throw new Error('fate: Post ID is required.');
11
- }
12
-
13
- const { post } = useRequest({
14
- post: { id, view: PostView },
15
- });
16
-
17
- return (
18
- <Section>
19
- <PostCard detail post={post} />
20
- </Section>
21
- );
22
- }
@@ -1,99 +0,0 @@
1
- import type { Comment, Post } from '@app/server/src/router.ts';
2
- import Stack, { VStack } from '@nkzw/stack';
3
- import { fbs } from 'fbtee';
4
- import { Suspense, useDeferredValue, useState } from 'react';
5
- import { ErrorBoundary } from 'react-error-boundary';
6
- import { useRequest, useView, view, ViewRef } from 'react-fate';
7
- import cx from '../src/lib/cx.tsx';
8
- import Card from '../src/ui/Card.tsx';
9
- import CommentCard, { CommentView } from '../src/ui/CommentCard.tsx';
10
- import Error from '../src/ui/Error.tsx';
11
- import Input from '../src/ui/Input.tsx';
12
- import Section from '../src/ui/Section.tsx';
13
-
14
- const CommentPostView = view<Post>()({
15
- commentCount: true,
16
- id: true,
17
- title: true,
18
- });
19
-
20
- const CommentSearchView = view<Comment>()({
21
- ...CommentView,
22
- id: true,
23
- post: CommentPostView,
24
- });
25
-
26
- const isDevelopment = import.meta.env.DEV;
27
-
28
- const CommentResult = ({ comment: commentRef }: { comment: ViewRef<'Comment'> }) => {
29
- const comment = useView(CommentSearchView, commentRef);
30
- const post = useView(CommentPostView, comment.post);
31
-
32
- return <CommentCard comment={comment} link post={post} />;
33
- };
34
-
35
- const SearchResults = ({ isStale, query }: { isStale: boolean; query: string }) => {
36
- const { commentSearch } = useRequest({
37
- commentSearch: { args: { query }, list: CommentSearchView },
38
- });
39
-
40
- if (commentSearch.length === 0) {
41
- return (
42
- <p>
43
- <fbt desc="No matches text">
44
- No matches for{' '}
45
- <i>
46
- &quot;<fbt:param name="query">{query}</fbt:param>&quot;
47
- </i>
48
- </fbt>
49
- </p>
50
- );
51
- }
52
-
53
- return (
54
- <VStack className={cx(isStale && 'opacity-50')} gap={12}>
55
- {commentSearch.map((comment) => (
56
- <CommentResult comment={comment} key={comment.id} />
57
- ))}
58
- </VStack>
59
- );
60
- };
61
-
62
- export default function SearchPage() {
63
- const [query, setQuery] = useState('');
64
- const deferredQuery = useDeferredValue(query);
65
- const isStale = query !== deferredQuery;
66
-
67
- return (
68
- <Section>
69
- <Card>
70
- <Stack alignCenter between gap={16}>
71
- <Input
72
- className="w-64"
73
- onChange={(e) => setQuery(e.target.value)}
74
- placeholder={fbs('Search comments...', 'Search input placeholder')}
75
- ref={(ref) => ref?.focus()}
76
- value={query}
77
- />
78
- {isDevelopment ? (
79
- <div className="text-xs text-muted-foreground">
80
- <fbt desc="Slowdown label explanation">500ms artificial slowdown</fbt>
81
- </div>
82
- ) : null}
83
- </Stack>
84
-
85
- <ErrorBoundary FallbackComponent={Error}>
86
- <Suspense
87
- fallback={
88
- <h2>
89
- <fbt desc="Text for thinking/loading screen">Thinking…</fbt>
90
- </h2>
91
- }
92
- >
93
- {query.trim().length > 0 ? <SearchResults isStale={isStale} query={query} /> : null}
94
- </Suspense>
95
- </ErrorBoundary>
96
- </Card>
97
- </Section>
98
- );
99
- }
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMax" viewBox="0 0 160 160"><path d="M108.301 17.465h.272c1.797-.005 3.563.177 5.331.496l.349.063c5.588 1.02 10.731 3.447 15.201 6.933l.347.267c1.579 1.26 3.083 2.684 4.386 4.227l.161.186c4.018 4.719 6.924 10.686 7.767 16.852l.033.239c.262 1.848.351 3.688.352 5.551l.001.307c-.001 1.623-.092 3.188-.386 4.788l-.05.292c-1.003 5.874-3.476 11.447-7.286 16.034l-.29.358c-1.422 1.721-3.011 3.382-4.797 4.729l-.444.354c-3.046 2.405-6.436 4.147-10.084 5.442l-.497.186c-1.766.627-3.615.974-5.465 1.266l-.364.058c-1.591.238-3.185.286-4.791.281h-.499l-1.339-.002h-1.408c-.886-.001-1.772-.001-2.656-.003-3.085-.001-6.163-.005-9.247-.008v-12.78l3.606-.006 2.282-.007c1.205-.006 2.407-.01 3.611-.011.878 0 1.754-.003 2.63-.007.462-.002.928-.005 1.389-.002 6.302.01 12.003-1.72 16.65-6.117l.291-.272c3.951-3.807 6.097-9.302 6.241-14.736.04-3.078-.476-6.048-1.68-8.892l-.104-.244c-2.382-5.559-6.98-9.439-12.504-11.675-2.204-.816-4.522-1.16-6.863-1.134-.301.004-.606.004-.909.001-1.677.003-3.304.127-4.924.591l-.331.098c-2.625.758-5.093 1.928-7.254 3.607l-.323.249c-1.046.817-2.031 1.682-2.873 2.71l-.154.179c-2.354 2.782-3.9 5.988-4.727 9.529l-.054.229c-.391 1.8-.423 3.633-.42 5.471l-.001.74c.002 1.4.001 2.801-.004 4.201l-.004 3.779c0 1.824-.001 3.649-.003 5.473l-.006 2.813-.005 6.076-.001.267-.008 8.614c-.001 2.023-.004 4.045-.006 6.066v.259l-.004 2.55-.006 5.46c0 1.331-.001 2.658-.003 3.985-.002.72-.002 1.438-.002 2.156 0 .658 0 1.317-.002 1.978v.708c.004 2.098-.07 4.214-.545 6.263l-.077.359-.161.716c-.071.302-.136.605-.199.909-.55 2.538-1.6 5.067-2.832 7.348l-.214.42c-.965 1.921-2.22 3.714-3.574 5.38l-.152.183c-.78.973-1.639 1.866-2.519 2.751l-.308.313a25.81 25.81 0 0 1-2.226 1.955l-.22.179c-3.698 2.953-7.975 5.044-12.538 6.262-.212.056-.422.115-.631.176-8.366 2.287-17.8.738-25.278-3.512-3.639-2.122-7.171-4.945-9.721-8.307-.121-.15-.241-.298-.356-.448a36.247 36.247 0 0 1-2.605-3.814l-.144-.234c-.889-1.466-1.562-3.034-2.222-4.617l-.11-.265c-3.253-7.791-2.911-17.367.184-25.133.865-2.069 1.869-4.089 3.123-5.951l.172-.261a31.91 31.91 0 0 1 2.547-3.29l.229-.263c.13-.152.266-.304.396-.452l.425-.493c1.216-1.389 2.593-2.615 4.068-3.723.208-.157.414-.315.62-.476 1.184-.901 2.437-1.665 3.729-2.4l.272-.159c1.586-.893 3.235-1.573 4.934-2.21l.253-.097c4.232-1.567 8.615-1.836 13.079-1.82 1.359 0 2.732.002 4.093.007 1.209.005 2.417.006 3.621.006 1.899.002 3.794.007 5.688.012v12.78l-3.612.013-2.282.011c-1.201.005-2.401.012-3.61.016-.876.003-1.751.005-2.629.013-.463.002-.924.005-1.387.006-4.322.005-8.193.592-12.033 2.662l-.217.114c-1.458.773-2.697 1.731-3.908 2.849-.206.185-.413.362-.63.535-.435.376-.794.788-1.16 1.232l-.153.18a21.18 21.18 0 0 0-4.474 8.651l-.094.342c-.42 1.682-.54 3.395-.536 5.127v.272c.019 5.672 2.392 10.671 6.206 14.769l.215.237c3.296 3.453 8.483 5.917 13.247 6.046.448.008.896.01 1.345.01.276 0 .553.003.835.005 4.917.019 9.864-1.73 13.577-4.995l.303-.267c.299-.263.592-.527.881-.799l.262-.247c.787-.756 1.451-1.599 2.104-2.474l.151-.201c1.929-2.606 3.117-5.723 3.635-8.909l.059-.362c.194-1.296.21-2.573.207-3.883l.003-.74v-2.02c0-.73 0-1.459.005-2.188v-3.782c0-1.827.004-3.654.007-5.481 0-.939 0-1.877.004-2.816l.003-6.082v-.268c.005-2.876.008-5.75.008-8.627l.013-8.883c.004-1.823.004-3.646.004-5.469 0-1.33.004-2.659.004-3.989.003-.721.003-1.442.003-2.159v-1.98c.005-.237.005-.473 0-.711-.011-8.523 3.072-17.023 8.941-23.268.244-.263.483-.531.717-.805.416-.48.861-.918 1.324-1.352l.252-.232a26.259 26.259 0 0 1 2.184-1.812l.46-.349c1.39-1.058 2.837-1.951 4.375-2.775l.318-.172c5.005-2.666 10.5-3.877 16.15-3.889Z" style="transform-box:fill-box;transform-origin:50% 50%" transform="rotate(-31 0 0)"/></svg>
@@ -1,153 +0,0 @@
1
- @import 'tailwindcss';
2
-
3
- body {
4
- font-family:
5
- system-ui,
6
- -apple-system,
7
- BlinkMacSystemFont,
8
- 'Segoe UI',
9
- 'Open Sans',
10
- 'Helvetica Neue',
11
- sans-serif;
12
-
13
- background-color: hsl(var(--background));
14
- color: hsl(var(--foreground));
15
- }
16
-
17
- @theme {
18
- --color-accent: hsl(var(--accent));
19
- --color-accent-foreground: hsl(var(--accent-foreground));
20
-
21
- --color-background: hsl(var(--background));
22
- --color-foreground: hsl(var(--foreground));
23
- --color-border: hsl(var(--border));
24
- --color-ring: hsl(var(--ring));
25
-
26
- --color-card: hsl(var(--card));
27
- --color-card-foreground: hsl(var(--card-foreground));
28
-
29
- --color-muted: hsl(var(--muted));
30
- --color-muted-foreground: hsl(var(--muted-foreground));
31
-
32
- --color-secondary: hsl(var(--secondary));
33
- --color-secondary-foreground: hsl(var(--secondary-foreground));
34
-
35
- --color-destructive: hsl(var(--destructive));
36
- --color-destructive-foreground: hsl(var(--destructive-foreground));
37
- }
38
-
39
- @layer utilities {
40
- .text-balance {
41
- text-wrap: balance;
42
- }
43
- }
44
-
45
- @layer base {
46
- :root {
47
- --background: 0 0% 100%;
48
- --foreground: 0 0% 3.9%;
49
- --card: 0 0% 100%;
50
- --card-foreground: 0 0% 3.9%;
51
- --popover: 0 0% 100%;
52
- --popover-foreground: 0 0% 3.9%;
53
- --primary: 0 0% 9%;
54
- --primary-foreground: 0 0% 98%;
55
- --secondary: 0 0% 96.1%;
56
- --secondary-foreground: 0 0% 9%;
57
- --muted: 0 0% 96.1%;
58
- --muted-foreground: 0 0 40%;
59
- --accent: 0 0% 96.1%;
60
- --accent-foreground: 0 0% 9%;
61
- --destructive: 0 84.2% 60.2%;
62
- --destructive-foreground: 0 0% 98%;
63
- --border: 0 0% 89.8%;
64
- --input: 0 0% 89.8%;
65
- --ring: 0 0% 3.9%;
66
- --chart-1: 12 76% 61%;
67
- --chart-2: 173 58% 39%;
68
- --chart-3: 197 37% 24%;
69
- --chart-4: 43 74% 66%;
70
- --chart-5: 27 87% 67%;
71
- --radius: 0.5rem;
72
- --sidebar-background: 0 0% 98%;
73
- --sidebar-foreground: 240 5.3% 26.1%;
74
- --sidebar-primary: 240 5.9% 10%;
75
- --sidebar-primary-foreground: 0 0% 98%;
76
- --sidebar-accent: 240 4.8% 95.9%;
77
- --sidebar-accent-foreground: 240 5.9% 10%;
78
- --sidebar-border: 220 13% 91%;
79
- --sidebar-ring: 217.2 91.2% 59.8%;
80
- }
81
- @media (prefers-color-scheme: dark) {
82
- :root {
83
- --background: 0 0% 3.9%;
84
- --foreground: 0 0% 98%;
85
- --card: 0 0% 3.9%;
86
- --card-foreground: 0 0% 98%;
87
- --popover: 0 0% 3.9%;
88
- --popover-foreground: 0 0% 98%;
89
- --primary: 0 0% 98%;
90
- --primary-foreground: 0 0% 9%;
91
- --secondary: 0 0% 14.9%;
92
- --secondary-foreground: 0 0% 98%;
93
- --muted: 0 0% 14.9%;
94
- --muted-foreground: 0 0% 63.9%;
95
- --accent: 0 0% 14.9%;
96
- --accent-foreground: 0 0% 98%;
97
- --destructive: 0 62.8% 30.6%;
98
- --destructive-foreground: 0 0% 98%;
99
- --border: 0 0% 14.9%;
100
- --input: 0 0% 14.9%;
101
- --ring: 0 0% 83.1%;
102
- --chart-1: 220 70% 50%;
103
- --chart-2: 160 60% 45%;
104
- --chart-3: 30 80% 55%;
105
- --chart-4: 280 65% 60%;
106
- --chart-5: 340 75% 55%;
107
- --sidebar-background: 240 5.9% 10%;
108
- --sidebar-foreground: 240 4.8% 95.9%;
109
- --sidebar-primary: 224.3 76.3% 48%;
110
- --sidebar-primary-foreground: 0 0% 100%;
111
- --sidebar-accent: 240 3.7% 15.9%;
112
- --sidebar-accent-foreground: 240 4.8% 95.9%;
113
- --sidebar-border: 240 3.7% 15.9%;
114
- --sidebar-ring: 217.2 91.2% 59.8%;
115
- }
116
- }
117
-
118
- * {
119
- @apply border-border;
120
- }
121
- }
122
-
123
- textarea {
124
- resize: none;
125
- }
126
-
127
- .squircle {
128
- border-radius: 32px;
129
- corner-shape: squircle;
130
- }
131
-
132
- ::backdrop {
133
- backdrop-filter: blur(4px);
134
- }
135
-
136
- [popover] {
137
- transition:
138
- opacity 150ms ease-in-out,
139
- display 150ms ease-out allow-discrete,
140
- overlay 150ms ease-out allow-discrete;
141
- opacity: 0;
142
- }
143
-
144
- [popover]:popover-open {
145
- opacity: 1;
146
- display: block;
147
- }
148
-
149
- @starting-style {
150
- [popover]:popover-open {
151
- opacity: 0;
152
- }
153
- }
@@ -1,5 +0,0 @@
1
- export default new Map([
2
- ['en-US', 'English'],
3
- ['de-DE', 'Deutsch (German)'],
4
- ['ja-JP', '日本語 (Japanese)'],
5
- ]);