Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: layout style and button #392

Merged
merged 2 commits into from
Jul 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 43 additions & 32 deletions components/shared/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,67 +1,78 @@
import { useState } from "react";
import type { IconNameV2 } from "@/components/shared/Icon/v2/icons";
import Icon from "@/components/shared/Icon";
import IconV2 from "@/components/shared/Icon/v2";
import Button from "@/components/shared/Button";
import Badge from "@/components/shared/Badge";
import UserInfoModal from "@/components/lobby/UserInfoModal";
import { cn } from "@/lib/utils";
import useAuth from "@/hooks/context/useAuth";
import useUser from "@/hooks/useUser";
import UserInfoModal from "../lobby/UserInfoModal";
import Button from "./Button";
import Badge from "./Badge";
import Icon from "./Icon";
import type { IconName } from "./Icon/icons";

enum HeaderActions {
HELP = "HELP",
REMIND = "REMIND",
CHAT = "CHAT",
NOTIFICATION = "NOTIFICATION",
PROFILE = "PROFILE",
}

export default function Header() {
const { currentUser } = useAuth();
const { logout } = useUser();
interface ButtonProps {
type: HeaderActions;
iconName: IconNameV2;
isActive: boolean;
onClick: () => void;
}

export default function Header() {
const [openProfile, setOpenProfile] = useState(false);

const buttons = [
const buttons: ButtonProps[] = [
{
iconName: "chatDefault",
type: HeaderActions.CHAT,
isActive: false,
onClick: () => {},
},
{
iconName: "notificationDefault",
type: HeaderActions.NOTIFICATION,
isActive: false,
onClick: () => {},
},
{
Icon: "player" as IconName,
iconName: "player",
type: HeaderActions.PROFILE,
click: () => {
isActive: openProfile,
onClick: () => {
setOpenProfile(true);
},
active: openProfile,
},
];

return (
<header className="flex flex-row items-center justify-between p-[10px_15px] bg-dark1E">
<header className="flex flex-row items-center justify-between px-8 py-2 bg-white/8 glass-shadow">
<div className="flex items-center gap-3">
<Icon name="logo" className="bg-transparent" />
<h2 className="text-primary-100 text-2xl">遊戲微服務大平台</h2>
</div>
<div className="header___actions flex gap-6">
{buttons.map((ButtonProps) => (
<div className="header___actions flex gap-5">
{buttons.map(({ type, iconName, isActive, onClick }) => (
<Badge
dot
key={ButtonProps.type}
key={type}
placement="top-right"
count={ButtonProps.type !== HeaderActions.HELP ? 1 : 0}
size="xLarge"
className={cn("top-1 right-1", {
"right-2": ButtonProps.type === HeaderActions.REMIND,
})}
className={cn("top-1 right-1")}
>
<Button
className="relative bg-transparent hover:shadow-none p-0"
onClick={ButtonProps.click}
className="relative bg-transparent hover:shadow-none p-2.5"
onClick={onClick}
>
<Icon
name={ButtonProps.Icon}
className={cn("[&_*]:stroke-white", {
"fill-blue": ButtonProps.active,
<IconV2
name={iconName}
className={cn("w-5 h-5 [&_*]:stroke-white", {
"fill-blue": isActive,
})}
/>
</Button>
</Badge>
))}
{currentUser && <Button onClick={logout}>登出</Button>}
</div>
{openProfile && (
<UserInfoModal
Expand Down
62 changes: 35 additions & 27 deletions components/shared/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,65 @@
import Link from "next/link";
import { useRouter } from "next/router";
import { cn } from "@/lib/utils";

import Button from "./Button";
import Icon from "@/components/shared/Icon";
import type { IconName } from "./Icon/icons";
import type { IconNameV2 } from "@/components/shared/Icon/v2/icons";
import Icon from "@/components/shared/Icon/v2";
import Button from "@/components/shared/Button";
import useAuth from "@/hooks/context/useAuth";
import useUser from "@/hooks/useUser";
import { cn } from "@/lib/utils";

enum SidebarRoutes {
HOME = "/",
ROOMS = "/rooms",
}

interface ButtonProps {
text: string;
iconName: IconNameV2;
route: SidebarRoutes;
}

export default function Sidebar() {
const router = useRouter();
const { pathname } = router;
const { pathname } = useRouter();
const { currentUser } = useAuth();
const { logout } = useUser();

const buttons: {
text: string;
iconName: IconName;
route: SidebarRoutes;
}[] = [
const buttons: ButtonProps[] = [
{ text: "遊戲大廳", iconName: "home", route: SidebarRoutes.HOME },
{ text: "遊戲房間", iconName: "arcade", route: SidebarRoutes.ROOMS },
];

return (
<nav className="flex flex-col shrink-0 justify-start bg-dark29 rounded-[10px] w-[71px] gap-5">
<nav className="flex flex-col shrink-0 justify-start bg-white/8 glass-shadow my-6 ms-1.5 py-6 rounded-2xl w-18 gap-5">
{buttons.map((ButtonProps) => (
<Link
href={ButtonProps.route}
key={ButtonProps.text}
className="flex justify-center items-center"
>
<Button
className={cn(
"bg-transparent px-0 justify-center opacity-[0.3] hover:shadow-none hover:opacity-100",
{
"opacity-1": pathname === ButtonProps.route,
}
)}
className={cn("bg-transparent p-3 rounded-full hover:shadow-none", {
"bg-primary-200/20": pathname === ButtonProps.route,
})}
>
<div className="w-full flex flex-col items-center gap-1">
<Icon
name={ButtonProps.iconName}
className={{
"[&_*]:stroke-[#2F88FF]": pathname === ButtonProps.route,
}}
/>
<span className={cn("text-xs")}>{ButtonProps.text}</span>
</div>
<Icon
name={ButtonProps.iconName}
className={cn("w-6 h-6 stroke-primary-400", {
"stroke-primary-200": pathname === ButtonProps.route,
})}
/>
</Button>
</Link>
))}
{currentUser && (
<Button
className="mt-auto bg-transparent px-0 justify-center opacity-[0.3] hover:shadow-none hover:opacity-100"
onClick={logout}
>
<Icon className="stroke-primary-400" name="logOut" />
<span className="text-xs">登出</span>
</Button>
)}
</nav>
);
}
2 changes: 1 addition & 1 deletion containers/layout/AppLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
<Header />
<div className="container__ flex flex-grow gap-5">
<Sidebar />
<main className="flex-grow w-full h-full">{children}</main>
<main className="flex-grow">{children}</main>
</div>
<Footer />
</div>
Expand Down
2 changes: 1 addition & 1 deletion hooks/useRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const useRequest = () => {
toast: {
show: true,
options: {
position: "bottom-left",
position: "bottom-right",
},
},
}
Expand Down
5 changes: 1 addition & 4 deletions pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ export default function Home() {
return (
<>
<h1 className="text-white">遊戲大廳!</h1>
<div
className="px-[18px] mt-[12px] mb-[22px]"
style={{ width: "calc(100vw - 71px)" }}
>
<div className="px-[18px] mt-[12px] mb-[22px] w-[calc(100vw-100px)]">
<Carousel
itemWidth={332}
itemHeight={158}
Expand Down
10 changes: 10 additions & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ module.exports = {
body: ['"Noto Sans TC"', "Roboto"],
},
extend: {
width: {
18: "4.5rem" /** 72px */,
},
opacity: {
4: 0.04,
8: 0.08,
Expand Down Expand Up @@ -128,6 +131,13 @@ module.exports = {
"background-image":
"linear-gradient(145.51deg, #06020B -7.4%, #2C1B47 154.79%)",
},
".glass-shadow": {
"box-shadow": `
0 8px 6px rgba(0, 0, 0, 0.05),
0 1px 1px rgba(255, 255, 255, 0.25),
0 -1px 1px rgba(255, 255, 255, 0.1)
`,
},
});
}),
plugin(({ addUtilities }) => {
Expand Down
Loading