mirror of
https://github.com/remvze/moodist.git
synced 2025-12-17 08:54:13 +00:00
feat: implement shuffling functionality
This commit is contained in:
parent
b634d6f3c3
commit
3ac211e355
6 changed files with 90 additions and 0 deletions
|
|
@ -9,6 +9,7 @@ import { StoreConsumer } from '@/components/store-consumer';
|
||||||
import { Buttons } from '@/components/buttons';
|
import { Buttons } from '@/components/buttons';
|
||||||
import { Categories } from '@/components/categories';
|
import { Categories } from '@/components/categories';
|
||||||
import { ScrollToTop } from '@/components/scroll-to-top';
|
import { ScrollToTop } from '@/components/scroll-to-top';
|
||||||
|
import { Shuffle } from '@/components/shuffle';
|
||||||
import { SnackbarProvider } from '@/contexts/snackbar';
|
import { SnackbarProvider } from '@/contexts/snackbar';
|
||||||
|
|
||||||
import { sounds } from '@/data/sounds';
|
import { sounds } from '@/data/sounds';
|
||||||
|
|
@ -59,6 +60,7 @@ export function App() {
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<ScrollToTop />
|
<ScrollToTop />
|
||||||
|
<Shuffle />
|
||||||
</StoreConsumer>
|
</StoreConsumer>
|
||||||
</SnackbarProvider>
|
</SnackbarProvider>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
1
src/components/shuffle/index.ts
Normal file
1
src/components/shuffle/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { Shuffle } from './shuffle';
|
||||||
17
src/components/shuffle/shuffle.module.css
Normal file
17
src/components/shuffle/shuffle.module.css
Normal file
|
|
@ -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);
|
||||||
|
}
|
||||||
22
src/components/shuffle/shuffle.tsx
Normal file
22
src/components/shuffle/shuffle.tsx
Normal file
|
|
@ -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 (
|
||||||
|
<Tooltip content="Shuffle sounds" hideDelay={0} showDelay={0}>
|
||||||
|
<button
|
||||||
|
aria-label="Shuffle sounds"
|
||||||
|
className={styles.button}
|
||||||
|
onClick={shuffle}
|
||||||
|
>
|
||||||
|
<BiShuffle />
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
26
src/helpers/random.ts
Normal file
26
src/helpers/random.ts
Normal file
|
|
@ -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<T>(array: Array<T>): T {
|
||||||
|
const randomIndex = random(0, array.length);
|
||||||
|
|
||||||
|
return array[randomIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pickMany<T>(array: Array<T>, count: number): Array<T> {
|
||||||
|
const shuffled = shuffle(array);
|
||||||
|
|
||||||
|
return shuffled.slice(0, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shuffle<T>(array: Array<T>): Array<T> {
|
||||||
|
return array
|
||||||
|
.map(value => ({ sort: Math.random(), value }))
|
||||||
|
.sort((a, b) => a.sort - b.sort)
|
||||||
|
.map(({ value }) => value);
|
||||||
|
}
|
||||||
|
|
@ -2,12 +2,15 @@ import type { StateCreator } from 'zustand';
|
||||||
|
|
||||||
import type { SoundState } from './sound.state';
|
import type { SoundState } from './sound.state';
|
||||||
|
|
||||||
|
import { pickMany, random } from '@/helpers/random';
|
||||||
|
|
||||||
export interface SoundActions {
|
export interface SoundActions {
|
||||||
pause: () => void;
|
pause: () => void;
|
||||||
play: () => void;
|
play: () => void;
|
||||||
restoreHistory: () => void;
|
restoreHistory: () => void;
|
||||||
select: (id: string) => void;
|
select: (id: string) => void;
|
||||||
setVolume: (id: string, volume: number) => void;
|
setVolume: (id: string, volume: number) => void;
|
||||||
|
shuffle: () => void;
|
||||||
toggleFavorite: (id: string) => void;
|
toggleFavorite: (id: string) => void;
|
||||||
togglePlay: () => void;
|
togglePlay: () => void;
|
||||||
unselect: (id: string) => 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) {
|
toggleFavorite(id) {
|
||||||
const sounds = get().sounds;
|
const sounds = get().sounds;
|
||||||
const sound = sounds[id];
|
const sound = sounds[id];
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue