mirror of
https://github.com/usememos/memos.git
synced 2025-06-05 22:09:59 +02:00
chore: tweak memo detail page
This commit is contained in:
@ -1,18 +1,21 @@
|
|||||||
import { IconButton } from "@mui/joy";
|
import { IconButton } from "@mui/joy";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useTagStore } from "@/store/v1";
|
import { useTagStore } from "@/store/v1";
|
||||||
import { MemoRelation } from "@/types/proto/api/v1/memo_relation_service";
|
import MemoEditor, { Props as MemoEditorProps } from ".";
|
||||||
import MemoEditor from ".";
|
|
||||||
import { generateDialog } from "../Dialog";
|
import { generateDialog } from "../Dialog";
|
||||||
import Icon from "../Icon";
|
import Icon from "../Icon";
|
||||||
|
|
||||||
interface Props extends DialogProps {
|
interface Props extends DialogProps, MemoEditorProps {}
|
||||||
memoName?: string;
|
|
||||||
cacheKey?: string;
|
|
||||||
relationList?: MemoRelation[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const MemoEditorDialog: React.FC<Props> = ({ memoName: memo, cacheKey, relationList, destroy }: Props) => {
|
const MemoEditorDialog: React.FC<Props> = ({
|
||||||
|
memoName: memo,
|
||||||
|
parentMemoName,
|
||||||
|
placeholder,
|
||||||
|
cacheKey,
|
||||||
|
relationList,
|
||||||
|
onConfirm,
|
||||||
|
destroy,
|
||||||
|
}: Props) => {
|
||||||
const tagStore = useTagStore();
|
const tagStore = useTagStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -23,6 +26,13 @@ const MemoEditorDialog: React.FC<Props> = ({ memoName: memo, cacheKey, relationL
|
|||||||
destroy();
|
destroy();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleConfirm = (memoName: string) => {
|
||||||
|
handleCloseBtnClick();
|
||||||
|
if (onConfirm) {
|
||||||
|
onConfirm(memoName);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="w-full flex flex-row justify-between items-center mb-2">
|
<div className="w-full flex flex-row justify-between items-center mb-2">
|
||||||
@ -39,8 +49,10 @@ const MemoEditorDialog: React.FC<Props> = ({ memoName: memo, cacheKey, relationL
|
|||||||
className="border-none !p-0 -mb-2"
|
className="border-none !p-0 -mb-2"
|
||||||
cacheKey={`memo-editor-${cacheKey || memo}`}
|
cacheKey={`memo-editor-${cacheKey || memo}`}
|
||||||
memoName={memo}
|
memoName={memo}
|
||||||
|
parentMemoName={parentMemoName}
|
||||||
|
placeholder={placeholder}
|
||||||
relationList={relationList}
|
relationList={relationList}
|
||||||
onConfirm={handleCloseBtnClick}
|
onConfirm={handleConfirm}
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -48,7 +60,7 @@ const MemoEditorDialog: React.FC<Props> = ({ memoName: memo, cacheKey, relationL
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function showMemoEditorDialog(props: Pick<Props, "memoName" | "cacheKey" | "relationList"> = {}): void {
|
export default function showMemoEditorDialog(props: Partial<Props> = {}): void {
|
||||||
generateDialog(
|
generateDialog(
|
||||||
{
|
{
|
||||||
className: "memo-editor-dialog",
|
className: "memo-editor-dialog",
|
||||||
|
@ -28,7 +28,7 @@ import ResourceListView from "./ResourceListView";
|
|||||||
import { handleEditorKeydownWithMarkdownShortcuts, hyperlinkHighlightedText } from "./handlers";
|
import { handleEditorKeydownWithMarkdownShortcuts, hyperlinkHighlightedText } from "./handlers";
|
||||||
import { MemoEditorContext } from "./types";
|
import { MemoEditorContext } from "./types";
|
||||||
|
|
||||||
interface Props {
|
export interface Props {
|
||||||
className?: string;
|
className?: string;
|
||||||
cacheKey?: string;
|
cacheKey?: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
.dialog-wrapper {
|
.dialog-wrapper {
|
||||||
@apply fixed top-0 left-0 flex flex-col justify-start items-center w-full h-full pt-16 pb-8 px-4 z-2000 overflow-x-hidden overflow-y-scroll bg-transparent transition-all hide-scrollbar bg-black bg-opacity-60;
|
@apply fixed top-0 left-0 flex flex-col justify-start items-center w-full h-full pt-16 pb-8 px-4 z-1000 overflow-x-hidden overflow-y-scroll bg-transparent transition-all hide-scrollbar bg-black bg-opacity-60;
|
||||||
|
|
||||||
> .dialog-container {
|
> .dialog-container {
|
||||||
@apply max-w-full shadow flex flex-col justify-start items-start bg-white dark:bg-zinc-800 dark:text-gray-300 p-4 rounded-lg;
|
@apply max-w-full shadow flex flex-col justify-start items-start bg-white dark:bg-zinc-800 dark:text-gray-300 p-4 rounded-lg;
|
||||||
|
@ -96,8 +96,8 @@
|
|||||||
"memo": {
|
"memo": {
|
||||||
"archived-at": "Archived at",
|
"archived-at": "Archived at",
|
||||||
"comment": {
|
"comment": {
|
||||||
"no-comment": "No comment",
|
"self": "Comments",
|
||||||
"self": "Comments"
|
"write-a-comment": "Write a comment"
|
||||||
},
|
},
|
||||||
"copy-link": "Copy Link",
|
"copy-link": "Copy Link",
|
||||||
"count-memos-in-date": "{{count}} memos in {{date}}",
|
"count-memos-in-date": "{{count}} memos in {{date}}",
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
|
import { Button } from "@mui/joy";
|
||||||
import { ClientError } from "nice-grpc-web";
|
import { ClientError } from "nice-grpc-web";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
import { Link, useParams } from "react-router-dom";
|
import { Link, useParams } from "react-router-dom";
|
||||||
import Icon from "@/components/Icon";
|
import Icon from "@/components/Icon";
|
||||||
import MemoEditor from "@/components/MemoEditor";
|
import showMemoEditorDialog from "@/components/MemoEditor/MemoEditorDialog";
|
||||||
import MemoView from "@/components/MemoView";
|
import MemoView from "@/components/MemoView";
|
||||||
import MobileHeader from "@/components/MobileHeader";
|
import MobileHeader from "@/components/MobileHeader";
|
||||||
import useCurrentUser from "@/hooks/useCurrentUser";
|
import useCurrentUser from "@/hooks/useCurrentUser";
|
||||||
@ -60,6 +61,14 @@ const MemoDetail = () => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleShowCommentEditor = () => {
|
||||||
|
showMemoEditorDialog({
|
||||||
|
placeholder: t("editor.add-your-comment-here"),
|
||||||
|
parentMemoName: memo.name,
|
||||||
|
onConfirm: handleCommentCreated,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const handleCommentCreated = async (memoCommentName: string) => {
|
const handleCommentCreated = async (memoCommentName: string) => {
|
||||||
await memoStore.getOrFetchMemoByName(memoCommentName);
|
await memoStore.getOrFetchMemoByName(memoCommentName);
|
||||||
await memoStore.getOrFetchMemoByName(memo.name, { skipCache: true });
|
await memoStore.getOrFetchMemoByName(memo.name, { skipCache: true });
|
||||||
@ -96,33 +105,35 @@ const MemoDetail = () => {
|
|||||||
</h2>
|
</h2>
|
||||||
<div className="relative mx-auto flex-grow w-full min-h-full flex flex-col justify-start items-start gap-y-1">
|
<div className="relative mx-auto flex-grow w-full min-h-full flex flex-col justify-start items-start gap-y-1">
|
||||||
{comments.length === 0 ? (
|
{comments.length === 0 ? (
|
||||||
<div className="w-full flex flex-col justify-center items-center py-6 mb-2">
|
currentUser && (
|
||||||
<Icon.MessageCircle strokeWidth={1} className="w-8 h-auto text-gray-400" />
|
<div className="w-full flex flex-row justify-center items-center py-6">
|
||||||
<p className="text-gray-400 italic text-sm">{t("memo.comment.no-comment")}</p>
|
<Button
|
||||||
|
variant="plain"
|
||||||
|
color="neutral"
|
||||||
|
startDecorator={<Icon.MessageCircle className="w-5 h-auto text-gray-400" />}
|
||||||
|
onClick={handleShowCommentEditor}
|
||||||
|
>
|
||||||
|
<span className="">{t("memo.comment.write-a-comment")}</span>
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="w-full flex flex-row justify-start items-center pl-3 mb-3">
|
<div className="w-full flex flex-row justify-between items-center px-3 mb-2">
|
||||||
|
<div className="flex flex-row justify-start items-center">
|
||||||
<Icon.MessageCircle className="w-5 h-auto text-gray-400 mr-1" />
|
<Icon.MessageCircle className="w-5 h-auto text-gray-400 mr-1" />
|
||||||
<span className="text-gray-400 text-sm">{t("memo.comment.self")}</span>
|
<span className="text-gray-400 text-sm">{t("memo.comment.self")}</span>
|
||||||
<span className="text-gray-400 text-sm ml-0.5">({comments.length})</span>
|
<span className="text-gray-400 text-sm ml-1">({comments.length})</span>
|
||||||
|
</div>
|
||||||
|
<Button variant="plain" color="neutral" onClick={handleShowCommentEditor}>
|
||||||
|
<span className="font-normal">{t("memo.comment.write-a-comment")}</span>
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{comments.map((comment) => (
|
{comments.map((comment) => (
|
||||||
<MemoView key={`${comment.name}-${comment.displayTime}`} memo={comment} showCreator />
|
<MemoView key={`${comment.name}-${comment.displayTime}`} memo={comment} showCreator />
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Only show comment editor when user login */}
|
|
||||||
{currentUser && (
|
|
||||||
<MemoEditor
|
|
||||||
key={memo.name}
|
|
||||||
cacheKey={`comment-editor-${memo.name}`}
|
|
||||||
placeholder={t("editor.add-your-comment-here")}
|
|
||||||
parentMemoName={memo.name}
|
|
||||||
onConfirm={handleCommentCreated}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user