Feat/web workflow improvements (#27981)

Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com>
Co-authored-by: johnny0120 <johnny0120@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Wood <tuiskuwood@outlook.com>
This commit is contained in:
Xiu-Lan
2025-11-25 19:54:40 +08:00
committed by GitHub
parent ce00388278
commit abc13ef762
24 changed files with 179 additions and 62 deletions

View File

@@ -10,10 +10,11 @@ import { Theme } from '@/types/app'
import cn from '@/utils/classnames'
type AudioPlayerProps = {
src: string
src?: string // Keep backward compatibility
srcs?: string[] // Support multiple sources
}
const AudioPlayer: React.FC<AudioPlayerProps> = ({ src }) => {
const AudioPlayer: React.FC<AudioPlayerProps> = ({ src, srcs }) => {
const [isPlaying, setIsPlaying] = useState(false)
const [currentTime, setCurrentTime] = useState(0)
const [duration, setDuration] = useState(0)
@@ -61,19 +62,22 @@ const AudioPlayer: React.FC<AudioPlayerProps> = ({ src }) => {
// Preload audio metadata
audio.load()
// Delayed generation of waveform data
// eslint-disable-next-line ts/no-use-before-define
const timer = setTimeout(() => generateWaveformData(src), 1000)
return () => {
audio.removeEventListener('loadedmetadata', setAudioData)
audio.removeEventListener('timeupdate', setAudioTime)
audio.removeEventListener('progress', handleProgress)
audio.removeEventListener('ended', handleEnded)
audio.removeEventListener('error', handleError)
clearTimeout(timer)
// Use the first source or src to generate waveform
const primarySrc = srcs?.[0] || src
if (primarySrc) {
// Delayed generation of waveform data
// eslint-disable-next-line ts/no-use-before-define
const timer = setTimeout(() => generateWaveformData(primarySrc), 1000)
return () => {
audio.removeEventListener('loadedmetadata', setAudioData)
audio.removeEventListener('timeupdate', setAudioTime)
audio.removeEventListener('progress', handleProgress)
audio.removeEventListener('ended', handleEnded)
audio.removeEventListener('error', handleError)
clearTimeout(timer)
}
}
}, [src])
}, [src, srcs])
const generateWaveformData = async (audioSrc: string) => {
if (!window.AudioContext && !(window as any).webkitAudioContext) {
@@ -85,8 +89,9 @@ const AudioPlayer: React.FC<AudioPlayerProps> = ({ src }) => {
return null
}
const url = new URL(src)
const isHttp = url.protocol === 'http:' || url.protocol === 'https:'
const primarySrc = srcs?.[0] || src
const url = primarySrc ? new URL(primarySrc) : null
const isHttp = url ? (url.protocol === 'http:' || url.protocol === 'https:') : false
if (!isHttp) {
setIsAudioAvailable(false)
return null
@@ -286,8 +291,13 @@ const AudioPlayer: React.FC<AudioPlayerProps> = ({ src }) => {
}, [duration])
return (
<div className='flex h-9 min-w-[240px] max-w-[420px] items-end gap-2 rounded-[10px] border border-components-panel-border-subtle bg-components-chat-input-audio-bg-alt p-2 shadow-xs backdrop-blur-sm'>
<audio ref={audioRef} src={src} preload="auto"/>
<div className='flex h-9 min-w-[240px] max-w-[420px] items-center gap-2 rounded-[10px] border border-components-panel-border-subtle bg-components-chat-input-audio-bg-alt p-2 shadow-xs backdrop-blur-sm'>
<audio ref={audioRef} src={src} preload="auto">
{/* If srcs array is provided, render multiple source elements */}
{srcs && srcs.map((srcUrl, index) => (
<source key={index} src={srcUrl} />
))}
</audio>
<button type="button" className='inline-flex shrink-0 cursor-pointer items-center justify-center border-none text-text-accent transition-all hover:text-text-accent-secondary disabled:text-components-button-primary-bg-disabled' onClick={togglePlay} disabled={!isAudioAvailable}>
{isPlaying
? (