feat(web): refresh audio card UI and enforce outside-click menu close
All checks were successful
CI / test (push) Successful in 24s

This commit is contained in:
2026-03-08 12:55:55 +03:00
parent 82322c4d42
commit 58208787e7
2 changed files with 117 additions and 83 deletions

View File

@@ -511,11 +511,12 @@ export function MessageList() {
{ctx
? createPortal(
<div
className="fixed z-[110] w-56 rounded-xl border border-slate-700/90 bg-slate-900/95 p-1.5 shadow-2xl"
style={{ left: ctx.x, top: ctx.y }}
onClick={(event) => event.stopPropagation()}
>
<div className="fixed inset-0 z-[109]" onClick={() => setCtx(null)}>
<div
className="fixed z-[110] w-56 rounded-xl border border-slate-700/90 bg-slate-900/95 p-1.5 shadow-2xl"
style={{ left: ctx.x, top: ctx.y }}
onClick={(event) => event.stopPropagation()}
>
<div className="mb-1 flex flex-wrap gap-1 rounded-lg bg-slate-800/80 p-1">
{QUICK_REACTIONS.map((emoji) => (
<button
@@ -623,6 +624,7 @@ export function MessageList() {
</button>
</>
) : null}
</div>
</div>,
document.body
)
@@ -854,10 +856,10 @@ function renderMessageContent(
opts.onAttachmentContextMenu(event, text);
}}>
<div className="mb-1 flex items-center gap-2 text-xs text-slate-300">
<span className="inline-flex h-7 w-7 items-center justify-center rounded-full bg-slate-700/80">🎵</span>
<span className="inline-flex h-8 w-8 items-center justify-center rounded-full bg-emerald-500/25 text-emerald-200">🎵</span>
<div className="min-w-0">
<p className="truncate font-semibold text-slate-200">{extractFileName(text)}</p>
<p className="text-[11px] text-slate-400">Audio file</p>
<p className="truncate font-semibold text-slate-100">{extractFileName(text)}</p>
<p className="text-[11px] text-slate-400">Audio</p>
</div>
</div>
<AudioInlinePlayer src={text} title={extractFileName(text)} />
@@ -994,28 +996,34 @@ function AudioInlinePlayer({ src, title }: { src: string; title: string }) {
}
return (
<div className="rounded-lg border border-sky-500/40 bg-sky-600/20 px-2 py-1.5">
<div className="rounded-lg border border-slate-600/70 bg-slate-900/60 px-2 py-2">
<div className="flex items-center gap-2">
<button
className="inline-flex h-7 w-7 items-center justify-center rounded-full bg-slate-900/70 text-xs text-white hover:bg-slate-900"
className="inline-flex h-8 w-8 items-center justify-center rounded-full bg-emerald-500/80 text-xs text-slate-950 hover:bg-emerald-400"
onClick={() => void togglePlay()}
type="button"
>
{isPlaying ? "❚❚" : "▶"}
</button>
<input
className="h-1.5 w-24 cursor-pointer accent-sky-300"
max={Math.max(duration, 0.01)}
min={0}
onChange={(event) => onSeek(Number(event.target.value))}
step={0.1}
type="range"
value={Math.min(position, Math.max(duration, 0.01))}
/>
<div className="min-w-0 flex-1">
<div className="mb-1 flex items-center justify-between gap-2 text-[11px] text-slate-300">
<span className="truncate">{title}</span>
<span className="tabular-nums">{formatAudioTime(position)} / {formatAudioTime(duration)}</span>
</div>
<input
className="h-1.5 w-full cursor-pointer accent-emerald-300"
max={Math.max(duration, 0.01)}
min={0}
onChange={(event) => onSeek(Number(event.target.value))}
step={0.1}
type="range"
value={Math.min(position, Math.max(duration, 0.01))}
/>
</div>
<span className="w-20 text-center text-xs tabular-nums text-slate-100">
{formatAudioTime(position)} / {formatAudioTime(duration)}
<span className="inline-flex h-6 min-w-6 items-center justify-center rounded-full bg-slate-800 px-1 text-[10px] text-slate-300">
</span>
</div>
</div>