refactor: modals
This commit is contained in:
@@ -7,7 +7,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|||||||
import Dropdown from '../Dropdown/Dropdown'
|
import Dropdown from '../Dropdown/Dropdown'
|
||||||
import Icon from '../Icon/Icon'
|
import Icon from '../Icon/Icon'
|
||||||
import DecoratedInput from '../Input/DecoratedInput'
|
import DecoratedInput from '../Input/DecoratedInput'
|
||||||
import Modal from '../Shared/Modal'
|
import Modal from '../Modal/Modal'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
filesController: FilesController
|
filesController: FilesController
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { observer } from 'mobx-react-lite'
|
|||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import Icon from '../Icon/Icon'
|
import Icon from '../Icon/Icon'
|
||||||
import DecoratedInput from '../Input/DecoratedInput'
|
import DecoratedInput from '../Input/DecoratedInput'
|
||||||
import Modal from '../Shared/Modal'
|
import Modal from '../Modal/Modal'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
filesController: FilesController
|
filesController: FilesController
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { WebApplication } from '@/Application/Application'
|
import { WebApplication } from '@/Application/Application'
|
||||||
import { DialogContent, DialogOverlay } from '@reach/dialog'
|
|
||||||
import {
|
import {
|
||||||
ButtonType,
|
ButtonType,
|
||||||
Challenge,
|
Challenge,
|
||||||
@@ -21,8 +20,10 @@ import { ChallengeModalValues } from './ChallengeModalValues'
|
|||||||
import { InputValue } from './InputValue'
|
import { InputValue } from './InputValue'
|
||||||
import { isIOS, isMobileScreen } from '@/Utils'
|
import { isIOS, isMobileScreen } from '@/Utils'
|
||||||
import { classNames } from '@standardnotes/utils'
|
import { classNames } from '@standardnotes/utils'
|
||||||
import MobileModalAction from '../Shared/MobileModalAction'
|
import MobileModalAction from '../Modal/MobileModalAction'
|
||||||
import { useModalAnimation } from '../Shared/useModalAnimation'
|
import MobileModalHeader from '../Modal/MobileModalHeader'
|
||||||
|
import ModalOverlay from '../Modal/ModalOverlay'
|
||||||
|
import Modal from '../Modal/Modal'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
application: WebApplication
|
application: WebApplication
|
||||||
@@ -211,38 +212,35 @@ const ChallengeModal: FunctionComponent<Props> = ({
|
|||||||
}
|
}
|
||||||
}, [application, cancelChallenge, challenge.cancelable])
|
}, [application, cancelChallenge, challenge.cancelable])
|
||||||
|
|
||||||
const [isMounted, setElement] = useModalAnimation(!!challenge.prompts.length)
|
|
||||||
|
|
||||||
if (!isMounted) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const isFullScreenBlocker = challenge.reason === ChallengeReason.ApplicationUnlock
|
const isFullScreenBlocker = challenge.reason === ChallengeReason.ApplicationUnlock
|
||||||
const isMobileOverlay = isMobileScreen() && !isFullScreenBlocker
|
const isMobileOverlay = isMobileScreen() && !isFullScreenBlocker
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DialogOverlay
|
<ModalOverlay
|
||||||
|
isOpen={true}
|
||||||
className={`sn-component p-0 ${isFullScreenBlocker ? 'bg-passive-5' : ''}`}
|
className={`sn-component p-0 ${isFullScreenBlocker ? 'bg-passive-5' : ''}`}
|
||||||
onDismiss={cancelChallenge}
|
onDismiss={cancelChallenge}
|
||||||
dangerouslyBypassFocusLock={bypassModalFocusLock}
|
dangerouslyBypassFocusLock={bypassModalFocusLock}
|
||||||
key={challenge.id}
|
key={challenge.id}
|
||||||
ref={setElement}
|
|
||||||
>
|
>
|
||||||
<DialogContent
|
<Modal
|
||||||
aria-label="Challenge modal"
|
title="Authenticate"
|
||||||
className={classNames(
|
close={cancelChallenge}
|
||||||
'challenge-modal relative m-0 flex h-full w-full flex-col items-center rounded border-solid border-border bg-default p-0 md:h-auto md:w-auto md:border',
|
className={{
|
||||||
!isMobileScreen() && 'shadow-overlay-light',
|
content: classNames(
|
||||||
isMobileOverlay && 'shadow-overlay-light border border-solid border-border',
|
'challenge-modal relative m-0 flex h-full w-full flex-col items-center rounded border-solid border-border bg-default p-0 md:h-auto md:w-auto md:border',
|
||||||
)}
|
!isMobileScreen() && 'shadow-overlay-light',
|
||||||
|
isMobileOverlay && 'shadow-overlay-light border border-solid border-border',
|
||||||
|
),
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div
|
{/* <div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'w-full border-b border-solid border-border py-1.5 px-1.5 md:hidden',
|
'w-full border-b border-solid border-border py-1.5 px-1.5 md:hidden',
|
||||||
isIOS() && 'pt-safe-top',
|
isIOS() && 'pt-safe-top',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="grid w-full grid-cols-[0.35fr_1fr_0.35fr] gap-2">
|
<MobileModalHeader>
|
||||||
{challenge.cancelable ? (
|
{challenge.cancelable ? (
|
||||||
<MobileModalAction slot="left" type="cancel" action={cancelChallenge}>
|
<MobileModalAction slot="left" type="cancel" action={cancelChallenge}>
|
||||||
Cancel
|
Cancel
|
||||||
@@ -252,8 +250,8 @@ const ChallengeModal: FunctionComponent<Props> = ({
|
|||||||
)}
|
)}
|
||||||
<div className="flex items-center justify-center text-base font-semibold text-text">Authenticate</div>
|
<div className="flex items-center justify-center text-base font-semibold text-text">Authenticate</div>
|
||||||
<div />
|
<div />
|
||||||
</div>
|
</MobileModalHeader>
|
||||||
</div>
|
</div> */}
|
||||||
{challenge.cancelable && (
|
{challenge.cancelable && (
|
||||||
<button
|
<button
|
||||||
onClick={cancelChallenge}
|
onClick={cancelChallenge}
|
||||||
@@ -326,8 +324,8 @@ const ChallengeModal: FunctionComponent<Props> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
</Modal>
|
||||||
</DialogOverlay>
|
</ModalOverlay>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { PremiumFeatureIconClass, PremiumFeatureIconName } from '../Icon/Premium
|
|||||||
import { SuperNoteImporter } from '../NoteView/SuperEditor/SuperNoteImporter'
|
import { SuperNoteImporter } from '../NoteView/SuperEditor/SuperNoteImporter'
|
||||||
import MenuRadioButtonItem from '../Menu/MenuRadioButtonItem'
|
import MenuRadioButtonItem from '../Menu/MenuRadioButtonItem'
|
||||||
import { Pill } from '../Preferences/PreferencesComponents/Content'
|
import { Pill } from '../Preferences/PreferencesComponents/Content'
|
||||||
import ModalOverlay from '../Shared/ModalOverlay'
|
import ModalOverlay from '../Modal/ModalOverlay'
|
||||||
|
|
||||||
type ChangeEditorMenuProps = {
|
type ChangeEditorMenuProps = {
|
||||||
application: WebApplication
|
application: WebApplication
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { EditorMenuGroup } from '../NotesOptions/EditorMenuGroup'
|
|||||||
import { EditorMenuItem } from '../NotesOptions/EditorMenuItem'
|
import { EditorMenuItem } from '../NotesOptions/EditorMenuItem'
|
||||||
import { SuperNoteImporter } from '../NoteView/SuperEditor/SuperNoteImporter'
|
import { SuperNoteImporter } from '../NoteView/SuperEditor/SuperNoteImporter'
|
||||||
import { Pill } from '../Preferences/PreferencesComponents/Content'
|
import { Pill } from '../Preferences/PreferencesComponents/Content'
|
||||||
import ModalOverlay from '../Shared/ModalOverlay'
|
import ModalOverlay from '../Modal/ModalOverlay'
|
||||||
|
|
||||||
const getGroupId = (group: EditorMenuGroup) => group.title.toLowerCase().replace(/\s/, '-')
|
const getGroupId = (group: EditorMenuGroup) => group.title.toLowerCase().replace(/\s/, '-')
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ 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 Popover from '@/Components/Popover/Popover'
|
import Popover from '@/Components/Popover/Popover'
|
||||||
import ModalOverlay from '@/Components/Shared/ModalOverlay'
|
import ModalOverlay from '@/Components/Modal/ModalOverlay'
|
||||||
import { FilesController } from '@/Controllers/FilesController'
|
import { FilesController } from '@/Controllers/FilesController'
|
||||||
import { PhotoRecorder } from '@/Controllers/Moments/PhotoRecorder'
|
import { PhotoRecorder } from '@/Controllers/Moments/PhotoRecorder'
|
||||||
import { classNames } from '@standardnotes/snjs'
|
import { classNames } from '@standardnotes/snjs'
|
||||||
|
|||||||
@@ -1,15 +1,6 @@
|
|||||||
import { WebApplication } from '@/Application/Application'
|
import { WebApplication } from '@/Application/Application'
|
||||||
import { DialogContent, DialogOverlay } from '@reach/dialog'
|
import { DialogContent } from '@reach/dialog'
|
||||||
import {
|
import { FunctionComponent, KeyboardEventHandler, useCallback, useMemo, useRef, useState } from 'react'
|
||||||
ForwardedRef,
|
|
||||||
forwardRef,
|
|
||||||
FunctionComponent,
|
|
||||||
KeyboardEventHandler,
|
|
||||||
useCallback,
|
|
||||||
useMemo,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from 'react'
|
|
||||||
import { getFileIconComponent } from './getFileIconComponent'
|
import { getFileIconComponent } from './getFileIconComponent'
|
||||||
import Icon from '@/Components/Icon/Icon'
|
import Icon from '@/Components/Icon/Icon'
|
||||||
import FilePreviewInfoPanel from './FilePreviewInfoPanel'
|
import FilePreviewInfoPanel from './FilePreviewInfoPanel'
|
||||||
@@ -26,248 +17,243 @@ import LinkedItemBubblesContainer from '../LinkedItems/LinkedItemBubblesContaine
|
|||||||
import StyledTooltip from '../StyledTooltip/StyledTooltip'
|
import StyledTooltip from '../StyledTooltip/StyledTooltip'
|
||||||
import DecoratedInput from '../Input/DecoratedInput'
|
import DecoratedInput from '../Input/DecoratedInput'
|
||||||
import { mergeRefs } from '@/Hooks/mergeRefs'
|
import { mergeRefs } from '@/Hooks/mergeRefs'
|
||||||
import { useModalAnimation } from '../Shared/useModalAnimation'
|
import { classNames } from '@standardnotes/snjs'
|
||||||
|
import { isIOS } from '@/Utils'
|
||||||
|
import ModalOverlay from '../Modal/ModalOverlay'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
application: WebApplication
|
application: WebApplication
|
||||||
viewControllerManager: ViewControllerManager
|
viewControllerManager: ViewControllerManager
|
||||||
}
|
}
|
||||||
|
|
||||||
const FilePreviewModal = observer(
|
const FilePreviewModal = observer(({ application, viewControllerManager }: Props) => {
|
||||||
forwardRef(({ application, viewControllerManager }: Props, ref: ForwardedRef<HTMLDivElement>) => {
|
const { currentFile, setCurrentFile, otherFiles, dismiss } = viewControllerManager.filePreviewModalController
|
||||||
const { currentFile, setCurrentFile, otherFiles, dismiss } = viewControllerManager.filePreviewModalController
|
|
||||||
|
|
||||||
const [isRenaming, setIsRenaming] = useState(false)
|
const [isRenaming, setIsRenaming] = useState(false)
|
||||||
const renameInputRef = useRef<HTMLInputElement>(null)
|
const renameInputRef = useRef<HTMLInputElement>(null)
|
||||||
const [showLinkedBubblesContainer, setShowLinkedBubblesContainer] = useState(false)
|
const [showLinkedBubblesContainer, setShowLinkedBubblesContainer] = useState(false)
|
||||||
const [showOptionsMenu, setShowOptionsMenu] = useState(false)
|
const [showOptionsMenu, setShowOptionsMenu] = useState(false)
|
||||||
const [showFileInfoPanel, setShowFileInfoPanel] = useState(false)
|
const [showFileInfoPanel, setShowFileInfoPanel] = useState(false)
|
||||||
const menuButtonRef = useRef<HTMLButtonElement>(null)
|
const menuButtonRef = useRef<HTMLButtonElement>(null)
|
||||||
const closeButtonRef = useRef<HTMLButtonElement>(null)
|
const closeButtonRef = useRef<HTMLButtonElement>(null)
|
||||||
|
|
||||||
const keyDownHandler: KeyboardEventHandler = useCallback(
|
const keyDownHandler: KeyboardEventHandler = useCallback(
|
||||||
(event) => {
|
(event) => {
|
||||||
if (!currentFile) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const KeysToHandle: string[] = [KeyboardKey.Left, KeyboardKey.Right, KeyboardKey.Escape]
|
|
||||||
|
|
||||||
if (!KeysToHandle.includes(event.key) || event.target === renameInputRef.current) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
event.preventDefault()
|
|
||||||
|
|
||||||
const currentFileIndex = otherFiles.findIndex((fileFromArray) => fileFromArray.uuid === currentFile.uuid)
|
|
||||||
|
|
||||||
switch (event.key) {
|
|
||||||
case KeyboardKey.Left: {
|
|
||||||
const previousFileIndex = currentFileIndex - 1 >= 0 ? currentFileIndex - 1 : otherFiles.length - 1
|
|
||||||
const previousFile = otherFiles[previousFileIndex]
|
|
||||||
if (previousFile) {
|
|
||||||
setCurrentFile(previousFile)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case KeyboardKey.Right: {
|
|
||||||
const nextFileIndex = currentFileIndex + 1 < otherFiles.length ? currentFileIndex + 1 : 0
|
|
||||||
const nextFile = otherFiles[nextFileIndex]
|
|
||||||
if (nextFile) {
|
|
||||||
setCurrentFile(nextFile)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case KeyboardKey.Escape:
|
|
||||||
dismiss()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[currentFile, dismiss, otherFiles, setCurrentFile],
|
|
||||||
)
|
|
||||||
|
|
||||||
const IconComponent = useMemo(() => {
|
|
||||||
return currentFile
|
|
||||||
? getFileIconComponent(getIconForFileType(currentFile.mimeType), 'w-6 h-6 flex-shrink-0')
|
|
||||||
: null
|
|
||||||
}, [currentFile])
|
|
||||||
|
|
||||||
const focusInputOnMount = useCallback((input: HTMLInputElement | null) => {
|
|
||||||
if (input) {
|
|
||||||
input.focus()
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const handleRename = useCallback(async () => {
|
|
||||||
if (!currentFile) {
|
if (!currentFile) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
if (renameInputRef.current) {
|
|
||||||
const newName = renameInputRef.current.value
|
|
||||||
if (newName && newName !== currentFile.name) {
|
|
||||||
await application.items.renameFile(currentFile, newName)
|
|
||||||
setIsRenaming(false)
|
|
||||||
setCurrentFile(application.items.findSureItem(currentFile.uuid))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
setIsRenaming(false)
|
|
||||||
}
|
|
||||||
}, [application.items, currentFile, setCurrentFile])
|
|
||||||
|
|
||||||
|
const KeysToHandle: string[] = [KeyboardKey.Left, KeyboardKey.Right, KeyboardKey.Escape]
|
||||||
|
|
||||||
|
if (!KeysToHandle.includes(event.key) || event.target === renameInputRef.current) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
const currentFileIndex = otherFiles.findIndex((fileFromArray) => fileFromArray.uuid === currentFile.uuid)
|
||||||
|
|
||||||
|
switch (event.key) {
|
||||||
|
case KeyboardKey.Left: {
|
||||||
|
const previousFileIndex = currentFileIndex - 1 >= 0 ? currentFileIndex - 1 : otherFiles.length - 1
|
||||||
|
const previousFile = otherFiles[previousFileIndex]
|
||||||
|
if (previousFile) {
|
||||||
|
setCurrentFile(previousFile)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case KeyboardKey.Right: {
|
||||||
|
const nextFileIndex = currentFileIndex + 1 < otherFiles.length ? currentFileIndex + 1 : 0
|
||||||
|
const nextFile = otherFiles[nextFileIndex]
|
||||||
|
if (nextFile) {
|
||||||
|
setCurrentFile(nextFile)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case KeyboardKey.Escape:
|
||||||
|
dismiss()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[currentFile, dismiss, otherFiles, setCurrentFile],
|
||||||
|
)
|
||||||
|
|
||||||
|
const IconComponent = useMemo(() => {
|
||||||
|
return currentFile ? getFileIconComponent(getIconForFileType(currentFile.mimeType), 'w-6 h-6 flex-shrink-0') : null
|
||||||
|
}, [currentFile])
|
||||||
|
|
||||||
|
const focusInputOnMount = useCallback((input: HTMLInputElement | null) => {
|
||||||
|
if (input) {
|
||||||
|
input.focus()
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const handleRename = useCallback(async () => {
|
||||||
if (!currentFile) {
|
if (!currentFile) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
if (renameInputRef.current) {
|
||||||
|
const newName = renameInputRef.current.value
|
||||||
|
if (newName && newName !== currentFile.name) {
|
||||||
|
await application.items.renameFile(currentFile, newName)
|
||||||
|
setIsRenaming(false)
|
||||||
|
setCurrentFile(application.items.findSureItem(currentFile.uuid))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setIsRenaming(false)
|
||||||
|
}
|
||||||
|
}, [application.items, currentFile, setCurrentFile])
|
||||||
|
|
||||||
return (
|
if (!currentFile) {
|
||||||
<DialogOverlay
|
return null
|
||||||
className="sn-component p-0"
|
}
|
||||||
aria-label="File preview modal"
|
|
||||||
onDismiss={dismiss}
|
return (
|
||||||
initialFocusRef={closeButtonRef}
|
<DialogContent
|
||||||
dangerouslyBypassScrollLock
|
className={classNames(
|
||||||
ref={ref}
|
'm-0 flex h-full w-full flex-col rounded bg-[color:var(--modal-background-color)] p-0 shadow-main md:max-h-[90%] md:max-w-[90%]',
|
||||||
|
isIOS() && 'pt-safe-top',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="flex h-full w-full flex-col focus:shadow-none focus:outline-none"
|
||||||
|
tabIndex={FOCUSABLE_BUT_NOT_TABBABLE}
|
||||||
|
onKeyDown={keyDownHandler}
|
||||||
>
|
>
|
||||||
<DialogContent
|
<div className="min-h-6 flex flex-shrink-0 flex-wrap items-center justify-between gap-2 border-0 border-b border-solid border-border px-4 py-3 focus:shadow-none">
|
||||||
aria-label="File preview modal"
|
<div className="flex items-center">
|
||||||
className="m-0 flex h-full min-h-[90%] w-full min-w-[90%] flex-col rounded bg-[color:var(--modal-background-color)] p-0 shadow-main "
|
<div className="h-6 w-6">{IconComponent}</div>
|
||||||
>
|
{isRenaming ? (
|
||||||
<div
|
<DecoratedInput
|
||||||
className="flex h-full w-full flex-col focus:shadow-none focus:outline-none"
|
defaultValue={currentFile.name}
|
||||||
tabIndex={FOCUSABLE_BUT_NOT_TABBABLE}
|
className={{ container: 'ml-3', input: 'p-1', right: 'items-stretch !p-0' }}
|
||||||
onKeyDown={keyDownHandler}
|
onKeyDown={(event) => {
|
||||||
>
|
if (event.key === KeyboardKey.Enter) {
|
||||||
<div className="min-h-6 flex flex-shrink-0 flex-wrap items-center justify-between gap-2 border-0 border-b border-solid border-border px-4 py-3 focus:shadow-none">
|
void handleRename()
|
||||||
<div className="flex items-center">
|
}
|
||||||
<div className="h-6 w-6">{IconComponent}</div>
|
}}
|
||||||
{isRenaming ? (
|
right={[
|
||||||
<DecoratedInput
|
|
||||||
defaultValue={currentFile.name}
|
|
||||||
className={{ container: 'ml-3', input: 'p-1', right: 'items-stretch !p-0' }}
|
|
||||||
onKeyDown={(event) => {
|
|
||||||
if (event.key === KeyboardKey.Enter) {
|
|
||||||
void handleRename()
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
right={[
|
|
||||||
<button
|
|
||||||
className="flex h-full items-center justify-center border-l border-border px-2 py-1.5 text-neutral hover:bg-passive-4"
|
|
||||||
title="Submit"
|
|
||||||
onClick={handleRename}
|
|
||||||
>
|
|
||||||
<Icon type="check" size="small" />
|
|
||||||
</button>,
|
|
||||||
]}
|
|
||||||
ref={mergeRefs([renameInputRef, focusInputOnMount])}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<span className="ml-3 font-medium">{currentFile.name}</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center">
|
|
||||||
<StyledTooltip label="Rename file" className="!z-modal">
|
|
||||||
<button
|
<button
|
||||||
className="mr-4 flex cursor-pointer rounded border border-solid border-border bg-transparent p-1.5 hover:bg-contrast"
|
className="flex h-full items-center justify-center border-l border-border px-2 py-1.5 text-neutral hover:bg-passive-4"
|
||||||
onClick={() => setIsRenaming((isRenaming) => !isRenaming)}
|
title="Submit"
|
||||||
aria-label="Rename file"
|
onClick={handleRename}
|
||||||
>
|
>
|
||||||
<Icon type="pencil-filled" className="text-neutral" />
|
<Icon type="check" size="small" />
|
||||||
</button>
|
</button>,
|
||||||
</StyledTooltip>
|
]}
|
||||||
<StyledTooltip label="Show linked items" className="!z-modal">
|
ref={mergeRefs([renameInputRef, focusInputOnMount])}
|
||||||
<button
|
/>
|
||||||
className="mr-4 flex cursor-pointer rounded border border-solid border-border bg-transparent p-1.5 hover:bg-contrast"
|
) : (
|
||||||
onClick={() => setShowLinkedBubblesContainer((show) => !show)}
|
<span className="ml-3 font-medium">{currentFile.name}</span>
|
||||||
aria-label="Show linked items"
|
)}
|
||||||
>
|
</div>
|
||||||
<Icon type="link" className="text-neutral" />
|
<div className="flex items-center">
|
||||||
</button>
|
<StyledTooltip label="Rename file" className="!z-modal">
|
||||||
</StyledTooltip>
|
<button
|
||||||
<StyledTooltip label="Show file options" className="!z-modal">
|
className="mr-4 flex cursor-pointer rounded border border-solid border-border bg-transparent p-1.5 hover:bg-contrast"
|
||||||
<button
|
onClick={() => setIsRenaming((isRenaming) => !isRenaming)}
|
||||||
className="mr-4 flex cursor-pointer rounded border border-solid border-border bg-transparent p-1.5 hover:bg-contrast"
|
aria-label="Rename file"
|
||||||
onClick={() => setShowOptionsMenu((show) => !show)}
|
>
|
||||||
ref={menuButtonRef}
|
<Icon type="pencil-filled" className="text-neutral" />
|
||||||
aria-label="Show file options"
|
</button>
|
||||||
>
|
</StyledTooltip>
|
||||||
<Icon type="more" className="text-neutral" />
|
<StyledTooltip label="Show linked items" className="!z-modal">
|
||||||
</button>
|
<button
|
||||||
</StyledTooltip>
|
className="mr-4 flex cursor-pointer rounded border border-solid border-border bg-transparent p-1.5 hover:bg-contrast"
|
||||||
<Popover
|
onClick={() => setShowLinkedBubblesContainer((show) => !show)}
|
||||||
title="File options"
|
aria-label="Show linked items"
|
||||||
open={showOptionsMenu}
|
>
|
||||||
anchorElement={menuButtonRef.current}
|
<Icon type="link" className="text-neutral" />
|
||||||
togglePopover={() => {
|
</button>
|
||||||
|
</StyledTooltip>
|
||||||
|
<StyledTooltip label="Show file options" className="!z-modal">
|
||||||
|
<button
|
||||||
|
className="mr-4 flex cursor-pointer rounded border border-solid border-border bg-transparent p-1.5 hover:bg-contrast"
|
||||||
|
onClick={() => setShowOptionsMenu((show) => !show)}
|
||||||
|
ref={menuButtonRef}
|
||||||
|
aria-label="Show file options"
|
||||||
|
>
|
||||||
|
<Icon type="more" className="text-neutral" />
|
||||||
|
</button>
|
||||||
|
</StyledTooltip>
|
||||||
|
<Popover
|
||||||
|
title="File options"
|
||||||
|
open={showOptionsMenu}
|
||||||
|
anchorElement={menuButtonRef.current}
|
||||||
|
togglePopover={() => {
|
||||||
|
setShowOptionsMenu(false)
|
||||||
|
}}
|
||||||
|
side="bottom"
|
||||||
|
align="start"
|
||||||
|
className="py-2"
|
||||||
|
overrideZIndex="z-modal"
|
||||||
|
>
|
||||||
|
<Menu a11yLabel="File context menu" isOpen={showOptionsMenu}>
|
||||||
|
<FileMenuOptions
|
||||||
|
filesController={viewControllerManager.filesController}
|
||||||
|
linkingController={viewControllerManager.linkingController}
|
||||||
|
navigationController={viewControllerManager.navigationController}
|
||||||
|
selectedFiles={[currentFile]}
|
||||||
|
closeMenu={() => {
|
||||||
setShowOptionsMenu(false)
|
setShowOptionsMenu(false)
|
||||||
}}
|
}}
|
||||||
side="bottom"
|
shouldShowRenameOption={false}
|
||||||
align="start"
|
shouldShowAttachOption={false}
|
||||||
className="py-2"
|
|
||||||
overrideZIndex="z-modal"
|
|
||||||
>
|
|
||||||
<Menu a11yLabel="File context menu" isOpen={showOptionsMenu}>
|
|
||||||
<FileMenuOptions
|
|
||||||
filesController={viewControllerManager.filesController}
|
|
||||||
linkingController={viewControllerManager.linkingController}
|
|
||||||
navigationController={viewControllerManager.navigationController}
|
|
||||||
selectedFiles={[currentFile]}
|
|
||||||
closeMenu={() => {
|
|
||||||
setShowOptionsMenu(false)
|
|
||||||
}}
|
|
||||||
shouldShowRenameOption={false}
|
|
||||||
shouldShowAttachOption={false}
|
|
||||||
/>
|
|
||||||
</Menu>
|
|
||||||
</Popover>
|
|
||||||
<StyledTooltip label="Show file info" className="!z-modal">
|
|
||||||
<button
|
|
||||||
className="mr-4 flex cursor-pointer rounded border border-solid border-border bg-transparent p-1.5 hover:bg-contrast"
|
|
||||||
onClick={() => setShowFileInfoPanel((show) => !show)}
|
|
||||||
aria-label="Show file info"
|
|
||||||
>
|
|
||||||
<Icon type="info" className="text-neutral" />
|
|
||||||
</button>
|
|
||||||
</StyledTooltip>
|
|
||||||
<button
|
|
||||||
ref={closeButtonRef}
|
|
||||||
onClick={dismiss}
|
|
||||||
aria-label="Close modal"
|
|
||||||
className="flex cursor-pointer rounded border-0 bg-transparent p-1 hover:bg-contrast"
|
|
||||||
>
|
|
||||||
<Icon type="close" className="text-neutral" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{showLinkedBubblesContainer && (
|
|
||||||
<div className="-mt-1 min-h-0 flex-shrink-0 border-b border-border py-1.5 px-3.5">
|
|
||||||
<LinkedItemBubblesContainer
|
|
||||||
linkingController={viewControllerManager.linkingController}
|
|
||||||
item={currentFile}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</Menu>
|
||||||
)}
|
</Popover>
|
||||||
<div className="flex min-h-0 flex-grow">
|
<StyledTooltip label="Show file info" className="!z-modal">
|
||||||
<div className="relative flex max-w-full flex-grow items-center justify-center">
|
<button
|
||||||
<FilePreview file={currentFile} application={application} key={currentFile.uuid} />
|
className="mr-4 flex cursor-pointer rounded border border-solid border-border bg-transparent p-1.5 hover:bg-contrast"
|
||||||
</div>
|
onClick={() => setShowFileInfoPanel((show) => !show)}
|
||||||
{showFileInfoPanel && <FilePreviewInfoPanel file={currentFile} />}
|
aria-label="Show file info"
|
||||||
</div>
|
>
|
||||||
|
<Icon type="info" className="text-neutral" />
|
||||||
|
</button>
|
||||||
|
</StyledTooltip>
|
||||||
|
<button
|
||||||
|
ref={closeButtonRef}
|
||||||
|
onClick={dismiss}
|
||||||
|
aria-label="Close modal"
|
||||||
|
className="flex cursor-pointer rounded border-0 bg-transparent p-1 hover:bg-contrast"
|
||||||
|
>
|
||||||
|
<Icon type="close" className="text-neutral" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
</div>
|
||||||
</DialogOverlay>
|
{showLinkedBubblesContainer && (
|
||||||
)
|
<div className="-mt-1 min-h-0 flex-shrink-0 border-b border-border py-1.5 px-3.5">
|
||||||
}),
|
<LinkedItemBubblesContainer
|
||||||
)
|
linkingController={viewControllerManager.linkingController}
|
||||||
|
item={currentFile}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="flex min-h-0 flex-grow">
|
||||||
|
<div className="relative flex max-w-full flex-grow items-center justify-center">
|
||||||
|
<FilePreview file={currentFile} application={application} key={currentFile.uuid} />
|
||||||
|
</div>
|
||||||
|
{showFileInfoPanel && <FilePreviewInfoPanel file={currentFile} />}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
FilePreviewModal.displayName = 'FilePreviewModal'
|
FilePreviewModal.displayName = 'FilePreviewModal'
|
||||||
|
|
||||||
const FilePreviewModalWrapper: FunctionComponent<Props> = ({ application, viewControllerManager }) => {
|
const FilePreviewModalWrapper: FunctionComponent<Props> = ({ application, viewControllerManager }) => {
|
||||||
const [isMounted, setElement] = useModalAnimation(viewControllerManager.filePreviewModalController.isOpen)
|
return (
|
||||||
|
<ModalOverlay
|
||||||
if (!isMounted) {
|
className="sn-component p-0"
|
||||||
return null
|
aria-label="File preview modal"
|
||||||
}
|
isOpen={viewControllerManager.filePreviewModalController.isOpen}
|
||||||
|
onDismiss={viewControllerManager.filePreviewModalController.dismiss}
|
||||||
return <FilePreviewModal application={application} viewControllerManager={viewControllerManager} ref={setElement} />
|
dangerouslyBypassScrollLock
|
||||||
|
>
|
||||||
|
<FilePreviewModal application={application} viewControllerManager={viewControllerManager} />
|
||||||
|
</ModalOverlay>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default observer(FilePreviewModalWrapper)
|
export default observer(FilePreviewModalWrapper)
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import { useStateRef } from '@/Hooks/useStateRef'
|
|||||||
import { ImportModalFileItem } from './ImportModalFileItem'
|
import { ImportModalFileItem } from './ImportModalFileItem'
|
||||||
import ImportModalInitialPage from './InitialPage'
|
import ImportModalInitialPage from './InitialPage'
|
||||||
import { ImportModalAction, ImportModalFile, ImportModalState } from './Types'
|
import { ImportModalAction, ImportModalFile, ImportModalState } from './Types'
|
||||||
import Modal, { ModalAction } from '../Shared/Modal'
|
import Modal, { ModalAction } from '../Modal/Modal'
|
||||||
import ModalOverlay from '../Shared/ModalOverlay'
|
import ModalOverlay from '../Modal/ModalOverlay'
|
||||||
|
|
||||||
const reducer = (state: ImportModalState, action: ImportModalAction): ImportModalState => {
|
const reducer = (state: ImportModalState, action: ImportModalAction): ImportModalState => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { classNames } from '@standardnotes/utils'
|
||||||
|
import { ReactNode } from 'react'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
className?: string
|
||||||
|
children: ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
const MobileModalHeader = ({ className, children }: Props) => {
|
||||||
|
return <div className={classNames('grid w-full grid-cols-[0.35fr_1fr_0.35fr] gap-2', className)}>{children}</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MobileModalHeader
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
import { useMediaQuery, MutuallyExclusiveMediaQueryBreakpoints } from '@/Hooks/useMediaQuery'
|
import { useMediaQuery, MutuallyExclusiveMediaQueryBreakpoints } from '@/Hooks/useMediaQuery'
|
||||||
import { isIOS } from '@/Utils'
|
import { isIOS } from '@/Utils'
|
||||||
import { AlertDialogContent, AlertDialogLabel } from '@reach/alert-dialog'
|
import { DialogContent } from '@reach/dialog'
|
||||||
import { classNames } from '@standardnotes/snjs'
|
import { classNames } from '@standardnotes/snjs'
|
||||||
import { ReactNode, useMemo, useRef, useState } from 'react'
|
import { ReactNode, useMemo, useRef, useState } from 'react'
|
||||||
import Button from '../Button/Button'
|
import Button from '../Button/Button'
|
||||||
import Icon from '../Icon/Icon'
|
import Icon from '../Icon/Icon'
|
||||||
import Popover from '../Popover/Popover'
|
import Popover from '../Popover/Popover'
|
||||||
import MobileModalAction from './MobileModalAction'
|
import MobileModalAction from './MobileModalAction'
|
||||||
|
import MobileModalHeader from './MobileModalHeader'
|
||||||
import ModalAndroidBackHandler from './ModalAndroidBackHandler'
|
import ModalAndroidBackHandler from './ModalAndroidBackHandler'
|
||||||
import ModalDialogDescription from './ModalDialogDescription'
|
|
||||||
|
|
||||||
export type ModalAction = {
|
export type ModalAction = {
|
||||||
label: NonNullable<ReactNode>
|
label: NonNullable<ReactNode>
|
||||||
@@ -28,11 +28,21 @@ type Props = {
|
|||||||
description?: string
|
description?: string
|
||||||
}
|
}
|
||||||
customHeader?: ReactNode
|
customHeader?: ReactNode
|
||||||
|
disableCustomHeader?: boolean
|
||||||
customFooter?: ReactNode
|
customFooter?: ReactNode
|
||||||
children: ReactNode
|
children: ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
const Modal = ({ title, close, actions = [], className = {}, customHeader, customFooter, children }: Props) => {
|
const Modal = ({
|
||||||
|
title,
|
||||||
|
close,
|
||||||
|
actions = [],
|
||||||
|
className = {},
|
||||||
|
customHeader,
|
||||||
|
disableCustomHeader = false,
|
||||||
|
customFooter,
|
||||||
|
children,
|
||||||
|
}: Props) => {
|
||||||
const sortedActions = useMemo(
|
const sortedActions = useMemo(
|
||||||
() =>
|
() =>
|
||||||
actions
|
actions
|
||||||
@@ -75,7 +85,6 @@ const Modal = ({ title, close, actions = [], className = {}, customHeader, custo
|
|||||||
|
|
||||||
const leftSlotAction = sortedActions.find((action) => action.mobileSlot === 'left')
|
const leftSlotAction = sortedActions.find((action) => action.mobileSlot === 'left')
|
||||||
const rightSlotAction = sortedActions.find((action) => action.mobileSlot === 'right')
|
const rightSlotAction = sortedActions.find((action) => action.mobileSlot === 'right')
|
||||||
const hasCancelAction = sortedActions.some((action) => action.type === 'cancel')
|
|
||||||
const firstPrimaryActionIndex = sortedActions.findIndex((action) => action.type === 'primary')
|
const firstPrimaryActionIndex = sortedActions.findIndex((action) => action.type === 'primary')
|
||||||
|
|
||||||
const extraActions = sortedActions.filter((action) => action.type !== 'primary' && action.type !== 'cancel')
|
const extraActions = sortedActions.filter((action) => action.type !== 'primary' && action.type !== 'cancel')
|
||||||
@@ -86,23 +95,24 @@ const Modal = ({ title, close, actions = [], className = {}, customHeader, custo
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ModalAndroidBackHandler close={close} />
|
<ModalAndroidBackHandler close={close} />
|
||||||
<AlertDialogContent
|
<DialogContent
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'm-0 flex h-full w-full flex-col border-solid border-border bg-default p-0 md:h-auto md:max-h-[85vh] md:w-160 md:rounded md:border md:shadow-main',
|
'm-0 flex h-full w-full flex-col border-solid border-border bg-default p-0 md:h-auto md:max-h-[85vh] md:w-160 md:rounded md:border md:shadow-main',
|
||||||
className.content,
|
className.content,
|
||||||
)}
|
)}
|
||||||
|
aria-label={title}
|
||||||
>
|
>
|
||||||
{customHeader ? (
|
{customHeader && !disableCustomHeader ? (
|
||||||
customHeader
|
customHeader
|
||||||
) : (
|
) : (
|
||||||
<AlertDialogLabel
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'flex flex-shrink-0 items-center justify-between rounded-t border-b border-solid border-border bg-default text-text md:px-4.5 md:py-3',
|
'flex w-full flex-shrink-0 items-center justify-between rounded-t border-b border-solid border-border bg-default text-text md:px-4.5 md:py-3',
|
||||||
isIOS() ? 'pt-safe-top' : 'py-1.5 px-2',
|
isIOS() ? 'px-2 pt-safe-top pb-1.5' : 'py-1.5 px-2',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="grid w-full grid-cols-[0.35fr_1fr_0.35fr] flex-row items-center justify-between gap-2 md:flex md:gap-0">
|
<MobileModalHeader className="flex-row items-center justify-between md:flex md:gap-0">
|
||||||
{leftSlotAction ? (
|
{leftSlotAction ? (
|
||||||
<MobileModalAction
|
<MobileModalAction
|
||||||
type={leftSlotAction.type}
|
type={leftSlotAction.type}
|
||||||
@@ -172,13 +182,11 @@ const Modal = ({ title, close, actions = [], className = {}, customHeader, custo
|
|||||||
>
|
>
|
||||||
{rightSlotAction.label}
|
{rightSlotAction.label}
|
||||||
</MobileModalAction>
|
</MobileModalAction>
|
||||||
) : sortedActions.length === 0 || !hasCancelAction ? (
|
|
||||||
<MobileModalAction children="Done" action={close} slot="right" />
|
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</MobileModalHeader>
|
||||||
</AlertDialogLabel>
|
</div>
|
||||||
)}
|
)}
|
||||||
<ModalDialogDescription className={className.description}>{children}</ModalDialogDescription>
|
<div className={classNames('flex-grow overflow-y-auto', className.description)}>{children}</div>
|
||||||
{customFooter
|
{customFooter
|
||||||
? customFooter
|
? customFooter
|
||||||
: sortedActions.length > 0 && (
|
: sortedActions.length > 0 && (
|
||||||
@@ -207,7 +215,7 @@ const Modal = ({ title, close, actions = [], className = {}, customHeader, custo
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</AlertDialogContent>
|
</DialogContent>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -8,14 +8,15 @@ type Props = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ModalDialogButtons: FunctionComponent<Props> = ({ children, className }) => (
|
const ModalDialogButtons: FunctionComponent<Props> = ({ children, className }) => (
|
||||||
<>
|
<div
|
||||||
<hr className="m-0 h-[1px] border-none bg-border" />
|
className={classNames(
|
||||||
<div
|
'flex items-center justify-end gap-3 border-t border-border px-4 py-4',
|
||||||
className={classNames('flex items-center justify-end gap-3 px-4 py-4', isIOS() && 'pb-safe-bottom', className)}
|
isIOS() && 'pb-safe-bottom',
|
||||||
>
|
className,
|
||||||
{children}
|
)}
|
||||||
</div>
|
>
|
||||||
</>
|
{children}
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
export default ModalDialogButtons
|
export default ModalDialogButtons
|
||||||
@@ -1,18 +1,16 @@
|
|||||||
import { AlertDialogOverlay } from '@reach/alert-dialog'
|
import { DialogOverlay, DialogOverlayProps } from '@reach/dialog'
|
||||||
import { classNames } from '@standardnotes/snjs'
|
import { classNames } from '@standardnotes/snjs'
|
||||||
import { ReactNode, useRef } from 'react'
|
import { ReactNode } from 'react'
|
||||||
import { useModalAnimation } from './useModalAnimation'
|
import { useModalAnimation } from '../Modal/useModalAnimation'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean
|
isOpen: boolean
|
||||||
onDismiss?: () => void
|
onDismiss?: () => void
|
||||||
children: ReactNode
|
children: ReactNode
|
||||||
className?: string
|
className?: string
|
||||||
}
|
} & DialogOverlayProps
|
||||||
|
|
||||||
const ModalOverlay = ({ isOpen, onDismiss, children, className }: Props) => {
|
|
||||||
const ldRef = useRef<HTMLButtonElement>(null)
|
|
||||||
|
|
||||||
|
const ModalOverlay = ({ isOpen, onDismiss, children, className, ...props }: Props) => {
|
||||||
const [isMounted, setElement] = useModalAnimation(isOpen)
|
const [isMounted, setElement] = useModalAnimation(isOpen)
|
||||||
|
|
||||||
if (!isMounted) {
|
if (!isMounted) {
|
||||||
@@ -20,14 +18,14 @@ const ModalOverlay = ({ isOpen, onDismiss, children, className }: Props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AlertDialogOverlay
|
<DialogOverlay
|
||||||
className={classNames('p-0 md:px-0 md:opacity-100', className)}
|
className={classNames('p-0 md:px-0 md:opacity-100', className)}
|
||||||
leastDestructiveRef={ldRef}
|
|
||||||
onDismiss={onDismiss}
|
onDismiss={onDismiss}
|
||||||
ref={setElement}
|
ref={setElement}
|
||||||
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</AlertDialogOverlay>
|
</DialogOverlay>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ import { getPlaintextFontSize } from '@/Utils/getPlaintextFontSize'
|
|||||||
import ReadonlyPlugin from './Plugins/ReadonlyPlugin/ReadonlyPlugin'
|
import ReadonlyPlugin from './Plugins/ReadonlyPlugin/ReadonlyPlugin'
|
||||||
import { SuperSearchContextProvider } from './Plugins/SearchPlugin/Context'
|
import { SuperSearchContextProvider } from './Plugins/SearchPlugin/Context'
|
||||||
import { SearchPlugin } from './Plugins/SearchPlugin/SearchPlugin'
|
import { SearchPlugin } from './Plugins/SearchPlugin/SearchPlugin'
|
||||||
import ModalOverlay from '@/Components/Shared/ModalOverlay'
|
import ModalOverlay from '@/Components/Modal/ModalOverlay'
|
||||||
|
|
||||||
const NotePreviewCharLimit = 160
|
const NotePreviewCharLimit = 160
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { ErrorBoundary } from '@/Utils/ErrorBoundary'
|
|||||||
import ImportPlugin from './Plugins/ImportPlugin/ImportPlugin'
|
import ImportPlugin from './Plugins/ImportPlugin/ImportPlugin'
|
||||||
import { NoteViewController } from '../Controller/NoteViewController'
|
import { NoteViewController } from '../Controller/NoteViewController'
|
||||||
import { spaceSeparatedStrings } from '@standardnotes/utils'
|
import { spaceSeparatedStrings } from '@standardnotes/utils'
|
||||||
import Modal, { ModalAction } from '@/Components/Shared/Modal'
|
import Modal, { ModalAction } from '@/Components/Modal/Modal'
|
||||||
|
|
||||||
const NotePreviewCharLimit = 160
|
const NotePreviewCharLimit = 160
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import MarkdownPreviewPlugin from './Plugins/MarkdownPreviewPlugin/MarkdownPrevi
|
|||||||
import { FileNode } from './Plugins/EncryptedFilePlugin/Nodes/FileNode'
|
import { FileNode } from './Plugins/EncryptedFilePlugin/Nodes/FileNode'
|
||||||
import { BubbleNode } from './Plugins/ItemBubblePlugin/Nodes/BubbleNode'
|
import { BubbleNode } from './Plugins/ItemBubblePlugin/Nodes/BubbleNode'
|
||||||
import { copyTextToClipboard } from '../../../Utils/copyTextToClipboard'
|
import { copyTextToClipboard } from '../../../Utils/copyTextToClipboard'
|
||||||
import Modal, { ModalAction } from '@/Components/Shared/Modal'
|
import Modal, { ModalAction } from '@/Components/Modal/Modal'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
note: SNNote
|
note: SNNote
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { WebApplication } from '@/Application/Application'
|
|||||||
import { createRef } from 'react'
|
import { createRef } from 'react'
|
||||||
import { AbstractComponent } from '@/Components/Abstract/PureComponent'
|
import { AbstractComponent } from '@/Components/Abstract/PureComponent'
|
||||||
import DecoratedPasswordInput from '../Input/DecoratedPasswordInput'
|
import DecoratedPasswordInput from '../Input/DecoratedPasswordInput'
|
||||||
import Modal from '../Shared/Modal'
|
import Modal from '../Modal/Modal'
|
||||||
import { isMobileScreen } from '@/Utils'
|
import { isMobileScreen } from '@/Utils'
|
||||||
import Spinner from '../Spinner/Spinner'
|
import Spinner from '../Spinner/Spinner'
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { SNComponent } from '@standardnotes/snjs'
|
import { SNComponent } from '@standardnotes/snjs'
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import Button from '@/Components/Button/Button'
|
import Button from '@/Components/Button/Button'
|
||||||
import ModalDialogButtons from '../Shared/ModalDialogButtons'
|
import ModalDialogButtons from '../Modal/ModalDialogButtons'
|
||||||
import Modal from '../Shared/Modal'
|
import Modal from '../Modal/Modal'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
callback: (approved: boolean) => void
|
callback: (approved: boolean) => void
|
||||||
@@ -37,13 +37,11 @@ const PermissionsModal = ({ callback, component, dismiss, permissionsString }: P
|
|||||||
]}
|
]}
|
||||||
className={{ content: 'md:!w-[350px]' }}
|
className={{ content: 'md:!w-[350px]' }}
|
||||||
customFooter={
|
customFooter={
|
||||||
<div className="hidden md:block">
|
<ModalDialogButtons className="hidden md:flex">
|
||||||
<ModalDialogButtons>
|
<Button primary fullWidth onClick={accept} className="block">
|
||||||
<Button primary fullWidth onClick={accept} className="block">
|
Continue
|
||||||
Continue
|
</Button>
|
||||||
</Button>
|
</ModalDialogButtons>
|
||||||
</ModalDialogButtons>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="px-4 py-4">
|
<div className="px-4 py-4">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { WebApplication } from '@/Application/Application'
|
import { WebApplication } from '@/Application/Application'
|
||||||
import { ApplicationEvent, PermissionDialog } from '@standardnotes/snjs'
|
import { ApplicationEvent, PermissionDialog } from '@standardnotes/snjs'
|
||||||
import { FunctionComponent, useCallback, useEffect, useState } from 'react'
|
import { FunctionComponent, useCallback, useEffect, useState } from 'react'
|
||||||
import ModalOverlay from '../Shared/ModalOverlay'
|
import ModalOverlay from '../Modal/ModalOverlay'
|
||||||
import PermissionsModal from './PermissionsModal'
|
import PermissionsModal from './PermissionsModal'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ import { useDisableBodyScrollOnMobile } from '@/Hooks/useDisableBodyScrollOnMobi
|
|||||||
import { classNames } from '@standardnotes/snjs'
|
import { classNames } from '@standardnotes/snjs'
|
||||||
import { ReactNode } from 'react'
|
import { ReactNode } from 'react'
|
||||||
import Portal from '../Portal/Portal'
|
import Portal from '../Portal/Portal'
|
||||||
import MobileModalAction from '../Shared/MobileModalAction'
|
import MobileModalAction from '../Modal/MobileModalAction'
|
||||||
import { useModalAnimation } from '../Shared/useModalAnimation'
|
import { useModalAnimation } from '../Modal/useModalAnimation'
|
||||||
|
import MobileModalHeader from '../Modal/MobileModalHeader'
|
||||||
|
|
||||||
const DisableScroll = () => {
|
const DisableScroll = () => {
|
||||||
useDisableBodyScrollOnMobile()
|
useDisableBodyScrollOnMobile()
|
||||||
@@ -41,13 +42,13 @@ const MobilePopoverContent = ({
|
|||||||
data-popover={id}
|
data-popover={id}
|
||||||
data-mobile-popover
|
data-mobile-popover
|
||||||
>
|
>
|
||||||
<div className="grid w-full grid-cols-[0.35fr_1fr_0.35fr] gap-2 border-b border-border py-1.5 px-2 text-base">
|
<MobileModalHeader className="border-b border-border py-1.5 px-2 text-base">
|
||||||
<div />
|
<div />
|
||||||
<div className="flex items-center justify-center font-semibold">{title}</div>
|
<div className="flex items-center justify-center font-semibold">{title}</div>
|
||||||
<MobileModalAction type="primary" slot="right" action={requestClose}>
|
<MobileModalAction type="primary" slot="right" action={requestClose}>
|
||||||
Done
|
Done
|
||||||
</MobileModalAction>
|
</MobileModalAction>
|
||||||
</div>
|
</MobileModalHeader>
|
||||||
<div className={classNames('h-full overflow-y-auto', className)}>{children}</div>
|
<div className={classNames('h-full overflow-y-auto', className)}>{children}</div>
|
||||||
</div>
|
</div>
|
||||||
</Portal>
|
</Portal>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { WebApplication } from '@/Application/Application'
|
|||||||
import { useBeforeUnload } from '@/Hooks/useBeforeUnload'
|
import { useBeforeUnload } from '@/Hooks/useBeforeUnload'
|
||||||
import ChangeEmailForm from './ChangeEmailForm'
|
import ChangeEmailForm from './ChangeEmailForm'
|
||||||
import ChangeEmailSuccess from './ChangeEmailSuccess'
|
import ChangeEmailSuccess from './ChangeEmailSuccess'
|
||||||
import Modal, { ModalAction } from '@/Components/Shared/Modal'
|
import Modal, { ModalAction } from '@/Components/Modal/Modal'
|
||||||
|
|
||||||
enum SubmitButtonTitles {
|
enum SubmitButtonTitles {
|
||||||
Default = 'Continue',
|
Default = 'Continue',
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
|
|||||||
import PasswordWizard from '@/Components/PasswordWizard/PasswordWizard'
|
import PasswordWizard from '@/Components/PasswordWizard/PasswordWizard'
|
||||||
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
|
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
|
||||||
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
||||||
import ModalOverlay from '@/Components/Shared/ModalOverlay'
|
import ModalOverlay from '@/Components/Modal/ModalOverlay'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
application: WebApplication
|
application: WebApplication
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { SubscriptionController } from '@/Controllers/Subscription/SubscriptionC
|
|||||||
|
|
||||||
import InviteForm from './InviteForm'
|
import InviteForm from './InviteForm'
|
||||||
import InviteSuccess from './InviteSuccess'
|
import InviteSuccess from './InviteSuccess'
|
||||||
import Modal, { ModalAction } from '@/Components/Shared/Modal'
|
import Modal, { ModalAction } from '@/Components/Modal/Modal'
|
||||||
|
|
||||||
enum SubmitButtonTitles {
|
enum SubmitButtonTitles {
|
||||||
Default = 'Invite',
|
Default = 'Invite',
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import InvitationsList from './InvitationsList'
|
|||||||
import Invite from './Invite/Invite'
|
import Invite from './Invite/Invite'
|
||||||
import Button from '@/Components/Button/Button'
|
import Button from '@/Components/Button/Button'
|
||||||
import SharingStatusText from './SharingStatusText'
|
import SharingStatusText from './SharingStatusText'
|
||||||
import ModalOverlay from '@/Components/Shared/ModalOverlay'
|
import ModalOverlay from '@/Components/Modal/ModalOverlay'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
application: WebApplication
|
application: WebApplication
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import Icon from '@/Components/Icon/Icon'
|
import Icon from '@/Components/Icon/Icon'
|
||||||
import IconPicker from '@/Components/Icon/IconPicker'
|
import IconPicker from '@/Components/Icon/IconPicker'
|
||||||
import Popover from '@/Components/Popover/Popover'
|
import Popover from '@/Components/Popover/Popover'
|
||||||
import Modal, { ModalAction } from '@/Components/Shared/Modal'
|
import Modal, { ModalAction } from '@/Components/Modal/Modal'
|
||||||
import Spinner from '@/Components/Spinner/Spinner'
|
import Spinner from '@/Components/Spinner/Spinner'
|
||||||
import { Platform, SmartViewDefaultIconName, VectorIconNameOrEmoji } from '@standardnotes/snjs'
|
import { Platform, SmartViewDefaultIconName, VectorIconNameOrEmoji } from '@standardnotes/snjs'
|
||||||
import { observer } from 'mobx-react-lite'
|
import { observer } from 'mobx-react-lite'
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import NoSubscriptionBanner from '@/Components/NoSubscriptionBanner/NoSubscripti
|
|||||||
import { EditSmartViewModalController } from './EditSmartViewModalController'
|
import { EditSmartViewModalController } from './EditSmartViewModalController'
|
||||||
import { STRING_DELETE_TAG } from '@/Constants/Strings'
|
import { STRING_DELETE_TAG } from '@/Constants/Strings'
|
||||||
import { confirmDialog } from '@standardnotes/ui-services'
|
import { confirmDialog } from '@standardnotes/ui-services'
|
||||||
import ModalOverlay from '@/Components/Shared/ModalOverlay'
|
import ModalOverlay from '@/Components/Modal/ModalOverlay'
|
||||||
|
|
||||||
type NewType = {
|
type NewType = {
|
||||||
application: WebApplication
|
application: WebApplication
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import PreferencesGroup from '@/Components/Preferences/PreferencesComponents/Pre
|
|||||||
import PreferencesSegment from '@/Components/Preferences/PreferencesComponents/PreferencesSegment'
|
import PreferencesSegment from '@/Components/Preferences/PreferencesComponents/PreferencesSegment'
|
||||||
import { WebApplication } from '@/Application/Application'
|
import { WebApplication } from '@/Application/Application'
|
||||||
import RecoveryCodeBanner from '@/Components/RecoveryCodeBanner/RecoveryCodeBanner'
|
import RecoveryCodeBanner from '@/Components/RecoveryCodeBanner/RecoveryCodeBanner'
|
||||||
import Modal, { ModalAction } from '@/Components/Shared/Modal'
|
import Modal, { ModalAction } from '@/Components/Modal/Modal'
|
||||||
import ModalOverlay from '@/Components/Shared/ModalOverlay'
|
import ModalOverlay from '@/Components/Modal/ModalOverlay'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
auth: TwoFactorAuth
|
auth: TwoFactorAuth
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ import { PreferencesProps } from './PreferencesProps'
|
|||||||
import { useDisableBodyScrollOnMobile } from '@/Hooks/useDisableBodyScrollOnMobile'
|
import { useDisableBodyScrollOnMobile } from '@/Hooks/useDisableBodyScrollOnMobile'
|
||||||
import { useAndroidBackHandler } from '@/NativeMobileWeb/useAndroidBackHandler'
|
import { useAndroidBackHandler } from '@/NativeMobileWeb/useAndroidBackHandler'
|
||||||
import { ESCAPE_COMMAND } from '@standardnotes/ui-services'
|
import { ESCAPE_COMMAND } from '@standardnotes/ui-services'
|
||||||
import Modal from '../Shared/Modal'
|
import Modal from '../Modal/Modal'
|
||||||
import { AlertDialogLabel } from '@reach/alert-dialog'
|
|
||||||
import { classNames } from '@standardnotes/snjs'
|
import { classNames } from '@standardnotes/snjs'
|
||||||
import { isIOS } from '@/Utils'
|
import { isIOS } from '@/Utils'
|
||||||
|
|
||||||
@@ -63,7 +62,7 @@ const PreferencesView: FunctionComponent<PreferencesProps> = ({
|
|||||||
description: 'flex flex-col',
|
description: 'flex flex-col',
|
||||||
}}
|
}}
|
||||||
customHeader={
|
customHeader={
|
||||||
<AlertDialogLabel
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'flex w-full flex-row items-center justify-between border-b border-solid border-border bg-default px-3 pb-2 md:p-3',
|
'flex w-full flex-row items-center justify-between border-b border-solid border-border bg-default px-3 pb-2 md:p-3',
|
||||||
isIOS() ? 'pt-safe-top' : 'pt-2',
|
isIOS() ? 'pt-safe-top' : 'pt-2',
|
||||||
@@ -78,7 +77,7 @@ const PreferencesView: FunctionComponent<PreferencesProps> = ({
|
|||||||
icon="close"
|
icon="close"
|
||||||
label="Close preferences"
|
label="Close preferences"
|
||||||
/>
|
/>
|
||||||
</AlertDialogLabel>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<PreferencesCanvas
|
<PreferencesCanvas
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import PreferencesView from './PreferencesView'
|
|||||||
import { PreferencesViewWrapperProps } from './PreferencesViewWrapperProps'
|
import { PreferencesViewWrapperProps } from './PreferencesViewWrapperProps'
|
||||||
import { useCommandService } from '../CommandProvider'
|
import { useCommandService } from '../CommandProvider'
|
||||||
import { OPEN_PREFERENCES_COMMAND } from '@standardnotes/ui-services'
|
import { OPEN_PREFERENCES_COMMAND } from '@standardnotes/ui-services'
|
||||||
import ModalOverlay from '../Shared/ModalOverlay'
|
import ModalOverlay from '../Modal/ModalOverlay'
|
||||||
|
|
||||||
const PreferencesViewWrapper: FunctionComponent<PreferencesViewWrapperProps> = ({
|
const PreferencesViewWrapper: FunctionComponent<PreferencesViewWrapperProps> = ({
|
||||||
viewControllerManager,
|
viewControllerManager,
|
||||||
|
|||||||
@@ -8,8 +8,9 @@ import { NoteHistoryController } from '@/Controllers/NoteHistory/NoteHistoryCont
|
|||||||
import Icon from '../Icon/Icon'
|
import Icon from '../Icon/Icon'
|
||||||
import { classNames } from '@standardnotes/utils'
|
import { classNames } from '@standardnotes/utils'
|
||||||
import { HistoryModalMobileTab } from './utils'
|
import { HistoryModalMobileTab } from './utils'
|
||||||
import MobileModalAction from '../Shared/MobileModalAction'
|
import MobileModalAction from '../Modal/MobileModalAction'
|
||||||
import Popover from '../Popover/Popover'
|
import Popover from '../Popover/Popover'
|
||||||
|
import MobileModalHeader from '../Modal/MobileModalHeader'
|
||||||
|
|
||||||
const HistoryModalDialogContent = ({
|
const HistoryModalDialogContent = ({
|
||||||
application,
|
application,
|
||||||
@@ -28,7 +29,7 @@ const HistoryModalDialogContent = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="grid w-full grid-cols-[0.35fr_1fr_0.35fr] items-center gap-2 border-b border-border py-1 px-2 md:hidden">
|
<MobileModalHeader className="items-center border-b border-border py-1 px-2 md:hidden">
|
||||||
<MobileModalAction type="secondary" action={toggleTabMenu} slot="left" ref={tabOptionRef}>
|
<MobileModalAction type="secondary" action={toggleTabMenu} slot="left" ref={tabOptionRef}>
|
||||||
<div className="rounded-full border border-border p-0.5">
|
<div className="rounded-full border border-border p-0.5">
|
||||||
<Icon type="more" />
|
<Icon type="more" />
|
||||||
@@ -67,7 +68,7 @@ const HistoryModalDialogContent = ({
|
|||||||
<MobileModalAction type="primary" slot="right" action={dismissModal}>
|
<MobileModalAction type="primary" slot="right" action={dismissModal}>
|
||||||
Done
|
Done
|
||||||
</MobileModalAction>
|
</MobileModalAction>
|
||||||
</div>
|
</MobileModalHeader>
|
||||||
<div className="flex min-h-0 flex-grow">
|
<div className="flex min-h-0 flex-grow">
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import HistoryModalDialogContent from './HistoryModalDialogContent'
|
|||||||
import HistoryModalDialog from './HistoryModalDialog'
|
import HistoryModalDialog from './HistoryModalDialog'
|
||||||
import { RevisionHistoryModalProps } from './RevisionHistoryModalProps'
|
import { RevisionHistoryModalProps } from './RevisionHistoryModalProps'
|
||||||
import { useAndroidBackHandler } from '@/NativeMobileWeb/useAndroidBackHandler'
|
import { useAndroidBackHandler } from '@/NativeMobileWeb/useAndroidBackHandler'
|
||||||
import { useModalAnimation } from '../Shared/useModalAnimation'
|
import { useModalAnimation } from '../Modal/useModalAnimation'
|
||||||
|
|
||||||
const RevisionHistoryModal: FunctionComponent<RevisionHistoryModalProps> = ({
|
const RevisionHistoryModal: FunctionComponent<RevisionHistoryModalProps> = ({
|
||||||
application,
|
application,
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import { observer } from 'mobx-react-lite'
|
|||||||
import Spinner from '@/Components/Spinner/Spinner'
|
import Spinner from '@/Components/Spinner/Spinner'
|
||||||
import Button from '@/Components/Button/Button'
|
import Button from '@/Components/Button/Button'
|
||||||
import Icon from '../Icon/Icon'
|
import Icon from '../Icon/Icon'
|
||||||
import Modal, { ModalAction } from '../Shared/Modal'
|
import Modal, { ModalAction } from '../Modal/Modal'
|
||||||
import ModalOverlay from '../Shared/ModalOverlay'
|
import ModalOverlay from '../Modal/ModalOverlay'
|
||||||
|
|
||||||
type Session = RemoteSession & {
|
type Session = RemoteSession & {
|
||||||
revoking?: true
|
revoking?: true
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
import { useRef, ReactNode } from 'react'
|
|
||||||
import { AlertDialogContent, AlertDialogOverlay } from '@reach/alert-dialog'
|
|
||||||
import { classNames } from '@standardnotes/utils'
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
children: ReactNode
|
|
||||||
onDismiss?: () => void
|
|
||||||
className?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const ModalDialog = ({ children, onDismiss, className }: Props) => {
|
|
||||||
const ldRef = useRef<HTMLButtonElement>(null)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AlertDialogOverlay className="p-0 md:px-0" leastDestructiveRef={ldRef} onDismiss={onDismiss}>
|
|
||||||
<AlertDialogContent
|
|
||||||
tabIndex={0}
|
|
||||||
className={classNames(
|
|
||||||
'm-0 flex w-full flex-col border-solid border-border bg-default p-0 shadow-main md:max-h-[85vh] md:w-160 md:rounded md:border',
|
|
||||||
className,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</AlertDialogContent>
|
|
||||||
</AlertDialogOverlay>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ModalDialog
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { FunctionComponent, ReactNode } from 'react'
|
|
||||||
import { AlertDialogDescription } from '@reach/alert-dialog'
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
className?: string
|
|
||||||
children?: ReactNode
|
|
||||||
}
|
|
||||||
|
|
||||||
const ModalDialogDescription: FunctionComponent<Props> = ({ children, className = '' }) => (
|
|
||||||
<AlertDialogDescription className={`flex-grow overflow-y-auto ${className}`}>{children}</AlertDialogDescription>
|
|
||||||
)
|
|
||||||
|
|
||||||
export default ModalDialogDescription
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
import { FunctionComponent, ReactNode, useEffect } from 'react'
|
|
||||||
import { AlertDialogLabel } from '@reach/alert-dialog'
|
|
||||||
import Icon from '@/Components/Icon/Icon'
|
|
||||||
import { classNames } from '@standardnotes/utils'
|
|
||||||
import { useAndroidBackHandler } from '@/NativeMobileWeb/useAndroidBackHandler'
|
|
||||||
import { isIOS } from '@/Utils'
|
|
||||||
import MobileModalAction from './MobileModalAction'
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
closeDialog: () => void
|
|
||||||
className?: string
|
|
||||||
headerButtons?: ReactNode
|
|
||||||
leftMobileButton?: ReactNode
|
|
||||||
rightMobileButton?: ReactNode
|
|
||||||
children?: ReactNode
|
|
||||||
}
|
|
||||||
|
|
||||||
const ModalDialogLabel: FunctionComponent<Props> = ({
|
|
||||||
children,
|
|
||||||
closeDialog,
|
|
||||||
className,
|
|
||||||
headerButtons,
|
|
||||||
leftMobileButton,
|
|
||||||
rightMobileButton,
|
|
||||||
}) => {
|
|
||||||
const addAndroidBackHandler = useAndroidBackHandler()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const removeListener = addAndroidBackHandler(() => {
|
|
||||||
closeDialog()
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return () => {
|
|
||||||
if (removeListener) {
|
|
||||||
removeListener()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [addAndroidBackHandler, closeDialog])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AlertDialogLabel
|
|
||||||
className={classNames(
|
|
||||||
'flex flex-shrink-0 items-center justify-between rounded-t border-b border-solid border-border bg-default py-1.5 px-1 text-text md:px-4.5 md:py-3',
|
|
||||||
isIOS() && 'pt-safe-top',
|
|
||||||
className,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="grid w-full grid-cols-[0.35fr_1fr_0.35fr] flex-row items-center justify-between gap-2 md:flex md:gap-0">
|
|
||||||
{leftMobileButton ? leftMobileButton : <div className="md:hidden" />}
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
'overflow-hidden text-ellipsis whitespace-nowrap text-center text-base font-semibold text-text md:flex-grow md:text-left md:text-lg',
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
<div className="hidden items-center gap-2 md:flex">
|
|
||||||
{headerButtons}
|
|
||||||
<button tabIndex={0} className="ml-2 rounded p-1 font-bold hover:bg-contrast" onClick={closeDialog}>
|
|
||||||
<Icon type="close" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{rightMobileButton ? (
|
|
||||||
rightMobileButton
|
|
||||||
) : (
|
|
||||||
<MobileModalAction slot="right" children="Done" action={closeDialog} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<hr className="h-1px no-border m-0 bg-border" />
|
|
||||||
</AlertDialogLabel>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ModalDialogLabel
|
|
||||||
@@ -13,7 +13,7 @@ import TabsContainer from '../Tabs/TabsContainer'
|
|||||||
import CopyableCodeBlock from '../Shared/CopyableCodeBlock'
|
import CopyableCodeBlock from '../Shared/CopyableCodeBlock'
|
||||||
import { Disclosure, DisclosureButton, DisclosurePanel } from '@reach/disclosure'
|
import { Disclosure, DisclosureButton, DisclosurePanel } from '@reach/disclosure'
|
||||||
import { classNames } from '@standardnotes/utils'
|
import { classNames } from '@standardnotes/utils'
|
||||||
import Modal, { ModalAction } from '../Shared/Modal'
|
import Modal, { ModalAction } from '../Modal/Modal'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
controller: AddSmartViewModalController
|
controller: AddSmartViewModalController
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { FunctionComponent, useCallback, useMemo } from 'react'
|
|||||||
import IconButton from '../Button/IconButton'
|
import IconButton from '../Button/IconButton'
|
||||||
import EditSmartViewModal from '../Preferences/Panes/General/SmartViews/EditSmartViewModal'
|
import EditSmartViewModal from '../Preferences/Panes/General/SmartViews/EditSmartViewModal'
|
||||||
import { EditSmartViewModalController } from '../Preferences/Panes/General/SmartViews/EditSmartViewModalController'
|
import { EditSmartViewModalController } from '../Preferences/Panes/General/SmartViews/EditSmartViewModalController'
|
||||||
import ModalOverlay from '../Shared/ModalOverlay'
|
import ModalOverlay from '../Modal/ModalOverlay'
|
||||||
import AddSmartViewModal from '../SmartViewBuilder/AddSmartViewModal'
|
import AddSmartViewModal from '../SmartViewBuilder/AddSmartViewModal'
|
||||||
import { AddSmartViewModalController } from '../SmartViewBuilder/AddSmartViewModalController'
|
import { AddSmartViewModalController } from '../SmartViewBuilder/AddSmartViewModalController'
|
||||||
import SmartViewsList from './SmartViewsList'
|
import SmartViewsList from './SmartViewsList'
|
||||||
|
|||||||
Reference in New Issue
Block a user