wwf
2 天以前 a430284aa21e3ae1f0d5654e55b2ad2852519cc2
app/components/base/audio-gallery/AudioPlayer.tsx
@@ -1,13 +1,7 @@
import React, { useCallback, useEffect, useRef, useState } from 'react'
import { t } from 'i18next'
import {
  RiPauseCircleFill,
  RiPlayLargeFill,
} from '@remixicon/react'
import styles from './AudioPlayer.module.css'
import Toast from '@/app/components/base/toast'
import useTheme from '@/hooks/use-theme'
import { Theme } from '@/types/app'
import cn from '@/utils/classnames'
type AudioPlayerProps = {
  src: string
@@ -24,7 +18,6 @@
  const [hasStartedPlaying, setHasStartedPlaying] = useState(false)
  const [hoverTime, setHoverTime] = useState(0)
  const [isAudioAvailable, setIsAudioAvailable] = useState(true)
  const { theme } = useTheme()
  useEffect(() => {
    const audio = audioRef.current
@@ -62,7 +55,7 @@
    audio.load()
    // Delayed generation of waveform data
    // eslint-disable-next-line ts/no-use-before-define
    // eslint-disable-next-line @typescript-eslint/no-use-before-define
    const timer = setTimeout(() => generateWaveformData(src), 1000)
    return () => {
@@ -124,7 +117,7 @@
      setWaveformData(normalizedWaveform)
      setIsAudioAvailable(true)
    }
    catch {
    catch (error) {
      const waveform: number[] = []
      let prevValue = Math.random()
@@ -237,11 +230,11 @@
      let color
      if (index * barWidth <= playedWidth)
        color = theme === Theme.light ? '#296DFF' : '#84ABFF'
        color = '#296DFF'
      else if ((index * barWidth / width) * duration <= hoverTime)
        color = theme === Theme.light ? 'rgba(21,90,239,.40)' : 'rgba(200, 206, 218, 0.28)'
        color = 'rgba(21,90,239,.40)'
      else
        color = theme === Theme.light ? 'rgba(21,90,239,.20)' : 'rgba(200, 206, 218, 0.14)'
        color = 'rgba(21,90,239,.20)'
      const barHeight = value * height
      const rectX = index * barWidth
@@ -260,7 +253,7 @@
        ctx.fillRect(rectX, rectY, rectWidth, rectHeight)
      }
    })
  }, [currentTime, duration, hoverTime, theme, waveformData])
  }, [currentTime, duration, hoverTime, waveformData])
  useEffect(() => {
    drawWaveform()
@@ -286,32 +279,40 @@
  }, [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'>
    <div className={styles.audioPlayer}>
      <audio ref={audioRef} src={src} preload="auto"/>
      <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}>
      <button className={styles.playButton} onClick={togglePlay} disabled={!isAudioAvailable}>
        {isPlaying
          ? (
            <RiPauseCircleFill className='h-5 w-5' />
            <svg viewBox="0 0 24 24" width="16" height="16">
              <rect x="7" y="6" width="3" height="12" rx="1.5" ry="1.5"/>
              <rect x="15" y="6" width="3" height="12" rx="1.5" ry="1.5"/>
            </svg>
          )
          : (
            <RiPlayLargeFill className='h-5 w-5' />
            <svg viewBox="0 0 24 24" width="16" height="16">
              <path d="M8 5v14l11-7z" fill="currentColor"/>
            </svg>
          )}
      </button>
      <div className={cn(isAudioAvailable && 'grow')} hidden={!isAudioAvailable}>
        <div className='flex h-8 items-center justify-center'>
      <div className={isAudioAvailable ? styles.audioControls : styles.audioControls_disabled} hidden={!isAudioAvailable}>
        <div className={styles.progressBarContainer}>
          <canvas
            ref={canvasRef}
            className='relative flex h-6 w-full grow cursor-pointer items-center justify-center'
            className={styles.waveform}
            onClick={handleCanvasInteraction}
            onMouseMove={handleMouseMove}
            onMouseDown={handleCanvasInteraction}
          />
          <div className='system-xs-medium inline-flex min-w-[50px] items-center justify-center text-text-accent-secondary'>
            <span className='rounded-[10px] px-0.5 py-1'>{formatTime(duration)}</span>
          {/* <div className={styles.currentTime} style={{ left: `${(currentTime / duration) * 81}%`, bottom: '29px' }}>
            {formatTime(currentTime)}
          </div> */}
          <div className={styles.timeDisplay}>
            <span className={styles.duration}>{formatTime(duration)}</span>
          </div>
        </div>
      </div>
      <div className='absolute left-0 top-0 flex h-full w-full items-center justify-center text-text-quaternary' hidden={isAudioAvailable}>{t('common.operation.audioSourceUnavailable')}</div>
      <div className={styles.source_unavailable} hidden={isAudioAvailable}>{t('common.operation.audioSourceUnavailable')}</div>
    </div>
  )
}