feat: "create new note" floating button on mobile (#1857)
This commit is contained in:
@@ -1,32 +1,37 @@
|
||||
import { FunctionComponent, MouseEventHandler } from 'react'
|
||||
import { ForwardedRef, forwardRef, MouseEventHandler } from 'react'
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import { IconType } from '@standardnotes/snjs'
|
||||
|
||||
type ButtonType = 'normal' | 'primary'
|
||||
import { classNames } from '@/Utils/ConcatenateClassNames'
|
||||
|
||||
type Props = {
|
||||
onClick: () => void
|
||||
type: ButtonType
|
||||
className?: string
|
||||
icon: IconType
|
||||
iconClassName?: string
|
||||
label: string
|
||||
id?: string
|
||||
}
|
||||
|
||||
const RoundIconButton: FunctionComponent<Props> = ({ onClick, type, className, icon: iconType }) => {
|
||||
const click: MouseEventHandler = (e) => {
|
||||
e.preventDefault()
|
||||
onClick()
|
||||
}
|
||||
const classes = type === 'primary' ? 'info ' : ''
|
||||
return (
|
||||
<button
|
||||
className={`m-0 flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border bg-transparent bg-clip-padding text-neutral hover:bg-contrast hover:text-text focus:bg-contrast focus:text-text focus:outline-none focus:ring-info ${classes} ${
|
||||
className ?? ''
|
||||
}`}
|
||||
onClick={click}
|
||||
>
|
||||
<Icon type={iconType} />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
const RoundIconButton = forwardRef(
|
||||
({ onClick, className, icon: iconType, iconClassName, id }: Props, ref: ForwardedRef<HTMLButtonElement>) => {
|
||||
const click: MouseEventHandler = (e) => {
|
||||
e.preventDefault()
|
||||
onClick()
|
||||
}
|
||||
return (
|
||||
<button
|
||||
className={classNames(
|
||||
'bg-text-padding min-w-8.5 m-0 flex h-8.5 cursor-pointer items-center justify-center rounded-full border border-solid border-border bg-clip-padding text-neutral hover:bg-contrast hover:text-text focus:bg-contrast focus:text-text focus:outline-none focus:ring-info md:h-8 md:min-w-8',
|
||||
className,
|
||||
)}
|
||||
onClick={click}
|
||||
ref={ref}
|
||||
id={id}
|
||||
>
|
||||
<Icon type={iconType} className={iconClassName} />
|
||||
</button>
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
export default RoundIconButton
|
||||
|
||||
@@ -2,9 +2,9 @@ import { WebApplication } from '@/Application/Application'
|
||||
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { FunctionComponent, useCallback, useRef, useState } from 'react'
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import ChangeEditorMenu from './ChangeEditorMenu'
|
||||
import Popover from '../Popover/Popover'
|
||||
import RoundIconButton from '../Button/RoundIconButton'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -38,15 +38,13 @@ const ChangeEditorButton: FunctionComponent<Props> = ({
|
||||
|
||||
return (
|
||||
<div ref={containerRef}>
|
||||
<button
|
||||
className="bg-text-padding flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-border text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
title="Change note type"
|
||||
aria-label="Change note type"
|
||||
<RoundIconButton
|
||||
label="Change note type"
|
||||
onClick={toggleMenu}
|
||||
ref={buttonRef}
|
||||
>
|
||||
<Icon type={selectedEditorIcon} className={`text-accessory-tint-${selectedEditorIconTint}`} />
|
||||
</button>
|
||||
icon={selectedEditorIcon}
|
||||
iconClassName={`text-accessory-tint-${selectedEditorIconTint}`}
|
||||
/>
|
||||
<Popover togglePopover={toggleMenu} anchorElement={buttonRef.current} open={isOpen} className="pt-2 md:pt-0">
|
||||
<ChangeEditorMenu
|
||||
application={application}
|
||||
|
||||
@@ -5,11 +5,13 @@ import { classNames } from '@/Utils/ConcatenateClassNames'
|
||||
import Popover from '@/Components/Popover/Popover'
|
||||
import DisplayOptionsMenu from './DisplayOptionsMenu'
|
||||
import { NavigationMenuButton } from '@/Components/NavigationMenu/NavigationMenu'
|
||||
import RoundIconButton from '@/Components/Button/RoundIconButton'
|
||||
|
||||
type Props = {
|
||||
application: {
|
||||
getPreference: WebApplication['getPreference']
|
||||
setPreference: WebApplication['setPreference']
|
||||
isNativeMobileWeb: WebApplication['isNativeMobileWeb']
|
||||
}
|
||||
panelTitle: string
|
||||
addButtonLabel: string
|
||||
@@ -44,16 +46,13 @@ const ContentListHeader = ({
|
||||
</div>
|
||||
<div className="flex">
|
||||
<div className="relative" ref={displayOptionsContainerRef}>
|
||||
<button
|
||||
className={classNames(
|
||||
'bg-text-padding flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border text-neutral hover:bg-contrast focus:bg-contrast',
|
||||
showDisplayOptionsMenu && 'bg-contrast',
|
||||
)}
|
||||
<RoundIconButton
|
||||
className={classNames(showDisplayOptionsMenu && 'bg-contrast')}
|
||||
onClick={toggleDisplayOptionsMenu}
|
||||
ref={displayOptionsButtonRef}
|
||||
>
|
||||
<Icon type="sort-descending" />
|
||||
</button>
|
||||
icon="sort-descending"
|
||||
label="Display options menu"
|
||||
/>
|
||||
<Popover
|
||||
open={showDisplayOptionsMenu}
|
||||
anchorElement={displayOptionsButtonRef.current}
|
||||
@@ -70,12 +69,12 @@ const ContentListHeader = ({
|
||||
</Popover>
|
||||
</div>
|
||||
<button
|
||||
className="ml-3 flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-transparent bg-info text-info-contrast hover:brightness-125"
|
||||
className="absolute bottom-6 right-6 ml-3 flex h-13 w-13 cursor-pointer items-center justify-center rounded-full border border-solid border-transparent bg-info text-info-contrast hover:brightness-125 md:static md:h-8 md:w-8"
|
||||
title={addButtonLabel}
|
||||
aria-label={addButtonLabel}
|
||||
onClick={addNewItem}
|
||||
>
|
||||
<Icon type="add" />
|
||||
<Icon type="add" size="custom" className="h-6 w-6 md:h-5 md:w-5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import { DisclosureButton } from '@reach/disclosure'
|
||||
import styled from 'styled-components'
|
||||
|
||||
const StyledDisplayOptionsButton = styled(DisclosureButton).attrs(() => ({
|
||||
className:
|
||||
'flex justify-center items-center min-w-8 h-8 bg-text-padding hover:bg-contrast focus:bg-contrast text-neutral border border-solid border-border rounded-full cursor-pointer',
|
||||
}))<{
|
||||
$pressed: boolean
|
||||
}>`
|
||||
background-color: ${(props) => (props.$pressed ? 'var(--sn-stylekit-contrast-background-color)' : 'transparent')};
|
||||
`
|
||||
|
||||
export default StyledDisplayOptionsButton
|
||||
@@ -1,10 +1,10 @@
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import { useCallback, useRef, useState } from 'react'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import FileMenuOptions from './FileMenuOptions'
|
||||
import { FilesController } from '@/Controllers/FilesController'
|
||||
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
|
||||
import Popover from '../Popover/Popover'
|
||||
import RoundIconButton from '../Button/RoundIconButton'
|
||||
|
||||
type Props = {
|
||||
filesController: FilesController
|
||||
@@ -19,15 +19,7 @@ const FilesOptionsPanel = ({ filesController, selectionController }: Props) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className="bg-text-padding flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
title="File options menu"
|
||||
aria-label="File options menu"
|
||||
onClick={toggleMenu}
|
||||
ref={buttonRef}
|
||||
>
|
||||
<Icon type="more" />
|
||||
</button>
|
||||
<RoundIconButton label="File options menu" onClick={toggleMenu} ref={buttonRef} icon="more" />
|
||||
<Popover togglePopover={toggleMenu} anchorElement={buttonRef.current} open={isOpen} className="py-2">
|
||||
<FileMenuOptions
|
||||
filesController={filesController}
|
||||
|
||||
@@ -7,10 +7,10 @@ import { FileViewProps } from './FileViewProps'
|
||||
import MobileItemsListButton from '../NoteGroupView/MobileItemsListButton'
|
||||
import LinkedItemsButton from '../LinkedItems/LinkedItemsButton'
|
||||
import LinkedItemBubblesContainer from '../LinkedItems/LinkedItemBubblesContainer'
|
||||
import Icon from '../Icon/Icon'
|
||||
import Popover from '../Popover/Popover'
|
||||
import FilePreviewInfoPanel from '../FilePreview/FilePreviewInfoPanel'
|
||||
import { useFileDragNDrop } from '../FileDragNDropProvider/FileDragNDropProvider'
|
||||
import RoundIconButton from '../Button/RoundIconButton'
|
||||
|
||||
const SyncTimeoutNoDebounceMs = 100
|
||||
const SyncTimeoutDebounceMs = 350
|
||||
@@ -95,15 +95,12 @@ const FileViewWithoutProtection = ({ application, viewControllerManager, file }:
|
||||
filesController={viewControllerManager.filesController}
|
||||
linkingController={viewControllerManager.linkingController}
|
||||
/>
|
||||
<button
|
||||
className="bg-text-padding flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
title="File information panel"
|
||||
aria-label="File information panel"
|
||||
<RoundIconButton
|
||||
label="File information panel"
|
||||
onClick={toggleFileInfoPanel}
|
||||
ref={fileInfoButtonRef}
|
||||
>
|
||||
<Icon type="info" />
|
||||
</button>
|
||||
icon="info"
|
||||
/>
|
||||
<Popover
|
||||
open={isFileInfoPanelOpen}
|
||||
togglePopover={toggleFileInfoPanel}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { FilesController } from '@/Controllers/FilesController'
|
||||
import { LinkingController } from '@/Controllers/LinkingController'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useRef, useCallback } from 'react'
|
||||
import Icon from '../Icon/Icon'
|
||||
import RoundIconButton from '../Button/RoundIconButton'
|
||||
import Popover from '../Popover/Popover'
|
||||
import StyledTooltip from '../StyledTooltip/StyledTooltip'
|
||||
import LinkedItemsPanel from './LinkedItemsPanel'
|
||||
@@ -28,14 +28,7 @@ const LinkedItemsButton = ({ linkingController, filesController, onClickPreproce
|
||||
return (
|
||||
<>
|
||||
<StyledTooltip label="Linked items panel">
|
||||
<button
|
||||
className="bg-text-padding flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
aria-label="Linked items panel"
|
||||
onClick={toggleMenu}
|
||||
ref={buttonRef}
|
||||
>
|
||||
<Icon type="link" />
|
||||
</button>
|
||||
<RoundIconButton label="Linked items panel" onClick={toggleMenu} ref={buttonRef} icon="link" />
|
||||
</StyledTooltip>
|
||||
<Popover togglePopover={toggleMenu} anchorElement={buttonRef.current} open={isLinkingPanelOpen} className="pb-2">
|
||||
<LinkedItemsPanel
|
||||
|
||||
@@ -9,10 +9,10 @@ import PanelResizer, { PanelSide, ResizeFinishCallback, PanelResizeType } from '
|
||||
import ResponsivePaneContent from '@/Components/ResponsivePane/ResponsivePaneContent'
|
||||
import { AppPaneId } from '@/Components/ResponsivePane/AppPaneMetadata'
|
||||
import { classNames } from '@/Utils/ConcatenateClassNames'
|
||||
import Icon from '../Icon/Icon'
|
||||
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
|
||||
import { isIOS } from '@/Utils'
|
||||
import UpgradeNow from '../Footer/UpgradeNow'
|
||||
import RoundIconButton from '../Button/RoundIconButton'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -89,58 +89,48 @@ const Navigation: FunctionComponent<Props> = ({ application }) => {
|
||||
<TagsSection viewControllerManager={viewControllerManager} />
|
||||
</div>
|
||||
<div className="flex items-center border-t border-border px-3.5 pt-2.5 md:hidden">
|
||||
<button
|
||||
className="mr-auto flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border bg-default text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
<RoundIconButton
|
||||
className="mr-auto bg-default"
|
||||
onClick={() => {
|
||||
toggleAppPane(AppPaneId.Items)
|
||||
}}
|
||||
title="Go to items list"
|
||||
aria-label="Go to items list"
|
||||
>
|
||||
<Icon type="chevron-left" />
|
||||
</button>
|
||||
label="Go to items list"
|
||||
icon="chevron-left"
|
||||
/>
|
||||
<UpgradeNow application={application} featuresController={viewControllerManager.featuresController} />
|
||||
<button
|
||||
className="ml-2.5 flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border bg-default text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
<RoundIconButton
|
||||
className="ml-2.5 bg-default"
|
||||
onClick={() => {
|
||||
viewControllerManager.accountMenuController.toggleShow()
|
||||
}}
|
||||
title="Go to account menu"
|
||||
aria-label="Go to account menu"
|
||||
>
|
||||
<Icon type="account-circle" />
|
||||
</button>
|
||||
label="Go to account menu"
|
||||
icon="account-circle"
|
||||
/>
|
||||
{hasPasscode && (
|
||||
<button
|
||||
<RoundIconButton
|
||||
id="lock-item"
|
||||
onClick={() => application.lock()}
|
||||
title="Locks application and wipes unencrypted data from memory."
|
||||
aria-label="Locks application and wipes unencrypted data from memory."
|
||||
className="ml-2.5 flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border bg-default text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
>
|
||||
<Icon type="lock-filled" size="custom" className="h-4.5 w-4.5" />
|
||||
</button>
|
||||
label="Locks application and wipes unencrypted data from memory."
|
||||
className="ml-2.5 bg-default"
|
||||
icon="lock-filled"
|
||||
/>
|
||||
)}
|
||||
<button
|
||||
className="ml-2.5 flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border bg-default text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
<RoundIconButton
|
||||
className="ml-2.5 bg-default"
|
||||
onClick={() => {
|
||||
viewControllerManager.preferencesController.openPreferences()
|
||||
}}
|
||||
title="Go to preferences"
|
||||
aria-label="Go to preferences"
|
||||
>
|
||||
<Icon type="tune" />
|
||||
</button>
|
||||
<button
|
||||
className="ml-2.5 flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border bg-default text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
label="Go to preferences"
|
||||
icon="tune"
|
||||
/>
|
||||
<RoundIconButton
|
||||
className="ml-2.5 bg-default"
|
||||
onClick={() => {
|
||||
viewControllerManager.quickSettingsMenuController.toggle()
|
||||
}}
|
||||
title="Go to quick settings menu"
|
||||
aria-label="Go to quick settings menu"
|
||||
>
|
||||
<Icon type="themes" />
|
||||
</button>
|
||||
label="Go to quick settings menu"
|
||||
icon="themes"
|
||||
/>
|
||||
</div>
|
||||
</ResponsivePaneContent>
|
||||
{panelElement && (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Icon from '../Icon/Icon'
|
||||
import RoundIconButton from '../Button/RoundIconButton'
|
||||
import { AppPaneId } from '../ResponsivePane/AppPaneMetadata'
|
||||
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
|
||||
|
||||
@@ -6,8 +6,8 @@ export const NavigationMenuButton = () => {
|
||||
const { selectedPane, toggleAppPane } = useResponsiveAppPane()
|
||||
|
||||
return (
|
||||
<button
|
||||
className="bg-text-padding mr-3 inline-flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border align-middle text-neutral hover:bg-contrast focus:bg-contrast md:hidden pointer-coarse:md-only:inline-flex pointer-coarse:lg-only:inline-flex"
|
||||
<RoundIconButton
|
||||
className="mr-3 md:hidden"
|
||||
onClick={() => {
|
||||
if (selectedPane === AppPaneId.Items || selectedPane === AppPaneId.Editor) {
|
||||
toggleAppPane(AppPaneId.Navigation)
|
||||
@@ -15,10 +15,8 @@ export const NavigationMenuButton = () => {
|
||||
toggleAppPane(AppPaneId.Items)
|
||||
}
|
||||
}}
|
||||
title="Navigation menu"
|
||||
aria-label="Navigation menu"
|
||||
>
|
||||
<Icon type="menu-variant" />
|
||||
</button>
|
||||
label="Open navigation menu"
|
||||
icon="menu-variant"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { AppPaneId } from '../ResponsivePane/AppPaneMetadata'
|
||||
import Icon from '../Icon/Icon'
|
||||
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
|
||||
import { useMediaQuery, MediaQueryBreakpoints } from '@/Hooks/useMediaQuery'
|
||||
import { IconType } from '@standardnotes/snjs'
|
||||
import RoundIconButton from '../Button/RoundIconButton'
|
||||
|
||||
const MobileItemsListButton = () => {
|
||||
const { toggleAppPane, isNotesListVisibleOnTablets, toggleNotesListOnTablets } = useResponsiveAppPane()
|
||||
@@ -18,8 +18,8 @@ const MobileItemsListButton = () => {
|
||||
: 'Go to items list'
|
||||
|
||||
return (
|
||||
<button
|
||||
className="bg-text-padding mr-3 flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border text-neutral hover:bg-contrast focus:bg-contrast md:hidden pointer-coarse:md-only:flex pointer-coarse:lg-only:flex"
|
||||
<RoundIconButton
|
||||
className="mr-3"
|
||||
onClick={() => {
|
||||
if (isTabletScreenSize) {
|
||||
toggleNotesListOnTablets()
|
||||
@@ -27,11 +27,9 @@ const MobileItemsListButton = () => {
|
||||
toggleAppPane(AppPaneId.Items)
|
||||
}
|
||||
}}
|
||||
title={label}
|
||||
aria-label={label}
|
||||
>
|
||||
<Icon type={iconType} />
|
||||
</button>
|
||||
label={label}
|
||||
icon={iconType}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import { useCallback, useRef, useState } from 'react'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import NotesOptions from './NotesOptions'
|
||||
@@ -8,6 +7,7 @@ import { NavigationController } from '@/Controllers/Navigation/NavigationControl
|
||||
import { HistoryModalController } from '@/Controllers/NoteHistory/HistoryModalController'
|
||||
import Popover from '../Popover/Popover'
|
||||
import { LinkingController } from '@/Controllers/LinkingController'
|
||||
import RoundIconButton from '../Button/RoundIconButton'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -39,15 +39,7 @@ const NotesOptionsPanel = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className="bg-text-padding flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
title="Note options menu"
|
||||
aria-label="Note options menu"
|
||||
onClick={toggleMenu}
|
||||
ref={buttonRef}
|
||||
>
|
||||
<Icon type="more" />
|
||||
</button>
|
||||
<RoundIconButton label="Note options menu" onClick={toggleMenu} ref={buttonRef} icon="more" />
|
||||
<Popover togglePopover={toggleMenu} anchorElement={buttonRef.current} open={isOpen} className="select-none py-2">
|
||||
<NotesOptions
|
||||
application={application}
|
||||
|
||||
@@ -27,7 +27,7 @@ const PinNoteButton: FunctionComponent<Props> = ({ className = '', notesControll
|
||||
|
||||
return (
|
||||
<button
|
||||
className={`sn-icon-button flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border text-neutral hover:bg-contrast focus:bg-contrast ${
|
||||
className={`sn-icon-button flex h-9 w-9 cursor-pointer items-center justify-center rounded-full border border-solid border-border text-neutral hover:bg-contrast focus:bg-contrast md:h-8 md:w-8 ${
|
||||
pinned ? 'toggled' : ''
|
||||
} ${className}`}
|
||||
onClick={togglePinned}
|
||||
|
||||
@@ -71,8 +71,8 @@ const PreferencesView: FunctionComponent<PreferencesProps> = ({
|
||||
onClick={() => {
|
||||
closePreferences()
|
||||
}}
|
||||
type="normal"
|
||||
icon="close"
|
||||
label="Close preferences"
|
||||
/>
|
||||
</div>
|
||||
<PreferencesCanvas
|
||||
|
||||
@@ -8,6 +8,8 @@ module.exports = {
|
||||
extend: {
|
||||
spacing: {
|
||||
4.5: '1.125rem',
|
||||
8.5: '2.125rem',
|
||||
13: '3.25rem',
|
||||
18: '4.5rem',
|
||||
26: '6.5rem',
|
||||
30: '7.5rem',
|
||||
@@ -27,6 +29,8 @@ module.exports = {
|
||||
4: '1rem',
|
||||
5: '1.25rem',
|
||||
8: '2rem',
|
||||
8.5: '2.125rem',
|
||||
9: '2.25rem',
|
||||
15: '3.75rem',
|
||||
20: '5rem',
|
||||
24: '6rem',
|
||||
|
||||
Reference in New Issue
Block a user