From e29edfc02b268855b2fad746e3c6e0dd590ef8b6 Mon Sep 17 00:00:00 2001 From: Ramesh Kumar Chandra <31303617+rameshkumarchandra@users.noreply.github.com> Date: Mon, 12 Feb 2024 17:01:24 +0530 Subject: [PATCH] style: issue detail responsiveness (#3625) --- .../headers/project-issue-details.tsx | 12 +++++++++-- .../actions/helpers/activity-block.tsx | 2 +- web/components/issues/issue-detail/root.tsx | 16 +++++++++------ .../issues/issue-detail/sidebar.tsx | 13 ++++++------ .../issues/issue-detail/subscription.tsx | 14 ++++++++++--- .../spreadsheet/columns/header-column.tsx | 19 +++++++++--------- .../projects/[projectId]/issues/[issueId].tsx | 20 +++++++++++++++++-- web/store/application/theme.store.ts | 16 ++++++++++++++- 8 files changed, 80 insertions(+), 32 deletions(-) diff --git a/web/components/headers/project-issue-details.tsx b/web/components/headers/project-issue-details.tsx index 8d3a22682..3732f2598 100644 --- a/web/components/headers/project-issue-details.tsx +++ b/web/components/headers/project-issue-details.tsx @@ -3,7 +3,7 @@ import useSWR from "swr"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; // hooks -import { useProject } from "hooks/store"; +import { useApplication, useProject } from "hooks/store"; // ui import { Breadcrumbs, LayersIcon } from "@plane/ui"; // helpers @@ -15,6 +15,8 @@ import { ISSUE_DETAILS } from "constants/fetch-keys"; // components import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle"; import { BreadcrumbLink } from "components/common"; +import { PanelRight } from "lucide-react"; +import { cn } from "helpers/common.helper"; // services const issueService = new IssueService(); @@ -25,6 +27,7 @@ export const ProjectIssueDetailsHeader: FC = observer(() => { const { workspaceSlug, projectId, issueId } = router.query; // store hooks const { currentProjectDetails, getProjectById } = useProject(); + const { theme: themeStore } = useApplication(); const { data: issueDetails } = useSWR( workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId as string) : null, @@ -33,12 +36,14 @@ export const ProjectIssueDetailsHeader: FC = observer(() => { : null ); + const isSidebarCollapsed = themeStore.issueDetailSidebarCollapsed; + return (
- + {
+
); }); diff --git a/web/components/issues/issue-detail/issue-activity/activity/actions/helpers/activity-block.tsx b/web/components/issues/issue-detail/issue-activity/activity/actions/helpers/activity-block.tsx index eabe5d518..c7b75340b 100644 --- a/web/components/issues/issue-detail/issue-activity/activity/actions/helpers/activity-block.tsx +++ b/web/components/issues/issue-detail/issue-activity/activity/actions/helpers/activity-block.tsx @@ -33,7 +33,7 @@ export const IssueActivityBlockComponent: FC = (pr }`} >
-
+
{icon ? icon : }
diff --git a/web/components/issues/issue-detail/root.tsx b/web/components/issues/issue-detail/root.tsx index 2e0303a8e..902ba7c25 100644 --- a/web/components/issues/issue-detail/root.tsx +++ b/web/components/issues/issue-detail/root.tsx @@ -9,13 +9,14 @@ import { EmptyState } from "components/common"; // images import emptyIssue from "public/empty-state/issue.svg"; // hooks -import { useEventTracker, useIssueDetail, useIssues, useUser } from "hooks/store"; +import { useApplication, useEventTracker, useIssueDetail, useIssues, useUser } from "hooks/store"; import useToast from "hooks/use-toast"; // types import { TIssue } from "@plane/types"; // constants import { EUserProjectRoles } from "constants/project"; import { EIssuesStoreType } from "constants/issue"; +import { observer } from "mobx-react"; export type TIssueOperations = { fetch: (workspaceSlug: string, projectId: string, issueId: string) => Promise; @@ -51,7 +52,7 @@ export type TIssueDetailRoot = { is_archived?: boolean; }; -export const IssueDetailRoot: FC = (props) => { +export const IssueDetailRoot: FC = observer((props) => { const { workspaceSlug, projectId, issueId, is_archived = false } = props; // router const router = useRouter(); @@ -75,6 +76,7 @@ export const IssueDetailRoot: FC = (props) => { const { membership: { currentProjectRole }, } = useUser(); + const { theme: themeStore } = useApplication(); const issueOperations: TIssueOperations = useMemo( () => ({ @@ -346,8 +348,8 @@ export const IssueDetailRoot: FC = (props) => { }} /> ) : ( -
-
+
+
= (props) => { is_editable={!is_archived && is_editable} />
-
+
= (props) => { ); -}; +}); diff --git a/web/components/issues/issue-detail/sidebar.tsx b/web/components/issues/issue-detail/sidebar.tsx index 668d3538f..c78bbe942 100644 --- a/web/components/issues/issue-detail/sidebar.tsx +++ b/web/components/issues/issue-detail/sidebar.tsx @@ -187,9 +187,8 @@ export const IssueDetailsSidebar: React.FC = observer((props) => { buttonVariant={issue?.assignee_ids?.length > 1 ? "transparent-without-text" : "transparent-with-text"} className="w-3/5 flex-grow group" buttonContainerClassName="w-full text-left" - buttonClassName={`text-sm justify-between ${ - issue?.assignee_ids.length > 0 ? "" : "text-custom-text-400" - }`} + buttonClassName={`text-sm justify-between ${issue?.assignee_ids.length > 0 ? "" : "text-custom-text-400" + }`} hideIcon={issue.assignee_ids?.length === 0} dropdownArrow dropdownArrowClassName="h-3.5 w-3.5 hidden group-hover:inline" @@ -233,8 +232,8 @@ export const IssueDetailsSidebar: React.FC = observer((props) => { buttonClassName={`text-sm ${issue?.start_date ? "" : "text-custom-text-400"}`} hideIcon clearIconClassName="h-3 w-3 hidden group-hover:inline" - // TODO: add this logic - // showPlaceholderIcon + // TODO: add this logic + // showPlaceholderIcon />
@@ -259,8 +258,8 @@ export const IssueDetailsSidebar: React.FC = observer((props) => { buttonClassName={`text-sm ${issue?.target_date ? "" : "text-custom-text-400"}`} hideIcon clearIconClassName="h-3 w-3 hidden group-hover:inline" - // TODO: add this logic - // showPlaceholderIcon + // TODO: add this logic + // showPlaceholderIcon />
diff --git a/web/components/issues/issue-detail/subscription.tsx b/web/components/issues/issue-detail/subscription.tsx index b57e75bed..8d05140b3 100644 --- a/web/components/issues/issue-detail/subscription.tsx +++ b/web/components/issues/issue-detail/subscription.tsx @@ -1,5 +1,5 @@ import { FC, useState } from "react"; -import { Bell } from "lucide-react"; +import { Bell, BellOff } from "lucide-react"; import { observer } from "mobx-react-lite"; // UI import { Button } from "@plane/ui"; @@ -52,12 +52,20 @@ export const IssueSubscription: FC = observer((props) => {
); diff --git a/web/components/issues/issue-layouts/spreadsheet/columns/header-column.tsx b/web/components/issues/issue-layouts/spreadsheet/columns/header-column.tsx index dc9f8c7c6..95982ab25 100644 --- a/web/components/issues/issue-layouts/spreadsheet/columns/header-column.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/columns/header-column.tsx @@ -63,14 +63,14 @@ export const SpreadsheetHeaderColumn = (props: Props) => {
} placement="bottom-end" + closeOnSelect > handleOrderBy(propertyDetails.ascendingOrderKey, property)}>
@@ -84,11 +84,10 @@ export const SpreadsheetHeaderColumn = (props: Props) => { handleOrderBy(propertyDetails.descendingOrderKey, property)}>
diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx index 6be784368..64f43939e 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx @@ -1,4 +1,4 @@ -import React, { ReactElement } from "react"; +import React, { ReactElement, useEffect } from "react"; import { useRouter } from "next/router"; import useSWR from "swr"; import { observer } from "mobx-react-lite"; @@ -12,7 +12,7 @@ import { Loader } from "@plane/ui"; // types import { NextPageWithLayout } from "lib/types"; // fetch-keys -import { useIssueDetail } from "hooks/store"; +import { useApplication, useIssueDetail } from "hooks/store"; const IssueDetailsPage: NextPageWithLayout = observer(() => { // router @@ -23,6 +23,7 @@ const IssueDetailsPage: NextPageWithLayout = observer(() => { fetchIssue, issue: { getIssueById }, } = useIssueDetail(); + const { theme: themeStore } = useApplication(); const { isLoading } = useSWR( workspaceSlug && projectId && issueId ? `ISSUE_DETAIL_${workspaceSlug}_${projectId}_${issueId}` : null, @@ -34,6 +35,21 @@ const IssueDetailsPage: NextPageWithLayout = observer(() => { const issue = getIssueById(issueId?.toString() || "") || undefined; const issueLoader = !issue || isLoading ? true : false; + useEffect(() => { + const handleToggleIssueDetailSidebar = () => { + if (window && window.innerWidth < 768) { + themeStore.toggleIssueDetailSidebar(true); + } + if (window && themeStore.issueDetailSidebarCollapsed && window.innerWidth >= 768) { + themeStore.toggleIssueDetailSidebar(false); + } + }; + + window.addEventListener("resize", handleToggleIssueDetailSidebar); + handleToggleIssueDetailSidebar(); + return () => window.removeEventListener("resize", handleToggleIssueDetailSidebar); + }, [themeStore]); + return ( <> {issueLoader ? ( diff --git a/web/store/application/theme.store.ts b/web/store/application/theme.store.ts index f264c175d..505f3803c 100644 --- a/web/store/application/theme.store.ts +++ b/web/store/application/theme.store.ts @@ -9,11 +9,13 @@ export interface IThemeStore { sidebarCollapsed: boolean | undefined; profileSidebarCollapsed: boolean | undefined; workspaceAnalyticsSidebarCollapsed: boolean | undefined; + issueDetailSidebarCollapsed: boolean | undefined; // actions toggleSidebar: (collapsed?: boolean) => void; setTheme: (theme: any) => void; toggleProfileSidebar: (collapsed?: boolean) => void; toggleWorkspaceAnalyticsSidebar: (collapsed?: boolean) => void; + toggleIssueDetailSidebar: (collapsed?: boolean) => void; } export class ThemeStore implements IThemeStore { @@ -22,6 +24,7 @@ export class ThemeStore implements IThemeStore { theme: string | null = null; profileSidebarCollapsed: boolean | undefined = undefined; workspaceAnalyticsSidebarCollapsed: boolean | undefined = undefined; + issueDetailSidebarCollapsed: boolean | undefined = undefined; // root store rootStore; @@ -32,11 +35,13 @@ export class ThemeStore implements IThemeStore { theme: observable.ref, profileSidebarCollapsed: observable.ref, workspaceAnalyticsSidebarCollapsed: observable.ref, + issueDetailSidebarCollapsed: observable.ref, // action toggleSidebar: action, setTheme: action, toggleProfileSidebar: action, - toggleWorkspaceAnalyticsSidebar: action + toggleWorkspaceAnalyticsSidebar: action, + toggleIssueDetailSidebar: action, // computed }); // root store @@ -82,6 +87,15 @@ export class ThemeStore implements IThemeStore { localStorage.setItem("workspace_analytics_sidebar_collapsed", this.workspaceAnalyticsSidebarCollapsed.toString()); }; + toggleIssueDetailSidebar = (collapsed?: boolean) => { + if(collapsed === undefined) { + this.issueDetailSidebarCollapsed = !this.issueDetailSidebarCollapsed; + } else { + this.issueDetailSidebarCollapsed = collapsed; + } + localStorage.setItem("issue_detail_sidebar_collapsed", this.issueDetailSidebarCollapsed.toString()); + } + /** * Sets the user theme and applies it to the platform * @param _theme