import React, { memo, useCallback, useMemo, useState, } from 'react'; import { type EditorTheme, type KeyMapMode, PasteMode, AllPasteMode, DEFAULT_KEYMAP, DEFAULT_PASTE_MODE, DEFAULT_THEME, } from '@growi/editor'; import { useTranslation } from 'next-i18next'; import Image from 'next/image'; import { Dropdown, DropdownToggle, DropdownMenu, Input, FormGroup, } from 'reactstrap'; import { useIsIndentSizeForced } from '~/stores-universal/context'; import { useEditorSettings, useCurrentIndentSize } from '~/stores/editor'; import { useIsDeviceLargerThanMd, } from '~/stores/ui'; type RadioListItemProps = { onClick: () => void, icon?: React.ReactNode, text: string, checked?: boolean } const RadioListItem = (props: RadioListItemProps): JSX.Element => { const { onClick, icon, text, checked, } = props; return (
  • {icon}
  • ); }; type SelectorProps = { header: string, onClickBefore: () => void, items: JSX.Element, } const Selector = (props: SelectorProps): JSX.Element => { const { header, onClickBefore, items } = props; return (

    ); }; type EditorThemeToLabel = { [key in EditorTheme]: string; } const EDITORTHEME_LABEL_MAP: EditorThemeToLabel = { defaultlight: 'DefaultLight', eclipse: 'Eclipse', basic: 'Basic', ayu: 'Ayu', rosepine: 'Rosé Pine', defaultdark: 'DefaultDark', material: 'Material', nord: 'Nord', cobalt: 'Cobalt', kimbie: 'Kimbie', }; const ThemeSelector = memo(({ onClickBefore }: {onClickBefore: () => void}): JSX.Element => { const { t } = useTranslation(); const { data: editorSettings, update } = useEditorSettings(); const selectedTheme = editorSettings?.theme ?? DEFAULT_THEME; const listItems = useMemo(() => ( <> { (Object.keys(EDITORTHEME_LABEL_MAP) as EditorTheme[]).map((theme) => { const themeLabel = EDITORTHEME_LABEL_MAP[theme]; return ( update({ theme })} text={themeLabel} checked={theme === selectedTheme} /> ); }) } ), [update, selectedTheme]); return ( ); }); ThemeSelector.displayName = 'ThemeSelector'; type KeyMapModeToLabel = { [key in KeyMapMode]: string; } const KEYMAP_LABEL_MAP: KeyMapModeToLabel = { default: 'Default', vim: 'Vim', emacs: 'Emacs', vscode: 'Visual Studio Code', }; const KeymapSelector = memo(({ onClickBefore }: {onClickBefore: () => void}): JSX.Element => { const { t } = useTranslation(); const { data: editorSettings, update } = useEditorSettings(); const selectedKeymapMode = editorSettings?.keymapMode ?? DEFAULT_KEYMAP; const listItems = useMemo(() => ( <> { (Object.keys(KEYMAP_LABEL_MAP) as KeyMapMode[]).map((keymapMode) => { const keymapLabel = KEYMAP_LABEL_MAP[keymapMode]; const icon = (keymapMode !== 'default') ? {keymapMode} : null; return ( update({ keymapMode })} icon={icon} text={keymapLabel} checked={keymapMode === selectedKeymapMode} /> ); }) } ), [update, selectedKeymapMode]); return ( ); }); KeymapSelector.displayName = 'KeymapSelector'; const TYPICAL_INDENT_SIZE = [2, 4]; const IndentSizeSelector = memo(({ onClickBefore }: {onClickBefore: () => void}): JSX.Element => { const { t } = useTranslation(); const { data: currentIndentSize, mutate: mutateCurrentIndentSize } = useCurrentIndentSize(); const listItems = useMemo(() => ( <> { TYPICAL_INDENT_SIZE.map((indent) => { return ( mutateCurrentIndentSize(indent)} text={indent.toString()} checked={indent === currentIndentSize} /> ); }) } ), [currentIndentSize, mutateCurrentIndentSize]); return ( ); }); IndentSizeSelector.displayName = 'IndentSizeSelector'; const PasteSelector = memo(({ onClickBefore }: {onClickBefore: () => void}): JSX.Element => { const { t } = useTranslation(); const { data: editorSettings, update } = useEditorSettings(); const selectedPasteMode = editorSettings?.pasteMode ?? DEFAULT_PASTE_MODE; const listItems = useMemo(() => ( <> { (AllPasteMode).map((pasteMode) => { return ( update({ pasteMode })} text={t(`page_edit.paste.${pasteMode}`) ?? ''} checked={pasteMode === selectedPasteMode} /> ); }) } ), [update, t, selectedPasteMode]); return ( ); }); PasteSelector.displayName = 'PasteSelector'; type SwitchItemProps = { inputId: string, onChange: () => void, checked: boolean, text: string, }; const SwitchItem = memo((props: SwitchItemProps): JSX.Element => { const { inputId, onChange, checked, text, } = props; return ( ); }); const ConfigurationSelector = memo((): JSX.Element => { const { t } = useTranslation(); const { data: editorSettings, update } = useEditorSettings(); const renderActiveLineMenuItem = useCallback(() => { if (editorSettings == null) { return <>; } const isActive = editorSettings.styleActiveLine; return ( update({ styleActiveLine: !isActive })} checked={isActive} text={t('page_edit.Show active line')} /> ); }, [editorSettings, update, t]); const renderMarkdownTableAutoFormattingMenuItem = useCallback(() => { if (editorSettings == null) { return <>; } const isActive = editorSettings.autoFormatMarkdownTable; return ( update({ autoFormatMarkdownTable: !isActive })} checked={isActive} text={t('page_edit.auto_format_table')} /> ); }, [editorSettings, t, update]); return (
    {renderActiveLineMenuItem()} {renderMarkdownTableAutoFormattingMenuItem()}
    ); }); ConfigurationSelector.displayName = 'ConfigurationSelector'; type ChangeStateButtonProps = { onClick: () => void, header: string, data: string, disabled?: boolean, } const ChangeStateButton = memo((props: ChangeStateButtonProps): JSX.Element => { const { onClick, header, data, disabled, } = props; return ( ); }); const OptionsStatus = { Home: 'Home', Theme: 'Theme', Keymap: 'Keymap', Indent: 'Indent', Paste: 'Paste', } as const; type OptionStatus = typeof OptionsStatus[keyof typeof OptionsStatus]; export const OptionsSelector = (): JSX.Element => { const { t } = useTranslation(); const [dropdownOpen, setDropdownOpen] = useState(false); const [status, setStatus] = useState(OptionsStatus.Home); const { data: editorSettings } = useEditorSettings(); const { data: currentIndentSize } = useCurrentIndentSize(); const { data: isIndentSizeForced } = useIsIndentSizeForced(); const { data: isDeviceLargerThanMd } = useIsDeviceLargerThanMd(); if (editorSettings == null || currentIndentSize == null || isIndentSizeForced == null) { return <>; } return ( { setStatus(OptionsStatus.Home); setDropdownOpen(!dropdownOpen) }} direction="up" className=""> settings { isDeviceLargerThanMd ? : <> } { status === OptionsStatus.Home && (

    setStatus(OptionsStatus.Theme)} header={t('page_edit.theme')} data={EDITORTHEME_LABEL_MAP[editorSettings.theme ?? ''] ?? ''} />
    setStatus(OptionsStatus.Keymap)} header={t('page_edit.keymap')} data={KEYMAP_LABEL_MAP[editorSettings.keymapMode ?? ''] ?? ''} />
    setStatus(OptionsStatus.Indent)} header={t('page_edit.indent')} data={currentIndentSize.toString() ?? ''} />
    setStatus(OptionsStatus.Paste)} header={t('page_edit.paste.title')} data={t(`page_edit.paste.${editorSettings.pasteMode ?? PasteMode.both}`) ?? ''} />
    ) } { status === OptionsStatus.Theme && ( setStatus(OptionsStatus.Home)} /> ) } { status === OptionsStatus.Keymap && ( setStatus(OptionsStatus.Home)} /> ) } { status === OptionsStatus.Indent && ( setStatus(OptionsStatus.Home)} /> ) } { status === OptionsStatus.Paste && ( setStatus(OptionsStatus.Home)} /> )}
    ); };