Authorization working
This commit is contained in:
18
src/components/button/PrimaryButton.tsx
Normal file
18
src/components/button/PrimaryButton.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
63
src/components/input/PasswordInput.tsx
Normal file
63
src/components/input/PasswordInput.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
64
src/components/input/TextInput.tsx
Normal file
64
src/components/input/TextInput.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
32
src/components/nav/DarkModeToggle.tsx
Normal file
32
src/components/nav/DarkModeToggle.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
56
src/components/nav/NavBar.tsx
Normal file
56
src/components/nav/NavBar.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
48
src/components/nav/ProtectedNavLinks.tsx
Normal file
48
src/components/nav/ProtectedNavLinks.tsx
Normal 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>
|
||||
))
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
39
src/components/nav/PublicNavLinks.tsx
Normal file
39
src/components/nav/PublicNavLinks.tsx
Normal 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>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user