chore: make mobile menu ui more native-like (#2594)
This commit is contained in:
@@ -6,13 +6,13 @@ import { useCallback, useMemo, useState, FunctionComponent } from 'react'
|
|||||||
import { AccountMenuPane } from './AccountMenuPane'
|
import { AccountMenuPane } from './AccountMenuPane'
|
||||||
import Menu from '@/Components/Menu/Menu'
|
import Menu from '@/Components/Menu/Menu'
|
||||||
import MenuItem from '@/Components/Menu/MenuItem'
|
import MenuItem from '@/Components/Menu/MenuItem'
|
||||||
import MenuItemSeparator from '@/Components/Menu/MenuItemSeparator'
|
|
||||||
import WorkspaceSwitcherOption from './WorkspaceSwitcher/WorkspaceSwitcherOption'
|
import WorkspaceSwitcherOption from './WorkspaceSwitcher/WorkspaceSwitcherOption'
|
||||||
import { WebApplicationGroup } from '@/Application/WebApplicationGroup'
|
import { WebApplicationGroup } from '@/Application/WebApplicationGroup'
|
||||||
import { formatLastSyncDate } from '@/Utils/DateUtils'
|
import { formatLastSyncDate } from '@/Utils/DateUtils'
|
||||||
import Spinner from '@/Components/Spinner/Spinner'
|
import Spinner from '@/Components/Spinner/Spinner'
|
||||||
import { MenuItemIconSize } from '@/Constants/TailwindClassNames'
|
import { MenuItemIconSize } from '@/Constants/TailwindClassNames'
|
||||||
import { useApplication } from '../ApplicationProvider'
|
import { useApplication } from '../ApplicationProvider'
|
||||||
|
import MenuSection from '../Menu/MenuSection'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
mainApplicationGroup: WebApplicationGroup
|
mainApplicationGroup: WebApplicationGroup
|
||||||
@@ -92,7 +92,7 @@ const GeneralAccountMenu: FunctionComponent<Props> = ({ setMenuPane, closeMenu,
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="mb-1 mt-1 hidden items-center justify-between px-3 md:flex">
|
<div className="mb-1 mt-1 hidden items-center justify-between px-4 md:flex md:px-3">
|
||||||
<div className="text-lg font-bold lg:text-base">Account</div>
|
<div className="text-lg font-bold lg:text-base">Account</div>
|
||||||
<div className="flex cursor-pointer" onClick={closeMenu}>
|
<div className="flex cursor-pointer" onClick={closeMenu}>
|
||||||
<Icon type="close" className="text-neutral" />
|
<Icon type="close" className="text-neutral" />
|
||||||
@@ -100,12 +100,12 @@ const GeneralAccountMenu: FunctionComponent<Props> = ({ setMenuPane, closeMenu,
|
|||||||
</div>
|
</div>
|
||||||
{user ? (
|
{user ? (
|
||||||
<>
|
<>
|
||||||
<div className="mb-3 px-3 text-lg text-foreground lg:text-sm">
|
<div className="mb-3 px-4 text-lg text-foreground md:px-3 lg:text-sm">
|
||||||
<div>You're signed in as:</div>
|
<div>You're signed in as:</div>
|
||||||
<div className="wrap my-0.5 font-bold">{user.email}</div>
|
<div className="wrap my-0.5 font-bold">{user.email}</div>
|
||||||
<span className="text-neutral">{application.getHost.execute().getValue()}</span>
|
<span className="text-neutral">{application.getHost.execute().getValue()}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-2 flex items-start justify-between px-3 text-mobile-menu-item md:text-tablet-menu-item lg:text-menu-item">
|
<div className="mb-2 flex items-start justify-between px-4 text-mobile-menu-item md:px-3 md:text-tablet-menu-item lg:text-menu-item">
|
||||||
{isSyncingInProgress ? (
|
{isSyncingInProgress ? (
|
||||||
<div className="flex items-center font-semibold text-info">
|
<div className="flex items-center font-semibold text-info">
|
||||||
<Spinner className="mr-2 h-5 w-5" />
|
<Spinner className="mr-2 h-5 w-5" />
|
||||||
@@ -127,7 +127,7 @@ const GeneralAccountMenu: FunctionComponent<Props> = ({ setMenuPane, closeMenu,
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="mb-1 px-3">
|
<div className="mb-1 px-4 md:px-3">
|
||||||
<div className="mb-3 text-base text-foreground lg:text-sm">
|
<div className="mb-3 text-base text-foreground lg:text-sm">
|
||||||
You’re offline. Sign in to sync your notes and preferences across all your devices and enable end-to-end
|
You’re offline. Sign in to sync your notes and preferences across all your devices and enable end-to-end
|
||||||
encryption.
|
encryption.
|
||||||
@@ -145,56 +145,57 @@ const GeneralAccountMenu: FunctionComponent<Props> = ({ setMenuPane, closeMenu,
|
|||||||
closeMenu={closeMenu}
|
closeMenu={closeMenu}
|
||||||
initialFocus={!application.hasAccount() ? CREATE_ACCOUNT_INDEX : SWITCHER_INDEX}
|
initialFocus={!application.hasAccount() ? CREATE_ACCOUNT_INDEX : SWITCHER_INDEX}
|
||||||
>
|
>
|
||||||
<MenuItemSeparator />
|
<MenuSection className="md:border-t md:pt-2">
|
||||||
<WorkspaceSwitcherOption mainApplicationGroup={mainApplicationGroup} />
|
<WorkspaceSwitcherOption mainApplicationGroup={mainApplicationGroup} />
|
||||||
<MenuItemSeparator />
|
</MenuSection>
|
||||||
{user ? (
|
<MenuSection>
|
||||||
<MenuItem onClick={openPreferences}>
|
{user ? (
|
||||||
<Icon type="user" className={iconClassName} />
|
<MenuItem onClick={openPreferences}>
|
||||||
Account settings
|
|
||||||
</MenuItem>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<MenuItem onClick={activateRegisterPane}>
|
|
||||||
<Icon type="user" className={iconClassName} />
|
<Icon type="user" className={iconClassName} />
|
||||||
Create free account
|
Account settings
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem onClick={activateSignInPane}>
|
) : (
|
||||||
<Icon type="signIn" className={iconClassName} />
|
<>
|
||||||
Sign in
|
<MenuItem onClick={activateRegisterPane}>
|
||||||
</MenuItem>
|
<Icon type="user" className={iconClassName} />
|
||||||
</>
|
Create free account
|
||||||
)}
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem onClick={activateSignInPane}>
|
||||||
onClick={() => {
|
<Icon type="signIn" className={iconClassName} />
|
||||||
application.importModalController.setIsVisible(true)
|
Sign in
|
||||||
application.accountMenuController.closeAccountMenu()
|
</MenuItem>
|
||||||
}}
|
</>
|
||||||
>
|
)}
|
||||||
<Icon type="archive" className={iconClassName} />
|
<MenuItem
|
||||||
Import
|
onClick={() => {
|
||||||
</MenuItem>
|
application.importModalController.setIsVisible(true)
|
||||||
{application.isNativeMobileWeb() && (
|
application.accountMenuController.closeAccountMenu()
|
||||||
<MenuItem onClick={openEmail}>
|
}}
|
||||||
<Icon type="email-filled" className={iconClassName} />
|
>
|
||||||
Email us
|
<Icon type="archive" className={iconClassName} />
|
||||||
|
Import
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
{application.isNativeMobileWeb() && (
|
||||||
<MenuItem className="justify-between" onClick={openHelp}>
|
<MenuItem onClick={openEmail}>
|
||||||
<div className="flex items-center">
|
<Icon type="email-filled" className={iconClassName} />
|
||||||
<Icon type="help" className={iconClassName} />
|
Email us
|
||||||
Help & feedback
|
</MenuItem>
|
||||||
</div>
|
)}
|
||||||
<span className="text-neutral">v{application.version}</span>
|
<MenuItem className="justify-between" onClick={openHelp}>
|
||||||
</MenuItem>
|
<div className="flex items-center">
|
||||||
|
<Icon type="help" className={iconClassName} />
|
||||||
|
Help & feedback
|
||||||
|
</div>
|
||||||
|
<span className="text-neutral">v{application.version}</span>
|
||||||
|
</MenuItem>
|
||||||
|
</MenuSection>
|
||||||
{user ? (
|
{user ? (
|
||||||
<>
|
<MenuSection>
|
||||||
<MenuItemSeparator />
|
|
||||||
<MenuItem onClick={signOut}>
|
<MenuItem onClick={signOut}>
|
||||||
<Icon type="signOut" className={iconClassName} />
|
<Icon type="signOut" className={iconClassName} />
|
||||||
Sign out workspace
|
Sign out workspace
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</>
|
</MenuSection>
|
||||||
) : null}
|
) : null}
|
||||||
</Menu>
|
</Menu>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import { FunctionComponent, useCallback, useEffect, useState } from 'react'
|
|||||||
import Icon from '@/Components/Icon/Icon'
|
import Icon from '@/Components/Icon/Icon'
|
||||||
import Menu from '@/Components/Menu/Menu'
|
import Menu from '@/Components/Menu/Menu'
|
||||||
import MenuItem from '@/Components/Menu/MenuItem'
|
import MenuItem from '@/Components/Menu/MenuItem'
|
||||||
import MenuItemSeparator from '@/Components/Menu/MenuItemSeparator'
|
|
||||||
import WorkspaceMenuItem from './WorkspaceMenuItem'
|
import WorkspaceMenuItem from './WorkspaceMenuItem'
|
||||||
import { useApplication } from '@/Components/ApplicationProvider'
|
import { useApplication } from '@/Components/ApplicationProvider'
|
||||||
|
import MenuSection from '@/Components/Menu/MenuSection'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
mainApplicationGroup: WebApplicationGroup
|
mainApplicationGroup: WebApplicationGroup
|
||||||
@@ -71,30 +71,32 @@ const WorkspaceSwitcherMenu: FunctionComponent<Props> = ({
|
|||||||
}, [mainApplicationGroup])
|
}, [mainApplicationGroup])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Menu a11yLabel="Workspace switcher menu" className="px-0 focus:shadow-none" isOpen={isOpen}>
|
<Menu a11yLabel="Workspace switcher menu" className="focus:shadow-none" isOpen={isOpen}>
|
||||||
{applicationDescriptors.map((descriptor) => (
|
<MenuSection>
|
||||||
<WorkspaceMenuItem
|
{applicationDescriptors.map((descriptor) => (
|
||||||
key={descriptor.identifier}
|
<WorkspaceMenuItem
|
||||||
descriptor={descriptor}
|
key={descriptor.identifier}
|
||||||
hideOptions={hideWorkspaceOptions}
|
descriptor={descriptor}
|
||||||
onDelete={destroyWorkspace}
|
hideOptions={hideWorkspaceOptions}
|
||||||
onClick={() => activateWorkspace(descriptor)}
|
onDelete={destroyWorkspace}
|
||||||
renameDescriptor={(label: string) => mainApplicationGroup.renameDescriptor(descriptor, label)}
|
onClick={() => activateWorkspace(descriptor)}
|
||||||
/>
|
renameDescriptor={(label: string) => mainApplicationGroup.renameDescriptor(descriptor, label)}
|
||||||
))}
|
/>
|
||||||
<MenuItemSeparator />
|
))}
|
||||||
|
</MenuSection>
|
||||||
|
|
||||||
<MenuItem onClick={addAnotherWorkspace}>
|
<MenuSection>
|
||||||
<Icon type="user-add" className="mr-2 text-neutral" />
|
<MenuItem onClick={addAnotherWorkspace}>
|
||||||
Add another workspace
|
<Icon type="user-add" className="mr-2 text-neutral" />
|
||||||
</MenuItem>
|
Add another workspace
|
||||||
|
|
||||||
{!hideWorkspaceOptions && (
|
|
||||||
<MenuItem onClick={signoutAll}>
|
|
||||||
<Icon type="signOut" className="mr-2 text-neutral" />
|
|
||||||
Sign out all workspaces
|
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
{!hideWorkspaceOptions && (
|
||||||
|
<MenuItem onClick={signoutAll}>
|
||||||
|
<Icon type="signOut" className="mr-2 text-neutral" />
|
||||||
|
Sign out all workspaces
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
|
</MenuSection>
|
||||||
</Menu>
|
</Menu>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const WorkspaceSwitcherOption: FunctionComponent<Props> = ({ mainApplicationGrou
|
|||||||
title="Switch workspace"
|
title="Switch workspace"
|
||||||
align="end"
|
align="end"
|
||||||
anchorElement={buttonRef}
|
anchorElement={buttonRef}
|
||||||
className="py-2"
|
className="pb-2"
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
side="right"
|
side="right"
|
||||||
togglePopover={toggleMenu}
|
togglePopover={toggleMenu}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ const LockscreenWorkspaceSwitcher: FunctionComponent<Props> = ({ mainApplication
|
|||||||
title="Switch workspace"
|
title="Switch workspace"
|
||||||
align="center"
|
align="center"
|
||||||
anchorElement={buttonRef}
|
anchorElement={buttonRef}
|
||||||
className="py-2"
|
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
overrideZIndex="z-modal"
|
overrideZIndex="z-modal"
|
||||||
side="right"
|
side="right"
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ const ChangeEditorButton: FunctionComponent<Props> = ({ noteViewController, onCl
|
|||||||
disableClickOutside={isClickOutsideDisabled}
|
disableClickOutside={isClickOutsideDisabled}
|
||||||
anchorElement={buttonRef}
|
anchorElement={buttonRef}
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
className="pt-2 md:pt-0"
|
className="md:pb-1"
|
||||||
>
|
>
|
||||||
<ChangeEditorMenu
|
<ChangeEditorMenu
|
||||||
application={application}
|
application={application}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
PrefKey,
|
PrefKey,
|
||||||
SNNote,
|
SNNote,
|
||||||
} from '@standardnotes/snjs'
|
} from '@standardnotes/snjs'
|
||||||
import { Fragment, FunctionComponent, useCallback, useEffect, useMemo, useState } from 'react'
|
import { FunctionComponent, useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
import { EditorMenuGroup } from '@/Components/NotesOptions/EditorMenuGroup'
|
import { EditorMenuGroup } from '@/Components/NotesOptions/EditorMenuGroup'
|
||||||
import { EditorMenuItem } from '@/Components/NotesOptions/EditorMenuItem'
|
import { EditorMenuItem } from '@/Components/NotesOptions/EditorMenuItem'
|
||||||
import { createEditorMenuGroups } from '../../Utils/createEditorMenuGroups'
|
import { createEditorMenuGroups } from '../../Utils/createEditorMenuGroups'
|
||||||
@@ -24,6 +24,7 @@ import MenuRadioButtonItem from '../Menu/MenuRadioButtonItem'
|
|||||||
import { Pill } from '../Preferences/PreferencesComponents/Content'
|
import { Pill } from '../Preferences/PreferencesComponents/Content'
|
||||||
import ModalOverlay from '../Modal/ModalOverlay'
|
import ModalOverlay from '../Modal/ModalOverlay'
|
||||||
import SuperNoteConverter from '../SuperEditor/SuperNoteConverter'
|
import SuperNoteConverter from '../SuperEditor/SuperNoteConverter'
|
||||||
|
import MenuSection from '../Menu/MenuSection'
|
||||||
|
|
||||||
type ChangeEditorMenuProps = {
|
type ChangeEditorMenuProps = {
|
||||||
application: WebApplication
|
application: WebApplication
|
||||||
@@ -210,48 +211,42 @@ const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({
|
|||||||
<Menu className="pb-1 pt-0.5" a11yLabel="Change note type menu" isOpen={isVisible}>
|
<Menu className="pb-1 pt-0.5" a11yLabel="Change note type menu" isOpen={isVisible}>
|
||||||
{groups
|
{groups
|
||||||
.filter((group) => group.items && group.items.length)
|
.filter((group) => group.items && group.items.length)
|
||||||
.map((group, index) => {
|
.map((group) => {
|
||||||
const groupId = getGroupId(group)
|
const groupId = getGroupId(group)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment key={groupId}>
|
<MenuSection key={groupId}>
|
||||||
<div
|
{group.items.map((menuItem) => {
|
||||||
className={`border-0 border-t border-solid border-[--separator-color] py-1 ${
|
const onClickEditorItem = () => {
|
||||||
index === 0 ? 'border-t-0' : ''
|
handleMenuSelection(menuItem).catch(console.error)
|
||||||
}`}
|
}
|
||||||
>
|
|
||||||
{group.items.map((menuItem) => {
|
|
||||||
const onClickEditorItem = () => {
|
|
||||||
handleMenuSelection(menuItem).catch(console.error)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuRadioButtonItem
|
<MenuRadioButtonItem
|
||||||
key={menuItem.uiFeature.uniqueIdentifier.value}
|
key={menuItem.uiFeature.uniqueIdentifier.value}
|
||||||
onClick={onClickEditorItem}
|
onClick={onClickEditorItem}
|
||||||
className={'flex-row-reversed py-2'}
|
className={'flex-row-reversed py-2'}
|
||||||
checked={isSelected(menuItem)}
|
checked={isSelected(menuItem)}
|
||||||
info={menuItem.uiFeature.description}
|
info={menuItem.uiFeature.description}
|
||||||
>
|
>
|
||||||
<div className="flex flex-grow items-center justify-between">
|
<div className="flex flex-grow items-center justify-between">
|
||||||
<div className={`flex items-center ${group.featured ? 'font-bold' : ''}`}>
|
<div className={`flex items-center ${group.featured ? 'font-bold' : ''}`}>
|
||||||
{group.icon && <Icon type={group.icon} className={`mr-2 ${group.iconClassName}`} />}
|
{group.icon && <Icon type={group.icon} className={`mr-2 ${group.iconClassName}`} />}
|
||||||
{menuItem.uiFeature.displayName}
|
{menuItem.uiFeature.displayName}
|
||||||
{menuItem.isLabs && (
|
{menuItem.isLabs && (
|
||||||
<Pill className="px-1.5 py-0.5" style="success">
|
<Pill className="px-1.5 py-0.5" style="success">
|
||||||
Labs
|
Labs
|
||||||
</Pill>
|
</Pill>
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{!menuItem.isEntitled && (
|
|
||||||
<Icon type={PremiumFeatureIconName} className={PremiumFeatureIconClass} />
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</MenuRadioButtonItem>
|
{!menuItem.isEntitled && (
|
||||||
)
|
<Icon type={PremiumFeatureIconName} className={PremiumFeatureIconClass} />
|
||||||
})}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Fragment>
|
</MenuRadioButtonItem>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</MenuSection>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
NoteType,
|
NoteType,
|
||||||
SNNote,
|
SNNote,
|
||||||
} from '@standardnotes/snjs'
|
} from '@standardnotes/snjs'
|
||||||
import { Fragment, useCallback, useMemo, useState } from 'react'
|
import { useCallback, useMemo, useState } from 'react'
|
||||||
import Icon from '../Icon/Icon'
|
import Icon from '../Icon/Icon'
|
||||||
import { PremiumFeatureIconName, PremiumFeatureIconClass } from '../Icon/PremiumFeatureIcon'
|
import { PremiumFeatureIconName, PremiumFeatureIconClass } from '../Icon/PremiumFeatureIcon'
|
||||||
import Menu from '../Menu/Menu'
|
import Menu from '../Menu/Menu'
|
||||||
@@ -20,6 +20,7 @@ import { EditorMenuItem } from '../NotesOptions/EditorMenuItem'
|
|||||||
import { SuperNoteImporter } from '../SuperEditor/SuperNoteImporter'
|
import { SuperNoteImporter } from '../SuperEditor/SuperNoteImporter'
|
||||||
import { Pill } from '../Preferences/PreferencesComponents/Content'
|
import { Pill } from '../Preferences/PreferencesComponents/Content'
|
||||||
import ModalOverlay from '../Modal/ModalOverlay'
|
import ModalOverlay from '../Modal/ModalOverlay'
|
||||||
|
import MenuSection from '../Menu/MenuSection'
|
||||||
|
|
||||||
const getGroupId = (group: EditorMenuGroup) => group.title.toLowerCase().replace(/\s/, '-')
|
const getGroupId = (group: EditorMenuGroup) => group.title.toLowerCase().replace(/\s/, '-')
|
||||||
|
|
||||||
@@ -132,36 +133,34 @@ const ChangeEditorMultipleMenu = ({ application, notes, setDisableClickOutside }
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Menu isOpen={true} a11yLabel="Change note type">
|
<Menu isOpen={true} a11yLabel="Change note type">
|
||||||
{groupsWithItems.map((group, index) => (
|
{groupsWithItems.map((group) => (
|
||||||
<Fragment key={getGroupId(group)}>
|
<MenuSection key={getGroupId(group)}>
|
||||||
<div className={`border-0 border-t border-solid border-border py-1 ${index === 0 ? 'border-t-0' : ''}`}>
|
{group.items.map((item) => {
|
||||||
{group.items.map((item) => {
|
const onClickEditorItem = () => {
|
||||||
const onClickEditorItem = () => {
|
handleMenuSelection(item).catch(console.error)
|
||||||
handleMenuSelection(item).catch(console.error)
|
}
|
||||||
}
|
return (
|
||||||
return (
|
<MenuItem
|
||||||
<MenuItem
|
key={item.uiFeature.uniqueIdentifier.value}
|
||||||
key={item.uiFeature.uniqueIdentifier.value}
|
onClick={onClickEditorItem}
|
||||||
onClick={onClickEditorItem}
|
className={'flex-row-reversed py-2'}
|
||||||
className={'flex-row-reversed py-2'}
|
>
|
||||||
>
|
<div className="flex flex-grow items-center justify-between">
|
||||||
<div className="flex flex-grow items-center justify-between">
|
<div className={'flex items-center'}>
|
||||||
<div className={'flex items-center'}>
|
{group.icon && <Icon type={group.icon} className={`mr-2 ${group.iconClassName}`} />}
|
||||||
{group.icon && <Icon type={group.icon} className={`mr-2 ${group.iconClassName}`} />}
|
{item.uiFeature.displayName}
|
||||||
{item.uiFeature.displayName}
|
{item.isLabs && (
|
||||||
{item.isLabs && (
|
<Pill className="px-1.5 py-0.5" style="success">
|
||||||
<Pill className="px-1.5 py-0.5" style="success">
|
Labs
|
||||||
Labs
|
</Pill>
|
||||||
</Pill>
|
)}
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{!item.isEntitled && <Icon type={PremiumFeatureIconName} className={PremiumFeatureIconClass} />}
|
|
||||||
</div>
|
</div>
|
||||||
</MenuItem>
|
{!item.isEntitled && <Icon type={PremiumFeatureIconName} className={PremiumFeatureIconClass} />}
|
||||||
)
|
</div>
|
||||||
})}
|
</MenuItem>
|
||||||
</div>
|
)
|
||||||
</Fragment>
|
})}
|
||||||
|
</MenuSection>
|
||||||
))}
|
))}
|
||||||
</Menu>
|
</Menu>
|
||||||
<ModalOverlay isOpen={showSuperImporter} close={closeCurrentSuperNoteImporter}>
|
<ModalOverlay isOpen={showSuperImporter} close={closeCurrentSuperNoteImporter}>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const ChangeMultipleButton = ({ application, notesController }: Props) => {
|
|||||||
disableClickOutside={disableClickOutside}
|
disableClickOutside={disableClickOutside}
|
||||||
anchorElement={changeButtonRef}
|
anchorElement={changeButtonRef}
|
||||||
open={isChangeMenuOpen}
|
open={isChangeMenuOpen}
|
||||||
className="pt-2 md:pt-0"
|
className="md:pb-1"
|
||||||
>
|
>
|
||||||
<ChangeEditorMultipleMenu
|
<ChangeEditorMultipleMenu
|
||||||
application={application}
|
application={application}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import { observer } from 'mobx-react-lite'
|
|||||||
import { FunctionComponent, useCallback, useEffect, useState } from 'react'
|
import { FunctionComponent, useCallback, useEffect, useState } from 'react'
|
||||||
import Icon from '@/Components/Icon/Icon'
|
import Icon from '@/Components/Icon/Icon'
|
||||||
import Menu from '@/Components/Menu/Menu'
|
import Menu from '@/Components/Menu/Menu'
|
||||||
import MenuItemSeparator from '@/Components/Menu/MenuItemSeparator'
|
|
||||||
import { DisplayOptionsMenuProps } from './DisplayOptionsMenuProps'
|
import { DisplayOptionsMenuProps } from './DisplayOptionsMenuProps'
|
||||||
import NewNotePreferences from './NewNotePreferences'
|
import NewNotePreferences from './NewNotePreferences'
|
||||||
import { PreferenceMode } from './PreferenceMode'
|
import { PreferenceMode } from './PreferenceMode'
|
||||||
@@ -26,6 +25,7 @@ import MenuSwitchButtonItem from '@/Components/Menu/MenuSwitchButtonItem'
|
|||||||
import { Pill } from '@/Components/Preferences/PreferencesComponents/Content'
|
import { Pill } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||||
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
|
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
|
||||||
import { PaneLayout } from '@/Controllers/PaneController/PaneLayout'
|
import { PaneLayout } from '@/Controllers/PaneController/PaneLayout'
|
||||||
|
import MenuSection from '@/Components/Menu/MenuSection'
|
||||||
|
|
||||||
const DailyEntryModeEnabled = true
|
const DailyEntryModeEnabled = true
|
||||||
|
|
||||||
@@ -316,45 +316,43 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<MenuItemSeparator />
|
<MenuSection title="Sort by">
|
||||||
|
<MenuRadioButtonItem
|
||||||
|
disabled={controlsDisabled || isDailyEntry}
|
||||||
|
className="py-2"
|
||||||
|
onClick={toggleSortByDateModified}
|
||||||
|
checked={preferences.sortBy === CollectionSort.UpdatedAt}
|
||||||
|
>
|
||||||
|
<div className="ml-1 flex flex-grow items-center justify-between md:ml-2">
|
||||||
|
<span>Date modified</span>
|
||||||
|
<SortIcon enabled={preferences.sortBy === CollectionSort.UpdatedAt} reverse={preferences.sortReverse} />
|
||||||
|
</div>
|
||||||
|
</MenuRadioButtonItem>
|
||||||
|
<MenuRadioButtonItem
|
||||||
|
disabled={controlsDisabled || isDailyEntry}
|
||||||
|
className="py-2"
|
||||||
|
onClick={toggleSortByCreationDate}
|
||||||
|
checked={preferences.sortBy === CollectionSort.CreatedAt}
|
||||||
|
>
|
||||||
|
<div className="ml-1 flex flex-grow items-center justify-between md:ml-2">
|
||||||
|
<span>Creation date</span>
|
||||||
|
<SortIcon enabled={preferences.sortBy === CollectionSort.CreatedAt} reverse={preferences.sortReverse} />
|
||||||
|
</div>
|
||||||
|
</MenuRadioButtonItem>
|
||||||
|
<MenuRadioButtonItem
|
||||||
|
disabled={controlsDisabled || isDailyEntry}
|
||||||
|
className="py-2"
|
||||||
|
onClick={toggleSortByTitle}
|
||||||
|
checked={preferences.sortBy === CollectionSort.Title}
|
||||||
|
>
|
||||||
|
<div className="ml-1 flex flex-grow items-center justify-between md:ml-2">
|
||||||
|
<span>Title</span>
|
||||||
|
<SortIcon enabled={preferences.sortBy === CollectionSort.Title} reverse={preferences.sortReverse} />
|
||||||
|
</div>
|
||||||
|
</MenuRadioButtonItem>
|
||||||
|
</MenuSection>
|
||||||
|
|
||||||
<div className="my-1 px-3 text-base font-semibold uppercase text-text lg:text-xs">Sort by</div>
|
<MenuSection title="View">
|
||||||
<MenuRadioButtonItem
|
|
||||||
disabled={controlsDisabled || isDailyEntry}
|
|
||||||
className="py-2"
|
|
||||||
onClick={toggleSortByDateModified}
|
|
||||||
checked={preferences.sortBy === CollectionSort.UpdatedAt}
|
|
||||||
>
|
|
||||||
<div className="ml-1 flex flex-grow items-center justify-between md:ml-2">
|
|
||||||
<span>Date modified</span>
|
|
||||||
<SortIcon enabled={preferences.sortBy === CollectionSort.UpdatedAt} reverse={preferences.sortReverse} />
|
|
||||||
</div>
|
|
||||||
</MenuRadioButtonItem>
|
|
||||||
<MenuRadioButtonItem
|
|
||||||
disabled={controlsDisabled || isDailyEntry}
|
|
||||||
className="py-2"
|
|
||||||
onClick={toggleSortByCreationDate}
|
|
||||||
checked={preferences.sortBy === CollectionSort.CreatedAt}
|
|
||||||
>
|
|
||||||
<div className="ml-1 flex flex-grow items-center justify-between md:ml-2">
|
|
||||||
<span>Creation date</span>
|
|
||||||
<SortIcon enabled={preferences.sortBy === CollectionSort.CreatedAt} reverse={preferences.sortReverse} />
|
|
||||||
</div>
|
|
||||||
</MenuRadioButtonItem>
|
|
||||||
<MenuRadioButtonItem
|
|
||||||
disabled={controlsDisabled || isDailyEntry}
|
|
||||||
className="py-2"
|
|
||||||
onClick={toggleSortByTitle}
|
|
||||||
checked={preferences.sortBy === CollectionSort.Title}
|
|
||||||
>
|
|
||||||
<div className="ml-1 flex flex-grow items-center justify-between md:ml-2">
|
|
||||||
<span>Title</span>
|
|
||||||
<SortIcon enabled={preferences.sortBy === CollectionSort.Title} reverse={preferences.sortReverse} />
|
|
||||||
</div>
|
|
||||||
</MenuRadioButtonItem>
|
|
||||||
<>
|
|
||||||
<MenuItemSeparator />
|
|
||||||
<div className="px-3 py-1 text-base font-semibold uppercase text-text lg:text-xs">View</div>
|
|
||||||
{!shouldHideNonApplicableOptions && !isFilesSmartView && (
|
{!shouldHideNonApplicableOptions && !isFilesSmartView && (
|
||||||
<MenuSwitchButtonItem
|
<MenuSwitchButtonItem
|
||||||
disabled={controlsDisabled}
|
disabled={controlsDisabled}
|
||||||
@@ -389,49 +387,47 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
|
|||||||
>
|
>
|
||||||
Show icon
|
Show icon
|
||||||
</MenuSwitchButtonItem>
|
</MenuSwitchButtonItem>
|
||||||
{!shouldHideNonApplicableOptions && (
|
</MenuSection>
|
||||||
<>
|
|
||||||
<MenuItemSeparator />
|
{!shouldHideNonApplicableOptions && (
|
||||||
<div className="px-3 py-1 text-base font-semibold uppercase text-text lg:text-xs">Other</div>
|
<MenuSection title="Other">
|
||||||
<MenuSwitchButtonItem
|
<MenuSwitchButtonItem
|
||||||
disabled={controlsDisabled}
|
disabled={controlsDisabled}
|
||||||
className="py-1 hover:bg-contrast focus:bg-info-backdrop"
|
className="py-1 hover:bg-contrast focus:bg-info-backdrop"
|
||||||
checked={!preferences.hidePinned}
|
checked={!preferences.hidePinned}
|
||||||
onChange={toggleHidePinned}
|
onChange={toggleHidePinned}
|
||||||
>
|
>
|
||||||
Show pinned
|
Show pinned
|
||||||
</MenuSwitchButtonItem>
|
</MenuSwitchButtonItem>
|
||||||
<MenuSwitchButtonItem
|
<MenuSwitchButtonItem
|
||||||
disabled={controlsDisabled}
|
disabled={controlsDisabled}
|
||||||
className="py-1 hover:bg-contrast focus:bg-info-backdrop"
|
className="py-1 hover:bg-contrast focus:bg-info-backdrop"
|
||||||
checked={!preferences.hideProtected}
|
checked={!preferences.hideProtected}
|
||||||
onChange={toggleHideProtected}
|
onChange={toggleHideProtected}
|
||||||
>
|
>
|
||||||
Show protected
|
Show protected
|
||||||
</MenuSwitchButtonItem>
|
</MenuSwitchButtonItem>
|
||||||
<MenuSwitchButtonItem
|
<MenuSwitchButtonItem
|
||||||
disabled={controlsDisabled}
|
disabled={controlsDisabled}
|
||||||
className="py-1 hover:bg-contrast focus:bg-info-backdrop"
|
className="py-1 hover:bg-contrast focus:bg-info-backdrop"
|
||||||
checked={Boolean(preferences.showArchived)}
|
checked={Boolean(preferences.showArchived)}
|
||||||
onChange={toggleShowArchived}
|
onChange={toggleShowArchived}
|
||||||
>
|
>
|
||||||
Show archived
|
Show archived
|
||||||
</MenuSwitchButtonItem>
|
</MenuSwitchButtonItem>
|
||||||
<MenuSwitchButtonItem
|
<MenuSwitchButtonItem
|
||||||
disabled={controlsDisabled}
|
disabled={controlsDisabled}
|
||||||
className="py-1 hover:bg-contrast focus:bg-info-backdrop"
|
className="py-1 hover:bg-contrast focus:bg-info-backdrop"
|
||||||
checked={Boolean(preferences.showTrashed)}
|
checked={Boolean(preferences.showTrashed)}
|
||||||
onChange={toggleShowTrashed}
|
onChange={toggleShowTrashed}
|
||||||
>
|
>
|
||||||
Show trashed
|
Show trashed
|
||||||
</MenuSwitchButtonItem>
|
</MenuSwitchButtonItem>
|
||||||
</>
|
</MenuSection>
|
||||||
)}
|
)}
|
||||||
</>
|
|
||||||
|
|
||||||
{currentMode === 'tag' && !isSystemTag && DailyEntryModeEnabled && !isTableViewEnabled && (
|
{currentMode === 'tag' && !isSystemTag && DailyEntryModeEnabled && !isTableViewEnabled && (
|
||||||
<>
|
<MenuSection>
|
||||||
<MenuItemSeparator />
|
|
||||||
<MenuSwitchButtonItem
|
<MenuSwitchButtonItem
|
||||||
disabled={controlsDisabled}
|
disabled={controlsDisabled}
|
||||||
className="py-1 hover:bg-contrast focus:bg-info-backdrop"
|
className="py-1 hover:bg-contrast focus:bg-info-backdrop"
|
||||||
@@ -441,19 +437,18 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
|
|||||||
<div className="flex flex-col pr-5">
|
<div className="flex flex-col pr-5">
|
||||||
<div className="flex flex-row items-center">
|
<div className="flex flex-row items-center">
|
||||||
<div className="text-base font-semibold uppercase text-text lg:text-xs">Daily Notebook</div>
|
<div className="text-base font-semibold uppercase text-text lg:text-xs">Daily Notebook</div>
|
||||||
<Pill className="px-1.5 !py-0.5" style="success">
|
<Pill className="!py-0.5 px-1.5" style="success">
|
||||||
Labs
|
Labs
|
||||||
</Pill>
|
</Pill>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1">Capture new notes daily with a calendar-based layout</div>
|
<div className="mt-1">Capture new notes daily with a calendar-based layout</div>
|
||||||
</div>
|
</div>
|
||||||
</MenuSwitchButtonItem>
|
</MenuSwitchButtonItem>
|
||||||
</>
|
</MenuSection>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{currentMode === 'tag' && !isSystemTag && !isDailyEntry && (
|
{currentMode === 'tag' && !isSystemTag && !isDailyEntry && (
|
||||||
<>
|
<MenuSection>
|
||||||
<MenuItemSeparator />
|
|
||||||
<MenuSwitchButtonItem
|
<MenuSwitchButtonItem
|
||||||
disabled={controlsDisabled}
|
disabled={controlsDisabled}
|
||||||
className="py-1 hover:bg-contrast focus:bg-info-backdrop"
|
className="py-1 hover:bg-contrast focus:bg-info-backdrop"
|
||||||
@@ -463,19 +458,18 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
|
|||||||
<div className="flex flex-col pr-5">
|
<div className="flex flex-col pr-5">
|
||||||
<div className="flex flex-row items-center">
|
<div className="flex flex-row items-center">
|
||||||
<div className="text-base font-semibold uppercase text-text lg:text-xs">Table view</div>
|
<div className="text-base font-semibold uppercase text-text lg:text-xs">Table view</div>
|
||||||
<Pill className="px-1.5 !py-0.5" style="success">
|
<Pill className="!py-0.5 px-1.5" style="success">
|
||||||
Labs
|
Labs
|
||||||
</Pill>
|
</Pill>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1">Display the notes and files in the current tag in a table layout</div>
|
<div className="mt-1">Display the notes and files in the current tag in a table layout</div>
|
||||||
</div>
|
</div>
|
||||||
</MenuSwitchButtonItem>
|
</MenuSwitchButtonItem>
|
||||||
</>
|
</MenuSection>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!shouldHideNonApplicableOptions && (!isSystemTag || currentMode === 'global') && (
|
{!shouldHideNonApplicableOptions && (!isSystemTag || currentMode === 'global') && (
|
||||||
<>
|
<MenuSection title="New note defaults">
|
||||||
<MenuItemSeparator />
|
|
||||||
<NewNotePreferences
|
<NewNotePreferences
|
||||||
disabled={controlsDisabled}
|
disabled={controlsDisabled}
|
||||||
application={application}
|
application={application}
|
||||||
@@ -483,7 +477,7 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
|
|||||||
mode={currentMode}
|
mode={currentMode}
|
||||||
changePreferencesCallback={changePreferences}
|
changePreferencesCallback={changePreferences}
|
||||||
/>
|
/>
|
||||||
</>
|
</MenuSection>
|
||||||
)}
|
)}
|
||||||
</Menu>
|
</Menu>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -173,10 +173,9 @@ const NewNotePreferences: FunctionComponent<Props> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="my-1 px-3 pb-2 pt-1">
|
<div className="px-3 py-3">
|
||||||
<div className="text-base font-semibold uppercase text-text lg:text-xs">New Note Defaults</div>
|
|
||||||
<div>
|
<div>
|
||||||
<div className="mt-3 text-mobile-menu-item md:text-menu-item">Note Type</div>
|
<div className="text-mobile-menu-item md:text-menu-item">Note Type</div>
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<Dropdown
|
<Dropdown
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const FileContextMenu: FunctionComponent<Props> = observer(({ filesController, i
|
|||||||
anchorPoint={fileContextMenuLocation}
|
anchorPoint={fileContextMenuLocation}
|
||||||
togglePopover={() => setShowFileContextMenu(!showFileContextMenu)}
|
togglePopover={() => setShowFileContextMenu(!showFileContextMenu)}
|
||||||
align="start"
|
align="start"
|
||||||
className="py-2"
|
className="md:pb-2"
|
||||||
>
|
>
|
||||||
<Menu a11yLabel="File context menu" isOpen={showFileContextMenu}>
|
<Menu a11yLabel="File context menu" isOpen={showFileContextMenu}>
|
||||||
<FileMenuOptions
|
<FileMenuOptions
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useApplication } from '../ApplicationProvider'
|
|||||||
import { FileBackupRecord, FileItem } from '@standardnotes/snjs'
|
import { FileBackupRecord, FileItem } from '@standardnotes/snjs'
|
||||||
import { dateToStringStyle1 } from '@/Utils/DateUtils'
|
import { dateToStringStyle1 } from '@/Utils/DateUtils'
|
||||||
import { MenuItemIconSize } from '@/Constants/TailwindClassNames'
|
import { MenuItemIconSize } from '@/Constants/TailwindClassNames'
|
||||||
|
import MenuSection from '../Menu/MenuSection'
|
||||||
|
|
||||||
export const FileContextMenuBackupOption: FunctionComponent<{ file: FileItem }> = ({ file }) => {
|
export const FileContextMenuBackupOption: FunctionComponent<{ file: FileItem }> = ({ file }) => {
|
||||||
const application = useApplication()
|
const application = useApplication()
|
||||||
@@ -33,8 +34,12 @@ export const FileContextMenuBackupOption: FunctionComponent<{ file: FileItem }>
|
|||||||
application.openPreferences('backups')
|
application.openPreferences('backups')
|
||||||
}, [application])
|
}, [application])
|
||||||
|
|
||||||
|
if (!application.fileBackups) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<MenuSection>
|
||||||
{backupInfo && (
|
{backupInfo && (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon={'check-circle'}
|
icon={'check-circle'}
|
||||||
@@ -62,6 +67,6 @@ export const FileContextMenuBackupOption: FunctionComponent<{ file: FileItem }>
|
|||||||
</div>
|
</div>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
</>
|
</MenuSection>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { FunctionComponent, useCallback, useMemo } from 'react'
|
|||||||
import { FileItemActionType } from '../AttachedFilesPopover/PopoverFileItemAction'
|
import { FileItemActionType } from '../AttachedFilesPopover/PopoverFileItemAction'
|
||||||
import Icon from '@/Components/Icon/Icon'
|
import Icon from '@/Components/Icon/Icon'
|
||||||
import { observer } from 'mobx-react-lite'
|
import { observer } from 'mobx-react-lite'
|
||||||
import HorizontalSeparator from '../Shared/HorizontalSeparator'
|
|
||||||
import { formatSizeToReadableString } from '@standardnotes/filepicker'
|
import { formatSizeToReadableString } from '@standardnotes/filepicker'
|
||||||
import { useResponsiveAppPane } from '../Panes/ResponsivePaneProvider'
|
import { useResponsiveAppPane } from '../Panes/ResponsivePaneProvider'
|
||||||
import { AppPaneId } from '../Panes/AppPaneMetadata'
|
import { AppPaneId } from '../Panes/AppPaneMetadata'
|
||||||
@@ -15,6 +14,7 @@ import { MenuItemIconSize } from '@/Constants/TailwindClassNames'
|
|||||||
import AddToVaultMenuOption from '../Vaults/AddToVaultMenuOption'
|
import AddToVaultMenuOption from '../Vaults/AddToVaultMenuOption'
|
||||||
import { iconClass } from '../NotesOptions/ClassNames'
|
import { iconClass } from '../NotesOptions/ClassNames'
|
||||||
import { useApplication } from '../ApplicationProvider'
|
import { useApplication } from '../ApplicationProvider'
|
||||||
|
import MenuSection from '../Menu/MenuSection'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
closeMenu: () => void
|
closeMenu: () => void
|
||||||
@@ -87,8 +87,8 @@ const FileMenuOptions: FunctionComponent<Props> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{selectedFiles.length === 1 && (
|
{selectedFiles.length === 1 && (isFileAttachedToNote || shouldShowAttachOption) && (
|
||||||
<>
|
<MenuSection>
|
||||||
{isFileAttachedToNote ? (
|
{isFileAttachedToNote ? (
|
||||||
<MenuItem onClick={onDetach}>
|
<MenuItem onClick={onDetach}>
|
||||||
<Icon type="link-off" className="mr-2 text-neutral" />
|
<Icon type="link-off" className="mr-2 text-neutral" />
|
||||||
@@ -100,67 +100,69 @@ const FileMenuOptions: FunctionComponent<Props> = ({
|
|||||||
Attach to note
|
Attach to note
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
) : null}
|
) : null}
|
||||||
</>
|
</MenuSection>
|
||||||
)}
|
)}
|
||||||
{application.featuresController.isVaultsEnabled() && (
|
<MenuSection>
|
||||||
<AddToVaultMenuOption
|
{application.featuresController.isVaultsEnabled() && (
|
||||||
iconClassName={iconClass}
|
<AddToVaultMenuOption
|
||||||
items={selectedFiles}
|
iconClassName={iconClass}
|
||||||
disabled={!hasAdminPermissionForAllSharedFiles}
|
items={selectedFiles}
|
||||||
|
disabled={!hasAdminPermissionForAllSharedFiles}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<AddTagOption
|
||||||
|
navigationController={application.navigationController}
|
||||||
|
linkingController={application.linkingController}
|
||||||
|
selectedItems={selectedFiles}
|
||||||
|
iconClassName={`text-neutral mr-2 ${MenuItemIconSize}`}
|
||||||
|
disabled={areSomeFilesInReadonlySharedVault}
|
||||||
/>
|
/>
|
||||||
)}
|
<MenuSwitchButtonItem
|
||||||
<AddTagOption
|
checked={hasProtectedFiles}
|
||||||
navigationController={application.navigationController}
|
onChange={(hasProtectedFiles) => {
|
||||||
linkingController={application.linkingController}
|
void application.filesController.setProtectionForFiles(hasProtectedFiles, selectedFiles)
|
||||||
selectedItems={selectedFiles}
|
|
||||||
iconClassName={`text-neutral mr-2 ${MenuItemIconSize}`}
|
|
||||||
disabled={areSomeFilesInReadonlySharedVault}
|
|
||||||
/>
|
|
||||||
<MenuSwitchButtonItem
|
|
||||||
checked={hasProtectedFiles}
|
|
||||||
onChange={(hasProtectedFiles) => {
|
|
||||||
void application.filesController.setProtectionForFiles(hasProtectedFiles, selectedFiles)
|
|
||||||
}}
|
|
||||||
disabled={areSomeFilesInReadonlySharedVault}
|
|
||||||
>
|
|
||||||
<Icon type="lock" className={`mr-2 text-neutral ${MenuItemIconSize}`} />
|
|
||||||
Password protect
|
|
||||||
</MenuSwitchButtonItem>
|
|
||||||
<HorizontalSeparator classes="my-1" />
|
|
||||||
<MenuItem
|
|
||||||
onClick={() => {
|
|
||||||
void application.filesController.downloadFiles(selectedFiles)
|
|
||||||
closeMenu()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon type="download" className={`mr-2 text-neutral ${MenuItemIconSize}`} />
|
|
||||||
Download
|
|
||||||
</MenuItem>
|
|
||||||
{shouldShowRenameOption && (
|
|
||||||
<MenuItem
|
|
||||||
onClick={() => {
|
|
||||||
renameToggleCallback?.(true)
|
|
||||||
}}
|
}}
|
||||||
disabled={areSomeFilesInReadonlySharedVault}
|
disabled={areSomeFilesInReadonlySharedVault}
|
||||||
>
|
>
|
||||||
<Icon type="pencil" className={`mr-2 text-neutral ${MenuItemIconSize}`} />
|
<Icon type="lock" className={`mr-2 text-neutral ${MenuItemIconSize}`} />
|
||||||
Rename
|
Password protect
|
||||||
|
</MenuSwitchButtonItem>
|
||||||
|
</MenuSection>
|
||||||
|
<MenuSection>
|
||||||
|
<MenuItem
|
||||||
|
onClick={() => {
|
||||||
|
void application.filesController.downloadFiles(selectedFiles)
|
||||||
|
closeMenu()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon type="download" className={`mr-2 text-neutral ${MenuItemIconSize}`} />
|
||||||
|
Download
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
{shouldShowRenameOption && (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
closeMenuAndToggleFilesList()
|
renameToggleCallback?.(true)
|
||||||
void application.filesController.deleteFilesPermanently(selectedFiles)
|
}}
|
||||||
}}
|
disabled={areSomeFilesInReadonlySharedVault}
|
||||||
disabled={areSomeFilesInReadonlySharedVault}
|
>
|
||||||
>
|
<Icon type="pencil" className={`mr-2 text-neutral ${MenuItemIconSize}`} />
|
||||||
<Icon type="trash" className={`mr-2 text-danger ${MenuItemIconSize}`} />
|
Rename
|
||||||
<span className="text-danger">Delete permanently</span>
|
</MenuItem>
|
||||||
</MenuItem>
|
)}
|
||||||
|
<MenuItem
|
||||||
|
onClick={() => {
|
||||||
|
closeMenuAndToggleFilesList()
|
||||||
|
void application.filesController.deleteFilesPermanently(selectedFiles)
|
||||||
|
}}
|
||||||
|
disabled={areSomeFilesInReadonlySharedVault}
|
||||||
|
>
|
||||||
|
<Icon type="trash" className={`mr-2 text-danger ${MenuItemIconSize}`} />
|
||||||
|
<span className="text-danger">Delete permanently</span>
|
||||||
|
</MenuItem>
|
||||||
|
</MenuSection>
|
||||||
|
|
||||||
<FileContextMenuBackupOption file={selectedFiles[0]} />
|
<FileContextMenuBackupOption file={selectedFiles[0]} />
|
||||||
|
|
||||||
<HorizontalSeparator classes="my-2" />
|
|
||||||
<div className="px-3 pb-0.5 pt-1 text-xs font-medium text-neutral">
|
<div className="px-3 pb-0.5 pt-1 text-xs font-medium text-neutral">
|
||||||
{!hasSelectedMultipleFiles && (
|
{!hasSelectedMultipleFiles && (
|
||||||
<div className="mb-1">
|
<div className="mb-1">
|
||||||
|
|||||||
@@ -19,7 +19,13 @@ const FilesOptionsPanel = ({ itemListController }: Props) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RoundIconButton label="File options menu" onClick={toggleMenu} ref={buttonRef} icon="more" />
|
<RoundIconButton label="File options menu" onClick={toggleMenu} ref={buttonRef} icon="more" />
|
||||||
<Popover title="File options" togglePopover={toggleMenu} anchorElement={buttonRef} open={isOpen} className="py-2">
|
<Popover
|
||||||
|
title="File options"
|
||||||
|
togglePopover={toggleMenu}
|
||||||
|
anchorElement={buttonRef}
|
||||||
|
open={isOpen}
|
||||||
|
className="md:pb-2"
|
||||||
|
>
|
||||||
<Menu a11yLabel="File options panel" isOpen={isOpen}>
|
<Menu a11yLabel="File options panel" isOpen={isOpen}>
|
||||||
<FileMenuOptions
|
<FileMenuOptions
|
||||||
selectedFiles={itemListController.selectedFiles}
|
selectedFiles={itemListController.selectedFiles}
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ const FilePreviewModal = observer(({ application }: Props) => {
|
|||||||
togglePopover={closeOptionsMenu}
|
togglePopover={closeOptionsMenu}
|
||||||
side="bottom"
|
side="bottom"
|
||||||
align="start"
|
align="start"
|
||||||
className="py-2"
|
className="md:pb-2"
|
||||||
overrideZIndex="z-modal"
|
overrideZIndex="z-modal"
|
||||||
>
|
>
|
||||||
<Menu a11yLabel="File context menu" isOpen={showOptionsMenu}>
|
<Menu a11yLabel="File context menu" isOpen={showOptionsMenu}>
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ const QuickSettingsButton = ({ application, isMobileNavigation = false }: Props)
|
|||||||
open={isOpen}
|
open={isOpen}
|
||||||
side="top"
|
side="top"
|
||||||
align="start"
|
align="start"
|
||||||
className="py-2"
|
className="md:py-2"
|
||||||
>
|
>
|
||||||
<QuickSettingsMenu closeMenu={toggleMenu} />
|
<QuickSettingsMenu closeMenu={toggleMenu} />
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ const Menu = forwardRef(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<menu
|
<menu
|
||||||
className={`m-0 list-none pl-0 focus:shadow-none ${className}`}
|
className={`m-0 list-none px-4 focus:shadow-none md:px-0 ${className}`}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
ref={mergeRefs([menuElementRef, forwardedRef])}
|
ref={mergeRefs([menuElementRef, forwardedRef])}
|
||||||
style={style}
|
style={style}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ const MenuItem = forwardRef(
|
|||||||
role="menuitem"
|
role="menuitem"
|
||||||
tabIndex={typeof tabIndex === 'number' ? tabIndex : FOCUSABLE_BUT_NOT_TABBABLE}
|
tabIndex={typeof tabIndex === 'number' ? tabIndex : FOCUSABLE_BUT_NOT_TABBABLE}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'flex w-full cursor-pointer select-none border-0 bg-transparent px-3 py-2 text-left md:py-1.5',
|
'flex w-full cursor-pointer select-none border-0 bg-transparent px-3 py-2.5 text-left md:py-1.5',
|
||||||
'text-mobile-menu-item text-text enabled:hover:bg-contrast enabled:hover:text-foreground',
|
'text-mobile-menu-item text-text enabled:hover:bg-contrast enabled:hover:text-foreground',
|
||||||
'focus:bg-info-backdrop focus:shadow-none md:text-tablet-menu-item lg:text-menu-item',
|
'focus:bg-info-backdrop focus:shadow-none md:text-tablet-menu-item lg:text-menu-item',
|
||||||
'disabled:cursor-not-allowed disabled:opacity-60',
|
'disabled:cursor-not-allowed disabled:opacity-60',
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ const MenuRadioButtonItem = forwardRef(
|
|||||||
role="menuitemradio"
|
role="menuitemradio"
|
||||||
tabIndex={typeof tabIndex === 'number' ? tabIndex : FOCUSABLE_BUT_NOT_TABBABLE}
|
tabIndex={typeof tabIndex === 'number' ? tabIndex : FOCUSABLE_BUT_NOT_TABBABLE}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'flex w-full cursor-pointer gap-2 border-0 bg-transparent px-3 py-2 text-left md:py-1.5',
|
'flex w-full cursor-pointer gap-2 border-0 bg-transparent px-3 py-2.5 text-left md:py-1.5',
|
||||||
'text-mobile-menu-item text-text hover:bg-contrast hover:text-foreground',
|
'text-mobile-menu-item text-text hover:bg-contrast hover:text-foreground',
|
||||||
'focus:bg-info-backdrop focus:shadow-none md:text-tablet-menu-item lg:text-menu-item',
|
'focus:bg-info-backdrop focus:shadow-none md:text-tablet-menu-item lg:text-menu-item',
|
||||||
className,
|
className,
|
||||||
|
|||||||
26
packages/web/src/javascripts/Components/Menu/MenuSection.tsx
Normal file
26
packages/web/src/javascripts/Components/Menu/MenuSection.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { classNames } from '@standardnotes/snjs'
|
||||||
|
import { ReactNode } from 'react'
|
||||||
|
|
||||||
|
const MenuSection = ({
|
||||||
|
title,
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
title?: ReactNode
|
||||||
|
className?: string
|
||||||
|
children: ReactNode
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'my-4 md:my-2 md:border-b md:border-border md:pb-2 md:last:mb-0 md:last:border-b-0 md:last:pb-0 md:translucent-ui:border-[--popover-border-color]',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{title && <div className="px-3 py-1 text-sm font-semibold uppercase text-text lg:text-xs">{title}</div>}
|
||||||
|
<div className="divide-y divide-passive-3 rounded bg-passive-4 md:divide-none md:bg-transparent">{children}</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MenuSection
|
||||||
@@ -36,7 +36,7 @@ const MenuSwitchButtonItem = forwardRef(
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5',
|
'flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-2 md:py-1.5',
|
||||||
'text-left text-text focus:bg-info-backdrop focus:shadow-none enabled:hover:bg-contrast enabled:hover:text-foreground',
|
'text-left text-text focus:bg-info-backdrop focus:shadow-none enabled:hover:bg-contrast enabled:hover:text-foreground',
|
||||||
'text-mobile-menu-item md:text-tablet-menu-item lg:text-menu-item',
|
'text-mobile-menu-item md:text-tablet-menu-item lg:text-menu-item',
|
||||||
'disabled:cursor-not-allowed disabled:opacity-60',
|
'disabled:cursor-not-allowed disabled:opacity-60',
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ const NotesContextMenu = () => {
|
|||||||
y: contextMenuClickLocation.y,
|
y: contextMenuClickLocation.y,
|
||||||
}}
|
}}
|
||||||
disableClickOutside={disableClickOutside}
|
disableClickOutside={disableClickOutside}
|
||||||
className="py-2"
|
|
||||||
open={contextMenuOpen}
|
open={contextMenuOpen}
|
||||||
togglePopover={closeMenu}
|
togglePopover={closeMenu}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ const AddTagOption: FunctionComponent<Props> = ({
|
|||||||
className="py-2"
|
className="py-2"
|
||||||
overrideZIndex="z-modal"
|
overrideZIndex="z-modal"
|
||||||
>
|
>
|
||||||
<Menu a11yLabel="Tag selection menu" isOpen={isOpen}>
|
<Menu a11yLabel="Tag selection menu" isOpen={isOpen} className="!px-0">
|
||||||
{navigationController.tags.map((tag) => (
|
{navigationController.tags.map((tag) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={tag.uuid}
|
key={tag.uuid}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({
|
|||||||
title="Change note type"
|
title="Change note type"
|
||||||
align="start"
|
align="start"
|
||||||
anchorElement={buttonRef}
|
anchorElement={buttonRef}
|
||||||
className="pt-2 md:pt-0"
|
className="md:pb-1"
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
side="right"
|
side="right"
|
||||||
togglePopover={toggleMenu}
|
togglePopover={toggleMenu}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { WebApplication } from '@/Application/WebApplication'
|
import { WebApplication } from '@/Application/WebApplication'
|
||||||
import { Action, SNNote } from '@standardnotes/snjs'
|
import { Action, SNNote } from '@standardnotes/snjs'
|
||||||
import { Fragment, useCallback, useEffect, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
import Icon from '@/Components/Icon/Icon'
|
import Icon from '@/Components/Icon/Icon'
|
||||||
import { ListedMenuGroup } from './ListedMenuGroup'
|
import { ListedMenuGroup } from './ListedMenuGroup'
|
||||||
import ListedMenuItem from './ListedMenuItem'
|
import ListedMenuItem from './ListedMenuItem'
|
||||||
import Spinner from '@/Components/Spinner/Spinner'
|
import Spinner from '@/Components/Spinner/Spinner'
|
||||||
|
import MenuSection from '@/Components/Menu/MenuSection'
|
||||||
|
|
||||||
type ListedActionsMenuProps = {
|
type ListedActionsMenuProps = {
|
||||||
application: WebApplication
|
application: WebApplication
|
||||||
@@ -125,15 +126,15 @@ const ListedActionsMenu = ({ application, note }: ListedActionsMenuProps) => {
|
|||||||
)}
|
)}
|
||||||
{!isFetchingAccounts && menuGroups.length ? (
|
{!isFetchingAccounts && menuGroups.length ? (
|
||||||
<>
|
<>
|
||||||
{menuGroups.map((group, index) => (
|
{menuGroups.map((group) => (
|
||||||
<Fragment key={group.account.authorId}>
|
<MenuSection
|
||||||
<div
|
key={group.account.authorId}
|
||||||
className={`text-input flex w-full items-center border-y border-solid border-border px-2.5 py-2 font-semibold text-text ${
|
title={
|
||||||
index === 0 ? 'mb-1 border-t-0' : 'my-1'
|
<div className="flex items-center">
|
||||||
}`}
|
<Icon type="notes" className="mr-2 text-info" /> {group.name}
|
||||||
>
|
</div>
|
||||||
<Icon type="notes" className="mr-2 text-info" /> {group.name}
|
}
|
||||||
</div>
|
>
|
||||||
{group.actions.length ? (
|
{group.actions.length ? (
|
||||||
group.actions.map((action) => (
|
group.actions.map((action) => (
|
||||||
<ListedMenuItem
|
<ListedMenuItem
|
||||||
@@ -148,7 +149,7 @@ const ListedActionsMenu = ({ application, note }: ListedActionsMenuProps) => {
|
|||||||
) : (
|
) : (
|
||||||
<div className="select-none px-3 py-2 text-sm text-passive-0">No actions available</div>
|
<div className="select-none px-3 py-2 text-sm text-passive-0">No actions available</div>
|
||||||
)}
|
)}
|
||||||
</Fragment>
|
</MenuSection>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ const ListedActionsOption: FunctionComponent<Props> = ({ application, note, icon
|
|||||||
open={isOpen}
|
open={isOpen}
|
||||||
side="right"
|
side="right"
|
||||||
align="end"
|
align="end"
|
||||||
className="pt-2 md:pt-0"
|
className="px-4 md:px-0 md:pt-0"
|
||||||
>
|
>
|
||||||
<ListedActionsMenu application={application} note={note} />
|
<ListedActionsMenu application={application} note={note} />
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import ListedActionsOption from './Listed/ListedActionsOption'
|
|||||||
import AddTagOption from './AddTagOption'
|
import AddTagOption from './AddTagOption'
|
||||||
import { addToast, dismissToast, ToastType } from '@standardnotes/toast'
|
import { addToast, dismissToast, ToastType } from '@standardnotes/toast'
|
||||||
import { NotesOptionsProps } from './NotesOptionsProps'
|
import { NotesOptionsProps } from './NotesOptionsProps'
|
||||||
import HorizontalSeparator from '../Shared/HorizontalSeparator'
|
|
||||||
import { useResponsiveAppPane } from '../Panes/ResponsivePaneProvider'
|
import { useResponsiveAppPane } from '../Panes/ResponsivePaneProvider'
|
||||||
import { AppPaneId } from '../Panes/AppPaneMetadata'
|
import { AppPaneId } from '../Panes/AppPaneMetadata'
|
||||||
import { getNoteBlob, getNoteFileName } from '@/Utils/NoteExportUtils'
|
import { getNoteBlob, getNoteFileName } from '@/Utils/NoteExportUtils'
|
||||||
@@ -42,6 +41,7 @@ import { MutuallyExclusiveMediaQueryBreakpoints } from '@/Hooks/useMediaQuery'
|
|||||||
import AddToVaultMenuOption from '../Vaults/AddToVaultMenuOption'
|
import AddToVaultMenuOption from '../Vaults/AddToVaultMenuOption'
|
||||||
import Menu from '../Menu/Menu'
|
import Menu from '../Menu/Menu'
|
||||||
import Popover from '../Popover/Popover'
|
import Popover from '../Popover/Popover'
|
||||||
|
import MenuSection from '../Menu/MenuSection'
|
||||||
|
|
||||||
const iconSize = MenuItemIconSize
|
const iconSize = MenuItemIconSize
|
||||||
const iconClassDanger = `text-danger mr-2 ${iconSize}`
|
const iconClassDanger = `text-danger mr-2 ${iconSize}`
|
||||||
@@ -230,271 +230,282 @@ const NotesOptions = ({ notes, closeMenu }: NotesOptionsProps) => {
|
|||||||
<>
|
<>
|
||||||
{notes.length === 1 && (
|
{notes.length === 1 && (
|
||||||
<>
|
<>
|
||||||
<MenuItem onClick={openRevisionHistoryModal}>
|
<MenuSection>
|
||||||
<Icon type="history" className={iconClass} />
|
<MenuItem onClick={openRevisionHistoryModal}>
|
||||||
Note history
|
<Icon type="history" className={iconClass} />
|
||||||
{historyShortcut && <KeyboardShortcutIndicator className="ml-auto" shortcut={historyShortcut} />}
|
Note history
|
||||||
</MenuItem>
|
{historyShortcut && <KeyboardShortcutIndicator className="ml-auto" shortcut={historyShortcut} />}
|
||||||
<HorizontalSeparator classes="my-2" />
|
</MenuItem>
|
||||||
<MenuItem onClick={toggleLineWidthModal} disabled={areSomeNotesInReadonlySharedVault}>
|
</MenuSection>
|
||||||
<Icon type="line-width" className={iconClass} />
|
<MenuSection>
|
||||||
Editor width
|
<MenuItem onClick={toggleLineWidthModal} disabled={areSomeNotesInReadonlySharedVault}>
|
||||||
{editorWidthShortcut && <KeyboardShortcutIndicator className="ml-auto" shortcut={editorWidthShortcut} />}
|
<Icon type="line-width" className={iconClass} />
|
||||||
</MenuItem>
|
Editor width
|
||||||
|
{editorWidthShortcut && <KeyboardShortcutIndicator className="ml-auto" shortcut={editorWidthShortcut} />}
|
||||||
|
</MenuItem>
|
||||||
|
</MenuSection>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<MenuSwitchButtonItem
|
<MenuSection>
|
||||||
checked={locked}
|
<MenuSwitchButtonItem
|
||||||
onChange={(locked) => {
|
checked={locked}
|
||||||
application.notesController.setLockSelectedNotes(locked)
|
onChange={(locked) => {
|
||||||
}}
|
application.notesController.setLockSelectedNotes(locked)
|
||||||
disabled={areSomeNotesInReadonlySharedVault}
|
}}
|
||||||
>
|
disabled={areSomeNotesInReadonlySharedVault}
|
||||||
<Icon type="pencil-off" className={iconClass} />
|
>
|
||||||
Prevent editing
|
<Icon type="pencil-off" className={iconClass} />
|
||||||
</MenuSwitchButtonItem>
|
Prevent editing
|
||||||
<MenuSwitchButtonItem
|
</MenuSwitchButtonItem>
|
||||||
checked={!hidePreviews}
|
<MenuSwitchButtonItem
|
||||||
onChange={(hidePreviews) => {
|
checked={!hidePreviews}
|
||||||
application.notesController.setHideSelectedNotePreviews(!hidePreviews)
|
onChange={(hidePreviews) => {
|
||||||
}}
|
application.notesController.setHideSelectedNotePreviews(!hidePreviews)
|
||||||
disabled={areSomeNotesInReadonlySharedVault}
|
}}
|
||||||
>
|
disabled={areSomeNotesInReadonlySharedVault}
|
||||||
<Icon type="rich-text" className={iconClass} />
|
>
|
||||||
Show preview
|
<Icon type="rich-text" className={iconClass} />
|
||||||
</MenuSwitchButtonItem>
|
Show preview
|
||||||
<MenuSwitchButtonItem
|
</MenuSwitchButtonItem>
|
||||||
checked={protect}
|
<MenuSwitchButtonItem
|
||||||
onChange={(protect) => {
|
checked={protect}
|
||||||
application.notesController.setProtectSelectedNotes(protect).catch(console.error)
|
onChange={(protect) => {
|
||||||
}}
|
application.notesController.setProtectSelectedNotes(protect).catch(console.error)
|
||||||
disabled={areSomeNotesInReadonlySharedVault}
|
}}
|
||||||
>
|
disabled={areSomeNotesInReadonlySharedVault}
|
||||||
<Icon type="lock" className={iconClass} />
|
>
|
||||||
Password protect
|
<Icon type="lock" className={iconClass} />
|
||||||
</MenuSwitchButtonItem>
|
Password protect
|
||||||
|
</MenuSwitchButtonItem>
|
||||||
|
</MenuSection>
|
||||||
{notes.length === 1 && (
|
{notes.length === 1 && (
|
||||||
<>
|
<MenuSection>
|
||||||
<HorizontalSeparator classes="my-2" />
|
|
||||||
<ChangeEditorOption
|
<ChangeEditorOption
|
||||||
iconClassName={iconClass}
|
iconClassName={iconClass}
|
||||||
application={application}
|
application={application}
|
||||||
note={notes[0]}
|
note={notes[0]}
|
||||||
disabled={areSomeNotesInReadonlySharedVault}
|
disabled={areSomeNotesInReadonlySharedVault}
|
||||||
/>
|
/>
|
||||||
</>
|
</MenuSection>
|
||||||
)}
|
|
||||||
<HorizontalSeparator classes="my-2" />
|
|
||||||
|
|
||||||
{application.featuresController.isVaultsEnabled() && (
|
|
||||||
<AddToVaultMenuOption iconClassName={iconClass} items={notes} disabled={!hasAdminPermissionForAllSharedNotes} />
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{application.navigationController.tagsCount > 0 && (
|
<MenuSection>
|
||||||
<AddTagOption
|
{application.featuresController.isVaultsEnabled() && (
|
||||||
iconClassName={iconClass}
|
<AddToVaultMenuOption
|
||||||
navigationController={application.navigationController}
|
iconClassName={iconClass}
|
||||||
selectedItems={notes}
|
items={notes}
|
||||||
linkingController={application.linkingController}
|
disabled={!hasAdminPermissionForAllSharedNotes}
|
||||||
disabled={areSomeNotesInReadonlySharedVault}
|
/>
|
||||||
/>
|
)}
|
||||||
)}
|
|
||||||
<MenuItem
|
|
||||||
onClick={() => {
|
|
||||||
application.notesController.setStarSelectedNotes(!starred)
|
|
||||||
}}
|
|
||||||
disabled={areSomeNotesInReadonlySharedVault}
|
|
||||||
>
|
|
||||||
<Icon type="star" className={iconClass} />
|
|
||||||
{starred ? 'Unstar' : 'Star'}
|
|
||||||
{starShortcut && <KeyboardShortcutIndicator className="ml-auto" shortcut={starShortcut} />}
|
|
||||||
</MenuItem>
|
|
||||||
|
|
||||||
{unpinned && (
|
{application.navigationController.tagsCount > 0 && (
|
||||||
|
<AddTagOption
|
||||||
|
iconClassName={iconClass}
|
||||||
|
navigationController={application.navigationController}
|
||||||
|
selectedItems={notes}
|
||||||
|
linkingController={application.linkingController}
|
||||||
|
disabled={areSomeNotesInReadonlySharedVault}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
application.notesController.setPinSelectedNotes(true)
|
application.notesController.setStarSelectedNotes(!starred)
|
||||||
}}
|
}}
|
||||||
disabled={areSomeNotesInReadonlySharedVault}
|
disabled={areSomeNotesInReadonlySharedVault}
|
||||||
>
|
>
|
||||||
<Icon type="pin" className={iconClass} />
|
<Icon type="star" className={iconClass} />
|
||||||
Pin to top
|
{starred ? 'Unstar' : 'Star'}
|
||||||
{pinShortcut && <KeyboardShortcutIndicator className="ml-auto" shortcut={pinShortcut} />}
|
{starShortcut && <KeyboardShortcutIndicator className="ml-auto" shortcut={starShortcut} />}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
|
||||||
{pinned && (
|
{unpinned && (
|
||||||
<MenuItem
|
|
||||||
onClick={() => {
|
|
||||||
application.notesController.setPinSelectedNotes(false)
|
|
||||||
}}
|
|
||||||
disabled={areSomeNotesInReadonlySharedVault}
|
|
||||||
>
|
|
||||||
<Icon type="unpin" className={iconClass} />
|
|
||||||
Unpin
|
|
||||||
{pinShortcut && <KeyboardShortcutIndicator className="ml-auto" shortcut={pinShortcut} />}
|
|
||||||
</MenuItem>
|
|
||||||
)}
|
|
||||||
{isOnlySuperNoteSelected ? (
|
|
||||||
<>
|
|
||||||
<MenuItem
|
|
||||||
ref={superExportButtonRef}
|
|
||||||
onClick={() => {
|
|
||||||
setIsSuperExportMenuOpen((open) => !open)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="flex items-center">
|
|
||||||
<Icon type="download" className={iconClass} />
|
|
||||||
Export
|
|
||||||
</div>
|
|
||||||
<Icon type="chevron-right" className="ml-auto text-neutral" />
|
|
||||||
</MenuItem>
|
|
||||||
<Popover
|
|
||||||
title="Export note"
|
|
||||||
side="left"
|
|
||||||
align="start"
|
|
||||||
open={isSuperExportMenuOpen}
|
|
||||||
anchorElement={superExportButtonRef.current}
|
|
||||||
togglePopover={() => {
|
|
||||||
setIsSuperExportMenuOpen(!isSuperExportMenuOpen)
|
|
||||||
}}
|
|
||||||
className="py-1"
|
|
||||||
>
|
|
||||||
<Menu a11yLabel={'Super note export menu'} isOpen={isSuperExportMenuOpen}>
|
|
||||||
<MenuItem onClick={() => commandService.triggerCommand(SUPER_EXPORT_JSON, notes[0].title)}>
|
|
||||||
<Icon type="code" className={iconClass} />
|
|
||||||
Export as JSON
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem onClick={() => commandService.triggerCommand(SUPER_EXPORT_MARKDOWN, notes[0].title)}>
|
|
||||||
<Icon type="markdown" className={iconClass} />
|
|
||||||
Export as Markdown
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem onClick={() => commandService.triggerCommand(SUPER_EXPORT_HTML, notes[0].title)}>
|
|
||||||
<Icon type="rich-text" className={iconClass} />
|
|
||||||
Export as HTML
|
|
||||||
</MenuItem>
|
|
||||||
</Menu>
|
|
||||||
</Popover>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (application.isNativeMobileWeb()) {
|
application.notesController.setPinSelectedNotes(true)
|
||||||
void shareSelectedNotes(application, notes)
|
|
||||||
} else {
|
|
||||||
const hasSuperNote = notes.some((note) => note.noteType === NoteType.Super)
|
|
||||||
|
|
||||||
if (hasSuperNote) {
|
|
||||||
setShowExportSuperModal(true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
void downloadSelectedItems()
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon type={application.platform === Platform.Android ? 'share' : 'download'} className={iconClass} />
|
|
||||||
{application.platform === Platform.Android ? 'Share' : 'Export'}
|
|
||||||
</MenuItem>
|
|
||||||
{application.platform === Platform.Android && (
|
|
||||||
<MenuItem onClick={() => downloadSelectedNotesOnAndroid(application, notes)}>
|
|
||||||
<Icon type="download" className={iconClass} />
|
|
||||||
Export
|
|
||||||
</MenuItem>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<MenuItem onClick={duplicateSelectedItems} disabled={areSomeNotesInReadonlySharedVault}>
|
|
||||||
<Icon type="copy" className={iconClass} />
|
|
||||||
Duplicate
|
|
||||||
</MenuItem>
|
|
||||||
{unarchived && (
|
|
||||||
<MenuItem
|
|
||||||
onClick={async () => {
|
|
||||||
await application.notesController.setArchiveSelectedNotes(true).catch(console.error)
|
|
||||||
closeMenuAndToggleNotesList()
|
|
||||||
}}
|
|
||||||
disabled={areSomeNotesInReadonlySharedVault}
|
|
||||||
>
|
|
||||||
<Icon type="archive" className={iconClassWarning} />
|
|
||||||
<span className="text-warning">Archive</span>
|
|
||||||
</MenuItem>
|
|
||||||
)}
|
|
||||||
{archived && (
|
|
||||||
<MenuItem
|
|
||||||
onClick={async () => {
|
|
||||||
await application.notesController.setArchiveSelectedNotes(false).catch(console.error)
|
|
||||||
closeMenuAndToggleNotesList()
|
|
||||||
}}
|
|
||||||
disabled={areSomeNotesInReadonlySharedVault}
|
|
||||||
>
|
|
||||||
<Icon type="unarchive" className={iconClassWarning} />
|
|
||||||
<span className="text-warning">Unarchive</span>
|
|
||||||
</MenuItem>
|
|
||||||
)}
|
|
||||||
{notTrashed &&
|
|
||||||
(altKeyDown ? (
|
|
||||||
<MenuItem
|
|
||||||
disabled={areSomeNotesInReadonlySharedVault}
|
|
||||||
onClick={async () => {
|
|
||||||
await application.notesController.deleteNotesPermanently()
|
|
||||||
closeMenuAndToggleNotesList()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon type="close" className="mr-2 text-danger" />
|
|
||||||
<span className="text-danger">Delete permanently</span>
|
|
||||||
</MenuItem>
|
|
||||||
) : (
|
|
||||||
<MenuItem
|
|
||||||
onClick={async () => {
|
|
||||||
await application.notesController.setTrashSelectedNotes(true)
|
|
||||||
closeMenuAndToggleNotesList()
|
|
||||||
}}
|
}}
|
||||||
disabled={areSomeNotesInReadonlySharedVault}
|
disabled={areSomeNotesInReadonlySharedVault}
|
||||||
>
|
>
|
||||||
<Icon type="trash" className={iconClassDanger} />
|
<Icon type="pin" className={iconClass} />
|
||||||
<span className="text-danger">Move to trash</span>
|
Pin to top
|
||||||
|
{pinShortcut && <KeyboardShortcutIndicator className="ml-auto" shortcut={pinShortcut} />}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
)}
|
||||||
{trashed && (
|
{pinned && (
|
||||||
<>
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={async () => {
|
onClick={() => {
|
||||||
await application.notesController.setTrashSelectedNotes(false)
|
application.notesController.setPinSelectedNotes(false)
|
||||||
closeMenuAndToggleNotesList()
|
|
||||||
}}
|
}}
|
||||||
disabled={areSomeNotesInReadonlySharedVault}
|
disabled={areSomeNotesInReadonlySharedVault}
|
||||||
>
|
>
|
||||||
<Icon type="restore" className={iconClassSuccess} />
|
<Icon type="unpin" className={iconClass} />
|
||||||
<span className="text-success">Restore</span>
|
Unpin
|
||||||
|
{pinShortcut && <KeyboardShortcutIndicator className="ml-auto" shortcut={pinShortcut} />}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
)}
|
||||||
disabled={areSomeNotesInReadonlySharedVault}
|
{isOnlySuperNoteSelected ? (
|
||||||
onClick={async () => {
|
<>
|
||||||
await application.notesController.deleteNotesPermanently()
|
<MenuItem
|
||||||
closeMenuAndToggleNotesList()
|
ref={superExportButtonRef}
|
||||||
}}
|
onClick={() => {
|
||||||
>
|
setIsSuperExportMenuOpen((open) => !open)
|
||||||
<Icon type="close" className="mr-2 text-danger" />
|
}}
|
||||||
<span className="text-danger">Delete permanently</span>
|
>
|
||||||
</MenuItem>
|
<div className="flex items-center">
|
||||||
<MenuItem
|
<Icon type="download" className={iconClass} />
|
||||||
onClick={async () => {
|
Export
|
||||||
await application.notesController.emptyTrash()
|
|
||||||
closeMenuAndToggleNotesList()
|
|
||||||
}}
|
|
||||||
disabled={areSomeNotesInReadonlySharedVault}
|
|
||||||
>
|
|
||||||
<div className="flex items-start">
|
|
||||||
<Icon type="trash-sweep" className="mr-2 text-danger" />
|
|
||||||
<div className="flex-row">
|
|
||||||
<div className="text-danger">Empty Trash</div>
|
|
||||||
<div className="text-xs">{application.notesController.trashedNotesCount} notes in Trash</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<Icon type="chevron-right" className="ml-auto text-neutral" />
|
||||||
|
</MenuItem>
|
||||||
|
<Popover
|
||||||
|
title="Export note"
|
||||||
|
side="left"
|
||||||
|
align="start"
|
||||||
|
open={isSuperExportMenuOpen}
|
||||||
|
anchorElement={superExportButtonRef.current}
|
||||||
|
togglePopover={() => {
|
||||||
|
setIsSuperExportMenuOpen(!isSuperExportMenuOpen)
|
||||||
|
}}
|
||||||
|
className="md:py-1"
|
||||||
|
>
|
||||||
|
<Menu a11yLabel={'Super note export menu'} isOpen={isSuperExportMenuOpen}>
|
||||||
|
<MenuSection>
|
||||||
|
<MenuItem onClick={() => commandService.triggerCommand(SUPER_EXPORT_JSON, notes[0].title)}>
|
||||||
|
<Icon type="code" className={iconClass} />
|
||||||
|
Export as JSON
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem onClick={() => commandService.triggerCommand(SUPER_EXPORT_MARKDOWN, notes[0].title)}>
|
||||||
|
<Icon type="markdown" className={iconClass} />
|
||||||
|
Export as Markdown
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem onClick={() => commandService.triggerCommand(SUPER_EXPORT_HTML, notes[0].title)}>
|
||||||
|
<Icon type="rich-text" className={iconClass} />
|
||||||
|
Export as HTML
|
||||||
|
</MenuItem>
|
||||||
|
</MenuSection>
|
||||||
|
</Menu>
|
||||||
|
</Popover>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<MenuItem
|
||||||
|
onClick={() => {
|
||||||
|
if (application.isNativeMobileWeb()) {
|
||||||
|
void shareSelectedNotes(application, notes)
|
||||||
|
} else {
|
||||||
|
const hasSuperNote = notes.some((note) => note.noteType === NoteType.Super)
|
||||||
|
|
||||||
|
if (hasSuperNote) {
|
||||||
|
setShowExportSuperModal(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
void downloadSelectedItems()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon type={application.platform === Platform.Android ? 'share' : 'download'} className={iconClass} />
|
||||||
|
{application.platform === Platform.Android ? 'Share' : 'Export'}
|
||||||
|
</MenuItem>
|
||||||
|
{application.platform === Platform.Android && (
|
||||||
|
<MenuItem onClick={() => downloadSelectedNotesOnAndroid(application, notes)}>
|
||||||
|
<Icon type="download" className={iconClass} />
|
||||||
|
Export
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<MenuItem onClick={duplicateSelectedItems} disabled={areSomeNotesInReadonlySharedVault}>
|
||||||
|
<Icon type="copy" className={iconClass} />
|
||||||
|
Duplicate
|
||||||
|
</MenuItem>
|
||||||
|
{unarchived && (
|
||||||
|
<MenuItem
|
||||||
|
onClick={async () => {
|
||||||
|
await application.notesController.setArchiveSelectedNotes(true).catch(console.error)
|
||||||
|
closeMenuAndToggleNotesList()
|
||||||
|
}}
|
||||||
|
disabled={areSomeNotesInReadonlySharedVault}
|
||||||
|
>
|
||||||
|
<Icon type="archive" className={iconClassWarning} />
|
||||||
|
<span className="text-warning">Archive</span>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</>
|
)}
|
||||||
)}
|
{archived && (
|
||||||
|
<MenuItem
|
||||||
|
onClick={async () => {
|
||||||
|
await application.notesController.setArchiveSelectedNotes(false).catch(console.error)
|
||||||
|
closeMenuAndToggleNotesList()
|
||||||
|
}}
|
||||||
|
disabled={areSomeNotesInReadonlySharedVault}
|
||||||
|
>
|
||||||
|
<Icon type="unarchive" className={iconClassWarning} />
|
||||||
|
<span className="text-warning">Unarchive</span>
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
|
{notTrashed &&
|
||||||
|
(altKeyDown ? (
|
||||||
|
<MenuItem
|
||||||
|
disabled={areSomeNotesInReadonlySharedVault}
|
||||||
|
onClick={async () => {
|
||||||
|
await application.notesController.deleteNotesPermanently()
|
||||||
|
closeMenuAndToggleNotesList()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon type="close" className="mr-2 text-danger" />
|
||||||
|
<span className="text-danger">Delete permanently</span>
|
||||||
|
</MenuItem>
|
||||||
|
) : (
|
||||||
|
<MenuItem
|
||||||
|
onClick={async () => {
|
||||||
|
await application.notesController.setTrashSelectedNotes(true)
|
||||||
|
closeMenuAndToggleNotesList()
|
||||||
|
}}
|
||||||
|
disabled={areSomeNotesInReadonlySharedVault}
|
||||||
|
>
|
||||||
|
<Icon type="trash" className={iconClassDanger} />
|
||||||
|
<span className="text-danger">Move to trash</span>
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
{trashed && (
|
||||||
|
<>
|
||||||
|
<MenuItem
|
||||||
|
onClick={async () => {
|
||||||
|
await application.notesController.setTrashSelectedNotes(false)
|
||||||
|
closeMenuAndToggleNotesList()
|
||||||
|
}}
|
||||||
|
disabled={areSomeNotesInReadonlySharedVault}
|
||||||
|
>
|
||||||
|
<Icon type="restore" className={iconClassSuccess} />
|
||||||
|
<span className="text-success">Restore</span>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
disabled={areSomeNotesInReadonlySharedVault}
|
||||||
|
onClick={async () => {
|
||||||
|
await application.notesController.deleteNotesPermanently()
|
||||||
|
closeMenuAndToggleNotesList()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon type="close" className="mr-2 text-danger" />
|
||||||
|
<span className="text-danger">Delete permanently</span>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
onClick={async () => {
|
||||||
|
await application.notesController.emptyTrash()
|
||||||
|
closeMenuAndToggleNotesList()
|
||||||
|
}}
|
||||||
|
disabled={areSomeNotesInReadonlySharedVault}
|
||||||
|
>
|
||||||
|
<div className="flex items-start">
|
||||||
|
<Icon type="trash-sweep" className="mr-2 text-danger" />
|
||||||
|
<div className="flex-row">
|
||||||
|
<div className="text-danger">Empty Trash</div>
|
||||||
|
<div className="text-xs">{application.notesController.trashedNotesCount} notes in Trash</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</MenuItem>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</MenuSection>
|
||||||
|
|
||||||
{notes.length === 1 ? (
|
{notes.length === 1 ? (
|
||||||
<>
|
<>
|
||||||
@@ -507,25 +518,22 @@ const NotesOptions = ({ notes, closeMenu }: NotesOptionsProps) => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{!areSomeNotesInSharedVault && (
|
{!areSomeNotesInSharedVault && (
|
||||||
<>
|
<MenuSection>
|
||||||
<HorizontalSeparator classes="my-2" />
|
|
||||||
<ListedActionsOption iconClassName={iconClass} application={application} note={notes[0]} />
|
<ListedActionsOption iconClassName={iconClass} application={application} note={notes[0]} />
|
||||||
</>
|
</MenuSection>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<HorizontalSeparator classes="my-2" />
|
|
||||||
|
|
||||||
{editorForNote && (
|
{editorForNote && (
|
||||||
<SpellcheckOptions
|
<MenuSection>
|
||||||
editorForNote={editorForNote}
|
<SpellcheckOptions
|
||||||
notesController={application.notesController}
|
editorForNote={editorForNote}
|
||||||
note={notes[0]}
|
notesController={application.notesController}
|
||||||
disabled={areSomeNotesInReadonlySharedVault}
|
note={notes[0]}
|
||||||
/>
|
disabled={areSomeNotesInReadonlySharedVault}
|
||||||
|
/>
|
||||||
|
</MenuSection>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<HorizontalSeparator classes="my-2" />
|
|
||||||
|
|
||||||
<NoteAttributes className="mb-2" application={application} note={notes[0]} />
|
<NoteAttributes className="mb-2" application={application} note={notes[0]} />
|
||||||
|
|
||||||
<NoteSizeWarning note={notes[0]} />
|
<NoteSizeWarning note={notes[0]} />
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ const NotesOptionsPanel = ({ notesController, onClickPreprocessing }: Props) =>
|
|||||||
togglePopover={toggleMenu}
|
togglePopover={toggleMenu}
|
||||||
anchorElement={buttonRef}
|
anchorElement={buttonRef}
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
className="select-none pt-2"
|
className="select-none"
|
||||||
>
|
>
|
||||||
<Menu a11yLabel="Note options menu" isOpen={isOpen}>
|
<Menu a11yLabel="Note options menu" isOpen={isOpen}>
|
||||||
<NotesOptions
|
<NotesOptions
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import { PlatformedKeyboardShortcut } from '@standardnotes/ui-services'
|
|||||||
import Icon from '../Icon/Icon'
|
import Icon from '../Icon/Icon'
|
||||||
import { KeyboardShortcutIndicator } from '../KeyboardShortcutIndicator/KeyboardShortcutIndicator'
|
import { KeyboardShortcutIndicator } from '../KeyboardShortcutIndicator/KeyboardShortcutIndicator'
|
||||||
import MenuItem from '../Menu/MenuItem'
|
import MenuItem from '../Menu/MenuItem'
|
||||||
import HorizontalSeparator from '../Shared/HorizontalSeparator'
|
|
||||||
import { iconClass } from './ClassNames'
|
import { iconClass } from './ClassNames'
|
||||||
|
import MenuSection from '../Menu/MenuSection'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
note: SNNote
|
note: SNNote
|
||||||
@@ -14,17 +14,13 @@ type Props = {
|
|||||||
|
|
||||||
const SuperNoteOptions = ({ markdownShortcut, enableSuperMarkdownPreview }: Props) => {
|
const SuperNoteOptions = ({ markdownShortcut, enableSuperMarkdownPreview }: Props) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<MenuSection>
|
||||||
<HorizontalSeparator classes="my-2" />
|
|
||||||
|
|
||||||
<div className="my-1 px-3 text-base font-semibold uppercase text-text lg:text-xs">Super</div>
|
|
||||||
|
|
||||||
<MenuItem onClick={enableSuperMarkdownPreview}>
|
<MenuItem onClick={enableSuperMarkdownPreview}>
|
||||||
<Icon type="markdown" className={iconClass} />
|
<Icon type="markdown" className={iconClass} />
|
||||||
Show Markdown
|
Show Markdown
|
||||||
{markdownShortcut && <KeyboardShortcutIndicator className="ml-auto" shortcut={markdownShortcut} />}
|
{markdownShortcut && <KeyboardShortcutIndicator className="ml-auto" shortcut={markdownShortcut} />}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</>
|
</MenuSection>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import MenuSwitchButtonItem from '../Menu/MenuSwitchButtonItem'
|
|||||||
import MenuRadioButtonItem from '../Menu/MenuRadioButtonItem'
|
import MenuRadioButtonItem from '../Menu/MenuRadioButtonItem'
|
||||||
import { useApplication } from '../ApplicationProvider'
|
import { useApplication } from '../ApplicationProvider'
|
||||||
import { GetAllThemesUseCase } from '@standardnotes/ui-services'
|
import { GetAllThemesUseCase } from '@standardnotes/ui-services'
|
||||||
import MenuItemSeparator from '../Menu/MenuItemSeparator'
|
import MenuSection from '../Menu/MenuSection'
|
||||||
|
|
||||||
type MenuProps = {
|
type MenuProps = {
|
||||||
closeMenu: () => void
|
closeMenu: () => void
|
||||||
@@ -117,8 +117,7 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = ({ closeMenu }) => {
|
|||||||
return (
|
return (
|
||||||
<Menu a11yLabel="Quick settings menu" isOpen>
|
<Menu a11yLabel="Quick settings menu" isOpen>
|
||||||
{editorStackComponents.length > 0 && (
|
{editorStackComponents.length > 0 && (
|
||||||
<>
|
<MenuSection title="Tools">
|
||||||
<div className="my-1 px-3 text-sm font-semibold uppercase text-text">Tools</div>
|
|
||||||
{editorStackComponents.map((component) => (
|
{editorStackComponents.map((component) => (
|
||||||
<MenuSwitchButtonItem
|
<MenuSwitchButtonItem
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
@@ -131,17 +130,17 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = ({ closeMenu }) => {
|
|||||||
{component.displayName}
|
{component.displayName}
|
||||||
</MenuSwitchButtonItem>
|
</MenuSwitchButtonItem>
|
||||||
))}
|
))}
|
||||||
<MenuItemSeparator />
|
</MenuSection>
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
<div className="my-1 px-3 text-sm font-semibold uppercase text-text">Appearance</div>
|
<MenuSection title="Appearance">
|
||||||
<MenuRadioButtonItem checked={defaultThemeOn} onClick={toggleDefaultTheme} ref={defaultThemeButtonRef}>
|
<MenuRadioButtonItem checked={defaultThemeOn} onClick={toggleDefaultTheme} ref={defaultThemeButtonRef}>
|
||||||
Default
|
Default
|
||||||
</MenuRadioButtonItem>
|
</MenuRadioButtonItem>
|
||||||
{themes.map((theme) => (
|
{themes.map((theme) => (
|
||||||
<ThemesMenuButton uiFeature={theme} key={theme.uniqueIdentifier.value} />
|
<ThemesMenuButton uiFeature={theme} key={theme.uniqueIdentifier.value} />
|
||||||
))}
|
))}
|
||||||
<MenuItemSeparator />
|
</MenuSection>
|
||||||
|
|
||||||
<FocusModeSwitch
|
<FocusModeSwitch
|
||||||
application={application}
|
application={application}
|
||||||
onToggle={setFocusModeEnabled}
|
onToggle={setFocusModeEnabled}
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ function TableActionMenu({ onClose, tableCellNode: _tableCellNode, cellMerge }:
|
|||||||
(tableCellNode.__headerState & TableCellHeaderStates.COLUMN) === TableCellHeaderStates.COLUMN
|
(tableCellNode.__headerState & TableCellHeaderStates.COLUMN) === TableCellHeaderStates.COLUMN
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Menu className="dropdown" ref={dropDownRef} a11yLabel="Table actions menu" isOpen>
|
<Menu className="dropdown !px-0" ref={dropDownRef} a11yLabel="Table actions menu" isOpen>
|
||||||
{mergeCellButton}
|
{mergeCellButton}
|
||||||
{!!mergeCellButton && <MenuItemSeparator />}
|
{!!mergeCellButton && <MenuItemSeparator />}
|
||||||
<MenuItem onClick={() => insertTableRowAtSelection(false)}>
|
<MenuItem onClick={() => insertTableRowAtSelection(false)}>
|
||||||
|
|||||||
@@ -685,7 +685,7 @@ const ToolbarPlugin = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Menu a11yLabel="Table of contents" isOpen>
|
<Menu a11yLabel="Table of contents" isOpen className="!px-0">
|
||||||
{tableOfContents.map(([key, text, tag]) => (
|
{tableOfContents.map(([key, text, tag]) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={key}
|
key={key}
|
||||||
|
|||||||
Reference in New Issue
Block a user