Files
Epicure/apps/web/components/shared/export-markdown-button.tsx
T
Arnaud 1614da38cd fix: recipe version diff readability + i18n, tooltip on markdown export
- Version compare used positional (index-by-index) list alignment —
  inserting one ingredient in the middle shifted every subsequent line
  out of alignment, making the whole rest of the list look changed.
  Switch to diffArrays (LCS-based) so insertions/deletions are
  detected properly; adjacent removed+added chunks still get paired
  for word-level diffing so a single edited item doesn't render as a
  full delete+insert.
- Translated "Title"/"Description"/"Ingredients"/"Steps" diff section
  headers, "Version History" sheet title, compare/restore buttons,
  loading/empty states, and the version-detail ingredient/step count
  summary (with proper plural forms).
- formatDate() in version history was hardcoded to "en-US" regardless
  of the app's locale — now uses the session locale.
- ExportMarkdownButton had no hover tooltip (bare title attribute) —
  wrap it in the same Tooltip pattern every other icon button in the
  toolbar uses.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-09 04:19:33 +02:00

72 lines
2.0 KiB
TypeScript

"use client";
import { Copy, Download, FileDown } from "lucide-react";
import { toast } from "sonner";
import { useTranslations } from "next-intl";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
export function ExportMarkdownButton({
markdown,
filename,
}: {
markdown: string;
filename: string;
}) {
const t = useTranslations("common");
async function handleCopy() {
try {
await navigator.clipboard.writeText(markdown);
toast.success(t("copiedToClipboard"));
} catch {
toast.error(t("copyFailed"));
}
}
function handleDownload() {
const blob = new Blob([markdown], { type: "text/markdown;charset=utf-8" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = filename.endsWith(".md") ? filename : `${filename}.md`;
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
}
return (
<DropdownMenu>
<TooltipProvider>
<Tooltip>
<TooltipTrigger render={
<DropdownMenuTrigger render={
<Button variant="ghost" size="icon">
<FileDown className="h-4 w-4" />
</Button>
} />
} />
<TooltipContent>{t("exportMarkdown")}</TooltipContent>
</Tooltip>
</TooltipProvider>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => { void handleCopy(); }}>
<Copy className="h-4 w-4" />
{t("copyMarkdown")}
</DropdownMenuItem>
<DropdownMenuItem onClick={handleDownload}>
<Download className="h-4 w-4" />
{t("downloadMarkdown")}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
}