From 111783fce3dd471983543ad1f5b2164e7bec54e8 Mon Sep 17 00:00:00 2001 From: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com> Date: Thu, 29 Jun 2023 09:34:27 -0600 Subject: [PATCH] Refactor Furo to use Sass nesting (#429) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sass allows nesting: > When writing HTML you’ve probably noticed that it has a clear nested and visual hierarchy. CSS, on the other hand, doesn’t. > > Sass will let you nest your CSS selectors in a way that follows the same visual hierarchy of your HTML. E.g. ```scss nav { ul { margin: 0; padding: 0; list-style: none; } li { display: inline-block; } } ``` vs. ```css nav ul { margin: 0; padding: 0; list-style: none; } nav li { display: inline-block; } ``` This cleans up some of our hard-to-read selectors. --- .../assets/styles/_admonitions.scss | 140 +++++++-------- .../assets/styles/_api.scss | 64 +++---- .../assets/styles/_layout.scss | 10 +- .../assets/styles/_left-sidebar.scss | 162 +++++++++--------- .../assets/styles/_tables.scss | 30 ++-- .../assets/styles/_top-nav-bar.scss | 2 +- 6 files changed, 198 insertions(+), 210 deletions(-) diff --git a/src/qiskit_sphinx_theme/assets/styles/_admonitions.scss b/src/qiskit_sphinx_theme/assets/styles/_admonitions.scss index c43d6bb7..6e2a0383 100644 --- a/src/qiskit_sphinx_theme/assets/styles/_admonitions.scss +++ b/src/qiskit_sphinx_theme/assets/styles/_admonitions.scss @@ -13,19 +13,18 @@ body { --qiskit-color-admonition-error--border: #da1e28; } - .topic { border: 1px solid var(--qiskit-color-admonition-info--background); } -p.topic-title::before { - -webkit-mask-image: var(--icon-info); - mask-image: var(--icon-info); - background-color: var(--qiskit-color-admonition-info--border); -} - p.topic-title { background-color: var(--qiskit-color-admonition-info--background); + + &::before { + -webkit-mask-image: var(--icon-info); + mask-image: var(--icon-info); + background-color: var(--qiskit-color-admonition-info--border); + } } // Admonitions are complex because they use a 3px left border with a different color than the rest @@ -45,92 +44,81 @@ p.topic-title { border-bottom-width: 1px; position: relative; padding-left: 12px; -} -.admonition::before { - content: ''; - position: absolute; - top: 0; - bottom: 0; - left: 0; - width: 3px; -} -.admonition.attention > .admonition-title::before, -.admonition.caution > .admonition-title::before, -.admonition.important > .admonition-title::before, -.admonition.warning > .admonition-title::before { - // Rather than using mask-image like Furo normally does, we set `content` to the SVG. This is - // because Carbon requires that we have a black exclamation mark for accessibility: the - // light yellow background wouldn't be distinct enough compared to the dark yellow icon. Mask - // image doesn't let us set colors, only whether to use the background color of the underlying - // HTML element vs. use the background color of the SVG container. So, having a black exclamation - // mark would require setting the entire .admonition-title background color to black. - content: var(--icon-warning); - -webkit-mask-image: unset; - mask-image: unset; - background-color: var(--qiskit-color-admonition-warning--background); -} -.admonition.attention > .admonition-title, -.admonition.caution > .admonition-title, -.admonition.important > .admonition-title, -.admonition.warning > .admonition-title { - background-color: var(--qiskit-color-admonition-warning--background); + &::before { + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 3px; + } } + .admonition.attention, .admonition.caution, .admonition.important, .admonition.warning { border-color: var(--qiskit-color-admonition-warning--background); -} -.admonition.attention::before, -.admonition.caution::before, -.admonition.important::before, -.admonition.warning::before { - background: var(--qiskit-color-admonition-warning--border); -} -.admonition.danger > .admonition-title::before, -.admonition.error > .admonition-title::before { - -webkit-mask-image: var(--icon-failure); - mask-image: var(--icon-failure); - background-color: var(--qiskit-color-admonition-error--border); -} -.admonition.danger > .admonition-title, -.admonition.error > .admonition-title { - background-color: var(--qiskit-color-admonition-error--background); + &::before { + background: var(--qiskit-color-admonition-warning--border); + } + + > .admonition-title { + background-color: var(--qiskit-color-admonition-warning--background); + } + + > .admonition-title::before { + // Rather than using mask-image like Furo normally does, we set `content` to the SVG. This is + // because Carbon requires that we have a black exclamation mark for accessibility: the + // light yellow background wouldn't be distinct enough compared to the dark yellow icon. Mask + // image doesn't let us set colors, only whether to use the background color of the underlying + // HTML element vs. use the background color of the SVG container. So, having a black exclamation + // mark would require setting the entire .admonition-title background color to black. + content: var(--icon-warning); + -webkit-mask-image: unset; + mask-image: unset; + background-color: var(--qiskit-color-admonition-warning--background); + } } + .admonition.danger, .admonition.error { border-color: var(--qiskit-color-admonition-error--background); -} -.admonition.danger::before, -.admonition.error::before { - background: var(--qiskit-color-admonition-error--border); -} -.admonition > .admonition-title::before, -.admonition.hint > .admonition-title::before, -.admonition.note > .admonition-title::before, -.admonition.tip > .admonition-title::before { - -webkit-mask-image: var(--icon-info); - mask-image: var(--icon-info); - background-color: var(--qiskit-color-admonition-info--border); -} -.admonition > .admonition-title, -.admonition.hint > .admonition-title, -.admonition.note > .admonition-title, -.admonition.tip > .admonition-title { - background-color: var(--qiskit-color-admonition-info--background); + &::before { + background: var(--qiskit-color-admonition-error--border); + } + + > .admonition-title { + background-color: var(--qiskit-color-admonition-error--background); + } + + > .admonition-title::before { + -webkit-mask-image: var(--icon-failure); + mask-image: var(--icon-failure); + background-color: var(--qiskit-color-admonition-error--border); + } } + .admonition, .admonition.hint, .admonition.note, .admonition.tip { border-color: var(--qiskit-color-admonition-info--background); -} -.admonition::before, -.admonition.hint::before, -.admonition.note::before, -.admonition.tip::before { - background: var(--qiskit-color-admonition-info--border); + + &::before { + background: var(--qiskit-color-admonition-info--border); + } + + > .admonition-title { + background-color: var(--qiskit-color-admonition-info--background); + } + + > .admonition-title::before { + -webkit-mask-image: var(--icon-info); + mask-image: var(--icon-info); + background-color: var(--qiskit-color-admonition-info--border); + } } diff --git a/src/qiskit_sphinx_theme/assets/styles/_api.scss b/src/qiskit_sphinx_theme/assets/styles/_api.scss index 57602535..5746e266 100644 --- a/src/qiskit_sphinx_theme/assets/styles/_api.scss +++ b/src/qiskit_sphinx_theme/assets/styles/_api.scss @@ -2,7 +2,6 @@ body { --color-api-name: var(--color-foreground-primary); --color-api-pre-name: var(--color-foreground-secondary); - } // Definition lists are used for sections like "Parameters", "Return type", and "Attributes" @@ -16,38 +15,43 @@ dl.py:not(.docutils) dt { } // Rules that impact the top-level entry for the code object, which e.g. has the `[source]` button. -section > dl.py:not(.docutils) > dt { - // We normally want to use inline-block for definition terms so that the purple border we add on - // top does not stretch across the whole screen. But, we make an exception here it will have a - // `[source]` button that floats to the right. The spacing of that is non-trivial and was the - // source of issues in Pytorch, so we stick with Furo's spacing. - display: block; - // Make the border less thick so its clear the top-level page header corresponds to this line. - border-top-width: 1px; - margin-bottom: 1rem; -} -// It's possible to have multiple entries for the same code object, e.g. when using typing.overload. -// This cancels out the margin-bottom such that only the bottom-most `dt` will have a margin-bottom -// in effect. -section > dl.py:not(.docutils) > dt:not(:first-child) { - margin-top: -1rem; +section > dl.py:not(.docutils) { + > dt { + // We normally want to use inline-block for definition terms so that the purple border we add on + // top does not stretch across the whole screen. But, we make an exception here it will have a + // `[source]` button that floats to the right. The spacing of that is non-trivial and was the + // source of issues in Pytorch, so we stick with Furo's spacing. + display: block; + // Make the border less thick so its clear the top-level page header corresponds to this line. + border-top-width: 1px; + margin-bottom: 1rem; + } + + // It's possible to have multiple entries for the same code object, e.g. when using typing.overload. + // This cancels out the margin-bottom such that only the bottom-most `dt` will have a margin-bottom + // in effect. + > dt:not(:first-child) { + margin-top: -1rem; + } } // Fix some of the definition terms like "Parameters" having no padding and being in all caps. -// -// Some Qiskit projects, like Experiments, use custom API sections. Those don't set the class -// `.field-list` on the `dl`, so we change Furo's selector from `.field-list > dt` to `dl > dt`. But, -// to override Furo's properties we don't like, we also have to use `.field-list > dt` for some -// rules to win the specificity war. -dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl > dt { - font-weight: 700; - // Copied from Furo's `.sig:not(.sig-inline)` - padding: .25rem .5rem .25rem 3em; - text-indent: -2.5em; -} -dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list > dt { - text-transform: unset; - font-size: unset; +dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) { + // Some Qiskit projects, like Experiments, use custom API sections. Those don't set the class + // `.field-list` on the `dl`, so we change Furo's selector from `.field-list > dt` to `dl > dt`. + dl > dt { + font-weight: 700; + // Copied from Furo's `.sig:not(.sig-inline)` + padding: .25rem .5rem .25rem 3em; + text-indent: -2.5em; + } + + // But, to override Furo's properties we don't like, we also have to use `.field-list > dt` for some + // rules to win the specificity war. + .field-list > dt { + text-transform: unset; + font-size: unset; + } } .sig:not(.sig-inline) { diff --git a/src/qiskit_sphinx_theme/assets/styles/_layout.scss b/src/qiskit_sphinx_theme/assets/styles/_layout.scss index 6fcb13b5..a2500c11 100644 --- a/src/qiskit_sphinx_theme/assets/styles/_layout.scss +++ b/src/qiskit_sphinx_theme/assets/styles/_layout.scss @@ -32,6 +32,10 @@ body { flex: 0 0 var(--qiskit-left-sidebar-width); width: var(--qiskit-left-sidebar-width); min-width: var(--qiskit-left-sidebar-width); + + @media (max-width: 67em) { + left: calc(var(--qiskit-left-sidebar-width) * -1); + } } .sidebar-container { @@ -46,9 +50,3 @@ body { .toc-drawer { flex: 0 0 15em; } - -@media (max-width: 67em) { - .sidebar-drawer { - left: calc(var(--qiskit-left-sidebar-width) * -1); - } -} diff --git a/src/qiskit_sphinx_theme/assets/styles/_left-sidebar.scss b/src/qiskit_sphinx_theme/assets/styles/_left-sidebar.scss index 074d2d25..16a53d15 100644 --- a/src/qiskit_sphinx_theme/assets/styles/_left-sidebar.scss +++ b/src/qiskit_sphinx_theme/assets/styles/_left-sidebar.scss @@ -3,21 +3,21 @@ // ------------------------------------------------------------------------------ body { - // Use gray for the top-level links to be more muted. + // Use gray for the top-level links to be more muted. --color-sidebar-link-text--top-level: var(--color-sidebar-link-text); - // Turn off gradient for hover. + // Turn off gradient for hover. --color-sidebar-item-background--hover: #efeff4; } // Even though we override --color-sidebar-link--top-level to be a more muted look, we change -// the currently selected page to be purple to make it more obvious. +// the currently selected page to be purple to make it more obvious. .sidebar-tree .current-page > .reference { color: var(--qiskit-color-purple); } // -------------------------------------------------------------------------------------- // Common config for Translations & Previous Releases -// -------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------- .qiskit-translations-list-container, .qiskit-previous-releases-list-container { @@ -28,7 +28,7 @@ body { display: block; } -// Based off of `.toctree-l1 li`. +// Based off of `.toctree-l1 li`. .qiskit-translations-header-container, .qiskit-previous-releases-header-container { margin: 0; @@ -36,38 +36,35 @@ body { // Normally this is set on `.sidebar-tree label`, which corresponds to // `.qiskit-translations-toggle-container` and `.qiskit-previous-releases-toggle-container`. // But we set it on the whole container because otherwise we get annoying browser highlighting - // of the text. + // of the text. -webkit-user-select: none; user-select: none; -} - -.qiskit-translations-header-container label, -.qiskit-previous-releases-header-container label { - cursor: pointer; -} -// Based off of `.sidebar-tree li.has-children > reference` and `.sidebar-tree .reference`. -.qiskit-translations-header-container p, -.qiskit-previous-releases-header-container p { - box-sizing: border-box; - display: inline-block; - height: 100%; - line-height: var(--sidebar-item-line-height); - overflow-wrap: anywhere; - text-decoration: none; - width: 100%; - padding-left: var(--sidebar-item-spacing-horizontal); - padding-right: var(--sidebar-expander-width); -} - -// Based off of `.sidebar-tree .reference:hover`, but applied to the whole container rather than -// only the label text. -.qiskit-translations-header-container:hover, -.qiskit-previous-releases-header-container:hover { - background: var(--color-sidebar-item-background--hover); -} - -// Based off of `.sidebar-tree label`. + // Based off of `.sidebar-tree .reference:hover`, but applied to the whole container rather than + // only the label text. + &:hover { + background: var(--color-sidebar-item-background--hover); + } + + label { + cursor: pointer; + } + + // Based off of `.sidebar-tree li.has-children > reference` and `.sidebar-tree .reference`. + p { + box-sizing: border-box; + display: inline-block; + height: 100%; + line-height: var(--sidebar-item-line-height); + overflow-wrap: anywhere; + text-decoration: none; + width: 100%; + padding-left: var(--sidebar-item-spacing-horizontal); + padding-right: var(--sidebar-expander-width); + } +} + +// Based off of `.sidebar-tree label`. .qiskit-translations-toggle-container, .qiskit-previous-releases-toggle-container { background: var(--color-sidebar-item-expander-background); @@ -81,7 +78,7 @@ body { width: var(--sidebar-expander-width); } -// Based off of `.toctree-checkbox`. +// Based off of `.toctree-checkbox`. #translations-checkbox, #previous-releases-checkbox { display: none; @@ -96,41 +93,40 @@ body { transform: rotate(-90deg); } -// Based off of `.sidebar-tree ul`. -.qiskit-translations-list-container ul, -.qiskit-previous-releases-list-container ul { - display: flex; - flex-direction: column; - list-style: none; - margin-bottom: 0; - margin-top: 0; - padding: 0; -} - -// Based off of `.sidebar-tree li`. -.qiskit-translations-list-container li, -.qiskit-previous-releases-list-container li { - margin: 0; - position: relative; -} - -// Based off of `.sidebar-tree .reference`. -.qiskit-translations-list-container a, -.qiskit-previous-releases-list-container a { - box-sizing: border-box; - display: inline-block; - height: 100%; - line-height: var(--sidebar-item-line-height); - overflow-wrap: anywhere; - padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal); - text-decoration: none; - width: 100%; -} - -// Based off of `.sidebar-tree .reference:hover`. -.qiskit-translations-list-container a:hover, -.qiskit-previous-releases-list-container a:hover { - background: var(--color-sidebar-item-background--hover); +.qiskit-translations-list-container, +.qiskit-previous-releases-list-container { + // Based off of `.sidebar-tree ul`. + ul { + display: flex; + flex-direction: column; + list-style: none; + margin-bottom: 0; + margin-top: 0; + padding: 0; + } + + // Based off of `.sidebar-tree li`. + li { + margin: 0; + position: relative; + } + + // Based off of `.sidebar-tree .reference`. + a { + box-sizing: border-box; + display: inline-block; + height: 100%; + line-height: var(--sidebar-item-line-height); + overflow-wrap: anywhere; + padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal); + text-decoration: none; + width: 100%; + } + + // Based off of `.sidebar-tree .reference:hover`. + a:hover { + background: var(--color-sidebar-item-background--hover); + } } // -------------------------------------------------------------------------------------- @@ -143,15 +139,15 @@ body { .qiskit-translations-list-container { padding-bottom: var(--sidebar-item-spacing-vertical); -} -.qiskit-translations-list-container a { - // We increase the horizontal padding for some visual distinction with the normal sidebar. - padding: var(--sidebar-item-spacing-vertical) calc(var(--sidebar-item-spacing-horizontal) * 1.5); + a { + // We increase the horizontal padding for some visual distinction with the normal sidebar. + padding: var(--sidebar-item-spacing-vertical) calc(var(--sidebar-item-spacing-horizontal) * 1.5); + } } .qiskit-translations-toggle-container { - // Unlike Furo, we set this to 100% instead of `var(--sidebar-item-height)`. + // Unlike Furo, we set this to 100% instead of `var(--sidebar-item-height)`. height: 100%; } @@ -159,16 +155,18 @@ body { // Previous Releases // ------------------------------------------------------------------------------ -// Inspired by `.sidebar-tree li > ul`. -.qiskit-previous-releases-list-container ul { - margin-left: calc(var(--sidebar-item-spacing-horizontal) * 0.5); -} +.qiskit-previous-releases-list-container { + // Inspired by `.sidebar-tree li > ul`. + ul { + margin-left: calc(var(--sidebar-item-spacing-horizontal) * 0.5); + } -.qiskit-previous-releases-list-container a { - color: var(--color-sidebar-link-text); + a { + color: var(--color-sidebar-link-text); + } } -// Inspired by `.sidebar-tree`. +// Inspired by `.sidebar-tree`. .qiskit-previous-releases-container { font-size: var(--sidebar-item-font-size); margin-bottom: var(--sidebar-item-spacing-vertical); diff --git a/src/qiskit_sphinx_theme/assets/styles/_tables.scss b/src/qiskit_sphinx_theme/assets/styles/_tables.scss index 987d00e5..f04192cc 100644 --- a/src/qiskit_sphinx_theme/assets/styles/_tables.scss +++ b/src/qiskit_sphinx_theme/assets/styles/_tables.scss @@ -3,24 +3,24 @@ body { --color-table-header-background: #dde1e6; } -// Add a border to the top of the table so that tables without headers have a border. -// -// It's arguably not necessary to add a top border when the table has a header and we could -// use a more precise selector `table.docutils tbody`. But, the rest of the table will already have -// borders so we are consistent this way. table.docutils { + // Add a border to the top of the table so that tables without headers have a border. + // + // It's arguably not necessary to add a top border when the table has a header and we could + // use a more precise selector `table.docutils tbody`. But, the rest of the table will already have + // borders so we are consistent this way. border-top: 1px solid var(--color-table-border); -} -// Because we disable drop shadows in _drop-shadows.scss, restore borders for tables by overriding -// rules that disabled them. -table.docutils td:last-child, -table.docutils th:last-child { - border-right: 1px solid var(--color-table-border); -} -table.docutils td:first-child, -table.docutils th:first-child { - border-left: 1px solid var(--color-table-border); + // Because we disable drop shadows in _drop-shadows.scss, restore borders for tables by + // overriding rules that disabled them. */ + td:last-child, + th:last-child { + border-right: 1px solid var(--color-table-border); + } + td:first-child, + th:first-child { + border-left: 1px solid var(--color-table-border); + } } // Turn off center aligning of tables. diff --git a/src/qiskit_sphinx_theme/assets/styles/_top-nav-bar.scss b/src/qiskit_sphinx_theme/assets/styles/_top-nav-bar.scss index 067bd3f7..f59fc53c 100644 --- a/src/qiskit_sphinx_theme/assets/styles/_top-nav-bar.scss +++ b/src/qiskit_sphinx_theme/assets/styles/_top-nav-bar.scss @@ -4,7 +4,7 @@ body { --qiskit-top-nav-bar-height: 3.5rem; } -// Disable dark mode until qiskit.org has it: https://github.com/Qiskit/qiskit.org/issues/2310 */ +// Disable dark mode until qiskit.org has it: https://github.com/Qiskit/qiskit.org/issues/2310 .theme-toggle-container { display: none; }