Skip to content

Commit

Permalink
feat: implement inline memo editor
Browse files Browse the repository at this point in the history
  • Loading branch information
boojack committed Jul 17, 2024
1 parent 956f218 commit e2fd792
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 53 deletions.
7 changes: 7 additions & 0 deletions web/src/components/MemoActionMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ interface Props {
memo: Memo;
className?: string;
hiddenActions?: ("edit" | "archive" | "delete" | "share" | "pin")[];
onEdit?: () => void;
}

const MemoActionMenu = (props: Props) => {
Expand Down Expand Up @@ -50,6 +51,12 @@ const MemoActionMenu = (props: Props) => {
};

const handleEditMemoClick = () => {
if (props.onEdit) {
props.onEdit();
return;
}

// TODO: remove me later.
showMemoEditorDialog({
memoName: memo.name,
cacheKey: `${memo.name}-${memo.updateTime}`,
Expand Down
8 changes: 7 additions & 1 deletion web/src/components/MemoEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export interface Props {
autoFocus?: boolean;
memoPatchRef?: React.MutableRefObject<Partial<Memo>>;
onConfirm?: (memoName: string) => void;
onCancel?: () => void;
}

interface State {
Expand Down Expand Up @@ -439,7 +440,12 @@ const MemoEditor = (props: Props) => {
))}
</Select>
</div>
<div className="shrink-0 flex flex-row justify-end items-center">
<div className="shrink-0 flex flex-row justify-end items-center gap-2">
{props.onCancel && (
<Button className="!font-normal" color="neutral" variant="plain" loading={state.isRequesting} onClick={props.onCancel}>
{t("common.cancel")}
</Button>
)}
<Button
className="!font-normal"
disabled={!allowSave}
Expand Down
111 changes: 66 additions & 45 deletions web/src/components/MemoView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { convertVisibilityToString } from "@/utils/memo";
import Icon from "./Icon";
import MemoActionMenu from "./MemoActionMenu";
import MemoContent from "./MemoContent";
import showMemoEditorDialog from "./MemoEditor/MemoEditorDialog";
import MemoEditor from "./MemoEditor";
import MemoReactionistView from "./MemoReactionListView";
import MemoRelationListView from "./MemoRelationListView";
import MemoResourceListView from "./MemoResourceListView";
Expand Down Expand Up @@ -45,6 +45,7 @@ const MemoView: React.FC<Props> = (props: Props) => {
const workspaceMemoRelatedSetting =
workspaceSettingStore.getWorkspaceSettingByKey(WorkspaceSettingKey.MEMO_RELATED).memoRelatedSetting ||
WorkspaceMemoRelatedSetting.fromPartial({});
const [showEditor, setShowEditor] = useState<boolean>(false);
const [creator, setCreator] = useState(userStore.getUserByName(memo.creator));
const memoContainerRef = useRef<HTMLDivElement>(null);
const referencedMemos = memo.relations.filter((relation) => relation.type === MemoRelation_Type.REFERENCE);
Expand Down Expand Up @@ -85,10 +86,7 @@ const MemoView: React.FC<Props> = (props: Props) => {

if (workspaceMemoRelatedSetting.enableDoubleClickEdit) {
e.preventDefault();
showMemoEditorDialog({
memoName: memo.name,
cacheKey: `${memo.name}-${memo.updateTime}`,
});
setShowEditor(true);
}
}, []);

Expand Down Expand Up @@ -137,50 +135,73 @@ const MemoView: React.FC<Props> = (props: Props) => {
</div>
)}
</div>
<div className="flex flex-row justify-end items-center select-none shrink-0 gap-2">
<div className="w-auto invisible group-hover:visible flex flex-row justify-between items-center gap-2">
{props.showVisibility && memo.visibility !== Visibility.PRIVATE && (
<Tooltip title={t(`memo.visibility.${convertVisibilityToString(memo.visibility).toLowerCase()}` as any)} placement="top">
<span className="flex justify-center items-center hover:opacity-70">
<VisibilityIcon visibility={memo.visibility} />
</span>
{!showEditor && (
<div className="flex flex-row justify-end items-center select-none shrink-0 gap-2">
<div className="w-auto invisible group-hover:visible flex flex-row justify-between items-center gap-2">
{props.showVisibility && memo.visibility !== Visibility.PRIVATE && (
<Tooltip title={t(`memo.visibility.${convertVisibilityToString(memo.visibility).toLowerCase()}` as any)} placement="top">
<span className="flex justify-center items-center hover:opacity-70">
<VisibilityIcon visibility={memo.visibility} />
</span>
</Tooltip>
)}
{currentUser && <ReactionSelector className="border-none w-auto h-auto" memo={memo} />}
</div>
{!isInMemoDetailPage && (
<Link
className={clsx(
"flex flex-row justify-start items-center hover:opacity-70",
commentAmount === 0 && "invisible group-hover:visible",
)}
to={`/m/${memo.uid}#comments`}
unstable_viewTransition
>
<Icon.MessageCircleMore className="w-4 h-4 mx-auto text-gray-500 dark:text-gray-400" />
{commentAmount > 0 && <span className="text-xs text-gray-500 dark:text-gray-400">{commentAmount}</span>}
</Link>
)}
{props.showPinned && memo.pinned && (
<Tooltip title={t("common.pinned")} placement="top">
<Icon.Bookmark className="w-4 h-auto text-amber-500" />
</Tooltip>
)}
{currentUser && <ReactionSelector className="border-none w-auto h-auto" memo={memo} />}
{!readonly && (
<MemoActionMenu
className="-ml-1"
memo={memo}
hiddenActions={props.showPinned ? [] : ["pin"]}
onEdit={() => setShowEditor(true)}
/>
)}
</div>
{!isInMemoDetailPage && (
<Link
className={clsx(
"flex flex-row justify-start items-center hover:opacity-70",
commentAmount === 0 && "invisible group-hover:visible",
)}
to={`/m/${memo.uid}#comments`}
unstable_viewTransition
>
<Icon.MessageCircleMore className="w-4 h-4 mx-auto text-gray-500 dark:text-gray-400" />
{commentAmount > 0 && <span className="text-xs text-gray-500 dark:text-gray-400">{commentAmount}</span>}
</Link>
)}
{props.showPinned && memo.pinned && (
<Tooltip title={t("common.pinned")} placement="top">
<Icon.Bookmark className="w-4 h-auto text-amber-500" />
</Tooltip>
)}
{!readonly && <MemoActionMenu className="-ml-1" memo={memo} hiddenActions={props.showPinned ? [] : ["pin"]} />}
</div>
)}
</div>
<MemoContent
key={`${memo.name}-${memo.updateTime}`}
memoName={memo.name}
nodes={memo.nodes}
readonly={readonly}
onClick={handleMemoContentClick}
onDoubleClick={handleMemoContentDoubleClick}
compact={props.compact && workspaceMemoRelatedSetting.enableAutoCompact}
/>
<MemoResourceListView resources={memo.resources} />
<MemoRelationListView memo={memo} relations={referencedMemos} />
<MemoReactionistView memo={memo} reactions={memo.reactions} />

{showEditor ? (
<MemoEditor
autoFocus
className="border-none !p-0 -mb-2"
cacheKey={`inline-memo-editor-${memo.name}`}
memoName={memo.name}
onConfirm={() => setShowEditor(false)}
onCancel={() => setShowEditor(false)}
/>
) : (
<>
<MemoContent
key={`${memo.name}-${memo.updateTime}`}
memoName={memo.name}
nodes={memo.nodes}
readonly={readonly}
onClick={handleMemoContentClick}
onDoubleClick={handleMemoContentDoubleClick}
compact={props.compact && workspaceMemoRelatedSetting.enableAutoCompact}
/>
<MemoResourceListView resources={memo.resources} />
<MemoRelationListView memo={memo} relations={referencedMemos} />
<MemoReactionistView memo={memo} reactions={memo.reactions} />
</>
)}
</div>
);
};
Expand Down
23 changes: 16 additions & 7 deletions web/src/pages/MemoDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { toast } from "react-hot-toast";
import { Link, useParams } from "react-router-dom";
import Icon from "@/components/Icon";
import { MemoDetailSidebar, MemoDetailSidebarDrawer } from "@/components/MemoDetailSidebar";
import showMemoEditorDialog from "@/components/MemoEditor/MemoEditorDialog";
import MemoEditor from "@/components/MemoEditor";
import MemoView from "@/components/MemoView";
import MobileHeader from "@/components/MobileHeader";
import useCurrentUser from "@/hooks/useCurrentUser";
Expand All @@ -27,6 +27,7 @@ const MemoDetail = () => {
const uid = params.uid;
const memo = memoStore.getMemoByUid(uid || "");
const [parentMemo, setParentMemo] = useState<Memo | undefined>(undefined);
const [showCommentEditor, setShowCommentEditor] = useState(false);
const commentRelations =
memo?.relations.filter((relation) => relation.relatedMemo === memo.name && relation.type === MemoRelation_Type.COMMENT) || [];
const comments = commentRelations.map((relation) => memoStore.getMemoByName(relation.memo)).filter((memo) => memo) as any as Memo[];
Expand Down Expand Up @@ -66,17 +67,13 @@ const MemoDetail = () => {
}

const handleShowCommentEditor = () => {
showMemoEditorDialog({
placeholder: t("editor.add-your-comment-here"),
parentMemoName: memo.name,
onConfirm: handleCommentCreated,
cacheKey: `${memo.name}-${memo.updateTime}-comment`,
});
setShowCommentEditor(true);
};

const handleCommentCreated = async (memoCommentName: string) => {
await memoStore.getOrFetchMemoByName(memoCommentName);
await memoStore.getOrFetchMemoByName(memo.name, { skipCache: true });
setShowCommentEditor(false);
};

return (
Expand Down Expand Up @@ -145,6 +142,18 @@ const MemoDetail = () => {
</>
)}
</div>
{showCommentEditor && (
<div className="w-full">
<MemoEditor
cacheKey={`${memo.name}-${memo.updateTime}-comment`}
placeholder={t("editor.add-your-comment-here")}
parentMemoName={memo.name}
autoFocus
onConfirm={handleCommentCreated}
onCancel={() => setShowCommentEditor(false)}
/>
</div>
)}
</div>
</div>
{md && (
Expand Down

0 comments on commit e2fd792

Please sign in to comment.