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
c2e5a1a5
Commit
c2e5a1a5
authored
May 21, 2022
by
boojack
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor: use `redux`
parent
2e9152e2
Changes
45
Hide whitespace changes
Inline
Side-by-side
Showing
45 changed files
with
685 additions
and
1112 deletions
+685
-1112
package.json
web/package.json
+3
-1
App.tsx
web/src/App.tsx
+2
-5
CreateShortcutDialog.tsx
web/src/components/CreateShortcutDialog.tsx
+2
-4
Dialog.tsx
web/src/components/Dialog.tsx
+3
-8
Memo.tsx
web/src/components/Memo.tsx
+9
-19
MemoCardDialog.tsx
web/src/components/MemoCardDialog.tsx
+2
-2
MemoEditor.tsx
web/src/components/MemoEditor.tsx
+24
-20
MemoFilter.tsx
web/src/components/MemoFilter.tsx
+5
-7
MemoList.tsx
web/src/components/MemoList.tsx
+8
-8
MemosHeader.tsx
web/src/components/MemosHeader.tsx
+8
-10
SearchBar.tsx
web/src/components/SearchBar.tsx
+5
-10
SettingDialog.tsx
web/src/components/SettingDialog.tsx
+4
-4
MyAccountSection.tsx
web/src/components/Settings/MyAccountSection.tsx
+3
-3
ShortcutList.tsx
web/src/components/ShortcutList.tsx
+7
-9
Sidebar.tsx
web/src/components/Sidebar.tsx
+4
-5
TagList.tsx
web/src/components/TagList.tsx
+8
-10
UsageHeatMap.tsx
web/src/components/UsageHeatMap.tsx
+5
-5
UserBanner.tsx
web/src/components/UserBanner.tsx
+4
-4
shortcut-list.less
web/src/less/shortcut-list.less
+1
-1
main.tsx
web/src/main.tsx
+11
-4
Home.tsx
web/src/pages/Home.tsx
+4
-4
editorStateService.ts
web/src/services/editorStateService.ts
+18
-0
globalStateService.ts
web/src/services/globalStateService.ts
+0
-50
index.ts
web/src/services/index.ts
+2
-2
locationService.ts
web/src/services/locationService.ts
+74
-155
memoService.ts
web/src/services/memoService.ts
+72
-99
resourceService.ts
web/src/services/resourceService.ts
+4
-6
shortcutService.ts
web/src/services/shortcutService.ts
+44
-64
userService.ts
web/src/services/userService.ts
+29
-42
index.ts
web/src/store/index.ts
+25
-0
editor.ts
web/src/store/modules/editor.ts
+23
-0
location.ts
web/src/store/modules/location.ts
+62
-0
memo.ts
web/src/store/modules/memo.ts
+44
-0
shortcut.ts
web/src/store/modules/shortcut.ts
+39
-0
user.ts
web/src/store/modules/user.ts
+34
-0
appContext.ts
web/src/stores/appContext.ts
+0
-6
appStore.ts
web/src/stores/appStore.ts
+0
-36
globalStateStore.ts
web/src/stores/globalStateStore.ts
+0
-75
locationStore.ts
web/src/stores/locationStore.ts
+0
-187
memoStore.ts
web/src/stores/memoStore.ts
+0
-98
shortcutStore.ts
web/src/stores/shortcutStore.ts
+0
-92
userStore.ts
web/src/stores/userStore.ts
+0
-52
common.d.ts
web/src/types/common.d.ts
+2
-0
location.d.ts
web/src/types/location.d.ts
+4
-4
yarn.lock
web/yarn.lock
+87
-1
No files found.
web/package.json
View file @
c2e5a1a5
...
@@ -8,9 +8,11 @@
...
@@ -8,9 +8,11 @@
"lint"
:
"eslint --ext .js,.ts,.tsx, src"
"lint"
:
"eslint --ext .js,.ts,.tsx, src"
},
},
"dependencies"
:
{
"dependencies"
:
{
"@reduxjs/toolkit"
:
"^1.8.1"
,
"lodash-es"
:
"^4.17.21"
,
"lodash-es"
:
"^4.17.21"
,
"react"
:
"^18.1.0"
,
"react"
:
"^18.1.0"
,
"react-dom"
:
"^18.1.0"
"react-dom"
:
"^18.1.0"
,
"react-redux"
:
"^8.0.1"
},
},
"devDependencies"
:
{
"devDependencies"
:
{
"@types/lodash-es"
:
"^4.17.5"
,
"@types/lodash-es"
:
"^4.17.5"
,
...
...
web/src/App.tsx
View file @
c2e5a1a5
import
{
useContext
}
from
"react"
;
import
appContext
from
"./stores/appContext"
;
import
{
appRouterSwitch
}
from
"./routers"
;
import
{
appRouterSwitch
}
from
"./routers"
;
import
{
useAppSelector
}
from
"./store"
;
import
"./less/app.less"
;
import
"./less/app.less"
;
function
App
()
{
function
App
()
{
const
{
const
pathname
=
useAppSelector
((
state
)
=>
state
.
location
.
pathname
);
locationState
:
{
pathname
},
}
=
useContext
(
appContext
);
return
<>
{
appRouterSwitch
(
pathname
)
}
</>;
return
<>
{
appRouterSwitch
(
pathname
)
}
</>;
}
}
...
...
web/src/components/CreateShortcutDialog.tsx
View file @
c2e5a1a5
...
@@ -48,11 +48,9 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
...
@@ -48,11 +48,9 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
try
{
try
{
if
(
shortcutId
)
{
if
(
shortcutId
)
{
const
editedShortcut
=
await
shortcutService
.
updateShortcut
(
shortcutId
,
title
,
JSON
.
stringify
(
filters
));
await
shortcutService
.
updateShortcut
(
shortcutId
,
title
,
JSON
.
stringify
(
filters
));
shortcutService
.
editShortcut
(
shortcutService
.
convertResponseModelShortcut
(
editedShortcut
));
}
else
{
}
else
{
const
shortcut
=
await
shortcutService
.
createShortcut
(
title
,
JSON
.
stringify
(
filters
));
await
shortcutService
.
createShortcut
(
title
,
JSON
.
stringify
(
filters
));
shortcutService
.
pushShortcut
(
shortcutService
.
convertResponseModelShortcut
(
shortcut
));
}
}
}
catch
(
error
:
any
)
{
}
catch
(
error
:
any
)
{
toastHelper
.
error
(
error
.
message
);
toastHelper
.
error
(
error
.
message
);
...
...
web/src/components/Dialog.tsx
View file @
c2e5a1a5
import
{
createRoot
}
from
"react-dom/client"
;
import
{
createRoot
}
from
"react-dom/client"
;
import
appContext
from
"../stores/appContext"
;
import
{
Provider
}
from
"react-redux"
;
import
Provider
from
"../labs/Provider"
;
import
store
from
"../store"
;
import
appStore
from
"../stores/appStore"
;
import
{
ANIMATION_DURATION
}
from
"../helpers/consts"
;
import
{
ANIMATION_DURATION
}
from
"../helpers/consts"
;
import
"../less/dialog.less"
;
import
"../less/dialog.less"
;
...
@@ -69,11 +68,7 @@ export function showDialog<T extends DialogProps>(
...
@@ -69,11 +68,7 @@ export function showDialog<T extends DialogProps>(
);
);
if
(
config
.
useAppContext
)
{
if
(
config
.
useAppContext
)
{
Fragment
=
(
Fragment
=
<
Provider
store=
{
store
}
>
{
Fragment
}
</
Provider
>;
<
Provider
store=
{
appStore
}
context=
{
appContext
}
>
{
Fragment
}
</
Provider
>
);
}
}
dialog
.
render
(
Fragment
);
dialog
.
render
(
Fragment
);
...
...
web/src/components/Memo.tsx
View file @
c2e5a1a5
...
@@ -4,7 +4,7 @@ import { IMAGE_URL_REG, LINK_REG, MEMO_LINK_REG, TAG_REG, UNKNOWN_ID } from "../
...
@@ -4,7 +4,7 @@ import { IMAGE_URL_REG, LINK_REG, MEMO_LINK_REG, TAG_REG, UNKNOWN_ID } from "../
import
{
parseMarkedToHtml
,
parseRawTextToHtml
}
from
"../helpers/marked"
;
import
{
parseMarkedToHtml
,
parseRawTextToHtml
}
from
"../helpers/marked"
;
import
utils
from
"../helpers/utils"
;
import
utils
from
"../helpers/utils"
;
import
useToggle
from
"../hooks/useToggle"
;
import
useToggle
from
"../hooks/useToggle"
;
import
{
global
StateService
,
memoService
}
from
"../services"
;
import
{
editor
StateService
,
memoService
}
from
"../services"
;
import
Only
from
"./common/OnlyWhen"
;
import
Only
from
"./common/OnlyWhen"
;
import
Image
from
"./Image"
;
import
Image
from
"./Image"
;
import
showMemoCardDialog
from
"./MemoCardDialog"
;
import
showMemoCardDialog
from
"./MemoCardDialog"
;
...
@@ -50,23 +50,23 @@ const Memo: React.FC<Props> = (props: Props) => {
...
@@ -50,23 +50,23 @@ const Memo: React.FC<Props> = (props: Props) => {
};
};
const
handleMarkMemoClick
=
()
=>
{
const
handleMarkMemoClick
=
()
=>
{
globalStateService
.
setMarkMemoId
(
memo
.
id
);
editorStateService
.
setMarkMemo
(
memo
.
id
);
};
};
const
handleEditMemoClick
=
()
=>
{
const
handleEditMemoClick
=
()
=>
{
globalStateService
.
setEditMemoId
(
memo
.
id
);
editorStateService
.
setEditMemo
(
memo
.
id
);
};
};
const
handleDeleteMemoClick
=
async
()
=>
{
const
handleDeleteMemoClick
=
async
()
=>
{
if
(
showConfirmDeleteBtn
)
{
if
(
showConfirmDeleteBtn
)
{
try
{
try
{
await
memoService
.
hid
eMemoById
(
memo
.
id
);
await
memoService
.
archiv
eMemoById
(
memo
.
id
);
}
catch
(
error
:
any
)
{
}
catch
(
error
:
any
)
{
toastHelper
.
error
(
error
.
message
);
toastHelper
.
error
(
error
.
message
);
}
}
if
(
global
StateService
.
getState
().
editMemoId
===
memo
.
id
)
{
if
(
editor
StateService
.
getState
().
editMemoId
===
memo
.
id
)
{
globalStateService
.
setEditMemoId
(
UNKNOWN_ID
);
editorStateService
.
setEditMemo
(
UNKNOWN_ID
);
}
}
}
else
{
}
else
{
toggleConfirmDeleteBtn
();
toggleConfirmDeleteBtn
();
...
@@ -163,15 +163,9 @@ export function formatMemoContent(content: string) {
...
@@ -163,15 +163,9 @@ export function formatMemoContent(content: string) {
})
})
.
join
(
""
);
.
join
(
""
);
con
st
{
shouldUseMarkdownParser
,
shouldSplitMemoWord
,
shouldHideImageUrl
}
=
globalStateService
.
getState
(
);
con
tent
=
parseMarkedToHtml
(
content
);
if
(
shouldUseMarkdownParser
)
{
content
=
content
.
replace
(
IMAGE_URL_REG
,
""
);
content
=
parseMarkedToHtml
(
content
);
}
if
(
shouldHideImageUrl
)
{
content
=
content
.
replace
(
IMAGE_URL_REG
,
""
);
}
content
=
content
content
=
content
.
replace
(
TAG_REG
,
"<span class='tag-span'>#$1</span>"
)
.
replace
(
TAG_REG
,
"<span class='tag-span'>#$1</span>"
)
...
@@ -179,11 +173,7 @@ export function formatMemoContent(content: string) {
...
@@ -179,11 +173,7 @@ export function formatMemoContent(content: string) {
.
replace
(
MEMO_LINK_REG
,
"<span class='memo-link-text' data-value='$2'>$1</span>"
);
.
replace
(
MEMO_LINK_REG
,
"<span class='memo-link-text' data-value='$2'>$1</span>"
);
// Add space in english and chinese
// Add space in english and chinese
if
(
shouldSplitMemoWord
)
{
content
=
content
.
replace
(
/
([\u
4e00-
\u
9fa5
])([
A-Za-z0-9?.,;[
\]]
+
)
/g
,
"$1 $2"
).
replace
(
/
([
A-Za-z0-9?.,;[
\]]
+
)([\u
4e00-
\u
9fa5
])
/g
,
"$1 $2"
);
content
=
content
.
replace
(
/
([\u
4e00-
\u
9fa5
])([
A-Za-z0-9?.,;[
\]]
+
)
/g
,
"$1 $2"
)
.
replace
(
/
([
A-Za-z0-9?.,;[
\]]
+
)([\u
4e00-
\u
9fa5
])
/g
,
"$1 $2"
);
}
const
tempDivContainer
=
document
.
createElement
(
"div"
);
const
tempDivContainer
=
document
.
createElement
(
"div"
);
tempDivContainer
.
innerHTML
=
content
;
tempDivContainer
.
innerHTML
=
content
;
...
...
web/src/components/MemoCardDialog.tsx
View file @
c2e5a1a5
import
{
useState
,
useEffect
,
useCallback
}
from
"react"
;
import
{
useState
,
useEffect
,
useCallback
}
from
"react"
;
import
{
IMAGE_URL_REG
,
MEMO_LINK_REG
,
UNKNOWN_ID
}
from
"../helpers/consts"
;
import
{
IMAGE_URL_REG
,
MEMO_LINK_REG
,
UNKNOWN_ID
}
from
"../helpers/consts"
;
import
utils
from
"../helpers/utils"
;
import
utils
from
"../helpers/utils"
;
import
{
global
StateService
,
memoService
}
from
"../services"
;
import
{
editor
StateService
,
memoService
}
from
"../services"
;
import
{
parseHtmlToRawText
}
from
"../helpers/marked"
;
import
{
parseHtmlToRawText
}
from
"../helpers/marked"
;
import
{
formatMemoContent
}
from
"./Memo"
;
import
{
formatMemoContent
}
from
"./Memo"
;
import
toastHelper
from
"./Toast"
;
import
toastHelper
from
"./Toast"
;
...
@@ -96,7 +96,7 @@ const MemoCardDialog: React.FC<Props> = (props: Props) => {
...
@@ -96,7 +96,7 @@ const MemoCardDialog: React.FC<Props> = (props: Props) => {
const
handleEditMemoBtnClick
=
useCallback
(()
=>
{
const
handleEditMemoBtnClick
=
useCallback
(()
=>
{
props
.
destroy
();
props
.
destroy
();
globalStateService
.
setEditMemoId
(
memo
.
id
);
editorStateService
.
setEditMemo
(
memo
.
id
);
},
[
memo
.
id
]);
},
[
memo
.
id
]);
return
(
return
(
...
...
web/src/components/MemoEditor.tsx
View file @
c2e5a1a5
import
React
,
{
useCallback
,
use
Context
,
use
Effect
,
useMemo
,
useRef
}
from
"react"
;
import
React
,
{
useCallback
,
useEffect
,
useMemo
,
useRef
}
from
"react"
;
import
appContext
from
"../stores/appContext
"
;
import
{
editorStateService
,
locationService
,
memoService
,
resourceService
}
from
"../services
"
;
import
{
globalStateService
,
locationService
,
memoService
,
resourceService
}
from
"../services
"
;
import
{
useAppSelector
}
from
"../store
"
;
import
{
UNKNOWN_ID
}
from
"../helpers/consts"
;
import
{
UNKNOWN_ID
}
from
"../helpers/consts"
;
import
{
storage
}
from
"../helpers/storage"
;
import
{
storage
}
from
"../helpers/storage"
;
import
useToggle
from
"../hooks/useToggle"
;
import
useToggle
from
"../hooks/useToggle"
;
...
@@ -44,32 +44,36 @@ interface Props {}
...
@@ -44,32 +44,36 @@ interface Props {}
const
MemoEditor
:
React
.
FC
<
Props
>
=
()
=>
{
const
MemoEditor
:
React
.
FC
<
Props
>
=
()
=>
{
const
{
const
{
global
State
,
editor
:
editor
State
,
memo
State
:
{
tags
},
memo
:
{
tags
},
}
=
use
Context
(
appContext
);
}
=
use
AppSelector
((
state
)
=>
state
);
const
[
isTagSeletorShown
,
toggleTagSeletor
]
=
useToggle
(
false
);
const
[
isTagSeletorShown
,
toggleTagSeletor
]
=
useToggle
(
false
);
const
editorRef
=
useRef
<
EditorRefActions
>
(
null
);
const
editorRef
=
useRef
<
EditorRefActions
>
(
null
);
const
prevGlobalStateRef
=
useRef
(
global
State
);
const
prevGlobalStateRef
=
useRef
(
editor
State
);
const
tagSeletorRef
=
useRef
<
HTMLDivElement
>
(
null
);
const
tagSeletorRef
=
useRef
<
HTMLDivElement
>
(
null
);
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
global
State
.
markMemoId
!==
UNKNOWN_ID
)
{
if
(
editorState
.
markMemoId
&&
editor
State
.
markMemoId
!==
UNKNOWN_ID
)
{
const
editorCurrentValue
=
editorRef
.
current
?.
getContent
();
const
editorCurrentValue
=
editorRef
.
current
?.
getContent
();
const
memoLinkText
=
`
${
editorCurrentValue
?
"
\n
"
:
""
}
Mark: [@MEMO](
${
global
State
.
markMemoId
}
)`
;
const
memoLinkText
=
`
${
editorCurrentValue
?
"
\n
"
:
""
}
Mark: [@MEMO](
${
editor
State
.
markMemoId
}
)`
;
editorRef
.
current
?.
insertText
(
memoLinkText
);
editorRef
.
current
?.
insertText
(
memoLinkText
);
globalStateService
.
setMarkMemoId
(
UNKNOWN_ID
);
editorStateService
.
setMarkMemo
(
UNKNOWN_ID
);
}
}
if
(
globalState
.
editMemoId
!==
UNKNOWN_ID
&&
globalState
.
editMemoId
!==
prevGlobalStateRef
.
current
.
editMemoId
)
{
if
(
const
editMemo
=
memoService
.
getMemoById
(
globalState
.
editMemoId
);
editorState
.
editMemoId
&&
editorState
.
editMemoId
!==
UNKNOWN_ID
&&
editorState
.
editMemoId
!==
prevGlobalStateRef
.
current
.
editMemoId
)
{
const
editMemo
=
memoService
.
getMemoById
(
editorState
.
editMemoId
??
UNKNOWN_ID
);
if
(
editMemo
)
{
if
(
editMemo
)
{
editorRef
.
current
?.
setContent
(
editMemo
.
content
??
""
);
editorRef
.
current
?.
setContent
(
editMemo
.
content
??
""
);
editorRef
.
current
?.
focus
();
editorRef
.
current
?.
focus
();
}
}
}
}
prevGlobalStateRef
.
current
=
global
State
;
prevGlobalStateRef
.
current
=
editor
State
;
},
[
globalState
.
markMemoId
,
global
State
.
editMemoId
]);
},
[
editorState
.
markMemoId
,
editor
State
.
editMemoId
]);
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
!
editorRef
.
current
)
{
if
(
!
editorRef
.
current
)
{
...
@@ -144,18 +148,18 @@ const MemoEditor: React.FC<Props> = () => {
...
@@ -144,18 +148,18 @@ const MemoEditor: React.FC<Props> = () => {
return
;
return
;
}
}
const
{
editMemoId
}
=
global
StateService
.
getState
();
const
{
editMemoId
}
=
editor
StateService
.
getState
();
try
{
try
{
if
(
editMemoId
!==
UNKNOWN_ID
)
{
if
(
editMemoId
&&
editMemoId
!==
UNKNOWN_ID
)
{
const
prevMemo
=
memoService
.
getMemoById
(
editMemoId
);
const
prevMemo
=
memoService
.
getMemoById
(
editMemoId
??
UNKNOWN_ID
);
if
(
prevMemo
&&
prevMemo
.
content
!==
content
)
{
if
(
prevMemo
&&
prevMemo
.
content
!==
content
)
{
const
editedMemo
=
await
memoService
.
updateMemo
(
prevMemo
.
id
,
content
);
const
editedMemo
=
await
memoService
.
updateMemo
(
prevMemo
.
id
,
content
);
editedMemo
.
createdTs
=
Date
.
now
();
editedMemo
.
createdTs
=
Date
.
now
();
memoService
.
editMemo
(
editedMemo
);
memoService
.
editMemo
(
editedMemo
);
}
}
globalStateService
.
setEditMemoId
(
UNKNOWN_ID
);
editorStateService
.
setEditMemo
(
UNKNOWN_ID
);
}
else
{
}
else
{
const
newMemo
=
await
memoService
.
createMemo
(
content
);
const
newMemo
=
await
memoService
.
createMemo
(
content
);
memoService
.
pushMemo
(
newMemo
);
memoService
.
pushMemo
(
newMemo
);
...
@@ -169,7 +173,7 @@ const MemoEditor: React.FC<Props> = () => {
...
@@ -169,7 +173,7 @@ const MemoEditor: React.FC<Props> = () => {
},
[]);
},
[]);
const
handleCancelBtnClick
=
useCallback
(()
=>
{
const
handleCancelBtnClick
=
useCallback
(()
=>
{
globalStateService
.
setEditMemoId
(
UNKNOWN_ID
);
editorStateService
.
setEditMemo
(
UNKNOWN_ID
);
editorRef
.
current
?.
setContent
(
""
);
editorRef
.
current
?.
setContent
(
""
);
setEditorContentCache
(
""
);
setEditorContentCache
(
""
);
},
[]);
},
[]);
...
@@ -259,7 +263,7 @@ const MemoEditor: React.FC<Props> = () => {
...
@@ -259,7 +263,7 @@ const MemoEditor: React.FC<Props> = () => {
}
}
},
[]);
},
[]);
const
isEditing
=
globalState
.
editMemoId
!==
UNKNOWN_ID
;
const
isEditing
=
Boolean
(
editorState
.
editMemoId
&&
editorState
.
editMemoId
!==
UNKNOWN_ID
)
;
const
editorConfig
=
useMemo
(
const
editorConfig
=
useMemo
(
()
=>
({
()
=>
({
...
...
web/src/components/MemoFilter.tsx
View file @
c2e5a1a5
import
{
useContext
}
from
"react"
;
import
{
useAppSelector
}
from
"../store"
;
import
appContext
from
"../stores/appContext"
;
import
{
locationService
,
shortcutService
}
from
"../services"
;
import
{
locationService
,
shortcutService
}
from
"../services"
;
import
utils
from
"../helpers/utils"
;
import
utils
from
"../helpers/utils"
;
import
{
getTextWithMemoType
}
from
"../helpers/filter"
;
import
{
getTextWithMemoType
}
from
"../helpers/filter"
;
...
@@ -9,10 +8,9 @@ interface FilterProps {}
...
@@ -9,10 +8,9 @@ interface FilterProps {}
const
MemoFilter
:
React
.
FC
<
FilterProps
>
=
()
=>
{
const
MemoFilter
:
React
.
FC
<
FilterProps
>
=
()
=>
{
const
{
const
{
locationState
:
{
query
},
location
:
{
query
},
}
=
useContext
(
appContext
);
}
=
useAppSelector
((
state
)
=>
state
);
const
{
tag
:
tagQuery
,
duration
,
type
:
memoType
,
text
:
textQuery
,
shortcutId
}
=
query
??
{};
const
{
tag
:
tagQuery
,
duration
,
type
:
memoType
,
text
:
textQuery
,
shortcutId
}
=
query
;
const
shortcut
=
shortcutId
?
shortcutService
.
getShortcutById
(
shortcutId
)
:
null
;
const
shortcut
=
shortcutId
?
shortcutService
.
getShortcutById
(
shortcutId
)
:
null
;
const
showFilter
=
Boolean
(
tagQuery
||
(
duration
&&
duration
.
from
<
duration
.
to
)
||
memoType
||
textQuery
||
shortcut
);
const
showFilter
=
Boolean
(
tagQuery
||
(
duration
&&
duration
.
from
<
duration
.
to
)
||
memoType
||
textQuery
||
shortcut
);
...
@@ -38,7 +36,7 @@ const MemoFilter: React.FC<FilterProps> = () => {
...
@@ -38,7 +36,7 @@ const MemoFilter: React.FC<FilterProps> = () => {
<
div
<
div
className=
{
"filter-item-container "
+
(
memoType
?
""
:
"hidden"
)
}
className=
{
"filter-item-container "
+
(
memoType
?
""
:
"hidden"
)
}
onClick=
{
()
=>
{
onClick=
{
()
=>
{
locationService
.
setMemoTypeQuery
(
""
);
locationService
.
setMemoTypeQuery
(
undefined
);
}
}
}
}
>
>
<
span
className=
"icon-text"
>
📦
</
span
>
{
getTextWithMemoType
(
memoType
as
MemoSpecType
)
}
<
span
className=
"icon-text"
>
📦
</
span
>
{
getTextWithMemoType
(
memoType
as
MemoSpecType
)
}
...
...
web/src/components/MemoList.tsx
View file @
c2e5a1a5
import
{
useCallback
,
useContext
,
useEffect
,
useRef
,
useState
}
from
"react"
;
import
{
useCallback
,
useEffect
,
useRef
,
useState
}
from
"react"
;
import
appContext
from
"../stores/appContext"
;
import
{
locationService
,
memoService
,
shortcutService
}
from
"../services"
;
import
{
locationService
,
memoService
,
shortcutService
}
from
"../services"
;
import
{
useAppSelector
}
from
"../store"
;
import
{
IMAGE_URL_REG
,
LINK_REG
,
MEMO_LINK_REG
,
TAG_REG
}
from
"../helpers/consts"
;
import
{
IMAGE_URL_REG
,
LINK_REG
,
MEMO_LINK_REG
,
TAG_REG
}
from
"../helpers/consts"
;
import
utils
from
"../helpers/utils"
;
import
utils
from
"../helpers/utils"
;
import
{
checkShouldShowMemoWithFilters
}
from
"../helpers/filter"
;
import
{
checkShouldShowMemoWithFilters
}
from
"../helpers/filter"
;
...
@@ -12,13 +12,13 @@ interface Props {}
...
@@ -12,13 +12,13 @@ interface Props {}
const
MemoList
:
React
.
FC
<
Props
>
=
()
=>
{
const
MemoList
:
React
.
FC
<
Props
>
=
()
=>
{
const
{
const
{
location
State
:
{
query
},
location
:
{
query
},
memo
State
:
{
memos
},
memo
:
{
memos
},
}
=
use
Context
(
appContext
);
}
=
use
AppSelector
((
state
)
=>
state
);
const
[
isFetching
,
setFetchStatus
]
=
useState
(
true
);
const
[
isFetching
,
setFetchStatus
]
=
useState
(
true
);
const
wrapperElement
=
useRef
<
HTMLDivElement
>
(
null
);
const
wrapperElement
=
useRef
<
HTMLDivElement
>
(
null
);
const
{
tag
:
tagQuery
,
duration
,
type
:
memoType
,
text
:
textQuery
,
shortcutId
}
=
query
;
const
{
tag
:
tagQuery
,
duration
,
type
:
memoType
,
text
:
textQuery
,
shortcutId
}
=
query
??
{}
;
const
shortcut
=
shortcutId
?
shortcutService
.
getShortcutById
(
shortcutId
)
:
null
;
const
shortcut
=
shortcutId
?
shortcutService
.
getShortcutById
(
shortcutId
)
:
null
;
const
showMemoFilter
=
Boolean
(
tagQuery
||
(
duration
&&
duration
.
from
<
duration
.
to
)
||
memoType
||
textQuery
||
shortcut
);
const
showMemoFilter
=
Boolean
(
tagQuery
||
(
duration
&&
duration
.
from
<
duration
.
to
)
||
memoType
||
textQuery
||
shortcut
);
...
@@ -78,7 +78,7 @@ const MemoList: React.FC<Props> = () => {
...
@@ -78,7 +78,7 @@ const MemoList: React.FC<Props> = () => {
const pinnedMemos = shownMemos.filter((m) =
>
m.pinned);
const pinnedMemos = shownMemos.filter((m) =
>
m.pinned);
const unpinnedMemos = shownMemos.filter((m) =
>
!m.pinned);
const unpinnedMemos = shownMemos.filter((m) =
>
!m.pinned);
const sortedMemos = pinnedMemos.concat(unpinnedMemos);
const sortedMemos = pinnedMemos.concat(unpinnedMemos)
.filter((m) =
>
m.rowStatus === "NORMAL")
;
useEffect(() =
>
{
useEffect(() =
>
{
memoService
memoService
...
@@ -100,7 +100,7 @@ const MemoList: React.FC<Props> = () => {
...
@@ -100,7 +100,7 @@ const MemoList: React.FC<Props> = () => {
const
targetEl
=
event
.
target
as
HTMLElement
;
const
targetEl
=
event
.
target
as
HTMLElement
;
if
(
targetEl
.
tagName
===
"SPAN"
&&
targetEl
.
className
===
"tag-span"
)
{
if
(
targetEl
.
tagName
===
"SPAN"
&&
targetEl
.
className
===
"tag-span"
)
{
const
tagName
=
targetEl
.
innerText
.
slice
(
1
);
const
tagName
=
targetEl
.
innerText
.
slice
(
1
);
const
currTagQuery
=
locationService
.
getState
().
query
.
tag
;
const
currTagQuery
=
locationService
.
getState
().
query
?
.
tag
;
if
(
currTagQuery
===
tagName
)
{
if
(
currTagQuery
===
tagName
)
{
locationService
.
setTagQuery
(
""
);
locationService
.
setTagQuery
(
""
);
}
else
{
}
else
{
...
...
web/src/components/MemosHeader.tsx
View file @
c2e5a1a5
import
{
useCallback
,
use
Context
,
use
Effect
,
useState
}
from
"react"
;
import
{
useCallback
,
useEffect
,
useState
}
from
"react"
;
import
appContext
from
"../stores/appContext
"
;
import
{
useAppSelector
}
from
"../store
"
;
import
SearchBar
from
"./SearchBar"
;
import
SearchBar
from
"./SearchBar"
;
import
{
memoService
,
shortcutService
}
from
"../services"
;
import
{
memoService
,
shortcutService
}
from
"../services"
;
import
"../less/memos-header.less"
;
import
"../less/memos-header.less"
;
...
@@ -10,25 +10,23 @@ interface Props {}
...
@@ -10,25 +10,23 @@ interface Props {}
const
MemosHeader
:
React
.
FC
<
Props
>
=
()
=>
{
const
MemosHeader
:
React
.
FC
<
Props
>
=
()
=>
{
const
{
const
{
locationState
:
{
location
:
{
query
},
query
:
{
shortcutId
},
shortcut
:
{
shortcuts
},
},
}
=
useAppSelector
((
state
)
=>
state
);
shortcutState
:
{
shortcuts
},
}
=
useContext
(
appContext
);
const
[
titleText
,
setTitleText
]
=
useState
(
"MEMOS"
);
const
[
titleText
,
setTitleText
]
=
useState
(
"MEMOS"
);
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
!
shortcutId
)
{
if
(
!
query
?.
shortcutId
)
{
setTitleText
(
"MEMOS"
);
setTitleText
(
"MEMOS"
);
return
;
return
;
}
}
const
shortcut
=
shortcutService
.
getShortcutById
(
shortcutId
);
const
shortcut
=
shortcutService
.
getShortcutById
(
query
?.
shortcutId
);
if
(
shortcut
)
{
if
(
shortcut
)
{
setTitleText
(
shortcut
.
title
);
setTitleText
(
shortcut
.
title
);
}
}
},
[
shortcutId
,
shortcuts
]);
},
[
query
,
shortcuts
]);
const
handleMemoTextClick
=
useCallback
(()
=>
{
const
handleMemoTextClick
=
useCallback
(()
=>
{
const
now
=
Date
.
now
();
const
now
=
Date
.
now
();
...
...
web/src/components/SearchBar.tsx
View file @
c2e5a1a5
import
{
useContext
}
from
"react"
;
import
appContext
from
"../stores/appContext"
;
import
{
locationService
}
from
"../services"
;
import
{
locationService
}
from
"../services"
;
import
{
useAppSelector
}
from
"../store"
;
import
{
memoSpecialTypes
}
from
"../helpers/filter"
;
import
{
memoSpecialTypes
}
from
"../helpers/filter"
;
import
"../less/search-bar.less"
;
import
"../less/search-bar.less"
;
interface
Props
{}
interface
Props
{}
const
SearchBar
:
React
.
FC
<
Props
>
=
()
=>
{
const
SearchBar
:
React
.
FC
<
Props
>
=
()
=>
{
const
{
const
memoType
=
useAppSelector
((
state
)
=>
state
.
location
.
query
?.
type
);
locationState
:
{
query
:
{
type
:
memoType
},
},
}
=
useContext
(
appContext
);
const
handleMemoTypeItemClick
=
(
type
:
MemoSpecType
|
""
)
=>
{
const
handleMemoTypeItemClick
=
(
type
:
MemoSpecType
|
undefined
)
=>
{
const
{
type
:
prevType
}
=
locationService
.
getState
().
query
;
const
{
type
:
prevType
}
=
locationService
.
getState
().
query
??
{}
;
if
(
type
===
prevType
)
{
if
(
type
===
prevType
)
{
type
=
""
;
type
=
undefined
;
}
}
locationService
.
setMemoTypeQuery
(
type
);
locationService
.
setMemoTypeQuery
(
type
);
};
};
...
...
web/src/components/SettingDialog.tsx
View file @
c2e5a1a5
import
{
use
Context
,
use
State
}
from
"react"
;
import
{
useState
}
from
"react"
;
import
appContext
from
"../stores/appContext
"
;
import
{
useAppSelector
}
from
"../store
"
;
import
{
showDialog
}
from
"./Dialog"
;
import
{
showDialog
}
from
"./Dialog"
;
import
MyAccountSection
from
"./Settings/MyAccountSection"
;
import
MyAccountSection
from
"./Settings/MyAccountSection"
;
import
PreferencesSection
from
"./Settings/PreferencesSection"
;
import
PreferencesSection
from
"./Settings/PreferencesSection"
;
...
@@ -16,8 +16,8 @@ interface State {
...
@@ -16,8 +16,8 @@ interface State {
const
SettingDialog
:
React
.
FC
<
Props
>
=
(
props
:
Props
)
=>
{
const
SettingDialog
:
React
.
FC
<
Props
>
=
(
props
:
Props
)
=>
{
const
{
const
{
user
State
:
{
user
},
user
:
{
user
},
}
=
use
Context
(
appContext
);
}
=
use
AppSelector
((
state
)
=>
state
);
const
{
destroy
}
=
props
;
const
{
destroy
}
=
props
;
const
[
state
,
setState
]
=
useState
<
State
>
({
const
[
state
,
setState
]
=
useState
<
State
>
({
selectedSection
:
"my-account"
,
selectedSection
:
"my-account"
,
...
...
web/src/components/Settings/MyAccountSection.tsx
View file @
c2e5a1a5
import
{
use
Context
,
use
State
}
from
"react"
;
import
{
useState
}
from
"react"
;
import
appContext
from
"../../stores/appContext
"
;
import
{
useAppSelector
}
from
"../../store
"
;
import
{
userService
}
from
"../../services"
;
import
{
userService
}
from
"../../services"
;
import
{
validate
,
ValidatorConfig
}
from
"../../helpers/validator"
;
import
{
validate
,
ValidatorConfig
}
from
"../../helpers/validator"
;
import
toastHelper
from
"../Toast"
;
import
toastHelper
from
"../Toast"
;
...
@@ -17,7 +17,7 @@ const validateConfig: ValidatorConfig = {
...
@@ -17,7 +17,7 @@ const validateConfig: ValidatorConfig = {
interface
Props
{}
interface
Props
{}
const
MyAccountSection
:
React
.
FC
<
Props
>
=
()
=>
{
const
MyAccountSection
:
React
.
FC
<
Props
>
=
()
=>
{
const
{
user
State
}
=
useContext
(
appContext
);
const
{
user
:
userState
}
=
useAppSelector
((
state
)
=>
state
);
const
user
=
userState
.
user
as
User
;
const
user
=
userState
.
user
as
User
;
const
[
username
,
setUsername
]
=
useState
<
string
>
(
user
.
name
);
const
[
username
,
setUsername
]
=
useState
<
string
>
(
user
.
name
);
const
openAPIRoute
=
`
${
window
.
location
.
origin
}
/h/
${
user
.
openId
}
/memo`
;
const
openAPIRoute
=
`
${
window
.
location
.
origin
}
/h/
${
user
.
openId
}
/memo`
;
...
...
web/src/components/ShortcutList.tsx
View file @
c2e5a1a5
import
{
use
Context
,
use
Effect
}
from
"react"
;
import
{
useEffect
}
from
"react"
;
import
{
locationService
,
shortcutService
}
from
"../services"
;
import
{
locationService
,
shortcutService
}
from
"../services"
;
import
appContext
from
"../stores/appContext
"
;
import
{
useAppSelector
}
from
"../store
"
;
import
{
UNKNOWN_ID
}
from
"../helpers/consts"
;
import
{
UNKNOWN_ID
}
from
"../helpers/consts"
;
import
utils
from
"../helpers/utils"
;
import
utils
from
"../helpers/utils"
;
import
useToggle
from
"../hooks/useToggle"
;
import
useToggle
from
"../hooks/useToggle"
;
...
@@ -13,11 +13,9 @@ interface Props {}
...
@@ -13,11 +13,9 @@ interface Props {}
const
ShortcutList
:
React
.
FC
<
Props
>
=
()
=>
{
const
ShortcutList
:
React
.
FC
<
Props
>
=
()
=>
{
const
{
const
{
shortcutState
:
{
shortcuts
},
location
:
{
query
},
locationState
:
{
shortcut
:
{
shortcuts
},
query
:
{
shortcutId
},
}
=
useAppSelector
((
state
)
=>
state
);
},
}
=
useContext
(
appContext
);
const
loadingState
=
useLoading
();
const
loadingState
=
useLoading
();
const
pinnedShortcuts
=
shortcuts
const
pinnedShortcuts
=
shortcuts
.
filter
((
s
)
=>
s
.
rowStatus
===
"ARCHIVED"
)
.
filter
((
s
)
=>
s
.
rowStatus
===
"ARCHIVED"
)
...
@@ -48,7 +46,7 @@ const ShortcutList: React.FC<Props> = () => {
...
@@ -48,7 +46,7 @@ const ShortcutList: React.FC<Props> = () => {
</
p
>
</
p
>
<
div
className=
"shortcuts-container"
>
<
div
className=
"shortcuts-container"
>
{
sortedShortcuts
.
map
((
s
)
=>
{
{
sortedShortcuts
.
map
((
s
)
=>
{
return
<
ShortcutContainer
key=
{
s
.
id
}
shortcut=
{
s
}
isActive=
{
s
.
id
===
Number
(
shortcutId
)
}
/>;
return
<
ShortcutContainer
key=
{
s
.
id
}
shortcut=
{
s
}
isActive=
{
s
.
id
===
Number
(
query
?.
shortcutId
)
}
/>;
})
}
})
}
</
div
>
</
div
>
</
div
>
</
div
>
...
@@ -80,7 +78,7 @@ const ShortcutContainer: React.FC<ShortcutContainerProps> = (props: ShortcutCont
...
@@ -80,7 +78,7 @@ const ShortcutContainer: React.FC<ShortcutContainerProps> = (props: ShortcutCont
if
(
showConfirmDeleteBtn
)
{
if
(
showConfirmDeleteBtn
)
{
try
{
try
{
await
shortcutService
.
deleteShortcut
(
shortcut
.
id
);
await
shortcutService
.
deleteShortcut
ById
(
shortcut
.
id
);
}
catch
(
error
:
any
)
{
}
catch
(
error
:
any
)
{
toastHelper
.
error
(
error
.
message
);
toastHelper
.
error
(
error
.
message
);
}
}
...
...
web/src/components/Sidebar.tsx
View file @
c2e5a1a5
import
{
useContext
}
from
"react"
;
import
{
useAppSelector
}
from
"../store"
;
import
appContext
from
"../stores/appContext"
;
import
utils
from
"../helpers/utils"
;
import
utils
from
"../helpers/utils"
;
import
showDailyMemoDiaryDialog
from
"./DailyMemoDiaryDialog"
;
import
showDailyMemoDiaryDialog
from
"./DailyMemoDiaryDialog"
;
import
showSettingDialog
from
"./SettingDialog"
;
import
showSettingDialog
from
"./SettingDialog"
;
...
@@ -14,9 +13,9 @@ interface Props {}
...
@@ -14,9 +13,9 @@ interface Props {}
const
Sidebar
:
React
.
FC
<
Props
>
=
()
=>
{
const
Sidebar
:
React
.
FC
<
Props
>
=
()
=>
{
const
{
const
{
memo
State
:
{
memos
,
tags
},
memo
:
{
memos
,
tags
},
user
State
:
{
user
},
user
:
{
user
},
}
=
use
Context
(
appContext
);
}
=
use
AppSelector
((
state
)
=>
state
);
const
createdDays
=
user
?
Math
.
ceil
((
Date
.
now
()
-
utils
.
getTimeStampByDate
(
user
.
createdTs
))
/
1000
/
3600
/
24
)
:
0
;
const
createdDays
=
user
?
Math
.
ceil
((
Date
.
now
()
-
utils
.
getTimeStampByDate
(
user
.
createdTs
))
/
1000
/
3600
/
24
)
:
0
;
const
handleMyAccountBtnClick
=
()
=>
{
const
handleMyAccountBtnClick
=
()
=>
{
...
...
web/src/components/TagList.tsx
View file @
c2e5a1a5
import
{
use
Context
,
use
Effect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
appContext
from
"../stores/appContext
"
;
import
{
useAppSelector
}
from
"../store
"
;
import
{
locationService
,
memoService
}
from
"../services"
;
import
{
locationService
,
memoService
}
from
"../services"
;
import
useToggle
from
"../hooks/useToggle"
;
import
useToggle
from
"../hooks/useToggle"
;
import
Only
from
"./common/OnlyWhen"
;
import
Only
from
"./common/OnlyWhen"
;
...
@@ -16,11 +16,9 @@ interface Props {}
...
@@ -16,11 +16,9 @@ interface Props {}
const
TagList
:
React
.
FC
<
Props
>
=
()
=>
{
const
TagList
:
React
.
FC
<
Props
>
=
()
=>
{
const
{
const
{
locationState
:
{
location
:
{
query
},
query
:
{
tag
:
tagQuery
},
memo
:
{
memos
,
tags
:
tagsText
},
},
}
=
useAppSelector
((
state
)
=>
state
);
memoState
:
{
tags
:
tagsText
,
memos
},
}
=
useContext
(
appContext
);
const
[
tags
,
setTags
]
=
useState
<
Tag
[]
>
([]);
const
[
tags
,
setTags
]
=
useState
<
Tag
[]
>
([]);
useEffect
(()
=>
{
useEffect
(()
=>
{
...
@@ -73,9 +71,9 @@ const TagList: React.FC<Props> = () => {
...
@@ -73,9 +71,9 @@ const TagList: React.FC<Props> = () => {
<
p
className=
"title-text"
>
Tags
</
p
>
<
p
className=
"title-text"
>
Tags
</
p
>
<
div
className=
"tags-container"
>
<
div
className=
"tags-container"
>
{
tags
.
map
((
t
,
idx
)
=>
(
{
tags
.
map
((
t
,
idx
)
=>
(
<
TagItemContainer
key=
{
t
.
text
+
"-"
+
idx
}
tag=
{
t
}
tagQuery=
{
tagQuery
}
/>
<
TagItemContainer
key=
{
t
.
text
+
"-"
+
idx
}
tag=
{
t
}
tagQuery=
{
query
?.
tag
}
/>
))
}
))
}
<
Only
when=
{
tags
.
length
<
5
&&
memoService
.
initialized
}
>
<
Only
when=
{
tags
.
length
<
5
}
>
<
p
className=
"tag-tip-container"
>
<
p
className=
"tag-tip-container"
>
Enter
<
span
className=
"code-text"
>
#tag
</
span
>
to create a tag
Enter
<
span
className=
"code-text"
>
#tag
</
span
>
to create a tag
</
p
>
</
p
>
...
@@ -87,7 +85,7 @@ const TagList: React.FC<Props> = () => {
...
@@ -87,7 +85,7 @@ const TagList: React.FC<Props> = () => {
interface
TagItemContainerProps
{
interface
TagItemContainerProps
{
tag
:
Tag
;
tag
:
Tag
;
tagQuery
:
string
;
tagQuery
?
:
string
;
}
}
const
TagItemContainer
:
React
.
FC
<
TagItemContainerProps
>
=
(
props
:
TagItemContainerProps
)
=>
{
const
TagItemContainer
:
React
.
FC
<
TagItemContainerProps
>
=
(
props
:
TagItemContainerProps
)
=>
{
...
...
web/src/components/UsageHeatMap.tsx
View file @
c2e5a1a5
import
{
useCallback
,
use
Context
,
use
Effect
,
useRef
,
useState
}
from
"react"
;
import
{
useCallback
,
useEffect
,
useRef
,
useState
}
from
"react"
;
import
appContext
from
"../stores/appContext
"
;
import
{
useAppSelector
}
from
"../store
"
;
import
{
locationService
}
from
"../services"
;
import
{
locationService
}
from
"../services"
;
import
{
DAILY_TIMESTAMP
}
from
"../helpers/consts"
;
import
{
DAILY_TIMESTAMP
}
from
"../helpers/consts"
;
import
utils
from
"../helpers/utils"
;
import
utils
from
"../helpers/utils"
;
...
@@ -36,8 +36,8 @@ const UsageHeatMap: React.FC<Props> = () => {
...
@@ -36,8 +36,8 @@ const UsageHeatMap: React.FC<Props> = () => {
const
beginDayTimestemp
=
todayTimeStamp
-
usedDaysAmount
*
DAILY_TIMESTAMP
;
const
beginDayTimestemp
=
todayTimeStamp
-
usedDaysAmount
*
DAILY_TIMESTAMP
;
const
{
const
{
memo
State
:
{
memos
},
memo
:
{
memos
},
}
=
use
Context
(
appContext
);
}
=
use
AppSelector
((
state
)
=>
state
);
const
[
allStat
,
setAllStat
]
=
useState
<
DailyUsageStat
[]
>
(
getInitialUsageStat
(
usedDaysAmount
,
beginDayTimestemp
));
const
[
allStat
,
setAllStat
]
=
useState
<
DailyUsageStat
[]
>
(
getInitialUsageStat
(
usedDaysAmount
,
beginDayTimestemp
));
const
[
popupStat
,
setPopupStat
]
=
useState
<
DailyUsageStat
|
null
>
(
null
);
const
[
popupStat
,
setPopupStat
]
=
useState
<
DailyUsageStat
|
null
>
(
null
);
const
[
currentStat
,
setCurrentStat
]
=
useState
<
DailyUsageStat
|
null
>
(
null
);
const
[
currentStat
,
setCurrentStat
]
=
useState
<
DailyUsageStat
|
null
>
(
null
);
...
@@ -71,7 +71,7 @@ const UsageHeatMap: React.FC<Props> = () => {
...
@@ -71,7 +71,7 @@ const UsageHeatMap: React.FC<Props> = () => {
},
[]);
},
[]);
const
handleUsageStatItemClick
=
useCallback
((
item
:
DailyUsageStat
)
=>
{
const
handleUsageStatItemClick
=
useCallback
((
item
:
DailyUsageStat
)
=>
{
if
(
locationService
.
getState
().
query
.
duration
?.
from
===
item
.
timestamp
)
{
if
(
locationService
.
getState
().
query
?
.
duration
?.
from
===
item
.
timestamp
)
{
locationService
.
setFromAndToQuery
(
0
,
0
);
locationService
.
setFromAndToQuery
(
0
,
0
);
setCurrentStat
(
null
);
setCurrentStat
(
null
);
}
else
if
(
item
.
count
>
0
)
{
}
else
if
(
item
.
count
>
0
)
{
...
...
web/src/components/UserBanner.tsx
View file @
c2e5a1a5
import
{
useCallback
,
use
Context
,
use
State
}
from
"react"
;
import
{
useCallback
,
useState
}
from
"react"
;
import
appContext
from
"../stores/appContext
"
;
import
{
useAppSelector
}
from
"../store
"
;
import
{
locationService
}
from
"../services"
;
import
{
locationService
}
from
"../services"
;
import
MenuBtnsPopup
from
"./MenuBtnsPopup"
;
import
MenuBtnsPopup
from
"./MenuBtnsPopup"
;
import
"../less/user-banner.less"
;
import
"../less/user-banner.less"
;
...
@@ -8,8 +8,8 @@ interface Props {}
...
@@ -8,8 +8,8 @@ interface Props {}
const
UserBanner
:
React
.
FC
<
Props
>
=
()
=>
{
const
UserBanner
:
React
.
FC
<
Props
>
=
()
=>
{
const
{
const
{
user
State
:
{
user
},
user
:
{
user
},
}
=
use
Context
(
appContext
);
}
=
use
AppSelector
((
state
)
=>
state
);
const
username
=
user
?
user
.
name
:
"Memos"
;
const
username
=
user
?
user
.
name
:
"Memos"
;
const
[
shouldShowPopupBtns
,
setShouldShowPopupBtns
]
=
useState
(
false
);
const
[
shouldShowPopupBtns
,
setShouldShowPopupBtns
]
=
useState
(
false
);
...
...
web/src/less/shortcut-list.less
View file @
c2e5a1a5
...
@@ -42,7 +42,7 @@
...
@@ -42,7 +42,7 @@
> .shortcut-container {
> .shortcut-container {
.flex(row, space-between, center);
.flex(row, space-between, center);
@apply w-full h-10 py-0 px-4 mt-2 rounded-lg text-base cursor-pointer select-none shrink-0;
@apply w-full h-10 py-0 px-4 mt-
px first:mt-
2 rounded-lg text-base cursor-pointer select-none shrink-0;
&:hover {
&:hover {
background-color: @bg-gray;
background-color: @bg-gray;
...
...
web/src/main.tsx
View file @
c2e5a1a5
import
React
from
"react"
;
import
React
from
"react"
;
import
{
createRoot
}
from
"react-dom/client"
;
import
{
createRoot
}
from
"react-dom/client"
;
import
Provider
from
"./labs/Provider
"
;
import
{
Provider
}
from
"react-redux
"
;
import
appContext
from
"./stores/appContext
"
;
import
store
from
"./store
"
;
import
appStore
from
"./stores/appStore
"
;
import
{
updateStateWithLocation
}
from
"./store/modules/location
"
;
import
App
from
"./App"
;
import
App
from
"./App"
;
import
"./helpers/polyfill"
;
import
"./helpers/polyfill"
;
import
"./less/global.less"
;
import
"./less/global.less"
;
...
@@ -12,8 +12,15 @@ const container = document.getElementById("root");
...
@@ -12,8 +12,15 @@ const container = document.getElementById("root");
const
root
=
createRoot
(
container
as
HTMLElement
);
const
root
=
createRoot
(
container
as
HTMLElement
);
root
.
render
(
root
.
render
(
<
React
.
StrictMode
>
<
React
.
StrictMode
>
<
Provider
store=
{
appStore
}
context=
{
appContext
}
>
<
Provider
store=
{
store
}
>
<
App
/>
<
App
/>
</
Provider
>
</
Provider
>
</
React
.
StrictMode
>
</
React
.
StrictMode
>
);
);
window
.
onload
=
()
=>
{
store
.
dispatch
(
updateStateWithLocation
());
window
.
onpopstate
=
()
=>
{
store
.
dispatch
(
updateStateWithLocation
());
};
};
web/src/pages/Home.tsx
View file @
c2e5a1a5
import
{
use
Context
,
use
Effect
}
from
"react"
;
import
{
useEffect
}
from
"react"
;
import
{
locationService
,
userService
}
from
"../services"
;
import
{
locationService
,
userService
}
from
"../services"
;
import
{
homeRouterSwitch
}
from
"../routers"
;
import
{
homeRouterSwitch
}
from
"../routers"
;
import
appContext
from
"../stores/appContext
"
;
import
{
useAppSelector
}
from
"../store
"
;
import
Sidebar
from
"../components/Sidebar"
;
import
Sidebar
from
"../components/Sidebar"
;
import
useLoading
from
"../hooks/useLoading"
;
import
useLoading
from
"../hooks/useLoading"
;
import
"../less/home.less"
;
import
"../less/home.less"
;
function
Home
()
{
function
Home
()
{
const
{
const
{
location
State
:
{
pathname
},
location
:
{
pathname
},
}
=
use
Context
(
appContext
);
}
=
use
AppSelector
((
state
)
=>
state
);
const
loadingState
=
useLoading
();
const
loadingState
=
useLoading
();
useEffect
(()
=>
{
useEffect
(()
=>
{
...
...
web/src/services/editorStateService.ts
0 → 100644
View file @
c2e5a1a5
import
store
from
"../store"
;
import
{
setEditMemoId
,
setMarkMemoId
}
from
"../store/modules/editor"
;
const
editorStateService
=
{
getState
:
()
=>
{
return
store
.
getState
().
editor
;
},
setEditMemo
:
(
editMemoId
:
MemoId
)
=>
{
store
.
dispatch
(
setEditMemoId
(
editMemoId
));
},
setMarkMemo
:
(
markMemoId
:
MemoId
)
=>
{
store
.
dispatch
(
setMarkMemoId
(
markMemoId
));
},
};
export
default
editorStateService
;
web/src/services/globalStateService.ts
deleted
100644 → 0
View file @
2e9152e2
import
{
storage
}
from
"../helpers/storage"
;
import
appStore
from
"../stores/appStore"
;
import
{
AppSetting
}
from
"../stores/globalStateStore"
;
class
GlobalStateService
{
constructor
()
{
const
cachedSetting
=
storage
.
get
([
"shouldSplitMemoWord"
,
"shouldHideImageUrl"
,
"shouldUseMarkdownParser"
]);
const
defaultAppSetting
=
{
shouldSplitMemoWord
:
cachedSetting
.
shouldSplitMemoWord
??
true
,
shouldHideImageUrl
:
cachedSetting
.
shouldHideImageUrl
??
true
,
shouldUseMarkdownParser
:
cachedSetting
.
shouldUseMarkdownParser
??
true
,
};
this
.
setAppSetting
(
defaultAppSetting
);
}
public
getState
=
()
=>
{
return
appStore
.
getState
().
globalState
;
};
public
setEditMemoId
=
(
editMemoId
:
MemoId
)
=>
{
appStore
.
dispatch
({
type
:
"SET_EDIT_MEMO_ID"
,
payload
:
{
editMemoId
,
},
});
};
public
setMarkMemoId
=
(
markMemoId
:
MemoId
)
=>
{
appStore
.
dispatch
({
type
:
"SET_MARK_MEMO_ID"
,
payload
:
{
markMemoId
,
},
});
};
public
setAppSetting
=
(
appSetting
:
Partial
<
AppSetting
>
)
=>
{
appStore
.
dispatch
({
type
:
"SET_APP_SETTING"
,
payload
:
appSetting
,
});
storage
.
set
(
appSetting
);
};
}
const
globalStateService
=
new
GlobalStateService
();
export
default
globalStateService
;
web/src/services/index.ts
View file @
c2e5a1a5
import
globalStateService
from
"./global
StateService"
;
import
editorStateService
from
"./editor
StateService"
;
import
locationService
from
"./locationService"
;
import
locationService
from
"./locationService"
;
import
memoService
from
"./memoService"
;
import
memoService
from
"./memoService"
;
import
shortcutService
from
"./shortcutService"
;
import
shortcutService
from
"./shortcutService"
;
import
userService
from
"./userService"
;
import
userService
from
"./userService"
;
import
resourceService
from
"./resourceService"
;
import
resourceService
from
"./resourceService"
;
export
{
global
StateService
,
locationService
,
memoService
,
shortcutService
,
userService
,
resourceService
};
export
{
editor
StateService
,
locationService
,
memoService
,
shortcutService
,
userService
,
resourceService
};
web/src/services/locationService.ts
View file @
c2e5a1a5
import
utils
from
"../helpers/utils"
;
import
utils
from
"../helpers/utils"
;
import
appStore
from
"../stores/appStore"
;
import
store
from
"../store"
;
import
{
setQuery
,
setPathname
}
from
"../store/modules/location"
;
const
updateLocationUrl
=
(
method
:
"replace"
|
"push"
=
"replace"
)
=>
{
const
updateLocationUrl
=
(
method
:
"replace"
|
"push"
=
"replace"
)
=>
{
const
{
query
,
pathname
,
hash
}
=
appStore
.
getState
().
locationState
;
const
{
query
,
pathname
,
hash
}
=
store
.
getState
().
location
;
let
queryString
=
utils
.
transformObjectToParamsString
(
query
);
let
queryString
=
utils
.
transformObjectToParamsString
(
query
??
{}
);
if
(
queryString
)
{
if
(
queryString
)
{
queryString
=
"?"
+
queryString
;
queryString
=
"?"
+
queryString
;
}
else
{
}
else
{
...
@@ -17,180 +18,98 @@ const updateLocationUrl = (method: "replace" | "push" = "replace") => {
...
@@ -17,180 +18,98 @@ const updateLocationUrl = (method: "replace" | "push" = "replace") => {
}
}
};
};
class
LocationService
{
const
locationService
=
{
constructor
()
{
getState
:
()
=>
{
this
.
updateStateWithLocation
();
return
store
.
getState
().
location
;
window
.
onpopstate
=
()
=>
{
},
this
.
updateStateWithLocation
();
};
}
public
updateStateWithLocation
=
()
=>
{
const
{
pathname
,
search
,
hash
}
=
window
.
location
;
const
urlParams
=
new
URLSearchParams
(
search
);
const
state
:
AppLocation
=
{
pathname
:
"/"
,
hash
:
""
,
query
:
{
tag
:
""
,
duration
:
null
,
text
:
""
,
type
:
""
,
},
};
state
.
query
.
tag
=
urlParams
.
get
(
"tag"
)
??
""
;
state
.
query
.
type
=
(
urlParams
.
get
(
"type"
)
??
""
)
as
MemoSpecType
;
state
.
query
.
text
=
urlParams
.
get
(
"text"
)
??
""
;
state
.
query
.
shortcutId
=
Number
(
urlParams
.
get
(
"shortcutId"
))
??
undefined
;
const
from
=
parseInt
(
urlParams
.
get
(
"from"
)
??
"0"
);
const
to
=
parseInt
(
urlParams
.
get
(
"to"
)
??
"0"
);
if
(
to
>
from
&&
to
!==
0
)
{
state
.
query
.
duration
=
{
from
,
to
,
};
}
state
.
hash
=
hash
;
state
.
pathname
=
this
.
getValidPathname
(
pathname
);
appStore
.
dispatch
({
type
:
"SET_LOCATION"
,
payload
:
state
,
});
};
public
getState
=
()
=>
{
return
appStore
.
getState
().
locationState
;
};
public
clearQuery
=
()
=>
{
appStore
.
dispatch
({
type
:
"SET_QUERY"
,
payload
:
{
tag
:
""
,
duration
:
null
,
text
:
""
,
type
:
""
,
},
});
updateLocationUrl
();
};
public
setQuery
=
(
query
:
Query
)
=>
{
appStore
.
dispatch
({
type
:
"SET_QUERY"
,
payload
:
query
,
});
clearQuery
:
()
=>
{
store
.
dispatch
(
setQuery
({}));
updateLocationUrl
();
updateLocationUrl
();
};
},
public
setHash
=
(
hash
:
string
)
=>
{
appStore
.
dispatch
({
type
:
"SET_HASH"
,
payload
:
{
hash
,
},
});
setQuery
:
(
query
:
Query
)
=>
{
store
.
dispatch
(
setQuery
(
query
));
updateLocationUrl
();
updateLocationUrl
();
};
},
public
setPathname
=
(
pathname
:
string
)
=>
{
appStore
.
dispatch
({
type
:
"SET_PATHNAME"
,
payload
:
{
pathname
,
},
});
setPathname
:
(
pathname
:
AppRouter
)
=>
{
store
.
dispatch
(
setPathname
(
pathname
));
updateLocationUrl
();
updateLocationUrl
();
};
},
public
pushHistory
=
(
pathname
:
string
)
=>
{
appStore
.
dispatch
({
type
:
"SET_PATHNAME"
,
payload
:
{
pathname
,
},
});
pushHistory
:
(
pathname
:
AppRouter
)
=>
{
store
.
dispatch
(
setPathname
(
pathname
));
updateLocationUrl
(
"push"
);
updateLocationUrl
(
"push"
);
};
},
public
replaceHistory
=
(
pathname
:
string
)
=>
{
appStore
.
dispatch
({
type
:
"SET_PATHNAME"
,
payload
:
{
pathname
,
},
});
replaceHistory
:
(
pathname
:
AppRouter
)
=>
{
store
.
dispatch
(
setPathname
(
pathname
));
updateLocationUrl
(
"replace"
);
updateLocationUrl
(
"replace"
);
}
;
}
,
public
setMemoTypeQuery
=
(
type
:
MemoSpecType
|
""
=
""
)
=>
{
setMemoTypeQuery
:
(
type
?:
MemoSpecType
)
=>
{
appStore
.
dispatch
({
const
{
query
}
=
store
.
getState
().
location
;
type
:
"SET_TYPE"
,
store
.
dispatch
(
payload
:
{
setQuery
(
{
type
,
...
query
,
}
,
type
:
type
,
});
})
);
updateLocationUrl
();
updateLocationUrl
();
};
},
public
setMemoShortcut
=
(
shortcutId
?:
ShortcutId
)
=>
{
setMemoShortcut
:
(
shortcutId
?:
ShortcutId
)
=>
{
appStore
.
dispatch
({
const
{
query
}
=
store
.
getState
().
location
;
type
:
"SET_SHORTCUT_ID"
,
store
.
dispatch
(
payload
:
shortcutId
,
setQuery
({
});
...
query
,
shortcutId
:
shortcutId
,
})
);
updateLocationUrl
();
updateLocationUrl
();
}
;
}
,
public
setTextQuery
=
(
text
:
string
)
=>
{
setTextQuery
:
(
text
?
:
string
)
=>
{
appStore
.
dispatch
({
const
{
query
}
=
store
.
getState
().
location
;
type
:
"SET_TEXT"
,
store
.
dispatch
(
payload
:
{
setQuery
(
{
text
,
...
query
,
}
,
text
:
text
,
});
})
);
updateLocationUrl
();
updateLocationUrl
();
}
;
}
,
public
setTagQuery
=
(
tag
:
string
)
=>
{
setTagQuery
:
(
tag
?
:
string
)
=>
{
appStore
.
dispatch
({
const
{
query
}
=
store
.
getState
().
location
;
type
:
"SET_TAG_QUERY"
,
store
.
dispatch
(
payload
:
{
setQuery
(
{
tag
,
...
query
,
}
,
tag
:
tag
,
});
})
);
updateLocationUrl
();
updateLocationUrl
();
}
;
}
,
public
setFromAndToQuery
=
(
from
:
number
,
to
:
number
)
=>
{
setFromAndToQuery
:
(
from
:
number
,
to
:
number
)
=>
{
appStore
.
dispatch
({
const
{
query
}
=
store
.
getState
().
location
;
type
:
"SET_DURATION_QUERY"
,
store
.
dispatch
(
payload
:
{
setQuery
({
...
query
,
duration
:
{
from
,
to
},
duration
:
{
from
,
to
},
},
})
});
);
updateLocationUrl
();
updateLocationUrl
();
}
;
}
,
public
getValidPathname
=
(
pathname
:
string
):
AppRouter
=>
{
getValidPathname
:
(
pathname
:
string
):
AppRouter
=>
{
if
([
"/"
,
"/signin"
].
includes
(
pathname
))
{
if
([
"/"
,
"/signin"
].
includes
(
pathname
))
{
return
pathname
as
AppRouter
;
return
pathname
as
AppRouter
;
}
else
{
}
else
{
return
"/"
;
return
"/"
;
}
}
};
},
}
};
const
locationService
=
new
LocationService
();
export
default
locationService
;
export
default
locationService
;
web/src/services/memoService.ts
View file @
c2e5a1a5
import
api
from
"../helpers/api"
;
import
api
from
"../helpers/api"
;
import
{
TAG_REG
}
from
"../helpers/consts"
;
import
{
TAG_REG
}
from
"../helpers/consts"
;
import
utils
from
"../helpers/utils"
;
import
utils
from
"../helpers/utils"
;
import
appStore
from
"../stores/appStore"
;
import
{
patchMemo
,
setMemos
,
setTags
}
from
"../store/modules/memo"
;
import
store
from
"../store"
;
import
userService
from
"./userService"
;
import
userService
from
"./userService"
;
class
MemoService
{
const
convertResponseModelMemo
=
(
memo
:
Memo
):
Memo
=>
{
public
initialized
=
false
;
return
{
...
memo
,
createdTs
:
memo
.
createdTs
*
1000
,
updatedTs
:
memo
.
updatedTs
*
1000
,
};
};
public
getState
()
{
const
memoService
=
{
return
appStore
.
getState
().
memoState
;
getState
:
()
=>
{
}
return
store
.
getState
().
memo
;
},
public
async
fetchAllMemos
()
{
fetchAllMemos
:
async
()
=>
{
if
(
!
userService
.
getState
().
user
)
{
if
(
!
userService
.
getState
().
user
)
{
return
false
;
return
false
;
}
}
const
data
=
await
api
.
getMyMemos
();
const
data
=
await
api
.
getMyMemos
();
const
memos
:
Memo
[]
=
data
.
filter
((
m
)
=>
m
.
rowStatus
!==
"ARCHIVED"
).
map
((
m
)
=>
this
.
convertResponseModelMemo
(
m
));
const
memos
:
Memo
[]
=
data
.
filter
((
m
)
=>
m
.
rowStatus
!==
"ARCHIVED"
).
map
((
m
)
=>
convertResponseModelMemo
(
m
));
appStore
.
dispatch
({
store
.
dispatch
(
setMemos
(
memos
));
type
:
"SET_MEMOS"
,
payload
:
{
memos
,
},
});
if
(
!
this
.
initialized
)
{
this
.
initialized
=
true
;
}
return
memos
;
return
memos
;
}
}
,
public
async
fetchDeletedMemos
()
{
fetchDeletedMemos
:
async
()
=>
{
if
(
!
userService
.
getState
().
user
)
{
if
(
!
userService
.
getState
().
user
)
{
return
false
;
return
false
;
}
}
const
data
=
await
api
.
getMyArchivedMemos
();
const
data
=
await
api
.
getMyArchivedMemos
();
const
deletedMemos
:
Memo
[]
=
data
.
map
((
m
)
=>
{
const
deletedMemos
:
Memo
[]
=
data
.
map
((
m
)
=>
{
return
this
.
convertResponseModelMemo
(
m
);
return
convertResponseModelMemo
(
m
);
});
});
return
deletedMemos
;
return
deletedMemos
;
}
},
public
pushMemo
(
memo
:
Memo
)
{
appStore
.
dispatch
({
type
:
"INSERT_MEMO"
,
payload
:
{
memo
:
{
...
memo
,
},
},
});
}
public
getMemoById
(
id
:
MemoId
)
{
pushMemo
:
(
memo
:
Memo
)
=>
{
for
(
const
m
of
this
.
getState
().
memos
)
{
store
.
dispatch
(
setMemos
(
memoService
.
getState
().
memos
.
concat
(
memo
)));
},
getMemoById
:
(
id
:
MemoId
)
=>
{
for
(
const
m
of
memoService
.
getState
().
memos
)
{
if
(
m
.
id
===
id
)
{
if
(
m
.
id
===
id
)
{
return
m
;
return
m
;
}
}
}
}
return
null
;
return
null
;
}
}
,
public
async
hideMemoById
(
id
:
MemoId
)
{
archiveMemoById
:
async
(
id
:
MemoId
)
=>
{
await
api
.
archiveMemo
(
id
);
const
memo
=
memoService
.
getMemoById
(
id
);
appStore
.
dispatch
({
if
(
!
memo
)
{
type
:
"DELETE_MEMO_BY_ID"
,
return
;
payload
:
{
}
id
:
id
,
},
});
}
public
async
restoreMemoById
(
id
:
MemoId
)
{
await
api
.
archiveMemo
(
id
);
store
.
dispatch
(
patchMemo
({
...
memo
,
rowStatus
:
"ARCHIVED"
,
})
);
},
restoreMemoById
:
async
(
id
:
MemoId
)
=>
{
await
api
.
restoreMemo
(
id
);
await
api
.
restoreMemo
(
id
);
memoService
.
clearMemos
();
memoService
.
clearMemos
();
memoService
.
fetchAllMemos
();
memoService
.
fetchAllMemos
();
}
}
,
public
async
deleteMemoById
(
id
:
MemoId
)
{
deleteMemoById
:
async
(
id
:
MemoId
)
=>
{
await
api
.
deleteMemo
(
id
);
await
api
.
deleteMemo
(
id
);
}
}
,
public
editMemo
(
memo
:
Memo
)
{
editMemo
:
(
memo
:
Memo
)
=>
{
appStore
.
dispatch
({
store
.
dispatch
(
patchMemo
(
memo
));
type
:
"EDIT_MEMO"
,
},
payload
:
memo
,
});
}
public
updateTagsState
()
{
updateTagsState
:
()
=>
{
const
{
memos
}
=
this
.
getState
();
const
{
memos
}
=
memoService
.
getState
();
const
tagsSet
=
new
Set
<
string
>
();
const
tagsSet
=
new
Set
<
string
>
();
for
(
const
m
of
memos
)
{
for
(
const
m
of
memos
)
{
for
(
const
t
of
Array
.
from
(
m
.
content
.
match
(
TAG_REG
)
??
[]))
{
for
(
const
t
of
Array
.
from
(
m
.
content
.
match
(
TAG_REG
)
??
[]))
{
...
@@ -101,69 +94,49 @@ class MemoService {
...
@@ -101,69 +94,49 @@ class MemoService {
}
}
}
}
appStore
.
dispatch
({
store
.
dispatch
(
setTags
(
Array
.
from
(
tagsSet
).
filter
((
t
)
=>
Boolean
(
t
))));
type
:
"SET_TAGS"
,
},
payload
:
{
tags
:
Array
.
from
(
tagsSet
).
filter
((
t
)
=>
Boolean
(
t
)),
clearMemos
:
()
=>
{
},
store
.
dispatch
(
setMemos
([]));
});
},
}
public
clearMemos
()
{
appStore
.
dispatch
({
type
:
"SET_MEMOS"
,
payload
:
{
memos
:
[],
},
});
}
public
async
getLinkedMemos
(
memoId
:
MemoId
):
Promise
<
Memo
[]
>
{
getLinkedMemos
:
async
(
memoId
:
MemoId
):
Promise
<
Memo
[]
>
=
>
{
const
{
memos
}
=
this
.
getState
();
const
{
memos
}
=
memoService
.
getState
();
return
memos
.
filter
((
m
)
=>
m
.
content
.
includes
(
`
${
memoId
}
`
));
return
memos
.
filter
((
m
)
=>
m
.
content
.
includes
(
`
${
memoId
}
`
));
}
}
,
public
async
createMemo
(
content
:
string
):
Promise
<
Memo
>
{
createMemo
:
async
(
content
:
string
):
Promise
<
Memo
>
=
>
{
const
memo
=
await
api
.
createMemo
({
const
memo
=
await
api
.
createMemo
({
content
,
content
,
});
});
return
this
.
convertResponseModelMemo
(
memo
);
return
convertResponseModelMemo
(
memo
);
}
}
,
public
async
updateMemo
(
memoId
:
MemoId
,
content
:
string
):
Promise
<
Memo
>
{
updateMemo
:
async
(
memoId
:
MemoId
,
content
:
string
):
Promise
<
Memo
>
=
>
{
const
memo
=
await
api
.
patchMemo
({
const
memo
=
await
api
.
patchMemo
({
id
:
memoId
,
id
:
memoId
,
content
,
content
,
});
});
return
this
.
convertResponseModelMemo
(
memo
);
return
convertResponseModelMemo
(
memo
);
}
}
,
p
ublic
async
pinMemo
(
memoId
:
MemoId
)
{
p
inMemo
:
async
(
memoId
:
MemoId
)
=>
{
await
api
.
pinMemo
(
memoId
);
await
api
.
pinMemo
(
memoId
);
}
}
,
public
async
unpinMemo
(
memoId
:
MemoId
)
{
unpinMemo
:
async
(
memoId
:
MemoId
)
=>
{
await
api
.
unpinMemo
(
memoId
);
await
api
.
unpinMemo
(
memoId
);
}
}
,
public
async
importMemo
(
content
:
string
,
createdAt
:
string
)
{
importMemo
:
async
(
content
:
string
,
createdAt
:
string
)
=>
{
const
createdTs
=
Math
.
floor
(
utils
.
getTimeStampByDate
(
createdAt
)
/
1000
);
const
createdTs
=
Math
.
floor
(
utils
.
getTimeStampByDate
(
createdAt
)
/
1000
);
await
api
.
createMemo
({
await
api
.
createMemo
({
content
,
content
,
createdTs
,
createdTs
,
});
});
}
},
};
private
convertResponseModelMemo
(
memo
:
Memo
):
Memo
{
return
{
...
memo
,
createdTs
:
memo
.
createdTs
*
1000
,
updatedTs
:
memo
.
updatedTs
*
1000
,
};
}
}
const
memoService
=
new
MemoService
();
export
default
memoService
;
export
default
memoService
;
web/src/services/resourceService.ts
View file @
c2e5a1a5
import
api
from
"../helpers/api"
;
import
api
from
"../helpers/api"
;
c
lass
ResourceService
{
c
onst
resourceService
=
{
/**
/**
* Upload resource file to server,
* Upload resource file to server,
* @param file file
* @param file file
* @returns resource: id, filename
* @returns resource: id, filename
*/
*/
public
async
upload
(
file
:
File
)
{
async
upload
(
file
:
File
)
{
const
{
name
:
filename
,
size
}
=
file
;
const
{
name
:
filename
,
size
}
=
file
;
if
(
size
>
64
<<
20
)
{
if
(
size
>
64
<<
20
)
{
...
@@ -18,9 +18,7 @@ class ResourceService {
...
@@ -18,9 +18,7 @@ class ResourceService {
const
data
=
await
api
.
uploadFile
(
formData
);
const
data
=
await
api
.
uploadFile
(
formData
);
return
data
;
return
data
;
}
},
}
};
const
resourceService
=
new
ResourceService
();
export
default
resourceService
;
export
default
resourceService
;
web/src/services/shortcutService.ts
View file @
c2e5a1a5
import
userService
from
"./userService"
;
import
userService
from
"./userService"
;
import
api
from
"../helpers/api"
;
import
api
from
"../helpers/api"
;
import
appStore
from
"../stores/appStore"
;
import
{
UNKNOWN_ID
}
from
"../helpers/consts"
;
import
{
UNKNOWN_ID
}
from
"../helpers/consts"
;
import
store
from
"../store/"
;
class
ShortcutService
{
import
{
deleteShortcut
,
patchShortcut
,
setShortcuts
}
from
"../store/modules/shortcut"
;
public
getState
()
{
return
appStore
.
getState
().
shortcutState
;
const
convertResponseModelShortcut
=
(
shortcut
:
Shortcut
):
Shortcut
=>
{
}
return
{
...
shortcut
,
public
async
getMyAllShortcuts
()
{
createdTs
:
shortcut
.
createdTs
*
1000
,
updatedTs
:
shortcut
.
updatedTs
*
1000
,
};
};
const
shortcutService
=
{
getState
:
()
=>
{
return
store
.
getState
().
shortcut
;
},
getMyAllShortcuts
:
async
()
=>
{
if
(
!
userService
.
getState
().
user
)
{
if
(
!
userService
.
getState
().
user
)
{
return
false
;
return
false
;
}
}
const
data
=
await
api
.
getMyShortcuts
();
const
data
=
await
api
.
getMyShortcuts
();
appStore
.
dispatch
({
const
shortcuts
=
data
.
map
((
s
)
=>
convertResponseModelShortcut
(
s
));
type
:
"SET_SHORTCUTS"
,
store
.
dispatch
(
setShortcuts
(
shortcuts
));
payload
:
{
return
shortcuts
;
shortcuts
:
data
.
map
((
s
)
=>
this
.
convertResponseModelShortcut
(
s
)),
},
},
});
return
data
;
}
public
getShortcutById
(
id
:
ShortcutId
)
{
getShortcutById
:
(
id
:
ShortcutId
)
=>
{
if
(
id
===
UNKNOWN_ID
)
{
if
(
id
===
UNKNOWN_ID
)
{
return
null
;
return
null
;
}
}
for
(
const
s
of
this
.
getState
().
shortcuts
)
{
for
(
const
s
of
shortcutService
.
getState
().
shortcuts
)
{
if
(
s
.
id
===
id
)
{
if
(
s
.
id
===
id
)
{
return
s
;
return
s
;
}
}
}
}
return
null
;
return
null
;
}
}
,
public
pushShortcut
(
shortcut
:
Shortcut
)
{
pushShortcut
:
(
shortcut
:
Shortcut
)
=>
{
appStore
.
dispatch
({
store
.
dispatch
(
setShortcuts
(
shortcutService
.
getState
().
shortcuts
.
concat
(
shortcut
)));
type
:
"INSERT_SHORTCUT"
,
},
payload
:
{
shortcut
:
{
...
shortcut
,
},
},
});
}
public
editShortcut
(
shortcut
:
Shortcut
)
{
editShortcut
:
(
shortcut
:
Shortcut
)
=>
{
appStore
.
dispatch
({
store
.
dispatch
(
patchShortcut
(
shortcut
));
type
:
"UPDATE_SHORTCUT"
,
},
payload
:
shortcut
,
});
}
public
async
deleteShortcut
(
shortcutId
:
ShortcutId
)
{
deleteShortcutById
:
async
(
shortcutId
:
ShortcutId
)
=>
{
await
api
.
deleteShortcutById
(
shortcutId
);
await
api
.
deleteShortcutById
(
shortcutId
);
appStore
.
dispatch
({
store
.
dispatch
(
deleteShortcut
(
shortcutId
));
type
:
"DELETE_SHORTCUT_BY_ID"
,
},
payload
:
{
id
:
shortcutId
,
},
});
}
public
async
createShortcut
(
title
:
string
,
payload
:
string
)
{
createShortcut
:
async
(
title
:
string
,
payload
:
string
)
=>
{
const
data
=
await
api
.
createShortcut
(
title
,
payload
);
const
data
=
await
api
.
createShortcut
(
title
,
payload
);
return
data
;
shortcutService
.
pushShortcut
(
convertResponseModelShortcut
(
data
))
;
}
}
,
public
async
updateShortcut
(
shortcutId
:
ShortcutId
,
title
:
string
,
payload
:
string
)
{
updateShortcut
:
async
(
shortcutId
:
ShortcutId
,
title
:
string
,
payload
:
string
)
=>
{
const
data
=
await
api
.
updateShortcut
(
shortcutId
,
title
,
payload
);
const
data
=
await
api
.
updateShortcut
(
shortcutId
,
title
,
payload
);
return
data
;
store
.
dispatch
(
patchShortcut
(
convertResponseModelShortcut
(
data
)))
;
}
}
,
p
ublic
async
pinShortcut
(
shortcutId
:
ShortcutId
)
{
p
inShortcut
:
async
(
shortcutId
:
ShortcutId
)
=>
{
await
api
.
pinShortcut
(
shortcutId
);
await
api
.
pinShortcut
(
shortcutId
);
}
}
,
public
async
unpinShortcut
(
shortcutId
:
ShortcutId
)
{
unpinShortcut
:
async
(
shortcutId
:
ShortcutId
)
=>
{
await
api
.
unpinShortcut
(
shortcutId
);
await
api
.
unpinShortcut
(
shortcutId
);
}
},
};
public
convertResponseModelShortcut
(
shortcut
:
Shortcut
):
Shortcut
{
return
{
...
shortcut
,
createdTs
:
shortcut
.
createdTs
*
1000
,
updatedTs
:
shortcut
.
updatedTs
*
1000
,
};
}
}
const
shortcutService
=
new
ShortcutService
();
export
default
shortcutService
;
export
default
shortcutService
;
web/src/services/userService.ts
View file @
c2e5a1a5
import
api
from
"../helpers/api"
;
import
api
from
"../helpers/api"
;
import
appStore
from
"../stores/appStore"
;
import
{
signin
,
signout
}
from
"../store/modules/user"
;
import
store
from
"../store"
;
class
UserService
{
public
getState
()
{
const
convertResponseModelUser
=
(
user
:
User
):
User
=>
{
return
appStore
.
getState
().
userState
;
return
{
}
...
user
,
createdTs
:
user
.
createdTs
*
1000
,
public
async
doSignIn
()
{
updatedTs
:
user
.
updatedTs
*
1000
,
};
};
const
userService
=
{
getState
:
()
=>
{
return
store
.
getState
().
user
;
},
doSignIn
:
async
()
=>
{
const
user
=
await
api
.
getUser
();
const
user
=
await
api
.
getUser
();
if
(
user
)
{
if
(
user
)
{
appStore
.
dispatch
({
store
.
dispatch
(
signin
(
convertResponseModelUser
(
user
)));
type
:
"LOGIN"
,
payload
:
{
user
:
this
.
convertResponseModelUser
(
user
),
},
});
}
else
{
}
else
{
userService
.
doSignOut
();
userService
.
doSignOut
();
}
}
return
user
;
return
user
;
}
}
,
public
async
doSignOut
()
{
doSignOut
:
async
()
=>
{
appStore
.
dispatch
({
store
.
dispatch
(
signout
);
type
:
"SIGN_OUT"
,
payload
:
null
,
});
api
.
signout
().
catch
(()
=>
{
api
.
signout
().
catch
(()
=>
{
// do nth
// do nth
});
});
}
}
,
public
async
updateUsername
(
name
:
string
):
Promise
<
void
>
{
updateUsername
:
async
(
name
:
string
):
Promise
<
void
>
=
>
{
await
api
.
patchUser
({
await
api
.
patchUser
({
name
,
name
,
});
});
}
}
,
public
async
updatePassword
(
password
:
string
):
Promise
<
void
>
{
updatePassword
:
async
(
password
:
string
):
Promise
<
void
>
=
>
{
await
api
.
patchUser
({
await
api
.
patchUser
({
password
,
password
,
});
});
}
}
,
public
async
resetOpenId
():
Promise
<
string
>
{
resetOpenId
:
async
():
Promise
<
string
>
=
>
{
const
user
=
await
api
.
patchUser
({
const
user
=
await
api
.
patchUser
({
resetOpenId
:
true
,
resetOpenId
:
true
,
});
});
appStore
.
dispatch
({
type
:
"RESET_OPENID"
,
payload
:
user
.
openId
,
});
return
user
.
openId
;
return
user
.
openId
;
}
},
};
private
convertResponseModelUser
(
user
:
User
):
User
{
return
{
...
user
,
createdTs
:
user
.
createdTs
*
1000
,
updatedTs
:
user
.
updatedTs
*
1000
,
};
}
}
const
userService
=
new
UserService
();
export
default
userService
;
export
default
userService
;
web/src/store/index.ts
0 → 100644
View file @
c2e5a1a5
import
{
configureStore
}
from
"@reduxjs/toolkit"
;
import
{
TypedUseSelectorHook
,
useDispatch
,
useSelector
}
from
"react-redux"
;
import
userReducer
from
"./modules/user"
;
import
memoReducer
from
"./modules/memo"
;
import
editorReducer
from
"./modules/editor"
;
import
shortcutReducer
from
"./modules/shortcut"
;
import
locationReducer
from
"./modules/location"
;
const
store
=
configureStore
({
reducer
:
{
user
:
userReducer
,
memo
:
memoReducer
,
editor
:
editorReducer
,
shortcut
:
shortcutReducer
,
location
:
locationReducer
,
},
});
type
AppState
=
ReturnType
<
typeof
store
.
getState
>
;
type
AppDispatch
=
typeof
store
.
dispatch
;
export
const
useAppSelector
:
TypedUseSelectorHook
<
AppState
>
=
useSelector
;
export
const
useAppDispatch
=
()
=>
useDispatch
<
AppDispatch
>
();
export
default
store
;
web/src/store/modules/editor.ts
0 → 100644
View file @
c2e5a1a5
import
{
createSlice
,
PayloadAction
}
from
"@reduxjs/toolkit"
;
interface
State
{
markMemoId
?:
MemoId
;
editMemoId
?:
MemoId
;
}
const
editorSlice
=
createSlice
({
name
:
"editor"
,
initialState
:
{}
as
State
,
reducers
:
{
setMarkMemoId
:
(
state
,
action
:
PayloadAction
<
Option
<
MemoId
>>
)
=>
{
state
.
markMemoId
=
action
.
payload
;
},
setEditMemoId
:
(
state
,
action
:
PayloadAction
<
Option
<
MemoId
>>
)
=>
{
state
.
editMemoId
=
action
.
payload
;
},
},
});
export
const
{
setEditMemoId
,
setMarkMemoId
}
=
editorSlice
.
actions
;
export
default
editorSlice
.
reducer
;
web/src/store/modules/location.ts
0 → 100644
View file @
c2e5a1a5
import
{
createSlice
,
PayloadAction
}
from
"@reduxjs/toolkit"
;
interface
State
{
pathname
:
AppRouter
;
hash
:
string
;
query
?:
Query
;
}
const
getValidPathname
=
(
pathname
:
string
):
AppRouter
=>
{
if
([
"/"
,
"/signin"
].
includes
(
pathname
))
{
return
pathname
as
AppRouter
;
}
else
{
return
"/"
;
}
};
const
getStateFromLocation
=
()
=>
{
const
{
pathname
,
search
,
hash
}
=
window
.
location
;
const
urlParams
=
new
URLSearchParams
(
search
);
const
state
:
State
=
{
pathname
:
getValidPathname
(
pathname
),
hash
:
hash
,
};
if
(
search
!==
""
)
{
state
.
query
=
{};
state
.
query
.
tag
=
urlParams
.
get
(
"tag"
)
??
undefined
;
state
.
query
.
type
=
(
urlParams
.
get
(
"type"
)
as
MemoSpecType
)
??
undefined
;
state
.
query
.
text
=
urlParams
.
get
(
"text"
)
??
undefined
;
state
.
query
.
shortcutId
=
Number
(
urlParams
.
get
(
"shortcutId"
))
??
undefined
;
const
from
=
parseInt
(
urlParams
.
get
(
"from"
)
??
"0"
);
const
to
=
parseInt
(
urlParams
.
get
(
"to"
)
??
"0"
);
if
(
to
>
from
&&
to
!==
0
)
{
state
.
query
.
duration
=
{
from
,
to
,
};
}
}
return
state
;
};
const
locationSlice
=
createSlice
({
name
:
"location"
,
initialState
:
getStateFromLocation
(),
reducers
:
{
updateStateWithLocation
:
()
=>
{
return
getStateFromLocation
();
},
setPathname
:
(
state
,
action
:
PayloadAction
<
AppRouter
>
)
=>
{
state
.
pathname
=
action
.
payload
;
},
setQuery
:
(
state
,
action
:
PayloadAction
<
Partial
<
Query
>>
)
=>
{
state
.
query
=
action
.
payload
;
},
},
});
export
const
{
setPathname
,
setQuery
,
updateStateWithLocation
}
=
locationSlice
.
actions
;
export
default
locationSlice
.
reducer
;
web/src/store/modules/memo.ts
0 → 100644
View file @
c2e5a1a5
import
{
createSlice
,
PayloadAction
}
from
"@reduxjs/toolkit"
;
interface
State
{
memos
:
Memo
[];
tags
:
string
[];
}
const
memoSlice
=
createSlice
({
name
:
"memo"
,
initialState
:
{
memos
:
[],
tags
:
[],
}
as
State
,
reducers
:
{
setMemos
:
(
state
,
action
:
PayloadAction
<
Memo
[]
>
)
=>
{
state
.
memos
=
action
.
payload
;
},
setTags
:
(
state
,
action
:
PayloadAction
<
string
[]
>
)
=>
{
state
.
tags
=
action
.
payload
;
},
createMemo
:
(
state
,
action
:
PayloadAction
<
Memo
>
)
=>
{
state
.
memos
=
state
.
memos
.
concat
(
action
.
payload
);
},
patchMemo
:
(
state
,
action
:
PayloadAction
<
Partial
<
Memo
>>
)
=>
{
state
.
memos
=
state
.
memos
.
map
((
m
)
=>
{
if
(
m
.
id
===
action
.
payload
.
id
)
{
return
{
...
m
,
...
action
.
payload
,
};
}
else
{
return
m
;
}
});
},
deleteMemo
:
(
state
,
action
:
PayloadAction
<
MemoId
>
)
=>
{
state
.
memos
=
[...
state
.
memos
].
filter
((
memo
)
=>
memo
.
id
!==
action
.
payload
);
},
},
});
export
const
{
setMemos
,
setTags
,
createMemo
,
patchMemo
,
deleteMemo
}
=
memoSlice
.
actions
;
export
default
memoSlice
.
reducer
;
web/src/store/modules/shortcut.ts
0 → 100644
View file @
c2e5a1a5
import
{
createSlice
,
PayloadAction
}
from
"@reduxjs/toolkit"
;
interface
State
{
shortcuts
:
Shortcut
[];
}
const
shortcutSlice
=
createSlice
({
name
:
"memo"
,
initialState
:
{
shortcuts
:
[],
}
as
State
,
reducers
:
{
setShortcuts
:
(
state
,
action
:
PayloadAction
<
Shortcut
[]
>
)
=>
{
state
.
shortcuts
=
action
.
payload
;
},
createShortcut
:
(
state
,
action
:
PayloadAction
<
Shortcut
>
)
=>
{
state
.
shortcuts
=
state
.
shortcuts
.
concat
(
action
.
payload
);
},
patchShortcut
:
(
state
,
action
:
PayloadAction
<
Partial
<
Shortcut
>>
)
=>
{
state
.
shortcuts
=
state
.
shortcuts
.
map
((
s
)
=>
{
if
(
s
.
id
===
action
.
payload
.
id
)
{
return
{
...
s
,
...
action
.
payload
,
};
}
else
{
return
s
;
}
});
},
deleteShortcut
:
(
state
,
action
:
PayloadAction
<
ShortcutId
>
)
=>
{
state
.
shortcuts
=
[...
state
.
shortcuts
].
filter
((
shortcut
)
=>
shortcut
.
id
!==
action
.
payload
);
},
},
});
export
const
{
setShortcuts
,
createShortcut
,
patchShortcut
,
deleteShortcut
}
=
shortcutSlice
.
actions
;
export
default
shortcutSlice
.
reducer
;
web/src/store/modules/user.ts
0 → 100644
View file @
c2e5a1a5
import
{
createSlice
,
PayloadAction
}
from
"@reduxjs/toolkit"
;
interface
State
{
user
?:
User
;
}
const
userSlice
=
createSlice
({
name
:
"user"
,
initialState
:
{}
as
State
,
reducers
:
{
signin
:
(
state
,
action
:
PayloadAction
<
User
>
)
=>
{
return
{
...
state
,
user
:
action
.
payload
,
};
},
signout
:
(
state
)
=>
{
return
{
...
state
,
user
:
undefined
,
};
},
patchUser
:
(
state
,
action
:
PayloadAction
<
Partial
<
User
>>
)
=>
{
state
.
user
=
{
...
state
.
user
,
...
action
.
payload
,
}
as
User
;
},
},
});
export
const
{
signin
,
signout
,
patchUser
}
=
userSlice
.
actions
;
export
default
userSlice
.
reducer
;
web/src/stores/appContext.ts
deleted
100644 → 0
View file @
2e9152e2
import
{
createContext
}
from
"react"
;
import
appStore
from
"./appStore"
;
const
appContext
=
createContext
(
appStore
.
getState
());
export
default
appContext
;
web/src/stores/appStore.ts
deleted
100644 → 0
View file @
2e9152e2
import
combineReducers
from
"../labs/combineReducers"
;
import
createStore
from
"../labs/createStore"
;
import
*
as
globalStore
from
"./globalStateStore"
;
import
*
as
locationStore
from
"./locationStore"
;
import
*
as
memoStore
from
"./memoStore"
;
import
*
as
userStore
from
"./userStore"
;
import
*
as
shortcutStore
from
"./shortcutStore"
;
interface
AppState
{
globalState
:
globalStore
.
State
;
locationState
:
locationStore
.
State
;
memoState
:
memoStore
.
State
;
userState
:
userStore
.
State
;
shortcutState
:
shortcutStore
.
State
;
}
type
AppStateActions
=
globalStore
.
Actions
|
locationStore
.
Actions
|
memoStore
.
Actions
|
userStore
.
Actions
|
shortcutStore
.
Actions
;
const
appStore
=
createStore
<
AppState
,
AppStateActions
>
(
{
globalState
:
globalStore
.
defaultState
,
locationState
:
locationStore
.
defaultState
,
memoState
:
memoStore
.
defaultState
,
userState
:
userStore
.
defaultState
,
shortcutState
:
shortcutStore
.
defaultState
,
},
combineReducers
<
AppState
,
AppStateActions
>
({
globalState
:
globalStore
.
reducer
,
locationState
:
locationStore
.
reducer
,
memoState
:
memoStore
.
reducer
,
userState
:
userStore
.
reducer
,
shortcutState
:
shortcutStore
.
reducer
,
})
);
export
default
appStore
;
web/src/stores/globalStateStore.ts
deleted
100644 → 0
View file @
2e9152e2
import
{
UNKNOWN_ID
}
from
"../helpers/consts"
;
export
interface
AppSetting
{
shouldSplitMemoWord
:
boolean
;
shouldHideImageUrl
:
boolean
;
shouldUseMarkdownParser
:
boolean
;
}
export
interface
State
extends
AppSetting
{
markMemoId
:
MemoId
;
editMemoId
:
MemoId
;
}
interface
SetMarkMemoIdAction
{
type
:
"SET_MARK_MEMO_ID"
;
payload
:
{
markMemoId
:
MemoId
;
};
}
interface
SetEditMemoIdAction
{
type
:
"SET_EDIT_MEMO_ID"
;
payload
:
{
editMemoId
:
MemoId
;
};
}
interface
SetAppSettingAction
{
type
:
"SET_APP_SETTING"
;
payload
:
Partial
<
AppSetting
>
;
}
export
type
Actions
=
SetEditMemoIdAction
|
SetMarkMemoIdAction
|
SetAppSettingAction
;
export
function
reducer
(
state
:
State
,
action
:
Actions
)
{
switch
(
action
.
type
)
{
case
"SET_MARK_MEMO_ID"
:
{
if
(
action
.
payload
.
markMemoId
===
state
.
markMemoId
)
{
return
state
;
}
return
{
...
state
,
markMemoId
:
action
.
payload
.
markMemoId
,
};
}
case
"SET_EDIT_MEMO_ID"
:
{
if
(
action
.
payload
.
editMemoId
===
state
.
editMemoId
)
{
return
state
;
}
return
{
...
state
,
editMemoId
:
action
.
payload
.
editMemoId
,
};
}
case
"SET_APP_SETTING"
:
{
return
{
...
state
,
...
action
.
payload
,
};
}
default
:
{
return
state
;
}
}
}
export
const
defaultState
:
State
=
{
markMemoId
:
UNKNOWN_ID
,
editMemoId
:
UNKNOWN_ID
,
shouldSplitMemoWord
:
true
,
shouldHideImageUrl
:
true
,
shouldUseMarkdownParser
:
true
,
};
web/src/stores/locationStore.ts
deleted
100644 → 0
View file @
2e9152e2
export
type
State
=
AppLocation
;
interface
SetLocationAction
{
type
:
"SET_LOCATION"
;
payload
:
State
;
}
interface
SetPathnameAction
{
type
:
"SET_PATHNAME"
;
payload
:
{
pathname
:
string
;
};
}
interface
SetQueryAction
{
type
:
"SET_QUERY"
;
payload
:
Query
;
}
interface
SetShortcutIdAction
{
type
:
"SET_SHORTCUT_ID"
;
payload
:
ShortcutId
|
undefined
;
}
interface
SetTagQueryAction
{
type
:
"SET_TAG_QUERY"
;
payload
:
{
tag
:
string
;
};
}
interface
SetFromAndToQueryAction
{
type
:
"SET_DURATION_QUERY"
;
payload
:
{
duration
:
Duration
|
null
;
};
}
interface
SetTypeAction
{
type
:
"SET_TYPE"
;
payload
:
{
type
:
MemoSpecType
|
""
;
};
}
interface
SetTextAction
{
type
:
"SET_TEXT"
;
payload
:
{
text
:
string
;
};
}
interface
SetHashAction
{
type
:
"SET_HASH"
;
payload
:
{
hash
:
string
;
};
}
export
type
Actions
=
|
SetLocationAction
|
SetPathnameAction
|
SetQueryAction
|
SetTagQueryAction
|
SetFromAndToQueryAction
|
SetTypeAction
|
SetTextAction
|
SetShortcutIdAction
|
SetHashAction
;
export
function
reducer
(
state
:
State
,
action
:
Actions
)
{
switch
(
action
.
type
)
{
case
"SET_LOCATION"
:
{
return
action
.
payload
;
}
case
"SET_PATHNAME"
:
{
if
(
action
.
payload
.
pathname
===
state
.
pathname
)
{
return
state
;
}
return
{
...
state
,
pathname
:
action
.
payload
.
pathname
,
};
}
case
"SET_HASH"
:
{
if
(
action
.
payload
.
hash
===
state
.
hash
)
{
return
state
;
}
return
{
...
state
,
hash
:
action
.
payload
.
hash
,
};
}
case
"SET_QUERY"
:
{
return
{
...
state
,
query
:
{
...
action
.
payload
,
},
};
}
case
"SET_TAG_QUERY"
:
{
if
(
action
.
payload
.
tag
===
state
.
query
.
tag
)
{
return
state
;
}
return
{
...
state
,
query
:
{
...
state
.
query
,
tag
:
action
.
payload
.
tag
,
},
};
}
case
"SET_DURATION_QUERY"
:
{
if
(
action
.
payload
.
duration
===
state
.
query
.
duration
)
{
return
state
;
}
return
{
...
state
,
query
:
{
...
state
.
query
,
duration
:
{
...
state
.
query
.
duration
,
...
action
.
payload
.
duration
,
},
},
};
}
case
"SET_TYPE"
:
{
if
(
action
.
payload
.
type
===
state
.
query
.
type
)
{
return
state
;
}
return
{
...
state
,
query
:
{
...
state
.
query
,
type
:
action
.
payload
.
type
,
},
};
}
case
"SET_TEXT"
:
{
if
(
action
.
payload
.
text
===
state
.
query
.
text
)
{
return
state
;
}
return
{
...
state
,
query
:
{
...
state
.
query
,
text
:
action
.
payload
.
text
,
},
};
}
case
"SET_SHORTCUT_ID"
:
{
if
(
action
.
payload
===
state
.
query
.
shortcutId
)
{
return
state
;
}
return
{
...
state
,
query
:
{
...
state
.
query
,
shortcutId
:
action
.
payload
,
},
};
}
default
:
{
return
state
;
}
}
}
export
const
defaultState
:
State
=
{
pathname
:
"/"
,
hash
:
""
,
query
:
{
tag
:
""
,
duration
:
null
,
type
:
""
,
text
:
""
,
},
};
web/src/stores/memoStore.ts
deleted
100644 → 0
View file @
2e9152e2
import
utils
from
"../helpers/utils"
;
export
interface
State
{
memos
:
Memo
[];
tags
:
string
[];
}
interface
SetMemosAction
{
type
:
"SET_MEMOS"
;
payload
:
{
memos
:
Memo
[];
};
}
interface
SetTagsAction
{
type
:
"SET_TAGS"
;
payload
:
{
tags
:
string
[];
};
}
interface
InsertMemoAction
{
type
:
"INSERT_MEMO"
;
payload
:
{
memo
:
Memo
;
};
}
interface
DeleteMemoByIdAction
{
type
:
"DELETE_MEMO_BY_ID"
;
payload
:
{
id
:
MemoId
;
};
}
interface
EditMemoByIdAction
{
type
:
"EDIT_MEMO"
;
payload
:
Memo
;
}
export
type
Actions
=
SetMemosAction
|
SetTagsAction
|
InsertMemoAction
|
DeleteMemoByIdAction
|
EditMemoByIdAction
;
export
function
reducer
(
state
:
State
,
action
:
Actions
):
State
{
switch
(
action
.
type
)
{
case
"SET_MEMOS"
:
{
const
memos
=
utils
.
dedupeObjectWithId
(
action
.
payload
.
memos
.
sort
((
a
,
b
)
=>
b
.
createdTs
-
a
.
createdTs
));
return
{
...
state
,
memos
:
[...
memos
],
};
}
case
"SET_TAGS"
:
{
return
{
...
state
,
tags
:
action
.
payload
.
tags
,
};
}
case
"INSERT_MEMO"
:
{
const
memos
=
utils
.
dedupeObjectWithId
([
action
.
payload
.
memo
,
...
state
.
memos
].
sort
((
a
,
b
)
=>
b
.
createdTs
-
a
.
createdTs
));
return
{
...
state
,
memos
,
};
}
case
"DELETE_MEMO_BY_ID"
:
{
return
{
...
state
,
memos
:
[...
state
.
memos
].
filter
((
memo
)
=>
memo
.
id
!==
action
.
payload
.
id
),
};
}
case
"EDIT_MEMO"
:
{
const
memos
=
state
.
memos
.
map
((
m
)
=>
{
if
(
m
.
id
===
action
.
payload
.
id
)
{
return
{
...
m
,
...
action
.
payload
,
};
}
else
{
return
m
;
}
});
return
{
...
state
,
memos
,
};
}
default
:
{
return
state
;
}
}
}
export
const
defaultState
:
State
=
{
memos
:
[],
tags
:
[],
};
web/src/stores/shortcutStore.ts
deleted
100644 → 0
View file @
2e9152e2
import
utils
from
"../helpers/utils"
;
export
interface
State
{
shortcuts
:
Shortcut
[];
}
interface
SetShortcutsAction
{
type
:
"SET_SHORTCUTS"
;
payload
:
{
shortcuts
:
Shortcut
[];
};
}
interface
InsertShortcutAction
{
type
:
"INSERT_SHORTCUT"
;
payload
:
{
shortcut
:
Shortcut
;
};
}
interface
DeleteShortcutByIdAction
{
type
:
"DELETE_SHORTCUT_BY_ID"
;
payload
:
{
id
:
ShortcutId
;
};
}
interface
UpdateShortcutAction
{
type
:
"UPDATE_SHORTCUT"
;
payload
:
Shortcut
;
}
export
type
Actions
=
SetShortcutsAction
|
InsertShortcutAction
|
DeleteShortcutByIdAction
|
UpdateShortcutAction
;
export
function
reducer
(
state
:
State
,
action
:
Actions
):
State
{
switch
(
action
.
type
)
{
case
"SET_SHORTCUTS"
:
{
const
shortcuts
=
utils
.
dedupeObjectWithId
(
action
.
payload
.
shortcuts
.
sort
((
a
,
b
)
=>
utils
.
getTimeStampByDate
(
b
.
createdTs
)
-
utils
.
getTimeStampByDate
(
a
.
createdTs
))
.
sort
((
a
,
b
)
=>
utils
.
getTimeStampByDate
(
b
.
updatedTs
)
-
utils
.
getTimeStampByDate
(
a
.
updatedTs
))
);
return
{
...
state
,
shortcuts
,
};
}
case
"INSERT_SHORTCUT"
:
{
const
shortcuts
=
utils
.
dedupeObjectWithId
(
[
action
.
payload
.
shortcut
,
...
state
.
shortcuts
].
sort
(
(
a
,
b
)
=>
utils
.
getTimeStampByDate
(
b
.
createdTs
)
-
utils
.
getTimeStampByDate
(
a
.
createdTs
)
)
);
return
{
...
state
,
shortcuts
,
};
}
case
"DELETE_SHORTCUT_BY_ID"
:
{
return
{
...
state
,
shortcuts
:
[...
state
.
shortcuts
].
filter
((
shortcut
)
=>
shortcut
.
id
!==
action
.
payload
.
id
),
};
}
case
"UPDATE_SHORTCUT"
:
{
const
shortcuts
=
state
.
shortcuts
.
map
((
m
)
=>
{
if
(
m
.
id
===
action
.
payload
.
id
)
{
return
{
...
m
,
...
action
.
payload
,
};
}
else
{
return
m
;
}
});
return
{
...
state
,
shortcuts
,
};
}
default
:
{
return
state
;
}
}
}
export
const
defaultState
:
State
=
{
shortcuts
:
[],
};
web/src/stores/userStore.ts
deleted
100644 → 0
View file @
2e9152e2
export
interface
State
{
user
:
User
|
null
;
}
interface
SignInAction
{
type
:
"LOGIN"
;
payload
:
State
;
}
interface
SignOutAction
{
type
:
"SIGN_OUT"
;
payload
:
null
;
}
interface
ResetOpenIdAction
{
type
:
"RESET_OPENID"
;
payload
:
string
;
}
export
type
Actions
=
SignInAction
|
SignOutAction
|
ResetOpenIdAction
;
export
function
reducer
(
state
:
State
,
action
:
Actions
):
State
{
switch
(
action
.
type
)
{
case
"LOGIN"
:
{
return
{
user
:
action
.
payload
.
user
,
};
}
case
"SIGN_OUT"
:
{
return
{
user
:
null
,
};
}
case
"RESET_OPENID"
:
{
if
(
!
state
.
user
)
{
return
state
;
}
return
{
user
:
{
...
state
.
user
,
openId
:
action
.
payload
,
},
};
}
default
:
{
return
state
;
}
}
}
export
const
defaultState
:
State
=
{
user
:
null
};
web/src/types/common.d.ts
View file @
c2e5a1a5
...
@@ -9,3 +9,5 @@ type FunctionType = (...args: unknown[]) => unknown;
...
@@ -9,3 +9,5 @@ type FunctionType = (...args: unknown[]) => unknown;
interface
KVObject
<
T
=
any
>
{
interface
KVObject
<
T
=
any
>
{
[
key
:
string
]:
T
;
[
key
:
string
]:
T
;
}
}
type
Option
<
T
>
=
T
|
undefined
;
web/src/types/location.d.ts
View file @
c2e5a1a5
...
@@ -4,10 +4,10 @@ interface Duration {
...
@@ -4,10 +4,10 @@ interface Duration {
}
}
interface
Query
{
interface
Query
{
tag
:
string
;
tag
?
:
string
;
duration
:
Duration
|
null
;
duration
?:
Duration
;
type
:
MemoSpecType
|
""
;
type
?:
MemoSpecType
;
text
:
string
;
text
?
:
string
;
shortcutId
?:
ShortcutId
;
shortcutId
?:
ShortcutId
;
}
}
...
...
web/yarn.lock
View file @
c2e5a1a5
...
@@ -202,6 +202,13 @@
...
@@ -202,6 +202,13 @@
"@babel/plugin-syntax-jsx" "^7.16.7"
"@babel/plugin-syntax-jsx" "^7.16.7"
"@babel/types" "^7.17.0"
"@babel/types" "^7.17.0"
"@babel/runtime@^7.12.1", "@babel/runtime@^7.9.2":
version "7.18.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.0.tgz#6d77142a19cb6088f0af662af1ada37a604d34ae"
integrity sha512-YMQvx/6nKEaucl0MY56mwIG483xk8SDNdlUwb2Ts6FUpr7fm85DxEmsY18LXBNhcTz6tO6JwZV8w1W06v8UKeg==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/template@^7.16.7":
"@babel/template@^7.16.7":
version "7.16.7"
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155"
...
@@ -303,6 +310,16 @@
...
@@ -303,6 +310,16 @@
"@nodelib/fs.scandir" "2.1.5"
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
fastq "^1.6.0"
"@reduxjs/toolkit@^1.8.1":
version "1.8.1"
resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.8.1.tgz#94ee1981b8cf9227cda40163a04704a9544c9a9f"
integrity sha512-Q6mzbTpO9nOYRnkwpDlFOAbQnd3g7zj7CtHAZWz5SzE5lcV97Tf8f3SzOO8BoPOMYBFgfZaqTUZqgGu+a0+Fng==
dependencies:
immer "^9.0.7"
redux "^4.1.2"
redux-thunk "^2.4.1"
reselect "^4.1.5"
"@rollup/pluginutils@^4.2.0":
"@rollup/pluginutils@^4.2.0":
version "4.2.1"
version "4.2.1"
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d"
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d"
...
@@ -311,6 +328,14 @@
...
@@ -311,6 +328,14 @@
estree-walker "^2.0.1"
estree-walker "^2.0.1"
picomatch "^2.2.2"
picomatch "^2.2.2"
"@types/hoist-non-react-statics@^3.3.1":
version "3.3.1"
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
dependencies:
"@types/react" "*"
hoist-non-react-statics "^3.3.0"
"@types/json-schema@^7.0.9":
"@types/json-schema@^7.0.9":
version "7.0.11"
version "7.0.11"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
...
@@ -363,6 +388,11 @@
...
@@ -363,6 +388,11 @@
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
"@types/use-sync-external-store@^0.0.3":
version "0.0.3"
resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43"
integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==
"@typescript-eslint/eslint-plugin@^5.6.0":
"@typescript-eslint/eslint-plugin@^5.6.0":
version "5.19.0"
version "5.19.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.19.0.tgz#9608a4b6d0427104bccf132f058cba629a6553c0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.19.0.tgz#9608a4b6d0427104bccf132f058cba629a6553c0"
...
@@ -1340,6 +1370,13 @@ has@^1.0.3:
...
@@ -1340,6 +1370,13 @@ has@^1.0.3:
dependencies:
dependencies:
function-bind "^1.1.1"
function-bind "^1.1.1"
hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
dependencies:
react-is "^16.7.0"
iconv-lite@^0.4.4:
iconv-lite@^0.4.4:
version "0.4.24"
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
...
@@ -1357,6 +1394,11 @@ image-size@~0.5.0:
...
@@ -1357,6 +1394,11 @@ image-size@~0.5.0:
resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"
resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"
integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=
integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=
immer@^9.0.7:
version "9.0.14"
resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.14.tgz#e05b83b63999d26382bb71676c9d827831248a48"
integrity sha512-ubBeqQutOSLIFCUBN03jGeOS6a3DoYlSYwYJTa+gSKEZKU5redJIqkIdZ3JVv/4RZpfcXdAWH5zCNLWPRv2WDw==
import-fresh@^3.0.0, import-fresh@^3.2.1:
import-fresh@^3.0.0, import-fresh@^3.2.1:
version "3.3.0"
version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
...
@@ -1913,11 +1955,28 @@ react-dom@^18.1.0:
...
@@ -1913,11 +1955,28 @@ react-dom@^18.1.0:
loose-envify "^1.1.0"
loose-envify "^1.1.0"
scheduler "^0.22.0"
scheduler "^0.22.0"
react-is@^16.13.1:
react-is@^16.13.1
, react-is@^16.7.0
:
version "16.13.1"
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-is@^18.0.0:
version "18.1.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.1.0.tgz#61aaed3096d30eacf2a2127118b5b41387d32a67"
integrity sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==
react-redux@^8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.0.1.tgz#2bc029f5ada9b443107914c373a2750f6bc0f40c"
integrity sha512-LMZMsPY4DYdZfLJgd7i79n5Kps5N9XVLCJJeWAaPYTV+Eah2zTuBjTxKtNEbjiyitbq80/eIkm55CYSLqAub3w==
dependencies:
"@babel/runtime" "^7.12.1"
"@types/hoist-non-react-statics" "^3.3.1"
"@types/use-sync-external-store" "^0.0.3"
hoist-non-react-statics "^3.3.2"
react-is "^18.0.0"
use-sync-external-store "^1.0.0"
react-refresh@^0.12.0:
react-refresh@^0.12.0:
version "0.12.0"
version "0.12.0"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.12.0.tgz#28ac0a2c30ef2bb3433d5fd0621e69a6d774c3a4"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.12.0.tgz#28ac0a2c30ef2bb3433d5fd0621e69a6d774c3a4"
...
@@ -1937,6 +1996,23 @@ readdirp@~3.6.0:
...
@@ -1937,6 +1996,23 @@ readdirp@~3.6.0:
dependencies:
dependencies:
picomatch "^2.2.1"
picomatch "^2.2.1"
redux-thunk@^2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.1.tgz#0dd8042cf47868f4b29699941de03c9301a75714"
integrity sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==
redux@^4.1.2:
version "4.2.0"
resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.0.tgz#46f10d6e29b6666df758780437651eeb2b969f13"
integrity sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==
dependencies:
"@babel/runtime" "^7.9.2"
regenerator-runtime@^0.13.4:
version "0.13.9"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
regexp.prototype.flags@^1.4.1:
regexp.prototype.flags@^1.4.1:
version "1.4.2"
version "1.4.2"
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.2.tgz#bf635117a2f4b755595ebb0c0ee2d2a49b2084db"
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.2.tgz#bf635117a2f4b755595ebb0c0ee2d2a49b2084db"
...
@@ -1950,6 +2026,11 @@ regexpp@^3.2.0:
...
@@ -1950,6 +2026,11 @@ regexpp@^3.2.0:
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
reselect@^4.1.5:
version "4.1.5"
resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.5.tgz#852c361247198da6756d07d9296c2b51eddb79f6"
integrity sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ==
resolve-from@^4.0.0:
resolve-from@^4.0.0:
version "4.0.0"
version "4.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
...
@@ -2234,6 +2315,11 @@ uri-js@^4.2.2:
...
@@ -2234,6 +2315,11 @@ uri-js@^4.2.2:
dependencies:
dependencies:
punycode "^2.1.0"
punycode "^2.1.0"
use-sync-external-store@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.1.0.tgz#3343c3fe7f7e404db70f8c687adf5c1652d34e82"
integrity sha512-SEnieB2FPKEVne66NpXPd1Np4R1lTNKfjuy3XdIoPQKYBAFdzbzSZlSn1KJZUiihQLQC5Znot4SBz1EOTBwQAQ==
util-deprecate@^1.0.2:
util-deprecate@^1.0.2:
version "1.0.2"
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
...
...
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