feat: "create new note" floating button on mobile (#1857)

This commit is contained in:
Aman Harwara
2022-10-21 18:36:55 +05:30
committed by GitHub
parent 173bacdfa3
commit 21f725bb2a
14 changed files with 96 additions and 143 deletions

View File

@@ -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

View File

@@ -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}

View File

@@ -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>

View File

@@ -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

View File

@@ -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}

View File

@@ -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}

View File

@@ -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

View File

@@ -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 && (

View File

@@ -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"
/>
)
}

View File

@@ -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}
/>
)
}

View File

@@ -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}

View File

@@ -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}

View File

@@ -71,8 +71,8 @@ const PreferencesView: FunctionComponent<PreferencesProps> = ({
onClick={() => {
closePreferences()
}}
type="normal"
icon="close"
label="Close preferences"
/>
</div>
<PreferencesCanvas

View File

@@ -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',