make everything pretty & try to fix authentik
This commit is contained in:
parent
7d637b7401
commit
ed4d51400c
5
.prettierrc
Normal file
5
.prettierrc
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"singleQuote": true,
|
||||||
|
"jsxSingleQuote": true,
|
||||||
|
"trailingComma": "all"
|
||||||
|
}
|
@ -1,12 +1,12 @@
|
|||||||
import { type Config } from "drizzle-kit";
|
import { type Config } from 'drizzle-kit';
|
||||||
|
|
||||||
import { env } from "~/env";
|
import { env } from '~/env';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
schema: "./src/server/db/schema.ts",
|
schema: './src/server/db/schema.ts',
|
||||||
dialect: "mysql",
|
dialect: 'mysql',
|
||||||
dbCredentials: {
|
dbCredentials: {
|
||||||
url: env.DATABASE_URL,
|
url: env.DATABASE_URL,
|
||||||
},
|
},
|
||||||
tablesFilter: ["tech_tracker_web_*"],
|
tablesFilter: ['tech_tracker_web_*'],
|
||||||
} satisfies Config;
|
} satisfies Config;
|
||||||
|
16
env.example
16
env.example
@ -1,16 +0,0 @@
|
|||||||
# When adding additional environment variables, the schema in "/src/env.js"
|
|
||||||
# should be updated accordingly.
|
|
||||||
|
|
||||||
# Drizzle
|
|
||||||
DATABASE_URL=""
|
|
||||||
|
|
||||||
# API Key
|
|
||||||
API_KEY=""
|
|
||||||
|
|
||||||
# Auth.js
|
|
||||||
#NEXTAUTH_SECRET=""
|
|
||||||
AUTH_SECRET=""
|
|
||||||
# Entra - https://authjs.dev/getting-started/providers/microsoft-entra-id
|
|
||||||
AUTH_MICROSOFT_ENTRA_ID_ID=""
|
|
||||||
AUTH_MICROSOFT_ENTRA_ID_SECRET=""
|
|
||||||
AUTH_MICROSOFT_ENTRA_ID_TENANT_ID=""
|
|
@ -47,4 +47,3 @@ export default config;
|
|||||||
//};
|
//};
|
||||||
|
|
||||||
//export default config;
|
//export default config;
|
||||||
|
|
||||||
|
80
package.json
80
package.json
@ -12,66 +12,66 @@
|
|||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"godev": "git pull && next dev",
|
"format:write": "prettier --write \"**/*.{ts,tsx,js,jsx,mdx}\" --cache",
|
||||||
"go": "next build && next start"
|
"format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,mdx}\" --cache"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^3.9.0",
|
"@hookform/resolvers": "^3.10.0",
|
||||||
"@radix-ui/react-checkbox": "^1.1.1",
|
"@radix-ui/react-checkbox": "^1.1.3",
|
||||||
"@radix-ui/react-dialog": "^1.1.1",
|
"@radix-ui/react-dialog": "^1.1.4",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
"@radix-ui/react-dropdown-menu": "^2.1.4",
|
||||||
"@radix-ui/react-label": "^2.1.0",
|
"@radix-ui/react-label": "^2.1.1",
|
||||||
"@radix-ui/react-popover": "^1.1.1",
|
"@radix-ui/react-popover": "^1.1.4",
|
||||||
"@radix-ui/react-progress": "^1.1.0",
|
"@radix-ui/react-progress": "^1.1.1",
|
||||||
"@radix-ui/react-radio-group": "^1.2.0",
|
"@radix-ui/react-radio-group": "^1.2.2",
|
||||||
"@radix-ui/react-scroll-area": "^1.1.0",
|
"@radix-ui/react-scroll-area": "^1.2.2",
|
||||||
"@radix-ui/react-select": "^2.1.1",
|
"@radix-ui/react-select": "^2.1.4",
|
||||||
"@radix-ui/react-slot": "^1.1.0",
|
"@radix-ui/react-slot": "^1.1.1",
|
||||||
"@radix-ui/react-switch": "^1.1.0",
|
"@radix-ui/react-switch": "^1.1.2",
|
||||||
"@radix-ui/react-toggle": "^1.1.0",
|
"@radix-ui/react-toggle": "^1.1.1",
|
||||||
"@radix-ui/react-toggle-group": "^1.1.0",
|
"@radix-ui/react-toggle-group": "^1.1.1",
|
||||||
"@radix-ui/react-tooltip": "^1.1.2",
|
"@radix-ui/react-tooltip": "^1.1.6",
|
||||||
"@t3-oss/env-nextjs": "^0.10.1",
|
"@t3-oss/env-nextjs": "^0.10.1",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.0.0",
|
"cmdk": "^1.0.4",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
"drizzle-orm": "^0.30.10",
|
"drizzle-orm": "^0.30.10",
|
||||||
"geist": "^1.3.1",
|
"geist": "^1.3.1",
|
||||||
"lucide-react": "^0.411.0",
|
"lucide-react": "^0.411.0",
|
||||||
"mysql2": "^3.11.0",
|
"mysql2": "^3.12.0",
|
||||||
"next": "^14.2.5",
|
"next": "^14.2.23",
|
||||||
"next-auth": "5.0.0-beta.19",
|
"next-auth": "5.0.0-beta.19",
|
||||||
"next-themes": "^0.3.0",
|
"next-themes": "^0.3.0",
|
||||||
"pm2": "^5.4.2",
|
"pm2": "^5.4.3",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-day-picker": "^9.0.6",
|
"react-day-picker": "^9.5.0",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-hook-form": "^7.52.1",
|
"react-hook-form": "^7.54.2",
|
||||||
"server-only": "^0.0.1",
|
"server-only": "^0.0.1",
|
||||||
"sharp": "^0.33.4",
|
"sharp": "^0.33.5",
|
||||||
"sonner": "^1.5.0",
|
"sonner": "^1.7.2",
|
||||||
"tailwind-merge": "^2.4.0",
|
"tailwind-merge": "^2.6.0",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"vaul": "^0.9.1",
|
"vaul": "^0.9.9",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.24.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/eslint": "^8.56.11",
|
"@types/eslint": "^8.56.12",
|
||||||
"@types/node": "^20.14.13",
|
"@types/node": "^20.17.14",
|
||||||
"@types/react": "^18.3.3",
|
"@types/react": "^18.3.18",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.5",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||||
"@typescript-eslint/parser": "^7.18.0",
|
"@typescript-eslint/parser": "^7.18.0",
|
||||||
"drizzle-kit": "^0.21.4",
|
"drizzle-kit": "^0.21.4",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.1",
|
||||||
"eslint-config-next": "^14.2.5",
|
"eslint-config-next": "^14.2.23",
|
||||||
"eslint-plugin-drizzle": "^0.2.3",
|
"eslint-plugin-drizzle": "^0.2.3",
|
||||||
"postcss": "^8.4.40",
|
"postcss": "^8.5.1",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.4.2",
|
||||||
"prettier-plugin-tailwindcss": "^0.6.5",
|
"prettier-plugin-tailwindcss": "^0.6.10",
|
||||||
"tailwindcss": "^3.4.7",
|
"tailwindcss": "^3.4.17",
|
||||||
"typescript": "^5.5.4"
|
"typescript": "^5.7.3"
|
||||||
},
|
},
|
||||||
"ct3aMetadata": {
|
"ct3aMetadata": {
|
||||||
"initVersion": "7.36.1"
|
"initVersion": "7.36.1"
|
||||||
|
3802
pnpm-lock.yaml
generated
3802
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
/** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').PluginOptions} */
|
/** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').PluginOptions} */
|
||||||
const config = {
|
const config = {
|
||||||
plugins: ["prettier-plugin-tailwindcss"],
|
plugins: ['prettier-plugin-tailwindcss'],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
@ -47,4 +47,3 @@ export default config;
|
|||||||
//};
|
//};
|
||||||
|
|
||||||
//export default config;
|
//export default config;
|
||||||
|
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
import { handlers } from "~/auth"
|
import { handlers } from '~/auth';
|
||||||
export const { GET, POST } = handlers
|
export const { GET, POST } = handlers;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
"use server";
|
'use server';
|
||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from 'next/server';
|
||||||
import { get_history } from '~/server/functions';
|
import { get_history } from '~/server/functions';
|
||||||
import { auth } from '~/auth';
|
import { auth } from '~/auth';
|
||||||
@ -13,10 +13,7 @@ export const GET = async (request: Request) => {
|
|||||||
if (apiKey !== process.env.API_KEY) {
|
if (apiKey !== process.env.API_KEY) {
|
||||||
const session = await auth();
|
const session = await auth();
|
||||||
if (!session)
|
if (!session)
|
||||||
return NextResponse.json(
|
return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });
|
||||||
{ message: 'Unauthorized' },
|
|
||||||
{ status: 401 }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
const historyData = await get_history(userId, page, perPage);
|
const historyData = await get_history(userId, page, perPage);
|
||||||
return NextResponse.json(historyData, { status: 200 });
|
return NextResponse.json(historyData, { status: 200 });
|
||||||
@ -24,7 +21,7 @@ export const GET = async (request: Request) => {
|
|||||||
console.error('Error fetching history data:', error);
|
console.error('Error fetching history data:', error);
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ message: 'Internal server error' },
|
{ message: 'Internal server error' },
|
||||||
{ status: 500 }
|
{ status: 500 },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
"use server";
|
'use server';
|
||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from 'next/server';
|
||||||
import { getEmployees } from '~/server/functions';
|
import { getEmployees } from '~/server/functions';
|
||||||
import { auth } from '~/auth';
|
import { auth } from '~/auth';
|
||||||
@ -10,10 +10,7 @@ export const GET = async (request: Request) => {
|
|||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
const apiKey = url.searchParams.get('apikey');
|
const apiKey = url.searchParams.get('apikey');
|
||||||
if (apiKey !== process.env.API_KEY)
|
if (apiKey !== process.env.API_KEY)
|
||||||
return NextResponse.json(
|
return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });
|
||||||
{ message: 'Unauthorized' },
|
|
||||||
{ status: 401 }
|
|
||||||
);
|
|
||||||
else {
|
else {
|
||||||
const employees = await getEmployees();
|
const employees = await getEmployees();
|
||||||
return NextResponse.json(employees, { status: 200 });
|
return NextResponse.json(employees, { status: 200 });
|
||||||
@ -26,7 +23,7 @@ export const GET = async (request: Request) => {
|
|||||||
console.error('Error fetching employees:', error);
|
console.error('Error fetching employees:', error);
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ message: 'Internal server error' },
|
{ message: 'Internal server error' },
|
||||||
{ status: 500 }
|
{ status: 500 },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Update Employee Status by IDs
|
// Update Employee Status by IDs
|
||||||
"use server";
|
'use server';
|
||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from 'next/server';
|
||||||
import type { NextRequest } from 'next/server';
|
import type { NextRequest } from 'next/server';
|
||||||
import { updateEmployeeStatus } from '~/server/functions';
|
import { updateEmployeeStatus } from '~/server/functions';
|
||||||
@ -16,28 +16,22 @@ export const POST = async (req: NextRequest) => {
|
|||||||
const url = new URL(req.url);
|
const url = new URL(req.url);
|
||||||
const apiKey = url.searchParams.get('apikey');
|
const apiKey = url.searchParams.get('apikey');
|
||||||
if (apiKey !== process.env.API_KEY)
|
if (apiKey !== process.env.API_KEY)
|
||||||
return NextResponse.json(
|
return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });
|
||||||
{ message: 'Unauthorized' },
|
|
||||||
{ status: 401 }
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
const { employeeIds, newStatus } = await req.json() as UpdateStatusBody;
|
const { employeeIds, newStatus } = (await req.json()) as UpdateStatusBody;
|
||||||
if (!Array.isArray(employeeIds) || typeof newStatus !== 'string')
|
if (!Array.isArray(employeeIds) || typeof newStatus !== 'string')
|
||||||
return NextResponse.json(
|
return NextResponse.json({ message: 'Invalid input' }, { status: 400 });
|
||||||
{ message: 'Invalid input' },
|
|
||||||
{ status: 400 }
|
|
||||||
);
|
|
||||||
try {
|
try {
|
||||||
await updateEmployeeStatus(employeeIds, newStatus);
|
await updateEmployeeStatus(employeeIds, newStatus);
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ message: 'Status updated successfully' },
|
{ message: 'Status updated successfully' },
|
||||||
{ status: 200 }
|
{ status: 200 },
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error updating status:', error);
|
console.error('Error updating status:', error);
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ message: 'Internal server error' },
|
{ message: 'Internal server error' },
|
||||||
{ status: 500 }
|
{ status: 500 },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,22 @@
|
|||||||
// Update Employee Status by Names
|
// Update Employee Status by Names
|
||||||
"use server";
|
'use server';
|
||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from 'next/server';
|
||||||
import { updateEmployeeStatusByName } from '~/server/functions';
|
import { updateEmployeeStatusByName } from '~/server/functions';
|
||||||
|
|
||||||
type Technician = {
|
type Technician = {
|
||||||
name: string;
|
name: string;
|
||||||
status: string;
|
status: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Type guard to check if an object is a Technician
|
// Type guard to check if an object is a Technician
|
||||||
const isTechnician = (technician: unknown): technician is Technician => {
|
const isTechnician = (technician: unknown): technician is Technician => {
|
||||||
if (typeof technician !== 'object' || technician === null) return false;
|
if (typeof technician !== 'object' || technician === null) return false;
|
||||||
return 'name' in technician &&
|
return (
|
||||||
|
'name' in technician &&
|
||||||
typeof (technician as Technician).name === 'string' &&
|
typeof (technician as Technician).name === 'string' &&
|
||||||
'status' in technician &&
|
'status' in technician &&
|
||||||
typeof (technician as Technician).status === 'string';
|
typeof (technician as Technician).status === 'string'
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const POST = async (request: Request) => {
|
export const POST = async (request: Request) => {
|
||||||
@ -25,28 +27,31 @@ export const POST = async (request: Request) => {
|
|||||||
return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });
|
return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });
|
||||||
const body: unknown = await request.json();
|
const body: unknown = await request.json();
|
||||||
// Validate the body and its technicians property
|
// Validate the body and its technicians property
|
||||||
if (typeof body !== 'object' || body === null ||
|
if (
|
||||||
!Array.isArray((body as { technicians?: unknown[] }).technicians))
|
typeof body !== 'object' ||
|
||||||
|
body === null ||
|
||||||
|
!Array.isArray((body as { technicians?: unknown[] }).technicians)
|
||||||
|
)
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ message: 'Invalid input: expecting an array of technicians.' },
|
{ message: 'Invalid input: expecting an array of technicians.' },
|
||||||
{ status: 400 }
|
{ status: 400 },
|
||||||
);
|
);
|
||||||
const technicians = (body as { technicians: unknown[] }).technicians;
|
const technicians = (body as { technicians: unknown[] }).technicians;
|
||||||
if (!technicians.every(isTechnician))
|
if (!technicians.every(isTechnician))
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ message: 'Invalid input: missing name or status for a technician.' },
|
{ message: 'Invalid input: missing name or status for a technician.' },
|
||||||
{ status: 400 }
|
{ status: 400 },
|
||||||
);
|
);
|
||||||
await updateEmployeeStatusByName(technicians);
|
await updateEmployeeStatusByName(technicians);
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ message: 'Technicians updated successfully.' },
|
{ message: 'Technicians updated successfully.' },
|
||||||
{ status: 200 }
|
{ status: 200 },
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error updating technicians:', error);
|
console.error('Error updating technicians:', error);
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ message: 'Internal server error' },
|
{ message: 'Internal server error' },
|
||||||
{ status: 500 }
|
{ status: 500 },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
import "~/styles/globals.css";
|
import '~/styles/globals.css';
|
||||||
import { Inter as FontSans } from "next/font/google";
|
import { Inter as FontSans } from 'next/font/google';
|
||||||
import { cn } from "~/lib/utils";
|
import { cn } from '~/lib/utils';
|
||||||
import { SessionProvider } from "next-auth/react";
|
import { SessionProvider } from 'next-auth/react';
|
||||||
import { TVModeProvider } from "~/components/context/TVModeContext";
|
import { TVModeProvider } from '~/components/context/TVModeContext';
|
||||||
|
|
||||||
import { type Metadata } from "next";
|
import { type Metadata } from 'next';
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Tech Tracker",
|
title: 'Tech Tracker',
|
||||||
description: "App used by COG IT employees to \
|
description:
|
||||||
update their status throughout the day.",
|
'App used by COG IT employees to \
|
||||||
|
update their status throughout the day.',
|
||||||
icons: [
|
icons: [
|
||||||
{
|
{
|
||||||
rel: 'icon',
|
rel: 'icon',
|
||||||
@ -28,24 +29,23 @@ export const metadata: Metadata = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fontSans = FontSans({
|
const fontSans = FontSans({
|
||||||
subsets: ["latin"],
|
subsets: ['latin'],
|
||||||
variable: "--font-sans",
|
variable: '--font-sans',
|
||||||
});
|
});
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
children,
|
children,
|
||||||
}: Readonly<{ children: React.ReactNode }>) {
|
}: Readonly<{ children: React.ReactNode }>) {
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang='en'>
|
||||||
<body
|
<body
|
||||||
className={cn(
|
className={cn(
|
||||||
"min-h-screen bg-background font-sans antialiased",
|
'min-h-screen bg-background font-sans antialiased',
|
||||||
fontSans.variable)}
|
fontSans.variable,
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<SessionProvider>
|
<SessionProvider>
|
||||||
<TVModeProvider>
|
<TVModeProvider>{children}</TVModeProvider>
|
||||||
{children}
|
|
||||||
</TVModeProvider>
|
|
||||||
</SessionProvider>
|
</SessionProvider>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,19 +1,21 @@
|
|||||||
"use server";
|
'use server';
|
||||||
import { auth } from "~/auth";
|
import { auth } from '~/auth';
|
||||||
import No_Session from "~/components/ui/No_Session";
|
import No_Session from '~/components/ui/No_Session';
|
||||||
import Header from "~/components/ui/Header";
|
import Header from '~/components/ui/Header';
|
||||||
import { getEmployees } from "~/server/functions";
|
import { getEmployees } from '~/server/functions';
|
||||||
import Tech_Table from "~/components/ui/Tech_Table";
|
import Tech_Table from '~/components/ui/Tech_Table';
|
||||||
|
|
||||||
export default async function HomePage() {
|
export default async function HomePage() {
|
||||||
const session = await auth();
|
const session = await auth();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
return <No_Session />
|
return <No_Session />;
|
||||||
} else {
|
} else {
|
||||||
const employees = await getEmployees();
|
const employees = await getEmployees();
|
||||||
return (
|
return (
|
||||||
<main className="min-h-screen
|
<main
|
||||||
bg-gradient-to-b from-[#111111] to-[#212325]">
|
className='min-h-screen
|
||||||
|
bg-gradient-to-b from-[#111111] to-[#212325]'
|
||||||
|
>
|
||||||
<Header />
|
<Header />
|
||||||
<Tech_Table employees={employees} />
|
<Tech_Table employees={employees} />
|
||||||
</main>
|
</main>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import NextAuth from "next-auth"
|
import NextAuth from 'next-auth';
|
||||||
import Entra from "next-auth/providers/microsoft-entra-id"
|
import Entra from 'next-auth/providers/microsoft-entra-id';
|
||||||
import Authentik from "next-auth/providers/authentik"
|
import Authentik from 'next-auth/providers/authentik';
|
||||||
|
|
||||||
export const { handlers, auth, signIn, signOut } = NextAuth({
|
export const { handlers, auth, signIn, signOut } = NextAuth({
|
||||||
providers: [
|
providers: [
|
||||||
@ -15,4 +15,4 @@ export const { handlers, auth, signIn, signOut } = NextAuth({
|
|||||||
issuer: process.env.AUTH_AUTHENTIK_ISSUER,
|
issuer: process.env.AUTH_AUTHENTIK_ISSUER,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
})
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { signOut } from "next-auth/react";
|
import { signOut } from 'next-auth/react';
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from 'next-auth/react';
|
||||||
import Image from "next/image";
|
import Image from 'next/image';
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
@ -8,33 +8,35 @@ import {
|
|||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "~/components/ui/shadcn/dropdown-menu";
|
} from '~/components/ui/shadcn/dropdown-menu';
|
||||||
|
|
||||||
export default function Sign_Out() {
|
export default function Sign_Out() {
|
||||||
const { data: session } = useSession();
|
const { data: session } = useSession();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
return <div />;
|
return <div />;
|
||||||
} else {
|
} else {
|
||||||
const pfp = session?.user?.image ? session.user.image : "/images/default_user_pfp.png";
|
const pfp = session?.user?.image
|
||||||
const name = session?.user?.name ? session.user.name : "Profile";
|
? session.user.image
|
||||||
|
: '/images/default_user_pfp.png';
|
||||||
|
const name = session?.user?.name ? session.user.name : 'Profile';
|
||||||
return (
|
return (
|
||||||
<div className="m-auto mt-1">
|
<div className='m-auto mt-1'>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger>
|
<DropdownMenuTrigger>
|
||||||
<Image src={pfp} alt="" width={35} height={35}
|
<Image
|
||||||
className="rounded-full border-2 border-white m-auto mr-1 md:mr-2
|
src={pfp}
|
||||||
max-w-[25px] md:max-w-[35px]"
|
alt=''
|
||||||
|
width={35}
|
||||||
|
height={35}
|
||||||
|
className='rounded-full border-2 border-white m-auto mr-1 md:mr-2
|
||||||
|
max-w-[25px] md:max-w-[35px]'
|
||||||
/>
|
/>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent>
|
<DropdownMenuContent>
|
||||||
<DropdownMenuLabel>
|
<DropdownMenuLabel>{name}</DropdownMenuLabel>
|
||||||
{name}
|
|
||||||
</DropdownMenuLabel>
|
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem>
|
<DropdownMenuItem>
|
||||||
<button onClick={() => signOut()}
|
<button onClick={() => signOut()} className='w-full'>
|
||||||
className="w-full"
|
|
||||||
>
|
|
||||||
Sign Out
|
Sign Out
|
||||||
</button>
|
</button>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
@ -43,4 +45,4 @@ export default function Sign_Out() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import { signIn } from "next-auth/react";
|
import { signIn } from 'next-auth/react';
|
||||||
import { Button } from "~/components/ui/shadcn/button";
|
import { Button } from '~/components/ui/shadcn/button';
|
||||||
|
|
||||||
export default function Sign_In_Authentik() {
|
export default function Sign_In_Authentik() {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => signIn('authentik')}
|
onClick={() => signIn('authentik')}
|
||||||
className="bg-gradient-to-tl from-[#35363F] to=[#24191A] rounded-xl
|
className='bg-gradient-to-tl from-[#35363F] to=[#24191A] rounded-xl
|
||||||
px-4 py-2 md:py-2.5 font-semibold text-white hover:bg-gradient-to-tr
|
px-4 py-2 md:py-2.5 font-semibold text-white hover:bg-gradient-to-tr
|
||||||
hover:from-[#35363F] hover:to-[#23242F]"
|
hover:from-[#35363F] hover:to-[#23242F]'
|
||||||
>
|
>
|
||||||
<h1 className="md:text-2xl my-auto font-semibold">Sign In</h1>
|
<h1 className='md:text-2xl my-auto font-semibold'>Sign In</h1>
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import { signIn } from "next-auth/react";
|
import { signIn } from 'next-auth/react';
|
||||||
import { Button } from "~/components/ui/shadcn/button";
|
import { Button } from '~/components/ui/shadcn/button';
|
||||||
|
|
||||||
export default function Sign_In_Microsoft() {
|
export default function Sign_In_Microsoft() {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => signIn('microsoft-entra-id')}
|
onClick={() => signIn('microsoft-entra-id')}
|
||||||
className="bg-gradient-to-tl from-[#35363F] to=[#24191A] rounded-xl
|
className='bg-gradient-to-tl from-[#35363F] to=[#24191A] rounded-xl
|
||||||
px-4 py-2 md:py-2.5 font-semibold text-white hover:bg-gradient-to-tr
|
px-4 py-2 md:py-2.5 font-semibold text-white hover:bg-gradient-to-tr
|
||||||
hover:from-[#35363F] hover:to-[#23242F]"
|
hover:from-[#35363F] hover:to-[#23242F]'
|
||||||
>
|
>
|
||||||
<h1 className="md:text-2xl my-auto font-semibold">Sign In</h1>
|
<h1 className='md:text-2xl my-auto font-semibold'>Sign In</h1>
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
@ -1,31 +1,41 @@
|
|||||||
import Image from "next/image";
|
import Image from 'next/image';
|
||||||
import { auth } from "~/auth"
|
import { auth } from '~/auth';
|
||||||
import { signOut } from "~/auth"
|
import { signOut } from '~/auth';
|
||||||
|
|
||||||
export default async function Sign_Out() {
|
export default async function Sign_Out() {
|
||||||
const session = await auth();
|
const session = await auth();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
return (<div/>);
|
return <div />;
|
||||||
} else {
|
} else {
|
||||||
// Add User profile picture next to Sign Out button
|
// Add User profile picture next to Sign Out button
|
||||||
const pfp = session?.user?.image ? session.user.image : "/images/default_user_pfp.png";
|
const pfp = session?.user?.image
|
||||||
|
? session.user.image
|
||||||
|
: '/images/default_user_pfp.png';
|
||||||
return (
|
return (
|
||||||
<form className="flex flex-row"
|
<form
|
||||||
|
className='flex flex-row'
|
||||||
action={async () => {
|
action={async () => {
|
||||||
"use server"
|
'use server';
|
||||||
await signOut()
|
await signOut();
|
||||||
}}>
|
}}
|
||||||
<Image src={pfp} alt="" width={35} height={35}
|
>
|
||||||
className="rounded-full border-2 border-white m-auto mr-1 md:mr-2
|
<Image
|
||||||
max-w-[25px] md:max-w-[35px]"
|
src={pfp}
|
||||||
|
alt=''
|
||||||
|
width={35}
|
||||||
|
height={35}
|
||||||
|
className='rounded-full border-2 border-white m-auto mr-1 md:mr-2
|
||||||
|
max-w-[25px] md:max-w-[35px]'
|
||||||
/>
|
/>
|
||||||
<button type="submit" className="w-full p-2 rounded-xl text-sm md:text-lg
|
<button
|
||||||
|
type='submit'
|
||||||
|
className='w-full p-2 rounded-xl text-sm md:text-lg
|
||||||
bg-gradient-to-tl from-[#35363F] to=[#24191A]
|
bg-gradient-to-tl from-[#35363F] to=[#24191A]
|
||||||
hover:bg-gradient-to-tr hover:from-[#35363F] hover:to-[#23242F]"
|
hover:bg-gradient-to-tr hover:from-[#35363F] hover:to-[#23242F]'
|
||||||
>
|
>
|
||||||
Sign Out
|
Sign Out
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
@ -1,21 +1,33 @@
|
|||||||
import Image from "next/image";
|
import Image from 'next/image';
|
||||||
import { signIn } from "~/auth";
|
import { signIn } from '~/auth';
|
||||||
|
|
||||||
export default async function Sign_In_Authentik() {
|
const Sign_In_Authentik = () => {
|
||||||
return (
|
return (
|
||||||
<form className="items-center justify-center mx-auto"
|
<form
|
||||||
|
className='items-center justify-center mx-auto'
|
||||||
action={async () => {
|
action={async () => {
|
||||||
"use server";
|
'use server';
|
||||||
await signIn("authentik");
|
await signIn('authentik');
|
||||||
}}>
|
}}
|
||||||
<button type="submit" className="flex flex-row mx-auto
|
>
|
||||||
|
<button
|
||||||
|
type='submit'
|
||||||
|
className='flex flex-row mx-auto
|
||||||
bg-gradient-to-tl from-[#35363F] to=[#24191A] rounded-xl px-4 py-2 md:py-2.5
|
bg-gradient-to-tl from-[#35363F] to=[#24191A] rounded-xl px-4 py-2 md:py-2.5
|
||||||
font-semibold text-white hover:bg-gradient-to-tr hover:from-[#35363F] hover:to-[#23242F]">
|
font-semibold text-white hover:bg-gradient-to-tr hover:from-[#35363F] hover:to-[#23242F]'
|
||||||
<Image src="/images/microsoft_logo.png" alt="Microsoft" width={35} height={35}
|
>
|
||||||
className="mr-2"
|
<Image
|
||||||
|
src='/images/microsoft_logo.png'
|
||||||
|
alt='Microsoft'
|
||||||
|
width={35}
|
||||||
|
height={35}
|
||||||
|
className='mr-2'
|
||||||
/>
|
/>
|
||||||
<h1 className="md:text-2xl my-auto font-semibold">Sign In with Authentik</h1>
|
<h1 className='md:text-2xl my-auto font-semibold'>
|
||||||
|
Sign In with Authentik
|
||||||
|
</h1>
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
export default Sign_In_Authentik;
|
||||||
|
@ -1,20 +1,29 @@
|
|||||||
import Image from "next/image";
|
import Image from 'next/image';
|
||||||
import { signIn } from "~/auth";
|
import { signIn } from '~/auth';
|
||||||
|
|
||||||
export default async function Sign_In_Microsoft() {
|
export default async function Sign_In_Microsoft() {
|
||||||
return (
|
return (
|
||||||
<form className="items-center justify-center mx-auto"
|
<form
|
||||||
|
className='items-center justify-center mx-auto'
|
||||||
action={async () => {
|
action={async () => {
|
||||||
"use server";
|
'use server';
|
||||||
await signIn("microsoft-entra-id");
|
await signIn('microsoft-entra-id');
|
||||||
}}>
|
}}
|
||||||
<button type="submit" className="flex flex-row mx-auto
|
>
|
||||||
|
<button
|
||||||
|
type='submit'
|
||||||
|
className='flex flex-row mx-auto
|
||||||
bg-gradient-to-tl from-[#35363F] to=[#24191A] rounded-xl px-4 py-2 md:py-2.5
|
bg-gradient-to-tl from-[#35363F] to=[#24191A] rounded-xl px-4 py-2 md:py-2.5
|
||||||
font-semibold text-white hover:bg-gradient-to-tr hover:from-[#35363F] hover:to-[#23242F]">
|
font-semibold text-white hover:bg-gradient-to-tr hover:from-[#35363F] hover:to-[#23242F]'
|
||||||
<Image src="/images/microsoft_logo.png" alt="Microsoft" width={35} height={35}
|
>
|
||||||
className="mr-2"
|
<Image
|
||||||
|
src='/images/microsoft_logo.png'
|
||||||
|
alt='Microsoft'
|
||||||
|
width={35}
|
||||||
|
height={35}
|
||||||
|
className='mr-2'
|
||||||
/>
|
/>
|
||||||
<h1 className="md:text-2xl my-auto font-semibold">Sign In</h1>
|
<h1 className='md:text-2xl my-auto font-semibold'>Sign In</h1>
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
"use client";
|
'use client';
|
||||||
import React, { createContext, useContext, useState } from 'react';
|
import React, { createContext, useContext, useState } from 'react';
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
|
|
||||||
|
@ -1,41 +1,48 @@
|
|||||||
"use client";
|
'use client';
|
||||||
import Image from "next/image";
|
import Image from 'next/image';
|
||||||
import Sign_Out from "~/components/auth/client/Sign_Out";
|
import Sign_Out from '~/components/auth/client/Sign_Out';
|
||||||
import TV_Toggle from "~/components/ui/TV_Toggle";
|
import TV_Toggle from '~/components/ui/TV_Toggle';
|
||||||
import { useTVMode } from "~/components/context/TVModeContext";
|
import { useTVMode } from '~/components/context/TVModeContext';
|
||||||
|
|
||||||
export default function Header() {
|
export default function Header() {
|
||||||
const { tvMode } = useTVMode();
|
const { tvMode } = useTVMode();
|
||||||
if (tvMode) {
|
if (tvMode) {
|
||||||
return (
|
return (
|
||||||
<div className="absolute top-4 right-2">
|
<div className='absolute top-4 right-2'>
|
||||||
<div className="flex flex-row my-auto items-center pt-2 pr-0 md:pt-4">
|
<div className='flex flex-row my-auto items-center pt-2 pr-0 md:pt-4'>
|
||||||
<TV_Toggle />
|
<TV_Toggle />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<header className="w-full py-2 pt-6 md:py-5">
|
<header className='w-full py-2 pt-6 md:py-5'>
|
||||||
<div className="absolute top-4 right-6">
|
<div className='absolute top-4 right-6'>
|
||||||
<div className="flex flex-row my-auto items-center pt-2 pr-0 md:pt-4 md:pr-8">
|
<div className='flex flex-row my-auto items-center pt-2 pr-0 md:pt-4 md:pr-8'>
|
||||||
<TV_Toggle />
|
<TV_Toggle />
|
||||||
<Sign_Out />
|
<Sign_Out />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row items-center text-center
|
<div
|
||||||
sm:justify-center ml-4 sm:ml-0 p-4">
|
className='flex flex-row items-center text-center
|
||||||
<Image src="/images/tech_tracker_logo.png"
|
sm:justify-center ml-4 sm:ml-0 p-4'
|
||||||
alt="Tech Tracker Logo" width={100} height={100}
|
>
|
||||||
className="max-w-[40px] md:max-w-[120px]"
|
<Image
|
||||||
|
src='/images/tech_tracker_logo.png'
|
||||||
|
alt='Tech Tracker Logo'
|
||||||
|
width={100}
|
||||||
|
height={100}
|
||||||
|
className='max-w-[40px] md:max-w-[120px]'
|
||||||
/>
|
/>
|
||||||
<h1 className="title-text text-sm md:text-4xl lg:text-8xl
|
<h1
|
||||||
|
className='title-text text-sm md:text-4xl lg:text-8xl
|
||||||
bg-gradient-to-r from-[#bec8e6] via-[#F0EEE4] to-[#FFF8E7]
|
bg-gradient-to-r from-[#bec8e6] via-[#F0EEE4] to-[#FFF8E7]
|
||||||
font-bold pl-2 md:pl-12 text-transparent bg-clip-text">
|
font-bold pl-2 md:pl-12 text-transparent bg-clip-text'
|
||||||
|
>
|
||||||
Tech Tracker
|
Tech Tracker
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from 'react';
|
||||||
import Image from "next/image";
|
import Image from 'next/image';
|
||||||
import { ScrollArea } from "~/components/ui/shadcn/scroll-area";
|
import { ScrollArea } from '~/components/ui/shadcn/scroll-area';
|
||||||
import {
|
import {
|
||||||
DrawerClose,
|
DrawerClose,
|
||||||
DrawerContent,
|
DrawerContent,
|
||||||
DrawerFooter,
|
DrawerFooter,
|
||||||
DrawerHeader,
|
DrawerHeader,
|
||||||
DrawerTitle,
|
DrawerTitle,
|
||||||
} from "~/components/ui/shadcn/drawer";
|
} from '~/components/ui/shadcn/drawer';
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
@ -15,7 +15,7 @@ import {
|
|||||||
TableHead,
|
TableHead,
|
||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "~/components/ui/shadcn/table";
|
} from '~/components/ui/shadcn/table';
|
||||||
import {
|
import {
|
||||||
Pagination,
|
Pagination,
|
||||||
PaginationContent,
|
PaginationContent,
|
||||||
@ -23,7 +23,7 @@ import {
|
|||||||
PaginationItem,
|
PaginationItem,
|
||||||
PaginationNext,
|
PaginationNext,
|
||||||
PaginationPrevious,
|
PaginationPrevious,
|
||||||
} from "~/components/ui/shadcn/pagination";
|
} from '~/components/ui/shadcn/pagination';
|
||||||
|
|
||||||
// Type definitions for Paginated History API
|
// Type definitions for Paginated History API
|
||||||
type HistoryEntry = {
|
type HistoryEntry = {
|
||||||
@ -38,7 +38,7 @@ type PaginatedHistory = {
|
|||||||
per_page: number;
|
per_page: number;
|
||||||
total_pages: number;
|
total_pages: number;
|
||||||
total_count: number;
|
total_count: number;
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
type History_Drawer_Props = {
|
type History_Drawer_Props = {
|
||||||
user_id: number;
|
user_id: number;
|
||||||
@ -52,9 +52,12 @@ const History_Drawer: React.FC<History_Drawer_Props> = ({ user_id }) => {
|
|||||||
|
|
||||||
const fetchHistory = async (currentPage: number, user_id: number) => {
|
const fetchHistory = async (currentPage: number, user_id: number) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/get_paginated_history?user_id=${user_id}&page=${currentPage}&per_page=${perPage}`);
|
const response = await fetch(
|
||||||
|
`/api/get_paginated_history?user_id=${user_id}&page=${currentPage}&per_page=${perPage}`,
|
||||||
|
);
|
||||||
if (!response.ok) throw new Error('Failed to fetch history');
|
if (!response.ok) throw new Error('Failed to fetch history');
|
||||||
const data: PaginatedHistory = await response.json() as PaginatedHistory;
|
const data: PaginatedHistory =
|
||||||
|
(await response.json()) as PaginatedHistory;
|
||||||
setHistory(data.data);
|
setHistory(data.data);
|
||||||
setTotalPages(data.meta.total_pages);
|
setTotalPages(data.meta.total_pages);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -76,29 +79,47 @@ const History_Drawer: React.FC<History_Drawer_Props> = ({ user_id }) => {
|
|||||||
<DrawerContent>
|
<DrawerContent>
|
||||||
<DrawerHeader>
|
<DrawerHeader>
|
||||||
<DrawerTitle>
|
<DrawerTitle>
|
||||||
<div className="flex flex-row items-center text-center sm:justify-center sm:ml-0 py-4">
|
<div className='flex flex-row items-center text-center sm:justify-center sm:ml-0 py-4'>
|
||||||
<Image src="/images/tech_tracker_logo.png" alt="Tech Tracker Logo" width={60} height={60} className="max-w-[40px] md:max-w-[120px]" />
|
<Image
|
||||||
<h1 className="title-text text-sm md:text-2xl lg:text-6xl bg-gradient-to-r from-[#bec8e6] via-[#F0EEE4] to-[#FFF8E7] font-bold pl-2 md:pl-4 text-transparent bg-clip-text">
|
src='/images/tech_tracker_logo.png'
|
||||||
|
alt='Tech Tracker Logo'
|
||||||
|
width={60}
|
||||||
|
height={60}
|
||||||
|
className='max-w-[40px] md:max-w-[120px]'
|
||||||
|
/>
|
||||||
|
<h1 className='title-text text-sm md:text-2xl lg:text-6xl bg-gradient-to-r from-[#bec8e6] via-[#F0EEE4] to-[#FFF8E7] font-bold pl-2 md:pl-4 text-transparent bg-clip-text'>
|
||||||
History
|
History
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
</DrawerTitle>
|
</DrawerTitle>
|
||||||
</DrawerHeader>
|
</DrawerHeader>
|
||||||
<ScrollArea className="w-full sm:w-5/6 lg:w-5/12 m-auto h-80">
|
<ScrollArea className='w-full sm:w-5/6 lg:w-5/12 m-auto h-80'>
|
||||||
<Table className="w-full m-auto">
|
<Table className='w-full m-auto'>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead className="font-semibold lg:max-w-[100px]">Name</TableHead>
|
<TableHead className='font-semibold lg:max-w-[100px]'>
|
||||||
<TableHead className="font-semibold lg:max-w-[100px]">Status</TableHead>
|
Name
|
||||||
<TableHead className="font-semibold lg:max-w-[100px] justify-end items-end text-right">Updated At</TableHead>
|
</TableHead>
|
||||||
|
<TableHead className='font-semibold lg:max-w-[100px]'>
|
||||||
|
Status
|
||||||
|
</TableHead>
|
||||||
|
<TableHead className='font-semibold lg:max-w-[100px] justify-end items-end text-right'>
|
||||||
|
Updated At
|
||||||
|
</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{history.map((entry, index) => (
|
{history.map((entry, index) => (
|
||||||
<TableRow key={index}>
|
<TableRow key={index}>
|
||||||
<TableCell className="font-medium lg:max-w-[100px]">{entry.name}</TableCell>
|
<TableCell className='font-medium lg:max-w-[100px]'>
|
||||||
<TableCell className="font-medium lg:max-w-[100px] wrapword">{entry.status}</TableCell>
|
{entry.name}
|
||||||
<TableCell className="font-medium lg:max-w-[100px] justify-end items-end text-right">{new Date(entry.updatedAt).toLocaleString()}</TableCell>
|
</TableCell>
|
||||||
|
<TableCell className='font-medium lg:max-w-[100px] wrapword'>
|
||||||
|
{entry.status}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className='font-medium lg:max-w-[100px] justify-end items-end text-right'>
|
||||||
|
{new Date(entry.updatedAt).toLocaleString()}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
@ -110,7 +131,7 @@ const History_Drawer: React.FC<History_Drawer_Props> = ({ user_id }) => {
|
|||||||
{page > 1 && (
|
{page > 1 && (
|
||||||
<PaginationItem>
|
<PaginationItem>
|
||||||
<PaginationPrevious
|
<PaginationPrevious
|
||||||
href="#"
|
href='#'
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
handlePageChange(page - 1);
|
handlePageChange(page - 1);
|
||||||
@ -119,33 +140,31 @@ const History_Drawer: React.FC<History_Drawer_Props> = ({ user_id }) => {
|
|||||||
</PaginationItem>
|
</PaginationItem>
|
||||||
)}
|
)}
|
||||||
{totalPages > 10 && (
|
{totalPages > 10 && (
|
||||||
<h3 className="text-center flex flex-row">
|
<h3 className='text-center flex flex-row'>
|
||||||
Page
|
Page
|
||||||
<h3 className="font-bold mx-1">
|
<h3 className='font-bold mx-1'>{page}</h3>
|
||||||
{page}
|
|
||||||
</h3>
|
|
||||||
of
|
of
|
||||||
<h3 className="font-semibold ml-1">
|
<h3 className='font-semibold ml-1'>{totalPages}</h3>
|
||||||
{totalPages}
|
|
||||||
</h3>
|
|
||||||
</h3>
|
</h3>
|
||||||
)}
|
)}
|
||||||
{totalPages <= 10 && Array.from({ length: totalPages }).map((_, idx) => (
|
{totalPages <= 10 &&
|
||||||
|
Array.from({ length: totalPages }).map((_, idx) => (
|
||||||
<PaginationItem key={idx}>
|
<PaginationItem key={idx}>
|
||||||
<PaginationLink
|
<PaginationLink
|
||||||
href="#"
|
href='#'
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
handlePageChange(idx + 1);
|
handlePageChange(idx + 1);
|
||||||
}}
|
}}
|
||||||
>{idx + 1}
|
>
|
||||||
|
{idx + 1}
|
||||||
</PaginationLink>
|
</PaginationLink>
|
||||||
</PaginationItem>
|
</PaginationItem>
|
||||||
))}
|
))}
|
||||||
{page < totalPages && (
|
{page < totalPages && (
|
||||||
<PaginationItem>
|
<PaginationItem>
|
||||||
<PaginationNext
|
<PaginationNext
|
||||||
href="#"
|
href='#'
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
handlePageChange(page + 1);
|
handlePageChange(page + 1);
|
||||||
@ -155,8 +174,7 @@ const History_Drawer: React.FC<History_Drawer_Props> = ({ user_id }) => {
|
|||||||
)}
|
)}
|
||||||
</PaginationContent>
|
</PaginationContent>
|
||||||
</Pagination>
|
</Pagination>
|
||||||
<DrawerClose>
|
<DrawerClose></DrawerClose>
|
||||||
</DrawerClose>
|
|
||||||
</DrawerFooter>
|
</DrawerFooter>
|
||||||
</DrawerContent>
|
</DrawerContent>
|
||||||
);
|
);
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
"use client"
|
'use client';
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import { Progress } from "~/components/ui/shadcn/progress"
|
import { Progress } from '~/components/ui/shadcn/progress';
|
||||||
|
|
||||||
interface Loading_Props {
|
interface Loading_Props {
|
||||||
interval_amount: number
|
interval_amount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Loading: React.FC<Loading_Props> = ({ interval_amount }) => {
|
const Loading: React.FC<Loading_Props> = ({ interval_amount }) => {
|
||||||
@ -19,12 +19,11 @@ const Loading: React.FC<Loading_Props> = ({interval_amount}) => {
|
|||||||
});
|
});
|
||||||
}, 50);
|
}, 50);
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
|
});
|
||||||
})
|
|
||||||
return (
|
return (
|
||||||
<div className="items-center justify-center w-1/3 m-auto pt-20">
|
<div className='items-center justify-center w-1/3 m-auto pt-20'>
|
||||||
<Progress value={progress} />
|
<Progress value={progress} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
export default Loading;
|
export default Loading;
|
||||||
|
@ -1,35 +1,42 @@
|
|||||||
import Link from "next/link";
|
import Link from 'next/link';
|
||||||
import Image from "next/image";
|
import Image from 'next/image';
|
||||||
import Sign_In_Microsoft from "~/components/auth/server/microsoft/Sign_In";
|
import Sign_In_Microsoft from '~/components/auth/server/microsoft/Sign_In';
|
||||||
import Sign_In_Authentik from "~/components/auth/server/authentik/Sign_In";
|
import Sign_In_Authentik from '~/components/auth/server/authentik/Sign_In';
|
||||||
import Header from "~/components/ui/Header";
|
import Header from '~/components/ui/Header';
|
||||||
|
|
||||||
export default function No_Session() {
|
export default function No_Session() {
|
||||||
return (
|
return (
|
||||||
<main className="w-full min-h-screen mx-auto text-center pt-2 md:pt-10
|
<main
|
||||||
bg-gradient-to-b from-[#111111] to-[#212325]">
|
className='w-full min-h-screen mx-auto text-center pt-2 md:pt-10
|
||||||
<div className="md:w-2/3 pt-4 pb-2 md:pt-10 md:pb-4 m-auto">
|
bg-gradient-to-b from-[#111111] to-[#212325]'
|
||||||
|
>
|
||||||
|
<div className='md:w-2/3 pt-4 pb-2 md:pt-10 md:pb-4 m-auto'>
|
||||||
<Header />
|
<Header />
|
||||||
</div>
|
</div>
|
||||||
<div className="mx-auto flex flex-col">
|
<div className='mx-auto flex flex-col'>
|
||||||
<div className="py-4">
|
<div className='py-4'>
|
||||||
<Sign_In_Microsoft />
|
<Sign_In_Microsoft />
|
||||||
</div>
|
</div>
|
||||||
<div className="py-4">
|
<div className='py-4'>
|
||||||
<Sign_In_Authentik />
|
<Sign_In_Authentik />
|
||||||
</div>
|
</div>
|
||||||
<Link href="https://git.gibbyb.com/gib/Tech_Tracker_Web"
|
<Link
|
||||||
className="text-center text-[16px] md:text-lg px-4 py-2 md:py-2.5 font-semibold
|
href='https://git.gibbyb.com/gib/Tech_Tracker_Web'
|
||||||
|
className='text-center text-[16px] md:text-lg px-4 py-2 md:py-2.5 font-semibold
|
||||||
bg-gradient-to-tl from-[#35363F] to=[#24191A] rounded-xl hover:text-sky-200
|
bg-gradient-to-tl from-[#35363F] to=[#24191A] rounded-xl hover:text-sky-200
|
||||||
hover:bg-gradient-to-tr hover:from-[#35363F] hover:to-[#23242F]
|
hover:bg-gradient-to-tr hover:from-[#35363F] hover:to-[#23242F]
|
||||||
mx-auto flex flex-row"
|
mx-auto flex flex-row'
|
||||||
>
|
>
|
||||||
<Image src="/images/gitea_logo.svg" alt="Gitea" width={35} height={35}
|
<Image
|
||||||
className="mr-2"
|
src='/images/gitea_logo.svg'
|
||||||
|
alt='Gitea'
|
||||||
|
width={35}
|
||||||
|
height={35}
|
||||||
|
className='mr-2'
|
||||||
/>
|
/>
|
||||||
<h3 className="my-auto">Source Code</h3>
|
<h3 className='my-auto'>Source Code</h3>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
@ -1,21 +1,27 @@
|
|||||||
"use client";
|
'use client';
|
||||||
import Image from "next/image";
|
import Image from 'next/image';
|
||||||
import { useTVMode } from "~/components/context/TVModeContext";
|
import { useTVMode } from '~/components/context/TVModeContext';
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from 'next-auth/react';
|
||||||
|
|
||||||
export default function TV_Toggle() {
|
export default function TV_Toggle() {
|
||||||
const { tvMode, toggleTVMode } = useTVMode();
|
const { tvMode, toggleTVMode } = useTVMode();
|
||||||
const { data: session } = useSession();
|
const { data: session } = useSession();
|
||||||
if (!session) return <div />;
|
if (!session) return <div />;
|
||||||
return (
|
return (
|
||||||
<button onClick={toggleTVMode} className="mr-4 mt-1">
|
<button onClick={toggleTVMode} className='mr-4 mt-1'>
|
||||||
{tvMode ? (
|
{tvMode ? (
|
||||||
<Image src="/images/exit_fullscreen.svg" alt="Exit TV Mode"
|
<Image
|
||||||
width={25} height={25}
|
src='/images/exit_fullscreen.svg'
|
||||||
|
alt='Exit TV Mode'
|
||||||
|
width={25}
|
||||||
|
height={25}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Image src="/images/fullscreen.svg" alt="Enter TV Mode"
|
<Image
|
||||||
width={25} height={25}
|
src='/images/fullscreen.svg'
|
||||||
|
alt='Enter TV Mode'
|
||||||
|
width={25}
|
||||||
|
height={25}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
"use client";
|
'use client';
|
||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from 'next-auth/react';
|
||||||
import Loading from "~/components/ui/Loading";
|
import Loading from '~/components/ui/Loading';
|
||||||
import { useTVMode } from "~/components/context/TVModeContext";
|
import { useTVMode } from '~/components/context/TVModeContext';
|
||||||
import { Drawer, DrawerTrigger } from "~/components/ui/shadcn/drawer";
|
import { Drawer, DrawerTrigger } from '~/components/ui/shadcn/drawer';
|
||||||
import { ScrollArea } from "~/components/ui/shadcn/scroll-area";
|
import { ScrollArea } from '~/components/ui/shadcn/scroll-area';
|
||||||
|
|
||||||
import History_Drawer from "~/components/ui/History_Drawer";
|
import History_Drawer from '~/components/ui/History_Drawer';
|
||||||
|
|
||||||
type Employee = {
|
type Employee = {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
status: string;
|
status: string;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
};
|
||||||
|
|
||||||
export default function Tech_Table({ employees }: { employees: Employee[] }) {
|
export default function Tech_Table({ employees }: { employees: Employee[] }) {
|
||||||
const { data: session, status } = useSession();
|
const { data: session, status } = useSession();
|
||||||
@ -29,32 +29,34 @@ export default function Tech_Table({ employees }: { employees: Employee[] }) {
|
|||||||
const res = await fetch('/api/get_technicians', {
|
const res = await fetch('/api/get_technicians', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': `Bearer ${process.env.API_KEY}`
|
Authorization: `Bearer ${process.env.API_KEY}`,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
return res.json() as Promise<Employee[]>;
|
return res.json() as Promise<Employee[]>;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const update_status = async () => {
|
const update_status = async () => {
|
||||||
if (!session) {
|
if (!session) {
|
||||||
alert("You must be signed in to update status.");
|
alert('You must be signed in to update status.');
|
||||||
return;
|
return;
|
||||||
} else if (selectedIds.length === 0 && employeeStatus.trim() !== '') {
|
} else if (selectedIds.length === 0 && employeeStatus.trim() !== '') {
|
||||||
const users_name = session.user?.name ?? "";
|
const users_name = session.user?.name ?? '';
|
||||||
const name_arr = users_name.split(' ');
|
const name_arr = users_name.split(' ');
|
||||||
const lname = name_arr[name_arr.length - 1] ?? "";
|
const lname = name_arr[name_arr.length - 1] ?? '';
|
||||||
const cur_user = employees.find(employee => employee.name.includes(lname));
|
const cur_user = employees.find((employee) =>
|
||||||
|
employee.name.includes(lname),
|
||||||
|
);
|
||||||
if (cur_user) {
|
if (cur_user) {
|
||||||
await fetch('/api/update_status_by_id', {
|
await fetch('/api/update_status_by_id', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Authorization': `Bearer ${process.env.API_KEY}`
|
Authorization: `Bearer ${process.env.API_KEY}`,
|
||||||
},
|
},
|
||||||
body: JSON.stringify(
|
body: JSON.stringify({
|
||||||
{ employeeIds: [cur_user.id],
|
employeeIds: [cur_user.id],
|
||||||
newStatus: employeeStatus }
|
newStatus: employeeStatus,
|
||||||
),
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (employeeStatus.trim() !== '') {
|
} else if (employeeStatus.trim() !== '') {
|
||||||
@ -62,12 +64,12 @@ export default function Tech_Table({ employees }: { employees: Employee[] }) {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Authorization': `Bearer ${process.env.API_KEY}`
|
Authorization: `Bearer ${process.env.API_KEY}`,
|
||||||
},
|
},
|
||||||
body: JSON.stringify(
|
body: JSON.stringify({
|
||||||
{ employeeIds: selectedIds,
|
employeeIds: selectedIds,
|
||||||
newStatus: employeeStatus }
|
newStatus: employeeStatus,
|
||||||
),
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +83,7 @@ export default function Tech_Table({ employees }: { employees: Employee[] }) {
|
|||||||
setSelectedIds((prevSelected) =>
|
setSelectedIds((prevSelected) =>
|
||||||
prevSelected.includes(id)
|
prevSelected.includes(id)
|
||||||
? prevSelected.filter((prevId) => prevId !== id)
|
? prevSelected.filter((prevId) => prevId !== id)
|
||||||
: [...prevSelected, id]
|
: [...prevSelected, id],
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -121,7 +123,7 @@ export default function Tech_Table({ employees }: { employees: Employee[] }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (status !== "loading") {
|
if (status !== 'loading') {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, [status]);
|
}, [status]);
|
||||||
@ -163,57 +165,61 @@ export default function Tech_Table({ employees }: { employees: Employee[] }) {
|
|||||||
else {
|
else {
|
||||||
return (
|
return (
|
||||||
<div className={`${tvMode ? 'content-fullscreen' : ''}`}>
|
<div className={`${tvMode ? 'content-fullscreen' : ''}`}>
|
||||||
{tvMode && <div className="w-full tablefill"></div>}
|
{tvMode && <div className='w-full tablefill'></div>}
|
||||||
<table className={`techtable m-auto text-center text-[42px]
|
<table
|
||||||
${tvMode ? 'techtable-fullscreen' : 'w-5/6'}`}>
|
className={`techtable m-auto text-center text-[42px]
|
||||||
<thead className="tabletitles border border-[#3e4446] bg-gradient-to-b
|
${tvMode ? 'techtable-fullscreen' : 'w-5/6'}`}
|
||||||
from-[#282828] to-[#383838] text-[48px]">
|
>
|
||||||
|
<thead
|
||||||
|
className='tabletitles border border-[#3e4446] bg-gradient-to-b
|
||||||
|
from-[#282828] to-[#383838] text-[48px]'
|
||||||
|
>
|
||||||
<tr>
|
<tr>
|
||||||
{!tvMode && (
|
{!tvMode && (
|
||||||
<th className="py-3 px-3 md:px-6 border border-[#3e4446]">
|
<th className='py-3 px-3 md:px-6 border border-[#3e4446]'>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type='checkbox'
|
||||||
className="m-auto cursor-pointer md:scale-150"
|
className='m-auto cursor-pointer md:scale-150'
|
||||||
checked={selectAll}
|
checked={selectAll}
|
||||||
onChange={handleSelectAllChange}
|
onChange={handleSelectAllChange}
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
)}
|
)}
|
||||||
<th className="border border-[#3e4446] py-3">Name</th>
|
<th className='border border-[#3e4446] py-3'>Name</th>
|
||||||
<th className="border border-[#3e4446] py-3">
|
<th className='border border-[#3e4446] py-3'>
|
||||||
<Drawer>
|
<Drawer>
|
||||||
<DrawerTrigger>
|
<DrawerTrigger>Status</DrawerTrigger>
|
||||||
Status
|
|
||||||
</DrawerTrigger>
|
|
||||||
<History_Drawer user_id={-1} />
|
<History_Drawer user_id={-1} />
|
||||||
</Drawer>
|
</Drawer>
|
||||||
</th>
|
</th>
|
||||||
<th className="border border-[#3e4446] py-3">Updated At</th>
|
<th className='border border-[#3e4446] py-3'>Updated At</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{employeeData.map((employee) => (
|
{employeeData.map((employee) => (
|
||||||
<tr
|
<tr
|
||||||
className="even:bg-gradient-to-br from-[#272727] to-[#313131]
|
className='even:bg-gradient-to-br from-[#272727] to-[#313131]
|
||||||
odd:bg-gradient-to-bl odd:from-[#252525] odd:to-[#212125]"
|
odd:bg-gradient-to-bl odd:from-[#252525] odd:to-[#212125]'
|
||||||
key={employee.id}
|
key={employee.id}
|
||||||
>
|
>
|
||||||
{!tvMode && (
|
{!tvMode && (
|
||||||
<td className="p-1 border border-[#3e4446]">
|
<td className='p-1 border border-[#3e4446]'>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type='checkbox'
|
||||||
className="m-auto cursor-pointer md:scale-150"
|
className='m-auto cursor-pointer md:scale-150'
|
||||||
checked={selectedIds.includes(employee.id)}
|
checked={selectedIds.includes(employee.id)}
|
||||||
onChange={() => handleCheckboxChange(employee.id)}
|
onChange={() => handleCheckboxChange(employee.id)}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
)}
|
)}
|
||||||
<td className="n-column px-1 md:py-3 border border-[#3e4446]">
|
<td className='n-column px-1 md:py-3 border border-[#3e4446]'>
|
||||||
{employee.name}
|
{employee.name}
|
||||||
</td>
|
</td>
|
||||||
<td className="s-column max-w-[700px] px-1 md:py-3 border
|
<td
|
||||||
border-[#3e4446] wrapword max-h-0">
|
className='s-column max-w-[700px] px-1 md:py-3 border
|
||||||
<ScrollArea className="w-full m-auto h-[60px]">
|
border-[#3e4446] wrapword max-h-0'
|
||||||
|
>
|
||||||
|
<ScrollArea className='w-full m-auto h-[60px]'>
|
||||||
<Drawer>
|
<Drawer>
|
||||||
<DrawerTrigger>
|
<DrawerTrigger>
|
||||||
<button onClick={() => handleStatusClick(employee.id)}>
|
<button onClick={() => handleStatusClick(employee.id)}>
|
||||||
@ -221,12 +227,15 @@ export default function Tech_Table({ employees }: { employees: Employee[] }) {
|
|||||||
</button>
|
</button>
|
||||||
</DrawerTrigger>
|
</DrawerTrigger>
|
||||||
{selectedUserId !== -1 && (
|
{selectedUserId !== -1 && (
|
||||||
<History_Drawer key={selectedUserId} user_id={selectedUserId} />
|
<History_Drawer
|
||||||
|
key={selectedUserId}
|
||||||
|
user_id={selectedUserId}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</Drawer>
|
</Drawer>
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
</td>
|
</td>
|
||||||
<td className="ua-column px-1 md:py-3 border border-[#3e4446]">
|
<td className='ua-column px-1 md:py-3 border border-[#3e4446]'>
|
||||||
{formatTime(employee.updatedAt)}
|
{formatTime(employee.updatedAt)}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -234,23 +243,23 @@ export default function Tech_Table({ employees }: { employees: Employee[] }) {
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{!tvMode && (
|
{!tvMode && (
|
||||||
<div className="m-auto flex flex-row items-center justify-center py-5">
|
<div className='m-auto flex flex-row items-center justify-center py-5'>
|
||||||
<input
|
<input
|
||||||
autoFocus
|
autoFocus
|
||||||
type="text"
|
type='text'
|
||||||
placeholder="New Status"
|
placeholder='New Status'
|
||||||
className="min-w-[120px] lg:min-w-[400px] bg-[#F9F6EE] py-2 px-3
|
className='min-w-[120px] lg:min-w-[400px] bg-[#F9F6EE] py-2 px-3
|
||||||
border-none rounded-xl text-[#111111] lg:text-2xl"
|
border-none rounded-xl text-[#111111] lg:text-2xl'
|
||||||
value={employeeStatus}
|
value={employeeStatus}
|
||||||
onChange={handleStatusChange}
|
onChange={handleStatusChange}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type='submit'
|
||||||
className="min-w-[100px] lg:min-w-[160px] m-2 p-2 border-none rounded-xl
|
className='min-w-[100px] lg:min-w-[160px] m-2 p-2 border-none rounded-xl
|
||||||
text-center font-semibold lg:text-2xl hover:text-slate-300
|
text-center font-semibold lg:text-2xl hover:text-slate-300
|
||||||
hover:bg-gradient-to-bl hover:from-[#484848] hover:to-[#333333]
|
hover:bg-gradient-to-bl hover:from-[#484848] hover:to-[#333333]
|
||||||
bg-gradient-to-br from-[#595959] to-[#444444]"
|
bg-gradient-to-br from-[#595959] to-[#444444]'
|
||||||
onClick={update_status}
|
onClick={update_status}
|
||||||
>
|
>
|
||||||
Update
|
Update
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
"use client"
|
'use client';
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
|
import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
|
||||||
|
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
|
|
||||||
const ScrollArea = React.forwardRef<
|
const ScrollArea = React.forwardRef<
|
||||||
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
||||||
@ -11,38 +11,38 @@ const ScrollArea = React.forwardRef<
|
|||||||
>(({ className, children, ...props }, ref) => (
|
>(({ className, children, ...props }, ref) => (
|
||||||
<ScrollAreaPrimitive.Root
|
<ScrollAreaPrimitive.Root
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("relative overflow-hidden", className)}
|
className={cn('relative overflow-hidden', className)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
|
<ScrollAreaPrimitive.Viewport className='h-full w-full rounded-[inherit]'>
|
||||||
{children}
|
{children}
|
||||||
</ScrollAreaPrimitive.Viewport>
|
</ScrollAreaPrimitive.Viewport>
|
||||||
<ScrollBar />
|
<ScrollBar />
|
||||||
<ScrollAreaPrimitive.Corner />
|
<ScrollAreaPrimitive.Corner />
|
||||||
</ScrollAreaPrimitive.Root>
|
</ScrollAreaPrimitive.Root>
|
||||||
))
|
));
|
||||||
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
|
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
|
||||||
|
|
||||||
const ScrollBar = React.forwardRef<
|
const ScrollBar = React.forwardRef<
|
||||||
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
||||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
|
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||||
>(({ className, orientation = "vertical", ...props }, ref) => (
|
>(({ className, orientation = 'vertical', ...props }, ref) => (
|
||||||
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||||
ref={ref}
|
ref={ref}
|
||||||
orientation={orientation}
|
orientation={orientation}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex touch-none select-none transition-colors",
|
'flex touch-none select-none transition-colors',
|
||||||
orientation === "vertical" &&
|
orientation === 'vertical' &&
|
||||||
"h-full w-2.5 border-l border-l-transparent p-[1px]",
|
'h-full w-2.5 border-l border-l-transparent p-[1px]',
|
||||||
orientation === "horizontal" &&
|
orientation === 'horizontal' &&
|
||||||
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
|
'h-2.5 flex-col border-t border-t-transparent p-[1px]',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
|
<ScrollAreaPrimitive.ScrollAreaThumb className='relative flex-1 rounded-full bg-border' />
|
||||||
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||||
))
|
));
|
||||||
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
|
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
|
||||||
|
|
||||||
export { ScrollArea, ScrollBar }
|
export { ScrollArea, ScrollBar };
|
||||||
|
@ -1,59 +1,59 @@
|
|||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import { Slot } from "@radix-ui/react-slot"
|
import { Slot } from '@radix-ui/react-slot';
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from 'class-variance-authority';
|
||||||
|
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
|
|
||||||
const buttonVariants = cva(
|
const buttonVariants = cva(
|
||||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm " +
|
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm ' +
|
||||||
"font-medium ring-offset-background transition-colors focus-visible:outline-none " +
|
'font-medium ring-offset-background transition-colors focus-visible:outline-none ' +
|
||||||
"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 " +
|
'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ' +
|
||||||
"disabled:pointer-events-none disabled:opacity-50",
|
'disabled:pointer-events-none disabled:opacity-50',
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
||||||
destructive:
|
destructive:
|
||||||
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
||||||
outline:
|
outline:
|
||||||
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
|
||||||
secondary:
|
secondary:
|
||||||
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
||||||
link: "text-primary underline-offset-4 hover:underline",
|
link: 'text-primary underline-offset-4 hover:underline',
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: "h-10 px-4 py-2",
|
default: 'h-10 px-4 py-2',
|
||||||
sm: "h-9 rounded-md px-3",
|
sm: 'h-9 rounded-md px-3',
|
||||||
lg: "h-11 rounded-md px-8",
|
lg: 'h-11 rounded-md px-8',
|
||||||
icon: "h-10 w-10",
|
icon: 'h-10 w-10',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
variant: "default",
|
variant: 'default',
|
||||||
size: "default",
|
size: 'default',
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
export interface ButtonProps
|
export interface ButtonProps
|
||||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||||
VariantProps<typeof buttonVariants> {
|
VariantProps<typeof buttonVariants> {
|
||||||
asChild?: boolean
|
asChild?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||||
const Comp = asChild ? Slot : "button"
|
const Comp = asChild ? Slot : 'button';
|
||||||
return (
|
return (
|
||||||
<Comp
|
<Comp
|
||||||
className={cn(buttonVariants({ variant, size, className }))}
|
className={cn(buttonVariants({ variant, size, className }))}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
Button.displayName = "Button"
|
Button.displayName = 'Button';
|
||||||
|
|
||||||
export { Button, buttonVariants }
|
export { Button, buttonVariants };
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
"use client"
|
'use client';
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react"
|
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
||||||
import { DayPicker } from "react-day-picker"
|
import { DayPicker } from 'react-day-picker';
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
import { buttonVariants } from "~/components/ui/shadcn/button"
|
import { buttonVariants } from '~/components/ui/shadcn/button';
|
||||||
|
|
||||||
export type CalendarProps = React.ComponentProps<typeof DayPicker>
|
export type CalendarProps = React.ComponentProps<typeof DayPicker>;
|
||||||
|
|
||||||
function Calendar({
|
function Calendar({
|
||||||
className,
|
className,
|
||||||
@ -16,59 +16,60 @@ function Calendar({
|
|||||||
return (
|
return (
|
||||||
<DayPicker
|
<DayPicker
|
||||||
showOutsideDays={showOutsideDays}
|
showOutsideDays={showOutsideDays}
|
||||||
className={cn("p-3", className)}
|
className={cn('p-3', className)}
|
||||||
classNames={{
|
classNames={{
|
||||||
months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
|
months: 'flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0',
|
||||||
month: "space-y-4",
|
month: 'space-y-4',
|
||||||
caption: "flex justify-center pt-1 relative items-center",
|
caption: 'flex justify-center pt-1 relative items-center',
|
||||||
caption_label: "text-sm font-medium",
|
caption_label: 'text-sm font-medium',
|
||||||
nav: "space-x-1 flex items-center",
|
nav: 'space-x-1 flex items-center',
|
||||||
nav_button: cn(
|
nav_button: cn(
|
||||||
buttonVariants({ variant: "outline" }),
|
buttonVariants({ variant: 'outline' }),
|
||||||
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
|
'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
|
||||||
),
|
),
|
||||||
nav_button_previous: "absolute left-1",
|
nav_button_previous: 'absolute left-1',
|
||||||
nav_button_next: "absolute right-1",
|
nav_button_next: 'absolute right-1',
|
||||||
table: "w-full border-collapse space-y-1",
|
table: 'w-full border-collapse space-y-1',
|
||||||
head_row: "flex",
|
head_row: 'flex',
|
||||||
head_cell:
|
head_cell:
|
||||||
"text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]",
|
'text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]',
|
||||||
row: "flex w-full mt-2",
|
row: 'flex w-full mt-2',
|
||||||
cell: "h-9 w-9 text-center text-sm p-0 relative " +
|
cell:
|
||||||
"[&:has([aria-selected].day-range-end)]:rounded-r-md " +
|
'h-9 w-9 text-center text-sm p-0 relative ' +
|
||||||
"[&:has([aria-selected].day-outside)]:bg-accent/50 " +
|
'[&:has([aria-selected].day-range-end)]:rounded-r-md ' +
|
||||||
"[&:has([aria-selected])]:bg-accent " +
|
'[&:has([aria-selected].day-outside)]:bg-accent/50 ' +
|
||||||
"first:[&:has([aria-selected])]:rounded-l-md " +
|
'[&:has([aria-selected])]:bg-accent ' +
|
||||||
"last:[&:has([aria-selected])]:rounded-r-md " +
|
'first:[&:has([aria-selected])]:rounded-l-md ' +
|
||||||
"focus-within:relative focus-within:z-20",
|
'last:[&:has([aria-selected])]:rounded-r-md ' +
|
||||||
|
'focus-within:relative focus-within:z-20',
|
||||||
day: cn(
|
day: cn(
|
||||||
buttonVariants({ variant: "ghost" }),
|
buttonVariants({ variant: 'ghost' }),
|
||||||
"h-9 w-9 p-0 font-normal aria-selected:opacity-100"
|
'h-9 w-9 p-0 font-normal aria-selected:opacity-100',
|
||||||
),
|
),
|
||||||
day_range_end: "day-range-end",
|
day_range_end: 'day-range-end',
|
||||||
day_selected:
|
day_selected:
|
||||||
"bg-primary text-primary-foreground hover:bg-primary " +
|
'bg-primary text-primary-foreground hover:bg-primary ' +
|
||||||
"hover:text-primary-foreground focus:bg-primary " +
|
'hover:text-primary-foreground focus:bg-primary ' +
|
||||||
"focus:text-primary-foreground",
|
'focus:text-primary-foreground',
|
||||||
day_today: "bg-accent text-accent-foreground",
|
day_today: 'bg-accent text-accent-foreground',
|
||||||
day_outside:
|
day_outside:
|
||||||
"day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 " +
|
'day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 ' +
|
||||||
"aria-selected:text-muted-foreground aria-selected:opacity-30",
|
'aria-selected:text-muted-foreground aria-selected:opacity-30',
|
||||||
day_disabled: "text-muted-foreground opacity-50",
|
day_disabled: 'text-muted-foreground opacity-50',
|
||||||
day_range_middle:
|
day_range_middle:
|
||||||
"aria-selected:bg-accent aria-selected:text-accent-foreground",
|
'aria-selected:bg-accent aria-selected:text-accent-foreground',
|
||||||
day_hidden: "invisible",
|
day_hidden: 'invisible',
|
||||||
...classNames,
|
...classNames,
|
||||||
}}
|
}}
|
||||||
components={{
|
components={{
|
||||||
// @ts-expect-error - I didn't even write this code man cmon
|
// @ts-expect-error - I didn't even write this code man cmon
|
||||||
IconLeft: ({ ...props }) => <ChevronLeft className="h-4 w-4" />,
|
IconLeft: ({ ...props }) => <ChevronLeft className='h-4 w-4' />,
|
||||||
IconRight: ({ ...props }) => <ChevronRight className="h-4 w-4" />,
|
IconRight: ({ ...props }) => <ChevronRight className='h-4 w-4' />,
|
||||||
}}
|
}}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
Calendar.displayName = "Calendar"
|
Calendar.displayName = 'Calendar';
|
||||||
|
|
||||||
export { Calendar }
|
export { Calendar };
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
"use client"
|
'use client';
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
|
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
||||||
import { Check } from "lucide-react"
|
import { Check } from 'lucide-react';
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
|
|
||||||
const Checkbox = React.forwardRef<
|
const Checkbox = React.forwardRef<
|
||||||
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
||||||
@ -11,21 +11,21 @@ const Checkbox = React.forwardRef<
|
|||||||
<CheckboxPrimitive.Root
|
<CheckboxPrimitive.Root
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background " +
|
'peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background ' +
|
||||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring " +
|
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ' +
|
||||||
"focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 " +
|
'focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 ' +
|
||||||
"data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
'data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<CheckboxPrimitive.Indicator
|
<CheckboxPrimitive.Indicator
|
||||||
className={cn("flex items-center justify-center text-current")}
|
className={cn('flex items-center justify-center text-current')}
|
||||||
>
|
>
|
||||||
<Check className="h-4 w-4" />
|
<Check className='h-4 w-4' />
|
||||||
</CheckboxPrimitive.Indicator>
|
</CheckboxPrimitive.Indicator>
|
||||||
</CheckboxPrimitive.Root>
|
</CheckboxPrimitive.Root>
|
||||||
))
|
));
|
||||||
Checkbox.displayName = CheckboxPrimitive.Root.displayName
|
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
|
||||||
|
|
||||||
export { Checkbox }
|
export { Checkbox };
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
"use client"
|
'use client';
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import { Check, ChevronsUpDown } from "lucide-react"
|
import { Check, ChevronsUpDown } from 'lucide-react';
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
import { Button } from "~/components/ui/shadcn/button"
|
import { Button } from '~/components/ui/shadcn/button';
|
||||||
import {
|
import {
|
||||||
Command,
|
Command,
|
||||||
CommandEmpty,
|
CommandEmpty,
|
||||||
@ -10,12 +10,12 @@ import {
|
|||||||
CommandInput,
|
CommandInput,
|
||||||
CommandItem,
|
CommandItem,
|
||||||
CommandList,
|
CommandList,
|
||||||
} from "~/components/ui/shadcn/command"
|
} from '~/components/ui/shadcn/command';
|
||||||
import {
|
import {
|
||||||
Popover,
|
Popover,
|
||||||
PopoverContent,
|
PopoverContent,
|
||||||
PopoverTrigger,
|
PopoverTrigger,
|
||||||
} from "~/components/ui/shadcn/popover"
|
} from '~/components/ui/shadcn/popover';
|
||||||
|
|
||||||
// Define the type correctly as an array of objects
|
// Define the type correctly as an array of objects
|
||||||
type ListItem = {
|
type ListItem = {
|
||||||
@ -29,27 +29,28 @@ type ComboboxDemoProps = {
|
|||||||
|
|
||||||
export function ComboboxDemo({ listItems }: ComboboxDemoProps) {
|
export function ComboboxDemo({ listItems }: ComboboxDemoProps) {
|
||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(false);
|
||||||
const [value, setValue] = React.useState("");
|
const [value, setValue] = React.useState('');
|
||||||
|
|
||||||
const selectedItem = listItems.find(
|
const selectedItem =
|
||||||
(item) => item.value === value)?.label ?? "Select listItem...";
|
listItems.find((item) => item.value === value)?.label ??
|
||||||
|
'Select listItem...';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover open={open} onOpenChange={setOpen}>
|
<Popover open={open} onOpenChange={setOpen}>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant='outline'
|
||||||
role="combobox"
|
role='combobox'
|
||||||
aria-expanded={open}
|
aria-expanded={open}
|
||||||
className="w-[200px] justify-between"
|
className='w-[200px] justify-between'
|
||||||
>
|
>
|
||||||
{selectedItem}
|
{selectedItem}
|
||||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
<ChevronsUpDown className='ml-2 h-4 w-4 shrink-0 opacity-50' />
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent className="w-[200px] p-0">
|
<PopoverContent className='w-[200px] p-0'>
|
||||||
<Command>
|
<Command>
|
||||||
<CommandInput placeholder="Search listItem..." />
|
<CommandInput placeholder='Search listItem...' />
|
||||||
<CommandEmpty>No Item found.</CommandEmpty>
|
<CommandEmpty>No Item found.</CommandEmpty>
|
||||||
<CommandList>
|
<CommandList>
|
||||||
<CommandGroup>
|
<CommandGroup>
|
||||||
@ -58,14 +59,14 @@ export function ComboboxDemo({ listItems }: ComboboxDemoProps) {
|
|||||||
key={listItem.value}
|
key={listItem.value}
|
||||||
value={listItem.value}
|
value={listItem.value}
|
||||||
onSelect={(currentValue) => {
|
onSelect={(currentValue) => {
|
||||||
setValue(currentValue === value ? "" : currentValue);
|
setValue(currentValue === value ? '' : currentValue);
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Check
|
<Check
|
||||||
className={cn(
|
className={cn(
|
||||||
"mr-2 h-4 w-4",
|
'mr-2 h-4 w-4',
|
||||||
value === listItem.value ? "opacity-100" : "opacity-0"
|
value === listItem.value ? 'opacity-100' : 'opacity-0',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{listItem.label}
|
{listItem.label}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
"use client"
|
'use client';
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import { type DialogProps } from "@radix-ui/react-dialog"
|
import { type DialogProps } from '@radix-ui/react-dialog';
|
||||||
import { Command as CommandPrimitive } from "cmdk"
|
import { Command as CommandPrimitive } from 'cmdk';
|
||||||
import { Search } from "lucide-react"
|
import { Search } from 'lucide-react';
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
import { Dialog, DialogContent } from "~/components/ui/shadcn/dialog"
|
import { Dialog, DialogContent } from '~/components/ui/shadcn/dialog';
|
||||||
|
|
||||||
const Command = React.forwardRef<
|
const Command = React.forwardRef<
|
||||||
React.ElementRef<typeof CommandPrimitive>,
|
React.ElementRef<typeof CommandPrimitive>,
|
||||||
@ -13,55 +13,57 @@ const Command = React.forwardRef<
|
|||||||
<CommandPrimitive
|
<CommandPrimitive
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-full w-full flex-col overflow-hidden " +
|
'flex h-full w-full flex-col overflow-hidden ' +
|
||||||
"rounded-md bg-popover text-popover-foreground",
|
'rounded-md bg-popover text-popover-foreground',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
Command.displayName = CommandPrimitive.displayName
|
Command.displayName = CommandPrimitive.displayName;
|
||||||
|
|
||||||
interface CommandDialogProps extends DialogProps {}
|
interface CommandDialogProps extends DialogProps {}
|
||||||
|
|
||||||
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
|
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
|
||||||
return (
|
return (
|
||||||
<Dialog {...props}>
|
<Dialog {...props}>
|
||||||
<DialogContent className="overflow-hidden p-0 shadow-lg">
|
<DialogContent className='overflow-hidden p-0 shadow-lg'>
|
||||||
<Command className="[&_[cmdk-group-heading]]:px-2
|
<Command
|
||||||
|
className='[&_[cmdk-group-heading]]:px-2
|
||||||
[&_[cmdk-group-heading]]:font-medium
|
[&_[cmdk-group-heading]]:font-medium
|
||||||
[&_[cmdk-group-heading]]:text-muted-foreground
|
[&_[cmdk-group-heading]]:text-muted-foreground
|
||||||
[&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2
|
[&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2
|
||||||
[&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5
|
[&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5
|
||||||
[&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3
|
[&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3
|
||||||
[&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
|
[&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5'
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</Command>
|
</Command>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
const CommandInput = React.forwardRef<
|
const CommandInput = React.forwardRef<
|
||||||
React.ElementRef<typeof CommandPrimitive.Input>,
|
React.ElementRef<typeof CommandPrimitive.Input>,
|
||||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
|
<div className='flex items-center border-b px-3' cmdk-input-wrapper=''>
|
||||||
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
<Search className='mr-2 h-4 w-4 shrink-0 opacity-50' />
|
||||||
<CommandPrimitive.Input
|
<CommandPrimitive.Input
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-11 w-full rounded-md bg-transparent py-3 text-sm " +
|
'flex h-11 w-full rounded-md bg-transparent py-3 text-sm ' +
|
||||||
"outline-none placeholder:text-muted-foreground " +
|
'outline-none placeholder:text-muted-foreground ' +
|
||||||
"disabled:cursor-not-allowed disabled:opacity-50",
|
'disabled:cursor-not-allowed disabled:opacity-50',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))
|
));
|
||||||
|
|
||||||
CommandInput.displayName = CommandPrimitive.Input.displayName
|
CommandInput.displayName = CommandPrimitive.Input.displayName;
|
||||||
|
|
||||||
const CommandList = React.forwardRef<
|
const CommandList = React.forwardRef<
|
||||||
React.ElementRef<typeof CommandPrimitive.List>,
|
React.ElementRef<typeof CommandPrimitive.List>,
|
||||||
@ -69,12 +71,12 @@ const CommandList = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<CommandPrimitive.List
|
<CommandPrimitive.List
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
|
className={cn('max-h-[300px] overflow-y-auto overflow-x-hidden', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
|
|
||||||
CommandList.displayName = CommandPrimitive.List.displayName
|
CommandList.displayName = CommandPrimitive.List.displayName;
|
||||||
|
|
||||||
const CommandEmpty = React.forwardRef<
|
const CommandEmpty = React.forwardRef<
|
||||||
React.ElementRef<typeof CommandPrimitive.Empty>,
|
React.ElementRef<typeof CommandPrimitive.Empty>,
|
||||||
@ -82,12 +84,12 @@ const CommandEmpty = React.forwardRef<
|
|||||||
>((props, ref) => (
|
>((props, ref) => (
|
||||||
<CommandPrimitive.Empty
|
<CommandPrimitive.Empty
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className="py-6 text-center text-sm"
|
className='py-6 text-center text-sm'
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
|
|
||||||
CommandEmpty.displayName = CommandPrimitive.Empty.displayName
|
CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
|
||||||
|
|
||||||
const CommandGroup = React.forwardRef<
|
const CommandGroup = React.forwardRef<
|
||||||
React.ElementRef<typeof CommandPrimitive.Group>,
|
React.ElementRef<typeof CommandPrimitive.Group>,
|
||||||
@ -96,17 +98,17 @@ const CommandGroup = React.forwardRef<
|
|||||||
<CommandPrimitive.Group
|
<CommandPrimitive.Group
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 " +
|
'overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 ' +
|
||||||
"[&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs " +
|
'[&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs ' +
|
||||||
"[&_[cmdk-group-heading]]:font-medium " +
|
'[&_[cmdk-group-heading]]:font-medium ' +
|
||||||
"[&_[cmdk-group-heading]]:text-muted-foreground",
|
'[&_[cmdk-group-heading]]:text-muted-foreground',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
|
|
||||||
CommandGroup.displayName = CommandPrimitive.Group.displayName
|
CommandGroup.displayName = CommandPrimitive.Group.displayName;
|
||||||
|
|
||||||
const CommandSeparator = React.forwardRef<
|
const CommandSeparator = React.forwardRef<
|
||||||
React.ElementRef<typeof CommandPrimitive.Separator>,
|
React.ElementRef<typeof CommandPrimitive.Separator>,
|
||||||
@ -114,11 +116,11 @@ const CommandSeparator = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<CommandPrimitive.Separator
|
<CommandPrimitive.Separator
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("-mx-1 h-px bg-border", className)}
|
className={cn('-mx-1 h-px bg-border', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
CommandSeparator.displayName = CommandPrimitive.Separator.displayName
|
CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
|
||||||
|
|
||||||
const CommandItem = React.forwardRef<
|
const CommandItem = React.forwardRef<
|
||||||
React.ElementRef<typeof CommandPrimitive.Item>,
|
React.ElementRef<typeof CommandPrimitive.Item>,
|
||||||
@ -127,17 +129,17 @@ const CommandItem = React.forwardRef<
|
|||||||
<CommandPrimitive.Item
|
<CommandPrimitive.Item
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex cursor-default select-none items-center rounded-sm " +
|
'relative flex cursor-default select-none items-center rounded-sm ' +
|
||||||
"px-2 py-1.5 text-sm outline-none aria-selected:bg-accent " +
|
'px-2 py-1.5 text-sm outline-none aria-selected:bg-accent ' +
|
||||||
"aria-selected:text-accent-foreground " +
|
'aria-selected:text-accent-foreground ' +
|
||||||
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
|
|
||||||
CommandItem.displayName = CommandPrimitive.Item.displayName
|
CommandItem.displayName = CommandPrimitive.Item.displayName;
|
||||||
|
|
||||||
const CommandShortcut = ({
|
const CommandShortcut = ({
|
||||||
className,
|
className,
|
||||||
@ -146,14 +148,14 @@ const CommandShortcut = ({
|
|||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
"ml-auto text-xs tracking-widest text-muted-foreground",
|
'ml-auto text-xs tracking-widest text-muted-foreground',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
CommandShortcut.displayName = "CommandShortcut"
|
CommandShortcut.displayName = 'CommandShortcut';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Command,
|
Command,
|
||||||
@ -165,4 +167,4 @@ export {
|
|||||||
CommandItem,
|
CommandItem,
|
||||||
CommandShortcut,
|
CommandShortcut,
|
||||||
CommandSeparator,
|
CommandSeparator,
|
||||||
}
|
};
|
||||||
|
@ -1,41 +1,41 @@
|
|||||||
"use client"
|
'use client';
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import { format } from "date-fns"
|
import { format } from 'date-fns';
|
||||||
import { Calendar as CalendarIcon } from "lucide-react"
|
import { Calendar as CalendarIcon } from 'lucide-react';
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
import { Button } from "~/components/ui/shadcn/button"
|
import { Button } from '~/components/ui/shadcn/button';
|
||||||
import { Calendar } from "~/components/ui/shadcn/calendar"
|
import { Calendar } from '~/components/ui/shadcn/calendar';
|
||||||
import {
|
import {
|
||||||
Popover,
|
Popover,
|
||||||
PopoverContent,
|
PopoverContent,
|
||||||
PopoverTrigger,
|
PopoverTrigger,
|
||||||
} from "~/components/ui/shadcn/popover"
|
} from '~/components/ui/shadcn/popover';
|
||||||
|
|
||||||
export function DatePickerDemo() {
|
export function DatePickerDemo() {
|
||||||
const [date, setDate] = React.useState<Date>()
|
const [date, setDate] = React.useState<Date>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
variant={"outline"}
|
variant={'outline'}
|
||||||
className={cn(
|
className={cn(
|
||||||
"w-[280px] justify-start text-left font-normal",
|
'w-[280px] justify-start text-left font-normal',
|
||||||
!date && "text-muted-foreground"
|
!date && 'text-muted-foreground',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
<CalendarIcon className='mr-2 h-4 w-4' />
|
||||||
{date ? format(date, "PPP") : <span>Pick a date</span>}
|
{date ? format(date, 'PPP') : <span>Pick a date</span>}
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent className="w-auto p-0">
|
<PopoverContent className='w-auto p-0'>
|
||||||
<Calendar
|
<Calendar
|
||||||
mode="single"
|
mode='single'
|
||||||
selected={date}
|
selected={date}
|
||||||
onSelect={setDate}
|
onSelect={setDate}
|
||||||
//initialFocus // Causes an error idk if it's needed
|
//initialFocus // Causes an error idk if it's needed
|
||||||
/>
|
/>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
"use client"
|
'use client';
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import * as DialogPrimitive from "@radix-ui/react-dialog"
|
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
||||||
import { X } from "lucide-react"
|
import { X } from 'lucide-react';
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
|
|
||||||
const Dialog = DialogPrimitive.Root
|
const Dialog = DialogPrimitive.Root;
|
||||||
const DialogTrigger = DialogPrimitive.Trigger
|
const DialogTrigger = DialogPrimitive.Trigger;
|
||||||
const DialogPortal = DialogPrimitive.Portal
|
const DialogPortal = DialogPrimitive.Portal;
|
||||||
const DialogClose = DialogPrimitive.Close
|
const DialogClose = DialogPrimitive.Close;
|
||||||
|
|
||||||
const DialogOverlay = React.forwardRef<
|
const DialogOverlay = React.forwardRef<
|
||||||
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
||||||
@ -16,15 +16,15 @@ const DialogOverlay = React.forwardRef<
|
|||||||
<DialogPrimitive.Overlay
|
<DialogPrimitive.Overlay
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in " +
|
'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in ' +
|
||||||
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 " +
|
'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 ' +
|
||||||
"data-[state=open]:fade-in-0",
|
'data-[state=open]:fade-in-0',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
||||||
|
|
||||||
const DialogContent = React.forwardRef<
|
const DialogContent = React.forwardRef<
|
||||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||||
@ -35,31 +35,33 @@ const DialogContent = React.forwardRef<
|
|||||||
<DialogPrimitive.Content
|
<DialogPrimitive.Content
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] " +
|
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] ' +
|
||||||
"translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 " +
|
'translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 ' +
|
||||||
"data-[state=open]:animate-in data-[state=closed]:animate-out " +
|
'data-[state=open]:animate-in data-[state=closed]:animate-out ' +
|
||||||
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 " +
|
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 ' +
|
||||||
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 " +
|
'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 ' +
|
||||||
"data-[state=closed]:slide-out-to-left-1/2 " +
|
'data-[state=closed]:slide-out-to-left-1/2 ' +
|
||||||
"data-[state=closed]:slide-out-to-top-[48%] " +
|
'data-[state=closed]:slide-out-to-top-[48%] ' +
|
||||||
"data-[state=open]:slide-in-from-left-1/2 " +
|
'data-[state=open]:slide-in-from-left-1/2 ' +
|
||||||
"data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
'data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70
|
<DialogPrimitive.Close
|
||||||
|
className='absolute right-4 top-4 rounded-sm opacity-70
|
||||||
ring-offset-background transition-opacity hover:opacity-100 focus:outline-none
|
ring-offset-background transition-opacity hover:opacity-100 focus:outline-none
|
||||||
focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none
|
focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none
|
||||||
data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
data-[state=open]:bg-accent data-[state=open]:text-muted-foreground'
|
||||||
<X className="h-4 w-4" />
|
>
|
||||||
<span className="sr-only">Close</span>
|
<X className='h-4 w-4' />
|
||||||
|
<span className='sr-only'>Close</span>
|
||||||
</DialogPrimitive.Close>
|
</DialogPrimitive.Close>
|
||||||
</DialogPrimitive.Content>
|
</DialogPrimitive.Content>
|
||||||
</DialogPortal>
|
</DialogPortal>
|
||||||
))
|
));
|
||||||
DialogContent.displayName = DialogPrimitive.Content.displayName
|
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
||||||
|
|
||||||
const DialogHeader = ({
|
const DialogHeader = ({
|
||||||
className,
|
className,
|
||||||
@ -67,13 +69,13 @@ const DialogHeader = ({
|
|||||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex flex-col space-y-1.5 text-center sm:text-left",
|
'flex flex-col space-y-1.5 text-center sm:text-left',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
DialogHeader.displayName = "DialogHeader"
|
DialogHeader.displayName = 'DialogHeader';
|
||||||
|
|
||||||
const DialogFooter = ({
|
const DialogFooter = ({
|
||||||
className,
|
className,
|
||||||
@ -81,13 +83,13 @@ const DialogFooter = ({
|
|||||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
DialogFooter.displayName = "DialogFooter"
|
DialogFooter.displayName = 'DialogFooter';
|
||||||
|
|
||||||
const DialogTitle = React.forwardRef<
|
const DialogTitle = React.forwardRef<
|
||||||
React.ElementRef<typeof DialogPrimitive.Title>,
|
React.ElementRef<typeof DialogPrimitive.Title>,
|
||||||
@ -96,13 +98,13 @@ const DialogTitle = React.forwardRef<
|
|||||||
<DialogPrimitive.Title
|
<DialogPrimitive.Title
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"text-lg font-semibold leading-none tracking-tight",
|
'text-lg font-semibold leading-none tracking-tight',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DialogTitle.displayName = DialogPrimitive.Title.displayName
|
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
||||||
|
|
||||||
const DialogDescription = React.forwardRef<
|
const DialogDescription = React.forwardRef<
|
||||||
React.ElementRef<typeof DialogPrimitive.Description>,
|
React.ElementRef<typeof DialogPrimitive.Description>,
|
||||||
@ -110,11 +112,11 @@ const DialogDescription = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<DialogPrimitive.Description
|
<DialogPrimitive.Description
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("text-sm text-muted-foreground", className)}
|
className={cn('text-sm text-muted-foreground', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DialogDescription.displayName = DialogPrimitive.Description.displayName
|
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Dialog,
|
Dialog,
|
||||||
@ -127,4 +129,4 @@ export {
|
|||||||
DialogFooter,
|
DialogFooter,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogDescription,
|
DialogDescription,
|
||||||
}
|
};
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
"use client"
|
'use client';
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import { Drawer as DrawerPrimitive } from "vaul"
|
import { Drawer as DrawerPrimitive } from 'vaul';
|
||||||
|
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
|
|
||||||
const Drawer = ({
|
const Drawer = ({
|
||||||
shouldScaleBackground = true,
|
shouldScaleBackground = true,
|
||||||
@ -13,14 +13,14 @@ const Drawer = ({
|
|||||||
shouldScaleBackground={shouldScaleBackground}
|
shouldScaleBackground={shouldScaleBackground}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
Drawer.displayName = "Drawer"
|
Drawer.displayName = 'Drawer';
|
||||||
|
|
||||||
const DrawerTrigger = DrawerPrimitive.Trigger
|
const DrawerTrigger = DrawerPrimitive.Trigger;
|
||||||
|
|
||||||
const DrawerPortal = DrawerPrimitive.Portal
|
const DrawerPortal = DrawerPrimitive.Portal;
|
||||||
|
|
||||||
const DrawerClose = DrawerPrimitive.Close
|
const DrawerClose = DrawerPrimitive.Close;
|
||||||
|
|
||||||
const DrawerOverlay = React.forwardRef<
|
const DrawerOverlay = React.forwardRef<
|
||||||
React.ElementRef<typeof DrawerPrimitive.Overlay>,
|
React.ElementRef<typeof DrawerPrimitive.Overlay>,
|
||||||
@ -28,11 +28,11 @@ const DrawerOverlay = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<DrawerPrimitive.Overlay
|
<DrawerPrimitive.Overlay
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("fixed inset-0 z-50 bg-black/80", className)}
|
className={cn('fixed inset-0 z-50 bg-black/80', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName
|
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName;
|
||||||
|
|
||||||
const DrawerContent = React.forwardRef<
|
const DrawerContent = React.forwardRef<
|
||||||
React.ElementRef<typeof DrawerPrimitive.Content>,
|
React.ElementRef<typeof DrawerPrimitive.Content>,
|
||||||
@ -43,39 +43,39 @@ const DrawerContent = React.forwardRef<
|
|||||||
<DrawerPrimitive.Content
|
<DrawerPrimitive.Content
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
|
'fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
|
<div className='mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted' />
|
||||||
{children}
|
{children}
|
||||||
</DrawerPrimitive.Content>
|
</DrawerPrimitive.Content>
|
||||||
</DrawerPortal>
|
</DrawerPortal>
|
||||||
))
|
));
|
||||||
DrawerContent.displayName = "DrawerContent"
|
DrawerContent.displayName = 'DrawerContent';
|
||||||
|
|
||||||
const DrawerHeader = ({
|
const DrawerHeader = ({
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
<div
|
<div
|
||||||
className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
|
className={cn('grid gap-1.5 p-4 text-center sm:text-left', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
DrawerHeader.displayName = "DrawerHeader"
|
DrawerHeader.displayName = 'DrawerHeader';
|
||||||
|
|
||||||
const DrawerFooter = ({
|
const DrawerFooter = ({
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
<div
|
<div
|
||||||
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
|
className={cn('mt-auto flex flex-col gap-2 p-4', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
DrawerFooter.displayName = "DrawerFooter"
|
DrawerFooter.displayName = 'DrawerFooter';
|
||||||
|
|
||||||
const DrawerTitle = React.forwardRef<
|
const DrawerTitle = React.forwardRef<
|
||||||
React.ElementRef<typeof DrawerPrimitive.Title>,
|
React.ElementRef<typeof DrawerPrimitive.Title>,
|
||||||
@ -84,13 +84,13 @@ const DrawerTitle = React.forwardRef<
|
|||||||
<DrawerPrimitive.Title
|
<DrawerPrimitive.Title
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"text-lg font-semibold leading-none tracking-tight",
|
'text-lg font-semibold leading-none tracking-tight',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DrawerTitle.displayName = DrawerPrimitive.Title.displayName
|
DrawerTitle.displayName = DrawerPrimitive.Title.displayName;
|
||||||
|
|
||||||
const DrawerDescription = React.forwardRef<
|
const DrawerDescription = React.forwardRef<
|
||||||
React.ElementRef<typeof DrawerPrimitive.Description>,
|
React.ElementRef<typeof DrawerPrimitive.Description>,
|
||||||
@ -98,11 +98,11 @@ const DrawerDescription = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<DrawerPrimitive.Description
|
<DrawerPrimitive.Description
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("text-sm text-muted-foreground", className)}
|
className={cn('text-sm text-muted-foreground', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DrawerDescription.displayName = DrawerPrimitive.Description.displayName
|
DrawerDescription.displayName = DrawerPrimitive.Description.displayName;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Drawer,
|
Drawer,
|
||||||
@ -115,4 +115,4 @@ export {
|
|||||||
DrawerFooter,
|
DrawerFooter,
|
||||||
DrawerTitle,
|
DrawerTitle,
|
||||||
DrawerDescription,
|
DrawerDescription,
|
||||||
}
|
};
|
||||||
|
@ -1,38 +1,38 @@
|
|||||||
"use client"
|
'use client';
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
|
||||||
import { Check, ChevronRight, Circle } from "lucide-react"
|
import { Check, ChevronRight, Circle } from 'lucide-react';
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
|
|
||||||
const DropdownMenu = DropdownMenuPrimitive.Root
|
const DropdownMenu = DropdownMenuPrimitive.Root;
|
||||||
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
|
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
||||||
const DropdownMenuGroup = DropdownMenuPrimitive.Group
|
const DropdownMenuGroup = DropdownMenuPrimitive.Group;
|
||||||
const DropdownMenuPortal = DropdownMenuPrimitive.Portal
|
const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
|
||||||
const DropdownMenuSub = DropdownMenuPrimitive.Sub
|
const DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
||||||
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
|
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
||||||
|
|
||||||
const DropdownMenuSubTrigger = React.forwardRef<
|
const DropdownMenuSubTrigger = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
||||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||||
inset?: boolean
|
inset?: boolean;
|
||||||
}
|
}
|
||||||
>(({ className, inset, children, ...props }, ref) => (
|
>(({ className, inset, children, ...props }, ref) => (
|
||||||
<DropdownMenuPrimitive.SubTrigger
|
<DropdownMenuPrimitive.SubTrigger
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex cursor-default select-none items-center rounded-sm " +
|
'flex cursor-default select-none items-center rounded-sm ' +
|
||||||
"px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
|
'px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent',
|
||||||
inset && "pl-8",
|
inset && 'pl-8',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
<ChevronRight className="ml-auto h-4 w-4" />
|
<ChevronRight className='ml-auto h-4 w-4' />
|
||||||
</DropdownMenuPrimitive.SubTrigger>
|
</DropdownMenuPrimitive.SubTrigger>
|
||||||
))
|
));
|
||||||
DropdownMenuSubTrigger.displayName =
|
DropdownMenuSubTrigger.displayName =
|
||||||
DropdownMenuPrimitive.SubTrigger.displayName
|
DropdownMenuPrimitive.SubTrigger.displayName;
|
||||||
|
|
||||||
const DropdownMenuSubContent = React.forwardRef<
|
const DropdownMenuSubContent = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
||||||
@ -41,20 +41,20 @@ const DropdownMenuSubContent = React.forwardRef<
|
|||||||
<DropdownMenuPrimitive.SubContent
|
<DropdownMenuPrimitive.SubContent
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 " +
|
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 ' +
|
||||||
"text-popover-foreground shadow-lg data-[state=open]:animate-in " +
|
'text-popover-foreground shadow-lg data-[state=open]:animate-in ' +
|
||||||
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 " +
|
'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 ' +
|
||||||
"data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 " +
|
'data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 ' +
|
||||||
"data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 " +
|
'data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 ' +
|
||||||
"data-[side=left]:slide-in-from-right-2 " +
|
'data-[side=left]:slide-in-from-right-2 ' +
|
||||||
"data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
'data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DropdownMenuSubContent.displayName =
|
DropdownMenuSubContent.displayName =
|
||||||
DropdownMenuPrimitive.SubContent.displayName
|
DropdownMenuPrimitive.SubContent.displayName;
|
||||||
|
|
||||||
const DropdownMenuContent = React.forwardRef<
|
const DropdownMenuContent = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
||||||
@ -65,41 +65,41 @@ const DropdownMenuContent = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 " +
|
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 ' +
|
||||||
"text-popover-foreground shadow-md data-[state=open]:animate-in " +
|
'text-popover-foreground shadow-md data-[state=open]:animate-in ' +
|
||||||
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 " +
|
'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 ' +
|
||||||
"data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 " +
|
'data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 ' +
|
||||||
"data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 " +
|
'data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 ' +
|
||||||
"data-[side=left]:slide-in-from-right-2 " +
|
'data-[side=left]:slide-in-from-right-2 ' +
|
||||||
"data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
'data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</DropdownMenuPrimitive.Portal>
|
</DropdownMenuPrimitive.Portal>
|
||||||
))
|
));
|
||||||
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
|
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
||||||
|
|
||||||
const DropdownMenuItem = React.forwardRef<
|
const DropdownMenuItem = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
||||||
inset?: boolean
|
inset?: boolean;
|
||||||
}
|
}
|
||||||
>(({ className, inset, ...props }, ref) => (
|
>(({ className, inset, ...props }, ref) => (
|
||||||
<DropdownMenuPrimitive.Item
|
<DropdownMenuPrimitive.Item
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex cursor-default select-none items-center rounded-sm " +
|
'relative flex cursor-default select-none items-center rounded-sm ' +
|
||||||
"px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent " +
|
'px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent ' +
|
||||||
"focus:text-accent-foreground data-[disabled]:pointer-events-none " +
|
'focus:text-accent-foreground data-[disabled]:pointer-events-none ' +
|
||||||
"data-[disabled]:opacity-50",
|
'data-[disabled]:opacity-50',
|
||||||
inset && "pl-8",
|
inset && 'pl-8',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
|
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
||||||
|
|
||||||
const DropdownMenuCheckboxItem = React.forwardRef<
|
const DropdownMenuCheckboxItem = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
||||||
@ -108,25 +108,25 @@ const DropdownMenuCheckboxItem = React.forwardRef<
|
|||||||
<DropdownMenuPrimitive.CheckboxItem
|
<DropdownMenuPrimitive.CheckboxItem
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex cursor-default select-none items-center rounded-sm " +
|
'relative flex cursor-default select-none items-center rounded-sm ' +
|
||||||
"py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent " +
|
'py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent ' +
|
||||||
"focus:text-accent-foreground data-[disabled]:pointer-events-none " +
|
'focus:text-accent-foreground data-[disabled]:pointer-events-none ' +
|
||||||
"data-[disabled]:opacity-50",
|
'data-[disabled]:opacity-50',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
checked={checked}
|
checked={checked}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
<span className='absolute left-2 flex h-3.5 w-3.5 items-center justify-center'>
|
||||||
<DropdownMenuPrimitive.ItemIndicator>
|
<DropdownMenuPrimitive.ItemIndicator>
|
||||||
<Check className="h-4 w-4" />
|
<Check className='h-4 w-4' />
|
||||||
</DropdownMenuPrimitive.ItemIndicator>
|
</DropdownMenuPrimitive.ItemIndicator>
|
||||||
</span>
|
</span>
|
||||||
{children}
|
{children}
|
||||||
</DropdownMenuPrimitive.CheckboxItem>
|
</DropdownMenuPrimitive.CheckboxItem>
|
||||||
))
|
));
|
||||||
DropdownMenuCheckboxItem.displayName =
|
DropdownMenuCheckboxItem.displayName =
|
||||||
DropdownMenuPrimitive.CheckboxItem.displayName
|
DropdownMenuPrimitive.CheckboxItem.displayName;
|
||||||
|
|
||||||
const DropdownMenuRadioItem = React.forwardRef<
|
const DropdownMenuRadioItem = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
||||||
@ -135,41 +135,41 @@ const DropdownMenuRadioItem = React.forwardRef<
|
|||||||
<DropdownMenuPrimitive.RadioItem
|
<DropdownMenuPrimitive.RadioItem
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex cursor-default select-none items-center rounded-sm " +
|
'relative flex cursor-default select-none items-center rounded-sm ' +
|
||||||
"py-1.5 pl-8 pr-2 text-sm outline-none transition-colors " +
|
'py-1.5 pl-8 pr-2 text-sm outline-none transition-colors ' +
|
||||||
"focus:bg-accent focus:text-accent-foreground " +
|
'focus:bg-accent focus:text-accent-foreground ' +
|
||||||
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
<span className='absolute left-2 flex h-3.5 w-3.5 items-center justify-center'>
|
||||||
<DropdownMenuPrimitive.ItemIndicator>
|
<DropdownMenuPrimitive.ItemIndicator>
|
||||||
<Circle className="h-2 w-2 fill-current" />
|
<Circle className='h-2 w-2 fill-current' />
|
||||||
</DropdownMenuPrimitive.ItemIndicator>
|
</DropdownMenuPrimitive.ItemIndicator>
|
||||||
</span>
|
</span>
|
||||||
{children}
|
{children}
|
||||||
</DropdownMenuPrimitive.RadioItem>
|
</DropdownMenuPrimitive.RadioItem>
|
||||||
))
|
));
|
||||||
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
|
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
|
||||||
|
|
||||||
const DropdownMenuLabel = React.forwardRef<
|
const DropdownMenuLabel = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
||||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
||||||
inset?: boolean
|
inset?: boolean;
|
||||||
}
|
}
|
||||||
>(({ className, inset, ...props }, ref) => (
|
>(({ className, inset, ...props }, ref) => (
|
||||||
<DropdownMenuPrimitive.Label
|
<DropdownMenuPrimitive.Label
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"px-2 py-1.5 text-sm font-semibold",
|
'px-2 py-1.5 text-sm font-semibold',
|
||||||
inset && "pl-8",
|
inset && 'pl-8',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
|
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
|
||||||
|
|
||||||
const DropdownMenuSeparator = React.forwardRef<
|
const DropdownMenuSeparator = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
||||||
@ -177,11 +177,11 @@ const DropdownMenuSeparator = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<DropdownMenuPrimitive.Separator
|
<DropdownMenuPrimitive.Separator
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
className={cn('-mx-1 my-1 h-px bg-muted', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
|
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
||||||
|
|
||||||
const DropdownMenuShortcut = ({
|
const DropdownMenuShortcut = ({
|
||||||
className,
|
className,
|
||||||
@ -189,12 +189,12 @@ const DropdownMenuShortcut = ({
|
|||||||
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
|
className={cn('ml-auto text-xs tracking-widest opacity-60', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
|
DropdownMenuShortcut.displayName = 'DropdownMenuShortcut';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
@ -212,4 +212,4 @@ export {
|
|||||||
DropdownMenuSubContent,
|
DropdownMenuSubContent,
|
||||||
DropdownMenuSubTrigger,
|
DropdownMenuSubTrigger,
|
||||||
DropdownMenuRadioGroup,
|
DropdownMenuRadioGroup,
|
||||||
}
|
};
|
||||||
|
@ -1,36 +1,28 @@
|
|||||||
"use client"
|
'use client';
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import type * as LabelPrimitive from "@radix-ui/react-label"
|
import type * as LabelPrimitive from '@radix-ui/react-label';
|
||||||
import { Slot } from "@radix-ui/react-slot"
|
import { Slot } from '@radix-ui/react-slot';
|
||||||
import type {
|
import type { ControllerProps, FieldPath, FieldValues } from 'react-hook-form';
|
||||||
ControllerProps,
|
import { Controller, FormProvider, useFormContext } from 'react-hook-form';
|
||||||
FieldPath,
|
import { cn } from '~/lib/utils';
|
||||||
FieldValues,
|
import { Label } from '~/components/ui/shadcn/label';
|
||||||
} from "react-hook-form"
|
|
||||||
import {
|
|
||||||
Controller,
|
|
||||||
FormProvider,
|
|
||||||
useFormContext,
|
|
||||||
} from "react-hook-form"
|
|
||||||
import { cn } from "~/lib/utils"
|
|
||||||
import { Label } from "~/components/ui/shadcn/label"
|
|
||||||
|
|
||||||
const Form = FormProvider
|
const Form = FormProvider;
|
||||||
|
|
||||||
type FormFieldContextValue<
|
type FormFieldContextValue<
|
||||||
TFieldValues extends FieldValues = FieldValues,
|
TFieldValues extends FieldValues = FieldValues,
|
||||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
||||||
> = {
|
> = {
|
||||||
name: TName
|
name: TName;
|
||||||
}
|
};
|
||||||
|
|
||||||
const FormFieldContext = React.createContext<FormFieldContextValue>(
|
const FormFieldContext = React.createContext<FormFieldContextValue>(
|
||||||
{} as FormFieldContextValue
|
{} as FormFieldContextValue,
|
||||||
)
|
);
|
||||||
|
|
||||||
const FormField = <
|
const FormField = <
|
||||||
TFieldValues extends FieldValues = FieldValues,
|
TFieldValues extends FieldValues = FieldValues,
|
||||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
||||||
>({
|
>({
|
||||||
...props
|
...props
|
||||||
}: ControllerProps<TFieldValues, TName>) => {
|
}: ControllerProps<TFieldValues, TName>) => {
|
||||||
@ -38,21 +30,21 @@ const FormField = <
|
|||||||
<FormFieldContext.Provider value={{ name: props.name }}>
|
<FormFieldContext.Provider value={{ name: props.name }}>
|
||||||
<Controller {...props} />
|
<Controller {...props} />
|
||||||
</FormFieldContext.Provider>
|
</FormFieldContext.Provider>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
const useFormField = () => {
|
const useFormField = () => {
|
||||||
const fieldContext = React.useContext(FormFieldContext)
|
const fieldContext = React.useContext(FormFieldContext);
|
||||||
const itemContext = React.useContext(FormItemContext)
|
const itemContext = React.useContext(FormItemContext);
|
||||||
const { getFieldState, formState } = useFormContext()
|
const { getFieldState, formState } = useFormContext();
|
||||||
|
|
||||||
const fieldState = getFieldState(fieldContext.name, formState)
|
const fieldState = getFieldState(fieldContext.name, formState);
|
||||||
|
|
||||||
if (!fieldContext) {
|
if (!fieldContext) {
|
||||||
throw new Error("useFormField should be used within <FormField>")
|
throw new Error('useFormField should be used within <FormField>');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { id } = itemContext
|
const { id } = itemContext;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
@ -61,53 +53,54 @@ const useFormField = () => {
|
|||||||
formDescriptionId: `${id}-form-item-description`,
|
formDescriptionId: `${id}-form-item-description`,
|
||||||
formMessageId: `${id}-form-item-message`,
|
formMessageId: `${id}-form-item-message`,
|
||||||
...fieldState,
|
...fieldState,
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
type FormItemContextValue = {
|
type FormItemContextValue = {
|
||||||
id: string
|
id: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
const FormItemContext = React.createContext<FormItemContextValue>(
|
const FormItemContext = React.createContext<FormItemContextValue>(
|
||||||
{} as FormItemContextValue
|
{} as FormItemContextValue,
|
||||||
)
|
);
|
||||||
|
|
||||||
const FormItem = React.forwardRef<
|
const FormItem = React.forwardRef<
|
||||||
HTMLDivElement,
|
HTMLDivElement,
|
||||||
React.HTMLAttributes<HTMLDivElement>
|
React.HTMLAttributes<HTMLDivElement>
|
||||||
>(({ className, ...props }, ref) => {
|
>(({ className, ...props }, ref) => {
|
||||||
const id = React.useId()
|
const id = React.useId();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormItemContext.Provider value={{ id }}>
|
<FormItemContext.Provider value={{ id }}>
|
||||||
<div ref={ref} className={cn("space-y-2", className)} {...props} />
|
<div ref={ref} className={cn('space-y-2', className)} {...props} />
|
||||||
</FormItemContext.Provider>
|
</FormItemContext.Provider>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormItem.displayName = "FormItem"
|
FormItem.displayName = 'FormItem';
|
||||||
|
|
||||||
const FormLabel = React.forwardRef<
|
const FormLabel = React.forwardRef<
|
||||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
|
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
|
||||||
>(({ className, ...props }, ref) => {
|
>(({ className, ...props }, ref) => {
|
||||||
const { error, formItemId } = useFormField()
|
const { error, formItemId } = useFormField();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Label
|
<Label
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(error && "text-destructive", className)}
|
className={cn(error && 'text-destructive', className)}
|
||||||
htmlFor={formItemId}
|
htmlFor={formItemId}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormLabel.displayName = "FormLabel"
|
FormLabel.displayName = 'FormLabel';
|
||||||
|
|
||||||
const FormControl = React.forwardRef<
|
const FormControl = React.forwardRef<
|
||||||
React.ElementRef<typeof Slot>,
|
React.ElementRef<typeof Slot>,
|
||||||
React.ComponentPropsWithoutRef<typeof Slot>
|
React.ComponentPropsWithoutRef<typeof Slot>
|
||||||
>(({ ...props }, ref) => {
|
>(({ ...props }, ref) => {
|
||||||
const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
|
const { error, formItemId, formDescriptionId, formMessageId } =
|
||||||
|
useFormField();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slot
|
<Slot
|
||||||
@ -121,50 +114,50 @@ const FormControl = React.forwardRef<
|
|||||||
aria-invalid={!!error}
|
aria-invalid={!!error}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormControl.displayName = "FormControl"
|
FormControl.displayName = 'FormControl';
|
||||||
|
|
||||||
const FormDescription = React.forwardRef<
|
const FormDescription = React.forwardRef<
|
||||||
HTMLParagraphElement,
|
HTMLParagraphElement,
|
||||||
React.HTMLAttributes<HTMLParagraphElement>
|
React.HTMLAttributes<HTMLParagraphElement>
|
||||||
>(({ className, ...props }, ref) => {
|
>(({ className, ...props }, ref) => {
|
||||||
const { formDescriptionId } = useFormField()
|
const { formDescriptionId } = useFormField();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<p
|
<p
|
||||||
ref={ref}
|
ref={ref}
|
||||||
id={formDescriptionId}
|
id={formDescriptionId}
|
||||||
className={cn("text-sm text-muted-foreground", className)}
|
className={cn('text-sm text-muted-foreground', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormDescription.displayName = "FormDescription"
|
FormDescription.displayName = 'FormDescription';
|
||||||
|
|
||||||
const FormMessage = React.forwardRef<
|
const FormMessage = React.forwardRef<
|
||||||
HTMLParagraphElement,
|
HTMLParagraphElement,
|
||||||
React.HTMLAttributes<HTMLParagraphElement>
|
React.HTMLAttributes<HTMLParagraphElement>
|
||||||
>(({ className, children, ...props }, ref) => {
|
>(({ className, children, ...props }, ref) => {
|
||||||
const { error, formMessageId } = useFormField()
|
const { error, formMessageId } = useFormField();
|
||||||
const body = error ? String(error?.message) : children
|
const body = error ? String(error?.message) : children;
|
||||||
|
|
||||||
if (!body) {
|
if (!body) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<p
|
<p
|
||||||
ref={ref}
|
ref={ref}
|
||||||
id={formMessageId}
|
id={formMessageId}
|
||||||
className={cn("text-sm font-medium text-destructive", className)}
|
className={cn('text-sm font-medium text-destructive', className)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{body}
|
{body}
|
||||||
</p>
|
</p>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormMessage.displayName = "FormMessage"
|
FormMessage.displayName = 'FormMessage';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
useFormField,
|
useFormField,
|
||||||
@ -175,4 +168,4 @@ export {
|
|||||||
FormDescription,
|
FormDescription,
|
||||||
FormMessage,
|
FormMessage,
|
||||||
FormField,
|
FormField,
|
||||||
}
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
|
|
||||||
export interface InputProps
|
export interface InputProps
|
||||||
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||||
@ -10,18 +10,18 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|||||||
<input
|
<input
|
||||||
type={type}
|
type={type}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-10 w-full rounded-md border border-input bg-background px-3 " +
|
'flex h-10 w-full rounded-md border border-input bg-background px-3 ' +
|
||||||
"py-2 text-sm ring-offset-background file:border-0 file:bg-transparent " +
|
'py-2 text-sm ring-offset-background file:border-0 file:bg-transparent ' +
|
||||||
"file:text-sm file:font-medium placeholder:text-muted-foreground " +
|
'file:text-sm file:font-medium placeholder:text-muted-foreground ' +
|
||||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring " +
|
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ' +
|
||||||
"focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
'focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
Input.displayName = "Input"
|
Input.displayName = 'Input';
|
||||||
export { Input }
|
export { Input };
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
"use client"
|
'use client';
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import * as LabelPrimitive from "@radix-ui/react-label"
|
import * as LabelPrimitive from '@radix-ui/react-label';
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from 'class-variance-authority';
|
||||||
|
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
|
|
||||||
const labelVariants = cva(
|
const labelVariants = cva(
|
||||||
"text-sm font-medium leading-none " +
|
'text-sm font-medium leading-none ' +
|
||||||
"peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
'peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
|
||||||
)
|
);
|
||||||
|
|
||||||
const Label = React.forwardRef<
|
const Label = React.forwardRef<
|
||||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||||
@ -21,7 +21,7 @@ const Label = React.forwardRef<
|
|||||||
className={cn(labelVariants(), className)}
|
className={cn(labelVariants(), className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
Label.displayName = LabelPrimitive.Root.displayName
|
Label.displayName = LabelPrimitive.Root.displayName;
|
||||||
|
|
||||||
export { Label }
|
export { Label };
|
||||||
|
@ -1,111 +1,111 @@
|
|||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react"
|
import { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react';
|
||||||
|
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
import { buttonVariants } from "~/components/ui/shadcn/button"
|
import { buttonVariants } from '~/components/ui/shadcn/button';
|
||||||
import type { ButtonProps } from "~/components/ui/shadcn/button"
|
import type { ButtonProps } from '~/components/ui/shadcn/button';
|
||||||
|
|
||||||
const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
|
const Pagination = ({ className, ...props }: React.ComponentProps<'nav'>) => (
|
||||||
<nav
|
<nav
|
||||||
role="navigation"
|
role='navigation'
|
||||||
aria-label="pagination"
|
aria-label='pagination'
|
||||||
className={cn("mx-auto flex w-full justify-center", className)}
|
className={cn('mx-auto flex w-full justify-center', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
Pagination.displayName = "Pagination"
|
Pagination.displayName = 'Pagination';
|
||||||
|
|
||||||
const PaginationContent = React.forwardRef<
|
const PaginationContent = React.forwardRef<
|
||||||
HTMLUListElement,
|
HTMLUListElement,
|
||||||
React.ComponentProps<"ul">
|
React.ComponentProps<'ul'>
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<ul
|
<ul
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("flex flex-row items-center gap-1", className)}
|
className={cn('flex flex-row items-center gap-1', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
PaginationContent.displayName = "PaginationContent"
|
PaginationContent.displayName = 'PaginationContent';
|
||||||
|
|
||||||
const PaginationItem = React.forwardRef<
|
const PaginationItem = React.forwardRef<
|
||||||
HTMLLIElement,
|
HTMLLIElement,
|
||||||
React.ComponentProps<"li">
|
React.ComponentProps<'li'>
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<li ref={ref} className={cn("", className)} {...props} />
|
<li ref={ref} className={cn('', className)} {...props} />
|
||||||
))
|
));
|
||||||
PaginationItem.displayName = "PaginationItem"
|
PaginationItem.displayName = 'PaginationItem';
|
||||||
|
|
||||||
type PaginationLinkProps = {
|
type PaginationLinkProps = {
|
||||||
isActive?: boolean
|
isActive?: boolean;
|
||||||
} & Pick<ButtonProps, "size"> &
|
} & Pick<ButtonProps, 'size'> &
|
||||||
React.ComponentProps<"a">
|
React.ComponentProps<'a'>;
|
||||||
|
|
||||||
const PaginationLink = ({
|
const PaginationLink = ({
|
||||||
className,
|
className,
|
||||||
isActive,
|
isActive,
|
||||||
size = "icon",
|
size = 'icon',
|
||||||
...props
|
...props
|
||||||
}: PaginationLinkProps) => (
|
}: PaginationLinkProps) => (
|
||||||
<a
|
<a
|
||||||
aria-current={isActive ? "page" : undefined}
|
aria-current={isActive ? 'page' : undefined}
|
||||||
className={cn(
|
className={cn(
|
||||||
buttonVariants({
|
buttonVariants({
|
||||||
variant: isActive ? "outline" : "ghost",
|
variant: isActive ? 'outline' : 'ghost',
|
||||||
size,
|
size,
|
||||||
}),
|
}),
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
PaginationLink.displayName = "PaginationLink"
|
PaginationLink.displayName = 'PaginationLink';
|
||||||
|
|
||||||
const PaginationPrevious = ({
|
const PaginationPrevious = ({
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof PaginationLink>) => (
|
}: React.ComponentProps<typeof PaginationLink>) => (
|
||||||
<PaginationLink
|
<PaginationLink
|
||||||
aria-label="Go to previous page"
|
aria-label='Go to previous page'
|
||||||
size="default"
|
size='default'
|
||||||
className={cn("gap-1 pl-2.5", className)}
|
className={cn('gap-1 pl-2.5', className)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ChevronLeft className="h-4 w-4" />
|
<ChevronLeft className='h-4 w-4' />
|
||||||
<span>Previous</span>
|
<span>Previous</span>
|
||||||
</PaginationLink>
|
</PaginationLink>
|
||||||
)
|
);
|
||||||
PaginationPrevious.displayName = "PaginationPrevious"
|
PaginationPrevious.displayName = 'PaginationPrevious';
|
||||||
|
|
||||||
const PaginationNext = ({
|
const PaginationNext = ({
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof PaginationLink>) => (
|
}: React.ComponentProps<typeof PaginationLink>) => (
|
||||||
<PaginationLink
|
<PaginationLink
|
||||||
aria-label="Go to next page"
|
aria-label='Go to next page'
|
||||||
size="default"
|
size='default'
|
||||||
className={cn("gap-1 pr-2.5", className)}
|
className={cn('gap-1 pr-2.5', className)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<span>Next</span>
|
<span>Next</span>
|
||||||
<ChevronRight className="h-4 w-4" />
|
<ChevronRight className='h-4 w-4' />
|
||||||
</PaginationLink>
|
</PaginationLink>
|
||||||
)
|
);
|
||||||
PaginationNext.displayName = "PaginationNext"
|
PaginationNext.displayName = 'PaginationNext';
|
||||||
|
|
||||||
const PaginationEllipsis = ({
|
const PaginationEllipsis = ({
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<"span">) => (
|
}: React.ComponentProps<'span'>) => (
|
||||||
<span
|
<span
|
||||||
aria-hidden
|
aria-hidden
|
||||||
className={cn("flex h-9 w-9 items-center justify-center", className)}
|
className={cn('flex h-9 w-9 items-center justify-center', className)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<MoreHorizontal className="h-4 w-4" />
|
<MoreHorizontal className='h-4 w-4' />
|
||||||
<span className="sr-only">More pages</span>
|
<span className='sr-only'>More pages</span>
|
||||||
</span>
|
</span>
|
||||||
)
|
);
|
||||||
PaginationEllipsis.displayName = "PaginationEllipsis"
|
PaginationEllipsis.displayName = 'PaginationEllipsis';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Pagination,
|
Pagination,
|
||||||
@ -115,4 +115,4 @@ export {
|
|||||||
PaginationLink,
|
PaginationLink,
|
||||||
PaginationNext,
|
PaginationNext,
|
||||||
PaginationPrevious,
|
PaginationPrevious,
|
||||||
}
|
};
|
||||||
|
@ -1,36 +1,36 @@
|
|||||||
"use client"
|
'use client';
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
||||||
|
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
|
|
||||||
const Popover = PopoverPrimitive.Root
|
const Popover = PopoverPrimitive.Root;
|
||||||
|
|
||||||
const PopoverTrigger = PopoverPrimitive.Trigger
|
const PopoverTrigger = PopoverPrimitive.Trigger;
|
||||||
|
|
||||||
const PopoverContent = React.forwardRef<
|
const PopoverContent = React.forwardRef<
|
||||||
React.ElementRef<typeof PopoverPrimitive.Content>,
|
React.ElementRef<typeof PopoverPrimitive.Content>,
|
||||||
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
|
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
|
||||||
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
|
||||||
<PopoverPrimitive.Portal>
|
<PopoverPrimitive.Portal>
|
||||||
<PopoverPrimitive.Content
|
<PopoverPrimitive.Content
|
||||||
ref={ref}
|
ref={ref}
|
||||||
align={align}
|
align={align}
|
||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md " +
|
'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md ' +
|
||||||
"outline-none data-[state=open]:animate-in data-[state=closed]:animate-out " +
|
'outline-none data-[state=open]:animate-in data-[state=closed]:animate-out ' +
|
||||||
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 " +
|
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 ' +
|
||||||
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 " +
|
'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 ' +
|
||||||
"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 " +
|
'data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 ' +
|
||||||
"data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
'data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</PopoverPrimitive.Portal>
|
</PopoverPrimitive.Portal>
|
||||||
))
|
));
|
||||||
PopoverContent.displayName = PopoverPrimitive.Content.displayName
|
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
||||||
|
|
||||||
export { Popover, PopoverTrigger, PopoverContent }
|
export { Popover, PopoverTrigger, PopoverContent };
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
"use client"
|
'use client';
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import * as ProgressPrimitive from "@radix-ui/react-progress"
|
import * as ProgressPrimitive from '@radix-ui/react-progress';
|
||||||
|
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
|
|
||||||
const Progress = React.forwardRef<
|
const Progress = React.forwardRef<
|
||||||
React.ElementRef<typeof ProgressPrimitive.Root>,
|
React.ElementRef<typeof ProgressPrimitive.Root>,
|
||||||
@ -12,17 +12,17 @@ const Progress = React.forwardRef<
|
|||||||
<ProgressPrimitive.Root
|
<ProgressPrimitive.Root
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative h-4 w-full overflow-hidden rounded-full bg-secondary",
|
'relative h-4 w-full overflow-hidden rounded-full bg-secondary',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ProgressPrimitive.Indicator
|
<ProgressPrimitive.Indicator
|
||||||
className="h-full w-full flex-1 bg-primary transition-all"
|
className='h-full w-full flex-1 bg-primary transition-all'
|
||||||
style={{ transform: `translateX(-${100 - (value ?? 0)}%)` }}
|
style={{ transform: `translateX(-${100 - (value ?? 0)}%)` }}
|
||||||
/>
|
/>
|
||||||
</ProgressPrimitive.Root>
|
</ProgressPrimitive.Root>
|
||||||
))
|
));
|
||||||
Progress.displayName = ProgressPrimitive.Root.displayName
|
Progress.displayName = ProgressPrimitive.Root.displayName;
|
||||||
|
|
||||||
export { Progress }
|
export { Progress };
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
"use client"
|
'use client';
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
|
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
||||||
import { Circle } from "lucide-react"
|
import { Circle } from 'lucide-react';
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
|
|
||||||
const RadioGroup = React.forwardRef<
|
const RadioGroup = React.forwardRef<
|
||||||
React.ElementRef<typeof RadioGroupPrimitive.Root>,
|
React.ElementRef<typeof RadioGroupPrimitive.Root>,
|
||||||
@ -10,13 +10,13 @@ const RadioGroup = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => {
|
>(({ className, ...props }, ref) => {
|
||||||
return (
|
return (
|
||||||
<RadioGroupPrimitive.Root
|
<RadioGroupPrimitive.Root
|
||||||
className={cn("grid gap-2", className)}
|
className={cn('grid gap-2', className)}
|
||||||
{...props}
|
{...props}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName
|
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
|
||||||
|
|
||||||
const RadioGroupItem = React.forwardRef<
|
const RadioGroupItem = React.forwardRef<
|
||||||
React.ElementRef<typeof RadioGroupPrimitive.Item>,
|
React.ElementRef<typeof RadioGroupPrimitive.Item>,
|
||||||
@ -26,20 +26,20 @@ const RadioGroupItem = React.forwardRef<
|
|||||||
<RadioGroupPrimitive.Item
|
<RadioGroupPrimitive.Item
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"aspect-square h-4 w-4 rounded-full border border-primary text-primary " +
|
'aspect-square h-4 w-4 rounded-full border border-primary text-primary ' +
|
||||||
"ring-offset-background focus:outline-none focus-visible:ring-2 " +
|
'ring-offset-background focus:outline-none focus-visible:ring-2 ' +
|
||||||
"focus-visible:ring-ring focus-visible:ring-offset-2 " +
|
'focus-visible:ring-ring focus-visible:ring-offset-2 ' +
|
||||||
"disabled:cursor-not-allowed disabled:opacity-50",
|
'disabled:cursor-not-allowed disabled:opacity-50',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<RadioGroupPrimitive.Indicator className="flex items-center justify-center">
|
<RadioGroupPrimitive.Indicator className='flex items-center justify-center'>
|
||||||
<Circle className="h-2.5 w-2.5 fill-current text-current" />
|
<Circle className='h-2.5 w-2.5 fill-current text-current' />
|
||||||
</RadioGroupPrimitive.Indicator>
|
</RadioGroupPrimitive.Indicator>
|
||||||
</RadioGroupPrimitive.Item>
|
</RadioGroupPrimitive.Item>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName
|
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
|
||||||
|
|
||||||
export { RadioGroup, RadioGroupItem }
|
export { RadioGroup, RadioGroupItem };
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
"use client"
|
'use client';
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
|
import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
|
||||||
|
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
|
|
||||||
const ScrollArea = React.forwardRef<
|
const ScrollArea = React.forwardRef<
|
||||||
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
||||||
@ -11,38 +11,38 @@ const ScrollArea = React.forwardRef<
|
|||||||
>(({ className, children, ...props }, ref) => (
|
>(({ className, children, ...props }, ref) => (
|
||||||
<ScrollAreaPrimitive.Root
|
<ScrollAreaPrimitive.Root
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("relative overflow-hidden", className)}
|
className={cn('relative overflow-hidden', className)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
|
<ScrollAreaPrimitive.Viewport className='h-full w-full rounded-[inherit]'>
|
||||||
{children}
|
{children}
|
||||||
</ScrollAreaPrimitive.Viewport>
|
</ScrollAreaPrimitive.Viewport>
|
||||||
<ScrollBar />
|
<ScrollBar />
|
||||||
<ScrollAreaPrimitive.Corner />
|
<ScrollAreaPrimitive.Corner />
|
||||||
</ScrollAreaPrimitive.Root>
|
</ScrollAreaPrimitive.Root>
|
||||||
))
|
));
|
||||||
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
|
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
|
||||||
|
|
||||||
const ScrollBar = React.forwardRef<
|
const ScrollBar = React.forwardRef<
|
||||||
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
||||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
|
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||||
>(({ className, orientation = "vertical", ...props }, ref) => (
|
>(({ className, orientation = 'vertical', ...props }, ref) => (
|
||||||
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||||
ref={ref}
|
ref={ref}
|
||||||
orientation={orientation}
|
orientation={orientation}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex touch-none select-none transition-colors",
|
'flex touch-none select-none transition-colors',
|
||||||
orientation === "vertical" &&
|
orientation === 'vertical' &&
|
||||||
"h-full w-2.5 border-l border-l-transparent p-[1px]",
|
'h-full w-2.5 border-l border-l-transparent p-[1px]',
|
||||||
orientation === "horizontal" &&
|
orientation === 'horizontal' &&
|
||||||
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
|
'h-2.5 flex-col border-t border-t-transparent p-[1px]',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
|
<ScrollAreaPrimitive.ScrollAreaThumb className='relative flex-1 rounded-full bg-border' />
|
||||||
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||||
))
|
));
|
||||||
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
|
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
|
||||||
|
|
||||||
export { ScrollArea, ScrollBar }
|
export { ScrollArea, ScrollBar };
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
"use client"
|
'use client';
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import * as SelectPrimitive from "@radix-ui/react-select"
|
import * as SelectPrimitive from '@radix-ui/react-select';
|
||||||
import { Check, ChevronDown, ChevronUp } from "lucide-react"
|
import { Check, ChevronDown, ChevronUp } from 'lucide-react';
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
|
|
||||||
const Select = SelectPrimitive.Root
|
const Select = SelectPrimitive.Root;
|
||||||
const SelectGroup = SelectPrimitive.Group
|
const SelectGroup = SelectPrimitive.Group;
|
||||||
const SelectValue = SelectPrimitive.Value
|
const SelectValue = SelectPrimitive.Value;
|
||||||
|
|
||||||
const SelectTrigger = React.forwardRef<
|
const SelectTrigger = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||||
@ -15,22 +15,22 @@ const SelectTrigger = React.forwardRef<
|
|||||||
<SelectPrimitive.Trigger
|
<SelectPrimitive.Trigger
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-10 w-full items-center justify-between rounded-md border " +
|
'flex h-10 w-full items-center justify-between rounded-md border ' +
|
||||||
"border-input bg-background px-3 py-2 text-sm ring-offset-background " +
|
'border-input bg-background px-3 py-2 text-sm ring-offset-background ' +
|
||||||
"placeholder:text-muted-foreground focus:outline-none focus:ring-2 " +
|
'placeholder:text-muted-foreground focus:outline-none focus:ring-2 ' +
|
||||||
"focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed " +
|
'focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed ' +
|
||||||
"disabled:opacity-50 [&>span]:line-clamp-1",
|
'disabled:opacity-50 [&>span]:line-clamp-1',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
<SelectPrimitive.Icon asChild>
|
<SelectPrimitive.Icon asChild>
|
||||||
<ChevronDown className="h-4 w-4 opacity-50" />
|
<ChevronDown className='h-4 w-4 opacity-50' />
|
||||||
</SelectPrimitive.Icon>
|
</SelectPrimitive.Icon>
|
||||||
</SelectPrimitive.Trigger>
|
</SelectPrimitive.Trigger>
|
||||||
))
|
));
|
||||||
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
|
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
||||||
|
|
||||||
const SelectScrollUpButton = React.forwardRef<
|
const SelectScrollUpButton = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
||||||
@ -39,15 +39,15 @@ const SelectScrollUpButton = React.forwardRef<
|
|||||||
<SelectPrimitive.ScrollUpButton
|
<SelectPrimitive.ScrollUpButton
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex cursor-default items-center justify-center py-1",
|
'flex cursor-default items-center justify-center py-1',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ChevronUp className="h-4 w-4" />
|
<ChevronUp className='h-4 w-4' />
|
||||||
</SelectPrimitive.ScrollUpButton>
|
</SelectPrimitive.ScrollUpButton>
|
||||||
))
|
));
|
||||||
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
|
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
||||||
|
|
||||||
const SelectScrollDownButton = React.forwardRef<
|
const SelectScrollDownButton = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
||||||
@ -56,36 +56,36 @@ const SelectScrollDownButton = React.forwardRef<
|
|||||||
<SelectPrimitive.ScrollDownButton
|
<SelectPrimitive.ScrollDownButton
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex cursor-default items-center justify-center py-1",
|
'flex cursor-default items-center justify-center py-1',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ChevronDown className="h-4 w-4" />
|
<ChevronDown className='h-4 w-4' />
|
||||||
</SelectPrimitive.ScrollDownButton>
|
</SelectPrimitive.ScrollDownButton>
|
||||||
))
|
));
|
||||||
SelectScrollDownButton.displayName =
|
SelectScrollDownButton.displayName =
|
||||||
SelectPrimitive.ScrollDownButton.displayName
|
SelectPrimitive.ScrollDownButton.displayName;
|
||||||
|
|
||||||
const SelectContent = React.forwardRef<
|
const SelectContent = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Content>,
|
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
||||||
>(({ className, children, position = "popper", ...props }, ref) => (
|
>(({ className, children, position = 'popper', ...props }, ref) => (
|
||||||
<SelectPrimitive.Portal>
|
<SelectPrimitive.Portal>
|
||||||
<SelectPrimitive.Content
|
<SelectPrimitive.Content
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border " +
|
'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border ' +
|
||||||
"bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in " +
|
'bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in ' +
|
||||||
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 " +
|
'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 ' +
|
||||||
"data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 " +
|
'data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 ' +
|
||||||
"data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 " +
|
'data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 ' +
|
||||||
"data-[side=left]:slide-in-from-right-2 " +
|
'data-[side=left]:slide-in-from-right-2 ' +
|
||||||
"data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
'data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||||
position === "popper" &&
|
position === 'popper' &&
|
||||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 " +
|
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 ' +
|
||||||
"data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
'data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
position={position}
|
position={position}
|
||||||
{...props}
|
{...props}
|
||||||
@ -93,10 +93,10 @@ const SelectContent = React.forwardRef<
|
|||||||
<SelectScrollUpButton />
|
<SelectScrollUpButton />
|
||||||
<SelectPrimitive.Viewport
|
<SelectPrimitive.Viewport
|
||||||
className={cn(
|
className={cn(
|
||||||
"p-1",
|
'p-1',
|
||||||
position === "popper" &&
|
position === 'popper' &&
|
||||||
"h-[var(--radix-select-trigger-height)] w-full " +
|
'h-[var(--radix-select-trigger-height)] w-full ' +
|
||||||
"min-w-[var(--radix-select-trigger-width)]"
|
'min-w-[var(--radix-select-trigger-width)]',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
@ -104,8 +104,8 @@ const SelectContent = React.forwardRef<
|
|||||||
<SelectScrollDownButton />
|
<SelectScrollDownButton />
|
||||||
</SelectPrimitive.Content>
|
</SelectPrimitive.Content>
|
||||||
</SelectPrimitive.Portal>
|
</SelectPrimitive.Portal>
|
||||||
))
|
));
|
||||||
SelectContent.displayName = SelectPrimitive.Content.displayName
|
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
||||||
|
|
||||||
const SelectLabel = React.forwardRef<
|
const SelectLabel = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Label>,
|
React.ElementRef<typeof SelectPrimitive.Label>,
|
||||||
@ -113,11 +113,11 @@ const SelectLabel = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<SelectPrimitive.Label
|
<SelectPrimitive.Label
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
|
className={cn('py-1.5 pl-8 pr-2 text-sm font-semibold', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
SelectLabel.displayName = SelectPrimitive.Label.displayName
|
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
||||||
|
|
||||||
const SelectItem = React.forwardRef<
|
const SelectItem = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Item>,
|
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||||
@ -126,24 +126,24 @@ const SelectItem = React.forwardRef<
|
|||||||
<SelectPrimitive.Item
|
<SelectPrimitive.Item
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex w-full cursor-default select-none items-center rounded-sm " +
|
'relative flex w-full cursor-default select-none items-center rounded-sm ' +
|
||||||
"py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent " +
|
'py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent ' +
|
||||||
"focus:text-accent-foreground data-[disabled]:pointer-events-none " +
|
'focus:text-accent-foreground data-[disabled]:pointer-events-none ' +
|
||||||
"data-[disabled]:opacity-50",
|
'data-[disabled]:opacity-50',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
<span className='absolute left-2 flex h-3.5 w-3.5 items-center justify-center'>
|
||||||
<SelectPrimitive.ItemIndicator>
|
<SelectPrimitive.ItemIndicator>
|
||||||
<Check className="h-4 w-4" />
|
<Check className='h-4 w-4' />
|
||||||
</SelectPrimitive.ItemIndicator>
|
</SelectPrimitive.ItemIndicator>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||||
</SelectPrimitive.Item>
|
</SelectPrimitive.Item>
|
||||||
))
|
));
|
||||||
SelectItem.displayName = SelectPrimitive.Item.displayName
|
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
||||||
|
|
||||||
const SelectSeparator = React.forwardRef<
|
const SelectSeparator = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Separator>,
|
React.ElementRef<typeof SelectPrimitive.Separator>,
|
||||||
@ -151,11 +151,11 @@ const SelectSeparator = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<SelectPrimitive.Separator
|
<SelectPrimitive.Separator
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
className={cn('-mx-1 my-1 h-px bg-muted', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
|
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Select,
|
Select,
|
||||||
@ -168,4 +168,4 @@ export {
|
|||||||
SelectSeparator,
|
SelectSeparator,
|
||||||
SelectScrollUpButton,
|
SelectScrollUpButton,
|
||||||
SelectScrollDownButton,
|
SelectScrollDownButton,
|
||||||
}
|
};
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
"use client"
|
'use client';
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import * as SwitchPrimitives from "@radix-ui/react-switch"
|
import * as SwitchPrimitives from '@radix-ui/react-switch';
|
||||||
|
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
|
|
||||||
const Switch = React.forwardRef<
|
const Switch = React.forwardRef<
|
||||||
React.ElementRef<typeof SwitchPrimitives.Root>,
|
React.ElementRef<typeof SwitchPrimitives.Root>,
|
||||||
@ -11,26 +11,26 @@ const Switch = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<SwitchPrimitives.Root
|
<SwitchPrimitives.Root
|
||||||
className={cn(
|
className={cn(
|
||||||
"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full " +
|
'peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full ' +
|
||||||
"border-2 border-transparent transition-colors focus-visible:outline-none " +
|
'border-2 border-transparent transition-colors focus-visible:outline-none ' +
|
||||||
"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 " +
|
'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ' +
|
||||||
"focus-visible:ring-offset-background disabled:cursor-not-allowed " +
|
'focus-visible:ring-offset-background disabled:cursor-not-allowed ' +
|
||||||
"disabled:opacity-50 data-[state=checked]:bg-primary " +
|
'disabled:opacity-50 data-[state=checked]:bg-primary ' +
|
||||||
"data-[state=unchecked]:bg-input",
|
'data-[state=unchecked]:bg-input',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
>
|
>
|
||||||
<SwitchPrimitives.Thumb
|
<SwitchPrimitives.Thumb
|
||||||
className={cn(
|
className={cn(
|
||||||
"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg " +
|
'pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ' +
|
||||||
"ring-0 transition-transform data-[state=checked]:translate-x-5 " +
|
'ring-0 transition-transform data-[state=checked]:translate-x-5 ' +
|
||||||
"data-[state=unchecked]:translate-x-0"
|
'data-[state=unchecked]:translate-x-0',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</SwitchPrimitives.Root>
|
</SwitchPrimitives.Root>
|
||||||
))
|
));
|
||||||
Switch.displayName = SwitchPrimitives.Root.displayName
|
Switch.displayName = SwitchPrimitives.Root.displayName;
|
||||||
|
|
||||||
export { Switch }
|
export { Switch };
|
||||||
|
@ -1,28 +1,28 @@
|
|||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
|
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
|
|
||||||
const Table = React.forwardRef<
|
const Table = React.forwardRef<
|
||||||
HTMLTableElement,
|
HTMLTableElement,
|
||||||
React.HTMLAttributes<HTMLTableElement>
|
React.HTMLAttributes<HTMLTableElement>
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<div className="relative w-full overflow-auto">
|
<div className='relative w-full overflow-auto'>
|
||||||
<table
|
<table
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("w-full caption-bottom text-sm", className)}
|
className={cn('w-full caption-bottom text-sm', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))
|
));
|
||||||
Table.displayName = "Table"
|
Table.displayName = 'Table';
|
||||||
|
|
||||||
const TableHeader = React.forwardRef<
|
const TableHeader = React.forwardRef<
|
||||||
HTMLTableSectionElement,
|
HTMLTableSectionElement,
|
||||||
React.HTMLAttributes<HTMLTableSectionElement>
|
React.HTMLAttributes<HTMLTableSectionElement>
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
|
<thead ref={ref} className={cn('[&_tr]:border-b', className)} {...props} />
|
||||||
))
|
));
|
||||||
TableHeader.displayName = "TableHeader"
|
TableHeader.displayName = 'TableHeader';
|
||||||
|
|
||||||
const TableBody = React.forwardRef<
|
const TableBody = React.forwardRef<
|
||||||
HTMLTableSectionElement,
|
HTMLTableSectionElement,
|
||||||
@ -30,11 +30,11 @@ const TableBody = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<tbody
|
<tbody
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("[&_tr:last-child]:border-0", className)}
|
className={cn('[&_tr:last-child]:border-0', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TableBody.displayName = "TableBody"
|
TableBody.displayName = 'TableBody';
|
||||||
|
|
||||||
const TableFooter = React.forwardRef<
|
const TableFooter = React.forwardRef<
|
||||||
HTMLTableSectionElement,
|
HTMLTableSectionElement,
|
||||||
@ -43,13 +43,13 @@ const TableFooter = React.forwardRef<
|
|||||||
<tfoot
|
<tfoot
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
|
'border-t bg-muted/50 font-medium [&>tr]:last:border-b-0',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TableFooter.displayName = "TableFooter"
|
TableFooter.displayName = 'TableFooter';
|
||||||
|
|
||||||
const TableRow = React.forwardRef<
|
const TableRow = React.forwardRef<
|
||||||
HTMLTableRowElement,
|
HTMLTableRowElement,
|
||||||
@ -58,13 +58,13 @@ const TableRow = React.forwardRef<
|
|||||||
<tr
|
<tr
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
'border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TableRow.displayName = "TableRow"
|
TableRow.displayName = 'TableRow';
|
||||||
|
|
||||||
const TableHead = React.forwardRef<
|
const TableHead = React.forwardRef<
|
||||||
HTMLTableCellElement,
|
HTMLTableCellElement,
|
||||||
@ -73,14 +73,14 @@ const TableHead = React.forwardRef<
|
|||||||
<th
|
<th
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-12 px-4 text-left align-middle font-medium " +
|
'h-12 px-4 text-left align-middle font-medium ' +
|
||||||
"text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
'text-muted-foreground [&:has([role=checkbox])]:pr-0',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TableHead.displayName = "TableHead"
|
TableHead.displayName = 'TableHead';
|
||||||
|
|
||||||
const TableCell = React.forwardRef<
|
const TableCell = React.forwardRef<
|
||||||
HTMLTableCellElement,
|
HTMLTableCellElement,
|
||||||
@ -88,11 +88,11 @@ const TableCell = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<td
|
<td
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
|
className={cn('p-4 align-middle [&:has([role=checkbox])]:pr-0', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TableCell.displayName = "TableCell"
|
TableCell.displayName = 'TableCell';
|
||||||
|
|
||||||
const TableCaption = React.forwardRef<
|
const TableCaption = React.forwardRef<
|
||||||
HTMLTableCaptionElement,
|
HTMLTableCaptionElement,
|
||||||
@ -100,11 +100,11 @@ const TableCaption = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<caption
|
<caption
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
className={cn('mt-4 text-sm text-muted-foreground', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TableCaption.displayName = "TableCaption"
|
TableCaption.displayName = 'TableCaption';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Table,
|
Table,
|
||||||
@ -115,4 +115,4 @@ export {
|
|||||||
TableRow,
|
TableRow,
|
||||||
TableCell,
|
TableCell,
|
||||||
TableCaption,
|
TableCaption,
|
||||||
}
|
};
|
||||||
|
@ -1,31 +1,31 @@
|
|||||||
"use client"
|
'use client';
|
||||||
import { useTheme } from "next-themes"
|
import { useTheme } from 'next-themes';
|
||||||
import { Toaster as Sonner } from "sonner"
|
import { Toaster as Sonner } from 'sonner';
|
||||||
|
|
||||||
type ToasterProps = React.ComponentProps<typeof Sonner>
|
type ToasterProps = React.ComponentProps<typeof Sonner>;
|
||||||
|
|
||||||
const Toaster = ({ ...props }: ToasterProps) => {
|
const Toaster = ({ ...props }: ToasterProps) => {
|
||||||
const { theme = "system" } = useTheme()
|
const { theme = 'system' } = useTheme();
|
||||||
return (
|
return (
|
||||||
<Sonner
|
<Sonner
|
||||||
theme={theme as ToasterProps["theme"]}
|
theme={theme as ToasterProps['theme']}
|
||||||
className="toaster group"
|
className='toaster group'
|
||||||
toastOptions={{
|
toastOptions={{
|
||||||
classNames: {
|
classNames: {
|
||||||
toast:
|
toast:
|
||||||
"group toast group-[.toaster]:bg-background " +
|
'group toast group-[.toaster]:bg-background ' +
|
||||||
"group-[.toaster]:text-foreground " +
|
'group-[.toaster]:text-foreground ' +
|
||||||
"group-[.toaster]:border-border group-[.toaster]:shadow-lg",
|
'group-[.toaster]:border-border group-[.toaster]:shadow-lg',
|
||||||
description: "group-[.toast]:text-muted-foreground",
|
description: 'group-[.toast]:text-muted-foreground',
|
||||||
actionButton:
|
actionButton:
|
||||||
"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
|
'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',
|
||||||
cancelButton:
|
cancelButton:
|
||||||
"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
|
'group-[.toast]:bg-muted group-[.toast]:text-muted-foreground',
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export { Toaster }
|
export { Toaster };
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
"use client"
|
'use client';
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group"
|
import * as ToggleGroupPrimitive from '@radix-ui/react-toggle-group';
|
||||||
import { type VariantProps } from "class-variance-authority"
|
import { type VariantProps } from 'class-variance-authority';
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
import { toggleVariants } from "~/components/ui/shadcn/toggle"
|
import { toggleVariants } from '~/components/ui/shadcn/toggle';
|
||||||
|
|
||||||
const ToggleGroupContext = React.createContext<
|
const ToggleGroupContext = React.createContext<
|
||||||
VariantProps<typeof toggleVariants>
|
VariantProps<typeof toggleVariants>
|
||||||
>({
|
>({
|
||||||
size: "default",
|
size: 'default',
|
||||||
variant: "default",
|
variant: 'default',
|
||||||
})
|
});
|
||||||
|
|
||||||
const ToggleGroup = React.forwardRef<
|
const ToggleGroup = React.forwardRef<
|
||||||
React.ElementRef<typeof ToggleGroupPrimitive.Root>,
|
React.ElementRef<typeof ToggleGroupPrimitive.Root>,
|
||||||
@ -19,23 +19,23 @@ const ToggleGroup = React.forwardRef<
|
|||||||
>(({ className, variant, size, children, ...props }, ref) => (
|
>(({ className, variant, size, children, ...props }, ref) => (
|
||||||
<ToggleGroupPrimitive.Root
|
<ToggleGroupPrimitive.Root
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("flex items-center justify-center gap-1", className)}
|
className={cn('flex items-center justify-center gap-1', className)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ToggleGroupContext.Provider value={{ variant, size }}>
|
<ToggleGroupContext.Provider value={{ variant, size }}>
|
||||||
{children}
|
{children}
|
||||||
</ToggleGroupContext.Provider>
|
</ToggleGroupContext.Provider>
|
||||||
</ToggleGroupPrimitive.Root>
|
</ToggleGroupPrimitive.Root>
|
||||||
))
|
));
|
||||||
|
|
||||||
ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName
|
ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;
|
||||||
|
|
||||||
const ToggleGroupItem = React.forwardRef<
|
const ToggleGroupItem = React.forwardRef<
|
||||||
React.ElementRef<typeof ToggleGroupPrimitive.Item>,
|
React.ElementRef<typeof ToggleGroupPrimitive.Item>,
|
||||||
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
|
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
|
||||||
VariantProps<typeof toggleVariants>
|
VariantProps<typeof toggleVariants>
|
||||||
>(({ className, children, variant, size, ...props }, ref) => {
|
>(({ className, children, variant, size, ...props }, ref) => {
|
||||||
const context = React.useContext(ToggleGroupContext)
|
const context = React.useContext(ToggleGroupContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ToggleGroupPrimitive.Item
|
<ToggleGroupPrimitive.Item
|
||||||
@ -45,15 +45,15 @@ const ToggleGroupItem = React.forwardRef<
|
|||||||
variant: context.variant ?? variant,
|
variant: context.variant ?? variant,
|
||||||
size: context.size ?? size,
|
size: context.size ?? size,
|
||||||
}),
|
}),
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</ToggleGroupPrimitive.Item>
|
</ToggleGroupPrimitive.Item>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
|
|
||||||
ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName
|
ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
|
||||||
|
|
||||||
export { ToggleGroup, ToggleGroupItem }
|
export { ToggleGroup, ToggleGroupItem };
|
||||||
|
@ -1,35 +1,35 @@
|
|||||||
"use client"
|
'use client';
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import * as TogglePrimitive from "@radix-ui/react-toggle"
|
import * as TogglePrimitive from '@radix-ui/react-toggle';
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from 'class-variance-authority';
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
|
|
||||||
const toggleVariants = cva(
|
const toggleVariants = cva(
|
||||||
"inline-flex items-center justify-center rounded-md text-sm font-medium " +
|
'inline-flex items-center justify-center rounded-md text-sm font-medium ' +
|
||||||
"ring-offset-background transition-colors hover:bg-muted " +
|
'ring-offset-background transition-colors hover:bg-muted ' +
|
||||||
"hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 " +
|
'hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 ' +
|
||||||
"focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none " +
|
'focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none ' +
|
||||||
"disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
|
'disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground',
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default: "bg-transparent",
|
default: 'bg-transparent',
|
||||||
outline:
|
outline:
|
||||||
"border border-input bg-transparent hover:bg-accent " +
|
'border border-input bg-transparent hover:bg-accent ' +
|
||||||
"hover:text-accent-foreground",
|
'hover:text-accent-foreground',
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: "h-10 px-3",
|
default: 'h-10 px-3',
|
||||||
sm: "h-9 px-2.5",
|
sm: 'h-9 px-2.5',
|
||||||
lg: "h-11 px-5",
|
lg: 'h-11 px-5',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
variant: "default",
|
variant: 'default',
|
||||||
size: "default",
|
size: 'default',
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
const Toggle = React.forwardRef<
|
const Toggle = React.forwardRef<
|
||||||
React.ElementRef<typeof TogglePrimitive.Root>,
|
React.ElementRef<typeof TogglePrimitive.Root>,
|
||||||
@ -41,8 +41,8 @@ const Toggle = React.forwardRef<
|
|||||||
className={cn(toggleVariants({ variant, size, className }))}
|
className={cn(toggleVariants({ variant, size, className }))}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
|
|
||||||
Toggle.displayName = TogglePrimitive.Root.displayName
|
Toggle.displayName = TogglePrimitive.Root.displayName;
|
||||||
|
|
||||||
export { Toggle, toggleVariants }
|
export { Toggle, toggleVariants };
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
"use client"
|
'use client';
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
|
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
||||||
import { cn } from "~/lib/utils"
|
import { cn } from '~/lib/utils';
|
||||||
|
|
||||||
const TooltipProvider = TooltipPrimitive.Provider
|
const TooltipProvider = TooltipPrimitive.Provider;
|
||||||
const Tooltip = TooltipPrimitive.Root
|
const Tooltip = TooltipPrimitive.Root;
|
||||||
const TooltipTrigger = TooltipPrimitive.Trigger
|
const TooltipTrigger = TooltipPrimitive.Trigger;
|
||||||
|
|
||||||
const TooltipContent = React.forwardRef<
|
const TooltipContent = React.forwardRef<
|
||||||
React.ElementRef<typeof TooltipPrimitive.Content>,
|
React.ElementRef<typeof TooltipPrimitive.Content>,
|
||||||
@ -15,16 +15,16 @@ const TooltipContent = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 " +
|
'z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 ' +
|
||||||
"text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 " +
|
'text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 ' +
|
||||||
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 " +
|
'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 ' +
|
||||||
"data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 " +
|
'data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 ' +
|
||||||
"data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 " +
|
'data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 ' +
|
||||||
"data-[side=top]:slide-in-from-bottom-2",
|
'data-[side=top]:slide-in-from-bottom-2',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TooltipContent.displayName = TooltipPrimitive.Content.displayName
|
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
||||||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
|
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
||||||
|
11
src/env.js
11
src/env.js
@ -1,5 +1,5 @@
|
|||||||
import { createEnv } from "@t3-oss/env-nextjs";
|
import { createEnv } from '@t3-oss/env-nextjs';
|
||||||
import { z } from "zod";
|
import { z } from 'zod';
|
||||||
|
|
||||||
export const env = createEnv({
|
export const env = createEnv({
|
||||||
/**
|
/**
|
||||||
@ -9,8 +9,8 @@ export const env = createEnv({
|
|||||||
server: {
|
server: {
|
||||||
DATABASE_URL: z.string().url(),
|
DATABASE_URL: z.string().url(),
|
||||||
NODE_ENV: z
|
NODE_ENV: z
|
||||||
.enum(["development", "test", "production"])
|
.enum(['development', 'test', 'production'])
|
||||||
.default("development"),
|
.default('development'),
|
||||||
API_KEY: z.string(),
|
API_KEY: z.string(),
|
||||||
AUTH_TRUST_HOST: z.boolean().default(false),
|
AUTH_TRUST_HOST: z.boolean().default(false),
|
||||||
AUTH_SECRET: z.string(),
|
AUTH_SECRET: z.string(),
|
||||||
@ -43,7 +43,8 @@ export const env = createEnv({
|
|||||||
AUTH_SECRET: process.env.AUTH_SECRET,
|
AUTH_SECRET: process.env.AUTH_SECRET,
|
||||||
AUTH_MICROSOFT_ENTRA_ID_ID: process.env.AUTH_MICROSOFT_ENTRA_ID_ID,
|
AUTH_MICROSOFT_ENTRA_ID_ID: process.env.AUTH_MICROSOFT_ENTRA_ID_ID,
|
||||||
AUTH_MICROSOFT_ENTRA_ID_SECRET: process.env.AUTH_MICROSOFT_ENTRA_ID_SECRET,
|
AUTH_MICROSOFT_ENTRA_ID_SECRET: process.env.AUTH_MICROSOFT_ENTRA_ID_SECRET,
|
||||||
AUTH_MICROSOFT_ENTRA_ID_TENANT_ID: process.env.AUTH_MICROSOFT_ENTRA_ID_TENANT_ID,
|
AUTH_MICROSOFT_ENTRA_ID_TENANT_ID:
|
||||||
|
process.env.AUTH_MICROSOFT_ENTRA_ID_TENANT_ID,
|
||||||
AUTH_AUTHENTIK_CLIENT_ID: process.env.AUTH_AUTHENTIK_CLIENT_ID,
|
AUTH_AUTHENTIK_CLIENT_ID: process.env.AUTH_AUTHENTIK_CLIENT_ID,
|
||||||
AUTH_AUTHENTIK_CLIENT_SECRET: process.env.AUTH_AUTHENTIK_CLIENT_SECRET,
|
AUTH_AUTHENTIK_CLIENT_SECRET: process.env.AUTH_AUTHENTIK_CLIENT_SECRET,
|
||||||
AUTH_AUTHENTIK_ISSUER: process.env.AUTH_AUTHENTIK_ISSUER,
|
AUTH_AUTHENTIK_ISSUER: process.env.AUTH_AUTHENTIK_ISSUER,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { type ClassValue, clsx } from "clsx"
|
import { type ClassValue, clsx } from 'clsx';
|
||||||
import { twMerge } from "tailwind-merge"
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
export function cn(...inputs: ClassValue[]) {
|
export function cn(...inputs: ClassValue[]) {
|
||||||
return twMerge(clsx(inputs))
|
return twMerge(clsx(inputs));
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
export { auth as middleware } from "~/auth"
|
export { auth as middleware } from '~/auth';
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { drizzle } from "drizzle-orm/mysql2";
|
import { drizzle } from 'drizzle-orm/mysql2';
|
||||||
import { createPool, type Pool } from "mysql2/promise";
|
import { createPool, type Pool } from 'mysql2/promise';
|
||||||
|
|
||||||
import { env } from "~/env";
|
import { env } from '~/env';
|
||||||
import * as schema from "./schema";
|
import * as schema from './schema';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache the database connection in development. This avoids creating a new connection on every HMR
|
* Cache the database connection in development. This avoids creating a new connection on every HMR
|
||||||
@ -13,6 +13,6 @@ const globalForDb = globalThis as unknown as {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const conn = globalForDb.conn ?? createPool({ uri: env.DATABASE_URL });
|
const conn = globalForDb.conn ?? createPool({ uri: env.DATABASE_URL });
|
||||||
if (env.NODE_ENV !== "production") globalForDb.conn = conn;
|
if (env.NODE_ENV !== 'production') globalForDb.conn = conn;
|
||||||
|
|
||||||
export const db = drizzle(conn, { schema, mode: "default" });
|
export const db = drizzle(conn, { schema, mode: 'default' });
|
||||||
|
@ -1,32 +1,26 @@
|
|||||||
// https://orm.drizzle.team/docs/sql-schema-declaration
|
// https://orm.drizzle.team/docs/sql-schema-declaration
|
||||||
import { sql } from "drizzle-orm";
|
import { sql } from 'drizzle-orm';
|
||||||
import {
|
import {
|
||||||
bigint,
|
bigint,
|
||||||
mysqlTableCreator,
|
mysqlTableCreator,
|
||||||
timestamp,
|
timestamp,
|
||||||
varchar,
|
varchar,
|
||||||
} from "drizzle-orm/mysql-core";
|
} from 'drizzle-orm/mysql-core';
|
||||||
|
|
||||||
export const createTable = mysqlTableCreator((name) => `${name}`);
|
export const createTable = mysqlTableCreator((name) => `${name}`);
|
||||||
|
|
||||||
export const users = createTable(
|
export const users = createTable('users', {
|
||||||
"users",
|
id: bigint('id', { mode: 'number' }).primaryKey().autoincrement(),
|
||||||
{
|
name: varchar('name', { length: 256 }).notNull(),
|
||||||
id: bigint("id", {mode: "number"}).primaryKey().autoincrement(),
|
status: varchar('status', { length: 256 }).notNull(),
|
||||||
name: varchar("name", { length: 256 }).notNull(),
|
updatedAt: timestamp('updatedAt')
|
||||||
status: varchar("status", { length: 256 }).notNull(),
|
|
||||||
updatedAt: timestamp("updatedAt")
|
|
||||||
.default(sql`CURRENT_TIMESTAMP`)
|
.default(sql`CURRENT_TIMESTAMP`)
|
||||||
.notNull(),
|
.notNull(),
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
export const history = createTable(
|
export const history = createTable('history', {
|
||||||
"history",
|
id: bigint('id', { mode: 'number' }).primaryKey().autoincrement(),
|
||||||
{
|
user_id: bigint('user_id', { mode: 'number' }).references(() => users.id),
|
||||||
id: bigint("id", {mode: "number"}).primaryKey().autoincrement(),
|
status: varchar('status', { length: 256 }).notNull(),
|
||||||
user_id: bigint("user_id", {mode: "number"}).references(() => users.id),
|
updatedAt: timestamp('updatedAt').notNull(),
|
||||||
status: varchar("status", { length: 256 }).notNull(),
|
});
|
||||||
updatedAt: timestamp("updatedAt").notNull(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import "server-only";
|
import 'server-only';
|
||||||
import { db } from "~/server/db";
|
import { db } from '~/server/db';
|
||||||
import { sql } from "drizzle-orm";
|
import { sql } from 'drizzle-orm';
|
||||||
|
|
||||||
export const getEmployees = async () => {
|
export const getEmployees = async () => {
|
||||||
return await db.query.users.findMany({
|
return await db.query.users.findMany({
|
||||||
@ -10,11 +10,13 @@ export const getEmployees = async () => {
|
|||||||
|
|
||||||
// Update Employee Status uses Raw SQL because Drizzle ORM doesn't support
|
// Update Employee Status uses Raw SQL because Drizzle ORM doesn't support
|
||||||
// update with MySQL
|
// update with MySQL
|
||||||
export const updateEmployeeStatus =
|
export const updateEmployeeStatus = async (
|
||||||
async (employeeIds: string[], newStatus: string) => {
|
employeeIds: string[],
|
||||||
|
newStatus: string,
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
// Convert array of ids to a format suitable for SQL query (comma-separated string)
|
// Convert array of ids to a format suitable for SQL query (comma-separated string)
|
||||||
const idList = employeeIds.map(id => parseInt(id, 10));
|
const idList = employeeIds.map((id) => parseInt(id, 10));
|
||||||
let updatedAt = new Date();
|
let updatedAt = new Date();
|
||||||
// Not sure why but localhost is off by 5 hours
|
// Not sure why but localhost is off by 5 hours
|
||||||
if (process.env.NODE_ENV === 'development')
|
if (process.env.NODE_ENV === 'development')
|
||||||
@ -27,14 +29,15 @@ export const updateEmployeeStatus =
|
|||||||
await db.execute(query);
|
await db.execute(query);
|
||||||
return { success: true };
|
return { success: true };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error updating employee status:", error);
|
console.error('Error updating employee status:', error);
|
||||||
throw new Error("Failed to update status");
|
throw new Error('Failed to update status');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to Update Employee Status by Name using Raw SQL
|
// Function to Update Employee Status by Name using Raw SQL
|
||||||
export const updateEmployeeStatusByName =
|
export const updateEmployeeStatusByName = async (
|
||||||
async (technicians:{ name: string, status: string }[]) => {
|
technicians: { name: string; status: string }[],
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
for (const technician of technicians) {
|
for (const technician of technicians) {
|
||||||
const { name, status } = technician;
|
const { name, status } = technician;
|
||||||
@ -47,8 +50,8 @@ export const updateEmployeeStatusByName =
|
|||||||
}
|
}
|
||||||
return { success: true };
|
return { success: true };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error updating employee status by name:", error);
|
console.error('Error updating employee status by name:', error);
|
||||||
throw new Error("Failed to update status by name");
|
throw new Error('Failed to update status by name');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -57,7 +60,7 @@ type HistoryEntry = {
|
|||||||
name: string;
|
name: string;
|
||||||
status: string;
|
status: string;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
};
|
||||||
type PaginatedHistory = {
|
type PaginatedHistory = {
|
||||||
data: HistoryEntry[];
|
data: HistoryEntry[];
|
||||||
meta: {
|
meta: {
|
||||||
@ -65,10 +68,14 @@ type PaginatedHistory = {
|
|||||||
per_page: number;
|
per_page: number;
|
||||||
total_pages: number;
|
total_pages: number;
|
||||||
total_count: number;
|
total_count: number;
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export const get_history = async (user_id: number, page: number, perPage: number): Promise<PaginatedHistory> => {
|
export const get_history = async (
|
||||||
|
user_id: number,
|
||||||
|
page: number,
|
||||||
|
perPage: number,
|
||||||
|
): Promise<PaginatedHistory> => {
|
||||||
const offset = (page - 1) * perPage;
|
const offset = (page - 1) * perPage;
|
||||||
let historyQuery = sql`
|
let historyQuery = sql`
|
||||||
SELECT u.name, h.status, h.updatedAt
|
SELECT u.name, h.status, h.updatedAt
|
||||||
@ -101,21 +108,26 @@ export const get_history = async (user_id: number, page: number, perPage: number
|
|||||||
db.execute(countQuery),
|
db.execute(countQuery),
|
||||||
]);
|
]);
|
||||||
// Safely cast results
|
// Safely cast results
|
||||||
const historyrows = historyresults[0] as unknown as
|
const historyrows = historyresults[0] as unknown as {
|
||||||
{ name: string, status: string, updatedAt: Date }[];
|
name: string;
|
||||||
|
status: string;
|
||||||
|
updatedAt: Date;
|
||||||
|
}[];
|
||||||
const countrow = countresults[0] as unknown as { total_count: number }[];
|
const countrow = countresults[0] as unknown as { total_count: number }[];
|
||||||
const totalCount = countrow[0]?.total_count ?? 0;
|
const totalCount = countrow[0]?.total_count ?? 0;
|
||||||
const totalPages = Math.ceil(totalCount / perPage);
|
const totalPages = Math.ceil(totalCount / perPage);
|
||||||
// Format and map results
|
// Format and map results
|
||||||
let formattedResults: HistoryEntry[] = historyrows.map(row => ({
|
let formattedResults: HistoryEntry[] = historyrows.map((row) => ({
|
||||||
name: row.name,
|
name: row.name,
|
||||||
status: row.status,
|
status: row.status,
|
||||||
updatedAt: new Date(row.updatedAt),
|
updatedAt: new Date(row.updatedAt),
|
||||||
}));
|
}));
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
formattedResults = formattedResults.map(entry => ({
|
formattedResults = formattedResults.map((entry) => ({
|
||||||
...entry,
|
...entry,
|
||||||
updatedAt: new Date(entry.updatedAt.setHours(entry.updatedAt.getUTCHours()+14)),
|
updatedAt: new Date(
|
||||||
|
entry.updatedAt.setHours(entry.updatedAt.getUTCHours() + 14),
|
||||||
|
),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@ -125,6 +137,6 @@ export const get_history = async (user_id: number, page: number, perPage: number
|
|||||||
per_page: perPage,
|
per_page: perPage,
|
||||||
total_pages: totalPages,
|
total_pages: totalPages,
|
||||||
total_count: totalCount,
|
total_count: totalCount,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,84 +1,84 @@
|
|||||||
import type { Config } from "tailwindcss"
|
import type { Config } from 'tailwindcss';
|
||||||
import { fontFamily } from "tailwindcss/defaultTheme"
|
import { fontFamily } from 'tailwindcss/defaultTheme';
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
darkMode: ["class"],
|
darkMode: ['class'],
|
||||||
content: [
|
content: [
|
||||||
'./pages/**/*.{ts,tsx}',
|
'./pages/**/*.{ts,tsx}',
|
||||||
'./components/**/*.{ts,tsx}',
|
'./components/**/*.{ts,tsx}',
|
||||||
'./app/**/*.{ts,tsx}',
|
'./app/**/*.{ts,tsx}',
|
||||||
'./src/**/*.{ts,tsx}',
|
'./src/**/*.{ts,tsx}',
|
||||||
],
|
],
|
||||||
prefix: "",
|
prefix: '',
|
||||||
theme: {
|
theme: {
|
||||||
container: {
|
container: {
|
||||||
center: true,
|
center: true,
|
||||||
padding: "2rem",
|
padding: '2rem',
|
||||||
screens: {
|
screens: {
|
||||||
"2xl": "1400px",
|
'2xl': '1400px',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
extend: {
|
extend: {
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
sans: ["var(--font-sans)", ...fontFamily.sans],
|
sans: ['var(--font-sans)', ...fontFamily.sans],
|
||||||
},
|
},
|
||||||
colors: {
|
colors: {
|
||||||
border: "hsl(var(--border))",
|
border: 'hsl(var(--border))',
|
||||||
input: "hsl(var(--input))",
|
input: 'hsl(var(--input))',
|
||||||
ring: "hsl(var(--ring))",
|
ring: 'hsl(var(--ring))',
|
||||||
background: "hsl(var(--background))",
|
background: 'hsl(var(--background))',
|
||||||
foreground: "hsl(var(--foreground))",
|
foreground: 'hsl(var(--foreground))',
|
||||||
primary: {
|
primary: {
|
||||||
DEFAULT: "hsl(var(--primary))",
|
DEFAULT: 'hsl(var(--primary))',
|
||||||
foreground: "hsl(var(--primary-foreground))",
|
foreground: 'hsl(var(--primary-foreground))',
|
||||||
},
|
},
|
||||||
secondary: {
|
secondary: {
|
||||||
DEFAULT: "hsl(var(--secondary))",
|
DEFAULT: 'hsl(var(--secondary))',
|
||||||
foreground: "hsl(var(--secondary-foreground))",
|
foreground: 'hsl(var(--secondary-foreground))',
|
||||||
},
|
},
|
||||||
destructive: {
|
destructive: {
|
||||||
DEFAULT: "hsl(var(--destructive))",
|
DEFAULT: 'hsl(var(--destructive))',
|
||||||
foreground: "hsl(var(--destructive-foreground))",
|
foreground: 'hsl(var(--destructive-foreground))',
|
||||||
},
|
},
|
||||||
muted: {
|
muted: {
|
||||||
DEFAULT: "hsl(var(--muted))",
|
DEFAULT: 'hsl(var(--muted))',
|
||||||
foreground: "hsl(var(--muted-foreground))",
|
foreground: 'hsl(var(--muted-foreground))',
|
||||||
},
|
},
|
||||||
accent: {
|
accent: {
|
||||||
DEFAULT: "hsl(var(--accent))",
|
DEFAULT: 'hsl(var(--accent))',
|
||||||
foreground: "hsl(var(--accent-foreground))",
|
foreground: 'hsl(var(--accent-foreground))',
|
||||||
},
|
},
|
||||||
popover: {
|
popover: {
|
||||||
DEFAULT: "hsl(var(--popover))",
|
DEFAULT: 'hsl(var(--popover))',
|
||||||
foreground: "hsl(var(--popover-foreground))",
|
foreground: 'hsl(var(--popover-foreground))',
|
||||||
},
|
},
|
||||||
card: {
|
card: {
|
||||||
DEFAULT: "hsl(var(--card))",
|
DEFAULT: 'hsl(var(--card))',
|
||||||
foreground: "hsl(var(--card-foreground))",
|
foreground: 'hsl(var(--card-foreground))',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
borderRadius: {
|
borderRadius: {
|
||||||
lg: "var(--radius)",
|
lg: 'var(--radius)',
|
||||||
md: "calc(var(--radius) - 2px)",
|
md: 'calc(var(--radius) - 2px)',
|
||||||
sm: "calc(var(--radius) - 4px)",
|
sm: 'calc(var(--radius) - 4px)',
|
||||||
},
|
},
|
||||||
keyframes: {
|
keyframes: {
|
||||||
"accordion-down": {
|
'accordion-down': {
|
||||||
from: { height: "0" },
|
from: { height: '0' },
|
||||||
to: { height: "var(--radix-accordion-content-height)" },
|
to: { height: 'var(--radix-accordion-content-height)' },
|
||||||
},
|
},
|
||||||
"accordion-up": {
|
'accordion-up': {
|
||||||
from: { height: "var(--radix-accordion-content-height)" },
|
from: { height: 'var(--radix-accordion-content-height)' },
|
||||||
to: { height: "0" },
|
to: { height: '0' },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
animation: {
|
animation: {
|
||||||
"accordion-down": "accordion-down 0.2s ease-out",
|
'accordion-down': 'accordion-down 0.2s ease-out',
|
||||||
"accordion-up": "accordion-up 0.2s ease-out",
|
'accordion-up': 'accordion-up 0.2s ease-out',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [require("tailwindcss-animate")],
|
plugins: [require('tailwindcss-animate')],
|
||||||
} satisfies Config
|
} satisfies Config;
|
||||||
|
|
||||||
export default config
|
export default config;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user