feat: support mobile video previews
This commit is contained in:
@@ -11,7 +11,13 @@ import { DocumentMeta } from "../components/DocumentMeta";
|
||||
import { SearchPanel } from "../components/SearchPanel";
|
||||
import { useI18n, type Lang } from "../i18n";
|
||||
import { LANG_OPTIONS } from "../i18nLanguages";
|
||||
import { homePathForLang, isHomePathname } from "../languageRoutes";
|
||||
import {
|
||||
homePathForLang,
|
||||
isHomePathname,
|
||||
languageFromPathname,
|
||||
stripLangPrefix,
|
||||
} from "../languageRoutes";
|
||||
import { useLocalizedPath } from "../useLocalizedPath";
|
||||
|
||||
type PublicNavWhich =
|
||||
| "home"
|
||||
@@ -29,25 +35,26 @@ function navIsActive(
|
||||
which: PublicNavWhich,
|
||||
): boolean {
|
||||
const sp = new URLSearchParams(search);
|
||||
const stripped = stripLangPrefix(pathname);
|
||||
switch (which) {
|
||||
case "home":
|
||||
return isHomePathname(pathname);
|
||||
case "browseAll":
|
||||
return pathname === "/browse" && !sp.has("sort");
|
||||
return stripped === "/browse" && !sp.has("sort");
|
||||
case "categories":
|
||||
return (
|
||||
pathname === "/categories" ||
|
||||
stripped === "/categories" ||
|
||||
(isHomePathname(pathname) && hash === "#categories")
|
||||
);
|
||||
case "browseLatest":
|
||||
return pathname === "/browse" && sp.get("sort") === "latest";
|
||||
return stripped === "/browse" && sp.get("sort") === "latest";
|
||||
case "browseRecommended":
|
||||
return pathname === "/official-recommendations";
|
||||
return stripped === "/official-recommendations";
|
||||
case "browsePopular":
|
||||
return pathname === "/browse" && sp.get("sort") === "popular";
|
||||
return stripped === "/browse" && sp.get("sort") === "popular";
|
||||
case "favorites":
|
||||
return (
|
||||
pathname === "/favorites" ||
|
||||
stripped === "/favorites" ||
|
||||
(isHomePathname(pathname) && hash === "#favorites")
|
||||
);
|
||||
default:
|
||||
@@ -295,6 +302,15 @@ export function PublicLayout() {
|
||||
const desktopSearchRef = useRef<HTMLDivElement>(null);
|
||||
const desktopSearchPanelRef = useRef<HTMLDivElement>(null);
|
||||
const nav = useNavigate();
|
||||
const lp = useLocalizedPath();
|
||||
|
||||
// Keep i18n state in sync with URL so deep links (`/malay/browse`) flip the
|
||||
// UI language even if the user navigated via address bar or shared link.
|
||||
useEffect(() => {
|
||||
const urlLang = languageFromPathname(pathname);
|
||||
if (urlLang !== lang) setLang(urlLang);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [pathname]);
|
||||
|
||||
const na = (which: PublicNavWhich) =>
|
||||
navIsActive(pathname, search, hash, which);
|
||||
@@ -304,7 +320,7 @@ export function PublicLayout() {
|
||||
setLang(nextLang);
|
||||
if (isHome) nav(homePathForLang(nextLang), { replace: true });
|
||||
};
|
||||
const footerInContentFlow = pathname === "/browse";
|
||||
const footerInContentFlow = stripLangPrefix(pathname) === "/browse";
|
||||
// Current page name shown in the header brand slot (falls back to the brand).
|
||||
const pageTitle = usePageTitle();
|
||||
|
||||
@@ -344,12 +360,12 @@ export function PublicLayout() {
|
||||
if (idleId) ric.cancelIdleCallback?.(idleId);
|
||||
};
|
||||
}, [lang]);
|
||||
const popularHref = "/browse?sort=popular";
|
||||
const popularHref = lp("/browse?sort=popular");
|
||||
|
||||
const goSearch = () => {
|
||||
const s = q.trim();
|
||||
if (!s) return;
|
||||
nav(`/browse?q=${encodeURIComponent(s)}`);
|
||||
nav(lp(`/browse?q=${encodeURIComponent(s)}`));
|
||||
setOpen(false);
|
||||
setMobileSearchOpen(false);
|
||||
setDesktopSearchOpen(false);
|
||||
@@ -574,35 +590,35 @@ export function PublicLayout() {
|
||||
aria-label={t("mainNav")}
|
||||
>
|
||||
<Link
|
||||
to="/browse"
|
||||
to={lp("/browse")}
|
||||
className={navClassName(na("browseAll"))}
|
||||
aria-current={na("browseAll") ? "page" : undefined}
|
||||
>
|
||||
{t("all")}
|
||||
</Link>
|
||||
<Link
|
||||
to="/categories"
|
||||
to={lp("/categories")}
|
||||
className={navClassName(na("categories"))}
|
||||
aria-current={na("categories") ? "page" : undefined}
|
||||
>
|
||||
{t("categories")}
|
||||
</Link>
|
||||
<Link
|
||||
to="/official-recommendations"
|
||||
to={lp("/official-recommendations")}
|
||||
className={navClassName(na("browseRecommended"))}
|
||||
aria-current={na("browseRecommended") ? "page" : undefined}
|
||||
>
|
||||
{t("official")}
|
||||
</Link>
|
||||
<Link
|
||||
to="/browse?sort=latest"
|
||||
to={lp("/browse?sort=latest")}
|
||||
className={navClassName(na("browseLatest"))}
|
||||
aria-current={na("browseLatest") ? "page" : undefined}
|
||||
>
|
||||
{t("latest")}
|
||||
</Link>
|
||||
<Link
|
||||
to="/favorites"
|
||||
to={lp("/favorites")}
|
||||
className={navClassName(na("favorites"))}
|
||||
aria-current={na("favorites") ? "page" : undefined}
|
||||
>
|
||||
@@ -661,7 +677,7 @@ export function PublicLayout() {
|
||||
className={`${headerMenuAnimationClass} fixed inset-x-0 top-[64px] z-50 grid gap-2 bg-[#08070c] px-4 py-3 shadow-2xl shadow-black/50 min-[440px]:px-5 sm:px-6 md:top-[70px] md:px-9 min-[1000px]:hidden`}
|
||||
>
|
||||
<Link
|
||||
to="/browse"
|
||||
to={lp("/browse")}
|
||||
className={mobileMenuNavClassName(na("browseAll"))}
|
||||
aria-current={na("browseAll") ? "page" : undefined}
|
||||
onClick={() => setOpen(false)}
|
||||
@@ -669,7 +685,7 @@ export function PublicLayout() {
|
||||
{t("all")}
|
||||
</Link>
|
||||
<Link
|
||||
to="/categories"
|
||||
to={lp("/categories")}
|
||||
className={mobileMenuNavClassName(na("categories"))}
|
||||
aria-current={na("categories") ? "page" : undefined}
|
||||
onClick={() => setOpen(false)}
|
||||
@@ -677,7 +693,7 @@ export function PublicLayout() {
|
||||
{t("categories")}
|
||||
</Link>
|
||||
<Link
|
||||
to="/official-recommendations"
|
||||
to={lp("/official-recommendations")}
|
||||
className={mobileMenuNavClassName(na("browseRecommended"))}
|
||||
aria-current={na("browseRecommended") ? "page" : undefined}
|
||||
onClick={() => setOpen(false)}
|
||||
@@ -685,7 +701,7 @@ export function PublicLayout() {
|
||||
{t("official")}
|
||||
</Link>
|
||||
<Link
|
||||
to="/browse?sort=latest"
|
||||
to={lp("/browse?sort=latest")}
|
||||
className={mobileMenuNavClassName(na("browseLatest"))}
|
||||
aria-current={na("browseLatest") ? "page" : undefined}
|
||||
onClick={() => setOpen(false)}
|
||||
@@ -693,7 +709,7 @@ export function PublicLayout() {
|
||||
{t("latest")}
|
||||
</Link>
|
||||
<Link
|
||||
to="/favorites"
|
||||
to={lp("/favorites")}
|
||||
className={mobileMenuNavClassName(na("favorites"))}
|
||||
aria-current={na("favorites") ? "page" : undefined}
|
||||
onClick={() => setOpen(false)}
|
||||
@@ -767,15 +783,16 @@ export function PublicLayout() {
|
||||
active={isHome}
|
||||
/>
|
||||
<BottomNavIcon
|
||||
to="/browse"
|
||||
to={lp("/browse")}
|
||||
label={t("all")}
|
||||
icon="document"
|
||||
active={
|
||||
pathname === "/browse" && !new URLSearchParams(search).get("sort")
|
||||
stripLangPrefix(pathname) === "/browse" &&
|
||||
!new URLSearchParams(search).get("sort")
|
||||
}
|
||||
/>
|
||||
<BottomNavIcon
|
||||
to="/favorites"
|
||||
to={lp("/favorites")}
|
||||
label={t("favorites")}
|
||||
icon="bookmark"
|
||||
active={na("favorites")}
|
||||
@@ -789,7 +806,7 @@ export function PublicLayout() {
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{pathname === "/browse" ? <BackToTop /> : null}
|
||||
{stripLangPrefix(pathname) === "/browse" ? <BackToTop /> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user