fix: download button on cards opens the post page

On compact cards the user cannot see which file is attached, especially for multi-attachment posts. Make the small download button on PopularRankRow, RecommendedCard, and LatestUpdateCard navigate to the post detail page instead of triggering an immediate download, so the user lands in the full post and picks the exact attachment to download.
This commit is contained in:
TerryM
2026-06-05 19:36:54 +08:00
parent 69bef7ee6e
commit 75ccfd78ed
3 changed files with 38 additions and 131 deletions

View File

@@ -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 ? (
<LoaderCircle
className="h-4 w-4 animate-spin"
strokeWidth={2.2}
/>
) : useFigmaDesign ? (
<DownloadCloudIcon className="h-5 w-5" />
) : (
<Download className="h-5 w-5" strokeWidth={2.2} />
)}
<DownloadCloudIcon className="h-5 w-5" />
</button>
) : null}
</div>