diff --git a/packages/base-styles/_z-index.scss b/packages/base-styles/_z-index.scss index 96040ec29d07b8..cc4a42df98f0aa 100644 --- a/packages/base-styles/_z-index.scss +++ b/packages/base-styles/_z-index.scss @@ -182,6 +182,7 @@ $z-layers: ( ".customize-widgets__block-toolbar": 7, // Site editor layout + ".edit-site-layout__header-container": 4, ".edit-site-layout__hub": 3, ".edit-site-layout__header": 2, ".edit-site-page-header": 2, diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index 72c3d50372e48e..2c42b42afc4424 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -711,6 +711,7 @@ _Properties_ - _maxWidth_ `number`: Max width to constraint resizing - _allowedBlockTypes_ `boolean|Array`: Allowed block types - _hasFixedToolbar_ `boolean`: Whether or not the editor toolbar is fixed +- _distractionFree_ `boolean`: Whether or not the editor UI is distraction free - _focusMode_ `boolean`: Whether the focus mode is enabled or not - _styles_ `Array`: Editor Styles - _keepCaretInsideBlock_ `boolean`: Whether caret should move between blocks in edit mode diff --git a/packages/block-editor/src/store/defaults.js b/packages/block-editor/src/store/defaults.js index 7c33350d12dd01..acd40244cb2604 100644 --- a/packages/block-editor/src/store/defaults.js +++ b/packages/block-editor/src/store/defaults.js @@ -18,6 +18,7 @@ export const PREFERENCES_DEFAULTS = { * @property {number} maxWidth Max width to constraint resizing * @property {boolean|Array} allowedBlockTypes Allowed block types * @property {boolean} hasFixedToolbar Whether or not the editor toolbar is fixed + * @property {boolean} distractionFree Whether or not the editor UI is distraction free * @property {boolean} focusMode Whether the focus mode is enabled or not * @property {Array} styles Editor Styles * @property {boolean} keepCaretInsideBlock Whether caret should move between blocks in edit mode diff --git a/packages/edit-post/src/components/header/index.js b/packages/edit-post/src/components/header/index.js index dfdeb2d130aa35..3f42d4736f57bb 100644 --- a/packages/edit-post/src/components/header/index.js +++ b/packages/edit-post/src/components/header/index.js @@ -20,6 +20,16 @@ import MainDashboardButton from './main-dashboard-button'; import { store as editPostStore } from '../../store'; import DocumentTitle from './document-title'; +const slideY = { + hidden: { y: '-50px' }, + hover: { y: 0, transition: { type: 'tween', delay: 0.2 } }, +}; + +const slideX = { + hidden: { x: '-100%' }, + hover: { x: 0, transition: { type: 'tween', delay: 0.2 } }, +}; + function Header( { setEntitiesSavedStatesCallback } ) { const isLargeViewport = useViewportMatch( 'large' ); const { @@ -39,16 +49,6 @@ function Header( { setEntitiesSavedStatesCallback } ) { [] ); - const slideY = { - hidden: { y: '-50px' }, - hover: { y: 0, transition: { type: 'tween', delay: 0.2 } }, - }; - - const slideX = { - hidden: { x: '-100%' }, - hover: { x: 0, transition: { type: 'tween', delay: 0.2 } }, - }; - return (
diff --git a/packages/edit-post/src/components/keyboard-shortcuts/index.js b/packages/edit-post/src/components/keyboard-shortcuts/index.js index 432bce0a3bff5c..9a9574fd38bb7e 100644 --- a/packages/edit-post/src/components/keyboard-shortcuts/index.js +++ b/packages/edit-post/src/components/keyboard-shortcuts/index.js @@ -223,8 +223,6 @@ function KeyboardShortcuts() { } ); useShortcut( 'core/edit-post/toggle-distraction-free', () => { - closeGeneralSidebar(); - setIsListViewOpened( false ); toggleDistractionFree(); toggleFeature( 'distractionFree' ); createInfoNotice( diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index 24805014e3d695..238cad73870553 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -180,6 +180,7 @@ export default function Editor( { isLoading } ) { { isEditMode && } { hasDefaultEditorCanvasView && (
- + { ! isDistractionFree && ( + + ) } { isLargeViewport && ( <> - - { isZoomedOutViewExperimentEnabled && ( + { ! isDistractionFree && ( { - setPreviewDeviceType( 'desktop' ); - __unstableSetEditorMode( - isZoomedOutView - ? 'edit' - : 'zoom-out' - ); - } } + label={ __( 'List View' ) } + onClick={ toggleListView } + shortcut={ listViewShortcut } + showTooltip={ ! showIconLabels } + variant={ + showIconLabels + ? 'tertiary' + : undefined + } /> ) } + { isZoomedOutViewExperimentEnabled && + ! isDistractionFree && ( + { + setPreviewDeviceType( + 'desktop' + ); + __unstableSetEditorMode( + isZoomedOutView + ? 'edit' + : 'zoom-out' + ); + } } + /> + ) } ) }
) } -
- { ! hasDefaultEditorCanvasView ? ( - getEditorCanvasContainerTitle( editorCanvasView ) - ) : ( - - ) } -
+ { ! isDistractionFree && ( +
+ { ! hasDefaultEditorCanvasView ? ( + getEditorCanvasContainerTitle( editorCanvasView ) + ) : ( + + ) } +
+ ) }
-
+ { ! isFocusMode && hasDefaultEditorCanvasView && (
) } - + { ! isDistractionFree && ( + + ) } -
+
); diff --git a/packages/edit-site/src/components/header-edit-mode/more-menu/index.js b/packages/edit-site/src/components/header-edit-mode/more-menu/index.js index a7c9ea977db176..802e9f9439811f 100644 --- a/packages/edit-site/src/components/header-edit-mode/more-menu/index.js +++ b/packages/edit-site/src/components/header-edit-mode/more-menu/index.js @@ -3,12 +3,16 @@ */ import { __, _x } from '@wordpress/i18n'; import { useReducer } from '@wordpress/element'; +import { useSelect, useDispatch, useRegistry } from '@wordpress/data'; import { useShortcut } from '@wordpress/keyboard-shortcuts'; import { displayShortcut } from '@wordpress/keycodes'; import { external } from '@wordpress/icons'; import { MenuGroup, MenuItem, VisuallyHidden } from '@wordpress/components'; import { ActionItem, MoreMenuDropdown } from '@wordpress/interface'; -import { PreferenceToggleMenuItem } from '@wordpress/preferences'; +import { + PreferenceToggleMenuItem, + store as preferencesStore, +} from '@wordpress/preferences'; /** * Internal dependencies @@ -20,6 +24,7 @@ import SiteExport from './site-export'; import WelcomeGuideMenuItem from './welcome-guide-menu-item'; import CopyContentMenuItem from './copy-content-menu-item'; import ModeSwitcher from '../mode-switcher'; +import { store as siteEditorStore } from '../../../store'; export default function MoreMenu( { showIconLabels } ) { const [ isModalActive, toggleModal ] = useReducer( @@ -32,6 +37,29 @@ export default function MoreMenu( { showIconLabels } ) { false ); + const registry = useRegistry(); + const isDistractionFree = useSelect( + ( select ) => + select( preferencesStore ).get( + 'core/edit-site', + 'distractionFree' + ), + [] + ); + + const { setIsInserterOpened, setIsListViewOpened, closeGeneralSidebar } = + useDispatch( siteEditorStore ); + const { set: setPreference } = useDispatch( preferencesStore ); + + const toggleDistractionFree = () => { + registry.batch( () => { + setPreference( 'core/edit-site', 'fixedToolbar', false ); + setIsInserterOpened( false ); + setIsListViewOpened( false ); + closeGeneralSidebar(); + } ); + }; + useShortcut( 'core/edit-site/keyboard-shortcuts', toggleModal ); return ( @@ -48,6 +76,7 @@ export default function MoreMenu( { showIconLabels } ) { + { + setPreference( 'core/edit-site', 'fixedToolbar', false ); + setIsInserterOpened( false ); + setIsListViewOpened( false ); + closeGeneralSidebar(); + }; + const handleTextLevelShortcut = ( event, level ) => { event.preventDefault(); const destinationBlockName = @@ -114,6 +133,20 @@ function KeyboardShortcutsEditMode() { ); } ); + useShortcut( 'core/edit-site/toggle-distraction-free', () => { + toggleDistractionFree(); + toggleFeature( 'distractionFree' ); + createInfoNotice( + isFeatureActive( 'distractionFree' ) + ? __( 'Distraction free mode turned on.' ) + : __( 'Distraction free mode turned off.' ), + { + id: 'core/edit-site/distraction-free-mode/notice', + type: 'snackbar', + } + ); + } ); + return null; } diff --git a/packages/edit-site/src/components/keyboard-shortcuts/register.js b/packages/edit-site/src/components/keyboard-shortcuts/register.js index 9660b03e762ed6..8dfd1e3e2a45bf 100644 --- a/packages/edit-site/src/components/keyboard-shortcuts/register.js +++ b/packages/edit-site/src/components/keyboard-shortcuts/register.js @@ -149,6 +149,16 @@ function KeyboardShortcutsRegister() { }, } ); } ); + + registerShortcut( { + name: 'core/edit-site/toggle-distraction-free', + category: 'global', + description: __( 'Toggle distraction free mode.' ), + keyCombination: { + modifier: 'primaryShift', + character: '\\', + }, + } ); }, [ registerShortcut ] ); return null; diff --git a/packages/edit-site/src/components/layout/index.js b/packages/edit-site/src/components/layout/index.js index 60d493192b9a19..3398ec332c7662 100644 --- a/packages/edit-site/src/components/layout/index.js +++ b/packages/edit-site/src/components/layout/index.js @@ -72,24 +72,36 @@ export default function Layout() { const isMobileViewport = useViewportMatch( 'medium', '<' ); const isListPage = getIsListPage( params, isMobileViewport ); const isEditorPage = ! isListPage; - const { hasFixedToolbar, canvasMode, previousShortcut, nextShortcut } = - useSelect( ( select ) => { - const { getAllShortcutKeyCombinations } = select( - keyboardShortcutsStore - ); - const { getCanvasMode } = unlock( select( editSiteStore ) ); - return { - canvasMode: getCanvasMode(), - previousShortcut: getAllShortcutKeyCombinations( - 'core/edit-site/previous-region' - ), - nextShortcut: getAllShortcutKeyCombinations( - 'core/edit-site/next-region' - ), - hasFixedToolbar: - select( preferencesStore ).get( 'fixedToolbar' ), - }; - }, [] ); + + const { + isDistractionFree, + hasFixedToolbar, + canvasMode, + previousShortcut, + nextShortcut, + } = useSelect( ( select ) => { + const { getAllShortcutKeyCombinations } = select( + keyboardShortcutsStore + ); + const { getCanvasMode } = unlock( select( editSiteStore ) ); + return { + canvasMode: getCanvasMode(), + previousShortcut: getAllShortcutKeyCombinations( + 'core/edit-site/previous-region' + ), + nextShortcut: getAllShortcutKeyCombinations( + 'core/edit-site/next-region' + ), + hasFixedToolbar: select( preferencesStore ).get( + 'core/edit-site', + 'fixedToolbar' + ), + isDistractionFree: select( preferencesStore ).get( + 'core/edit-site', + 'distractionFree' + ), + }; + }, [] ); const isEditing = canvasMode === 'edit'; const navigateRegionsProps = useNavigateRegions( { previous: previousShortcut, @@ -110,6 +122,27 @@ export default function Layout() { const [ isResizing ] = useState( false ); const isEditorLoading = useIsSiteEditorLoading(); + // This determines which animation variant should apply to the header. + // There is also a `isDistractionFreeHovering` state that gets priority + // when hovering the `edit-site-layout__header-container` in distraction + // free mode. It's set via framer and trickles down to all the children + // so they can use this variant state too. + // + // TODO: The issue with this is we want to have the hover state stick when hovering + // a popover opened via the header. We'll probably need to lift this state to + // handle it ourselves. Also, focusWithin the header needs to be handled. + let headerAnimationState; + + if ( canvasMode === 'view' ) { + // We need 'view' to always take priority so 'isDistractionFree' + // doesn't bleed over into the view (sidebar) state + headerAnimationState = 'view'; + } else if ( isDistractionFree ) { + headerAnimationState = 'isDistractionFree'; + } else { + headerAnimationState = canvasMode; // edit, view, init + } + // Sets the right context for the command center const commandContext = canvasMode === 'edit' && isEditorPage @@ -140,41 +173,77 @@ export default function Layout() { 'edit-site-layout', navigateRegionsProps.className, { + 'is-distraction-free': isDistractionFree && isEditing, 'is-full-canvas': isFullCanvas, 'is-edit-mode': isEditing, 'has-fixed-toolbar': hasFixedToolbar, } ) } > - - - - { isEditorPage && isEditing && ( - - { isEditing &&
} - - ) } - + delay: 0.8, + delayChildren: 0.8, + }, // How long to wait before the header exits + }, + isDistractionFreeHovering: { + opacity: 1, + transition: { + type: 'tween', + delay: 0.2, + delayChildren: 0.2, + }, // How long to wait before the header shows + }, + view: { opacity: 1 }, + edit: { opacity: 1 }, + } } + whileHover={ + isDistractionFree + ? 'isDistractionFreeHovering' + : undefined + } + animate={ headerAnimationState } + > + + + + { isEditorPage && isEditing && ( + + { isEditing &&
} + + ) } + +
diff --git a/packages/edit-site/src/components/layout/style.scss b/packages/edit-site/src/components/layout/style.scss index 2097154fa94c34..dbccc48100cf6b 100644 --- a/packages/edit-site/src/components/layout/style.scss +++ b/packages/edit-site/src/components/layout/style.scss @@ -36,6 +36,10 @@ } } +.edit-site-layout__header-container { + z-index: z-index(".edit-site-layout__header-container"); +} + .edit-site-layout__header { height: $header-height; display: flex; @@ -249,6 +253,9 @@ // so the fixed toolbar can be positioned on top of it // but only on desktop @include break-medium() { + .edit-site-layout__canvas-container { + z-index: 5; + } .edit-site-site-hub { z-index: 4; } @@ -258,3 +265,42 @@ } } +.is-edit-mode.is-distraction-free { + + .edit-site-layout__header-container { + height: $header-height; + position: absolute; + top: 0; + left: 0; + right: 0; + z-index: z-index(".edit-site-layout__header-container"); + width: 100%; + + // We need ! important because we override inline styles + // set by the motion component. + &:focus-within { + opacity: 1 !important; + div { + transform: translateX(0) translateY(0) translateZ(0) !important; + } + + .edit-site-layout__header { + opacity: 1 !important; + } + } + } + + .edit-site-site-hub, + .edit-site-layout__header { + position: absolute; + top: 0; + z-index: z-index(".edit-site-layout__header"); + } + .edit-site-site-hub { + z-index: z-index(".edit-site-layout__hub"); + } + .edit-site-layout__header { + width: 100%; + } + +} diff --git a/packages/edit-site/src/components/preferences-modal/enable-feature.js b/packages/edit-site/src/components/preferences-modal/enable-feature.js index ca4a8a1bb1a327..9cd2105ba69fff 100644 --- a/packages/edit-site/src/components/preferences-modal/enable-feature.js +++ b/packages/edit-site/src/components/preferences-modal/enable-feature.js @@ -6,14 +6,17 @@ import { ___unstablePreferencesModalBaseOption as BaseOption } from '@wordpress/ import { store as preferencesStore } from '@wordpress/preferences'; export default function EnableFeature( props ) { - const { featureName, ...remainingProps } = props; + const { featureName, onToggle = () => {}, ...remainingProps } = props; const isChecked = useSelect( ( select ) => !! select( preferencesStore ).get( 'core/edit-site', featureName ), [ featureName ] ); const { toggle } = useDispatch( preferencesStore ); - const onChange = () => toggle( 'core/edit-site', featureName ); + const onChange = () => { + onToggle(); + toggle( 'core/edit-site', featureName ); + }; return ( { + registry.batch( () => { + setPreference( 'core/edit-site', 'fixedToolbar', false ); + setIsInserterOpened( false ); + setIsListViewOpened( false ); + closeGeneralSidebar(); + } ); + }; + const sections = useMemo( () => [ { name: 'general', @@ -29,6 +46,14 @@ export default function EditSitePreferencesModal( { 'Customize options related to the block editor interface and editing flow.' ) } > + {}; export function SidebarNavigationItemGlobalStyles( props ) { - const { openGeneralSidebar } = useDispatch( editSiteStore ); + const { openGeneralSidebar, toggleFeature } = useDispatch( editSiteStore ); const { setCanvasMode } = unlock( useDispatch( editSiteStore ) ); + const { createNotice } = useDispatch( noticesStore ); const hasGlobalStyleVariations = useSelect( ( select ) => !! select( @@ -53,9 +55,19 @@ export function SidebarNavigationItemGlobalStyles( props ) { { - // switch to edit mode. + // Disable distraction free mode. + toggleFeature( 'distractionFree', false ); + createNotice( + 'info', + __( 'Distraction free mode turned off' ), + { + isDismissible: true, + type: 'snackbar', + } + ); + // Switch to edit mode. setCanvasMode( 'edit' ); - // open global styles sidebar. + // Open global styles sidebar. openGeneralSidebar( 'edit-site/global-styles' ); } } /> diff --git a/packages/edit-site/src/index.js b/packages/edit-site/src/index.js index e696a441bb10da..a4698c02aff90b 100644 --- a/packages/edit-site/src/index.js +++ b/packages/edit-site/src/index.js @@ -63,6 +63,7 @@ export function initializeEditor( id, settings ) { editorMode: 'visual', fixedToolbar: false, focusMode: false, + distractionFree: false, keepCaretInsideBlock: false, welcomeGuide: true, welcomeGuideStyles: true, diff --git a/packages/edit-site/src/store/selectors.js b/packages/edit-site/src/store/selectors.js index e8dcd03da73416..654b3c321ae93f 100644 --- a/packages/edit-site/src/store/selectors.js +++ b/packages/edit-site/src/store/selectors.js @@ -107,6 +107,10 @@ export const getSettings = createSelector( ...state.settings, outlineMode: true, focusMode: !! __unstableGetPreference( state, 'focusMode' ), + isDistractionFree: !! __unstableGetPreference( + state, + 'distractionFree' + ), hasFixedToolbar: !! __unstableGetPreference( state, 'fixedToolbar' @@ -143,6 +147,7 @@ export const getSettings = createSelector( getCanUserCreateMedia( state ), state.settings, __unstableGetPreference( state, 'focusMode' ), + __unstableGetPreference( state, 'distractionFree' ), __unstableGetPreference( state, 'fixedToolbar' ), __unstableGetPreference( state, 'keepCaretInsideBlock' ), __unstableGetPreference( state, 'showIconLabels' ), diff --git a/packages/edit-site/src/store/test/selectors.js b/packages/edit-site/src/store/test/selectors.js index ac4778f03c7b54..9380f8ea4d276c 100644 --- a/packages/edit-site/src/store/test/selectors.js +++ b/packages/edit-site/src/store/test/selectors.js @@ -77,6 +77,7 @@ describe( 'selectors', () => { outlineMode: true, focusMode: false, hasFixedToolbar: false, + isDistractionFree: false, keepCaretInsideBlock: false, showIconLabels: false, __experimentalSetIsInserterOpened: setInserterOpened, @@ -102,6 +103,7 @@ describe( 'selectors', () => { key: 'value', focusMode: true, hasFixedToolbar: true, + isDistractionFree: false, keepCaretInsideBlock: false, showIconLabels: false, __experimentalSetIsInserterOpened: setInserterOpened, diff --git a/packages/editor/src/components/provider/use-block-editor-settings.js b/packages/editor/src/components/provider/use-block-editor-settings.js index 8a71fb5deca65f..400e6799996ccb 100644 --- a/packages/editor/src/components/provider/use-block-editor-settings.js +++ b/packages/editor/src/components/provider/use-block-editor-settings.js @@ -47,6 +47,7 @@ const BLOCK_EDITOR_SETTINGS = [ 'enableCustomUnits', 'enableOpenverseMediaCategory', 'focusMode', + 'distractionFree', 'fontSizes', 'gradients', 'generateAnchors', diff --git a/packages/interface/src/components/interface-skeleton/index.js b/packages/interface/src/components/interface-skeleton/index.js index 43e4e532e8eab3..baf98d153ed870 100644 --- a/packages/interface/src/components/interface-skeleton/index.js +++ b/packages/interface/src/components/interface-skeleton/index.js @@ -33,6 +33,15 @@ function useHTMLClass( className ) { }, [ className ] ); } +const headerVariants = { + hidden: { opacity: 0 }, + hover: { + opacity: 1, + transition: { type: 'tween', delay: 0.2, delayChildren: 0.2 }, + }, + distractionFreeInactive: { opacity: 1, transition: { delay: 0 } }, +}; + function InterfaceSkeleton( { isDistractionFree, @@ -74,15 +83,6 @@ function InterfaceSkeleton( const mergedLabels = { ...defaultLabels, ...labels }; - const headerVariants = { - hidden: { opacity: 0 }, - hover: { - opacity: 1, - transition: { type: 'tween', delay: 0.2, delayChildren: 0.2 }, - }, - distractionFreeInactive: { opacity: 1, transition: { delay: 0 } }, - }; - return (