mirror of
https://github.com/usememos/memos.git
synced 2024-12-25 12:23:09 +03:00
chore: update detail styles (#1964)
This commit is contained in:
parent
49dd90578b
commit
01f4780655
@ -14,6 +14,7 @@
|
||||
"@mui/joy": "^5.0.0-alpha.75",
|
||||
"@reduxjs/toolkit": "^1.8.1",
|
||||
"axios": "^0.27.2",
|
||||
"classnames": "^2.3.2",
|
||||
"copy-to-clipboard": "^3.3.2",
|
||||
"highlight.js": "^11.6.0",
|
||||
"i18next": "^21.9.2",
|
||||
|
@ -1,4 +1,4 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
@ -23,6 +23,9 @@ dependencies:
|
||||
axios:
|
||||
specifier: ^0.27.2
|
||||
version: 0.27.2
|
||||
classnames:
|
||||
specifier: ^2.3.2
|
||||
version: 2.3.2
|
||||
copy-to-clipboard:
|
||||
specifier: ^3.3.2
|
||||
version: 3.3.2
|
||||
@ -1346,6 +1349,10 @@ packages:
|
||||
fsevents: 2.3.2
|
||||
dev: false
|
||||
|
||||
/classnames@2.3.2:
|
||||
resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==}
|
||||
dev: false
|
||||
|
||||
/clsx@1.2.1:
|
||||
resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -1,7 +1,8 @@
|
||||
import classNames from "classnames";
|
||||
import { useEffect } from "react";
|
||||
import { NavLink, useLocation } from "react-router-dom";
|
||||
import { useTranslate } from "@/utils/i18n";
|
||||
import { useLayoutStore, useUserStore } from "@/store/module";
|
||||
import { useTranslate } from "@/utils/i18n";
|
||||
import { resolution } from "@/utils/layout";
|
||||
import Icon from "./Icon";
|
||||
import UserBanner from "./UserBanner";
|
||||
@ -53,9 +54,10 @@ const Header = () => {
|
||||
to="/"
|
||||
id="header-home"
|
||||
className={({ isActive }) =>
|
||||
`${
|
||||
isActive && "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600"
|
||||
} px-4 pr-5 py-2 rounded-full border border-transparent flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700`
|
||||
classNames(
|
||||
"px-4 pr-5 py-2 rounded-full border flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700",
|
||||
isActive ? "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" : "border-transparent"
|
||||
)
|
||||
}
|
||||
>
|
||||
<>
|
||||
@ -66,9 +68,10 @@ const Header = () => {
|
||||
to="/review"
|
||||
id="header-review"
|
||||
className={({ isActive }) =>
|
||||
`${
|
||||
isActive && "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600"
|
||||
} px-4 pr-5 py-2 rounded-full border border-transparent flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700`
|
||||
classNames(
|
||||
"px-4 pr-5 py-2 rounded-full border flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700",
|
||||
isActive ? "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" : "border-transparent"
|
||||
)
|
||||
}
|
||||
>
|
||||
<>
|
||||
@ -79,9 +82,10 @@ const Header = () => {
|
||||
to="/resources"
|
||||
id="header-resources"
|
||||
className={({ isActive }) =>
|
||||
`${
|
||||
isActive && "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600"
|
||||
} px-4 pr-5 py-2 rounded-full border border-transparent flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700`
|
||||
classNames(
|
||||
"px-4 pr-5 py-2 rounded-full border flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700",
|
||||
isActive ? "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" : "border-transparent"
|
||||
)
|
||||
}
|
||||
>
|
||||
<>
|
||||
@ -94,9 +98,10 @@ const Header = () => {
|
||||
to="/explore"
|
||||
id="header-explore"
|
||||
className={({ isActive }) =>
|
||||
`${
|
||||
isActive && "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600"
|
||||
} px-4 pr-5 py-2 rounded-full border border-transparent flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700`
|
||||
classNames(
|
||||
"px-4 pr-5 py-2 rounded-full border flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700",
|
||||
isActive ? "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" : "border-transparent"
|
||||
)
|
||||
}
|
||||
>
|
||||
<>
|
||||
@ -110,9 +115,10 @@ const Header = () => {
|
||||
to="/memo-chat"
|
||||
id="header-memo-chat"
|
||||
className={({ isActive }) =>
|
||||
`${
|
||||
isActive && "bg-white dark:bg-zinc-700 shadow"
|
||||
} px-4 pr-5 py-2 rounded-full flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:shadow dark:hover:bg-zinc-700`
|
||||
classNames(
|
||||
"px-4 pr-5 py-2 rounded-full border flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700",
|
||||
isActive ? "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" : "border-transparent"
|
||||
)
|
||||
}
|
||||
>
|
||||
<>
|
||||
@ -123,9 +129,10 @@ const Header = () => {
|
||||
to="/archived"
|
||||
id="header-archived"
|
||||
className={({ isActive }) =>
|
||||
`${
|
||||
isActive && "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600"
|
||||
} px-4 pr-5 py-2 rounded-full border border-transparent flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700`
|
||||
classNames(
|
||||
"px-4 pr-5 py-2 rounded-full border flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700",
|
||||
isActive ? "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" : "border-transparent"
|
||||
)
|
||||
}
|
||||
>
|
||||
<>
|
||||
@ -136,9 +143,10 @@ const Header = () => {
|
||||
to="/setting"
|
||||
id="header-setting"
|
||||
className={({ isActive }) =>
|
||||
`${
|
||||
isActive && "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600"
|
||||
} px-4 pr-5 py-2 rounded-full border border-transparent flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700`
|
||||
classNames(
|
||||
"px-4 pr-5 py-2 rounded-full border flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700",
|
||||
isActive ? "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" : "border-transparent"
|
||||
)
|
||||
}
|
||||
>
|
||||
<>
|
||||
@ -154,9 +162,10 @@ const Header = () => {
|
||||
to="/auth"
|
||||
id="header-auth"
|
||||
className={({ isActive }) =>
|
||||
`${
|
||||
isActive && "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600"
|
||||
} px-4 pr-5 py-2 rounded-full border border-transparent flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700`
|
||||
classNames(
|
||||
"px-4 pr-5 py-2 rounded-full border flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700",
|
||||
isActive ? "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" : "border-transparent"
|
||||
)
|
||||
}
|
||||
>
|
||||
<>
|
||||
|
@ -2,20 +2,15 @@ import Icon from "@/components/Icon";
|
||||
import Textarea from "@mui/joy/Textarea/Textarea";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
interface MemosChatInputProps {
|
||||
interface Props {
|
||||
question: string;
|
||||
handleQuestionTextareaChange: any;
|
||||
setIsInIME: any;
|
||||
handleKeyDown: any;
|
||||
handleSendQuestionButtonClick: any;
|
||||
}
|
||||
const MemosChatInput = ({
|
||||
question,
|
||||
handleQuestionTextareaChange,
|
||||
setIsInIME,
|
||||
handleKeyDown,
|
||||
handleSendQuestionButtonClick,
|
||||
}: MemosChatInputProps) => {
|
||||
|
||||
const ChatInput = ({ question, handleQuestionTextareaChange, setIsInIME, handleKeyDown, handleSendQuestionButtonClick }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
@ -39,4 +34,4 @@ const MemosChatInput = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default MemosChatInput;
|
||||
export default ChatInput;
|
@ -7,7 +7,7 @@ interface MessageProps {
|
||||
message: Message;
|
||||
}
|
||||
|
||||
const MemosChatMessage = ({ index, message }: MessageProps) => {
|
||||
const ChatMessage = ({ index, message }: MessageProps) => {
|
||||
return (
|
||||
<div key={index} className="w-full flex flex-col justify-start items-start space-y-2">
|
||||
{message.role === "user" ? (
|
||||
@ -28,4 +28,4 @@ const MemosChatMessage = ({ index, message }: MessageProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default MemosChatMessage;
|
||||
export default ChatMessage;
|
@ -1,3 +1,4 @@
|
||||
import { Button } from "@mui/joy";
|
||||
import { isNumber, last, uniq } from "lodash-es";
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { toast } from "react-hot-toast";
|
||||
@ -421,9 +422,9 @@ const MemoEditor = (props: Props) => {
|
||||
<div className="editor-footer-container">
|
||||
<MemoVisibilitySelector value={state.memoVisibility} onChange={handleMemoVisibilityChange} />
|
||||
<div className="buttons-container">
|
||||
<button className="action-btn confirm-btn" disabled={!allowSave} onClick={handleSaveBtnClick}>
|
||||
<Button disabled={!allowSave} onClick={handleSaveBtnClick}>
|
||||
{t("editor.save")}
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -76,7 +76,7 @@ const MemoList = () => {
|
||||
return shouldShow;
|
||||
})
|
||||
: memos
|
||||
).filter((memo) => memo.creatorId === currentUserId);
|
||||
).filter((memo) => memo.creatorId === currentUserId && memo.rowStatus === "NORMAL");
|
||||
|
||||
const pinnedMemos = shownMemos.filter((m) => m.pinned);
|
||||
const unpinnedMemos = shownMemos.filter((m) => !m.pinned);
|
||||
|
@ -326,6 +326,14 @@
|
||||
"and": "And",
|
||||
"or": "Or"
|
||||
},
|
||||
"amount-text": {
|
||||
"memo_one": "MEMO",
|
||||
"memo_other": "MEMOS",
|
||||
"tag_one": "TAG",
|
||||
"tag_other": "TAGS",
|
||||
"day_one": "TAG",
|
||||
"day_other": "TAGE"
|
||||
},
|
||||
"message": {
|
||||
"no-data": "Maybe no data was found, maybe it should be another option.",
|
||||
"memos-ready": "all memos are ready 🎉",
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Button, Divider } from "@mui/joy";
|
||||
import { Button, Divider, Input } from "@mui/joy";
|
||||
import { useEffect, useState } from "react";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { useTranslate } from "@/utils/i18n";
|
||||
@ -131,71 +131,44 @@ const Auth = () => {
|
||||
<div className="flex flex-row justify-center items-center w-full h-full dark:bg-zinc-800">
|
||||
<div className="w-80 max-w-full h-full py-4 flex flex-col justify-start items-center">
|
||||
<div className="w-full py-4 grow flex flex-col justify-center items-center">
|
||||
<div className="flex flex-col justify-start items-start w-full mb-4">
|
||||
<div className="w-full flex flex-row justify-start items-center mb-2">
|
||||
<img className="h-12 w-auto rounded-lg mr-1" src={systemStatus.customizedProfile.logoUrl} alt="" />
|
||||
<p className="text-6xl tracking-wide text-black opacity-80 dark:text-gray-200">{systemStatus.customizedProfile.name}</p>
|
||||
</div>
|
||||
<p className="text-sm text-gray-700 dark:text-gray-300">
|
||||
{systemStatus.customizedProfile.description || t("common.memos-slogan")}
|
||||
</p>
|
||||
<div className="w-full flex flex-col justify-center items-center mb-2">
|
||||
<img className="h-20 w-auto rounded-full shadow mr-1" src={systemStatus.customizedProfile.logoUrl} alt="" />
|
||||
<p className="text-3xl text-black opacity-80 dark:text-gray-200">{systemStatus.customizedProfile.name}</p>
|
||||
</div>
|
||||
<form className="w-full" onSubmit={handleFormSubmit}>
|
||||
<div className={`flex flex-col justify-start items-start w-full ${actionBtnLoadingState.isLoading && "opacity-80"}`}>
|
||||
<div className="flex flex-col justify-start items-start relative w-full text-base mt-2 py-2">
|
||||
<span
|
||||
className={`absolute top-3 left-3 px-1 leading-10 shrink-0 text-base cursor-text text-gray-400 transition-all select-none pointer-events-none ${
|
||||
username ? "!text-sm !top-0 !z-10 !leading-4 bg-white dark:bg-zinc-800 rounded" : ""
|
||||
}`}
|
||||
>
|
||||
{t("common.username")}
|
||||
</span>
|
||||
<input
|
||||
className="input-text w-full py-3 px-3 text-base rounded-lg dark:bg-zinc-800"
|
||||
type="text"
|
||||
value={username}
|
||||
onChange={handleUsernameInputChanged}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col justify-start items-start relative w-full text-base mt-2 py-2">
|
||||
<span
|
||||
className={`absolute top-3 left-3 px-1 leading-10 shrink-0 text-base cursor-text text-gray-400 transition-all select-none pointer-events-none ${
|
||||
password ? "!text-sm !top-0 !z-10 !leading-4 bg-white dark:bg-zinc-800 rounded" : ""
|
||||
}`}
|
||||
>
|
||||
{t("common.password")}
|
||||
</span>
|
||||
<input
|
||||
className="input-text w-full py-3 px-3 text-base rounded-lg dark:bg-zinc-800"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={handlePasswordInputChanged}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<form className="w-full mt-4" onSubmit={handleFormSubmit}>
|
||||
<div className="flex flex-col justify-start items-start w-full gap-4">
|
||||
<Input
|
||||
className="w-full"
|
||||
size="lg"
|
||||
type="text"
|
||||
placeholder={t("common.username")}
|
||||
value={username}
|
||||
onChange={handleUsernameInputChanged}
|
||||
required
|
||||
/>
|
||||
<Input
|
||||
className="w-full"
|
||||
size="lg"
|
||||
type="password"
|
||||
placeholder={t("common.password")}
|
||||
value={password}
|
||||
onChange={handlePasswordInputChanged}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-row justify-end items-center w-full mt-2">
|
||||
<div className="flex flex-row justify-end items-center w-full mt-6">
|
||||
{actionBtnLoadingState.isLoading && <Icon.Loader className="w-4 h-auto mr-2 animate-spin dark:text-gray-300" />}
|
||||
{systemStatus?.allowSignUp && (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
className={`btn-text ${actionBtnLoadingState.isLoading ? "cursor-wait opacity-80" : ""}`}
|
||||
onClick={handleSignUpButtonClick}
|
||||
>
|
||||
<Button variant={"plain"} loading={actionBtnLoadingState.isLoading} onClick={handleSignUpButtonClick}>
|
||||
{t("common.sign-up")}
|
||||
</button>
|
||||
</Button>
|
||||
<span className="mr-2 font-mono text-gray-200">/</span>
|
||||
</>
|
||||
)}
|
||||
<button
|
||||
type="submit"
|
||||
className={`btn-primary ${actionBtnLoadingState.isLoading ? "cursor-wait opacity-80" : ""}`}
|
||||
onClick={handleSignInButtonClick}
|
||||
>
|
||||
<Button type="submit" loading={actionBtnLoadingState.isLoading} onClick={handleSignInButtonClick}>
|
||||
{t("common.sign-in")}
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
{identityProviderList.length > 0 && (
|
||||
|
@ -11,19 +11,13 @@ import Memo from "@/components/Memo";
|
||||
import MobileHeader from "@/components/MobileHeader";
|
||||
import Empty from "@/components/Empty";
|
||||
|
||||
interface State {
|
||||
memos: Memo[];
|
||||
}
|
||||
|
||||
const Explore = () => {
|
||||
const t = useTranslate();
|
||||
const location = useLocation();
|
||||
const filterStore = useFilterStore();
|
||||
const memoStore = useMemoStore();
|
||||
const filter = filterStore.state;
|
||||
const [state, setState] = useState<State>({
|
||||
memos: [],
|
||||
});
|
||||
const memos = memoStore.state.memos;
|
||||
const [isComplete, setIsComplete] = useState<boolean>(false);
|
||||
const loadingState = useLoading();
|
||||
|
||||
@ -32,9 +26,6 @@ const Explore = () => {
|
||||
if (memos.length < DEFAULT_MEMO_LIMIT) {
|
||||
setIsComplete(true);
|
||||
}
|
||||
setState({
|
||||
memos,
|
||||
});
|
||||
loadingState.setFinish();
|
||||
});
|
||||
}, [location]);
|
||||
@ -43,7 +34,7 @@ const Explore = () => {
|
||||
const showMemoFilter = Boolean(tagQuery || textQuery);
|
||||
|
||||
const shownMemos = showMemoFilter
|
||||
? state.memos.filter((memo) => {
|
||||
? memos.filter((memo) => {
|
||||
let shouldShow = true;
|
||||
|
||||
if (tagQuery) {
|
||||
@ -64,21 +55,17 @@ const Explore = () => {
|
||||
}
|
||||
return shouldShow;
|
||||
})
|
||||
: state.memos;
|
||||
|
||||
const sortedMemos = shownMemos.filter((m) => m.rowStatus === "NORMAL");
|
||||
: memos;
|
||||
|
||||
const sortedMemos = shownMemos.filter((m) => m.rowStatus === "NORMAL" && m.visibility !== "PRIVATE");
|
||||
const handleFetchMoreClick = async () => {
|
||||
try {
|
||||
const fetchedMemos = await memoStore.fetchAllMemos(DEFAULT_MEMO_LIMIT, state.memos.length);
|
||||
const fetchedMemos = await memoStore.fetchAllMemos(DEFAULT_MEMO_LIMIT, memos.length);
|
||||
if (fetchedMemos.length < DEFAULT_MEMO_LIMIT) {
|
||||
setIsComplete(true);
|
||||
} else {
|
||||
setIsComplete(false);
|
||||
}
|
||||
setState({
|
||||
memos: state.memos.concat(fetchedMemos),
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
toast.error(error.response.data.message);
|
||||
@ -95,7 +82,7 @@ const Explore = () => {
|
||||
return <Memo key={`${memo.id}-${memo.displayTs}`} memo={memo} showCreator />;
|
||||
})}
|
||||
{isComplete ? (
|
||||
state.memos.length === 0 && (
|
||||
memos.length === 0 && (
|
||||
<div className="w-full mt-16 mb-8 flex flex-col justify-center items-center italic">
|
||||
<Empty />
|
||||
<p className="mt-4 text-gray-600 dark:text-gray-400">{t("message.no-data")}</p>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Button, Stack } from "@mui/joy";
|
||||
import { head } from "lodash-es";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@ -9,27 +10,23 @@ import { Conversation, useConversationStore } from "@/store/zustand/conversation
|
||||
import Icon from "@/components/Icon";
|
||||
import { generateUUID } from "@/utils/uuid";
|
||||
import MobileHeader from "@/components/MobileHeader";
|
||||
import MemosChatMessage from "@/components/MemosChat/MemosChatMessage";
|
||||
import MemosChatInput from "@/components/MemosChat/MemosChatInput";
|
||||
import head from "lodash-es/head";
|
||||
import ConversationTab from "@/components/MemosChat/ConversationTab";
|
||||
import ChatMessage from "@/components/MemoChat/ChatMessage";
|
||||
import ChatInput from "@/components/MemoChat/ChatInput";
|
||||
import ConversationTab from "@/components/MemoChat/ConversationTab";
|
||||
import Empty from "@/components/Empty";
|
||||
|
||||
const MemosChat = () => {
|
||||
const MemoChat = () => {
|
||||
const { t } = useTranslation();
|
||||
const fetchingState = useLoading(false);
|
||||
const [isEnabled, setIsEnabled] = useState<boolean>(true);
|
||||
const [isInIME, setIsInIME] = useState(false);
|
||||
const [question, setQuestion] = useState<string>("");
|
||||
|
||||
const conversationStore = useConversationStore();
|
||||
const conversationList = conversationStore.conversationList;
|
||||
|
||||
const [selectedConversationId, setSelectedConversationId] = useState<string>(head(conversationList)?.messageStorageId || "");
|
||||
const messageStore = useMessageStore(selectedConversationId)();
|
||||
const messageList = messageStore.messageList;
|
||||
|
||||
// the state didn't show in component, just for trigger re-render
|
||||
// The state didn't show in component, just for trigger re-render
|
||||
const [message, setMessage] = useState<string>("");
|
||||
|
||||
useEffect(() => {
|
||||
@ -170,7 +167,7 @@ const MemosChat = () => {
|
||||
</div>
|
||||
)}
|
||||
{messageList.map((message, index) => (
|
||||
<MemosChatMessage key={index} message={message} index={index} />
|
||||
<ChatMessage key={index} message={message} index={index} />
|
||||
))}
|
||||
</Stack>
|
||||
{fetchingState.isLoading && (
|
||||
@ -185,7 +182,7 @@ const MemosChat = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<MemosChatInput
|
||||
<ChatInput
|
||||
question={question}
|
||||
handleQuestionTextareaChange={handleQuestionTextareaChange}
|
||||
setIsInIME={setIsInIME}
|
||||
@ -198,4 +195,4 @@ const MemosChat = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default MemosChat;
|
||||
export default MemoChat;
|
@ -1,40 +1,28 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { useTranslate } from "@/utils/i18n";
|
||||
import { Link, useLocation, useParams } from "react-router-dom";
|
||||
import { UNKNOWN_ID } from "@/helpers/consts";
|
||||
import { useGlobalStore, useMemoStore } from "@/store/module";
|
||||
import useLoading from "@/hooks/useLoading";
|
||||
import Icon from "@/components/Icon";
|
||||
import Memo from "@/components/Memo";
|
||||
|
||||
interface State {
|
||||
memo: Memo;
|
||||
}
|
||||
|
||||
const MemoDetail = () => {
|
||||
const t = useTranslate();
|
||||
const params = useParams();
|
||||
const location = useLocation();
|
||||
const globalStore = useGlobalStore();
|
||||
const memoStore = useMemoStore();
|
||||
const [state, setState] = useState<State>({
|
||||
memo: {
|
||||
id: UNKNOWN_ID,
|
||||
} as Memo,
|
||||
});
|
||||
const loadingState = useLoading();
|
||||
const customizedProfile = globalStore.state.systemStatus.customizedProfile;
|
||||
const memoId = Number(params.memoId);
|
||||
const memo = memoStore.state.memos.find((memo) => memo.id === memoId);
|
||||
|
||||
useEffect(() => {
|
||||
const memoId = Number(params.memoId);
|
||||
if (memoId && !isNaN(memoId)) {
|
||||
memoStore
|
||||
.fetchMemoById(memoId)
|
||||
.then((memo) => {
|
||||
setState({
|
||||
memo,
|
||||
});
|
||||
.then(() => {
|
||||
loadingState.setFinish();
|
||||
})
|
||||
.catch((error) => {
|
||||
@ -53,21 +41,26 @@ const MemoDetail = () => {
|
||||
<p className="detail-name text-4xl tracking-wide text-black dark:text-white">{customizedProfile.name}</p>
|
||||
</div>
|
||||
</div>
|
||||
{!loadingState.isLoading && (
|
||||
<>
|
||||
<main className="relative flex-grow max-w-2xl w-full min-h-full flex flex-col justify-start items-start px-4">
|
||||
<Memo memo={state.memo} showCreator showRelatedMemos />
|
||||
</main>
|
||||
<div className="mt-4 w-full flex flex-row justify-center items-center gap-2">
|
||||
<Link
|
||||
to="/"
|
||||
className="flex flex-row justify-center items-center text-gray-600 dark:text-gray-300 text-sm px-3 hover:opacity-80 hover:underline"
|
||||
>
|
||||
<Icon.Home className="w-4 h-auto mr-1 -mt-0.5" /> {t("router.back-to-home")}
|
||||
</Link>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{!loadingState.isLoading &&
|
||||
(memo ? (
|
||||
<>
|
||||
<main className="relative flex-grow max-w-2xl w-full min-h-full flex flex-col justify-start items-start px-4">
|
||||
<Memo memo={memo} showCreator showRelatedMemos />
|
||||
</main>
|
||||
<div className="mt-4 w-full flex flex-row justify-center items-center gap-2">
|
||||
<Link
|
||||
to="/"
|
||||
className="flex flex-row justify-center items-center text-gray-600 dark:text-gray-300 text-sm px-3 hover:opacity-80 hover:underline"
|
||||
>
|
||||
<Icon.Home className="w-4 h-auto mr-1 -mt-0.5" /> {t("router.back-to-home")}
|
||||
</Link>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p>Not found</p>
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
@ -16,7 +16,7 @@ const Home = lazy(() => import("@/pages/Home"));
|
||||
const MemoDetail = lazy(() => import("@/pages/MemoDetail"));
|
||||
const EmbedMemo = lazy(() => import("@/pages/EmbedMemo"));
|
||||
const NotFound = lazy(() => import("@/pages/NotFound"));
|
||||
const MemosChat = lazy(() => import("@/pages/MemosChat"));
|
||||
const MemoChat = lazy(() => import("@/pages/MemoChat"));
|
||||
|
||||
const initialGlobalStateLoader = (() => {
|
||||
let done = false;
|
||||
@ -150,7 +150,7 @@ const router = createBrowserRouter([
|
||||
},
|
||||
{
|
||||
path: "memo-chat",
|
||||
element: <MemosChat />,
|
||||
element: <MemoChat />,
|
||||
loader: async () => {
|
||||
await initialGlobalStateLoader();
|
||||
|
||||
|
@ -23,6 +23,7 @@ export const useMemoStore = () => {
|
||||
const fetchMemoById = async (memoId: MemoId) => {
|
||||
const { data } = await api.getMemoById(memoId);
|
||||
const memo = convertResponseModelMemo(data);
|
||||
store.dispatch(upsertMemos([memo]));
|
||||
|
||||
return memo;
|
||||
};
|
||||
@ -62,6 +63,7 @@ export const useMemoStore = () => {
|
||||
|
||||
const { data } = await api.getAllMemos(memoFind);
|
||||
const fetchedMemos = data.map((m) => convertResponseModelMemo(m));
|
||||
store.dispatch(upsertMemos(fetchedMemos));
|
||||
|
||||
for (const m of fetchedMemos) {
|
||||
memoCacheStore.setMemoCache(m);
|
||||
|
Loading…
Reference in New Issue
Block a user