mirror of
https://github.com/usememos/memos.git
synced 2025-06-05 22:09:59 +02:00
feat: support updating display time
This commit is contained in:
@ -277,6 +277,17 @@ func (s *APIV1Service) UpdateMemo(ctx context.Context, request *v1pb.UpdateMemoR
|
||||
} else if path == "created_ts" {
|
||||
createdTs := request.Memo.CreateTime.AsTime().Unix()
|
||||
update.CreatedTs = &createdTs
|
||||
} else if path == "display_ts" {
|
||||
displayTs := request.Memo.DisplayTime.AsTime().Unix()
|
||||
memoRelatedSetting, err := s.Store.GetWorkspaceMemoRelatedSetting(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get workspace memo related setting")
|
||||
}
|
||||
if memoRelatedSetting.DisplayWithUpdateTime {
|
||||
update.UpdatedTs = &displayTs
|
||||
} else {
|
||||
update.CreatedTs = &displayTs
|
||||
}
|
||||
} else if path == "pinned" {
|
||||
if _, err := s.Store.UpsertMemoOrganizer(ctx, &store.MemoOrganizer{
|
||||
MemoID: id,
|
||||
|
@ -77,10 +77,8 @@ export function generateDialog<T extends DialogProps>(
|
||||
const cbs: DialogCallback = {
|
||||
destroy: () => {
|
||||
document.body.style.removeProperty("overflow");
|
||||
setTimeout(() => {
|
||||
dialog.unmount();
|
||||
tempDiv.remove();
|
||||
});
|
||||
dialog.unmount();
|
||||
tempDiv.remove();
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -15,7 +15,7 @@ const ExploreSidebar = (props: Props) => {
|
||||
)}
|
||||
>
|
||||
<SearchBar />
|
||||
<TagsSection hideTips={true} />
|
||||
<TagsSection readonly={true} />
|
||||
</aside>
|
||||
);
|
||||
};
|
||||
|
@ -14,7 +14,7 @@ import Icon from "../Icon";
|
||||
import showRenameTagDialog from "../RenameTagDialog";
|
||||
|
||||
interface Props {
|
||||
hideTips?: boolean;
|
||||
readonly?: boolean;
|
||||
}
|
||||
|
||||
const TagsSection = (props: Props) => {
|
||||
@ -62,7 +62,7 @@ const TagsSection = (props: Props) => {
|
||||
<div className="flex flex-col justify-start items-start w-full mt-3 px-1 h-auto shrink-0 flex-nowrap hide-scrollbar">
|
||||
<div className="group flex flex-row justify-start items-center w-full gap-1 mb-1">
|
||||
<span className="text-sm leading-6 font-mono text-gray-400 select-none">{t("common.tags")}</span>
|
||||
{!props.hideTips && (
|
||||
{!props.readonly && (
|
||||
<div className={clsx("group-hover:block", tagAmounts.length > 0 ? "hidden" : "")}>
|
||||
<Tooltip title={"Rebuild"} placement="top">
|
||||
<Icon.RefreshCcw
|
||||
@ -80,7 +80,7 @@ const TagsSection = (props: Props) => {
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
!props.hideTips && (
|
||||
!props.readonly && (
|
||||
<div className="p-2 border border-dashed dark:border-zinc-800 rounded-md flex flex-row justify-start items-start gap-1 text-gray-400 dark:text-gray-500">
|
||||
<Icon.Tags />
|
||||
<p className="mt-0.5 text-sm leading-snug italic">{t("tag.create-tags-guide")}</p>
|
||||
|
@ -3,7 +3,7 @@ interface Props {
|
||||
}
|
||||
|
||||
const Code: React.FC<Props> = ({ content }: Props) => {
|
||||
return <code className="inline break-all px-1 font-mono rounded bg-gray-100 dark:bg-zinc-700">{content}</code>;
|
||||
return <code className="inline break-all px-1 font-mono text-sm rounded opacity-80 bg-gray-100 dark:bg-zinc-700">{content}</code>;
|
||||
};
|
||||
|
||||
export default Code;
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { IconButton } from "@mui/joy";
|
||||
import { useEffect } from "react";
|
||||
import { useTagStore } from "@/store/v1";
|
||||
import clsx from "clsx";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useMemoStore, useTagStore } from "@/store/v1";
|
||||
import { Memo } from "@/types/proto/api/v1/memo_service";
|
||||
import MemoEditor, { Props as MemoEditorProps } from ".";
|
||||
import { generateDialog } from "../Dialog";
|
||||
import Icon from "../Icon";
|
||||
@ -8,7 +10,7 @@ import Icon from "../Icon";
|
||||
interface Props extends DialogProps, MemoEditorProps {}
|
||||
|
||||
const MemoEditorDialog: React.FC<Props> = ({
|
||||
memoName: memo,
|
||||
memoName,
|
||||
parentMemoName,
|
||||
placeholder,
|
||||
cacheKey,
|
||||
@ -17,11 +19,21 @@ const MemoEditorDialog: React.FC<Props> = ({
|
||||
destroy,
|
||||
}: Props) => {
|
||||
const tagStore = useTagStore();
|
||||
const memoStore = useMemoStore();
|
||||
const [displayTime, setDisplayTime] = useState<string | undefined>(memoStore.getMemoByName(memoName || "")?.displayTime?.toISOString());
|
||||
const memoPatchRef = useRef<Partial<Memo>>({
|
||||
displayTime: memoStore.getMemoByName(memoName || "")?.displayTime,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
tagStore.fetchTags(undefined, { skipCache: false });
|
||||
}, []);
|
||||
|
||||
const updateDisplayTime = (displayTime: string) => {
|
||||
setDisplayTime(displayTime);
|
||||
memoPatchRef.current.displayTime = new Date(displayTime);
|
||||
};
|
||||
|
||||
const handleCloseBtnClick = () => {
|
||||
destroy();
|
||||
};
|
||||
@ -35,10 +47,25 @@ const MemoEditorDialog: React.FC<Props> = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-full flex flex-row justify-between items-center mb-2">
|
||||
<div className="flex flex-row justify-start items-center">
|
||||
<img className="w-6 h-auto rounded-full shadow" src={"/full-logo.webp"} alt="" />
|
||||
<p className="ml-1 text-lg opacity-80 dark:text-gray-300">Memos</p>
|
||||
<div className="w-full flex flex-row justify-between items-center">
|
||||
<div className={clsx("flex flex-row justify-start items-center", !displayTime && "mb-2")}>
|
||||
{displayTime ? (
|
||||
<div className="relative">
|
||||
<span className="cursor-pointer text-gray-500 dark:text-gray-400">{new Date(displayTime).toLocaleString()}</span>
|
||||
<input
|
||||
className="inset-0 absolute z-1 opacity-0"
|
||||
type="datetime-local"
|
||||
value={displayTime}
|
||||
onFocus={(e: any) => e.target.showPicker()}
|
||||
onChange={(e) => updateDisplayTime(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<img className="w-6 h-auto rounded-full shadow" src={"/full-logo.webp"} alt="" />
|
||||
<p className="ml-1 text-lg opacity-80 dark:text-gray-300">Memos</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<IconButton size="sm" onClick={handleCloseBtnClick}>
|
||||
<Icon.X className="w-5 h-auto" />
|
||||
@ -47,11 +74,12 @@ const MemoEditorDialog: React.FC<Props> = ({
|
||||
<div className="flex flex-col justify-start items-start max-w-full w-[36rem]">
|
||||
<MemoEditor
|
||||
className="border-none !p-0 -mb-2"
|
||||
cacheKey={`memo-editor-${cacheKey || memo}`}
|
||||
memoName={memo}
|
||||
cacheKey={`memo-editor-${cacheKey || memoName}`}
|
||||
memoName={memoName}
|
||||
parentMemoName={parentMemoName}
|
||||
placeholder={placeholder}
|
||||
relationList={relationList}
|
||||
memoPatchRef={memoPatchRef}
|
||||
onConfirm={handleConfirm}
|
||||
autoFocus
|
||||
/>
|
||||
|
@ -9,7 +9,7 @@ import { isValidUrl } from "@/helpers/utils";
|
||||
import useCurrentUser from "@/hooks/useCurrentUser";
|
||||
import { useMemoStore, useResourceStore, useUserStore, useWorkspaceSettingStore } from "@/store/v1";
|
||||
import { MemoRelation, MemoRelation_Type } from "@/types/proto/api/v1/memo_relation_service";
|
||||
import { Visibility } from "@/types/proto/api/v1/memo_service";
|
||||
import { Memo, Visibility } from "@/types/proto/api/v1/memo_service";
|
||||
import { Resource } from "@/types/proto/api/v1/resource_service";
|
||||
import { UserSetting } from "@/types/proto/api/v1/user_service";
|
||||
import { WorkspaceMemoRelatedSetting } from "@/types/proto/api/v1/workspace_setting_service";
|
||||
@ -36,8 +36,8 @@ export interface Props {
|
||||
parentMemoName?: string;
|
||||
relationList?: MemoRelation[];
|
||||
autoFocus?: boolean;
|
||||
memoPatchRef?: React.MutableRefObject<Partial<Memo>>;
|
||||
onConfirm?: (memoName: string) => void;
|
||||
onEditPrevious?: () => void;
|
||||
}
|
||||
|
||||
interface State {
|
||||
@ -159,12 +159,6 @@ const MemoEditor = (props: Props) => {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!!props.onEditPrevious && event.key === "ArrowDown" && !state.isComposing && editorRef.current.getContent() === "") {
|
||||
event.preventDefault();
|
||||
props.onEditPrevious();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const handleMemoVisibilityChange = (visibility: Visibility) => {
|
||||
@ -293,13 +287,18 @@ const MemoEditor = (props: Props) => {
|
||||
if (memoName) {
|
||||
const prevMemo = await memoStore.getOrFetchMemoByName(memoName);
|
||||
if (prevMemo) {
|
||||
const updateMask = ["content", "visibility"];
|
||||
if (props.memoPatchRef?.current?.displayTime) {
|
||||
updateMask.push("display_ts");
|
||||
}
|
||||
const memo = await memoStore.updateMemo(
|
||||
{
|
||||
name: prevMemo.name,
|
||||
content,
|
||||
visibility: state.memoVisibility,
|
||||
...props.memoPatchRef?.current,
|
||||
},
|
||||
["content", "visibility"],
|
||||
updateMask,
|
||||
);
|
||||
await memoServiceClient.setMemoResources({
|
||||
name: memo.name,
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { Button } from "@mui/joy";
|
||||
import clsx from "clsx";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import Empty from "@/components/Empty";
|
||||
import { HomeSidebar, HomeSidebarDrawer } from "@/components/HomeSidebar";
|
||||
import Icon from "@/components/Icon";
|
||||
import MemoEditor from "@/components/MemoEditor";
|
||||
import showMemoEditorDialog from "@/components/MemoEditor/MemoEditorDialog";
|
||||
import MemoFilter from "@/components/MemoFilter";
|
||||
import MemoView from "@/components/MemoView";
|
||||
import MobileHeader from "@/components/MobileHeader";
|
||||
@ -59,14 +58,6 @@ const Home = () => {
|
||||
setNextPageToken(response.nextPageToken);
|
||||
};
|
||||
|
||||
const handleEditPrevious = useCallback(() => {
|
||||
const lastMemo = memoList.value[memoList.value.length - 1];
|
||||
showMemoEditorDialog({
|
||||
memoName: lastMemo.name,
|
||||
cacheKey: `${lastMemo.name}-${lastMemo.displayTime}`,
|
||||
});
|
||||
}, [memoList]);
|
||||
|
||||
return (
|
||||
<section className="@container w-full max-w-5xl min-h-full flex flex-col justify-start items-center sm:pt-3 md:pt-6 pb-8">
|
||||
{!md && (
|
||||
@ -76,7 +67,7 @@ const Home = () => {
|
||||
)}
|
||||
<div className={clsx("w-full flex flex-row justify-start items-start px-4 sm:px-6 gap-4")}>
|
||||
<div className={clsx(md ? "w-[calc(100%-15rem)]" : "w-full")}>
|
||||
<MemoEditor className="mb-2" cacheKey="home-memo-editor" onEditPrevious={handleEditPrevious} />
|
||||
<MemoEditor className="mb-2" cacheKey="home-memo-editor" />
|
||||
<div className="flex flex-col justify-start items-start w-full max-w-full">
|
||||
<MemoFilter className="px-2 pb-2" />
|
||||
{sortedMemos.map((memo) => (
|
||||
|
Reference in New Issue
Block a user