refactor(core): ♻️ pre-work to allow Citizen to render ToC

This commit is contained in:
alistair3149 2022-10-06 13:45:23 -04:00
parent 5c962ca22f
commit 3eaeaa15f7
No known key found for this signature in database
11 changed files with 38 additions and 301 deletions

View file

@ -165,6 +165,9 @@ class SkinCitizen extends SkinMustache {
// Add theme handler
$skinTheme->setSkinTheme( $options );
// Disable default ToC since it is handled by Citizen
$options['toc'] = false;
// Collapsible sections
// Load in content pages
if ( $title !== null && $title->isContentPage() ) {
@ -176,9 +179,6 @@ class SkinCitizen extends SkinMustache {
}
}
// Table of content highlight
$options['styles'][] = 'skins.citizen.styles.toc';
// CJK fonts
if ( $this->getConfigValue( 'CitizenEnableCJKFonts' ) === true ) {
$options['styles'][] = 'skins.citizen.styles.fonts.cjk';

View file

@ -121,18 +121,20 @@ function main( window ) {
// Handle ToC
// TODO: There must be a cleaner way to do this
const tocContainer = document.getElementById( 'toc' );
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' );

View file

@ -1,4 +1,4 @@
const ACTIVE_SECTION_CLASS = 'toc__item--active';
const ACTIVE_SECTION_CLASS = 'citizen-toc__listItem--active';
let /** @type {HTMLElement | undefined} */ activeSection;
@ -6,7 +6,7 @@ let /** @type {HTMLElement | undefined} */ activeSection;
* @param {string} id
*/
function changeActiveSection( id ) {
const toc = document.getElementById( 'toc' );
const toc = document.getElementById( 'mw-panel-toc' );
const getLink = ( hash ) => {
const

View file

@ -1,269 +0,0 @@
@import '../variables.less';
@import '../mixins.less';
@media screen {
html {
// Make ToC width accessible as CSS var
--width-toc: @width-toc;
}
.toc {
position: fixed;
top: 3rem;
right: var( --space-sm );
width: 100%;
max-width: ~'calc( var( --width-toc ) - var( --space-sm ) * 2 )';
color: var( --color-base--subtle );
font-size: 0.875rem;
&::-webkit-scrollbar {
width: 0; // Hide bar on toc
}
&title {
h2 {
margin: 0;
color: var( --color-base--subtle );
font-size: inherit;
font-weight: normal;
letter-spacing: 0.75px;
}
}
&toggle {
&span {
display: none;
}
&checkbox:checked ~ ul {
display: block !important; // Force display
}
}
li {
border-left: 2px solid var( --border-color-base--darker );
&.toclevel-2,
&.toclevel-3,
&.toclevel-4,
&.toclevel-5,
&.toclevel-6 {
margin-left: 0.75rem;
}
}
.toc__item--active {
border-color: var( --color-primary );
color: var( --color-primary );
> a,
> a:hover,
> a:active {
color: inherit;
}
}
a {
display: block;
padding: 0.25rem 0 0.25rem 0.75rem;
color: var( --color-base );
&:hover {
color: var( --color-primary--hover );
}
&:active {
color: var( --color-primary--active );
}
}
&number {
display: none;
margin-right: 0.25rem;
opacity: 0.7;
}
&text {
font-weight: 500;
}
ul {
list-style: none;
}
> ul {
position: relative;
z-index: 2;
display: block;
overflow: visible auto;
max-height: ~'calc( 100vh - 10rem )'; // Somehow it works
padding-right: 0.75rem;
margin: 0.6rem 0 0 0;
font-weight: 450;
overscroll-behavior: contain;
ul {
margin: 0;
}
}
}
@media ( max-width: @width-breakpoint-desktop-wide ) {
.toc {
z-index: @z-index-page-header + 1;
pointer-events: none;
&toggle {
&span {
display: block;
font-size: 0;
}
&label {
--label-position: ~'calc( var( --width-toc ) - var( --space-sm ) )';
position: fixed;
right: var( --label-position );
width: 2.5rem;
height: 2.5rem;
border-bottom-left-radius: var( --border-radius--medium );
border-top-left-radius: var( --border-radius--medium );
cursor: pointer;
pointer-events: auto;
.citizen-card( false );
&:hover {
background-color: var( --color-surface-3 );
&:before {
opacity: var( --opacity-icon-base--hover );
}
}
&:active {
background-color: var( --color-surface-1 );
&:before {
opacity: var( --opacity-icon-base--active );
}
}
&:before {
.resource-loader-icon;
display: block;
background-size: 1rem;
opacity: var( --opacity-icon-base );
}
}
// By default .toccheckbox is checked on page load
// This is needed to prevent ToC popping up on mobile
&checkbox:not( :checked ) {
~ .toctitle .toctogglelabel {
transform: translateX( ~'var( --label-position )' );
}
~ .toctitle h2,
~ ul {
transform: translateX( 120% );
}
}
}
&title h2 {
position: absolute;
z-index: 3;
width: ~'calc( 100% - var( --space-md ) * 2 )';
padding: 1rem var( --space-md );
&:before {
position: absolute;
z-index: -1;
top: 0;
right: 0;
left: 0;
height: 100%;
border-radius: var( --border-radius--medium );
background: var( --color-surface-1 );
content: '';
-webkit-mask-image: linear-gradient( 180deg, #000, transparent );
mask-image: linear-gradient( 180deg, #000, transparent );
}
}
> ul {
display: block !important; // So that animation is visible
max-height: ~'calc( 100vh - var( --header-size ) * 3 )';
padding: 2.6rem var( --space-md ) 1rem var( --space-md ); // hardcoded for now
border-radius: 0 var( --border-radius--medium ) var( --border-radius--medium ) var( --border-radius--medium );
margin-top: 0;
pointer-events: auto;
.citizen-card( false );
}
&togglelabel,
&title h2,
> ul {
transition: @transition-opacity;
}
}
.citizen-animations-ready {
.toc {
&togglelabel,
&title h2,
> ul {
transition: @transition-transform, @transition-opacity;
}
}
}
.skin-citizen-dark {
.toc {
&togglelabel {
&:before {
filter: invert( 1 );
}
}
}
}
}
@media ( max-width: @width-breakpoint-tablet ) {
.toc {
right: var( --space-sm );
> ul {
max-height: 60vh;
}
}
}
@media ( max-width: @width-breakpoint-mobile ) {
.toc {
max-width: ~'calc(100vw - var( --space-sm ) * 2)';
}
}
@media ( min-width: @width-breakpoint-desktop-wide ) {
.citizen-toc-enabled {
.mw-body-header,
.citizen-body,
.mw-body-footer {
// Reserve space for ToC
padding-right: var( --width-toc );
}
}
.citizen-animations-ready {
.toc {
transition: @transition-transform;
}
}
.citizen-body-header--sticky {
.toc {
transform: translateY( 3rem );
}
}
}
}

View file

@ -84,13 +84,5 @@
transform: translateX( var( --width-toc ) );
}
}
.toc {
transform: translateY( 3rem );
@media ( max-height: 800px ) {
transform: translateY( 2rem ) !important; // Somehow need this idk why
}
}
}
}

View file

@ -30,7 +30,8 @@
@import 'Catlinks.less';
@import 'ContentFooter.less';
@import 'Footer.less';
@import 'Stickyheader.less';
@import 'TableOfContents.less';
@import 'StickyHeader.less';
}
@media print {

View file

@ -44,7 +44,8 @@
"citizen-search-toggle",
"randompage",
"search",
"sitetitle"
"sitetitle",
"toc"
]
}
]
@ -171,22 +172,6 @@
"resources/skins.citizen.styles.sitestats/skins.citizen.styles.sitestats.less"
]
},
"skins.citizen.styles.toc": {
"class": "ResourceLoaderSkinModule",
"targets": [
"desktop",
"mobile"
],
"features": {
"content-parser-output": false,
"content-body": false,
"logo": false,
"toc": false
},
"styles": [
"resources/skins.citizen.styles.toc/skins.citizen.styles.toc.less"
]
},
"skins.citizen.scripts": {
"packageFiles": [
"resources/skins.citizen.scripts/skin.js",

View file

@ -0,0 +1,10 @@
{{#data-toc}}
<nav id="mw-panel-toc" class="citizen-toc" role="navigation" aria-labelledby="mw-panel-toc-label">
<div id="mw-panel-toc-label" class="citizen-toc__header">{{msg-toc}}</div>
<ul class="citizen-toc__contents" id="mw-panel-toc-list">
{{#array-sections}}
{{>TableOfContents__line}}
{{/array-sections}}
</ul>
</nav>
{{/data-toc}}

View file

@ -0,0 +1,15 @@
<li id="toc-{{anchor}}"
class="citizen-toc__listItem citizen-toc-level--{{toclevel}}">
<a class="citizen-toc__link" href="#{{linkAnchor}}{{^linkAnchor}}{{anchor}}{{/linkAnchor}}">
<div class="citizen-toc__text">
<span class="citizen-toc__numb">{{number}}</span>{{{line}}}</div>
</a>
{{#html-summary}}
{{{.}}}
{{/html-summary}}
<ul id="toc-{{anchor}}-sublist" class="citizen-toc__list">
{{#array-sections}}
{{>TableOfContents__line}}
{{/array-sections}}
</ul>
</li>

View file

@ -21,6 +21,7 @@
{{{html-user-message}}}
{{{html-body-content--formatted}}}
</div>
{{#toc-enabled}}{{>TableOfContents}}{{/toc-enabled}}
{{>ContentFooter}}
</main>
{{{html-after-content}}}