Files
biliup/app/layout.tsx
T
2024-06-01 00:07:21 +08:00

341 lines
13 KiB
TypeScript

"use client";
import "./globals.css";
import styles from "./page.module.css";
import { SetStateAction, useCallback, useMemo, useState } from "react";
import Link from "next/link";
import { usePathname, useRouter } from "next/navigation";
import { Button, Nav } from "@douyinfe/semi-ui";
import { OnSelectedData } from "@douyinfe/semi-ui/lib/es/navigation";
import { Layout as SeLayout } from "@douyinfe/semi-ui/lib/es/layout";
import {
IconCloudStroked,
IconCustomerSupport,
IconDoubleChevronLeft,
IconDoubleChevronRight,
IconMoon,
IconSemiLogo,
IconStar,
IconSun,
IconVideoListStroked,
IconHome, IconSetting,
} from "@douyinfe/semi-icons";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const { Sider } = SeLayout;
const pathname = usePathname();
let initOpenKeys: any = [];
if (pathname.slice(1) === "streamers" || pathname.slice(1) === "history") {
initOpenKeys = ["manager"];
}
const [openKeys, setOpenKeys] = useState(initOpenKeys);
const [selectedKeys, setSelectedKeys] = useState<any>([pathname.slice(1)]);
const [isCollapsed, setIsCollapsed] = useState(false);
const [mode, setMode] = useState("light");
let navStyle = isCollapsed
? { height: "100%", overflow: "visible" }
: { height: "100%" };
const items = useMemo(
() =>
[
{
itemKey: "home",
text: "主页",
icon: (
<div
style={{
backgroundColor: "#ffaa00ff",
borderRadius:
"var(--semi-border-radius-medium)",
color: "var(--semi-color-bg-0)",
display: "flex",
// justifyContent: 'center',
padding: "4px",
}}
>
<IconHome size="small" />
</div>
),
},
{
itemKey: "manager",
text: "录播管理",
items: [
{ itemKey: "streamers", text: "直播管理" },
{ itemKey: "history", text: "历史记录" },
],
icon: (
<div
style={{
backgroundColor: "#5ac262ff",
borderRadius:
"var(--semi-border-radius-medium)",
color: "var(--semi-color-bg-0)",
display: "flex",
// justifyContent: 'center',
padding: "4px",
}}
>
<IconVideoListStroked size="small" />
</div>
),
},
{
itemKey: "upload-manager",
text: "投稿管理",
icon: (
<div
style={{
backgroundColor: "#885bd2ff",
borderRadius:
"var(--semi-border-radius-medium)",
color: "var(--semi-color-bg-0)",
display: "flex",
padding: "4px",
}}
>
<IconCloudStroked size="small" />
</div>
),
},
{
itemKey: "dashboard",
text: "空间配置",
icon: (
<div
style={{
backgroundColor: "#6b6c75ff",
borderRadius:
"var(--semi-border-radius-medium)",
color: "var(--semi-color-bg-0)",
display: "flex",
padding: "4px",
}}
>
<IconStar size="small" />
</div>
),
},
{
itemKey: "job",
text: "直播历史",
icon: (
<div
style={{
backgroundColor: "rgb(250 102 76)",
borderRadius:
"var(--semi-border-radius-medium)",
color: "var(--semi-color-bg-0)",
display: "flex",
padding: "4px",
}}
>
<IconCustomerSupport size="small" />
</div>
),
},
{
text: '任务平台',
icon: <div
style={{
backgroundColor: "rgba(var(--semi-lime-2), 1)",
borderRadius:
"var(--semi-border-radius-medium)",
color: "var(--semi-color-bg-0)",
display: "flex",
padding: "4px",
}}
>
<IconSetting size="small"/>
</div>,
itemKey: 'status',
// items: [{itemKey: 'About', text: '任务管理'}, {itemKey: 'Dashboard', text: '用户任务查询'}],
},
].map((value: any) => {
value.text = (
<div
style={{
color:
selectedKeys.some(
(key: string) => value.itemKey === key
) ||
(selectedKeys.some((key: string) =>
openKeys.some((o: string | number) =>
isSub(key, o)
)
) &&
openKeys.some(
(key: any) => value.itemKey === key
))
? "var(--semi-color-text-0)"
: "var(--semi-color-text-2)",
fontWeight: 600,
}}
>
{value.text}
</div>
);
return value;
}),
[openKeys, selectedKeys]
);
const renderWrapper = useCallback(
({ itemElement, isSubNav, isInSubNav, props }: any) => {
const routerMap: Record<string, string> = {
home: "/",
history: "/history",
dashboard: "/dashboard",
streamers: "/streamers",
"upload-manager": "/upload-manager",
job: "/job",
status: "/status",
};
if (!routerMap[props.itemKey]) {
return itemElement;
}
return (
<Link
style={{
textDecoration: "none",
fontWeight: "600 !important",
}}
href={routerMap[props.itemKey]}
>
{itemElement}
</Link>
);
// return itemElement;
},
[]
);
const onSelect = (data: OnSelectedData) => {
setSelectedKeys([...data.selectedKeys]);
};
const onOpenChange = (data: any) => {
setOpenKeys([...data.openKeys]);
};
const onCollapseChange = useCallback(() => {
setIsCollapsed(!isCollapsed);
}, [isCollapsed]);
return (
<html lang="zh-Hans">
<body style={{ width: "100%" }}>
<SeLayout className="components-layout-demo semi-light-scrollbar">
<Sider>
<Nav
style={navStyle}
// toggleIconPosition={'left'}
// defaultOpenKeys={['job']}
openKeys={openKeys}
selectedKeys={selectedKeys}
isCollapsed={isCollapsed}
// bodyStyle={{height: '100%'}}
renderWrapper={renderWrapper}
items={items}
// onCollapseChange={onCollapseChange}
onOpenChange={onOpenChange}
onSelect={onSelect}
// header={{
// logo: <IconSemiLogo style={{height: '36px', fontSize: 36}}/>,
// text: 'BILIUP'
// }}
// footer={{
// collapseButton: true,
// }}
>
<Nav.Header
logo={
// <IconSemiLogo
// style={{ height: "36px", fontSize: 36 }}
// />
<img src='logo.png' alt='{}'></img>
}
style={{ justifyContent: "flex-start" }}
text="BILIUP"
>
<div
style={{
flexGrow: 1,
display: "flex",
flexDirection: "row-reverse",
alignSelf: "flex-end",
zIndex: 2,
}}
>
<Button
onClick={onCollapseChange}
type="tertiary"
className={styles.shadow}
theme="borderless"
icon={
isCollapsed ? (
<IconDoubleChevronRight />
) : (
<IconDoubleChevronLeft />
)
}
/>
</div>
</Nav.Header>
{footer(mode, setMode)}
</Nav>
</Sider>
<SeLayout style={{ height: "100vh" }}>{children}</SeLayout>
</SeLayout>
</body>
</html>
);
}
function footer(
mode: string,
setMode: {
(value: SetStateAction<string>): void;
(arg0: string): void;
}
) {
const switchMode = () => {
const body = document.body;
if (body.hasAttribute("theme-mode")) {
body.removeAttribute("theme-mode");
setMode("light");
} else {
body.setAttribute("theme-mode", "dark");
setMode("dark");
}
};
return (
<Nav.Footer collapseButton={true}>
<Button
onClick={switchMode}
theme="borderless"
icon={
mode === "light" ? (
<IconMoon size="large" />
) : (
<IconSun size="large" />
)
}
style={{
color: "var(--semi-color-text-2)",
// marginRight: '12px',
// zIndex: 100,
}}
/>
</Nav.Footer>
);
}
function isSub(key1: string, key2: string | number) {
const routerMap: any = {
manager: ["streamers", "history"],
};
return routerMap[key2]?.includes(key1);
}