diff --git a/apps/server/drizzle.config.ts b/apps/server/drizzle.config.ts index e772308..c1775ea 100644 --- a/apps/server/drizzle.config.ts +++ b/apps/server/drizzle.config.ts @@ -1,10 +1,10 @@ import { defineConfig } from "drizzle-kit"; export default defineConfig({ - schema: "./src/db/schema", - out: "./src/db/migrations", - dialect: "postgresql", - dbCredentials: { - url: process.env.DATABASE_URL || "", - }, + schema: "./src/db/schema", + out: "./src/db/migrations", + dialect: "postgresql", + dbCredentials: { + url: process.env.DATABASE_URL || "", + }, }); diff --git a/apps/server/package.json b/apps/server/package.json index 22b4bd8..fe681b0 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -1,38 +1,38 @@ { - "name": "server", - "main": "src/index.ts", - "type": "module", - "scripts": { - "build": "tsdown", - "check-types": "tsc -b", - "compile": "bun build --compile --minify --sourcemap --bytecode ./src/index.ts --outfile server", - "dev": "bun run --hot src/index.ts", - "start": "bun run dist/index.js", - "db:push": "drizzle-kit push", - "db:studio": "drizzle-kit studio", - "db:generate": "drizzle-kit generate", - "db:migrate": "drizzle-kit migrate", - "db:start": "docker compose up -d", - "db:watch": "docker compose up", - "db:stop": "docker compose stop", - "db:down": "docker compose down" - }, - "dependencies": { - "dotenv": "^17.2.1", - "zod": "^4.0.2", - "@trpc/server": "^11.5.0", - "@trpc/client": "^11.5.0", - "@hono/trpc-server": "^0.4.0", - "hono": "^4.8.2", - "drizzle-orm": "^0.44.2", - "pg": "^8.14.1", - "better-auth": "^1.3.7" - }, - "devDependencies": { - "tsdown": "^0.14.1", - "typescript": "^5.8.2", - "@types/bun": "^1.2.6", - "drizzle-kit": "^0.31.2", - "@types/pg": "^8.11.11" - } + "name": "server", + "main": "src/index.ts", + "type": "module", + "scripts": { + "build": "tsdown", + "check-types": "tsc -b", + "compile": "bun build --compile --minify --sourcemap --bytecode ./src/index.ts --outfile server", + "dev": "bun run --hot src/index.ts", + "start": "bun run dist/index.js", + "db:push": "drizzle-kit push", + "db:studio": "drizzle-kit studio", + "db:generate": "drizzle-kit generate", + "db:migrate": "drizzle-kit migrate", + "db:start": "docker compose up -d", + "db:watch": "docker compose up", + "db:stop": "docker compose stop", + "db:down": "docker compose down" + }, + "dependencies": { + "dotenv": "^17.2.1", + "zod": "^4.0.2", + "@trpc/server": "^11.5.0", + "@trpc/client": "^11.5.0", + "@hono/trpc-server": "^0.4.0", + "hono": "^4.8.2", + "drizzle-orm": "^0.44.2", + "pg": "^8.14.1", + "better-auth": "^1.3.7" + }, + "devDependencies": { + "tsdown": "^0.14.1", + "typescript": "^5.8.2", + "@types/bun": "^1.2.6", + "drizzle-kit": "^0.31.2", + "@types/pg": "^8.11.11" + } } diff --git a/apps/server/src/db/schema/auth.ts b/apps/server/src/db/schema/auth.ts index 3af222d..ca8f6e0 100644 --- a/apps/server/src/db/schema/auth.ts +++ b/apps/server/src/db/schema/auth.ts @@ -1,51 +1,51 @@ import { pgTable, text, timestamp, boolean, serial } from "drizzle-orm/pg-core"; export const user = pgTable("user", { - id: text("id").primaryKey(), - name: text("name").notNull(), - email: text("email").notNull().unique(), - emailVerified: boolean("email_verified").notNull(), - image: text("image"), - createdAt: timestamp("created_at").notNull(), - updatedAt: timestamp("updated_at").notNull(), + id: text("id").primaryKey(), + name: text("name").notNull(), + email: text("email").notNull().unique(), + emailVerified: boolean("email_verified").notNull(), + image: text("image"), + createdAt: timestamp("created_at").notNull(), + updatedAt: timestamp("updated_at").notNull(), }); export const session = pgTable("session", { - id: text("id").primaryKey(), - expiresAt: timestamp("expires_at").notNull(), - token: text("token").notNull().unique(), - createdAt: timestamp("created_at").notNull(), - updatedAt: timestamp("updated_at").notNull(), - ipAddress: text("ip_address"), - userAgent: text("user_agent"), - userId: text("user_id") - .notNull() - .references(() => user.id, { onDelete: "cascade" }), + id: text("id").primaryKey(), + expiresAt: timestamp("expires_at").notNull(), + token: text("token").notNull().unique(), + createdAt: timestamp("created_at").notNull(), + updatedAt: timestamp("updated_at").notNull(), + ipAddress: text("ip_address"), + userAgent: text("user_agent"), + userId: text("user_id") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), }); export const account = pgTable("account", { - id: text("id").primaryKey(), - accountId: text("account_id").notNull(), - providerId: text("provider_id").notNull(), - userId: text("user_id") - .notNull() - .references(() => user.id, { onDelete: "cascade" }), - accessToken: text("access_token"), - refreshToken: text("refresh_token"), - idToken: text("id_token"), - accessTokenExpiresAt: timestamp("access_token_expires_at"), - refreshTokenExpiresAt: timestamp("refresh_token_expires_at"), - scope: text("scope"), - password: text("password"), - createdAt: timestamp("created_at").notNull(), - updatedAt: timestamp("updated_at").notNull(), + id: text("id").primaryKey(), + accountId: text("account_id").notNull(), + providerId: text("provider_id").notNull(), + userId: text("user_id") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), + accessToken: text("access_token"), + refreshToken: text("refresh_token"), + idToken: text("id_token"), + accessTokenExpiresAt: timestamp("access_token_expires_at"), + refreshTokenExpiresAt: timestamp("refresh_token_expires_at"), + scope: text("scope"), + password: text("password"), + createdAt: timestamp("created_at").notNull(), + updatedAt: timestamp("updated_at").notNull(), }); export const verification = pgTable("verification", { - id: text("id").primaryKey(), - identifier: text("identifier").notNull(), - value: text("value").notNull(), - expiresAt: timestamp("expires_at").notNull(), - createdAt: timestamp("created_at"), - updatedAt: timestamp("updated_at"), + id: text("id").primaryKey(), + identifier: text("identifier").notNull(), + value: text("value").notNull(), + expiresAt: timestamp("expires_at").notNull(), + createdAt: timestamp("created_at"), + updatedAt: timestamp("updated_at"), }); diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts index faedbab..7fbf355 100644 --- a/apps/server/src/index.ts +++ b/apps/server/src/index.ts @@ -14,43 +14,42 @@ import { logger } from "./lib/logger"; const app = new Hono(); if (process.env.NODE_ENV === "development") { - try { - const composePath = join(process.cwd(), "docker-compose.yml"); - execSync(`docker-compose -f ${composePath} up -d`, { stdio: "inherit" }); - logger.info("Waiting for services to start..."); - execSync("sleep 2"); - logger.info("Docker Compose started successfully"); -} catch (error) { - logger.error("Failed to start Docker Compose:", error); -} - + try { + const composePath = join(process.cwd(), "docker-compose.yml"); + execSync(`docker-compose -f ${composePath} up -d`, { stdio: "inherit" }); + logger.info("Waiting for services to start..."); + execSync("sleep 2"); + logger.info("Docker Compose started successfully"); + } catch (error) { + logger.error("Failed to start Docker Compose:", error); + } } app.use(honoLogger()); app.use( - "/*", - cors({ - origin: process.env.CORS_ORIGIN || "", - allowMethods: ["GET", "POST", "OPTIONS"], - allowHeaders: ["Content-Type", "Authorization"], - credentials: true, - }), + "/*", + cors({ + origin: process.env.CORS_ORIGIN || "", + allowMethods: ["GET", "POST", "OPTIONS"], + allowHeaders: ["Content-Type", "Authorization"], + credentials: true, + }) ); app.on(["POST", "GET"], "/api/auth/**", (c) => auth.handler(c.req.raw)); app.use( - "/trpc/*", - trpcServer({ - router: appRouter, - createContext: (_opts, context) => { - return createContext({ context }); - }, - }), + "/trpc/*", + trpcServer({ + router: appRouter, + createContext: (_opts, context) => { + return createContext({ context }); + }, + }) ); app.get("/", (c) => { - return c.text("OK"); + return c.text("OK"); }); export default app; diff --git a/apps/server/src/lib/auth.ts b/apps/server/src/lib/auth.ts index 2267411..ca30fd7 100644 --- a/apps/server/src/lib/auth.ts +++ b/apps/server/src/lib/auth.ts @@ -4,20 +4,20 @@ import { db } from "../db"; import * as schema from "../db/schema/auth"; export const auth = betterAuth({ - database: drizzleAdapter(db, { - provider: "pg", + database: drizzleAdapter(db, { + provider: "pg", - schema: schema, - }), - trustedOrigins: [process.env.CORS_ORIGIN || ""], - emailAndPassword: { - enabled: true, - }, - advanced: { - defaultCookieAttributes: { - sameSite: "none", - secure: true, - httpOnly: true, - }, - }, + schema: schema, + }), + trustedOrigins: [process.env.CORS_ORIGIN || ""], + emailAndPassword: { + enabled: true, + }, + advanced: { + defaultCookieAttributes: { + sameSite: "none", + secure: true, + httpOnly: true, + }, + }, }); diff --git a/apps/server/src/lib/context.ts b/apps/server/src/lib/context.ts index 3a62348..e1ec247 100644 --- a/apps/server/src/lib/context.ts +++ b/apps/server/src/lib/context.ts @@ -2,16 +2,16 @@ import type { Context as HonoContext } from "hono"; import { auth } from "./auth"; export type CreateContextOptions = { - context: HonoContext; + context: HonoContext; }; export async function createContext({ context }: CreateContextOptions) { - const session = await auth.api.getSession({ - headers: context.req.raw.headers, - }); - return { - session, - }; + const session = await auth.api.getSession({ + headers: context.req.raw.headers, + }); + return { + session, + }; } export type Context = Awaited>; diff --git a/apps/server/src/lib/trpc.ts b/apps/server/src/lib/trpc.ts index d70698b..3affce2 100644 --- a/apps/server/src/lib/trpc.ts +++ b/apps/server/src/lib/trpc.ts @@ -8,17 +8,17 @@ export const router = t.router; export const publicProcedure = t.procedure; export const protectedProcedure = t.procedure.use(({ ctx, next }) => { - if (!ctx.session) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "Authentication required", - cause: "No session", - }); - } - return next({ - ctx: { - ...ctx, - session: ctx.session, - }, - }); + if (!ctx.session) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "Authentication required", + cause: "No session", + }); + } + return next({ + ctx: { + ...ctx, + session: ctx.session, + }, + }); }); diff --git a/apps/server/src/routers/index.ts b/apps/server/src/routers/index.ts index 3164fe2..170eb64 100644 --- a/apps/server/src/routers/index.ts +++ b/apps/server/src/routers/index.ts @@ -1,14 +1,14 @@ import { protectedProcedure, publicProcedure, router } from "../lib/trpc"; export const appRouter = router({ - healthCheck: publicProcedure.query(() => { - return "OK"; - }), - privateData: protectedProcedure.query(({ ctx }) => { - return { - message: "This is private", - user: ctx.session.user, - }; - }), + healthCheck: publicProcedure.query(() => { + return "OK"; + }), + privateData: protectedProcedure.query(({ ctx }) => { + return { + message: "This is private", + user: ctx.session.user, + }; + }), }); export type AppRouter = typeof appRouter; diff --git a/apps/server/tsconfig.json b/apps/server/tsconfig.json index 5005607..f477262 100644 --- a/apps/server/tsconfig.json +++ b/apps/server/tsconfig.json @@ -1,19 +1,19 @@ { - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "bundler", - "verbatimModuleSyntax": true, - "strict": true, - "skipLibCheck": true, - "baseUrl": "./", - "paths": { - "@/*": ["./src/*"] - }, - "outDir": "./dist", - "types": ["bun"], - "composite": true, - "jsx": "react-jsx", - "jsxImportSource": "hono/jsx" - } + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "bundler", + "verbatimModuleSyntax": true, + "strict": true, + "skipLibCheck": true, + "baseUrl": "./", + "paths": { + "@/*": ["./src/*"] + }, + "outDir": "./dist", + "types": ["bun"], + "composite": true, + "jsx": "react-jsx", + "jsxImportSource": "hono/jsx" + } } diff --git a/apps/web/components.json b/apps/web/components.json index 802bb88..13e1db0 100644 --- a/apps/web/components.json +++ b/apps/web/components.json @@ -1,21 +1,21 @@ { - "$schema": "https://ui.shadcn.com/schema.json", - "style": "new-york", - "rsc": false, - "tsx": true, - "tailwind": { - "config": "", - "css": "src/index.css", - "baseColor": "neutral", - "cssVariables": true, - "prefix": "" - }, - "aliases": { - "components": "@/components", - "utils": "@/lib/utils", - "ui": "@/components/ui", - "lib": "@/lib", - "hooks": "@/hooks" - }, - "iconLibrary": "lucide" + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/index.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" } diff --git a/apps/web/package.json b/apps/web/package.json index 09489fe..cdddfb3 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,55 +1,55 @@ { - "name": "web", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "dev": "vite --port=3001", - "build": "vite build", - "serve": "vite preview", - "start": "vite", - "check-types": "tsc --noEmit", - "generate-pwa-assets": "pwa-assets-generator", - "tauri": "tauri", - "desktop:dev": "tauri dev", - "desktop:build": "tauri build" - }, - "dependencies": { - "@hookform/resolvers": "^5.1.1", - "radix-ui": "^1.4.2", - "@tanstack/react-form": "^1.12.3", - "@tailwindcss/vite": "^4.0.15", - "@tanstack/react-router": "^1.114.25", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "lucide-react": "^0.473.0", - "next-themes": "^0.4.6", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "sonner": "^2.0.5", - "tailwind-merge": "^3.3.1", - "tw-animate-css": "^1.2.5", - "zod": "^4.0.2", - "@trpc/tanstack-react-query": "^11.5.0", - "@trpc/client": "^11.5.0", - "@trpc/server": "^11.5.0", - "@tanstack/react-query": "^5.85.5", - "vite-plugin-pwa": "^1.0.1", - "better-auth": "^1.3.7" - }, - "devDependencies": { - "@tanstack/react-router-devtools": "^1.114.27", - "@tanstack/router-plugin": "^1.114.27", - "@types/node": "^22.13.13", - "@types/react": "^19.0.12", - "@types/react-dom": "^19.0.4", - "@vitejs/plugin-react": "^4.3.4", - "postcss": "^8.5.3", - "typescript": "^5.8.3", - "tailwindcss": "^4.0.15", - "vite": "^6.2.2", - "@tanstack/react-query-devtools": "^5.85.5", - "@vite-pwa/assets-generator": "^1.0.0", - "@tauri-apps/cli": "^2.4.0" - } + "name": "web", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3001", + "build": "vite build", + "serve": "vite preview", + "start": "vite", + "check-types": "tsc --noEmit", + "generate-pwa-assets": "pwa-assets-generator", + "tauri": "tauri", + "desktop:dev": "tauri dev", + "desktop:build": "tauri build" + }, + "dependencies": { + "@hookform/resolvers": "^5.1.1", + "radix-ui": "^1.4.2", + "@tanstack/react-form": "^1.12.3", + "@tailwindcss/vite": "^4.0.15", + "@tanstack/react-router": "^1.114.25", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-react": "^0.473.0", + "next-themes": "^0.4.6", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "sonner": "^2.0.5", + "tailwind-merge": "^3.3.1", + "tw-animate-css": "^1.2.5", + "zod": "^4.0.2", + "@trpc/tanstack-react-query": "^11.5.0", + "@trpc/client": "^11.5.0", + "@trpc/server": "^11.5.0", + "@tanstack/react-query": "^5.85.5", + "vite-plugin-pwa": "^1.0.1", + "better-auth": "^1.3.7" + }, + "devDependencies": { + "@tanstack/react-router-devtools": "^1.114.27", + "@tanstack/router-plugin": "^1.114.27", + "@types/node": "^22.13.13", + "@types/react": "^19.0.12", + "@types/react-dom": "^19.0.4", + "@vitejs/plugin-react": "^4.3.4", + "postcss": "^8.5.3", + "typescript": "^5.8.3", + "tailwindcss": "^4.0.15", + "vite": "^6.2.2", + "@tanstack/react-query-devtools": "^5.85.5", + "@vite-pwa/assets-generator": "^1.0.0", + "@tauri-apps/cli": "^2.4.0" + } } diff --git a/apps/web/pwa-assets.config.ts b/apps/web/pwa-assets.config.ts index 8b1eee8..60f5657 100644 --- a/apps/web/pwa-assets.config.ts +++ b/apps/web/pwa-assets.config.ts @@ -1,12 +1,12 @@ import { - defineConfig, - minimal2023Preset as preset, + defineConfig, + minimal2023Preset as preset, } from "@vite-pwa/assets-generator/config"; export default defineConfig({ - headLinkOptions: { - preset: "2023", - }, - preset, - images: ["public/logo.png"], + headLinkOptions: { + preset: "2023", + }, + preset, + images: ["public/logo.png"], }); diff --git a/apps/web/src/components/header.tsx b/apps/web/src/components/header.tsx index 7086268..5221de1 100644 --- a/apps/web/src/components/header.tsx +++ b/apps/web/src/components/header.tsx @@ -3,29 +3,29 @@ import { ModeToggle } from "./mode-toggle"; import UserMenu from "./user-menu"; export default function Header() { - const links = [ - { to: "/", label: "Home" }, - { to: "/dashboard", label: "Dashboard" }, - ] as const; + const links = [ + { to: "/", label: "Home" }, + { to: "/dashboard", label: "Dashboard" }, + ] as const; - return ( -
-
- -
- - -
-
-
-
- ); + return ( +
+
+ +
+ + +
+
+
+
+ ); } diff --git a/apps/web/src/components/loader.tsx b/apps/web/src/components/loader.tsx index 7501df6..e17ec79 100644 --- a/apps/web/src/components/loader.tsx +++ b/apps/web/src/components/loader.tsx @@ -1,9 +1,9 @@ import { Loader2 } from "lucide-react"; export default function Loader() { - return ( -
- -
- ); + return ( +
+ +
+ ); } diff --git a/apps/web/src/components/mode-toggle.tsx b/apps/web/src/components/mode-toggle.tsx index a11a92e..199d09f 100644 --- a/apps/web/src/components/mode-toggle.tsx +++ b/apps/web/src/components/mode-toggle.tsx @@ -2,36 +2,36 @@ import { Moon, Sun } from "lucide-react"; import { Button } from "@/components/ui/button"; import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { useTheme } from "@/components/theme-provider"; export function ModeToggle() { - const { setTheme } = useTheme(); + const { setTheme } = useTheme(); - return ( - - - - - - setTheme("light")}> - Light - - setTheme("dark")}> - Dark - - setTheme("system")}> - System - - - - ); + return ( + + + + + + setTheme("light")}> + Light + + setTheme("dark")}> + Dark + + setTheme("system")}> + System + + + + ); } diff --git a/apps/web/src/components/sign-in-form.tsx b/apps/web/src/components/sign-in-form.tsx index b9b3c05..4c5b044 100644 --- a/apps/web/src/components/sign-in-form.tsx +++ b/apps/web/src/components/sign-in-form.tsx @@ -9,131 +9,131 @@ import { Input } from "./ui/input"; import { Label } from "./ui/label"; export default function SignInForm({ - onSwitchToSignUp, + onSwitchToSignUp, }: { - onSwitchToSignUp: () => void; + onSwitchToSignUp: () => void; }) { - const navigate = useNavigate({ - from: "/", - }); - const { isPending } = authClient.useSession(); + const navigate = useNavigate({ + from: "/", + }); + const { isPending } = authClient.useSession(); - const form = useForm({ - defaultValues: { - email: "", - password: "", - }, - onSubmit: async ({ value }) => { - await authClient.signIn.email( - { - email: value.email, - password: value.password, - }, - { - onSuccess: () => { - navigate({ - to: "/dashboard", - }); - toast.success("Sign in successful"); - }, - onError: (error) => { - toast.error(error.error.message || error.error.statusText); - }, - }, - ); - }, - validators: { - onSubmit: z.object({ - email: z.email("Invalid email address"), - password: z.string().min(8, "Password must be at least 8 characters"), - }), - }, - }); + const form = useForm({ + defaultValues: { + email: "", + password: "", + }, + onSubmit: async ({ value }) => { + await authClient.signIn.email( + { + email: value.email, + password: value.password, + }, + { + onSuccess: () => { + navigate({ + to: "/dashboard", + }); + toast.success("Sign in successful"); + }, + onError: (error) => { + toast.error(error.error.message || error.error.statusText); + }, + } + ); + }, + validators: { + onSubmit: z.object({ + email: z.email("Invalid email address"), + password: z.string().min(8, "Password must be at least 8 characters"), + }), + }, + }); - if (isPending) { - return ; - } + if (isPending) { + return ; + } - return ( -
-

Welcome Back

+ return ( +
+

Welcome Back

-
{ - e.preventDefault(); - e.stopPropagation(); - form.handleSubmit(); - }} - className="space-y-4" - > -
- - {(field) => ( -
- - field.handleChange(e.target.value)} - /> - {field.state.meta.errors.map((error) => ( -

- {error?.message} -

- ))} -
- )} -
-
+ { + e.preventDefault(); + e.stopPropagation(); + form.handleSubmit(); + }} + className="space-y-4" + > +
+ + {(field) => ( +
+ + field.handleChange(e.target.value)} + /> + {field.state.meta.errors.map((error) => ( +

+ {error?.message} +

+ ))} +
+ )} +
+
-
- - {(field) => ( -
- - field.handleChange(e.target.value)} - /> - {field.state.meta.errors.map((error) => ( -

- {error?.message} -

- ))} -
- )} -
-
+
+ + {(field) => ( +
+ + field.handleChange(e.target.value)} + /> + {field.state.meta.errors.map((error) => ( +

+ {error?.message} +

+ ))} +
+ )} +
+
- - {(state) => ( - - )} - -
+ + {(state) => ( + + )} + + -
- -
-
- ); +
+ +
+
+ ); } diff --git a/apps/web/src/components/sign-up-form.tsx b/apps/web/src/components/sign-up-form.tsx index 0ee113d..56ea996 100644 --- a/apps/web/src/components/sign-up-form.tsx +++ b/apps/web/src/components/sign-up-form.tsx @@ -9,156 +9,156 @@ import { Input } from "./ui/input"; import { Label } from "./ui/label"; export default function SignUpForm({ - onSwitchToSignIn, + onSwitchToSignIn, }: { - onSwitchToSignIn: () => void; + onSwitchToSignIn: () => void; }) { - const navigate = useNavigate({ - from: "/", - }); - const { isPending } = authClient.useSession(); + const navigate = useNavigate({ + from: "/", + }); + const { isPending } = authClient.useSession(); - const form = useForm({ - defaultValues: { - email: "", - password: "", - name: "", - }, - onSubmit: async ({ value }) => { - await authClient.signUp.email( - { - email: value.email, - password: value.password, - name: value.name, - }, - { - onSuccess: () => { - navigate({ - to: "/dashboard", - }); - toast.success("Sign up successful"); - }, - onError: (error) => { - toast.error(error.error.message || error.error.statusText); - }, - }, - ); - }, - validators: { - onSubmit: z.object({ - name: z.string().min(2, "Name must be at least 2 characters"), - email: z.email("Invalid email address"), - password: z.string().min(8, "Password must be at least 8 characters"), - }), - }, - }); + const form = useForm({ + defaultValues: { + email: "", + password: "", + name: "", + }, + onSubmit: async ({ value }) => { + await authClient.signUp.email( + { + email: value.email, + password: value.password, + name: value.name, + }, + { + onSuccess: () => { + navigate({ + to: "/dashboard", + }); + toast.success("Sign up successful"); + }, + onError: (error) => { + toast.error(error.error.message || error.error.statusText); + }, + } + ); + }, + validators: { + onSubmit: z.object({ + name: z.string().min(2, "Name must be at least 2 characters"), + email: z.email("Invalid email address"), + password: z.string().min(8, "Password must be at least 8 characters"), + }), + }, + }); - if (isPending) { - return ; - } + if (isPending) { + return ; + } - return ( -
-

Create Account

+ return ( +
+

Create Account

-
{ - e.preventDefault(); - e.stopPropagation(); - form.handleSubmit(); - }} - className="space-y-4" - > -
- - {(field) => ( -
- - field.handleChange(e.target.value)} - /> - {field.state.meta.errors.map((error) => ( -

- {error?.message} -

- ))} -
- )} -
-
+ { + e.preventDefault(); + e.stopPropagation(); + form.handleSubmit(); + }} + className="space-y-4" + > +
+ + {(field) => ( +
+ + field.handleChange(e.target.value)} + /> + {field.state.meta.errors.map((error) => ( +

+ {error?.message} +

+ ))} +
+ )} +
+
-
- - {(field) => ( -
- - field.handleChange(e.target.value)} - /> - {field.state.meta.errors.map((error) => ( -

- {error?.message} -

- ))} -
- )} -
-
+
+ + {(field) => ( +
+ + field.handleChange(e.target.value)} + /> + {field.state.meta.errors.map((error) => ( +

+ {error?.message} +

+ ))} +
+ )} +
+
-
- - {(field) => ( -
- - field.handleChange(e.target.value)} - /> - {field.state.meta.errors.map((error) => ( -

- {error?.message} -

- ))} -
- )} -
-
+
+ + {(field) => ( +
+ + field.handleChange(e.target.value)} + /> + {field.state.meta.errors.map((error) => ( +

+ {error?.message} +

+ ))} +
+ )} +
+
- - {(state) => ( - - )} - -
+ + {(state) => ( + + )} + + -
- -
-
- ); +
+ +
+
+ ); } diff --git a/apps/web/src/components/theme-provider.tsx b/apps/web/src/components/theme-provider.tsx index 8368643..d962534 100644 --- a/apps/web/src/components/theme-provider.tsx +++ b/apps/web/src/components/theme-provider.tsx @@ -2,10 +2,10 @@ import * as React from "react"; import { ThemeProvider as NextThemesProvider } from "next-themes"; export function ThemeProvider({ - children, - ...props + children, + ...props }: React.ComponentProps) { - return {children}; + return {children}; } export { useTheme } from "next-themes"; diff --git a/apps/web/src/components/ui/button.tsx b/apps/web/src/components/ui/button.tsx index 05c9576..68d62d8 100644 --- a/apps/web/src/components/ui/button.tsx +++ b/apps/web/src/components/ui/button.tsx @@ -5,55 +5,55 @@ import { cva, type VariantProps } from "class-variance-authority"; import { cn } from "@/lib/utils"; const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", - { - variants: { - variant: { - default: - "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", - destructive: - "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", - outline: - "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50", - secondary: - "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80", - ghost: - "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", - link: "text-primary underline-offset-4 hover:underline", - }, - size: { - default: "h-9 px-4 py-2 has-[>svg]:px-3", - sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", - lg: "h-10 rounded-md px-6 has-[>svg]:px-4", - icon: "size-9", - }, - }, - defaultVariants: { - variant: "default", - size: "default", - }, - }, + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", + destructive: + "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50", + secondary: + "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80", + ghost: + "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2 has-[>svg]:px-3", + sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", + lg: "h-10 rounded-md px-6 has-[>svg]:px-4", + icon: "size-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } ); function Button({ - className, - variant, - size, - asChild = false, - ...props + className, + variant, + size, + asChild = false, + ...props }: React.ComponentProps<"button"> & - VariantProps & { - asChild?: boolean; - }) { - const Comp = asChild ? SlotPrimitive.Slot : "button"; + VariantProps & { + asChild?: boolean; + }) { + const Comp = asChild ? SlotPrimitive.Slot : "button"; - return ( - - ); + return ( + + ); } export { Button, buttonVariants }; diff --git a/apps/web/src/components/ui/card.tsx b/apps/web/src/components/ui/card.tsx index c9f7bff..93a82d9 100644 --- a/apps/web/src/components/ui/card.tsx +++ b/apps/web/src/components/ui/card.tsx @@ -3,90 +3,90 @@ import * as React from "react"; import { cn } from "@/lib/utils"; function Card({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ); + return ( +
+ ); } function CardHeader({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ); + return ( +
+ ); } function CardTitle({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ); + return ( +
+ ); } function CardDescription({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ); + return ( +
+ ); } function CardAction({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ); + return ( +
+ ); } function CardContent({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ); + return ( +
+ ); } function CardFooter({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ); + return ( +
+ ); } export { - Card, - CardHeader, - CardFooter, - CardTitle, - CardAction, - CardDescription, - CardContent, + Card, + CardHeader, + CardFooter, + CardTitle, + CardAction, + CardDescription, + CardContent, }; diff --git a/apps/web/src/components/ui/checkbox.tsx b/apps/web/src/components/ui/checkbox.tsx index 7cc0eac..9d874d3 100644 --- a/apps/web/src/components/ui/checkbox.tsx +++ b/apps/web/src/components/ui/checkbox.tsx @@ -5,26 +5,26 @@ import { CheckIcon } from "lucide-react"; import { cn } from "@/lib/utils"; function Checkbox({ - className, - ...props + className, + ...props }: React.ComponentProps) { - return ( - - - - - - ); + return ( + + + + + + ); } export { Checkbox }; diff --git a/apps/web/src/components/ui/dropdown-menu.tsx b/apps/web/src/components/ui/dropdown-menu.tsx index e8dc6d0..80e3b40 100644 --- a/apps/web/src/components/ui/dropdown-menu.tsx +++ b/apps/web/src/components/ui/dropdown-menu.tsx @@ -7,251 +7,251 @@ import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"; import { cn } from "@/lib/utils"; function DropdownMenu({ - ...props + ...props }: React.ComponentProps) { - return ; + return ; } function DropdownMenuPortal({ - ...props + ...props }: React.ComponentProps) { - return ( - - ); + return ( + + ); } function DropdownMenuTrigger({ - ...props + ...props }: React.ComponentProps) { - return ( - - ); + return ( + + ); } function DropdownMenuContent({ - className, - sideOffset = 4, - ...props + className, + sideOffset = 4, + ...props }: React.ComponentProps) { - return ( - - - - ); + return ( + + + + ); } function DropdownMenuGroup({ - ...props + ...props }: React.ComponentProps) { - return ( - - ); + return ( + + ); } function DropdownMenuItem({ - className, - inset, - variant = "default", - ...props + className, + inset, + variant = "default", + ...props }: React.ComponentProps & { - inset?: boolean; - variant?: "default" | "destructive"; + inset?: boolean; + variant?: "default" | "destructive"; }) { - return ( - - ); + return ( + + ); } function DropdownMenuCheckboxItem({ - className, - children, - checked, - ...props + className, + children, + checked, + ...props }: React.ComponentProps) { - return ( - - - - - - - {children} - - ); + return ( + + + + + + + {children} + + ); } function DropdownMenuRadioGroup({ - ...props + ...props }: React.ComponentProps) { - return ( - - ); + return ( + + ); } function DropdownMenuRadioItem({ - className, - children, - ...props + className, + children, + ...props }: React.ComponentProps) { - return ( - - - - - - - {children} - - ); + return ( + + + + + + + {children} + + ); } function DropdownMenuLabel({ - className, - inset, - ...props + className, + inset, + ...props }: React.ComponentProps & { - inset?: boolean; + inset?: boolean; }) { - return ( - - ); + return ( + + ); } function DropdownMenuSeparator({ - className, - ...props + className, + ...props }: React.ComponentProps) { - return ( - - ); + return ( + + ); } function DropdownMenuShortcut({ - className, - ...props + className, + ...props }: React.ComponentProps<"span">) { - return ( - - ); + return ( + + ); } function DropdownMenuSub({ - ...props + ...props }: React.ComponentProps) { - return ; + return ; } function DropdownMenuSubTrigger({ - className, - inset, - children, - ...props + className, + inset, + children, + ...props }: React.ComponentProps & { - inset?: boolean; + inset?: boolean; }) { - return ( - - {children} - - - ); + return ( + + {children} + + + ); } function DropdownMenuSubContent({ - className, - ...props + className, + ...props }: React.ComponentProps) { - return ( - - ); + return ( + + ); } export { - DropdownMenu, - DropdownMenuPortal, - DropdownMenuTrigger, - DropdownMenuContent, - DropdownMenuGroup, - DropdownMenuLabel, - DropdownMenuItem, - DropdownMenuCheckboxItem, - DropdownMenuRadioGroup, - DropdownMenuRadioItem, - DropdownMenuSeparator, - DropdownMenuShortcut, - DropdownMenuSub, - DropdownMenuSubTrigger, - DropdownMenuSubContent, + DropdownMenu, + DropdownMenuPortal, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuLabel, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubTrigger, + DropdownMenuSubContent, }; diff --git a/apps/web/src/components/ui/input.tsx b/apps/web/src/components/ui/input.tsx index 433a51c..0316cc4 100644 --- a/apps/web/src/components/ui/input.tsx +++ b/apps/web/src/components/ui/input.tsx @@ -3,19 +3,19 @@ import * as React from "react"; import { cn } from "@/lib/utils"; function Input({ className, type, ...props }: React.ComponentProps<"input">) { - return ( - - ); + return ( + + ); } export { Input }; diff --git a/apps/web/src/components/ui/label.tsx b/apps/web/src/components/ui/label.tsx index e46815f..a94bfae 100644 --- a/apps/web/src/components/ui/label.tsx +++ b/apps/web/src/components/ui/label.tsx @@ -4,19 +4,19 @@ import { Label as LabelPrimitive } from "radix-ui"; import { cn } from "@/lib/utils"; function Label({ - className, - ...props + className, + ...props }: React.ComponentProps) { - return ( - - ); + return ( + + ); } export { Label }; diff --git a/apps/web/src/components/ui/skeleton.tsx b/apps/web/src/components/ui/skeleton.tsx index eded6ce..0168998 100644 --- a/apps/web/src/components/ui/skeleton.tsx +++ b/apps/web/src/components/ui/skeleton.tsx @@ -1,13 +1,13 @@ import { cn } from "@/lib/utils"; function Skeleton({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ); + return ( +
+ ); } export { Skeleton }; diff --git a/apps/web/src/components/ui/sonner.tsx b/apps/web/src/components/ui/sonner.tsx index b08c2e8..f96a98d 100644 --- a/apps/web/src/components/ui/sonner.tsx +++ b/apps/web/src/components/ui/sonner.tsx @@ -4,22 +4,22 @@ import { useTheme } from "next-themes"; import { Toaster as Sonner, type ToasterProps } from "sonner"; const Toaster = ({ ...props }: ToasterProps) => { - const { theme = "system" } = useTheme(); + const { theme = "system" } = useTheme(); - return ( - - ); + return ( + + ); }; export { Toaster }; diff --git a/apps/web/src/components/user-menu.tsx b/apps/web/src/components/user-menu.tsx index 302c4c2..3f92e13 100644 --- a/apps/web/src/components/user-menu.tsx +++ b/apps/web/src/components/user-menu.tsx @@ -1,10 +1,10 @@ import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger, + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { authClient } from "@/lib/auth-client"; import { useNavigate } from "@tanstack/react-router"; @@ -13,50 +13,50 @@ import { Skeleton } from "./ui/skeleton"; import { Link } from "@tanstack/react-router"; export default function UserMenu() { - const navigate = useNavigate(); - const { data: session, isPending } = authClient.useSession(); + const navigate = useNavigate(); + const { data: session, isPending } = authClient.useSession(); - if (isPending) { - return ; - } + if (isPending) { + return ; + } - if (!session) { - return ( - - ); - } + if (!session) { + return ( + + ); + } - return ( - - - - - - My Account - - {session.user.email} - - - - - - ); + return ( + + + + + + My Account + + {session.user.email} + + + + + + ); } diff --git a/apps/web/src/index.css b/apps/web/src/index.css index 3e3089b..3e39939 100644 --- a/apps/web/src/index.css +++ b/apps/web/src/index.css @@ -4,132 +4,132 @@ @custom-variant dark (&:where(.dark, .dark *)); @theme { - --font-sans: - "Inter", "Geist", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", - "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --font-sans: + "Inter", "Geist", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", + "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; } html, body { - @apply bg-white dark:bg-gray-950; + @apply bg-white dark:bg-gray-950; - @media (prefers-color-scheme: dark) { - color-scheme: dark; - } + @media (prefers-color-scheme: dark) { + color-scheme: dark; + } } :root { - --radius: 0.625rem; - --background: oklch(1 0 0); - --foreground: oklch(0.145 0 0); - --card: oklch(1 0 0); - --card-foreground: oklch(0.145 0 0); - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.145 0 0); - --primary: oklch(0.205 0 0); - --primary-foreground: oklch(0.985 0 0); - --secondary: oklch(0.97 0 0); - --secondary-foreground: oklch(0.205 0 0); - --muted: oklch(0.97 0 0); - --muted-foreground: oklch(0.556 0 0); - --accent: oklch(0.97 0 0); - --accent-foreground: oklch(0.205 0 0); - --destructive: oklch(0.577 0.245 27.325); - --border: oklch(0.922 0 0); - --input: oklch(0.922 0 0); - --ring: oklch(0.708 0 0); - --chart-1: oklch(0.646 0.222 41.116); - --chart-2: oklch(0.6 0.118 184.704); - --chart-3: oklch(0.398 0.07 227.392); - --chart-4: oklch(0.828 0.189 84.429); - --chart-5: oklch(0.769 0.188 70.08); - --sidebar: oklch(0.985 0 0); - --sidebar-foreground: oklch(0.145 0 0); - --sidebar-primary: oklch(0.205 0 0); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.97 0 0); - --sidebar-accent-foreground: oklch(0.205 0 0); - --sidebar-border: oklch(0.922 0 0); - --sidebar-ring: oklch(0.708 0 0); + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); } .dark { - --background: oklch(0.145 0 0); - --foreground: oklch(0.985 0 0); - --card: oklch(0.205 0 0); - --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.205 0 0); - --popover-foreground: oklch(0.985 0 0); - --primary: oklch(0.922 0 0); - --primary-foreground: oklch(0.205 0 0); - --secondary: oklch(0.269 0 0); - --secondary-foreground: oklch(0.985 0 0); - --muted: oklch(0.269 0 0); - --muted-foreground: oklch(0.708 0 0); - --accent: oklch(0.269 0 0); - --accent-foreground: oklch(0.985 0 0); - --destructive: oklch(0.704 0.191 22.216); - --border: oklch(1 0 0 / 10%); - --input: oklch(1 0 0 / 15%); - --ring: oklch(0.556 0 0); - --chart-1: oklch(0.488 0.243 264.376); - --chart-2: oklch(0.696 0.17 162.48); - --chart-3: oklch(0.769 0.188 70.08); - --chart-4: oklch(0.627 0.265 303.9); - --chart-5: oklch(0.645 0.246 16.439); - --sidebar: oklch(0.205 0 0); - --sidebar-foreground: oklch(0.985 0 0); - --sidebar-primary: oklch(0.488 0.243 264.376); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.269 0 0); - --sidebar-accent-foreground: oklch(0.985 0 0); - --sidebar-border: oklch(1 0 0 / 10%); - --sidebar-ring: oklch(0.556 0 0); + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); } @theme inline { - --radius-sm: calc(var(--radius) - 4px); - --radius-md: calc(var(--radius) - 2px); - --radius-lg: var(--radius); - --radius-xl: calc(var(--radius) + 4px); - --color-background: var(--background); - --color-foreground: var(--foreground); - --color-card: var(--card); - --color-card-foreground: var(--card-foreground); - --color-popover: var(--popover); - --color-popover-foreground: var(--popover-foreground); - --color-primary: var(--primary); - --color-primary-foreground: var(--primary-foreground); - --color-secondary: var(--secondary); - --color-secondary-foreground: var(--secondary-foreground); - --color-muted: var(--muted); - --color-muted-foreground: var(--muted-foreground); - --color-accent: var(--accent); - --color-accent-foreground: var(--accent-foreground); - --color-destructive: var(--destructive); - --color-border: var(--border); - --color-input: var(--input); - --color-ring: var(--ring); - --color-chart-1: var(--chart-1); - --color-chart-2: var(--chart-2); - --color-chart-3: var(--chart-3); - --color-chart-4: var(--chart-4); - --color-chart-5: var(--chart-5); - --color-sidebar: var(--sidebar); - --color-sidebar-foreground: var(--sidebar-foreground); - --color-sidebar-primary: var(--sidebar-primary); - --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); - --color-sidebar-accent: var(--sidebar-accent); - --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); - --color-sidebar-border: var(--sidebar-border); - --color-sidebar-ring: var(--sidebar-ring); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); } @layer base { - * { - @apply border-border outline-ring/50; - } - body { - @apply bg-background text-foreground; - } + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } } diff --git a/apps/web/src/lib/auth-client.ts b/apps/web/src/lib/auth-client.ts index d789aea..e91bf02 100644 --- a/apps/web/src/lib/auth-client.ts +++ b/apps/web/src/lib/auth-client.ts @@ -1,5 +1,5 @@ import { createAuthClient } from "better-auth/react"; export const authClient = createAuthClient({ - baseURL: import.meta.env.VITE_SERVER_URL, + baseURL: import.meta.env.VITE_SERVER_URL, }); diff --git a/apps/web/src/lib/utils.ts b/apps/web/src/lib/utils.ts index 3200be2..a5ef193 100644 --- a/apps/web/src/lib/utils.ts +++ b/apps/web/src/lib/utils.ts @@ -2,5 +2,5 @@ import { clsx, type ClassValue } from "clsx"; import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); + return twMerge(clsx(inputs)); } diff --git a/apps/web/src/main.tsx b/apps/web/src/main.tsx index 8a70e69..bdc5d91 100644 --- a/apps/web/src/main.tsx +++ b/apps/web/src/main.tsx @@ -7,30 +7,30 @@ import { QueryClientProvider } from "@tanstack/react-query"; import { queryClient, trpc } from "./utils/trpc"; const router = createRouter({ - routeTree, - defaultPreload: "intent", - defaultPendingComponent: () => , - context: { trpc, queryClient }, - Wrap: function WrapComponent({ children }: { children: React.ReactNode }) { - return ( - {children} - ); - }, + routeTree, + defaultPreload: "intent", + defaultPendingComponent: () => , + context: { trpc, queryClient }, + Wrap: function WrapComponent({ children }: { children: React.ReactNode }) { + return ( + {children} + ); + }, }); declare module "@tanstack/react-router" { - interface Register { - router: typeof router; - } + interface Register { + router: typeof router; + } } const rootElement = document.getElementById("app"); if (!rootElement) { - throw new Error("Root element not found"); + throw new Error("Root element not found"); } if (!rootElement.innerHTML) { - const root = ReactDOM.createRoot(rootElement); - root.render(); + const root = ReactDOM.createRoot(rootElement); + root.render(); } diff --git a/apps/web/src/routeTree.gen.ts b/apps/web/src/routeTree.gen.ts new file mode 100644 index 0000000..22ef8be --- /dev/null +++ b/apps/web/src/routeTree.gen.ts @@ -0,0 +1,95 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { Route as rootRouteImport } from './routes/__root' +import { Route as LoginRouteImport } from './routes/login' +import { Route as DashboardRouteImport } from './routes/dashboard' +import { Route as IndexRouteImport } from './routes/index' + +const LoginRoute = LoginRouteImport.update({ + id: '/login', + path: '/login', + getParentRoute: () => rootRouteImport, +} as any) +const DashboardRoute = DashboardRouteImport.update({ + id: '/dashboard', + path: '/dashboard', + getParentRoute: () => rootRouteImport, +} as any) +const IndexRoute = IndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRouteImport, +} as any) + +export interface FileRoutesByFullPath { + '/': typeof IndexRoute + '/dashboard': typeof DashboardRoute + '/login': typeof LoginRoute +} +export interface FileRoutesByTo { + '/': typeof IndexRoute + '/dashboard': typeof DashboardRoute + '/login': typeof LoginRoute +} +export interface FileRoutesById { + __root__: typeof rootRouteImport + '/': typeof IndexRoute + '/dashboard': typeof DashboardRoute + '/login': typeof LoginRoute +} +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/' | '/dashboard' | '/login' + fileRoutesByTo: FileRoutesByTo + to: '/' | '/dashboard' | '/login' + id: '__root__' | '/' | '/dashboard' | '/login' + fileRoutesById: FileRoutesById +} +export interface RootRouteChildren { + IndexRoute: typeof IndexRoute + DashboardRoute: typeof DashboardRoute + LoginRoute: typeof LoginRoute +} + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/login': { + id: '/login' + path: '/login' + fullPath: '/login' + preLoaderRoute: typeof LoginRouteImport + parentRoute: typeof rootRouteImport + } + '/dashboard': { + id: '/dashboard' + path: '/dashboard' + fullPath: '/dashboard' + preLoaderRoute: typeof DashboardRouteImport + parentRoute: typeof rootRouteImport + } + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + } +} + +const rootRouteChildren: RootRouteChildren = { + IndexRoute: IndexRoute, + DashboardRoute: DashboardRoute, + LoginRoute: LoginRoute, +} +export const routeTree = rootRouteImport + ._addFileChildren(rootRouteChildren) + ._addFileTypes() diff --git a/apps/web/src/routes/__root.tsx b/apps/web/src/routes/__root.tsx index 2e523a1..6fdf250 100644 --- a/apps/web/src/routes/__root.tsx +++ b/apps/web/src/routes/__root.tsx @@ -6,62 +6,62 @@ import type { trpc } from "@/utils/trpc"; import type { QueryClient } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import { - HeadContent, - Outlet, - createRootRouteWithContext, - useRouterState, + HeadContent, + Outlet, + createRootRouteWithContext, + useRouterState, } from "@tanstack/react-router"; import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; import "../index.css"; export interface RouterAppContext { - trpc: typeof trpc; - queryClient: QueryClient; + trpc: typeof trpc; + queryClient: QueryClient; } export const Route = createRootRouteWithContext()({ - component: RootComponent, - head: () => ({ - meta: [ - { - title: "Reflecto", - }, - { - name: "description", - content: "Reflecto is a web application", - }, - ], - links: [ - { - rel: "icon", - href: "/favicon.ico", - }, - ], - }), + component: RootComponent, + head: () => ({ + meta: [ + { + title: "Reflecto", + }, + { + name: "description", + content: "Reflecto is a web application", + }, + ], + links: [ + { + rel: "icon", + href: "/favicon.ico", + }, + ], + }), }); function RootComponent() { - const isFetching = useRouterState({ - select: (s) => s.isLoading, - }); + const isFetching = useRouterState({ + select: (s) => s.isLoading, + }); - return ( - <> - - -
-
- {isFetching ? : } -
- -
- - - - ); + return ( + <> + + +
+
+ {isFetching ? : } +
+ +
+ + + + ); } diff --git a/apps/web/src/routes/dashboard.tsx b/apps/web/src/routes/dashboard.tsx index ec33694..c53ce0c 100644 --- a/apps/web/src/routes/dashboard.tsx +++ b/apps/web/src/routes/dashboard.tsx @@ -5,33 +5,33 @@ import { createFileRoute } from "@tanstack/react-router"; import { useEffect } from "react"; export const Route = createFileRoute("/dashboard")({ - component: RouteComponent, + component: RouteComponent, }); function RouteComponent() { - const { data: session, isPending } = authClient.useSession(); + const { data: session, isPending } = authClient.useSession(); - const navigate = Route.useNavigate(); + const navigate = Route.useNavigate(); - const privateData = useQuery(trpc.privateData.queryOptions()); + const privateData = useQuery(trpc.privateData.queryOptions()); - useEffect(() => { - if (!session && !isPending) { - navigate({ - to: "/login", - }); - } - }, [session, isPending]); + useEffect(() => { + if (!session && !isPending) { + navigate({ + to: "/login", + }); + } + }, [session, isPending]); - if (isPending) { - return
Loading...
; - } + if (isPending) { + return
Loading...
; + } - return ( -
-

Dashboard

-

Welcome {session?.user.name}

-

privateData: {privateData.data?.message}

-
- ); + return ( +
+

Dashboard

+

Welcome {session?.user.name}

+

privateData: {privateData.data?.message}

+
+ ); } diff --git a/apps/web/src/routes/index.tsx b/apps/web/src/routes/index.tsx index 4b8a110..9f5a627 100644 --- a/apps/web/src/routes/index.tsx +++ b/apps/web/src/routes/index.tsx @@ -3,7 +3,7 @@ import { trpc } from "@/utils/trpc"; import { useQuery } from "@tanstack/react-query"; export const Route = createFileRoute("/")({ - component: HomeComponent, + component: HomeComponent, }); const TITLE_TEXT = ` @@ -23,28 +23,28 @@ const TITLE_TEXT = ` `; function HomeComponent() { - const healthCheck = useQuery(trpc.healthCheck.queryOptions()); + const healthCheck = useQuery(trpc.healthCheck.queryOptions()); - return ( -
-
{TITLE_TEXT}
-
-
-

API Status

-
-
- - {healthCheck.isLoading - ? "Checking..." - : healthCheck.data - ? "Connected" - : "Disconnected"} - -
-
-
-
- ); + return ( +
+
{TITLE_TEXT}
+
+
+

API Status

+
+
+ + {healthCheck.isLoading + ? "Checking..." + : healthCheck.data + ? "Connected" + : "Disconnected"} + +
+
+
+
+ ); } diff --git a/apps/web/src/routes/login.tsx b/apps/web/src/routes/login.tsx index 48928f1..81dc6a0 100644 --- a/apps/web/src/routes/login.tsx +++ b/apps/web/src/routes/login.tsx @@ -4,15 +4,15 @@ import { createFileRoute } from "@tanstack/react-router"; import { useState } from "react"; export const Route = createFileRoute("/login")({ - component: RouteComponent, + component: RouteComponent, }); function RouteComponent() { - const [showSignIn, setShowSignIn] = useState(false); + const [showSignIn, setShowSignIn] = useState(false); - return showSignIn ? ( - setShowSignIn(false)} /> - ) : ( - setShowSignIn(true)} /> - ); + return showSignIn ? ( + setShowSignIn(false)} /> + ) : ( + setShowSignIn(true)} /> + ); } diff --git a/apps/web/src/utils/trpc.ts b/apps/web/src/utils/trpc.ts index 5e1c0ea..986941c 100644 --- a/apps/web/src/utils/trpc.ts +++ b/apps/web/src/utils/trpc.ts @@ -5,35 +5,35 @@ import { createTRPCOptionsProxy } from "@trpc/tanstack-react-query"; import { toast } from "sonner"; export const queryClient = new QueryClient({ - queryCache: new QueryCache({ - onError: (error) => { - toast.error(error.message, { - action: { - label: "retry", - onClick: () => { - queryClient.invalidateQueries(); - }, - }, - }); - }, - }), + queryCache: new QueryCache({ + onError: (error) => { + toast.error(error.message, { + action: { + label: "retry", + onClick: () => { + queryClient.invalidateQueries(); + }, + }, + }); + }, + }), }); export const trpcClient = createTRPCClient({ - links: [ - httpBatchLink({ - url: `${import.meta.env.VITE_SERVER_URL}/trpc`, - fetch(url, options) { - return fetch(url, { - ...options, - credentials: "include", - }); - }, - }), - ], + links: [ + httpBatchLink({ + url: `${import.meta.env.VITE_SERVER_URL}/trpc`, + fetch(url, options) { + return fetch(url, { + ...options, + credentials: "include", + }); + }, + }), + ], }); export const trpc = createTRPCOptionsProxy({ - client: trpcClient, - queryClient, + client: trpcClient, + queryClient, }); diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json index 0c52e9b..68a0e60 100644 --- a/apps/web/tsconfig.json +++ b/apps/web/tsconfig.json @@ -1,23 +1,23 @@ { - "compilerOptions": { - "strict": true, - "esModuleInterop": true, - "jsx": "react-jsx", - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "Bundler", - "verbatimModuleSyntax": true, - "skipLibCheck": true, - "types": ["vite/client"], - "rootDirs": ["."], - "baseUrl": ".", - "paths": { - "@/*": ["./src/*"] - } - }, - "references": [ - { - "path": "../server" - } - ] + "compilerOptions": { + "strict": true, + "esModuleInterop": true, + "jsx": "react-jsx", + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Bundler", + "verbatimModuleSyntax": true, + "skipLibCheck": true, + "types": ["vite/client"], + "rootDirs": ["."], + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "references": [ + { + "path": "../server" + } + ] } diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index ded44b6..1a0a1e1 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -6,25 +6,25 @@ import path from "node:path"; import { defineConfig } from "vite"; export default defineConfig({ - plugins: [ - tailwindcss(), - tanstackRouter({}), - react(), - VitePWA({ - registerType: "autoUpdate", - manifest: { - name: "Reflecto", - short_name: "Reflecto", - description: "Reflecto - PWA Application", - theme_color: "#0c0c0c", - }, - pwaAssets: { disabled: false, config: true }, - devOptions: { enabled: true }, - }), - ], - resolve: { - alias: { - "@": path.resolve(__dirname, "./src"), - }, - }, + plugins: [ + tailwindcss(), + tanstackRouter({}), + react(), + VitePWA({ + registerType: "autoUpdate", + manifest: { + name: "Reflecto", + short_name: "Reflecto", + description: "Reflecto - PWA Application", + theme_color: "#0c0c0c", + }, + pwaAssets: { disabled: false, config: true }, + devOptions: { enabled: true }, + }), + ], + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, }); diff --git a/biome.json b/biome.json index 5a460df..53144dd 100644 --- a/biome.json +++ b/biome.json @@ -1,25 +1,25 @@ { - "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", - "files": { - "ignoreUnknown": false, - "includes": [ - "**", - "!**/.next", - "!**/dist", - "!**/.turbo", - "!**/dev-dist", - "!**/.zed", - "!**/.vscode", - "!**/routeTree.gen.ts", - "!**/src-tauri", - "!**/.nuxt", - "!bts.jsonc", - "!**/.expo", - "!**/.wrangler", - "!**/.alchemy", - "!**/wrangler.jsonc", - "!**/.source" - ] - }, - "extends": ["ultracite"] + "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", + "files": { + "ignoreUnknown": false, + "includes": [ + "**", + "!**/.next", + "!**/dist", + "!**/.turbo", + "!**/dev-dist", + "!**/.zed", + "!**/.vscode", + "!**/routeTree.gen.ts", + "!**/src-tauri", + "!**/.nuxt", + "!bts.jsonc", + "!**/.expo", + "!**/.wrangler", + "!**/.alchemy", + "!**/wrangler.jsonc", + "!**/.source" + ] + }, + "extends": ["ultracite"] } diff --git a/package.json b/package.json index 2ea0051..6b2e61e 100644 --- a/package.json +++ b/package.json @@ -1,39 +1,39 @@ { - "name": "Reflecto", - "private": true, - "workspaces": [ - "apps/*", - "packages/*" - ], - "scripts": { - "check": "biome check --write .", - "dev": "turbo dev", - "build": "turbo build", - "check-types": "turbo check-types", - "dev:native": "turbo -F native dev", - "dev:web": "turbo -F web dev", - "dev:server": "turbo -F server dev", - "db:push": "turbo -F server db:push", - "db:studio": "turbo -F server db:studio", - "db:generate": "turbo -F server db:generate", - "db:migrate": "turbo -F server db:migrate", - "db:start": "turbo -F server db:start", - "db:watch": "turbo -F server db:watch", - "db:stop": "turbo -F server db:stop", - "db:down": "turbo -F server db:down" - }, - "dependencies": {}, - "devDependencies": { - "turbo": "^2.5.4", - "@biomejs/biome": "2.2.2", - "ultracite": "5.3.2", - "husky": "^9.1.7", - "lint-staged": "^16.1.2" - }, - "lint-staged": { - "*.{js,jsx,ts,tsx,json,jsonc,css,scss,md,mdx}": [ - "pnpm dlx ultracite fix" - ] - }, - "packageManager": "pnpm@10.14.0" + "name": "Reflecto", + "private": true, + "workspaces": [ + "apps/*", + "packages/*" + ], + "scripts": { + "check": "biome check --write .", + "dev": "turbo dev", + "build": "turbo build", + "check-types": "turbo check-types", + "dev:native": "turbo -F native dev", + "dev:web": "turbo -F web dev", + "dev:server": "turbo -F server dev", + "db:push": "turbo -F server db:push", + "db:studio": "turbo -F server db:studio", + "db:generate": "turbo -F server db:generate", + "db:migrate": "turbo -F server db:migrate", + "db:start": "turbo -F server db:start", + "db:watch": "turbo -F server db:watch", + "db:stop": "turbo -F server db:stop", + "db:down": "turbo -F server db:down" + }, + "dependencies": {}, + "devDependencies": { + "turbo": "^2.5.4", + "@biomejs/biome": "2.2.2", + "ultracite": "5.3.2", + "husky": "^9.1.7", + "lint-staged": "^16.1.2" + }, + "lint-staged": { + "*.{js,jsx,ts,tsx,json,jsonc,css,scss,md,mdx}": [ + "pnpm dlx ultracite fix" + ] + }, + "packageManager": "pnpm@10.14.0" } diff --git a/tsconfig.json b/tsconfig.json index 142e0af..9647394 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,5 @@ { - "compilerOptions": { - "strictNullChecks": true - } + "compilerOptions": { + "strictNullChecks": true + } } diff --git a/turbo.json b/turbo.json index 53076fc..41769b9 100644 --- a/turbo.json +++ b/turbo.json @@ -1,53 +1,53 @@ { - "$schema": "https://turbo.build/schema.json", - "ui": "tui", - "tasks": { - "build": { - "dependsOn": ["^build"], - "inputs": ["$TURBO_DEFAULT$", ".env*"], - "outputs": ["dist/**"] - }, - "lint": { - "dependsOn": ["^lint"] - }, - "check-types": { - "dependsOn": ["^check-types"] - }, - "dev": { - "cache": false, - "persistent": true - }, - "db:push": { - "cache": false, - "persistent": true - }, - "db:studio": { - "cache": false, - "persistent": true - }, - "db:migrate": { - "cache": false, - "persistent": true - }, - "db:generate": { - "cache": false, - "persistent": true - }, - "db:start": { - "cache": false, - "persistent": true - }, - "db:stop": { - "cache": false, - "persistent": true - }, - "db:watch": { - "cache": false, - "persistent": true - }, - "db:down": { - "cache": false, - "persistent": true - } - } + "$schema": "https://turbo.build/schema.json", + "ui": "tui", + "tasks": { + "build": { + "dependsOn": ["^build"], + "inputs": ["$TURBO_DEFAULT$", ".env*"], + "outputs": ["dist/**"] + }, + "lint": { + "dependsOn": ["^lint"] + }, + "check-types": { + "dependsOn": ["^check-types"] + }, + "dev": { + "cache": false, + "persistent": true + }, + "db:push": { + "cache": false, + "persistent": true + }, + "db:studio": { + "cache": false, + "persistent": true + }, + "db:migrate": { + "cache": false, + "persistent": true + }, + "db:generate": { + "cache": false, + "persistent": true + }, + "db:start": { + "cache": false, + "persistent": true + }, + "db:stop": { + "cache": false, + "persistent": true + }, + "db:watch": { + "cache": false, + "persistent": true + }, + "db:down": { + "cache": false, + "persistent": true + } + } }