[WEB-5092] feat: app sidebar enhancements (#7946)
* chore: project sidebar and settings sidebar improvement * chore: navigationitem ui improvement * chore: workspace level new icon added * chore: propel icon migration * chore: code refactor * chore: dashboard icon updated * chore: code refactor * chore: icons updated * chore: code refactor * chore: code refactor * chore: scroll area component refactor * chore: sidebar enhancements * chore: add and archive icon updated * chore: code refactor * chore: code refactor * chore: code refactor
This commit is contained in:
parent
9cfde896b3
commit
a3019ebd46
12 changed files with 93 additions and 43 deletions
|
|
@ -1,8 +1,8 @@
|
|||
import { observer } from "mobx-react";
|
||||
import { Search } from "lucide-react";
|
||||
// plane imports
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
// hooks
|
||||
import { SidebarSearchButton } from "@/components/sidebar/search-button";
|
||||
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
||||
|
||||
export const AppSearch = observer(() => {
|
||||
|
|
@ -14,11 +14,10 @@ export const AppSearch = observer(() => {
|
|||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="flex-shrink-0 size-8 aspect-square grid place-items-center rounded hover:bg-custom-sidebar-background-90 outline-none border-[0.5px] border-custom-sidebar-border-300"
|
||||
onClick={() => toggleCommandPaletteModal(true)}
|
||||
aria-label={t("aria_labels.projects_sidebar.open_command_palette")}
|
||||
>
|
||||
<Search className="size-4 text-custom-sidebar-text-300" />
|
||||
<SidebarSearchButton isActive={false} />
|
||||
</button>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -60,11 +60,11 @@ export const NavItemChildren = observer((props: { projectId: string }) => {
|
|||
className={cn(
|
||||
"cursor-pointer relative group w-full flex items-center justify-between gap-1.5 rounded p-1 px-1.5 outline-none",
|
||||
{
|
||||
"text-custom-primary-200 bg-custom-primary-100/10": isActive,
|
||||
"text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-90 active:bg-custom-sidebar-background-90":
|
||||
"text-custom-text-200 bg-custom-background-80/75": isActive,
|
||||
"text-custom-sidebar-text-300 hover:bg-custom-sidebar-background-90 active:bg-custom-sidebar-background-90":
|
||||
!isActive,
|
||||
},
|
||||
"text-sm font-medium"
|
||||
"text-xs font-medium"
|
||||
)}
|
||||
>
|
||||
{t(getProjectSettingsPageLabelI18nKey(link.key, link.i18n_label))}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export const SettingsSidebarHeader = observer((props: { customHeader?: React.Rea
|
|||
return customHeader
|
||||
? customHeader
|
||||
: currentWorkspace && (
|
||||
<div className="flex w-full gap-3 items-center justify-between pr-2">
|
||||
<div className="flex w-full gap-3 items-center justify-between px-2">
|
||||
<div className="flex w-full gap-3 items-center overflow-hidden">
|
||||
<WorkspaceLogo
|
||||
logo={currentWorkspace.logo_url ?? ""}
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ const SettingsSidebarNavItem = observer((props: TSettingsSidebarNavItemProps) =>
|
|||
"flex w-full items-center px-2 py-1.5 rounded text-custom-text-200 justify-between",
|
||||
"hover:bg-custom-primary-100/10",
|
||||
{
|
||||
"text-custom-primary-200 bg-custom-primary-100/10": typeof isActive === "function" ? isActive(setting) : isActive,
|
||||
"hover:bg-custom-sidebar-background-90 active:bg-custom-sidebar-background-90":
|
||||
"text-custom-text-200 bg-custom-background-80/75": typeof isActive === "function" ? isActive(setting) : isActive,
|
||||
"text-custom-sidebar-text-300 hover:bg-custom-sidebar-background-90 active:bg-custom-sidebar-background-90":
|
||||
typeof isActive === "function" ? !isActive(setting) : !isActive,
|
||||
}
|
||||
);
|
||||
|
|
@ -83,14 +83,9 @@ const SettingsSidebarNavItem = observer((props: TSettingsSidebarNavItemProps) =>
|
|||
</Disclosure.Button>
|
||||
{/* Nested Navigation */}
|
||||
{isExpanded && (
|
||||
<Disclosure.Panel
|
||||
as="div"
|
||||
className={cn("flex flex-col gap-0.5", {
|
||||
"space-y-0 ml-0": isExpanded,
|
||||
})}
|
||||
static
|
||||
>
|
||||
<div className="ml-4 border-l border-custom-border-200 pl-2 my-0.5">{renderChildren?.(setting.key)}</div>
|
||||
<Disclosure.Panel as="div" className={cn("relative flex flex-col gap-0.5 mt-1 pl-6 mb-1.5")} static>
|
||||
<div className="absolute left-[15px] top-0 bottom-1 w-[1px] bg-custom-border-200" />
|
||||
{renderChildren?.(setting.key)}
|
||||
</Disclosure.Panel>
|
||||
)}
|
||||
</Disclosure>
|
||||
|
|
|
|||
25
apps/web/core/components/sidebar/add-button.tsx
Normal file
25
apps/web/core/components/sidebar/add-button.tsx
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import React, { FC } from "react";
|
||||
import { cn } from "@plane/utils";
|
||||
|
||||
type Props = React.ComponentProps<"button"> & {
|
||||
label: React.ReactNode;
|
||||
onClick: () => void;
|
||||
};
|
||||
|
||||
export const SidebarAddButton: FC<Props> = (props) => {
|
||||
const { label, onClick, disabled, ...rest } = props;
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
"flex-grow text-custom-text-300 text-sm font-medium border-[0.5px] border-custom-sidebar-border-300 text-left rounded-md shadow-sm h-8 px-2 flex items-center gap-1.5",
|
||||
!disabled && "hover:bg-custom-sidebar-background-90"
|
||||
)}
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
{...rest}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
27
apps/web/core/components/sidebar/search-button.tsx
Normal file
27
apps/web/core/components/sidebar/search-button.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import React, { FC } from "react";
|
||||
import { Search } from "lucide-react";
|
||||
import { cn } from "@plane/utils";
|
||||
|
||||
type Props = {
|
||||
isActive?: boolean;
|
||||
};
|
||||
|
||||
export const SidebarSearchButton: FC<Props> = (props) => {
|
||||
const { isActive } = props;
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"flex-shrink-0 size-8 aspect-square grid place-items-center rounded-md shadow-sm hover:bg-custom-sidebar-background-90 outline-none border-[0.5px] border-custom-sidebar-border-300",
|
||||
{
|
||||
"bg-custom-primary-100/10 hover:bg-custom-primary-100/10 border-custom-primary-200": isActive,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<Search
|
||||
className={cn("size-4 text-custom-sidebar-text-300", {
|
||||
"text-custom-primary-200": isActive,
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -17,8 +17,8 @@ export const SidebarNavItem: FC<TSidebarNavItem> = (props) => {
|
|||
className={cn(
|
||||
"cursor-pointer relative group w-full flex items-center justify-between gap-1.5 rounded px-2 py-1 outline-none",
|
||||
{
|
||||
"text-custom-primary-200 bg-custom-primary-100/10": isActive,
|
||||
"text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-90 active:bg-custom-sidebar-background-90":
|
||||
"text-custom-text-200 bg-custom-background-80/75": isActive,
|
||||
"text-custom-sidebar-text-300 hover:bg-custom-sidebar-background-90 active:bg-custom-sidebar-background-90":
|
||||
!isActive,
|
||||
},
|
||||
className
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { useEffect, useRef } from "react";
|
|||
import { observer } from "mobx-react";
|
||||
// plane helpers
|
||||
import { useOutsideClickDetector } from "@plane/hooks";
|
||||
import { ScrollArea } from "@plane/propel/scrollarea";
|
||||
// components
|
||||
import { AppSidebarToggleButton } from "@/components/sidebar/sidebar-toggle-button";
|
||||
import { SidebarDropdown } from "@/components/workspace/sidebar/dropdown";
|
||||
|
|
@ -57,9 +58,16 @@ export const SidebarWrapper: FC<TSidebarWrapperProps> = observer((props) => {
|
|||
{/* Quick actions */}
|
||||
{quickActions}
|
||||
</div>
|
||||
<div className="flex flex-col gap-3 overflow-x-hidden scrollbar-sm h-full w-full overflow-y-auto vertical-scrollbar px-3 pt-3 pb-0.5">
|
||||
|
||||
<ScrollArea
|
||||
orientation="vertical"
|
||||
scrollType="hover"
|
||||
size="sm"
|
||||
rootClassName="size-full overflow-x-hidden overflow-y-auto"
|
||||
viewportClassName="flex flex-col gap-3 overflow-x-hidden h-full w-full overflow-y-auto px-3 pt-3 pb-0.5"
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
{/* Help Section */}
|
||||
<div className="flex items-center justify-between p-3 border-t border-custom-border-200 bg-custom-sidebar-background-100 h-12">
|
||||
<WorkspaceEditionBadge />
|
||||
|
|
|
|||
|
|
@ -17,14 +17,14 @@ export const WorkspaceLogo = observer((props: Props) => {
|
|||
<div
|
||||
className={cn(
|
||||
`relative grid h-6 w-6 flex-shrink-0 place-items-center uppercase ${
|
||||
!props.logo && "rounded bg-[#026292] text-white"
|
||||
!props.logo && "rounded-md bg-[#026292] text-white"
|
||||
} ${props.classNames ? props.classNames : ""}`
|
||||
)}
|
||||
>
|
||||
{props.logo && props.logo !== "" ? (
|
||||
<img
|
||||
src={getFileURL(props.logo)}
|
||||
className="absolute left-0 top-0 h-full w-full rounded object-cover"
|
||||
className="absolute left-0 top-0 h-full w-full rounded-md object-cover"
|
||||
alt={t("aria_labels.projects_sidebar.workspace_logo")}
|
||||
/>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ export const ProjectNavigation: FC<TProjectItemsProps> = observer((props) => {
|
|||
|
||||
return (
|
||||
<Link key={item.key} href={item.href} onClick={handleProjectClick}>
|
||||
<SidebarNavItem className="pl-[18px]" isActive={!!isActive(item)}>
|
||||
<SidebarNavItem isActive={!!isActive(item)}>
|
||||
<div className="flex items-center gap-1.5 py-[1px]">
|
||||
<item.icon className={`flex-shrink-0 size-4 ${item.name === "Intake" ? "stroke-1" : "stroke-[1.5]"}`} />
|
||||
<span className="text-xs font-medium">{t(item.i18n_key)}</span>
|
||||
|
|
|
|||
|
|
@ -402,7 +402,8 @@ export const SidebarProjectsListItem: React.FC<Props> = observer((props) => {
|
|||
leaveTo="transform scale-95 opacity-0"
|
||||
>
|
||||
{isProjectListOpen && (
|
||||
<Disclosure.Panel as="div" className="flex flex-col gap-0.5 mt-1">
|
||||
<Disclosure.Panel as="div" className="relative flex flex-col gap-0.5 mt-1 pl-6 mb-1.5">
|
||||
<div className="absolute left-[15px] top-0 bottom-1 w-[1px] bg-custom-border-200" />
|
||||
<ProjectNavigationRoot workspaceSlug={workspaceSlug.toString()} projectId={projectId.toString()} />
|
||||
</Disclosure.Panel>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import type { TIssue } from "@plane/types";
|
|||
import { cn } from "@plane/utils";
|
||||
// components
|
||||
import { CreateUpdateIssueModal } from "@/components/issues/issue-modal/modal";
|
||||
import { SidebarAddButton } from "@/components/sidebar/add-button";
|
||||
// hooks
|
||||
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
|
|
@ -73,26 +74,20 @@ export const SidebarQuickActions = observer(() => {
|
|||
fetchIssueDetails={false}
|
||||
isDraft
|
||||
/>
|
||||
<div className={cn("flex items-center justify-between gap-1 cursor-pointer", {})}>
|
||||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
"relative flex flex-shrink-0 flex-grow items-center gap-2 h-8 text-custom-sidebar-text-300 rounded outline-none hover:bg-custom-sidebar-background-90 px-3 border-[0.5px] border-custom-sidebar-border-300",
|
||||
{
|
||||
"cursor-not-allowed opacity-50 ": disabled,
|
||||
}
|
||||
)}
|
||||
data-ph-element={SIDEBAR_TRACKER_ELEMENTS.CREATE_WORK_ITEM_BUTTON}
|
||||
onClick={() => {
|
||||
toggleCreateIssueModal(true);
|
||||
}}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
disabled={disabled}
|
||||
>
|
||||
<div className="flex items-center justify-between gap-2 cursor-pointer">
|
||||
<SidebarAddButton
|
||||
label={
|
||||
<>
|
||||
<AddIcon className="size-4" />
|
||||
<span className="text-sm font-medium truncate max-w-[145px]">{t("sidebar.new_work_item")}</span>
|
||||
</button>
|
||||
</>
|
||||
}
|
||||
onClick={() => toggleCreateIssueModal(true)}
|
||||
disabled={disabled}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
data-ph-element={SIDEBAR_TRACKER_ELEMENTS.CREATE_WORK_ITEM_BUTTON}
|
||||
/>
|
||||
<AppSearch />
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue