From 636d256edb8347cc540f6066c3e4b14172ca738c Mon Sep 17 00:00:00 2001 From: Matthew Butcher Date: Wed, 19 Nov 2025 12:34:59 -0800 Subject: [PATCH 1/8] trying to push the code for the calander widgtet --- src/widgets/Calander.css | 0 src/widgets/CalanderProto.tsx | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/widgets/Calander.css create mode 100644 src/widgets/CalanderProto.tsx diff --git a/src/widgets/Calander.css b/src/widgets/Calander.css new file mode 100644 index 0000000..e69de29 diff --git a/src/widgets/CalanderProto.tsx b/src/widgets/CalanderProto.tsx new file mode 100644 index 0000000..e69de29 From 5858bb30491afe8b7dd187b8b785366271908aad Mon Sep 17 00:00:00 2001 From: Matthew Butcher Date: Mon, 1 Dec 2025 11:34:26 -0800 Subject: [PATCH 2/8] adding test widget --- package-lock.json | 122 +++++++++++++++++++++++++++++++++++++---- package.json | 1 + src/widgets/TimerW.tsx | 0 3 files changed, 113 insertions(+), 10 deletions(-) create mode 100644 src/widgets/TimerW.tsx diff --git a/package-lock.json b/package-lock.json index 23255c4..56e0a76 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "nanoid": "^5.1.6", "openmeteo": "^1.2.1", "react": "^19.1.1", + "react-calendar": "^6.0.0", "react-dom": "^19.1.1", "typescript": "^5.9.2" }, @@ -357,7 +358,6 @@ "integrity": "sha512-neCNfVxOoE7DsqDB5m1hEwxCwaTRdF6g5Nxq21FaDpSg0TpAdwzYlhHDhaCcriTOP0WhdYBn4l0TRRLP3bPDQQ==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "@rspack/core": "1.5.5", "@rspack/lite-tapable": "~1.0.1", @@ -618,7 +618,6 @@ "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "tslib": "^2.8.0" } @@ -652,9 +651,8 @@ "version": "19.1.13", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.13.tgz", "integrity": "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==", - "dev": true, + "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -669,13 +667,21 @@ "@types/react": "^19.0.0" } }, + "node_modules/@wojtekmaj/date-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@wojtekmaj/date-utils/-/date-utils-2.0.2.tgz", + "integrity": "sha512-Do66mSlSNifFFuo3l9gNKfRMSFi26CRuQMsDJuuKO/ekrDWuTTtE4ZQxoFCUOG+NgxnpSeBq/k5TY8ZseEzLpA==", + "license": "MIT", + "funding": { + "url": "https://github.com/wojtekmaj/date-utils?sponsor=1" + } + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -778,6 +784,15 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -836,7 +851,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/debug": { @@ -893,7 +908,6 @@ "integrity": "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -1121,6 +1135,18 @@ "dev": true, "license": "ISC" }, + "node_modules/get-user-locale": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-user-locale/-/get-user-locale-3.0.0.tgz", + "integrity": "sha512-iJfHSmdYV39UUBw7Jq6GJzeJxUr4U+S03qdhVuDsR9gCEnfbqLy9gYDJFBJQL1riqolFUKQvx36mEkp2iGgJ3g==", + "license": "MIT", + "dependencies": { + "memoize": "^10.0.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/get-user-locale?sponsor=1" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -1257,6 +1283,12 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -1338,6 +1370,45 @@ "dev": true, "license": "MIT" }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/memoize": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/memoize/-/memoize-10.2.0.tgz", + "integrity": "sha512-DeC6b7QBrZsRs3Y02A6A7lQyzFbsQbqgjI6UW0GigGWV+u1s25TycMr0XHZE4cJce7rY/vyw2ctMQqfDkIhUEA==", + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/memoize?sponsor=1" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1527,17 +1598,40 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/react-calendar": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/react-calendar/-/react-calendar-6.0.0.tgz", + "integrity": "sha512-6wqaki3Us0DNDjZDr0DYIzhSFprNoy4FdPT9Pjy5aD2hJJVjtJwmdMT9VmrTUo949nlk35BOxehThxX62RkuRQ==", + "license": "MIT", + "dependencies": { + "@wojtekmaj/date-utils": "^2.0.2", + "clsx": "^2.0.0", + "get-user-locale": "^3.0.0", + "warning": "^4.0.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/react-calendar?sponsor=1" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-dom": { "version": "19.1.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.26.0" }, @@ -1551,7 +1645,6 @@ "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -1671,6 +1764,15 @@ "punycode": "^2.1.0" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 3e71fa8..20e345b 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "nanoid": "^5.1.6", "openmeteo": "^1.2.1", "react": "^19.1.1", + "react-calendar": "^6.0.0", "react-dom": "^19.1.1", "typescript": "^5.9.2" }, diff --git a/src/widgets/TimerW.tsx b/src/widgets/TimerW.tsx new file mode 100644 index 0000000..e69de29 From a8beb7b1aa76a3d250f6c5c3d56f36c16420aac7 Mon Sep 17 00:00:00 2001 From: Matthew Butcher Date: Mon, 1 Dec 2025 12:43:25 -0800 Subject: [PATCH 3/8] version 2 of the basic timer function, it work in the dev build, we might need to add a slider on the side of the add menu --- src/widgets/TimerW2.tsx | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/widgets/TimerW2.tsx diff --git a/src/widgets/TimerW2.tsx b/src/widgets/TimerW2.tsx new file mode 100644 index 0000000..83ffadf --- /dev/null +++ b/src/widgets/TimerW2.tsx @@ -0,0 +1,44 @@ +import React, { useState, useEffect } from 'react'; +import { WidgetState } from "../Widget"; + +export function TimerWidget() { + const [seconds, setSeconds] = useState(0); + const [isRunning, setIsRunning] = useState(false); + + useEffect(() => { + let intervalId; + if (isRunning) { + intervalId = setInterval(() => { + setSeconds(prevSeconds => prevSeconds + 1); + }, 1000); + // Update every second + } + + return () => clearInterval(intervalId); + // Cleanup on unmount or when isRunning changes + }, [isRunning]); + + const handleStart = () => { + setIsRunning(true); + }; + + const handleStop = () => { + setIsRunning(false); + }; + + const handleReset = () => { + setSeconds(0); + setIsRunning(false); + }; + + return ( +
+

Timer: {seconds}s

+ + + +
+ ); +} + +//export default TimerWidget; \ No newline at end of file From 5e3c72e694bd97f3af59ccda53fa74d3b4258752 Mon Sep 17 00:00:00 2001 From: Matthew Butcher Date: Mon, 1 Dec 2025 12:44:58 -0800 Subject: [PATCH 4/8] adding changes to widgetmap --- src/WidgetMap.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/WidgetMap.tsx b/src/WidgetMap.tsx index aaa031d..2d2b220 100644 --- a/src/WidgetMap.tsx +++ b/src/WidgetMap.tsx @@ -5,6 +5,8 @@ import { Search, SearchSettings } from "./widgets/Search"; import { Shortcut, ShortcutSettings } from "./widgets/Shortcut"; import { ToDoList } from "./widgets/ToDoList"; import { Weather } from "./widgets/Weather"; +//import { CountdownTimer } from "./widgets/TimerW"; +import { TimerWidget } from "./widgets/TimerW2"; const WidgetMap = { battery: { @@ -24,7 +26,7 @@ const WidgetMap = { notepad: { component: Notepad, - size: { width: 4, height: 4 }, + size: { width: 4, height: 2 }, }, search: { @@ -46,13 +48,19 @@ const WidgetMap = { todo: { component: ToDoList, - size: { width: 4, height: 4 }, + size: { width: 4, height: 2 }, }, weather: { component: Weather, size: { width: 6, height: 1 }, }, + + timer: { + component: TimerWidget, + //component: CountdownTimer, + size: { width: 4, height: 1 }, + }, }; export default WidgetMap; From a0351b1a790f80fba0b1dfe0af14549c88f1c1e6 Mon Sep 17 00:00:00 2001 From: Matthew Butcher Date: Wed, 3 Dec 2025 12:37:16 -0800 Subject: [PATCH 5/8] adding the basis for a new timer function and a count down widget --- src/widgets/CountDown.tsx | 0 src/widgets/TimerW3.tsx | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/widgets/CountDown.tsx create mode 100644 src/widgets/TimerW3.tsx diff --git a/src/widgets/CountDown.tsx b/src/widgets/CountDown.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/widgets/TimerW3.tsx b/src/widgets/TimerW3.tsx new file mode 100644 index 0000000..e69de29 From 11f1993af944aac09c51ce87d5bfddc3557a8a4f Mon Sep 17 00:00:00 2001 From: Matthew Butcher Date: Wed, 3 Dec 2025 12:52:11 -0800 Subject: [PATCH 6/8] adding second version of the countdown widget --- src/widgets/CountDown2.tsx | 63 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/widgets/CountDown2.tsx diff --git a/src/widgets/CountDown2.tsx b/src/widgets/CountDown2.tsx new file mode 100644 index 0000000..7317011 --- /dev/null +++ b/src/widgets/CountDown2.tsx @@ -0,0 +1,63 @@ +import React, { useState, useEffect } from 'react'; +import { WidgetState } from "../Widget"; + +interface CountdownTimerProps { + targetDate: Date; + } + +export const CountdownTimer: React.FC = ({ targetDate }) => { + const calculateTimeLeft = () => { + const difference = targetDate.getTime() - new Date().getTime(); + let timeLeft = {}; + + if (difference > 0) { + timeLeft = { + days: Math.floor(difference / (1000 * 60 * 60 * 24)), + hours: Math.floor((difference / (1000 * 60 * 60)) % 24), + minutes: Math.floor((difference / 1000 / 60) % 60), + seconds: Math.floor((difference / 1000) % 60), + }; + } + return timeLeft; + }; + + const [timeLeft, setTimeLeft] = useState(calculateTimeLeft()); + + useEffect(() => { + const timer = setTimeout(() => { + setTimeLeft(calculateTimeLeft()); + }, 1000); + + // Clear timeout if the component is unmounted + return () => clearTimeout(timer); + }); + + const timerComponents = []; + + Object.keys(timeLeft).forEach((interval) => { + if (!(timeLeft as any)[interval]) { + return; + } + + timerComponents.push( + + { + { + days: `${(timeLeft as any)[interval]}d`, + hours: `${(timeLeft as any)[interval]}h`, + minutes: `${(timeLeft as any)[interval]}m`, + seconds: `${(timeLeft as any)[interval]}s`, + }[interval] + }{' '} + + ); + }); + + return ( +
+ {timerComponents.length ? timerComponents : Time's up!} +
+ ); + }; + + // export default CountdownTimer; \ No newline at end of file From ae1c2c6f5213b207ba591c91e93a2ec4ef388df6 Mon Sep 17 00:00:00 2001 From: Matthew Butcher Date: Sun, 14 Dec 2025 23:48:07 -0800 Subject: [PATCH 7/8] this was supposed to be a timmer widget taht could be set up with a certain time and alert you when it finished but the issue of getting it to work with the rest of the app just couldnet be done in time --- src/widgets/CountDown5.tsx | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/widgets/CountDown5.tsx diff --git a/src/widgets/CountDown5.tsx b/src/widgets/CountDown5.tsx new file mode 100644 index 0000000..5d010c5 --- /dev/null +++ b/src/widgets/CountDown5.tsx @@ -0,0 +1,46 @@ +import React, { useState, useEffect } from 'react'; +import { WidgetState } from "../Widget"; +import styles from "./CountDown.css"; + +export function CountdownTimer5({ deadline }) { + const [timeLeft, setTimeLeft] = useState(calculateTimeLeft(deadline)); + + useEffect(() => { + const timer = setInterval(() => { + setTimeLeft(calculateTimeLeft(deadline)); + }, 1000); + + // Cleanup function to clear the interval + return () => clearInterval(timer); + }, [deadline]); + // Re-run effect if deadline changes + + function calculateTimeLeft(targetDate) { + const difference = +new Date(targetDate) - +new Date(); + let timeLeft = {}; + + if (difference > 0) { + timeLeft = { + days: Math.floor(difference / (1000 * 60 * 60 * 24)), + hours: Math.floor((difference / (1000 * 60 * 60)) % 24), + minutes: Math.floor((difference / 1000 / 60) % 60), + seconds: Math.floor((difference / 1000) % 60), + }; + } + return timeLeft; + } + + return ( +
+ {Object.keys(timeLeft).length ? ( +

+ {timeLeft.days}d {timeLeft.hours}h {timeLeft.minutes}m {timeLeft.seconds}s +

+ ) : ( +

Time's up!

+ )} +
+ ); +} + +//export default CountdownTimer; \ No newline at end of file From 92444d80147fdba889670a95328b4e18469bbf35 Mon Sep 17 00:00:00 2001 From: Matthew Butcher Date: Sun, 14 Dec 2025 23:50:05 -0800 Subject: [PATCH 8/8] this is a simplified timer widget, it was ment to be a simple widget that when pressed would continue counting until told to stop and rest, it was a steping stone for the more complex set time timer wiget --- src/widgets/TimerW.tsx | 56 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/widgets/TimerW.tsx b/src/widgets/TimerW.tsx index e69de29..5a03a06 100644 --- a/src/widgets/TimerW.tsx +++ b/src/widgets/TimerW.tsx @@ -0,0 +1,56 @@ +import React, { useEffect, useState } from "react"; +import { WidgetState } from "../Widget"; + + +export const CountdownTimer = ({ initialSeconds = 0 }) => { +//const CountdownTimer = ({ initialSeconds = 0 }) => { + const [seconds, setSeconds] = useState(initialSeconds); + const [isRunning, setIsRunning] = useState(false); + + useEffect(() => { + let interval; + if (isRunning && seconds > 0) { + interval = setInterval(() => { + setSeconds(prevSeconds => prevSeconds - 1); + }, 1000); + } else if (seconds === 0 && isRunning) { + setIsRunning(false); + // Stop the timer when it reaches zero + } + return () => clearInterval(interval); + // Cleanup on component unmount or re-render + }, [isRunning, seconds]); + // set the is running to true + + const startTimer = () => { + setIsRunning(true); + }; + + const pauseTimer = () => { + setIsRunning(false); + }; + + const resetTimer = () => { + setIsRunning(false); + setSeconds(initialSeconds); + }; + + const formatTime = (timeInSeconds) => { + const minutes = Math.floor(timeInSeconds / 60); + const remainingSeconds = timeInSeconds % 60; + return `${minutes}:${remainingSeconds < 10 ? '0' : ''}${remainingSeconds}`; + }; + + return ( +
+

{formatTime(seconds)}

+
+ + + +
+
+ ); + }; + + //export default CountdownTimer; \ No newline at end of file