topbar: make button flyouts modular #639

This commit is contained in:
Sören Weber 2023-09-15 00:23:41 +02:00
parent 4921ec0583
commit 6cd5a93198
No known key found for this signature in database
GPG key ID: BEC6D55545451B6D
9 changed files with 209 additions and 132 deletions

View file

@ -1,5 +1,3 @@
<div class="default-animation progress">
<div class="toc-wrapper">
{{- if eq .Kind "taxonomy" }}
<nav id="TableOfContents">
<ul>
@ -18,6 +16,4 @@
"page" .
"pagefield" "TableOfContents"
) }}
{{- end }}
</div>
</div>
{{- end }}

View file

@ -67,6 +67,7 @@
</head>
<body class="mobile-support {{ $outputFormat }}{{- if .Site.Params.disableInlineCopyToClipBoard }} disableInlineCopyToClipboard{{ end }}{{- if .Site.Params.disableHoverBlockCopyToClipBoard }} disableHoverBlockCopyToClipBoard{{ end }}" data-url="{{ partial "relLangPrettyUglyURL.hugo" (dict "to" .) }}">
<div id="body" class="default-animation">
<div id="body-overlay"></div>
<nav id="topbar">
<div>
<div class="topbar-sidebar-divider"></div>
@ -74,26 +75,24 @@
{{- partial "topbar-button.html" (dict
"page" $page
"class" "topbar-sidebar"
"href" "javascript:showNav()"
"href" "javascript:toggleNav()"
"icon" "bars"
"title" (printf "%s (CTRL+ALT+n)" (T "Navigation-toggle"))
)}}
<div id="sidebar-overlay"></div>
{{- $defaultDisableToc := .Site.Params.disableToc | default false }}
{{- $currentDisableToc := .Params.disableToc | default $defaultDisableToc }}
{{- $toc_content := partial "toc.html" . }}
{{- $hastoc := not (eq 0 (int (len (trim ($toc_content | plainify) "\n\t ")))) }}
{{- $toc_content := partial "toc-class.html" . }}
{{- $hastoc := not (eq 0 (int (len (trim ($toc_content | plainify) "\n\r\t ")))) }}
{{- $toc := and $hastoc (not $currentDisableToc) (eq $outputFormat "html") }}
{{- if $toc }}
{{- partial "topbar-button.html" (dict
"page" $page
"class" "topbar-toc"
"href" "javascript:showToc()"
"href" "javascript:toggleTopbarFlyout(this)"
"icon" "list-alt"
"title" (printf "%s (CTRL+ALT+t)" (T "Toc-toggle"))
"content" $toc_content
)}}
{{ $toc_content }}
<div id="toc-overlay"></div>
{{- end }}
</div>
{{- $showBreadcrumb := (and (not .Params.disableBreadcrumb) (not .Site.Params.disableBreadcrumb)) }}
@ -168,6 +167,7 @@
</div>
</nav>
{{- $hook := "styleclass" }}
<div id="main-overlay"></div>
<main id="body-inner" class="highlightable {{ partialCached "archetype.hugo" (dict "hook" $hook "page" . "parameter" . "outputFormat" $outputFormat) .RelPermalink $outputFormat $hook }}" tabindex="-1">
<div class="flex-block-wrapper">
{{- define "breadcrumb" }}

View file

@ -0,0 +1,3 @@
{{- $toc_content := partial "toc.html" . }}
{{- $toc_content = strings.Replace $toc_content "id=\"TableOfContents\"" "class=\"TableOfContents\"" 1 }}
{{- $toc_content | safeHTML }}

View file

@ -1,5 +1,3 @@
<div class="default-animation progress">
<div class="toc-wrapper">
{{- if eq .Kind "taxonomy" }}
<nav id="TableOfContents">
<ul>
@ -15,6 +13,4 @@
</nav>
{{- else }}
{{- .TableOfContents }}
{{- end }}
</div>
</div>
{{- end }}

View file

@ -22,13 +22,14 @@
{{- if and $icon (not (findRE ".*?\\bfa-\\w.*?" $icon)) }}
{{- $icon = printf "fa-fw fas fa-%s" $icon }}
{{- end }}
{{- $content := .content }}
<div class="topbar-button {{ $class }}">
{{- if $isDisabled }}
<span>
<span class="topbar-button-control">
{{- else if $isButton }}
<button{{ if $href }} onclick="{{ $href | safeJS }}"{{ end }}{{ if gt (len $type) 0 }} type="{{ $type }}"{{ end }} title="{{ $title }}">
<button class="topbar-button-control"{{ if $href }} onclick="{{ $href | safeJS }}"{{ end }}{{ if gt (len $type) 0 }} type="{{ $type }}"{{ end }} title="{{ $title }}">
{{- else }}
<a{{ if $href }} href="{{ $href }}"{{ if gt (len $target) 0 }} target="{{ $target }}"{{ end }}{{ end }} title="{{ $title }}">
<a class="topbar-button-control"{{ if $href }} href="{{ $href }}"{{ if gt (len $target) 0 }} target="{{ $target }}"{{ end }}{{ end }} title="{{ $title }}">
{{- end }}
<i class="{{ $icon }}"></i>
{{- if $isDisabled }}
@ -37,5 +38,12 @@
</button>
{{- else }}
</a>
{{- end }}
{{- if $content }}
<div class="topbar-button-flyout">
<div class="topbar-button-flyout-wrapper">
{{- $content }}
</div>
</div>
{{- end }}
</div>

View file

@ -70,10 +70,10 @@
border-top-right-radius: 0;
border-right-width: 0;
}
.topbar-left .topbar-button > * {
.topbar-left .topbar-button > .topbar-button-control {
border-right: 1px solid rgba( 134, 134, 134, .333 );
}
.topbar-right .topbar-button > * {
.topbar-right .topbar-button > .topbar-button-control {
border-left: 1px solid rgba( 134, 134, 134, .333 );
}
#body .topbar-sidebar-divider {
@ -85,14 +85,9 @@
html[dir="rtl"] .topbar-next i {
transform: scaleX(1);
}
.progress {
.topbar-button-flyout {
left: 1rem;
}
@media screen and (max-width: 48rem) {
.progress {
left: 4.25rem;
}
}
@media screen and (max-width: 60rem) {
#body {
margin-left: 14.375rem;
@ -572,7 +567,7 @@
border-color: rgba( 125, 201, 3, 1 ); /* var(--MENU-HEADER-SEPARATOR-color) */
}
.progress {
.topbar-button-flyout {
background-color: rgba( 255, 255, 255, 1 ); /* var(--MAIN-BG-color) */
}

View file

@ -401,9 +401,9 @@ dd {
.topbar-breadcrumbs a:hover *,
.topbar-breadcrumbs a:active *,
.topbar-breadcrumbs a:focus *,
.toc-wrapper a:hover,
.toc-wrapper a:active,
.toc-wrapper a:focus,
.topbar-button-flyout a:hover,
.topbar-button-flyout a:active,
.topbar-button-flyout a:focus,
article a:hover,
article a:active,
article a:focus {
@ -989,15 +989,15 @@ td {
position: relative;
}
.topbar-button > * {
.topbar-button > .topbar-button-control {
display: inline-block;
padding-left: 1rem;
padding-right: 1rem;
}
.topbar-left .topbar-button > * {
.topbar-left .topbar-button > .topbar-button-control {
border-inline-end: 1px solid rgba( 134, 134, 134, .333 );
}
.topbar-right .topbar-button > * {
.topbar-right .topbar-button > .topbar-button-control {
border-inline-start: 1px solid rgba( 134, 134, 134, .333 );
}
@ -1048,14 +1048,14 @@ html[dir="rtl"] .topbar-next i {
}
}
.progress {
inset-inline-start: 1rem;
top: 1rem;
.topbar-button-flyout {
top: .75rem;
}
@media screen and (max-width: 48rem) {
.progress {
inset-inline-start: 4.25rem;
}
.topbar-left .topbar-button-flyout {
inset-inline-start: 1.5rem;
}
.topbar-right .topbar-button-flyout {
inset-inline-end: 1.5rem;
}
.topbar-breadcrumbs {
@ -1135,7 +1135,7 @@ html[dir="rtl"] .topbar-next i {
margin-inline-start: 14.375rem;
overflow: hidden;
}
.mobile-support.sidebar-flyout #sidebar-overlay{
.mobile-support.sidebar-flyout #body-overlay{
background-color: rgba( 134, 134, 134, .5 );
bottom: 0;
cursor: pointer;
@ -1360,10 +1360,9 @@ html[dir="rtl"] .expand > .expand-label > i.fa-chevron-right {
/* Table of contents */
.toc-flyout #toc-overlay{
.topbar-flyout #main-overlay{
bottom: 0;
cursor: pointer;
height: calc(100vh - 3rem);
left: 0;
position: absolute;
right: 0;
@ -1371,7 +1370,7 @@ html[dir="rtl"] .expand > .expand-label > i.fa-chevron-right {
z-index: 160;
}
.progress {
.topbar-button-flyout {
border: 0 solid rgba( 134, 134, 134, .166 );
box-shadow: 1px 2px 5px 1px rgba( 134, 134, 134, .2 );
height: 0;
@ -1382,33 +1381,48 @@ html[dir="rtl"] .expand > .expand-label > i.fa-chevron-right {
z-index: 180;
}
.toc-flyout .progress {
.topbar-button.topbar-flyout .topbar-button-flyout {
border-width: 1px;
height: auto;
opacity: 1;
width: auto;
}
.progress .toc-wrapper {
.topbar-button-flyout .topbar-button-flyout-wrapper {
background-color: rgba( 134, 134, 134, .066 );
}
.progress ul {
.topbar-button-flyout-wrapper {
--ps-rail-hover-color: rgba( 176, 176, 176, .25 );
max-height: 90vh;
overflow: hidden;
padding: 1rem 1rem;
position: relative; /* PS */
}
#TableOfContents,
.TableOfContents {
font-size: .8125rem;
}
#TableOfContents ul,
.TableOfContents ul {
list-style: none;
margin: 0;
padding: 0 1rem;
}
#TableOfContents {
--ps-rail-hover-color: rgba( 176, 176, 176, .25 );
font-size: .8125rem !important;
max-height: 90vh;
overflow: hidden;
padding: 1rem .375rem !important;
position: relative; /* PS */
#TableOfContents > ul,
.TableOfContents > ul {
padding: 0;
}
#TableOfContents > ul > li > a {
#TableOfContents li,
.TableOfContents li {
white-space: nowrap;
}
#TableOfContents > ul > li > a,
.TableOfContents > ul > li > a {
font-weight: 500;
}

View file

@ -318,7 +318,7 @@ pre .copy-to-clipboard-button:hover {
border-color: var(--INTERNAL-MENU-HEADER-SEPARATOR-color);
}
.progress {
.topbar-button-flyout {
background-color: var(--INTERNAL-MAIN-BG-color);
}

View file

@ -34,7 +34,7 @@ var formelements = 'button, datalist, fieldset, input, label, legend, meter, opt
// PerfectScrollbar
var psc;
var psm;
var pst;
var pst = new Map();
var elc = document.querySelector('#body-inner');
function regexEscape( s ){
@ -709,7 +709,7 @@ function initMenuScrollbar(){
}
var elm = document.querySelector('#content-wrapper');
var elt = document.querySelector('#TableOfContents');
var elt = document.querySelector('.topbar-button.topbar-flyout .topbar-button-flyout-wrapper');
var autofocus = true;
document.addEventListener('keydown', function(event){
@ -737,10 +737,11 @@ function initMenuScrollbar(){
// if we are showing the sidebar as a flyout we
// want to scroll the content-wrapper, otherwise we want
// to scroll the body
var nt = document.querySelector('body').matches('.toc-flyout');
var nt = document.querySelector('body').matches('.topbar-flyout');
var nm = document.querySelector('body').matches('.sidebar-flyout');
if( nt ){
pst && pst.scrollbarY.focus();
var psb = pst.get( document.querySelector('.topbar-button.topbar-flyout') );
psb && psb.scrollbarY.focus();
}
else if( nm ){
psm && psm.scrollbarY.focus();
@ -756,7 +757,15 @@ function initMenuScrollbar(){
// PSC removed for #242 #243 #244
// psc = elc && new PerfectScrollbar('#body-inner');
psm = elm && new PerfectScrollbar('#content-wrapper');
pst = elt && new PerfectScrollbar('#TableOfContents');
document.querySelectorAll('.topbar-button .topbar-button-flyout-wrapper').forEach( function( e ){
var button = getTopbarButtonParent( e );
if( !button ){
return;
}
pst.set( button, new PerfectScrollbar( e ) );
e.addEventListener( 'click', toggleTopbarFlyoutEvent );
});
document.addEventListener('keydown', function(){
// if we facked initial scrolling, we want to
// remove the focus to not leave visual markers on
@ -764,14 +773,18 @@ function initMenuScrollbar(){
if( autofocus ){
psc && psc.scrollbarY.blur();
psm && psm.scrollbarY.blur();
pst && pst.scrollbarY.blur();
pst.forEach( function( psb ){
psb.scrollbarY.blur();
});
autofocus = false;
}
});
// on resize, we have to redraw the scrollbars to let new height
// affect their size
window.addEventListener('resize', function(){
pst && setTimeout( function(){ pst.update(); }, 10 );
pst.forEach( function( psb ){
setTimeout( function(){ psb.update(); }, 10 );
});
psm && setTimeout( function(){ psm.update(); }, 10 );
psc && setTimeout( function(){ psc.update(); }, 10 );
});
@ -784,7 +797,9 @@ function initMenuScrollbar(){
});
// bugfix for PS in RTL mode: the initial scrollbar position is off;
// calling update() once, fixes this
pst && setTimeout( function(){ pst.update(); }, 10 );
pst.forEach( function( psb ){
setTimeout( function(){ psb.update(); }, 10 );
});
psm && setTimeout( function(){ psm.update(); }, 10 );
psc && setTimeout( function(){ psc.update(); }, 10 );
@ -800,27 +815,9 @@ function imageEscapeHandler( event ){
}
}
function sidebarEscapeHandler( event ){
if( event.key == "Escape" ){
var b = document.querySelector( 'body' );
b.classList.remove( 'sidebar-flyout' );
document.removeEventListener( 'keydown', sidebarEscapeHandler );
documentFocus();
}
}
function tocEscapeHandler( event ){
if( event.key == "Escape" ){
var b = document.querySelector( 'body' );
b.classList.remove( 'toc-flyout' );
document.removeEventListener( 'keydown', tocEscapeHandler );
documentFocus();
}
}
function sidebarShortcutHandler( event ){
function navShortcutHandler( event ){
if( !event.shiftKey && event.altKey && event.ctrlKey && !event.metaKey && event.which == 78 /* n */ ){
showNav();
toggleNav();
}
}
@ -832,7 +829,7 @@ function searchShortcutHandler( event ){
function tocShortcutHandler( event ){
if( !event.shiftKey && event.altKey && event.ctrlKey && !event.metaKey && event.which == 84 /* t */ ){
showToc();
toggleToc();
}
}
@ -856,55 +853,127 @@ function showSearch(){
var b = document.querySelector( 'body' );
if( s == document.activeElement ){
if( b.classList.contains( 'sidebar-flyout' ) ){
showNav();
closeNav();
}
documentFocus();
} else {
if( !b.classList.contains( 'sidebar-flyout' ) ){
showNav();
openNav();
}
s.focus();
}
}
function showNav(){
if( !document.querySelector( '#sidebar-overlay' ) ){
// we may not have a flyout
return;
}
function openNav(){
closeSomeTopbarButtonFlyout();
var b = document.querySelector( 'body' );
b.classList.toggle( 'sidebar-flyout' );
if( b.classList.contains( 'sidebar-flyout' ) ){
b.classList.remove( 'toc-flyout' );
document.removeEventListener( 'keydown', tocEscapeHandler );
document.addEventListener( 'keydown', sidebarEscapeHandler );
}
else{
document.removeEventListener( 'keydown', sidebarEscapeHandler );
documentFocus();
b.classList.add( 'sidebar-flyout' );
psm && setTimeout( function(){ psm.update(); }, 10 );
psm && psm.scrollbarY.focus();
var a = document.querySelector( '#sidebar a' )
if( a ){
a.focus();
}
}
function showToc(){
var t = document.querySelector( '.topbar-toc' );
if( !t ){
// we may not have a toc
return;
}
function closeNav(){
var b = document.querySelector( 'body' );
b.classList.toggle( 'toc-flyout' );
if( b.classList.contains( 'toc-flyout' ) ){
pst && setTimeout( function(){ pst.update(); }, 10 );
pst && pst.scrollbarY.focus();
document.querySelector( '.toc-wrapper ul a' ).focus();
document.addEventListener( 'keydown', tocEscapeHandler );
b.classList.remove( 'sidebar-flyout' );
documentFocus();
}
function toggleNav(){
var b = document.querySelector( 'body' );
if( b.classList.contains( 'sidebar-flyout' ) ){
closeNav();
}
else{
document.removeEventListener( 'keydown', tocEscapeHandler );
documentFocus();
openNav();
}
}
function navEscapeHandler( event ){
if( event.key == "Escape" ){
closeNav();
}
}
function getTopbarButtonParent( e ){
var button = e;
while( button && !button.classList.contains( 'topbar-button' ) ){
button = button.parentElement;
}
return button;
}
function openTopbarButtonFlyout( button ){
closeNav();
var body = document.querySelector( 'body' );
button.classList.add( 'topbar-flyout' );
body.classList.add( 'topbar-flyout' );
var psb = pst.get( button );
psb && setTimeout( function(){ psb.update(); }, 10 );
psb && psb.scrollbarY.focus();
var a = button.querySelector( '.topbar-button-flyout-wrapper a' );
if( a ){
a.focus();
}
}
function closeTopbarButtonFlyout( button ){
var body = document.querySelector( 'body' );
button.classList.remove( 'topbar-flyout' );
body.classList.remove( 'topbar-flyout' );
documentFocus();
}
function closeSomeTopbarButtonFlyout(){
var someButton = document.querySelector( '.topbar-button.topbar-flyout' );
if( someButton ){
closeTopbarButtonFlyout( someButton );
};
return someButton
}
function toggleTopbarButtonFlyout( button ){
var someButton = closeSomeTopbarButtonFlyout();
if( button && button != someButton ){
openTopbarButtonFlyout( button );
}
}
function toggleTopbarFlyout( e ){
var button = getTopbarButtonParent( e );
if( !button ){
return;
}
toggleTopbarButtonFlyout( button );
}
function toggleTopbarFlyoutEvent( event ){
if( event.target.classList.contains( 'topbar-button-flyout' )
|| event.target.classList.contains( 'topbar-button-flyout-wrapper' )
|| event.target.classList.contains( 'ps__rail-x' )
|| event.target.classList.contains( 'ps__rail-y' )
|| event.target.classList.contains( 'ps__thumb-x' )
|| event.target.classList.contains( 'ps__thumb-y' )
){
// the scrollbar was used, don't close flyout
return;
}
toggleTopbarFlyout( event.target )
}
function topbarFlyoutEscapeHandler( event ){
if( event.key == "Escape" ){
closeSomeTopbarButtonFlyout();
}
}
function toggleToc(){
toggleTopbarButtonFlyout( document.querySelector( '.topbar-toc' ) );
}
function showEdit(){
var l = document.querySelector( '.topbar-edit a' );
if( l ){
@ -935,21 +1004,20 @@ function initToc(){
}
document.addEventListener( 'keydown', editShortcutHandler );
document.addEventListener( 'keydown', navShortcutHandler );
document.addEventListener( 'keydown', printShortcutHandler );
document.addEventListener( 'keydown', sidebarShortcutHandler );
document.addEventListener( 'keydown', searchShortcutHandler );
document.addEventListener( 'keydown', tocShortcutHandler );
document.addEventListener( 'keydown', navEscapeHandler );
document.addEventListener( 'keydown', topbarFlyoutEscapeHandler );
var s = document.querySelector( '#sidebar-overlay' );
if( s ){
s.addEventListener( 'click', showNav );
var b = document.querySelector( '#body-overlay' );
if( b ){
b.addEventListener( 'click', closeNav );
}
var o = document.querySelector( '#toc-overlay' );
var p = document.querySelector( '.progress' );
if( o && p ){
// we may not have a toc
o.addEventListener( 'click', showToc );
p.addEventListener( 'click', showToc );
var m = document.querySelector( '#main-overlay' );
if( m ){
m.addEventListener( 'click', closeSomeTopbarButtonFlyout );
}
// finally give initial focus to allow keyboard scrolling in FF
@ -980,10 +1048,7 @@ function initSwipeHandler(){
else if( diffx > 30 ){
startx = null;
starty = null;
var b = document.querySelector( 'body' );
b.classList.remove( 'sidebar-flyout' );
document.removeEventListener( 'keydown', sidebarEscapeHandler );
documentFocus();
closeNav();
}
}
return false;
@ -994,7 +1059,7 @@ function initSwipeHandler(){
return false;
};
var s = document.querySelector( '#sidebar-overlay' );
var s = document.querySelector( '#body-overlay' );
s && s.addEventListener("touchstart", handleStartX, false);
document.querySelector( '#sidebar' ).addEventListener("touchstart", handleStartX, false);
document.querySelectorAll( '#sidebar *' ).forEach( function(e){ e.addEventListener("touchstart", handleStartX); }, false);