Update home page

This commit is contained in:
2025-10-02 22:25:37 +08:00
parent 3a99d03427
commit 97ee74899c
4 changed files with 90 additions and 11 deletions

View File

@@ -205,3 +205,9 @@ export interface Collection {
images: Image[];
isPublic: boolean;
}
export interface Statistics {
total_resources: number;
total_files: number;
start_time: number;
}

View File

@@ -20,6 +20,7 @@ import {
Activity,
CommentWithRef,
Collection,
Statistics,
} from "./models.ts";
class Network {
@@ -795,6 +796,12 @@ class Network {
}),
);
}
async getStatistic(): Promise<Response<Statistics>> {
return this._callApi(() =>
axios.get(`${this.apiBaseUrl}/config/statistics`),
);
}
}
export const network = new Network();

View File

@@ -2,12 +2,17 @@ import { useEffect, useState } from "react";
import ResourcesView from "../components/resources_view.tsx";
import { network } from "../network/network.ts";
import { app } from "../app.ts";
import { Resource, RSort } from "../network/models.ts";
import { Resource, RSort, Statistics } 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";
import { useNavigator } from "../components/navigator.tsx";
import {
MdOutlineAccessTime,
MdOutlineArchive,
MdOutlineClass,
} from "react-icons/md";
export default function HomePage() {
useEffect(() => {
@@ -33,7 +38,7 @@ export default function HomePage() {
return (
<>
<PinnedResources />
<HomeHeader />
<div className={"flex pt-4 px-4 items-center"}>
<Select
values={[
@@ -64,8 +69,9 @@ export default function HomePage() {
let cachedPinnedResources: Resource[] | null = null;
function PinnedResources() {
function HomeHeader() {
const [pinnedResources, setPinnedResources] = useState<Resource[]>([]);
const [statistic, setStatistic] = useState<Statistics | null>(null);
const navigator = useNavigator();
useEffect(() => {
@@ -79,9 +85,18 @@ function PinnedResources() {
network.getResampledImageUrl(prefetchData.background),
);
}
let ok1 = false;
let ok2 = false;
if (prefetchData && prefetchData.statistics) {
setStatistic(prefetchData.statistics);
ok1 = true;
}
if (prefetchData && prefetchData.pinned) {
cachedPinnedResources = prefetchData.pinned;
setPinnedResources(cachedPinnedResources!);
ok2 = true;
}
if (ok1 && ok2) {
return;
}
const fetchPinnedResources = async () => {
@@ -91,18 +106,30 @@ function PinnedResources() {
setPinnedResources(res.data ?? []);
}
};
const fetchStatistics = async () => {
const res = await network.getStatistic();
if (res.success) {
setStatistic(res.data!);
}
};
fetchPinnedResources();
}, []);
fetchStatistics();
}, [navigator]);
if (pinnedResources.length == 0) {
if (pinnedResources.length == 0 || statistic == null) {
return <></>;
}
return (
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 p-4">
{pinnedResources.map((resource) => (
<PinnedResourceItem key={resource.id} resource={resource} />
))}
<div className="grid grid-cols-1 md:grid-cols-2 p-4 gap-4">
<PinnedResourceItem resource={pinnedResources[0]} />
<div className={"hidden md:block"}>
<div className={"card w-full shadow p-4 mb-4 bg-base-100-tr82 h-28"}>
<h2 className={"text-lg font-bold pb-2"}>{app.appName}</h2>
<p className={"text-xs"}>{app.siteInfo}</p>
</div>
<StatisticCard statistic={statistic} />
</div>
</div>
);
}
@@ -129,7 +156,7 @@ function PinnedResourceItem({ resource }: { resource: Resource }) {
<img
src={network.getResampledImageUrl(resource.image.id)}
alt="cover"
className="w-full aspect-[7/3] object-cover"
className="w-full h-52 lg:h-60 object-cover"
/>
</figure>
)}
@@ -140,3 +167,40 @@ function PinnedResourceItem({ resource }: { resource: Resource }) {
</a>
);
}
function StatisticCard({ statistic }: { statistic: Statistics }) {
const { t } = useTranslation();
const now = new Date();
const createdAt = new Date(statistic.start_time * 1000);
const diffTime = Math.abs(now.getTime() - createdAt.getTime());
const survivalTime = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
return (
<div className="stats shadow w-full bg-base-100-tr82">
<div className="stat">
<div className="stat-figure text-secondary pt-2">
<MdOutlineClass size={28} />
</div>
<div className="stat-title">{t("Resources")}</div>
<div className="stat-value">{statistic.total_resources}</div>
</div>
<div className="stat">
<div className="stat-figure text-secondary pt-2">
<MdOutlineArchive size={28} />
</div>
<div className="stat-title">{t("Files")}</div>
<div className="stat-value">{statistic.total_files}</div>
</div>
<div className="stat">
<div className="stat-figure text-accent pt-2">
<MdOutlineAccessTime size={28} />
</div>
<div className="stat-title">{t("Survival time")}</div>
<div className="stat-value">{survivalTime}</div>
</div>
</div>
);
}

View File

@@ -158,10 +158,12 @@ func serveIndexHtml(c fiber.Ctx) error {
} else if path == "/" || path == "" {
pinned, err := service.GetPinnedResources()
random, err1 := service.RandomCover()
if err == nil && err1 == nil {
statistic, err2 := service.GetStatistic()
if err == nil && err1 == nil && err2 == nil {
preFetchDataJson, _ := json.Marshal(map[string]interface{}{
"pinned": pinned,
"background": random,
"statistic": statistic,
})
preFetchData = url.PathEscape(string(preFetchDataJson))
}