aboutsummaryrefslogtreecommitdiffstats
path: root/old-apps/web-shared/src/components/stopwatch.svelte
diff options
context:
space:
mode:
authorivarlovlie <git@ivarlovlie.no>2022-09-20 09:24:27 +0200
committerivarlovlie <git@ivarlovlie.no>2022-09-20 09:24:27 +0200
commita9072370ca1eb9a5cce928b1d487db0f307edea6 (patch)
tree59c3c23df930a8b5f888dc7813923abf4ceefed4 /old-apps/web-shared/src/components/stopwatch.svelte
parent56fa963a1d63cbe0bf28e29e717cceaa417c45c1 (diff)
downloadgreatoffice-a9072370ca1eb9a5cce928b1d487db0f307edea6.tar.xz
greatoffice-a9072370ca1eb9a5cce928b1d487db0f307edea6.zip
feat: Move old apps into it's own directory
Diffstat (limited to 'old-apps/web-shared/src/components/stopwatch.svelte')
-rw-r--r--old-apps/web-shared/src/components/stopwatch.svelte196
1 files changed, 196 insertions, 0 deletions
diff --git a/old-apps/web-shared/src/components/stopwatch.svelte b/old-apps/web-shared/src/components/stopwatch.svelte
new file mode 100644
index 0000000..0e641e8
--- /dev/null
+++ b/old-apps/web-shared/src/components/stopwatch.svelte
@@ -0,0 +1,196 @@
+<script lang="ts">
+ import Button from "$shared/components/button.svelte";
+ import { Textarea } from "$shared/components/form";
+ import { StorageKeys } from "$shared/lib/configuration";
+ import { loadLocaleAsync } from "$shared/lib/i18n/i18n-util.async";
+ import { i18nObject } from "$shared/lib/i18n/i18n-util";
+ import { currentLocale, preffered_or_default } from "$shared/lib/locale";
+ import { StoreType, writable_persistent } from "$shared/lib/persistent-store";
+ import { Temporal } from "@js-temporal/polyfill";
+ import { createEventDispatcher, onMount } from "svelte";
+
+ const state = writable_persistent({
+ initialState: {
+ hours: 0,
+ minutes: 0,
+ seconds: 0,
+ startTime: null as Temporal.PlainDateTime,
+ lastStep: null as Temporal.PlainDateTime,
+ isRunning: false,
+ intervalId: 0,
+ note: "",
+ },
+ options: {
+ store: StoreType.LOCAL
+ },
+ name: StorageKeys.stopwatch,
+ });
+
+ let timeString;
+ let LL = i18nObject($currentLocale);
+
+ $: if ($state.hours || $state.minutes || $state.seconds) {
+ timeString = $state.hours.toLocaleString(undefined, {minimumIntegerDigits: 2})
+ + ":" + $state.minutes.toLocaleString(undefined, {minimumIntegerDigits: 2})
+ + ":" + $state.seconds.toLocaleString(undefined, {minimumIntegerDigits: 2});
+ } else {
+ timeString = "--:--:--";
+ }
+
+ currentLocale.subscribe(async locale => {
+ if (locale === "preffered") locale = preffered_or_default();
+ await loadLocaleAsync(locale);
+ LL = i18nObject(locale);
+ });
+
+ onMount(async () => {
+ start_if_running();
+ await loadLocaleAsync($currentLocale);
+ LL = i18nObject($currentLocale);
+ });
+
+ function start_if_running() {
+ if ($state.isRunning) {
+ if (Temporal.PlainDateTime.compare($state.lastStep, Temporal.Now.plainDateTimeISO()) == -1) {
+ const duration = Temporal.Now.plainDateTimeISO().since($state.lastStep, {smallestUnit: "second"});
+ console.log("lastStep", $state.lastStep.toString());
+ console.log("duration", duration.toString());
+ console.log(duration.seconds);
+ // for (let i = 0; i < steps; i++) {
+ // step();
+ // }
+ }
+ clearInterval($state.intervalId);
+ $state.intervalId = setInterval(step, 1000);
+ }
+ }
+
+ window.addEventListener("focus", () => {
+ start_if_running();
+ });
+
+ const dispatch = createEventDispatcher();
+
+ function step() {
+ $state.seconds = $state.seconds + 1;
+
+ if ($state.seconds == 60) {
+ $state.minutes = $state.minutes + 1;
+ $state.seconds = 0;
+ }
+
+ if ($state.minutes == 60) {
+ $state.hours = $state.hours + 1;
+ $state.minutes = 0;
+ $state.seconds = 0;
+ }
+
+ if (!$state.startTime) $state.startTime = Temporal.Now.plainDateTimeISO();
+ $state.lastStep = Temporal.Now.plainDateTimeISO();
+ }
+
+ function reset() {
+ clearInterval($state.intervalId);
+ $state.isRunning = false;
+ $state.hours = 0;
+ $state.minutes = 0;
+ $state.seconds = 0;
+ $state.startTime = null;
+ $state.intervalId = 0;
+ $state.note = "";
+ }
+
+ let roundUpToNearest = 30;
+ let roundDownToNearest = 30;
+
+ function on_round_up() {
+ const newTime = Temporal.PlainTime
+ .from({hour: $state.hours, minute: $state.minutes, second: $state.seconds})
+ .round({
+ roundingIncrement: roundUpToNearest,
+ smallestUnit: "minute",
+ roundingMode: "ceil"
+ });
+ $state.hours = newTime.hour;
+ $state.minutes = newTime.minute;
+ $state.seconds = newTime.second;
+ }
+
+ function on_round_down() {
+ const newTime = Temporal.PlainTime
+ .from({hour: $state.hours, minute: $state.minutes, second: $state.seconds,})
+ .round({
+ roundingIncrement: roundDownToNearest,
+ smallestUnit: "minute",
+ roundingMode: "trunc"
+ });
+ $state.hours = newTime.hour;
+ $state.minutes = newTime.minute;
+ $state.seconds = newTime.second;
+ }
+
+ function on_start_stop() {
+ if ($state.isRunning) {
+ clearInterval($state.intervalId);
+ $state.isRunning = false;
+ return;
+ }
+ step();
+ $state.intervalId = setInterval(step, 1000);
+ $state.isRunning = true;
+ }
+
+ function on_create_entry() {
+ if (!$state.startTime) return;
+ const plainStartTime = Temporal.PlainDateTime.from($state.startTime);
+ dispatch("create", {
+ from: plainStartTime,
+ to: plainStartTime.add({hours: $state.hours, minutes: $state.minutes, seconds: $state.seconds}),
+ description: $state.note
+ });
+ reset();
+ }
+</script>
+
+<div class="grid">
+ <div class="col-6">
+ <slot name="header"></slot>
+ <pre class="text-xxl padding-y-sm">{timeString}</pre>
+ </div>
+ <div class="col-6 flex align-bottom flex-column text-xs">
+ <Button title="{$state.isRunning ? LL.stopwatch.stop() : LL.stopwatch.start()}"
+ text="{$state.isRunning ? LL.stopwatch.stop() : LL.stopwatch.start()}"
+ variant="link"
+ on:click={on_start_stop}/>
+
+ {#if $state.startTime}
+ <Button title="{LL.stopwatch.reset()}"
+ text="{LL.stopwatch.reset()}"
+ variant="link"
+ class="bg-error-lighter@hover color-white@hover"
+ on:click={reset}/>
+ {#if !$state.isRunning}
+ <Button title="{LL.stopwatch.roundUp()}"
+ text="{LL.stopwatch.roundUp()}"
+ variant="link"
+ on:click={on_round_up}/>
+ <Button title="{LL.stopwatch.roundDown()}"
+ text="{LL.stopwatch.roundDown()}"
+ variant="link"
+ on:click={on_round_down}/>
+ {#if $state.minutes > 0 || $state.hours > 0}
+ <Button title="{LL.stopwatch.createEntry()}"
+ text="{LL.stopwatch.createEntry()}"
+ variant="link"
+ on:click={on_create_entry}/>
+ {/if}
+ {/if}
+ {/if}
+ </div>
+</div>
+
+<Textarea class="width-100% margin-top-xs"
+ placeholder="{LL.stopwatch.whatsYourFocus()}"
+ rows="1"
+ bind:value={$state.note}
+/>