diff --git a/src/components/LatestUpdateCard.tsx b/src/components/LatestUpdateCard.tsx index ef30bff..16d62b8 100644 --- a/src/components/LatestUpdateCard.tsx +++ b/src/components/LatestUpdateCard.tsx @@ -1,17 +1,10 @@ -import { LoaderCircle, Play } from "lucide-react"; -import { useState } from "react"; -import { Link } from "react-router-dom"; +import { Play } from "lucide-react"; +import { Link, useNavigate } from "react-router-dom"; import { FavoriteButton } from "../favorites/FavoriteButton"; import { useI18n } from "../i18n"; import { useLocalizedPath } from "../useLocalizedPath"; import type { Attachment, Post } from "../types/post"; import { DownloadCloudIcon } from "./icons/DownloadCloudIcon"; -import { - mediaSaveKindFromAttachment, - useSaveToAlbumGuide, -} from "./SaveToAlbumGuide"; -import { useToast } from "./Toast"; -import { downloadAttachment } from "./messageStream/utils/downloadFile"; import { fileIcon } from "./messageStream/utils/fileIcon"; import { filenameWithExtension, @@ -30,24 +23,11 @@ function LatestActions({ attachment?: Attachment; }) { const { t } = useI18n(); - const { showToast } = useToast(); - const { showSaveToAlbumGuide } = useSaveToAlbumGuide(); - const [isDownloading, setIsDownloading] = useState(false); + const lp = useLocalizedPath(); + const navigate = useNavigate(); - const handleDownload = async () => { - if (!attachment || isDownloading) return; - setIsDownloading(true); - try { - await downloadAttachment(post.id, attachment.id, attachment.filename, { - sizeBytes: attachment.sizeBytes, - }); - const mediaKind = mediaSaveKindFromAttachment(attachment); - if (mediaKind) showSaveToAlbumGuide(mediaKind); - } catch { - showToast(t("downloadFail"), "error"); - } finally { - setIsDownloading(false); - } + const goToPost = () => { + navigate(lp(`/browse?post=${encodeURIComponent(post.id)}`)); }; return ( @@ -59,23 +39,13 @@ function LatestActions({ onClick={(event) => { event.preventDefault(); event.stopPropagation(); - void handleDownload(); + goToPost(); }} - disabled={isDownloading} - aria-label={ - isDownloading ? t("downloading") : `Download ${attachment.filename}` - } - aria-busy={isDownloading} - className="relative z-20 flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-[#191921] text-white outline-none transition hover:bg-[#22232D] focus-visible:ring-2 focus-visible:ring-ark-gold/70 disabled:cursor-wait" + aria-label={t("download")} + title={t("download")} + className="relative z-20 flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-[#191921] text-white outline-none transition hover:bg-[#22232D] focus-visible:ring-2 focus-visible:ring-ark-gold/70" > - {isDownloading ? ( - - ) : ( - - )} + ) : null} diff --git a/src/components/PopularRankList.tsx b/src/components/PopularRankList.tsx index c939352..12123df 100644 --- a/src/components/PopularRankList.tsx +++ b/src/components/PopularRankList.tsx @@ -4,7 +4,6 @@ import { FileText, Image as ImageIcon, Link as LinkIcon, - LoaderCircle, Music, Presentation, Video, @@ -21,9 +20,6 @@ import { cleanCategoryDisplayName } from "../utils/categoryDisplay"; import { formatDateYmd } from "../utils/format"; import { postToResource } from "../utils/postResourceAdapter"; import type { Post } from "../types/post"; -import { downloadAttachment } from "./messageStream/utils/downloadFile"; -import { mediaSaveKindFromType, useSaveToAlbumGuide } from "./SaveToAlbumGuide"; -import { useToast } from "./Toast"; import { FavoriteButton } from "../favorites/FavoriteButton"; const MEDALS = ["🥇", "🥈", "🥉"]; @@ -105,31 +101,18 @@ export function PopularRankRow({ const { t, lang } = useI18n(); const navigate = useNavigate(); const lp = useLocalizedPath(); - const { showToast } = useToast(); - const { showSaveToAlbumGuide } = useSaveToAlbumGuide(); - const [isDownloading, setIsDownloading] = useState(false); const [coverFailed, setCoverFailed] = useState(false); const r = postToResource(post, lang, categories); const cover = r.coverImage && !coverFailed ? assetUrl(r.coverImage) : ""; const isTop3 = showRank && index < MEDALS.length; - const handleDownload = async () => { - if (isDownloading || !r.downloadPostId || !r.downloadAttachmentId) return; - setIsDownloading(true); - try { - await downloadAttachment( - r.downloadPostId, - r.downloadAttachmentId, - r.title, - ); - const mediaKind = mediaSaveKindFromType(r.type); - if (mediaKind) showSaveToAlbumGuide(mediaKind); - } catch { - showToast(t("downloadFail"), "error"); - } finally { - setIsDownloading(false); - } + const goToPost = () => { + const params = new URLSearchParams(); + if (browseSort) params.set("sort", browseSort); + params.set("post", post.id); + if (singlePostLink) params.set("single", "1"); + navigate(lp(`/browse?${params.toString()}`)); }; return ( @@ -142,13 +125,7 @@ export function PopularRankRow({ > ) : null} diff --git a/src/components/RecommendedCard.tsx b/src/components/RecommendedCard.tsx index f3566ca..2dbbb2b 100644 --- a/src/components/RecommendedCard.tsx +++ b/src/components/RecommendedCard.tsx @@ -1,20 +1,13 @@ -import { Download, LoaderCircle } from "lucide-react"; import { m } from "framer-motion"; -import { Link } from "react-router-dom"; +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, useState } from "react"; +import { useMemo } from "react"; import { formatDateYmd } from "../utils/format"; import { DownloadCloudIcon } from "./icons/DownloadCloudIcon"; import { officialRecommendationCoverFallbacks } from "./FigmaBanner"; -import { - downloadAttachment, - downloadFile, -} from "./messageStream/utils/downloadFile"; -import { mediaSaveKindFromType, useSaveToAlbumGuide } from "./SaveToAlbumGuide"; -import { useToast } from "./Toast"; import { FavoriteButton } from "../favorites/FavoriteButton"; function isPlaceholderAsset(path: string | undefined | null) { @@ -53,9 +46,7 @@ export function RecommendedCard({ }) { const { t } = useI18n(); const lp = useLocalizedPath(); - const { showToast } = useToast(); - const { showSaveToAlbumGuide } = useSaveToAlbumGuide(); - const [isDownloading, setIsDownloading] = useState(false); + const navigate = useNavigate(); const figmaCover = officialRecommendationCoverFallbacks[ visualIndex % officialRecommendationCoverFallbacks.length @@ -77,26 +68,10 @@ export function RecommendedCard({ ? assetUrl(r.fileUrl || r.previewUrl) : ""; - const handleDownload = async () => { - if (isDownloading) return; - setIsDownloading(true); - try { - if (r.downloadPostId && r.downloadAttachmentId) { - await downloadAttachment( - r.downloadPostId, - r.downloadAttachmentId, - displayTitle, - ); - } else { - await downloadFile(dl, displayTitle); - } - const mediaKind = mediaSaveKindFromType(r.type); - if (mediaKind) showSaveToAlbumGuide(mediaKind); - } catch { - showToast(t("downloadFail"), "error"); - } finally { - setIsDownloading(false); - } + 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 ( @@ -193,29 +168,18 @@ export function RecommendedCard({ type="button" className={ useFigmaDesign - ? "relative z-20 flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-[#191921] text-white outline-none transition hover:bg-[#22232D] active:scale-95 focus-visible:ring-2 focus-visible:ring-ark-gold/80 disabled:cursor-wait" - : "relative z-20 shrink-0 rounded-lg p-1 text-white outline-none transition hover:bg-ark-gold/10 active:scale-95 focus-visible:ring-2 focus-visible:ring-ark-gold/80 disabled:cursor-wait" + ? "relative z-20 flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-[#191921] text-white outline-none transition hover:bg-[#22232D] active:scale-95 focus-visible:ring-2 focus-visible:ring-ark-gold/80" + : "relative z-20 shrink-0 rounded-lg p-1 text-white outline-none transition hover:bg-ark-gold/10 active:scale-95 focus-visible:ring-2 focus-visible:ring-ark-gold/80" } - title={isDownloading ? t("downloading") : t("download")} - aria-label={isDownloading ? t("downloading") : t("download")} - aria-busy={isDownloading} - disabled={isDownloading} + title={t("download")} + aria-label={t("download")} onClick={(e) => { e.preventDefault(); e.stopPropagation(); - void handleDownload(); + goToPost(); }} > - {isDownloading ? ( - - ) : useFigmaDesign ? ( - - ) : ( - - )} + ) : null}