[ Update UI Tamplate ]
This commit is contained in:
125
src/components/AlertDailog.tsx
Normal file
125
src/components/AlertDailog.tsx
Normal file
@@ -0,0 +1,125 @@
|
||||
import React from "react";
|
||||
|
||||
import { DialogBody, HStack, Icon, Text } from "@chakra-ui/react";
|
||||
import { Button } from "./ui/button";
|
||||
import {
|
||||
DialogActionTrigger,
|
||||
DialogCloseTrigger,
|
||||
DialogContent,
|
||||
DialogRoot,
|
||||
DialogTrigger,
|
||||
} from "./ui/dialog";
|
||||
|
||||
interface DeleteConfirmationDialogProps {
|
||||
onConfirm?: () => void;
|
||||
alertText?: string;
|
||||
alertCaption?: string;
|
||||
alertIcon?: any;
|
||||
AltertTiggerIcon?: any;
|
||||
button?: any;
|
||||
iconColor?: string;
|
||||
}
|
||||
|
||||
const AlertDailog: React.FC<DeleteConfirmationDialogProps> = ({
|
||||
onConfirm,
|
||||
alertText,
|
||||
alertCaption,
|
||||
alertIcon,
|
||||
AltertTiggerIcon,
|
||||
button,
|
||||
iconColor,
|
||||
}) => {
|
||||
return (
|
||||
<DialogRoot
|
||||
placement={"center"}
|
||||
motionPreset="slide-in-bottom"
|
||||
size={"xs"}
|
||||
role="alertdialog"
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
{button ? (
|
||||
button
|
||||
) : (
|
||||
<Icon
|
||||
cursor={"pointer"}
|
||||
p={0.5}
|
||||
_hover={{ bg: "#00000015" }}
|
||||
rounded={"md"}
|
||||
boxSize={5}
|
||||
color={iconColor && iconColor}
|
||||
>
|
||||
<AltertTiggerIcon />
|
||||
</Icon>
|
||||
)}
|
||||
</DialogTrigger>
|
||||
<DialogContent bgColor="#fff">
|
||||
{/* <DialogHeader display="flex" justifyContent="center"> */}
|
||||
{/* <Image src={alertIcon} h={"39px"} /> */}
|
||||
|
||||
{/* </DialogHeader> */}
|
||||
<DialogBody
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
alignItems="center"
|
||||
color="black"
|
||||
p={8}
|
||||
gap={2}
|
||||
>
|
||||
{alertIcon && alertIcon}
|
||||
<Text
|
||||
mt={3}
|
||||
fontWeight={600}
|
||||
fontSize="sm"
|
||||
color="#000000"
|
||||
textAlign="center"
|
||||
as={"span"}
|
||||
>
|
||||
{alertText}
|
||||
</Text>
|
||||
<Text
|
||||
as={"span"}
|
||||
fontSize="sm"
|
||||
style={{ textAlign: "center", color: "#000000CC", width: "100%" }}
|
||||
>
|
||||
{" "}
|
||||
{alertCaption}
|
||||
</Text>
|
||||
<HStack mt={2} w={"100%"}>
|
||||
<DialogActionTrigger asChild>
|
||||
<Button
|
||||
width="50%"
|
||||
color="black"
|
||||
_hover={{ bgColor: "white" }}
|
||||
variant="outline"
|
||||
borderRadius="sm"
|
||||
border="1px solid #007F33"
|
||||
size={"xs"}
|
||||
>
|
||||
No
|
||||
</Button>
|
||||
</DialogActionTrigger>
|
||||
<Button
|
||||
borderRadius="sm"
|
||||
width="50%"
|
||||
bgColor="#007F33"
|
||||
color="white"
|
||||
// colorPalette="#007F33"
|
||||
onClick={onConfirm}
|
||||
size={"xs"}
|
||||
>
|
||||
Yes{" "}
|
||||
</Button>
|
||||
</HStack>
|
||||
</DialogBody>
|
||||
|
||||
<DialogCloseTrigger
|
||||
_hover={{ bg: "#00000010" }}
|
||||
color={"#000"}
|
||||
colorPalette={"bg"}
|
||||
/>
|
||||
</DialogContent>
|
||||
</DialogRoot>
|
||||
);
|
||||
};
|
||||
|
||||
export default AlertDailog;
|
||||
130
src/components/DataTable.tsx
Normal file
130
src/components/DataTable.tsx
Normal file
@@ -0,0 +1,130 @@
|
||||
import { useState } from "react";
|
||||
import { HStack, Stack, Table } from "@chakra-ui/react";
|
||||
import { PaginationItems, PaginationNextTrigger, PaginationPrevTrigger, PaginationRoot } from "./ui/pagination";
|
||||
// import {
|
||||
// PaginationItems,
|
||||
// PaginationNextTrigger,
|
||||
// PaginationPrevTrigger,
|
||||
// PaginationRoot,
|
||||
// } from "./ui/pagination";
|
||||
|
||||
interface TableProps {
|
||||
tableHeadRow: string[];
|
||||
data: Record<string, any>[];
|
||||
sortableColumns?: string[]; // Specify which columns are sortable
|
||||
}
|
||||
|
||||
const DataTable: React.FC<TableProps> = ({
|
||||
tableHeadRow,
|
||||
data,
|
||||
sortableColumns = [],
|
||||
}) => {
|
||||
const [sortedData, setSortedData] = useState(data);
|
||||
const [sortConfig, setSortConfig] = useState<{
|
||||
key: string;
|
||||
direction: "asc" | "desc";
|
||||
} | null>(null);
|
||||
|
||||
const handleSort = (column: string) => {
|
||||
if (!sortableColumns.includes(column)) return;
|
||||
|
||||
let direction: "asc" | "desc" = "asc";
|
||||
if (
|
||||
sortConfig &&
|
||||
sortConfig.key === column &&
|
||||
sortConfig.direction === "asc"
|
||||
) {
|
||||
direction = "desc";
|
||||
}
|
||||
|
||||
const sortedArray = [...sortedData].sort((a, b) => {
|
||||
if (a[column] < b[column]) return direction === "asc" ? -1 : 1;
|
||||
if (a[column] > b[column]) return direction === "asc" ? 1 : -1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
setSortedData(sortedArray);
|
||||
setSortConfig({ key: column, direction });
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack mt={0} color={"#000000CC"}>
|
||||
<Table.ScrollArea mb={3}>
|
||||
<Table.Root size="sm" variant={"line"} stickyHeader>
|
||||
<Table.Header>
|
||||
<Table.Row bg={"#02A0A0"}>
|
||||
{tableHeadRow.map((item, index) => (
|
||||
<Table.ColumnHeader
|
||||
color="white"
|
||||
fontSize={"xs"}
|
||||
fontWeight={600}
|
||||
px={4}
|
||||
p={3}
|
||||
textAlign={
|
||||
index === tableHeadRow.length - 1 ? "center" : "left"
|
||||
}
|
||||
key={index}
|
||||
border={"none"}
|
||||
onClick={() => handleSort(item)}
|
||||
cursor={
|
||||
sortableColumns.includes(item) ? "pointer" : "default"
|
||||
}
|
||||
_hover={
|
||||
sortableColumns.includes(item)
|
||||
? { textDecoration: "underline" }
|
||||
: {}
|
||||
}
|
||||
>
|
||||
{item}
|
||||
{sortableColumns.includes(item) &&
|
||||
sortConfig?.key === item && (
|
||||
<span style={{ marginLeft: "4px" }}>
|
||||
{sortConfig.direction === "asc" ? "\u25B2" : "\u25BC"}
|
||||
</span>
|
||||
)}
|
||||
</Table.ColumnHeader>
|
||||
))}
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{sortedData.map((item: any, index) => (
|
||||
<Table.Row
|
||||
key={index}
|
||||
bg={index % 2 === 0 ? "#fff" : "#007F3310"}
|
||||
>
|
||||
{tableHeadRow.map((heading, colIndex) => (
|
||||
<Table.Cell
|
||||
// className="oxygen"
|
||||
px={4}
|
||||
p={2}
|
||||
key={`${index}-${colIndex}`}
|
||||
fontSize={"xs"}
|
||||
fontWeight={500}
|
||||
border={"none"}
|
||||
>
|
||||
{item[heading]}
|
||||
</Table.Cell>
|
||||
))}
|
||||
</Table.Row>
|
||||
))}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
</Table.ScrollArea>
|
||||
<PaginationRoot
|
||||
size={"xs"}
|
||||
count={20}
|
||||
pageSize={2}
|
||||
defaultPage={1}
|
||||
mb={4}
|
||||
>
|
||||
<HStack justifyContent="flex-end">
|
||||
<PaginationPrevTrigger />
|
||||
<PaginationItems />
|
||||
<PaginationNextTrigger />
|
||||
</HStack>
|
||||
</PaginationRoot>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default DataTable;
|
||||
@@ -13,13 +13,15 @@ interface MainFrameProps {
|
||||
|
||||
const MainFrame: FC<MainFrameProps> = ({ children, title }) => {
|
||||
return (
|
||||
<MotionVStack {...OPACITY_ON_LOAD} w="100%" h="94%" p={4} pb={0} >
|
||||
<MotionVStack {...OPACITY_ON_LOAD} w="100%" h="90%" p={0} pb={0}>
|
||||
<Box
|
||||
w="100%"
|
||||
h="97%"
|
||||
h="100%"
|
||||
bg="#ffffff"
|
||||
rounded="md"
|
||||
overflow={'scroll'}
|
||||
// rounded="md"
|
||||
boxShadow={'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px'}
|
||||
pt={3}
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
|
||||
12
src/components/ui/link-button.tsx
Normal file
12
src/components/ui/link-button.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
"use client"
|
||||
|
||||
import type { HTMLChakraProps, RecipeProps } from "@chakra-ui/react"
|
||||
import { createRecipeContext } from "@chakra-ui/react"
|
||||
|
||||
export interface LinkButtonProps
|
||||
extends HTMLChakraProps<"a", RecipeProps<"button">> {}
|
||||
|
||||
const { withContext } = createRecipeContext({ key: "button" })
|
||||
|
||||
// Replace "a" with your framework's link component
|
||||
export const LinkButton = withContext<HTMLAnchorElement, LinkButtonProps>("a")
|
||||
237
src/components/ui/pagination.tsx
Normal file
237
src/components/ui/pagination.tsx
Normal file
@@ -0,0 +1,237 @@
|
||||
"use client";
|
||||
|
||||
import type { ButtonProps, TextProps } from "@chakra-ui/react";
|
||||
import {
|
||||
Button,
|
||||
Pagination as ChakraPagination,
|
||||
HStack,
|
||||
IconButton,
|
||||
Text,
|
||||
createContext,
|
||||
usePaginationContext,
|
||||
} from "@chakra-ui/react";
|
||||
import * as React from "react";
|
||||
import { HiChevronLeft, HiChevronRight } from "react-icons/hi2";
|
||||
import { LinkButton } from "./link-button";
|
||||
|
||||
interface ButtonVariantMap {
|
||||
current: ButtonProps["variant"];
|
||||
default: ButtonProps["variant"];
|
||||
ellipsis: ButtonProps["variant"];
|
||||
}
|
||||
|
||||
type PaginationVariant = "outline" | "solid" | "subtle";
|
||||
|
||||
interface ButtonVariantContext {
|
||||
size: ButtonProps["size"];
|
||||
variantMap: ButtonVariantMap;
|
||||
getHref?: (page: number) => string;
|
||||
}
|
||||
|
||||
const [RootPropsProvider, useRootProps] = createContext<ButtonVariantContext>({
|
||||
name: "RootPropsProvider",
|
||||
});
|
||||
|
||||
export interface PaginationRootProps
|
||||
extends Omit<ChakraPagination.RootProps, "type"> {
|
||||
size?: ButtonProps["size"];
|
||||
variant?: PaginationVariant;
|
||||
getHref?: (page: number) => string;
|
||||
}
|
||||
|
||||
const variantMap: Record<PaginationVariant, ButtonVariantMap> = {
|
||||
outline: { default: "ghost", ellipsis: "plain", current: "solid" },
|
||||
solid: { default: "outline", ellipsis: "outline", current: "solid" },
|
||||
subtle: { default: "ghost", ellipsis: "plain", current: "subtle" },
|
||||
};
|
||||
|
||||
export const PaginationRoot = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
PaginationRootProps
|
||||
>(function PaginationRoot(props, ref) {
|
||||
const { size = "sm", variant = "outline", getHref, ...rest } = props;
|
||||
return (
|
||||
<RootPropsProvider
|
||||
value={{ size, variantMap: variantMap[variant], getHref }}
|
||||
>
|
||||
<ChakraPagination.Root
|
||||
ref={ref}
|
||||
type={getHref ? "link" : "button"}
|
||||
{...rest}
|
||||
/>
|
||||
</RootPropsProvider>
|
||||
);
|
||||
});
|
||||
|
||||
export const PaginationEllipsis = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
ChakraPagination.EllipsisProps
|
||||
>(function PaginationEllipsis(props, ref) {
|
||||
const { size, variantMap } = useRootProps();
|
||||
return (
|
||||
<ChakraPagination.Ellipsis ref={ref} {...props} asChild>
|
||||
<Button as="span" variant={variantMap.ellipsis} size={size}>
|
||||
...
|
||||
</Button>
|
||||
</ChakraPagination.Ellipsis>
|
||||
);
|
||||
});
|
||||
|
||||
export const PaginationItem = React.forwardRef<
|
||||
HTMLButtonElement,
|
||||
ChakraPagination.ItemProps
|
||||
>(function PaginationItem(props, ref) {
|
||||
const { page } = usePaginationContext();
|
||||
const { size, variantMap, getHref } = useRootProps();
|
||||
|
||||
const current = page === props.value;
|
||||
const variant = current ? variantMap.current : variantMap.default;
|
||||
|
||||
if (getHref) {
|
||||
return (
|
||||
<LinkButton
|
||||
href={getHref(props.value)}
|
||||
variant={variant}
|
||||
size={size}
|
||||
bg={current ? "#02A0A0" : "white"}
|
||||
color={current ? "black" : "black"}
|
||||
_hover={{ bg: "#02A0A0", color: "black" }}
|
||||
>
|
||||
{props.value}
|
||||
</LinkButton>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ChakraPagination.Item ref={ref} {...props} asChild>
|
||||
<Button
|
||||
bg={current ? "#F5F8FB" : "white"}
|
||||
color={current ? "black" : "black"}
|
||||
variant={variant}
|
||||
size={size}
|
||||
_hover={{ bg: "#F5F8FB", color: "black" }}
|
||||
border="none"
|
||||
>
|
||||
{props.value}
|
||||
</Button>
|
||||
</ChakraPagination.Item>
|
||||
);
|
||||
});
|
||||
|
||||
export const PaginationPrevTrigger = React.forwardRef<
|
||||
HTMLButtonElement,
|
||||
ChakraPagination.PrevTriggerProps
|
||||
>(function PaginationPrevTrigger(props, ref) {
|
||||
const { size, variantMap, getHref } = useRootProps();
|
||||
const { previousPage } = usePaginationContext();
|
||||
|
||||
if (getHref) {
|
||||
return (
|
||||
<LinkButton
|
||||
href={previousPage != null ? getHref(previousPage) : undefined}
|
||||
variant={variantMap.default}
|
||||
size={size}
|
||||
_hover={{ bg: "#F5F8FB", color: "black" }}
|
||||
>
|
||||
<HiChevronLeft />
|
||||
</LinkButton>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ChakraPagination.PrevTrigger ref={ref} asChild {...props}>
|
||||
<IconButton variant={variantMap.default} size={size}>
|
||||
<HiChevronLeft />
|
||||
</IconButton>
|
||||
</ChakraPagination.PrevTrigger>
|
||||
);
|
||||
});
|
||||
|
||||
export const PaginationNextTrigger = React.forwardRef<
|
||||
HTMLButtonElement,
|
||||
ChakraPagination.NextTriggerProps
|
||||
>(function PaginationNextTrigger(props, ref) {
|
||||
const { size, variantMap, getHref } = useRootProps();
|
||||
const { nextPage } = usePaginationContext();
|
||||
|
||||
if (getHref) {
|
||||
return (
|
||||
<LinkButton
|
||||
href={nextPage != null ? getHref(nextPage) : undefined}
|
||||
variant={variantMap.default}
|
||||
// size={size}
|
||||
borderRadius="94px"
|
||||
bg="#F5F8FB"
|
||||
color="white"
|
||||
w="136px"
|
||||
fontSize="sm"
|
||||
_hover={{ bg: "#026060" }}
|
||||
>
|
||||
Next
|
||||
</LinkButton>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ChakraPagination.NextTrigger ref={ref} asChild {...props}>
|
||||
<Text
|
||||
w="136px"
|
||||
// borderRadius="94px"
|
||||
// bg="#02A0A0"
|
||||
color="black"
|
||||
// variant={variantMap.default}
|
||||
// size={size}
|
||||
cursor="pointer"
|
||||
// _hover={{ bg: "#026060" }}
|
||||
display="flex"
|
||||
gap="12px"
|
||||
alignItems="center"
|
||||
fontSize="xs"
|
||||
justifyContent="center"
|
||||
>
|
||||
Next
|
||||
<HiChevronRight />
|
||||
</Text>
|
||||
</ChakraPagination.NextTrigger>
|
||||
);
|
||||
});
|
||||
|
||||
export const PaginationItems = (props: React.HTMLAttributes<HTMLElement>) => {
|
||||
return (
|
||||
<ChakraPagination.Context>
|
||||
{({ pages }) =>
|
||||
pages.map((page, index) => (
|
||||
<PaginationItem
|
||||
key={index}
|
||||
type="page"
|
||||
value={page.value}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</ChakraPagination.Context>
|
||||
);
|
||||
};
|
||||
|
||||
interface PageTextProps extends TextProps {
|
||||
format?: "short" | "compact" | "long";
|
||||
}
|
||||
|
||||
export const PaginationPageText = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
PageTextProps
|
||||
>(function PaginationPageText(props, ref) {
|
||||
const { format = "compact", ...rest } = props;
|
||||
const { page, totalPages, pageRange, count } = usePaginationContext();
|
||||
const content = React.useMemo(() => {
|
||||
if (format === "short") return `${page} / ${totalPages}`;
|
||||
if (format === "compact") return `${page} of ${totalPages}`;
|
||||
return `${pageRange.start + 1} - ${Math.min(pageRange.end, count)} of ${count}`;
|
||||
}, [format, page, totalPages, pageRange, count]);
|
||||
|
||||
return (
|
||||
<Text fontWeight="medium" ref={ref} {...rest}>
|
||||
{content}
|
||||
</Text>
|
||||
);
|
||||
});
|
||||
39
src/components/ui/switch.tsx
Normal file
39
src/components/ui/switch.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Switch as ChakraSwitch } from "@chakra-ui/react"
|
||||
import * as React from "react"
|
||||
|
||||
export interface SwitchProps extends ChakraSwitch.RootProps {
|
||||
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
|
||||
rootRef?: React.Ref<HTMLLabelElement>
|
||||
trackLabel?: { on: React.ReactNode; off: React.ReactNode }
|
||||
thumbLabel?: { on: React.ReactNode; off: React.ReactNode }
|
||||
}
|
||||
|
||||
export const Switch = React.forwardRef<HTMLInputElement, SwitchProps>(
|
||||
function Switch(props, ref) {
|
||||
const { inputProps, children, rootRef, trackLabel, thumbLabel, ...rest } =
|
||||
props
|
||||
|
||||
return (
|
||||
<ChakraSwitch.Root ref={rootRef} {...rest}>
|
||||
<ChakraSwitch.HiddenInput ref={ref} {...inputProps} />
|
||||
<ChakraSwitch.Control>
|
||||
<ChakraSwitch.Thumb>
|
||||
{thumbLabel && (
|
||||
<ChakraSwitch.ThumbIndicator fallback={thumbLabel?.off}>
|
||||
{thumbLabel?.on}
|
||||
</ChakraSwitch.ThumbIndicator>
|
||||
)}
|
||||
</ChakraSwitch.Thumb>
|
||||
{trackLabel && (
|
||||
<ChakraSwitch.Indicator fallback={trackLabel.off}>
|
||||
{trackLabel.on}
|
||||
</ChakraSwitch.Indicator>
|
||||
)}
|
||||
</ChakraSwitch.Control>
|
||||
{children != null && (
|
||||
<ChakraSwitch.Label>{children}</ChakraSwitch.Label>
|
||||
)}
|
||||
</ChakraSwitch.Root>
|
||||
)
|
||||
},
|
||||
)
|
||||
Reference in New Issue
Block a user