Skip to content

Commit 0e4d2d2

Browse files
committed
refactor: simplify audio attachment playback component
1 parent 9676e72 commit 0e4d2d2

File tree

4 files changed

+25
-58
lines changed

4 files changed

+25
-58
lines changed

web/src/components/MemoEditor/components/VoiceRecorderPanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,10 @@ export const VoiceRecorderPanel: FC<VoiceRecorderPanelProps> = ({
8787
<div className="mt-3">
8888
<AudioAttachmentItem
8989
filename={recording.localFile.file.name}
90-
displayName="Voice note"
9190
sourceUrl={recording.localFile.previewUrl}
9291
mimeType={recording.mimeType}
9392
size={recording.localFile.file.size}
93+
title="Voice note"
9494
/>
9595
</div>
9696
)}

web/src/components/MemoMetadata/Attachment/AttachmentListEditor.tsx

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { cn } from "@/lib/utils";
66
import type { Attachment } from "@/types/proto/api/v1/attachment_service_pb";
77
import { formatFileSize, getFileTypeLabel } from "@/utils/format";
88
import SectionHeader from "../SectionHeader";
9-
import AudioAttachmentItem from "./AudioAttachmentItem";
109

1110
interface AttachmentListEditorProps {
1211
attachments: Attachment[];
@@ -23,38 +22,11 @@ const AttachmentItemCard: FC<{
2322
canMoveUp?: boolean;
2423
canMoveDown?: boolean;
2524
}> = ({ item, onRemove, onMoveUp, onMoveDown, canMoveUp = true, canMoveDown = true }) => {
26-
const { category, filename, thumbnailUrl, mimeType, size, sourceUrl } = item;
25+
const { category, filename, thumbnailUrl, mimeType, size } = item;
2726
const fileTypeLabel = getFileTypeLabel(mimeType);
2827
const fileSizeLabel = size ? formatFileSize(size) : undefined;
2928
const displayName = category === "audio" && /^voice-(recording|note)-/i.test(filename) ? "Voice note" : filename;
3029

31-
if (category === "audio") {
32-
return (
33-
<div className="rounded border border-transparent transition-all hover:border-border hover:bg-accent/20">
34-
<AudioAttachmentItem
35-
filename={filename}
36-
displayName={displayName}
37-
sourceUrl={sourceUrl}
38-
mimeType={mimeType}
39-
size={size}
40-
actionSlot={
41-
onRemove ? (
42-
<button
43-
type="button"
44-
onClick={onRemove}
45-
className="inline-flex size-6.5 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive"
46-
title="Remove"
47-
aria-label="Remove attachment"
48-
>
49-
<XIcon className="h-3 w-3" />
50-
</button>
51-
) : undefined
52-
}
53-
/>
54-
</div>
55-
);
56-
}
57-
5830
return (
5931
<div className="relative rounded border border-transparent px-1.5 py-1 transition-all hover:border-border hover:bg-accent/20">
6032
<div className="flex items-center gap-1.5">

web/src/components/MemoMetadata/Attachment/AttachmentListView.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,13 @@ const VisualSection = ({ attachments, onImageClick }: { attachments: Attachment[
147147
const AudioList = ({ attachments }: { attachments: Attachment[] }) => (
148148
<div className="flex flex-col gap-2">
149149
{attachments.map((attachment) => (
150-
<AudioAttachmentItem key={attachment.name} attachment={attachment} />
150+
<AudioAttachmentItem
151+
key={attachment.name}
152+
filename={attachment.filename}
153+
sourceUrl={getAttachmentUrl(attachment)}
154+
mimeType={attachment.type}
155+
size={Number(attachment.size)}
156+
/>
151157
))}
152158
</div>
153159
);

web/src/components/MemoMetadata/Attachment/AudioAttachmentItem.tsx

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import { FileAudioIcon, PauseIcon, PlayIcon } from "lucide-react";
2-
import { type ReactNode, useEffect, useRef, useState } from "react";
3-
import type { Attachment } from "@/types/proto/api/v1/attachment_service_pb";
4-
import { getAttachmentUrl } from "@/utils/attachment";
2+
import { useEffect, useRef, useState } from "react";
53
import { formatFileSize, getFileTypeLabel } from "@/utils/format";
6-
import { formatAudioTime, getAttachmentMetadata } from "./attachmentViewHelpers";
4+
import { formatAudioTime } from "./attachmentViewHelpers";
75

86
const AUDIO_PLAYBACK_RATES = [1, 1.5, 2] as const;
97

@@ -47,30 +45,22 @@ const AudioProgressBar = ({ filename, currentTime, duration, progressPercent, on
4745
);
4846

4947
interface AudioAttachmentItemProps {
50-
attachment?: Attachment;
51-
filename?: string;
52-
displayName?: string;
53-
sourceUrl?: string;
54-
mimeType?: string;
48+
filename: string;
49+
sourceUrl: string;
50+
mimeType: string;
5551
size?: number;
56-
actionSlot?: ReactNode;
52+
title?: string;
5753
}
5854

59-
const AudioAttachmentItem = ({ attachment, filename, displayName, sourceUrl, mimeType, size, actionSlot }: AudioAttachmentItemProps) => {
60-
const resolvedFilename = attachment?.filename ?? filename ?? "audio";
61-
const resolvedDisplayName = displayName ?? resolvedFilename;
62-
const resolvedSourceUrl = attachment ? getAttachmentUrl(attachment) : (sourceUrl ?? "");
55+
const AudioAttachmentItem = ({ filename, sourceUrl, mimeType, size, title }: AudioAttachmentItemProps) => {
6356
const audioRef = useRef<HTMLAudioElement>(null);
6457
const [isPlaying, setIsPlaying] = useState(false);
6558
const [currentTime, setCurrentTime] = useState(0);
6659
const [duration, setDuration] = useState(0);
6760
const [playbackRate, setPlaybackRate] = useState<(typeof AUDIO_PLAYBACK_RATES)[number]>(1);
68-
const { fileTypeLabel, fileSizeLabel } = attachment
69-
? getAttachmentMetadata(attachment)
70-
: {
71-
fileTypeLabel: getFileTypeLabel(mimeType ?? ""),
72-
fileSizeLabel: size ? formatFileSize(size) : undefined,
73-
};
61+
const displayTitle = title ?? filename;
62+
const fileTypeLabel = getFileTypeLabel(mimeType);
63+
const fileSizeLabel = size ? formatFileSize(size) : undefined;
7464
const progressPercent = duration > 0 ? (currentTime / duration) * 100 : 0;
7565

7666
useEffect(() => {
@@ -131,8 +121,8 @@ const AudioAttachmentItem = ({ attachment, filename, displayName, sourceUrl, mim
131121

132122
<div className="flex min-w-0 flex-1 items-start justify-between gap-3">
133123
<div className="min-w-0 flex-1">
134-
<div className="truncate text-sm font-medium leading-5 text-foreground" title={resolvedFilename}>
135-
{resolvedDisplayName}
124+
<div className="truncate text-sm font-medium leading-5 text-foreground" title={filename}>
125+
{displayTitle}
136126
</div>
137127
<div className="flex flex-wrap items-center gap-x-1.5 gap-y-0.5 text-xs leading-4 text-muted-foreground">
138128
<span>{fileTypeLabel}</span>
@@ -146,20 +136,19 @@ const AudioAttachmentItem = ({ attachment, filename, displayName, sourceUrl, mim
146136
</div>
147137

148138
<div className="mt-0.5 flex shrink-0 items-center gap-1">
149-
{actionSlot}
150139
<button
151140
type="button"
152141
onClick={handlePlaybackRateChange}
153142
className="inline-flex h-6 items-center justify-center px-1 text-[11px] font-medium text-muted-foreground transition-colors hover:text-foreground"
154-
aria-label={`Playback speed ${playbackRate}x for ${resolvedDisplayName}`}
143+
aria-label={`Playback speed ${playbackRate}x for ${displayTitle}`}
155144
>
156145
{playbackRate}x
157146
</button>
158147
<button
159148
type="button"
160149
onClick={togglePlayback}
161150
className="inline-flex size-6.5 items-center justify-center rounded-md border border-border/45 bg-background/85 text-foreground transition-colors hover:bg-muted/45"
162-
aria-label={isPlaying ? `Pause ${resolvedDisplayName}` : `Play ${resolvedDisplayName}`}
151+
aria-label={isPlaying ? `Pause ${displayTitle}` : `Play ${displayTitle}`}
163152
>
164153
{isPlaying ? <PauseIcon className="size-3" /> : <PlayIcon className="size-3 translate-x-[0.5px]" />}
165154
</button>
@@ -168,7 +157,7 @@ const AudioAttachmentItem = ({ attachment, filename, displayName, sourceUrl, mim
168157
</div>
169158

170159
<AudioProgressBar
171-
filename={resolvedFilename}
160+
filename={filename}
172161
currentTime={currentTime}
173162
duration={duration}
174163
progressPercent={progressPercent}
@@ -177,7 +166,7 @@ const AudioAttachmentItem = ({ attachment, filename, displayName, sourceUrl, mim
177166

178167
<audio
179168
ref={audioRef}
180-
src={resolvedSourceUrl}
169+
src={sourceUrl}
181170
preload="metadata"
182171
className="hidden"
183172
onLoadedMetadata={(e) => handleDuration(e.currentTarget.duration)}

0 commit comments

Comments
 (0)