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:
parent
e496cec49f
commit
98b1a078de
30 changed files with 891 additions and 699 deletions
|
|
@ -1,92 +1,82 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { useTheme } from "next-themes";
|
||||
// hooks
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import useToast from "hooks/use-toast";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
// components
|
||||
import { CustomThemeSelector, ThemeSwitch } from "components/core";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
import { ProfilePreferencesHeader } from "components/headers";
|
||||
// ui
|
||||
import { Spinner } from "@plane/ui";
|
||||
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
||||
// types
|
||||
import { ICustomTheme } from "types";
|
||||
// mobx react lite
|
||||
import { observer } from "mobx-react-lite";
|
||||
// mobx store
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
// constants
|
||||
import { I_THEME_OPTION, THEME_OPTIONS } from "constants/themes";
|
||||
|
||||
const ProfilePreferences = observer(() => {
|
||||
const { user: myProfile } = useUserAuth();
|
||||
|
||||
const store: any = useMobxStore();
|
||||
|
||||
// console.log("store", store?.theme?.theme);
|
||||
// console.log("theme", theme);
|
||||
|
||||
const [customThemeSelectorOptions, setCustomThemeSelectorOptions] = useState(false);
|
||||
|
||||
const [preLoadedData, setPreLoadedData] = useState<ICustomTheme | null>(null);
|
||||
const ProfilePreferencesPage = observer(() => {
|
||||
const { user: userStore } = useMobxStore();
|
||||
// states
|
||||
const [currentTheme, setCurrentTheme] = useState<I_THEME_OPTION | null>(null);
|
||||
// computed
|
||||
const userTheme = userStore.currentUser?.theme;
|
||||
// hooks
|
||||
const { setTheme } = useTheme();
|
||||
const { setToastAlert } = useToast();
|
||||
|
||||
useEffect(() => {
|
||||
if (store?.user && store?.theme?.theme === "custom") {
|
||||
const currentTheme = store?.user?.currentUserSettings?.theme;
|
||||
if (currentTheme.palette)
|
||||
setPreLoadedData({
|
||||
background: currentTheme.background !== "" ? currentTheme.background : "#0d101b",
|
||||
text: currentTheme.text !== "" ? currentTheme.text : "#c5c5c5",
|
||||
primary: currentTheme.primary !== "" ? currentTheme.primary : "#3f76ff",
|
||||
sidebarBackground: currentTheme.sidebarBackground !== "" ? currentTheme.sidebarBackground : "#0d101b",
|
||||
sidebarText: currentTheme.sidebarText !== "" ? currentTheme.sidebarText : "#c5c5c5",
|
||||
darkPalette: false,
|
||||
palette: currentTheme.palette !== ",,,," ? currentTheme.palette : "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5",
|
||||
theme: "custom",
|
||||
});
|
||||
setCustomThemeSelectorOptions(() => true);
|
||||
if (userTheme) {
|
||||
const userThemeOption = THEME_OPTIONS.find((t) => t.value === userTheme?.theme);
|
||||
if (userThemeOption) {
|
||||
setCurrentTheme(userThemeOption);
|
||||
}
|
||||
}
|
||||
}, [store, store?.theme?.theme]);
|
||||
}, [userTheme]);
|
||||
|
||||
const handleThemeChange = (themeOption: I_THEME_OPTION) => {
|
||||
setTheme(themeOption.value);
|
||||
userStore.updateCurrentUserTheme(themeOption.value).catch(() => {
|
||||
setToastAlert({
|
||||
title: "Failed to Update the theme",
|
||||
type: "error",
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<WorkspaceAuthorizationLayout
|
||||
breadcrumbs={
|
||||
<Breadcrumbs>
|
||||
<BreadcrumbItem title="My Profile Preferences" />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
>
|
||||
{myProfile ? (
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
<AppLayout header={<ProfilePreferencesHeader />}>
|
||||
<>
|
||||
{userStore.currentUser ? (
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
|
||||
<div className="pr-9 py-8 w-full overflow-y-auto">
|
||||
<div className="flex items-center py-3.5 border-b border-custom-border-200">
|
||||
<h3 className="text-xl font-medium">Preferences</h3>
|
||||
</div>
|
||||
<div className="grid grid-cols-12 gap-4 sm:gap-16 py-6">
|
||||
<div className="col-span-12 sm:col-span-6">
|
||||
<h4 className="text-lg font-semibold text-custom-text-100">Theme</h4>
|
||||
<p className="text-sm text-custom-text-200">Select or customize your interface color scheme.</p>
|
||||
<div className="pr-9 py-8 w-full overflow-y-auto">
|
||||
<div className="flex items-center py-3.5 border-b border-custom-border-200">
|
||||
<h3 className="text-xl font-medium">Preferences</h3>
|
||||
</div>
|
||||
<div className="col-span-12 sm:col-span-6">
|
||||
<ThemeSwitch
|
||||
setPreLoadedData={setPreLoadedData}
|
||||
customThemeSelectorOptions={customThemeSelectorOptions}
|
||||
setCustomThemeSelectorOptions={setCustomThemeSelectorOptions}
|
||||
/>
|
||||
<div className="grid grid-cols-12 gap-4 sm:gap-16 py-6">
|
||||
<div className="col-span-12 sm:col-span-6">
|
||||
<h4 className="text-lg font-semibold text-custom-text-100">Theme</h4>
|
||||
<p className="text-sm text-custom-text-200">Select or customize your interface color scheme.</p>
|
||||
</div>
|
||||
<div className="col-span-12 sm:col-span-6">
|
||||
<ThemeSwitch value={currentTheme} onChange={handleThemeChange} />
|
||||
</div>
|
||||
</div>
|
||||
{userTheme?.theme === "custom" && <CustomThemeSelector />}
|
||||
</div>
|
||||
{customThemeSelectorOptions && <CustomThemeSelector preLoadedData={preLoadedData} />}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid h-full w-full place-items-center px-4 sm:px-0">
|
||||
<Spinner />
|
||||
</div>
|
||||
)}
|
||||
</WorkspaceAuthorizationLayout>
|
||||
) : (
|
||||
<div className="grid h-full w-full place-items-center px-4 sm:px-0">
|
||||
<Spinner />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
</AppLayout>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProfilePreferences;
|
||||
export default ProfilePreferencesPage;
|
||||
|
|
|
|||
|
|
@ -2,25 +2,23 @@ import { Fragment, useCallback, useEffect, useState } from "react";
|
|||
import { useRouter } from "next/router";
|
||||
import { Tab } from "@headlessui/react";
|
||||
import useSWR from "swr";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { Plus } from "lucide-react";
|
||||
// hooks
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
// components
|
||||
import { CyclesHeader } from "components/headers";
|
||||
import { CyclesView, ActiveCycleDetails } from "components/cycles";
|
||||
import { CycleCreateEditModal } from "components/cycles/cycle-create-edit-modal";
|
||||
// ui
|
||||
import { Button } from "@plane/ui";
|
||||
import { EmptyState } from "components/common";
|
||||
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
||||
// images
|
||||
import emptyCycle from "public/empty-state/cycle.svg";
|
||||
// types
|
||||
import { TCycleView, TCycleLayout } from "types";
|
||||
import type { NextPage } from "next";
|
||||
// helper
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import { observer } from "mobx-react-lite";
|
||||
// constants
|
||||
import { CYCLE_TAB_LIST, CYCLE_VIEWS } from "constants/cycle";
|
||||
// lib cookie
|
||||
|
|
@ -85,25 +83,7 @@ const ProjectCyclesPage: NextPage = observer(() => {
|
|||
const cycleLayout = cycleStore?.cycleLayout;
|
||||
|
||||
return (
|
||||
<ProjectAuthorizationWrapper
|
||||
breadcrumbs={
|
||||
<Breadcrumbs>
|
||||
<BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} />
|
||||
<BreadcrumbItem title={`${truncateText(projectDetails?.name ?? "Project", 32)} Cycles`} />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
right={
|
||||
<Button
|
||||
variant="primary"
|
||||
prependIcon={<Plus />}
|
||||
onClick={() => {
|
||||
setCreateModal(true);
|
||||
}}
|
||||
>
|
||||
Add Cycle
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<AppLayout header={<CyclesHeader name={projectDetails?.name} />} withProjectWrapper>
|
||||
<CycleCreateEditModal
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
|
|
@ -226,7 +206,7 @@ const ProjectCyclesPage: NextPage = observer(() => {
|
|||
</Tab.Panels>
|
||||
</Tab.Group>
|
||||
)}
|
||||
</ProjectAuthorizationWrapper>
|
||||
</AppLayout>
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useRouter } from "next/router";
|
||||
import { NextPage } from "next";
|
||||
import useSWR from "swr";
|
||||
|
||||
// mobx store
|
||||
// hooks
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
|
|
@ -12,8 +12,6 @@ import { ProjectInboxHeader } from "components/headers";
|
|||
import { truncateText } from "helpers/string.helper";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
|
||||
const ProjectInbox: NextPage = () => {
|
||||
const router = useRouter();
|
||||
|
|
|
|||
|
|
@ -1,38 +1,20 @@
|
|||
import { useRouter } from "next/router";
|
||||
|
||||
import useSWR from "swr";
|
||||
|
||||
// mobx
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
// services
|
||||
import { ProjectService } from "services/project";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// helper
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
// components
|
||||
import { ProjectLayoutRoot } from "components/issues";
|
||||
import { ProjectIssuesHeader } from "components/headers";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
// fetch-keys
|
||||
import { PROJECT_DETAILS } from "constants/fetch-keys";
|
||||
|
||||
// services
|
||||
const projectService = new ProjectService();
|
||||
// layouts
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
|
||||
const ProjectIssues: NextPage = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
|
||||
const { issueFilter: issueFilterStore, project: projectStore, inbox: inboxStore } = useMobxStore();
|
||||
|
||||
const { data: projectDetails } = useSWR(
|
||||
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
|
||||
workspaceSlug && projectId ? () => projectService.getProject(workspaceSlug as string, projectId as string) : null
|
||||
);
|
||||
const { issueFilter: issueFilterStore } = useMobxStore();
|
||||
|
||||
// TODO: update the fetch keys
|
||||
useSWR(
|
||||
|
|
@ -42,57 +24,12 @@ const ProjectIssues: NextPage = () => {
|
|||
: null
|
||||
);
|
||||
|
||||
useSWR(
|
||||
workspaceSlug && projectId ? "REVALIDATE_PROJECT_STATES_LIST" : null,
|
||||
workspaceSlug && projectId
|
||||
? () => projectStore.fetchProjectStates(workspaceSlug.toString(), projectId.toString())
|
||||
: null
|
||||
);
|
||||
|
||||
useSWR(
|
||||
workspaceSlug && projectId ? "REVALIDATE_PROJECT_LABELS_LIST" : null,
|
||||
workspaceSlug && projectId
|
||||
? () => projectStore.fetchProjectLabels(workspaceSlug.toString(), projectId.toString())
|
||||
: null
|
||||
);
|
||||
|
||||
useSWR(
|
||||
workspaceSlug && projectId ? "REVALIDATE_PROJECT_MEMBERS_LIST" : null,
|
||||
workspaceSlug && projectId
|
||||
? () => projectStore.fetchProjectMembers(workspaceSlug.toString(), projectId.toString())
|
||||
: null
|
||||
);
|
||||
|
||||
useSWR(
|
||||
workspaceSlug && projectId ? "REVALIDATE_PROJECT_DETAILS" : null,
|
||||
workspaceSlug && projectId
|
||||
? () => projectStore.fetchProjectDetails(workspaceSlug.toString(), projectId.toString())
|
||||
: null
|
||||
);
|
||||
|
||||
useSWR(
|
||||
workspaceSlug && projectId ? "REVALIDATE_INBOXES_LIST" : null,
|
||||
workspaceSlug && projectId
|
||||
? () => inboxStore.fetchInboxesList(workspaceSlug.toString(), projectId.toString())
|
||||
: null
|
||||
);
|
||||
// TODO: remove all the above fetching logic to project auth wrapper
|
||||
|
||||
return (
|
||||
<ProjectAuthorizationWrapper
|
||||
breadcrumbs={
|
||||
<Breadcrumbs>
|
||||
<BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} />
|
||||
<BreadcrumbItem title={`${truncateText(projectDetails?.name ?? "Project", 32)} Issues`} />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
right={<ProjectIssuesHeader />}
|
||||
bg="secondary"
|
||||
>
|
||||
<AppLayout header={<ProjectIssuesHeader />} withProjectWrapper>
|
||||
<div className="h-full w-full flex flex-col">
|
||||
<ProjectLayoutRoot />
|
||||
</div>
|
||||
</ProjectAuthorizationWrapper>
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import useSWR from "swr";
|
||||
|
||||
import { NextPage } from "next";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
// hooks
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
// services
|
||||
|
|
@ -13,45 +11,30 @@ import { ProjectService } from "services/project";
|
|||
import { ModuleService } from "services/module.service";
|
||||
// components
|
||||
import { CreateUpdateModuleModal, ModulesListGanttChartView, SingleModuleCard } from "components/modules";
|
||||
import { ModulesHeader } from "components/headers";
|
||||
// ui
|
||||
import { Button, Loader, Tooltip } from "@plane/ui";
|
||||
import { Loader } from "@plane/ui";
|
||||
import { EmptyState } from "components/common";
|
||||
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
||||
// icons
|
||||
import { GanttChart, LayoutGrid, Plus } from "lucide-react";
|
||||
import { Plus } from "lucide-react";
|
||||
// images
|
||||
import emptyModule from "public/empty-state/module.svg";
|
||||
// types
|
||||
import { IModule, SelectModuleType } from "types/modules";
|
||||
import type { NextPage } from "next";
|
||||
// fetch-keys
|
||||
import { MODULE_LIST, PROJECT_DETAILS } from "constants/fetch-keys";
|
||||
// helper
|
||||
import { replaceUnderscoreIfSnakeCase, truncateText } from "helpers/string.helper";
|
||||
|
||||
const moduleViewOptions: { type: "grid" | "gantt_chart"; icon: any }[] = [
|
||||
{
|
||||
type: "gantt_chart",
|
||||
icon: GanttChart,
|
||||
},
|
||||
{
|
||||
type: "grid",
|
||||
icon: LayoutGrid,
|
||||
},
|
||||
];
|
||||
|
||||
// services
|
||||
const projectService = new ProjectService();
|
||||
const moduleService = new ModuleService();
|
||||
|
||||
const ProjectModules: NextPage = () => {
|
||||
const [selectedModule, setSelectedModule] = useState<SelectModuleType>();
|
||||
const [createUpdateModule, setCreateUpdateModule] = useState(false);
|
||||
|
||||
const [modulesView, setModulesView] = useState<"grid" | "gantt_chart">("grid");
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
// states
|
||||
const [modulesView, setModulesView] = useState<"grid" | "gantt_chart">("grid");
|
||||
const [selectedModule, setSelectedModule] = useState<SelectModuleType>();
|
||||
const [createUpdateModule, setCreateUpdateModule] = useState(false);
|
||||
|
||||
const { user } = useUserAuth();
|
||||
|
||||
|
|
@ -80,44 +63,8 @@ const ProjectModules: NextPage = () => {
|
|||
}, [createUpdateModule]);
|
||||
|
||||
return (
|
||||
<ProjectAuthorizationWrapper
|
||||
breadcrumbs={
|
||||
<Breadcrumbs>
|
||||
<BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} />
|
||||
<BreadcrumbItem title={`${truncateText(activeProject?.name ?? "Project", 32)} Modules`} />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
right={
|
||||
<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)}
|
||||
>
|
||||
<option.icon className="h-4 w-4" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
))}
|
||||
<Button
|
||||
variant="primary"
|
||||
prependIcon={<Plus />}
|
||||
onClick={() => {
|
||||
const e = new KeyboardEvent("keydown", { key: "m" });
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
>
|
||||
Add Module
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
<AppLayout
|
||||
header={<ModulesHeader name={activeProject?.name} modulesView={modulesView} setModulesView={setModulesView} />}
|
||||
>
|
||||
<CreateUpdateModuleModal
|
||||
isOpen={createUpdateModule}
|
||||
|
|
@ -173,7 +120,7 @@ const ProjectModules: NextPage = () => {
|
|||
<Loader.Item height="100px" />
|
||||
</Loader>
|
||||
)}
|
||||
</ProjectAuthorizationWrapper>
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,14 @@
|
|||
import React from "react";
|
||||
|
||||
import type { NextPage } from "next";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import useSWR from "swr";
|
||||
|
||||
// mobx store
|
||||
// hooks
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import { ProjectViewsHeader } from "components/headers";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
||||
// components
|
||||
import { ProjectViewsList } from "components/views";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
// layouts
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
|
||||
const ProjectViews: NextPage = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -43,17 +36,9 @@ const ProjectViews: NextPage = () => {
|
|||
: undefined;
|
||||
|
||||
return (
|
||||
<ProjectAuthorizationWrapper
|
||||
breadcrumbs={
|
||||
<Breadcrumbs>
|
||||
<BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} />
|
||||
<BreadcrumbItem title={`${projectDetails?.name ?? "Project"} Views`} />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
right={<ProjectViewsHeader />}
|
||||
>
|
||||
<AppLayout header={<ProjectViewsHeader title={projectDetails?.name} />}>
|
||||
<ProjectViewsList />
|
||||
</ProjectAuthorizationWrapper>
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue