frontend for pinned resources

This commit is contained in:
2025-08-28 11:28:59 +08:00
parent 1925cf404e
commit b17fa45d79
9 changed files with 137 additions and 12 deletions

View File

@@ -2,10 +2,11 @@ import { useEffect, useState } from "react";
import ResourcesView from "../components/resources_view.tsx";
import { network } from "../network/network.ts";
import { app } from "../app.ts";
import { RSort } from "../network/models.ts";
import { Resource, RSort } from "../network/models.ts";
import { useTranslation } from "../utils/i18n";
import { useAppContext } from "../components/AppContext.tsx";
import Select from "../components/select.tsx";
import { useNavigate } from "react-router";
export default function HomePage() {
useEffect(() => {
@@ -31,6 +32,7 @@ export default function HomePage() {
return (
<>
<PinnedResources />
<div className={"flex pt-4 px-4 items-center"}>
<Select
values={[
@@ -58,3 +60,76 @@ export default function HomePage() {
</>
);
}
let cachedPinnedResources: Resource[] | null = null;
function PinnedResources() {
const [pinnedResources, setPinnedResources] = useState<Resource[]>([]);
useEffect(() => {
if (cachedPinnedResources != null) {
setPinnedResources(cachedPinnedResources);
return;
}
const prefetchData = app.getPreFetchData();
if (prefetchData && prefetchData.pinned) {
cachedPinnedResources = prefetchData.pinned;
setPinnedResources(cachedPinnedResources!);
return;
}
const fetchPinnedResources = async () => {
const res = await network.getPinnedResources();
if (res.success) {
cachedPinnedResources = res.data ?? [];
setPinnedResources(res.data ?? []);
}
};
fetchPinnedResources();
}, []);
if (pinnedResources.length == 0) {
return <></>;
}
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 p-4">
{pinnedResources.map((resource) => (
<PinnedResourceItem key={resource.id} resource={resource} />
))}
</div>
);
}
function PinnedResourceItem({ resource }: { resource: Resource }) {
const navigate = useNavigate();
return (
<a
href={`/resources/${resource.id}`}
className={"p-2 cursor-pointer block"}
onClick={(e) => {
e.preventDefault();
navigate(`/resources/${resource.id}`);
}}
>
<div
className={
"card shadow hover:shadow-md transition-shadow bg-base-100-tr82"
}
>
{resource.image != null && (
<figure>
<img
src={network.getResampledImageUrl(resource.image.id)}
alt="cover"
className="w-full aspect-[5/2] object-cover"
/>
</figure>
)}
<div className="p-4">
<h2 className="card-title break-all">{resource.title}</h2>
</div>
</div>
</a>
);
}