diff --git a/src/components/store-consumer/store-consumer.tsx b/src/components/store-consumer/store-consumer.tsx
index 77b10cc..101be03 100644
--- a/src/components/store-consumer/store-consumer.tsx
+++ b/src/components/store-consumer/store-consumer.tsx
@@ -3,7 +3,6 @@ import { useEffect } from 'react';
import { useSoundStore } from '@/stores/sound';
import { useNoteStore } from '@/stores/note';
import { usePresetStore } from '@/stores/preset';
-import { useTimers } from '@/stores/timers';
interface StoreConsumerProps {
children: React.ReactNode;
@@ -14,7 +13,6 @@ export function StoreConsumer({ children }: StoreConsumerProps) {
useSoundStore.persist.rehydrate();
useNoteStore.persist.rehydrate();
usePresetStore.persist.rehydrate();
- useTimers.persist.rehydrate();
}, []);
return <>{children}>;
diff --git a/src/components/tools/about.astro b/src/components/tools/about.astro
deleted file mode 100644
index 68eaea3..0000000
--- a/src/components/tools/about.astro
+++ /dev/null
@@ -1,54 +0,0 @@
----
-import { Container } from '../container';
-import { SpecialButton } from '../special-button';
-
-interface Props {
- text: string;
-}
-
-const { text } = Astro.props;
----
-
-
-
- About This Tool
- {text}
-
- About Moodist
-
- Immerse yourself in tranquility with Moodist, a simple ambient sound
- generator. Create the perfect atmosphere for relaxation, focus, or sleep
- by customizing soothing soundscapes to match your mood.
-
-
-
- Use Moodist
-
-
-
-
-
diff --git a/src/components/tools/breathing/breathing.module.css b/src/components/tools/breathing/breathing.module.css
deleted file mode 100644
index fdbd99d..0000000
--- a/src/components/tools/breathing/breathing.module.css
+++ /dev/null
@@ -1 +0,0 @@
-/* WIP */
diff --git a/src/components/tools/breathing/breathing.tsx b/src/components/tools/breathing/breathing.tsx
deleted file mode 100644
index cc54de4..0000000
--- a/src/components/tools/breathing/breathing.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import { Container } from '@/components/container';
-import { Exercise } from './exercise';
-
-export function BreathingExercises() {
- return (
-
-
-
- );
-}
diff --git a/src/components/tools/breathing/exercise/exercise.module.css b/src/components/tools/breathing/exercise/exercise.module.css
deleted file mode 100644
index 05b9baa..0000000
--- a/src/components/tools/breathing/exercise/exercise.module.css
+++ /dev/null
@@ -1,47 +0,0 @@
-.exercise {
- position: relative;
- z-index: 1;
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 75px 0;
- margin-top: 12px;
- background-color: var(--color-neutral-50);
- border: 1px solid var(--color-neutral-200);
- border-radius: 8px;
-
- & .phase {
- font-family: var(--font-display);
- font-size: var(--font-lg);
- font-weight: 600;
- }
-
- & .circle {
- position: absolute;
- top: 50%;
- left: 50%;
- z-index: -1;
- height: 55%;
- aspect-ratio: 1 / 1;
- background-image: radial-gradient(
- var(--color-neutral-50),
- var(--color-neutral-100)
- );
- border: 1px solid var(--color-neutral-200);
- border-radius: 50%;
- transform: translate(-50%, -50%);
- }
-}
-
-.selectBox {
- width: 100%;
- min-width: 0;
- height: 45px;
- padding: 0 12px;
- margin-top: 8px;
- font-size: var(--font-sm);
- color: var(--color-foreground);
- background-color: var(--color-neutral-100);
- border: 1px solid var(--color-neutral-200);
- border-radius: 8px;
-}
diff --git a/src/components/tools/breathing/exercise/exercise.tsx b/src/components/tools/breathing/exercise/exercise.tsx
deleted file mode 100644
index 14e07fb..0000000
--- a/src/components/tools/breathing/exercise/exercise.tsx
+++ /dev/null
@@ -1,109 +0,0 @@
-import { useState, useEffect, useMemo, useCallback } from 'react';
-import { motion } from 'framer-motion';
-import styles from './exercise.module.css';
-
-type Exercise = 'Box Breathing' | 'Resonant Breathing' | '4-7-8 Breathing';
-type Phase = 'inhale' | 'exhale' | 'holdInhale' | 'holdExhale';
-
-const EXERCISE_PHASES: Record = {
- '4-7-8 Breathing': ['inhale', 'holdInhale', 'exhale'],
- 'Box Breathing': ['inhale', 'holdInhale', 'exhale', 'holdExhale'],
- 'Resonant Breathing': ['inhale', 'exhale'],
-};
-
-const EXERCISE_DURATIONS: Record>> = {
- '4-7-8 Breathing': { exhale: 8, holdInhale: 7, inhale: 4 },
- 'Box Breathing': { exhale: 4, holdExhale: 4, holdInhale: 4, inhale: 4 },
- 'Resonant Breathing': { exhale: 5, inhale: 5 }, // No holdExhale
-};
-
-const PHASE_LABELS: Record = {
- exhale: 'Exhale',
- holdExhale: 'Hold',
- holdInhale: 'Hold',
- inhale: 'Inhale',
-};
-
-export function Exercise() {
- const [selectedExercise, setSelectedExercise] =
- useState('4-7-8 Breathing');
- const [phaseIndex, setPhaseIndex] = useState(0);
-
- const phases = useMemo(
- () => EXERCISE_PHASES[selectedExercise],
- [selectedExercise],
- );
- const durations = useMemo(
- () => EXERCISE_DURATIONS[selectedExercise],
- [selectedExercise],
- );
-
- const currentPhase = phases[phaseIndex];
-
- const animationVariants = useMemo(
- () => ({
- exhale: {
- transform: 'translate(-50%, -50%) scale(1)',
- transition: { duration: durations.exhale },
- },
- holdExhale: {
- transform: 'translate(-50%, -50%) scale(1)',
- transition: { duration: durations.holdExhale },
- },
- holdInhale: {
- transform: 'translate(-50%, -50%) scale(1.5)',
- transition: { duration: durations.holdInhale },
- },
- inhale: {
- transform: 'translate(-50%, -50%) scale(1.5)',
- transition: { duration: durations.inhale },
- },
- }),
- [durations],
- );
-
- const resetExercise = useCallback(() => {
- setPhaseIndex(0);
- }, []);
-
- const updatePhase = useCallback(() => {
- setPhaseIndex(prevIndex => (prevIndex + 1) % phases.length);
- }, [phases.length]);
-
- useEffect(() => {
- resetExercise();
- }, [selectedExercise, resetExercise]);
-
- useEffect(() => {
- const intervalDuration = (durations[currentPhase] || 4) * 1000;
- const interval = setInterval(updatePhase, intervalDuration);
-
- return () => clearInterval(interval);
- }, [currentPhase, durations, updatePhase]);
-
- return (
- <>
-
-
-
{PHASE_LABELS[currentPhase]}
-
-
- setSelectedExercise(e.target.value as Exercise)}
- >
- {Object.keys(EXERCISE_PHASES).map(exercise => (
-
- {exercise}
-
- ))}
-
- >
- );
-}
diff --git a/src/components/tools/breathing/exercise/index.ts b/src/components/tools/breathing/exercise/index.ts
deleted file mode 100644
index 881062d..0000000
--- a/src/components/tools/breathing/exercise/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Exercise } from './exercise';
diff --git a/src/components/tools/breathing/index.ts b/src/components/tools/breathing/index.ts
deleted file mode 100644
index dbd185a..0000000
--- a/src/components/tools/breathing/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { BreathingExercises } from './breathing';
diff --git a/src/components/tools/generics/button/button.module.css b/src/components/tools/generics/button/button.module.css
deleted file mode 100644
index a96e112..0000000
--- a/src/components/tools/generics/button/button.module.css
+++ /dev/null
@@ -1,34 +0,0 @@
-.button {
- display: flex;
- align-items: center;
- justify-content: center;
- width: 30px;
- height: 30px;
- font-size: var(--font-sm);
- color: var(--color-foreground);
- cursor: pointer;
- background-color: var(--color-neutral-100);
- border: 1px solid var(--color-neutral-200);
- border-radius: 4px;
- outline: none;
- transition: 0.2s;
-
- &:focus-visible {
- outline: 2px solid var(--color-neutral-400);
- outline-offset: 2px;
- }
-
- &:hover,
- &:focus-visible {
- background-color: var(--color-neutral-200);
- }
-
- &.smallIcon {
- font-size: var(--font-xsm);
- }
-
- &:disabled {
- cursor: not-allowed;
- opacity: 0.4;
- }
-}
diff --git a/src/components/tools/generics/button/button.tsx b/src/components/tools/generics/button/button.tsx
deleted file mode 100644
index 5828ad6..0000000
--- a/src/components/tools/generics/button/button.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import { Tooltip } from '@/components/tooltip';
-
-import { cn } from '@/helpers/styles';
-
-import styles from './button.module.css';
-
-interface ButtonProps {
- disabled?: boolean;
- icon: React.ReactElement;
- onClick: () => void;
- smallIcon?: boolean;
- tooltip: string;
-}
-
-export function Button({
- disabled = false,
- icon,
- onClick,
- smallIcon,
- tooltip,
-}: ButtonProps) {
- return (
-
-
- {icon}
-
-
- );
-}
diff --git a/src/components/tools/generics/button/index.ts b/src/components/tools/generics/button/index.ts
deleted file mode 100644
index a039b75..0000000
--- a/src/components/tools/generics/button/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Button } from './button';
diff --git a/src/components/tools/hero.astro b/src/components/tools/hero.astro
deleted file mode 100644
index a502ae4..0000000
--- a/src/components/tools/hero.astro
+++ /dev/null
@@ -1,114 +0,0 @@
----
-import { Container } from '../container';
-
-interface Props {
- desc: string;
- title: string;
-}
-
-const { desc, title } = Astro.props;
----
-
-
-
-
-
-
-
-
{title}
-
{desc}
-
-
Part of Moodist
-
-
-
-
-
diff --git a/src/components/tools/notepad/button/button.module.css b/src/components/tools/notepad/button/button.module.css
deleted file mode 100644
index 4a4e756..0000000
--- a/src/components/tools/notepad/button/button.module.css
+++ /dev/null
@@ -1,45 +0,0 @@
-.button {
- display: flex;
- align-items: center;
- justify-content: center;
- width: 30px;
- height: 30px;
- font-size: var(--font-sm);
- color: var(--color-foreground);
- cursor: pointer;
- background-color: var(--color-neutral-100);
- border: 1px solid var(--color-neutral-200);
- border-radius: 4px;
- outline: none;
- transition: 0.2s;
- transition-property: border-color, color, background-color;
-
- &:focus-visible {
- outline: 2px solid var(--color-neutral-400);
- outline-offset: 2px;
- }
-
- &.critical {
- color: #f43f5e;
- border-color: #f43f5e;
-
- &:hover {
- background-color: rgb(244 63 94 / 10%);
- }
- }
-
- &.recommended {
- font-size: var(--font-xsm);
- color: #22c55e;
- border-color: #22c55e;
-
- &:hover {
- background-color: rgb(34 197 94 / 10%);
- }
- }
-
- &:hover,
- &:focus-visible {
- background-color: var(--color-neutral-200);
- }
-}
diff --git a/src/components/tools/notepad/button/button.tsx b/src/components/tools/notepad/button/button.tsx
deleted file mode 100644
index d3da910..0000000
--- a/src/components/tools/notepad/button/button.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import { Tooltip } from '@/components/tooltip';
-
-import { cn } from '@/helpers/styles';
-
-import styles from './button.module.css';
-
-interface ButtonProps {
- critical?: boolean;
- icon: React.ReactElement;
- onClick: () => void;
- recommended?: boolean;
- tooltip: string;
-}
-
-export function Button({
- critical,
- icon,
- onClick,
- recommended,
- tooltip,
-}: ButtonProps) {
- return (
-
-
- {icon}
-
-
- );
-}
diff --git a/src/components/tools/notepad/button/index.ts b/src/components/tools/notepad/button/index.ts
deleted file mode 100644
index a039b75..0000000
--- a/src/components/tools/notepad/button/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Button } from './button';
diff --git a/src/components/tools/notepad/index.tsx b/src/components/tools/notepad/index.tsx
deleted file mode 100644
index 02c1b24..0000000
--- a/src/components/tools/notepad/index.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import { StoreConsumer } from '@/components/store-consumer';
-
-import { Notepad as NotepadComponent } from './notepad';
-
-export function Notepad() {
- return (
-
-
-
- );
-}
diff --git a/src/components/tools/notepad/notepad.module.css b/src/components/tools/notepad/notepad.module.css
deleted file mode 100644
index 2dadc40..0000000
--- a/src/components/tools/notepad/notepad.module.css
+++ /dev/null
@@ -1,44 +0,0 @@
-.header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-bottom: 8px;
-
- & .label {
- font-size: var(--font-sm);
- font-weight: 500;
- color: var(--color-foreground-subtle);
- }
-
- & .buttons {
- display: flex;
- column-gap: 4px;
- align-items: center;
- }
-}
-
-.textarea {
- width: 100%;
- height: 350px;
- padding: 12px;
- line-height: 1.6;
- color: var(--color-foreground-subtle);
- resize: none;
- background-color: var(--color-neutral-50);
- border: 1px solid var(--color-neutral-200);
- border-radius: 4px;
- outline: none;
- scroll-padding-bottom: 12px;
-
- &:focus-visible {
- outline: 2px solid var(--color-neutral-400);
- outline-offset: 2px;
- }
-}
-
-.counter {
- margin-top: 8px;
- font-size: var(--font-xsm);
- color: var(--color-foreground-subtle);
- text-align: center;
-}
diff --git a/src/components/tools/notepad/notepad.tsx b/src/components/tools/notepad/notepad.tsx
deleted file mode 100644
index 9ca334e..0000000
--- a/src/components/tools/notepad/notepad.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-import { BiTrash } from 'react-icons/bi/index';
-import { LuCopy, LuDownload } from 'react-icons/lu/index';
-import { FaCheck } from 'react-icons/fa6/index';
-import { FaUndo } from 'react-icons/fa/index';
-
-import { Button } from './button';
-
-import { useNoteStore } from '@/stores/note';
-import { useCopy } from '@/hooks/use-copy';
-import { download } from '@/helpers/download';
-
-import styles from './notepad.module.css';
-import { Container } from '@/components/container';
-
-export function Notepad() {
- const note = useNoteStore(state => state.note);
- const history = useNoteStore(state => state.history);
- const write = useNoteStore(state => state.write);
- const words = useNoteStore(state => state.words());
- const characters = useNoteStore(state => state.characters());
- const clear = useNoteStore(state => state.clear);
- const restore = useNoteStore(state => state.restore);
-
- const { copy, copying } = useCopy();
-
- return (
-
-
- Your Note
-
- : }
- tooltip="Copy Note"
- onClick={() => copy(note)}
- />
- }
- tooltip="Download Note"
- onClick={() => download('Moodit Note.txt', note)}
- />
- : }
- recommended={!!history}
- tooltip={history ? 'Restore Note' : 'Clear Note'}
- onClick={() => (history ? restore() : clear())}
- />
-
-
-
-
- );
-}
diff --git a/src/components/tools/pomodoro/index.ts b/src/components/tools/pomodoro/index.ts
deleted file mode 100644
index 9b721ae..0000000
--- a/src/components/tools/pomodoro/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Pomodoro } from './pomodoro';
diff --git a/src/components/tools/pomodoro/pomodoro.module.css b/src/components/tools/pomodoro/pomodoro.module.css
deleted file mode 100644
index 33109cf..0000000
--- a/src/components/tools/pomodoro/pomodoro.module.css
+++ /dev/null
@@ -1,36 +0,0 @@
-.header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-bottom: 8px;
-
- & .title {
- font-size: var(--font-sm);
- font-weight: 500;
- color: var(--color-foreground-subtle);
- }
-
- & .buttons {
- display: flex;
- column-gap: 4px;
- align-items: center;
- }
-}
-
-.control {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-top: 8px;
-
- & .completed {
- font-size: var(--font-xsm);
- color: var(--color-foreground-subtle);
- }
-
- & .buttons {
- display: flex;
- column-gap: 4px;
- align-items: center;
- }
-}
diff --git a/src/components/tools/pomodoro/pomodoro.tsx b/src/components/tools/pomodoro/pomodoro.tsx
deleted file mode 100644
index 83f8354..0000000
--- a/src/components/tools/pomodoro/pomodoro.tsx
+++ /dev/null
@@ -1,168 +0,0 @@
-import { useState, useEffect, useRef, useMemo } from 'react';
-import { FaUndo, FaPlay, FaPause } from 'react-icons/fa/index';
-import { IoMdSettings } from 'react-icons/io/index';
-
-import { Button } from '../generics/button';
-import { Timer } from '@/components/timer';
-import { Tabs } from './tabs';
-import { Setting } from './setting';
-
-import { useLocalStorage } from '@/hooks/use-local-storage';
-import { useSoundEffect } from '@/hooks/use-sound-effect';
-import { usePomodoroStore } from '@/stores/pomodoro';
-import { useCloseListener } from '@/hooks/use-close-listener';
-
-import styles from './pomodoro.module.css';
-import { Container } from '@/components/container';
-
-export function Pomodoro() {
- const [showSetting, setShowSetting] = useState(false);
-
- const [selectedTab, setSelectedTab] = useState('pomodoro');
-
- const running = usePomodoroStore(state => state.running);
- const setRunning = usePomodoroStore(state => state.setRunning);
-
- const [timer, setTimer] = useState(0);
- const interval = useRef | null>(null);
-
- const alarm = useSoundEffect('/sounds/alarm.mp3');
-
- const defaultTimes = useMemo(
- () => ({
- long: 15 * 60,
- pomodoro: 25 * 60,
- short: 5 * 60,
- }),
- [],
- );
-
- const [times, setTimes] = useLocalStorage>(
- 'moodist-pomodoro-setting',
- defaultTimes,
- );
-
- const [completions, setCompletions] = useState>({
- long: 0,
- pomodoro: 0,
- short: 0,
- });
-
- const tabs = useMemo(
- () => [
- { id: 'pomodoro', label: 'Pomodoro' },
- { id: 'short', label: 'Break' },
- { id: 'long', label: 'Long Break' },
- ],
- [],
- );
-
- useCloseListener(() => setShowSetting(false));
-
- useEffect(() => {
- if (running) {
- if (interval.current) clearInterval(interval.current);
-
- interval.current = setInterval(() => {
- setTimer(prev => prev - 1);
- }, 1000);
- } else {
- if (interval.current) clearInterval(interval.current);
- }
- }, [running]);
-
- useEffect(() => {
- if (timer <= 0 && running) {
- if (interval.current) clearInterval(interval.current);
-
- alarm.play();
-
- setRunning(false);
- setCompletions(prev => ({
- ...prev,
- [selectedTab]: prev[selectedTab] + 1,
- }));
- }
- }, [timer, selectedTab, running, setRunning, alarm]);
-
- useEffect(() => {
- const time = times[selectedTab] || 10;
-
- if (interval.current) clearInterval(interval.current);
-
- setRunning(false);
- setTimer(time);
- }, [selectedTab, times, setRunning]);
-
- const toggleRunning = () => {
- if (running) setRunning(false);
- else if (timer <= 0) {
- const time = times[selectedTab] || 10;
-
- setTimer(time);
- setRunning(true);
- } else setRunning(true);
- };
-
- const restart = () => {
- if (interval.current) clearInterval(interval.current);
-
- const time = times[selectedTab] || 10;
-
- setRunning(false);
- setTimer(time);
- };
-
- return (
-
-
-
-
-
-
-
-
- {completions[selectedTab] || 0} completed
-
-
- }
- smallIcon
- tooltip="Restart"
- onClick={restart}
- />
- : }
- smallIcon
- tooltip={running ? 'Pause' : 'Start'}
- onClick={toggleRunning}
- />
-
-
-
- {
- setShowSetting(false);
- setTimes(times);
- }}
- onClose={() => {
- setShowSetting(false);
- }}
- />
-
- );
-}
diff --git a/src/components/tools/pomodoro/setting/index.ts b/src/components/tools/pomodoro/setting/index.ts
deleted file mode 100644
index 0394f8b..0000000
--- a/src/components/tools/pomodoro/setting/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Setting } from './setting';
diff --git a/src/components/tools/pomodoro/setting/setting.module.css b/src/components/tools/pomodoro/setting/setting.module.css
deleted file mode 100644
index 89583ef..0000000
--- a/src/components/tools/pomodoro/setting/setting.module.css
+++ /dev/null
@@ -1,76 +0,0 @@
-.title {
- margin-bottom: 16px;
- font-family: var(--font-heading);
- font-size: var(--font-md);
- font-weight: 600;
-}
-
-& .form {
- display: flex;
- flex-direction: column;
-
- & .field {
- display: flex;
- flex-direction: column;
- row-gap: 8px;
- margin-bottom: 16px;
-
- & .label {
- font-size: var(--font-sm);
- color: var(--color-foreground);
-
- & span {
- color: var(--color-foreground-subtle);
- }
- }
-
- & .input {
- display: block;
- height: 40px;
- padding: 0 8px;
- color: var(--color-foreground);
- background-color: var(--color-neutral-50);
- border: 1px solid var(--color-neutral-200);
- border-radius: 4px;
- outline: none;
-
- &:focus-visible {
- outline: 2px solid var(--color-neutral-400);
- outline-offset: 2px;
- }
- }
- }
-
- & .buttons {
- display: flex;
- column-gap: 8px;
- align-items: center;
- justify-content: flex-end;
-
- & button {
- display: flex;
- align-items: center;
- justify-content: center;
- height: 40px;
- padding: 0 16px;
- font-size: var(--font-sm);
- font-weight: 500;
- color: var(--color-foreground);
- cursor: pointer;
- background-color: var(--color-neutral-200);
- border: none;
- border-radius: 4px;
- outline: none;
-
- &:focus-visible {
- outline: 2px solid var(--color-neutral-400);
- outline-offset: 2px;
- }
-
- &.primary {
- color: var(--color-neutral-100);
- background-color: var(--color-neutral-950);
- }
- }
- }
-}
diff --git a/src/components/tools/pomodoro/setting/setting.tsx b/src/components/tools/pomodoro/setting/setting.tsx
deleted file mode 100644
index 8db1a93..0000000
--- a/src/components/tools/pomodoro/setting/setting.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-import { useEffect, useState } from 'react';
-
-import { Modal } from '@/components/modal';
-
-import styles from './setting.module.css';
-
-interface SettingProps {
- onChange: (newTimes: Record) => void;
- onClose: () => void;
- show: boolean;
- times: Record;
-}
-
-export function Setting({ onChange, onClose, show, times }: SettingProps) {
- const [values, setValues] = useState>(times);
-
- useEffect(() => {
- if (show) setValues(times);
- }, [times, show]);
-
- const handleChange = (id: string) => (value: number | string) => {
- setValues(prev => ({
- ...prev,
- [id]: typeof value === 'number' ? value * 60 : '',
- }));
- };
-
- const handleSubmit = (e: React.FormEvent) => {
- e.preventDefault();
-
- const newValues: Record = {};
-
- Object.keys(values).forEach(name => {
- newValues[name] =
- typeof values[name] === 'number' ? values[name] : times[name];
- });
-
- onChange(newValues);
- };
-
- const handleCancel = (e: React.MouseEvent) => {
- e.preventDefault();
-
- onClose();
- };
-
- return (
-
- Change Times
-
-
-
- );
-}
-
-interface FieldProps {
- id: string;
- label: string;
- onChange: (value: number | string) => void;
- value: number | string;
-}
-
-function Field({ id, label, onChange, value }: FieldProps) {
- return (
-
-
- {label} (minutes)
-
- {
- onChange(e.target.value === '' ? '' : Number(e.target.value));
- }}
- />
-
- );
-}
diff --git a/src/components/tools/pomodoro/tabs/index.ts b/src/components/tools/pomodoro/tabs/index.ts
deleted file mode 100644
index 81aabb7..0000000
--- a/src/components/tools/pomodoro/tabs/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Tabs } from './tabs';
diff --git a/src/components/tools/pomodoro/tabs/tabs.module.css b/src/components/tools/pomodoro/tabs/tabs.module.css
deleted file mode 100644
index 222164c..0000000
--- a/src/components/tools/pomodoro/tabs/tabs.module.css
+++ /dev/null
@@ -1,43 +0,0 @@
-.tabs {
- display: flex;
- column-gap: 4px;
- align-items: center;
- padding: 4px;
- margin: 8px 0;
- background-color: var(--color-neutral-50);
- border: 1px solid var(--color-neutral-200);
- border-radius: 8px;
-
- & .tab {
- display: flex;
- flex-grow: 1;
- align-items: center;
- justify-content: center;
- height: 45px;
- font-size: var(--font-sm);
- color: var(--color-foreground-subtle);
- cursor: pointer;
- background-color: transparent;
- border: 1px solid transparent;
- border-radius: 4px;
- outline: none;
- transition: 0.2s;
-
- &:focus-visible {
- outline: 2px solid var(--color-neutral-400);
- outline-offset: 2px;
- }
-
- &.selected {
- color: var(--color-foreground);
- background-color: var(--color-neutral-200);
- border-color: var(--color-neutral-300);
- }
-
- &:not(.selected):hover,
- &:not(.selected):focus-visible {
- color: var(--color-foreground);
- background-color: var(--color-neutral-100);
- }
- }
-}
diff --git a/src/components/tools/pomodoro/tabs/tabs.tsx b/src/components/tools/pomodoro/tabs/tabs.tsx
deleted file mode 100644
index 728bc5e..0000000
--- a/src/components/tools/pomodoro/tabs/tabs.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { cn } from '@/helpers/styles';
-
-import styles from './tabs.module.css';
-
-interface TabsProps {
- onSelect: (id: string) => void;
- selectedTab: string;
- tabs: Array<{ id: string; label: string }>;
-}
-
-export function Tabs({ onSelect, selectedTab, tabs }: TabsProps) {
- return (
-
- {tabs.map(tab => (
- onSelect(tab.id)}
- >
- {tab.label}
-
- ))}
-
- );
-}
diff --git a/src/components/tools/timer/form/field/field.module.css b/src/components/tools/timer/form/field/field.module.css
deleted file mode 100644
index b505d8a..0000000
--- a/src/components/tools/timer/form/field/field.module.css
+++ /dev/null
@@ -1,27 +0,0 @@
-.field {
- flex-grow: 1;
-
- & .label {
- display: block;
- margin-bottom: 8px;
- font-size: var(--font-sm);
- font-weight: 500;
-
- & .optional {
- font-weight: 400;
- color: var(--color-foreground-subtle);
- }
- }
-
- & .input {
- width: 100%;
- min-width: 0;
- height: 40px;
- padding: 0 16px;
- color: var(--color-foreground);
- background-color: var(--color-neutral-100);
- border: 1px solid var(--color-neutral-200);
- border-radius: 8px;
- outline: none;
- }
-}
diff --git a/src/components/tools/timer/form/field/field.tsx b/src/components/tools/timer/form/field/field.tsx
deleted file mode 100644
index 6b057a8..0000000
--- a/src/components/tools/timer/form/field/field.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import styles from './field.module.css';
-
-interface FieldProps {
- children?: React.ReactNode;
- label: string;
- onChange: (value: string | number) => void;
- optional?: boolean;
- type: 'text' | 'select';
- value: string | number;
-}
-
-export function Field({
- children,
- label,
- onChange,
- optional,
- type,
- value,
-}: FieldProps) {
- return (
-
-
- {label}{' '}
- {optional && (optional) }
-
-
- {type === 'text' && (
- onChange(e.target.value)}
- />
- )}
-
- {type === 'select' && (
- onChange(parseInt(e.target.value))}
- >
- {children}
-
- )}
-
- );
-}
diff --git a/src/components/tools/timer/form/field/index.ts b/src/components/tools/timer/form/field/index.ts
deleted file mode 100644
index 497b3a7..0000000
--- a/src/components/tools/timer/form/field/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Field } from './field';
diff --git a/src/components/tools/timer/form/form.module.css b/src/components/tools/timer/form/form.module.css
deleted file mode 100644
index b6a60ee..0000000
--- a/src/components/tools/timer/form/form.module.css
+++ /dev/null
@@ -1,28 +0,0 @@
-.form {
- display: flex;
- flex-direction: column;
- row-gap: 28px;
-
- & .button {
- display: flex;
- align-items: center;
- justify-content: center;
- width: 100%;
- height: 45px;
- font-weight: 500;
- color: var(--color-neutral-50);
- cursor: pointer;
- background-color: var(--color-neutral-950);
- border: none;
- border-radius: 8px;
- outline: none;
- box-shadow: inset 0 -3px 0 var(--color-neutral-700);
- }
-}
-
-.timeFields {
- display: flex;
- column-gap: 12px;
- align-items: flex-end;
- justify-content: space-between;
-}
diff --git a/src/components/tools/timer/form/form.tsx b/src/components/tools/timer/form/form.tsx
deleted file mode 100644
index 748c3a0..0000000
--- a/src/components/tools/timer/form/form.tsx
+++ /dev/null
@@ -1,97 +0,0 @@
-import { useState, useMemo } from 'react';
-
-import { Field } from './field';
-
-import { useTimers } from '@/stores/timers';
-
-import styles from './form.module.css';
-
-export function Form() {
- const [name, setName] = useState('');
- const [hours, setHours] = useState(0);
- const [minutes, setMinutes] = useState(10);
- const [seconds, setSeconds] = useState(0);
-
- const totalSeconds = useMemo(
- () => hours * 60 * 60 + minutes * 60 + seconds,
- [hours, minutes, seconds],
- );
-
- const add = useTimers(state => state.add);
-
- const handleSubmit = (e: React.FormEvent) => {
- e.preventDefault();
-
- if (totalSeconds === 0) return;
-
- add({
- name,
- total: totalSeconds,
- });
-
- setName('');
- };
-
- return (
-
- );
-}
diff --git a/src/components/tools/timer/form/index.ts b/src/components/tools/timer/form/index.ts
deleted file mode 100644
index 9398c9e..0000000
--- a/src/components/tools/timer/form/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Form } from './form';
diff --git a/src/components/tools/timer/index.ts b/src/components/tools/timer/index.ts
deleted file mode 100644
index 91b3f08..0000000
--- a/src/components/tools/timer/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Timer } from './timer';
diff --git a/src/components/tools/timer/timer.tsx b/src/components/tools/timer/timer.tsx
deleted file mode 100644
index c7affa1..0000000
--- a/src/components/tools/timer/timer.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Container } from '@/components/container';
-import { Timers } from './timers';
-import { Form } from './form';
-import { StoreConsumer } from '@/components/store-consumer';
-
-export function Timer() {
- return (
-
-
-
-
-
-
- );
-}
diff --git a/src/components/tools/timer/timers/index.ts b/src/components/tools/timer/timers/index.ts
deleted file mode 100644
index 0f9e27a..0000000
--- a/src/components/tools/timer/timers/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Timers } from './timers';
diff --git a/src/components/tools/timer/timers/notice/index.ts b/src/components/tools/timer/timers/notice/index.ts
deleted file mode 100644
index 64af78d..0000000
--- a/src/components/tools/timer/timers/notice/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Notice } from './notice';
diff --git a/src/components/tools/timer/timers/notice/notice.module.css b/src/components/tools/timer/timers/notice/notice.module.css
deleted file mode 100644
index 54c58c0..0000000
--- a/src/components/tools/timer/timers/notice/notice.module.css
+++ /dev/null
@@ -1,10 +0,0 @@
-.notice {
- padding: 16px;
- margin-top: 16px;
- font-size: var(--font-sm);
- line-height: 1.65;
- color: var(--color-foreground-subtle);
- text-align: center;
- border: 1px dashed var(--color-neutral-200);
- border-radius: 8px;
-}
diff --git a/src/components/tools/timer/timers/notice/notice.tsx b/src/components/tools/timer/timers/notice/notice.tsx
deleted file mode 100644
index a25b74c..0000000
--- a/src/components/tools/timer/timers/notice/notice.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import styles from './notice.module.css';
-
-export function Notice() {
- return (
-
- Please do not close this tab while timers are running, otherwise all
- timers will be stopped.
-
- );
-}
diff --git a/src/components/tools/timer/timers/timer/index.ts b/src/components/tools/timer/timers/timer/index.ts
deleted file mode 100644
index 91b3f08..0000000
--- a/src/components/tools/timer/timers/timer/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Timer } from './timer';
diff --git a/src/components/tools/timer/timers/timer/timer.module.css b/src/components/tools/timer/timers/timer/timer.module.css
deleted file mode 100644
index a59151c..0000000
--- a/src/components/tools/timer/timers/timer/timer.module.css
+++ /dev/null
@@ -1,126 +0,0 @@
-.timer {
- position: relative;
- padding: 8px;
- overflow: hidden;
- background-color: var(--color-neutral-100);
- border: 1px solid var(--color-neutral-200);
- border-radius: 8px;
-
- &:not(:last-of-type) {
- margin-bottom: 24px;
- }
-
- & .header {
- position: relative;
- top: -8px;
- width: 100%;
-
- & .bar {
- height: 2px;
- margin: 0 -8px;
- background-color: var(--color-neutral-200);
-
- & .completed {
- height: 100%;
- background-color: var(--color-neutral-500);
- transition: 0.2s;
- }
- }
- }
-
- & .footer {
- display: flex;
- column-gap: 4px;
- align-items: center;
-
- & .control {
- display: flex;
- flex-grow: 1;
- column-gap: 4px;
- align-items: center;
- height: 40px;
- padding: 4px;
- background-color: var(--color-neutral-50);
- border: 1px solid var(--color-neutral-200);
- border-radius: 4px;
-
- & .input {
- flex-grow: 1;
- width: 100%;
- min-width: 0;
- height: 100%;
- padding: 0 8px;
- color: var(--color-foreground-subtle);
- background-color: transparent;
- border: none;
- border-radius: 4px;
- outline: none;
-
- &.finished {
- text-decoration: line-through;
- }
- }
-
- & .button {
- display: flex;
- align-items: center;
- justify-content: center;
- height: 100%;
- aspect-ratio: 1 / 1;
- color: var(--color-foreground);
- cursor: pointer;
- background-color: var(--color-neutral-200);
- border: 1px solid var(--color-neutral-300);
- border-radius: 2px;
- outline: none;
- transition: 0.2s;
-
- &.reset {
- background-color: var(--color-neutral-100);
- border: none;
- }
-
- &:disabled,
- &.disabled {
- cursor: not-allowed;
- opacity: 0.6;
- }
- }
- }
-
- & .delete {
- display: flex;
- align-items: center;
- justify-content: center;
- width: 38px;
- height: 38px;
- color: #f43f5e;
- cursor: pointer;
- background-color: rgb(244 63 94 / 10%);
- border: none;
- border-radius: 4px;
- outline: none;
- transition: 0.2s;
-
- &.disabled {
- cursor: not-allowed;
- opacity: 0.6;
- }
- }
- }
-
- & .left {
- display: flex;
- align-items: center;
- justify-content: center;
- height: 120px;
- font-family: var(--font-mono);
- font-size: var(--font-2xlg);
- font-weight: 700;
- cursor: pointer;
-
- & span {
- color: var(--color-foreground-subtle);
- }
- }
-}
diff --git a/src/components/tools/timer/timers/timer/timer.tsx b/src/components/tools/timer/timers/timer/timer.tsx
deleted file mode 100644
index 516da01..0000000
--- a/src/components/tools/timer/timers/timer/timer.tsx
+++ /dev/null
@@ -1,212 +0,0 @@
-import { useRef, useMemo, useState, useEffect } from 'react';
-import { IoPlay, IoPause, IoRefresh, IoTrashOutline } from 'react-icons/io5';
-
-import { Toolbar } from './toolbar';
-
-import { useTimers } from '@/stores/timers';
-import { useAlarm } from '@/hooks/use-alarm';
-import { useSnackbar } from '@/contexts/snackbar';
-import { padNumber } from '@/helpers/number';
-import { cn } from '@/helpers/styles';
-
-import styles from './timer.module.css';
-
-interface TimerProps {
- id: string;
-}
-
-export function Timer({ id }: TimerProps) {
- const intervalRef = useRef | null>(null);
- const lastActiveTimeRef = useRef(null);
- const lastStateRef = useRef<{ spent: number; total: number } | null>(null);
-
- const [isRunning, setIsRunning] = useState(false);
-
- const { first, last, name, spent, total } = useTimers(state =>
- state.getTimer(id),
- );
- const tick = useTimers(state => state.tick);
- const rename = useTimers(state => state.rename);
- const reset = useTimers(state => state.reset);
- const deleteTimer = useTimers(state => state.delete);
-
- const left = useMemo(() => total - spent, [total, spent]);
-
- const hours = useMemo(() => Math.floor(left / 3600), [left]);
- const minutes = useMemo(() => Math.floor((left % 3600) / 60), [left]);
- const seconds = useMemo(() => left % 60, [left]);
-
- const [isReversed, setIsReversed] = useState(false);
-
- const spentHours = useMemo(() => Math.floor(spent / 3600), [spent]);
- const spentMinutes = useMemo(() => Math.floor((spent % 3600) / 60), [spent]);
- const spentSeconds = useMemo(() => spent % 60, [spent]);
-
- const playAlarm = useAlarm();
-
- const showSnackbar = useSnackbar();
-
- const handleStart = () => {
- if (left > 0) setIsRunning(true);
- };
-
- const handlePause = () => setIsRunning(false);
-
- const handleToggle = () => {
- if (isRunning) handlePause();
- else handleStart();
- };
-
- const handleReset = () => {
- if (spent === 0) return;
-
- if (isRunning) return showSnackbar('Please first stop the timer.');
-
- setIsRunning(false);
- reset(id);
- };
-
- const handleDelete = () => {
- if (isRunning) return showSnackbar('Please first stop the timer.');
-
- deleteTimer(id);
- };
-
- useEffect(() => {
- if (isRunning) {
- if (intervalRef.current) clearInterval(intervalRef.current);
-
- intervalRef.current = setInterval(() => tick(id), 1000);
- }
-
- return () => {
- if (intervalRef.current) clearInterval(intervalRef.current);
- };
- }, [isRunning, tick, id]);
-
- useEffect(() => {
- if (left === 0 && isRunning) {
- setIsRunning(false);
- playAlarm();
-
- if (intervalRef.current) clearInterval(intervalRef.current);
- }
- }, [left, isRunning, playAlarm]);
-
- useEffect(() => {
- const handleBlur = () => {
- if (isRunning) {
- lastActiveTimeRef.current = Date.now();
- lastStateRef.current = { spent, total };
- }
- };
-
- const handleFocus = () => {
- if (isRunning && lastActiveTimeRef.current && lastStateRef.current) {
- const elapsed = Math.floor(
- (Date.now() - lastActiveTimeRef.current) / 1000,
- );
- const previousLeft =
- lastStateRef.current.total - lastStateRef.current.spent;
- const currentLeft = left;
- const correctedLeft = previousLeft - elapsed;
-
- if (correctedLeft < currentLeft) {
- tick(id, currentLeft - correctedLeft);
- }
-
- lastActiveTimeRef.current = null;
- lastStateRef.current = null;
- }
- };
-
- window.addEventListener('blur', handleBlur);
- window.addEventListener('focus', handleFocus);
-
- return () => {
- window.removeEventListener('blur', handleBlur);
- window.removeEventListener('focus', handleFocus);
- };
- }, [isRunning, tick, id, spent, total, left]);
-
- return (
-
-
-
-
-
-
setIsReversed(prev => !prev)}
- onKeyDown={() => setIsReversed(prev => !prev)}
- >
- {!isReversed ? (
- <>
- {padNumber(hours)}
- :
- {padNumber(minutes)}
- :
- {padNumber(seconds)}
- >
- ) : (
- <>
- -
- {padNumber(spentHours)}
- :
- {padNumber(spentMinutes)}
- :
- {padNumber(spentSeconds)}
- >
- )}
-
-
-
-
- );
-}
diff --git a/src/components/tools/timer/timers/timer/toolbar/index.ts b/src/components/tools/timer/timers/timer/toolbar/index.ts
deleted file mode 100644
index dc5abb1..0000000
--- a/src/components/tools/timer/timers/timer/toolbar/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Toolbar } from './toolbar';
diff --git a/src/components/tools/timer/timers/timer/toolbar/toolbar.module.css b/src/components/tools/timer/timers/timer/toolbar/toolbar.module.css
deleted file mode 100644
index 473234c..0000000
--- a/src/components/tools/timer/timers/timer/toolbar/toolbar.module.css
+++ /dev/null
@@ -1,37 +0,0 @@
-.toolbar {
- position: absolute;
- top: 12px;
- right: 12px;
- display: flex;
- column-gap: 4px;
- align-items: center;
- height: 30px;
- padding: 4px;
- background-color: var(--color-neutral-50);
- border: 1px solid var(--color-neutral-200);
- border-radius: 4px;
-
- & button {
- display: flex;
- align-items: center;
- justify-content: center;
- height: 100%;
- aspect-ratio: 1 / 1;
- font-size: var(--font-xsm);
- color: var(--color-foreground-subtle);
- cursor: pointer;
- background-color: transparent;
- border: none;
- transition: 0.2s;
-
- &:disabled {
- cursor: not-allowed;
- opacity: 0.2;
- }
-
- &:not(:disabled):hover {
- color: var(--color-foreground);
- background-color: var(--color-neutral-100);
- }
- }
-}
diff --git a/src/components/tools/timer/timers/timer/toolbar/toolbar.tsx b/src/components/tools/timer/timers/timer/toolbar/toolbar.tsx
deleted file mode 100644
index 7020ee8..0000000
--- a/src/components/tools/timer/timers/timer/toolbar/toolbar.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import { IoIosArrowDown, IoIosArrowUp } from 'react-icons/io';
-
-import { useTimers } from '@/stores/timers';
-
-import styles from './toolbar.module.css';
-
-interface ToolbarProps {
- first: boolean;
- id: string;
- last: boolean;
-}
-
-export function Toolbar({ first, id, last }: ToolbarProps) {
- const moveUp = useTimers(state => state.moveUp);
- const moveDown = useTimers(state => state.moveDown);
-
- return (
-
- {
- e.stopPropagation();
- moveUp(id);
- }}
- >
-
-
- {
- e.stopPropagation();
- moveDown(id);
- }}
- >
-
-
-
- );
-}
diff --git a/src/components/tools/timer/timers/timers.module.css b/src/components/tools/timer/timers/timers.module.css
deleted file mode 100644
index e8cc2c6..0000000
--- a/src/components/tools/timer/timers/timers.module.css
+++ /dev/null
@@ -1,27 +0,0 @@
-.timers {
- margin-top: 48px;
-
- & > header {
- display: flex;
- column-gap: 12px;
- align-items: center;
- margin-bottom: 16px;
-
- & .title {
- font-family: var(--font-display);
- font-size: var(--font-lg);
- line-height: 1;
- }
-
- & .line {
- flex-grow: 1;
- height: 0;
- border-top: 1px dashed var(--color-neutral-200);
- }
-
- & .spent {
- font-size: var(--font-sm);
- color: var(--color-foreground-subtle);
- }
- }
-}
diff --git a/src/components/tools/timer/timers/timers.tsx b/src/components/tools/timer/timers/timers.tsx
deleted file mode 100644
index 03ebddd..0000000
--- a/src/components/tools/timer/timers/timers.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import { useMemo } from 'react';
-import { useAutoAnimate } from '@formkit/auto-animate/react';
-
-import { Timer } from './timer';
-import { Notice } from './notice';
-
-import { useTimers } from '@/stores/timers';
-
-import styles from './timers.module.css';
-
-export function Timers() {
- const [animationParent] = useAutoAnimate();
- const [animationList] = useAutoAnimate();
-
- const timers = useTimers(state => state.timers);
- const spent = useTimers(state => state.spent());
- const total = useTimers(state => state.total());
-
- const spentMinutes = useMemo(() => Math.floor(spent / 60), [spent]);
- const totalMinutes = useMemo(() => Math.floor(total / 60), [total]);
-
- return (
-
- {timers.length > 0 ? (
-
-
-
- {timers.map(timer => (
-
- ))}
-
-
-
- ) : null}
-
- );
-}
diff --git a/src/pages/tools/breathing-exercises.astro b/src/pages/tools/breathing-exercises.astro
deleted file mode 100644
index 9331e92..0000000
--- a/src/pages/tools/breathing-exercises.astro
+++ /dev/null
@@ -1,24 +0,0 @@
----
-import Layout from '@/layouts/layout.astro';
-
-import Donate from '@/components/donate.astro';
-import Hero from '@/components/tools/hero.astro';
-import { BreathingExercises as Breathing } from '@/components/tools/breathing';
-import Footer from '@/components/footer.astro';
-import About from '@/components/tools/about.astro';
-import Source from '@/components/source.astro';
----
-
-
-
-
-
-
-
-
-
diff --git a/src/pages/tools/countdown-timer.astro b/src/pages/tools/countdown-timer.astro
deleted file mode 100644
index c10446a..0000000
--- a/src/pages/tools/countdown-timer.astro
+++ /dev/null
@@ -1,21 +0,0 @@
----
-import Layout from '@/layouts/layout.astro';
-
-import Donate from '@/components/donate.astro';
-import Hero from '@/components/tools/hero.astro';
-import { Timer } from '@/components/tools/timer';
-import Footer from '@/components/footer.astro';
-import About from '@/components/tools/about.astro';
-import Source from '@/components/source.astro';
----
-
-
-
-
-
-
-
-
-
diff --git a/src/pages/tools/notepad.astro b/src/pages/tools/notepad.astro
deleted file mode 100644
index ccabc43..0000000
--- a/src/pages/tools/notepad.astro
+++ /dev/null
@@ -1,21 +0,0 @@
----
-import Layout from '@/layouts/layout.astro';
-
-import Donate from '@/components/donate.astro';
-import Hero from '@/components/tools/hero.astro';
-import { Notepad as NotepadComponent } from '@/components/tools/notepad';
-import Footer from '@/components/footer.astro';
-import About from '@/components/tools/about.astro';
-import Source from '@/components/source.astro';
----
-
-
-
-
-
-
-
-
-
diff --git a/src/pages/tools/pomodoro.astro b/src/pages/tools/pomodoro.astro
deleted file mode 100644
index 72d4cf5..0000000
--- a/src/pages/tools/pomodoro.astro
+++ /dev/null
@@ -1,21 +0,0 @@
----
-import Layout from '@/layouts/layout.astro';
-
-import Donate from '@/components/donate.astro';
-import Hero from '@/components/tools/hero.astro';
-import { Pomodoro as PomodoroTimer } from '@/components/tools/pomodoro';
-import Footer from '@/components/footer.astro';
-import About from '@/components/tools/about.astro';
-import Source from '@/components/source.astro';
----
-
-
-
-
-
-
-
-
-
diff --git a/src/stores/alarm.ts b/src/stores/alarm.ts
deleted file mode 100644
index 2c981d1..0000000
--- a/src/stores/alarm.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { create } from 'zustand';
-
-interface AlarmStore {
- isPlaying: boolean;
- play: () => void;
- stop: () => void;
-}
-
-export const useAlarmStore = create()(set => ({
- isPlaying: false,
-
- play() {
- set({ isPlaying: true });
- },
-
- stop() {
- set({ isPlaying: false });
- },
-}));
diff --git a/src/stores/timers.ts b/src/stores/timers.ts
deleted file mode 100644
index c5c8e39..0000000
--- a/src/stores/timers.ts
+++ /dev/null
@@ -1,155 +0,0 @@
-import { v4 as uuid } from 'uuid';
-import { create } from 'zustand';
-import { createJSONStorage, persist } from 'zustand/middleware';
-
-interface Timer {
- id: string;
- name: string;
- spent: number;
- total: number;
-}
-
-interface State {
- spent: () => number;
- timers: Array;
- total: () => number;
-}
-
-interface Actions {
- add: (timer: { name: string; total: number }) => void;
- delete: (id: string) => void;
- getTimer: (id: string) => Timer & { first: boolean; last: boolean };
- moveDown: (id: string) => void;
- moveUp: (id: string) => void;
- rename: (id: string, newName: string) => void;
- reset: (id: string) => void;
- tick: (id: string, amount?: number) => void;
-}
-
-export const useTimers = create()(
- persist(
- (set, get) => ({
- add({ name, total }) {
- set(state => ({
- timers: [
- {
- id: uuid(),
- name,
- spent: 0,
- total,
- },
- ...state.timers,
- ],
- }));
- },
-
- delete(id) {
- set(state => ({
- timers: state.timers.filter(timer => timer.id !== id),
- }));
- },
-
- getTimer(id) {
- const timers = get().timers;
- const timer = timers.filter(timer => timer.id === id)[0];
- const index = timers.indexOf(timer);
-
- return {
- ...timer,
- first: index === 0,
- last: index === timers.length - 1,
- };
- },
-
- moveDown(id) {
- set(state => {
- const index = state.timers.findIndex(timer => timer.id === id);
-
- if (index < state.timers.length - 1) {
- const newTimers = [...state.timers];
-
- [newTimers[index + 1], newTimers[index]] = [
- newTimers[index],
- newTimers[index + 1],
- ];
-
- return { timers: newTimers };
- }
-
- return state;
- });
- },
-
- moveUp(id) {
- set(state => {
- const index = state.timers.findIndex(timer => timer.id === id);
-
- if (index > 0) {
- const newTimers = [...state.timers];
-
- [newTimers[index - 1], newTimers[index]] = [
- newTimers[index],
- newTimers[index - 1],
- ];
-
- return { timers: newTimers };
- }
-
- return state;
- });
- },
-
- rename(id, newName) {
- set(state => ({
- timers: state.timers.map(timer => {
- if (timer.id !== id) return timer;
-
- return { ...timer, name: newName };
- }),
- }));
- },
-
- reset(id) {
- set(state => ({
- timers: state.timers.map(timer => {
- if (timer.id !== id) return timer;
-
- return { ...timer, spent: 0 };
- }),
- }));
- },
-
- spent() {
- return get().timers.reduce((prev, curr) => prev + curr.spent, 0);
- },
-
- tick(id, amount = 1) {
- set(state => ({
- timers: state.timers.map(timer => {
- if (timer.id !== id) return timer;
-
- const updatedSpent =
- timer.spent + amount > timer.total
- ? timer.total
- : timer.spent + amount;
-
- return { ...timer, spent: updatedSpent };
- }),
- }));
- },
-
- timers: [],
-
- total() {
- return get().timers.reduce((prev, curr) => prev + curr.total, 0);
- },
- }),
- {
- name: 'moodist-countdown-timers',
- partialize: state => ({ timers: state.timers }),
- skipHydration: true,
- storage: createJSONStorage(() => localStorage),
- version: 0,
- },
- ),
-);