From 1983b94a4922a07ffca7366c3df2e0c89a5bdb4f Mon Sep 17 00:00:00 2001 From: Aman Harwara Date: Thu, 17 Feb 2022 01:01:54 +0530 Subject: [PATCH] feat: add change editor button (#874) --- .../components/ChangeEditorButton.tsx | 138 ++++++++++++++++++ app/assets/javascripts/components/Icon.tsx | 2 + .../components/NoteView/NoteView.tsx | 30 ++-- .../NotesOptions/ChangeEditorOption.tsx | 7 +- package.json | 2 +- yarn.lock | 8 +- 6 files changed, 169 insertions(+), 18 deletions(-) create mode 100644 app/assets/javascripts/components/ChangeEditorButton.tsx diff --git a/app/assets/javascripts/components/ChangeEditorButton.tsx b/app/assets/javascripts/components/ChangeEditorButton.tsx new file mode 100644 index 000000000..a62307ab8 --- /dev/null +++ b/app/assets/javascripts/components/ChangeEditorButton.tsx @@ -0,0 +1,138 @@ +import { WebApplication } from '@/ui_models/application'; +import { AppState } from '@/ui_models/app_state'; +import { MENU_MARGIN_FROM_APP_BORDER } from '@/views/constants'; +import { + Disclosure, + DisclosureButton, + DisclosurePanel, +} from '@reach/disclosure'; +import VisuallyHidden from '@reach/visually-hidden'; +import { ComponentArea, SNComponent } from '@standardnotes/snjs'; +import { observer } from 'mobx-react-lite'; +import { FunctionComponent } from 'preact'; +import { useEffect, useRef, useState } from 'preact/hooks'; +import { Icon } from './Icon'; +import { ChangeEditorMenu } from './NotesOptions/changeEditor/ChangeEditorMenu'; +import { createEditorMenuGroups } from './NotesOptions/changeEditor/createEditorMenuGroups'; +import { EditorMenuGroup } from './NotesOptions/ChangeEditorOption'; +import { useCloseOnBlur } from './utils'; + +type Props = { + application: WebApplication; + appState: AppState; + onClickPreprocessing?: () => Promise; +}; + +export const ChangeEditorButton: FunctionComponent = observer( + ({ application, appState, onClickPreprocessing }) => { + const note = Object.values(appState.notes.selectedNotes)[0]; + const [open, setOpen] = useState(false); + const [position, setPosition] = useState({ + top: 0, + right: 0, + }); + const [maxHeight, setMaxHeight] = useState('auto'); + const buttonRef = useRef(null); + const panelRef = useRef(null); + const containerRef = useRef(null); + const [closeOnBlur] = useCloseOnBlur(containerRef, setOpen); + const [editors] = useState(() => + application.componentManager + .componentsForArea(ComponentArea.Editor) + .sort((a, b) => { + return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1; + }) + ); + const [editorMenuGroups, setEditorMenuGroups] = useState( + [] + ); + const [currentEditor, setCurrentEditor] = useState(); + + useEffect(() => { + setEditorMenuGroups(createEditorMenuGroups(editors)); + }, [editors]); + + useEffect(() => { + if (note) { + setCurrentEditor(application.componentManager.editorForNote(note)); + } + }, [application, note]); + + const toggleChangeEditorMenu = async () => { + const rect = buttonRef.current?.getBoundingClientRect(); + if (rect) { + const { clientHeight } = document.documentElement; + const footerElementRect = document + .getElementById('footer-bar') + ?.getBoundingClientRect(); + const footerHeightInPx = footerElementRect?.height; + + if (footerHeightInPx) { + setMaxHeight( + clientHeight - + rect.bottom - + footerHeightInPx - + MENU_MARGIN_FROM_APP_BORDER + ); + } + + setPosition({ + top: rect.bottom, + right: document.body.clientWidth - rect.right, + }); + + const newOpenState = !open; + if (newOpenState && onClickPreprocessing) { + await onClickPreprocessing(); + } + + setOpen(newOpenState); + } + }; + + return ( +
+ + { + if (event.key === 'Escape') { + setOpen(false); + } + }} + onBlur={closeOnBlur} + ref={buttonRef} + className="sn-icon-button" + > + Change editor + + + { + if (event.key === 'Escape') { + setOpen(false); + buttonRef.current?.focus(); + } + }} + ref={panelRef} + style={{ + ...position, + maxHeight, + }} + className="sn-dropdown sn-dropdown--animated min-w-68 max-h-120 max-w-xs flex flex-col overflow-y-auto fixed" + onBlur={closeOnBlur} + > + + + +
+ ); + } +); diff --git a/app/assets/javascripts/components/Icon.tsx b/app/assets/javascripts/components/Icon.tsx index f2db39f7b..55dea7adc 100644 --- a/app/assets/javascripts/components/Icon.tsx +++ b/app/assets/javascripts/components/Icon.tsx @@ -19,6 +19,7 @@ import { CloudOffIcon, CodeIcon, CopyIcon, + DashboardIcon, DownloadIcon, EditorIcon, EmailIcon, @@ -105,6 +106,7 @@ const ICONS = { close: CloseIcon, code: CodeIcon, copy: CopyIcon, + dashboard: DashboardIcon, download: DownloadIcon, editor: EditorIcon, email: EmailIcon, diff --git a/app/assets/javascripts/components/NoteView/NoteView.tsx b/app/assets/javascripts/components/NoteView/NoteView.tsx index c1b35faa6..dbdaa53ca 100644 --- a/app/assets/javascripts/components/NoteView/NoteView.tsx +++ b/app/assets/javascripts/components/NoteView/NoteView.tsx @@ -37,6 +37,7 @@ import { ActionsMenu } from '../ActionsMenu'; import { ComponentView } from '../ComponentView'; import { PanelSide, PanelResizer, PanelResizeType } from '../PanelResizer'; import { ElementIds } from '@/element_ids'; +import { ChangeEditorButton } from '../ChangeEditorButton'; const MINIMUM_STATUS_DURATION = 400; const TEXTAREA_DEBOUNCE = 100; @@ -1070,23 +1071,30 @@ export class NoteView extends PureComponent {
{this.state.noteStatus.desc}
)} - <> -
- -
- + - + +
+ +
+ diff --git a/app/assets/javascripts/components/NotesOptions/ChangeEditorOption.tsx b/app/assets/javascripts/components/NotesOptions/ChangeEditorOption.tsx index afd4a179e..cce8a48c3 100644 --- a/app/assets/javascripts/components/NotesOptions/ChangeEditorOption.tsx +++ b/app/assets/javascripts/components/NotesOptions/ChangeEditorOption.tsx @@ -201,7 +201,10 @@ export const ChangeEditorOption: FunctionComponent = ({ newMenuPosition.top !== 'auto' ) { setChangeEditorMenuMaxHeight( - clientHeight - newMenuPosition.top - footerHeightInPx - 2 + clientHeight - + newMenuPosition.top - + footerHeightInPx - + MENU_MARGIN_FROM_APP_BORDER ); } @@ -225,7 +228,7 @@ export const ChangeEditorOption: FunctionComponent = ({ className="sn-dropdown-item justify-between" >
- + Change editor
diff --git a/package.json b/package.json index 07d3b270e..d8fe21597 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "pug-loader": "^2.4.0", "sass-loader": "^12.2.0", "serve-static": "^1.14.1", - "@standardnotes/stylekit": "5.6.0", + "@standardnotes/stylekit": "5.7.0", "svg-jest": "^1.0.1", "ts-jest": "^27.0.7", "ts-loader": "^9.2.6", diff --git a/yarn.lock b/yarn.lock index b8d3a0f38..8a203597a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2887,10 +2887,10 @@ "@standardnotes/settings" "^1.11.3" "@standardnotes/sncrypto-common" "^1.7.0" -"@standardnotes/stylekit@5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@standardnotes/stylekit/-/stylekit-5.6.0.tgz#52ff63e9bfc823817832786d54e21e8522f061ac" - integrity sha512-F6PxkVSKJBZMTYkGT96hVPDvcmpvevAC36KwMnaMtnjMQGfOjMLYJRgef5bJunvOeqo2bvoPX5xcd4EwacTBBw== +"@standardnotes/stylekit@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@standardnotes/stylekit/-/stylekit-5.7.0.tgz#3dc9c22ad554ec4f2cc58462fa6199a3339a4ab0" + integrity sha512-zc3XiRa/oKOZMc1BHo/sP9ncAdFOXaRGGa87hVtMcQ9gUbouuWvBbkL1ZLV0sb63J5SuPPScEnfK/XqVld8ChA== dependencies: "@reach/listbox" "^0.15.0" "@reach/menu-button" "^0.15.1"