diff --git a/src/components/buttons/buttons.module.css b/src/components/buttons/buttons.module.css index e53a005..34f0e9a 100644 --- a/src/components/buttons/buttons.module.css +++ b/src/components/buttons/buttons.module.css @@ -25,12 +25,16 @@ line-height: 0; outline: none; + &:disabled { + cursor: default; + } + & span { font-size: var(--font-lg); } } - & .shuffleButton { + & .smallButton { display: flex; width: 45px; height: 45px; @@ -47,5 +51,24 @@ font-size: var(--font-md); line-height: 0; outline: none; + transition: 0.2s; + + &:disabled { + cursor: default; + } + + &.restore { + border-top-color: #34d399; + border-bottom-color: #047857; + background-color: #10b981; + color: var(--color-foreground); + } + + &.delete { + border-top-color: #fb7185; + border-bottom-color: #be123c; + background-color: #f43f5e; + color: var(--color-foreground); + } } } diff --git a/src/components/buttons/buttons.tsx b/src/components/buttons/buttons.tsx index 8d9d694..8e879f8 100644 --- a/src/components/buttons/buttons.tsx +++ b/src/components/buttons/buttons.tsx @@ -1,15 +1,18 @@ import { useEffect } from 'react'; -import { BiPause, BiPlay, BiShuffle } from 'react-icons/bi/index'; +import { BiPause, BiPlay, BiUndo, BiTrash } from 'react-icons/bi/index'; import { useSoundStore } from '@/store'; import { usePlay } from '@/contexts/play'; +import { cn } from '@/helpers/styles'; import styles from './buttons.module.css'; export function Buttons() { - const { isPlaying, pause, play, toggle } = usePlay(); + const { isPlaying, pause, toggle } = usePlay(); const noSelected = useSoundStore(state => state.noSelected()); - const shuffle = useSoundStore(state => state.shuffle); + const restoreHistory = useSoundStore(state => state.restoreHistory); + const hasHistory = useSoundStore(state => !!state.history); + const unselectAll = useSoundStore(state => state.unselectAll); const handleClick = () => { if (noSelected) return pause(); @@ -23,7 +26,11 @@ export function Buttons() { return (
-
); diff --git a/src/helpers/random.ts b/src/helpers/random.ts deleted file mode 100644 index 8e577c2..0000000 --- a/src/helpers/random.ts +++ /dev/null @@ -1,26 +0,0 @@ -export function random(min: number, max: number): number { - return Math.random() * (max - min) + min; -} - -export function randomInt(min: number, max: number): number { - return Math.floor(random(min, max)); -} - -export function pickOne(array: Array): T { - const randomIndex = random(0, array.length); - - return array[randomIndex]; -} - -export function shuffle(array: Array): Array { - return array - .map(value => ({ sort: Math.random(), value })) - .sort((a, b) => a.sort - b.sort) - .map(({ value }) => value); -} - -export function pickMany(array: Array, count: number): Array { - const shuffled = shuffle(array); - - return shuffled.slice(0, count); -} diff --git a/src/store/sound/index.ts b/src/store/sound/index.ts index e44b43f..b301dff 100644 --- a/src/store/sound/index.ts +++ b/src/store/sound/index.ts @@ -12,6 +12,7 @@ export const useSoundStore = create()( }), { name: 'moodist-sounds', + partialize: state => ({ sounds: state.sounds }), skipHydration: true, storage: createJSONStorage(() => localStorage), version: 0, diff --git a/src/store/sound/sound.actions.ts b/src/store/sound/sound.actions.ts index 2c18b96..1d4f9a2 100644 --- a/src/store/sound/sound.actions.ts +++ b/src/store/sound/sound.actions.ts @@ -2,14 +2,12 @@ import type { StateCreator } from 'zustand'; import type { SoundState } from './sound.state'; -import { pickMany, random } from '@/helpers/random'; - export interface SoundActions { select: (id: string) => void; unselect: (id: string) => void; setVolume: (id: string, volume: number) => void; - unselectAll: () => void; - shuffle: () => void; + unselectAll: (pushToHistory?: boolean) => void; + restoreHistory: () => void; } export const createActions: StateCreator< @@ -19,6 +17,14 @@ export const createActions: StateCreator< SoundActions > = (set, get) => { return { + restoreHistory() { + const history = get().history; + + if (!history) return; + + set({ history: null, sounds: history }); + }, + select(id) { set({ sounds: { @@ -37,21 +43,6 @@ export const createActions: StateCreator< }); }, - shuffle() { - get().unselectAll(); - - const sounds = get().sounds; - const ids = Object.keys(sounds); - const randomIDs = pickMany(ids, 4); - - randomIDs.forEach(id => { - sounds[id].isSelected = true; - sounds[id].volume = random(0.2, 0.8); - }); - - set({ sounds }); - }, - unselect(id) { set({ sounds: { @@ -61,8 +52,18 @@ export const createActions: StateCreator< }); }, - unselectAll() { + unselectAll(pushToHistory = false) { + const noSelected = get().noSelected(); + + if (noSelected) return; + const sounds = get().sounds; + + if (pushToHistory) { + const history = JSON.parse(JSON.stringify(sounds)); + set({ history }); + } + const ids = Object.keys(sounds); ids.forEach(id => { diff --git a/src/store/sound/sound.state.ts b/src/store/sound/sound.state.ts index 3019c6d..6857fa0 100644 --- a/src/store/sound/sound.state.ts +++ b/src/store/sound/sound.state.ts @@ -11,6 +11,12 @@ export interface SoundState { volume: number; }; }; + history: { + [id: string]: { + isSelected: boolean; + volume: number; + }; + } | null; noSelected: () => boolean; } @@ -21,13 +27,13 @@ export const createState: StateCreator< SoundState > = (set, get) => { const state: SoundState = { + history: null, noSelected() { const { sounds } = get(); const keys = Object.keys(sounds); return keys.every(key => !sounds[key].isSelected); }, - sounds: {}, };