fix: project layout added and theming fixes (#2455)

* fix: project layout added and theme fixes

* feat: input color picker component added to ui package

* fix: layout fixes

* fix: conflicts and build issues resolved

* fix: layout headers fixes
This commit is contained in:
sriram veeraghanta
2023-10-17 12:46:38 +05:30
committed by GitHub
parent e496cec49f
commit 98b1a078de
30 changed files with 891 additions and 699 deletions

View File

@@ -0,0 +1,56 @@
import { FC } from "react";
import { useRouter } from "next/router";
import { ArrowLeft, Plus } from "lucide-react";
// components
import { Breadcrumbs, BreadcrumbItem } from "components/breadcrumbs";
// ui
import { Button } from "@plane/ui";
// helpers
import { truncateText } from "helpers/string.helper";
export interface ICyclesHeader {
name: string | undefined;
}
export const CyclesHeader: FC<ICyclesHeader> = (props) => {
const { name } = props;
// router
const router = useRouter();
const { workspaceSlug } = router.query;
return (
<div
className={`relative flex w-full flex-shrink-0 flex-row z-10 items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4`}
>
<div className="flex items-center gap-2 flex-grow w-full whitespace-nowrap overflow-ellipsis">
<div className="block md:hidden">
<button
type="button"
className="grid h-8 w-8 place-items-center rounded border border-custom-border-200"
onClick={() => router.back()}
>
<ArrowLeft fontSize={14} strokeWidth={2} />
</button>
</div>
<div>
<Breadcrumbs>
<BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} />
<BreadcrumbItem title={`${truncateText(name ?? "Project", 32)} Cycles`} />
</Breadcrumbs>
</div>
</div>
<div className="flex items-center gap-3">
<Button
variant="primary"
prependIcon={<Plus />}
onClick={() => {
const e = new KeyboardEvent("keydown", { key: "q" });
document.dispatchEvent(e);
}}
>
Add Cycle
</Button>
</div>
</div>
);
};

View File

@@ -8,3 +8,6 @@ export * from "./project-views";
export * from "./workspace-analytics";
export * from "./workspace-dashboard";
export * from "./projects";
export * from "./profile-preferences";
export * from "./cycles";
export * from "./modules";

View File

@@ -0,0 +1,87 @@
import { Dispatch, FC, SetStateAction } from "react";
import { useRouter } from "next/router";
import { ArrowLeft, Plus } from "lucide-react";
// components
import { Breadcrumbs, BreadcrumbItem } from "components/breadcrumbs";
// ui
import { Button, Tooltip } from "@plane/ui";
import { Icon } from "components/ui";
// helper
import { replaceUnderscoreIfSnakeCase, truncateText } from "helpers/string.helper";
export interface IModulesHeader {
name: string | undefined;
modulesView: string;
setModulesView: Dispatch<SetStateAction<"grid" | "gantt_chart">>;
}
const moduleViewOptions: { type: "grid" | "gantt_chart"; icon: any }[] = [
{
type: "gantt_chart",
icon: "view_timeline",
},
{
type: "grid",
icon: "table_rows",
},
];
export const ModulesHeader: FC<IModulesHeader> = (props) => {
const { name, modulesView, setModulesView } = props;
// router
const router = useRouter();
const { workspaceSlug } = router.query;
return (
<div
className={`relative flex w-full flex-shrink-0 flex-row z-10 items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4`}
>
<div className="flex items-center gap-2 flex-grow w-full whitespace-nowrap overflow-ellipsis">
<div className="block md:hidden">
<button
type="button"
className="grid h-8 w-8 place-items-center rounded border border-custom-border-200"
onClick={() => router.back()}
>
<ArrowLeft fontSize={14} strokeWidth={2} />
</button>
</div>
<div>
<Breadcrumbs>
<BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} />
<BreadcrumbItem title={`${truncateText(name ?? "Project", 32)} Cycles`} />
</Breadcrumbs>
</div>
</div>
<div className="flex items-center gap-2">
{moduleViewOptions.map((option) => (
<Tooltip
key={option.type}
tooltipContent={<span className="capitalize">{replaceUnderscoreIfSnakeCase(option.type)} Layout</span>}
position="bottom"
>
<button
type="button"
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none hover:bg-custom-sidebar-background-80 duration-300 ${
modulesView === option.type ? "bg-custom-sidebar-background-80" : "text-custom-sidebar-text-200"
}`}
onClick={() => setModulesView(option.type)}
>
<Icon iconName={option.icon} className={`!text-base ${option.type === "grid" ? "rotate-90" : ""}`} />
</button>
</Tooltip>
))}
<Button
variant="primary"
prependIcon={<Plus />}
onClick={() => {
const e = new KeyboardEvent("keydown", { key: "m" });
document.dispatchEvent(e);
}}
>
Add Module
</Button>
</div>
</div>
);
};

View File

@@ -0,0 +1,31 @@
import { useRouter } from "next/router";
import { ArrowLeft } from "lucide-react";
// components
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
export const ProfilePreferencesHeader = () => {
const router = useRouter();
return (
<div
className={`relative flex w-full flex-shrink-0 flex-row z-10 items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4`}
>
<div className="flex items-center gap-2 flex-grow w-full whitespace-nowrap overflow-ellipsis">
<div className="block md:hidden">
<button
type="button"
className="grid h-8 w-8 place-items-center rounded border border-custom-border-200"
onClick={() => router.back()}
>
<ArrowLeft fontSize={14} strokeWidth={2} />
</button>
</div>
<div>
<Breadcrumbs>
<BreadcrumbItem title="My Profile Preferences" />
</Breadcrumbs>
</div>
</div>
</div>
);
};

View File

@@ -1,23 +1,24 @@
import { useCallback, useState } from "react";
import { useCallback, useState, FC } from "react";
import Link from "next/link";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
// mobx store
import { ArrowLeft, Plus } from "lucide-react";
// hooks
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
import { ProjectAnalyticsModal } from "components/analytics";
// ui
import { Button } from "@plane/ui";
// icons
import { Plus } from "lucide-react";
import { Breadcrumbs, BreadcrumbItem } from "components/breadcrumbs";
// types
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "types";
// constants
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
// helper
import { truncateText } from "helpers/string.helper";
export const ProjectIssuesHeader: React.FC = observer(() => {
export const ProjectIssuesHeader: FC = observer(() => {
const [analyticsModal, setAnalyticsModal] = useState(false);
const router = useRouter();
@@ -100,64 +101,85 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
onClose={() => setAnalyticsModal(false)}
projectDetails={projectDetails ?? undefined}
/>
<div className="flex items-center gap-2">
<LayoutSelection
layouts={["list", "kanban", "calendar", "spreadsheet", "gantt_chart"]}
onChange={(layout) => handleLayoutChange(layout)}
selectedLayout={activeLayout}
/>
<FiltersDropdown title="Filters">
<FilterSelection
filters={issueFilterStore.userFilters}
handleFiltersUpdate={handleFiltersUpdate}
layoutDisplayFiltersOptions={
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined
}
labels={projectStore.labels?.[projectId?.toString() ?? ""] ?? undefined}
members={projectStore.members?.[projectId?.toString() ?? ""]?.map((m) => m.member)}
states={projectStore.states?.[projectId?.toString() ?? ""] ?? undefined}
<div
className={`relative flex w-full flex-shrink-0 flex-row z-10 items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4`}
>
<div className="flex items-center gap-2 flex-grow w-full whitespace-nowrap overflow-ellipsis">
<div className="block md:hidden">
<button
type="button"
className="grid h-8 w-8 place-items-center rounded border border-custom-border-200"
onClick={() => router.back()}
>
<ArrowLeft fontSize={14} strokeWidth={2} />
</button>
</div>
<div>
<Breadcrumbs>
<BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} />
<BreadcrumbItem title={`${truncateText(projectDetails?.name ?? "Project", 32)} Issues`} />
</Breadcrumbs>
</div>
</div>
<div className="flex items-center gap-3">
<LayoutSelection
layouts={["list", "kanban", "calendar", "spreadsheet", "gantt_chart"]}
onChange={(layout) => handleLayoutChange(layout)}
selectedLayout={activeLayout}
/>
</FiltersDropdown>
<FiltersDropdown title="View">
<DisplayFiltersSelection
displayFilters={issueFilterStore.userDisplayFilters}
displayProperties={issueFilterStore.userDisplayProperties}
handleDisplayFiltersUpdate={handleDisplayFiltersUpdate}
handleDisplayPropertiesUpdate={handleDisplayPropertiesUpdate}
layoutDisplayFiltersOptions={
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined
}
/>
</FiltersDropdown>
{projectId && inboxStore.isInboxEnabled(projectId.toString()) && (
<Link href={`/${workspaceSlug}/projects/${projectId}/inbox/${inboxStore.getInboxId(projectId.toString())}`}>
<a>
<Button variant="neutral-primary" size="sm" className="relative">
Inbox
{inboxDetails && (
<span className="absolute -top-1.5 -right-1.5 h-4 w-4 rounded-full text-custom-text-100 bg-custom-sidebar-background-80 border border-custom-sidebar-border-200">
{inboxDetails.pending_issue_count}
</span>
)}
</Button>
</a>
</Link>
)}
<Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm">
Analytics
</Button>
<Button
onClick={() => {
const e = new KeyboardEvent("keydown", {
key: "c",
});
document.dispatchEvent(e);
}}
size="sm"
prependIcon={<Plus />}
>
Add Issue
</Button>
<FiltersDropdown title="Filters">
<FilterSelection
filters={issueFilterStore.userFilters}
handleFiltersUpdate={handleFiltersUpdate}
layoutDisplayFiltersOptions={
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined
}
labels={projectStore.labels?.[projectId?.toString() ?? ""] ?? undefined}
members={projectStore.members?.[projectId?.toString() ?? ""]?.map((m) => m.member)}
states={projectStore.states?.[projectId?.toString() ?? ""] ?? undefined}
/>
</FiltersDropdown>
<FiltersDropdown title="View">
<DisplayFiltersSelection
displayFilters={issueFilterStore.userDisplayFilters}
displayProperties={issueFilterStore.userDisplayProperties}
handleDisplayFiltersUpdate={handleDisplayFiltersUpdate}
handleDisplayPropertiesUpdate={handleDisplayPropertiesUpdate}
layoutDisplayFiltersOptions={
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined
}
/>
</FiltersDropdown>
{projectId && inboxStore.isInboxEnabled(projectId.toString()) && (
<Link href={`/${workspaceSlug}/projects/${projectId}/inbox/${inboxStore.getInboxId(projectId.toString())}`}>
<a>
<Button variant="neutral-primary" size="sm" className="relative">
Inbox
{inboxDetails && (
<span className="absolute -top-1.5 -right-1.5 h-4 w-4 rounded-full text-custom-text-100 bg-custom-sidebar-background-80 border border-custom-sidebar-border-200">
{inboxDetails.pending_issue_count}
</span>
)}
</Button>
</a>
</Link>
)}
<Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm">
Analytics
</Button>
<Button
onClick={() => {
const e = new KeyboardEvent("keydown", {
key: "c",
});
document.dispatchEvent(e);
}}
size="sm"
prependIcon={<Plus />}
>
Add Issue
</Button>
</div>
</div>
</>
);

View File

@@ -1,30 +1,66 @@
import { useState } from "react";
import { FC, useState } from "react";
import { useRouter } from "next/router";
// icons
import { ArrowLeft, Plus } from "lucide-react";
// components
import { CreateUpdateProjectViewModal } from "components/views";
// components
import { Breadcrumbs, BreadcrumbItem } from "components/breadcrumbs";
// ui
import { PrimaryButton } from "components/ui";
// icons
import { Plus } from "lucide-react";
// helpers
import { truncateText } from "helpers/string.helper";
export const ProjectViewsHeader = () => {
interface IProjectViewsHeader {
title: string | undefined;
}
export const ProjectViewsHeader: FC<IProjectViewsHeader> = (props) => {
const { title } = props;
// router
const router = useRouter();
const { workspaceSlug } = router.query;
// states
const [createViewModal, setCreateViewModal] = useState(false);
return (
<>
<CreateUpdateProjectViewModal isOpen={createViewModal} onClose={() => setCreateViewModal(false)} />
<div>
<PrimaryButton
type="button"
className="flex items-center gap-2"
onClick={() => {
const e = new KeyboardEvent("keydown", { key: "v" });
document.dispatchEvent(e);
}}
>
<Plus size={14} strokeWidth={2} />
Create View
</PrimaryButton>
<div
className={`relative flex w-full flex-shrink-0 flex-row z-10 items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4`}
>
<div className="flex items-center gap-2 flex-grow w-full whitespace-nowrap overflow-ellipsis">
<div className="block md:hidden">
<button
type="button"
className="grid h-8 w-8 place-items-center rounded border border-custom-border-200"
onClick={() => router.back()}
>
<ArrowLeft fontSize={14} strokeWidth={2} />
</button>
</div>
<div>
<Breadcrumbs>
<BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} />
<BreadcrumbItem title={`${truncateText(title ?? "Project", 32)} Cycles`} />
</Breadcrumbs>
</div>
</div>
<div className="flex items-center gap-2">
<div>
<PrimaryButton
type="button"
className="flex items-center gap-2"
onClick={() => {
const e = new KeyboardEvent("keydown", { key: "v" });
document.dispatchEvent(e);
}}
>
<Plus size={14} strokeWidth={2} />
Create View
</PrimaryButton>
</div>
</div>
</div>
</>
);