Add more configurations for the timer
This commit is contained in:
parent
72898aa8c8
commit
5524503d75
|
@ -3,17 +3,40 @@
|
|||
import { writable } from "svelte/store"
|
||||
import type { Writable } from "svelte/store"
|
||||
|
||||
const BREAK_INTERVAL = 20 * 60 * 1000 // 20 minutes
|
||||
const MINI_BREAK_DURATION = 20 * 1000 // 20 seconds
|
||||
const LONG_BREAK_DURATION = 5 * 60 * 1000 // 5 minutes
|
||||
const BREAK_INTERVAL_STORE: Writable<number> = writable(0.2)
|
||||
const MINI_BREAK_DURATION_STORE: Writable<number> = writable(20)
|
||||
const LONG_BREAK_DURATION_STORE: Writable<number> = writable(5)
|
||||
const SOUND_ENABLED: Writable<boolean> = writable(true)
|
||||
const NOTIFICATIONS_ENABLED: Writable<boolean> = writable(true)
|
||||
|
||||
let BREAK_INTERVAL: number
|
||||
let MINI_BREAK_DURATION: number
|
||||
let LONG_BREAK_DURATION: number
|
||||
let SOUND_ENABLED_STATE: boolean
|
||||
let NOTIFICATIONS_ENABLED_STATE: boolean
|
||||
|
||||
let timer: number | null = null
|
||||
|
||||
const state: Writable<string> = writable("Ready")
|
||||
const timeLeftDisplay: Writable<string> = writable("")
|
||||
const timeLeft: Writable<number> = writable($BREAK_INTERVAL_STORE)
|
||||
|
||||
BREAK_INTERVAL_STORE.subscribe((value) => {
|
||||
BREAK_INTERVAL = value * 60 * 1000
|
||||
timeLeft.set(BREAK_INTERVAL)
|
||||
timeLeftDisplay.set(formatTime(BREAK_INTERVAL))
|
||||
})
|
||||
MINI_BREAK_DURATION_STORE.subscribe((value) => (MINI_BREAK_DURATION = value * 1000))
|
||||
LONG_BREAK_DURATION_STORE.subscribe((value) => (LONG_BREAK_DURATION = value * 60 * 1000))
|
||||
SOUND_ENABLED.subscribe((value) => (SOUND_ENABLED_STATE = value))
|
||||
NOTIFICATIONS_ENABLED.subscribe((value) => (NOTIFICATIONS_ENABLED_STATE = value))
|
||||
|
||||
let miniBreakCount = 0
|
||||
|
||||
let audio: HTMLAudioElement | null = null
|
||||
|
||||
const playSound = () => {
|
||||
if (audio) {
|
||||
if (SOUND_ENABLED_STATE && audio) {
|
||||
audio.pause()
|
||||
audio.src = "/sounds/Bells.mp3"
|
||||
audio.volume = 0.4
|
||||
|
@ -22,21 +45,19 @@
|
|||
}
|
||||
|
||||
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)
|
||||
}
|
||||
})
|
||||
if (NOTIFICATIONS_ENABLED_STATE) {
|
||||
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(BREAK_INTERVAL)
|
||||
|
||||
const startTimer = () => {
|
||||
if (timer) clearInterval(timer)
|
||||
|
||||
|
@ -57,7 +78,8 @@
|
|||
miniBreakCount = 0
|
||||
timeLeftDisplay.set(formatTime(LONG_BREAK_DURATION))
|
||||
showNotification("Long Break", {
|
||||
body: "Take a 5-minute break now!",
|
||||
body: `Take a ${LONG_BREAK_DURATION / (60 * 1000)}-second break now!`,
|
||||
|
||||
})
|
||||
playSound()
|
||||
return LONG_BREAK_DURATION
|
||||
|
@ -65,7 +87,7 @@
|
|||
state.set("Mini Break")
|
||||
timeLeftDisplay.set(formatTime(MINI_BREAK_DURATION))
|
||||
showNotification("Mini Break", {
|
||||
body: "Take a 20-second break now!",
|
||||
body: `Take a ${MINI_BREAK_DURATION / 1000}-second break now!`,
|
||||
})
|
||||
playSound()
|
||||
return MINI_BREAK_DURATION
|
||||
|
@ -106,32 +128,88 @@
|
|||
</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 class="container">
|
||||
<div class="settings">
|
||||
<h1>Prevent CVS</h1>
|
||||
|
||||
<div class="setting">
|
||||
<label for="break-interval">Break interval: {BREAK_INTERVAL / (60 * 1000)} minutes</label>
|
||||
<input type="range" min="1" max="60" step="1" bind:value={$BREAK_INTERVAL_STORE} />
|
||||
</div>
|
||||
|
||||
<div class="setting">
|
||||
<label for="mini-break-duration">Mini break duration: {MINI_BREAK_DURATION / 1000} seconds</label>
|
||||
<input type="range" min="5" max="60" step="1" bind:value={$MINI_BREAK_DURATION_STORE} />
|
||||
</div>
|
||||
|
||||
<div class="setting">
|
||||
<label for="long-break-duration">Long break duration: {LONG_BREAK_DURATION / (60 * 1000)} minutes</label>
|
||||
<input type="range" min="1" max="30" step="1" bind:value={$LONG_BREAK_DURATION_STORE} />
|
||||
</div>
|
||||
|
||||
<div class="setting">
|
||||
<label>
|
||||
<input type="checkbox" bind:checked={$SOUND_ENABLED} />
|
||||
Sound
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="setting">
|
||||
<label>
|
||||
<input type="checkbox" bind:checked={$NOTIFICATIONS_ENABLED} />
|
||||
Notifications
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="timer">
|
||||
{#if $state !== "Ready"}
|
||||
<div class="timer-content">
|
||||
<p class="state">{$state}</p>
|
||||
<p>Time left until end of break: {$timeLeftDisplay}</p>
|
||||
<button on:click={skipBreak}>Skip break</button>
|
||||
</div>
|
||||
{:else}
|
||||
<p>Time left until break: {$timeLeftDisplay}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<style lang="postcss">
|
||||
main {
|
||||
@apply text-center;
|
||||
@apply mx-auto my-64;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
grid-gap: 20px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply text-4xl mb-8;
|
||||
@apply font-bold text-primary;
|
||||
}
|
||||
|
||||
.container {
|
||||
@apply bg-white rounded-lg shadow-lg p-8;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.timer, .settings {
|
||||
@apply text-black;
|
||||
}
|
||||
|
||||
.setting {
|
||||
@apply mb-2;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply text-base mb-4;
|
||||
@apply text-black;
|
||||
}
|
||||
|
||||
button {
|
||||
|
@ -144,4 +222,8 @@
|
|||
button:hover {
|
||||
@apply bg-primaryLight text-white;
|
||||
}
|
||||
|
||||
.state {
|
||||
@apply text-2xl font-semibold text-red-500;
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue