v3: localization fixes, char counters & limits on all text fields, ux fixes

This commit is contained in:
khannurien
2026-04-03 19:47:37 +00:00
parent 0ce80398a4
commit a69788c15b
48 changed files with 1133 additions and 305 deletions

View File

@@ -33,9 +33,13 @@ function AudioFilePreview(
useEffect(() => {
let cancelled = false;
extractPeaks(fileUrl, NUM_BARS)
.then((p) => { if (!cancelled) setPeaks(p); })
.then((p) => {
if (!cancelled) setPeaks(p);
})
.catch(() => {});
return () => { cancelled = true; };
return () => {
cancelled = true;
};
}, [fileUrl]);
const handlePlayBtn = () => {
@@ -45,7 +49,10 @@ function AudioFilePreview(
const handleWaveformClick = (e: React.MouseEvent<Element>) => {
const rect = e.currentTarget.getBoundingClientRect();
const ratio = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
const ratio = Math.max(
0,
Math.min(1, (e.clientX - rect.left) / rect.width),
);
if (isActive) {
seekTo(ratio * duration);
} else {
@@ -58,7 +65,11 @@ function AudioFilePreview(
const isPlaying = isActive && playing;
return (
<div className={`audio-file-preview${isActive ? " audio-file-preview--active" : ""}`}>
<div
className={`audio-file-preview${
isActive ? " audio-file-preview--active" : ""
}`}
>
<button
type="button"
className="audio-player-btn"
@@ -67,13 +78,21 @@ function AudioFilePreview(
>
{isPlaying
? (
<svg viewBox="0 0 24 24" fill="currentColor" style={{ padding: "1px" }}>
<svg
viewBox="0 0 24 24"
fill="currentColor"
style={{ padding: "1px" }}
>
<rect x="5" y="3" width="4" height="18" rx="1" />
<rect x="15" y="3" width="4" height="18" rx="1" />
</svg>
)
: (
<svg viewBox="0 0 24 24" fill="currentColor" style={{ marginLeft: "2px" }}>
<svg
viewBox="0 0 24 24"
fill="currentColor"
style={{ marginLeft: "2px" }}
>
<polygon points="6,3 20,12 6,21" />
</svg>
)}
@@ -98,7 +117,9 @@ function AudioFilePreview(
y={y}
width={BAR_W}
height={barH}
className={`waveform-bar${played ? " waveform-bar--played" : ""}`}
className={`waveform-bar${
played ? " waveform-bar--played" : ""
}`}
/>
);
})}
@@ -130,7 +151,6 @@ export default function FilePreview(
const { current, playing, play, togglePlay } = useContext(PlayerContext);
const fileUrl = `${API_URL}/api/files/${dump.id}?v=${dump.fileSize ?? 0}`;
const mime = dump.fileMime ?? "";
const isMedia = mime.startsWith("video/") || mime.startsWith("audio/");
const isPlaying = current?.kind === "file" && current.fileUrl === fileUrl;
if (compact) {
@@ -150,7 +170,9 @@ export default function FilePreview(
return (
<button
type="button"
className={`rich-content-thumbnail-btn${isPlaying ? " is-playing" : ""}`}
className={`rich-content-thumbnail-btn${
isPlaying ? " is-playing" : ""
}`}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
@@ -174,14 +196,16 @@ export default function FilePreview(
return (
<button
type="button"
className={`rich-content-compact-icon rich-content-thumbnail-btn${isPlaying ? " is-playing" : ""}`}
className={`rich-content-thumbnail-btn${
isPlaying ? " is-playing" : ""
}`}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
play({ kind: "file", fileUrl, mimeType: mime, title: dump.title });
}}
>
{mimeIcon(mime)}
<span className="rich-content-compact-icon">{mimeIcon(mime)}</span>
</button>
);
}
@@ -202,7 +226,13 @@ export default function FilePreview(
<button
type="button"
className={`file-preview-play-btn${videoActive ? " is-playing" : ""}`}
onClick={() => videoActive ? togglePlay() : play({ kind: "file", fileUrl, mimeType: mime, title: dump.title })}
onClick={() =>
videoActive ? togglePlay() : play({
kind: "file",
fileUrl,
mimeType: mime,
title: dump.title,
})}
>
<video
src={fileUrl}