feat(core): add reload button to audio block (#12451)

Related to: [BS-3143](https://linear.app/affine-design/issue/BS-3143/更新-loading-和错误样式)

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Added a reload button with an icon for audio blocks, allowing users to retry loading audio files if an error occurs.
  - Error messages are now displayed with actionable options when audio loading fails.

- **Enhancements**
  - Audio file sizes are now shown in a human-readable format within the audio player.
  - Improved display of audio file information, including error messages and formatted descriptions.

- **Style**
  - Updated styling for audio player and audio block components, including new styles for error states and reload button.
  - Renamed and refined audio player description styling for better layout and spacing.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
fundon
2025-05-23 06:04:07 +00:00
parent 3d9b13c53c
commit e2e00688a9
7 changed files with 72 additions and 24 deletions

View File

@@ -60,8 +60,9 @@ export const spacer = style({
flex: 1,
});
export const sizeInfo = style({
export const description = style({
display: 'flex',
gap: '8px',
alignItems: 'center',
fontSize: cssVar('fontXs'),
color: cssVarV2('text/secondary'),

View File

@@ -1,5 +1,6 @@
import type { Meta, StoryObj } from '@storybook/react';
import { useCallback, useEffect, useRef, useState } from 'react';
import bytes from 'bytes';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { AudioPlayer, MiniAudioPlayer } from './audio-player';
@@ -159,6 +160,10 @@ const AudioWrapper = () => {
}
}, []);
const description = useMemo(() => {
return audioFile ? <>{bytes(audioFile.size)}</> : null;
}, [audioFile]);
useEffect(() => {
const audio = audioRef.current;
if (!audio || !audioFile) return;
@@ -296,7 +301,7 @@ const AudioWrapper = () => {
/>
<MiniAudioPlayer
name={audioFile.name}
size={audioFile.size}
description={description}
waveform={waveform}
playbackState={playbackState}
seekTime={seekTime}
@@ -311,7 +316,7 @@ const AudioWrapper = () => {
/>
<AudioPlayer
name={audioFile.name}
size={audioFile.size}
description={description}
waveform={waveform}
playbackState={playbackState}
seekTime={seekTime}

View File

@@ -4,7 +4,6 @@ import {
RewindFifteenSecondsIcon,
VoiceIcon,
} from '@blocksuite/icons/rc';
import bytes from 'bytes';
import { clamp } from 'lodash-es';
import { type MouseEventHandler, type ReactNode, useCallback } from 'react';
@@ -24,7 +23,7 @@ const formatTime = (seconds: number): string => {
export interface AudioPlayerProps {
// Audio metadata
name: string;
size: number | ReactNode; // the size entry may be used for drawing error message
description?: ReactNode; // Display file size or error message
waveform: number[] | null;
// Playback state
playbackState: 'idle' | 'playing' | 'paused' | 'stopped';
@@ -52,7 +51,7 @@ const playbackRates = [0.5, 0.75, 1, 1.5, 1.75, 2, 3];
export const AudioPlayer = ({
name,
size,
description,
playbackState,
seekTime,
duration,
@@ -108,9 +107,7 @@ export const AudioPlayer = ({
<div className={styles.nameLabel}>{name}</div>
</div>
<div className={styles.upperRow}>
<div className={styles.sizeInfo}>
{typeof size === 'number' ? bytes(size) : size}
</div>
<div className={styles.description}>{description}</div>
</div>
</div>
<div className={styles.upperRight}>