From 855ce24fc11e02fad0d09e50dfaad185972f118b Mon Sep 17 00:00:00 2001 From: Braden Currah Date: Sun, 7 Dec 2025 23:55:41 -0800 Subject: [PATCH] Add basic calendar widget --- src/WidgetMap.tsx | 6 +++ src/widgets/Calendar.css | 83 ++++++++++++++++++++++++++++++++++++++ src/widgets/Calendar.tsx | 86 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 src/widgets/Calendar.css create mode 100644 src/widgets/Calendar.tsx diff --git a/src/WidgetMap.tsx b/src/WidgetMap.tsx index aaa031d..6af88b3 100644 --- a/src/WidgetMap.tsx +++ b/src/WidgetMap.tsx @@ -1,4 +1,5 @@ import { BatteryWidget } from "./widgets/BatteryWidget"; +import { Calendar, CalendarSettings } from "./widgets/Calendar"; import { Clock, ClockSettings } from "./widgets/Clock"; import { Notepad } from "./widgets/Notepad"; import { Search, SearchSettings } from "./widgets/Search"; @@ -12,6 +13,11 @@ const WidgetMap = { size: { width: 2, height: 1 }, }, + calendar: { + component: Calendar, + size: { width: 6, height: 6 }, + }, + clock: { component: Clock, size: { width: 4, height: 2 }, diff --git a/src/widgets/Calendar.css b/src/widgets/Calendar.css new file mode 100644 index 0000000..49e37a3 --- /dev/null +++ b/src/widgets/Calendar.css @@ -0,0 +1,83 @@ +.body { + display: flex; + flex-flow: column nowrap; + position: relative; + width: 100%; + height: 100%; + padding: 8px; + gap: 4px; +} + +.header { + width: 100%; + display: flex; + flex-flow: row nowrap; + justify-content: center; +} + +.selector { + width: 21ch; + display: flex; + justify-content: space-between; + align-items: center; + font-weight: 700; + color: #fffc; + gap: 8px; +} + +.selector-button { + display: flex; + align-items: center; + cursor: pointer; + background-color: transparent; + border: 1px solid transparent; + border-radius: 4px; + color: #fffc; + padding: 2px; + transition: + background-color 0.15s, + border-color 0.15s; +} + +.selector-button:hover { + background-color: #0002; + border: 1px solid #fff2; +} + +.day-names { + display: grid; + grid-template-columns: repeat(7, 1fr); + text-align: center; + font-size: 0.8rem; + color: #fff8; +} + +.month { + width: 100%; + height: 100%; + display: grid; + grid-template-rows: repeat(6, 1fr); + grid-template-columns: repeat(7, 1fr); + gap: 4px; +} + +.day { + background-color: #0002; + border: 1px solid #fff2; + border-radius: 8px; +} + +.day.active { + background-color: #0004; +} + +.day.today { + border: 1px solid #fff4; + background-color: #fff2; +} + +.day span { + font-size: 0.8rem; + color: #fff8; + padding: 2px 4px; +} diff --git a/src/widgets/Calendar.tsx b/src/widgets/Calendar.tsx new file mode 100644 index 0000000..fc54fc6 --- /dev/null +++ b/src/widgets/Calendar.tsx @@ -0,0 +1,86 @@ +import React, { useEffect, useState } from "react"; +import { WidgetState } from "../Widget"; +import globalStyles from "../App.css"; +import styles from "./Calendar.css"; +import { CaretLeftIcon, CaretRightIcon } from "@phosphor-icons/react"; + +export interface CalendarSettings {} + +export function Calendar({ settings }: WidgetState) { + const [date, setDate] = useState(new Date()); + const offset = new Date(date.getFullYear(), date.getMonth(), 1).getDay(); + + const days = []; + for (let i = -offset; i < 42 - offset; i++) { + days.push(new Date(date.getFullYear(), date.getMonth(), i + 1)); + } + + return ( +
+
+
+ + + {date.toLocaleDateString(undefined, { + month: "long", + year: "numeric", + })} + + +
+
+
+ Sun + Mon + Tue + Wed + Thu + Fri + Sat +
+
+ {days.map((d, i) => { + const inMonth = + d.getFullYear() === date.getFullYear() && + d.getMonth() === date.getMonth(); + + const now = new Date(); + const today = + d.getFullYear() === now.getFullYear() && + d.getMonth() === now.getMonth() && + d.getDate() === now.getDate(); + return ( +
+ {d.getDate()} +
+ ); + })} +
+
+ ); +}