Files
multica/packages/ui/components/common/file-upload-button.tsx
Naiyuan Qing 7c71007e6e refactor(comments): trim trigger preview copy and unify composer buttons (#4174)
Two related cleanups to the issue comment/reply/edit composer:

- Drop the trigger-preview "context" copy added in #4147 (chip prefix
  `trigger_context_*` and per-context popover titles `trigger_preview_title_*`).
  The actual "align context" fix in #4147 was the backend/hook work; the copy
  was redundant decoration. Removes the `context` prop, the dead i18n keys
  across en/zh/ja/ko, and the corresponding test assertions; the popover title
  falls back to the original single `trigger_preview_title`.

- Edit-comment footer: lay the trigger chip on a single row with the action
  cluster (📎 Cancel Save) on the right, attachments on their own full-width
  row above. The 📎 now sits with the action buttons, matching the new-comment
  and reply composers.

- Unify composer buttons on shadcn `Button`: `FileUploadButton` renders a
  ghost icon button instead of a hand-rolled circle, and the reply submit
  button uses `Button` (icon-xs, ghost-when-empty / primary-when-typed) instead
  of a hand-rolled element. Sizes: 📎 and reply submit are both icon-xs (24px).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 09:44:05 +08:00

65 lines
1.7 KiB
TypeScript

"use client";
import { useRef } from "react";
import { Paperclip } from "lucide-react";
import { useTranslation } from "react-i18next";
import { Button } from "@multica/ui/components/ui/button";
import { cn } from "@multica/ui/lib/utils";
interface FileUploadButtonProps {
/** Called with the selected File — caller handles upload. */
onSelect: (file: File) => void;
disabled?: boolean;
className?: string;
size?: "sm" | "default";
multiple?: boolean;
}
function FileUploadButton({
onSelect,
disabled,
className,
size = "default",
multiple = false,
}: FileUploadButtonProps) {
const { t } = useTranslation("ui");
const inputRef = useRef<HTMLInputElement>(null);
const attachLabel = t(($) => $.attach_file);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const files = Array.from(e.target.files ?? []);
if (files.length === 0) return;
e.target.value = "";
for (const file of files) onSelect(file);
};
const iconSize = size === "sm" ? "h-3.5 w-3.5" : "h-4 w-4";
const buttonSize = size === "sm" ? "icon-xs" : "icon-sm";
return (
<>
<Button
type="button"
variant="ghost"
size={buttonSize}
onClick={() => inputRef.current?.click()}
disabled={disabled}
aria-label={attachLabel}
title={attachLabel}
className={cn("text-muted-foreground", className)}
>
<Paperclip className={iconSize} />
</Button>
<input
ref={inputRef}
type="file"
multiple={multiple}
className="hidden"
onChange={handleChange}
/>
</>
);
}
export { FileUploadButton, type FileUploadButtonProps };