mirror of
https://github.com/usememos/memos.git
synced 2025-10-29 15:56:03 +08:00
chore: simplify add memo relation
This commit is contained in:
parent
9b5b7b1ea2
commit
f78b277462
2 changed files with 22 additions and 90 deletions
|
|
@ -1,43 +1,30 @@
|
|||
import { uniqBy } from "lodash-es";
|
||||
import { LinkIcon, X } from "lucide-react";
|
||||
import React, { useContext, useState } from "react";
|
||||
import { LinkIcon } from "lucide-react";
|
||||
import { useContext, useState } from "react";
|
||||
import { toast } from "react-hot-toast";
|
||||
import useDebounce from "react-use/lib/useDebounce";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||
import { memoServiceClient } from "@/grpcweb";
|
||||
import { DEFAULT_LIST_MEMOS_PAGE_SIZE } from "@/helpers/consts";
|
||||
import useCurrentUser from "@/hooks/useCurrentUser";
|
||||
import { extractMemoIdFromName } from "@/store/common";
|
||||
import { extractUserIdFromName } from "@/store/common";
|
||||
import { Memo, MemoRelation_Memo, MemoRelation_Type } from "@/types/proto/api/v1/memo_service";
|
||||
import { useTranslate } from "@/utils/i18n";
|
||||
import { EditorRefActions } from "../Editor";
|
||||
import { MemoEditorContext } from "../types";
|
||||
|
||||
interface Props {
|
||||
editorRef: React.RefObject<EditorRefActions>;
|
||||
}
|
||||
|
||||
const AddMemoRelationPopover = (props: Props) => {
|
||||
const { editorRef } = props;
|
||||
const AddMemoRelationPopover = () => {
|
||||
const t = useTranslate();
|
||||
const context = useContext(MemoEditorContext);
|
||||
const user = useCurrentUser();
|
||||
const [searchText, setSearchText] = useState<string>("");
|
||||
const [isFetching, setIsFetching] = useState<boolean>(true);
|
||||
const [fetchedMemos, setFetchedMemos] = useState<Memo[]>([]);
|
||||
const [selectedMemos, setSelectedMemos] = useState<Memo[]>([]);
|
||||
const [embedded, setEmbedded] = useState<boolean>(false);
|
||||
const [popoverOpen, setPopoverOpen] = useState<boolean>(false);
|
||||
|
||||
const filteredMemos = fetchedMemos.filter(
|
||||
(memo) =>
|
||||
!selectedMemos.includes(memo) &&
|
||||
memo.name !== context.memoName &&
|
||||
!context.relationList.some((relation) => relation.relatedMemo?.name === memo.name),
|
||||
(memo) => memo.name !== context.memoName && !context.relationList.some((relation) => relation.relatedMemo?.name === memo.name),
|
||||
);
|
||||
|
||||
useDebounce(
|
||||
|
|
@ -46,10 +33,7 @@ const AddMemoRelationPopover = (props: Props) => {
|
|||
|
||||
setIsFetching(true);
|
||||
try {
|
||||
const conditions = [];
|
||||
// Extract user ID from user name (format: users/{user_id})
|
||||
const userId = user.name.replace("users/", "");
|
||||
conditions.push(`creator_id == ${userId}`);
|
||||
const conditions = [`creator_id == ${extractUserIdFromName(user.name)}`];
|
||||
if (searchText) {
|
||||
conditions.push(`content.contains("${searchText}")`);
|
||||
}
|
||||
|
|
@ -92,42 +76,20 @@ const AddMemoRelationPopover = (props: Props) => {
|
|||
);
|
||||
};
|
||||
|
||||
const addMemoRelations = async () => {
|
||||
// If embedded mode is enabled, embed the memo instead of creating a relation.
|
||||
if (embedded) {
|
||||
if (!editorRef.current) {
|
||||
toast.error(t("message.failed-to-embed-memo"));
|
||||
return;
|
||||
}
|
||||
|
||||
const cursorPosition = editorRef.current.getCursorPosition();
|
||||
const prevValue = editorRef.current.getContent().slice(0, cursorPosition);
|
||||
if (prevValue !== "" && !prevValue.endsWith("\n")) {
|
||||
editorRef.current.insertText("\n");
|
||||
}
|
||||
for (const memo of selectedMemos) {
|
||||
editorRef.current.insertText(`![[memos/${extractMemoIdFromName(memo.name)}]]\n`);
|
||||
}
|
||||
setTimeout(() => {
|
||||
editorRef.current?.scrollToCursor();
|
||||
editorRef.current?.focus();
|
||||
});
|
||||
} else {
|
||||
context.setRelationList(
|
||||
uniqBy(
|
||||
[
|
||||
...selectedMemos.map((memo) => ({
|
||||
memo: MemoRelation_Memo.fromPartial({ name: memo.name }),
|
||||
relatedMemo: MemoRelation_Memo.fromPartial({ name: memo.name }),
|
||||
type: MemoRelation_Type.REFERENCE,
|
||||
})),
|
||||
...context.relationList,
|
||||
].filter((relation) => relation.relatedMemo !== context.memoName),
|
||||
"relatedMemo",
|
||||
),
|
||||
);
|
||||
}
|
||||
setSelectedMemos([]);
|
||||
const addMemoRelations = async (memo: Memo) => {
|
||||
context.setRelationList(
|
||||
uniqBy(
|
||||
[
|
||||
{
|
||||
memo: MemoRelation_Memo.fromPartial({ name: memo.name }),
|
||||
relatedMemo: MemoRelation_Memo.fromPartial({ name: memo.name }),
|
||||
type: MemoRelation_Type.REFERENCE,
|
||||
},
|
||||
...context.relationList,
|
||||
].filter((relation) => relation.relatedMemo !== context.memoName),
|
||||
"relatedMemo",
|
||||
),
|
||||
);
|
||||
setPopoverOpen(false);
|
||||
};
|
||||
|
||||
|
|
@ -140,24 +102,6 @@ const AddMemoRelationPopover = (props: Props) => {
|
|||
</PopoverTrigger>
|
||||
<PopoverContent align="center">
|
||||
<div className="w-[16rem] p-1 flex flex-col justify-start items-start">
|
||||
{/* Selected memos display */}
|
||||
{selectedMemos.length > 0 && (
|
||||
<div className="w-full mb-2 flex flex-wrap gap-1">
|
||||
{selectedMemos.map((memo) => (
|
||||
<Badge key={memo.name} variant="outline" className="max-w-full flex items-center gap-1 p-2">
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-xs text-muted-foreground select-none">{memo.displayTime?.toLocaleString()}</p>
|
||||
<span className="text-sm leading-5 truncate block">{memo.content}</span>
|
||||
</div>
|
||||
<X
|
||||
className="w-3 h-3 cursor-pointer hover:text-destructive flex-shrink-0"
|
||||
onClick={() => setSelectedMemos((memos) => memos.filter((m) => m.name !== memo.name))}
|
||||
/>
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Search and selection interface */}
|
||||
<div className="w-full">
|
||||
<Input
|
||||
|
|
@ -177,7 +121,7 @@ const AddMemoRelationPopover = (props: Props) => {
|
|||
key={memo.name}
|
||||
className="relative flex cursor-pointer items-start gap-2 rounded-sm px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground"
|
||||
onClick={() => {
|
||||
setSelectedMemos((prev) => [...prev, memo]);
|
||||
addMemoRelations(memo);
|
||||
}}
|
||||
>
|
||||
<div className="w-full flex flex-col justify-start items-start">
|
||||
|
|
@ -191,18 +135,6 @@ const AddMemoRelationPopover = (props: Props) => {
|
|||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-2 w-full flex flex-row justify-end items-center gap-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox id="embed-checkbox" checked={embedded} onCheckedChange={(checked) => setEmbedded(checked === true)} />
|
||||
<label htmlFor="embed-checkbox" className="text-sm">
|
||||
Embed
|
||||
</label>
|
||||
</div>
|
||||
<Button onClick={addMemoRelations} disabled={selectedMemos.length === 0}>
|
||||
{t("common.add")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ const Editor = forwardRef(function Editor(props: Props, ref: React.ForwardedRef<
|
|||
<div className={cn("flex flex-col justify-start items-start relative w-full h-auto max-h-[50vh] bg-inherit", className)}>
|
||||
<textarea
|
||||
className="w-full h-full my-1 text-base resize-none overflow-x-hidden overflow-y-auto bg-transparent outline-none placeholder:opacity-70 whitespace-pre-wrap break-words"
|
||||
rows={2}
|
||||
rows={1}
|
||||
placeholder={placeholder}
|
||||
ref={editorRef}
|
||||
onPaste={onPaste}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue