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];