import { siteurl } from "@/lib/utils/siteurl"; import { useLocal } from "@/lib/utils/use-local"; import { ExternalLink } from "lucide-react"; import { ReactElement } from "react"; export const ThumbPreview = ({ url, options, }: { url: string; options: ReactElement; }) => { const local = useLocal({ size: "", is_doc: true }, async () => { }); const file = getFileName(url); if (typeof file === "string") return; const color = darkenColor(generateRandomColor(file.extension)); let content = (
{ // let _url = siteurl(url || ""); // window.open(_url, "_blank"); }} >
{file.extension}
{local.size}
); let is_image = false; if ([".png", ".jpeg", ".jpg", ".webp"].find((e) => url.endsWith(e))) { is_image = true; local.is_doc = false; content = ( { let _url = siteurl(url || ""); window.open(_url, "_blank"); }} className={cx( "rounded-md", css` &:hover { outline: 2px solid #1c4ed8; } `, css` width: 60px; height: 60px; background-image: linear-gradient( 45deg, #ccc 25%, transparent 25% ), linear-gradient(135deg, #ccc 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #ccc 75%), linear-gradient(135deg, transparent 75%, #ccc 75%); background-size: 25px 25px; /* Must be a square */ background-position: 0 0, 12.5px 0, 12.5px -12.5px, 0px 12.5px; /* Must be half of one side of the square */ ` )} src={siteurl( `/_img/${url.substring("_file/".length)}?${"w=60&h=60&fit=cover"}` )} /> ); } return ( <> {file.extension && (
{content} {options}
)} ); }; export const FilePreview = ({ url }: { url: string }) => { const file = getFileName(url); if (typeof file === "string") return (
{file}
); const color = darkenColor(generateRandomColor(file.extension)); let content = (
{file.extension}
); if (url.startsWith("_file/")) { if ([".png", ".jpeg", ".jpg", ".webp"].find((e) => url.endsWith(e))) { content = ( ); } } return ( <> {file.extension && (
{ let _url = siteurl(url || ""); window.open(_url, "_blank"); }} > {content}
)} ); }; function darkenColor(color: string, factor: number = 0.5): string { const rgb = hexToRgb(color); const r = Math.floor(rgb.r * factor); const g = Math.floor(rgb.g * factor); const b = Math.floor(rgb.b * factor); return rgbToHex(r, g, b); } function hexToRgb(hex: string): { r: number; g: number; b: number } { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16), } : { r: 0, g: 0, b: 0 }; } function rgbToHex(r: number, g: number, b: number): string { return `#${r.toString(16).padStart(2, "0")}${g .toString(16) .padStart(2, "0")}${b.toString(16).padStart(2, "0")}`; } function generateRandomColor(str: string): string { let hash = 0; if (str.length === 0) return hash.toString(); // Return a string representation of the hash for (let i = 0; i < str.length; i++) { hash = str.charCodeAt(i) + ((hash << 5) - hash); hash = hash & hash; } let color = "#"; for (let i = 0; i < 3; i++) { const value = (hash >> (i * 8)) & 255; color += ("00" + value.toString(16)).substr(-2); } return color; } const getFileName = (url: string) => { if (url.startsWith("[")) { try { const list = JSON.parse(url); if (list.length === 0) return "Empty"; return `${list.length} File${list.length > 1 ? "s" : ""}`; } catch (e) { console.error(`Error parsing multi-file: ${url}`); } return "Unknown File"; } const fileName = url.substring(url.lastIndexOf("/") + 1); const dotIndex = fileName.lastIndexOf("."); const fullname = fileName; if (dotIndex === -1) { return { name: fileName, extension: "", fullname }; } const name = fileName.substring(0, dotIndex); const extension = fileName.substring(dotIndex + 1); return { name, extension, fullname }; }; export const ImgThumb = ({ className, url, w, h, fit, }: { className?: string; url: string; w: number; h: number; fit?: "cover" | "contain" | "inside" | "fill" | "outside"; }) => { const local = useLocal({ error: false }); return (
{!local.error && url && ( { local.error = true; local.render(); }} src={siteurl( `/_img/${url.substring("_file/".length)}?w=${w}&h=${h}&fit=${ fit || "cover" }` )} /> )}
); };