This commit is contained in:
rizrmd 2024-02-05 07:35:56 -07:00
parent 3a1a1388a4
commit 1ac69b0409
7 changed files with 96 additions and 255 deletions

View File

@ -7,6 +7,7 @@ export const Tab: FC<{
label: string; label: string;
navigate: string; navigate: string;
count: string; count: string;
width?: number;
color?: string; color?: string;
onClick?: () => Promise<void> | void; onClick?: () => Promise<void> | void;
}[]; }[];
@ -15,40 +16,59 @@ export const Tab: FC<{
on_load?: () => any; on_load?: () => any;
PassProp: any; PassProp: any;
}> = ({ tabs, active, body, PassProp, on_load }) => { }> = ({ tabs, active, body, PassProp, on_load }) => {
const local = useLocal({ const local = useLocal(
active, {
count: [] as (number | string)[], active,
status: "init" as "init" | "load" | "ready", count: [] as (number | string)[],
}, () => { status: "init" as "init" | "load" | "ready",
if (local.status === "init") { },
if (typeof on_load === "function" && !isEditor) { () => {
local.status = "load"; if (local.status === "init") {
const res = on_load(); if (typeof on_load === "function" && !isEditor) {
if (typeof res === "object" && res instanceof Promise) { local.status = "load";
res.then((value) => { const res = on_load();
local.count = value; if (typeof res === "object" && res instanceof Promise) {
res.then((value) => {
local.count = value;
local.status = "ready";
local.render();
});
} else {
local.count = res;
local.status = "ready"; local.status = "ready";
local.render(); }
});
} else { } else {
local.count = res;
local.status = "ready"; local.status = "ready";
} }
} else {
local.status = "ready";
} }
} }
}); );
const all_tabs = tabs({ count: local.count || [] }); const all_tabs = tabs({ count: local.count || [] });
if (!parseInt(local.active)) {
local.active = "0";
}
return ( return (
<div className="c-p-1 c-flex c-flex-1 c-w-full c-flex-col c-items-stretch"> <div className="c-flex c-flex-1 c-w-full c-flex-col c-items-stretch">
<Tabs value={local.active} className=""> <Tabs
value={local.active}
className={cx(
css`
padding: 0;
button {
border-radius: 0;
}
`
)}
>
<TabsList <TabsList
className={cx( className={cx(
"c-grid c-w-full ", "c-flex c-w-full c-rounded-none c-border-b c-border-gray-300",
css` css`
grid-template-columns: repeat(${all_tabs.length}, minmax(0, 1fr)); padding: 0 !important;
height: auto !important;
` `
)} )}
> >
@ -56,6 +76,10 @@ export const Tab: FC<{
if (e.navigate) { if (e.navigate) {
preload(e.navigate); preload(e.navigate);
} }
let has_count =
local.status !== "ready" ||
typeof e.count === "number" ||
typeof e.count === "string";
return ( return (
<TabsTrigger <TabsTrigger
value={idx + ""} value={idx + ""}
@ -68,17 +92,22 @@ export const Tab: FC<{
}} }}
className={cx( className={cx(
css` css`
padding: 0px !important; padding: 0 !important;
margin: 0px 0px 0px ${idx === 0 ? 0 : 5}px; margin: 0 0 0 ${idx !== 0 ? "5px" : 0};
border-bottom-right-radius: 0px; `,
border-bottom-left-radius: 0px; e.width
` ? css`
max-width: ${e.width}px;
overflow: hidden;
`
: "c-flex-1"
)} )}
> >
<div <div
className={cx( className={cx(
" c-flex-1 c-p-1", "c-p-1 c-h-10 c-flex c-items-center",
e.count ? "c-flex c-justify-between" : "", e.width ? "" : " c-flex-1 ",
e.count ? " c-justify-between" : "",
local.active === idx.toString() local.active === idx.toString()
? css` ? css`
border-bottom: 2px solid border-bottom: 2px solid
@ -87,8 +116,8 @@ export const Tab: FC<{
: "border-b-transparent" : "border-b-transparent"
)} )}
> >
<div className="mr-1">{e.label}</div> <div className={cx("c-mr-1 c-flex-1 c-px-1 c-flex")}>{e.label}</div>
{e.count && ( {has_count && (
<div <div
className={cx( className={cx(
"c-rounded-sm c-px-2 c-text-white", "c-rounded-sm c-px-2 c-text-white",

View File

@ -3,32 +3,34 @@ import { FC, ReactElement, useEffect } from "react";
import { Skeleton } from "../ui/skeleton"; import { Skeleton } from "../ui/skeleton";
import get from "lodash.get"; import get from "lodash.get";
export const List: FC<{ type ListProp = {
className: string;
on_load: (arg: { params: any }) => Promise<any[]>; on_load: (arg: { params: any }) => Promise<any[]>;
map_val: (item: any) => any; map_val: (item: any) => any;
row: ReactElement; row: ReactElement;
props: any; props: any;
PassProp: any; PassProp: any;
}> = ({ className, row, props, on_load, PassProp, map_val }) => { mode: "responsive" | "list" | "table";
};
export const List: FC<ListProp> = (_arg) => {
const { row, on_load, PassProp, map_val } = _arg;
const local = useLocal({ const local = useLocal({
pathname: "",
status: "init" as "init" | "loading" | "ready", status: "init" as "init" | "loading" | "ready",
params: { params: {
skip: 0, // skip: 0,
take: 3, // take: 3,
}, },
list: [] as any[], list: [] as any[],
}); });
if (isEditor) { if (isEditor) {
return ( return <ListDummy {..._arg} />;
<ListDummy }
row={row}
props={props} if (location.pathname !== local.pathname) {
PassProp={PassProp} local.status = "init";
map_val={map_val} local.pathname = location.pathname;
/>
);
} }
useEffect(() => { useEffect(() => {
@ -46,12 +48,7 @@ export const List: FC<{
}, [on_load]); }, [on_load]);
return ( return (
<div <div className="c-flex c-flex-1 c-w-full c-h-full c-relative c-overflow-auto">
className="c-flex c-flex-1 c-w-full c-h-full c-relative c-overflow-auto"
onPointerDown={props.onPointerDown}
onPointerLeave={props.onPointerLeave}
onPointerEnter={props.onPointerEnter}
>
<div className="c-absolute c-inset-0 c-flex c-flex-col c-items-stretch"> <div className="c-absolute c-inset-0 c-flex c-flex-col c-items-stretch">
{local.status !== "ready" ? ( {local.status !== "ready" ? (
<div className="c-p-2 c-flex c-flex-col c-space-y-2 c-flex-1 c-items-start"> <div className="c-p-2 c-flex c-flex-col c-space-y-2 c-flex-1 c-items-start">
@ -61,12 +58,7 @@ export const List: FC<{
) : ( ) : (
<> <>
{local.list === null ? ( {local.list === null ? (
<ListDummy <ListDummy {..._arg} />
row={row}
props={props}
PassProp={PassProp}
map_val={map_val}
/>
) : ( ) : (
local.list.map((item, idx) => { local.list.map((item, idx) => {
const val = (...arg: any[]) => { const val = (...arg: any[]) => {
@ -84,10 +76,10 @@ export const List: FC<{
)} )}
</div> </div>
</div> </div>
); );
}; };
const ListDummy = ({ props, row, PassProp, map_val }: any) => { const ListDummy = ({ props, row, PassProp, map_val, mode }: ListProp) => {
const item = (...arg: string[]) => { const item = (...arg: string[]) => {
if (map_val) { if (map_val) {
const value = get(map_val({}), `${arg.join("")}`); const value = get(map_val({}), `${arg.join("")}`);
@ -107,8 +99,6 @@ const ListDummy = ({ props, row, PassProp, map_val }: any) => {
<div className="c-border-b "> <div className="c-border-b ">
<PassProp item={item}>{row}</PassProp> <PassProp item={item}>{row}</PassProp>
</div> </div>
<div className="c-border-b px-2"> ...</div>
<div className="c-border-b px-2"> ...</div>
</div> </div>
</div> </div>
); );

View File

@ -1,103 +0,0 @@
import { useLocal } from "@/utils/use-local";
import { FC, ReactElement, useEffect } from "react";
import { Skeleton } from "../ui/skeleton";
import get from "lodash.get";
type ListNewProp = {
on_load: (arg: { params: any }) => Promise<any[]>;
map_val: (item: any) => any;
row: ReactElement;
props: any;
PassProp: any;
mode: "responsive" | "list" | "table";
};
export const ListNew: FC<ListNewProp> = (_arg) => {
const { row, on_load, PassProp, map_val } = _arg;
const local = useLocal({
status: "init" as "init" | "loading" | "ready",
params: {
skip: 0,
take: 3,
},
list: [] as any[],
});
if (isEditor) {
return <ListDummy {..._arg} />;
}
useEffect(() => {
(async () => {
if (local.status === "init") {
local.status = "loading";
local.render();
local.list = await on_load({ params: local.params });
local.status = "ready";
local.render();
}
})();
}, [on_load]);
return (
<div className="c-flex c-flex-1 c-w-full c-h-full c-relative c-overflow-auto">
<div className="c-absolute c-inset-0 c-flex c-flex-col c-items-stretch">
{local.status !== "ready" ? (
<div className="c-p-2 c-flex c-flex-col c-space-y-2 c-flex-1 c-items-start">
<Skeleton className="c-h-4 c-w-[80%]" />
<Skeleton className="c-h-4 c-w-[70%]" />
</div>
) : (
<>
{local.list === null ? (
<ListDummy {..._arg} />
) : (
local.list.map((item, idx) => {
const val = (...arg: any[]) => {
const value = get(map_val(item), `${arg.join("")}`);
return value;
};
return (
<div key={item} className="c-border-b">
<PassProp item={val}>{row}</PassProp>
</div>
);
})
)}
</>
)}
</div>
</div>
);
};
const ListDummy = ({ props, row, PassProp, map_val, mode }: ListNewProp) => {
const item = (...arg: string[]) => {
if (map_val) {
const value = get(map_val({}), `${arg.join("")}`);
if (value) return value;
}
return `[${arg.join("")}]`;
};
return (
<div
className="c-flex c-flex-1 c-w-full c-h-full c-relative c-overflow-auto"
onPointerDown={props.onPointerDown}
onPointerLeave={props.onPointerLeave}
onPointerEnter={props.onPointerEnter}
>
{isMobile && "mobile"}
{isDesktop && "desktop"}
<div className="c-absolute c-inset-0 c-flex c-flex-col c-items-stretch">
<div className="c-border-b ">
<PassProp item={item}>{row}</PassProp>
</div>
<div className="c-border-b px-2"> ...</div>
<div className="c-border-b px-2"> ...</div>
</div>
</div>
);
};

View File

@ -1,8 +1,8 @@
import * as React from "react" import * as React from "react";
import { Slot } from "@radix-ui/react-slot" import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority" import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/utils" import { cn } from "@/utils";
const buttonVariants = cva( const buttonVariants = cva(
"c-inline-flex c-items-center c-justify-center c-whitespace-nowrap c-rounded-md c-text-sm c-font-medium c-ring-offset-background c-transition-colors focus-visible:c-outline-none focus-visible:c-ring-2 focus-visible:c-ring-ring focus-visible:c-ring-offset-2 disabled:c-pointer-events-none disabled:c-opacity-50", "c-inline-flex c-items-center c-justify-center c-whitespace-nowrap c-rounded-md c-text-sm c-font-medium c-ring-offset-background c-transition-colors focus-visible:c-outline-none focus-visible:c-ring-2 focus-visible:c-ring-ring focus-visible:c-ring-offset-2 disabled:c-pointer-events-none disabled:c-opacity-50",
@ -31,26 +31,29 @@ const buttonVariants = cva(
size: "default", size: "default",
}, },
} }
) );
export interface ButtonProps export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>, extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> { VariantProps<typeof buttonVariants> {
asChild?: boolean asChild?: boolean;
} }
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => { ({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button" const Comp = asChild ? Slot : "button";
return ( return (
<Comp <Comp
className={cn(buttonVariants({ variant, size, className }))} className={cn(
buttonVariants({ variant, size, className }),
`btn-${variant || "default"} c-transition-all c-duration-300`
)}
ref={ref} ref={ref}
{...props} {...props}
/> />
) );
} }
) );
Button.displayName = "Button" Button.displayName = "Button";
export { Button, buttonVariants } export { Button, buttonVariants };

File diff suppressed because one or more lines are too long

View File

@ -1,76 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 240 5.9% 90%;
--input: 240 5.9% 90%;
--ring: 240 10% 3.9%;
--radius: 0.5rem;
}
.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--card: 240 10% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%;
--accent: 240 3.7% 15.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--ring: 240 4.9% 83.9%;
}
}
@layer base {
* {
@apply c-border-border;
}
body {
@apply c-bg-background c-text-foreground;
}
}

View File

@ -6,7 +6,6 @@ export { Form } from "@/comps/form/Form";
export { formatMoney } from "@/comps/form/InputMoney"; export { formatMoney } from "@/comps/form/InputMoney";
export { icon } from "@/comps/icon"; export { icon } from "@/comps/icon";
export { List } from "@/comps/list/List"; export { List } from "@/comps/list/List";
export { ListNew } from "@/comps/list/ListNew";
export { Slider } from "@/comps/ui/slider"; export { Slider } from "@/comps/ui/slider";
export { longDate, shortDate } from "@/utils/date"; export { longDate, shortDate } from "@/utils/date";
export { Button } from "@/comps/ui/button"; export { Button } from "@/comps/ui/button";