From e2e5e02e78123bb5df1bbfc98f2804468ab7c7e4 Mon Sep 17 00:00:00 2001 From: Dylan Halperin Date: Sat, 22 May 2021 12:05:29 -0400 Subject: [PATCH 1/6] make default colors less harsh, add dark/light theme swapper --- scaladoc/resources/dotty_res/scripts/theme.js | 33 ++++ .../resources/dotty_res/styles/filter-bar.css | 47 +++--- .../resources/dotty_res/styles/nord-light.css | 45 +++-- .../resources/dotty_res/styles/scalastyle.css | 155 +++++++++++++++--- .../scaladoc/renderers/HtmlRenderer.scala | 11 +- .../tools/scaladoc/renderers/Resources.scala | 13 +- .../src/dotty/tools/scaladoc/util/html.scala | 1 + 7 files changed, 246 insertions(+), 59 deletions(-) create mode 100644 scaladoc/resources/dotty_res/scripts/theme.js diff --git a/scaladoc/resources/dotty_res/scripts/theme.js b/scaladoc/resources/dotty_res/scripts/theme.js new file mode 100644 index 000000000000..39820510cb73 --- /dev/null +++ b/scaladoc/resources/dotty_res/scripts/theme.js @@ -0,0 +1,33 @@ +;(function () { + const supportsLocalStorage = (() => { + try { + localStorage.setItem('test', 'test'); + localStorage.removeItem('test'); + return true; + } catch (e) { + return false; + } + })(); + + function toggleDarkTheme(isDark) { + currentlyDark = isDark + // this triggers the `:root.theme-dark` rule from scalastyle.css, + // which changes the values of a bunch of CSS color variables + document.documentElement.classList.toggle("theme-dark", isDark); + supportsLocalStorage && localStorage.setItem("use-dark-theme", isDark); + } + + /* This needs to happen ASAP so we don't get a FOUC of bright colors before the dark theme is applied */ + const initiallyDark = supportsLocalStorage && (localStorage.getItem("use-dark-theme") === "true"); + let currentlyDark = initiallyDark; + toggleDarkTheme(initiallyDark); + + /* Wait for the DOM to be loaded before we try to attach event listeners to things in the DOM */ + window.addEventListener("DOMContentLoaded", () => { + const themeToggler = document.querySelector('#theme-toggle input'); + themeToggler.checked = !currentlyDark; + themeToggler.addEventListener("change", e => { + toggleDarkTheme(!e.target.checked); + }); + }); +})(); diff --git a/scaladoc/resources/dotty_res/styles/filter-bar.css b/scaladoc/resources/dotty_res/styles/filter-bar.css index f8ed5eb9d94d..5a73a87e673d 100644 --- a/scaladoc/resources/dotty_res/styles/filter-bar.css +++ b/scaladoc/resources/dotty_res/styles/filter-bar.css @@ -1,6 +1,6 @@ .documentableFilter { padding: 24px 12px; - background-color: var(--leftbar-bg); + background-color: var(--code-bg); } .documentableFilter.active .filterToggleButton svg { @@ -26,13 +26,13 @@ } .filterToggleButton svg { - fill: var(--code-bg); + fill: var(--body-fg); transition: fill 0.1s ease-in, transform 0.1s ease-in-out; } .filterToggleButton:hover svg, .filterToggleButton:focus svg { - fill: var(--active-tab-color); + fill: var(--active-fg); } .filterableInput { @@ -41,7 +41,7 @@ outline: 0; border: 0; border-radius: 3px; - background-color: var(--code-bg); + background-color: var(--body-bg); } .filterLowerContainer { @@ -50,12 +50,11 @@ } .filterGroup { - display: flex; margin-bottom: 16px; } .filterList { - margin-left: 10px; + margin: 0.5em; } .filterButtonItem { @@ -66,12 +65,12 @@ outline: 0; border: 0; border-radius: 3px; - color: var(--leftbar-bg); - background-color: var(--code-bg); + color: var(--inactive-fg); + background-color: var(--inactive-bg); font-size: 12px; font-weight: 700; cursor: pointer; - border-bottom: 2px solid var(--inactive-fg); + border-bottom: 2px solid var(--inactive-bg-shadow); transition: all 0.1s ease-in; } @@ -81,9 +80,9 @@ } .filterButtonItem.active { - color: var(--code-bg); - border-bottom-color: var(--link-fg); - background-color: var(--active-tab-color); + color: var(--active-fg); + border-bottom-color: var(--active-bg-shadow); + background-color: var(--active-bg); } .filterButtonItem.visible { @@ -91,17 +90,19 @@ } .groupTitle { - min-width: 98px; - margin-top: 4px; + margin-bottom: 4px; font-weight: 700; - font-size: 14px; - color: var(--code-bg); + color: var(--body-fg); +} +.groupTitle > span { + display: inline-block; + vertical-align: baseline; } .groupButtonsContainer { - display: flex; - align-items: center; - margin-top: 4px; + display: inline-block; + vertical-align: baseline; + margin-left: 1em; } .selectAll { @@ -114,8 +115,8 @@ border: 0; background-color: transparent; padding: 0; - color: var(--code-bg); - font-size: 8px; + color: var(--active-fg); + font-size: 0.7em; cursor: pointer; transition: all 0.1s ease-in; } @@ -123,7 +124,7 @@ .selectAll { padding: 4px; border-radius: 2px; - background-color: var(--active-tab-color); + background-color: var(--active-bg); } .selectAll:hover, @@ -133,5 +134,5 @@ .deselectAll:hover, .deselectAll:focus { - color: var(--active-tab-color); + color: var(--active-bg); } diff --git a/scaladoc/resources/dotty_res/styles/nord-light.css b/scaladoc/resources/dotty_res/styles/nord-light.css index 71eac33c4930..9d1604dd0364 100644 --- a/scaladoc/resources/dotty_res/styles/nord-light.css +++ b/scaladoc/resources/dotty_res/styles/nord-light.css @@ -1,14 +1,37 @@ /* Theme inspired by nordtheme. The colors have been darkened to work on light backgrounds. */ +:root { + --hljs-bg: var(--code-bg); + --hljs-fg: var(--code-fg); + --hljs-comment: #90A1C1; + --hljs-doctag: #4B6B92; + --hljs-meta: hsl(40, 100%, 40%); + --hljs-subst: hsl(40, 100%, 40%); + --hljs-title: hsl(193, 60%, 42%); + --hljs-type: hsl(179, 61%, 30%); + --hljs-keyword: hsl(213, 60%, 45%); + --hljs-string: hsl(92, 46%, 43%); + --hljs-literal: hsl(311, 30%, 47%); +} +:root.theme-dark { + --hljs-meta: hsl(40, 100%, 49%); + --hljs-subst: hsl(40, 100%, 49%); + --hljs-title: hsl(193, 60%, 58%); + --hljs-keyword: hsl(213, 60%, 60%); + --hljs-type: hsl(179, 61%, 45%); + --hljs-string: hsl(92, 46%, 68%); + --hljs-literal: hsl(311, 30%, 62%); +} + pre, .hljs { - background: #F4F5FA; - color: #4C566A; + background: var(--hljs-bg); + color: var(--code-fg); } .hljs-comment { - color: #90A1C1; + color: var(--hljs-comment); } .hljs-doctag { - color: #4B6B92; + color: var(--hljs-doctag); font-weight: 500; } .hljs-emphasis { @@ -19,26 +42,26 @@ pre, .hljs { } .hljs-meta { - color: #F9A600; + color: var(--hljs-meta); font-weight: 500; } .hljs-subst { - color: #F9A600; + color: var(--hljs-subst); } .hljs-title { - color: #2B8FAC; + color: var(--hljs-title); font-weight: 500; } .hljs-type { - color: #1E7C7A; + color: var(--hljs-type); } .hljs-keyword { - color: #2E6BB8; + color: var(--hljs-keyword); font-weight: 500; } .hljs-string { - color: #6AA13B; + color: var(--hljs-string); } .hljs-built_in, .hljs-number, .hljs-literal { - color: #9D5490; + color: var(--hljs-literal); } diff --git a/scaladoc/resources/dotty_res/styles/scalastyle.css b/scaladoc/resources/dotty_res/styles/scalastyle.css index 25b4c26f7034..917fe563907d 100644 --- a/scaladoc/resources/dotty_res/styles/scalastyle.css +++ b/scaladoc/resources/dotty_res/styles/scalastyle.css @@ -5,28 +5,37 @@ --border-light: #DADFE6; --border-medium: #abc; - --body-bg: #f0f3f6; - --code-bg: #F4F5FA; - --documentable-bg: #FFFFFF; - --symbol-fg: #333; + --body-bg: #eee; + --body-fg: #333; + --title-fg: hsl(200, 80%, 30%); + + --active-bg: var(--leftbar-current-bg); + --active-bg-shadow: hsl(200, 38%, 50%); + --active-fg: var(--body-fg); + + --inactive-bg: #bbb; + --inactive-bg-shadow: var(--inactive-fg); + --inactive-fg: #777; + + --code-bg: hsl(200, 10%, 90%); + --code-fg: #4C566A; + --symbol-fg: var(--body-fg); + --documentable-bg: var(--code-bg); + --link-fg: #00607D; --link-hover-fg: #00A0D0; - --inactive-fg: #777; - --title-fg: #00485E; --link-sig-fd: #2da0d1; --link-sig-hover-fd: #7c99a5; - --leftbar-bg: #003048; - --leftbar-fg: #fff; - --leftbar-current-bg: #0090BB; + --leftbar-bg: hsl(200, 65%, 75%); + --leftbar-fg: #333; + --leftbar-current-bg: hsl(200, 80%, 65%); --leftbar-current-fg: #fff; - --leftbar-hover-bg: #00485E; - --leftbar-hover-fg: #fff; - --logo-fg: var(--leftbar-fg); + --leftbar-hover-bg: hsl(200, 65%, 65%); + --leftbar-hover-fg: #333; --icon-color: #00485E; - --active-tab-color: #00A0D0; --selected-fg: #00303E; --selected-bg: #BFE7F3; @@ -41,13 +50,54 @@ --content-padding: 24px 42px; --footer-height: 42px; } +:root.theme-dark { + /* Color Settings */ + --border-light: #DADFE6; + --border-medium: #abc; + + --body-bg: hsl(200, 100%, 3%); + --body-fg: #CCC; + --title-fg: hsl(200, 50%, 80%); + + --active-bg: hsl(200, 80%, 25%); + --active-bg-shadow: hsl(200, 38%, 50%); + --active-fg: var(--body-fg); + + --inactive-bg: #444; + --inactive-bg-shadow: var(--inactive-fg); + --inactive-fg: #777; + + --code-bg: hsl(200, 30%, 10%); + --code-fg: #bfbfbf; + --symbol-fg: var(--body-fg); + --link-fg: hsl(200, 100%, 70%); + --link-hover-fg: #00A0D0; + + --link-sig-fd: #2da0d1; + --link-sig-hover-fd: #7c99a5; + + --leftbar-bg: hsl(200, 100%, 14%); + --leftbar-fg: #CCC; + --leftbar-current-bg: hsl(200, 100%, 35%); + --leftbar-current-fg: #CCC; + --leftbar-hover-bg: hsl(200, 80%, 25%); + --leftbar-hover-fg: #CCC; + + --icon-color: #00485E; + --selected-fg: #00303E; + --selected-bg: #BFE7F3; + +} body { margin: 0; padding: 0; font-family: "Lato", sans-serif; font-size: 16px; - background-color: var(--body-bg); + background: var(--body-bg); +} +body, button, input { + color: var(--body-fg); } /* Page layout */ @@ -328,7 +378,7 @@ span.ar::before { .section-tab[data-active=""] { color: unset; font-weight: bold; - border-bottom: 2px solid var(--active-tab-color); + border-bottom: 2px solid var(--active-bg); } .tabs-section-body > :not([data-active]) { display: none; @@ -517,6 +567,67 @@ footer .pull-right { margin-left: auto; } +/* Theme Toggle */ +.switch { + /* The switch - the box around the slider */ + position: relative; + display: inline-block; + width: 60px; + height: 34px; + margin-bottom: 0; +} +.switch input { + /* Hide default HTML checkbox */ + opacity: 0; + width: 0; + height: 0; +} +.switch .slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + border-radius: 34px; + background-color: #ccc; + -webkit-transition: 0.4s; + transition: 0.4s; +} +.switch .slider:before { + position: absolute; + content: "🌘"; + height: 40px; + width: 40px; + line-height:40px; + font-size:20px; + text-align: center; + left: 0px; + bottom: 4px; + top: 0; + bottom: 0; + border-radius: 50%; + margin: auto 0; + -webkit-transition: 0.4s; + transition: 0.4s; + box-shadow: 0 0px 15px #2020203d; + + background-repeat: no-repeat; + background-position: center; +} +.switch input:checked + .slider { + background-color: hsl(200, 80%, 65%); /* --active-bg, but not affected by the theme */ +} +.switch input:focus + .slider { + box-shadow: 0 0 1px #2196f3; +} +.switch input:checked + .slider:before { + content: "🌞"; + -webkit-transform: translateX(24px); + -ms-transform: translateX(24px); + transform: translateX(24px); + background: white; +} .documentableElement .modifiers { display: table-cell; @@ -553,7 +664,7 @@ footer .pull-right { } .documentableElement .signature { - color: #5a5a5a; + color: var(--code-fg); display: table-cell; white-space: pre-wrap; } @@ -576,7 +687,8 @@ footer .pull-right { font-weight: 500; font-size: 12px; background: var(--documentable-bg); - border: 0.25em solid var(--body-bg); + border-left: 0.25em solid transparent; + margin: 0.25em; } .documentableElement>div { @@ -611,11 +723,11 @@ footer .pull-right { .documentableElement:hover { cursor: pointer; - border-left: 0.25em solid var(--leftbar-bg); + border-left-color: var(--active-bg); } .expand.documentableElement { - border-left: 0.25em solid var(--leftbar-bg); + border-left-color: var(--active-bg); } .documentableElement .annotations { color: gray; @@ -658,7 +770,7 @@ footer .pull-right { .tabs .names .tab.selected { color: unset; font-weight: bold; - border-bottom: 2px solid var(--active-tab-color); + border-bottom: 2px solid var(--active-bg); } .tabs .names { @@ -691,6 +803,9 @@ footer .pull-right { width: 5.7em; color:transparent; } +.theme-dark .micon { + filter: brightness(120%); +} .micon.cl { content: url("../images/class.svg") diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala index 2c7a9a1a4fa8..0fe0ee10d315 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala @@ -130,6 +130,10 @@ class HtmlRenderer(rootPackage: Member, val members: Map[DRI, Member])(using ctx case _ => memberResourcesPaths + val earlyResources = page.content match + case t: ResolvedTemplate => if t.hasFrame then earlyMemberResourcePaths else Nil + case _ => earlyMemberResourcePaths + head( meta(charset := "utf-8"), meta(util.HTML.name := "viewport", content := "width=device-width, initial-scale=1"), @@ -140,7 +144,8 @@ class HtmlRenderer(rootPackage: Member, val members: Map[DRI, Member])(using ctx `type` := "image/x-icon", href := resolveLink(page.link.dri, "favicon.ico") ), - linkResources(page.link.dri, resources).toList, + linkResources(page.link.dri, earlyResources, deferJs = false).toList, + linkResources(page.link.dri, resources, deferJs = true).toList, script(raw(s"""var pathToRoot = "${pathToRoot(page.link.dri)}";""")), ctx.args.versionsDictionaryUrl match case Some(url) => script(raw(s"""var versionsDictionaryUrl = "$url";""")) @@ -260,6 +265,10 @@ class HtmlRenderer(rootPackage: Member, val members: Map[DRI, Member])(using ctx raw(" Back to top") ) ), + label(id := "theme-toggle", cls := "switch")( + input(`type` := "checkbox"), + span(cls := "slider") + ), div(cls := "socials")( if hasSocialLinks then Seq(raw("Social links ")) else Nil, socialLinks(whiteIcon = false) diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala index 086f0b709cd5..8733693cdc4e 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala @@ -38,7 +38,7 @@ trait Resources(using ctx: DocContext) extends Locations, Writer: private def dottyRes(path: String) = Resource.Classpath(path, s"dotty_res/$path") - def linkResources(dri: DRI, resources: Iterable[String]): Iterable[AppliedTag] = + def linkResources(dri: DRI, resources: Iterable[String], deferJs: Boolean): Iterable[AppliedTag] = def fileExtension(url: String): String = val param = url.indexOf('?') val end = if param < 0 then url.length else param @@ -48,9 +48,14 @@ trait Resources(using ctx: DocContext) extends Locations, Writer: for res <- resources yield fileExtension(res) match case "css" => link(rel := "stylesheet", href := resolveLink(dri, res)) - case "js" => script(`type` := "text/javascript", src := resolveLink(dri, res), defer := "true") + case "js" => script(`type` := "text/javascript", src := resolveLink(dri, res), if (deferJs) Seq(defer := "true") else Nil) case _ => raw("") + val earlyMemberResources: Seq[Resource] = + List( + "scripts/theme.js" + ).map(dottyRes) + val memberResources: Seq[Resource] = val fromResources = List( "styles/nord-light.css", @@ -85,7 +90,7 @@ trait Resources(using ctx: DocContext) extends Locations, Writer: val searchDataPath = "scripts/searchData.js" val memberResourcesPaths = Seq(searchDataPath) ++ memberResources.map(_.path) - + val earlyMemberResourcePaths = earlyMemberResources.map(_.path) def searchData(pages: Seq[Page]) = def flattenToText(signature: Signature): String = @@ -125,7 +130,7 @@ trait Resources(using ctx: DocContext) extends Locations, Writer: Resource.Text(searchDataPath, s"pages = ${jsonList(entries)};") - def allResources(pages: Seq[Page]): Seq[Resource] = memberResources ++ Seq( + def allResources(pages: Seq[Page]): Seq[Resource] = earlyMemberResources ++ memberResources ++ Seq( dottyRes("favicon.ico"), dottyRes("fonts/dotty-icons.woff"), dottyRes("fonts/dotty-icons.ttf"), diff --git a/scaladoc/src/dotty/tools/scaladoc/util/html.scala b/scaladoc/src/dotty/tools/scaladoc/util/html.scala index e3065bbafbdd..4fe69cd1de3b 100644 --- a/scaladoc/src/dotty/tools/scaladoc/util/html.scala +++ b/scaladoc/src/dotty/tools/scaladoc/util/html.scala @@ -65,6 +65,7 @@ object HTML: val svg = Tag("svg") val button = Tag("button") val input = Tag("input") + val label = Tag("label") val script = Tag("script") val link = Tag("link") val footer = Tag("footer") From de2777931909ec9de085cb3280b8244ce14aa803 Mon Sep 17 00:00:00 2001 From: Dylan Halperin Date: Sat, 22 May 2021 13:00:00 -0400 Subject: [PATCH 2/6] make dottydoc anchors transparent instead of white when not hovered --- docs/css/dottydoc.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/css/dottydoc.css b/docs/css/dottydoc.css index d2520888120a..c39c18991417 100644 --- a/docs/css/dottydoc.css +++ b/docs/css/dottydoc.css @@ -43,7 +43,7 @@ ul.post-list { /* headings anchors */ a.anchor { - color: white; + color: transparent; margin-left: -23px; padding-right: 3px; transition: color .4s ease-out; From 2b8d235244d28a9a81152c6fb5798c290ba35700 Mon Sep 17 00:00:00 2001 From: Dylan Halperin Date: Sat, 22 May 2021 15:39:33 -0400 Subject: [PATCH 3/6] infer dark theme preference from user's system --- scaladoc/resources/dotty_res/scripts/theme.js | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/scaladoc/resources/dotty_res/scripts/theme.js b/scaladoc/resources/dotty_res/scripts/theme.js index 39820510cb73..4061238b02e2 100644 --- a/scaladoc/resources/dotty_res/scripts/theme.js +++ b/scaladoc/resources/dotty_res/scripts/theme.js @@ -9,16 +9,24 @@ } })(); + const settingKey = "use-dark-theme"; + function toggleDarkTheme(isDark) { currentlyDark = isDark // this triggers the `:root.theme-dark` rule from scalastyle.css, // which changes the values of a bunch of CSS color variables document.documentElement.classList.toggle("theme-dark", isDark); - supportsLocalStorage && localStorage.setItem("use-dark-theme", isDark); + supportsLocalStorage && localStorage.setItem(settingKey, isDark); } + /* Infer a dark/light theme preference from the user's system */ + const colorSchemePrefMql = window.matchMedia("(prefers-color-scheme: dark)"); + /* This needs to happen ASAP so we don't get a FOUC of bright colors before the dark theme is applied */ - const initiallyDark = supportsLocalStorage && (localStorage.getItem("use-dark-theme") === "true"); + const initiallyDark = (() => { + const storedSetting = supportsLocalStorage && localStorage.getItem(settingKey); + return (storedSetting === null) ? colorSchemePrefMql.matches : storedSetting === "true"; + })(); let currentlyDark = initiallyDark; toggleDarkTheme(initiallyDark); @@ -29,5 +37,12 @@ themeToggler.addEventListener("change", e => { toggleDarkTheme(!e.target.checked); }); + + /* Auto-swap the dark/light theme if the user changes it in their system */ + colorSchemePrefMql.addEventListener('change', e => { + const preferDark = e.matches + themeToggler.checked = !preferDark + toggleDarkTheme(preferDark) + }) }); })(); From e5ef6d3645ae530933da42548accba646adc0ea7 Mon Sep 17 00:00:00 2001 From: Dylan Halperin Date: Sat, 22 May 2021 15:45:44 -0400 Subject: [PATCH 4/6] add some 'missing' semicolons to some JS --- scaladoc/resources/dotty_res/scripts/theme.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scaladoc/resources/dotty_res/scripts/theme.js b/scaladoc/resources/dotty_res/scripts/theme.js index 4061238b02e2..b5cf46b1a221 100644 --- a/scaladoc/resources/dotty_res/scripts/theme.js +++ b/scaladoc/resources/dotty_res/scripts/theme.js @@ -40,9 +40,9 @@ /* Auto-swap the dark/light theme if the user changes it in their system */ colorSchemePrefMql.addEventListener('change', e => { - const preferDark = e.matches - themeToggler.checked = !preferDark - toggleDarkTheme(preferDark) - }) + const preferDark = e.matches; + themeToggler.checked = !preferDark; + toggleDarkTheme(preferDark); + }); }); })(); From 1c611298834306e4c8b86a429f55dd1bc030ce77 Mon Sep 17 00:00:00 2001 From: Dylan Halperin Date: Sat, 22 May 2021 19:37:31 -0400 Subject: [PATCH 5/6] set min-width on the theme switch so it doesn't get squished --- scaladoc/resources/dotty_res/styles/scalastyle.css | 1 + 1 file changed, 1 insertion(+) diff --git a/scaladoc/resources/dotty_res/styles/scalastyle.css b/scaladoc/resources/dotty_res/styles/scalastyle.css index 917fe563907d..b8a61bce3d48 100644 --- a/scaladoc/resources/dotty_res/styles/scalastyle.css +++ b/scaladoc/resources/dotty_res/styles/scalastyle.css @@ -573,6 +573,7 @@ footer .pull-right { position: relative; display: inline-block; width: 60px; + min-width: 60px; height: 34px; margin-bottom: 0; } From be8fbba9b0148b94de09b0c72b0ee260c6a7ca76 Mon Sep 17 00:00:00 2001 From: Dylan Halperin Date: Fri, 28 May 2021 16:10:11 -0400 Subject: [PATCH 6/6] Make dark-mode footer actually dark. Improve contrast/accessibility. Used the "poor man's dark mode" approach to deal with the images in the footer in dark mode, i.e. invert and hue rotate (without the hue rotate, the red scala3doc logo becomes blue) Also fix an issue where if you click "back to top" and then refresh the page, the "container" element gains the "expand" class, which causes the main signature (i.e. `class List[A] ...`) to become 'inline' instead of a block, and it also triggers the 6.5em left-margin that's intended for method signatures when they get expanded. Also consolidated the `footer` styles, since they were spread all over. --- scaladoc/resources/dotty_res/scripts/ux.js | 11 +++-- .../resources/dotty_res/styles/scalastyle.css | 40 +++++++++---------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/scaladoc/resources/dotty_res/scripts/ux.js b/scaladoc/resources/dotty_res/scripts/ux.js index 63d284d2d93e..b491d2f115fb 100644 --- a/scaladoc/resources/dotty_res/scripts/ux.js +++ b/scaladoc/resources/dotty_res/scripts/ux.js @@ -39,9 +39,14 @@ window.addEventListener("DOMContentLoaded", () => { }) if (location.hash) { - var selected = document.getElementById(location.hash.substring(1)); - if (selected){ - selected.classList.toggle("expand"); + var target = location.hash.substring(1); + // setting the 'expand' class on the top-level container causes undesireable styles + // to apply to the top-level docs, so we avoid this logic for that element. + if (target != 'container') { + var selected = document.getElementById(location.hash.substring(1)); + if (selected) { + selected.classList.toggle("expand"); + } } } diff --git a/scaladoc/resources/dotty_res/styles/scalastyle.css b/scaladoc/resources/dotty_res/styles/scalastyle.css index b8a61bce3d48..77efb2c7541d 100644 --- a/scaladoc/resources/dotty_res/styles/scalastyle.css +++ b/scaladoc/resources/dotty_res/styles/scalastyle.css @@ -25,8 +25,7 @@ --link-fg: #00607D; --link-hover-fg: #00A0D0; - --link-sig-fd: #2da0d1; - --link-sig-hover-fd: #7c99a5; + --link-sig-fg: var(--link-fg); --leftbar-bg: hsl(200, 65%, 75%); --leftbar-fg: #333; @@ -35,6 +34,8 @@ --leftbar-hover-bg: hsl(200, 65%, 65%); --leftbar-hover-fg: #333; + --footer-bg: #FFF; + --icon-color: #00485E; --selected-fg: #00303E; --selected-bg: #BFE7F3; @@ -73,16 +74,18 @@ --link-fg: hsl(200, 100%, 70%); --link-hover-fg: #00A0D0; - --link-sig-fd: #2da0d1; - --link-sig-hover-fd: #7c99a5; + --link-sig-fg: #2da0d1; --leftbar-bg: hsl(200, 100%, 14%); --leftbar-fg: #CCC; --leftbar-current-bg: hsl(200, 100%, 35%); - --leftbar-current-fg: #CCC; + --leftbar-current-fg: #FFF; --leftbar-hover-bg: hsl(200, 80%, 25%); --leftbar-hover-fg: #CCC; + --footer-bg: var(--body-bg); + --footer-fg: var(--body-fg); + --icon-color: #00485E; --selected-fg: #00303E; --selected-bg: #BFE7F3; @@ -321,6 +324,7 @@ th { #sideMenu2 a.selected { background: var(--leftbar-current-bg); + color: var(--leftbar-current-fg); font-weight: bold; } @@ -536,6 +540,8 @@ Same solution is already used in Dokka. /* Footer */ footer { + background: var(--footer-bg); + color: var(--footer-fg); display: flex; bottom: 0px; align-items: center; @@ -546,8 +552,12 @@ footer { min-height: var(--footer-height); border-top: 1px solid var(--border-light); } -footer span.go-to-top-icon { - background-color: white; +.theme-dark footer img { + /* "Poor man's dark mode" for images. + * This works great with black images, + * and just-okay with colored images. + */ + filter: invert(100%) hue-rotate(180deg); } footer > span:first-child { margin-left: 24px; @@ -612,9 +622,7 @@ footer .pull-right { -webkit-transition: 0.4s; transition: 0.4s; box-shadow: 0 0px 15px #2020203d; - - background-repeat: no-repeat; - background-position: center; + background: #555; } .switch input:checked + .slider { background-color: hsl(200, 80%, 65%); /* --active-bg, but not affected by the theme */ @@ -656,7 +664,7 @@ footer .pull-right { } .other-modifiers a, .other-modifiers a:visited, .other-modifiers span[data-unresolved-link] { - color: var(--link-sig-fd); + color: var(--link-sig-fg); } .documentableElement.expand .modifiers { @@ -671,7 +679,7 @@ footer .pull-right { } .signature a, .signature a:visited, .signature span[data-unresolved-link] { - color: var(--link-sig-fd); + color: var(--link-sig-fg); } .expand .signature { @@ -869,10 +877,6 @@ footer .pull-right { margin-right: 5%; } -footer { - color: grey; -} - footer .socials { margin-left: 10px; margin-right: 10px; @@ -977,10 +981,6 @@ footer .socials { } } -footer { - background-color: white; -} - /* The container
- needed to position the dropdown content */ .versions-dropdown { position: relative;