diff --git a/package-lock.json b/package-lock.json index 72eafff..e9644cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,8 +13,8 @@ "html-to-image": "^1.11.13", "nanoid": "^5.1.6", "openmeteo": "^1.2.1", - "react": "^19.1.1", - "react-dom": "^19.1.1", + "react": "^19.2.3", + "react-dom": "^19.2.3", "typescript": "^5.9.2" }, "devDependencies": { @@ -5665,24 +5665,24 @@ ] }, "node_modules/react": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", - "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "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==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", "dependencies": { - "scheduler": "^0.26.0" + "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.1.1" + "react": "^19.2.3" } }, "node_modules/react-is": { @@ -5780,9 +5780,9 @@ } }, "node_modules/scheduler": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", - "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, "node_modules/semver": { diff --git a/package.json b/package.json index d2346ec..d421b4e 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,8 @@ "html-to-image": "^1.11.13", "nanoid": "^5.1.6", "openmeteo": "^1.2.1", - "react": "^19.1.1", - "react-dom": "^19.1.1", + "react": "^19.2.3", + "react-dom": "^19.2.3", "typescript": "^5.9.2" }, "devDependencies": { diff --git a/src/WidgetMap.tsx b/src/WidgetMap.tsx index b20bafe..526419a 100644 --- a/src/WidgetMap.tsx +++ b/src/WidgetMap.tsx @@ -6,6 +6,9 @@ import { Search, SearchSettings } from "./widgets/Search"; import { Shortcut, ShortcutSettings } from "./widgets/Shortcut"; import { ToDoList } from "./widgets/ToDoList"; import { Weather } from "./widgets/Weather"; +import { TimerWidget } from "./widgets/TimeCounter"; +import TimerWidgetSet from "./widgets/TimerSet"; + const WidgetMap = { battery: { @@ -60,6 +63,14 @@ const WidgetMap = { component: Weather, size: { width: 6, height: 1 }, }, + timer: { + component: TimerWidget, + size: { width: 4, height: 1 }, + }, + Countdown: { + component: TimerWidgetSet, + size: { width: 4, height: 1 }, + }, }; export default WidgetMap; diff --git a/src/widgets/TimeCounter.css b/src/widgets/TimeCounter.css new file mode 100644 index 0000000..02c751e --- /dev/null +++ b/src/widgets/TimeCounter.css @@ -0,0 +1,22 @@ +.body { + width: 100%; + height: 100%; + + display: flex; + flex-flow: column nowrap; + align-items: center; + justify-content: center; + + font-family: Inter, sans-serif; + text-align: center; + + container-name: box; + + } + + .box { + font-size: 4rem; + font-weight: 700; + } + + \ No newline at end of file diff --git a/src/widgets/TimeCounter.tsx b/src/widgets/TimeCounter.tsx new file mode 100644 index 0000000..5d4c712 --- /dev/null +++ b/src/widgets/TimeCounter.tsx @@ -0,0 +1,45 @@ +import React, { useState, useEffect } from 'react'; +import { WidgetState } from "../Widget"; +import styles from "./TimeCounter.css"; + +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 ( +