create-fate 1.0.3 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/bin/create-fate.mjs +594 -9
- package/package.json +2 -2
- package/templates/fate/README.md +3 -0
- package/templates/fate/_shared/vue-app/package.json +54 -0
- package/templates/fate/_shared/vue-app/pages/index.vue +57 -0
- package/templates/fate/_shared/vue-app/pages/layout.vue +32 -0
- package/templates/fate/_shared/vue-app/pages/post/[id].vue +24 -0
- package/templates/fate/_shared/vue-app/src/App.css +63 -0
- package/templates/fate/_shared/vue-app/src/fateViews.ts +14 -0
- package/templates/fate/_shared/vue-app/src/lib/cx.ts +6 -0
- package/templates/fate/_shared/vue-app/src/lib/env.ts +3 -0
- package/templates/fate/_shared/vue-app/src/ui/Button.vue +67 -0
- package/templates/fate/_shared/vue-app/src/ui/Card.vue +16 -0
- package/templates/fate/_shared/vue-app/src/ui/Error.vue +9 -0
- package/templates/fate/_shared/vue-app/src/ui/ErrorBoundary.vue +22 -0
- package/templates/fate/_shared/vue-app/src/ui/Header.vue +35 -0
- package/templates/fate/_shared/vue-app/src/ui/Link.vue +15 -0
- package/templates/fate/_shared/vue-app/src/ui/PostCard.vue +29 -0
- package/templates/fate/_shared/vue-app/src/ui/Section.vue +19 -0
- package/templates/fate/_shared/vue-app/src/ui/Thinking.vue +11 -0
- package/templates/fate/_shared/vue-app/src/ui/UserCard.vue +23 -0
- package/templates/fate/_shared/vue-app/src/vue-shims.d.ts +6 -0
- package/templates/fate/_shared/vue-app/tsconfig.json +22 -0
- package/templates/fate/_shared/vue-app/vite.config.ts +58 -0
- package/templates/fate/_shared/vue-app/void.json +5 -0
- package/templates/fate/cloudflare/.github/workflows/push.yml +27 -0
- package/templates/fate/cloudflare/.vite-hooks/pre-commit +1 -0
- package/templates/fate/cloudflare/.vscode/extensions.json +12 -0
- package/templates/fate/cloudflare/.vscode/settings.json +25 -0
- package/templates/fate/cloudflare/AGENTS.md +55 -0
- package/templates/fate/cloudflare/README.md +126 -0
- package/templates/fate/cloudflare/_gitignore +20 -0
- package/templates/fate/cloudflare/client/package.json +56 -0
- package/templates/fate/cloudflare/client/pages/index.tsx +96 -0
- package/templates/fate/cloudflare/client/pages/layout.tsx +82 -0
- package/templates/fate/cloudflare/client/pages/login.tsx +107 -0
- package/templates/fate/cloudflare/client/pages/post/[id].tsx +22 -0
- package/templates/fate/cloudflare/client/pages/search.tsx +99 -0
- package/templates/fate/cloudflare/client/public/icon.svg +1 -0
- package/templates/fate/cloudflare/client/src/App.css +153 -0
- package/templates/fate/cloudflare/client/src/lib/AvailableLanguages.tsx +5 -0
- package/templates/fate/cloudflare/client/src/lib/cx.tsx +6 -0
- package/templates/fate/cloudflare/client/src/lib/env.tsx +5 -0
- package/templates/fate/cloudflare/client/src/ui/Badge.tsx +31 -0
- package/templates/fate/cloudflare/client/src/ui/Button.tsx +108 -0
- package/templates/fate/cloudflare/client/src/ui/Card.tsx +32 -0
- package/templates/fate/cloudflare/client/src/ui/CommentCard.tsx +75 -0
- package/templates/fate/cloudflare/client/src/ui/Error.tsx +19 -0
- package/templates/fate/cloudflare/client/src/ui/H2.tsx +15 -0
- package/templates/fate/cloudflare/client/src/ui/H3.tsx +20 -0
- package/templates/fate/cloudflare/client/src/ui/Header.tsx +98 -0
- package/templates/fate/cloudflare/client/src/ui/Input.tsx +17 -0
- package/templates/fate/cloudflare/client/src/ui/Link.tsx +11 -0
- package/templates/fate/cloudflare/client/src/ui/LocaleSwitcher.tsx +52 -0
- package/templates/fate/cloudflare/client/src/ui/PostCard.tsx +303 -0
- package/templates/fate/cloudflare/client/src/ui/Section.tsx +23 -0
- package/templates/fate/cloudflare/client/src/ui/UserCard.tsx +131 -0
- package/templates/fate/cloudflare/client/src/user/AuthClient.tsx +6 -0
- package/templates/fate/cloudflare/client/translations/de_DE.json +689 -0
- package/templates/fate/cloudflare/client/translations/ja_JP.json +689 -0
- package/templates/fate/cloudflare/client/vite.config.ts +45 -0
- package/templates/fate/cloudflare/client/void.json +29 -0
- package/templates/fate/cloudflare/package.json +46 -0
- package/templates/fate/cloudflare/pnpm-workspace.yaml +39 -0
- package/templates/fate/cloudflare/server/.env.example +1 -0
- package/templates/fate/cloudflare/server/db/db.ts +30 -0
- package/templates/fate/cloudflare/server/db/migrations/20260508073357_initial_schema.sql +133 -0
- package/templates/fate/cloudflare/server/db/migrations/20260508120500_seed_cloudflare_demo.sql +170 -0
- package/templates/fate/cloudflare/server/db/migrations/meta/20260508073357_snapshot.json +868 -0
- package/templates/fate/cloudflare/server/db/migrations/meta/_journal.json +20 -0
- package/templates/fate/cloudflare/server/db/queries.ts +211 -0
- package/templates/fate/cloudflare/server/db/schema.ts +332 -0
- package/templates/fate/cloudflare/server/package.json +34 -0
- package/templates/fate/cloudflare/server/src/fate/commentPermissions.ts +17 -0
- package/templates/fate/cloudflare/server/src/fate/context.ts +15 -0
- package/templates/fate/cloudflare/server/src/fate/live.ts +7 -0
- package/templates/fate/cloudflare/server/src/fate/server.ts +411 -0
- package/templates/fate/cloudflare/server/src/fate/views.ts +164 -0
- package/templates/fate/cloudflare/server/src/index.ts +80 -0
- package/templates/fate/cloudflare/server/src/lib/auth.ts +66 -0
- package/templates/fate/cloudflare/server/src/lib/origins.ts +17 -0
- package/templates/fate/cloudflare/server/src/router.ts +2 -0
- package/templates/fate/cloudflare/server/src/user/SessionUser.tsx +17 -0
- package/templates/fate/cloudflare/server/tsconfig.json +10 -0
- package/templates/fate/cloudflare/server/wrangler.jsonc +29 -0
- package/templates/fate/cloudflare/tsconfig.json +33 -0
- package/templates/fate/cloudflare/vite.config.ts +72 -0
- package/templates/fate/drizzle/README.md +2 -8
- package/templates/fate/drizzle/client/pages/layout.tsx +2 -2
- package/templates/fate/drizzle/client/src/ui/PostCard.tsx +38 -15
- package/templates/fate/drizzle/pnpm-workspace.yaml +9 -3
- package/templates/fate/drizzle/server/vite.config.ts +1 -1
- package/templates/fate/graphql/.github/workflows/push.yml +27 -0
- package/templates/fate/graphql/.vite-hooks/pre-commit +1 -0
- package/templates/fate/graphql/.vscode/extensions.json +12 -0
- package/templates/fate/graphql/.vscode/settings.json +25 -0
- package/templates/fate/graphql/AGENTS.md +55 -0
- package/templates/fate/graphql/README.md +121 -0
- package/templates/fate/graphql/_gitignore +23 -0
- package/templates/fate/graphql/client/package.json +57 -0
- package/templates/fate/graphql/client/pages/index.tsx +96 -0
- package/templates/fate/graphql/client/pages/layout.tsx +83 -0
- package/templates/fate/graphql/client/pages/login.tsx +107 -0
- package/templates/fate/graphql/client/pages/post/[id].tsx +22 -0
- package/templates/fate/graphql/client/pages/search.tsx +99 -0
- package/templates/fate/graphql/client/public/icon.svg +1 -0
- package/templates/fate/graphql/client/src/App.css +153 -0
- package/templates/fate/graphql/client/src/lib/AvailableLanguages.tsx +5 -0
- package/templates/fate/graphql/client/src/lib/cx.tsx +6 -0
- package/templates/fate/graphql/client/src/lib/env.tsx +5 -0
- package/templates/fate/graphql/client/src/ui/Badge.tsx +31 -0
- package/templates/fate/graphql/client/src/ui/Button.tsx +108 -0
- package/templates/fate/graphql/client/src/ui/Card.tsx +32 -0
- package/templates/fate/graphql/client/src/ui/CommentCard.tsx +75 -0
- package/templates/fate/graphql/client/src/ui/Error.tsx +19 -0
- package/templates/fate/graphql/client/src/ui/H2.tsx +15 -0
- package/templates/fate/graphql/client/src/ui/H3.tsx +20 -0
- package/templates/fate/graphql/client/src/ui/Header.tsx +98 -0
- package/templates/fate/graphql/client/src/ui/Input.tsx +17 -0
- package/templates/fate/graphql/client/src/ui/Link.tsx +11 -0
- package/templates/fate/graphql/client/src/ui/LocaleSwitcher.tsx +52 -0
- package/templates/fate/graphql/client/src/ui/PostCard.tsx +303 -0
- package/templates/fate/graphql/client/src/ui/Section.tsx +23 -0
- package/templates/fate/graphql/client/src/ui/UserCard.tsx +131 -0
- package/templates/fate/graphql/client/src/user/AuthClient.tsx +6 -0
- package/templates/fate/graphql/client/translations/de_DE.json +689 -0
- package/templates/fate/graphql/client/translations/ja_JP.json +689 -0
- package/templates/fate/graphql/client/vite.config.ts +40 -0
- package/templates/fate/graphql/client/void.json +29 -0
- package/templates/fate/graphql/docker-compose.yml +11 -0
- package/templates/fate/graphql/package.json +47 -0
- package/templates/fate/graphql/pnpm-workspace.yaml +45 -0
- package/templates/fate/graphql/server/.env.example +5 -0
- package/templates/fate/graphql/server/README.md +27 -0
- package/templates/fate/graphql/server/package.json +64 -0
- package/templates/fate/graphql/server/prisma.config.ts +17 -0
- package/templates/fate/graphql/server/scripts/generate-graphql.tsx +40 -0
- package/templates/fate/graphql/server/src/__tests__/index.test.tsx +5 -0
- package/templates/fate/graphql/server/src/app.tsx +47 -0
- package/templates/fate/graphql/server/src/graphql/builder.tsx +121 -0
- package/templates/fate/graphql/server/src/graphql/context.tsx +22 -0
- package/templates/fate/graphql/server/src/graphql/fate.ts +85 -0
- package/templates/fate/graphql/server/src/graphql/lib/authDirectives.tsx +93 -0
- package/templates/fate/graphql/server/src/graphql/lib/decodeGlobalID.tsx +12 -0
- package/templates/fate/graphql/server/src/graphql/lib/decodeIDOrThrow.tsx +10 -0
- package/templates/fate/graphql/server/src/graphql/lib/encodeGlobalID.tsx +5 -0
- package/templates/fate/graphql/server/src/graphql/live.tsx +241 -0
- package/templates/fate/graphql/server/src/graphql/mutations.tsx +265 -0
- package/templates/fate/graphql/server/src/graphql/nodes/Category.tsx +35 -0
- package/templates/fate/graphql/server/src/graphql/nodes/Comment.tsx +46 -0
- package/templates/fate/graphql/server/src/graphql/nodes/Event.tsx +71 -0
- package/templates/fate/graphql/server/src/graphql/nodes/Post.tsx +45 -0
- package/templates/fate/graphql/server/src/graphql/nodes/Tag.tsx +11 -0
- package/templates/fate/graphql/server/src/graphql/nodes/User.tsx +28 -0
- package/templates/fate/graphql/server/src/graphql/schema.tsx +16 -0
- package/templates/fate/graphql/server/src/graphql/views.ts +193 -0
- package/templates/fate/graphql/server/src/index.tsx +45 -0
- package/templates/fate/graphql/server/src/lib/auth.tsx +31 -0
- package/templates/fate/graphql/server/src/lib/env.tsx +3 -0
- package/templates/fate/graphql/server/src/lib/origins.ts +18 -0
- package/templates/fate/graphql/server/src/prisma/prisma.tsx +9 -0
- package/templates/fate/graphql/server/src/prisma/schema.prisma +181 -0
- package/templates/fate/graphql/server/src/prisma/seed.tsx +161 -0
- package/templates/fate/graphql/server/src/user/SessionUser.tsx +17 -0
- package/templates/fate/graphql/server/src/user/isAdmin.tsx +3 -0
- package/templates/fate/graphql/server/tsconfig.json +33 -0
- package/templates/fate/graphql/server/vite.config.ts +55 -0
- package/templates/fate/graphql/tsconfig.json +33 -0
- package/templates/fate/graphql/vite.config.ts +80 -0
- package/templates/fate/graphql-client/.env.example +3 -0
- package/templates/fate/graphql-client/AGENTS.md +3 -0
- package/templates/fate/graphql-client/README.md +69 -0
- package/templates/fate/graphql-client/_gitignore +14 -0
- package/templates/fate/graphql-client/package.json +62 -0
- package/templates/fate/graphql-client/pages/index.tsx +69 -0
- package/templates/fate/graphql-client/pages/layout.tsx +41 -0
- package/templates/fate/graphql-client/pnpm-workspace.yaml +38 -0
- package/templates/fate/graphql-client/public/icon.svg +8 -0
- package/templates/fate/graphql-client/src/App.css +28 -0
- package/templates/fate/graphql-client/src/fate/graphql.ts +52 -0
- package/templates/fate/graphql-client/tsconfig.json +30 -0
- package/templates/fate/graphql-client/vite.config.ts +87 -0
- package/templates/fate/graphql-client/void.json +29 -0
- package/templates/fate/http/README.md +2 -8
- package/templates/fate/http/client/pages/layout.tsx +2 -2
- package/templates/fate/http/client/src/ui/PostCard.tsx +37 -15
- package/templates/fate/http/pnpm-workspace.yaml +9 -3
- package/templates/fate/http/server/vite.config.ts +1 -1
- package/templates/fate/prisma/README.md +2 -8
- package/templates/fate/prisma/client/pages/layout.tsx +2 -2
- package/templates/fate/prisma/client/src/ui/PostCard.tsx +37 -15
- package/templates/fate/prisma/pnpm-workspace.yaml +9 -3
- package/templates/fate/prisma/server/vite.config.ts +1 -1
- package/templates/fate/prisma/vite.config.ts +1 -1
- package/templates/fate/void/package.json +10 -2
- package/templates/fate/void/pages/login.tsx +3 -3
- package/templates/fate/void/pnpm-workspace.yaml +12 -4
- package/templates/fate/void/src/ui/Button.tsx +42 -26
- package/templates/fate/void/src/ui/CategoryCard.tsx +3 -7
- package/templates/fate/void/src/ui/PostCard.tsx +38 -15
- package/templates/fate/void/vite.config.ts +15 -14
- package/templates/fate/drizzle/public/fate-logo-dark.svg +0 -4
- package/templates/fate/drizzle/public/fate-logo.svg +0 -4
- package/templates/fate/http/public/fate-logo-dark.svg +0 -4
- package/templates/fate/http/public/fate-logo.svg +0 -4
- package/templates/fate/prisma/public/fate-logo-dark.svg +0 -4
- package/templates/fate/prisma/public/fate-logo.svg +0 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-fate",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Create a new fate app.",
|
|
5
5
|
"homepage": "https://github.com/nkzw-tech/fate",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
],
|
|
23
23
|
"type": "module",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@clack/prompts": "^1.
|
|
25
|
+
"@clack/prompts": "^1.5.0"
|
|
26
26
|
},
|
|
27
27
|
"engines": {
|
|
28
28
|
"node": ">=24.0.0"
|
package/templates/fate/README.md
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
This directory is the canonical source for fate project scaffolds.
|
|
4
4
|
|
|
5
5
|
- `void/` contains the Void pages router + Drizzle template.
|
|
6
|
+
- `cloudflare/` contains the Cloudflare Workers + D1 + Drizzle template.
|
|
6
7
|
- `drizzle/` contains the tRPC + Drizzle template.
|
|
8
|
+
- `graphql/` contains the GraphQL + Prisma template.
|
|
9
|
+
- `graphql-client/` contains the existing GraphQL server template.
|
|
7
10
|
- `http/` contains the native HTTP + Drizzle template.
|
|
8
11
|
- `prisma/` contains the tRPC + Prisma template.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@app/client",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "fate is a modern data client for Vue.",
|
|
6
|
+
"author": "Christoph Nakazawa <christoph.pojer@gmail.com>",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git://github.com/nkzw-tech/fate.git"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "vp build",
|
|
14
|
+
"dev": "vp dev",
|
|
15
|
+
"dev:setup": "vp run prepare:void && vp run fate:generate",
|
|
16
|
+
"fate:generate": "vp exec fate generate",
|
|
17
|
+
"prepare:void": "void prepare"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@nkzw/core": "^1.3.1",
|
|
21
|
+
"@nkzw/define-env": "^1.1.0",
|
|
22
|
+
"@trpc/client": "^11.17.0",
|
|
23
|
+
"@void/vue": "^0.9.2",
|
|
24
|
+
"class-variance-authority": "^0.7.1",
|
|
25
|
+
"clsx": "^2.1.1",
|
|
26
|
+
"dotenv": "^17.4.2",
|
|
27
|
+
"graphql-sse": "^2.6.0",
|
|
28
|
+
"lucide-vue-next": "^0.561.0",
|
|
29
|
+
"tailwind-merge": "^3.5.0",
|
|
30
|
+
"void": "^0.9.2",
|
|
31
|
+
"vue": "^3.5.24",
|
|
32
|
+
"vue-fate": "latest"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@nkzw/eslint-plugin": "^2.0.0",
|
|
36
|
+
"@nkzw/oxlint-config": "^1.2.1",
|
|
37
|
+
"@swc/core": "^1.15.33",
|
|
38
|
+
"@tailwindcss/vite": "^4.2.4",
|
|
39
|
+
"@types/node": "^25.6.0",
|
|
40
|
+
"@typescript/native-preview": "7.0.0-dev.20260505.1",
|
|
41
|
+
"eslint-plugin-no-only-tests": "^3.4.0",
|
|
42
|
+
"eslint-plugin-perfectionist": "^5.9.0",
|
|
43
|
+
"tailwindcss": "^4.2.4",
|
|
44
|
+
"ts-node": "^10.9.2",
|
|
45
|
+
"vite": "catalog:",
|
|
46
|
+
"vite-plus": "catalog:",
|
|
47
|
+
"vitest": "catalog:"
|
|
48
|
+
},
|
|
49
|
+
"browserslist": [
|
|
50
|
+
">0.2%",
|
|
51
|
+
"not dead",
|
|
52
|
+
"not op_mini all"
|
|
53
|
+
]
|
|
54
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useListView, useRequest } from 'vue-fate';
|
|
3
|
+
import { PostView, UserView } from '../src/fateViews.ts';
|
|
4
|
+
import Button from '../src/ui/Button.vue';
|
|
5
|
+
import Card from '../src/ui/Card.vue';
|
|
6
|
+
import PostCard from '../src/ui/PostCard.vue';
|
|
7
|
+
import Section from '../src/ui/Section.vue';
|
|
8
|
+
import UserCard from '../src/ui/UserCard.vue';
|
|
9
|
+
|
|
10
|
+
const PostConnectionView = {
|
|
11
|
+
args: { first: 10 },
|
|
12
|
+
items: {
|
|
13
|
+
node: PostView,
|
|
14
|
+
},
|
|
15
|
+
pagination: {
|
|
16
|
+
hasNext: true,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const request = useRequest({
|
|
21
|
+
posts: { list: PostConnectionView },
|
|
22
|
+
viewer: { view: UserView },
|
|
23
|
+
});
|
|
24
|
+
const { posts: postsRef, viewer } = await request.ready();
|
|
25
|
+
const [posts, loadNext] = useListView(PostConnectionView, postsRef);
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<template>
|
|
29
|
+
<Section :gap="32">
|
|
30
|
+
<div class="grid gap-8 lg:grid-cols-[1.6fr_1fr] lg:items-stretch">
|
|
31
|
+
<Card class="border border-white/20 bg-linear-to-r from-blue-500 to-sky-500 text-white">
|
|
32
|
+
<div class="space-y-3">
|
|
33
|
+
<p class="text-xs font-semibold tracking-widest uppercase">
|
|
34
|
+
<span class="lowercase italic">fate</span> demo
|
|
35
|
+
</p>
|
|
36
|
+
<h1 class="text-3xl leading-tight font-semibold text-balance lg:text-4xl">
|
|
37
|
+
fate is a modern data client for Vue inspired by Relay and GraphQL.
|
|
38
|
+
</h1>
|
|
39
|
+
<p class="text-sm text-white/80 lg:text-base">
|
|
40
|
+
This template uses Vue-native fate composables, normalized caching, data masking, and
|
|
41
|
+
type-safe data fetching.
|
|
42
|
+
</p>
|
|
43
|
+
</div>
|
|
44
|
+
</Card>
|
|
45
|
+
<UserCard v-if="viewer" :viewer="viewer" />
|
|
46
|
+
</div>
|
|
47
|
+
<div v-if="posts.length" class="flex flex-col gap-4">
|
|
48
|
+
<h2 class="pl-5 text-2xl font-semibold tracking-tight">Latest posts</h2>
|
|
49
|
+
<div class="flex flex-col gap-4">
|
|
50
|
+
<PostCard v-for="{ node } in posts" :key="node.id" :post="node" />
|
|
51
|
+
</div>
|
|
52
|
+
<div v-if="loadNext" class="flex justify-center">
|
|
53
|
+
<Button :action="loadNext" variant="ghost">Load more posts</Button>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</Section>
|
|
57
|
+
</template>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import '../src/App.css';
|
|
3
|
+
import { computed } from 'vue';
|
|
4
|
+
import { FateClient } from 'vue-fate';
|
|
5
|
+
import { createFateClient } from 'vue-fate/client';
|
|
6
|
+
/* __CLIENT_IMPORTS__ */
|
|
7
|
+
import ErrorBoundary from '../src/ui/ErrorBoundary.vue';
|
|
8
|
+
import Header from '../src/ui/Header.vue';
|
|
9
|
+
import Thinking from '../src/ui/Thinking.vue';
|
|
10
|
+
|
|
11
|
+
const fate = computed(() => createFateClient(__CREATE_FATE_OPTIONS__));
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<template>
|
|
15
|
+
<div class="min-h-screen bg-background text-foreground">
|
|
16
|
+
<div
|
|
17
|
+
class="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%)]"
|
|
18
|
+
>
|
|
19
|
+
<Header />
|
|
20
|
+
<FateClient :client="fate">
|
|
21
|
+
<ErrorBoundary>
|
|
22
|
+
<Suspense timeout="0">
|
|
23
|
+
<slot />
|
|
24
|
+
<template #fallback>
|
|
25
|
+
<Thinking />
|
|
26
|
+
</template>
|
|
27
|
+
</Suspense>
|
|
28
|
+
</ErrorBoundary>
|
|
29
|
+
</FateClient>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</template>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useParams } from '@void/vue';
|
|
3
|
+
import { useRequest } from 'vue-fate';
|
|
4
|
+
import { PostView } from '../../src/fateViews.ts';
|
|
5
|
+
import PostCard from '../../src/ui/PostCard.vue';
|
|
6
|
+
import Section from '../../src/ui/Section.vue';
|
|
7
|
+
|
|
8
|
+
const params = useParams<{ id: string }>();
|
|
9
|
+
const id = params.id;
|
|
10
|
+
|
|
11
|
+
if (!id) {
|
|
12
|
+
throw new Error('fate: Post ID is required.');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { post } = await useRequest({
|
|
16
|
+
post: { id, view: PostView },
|
|
17
|
+
}).ready();
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<Section>
|
|
22
|
+
<PostCard :post="post" />
|
|
23
|
+
</Section>
|
|
24
|
+
</template>
|
|
@@ -0,0 +1,63 @@
|
|
|
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-background: hsl(var(--background));
|
|
19
|
+
--color-foreground: hsl(var(--foreground));
|
|
20
|
+
--color-border: hsl(var(--border));
|
|
21
|
+
--color-card: hsl(var(--card));
|
|
22
|
+
--color-card-foreground: hsl(var(--card-foreground));
|
|
23
|
+
--color-muted-foreground: hsl(var(--muted-foreground));
|
|
24
|
+
--color-primary: hsl(var(--primary));
|
|
25
|
+
--color-primary-foreground: hsl(var(--primary-foreground));
|
|
26
|
+
--color-secondary: hsl(var(--secondary));
|
|
27
|
+
--color-secondary-foreground: hsl(var(--secondary-foreground));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@layer base {
|
|
31
|
+
:root {
|
|
32
|
+
--background: 0 0% 100%;
|
|
33
|
+
--foreground: 0 0% 3.9%;
|
|
34
|
+
--card: 0 0% 100%;
|
|
35
|
+
--card-foreground: 0 0% 3.9%;
|
|
36
|
+
--border: 0 0% 89.8%;
|
|
37
|
+
--muted-foreground: 0 0% 40%;
|
|
38
|
+
--primary: 0 0% 9%;
|
|
39
|
+
--primary-foreground: 0 0% 98%;
|
|
40
|
+
--secondary: 0 0% 96.1%;
|
|
41
|
+
--secondary-foreground: 0 0% 9%;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@media (prefers-color-scheme: dark) {
|
|
45
|
+
:root {
|
|
46
|
+
--background: 0 0% 3.9%;
|
|
47
|
+
--foreground: 0 0% 98%;
|
|
48
|
+
--card: 0 0% 3.9%;
|
|
49
|
+
--card-foreground: 0 0% 98%;
|
|
50
|
+
--border: 0 0% 14.9%;
|
|
51
|
+
--muted-foreground: 0 0% 63.9%;
|
|
52
|
+
--primary: 0 0% 98%;
|
|
53
|
+
--primary-foreground: 0 0% 9%;
|
|
54
|
+
--secondary: 0 0% 14.9%;
|
|
55
|
+
--secondary-foreground: 0 0% 98%;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.squircle {
|
|
61
|
+
border-radius: 32px;
|
|
62
|
+
corner-shape: squircle;
|
|
63
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Post, User } from '__FATE_TYPE_MODULE__';
|
|
2
|
+
import { view } from 'vue-fate';
|
|
3
|
+
|
|
4
|
+
export const UserView = view<User>()({
|
|
5
|
+
id: true,
|
|
6
|
+
name: true,
|
|
7
|
+
username: true,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export const PostView = view<Post>()({
|
|
11
|
+
author: UserView,
|
|
12
|
+
id: true,
|
|
13
|
+
title: true,
|
|
14
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
|
+
import { computed, ref } from 'vue';
|
|
4
|
+
import cx from '../lib/cx.ts';
|
|
5
|
+
|
|
6
|
+
const buttonVariants = cva(
|
|
7
|
+
'squircle inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap text-sm font-medium transition-colors disabled:pointer-events-none disabled:opacity-50',
|
|
8
|
+
{
|
|
9
|
+
defaultVariants: {
|
|
10
|
+
size: 'default',
|
|
11
|
+
variant: 'default',
|
|
12
|
+
},
|
|
13
|
+
variants: {
|
|
14
|
+
size: {
|
|
15
|
+
default: 'h-10 px-3 py-2',
|
|
16
|
+
sm: 'h-9 px-2',
|
|
17
|
+
},
|
|
18
|
+
variant: {
|
|
19
|
+
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
|
20
|
+
ghost: 'hover:bg-secondary hover:text-secondary-foreground',
|
|
21
|
+
outline: 'border border-border bg-background hover:bg-secondary',
|
|
22
|
+
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
type ButtonVariants = VariantProps<typeof buttonVariants>;
|
|
29
|
+
|
|
30
|
+
const props = withDefaults(
|
|
31
|
+
defineProps<{
|
|
32
|
+
action?: () => Promise<unknown> | unknown;
|
|
33
|
+
class?: string;
|
|
34
|
+
disabled?: boolean;
|
|
35
|
+
size?: ButtonVariants['size'];
|
|
36
|
+
type?: 'button' | 'submit';
|
|
37
|
+
variant?: ButtonVariants['variant'];
|
|
38
|
+
}>(),
|
|
39
|
+
{
|
|
40
|
+
type: 'button',
|
|
41
|
+
},
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const isPending = ref(false);
|
|
45
|
+
const classes = computed(() =>
|
|
46
|
+
cx(buttonVariants({ size: props.size, variant: props.variant }), props.class),
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const onClick = async () => {
|
|
50
|
+
if (!props.action || isPending.value || props.disabled) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
isPending.value = true;
|
|
55
|
+
try {
|
|
56
|
+
await props.action();
|
|
57
|
+
} finally {
|
|
58
|
+
isPending.value = false;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
</script>
|
|
62
|
+
|
|
63
|
+
<template>
|
|
64
|
+
<button :class="classes" :disabled="disabled || isPending" :type="type" @click="onClick">
|
|
65
|
+
<slot />
|
|
66
|
+
</button>
|
|
67
|
+
</template>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue';
|
|
3
|
+
import cx from '../lib/cx.ts';
|
|
4
|
+
|
|
5
|
+
const props = defineProps<{ class?: string }>();
|
|
6
|
+
|
|
7
|
+
const classes = computed(() =>
|
|
8
|
+
cx('rounded-lg border border-border bg-card p-5 text-card-foreground shadow-sm', props.class),
|
|
9
|
+
);
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<div :class="classes">
|
|
14
|
+
<slot />
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { onErrorCaptured, ref } from 'vue';
|
|
3
|
+
import Card from './Card.vue';
|
|
4
|
+
import Error from './Error.vue';
|
|
5
|
+
import Section from './Section.vue';
|
|
6
|
+
|
|
7
|
+
const error = ref<unknown>(null);
|
|
8
|
+
|
|
9
|
+
onErrorCaptured((capturedError) => {
|
|
10
|
+
error.value = capturedError;
|
|
11
|
+
return false;
|
|
12
|
+
});
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<Section v-if="error">
|
|
17
|
+
<Card>
|
|
18
|
+
<Error :error="error" />
|
|
19
|
+
</Card>
|
|
20
|
+
</Section>
|
|
21
|
+
<slot v-else />
|
|
22
|
+
</template>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { Link } from '@void/vue';
|
|
3
|
+
import { Search } from 'lucide-vue-next';
|
|
4
|
+
import Button from './Button.vue';
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<header
|
|
9
|
+
class="sticky top-0 z-50 border-b border-white/60 bg-white/60 backdrop-blur dark:border-neutral-800 dark:bg-neutral-950/70"
|
|
10
|
+
>
|
|
11
|
+
<div class="container mx-auto flex h-16 max-w-5xl items-center justify-between gap-4 px-6">
|
|
12
|
+
<Link class="flex items-center gap-3" href="/">
|
|
13
|
+
<div
|
|
14
|
+
class="squircle flex h-10 w-10 items-center justify-center bg-linear-to-br from-gray-100 to-gray-200 text-gray-500 shadow-lg shadow-gray-500/20"
|
|
15
|
+
>
|
|
16
|
+
f
|
|
17
|
+
</div>
|
|
18
|
+
<div>
|
|
19
|
+
<span
|
|
20
|
+
class="bg-linear-to-r from-gray-500 to-gray-900 bg-clip-text text-xl font-semibold text-transparent dark:from-gray-200 dark:to-white"
|
|
21
|
+
>
|
|
22
|
+
<span class="italic">fate</span>
|
|
23
|
+
</span>
|
|
24
|
+
<p class="hidden text-xs text-muted-foreground sm:block">A modern data client for Vue.</p>
|
|
25
|
+
</div>
|
|
26
|
+
</Link>
|
|
27
|
+
<Button size="sm" variant="ghost">
|
|
28
|
+
<Link class="inline-flex items-center gap-2" href="/">
|
|
29
|
+
<Search class="h-4 w-4" />
|
|
30
|
+
<span class="hidden sm:inline">Home</span>
|
|
31
|
+
</Link>
|
|
32
|
+
</Button>
|
|
33
|
+
</div>
|
|
34
|
+
</header>
|
|
35
|
+
</template>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { Link as VoidLink } from '@void/vue';
|
|
3
|
+
|
|
4
|
+
defineProps<{
|
|
5
|
+
class?: string;
|
|
6
|
+
href?: string;
|
|
7
|
+
to?: string;
|
|
8
|
+
}>();
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<VoidLink :class="$props.class" :href="href ?? to ?? '/'">
|
|
13
|
+
<slot />
|
|
14
|
+
</VoidLink>
|
|
15
|
+
</template>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ViewRef } from 'vue-fate';
|
|
3
|
+
import { useView } from 'vue-fate';
|
|
4
|
+
import { PostView, UserView } from '../fateViews.ts';
|
|
5
|
+
import Card from './Card.vue';
|
|
6
|
+
import Link from './Link.vue';
|
|
7
|
+
|
|
8
|
+
const props = defineProps<{
|
|
9
|
+
post: ViewRef<'Post'>;
|
|
10
|
+
}>();
|
|
11
|
+
|
|
12
|
+
const post = useView(PostView, () => props.post);
|
|
13
|
+
const author = useView(UserView, () => post.value?.author ?? null);
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<Card v-if="post">
|
|
18
|
+
<article class="space-y-3">
|
|
19
|
+
<div>
|
|
20
|
+
<Link class="text-lg font-semibold hover:underline" :href="`/post/${post.id}`">
|
|
21
|
+
{{ post.title }}
|
|
22
|
+
</Link>
|
|
23
|
+
<p v-if="author" class="mt-1 text-sm text-muted-foreground">
|
|
24
|
+
By {{ author.name ?? author.username ?? author.id }}
|
|
25
|
+
</p>
|
|
26
|
+
</div>
|
|
27
|
+
</article>
|
|
28
|
+
</Card>
|
|
29
|
+
</template>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue';
|
|
3
|
+
import cx from '../lib/cx.ts';
|
|
4
|
+
|
|
5
|
+
const props = defineProps<{
|
|
6
|
+
class?: string;
|
|
7
|
+
gap?: number;
|
|
8
|
+
}>();
|
|
9
|
+
|
|
10
|
+
const classes = computed(() =>
|
|
11
|
+
cx('container mx-auto flex max-w-5xl flex-col px-4 py-6 lg:px-8 lg:py-10', props.class),
|
|
12
|
+
);
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<section :class="classes" :style="{ gap: `${gap ?? 16}px` }">
|
|
17
|
+
<slot />
|
|
18
|
+
</section>
|
|
19
|
+
</template>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ViewRef } from 'vue-fate';
|
|
3
|
+
import { useView } from 'vue-fate';
|
|
4
|
+
import { UserView } from '../fateViews.ts';
|
|
5
|
+
import Card from './Card.vue';
|
|
6
|
+
|
|
7
|
+
const props = defineProps<{
|
|
8
|
+
viewer: ViewRef<'User'>;
|
|
9
|
+
}>();
|
|
10
|
+
|
|
11
|
+
const viewer = useView(UserView, () => props.viewer);
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<template>
|
|
15
|
+
<Card v-if="viewer">
|
|
16
|
+
<div class="space-y-2">
|
|
17
|
+
<h2 class="text-sm font-medium text-muted-foreground">Viewer</h2>
|
|
18
|
+
<p class="text-lg font-semibold">
|
|
19
|
+
{{ viewer.name ?? viewer.username ?? viewer.id }}
|
|
20
|
+
</p>
|
|
21
|
+
</div>
|
|
22
|
+
</Card>
|
|
23
|
+
</template>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "__TSCONFIG_EXTENDS__",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"allowImportingTsExtensions": true,
|
|
5
|
+
"esModuleInterop": true,
|
|
6
|
+
"forceConsistentCasingInFileNames": true,
|
|
7
|
+
"incremental": true,
|
|
8
|
+
"isolatedModules": true,
|
|
9
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
10
|
+
"module": "ESNext",
|
|
11
|
+
"moduleResolution": "Bundler",
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"noImplicitOverride": true,
|
|
14
|
+
"noUnusedLocals": true,
|
|
15
|
+
"resolveJsonModule": true,
|
|
16
|
+
"skipLibCheck": true,
|
|
17
|
+
"strict": true,
|
|
18
|
+
"target": "ES2022",
|
|
19
|
+
"types": ["vite/client", "void/env"]
|
|
20
|
+
},
|
|
21
|
+
"include": "__TSCONFIG_INCLUDE__"
|
|
22
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import nkzw from '@nkzw/oxlint-config';
|
|
3
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
4
|
+
import { voidVue } from '@void/vue/plugin';
|
|
5
|
+
import dotenv from 'dotenv';
|
|
6
|
+
import { defineConfig, lazyPlugins } from 'vite-plus';
|
|
7
|
+
import { voidPlugin } from 'void';
|
|
8
|
+
import { fate } from 'vue-fate/vite';
|
|
9
|
+
|
|
10
|
+
const root = process.cwd();
|
|
11
|
+
__DOTENV_CONFIG__;
|
|
12
|
+
|
|
13
|
+
export default defineConfig({
|
|
14
|
+
/* __BUILD_CONFIG__ */
|
|
15
|
+
optimizeDeps: {
|
|
16
|
+
exclude: ['@nkzw/fate/client', 'vue-fate/client'],
|
|
17
|
+
},
|
|
18
|
+
fmt: {
|
|
19
|
+
experimentalSortImports: {
|
|
20
|
+
newlinesBetween: false,
|
|
21
|
+
},
|
|
22
|
+
experimentalSortPackageJson: {
|
|
23
|
+
sortScripts: true,
|
|
24
|
+
},
|
|
25
|
+
experimentalTailwindcss: {
|
|
26
|
+
stylesheet: 'src/App.css',
|
|
27
|
+
},
|
|
28
|
+
ignorePatterns: __FMT_IGNORE_PATTERNS__,
|
|
29
|
+
singleQuote: true,
|
|
30
|
+
},
|
|
31
|
+
lint: {
|
|
32
|
+
extends: [nkzw],
|
|
33
|
+
ignorePatterns: __LINT_IGNORE_PATTERNS__,
|
|
34
|
+
options: { typeAware: true, typeCheck: true },
|
|
35
|
+
rules: {
|
|
36
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
plugins: [
|
|
40
|
+
...(lazyPlugins(() => [tailwindcss(), voidPlugin(), voidVue()]) ?? []),
|
|
41
|
+
fate({
|
|
42
|
+
module: '__FATE_MODULE__',
|
|
43
|
+
/* __FATE_TRANSPORT__ */
|
|
44
|
+
}),
|
|
45
|
+
],
|
|
46
|
+
run: {
|
|
47
|
+
tasks: {
|
|
48
|
+
'test:all': {
|
|
49
|
+
command: 'vp check && vp test',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
server: { port: 6001 },
|
|
54
|
+
ssr: { noExternal: ['@nkzw/fate', 'vue-fate'] },
|
|
55
|
+
staged: {
|
|
56
|
+
'*': 'vp check --fix',
|
|
57
|
+
},
|
|
58
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
branches:
|
|
9
|
+
- main
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
strategy:
|
|
15
|
+
matrix:
|
|
16
|
+
node-version: [24]
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- uses: voidzero-dev/setup-vp@v1
|
|
20
|
+
with:
|
|
21
|
+
node-version: ${{ matrix.node-version }}
|
|
22
|
+
cache: true
|
|
23
|
+
run-install: true
|
|
24
|
+
- run: |
|
|
25
|
+
vp run dev:setup
|
|
26
|
+
vp run test:all
|
|
27
|
+
vp run build
|