-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add fullscreen calendar component
- Loading branch information
1 parent
f07c7ad
commit 83ddac6
Showing
18 changed files
with
1,337 additions
and
0 deletions.
There are no files selected for viewing
9 changes: 9 additions & 0 deletions
9
apps/www/__registry__/default/blocks/fullscreen-calendar/page.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { FullScreenCalendar } from "@/registry/default/blocks/fullscreen-calendar/components/fullscreen-calendar" | ||
|
||
export default function Page() { | ||
return ( | ||
<div className="flex h-screen flex-1 flex-col"> | ||
<FullScreenCalendar /> | ||
</div> | ||
) | ||
} |
9 changes: 9 additions & 0 deletions
9
apps/www/__registry__/new-york/blocks/fullscreen-calendar/page.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { FullScreenCalendar } from "@/registry/new-york/blocks/fullscreen-calendar/components/fullscreen-calendar" | ||
|
||
export default function Page() { | ||
return ( | ||
<div className="flex h-screen flex-1 flex-col"> | ||
<FullScreenCalendar /> | ||
</div> | ||
) | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
50 changes: 50 additions & 0 deletions
50
apps/www/public/r/styles/new-york/fullscreen-calendar.json
Large diffs are not rendered by default.
Oops, something went wrong.
174 changes: 174 additions & 0 deletions
174
apps/www/registry/default/blocks/fullscreen-calendar/components/fullscreen-calendar-day.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
"use client" | ||
|
||
import React from "react" | ||
import { | ||
format, | ||
getDay, | ||
isEqual, | ||
isSameDay, | ||
isSameMonth, | ||
isToday, | ||
} from "date-fns" | ||
|
||
import { cn } from "@/lib/utils" | ||
import { useMediaQuery } from "@/hooks/use-media-query" | ||
|
||
interface FullscreenCalendarDayProps { | ||
day: Date | ||
selectedDay: Date | ||
setSelectedDay: React.Dispatch<React.SetStateAction<Date>> | ||
firstDayCurrentMonth: Date | ||
dayIndex: number | ||
data: { | ||
day: Date | ||
events: { | ||
id: number | ||
name: string | ||
time: string | ||
datetime: string | ||
}[] | ||
}[] | ||
} | ||
|
||
const colStartClasses = [ | ||
"", | ||
"col-start-2", | ||
"col-start-3", | ||
"col-start-4", | ||
"col-start-5", | ||
"col-start-6", | ||
"col-start-7", | ||
] | ||
|
||
export function FullScreenCalendarDay({ | ||
day, | ||
selectedDay, | ||
setSelectedDay, | ||
firstDayCurrentMonth, | ||
dayIndex, | ||
data, | ||
}: FullscreenCalendarDayProps) { | ||
const isDesktop = useMediaQuery("(min-width: 768px)") | ||
|
||
if (!isDesktop) { | ||
return ( | ||
<button | ||
onClick={() => setSelectedDay(day)} | ||
key={dayIndex} | ||
type="button" | ||
className={cn( | ||
isEqual(day, selectedDay) && "text-primary-foreground", | ||
!isEqual(day, selectedDay) && | ||
!isToday(day) && | ||
isSameMonth(day, firstDayCurrentMonth) && | ||
"text-foreground", | ||
!isEqual(day, selectedDay) && | ||
!isToday(day) && | ||
!isSameMonth(day, firstDayCurrentMonth) && | ||
"text-muted-foreground", | ||
(isEqual(day, selectedDay) || isToday(day)) && "font-semibold", | ||
"flex h-14 flex-col border-b border-r px-3 py-2 hover:bg-muted focus:z-10" | ||
)} | ||
> | ||
<time | ||
dateTime={format(day, "yyyy-MM-dd")} | ||
className={cn( | ||
"ml-auto flex size-6 items-center justify-center rounded-full", | ||
isEqual(day, selectedDay) && | ||
isToday(day) && | ||
"bg-primary text-primary-foreground", | ||
isEqual(day, selectedDay) && | ||
!isToday(day) && | ||
"bg-primary text-primary-foreground" | ||
)} | ||
> | ||
{format(day, "d")} | ||
</time> | ||
{data.filter((date) => isSameDay(date.day, day)).length > 0 && ( | ||
<div> | ||
{data | ||
.filter((date) => isSameDay(date.day, day)) | ||
.map((date) => ( | ||
<div | ||
key={date.day.toString()} | ||
className="-mx-0.5 mt-auto flex flex-wrap-reverse" | ||
> | ||
{date.events.map((event) => ( | ||
<span | ||
key={event.id} | ||
className="mx-0.5 mt-1 h-1.5 w-1.5 rounded-full bg-muted-foreground" | ||
/> | ||
))} | ||
</div> | ||
))} | ||
</div> | ||
)} | ||
</button> | ||
) | ||
} | ||
|
||
return ( | ||
<div | ||
key={dayIndex} | ||
onClick={() => setSelectedDay(day)} | ||
className={cn( | ||
dayIndex === 0 && colStartClasses[getDay(day)], | ||
!isEqual(day, selectedDay) && | ||
!isToday(day) && | ||
!isSameMonth(day, firstDayCurrentMonth) && | ||
"bg-accent/50 text-muted-foreground", | ||
"relative flex flex-col border-b border-r hover:bg-muted focus:z-10", | ||
!isEqual(day, selectedDay) && "hover:bg-accent/75" | ||
)} | ||
> | ||
<header className="flex items-center justify-between p-2.5"> | ||
<button | ||
type="button" | ||
className={cn( | ||
isEqual(day, selectedDay) && "text-primary-foreground", | ||
!isEqual(day, selectedDay) && | ||
!isToday(day) && | ||
isSameMonth(day, firstDayCurrentMonth) && | ||
"text-foreground", | ||
!isEqual(day, selectedDay) && | ||
!isToday(day) && | ||
!isSameMonth(day, firstDayCurrentMonth) && | ||
"text-muted-foreground", | ||
isEqual(day, selectedDay) && | ||
isToday(day) && | ||
"border-none bg-primary", | ||
isEqual(day, selectedDay) && !isToday(day) && "bg-foreground", | ||
(isEqual(day, selectedDay) || isToday(day)) && "font-semibold", | ||
"flex h-7 w-7 items-center justify-center rounded-full text-xs hover:border" | ||
)} | ||
> | ||
<time dateTime={format(day, "yyyy-MM-dd")}>{format(day, "d")}</time> | ||
</button> | ||
</header> | ||
<div className="flex-1 p-2.5"> | ||
{data | ||
.filter((event) => isSameDay(event.day, day)) | ||
.map((day) => ( | ||
<div key={day.day.toString()} className="space-y-1.5"> | ||
{day.events.slice(0, 1).map((event) => ( | ||
<div | ||
key={event.id} | ||
className="flex flex-col items-start gap-1 rounded-lg border bg-muted/50 p-2 text-xs leading-tight" | ||
> | ||
<p className="font-medium leading-none">{event.name}</p> | ||
<p className="leading-none text-muted-foreground"> | ||
{event.time} | ||
</p> | ||
</div> | ||
))} | ||
{day.events.length > 1 && ( | ||
<div className="text-xs text-muted-foreground"> | ||
+ {day.events.length - 1} more | ||
</div> | ||
)} | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
) | ||
} |
105 changes: 105 additions & 0 deletions
105
...www/registry/default/blocks/fullscreen-calendar/components/fullscreen-calendar-header.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
"use client" | ||
|
||
import React from "react" | ||
import { format, startOfToday } from "date-fns" | ||
import { | ||
ChevronLeftIcon, | ||
ChevronRightIcon, | ||
PlusCircleIcon, | ||
SearchIcon, | ||
} from "lucide-react" | ||
|
||
import { Button } from "@/registry/default/ui/button" | ||
import { Separator } from "@/registry/default/ui/separator" | ||
|
||
interface FullScreenCalendarHeaderProps { | ||
startOfMonth: Date | ||
endOfMonth: Date | ||
nextMonth: () => void | ||
goToToday: () => void | ||
previousMonth: () => void | ||
} | ||
|
||
export function FullScreenCalendarHeader({ | ||
nextMonth, | ||
goToToday, | ||
previousMonth, | ||
startOfMonth, | ||
endOfMonth, | ||
}: FullScreenCalendarHeaderProps) { | ||
const today = startOfToday() | ||
|
||
return ( | ||
<div className="flex flex-col space-y-4 p-4 md:flex-row md:items-center md:justify-between md:space-y-0 lg:flex-none"> | ||
<div className="flex flex-auto"> | ||
<div className="flex items-center gap-4"> | ||
<div className="hidden w-20 flex-col items-center justify-center rounded-lg border bg-muted p-0.5 md:flex"> | ||
<h1 className="p-1 text-xs uppercase text-muted-foreground"> | ||
{format(today, "MMM")} | ||
</h1> | ||
<div className="flex w-full items-center justify-center rounded-lg border bg-background p-0.5 text-lg font-bold"> | ||
<span>{format(today, "d")}</span> | ||
</div> | ||
</div> | ||
<div className="flex flex-col"> | ||
<h2 className="text-lg font-semibold text-foreground"> | ||
{format(startOfMonth, "MMMM, yyyy")} | ||
</h2> | ||
<p className="text-sm text-muted-foreground"> | ||
{format(startOfMonth, "MMM d, yyyy")} -{" "} | ||
{format(endOfMonth, "MMM d, yyyy")} | ||
</p> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<div className="flex flex-col items-center gap-4 md:flex-row md:gap-6"> | ||
<Button variant="outline" size="icon" className="hidden lg:flex"> | ||
<SearchIcon size={16} strokeWidth={2} aria-hidden="true" /> | ||
</Button> | ||
|
||
<Separator orientation="vertical" className="hidden h-6 lg:block" /> | ||
|
||
<div className="inline-flex w-full -space-x-px rounded-lg shadow-sm shadow-black/5 md:w-auto rtl:space-x-reverse"> | ||
<Button | ||
onClick={previousMonth} | ||
className="rounded-none shadow-none first:rounded-s-lg last:rounded-e-lg focus-visible:z-10" | ||
variant="outline" | ||
size="icon" | ||
aria-label="Navigate to previous month" | ||
> | ||
<ChevronLeftIcon size={16} strokeWidth={2} aria-hidden="true" /> | ||
</Button> | ||
<Button | ||
onClick={goToToday} | ||
className="w-full rounded-none shadow-none first:rounded-s-lg last:rounded-e-lg focus-visible:z-10 md:w-auto" | ||
variant="outline" | ||
> | ||
Today | ||
</Button> | ||
<Button | ||
onClick={nextMonth} | ||
className="rounded-none shadow-none first:rounded-s-lg last:rounded-e-lg focus-visible:z-10" | ||
variant="outline" | ||
size="icon" | ||
aria-label="Navigate to next month" | ||
> | ||
<ChevronRightIcon size={16} strokeWidth={2} aria-hidden="true" /> | ||
</Button> | ||
</div> | ||
|
||
<Separator orientation="vertical" className="hidden h-6 md:block" /> | ||
|
||
<Separator | ||
orientation="horizontal" | ||
className="block w-full md:hidden" | ||
/> | ||
|
||
<Button className="w-full gap-2 md:w-auto"> | ||
<PlusCircleIcon size={16} strokeWidth={2} aria-hidden="true" /> | ||
<span>New Event</span> | ||
</Button> | ||
</div> | ||
</div> | ||
) | ||
} |
15 changes: 15 additions & 0 deletions
15
.../registry/default/blocks/fullscreen-calendar/components/fullscreen-calendar-week-days.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import React from "react" | ||
|
||
export function FullScreenCalendarWeekDays() { | ||
return ( | ||
<div className="grid grid-cols-7 border text-center text-xs font-semibold leading-6 lg:flex-none"> | ||
<div className="border-r py-2.5">Sun</div> | ||
<div className="border-r py-2.5">Mon</div> | ||
<div className="border-r py-2.5">Tue</div> | ||
<div className="border-r py-2.5">Wed</div> | ||
<div className="border-r py-2.5">Thu</div> | ||
<div className="border-r py-2.5">Fri</div> | ||
<div className="py-2.5">Sat</div> | ||
</div> | ||
) | ||
} |
Oops, something went wrong.