Refine file download behavior
This commit is contained in:
parent
0dc627b774
commit
d3c8db474e
@ -4,7 +4,11 @@ import { ComponentProps, useMemo } from 'react';
|
||||
import { pathForAdminPhotoEdit, pathForPhoto } from '@/site/paths';
|
||||
import { deletePhotoAction, toggleFavoritePhotoAction } from '@/photo/actions';
|
||||
import { FaRegEdit, FaRegStar, FaStar } from 'react-icons/fa';
|
||||
import { Photo, deleteConfirmationTextForPhoto } from '@/photo';
|
||||
import {
|
||||
Photo,
|
||||
deleteConfirmationTextForPhoto,
|
||||
downloadFileNameForPhoto,
|
||||
} from '@/photo';
|
||||
import { isPathFavs, isPhotoFav } from '@/tag';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { BiTrash } from 'react-icons/bi';
|
||||
@ -64,7 +68,7 @@ export default function AdminPhotoMenuClient({
|
||||
className="translate-x-[-1.5px] translate-y-[-0.5px]"
|
||||
/>,
|
||||
href: photo.url,
|
||||
hrefDownloadName: photo.url.split('/').pop(),
|
||||
hrefDownloadName: downloadFileNameForPhoto(photo),
|
||||
});
|
||||
items.push({
|
||||
label: 'Delete',
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { MdOutlineFileDownload } from 'react-icons/md';
|
||||
import PathLoaderButton from './primitives/PathLoaderButton';
|
||||
import { clsx } from 'clsx/lite';
|
||||
import { Photo } from '@/photo';
|
||||
import { downloadFileNameForPhoto, Photo } from '@/photo';
|
||||
import LoaderButton from './primitives/LoaderButton';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function DownloadButton({
|
||||
photo,
|
||||
@ -12,30 +13,30 @@ export default function DownloadButton({
|
||||
dim?: boolean
|
||||
className?: string
|
||||
}) {
|
||||
const {url, title} = photo;
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
return (
|
||||
<PathLoaderButton
|
||||
path={url}
|
||||
<LoaderButton
|
||||
title="Download Original File"
|
||||
className={clsx(
|
||||
className,
|
||||
dim ? 'text-dim' : 'text-medium',
|
||||
'-mx-0.5 translate-x-0.5',
|
||||
'sm:mx-0 sm:translate-x-0'
|
||||
)}
|
||||
icon={<MdOutlineFileDownload size={16} />}
|
||||
icon={<MdOutlineFileDownload size={18} />}
|
||||
spinnerColor='dim'
|
||||
styleAs='link'
|
||||
shouldReplace
|
||||
handleAction={async () => {
|
||||
const response = await fetch(url);
|
||||
const blob = await response.blob();
|
||||
isLoading={isLoading}
|
||||
onClick={async () => {
|
||||
setIsLoading(true);
|
||||
const blob = await fetch(photo.url)
|
||||
.then(response => response.blob())
|
||||
.finally(() => setIsLoading(false));
|
||||
const downloadUrl = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = downloadUrl;
|
||||
link.download = title
|
||||
? title.replace(/[^a-z0-9]/gi, '_').toLowerCase()
|
||||
: url.split('/').pop() || 'download';
|
||||
link.download = downloadFileNameForPhoto(photo);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
@ -10,7 +10,6 @@ export default function PathLoaderButton({
|
||||
loaderDelay = 100,
|
||||
shouldScroll = true,
|
||||
shouldReplace,
|
||||
handleAction,
|
||||
children,
|
||||
...props
|
||||
}: {
|
||||
@ -19,7 +18,6 @@ export default function PathLoaderButton({
|
||||
loaderDelay?: number
|
||||
shouldScroll?: boolean
|
||||
shouldReplace?: boolean
|
||||
handleAction?: () => Promise<void>
|
||||
} & ComponentProps<typeof LoaderButton>) {
|
||||
const router = useRouter();
|
||||
|
||||
@ -48,15 +46,11 @@ export default function PathLoaderButton({
|
||||
<LoaderButton
|
||||
{...props}
|
||||
onClick={() => {
|
||||
startTransition(async () => {
|
||||
if (handleAction) {
|
||||
await handleAction();
|
||||
startTransition(() => {
|
||||
if (shouldReplace) {
|
||||
router.replace(path, { scroll: shouldScroll });
|
||||
} else {
|
||||
if (shouldReplace) {
|
||||
router.replace(path, { scroll: shouldScroll });
|
||||
} else {
|
||||
router.push(path, { scroll: shouldScroll });
|
||||
}
|
||||
router.push(path, { scroll: shouldScroll });
|
||||
}
|
||||
});
|
||||
}}
|
||||
|
||||
@ -12,6 +12,7 @@ import {
|
||||
formatExposureCompensation,
|
||||
formatExposureTime,
|
||||
} from '@/utility/exif';
|
||||
import { parameterize } from '@/utility/string';
|
||||
import camelcaseKeys from 'camelcase-keys';
|
||||
import { isBefore } from 'date-fns';
|
||||
import type { Metadata } from 'next';
|
||||
@ -311,5 +312,10 @@ export const isNextImageReadyBasedOnPhotos = async (photos: Photo[]) =>
|
||||
.then(response => response.ok)
|
||||
.catch(() => false);
|
||||
|
||||
export const downloadFileNameForPhoto = (photo: Photo) =>
|
||||
photo.title
|
||||
? `${parameterize(photo.title)}.${photo.extension}`
|
||||
: photo.url.split('/').pop() || 'download';
|
||||
|
||||
export const doesPhotoNeedBlurCompatibility = (photo: Photo) =>
|
||||
isBefore(photo.updatedAt, new Date('2024-05-07'));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user