>(
59 | ({ className, ...props }, ref) => (
60 | [role=checkbox]]:translate-y-[2px]", className)}
63 | {...props}
64 | />
65 | ),
66 | )
67 | TableCell.displayName = "TableCell"
68 |
69 | const TableCaption = React.forwardRef>(
70 | ({ className, ...props }, ref) => (
71 |
72 | ),
73 | )
74 | TableCaption.displayName = "TableCaption"
75 |
76 | export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption }
77 |
--------------------------------------------------------------------------------
/src/components/ui/tabs.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as TabsPrimitive from "@radix-ui/react-tabs"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | const Tabs = TabsPrimitive.Root
9 |
10 | const TabsList = React.forwardRef<
11 | React.ElementRef,
12 | React.ComponentPropsWithoutRef
13 | >(({ className, ...props }, ref) => (
14 |
22 | ))
23 | TabsList.displayName = TabsPrimitive.List.displayName
24 |
25 | const TabsTrigger = React.forwardRef<
26 | React.ElementRef,
27 | React.ComponentPropsWithoutRef
28 | >(({ className, ...props }, ref) => (
29 |
37 | ))
38 | TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
39 |
40 | const TabsContent = React.forwardRef<
41 | React.ElementRef,
42 | React.ComponentPropsWithoutRef
43 | >(({ className, ...props }, ref) => (
44 |
52 | ))
53 | TabsContent.displayName = TabsPrimitive.Content.displayName
54 |
55 | export { Tabs, TabsList, TabsTrigger, TabsContent }
56 |
--------------------------------------------------------------------------------
/src/hooks/use-media-query.ts:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import { useEffect, useState } from "react"
4 |
5 | export function useMediaQuery(query: string) {
6 | const [value, setValue] = useState(false)
7 |
8 | useEffect(() => {
9 | function onChange(event: MediaQueryListEvent) {
10 | setValue(event.matches)
11 | }
12 |
13 | const result = matchMedia(query)
14 | result.addEventListener("change", onChange)
15 | setValue(result.matches)
16 |
17 | return () => result.removeEventListener("change", onChange)
18 | }, [query])
19 |
20 | return value
21 | }
22 |
--------------------------------------------------------------------------------
/src/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { clsx, type ClassValue } from "clsx"
2 | import { twMerge } from "tailwind-merge"
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs))
6 | }
7 |
--------------------------------------------------------------------------------
/src/types/@tanstack/react-table.d.ts:
--------------------------------------------------------------------------------
1 | import "@tanstack/react-table"
2 |
3 | declare module "@tanstack/react-table" {
4 | interface ColumnMeta {
5 | align?: "left" | "center" | "right"
6 | export?:
7 | | boolean
8 | | {
9 | pdf?: boolean | { header?: string }
10 | csv?: boolean | { header?: string }
11 | }
12 | }
13 |
14 | interface FilterFns {
15 | filterRows: FilterFn
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from "tailwindcss";
2 |
3 | export default {
4 | darkMode: ["class"],
5 | content: [
6 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
7 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
8 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
9 | ],
10 | theme: {
11 | extend: {
12 | colors: {
13 | background: 'hsl(var(--background))',
14 | foreground: 'hsl(var(--foreground))',
15 | card: {
16 | DEFAULT: 'hsl(var(--card))',
17 | foreground: 'hsl(var(--card-foreground))'
18 | },
19 | popover: {
20 | DEFAULT: 'hsl(var(--popover))',
21 | foreground: 'hsl(var(--popover-foreground))'
22 | },
23 | primary: {
24 | DEFAULT: 'hsl(var(--primary))',
25 | foreground: 'hsl(var(--primary-foreground))'
26 | },
27 | secondary: {
28 | DEFAULT: 'hsl(var(--secondary))',
29 | foreground: 'hsl(var(--secondary-foreground))'
30 | },
31 | muted: {
32 | DEFAULT: 'hsl(var(--muted))',
33 | foreground: 'hsl(var(--muted-foreground))'
34 | },
35 | accent: {
36 | DEFAULT: 'hsl(var(--accent))',
37 | foreground: 'hsl(var(--accent-foreground))'
38 | },
39 | destructive: {
40 | DEFAULT: 'hsl(var(--destructive))',
41 | foreground: 'hsl(var(--destructive-foreground))'
42 | },
43 | border: 'hsl(var(--border))',
44 | input: 'hsl(var(--input))',
45 | ring: 'hsl(var(--ring))',
46 | chart: {
47 | '1': 'hsl(var(--chart-1))',
48 | '2': 'hsl(var(--chart-2))',
49 | '3': 'hsl(var(--chart-3))',
50 | '4': 'hsl(var(--chart-4))',
51 | '5': 'hsl(var(--chart-5))'
52 | },
53 | sidebar: {
54 | DEFAULT: 'hsl(var(--sidebar-background))',
55 | foreground: 'hsl(var(--sidebar-foreground))',
56 | primary: 'hsl(var(--sidebar-primary))',
57 | 'primary-foreground': 'hsl(var(--sidebar-primary-foreground))',
58 | accent: 'hsl(var(--sidebar-accent))',
59 | 'accent-foreground': 'hsl(var(--sidebar-accent-foreground))',
60 | border: 'hsl(var(--sidebar-border))',
61 | ring: 'hsl(var(--sidebar-ring))'
62 | }
63 | },
64 | borderRadius: {
65 | lg: 'var(--radius)',
66 | md: 'calc(var(--radius) - 2px)',
67 | sm: 'calc(var(--radius) - 4px)'
68 | },
69 | keyframes: {
70 | 'accordion-down': {
71 | from: {
72 | height: '0'
73 | },
74 | to: {
75 | height: 'var(--radix-accordion-content-height)'
76 | }
77 | },
78 | 'accordion-up': {
79 | from: {
80 | height: 'var(--radix-accordion-content-height)'
81 | },
82 | to: {
83 | height: '0'
84 | }
85 | }
86 | },
87 | animation: {
88 | 'accordion-down': 'accordion-down 0.2s ease-out',
89 | 'accordion-up': 'accordion-up 0.2s ease-out'
90 | }
91 | }
92 | },
93 | plugins: [require("tailwindcss-animate")],
94 | } satisfies Config;
95 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2017",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "noEmit": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "jsx": "preserve",
15 | "incremental": true,
16 | "plugins": [
17 | {
18 | "name": "next"
19 | }
20 | ],
21 | "paths": {
22 | "@/*": ["./src/*"]
23 | }
24 | },
25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
26 | "exclude": ["node_modules", ".next"]
27 | }
28 |
--------------------------------------------------------------------------------
|