feat: separate popular browse navigation

This commit is contained in:
TerryM
2026-05-28 16:28:50 +08:00
parent fea6e1c93b
commit 6a998c0186
3 changed files with 49 additions and 13 deletions

View File

@@ -15,6 +15,7 @@ export type PostStreamParams = {
type?: string; type?: string;
language?: string; language?: string;
q?: string; q?: string;
sort?: string;
lang: Lang; lang: Lang;
}; };
@@ -87,6 +88,7 @@ function buildRealUrl(params: PostStreamParams, cursor?: string): string {
if (q) sp.set("q", q); if (q) sp.set("q", q);
if (params.scope.kind === "category") sp.set("category", params.scope.slug); if (params.scope.kind === "category") sp.set("category", params.scope.slug);
if (params.type && params.type !== "all") sp.set("type", params.type); if (params.type && params.type !== "all") sp.set("type", params.type);
if (params.sort) sp.set("sort", params.sort);
if (params.language) sp.set("language", sourceLanguageQuery(params.language)); if (params.language) sp.set("language", sourceLanguageQuery(params.language));
if (cursor) sp.set("cursor", cursor); if (cursor) sp.set("cursor", cursor);
return `${q ? "/api/posts/search" : "/api/posts"}?${sp.toString()}`; return `${q ? "/api/posts/search" : "/api/posts"}?${sp.toString()}`;
@@ -163,6 +165,7 @@ export function usePostStream(params: PostStreamParams): PostStreamResult {
params.type, params.type,
params.language, params.language,
params.q, params.q,
params.sort,
params.lang, params.lang,
]); ]);

View File

@@ -12,6 +12,7 @@ type PublicNavWhich =
| "browseLatest" | "browseLatest"
| "browseRecommended" | "browseRecommended"
| "browsePopular" | "browsePopular"
| "favorites"
| "about"; | "about";
function navIsActive( function navIsActive(
@@ -32,11 +33,15 @@ function navIsActive(
(pathname === "/" && hash === "#categories") (pathname === "/" && hash === "#categories")
); );
case "browseLatest": case "browseLatest":
return pathname === "/" && hash === "#latest"; return pathname === "/browse" && sp.get("sort") === "latest";
case "browseRecommended": case "browseRecommended":
return pathname === "/" && hash === "#official"; return pathname === "/official-recommendations";
case "browsePopular": case "browsePopular":
return pathname === "/" && hash === "#popular"; return pathname === "/browse" && sp.get("sort") === "popular";
case "favorites":
return (
pathname === "/favorites" || (pathname === "/" && hash === "#favorites")
);
case "about": case "about":
return pathname === "/about"; return pathname === "/about";
default: default:
@@ -397,26 +402,33 @@ export function PublicLayout() {
{t("categories")} {t("categories")}
</Link> </Link>
<Link <Link
to="/#official" to="/official-recommendations"
className={navClassName(na("browseRecommended"))} className={navClassName(na("browseRecommended"))}
aria-current={na("browseRecommended") ? "page" : undefined} aria-current={na("browseRecommended") ? "page" : undefined}
> >
{t("official")} {t("official")}
</Link> </Link>
<Link <Link
to="/#latest" to="/browse?sort=latest"
className={navClassName(na("browseLatest"))} className={navClassName(na("browseLatest"))}
aria-current={na("browseLatest") ? "page" : undefined} aria-current={na("browseLatest") ? "page" : undefined}
> >
{t("latest")} {t("latest")}
</Link> </Link>
<Link <Link
to="/#popular" to="/browse?sort=popular"
className={navClassName(na("browsePopular"))} className={navClassName(na("browsePopular"))}
aria-current={na("browsePopular") ? "page" : undefined} aria-current={na("browsePopular") ? "page" : undefined}
> >
{t("popular")} {t("popular")}
</Link> </Link>
<Link
to="/favorites"
className={navClassName(na("favorites"))}
aria-current={na("favorites") ? "page" : undefined}
>
{t("favorites")}
</Link>
<Link <Link
to="/about" to="/about"
className={navClassName(na("about"))} className={navClassName(na("about"))}
@@ -490,7 +502,7 @@ export function PublicLayout() {
{t("categories")} {t("categories")}
</Link> </Link>
<Link <Link
to="/#official" to="/official-recommendations"
className={navClassName(na("browseRecommended"))} className={navClassName(na("browseRecommended"))}
aria-current={na("browseRecommended") ? "page" : undefined} aria-current={na("browseRecommended") ? "page" : undefined}
onClick={() => setOpen(false)} onClick={() => setOpen(false)}
@@ -498,7 +510,7 @@ export function PublicLayout() {
{t("official")} {t("official")}
</Link> </Link>
<Link <Link
to="/#latest" to="/browse?sort=latest"
className={navClassName(na("browseLatest"))} className={navClassName(na("browseLatest"))}
aria-current={na("browseLatest") ? "page" : undefined} aria-current={na("browseLatest") ? "page" : undefined}
onClick={() => setOpen(false)} onClick={() => setOpen(false)}
@@ -506,13 +518,21 @@ export function PublicLayout() {
{t("latest")} {t("latest")}
</Link> </Link>
<Link <Link
to="/#popular" to="/browse?sort=popular"
className={navClassName(na("browsePopular"))} className={navClassName(na("browsePopular"))}
aria-current={na("browsePopular") ? "page" : undefined} aria-current={na("browsePopular") ? "page" : undefined}
onClick={() => setOpen(false)} onClick={() => setOpen(false)}
> >
{t("popular")} {t("popular")}
</Link> </Link>
<Link
to="/favorites"
className={navClassName(na("favorites"))}
aria-current={na("favorites") ? "page" : undefined}
onClick={() => setOpen(false)}
>
{t("favorites")}
</Link>
<Link <Link
to="/about" to="/about"
className={navClassName(na("about"))} className={navClassName(na("about"))}
@@ -570,13 +590,16 @@ export function PublicLayout() {
to="/favorites" to="/favorites"
label={t("favorites")} label={t("favorites")}
icon="bookmark" icon="bookmark"
active={pathname === "/favorites"} active={na("favorites")}
/> />
<BottomNavIcon <BottomNavIcon
to="/#popular" to="/browse?sort=popular"
label={t("popular")} label={t("popular")}
icon="update" icon="update"
active={pathname === "/" && hash === "#popular"} active={
pathname === "/browse" &&
new URLSearchParams(search).get("sort") === "popular"
}
/> />
</div> </div>
</nav> </nav>

View File

@@ -7,10 +7,20 @@ export function Browse() {
const { t } = useI18n(); const { t } = useI18n();
const [sp] = useSearchParams(); const [sp] = useSearchParams();
const q = sp.get("q") || ""; const q = sp.get("q") || "";
const sort = sp.get("sort") || "";
const title = q
? `${t("search")}: ${q}`
: sort === "latest"
? t("latest")
: sort === "popular"
? t("popular")
: sort === "recommended"
? t("official")
: t("all");
return ( return (
<section> <section>
<div className="mx-auto max-w-full px-4 md:max-w-[820px] lg:max-w-[1080px] xl:max-w-[1180px]"> <div className="mx-auto max-w-full px-4 md:max-w-[820px] lg:max-w-[1080px] xl:max-w-[1180px]">
<SectionHeader title={q ? `${t("search")}: ${q}` : t("all")} /> <SectionHeader title={title} />
</div> </div>
<MessageStream scope={{ kind: "all" }} /> <MessageStream scope={{ kind: "all" }} />
</section> </section>