mirror of https://github.com/usememos/memos
feat: use dialog instead of page
parent
2b5ee78397
commit
da1ccabd1e
@ -0,0 +1,45 @@
|
||||
import { useEffect } from "react";
|
||||
import { memoService } from "../services";
|
||||
import { showDialog } from "./Dialog";
|
||||
import MyAccountSection from "./MyAccountSection";
|
||||
import PreferencesSection from "./PreferencesSection";
|
||||
import "../less/setting-dialog.less";
|
||||
|
||||
interface Props extends DialogProps {}
|
||||
|
||||
const SettingDialog: React.FC<Props> = (props: Props) => {
|
||||
const { destroy } = props;
|
||||
|
||||
useEffect(() => {
|
||||
memoService.fetchAllMemos();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="dialog-header-container">
|
||||
<p className="title-text">
|
||||
<span className="icon-text">👤</span>
|
||||
Setting
|
||||
</p>
|
||||
<button className="btn close-btn" onClick={destroy}>
|
||||
<img className="icon-img" src="/icons/close.svg" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="dialog-content-container">
|
||||
<MyAccountSection />
|
||||
<PreferencesSection />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default function showSettingDialog(): void {
|
||||
showDialog(
|
||||
{
|
||||
className: "setting-dialog",
|
||||
useAppContext: true,
|
||||
},
|
||||
SettingDialog,
|
||||
{}
|
||||
);
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
@import "./mixin.less";
|
||||
@import "./memos-header.less";
|
||||
|
||||
.memo-trash-dialog {
|
||||
> .dialog-container {
|
||||
@apply w-128 max-w-full mb-8;
|
||||
|
||||
> .dialog-content-container {
|
||||
.flex(column, flex-start, flex-start);
|
||||
@apply w-full overflow-y-scroll;
|
||||
|
||||
> .tip-text-container {
|
||||
@apply w-full h-32;
|
||||
.flex(column, center, center);
|
||||
}
|
||||
|
||||
> .deleted-memos-container {
|
||||
.flex(column, flex-start, flex-start);
|
||||
@apply w-full;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
@import "./mixin.less";
|
||||
@import "./memos-header.less";
|
||||
|
||||
.memo-trash-wrapper {
|
||||
@apply px-8;
|
||||
.flex(column, flex-start, flex-start);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex-grow: 1;
|
||||
overflow-y: scroll;
|
||||
.hide-scroll-bar();
|
||||
|
||||
> .section-header-container {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
margin-bottom: 0;
|
||||
|
||||
> .title-text {
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
color: @text-black;
|
||||
}
|
||||
}
|
||||
|
||||
> .tip-text-container {
|
||||
width: 100%;
|
||||
height: 128px;
|
||||
.flex(column, center, center);
|
||||
}
|
||||
|
||||
> .deleted-memos-container {
|
||||
.flex(column, flex-start, flex-start);
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
overflow-y: scroll;
|
||||
padding-bottom: 64px;
|
||||
.hide-scroll-bar();
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
@import "./mixin.less";
|
||||
@import "./memos-header.less";
|
||||
|
||||
.setting-dialog {
|
||||
> .dialog-container {
|
||||
@apply w-3/5 max-w-full mb-8;
|
||||
|
||||
> .dialog-content-container {
|
||||
.flex(column, flex-start, flex-start);
|
||||
@apply w-full overflow-y-scroll;
|
||||
.hide-scroll-bar();
|
||||
|
||||
> .section-container {
|
||||
.flex(column, flex-start, flex-start);
|
||||
@apply w-full my-2;
|
||||
|
||||
> .title-text {
|
||||
@apply text-base font-bold mb-2;
|
||||
color: @text-black;
|
||||
}
|
||||
|
||||
> .form-label {
|
||||
.flex(row, flex-start, center);
|
||||
@apply w-full text-sm mb-2;
|
||||
|
||||
> .normal-text {
|
||||
@apply shrink-0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
@import "./mixin.less";
|
||||
@import "./memos-header.less";
|
||||
|
||||
.preference-wrapper {
|
||||
.flex(column, flex-start, flex-start);
|
||||
@apply w-full h-full grow overflow-y-scroll px-8;
|
||||
.hide-scroll-bar();
|
||||
|
||||
> .section-header-container {
|
||||
@apply w-full h-10 mb-0;
|
||||
|
||||
> .title-text {
|
||||
@apply font-bold text-lg;
|
||||
color: @text-black;
|
||||
}
|
||||
}
|
||||
|
||||
> .tip-text-container {
|
||||
.flex(column, center, center);
|
||||
@apply w-full h-32;
|
||||
}
|
||||
|
||||
> .sections-wrapper {
|
||||
.flex(column, flex-start, flex-start);
|
||||
@apply grow w-full overflow-y-scroll pb-16;
|
||||
.hide-scroll-bar();
|
||||
|
||||
> .section-container {
|
||||
.flex(column, flex-start, flex-start);
|
||||
@apply w-full bg-white my-2 mx-0 p-4 pb-2 rounded-lg;
|
||||
|
||||
> .title-text {
|
||||
@apply text-base font-bold mb-2;
|
||||
color: @text-black;
|
||||
}
|
||||
|
||||
> .form-label {
|
||||
.flex(row, flex-start, center);
|
||||
@apply w-full text-sm mb-2;
|
||||
|
||||
> .normal-text {
|
||||
@apply shrink-0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
import { useEffect } from "react";
|
||||
import { memoService } from "../services";
|
||||
import MyAccountSection from "../components/MyAccountSection";
|
||||
import PreferencesSection from "../components/PreferencesSection";
|
||||
import "../less/setting.less";
|
||||
|
||||
interface Props {}
|
||||
|
||||
const Setting: React.FC<Props> = () => {
|
||||
useEffect(() => {
|
||||
memoService.fetchAllMemos();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="preference-wrapper">
|
||||
<div className="section-header-container">
|
||||
<div className="title-text">
|
||||
<span className="normal-text">Settings</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="sections-wrapper">
|
||||
<MyAccountSection />
|
||||
<PreferencesSection />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Setting;
|
@ -1,129 +0,0 @@
|
||||
import { useCallback, useContext, useEffect, useState } from "react";
|
||||
import appContext from "../stores/appContext";
|
||||
import useLoading from "../hooks/useLoading";
|
||||
import { locationService, memoService, shortcutService } from "../services";
|
||||
import { IMAGE_URL_REG, LINK_REG, MEMO_LINK_REG, TAG_REG } from "../helpers/consts";
|
||||
import utils from "../helpers/utils";
|
||||
import { checkShouldShowMemoWithFilters } from "../helpers/filter";
|
||||
import toastHelper from "../components/Toast";
|
||||
import DeletedMemo from "../components/DeletedMemo";
|
||||
import MemoFilter from "../components/MemoFilter";
|
||||
import "../less/memo-trash.less";
|
||||
|
||||
interface Props {}
|
||||
|
||||
const Trash: React.FC<Props> = () => {
|
||||
const {
|
||||
locationState: { query },
|
||||
} = useContext(appContext);
|
||||
const loadingState = useLoading();
|
||||
const [deletedMemos, setDeletedMemos] = useState<Model.Memo[]>([]);
|
||||
|
||||
const { tag: tagQuery, duration, type: memoType, text: textQuery, shortcutId } = query;
|
||||
const queryFilter = shortcutService.getShortcutById(shortcutId);
|
||||
const showMemoFilter = Boolean(tagQuery || (duration && duration.from < duration.to) || memoType || textQuery || queryFilter);
|
||||
|
||||
const shownMemos =
|
||||
showMemoFilter || queryFilter
|
||||
? deletedMemos.filter((memo) => {
|
||||
let shouldShow = true;
|
||||
|
||||
if (queryFilter) {
|
||||
const filters = JSON.parse(queryFilter.payload) as Filter[];
|
||||
if (Array.isArray(filters)) {
|
||||
shouldShow = checkShouldShowMemoWithFilters(memo, filters);
|
||||
}
|
||||
}
|
||||
|
||||
if (tagQuery) {
|
||||
const tagsSet = new Set<string>();
|
||||
for (const t of Array.from(memo.content.match(TAG_REG) ?? [])) {
|
||||
const tag = t.replace(TAG_REG, "$1").trim();
|
||||
const items = tag.split("/");
|
||||
let temp = "";
|
||||
for (const i of items) {
|
||||
temp += i;
|
||||
tagsSet.add(temp);
|
||||
temp += "/";
|
||||
}
|
||||
}
|
||||
if (!tagsSet.has(tagQuery)) {
|
||||
shouldShow = false;
|
||||
}
|
||||
}
|
||||
if (
|
||||
duration &&
|
||||
duration.from < duration.to &&
|
||||
(utils.getTimeStampByDate(memo.createdAt) < duration.from || utils.getTimeStampByDate(memo.createdAt) > duration.to)
|
||||
) {
|
||||
shouldShow = false;
|
||||
}
|
||||
if (memoType) {
|
||||
if (memoType === "NOT_TAGGED" && memo.content.match(TAG_REG) !== null) {
|
||||
shouldShow = false;
|
||||
} else if (memoType === "LINKED" && memo.content.match(LINK_REG) === null) {
|
||||
shouldShow = false;
|
||||
} else if (memoType === "IMAGED" && memo.content.match(IMAGE_URL_REG) === null) {
|
||||
shouldShow = false;
|
||||
} else if (memoType === "CONNECTED" && memo.content.match(MEMO_LINK_REG) === null) {
|
||||
shouldShow = false;
|
||||
}
|
||||
}
|
||||
if (textQuery && !memo.content.includes(textQuery)) {
|
||||
shouldShow = false;
|
||||
}
|
||||
|
||||
return shouldShow;
|
||||
})
|
||||
: deletedMemos;
|
||||
|
||||
useEffect(() => {
|
||||
memoService.fetchAllMemos();
|
||||
memoService
|
||||
.fetchDeletedMemos()
|
||||
.then((result) => {
|
||||
if (result !== false) {
|
||||
setDeletedMemos(result);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
toastHelper.error("Failed to fetch deleted memos: ", error);
|
||||
})
|
||||
.finally(() => {
|
||||
loadingState.setFinish();
|
||||
});
|
||||
locationService.clearQuery();
|
||||
}, []);
|
||||
|
||||
const handleDeletedMemoAction = useCallback((memoId: string) => {
|
||||
setDeletedMemos((deletedMemos) => deletedMemos.filter((memo) => memo.id !== memoId));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="memo-trash-wrapper">
|
||||
<div className="section-header-container">
|
||||
<div className="title-text">
|
||||
<span className="normal-text">Recycle Bin</span>
|
||||
</div>
|
||||
</div>
|
||||
<MemoFilter />
|
||||
{loadingState.isLoading ? (
|
||||
<div className="tip-text-container">
|
||||
<p className="tip-text">fetching data...</p>
|
||||
</div>
|
||||
) : deletedMemos.length === 0 ? (
|
||||
<div className="tip-text-container">
|
||||
<p className="tip-text">Here is No Zettels.</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="deleted-memos-container">
|
||||
{shownMemos.map((memo) => (
|
||||
<DeletedMemo key={`${memo.id}-${memo.updatedAt}`} memo={memo} handleDeletedMemoAction={handleDeletedMemoAction} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Trash;
|
Loading…
Reference in New Issue