Feat: web app dark mode (#14732)

This commit is contained in:
KVOJJJin
2025-03-03 14:44:51 +08:00
committed by GitHub
parent e53052ab7a
commit d0d0bf570e
98 changed files with 3006 additions and 2496 deletions

View File

@@ -1,7 +1,13 @@
import React, { useCallback, useEffect, useRef, useState } from 'react'
import { t } from 'i18next'
import styles from './AudioPlayer.module.css'
import {
RiPauseCircleFill,
RiPlayLargeFill,
} from '@remixicon/react'
import Toast from '@/app/components/base/toast'
import { useAppContext } from '@/context/app-context'
import { Theme } from '@/types/app'
import cn from '@/utils/classnames'
type AudioPlayerProps = {
src: string
@@ -18,6 +24,7 @@ const AudioPlayer: React.FC<AudioPlayerProps> = ({ src }) => {
const [hasStartedPlaying, setHasStartedPlaying] = useState(false)
const [hoverTime, setHoverTime] = useState(0)
const [isAudioAvailable, setIsAudioAvailable] = useState(true)
const { theme } = useAppContext()
useEffect(() => {
const audio = audioRef.current
@@ -230,11 +237,11 @@ const AudioPlayer: React.FC<AudioPlayerProps> = ({ src }) => {
let color
if (index * barWidth <= playedWidth)
color = '#296DFF'
color = theme === Theme.light ? '#296DFF' : '#84ABFF'
else if ((index * barWidth / width) * duration <= hoverTime)
color = 'rgba(21,90,239,.40)'
color = theme === Theme.light ? 'rgba(21,90,239,.40)' : 'rgba(200, 206, 218, 0.28)'
else
color = 'rgba(21,90,239,.20)'
color = theme === Theme.light ? 'rgba(21,90,239,.20)' : 'rgba(200, 206, 218, 0.14)'
const barHeight = value * height
const rectX = index * barWidth
@@ -253,7 +260,7 @@ const AudioPlayer: React.FC<AudioPlayerProps> = ({ src }) => {
ctx.fillRect(rectX, rectY, rectWidth, rectHeight)
}
})
}, [currentTime, duration, hoverTime, waveformData])
}, [currentTime, duration, hoverTime, theme, waveformData])
useEffect(() => {
drawWaveform()
@@ -279,40 +286,32 @@ const AudioPlayer: React.FC<AudioPlayerProps> = ({ src }) => {
}, [duration])
return (
<div className={styles.audioPlayer}>
<div className='flex items-end gap-2 h-9 min-w-[240px] max-w-[420px] p-2 bg-components-chat-input-audio-bg-alt backdrop-blur-sm rounded-[10px] border border-components-panel-border-subtle shadow-xs'>
<audio ref={audioRef} src={src} preload="auto"/>
<button className={styles.playButton} onClick={togglePlay} disabled={!isAudioAvailable}>
<button className='shrink-0 inline-flex items-center justify-center border-none text-text-accent hover:text-text-accent-secondary transition-all cursor-pointer disabled:text-components-button-primary-bg-disabled' onClick={togglePlay} disabled={!isAudioAvailable}>
{isPlaying
? (
<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>
<RiPauseCircleFill className='w-5 h-5' />
)
: (
<svg viewBox="0 0 24 24" width="16" height="16">
<path d="M8 5v14l11-7z" fill="currentColor"/>
</svg>
<RiPlayLargeFill className='w-5 h-5' />
)}
</button>
<div className={isAudioAvailable ? styles.audioControls : styles.audioControls_disabled} hidden={!isAudioAvailable}>
<div className={styles.progressBarContainer}>
<div className={cn(isAudioAvailable && 'grow')} hidden={!isAudioAvailable}>
<div className='h-8 flex items-center justify-center'>
<canvas
ref={canvasRef}
className={styles.waveform}
className='relative grow h-6 w-full flex items-center justify-center cursor-pointer'
onClick={handleCanvasInteraction}
onMouseMove={handleMouseMove}
onMouseDown={handleCanvasInteraction}
/>
{/* <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 className='inline-flex items-center justify-center min-w-[50px] text-text-accent-secondary system-xs-medium'>
<span className='px-0.5 py-1 rounded-[10px]'>{formatTime(duration)}</span>
</div>
</div>
</div>
<div className={styles.source_unavailable} hidden={isAudioAvailable}>{t('common.operation.audioSourceUnavailable')}</div>
<div className='absolute top-0 left-0 w-full h-full flex items-center justify-center text-text-quaternary' hidden={isAudioAvailable}>{t('common.operation.audioSourceUnavailable')}</div>
</div>
)
}