mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
style: calendar view (#948)
* style: calendar view * chore: add issue button positioning
This commit is contained in:
parent
7234d6f68b
commit
ff7f31c35b
@ -51,6 +51,7 @@ import { IIssue } from "types";
|
|||||||
// constant
|
// constant
|
||||||
import { monthOptions, yearOptions } from "constants/calendar";
|
import { monthOptions, yearOptions } from "constants/calendar";
|
||||||
import modulesService from "services/modules.service";
|
import modulesService from "services/modules.service";
|
||||||
|
import { getStateGroupIcon } from "components/icons";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
addIssueToDate: (date: string) => void;
|
addIssueToDate: (date: string) => void;
|
||||||
@ -62,9 +63,10 @@ interface ICalendarRange {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const CalendarView: React.FC<Props> = ({ addIssueToDate }) => {
|
export const CalendarView: React.FC<Props> = ({ addIssueToDate }) => {
|
||||||
const [showWeekEnds, setShowWeekEnds] = useState<boolean>(false);
|
const [showWeekEnds, setShowWeekEnds] = useState(false);
|
||||||
const [currentDate, setCurrentDate] = useState<Date>(new Date());
|
const [currentDate, setCurrentDate] = useState(new Date());
|
||||||
const [isMonthlyView, setIsMonthlyView] = useState<boolean>(true);
|
const [isMonthlyView, setIsMonthlyView] = useState(true);
|
||||||
|
const [showAllIssues, setShowAllIssues] = useState(false);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
||||||
@ -151,15 +153,15 @@ export const CalendarView: React.FC<Props> = ({ addIssueToDate }) => {
|
|||||||
const currentViewDays = showWeekEnds ? totalDate : onlyWeekDays;
|
const currentViewDays = showWeekEnds ? totalDate : onlyWeekDays;
|
||||||
|
|
||||||
const calendarIssues = cycleId
|
const calendarIssues = cycleId
|
||||||
? cycleCalendarIssues
|
? (cycleCalendarIssues as IIssue[])
|
||||||
: moduleId
|
: moduleId
|
||||||
? moduleCalendarIssues
|
? (moduleCalendarIssues as IIssue[])
|
||||||
: projectCalendarIssues;
|
: (projectCalendarIssues as IIssue[]);
|
||||||
|
|
||||||
const currentViewDaysData = currentViewDays.map((date: Date) => {
|
const currentViewDaysData = currentViewDays.map((date: Date) => {
|
||||||
const filterIssue =
|
const filterIssue =
|
||||||
calendarIssues && calendarIssues.length > 0
|
calendarIssues && calendarIssues.length > 0
|
||||||
? (calendarIssues as IIssue[]).filter(
|
? calendarIssues.filter(
|
||||||
(issue) =>
|
(issue) =>
|
||||||
issue.target_date && renderDateFormat(issue.target_date) === renderDateFormat(date)
|
issue.target_date && renderDateFormat(issue.target_date) === renderDateFormat(date)
|
||||||
)
|
)
|
||||||
@ -324,7 +326,7 @@ export const CalendarView: React.FC<Props> = ({ addIssueToDate }) => {
|
|||||||
|
|
||||||
<div className="flex w-full items-center justify-end gap-2">
|
<div className="flex w-full items-center justify-end gap-2">
|
||||||
<button
|
<button
|
||||||
className="group flex cursor-pointer items-center gap-2 rounded-md border border-brand-base bg-brand-surface-2 px-4 py-1.5 text-sm hover:bg-brand-surface-1 hover:text-brand-base focus:outline-none"
|
className="group flex cursor-pointer items-center gap-2 rounded-md border border-brand-base px-3 py-1 text-sm hover:bg-brand-surface-2 hover:text-brand-base focus:outline-none"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (isMonthlyView) {
|
if (isMonthlyView) {
|
||||||
updateDate(new Date());
|
updateDate(new Date());
|
||||||
@ -337,14 +339,12 @@ export const CalendarView: React.FC<Props> = ({ addIssueToDate }) => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Today{" "}
|
Today
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<CustomMenu
|
<CustomMenu
|
||||||
customButton={
|
customButton={
|
||||||
<div
|
<div className="group flex cursor-pointer items-center gap-2 rounded-md border border-brand-base px-3 py-1 text-sm hover:bg-brand-surface-2 hover:text-brand-base focus:outline-none ">
|
||||||
className={`group flex cursor-pointer items-center gap-2 rounded-md border border-brand-base bg-brand-surface-2 px-3 py-1.5 text-sm hover:bg-brand-surface-1 hover:text-brand-base focus:outline-none `}
|
|
||||||
>
|
|
||||||
{isMonthlyView ? "Monthly" : "Weekly"}
|
{isMonthlyView ? "Monthly" : "Weekly"}
|
||||||
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
|
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
|
||||||
</div>
|
</div>
|
||||||
@ -445,61 +445,87 @@ export const CalendarView: React.FC<Props> = ({ addIssueToDate }) => {
|
|||||||
showWeekEnds ? "grid-cols-7" : "grid-cols-5"
|
showWeekEnds ? "grid-cols-7" : "grid-cols-5"
|
||||||
} `}
|
} `}
|
||||||
>
|
>
|
||||||
{currentViewDaysData.map((date, index) => (
|
{currentViewDaysData.map((date, index) => {
|
||||||
<StrictModeDroppable droppableId={date.date}>
|
const totalIssues = date.issues.length;
|
||||||
{(provided, snapshot) => (
|
|
||||||
<div
|
return (
|
||||||
key={index}
|
<StrictModeDroppable droppableId={date.date}>
|
||||||
ref={provided.innerRef}
|
{(provided) => (
|
||||||
{...provided.droppableProps}
|
<div
|
||||||
className={`group flex flex-col gap-1.5 border-t border-brand-base p-2.5 text-left text-sm font-medium hover:bg-brand-surface-1 ${
|
key={index}
|
||||||
showWeekEnds
|
ref={provided.innerRef}
|
||||||
? (index + 1) % 7 === 0
|
{...provided.droppableProps}
|
||||||
|
className={`group relative flex flex-col gap-1.5 border-t border-brand-base p-2.5 text-left text-sm font-medium hover:bg-brand-surface-1 ${
|
||||||
|
showWeekEnds
|
||||||
|
? (index + 1) % 7 === 0
|
||||||
|
? ""
|
||||||
|
: "border-r"
|
||||||
|
: (index + 1) % 5 === 0
|
||||||
? ""
|
? ""
|
||||||
: "border-r"
|
: "border-r"
|
||||||
: (index + 1) % 5 === 0
|
}`}
|
||||||
? ""
|
>
|
||||||
: "border-r"
|
{isMonthlyView && <span>{formatDate(new Date(date.date), "d")}</span>}
|
||||||
}`}
|
{totalIssues > 0 &&
|
||||||
>
|
date.issues
|
||||||
{isMonthlyView && <span>{formatDate(new Date(date.date), "d")}</span>}
|
.slice(0, showAllIssues ? totalIssues : 4)
|
||||||
{date.issues.length > 0 &&
|
.map((issue: IIssue, index) => (
|
||||||
date.issues.map((issue: IIssue, index) => (
|
<Draggable draggableId={issue.id} index={index}>
|
||||||
<Draggable draggableId={issue.id} index={index}>
|
{(provided, snapshot) => (
|
||||||
{(provided, snapshot) => (
|
<div
|
||||||
<div
|
key={index}
|
||||||
key={index}
|
ref={provided.innerRef}
|
||||||
ref={provided.innerRef}
|
{...provided.draggableProps}
|
||||||
{...provided.draggableProps}
|
{...provided.dragHandleProps}
|
||||||
{...provided.dragHandleProps}
|
className={`w-full cursor-pointer truncate rounded border border-brand-base px-1.5 py-1 text-xs duration-300 hover:cursor-move hover:bg-brand-surface-2 ${
|
||||||
className={`w-full cursor-pointer truncate rounded bg-brand-surface-2 p-1.5 hover:scale-105 ${
|
snapshot.isDragging ? "bg-brand-surface-2 shadow-lg" : ""
|
||||||
snapshot.isDragging ? "shadow-lg" : ""
|
}`}
|
||||||
}`}
|
>
|
||||||
>
|
<Link
|
||||||
<Link
|
href={`/${workspaceSlug}/projects/${issue?.project_detail.id}/issues/${issue.id}`}
|
||||||
href={`/${workspaceSlug}/projects/${issue?.project_detail?.id}/issues/${issue.id}`}
|
>
|
||||||
className="w-full"
|
<a className="flex w-full items-center gap-2">
|
||||||
>
|
{getStateGroupIcon(
|
||||||
{issue.name}
|
issue.state_detail.group,
|
||||||
</Link>
|
"12",
|
||||||
</div>
|
"12",
|
||||||
)}
|
issue.state_detail.color
|
||||||
</Draggable>
|
)}
|
||||||
))}
|
{issue.name}
|
||||||
<div className="flex items-center justify-center p-1.5 text-sm text-brand-secondary opacity-0 group-hover:opacity-100">
|
</a>
|
||||||
<button
|
</Link>
|
||||||
className="flex items-center justify-center gap-2 text-center"
|
</div>
|
||||||
onClick={() => addIssueToDate(date.date)}
|
)}
|
||||||
|
</Draggable>
|
||||||
|
))}
|
||||||
|
{totalIssues > 4 && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="w-min whitespace-nowrap rounded-md border border-brand-base bg-brand-surface-2 px-1.5 py-1 text-xs"
|
||||||
|
onClick={() => setShowAllIssues((prevData) => !prevData)}
|
||||||
|
>
|
||||||
|
{showAllIssues ? "Hide" : totalIssues - 4 + " more"}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<div
|
||||||
|
className={`absolute ${
|
||||||
|
isMonthlyView ? "bottom-2" : "top-2"
|
||||||
|
} right-2 flex items-center justify-center rounded-md bg-brand-surface-2 p-1 text-xs text-brand-secondary opacity-0 group-hover:opacity-100`}
|
||||||
>
|
>
|
||||||
<PlusIcon className="h-4 w-4 text-brand-secondary" />
|
<button
|
||||||
Add new issue
|
className="flex items-center justify-center gap-1 text-center"
|
||||||
</button>
|
onClick={() => addIssueToDate(date.date)}
|
||||||
|
>
|
||||||
|
<PlusIcon className="h-3 w-3 text-brand-secondary" />
|
||||||
|
Add issue
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{provided.placeholder}
|
||||||
</div>
|
</div>
|
||||||
{provided.placeholder}
|
)}
|
||||||
</div>
|
</StrictModeDroppable>
|
||||||
)}
|
);
|
||||||
</StrictModeDroppable>
|
})}
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</DragDropContext>
|
</DragDropContext>
|
||||||
|
@ -426,7 +426,7 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{areFiltersApplied && (
|
{areFiltersApplied && (
|
||||||
<div className={` ${issueView === "list" ? "mt-4" : "my-4"} border-t`} />
|
<div className={`${issueView === "list" ? "mt-4" : "my-4"} border-t border-brand-base`} />
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user