wip fix
This commit is contained in:
parent
4eebe5bb99
commit
ab80962b47
|
|
@ -0,0 +1,92 @@
|
|||
import { useLocal } from "@/utils/use-local";
|
||||
import { FC, ReactNode, useEffect } from "react";
|
||||
import { Skeleton } from "../ui/skeleton";
|
||||
|
||||
type BreadcrumbProps = {
|
||||
on_load: () => Promise<any[]>;
|
||||
props: any;
|
||||
};
|
||||
|
||||
export const Breadcrumb: FC<BreadcrumbProps> = (_arg) => {
|
||||
const { on_load } = _arg;
|
||||
|
||||
const local = useLocal({
|
||||
list: [] as { label: string; url: string }[],
|
||||
status: "init" as "init" | "loading" | "ready",
|
||||
params: {},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
if (local.status === "init") {
|
||||
local.status = "loading";
|
||||
local.render();
|
||||
|
||||
local.list = await on_load();
|
||||
|
||||
local.status = "ready";
|
||||
local.render();
|
||||
}
|
||||
})();
|
||||
}, [on_load]);
|
||||
|
||||
return (
|
||||
<div className="c-w-full c-flex c-items-center c-px-4 c-flex-wrap c-py-2 c-border-b">
|
||||
{local.status !== "ready" ? (
|
||||
<Skeleton className="c-h-4 c-w-[80%]" />
|
||||
) : (
|
||||
<>
|
||||
{local.list === null ? (
|
||||
<>
|
||||
<h1 className="c-font-semibold c-text-xs md:c-text-base">
|
||||
Dummy
|
||||
</h1>
|
||||
</>
|
||||
) : (
|
||||
(local.list || []).map((item, index): ReactNode => {
|
||||
const lastIndex = local.list.length - 1;
|
||||
|
||||
return (
|
||||
<>
|
||||
{index === lastIndex ? (
|
||||
<h1 className="c-font-semibold c-text-xs md:c-text-base">
|
||||
{item?.label}
|
||||
</h1>
|
||||
) : (
|
||||
<h1
|
||||
className="c-font-normal c-text-xs md:c-text-base hover:c-cursor-pointer"
|
||||
onClick={() => {
|
||||
navigate(item?.url);
|
||||
}}
|
||||
>
|
||||
{item?.label}
|
||||
</h1>
|
||||
)}
|
||||
|
||||
{index !== lastIndex && (
|
||||
<div>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
className="lucide lucide-chevron-right"
|
||||
>
|
||||
<path d="m9 18 6-6-6-6" />
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -6,7 +6,9 @@ import { Skeleton } from "../ui/skeleton";
|
|||
|
||||
export const Card: FC<{
|
||||
title: { left: ReactNode; right: ReactNode };
|
||||
desc: (() => Promise<ReactNode>) | ReactNode;
|
||||
desc:
|
||||
| ((arg: { setOnClick: (fn: any) => void }) => Promise<ReactNode>)
|
||||
| ReactNode;
|
||||
value: (() => Promise<ReactNode>) | ReactNode;
|
||||
}> = ({ title, desc, value }) => {
|
||||
const local = useLocal({
|
||||
|
|
@ -14,6 +16,7 @@ export const Card: FC<{
|
|||
desc: "" as any,
|
||||
status_value: "init" as "init" | "loading" | "ready",
|
||||
status_desc: "init" as "init" | "loading" | "ready",
|
||||
onClick: null as null | (() => void),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -38,7 +41,12 @@ export const Card: FC<{
|
|||
if (!!desc && typeof desc === "function") {
|
||||
local.status_desc = "loading";
|
||||
local.render();
|
||||
const result = desc();
|
||||
const result = desc({
|
||||
setOnClick: (fn) => {
|
||||
local.onClick = fn;
|
||||
local.render();
|
||||
},
|
||||
});
|
||||
if (typeof result === "object" && result instanceof Promise) {
|
||||
result.then((val) => {
|
||||
local.desc = val;
|
||||
|
|
@ -71,7 +79,14 @@ export const Card: FC<{
|
|||
}
|
||||
|
||||
return (
|
||||
<card.Card className="c-flex c-flex-1 c-items-center">
|
||||
<card.Card
|
||||
className="c-flex c-flex-1 c-items-center"
|
||||
onClick={() => {
|
||||
if (local.onClick) {
|
||||
local.onClick();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className={cn("c-p-3 c-text-[14px] c-flex-1")}>
|
||||
{!!title && (title.left || title.right) && (
|
||||
<div className="c-tracking-tight c-text-sm c-font-medium c-flex c-justify-between c-space-x-1 mb-1 c-items-center">
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ import { Skeleton } from "../ui/skeleton";
|
|||
|
||||
export const Detail: FC<{
|
||||
detail: (item: any) => Record<string, [string, string, string]>;
|
||||
on_load: (arg: { params: any }) => Promise<any>;
|
||||
on_load: (arg: {
|
||||
params: any;
|
||||
bind: (fn: (on_load: any) => void) => void;
|
||||
}) => Promise<any>;
|
||||
mode: "standard" | "compact" | "inline";
|
||||
}> = ({ detail, mode, on_load }) => {
|
||||
const local = useLocal({
|
||||
|
|
@ -15,6 +18,7 @@ export const Detail: FC<{
|
|||
pathname: "",
|
||||
mode: mode,
|
||||
on_load,
|
||||
bound: false,
|
||||
});
|
||||
|
||||
if (!isEditor) {
|
||||
|
|
@ -39,7 +43,24 @@ export const Detail: FC<{
|
|||
}
|
||||
local.render();
|
||||
|
||||
const res = on_load({ params: {} });
|
||||
const res = on_load({
|
||||
params: {},
|
||||
bind: (fn) => {
|
||||
if (!local.bound) {
|
||||
local.bound = true;
|
||||
local.render();
|
||||
|
||||
fn(async () => {
|
||||
local.status = "loading";
|
||||
local.render();
|
||||
const item = await on_load({} as any);
|
||||
local.detail = detail(item);
|
||||
local.status = "ready";
|
||||
local.render();
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
if (typeof res === "object" && res instanceof Promise) {
|
||||
res.then((item) => {
|
||||
local.detail = detail(item);
|
||||
|
|
@ -70,7 +91,34 @@ export const Detail: FC<{
|
|||
"c-flex c-relative items-stretch",
|
||||
mode === "inline"
|
||||
? "c-flex-row c-my-2"
|
||||
: "c-flex-col c-flex-1 c-w-full c-h-full "
|
||||
: "c-flex-col c-flex-1 c-w-full c-h-full ",
|
||||
isDesktop &&
|
||||
entries.length > 3 &&
|
||||
mode === "compact" &&
|
||||
css`
|
||||
flex-direction: row !important;
|
||||
flex-wrap: wrap !important;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 10px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&::before {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
left: 49%;
|
||||
bottom: 0px;
|
||||
top: 0px;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
|
||||
> div {
|
||||
border-top: 0px;
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
width: 49% !important;
|
||||
}
|
||||
`
|
||||
)}
|
||||
>
|
||||
{entries.map(([name, data], idx) => {
|
||||
|
|
@ -90,7 +138,7 @@ export const Detail: FC<{
|
|||
|
||||
if (mode === "standard") {
|
||||
return (
|
||||
<div key={idx} className="c-flex c-flex-col c-items-stretch">
|
||||
<div key={idx} className="c-flex c-flex-col c-items-stretch c-pt-3">
|
||||
<div className="c-flex c-font-bold">{label}</div>
|
||||
<div className="c-flex">
|
||||
<Linkable
|
||||
|
|
|
|||
|
|
@ -0,0 +1,166 @@
|
|||
import { useLocal } from "@/utils/use-local";
|
||||
import { FC, ReactNode, useEffect } from "react";
|
||||
import { Skeleton } from "../ui/skeleton";
|
||||
|
||||
export const Header: FC<{
|
||||
text: string;
|
||||
back_url: string | (() => void);
|
||||
props: any;
|
||||
actions: () => Promise<[string, string | (() => void), ReactNode][]>;
|
||||
action_mode: "auto" | "buttons" | "sub-header" | "dropdown";
|
||||
edit_url: string;
|
||||
}> = ({ text, back_url, props, edit_url, actions, action_mode }) => {
|
||||
const local = useLocal({
|
||||
loading: false,
|
||||
actions: [] as [string, string | (() => void), ReactNode][],
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
if (typeof actions === "function") {
|
||||
local.loading = true;
|
||||
local.render();
|
||||
const res_actions = await actions();
|
||||
if (Array.isArray(res_actions)) {
|
||||
local.actions = res_actions;
|
||||
preload(
|
||||
res_actions
|
||||
.filter((e) => typeof e[1] === "string")
|
||||
.map((e) => e[1]) as string[]
|
||||
);
|
||||
}
|
||||
local.loading = false;
|
||||
local.render();
|
||||
}
|
||||
})();
|
||||
}, [actions, action_mode]);
|
||||
|
||||
const back = () => {
|
||||
if (isEditor) return;
|
||||
if (typeof back_url === "function") {
|
||||
const url = back_url();
|
||||
if (typeof url === "string") {
|
||||
if (url === "back") {
|
||||
history.back();
|
||||
return;
|
||||
}
|
||||
navigate(url);
|
||||
}
|
||||
} else {
|
||||
if (back_url === "back") {
|
||||
history.back();
|
||||
return;
|
||||
}
|
||||
navigate(back_url);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={cx(
|
||||
props.className,
|
||||
"whitespace-pre-wrap",
|
||||
css`
|
||||
min-height: 50px !important;
|
||||
`
|
||||
)}
|
||||
>
|
||||
{typeof back_url === "string" && preload([back_url])}
|
||||
{back_url && (
|
||||
<div className="mr-2" onClick={back}>
|
||||
<svg
|
||||
width="25"
|
||||
height="25"
|
||||
viewBox="0 0 15 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M8.84182 3.13514C9.04327 3.32401 9.05348 3.64042 8.86462 3.84188L5.43521 7.49991L8.86462 11.1579C9.05348 11.3594 9.04327 11.6758 8.84182 11.8647C8.64036 12.0535 8.32394 12.0433 8.13508 11.8419L4.38508 7.84188C4.20477 7.64955 4.20477 7.35027 4.38508 7.15794L8.13508 3.15794C8.32394 2.95648 8.64036 2.94628 8.84182 3.13514Z"
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
<div className="w-full flex flex-row justify-between items-center">
|
||||
<div className="c-whitespace-nowrap" onClick={back}>
|
||||
{text}
|
||||
</div>
|
||||
<div className="c-flex">
|
||||
{local.loading && (
|
||||
<Skeleton
|
||||
className={cx(
|
||||
css`
|
||||
height: 10px;
|
||||
min-width: 40px;
|
||||
`
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{!local.loading && (
|
||||
<>
|
||||
{local.actions.map((e) => {
|
||||
const [label, to, icon] = e;
|
||||
return (
|
||||
<div
|
||||
className="c-bg-primary hover:c-bg-primary/90 c-p-1 c-rounded-md c-text-sm c-flex c-text-white c-items-center c-space-x-1 c-px-2 c-ml-2"
|
||||
onClick={() => {
|
||||
if (isEditor) return;
|
||||
if (typeof to === "string") {
|
||||
navigate(to);
|
||||
} else if (typeof to === "function") {
|
||||
to();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={css`
|
||||
svg {
|
||||
max-width: 15px;
|
||||
}
|
||||
`}
|
||||
>
|
||||
{icon}
|
||||
</div>
|
||||
<div>{label}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* {edit_url && edit_url !== "" && params.id !== "_" && (
|
||||
<div
|
||||
className="c-bg-primary hover:c-bg-primary/90 c-p-1 c-rounded-md c-ml-2"
|
||||
onClick={() => {
|
||||
if (isEditor) return;
|
||||
if (typeof edit_url === "string") {
|
||||
navigate(edit_url);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="white"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
className="lucide lucide-pencil-line"
|
||||
>
|
||||
<path d="M12 20h9" />
|
||||
<path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z" />
|
||||
<path d="m15 5 3 3" />
|
||||
</svg>
|
||||
</div>
|
||||
)} */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { FC } from "react";
|
||||
import { FC, useEffect } from "react";
|
||||
import { Tabs, TabsList, TabsTrigger } from "../ui/tabs";
|
||||
import { useLocal } from "@/utils/use-local";
|
||||
|
||||
|
|
@ -64,6 +64,17 @@ export const Tab: FC<{
|
|||
}
|
||||
}
|
||||
|
||||
if (!isEditor) {
|
||||
useEffect(() => {
|
||||
if (local.mode === "hash") {
|
||||
local.activeIndex = location.hash.substring(1);
|
||||
if (!parseInt(local.activeIndex)) {
|
||||
local.activeIndex = "0";
|
||||
}
|
||||
local.render();
|
||||
}
|
||||
}, [location.hash]);
|
||||
}
|
||||
return (
|
||||
<div className="c-flex c-flex-1 c-w-full c-flex-col c-items-stretch">
|
||||
<Tabs
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
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>
|
||||
);
|
||||
};
|
||||
|
|
@ -6,31 +6,25 @@ import {
|
|||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/comps/ui/form";
|
||||
import { useLocal } from "@/utils/use-local";
|
||||
import autosize from "autosize";
|
||||
import { FC, useEffect, useRef } from "react";
|
||||
import { UseFormReturn } from "react-hook-form";
|
||||
import { Input } from "../ui/input";
|
||||
import { useLocal } from "@/utils/use-local";
|
||||
import { Button } from "../ui/button";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/comps/ui/popover";
|
||||
import { format } from "date-fns";
|
||||
import { Calendar } from "@/comps/ui/calendar";
|
||||
import { Calendar as CalendarIcon } from "lucide-react";
|
||||
import { PopUpDropdown } from "./PopUpDropdown";
|
||||
import { ButtonOptions } from "./ButtonOptions";
|
||||
import { Input } from "../ui/input";
|
||||
import { Textarea } from "../ui/textarea";
|
||||
import autosize from "autosize";
|
||||
import { InputMoney } from "./InputMoney";
|
||||
import { ButtonOptions } from "./ButtonOptions";
|
||||
import { Date } from "./Date";
|
||||
import { Datetime } from "./Datetime";
|
||||
import { Slider } from "@radix-ui/react-slider";
|
||||
import { InputMoney } from "./InputMoney";
|
||||
import { PopUpDropdown } from "./PopUpDropdown";
|
||||
import { SliderOptions } from "./Slider/types";
|
||||
import { cn } from "@/utils";
|
||||
|
||||
export const Field: FC<{
|
||||
name: string;
|
||||
label: string;
|
||||
desc?: string;
|
||||
form: { hook: UseFormReturn<any, any, undefined>; render: () => void };
|
||||
form?: { hook: UseFormReturn<any, any, undefined>; render: () => void };
|
||||
type:
|
||||
| "text"
|
||||
| "textarea"
|
||||
|
|
@ -46,7 +40,7 @@ export const Field: FC<{
|
|||
options: () => Promise<{ value: string; label: string }[]>;
|
||||
slider_options: () => Promise<SliderOptions>;
|
||||
}> = ({ name, form, desc, label, type, required, options, slider_options }) => {
|
||||
const value = form.hook.getValues()[name];
|
||||
const value = form?.hook.getValues()[name];
|
||||
const local = useLocal({
|
||||
dropdown: {
|
||||
popup: false,
|
||||
|
|
@ -104,14 +98,14 @@ export const Field: FC<{
|
|||
local.render();
|
||||
}}
|
||||
on_select={(value: any) => {
|
||||
form.hook.setValue(name, value);
|
||||
form?.hook.setValue(name, value);
|
||||
}}
|
||||
title={label}
|
||||
options={options}
|
||||
/>
|
||||
)}
|
||||
<FormField
|
||||
control={form.hook.control}
|
||||
control={form?.hook.control || {} as any}
|
||||
name={name}
|
||||
render={({ field }) => (
|
||||
<FormItem className="c-flex c-flex-1 c-flex-col">
|
||||
|
|
@ -138,7 +132,7 @@ export const Field: FC<{
|
|||
value,
|
||||
local.slider.opt
|
||||
);
|
||||
form.hook.setValue(name, value);
|
||||
form?.hook.setValue(name, value);
|
||||
local.render();
|
||||
}}
|
||||
value={local.slider.value}
|
||||
|
|
@ -180,7 +174,7 @@ export const Field: FC<{
|
|||
{type === "date" && (
|
||||
<Date
|
||||
on_select={(value: any) => {
|
||||
form.hook.setValue(name, value);
|
||||
form?.hook.setValue(name, value);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
|
@ -188,7 +182,7 @@ export const Field: FC<{
|
|||
{type === "datetime" && (
|
||||
<Datetime
|
||||
on_select={(value: any) => {
|
||||
form.hook.setValue(name, value);
|
||||
form?.hook.setValue(name, value);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
|
@ -198,7 +192,7 @@ export const Field: FC<{
|
|||
options={options}
|
||||
value={field.value}
|
||||
on_select={(value: any) => {
|
||||
form.hook.setValue(name, value);
|
||||
form?.hook.setValue(name, value);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
|
@ -207,7 +201,7 @@ export const Field: FC<{
|
|||
<InputMoney
|
||||
value={field.value}
|
||||
on_select={(value: any) => {
|
||||
form.hook.setValue(name, value);
|
||||
form?.hook.setValue(name, value);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { Form as FForm } from "@/comps/ui/form";
|
||||
import { useLocal } from "@/utils/use-local";
|
||||
import { FC } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
|
|
@ -8,13 +9,22 @@ export const Form: FC<{
|
|||
body: any;
|
||||
form: { hook: any; render: () => void };
|
||||
PassProp: any;
|
||||
}> = ({ on_load, body, form, PassProp, on_submit }) => {
|
||||
layout: "auto" | "1-col" | "2-col";
|
||||
}> = ({ on_load, body, form, PassProp, on_submit, layout: _layout }) => {
|
||||
const form_hook = useForm<any>({
|
||||
defaultValues: on_load,
|
||||
});
|
||||
|
||||
const local = useLocal({
|
||||
el: null as any,
|
||||
layout: "unknown" as "unknown" | "2-col" | "1-col",
|
||||
});
|
||||
|
||||
form.hook = form_hook;
|
||||
|
||||
let layout = _layout || "auto";
|
||||
if (layout !== "auto") local.layout = layout;
|
||||
|
||||
return (
|
||||
<FForm {...form_hook}>
|
||||
<form
|
||||
|
|
@ -27,7 +37,44 @@ export const Form: FC<{
|
|||
on_submit({ form: form.hook.getValues(), error: {} });
|
||||
}}
|
||||
>
|
||||
<div className="absolute inset-0">
|
||||
<div
|
||||
ref={(el) => {
|
||||
if (el && layout === "auto" && local.layout === "unknown") {
|
||||
let cur: any = el;
|
||||
let i = 0;
|
||||
while (
|
||||
cur.parentNode &&
|
||||
cur.getBoundingClientRect().width === 0
|
||||
) {
|
||||
cur = cur.parentNode;
|
||||
i++;
|
||||
if (i > 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cur.getBoundingClientRect().width < 500) {
|
||||
local.layout = "1-col";
|
||||
} else {
|
||||
local.layout = "2-col";
|
||||
}
|
||||
local.render();
|
||||
}
|
||||
}}
|
||||
className={cx(
|
||||
local.layout === "unknown" && "c-hidden",
|
||||
local.layout === "2-col" &&
|
||||
css`
|
||||
> div {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
> div {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
`
|
||||
)}
|
||||
>
|
||||
<PassProp
|
||||
submit={() => {
|
||||
on_submit({ form: form.hook.getValues(), error: {} });
|
||||
|
|
|
|||
|
|
@ -1,4 +1,48 @@
|
|||
import { Bell, Calendar, ChevronRight, UsersRound, ChevronDown, Contact2, Drill, HelpCircle, Home, LayoutList, ListChecks, ListTodo, PenBoxIcon, QrCode, UserCog, Workflow, Settings, Newspaper, PanelRightOpen, PanelLeftOpen, LayoutDashboard, Building, Box, Package, Blocks, Megaphone, MousePointerSquare, Siren, Ship, HeartHandshake, StickyNote, Volume2, Wallet, FileDown, Menu, X, LogOut, Rocket, BookOpen } from "lucide-react";
|
||||
import {
|
||||
Bell,
|
||||
Calendar,
|
||||
ChevronRight,
|
||||
UsersRound,
|
||||
ChevronDown,
|
||||
Contact2,
|
||||
Drill,
|
||||
HelpCircle,
|
||||
Home,
|
||||
LayoutList,
|
||||
ListChecks,
|
||||
ListTodo,
|
||||
PenBoxIcon,
|
||||
QrCode,
|
||||
UserCog,
|
||||
Workflow,
|
||||
Settings,
|
||||
Newspaper,
|
||||
PanelRightOpen,
|
||||
PanelLeftOpen,
|
||||
LayoutDashboard,
|
||||
Building,
|
||||
Box,
|
||||
Package,
|
||||
Blocks,
|
||||
Megaphone,
|
||||
MousePointerSquare,
|
||||
Siren,
|
||||
Ship,
|
||||
HeartHandshake,
|
||||
StickyNote,
|
||||
Volume2,
|
||||
Wallet,
|
||||
FileDown,
|
||||
Menu,
|
||||
X,
|
||||
LogOut,
|
||||
Rocket,
|
||||
BookOpen,
|
||||
Pencil,
|
||||
Plus,
|
||||
Delete,
|
||||
Edit,
|
||||
} from "lucide-react";
|
||||
|
||||
export const icon = {
|
||||
home: <Home />,
|
||||
|
|
@ -14,6 +58,8 @@ export const icon = {
|
|||
manage_user: <UserCog />,
|
||||
notification: <Bell />,
|
||||
profile: <Contact2 />,
|
||||
pencil: <Pencil />,
|
||||
plus: <Plus />,
|
||||
bell: <Bell />,
|
||||
bellSmall: <Bell className={`c-w-4`} fill="currentColor" />,
|
||||
bellSmallTransparent: <Bell className={`c-w-4`} />,
|
||||
|
|
@ -53,6 +99,20 @@ export const icon = {
|
|||
releaseSmallTransparent: <Rocket className={`c-w-4`} />,
|
||||
newsSmall: <BookOpen className={`c-w-4`} fill="currentColor" />,
|
||||
newsSmallTransparent: <BookOpen className={`c-w-4`} />,
|
||||
scan: (
|
||||
<svg
|
||||
width="28"
|
||||
height="28"
|
||||
viewBox="0 0 28 28"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M27.5 20V27.5H0.5V20H3.5V24.5H24.5V20H27.5ZM0.5 12.5H27.5V15.5H0.5V12.5ZM27.5 8H24.5V3.5H3.5V8H0.5V0.5H27.5V8Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
delete: <Delete />,
|
||||
update: <Edit />
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export const List: FC<ListProp> = (_arg) => {
|
|||
list: [] as any[],
|
||||
});
|
||||
|
||||
if (isEditor) {
|
||||
if (isEditor || typeof on_load !== 'function') {
|
||||
return <ListDummy {..._arg} />;
|
||||
}
|
||||
|
||||
|
|
@ -35,6 +35,7 @@ export const List: FC<ListProp> = (_arg) => {
|
|||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
if (typeof on_load === "function") {
|
||||
if (local.status === "init") {
|
||||
local.status = "loading";
|
||||
local.render();
|
||||
|
|
@ -44,6 +45,7 @@ export const List: FC<ListProp> = (_arg) => {
|
|||
local.status = "ready";
|
||||
local.render();
|
||||
}
|
||||
}
|
||||
})();
|
||||
}, [on_load]);
|
||||
|
||||
|
|
@ -61,13 +63,16 @@ export const List: FC<ListProp> = (_arg) => {
|
|||
<ListDummy {..._arg} />
|
||||
) : (
|
||||
(local.list || []).map((item, idx) => {
|
||||
const mapped = map_val(item);
|
||||
const val = (...arg: any[]) => {
|
||||
const value = get(map_val(item), `${arg.join("")}`);
|
||||
const value = get(mapped, `${arg.join("")}`);
|
||||
return value;
|
||||
};
|
||||
return (
|
||||
<div key={item} className="c-border-b">
|
||||
<PassProp item={val}>{row}</PassProp>
|
||||
<PassProp item={val} row={mapped}>
|
||||
{row}
|
||||
</PassProp>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
|
|
|
|||
|
|
@ -56,4 +56,21 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|||
);
|
||||
Button.displayName = "Button";
|
||||
|
||||
export { Button, buttonVariants };
|
||||
const FloatButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ variant, className, ...props }, ref) => {
|
||||
return (
|
||||
<button
|
||||
className={cn(
|
||||
buttonVariants({ variant, className }),
|
||||
`btn-${
|
||||
variant || "default"
|
||||
} btn c-transition-all c-duration-300 c-w-10 c-h-10 c-rounded-full c-z-50 c-absolute c-bottom-7 c-right-6 c-shadow-sm`
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Button, buttonVariants, FloatButton };
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ export { formatMoney } from "@/comps/form/InputMoney";
|
|||
export { icon } from "@/comps/icon";
|
||||
export { List } from "@/comps/list/List";
|
||||
export { Slider } from "@/comps/ui/slider";
|
||||
export { longDate, shortDate } from "@/utils/date";
|
||||
export { Button } from "@/comps/ui/button";
|
||||
export * from "@/utils/date";
|
||||
export { Button, FloatButton } from "@/comps/ui/button";
|
||||
export { getPathname } from "@/utils/pathname";
|
||||
export { Breadcrumb } from "./comps/custom/Breadcrumb";
|
||||
export { Header } from "./comps/custom/Header";
|
||||
export { Table } from "./comps/custom/Table";
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { format } from "date-fns";
|
||||
import { format, formatDistanceToNow } from "date-fns";
|
||||
|
||||
export const longDate = (date: string | Date) => {
|
||||
if (date instanceof Date || typeof date === "string") {
|
||||
|
|
@ -13,3 +13,10 @@ export const shortDate = (date: string | Date) => {
|
|||
}
|
||||
return "-";
|
||||
};
|
||||
|
||||
export const timeAgo = (date: string | Date) => {
|
||||
if (date instanceof Date || typeof date === "string") {
|
||||
return formatDistanceToNow(date, { addSuffix: true });
|
||||
}
|
||||
return "-";
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,8 +5,14 @@ export const getPathname = () => {
|
|||
location.pathname.startsWith("/prod") ||
|
||||
location.pathname.startsWith("/deploy")
|
||||
) {
|
||||
const hash = location.hash;
|
||||
|
||||
if (hash !== "") {
|
||||
return "/" + location.pathname.split("/").slice(3).join("/") + hash;
|
||||
} else {
|
||||
return "/" + location.pathname.split("/").slice(3).join("/");
|
||||
}
|
||||
}
|
||||
}
|
||||
return location.pathname;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue