import { m } from "framer-motion"; import { Link, useNavigate } from "react-router-dom"; import type { Resource } from "../api"; import { assetUrl } from "../api"; import { useI18n } from "../i18n"; import { useLocalizedPath } from "../useLocalizedPath"; import { useMemo } from "react"; import { formatDateYmd } from "../utils/format"; import { DownloadCloudIcon } from "./icons/DownloadCloudIcon"; import { officialRecommendationCoverFallbacks } from "./FigmaBanner"; import { FavoriteButton } from "../favorites/FavoriteButton"; function isPlaceholderAsset(path: string | undefined | null) { return !path || path.includes("placeholder-cover"); } const CARD_BASE_CLASS = "group flex shrink-0 flex-col overflow-hidden rounded-xl border bg-[#1D1E23] transition hover:border-ark-gold/55 hover:shadow-lg hover:shadow-black/30"; const CARD_HOVER_SPRING = { type: "spring", stiffness: 380, damping: 26, } as const; const CARD_CAROUSEL_SIZE_CLASS = "w-[208px] md:w-[240px] lg:w-[246.4px] min-[1100px]:w-[273px]"; const CARD_GRID_SIZE_CLASS = "w-full max-w-[360px] md:max-w-none"; type RecommendedResource = Resource & { downloadPostId?: string; downloadAttachmentId?: string; }; export function RecommendedCard({ r, visualIndex = 0, useFigmaDesign = false, layout = "carousel", }: { r: RecommendedResource; visualIndex?: number; useFigmaDesign?: boolean; layout?: "carousel" | "grid"; }) { const { t } = useI18n(); const lp = useLocalizedPath(); const navigate = useNavigate(); const figmaCover = officialRecommendationCoverFallbacks[ visualIndex % officialRecommendationCoverFallbacks.length ]; const cover = useMemo(() => { const original = r.coverImage || r.previewUrl; if (isPlaceholderAsset(original)) { return useFigmaDesign ? "" : figmaCover; } return assetUrl(original); }, [figmaCover, r.coverImage, r.previewUrl, useFigmaDesign]); const displayTitle = r.title; const displayCategoryName = r.categoryName; const dateStr = formatDateYmd(r.updatedAt); const dateTime = r.updatedAt; const dl = r.isDownloadable && (r.fileUrl || r.previewUrl) ? assetUrl(r.fileUrl || r.previewUrl) : ""; const goToPost = () => { // Same destination as the card-wide overlay link, so the user lands on the // post and can choose exactly which attachment to download. navigate(lp(`/resource/${r.id}`)); }; return ( {cover ? ( e.currentTarget.classList.add("is-loaded")} /> ) : ( )} {!useFigmaDesign && r.badgeLabel ? ( {r.badgeLabel} ) : null} {displayTitle} {useFigmaDesign ? ( {displayCategoryName} ) : null} {useFigmaDesign ? null : ( <> {displayCategoryName} · > )} {dateStr} {dl ? ( { e.preventDefault(); e.stopPropagation(); goToPost(); }} > ) : null} ); } export function ComingSoonRecommendedCard({ visualIndex = 0, }: { visualIndex?: number; }) { const cover = officialRecommendationCoverFallbacks[ visualIndex % officialRecommendationCoverFallbacks.length ]; return ( 即将到来 即将到来 更多内容准备中 ); }