feat: add selected sounds display module with complete functionality

- Create SelectedSoundsDisplay component to show selected sounds at the top of the page
- Add displayMode parameter to Sound component for functionality in display mode
- Implement complete audio controls including volume, speed, and rate progress bars
- Add random effects support with proper interval management
- Integrate multi-language support (Chinese: "当前声音", English: "Current Sounds")
- Update App component to include the new display module
- Use consistent styling with existing sound categories for seamless integration
- Upgrade version to 2.3.0 for this feature release
This commit is contained in:
zl 2025-11-17 12:51:06 +08:00
parent e50b782361
commit c1c4d894bc
6 changed files with 72 additions and 5 deletions

View file

@ -1,7 +1,7 @@
{ {
"name": "moodist", "name": "moodist",
"type": "module", "type": "module",
"version": "2.2.0", "version": "2.3.0",
"scripts": { "scripts": {
"dev": "astro dev", "dev": "astro dev",
"start": "astro dev", "start": "astro dev",

View file

@ -10,6 +10,7 @@ import { useTranslation } from '@/hooks/useTranslation';
import { Container } from '@/components/container'; import { Container } from '@/components/container';
import { StoreConsumer } from '@/components/store-consumer'; import { StoreConsumer } from '@/components/store-consumer';
import { Buttons } from '@/components/buttons'; import { Buttons } from '@/components/buttons';
import { SelectedSoundsDisplay } from '@/components/selected-sounds-display';
import { Categories } from '@/components/categories'; import { Categories } from '@/components/categories';
import { SharedModal } from '@/components/modals/shared'; import { SharedModal } from '@/components/modals/shared';
import { Toolbar } from '@/components/toolbar'; import { Toolbar } from '@/components/toolbar';
@ -99,6 +100,7 @@ export function App() {
<Container> <Container>
<div id="app" /> <div id="app" />
<Buttons /> <Buttons />
<SelectedSoundsDisplay />
<Categories categories={allCategories} /> <Categories categories={allCategories} />
</Container> </Container>

View file

@ -0,0 +1 @@
export { SelectedSoundsDisplay } from './selected-sounds-display';

View file

@ -0,0 +1,56 @@
import { useMemo } from 'react';
import { AnimatePresence } from 'motion/react';
import { useSoundStore } from '@/stores/sound';
import { useLocalizedSounds } from '@/hooks/useLocalizedSounds';
import { useTranslation } from '@/hooks/useTranslation';
import { Sound } from '@/components/sounds/sound';
import styles from '../sounds/sounds.module.css';
export function SelectedSoundsDisplay() {
const { t } = useTranslation();
const localizedCategories = useLocalizedSounds();
// 获取选中的声音
const selectedSoundIds = useSoundStore(state =>
Object.keys(state.sounds).filter(id => state.sounds[id].isSelected)
);
// 获取选中的声音详细信息
const selectedSounds = useMemo(() => {
const allSounds = localizedCategories
.map(category => category.sounds)
.flat();
return selectedSoundIds
.map(id => allSounds.find(sound => sound.id === id))
.filter(Boolean);
}, [selectedSoundIds, localizedCategories]);
// 如果没有选中任何声音,不显示组件
if (selectedSounds.length === 0) {
return null;
}
return (
<div className={styles.sounds}>
<AnimatePresence initial={false}>
{selectedSounds.map((sound) => (
<Sound
key={sound.id}
id={sound.id}
icon={sound.icon}
label={sound.label}
src={sound.src}
functional={false}
displayMode={true}
hidden={false}
selectHidden={() => {}}
unselectHidden={() => {}}
/>
))}
</AnimatePresence>
</div>
);
}

View file

@ -21,10 +21,11 @@ interface SoundProps extends SoundType {
hidden: boolean; hidden: boolean;
selectHidden: (key: string) => void; selectHidden: (key: string) => void;
unselectHidden: (key: string) => void; unselectHidden: (key: string) => void;
displayMode?: boolean; // 新增:展示模式参数
} }
export const Sound = forwardRef<HTMLDivElement, SoundProps>(function Sound( export const Sound = forwardRef<HTMLDivElement, SoundProps>(function Sound(
{ functional, hidden, icon, id, label, selectHidden, src, unselectHidden }, { functional, hidden, icon, id, label, selectHidden, src, unselectHidden, displayMode = false },
ref, ref,
) { ) {
const isPlaying = useSoundStore(state => state.isPlaying); const isPlaying = useSoundStore(state => state.isPlaying);
@ -60,12 +61,15 @@ export const Sound = forwardRef<HTMLDivElement, SoundProps>(function Sound(
useEffect(() => { useEffect(() => {
if (locked) return; if (locked) return;
if (isSelected && isPlaying && functional) { // 在展示模式下或者功能模式下,只要选中且在播放就应该播放
const shouldPlay = isSelected && isPlaying && (functional || displayMode);
if (shouldPlay) {
sound?.play(); sound?.play();
} else { } else {
sound?.pause(); sound?.pause();
} }
}, [isSelected, sound, isPlaying, functional, locked]); }, [isSelected, sound, isPlaying, functional, displayMode, locked]);
useEffect(() => { useEffect(() => {
if (hidden && isSelected) selectHidden(label); if (hidden && isSelected) selectHidden(label);
@ -75,7 +79,8 @@ export const Sound = forwardRef<HTMLDivElement, SoundProps>(function Sound(
// 改进的随机逻辑 - 每次只随机调整一个参数频率为1分钟 // 改进的随机逻辑 - 每次只随机调整一个参数频率为1分钟
useEffect(() => { useEffect(() => {
const hasAnyRandom = isRandomSpeed || isRandomVolume || isRandomRate; const hasAnyRandom = isRandomSpeed || isRandomVolume || isRandomRate;
if (!hasAnyRandom || !isSelected || !isPlaying) return; const isActiveMode = functional || displayMode;
if (!hasAnyRandom || !isSelected || !isPlaying || !isActiveMode) return;
const interval = setInterval(() => { const interval = setInterval(() => {
// 获取当前启用的随机选项列表 // 获取当前启用的随机选项列表

View file

@ -39,6 +39,7 @@ export interface Translations {
pause: string; pause: string;
favorite: string; favorite: string;
volume: string; volume: string;
selected_sounds: string;
// Support & Donate // Support & Donate
supportMe: string; supportMe: string;
@ -261,6 +262,7 @@ export const translations: Record<string, Translations> = {
pause: 'Pause', pause: 'Pause',
favorite: 'Favorite', favorite: 'Favorite',
volume: 'Volume', volume: 'Volume',
selected_sounds: 'Current Sounds',
// Support & Donate // Support & Donate
supportMe: 'Support Me', supportMe: 'Support Me',
@ -483,6 +485,7 @@ export const translations: Record<string, Translations> = {
pause: '暂停', pause: '暂停',
favorite: '收藏', favorite: '收藏',
volume: '音量', volume: '音量',
selected_sounds: '当前声音',
// Support & Donate // Support & Donate
supportMe: '支持我', supportMe: '支持我',