Add optional alternative mobile menu style

This commit is contained in:
Tetrakern 2024-01-11 14:18:17 +01:00
parent 7f8b249a99
commit 8f45c06fe2
12 changed files with 158 additions and 56 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -2541,6 +2541,30 @@ function fictioneer_add_layout_customizer_settings( $manager ) {
)
);
$manager->add_setting(
'mobile_menu_style',
array(
'capability' => 'manage_options',
'sanitize_callback' => 'sanitize_text_field',
'default' => 'minimize_to_right'
)
);
$manager->add_control(
'mobile_menu_style',
array(
'type' => 'select',
'priority' => 10,
'section' => 'layout',
'label' => __( 'Mobile Menu Style', 'fictioneer' ),
'description' => __( 'Choose the style of your mobile menu.', 'fictioneer' ),
'choices' => array(
'minimize_to_right' => _x( 'Minimize site to right', 'Customizer mobile menu style option.', 'fictioneer' ),
'left_slide_in' => _x( 'Slide in from left', 'Customizer mobile menu style option.', 'fictioneer' )
),
)
);
$manager->add_setting(
'dark_mode_font_weight',
array(

View File

@ -386,6 +386,11 @@ function fictioneer_add_classes_to_body( $classes ) {
$user = wp_get_current_user();
$includes = [];
// Mobile menu
if ( get_theme_mod( 'mobile_menu_style', 'minimize_to_right' ) === 'minimize_to_right' ) {
$classes[] = 'advanced-mobile-menu';
}
// Roles
if ( $user->ID > 0 && ! get_option( 'fictioneer_enable_public_cache_compatibility' ) ) {
$includes['is-admin'] = fictioneer_is_admin( $user->ID );
@ -426,9 +431,9 @@ if ( ! is_admin() ) {
*
* @since Fictioneer 5.0.0
*
* @param array $classes Current body classes.
* @param string $classes Current body classes separated by whitespace.
*
* @return array The updated body classes.
* @return string The updated body classes.
*/
function fictioneer_add_classes_to_admin_body( $classes ) {

View File

@ -20,9 +20,17 @@
*/
function fictioneer_output_mobile_menu( $args ) {
// Setup
$style = get_theme_mod( 'mobile_menu_style', 'minimize_to_right' );
$classes = [];
if ( $style === 'minimize_to_right' ) {
$classes[] = '_advanced-mobile-menu';
}
// Start HTML ---> ?>
<input id="mobile-menu-toggle" type="checkbox" autocomplete="off" tabindex="-1" hidden>
<div class="mobile-menu">
<div class="mobile-menu <?php echo implode( ' ', $classes ); ?>">
<div class="mobile-menu__top"><?php do_action( 'fictioneer_mobile_menu_top' ); ?></div>
<div class="mobile-menu__center">
<div class="mobile-menu__frame _active" data-frame="main"><?php

View File

@ -1 +1 @@
const fcn_mobileMenuToggle=_$$$("mobile-menu-toggle"),fcn_mobileMenuBottom=_$(".mobile-menu__bottom"),fcn_mobileMenuUser=_$$$("mobile-menu-user-panel"),fcn_mobileMenuNav=_$$$("mobile-navigation");var fcn_mobileMenuNavElements=[];function fcn_toggleMobileMenu(e){const n=_$$$("wpadminbar")?.offsetHeight??0,o=window.scrollY,t=fcn_theSite.scrollTop;e?(fcn_toggleMobileMenuContent(),fcn_theBody.classList.add("mobile-menu-open","scrolling-down"),fcn_theBody.classList.remove("scrolling-up"),fcn_theSite.classList.add("transformed-scroll","transformed-site"),fcn_theSite.scrollTop=o-n,fcn_updateThemeColor()):(fcn_theSite.classList.remove("transformed-site","transformed-scroll"),fcn_theBody.classList.remove("mobile-menu-open"),fcn_updateThemeColor(),fcn_closeMobileFrames(),fcn_openMobileFrame("main"),fcn_theRoot.style.scrollBehavior="auto",window.scroll(0,t+n),fcn_theRoot.style.scrollBehavior="",fcn_mobileMenuToggle.checked=!1,fcn_toggleMobileMenuContent(!1),"function"==typeof fcn_trackProgress&&fcn_trackProgress())}function fcn_toggleMobileMenuContent(e=!0){if(e||!fcn_mobileMenuNav)fcn_mobileMenuNavElements.forEach((e=>{fcn_mobileMenuNav.appendChild(e)})),fcn_mobileMenuNavElements=[];else for(;fcn_mobileMenuNav.firstChild;)fcn_mobileMenuNavElements.push(fcn_mobileMenuNav.removeChild(fcn_mobileMenuNav.firstChild))}function fcn_copyNavIntoMobileMenu(){const e=_$('[data-menu-id="main"]');if(e&&fcn_mobileMenuNav&&!_$("#mobile-navigation > ul")){const n=e.cloneNode(!0);n.id="mobile-menu-navigation",n.classList.remove("main-navigation__list"),n.classList.add("mobile-navigation__list"),n.dataset.menuId="mobile",_$$$("mobile-navigation").appendChild(n)}}function fcn_openMobileFrame(e){fcn_closeMobileFrames(),_$(`.mobile-menu__frame[data-frame="${e}"]`)?.classList.add("_active")}function fcn_closeMobileFrames(){_$$(".mobile-menu__frame._active").forEach((e=>{e.classList.remove("_active")}));const e=_$(".mobile-menu__bookmarks-panel");e&&(e.dataset.editing="false")}function fcn_appendChapterList(){const e=_$$$("mobile-menu-chapters-list");fcn_chapterList&&!e.hasChildNodes()&&e.appendChild(fcn_chapterList.cloneNode(!0))}fcn_copyNavIntoMobileMenu(),fcn_toggleMobileMenuContent(!1),_$$$("mobile-menu-toggle")?.addEventListener("change",(e=>{fcn_toggleMobileMenu(e.currentTarget.checked)})),fcn_theSite.addEventListener("click",(e=>{fcn_theBody.classList.contains("mobile-menu-open")&&(e.preventDefault(),fcn_toggleMobileMenu(!1))})),_$$$("mobile-menu-comment-jump")?.addEventListener("click",(()=>{fcn_toggleMobileMenu(!1),setTimeout((()=>{const e=_$$$("comments");e&&fcn_scrollTo(e)}),200)})),_$$$("mobile-menu-bookmark-jump")?.addEventListener("click",(()=>{fcn_toggleMobileMenu(!1),setTimeout((()=>{const e=_$(`[data-paragraph-id="${fcn_bookmarks.data[_$("article").id]["paragraph-id"]}"]`);e&&fcn_scrollTo(e)}),200)})),_$$(".button-change-lightness").forEach((e=>{e.addEventListener("click",(e=>{fcn_updateDarken(fcn_siteSettings.darken+parseFloat(e.currentTarget.value))}))})),_$$(".mobile-menu__frame-button").forEach((e=>{e.addEventListener("click",(e=>{fcn_openMobileFrame(e.currentTarget.dataset.frameTarget)}))})),_$$(".mobile-menu__back-button").forEach((e=>{e.addEventListener("click",(()=>{fcn_openMobileFrame("main")}))})),_$('.mobile-menu__frame-button[data-frame-target="chapters"]')?.addEventListener("click",(()=>{fcn_appendChapterList()}),{once:!0}),_$$$("micro-menu-label-open-chapter-list")?.addEventListener("click",(()=>{fcn_appendChapterList(),fcn_openMobileFrame("chapters")})),_$$$("button-mobile-menu-toggle-bookmarks-edit")?.addEventListener("click",(e=>{const n=e.currentTarget.closest(".mobile-menu__bookmarks-panel");n.dataset.editing="false"==n.dataset.editing?"true":"false"})),_$('.mobile-menu__frame-button[data-frame-target="bookmarks"]')?.addEventListener("click",(e=>{fcn_setMobileMenuBookmarks()}),{once:!0});
const fcn_mobileMenuToggle=_$$$("mobile-menu-toggle"),fcn_mobileMenuBottom=_$(".mobile-menu__bottom"),fcn_mobileMenuUser=_$$$("mobile-menu-user-panel"),fcn_mobileMenuNav=_$$$("mobile-navigation");function fcn_toggleMobileMenu(e){fcn_copyNavIntoMobileMenu(),_$(".mobile-menu._advanced-mobile-menu")?fcn_toggleAdvancedMobileMenu(e):fcn_toggleSimpleMobileMenu(e)}function fcn_toggleSimpleMobileMenu(e){e?(fcn_theBody.classList.add("mobile-menu-open","scrolling-down"),fcn_theBody.classList.remove("scrolling-up")):(fcn_theBody.classList.remove("mobile-menu-open"),fcn_closeMobileFrames(),fcn_openMobileFrame("main"),fcn_mobileMenuToggle.checked=!1)}function fcn_toggleAdvancedMobileMenu(e){const n=_$$$("wpadminbar")?.offsetHeight??0,o=window.scrollY,t=fcn_theSite.scrollTop;e?(fcn_theBody.classList.add("mobile-menu-open","scrolling-down"),fcn_theBody.classList.remove("scrolling-up"),fcn_theSite.classList.add("transformed-scroll","transformed-site"),fcn_theSite.scrollTop=o-n,fcn_updateThemeColor()):(fcn_theSite.classList.remove("transformed-site","transformed-scroll"),fcn_theBody.classList.remove("mobile-menu-open"),fcn_updateThemeColor(),fcn_closeMobileFrames(),fcn_openMobileFrame("main"),fcn_theRoot.style.scrollBehavior="auto",window.scroll(0,t+n),fcn_theRoot.style.scrollBehavior="",fcn_mobileMenuToggle.checked=!1,"function"==typeof fcn_trackProgress&&fcn_trackProgress())}function fcn_copyNavIntoMobileMenu(){const e=_$('[data-menu-id="main"]');if(e&&fcn_mobileMenuNav&&!_$("#mobile-navigation > ul")){const n=e.cloneNode(!0);n.id="mobile-menu-navigation",n.classList.remove("main-navigation__list"),n.classList.add("mobile-navigation__list"),n.dataset.menuId="mobile",_$$$("mobile-navigation").appendChild(n)}}function fcn_openMobileFrame(e){fcn_closeMobileFrames(),_$(`.mobile-menu__frame[data-frame="${e}"]`)?.classList.add("_active")}function fcn_closeMobileFrames(){_$$(".mobile-menu__frame._active").forEach((e=>{e.classList.remove("_active")}));const e=_$(".mobile-menu__bookmarks-panel");e&&(e.dataset.editing="false")}function fcn_appendChapterList(){const e=_$$$("mobile-menu-chapters-list");fcn_chapterList&&!e.hasChildNodes()&&e.appendChild(fcn_chapterList.cloneNode(!0))}_$$$("mobile-menu-toggle")?.addEventListener("change",(e=>{fcn_toggleMobileMenu(e.currentTarget.checked)})),fcn_theSite.addEventListener("click",(e=>{fcn_theBody.classList.contains("mobile-menu-open")&&(e.preventDefault(),fcn_toggleMobileMenu(!1))})),_$$$("mobile-menu-comment-jump")?.addEventListener("click",(()=>{fcn_toggleMobileMenu(!1),setTimeout((()=>{const e=_$$$("comments");e&&fcn_scrollTo(e)}),200)})),_$$$("mobile-menu-bookmark-jump")?.addEventListener("click",(()=>{fcn_toggleMobileMenu(!1),setTimeout((()=>{const e=_$(`[data-paragraph-id="${fcn_bookmarks.data[_$("article").id]["paragraph-id"]}"]`);e&&fcn_scrollTo(e)}),200)})),_$$(".button-change-lightness").forEach((e=>{e.addEventListener("click",(e=>{fcn_updateDarken(fcn_siteSettings.darken+parseFloat(e.currentTarget.value))}))})),_$$(".mobile-menu__frame-button").forEach((e=>{e.addEventListener("click",(e=>{fcn_openMobileFrame(e.currentTarget.dataset.frameTarget)}))})),_$$(".mobile-menu__back-button").forEach((e=>{e.addEventListener("click",(()=>{fcn_openMobileFrame("main")}))})),_$('.mobile-menu__frame-button[data-frame-target="chapters"]')?.addEventListener("click",(()=>{fcn_appendChapterList()}),{once:!0}),_$$$("micro-menu-label-open-chapter-list")?.addEventListener("click",(()=>{fcn_appendChapterList(),fcn_openMobileFrame("chapters")})),_$$$("button-mobile-menu-toggle-bookmarks-edit")?.addEventListener("click",(e=>{const n=e.currentTarget.closest(".mobile-menu__bookmarks-panel");n.dataset.editing="false"==n.dataset.editing?"true":"false"})),_$('.mobile-menu__frame-button[data-frame-target="bookmarks"]')?.addEventListener("click",(e=>{fcn_setMobileMenuBookmarks()}),{once:!0});

View File

@ -7,16 +7,49 @@ const /** @const {HTMLElement} */ fcn_mobileMenuToggle = _$$$('mobile-menu-toggl
/** @const {HTMLElement} */ fcn_mobileMenuUser = _$$$('mobile-menu-user-panel'),
/** @const {HTMLElement} */ fcn_mobileMenuNav = _$$$('mobile-navigation');
var fcn_mobileMenuNavElements = [];
/**
* Delegate toggling of the mobile menu.
*
* @since 5.8.7
* @param {boolean} isOpened - True or false.
*/
// Clone main navigation into mobile menu
fcn_copyNavIntoMobileMenu();
function fcn_toggleMobileMenu(isOpened) {
// Clone main navigation into mobile menu
fcn_copyNavIntoMobileMenu();
// Remove and store elements until needed
fcn_toggleMobileMenuContent(false);
if (_$('.mobile-menu._advanced-mobile-menu')) {
fcn_toggleAdvancedMobileMenu(isOpened);
} else {
fcn_toggleSimpleMobileMenu(isOpened);
}
}
/**
* Open or close the mobile menu.
* Open or close the simple mobile menu.
*
* @since 5.8.7
* @param {boolean} isOpened - True or false.
*/
function fcn_toggleSimpleMobileMenu(isOpened) {
if (isOpened) {
// Mobile menu was opened
fcn_theBody.classList.add('mobile-menu-open', 'scrolling-down');
fcn_theBody.classList.remove('scrolling-up');
} else {
// Mobile menu was closed
fcn_theBody.classList.remove('mobile-menu-open');
fcn_closeMobileFrames(); // Close all frames
fcn_openMobileFrame('main'); // Reset to main frame
// Reset control checkbox
fcn_mobileMenuToggle.checked = false;
}
}
/**
* Open or close the advanced mobile menu.
*
* @description When the site is transformed, the scroll context is changed as
* well. So the scroll position needs to be corrected by remembering the
@ -26,7 +59,7 @@ fcn_toggleMobileMenuContent(false);
* @param {boolean} isOpened - True or false.
*/
function fcn_toggleMobileMenu(isOpened) {
function fcn_toggleAdvancedMobileMenu(isOpened) {
// Get and preserve values before DOM changes destroy them
const adminBarOffset = _$$$('wpadminbar')?.offsetHeight ?? 0,
windowScrollY = window.scrollY,
@ -34,7 +67,6 @@ function fcn_toggleMobileMenu(isOpened) {
if (isOpened) {
// Mobile menu was opened
fcn_toggleMobileMenuContent();
fcn_theBody.classList.add('mobile-menu-open', 'scrolling-down');
fcn_theBody.classList.remove('scrolling-up');
fcn_theSite.classList.add('transformed-scroll', 'transformed-site');
@ -56,9 +88,6 @@ function fcn_toggleMobileMenu(isOpened) {
// Reset control checkbox
fcn_mobileMenuToggle.checked = false;
// Remove main navigation to save elements
fcn_toggleMobileMenuContent(false);
// Restart progress bar
if (typeof fcn_trackProgress === 'function') {
fcn_trackProgress();
@ -66,33 +95,8 @@ function fcn_toggleMobileMenu(isOpened) {
}
}
/**
* Add/Remove mobile menu elements on demand.
*
* @since 5.4.2
* @param {boolean} add - True or false.
*/
function fcn_toggleMobileMenuContent(add = true) {
// Remove
if (!add && fcn_mobileMenuNav) {
while (fcn_mobileMenuNav.firstChild) {
fcn_mobileMenuNavElements.push(fcn_mobileMenuNav.removeChild(fcn_mobileMenuNav.firstChild));
}
return;
}
// Restore nav elements
fcn_mobileMenuNavElements.forEach(element => {
fcn_mobileMenuNav.appendChild(element);
});
fcn_mobileMenuNavElements = [];
}
// Listen for change of mobile menu toggle checkbox
_$$$('mobile-menu-toggle')?.addEventListener('change', (e) => {
_$$$('mobile-menu-toggle')?.addEventListener('change', e => {
fcn_toggleMobileMenu(e.currentTarget.checked);
});
@ -104,6 +108,12 @@ fcn_theSite.addEventListener('click', e => {
}
});
/**
* Copy and adjust navigation to mobile menu.
*
* @since 5.4.2
*/
function fcn_copyNavIntoMobileMenu() {
const mainMenu = _$('[data-menu-id="main"]');

View File

@ -57,27 +57,68 @@ body:not(.mobile-menu-open) {
}
}
.mobile-menu-open {
overflow: hidden;
#site {
&::before {
content: '';
position: fixed;
inset: 0 100% -128px 0;
z-index: 100000; // Above adminbar
display: block;
background: #000;
opacity: 0;
transition: opacity 0.3s, right 0s;
transition-delay: 0s, 0.3s; // Delay instant movement of overlay until fade is done
}
}
.mobile-menu {
.mobile-menu-open {
:is(.mobile-menu, .mobile-menu.advanced-mobile-menu) {
left: 0;
display: flex;
content-visibility: visible;
opacity: 1;
}
&.advanced-mobile-menu {
overflow: hidden;
@include bp(desktop) {
left: max(50% - var(--site-width) / 2, (min(75vw, #{$max-mobile-menu-width}) / 2));
transform: translate3d(-50%, 0, 0);
}
#wpadminbar {
opacity: 0;
}
#site {
> :is(nav, header, main, footer, div) {
pointer-events: none;
}
}
}
&:not(.advanced-mobile-menu) {
#site {
&::before {
inset: 0 0 -128px;
opacity: 0.5;
transition: opacity 0.3s; // Override transition of overlay position
}
}
}
.mobile-menu-button {
.off {
display: none;
}
> .icon {
width: 0.9em;
}
}
#wpadminbar {
opacity: 0;
pointer-events: none;
}
}
@ -85,12 +126,10 @@ body:not(.mobile-menu-open) {
.mobile-menu {
position: fixed;
top: 0;
left: 0;
left: -100%;
bottom: -128px;
display: none;
content-visibility: hidden;
z-index: 100001; // Above adminbar
flex-direction: column;
justify-content: space-between;
background-color: var(--mobile-menu-background);
font-size: 15px;
line-height: 1.66; // ~ 25px @ 15px
@ -100,6 +139,8 @@ body:not(.mobile-menu-open) {
max-width: min(75vw, #{$max-mobile-menu-width});
overflow: auto;
box-shadow: var(--mobile-menu-site-box-shadow);
opacity: 0;
transition: left 0.3s, opacity 0.3s;
@media (hover: hover) and (pointer: fine) {
scrollbar-width: none; // FF
@ -109,6 +150,17 @@ body:not(.mobile-menu-open) {
}
}
&._advanced-mobile-menu {
top: 0;
left: 0;
display: none;
content-visibility: hidden;
background: var(--mobile-menu-advanced-background);
opacity: 1;
box-shadow: var(--mobile-advanced-menu-site-box-shadow);
transition: none;
}
.icon-menu {
flex-wrap: wrap;
margin: -12px 0 0 -8px;
@ -133,6 +185,7 @@ body:not(.mobile-menu-open) {
}
&__center {
flex-grow: 1;
padding: 0 0 16px;
}

View File

@ -2,7 +2,7 @@
--modal-width: 300px;
position: fixed;
inset: 0;
z-index: 1000;
z-index: 999999;
line-height: 1.3;
contain: content; // Improve performance

View File

@ -228,8 +228,10 @@
--embed-box-shadow: 0 0 2px rgb(0 0 0 / 30%);
// === MOBILE MENU ===========================================================
--mobile-menu-background: var(--e-body);
--mobile-menu-site-box-shadow: inset -5px 0 3px -4px rgb(0 0 0 / 30%);
--mobile-menu-background: var(--e-1);
--mobile-menu-advanced-background: var(--e-body);
--mobile-menu-site-box-shadow: 2px 0 3px rgb(0 0 0 / 30%);
--mobile-advanced-menu-site-box-shadow: inset -5px 0 3px -4px rgb(0 0 0 / 30%);
--mobile-menu-overlay: rgb(0 0 0 / 20%);
--mobile-menu-text-shadow: var(--text-shadow);
--mobile-menu-bookmark-progress-background: rgb(0 0 0 / 40%);