mirror of
https://github.com/Nezumi-2711/next-gdrive-index.git
synced 2026-09-22 20:01:36 +00:00
Fix list view copy and download, and Make SWRLayout not inside a card on file preview
This commit is contained in:
@@ -1,76 +1,24 @@
|
||||
import { drive_v3 } from "googleapis";
|
||||
import Link from "next/link";
|
||||
import { formatBytes, formatDate } from "utils/formatHelper";
|
||||
import { toast } from "react-toastify";
|
||||
import { MdContentCopy, MdDownload } from "react-icons/md";
|
||||
import { getFileIcon } from "utils/mimeTypesHelper";
|
||||
import { BsFolderFill } from "react-icons/bs";
|
||||
import siteConfig from "config/site.config";
|
||||
import { createFileId } from "utils/driveHelper";
|
||||
import useCopyText from "hooks/useCopyText";
|
||||
|
||||
type Props = {
|
||||
data: drive_v3.Schema$File;
|
||||
};
|
||||
|
||||
function CopyButton({ url, isFolder }: { url: string; isFolder: boolean }) {
|
||||
return (
|
||||
<button
|
||||
className={"p-2"}
|
||||
title={isFolder ? "Copy folder link" : "Copy raw file link"}
|
||||
onClick={async (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
if (!navigator.clipboard) {
|
||||
toast.error("Your browser doesn't support clipboard API");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const host = window.location.host;
|
||||
const copyUrl = isFolder ? host + url : host + url + "/view";
|
||||
await navigator.clipboard.writeText(copyUrl);
|
||||
toast.success(
|
||||
isFolder ? "Folder link copied" : "Raw file link copied",
|
||||
);
|
||||
} catch (error: any) {
|
||||
toast.error("Failed to copy to clipboard");
|
||||
console.error(error.message);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<MdContentCopy />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
function DownloadButton({
|
||||
fileId,
|
||||
fileName,
|
||||
}: {
|
||||
fileId: string;
|
||||
fileName: string;
|
||||
}) {
|
||||
return (
|
||||
<button
|
||||
className={"p-2"}
|
||||
onClick={async (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
window.open(`/download/${fileId}/${fileName}`, "_self");
|
||||
toast.info("Downloading file...");
|
||||
}}
|
||||
>
|
||||
<MdDownload />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default function ListFile({ data }: Props) {
|
||||
const isFolder = data.mimeType === "application/vnd.google-apps.folder";
|
||||
const Icon = isFolder
|
||||
? BsFolderFill
|
||||
: getFileIcon(data.fileExtension as string, data.mimeType as string);
|
||||
const copyText = useCopyText();
|
||||
|
||||
if (!data) return null;
|
||||
|
||||
return (
|
||||
@@ -122,19 +70,39 @@ export default function ListFile({ data }: Props) {
|
||||
{isFolder ? "" : formatBytes(data.size as string)}
|
||||
</div>
|
||||
<div className={"hidden gap-2 tablet:flex"}>
|
||||
<CopyButton
|
||||
url={
|
||||
isFolder
|
||||
? `/folder/${createFileId(data, true)}`
|
||||
: `/file/${createFileId(data, true)}`
|
||||
}
|
||||
isFolder={isFolder}
|
||||
/>
|
||||
{isFolder ? null : (
|
||||
<DownloadButton
|
||||
fileId={data.id as string}
|
||||
fileName={data.name as string}
|
||||
/>
|
||||
<button
|
||||
className={"p-2"}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
copyText(
|
||||
isFolder
|
||||
? `${process.env.NEXT_PUBLIC_DOMAIN}/folder/${createFileId(
|
||||
data,
|
||||
true,
|
||||
)}`
|
||||
: `${process.env.NEXT_PUBLIC_DOMAIN}/file/${createFileId(
|
||||
data,
|
||||
true,
|
||||
)}`,
|
||||
);
|
||||
}}
|
||||
>
|
||||
<MdContentCopy />
|
||||
</button>
|
||||
{!isFolder && (
|
||||
<Link
|
||||
href={`/api/files/${createFileId(data, true)}?download=1`}
|
||||
target={"_blank"}
|
||||
rel={"noopener noreferrer"}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<button className={"p-2"}>
|
||||
<MdDownload />
|
||||
</button>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
@@ -45,6 +45,7 @@ export default function AudioPreview({ data }: Props) {
|
||||
data={data}
|
||||
error={errorMessage}
|
||||
isLoading={isLoading}
|
||||
useCard={false}
|
||||
>
|
||||
<div className={"preview-audio w-full"}>
|
||||
<H5AudioPlayer
|
||||
|
||||
@@ -37,6 +37,7 @@ export default function CodePreview({ data }: Props) {
|
||||
data={codeContent}
|
||||
error={error}
|
||||
isLoading={isLoading}
|
||||
useCard={false}
|
||||
>
|
||||
<div className={"w-full"}>
|
||||
<MarkdownRender content={codeContent} />
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { TFile } from "types/googleapis";
|
||||
import { drive_v3 } from "googleapis";
|
||||
import { useEffect, useState } from "react";
|
||||
import config from "config/site.config";
|
||||
import { reverseString } from "utils/hashHelper";
|
||||
import SWRLayout from "components/layout/SWRLayout";
|
||||
import { createFileId } from "utils/driveHelper";
|
||||
|
||||
type Props = {
|
||||
data: TFile | drive_v3.Schema$File;
|
||||
data: drive_v3.Schema$File;
|
||||
hash?: string;
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@ export default function ImagePreview({ data, hash }: Props) {
|
||||
setIsLoading(false);
|
||||
}, config.preview.timeout);
|
||||
const image = new Image();
|
||||
image.src = `/media/${data.id}/${data.name}`;
|
||||
image.src = `/api/files/${createFileId(data)}?download=1`;
|
||||
image.onload = () => {
|
||||
setImageSrc(image.src);
|
||||
setIsLoading(false);
|
||||
@@ -36,7 +36,7 @@ export default function ImagePreview({ data, hash }: Props) {
|
||||
return () => {
|
||||
clearTimeout(timeout);
|
||||
};
|
||||
}, [data.id, data.name]);
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<div className='flex w-full items-center justify-center'>
|
||||
@@ -44,6 +44,7 @@ export default function ImagePreview({ data, hash }: Props) {
|
||||
data={data}
|
||||
error={errorMessage}
|
||||
isLoading={isLoading}
|
||||
useCard={false}
|
||||
>
|
||||
<img
|
||||
src={imageSrc}
|
||||
|
||||
@@ -22,6 +22,7 @@ export default function MarkdownPreview({ data }: Props) {
|
||||
data={swrData}
|
||||
error={error}
|
||||
isLoading={isLoading}
|
||||
useCard={false}
|
||||
>
|
||||
<div className={"w-full"}>
|
||||
<MarkdownRender content={swrData as string} />
|
||||
|
||||
@@ -33,6 +33,7 @@ export default function PDFPreview({ data }: Props) {
|
||||
data={data}
|
||||
error={errorMessage}
|
||||
isLoading={isLoading}
|
||||
useCard={false}
|
||||
>
|
||||
<></>
|
||||
</SWRLayout>
|
||||
|
||||
@@ -22,6 +22,7 @@ export default function TextPreview({ data }: Props) {
|
||||
data={swrData}
|
||||
error={error}
|
||||
isLoading={isLoading}
|
||||
useCard={false}
|
||||
>
|
||||
<div className={"w-full"}>
|
||||
<MarkdownRender content={swrData as string} />
|
||||
|
||||
@@ -6,10 +6,17 @@ type Props = {
|
||||
data: unknown;
|
||||
error: unknown;
|
||||
isLoading: boolean;
|
||||
useCard?: boolean;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export default function SWRLayout({ data, error, isLoading, children }: Props) {
|
||||
export default function SWRLayout({
|
||||
data,
|
||||
error,
|
||||
isLoading,
|
||||
useCard = true,
|
||||
children,
|
||||
}: Props) {
|
||||
const [isMounted, setIsMounted] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -21,12 +28,12 @@ export default function SWRLayout({ data, error, isLoading, children }: Props) {
|
||||
return (
|
||||
<>
|
||||
{isLoading && (
|
||||
<div className={"card"}>
|
||||
<div className={useCard ? "card" : ""}>
|
||||
<LoadingFeedback />
|
||||
</div>
|
||||
)}
|
||||
{!isLoading && error && (
|
||||
<div className={"card"}>
|
||||
<div className={useCard ? "card" : ""}>
|
||||
<ErrorFeedback />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -110,7 +110,7 @@ export default function Home({ id, folderName, bannerFileId }: Props) {
|
||||
openGraph={{
|
||||
title: folderName,
|
||||
url: `${process.env.NEXT_PUBLIC_DOMAIN}/folder/${id}`,
|
||||
description: `Exploring ${folderName}}`,
|
||||
description: `Exploring ${folderName}`,
|
||||
images: [
|
||||
{
|
||||
url: bannerFileId
|
||||
|
||||
Reference in New Issue
Block a user