Fix lots of bugs and refactor

This commit is contained in:
Santiago Lo Coco 2024-04-23 17:15:16 +02:00
parent 4c980657ec
commit 2eb6a9c0ba
14 changed files with 359 additions and 320 deletions

2
.gitignore vendored
View File

@ -27,4 +27,4 @@ vite.config.ts.timestamp-*
/src/lib/generated /src/lib/generated
/tailwind.css /tailwind.css
*.svelte-kit *.svelte-kit
/.vite

4
.prettierignore Normal file
View File

@ -0,0 +1,4 @@
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

9
.prettierrc Normal file
View File

@ -0,0 +1,9 @@
{
"semi": false,
"useTabs": false,
"singleQuote": false,
"trailingComma": "es5",
"printWidth": 80,
"plugins": ["prettier-plugin-svelte"],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}

128
package-lock.json generated
View File

@ -8,20 +8,20 @@
"name": "breakoften", "name": "breakoften",
"version": "0.0.1", "version": "0.0.1",
"devDependencies": { "devDependencies": {
"@sveltejs/adapter-auto": "^3.0.0", "@sveltejs/adapter-auto": "^3.1.1",
"@sveltejs/kit": "^2.0.0", "@sveltejs/kit": "^2.5.2",
"@sveltejs/vite-plugin-svelte": "^3.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.2",
"autoprefixer": "^10.4.19", "autoprefixer": "^10.4.19",
"postcss": "^8.4.38", "postcss": "^8.4.38",
"prettier": "^3.2.5", "prettier": "^3.2.5",
"prettier-plugin-svelte": "^3.2.3", "prettier-plugin-svelte": "^3.2.3",
"svelte": "^4.2.7", "svelte": "5.0.0-next.54",
"svelte-check": "^3.6.0", "svelte-check": "^3.6.0",
"tailwindcss": "^3.4.3", "tailwindcss": "^3.4.3",
"tslib": "^2.4.1", "tslib": "^2.4.1",
"tw-colors": "^3.3.1", "tw-colors": "^3.3.1",
"typescript": "^5.0.0", "typescript": "^5.0.0",
"vite": "^5.0.3" "vite": "^5.1.4"
} }
}, },
"node_modules/@alloc/quick-lru": { "node_modules/@alloc/quick-lru": {
@ -824,6 +824,18 @@
"vite": "^5.0.0" "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": { "node_modules/@types/cookie": {
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
@ -854,6 +866,15 @@
"node": ">=0.4.0" "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": { "node_modules/ansi-regex": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
@ -1101,19 +1122,6 @@
"fsevents": "~2.3.2" "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": { "node_modules/color": {
"version": "4.2.3", "version": "4.2.3",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
@ -1193,19 +1201,6 @@
"node": ">= 8" "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": { "node_modules/cssesc": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@ -1357,13 +1352,14 @@
"integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==", "integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==",
"dev": true "dev": true
}, },
"node_modules/estree-walker": { "node_modules/esrap": {
"version": "3.0.3", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.2.1.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "integrity": "sha512-dhkcOLfN/aDdMFI1iwPEcy/XqAZzGNfgfEJjZozy2tia6u0dQoZyXzkRshHTckuNsM+c0CYQndY+uRFe3N+AIQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/estree": "^1.0.0" "@jridgewell/sourcemap-codec": "^1.4.15",
"@types/estree": "^1.0.1"
} }
}, },
"node_modules/fast-glob": { "node_modules/fast-glob": {
@ -1739,12 +1735,6 @@
"@jridgewell/sourcemap-codec": "^1.4.15" "@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": { "node_modules/merge2": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@ -1974,17 +1964,6 @@
"url": "https://github.com/sponsors/isaacs" "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": { "node_modules/picocolors": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
@ -2641,28 +2620,27 @@
} }
}, },
"node_modules/svelte": { "node_modules/svelte": {
"version": "4.2.15", "version": "5.0.0-next.54",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.15.tgz", "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.0.0-next.54.tgz",
"integrity": "sha512-j9KJSccHgLeRERPlhMKrCXpk2TqL2m5Z+k+OBTQhZOhIdCCd3WfqV+ylPWeipEwq17P/ekiSFWwrVQv93i3bsg==", "integrity": "sha512-ik+hXhlKdZozs+EruogLXb5PVZD8X8ekNBwQGBYcTpj1FD0sgWZxvUEQV4m0rE5LaUL3J5cmO4e8daOuPxIK/A==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.2.1", "@ampproject/remapping": "^2.2.1",
"@jridgewell/sourcemap-codec": "^1.4.15", "@jridgewell/sourcemap-codec": "^1.4.15",
"@jridgewell/trace-mapping": "^0.3.18", "@types/estree": "^1.0.5",
"@types/estree": "^1.0.1", "acorn": "^8.11.3",
"acorn": "^8.9.0", "acorn-typescript": "^1.4.13",
"aria-query": "^5.3.0", "aria-query": "^5.3.0",
"axobject-query": "^4.0.0", "axobject-query": "^4.0.0",
"code-red": "^1.0.3", "esm-env": "^1.0.0",
"css-tree": "^2.3.1", "esrap": "^1.2.1",
"estree-walker": "^3.0.3", "is-reference": "^3.0.2",
"is-reference": "^3.0.1",
"locate-character": "^3.0.0", "locate-character": "^3.0.0",
"magic-string": "^0.30.4", "magic-string": "^0.30.5",
"periscopic": "^3.1.0" "zimmerframe": "^1.1.2"
}, },
"engines": { "engines": {
"node": ">=16" "node": ">=18"
} }
}, },
"node_modules/svelte-check": { "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" "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": { "node_modules/svelte-preprocess": {
"version": "5.1.4", "version": "5.1.4",
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.4.tgz", "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.4.tgz",
@ -3129,6 +3095,12 @@
"engines": { "engines": {
"node": ">= 14" "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
} }
} }
} }

View File

@ -7,23 +7,25 @@
"build": "vite build", "build": "vite build",
"preview": "vite preview", "preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "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": { "devDependencies": {
"@sveltejs/adapter-auto": "^3.0.0", "@sveltejs/adapter-auto": "^3.1.1",
"@sveltejs/kit": "^2.0.0", "@sveltejs/kit": "^2.5.2",
"@sveltejs/vite-plugin-svelte": "^3.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.2",
"autoprefixer": "^10.4.19", "autoprefixer": "^10.4.19",
"postcss": "^8.4.38", "postcss": "^8.4.38",
"prettier": "^3.2.5", "prettier": "^3.2.5",
"prettier-plugin-svelte": "^3.2.3", "prettier-plugin-svelte": "^3.2.3",
"svelte": "^4.2.7", "svelte": "5.0.0-next.54",
"svelte-check": "^3.6.0", "svelte-check": "^3.6.0",
"tailwindcss": "^3.4.3", "tailwindcss": "^3.4.3",
"tslib": "^2.4.1", "tslib": "^2.4.1",
"tw-colors": "^3.3.1", "tw-colors": "^3.3.1",
"typescript": "^5.0.0", "typescript": "^5.0.0",
"vite": "^5.0.3" "vite": "^5.1.4"
}, },
"type": "module" "type": "module"
} }

View File

@ -3,4 +3,4 @@ export default {
tailwindcss: {}, tailwindcss: {},
autoprefixer: {}, autoprefixer: {},
}, },
}; }

2
src/app.d.ts vendored
View File

@ -10,4 +10,4 @@ declare global {
} }
} }
export {}; export {}

View File

@ -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>

View File

@ -1,5 +1,27 @@
<script> <script lang="ts">
import "../app.css"; import ThemePicker, { type Theme } from "$lib/components/ThemePicker.svelte"
</script> import "../app.css"
<slot /> 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>

View File

@ -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> <main>
<h1>Welcome to the Prevent Computer Vision Syndrome App</h1> <h1>Welcome to BreakOften!</h1>
<button on:click={startApp}>Start Timer</button> <a href="/timer">Start Timer</a>
</main> </main>
<style lang="postcss"> <style lang="postcss">
main { main {
text-align: center; @apply text-center;
margin: 100px auto; @apply mx-auto my-64;
color: var(--text-color); }
}
h1 { h1 {
font-size: 2.5rem; @apply text-4xl mb-8;
margin-bottom: 20px; }
}
button { a {
padding: 10px 20px; @apply inline-block;
font-size: 1rem; @apply rounded px-4 py-2;
cursor: pointer; @apply transition duration-300 ease-in-out;
} @apply bg-primary text-white;
}
a:hover {
@apply bg-primaryLight text-white;
}
</style> </style>

View File

@ -1,180 +1,180 @@
<script context="module"> <script context="module">
export async function load() { export async function load() {
const res = await fetch("https://api.example.com/data"); const res = await fetch("https://api.example.com/data")
const data = await res.json(); const data = await res.json()
return { return {
props: { props: {
data, data,
}, },
}; }
} }
</script> </script>
<script lang="ts"> <script lang="ts">
import { onDestroy, onMount } from "svelte"; import { onDestroy, onMount } from "svelte"
import { writable } from "svelte/store"; import { writable } from "svelte/store"
import type { Writable } from "svelte/store"; import type { Writable } from "svelte/store"
const MINI_BREAK_DURATION = 0.15 * 60 * 1000; // 1 minutes const MINI_BREAK_DURATION = 0.15 * 60 * 1000 // 1 minutes
// const MINI_BREAK_DURATION = 20 * 60 * 1000; // 20 minutes // const MINI_BREAK_DURATION = 20 * 60 * 1000; // 20 minutes
const MINI_BREAK_INTERVAL = 5 * 1000; // 20 seconds const MINI_BREAK_INTERVAL = 5 * 1000 // 20 seconds
// const LONG_BREAK_DURATION = 5 * 60 * 1000; // 5 minutes // const LONG_BREAK_DURATION = 5 * 60 * 1000; // 5 minutes
const LONG_BREAK_DURATION = 0.3 * 60 * 1000; // 2 minutes const LONG_BREAK_DURATION = 0.3 * 60 * 1000 // 2 minutes
let timer: number | null = null; let timer: number | null = null
let miniBreakCount = 0; let miniBreakCount = 0
let audio: HTMLAudioElement | null = null; let audio: HTMLAudioElement | null = null
const playSound = () => { const playSound = () => {
if (audio) { if (audio) {
// audio.pause(); // audio.pause();
audio.src = "/sounds/Bells.mp3"; audio.src = "/sounds/Bells.mp3"
audio.volume = 0.4; audio.volume = 0.4
// audio.play(); // audio.play();
} }
}; }
const showNotification = (title: string, options: NotificationOptions) => { const showNotification = (title: string, options: NotificationOptions) => {
if (Notification.permission === "granted") { if (Notification.permission === "granted") {
// new Notification(title, options); // new Notification(title, options);
} else if (Notification.permission !== "denied") { } else if (Notification.permission !== "denied") {
Notification.requestPermission().then((permission) => { Notification.requestPermission().then((permission) => {
if (permission === "granted") { if (permission === "granted") {
// new Notification(title, options); // new Notification(title, options);
} }
}); })
} }
}; }
const state: Writable<string> = writable("Ready"); const state: Writable<string> = writable("Ready")
const timeLeftDisplay: Writable<string> = writable(""); const timeLeftDisplay: Writable<string> = writable("")
const timeLeft: Writable<number> = writable(MINI_BREAK_DURATION); const timeLeft: Writable<number> = writable(MINI_BREAK_DURATION)
const startTimer = () => { const startTimer = () => {
if (timer) clearInterval(timer); if (timer) clearInterval(timer)
timer = setInterval(() => { timer = setInterval(() => {
timeLeft.update((currentTimeLeft) => { timeLeft.update((currentTimeLeft) => {
const newTimeLeft = currentTimeLeft - 1000; const newTimeLeft = currentTimeLeft - 1000
if (newTimeLeft <= 0) { if (newTimeLeft <= 0) {
if ($state !== "Ready") { if ($state !== "Ready") {
state.set("Ready"); state.set("Ready")
miniBreakCount++; miniBreakCount++
timeLeftDisplay.set(formatTime(MINI_BREAK_DURATION)); timeLeftDisplay.set(formatTime(MINI_BREAK_DURATION))
showNotification("Ready", { body: "Continue working!" }); showNotification("Ready", { body: "Continue working!" })
playSound(); // Adjust volume as needed playSound() // Adjust volume as needed
return MINI_BREAK_DURATION; return MINI_BREAK_DURATION
} }
if (miniBreakCount === 3) { if (miniBreakCount === 3) {
state.set("Long Break"); state.set("Long Break")
miniBreakCount = 0; miniBreakCount = 0
timeLeftDisplay.set(formatTime(LONG_BREAK_DURATION)); timeLeftDisplay.set(formatTime(LONG_BREAK_DURATION))
showNotification("Long Break", { showNotification("Long Break", {
body: "Take a 5-minute break now!", body: "Take a 5-minute break now!",
}); })
playSound(); // Adjust volume as needed playSound() // Adjust volume as needed
return LONG_BREAK_DURATION; return LONG_BREAK_DURATION
} else { } else {
state.set("Mini Break"); state.set("Mini Break")
// miniBreakCount++; // miniBreakCount++;
timeLeftDisplay.set(formatTime(MINI_BREAK_INTERVAL)); timeLeftDisplay.set(formatTime(MINI_BREAK_INTERVAL))
showNotification("Mini Break", { showNotification("Mini Break", {
body: "Take a 20-second break now!", body: "Take a 20-second break now!",
}); })
playSound(); // Adjust volume as needed playSound() // Adjust volume as needed
return MINI_BREAK_INTERVAL; return MINI_BREAK_INTERVAL
} }
} }
timeLeftDisplay.set(formatTime(newTimeLeft)); timeLeftDisplay.set(formatTime(newTimeLeft))
return newTimeLeft; return newTimeLeft
}); })
}, 1000); }, 1000)
}; }
onMount(() => { onMount(() => {
audio = document.createElement('audio'); audio = document.createElement("audio")
startTimer(); startTimer()
}); })
onDestroy(() => { onDestroy(() => {
if (timer) clearInterval(timer); if (timer) clearInterval(timer)
if (audio) audio = null; if (audio) audio = null
}); })
const skipBreak = () => { const skipBreak = () => {
// if (timer) clearInterval(timer); // if (timer) clearInterval(timer);
if ($state === "Ready") { if ($state === "Ready") {
return; return
} }
state.set("Ready"); state.set("Ready")
timeLeft.set(MINI_BREAK_DURATION); timeLeft.set(MINI_BREAK_DURATION)
timeLeftDisplay.set(formatTime(MINI_BREAK_DURATION)); timeLeftDisplay.set(formatTime(MINI_BREAK_DURATION))
// startTimer(); // startTimer();
}; }
const postponeBreak = () => { const postponeBreak = () => {
// if (timer) clearInterval(timer); // if (timer) clearInterval(timer);
state.set("Ready"); state.set("Ready")
// setTimeout(startTimer, 2 * MINI_BREAK_INTERVAL); // Postpone for 2 mini-break intervals // setTimeout(startTimer, 2 * MINI_BREAK_INTERVAL); // Postpone for 2 mini-break intervals
timeLeft.set(MINI_BREAK_DURATION); // Corrected line timeLeft.set(MINI_BREAK_DURATION) // Corrected line
timeLeftDisplay.set(formatTime(MINI_BREAK_DURATION)); // Use MINI_BREAK_INTERVAL directly timeLeftDisplay.set(formatTime(MINI_BREAK_DURATION)) // Use MINI_BREAK_INTERVAL directly
}; }
function formatTime(milliseconds: number) { function formatTime(milliseconds: number) {
const totalSeconds = Math.floor(milliseconds / 1000); const totalSeconds = Math.floor(milliseconds / 1000)
const minutes = Math.floor(totalSeconds / 60); const minutes = Math.floor(totalSeconds / 60)
const seconds = totalSeconds % 60; const seconds = totalSeconds % 60
console.log( console.log(
`${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`, `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`
); )
return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`; return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`
} }
</script> </script>
<main class="min-h-screen flex items-center justify-center bg-gray-100"> <main>
<div class="max-w-md p-6 bg-white rounded-md shadow-md"> <div>
<h1 class="text-3xl mb-4 font-bold text-center"> <h1>
Prevent Computer Vision Syndrome Prevent CVS
</h1> </h1>
<p>{$state}</p> {#if $state !== "Ready"}
{#if $state !== "Ready"} <p>{$state}</p>
<p>Time left until Ready: {$timeLeftDisplay}</p> <p>Time left until end of break: {$timeLeftDisplay}</p>
{:else} {:else}
<p>Time left until break: {$timeLeftDisplay}</p> <p>Time left until break: {$timeLeftDisplay}</p>
{/if} {/if}
{#if $state !== "Ready"} {#if $state !== "Ready"}
<button <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
on:click={skipBreak}>Skip Break</button >
> {/if}
{/if} </div>
</div> </main>
</main>
<!-- <style lang="postcss">
<style> main {
main { @apply text-center;
text-align: center; @apply mx-auto my-64;
margin: 100px auto; }
color: var(--text-color);
} h1 {
@apply text-4xl mb-8;
h1 { }
font-size: 2.5rem;
margin-bottom: 20px; p {
} @apply text-base mb-4;
}
p {
font-size: 1.5rem; button {
margin-bottom: 20px; @apply inline-block;
} @apply rounded px-4 py-2;
@apply transition duration-300 ease-in-out;
button { @apply bg-primary text-white;
padding: 10px 20px; }
font-size: 1rem;
cursor: pointer; button:hover {
margin: 10px; @apply bg-primaryLight text-white;
} }
</style> --> </style>

View File

@ -1,8 +1,21 @@
import adapter from "@sveltejs/adapter-auto"; import adapter from "@sveltejs/adapter-auto"
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */
const 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 // Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors // for more information about preprocessors
preprocess: vitePreprocess(), preprocess: vitePreprocess(),
@ -13,6 +26,6 @@ const config = {
// See https://kit.svelte.dev/docs/adapters for more information about adapters. // See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter(), adapter: adapter(),
}, },
}; }
export default config; export default config

View File

@ -12,13 +12,15 @@ export default {
light: { light: {
background: colors.slate[50], background: colors.slate[50],
foreground: colors.slate[950], foreground: colors.slate[950],
primary: colors.yellow[600], primary: colors.blue[600],
primaryLight: colors.blue[800],
}, },
dark: { dark: {
background: colors.slate[950], background: colors.slate[950],
foreground: colors.slate[50], foreground: colors.slate[50],
primary: colors.pink[600], primary: colors.pink[600],
primaryLight: colors.pink[800],
}, },
}), }),
], ],
}; }

View File

@ -1,6 +1,6 @@
import { sveltekit } from "@sveltejs/kit/vite"; import { sveltekit } from "@sveltejs/kit/vite"
import { defineConfig } from "vite"; import { defineConfig } from "vite"
export default defineConfig({ export default defineConfig({
plugins: [sveltekit()], plugins: [sveltekit()],
}); })