Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
canifa_note
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Vũ Hoàng Anh
canifa_note
Commits
56ad8ab3
Commit
56ad8ab3
authored
Mar 06, 2025
by
Johnny
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor: view store
parent
2e0467e3
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
107 additions
and
80 deletions
+107
-80
MemoDisplaySettingMenu.tsx
web/src/components/MemoDisplaySettingMenu.tsx
+23
-13
MemoFilters.tsx
web/src/components/MemoFilters.tsx
+12
-41
PagedMemoList.tsx
web/src/components/PagedMemoList/PagedMemoList.tsx
+4
-4
Archived.tsx
web/src/pages/Archived.tsx
+3
-2
Explore.tsx
web/src/pages/Explore.tsx
+4
-3
Home.tsx
web/src/pages/Home.tsx
+4
-4
UserProfile.tsx
web/src/pages/UserProfile.tsx
+6
-5
memoFilter.ts
web/src/store/v1/memoFilter.ts
+0
-7
index.ts
web/src/store/v2/index.ts
+2
-1
view.ts
web/src/store/v2/view.ts
+49
-0
No files found.
web/src/components/MemoDisplaySettingMenu.tsx
View file @
56ad8ab3
import
{
Option
,
Select
,
Switch
}
from
"@mui/joy"
;
import
{
Option
,
Select
}
from
"@mui/joy"
;
import
{
Settings2Icon
}
from
"lucide-react"
;
import
{
Settings2Icon
}
from
"lucide-react"
;
import
{
observer
}
from
"mobx-react-lite"
;
import
{
observer
}
from
"mobx-react-lite"
;
import
{
useMemoFilterStore
}
from
"@/store/v1
"
;
import
{
viewStore
}
from
"@/store/v2
"
;
import
{
cn
}
from
"@/utils"
;
import
{
cn
}
from
"@/utils"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
Popover
,
PopoverContent
,
PopoverTrigger
}
from
"./ui/Popover"
;
import
{
Popover
,
PopoverContent
,
PopoverTrigger
}
from
"./ui/Popover"
;
...
@@ -12,34 +12,44 @@ interface Props {
...
@@ -12,34 +12,44 @@ interface Props {
const
MemoDisplaySettingMenu
=
observer
(({
className
}:
Props
)
=>
{
const
MemoDisplaySettingMenu
=
observer
(({
className
}:
Props
)
=>
{
const
t
=
useTranslate
();
const
t
=
useTranslate
();
const
memoFilterStore
=
useMemoFilterStore
();
const
isApplying
=
viewStore
.
state
.
orderByTimeAsc
!==
false
||
viewStore
.
state
.
layout
!==
"LIST"
;
const
isApplying
=
Boolean
(
memoFilterStore
.
orderByTimeAsc
)
!==
false
||
memoFilterStore
.
masonry
;
return
(
return
(
<
Popover
>
<
Popover
>
<
PopoverTrigger
<
PopoverTrigger
className=
{
cn
(
className
,
isApplying
?
"text-teal-600 bg-teal-
50 dark:text-teal-500 dark:bg-teal-900 rounded-sm
"
:
"opacity-40"
)
}
className=
{
cn
(
className
,
isApplying
?
"text-teal-600 bg-teal-
100 dark:text-teal-500 dark:bg-teal-900 rounded
"
:
"opacity-40"
)
}
>
>
<
Settings2Icon
className=
"w-4 h-auto shrink-0"
/>
<
Settings2Icon
className=
"w-4 h-auto shrink-0"
/>
</
PopoverTrigger
>
</
PopoverTrigger
>
<
PopoverContent
align=
"end"
alignOffset=
{
-
12
}
sideOffset=
{
14
}
>
<
PopoverContent
align=
"end"
alignOffset=
{
-
12
}
sideOffset=
{
14
}
>
<
div
className=
"flex flex-col gap-2"
>
<
div
className=
"flex flex-col gap-2"
>
<
div
className=
"w-full flex flex-row justify-between items-center"
>
<
span
className=
"text-sm shrink-0 mr-3"
>
{
t
(
"memo.order-by"
)
}
</
span
>
<
Select
value=
"displayTime"
>
<
Option
value=
{
"displayTime"
}
>
{
t
(
"memo.display-time"
)
}
</
Option
>
</
Select
>
</
div
>
<
div
className=
"w-full flex flex-row justify-between items-center"
>
<
div
className=
"w-full flex flex-row justify-between items-center"
>
<
span
className=
"text-sm shrink-0 mr-3"
>
{
t
(
"memo.direction"
)
}
</
span
>
<
span
className=
"text-sm shrink-0 mr-3"
>
{
t
(
"memo.direction"
)
}
</
span
>
<
Select
value=
{
memoFilterStore
.
orderByTimeAsc
}
onChange=
{
(
_
,
value
)
=>
memoFilterStore
.
setOrderByTimeAsc
(
Boolean
(
value
))
}
>
<
Select
value=
{
viewStore
.
state
.
orderByTimeAsc
}
onChange=
{
(
_
,
value
)
=>
viewStore
.
state
.
setPartial
({
orderByTimeAsc
:
Boolean
(
value
),
})
}
>
<
Option
value=
{
false
}
>
{
t
(
"memo.direction-desc"
)
}
</
Option
>
<
Option
value=
{
false
}
>
{
t
(
"memo.direction-desc"
)
}
</
Option
>
<
Option
value=
{
true
}
>
{
t
(
"memo.direction-asc"
)
}
</
Option
>
<
Option
value=
{
true
}
>
{
t
(
"memo.direction-asc"
)
}
</
Option
>
</
Select
>
</
Select
>
</
div
>
</
div
>
<
div
className=
"w-full flex flex-row justify-between items-center"
>
<
div
className=
"w-full flex flex-row justify-between items-center"
>
<
span
className=
"text-sm shrink-0 mr-3"
>
{
t
(
"memo.masonry-view"
)
}
</
span
>
<
span
className=
"text-sm shrink-0 mr-3"
>
{
t
(
"memo.masonry-view"
)
}
</
span
>
<
Switch
checked=
{
memoFilterStore
.
masonry
}
onChange=
{
(
event
)
=>
memoFilterStore
.
setMasonry
(
event
.
target
.
checked
)
}
/>
<
Select
value=
{
viewStore
.
state
.
layout
}
onChange=
{
(
_
,
value
)
=>
viewStore
.
state
.
setPartial
({
layout
:
value
as
"LIST"
|
"MASONRY"
,
})
}
>
<
Option
value=
{
"LIST"
}
>
{
"List"
}
</
Option
>
<
Option
value=
{
"MASONRY"
}
>
{
"Masonry"
}
</
Option
>
</
Select
>
</
div
>
</
div
>
</
div
>
</
div
>
</
PopoverContent
>
</
PopoverContent
>
...
...
web/src/components/MemoFilters.tsx
View file @
56ad8ab3
import
{
isEqual
}
from
"lodash-es"
;
import
{
isEqual
}
from
"lodash-es"
;
import
{
CalendarIcon
,
CheckCircleIcon
,
CodeIcon
,
EyeIcon
,
HashIcon
,
LinkIcon
,
SearchIcon
,
XIcon
}
from
"lucide-react"
;
import
{
CalendarIcon
,
CheckCircleIcon
,
CodeIcon
,
EyeIcon
,
HashIcon
,
LinkIcon
,
SearchIcon
,
XIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useRef
}
from
"react"
;
import
{
useEffect
}
from
"react"
;
import
{
useSearchParams
}
from
"react-router-dom"
;
import
{
useSearchParams
}
from
"react-router-dom"
;
import
{
FilterFactor
,
getMemoFilterKey
,
MemoFilter
,
parseFilterQuery
,
stringifyFilters
,
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
FilterFactor
,
getMemoFilterKey
,
MemoFilter
,
stringifyFilters
,
useMemoFilterStore
}
from
"@/store/v1"
;
const
MemoFilters
=
()
=>
{
const
MemoFilters
=
()
=>
{
const
[
searchParams
,
setSearchParams
]
=
useSearchParams
();
const
[
searchParams
,
setSearchParams
]
=
useSearchParams
();
const
memoFilterStore
=
useMemoFilterStore
();
const
memoFilterStore
=
useMemoFilterStore
();
const
filters
=
memoFilterStore
.
filters
;
const
filters
=
memoFilterStore
.
filters
;
const
orderByTimeAsc
=
memoFilterStore
.
orderByTimeAsc
;
const
lastUpdateRef
=
useRef
<
"url"
|
"store"
>
(
"url"
);
// set lastUpdateRef to store when filters or orderByTimeAsc changes
useEffect
(()
=>
{
lastUpdateRef
.
current
=
"store"
;
},
[
filters
,
orderByTimeAsc
]);
// set lastUpdateRef to url when searchParams changes
useEffect
(()
=>
{
lastUpdateRef
.
current
=
"url"
;
},
[
searchParams
]);
const
checkAndSync
=
()
=>
{
const
checkAndSync
=
()
=>
{
const
filtersInURL
=
searchParams
.
get
(
"filter"
)
||
""
;
const
filtersInURL
=
searchParams
.
get
(
"filter"
)
||
""
;
const
orderByTimeAscInURL
=
searchParams
.
get
(
"orderBy"
)
===
"asc"
;
const
storeMatchesURL
=
filtersInURL
===
stringifyFilters
(
filters
);
const
storeMatchesURL
=
filtersInURL
===
stringifyFilters
(
filters
)
&&
orderByTimeAscInURL
===
orderByTimeAsc
;
if
(
!
storeMatchesURL
)
{
if
(
!
storeMatchesURL
)
{
if
(
lastUpdateRef
.
current
===
"url"
)
{
// Sync Store -> URL
// Sync URL -> Store
const
newSearchParams
=
new
URLSearchParams
(
searchParams
);
memoFilterStore
.
setState
({
filters
:
parseFilterQuery
(
filtersInURL
),
orderByTimeAsc
:
orderByTimeAscInURL
,
masonry
:
memoFilterStore
.
masonry
,
});
}
else
if
(
lastUpdateRef
.
current
===
"store"
)
{
// Sync Store -> URL
const
newSearchParams
=
new
URLSearchParams
(
searchParams
);
if
(
orderByTimeAsc
)
{
newSearchParams
.
set
(
"orderBy"
,
"asc"
);
}
else
{
newSearchParams
.
delete
(
"orderBy"
);
}
if
(
filters
.
length
>
0
)
{
if
(
filters
.
length
>
0
)
{
newSearchParams
.
set
(
"filter"
,
stringifyFilters
(
filters
));
newSearchParams
.
set
(
"filter"
,
stringifyFilters
(
filters
));
}
else
{
}
else
{
newSearchParams
.
delete
(
"filter"
);
newSearchParams
.
delete
(
"filter"
);
}
setSearchParams
(
newSearchParams
);
}
}
setSearchParams
(
newSearchParams
);
}
}
};
};
// Watch both URL and store changes
useEffect
(
checkAndSync
,
[
searchParams
,
filters
]);
useEffect
(
checkAndSync
,
[
searchParams
,
filters
,
orderByTimeAsc
]);
const
getFilterDisplayText
=
(
filter
:
MemoFilter
)
=>
{
const
getFilterDisplayText
=
(
filter
:
MemoFilter
)
=>
{
if
(
filter
.
value
)
{
if
(
filter
.
value
)
{
...
...
web/src/components/PagedMemoList/PagedMemoList.tsx
View file @
56ad8ab3
...
@@ -7,7 +7,8 @@ import PullToRefresh from "react-simple-pull-to-refresh";
...
@@ -7,7 +7,8 @@ import PullToRefresh from "react-simple-pull-to-refresh";
import
{
DEFAULT_LIST_MEMOS_PAGE_SIZE
}
from
"@/helpers/consts"
;
import
{
DEFAULT_LIST_MEMOS_PAGE_SIZE
}
from
"@/helpers/consts"
;
import
useResponsiveWidth
from
"@/hooks/useResponsiveWidth"
;
import
useResponsiveWidth
from
"@/hooks/useResponsiveWidth"
;
import
{
Routes
}
from
"@/router"
;
import
{
Routes
}
from
"@/router"
;
import
{
useMemoFilterStore
,
useMemoList
,
useMemoStore
}
from
"@/store/v1"
;
import
{
useMemoList
,
useMemoStore
}
from
"@/store/v1"
;
import
{
viewStore
}
from
"@/store/v2"
;
import
{
Direction
,
State
}
from
"@/types/proto/api/v1/common"
;
import
{
Direction
,
State
}
from
"@/types/proto/api/v1/common"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
...
@@ -36,7 +37,6 @@ const PagedMemoList = observer((props: Props) => {
...
@@ -36,7 +37,6 @@ const PagedMemoList = observer((props: Props) => {
const
{
md
}
=
useResponsiveWidth
();
const
{
md
}
=
useResponsiveWidth
();
const
memoStore
=
useMemoStore
();
const
memoStore
=
useMemoStore
();
const
memoList
=
useMemoList
();
const
memoList
=
useMemoList
();
const
memoFilterStore
=
useMemoFilterStore
();
const
[
state
,
setState
]
=
useState
<
LocalState
>
({
const
[
state
,
setState
]
=
useState
<
LocalState
>
({
isRequesting
:
true
,
// Initial request
isRequesting
:
true
,
// Initial request
nextPageToken
:
""
,
nextPageToken
:
""
,
...
@@ -77,7 +77,7 @@ const PagedMemoList = observer((props: Props) => {
...
@@ -77,7 +77,7 @@ const PagedMemoList = observer((props: Props) => {
memoList=
{
sortedMemoList
}
memoList=
{
sortedMemoList
}
renderer=
{
props
.
renderer
}
renderer=
{
props
.
renderer
}
prefixElement=
{
showMemoEditor
?
<
MemoEditor
className=
"mb-2"
cacheKey=
"home-memo-editor"
/>
:
undefined
}
prefixElement=
{
showMemoEditor
?
<
MemoEditor
className=
"mb-2"
cacheKey=
"home-memo-editor"
/>
:
undefined
}
listMode=
{
!
memoFilterStore
.
masonry
}
listMode=
{
viewStore
.
state
.
layout
===
"LIST"
}
/>
/>
{
state
.
isRequesting
&&
(
{
state
.
isRequesting
&&
(
<
div
className=
"w-full flex flex-row justify-center items-center my-4"
>
<
div
className=
"w-full flex flex-row justify-center items-center my-4"
>
...
@@ -92,7 +92,7 @@ const PagedMemoList = observer((props: Props) => {
...
@@ -92,7 +92,7 @@ const PagedMemoList = observer((props: Props) => {
<
p
className=
"mt-2 text-gray-600 dark:text-gray-400"
>
{
t
(
"message.no-data"
)
}
</
p
>
<
p
className=
"mt-2 text-gray-600 dark:text-gray-400"
>
{
t
(
"message.no-data"
)
}
</
p
>
</
div
>
</
div
>
)
:
(
)
:
(
<
div
className=
"w-full flex flex-row justify-center items-center my-4"
>
<
div
className=
"w-full
opacity-70
flex flex-row justify-center items-center my-4"
>
{
state
.
nextPageToken
&&
(
{
state
.
nextPageToken
&&
(
<
Button
variant=
"plain"
onClick=
{
()
=>
fetchMoreMemos
(
state
.
nextPageToken
)
}
>
<
Button
variant=
"plain"
onClick=
{
()
=>
fetchMoreMemos
(
state
.
nextPageToken
)
}
>
{
t
(
"memo.load-more"
)
}
{
t
(
"memo.load-more"
)
}
...
...
web/src/pages/Archived.tsx
View file @
56ad8ab3
...
@@ -4,6 +4,7 @@ import MemoView from "@/components/MemoView";
...
@@ -4,6 +4,7 @@ import MemoView from "@/components/MemoView";
import
PagedMemoList
from
"@/components/PagedMemoList"
;
import
PagedMemoList
from
"@/components/PagedMemoList"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
viewStore
}
from
"@/store/v2"
;
import
{
Direction
,
State
}
from
"@/types/proto/api/v1/common"
;
import
{
Direction
,
State
}
from
"@/types/proto/api/v1/common"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
...
@@ -38,14 +39,14 @@ const Archived = () => {
...
@@ -38,14 +39,14 @@ const Archived = () => {
memos
memos
.
filter
((
memo
)
=>
memo
.
state
===
State
.
ARCHIVED
)
.
filter
((
memo
)
=>
memo
.
state
===
State
.
ARCHIVED
)
.
sort
((
a
,
b
)
=>
.
sort
((
a
,
b
)
=>
memoFilterStor
e
.
orderByTimeAsc
viewStore
.
stat
e
.
orderByTimeAsc
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
:
dayjs
(
b
.
displayTime
).
unix
()
-
dayjs
(
a
.
displayTime
).
unix
(),
:
dayjs
(
b
.
displayTime
).
unix
()
-
dayjs
(
a
.
displayTime
).
unix
(),
)
)
}
}
owner=
{
user
.
name
}
owner=
{
user
.
name
}
state=
{
State
.
ARCHIVED
}
state=
{
State
.
ARCHIVED
}
direction=
{
memoFilterStor
e
.
orderByTimeAsc
?
Direction
.
ASC
:
Direction
.
DESC
}
direction=
{
viewStore
.
stat
e
.
orderByTimeAsc
?
Direction
.
ASC
:
Direction
.
DESC
}
oldFilter=
{
memoListFilter
}
oldFilter=
{
memoListFilter
}
/>
/>
);
);
...
...
web/src/pages/Explore.tsx
View file @
56ad8ab3
...
@@ -4,6 +4,7 @@ import MemoView from "@/components/MemoView";
...
@@ -4,6 +4,7 @@ import MemoView from "@/components/MemoView";
import
PagedMemoList
from
"@/components/PagedMemoList"
;
import
PagedMemoList
from
"@/components/PagedMemoList"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
viewStore
}
from
"@/store/v2"
;
import
{
Direction
,
State
}
from
"@/types/proto/api/v1/common"
;
import
{
Direction
,
State
}
from
"@/types/proto/api/v1/common"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
...
@@ -41,7 +42,7 @@ const Explore = () => {
...
@@ -41,7 +42,7 @@ const Explore = () => {
conditions
.
push
(
`tag_search == [
${
tagSearch
.
join
(
", "
)}
]`
);
conditions
.
push
(
`tag_search == [
${
tagSearch
.
join
(
", "
)}
]`
);
}
}
return
conditions
.
join
(
" && "
);
return
conditions
.
join
(
" && "
);
},
[
user
,
memoFilterStore
.
filters
,
memoFilterStor
e
.
orderByTimeAsc
]);
},
[
user
,
memoFilterStore
.
filters
,
viewStore
.
stat
e
.
orderByTimeAsc
]);
return
(
return
(
<
PagedMemoList
<
PagedMemoList
...
@@ -50,12 +51,12 @@ const Explore = () => {
...
@@ -50,12 +51,12 @@ const Explore = () => {
memos
memos
.
filter
((
memo
)
=>
memo
.
state
===
State
.
NORMAL
)
.
filter
((
memo
)
=>
memo
.
state
===
State
.
NORMAL
)
.
sort
((
a
,
b
)
=>
.
sort
((
a
,
b
)
=>
memoFilterStor
e
.
orderByTimeAsc
viewStore
.
stat
e
.
orderByTimeAsc
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
:
dayjs
(
b
.
displayTime
).
unix
()
-
dayjs
(
a
.
displayTime
).
unix
(),
:
dayjs
(
b
.
displayTime
).
unix
()
-
dayjs
(
a
.
displayTime
).
unix
(),
)
)
}
}
direction=
{
memoFilterStor
e
.
orderByTimeAsc
?
Direction
.
ASC
:
Direction
.
DESC
}
direction=
{
viewStore
.
stat
e
.
orderByTimeAsc
?
Direction
.
ASC
:
Direction
.
DESC
}
oldFilter=
{
memoListFilter
}
oldFilter=
{
memoListFilter
}
/>
/>
);
);
...
...
web/src/pages/Home.tsx
View file @
56ad8ab3
...
@@ -5,7 +5,7 @@ import MemoView from "@/components/MemoView";
...
@@ -5,7 +5,7 @@ import MemoView from "@/components/MemoView";
import
PagedMemoList
from
"@/components/PagedMemoList"
;
import
PagedMemoList
from
"@/components/PagedMemoList"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
userStore
}
from
"@/store/v2"
;
import
{
viewStore
,
userStore
}
from
"@/store/v2"
;
import
{
Direction
,
State
}
from
"@/types/proto/api/v1/common"
;
import
{
Direction
,
State
}
from
"@/types/proto/api/v1/common"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
...
@@ -44,7 +44,7 @@ const Home = observer(() => {
...
@@ -44,7 +44,7 @@ const Home = observer(() => {
conditions
.
push
(
`tag_search == [
${
tagSearch
.
join
(
", "
)}
]`
);
conditions
.
push
(
`tag_search == [
${
tagSearch
.
join
(
", "
)}
]`
);
}
}
return
conditions
.
join
(
" && "
);
return
conditions
.
join
(
" && "
);
},
[
user
,
memoFilterStore
.
filters
,
memoFilterStor
e
.
orderByTimeAsc
]);
},
[
user
,
memoFilterStore
.
filters
,
viewStore
.
stat
e
.
orderByTimeAsc
]);
return
(
return
(
<
PagedMemoList
<
PagedMemoList
...
@@ -53,14 +53,14 @@ const Home = observer(() => {
...
@@ -53,14 +53,14 @@ const Home = observer(() => {
memos
memos
.
filter
((
memo
)
=>
memo
.
state
===
State
.
NORMAL
)
.
filter
((
memo
)
=>
memo
.
state
===
State
.
NORMAL
)
.
sort
((
a
,
b
)
=>
.
sort
((
a
,
b
)
=>
memoFilterStor
e
.
orderByTimeAsc
viewStore
.
stat
e
.
orderByTimeAsc
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
:
dayjs
(
b
.
displayTime
).
unix
()
-
dayjs
(
a
.
displayTime
).
unix
(),
:
dayjs
(
b
.
displayTime
).
unix
()
-
dayjs
(
a
.
displayTime
).
unix
(),
)
)
.
sort
((
a
,
b
)
=>
Number
(
b
.
pinned
)
-
Number
(
a
.
pinned
))
.
sort
((
a
,
b
)
=>
Number
(
b
.
pinned
)
-
Number
(
a
.
pinned
))
}
}
owner=
{
user
.
name
}
owner=
{
user
.
name
}
direction=
{
memoFilterStor
e
.
orderByTimeAsc
?
Direction
.
ASC
:
Direction
.
DESC
}
direction=
{
viewStore
.
stat
e
.
orderByTimeAsc
?
Direction
.
ASC
:
Direction
.
DESC
}
filter=
{
selectedShortcut
?.
filter
||
""
}
filter=
{
selectedShortcut
?.
filter
||
""
}
oldFilter=
{
memoListFilter
}
oldFilter=
{
memoListFilter
}
/>
/>
...
...
web/src/pages/UserProfile.tsx
View file @
56ad8ab3
...
@@ -2,6 +2,7 @@ import { Button } from "@usememos/mui";
...
@@ -2,6 +2,7 @@ import { Button } from "@usememos/mui";
import
copy
from
"copy-to-clipboard"
;
import
copy
from
"copy-to-clipboard"
;
import
dayjs
from
"dayjs"
;
import
dayjs
from
"dayjs"
;
import
{
ExternalLinkIcon
}
from
"lucide-react"
;
import
{
ExternalLinkIcon
}
from
"lucide-react"
;
import
{
observer
}
from
"mobx-react-lite"
;
import
{
useEffect
,
useMemo
,
useState
}
from
"react"
;
import
{
useEffect
,
useMemo
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
useParams
}
from
"react-router-dom"
;
import
{
useParams
}
from
"react-router-dom"
;
...
@@ -11,13 +12,13 @@ import PagedMemoList from "@/components/PagedMemoList";
...
@@ -11,13 +12,13 @@ import PagedMemoList from "@/components/PagedMemoList";
import
UserAvatar
from
"@/components/UserAvatar"
;
import
UserAvatar
from
"@/components/UserAvatar"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
userStore
}
from
"@/store/v2"
;
import
{
viewStore
,
userStore
}
from
"@/store/v2"
;
import
{
Direction
,
State
}
from
"@/types/proto/api/v1/common"
;
import
{
Direction
,
State
}
from
"@/types/proto/api/v1/common"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
User
}
from
"@/types/proto/api/v1/user_service"
;
import
{
User
}
from
"@/types/proto/api/v1/user_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
const
UserProfile
=
()
=>
{
const
UserProfile
=
observer
(
()
=>
{
const
t
=
useTranslate
();
const
t
=
useTranslate
();
const
params
=
useParams
();
const
params
=
useParams
();
const
loadingState
=
useLoading
();
const
loadingState
=
useLoading
();
...
@@ -107,14 +108,14 @@ const UserProfile = () => {
...
@@ -107,14 +108,14 @@ const UserProfile = () => {
memos
memos
.
filter
((
memo
)
=>
memo
.
state
===
State
.
NORMAL
)
.
filter
((
memo
)
=>
memo
.
state
===
State
.
NORMAL
)
.
sort
((
a
,
b
)
=>
.
sort
((
a
,
b
)
=>
memoFilterStor
e
.
orderByTimeAsc
viewStore
.
stat
e
.
orderByTimeAsc
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
:
dayjs
(
b
.
displayTime
).
unix
()
-
dayjs
(
a
.
displayTime
).
unix
(),
:
dayjs
(
b
.
displayTime
).
unix
()
-
dayjs
(
a
.
displayTime
).
unix
(),
)
)
.
sort
((
a
,
b
)
=>
Number
(
b
.
pinned
)
-
Number
(
a
.
pinned
))
.
sort
((
a
,
b
)
=>
Number
(
b
.
pinned
)
-
Number
(
a
.
pinned
))
}
}
owner=
{
user
.
name
}
owner=
{
user
.
name
}
direction=
{
memoFilterStor
e
.
orderByTimeAsc
?
Direction
.
ASC
:
Direction
.
DESC
}
direction=
{
viewStore
.
stat
e
.
orderByTimeAsc
?
Direction
.
ASC
:
Direction
.
DESC
}
oldFilter=
{
memoListFilter
}
oldFilter=
{
memoListFilter
}
/>
/>
</>
</>
...
@@ -124,6 +125,6 @@ const UserProfile = () => {
...
@@ -124,6 +125,6 @@ const UserProfile = () => {
</
div
>
</
div
>
</
section
>
</
section
>
);
);
};
}
)
;
export
default
UserProfile
;
export
default
UserProfile
;
web/src/store/v1/memoFilter.ts
View file @
56ad8ab3
...
@@ -40,19 +40,14 @@ export const stringifyFilters = (filters: MemoFilter[]): string => {
...
@@ -40,19 +40,14 @@ export const stringifyFilters = (filters: MemoFilter[]): string => {
interface
State
{
interface
State
{
filters
:
MemoFilter
[];
filters
:
MemoFilter
[];
orderByTimeAsc
:
boolean
;
// The id of selected shortcut.
// The id of selected shortcut.
shortcut
?:
string
;
shortcut
?:
string
;
// TODO: Remove this when the masonry view is implemented.
masonry
:
boolean
;
}
}
const
getInitialState
=
():
State
=>
{
const
getInitialState
=
():
State
=>
{
const
searchParams
=
new
URLSearchParams
(
window
.
location
.
search
);
const
searchParams
=
new
URLSearchParams
(
window
.
location
.
search
);
return
{
return
{
filters
:
parseFilterQuery
(
searchParams
.
get
(
"filter"
)),
filters
:
parseFilterQuery
(
searchParams
.
get
(
"filter"
)),
orderByTimeAsc
:
searchParams
.
get
(
"orderBy"
)
===
"asc"
,
masonry
:
false
,
};
};
};
};
...
@@ -63,8 +58,6 @@ export const useMemoFilterStore = create(
...
@@ -63,8 +58,6 @@ export const useMemoFilterStore = create(
getFiltersByFactor
:
(
factor
:
FilterFactor
)
=>
get
().
filters
.
filter
((
f
)
=>
f
.
factor
===
factor
),
getFiltersByFactor
:
(
factor
:
FilterFactor
)
=>
get
().
filters
.
filter
((
f
)
=>
f
.
factor
===
factor
),
addFilter
:
(
filter
:
MemoFilter
)
=>
set
((
state
)
=>
({
filters
:
uniqBy
([...
state
.
filters
,
filter
],
getMemoFilterKey
)
})),
addFilter
:
(
filter
:
MemoFilter
)
=>
set
((
state
)
=>
({
filters
:
uniqBy
([...
state
.
filters
,
filter
],
getMemoFilterKey
)
})),
removeFilter
:
(
filterFn
:
(
f
:
MemoFilter
)
=>
boolean
)
=>
set
((
state
)
=>
({
filters
:
state
.
filters
.
filter
((
f
)
=>
!
filterFn
(
f
))
})),
removeFilter
:
(
filterFn
:
(
f
:
MemoFilter
)
=>
boolean
)
=>
set
((
state
)
=>
({
filters
:
state
.
filters
.
filter
((
f
)
=>
!
filterFn
(
f
))
})),
setOrderByTimeAsc
:
(
orderByTimeAsc
:
boolean
)
=>
set
({
orderByTimeAsc
}),
setShortcut
:
(
shortcut
?:
string
)
=>
set
({
shortcut
}),
setShortcut
:
(
shortcut
?:
string
)
=>
set
({
shortcut
}),
setMasonry
:
(
masonry
:
boolean
)
=>
set
({
masonry
}),
})),
})),
);
);
web/src/store/v2/index.ts
View file @
56ad8ab3
import
userStore
from
"./user"
;
import
userStore
from
"./user"
;
import
viewStore
from
"./view"
;
import
workspaceStore
from
"./workspace"
;
import
workspaceStore
from
"./workspace"
;
export
{
workspaceStore
,
userStore
};
export
{
workspaceStore
,
userStore
,
viewStore
};
web/src/store/v2/view.ts
0 → 100644
View file @
56ad8ab3
import
{
makeAutoObservable
}
from
"mobx"
;
const
LOCAL_STORAGE_KEY
=
"memos-view-setting"
;
class
LocalState
{
orderByTimeAsc
:
boolean
=
false
;
layout
:
"LIST"
|
"MASONRY"
=
"LIST"
;
constructor
()
{
makeAutoObservable
(
this
);
}
setPartial
(
partial
:
Partial
<
LocalState
>
)
{
Object
.
assign
(
this
,
partial
);
localStorage
.
setItem
(
LOCAL_STORAGE_KEY
,
JSON
.
stringify
(
this
));
}
}
const
viewStore
=
(()
=>
{
const
state
=
new
LocalState
();
return
{
state
,
};
})();
// Initial state from localStorage.
(
async
()
=>
{
const
localCache
=
localStorage
.
getItem
(
LOCAL_STORAGE_KEY
);
if
(
!
localCache
)
{
return
;
}
try
{
const
cache
=
JSON
.
parse
(
localCache
);
if
(
Object
.
hasOwn
(
cache
,
"orderByTimeAsc"
))
{
viewStore
.
state
.
setPartial
({
orderByTimeAsc
:
Boolean
(
cache
.
orderByTimeAsc
)
});
}
if
(
Object
.
hasOwn
(
cache
,
"layout"
))
{
if
([
"LIST"
,
"MASONRY"
].
includes
(
cache
.
layout
))
{
viewStore
.
state
.
setPartial
({
layout
:
cache
.
layout
});
}
}
}
catch
{
// Do nothing
}
})();
export
default
viewStore
;
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment