feat: WIP

This commit is contained in:
Pablo Lara
2024-09-25 06:56:34 +02:00
parent 087ffcbb95
commit e67f4e5f29
7 changed files with 298 additions and 45 deletions
+5 -4
View File
@@ -1,6 +1,6 @@
import { Input } from "@nextui-org/react";
import debounce from "lodash.debounce";
import { XCircle } from "lucide-react";
import { SearchIcon, XCircle } from "lucide-react";
import { useRouter, useSearchParams } from "next/navigation";
import React, { useCallback, useEffect, useState } from "react";
@@ -39,9 +39,9 @@ export const CustomSearchInput: React.FC = () => {
<Input
variant="bordered"
placeholder="Search..."
label="Search"
labelPlacement="inside"
labelPlacement="outside"
value={searchQuery}
startContent={<SearchIcon className="text-default-400" width={16} />}
onChange={(e) => {
const value = e.target.value;
setSearchQuery(value);
@@ -54,7 +54,8 @@ export const CustomSearchInput: React.FC = () => {
</button>
)
}
size="sm"
radius="full"
size="lg"
/>
);
};
+83
View File
@@ -595,3 +595,86 @@ export const SuccessIcon: React.FC<IconSvgProps> = ({
/>
</svg>
);
export const ArrowUpIcon: React.FC<IconSvgProps> = ({
size,
height,
width,
...props
}) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
height={size || height || "1em"}
viewBox="0 0 12 12"
width={size || width || "1em"}
aria-hidden="true"
focusable="false"
role="presentation"
{...props}
>
<path
d="M3 7.5L6 4.5L9 7.5"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
/>
</svg>
);
};
export const ArrowDownIcon: React.FC<IconSvgProps> = ({
size,
height,
width,
...props
}) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
height={size || height || "1em"}
viewBox="0 0 12 12"
width={size || width || "1em"}
aria-hidden="true"
focusable="false"
role="presentation"
{...props}
>
<path
d="M3 4.5L6 7.5L9 4.5"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
/>
</svg>
);
};
export const ChevronsLeftRightIcon: React.FC<IconSvgProps> = ({
size,
height,
width,
...props
}) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
height={size || height || 24}
viewBox="0 0 24 24"
width={size || width || 24}
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="lucide lucide-chevrons-left-right ml-2 h-4 w-4 rotate-90"
{...props}
>
<path d="m9 7-5 5 5 5M15 7l5 5-5 5" />
</svg>
);
};
@@ -2,13 +2,14 @@
import { Button } from "@nextui-org/react";
import { Column } from "@tanstack/react-table";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { HTMLAttributes } from "react";
import {
ArrowDownIcon,
ArrowUpIcon,
ChevronsLeftRightIcon,
} from "lucide-react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { HTMLAttributes } from "react";
} from "@/components/icons";
interface DataTableColumnHeaderProps<TData, TValue>
extends HTMLAttributes<HTMLDivElement> {
@@ -64,12 +65,12 @@ export const DataTableColumnHeader = <TData, TValue>({
currentSortParam === "" ||
(currentSortParam !== param && currentSortParam !== `-${param}`)
) {
return <ChevronsLeftRightIcon className="ml-2 h-4 w-4 rotate-90" />;
return <ChevronsLeftRightIcon size={14} className="ml-2 rotate-90" />;
}
return currentSortParam === `-${param}` ? (
<ArrowDownIcon className="ml-2 h-4 w-4" />
<ArrowDownIcon size={12} className="ml-2" />
) : (
<ArrowUpIcon className="ml-2 h-4 w-4" />
<ArrowUpIcon size={12} className="ml-2" />
);
};
@@ -79,9 +80,7 @@ export const DataTableColumnHeader = <TData, TValue>({
return (
<Button
variant="light"
size="md"
className="text-slate-500 dark:text-slate-400 h-8"
className="w-full justify-between px-0 text-left align-middle dark:text-slate-400 h-10 bg-transparent whitespace-nowrap text-foreground-500 text-tiny font-semibold outline-none"
onClick={getToggleSortingHandler}
>
<span>{title}</span>
@@ -1,6 +1,15 @@
"use client";
import { Button } from "@nextui-org/react";
// import {
// Button,
// Input,
// Popover,
// PopoverContent,
// PopoverTrigger,
// RadioGroup,
// } from "@nextui-org/react";
// import { Icon, Radio, SearchIcon } from "lucide-react";
import { useRouter, useSearchParams } from "next/navigation";
import { useCallback, useMemo } from "react";
@@ -43,20 +52,84 @@ export function DataTableFilterCustom({ filters }: DataTableFilterCustomProps) {
);
return (
<div className="flex flex-wrap items-center space-x-2">
{filters.flatMap(({ key, values }) =>
values.map((value) => (
<Button
key={`${key}-${value}`}
onClick={() => applyFilter(key, value)}
// eslint-disable-next-line security/detect-object-injection
variant={activeFilters[key] === value ? "faded" : "light"}
size="sm"
>
{value || "All"}
</Button>
)),
)}
</div>
<>
{/* <div className="flex items-center gap-4 overflow-auto px-[6px] py-[4px]">
<div className="flex items-center gap-3">
<div className="flex items-center gap-4">
<Input
className="min-w-[200px]"
endContent={
<SearchIcon className="text-default-400" width={16} />
}
placeholder="Search"
size="sm"
// value={filterValue}
// onValueChange={onSearchChange}
/>
</div>
<div>
<Popover placement="bottom">
<PopoverTrigger>
<Button className="bg-default-100 text-default-800" size="sm">
Filter
</Button>
</PopoverTrigger>
<PopoverContent className="w-80">
<div className="flex w-full flex-col gap-6 px-2 py-4">
<RadioGroup
label="Worker Type"
// value={workerTypeFilter}
// onValueChange={setWorkerTypeFilter}
>
<Radio value="all">All</Radio>
<Radio value="employee">Employee</Radio>
<Radio value="contractor">Contractor</Radio>
</RadioGroup>
<RadioGroup
label="Status"
// value={statusFilter}
// onValueChange={setStatusFilter}
>
<Radio value="all">All</Radio>
<Radio value="active">Active</Radio>
<Radio value="inactive">Inactive</Radio>
<Radio value="paused">Paused</Radio>
<Radio value="vacation">Vacation</Radio>
</RadioGroup>
<RadioGroup
label="Start Date"
// value={startDateFilter}
// onValueChange={setStartDateFilter}
>
<Radio value="all">All</Radio>
<Radio value="last7Days">Last 7 days</Radio>
<Radio value="last30Days">Last 30 days</Radio>
<Radio value="last60Days">Last 60 days</Radio>
</RadioGroup>
</div>
</PopoverContent>
</Popover>
</div>
</div>
</div> */}
<div className="flex flex-wrap items-center space-x-2">
{filters.flatMap(({ key, values }) =>
values.map((value) => (
<Button
key={`${key}-${value}`}
onClick={() => applyFilter(key, value)}
// eslint-disable-next-line security/detect-object-injection
variant={activeFilters[key] === value ? "faded" : "light"}
size="sm"
>
{value || "All"}
</Button>
)),
)}
</div>
</>
);
}
@@ -1,5 +1,6 @@
"use client";
import { Icon } from "@iconify/react";
import { Button, Chip } from "@nextui-org/react";
import {
ColumnDef,
ColumnFiltersState,
@@ -11,7 +12,7 @@ import {
SortingState,
useReactTable,
} from "@tanstack/react-table";
import { useState } from "react";
import { useMemo, useState } from "react";
import {
Table,
@@ -64,11 +65,36 @@ export function DataTableProvider<TData, TValue>({
{ key: "connected", values: ["false", "true"] },
// Add more filter categories as needed
];
const topBar = useMemo(() => {
return (
<div className="mb-[18px] w-full flex items-center justify-between">
<div className="flex w-fit items-center gap-2">
<h1 className="text-2xl font-[700] leading-[32px]">Providers</h1>
<Chip
className="hidden items-center text-default-500 sm:flex"
size="sm"
variant="flat"
>
3
</Chip>
</div>
<Button
color="primary"
endContent={<Icon icon="solar:add-circle-bold" width={20} />}
>
Add Account
</Button>
</div>
);
}, []);
return (
<>
{topBar}
<DataTableFilterCustom filters={filters} />
<div className="rounded-md border w-full">
<div className="p-4 z-0 flex flex-col relative justify-between gap-4 bg-content1 overflow-auto rounded-large shadow-small w-full ">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
+19 -14
View File
@@ -1,12 +1,11 @@
import { cn } from "@nextui-org/react";
import * as React from "react";
import { cn } from "@/lib/utils";
const Table = React.forwardRef<
HTMLTableElement,
React.HTMLAttributes<HTMLTableElement>
>(({ className, ...props }, ref) => (
<div className="relative w-full overflow-auto">
<div className="relative w-full overflow-auto rounded-lg">
<table
ref={ref}
className={cn("w-full caption-bottom text-sm", className)}
@@ -20,7 +19,14 @@ const TableHeader = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
<thead
ref={ref}
className={cn(
"[&>tr]:first:rounded-lg [&>tr]:first:shadow-small",
className,
)}
{...props}
/>
));
TableHeader.displayName = "TableHeader";
@@ -28,11 +34,7 @@ const TableBody = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<tbody
ref={ref}
className={cn("[&_tr:last-child]:border-0", className)}
{...props}
/>
<tbody ref={ref} className={cn("", className)} {...props} />
));
TableBody.displayName = "TableBody";
@@ -43,7 +45,7 @@ const TableFooter = React.forwardRef<
<tfoot
ref={ref}
className={cn(
"border-t bg-slate-100/50 font-medium [&>tr]:last:border-b-0 dark:bg-slate-800/50",
"font-medium [&>tr]:last:border-b-0 dark:bg-slate-800/50",
className,
)}
{...props}
@@ -58,7 +60,7 @@ const TableRow = React.forwardRef<
<tr
ref={ref}
className={cn(
"border-b transition-colors hover:bg-slate-100/50 data-[state=selected]:bg-slate-100 dark:hover:bg-slate-800/50 dark:data-[state=selected]:bg-slate-800",
"transition-colors hover:bg-slate-100/50 data-[state=selected]:bg-slate-100 dark:hover:bg-slate-800/50 dark:data-[state=selected]:bg-slate-800",
className,
)}
{...props}
@@ -73,7 +75,7 @@ const TableHead = React.forwardRef<
<th
ref={ref}
className={cn(
"h-12 px-4 text-left align-middle font-medium text-slate-500 [&:has([role=checkbox])]:pr-0 dark:text-slate-400",
"px-4 text-left align-middle bg-default-100 [&:has([role=checkbox])]:pr-0 dark:text-slate-400 h-10 rtl:text-right whitespace-nowrap text-foreground-500 text-tiny font-semibold first:rounded-l-lg rtl:first:rounded-r-lg rtl:first:rounded-l-[unset] last:rounded-r-lg rtl:last:rounded-l-lg rtl:last:rounded-r-[unset] data-[hover=true]:text-foreground-400 outline-none data-[focus-visible=true]:z-10 data-[focus-visible=true]:outline-2 data-[focus-visible=true]:outline-focus data-[focus-visible=true]:outline-offset-2",
className,
)}
{...props}
@@ -87,7 +89,10 @@ const TableCell = React.forwardRef<
>(({ className, ...props }, ref) => (
<td
ref={ref}
className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
className={cn(
"px-4 py-2.5 align-middle [&:has([role=checkbox])]:pr-0",
className,
)}
{...props}
/>
));
@@ -99,7 +104,7 @@ const TableCaption = React.forwardRef<
>(({ className, ...props }, ref) => (
<caption
ref={ref}
className={cn("mt-4 text-sm text-slate-500 dark:text-slate-400", className)}
className={cn("mt-2 text-sm text-slate-500 dark:text-slate-400", className)}
{...props}
/>
));
+66
View File
@@ -19,6 +19,31 @@ module.exports = {
},
extend: {
colors: {
prowler: {
blue: {
midnight: "#030921",
pale: "#f3fcff",
},
grey: {
medium: "#353a4d",
light: "#868994",
},
theme: {
green: "#6af400",
purple: "#5001d0",
coral: "#ff5356",
orange: "#f69000",
yellow: "#ffdf16",
},
dark: {
title: "#E2E8F0",
text: "#94a3b8" /* primary default for dark mode */,
},
light: {
title: "#1e293bff",
text: "#64748b" /* primary default for light mode */,
},
},
system: {
success: {
DEFAULT: "#09BF3D",
@@ -56,6 +81,47 @@ module.exports = {
sans: ["var(--font-sans)"],
mono: ["var(--font-geist-mono)"],
},
boxShadow: {
"box-light":
"-16px -16px 40px rgba(255, 255, 255, 0.8), 16px 4px 64px rgba(18, 61, 101, 0.3), inset -8px -6px 80px rgba(255, 255, 255, 0.18)",
"button-curved-default":
"-4px -2px 16px rgba(255, 255, 255, 0.7), 4px 2px 16px rgba(136, 165, 191, 0.38)",
"button-curved-pressed":
"inset -4px -4px 16px rgba(255, 255, 255, 0.8), inset 4px 4px 12px rgba(136, 165, 191, 0.4)",
"button-flat-nopressed":
"-4px -2px 16px #FFFFFF, 4px 2px 16px rgba(136, 165, 191, 0.48)",
"button-flat-pressed":
"inset -3px -3px 7px #FFFFFF, inset 3px 3px 7px rgba(136, 165, 191, 0.48)",
"box-down-light":
"inset -3px -3px 7px #FFFFFF, inset 2px 2px 5px rgba(136, 165, 191, 0.38)",
"box-up":
"-4px -2px 16px #FFFFFF, 4px 2px 16px rgba(136, 165, 191, 0.54)",
"box-dark":
"-4px -2px 16px rgba(195, 200, 205, 0.09), 4px 4px 18px rgba(0, 0, 0, 0.5)",
"box-dark-out": "inset 2px 2px 2px rgba(26, 32, 38, 0.4)",
"buttons-box-dark":
"-5px -6px 16px rgba(195, 200, 205, 0.04), 22px 22px 60px rgba(0, 0, 0, 0.5)",
"button-curved-default-dark":
"-4px -4px 16px rgba(195, 200, 205, 0.06), 4px 4px 18px rgba(0, 0, 0, 0.6)",
"button-curved-pressed-dark":
"-4px -2px 16px rgba(195, 200, 205, 0.07), 4px 4px 18px rgba(0, 0, 0, 0.44)",
"sky-light":
"-16px 20px 40px rgba(215, 215, 215, 0.3), -2px 2px 24px rgba(22, 28, 47, 0.3), -16px 28px 120px rgba(0, 0, 0, 0.1)",
"midnight-dark":
"-16px 20px 40px rgba(3, 9, 33, 0.3), -2px 2px 24px rgba(3, 9, 33, 0.6), -16px 28px 120px rgba(3, 9, 33, 0.1)",
switcher:
"0px -6px 24px #FFFFFF, 0px 7px 16px rgba(104, 132, 157, 0.5)",
up: "0.3rem 0.3rem 0.6rem #c8d0e7, -0.2rem -0.2rem 0.5rem #fff",
down: "inset 0.2rem 0.2rem 0.5rem #c8d0e7, inset -0.2rem -0.2rem 0.5rem #fff",
},
animation: {
"fade-in": "fade-in 200ms ease-out 0s 1 normal forwards running",
"fade-out": "fade-out 200ms ease-in 0s 1 normal forwards running",
expand: "expand 400ms linear 0s 1 normal forwards running",
"slide-in": "slide-in 400ms linear 0s 1 normal forwards running",
"slide-out": "slide-out 400ms linear 0s 1 normal forwards running",
collapse: "collapse 400ms linear 0s 1 normal forwards running",
},
keyframes: {
"accordion-down": {
from: { height: "0" },