mirror of
https://github.com/wgh136/nysoure.git
synced 2025-12-16 15:51:14 +00:00
Update home page
This commit is contained in:
@@ -205,3 +205,9 @@ export interface Collection {
|
|||||||
images: Image[];
|
images: Image[];
|
||||||
isPublic: boolean;
|
isPublic: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Statistics {
|
||||||
|
total_resources: number;
|
||||||
|
total_files: number;
|
||||||
|
start_time: number;
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
Activity,
|
Activity,
|
||||||
CommentWithRef,
|
CommentWithRef,
|
||||||
Collection,
|
Collection,
|
||||||
|
Statistics,
|
||||||
} from "./models.ts";
|
} from "./models.ts";
|
||||||
|
|
||||||
class Network {
|
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();
|
export const network = new Network();
|
||||||
|
|||||||
@@ -2,12 +2,17 @@ import { useEffect, useState } from "react";
|
|||||||
import ResourcesView from "../components/resources_view.tsx";
|
import ResourcesView from "../components/resources_view.tsx";
|
||||||
import { network } from "../network/network.ts";
|
import { network } from "../network/network.ts";
|
||||||
import { app } from "../app.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 { useTranslation } from "../utils/i18n";
|
||||||
import { useAppContext } from "../components/AppContext.tsx";
|
import { useAppContext } from "../components/AppContext.tsx";
|
||||||
import Select from "../components/select.tsx";
|
import Select from "../components/select.tsx";
|
||||||
import { useNavigate } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
import { useNavigator } from "../components/navigator.tsx";
|
import { useNavigator } from "../components/navigator.tsx";
|
||||||
|
import {
|
||||||
|
MdOutlineAccessTime,
|
||||||
|
MdOutlineArchive,
|
||||||
|
MdOutlineClass,
|
||||||
|
} from "react-icons/md";
|
||||||
|
|
||||||
export default function HomePage() {
|
export default function HomePage() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -33,7 +38,7 @@ export default function HomePage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PinnedResources />
|
<HomeHeader />
|
||||||
<div className={"flex pt-4 px-4 items-center"}>
|
<div className={"flex pt-4 px-4 items-center"}>
|
||||||
<Select
|
<Select
|
||||||
values={[
|
values={[
|
||||||
@@ -64,8 +69,9 @@ export default function HomePage() {
|
|||||||
|
|
||||||
let cachedPinnedResources: Resource[] | null = null;
|
let cachedPinnedResources: Resource[] | null = null;
|
||||||
|
|
||||||
function PinnedResources() {
|
function HomeHeader() {
|
||||||
const [pinnedResources, setPinnedResources] = useState<Resource[]>([]);
|
const [pinnedResources, setPinnedResources] = useState<Resource[]>([]);
|
||||||
|
const [statistic, setStatistic] = useState<Statistics | null>(null);
|
||||||
const navigator = useNavigator();
|
const navigator = useNavigator();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -79,9 +85,18 @@ function PinnedResources() {
|
|||||||
network.getResampledImageUrl(prefetchData.background),
|
network.getResampledImageUrl(prefetchData.background),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
let ok1 = false;
|
||||||
|
let ok2 = false;
|
||||||
|
if (prefetchData && prefetchData.statistics) {
|
||||||
|
setStatistic(prefetchData.statistics);
|
||||||
|
ok1 = true;
|
||||||
|
}
|
||||||
if (prefetchData && prefetchData.pinned) {
|
if (prefetchData && prefetchData.pinned) {
|
||||||
cachedPinnedResources = prefetchData.pinned;
|
cachedPinnedResources = prefetchData.pinned;
|
||||||
setPinnedResources(cachedPinnedResources!);
|
setPinnedResources(cachedPinnedResources!);
|
||||||
|
ok2 = true;
|
||||||
|
}
|
||||||
|
if (ok1 && ok2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const fetchPinnedResources = async () => {
|
const fetchPinnedResources = async () => {
|
||||||
@@ -91,18 +106,30 @@ function PinnedResources() {
|
|||||||
setPinnedResources(res.data ?? []);
|
setPinnedResources(res.data ?? []);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const fetchStatistics = async () => {
|
||||||
|
const res = await network.getStatistic();
|
||||||
|
if (res.success) {
|
||||||
|
setStatistic(res.data!);
|
||||||
|
}
|
||||||
|
};
|
||||||
fetchPinnedResources();
|
fetchPinnedResources();
|
||||||
}, []);
|
fetchStatistics();
|
||||||
|
}, [navigator]);
|
||||||
|
|
||||||
if (pinnedResources.length == 0) {
|
if (pinnedResources.length == 0 || statistic == null) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 p-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 p-4 gap-4">
|
||||||
{pinnedResources.map((resource) => (
|
<PinnedResourceItem resource={pinnedResources[0]} />
|
||||||
<PinnedResourceItem key={resource.id} resource={resource} />
|
<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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -129,7 +156,7 @@ function PinnedResourceItem({ resource }: { resource: Resource }) {
|
|||||||
<img
|
<img
|
||||||
src={network.getResampledImageUrl(resource.image.id)}
|
src={network.getResampledImageUrl(resource.image.id)}
|
||||||
alt="cover"
|
alt="cover"
|
||||||
className="w-full aspect-[7/3] object-cover"
|
className="w-full h-52 lg:h-60 object-cover"
|
||||||
/>
|
/>
|
||||||
</figure>
|
</figure>
|
||||||
)}
|
)}
|
||||||
@@ -140,3 +167,40 @@ function PinnedResourceItem({ resource }: { resource: Resource }) {
|
|||||||
</a>
|
</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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -158,10 +158,12 @@ func serveIndexHtml(c fiber.Ctx) error {
|
|||||||
} else if path == "/" || path == "" {
|
} else if path == "/" || path == "" {
|
||||||
pinned, err := service.GetPinnedResources()
|
pinned, err := service.GetPinnedResources()
|
||||||
random, err1 := service.RandomCover()
|
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{}{
|
preFetchDataJson, _ := json.Marshal(map[string]interface{}{
|
||||||
"pinned": pinned,
|
"pinned": pinned,
|
||||||
"background": random,
|
"background": random,
|
||||||
|
"statistic": statistic,
|
||||||
})
|
})
|
||||||
preFetchData = url.PathEscape(string(preFetchDataJson))
|
preFetchData = url.PathEscape(string(preFetchDataJson))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user