set classes dynamically

* `sticky` on #header when scrolled
* `sectioned` on html for sectioned editor
This commit is contained in:
tophf 2022-02-13 07:56:55 +03:00
parent aad4828e4a
commit d25ef97205
4 changed files with 65 additions and 31 deletions

View File

@ -1,4 +1,4 @@
/* global $ $$ $create setupLivePrefs waitForSelector */// dom.js
/* global $ $$ $create $root setupLivePrefs waitForSelector */// dom.js
/* global API */// msg.js
/* global CODEMIRROR_THEMES */
/* global CodeMirror */
@ -32,7 +32,7 @@ const editor = {
cancel: () => location.assign('/manage.html'),
updateClass() {
document.documentElement.classList.toggle('is-new-style', !editor.style.id);
$root.classList.toggle('is-new-style', !editor.style.id);
},
updateTitle(isDirty = editor.dirty.isDirty()) {
@ -49,16 +49,14 @@ const editor = {
const baseInit = (() => {
const domReady = waitForSelector('#sections');
const mq = matchMedia('(max-width: 850px)');
(mq.onchange = e => {
document.documentElement.classList.toggle('compact-layout', e.matches);
for (const el of $$('details[data-pref]')) {
el.open = e.matches ? false : prefs.get(el.dataset.pref);
}
})(mq);
const mqCompact = matchMedia('(max-width: 850px)');
const toggleCompact = mq => $root.classList.toggle('compact-layout', mq.matches);
mqCompact.on('change', toggleCompact);
toggleCompact(mqCompact);
return {
domReady,
mqCompact,
ready: Promise.all([
domReady,
loadStyle(),
@ -94,7 +92,7 @@ const baseInit = (() => {
editor.style = style;
editor.updateClass();
editor.updateTitle(false);
document.documentElement.classList.toggle('usercss', editor.isUsercss);
$root.classList.add(editor.isUsercss ? 'usercss' : 'sectioned');
sessionStore.justEditedStyleId = style.id || '';
// no such style so let's clear the invalid URL parameters
if (!style.id) history.replaceState({}, '', location.pathname);

View File

@ -379,11 +379,11 @@ input:invalid {
box-shadow: none !important;
pointer-events: auto !important; /* FF bug */
}
.section-editor .section {
.sectioned .section {
margin: 0 0.7rem;
padding: 1rem;
}
.section-editor .section:not(:first-child) {
.sectioned .section:not(:first-child) {
border-top: 2px solid hsl(0, 0%, 80%);
}
.add-section:after {
@ -419,10 +419,10 @@ input:invalid {
content: counter(codebox) ": " attr(data-text);
margin-left: 0.25rem;
}
.single-editor .applies-to {
.usercss .applies-to {
border-width: 1px 0;
}
.single-editor .applies-to > label::before {
.usercss .applies-to > label::before {
content: attr(data-index) ":";
margin-right: 0.25rem;
font-size: 12px;
@ -586,7 +586,7 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high
padding: 0;
line-height: var(--input-height);
}
.section-editor .applies-to label {
.sectioned .applies-to label {
margin-left: -24px;
position: absolute;
}
@ -948,7 +948,7 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high
box-shadow: none;
}
html:not(.usercss) .usercss-only,
.sectioned .usercss-only,
.usercss .sectioned-only {
display: none !important; /* hide during page init */
}
@ -1020,28 +1020,40 @@ html:not(.usercss) .usercss-only,
/************ reponsive layouts ************/
@media(max-width: 850px) {
html:not(.usercss) body {
.sectioned body {
height: 100%;
}
.usercss body {
display: flex;
flex-direction: column;
}
.usercss #header {
position: inherit;
.usercss #header,
#header:not(.sticky) {
position: static;
}
#header {
display: block;
flex: 0 0 auto;
height: unset;
width: unset;
position: sticky;
width: 100%;
background: #fff;
border-right: none;
border-bottom: 1px dashed #AAA;
padding: var(--pad05) var(--pad05) 0;
}
#header.sticky {
box-shadow: 0 0 3rem -.75rem black;
}
#header.sticky #basic-info,
#header.sticky #mozilla-format-buttons,
#header.sticky .buttons > button,
#heading,
#header-sticker {
top: 0;
height: 1px;
position: absolute;
visibility: hidden;
}
h2 {
display: none;
}
@ -1092,7 +1104,6 @@ html:not(.usercss) .usercss-only,
#sections {
padding-left: 0;
}
/* TODO: switch from .single-editor to the global .usercss */
#sections > :not(.single-editor) {
margin: 0 .5rem;
padding: .5rem 0;

View File

@ -25,11 +25,7 @@ baseInit.ready.then(async () => {
await editor.ready;
editor.ready = true;
editor.dirty.onChange(editor.updateDirty);
prefs.subscribe('editor.linter', (key, value) => {
document.body.classList.toggle('linter-disabled', value === '');
linterMan.run();
});
prefs.subscribe('editor.linter', () => linterMan.run());
// enabling after init to prevent flash of validation failure on an empty name
$('#name').required = !editor.isUsercss;
@ -74,6 +70,34 @@ baseInit.ready.then(async () => {
'/edit/drafts',
'/edit/global-search',
]);
}).then(() => {
// Set up mini-header on scroll
const {isUsercss} = editor;
const el = $create('#header-sticker');
const scroller = isUsercss ? $('.CodeMirror-scroll') : document.body;
const xo = new IntersectionObserver(onScrolled, {root: isUsercss ? scroller : document});
scroller.appendChild(el);
onCompactToggled(baseInit.mqCompact);
baseInit.mqCompact.on('change', onCompactToggled);
/** @param {MediaQueryList} mq */
function onCompactToggled(mq) {
for (const el of $$('details[data-pref]')) {
el.open = mq.matches ? false : prefs.get(el.dataset.pref);
}
if (mq.matches) {
xo.observe(el);
} else {
xo.disconnect();
}
}
/** @param {IntersectionObserverEntry[]} entries */
function onScrolled([e]) {
const h = $('#header');
const sticky = !e.isIntersecting;
if (!isUsercss) scroller.style.paddingTop = sticky ? h.offsetHeight + 'px' : '';
h.classList.toggle('sticky', sticky);
}
});
//#endregion

View File

@ -27,6 +27,8 @@ Object.assign(EventTarget.prototype, {
//#region Exports
const $root = document.documentElement;
// Makes the focus outline appear on keyboard tabbing, but not on mouse clicks.
const focusAccessibility = {
// last event's focusedViaClick
@ -474,10 +476,9 @@ const dom = {};
const lazyScripts = [
'/js/dom-on-load',
];
const elHtml = document.documentElement;
if (!UA.windows) elHtml.classList.add('non-windows');
if (!UA.windows) $root.classList.add('non-windows');
// set language for a) CSS :lang pseudo and b) hyphenation
elHtml.setAttribute('lang', chrome.i18n.getUILanguage());
$root.setAttribute('lang', chrome.i18n.getUILanguage());
// set up header width resizer
const HW = 'headerWidth.';
const HWprefId = HW + location.pathname.match(/^.(\w*)/)[1];
@ -489,7 +490,7 @@ const dom = {};
// If this is a small window on a big monitor the user can maximize it later
const max = (innerWidth < 850 ? screen.availWidth : innerWidth) / 3;
width = Math.round(Math.max(200, Math.min(max, Number(width) || 0)));
elHtml.style.setProperty('--header-width', width + 'px');
$root.style.setProperty('--header-width', width + 'px');
return width;
},
});