From 29412f469017f703f78fe03c236d90ec60d6f14f Mon Sep 17 00:00:00 2001 From: Steven Date: Mon, 2 Feb 2026 22:06:04 +0800 Subject: [PATCH] refactor: simplify NSFW implementation by inlining logic - Remove unused showNsfwContent prop (was only used in MemoDetail to pre-reveal NSFW, which defeats the purpose) - Inline useNsfwContent hook logic directly into MemoView.tsx (only 3 lines, no reusability benefit) - Delete web/src/components/MemoView/hooks/useNsfwContent.ts - NSFW content now consistently starts hidden across all pages - Maintains same user experience: click to reveal, no toggle back This removes unnecessary indirection and prop threading while preserving functionality. --- web/src/components/MemoView/MemoView.tsx | 9 +++++--- .../MemoView/components/MemoHeader.tsx | 20 +++--------------- web/src/components/MemoView/hooks/index.ts | 1 - .../MemoView/hooks/useNsfwContent.ts | 21 ------------------- web/src/components/MemoView/types.ts | 2 -- web/src/pages/MemoDetail.tsx | 1 - 6 files changed, 9 insertions(+), 45 deletions(-) delete mode 100644 web/src/components/MemoView/hooks/useNsfwContent.ts diff --git a/web/src/components/MemoView/MemoView.tsx b/web/src/components/MemoView/MemoView.tsx index 9d617b7f8..fef97e7be 100644 --- a/web/src/components/MemoView/MemoView.tsx +++ b/web/src/components/MemoView/MemoView.tsx @@ -8,7 +8,7 @@ import MemoEditor from "../MemoEditor"; import PreviewImageDialog from "../PreviewImageDialog"; import { MemoBody, MemoHeader } from "./components"; import { MEMO_CARD_BASE_CLASSES } from "./constants"; -import { useImagePreview, useMemoActions, useMemoHandlers, useNsfwContent } from "./hooks"; +import { useImagePreview, useMemoActions, useMemoHandlers } from "./hooks"; import { MemoViewContext } from "./MemoViewContext"; import type { MemoViewProps } from "./types"; @@ -23,7 +23,11 @@ const MemoView: React.FC = (props: MemoViewProps) => { const readonly = memoData.creator !== currentUser?.name && !isSuperUser(currentUser); const parentPage = parentPageProp || "/"; - const { nsfw, showNSFWContent, toggleNsfwVisibility } = useNsfwContent(memoData, props.showNsfwContent); + // NSFW content management: always blur content tagged with NSFW (case-insensitive) + const [showNSFWContent, setShowNSFWContent] = useState(false); + const nsfw = memoData.tags?.some((tag) => tag.toUpperCase() === "NSFW") ?? false; + const toggleNsfwVisibility = () => setShowNSFWContent((prev) => !prev); + const { previewState, openPreview, setPreviewOpen } = useImagePreview(); const { unpinMemo } = useMemoActions(memoData, isArchived); @@ -76,7 +80,6 @@ const MemoView: React.FC = (props: MemoViewProps) => { onEdit={openEditor} onGotoDetail={handleGotoMemoDetailPage} onUnpin={unpinMemo} - onToggleNsfwVisibility={toggleNsfwVisibility} /> = ({ - showCreator, - showVisibility, - showPinned, - onEdit, - onGotoDetail, - onUnpin, - onToggleNsfwVisibility, -}) => { +const MemoHeader: React.FC = ({ showCreator, showVisibility, showPinned, onEdit, onGotoDetail, onUnpin }) => { const t = useTranslate(); const [reactionSelectorOpen, setReactionSelectorOpen] = useState(false); - const { memo, creator, currentUser, parentPage, isArchived, readonly, showNSFWContent, nsfw } = useMemoViewContext(); + const { memo, creator, currentUser, parentPage, isArchived, readonly } = useMemoViewContext(); const { isInMemoDetailPage, commentAmount, relativeTimeFormat } = useMemoViewDerived(); const displayTime = isArchived ? ( @@ -100,12 +92,6 @@ const MemoHeader: React.FC = ({ )} - {nsfw && showNSFWContent && onToggleNsfwVisibility && ( - - - - )} - diff --git a/web/src/components/MemoView/hooks/index.ts b/web/src/components/MemoView/hooks/index.ts index 65ca60b1b..f830d86ff 100644 --- a/web/src/components/MemoView/hooks/index.ts +++ b/web/src/components/MemoView/hooks/index.ts @@ -1,4 +1,3 @@ export { useImagePreview } from "./useImagePreview"; export { useMemoActions } from "./useMemoActions"; export { useMemoHandlers } from "./useMemoHandlers"; -export { useNsfwContent } from "./useNsfwContent"; diff --git a/web/src/components/MemoView/hooks/useNsfwContent.ts b/web/src/components/MemoView/hooks/useNsfwContent.ts deleted file mode 100644 index dcdec618f..000000000 --- a/web/src/components/MemoView/hooks/useNsfwContent.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { useState } from "react"; -import type { Memo } from "@/types/proto/api/v1/memo_service_pb"; - -export interface UseNsfwContentReturn { - nsfw: boolean; - showNSFWContent: boolean; - toggleNsfwVisibility: () => void; -} - -export const useNsfwContent = (memo: Memo, initialShowNsfw?: boolean): UseNsfwContentReturn => { - const [showNSFWContent, setShowNSFWContent] = useState(initialShowNsfw ?? false); - - // Always blur content tagged with NSFW - const nsfw = memo.tags?.includes("NSFW") ?? false; - - return { - nsfw, - showNSFWContent, - toggleNsfwVisibility: () => setShowNSFWContent((prev) => !prev), - }; -}; diff --git a/web/src/components/MemoView/types.ts b/web/src/components/MemoView/types.ts index 527d0f057..45e505dc7 100644 --- a/web/src/components/MemoView/types.ts +++ b/web/src/components/MemoView/types.ts @@ -6,7 +6,6 @@ export interface MemoViewProps { showCreator?: boolean; showVisibility?: boolean; showPinned?: boolean; - showNsfwContent?: boolean; className?: string; parentPage?: string; } @@ -18,7 +17,6 @@ export interface MemoHeaderProps { onEdit: () => void; onGotoDetail: () => void; onUnpin: () => void; - onToggleNsfwVisibility?: () => void; } export interface MemoBodyProps { diff --git a/web/src/pages/MemoDetail.tsx b/web/src/pages/MemoDetail.tsx index 3dabcf59e..acc843247 100644 --- a/web/src/pages/MemoDetail.tsx +++ b/web/src/pages/MemoDetail.tsx @@ -93,7 +93,6 @@ const MemoDetail = () => { showCreator showVisibility showPinned - showNsfwContent />