Skip to content

Commit 947ed09

Browse files
Restore Ultracite + fix sidebar (#1233)
1 parent 8fbfc25 commit 947ed09

File tree

177 files changed

+6799
-8197
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

177 files changed

+6799
-8197
lines changed

.cursor/rules/ultracite.mdc

Lines changed: 333 additions & 0 deletions
Large diffs are not rendered by default.

.vscode/settings.json

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,35 @@
11
{
2-
"editor.formatOnSave": true,
2+
"editor.defaultFormatter": "esbenp.prettier-vscode",
33
"[javascript]": {
44
"editor.defaultFormatter": "biomejs.biome"
55
},
66
"[typescript]": {
77
"editor.defaultFormatter": "biomejs.biome"
88
},
9+
"[javascriptreact]": {
10+
"editor.defaultFormatter": "biomejs.biome"
11+
},
912
"[typescriptreact]": {
1013
"editor.defaultFormatter": "biomejs.biome"
1114
},
15+
"[json]": {
16+
"editor.defaultFormatter": "biomejs.biome"
17+
},
18+
"[jsonc]": {
19+
"editor.defaultFormatter": "biomejs.biome"
20+
},
21+
"[css]": {
22+
"editor.defaultFormatter": "biomejs.biome"
23+
},
24+
"[graphql]": {
25+
"editor.defaultFormatter": "biomejs.biome"
26+
},
1227
"typescript.tsdk": "node_modules/typescript/lib",
13-
"eslint.workingDirectories": [
14-
{ "pattern": "app/*" },
15-
{ "pattern": "packages/*" }
16-
]
28+
"editor.formatOnSave": true,
29+
"editor.formatOnPaste": true,
30+
"emmet.showExpandedAbbreviation": "never",
31+
"editor.codeActionsOnSave": {
32+
"source.fixAll.biome": "explicit",
33+
"source.organizeImports.biome": "explicit"
34+
}
1735
}

app/(auth)/actions.ts

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,84 @@
1-
'use server';
1+
"use server";
22

3-
import { z } from 'zod';
3+
import { z } from "zod";
44

5-
import { createUser, getUser } from '@/lib/db/queries';
5+
import { createUser, getUser } from "@/lib/db/queries";
66

7-
import { signIn } from './auth';
7+
import { signIn } from "./auth";
88

99
const authFormSchema = z.object({
1010
email: z.string().email(),
1111
password: z.string().min(6),
1212
});
1313

14-
export interface LoginActionState {
15-
status: 'idle' | 'in_progress' | 'success' | 'failed' | 'invalid_data';
16-
}
14+
export type LoginActionState = {
15+
status: "idle" | "in_progress" | "success" | "failed" | "invalid_data";
16+
};
1717

1818
export const login = async (
1919
_: LoginActionState,
20-
formData: FormData,
20+
formData: FormData
2121
): Promise<LoginActionState> => {
2222
try {
2323
const validatedData = authFormSchema.parse({
24-
email: formData.get('email'),
25-
password: formData.get('password'),
24+
email: formData.get("email"),
25+
password: formData.get("password"),
2626
});
2727

28-
await signIn('credentials', {
28+
await signIn("credentials", {
2929
email: validatedData.email,
3030
password: validatedData.password,
3131
redirect: false,
3232
});
3333

34-
return { status: 'success' };
34+
return { status: "success" };
3535
} catch (error) {
3636
if (error instanceof z.ZodError) {
37-
return { status: 'invalid_data' };
37+
return { status: "invalid_data" };
3838
}
3939

40-
return { status: 'failed' };
40+
return { status: "failed" };
4141
}
4242
};
4343

44-
export interface RegisterActionState {
44+
export type RegisterActionState = {
4545
status:
46-
| 'idle'
47-
| 'in_progress'
48-
| 'success'
49-
| 'failed'
50-
| 'user_exists'
51-
| 'invalid_data';
52-
}
46+
| "idle"
47+
| "in_progress"
48+
| "success"
49+
| "failed"
50+
| "user_exists"
51+
| "invalid_data";
52+
};
5353

5454
export const register = async (
5555
_: RegisterActionState,
56-
formData: FormData,
56+
formData: FormData
5757
): Promise<RegisterActionState> => {
5858
try {
5959
const validatedData = authFormSchema.parse({
60-
email: formData.get('email'),
61-
password: formData.get('password'),
60+
email: formData.get("email"),
61+
password: formData.get("password"),
6262
});
6363

6464
const [user] = await getUser(validatedData.email);
6565

6666
if (user) {
67-
return { status: 'user_exists' } as RegisterActionState;
67+
return { status: "user_exists" } as RegisterActionState;
6868
}
6969
await createUser(validatedData.email, validatedData.password);
70-
await signIn('credentials', {
70+
await signIn("credentials", {
7171
email: validatedData.email,
7272
password: validatedData.password,
7373
redirect: false,
7474
});
7575

76-
return { status: 'success' };
76+
return { status: "success" };
7777
} catch (error) {
7878
if (error instanceof z.ZodError) {
79-
return { status: 'invalid_data' };
79+
return { status: "invalid_data" };
8080
}
8181

82-
return { status: 'failed' };
82+
return { status: "failed" };
8383
}
8484
};
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
export { GET, POST } from '@/app/(auth)/auth';
1+
// biome-ignore lint/performance/noBarrelFile: "Required"
2+
export { GET, POST } from "@/app/(auth)/auth";

app/(auth)/api/auth/guest/route.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { signIn } from '@/app/(auth)/auth';
2-
import { isDevelopmentEnvironment } from '@/lib/constants';
3-
import { getToken } from 'next-auth/jwt';
4-
import { NextResponse } from 'next/server';
1+
import { NextResponse } from "next/server";
2+
import { getToken } from "next-auth/jwt";
3+
import { signIn } from "@/app/(auth)/auth";
4+
import { isDevelopmentEnvironment } from "@/lib/constants";
55

66
export async function GET(request: Request) {
77
const { searchParams } = new URL(request.url);
8-
const redirectUrl = searchParams.get('redirectUrl') || '/';
8+
const redirectUrl = searchParams.get("redirectUrl") || "/";
99

1010
const token = await getToken({
1111
req: request,
@@ -14,8 +14,8 @@ export async function GET(request: Request) {
1414
});
1515

1616
if (token) {
17-
return NextResponse.redirect(new URL('/', request.url));
17+
return NextResponse.redirect(new URL("/", request.url));
1818
}
1919

20-
return signIn('guest', { redirect: true, redirectTo: redirectUrl });
20+
return signIn("guest", { redirect: true, redirectTo: redirectUrl });
2121
}

app/(auth)/auth.config.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import type { NextAuthConfig } from 'next-auth';
1+
import type { NextAuthConfig } from "next-auth";
22

33
export const authConfig = {
44
pages: {
5-
signIn: '/login',
6-
newUser: '/',
5+
signIn: "/login",
6+
newUser: "/",
77
},
88
providers: [
99
// added later in auth.ts since it requires bcrypt which is only compatible with Node.js

app/(auth)/auth.ts

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
1-
import { compare } from 'bcrypt-ts';
2-
import NextAuth, { type DefaultSession } from 'next-auth';
3-
import Credentials from 'next-auth/providers/credentials';
4-
import { createGuestUser, getUser } from '@/lib/db/queries';
5-
import { authConfig } from './auth.config';
6-
import { DUMMY_PASSWORD } from '@/lib/constants';
7-
import type { DefaultJWT } from 'next-auth/jwt';
1+
import { compare } from "bcrypt-ts";
2+
import NextAuth, { type DefaultSession } from "next-auth";
3+
import type { DefaultJWT } from "next-auth/jwt";
4+
import Credentials from "next-auth/providers/credentials";
5+
import { DUMMY_PASSWORD } from "@/lib/constants";
6+
import { createGuestUser, getUser } from "@/lib/db/queries";
7+
import { authConfig } from "./auth.config";
88

9-
export type UserType = 'guest' | 'regular';
9+
export type UserType = "guest" | "regular";
1010

11-
declare module 'next-auth' {
11+
declare module "next-auth" {
1212
interface Session extends DefaultSession {
1313
user: {
1414
id: string;
1515
type: UserType;
16-
} & DefaultSession['user'];
16+
} & DefaultSession["user"];
1717
}
1818

19+
// biome-ignore lint/nursery/useConsistentTypeDefinitions: "Required"
1920
interface User {
2021
id?: string;
2122
email?: string | null;
2223
type: UserType;
2324
}
2425
}
2526

26-
declare module 'next-auth/jwt' {
27+
declare module "next-auth/jwt" {
2728
interface JWT extends DefaultJWT {
2829
id: string;
2930
type: UserType;
@@ -57,30 +58,32 @@ export const {
5758

5859
const passwordsMatch = await compare(password, user.password);
5960

60-
if (!passwordsMatch) return null;
61+
if (!passwordsMatch) {
62+
return null;
63+
}
6164

62-
return { ...user, type: 'regular' };
65+
return { ...user, type: "regular" };
6366
},
6467
}),
6568
Credentials({
66-
id: 'guest',
69+
id: "guest",
6770
credentials: {},
6871
async authorize() {
6972
const [guestUser] = await createGuestUser();
70-
return { ...guestUser, type: 'guest' };
73+
return { ...guestUser, type: "guest" };
7174
},
7275
}),
7376
],
7477
callbacks: {
75-
async jwt({ token, user }) {
78+
jwt({ token, user }) {
7679
if (user) {
7780
token.id = user.id as string;
7881
token.type = user.type;
7982
}
8083

8184
return token;
8285
},
83-
async session({ session, token }) {
86+
session({ session, token }) {
8487
if (session.user) {
8588
session.user.id = token.id;
8689
session.user.type = token.type;

app/(auth)/login/page.tsx

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,51 @@
1-
'use client';
1+
"use client";
22

3-
import Link from 'next/link';
4-
import { useRouter } from 'next/navigation';
5-
import { useActionState, useEffect, useState } from 'react';
6-
import { toast } from '@/components/toast';
3+
import Link from "next/link";
4+
import { useRouter } from "next/navigation";
5+
import { useSession } from "next-auth/react";
6+
import { useActionState, useEffect, useState } from "react";
77

8-
import { AuthForm } from '@/components/auth-form';
9-
import { SubmitButton } from '@/components/submit-button';
10-
11-
import { login, type LoginActionState } from '../actions';
12-
import { useSession } from 'next-auth/react';
8+
import { AuthForm } from "@/components/auth-form";
9+
import { SubmitButton } from "@/components/submit-button";
10+
import { toast } from "@/components/toast";
11+
import { type LoginActionState, login } from "../actions";
1312

1413
export default function Page() {
1514
const router = useRouter();
1615

17-
const [email, setEmail] = useState('');
16+
const [email, setEmail] = useState("");
1817
const [isSuccessful, setIsSuccessful] = useState(false);
1918

2019
const [state, formAction] = useActionState<LoginActionState, FormData>(
2120
login,
2221
{
23-
status: 'idle',
24-
},
22+
status: "idle",
23+
}
2524
);
2625

2726
const { update: updateSession } = useSession();
2827

2928
useEffect(() => {
30-
if (state.status === 'failed') {
29+
if (state.status === "failed") {
3130
toast({
32-
type: 'error',
33-
description: 'Invalid credentials!',
31+
type: "error",
32+
description: "Invalid credentials!",
3433
});
35-
} else if (state.status === 'invalid_data') {
34+
} else if (state.status === "invalid_data") {
3635
toast({
37-
type: 'error',
38-
description: 'Failed validating your submission!',
36+
type: "error",
37+
description: "Failed validating your submission!",
3938
});
40-
} else if (state.status === 'success') {
39+
} else if (state.status === "success") {
4140
setIsSuccessful(true);
4241
updateSession();
4342
router.refresh();
4443
}
4544
// eslint-disable-next-line react-hooks/exhaustive-deps
46-
}, [state.status]);
45+
}, [state.status, router.refresh, updateSession]);
4746

4847
const handleSubmit = (formData: FormData) => {
49-
setEmail(formData.get('email') as string);
48+
setEmail(formData.get("email") as string);
5049
formAction(formData);
5150
};
5251

@@ -64,12 +63,12 @@ export default function Page() {
6463
<p className="mt-4 text-center text-gray-600 text-sm dark:text-zinc-400">
6564
{"Don't have an account? "}
6665
<Link
67-
href="/register"
6866
className="font-semibold text-gray-800 hover:underline dark:text-zinc-200"
67+
href="/register"
6968
>
7069
Sign up
7170
</Link>
72-
{' for free.'}
71+
{" for free."}
7372
</p>
7473
</AuthForm>
7574
</div>

0 commit comments

Comments
 (0)