feat: init Better Auth and DB
This commit is contained in:
+213
@@ -1,4 +1,9 @@
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
@import "shadcn/tailwind.css";
|
||||
@import "@fontsource-variable/inter";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
@theme {
|
||||
--font-sans:
|
||||
@@ -14,3 +19,211 @@ body {
|
||||
color-scheme: dark;
|
||||
}
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--font-heading: var(--font-sans);
|
||||
--font-sans: Oxanium, sans-serif;
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-ring: var(--ring);
|
||||
--color-input: var(--input);
|
||||
--color-border: var(--border);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-card: var(--card);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-background: var(--background);
|
||||
--radius-sm: calc(var(--radius) * 0.6);
|
||||
--radius-md: calc(var(--radius) * 0.8);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) * 1.4);
|
||||
--radius-2xl: calc(var(--radius) * 1.8);
|
||||
--radius-3xl: calc(var(--radius) * 2.2);
|
||||
--radius-4xl: calc(var(--radius) * 2.6);
|
||||
--font-mono: Fira Code, monospace;
|
||||
--font-serif: Merriweather, serif;
|
||||
--radius: 0.3rem;
|
||||
--tracking-tighter: calc(var(--tracking-normal) - 0.05em);
|
||||
--tracking-tight: calc(var(--tracking-normal) - 0.025em);
|
||||
--tracking-wide: calc(var(--tracking-normal) + 0.025em);
|
||||
--tracking-wider: calc(var(--tracking-normal) + 0.05em);
|
||||
--tracking-widest: calc(var(--tracking-normal) + 0.1em);
|
||||
--tracking-normal: var(--tracking-normal);
|
||||
--shadow-2xl: var(--shadow-2xl);
|
||||
--shadow-xl: var(--shadow-xl);
|
||||
--shadow-lg: var(--shadow-lg);
|
||||
--shadow-md: var(--shadow-md);
|
||||
--shadow: var(--shadow);
|
||||
--shadow-sm: var(--shadow-sm);
|
||||
--shadow-xs: var(--shadow-xs);
|
||||
--shadow-2xs: var(--shadow-2xs);
|
||||
--spacing: var(--spacing);
|
||||
--letter-spacing: var(--letter-spacing);
|
||||
--shadow-offset-y: var(--shadow-offset-y);
|
||||
--shadow-offset-x: var(--shadow-offset-x);
|
||||
--shadow-spread: var(--shadow-spread);
|
||||
--shadow-blur: var(--shadow-blur);
|
||||
--shadow-opacity: var(--shadow-opacity);
|
||||
--color-shadow-color: var(--shadow-color);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
}
|
||||
|
||||
:root {
|
||||
--background: oklch(0.9885 0.0057 84.5659);
|
||||
--foreground: oklch(0.366 0.0251 49.6085);
|
||||
--card: oklch(0.9686 0.0091 78.2818);
|
||||
--card-foreground: oklch(0.366 0.0251 49.6085);
|
||||
--popover: oklch(0.9686 0.0091 78.2818);
|
||||
--popover-foreground: oklch(0.366 0.0251 49.6085);
|
||||
--primary: oklch(0.5553 0.1455 48.9975);
|
||||
--primary-foreground: oklch(1 0 0);
|
||||
--secondary: oklch(0.8276 0.0752 74.44);
|
||||
--secondary-foreground: oklch(0.4444 0.0096 73.639);
|
||||
--muted: oklch(0.9363 0.0218 83.2637);
|
||||
--muted-foreground: oklch(0.5534 0.0116 58.0708);
|
||||
--accent: oklch(0.9 0.05 74.9889);
|
||||
--accent-foreground: oklch(0.4444 0.0096 73.639);
|
||||
--destructive: oklch(0.4437 0.1613 26.8994);
|
||||
--border: oklch(0.8866 0.0404 89.6994);
|
||||
--input: oklch(0.8866 0.0404 89.6994);
|
||||
--ring: oklch(0.5553 0.1455 48.9975);
|
||||
--chart-1: oklch(0.5553 0.1455 48.9975);
|
||||
--chart-2: oklch(0.5534 0.0116 58.0708);
|
||||
--chart-3: oklch(0.5538 0.1207 66.4416);
|
||||
--chart-4: oklch(0.5534 0.0116 58.0708);
|
||||
--chart-5: oklch(0.6806 0.1423 75.834);
|
||||
--radius: 0.3rem;
|
||||
--sidebar: oklch(0.9363 0.0218 83.2637);
|
||||
--sidebar-foreground: oklch(0.366 0.0251 49.6085);
|
||||
--sidebar-primary: oklch(0.5553 0.1455 48.9975);
|
||||
--sidebar-primary-foreground: oklch(1 0 0);
|
||||
--sidebar-accent: oklch(0.5538 0.1207 66.4416);
|
||||
--sidebar-accent-foreground: oklch(1 0 0);
|
||||
--sidebar-border: oklch(0.8866 0.0404 89.6994);
|
||||
--sidebar-ring: oklch(0.5553 0.1455 48.9975);
|
||||
--destructive-foreground: oklch(1 0 0);
|
||||
--font-sans: Oxanium, sans-serif;
|
||||
--font-serif: Merriweather, serif;
|
||||
--font-mono: Fira Code, monospace;
|
||||
--shadow-color: hsl(28 18% 25%);
|
||||
--shadow-opacity: 0.18;
|
||||
--shadow-blur: 3px;
|
||||
--shadow-spread: 0px;
|
||||
--shadow-offset-x: 0px;
|
||||
--shadow-offset-y: 2px;
|
||||
--letter-spacing: 0em;
|
||||
--spacing: 0.25rem;
|
||||
--shadow-2xs: 0px 2px 3px 0px hsl(28 18% 25% / 0.09);
|
||||
--shadow-xs: 0px 2px 3px 0px hsl(28 18% 25% / 0.09);
|
||||
--shadow-sm:
|
||||
0px 2px 3px 0px hsl(28 18% 25% / 0.18),
|
||||
0px 1px 2px -1px hsl(28 18% 25% / 0.18);
|
||||
--shadow:
|
||||
0px 2px 3px 0px hsl(28 18% 25% / 0.18),
|
||||
0px 1px 2px -1px hsl(28 18% 25% / 0.18);
|
||||
--shadow-md:
|
||||
0px 2px 3px 0px hsl(28 18% 25% / 0.18),
|
||||
0px 2px 4px -1px hsl(28 18% 25% / 0.18);
|
||||
--shadow-lg:
|
||||
0px 2px 3px 0px hsl(28 18% 25% / 0.18),
|
||||
0px 4px 6px -1px hsl(28 18% 25% / 0.18);
|
||||
--shadow-xl:
|
||||
0px 2px 3px 0px hsl(28 18% 25% / 0.18),
|
||||
0px 8px 10px -1px hsl(28 18% 25% / 0.18);
|
||||
--shadow-2xl: 0px 2px 3px 0px hsl(28 18% 25% / 0.45);
|
||||
--tracking-normal: 0em;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.2161 0.0061 56.0434);
|
||||
--foreground: oklch(0.9699 0.0013 106.4238);
|
||||
--card: oklch(0.2685 0.0063 34.2976);
|
||||
--card-foreground: oklch(0.9699 0.0013 106.4238);
|
||||
--popover: oklch(0.2685 0.0063 34.2976);
|
||||
--popover-foreground: oklch(0.9699 0.0013 106.4238);
|
||||
--primary: oklch(0.7049 0.1867 47.6044);
|
||||
--primary-foreground: oklch(1 0 0);
|
||||
--secondary: oklch(0.4444 0.0096 73.639);
|
||||
--secondary-foreground: oklch(0.9232 0.0026 48.7171);
|
||||
--muted: oklch(0.233 0.0073 67.4563);
|
||||
--muted-foreground: oklch(0.7161 0.0091 56.259);
|
||||
--accent: oklch(0.3598 0.0497 229.3202);
|
||||
--accent-foreground: oklch(0.9232 0.0026 48.7171);
|
||||
--destructive: oklch(0.5771 0.2152 27.325);
|
||||
--border: oklch(0.3741 0.0087 67.5582);
|
||||
--input: oklch(0.3741 0.0087 67.5582);
|
||||
--ring: oklch(0.7049 0.1867 47.6044);
|
||||
--chart-1: oklch(0.7049 0.1867 47.6044);
|
||||
--chart-2: oklch(0.6847 0.1479 237.3225);
|
||||
--chart-3: oklch(0.7952 0.1617 86.0468);
|
||||
--chart-4: oklch(0.7161 0.0091 56.259);
|
||||
--chart-5: oklch(0.5534 0.0116 58.0708);
|
||||
--sidebar: oklch(0.2685 0.0063 34.2976);
|
||||
--sidebar-foreground: oklch(0.9699 0.0013 106.4238);
|
||||
--sidebar-primary: oklch(0.7049 0.1867 47.6044);
|
||||
--sidebar-primary-foreground: oklch(1 0 0);
|
||||
--sidebar-accent: oklch(0.6847 0.1479 237.3225);
|
||||
--sidebar-accent-foreground: oklch(0.2839 0.0734 254.5378);
|
||||
--sidebar-border: oklch(0.3741 0.0087 67.5582);
|
||||
--sidebar-ring: oklch(0.7049 0.1867 47.6044);
|
||||
--destructive-foreground: oklch(1 0 0);
|
||||
--radius: 0.3rem;
|
||||
--font-sans: Oxanium, sans-serif;
|
||||
--font-serif: Merriweather, serif;
|
||||
--font-mono: Fira Code, monospace;
|
||||
--shadow-color: hsl(0 0% 5%);
|
||||
--shadow-opacity: 0.18;
|
||||
--shadow-blur: 3px;
|
||||
--shadow-spread: 0px;
|
||||
--shadow-offset-x: 0px;
|
||||
--shadow-offset-y: 2px;
|
||||
--letter-spacing: 0em;
|
||||
--spacing: 0.25rem;
|
||||
--shadow-2xs: 0px 2px 3px 0px hsl(0 0% 5% / 0.09);
|
||||
--shadow-xs: 0px 2px 3px 0px hsl(0 0% 5% / 0.09);
|
||||
--shadow-sm:
|
||||
0px 2px 3px 0px hsl(0 0% 5% / 0.18), 0px 1px 2px -1px hsl(0 0% 5% / 0.18);
|
||||
--shadow:
|
||||
0px 2px 3px 0px hsl(0 0% 5% / 0.18), 0px 1px 2px -1px hsl(0 0% 5% / 0.18);
|
||||
--shadow-md:
|
||||
0px 2px 3px 0px hsl(0 0% 5% / 0.18), 0px 2px 4px -1px hsl(0 0% 5% / 0.18);
|
||||
--shadow-lg:
|
||||
0px 2px 3px 0px hsl(0 0% 5% / 0.18), 0px 4px 6px -1px hsl(0 0% 5% / 0.18);
|
||||
--shadow-xl:
|
||||
0px 2px 3px 0px hsl(0 0% 5% / 0.18), 0px 8px 10px -1px hsl(0 0% 5% / 0.18);
|
||||
--shadow-2xl: 0px 2px 3px 0px hsl(0 0% 5% / 0.45);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
letter-spacing: var(--tracking-normal);
|
||||
}
|
||||
html {
|
||||
@apply font-sans;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
import { Button } from "./ui/button";
|
||||
|
||||
export default function Home() {
|
||||
return <main>Hello World</main>;
|
||||
return (
|
||||
<main className="h-screen w-full flex items-center justify-center">
|
||||
<Button>Hello World</Button>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import * as React from "react";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { Slot } from "radix-ui";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
|
||||
const buttonVariants = cva(
|
||||
"group/button inline-flex shrink-0 items-center justify-center rounded-none border border-transparent bg-clip-padding text-xs font-semibold tracking-widest whitespace-nowrap uppercase transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-primary text-primary-foreground hover:bg-primary/80",
|
||||
outline:
|
||||
"border-border bg-transparent hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-input/30",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
|
||||
ghost:
|
||||
"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
|
||||
destructive:
|
||||
"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
|
||||
link: "text-primary underline underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default:
|
||||
"h-10 gap-1.5 px-6 has-data-[icon=inline-end]:pr-4 has-data-[icon=inline-start]:pl-4",
|
||||
xs: "h-7 gap-1 px-3 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3",
|
||||
sm: "h-9 gap-1 px-4 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
|
||||
lg: "h-11 gap-1.5 px-8 has-data-[icon=inline-end]:pr-5 has-data-[icon=inline-start]:pl-5",
|
||||
icon: "size-10",
|
||||
"icon-xs": "size-7 [&_svg:not([class*='size-'])]:size-3",
|
||||
"icon-sm": "size-9",
|
||||
"icon-lg": "size-11",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
function Button({
|
||||
className,
|
||||
variant = "default",
|
||||
size = "default",
|
||||
asChild = false,
|
||||
...props
|
||||
}: React.ComponentProps<"button"> &
|
||||
VariantProps<typeof buttonVariants> & {
|
||||
asChild?: boolean;
|
||||
}) {
|
||||
const Comp = asChild ? Slot.Root : "button";
|
||||
|
||||
return (
|
||||
<Comp
|
||||
data-slot="button"
|
||||
data-variant={variant}
|
||||
data-size={size}
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export { Button, buttonVariants };
|
||||
@@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
create table "user" ("id" text not null primary key, "name" text not null, "email" text not null unique, "emailVerified" integer not null, "image" text, "createdAt" date not null, "updatedAt" date not null);
|
||||
|
||||
create table "session" ("id" text not null primary key, "expiresAt" date not null, "token" text not null unique, "createdAt" date not null, "updatedAt" date not null, "ipAddress" text, "userAgent" text, "userId" text not null references "user" ("id") on delete cascade);
|
||||
|
||||
create table "account" ("id" text not null primary key, "accountId" text not null, "providerId" text not null, "userId" text not null references "user" ("id") on delete cascade, "accessToken" text, "refreshToken" text, "idToken" text, "accessTokenExpiresAt" date, "refreshTokenExpiresAt" date, "scope" text, "password" text, "createdAt" date not null, "updatedAt" date not null);
|
||||
|
||||
create table "verification" ("id" text not null primary key, "identifier" text not null, "value" text not null, "expiresAt" date not null, "createdAt" date not null, "updatedAt" date not null);
|
||||
|
||||
create index "session_userId_idx" on "session" ("userId");
|
||||
|
||||
create index "account_userId_idx" on "account" ("userId");
|
||||
|
||||
create index "verification_identifier_idx" on "verification" ("identifier");
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "radix-sera",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "",
|
||||
"css": "app/app.css",
|
||||
"baseColor": "mist",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"iconLibrary": "lucide",
|
||||
"rtl": false,
|
||||
"aliases": {
|
||||
"components": "~/components",
|
||||
"utils": "~/lib/utils",
|
||||
"ui": "~/components/ui",
|
||||
"lib": "~/lib",
|
||||
"hooks": "~/hooks"
|
||||
},
|
||||
"menuColor": "default",
|
||||
"menuAccent": "subtle",
|
||||
"registries": {}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { betterAuth } from "better-auth";
|
||||
import Database from "better-sqlite3";
|
||||
|
||||
export const auth = betterAuth({
|
||||
database: new Database("./sqlite.db"),
|
||||
});
|
||||
Generated
+5616
-9
File diff suppressed because it is too large
Load Diff
+12
-1
@@ -10,17 +10,28 @@
|
||||
"format": "prettier . --write"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource-variable/inter": "^5.2.8",
|
||||
"@react-router/fs-routes": "^7.15.1",
|
||||
"@react-router/node": "7.15.1",
|
||||
"@react-router/serve": "7.15.1",
|
||||
"better-auth": "^1.6.11",
|
||||
"better-sqlite3": "^12.10.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"isbot": "^5.1.36",
|
||||
"lucide-react": "^1.16.0",
|
||||
"radix-ui": "^1.4.3",
|
||||
"react": "^19.2.6",
|
||||
"react-dom": "^19.2.6",
|
||||
"react-router": "7.15.1"
|
||||
"react-router": "7.15.1",
|
||||
"shadcn": "^4.7.0",
|
||||
"tailwind-merge": "^3.6.0",
|
||||
"tw-animate-css": "^1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-router/dev": "7.15.1",
|
||||
"@tailwindcss/vite": "^4.2.2",
|
||||
"@types/better-sqlite3": "^7.6.13",
|
||||
"@types/node": "^22",
|
||||
"@types/react": "^19.2.14",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
|
||||
Reference in New Issue
Block a user