fix: route home view-all links
This commit is contained in:
@@ -5,6 +5,8 @@ import {
|
||||
useState,
|
||||
type PointerEvent as ReactPointerEvent,
|
||||
} from "react";
|
||||
import { assetUrl, getJSON, itemsOrEmpty } from "../api";
|
||||
import { langQuery, useI18n, type Lang } from "../i18n";
|
||||
|
||||
const FIGMA_ASSET_BASE = "/assets/ark-library/figma";
|
||||
|
||||
@@ -17,42 +19,46 @@ type BannerSlide = {
|
||||
mobile: string;
|
||||
desktop: string;
|
||||
alt: string;
|
||||
linkUrl?: string;
|
||||
};
|
||||
|
||||
const BANNERS_BASE = "/assets/ark-library/banners";
|
||||
type BannerApiItem = {
|
||||
id: number | string;
|
||||
imageUrl: string;
|
||||
linkUrl?: string;
|
||||
sortOrder?: number;
|
||||
};
|
||||
|
||||
const BANNER_SLIDES: BannerSlide[] = [
|
||||
{
|
||||
id: "ark-banner-1",
|
||||
mobile: `${BANNERS_BASE}/banner-1.png`,
|
||||
desktop: `${BANNERS_BASE}/banner-1.png`,
|
||||
alt: "",
|
||||
},
|
||||
{
|
||||
id: "ark-banner-2",
|
||||
mobile: `${BANNERS_BASE}/banner-2.png`,
|
||||
desktop: `${BANNERS_BASE}/banner-2.png`,
|
||||
alt: "",
|
||||
},
|
||||
{
|
||||
id: "ark-banner-3",
|
||||
mobile: `${BANNERS_BASE}/banner-3.png`,
|
||||
desktop: `${BANNERS_BASE}/banner-3.png`,
|
||||
alt: "",
|
||||
},
|
||||
{
|
||||
id: "ark-banner-4",
|
||||
mobile: `${BANNERS_BASE}/banner-4.png`,
|
||||
desktop: `${BANNERS_BASE}/banner-4.png`,
|
||||
alt: "",
|
||||
},
|
||||
];
|
||||
type BannerApiResponse = {
|
||||
items?: BannerApiItem[] | null;
|
||||
};
|
||||
|
||||
const AUTOPLAY_MS = 3000;
|
||||
const RESUME_AFTER_INTERACTION_MS = 8000;
|
||||
|
||||
function bannerLangParam(lang: Lang): string {
|
||||
return langQuery(lang).toLowerCase();
|
||||
}
|
||||
|
||||
function toSlides(items: BannerApiItem[]): BannerSlide[] {
|
||||
return [...items]
|
||||
.sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0))
|
||||
.filter((item) => item.imageUrl)
|
||||
.map((item) => {
|
||||
const imageUrl = assetUrl(item.imageUrl);
|
||||
return {
|
||||
id: String(item.id),
|
||||
mobile: imageUrl,
|
||||
desktop: imageUrl,
|
||||
alt: "",
|
||||
linkUrl: item.linkUrl || undefined,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function FigmaBanner() {
|
||||
const slides = BANNER_SLIDES;
|
||||
const { lang } = useI18n();
|
||||
const [slides, setSlides] = useState<BannerSlide[]>([]);
|
||||
const scrollerRef = useRef<HTMLDivElement>(null);
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
const [autoplayPaused, setAutoplayPaused] = useState(false);
|
||||
@@ -65,6 +71,22 @@ export function FigmaBanner() {
|
||||
} | null>(null);
|
||||
const hasMultiple = slides.length > 1;
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
setActiveIndex(0);
|
||||
getJSON<BannerApiResponse>(`/api/banners?lang=${bannerLangParam(lang)}`)
|
||||
.then((res) => {
|
||||
if (cancelled) return;
|
||||
setSlides(toSlides(itemsOrEmpty(res.items)));
|
||||
})
|
||||
.catch(() => {
|
||||
if (!cancelled) setSlides([]);
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [lang]);
|
||||
|
||||
const goTo = useCallback((index: number, behavior: ScrollBehavior) => {
|
||||
const scroller = scrollerRef.current;
|
||||
if (!scroller) return;
|
||||
@@ -168,6 +190,8 @@ export function FigmaBanner() {
|
||||
}
|
||||
};
|
||||
|
||||
if (slides.length === 0) return null;
|
||||
|
||||
const pagination = hasMultiple ? (
|
||||
<div
|
||||
className="flex items-center justify-center gap-1.5 md:gap-2"
|
||||
@@ -213,14 +237,8 @@ export function FigmaBanner() {
|
||||
aria-roledescription="carousel"
|
||||
aria-label="ARK Library banner"
|
||||
>
|
||||
{slides.map((slide, index) => (
|
||||
<div
|
||||
key={slide.id}
|
||||
className="relative w-full shrink-0 snap-start"
|
||||
role="group"
|
||||
aria-roledescription="slide"
|
||||
aria-label={`${index + 1} / ${slides.length}`}
|
||||
>
|
||||
{slides.map((slide, index) => {
|
||||
const image = (
|
||||
<picture className="block w-full overflow-hidden bg-black md:rounded-xl">
|
||||
<source media="(max-width: 767px)" srcSet={slide.mobile} />
|
||||
<img
|
||||
@@ -234,8 +252,26 @@ export function FigmaBanner() {
|
||||
draggable={false}
|
||||
/>
|
||||
</picture>
|
||||
</div>
|
||||
))}
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={slide.id}
|
||||
className="relative w-full shrink-0 snap-start"
|
||||
role="group"
|
||||
aria-roledescription="slide"
|
||||
aria-label={`${index + 1} / ${slides.length}`}
|
||||
>
|
||||
{slide.linkUrl ? (
|
||||
<a href={slide.linkUrl} className="block" rel="noreferrer">
|
||||
{image}
|
||||
</a>
|
||||
) : (
|
||||
image
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{hasMultiple ? (
|
||||
|
||||
@@ -19,11 +19,10 @@ export function MessageStream({ scope }: MessageStreamProps) {
|
||||
const type = sp.get("type") || "all";
|
||||
const q = (sp.get("q") || "").trim();
|
||||
const sort = sp.get("sort") || "";
|
||||
const tag = sp.get("tag") || "";
|
||||
|
||||
const params = useMemo(
|
||||
() => ({ scope, type, q, sort, tag, lang }),
|
||||
[scope, type, q, sort, tag, lang],
|
||||
() => ({ scope, type, q, sort, lang }),
|
||||
[scope, type, q, sort, lang],
|
||||
);
|
||||
|
||||
const { items, isLoading, error, hasMore, loadMore, reset } =
|
||||
|
||||
@@ -16,7 +16,6 @@ export type PostStreamParams = {
|
||||
language?: string;
|
||||
q?: string;
|
||||
sort?: string;
|
||||
tag?: string;
|
||||
lang: Lang;
|
||||
};
|
||||
|
||||
@@ -61,9 +60,6 @@ function filterMock(params: PostStreamParams): Post[] {
|
||||
return false;
|
||||
const q = params.q?.trim().toLowerCase();
|
||||
if (params.language && p.language !== params.language) return false;
|
||||
const tag = params.tag?.trim().toLowerCase();
|
||||
if (tag && !(p.tags ?? []).some((t) => t.toLowerCase() === tag))
|
||||
return false;
|
||||
if (q) {
|
||||
const haystack = [
|
||||
p.text ?? "",
|
||||
@@ -93,7 +89,6 @@ function buildRealUrl(params: PostStreamParams, cursor?: string): string {
|
||||
if (params.scope.kind === "category") sp.set("category", params.scope.slug);
|
||||
if (params.type && params.type !== "all") sp.set("type", params.type);
|
||||
if (params.sort) sp.set("sort", params.sort);
|
||||
if (params.tag) sp.set("tag", params.tag);
|
||||
if (params.language) sp.set("language", sourceLanguageQuery(params.language));
|
||||
if (cursor) sp.set("cursor", cursor);
|
||||
return `${q ? "/api/posts/search" : "/api/posts"}?${sp.toString()}`;
|
||||
@@ -171,7 +166,6 @@ export function usePostStream(params: PostStreamParams): PostStreamResult {
|
||||
params.language,
|
||||
params.q,
|
||||
params.sort,
|
||||
params.tag,
|
||||
params.lang,
|
||||
]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user