diff --git a/.gitignore b/.gitignore index 6ac093e..e876885 100644 --- a/.gitignore +++ b/.gitignore @@ -27,4 +27,4 @@ vite.config.ts.timestamp-* /src/lib/generated /tailwind.css *.svelte-kit - +/.vite diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..75dc494 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +# Ignore files for PNPM, NPM and YARN +pnpm-lock.yaml +package-lock.json +yarn.lock diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..a72947e --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "semi": false, + "useTabs": false, + "singleQuote": false, + "trailingComma": "es5", + "printWidth": 80, + "plugins": ["prettier-plugin-svelte"], + "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] +} diff --git a/package-lock.json b/package-lock.json index d05c628..2e35d51 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,20 +8,20 @@ "name": "breakoften", "version": "0.0.1", "devDependencies": { - "@sveltejs/adapter-auto": "^3.0.0", - "@sveltejs/kit": "^2.0.0", - "@sveltejs/vite-plugin-svelte": "^3.0.0", + "@sveltejs/adapter-auto": "^3.1.1", + "@sveltejs/kit": "^2.5.2", + "@sveltejs/vite-plugin-svelte": "^3.0.2", "autoprefixer": "^10.4.19", "postcss": "^8.4.38", "prettier": "^3.2.5", "prettier-plugin-svelte": "^3.2.3", - "svelte": "^4.2.7", + "svelte": "5.0.0-next.54", "svelte-check": "^3.6.0", "tailwindcss": "^3.4.3", "tslib": "^2.4.1", "tw-colors": "^3.3.1", "typescript": "^5.0.0", - "vite": "^5.0.3" + "vite": "^5.1.4" } }, "node_modules/@alloc/quick-lru": { @@ -824,6 +824,18 @@ "vite": "^5.0.0" } }, + "node_modules/@sveltejs/vite-plugin-svelte/node_modules/svelte-hmr": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz", + "integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==", + "dev": true, + "engines": { + "node": "^12.20 || ^14.13.1 || >= 16" + }, + "peerDependencies": { + "svelte": "^3.19.0 || ^4.0.0" + } + }, "node_modules/@types/cookie": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", @@ -854,6 +866,15 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-typescript": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/acorn-typescript/-/acorn-typescript-1.4.13.tgz", + "integrity": "sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==", + "dev": true, + "peerDependencies": { + "acorn": ">=8.9.0" + } + }, "node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -1101,19 +1122,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/code-red": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", - "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15", - "@types/estree": "^1.0.1", - "acorn": "^8.10.0", - "estree-walker": "^3.0.3", - "periscopic": "^3.1.0" - } - }, "node_modules/color": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", @@ -1193,19 +1201,6 @@ "node": ">= 8" } }, - "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -1357,13 +1352,14 @@ "integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==", "dev": true }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "node_modules/esrap": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.2.1.tgz", + "integrity": "sha512-dhkcOLfN/aDdMFI1iwPEcy/XqAZzGNfgfEJjZozy2tia6u0dQoZyXzkRshHTckuNsM+c0CYQndY+uRFe3N+AIQ==", "dev": true, "dependencies": { - "@types/estree": "^1.0.0" + "@jridgewell/sourcemap-codec": "^1.4.15", + "@types/estree": "^1.0.1" } }, "node_modules/fast-glob": { @@ -1739,12 +1735,6 @@ "@jridgewell/sourcemap-codec": "^1.4.15" } }, - "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -1974,17 +1964,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/periscopic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", - "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", - "dev": true, - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^3.0.0", - "is-reference": "^3.0.0" - } - }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -2641,28 +2620,27 @@ } }, "node_modules/svelte": { - "version": "4.2.15", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.15.tgz", - "integrity": "sha512-j9KJSccHgLeRERPlhMKrCXpk2TqL2m5Z+k+OBTQhZOhIdCCd3WfqV+ylPWeipEwq17P/ekiSFWwrVQv93i3bsg==", + "version": "5.0.0-next.54", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.0.0-next.54.tgz", + "integrity": "sha512-ik+hXhlKdZozs+EruogLXb5PVZD8X8ekNBwQGBYcTpj1FD0sgWZxvUEQV4m0rE5LaUL3J5cmO4e8daOuPxIK/A==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.1", "@jridgewell/sourcemap-codec": "^1.4.15", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/estree": "^1.0.1", - "acorn": "^8.9.0", + "@types/estree": "^1.0.5", + "acorn": "^8.11.3", + "acorn-typescript": "^1.4.13", "aria-query": "^5.3.0", "axobject-query": "^4.0.0", - "code-red": "^1.0.3", - "css-tree": "^2.3.1", - "estree-walker": "^3.0.3", - "is-reference": "^3.0.1", + "esm-env": "^1.0.0", + "esrap": "^1.2.1", + "is-reference": "^3.0.2", "locate-character": "^3.0.0", - "magic-string": "^0.30.4", - "periscopic": "^3.1.0" + "magic-string": "^0.30.5", + "zimmerframe": "^1.1.2" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/svelte-check": { @@ -2687,18 +2665,6 @@ "svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0" } }, - "node_modules/svelte-hmr": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz", - "integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==", - "dev": true, - "engines": { - "node": "^12.20 || ^14.13.1 || >= 16" - }, - "peerDependencies": { - "svelte": "^3.19.0 || ^4.0.0" - } - }, "node_modules/svelte-preprocess": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.4.tgz", @@ -3129,6 +3095,12 @@ "engines": { "node": ">= 14" } + }, + "node_modules/zimmerframe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz", + "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==", + "dev": true } } } diff --git a/package.json b/package.json index 75cd3fe..1e7228d 100644 --- a/package.json +++ b/package.json @@ -7,23 +7,25 @@ "build": "vite build", "preview": "vite preview", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "lint": "prettier --check .", + "format": "prettier --write ." }, "devDependencies": { - "@sveltejs/adapter-auto": "^3.0.0", - "@sveltejs/kit": "^2.0.0", - "@sveltejs/vite-plugin-svelte": "^3.0.0", + "@sveltejs/adapter-auto": "^3.1.1", + "@sveltejs/kit": "^2.5.2", + "@sveltejs/vite-plugin-svelte": "^3.0.2", "autoprefixer": "^10.4.19", "postcss": "^8.4.38", "prettier": "^3.2.5", "prettier-plugin-svelte": "^3.2.3", - "svelte": "^4.2.7", + "svelte": "5.0.0-next.54", "svelte-check": "^3.6.0", "tailwindcss": "^3.4.3", "tslib": "^2.4.1", "tw-colors": "^3.3.1", "typescript": "^5.0.0", - "vite": "^5.0.3" + "vite": "^5.1.4" }, "type": "module" } diff --git a/postcss.config.js b/postcss.config.js index 2aa7205..2e7af2b 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -3,4 +3,4 @@ export default { tailwindcss: {}, autoprefixer: {}, }, -}; +} diff --git a/src/app.d.ts b/src/app.d.ts index ede601a..367926a 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -10,4 +10,4 @@ declare global { } } -export {}; +export {} diff --git a/src/lib/components/ThemePicker.svelte b/src/lib/components/ThemePicker.svelte new file mode 100644 index 0000000..bd6e097 --- /dev/null +++ b/src/lib/components/ThemePicker.svelte @@ -0,0 +1,35 @@ +<script lang="ts" context="module"> + export const themes = ["light", "dark"] as const + export type Theme = (typeof themes)[number] +</script> + +<script lang="ts"> + import { slide } from "svelte/transition" + let { theme } = $props<{ theme: Theme }>() + + function toggleTheme() { + const currentIndex = themes.indexOf(theme) + theme = themes[(currentIndex + 1) % themes.length] + } + + let icon = $derived.by(() => { + if (theme === "light") return "🌞" + if (theme === "dark") return "🌙" + }) +</script> + +{#key theme} + <button transition:slide={{ axis: "x" }} onclick={toggleTheme}> + {icon} + </button> +{/key} + +<slot /> + +<style lang="postcss"> + button { + @apply absolute top-0 right-0; + @apply text-3xl; + @apply cursor-pointer; + } +</style> diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 25cef10..790effd 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,5 +1,27 @@ -<script> - import "../app.css"; -</script> - -<slot /> +<script lang="ts"> + import ThemePicker, { type Theme } from "$lib/components/ThemePicker.svelte" + import "../app.css" + + let { data } = $props() + + let theme = $state("dark" as Theme) +</script> + +<div data-theme={theme}> + <ThemePicker bind:theme /> + + <slot /> +</div> + +<style lang="postcss"> + :global(body) { + @apply flex min-h-screen; + } + + div { + @apply flex-1; + @apply flex flex-col; + @apply bg-background text-foreground; + } +</style> + diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index e83482a..bb2a7a1 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,46 +1,26 @@ -<!-- <script context="module"> - export async function load() { - const res = await fetch("https://api.example.com/data"); - const data = await res.json(); - return { - props: { - data, - }, - }; - } -</script> --> - -<script> - import { goto } from "$app/navigation"; - // import { writable } from "svelte/store"; - - const startApp = () => { - goto("/timer"); - }; - - // const theme = writable("dark"); -</script> - <main> - <h1>Welcome to the Prevent Computer Vision Syndrome App</h1> - <button on:click={startApp}>Start Timer</button> + <h1>Welcome to BreakOften!</h1> + <a href="/timer">Start Timer</a> </main> <style lang="postcss"> - main { - text-align: center; - margin: 100px auto; - color: var(--text-color); - } +main { + @apply text-center; + @apply mx-auto my-64; + } - h1 { - font-size: 2.5rem; - margin-bottom: 20px; - } + h1 { + @apply text-4xl mb-8; + } - button { - padding: 10px 20px; - font-size: 1rem; - cursor: pointer; - } + a { + @apply inline-block; + @apply rounded px-4 py-2; + @apply transition duration-300 ease-in-out; + @apply bg-primary text-white; + } + + a:hover { + @apply bg-primaryLight text-white; + } </style> diff --git a/src/routes/timer/+page.svelte b/src/routes/timer/+page.svelte index e34ba9f..29a674e 100644 --- a/src/routes/timer/+page.svelte +++ b/src/routes/timer/+page.svelte @@ -1,180 +1,180 @@ -<script context="module"> - export async function load() { - const res = await fetch("https://api.example.com/data"); - const data = await res.json(); - return { - props: { - data, - }, - }; - } -</script> - -<script lang="ts"> - import { onDestroy, onMount } from "svelte"; - import { writable } from "svelte/store"; - import type { Writable } from "svelte/store"; - - const MINI_BREAK_DURATION = 0.15 * 60 * 1000; // 1 minutes - // const MINI_BREAK_DURATION = 20 * 60 * 1000; // 20 minutes - const MINI_BREAK_INTERVAL = 5 * 1000; // 20 seconds - // const LONG_BREAK_DURATION = 5 * 60 * 1000; // 5 minutes - const LONG_BREAK_DURATION = 0.3 * 60 * 1000; // 2 minutes - - let timer: number | null = null; - let miniBreakCount = 0; - - let audio: HTMLAudioElement | null = null; - - const playSound = () => { - if (audio) { - // audio.pause(); - audio.src = "/sounds/Bells.mp3"; - audio.volume = 0.4; - // audio.play(); - } - }; - - const showNotification = (title: string, options: NotificationOptions) => { - if (Notification.permission === "granted") { - // new Notification(title, options); - } else if (Notification.permission !== "denied") { - Notification.requestPermission().then((permission) => { - if (permission === "granted") { - // new Notification(title, options); - } - }); - } - }; - - const state: Writable<string> = writable("Ready"); - const timeLeftDisplay: Writable<string> = writable(""); - const timeLeft: Writable<number> = writable(MINI_BREAK_DURATION); - - const startTimer = () => { - if (timer) clearInterval(timer); - - timer = setInterval(() => { - timeLeft.update((currentTimeLeft) => { - const newTimeLeft = currentTimeLeft - 1000; - if (newTimeLeft <= 0) { - if ($state !== "Ready") { - state.set("Ready"); - miniBreakCount++; - timeLeftDisplay.set(formatTime(MINI_BREAK_DURATION)); - showNotification("Ready", { body: "Continue working!" }); - playSound(); // Adjust volume as needed - return MINI_BREAK_DURATION; - } - if (miniBreakCount === 3) { - state.set("Long Break"); - miniBreakCount = 0; - timeLeftDisplay.set(formatTime(LONG_BREAK_DURATION)); - showNotification("Long Break", { - body: "Take a 5-minute break now!", - }); - playSound(); // Adjust volume as needed - return LONG_BREAK_DURATION; - } else { - state.set("Mini Break"); - // miniBreakCount++; - timeLeftDisplay.set(formatTime(MINI_BREAK_INTERVAL)); - showNotification("Mini Break", { - body: "Take a 20-second break now!", - }); - playSound(); // Adjust volume as needed - return MINI_BREAK_INTERVAL; - } - } - timeLeftDisplay.set(formatTime(newTimeLeft)); - return newTimeLeft; - }); - }, 1000); - }; - - onMount(() => { - audio = document.createElement('audio'); - startTimer(); - }); - - onDestroy(() => { - if (timer) clearInterval(timer); - if (audio) audio = null; - }); - - const skipBreak = () => { - // if (timer) clearInterval(timer); - if ($state === "Ready") { - return; - } - state.set("Ready"); - timeLeft.set(MINI_BREAK_DURATION); - timeLeftDisplay.set(formatTime(MINI_BREAK_DURATION)); - // startTimer(); - }; - - const postponeBreak = () => { - // if (timer) clearInterval(timer); - state.set("Ready"); - // setTimeout(startTimer, 2 * MINI_BREAK_INTERVAL); // Postpone for 2 mini-break intervals - timeLeft.set(MINI_BREAK_DURATION); // Corrected line - timeLeftDisplay.set(formatTime(MINI_BREAK_DURATION)); // Use MINI_BREAK_INTERVAL directly - }; - - function formatTime(milliseconds: number) { - const totalSeconds = Math.floor(milliseconds / 1000); - const minutes = Math.floor(totalSeconds / 60); - const seconds = totalSeconds % 60; - console.log( - `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`, - ); - - return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`; - } -</script> - -<main class="min-h-screen flex items-center justify-center bg-gray-100"> - <div class="max-w-md p-6 bg-white rounded-md shadow-md"> - <h1 class="text-3xl mb-4 font-bold text-center"> - Prevent Computer Vision Syndrome - </h1> - <p>{$state}</p> - {#if $state !== "Ready"} - <p>Time left until Ready: {$timeLeftDisplay}</p> - {:else} - <p>Time left until break: {$timeLeftDisplay}</p> - {/if} - {#if $state !== "Ready"} - <button - class="px-4 py-2 bg-blue-500 text-white rounded-md shadow-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2" - on:click={skipBreak}>Skip Break</button - > - {/if} - </div> -</main> - -<!-- -<style> - main { - text-align: center; - margin: 100px auto; - color: var(--text-color); - } - - h1 { - font-size: 2.5rem; - margin-bottom: 20px; - } - - p { - font-size: 1.5rem; - margin-bottom: 20px; - } - - button { - padding: 10px 20px; - font-size: 1rem; - cursor: pointer; - margin: 10px; - } -</style> --> +<script context="module"> + export async function load() { + const res = await fetch("https://api.example.com/data") + const data = await res.json() + return { + props: { + data, + }, + } + } +</script> + +<script lang="ts"> + import { onDestroy, onMount } from "svelte" + import { writable } from "svelte/store" + import type { Writable } from "svelte/store" + + const MINI_BREAK_DURATION = 0.15 * 60 * 1000 // 1 minutes + // const MINI_BREAK_DURATION = 20 * 60 * 1000; // 20 minutes + const MINI_BREAK_INTERVAL = 5 * 1000 // 20 seconds + // const LONG_BREAK_DURATION = 5 * 60 * 1000; // 5 minutes + const LONG_BREAK_DURATION = 0.3 * 60 * 1000 // 2 minutes + + let timer: number | null = null + let miniBreakCount = 0 + + let audio: HTMLAudioElement | null = null + + const playSound = () => { + if (audio) { + // audio.pause(); + audio.src = "/sounds/Bells.mp3" + audio.volume = 0.4 + // audio.play(); + } + } + + const showNotification = (title: string, options: NotificationOptions) => { + if (Notification.permission === "granted") { + // new Notification(title, options); + } else if (Notification.permission !== "denied") { + Notification.requestPermission().then((permission) => { + if (permission === "granted") { + // new Notification(title, options); + } + }) + } + } + + const state: Writable<string> = writable("Ready") + const timeLeftDisplay: Writable<string> = writable("") + const timeLeft: Writable<number> = writable(MINI_BREAK_DURATION) + + const startTimer = () => { + if (timer) clearInterval(timer) + + timer = setInterval(() => { + timeLeft.update((currentTimeLeft) => { + const newTimeLeft = currentTimeLeft - 1000 + if (newTimeLeft <= 0) { + if ($state !== "Ready") { + state.set("Ready") + miniBreakCount++ + timeLeftDisplay.set(formatTime(MINI_BREAK_DURATION)) + showNotification("Ready", { body: "Continue working!" }) + playSound() // Adjust volume as needed + return MINI_BREAK_DURATION + } + if (miniBreakCount === 3) { + state.set("Long Break") + miniBreakCount = 0 + timeLeftDisplay.set(formatTime(LONG_BREAK_DURATION)) + showNotification("Long Break", { + body: "Take a 5-minute break now!", + }) + playSound() // Adjust volume as needed + return LONG_BREAK_DURATION + } else { + state.set("Mini Break") + // miniBreakCount++; + timeLeftDisplay.set(formatTime(MINI_BREAK_INTERVAL)) + showNotification("Mini Break", { + body: "Take a 20-second break now!", + }) + playSound() // Adjust volume as needed + return MINI_BREAK_INTERVAL + } + } + timeLeftDisplay.set(formatTime(newTimeLeft)) + return newTimeLeft + }) + }, 1000) + } + + onMount(() => { + audio = document.createElement("audio") + startTimer() + }) + + onDestroy(() => { + if (timer) clearInterval(timer) + if (audio) audio = null + }) + + const skipBreak = () => { + // if (timer) clearInterval(timer); + if ($state === "Ready") { + return + } + state.set("Ready") + timeLeft.set(MINI_BREAK_DURATION) + timeLeftDisplay.set(formatTime(MINI_BREAK_DURATION)) + // startTimer(); + } + + const postponeBreak = () => { + // if (timer) clearInterval(timer); + state.set("Ready") + // setTimeout(startTimer, 2 * MINI_BREAK_INTERVAL); // Postpone for 2 mini-break intervals + timeLeft.set(MINI_BREAK_DURATION) // Corrected line + timeLeftDisplay.set(formatTime(MINI_BREAK_DURATION)) // Use MINI_BREAK_INTERVAL directly + } + + function formatTime(milliseconds: number) { + const totalSeconds = Math.floor(milliseconds / 1000) + const minutes = Math.floor(totalSeconds / 60) + const seconds = totalSeconds % 60 + console.log( + `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}` + ) + + return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}` + } +</script> + +<main> + <div> + <h1> + Prevent CVS + </h1> + {#if $state !== "Ready"} + <p>{$state}</p> + <p>Time left until end of break: {$timeLeftDisplay}</p> + {:else} + <p>Time left until break: {$timeLeftDisplay}</p> + {/if} + {#if $state !== "Ready"} + <button + on:click={skipBreak}>Skip Break</button + > + {/if} + </div> +</main> + + +<style lang="postcss"> + main { + @apply text-center; + @apply mx-auto my-64; + } + + h1 { + @apply text-4xl mb-8; + } + + p { + @apply text-base mb-4; + } + + button { + @apply inline-block; + @apply rounded px-4 py-2; + @apply transition duration-300 ease-in-out; + @apply bg-primary text-white; + } + + button:hover { + @apply bg-primaryLight text-white; + } +</style> diff --git a/svelte.config.js b/svelte.config.js index 973bdc9..5f1cfd7 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -1,8 +1,21 @@ -import adapter from "@sveltejs/adapter-auto"; -import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; +import adapter from "@sveltejs/adapter-auto" +import { vitePreprocess } from "@sveltejs/vite-plugin-svelte" /** @type {import('@sveltejs/kit').Config} */ const config = { + + // vitePlugin: { + // dynamicCompileOptions({filename}){ + // if(filename.includes('node_modules')){ + // return {runes: undefined} // or false, check what works + // } + // }, + // }, + + // compilerOptions: { + // runes: true + // }, + // Consult https://kit.svelte.dev/docs/integrations#preprocessors // for more information about preprocessors preprocess: vitePreprocess(), @@ -13,6 +26,6 @@ const config = { // See https://kit.svelte.dev/docs/adapters for more information about adapters. adapter: adapter(), }, -}; +} -export default config; +export default config diff --git a/tailwind.config.js b/tailwind.config.js index a58bd60..410694f 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -12,13 +12,15 @@ export default { light: { background: colors.slate[50], foreground: colors.slate[950], - primary: colors.yellow[600], + primary: colors.blue[600], + primaryLight: colors.blue[800], }, dark: { background: colors.slate[950], foreground: colors.slate[50], primary: colors.pink[600], + primaryLight: colors.pink[800], }, }), ], -}; +} diff --git a/vite.config.ts b/vite.config.ts index 80864b9..5b29b3a 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,6 +1,6 @@ -import { sveltekit } from "@sveltejs/kit/vite"; -import { defineConfig } from "vite"; +import { sveltekit } from "@sveltejs/kit/vite" +import { defineConfig } from "vite" export default defineConfig({ plugins: [sveltekit()], -}); +})