diff --git a/README.md b/README.md
index e215bc4..d17f36f 100644
--- a/README.md
+++ b/README.md
@@ -1,36 +1,281 @@
-This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
+# SecNex Auth Login
+
+A Next.js 15 application for authentication with SecNex. The application uses Server Actions for login/logout and Route Handlers for session checks. Authentication tokens are managed via HTTP-only cookies.
+
+## Features
+
+- **Login Form** - Username/password authentication with form validation
+- **OAuth Authorization Flow** - `/authorize` endpoint for third-party app authorization
+- **Session Management** - Token validation and automatic cleanup
+- **Social Login Buttons** - GitHub and Google OAuth buttons (UI only)
+- **Responsive UI** - Built with shadcn/ui components
+- **Toast Notifications** - User feedback using Sonner
+
+## Project Structure
+
+```
+auth-login/
+├── app/
+│ ├── api/
+│ │ ├── logout/
+│ │ │ └── route.tsx # Route Handler for logout
+│ │ └── session/
+│ │ └── route.ts # Route Handler for session check
+│ ├── authorize/
+│ │ └── page.tsx # OAuth authorization page
+│ ├── layout.tsx # Root layout with fonts
+│ └── page.tsx # Home page (Login / Success)
+├── components/
+│ ├── core/
+│ │ ├── login-form.tsx # Login form components (Client Components)
+│ │ ├── authorize.tsx # OAuth authorization component
+│ │ ├── social-login-button.tsx
+│ │ └── loading.tsx # Loading spinner component
+│ ├── server/
+│ │ └── login.tsx # Server Actions for login
+│ └── ui/ # UI components (shadcn/ui)
+├── lib/
+│ └── utils.ts # Utility functions
+└── permissions.json # OAuth scope permissions
+```
+
+## Technical Details
+
+### Route Handlers vs Server Actions
+
+In Next.js 15, cookies can only be modified in the following contexts:
+- **Route Handlers** (API routes under `app/api/`)
+- **Server Actions** with `"use server"` directive
+
+**Key Difference:**
+- Route Handlers can ALWAYS modify cookies
+- Server Actions CANNOT modify cookies when called from a Server Component
+
+### Architecture Decisions
+
+| Operation | Type | Reason |
+|-----------|------|--------|
+| Login | Server Action | Called from Client Components |
+| Session Check | Route Handler | Called from Server Component, needs cookie deletion ability |
+| Logout | Route Handler | Called from Client Component via fetch |
+
+### Cookie Deletion in Route Handler
+
+**Problem:** The original code attempted to delete cookies in a Server Action called from a Server Component, resulting in:
+
+```
+Error: Cookies can only be modified in a Server Action or Route Handler.
+```
+
+**Solution:** The session check was moved to a Route Handler (`app/api/session/route.ts`). Route Handlers always have access to cookie modification, regardless of the caller.
## Getting Started
-First, run the development server:
+### Prerequisites
+
+- Node.js 18+
+- pnpm
+
+### Environment Variables
+
+Create a `.env.local` file in the root directory:
```bash
-npm run dev
-# or
-yarn dev
-# or
-pnpm dev
-# or
-bun dev
+SECNEX_API_HOST=http://localhost:3001
+SECNEX_API_KEY=your_api_key_here
```
-Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+### Installation
-You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
+```bash
+pnpm install
+```
-This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
+### Development Server
-## Learn More
+```bash
+pnpm dev
+```
-To learn more about Next.js, take a look at the following resources:
+The application will be available at [http://localhost:3000](http://localhost:3000).
-- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
-- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
+### Build
-You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
+```bash
+pnpm build
+```
-## Deploy on Vercel
+### Production
-The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
+```bash
+pnpm start
+```
-Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
+## How It Works
+
+### Login Flow
+
+1. User enters username and password
+2. `login()` Server Action is called
+3. Request to SecNex API (`/login`)
+4. On success: Token is stored in HTTP-only cookie
+5. Page is refreshed
+
+### Session Check (via Route Handler)
+
+1. Server Component checks if token exists
+2. GET request to `/api/session`
+3. Route Handler validates token with SecNex API (`/session/info`)
+4. On invalid token: Cookie is deleted directly
+5. Result is returned
+
+### Logout Flow
+
+1. `GET /api/logout` is called
+2. Request to SecNex API (`/logout`)
+3. Cookie is deleted
+
+### OAuth Authorization Flow
+
+1. User is redirected to `/authorize` with query parameters:
+ - `client_id` - The client application identifier
+ - `redirect_uri` - The URI to redirect after authorization
+ - `response_type` - The response type (default: "code")
+ - `scope` - Requested permissions (default: "profile email")
+2. User must be logged in (otherwise redirected to `/`)
+3. Authorization page shows:
+ - Application name and URL
+ - User information
+ - Requested permissions (from `permissions.json`)
+4. User can authorize or deny the request
+
+## API Endpoints
+
+### Server Actions
+
+#### `login(username, password)`
+
+Performs login and stores the token in a cookie.
+
+```typescript
+const response = await login("user", "password");
+// { success: boolean, message: string, token?: string }
+```
+
+### Route Handlers
+
+#### `GET /api/session`
+
+Validates the token and returns session information. Automatically deletes the cookie on invalid token.
+
+```typescript
+const response = await fetch("/api/session");
+const data = await response.json();
+// { success: boolean, message: string, sessionInfo?: { username, email, role } }
+```
+
+#### `GET /api/logout`
+
+Logs out the user and deletes the token.
+
+```typescript
+const response = await fetch("/api/logout");
+const data = await response.json();
+// { success: boolean, message: string }
+```
+
+## Components
+
+### `LoginContainer`
+
+Displays the login form.
+
+```tsx
+
+```
+
+### `LoginSuccessContainer`
+
+Displays the success page after login.
+
+```tsx
+
+```
+
+### `AuthorizeContainer`
+
+Displays the OAuth authorization page.
+
+```tsx
+
+```
+
+## Permissions
+
+The `permissions.json` file defines OAuth scope permissions:
+
+```json
+{
+ "profile": {
+ "name": "Profile Information",
+ "description": "View your name and profile picture"
+ },
+ "email": {
+ "name": "Email Address",
+ "description": "View your email address"
+ }
+}
+```
+
+## Important Notes
+
+- Server Actions use `"use server"` directive
+- Route Handlers allow cookie modification from Server Components
+- Cookies are HTTP-only for additional security
+- The SecNex API must be running at the configured `SECNEX_API_HOST`
+- API credentials should be stored in environment variables (not hardcoded)
+
+## Tech Stack
+
+- **Next.js 15** - React framework
+- **React 19** - UI library
+- **TypeScript** - Type safety
+- **Tailwind CSS** - Styling
+- **shadcn/ui** - UI components
+- **Radix UI** - Headless UI primitives
+- **React Hook Form** - Form management
+- **Zod** - Schema validation
+- **Sonner** - Toast notifications
+- **Tabler Icons** - Icon library
+
+## Deployment
+
+### Vercel
+
+The easiest way to deploy is using the Vercel platform:
+
+[https://vercel.com/new](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme)
+
+For more information, see the [Next.js Deployment Documentation](https://nextjs.org/docs/app/building-your-application/deploying).
+
+### Environment Variables
+
+Make sure to set the following environment variables in your deployment:
+
+- `SECNEX_API_HOST` - Your SecNex API host URL
+- `SECNEX_API_KEY` - Your SecNex API key
+
+## License
+
+MIT
diff --git a/app/api/logout/route.tsx b/app/api/logout/route.tsx
new file mode 100644
index 0000000..741d005
--- /dev/null
+++ b/app/api/logout/route.tsx
@@ -0,0 +1,34 @@
+import { NextResponse } from "next/server";
+import { cookies } from "next/headers";
+
+export async function GET() {
+ if (!process.env.SECNEX_API_HOST || !process.env.SECNEX_API_KEY) {
+ return NextResponse.json({ success: false, message: "SecNex API host or key is not set" });
+ }
+ const cookieStore = await cookies();
+ const token = cookieStore.get("token");
+ if (!token) {
+ console.log("No token found");
+ return NextResponse.json({ success: false, message: "No token found" });
+ }
+ console.log("Token found");
+ const response = await fetch(`${process.env.SECNEX_API_HOST}/logout`, {
+ method: "POST",
+ body: JSON.stringify({ token: token.value }),
+ headers: {
+ "Content-Type": "application/json",
+ "Authorization": `Bearer ${process.env.SECNEX_API_KEY}`,
+ },
+ });
+ if (!response.ok) {
+ const data = await response.json();
+ cookieStore.delete("token");
+ console.log("Token deleted");
+ return NextResponse.json({ success: false, message: data.body.message });
+ }
+ const data = await response.json();
+ cookieStore.delete("token");
+ console.log("Token deleted");
+ console.log("Logout successful");
+ return NextResponse.json({ success: true, message: data.body.message });
+}
\ No newline at end of file
diff --git a/app/api/session/route.ts b/app/api/session/route.ts
new file mode 100644
index 0000000..997eb11
--- /dev/null
+++ b/app/api/session/route.ts
@@ -0,0 +1,41 @@
+import { NextResponse } from "next/server";
+import { cookies } from "next/headers";
+import { revalidatePath } from "next/cache";
+
+export async function GET() {
+ if (!process.env.SECNEX_API_HOST || !process.env.SECNEX_API_KEY) {
+ return NextResponse.json({ success: false, message: "SecNex API host or key is not set" });
+ }
+ const cookieStore = await cookies();
+ const token = cookieStore.get("token");
+
+ if (!token) {
+ return NextResponse.json({ success: false, message: "No token found" });
+ }
+
+ try {
+ const response = await fetch(`${process.env.SECNEX_API_HOST}/session/info`, {
+ method: "POST",
+ body: JSON.stringify({ token: token.value }),
+ headers: {
+ "Content-Type": "application/json",
+ "Authorization": `Bearer ${process.env.SECNEX_API_KEY}`,
+ },
+ });
+
+ if (!response.ok) {
+ cookieStore.delete("token");
+ revalidatePath("/", "layout");
+ return NextResponse.json({ success: false, message: "Token is invalid" });
+ }
+
+ const dataResponse = await response.json();
+ const body = dataResponse.body.session;
+ return NextResponse.json({ success: true, message: body.message, sessionInfo: body });
+ } catch (error) {
+ console.error(error);
+ cookieStore.delete("token");
+ revalidatePath("/", "layout");
+ return NextResponse.json({ success: false, message: "Failed to get session info" });
+ }
+}
diff --git a/app/authorize/page.tsx b/app/authorize/page.tsx
new file mode 100644
index 0000000..99882b6
--- /dev/null
+++ b/app/authorize/page.tsx
@@ -0,0 +1,27 @@
+import * as React from "react";
+
+import { redirect } from "next/navigation";
+import { cookies } from "next/headers";
+
+import { AuthorizeContainer } from "@/components/core/authorize";
+
+export default async function AuthorizePage({ searchParams }: { searchParams: Promise<{ [key: string]: string | string[] | undefined }> }) {
+ const params = await searchParams;
+
+ const cookieStore = await cookies();
+ const token = cookieStore.get("token");
+ if (!token) {
+ redirect("/");
+ }
+
+ const client_id = params.client_id as string;
+ const redirect_uri = params.redirect_uri as string;
+ const response_type = params.response_type as string || "code";
+ const scope = params.scope as string || "profile email";
+
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/app/globals.css b/app/globals.css
index a2dc41e..ca64022 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -1,26 +1,322 @@
@import "tailwindcss";
+@import "tw-animate-css";
-:root {
- --background: #ffffff;
- --foreground: #171717;
-}
+@custom-variant dark (&:is(.dark *));
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
+ --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-accent-primary: var(--ui-accent-primary);
+ --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);
+ --radius-sm: calc(var(--radius) - 4px);
+ --radius-md: calc(var(--radius) - 2px);
+ --radius-lg: var(--radius);
+ --radius-xl: calc(var(--radius) + 4px);
+ --radius-2xl: calc(var(--radius) + 8px);
+ --radius-3xl: calc(var(--radius) + 12px);
+ --radius-4xl: calc(var(--radius) + 16px);
+
+ /* Text color scale */
+ --color-text-50: var(--text-50);
+ --color-text-100: var(--text-100);
+ --color-text-200: var(--text-200);
+ --color-text-300: var(--text-300);
+ --color-text-400: var(--text-400);
+ --color-text-500: var(--text-500);
+ --color-text-600: var(--text-600);
+ --color-text-700: var(--text-700);
+ --color-text-800: var(--text-800);
+ --color-text-900: var(--text-900);
+ --color-text-950: var(--text-950);
+
+ /* Background color scale */
+ --color-background-50: var(--background-50);
+ --color-background-100: var(--background-100);
+ --color-background-200: var(--background-200);
+ --color-background-300: var(--background-300);
+ --color-background-400: var(--background-400);
+ --color-background-500: var(--background-500);
+ --color-background-600: var(--background-600);
+ --color-background-700: var(--background-700);
+ --color-background-800: var(--background-800);
+ --color-background-900: var(--background-900);
+ --color-background-950: var(--background-950);
+
+ /* Primary color scale */
+ --color-primary-50: var(--primary-50);
+ --color-primary-100: var(--primary-100);
+ --color-primary-200: var(--primary-200);
+ --color-primary-300: var(--primary-300);
+ --color-primary-400: var(--primary-400);
+ --color-primary-500: var(--primary-500);
+ --color-primary-600: var(--primary-600);
+ --color-primary-700: var(--primary-700);
+ --color-primary-800: var(--primary-800);
+ --color-primary-900: var(--primary-900);
+ --color-primary-950: var(--primary-950);
+
+ /* Secondary color scale */
+ --color-secondary-50: var(--secondary-50);
+ --color-secondary-100: var(--secondary-100);
+ --color-secondary-200: var(--secondary-200);
+ --color-secondary-300: var(--secondary-300);
+ --color-secondary-400: var(--secondary-400);
+ --color-secondary-500: var(--secondary-500);
+ --color-secondary-600: var(--secondary-600);
+ --color-secondary-700: var(--secondary-700);
+ --color-secondary-800: var(--secondary-800);
+ --color-secondary-900: var(--secondary-900);
+ --color-secondary-950: var(--secondary-950);
+
+ /* Accent color scale */
+ --color-accent-50: var(--accent-50);
+ --color-accent-100: var(--accent-100);
+ --color-accent-200: var(--accent-200);
+ --color-accent-300: var(--accent-300);
+ --color-accent-400: var(--accent-400);
+ --color-accent-600: var(--accent-600);
+ --color-accent-700: var(--accent-700);
+ --color-accent-800: var(--accent-800);
+ --color-accent-900: var(--accent-900);
+ --color-accent-950: var(--accent-950);
}
-@media (prefers-color-scheme: dark) {
- :root {
- --background: #0a0a0a;
- --foreground: #ededed;
+:root {
+ --radius: 0.625rem;
+ --background: oklch(1 0 0);
+ --foreground: oklch(0.141 0.005 285.823);
+ --card: oklch(1 0 0);
+ --card-foreground: oklch(0.141 0.005 285.823);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.141 0.005 285.823);
+ --primary: oklch(0.21 0.006 285.885);
+ --primary-foreground: oklch(0.985 0 0);
+ --secondary: oklch(0.967 0.001 286.375);
+ --secondary-foreground: oklch(0.21 0.006 285.885);
+ --muted: oklch(0.967 0.001 286.375);
+ --muted-foreground: oklch(0.552 0.016 285.938);
+ --accent: oklch(0.967 0.001 286.375);
+ --accent-foreground: oklch(0.21 0.006 285.885);
+ --destructive: oklch(0.577 0.245 27.325);
+ --border: oklch(0.92 0.004 286.32);
+ --input: oklch(0.92 0.004 286.32);
+ --ring: oklch(0.705 0.015 286.067);
+ --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.141 0.005 285.823);
+ --sidebar-primary: oklch(0.21 0.006 285.885);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.967 0.001 286.375);
+ --sidebar-accent-foreground: oklch(0.21 0.006 285.885);
+ --sidebar-border: oklch(0.92 0.004 286.32);
+ --sidebar-ring: oklch(0.705 0.015 286.067);
+
+ --text-50: oklch(96.12% 0.000 89.88);
+ --text-100: oklch(92.49% 0.000 89.88);
+ --text-200: oklch(84.52% 0.000 89.88);
+ --text-300: oklch(76.68% 0.000 89.88);
+ --text-400: oklch(68.30% 0.000 89.88);
+ --text-500: oklch(59.99% 0.000 89.88);
+ --text-600: oklch(51.03% 0.000 89.88);
+ --text-700: oklch(42.02% 0.000 89.88);
+ --text-800: oklch(32.11% 0.000 89.88);
+ --text-900: oklch(21.78% 0.000 89.88);
+ --text-950: oklch(15.91% 0.000 89.88);
+
+ --background-50: oklch(95.94% 0.007 325.63);
+ --background-100: oklch(92.03% 0.012 325.67);
+ --background-200: oklch(83.83% 0.028 325.82);
+ --background-300: oklch(75.54% 0.041 325.98);
+ --background-400: oklch(67.09% 0.056 326.17);
+ --background-500: oklch(58.40% 0.074 326.48);
+ --background-600: oklch(49.87% 0.060 326.42);
+ --background-700: oklch(40.90% 0.048 326.41);
+ --background-800: oklch(31.40% 0.036 326.39);
+ --background-900: oklch(21.18% 0.017 326.17);
+ --background-950: oklch(15.66% 0.011 326.07);
+
+ --primary-50: oklch(95.93% 0.011 330.15);
+ --primary-100: oklch(91.78% 0.022 325.76);
+ --primary-200: oklch(83.31% 0.047 328.24);
+ --primary-300: oklch(74.91% 0.072 327.84);
+ --primary-400: oklch(66.40% 0.100 328.46);
+ --primary-500: oklch(57.99% 0.124 329.14);
+ --primary-600: oklch(49.48% 0.105 328.96);
+ --primary-700: oklch(40.58% 0.082 328.69);
+ --primary-800: oklch(31.11% 0.059 329.44);
+ --primary-900: oklch(21.00% 0.032 326.64);
+ --primary-950: oklch(15.30% 0.019 326.44);
+
+ --secondary-50: oklch(95.68% 0.017 325.71);
+ --secondary-100: oklch(91.40% 0.034 328.84);
+ --secondary-200: oklch(82.81% 0.070 329.32);
+ --secondary-300: oklch(74.35% 0.107 329.33);
+ --secondary-400: oklch(66.12% 0.144 330.14);
+ --secondary-500: oklch(58.42% 0.178 331.03);
+ --secondary-600: oklch(49.78% 0.149 330.88);
+ --secondary-700: oklch(40.76% 0.118 330.63);
+ --secondary-800: oklch(31.16% 0.085 331.11);
+ --secondary-900: oklch(20.86% 0.048 330.70);
+ --secondary-950: oklch(15.39% 0.025 330.22);
+
+ --accent-50: oklch(95.48% 0.023 327.93);
+ --accent-100: oklch(91.21% 0.045 327.08);
+ --accent-200: oklch(82.54% 0.092 328.20);
+ --accent-300: oklch(74.23% 0.139 328.61);
+ --accent-400: oklch(66.54% 0.184 329.18);
+ --ui-accent-primary: oklch(59.84% 0.220 330.13);
+ --accent-600: oklch(50.93% 0.185 329.84);
+ --accent-700: oklch(41.58% 0.147 329.90);
+ --accent-800: oklch(31.68% 0.106 330.02);
+ --accent-900: oklch(21.06% 0.061 328.92);
+ --accent-950: oklch(15.28% 0.036 329.73);
+}
+
+.dark {
+ --background: oklch(0.141 0.005 285.823);
+ --foreground: oklch(0.985 0 0);
+ --card: oklch(0.21 0.006 285.885);
+ --card-foreground: oklch(0.985 0 0);
+ --popover: oklch(0.21 0.006 285.885);
+ --popover-foreground: oklch(0.985 0 0);
+ --primary: oklch(0.92 0.004 286.32);
+ --primary-foreground: oklch(0.21 0.006 285.885);
+ --secondary: oklch(0.274 0.006 286.033);
+ --secondary-foreground: oklch(0.985 0 0);
+ --muted: oklch(0.274 0.006 286.033);
+ --muted-foreground: oklch(0.705 0.015 286.067);
+ --accent: oklch(0.274 0.006 286.033);
+ --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.552 0.016 285.938);
+ --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.21 0.006 285.885);
+ --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.274 0.006 286.033);
+ --sidebar-accent-foreground: oklch(0.985 0 0);
+ --sidebar-border: oklch(1 0 0 / 10%);
+ --sidebar-ring: oklch(0.552 0.016 285.938);
+
+ --text-50: oklch(96.12% 0.000 89.88);
+ --text-100: oklch(92.49% 0.000 89.88);
+ --text-200: oklch(84.52% 0.000 89.88);
+ --text-300: oklch(76.68% 0.000 89.88);
+ --text-400: oklch(68.30% 0.000 89.88);
+ --text-500: oklch(59.99% 0.000 89.88);
+ --text-600: oklch(51.03% 0.000 89.88);
+ --text-700: oklch(42.02% 0.000 89.88);
+ --text-800: oklch(32.11% 0.000 89.88);
+ --text-900: oklch(21.78% 0.000 89.88);
+ --text-950: oklch(15.91% 0.000 89.88);
+
+ --background-50: oklch(95.94% 0.007 325.63);
+ --background-100: oklch(92.03% 0.012 325.67);
+ --background-200: oklch(83.83% 0.028 325.82);
+ --background-300: oklch(75.54% 0.041 325.98);
+ --background-400: oklch(67.09% 0.056 326.17);
+ --background-500: oklch(58.40% 0.074 326.48);
+ --background-600: oklch(49.87% 0.060 326.42);
+ --background-700: oklch(40.90% 0.048 326.41);
+ --background-800: oklch(31.40% 0.036 326.39);
+ --background-900: oklch(21.18% 0.017 326.17);
+ --background-950: oklch(15.66% 0.011 326.07);
+
+ --primary-50: oklch(95.93% 0.011 330.15);
+ --primary-100: oklch(91.78% 0.022 325.76);
+ --primary-200: oklch(83.31% 0.047 328.24);
+ --primary-300: oklch(74.91% 0.072 327.84);
+ --primary-400: oklch(66.40% 0.100 328.46);
+ --primary-500: oklch(57.99% 0.124 329.14);
+ --primary-600: oklch(49.48% 0.105 328.96);
+ --primary-700: oklch(40.58% 0.082 328.69);
+ --primary-800: oklch(31.11% 0.059 329.44);
+ --primary-900: oklch(21.00% 0.032 326.64);
+ --primary-950: oklch(15.30% 0.019 326.44);
+
+ --secondary-50: oklch(95.68% 0.017 325.71);
+ --secondary-100: oklch(91.40% 0.034 328.84);
+ --secondary-200: oklch(82.81% 0.070 329.32);
+ --secondary-300: oklch(74.35% 0.107 329.33);
+ --secondary-400: oklch(66.12% 0.144 330.14);
+ --ui-secondary: oklch(58.42% 0.178 331.03);
+ --secondary-600: oklch(49.78% 0.149 330.88);
+ --secondary-700: oklch(40.76% 0.118 330.63);
+ --secondary-800: oklch(31.16% 0.085 331.11);
+ --secondary-900: oklch(20.86% 0.048 330.70);
+ --secondary-950: oklch(15.39% 0.025 330.22);
+
+ --accent-50: oklch(95.48% 0.023 327.93);
+ --accent-100: oklch(91.21% 0.045 327.08);
+ --accent-200: oklch(82.54% 0.092 328.20);
+ --accent-300: oklch(74.23% 0.139 328.61);
+ --accent-400: oklch(66.54% 0.184 329.18);
+ --ui-accent-primary: oklch(59.84% 0.220 330.13);
+ --accent-600: oklch(50.93% 0.185 329.84);
+ --accent-700: oklch(41.58% 0.147 329.90);
+ --accent-800: oklch(31.68% 0.106 330.02);
+ --accent-900: oklch(21.06% 0.061 328.92);
+ --accent-950: oklch(15.28% 0.036 329.73);
+}
+
+@layer base {
+ * {
+ @apply border-border outline-ring/50;
+ }
+ body {
+ @apply bg-background text-foreground;
}
}
-body {
- background: var(--background);
- color: var(--foreground);
- font-family: Arial, Helvetica, sans-serif;
+@layer utilities {
+ .text-ui-accent-primary {
+ color: var(--ui-accent-primary);
+ }
+ .text-ui-secondary {
+ color: var(--ui-secondary);
+ }
+ .border-ui-secondary {
+ border-color: var(--ui-secondary);
+ }
}
diff --git a/app/layout.tsx b/app/layout.tsx
index f7fa87e..cf34e3f 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -2,6 +2,10 @@ import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
+import { NuqsAdapter } from "nuqs/adapters/next/app";
+
+import { Toaster } from "@/components/ui/sonner";
+
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
@@ -13,8 +17,8 @@ const geistMono = Geist_Mono({
});
export const metadata: Metadata = {
- title: "Create Next App",
- description: "Generated by create next app",
+ title: "SecNex",
+ description: "Secured by SecNex",
};
export default function RootLayout({
@@ -27,7 +31,10 @@ export default function RootLayout({
- {children}
+
+ {children}
+
+