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",
"type": "module",
"version": "2.2.0",
"version": "2.3.0",
"scripts": {
"dev": "astro dev",
"start": "astro dev",

View file

@ -10,6 +10,7 @@ import { useTranslation } from '@/hooks/useTranslation';
import { Container } from '@/components/container';
import { StoreConsumer } from '@/components/store-consumer';
import { Buttons } from '@/components/buttons';
import { SelectedSoundsDisplay } from '@/components/selected-sounds-display';
import { Categories } from '@/components/categories';
import { SharedModal } from '@/components/modals/shared';
import { Toolbar } from '@/components/toolbar';
@ -99,6 +100,7 @@ export function App() {
<Container>
<div id="app" />
<Buttons />
<SelectedSoundsDisplay />
<Categories categories={allCategories} />
</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;
selectHidden: (key: string) => void;
unselectHidden: (key: string) => void;
displayMode?: boolean; // 新增:展示模式参数
}
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,
) {
const isPlaying = useSoundStore(state => state.isPlaying);
@ -60,12 +61,15 @@ export const Sound = forwardRef<HTMLDivElement, SoundProps>(function Sound(
useEffect(() => {
if (locked) return;
if (isSelected && isPlaying && functional) {
// 在展示模式下或者功能模式下,只要选中且在播放就应该播放
const shouldPlay = isSelected && isPlaying && (functional || displayMode);
if (shouldPlay) {
sound?.play();
} else {
sound?.pause();
}
}, [isSelected, sound, isPlaying, functional, locked]);
}, [isSelected, sound, isPlaying, functional, displayMode, locked]);
useEffect(() => {
if (hidden && isSelected) selectHidden(label);
@ -75,7 +79,8 @@ export const Sound = forwardRef<HTMLDivElement, SoundProps>(function Sound(
// 改进的随机逻辑 - 每次只随机调整一个参数频率为1分钟
useEffect(() => {
const hasAnyRandom = isRandomSpeed || isRandomVolume || isRandomRate;
if (!hasAnyRandom || !isSelected || !isPlaying) return;
const isActiveMode = functional || displayMode;
if (!hasAnyRandom || !isSelected || !isPlaying || !isActiveMode) return;
const interval = setInterval(() => {
// 获取当前启用的随机选项列表

View file

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