Add AboutPage component and integrate sorting options in resource retrieval

This commit is contained in:
2025-05-25 11:27:24 +08:00
parent b610a5db9d
commit 6e78707d9e
11 changed files with 139 additions and 27 deletions

View File

@@ -10,6 +10,7 @@ import ManagePage from "./pages/manage_page.tsx";
import TaggedResourcesPage from "./pages/tagged_resources_page.tsx";
import UserPage from "./pages/user_page.tsx";
import EditResourcePage from "./pages/edit_resource_page.tsx";
import AboutPage from "./pages/about_page.tsx";
export default function App() {
return (
@@ -26,6 +27,7 @@ export default function App() {
<Route path={"/tag/:tag"} element={<TaggedResourcesPage/>}/>
<Route path={"/user/:username"} element={<UserPage/>}/>
<Route path={"/resource/edit/:rid"} element={<EditResourcePage/>}/>
<Route path={"/about"} element={<AboutPage/>}/>
</Route>
</Routes>
</BrowserRouter>

View File

@@ -319,6 +319,15 @@ export const i18nData = {
"Set the description of the tag.": "设置标签的描述。",
"Use markdown format.": "使用Markdown格式。",
"Tag: ": "标签: ",
// 添加排序选项翻译
"Select a Order": "选择排序方式",
"Latest": "最新",
"Oldest": "最早",
"Most Viewed": "浏览最多",
"Least Viewed": "浏览最少",
"Most Downloaded": "下载最多",
"Least Downloaded": "下载最少",
}
},
"zh-TW": {
@@ -480,6 +489,15 @@ export const i18nData = {
"Set the description of the tag.": "設置標籤的描述。",
"Use markdown format.": "使用Markdown格式。",
"Tag: ": "標籤: ",
// 添加排序选项翻译
"Select a Order": "選擇排序方式",
"Latest": "最新",
"Oldest": "最早",
"Most Viewed": "瀏覽最多",
"Least Viewed": "瀏覽最少",
"Most Downloaded": "下載最多",
"Least Downloaded": "下載最少",
}
}
}

View File

@@ -84,6 +84,9 @@ article {
border-radius: 4px;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, system-ui;
}
.line-break {
white-space: pre-wrap;
}
}
a.no-underline {

View File

@@ -126,3 +126,12 @@ export interface ServerConfig {
server_description: string;
site_info: string;
}
export enum RSort {
TimeAsc = 0,
TimeDesc = 1,
ViewsAsc = 2,
ViewsDesc = 3,
DownloadsAsc = 4,
DownloadsDesc = 5,
}

View File

@@ -14,7 +14,7 @@ import {
UserWithToken,
Comment,
CommentWithResource,
ServerConfig
ServerConfig, RSort
} from "./models.ts";
class Network {
@@ -409,11 +409,12 @@ class Network {
}
}
async getResources(page: number): Promise<PageResponse<Resource>> {
async getResources(page: number, sort: RSort): Promise<PageResponse<Resource>> {
try {
const response = await axios.get(`${this.apiBaseUrl}/resource`, {
params: {
page
page,
sort,
}
})
return response.data

View File

@@ -0,0 +1,10 @@
import Markdown from "react-markdown";
import {app} from "../app.ts";
export default function AboutPage() {
return <article className={"p-4"}>
<Markdown>
{app.siteInfo}
</Markdown>
</article>
}

View File

@@ -2,36 +2,63 @@ import {useEffect, useState} from "react";
import ResourcesView from "../components/resources_view.tsx";
import {network} from "../network/network.ts";
import { app } from "../app.ts";
import Markdown from "react-markdown";
import {RSort} from "../network/models.ts";
import Button from "../components/button.tsx";
import {MdInfoOutline} from "react-icons/md";
import {useTranslation} from "react-i18next";
import {useNavigate} from "react-router";
export default function HomePage() {
useEffect(() => {
document.title = app.appName;
}, [])
const [isCollapsed, setIsCollapsed] = useState(false);
const [order, setOrder] = useState(RSort.TimeAsc)
const {t} = useTranslation()
const navigate = useNavigate()
return <>
{
app.siteInfo && <div className={"mt-4 px-4"}>
<div className="collapse collapse-arrow bg-base-100 border border-base-300" onClick={() => setIsCollapsed(!isCollapsed)}>
<input type="radio" name="my-accordion-2" checked={isCollapsed} style={{
"cursor": "pointer",
}}/>
<div className="collapse-title font-semibold cursor-pointer">{t("About this site")}</div>
<article className="collapse-content text-sm cursor-auto" onClick={(e) => {
e.stopPropagation();
}}>
<Markdown>
{app.siteInfo}
</Markdown>
</article>
<div className={"flex p-4 items-center"}>
<select value={order} className="select w-52 select-info" onInput={(e) => {
const value = e.currentTarget.value;
if (value === "0") {
setOrder(RSort.TimeAsc);
} else if (value === "1") {
setOrder(RSort.TimeDesc);
} else if (value === "2") {
setOrder(RSort.ViewsDesc);
} else if (value === "3") {
setOrder(RSort.ViewsAsc);
} else if (value === "4") {
setOrder(RSort.DownloadsDesc);
} else if (value === "5") {
setOrder(RSort.DownloadsAsc);
}
}}>
<option disabled>{t("Select a Order")}</option>
<option value={0}>{t("Latest")}</option>
<option value={1}>{t("Oldest")}</option>
<option value={2}>{t("Most Viewed")}</option>
<option value={3}>{t("Least Viewed")}</option>
<option value={4}>{t("Most Downloaded")}</option>
<option value={5}>{t("Least Downloaded")}</option>
</select>
<span className={"flex-1"}/>
<Button onClick={() => {
navigate("/about");
}}>
<div className={"flex items-center"}>
<MdInfoOutline size={24} className={"inline-block mr-2"}/>
<span>{t("About this site")}</span>
</div>
</div>
}
<ResourcesView storageKey={"home_page"} loader={(page) => network.getResources(page)}></ResourcesView>
</Button>
</div>
<ResourcesView
key={`home_page_${order}`}
storageKey={`home_page_${order}`}
loader={(page) => network.getResources(page, order)}
/>
</>
}