chore(client): eslint format

Signed-off-by: Noa Virellia <noa@requiem.garden>
This commit is contained in:
2025-12-27 00:25:18 +08:00
parent a06248f3be
commit 2b99d415de
7 changed files with 359 additions and 337 deletions

View File

@@ -1,9 +1,9 @@
"use client" 'use client';
import * as React from "react" import type { ChartConfig } from '@/components/ui/chart';
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts" import * as React from 'react';
import { useIsMobile } from "@/hooks/use-mobile" import { Area, AreaChart, CartesianGrid, XAxis } from 'recharts';
import { import {
Card, Card,
CardAction, CardAction,
@@ -11,158 +11,160 @@ import {
CardDescription, CardDescription,
CardHeader, CardHeader,
CardTitle, CardTitle,
} from "@/components/ui/card" } from '@/components/ui/card';
import { import {
ChartContainer, ChartContainer,
ChartTooltip, ChartTooltip,
ChartTooltipContent, ChartTooltipContent,
type ChartConfig, } from '@/components/ui/chart';
} from "@/components/ui/chart"
import { import {
Select, Select,
SelectContent, SelectContent,
SelectItem, SelectItem,
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select" } from '@/components/ui/select';
import { import {
ToggleGroup, ToggleGroup,
ToggleGroupItem, ToggleGroupItem,
} from "@/components/ui/toggle-group" } from '@/components/ui/toggle-group';
import { useIsMobile } from '@/hooks/use-mobile';
export const description = "An interactive area chart" export const description = 'An interactive area chart';
const chartData = [ const chartData = [
{ date: "2024-04-01", desktop: 222, mobile: 150 }, { date: '2024-04-01', desktop: 222, mobile: 150 },
{ date: "2024-04-02", desktop: 97, mobile: 180 }, { date: '2024-04-02', desktop: 97, mobile: 180 },
{ date: "2024-04-03", desktop: 167, mobile: 120 }, { date: '2024-04-03', desktop: 167, mobile: 120 },
{ date: "2024-04-04", desktop: 242, mobile: 260 }, { date: '2024-04-04', desktop: 242, mobile: 260 },
{ date: "2024-04-05", desktop: 373, mobile: 290 }, { date: '2024-04-05', desktop: 373, mobile: 290 },
{ date: "2024-04-06", desktop: 301, mobile: 340 }, { date: '2024-04-06', desktop: 301, mobile: 340 },
{ date: "2024-04-07", desktop: 245, mobile: 180 }, { date: '2024-04-07', desktop: 245, mobile: 180 },
{ date: "2024-04-08", desktop: 409, mobile: 320 }, { date: '2024-04-08', desktop: 409, mobile: 320 },
{ date: "2024-04-09", desktop: 59, mobile: 110 }, { date: '2024-04-09', desktop: 59, mobile: 110 },
{ date: "2024-04-10", desktop: 261, mobile: 190 }, { date: '2024-04-10', desktop: 261, mobile: 190 },
{ date: "2024-04-11", desktop: 327, mobile: 350 }, { date: '2024-04-11', desktop: 327, mobile: 350 },
{ date: "2024-04-12", desktop: 292, mobile: 210 }, { date: '2024-04-12', desktop: 292, mobile: 210 },
{ date: "2024-04-13", desktop: 342, mobile: 380 }, { date: '2024-04-13', desktop: 342, mobile: 380 },
{ date: "2024-04-14", desktop: 137, mobile: 220 }, { date: '2024-04-14', desktop: 137, mobile: 220 },
{ date: "2024-04-15", desktop: 120, mobile: 170 }, { date: '2024-04-15', desktop: 120, mobile: 170 },
{ date: "2024-04-16", desktop: 138, mobile: 190 }, { date: '2024-04-16', desktop: 138, mobile: 190 },
{ date: "2024-04-17", desktop: 446, mobile: 360 }, { date: '2024-04-17', desktop: 446, mobile: 360 },
{ date: "2024-04-18", desktop: 364, mobile: 410 }, { date: '2024-04-18', desktop: 364, mobile: 410 },
{ date: "2024-04-19", desktop: 243, mobile: 180 }, { date: '2024-04-19', desktop: 243, mobile: 180 },
{ date: "2024-04-20", desktop: 89, mobile: 150 }, { date: '2024-04-20', desktop: 89, mobile: 150 },
{ date: "2024-04-21", desktop: 137, mobile: 200 }, { date: '2024-04-21', desktop: 137, mobile: 200 },
{ date: "2024-04-22", desktop: 224, mobile: 170 }, { date: '2024-04-22', desktop: 224, mobile: 170 },
{ date: "2024-04-23", desktop: 138, mobile: 230 }, { date: '2024-04-23', desktop: 138, mobile: 230 },
{ date: "2024-04-24", desktop: 387, mobile: 290 }, { date: '2024-04-24', desktop: 387, mobile: 290 },
{ date: "2024-04-25", desktop: 215, mobile: 250 }, { date: '2024-04-25', desktop: 215, mobile: 250 },
{ date: "2024-04-26", desktop: 75, mobile: 130 }, { date: '2024-04-26', desktop: 75, mobile: 130 },
{ date: "2024-04-27", desktop: 383, mobile: 420 }, { date: '2024-04-27', desktop: 383, mobile: 420 },
{ date: "2024-04-28", desktop: 122, mobile: 180 }, { date: '2024-04-28', desktop: 122, mobile: 180 },
{ date: "2024-04-29", desktop: 315, mobile: 240 }, { date: '2024-04-29', desktop: 315, mobile: 240 },
{ date: "2024-04-30", desktop: 454, mobile: 380 }, { date: '2024-04-30', desktop: 454, mobile: 380 },
{ date: "2024-05-01", desktop: 165, mobile: 220 }, { date: '2024-05-01', desktop: 165, mobile: 220 },
{ date: "2024-05-02", desktop: 293, mobile: 310 }, { date: '2024-05-02', desktop: 293, mobile: 310 },
{ date: "2024-05-03", desktop: 247, mobile: 190 }, { date: '2024-05-03', desktop: 247, mobile: 190 },
{ date: "2024-05-04", desktop: 385, mobile: 420 }, { date: '2024-05-04', desktop: 385, mobile: 420 },
{ date: "2024-05-05", desktop: 481, mobile: 390 }, { date: '2024-05-05', desktop: 481, mobile: 390 },
{ date: "2024-05-06", desktop: 498, mobile: 520 }, { date: '2024-05-06', desktop: 498, mobile: 520 },
{ date: "2024-05-07", desktop: 388, mobile: 300 }, { date: '2024-05-07', desktop: 388, mobile: 300 },
{ date: "2024-05-08", desktop: 149, mobile: 210 }, { date: '2024-05-08', desktop: 149, mobile: 210 },
{ date: "2024-05-09", desktop: 227, mobile: 180 }, { date: '2024-05-09', desktop: 227, mobile: 180 },
{ date: "2024-05-10", desktop: 293, mobile: 330 }, { date: '2024-05-10', desktop: 293, mobile: 330 },
{ date: "2024-05-11", desktop: 335, mobile: 270 }, { date: '2024-05-11', desktop: 335, mobile: 270 },
{ date: "2024-05-12", desktop: 197, mobile: 240 }, { date: '2024-05-12', desktop: 197, mobile: 240 },
{ date: "2024-05-13", desktop: 197, mobile: 160 }, { date: '2024-05-13', desktop: 197, mobile: 160 },
{ date: "2024-05-14", desktop: 448, mobile: 490 }, { date: '2024-05-14', desktop: 448, mobile: 490 },
{ date: "2024-05-15", desktop: 473, mobile: 380 }, { date: '2024-05-15', desktop: 473, mobile: 380 },
{ date: "2024-05-16", desktop: 338, mobile: 400 }, { date: '2024-05-16', desktop: 338, mobile: 400 },
{ date: "2024-05-17", desktop: 499, mobile: 420 }, { date: '2024-05-17', desktop: 499, mobile: 420 },
{ date: "2024-05-18", desktop: 315, mobile: 350 }, { date: '2024-05-18', desktop: 315, mobile: 350 },
{ date: "2024-05-19", desktop: 235, mobile: 180 }, { date: '2024-05-19', desktop: 235, mobile: 180 },
{ date: "2024-05-20", desktop: 177, mobile: 230 }, { date: '2024-05-20', desktop: 177, mobile: 230 },
{ date: "2024-05-21", desktop: 82, mobile: 140 }, { date: '2024-05-21', desktop: 82, mobile: 140 },
{ date: "2024-05-22", desktop: 81, mobile: 120 }, { date: '2024-05-22', desktop: 81, mobile: 120 },
{ date: "2024-05-23", desktop: 252, mobile: 290 }, { date: '2024-05-23', desktop: 252, mobile: 290 },
{ date: "2024-05-24", desktop: 294, mobile: 220 }, { date: '2024-05-24', desktop: 294, mobile: 220 },
{ date: "2024-05-25", desktop: 201, mobile: 250 }, { date: '2024-05-25', desktop: 201, mobile: 250 },
{ date: "2024-05-26", desktop: 213, mobile: 170 }, { date: '2024-05-26', desktop: 213, mobile: 170 },
{ date: "2024-05-27", desktop: 420, mobile: 460 }, { date: '2024-05-27', desktop: 420, mobile: 460 },
{ date: "2024-05-28", desktop: 233, mobile: 190 }, { date: '2024-05-28', desktop: 233, mobile: 190 },
{ date: "2024-05-29", desktop: 78, mobile: 130 }, { date: '2024-05-29', desktop: 78, mobile: 130 },
{ date: "2024-05-30", desktop: 340, mobile: 280 }, { date: '2024-05-30', desktop: 340, mobile: 280 },
{ date: "2024-05-31", desktop: 178, mobile: 230 }, { date: '2024-05-31', desktop: 178, mobile: 230 },
{ date: "2024-06-01", desktop: 178, mobile: 200 }, { date: '2024-06-01', desktop: 178, mobile: 200 },
{ date: "2024-06-02", desktop: 470, mobile: 410 }, { date: '2024-06-02', desktop: 470, mobile: 410 },
{ date: "2024-06-03", desktop: 103, mobile: 160 }, { date: '2024-06-03', desktop: 103, mobile: 160 },
{ date: "2024-06-04", desktop: 439, mobile: 380 }, { date: '2024-06-04', desktop: 439, mobile: 380 },
{ date: "2024-06-05", desktop: 88, mobile: 140 }, { date: '2024-06-05', desktop: 88, mobile: 140 },
{ date: "2024-06-06", desktop: 294, mobile: 250 }, { date: '2024-06-06', desktop: 294, mobile: 250 },
{ date: "2024-06-07", desktop: 323, mobile: 370 }, { date: '2024-06-07', desktop: 323, mobile: 370 },
{ date: "2024-06-08", desktop: 385, mobile: 320 }, { date: '2024-06-08', desktop: 385, mobile: 320 },
{ date: "2024-06-09", desktop: 438, mobile: 480 }, { date: '2024-06-09', desktop: 438, mobile: 480 },
{ date: "2024-06-10", desktop: 155, mobile: 200 }, { date: '2024-06-10', desktop: 155, mobile: 200 },
{ date: "2024-06-11", desktop: 92, mobile: 150 }, { date: '2024-06-11', desktop: 92, mobile: 150 },
{ date: "2024-06-12", desktop: 492, mobile: 420 }, { date: '2024-06-12', desktop: 492, mobile: 420 },
{ date: "2024-06-13", desktop: 81, mobile: 130 }, { date: '2024-06-13', desktop: 81, mobile: 130 },
{ date: "2024-06-14", desktop: 426, mobile: 380 }, { date: '2024-06-14', desktop: 426, mobile: 380 },
{ date: "2024-06-15", desktop: 307, mobile: 350 }, { date: '2024-06-15', desktop: 307, mobile: 350 },
{ date: "2024-06-16", desktop: 371, mobile: 310 }, { date: '2024-06-16', desktop: 371, mobile: 310 },
{ date: "2024-06-17", desktop: 475, mobile: 520 }, { date: '2024-06-17', desktop: 475, mobile: 520 },
{ date: "2024-06-18", desktop: 107, mobile: 170 }, { date: '2024-06-18', desktop: 107, mobile: 170 },
{ date: "2024-06-19", desktop: 341, mobile: 290 }, { date: '2024-06-19', desktop: 341, mobile: 290 },
{ date: "2024-06-20", desktop: 408, mobile: 450 }, { date: '2024-06-20', desktop: 408, mobile: 450 },
{ date: "2024-06-21", desktop: 169, mobile: 210 }, { date: '2024-06-21', desktop: 169, mobile: 210 },
{ date: "2024-06-22", desktop: 317, mobile: 270 }, { date: '2024-06-22', desktop: 317, mobile: 270 },
{ date: "2024-06-23", desktop: 480, mobile: 530 }, { date: '2024-06-23', desktop: 480, mobile: 530 },
{ date: "2024-06-24", desktop: 132, mobile: 180 }, { date: '2024-06-24', desktop: 132, mobile: 180 },
{ date: "2024-06-25", desktop: 141, mobile: 190 }, { date: '2024-06-25', desktop: 141, mobile: 190 },
{ date: "2024-06-26", desktop: 434, mobile: 380 }, { date: '2024-06-26', desktop: 434, mobile: 380 },
{ date: "2024-06-27", desktop: 448, mobile: 490 }, { date: '2024-06-27', desktop: 448, mobile: 490 },
{ date: "2024-06-28", desktop: 149, mobile: 200 }, { date: '2024-06-28', desktop: 149, mobile: 200 },
{ date: "2024-06-29", desktop: 103, mobile: 160 }, { date: '2024-06-29', desktop: 103, mobile: 160 },
{ date: "2024-06-30", desktop: 446, mobile: 400 }, { date: '2024-06-30', desktop: 446, mobile: 400 },
] ];
const chartConfig = { const chartConfig = {
visitors: { visitors: {
label: "Visitors", label: 'Visitors',
}, },
desktop: { desktop: {
label: "Desktop", label: 'Desktop',
color: "var(--primary)", color: 'var(--primary)',
}, },
mobile: { mobile: {
label: "Mobile", label: 'Mobile',
color: "var(--primary)", color: 'var(--primary)',
}, },
} satisfies ChartConfig } satisfies ChartConfig;
export function ChartAreaInteractive() { export function ChartAreaInteractive() {
const isMobile = useIsMobile() const isMobile = useIsMobile();
const [timeRange, setTimeRange] = React.useState("90d") const [timeRange, setTimeRange] = React.useState('90d');
React.useEffect(() => { React.useEffect(() => {
if (isMobile) { if (isMobile) {
setTimeRange("7d") setTimeRange('7d');
} }
}, [isMobile]) }, [isMobile]);
const filteredData = chartData.filter((item) => { const filteredData = chartData.filter((item) => {
const date = new Date(item.date) const date = new Date(item.date);
const referenceDate = new Date("2024-06-30") const referenceDate = new Date('2024-06-30');
let daysToSubtract = 90 let daysToSubtract = 90;
if (timeRange === "30d") { if (timeRange === '30d') {
daysToSubtract = 30 daysToSubtract = 30;
} else if (timeRange === "7d") {
daysToSubtract = 7
} }
const startDate = new Date(referenceDate) else if (timeRange === '7d') {
startDate.setDate(startDate.getDate() - daysToSubtract) daysToSubtract = 7;
return date >= startDate }
}) const startDate = new Date(referenceDate);
startDate.setDate(startDate.getDate() - daysToSubtract);
return date >= startDate;
});
return ( return (
<Card className="@container/card"> <Card className="@container/card">
@@ -248,26 +250,26 @@ export function ChartAreaInteractive() {
tickMargin={8} tickMargin={8}
minTickGap={32} minTickGap={32}
tickFormatter={(value) => { tickFormatter={(value) => {
const date = new Date(value) const date = new Date(value);
return date.toLocaleDateString("en-US", { return date.toLocaleDateString('en-US', {
month: "short", month: 'short',
day: "numeric", day: 'numeric',
}) });
}} }}
/> />
<ChartTooltip <ChartTooltip
cursor={false} cursor={false}
content={ content={(
<ChartTooltipContent <ChartTooltipContent
labelFormatter={(value) => { labelFormatter={(value) => {
return new Date(value).toLocaleDateString("en-US", { return new Date(value).toLocaleDateString('en-US', {
month: "short", month: 'short',
day: "numeric", day: 'numeric',
}) });
}} }}
indicator="dot" indicator="dot"
/> />
} )}
/> />
<Area <Area
dataKey="mobile" dataKey="mobile"
@@ -287,5 +289,5 @@ export function ChartAreaInteractive() {
</ChartContainer> </ChartContainer>
</CardContent> </CardContent>
</Card> </Card>
) );
} }

View File

@@ -1,23 +1,25 @@
import * as React from "react" import type { DragEndEvent, UniqueIdentifier } from '@dnd-kit/core';
import type { ColumnDef, ColumnFiltersState, Row, SortingState, VisibilityState } from '@tanstack/react-table';
import type { ChartConfig } from '@/components/ui/chart';
import { import {
closestCenter, closestCenter,
DndContext, DndContext,
KeyboardSensor, KeyboardSensor,
MouseSensor, MouseSensor,
TouchSensor, TouchSensor,
useSensor, useSensor,
useSensors, useSensors,
type DragEndEvent, } from '@dnd-kit/core';
type UniqueIdentifier, import { restrictToVerticalAxis } from '@dnd-kit/modifiers';
} from "@dnd-kit/core"
import { restrictToVerticalAxis } from "@dnd-kit/modifiers"
import { import {
arrayMove, arrayMove,
SortableContext, SortableContext,
useSortable, useSortable,
verticalListSortingStrategy, verticalListSortingStrategy,
} from "@dnd-kit/sortable" } from '@dnd-kit/sortable';
import { CSS } from "@dnd-kit/utilities" import { CSS } from '@dnd-kit/utilities';
import { import {
IconChevronDown, IconChevronDown,
IconChevronLeft, IconChevronLeft,
@@ -31,8 +33,9 @@ import {
IconLoader, IconLoader,
IconPlus, IconPlus,
IconTrendingUp, IconTrendingUp,
} from "@tabler/icons-react" } from '@tabler/icons-react';
import { import {
flexRender, flexRender,
getCoreRowModel, getCoreRowModel,
getFacetedRowModel, getFacetedRowModel,
@@ -40,27 +43,24 @@ import {
getFilteredRowModel, getFilteredRowModel,
getPaginationRowModel, getPaginationRowModel,
getSortedRowModel, getSortedRowModel,
useReactTable,
type ColumnDef,
type ColumnFiltersState,
type Row,
type SortingState,
type VisibilityState,
} from "@tanstack/react-table"
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts"
import { toast } from "sonner"
import { z } from "zod"
import { useIsMobile } from "@/hooks/use-mobile" useReactTable,
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button" } from '@tanstack/react-table';
import * as React from 'react';
import { Area, AreaChart, CartesianGrid, XAxis } from 'recharts';
import { toast } from 'sonner';
import { z } from 'zod';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { import {
ChartContainer, ChartContainer,
ChartTooltip, ChartTooltip,
ChartTooltipContent, ChartTooltipContent,
type ChartConfig, } from '@/components/ui/chart';
} from "@/components/ui/chart" import { Checkbox } from '@/components/ui/checkbox';
import { Checkbox } from "@/components/ui/checkbox"
import { import {
Drawer, Drawer,
DrawerClose, DrawerClose,
@@ -70,7 +70,7 @@ import {
DrawerHeader, DrawerHeader,
DrawerTitle, DrawerTitle,
DrawerTrigger, DrawerTrigger,
} from "@/components/ui/drawer" } from '@/components/ui/drawer';
import { import {
DropdownMenu, DropdownMenu,
DropdownMenuCheckboxItem, DropdownMenuCheckboxItem,
@@ -78,17 +78,17 @@ import {
DropdownMenuItem, DropdownMenuItem,
DropdownMenuSeparator, DropdownMenuSeparator,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu" } from '@/components/ui/dropdown-menu';
import { Input } from "@/components/ui/input" import { Input } from '@/components/ui/input';
import { Label } from "@/components/ui/label" import { Label } from '@/components/ui/label';
import { import {
Select, Select,
SelectContent, SelectContent,
SelectItem, SelectItem,
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select" } from '@/components/ui/select';
import { Separator } from "@/components/ui/separator" import { Separator } from '@/components/ui/separator';
import { import {
Table, Table,
TableBody, TableBody,
@@ -96,13 +96,14 @@ import {
TableHead, TableHead,
TableHeader, TableHeader,
TableRow, TableRow,
} from "@/components/ui/table" } from '@/components/ui/table';
import { import {
Tabs, Tabs,
TabsContent, TabsContent,
TabsList, TabsList,
TabsTrigger, TabsTrigger,
} from "@/components/ui/tabs" } from '@/components/ui/tabs';
import { useIsMobile } from '@/hooks/use-mobile';
export const schema = z.object({ export const schema = z.object({
id: z.number(), id: z.number(),
@@ -112,13 +113,13 @@ export const schema = z.object({
target: z.string(), target: z.string(),
limit: z.string(), limit: z.string(),
reviewer: z.string(), reviewer: z.string(),
}) });
// Create a separate component for the drag handle // Create a separate component for the drag handle
function DragHandle({ id }: { id: number }) { function DragHandle({ id }: { id: number }) {
const { attributes, listeners } = useSortable({ const { attributes, listeners } = useSortable({
id, id,
}) });
return ( return (
<Button <Button
@@ -131,25 +132,25 @@ function DragHandle({ id }: { id: number }) {
<IconGripVertical className="text-muted-foreground size-3" /> <IconGripVertical className="text-muted-foreground size-3" />
<span className="sr-only">Drag to reorder</span> <span className="sr-only">Drag to reorder</span>
</Button> </Button>
) );
} }
const columns: ColumnDef<z.infer<typeof schema>>[] = [ const columns: ColumnDef<z.infer<typeof schema>>[] = [
{ {
id: "drag", id: 'drag',
header: () => null, header: () => null,
cell: ({ row }) => <DragHandle id={row.original.id} />, cell: ({ row }) => <DragHandle id={row.original.id} />,
}, },
{ {
id: "select", id: 'select',
header: ({ table }) => ( header: ({ table }) => (
<div className="flex items-center justify-center"> <div className="flex items-center justify-center">
<Checkbox <Checkbox
checked={ checked={
table.getIsAllPageRowsSelected() || table.getIsAllPageRowsSelected()
(table.getIsSomePageRowsSelected() && "indeterminate") || (table.getIsSomePageRowsSelected() && 'indeterminate')
} }
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)} onCheckedChange={value => table.toggleAllPageRowsSelected(!!value)}
aria-label="Select all" aria-label="Select all"
/> />
</div> </div>
@@ -158,7 +159,7 @@ const columns: ColumnDef<z.infer<typeof schema>>[] = [
<div className="flex items-center justify-center"> <div className="flex items-center justify-center">
<Checkbox <Checkbox
checked={row.getIsSelected()} checked={row.getIsSelected()}
onCheckedChange={(value) => row.toggleSelected(!!value)} onCheckedChange={value => row.toggleSelected(!!value)}
aria-label="Select row" aria-label="Select row"
/> />
</div> </div>
@@ -167,16 +168,16 @@ const columns: ColumnDef<z.infer<typeof schema>>[] = [
enableHiding: false, enableHiding: false,
}, },
{ {
accessorKey: "header", accessorKey: 'header',
header: "Header", header: 'Header',
cell: ({ row }) => { cell: ({ row }) => {
return <TableCellViewer item={row.original} /> return <TableCellViewer item={row.original} />;
}, },
enableHiding: false, enableHiding: false,
}, },
{ {
accessorKey: "type", accessorKey: 'type',
header: "Section Type", header: 'Section Type',
cell: ({ row }) => ( cell: ({ row }) => (
<div className="w-32"> <div className="w-32">
<Badge variant="outline" className="text-muted-foreground px-1.5"> <Badge variant="outline" className="text-muted-foreground px-1.5">
@@ -186,31 +187,33 @@ const columns: ColumnDef<z.infer<typeof schema>>[] = [
), ),
}, },
{ {
accessorKey: "status", accessorKey: 'status',
header: "Status", header: 'Status',
cell: ({ row }) => ( cell: ({ row }) => (
<Badge variant="outline" className="text-muted-foreground px-1.5"> <Badge variant="outline" className="text-muted-foreground px-1.5">
{row.original.status === "Done" ? ( {row.original.status === 'Done'
<IconCircleCheckFilled className="fill-green-500 dark:fill-green-400" /> ? (
) : ( <IconCircleCheckFilled className="fill-green-500 dark:fill-green-400" />
<IconLoader /> )
)} : (
<IconLoader />
)}
{row.original.status} {row.original.status}
</Badge> </Badge>
), ),
}, },
{ {
accessorKey: "target", accessorKey: 'target',
header: () => <div className="w-full text-right">Target</div>, header: () => <div className="w-full text-right">Target</div>,
cell: ({ row }) => ( cell: ({ row }) => (
<form <form
onSubmit={(e) => { onSubmit={(e) => {
e.preventDefault() e.preventDefault();
toast.promise(new Promise((resolve) => setTimeout(resolve, 1000)), { toast.promise(new Promise(resolve => setTimeout(resolve, 1000)), {
loading: `Saving ${row.original.header}`, loading: `Saving ${row.original.header}`,
success: "Done", success: 'Done',
error: "Error", error: 'Error',
}) });
}} }}
> >
<Label htmlFor={`${row.original.id}-target`} className="sr-only"> <Label htmlFor={`${row.original.id}-target`} className="sr-only">
@@ -225,17 +228,17 @@ const columns: ColumnDef<z.infer<typeof schema>>[] = [
), ),
}, },
{ {
accessorKey: "limit", accessorKey: 'limit',
header: () => <div className="w-full text-right">Limit</div>, header: () => <div className="w-full text-right">Limit</div>,
cell: ({ row }) => ( cell: ({ row }) => (
<form <form
onSubmit={(e) => { onSubmit={(e) => {
e.preventDefault() e.preventDefault();
toast.promise(new Promise((resolve) => setTimeout(resolve, 1000)), { toast.promise(new Promise(resolve => setTimeout(resolve, 1000)), {
loading: `Saving ${row.original.header}`, loading: `Saving ${row.original.header}`,
success: "Done", success: 'Done',
error: "Error", error: 'Error',
}) });
}} }}
> >
<Label htmlFor={`${row.original.id}-limit`} className="sr-only"> <Label htmlFor={`${row.original.id}-limit`} className="sr-only">
@@ -250,13 +253,13 @@ const columns: ColumnDef<z.infer<typeof schema>>[] = [
), ),
}, },
{ {
accessorKey: "reviewer", accessorKey: 'reviewer',
header: "Reviewer", header: 'Reviewer',
cell: ({ row }) => { cell: ({ row }) => {
const isAssigned = row.original.reviewer !== "Assign reviewer" const isAssigned = row.original.reviewer !== 'Assign reviewer';
if (isAssigned) { if (isAssigned) {
return row.original.reviewer return row.original.reviewer;
} }
return ( return (
@@ -280,11 +283,11 @@ const columns: ColumnDef<z.infer<typeof schema>>[] = [
</SelectContent> </SelectContent>
</Select> </Select>
</> </>
) );
}, },
}, },
{ {
id: "actions", id: 'actions',
cell: () => ( cell: () => (
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
@@ -307,61 +310,61 @@ const columns: ColumnDef<z.infer<typeof schema>>[] = [
</DropdownMenu> </DropdownMenu>
), ),
}, },
] ];
function DraggableRow({ row }: { row: Row<z.infer<typeof schema>> }) { function DraggableRow({ row }: { row: Row<z.infer<typeof schema>> }) {
const { transform, transition, setNodeRef, isDragging } = useSortable({ const { transform, transition, setNodeRef, isDragging } = useSortable({
id: row.original.id, id: row.original.id,
}) });
return ( return (
<TableRow <TableRow
data-state={row.getIsSelected() && "selected"} data-state={row.getIsSelected() && 'selected'}
data-dragging={isDragging} data-dragging={isDragging}
ref={setNodeRef} ref={setNodeRef}
className="relative z-0 data-[dragging=true]:z-10 data-[dragging=true]:opacity-80" className="relative z-0 data-[dragging=true]:z-10 data-[dragging=true]:opacity-80"
style={{ style={{
transform: CSS.Transform.toString(transform), transform: CSS.Transform.toString(transform),
transition: transition, transition,
}} }}
> >
{row.getVisibleCells().map((cell) => ( {row.getVisibleCells().map(cell => (
<TableCell key={cell.id}> <TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())} {flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell> </TableCell>
))} ))}
</TableRow> </TableRow>
) );
} }
export function DataTable({ export function DataTable({
data: initialData, data: initialData,
}: { }: {
data: z.infer<typeof schema>[] data: z.infer<typeof schema>[];
}) { }) {
const [data, setData] = React.useState(() => initialData) const [data, setData] = React.useState(() => initialData);
const [rowSelection, setRowSelection] = React.useState({}) const [rowSelection, setRowSelection] = React.useState({});
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility]
React.useState<VisibilityState>({}) = React.useState<VisibilityState>({});
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>( const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[] [],
) );
const [sorting, setSorting] = React.useState<SortingState>([]) const [sorting, setSorting] = React.useState<SortingState>([]);
const [pagination, setPagination] = React.useState({ const [pagination, setPagination] = React.useState({
pageIndex: 0, pageIndex: 0,
pageSize: 10, pageSize: 10,
}) });
const sortableId = React.useId() const sortableId = React.useId();
const sensors = useSensors( const sensors = useSensors(
useSensor(MouseSensor, {}), useSensor(MouseSensor, {}),
useSensor(TouchSensor, {}), useSensor(TouchSensor, {}),
useSensor(KeyboardSensor, {}) useSensor(KeyboardSensor, {}),
) );
const dataIds = React.useMemo<UniqueIdentifier[]>( const dataIds = React.useMemo<UniqueIdentifier[]>(
() => data?.map(({ id }) => id) || [], () => data?.map(({ id }) => id) || [],
[data] [data],
) );
const table = useReactTable({ const table = useReactTable({
data, data,
@@ -373,7 +376,7 @@ export function DataTable({
columnFilters, columnFilters,
pagination, pagination,
}, },
getRowId: (row) => row.id.toString(), getRowId: row => row.id.toString(),
enableRowSelection: true, enableRowSelection: true,
onRowSelectionChange: setRowSelection, onRowSelectionChange: setRowSelection,
onSortingChange: setSorting, onSortingChange: setSorting,
@@ -386,16 +389,16 @@ export function DataTable({
getSortedRowModel: getSortedRowModel(), getSortedRowModel: getSortedRowModel(),
getFacetedRowModel: getFacetedRowModel(), getFacetedRowModel: getFacetedRowModel(),
getFacetedUniqueValues: getFacetedUniqueValues(), getFacetedUniqueValues: getFacetedUniqueValues(),
}) });
function handleDragEnd(event: DragEndEvent) { function handleDragEnd(event: DragEndEvent) {
const { active, over } = event const { active, over } = event;
if (active && over && active.id !== over.id) { if (active && over && active.id !== over.id) {
setData((data) => { setData((data) => {
const oldIndex = dataIds.indexOf(active.id) const oldIndex = dataIds.indexOf(active.id);
const newIndex = dataIds.indexOf(over.id) const newIndex = dataIds.indexOf(over.id);
return arrayMove(data, oldIndex, newIndex) return arrayMove(data, oldIndex, newIndex);
}) });
} }
} }
@@ -426,10 +429,14 @@ export function DataTable({
<TabsList className="**:data-[slot=badge]:bg-muted-foreground/30 hidden **:data-[slot=badge]:size-5 **:data-[slot=badge]:rounded-full **:data-[slot=badge]:px-1 @4xl/main:flex"> <TabsList className="**:data-[slot=badge]:bg-muted-foreground/30 hidden **:data-[slot=badge]:size-5 **:data-[slot=badge]:rounded-full **:data-[slot=badge]:px-1 @4xl/main:flex">
<TabsTrigger value="outline">Outline</TabsTrigger> <TabsTrigger value="outline">Outline</TabsTrigger>
<TabsTrigger value="past-performance"> <TabsTrigger value="past-performance">
Past Performance <Badge variant="secondary">3</Badge> Past Performance
{' '}
<Badge variant="secondary">3</Badge>
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="key-personnel"> <TabsTrigger value="key-personnel">
Key Personnel <Badge variant="secondary">2</Badge> Key Personnel
{' '}
<Badge variant="secondary">2</Badge>
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="focus-documents">Focus Documents</TabsTrigger> <TabsTrigger value="focus-documents">Focus Documents</TabsTrigger>
</TabsList> </TabsList>
@@ -447,9 +454,9 @@ export function DataTable({
{table {table
.getAllColumns() .getAllColumns()
.filter( .filter(
(column) => column =>
typeof column.accessorFn !== "undefined" && typeof column.accessorFn !== 'undefined'
column.getCanHide() && column.getCanHide(),
) )
.map((column) => { .map((column) => {
return ( return (
@@ -457,13 +464,12 @@ export function DataTable({
key={column.id} key={column.id}
className="capitalize" className="capitalize"
checked={column.getIsVisible()} checked={column.getIsVisible()}
onCheckedChange={(value) => onCheckedChange={value =>
column.toggleVisibility(!!value) column.toggleVisibility(!!value)}
}
> >
{column.id} {column.id}
</DropdownMenuCheckboxItem> </DropdownMenuCheckboxItem>
) );
})} })}
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
@@ -487,7 +493,7 @@ export function DataTable({
> >
<Table> <Table>
<TableHeader className="bg-muted sticky top-0 z-10"> <TableHeader className="bg-muted sticky top-0 z-10">
{table.getHeaderGroups().map((headerGroup) => ( {table.getHeaderGroups().map(headerGroup => (
<TableRow key={headerGroup.id}> <TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => { {headerGroup.headers.map((header) => {
return ( return (
@@ -496,42 +502,49 @@ export function DataTable({
? null ? null
: flexRender( : flexRender(
header.column.columnDef.header, header.column.columnDef.header,
header.getContext() header.getContext(),
)} )}
</TableHead> </TableHead>
) );
})} })}
</TableRow> </TableRow>
))} ))}
</TableHeader> </TableHeader>
<TableBody className="**:data-[slot=table-cell]:first:w-8"> <TableBody className="**:data-[slot=table-cell]:first:w-8">
{table.getRowModel().rows?.length ? ( {table.getRowModel().rows?.length
<SortableContext ? (
items={dataIds} <SortableContext
strategy={verticalListSortingStrategy} items={dataIds}
> strategy={verticalListSortingStrategy}
{table.getRowModel().rows.map((row) => ( >
<DraggableRow key={row.id} row={row} /> {table.getRowModel().rows.map(row => (
))} <DraggableRow key={row.id} row={row} />
</SortableContext> ))}
) : ( </SortableContext>
<TableRow> )
<TableCell : (
colSpan={columns.length} <TableRow>
className="h-24 text-center" <TableCell
> colSpan={columns.length}
No results. className="h-24 text-center"
</TableCell> >
</TableRow> No results.
)} </TableCell>
</TableRow>
)}
</TableBody> </TableBody>
</Table> </Table>
</DndContext> </DndContext>
</div> </div>
<div className="flex items-center justify-between px-4"> <div className="flex items-center justify-between px-4">
<div className="text-muted-foreground hidden flex-1 text-sm lg:flex"> <div className="text-muted-foreground hidden flex-1 text-sm lg:flex">
{table.getFilteredSelectedRowModel().rows.length} of{" "} {table.getFilteredSelectedRowModel().rows.length}
{table.getFilteredRowModel().rows.length} row(s) selected. {' '}
of
{' '}
{table.getFilteredRowModel().rows.length}
{' '}
row(s) selected.
</div> </div>
<div className="flex w-full items-center gap-8 lg:w-fit"> <div className="flex w-full items-center gap-8 lg:w-fit">
<div className="hidden items-center gap-2 lg:flex"> <div className="hidden items-center gap-2 lg:flex">
@@ -541,7 +554,7 @@ export function DataTable({
<Select <Select
value={`${table.getState().pagination.pageSize}`} value={`${table.getState().pagination.pageSize}`}
onValueChange={(value) => { onValueChange={(value) => {
table.setPageSize(Number(value)) table.setPageSize(Number(value));
}} }}
> >
<SelectTrigger size="sm" className="w-20" id="rows-per-page"> <SelectTrigger size="sm" className="w-20" id="rows-per-page">
@@ -550,7 +563,7 @@ export function DataTable({
/> />
</SelectTrigger> </SelectTrigger>
<SelectContent side="top"> <SelectContent side="top">
{[10, 20, 30, 40, 50].map((pageSize) => ( {[10, 20, 30, 40, 50].map(pageSize => (
<SelectItem key={pageSize} value={`${pageSize}`}> <SelectItem key={pageSize} value={`${pageSize}`}>
{pageSize} {pageSize}
</SelectItem> </SelectItem>
@@ -559,7 +572,12 @@ export function DataTable({
</Select> </Select>
</div> </div>
<div className="flex w-fit items-center justify-center text-sm font-medium"> <div className="flex w-fit items-center justify-center text-sm font-medium">
Page {table.getState().pagination.pageIndex + 1} of{" "} Page
{' '}
{table.getState().pagination.pageIndex + 1}
{' '}
of
{' '}
{table.getPageCount()} {table.getPageCount()}
</div> </div>
<div className="ml-auto flex items-center gap-2 lg:ml-0"> <div className="ml-auto flex items-center gap-2 lg:ml-0">
@@ -622,34 +640,34 @@ export function DataTable({
<div className="aspect-video w-full flex-1 rounded-lg border border-dashed"></div> <div className="aspect-video w-full flex-1 rounded-lg border border-dashed"></div>
</TabsContent> </TabsContent>
</Tabs> </Tabs>
) );
} }
const chartData = [ const chartData = [
{ month: "January", desktop: 186, mobile: 80 }, { month: 'January', desktop: 186, mobile: 80 },
{ month: "February", desktop: 305, mobile: 200 }, { month: 'February', desktop: 305, mobile: 200 },
{ month: "March", desktop: 237, mobile: 120 }, { month: 'March', desktop: 237, mobile: 120 },
{ month: "April", desktop: 73, mobile: 190 }, { month: 'April', desktop: 73, mobile: 190 },
{ month: "May", desktop: 209, mobile: 130 }, { month: 'May', desktop: 209, mobile: 130 },
{ month: "June", desktop: 214, mobile: 140 }, { month: 'June', desktop: 214, mobile: 140 },
] ];
const chartConfig = { const chartConfig = {
desktop: { desktop: {
label: "Desktop", label: 'Desktop',
color: "var(--primary)", color: 'var(--primary)',
}, },
mobile: { mobile: {
label: "Mobile", label: 'Mobile',
color: "var(--primary)", color: 'var(--primary)',
}, },
} satisfies ChartConfig } satisfies ChartConfig;
function TableCellViewer({ item }: { item: z.infer<typeof schema> }) { function TableCellViewer({ item }: { item: z.infer<typeof schema> }) {
const isMobile = useIsMobile() const isMobile = useIsMobile();
return ( return (
<Drawer direction={isMobile ? "bottom" : "right"}> <Drawer direction={isMobile ? 'bottom' : 'right'}>
<DrawerTrigger asChild> <DrawerTrigger asChild>
<Button variant="link" className="text-foreground w-fit px-0 text-left"> <Button variant="link" className="text-foreground w-fit px-0 text-left">
{item.header} {item.header}
@@ -680,7 +698,7 @@ function TableCellViewer({ item }: { item: z.infer<typeof schema> }) {
tickLine={false} tickLine={false}
axisLine={false} axisLine={false}
tickMargin={8} tickMargin={8}
tickFormatter={(value) => value.slice(0, 3)} tickFormatter={value => value.slice(0, 3)}
hide hide
/> />
<ChartTooltip <ChartTooltip
@@ -708,7 +726,8 @@ function TableCellViewer({ item }: { item: z.infer<typeof schema> }) {
<Separator /> <Separator />
<div className="grid gap-2"> <div className="grid gap-2">
<div className="flex gap-2 leading-none font-medium"> <div className="flex gap-2 leading-none font-medium">
Trending up by 5.2% this month{" "} Trending up by 5.2% this month
{' '}
<IconTrendingUp className="size-4" /> <IconTrendingUp className="size-4" />
</div> </div>
<div className="text-muted-foreground"> <div className="text-muted-foreground">
@@ -801,5 +820,5 @@ function TableCellViewer({ item }: { item: z.infer<typeof schema> }) {
</DrawerFooter> </DrawerFooter>
</DrawerContent> </DrawerContent>
</Drawer> </Drawer>
) );
} }

View File

@@ -1,12 +1,13 @@
"use client" 'use client';
import type { Icon } from '@tabler/icons-react';
import { import {
IconDots, IconDots,
IconFolder, IconFolder,
IconShare3, IconShare3,
IconTrash, IconTrash,
type Icon, } from '@tabler/icons-react';
} from "@tabler/icons-react"
import { import {
DropdownMenu, DropdownMenu,
@@ -14,7 +15,7 @@ import {
DropdownMenuItem, DropdownMenuItem,
DropdownMenuSeparator, DropdownMenuSeparator,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu" } from '@/components/ui/dropdown-menu';
import { import {
SidebarGroup, SidebarGroup,
SidebarGroupLabel, SidebarGroupLabel,
@@ -23,24 +24,24 @@ import {
SidebarMenuButton, SidebarMenuButton,
SidebarMenuItem, SidebarMenuItem,
useSidebar, useSidebar,
} from "@/components/ui/sidebar" } from '@/components/ui/sidebar';
export function NavDocuments({ export function NavDocuments({
items, items,
}: { }: {
items: { items: {
name: string name: string;
url: string url: string;
icon: Icon icon: Icon;
}[] }[];
}) { }) {
const { isMobile } = useSidebar() const { isMobile } = useSidebar();
return ( return (
<SidebarGroup className="group-data-[collapsible=icon]:hidden"> <SidebarGroup className="group-data-[collapsible=icon]:hidden">
<SidebarGroupLabel>Documents</SidebarGroupLabel> <SidebarGroupLabel>Documents</SidebarGroupLabel>
<SidebarMenu> <SidebarMenu>
{items.map((item) => ( {items.map(item => (
<SidebarMenuItem key={item.name}> <SidebarMenuItem key={item.name}>
<SidebarMenuButton asChild> <SidebarMenuButton asChild>
<a href={item.url}> <a href={item.url}>
@@ -60,8 +61,8 @@ export function NavDocuments({
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent <DropdownMenuContent
className="w-24 rounded-lg" className="w-24 rounded-lg"
side={isMobile ? "bottom" : "right"} side={isMobile ? 'bottom' : 'right'}
align={isMobile ? "end" : "start"} align={isMobile ? 'end' : 'start'}
> >
<DropdownMenuItem> <DropdownMenuItem>
<IconFolder /> <IconFolder />
@@ -88,5 +89,5 @@ export function NavDocuments({
</SidebarMenuItem> </SidebarMenuItem>
</SidebarMenu> </SidebarMenu>
</SidebarGroup> </SidebarGroup>
) );
} }

View File

@@ -1,7 +1,7 @@
"use client" 'use client';
import * as React from "react" import type { Icon } from '@tabler/icons-react';
import { type Icon } from "@tabler/icons-react" import * as React from 'react';
import { import {
SidebarGroup, SidebarGroup,
@@ -9,23 +9,23 @@ import {
SidebarMenu, SidebarMenu,
SidebarMenuButton, SidebarMenuButton,
SidebarMenuItem, SidebarMenuItem,
} from "@/components/ui/sidebar" } from '@/components/ui/sidebar';
export function NavSecondary({ export function NavSecondary({
items, items,
...props ...props
}: { }: {
items: { items: {
title: string title: string;
url: string url: string;
icon: Icon icon: Icon;
}[] }[];
} & React.ComponentPropsWithoutRef<typeof SidebarGroup>) { } & React.ComponentPropsWithoutRef<typeof SidebarGroup>) {
return ( return (
<SidebarGroup {...props}> <SidebarGroup {...props}>
<SidebarGroupContent> <SidebarGroupContent>
<SidebarMenu> <SidebarMenu>
{items.map((item) => ( {items.map(item => (
<SidebarMenuItem key={item.title}> <SidebarMenuItem key={item.title}>
<SidebarMenuButton asChild> <SidebarMenuButton asChild>
<a href={item.url}> <a href={item.url}>
@@ -38,5 +38,5 @@ export function NavSecondary({
</SidebarMenu> </SidebarMenu>
</SidebarGroupContent> </SidebarGroupContent>
</SidebarGroup> </SidebarGroup>
) );
} }

View File

@@ -1,19 +1,19 @@
import * as React from "react" import * as React from 'react';
const MOBILE_BREAKPOINT = 768 const MOBILE_BREAKPOINT = 768;
export function useIsMobile() { export function useIsMobile() {
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined) const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined);
React.useEffect(() => { React.useEffect(() => {
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`) const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
const onChange = () => { const onChange = () => {
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
} };
mql.addEventListener("change", onChange) mql.addEventListener('change', onChange);
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
return () => mql.removeEventListener("change", onChange) return () => mql.removeEventListener('change', onChange);
}, []) }, []);
return !!isMobile return !!isMobile;
} }

View File

@@ -16,18 +16,18 @@ function RouteComponent() {
const { email } = Route.useSearch(); const { email } = Route.useSearch();
return email !== undefined return email !== undefined
? ( ? (
<div className=" <div className="
bg-background flex min-h-svh flex-row items-center justify-center gap-6 p-6 md:p-10" bg-background flex min-h-svh flex-row items-center justify-center gap-6 p-6 md:p-10"
> >
<NixOSLogo className="size-12" /> <NixOSLogo className="size-12" />
<span <span
aria-hidden="true" aria-hidden="true"
className="mx-2 inline-block h-6 w-px bg-current opacity-40" className="mx-2 inline-block h-6 w-px bg-current opacity-40"
/> />
{' '} {' '}
{email} {email}
</div> </div>
) )
: <Navigate to="/login" />; : <Navigate to="/login" />;
} }

View File

@@ -12,7 +12,7 @@
/* Bundler mode */ /* Bundler mode */
"moduleResolution": "bundler", "moduleResolution": "bundler",
"paths": { "paths": {
"@/*": ["./src/*"], "@/*": ["./src/*"]
}, },
"types": ["vite/client", "vite-plugin-svgr/client"], "types": ["vite/client", "vite-plugin-svgr/client"],
"allowImportingTsExtensions": true, "allowImportingTsExtensions": true,
@@ -26,7 +26,7 @@
"verbatimModuleSyntax": true, "verbatimModuleSyntax": true,
"erasableSyntaxOnly": true, "erasableSyntaxOnly": true,
"skipLibCheck": true, "skipLibCheck": true,
"noUncheckedSideEffectImports": true, "noUncheckedSideEffectImports": true
}, },
"include": ["src"], "include": ["src"]
} }