refactor: project configuration
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
import { FC, ReactEventHandler, useState } from "react";
|
||||
|
||||
interface Props {
|
||||
url: string;
|
||||
}
|
||||
|
||||
const Audio: FC<Props> = ({ url }) => {
|
||||
const [err, setErr] = useState(false);
|
||||
|
||||
const handleError: ReactEventHandler<HTMLAudioElement> = (err) => {
|
||||
console.error("audio err", err);
|
||||
setErr(true);
|
||||
};
|
||||
|
||||
if (!url) return null;
|
||||
return (
|
||||
<div className="flex-center h-full">
|
||||
{err ? (
|
||||
<div className="p-[18px] text-gray-500">Unable to play this audio</div>
|
||||
) : (
|
||||
<audio className="w-full" controls src={url} onError={handleError} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Audio;
|
||||
@@ -0,0 +1,23 @@
|
||||
import { useState, useEffect, FC } from "react";
|
||||
|
||||
interface Props {
|
||||
url: string;
|
||||
}
|
||||
|
||||
const Code: FC<Props> = ({ url }) => {
|
||||
const [content, setContent] = useState("");
|
||||
useEffect(() => {
|
||||
const getContent = async (url: string) => {
|
||||
if (!url) return;
|
||||
const resp = await fetch(url);
|
||||
const txt = await resp.text();
|
||||
setContent(txt);
|
||||
};
|
||||
getContent(url);
|
||||
}, [url]);
|
||||
if (!content) return null;
|
||||
|
||||
return <div className="h-[218px] p-[15px] pb-0 bg-black text-white overflow-scroll whitespace-pre-wrap break-all leading-snug">{content}</div>;
|
||||
};
|
||||
|
||||
export default Code;
|
||||
@@ -0,0 +1,23 @@
|
||||
import { useState, useEffect, FC } from "react";
|
||||
|
||||
interface Props {
|
||||
url: string;
|
||||
}
|
||||
|
||||
const Doc: FC<Props> = ({ url }) => {
|
||||
const [content, setContent] = useState("");
|
||||
useEffect(() => {
|
||||
const getContent = async (url: string) => {
|
||||
if (!url) return;
|
||||
const resp = await fetch(url);
|
||||
const txt = await resp.text();
|
||||
setContent(txt);
|
||||
};
|
||||
getContent(url);
|
||||
}, [url]);
|
||||
if (!content) return null;
|
||||
|
||||
return <div className="bg-white h-[218px] p-[15px] pb-0 whitespace-pre-wrap break-all">{content}</div>;
|
||||
};
|
||||
|
||||
export default Doc;
|
||||
@@ -0,0 +1,61 @@
|
||||
import { FC, useEffect, useState } from "react";
|
||||
import clsx from "clsx";
|
||||
import { FetchBaseQueryError } from "@reduxjs/toolkit/dist/query";
|
||||
import { LineWobble } from "@uiball/loaders";
|
||||
|
||||
import { useLazyPreCheckFileFromUrlQuery } from "@/app/services/message";
|
||||
interface Props {
|
||||
url: string;
|
||||
alt?: string;
|
||||
}
|
||||
|
||||
const ImageBox: FC<Props> = ({ url, alt }) => {
|
||||
const [loadFile, { error, isSuccess }] = useLazyPreCheckFileFromUrlQuery();
|
||||
const [status, setStatus] = useState<"loading" | "loaded" | "error" | number>("loading");
|
||||
|
||||
useEffect(() => {
|
||||
if (url) {
|
||||
loadFile(url);
|
||||
}
|
||||
}, [url]);
|
||||
useEffect(() => {
|
||||
// 预检成功
|
||||
if (isSuccess && url) {
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
setStatus("loaded");
|
||||
};
|
||||
img.onerror = () => {
|
||||
setStatus("error");
|
||||
};
|
||||
img.src = url;
|
||||
}
|
||||
// 预检失败
|
||||
if (error) {
|
||||
const errNum = (error as FetchBaseQueryError).status;
|
||||
console.log("error num", errNum);
|
||||
switch (errNum) {
|
||||
case 404:
|
||||
setStatus(404);
|
||||
break;
|
||||
|
||||
default:
|
||||
// setStatus("error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, [isSuccess, error, url]);
|
||||
|
||||
|
||||
return (
|
||||
<div className={clsx("h-[218px] overflow-hidden flex-center", status == "error" && "bg-red-100 dark:bg-red-200/60")}>
|
||||
{status == "loaded" ? <img className="w-full h-full object-cover" src={url} alt={alt} /> : (
|
||||
status == "loading" ? <span><LineWobble color="rgb(21,91,117)" /></span> :
|
||||
|
||||
status == 404 ? <span className="text-lg text-orange-500">File not found, removed maybe</span> : <span className="text-lg text-red-800">Load image error</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ImageBox;
|
||||
@@ -0,0 +1,15 @@
|
||||
import { FC } from "react";
|
||||
|
||||
interface Props {
|
||||
url: string;
|
||||
}
|
||||
|
||||
const Pdf: FC<Props> = ({ url }) => {
|
||||
return (
|
||||
<div className="p-2 overflow-hidden">
|
||||
<embed className="w-full h-full" src={url} type="application/pdf" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Pdf;
|
||||
@@ -0,0 +1,14 @@
|
||||
import React, { FC } from "react";
|
||||
interface Props {
|
||||
url: string;
|
||||
}
|
||||
|
||||
const Video: FC<Props> = ({ url }) => {
|
||||
return (
|
||||
<div className="h-[218px]">
|
||||
<video className="w-full h-full object-cover" controls src={url} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Video;
|
||||
@@ -0,0 +1,8 @@
|
||||
import VideoPreview from "./Video";
|
||||
import AudioPreview from "./Audio";
|
||||
import ImagePreview from "./Image";
|
||||
import PdfPreview from "./Pdf";
|
||||
import CodePreview from "./Code";
|
||||
import DocPreview from "./Doc";
|
||||
|
||||
export { VideoPreview, AudioPreview, ImagePreview, PdfPreview, CodePreview, DocPreview };
|
||||
Reference in New Issue
Block a user