diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 26a3fe55..451918a7 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -23,6 +23,7 @@ "@milkdown/theme-nord": "^7.5.0", "@prosemirror-adapter/react": "^0.2.6", "@radix-ui/react-dialog": "^1.1.2", + "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-label": "^2.1.0", "@radix-ui/react-slot": "^1.1.0", "class-variance-authority": "^0.7.0", diff --git a/packages/frontend/src/App.tsx b/packages/frontend/src/App.tsx index b1f7769c..7f41c5ed 100644 --- a/packages/frontend/src/App.tsx +++ b/packages/frontend/src/App.tsx @@ -10,7 +10,7 @@ function App() { } /> - } /> + } /> } /> diff --git a/packages/frontend/src/components/SpaceBreadcrumb.tsx b/packages/frontend/src/components/SpaceBreadcrumb.tsx new file mode 100644 index 00000000..092c883d --- /dev/null +++ b/packages/frontend/src/components/SpaceBreadcrumb.tsx @@ -0,0 +1,124 @@ +import { Link } from "react-router-dom"; + +import { + Breadcrumb, + BreadcrumbEllipsis, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator, +} from "./ui/breadcrumb"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "./ui/dropdown-menu"; + +type SpacePath = { + name: string; + urlPath: string; +}; + +function splitSpacePaths(spacePaths: SpacePath[], itemCountToDisplay: number) { + // 처음 스페이스는 무조건 보여준다. + const firstSpacePath = spacePaths[0]; + + // 중간 스페이스들은 ...으로 표시하고, 클릭 시 드롭다운 메뉴로 보여준다. + const hiddenSpacePaths = spacePaths.slice(1, -2); + + // 마지막 (n-1)개 스페이스는 무조건 보여준다. + const lastItemCount = Math.min(spacePaths.length, itemCountToDisplay - 1); + const shownSpacePaths = spacePaths.slice(-lastItemCount); + + return [firstSpacePath, hiddenSpacePaths, shownSpacePaths] as const; +} + +type HiddenItemsProps = { + spacePaths: SpacePath[]; +}; + +function HiddenItems({ spacePaths }: HiddenItemsProps) { + return ( + <> + + + + + + + {spacePaths.map(({ name, urlPath }) => ( + + {name} + + ))} + + + + + + ); +} + +type SpaceBreadcrumbItemProps = { + spacePath: SpacePath; + isPage?: boolean; +}; + +function SpaceBreadcrumbItem({ spacePath, isPage }: SpaceBreadcrumbItemProps) { + if (isPage) { + return ( + + + {spacePath.name} + + + ); + } + + return ( + + + + {spacePath.name} + + + + + ); +} + +type SpaceBreadcrumbProps = { + spacePaths: SpacePath[]; + itemCountToDisplay?: number; +}; + +export default function SpaceBreadcrumb({ + spacePaths, + itemCountToDisplay = 3, +}: SpaceBreadcrumbProps) { + // [처음, (...중간...), 직전, 현재] + const [firstSpacePath, hiddenSpacePaths, shownSpacePaths] = splitSpacePaths( + spacePaths, + itemCountToDisplay, + ); + + return ( + + + {firstSpacePath && } + {hiddenSpacePaths.length > 0 && ( + + )} + {shownSpacePaths.map((spacePath, index) => ( + + ))} + + + ); +} diff --git a/packages/frontend/src/components/space/SpacePageHeader.tsx b/packages/frontend/src/components/space/SpacePageHeader.tsx new file mode 100644 index 00000000..14cce5c3 --- /dev/null +++ b/packages/frontend/src/components/space/SpacePageHeader.tsx @@ -0,0 +1,33 @@ +import SpaceBreadcrumb from "../SpaceBreadcrumb"; +import { Button } from "../ui/button"; + +export default function SpacePageHeader() { + return ( +
+
+
+ +
+
+ +
+
+
+ ); +} diff --git a/packages/frontend/src/components/space/YjsSpaceView.tsx b/packages/frontend/src/components/space/YjsSpaceView.tsx deleted file mode 100644 index 519f3564..00000000 --- a/packages/frontend/src/components/space/YjsSpaceView.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { RefObject } from "react"; - -import useYjsConnection from "@/hooks/yjs/useYjsConnection"; -import { YjsStoreProvider } from "@/store/yjs"; - -import SpaceView from "./SpaceView"; - -type YjsSpaceViewProps = { - spaceId: string; - autofitTo?: Element | RefObject; -}; - -export default function YjsSpaceView({ - spaceId, - autofitTo, -}: YjsSpaceViewProps) { - const { yDoc, yProvider, setYDoc, setYProvider } = useYjsConnection(spaceId); - - return ( - - - - ); -} diff --git a/packages/frontend/src/components/ui/breadcrumb.tsx b/packages/frontend/src/components/ui/breadcrumb.tsx new file mode 100644 index 00000000..60e6c96f --- /dev/null +++ b/packages/frontend/src/components/ui/breadcrumb.tsx @@ -0,0 +1,115 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { ChevronRight, MoreHorizontal } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Breadcrumb = React.forwardRef< + HTMLElement, + React.ComponentPropsWithoutRef<"nav"> & { + separator?: React.ReactNode + } +>(({ ...props }, ref) =>