@farm.js/create-app 0.1.0-beta.4 → 0.1.0-beta.41
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 +41 -4
- package/bin/create-farm-app.js +8 -2
- package/dist/index.js +3244 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3239 -18
- package/dist/index.mjs.map +1 -1
- package/dist/utils.js +9 -6
- package/dist/utils.js.map +1 -1
- package/dist/utils.mjs +9 -6
- package/dist/utils.mjs.map +1 -1
- package/package.json +2 -2
- package/templates/_integrations/better-auth/preact/farm.config.ts +17 -0
- package/templates/_integrations/better-auth/preact/src/app/dashboard/page.tsx +73 -0
- package/templates/_integrations/better-auth/preact/src/app/layout.tsx +14 -0
- package/templates/_integrations/better-auth/preact/src/app/page.tsx +36 -0
- package/templates/_integrations/better-auth/preact/src/app/sign-in/page.tsx +10 -0
- package/templates/_integrations/better-auth/preact/src/app/sign-up/page.tsx +10 -0
- package/templates/_integrations/better-auth/preact/src/components/auth-form.tsx +92 -0
- package/templates/_integrations/better-auth/preact/src/components/auth-shell.tsx +16 -0
- package/templates/_integrations/better-auth/preact/src/lib/auth-client.ts +5 -0
- package/templates/_integrations/better-auth/solid/farm.config.ts +17 -0
- package/templates/_integrations/better-auth/solid/src/app/dashboard/page.tsx +67 -0
- package/templates/_integrations/better-auth/solid/src/app/layout.tsx +14 -0
- package/templates/_integrations/better-auth/solid/src/app/page.tsx +36 -0
- package/templates/_integrations/better-auth/solid/src/app/sign-in/page.tsx +10 -0
- package/templates/_integrations/better-auth/solid/src/app/sign-up/page.tsx +10 -0
- package/templates/_integrations/better-auth/solid/src/components/auth-form.tsx +91 -0
- package/templates/_integrations/better-auth/solid/src/components/auth-shell.tsx +16 -0
- package/templates/_integrations/better-auth/solid/src/lib/auth-client.ts +5 -0
- package/templates/_integrations/better-auth/svelte/farm.config.ts +17 -0
- package/templates/_integrations/better-auth/svelte/src/app/dashboard/page.svelte +62 -0
- package/templates/_integrations/better-auth/svelte/src/app/layout.svelte +20 -0
- package/templates/_integrations/better-auth/svelte/src/app/page.svelte +32 -0
- package/templates/_integrations/better-auth/svelte/src/app/sign-in/page.svelte +10 -0
- package/templates/_integrations/better-auth/svelte/src/app/sign-up/page.svelte +10 -0
- package/templates/_integrations/better-auth/svelte/src/components/auth-form.svelte +83 -0
- package/templates/_integrations/better-auth/svelte/src/components/auth-shell.svelte +16 -0
- package/templates/_integrations/better-auth/svelte/src/components/resource-links.svelte +47 -0
- package/templates/_integrations/better-auth/svelte/src/lib/auth-client.ts +5 -0
- package/templates/_integrations/better-auth/vue/farm.config.ts +17 -0
- package/templates/_integrations/better-auth/vue/src/app/dashboard/page.vue +62 -0
- package/templates/_integrations/better-auth/vue/src/app/layout.vue +20 -0
- package/templates/_integrations/better-auth/vue/src/app/page.vue +34 -0
- package/templates/_integrations/better-auth/vue/src/app/sign-in/page.vue +12 -0
- package/templates/_integrations/better-auth/vue/src/app/sign-up/page.vue +12 -0
- package/templates/_integrations/better-auth/vue/src/components/auth-form.vue +86 -0
- package/templates/_integrations/better-auth/vue/src/components/auth-shell.vue +15 -0
- package/templates/_integrations/better-auth/vue/src/components/resource-links.vue +43 -0
- package/templates/_integrations/better-auth/vue/src/lib/auth-client.ts +5 -0
- package/templates/_renderers/preact/farm.config.ts +12 -0
- package/templates/_renderers/preact/package.json +27 -0
- package/templates/_renderers/preact/src/app/api/greeting/route.ts +15 -0
- package/templates/_renderers/preact/src/app/layout.tsx +16 -0
- package/templates/_renderers/preact/src/app/page.tsx +66 -0
- package/templates/_renderers/preact/src/app/preact.css +26 -0
- package/templates/_renderers/preact/src/components/resource-links.tsx +71 -0
- package/templates/_renderers/preact/src/lib/api-client.ts +4 -0
- package/templates/_renderers/preact/src/lib/api.generated.ts +7 -0
- package/templates/_renderers/preact/tsconfig.json +25 -0
- package/templates/_renderers/solid/farm.config.ts +12 -0
- package/templates/_renderers/solid/package.json +26 -0
- package/templates/_renderers/solid/src/app/api/greeting/route.ts +15 -0
- package/templates/_renderers/solid/src/app/layout.tsx +15 -0
- package/templates/_renderers/solid/src/app/page.tsx +56 -0
- package/templates/_renderers/solid/src/app/solid.css +22 -0
- package/templates/_renderers/solid/src/components/resource-links.tsx +71 -0
- package/templates/_renderers/solid/src/lib/api-client.ts +4 -0
- package/templates/_renderers/solid/src/lib/api.generated.ts +7 -0
- package/templates/_renderers/solid/tsconfig.json +25 -0
- package/templates/_renderers/svelte/farm.config.ts +9 -0
- package/templates/_renderers/svelte/package.json +28 -0
- package/templates/_renderers/svelte/src/app/api/greeting/route.ts +15 -0
- package/templates/_renderers/svelte/src/app/layout.svelte +21 -0
- package/templates/_renderers/svelte/src/app/page.svelte +64 -0
- package/templates/_renderers/svelte/src/app/svelte.css +26 -0
- package/templates/_renderers/svelte/src/components/resource-links.svelte +31 -0
- package/templates/_renderers/svelte/src/lib/api-client.ts +4 -0
- package/templates/_renderers/svelte/src/lib/api.generated.ts +7 -0
- package/templates/_renderers/svelte/tsconfig.json +23 -0
- package/templates/_renderers/vue/farm.config.ts +12 -0
- package/templates/_renderers/vue/package.json +27 -0
- package/templates/_renderers/vue/src/app/api/greeting/route.ts +15 -0
- package/templates/_renderers/vue/src/app/layout.vue +21 -0
- package/templates/_renderers/vue/src/app/page.vue +69 -0
- package/templates/_renderers/vue/src/app/vue.css +26 -0
- package/templates/_renderers/vue/src/components/resource-links.vue +33 -0
- package/templates/_renderers/vue/src/env.d.ts +7 -0
- package/templates/_renderers/vue/src/lib/api-client.ts +4 -0
- package/templates/_renderers/vue/src/lib/api.generated.ts +7 -0
- package/templates/_renderers/vue/tsconfig.json +23 -0
- package/templates/auth/.env.example +6 -0
- package/templates/auth/README.md +95 -0
- package/templates/auth/farm.config.ts +14 -0
- package/templates/auth/gitignore +10 -0
- package/templates/auth/package.json +32 -0
- package/templates/auth/pnpm-workspace.yaml +13 -0
- package/templates/auth/src/app/dashboard/middleware.ts +13 -0
- package/templates/auth/src/app/dashboard/page.tsx +140 -0
- package/templates/auth/src/app/error.tsx +25 -0
- package/templates/auth/src/app/globals.css +1064 -0
- package/templates/auth/src/app/layout.tsx +11 -0
- package/templates/auth/src/app/loading.tsx +15 -0
- package/templates/auth/src/app/not-found.tsx +26 -0
- package/templates/auth/src/app/page.tsx +46 -0
- package/templates/auth/src/app/sign-in/page.tsx +16 -0
- package/templates/auth/src/app/sign-up/page.tsx +16 -0
- package/templates/auth/src/components/auth-form.tsx +120 -0
- package/templates/auth/src/components/auth-shell.tsx +21 -0
- package/templates/auth/src/components/resource-links.tsx +78 -0
- package/templates/auth/src/components/sign-out-button.tsx +45 -0
- package/templates/auth/src/components/site-header.tsx +46 -0
- package/templates/auth/tsconfig.json +20 -0
- package/templates/basic/farm.config.ts +3 -0
- package/templates/basic/gitignore +23 -0
- package/templates/basic/package.json +4 -2
- package/templates/basic/pnpm-workspace.yaml +8 -0
- package/templates/basic/public/favicon.svg +13 -0
- package/templates/basic/src/app/globals.css +241 -0
- package/templates/basic/src/app/layout.tsx +6 -5
- package/templates/basic/src/app/page.tsx +20 -61
- package/templates/basic/src/components/resource-links.tsx +78 -0
- package/templates/basic/tsconfig.json +4 -0
- package/templates/better-auth/.env.example +3 -0
- package/templates/better-auth/README.md +89 -0
- package/templates/better-auth/farm.config.ts +32 -0
- package/templates/better-auth/gitignore +10 -0
- package/templates/better-auth/package.json +34 -0
- package/templates/better-auth/pnpm-workspace.yaml +13 -0
- package/templates/better-auth/src/app/dashboard/middleware.ts +15 -0
- package/templates/better-auth/src/app/dashboard/page.tsx +188 -0
- package/templates/better-auth/src/app/error.tsx +25 -0
- package/templates/better-auth/src/app/globals.css +1064 -0
- package/templates/better-auth/src/app/layout.tsx +11 -0
- package/templates/better-auth/src/app/loading.tsx +15 -0
- package/templates/better-auth/src/app/not-found.tsx +26 -0
- package/templates/better-auth/src/app/page.tsx +50 -0
- package/templates/better-auth/src/app/sign-in/page.tsx +16 -0
- package/templates/better-auth/src/app/sign-up/page.tsx +16 -0
- package/templates/better-auth/src/components/auth-form.tsx +120 -0
- package/templates/better-auth/src/components/auth-shell.tsx +21 -0
- package/templates/better-auth/src/components/resource-links.tsx +78 -0
- package/templates/better-auth/src/components/sign-out-button.tsx +45 -0
- package/templates/better-auth/src/components/site-header.tsx +46 -0
- package/templates/better-auth/src/lib/auth-client.ts +5 -0
- package/templates/better-auth/src/lib/auth.ts +50 -0
- package/templates/better-auth/src/lib/session.ts +8 -0
- package/templates/better-auth/tsconfig.json +20 -0
- package/templates/react-compiler/README.md +62 -0
- package/templates/react-compiler/farm.config.ts +23 -0
- package/templates/react-compiler/gitignore +23 -0
- package/templates/react-compiler/package.json +31 -0
- package/templates/react-compiler/pnpm-workspace.yaml +8 -0
- package/templates/react-compiler/public/favicon.svg +5 -0
- package/templates/react-compiler/scripts/verify-experiment.mjs +113 -0
- package/templates/react-compiler/src/app/globals.css +470 -0
- package/templates/react-compiler/src/app/layout.tsx +22 -0
- package/templates/react-compiler/src/app/page.tsx +47 -0
- package/templates/react-compiler/src/components/compiler-comparison.tsx +93 -0
- package/templates/react-compiler/src/components/resource-links.tsx +78 -0
- package/templates/react-compiler/src/farm.d.ts +73 -0
- package/templates/react-compiler/src/lib/api.generated.ts +10 -0
- package/templates/react-compiler/tsconfig.json +24 -0
- package/templates/basic/src/app/about/page.tsx +0 -32
- package/templates/basic/src/farm-images.d.ts +0 -59
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { LayoutProps, Metadata } from "@farm.js/core";
|
|
2
|
+
import "./globals.css";
|
|
3
|
+
|
|
4
|
+
export const metadata: Metadata = {
|
|
5
|
+
title: "FARMJS Auth Starter",
|
|
6
|
+
description: "A production-shaped starter powered by FARMJS built-in authentication.",
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function RootLayout({ children }: LayoutProps) {
|
|
10
|
+
return <>{children}</>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export default function Loading() {
|
|
2
|
+
return (
|
|
3
|
+
<main className="loading-shell" aria-label="Loading page" aria-live="polite">
|
|
4
|
+
<div className="loading-block">
|
|
5
|
+
<span className="loading-label">Loading account</span>
|
|
6
|
+
<div className="loading-line wide" />
|
|
7
|
+
<div className="loading-line" />
|
|
8
|
+
<div className="loading-grid">
|
|
9
|
+
<div />
|
|
10
|
+
<div />
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
</main>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
interface NotFoundProps {
|
|
2
|
+
pathname?: string;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export default function NotFound({ pathname }: NotFoundProps) {
|
|
6
|
+
return (
|
|
7
|
+
<main className="error-shell">
|
|
8
|
+
<section className="error-panel">
|
|
9
|
+
<span className="section-index">404 / NOT FOUND</span>
|
|
10
|
+
<h1>This route is outside the starter.</h1>
|
|
11
|
+
<p>
|
|
12
|
+
{pathname ? (
|
|
13
|
+
<>
|
|
14
|
+
Nothing is registered at <code>{pathname}</code>.
|
|
15
|
+
</>
|
|
16
|
+
) : (
|
|
17
|
+
"The page you requested does not exist."
|
|
18
|
+
)}
|
|
19
|
+
</p>
|
|
20
|
+
<a className="button button-primary" href="/">
|
|
21
|
+
Return home
|
|
22
|
+
</a>
|
|
23
|
+
</section>
|
|
24
|
+
</main>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { auth } from "@farm.js/auth/server";
|
|
2
|
+
import { ResourceLinks } from "../components/resource-links";
|
|
3
|
+
|
|
4
|
+
export default async function HomePage() {
|
|
5
|
+
const session = await auth.session();
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<main className="landing-main">
|
|
9
|
+
<section className="hero-section">
|
|
10
|
+
<div className="hero-copy">
|
|
11
|
+
<div className="eyebrow-row">
|
|
12
|
+
<span>00</span>
|
|
13
|
+
<span>FARMJS / Auth starter</span>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<h1>
|
|
17
|
+
{session ? (
|
|
18
|
+
<>
|
|
19
|
+
Open your <code>/dashboard</code>.
|
|
20
|
+
</>
|
|
21
|
+
) : (
|
|
22
|
+
<>
|
|
23
|
+
Start at <code>/sign-up</code>.
|
|
24
|
+
</>
|
|
25
|
+
)}
|
|
26
|
+
</h1>
|
|
27
|
+
|
|
28
|
+
<div className="command-list" aria-label="Development command">
|
|
29
|
+
<div className="command-row">
|
|
30
|
+
<span>01</span>
|
|
31
|
+
<code>pnpm dev</code>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<ResourceLinks
|
|
36
|
+
className="resource-links"
|
|
37
|
+
primary={{
|
|
38
|
+
href: session ? "/dashboard" : "/sign-up",
|
|
39
|
+
label: session ? "Dashboard" : "Get started",
|
|
40
|
+
}}
|
|
41
|
+
/>
|
|
42
|
+
</div>
|
|
43
|
+
</section>
|
|
44
|
+
</main>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Metadata } from "@farm.js/core";
|
|
2
|
+
import { AuthForm } from "../../components/auth-form";
|
|
3
|
+
import { AuthShell } from "../../components/auth-shell";
|
|
4
|
+
|
|
5
|
+
export const metadata: Metadata = {
|
|
6
|
+
title: "Sign in | FARMJS Auth Starter",
|
|
7
|
+
description: "Sign in with FARMJS Auth.",
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default function SignInPage() {
|
|
11
|
+
return (
|
|
12
|
+
<AuthShell>
|
|
13
|
+
<AuthForm mode="sign-in" />
|
|
14
|
+
</AuthShell>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Metadata } from "@farm.js/core";
|
|
2
|
+
import { AuthForm } from "../../components/auth-form";
|
|
3
|
+
import { AuthShell } from "../../components/auth-shell";
|
|
4
|
+
|
|
5
|
+
export const metadata: Metadata = {
|
|
6
|
+
title: "Create account | FARMJS Auth Starter",
|
|
7
|
+
description: "Create an account with FARMJS Auth.",
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default function SignUpPage() {
|
|
11
|
+
return (
|
|
12
|
+
<AuthShell>
|
|
13
|
+
<AuthForm mode="sign-up" />
|
|
14
|
+
</AuthShell>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { signIn, signUp } from "@farm.js/auth/client";
|
|
5
|
+
|
|
6
|
+
interface AuthFormProps {
|
|
7
|
+
mode: "sign-in" | "sign-up";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function AuthForm({ mode }: AuthFormProps) {
|
|
11
|
+
const isSignUp = mode === "sign-up";
|
|
12
|
+
const [pending, setPending] = useState(false);
|
|
13
|
+
const [error, setError] = useState<string | null>(null);
|
|
14
|
+
|
|
15
|
+
async function submit(event: React.FormEvent<HTMLFormElement>) {
|
|
16
|
+
event.preventDefault();
|
|
17
|
+
setError(null);
|
|
18
|
+
setPending(true);
|
|
19
|
+
|
|
20
|
+
const formData = new FormData(event.currentTarget);
|
|
21
|
+
const email = String(formData.get("email") ?? "").trim();
|
|
22
|
+
const password = String(formData.get("password") ?? "");
|
|
23
|
+
const name = String(formData.get("name") ?? "").trim();
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const response = isSignUp
|
|
27
|
+
? await signUp({
|
|
28
|
+
email,
|
|
29
|
+
name,
|
|
30
|
+
password,
|
|
31
|
+
})
|
|
32
|
+
: await signIn({
|
|
33
|
+
email,
|
|
34
|
+
password,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (response.error) {
|
|
38
|
+
setError(response.error.message ?? "We could not complete that request.");
|
|
39
|
+
setPending(false);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
window.location.assign("/dashboard");
|
|
44
|
+
} catch {
|
|
45
|
+
setError("The authentication service could not be reached. Please try again.");
|
|
46
|
+
setPending(false);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div className="auth-form-panel">
|
|
52
|
+
<div className="auth-form-heading">
|
|
53
|
+
<span className="section-index">{isSignUp ? "01 / SIGN UP" : "01 / SIGN IN"}</span>
|
|
54
|
+
<h1>{isSignUp ? "Create account." : "Welcome back."}</h1>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<form className="auth-form" onSubmit={submit}>
|
|
58
|
+
{isSignUp ? (
|
|
59
|
+
<label className="field">
|
|
60
|
+
<span>
|
|
61
|
+
<small>01</small> Name
|
|
62
|
+
</span>
|
|
63
|
+
<input
|
|
64
|
+
autoComplete="name"
|
|
65
|
+
minLength={2}
|
|
66
|
+
name="name"
|
|
67
|
+
placeholder="Ada Lovelace"
|
|
68
|
+
required
|
|
69
|
+
type="text"
|
|
70
|
+
/>
|
|
71
|
+
</label>
|
|
72
|
+
) : null}
|
|
73
|
+
|
|
74
|
+
<label className="field">
|
|
75
|
+
<span>
|
|
76
|
+
<small>{isSignUp ? "02" : "01"}</small> Email
|
|
77
|
+
</span>
|
|
78
|
+
<input
|
|
79
|
+
autoComplete="email"
|
|
80
|
+
name="email"
|
|
81
|
+
placeholder="you@example.com"
|
|
82
|
+
required
|
|
83
|
+
type="email"
|
|
84
|
+
/>
|
|
85
|
+
</label>
|
|
86
|
+
|
|
87
|
+
<label className="field">
|
|
88
|
+
<span>
|
|
89
|
+
<small>{isSignUp ? "03" : "02"}</small> Password
|
|
90
|
+
</span>
|
|
91
|
+
<input
|
|
92
|
+
autoComplete={isSignUp ? "new-password" : "current-password"}
|
|
93
|
+
minLength={8}
|
|
94
|
+
name="password"
|
|
95
|
+
placeholder="At least 8 characters"
|
|
96
|
+
required
|
|
97
|
+
type="password"
|
|
98
|
+
/>
|
|
99
|
+
</label>
|
|
100
|
+
|
|
101
|
+
{error ? (
|
|
102
|
+
<div className="form-error" role="alert">
|
|
103
|
+
<strong>Authentication failed</strong>
|
|
104
|
+
<span>{error}</span>
|
|
105
|
+
</div>
|
|
106
|
+
) : null}
|
|
107
|
+
|
|
108
|
+
<button className="button button-primary auth-submit" disabled={pending} type="submit">
|
|
109
|
+
<span>{pending ? "Please wait…" : isSignUp ? "Create account" : "Sign in"}</span>
|
|
110
|
+
<span aria-hidden="true">{pending ? "···" : "→"}</span>
|
|
111
|
+
</button>
|
|
112
|
+
</form>
|
|
113
|
+
|
|
114
|
+
<p className="auth-switch">
|
|
115
|
+
{isSignUp ? "Have an account?" : "Need an account?"}{" "}
|
|
116
|
+
<a href={isSignUp ? "/sign-in" : "/sign-up"}>{isSignUp ? "Sign in →" : "Sign up →"}</a>
|
|
117
|
+
</p>
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { ResourceLinks } from "./resource-links";
|
|
3
|
+
|
|
4
|
+
interface AuthShellProps {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function AuthShell({ children }: AuthShellProps) {
|
|
9
|
+
return (
|
|
10
|
+
<main className="auth-shell">
|
|
11
|
+
<a className="auth-home-link" href="/" aria-label="Back to starter home">
|
|
12
|
+
<span>00</span>
|
|
13
|
+
<span>FARMJS / Auth starter</span>
|
|
14
|
+
</a>
|
|
15
|
+
|
|
16
|
+
<section className="auth-form-side">{children}</section>
|
|
17
|
+
|
|
18
|
+
<ResourceLinks className="auth-resource-links" />
|
|
19
|
+
</main>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
interface ResourceLinkAction {
|
|
2
|
+
href: string;
|
|
3
|
+
label: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
interface ResourceLinksProps {
|
|
7
|
+
className: string;
|
|
8
|
+
primary?: ResourceLinkAction;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function DocsIcon() {
|
|
12
|
+
return (
|
|
13
|
+
<svg
|
|
14
|
+
className="resource-icon"
|
|
15
|
+
viewBox="0 0 24 24"
|
|
16
|
+
fill="none"
|
|
17
|
+
stroke="currentColor"
|
|
18
|
+
strokeWidth="1.8"
|
|
19
|
+
strokeLinecap="round"
|
|
20
|
+
strokeLinejoin="round"
|
|
21
|
+
aria-hidden="true"
|
|
22
|
+
focusable="false"
|
|
23
|
+
>
|
|
24
|
+
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" />
|
|
25
|
+
<path d="M14 2v6h6M8 13h8M8 17h6" />
|
|
26
|
+
</svg>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function GitHubIcon() {
|
|
31
|
+
return (
|
|
32
|
+
<svg
|
|
33
|
+
className="resource-icon"
|
|
34
|
+
viewBox="0 0 24 24"
|
|
35
|
+
fill="currentColor"
|
|
36
|
+
aria-hidden="true"
|
|
37
|
+
focusable="false"
|
|
38
|
+
>
|
|
39
|
+
<path d="M12 .7a11.5 11.5 0 0 0-3.64 22.41c.58.1.79-.25.79-.56v-2.23c-3.22.7-3.9-1.37-3.9-1.37-.52-1.34-1.28-1.69-1.28-1.69-1.05-.72.08-.7.08-.7 1.16.08 1.77 1.19 1.77 1.19 1.03 1.77 2.7 1.26 3.36.96.1-.75.4-1.26.73-1.55-2.57-.29-5.27-1.29-5.27-5.68 0-1.26.45-2.28 1.18-3.09-.12-.29-.51-1.47.11-3.05 0 0 .96-.31 3.16 1.18A10.95 10.95 0 0 1 12 6.1c.98 0 1.95.13 2.87.39 2.2-1.49 3.16-1.18 3.16-1.18.62 1.58.23 2.76.11 3.05.74.81 1.18 1.83 1.18 3.09 0 4.4-2.71 5.38-5.29 5.67.42.36.79 1.07.79 2.16v3.27c0 .31.21.67.8.56A11.5 11.5 0 0 0 12 .7Z" />
|
|
40
|
+
</svg>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function ResourceSeparator() {
|
|
45
|
+
return (
|
|
46
|
+
<span className="resource-separator" aria-hidden="true">
|
|
47
|
+
/
|
|
48
|
+
</span>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function ResourceLinks({ className, primary }: ResourceLinksProps) {
|
|
53
|
+
return (
|
|
54
|
+
<nav className={className} aria-label="Starter resources">
|
|
55
|
+
{primary ? (
|
|
56
|
+
<span className="resource-link-item">
|
|
57
|
+
<a className="resource-link-primary" href={primary.href}>
|
|
58
|
+
{primary.label}
|
|
59
|
+
</a>
|
|
60
|
+
</span>
|
|
61
|
+
) : null}
|
|
62
|
+
<span className="resource-link-item">
|
|
63
|
+
{primary ? <ResourceSeparator /> : null}
|
|
64
|
+
<a href="https://farm.js.dev">
|
|
65
|
+
<DocsIcon />
|
|
66
|
+
<span>Docs</span>
|
|
67
|
+
</a>
|
|
68
|
+
</span>
|
|
69
|
+
<span className="resource-link-item">
|
|
70
|
+
<ResourceSeparator />
|
|
71
|
+
<a href="https://github.com/farming-labs/farm.js">
|
|
72
|
+
<GitHubIcon />
|
|
73
|
+
<span>GitHub</span>
|
|
74
|
+
</a>
|
|
75
|
+
</span>
|
|
76
|
+
</nav>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { signOut as endSession } from "@farm.js/auth/client";
|
|
5
|
+
|
|
6
|
+
export function SignOutButton() {
|
|
7
|
+
const [pending, setPending] = useState(false);
|
|
8
|
+
const [error, setError] = useState<string | null>(null);
|
|
9
|
+
|
|
10
|
+
async function signOut() {
|
|
11
|
+
setPending(true);
|
|
12
|
+
setError(null);
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const response = await endSession();
|
|
16
|
+
if (response.error) {
|
|
17
|
+
setError(response.error.message ?? "Could not sign out.");
|
|
18
|
+
setPending(false);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
window.location.assign("/");
|
|
22
|
+
} catch {
|
|
23
|
+
setError("Could not reach the authentication service.");
|
|
24
|
+
setPending(false);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<div className="sign-out-control">
|
|
30
|
+
<button
|
|
31
|
+
className="button button-secondary"
|
|
32
|
+
disabled={pending}
|
|
33
|
+
onClick={signOut}
|
|
34
|
+
type="button"
|
|
35
|
+
>
|
|
36
|
+
{pending ? "Signing out…" : "Sign out"}
|
|
37
|
+
</button>
|
|
38
|
+
{error ? (
|
|
39
|
+
<span className="inline-error" role="alert">
|
|
40
|
+
{error}
|
|
41
|
+
</span>
|
|
42
|
+
) : null}
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
interface HeaderUser {
|
|
2
|
+
email: string;
|
|
3
|
+
name: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
interface SiteHeaderProps {
|
|
7
|
+
user: HeaderUser | null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function SiteHeader({ user }: SiteHeaderProps) {
|
|
11
|
+
return (
|
|
12
|
+
<header className="site-header">
|
|
13
|
+
<a className="brand" href="/" aria-label="FARMJS Auth Starter home">
|
|
14
|
+
<span className="brand-mark" aria-hidden="true">
|
|
15
|
+
F
|
|
16
|
+
</span>
|
|
17
|
+
<span>
|
|
18
|
+
<strong>FARMJS</strong>
|
|
19
|
+
<small>Auth Starter</small>
|
|
20
|
+
</span>
|
|
21
|
+
</a>
|
|
22
|
+
|
|
23
|
+
<nav className="header-nav" aria-label="Primary navigation">
|
|
24
|
+
<a href="https://farm.js.dev">Docs</a>
|
|
25
|
+
{user ? (
|
|
26
|
+
<a className="header-account" href="/dashboard">
|
|
27
|
+
<span className="avatar" aria-hidden="true">
|
|
28
|
+
{(user.name || user.email).slice(0, 1).toUpperCase()}
|
|
29
|
+
</span>
|
|
30
|
+
<span className="account-copy">
|
|
31
|
+
<small>Signed in</small>
|
|
32
|
+
<strong>{user.name || user.email}</strong>
|
|
33
|
+
</span>
|
|
34
|
+
</a>
|
|
35
|
+
) : (
|
|
36
|
+
<>
|
|
37
|
+
<a href="/sign-in">Sign in</a>
|
|
38
|
+
<a className="button button-small button-primary" href="/sign-up">
|
|
39
|
+
Get started
|
|
40
|
+
</a>
|
|
41
|
+
</>
|
|
42
|
+
)}
|
|
43
|
+
</nav>
|
|
44
|
+
</header>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"moduleResolution": "bundler",
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
"isolatedModules": true,
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"jsx": "react-jsx",
|
|
14
|
+
"strict": true,
|
|
15
|
+
"noUnusedLocals": true,
|
|
16
|
+
"noUnusedParameters": true,
|
|
17
|
+
"noFallthroughCasesInSwitch": true
|
|
18
|
+
},
|
|
19
|
+
"include": ["src", "farm.config.ts"]
|
|
20
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules/
|
|
3
|
+
|
|
4
|
+
# Farm and deployment output
|
|
5
|
+
.farm/
|
|
6
|
+
.output/
|
|
7
|
+
.vercel/
|
|
8
|
+
dist/
|
|
9
|
+
|
|
10
|
+
# Local environment files
|
|
11
|
+
.env
|
|
12
|
+
.env.local
|
|
13
|
+
.env.*.local
|
|
14
|
+
|
|
15
|
+
# Local databases
|
|
16
|
+
*.sqlite
|
|
17
|
+
*.sqlite-*
|
|
18
|
+
*.db
|
|
19
|
+
*.db-*
|
|
20
|
+
|
|
21
|
+
# Logs and TypeScript cache
|
|
22
|
+
*.log
|
|
23
|
+
*.tsbuildinfo
|
|
@@ -10,12 +10,14 @@
|
|
|
10
10
|
"type-check": "tsc --noEmit"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@farm.js/core": "0.1.0-beta.
|
|
13
|
+
"@farm.js/core": "0.1.0-beta.41",
|
|
14
|
+
"@fontsource-variable/geist": "5.3.0",
|
|
15
|
+
"@fontsource-variable/geist-mono": "5.3.0",
|
|
14
16
|
"react": "^19.0.0",
|
|
15
17
|
"react-dom": "^19.0.0"
|
|
16
18
|
},
|
|
17
19
|
"devDependencies": {
|
|
18
|
-
"@farm.js/cli": "0.1.0-beta.
|
|
20
|
+
"@farm.js/cli": "0.1.0-beta.41",
|
|
19
21
|
"@types/react": "^19.0.0",
|
|
20
22
|
"@types/react-dom": "^19.0.0",
|
|
21
23
|
"tailwindcss": "^4.0.0",
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512" fill="none" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">Farming Labs</title>
|
|
3
|
+
<desc id="desc">The three-tone Farming Labs mark on a dark square.</desc>
|
|
4
|
+
<rect width="512" height="512" fill="#0A0A0A"/>
|
|
5
|
+
<svg x="135.25" y="142" width="241.5" height="228" viewBox="125 68 161 152">
|
|
6
|
+
<path d="M157 68H133C128.582 68 125 71.5817 125 76V100C125 104.418 128.582 108 133 108H157C161.418 108 165 104.418 165 100V76C165 71.5817 161.418 68 157 68Z" fill="#F5F5F4"/>
|
|
7
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M182.383 68H280.617C282.045 68 283.414 68.8429 284.423 70.3431C285.433 71.8434 286 73.8783 286 76V100C286 102.122 285.433 104.157 284.423 105.657C283.414 107.157 282.045 108 280.617 108H182.383C180.955 108 179.586 107.157 178.577 105.657C177.567 104.157 177 102.122 177 100V76C177 73.8783 177.567 71.8434 178.577 70.3431C179.586 68.8429 180.955 68 182.383 68ZM271.852 81C270.747 81 269.852 81.8954 269.852 83V93C269.852 94.1046 270.747 95 271.852 95H277.272C278.376 95 279.272 94.1046 279.272 93V83C279.272 81.8954 278.376 81 277.272 81H271.852Z" fill="#F5F5F4"/>
|
|
8
|
+
<path d="M157 124H133C128.582 124 125 127.582 125 132V156C125 160.418 128.582 164 133 164H157C161.418 164 165 160.418 165 156V132C165 127.582 161.418 124 157 124Z" fill="#A3A3A3"/>
|
|
9
|
+
<path d="M280.334 124H182.666C179.537 124 177 127.582 177 132V156C177 160.418 179.537 164 182.666 164H280.334C283.463 164 286 160.418 286 156V132C286 127.582 283.463 124 280.334 124Z" fill="#A3A3A3"/>
|
|
10
|
+
<path d="M157 180H133C128.582 180 125 183.582 125 188V212C125 216.418 128.582 220 133 220H157C161.418 220 165 216.418 165 212V188C165 183.582 161.418 180 157 180Z" fill="#595959"/>
|
|
11
|
+
<path d="M230.189 180H182.811C179.602 180 177 183.582 177 188V212C177 216.418 179.602 220 182.811 220H230.189C233.398 220 236 216.418 236 212V188C236 183.582 233.398 180 230.189 180Z" fill="#595959"/>
|
|
12
|
+
</svg>
|
|
13
|
+
</svg>
|