122 lines
6.6 KiB
TypeScript
122 lines
6.6 KiB
TypeScript
import { Headphones, Mic, Settings } from "lucide-react";
|
|
import React from "react";
|
|
import { NavLink } from "react-router";
|
|
import { useShallow } from 'zustand/react/shallow';
|
|
import { cn, getFirstLetters } from "~/lib/utils";
|
|
import { useServerListStore } from "~/store/server-list";
|
|
import { useUserStore } from "~/store/user";
|
|
import { CreateServerButton } from "./create-server";
|
|
import Discord from "./icons/Discord";
|
|
import { OnlineStatus } from "./online-status";
|
|
import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar";
|
|
import { Button } from "./ui/button";
|
|
import { ScrollArea } from "./ui/scroll-area";
|
|
import { Separator } from "./ui/separator";
|
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./ui/tooltip";
|
|
|
|
interface AppLayoutProps {
|
|
list: React.ReactNode;
|
|
children: React.ReactNode;
|
|
}
|
|
|
|
export default function AppLayout({ list, children }: AppLayoutProps) {
|
|
let user = useUserStore(state => state.user!)
|
|
let servers = useServerListStore(useShallow((state) => Array.from(state.servers.values())))
|
|
|
|
return (
|
|
<div className="flex h-screen w-screen overflow-hidden">
|
|
<div className="grid h-full max-h-screen bg-accent/60 min-w-80" style={{ gridTemplateColumns: "auto 1fr", gridTemplateRows: "1fr auto" }}>
|
|
<div className="col-start-1 row-start-1 col-span-1 row-span-1 overflow-hidden border-r-2 min-w-fit">
|
|
<ScrollArea className="h-full px-1" scrollbarSize="none">
|
|
<aside className="flex flex-col gap-4 p-2 h-full">
|
|
<NavLink to={`/app/@me`} className={({ isActive }) =>
|
|
cn(
|
|
"rounded-xl",
|
|
isActive ? "bg-primary" : "bg-accent",
|
|
)
|
|
}>
|
|
<Discord className="size-8 m-2" />
|
|
</NavLink>
|
|
<Separator />
|
|
{
|
|
servers.map((server, _) =>
|
|
<React.Fragment key={server.id}>
|
|
<TooltipProvider>
|
|
<Tooltip>
|
|
<NavLink to={`/app/server/${server.id}`} className={({ isActive }) =>
|
|
cn(
|
|
"rounded-xl overflow-hidden",
|
|
isActive ? "bg-primary" : "bg-accent",
|
|
)
|
|
}>
|
|
{({ isActive }) => (
|
|
<TooltipTrigger asChild>
|
|
<Avatar className="size-12 rounded-none">
|
|
<AvatarImage src={server.icon_url} className="rounded-none" />
|
|
<AvatarFallback className={cn(isActive ? "bg-primary text-accent" : "", "rounded-none")}>
|
|
<div>
|
|
{getFirstLetters(server.name, 4)}
|
|
</div>
|
|
</AvatarFallback>
|
|
</Avatar>
|
|
</TooltipTrigger>
|
|
)}
|
|
</NavLink>
|
|
<TooltipContent>
|
|
{server.name}
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
</TooltipProvider>
|
|
</React.Fragment>
|
|
)
|
|
}
|
|
{servers.length > 0 && <Separator />}
|
|
<CreateServerButton />
|
|
</aside>
|
|
</ScrollArea>
|
|
</div>
|
|
<div className="col-start-2 row-start-1 col-span-1 row-span-1 overflow-hidden">
|
|
{list}
|
|
</div>
|
|
|
|
<div className="col-start-1 row-start-2 col-span-2 row-span-1 mb-2 mx-2 min-w-fit z-1">
|
|
<div className="outline-1 p-2 h-full rounded-xl">
|
|
<div className="flex justify-between items-center gap-2">
|
|
<div className="grow flex flex-row gap-2">
|
|
<OnlineStatus status="online">
|
|
<Avatar className="size-10">
|
|
<AvatarImage src="https://api.dicebear.com/9.x/bottts/jpg?seed=lionarius" />
|
|
</Avatar>
|
|
</OnlineStatus>
|
|
|
|
<div className="flex flex-col text-sm justify-center">
|
|
<div className="truncate max-w-30">
|
|
{user.displayName || user.username}
|
|
</div>
|
|
<span className="text-muted-foreground text-xs">@{user.username}</span>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div className="flex flex-row-reverse gap-2 items-center">
|
|
<Button variant="secondary" size="none">
|
|
<Settings className="size-5 m-1.5" />
|
|
</Button>
|
|
<Button variant="secondary" size="none">
|
|
<Headphones className="size-5 m-1.5" />
|
|
</Button>
|
|
<Button variant="secondary" size="none">
|
|
<Mic className="size-5 m-1.5" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grow">
|
|
{children}
|
|
</div>
|
|
</div>
|
|
)
|
|
} |