Improve related resource rendering

This commit is contained in:
2025-07-11 10:18:19 +08:00
parent 19d37012d2
commit 8170ab5201

View File

@@ -16,6 +16,7 @@ import {
Storage, Storage,
Comment, Comment,
Tag, Tag,
Resource,
} from "../network/models.ts"; } from "../network/models.ts";
import { network } from "../network/network.ts"; import { network } from "../network/network.ts";
import showToast from "../components/toast.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 }) { function Article({ resource }: { resource: ResourceDetails }) {
const navigate = useNavigate();
return ( return (
<article> <article>
<Markdown <Markdown
@@ -502,25 +501,68 @@ function Article({ resource }: { resource: ResourceDetails }) {
}, },
a: ({ node, ...props }) => { a: ({ node, ...props }) => {
const href = props.href as string; const href = props.href as string;
const origin = window.location.origin;
if ( if (
href.startsWith(window.location.origin) || href.startsWith(origin) ||
href.startsWith("/") href.startsWith("/")
) { ) {
let path = href; let path = href;
if (path.startsWith(window.location.origin)) { if (path.startsWith(origin)) {
path = path.substring(window.location.origin.length); path = path.substring(origin.length);
} }
const content = props.children?.toString(); const content = props.children?.toString();
if (path.startsWith("/resources/")) { if (path.startsWith("/resources/")) {
const id = path.substring("/resources/".length); const id = path.substring("/resources/".length);
for (const r of resource.related ?? []) { for (const r of resource.related ?? []) {
if (r.id.toString() === id) { if (r.id.toString() === id) {
return <RelatedResourceCard r={r} content={content} />;
}
}
}
}
return <a target={"_blank"} {...props}></a>;
},
}}
>
{resource.article.replaceAll("\n", " \n")}
</Markdown>
</article>
);
}
function RelatedResourceCard({ r, content }: { r: Resource, content?: string }) {
const navigate = useNavigate();
const [articleWidth, setArticleWidth] = useState<number | null>(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 = const imgHeight =
r.image && r.image.width > r.image.height ? 320 : 420; r.image && r.image.width > r.image.height ? 320 : 420;
const imgWidth = r.image let imgWidth = r.image
? (r.image.width / r.image.height) * imgHeight ? (r.image.width / r.image.height) * imgHeight
: undefined; : undefined;
if (articleWidth && imgWidth && imgWidth > articleWidth) {
imgWidth = articleWidth;
}
if (!articleWidth) {
return <></>
}
return ( return (
<span className={"inline-flex max-w-full"}> <span className={"inline-flex max-w-full"}>
@@ -539,6 +581,7 @@ function Article({ resource }: { resource: ResourceDetails }) {
style={{ style={{
width: imgWidth, width: imgWidth,
height: imgHeight, height: imgHeight,
objectFit: "cover",
}} }}
className={"h-full min-h-0 object-cover min-w-0"} className={"h-full min-h-0 object-cover min-w-0"}
alt={"cover"} alt={"cover"}
@@ -578,19 +621,6 @@ function Article({ resource }: { resource: ResourceDetails }) {
</a> </a>
</span> </span>
); );
}
}
}
}
return <a target={"_blank"} {...props}></a>;
},
}}
>
{resource.article.replaceAll("\n", " \n")}
</Markdown>
</article>
);
} }
function fileSizeToString(size: number) { function fileSizeToString(size: number) {