mirror of https://github.com/usememos/memos
				
				
				
			chore: remove memo card dialog (#475)
							parent
							
								
									67195859dc
								
							
						
					
					
						commit
						de2eff474c
					
				@ -1,225 +0,0 @@
 | 
			
		||||
import copy from "copy-to-clipboard";
 | 
			
		||||
import { useState, useEffect, useCallback } from "react";
 | 
			
		||||
import { useTranslation } from "react-i18next";
 | 
			
		||||
import { editorStateService, memoService, userService } from "../services";
 | 
			
		||||
import { useAppSelector } from "../store";
 | 
			
		||||
import { UNKNOWN_ID } from "../helpers/consts";
 | 
			
		||||
import * as utils from "../helpers/utils";
 | 
			
		||||
import { parseHTMLToRawText } from "../helpers/utils";
 | 
			
		||||
import { marked } from "../labs/marked";
 | 
			
		||||
import { MARK_REG } from "../labs/marked/parser";
 | 
			
		||||
import toastHelper from "./Toast";
 | 
			
		||||
import { generateDialog } from "./Dialog";
 | 
			
		||||
import Icon from "./Icon";
 | 
			
		||||
import MemoContent from "./MemoContent";
 | 
			
		||||
import MemoResources from "./MemoResources";
 | 
			
		||||
import showChangeMemoCreatedTsDialog from "./ChangeMemoCreatedTsDialog";
 | 
			
		||||
import "../less/memo-card-dialog.less";
 | 
			
		||||
 | 
			
		||||
interface LinkedMemo extends Memo {
 | 
			
		||||
  createdAtStr: string;
 | 
			
		||||
  dateStr: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface Props extends DialogProps {
 | 
			
		||||
  memo: Memo;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const MemoCardDialog: React.FC<Props> = (props: Props) => {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  const memos = useAppSelector((state) => state.memo.memos);
 | 
			
		||||
  const [memo, setMemo] = useState<Memo>({
 | 
			
		||||
    ...props.memo,
 | 
			
		||||
  });
 | 
			
		||||
  const [linkMemos, setLinkMemos] = useState<LinkedMemo[]>([]);
 | 
			
		||||
  const [linkedMemos, setLinkedMemos] = useState<LinkedMemo[]>([]);
 | 
			
		||||
  const isVisitorMode = userService.isVisitorMode();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const fetchLinkedMemos = async () => {
 | 
			
		||||
      try {
 | 
			
		||||
        const linkMemos: LinkedMemo[] = [];
 | 
			
		||||
        const matchedArr = [...memo.content.matchAll(MARK_REG)];
 | 
			
		||||
        for (const matchRes of matchedArr) {
 | 
			
		||||
          if (matchRes && matchRes.length === 3) {
 | 
			
		||||
            const id = Number(matchRes[2]);
 | 
			
		||||
            if (id === memo.id) {
 | 
			
		||||
              continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const memoTemp = await memoService.getMemoById(id);
 | 
			
		||||
            if (memoTemp) {
 | 
			
		||||
              linkMemos.push({
 | 
			
		||||
                ...memoTemp,
 | 
			
		||||
                createdAtStr: utils.getDateTimeString(memoTemp.displayTs),
 | 
			
		||||
                dateStr: utils.getDateString(memoTemp.displayTs),
 | 
			
		||||
              });
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        setLinkMemos([...linkMemos]);
 | 
			
		||||
 | 
			
		||||
        const linkedMemos = await memoService.getLinkedMemos(memo.id);
 | 
			
		||||
        setLinkedMemos(
 | 
			
		||||
          linkedMemos
 | 
			
		||||
            .filter((m) => m.rowStatus === "NORMAL" && m.id !== memo.id)
 | 
			
		||||
            .sort((a, b) => utils.getTimeStampByDate(b.displayTs) - utils.getTimeStampByDate(a.displayTs))
 | 
			
		||||
            .map((m) => ({
 | 
			
		||||
              ...m,
 | 
			
		||||
              createdAtStr: utils.getDateTimeString(m.displayTs),
 | 
			
		||||
              dateStr: utils.getDateString(m.displayTs),
 | 
			
		||||
            }))
 | 
			
		||||
        );
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        // do nth
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    fetchLinkedMemos();
 | 
			
		||||
    memoService.getMemoById(memo.id).then((memo) => {
 | 
			
		||||
      setMemo(memo);
 | 
			
		||||
    });
 | 
			
		||||
  }, [memos, memo.id]);
 | 
			
		||||
 | 
			
		||||
  const handleMemoCreatedAtClick = () => {
 | 
			
		||||
    if (isVisitorMode) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    showChangeMemoCreatedTsDialog(memo.id);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleMemoContentClick = useCallback(async (e: React.MouseEvent) => {
 | 
			
		||||
    const targetEl = e.target as HTMLElement;
 | 
			
		||||
 | 
			
		||||
    if (targetEl.className === "memo-link-text") {
 | 
			
		||||
      const nextMemoId = targetEl.dataset?.value;
 | 
			
		||||
      const memoTemp = await memoService.getMemoById(Number(nextMemoId) ?? UNKNOWN_ID);
 | 
			
		||||
 | 
			
		||||
      if (memoTemp) {
 | 
			
		||||
        const nextMemo = {
 | 
			
		||||
          ...memoTemp,
 | 
			
		||||
          createdAtStr: utils.getDateTimeString(memoTemp.displayTs),
 | 
			
		||||
        };
 | 
			
		||||
        setLinkMemos([]);
 | 
			
		||||
        setLinkedMemos([]);
 | 
			
		||||
        setMemo(nextMemo);
 | 
			
		||||
      } else {
 | 
			
		||||
        toastHelper.error(t("message.memo-not-found"));
 | 
			
		||||
        targetEl.classList.remove("memo-link-text");
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }, []);
 | 
			
		||||
 | 
			
		||||
  const handleLinkedMemoClick = useCallback((memo: Memo) => {
 | 
			
		||||
    setLinkMemos([]);
 | 
			
		||||
    setLinkedMemos([]);
 | 
			
		||||
    setMemo(memo);
 | 
			
		||||
  }, []);
 | 
			
		||||
 | 
			
		||||
  const handleGotoMemoLinkBtnClick = () => {
 | 
			
		||||
    window.open(`/m/${memo.id}`);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleEditMemoBtnClick = () => {
 | 
			
		||||
    props.destroy();
 | 
			
		||||
    editorStateService.setEditMemoWithId(memo.id);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleCopyContent = () => {
 | 
			
		||||
    copy(memo.content);
 | 
			
		||||
    toastHelper.success(t("message.succeed-copy-content"));
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      <div className="memo-card-container">
 | 
			
		||||
        <div className="header-container">
 | 
			
		||||
          <p className="time-text" onClick={handleMemoCreatedAtClick}>
 | 
			
		||||
            {utils.getDateTimeString(memo.displayTs)}
 | 
			
		||||
          </p>
 | 
			
		||||
          <div className="btns-container">
 | 
			
		||||
            {!isVisitorMode && (
 | 
			
		||||
              <>
 | 
			
		||||
                <button className="btn edit-btn" onClick={handleGotoMemoLinkBtnClick}>
 | 
			
		||||
                  <Icon.ExternalLink className="icon-img" />
 | 
			
		||||
                </button>
 | 
			
		||||
                <button className="btn copy-btn" onClick={handleCopyContent}>
 | 
			
		||||
                  <Icon.Clipboard className="icon-img" />
 | 
			
		||||
                </button>
 | 
			
		||||
                <button className="btn edit-btn" onClick={handleEditMemoBtnClick}>
 | 
			
		||||
                  <Icon.Edit3 className="icon-img" />
 | 
			
		||||
                </button>
 | 
			
		||||
                <span className="split-line">/</span>
 | 
			
		||||
              </>
 | 
			
		||||
            )}
 | 
			
		||||
            <button className="btn close-btn" onClick={props.destroy}>
 | 
			
		||||
              <Icon.X className="icon-img" />
 | 
			
		||||
            </button>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className="memo-container">
 | 
			
		||||
          <MemoContent displayConfig={{ enableExpand: false }} content={memo.content} onMemoContentClick={handleMemoContentClick} />
 | 
			
		||||
          <MemoResources resourceList={memo.resourceList} />
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className="layer-container"></div>
 | 
			
		||||
        {linkMemos.map((_, idx) => {
 | 
			
		||||
          if (idx < 4) {
 | 
			
		||||
            return (
 | 
			
		||||
              <div
 | 
			
		||||
                className="background-layer-container"
 | 
			
		||||
                key={idx}
 | 
			
		||||
                style={{
 | 
			
		||||
                  bottom: (idx + 1) * -3 + "px",
 | 
			
		||||
                  left: (idx + 1) * 5 + "px",
 | 
			
		||||
                  width: `calc(100% - ${(idx + 1) * 10}px)`,
 | 
			
		||||
                  zIndex: -idx - 1,
 | 
			
		||||
                }}
 | 
			
		||||
              ></div>
 | 
			
		||||
            );
 | 
			
		||||
          } else {
 | 
			
		||||
            return null;
 | 
			
		||||
          }
 | 
			
		||||
        })}
 | 
			
		||||
      </div>
 | 
			
		||||
      {linkMemos.length > 0 ? (
 | 
			
		||||
        <div className="linked-memos-wrapper">
 | 
			
		||||
          <p className="normal-text">{linkMemos.length} related MEMO</p>
 | 
			
		||||
          {linkMemos.map((memo, index) => {
 | 
			
		||||
            const rawtext = parseHTMLToRawText(marked(memo.content)).replaceAll("\n", " ");
 | 
			
		||||
            return (
 | 
			
		||||
              <div className="linked-memo-container" key={`${index}-${memo.id}`} onClick={() => handleLinkedMemoClick(memo)}>
 | 
			
		||||
                <span className="time-text">{memo.dateStr} </span>
 | 
			
		||||
                {rawtext}
 | 
			
		||||
              </div>
 | 
			
		||||
            );
 | 
			
		||||
          })}
 | 
			
		||||
        </div>
 | 
			
		||||
      ) : null}
 | 
			
		||||
      {linkedMemos.length > 0 ? (
 | 
			
		||||
        <div className="linked-memos-wrapper">
 | 
			
		||||
          <p className="normal-text">{linkedMemos.length} linked MEMO</p>
 | 
			
		||||
          {linkedMemos.map((memo, index) => {
 | 
			
		||||
            const rawtext = parseHTMLToRawText(marked(memo.content)).replaceAll("\n", " ");
 | 
			
		||||
            return (
 | 
			
		||||
              <div className="linked-memo-container" key={`${index}-${memo.id}`} onClick={() => handleLinkedMemoClick(memo)}>
 | 
			
		||||
                <span className="time-text">{memo.dateStr} </span>
 | 
			
		||||
                {rawtext}
 | 
			
		||||
              </div>
 | 
			
		||||
            );
 | 
			
		||||
          })}
 | 
			
		||||
        </div>
 | 
			
		||||
      ) : null}
 | 
			
		||||
    </>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default function showMemoCardDialog(memo: Memo): void {
 | 
			
		||||
  generateDialog(
 | 
			
		||||
    {
 | 
			
		||||
      className: "memo-card-dialog",
 | 
			
		||||
    },
 | 
			
		||||
    MemoCardDialog,
 | 
			
		||||
    { memo }
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
@ -1,83 +0,0 @@
 | 
			
		||||
.dialog-wrapper.memo-card-dialog {
 | 
			
		||||
  @apply px-4;
 | 
			
		||||
 | 
			
		||||
  > .dialog-container {
 | 
			
		||||
    @apply w-full p-0 bg-transparent flex flex-col justify-start items-center;
 | 
			
		||||
 | 
			
		||||
    > .memo-card-container {
 | 
			
		||||
      @apply flex flex-col justify-start items-start relative w-128 max-w-full py-3 px-6 mb-3 rounded-lg bg-yellow-200;
 | 
			
		||||
 | 
			
		||||
      > * {
 | 
			
		||||
        z-index: 1;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      > .header-container {
 | 
			
		||||
        @apply flex flex-row justify-between items-center w-full h-auto pb-0 my-0;
 | 
			
		||||
 | 
			
		||||
        > .time-text {
 | 
			
		||||
          @apply text-sm text-gray-500 font-mono;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        > .btns-container {
 | 
			
		||||
          @apply flex flex-row justify-end items-center;
 | 
			
		||||
 | 
			
		||||
          > .btn {
 | 
			
		||||
            @apply flex flex-row justify-center items-center w-6 h-6 p-1 ml-2 rounded text-gray-600 hover:bg-white;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          > .split-line {
 | 
			
		||||
            @apply font-mono text-gray-300 ml-2;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      > .memo-container {
 | 
			
		||||
        @apply w-full flex flex-col justify-start items-start pt-2;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      > .normal-text {
 | 
			
		||||
        @apply mt-2 text-sm text-gray-500;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      > .layer-container,
 | 
			
		||||
      > .background-layer-container {
 | 
			
		||||
        @apply bg-white;
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        bottom: -3px;
 | 
			
		||||
        left: 3px;
 | 
			
		||||
        width: calc(100% - 6px);
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        border-radius: 8px;
 | 
			
		||||
        z-index: -1;
 | 
			
		||||
        border-bottom: 1px solid lightgray;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      > .layer-container {
 | 
			
		||||
        @apply bg-white;
 | 
			
		||||
        z-index: 0;
 | 
			
		||||
        border: 1px solid lightgray;
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        top: 0;
 | 
			
		||||
        left: 0;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    > .linked-memos-wrapper {
 | 
			
		||||
      @apply flex flex-col justify-start items-start w-128 max-w-full mt-2 py-3 px-6 rounded-lg bg-white last:mb-8;
 | 
			
		||||
 | 
			
		||||
      > .normal-text {
 | 
			
		||||
        @apply text-sm;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      > .linked-memo-container {
 | 
			
		||||
        @apply text-sm leading-6 mt-2 cursor-pointer max-w-full truncate hover:opacity-80;
 | 
			
		||||
 | 
			
		||||
        > .time-text {
 | 
			
		||||
          @apply font-mono text-gray-500;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
					Loading…
					
					
				
		Reference in New Issue