Modals and API calls working for admin tab

This commit is contained in:
2025-03-01 23:32:41 -05:00
parent d68e8864a0
commit 843970e229
34 changed files with 1150 additions and 131 deletions

View File

@@ -0,0 +1,41 @@
import { AccountStatus } from "@/interface/Account";
export default function AccountStatusSelector({
value,
onChange
}:{
value: AccountStatus;
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
}){
const modalId = crypto.randomUUID().replace("-", "");
return (
<div
className="flex flex-row flex-wrap justify-start gap-x-4"
>
{
Object.keys(AccountStatus).map((status: string) => (
<label
key={status}
className="whitespace-nowrap"
>
<input
type="radio"
name={`accountStatusSelector${modalId}`}
value={status}
onChange={onChange}
checked={value === status}
/>
<span
className="ml-1"
>
{status}
</span>
</label>
))
}
</div>
);
}

View File

@@ -3,7 +3,7 @@ import clsx from "clsx";
export type ButtonRounding = "none" | "sm" | "md" | "lg" | "full";
export type ButtonShape = "vertical" | "horizontal" | "square";
export type ButtonSizeType = "xsm" | "sm" | "md" | "lg" | "xl";
export type ButtonSizeType = "xs" | "sm" | "md" | "lg" | "xl";
export type ButtonVariant = "solid" | "outline" | "ghost" | "outline-ghost" | "icon";
export interface ButtonProps extends React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>{
@@ -17,7 +17,7 @@ export interface ButtonProps extends React.DetailedHTMLProps<React.ButtonHTMLAtt
export default function Button(props: ButtonProps){
const {
rounding = "lg",
shape = "vertical",
shape = "horizontal",
size = "md"
} = props;
@@ -33,6 +33,7 @@ export default function Button(props: ButtonProps){
{...props}
className={clsx(
props.className,
"transition-colors duration-300",
//Rounding
{
"rounded-none": rounding === "none",
@@ -44,19 +45,19 @@ export default function Button(props: ButtonProps){
//Shape & Size
{
//Square
"p-0": size === "xsm" && shape === "square",
"p-0": size === "xs" && shape === "square",
"p-1": size === "sm" && shape === "square",
"p-2": size === "md" && shape === "square",
"p-3": size === "lg" && shape === "square",
"p-4": size === "xl" && shape === "square",
//Horizontal
"px-1 py-0": size === "xsm" && shape === "horizontal",
"px-1 py-0": size === "xs" && shape === "horizontal",
"px-2 py-1": size === "sm" && shape === "horizontal",
"px-4 py-2": size === "md" && shape === "horizontal",
"px-6 py-3": size === "lg" && shape === "horizontal",
"px-8 py-4": size === "xl" && shape === "horizontal",
//Vertical
"px-0 py-1": size === "xsm" && shape === "vertical",
"px-0 py-1": size === "xs" && shape === "vertical",
"px-1 py-2": size === "sm" && shape === "vertical",
"px-2 py-4": size === "md" && shape === "vertical",
"px-3 py-6": size === "lg" && shape === "vertical",

View File

@@ -34,7 +34,7 @@ export default function Modal(props: ModalProps){
<div
{...divProps}
className={clsx(
"fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-50",
"fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 max-w-(--breakpoint-sm) z-50",
"flex flex-col rounded-lg max-h-full shadow-lg shadow-[#00000066]",
className
)}

View File

@@ -29,8 +29,10 @@ export default function ModalBackground(props: ModalBackgroundProps){
{
"bg-[#00000044]": backgroundType === "darken",
"bg-[#FFFFFF44]": backgroundType === "lighten",
"backdrop-blur-sm bg-radial-[circle] from-transparent from-25% to-[#00000066]": backgroundType === "darken-blur",
"backdrop-blur-sm bg-radial-[circle] from-transparent from-25% to-[#FFFFFF66]": backgroundType === "lighten-blur",
"backdrop-blur-sm bg-black/15": backgroundType === "darken-blur",
"backdrop-blur-sm bg-white/5": backgroundType === "lighten-blur",
"backdrop-blur-sm bg-radial-[circle] from-transparent from-25% to-[#00000066]": backgroundType === "darken-blur-radial",
"backdrop-blur-sm bg-radial-[circle] from-transparent from-25% to-[#FFFFFF66]": backgroundType === "lighten-blur-radial",
"bg-[#00000000]": backgroundType === "transparent",
"backdrop-blur-sm": backgroundType === "blur"
}

View File

@@ -1,6 +1,7 @@
import { ModalHeaderProps } from "@/interface/ModalInterfaces";
import clsx from "clsx";
import { BsXLg } from "react-icons/bs";
import Button from "../button/Button";
export default function ModalHeader(props: ModalHeaderProps){
@@ -30,14 +31,20 @@ export default function ModalHeader(props: ModalHeaderProps){
</div>
{
close &&
<div
className="absolute top-1 right-1 cursor-pointer"
<Button
variant="ghost"
shape="square"
size="sm"
className={clsx(
"absolute top-1 right-1 cursor-pointer",
"hover:bg-red-500 hover:text-white active:bg-red-600 active:text-white"
)}
onClick={close}
>
<BsXLg
size={20}
/>
</div>
</Button>
}
</div>
);

View File

@@ -0,0 +1,59 @@
import { useTheme } from "@/providers/ThemeProvider";
import Modal from "./Modal";
import ModalBody from "./ModalBody";
import ModalFooter from "./ModalFooter";
import ModalHeader from "./ModalHeader";
export default function RaidBuilderModal({
display,
modalHeader,
modalBody,
modalFooter,
close
}:{
display: boolean;
modalHeader: React.ReactNode;
modalBody: React.ReactNode;
modalFooter: React.ReactNode;
close: () => void;
}){
const { theme } = useTheme();
return (
<Modal
display={display}
close={close}
className="bg-(--bg-color) text-(--text-color)"
backgroundType={theme === "dark" ? "lighten-blur" : "darken-blur"}
>
<ModalHeader
className="bg-[#00000022] dark:bg-[#FFFFFF16]"
close={close}
>
<h3
className="text-2xl"
>
{modalHeader}
</h3>
</ModalHeader>
<ModalBody>
<div
className="my-8"
>
{modalBody}
</div>
</ModalBody>
<ModalFooter
className="bg-[#00000022] dark:bg-[#FFFFFF16]"
>
<div
className="flex flex-row items-center justify-center gap-4"
>
{modalFooter}
</div>
</ModalFooter>
</Modal>
);
}

View File

@@ -6,10 +6,6 @@ const publicLinks = [
{
name: "Home",
path: "/"
},
{
name: "Test",
path: "/test"
}
];

View File

@@ -12,19 +12,22 @@ export interface Tab {
}
export interface TabGroupProps extends HTMLProps<HTMLDivElement>{
tabs: Tab[];
tabs?: Tab[];
}
export default function TabGroup(props: TabGroupProps){
const { tabs, className } = props;
if(!tabs){ throw new Error("Tabs must be present"); }
const [ activeTab, setActiveTab ] = useState<number>(tabs.map((tab, index) => tab.active ? index : undefined)[0] ?? 0);
//TODO: Possible to maintain state of past tabs if we "cache" them in a useState<JSX.Element>() on their first render
const divProps = {...props};
delete divProps.tabs;
return (
<div
{...props}
{...divProps}
className={clsx(
className,
"flex flex-col w-full"
@@ -50,7 +53,7 @@ export default function TabGroup(props: TabGroupProps){
</div>
</div>
<div
className="flex flex-col items-center justify-center"
className="flex flex-col items-center justify-center mt-8"
>
{
tabs.map((tab, index) => (
@@ -108,8 +111,8 @@ function TabContent({
return (
<div
className={clsx(
tab.headerClasses,
""
"w-full",
tab.contentClasses
)}
>
{tab.tabContent}

View File

@@ -0,0 +1,39 @@
import clsx from "clsx";
import { HTMLProps } from "react";
import TableBody from "./TableBody";
import TableHead from "./TableHead";
export interface TableProps extends HTMLProps<HTMLTableElement>{
tableHeadElements?: React.ReactNode[];
tableBodyElements?: React.ReactNode[][];
}
export default function Table(props: TableProps){
const {
tableHeadElements,
tableBodyElements
} = props;
const tableProps = {...props};
delete tableProps.tableHeadElements;
delete tableProps.tableBodyElements;
return (
<table
{...tableProps}
className={clsx(
"w-full",
props.className
)}
>
<TableHead
headElements={tableHeadElements ?? []}
/>
<TableBody
bodyElements={tableBodyElements ?? []}
/>
</table>
);
}

View File

@@ -0,0 +1,46 @@
import clsx from "clsx";
export default function TableBody({
bodyElements
}:{
bodyElements: React.ReactNode[][];
}){
return (
<tbody>
{
bodyElements.map((row, rowIndex) => (
<tr
key={rowIndex}
>
{
row.map((element, elementIndex) => (
<td
key={elementIndex}
className={clsx(
{
"w-0": elementIndex === 0 || elementIndex === row.length - 1
}
)}
>
<div
className={clsx(
"bg-neutral-200 dark:bg-neutral-700",
{
"py-4 my-2": elementIndex < row.length - 1,
"rounded-l pl-2": elementIndex === 0,
"rounded-r pr-2": elementIndex === row.length - 1
}
)}
>
{element}
</div>
</td>
))
}
</tr>
))
}
</tbody>
);
}

View File

@@ -0,0 +1,30 @@
import clsx from "clsx";
export default function TableHead({
headElements
}:{
headElements: React.ReactNode[];
}){
return (
<thead>
<tr>
{
headElements.map((element, index) => (
<th
key={index}
className={clsx(
{
"pl-2": index === 0,
"pr-2": index === headElements.length - 1
}
)}
>
{element}
</th>
))
}
</tr>
</thead>
);
}