This commit is contained in:
rizrmd 2024-03-07 21:34:40 -07:00
parent ab80962b47
commit a721b6284f
6 changed files with 252 additions and 84 deletions

View File

@ -1,76 +0,0 @@
import { useLocal } from "@/utils/use-local";
import { FC, useEffect } from "react";
import { icon } from "../icon";
type TableProps = {
map_val: Array<{ name: string }>;
};
export const Table: FC<TableProps> = (_args) => {
const { map_val } = _args;
const local = useLocal({
list: [
{
name: "test1",
},
{
name: "test2",
},
] as { name: string }[],
status: "init" as "init" | "loading" | "ready",
});
// useEffect(() => {
// (async () => {
// if (local.status === "init") {
// local.status = "loading";
// local.render();
// local.list = await map_val;
// local.render();
// local.status = "ready";
// local.render();
// }
// })();
// }, [map_val]);
console.log(local.list, "tes");
return (
<div className="c-overflow-x-auto c-w-full">
<table className="c-table-auto c-w-full c-border-collapse c-rounded-lg c-border c-border-gray-300">
<thead>
<tr>
<th className="c-px-4 c-py-2 c-text-center">Nomor</th>
<th className="c-px-4 c-py-2 c-text-center">Header 1</th>
<th className="c-px-4 c-py-2 c-text-center">Action</th>
</tr>
</thead>
<tbody>
{!!local.list &&
local.list.map((item, index) => (
<tr
key={index}
className={index % 2 === 0 ? "c-bg-gray-100" : ""}
>
<td className="c-border c-px-4 c-py-2 c-text-center">
{index + 1}
</td>
<td className="c-border c-px-4 c-py-2">{item.name}</td>
<td className="c-border c-px-4 c-py-2 c-flex c-flex-col c-justify-center c-items-center c-space-y-2">
<button className="c-w-[50px] c-rounded c-flex c-justify-center c-bg-blue-300">
<span className="c-p-2">{icon.update}</span>
</button>
<button className="c-w-[50px] c-rounded c-flex c-justify-center c-bg-red-300">
<span className="c-p-2">{icon.delete}</span>
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
};

99
comps/custom/TableList.tsx Executable file
View File

@ -0,0 +1,99 @@
import { useLocal } from "@/utils/use-local";
import { FC, ReactNode, useEffect } from "react";
import { icon } from "../icon";
import { Skeleton } from "../ui/skeleton";
import {
Table,
TableBody,
TableCaption,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/comps/ui/table";
type TableListProps = {
mapping: () => Promise<Column[]>;
on_load: () => Promise<any[]>;
};
type Column = {
name: string;
title?: string;
jsx?: ReactNode;
type?: "number" | "default";
};
export const TableList: FC<TableListProps> = (_args) => {
const { mapping, on_load } = _args;
const local = useLocal({
columns: [] as Column[],
list: [] as Record<string, any>[],
status: "init" as "init" | "loading" | "ready",
});
useEffect(() => {
(async () => {
if (local.status === "init") {
local.status = "loading";
local.render();
local.columns = await mapping();
local.list = await on_load();
local.render();
local.status = "ready";
local.render();
}
})();
}, [mapping]);
console.log(local.columns, local.list, "s");
return (
<div className="c-overflow-x-auto c-w-full">
{local.status !== "ready" ? (
<Skeleton className="c-h-4 c-w-[80%]" />
) : (
<>
<Table>
{/* /** ini header */}
{!!local.columns && (
<TableHeader className="c-w-full">
<TableRow>
{local.columns.map((item: Column, index: number) => {
return (
<TableHead key={index} className="c-text-center">
{item.name}
</TableHead>
);
})}
</TableRow>
</TableHeader>
)}
<TableBody>
{!!local.list &&
local.list.map((item, idx) => (
<TableRow key={idx} className="c-flex c-flex-col">
{local.columns.map((col, col_idx) => (
<TableCell
key={col_idx}
className="c-flex c-flex-col c-text-center"
>
{!!col.title
? col.title
: !!col.jsx
? col.jsx
: item[col.name]}
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</>
)}
</div>
);
};

View File

@ -35,11 +35,22 @@ export const Field: FC<{
| "datetime" | "datetime"
| "money" | "money"
| "slider" | "slider"
| "master-linkF"; | "master-link";
required: "y" | "n"; required: "y" | "n";
options: () => Promise<{ value: string; label: string }[]>; options: () => Promise<{ value: string; label: string }[]>;
slider_options: () => Promise<SliderOptions>; slider: () => Promise<SliderOptions>;
}> = ({ name, form, desc, label, type, required, options, slider_options }) => { on_change: (arg: { value: any }) => void | Promise<void>;
}> = ({
name,
form,
desc,
label,
type,
required,
options,
slider,
on_change,
}) => {
const value = form?.hook.getValues()[name]; const value = form?.hook.getValues()[name];
const local = useLocal({ const local = useLocal({
dropdown: { dropdown: {
@ -71,12 +82,12 @@ export const Field: FC<{
useEffect(() => { useEffect(() => {
if (type === "slider") { if (type === "slider") {
local.slider.value = parseSliderValue(value, local.slider.opt); local.slider.value = parseSliderValue(value, local.slider.opt);
if (typeof slider_options === "function") { if (typeof slider === "function") {
if (local.slider.status === "init") { if (local.slider.status === "init") {
local.slider.status = "ready"; local.slider.status = "ready";
local.render(); local.render();
(async () => { (async () => {
const res = await slider_options(); const res = await slider();
local.slider.opt = res; local.slider.opt = res;
local.render(); local.render();
@ -105,7 +116,7 @@ export const Field: FC<{
/> />
)} )}
<FormField <FormField
control={form?.hook.control || {} as any} control={form?.hook.control || ({} as any)}
name={name} name={name}
render={({ field }) => ( render={({ field }) => (
<FormItem className="c-flex c-flex-1 c-flex-col"> <FormItem className="c-flex c-flex-1 c-flex-col">
@ -152,7 +163,18 @@ export const Field: FC<{
)} )}
{["text", "password"].includes(type) && ( {["text", "password"].includes(type) && (
<Input {...field} type={type} /> <Input
{...field}
type={type}
onChangeCapture={
typeof on_change === "function"
? (e) => {
console.log(e.currentTarget.value);
on_change({ value: e.currentTarget.value });
}
: undefined
}
/>
)} )}
{type === "textarea" && ( {type === "textarea" && (

View File

@ -42,10 +42,16 @@ import {
Plus, Plus,
Delete, Delete,
Edit, Edit,
BetweenHorizontalEnd,
BetweenHorizontalStart,
Outdent,
Indent,
} from "lucide-react"; } from "lucide-react";
export const icon = { export const icon = {
home: <Home />, home: <Home />,
in: <Indent />,
out: <Outdent />,
dashboard: <LayoutDashboard />, dashboard: <LayoutDashboard />,
dashboardSmall: <LayoutDashboard className={`c-w-4`} fill="currentColor" />, dashboardSmall: <LayoutDashboard className={`c-w-4`} fill="currentColor" />,
dashboardSmallTransparent: <LayoutDashboard className={`c-w-4`} />, dashboardSmallTransparent: <LayoutDashboard className={`c-w-4`} />,

117
comps/ui/table.tsx Executable file
View File

@ -0,0 +1,117 @@
import * as React from "react"
import { cn } from "@/utils"
const Table = React.forwardRef<
HTMLTableElement,
React.HTMLAttributes<HTMLTableElement>
>(({ className, ...props }, ref) => (
<div className="c-relative c-w-full c-overflow-auto">
<table
ref={ref}
className={cn("c-w-full c-caption-bottom c-text-sm", className)}
{...props}
/>
</div>
))
Table.displayName = "Table"
const TableHeader = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<thead ref={ref} className={cn("[&_tr]:c-border-b", className)} {...props} />
))
TableHeader.displayName = "TableHeader"
const TableBody = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<tbody
ref={ref}
className={cn("[&_tr:last-child]:c-border-0", className)}
{...props}
/>
))
TableBody.displayName = "TableBody"
const TableFooter = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<tfoot
ref={ref}
className={cn(
"c-border-t c-bg-muted/50 c-font-medium [&>tr]:last:c-border-b-0",
className
)}
{...props}
/>
))
TableFooter.displayName = "TableFooter"
const TableRow = React.forwardRef<
HTMLTableRowElement,
React.HTMLAttributes<HTMLTableRowElement>
>(({ className, ...props }, ref) => (
<tr
ref={ref}
className={cn(
"c-border-b c-transition-colors hover:c-bg-muted/50 data-[state=selected]:c-bg-muted",
className
)}
{...props}
/>
))
TableRow.displayName = "TableRow"
const TableHead = React.forwardRef<
HTMLTableCellElement,
React.ThHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<th
ref={ref}
className={cn(
"c-h-12 c-px-4 c-text-left c-align-middle c-font-medium c-text-muted-foreground [&:has([role=checkbox])]:c-pr-0",
className
)}
{...props}
/>
))
TableHead.displayName = "TableHead"
const TableCell = React.forwardRef<
HTMLTableCellElement,
React.TdHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<td
ref={ref}
className={cn("c-p-4 c-align-middle [&:has([role=checkbox])]:c-pr-0", className)}
{...props}
/>
))
TableCell.displayName = "TableCell"
const TableCaption = React.forwardRef<
HTMLTableCaptionElement,
React.HTMLAttributes<HTMLTableCaptionElement>
>(({ className, ...props }, ref) => (
<caption
ref={ref}
className={cn("c-mt-4 c-text-sm c-text-muted-foreground", className)}
{...props}
/>
))
TableCaption.displayName = "TableCaption"
export {
Table,
TableHeader,
TableBody,
TableFooter,
TableHead,
TableRow,
TableCell,
TableCaption,
}

View File

@ -12,4 +12,4 @@ export { Button, FloatButton } from "@/comps/ui/button";
export { getPathname } from "@/utils/pathname"; export { getPathname } from "@/utils/pathname";
export { Breadcrumb } from "./comps/custom/Breadcrumb"; export { Breadcrumb } from "./comps/custom/Breadcrumb";
export { Header } from "./comps/custom/Header"; export { Header } from "./comps/custom/Header";
export { Table } from "./comps/custom/Table"; export { TableList } from "./comps/custom/TableList";