Modals and API calls working for admin tab
This commit is contained in:
41
src/components/account/AccountStatusSelector.tsx
Normal file
41
src/components/account/AccountStatusSelector.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
)}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
59
src/components/modal/RaidBuilderModal.tsx
Normal file
59
src/components/modal/RaidBuilderModal.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -6,10 +6,6 @@ const publicLinks = [
|
||||
{
|
||||
name: "Home",
|
||||
path: "/"
|
||||
},
|
||||
{
|
||||
name: "Test",
|
||||
path: "/test"
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
39
src/components/table/Table.tsx
Normal file
39
src/components/table/Table.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
46
src/components/table/TableBody.tsx
Normal file
46
src/components/table/TableBody.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
30
src/components/table/TableHead.tsx
Normal file
30
src/components/table/TableHead.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user