mirror of
https://github.com/hex248/sprint.git
synced 2026-02-08 02:33:01 +00:00
made the sprint date selection beautiful
shows existing sprint dates
This commit is contained in:
@@ -49,10 +49,12 @@ const getDefaultDates = () => {
|
|||||||
|
|
||||||
export function CreateSprint({
|
export function CreateSprint({
|
||||||
projectId,
|
projectId,
|
||||||
|
sprints,
|
||||||
trigger,
|
trigger,
|
||||||
completeAction,
|
completeAction,
|
||||||
}: {
|
}: {
|
||||||
projectId?: number;
|
projectId?: number;
|
||||||
|
sprints: SprintRecord[];
|
||||||
trigger?: React.ReactNode;
|
trigger?: React.ReactNode;
|
||||||
completeAction?: (sprint: SprintRecord) => void | Promise<void>;
|
completeAction?: (sprint: SprintRecord) => void | Promise<void>;
|
||||||
}) {
|
}) {
|
||||||
@@ -203,6 +205,7 @@ export function CreateSprint({
|
|||||||
setStartDate(getStartOfDay(value));
|
setStartDate(getStartOfDay(value));
|
||||||
}}
|
}}
|
||||||
autoFocus
|
autoFocus
|
||||||
|
sprints={sprints}
|
||||||
/>
|
/>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
@@ -225,6 +228,8 @@ export function CreateSprint({
|
|||||||
setEndDate(getEndOfDay(value));
|
setEndDate(getEndOfDay(value));
|
||||||
}}
|
}}
|
||||||
autoFocus
|
autoFocus
|
||||||
|
sprints={sprints}
|
||||||
|
isEnd
|
||||||
/>
|
/>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|||||||
@@ -682,6 +682,7 @@ function OrganisationsDialog({
|
|||||||
<Plus className="size-4" />
|
<Plus className="size-4" />
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
|
sprints={sprints}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { SprintRecord } from "@sprint/shared";
|
||||||
import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { type DayButton, DayPicker, getDefaultClassNames } from "react-day-picker";
|
import { type DayButton, DayPicker, getDefaultClassNames } from "react-day-picker";
|
||||||
@@ -12,9 +13,13 @@ function Calendar({
|
|||||||
buttonVariant = "ghost",
|
buttonVariant = "ghost",
|
||||||
formatters,
|
formatters,
|
||||||
components,
|
components,
|
||||||
|
sprints,
|
||||||
|
isEnd,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof DayPicker> & {
|
}: React.ComponentProps<typeof DayPicker> & {
|
||||||
buttonVariant?: React.ComponentProps<typeof Button>["variant"];
|
buttonVariant?: React.ComponentProps<typeof Button>["variant"];
|
||||||
|
sprints?: SprintRecord[];
|
||||||
|
isEnd?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const defaultClassNames = getDefaultClassNames();
|
const defaultClassNames = getDefaultClassNames();
|
||||||
|
|
||||||
@@ -113,7 +118,7 @@ function Calendar({
|
|||||||
|
|
||||||
return <ChevronDownIcon className={cn("size-4", className)} {...props} />;
|
return <ChevronDownIcon className={cn("size-4", className)} {...props} />;
|
||||||
},
|
},
|
||||||
DayButton: CalendarDayButton,
|
DayButton: (props) => <CalendarDayButton {...props} sprints={sprints} isEnd={isEnd} />,
|
||||||
WeekNumber: ({ children, ...props }) => {
|
WeekNumber: ({ children, ...props }) => {
|
||||||
return (
|
return (
|
||||||
<td {...props}>
|
<td {...props}>
|
||||||
@@ -130,7 +135,16 @@ function Calendar({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CalendarDayButton({ className, day, modifiers, ...props }: React.ComponentProps<typeof DayButton>) {
|
function CalendarDayButton({
|
||||||
|
className,
|
||||||
|
day,
|
||||||
|
modifiers,
|
||||||
|
sprints,
|
||||||
|
style,
|
||||||
|
disabled,
|
||||||
|
isEnd,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof DayButton> & { sprints?: SprintRecord[]; isEnd?: boolean }) {
|
||||||
const defaultClassNames = getDefaultClassNames();
|
const defaultClassNames = getDefaultClassNames();
|
||||||
|
|
||||||
const ref = React.useRef<HTMLButtonElement>(null);
|
const ref = React.useRef<HTMLButtonElement>(null);
|
||||||
@@ -138,6 +152,16 @@ function CalendarDayButton({ className, day, modifiers, ...props }: React.Compon
|
|||||||
if (modifiers.focused) ref.current?.focus();
|
if (modifiers.focused) ref.current?.focus();
|
||||||
}, [modifiers.focused]);
|
}, [modifiers.focused]);
|
||||||
|
|
||||||
|
let isDisabled = false;
|
||||||
|
let sprint: SprintRecord | null = null;
|
||||||
|
|
||||||
|
for (const entry of sprints || []) {
|
||||||
|
if (day.date >= new Date(entry.startDate) && day.date <= new Date(entry.endDate)) {
|
||||||
|
isDisabled = true;
|
||||||
|
sprint = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
ref={ref}
|
ref={ref}
|
||||||
@@ -156,14 +180,34 @@ function CalendarDayButton({ className, day, modifiers, ...props }: React.Compon
|
|||||||
className={cn(
|
className={cn(
|
||||||
"flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal",
|
"flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal",
|
||||||
"[&>span]:text-xs [&>span]:opacity-70",
|
"[&>span]:text-xs [&>span]:opacity-70",
|
||||||
"hover:bg-primary/90 hover:text-foreground",
|
!sprint?.color && "hover:bg-primary/90 hover:text-foreground",
|
||||||
"data-[selected-single=true]:!bg-foreground data-[selected-single=true]:!text-background data-[selected-single=true]:hover:!bg-foreground/90",
|
"data-[selected-single=true]:!bg-foreground data-[selected-single=true]:!text-background data-[selected-single=true]:hover:!bg-foreground/90",
|
||||||
"data-[range-start=true]:!bg-foreground data-[range-start=true]:!text-background",
|
"data-[range-start=true]:!bg-foreground data-[range-start=true]:!text-background",
|
||||||
"data-[range-middle=true]:!bg-foreground data-[range-middle=true]:!text-background",
|
"data-[range-middle=true]:!bg-foreground data-[range-middle=true]:!text-background",
|
||||||
"data-[range-end=true]:!bg-foreground data-[range-end=true]:!text-background",
|
"data-[range-end=true]:!bg-foreground data-[range-end=true]:!text-background",
|
||||||
|
sprint?.color && "border-t border-b !border-(--sprint-color) !bg-(--sprint-color)/5",
|
||||||
defaultClassNames.day,
|
defaultClassNames.day,
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
...style,
|
||||||
|
"--sprint-color": sprint?.color ? sprint.color : null,
|
||||||
|
"border-left":
|
||||||
|
sprint && day.date.getUTCDate() === new Date(sprint.startDate).getUTCDate()
|
||||||
|
? `1px solid ${sprint?.color}`
|
||||||
|
: day.date.getDay() === 0 // sunday (left side)
|
||||||
|
? `1px dashed ${sprint?.color}`
|
||||||
|
: `0px`,
|
||||||
|
"border-right":
|
||||||
|
sprint && day.date.getUTCDate() === new Date(sprint.endDate).getUTCDate()
|
||||||
|
? `1px solid ${sprint?.color}`
|
||||||
|
: day.date.getDay() === 6 // saturday (right side)
|
||||||
|
? `1px dashed ${sprint?.color}`
|
||||||
|
: `0px`,
|
||||||
|
} as React.CSSProperties
|
||||||
|
}
|
||||||
|
disabled={isDisabled || disabled}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user