Authorization working

This commit is contained in:
2025-02-24 21:53:20 -05:00
parent 2186889b11
commit 5bb6e0a37f
37 changed files with 5723 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
import clsx from "clsx";
import { ComponentProps } from "react";
export default function PrimaryButton(props: ComponentProps<"button">){
return (
<button
{...props}
className={clsx(
props.className,
"rounded-lg py-2 px-4",
"bg-blue-500 dark:bg-blue-600 text-white"
)}
>
{props.children}
</button>
);
}

View File

@@ -0,0 +1,63 @@
import clsx from "clsx";
import { ComponentProps } from "react";
interface PasswordInputProps extends ComponentProps<"input">{
id: string;
inputClasses?: string;
labelClasses?: string;
accepted?: boolean;
}
export default function PasswordInput(props: PasswordInputProps){
const { id, placeholder, inputClasses, labelClasses, accepted } = props;
return (
<div
className="flex flex-row justify-center w-full rounded-sm bg-inherit"
>
<div
className="relative bg-inherit w-full"
>
<input
{...props}
type="password"
className={clsx(
"peer bg-transparent w-full min-w-72 px-2 py-1 rounded-lg",
"ring-2 focus:ring-sky-600 placeholder-transparent outline-hidden",
inputClasses,
{
"ring-gray-500": accepted === undefined,
"ring-red-600": accepted === false,
"ring-green-600": accepted === true
}
)}
/>
<label
htmlFor={id}
id={`${id}Label`}
className={clsx(
"absolute cursor-text left-0 -top-3 mx-1 px-1",
"bg-white dark:bg-neutral-825 text-sm",
"peer-placeholder-shown:text-base peer-placeholder-shown:text-gray-500 peer-placeholder-shown:top-1 peer-focus:-top-3 peer-focus:text-sky-600 peer-focus:text-sm",
labelClasses,
{
"text-gray-500": accepted === undefined,
"text-red-600": accepted === false,
"text-green-600": accepted === true
}
)}
style={{transitionProperty: "top, font-size, line-height",
transitionTimingFunction: "cubic-bezier(0.4, 0, 0.2, 1)",
transitionDuration: "150ms"
}}
>
{placeholder}
</label>
</div>
</div>
);
}

View File

@@ -0,0 +1,64 @@
import clsx from "clsx";
import { ComponentProps } from "react";
interface TextInputProps extends ComponentProps<"input">{
id: string;
inputClasses?: string;
labelClasses?: string;
accepted?: boolean;
}
export default function TextInput(props: TextInputProps){
const { id, placeholder, name, inputClasses, labelClasses, accepted } = props;
return (
<div
className="flex flex-row justify-center w-full rounded-sm bg-inherit"
>
<div
className="relative bg-inherit w-full"
>
<input
{...props}
type="text"
className={clsx(
"peer bg-transparent w-full min-w-72 px-2 py-1 rounded-lg",
"ring-2 focus:ring-sky-600 placeholder-transparent outline-hidden",
inputClasses,
{
"ring-gray-500": accepted === undefined,
"ring-red-600": accepted === false,
"ring-green-600": accepted === true
}
)}
name={name}
/>
<label
htmlFor={id}
id={`${id}Label`}
className={clsx(
"absolute cursor-text left-0 -top-3 mx-1 px-1",
"bg-white dark:bg-neutral-825 text-sm",
"peer-placeholder-shown:text-base peer-placeholder-shown:text-gray-500 peer-placeholder-shown:top-1 peer-focus:-top-3 peer-focus:text-sky-600 peer-focus:text-sm",
labelClasses,
{
"text-gray-500": accepted === undefined,
"text-red-600": accepted === false,
"text-green-600": accepted === true
}
)}
style={{transitionProperty: "top, font-size, line-height",
transitionTimingFunction: "cubic-bezier(0.4, 0, 0.2, 1)",
transitionDuration: "150ms"
}}
>
{placeholder}
</label>
</div>
</div>
);
}

View File

@@ -0,0 +1,32 @@
import { useTheme } from "@/providers/ThemeProvider";
import { BsLightbulb, BsLightbulbFill } from "react-icons/bs";
export default function DarkModeToggle(){
const { theme, setTheme } = useTheme();
return (
<div>
<input
id="darkModeCheckbox"
type="checkbox"
className="peer hidden"
onChange={() => setTheme(theme === "dark" ? "light" : "dark")}
defaultChecked={theme === "dark"}
/>
<label
htmlFor="darkModeCheckbox"
className="block peer-checked:hidden"
>
<BsLightbulbFill/>
</label>
<label
htmlFor="darkModeCheckbox"
className="hidden peer-checked:block"
>
<BsLightbulb/>
</label>
</div>
);
}

View File

@@ -0,0 +1,56 @@
import clsx from "clsx";
import { BsList } from "react-icons/bs";
import { Link } from "react-router";
import DarkModeToggle from "./DarkModeToggle";
import ProtectedNavLinks from "./ProtectedNavLinks";
import PublicNavLinks from "./PublicNavLinks";
import raidBuilderIcon from "/raidBuilderIcon.svg";
export default function NavBar(){
return (
<nav
className={clsx(
"fixed w-full top-0 left-0 border-b-2 z-40",
"bg-gray-700 border-gray-600 dark:bg-zinc-900 dark:border-neutral-850 text-white"
)}
>
<div
className="max-w-(--breakpoint-xl) flex flex-nowrap flex-row items-center justify-between mx-auto p-4"
>
<Link
to="/"
className="flex items-center space-x-3 rtl:space-x-reverse"
>
<img
src={raidBuilderIcon}
alt="Raid Builder Logo"
width={30}
height={30}
fetchPriority="high"
/>
<span
className="self-center text-2xl font-semibold whitespace-nowrap"
>
Raid Builder
</span>
</Link>
<div
className="peer md:hidden text-3xl"
>
<BsList/>
</div>
<div
className={clsx(
"relative top-0 left-0 flex flex-row items-center rounded-lg space-x-4",
"bg-gray-700 dark:bg-zinc-900"
)}
>
<PublicNavLinks/>
<ProtectedNavLinks/>
<DarkModeToggle/>
</div>
</div>
</nav>
);
}

View File

@@ -0,0 +1,48 @@
import { useAuth } from "@/providers/AuthProvider";
import { NavLink } from "react-router";
const protectedLinks = [
{
name: "Games",
path: "/game"
},
{
name: "Groups",
path: "/raidGroup"
},
{
name: "Admin",
path: "/admin"
},
{
name: "Logout",
path: "/logout"
}
];
export default function ProtectedNavLinks(){
const { jwt } = useAuth();
if(!jwt){
return <></>;
}
return (
<>
{
protectedLinks.map((link) => (
<NavLink
key={link.name}
to={link.path}
>
{link.name}
</NavLink>
))
}
</>
);
}

View File

@@ -0,0 +1,39 @@
import { useAuth } from "@/providers/AuthProvider";
import { NavLink } from "react-router";
const publicLinks = [
{
name: "Home",
path: "/"
}
];
export default function PublicNavLinks(){
const { jwt } = useAuth();
return (
<>
{
publicLinks.map((link) => (
<NavLink
key={link.name}
to={link.path}
>
{link.name}
</NavLink>
))
}
{
!jwt &&
<NavLink
to="/login"
>
Login
</NavLink>
}
</>
);
}