Skip to content

Commit

Permalink
feat: add fullscreen calendar component
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmedmayara committed Jan 16, 2025
1 parent f07c7ad commit 83ddac6
Show file tree
Hide file tree
Showing 18 changed files with 1,337 additions and 0 deletions.
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>
)
}
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>
)
}
50 changes: 50 additions & 0 deletions apps/www/public/r/styles/default/fullscreen-calendar.json

Large diffs are not rendered by default.

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 apps/www/public/r/styles/new-york/fullscreen-calendar.json

Large diffs are not rendered by default.

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>
)
}
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>
)
}
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>
)
}
Loading

0 comments on commit 83ddac6

Please sign in to comment.