calendar QoL changes

This commit is contained in:
2026-01-24 12:50:23 +00:00
parent 5b9a326d27
commit a6a58260f8
3 changed files with 66 additions and 16 deletions

View File

@@ -243,6 +243,7 @@ export function SprintForm({
<PopoverContent className="w-auto p-0" align="center">
<Calendar
mode="single"
currentSprint={{ colour, startDate, endDate }}
selected={startDate}
onSelect={(value) => {
if (!value) return;
@@ -250,6 +251,9 @@ export function SprintForm({
}}
autoFocus
sprints={calendarSprints}
showWeekNumber
showOutsideDays={false}
defaultMonth={startDate}
/>
</PopoverContent>
</Popover>
@@ -266,6 +270,7 @@ export function SprintForm({
<PopoverContent className="w-auto p-0" align="center">
<Calendar
mode="single"
currentSprint={{ colour, startDate, endDate }}
selected={endDate}
onSelect={(value) => {
if (!value) return;
@@ -274,6 +279,9 @@ export function SprintForm({
autoFocus
sprints={calendarSprints}
isEnd
showWeekNumber
showOutsideDays={false}
defaultMonth={endDate}
/>
</PopoverContent>
</Popover>

View File

@@ -5,7 +5,7 @@ import { Button, buttonVariants } from "@/components/ui/button";
import Icon from "@/components/ui/icon";
import { cn } from "@/lib/utils";
function Calendar({
export function Calendar({
className,
classNames,
showOutsideDays = true,
@@ -15,11 +15,13 @@ function Calendar({
components,
sprints,
isEnd,
currentSprint,
...props
}: React.ComponentProps<typeof DayPicker> & {
buttonVariant?: React.ComponentProps<typeof Button>["variant"];
sprints?: SprintRecord[];
isEnd?: boolean;
currentSprint?: { colour: string; startDate: Date; endDate: Date };
}) {
const defaultClassNames = getDefaultClassNames();
@@ -112,7 +114,9 @@ function Calendar({
return <Icon icon="chevronDownIcon" className={cn("size-4", className)} {...props} />;
},
DayButton: (props) => <CalendarDayButton {...props} sprints={sprints} isEnd={isEnd} />,
DayButton: (props) => (
<CalendarDayButton {...props} sprints={sprints} isEnd={isEnd} currentSprint={currentSprint} />
),
WeekNumber: ({ children, ...props }) => {
return (
<td {...props}>
@@ -129,7 +133,7 @@ function Calendar({
);
}
function CalendarDayButton({
export function CalendarDayButton({
className,
day,
modifiers,
@@ -137,8 +141,13 @@ function CalendarDayButton({
style,
disabled,
isEnd,
currentSprint,
...props
}: React.ComponentProps<typeof DayButton> & { sprints?: SprintRecord[]; isEnd?: boolean }) {
}: React.ComponentProps<typeof DayButton> & {
sprints?: SprintRecord[];
isEnd?: boolean;
currentSprint?: { colour: string; startDate: Date; endDate: Date };
}) {
const defaultClassNames = getDefaultClassNames();
const ref = React.useRef<HTMLButtonElement>(null);
@@ -172,11 +181,47 @@ function CalendarDayButton({
"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",
!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",
!currentSprint?.startDate &&
"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-middle=true]:!bg-foreground data-[range-middle=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",
// part of new sprint
currentSprint?.startDate &&
currentSprint?.endDate &&
day.date >= currentSprint?.startDate &&
day.date <= currentSprint?.endDate &&
"!border-t !border-b !border-(--current-sprint-color) !bg-(--current-sprint-color)/5 hover:!bg-(--current-sprint-color)/50 border-dashed",
// is start of new sprint
currentSprint?.startDate &&
day.date.getDate() === currentSprint?.startDate.getDate() &&
day.date.getMonth() === currentSprint?.startDate.getMonth() &&
"!border-l !border-(--current-sprint-color)",
// is start of new sprint
currentSprint?.endDate &&
day.date.getDate() === currentSprint?.endDate.getDate() &&
day.date.getMonth() === currentSprint?.endDate.getMonth() &&
"!border-r !border-(--current-sprint-color)",
// is selected
"data-[selected-single=true]:!bg-(--current-sprint-color)/75 data-[selected-single=true]:hover:!bg-(--current-sprint-color)/60",
// is start and after end date (disable)
!isEnd &&
currentSprint?.endDate &&
day.date > currentSprint?.endDate &&
"opacity-50 pointer-events-none cursor-not-allowed",
// isEnd and before start date (disable)
isEnd &&
currentSprint?.startDate &&
day.date < currentSprint?.startDate &&
"opacity-50 pointer-events-none cursor-not-allowed",
defaultClassNames.day,
className,
)}
@@ -184,6 +229,7 @@ function CalendarDayButton({
{
...style,
"--sprint-color": sprint?.color ? sprint.color : null,
"--current-sprint-color": currentSprint?.colour ? currentSprint.colour : null,
borderLeft:
sprint && day.date.getUTCDate() === new Date(sprint.startDate).getUTCDate()
? `1px solid ${sprint?.color}`
@@ -203,5 +249,3 @@ function CalendarDayButton({
/>
);
}
export { Calendar, CalendarDayButton };

16
todo.md
View File

@@ -1,19 +1,19 @@
# HIGH PRIORITY
- BUGS:
- date picker opens at today's date instead of the selected date
- january: date picker is above, february: date picker is below (likely due to how many rows worth of sprints are displayed) - -my-1/-m-px on dates that have a sprint
- FEATURES:
- issues
- issue type (options stored on Organisation)
- filters
# LOW PRIORITY
- setup guide
- time tracking:
- add overlay in the bottom left for active timers if there are any. this should be minimal with the issue key (API-005), the time, and a play/pause + end button
- pricing page
- see jira and other competitors
- explore payment providers (stripe is the only one i know)
# LOW PRIORITY
- disable self-hosting stuff
- make closed source
- dedicated /register route (currently login/register are combined on /login)
- real logo
- org settings
@@ -26,8 +26,6 @@
- deadline
- comments
- admins are capable of deleting comments from members who are at their permission level or below (not sure if this should apply, or if ANYONE should have control over others' comments - people in an org tend to be trusted to not be trolls)
- time tracking:
- add overlay in the bottom left for active timers if there are any. this should be minimal with the issue key (API-005), the time, and a play/pause + end button
- user preferences
- colour scheme
- "assign to me by default" option for new issues