diff --git a/src/components/app/app.tsx b/src/components/app/app.tsx index 122045c..1cd3257 100644 --- a/src/components/app/app.tsx +++ b/src/components/app/app.tsx @@ -9,6 +9,7 @@ import { StoreConsumer } from '@/components/store-consumer'; import { Buttons } from '@/components/buttons'; import { Categories } from '@/components/categories'; import { ScrollToTop } from '@/components/scroll-to-top'; +import { Shuffle } from '@/components/shuffle'; import { SnackbarProvider } from '@/contexts/snackbar'; import { sounds } from '@/data/sounds'; @@ -59,6 +60,7 @@ export function App() { + ); diff --git a/src/components/shuffle/index.ts b/src/components/shuffle/index.ts new file mode 100644 index 0000000..ec21ac8 --- /dev/null +++ b/src/components/shuffle/index.ts @@ -0,0 +1 @@ +export { Shuffle } from './shuffle'; diff --git a/src/components/shuffle/shuffle.module.css b/src/components/shuffle/shuffle.module.css new file mode 100644 index 0000000..d96a653 --- /dev/null +++ b/src/components/shuffle/shuffle.module.css @@ -0,0 +1,17 @@ +.button { + position: fixed; + z-index: 99; + right: 20px; + bottom: 20px; + display: flex; + width: 45px; + height: 45px; + align-items: center; + justify-content: center; + border: 1px solid var(--color-neutral-300); + border-radius: 50%; + background-color: var(--color-neutral-100); + color: var(--color-foreground); + cursor: pointer; + font-size: var(--font-md); +} diff --git a/src/components/shuffle/shuffle.tsx b/src/components/shuffle/shuffle.tsx new file mode 100644 index 0000000..121a3f8 --- /dev/null +++ b/src/components/shuffle/shuffle.tsx @@ -0,0 +1,22 @@ +import { BiShuffle } from 'react-icons/bi/index'; + +import { Tooltip } from '@/components/tooltip'; +import { useSoundStore } from '@/store'; + +import styles from './shuffle.module.css'; + +export function Shuffle() { + const shuffle = useSoundStore(state => state.shuffle); + + return ( + + + + ); +} diff --git a/src/helpers/random.ts b/src/helpers/random.ts new file mode 100644 index 0000000..c05fbeb --- /dev/null +++ b/src/helpers/random.ts @@ -0,0 +1,26 @@ +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 pick(array: Array): T { + const randomIndex = random(0, array.length); + + return array[randomIndex]; +} + +export function pickMany(array: Array, count: number): Array { + const shuffled = shuffle(array); + + return shuffled.slice(0, count); +} + +export function shuffle(array: Array): Array { + return array + .map(value => ({ sort: Math.random(), value })) + .sort((a, b) => a.sort - b.sort) + .map(({ value }) => value); +} diff --git a/src/store/sound/sound.actions.ts b/src/store/sound/sound.actions.ts index 21ab853..323f31d 100644 --- a/src/store/sound/sound.actions.ts +++ b/src/store/sound/sound.actions.ts @@ -2,12 +2,15 @@ import type { StateCreator } from 'zustand'; import type { SoundState } from './sound.state'; +import { pickMany, random } from '@/helpers/random'; + export interface SoundActions { pause: () => void; play: () => void; restoreHistory: () => void; select: (id: string) => void; setVolume: (id: string, volume: number) => void; + shuffle: () => void; toggleFavorite: (id: string) => void; togglePlay: () => void; unselect: (id: string) => void; @@ -56,6 +59,25 @@ export const createActions: StateCreator< }); }, + shuffle() { + const sounds = get().sounds; + const ids = Object.keys(sounds); + + ids.forEach(id => { + sounds[id].isSelected = false; + sounds[id].volume = 0.5; + }); + + const randomIDs = pickMany(ids, 4); + + randomIDs.forEach(id => { + sounds[id].isSelected = true; + sounds[id].volume = random(0.2, 1); + }); + + set({ history: null, isPlaying: true, sounds }); + }, + toggleFavorite(id) { const sounds = get().sounds; const sound = sounds[id];