Skip to content

Commit 631a23c

Browse files
committed
more work on calendar
1 parent 4d57bf8 commit 631a23c

File tree

19 files changed

+332
-131
lines changed

19 files changed

+332
-131
lines changed

src/common/utils/dateUtils.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const MS_PER_DAY = 24 * 60 * 60 * 1000;
2+
13
export function getMonthName(
24
monthIndex: number,
35
locale = "en-US",
@@ -30,3 +32,60 @@ export function isToday(
3032
day === today.getDate()
3133
);
3234
}
35+
36+
export function startOfDay(date: Date) {
37+
return new Date(
38+
date.getFullYear(),
39+
date.getMonth(),
40+
date.getDate(),
41+
0,
42+
0,
43+
0,
44+
0,
45+
);
46+
}
47+
48+
export function startOfDayUTC(date: Date) {
49+
return Date.UTC(
50+
date.getFullYear(),
51+
date.getMonth(),
52+
date.getDate(),
53+
0,
54+
0,
55+
0,
56+
0,
57+
);
58+
}
59+
60+
export function diffBetweenDates(start: Date, end: Date) {
61+
const startOfEarlier = startOfDay(start);
62+
const startOfEnd = startOfDay(end);
63+
64+
const utcEarlier = startOfDayUTC(startOfEarlier);
65+
const utcLater = startOfDayUTC(startOfEnd);
66+
67+
return Math.round((utcLater - utcEarlier) / MS_PER_DAY);
68+
}
69+
70+
export function toLocalISODateString(date: Date) {
71+
const y = date.getFullYear();
72+
const m = String(date.getMonth() + 1).padStart(2, "0");
73+
const d = String(date.getDate()).padStart(2, "0");
74+
return `${y}-${m}-${d}`;
75+
}
76+
77+
export function getSpannedDays(start: Date, end: Date): Date[] {
78+
const days: Date[] = [];
79+
let cursor = startOfDay(start);
80+
81+
while (cursor < end) {
82+
days.push(cursor);
83+
cursor = new Date(
84+
cursor.getFullYear(),
85+
cursor.getMonth(),
86+
cursor.getDate() + 1,
87+
);
88+
}
89+
90+
return days;
91+
}

src/components/BorderedApp/BorderedApp.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export interface BorderedAppContentHandles<T extends HTMLElement> {
3232
* Function for the app content (such as calculator, calendar etc) to implement
3333
* and handle keyDown events that fire from the bordered app.
3434
*/
35-
onParentKeyDown(e: React.KeyboardEvent): void;
35+
onBorderedAppKeyDown?(e: React.KeyboardEvent): void;
3636
/**
3737
* A reference to the app content's main element.
3838
*/
@@ -76,7 +76,7 @@ function BorderedApp<
7676

7777
// Listen for keyDown events and send them down to the content rendered inside the bordered app
7878
const handleKeyDown = (e: KeyboardEvent) =>
79-
contentRef.current?.onParentKeyDown(e);
79+
contentRef.current?.onBorderedAppKeyDown?.(e);
8080

8181
// Need a ref to point to the app for moving it around the screen
8282
const appRef = useRef<HTMLDivElement | null>(null);

src/hooks/useDragToResize.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ function useDragToResize({
9292
newWidth >= minDimensions.width &&
9393
(!maxDimensions || newWidth <= maxDimensions.width)
9494
) {
95-
console.log("maxwidth", maxDimensions?.width, "new width", newWidth);
9695
elementRect.current.width = newWidth;
9796
elementRef.current.style.width = `${elementRect.current.width}px`;
9897
elementRect.current.left = newLeft;

src/programs/Calculator/Calculator.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const Calculator = forwardRef<CalculatorHandles, CalculatorProps>(
4343
};
4444

4545
useImperativeHandle(ref, () => ({
46-
onParentKeyDown(e) {
46+
onBorderedAppKeyDown(e) {
4747
const { key } = e;
4848

4949
if (isDigit(key) || operators.has(key)) {

src/programs/Calendar/Calendar.tsx

Lines changed: 15 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { forwardRef, useEffect, useImperativeHandle, useRef } from "react";
1+
import { forwardRef, useImperativeHandle, useRef } from "react";
22
import useToggle from "../../hooks/useToggle";
33
import {
4-
StyledCalendarDay,
54
StyledCalendarDays,
65
StyledCalendarDaysFrame,
76
StyledCalendarLayout,
@@ -10,6 +9,8 @@ import useSystemSettings from "../../stores/systemSettingsStore";
109
import { BorderedAppContentHandles } from "../../components/BorderedApp/BorderedApp";
1110
import CalendarNavigation from "./CalendarNavigation/CalendarNavigation";
1211
import { useCalendar } from "./hooks/useCalendar";
12+
import CalendarSidebar from "./CalendarSidebar/CalendarSidebar";
13+
import CalendarDay from "./CalendarDay/CalendarDay";
1314

1415
type CalendarHandles = BorderedAppContentHandles<HTMLDivElement>;
1516

@@ -19,74 +20,40 @@ const Calendar = forwardRef<CalendarHandles, CalendarProps>((_props, ref) => {
1920
const sidebarToggle = useToggle();
2021
const calendarRef = useRef<HTMLDivElement>(null);
2122
const calendar = useCalendar();
22-
const [mainColor, accentColor, fontColor] = useSystemSettings((s) => [
23-
s.mainColor,
24-
s.accentColor,
25-
s.fontColor,
26-
]);
23+
const [accentColor] = useSystemSettings((s) => [s.accentColor]);
2724

2825
useImperativeHandle(ref, () => ({
29-
onParentKeyDown() {},
3026
element: calendarRef.current,
3127
}));
3228

33-
useEffect(() => {
34-
console.log("sidebar toggle", sidebarToggle.state);
35-
}, [sidebarToggle.state]);
36-
37-
useEffect(() => {
38-
if (!calendarRef.current) return;
39-
const el = calendarRef.current;
40-
41-
function onResize(entries: ResizeObserverEntry[]) {
42-
const entry = entries[0];
43-
if (!entry) return;
44-
45-
const width = entry.contentRect.width;
46-
47-
const wide = width >= 600;
48-
sidebarToggle.setState(wide);
49-
}
50-
51-
const observer = new ResizeObserver(onResize);
52-
53-
observer.observe(el);
54-
55-
return () => {
56-
if (el) observer.unobserve(el);
57-
observer.disconnect();
58-
};
59-
});
60-
6129
return (
6230
<StyledCalendarLayout
6331
ref={calendarRef}
6432
sidebarOpen={sidebarToggle.state}
6533
className="calendar"
6634
>
6735
<CalendarNavigation
68-
month={calendar.month}
69-
year={calendar.year}
36+
month={calendar.cursor.getMonth()}
37+
year={calendar.cursor.getFullYear()}
7038
onClickNextMonth={calendar.nextMonth}
7139
onClickNextYear={calendar.nextYear}
7240
onClickPrevMonth={calendar.prevMonth}
7341
onClickPrevYear={calendar.prevYear}
7442
/>
43+
<CalendarSidebar date={calendar.cursor} />
7544
<StyledCalendarDaysFrame frameColor={accentColor}>
7645
<StyledCalendarDays
7746
borderColor={accentColor}
7847
className="calendar__days"
7948
>
80-
{calendar.days.map(({ date, day, isToday, isThisMonth }) => (
81-
<StyledCalendarDay
82-
backgroundColor={mainColor}
83-
color={fontColor}
84-
currentMonth={isThisMonth}
85-
>
86-
<span>{day}</span>
87-
<span>{date}</span>
88-
{isToday && <span>TODAY</span>}
89-
</StyledCalendarDay>
49+
{calendar.days.map((day) => (
50+
<CalendarDay
51+
date={day.date}
52+
isThisMonth={day.isThisMonth}
53+
isToday={day.isToday}
54+
onClick={() => calendar.setCursor(day.date)}
55+
key={day.date.toISOString()}
56+
/>
9057
))}
9158
</StyledCalendarDays>
9259
</StyledCalendarDaysFrame>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { getDayName } from "../../../common/utils/dateUtils";
2+
import useSystemSettings from "../../../stores/systemSettingsStore";
3+
import { StyledCalendarDay } from "./styles";
4+
5+
interface CalendarDayProps {
6+
date: Date;
7+
isToday: boolean;
8+
isThisMonth: boolean;
9+
onClick(): void;
10+
}
11+
12+
export default function CalendarDay({
13+
date,
14+
isToday,
15+
isThisMonth,
16+
onClick,
17+
}: CalendarDayProps) {
18+
const [mainColor, fontColor] = useSystemSettings((s) => [
19+
s.mainColor,
20+
s.accentColor,
21+
s.fontColor,
22+
]);
23+
const dayOfWeek = getDayName(date.getDay());
24+
const dayOfMonth = date.getDate();
25+
26+
return (
27+
<StyledCalendarDay
28+
backgroundColor={mainColor}
29+
color={fontColor}
30+
currentMonth={isThisMonth}
31+
onClick={onClick}
32+
>
33+
<span>{dayOfWeek}</span>
34+
<span>{dayOfMonth}</span>
35+
{isToday && <span>TODAY</span>}
36+
</StyledCalendarDay>
37+
);
38+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import styled from "@emotion/styled";
2+
import { darken, lighten } from "polished";
3+
import { isLight } from "../../../common/utils/colorUtils";
4+
5+
interface StyledCalendarDayProps {
6+
backgroundColor: string;
7+
color: string;
8+
currentMonth: boolean;
9+
}
10+
11+
export const StyledCalendarDay = styled.div<StyledCalendarDayProps>`
12+
display: flex;
13+
flex-direction: column;
14+
background-color: ${(props) => props.backgroundColor};
15+
color: ${(props) =>
16+
props.currentMonth
17+
? undefined
18+
: isLight(props.color)
19+
? darken(0.3, props.color)
20+
: lighten(0.3, props.color)};
21+
transition: background-color 0.3s;
22+
:hover {
23+
background-color: ${(props) =>
24+
isLight(props.backgroundColor)
25+
? darken(0.1, props.backgroundColor)
26+
: lighten(0.1, props.backgroundColor)};
27+
}
28+
`;

src/programs/Calendar/CalendarLauncher/CalendarLauncher.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ function CalendarLauncher(_props: CalendarLauncherProps) {
1313
windowType={"calendar"}
1414
WindowTitle="Calendar"
1515
initialDimensions={{ height: 500, width: 500 }}
16+
minDimensions={{ height: 500, width: 500 }}
1617
menus={[]}
1718
appContent={<Calendar />}
1819
icon=""

src/programs/Calendar/CalendarNavigation/styles.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ interface StyledCalendarNavigationProps {}
66
export const StyledCalendarNavigation = styled.div<StyledCalendarNavigationProps>`
77
width: 100%;
88
display: flex;
9+
grid-area: nav;
910
`;
1011

1112
interface StyledNavigationButtonProps {}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// import useCalendarEvents from "../hooks/useCalendarEvents";
2+
import { StyledCalendarSidebar } from "./styles";
3+
4+
interface CalendarSidebarProps {
5+
date: Date;
6+
}
7+
8+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
9+
export default function CalendarSidebar({ date }: CalendarSidebarProps) {
10+
// const events = useCalendarEvents({ date });
11+
return (
12+
<StyledCalendarSidebar className="calendar__side-bar">
13+
{date.toISOString()}
14+
</StyledCalendarSidebar>
15+
);
16+
}

0 commit comments

Comments
 (0)