* storybook v2 init * Merge config into storybook vite build * Remove path * Storybook config tweaks * Added styles and settings for storybook v2, and started working on button documentation and examples. * Badges + flex wrap on mobile * Breadcrumbs+button+avatar * Checkbox * Input + moving files around * WIP table * WIP table grid * Replaced imports for new components. * Added first steps for varianttable. * Small alignment fix. * Custom Args Table - With scrollbar * Adding table to components that need it + darkmode * Add intro * Fix types * Remove V1 storybook and replace with V2 * Fix badge type error * Fixed storybook dependencies * Added cover image to storybook * Remove vita from ts config, we dont use vite. * Fixed button import. * Explained postcss pseudo plugin. * Fixed badge import. * Add Avatar Stories * ButtonGroup Stories * Fixed imports * Add checkbox stories * Inital state plannning * Inital state combined with passed in props * Start of UI work * Able to change dates? * Add dynamic hour props * Get grid system setup correctly * Show events on grid * Weird sizing issue but events placed correctly gridstart * CAL styled calendar event component * availability WIP ish * Blocking days! + Block days < today * Kinda working time line * Rename grid stop + formatting * Handle sorting events if required. * Add util for getting startDate bassed on weekday * Remove event stories for now * Implement gridstops per hour to be dyamic * New CSS Grid + offsetbased positoning * Fix weird Z-Index issues on hover * Implement blocklist again with new format * Side by side events working - styling needs work * New design of overlap * Overlapping? Working :O * Cleanup * WIP hover state * Werid border issue * fix translate issue * Kinda working with overflow * Fix overflow * Progressive date blocking * Cleanup * Fix double render of blocked list * WIP mobile implementaiton * Trying to fix CSS * Extract CSS to styles.css to allow media queries * Improve documentation - allow args to be changed in storybook * Fix hover showing even if disabled * WIP cols auto approach * Merge blocking dates * Fix zindex * Fix hover position * Fix Z-Index issues on hover and blocking events * Re add onclick handler * Fix overlapping blocking dates * Fix scaling for datevalues columns * Date values closer to DS * Blocked List Tidy up * Storybook + file tidy up * Little tidy up * Fix offsets * Remove event hover * Fix random bg-red-500 * Fix import * FIx blocking cells appearing above start Date * Fix truncation * Fix border overlap * Overlap a little nicer * Condtional 80% sizing * Nitpicks * Fix today height and top breaking * Add text left to time stamp * Support string dates * Add shalow to reduce re-renders * Rename to Calendar instead of scheduler * Fix 3 overlapping events * Fix merge type error * Fix destructuring * NITS * Move to features package Co-authored-by: Jeroen Reumkens <hello@jeroenreumkens.nl> Co-authored-by: zomars <zomars@me.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
130 lines
3.9 KiB
TypeScript
130 lines
3.9 KiB
TypeScript
import { useMemo } from "react";
|
|
import shallow from "zustand/shallow";
|
|
|
|
import dayjs from "@calcom/dayjs";
|
|
|
|
import { useCalendarStore } from "../../state/store";
|
|
import { BlockedTimeCell } from "./BlockedTimeCell";
|
|
|
|
type Props = {
|
|
day: dayjs.Dayjs;
|
|
containerRef: React.RefObject<HTMLDivElement>;
|
|
};
|
|
|
|
function roundX(x: number, roundBy: number) {
|
|
return Math.round(x / roundBy) * roundBy;
|
|
}
|
|
|
|
type BlockedDayProps = {
|
|
startHour: number;
|
|
endHour: number;
|
|
day: dayjs.Dayjs;
|
|
};
|
|
|
|
function BlockedBeforeToday({ day, startHour, endHour }: BlockedDayProps) {
|
|
return (
|
|
<>
|
|
{day.isBefore(dayjs(), "day") && (
|
|
<div
|
|
key={day.format("YYYY-MM-DD")}
|
|
className="absolute z-40 w-full"
|
|
style={{
|
|
top: `var(--one-minute-height)`,
|
|
zIndex: 60,
|
|
height: `calc(${(endHour + 1 - startHour) * 60} * var(--one-minute-height))`, // Add 1 to endHour to include the last hour that we add to display the last vertical line
|
|
}}>
|
|
<BlockedTimeCell />
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
}
|
|
function BlockedToday({
|
|
day,
|
|
startHour,
|
|
gridCellsPerHour,
|
|
endHour,
|
|
}: BlockedDayProps & { gridCellsPerHour: number }) {
|
|
const dayStart = useMemo(() => day.startOf("day").hour(startHour), [day, startHour]);
|
|
const dayEnd = useMemo(() => day.startOf("day").hour(endHour), [day, endHour]);
|
|
const dayEndInMinutes = useMemo(() => dayEnd.diff(dayStart, "minutes"), [dayEnd, dayStart]);
|
|
let nowComparedToDayStart = useMemo(() => dayjs().diff(dayStart, "minutes"), [dayStart]);
|
|
|
|
if (nowComparedToDayStart > dayEndInMinutes) nowComparedToDayStart = dayEndInMinutes;
|
|
|
|
return (
|
|
<>
|
|
{day.isToday() && (
|
|
<div
|
|
key={day.format("YYYY-MM-DD")}
|
|
className="absolute z-40 w-full"
|
|
style={{
|
|
top: `var(--one-minute-height)`, // Still need this as this var takes into consideration the offset of the "AllDayEvents" bar
|
|
zIndex: 60,
|
|
height: `calc(${roundX(
|
|
nowComparedToDayStart,
|
|
60 / gridCellsPerHour
|
|
)} * var(--one-minute-height) - 2px)`, // We minus the border width to make it 🧹
|
|
}}>
|
|
<BlockedTimeCell />
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
}
|
|
|
|
export function BlockedList({ day }: Props) {
|
|
const { startHour, blockingDates, endHour, gridCellsPerHour } = useCalendarStore(
|
|
(state) => ({
|
|
startHour: state.startHour || 0,
|
|
endHour: state.endHour || 23,
|
|
blockingDates: state.blockingDates,
|
|
gridCellsPerHour: state.gridCellsPerHour || 4,
|
|
}),
|
|
shallow
|
|
);
|
|
|
|
return (
|
|
<>
|
|
<BlockedBeforeToday day={day} startHour={startHour} endHour={endHour} />
|
|
<BlockedToday gridCellsPerHour={gridCellsPerHour} day={day} startHour={startHour} endHour={endHour} />
|
|
{blockingDates &&
|
|
blockingDates.map((event, i) => {
|
|
const dayStart = day.startOf("day").hour(startHour);
|
|
const blockingStart = dayjs(event.start);
|
|
const eventEnd = dayjs(event.end);
|
|
|
|
const eventStart = dayStart.isAfter(blockingStart) ? dayStart : blockingStart;
|
|
|
|
if (!eventStart.isSame(day, "day")) {
|
|
return null;
|
|
}
|
|
|
|
if (eventStart.isBefore(dayjs())) {
|
|
if (eventEnd.isBefore(dayjs())) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
const eventDuration = eventEnd.diff(eventStart, "minutes");
|
|
|
|
const eventStartHour = eventStart.hour();
|
|
const eventStartDiff = (eventStartHour - (startHour || 0)) * 60;
|
|
|
|
return (
|
|
<div
|
|
key={`${eventStart.toISOString()}-${i}`}
|
|
className="absolute w-full"
|
|
style={{
|
|
zIndex: 60,
|
|
top: `calc(${eventStartDiff}*var(--one-minute-height))`,
|
|
height: `calc(${eventDuration}*var(--one-minute-height))`,
|
|
}}>
|
|
<BlockedTimeCell />
|
|
</div>
|
|
);
|
|
})}
|
|
</>
|
|
);
|
|
}
|