Illuminix_nextjs/src/ui/(console)/side-bar.tsx

204 lines
9.1 KiB
TypeScript
Raw Normal View History

2024-09-18 16:35:40 +08:00
"use client";
import Link from "next/link";
import { usePathname, useRouter } from "next/navigation";
import React, { useState } from "react";
import Image from "next/image";
2024-09-18 21:44:09 +08:00
2024-09-18 16:35:40 +08:00
import { FaPlus, FaBars } from "react-icons/fa6";
import { MdOutlineHome, MdLogout } from "react-icons/md";
import { PiSquaresFourBold } from "react-icons/pi";
import { BsLightningChargeFill } from "react-icons/bs";
2024-09-18 21:44:09 +08:00
import { useTranslations, useLocale } from "next-intl";
2024-09-18 16:35:40 +08:00
import classNames from "classnames";
import useUserStore from "@/store/userStore";
import useFetch from "@/hooks/useFetch";
import { useToast } from "@/contexts/ToastContext";
import useLoadingStore from "@/store/loadingStore";
type MenuItem = {
name: string;
href: string;
icon?: React.ComponentType;
};
export default function SideBar() {
const pathname = usePathname();
const router = useRouter();
const user = useUserStore((state) => state.user);
const t = useTranslations("sideBar");
2024-09-18 21:44:09 +08:00
const locale = useLocale();
2024-09-18 16:35:40 +08:00
const { addToast, addToastSuccess, addToastError } = useToast();
const [sidebarOpen, setSidebarOpen] = useState(false); // 控制侧边栏的开关状态
const hideLoading = useLoadingStore((state) => state.hideLoading);
const toggleSidebar = () => {
setSidebarOpen(!sidebarOpen);
};
const menu: { title: string; items: MenuItem[] }[] = [
{
title: t("creation"),
items: [
{
name: t("videos"),
href: "/projects",
icon: PiSquaresFourBold,
},
],
},
];
const {
fetchData: logoutFetch,
loading: logoutLoading,
data: logoutResult,
} = useFetch({
2024-09-18 21:44:09 +08:00
url: "/api/logout/", // 假设你的退出接口路径为 /api/logout/
2024-09-18 16:35:40 +08:00
method: "POST",
});
2024-09-18 21:44:09 +08:00
const logout = () => {
logoutFetch() // 不需要传递参数
2024-09-18 16:35:40 +08:00
.then((res) => {
addToastSuccess(t("logoutSuccess"));
2024-09-18 21:44:09 +08:00
router.push("/login"); // 退出成功后跳转到登录页面
2024-09-18 16:35:40 +08:00
})
.finally(() => {
hideLoading();
});
};
return (
<div>
{/* 切换侧边栏按钮(仅在小屏幕显示) */}
<button
className="lg:hidden fixed top-4 left-4 z-30 bg-black text-white p-2 rounded-md"
onClick={toggleSidebar}
>
<FaBars size={20} />
</button>
{/* 侧边栏容器 */}
<div
className={classNames(
"fixed top-0 left-0 h-full bg-white border-r border-base-200 overflow-auto flex flex-col p-6 items-center z-20 transition-transform transform",
{
"translate-x-0": sidebarOpen, // 打开时显示
"-translate-x-full": !sidebarOpen, // 关闭时隐藏
"lg:translate-x-0 lg:relative lg:w-60": true, // 在大屏幕上始终显示
}
)}
style={{ width: "240px" }}
>
{/* 侧边栏内容 */}
2024-09-18 21:44:09 +08:00
<div className="w-full flex mt-2 mb-6 min-h-[34px]">
<Link className="w-full flex justify-center" href="/">
2024-09-18 16:35:40 +08:00
<Image
alt="typeframes.ai logo"
fetchPriority="high"
2024-09-18 21:44:09 +08:00
width={locale === "en" ? 168 : 128}
height={48}
2024-09-18 16:35:40 +08:00
decoding="async"
style={{ color: "transparent" }}
2024-09-18 21:44:09 +08:00
className=" object-contain"
src={
locale === "en"
? "/logo_en.png"
: "/logo_zh.png"
}
2024-09-18 16:35:40 +08:00
/>
</Link>
</div>
<Link
href="/create"
className="inline-flex gap-1.5 items-center justify-center whitespace-nowrap z-0 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-black border border-black relative text-white px-4 py-2 rounded-md w-full"
>
<span className="btn-icon">
<FaPlus size="1em" />
</span>
{t("createNewVideo")}
</Link>
<div className="mt-4 flex flex-col w-full gap-4 items-start justify-between h-full">
<div className="flex flex-col gap-2 w-full">
{menu.map((menuGroup) => {
return (
<div
className="flex flex-col gap-2"
key={menuGroup.title}
>
<div className="mt-4 mb-1 text-[10px] text-info tracking-wider">
{menuGroup.title}
</div>
{menuGroup.items.map((item) => {
return (
<div key={item.name}>
<Link
className={classNames(
"gap-2 cursor-pointer text-sm font-medium flex justify-start items-center p-2 hover:bg-base-100 rounded-md",
{
"bg-base-100/50":
pathname ===
item.href,
"text-info":
pathname !==
item.href,
}
)}
href={item.href}
>
<MdOutlineHome size={18} />
{item.name}
</Link>
</div>
);
})}
</div>
);
})}
</div>
<div className="flex flex-col w-full items-start">
<div className="relative flex items-center text-sm w-fit mb-4">
<div className="z-[0]">
<Link
className="btn-tf btn-tf-sm btn-tf-lock-price bg-black text-white cursor-pointer flex items-center gap-2.5"
href="/pricing"
>
<BsLightningChargeFill size={16} />
{t("upgradeNow")}
</Link>
<div className="absolute z-[-1] -inset-0.5 bg-gradient-to-r from-sky-400 to-fuchsia-400 rounded-full blur opacity-75 group-hover:opacity-100 transition duration-1000 group-hover:duration-200 animate-tilt"></div>
</div>
</div>
<div className="mt-2 flex justify-between items-center w-full text-info bg-gray-50 border border-base-100 rounded-lg px-2.5 py-1.5">
<div className="flex flex-col justify-center">
<div className="text-sm text-gray-600 font-medium overflow-hidden text-ellipsis max-w-[142px]">
{user?.username
? user.username
: user?.email}
</div>
<div className="relative flex items-center text-xs cursor-pointer">
{t("aiCredits")}: {user?.points}
</div>
</div>
<div className="cursor-pointer" onClick={logout}>
<MdLogout size={16} />
</div>
</div>
</div>
</div>
</div>
{/* 点击空白处关闭侧边栏 */}
{sidebarOpen && (
<div
className="fixed inset-0 bg-black bg-opacity-50 z-10 lg:hidden"
onClick={toggleSidebar}
></div>
)}
</div>
);
}