1
0
Fork 0
mirror of https://github.com/sussy-code/smov.git synced 2024-12-23 15:07:43 +01:00
smov/src/components/LinksDropdown.tsx

158 lines
4.6 KiB
TypeScript

import classNames from "classnames";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useHistory } from "react-router-dom";
import { base64ToBuffer, decryptData } from "@/backend/accounts/crypto";
import { UserAvatar } from "@/components/Avatar";
import { Icon, Icons } from "@/components/Icon";
import { Transition } from "@/components/Transition";
import { useAuth } from "@/hooks/auth/useAuth";
import { conf } from "@/setup/config";
import { useAuthStore } from "@/stores/auth";
function Divider() {
return <hr className="border-0 w-full h-px bg-dropdown-border" />;
}
function GoToLink(props: {
children: React.ReactNode;
href?: string;
className?: string;
onClick?: () => void;
}) {
const history = useHistory();
const goTo = (href: string) => {
if (href.startsWith("http")) window.open(href, "_blank");
else history.push(href);
};
return (
<a
href={props.href}
onClick={(evt) => {
evt.preventDefault();
if (props.href) goTo(props.href);
else props.onClick?.();
}}
className={props.className}
>
{props.children}
</a>
);
}
function DropdownLink(props: {
children: React.ReactNode;
href?: string;
icon?: Icons;
highlight?: boolean;
className?: string;
onClick?: () => void;
}) {
return (
<GoToLink
onClick={props.onClick}
href={props.href}
className={classNames(
"cursor-pointer flex gap-3 items-center m-4 font-medium transition-colors duration-100",
props.highlight
? "text-dropdown-highlight hover:text-dropdown-highlightHover"
: "text-dropdown-text hover:text-white",
props.className
)}
>
{props.icon ? <Icon icon={props.icon} className="text-xl" /> : null}
{props.children}
</GoToLink>
);
}
function CircleDropdownLink(props: { icon: Icons; href: string }) {
return (
<GoToLink
href={props.href}
className="w-11 h-11 rounded-full bg-dropdown-contentBackground text-dropdown-text hover:text-white transition-colors duration-100 flex justify-center items-center"
>
<Icon className="text-2xl" icon={props.icon} />
</GoToLink>
);
}
export function LinksDropdown(props: { children: React.ReactNode }) {
const [open, setOpen] = useState(false);
const deviceName = useAuthStore((s) => s.account?.deviceName);
const seed = useAuthStore((s) => s.account?.seed);
const bufferSeed = useMemo(
() => (seed ? base64ToBuffer(seed) : null),
[seed]
);
const { logout } = useAuth();
useEffect(() => {
function onWindowClick(evt: MouseEvent) {
if ((evt.target as HTMLElement).closest(".is-dropdown")) return;
setOpen(false);
}
window.addEventListener("click", onWindowClick);
return () => window.removeEventListener("click", onWindowClick);
}, []);
const toggleOpen = useCallback(() => {
setOpen((s) => !s);
}, []);
return (
<div className="relative is-dropdown">
<div className="cursor-pointer" onClick={toggleOpen}>
{props.children}
</div>
<Transition animation="slide-down" show={open}>
<div className="rounded-lg absolute w-64 bg-dropdown-altBackground top-full mt-3 right-0">
{deviceName && bufferSeed ? (
<DropdownLink className="text-white" href="/settings">
<UserAvatar />
{decryptData(deviceName, bufferSeed)}
</DropdownLink>
) : (
<DropdownLink href="/login" icon={Icons.RISING_STAR} highlight>
Sync to cloud
</DropdownLink>
)}
<Divider />
<DropdownLink href="/settings" icon={Icons.SETTINGS}>
Settings
</DropdownLink>
<DropdownLink href="/faq" icon={Icons.EPISODES}>
About us
</DropdownLink>
<DropdownLink href="/faq" icon={Icons.FILM}>
HELP MEEE
</DropdownLink>
{deviceName ? (
<DropdownLink
className="!text-type-danger opacity-75 hover:opacity-100"
icon={Icons.LOGOUT}
onClick={logout}
>
Log out
</DropdownLink>
) : null}
<Divider />
<div className="my-4 flex justify-center items-center gap-4">
<CircleDropdownLink
href={conf().DISCORD_LINK}
icon={Icons.DISCORD}
/>
<CircleDropdownLink href={conf().GITHUB_LINK} icon={Icons.GITHUB} />
<CircleDropdownLink
href={conf().DONATION_LINK}
icon={Icons.COINS}
/>
</div>
</div>
</Transition>
</div>
);
}