forked from github/plane
chore: workspace active cycles upgrade page implementation (#3454)
Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
This commit is contained in:
parent
a2f34e9573
commit
9d9d703c62
@ -20,3 +20,4 @@ export * from "./project-archived-issue-details";
|
||||
export * from "./project-archived-issues";
|
||||
export * from "./project-issue-details";
|
||||
export * from "./user-profile";
|
||||
export * from "./workspace-active-cycles";
|
||||
|
22
web/components/headers/workspace-active-cycles.tsx
Normal file
22
web/components/headers/workspace-active-cycles.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { observer } from "mobx-react-lite";
|
||||
// ui
|
||||
import { Breadcrumbs, ContrastIcon } from "@plane/ui";
|
||||
// icons
|
||||
import { Crown } from "lucide-react";
|
||||
|
||||
export const WorkspaceActiveCycleHeader = observer(() => (
|
||||
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row 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 w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<div className="flex items-center gap-2">
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
type="text"
|
||||
icon={<ContrastIcon className="h-4 w-4 text-custom-text-300 rotate-180" />}
|
||||
label="Active Cycles"
|
||||
/>
|
||||
</Breadcrumbs>
|
||||
<Crown className="h-3.5 w-3.5 text-amber-400" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
));
|
@ -8,3 +8,4 @@ export * from "./send-workspace-invitation-modal";
|
||||
export * from "./sidebar-dropdown";
|
||||
export * from "./sidebar-menu";
|
||||
export * from "./sidebar-quick-action";
|
||||
export * from "./workspace-active-cycles-upgrade";
|
||||
|
@ -8,9 +8,12 @@ import { useApplication, useUser } from "hooks/store";
|
||||
import { NotificationPopover } from "components/notifications";
|
||||
// ui
|
||||
import { Tooltip } from "@plane/ui";
|
||||
import { Crown } from "lucide-react";
|
||||
// constants
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
import { SIDEBAR_MENU_ITEMS } from "constants/dashboard";
|
||||
// helper
|
||||
import { cn } from "helpers/common.helper";
|
||||
|
||||
export const WorkspaceSidebarMenu = observer(() => {
|
||||
// store hooks
|
||||
@ -44,8 +47,17 @@ export const WorkspaceSidebarMenu = observer(() => {
|
||||
: "text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80"
|
||||
} ${themeStore?.sidebarCollapsed ? "justify-center" : ""}`}
|
||||
>
|
||||
{<link.Icon className="h-4 w-4" />}
|
||||
{
|
||||
<link.Icon
|
||||
className={cn("h-4 w-4", {
|
||||
"rotate-180": link.key === "active-cycles",
|
||||
})}
|
||||
/>
|
||||
}
|
||||
{!themeStore?.sidebarCollapsed && link.label}
|
||||
{!themeStore?.sidebarCollapsed && link.key === "active-cycles" && (
|
||||
<Crown className="h-3.5 w-3.5 text-amber-400" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
100
web/components/workspace/workspace-active-cycles-upgrade.tsx
Normal file
100
web/components/workspace/workspace-active-cycles-upgrade.tsx
Normal file
@ -0,0 +1,100 @@
|
||||
import React from "react";
|
||||
import Image from "next/image";
|
||||
import { observer } from "mobx-react";
|
||||
// hooks
|
||||
import { useUser } from "hooks/store";
|
||||
// ui
|
||||
import { getButtonStyling } from "@plane/ui";
|
||||
// icons
|
||||
import { Crown } from "lucide-react";
|
||||
// helper
|
||||
import { cn } from "helpers/common.helper";
|
||||
// constants
|
||||
import { WORKSPACE_ACTIVE_CYCLES_DETAILS } from "constants/cycle";
|
||||
|
||||
export const WorkspaceActiveCyclesUpgrade = observer(() => {
|
||||
// store hooks
|
||||
const { currentUser } = useUser();
|
||||
|
||||
const isDarkMode = currentUser?.theme.theme === "dark";
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-10 p-8 rounded-xl">
|
||||
<div
|
||||
className={cn("flex item-center justify-between rounded-xl min-h-[25rem]", {
|
||||
"bg-gradient-to-l from-[#CFCFCF] to-[#212121]": currentUser?.theme.theme === "dark",
|
||||
"bg-gradient-to-l from-[#3b5ec6] to-[#f5f7fe]": currentUser?.theme.theme === "light",
|
||||
})}
|
||||
>
|
||||
<div className="relative px-14 flex flex-col gap-7 justify-center lg:w-1/2">
|
||||
<div className="flex flex-col gap-2 max-w-64">
|
||||
<h2 className="text-2xl font-semibold">On-demand snapshots of all your cycles</h2>
|
||||
<p className="text-base font-medium text-custom-text-300">
|
||||
Monitor cycles across projects, track high-priority issues, and zoom in cycles that need attention.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<a
|
||||
className={`${getButtonStyling("primary", "md")} cursor-pointer`}
|
||||
href="https://plane.so/pricing"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Crown className="h-3.5 w-3.5" />
|
||||
Upgrade
|
||||
</a>
|
||||
<a
|
||||
className={cn("text-sm underline", {
|
||||
"text-white": currentUser?.theme.theme === "dark",
|
||||
"text-blue-600": currentUser?.theme.theme === "light",
|
||||
})}
|
||||
href="https://plane.so/pricing"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Talk custom pricing
|
||||
</a>
|
||||
</div>
|
||||
<span className="absolute left-0 top-0">
|
||||
<Image
|
||||
src={`/workspace-active-cycles/cta-l-1-${isDarkMode ? "dark" : "light"}.webp`}
|
||||
height={125}
|
||||
width={125}
|
||||
className="rounded-xl"
|
||||
alt="l-1"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div className="relative w-1/2 hidden lg:block">
|
||||
<span className="absolute right-0 bottom-0">
|
||||
<Image
|
||||
src={`/workspace-active-cycles/cta-r-1-${isDarkMode ? "dark" : "light"}.webp`}
|
||||
height={420}
|
||||
width={500}
|
||||
alt="r-1"
|
||||
/>
|
||||
</span>
|
||||
<span className="absolute right-1/2 -bottom-16 rounded-xl">
|
||||
<Image
|
||||
src={`/workspace-active-cycles/cta-r-2-${isDarkMode ? "dark" : "light"}.webp`}
|
||||
height={210}
|
||||
width={280}
|
||||
alt="r-2"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-5">
|
||||
{WORKSPACE_ACTIVE_CYCLES_DETAILS.map((item) => (
|
||||
<div className="flex flex-col gap-2 p-4 min-h-32 w-full bg-custom-background-80 rounded-md">
|
||||
<div className="flex items-center gap-2">
|
||||
<h3 className="font-medium">{item.title}</h3>
|
||||
<item.icon className="text-blue-500 h-4 w-4" />
|
||||
</div>
|
||||
<span className="text-sm text-custom-text-300">{item.description}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
@ -1,4 +1,15 @@
|
||||
import { GanttChartSquare, LayoutGrid, List } from "lucide-react";
|
||||
import {
|
||||
GanttChartSquare,
|
||||
LayoutGrid,
|
||||
List,
|
||||
AlertOctagon,
|
||||
BarChart4,
|
||||
CircleDashed,
|
||||
Folder,
|
||||
Microscope,
|
||||
Search,
|
||||
} from "lucide-react";
|
||||
|
||||
// types
|
||||
import { TCycleLayout, TCycleView } from "@plane/types";
|
||||
|
||||
@ -115,6 +126,43 @@ export const CYCLE_STATE_GROUPS_DETAILS = [
|
||||
},
|
||||
];
|
||||
|
||||
export const WORKSPACE_ACTIVE_CYCLES_DETAILS = [
|
||||
{
|
||||
title: "10,000-feet view of all active cycles.",
|
||||
description:
|
||||
"Zoom out to see running cycles across all your projects at once instead of going from Cycle to Cycle in each project.",
|
||||
icon: Folder,
|
||||
},
|
||||
{
|
||||
title: "Get a snapshot of each active cycle.",
|
||||
description:
|
||||
"Track high-level metrics for all active cycles, see their state of progress, and get a sense of scope against deadlines.",
|
||||
icon: CircleDashed,
|
||||
},
|
||||
{
|
||||
title: "Compare burndowns.",
|
||||
description: "Monitor how each of your teams are performing with a peek into each cycle’s burndown report.",
|
||||
icon: BarChart4,
|
||||
},
|
||||
{
|
||||
title: "Quickly see make-or-break issues. ",
|
||||
description:
|
||||
"Preview high-priority issues for each cycle against due dates. See all of them per cycle in one click.",
|
||||
icon: AlertOctagon,
|
||||
},
|
||||
{
|
||||
title: "Zoom into cycles that need attention. ",
|
||||
description: "Investigate the state of any cycle that doesn’t conform to expectations in one click.",
|
||||
icon: Search,
|
||||
},
|
||||
{
|
||||
title: "Stay ahead of blockers.",
|
||||
description:
|
||||
"Spot challenges from one project to another and see inter-cycle dependencies that aren’t obvious from any other view.",
|
||||
icon: Microscope,
|
||||
},
|
||||
];
|
||||
|
||||
export const CYCLE_EMPTY_STATE_DETAILS = {
|
||||
active: {
|
||||
key: "active",
|
||||
|
@ -19,6 +19,7 @@ import { Props } from "components/icons/types";
|
||||
import { EUserWorkspaceRoles } from "./workspace";
|
||||
// icons
|
||||
import { BarChart2, Briefcase, CheckCircle, LayoutGrid } from "lucide-react";
|
||||
import { ContrastIcon } from "@plane/ui";
|
||||
|
||||
// gradients for issues by priority widget graph bars
|
||||
export const PRIORITY_GRAPH_GRADIENTS = [
|
||||
@ -292,4 +293,12 @@ export const SIDEBAR_MENU_ITEMS: {
|
||||
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/workspace-views/all-issues`,
|
||||
Icon: CheckCircle,
|
||||
},
|
||||
{
|
||||
key: "active-cycles",
|
||||
label: "Active Cycles",
|
||||
href: `/active-cycles`,
|
||||
access: EUserWorkspaceRoles.GUEST,
|
||||
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/active-cycles`,
|
||||
Icon: ContrastIcon,
|
||||
},
|
||||
];
|
||||
|
16
web/pages/[workspaceSlug]/active-cycles.tsx
Normal file
16
web/pages/[workspaceSlug]/active-cycles.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { ReactElement } from "react";
|
||||
// components
|
||||
import { WorkspaceActiveCycleHeader } from "components/headers";
|
||||
import { WorkspaceActiveCyclesUpgrade } from "components/workspace";
|
||||
// layouts
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
// types
|
||||
import { NextPageWithLayout } from "lib/types";
|
||||
|
||||
const WorkspaceActiveCyclesPage: NextPageWithLayout = () => <WorkspaceActiveCyclesUpgrade />;
|
||||
|
||||
WorkspaceActiveCyclesPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return <AppLayout header={<WorkspaceActiveCycleHeader />}>{page}</AppLayout>;
|
||||
};
|
||||
|
||||
export default WorkspaceActiveCyclesPage;
|
BIN
web/public/workspace-active-cycles/cta-l-1-dark.webp
Normal file
BIN
web/public/workspace-active-cycles/cta-l-1-dark.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
BIN
web/public/workspace-active-cycles/cta-l-1-light.webp
Normal file
BIN
web/public/workspace-active-cycles/cta-l-1-light.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
BIN
web/public/workspace-active-cycles/cta-r-1-dark.webp
Normal file
BIN
web/public/workspace-active-cycles/cta-r-1-dark.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
BIN
web/public/workspace-active-cycles/cta-r-1-light.webp
Normal file
BIN
web/public/workspace-active-cycles/cta-r-1-light.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 63 KiB |
BIN
web/public/workspace-active-cycles/cta-r-2-dark.webp
Normal file
BIN
web/public/workspace-active-cycles/cta-r-2-dark.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 377 KiB |
BIN
web/public/workspace-active-cycles/cta-r-2-light.webp
Normal file
BIN
web/public/workspace-active-cycles/cta-r-2-light.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 383 KiB |
Loading…
Reference in New Issue
Block a user