diff --git a/resources/skins.citizen.scripts/skin.js b/resources/skins.citizen.scripts/skin.js index 28ef942d..e5d4748d 100644 --- a/resources/skins.citizen.scripts/skin.js +++ b/resources/skins.citizen.scripts/skin.js @@ -119,24 +119,6 @@ function main( window ) { bind(); bindCloseOnUnload(); - // Handle ToC - // TODO: There must be a cleaner way to do this - const tocContainer = document.getElementById( 'mw-panel-toc' ); - - if ( tocContainer ) { - const toc = require( './tableOfContents.js' ); - toc.init(); - - /* - checkboxHack.bind( - window, - document.getElementById( 'toctogglecheckbox' ), - tocContainer.querySelector( '.toctogglelabel' ), - tocContainer.querySelector( 'ul' ) - ); - */ - } - mw.loader.load( 'skins.citizen.preferences' ); // Set up loading indicator diff --git a/resources/skins.citizen.styles/Header.less b/resources/skins.citizen.styles/Header.less index 6f624215..39589fe0 100644 --- a/resources/skins.citizen.styles/Header.less +++ b/resources/skins.citizen.styles/Header.less @@ -2,9 +2,6 @@ --header-icon-size: ~'calc( var( --header-button-size ) / 2 )'; --header-button-size: ~'calc( var( --header-size ) - var( --space-sm ) * 2 )'; --header-direction: row; - // Browser UI can be unpredicatable - // And this leaves some empty space for dismissing the dialog - --header-card-maxheight: 70vh; position: fixed; z-index: @z-index-site-header; right: 0; @@ -153,7 +150,6 @@ @media ( min-width: @width-breakpoint-desktop ) { .citizen-header { --header-direction: column; - --header-card-maxheight: ~'calc( 100vh - var( --space-sm ) * 2 )'; top: 0; right: unset; left: 0; diff --git a/resources/skins.citizen.styles/TableOfContents.less b/resources/skins.citizen.styles/TableOfContents.less index 994b17b7..1bc3ca53 100644 --- a/resources/skins.citizen.styles/TableOfContents.less +++ b/resources/skins.citizen.styles/TableOfContents.less @@ -61,8 +61,10 @@ &.citizen-toc__top { height: 0; + padding-top: 0; + padding-bottom: 0; opacity: 0; - transition: @transition-opacity, @transition-height; + transition: @transition-opacity, @transition-height, padding @transition-timing-slow ease; visibility: hidden; } @@ -109,6 +111,8 @@ .citizen-body-header--sticky { .citizen-toc__top.citizen-toc__link { height: 1.05rem; // ( 1rem text + 1rem padding ) * line height / 2 + padding-top: var( --space-sm ); + padding-bottom: var( --space-sm ); opacity: 1; visibility: visible; } @@ -120,6 +124,84 @@ } } +@media ( max-width: ( @width-breakpoint-desktop - 1px ) ) { + .citizen-toc { + position: fixed; + right: 0; + bottom: ~'calc( var( --header-size ) + var( --space-sm ) )'; + + &__card { + overflow: auto; + // This is not bulletproof since it will get covered by page header + // in extremely short height. but it should be good for now + max-height: ~'calc( var( --header-card-maxheight ) - 8rem )'; + padding: var( --space-md ); + margin: var( --space-sm ); + overscroll-behavior: contain; + user-select: none; + .citizen-card; + .citizen-card-hide( bottom right, '', false ); + } + } + + #citizen-toc { + &__checkbox:checked { + ~ .citizen-toc__card { + .citizen-card-show( false ); + } + + ~ #citizen-toc__buttonCheckbox { + box-shadow: none; + } + } + + &__buttonCheckbox { + position: absolute; + right: 0; + bottom: 0; + width: 2.5rem; + height: 2.5rem; + border-radius: var( --border-radius--medium ); + margin: var( --space-sm ); + background-color: var( --color-surface-1 ); + box-shadow: var( --box-shadow-dialog ); + + &:after { + display: block; + width: inherit; + height: inherit; + background-position: center; + background-repeat: no-repeat; + background-size: 1rem; + content: ''; + opacity: var( --opacity-icon-base ); + } + + // The hover state colors are not great but it will do for now + &:hover { + background-color: var( --color-surface-3 ); + } + + &:active { + background-color: var( --color-surface-1 ); + } + } + } + + // Wait for first paint before animating + .citizen-animations-ready { + .citizen-toc__card { + .citizen-card-transition(); + } + } + + .skin-citizen-dark { + #citizen-toc__buttonCheckbox:after { + filter: invert( 1 ); + } + } +} + @media ( min-width: @width-breakpoint-desktop ) { .citizen-toc { grid-area: toc; diff --git a/resources/skins.citizen.styles/common/cssvariables.less b/resources/skins.citizen.styles/common/cssvariables.less index 4d981c9a..612f6ec7 100644 --- a/resources/skins.citizen.styles/common/cssvariables.less +++ b/resources/skins.citizen.styles/common/cssvariables.less @@ -72,6 +72,7 @@ html { /* Size */ --header-size: @header-size; + --header-card-maxheight: 70vh; --width-layout: @width-layout; --width-layout--extended: ~'calc( var( --width-layout ) * 1.5 )'; --width-toc: @width-toc; @@ -132,3 +133,9 @@ html { --border-color-input: @dark-border-color-input; --border-color-input--hover: @dark-border-color-input--hover; } + +@media ( min-width: @width-breakpoint-desktop ) { + html { + --header-card-maxheight: ~'calc( 100vh - var( --space-sm ) * 2 )'; + } +} diff --git a/skin.json b/skin.json index 72bc397a..98d7e138 100644 --- a/skin.json +++ b/skin.json @@ -277,13 +277,13 @@ "defaultColor": "#000", "images": { ".citizen-toc__top:before": "resources/skins.citizen.icons/backToTop.svg", - ".toctogglelabel:before": { + "#citizen-toc__buttonCheckbox:after": { "file": { "ltr": "resources/skins.citizen.icons/toc-ltr.svg", "rtl": "resources/skins.citizen.icons/toc-rtl.svg" } }, - ".toctogglecheckbox:checked ~ .toctitle .toctogglelabel:before": "resources/skins.citizen.icons/shared/close.svg", + "#citizen-toc__checkbox:checked ~ #citizen-toc__buttonCheckbox:after": "resources/skins.citizen.icons/shared/close.svg", "#citizen-userMenu__buttonCheckbox:after": "resources/skins.citizen.icons/shared/userAvatar.svg", ".citizen-search__icon:after": "resources/skins.citizen.icons/shared/search.svg", ".citizen-search__random:after": "resources/skins.citizen.icons/shared/random.svg", diff --git a/templates/TableOfContents.mustache b/templates/TableOfContents.mustache index b8cf7ada..59c84212 100644 --- a/templates/TableOfContents.mustache +++ b/templates/TableOfContents.mustache @@ -1,5 +1,5 @@ {{#data-toc}} -