feat: Replaced margin resizers with "Editor width" options. You can set it globally from Preferences > Appearance or per-note from the note options menu (#2324)

This commit is contained in:
Aman Harwara
2023-05-04 17:42:16 +05:30
committed by GitHub
parent 488142683c
commit 9fbb845b1d
18 changed files with 403 additions and 84 deletions

View File

@@ -0,0 +1,216 @@
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
import { classNames, EditorLineWidth, PrefKey, SNNote } from '@standardnotes/snjs'
import { useCallback, useEffect, useMemo, useState } from 'react'
import Button from '../Button/Button'
import Modal, { ModalAction } from '../Modal/Modal'
import ModalDialogButtons from '../Modal/ModalDialogButtons'
import RadioButtonGroup from '../RadioButtonGroup/RadioButtonGroup'
import { EditorMargins, EditorMaxWidths } from './EditorWidths'
import { useApplication } from '../ApplicationProvider'
import ModalOverlay from '../Modal/ModalOverlay'
import { CHANGE_EDITOR_WIDTH_COMMAND, ESCAPE_COMMAND } from '@standardnotes/ui-services'
import { PrefDefaults } from '@/Constants/PrefDefaults'
import { observer } from 'mobx-react-lite'
import Switch from '../Switch/Switch'
const DoubleSidedArrow = ({ className }: { className?: string }) => {
return (
<div
className={classNames(
'relative h-[2px] w-full bg-current',
'before:absolute before:-left-px before:top-1/2 before:h-0 before:w-0 before:-translate-y-1/2 before:border-r-[6px] before:border-t-[6px] before:border-b-[6px] before:border-current before:border-b-transparent before:border-t-transparent',
'after:absolute after:-right-px after:top-1/2 after:h-0 after:w-0 after:-translate-y-1/2 after:border-l-[6px] after:border-t-[6px] after:border-b-[6px] after:border-current after:border-b-transparent after:border-t-transparent',
className,
)}
/>
)
}
const EditorWidthSelectionModal = ({
initialValue,
handleChange,
close,
note,
}: {
initialValue: EditorLineWidth
handleChange: (value: EditorLineWidth, setGlobally: boolean) => void
close: () => void
note: SNNote | undefined
}) => {
const application = useApplication()
const isMobileScreen = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm)
const [value, setValue] = useState<EditorLineWidth>(() => initialValue)
const [setGlobally, setSetGlobally] = useState(false)
const options = useMemo(
() => [
{
label: 'Narrow',
value: EditorLineWidth.Narrow,
},
{
label: 'Wide',
value: EditorLineWidth.Wide,
},
{
label: 'Dynamic',
value: EditorLineWidth.Dynamic,
},
{
label: 'Full width',
value: EditorLineWidth.FullWidth,
},
],
[],
)
const accept = useCallback(() => {
handleChange(value, setGlobally)
close()
}, [close, handleChange, setGlobally, value])
const actions = useMemo(
(): ModalAction[] => [
{
label: 'Cancel',
type: 'cancel',
onClick: close,
mobileSlot: 'left',
},
{
label: 'Done',
type: 'primary',
onClick: accept,
mobileSlot: 'right',
},
],
[accept, close],
)
useEffect(() => {
return application.keyboardService.addCommandHandler({
command: ESCAPE_COMMAND,
onKeyDown() {
close()
return
},
})
}, [application.keyboardService, close])
const DynamicMargin = (
<div className="text-center text-sm text-passive-2">
<div className={value !== EditorLineWidth.Dynamic ? 'hidden' : ''}>
<div className="mb-2">{EditorMargins[value]}</div>
<DoubleSidedArrow />
</div>
</div>
)
return (
<Modal
title="Set editor width"
close={close}
customHeader={<></>}
customFooter={<></>}
disableCustomHeader={isMobileScreen}
actions={actions}
className={{
content: 'select-none md:min-w-[40vw]',
description: 'flex min-h-[50vh] flex-col',
}}
>
<div className="flex min-h-0 flex-grow flex-col overflow-hidden rounded bg-passive-5 p-4 pb-0">
<div
className={classNames(
'grid flex-grow grid-cols-[0fr_1fr_0fr] gap-3 rounded rounded-b-none bg-default px-2 pt-4 shadow-[0_1px_4px_rgba(0,0,0,0.12),0_2px_8px_rgba(0,0,0,0.04)] transition-all duration-200 md:px-4',
value === EditorLineWidth.Narrow && 'md:grid-cols-[1fr_60%_1fr]',
value === EditorLineWidth.Wide && 'md:grid-cols-[1fr_70%_1fr]',
value === EditorLineWidth.Dynamic && 'md:grid-cols-[1fr_80%_1fr]',
value === EditorLineWidth.FullWidth && 'md:grid-cols-[1fr_95%_1fr]',
)}
>
{DynamicMargin}
<div className="flex flex-col text-info">
<div className="mb-2 text-center text-sm">
{value === EditorLineWidth.Narrow || value === EditorLineWidth.Wide
? `Max. ${EditorMaxWidths[value]}`
: EditorMaxWidths[value]}
</div>
<DoubleSidedArrow />
<div className="w-full flex-grow bg-[linear-gradient(transparent_50%,var(--sn-stylekit-info-color)_50%)] bg-[length:100%_2.5rem] bg-repeat-y opacity-10" />
</div>
{DynamicMargin}
</div>
</div>
{!!note && (
<div className="border-t border-border bg-default px-4 py-2">
<label className="flex items-center gap-2">
<Switch checked={setGlobally} onChange={setSetGlobally} />
Set globally {note.editorWidth != undefined && '(will not apply to current note)'}
</label>
</div>
)}
<ModalDialogButtons className="justify-center md:justify-between">
<RadioButtonGroup items={options} value={value} onChange={(value) => setValue(value as EditorLineWidth)} />
<div className="hidden items-center gap-2 md:flex">
<Button onClick={close}>Cancel</Button>
<Button onClick={accept} primary>
Apply
</Button>
</div>
</ModalDialogButtons>
</Modal>
)
}
const EditorWidthSelectionModalWrapper = () => {
const application = useApplication()
const { notesController } = application.getViewControllerManager()
const [isOpen, setIsOpen] = useState(false)
const [isGlobal, setIsGlobal] = useState(false)
const note = notesController.selectedNotesCount === 1 && !isGlobal ? notesController.selectedNotes[0] : undefined
const lineWidth = note
? notesController.getEditorWidthForNote(note)
: application.getPreference(PrefKey.EditorLineWidth, PrefDefaults[PrefKey.EditorLineWidth])
const setLineWidth = useCallback(
(lineWidth: EditorLineWidth, setGlobally: boolean) => {
if (note && !setGlobally) {
notesController.setNoteEditorWidth(note, lineWidth).catch(console.error)
} else {
application.setPreference(PrefKey.EditorLineWidth, lineWidth).catch(console.error)
}
},
[application, note, notesController],
)
const toggle = useCallback(() => {
setIsOpen((open) => !open)
}, [])
useEffect(() => {
return application.keyboardService.addCommandHandler({
command: CHANGE_EDITOR_WIDTH_COMMAND,
onKeyDown: (_, data) => {
if (typeof data === 'boolean' && data) {
setIsGlobal(data)
} else {
setIsGlobal(false)
}
toggle()
},
})
}, [application, toggle])
return (
<ModalOverlay isOpen={isOpen}>
<EditorWidthSelectionModal initialValue={lineWidth} handleChange={setLineWidth} close={toggle} note={note} />
</ModalOverlay>
)
}
export default observer(EditorWidthSelectionModalWrapper)

View File

@@ -0,0 +1,15 @@
import { EditorLineWidth } from '@standardnotes/snjs'
export const EditorMaxWidths: { [k in EditorLineWidth]: string } = {
[EditorLineWidth.Narrow]: '512px',
[EditorLineWidth.Wide]: '720px',
[EditorLineWidth.Dynamic]: '80%',
[EditorLineWidth.FullWidth]: '100%',
}
export const EditorMargins: { [k in EditorLineWidth]: string } = {
[EditorLineWidth.Narrow]: 'auto',
[EditorLineWidth.Wide]: 'auto',
[EditorLineWidth.Dynamic]: '10%',
[EditorLineWidth.FullWidth]: '0',
}