import { Tooltip } from "@mui/joy"; import { BookmarkIcon, EyeOffIcon, MessageCircleMoreIcon } from "lucide-react"; // import { log } from "mermaid/dist/logger"; import { memo, useCallback, useRef, useState } from "react"; import { Link, useLocation } from "react-router-dom"; import useAsyncEffect from "@/hooks/useAsyncEffect"; import useCurrentUser from "@/hooks/useCurrentUser"; import useNavigateTo from "@/hooks/useNavigateTo"; import { useMemoStore } from "@/store/v1"; import { userStore, workspaceStore } from "@/store/v2"; import { State } from "@/types/proto/api/v1/common"; import { Memo, MemoRelation_Type, Visibility } from "@/types/proto/api/v1/memo_service"; import { cn } from "@/utils"; import { useTranslate } from "@/utils/i18n"; import { convertVisibilityToString } from "@/utils/memo"; import { isSuperUser } from "@/utils/user"; import MemoActionMenu from "./MemoActionMenu"; import MemoContent from "./MemoContent"; import MemoEditor from "./MemoEditor"; import MemoLocationView from "./MemoLocationView"; import MemoReactionistView from "./MemoReactionListView"; import MemoRelationListView from "./MemoRelationListView"; import MemoResourceListView from "./MemoResourceListView"; import showPreviewImageDialog from "./PreviewImageDialog"; import ReactionSelector from "./ReactionSelector"; import UserAvatar from "./UserAvatar"; import VisibilityIcon from "./VisibilityIcon"; interface Props { memo: Memo; compact?: boolean; showCreator?: boolean; showVisibility?: boolean; showPinned?: boolean; showNsfwContent?: boolean; className?: string; parentPage?: string; } const MemoView: React.FC = (props: Props) => { const { memo, className } = props; const t = useTranslate(); const location = useLocation(); const navigateTo = useNavigateTo(); const currentUser = useCurrentUser(); const user = useCurrentUser(); const memoStore = useMemoStore(); const [showEditor, setShowEditor] = useState(false); const [creator, setCreator] = useState(userStore.getUserByName(memo.creator)); const [showNSFWContent, setShowNSFWContent] = useState(props.showNsfwContent); const memoContainerRef = useRef(null); const workspaceMemoRelatedSetting = workspaceStore.state.memoRelatedSetting; const referencedMemos = memo.relations.filter((relation) => relation.type === MemoRelation_Type.REFERENCE); const commentAmount = memo.relations.filter( (relation) => relation.type === MemoRelation_Type.COMMENT && relation.relatedMemo?.name === memo.name, ).length; const relativeTimeFormat = Date.now() - memo.displayTime!.getTime() > 1000 * 60 * 60 * 24 ? "datetime" : "auto"; const isArchived = memo.state === State.ARCHIVED; const readonly = memo.creator !== user?.name && !isSuperUser(user); const isInMemoDetailPage = location.pathname.startsWith(`/${memo.name}`); const parentPage = props.parentPage || location.pathname; const nsfw = workspaceMemoRelatedSetting.enableBlurNsfwContent && memo.tags?.some((tag) => workspaceMemoRelatedSetting.nsfwTags.includes(tag.toLowerCase())); // Initial related data: creator. useAsyncEffect(async () => { const user = await userStore.getOrFetchUserByName(memo.creator); setCreator(user); }, []); const handleGotoMemoDetailPage = useCallback(() => { navigateTo(`/${memo.name}`, { state: { from: parentPage, }, }); }, [memo.name, parentPage]); const handleMemoContentClick = useCallback(async (e: React.MouseEvent) => { const targetEl = e.target as HTMLElement; if (targetEl.tagName === "IMG") { const imgUrl = targetEl.getAttribute("src"); if (imgUrl) { showPreviewImageDialog([imgUrl], 0); } } }, []); const handleMemoContentDoubleClick = useCallback(async (e: React.MouseEvent) => { if (readonly) { return; } if (workspaceMemoRelatedSetting.enableDoubleClickEdit) { e.preventDefault(); setShowEditor(true); } }, []); const onEditorConfirm = () => { setShowEditor(false); userStore.setStatsStateId(); }; const onPinIconClick = async () => { if (memo.pinned) { await memoStore.updateMemo( { name: memo.name, pinned: false, }, ["pinned"], ); } }; const displayTime = isArchived ? ( memo.displayTime?.toLocaleString() ) : ( ); let memoTags = ""; memo.tags?.forEach((tag) => { memoTags = memoTags + " tagged-" + tag.toLowerCase(); }); return (
{showEditor ? ( setShowEditor(false)} /> ) : ( <>
{props.showCreator && creator ? (
{creator.nickname || creator.username}
{displayTime}
) : (
{displayTime}
)}
{props.showVisibility && memo.visibility !== Visibility.PRIVATE && ( )} {currentUser && !isArchived && }
{!isInMemoDetailPage && (workspaceMemoRelatedSetting.enableComment || commentAmount > 0) && ( {commentAmount > 0 && {commentAmount}} )} {props.showPinned && memo.pinned && ( )} {nsfw && showNSFWContent && ( setShowNSFWContent(false)} /> )} setShowEditor(true)} />
{memo.location && }
{nsfw && !showNSFWContent && ( <>
)} )}
); }; export default memo(MemoView);