From 8170ab52019676e403e0464e38a38e52bd5ff703 Mon Sep 17 00:00:00 2001 From: nyne Date: Fri, 11 Jul 2025 10:18:19 +0800 Subject: [PATCH] Improve related resource rendering --- frontend/src/pages/resource_details_page.tsx | 166 +++++++++++-------- 1 file changed, 98 insertions(+), 68 deletions(-) diff --git a/frontend/src/pages/resource_details_page.tsx b/frontend/src/pages/resource_details_page.tsx index 35d5d88..bf8f13d 100644 --- a/frontend/src/pages/resource_details_page.tsx +++ b/frontend/src/pages/resource_details_page.tsx @@ -16,6 +16,7 @@ import { Storage, Comment, Tag, + Resource, } from "../network/models.ts"; import { network } from "../network/network.ts"; import showToast from "../components/toast.ts"; @@ -394,11 +395,9 @@ function DeleteResourceDialog({ ); } -const context = createContext<() => void>(() => {}); +const context = createContext<() => void>(() => { }); function Article({ resource }: { resource: ResourceDetails }) { - const navigate = useNavigate(); - return (
{ const href = props.href as string; + const origin = window.location.origin; if ( - href.startsWith(window.location.origin) || + href.startsWith(origin) || href.startsWith("/") ) { let path = href; - if (path.startsWith(window.location.origin)) { - path = path.substring(window.location.origin.length); + if (path.startsWith(origin)) { + path = path.substring(origin.length); } const content = props.children?.toString(); if (path.startsWith("/resources/")) { const id = path.substring("/resources/".length); for (const r of resource.related ?? []) { if (r.id.toString() === id) { - const imgHeight = - r.image && r.image.width > r.image.height ? 320 : 420; - const imgWidth = r.image - ? (r.image.width / r.image.height) * imgHeight - : undefined; - - return ( - - { - e.preventDefault(); - navigate(`/resources/${r.id}`); - }} - > - {r.image && ( - {"cover"} - )} - - - {r.title} - - - - {content} - - - - - ); + return ; } } } @@ -593,6 +532,97 @@ function Article({ resource }: { resource: ResourceDetails }) { ); } +function RelatedResourceCard({ r, content }: { r: Resource, content?: string }) { + const navigate = useNavigate(); + + const [articleWidth, setArticleWidth] = useState(null); + + useEffect(() => { + const observer = new ResizeObserver((entries) => { + for (const entry of entries) { + if (entry.contentRect.width !== articleWidth) { + setArticleWidth(entry.contentRect.width); + } + } + }); + const articleElement = document.querySelector("article"); + if (articleElement) { + observer.observe(articleElement); + } + }, []) + + const imgHeight = + r.image && r.image.width > r.image.height ? 320 : 420; + let imgWidth = r.image + ? (r.image.width / r.image.height) * imgHeight + : undefined; + if (articleWidth && imgWidth && imgWidth > articleWidth) { + imgWidth = articleWidth; + } + + if (!articleWidth) { + return <> + } + + return ( + + { + e.preventDefault(); + navigate(`/resources/${r.id}`); + }} + > + {r.image && ( + {"cover"} + )} + + + {r.title} + + + + {content} + + + + + ); +} + function fileSizeToString(size: number) { if (size < 1024) { return size + "B";