mirror of
https://github.com/usememos/memos.git
synced 2025-06-05 22:09:59 +02:00
chore: remove memo card dialog (#475)
This commit is contained in:
@ -11,7 +11,6 @@ import Icon from "./Icon";
|
|||||||
import toastHelper from "./Toast";
|
import toastHelper from "./Toast";
|
||||||
import MemoContent from "./MemoContent";
|
import MemoContent from "./MemoContent";
|
||||||
import MemoResources from "./MemoResources";
|
import MemoResources from "./MemoResources";
|
||||||
import showMemoCardDialog from "./MemoCardDialog";
|
|
||||||
import showShareMemoImageDialog from "./ShareMemoImageDialog";
|
import showShareMemoImageDialog from "./ShareMemoImageDialog";
|
||||||
import showPreviewImageDialog from "./PreviewImageDialog";
|
import showPreviewImageDialog from "./PreviewImageDialog";
|
||||||
import "../less/memo.less";
|
import "../less/memo.less";
|
||||||
@ -51,14 +50,6 @@ const Memo: React.FC<Props> = (props: Props) => {
|
|||||||
};
|
};
|
||||||
}, [i18n.language]);
|
}, [i18n.language]);
|
||||||
|
|
||||||
const handleShowMemoStoryDialog = () => {
|
|
||||||
if (isVisitorMode) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
showMemoCardDialog(memo);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleViewMemoDetailPage = () => {
|
const handleViewMemoDetailPage = () => {
|
||||||
navigate(`/m/${memo.id}`);
|
navigate(`/m/${memo.id}`);
|
||||||
};
|
};
|
||||||
@ -116,7 +107,7 @@ const Memo: React.FC<Props> = (props: Props) => {
|
|||||||
const memoTemp = await memoService.getMemoById(Number(memoId) ?? UNKNOWN_ID);
|
const memoTemp = await memoService.getMemoById(Number(memoId) ?? UNKNOWN_ID);
|
||||||
|
|
||||||
if (memoTemp) {
|
if (memoTemp) {
|
||||||
showMemoCardDialog(memoTemp);
|
navigate(`/m/${memoTemp.id}`);
|
||||||
} else {
|
} else {
|
||||||
toastHelper.error(t("message.memo-not-found"));
|
toastHelper.error(t("message.memo-not-found"));
|
||||||
targetEl.classList.remove("memo-link-text");
|
targetEl.classList.remove("memo-link-text");
|
||||||
@ -209,9 +200,7 @@ const Memo: React.FC<Props> = (props: Props) => {
|
|||||||
{memo.pinned && <div className="corner-container"></div>}
|
{memo.pinned && <div className="corner-container"></div>}
|
||||||
<div className="memo-top-wrapper">
|
<div className="memo-top-wrapper">
|
||||||
<div className="status-text-container">
|
<div className="status-text-container">
|
||||||
<span className="time-text" onClick={handleShowMemoStoryDialog}>
|
<span className="time-text">{displayTimeStr}</span>
|
||||||
{displayTimeStr}
|
|
||||||
</span>
|
|
||||||
{memo.visibility !== "PRIVATE" && !isVisitorMode && (
|
{memo.visibility !== "PRIVATE" && !isVisitorMode && (
|
||||||
<span
|
<span
|
||||||
className={`status-text ${memo.visibility.toLocaleLowerCase()}`}
|
className={`status-text ${memo.visibility.toLocaleLowerCase()}`}
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -28,7 +28,7 @@
|
|||||||
@apply flex flex-row justify-start items-center;
|
@apply flex flex-row justify-start items-center;
|
||||||
|
|
||||||
> .time-text {
|
> .time-text {
|
||||||
@apply text-xs text-gray-400 cursor-pointer;
|
@apply text-xs text-gray-400;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user