scrollable details + sticky header

This commit is contained in:
tophf 2022-02-04 05:28:05 +03:00
parent 2e021f6ac9
commit e11c4ef755
7 changed files with 125 additions and 232 deletions

View File

@ -418,17 +418,15 @@
<summary><h2 i18n-text="sections"></h2></summary>
<ol id="toc"></ol>
</details>
<details id="lint" data-pref="editor.lint.expanded" class="hidden-unless-compact ignore-pref-if-compact">
<details id="lint" data-pref="editor.lint.expanded" class="ignore-pref-if-compact" hidden>
<summary>
<h2 i18n-text="linterIssues">: <span id="issue-count"></span>
<h2><span i18n-text="linterIssues"></span><span id="issue-count"></span>
<a id="lint-help" class="svg-inline-wrapper intercepts-click" tabindex="0">
<svg class="svg-icon info"><use xlink:href="#svg-icon-help"/></svg>
</a>
</h2>
</summary>
<div class="lint-scroll-container">
<div class="lint-report-container"></div>
</div>
<div class="lint-report-container"></div>
</details>
</div>
<div id="header-resizer" i18n-title="headerResizerHint"></div>

View File

@ -6,14 +6,7 @@
/* global initBeautifyButton */// beautify.js
/* global prefs */
/* global t */// localization.js
/* global
FIREFOX
debounce
getOwnTab
sessionStore
tryJSONparse
tryURL
*/// toolbox.js
/* global FIREFOX getOwnTab sessionStore tryJSONparse tryURL */// toolbox.js
'use strict';
/**
@ -56,6 +49,13 @@ 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);
return {
domReady,
@ -120,45 +120,6 @@ const baseInit = (() => {
}
})();
//#endregion
//#region init layout/resize
baseInit.domReady.then(() => {
let headerHeight;
detectLayout(true);
window.on('resize', () => detectLayout());
function detectLayout(now) {
const compact = window.innerWidth <= 850;
if (compact) {
document.body.classList.add('compact-layout');
if (!editor.isUsercss) {
if (now) fixedHeader();
else debounce(fixedHeader, 250);
window.on('scroll', fixedHeader, {passive: true});
}
} else {
document.body.classList.remove('compact-layout', 'fixed-header');
window.off('scroll', fixedHeader);
}
for (const el of $$('details[data-pref]')) {
el.open = compact ? false : prefs.get(el.dataset.pref);
}
}
function fixedHeader() {
const headerFixed = $('.fixed-header');
if (!headerFixed) headerHeight = $('#header').clientHeight;
const scrollPoint = headerHeight - 43;
if (window.scrollY >= scrollPoint && !headerFixed) {
$('body').style.setProperty('--fixed-padding', ` ${headerHeight}px`);
$('body').classList.add('fixed-header');
} else if (window.scrollY < scrollPoint && headerFixed) {
$('body').classList.remove('fixed-header');
}
}
});
//#endregion
//#region init header

View File

@ -1,5 +1,6 @@
:root {
--fixed-padding: unset;
--pad: 1rem;
--pad05: calc(0.5 * var(--pad));
}
body {
@ -70,7 +71,7 @@ html:not(.is-new-style) #heading::after {
#popup-button:hover {
filter: drop-shadow(0 0 3px hsl(180, 70%, 50%));
}
.usercss body:not(.compact-layout) #popup-button {
.usercss:not(.compact-layout) #popup-button {
right: 24px;
}
/************ checkbox & select************/
@ -91,10 +92,10 @@ label {
#header {
width: var(--header-width);
height: 100vh;
overflow: auto;
overflow: hidden;
position: fixed;
top: 0;
padding: 1rem;
padding-top: var(--pad);
box-shadow: 0 0 3rem -1.2rem black;
box-sizing: border-box;
z-index: 10;
@ -222,56 +223,61 @@ input:invalid {
margin-left: 0;
}
/* collapsibles */
#header details {
margin-right: var(--header-resizer-width);
}
#header details[open] {
overflow-y: auto;
margin-top: calc(1.5*var(--pad));
}
#header details[open] summary {
position: absolute;
margin-top: calc(-1.5*var(--pad));
}
#header summary {
align-items: center;
margin-left: -13px;
margin-left: .25em;
cursor: pointer;
}
#header summary + * {
padding: .5rem 0;
white-space: nowrap;
}
#header summary h2 {
display: inline-block;
border-bottom: 1px dotted transparent;
margin-top: .1em;
margin-bottom: .1em;
margin-left: -13px;
margin: 0 0 0 -13px;
padding-left: 13px; /* clicking directly on details-marker doesn't set pref so we cover it with h2 */
max-width: calc(var(--header-width) - 2*var(--pad));
vertical-align: middle;
}
#header summary h2,
#header summary h2 > :first-child {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#header summary:hover h2 {
border-color: #bbb;
}
#header summary svg {
margin-top: -3px;
}
#header details > :not(summary) {
margin: 0 0 0 var(--pad);
padding: calc(var(--pad)/4) 0;
}
#details-wrapper {
display: flex;
flex-direction: column;
flex-grow: 1;
overflow: hidden;
margin-top: var(--pad05);
}
#header details[open] + details[open] {
margin-top: .5rem;
}
#actions .buttons {
display: inline-flex;
flex-wrap: wrap;
align-items: center;
}
#actions .buttons > * {
margin: 0 .25rem .5rem 0;
}
#options:not([open]) + #lint h2 {
margin-top: 0;
}
#lint:not([open]) h2 {
margin-bottom: 0;
margin: 0 .25rem var(--pad05) 0;
}
#publish > div > * {
@ -426,8 +432,6 @@ input:invalid {
}
#toc {
counter-reset: codelabel;
margin: 0;
padding: .5rem 0;
}
#toc li {
white-space: nowrap;
@ -829,40 +833,13 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high
/************ lint ************/
#lint {
overflow: hidden;
margin-left: -1rem;
margin-right: -1rem;
padding: 0;
box-sizing: border-box;
display: flex;
flex-grow: 1;
position: relative;
}
#lint > summary {
position: relative;
margin-left: 0;
padding-left: 4px;
}
#lint[open]:not(.hidden-unless-compact) {
min-height: 102px;
}
#lint summary h2 {
text-indent: -2px;
}
#lint > .lint-scroll-container {
margin: 1rem 10px 0;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow-y: auto;
overflow-x: hidden;
}
#lint summary h2 {
display: inline-flex;
}
#lint table {
font-size: 100%;
border-spacing: 0;
margin-bottom: 1rem;
line-height: 1.0;
width: 100%;
}
@ -878,7 +855,7 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high
#lint table.empty {
display: none;
}
#lint caption {
#lint caption:not(:empty) {
text-align: left;
font-weight: bold;
padding-bottom: 6px;
@ -908,6 +885,9 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high
text-align: left;
white-space: nowrap;
}
#issue-count::before {
content: ':\A0';
}
#message-box.center.lint-config #message-box-contents {
text-align: left;
}
@ -970,11 +950,6 @@ html:not(.usercss) .usercss-only,
display: none !important; /* hide during page init */
}
body:not(.compact-layout) .hidden-unless-compact,
body.linter-disabled .hidden-unless-compact {
display: none !important;
}
#options:not([open]) + #lint {
margin-top: 0;
}
@ -1021,152 +996,100 @@ body.linter-disabled .hidden-unless-compact {
margin-left: 0.2rem;
}
/************ full-width only ************/
/* TODO: maybe move more rules here so we don't need to reset them in @media(max-width: 850px) */
@media (min-width: 851px) {
#header > :not(#details-wrapper):not(#header-resizer) {
margin-left: var(--pad);
margin-right: var(--pad);
}
#publish[open],
#header details:not([open]) {
flex: 0 0 auto;
}
#header details[open]:not(:last-child) {
margin-bottom: var(--pad05);
}
#header details:last-child {
padding-bottom: var(--pad);
}
}
/************ reponsive layouts ************/
@media(max-width: 850px) {
body {
html:not(.usercss) body {
height: 100%;
}
.usercss body {
display: flex;
flex-direction: column;
}
.usercss #header {
position: inherit;
}
#header {
flex: 0 1 auto;
display: block;
flex: 0 0 auto;
height: unset;
width: unset;
position: inherit;
position: sticky;
background: #fff;
border-right: none;
border-bottom: 1px dashed #AAA;
padding: .5rem 1rem .5rem .5rem;
}
.fixed-header {
--fixed-height: 40px;
padding-top: var(--fixed-padding);
}
.fixed-header #header {
min-height: var(--fixed-height);
position: fixed;
top: 0;
left: 0;
right: 0;
padding: 0;
background-color: #fff;
}
.fixed-header #header > *:not(#details-wrapper),
.fixed-header #options {
display: none !important;
}
.fixed-header #details-wrapper {
padding-top: calc((var(--fixed-height) - 1.2rem) / 2); /* 1.2 is the normal line height */
}
#header summary + *,
#lint > .lint-scroll-container {
margin-left: 1rem;
padding: .25rem 0 .5rem;
}
#header input[type="checkbox"] {
vertical-align: middle;
}
#header details {
margin: 0;
padding: var(--pad05) var(--pad05) 0;
}
#heading,
h2 {
display: none;
}
#basic-info {
margin-bottom: .5rem;
margin: 0 16px var(--pad05) 0; /* for popup icon in simple window */
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
}
#basic-info #name,
#basic-info > *:first-child {
flex-grow: 1;
}
#basic-info > *:not(:last-child) {
margin-right: 0.8rem;
}
#basic-info #name {
flex-grow: 1;
#header details > :not(summary) {
margin-left: var(--pad05);
}
#options-wrapper {
display: flex;
flex-wrap: wrap;
box-sizing: border-box;
#header h2 {
font-size: 14px;
}
#actions {
display: inline-block;
}
#details-wrapper {
display: inline-flex;
vertical-align: top;
max-width: 100%;
flex-direction: row;
flex-wrap: wrap;
margin: .25em 0 var(--pad05);
}
#options[open] {
width: 100%;
#details-wrapper details[open] {
max-height: 10vh;
}
#sections-list[open] {
max-height: 102px;
}
#sections-list[open] #toc {
max-height: 60px;
overflow-y: auto;
}
#header details:not(#options) {
#details-wrapper[data-open^=".."] details {
max-width: 50%;
}
.options-column {
flex-grow: 1;
padding-right: .5rem;
box-sizing: border-box;
#details-wrapper[data-open^="..."] {
flex-wrap: wrap;
}
.options-column > .usercss-only {
margin-bottom: 0;
}
#options-wrapper .options-column:nth-child(2) {
margin-top: 0;
}
#options:not([open]),
#options[open],
#publish[open],
#lint:not([open]) {
overflow: initial;
}
#options:not([open]) + #lint:not([open]) {
margin-top: 0;
}
#lint summary {
position: static;
margin-bottom: 0;
}
#header summary {
margin-left: 0;
padding-left: 4px;
}
#header summary h2 {
margin: 0;
padding: 0;
}
.option label {
margin: 0;
}
#options [type="number"] {
text-align: left; /* workaround the column flow bug in webkit */
padding-left: 0.2rem;
}
#options #tabSize-label {
position: relative;
top: 0.2rem;
}
#lint > .lint-scroll-container {
padding-top: 0;
margin-right: 0;
}
#lint {
padding: 0;
margin: .5rem 0 0;
}
#lint:not([open]) + #footer {
margin: .25em 0 -1em .25em;
flex: 0 0 auto;
overflow-x: hidden;
}
#sections {
height: unset !important;
padding-left: 0;
display: flex;
flex-direction: column;
flex: 1;
}
/* TODO: switch from .single-editor to the global .usercss */
#sections > :not(.single-editor) {
margin: 0 .5rem;
padding: .5rem 0;
@ -1175,10 +1098,6 @@ body.linter-disabled .hidden-unless-compact {
overflow: hidden;
flex: 1;
}
.usercss #options:not([open]) ~ #lint.hidden ~ #footer,
.usercss #lint:not([open]) + #footer {
margin-top: -.25em;
}
#help-popup.big[style="display: block;"],
#help-popup[style="display: block;"] {
width: max-content;

View File

@ -1,4 +1,4 @@
/* global $ $create messageBoxProxy waitForSheet */// dom.js
/* global $$ $ $create messageBoxProxy waitForSheet */// dom.js
/* global API msg */// msg.js
/* global CodeMirror */
/* global SectionsEditor */
@ -43,6 +43,19 @@ baseInit.ready.then(async () => {
new MutationObserver(() => elSec.open && editor.updateToc())
.observe(elSec, {attributes: true, attributeFilter: ['open']});
// Auto-update `data-open` attribute to the number of open details
{
const wrapper = $('#details-wrapper');
const details = $$('details', wrapper);
const ds = wrapper.dataset;
const update = () => {
ds.open = '.'.repeat(details.reduce((res, el) => res + (el.open ? 1 : 0), 0));
};
for (const el of details) {
new MutationObserver(update).observe(el, {attributes: true, attributeFilter: ['open']});
}
}
$('#toc').onclick = e =>
editor.jumpToEditor([...$('#toc').children].indexOf(e.target));
$('#keyMap-help').onclick = () =>

View File

@ -312,7 +312,7 @@ linterMan.DEFAULTS = {
function updateCount() {
const issueCount = Array.from(tables.values())
.reduce((sum, table) => sum + table.trs.length, 0);
$('#lint').classList.toggle('hidden-unless-compact', issueCount === 0);
$('#lint').hidden = !issueCount;
$('#issue-count').textContent = issueCount;
}

View File

@ -277,13 +277,15 @@ input[type="number"][data-focused-via-click]:focus {
/* header resizer */
:root {
--header-width: 280px;
--header-resizer-width: 8px;
}
#header-resizer {
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 6px;
width: var(--header-resizer-width);
box-sizing: border-box;
cursor: e-resize;
border-width: 0 1px;
border-style: solid;

View File

@ -1,7 +1,7 @@
{
"name": "Stylus",
"version": "1.5.22",
"minimum_chrome_version": "55",
"minimum_chrome_version": "56",
"description": "__MSG_description__",
"homepage_url": "https://add0n.com/stylus.html",
"manifest_version": 2,