diff --git a/src/components/PreferencesModal/GeneralTab.tsx b/src/components/PreferencesModal/GeneralTab.tsx index 182721f2b5..cdb98f8d6f 100644 --- a/src/components/PreferencesModal/GeneralTab.tsx +++ b/src/components/PreferencesModal/GeneralTab.tsx @@ -18,7 +18,6 @@ import { useUsers } from '../../lib/accounts' import UserInfo from './UserInfo' import LoginButton from '../atoms/LoginButton' import { useAnalytics, analyticsEvents } from '../../lib/analytics' -import { IconArrowRotate } from '../icons' import { FormCheckItem } from '../atoms/form' const GeneralTab = () => { @@ -81,10 +80,7 @@ const GeneralTab = () => { loginState !== 'logging-in' ? ( <>{t('preferences.addAccount')} ) : ( - <> - - {t('preferences.loginWorking')} - + <>{t('preferences.loginWorking')} ) } diff --git a/src/components/PreferencesModal/PreferencesModal.tsx b/src/components/PreferencesModal/PreferencesModal.tsx index 4b4e7fde30..48d0deaeef 100644 --- a/src/components/PreferencesModal/PreferencesModal.tsx +++ b/src/components/PreferencesModal/PreferencesModal.tsx @@ -13,8 +13,9 @@ import { backgroundColor, closeIconColor, } from '../../lib/styled/styleFunctions' -import { IconClose } from '../icons' import { useTranslation } from 'react-i18next' +import Icon from '../atoms/Icon' +import { mdiClose } from '@mdi/js' const Container = styled.div` z-index: 7000; @@ -143,7 +144,7 @@ const PreferencesModal = () => { {content} - + ) diff --git a/src/components/atoms/ButtonIcon.tsx b/src/components/atoms/ButtonIcon.tsx index 2474cac672..d0c5334e5d 100644 --- a/src/components/atoms/ButtonIcon.tsx +++ b/src/components/atoms/ButtonIcon.tsx @@ -1,5 +1,6 @@ import React from 'react' import styled from '../../lib/styled' +import Icon from './Icon' const StyledButtonIcon = styled.button` color: currentColor; @@ -14,14 +15,14 @@ const StyledButtonIcon = styled.button` ` interface ButtonIconProps { - icon: React.ReactNode + iconPath: string className?: string onClick?: () => void } -const ButtonIcon = ({ icon, className, onClick }: ButtonIconProps) => ( +const ButtonIcon = ({ iconPath, className, onClick }: ButtonIconProps) => ( - {icon} + ) diff --git a/src/components/atoms/PageContainer.tsx b/src/components/atoms/PageContainer.tsx index bf4ddbaefd..cd852f4727 100644 --- a/src/components/atoms/PageContainer.tsx +++ b/src/components/atoms/PageContainer.tsx @@ -1,7 +1,7 @@ import styled from '../../lib/styled' const PageContainer = styled.div` - padding: 3rem; + padding: 1em; height: 100%; overflow-y: auto; ` diff --git a/src/components/atoms/ToolbarIconInput.tsx b/src/components/atoms/ToolbarIconInput.tsx deleted file mode 100644 index 95b70c9fed..0000000000 --- a/src/components/atoms/ToolbarIconInput.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import React from 'react' -import styled from '../../lib/styled' -import ButtonIcon from './ButtonIcon' -const StyledContainer = styled.div` - position: relative; - height: 22px; - .icon { - position: absolute; - top: 4px; - left: 4px; - height: 14px; - width: 14px; - z-index: 0; - } - .input { - position: relative; - width: 100%; - background-color: transparent; - border: solid 1px ${({ theme }) => theme.colors.border}; - height: 22px; - padding-left: 18px; - border-radius: 2px; - box-sizing: border-box; - } -` - -interface ToolbarIconInputProps { - className?: string - icon: React.ReactNode - value: string - onChange: React.ChangeEventHandler -} - -const ToolbarIconInput = ({ - className, - icon, - value, - onChange, -}: ToolbarIconInputProps) => { - return ( - - - - - ) -} - -export default ToolbarIconInput diff --git a/src/components/icons/AddRound.tsx b/src/components/icons/AddRound.tsx deleted file mode 100644 index 6af70fcc1c..0000000000 --- a/src/components/icons/AddRound.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconAddRound = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/AdjustVertical.tsx b/src/components/icons/AdjustVertical.tsx deleted file mode 100644 index 52b09cdff7..0000000000 --- a/src/components/icons/AdjustVertical.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconAdjustVertical = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/Alert.tsx b/src/components/icons/Alert.tsx deleted file mode 100644 index 2b754b3482..0000000000 --- a/src/components/icons/Alert.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconAlert = (props: BoostnoteIconProps) => ( - - - - - - - - -) diff --git a/src/components/icons/Alphabet.tsx b/src/components/icons/Alphabet.tsx deleted file mode 100644 index a437bf7c24..0000000000 --- a/src/components/icons/Alphabet.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconAlphabet = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/ArrowAgain.tsx b/src/components/icons/ArrowAgain.tsx deleted file mode 100644 index 146e365242..0000000000 --- a/src/components/icons/ArrowAgain.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconArrowAgain = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/ArrowOutput.tsx b/src/components/icons/ArrowOutput.tsx deleted file mode 100644 index 0d3e312c34..0000000000 --- a/src/components/icons/ArrowOutput.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconArrowOutput = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/ArrowRotate.tsx b/src/components/icons/ArrowRotate.tsx deleted file mode 100644 index 22a239c3c5..0000000000 --- a/src/components/icons/ArrowRotate.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconArrowRotate = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/Bold.tsx b/src/components/icons/Bold.tsx deleted file mode 100644 index 5ea233cdd5..0000000000 --- a/src/components/icons/Bold.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconBold = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/Book.tsx b/src/components/icons/Book.tsx deleted file mode 100644 index 8a9c11132e..0000000000 --- a/src/components/icons/Book.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconBook = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/Check.tsx b/src/components/icons/Check.tsx deleted file mode 100644 index cedf3e1b2e..0000000000 --- a/src/components/icons/Check.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconCheck = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/CheckActive.tsx b/src/components/icons/CheckActive.tsx deleted file mode 100644 index d57990f2a4..0000000000 --- a/src/components/icons/CheckActive.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconCheckActive = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/Close.tsx b/src/components/icons/Close.tsx deleted file mode 100644 index 24b178e1e8..0000000000 --- a/src/components/icons/Close.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconClose = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/Edit.tsx b/src/components/icons/Edit.tsx deleted file mode 100644 index 8785d1b2d8..0000000000 --- a/src/components/icons/Edit.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconEdit = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/EditView.tsx b/src/components/icons/EditView.tsx deleted file mode 100644 index f1b7f120b9..0000000000 --- a/src/components/icons/EditView.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconEditView = (props: BoostnoteIconProps) => ( - - - - - - - - -) diff --git a/src/components/icons/Eye.tsx b/src/components/icons/Eye.tsx deleted file mode 100644 index bd1ed51472..0000000000 --- a/src/components/icons/Eye.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconEye = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/File.tsx b/src/components/icons/File.tsx deleted file mode 100644 index 7150c3eb60..0000000000 --- a/src/components/icons/File.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconFile = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/FileOpen.tsx b/src/components/icons/FileOpen.tsx deleted file mode 100644 index 17dc6d50f6..0000000000 --- a/src/components/icons/FileOpen.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconFileOpen = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/Hash.tsx b/src/components/icons/Hash.tsx deleted file mode 100644 index 51c3530698..0000000000 --- a/src/components/icons/Hash.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconHash = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/HelpOutline.tsx b/src/components/icons/HelpOutline.tsx deleted file mode 100644 index 3125930ad3..0000000000 --- a/src/components/icons/HelpOutline.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconHelpOutline = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/Image.tsx b/src/components/icons/Image.tsx deleted file mode 100644 index b124a813f2..0000000000 --- a/src/components/icons/Image.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconImage = (props: BoostnoteIconProps) => ( - - - - - - - - -) diff --git a/src/components/icons/Info.tsx b/src/components/icons/Info.tsx deleted file mode 100644 index 435602a814..0000000000 --- a/src/components/icons/Info.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconInfo = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/Italic.tsx b/src/components/icons/Italic.tsx deleted file mode 100644 index 35358a35e4..0000000000 --- a/src/components/icons/Italic.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconItalic = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/LineThrough.tsx b/src/components/icons/LineThrough.tsx deleted file mode 100644 index 69051b1798..0000000000 --- a/src/components/icons/LineThrough.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconLineThrough = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/Link.tsx b/src/components/icons/Link.tsx deleted file mode 100644 index e3d41a3d30..0000000000 --- a/src/components/icons/Link.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconLink = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/List.tsx b/src/components/icons/List.tsx deleted file mode 100644 index 7b9fc48e43..0000000000 --- a/src/components/icons/List.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconList = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/Loupe.tsx b/src/components/icons/Loupe.tsx deleted file mode 100644 index 4d689a7665..0000000000 --- a/src/components/icons/Loupe.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconLoupe = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/Preview.tsx b/src/components/icons/Preview.tsx deleted file mode 100644 index b732dc2144..0000000000 --- a/src/components/icons/Preview.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconPreview = (props: BoostnoteIconProps) => ( - - - - - - - - -) diff --git a/src/components/icons/Quote.tsx b/src/components/icons/Quote.tsx deleted file mode 100644 index 734b03933d..0000000000 --- a/src/components/icons/Quote.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconQuote = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/Radio.tsx b/src/components/icons/Radio.tsx deleted file mode 100644 index 288b0a01cc..0000000000 --- a/src/components/icons/Radio.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconRadio = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/RadioActive.tsx b/src/components/icons/RadioActive.tsx deleted file mode 100644 index 18e22b6685..0000000000 --- a/src/components/icons/RadioActive.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconRadioActive = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/Setting.tsx b/src/components/icons/Setting.tsx deleted file mode 100644 index 79070054e4..0000000000 --- a/src/components/icons/Setting.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconSetting = (props: BoostnoteIconProps) => ( - - - - - - - - -) diff --git a/src/components/icons/Split.tsx b/src/components/icons/Split.tsx deleted file mode 100644 index d0de3e036c..0000000000 --- a/src/components/icons/Split.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconSplit = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/SplitView.tsx b/src/components/icons/SplitView.tsx deleted file mode 100644 index a0555b3e74..0000000000 --- a/src/components/icons/SplitView.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconSplitView = (props: BoostnoteIconProps) => ( - - - - - - - - -) diff --git a/src/components/icons/Star.tsx b/src/components/icons/Star.tsx deleted file mode 100644 index 61f177f9bf..0000000000 --- a/src/components/icons/Star.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconStar = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/StarActive.tsx b/src/components/icons/StarActive.tsx deleted file mode 100644 index 95c6635f05..0000000000 --- a/src/components/icons/StarActive.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconStarActive = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/T1.tsx b/src/components/icons/T1.tsx deleted file mode 100644 index 583163402e..0000000000 --- a/src/components/icons/T1.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconT1 = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/T2.tsx b/src/components/icons/T2.tsx deleted file mode 100644 index 9a7e817c0a..0000000000 --- a/src/components/icons/T2.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconT2 = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/T3.tsx b/src/components/icons/T3.tsx deleted file mode 100644 index 4d3024cf84..0000000000 --- a/src/components/icons/T3.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconT3 = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/Tag.tsx b/src/components/icons/Tag.tsx deleted file mode 100644 index 03a846b20b..0000000000 --- a/src/components/icons/Tag.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconTag = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/TagFill.tsx b/src/components/icons/TagFill.tsx deleted file mode 100644 index dac1a0b3e5..0000000000 --- a/src/components/icons/TagFill.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconTagFill = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/Tags.tsx b/src/components/icons/Tags.tsx deleted file mode 100644 index effb1f7da5..0000000000 --- a/src/components/icons/Tags.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconTags = (props: BoostnoteIconProps) => ( - - - - - - - - -) diff --git a/src/components/icons/Trash.tsx b/src/components/icons/Trash.tsx deleted file mode 100644 index 3d25106a76..0000000000 --- a/src/components/icons/Trash.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconTrash = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/TrashFill.tsx b/src/components/icons/TrashFill.tsx deleted file mode 100644 index 75fb14b5c4..0000000000 --- a/src/components/icons/TrashFill.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconTrashFill = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/Underline.tsx b/src/components/icons/Underline.tsx deleted file mode 100644 index 90e8936de8..0000000000 --- a/src/components/icons/Underline.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - BoostnoteIconProps, - BoostnoteIconStyledContainer, -} from '../../lib/icons' -import React from 'react' - -export const IconUnderline = (props: BoostnoteIconProps) => ( - - - - - -) diff --git a/src/components/icons/index.ts b/src/components/icons/index.ts deleted file mode 100644 index 6c65278f4f..0000000000 --- a/src/components/icons/index.ts +++ /dev/null @@ -1,44 +0,0 @@ -export * from './AddRound' -export * from './AdjustVertical' -export * from './Alert' -export * from './Alphabet' -export * from './ArrowAgain' -export * from './ArrowOutput' -export * from './ArrowRotate' -export * from './Bold' -export * from './Book' -export * from './Check' -export * from './CheckActive' -export * from './Close' -export * from './Edit' -export * from './EditView' -export * from './Eye' -export * from './File' -export * from './FileOpen' -export * from './Hash' -export * from './HelpOutline' -export * from './Image' -export * from './Info' -export * from './Italic' -export * from './LineThrough' -export * from './Link' -export * from './List' -export * from './Loupe' -export * from './Preview' -export * from './Quote' -export * from './Radio' -export * from './RadioActive' -export * from './Setting' -export * from './Split' -export * from './SplitView' -export * from './Star' -export * from './StarActive' -export * from './T1' -export * from './T2' -export * from './T3' -export * from './Tag' -export * from './TagFill' -export * from './Tags' -export * from './Trash' -export * from './TrashFill' -export * from './Underline' diff --git a/src/components/molecules/StorageNavigatorFragment.tsx b/src/components/molecules/StorageNavigatorFragment.tsx index a264fa8e19..4250299bb9 100644 --- a/src/components/molecules/StorageNavigatorFragment.tsx +++ b/src/components/molecules/StorageNavigatorFragment.tsx @@ -101,7 +101,7 @@ const StorageNavigatorFragment = ({ }) } - const syncThisStorage = () => { + const sync = () => { if (user == null) { pushMessage({ title: 'No User Error', @@ -148,7 +148,7 @@ const StorageNavigatorFragment = ({ { type: MenuTypes.Normal, label: 'Sync Storage', - onClick: syncThisStorage, + onClick: sync, }, { type: MenuTypes.Normal, @@ -241,7 +241,7 @@ const StorageNavigatorFragment = ({ {storage.cloudStorage != null && ( diff --git a/src/lib/db/NoteDb.spec.ts b/src/lib/db/NoteDb.spec.ts index 526f579e05..fc9274ed1f 100644 --- a/src/lib/db/NoteDb.spec.ts +++ b/src/lib/db/NoteDb.spec.ts @@ -421,7 +421,7 @@ describe('NoteDb', () => { content: 'test content', tags: [], bookmarked: false, - folderPathname: '/default', + folderPathname: '/', data: {}, createdAt: expect.any(String), updatedAt: expect.any(String), @@ -436,7 +436,7 @@ describe('NoteDb', () => { content: 'test content', tags: [], bookmarked: false, - folderPathname: '/default', + folderPathname: '/', data: {}, createdAt: expect.any(String), updatedAt: expect.any(String), @@ -502,7 +502,7 @@ describe('NoteDb', () => { content: 'changed content', tags: [], bookmarked: false, - folderPathname: '/default', + folderPathname: '/', data: {}, createdAt: expect.any(String), updatedAt: expect.any(String), @@ -517,7 +517,7 @@ describe('NoteDb', () => { content: 'changed content', tags: [], bookmarked: false, - folderPathname: '/default', + folderPathname: '/', data: {}, createdAt: expect.any(String), updatedAt: expect.any(String), @@ -646,19 +646,19 @@ describe('NoteDb', () => { const note1 = await noteDb.createNote({ title: 'test title1', content: 'test content1', - folderPathname: '/default', + folderPathname: '/', tags: ['tag1'], }) const note2 = await noteDb.createNote({ title: 'test title2', content: 'test content2', - folderPathname: '/default', + folderPathname: '/', tags: ['tag1', 'tag2'], }) const note3 = await noteDb.createNote({ title: 'test title3', content: 'test content3', - folderPathname: '/default', + folderPathname: '/', tags: ['tag2'], }) @@ -672,7 +672,7 @@ describe('NoteDb', () => { _rev: note1._rev, title: 'test title1', content: 'test content1', - folderPathname: '/default', + folderPathname: '/', tags: ['tag1'], bookmarked: false, data: {}, @@ -685,7 +685,7 @@ describe('NoteDb', () => { _rev: note2._rev, title: 'test title2', content: 'test content2', - folderPathname: '/default', + folderPathname: '/', tags: ['tag1', 'tag2'], bookmarked: false, data: {}, @@ -705,7 +705,7 @@ describe('NoteDb', () => { _rev: note2._rev, title: 'test title2', content: 'test content2', - folderPathname: '/default', + folderPathname: '/', tags: ['tag1', 'tag2'], data: {}, bookmarked: false, @@ -718,7 +718,7 @@ describe('NoteDb', () => { _rev: note3._rev, title: 'test title3', content: 'test content3', - folderPathname: '/default', + folderPathname: '/', tags: ['tag2'], bookmarked: false, data: {}, @@ -887,13 +887,13 @@ describe('NoteDb', () => { const note1 = await noteDb.createNote({ title: 'test title1', content: 'test content1', - folderPathname: '/default', + folderPathname: '/', tags: ['tag1'], }) const note2 = await noteDb.createNote({ title: 'test title2', content: 'test content2', - folderPathname: '/default', + folderPathname: '/', tags: ['tag1', 'tag2'], }) diff --git a/src/lib/db/NoteDb.ts b/src/lib/db/NoteDb.ts index 6324ca5422..9747f84962 100644 --- a/src/lib/db/NoteDb.ts +++ b/src/lib/db/NoteDb.ts @@ -222,7 +222,7 @@ export default class NoteDb { title: '', content: '', tags: [], - folderPathname: '/default', + folderPathname: '/', data: {}, bookmarked: false, ...noteProps, diff --git a/src/lib/db/utils.ts b/src/lib/db/utils.ts index 5fa67d6e3e..0be6c60295 100644 --- a/src/lib/db/utils.ts +++ b/src/lib/db/utils.ts @@ -31,6 +31,11 @@ export function getParentFolderPathname(pathname: string): string { return join(pathname, '..') } +export function getFolderNameFromPathname(pathname: string): string | null { + if (pathname === '/') return null + return pathname.split('/').slice(-1)[0] +} + export function getTagId(name: string): string { return `${TAG_ID_PREFIX}${name}` } diff --git a/src/lib/router/redirect.ts b/src/lib/router/redirect.ts index c3c9bd5552..144605b068 100644 --- a/src/lib/router/redirect.ts +++ b/src/lib/router/redirect.ts @@ -11,7 +11,9 @@ export default function useRedirectHandler() { useEffect(() => { const storageEntries = entries(storageMapRef.current) - if (pathname !== '/app') return + if (pathname !== '/app') { + return + } if (storageEntries.length === 0) { replace('/app/storages') diff --git a/src/lib/styled/styleFunctions.ts b/src/lib/styled/styleFunctions.ts index 2426e33cbb..d9f6531a37 100644 --- a/src/lib/styled/styleFunctions.ts +++ b/src/lib/styled/styleFunctions.ts @@ -194,3 +194,8 @@ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; ` + +export const flexCenter = () => `display: flex; +align-items: center; +justify-content: center; +` diff --git a/src/mobile/components/App.tsx b/src/mobile/components/App.tsx index 02a820b7e1..8cce2b659a 100644 --- a/src/mobile/components/App.tsx +++ b/src/mobile/components/App.tsx @@ -1,5 +1,5 @@ import React from 'react' -import Navigator from './Navigator' +import Navigator from './organisms/Navigator' import GlobalStyle from '../../components/GlobalStyle' import { ThemeProvider } from 'styled-components' import { darkTheme } from '../../themes/dark' diff --git a/src/mobile/components/ErrorBoundary.tsx b/src/mobile/components/ErrorBoundary.tsx index 53d433d070..0962193ced 100644 --- a/src/mobile/components/ErrorBoundary.tsx +++ b/src/mobile/components/ErrorBoundary.tsx @@ -72,7 +72,7 @@ class ErrorBoundary extends React.Component<{}, ErrorBoundaryState> { - +

Error!

Please click button

diff --git a/src/mobile/components/Navigator/ControlButton.tsx b/src/mobile/components/Navigator/ControlButton.tsx deleted file mode 100644 index 6ca3740aef..0000000000 --- a/src/mobile/components/Navigator/ControlButton.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react' -import styled from '../../../lib/styled' - -const StyledButton = styled.button` - position: relative; - right: 9px; - width: 30px; - padding: 0; - border: none; - background-color: transparent; - border-radius: 2px; - font-size: 20px; - line-height: 20px; - cursor: pointer; - vertical-align: middle; - color: ${({ theme }) => theme.sideNavLabelColor}; - &:hover, - &:active, - &:focus { - box-shadow: none; - } - + button { - top: -1px; - } -` - -interface ControlButtonProps { - icon: React.ReactNode - onClick?: (event: React.MouseEvent) => void -} - -const ControlButton = ({ icon, onClick }: ControlButtonProps) => { - return {icon} -} - -export default ControlButton diff --git a/src/mobile/components/Navigator/Navigator.tsx b/src/mobile/components/Navigator/Navigator.tsx deleted file mode 100644 index e18dfc9497..0000000000 --- a/src/mobile/components/Navigator/Navigator.tsx +++ /dev/null @@ -1,423 +0,0 @@ -import React, { useMemo, useCallback } from 'react' -import { useRouter, usePathnameWithoutNoteId } from '../../lib/router' -import { useDb } from '../../lib/db' -import { entries } from '../../../lib/db/utils' -import styled from '../../../lib/styled' -import { useDialog, DialogIconTypes } from '../../../lib/dialog' -import { useContextMenu, MenuTypes } from '../../../lib/contextMenu' -import { usePreferences } from '../../../lib/preferences' -import NavigatorItem from './NavigatorItem' -import { useGeneralStatus } from '../../lib/generalStatus' -import ControlButton from './ControlButton' -import FolderListFragment from './FolderListFragment' -import TagListFragment from './TagListFragment' -import { useUsers } from '../../../lib/accounts' -import { useToast } from '../../../lib/toast' -import { useTranslation } from 'react-i18next' -import { - IconAddRound, - IconAdjustVertical, - IconArrowAgain, - IconTrash, - IconSetting, - IconBook, -} from '../../../components/icons' -import Icon from '../../../components/atoms/Icon' -import { mdiClose } from '@mdi/js' - -const Description = styled.nav` - margin-left: 15px; - margin-bottom: 10px; - font-size: 18px; -` - -const StyledSideNavContainer = styled.nav` - display: flex; - background-color: ${({ theme }) => theme.sideNavBackgroundColor}; - flex-direction: column; - height: 100%; - .topControl { - height: 50px; - display: flex; - -webkit-app-region: drag; - .spacer { - flex: 1; - } - .button { - width: 50px; - height: 50px; - background-color: transparent; - border: none; - cursor: pointer; - font-size: 24px; - - transition: color 200ms ease-in-out; - color: ${({ theme }) => theme.sideNavButtonColor}; - &:hover { - color: ${({ theme }) => theme.sideNavButtonHoverColor}; - } - - &:active, - .active { - color: ${({ theme }) => theme.sideNavButtonActiveColor}; - } - } - } - - .storageList { - list-style: none; - padding: 0; - margin: 0; - flex: 1; - overflow: auto; - display: flex; - flex-direction: column; - } - - .empty { - padding: 4px; - padding-left: 26px; - margin-bottom: 4px; - color: ${({ theme }) => theme.sideNavLabelColor}; - user-select: none; - } - - .bottomControl { - height: 35px; - display: flex; - border-top: 1px solid ${({ theme }) => theme.colors.border}; - button { - height: 35px; - border: none; - background-color: transparent; - display: flex; - align-items: center; - } - .addFolderButton { - flex: 1; - border-right: 1px solid ${({ theme }) => theme.colors.border}; - } - .addFolderButtonIcon { - margin-right: 4px; - } - .moreButton { - width: 30px; - display: flex; - justify-content: center; - } - } -` - -const CreateStorageButton = styled.button` - position: absolute; - right: 8px; - border: none; - background-color: transparent; - cursor: pointer; - transition: color 200ms ease-in-out; - color: ${({ theme }) => theme.sideNavButtonColor}; - &:hover { - color: ${({ theme }) => theme.sideNavButtonHoverColor}; - } - - &:active, - .active { - color: ${({ theme }) => theme.sideNavButtonActiveColor}; - } -` - -const Spacer = styled.div` - flex: 1; -` - -interface NavigatorProps { - toggle: () => void -} - -export default ({ toggle }: NavigatorProps) => { - const { - createStorage, - createFolder, - renameFolder, - renameStorage, - removeStorage, - storageMap, - syncStorage, - } = useDb() - const { popup } = useContextMenu() - const { prompt, messageBox } = useDialog() - const { push } = useRouter() - const [[user]] = useUsers() - const { pushMessage } = useToast() - - const storageEntries = useMemo(() => { - return entries(storageMap) - }, [storageMap]) - - const openSideNavContextMenu = useCallback( - (event: React.MouseEvent) => { - event.preventDefault() - popup(event, [ - { - type: MenuTypes.Normal, - label: 'New Storage', - onClick: async () => { - prompt({ - title: 'Create a Storage', - message: 'Enter name of a storage to create', - iconType: DialogIconTypes.Question, - submitButtonLabel: 'Create Storage', - onClose: async (value: string | null) => { - if (value == null) return - const storage = await createStorage(value) - push(`/m/storages/${storage.id}/notes`) - }, - }) - }, - }, - ]) - }, - [popup, prompt, createStorage, push] - ) - - const { toggleClosed } = usePreferences() - const { - toggleSideNavOpenedItem, - sideNavOpenedItemSet, - openSideNavFolderItemRecursively, - toggleNav, - } = useGeneralStatus() - - const currentPathname = usePathnameWithoutNoteId() - - const { t } = useTranslation() - - return ( - -
- -
- -
- - - Storages - { - push('/m/storages') - toggleNav() - }} - > - - - - -
- {storageEntries.map(([, storage]) => { - const itemId = `storage:${storage.id}` - const storageIsFolded = !sideNavOpenedItemSet.has(itemId) - const showPromptToCreateFolder = (folderPathname: string) => { - prompt({ - title: 'Create a Folder', - message: 'Enter the path where do you want to create a folder', - iconType: DialogIconTypes.Question, - defaultValue: folderPathname === '/' ? '/' : `${folderPathname}/`, - submitButtonLabel: 'Create Folder', - onClose: async (value: string | null) => { - if (value == null) { - return - } - if (value.endsWith('/')) { - value = value.slice(0, value.length - 1) - } - await createFolder(storage.id, value) - - push(`/m/storages/${storage.id}/notes${value}`) - - // Open folder item - openSideNavFolderItemRecursively(storage.id, value) - }, - }) - } - const showPromptToRenameFolder = (folderPathname: string) => { - prompt({ - title: t('folder.rename'), - message: t('folder.renameMessage'), - iconType: DialogIconTypes.Question, - defaultValue: folderPathname.split('/').pop(), - submitButtonLabel: t('folder.rename'), - onClose: async (value: string | null) => { - const folderPathSplit = folderPathname.split('/') - if ( - value == null || - value === '' || - value === folderPathSplit.pop() - ) { - return - } - const newPathname = folderPathSplit.join('/') + '/' + value - try { - await renameFolder(storage.id, folderPathname, newPathname) - push(`/m/storages/${storage.id}/notes${newPathname}`) - openSideNavFolderItemRecursively(storage.id, newPathname) - } catch (error) { - pushMessage({ - title: t('general.error'), - description: t('folder.renameErrorMessage'), - }) - } - }, - }) - } - - const allNotesPagePathname = `/m/storages/${storage.id}/notes` - const allNotesPageIsActive = currentPathname === allNotesPagePathname - - const trashcanPagePathname = `/m/storages/${storage.id}/trashcan` - const trashcanPageIsActive = currentPathname === trashcanPagePathname - - const controlComponents = [ - showPromptToCreateFolder('/')} - icon={} - />, - ] - - if (storage.cloudStorage != null && user != null) { - const cloudSync = () => { - if (user == null) { - pushMessage({ - title: 'No User Error', - description: 'Please login first to sync the storage.', - }) - } - syncStorage(storage.id) - } - - controlComponents.unshift( - } - /> - ) - } - - controlComponents.unshift( - { - push(`/m/storages/${storage.id}/settings`) - toggleNav() - }} - icon={} - /> - ) - - return ( - - { - toggleSideNavOpenedItem(itemId) - }} - onClick={() => { - toggleSideNavOpenedItem(itemId) - }} - onContextMenu={(event) => { - event.preventDefault() - popup(event, [ - { - type: MenuTypes.Normal, - label: t('storage.rename'), - onClick: async () => { - prompt({ - title: `Rename "${storage.name}" storage`, - message: t('storage.renameMessage'), - iconType: DialogIconTypes.Question, - defaultValue: storage.name, - submitButtonLabel: t('storage.rename'), - onClose: async (value: string | null) => { - if (value == null) return - await renameStorage(storage.id, value) - }, - }) - }, - }, - { - type: MenuTypes.Normal, - label: t('storage.remove'), - onClick: async () => { - messageBox({ - title: `Remove "${storage.name}" storage`, - message: t('storage.removeMessage'), - iconType: DialogIconTypes.Warning, - buttons: [t('storage.remove'), t('general.cancel')], - defaultButtonIndex: 0, - cancelButtonIndex: 1, - onClose: (value: number | null) => { - if (value === 0) { - removeStorage(storage.id) - } - }, - }) - }, - }, - ]) - }} - controlComponents={controlComponents} - /> - {!storageIsFolded && ( - <> - } - active={allNotesPageIsActive} - onClick={() => { - push(allNotesPagePathname) - toggleNav() - }} - /> - - - - : } - active={trashcanPageIsActive} - onClick={() => { - push(trashcanPagePathname) - toggleNav() - }} - onContextMenu={(event) => { - event.preventDefault() - // TODO: Implement context menu(restore all notes) - }} - /> - - )} - - ) - })} - {storageEntries.length === 0 && ( -
{t('storage.noStorage')}
- )} - - -
- - ) -} diff --git a/src/mobile/components/Navigator/NavigatorItem.tsx b/src/mobile/components/Navigator/NavigatorItem.tsx deleted file mode 100644 index 028f989e38..0000000000 --- a/src/mobile/components/Navigator/NavigatorItem.tsx +++ /dev/null @@ -1,219 +0,0 @@ -import React from 'react' -import cc from 'classcat' -import styled from '../../../lib/styled' -import { activeBackgroundColor } from '../../../lib/styled/styleFunctions' -import Icon from '../../../components/atoms/Icon' -import { mdiChevronRight, mdiChevronDown } from '@mdi/js' - -const Container = styled.div` - position: relative; - user-select: none; - height: 34px; - display: flex; - justify-content: space-between; - - .sideNavWrapper { - min-width: 0; - flex: 1 1 auto; - - button > span { - width: 30px; - transition: color 200ms ease-in-out; - color: ${({ theme }) => theme.sideNavButtonColor}; - &:hover { - color: ${({ theme }) => theme.sideNavButtonHoverColor}; - } - - &:active, - .active { - color: ${({ theme }) => theme.sideNavButtonActiveColor}; - } - } - } - - transition: 200ms background-color; - &:hover, - &:focus, - &:active, - &.active { - ${activeBackgroundColor} - - button > span { - color: ${({ theme }) => theme.sideNavButtonColor}; - } - } - &:hover { - cursor: pointer; - } - - &.allnotes-sidenav { - padding-left: 4px !important; - button { - padding-left: 6px !important; - } - } - &.bookmark-sidenav { - padding-left: 4px !important; - margin-bottom: 25px; - button { - padding-left: 6px !important; - } - } -` - -const FoldButton = styled.button` - position: absolute; - width: 26px; - height: 26px; - padding-left: 10px; - border: none; - background-color: transparent; - margin-right: 3px; - border-radius: 2px; - flex: 0 0 26px; - top: 5px; - color: ${({ theme }) => theme.sideNavButtonColor}; - &:focus { - box-shadow: none; - } -` - -const ClickableContainer = styled.button` - background-color: transparent; - border: none; - height: 35px; - display: flex; - align-items: center; - min-width: 0; - width: 100%; - flex: 1 1 auto; - - color: ${({ theme }) => theme.sideNavLabelColor}; - - .icon { - flex: 0 0 auto; - margin-right: 4px; - color: ${({ theme }) => theme.sideNavButtonColor}; - &:hover { - color: ${({ theme }) => theme.sideNavButtonHoverColor}; - } - - &:active, - .active { - color: ${({ theme }) => theme.sideNavButtonActiveColor}; - } - } -` - -const Label = styled.div` - min-width: 0; - overflow: hidden; - white-space: nowrap; - flex: 1 1 auto; - text-align: left; -` - -const ControlContainer = styled.div` - position: absolute; - right: 0; - top: 4px; - padding-left: 10px; - display: flex; - flex: 2 0 auto; - justify-content: flex-end; - button { - transition: color 200ms ease-in-out; - color: ${({ theme }) => theme.sideNavButtonColor}; - &:hover { - color: ${({ theme }) => theme.sideNavButtonHoverColor}; - } - - &:active, - .active { - color: ${({ theme }) => theme.sideNavButtonActiveColor}; - } - } -` - -const SideNavigatorItemIconContainer = styled.span` - padding-right: 6px; -` - -interface NavigatorItemProps { - label: string - icon?: React.ReactNode - depth: number - controlComponents?: any[] - className?: string - folded?: boolean - active?: boolean - onFoldButtonClick?: (event: React.MouseEvent) => void - onClick?: (event: React.MouseEvent) => void - onContextMenu?: (event: React.MouseEvent) => void - onDrop?: (event: React.DragEvent) => void - onDragOver?: (event: React.DragEvent) => void - onDragEnd?: (event: React.DragEvent) => void - onDoubleClick?: (event: React.MouseEvent) => void -} - -const NavigatorItem = ({ - label, - icon, - depth, - controlComponents, - className, - folded, - active, - onFoldButtonClick, - onClick, - onDoubleClick, - onContextMenu, - onDrop, - onDragOver, - onDragEnd, -}: NavigatorItemProps) => { - return ( - -
- {folded != null && ( - - - - )} - - {icon != null && ( - - {icon} - - )} - - -
- {controlComponents && ( - - {controlComponents} - - )} -
- ) -} - -export default NavigatorItem diff --git a/src/mobile/components/Navigator/index.ts b/src/mobile/components/Navigator/index.ts deleted file mode 100644 index 49e364d97a..0000000000 --- a/src/mobile/components/Navigator/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import SideNavigator from './Navigator' - -export default SideNavigator diff --git a/src/mobile/components/atoms/ControlButton.tsx b/src/mobile/components/atoms/ControlButton.tsx new file mode 100644 index 0000000000..e3c67e89ae --- /dev/null +++ b/src/mobile/components/atoms/ControlButton.tsx @@ -0,0 +1,43 @@ +import React from 'react' +import styled from '../../../lib/styled' +import Icon from '../../../components/atoms/Icon' + +const StyledButton = styled.button` + display: flex; + align-items: center; + justify-content: center; + height: 34px; + width: 29px; + padding: 0; + border: none; + background-color: transparent; + font-size: 18px; + cursor: pointer; + color: ${({ theme }) => theme.sideNavButtonColor}; + + &.active { + color: ${({ theme }) => theme.sideNavButtonActiveColor}; + } +` + +interface ControlButtonProps { + iconPath: string + onClick?: (event: React.MouseEvent) => void + spin?: boolean + active?: boolean +} + +const ControlButton = ({ + iconPath, + spin, + onClick, + active = false, +}: ControlButtonProps) => { + return ( + + + + ) +} + +export default ControlButton diff --git a/src/mobile/components/atoms/NavigatorItem.tsx b/src/mobile/components/atoms/NavigatorItem.tsx new file mode 100644 index 0000000000..a5221fe55e --- /dev/null +++ b/src/mobile/components/atoms/NavigatorItem.tsx @@ -0,0 +1,108 @@ +import React from 'react' +import cc from 'classcat' +import styled from '../../../lib/styled' +import { textOverflow } from '../../../lib/styled/styleFunctions' +import Icon from '../../../components/atoms/Icon' +import { mdiChevronRight, mdiChevronDown } from '@mdi/js' + +const Container = styled.div` + position: relative; + user-select: none; + height: 34px; + display: flex; + &.active { + background-color: ${({ theme }) => theme.sideNavItemActiveBackgroundColor}; + } +` + +const FoldButton = styled.button` + position: absolute; + width: 24px; + height: 34px; + left: 0; + border: none; + background-color: transparent; + color: ${({ theme }) => theme.sideNavButtonColor}; +` + +const ClickableContainer = styled.button` + height: 34px; + display: flex; + align-items: center; + flex: 1; + + background-color: transparent; + border: none; + color: ${({ theme }) => theme.sideNavLabelColor}; +` + +const Label = styled.div` + min-width: 0; + margin-left: 0.25em; + text-align: left; + ${textOverflow} +` + +const Control = styled.div` + position: absolute; + right: 0; + height: 34px; + display: flex; + align-items: center; +` + +interface NavigatorItemProps { + label: string + iconPath?: string + depth: number + control?: React.ReactNode + className?: string + folded?: boolean + active?: boolean + onFoldButtonClick?: (event: React.MouseEvent) => void + onClick?: (event: React.MouseEvent) => void + onContextMenu?: (event: React.MouseEvent) => void + onDrop?: (event: React.DragEvent) => void + onDragOver?: (event: React.DragEvent) => void + onDragEnd?: (event: React.DragEvent) => void + onDoubleClick?: (event: React.MouseEvent) => void +} + +const NavigatorItem = ({ + label, + iconPath, + depth, + control, + className, + folded, + active, + onFoldButtonClick, + onClick, +}: NavigatorItemProps) => { + return ( + + {folded != null && ( + + + + )} + + {iconPath != null && } + + + {control && {control}} + + ) +} + +export default NavigatorItem diff --git a/src/mobile/components/layouts/TopBarLayout.tsx b/src/mobile/components/layouts/TopBarLayout.tsx index b6992c9daf..3efd8b110d 100644 --- a/src/mobile/components/layouts/TopBarLayout.tsx +++ b/src/mobile/components/layouts/TopBarLayout.tsx @@ -1,6 +1,11 @@ import React, { CSSProperties } from 'react' import styled from '../../../lib/styled' -import { borderBottom } from '../../../lib/styled/styleFunctions' +import { + borderBottom, + textOverflow, + flexCenter, +} from '../../../lib/styled/styleFunctions' +import Icon from '../../../components/atoms/Icon' const TopBarLayoutContainer = styled.div` display: flex; @@ -15,9 +20,7 @@ const TopBar = styled.div` height: 44px; position: relative; ${borderBottom} - display: flex; - align-items: center; - justify-content: center; + ${flexCenter} ` const TopBarLeftControl = styled.div` @@ -37,7 +40,19 @@ const TopBarRightControl = styled.div` const TopBarTitle = styled.div` height: 44px; - line-height: 44px; + flex: 1; + padding: 0 88px; + overflow: hidden; + ${flexCenter} +` + +const TopBarTitleIcon = styled.div` + padding-right: 0.25em; + ${flexCenter} +` + +const TopBarTitleLabel = styled.div` + ${textOverflow} ` const ContentContainer = styled.div` @@ -46,14 +61,16 @@ const ContentContainer = styled.div` ` interface TopBarLayoutProps { - title?: React.ReactNode + titleLabel?: React.ReactNode + titleIconPath?: string style?: CSSProperties leftControl?: React.ReactNode rightControl?: React.ReactNode } const TopBarLayout: React.FC = ({ - title, + titleLabel, + titleIconPath, children, style, leftControl, @@ -62,7 +79,14 @@ const TopBarLayout: React.FC = ({ {leftControl} - {title} + + {titleIconPath != null && ( + + + + )} + {titleLabel} + {rightControl} {children} diff --git a/src/mobile/components/Navigator/FolderListFragment.tsx b/src/mobile/components/molecules/FolderListFragment.tsx similarity index 87% rename from src/mobile/components/Navigator/FolderListFragment.tsx rename to src/mobile/components/molecules/FolderListFragment.tsx index d1a72839cd..d3d1810ed0 100644 --- a/src/mobile/components/Navigator/FolderListFragment.tsx +++ b/src/mobile/components/molecules/FolderListFragment.tsx @@ -2,30 +2,32 @@ import React, { useMemo } from 'react' import { useDb } from '../../lib/db' import { useDialog, DialogIconTypes } from '../../../lib/dialog' import { useContextMenu, MenuTypes } from '../../../lib/contextMenu' -import NavigatorItem from './NavigatorItem' +import NavigatorItem from '../atoms/NavigatorItem' import { NoteStorage } from '../../../lib/db/types' import { usePathnameWithoutNoteId, useRouter } from '../../lib/router' import { useGeneralStatus } from '../../lib/generalStatus' -import ControlButton from './ControlButton' +import ControlButton from '../atoms/ControlButton' import { getFolderItemId } from '../../../lib/nav' -import { IconAddRound, IconFile, IconFileOpen } from '../../../components/icons' import { useTranslation } from 'react-i18next' +import { mdiFolder, mdiFolderOpen, mdiDotsVertical } from '@mdi/js' interface FolderListFragmentProps { storage: NoteStorage + createNoteToFolder: (folderPathname: string) => void showPromptToCreateFolder: (folderPathname: string) => void showPromptToRenameFolder: (folderPathname: string) => void } const FolderListFragment = ({ storage, + createNoteToFolder, showPromptToCreateFolder, showPromptToRenameFolder, }: FolderListFragmentProps) => { const { removeFolder } = useDb() const { push } = useRouter() const { messageBox } = useDialog() - const { popup } = useContextMenu() + const { popupWithPosition } = useContextMenu() const { t } = useTranslation() const { folderMap, id: storageId } = storage @@ -57,9 +59,15 @@ const FolderListFragment = ({ storageId: string, folderPathname: string ) => { - return (event: React.MouseEvent) => { - event.preventDefault() - popup(event, [ + return () => { + popupWithPosition({ x: 0, y: 0 }, [ + { + type: MenuTypes.Normal, + label: 'New Note', + onClick: () => { + createNoteToFolder(folderPathname) + }, + }, { type: MenuTypes.Normal, label: t('folder.create'), @@ -67,6 +75,8 @@ const FolderListFragment = ({ showPromptToCreateFolder(folderPathname) }, }, + { type: MenuTypes.Separator }, + { type: MenuTypes.Normal, label: t('folder.rename'), @@ -141,22 +151,16 @@ const FolderListFragment = ({ folded={folded} depth={depth} active={folderIsActive} - icon={folderIsActive ? : } + iconPath={folderIsActive ? mdiFolderOpen : mdiFolder} label={folderName} onClick={createOnFolderItemClickHandler(folderPathname)} - onDoubleClick={() => showPromptToRenameFolder(folderPathname)} - onContextMenu={createOnContextMenuHandler( - storage.id, - folderPathname - )} onFoldButtonClick={() => toggleSideNavOpenedItem(itemId)} - controlComponents={[ + control={ showPromptToCreateFolder(folderPathname)} - icon={} - />, - ]} + onClick={createOnContextMenuHandler(storageId, folderPathname)} + iconPath={mdiDotsVertical} + /> + } /> ) })} diff --git a/src/mobile/components/molecules/StorageNavigatorFragment.tsx b/src/mobile/components/molecules/StorageNavigatorFragment.tsx new file mode 100644 index 0000000000..a85f2e2a5d --- /dev/null +++ b/src/mobile/components/molecules/StorageNavigatorFragment.tsx @@ -0,0 +1,303 @@ +import React, { useCallback, useMemo } from 'react' +import { useRouter, usePathnameWithoutNoteId } from '../../lib/router' +import { useDb } from '../../lib/db' +import { useDialog, DialogIconTypes } from '../../../lib/dialog' +import { useContextMenu, MenuTypes } from '../../../lib/contextMenu' +import { useFirstUser } from '../../../lib/preferences' +import NavigatorItem from '../atoms/NavigatorItem' +import { useGeneralStatus } from '../../lib/generalStatus' +import ControlButton from '../atoms/ControlButton' +import FolderListFragment from '../molecules/FolderListFragment' +import TagListFragment from '../molecules/TagListFragment' +import { useToast } from '../../../lib/toast' +import { useTranslation } from 'react-i18next' +import { mdiTrashCan, mdiBookOpen, mdiSync, mdiDotsVertical } from '@mdi/js' +import { NoteStorage } from '../../../lib/db/types' +import { dispatchNoteDetailFocusTitleInputEvent } from '../../../lib/events' + +interface StorageNavigatorFragmentProps { + storage: NoteStorage +} + +const StorageNavigatorFragment = ({ + storage, +}: StorageNavigatorFragmentProps) => { + const { + createFolder, + renameFolder, + renameStorage, + removeStorage, + syncStorage, + createNote, + } = useDb() + const currentPathname = usePathnameWithoutNoteId() + + const { + toggleSideNavOpenedItem, + sideNavOpenedItemSet, + openSideNavFolderItemRecursively, + toggleNav, + } = useGeneralStatus() + + const { t } = useTranslation() + const { popupWithPosition } = useContextMenu() + const { prompt, messageBox } = useDialog() + const { push } = useRouter() + const user = useFirstUser() + const { pushMessage } = useToast() + const itemId = `storage:${storage.id}` + const storageIsFolded = !sideNavOpenedItemSet.has(itemId) + + const showPromptToCreateFolder = useCallback( + (folderPathname: string) => { + prompt({ + title: 'Create a Folder', + message: 'Enter the path where do you want to create a folder', + iconType: DialogIconTypes.Question, + defaultValue: folderPathname === '/' ? '/' : `${folderPathname}/`, + submitButtonLabel: 'Create Folder', + onClose: async (value: string | null) => { + if (value == null) { + return + } + if (value.endsWith('/')) { + value = value.slice(0, value.length - 1) + } + await createFolder(storage.id, value) + + push(`/m/storages/${storage.id}/notes${value}`) + + // Open folder item + openSideNavFolderItemRecursively(storage.id, value) + }, + }) + }, + [createFolder, prompt, push, storage.id, openSideNavFolderItemRecursively] + ) + + const showPromptToRenameFolder = (folderPathname: string) => { + prompt({ + title: t('folder.rename'), + message: t('folder.renameMessage'), + iconType: DialogIconTypes.Question, + defaultValue: folderPathname.split('/').pop(), + submitButtonLabel: t('folder.rename'), + onClose: async (value: string | null) => { + const folderPathSplit = folderPathname.split('/') + if (value == null || value === '' || value === folderPathSplit.pop()) { + return + } + const newPathname = folderPathSplit.join('/') + '/' + value + try { + await renameFolder(storage.id, folderPathname, newPathname) + push(`/m/storages/${storage.id}/notes${newPathname}`) + openSideNavFolderItemRecursively(storage.id, newPathname) + } catch (error) { + pushMessage({ + title: t('general.error'), + description: t('folder.renameErrorMessage'), + }) + } + }, + }) + } + + const allNotesPagePathname = `/m/storages/${storage.id}/notes` + const allNotesPageIsActive = currentPathname === allNotesPagePathname + + const trashcanPagePathname = `/m/storages/${storage.id}/trashcan` + const trashcanPageIsActive = currentPathname === trashcanPagePathname + + const sync = useCallback(() => { + if (user == null) { + pushMessage({ + title: 'No User Error', + description: 'Please login first to sync the storage.', + }) + } + syncStorage(storage.id) + }, [user, pushMessage, syncStorage, storage.id]) + + const createNoteToFolder = useCallback( + async (folderPathname: string) => { + const newNote = await createNote(storage.id, { + folderPathname, + }) + if (newNote == null) { + return + } + console.log(folderPathname) + + const notePathname = + newNote.folderPathname === '/' + ? `/m/storages/${storage.id}/notes/${newNote._id}` + : `/m/storages/${storage.id}/notes${newNote.folderPathname}/${newNote._id}` + push(notePathname) + toggleNav() + dispatchNoteDetailFocusTitleInputEvent() + }, + [createNote, push, toggleNav, storage.id] + ) + + const openStorageContextMenu = useCallback(() => { + popupWithPosition({ x: 0, y: 0 }, [ + { + type: MenuTypes.Normal, + label: 'New Note', + onClick: async () => { + createNoteToFolder('/') + }, + }, + { + type: MenuTypes.Normal, + label: 'New Folder', + onClick: async () => { + showPromptToCreateFolder('/') + }, + }, + { type: MenuTypes.Separator }, + { + type: MenuTypes.Normal, + label: 'Sync Storage', + onClick: sync, + }, + { + type: MenuTypes.Normal, + label: t('storage.rename'), + onClick: async () => { + prompt({ + title: `Rename "${storage.name}" storage`, + message: t('storage.renameMessage'), + iconType: DialogIconTypes.Question, + defaultValue: storage.name, + submitButtonLabel: t('storage.rename'), + onClose: async (value: string | null) => { + if (value == null) { + return + } + renameStorage(storage.id, value) + }, + }) + }, + }, + { + type: MenuTypes.Normal, + label: 'Configure Storage', + onClick: async () => { + toggleNav() + push(`/m/storages/${storage.id}/settings`) + }, + }, + { type: MenuTypes.Separator }, + { + type: MenuTypes.Normal, + label: t('storage.remove'), + onClick: async () => { + messageBox({ + title: `Remove "${storage.name}" storage`, + message: t('storage.removeMessage'), + iconType: DialogIconTypes.Warning, + buttons: [t('storage.remove'), t('general.cancel')], + defaultButtonIndex: 0, + cancelButtonIndex: 1, + onClose: (value: number | null) => { + if (value === 0) { + removeStorage(storage.id) + } + }, + }) + }, + }, + ]) + }, [ + popupWithPosition, + showPromptToCreateFolder, + sync, + push, + prompt, + messageBox, + createNoteToFolder, + renameStorage, + toggleNav, + removeStorage, + storage.id, + storage.name, + t, + ]) + + const syncing = storage.sync != null + + const trashed = useMemo( + () => Object.values(storage.noteMap).filter((note) => note!.trashed), + [storage.noteMap] + ) + return ( + <> + { + toggleSideNavOpenedItem(itemId) + }} + onClick={() => { + toggleSideNavOpenedItem(itemId) + }} + control={ + <> + + + + } + /> + {!storageIsFolded && ( + <> + { + push(allNotesPagePathname) + toggleNav() + }} + /> + + + + {trashed.length > 0 && ( + { + push(trashcanPagePathname) + toggleNav() + }} + onContextMenu={(event) => { + event.preventDefault() + // TODO: Implement context menu(restore all notes) + }} + /> + )} + + )} + + ) +} + +export default StorageNavigatorFragment diff --git a/src/mobile/components/molecules/TagList.tsx b/src/mobile/components/molecules/TagList.tsx index fb8899e157..723555524c 100644 --- a/src/mobile/components/molecules/TagList.tsx +++ b/src/mobile/components/molecules/TagList.tsx @@ -2,7 +2,8 @@ import React, { useCallback } from 'react' import ButtonIcon from '../../../components/atoms/ButtonIcon' import styled from '../../../lib/styled' import { noteListIconColor } from '../../../lib/styled/styleFunctions' -import { IconTag, IconClose } from '../../../components/icons' +import Icon from '../../../components/atoms/Icon' +import { mdiClose, mdiTagMultiple } from '@mdi/js' interface TagListItemProps { tagName: string @@ -18,7 +19,7 @@ const TagListItem = ({ tagName, removeTagByName }: TagListItemProps) => {
{tagName}
) @@ -79,7 +80,7 @@ interface TagListProps { const TagList = ({ tags, removeTagByName }: TagListProps) => { return ( - } /> + {tags.map((tag) => ( { : } + iconPath={mdiPound} label={tagName} onClick={() => { push(tagPathname) @@ -83,11 +83,15 @@ const TagListFragment = ({ storage }: TagListFragmentProps) => { toggleNav, ]) + if (tagList.length === 0) { + return null + } + return ( <> } + iconPath={mdiTagMultiple} label={t('tag.tag')} folded={tagList.length > 0 ? tagListIsFolded : undefined} onFoldButtonClick={() => { diff --git a/src/mobile/components/organisms/ContextMenu.tsx b/src/mobile/components/organisms/ContextMenu.tsx index 5a65b4b7a4..19cf9cd7f0 100644 --- a/src/mobile/components/organisms/ContextMenu.tsx +++ b/src/mobile/components/organisms/ContextMenu.tsx @@ -78,6 +78,14 @@ const ContextMenuItem = styled.button` } ` +const SeparatorContextMenuItem = styled.div` + height: 10px; + box-sizing: border-box; + background-color: ${({ theme }) => theme.borderColor}; + border: none; + width: 100%; +` + interface ContextMenuProps { contextMenu: ContextMenuContext } @@ -137,6 +145,8 @@ class ContextMenu extends React.Component { {menu.label} ) + case MenuTypes.Separator: + return default: return ( diff --git a/src/mobile/components/organisms/GeneralPreferencesTab.tsx b/src/mobile/components/organisms/GeneralPreferencesTab.tsx index 7e1b9aaf32..80d15d3900 100644 --- a/src/mobile/components/organisms/GeneralPreferencesTab.tsx +++ b/src/mobile/components/organisms/GeneralPreferencesTab.tsx @@ -8,7 +8,6 @@ import { import LoginButton from '../../../components/atoms/LoginButton' import UserInfo from '../molecules/UserInfo' import { useUsers } from '../../../lib/accounts' -import { IconArrowRotate } from '../../../components/icons' import { FormCheckItem } from '../../../components/atoms/form' import { usePreferences } from '../../../lib/preferences' @@ -39,14 +38,7 @@ const GeneralPreferencesTab = () => { ButtonComponent={SectionPrimaryButton} > {(loginState) => - loginState !== 'logging-in' ? ( - <>Sign in - ) : ( - <> - - Loggin in... - - ) + loginState !== 'logging-in' ? <>Sign in : <>Loggin in... } )} diff --git a/src/mobile/components/organisms/Navigator.tsx b/src/mobile/components/organisms/Navigator.tsx new file mode 100644 index 0000000000..7aa3c038c9 --- /dev/null +++ b/src/mobile/components/organisms/Navigator.tsx @@ -0,0 +1,175 @@ +import React, { useMemo, useCallback } from 'react' +import { useRouter } from '../../lib/router' +import { useDb } from '../../lib/db' +import { entries } from '../../../lib/db/utils' +import styled from '../../../lib/styled' +import { useDialog, DialogIconTypes } from '../../../lib/dialog' +import { useContextMenu, MenuTypes } from '../../../lib/contextMenu' +import { usePreferences } from '../../../lib/preferences' +import { useGeneralStatus } from '../../lib/generalStatus' +import { useTranslation } from 'react-i18next' +import Icon from '../../../components/atoms/Icon' +import { mdiClose, mdiPlus, mdiTuneVertical } from '@mdi/js' +import StorageNavigatorFragment from '../molecules/StorageNavigatorFragment' +import { borderBottom } from '../../../lib/styled/styleFunctions' + +const StyledSideNavContainer = styled.nav` + display: flex; + background-color: ${({ theme }) => theme.sideNavBackgroundColor}; + flex-direction: column; + height: 100%; + .topControl { + height: 44px; + display: flex; + -webkit-app-region: drag; + ${borderBottom} + .spacer { + flex: 1; + } + .button { + width: 44px; + height: 44px; + background-color: transparent; + border: none; + cursor: pointer; + font-size: 24px; + + transition: color 200ms ease-in-out; + color: ${({ theme }) => theme.sideNavButtonColor}; + &:hover { + color: ${({ theme }) => theme.sideNavButtonHoverColor}; + } + + &:active, + .active { + color: ${({ theme }) => theme.sideNavButtonActiveColor}; + } + } + } + + .storageList { + list-style: none; + margin: 0; + flex: 1; + overflow: auto; + display: flex; + flex-direction: column; + } + + .empty { + padding: 4px; + padding-left: 26px; + margin-bottom: 4px; + color: ${({ theme }) => theme.sideNavLabelColor}; + user-select: none; + } + + .bottomControl { + height: 35px; + display: flex; + border-top: 1px solid ${({ theme }) => theme.colors.border}; + button { + height: 35px; + border: none; + background-color: transparent; + display: flex; + align-items: center; + } + .addFolderButton { + flex: 1; + border-right: 1px solid ${({ theme }) => theme.colors.border}; + } + .addFolderButtonIcon { + margin-right: 4px; + } + .moreButton { + width: 30px; + display: flex; + justify-content: center; + } + } +` + +const Spacer = styled.div` + flex: 1; +` + +interface NavigatorProps { + toggle: () => void +} + +export default ({ toggle }: NavigatorProps) => { + const { createStorage, storageMap } = useDb() + const { popup } = useContextMenu() + const { prompt } = useDialog() + const { push } = useRouter() + + const storageEntries = useMemo(() => { + return entries(storageMap) + }, [storageMap]) + + const openSideNavContextMenu = useCallback( + (event: React.MouseEvent) => { + event.preventDefault() + popup(event, [ + { + type: MenuTypes.Normal, + label: 'New Storage', + onClick: async () => { + prompt({ + title: 'Create a Storage', + message: 'Enter name of a storage to create', + iconType: DialogIconTypes.Question, + submitButtonLabel: 'Create Storage', + onClose: async (value: string | null) => { + if (value == null) return + const storage = await createStorage(value) + push(`/m/storages/${storage.id}/notes`) + }, + }) + }, + }, + ]) + }, + [popup, prompt, createStorage, push] + ) + + const { toggleClosed } = usePreferences() + const { toggleNav } = useGeneralStatus() + + const { t } = useTranslation() + + return ( + +
+ +
+ + +
+ +
+ {storageEntries.map(([, storage]) => ( + + ))} + {storageEntries.length === 0 && ( +
{t('storage.noStorage')}
+ )} + + +
+ + ) +} diff --git a/src/mobile/components/organisms/NoteItem.tsx b/src/mobile/components/organisms/NoteItem.tsx index 7f3b9a773c..4d291470b6 100644 --- a/src/mobile/components/organisms/NoteItem.tsx +++ b/src/mobile/components/organisms/NoteItem.tsx @@ -13,8 +13,9 @@ import { useDb } from '../../lib/db' import { useDialog, DialogIconTypes } from '../../../lib/dialog' import { useTranslation } from 'react-i18next' import { useRouter } from '../../lib/router' -import { IconTrash } from '../../../components/icons' import { NoteDoc } from '../../../lib/db/types' +import { mdiTrashCan } from '@mdi/js' +import Icon from '../../../components/atoms/Icon' export const NoteListItemContainer = styled.div` margin: 0; @@ -352,7 +353,7 @@ export default ({ } }} > - + diff --git a/src/mobile/components/organisms/PreferencesModal.tsx b/src/mobile/components/organisms/PreferencesModal.tsx index f3c9c17b8c..d20ec2a3ec 100644 --- a/src/mobile/components/organisms/PreferencesModal.tsx +++ b/src/mobile/components/organisms/PreferencesModal.tsx @@ -54,7 +54,7 @@ const PreferencesModal = () => { return ( @@ -70,7 +70,7 @@ const PreferencesModal = () => { return ( diff --git a/src/mobile/components/pages/AttachmentsPage.tsx b/src/mobile/components/pages/AttachmentsPage.tsx index a8f7dbd909..09ba3a5211 100644 --- a/src/mobile/components/pages/AttachmentsPage.tsx +++ b/src/mobile/components/pages/AttachmentsPage.tsx @@ -18,7 +18,7 @@ const AttachmentsPage = () => { return ( } - title={<>Attachments in {storage.name}} + titleLabel={`Attachments in ${storage.name}`} > diff --git a/src/mobile/components/pages/NotePage.tsx b/src/mobile/components/pages/NotePage.tsx index 480f91e8a3..8a45cde030 100644 --- a/src/mobile/components/pages/NotePage.tsx +++ b/src/mobile/components/pages/NotePage.tsx @@ -16,11 +16,19 @@ import TopBarLayout from '../layouts/TopBarLayout' import NoteDetail from '../organisms/NoteDetail' import styled from '../../../lib/styled' import Icon from '../../../components/atoms/Icon' -import { mdiChevronLeft, mdiEyeOutline, mdiDotsVertical } from '@mdi/js' +import { + mdiChevronLeft, + mdiEyeOutline, + mdiDotsVertical, + mdiFolderOpen, + mdiPound, + mdiTrashCan, + mdiBookOpen, +} from '@mdi/js' import TopBarButton from '../atoms/TopBarButton' import TopBarToggleNavButton from '../atoms/TopBarToggleNavButton' -import { IconFileOpen, IconTrash, IconTag } from '../../../components/icons' import { useContextMenu, MenuTypes } from '../../../lib/contextMenu' +import { values, getFolderNameFromPathname } from '../../../lib/db/utils' const NotePageContainer = styled.div` width: 100%; @@ -64,8 +72,11 @@ const NotePage = ({ storage }: NotePageProps) => { case 'storages.notes': const { folderPathname } = routeParams const folder = storage.folderMap[folderPathname] + if (folderPathname === '/') { + return values(storage.noteMap).filter((note) => !note.trashed) + } if (folder == null) return [] - return (Object.values(storage.noteMap) as NoteDoc[]).filter( + return values(storage.noteMap).filter( (note) => (note.folderPathname + '/').startsWith(folder.pathname + '/') && !note.trashed @@ -78,13 +89,17 @@ const NotePage = ({ storage }: NotePageProps) => { .map((noteId) => storage.noteMap[noteId]!) .filter((note) => !note.trashed) case 'storages.trashCan': - return (Object.values(storage.noteMap) as NoteDoc[]).filter( - (note) => note.trashed - ) + return values(storage.noteMap).filter((note) => note.trashed) } return [] }, [storage, routeParams]) + const sortedNotes = useMemo(() => { + return notes.slice().sort((a, b) => { + return new Date(b.updatedAt).valueOf() - new Date(a.updatedAt).valueOf() + }) + }, [notes]) + const currentNote: NoteDoc | undefined = useMemo(() => { if (storage == null || noteId == null) { return undefined @@ -147,31 +162,39 @@ const NotePage = ({ storage }: NotePageProps) => { push(currentPathnameWithoutNoteId) }, [push, currentPathnameWithoutNoteId]) - const noteListTitle = useMemo(() => { + const { titleIconPath, titleLabel } = useMemo<{ + titleIconPath?: string + titleLabel: React.ReactNode + }>(() => { switch (routeParams.name) { case 'storages.notes': - return ( - <> - {routeParams.folderPathname} in{' '} - {storage!.name} - - ) + const folderName = getFolderNameFromPathname(routeParams.folderPathname) + if (folderName === null) { + return { + titleIconPath: mdiBookOpen, + titleLabel: 'All Notes', + } + } + return { + titleIconPath: mdiFolderOpen, + titleLabel: {folderName}, + } case 'storages.tags.show': - return ( - <> - {routeParams.tagName} in {storage!.name} - - ) + return { + titleIconPath: mdiPound, + titleLabel: {routeParams.tagName}, + } case 'storages.trashCan': - return ( - <> - Trashed Notes in {storage!.name} - - ) + return { + titleIconPath: mdiTrashCan, + titleLabel: 'Trashed Notes', + } default: - return 'unknown' + return { + titleLabel: 'Unknown page', + } } - }, [routeParams, storage]) + }, [routeParams]) const toggleNoteViewMode = useCallback(() => { setGeneralStatus({ @@ -206,12 +229,13 @@ const NotePage = ({ storage }: NotePageProps) => { }} > } > { }} > { const [storageType, setStorageType] = useState<'cloud' | 'local'>('cloud') return ( - } title='New Storage'> + } + titleLabel='New Storage' + > - {t('Create new storage')} Storage Type diff --git a/src/mobile/components/pages/StorageEditPage.tsx b/src/mobile/components/pages/StorageEditPage.tsx index 73d1eec4be..4e78f663f9 100644 --- a/src/mobile/components/pages/StorageEditPage.tsx +++ b/src/mobile/components/pages/StorageEditPage.tsx @@ -63,7 +63,7 @@ const StorageEditPage = ({ storage }: StorageEditPageProps) => { return ( } - title={t('storage.edit')} + titleLabel={t('storage.edit')} > diff --git a/src/mobile/lib/redirect.ts b/src/mobile/lib/redirect.ts index eecaa377e6..1d4841e3ad 100644 --- a/src/mobile/lib/redirect.ts +++ b/src/mobile/lib/redirect.ts @@ -6,12 +6,15 @@ import { useEffectOnce } from 'react-use' export default function useRedirectHandler() { const db = useDb() - const { replace } = useRouter() + const { replace, pathname } = useRouter() const storageMapRef = useRef(db.storageMap) useEffectOnce(() => { const storageEntries = entries(storageMapRef.current) + if (pathname.startsWith('/m') && pathname !== '/m') { + return + } if (storageEntries.length === 0) { replace('/m/storages') } else { diff --git a/webpack.mobile.config.ts b/webpack.mobile.config.ts index 079038ea94..fa84e1297a 100644 --- a/webpack.mobile.config.ts +++ b/webpack.mobile.config.ts @@ -42,7 +42,7 @@ module.exports = (env, argv) => { }, { test: /\.tsx?$/, - use: [{ loader: 'ts-loader' }], + use: [{ loader: 'ts-loader', options: { transpileOnly: true } }], exclude: /node_modules/, }, {