diff --git a/qwen3-tts-frontend/src/components/ChapterPlayer.module.css b/qwen3-tts-frontend/src/components/ChapterPlayer.module.css
new file mode 100644
index 0000000..337f293
--- /dev/null
+++ b/qwen3-tts-frontend/src/components/ChapterPlayer.module.css
@@ -0,0 +1,123 @@
+.panel {
+ padding: 0.625rem 0.75rem 0.75rem;
+ background: rgb(249 115 22 / 0.12);
+ box-shadow: 0 -6px 24px rgba(0, 0, 0, 0.1);
+ border-top: 2px solid rgb(249 115 22 / 0.4);
+ position: relative;
+ z-index: 10;
+}
+
+.header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 0.5rem;
+ gap: 0.5rem;
+}
+
+.title {
+ font-size: 0.7rem;
+ font-weight: 600;
+ letter-spacing: 0.03em;
+ text-transform: uppercase;
+ color: rgb(249 115 22 / 0.85);
+ flex-shrink: 0;
+}
+
+.chapterName {
+ font-size: 0.75rem;
+ font-weight: 500;
+ color: hsl(var(--foreground) / 0.75);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ min-width: 0;
+}
+
+.waveformWrapper {
+ display: flex;
+ align-items: center;
+ border: 1px solid hsl(var(--border) / 0.6);
+ border-radius: var(--radius);
+ padding: 0.625rem 0.75rem;
+ background: hsl(var(--muted) / 0.3);
+ width: 100%;
+}
+
+.waveformWrapper :global(.waveform-player) {
+ background: transparent;
+ border: none;
+ padding: 0;
+ width: 100%;
+}
+
+.waveformWrapper :global(.waveform-btn) {
+ color: hsl(var(--foreground));
+ border-color: hsl(var(--border));
+ background: transparent;
+ transition: all 150ms ease;
+}
+
+.waveformWrapper :global(.waveform-btn:hover) {
+ color: rgb(249 115 22);
+ border-color: rgb(249 115 22);
+}
+
+.waveformWrapper :global(.waveform-canvas) {
+ border-radius: 3px;
+}
+
+.waveformWrapper :global(.waveform-title) {
+ display: none;
+}
+
+.waveformWrapper :global(.waveform-body) {
+ width: 100%;
+ align-items: center;
+}
+
+.waveformWrapper :global(.waveform-track) {
+ width: 100%;
+}
+
+.waveformWrapper :global(.waveform-info) {
+ justify-content: center;
+}
+
+.waveformWrapper :global(.waveform-text) {
+ display: none;
+}
+
+.waveformWrapper :global(.waveform-time) {
+ color: hsl(var(--muted-foreground));
+ font-size: 0.875rem;
+ font-weight: 500;
+}
+
+.waveformInner {
+ flex: 1;
+ min-width: 0;
+ width: 100%;
+}
+
+.subtitle {
+ margin-top: 0.5rem;
+ padding: 0 0.25rem;
+ display: flex;
+ align-items: baseline;
+ gap: 0.375rem;
+}
+
+.subtitleName {
+ font-size: 0.7rem;
+ font-weight: 700;
+ color: rgb(249 115 22);
+ flex-shrink: 0;
+ letter-spacing: 0.01em;
+}
+
+.subtitleText {
+ font-size: 0.75rem;
+ color: hsl(var(--muted-foreground));
+ line-height: 1.5;
+}
diff --git a/qwen3-tts-frontend/src/components/ChapterPlayer.tsx b/qwen3-tts-frontend/src/components/ChapterPlayer.tsx
index 9c7444b..85adbb3 100644
--- a/qwen3-tts-frontend/src/components/ChapterPlayer.tsx
+++ b/qwen3-tts-frontend/src/components/ChapterPlayer.tsx
@@ -6,7 +6,7 @@ import { Button } from '@/components/ui/button'
import { X, Loader2 } from 'lucide-react'
import apiClient from '@/lib/api'
import { audiobookApi, type AudiobookSegment } from '@/lib/api/audiobook'
-import styles from './AudioPlayer.module.css'
+import styles from './ChapterPlayer.module.css'
interface TimelineItem {
seg: AudiobookSegment
@@ -117,15 +117,15 @@ const ChapterPlayer = memo(({
}
const waveformColor = theme === 'dark' ? '#4b5563' : '#d1d5db'
- const progressColor = theme === 'dark' ? '#a78bfa' : '#7c3aed'
+ const progressColor = '#f97316'
const player = new WaveformPlayer(containerRef.current, {
url: blobUrl,
waveformStyle: 'mirror',
- height: 60,
- barWidth: 3,
+ height: 56,
+ barWidth: 2,
barSpacing: 1,
- samples: 200,
+ samples: 260,
waveformColor,
progressColor,
showTime: true,
@@ -161,17 +161,16 @@ const ChapterPlayer = memo(({
}, [])
return (
-
-
-
- {chapterTitle}
- {isLoadingTimeline && !isLoadingChapter && (
-
- 字幕轨道加载中…
-
- )}
-
-