fix: move note translation action

This commit is contained in:
lemon
2026-05-23 22:40:50 -07:00
parent 8d7d81dd3f
commit 3e7b7e824f
2 changed files with 39 additions and 26 deletions
+24 -21
View File
@@ -409,6 +409,7 @@ export const NoteCard = memo(function NoteCard({
const { data: btcPrice } = useBtcPrice();
const [moreMenuOpen, setMoreMenuOpen] = useState(false);
const [replyOpen, setReplyOpen] = useState(false);
const [translatedContent, setTranslatedContent] = useState<string | null>(null);
// Check if the current user can zap this event's author
// TODO: Enable zapping split-recipient NIP-75 goals once zap split payments are supported.
@@ -540,6 +541,12 @@ export const NoteCard = memo(function NoteCard({
const isComment = event.kind === 1111;
const isReply = isTextNote && !isComment && isReplyEvent(event);
const canTranslate = isTextNote && event.content.trim().length > 0;
const contentEvent = translatedContent ? { ...event, content: translatedContent } : event;
useEffect(() => {
setTranslatedContent(null);
}, [event.id]);
// Find all people being replied to (for "Replying to @user1 and @user2")
const replyToPubkeys = useMemo(() => {
@@ -743,7 +750,7 @@ export const NoteCard = memo(function NoteCard({
<ProfileCardContent event={event} />
) : (
<TruncatedNoteContent
event={event}
event={contentEvent}
/>
)}
</ContentWarningGuard>
@@ -878,6 +885,17 @@ export const NoteCard = memo(function NoteCard({
<div className="flex-1" />
{canTranslate && (
<TranslateButton
text={event.content}
isTranslated={translatedContent !== null}
onTranslated={setTranslatedContent}
onReset={() => setTranslatedContent(null)}
responsiveLabel
className="h-9 px-3 text-sm font-medium"
/>
)}
<button
className="inline-flex items-center justify-center h-9 w-9 rounded-full text-muted-foreground hover:text-primary hover:bg-primary/10 transition-colors sidebar:hidden"
title={t('feed.actions.share')}
@@ -1249,21 +1267,14 @@ function TruncatedNoteContent({
const contentRef = useRef<HTMLDivElement>(null);
const [overflows, setOverflows] = useState(false);
const [expanded, setExpanded] = useState(false);
const [translatedContent, setTranslatedContent] = useState<string | null>(null);
const singleImage = isSingleImagePost(event);
const canTranslate = event.content.trim().length > 0 && !singleImage;
const displayEvent = translatedContent ? { ...event, content: translatedContent } : event;
const measure = useCallback(() => {
const el = contentRef.current;
if (el) setOverflows(!singleImage && el.scrollHeight > MAX_HEIGHT);
}, [singleImage]);
useEffect(() => {
setTranslatedContent(null);
}, [event.id]);
useEffect(() => {
measure();
window.addEventListener("resize", measure);
@@ -1294,13 +1305,13 @@ function TruncatedNoteContent({
}
className="relative"
>
<NoteContent event={displayEvent} className="text-[15px] leading-relaxed" />
<NoteContent event={event} className="text-[15px] leading-relaxed" />
{!expanded && overflows && (
<div className="absolute bottom-0 left-0 right-0 h-16 bg-gradient-to-t from-background to-transparent pointer-events-none" />
)}
</div>
<div className="mt-1 flex flex-wrap items-center gap-2">
{overflows && (
{overflows && (
<div className="mt-1 flex flex-wrap items-center gap-2">
<button
className="text-sm text-primary hover:underline"
onClick={(e) => {
@@ -1310,16 +1321,8 @@ function TruncatedNoteContent({
>
{expanded ? t('noteCard.showLess') : t('noteCard.readMore')}
</button>
)}
{canTranslate && (
<TranslateButton
text={event.content}
isTranslated={translatedContent !== null}
onTranslated={setTranslatedContent}
onReset={() => setTranslatedContent(null)}
/>
)}
</div>
</div>
)}
</div>
);
}
+15 -5
View File
@@ -32,6 +32,8 @@ interface TranslateButtonProps {
onReset: () => void;
/** Whether translated content is currently visible. */
isTranslated: boolean;
/** Hide label on narrow screens so the action row can collapse to an icon. */
responsiveLabel?: boolean;
className?: string;
}
@@ -40,6 +42,7 @@ export function TranslateButton({
onTranslated,
onReset,
isTranslated,
responsiveLabel,
className,
}: TranslateButtonProps) {
const { t, i18n } = useTranslation();
@@ -98,8 +101,15 @@ export function TranslateButton({
void handleClick();
}}
disabled={loading || !text.trim()}
aria-label={
error
? t("translate.error")
: isTranslated
? t("translate.showOriginal")
: t("translate.translate")
}
className={cn(
"h-7 gap-1.5 px-2 text-xs transition-colors",
"h-7 gap-1.5 rounded-full px-2 text-xs transition-colors",
isTranslated || error
? "text-primary hover:text-primary/80"
: "text-muted-foreground hover:text-primary",
@@ -114,13 +124,13 @@ export function TranslateButton({
}
>
{loading ? (
<Loader2 className="h-3.5 w-3.5 animate-spin" />
<Loader2 className="size-[18px] animate-spin" />
) : isTranslated ? (
<RotateCcw className="h-3.5 w-3.5" />
<RotateCcw className="size-[18px]" />
) : (
<Languages className="h-3.5 w-3.5 shrink-0" />
<Languages className="size-[18px] shrink-0" />
)}
<span>
<span className={cn(responsiveLabel && "hidden sm:inline")}>
{loading
? t("translate.translating")
: error