feat: media & music file name
This commit is contained in:
@@ -18,7 +18,7 @@ import {
|
|||||||
Badge,
|
Badge,
|
||||||
} from "@/components/ui";
|
} from "@/components/ui";
|
||||||
import { EditIcon, PlusIcon, TrashIcon } from "@/components/icons";
|
import { EditIcon, PlusIcon, TrashIcon } from "@/components/icons";
|
||||||
import { formatMinutes } from "@/lib/utils";
|
import { formatMinutes, fileNameToTitle } from "@/lib/utils";
|
||||||
import { MediaPreview } from "@/components/MediaPreview";
|
import { MediaPreview } from "@/components/MediaPreview";
|
||||||
import { ImagePicker } from "@/components/ImagePicker";
|
import { ImagePicker } from "@/components/ImagePicker";
|
||||||
import { pickUrl, SOUND_KEYS, VIDEO_KEYS, IMAGE_KEYS } from "@/lib/media";
|
import { pickUrl, SOUND_KEYS, VIDEO_KEYS, IMAGE_KEYS } from "@/lib/media";
|
||||||
@@ -397,7 +397,12 @@ export default function MediaPage() {
|
|||||||
<Input
|
<Input
|
||||||
type="file"
|
type="file"
|
||||||
accept="audio/*,video/*"
|
accept="audio/*,video/*"
|
||||||
onChange={(e) => setFile(e.target.files?.[0] ?? null)}
|
onChange={(e) => {
|
||||||
|
const f = e.target.files?.[0] ?? null;
|
||||||
|
setFile(f);
|
||||||
|
// Fill the title from the file name if still empty.
|
||||||
|
if (f && !title.trim()) setTitle(fileNameToTitle(f.name));
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
PageHeader,
|
PageHeader,
|
||||||
} from "@/components/ui";
|
} from "@/components/ui";
|
||||||
import { EditIcon, PlusIcon, TrashIcon } from "@/components/icons";
|
import { EditIcon, PlusIcon, TrashIcon } from "@/components/icons";
|
||||||
import { formatMinutes } from "@/lib/utils";
|
import { formatMinutes, fileNameToTitle } from "@/lib/utils";
|
||||||
import { MediaPreview } from "@/components/MediaPreview";
|
import { MediaPreview } from "@/components/MediaPreview";
|
||||||
import { ImagePicker } from "@/components/ImagePicker";
|
import { ImagePicker } from "@/components/ImagePicker";
|
||||||
import { pickUrl, SOUND_KEYS, IMAGE_KEYS } from "@/lib/media";
|
import { pickUrl, SOUND_KEYS, IMAGE_KEYS } from "@/lib/media";
|
||||||
@@ -301,7 +301,12 @@ export default function MusicTracksPage() {
|
|||||||
<Input
|
<Input
|
||||||
type="file"
|
type="file"
|
||||||
accept="audio/*"
|
accept="audio/*"
|
||||||
onChange={(e) => setFile(e.target.files?.[0] ?? null)}
|
onChange={(e) => {
|
||||||
|
const f = e.target.files?.[0] ?? null;
|
||||||
|
setFile(f);
|
||||||
|
// Fill the title from the file name if still empty.
|
||||||
|
if (f && !title.trim()) setTitle(fileNameToTitle(f.name));
|
||||||
|
}}
|
||||||
required={!editing}
|
required={!editing}
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|||||||
@@ -19,6 +19,16 @@ export function formatDuration(seconds?: number | null): string {
|
|||||||
return toFa(`${m}:${String(s).padStart(2, "0")}`);
|
return toFa(`${m}:${String(s).padStart(2, "0")}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Derive a clean title from an uploaded file name: drop the extension and turn
|
||||||
|
// underscores/dashes into spaces (e.g. "morning_calm-01.mp3" -> "morning calm 01").
|
||||||
|
export function fileNameToTitle(name: string): string {
|
||||||
|
return name
|
||||||
|
.replace(/\.[^./\\]+$/, "")
|
||||||
|
.replace(/[_-]+/g, " ")
|
||||||
|
.replace(/\s+/g, " ")
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
// Minutes -> Persian label. Media and music store `duration` in minutes.
|
// Minutes -> Persian label. Media and music store `duration` in minutes.
|
||||||
export function formatMinutes(minutes?: number | null): string {
|
export function formatMinutes(minutes?: number | null): string {
|
||||||
if (minutes === null || minutes === undefined) return "—";
|
if (minutes === null || minutes === undefined) return "—";
|
||||||
|
|||||||
Reference in New Issue
Block a user