[WEB-4050] feat: breadcrumbs revamp (#7188)

* chore: project feature enum added

* feat: revamp breadcrumb and add navigation dropdown component

* chore: custom search select component refactoring

* chore: breadcrumb stories added

* chore: switch label and breadcrumb link component refactor

* chore: project navigation helper function added

* chore: common breadcrumb component added

* chore: breadcrumb refactoring

* chore: code refactor

* chore: code refactor

* fix: build error

* fix: nprogress and button tooltip

* chore: code refactor

* chore: workspace view breadcrumb improvements

* chore: code refactor

* chore: code refactor

* chore: code refactor

* chore: code refactor

---------

Co-authored-by: vamsikrishnamathala <matalav55@gmail.com>
This commit is contained in:
Anmol Singh Bhatia 2025-06-19 17:17:14 +05:30 committed by GitHub
parent 64fd0b2830
commit 2b7a17b484
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
44 changed files with 1251 additions and 581 deletions

View file

@ -66,10 +66,9 @@ export const ProjectArchivesHeader: FC<TProps> = observer((props: TProps) => {
<Header.LeftItem>
<div className="flex items-center gap-2.5">
<Breadcrumbs onBack={router.back} isLoading={loader === "init-loader"}>
<ProjectBreadcrumb />
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<ProjectBreadcrumb workspaceSlug={workspaceSlug?.toString()} projectId={projectId?.toString()} />
<Breadcrumbs.Item
component={
<BreadcrumbLink
href={`/${workspaceSlug}/projects/${projectId}/archives/issues`}
label="Archives"
@ -78,9 +77,8 @@ export const ProjectArchivesHeader: FC<TProps> = observer((props: TProps) => {
}
/>
{activeTabBreadcrumbDetail && (
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<Breadcrumbs.Item
component={
<BreadcrumbLink
label={activeTabBreadcrumbDetail.label}
icon={<activeTabBreadcrumbDetail.icon className="h-4 w-4 text-custom-text-300" />}

View file

@ -36,10 +36,9 @@ export const ProjectArchivedIssueDetailsHeader = observer(() => {
<Header>
<Header.LeftItem>
<Breadcrumbs isLoading={loader === "init-loader"}>
<ProjectBreadcrumb />
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<ProjectBreadcrumb workspaceSlug={workspaceSlug?.toString()} projectId={projectId?.toString()} />
<Breadcrumbs.Item
component={
<BreadcrumbLink
href={`/${workspaceSlug}/projects/${projectId}/archives/issues`}
label="Archives"
@ -47,9 +46,8 @@ export const ProjectArchivedIssueDetailsHeader = observer(() => {
/>
}
/>
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<Breadcrumbs.Item
component={
<BreadcrumbLink
href={`/${workspaceSlug}/projects/${projectId}/archives/issues`}
label="Work items"
@ -57,9 +55,8 @@ export const ProjectArchivedIssueDetailsHeader = observer(() => {
/>
}
/>
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<Breadcrumbs.Item
component={
<BreadcrumbLink
label={
currentProjectDetails && issueDetails

View file

@ -2,7 +2,6 @@
import { useCallback, useRef, useState } from "react";
import { observer } from "mobx-react";
import Link from "next/link";
import { useParams } from "next/navigation";
// icons
import { PanelRight } from "lucide-react";
@ -13,8 +12,10 @@ import {
EIssuesStoreType,
EUserPermissions,
EUserPermissionsLevel,
EProjectFeatureKey,
ISSUE_DISPLAY_FILTERS_BY_PAGE,
} from "@plane/constants";
import { usePlatformOS } from "@plane/hooks";
import { useTranslation } from "@plane/i18n";
import {
ICustomSearchSelectOption,
@ -22,11 +23,11 @@ import {
IIssueDisplayProperties,
IIssueFilterOptions,
} from "@plane/types";
import { Breadcrumbs, Button, ContrastIcon, CustomSearchSelect, Header, Tooltip } from "@plane/ui";
import { Breadcrumbs, Button, ContrastIcon, BreadcrumbNavigationSearchDropdown, Header, Tooltip } from "@plane/ui";
import { cn, isIssueFilterActive } from "@plane/utils";
// components
import { WorkItemsModal } from "@/components/analytics/work-items/modal";
import { BreadcrumbLink, SwitcherLabel } from "@/components/common";
import { SwitcherLabel } from "@/components/common";
import { CycleQuickActions } from "@/components/cycles";
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "@/components/issues";
// hooks
@ -43,9 +44,8 @@ import {
} from "@/hooks/store";
import { useAppRouter } from "@/hooks/use-app-router";
import useLocalStorage from "@/hooks/use-local-storage";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web imports
import { ProjectBreadcrumb } from "@/plane-web/components/breadcrumbs";
import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs/common";
export const CycleIssuesHeader: React.FC = observer(() => {
// refs
@ -166,63 +166,44 @@ export const CycleIssuesHeader: React.FC = observer(() => {
<Header.LeftItem>
<div className="flex items-center gap-2">
<Breadcrumbs onBack={router.back} isLoading={loader === "init-loader"}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<span>
<span className="hidden md:block">
<ProjectBreadcrumb />
</span>
<Link
href={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`}
className="block pl-2 text-custom-text-300 md:hidden"
>
...
</Link>
</span>
}
<CommonProjectBreadcrumbs
workspaceSlug={workspaceSlug?.toString()}
projectId={projectId?.toString()}
featureKey={EProjectFeatureKey.CYCLES}
/>
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<BreadcrumbLink
label={t("common.cycles")}
href={`/${workspaceSlug}/projects/${projectId}/cycles`}
icon={<ContrastIcon className="h-4 w-4 text-custom-text-300" />}
/>
}
/>
<Breadcrumbs.BreadcrumbItem
type="component"
<Breadcrumbs.Item
component={
<CustomSearchSelect
options={switcherOptions}
value={cycleId}
<BreadcrumbNavigationSearchDropdown
selectedItem={cycleId}
navigationItems={switcherOptions}
onChange={(value: string) => {
router.push(`/${workspaceSlug}/projects/${projectId}/cycles/${value}`);
}}
label={
<div className="flex items-center gap-1">
<SwitcherLabel name={cycleDetails?.name} LabelIcon={ContrastIcon} />
{workItemsCount && workItemsCount > 0 ? (
<Tooltip
isMobile={isMobile}
tooltipContent={`There are ${workItemsCount} ${
workItemsCount > 1 ? "work items" : "work item"
} in this cycle`}
position="bottom"
>
<span className="flex flex-shrink-0 cursor-default items-center justify-center rounded-xl bg-custom-primary-100/20 px-2 text-center text-xs font-semibold text-custom-primary-100">
{workItemsCount}
</span>
</Tooltip>
) : null}
</div>
title={cycleDetails?.name}
icon={
<Breadcrumbs.Icon>
<ContrastIcon className="size-4 flex-shrink-0 text-custom-text-300" />
</Breadcrumbs.Icon>
}
isLast
/>
}
isLast
/>
</Breadcrumbs>
{workItemsCount && workItemsCount > 0 ? (
<Tooltip
isMobile={isMobile}
tooltipContent={`There are ${workItemsCount} ${
workItemsCount > 1 ? "work items" : "work item"
} in this cycle`}
position="bottom"
>
<span className="flex flex-shrink-0 cursor-default items-center justify-center rounded-xl bg-custom-primary-100/20 px-2 text-center text-xs font-semibold text-custom-primary-100">
{workItemsCount}
</span>
</Tooltip>
) : null}
</div>
</Header.LeftItem>
<Header.RightItem className="items-center">

View file

@ -2,23 +2,25 @@
import { FC } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
// ui
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
import { EProjectFeatureKey, EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { Breadcrumbs, Button, ContrastIcon, Header } from "@plane/ui";
import { Breadcrumbs, Button, Header } from "@plane/ui";
// components
import { BreadcrumbLink } from "@/components/common";
import { CyclesViewHeader } from "@/components/cycles";
// hooks
import { useCommandPalette, useEventTracker, useProject, useUserPermissions } from "@/hooks/store";
import { useAppRouter } from "@/hooks/use-app-router";
// plane web
import { ProjectBreadcrumb } from "@/plane-web/components/breadcrumbs";
import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs/common";
// constants
export const CyclesListHeader: FC = observer(() => {
// router
const router = useAppRouter();
const { workspaceSlug } = useParams();
// store hooks
const { toggleCreateCycleModal } = useCommandPalette();
const { setTrackElement } = useEventTracker();
@ -35,15 +37,11 @@ export const CyclesListHeader: FC = observer(() => {
<Header>
<Header.LeftItem>
<Breadcrumbs onBack={router.back} isLoading={loader === "init-loader"}>
<ProjectBreadcrumb />
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<BreadcrumbLink
label={t("cycle.label", { count: 2 })}
icon={<ContrastIcon className="h-4 w-4 text-custom-text-300" />}
/>
}
<CommonProjectBreadcrumbs
workspaceSlug={workspaceSlug?.toString()}
projectId={currentProjectDetails?.id ?? ""}
featureKey={EProjectFeatureKey.CYCLES}
isLast
/>
</Breadcrumbs>
</Header.LeftItem>

View file

@ -93,11 +93,10 @@ export const ProjectDraftIssueHeader: FC = observer(() => {
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div className="flex items-center gap-2.5">
<Breadcrumbs isLoading={loader === "init-loader"}>
<ProjectBreadcrumb />
<ProjectBreadcrumb workspaceSlug={workspaceSlug} projectId={projectId} />
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<Breadcrumbs.Item
component={
<BreadcrumbLink
label="Draft work items"
icon={<LayersIcon className="h-4 w-4 text-custom-text-300" />}

View file

@ -2,7 +2,6 @@
import { useCallback, useRef, useState } from "react";
import { observer } from "mobx-react";
import Link from "next/link";
import { useParams } from "next/navigation";
// icons
import { PanelRight } from "lucide-react";
@ -14,6 +13,7 @@ import {
ISSUE_DISPLAY_FILTERS_BY_PAGE,
EUserPermissions,
EUserPermissionsLevel,
EProjectFeatureKey,
} from "@plane/constants";
import {
ICustomSearchSelectOption,
@ -21,11 +21,11 @@ import {
IIssueDisplayProperties,
IIssueFilterOptions,
} from "@plane/types";
import { Breadcrumbs, Button, DiceIcon, Tooltip, Header, CustomSearchSelect } from "@plane/ui";
import { Breadcrumbs, Button, DiceIcon, Header, BreadcrumbNavigationSearchDropdown, Tooltip } from "@plane/ui";
import { cn, isIssueFilterActive } from "@plane/utils";
// components
import { WorkItemsModal } from "@/components/analytics/work-items/modal";
import { BreadcrumbLink, SwitcherLabel } from "@/components/common";
import { SwitcherLabel } from "@/components/common";
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "@/components/issues";
// helpers
import { ModuleQuickActions } from "@/components/modules";
@ -46,7 +46,7 @@ import { useIssuesActions } from "@/hooks/use-issues-actions";
import useLocalStorage from "@/hooks/use-local-storage";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web
import { ProjectBreadcrumb } from "@/plane-web/components/breadcrumbs";
import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs";
export const ModuleIssuesHeader: React.FC = observer(() => {
// refs
@ -160,64 +160,42 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
/>
<Header>
<Header.LeftItem>
<Breadcrumbs onBack={router.back} isLoading={loader === "init-loader"}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<span>
<span className="hidden md:block">
<ProjectBreadcrumb />
</span>
<Link
href={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`}
className="block pl-2 text-custom-text-300 md:hidden"
>
...
</Link>
<div className="flex items-center gap-2 flex-grow">
<Breadcrumbs onBack={router.back} isLoading={loader === "init-loader"}>
<CommonProjectBreadcrumbs
workspaceSlug={workspaceSlug?.toString() ?? ""}
projectId={projectId?.toString() ?? ""}
featureKey={EProjectFeatureKey.MODULES}
/>
<Breadcrumbs.Item
component={
<BreadcrumbNavigationSearchDropdown
selectedItem={moduleId?.toString() ?? ""}
navigationItems={switcherOptions}
onChange={(value: string) => {
router.push(`/${workspaceSlug}/projects/${projectId}/modules/${value}`);
}}
title={moduleDetails?.name}
icon={<DiceIcon className="size-3.5 flex-shrink-0 text-custom-text-300" />}
isLast
/>
}
/>
</Breadcrumbs>
{workItemsCount && workItemsCount > 0 ? (
<Tooltip
isMobile={isMobile}
tooltipContent={`There are ${workItemsCount} ${
workItemsCount > 1 ? "work items" : "work item"
} in this module`}
position="bottom"
>
<span className="flex flex-shrink-0 cursor-default items-center justify-center rounded-xl bg-custom-primary-100/20 px-2 text-center text-xs font-semibold text-custom-primary-100">
{workItemsCount}
</span>
}
/>
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<BreadcrumbLink
href={`/${workspaceSlug}/projects/${projectId}/modules`}
label="Modules"
icon={<DiceIcon className="h-4 w-4 text-custom-text-300" />}
/>
}
/>
<Breadcrumbs.BreadcrumbItem
type="component"
component={
<CustomSearchSelect
options={switcherOptions}
label={
<div className="flex items-center gap-1">
<SwitcherLabel name={moduleDetails?.name} LabelIcon={DiceIcon} />
{workItemsCount && workItemsCount > 0 ? (
<Tooltip
isMobile={isMobile}
tooltipContent={`There are ${workItemsCount} ${
workItemsCount > 1 ? "work items" : "work item"
} in this module`}
position="bottom"
>
<span className="flex flex-shrink-0 cursor-default items-center justify-center rounded-xl bg-custom-primary-100/20 px-2 text-center text-xs font-semibold text-custom-primary-100">
{workItemsCount}
</span>
</Tooltip>
) : null}
</div>
}
value={moduleId}
onChange={(value: string) => {
router.push(`/${workspaceSlug}/projects/${projectId}/modules/${value}`);
}}
/>
}
/>
</Breadcrumbs>
</Tooltip>
) : null}
</div>
</Header.LeftItem>
<Header.RightItem className="items-center">
<div className="hidden gap-2 md:flex">

View file

@ -1,24 +1,25 @@
"use client";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
// plane imports
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
import { EProjectFeatureKey, EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
// ui
import { Breadcrumbs, Button, DiceIcon, Header } from "@plane/ui";
import { Breadcrumbs, Button, Header } from "@plane/ui";
// components
import { BreadcrumbLink } from "@/components/common";
import { ModuleViewHeader } from "@/components/modules";
// hooks
import { useCommandPalette, useEventTracker, useProject, useUserPermissions } from "@/hooks/store";
import { useAppRouter } from "@/hooks/use-app-router";
// plane web
import { ProjectBreadcrumb } from "@/plane-web/components/breadcrumbs";
import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs";
// constants
export const ModulesListHeader: React.FC = observer(() => {
// router
const router = useAppRouter();
const { workspaceSlug, projectId } = useParams() as { workspaceSlug: string; projectId: string };
// store hooks
const { toggleCreateModuleModal } = useCommandPalette();
const { setTrackElement } = useEventTracker();
@ -39,12 +40,11 @@ export const ModulesListHeader: React.FC = observer(() => {
<Header.LeftItem>
<div>
<Breadcrumbs onBack={router.back} isLoading={loader === "init-loader"}>
<ProjectBreadcrumb />
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<BreadcrumbLink label={t("modules")} icon={<DiceIcon className="h-4 w-4 text-custom-text-300" />} />
}
<CommonProjectBreadcrumbs
workspaceSlug={workspaceSlug?.toString() ?? ""}
projectId={projectId?.toString() ?? ""}
featureKey={EProjectFeatureKey.MODULES}
isLast
/>
</Breadcrumbs>
</div>

View file

@ -2,20 +2,21 @@
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { FileText } from "lucide-react";
import { EProjectFeatureKey } from "@plane/constants";
// types
import { ICustomSearchSelectOption } from "@plane/types";
// ui
import { Breadcrumbs, Header, CustomSearchSelect } from "@plane/ui";
import { Breadcrumbs, Header, BreadcrumbNavigationSearchDropdown } from "@plane/ui";
// components
import { getPageName } from "@plane/utils";
import { BreadcrumbLink, PageAccessIcon, SwitcherLabel } from "@/components/common";
import { PageAccessIcon, SwitcherIcon, SwitcherLabel } from "@/components/common";
import { PageHeaderActions } from "@/components/pages/header/actions";
// helpers
// hooks
import { useProject } from "@/hooks/store";
// plane web components
import { useAppRouter } from "@/hooks/use-app-router";
import { ProjectBreadcrumb } from "@/plane-web/components/breadcrumbs";
import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs/common";
import { PageDetailsHeaderExtraActions } from "@/plane-web/components/pages";
// plane web hooks
import { EPageStoreType, usePage, usePageStore } from "@/plane-web/hooks/store";
@ -31,7 +32,7 @@ export const PageDetailsHeader = observer(() => {
const router = useAppRouter();
const { workspaceSlug, pageId, projectId } = useParams();
// store hooks
const { currentProjectDetails, loader } = useProject();
const { loader } = useProject();
const { getPageById, getCurrentProjectPageIds } = usePageStore(storeType);
const page = usePage({
pageId: pageId?.toString() ?? "",
@ -64,45 +65,27 @@ export const PageDetailsHeader = observer(() => {
<Header.LeftItem>
<div>
<Breadcrumbs isLoading={loader === "init-loader"}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<span>
<span className="hidden md:block">
<ProjectBreadcrumb />
</span>
<span className="md:hidden">
<BreadcrumbLink
href={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`}
label={"..."}
/>
</span>
</span>
}
<CommonProjectBreadcrumbs
workspaceSlug={workspaceSlug?.toString()}
projectId={projectId?.toString()}
featureKey={EProjectFeatureKey.PAGES}
/>
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<BreadcrumbLink
href={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/pages`}
label="Pages"
icon={<FileText className="h-4 w-4 text-custom-text-300" />}
/>
}
/>
<Breadcrumbs.BreadcrumbItem
type="component"
<Breadcrumbs.Item
component={
<CustomSearchSelect
value={pageId}
options={switcherOptions}
label={
<SwitcherLabel logo_props={page.logo_props} name={getPageName(page.name)} LabelIcon={FileText} />
}
<BreadcrumbNavigationSearchDropdown
selectedItem={pageId?.toString() ?? ""}
navigationItems={switcherOptions}
onChange={(value: string) => {
router.push(`/${workspaceSlug}/projects/${projectId}/pages/${value}`);
}}
title={page?.name}
icon={
<Breadcrumbs.Icon>
<SwitcherIcon logo_props={page.logo_props} LabelIcon={FileText} size={16} />
</Breadcrumbs.Icon>
}
isLast
/>
}
/>

View file

@ -3,19 +3,16 @@
import { useState } from "react";
import { observer } from "mobx-react";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import { FileText } from "lucide-react";
// constants
import { EPageAccess } from "@plane/constants";
import { EPageAccess, EProjectFeatureKey } from "@plane/constants";
// plane types
import { TPage } from "@plane/types";
// plane ui
import { Breadcrumbs, Button, Header, setToast, TOAST_TYPE } from "@plane/ui";
// helpers
import { BreadcrumbLink } from "@/components/common";
// hooks
import { useEventTracker, useProject } from "@/hooks/store";
// plane web
import { ProjectBreadcrumb } from "@/plane-web/components/breadcrumbs";
import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs";
// plane web hooks
import { EPageStoreType, usePageStore } from "@/plane-web/hooks/store";
@ -58,15 +55,14 @@ export const PagesListHeader = observer(() => {
return (
<Header>
<Header.LeftItem>
<div>
<Breadcrumbs isLoading={loader === "init-loader"}>
<ProjectBreadcrumb />
<Breadcrumbs.BreadcrumbItem
type="text"
link={<BreadcrumbLink label="Pages" icon={<FileText className="h-4 w-4 text-custom-text-300" />} />}
/>
</Breadcrumbs>
</div>
<Breadcrumbs isLoading={loader === "init-loader"}>
<CommonProjectBreadcrumbs
workspaceSlug={workspaceSlug?.toString() ?? ""}
projectId={currentProjectDetails?.id?.toString() ?? ""}
featureKey={EProjectFeatureKey.PAGES}
isLast
/>
</Breadcrumbs>
</Header.LeftItem>
{canCurrentUserCreatePage ? (
<Header.RightItem>

View file

@ -13,6 +13,7 @@ import {
EViewAccess,
EUserPermissions,
EUserPermissionsLevel,
EProjectFeatureKey,
} from "@plane/constants";
// types
import {
@ -22,10 +23,10 @@ import {
IIssueFilterOptions,
} from "@plane/types";
// ui
import { Breadcrumbs, Button, Tooltip, Header, CustomSearchSelect } from "@plane/ui";
import { Breadcrumbs, Button, Tooltip, Header, BreadcrumbNavigationSearchDropdown } from "@plane/ui";
// components
import { isIssueFilterActive } from "@plane/utils";
import { BreadcrumbLink, SwitcherLabel } from "@/components/common";
import { SwitcherIcon, SwitcherLabel } from "@/components/common";
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "@/components/issues";
// constants
import { ViewQuickActions } from "@/components/views";
@ -44,7 +45,7 @@ import {
} from "@/hooks/store";
// plane web
import { useAppRouter } from "@/hooks/use-app-router";
import { ProjectBreadcrumb } from "@/plane-web/components/breadcrumbs";
import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs";
export const ProjectViewIssuesHeader: React.FC = observer(() => {
// refs
@ -164,27 +165,27 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
<Header>
<Header.LeftItem>
<Breadcrumbs isLoading={loader === "init-loader"}>
<ProjectBreadcrumb />
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<BreadcrumbLink
href={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/views`}
label="Views"
icon={<Layers className="h-4 w-4 text-custom-text-300" />}
/>
}
<CommonProjectBreadcrumbs
workspaceSlug={workspaceSlug?.toString() ?? ""}
projectId={projectId?.toString() ?? ""}
featureKey={EProjectFeatureKey.VIEWS}
/>
<Breadcrumbs.BreadcrumbItem
type="component"
<Breadcrumbs.Item
component={
<CustomSearchSelect
options={switcherOptions}
value={viewId}
label={<SwitcherLabel logo_props={viewDetails.logo_props} name={viewDetails.name} LabelIcon={Layers} />}
<BreadcrumbNavigationSearchDropdown
selectedItem={viewId?.toString() ?? ""}
navigationItems={switcherOptions}
onChange={(value: string) => {
router.push(`/${workspaceSlug}/projects/${projectId}/views/${value}`);
}}
title={viewDetails?.name}
icon={
<Breadcrumbs.Icon>
<SwitcherIcon logo_props={viewDetails.logo_props} LabelIcon={Layers} size={16} />
</Breadcrumbs.Icon>
}
isLast
/>
}
/>

View file

@ -1,18 +1,19 @@
"use client";
import { observer } from "mobx-react";
import { Layers } from "lucide-react";
import { useParams } from "next/navigation";
// ui
import { EProjectFeatureKey } from "@plane/constants";
import { Breadcrumbs, Button, Header } from "@plane/ui";
// components
import { BreadcrumbLink } from "@/components/common";
import { ViewListHeader } from "@/components/views";
// hooks
import { useCommandPalette, useProject } from "@/hooks/store";
// plane web
import { ProjectBreadcrumb } from "@/plane-web/components/breadcrumbs";
import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs";
export const ProjectViewsHeader = observer(() => {
const { workspaceSlug, projectId } = useParams() as { workspaceSlug: string; projectId: string };
// store hooks
const { toggleCreateViewModal } = useCommandPalette();
const { loader } = useProject();
@ -22,10 +23,11 @@ export const ProjectViewsHeader = observer(() => {
<Header>
<Header.LeftItem>
<Breadcrumbs isLoading={loader === "init-loader"}>
<ProjectBreadcrumb />
<Breadcrumbs.BreadcrumbItem
type="text"
link={<BreadcrumbLink label="Views" icon={<Layers className="h-4 w-4 text-custom-text-300" />} />}
<CommonProjectBreadcrumbs
workspaceSlug={workspaceSlug?.toString() ?? ""}
projectId={projectId?.toString() ?? ""}
featureKey={EProjectFeatureKey.VIEWS}
isLast
/>
</Breadcrumbs>
</Header.LeftItem>