mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
style: empty state global component (#435)
This commit is contained in:
parent
bfab4865cd
commit
636e8e6c60
@ -14,7 +14,9 @@ import { CompletedCycleIcon } from "components/icons";
|
||||
import { ICycle, SelectCycleType } from "types";
|
||||
// fetch-keys
|
||||
import { CYCLE_COMPLETE_LIST } from "constants/fetch-keys";
|
||||
import { Loader } from "components/ui";
|
||||
import { EmptyState, Loader } from "components/ui";
|
||||
// image
|
||||
import emptyCycle from "public/empty-state/empty-cycle.svg";
|
||||
|
||||
export interface CompletedCyclesListProps {
|
||||
setCreateUpdateCycleModal: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
@ -72,13 +74,13 @@ export const CompletedCyclesList: React.FC<CompletedCyclesListProps> = ({
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center gap-4 text-center">
|
||||
<CompletedCycleIcon height="56" width="56" />
|
||||
<h3 className="text-gray-500">
|
||||
No completed cycles yet. Create with{" "}
|
||||
<pre className="inline rounded bg-gray-200 px-2 py-1">Q</pre>.
|
||||
</h3>
|
||||
</div>
|
||||
<EmptyState
|
||||
type="cycle"
|
||||
title="Create New Cycle"
|
||||
description="Sprint more effectively with Cycles by confining your project
|
||||
to a fixed amount of time. Create new cycle now."
|
||||
imgURL={emptyCycle}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<Loader className="grid grid-cols-1 gap-9 md:grid-cols-2 lg:grid-cols-3">
|
||||
|
@ -1,8 +1,11 @@
|
||||
import { useState } from "react";
|
||||
|
||||
// components
|
||||
import { DeleteCycleModal, EmptyCycle, SingleCycleCard } from "components/cycles";
|
||||
import { Loader } from "components/ui";
|
||||
import { DeleteCycleModal, SingleCycleCard } from "components/cycles";
|
||||
import { EmptyState, Loader } from "components/ui";
|
||||
// image
|
||||
import emptyCycle from "public/empty-state/empty-cycle.svg";
|
||||
|
||||
// types
|
||||
import { ICycle, SelectCycleType } from "types";
|
||||
|
||||
@ -56,7 +59,13 @@ export const CyclesList: React.FC<TCycleStatsViewProps> = ({
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<EmptyCycle />
|
||||
<EmptyState
|
||||
type="cycle"
|
||||
title="Create New Cycle"
|
||||
description="Sprint more effectively with Cycles by confining your project
|
||||
to a fixed amount of time. Create new cycle now."
|
||||
imgURL={emptyCycle}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<Loader className="grid grid-cols-1 gap-9 md:grid-cols-2 lg:grid-cols-3">
|
||||
|
59
apps/app/components/ui/empty-state.tsx
Normal file
59
apps/app/components/ui/empty-state.tsx
Normal file
@ -0,0 +1,59 @@
|
||||
import React from "react";
|
||||
import Image from "next/image";
|
||||
|
||||
// icon
|
||||
import { PlusIcon } from "@heroicons/react/24/outline";
|
||||
// helper
|
||||
import { capitalizeFirstLetter } from "helpers/string.helper";
|
||||
|
||||
type Props = {
|
||||
type: "cycle" | "module" | "project" | "issue";
|
||||
title: string;
|
||||
description: React.ReactNode | string;
|
||||
imgURL: string;
|
||||
};
|
||||
|
||||
export const EmptyState: React.FC<Props> = ({ type, title, description, imgURL }) => {
|
||||
const shortcutKey = (type: string) => {
|
||||
switch (type) {
|
||||
case "cycle":
|
||||
return "Q";
|
||||
case "module":
|
||||
return "M";
|
||||
case "project":
|
||||
return "P";
|
||||
default:
|
||||
return "C";
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col items-center justify-center gap-5 text-center">
|
||||
<div className="h-32 w-72">
|
||||
<Image src={imgURL} height="128" width="288" alt={type} />
|
||||
</div>
|
||||
|
||||
<h3 className="text-xl font-semibold">{title}</h3>
|
||||
<span>
|
||||
Use shortcut{" "}
|
||||
<span className="rounded-sm mx-1 border border-gray-200 bg-gray-100 px-2 py-1 text-sm font-medium text-gray-800">
|
||||
{shortcutKey(type)}
|
||||
</span>{" "}
|
||||
to create {type} from anywhere.
|
||||
</span>
|
||||
<p className="max-w-md text-sm text-gray-500">{description}</p>
|
||||
|
||||
<button
|
||||
className="flex items-center gap-1 rounded-lg bg-theme px-2.5 py-2 text-sm text-white"
|
||||
onClick={() => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: shortcutKey(type),
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4 font-bold text-white" />
|
||||
Create New {capitalizeFirstLetter(type)}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -18,3 +18,4 @@ export * from "./spinner";
|
||||
export * from "./tooltip";
|
||||
export * from "./labels-list";
|
||||
export * from "./linear-progress-indicator";
|
||||
export * from "./empty-state";
|
@ -14,7 +14,7 @@ import { IssueViewContextProvider } from "contexts/issue-view.context";
|
||||
// components
|
||||
import { IssuesFilterView, IssuesView } from "components/core";
|
||||
// ui
|
||||
import { Spinner, EmptySpace, EmptySpaceItem, HeaderButton } from "components/ui";
|
||||
import { Spinner, EmptySpace, EmptySpaceItem, HeaderButton, EmptyState } from "components/ui";
|
||||
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
||||
// icons
|
||||
import { RectangleStackIcon, PlusIcon } from "@heroicons/react/24/outline";
|
||||
@ -23,6 +23,8 @@ import type { UserAuth } from "types";
|
||||
import type { GetServerSidePropsContext, NextPage } from "next";
|
||||
// fetch-keys
|
||||
import { PROJECT_DETAILS, PROJECT_ISSUES_LIST } from "constants/fetch-keys";
|
||||
// image
|
||||
import emptyIssue from "public/empty-state/empty-issue.svg";
|
||||
|
||||
const ProjectIssues: NextPage<UserAuth> = (props) => {
|
||||
const router = useRouter();
|
||||
@ -76,30 +78,13 @@ const ProjectIssues: NextPage<UserAuth> = (props) => {
|
||||
userAuth={props}
|
||||
/>
|
||||
) : (
|
||||
<div className="grid h-full w-full place-items-center px-4 sm:px-0">
|
||||
<EmptySpace
|
||||
title="You don't have any issue yet."
|
||||
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done."
|
||||
Icon={RectangleStackIcon}
|
||||
>
|
||||
<EmptySpaceItem
|
||||
title="Create a new issue"
|
||||
description={
|
||||
<span>
|
||||
Use <pre className="inline rounded bg-gray-200 px-2 py-1">C</pre> shortcut to
|
||||
create a new issue
|
||||
</span>
|
||||
}
|
||||
Icon={PlusIcon}
|
||||
action={() => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "c",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
/>
|
||||
</EmptySpace>
|
||||
</div>
|
||||
<EmptyState
|
||||
type="issue"
|
||||
title="Create New Issue"
|
||||
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done.
|
||||
Create a new issue"
|
||||
imgURL={emptyIssue}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
|
@ -2,7 +2,10 @@ import React, { useEffect, useState } from "react";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
import useSWR from "swr";
|
||||
import { PlusIcon, RectangleGroupIcon } from "@heroicons/react/24/outline";
|
||||
import { PlusIcon } from "@heroicons/react/24/outline";
|
||||
// image
|
||||
import emptyModule from "public/empty-state/empty-module.svg";
|
||||
|
||||
|
||||
// layouts
|
||||
import AppLayout from "layouts/app-layout";
|
||||
@ -14,7 +17,7 @@ import modulesService from "services/modules.service";
|
||||
// components
|
||||
import { CreateUpdateModuleModal, SingleModuleCard } from "components/modules";
|
||||
// ui
|
||||
import { EmptySpace, EmptySpaceItem, HeaderButton, Loader } from "components/ui";
|
||||
import { EmptyState, HeaderButton, Loader } from "components/ui";
|
||||
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
||||
// icons
|
||||
// types
|
||||
@ -103,30 +106,12 @@ const ProjectModules: NextPage = () => {
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex h-full w-full flex-col items-center justify-center px-4">
|
||||
<EmptySpace
|
||||
title="You don't have any module yet."
|
||||
description="Modules are smaller, focused projects that help you group and organize issues within a specific time frame."
|
||||
Icon={RectangleGroupIcon}
|
||||
>
|
||||
<EmptySpaceItem
|
||||
title="Create a new module"
|
||||
description={
|
||||
<span>
|
||||
Use <pre className="inline rounded bg-gray-200 px-2 py-1">M</pre> shortcut to
|
||||
create a new module
|
||||
</span>
|
||||
}
|
||||
Icon={PlusIcon}
|
||||
action={() => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "m",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
/>
|
||||
</EmptySpace>
|
||||
</div>
|
||||
<EmptyState
|
||||
type="module"
|
||||
title="Create New Module"
|
||||
description="Modules are smaller, focused projects that help you group and organize issues within a specific time frame."
|
||||
imgURL={emptyModule}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<Loader className="grid grid-cols-3 gap-4">
|
||||
|
@ -14,14 +14,16 @@ import AppLayout from "layouts/app-layout";
|
||||
import { JoinProjectModal } from "components/project/join-project-modal";
|
||||
import { DeleteProjectModal, SingleProjectCard } from "components/project";
|
||||
// ui
|
||||
import { HeaderButton, EmptySpace, EmptySpaceItem, Loader } from "components/ui";
|
||||
import { HeaderButton, Loader, EmptyState } from "components/ui";
|
||||
import { Breadcrumbs, BreadcrumbItem } from "components/breadcrumbs";
|
||||
// icons
|
||||
import { ClipboardDocumentListIcon, PlusIcon } from "@heroicons/react/24/outline";
|
||||
import { PlusIcon } from "@heroicons/react/24/outline";
|
||||
// types
|
||||
import type { GetServerSidePropsContext, NextPage } from "next";
|
||||
// fetch-keys
|
||||
import { PROJECT_MEMBERS } from "constants/fetch-keys";
|
||||
// image
|
||||
import emptyProject from "public/empty-state/empty-project.svg";
|
||||
|
||||
const ProjectsPage: NextPage = () => {
|
||||
// router
|
||||
@ -80,28 +82,12 @@ const ProjectsPage: NextPage = () => {
|
||||
{projects ? (
|
||||
<>
|
||||
{projects.length === 0 ? (
|
||||
<div className="grid h-full w-full place-items-center px-4 sm:px-0">
|
||||
<EmptySpace
|
||||
title="You don't have any project yet."
|
||||
description="Projects are a collection of issues. They can be used to represent the development work for a product, project, or service."
|
||||
Icon={ClipboardDocumentListIcon}
|
||||
>
|
||||
<EmptySpaceItem
|
||||
title="Create a new project"
|
||||
description={
|
||||
<span>
|
||||
Use <pre className="inline rounded bg-gray-200 px-2 py-1">P</pre> shortcut to
|
||||
create a new project
|
||||
</span>
|
||||
}
|
||||
Icon={PlusIcon}
|
||||
action={() => {
|
||||
const e = new KeyboardEvent("keydown", { key: "p" });
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
/>
|
||||
</EmptySpace>
|
||||
</div>
|
||||
<EmptyState
|
||||
type="project"
|
||||
title="Create New Project"
|
||||
description="Projects are a collection of issues. They can be used to represent the development work for a product, project, or service."
|
||||
imgURL={emptyProject}
|
||||
/>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 gap-9 md:grid-cols-2 lg:grid-cols-3">
|
||||
{projects.map((project) => (
|
||||
|
50
apps/app/public/empty-state/empty-cycle.svg
Normal file
50
apps/app/public/empty-state/empty-cycle.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 20 KiB |
62
apps/app/public/empty-state/empty-issue.svg
Normal file
62
apps/app/public/empty-state/empty-issue.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 19 KiB |
50
apps/app/public/empty-state/empty-module.svg
Normal file
50
apps/app/public/empty-state/empty-module.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 20 KiB |
56
apps/app/public/empty-state/empty-project.svg
Normal file
56
apps/app/public/empty-state/empty-project.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 24 KiB |
Loading…
Reference in New Issue
Block a user