diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java index 47b2322226ee8..d00d7b1becff4 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java @@ -327,6 +327,8 @@ protected void generateOtherFiles(ClassTree classTree) copyResource(DocPaths.RIGHT_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.RIGHT_SVG), true); copyResource(DocPaths.CLIPBOARD_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.CLIPBOARD_SVG), true); copyResource(DocPaths.LINK_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.LINK_SVG), true); + copyResource(DocPaths.MOON_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.MOON_SVG), true); + copyResource(DocPaths.SUN_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.SUN_SVG), true); if (options.createIndex()) { copyResource(DocPaths.SEARCH_JS_TEMPLATE, DocPaths.SCRIPT_FILES.resolve(DocPaths.SEARCH_JS), true); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java index 42d93c41e116a..c257e1e153c86 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java @@ -114,6 +114,11 @@ public class HtmlIds { static final HtmlId SEARCH_INPUT = HtmlId.of("search-input"); static final HtmlId SERVICES = HtmlId.of("services-summary"); static final HtmlId SKIP_NAVBAR_TOP = HtmlId.of("skip-navbar-top"); + static final HtmlId THEME_BUTTON = HtmlId.of("theme-button"); + static final HtmlId THEME_DARK = HtmlId.of("theme-dark"); + static final HtmlId THEME_LIGHT = HtmlId.of("theme-light"); + static final HtmlId THEME_OS = HtmlId.of("theme-os"); + static final HtmlId THEME_PANEL = HtmlId.of("theme-panel"); static final HtmlId UNNAMED_PACKAGE_ANCHOR = HtmlId.of("unnamed-package"); private static final String FIELDS_INHERITANCE = "fields-inherited-from-class-"; private static final String METHODS_INHERITANCE = "methods-inherited-from-class-"; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java index 61af26259af4e..1938a4838f554 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java @@ -137,6 +137,7 @@ private void addMainNavLinks(Content target) { addIndexLink(target); addSearchLink(target); addHelpLink(target); + addThemeSwitcher(target); break; case MODULE: addOverviewLink(target); @@ -148,6 +149,7 @@ private void addMainNavLinks(Content target) { addIndexLink(target); addSearchLink(target); addHelpLink(target); + addThemeSwitcher(target); break; case PACKAGE: addOverviewLink(target); @@ -166,6 +168,7 @@ private void addMainNavLinks(Content target) { addIndexLink(target); addSearchLink(target); addHelpLink(target); + addThemeSwitcher(target); break; case CLASS: addOverviewLink(target); @@ -184,6 +187,7 @@ private void addMainNavLinks(Content target) { addIndexLink(target); addSearchLink(target); addHelpLink(target); + addThemeSwitcher(target); break; case USE: addOverviewLink(target); @@ -208,6 +212,7 @@ private void addMainNavLinks(Content target) { addIndexLink(target); addSearchLink(target); addHelpLink(target); + addThemeSwitcher(target); break; case TREE: addOverviewLink(target); @@ -226,6 +231,7 @@ private void addMainNavLinks(Content target) { addIndexLink(target); addSearchLink(target); addHelpLink(target); + addThemeSwitcher(target); break; case DEPRECATED: case INDEX: @@ -268,6 +274,7 @@ private void addMainNavLinks(Content target) { } else { addHelpLink(target); } + addThemeSwitcher(target); break; case ALL_CLASSES: case ALL_PACKAGES: @@ -285,6 +292,7 @@ private void addMainNavLinks(Content target) { addIndexLink(target); addSearchLink(target); addHelpLink(target); + addThemeSwitcher(target); break; case DOC_FILE: addOverviewLink(target); @@ -311,16 +319,13 @@ private void addMainNavLinks(Content target) { addIndexLink(target); addSearchLink(target); addHelpLink(target); + addThemeSwitcher(target); break; default: break; } } - private void addContentToList(List listContents, Content source) { - listContents.add(HtmlTree.LI(source)); - } - private void addItemToList(Content list, Content item) { list.add(HtmlTree.LI(item)); } @@ -492,6 +497,17 @@ private void addHelpLink(Content target) { } } + private void addThemeSwitcher(Content target) { + var selectTheme = contents.getContent("doclet.theme.select_theme"); + target.add(HtmlTree.LI(HtmlTree.BUTTON(HtmlIds.THEME_BUTTON) + .add(HtmlTree.IMG(pathToRoot.resolve(DocPaths.RESOURCE_FILES).resolve(DocPaths.SUN_SVG), + selectTheme.toString()).addStyle(HtmlIds.THEME_LIGHT.name())) + .add(HtmlTree.IMG(pathToRoot.resolve(DocPaths.RESOURCE_FILES).resolve(DocPaths.MOON_SVG), + selectTheme.toString()).addStyle(HtmlIds.THEME_DARK.name())) + .put(HtmlAttr.ARIA_LABEL, selectTheme.toString()) + .put(HtmlAttr.TITLE, selectTheme.toString()))); + } + private void addSearch(Content target) { var resources = configuration.getDocResources(); var inputText = HtmlTree.INPUT(HtmlAttr.InputType.TEXT, HtmlIds.SEARCH_INPUT) @@ -545,6 +561,7 @@ public Content getContent() { navContent.add(aboutDiv); navigationBar.add(HtmlTree.DIV(HtmlStyles.topNav, navContent).setId(HtmlIds.NAVBAR_TOP)); + var subNavContent = HtmlTree.DIV(HtmlStyles.navContent); List subNavLinks = new ArrayList<>(); switch (documentedPage) { @@ -557,6 +574,22 @@ public Content getContent() { breadcrumbNav.addAll(subNavLinks, HtmlTree::LI); subNavContent.addUnchecked(breadcrumbNav); + var selectTheme = contents.getContent("doclet.theme.select_theme"); + subNavContent.add(HtmlTree.DIV(HtmlIds.THEME_PANEL) + .add(HtmlTree.DIV(selectTheme)) + .add(HtmlTree.DIV(HtmlTree.LABEL(HtmlIds.THEME_LIGHT.name(), Text.EMPTY) + .add(HtmlTree.INPUT(HtmlAttr.InputType.RADIO, HtmlIds.THEME_LIGHT) + .put(HtmlAttr.NAME, "theme").put(HtmlAttr.VALUE, HtmlIds.THEME_LIGHT.name())) + .add(HtmlTree.SPAN(contents.getContent("doclet.theme.light")))) + .add(HtmlTree.LABEL(HtmlIds.THEME_DARK.name(), Text.EMPTY) + .add(HtmlTree.INPUT(HtmlAttr.InputType.RADIO, HtmlIds.THEME_DARK) + .put(HtmlAttr.NAME, "theme").put(HtmlAttr.VALUE, HtmlIds.THEME_DARK.name())) + .add(HtmlTree.SPAN(contents.getContent("doclet.theme.dark")))) + .add(HtmlTree.LABEL(HtmlIds.THEME_OS.name(), Text.EMPTY) + .add(HtmlTree.INPUT(HtmlAttr.InputType.RADIO, HtmlIds.THEME_OS) + .put(HtmlAttr.NAME, "theme").put(HtmlAttr.VALUE, HtmlIds.THEME_OS.name())) + .add(HtmlTree.SPAN(contents.getContent("doclet.theme.system")))))); + if (options.createIndex() && documentedPage != PageMode.SEARCH) { addSearch(subNavContent); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/glass.svg b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/glass.svg index ff7df85e8f66e..c979c9f3d83ec 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/glass.svg +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/glass.svg @@ -8,6 +8,6 @@ --> - - - \ No newline at end of file + + + diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/highlight.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/highlight.css index 145c1c7f5d281..77c3254304965 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/highlight.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/highlight.css @@ -65,3 +65,188 @@ /* ignored */ } +body.theme-dark { + .hljs-title.function_, + .hljs-template-variable { + color: #66bcce; + } + .hljs-code, + .hljs-comment, + .hljs-quote { + color:#9d9d9d; + font-style: italic; + } + .hljs-meta { + color: #836F00; + } + .hljs-symbol, + .hljs-template-tag, + .hljs-keyword, + .hljs-literal, + .hljs-name, + .hljs-built_in, + .hljs-char.escape_ { + color: #88aece; + } + .hljs-variable, + .hljs-property, + .hljs-attr, + .hljs-section { + color: #c59bc1; + } + .hljs-attribute { + color: #c59bc1; + } + .hljs-regexp, + .hljs-number { + color: #cfe374; + } + .hljs-link { + color: #b5bd68; + } + .hljs-string { + color: #b5bd68; + } + .hljs-doctag { + text-decoration: underline; + } + .hljs-emphasis { + font-style: italic; + } + .hljs-strong { + font-weight: bold; + } + .hljs-subst, + .hljs-title, + .hljs-params, + .hljs-bullet, + .hljs-formula, + .hljs-tag, + .hljs-type { + /* ignored */ + } +} + +@media (prefers-color-scheme: dark) { + .hljs-title.function_, + .hljs-template-variable { + color: #66bcce; + } + .hljs-code, + .hljs-comment, + .hljs-quote { + color:#9d9d9d; + font-style: italic; + } + .hljs-meta { + color: #836F00; + } + .hljs-symbol, + .hljs-template-tag, + .hljs-keyword, + .hljs-literal, + .hljs-name, + .hljs-built_in, + .hljs-char.escape_ { + color: #88aece; + } + .hljs-variable, + .hljs-property, + .hljs-attr, + .hljs-section { + color: #c59bc1; + } + .hljs-attribute { + color: #c59bc1; + } + .hljs-regexp, + .hljs-number { + color: #cfe374; + } + .hljs-link { + color: #b5bd68; + } + .hljs-string { + color: #b5bd68; + } + .hljs-doctag { + text-decoration: underline; + } + .hljs-emphasis { + font-style: italic; + } + .hljs-strong { + font-weight: bold; + } + .hljs-subst, + .hljs-title, + .hljs-params, + .hljs-bullet, + .hljs-formula, + .hljs-tag, + .hljs-type { + /* ignored */ + } + + body.theme-light { + .hljs-title.function_, + .hljs-template-variable { + color: #00738F; + } + .hljs-code, + .hljs-comment, + .hljs-quote { + color: #6e6e71; + font-style: italic; + } + .hljs-meta { + color: #836F00; + } + .hljs-symbol, + .hljs-template-tag, + .hljs-keyword, + .hljs-literal, + .hljs-name, + .hljs-built_in, + .hljs-char.escape_ { + color: #0C40C2; + } + .hljs-variable, + .hljs-property, + .hljs-attr, + .hljs-section { + color: #841191; + } + .hljs-attribute { + color: #164ad9; + } + .hljs-regexp, + .hljs-number { + color: #104BEB; + } + .hljs-link { + color: #47688a; + } + .hljs-string { + color: #008313; + } + .hljs-doctag { + text-decoration: underline; + } + .hljs-emphasis { + font-style: italic; + } + .hljs-strong { + font-weight: bold; + } + .hljs-subst, + .hljs-title, + .hljs-params, + .hljs-bullet, + .hljs-formula, + .hljs-tag, + .hljs-type { + /* ignored */ + } + } +} diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/moon.svg b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/moon.svg new file mode 100644 index 0000000000000..856a8ffeeec21 --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/moon.svg @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template index d3b59f4f40bea..a32c44b8043b1 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template @@ -328,11 +328,7 @@ document.addEventListener("readystatechange", (e) => { }); document.addEventListener("DOMContentLoaded", function(e) { setTopMargin(); - // Make sure current element is visible in breadcrumb navigation on small displays const subnav = document.querySelector("ol.sub-nav-list"); - if (subnav && subnav.lastElementChild) { - subnav.lastElementChild.scrollIntoView({ behavior: "instant", inline: "start", block: "nearest" }); - } const keymap = new Map(); const searchInput = document.getElementById("search-input") || document.getElementById("page-search-input"); @@ -351,6 +347,49 @@ document.addEventListener("DOMContentLoaded", function(e) { const mainnav = navbar.querySelector("ul.nav-list"); const toggleButton = document.querySelector("button#navbar-toggle-button"); const tocMenu = sidebar ? sidebar.cloneNode(true) : null; + const themeButton = document.querySelector("button#theme-button"); + const themePanel = document.querySelector("div#theme-panel"); + var themePanelVisible = false; + themeButton.addEventListener("click", e => { + if (!themePanelVisible) { + let {x, y} = themeButton.getBoundingClientRect(); + themePanel.style.display = "block"; + if (window.innerHeight - 85 < y) { + themePanel.style.top = ""; + themePanel.style.bottom = "4px"; + } else { + themePanel.style.top = y + (expanded ? 0 : 36) + "px"; + themePanel.style.bottom = ""; + } + themePanel.style.left = x + (expanded ? 36 : 0) + "px"; + themeButton.setAttribute("aria-expanded", "true"); + themePanelVisible = true; + e.stopPropagation(); + } + }); + function closeThemePanel(e) { + if (themePanelVisible && (!e || !themePanel.contains(e.target))) { + themePanel.style.removeProperty("display"); + themeButton.setAttribute("aria-expanded", "false"); + themePanelVisible = false; + } + } + themePanel.querySelectorAll("input").forEach(input => { + input.removeAttribute("disabled"); + input.addEventListener("change", e => { + setTheme(e.target.value); + }) + }); + const THEMES = ["theme-light", "theme-dark", "theme-os"]; + function setTheme(theme) { + THEMES.forEach(t => { + if (t !== theme) document.body.classList.remove(t); + }); + document.body.classList.add(theme); + localStorage.setItem("theme", theme); + document.getElementById(theme).checked = true; + } + setTheme(localStorage.getItem("theme") || THEMES[0]); makeFilterWidget(sidebar, updateToc); if (tocMenu) { navbar.appendChild(tocMenu); @@ -362,6 +401,7 @@ document.addEventListener("DOMContentLoaded", function(e) { return; } if (!isInput(e.target) && keymap.has(e.key)) { + closeThemePanel(); var elem = keymap.get(e.key); if (elem === filterInput && !elem.offsetParent) { elem = getVisibleFilterInput(true); @@ -370,6 +410,7 @@ document.addEventListener("DOMContentLoaded", function(e) { elem.select(); e.preventDefault(); } else if (e.key === "Escape") { + closeThemePanel(); if (expanded) { collapse(); e.preventDefault(); @@ -389,6 +430,7 @@ document.addEventListener("DOMContentLoaded", function(e) { var windowWidth; var bodyHeight; function collapse() { + closeThemePanel(); if (expanded) { mainnav.removeAttribute("style"); if (tocMenu) { @@ -403,6 +445,7 @@ document.addEventListener("DOMContentLoaded", function(e) { } } function expand() { + closeThemePanel(); expanded = true; mainnav.style.display = "block"; mainnav.style.removeProperty("height"); @@ -457,6 +500,7 @@ document.addEventListener("DOMContentLoaded", function(e) { }); } document.querySelector("main").addEventListener("click", collapse); + document.querySelector("body").addEventListener("click", closeThemePanel); document.querySelectorAll("h1, h2, h3, h4, h5, h6") .forEach((hdr, idx) => { // Create anchor links for headers with an associated id attribute diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties index 9b111cb5edf35..5c654f2aff5ec 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties @@ -194,6 +194,10 @@ doclet.Window_Help_title=API Help doclet.references={0} references doclet.Window_Search_title=Search doclet.search.main_heading=Search +doclet.theme.select_theme=Select Theme +doclet.theme.light=Light +doclet.theme.dark=Dark +doclet.theme.system=System Setting # label for link/button element to show the information below doclet.search.show_more=Additional resources diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css index f7994c7f7ed3d..587121ad58207 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css @@ -28,13 +28,35 @@ /* Line height for continuous text blocks */ --block-line-height: 1.5; --code-line-height: 1.6; + /* Navigation bar and content area dimensions */ + --top-nav-height: 44px; + --sub-nav-height: 36px; + --nav-height: calc(var(--top-nav-height) + var(--sub-nav-height)); + --max-content-width: 1500px; + --content-margin: 0 auto; + /* Inline SVG icons for dark theme */ + --right-svg-dark: url('data:image/svg+xml; utf8, \ + \ + \ + '); + --glass-svg-dark: url('data:image/svg+xml; utf8, \ + \ + \ + '); + --x-svg-dark: url('data:image/svg+xml; utf8, \ + \ + \ + '); +} +body { /* Text colors for body and block elements */ --body-text-color: #181818; --block-text-color: #181818; /* Background colors for various elements */ --body-background-color: #ffffff; --section-background-color: var(--body-background-color); - --detail-background-color: #ffffff; + --detail-background-color: var(--body-background-color); --code-background-color: #f5f5f5; --mark-background-color: #f7f7f7; --detail-block-color: #f4f4f4; @@ -76,9 +98,10 @@ /* Search input colors */ --search-input-background-color: #ffffff; --search-input-text-color: #000000; - --search-input-placeholder-color: #909090; + --search-input-placeholder-color: #757575; /* Highlight color for active search tag target */ - --search-tag-highlight-color: #ffff66; + --search-tag-background-color: #ffff66; + --search-tag-text-color: var(--block-text-color); /* Copy button colors and filters */ --button-border-color: #b0b8c8; --button-active-filter: brightness(96%); @@ -86,12 +109,158 @@ /* Colors for invalid tag notifications */ --invalid-tag-background-color: #ffe6e6; --invalid-tag-text-color: #000000; - /* Navigation bar dimensions */ - --top-nav-height: 44px; - --sub-nav-height: 36px; - --nav-height: calc(var(--top-nav-height) + var(--sub-nav-height)); - --max-content-width: 1500px; - --content-margin: 0 auto; +} + +body.theme-dark { + --body-text-color: #e8e8e8; + --block-text-color: #e8e8e8; + --body-background-color: #222528; + --section-background-color: var(--body-background-color); + --detail-background-color: var(--body-background-color); + --code-background-color: #303940; + --mark-background-color: #313131; + --detail-block-color: #f4f4f4; + --navbar-background-color: #395A6F; + --navbar-text-color: #ffffff; + --subnav-background-color: #3d454d; + --subnav-link-color: #d8dcdf; + --member-heading-background-color: var(--subnav-background-color); + --selected-background-color: #f8981d; + --selected-text-color: #253441; + --selected-link-color: #4a698a; + --table-header-color: #38444d; + --even-row-color: #222528; + --odd-row-color: #2d3135; + --title-color: #fff; + --link-color: #94badb; + --link-color-active: #ffb45b; + --toc-background-color: #31363c; + --toc-highlight-color: var(--subnav-background-color); + --toc-hover-color: #3f4146; + --snippet-background-color: #2d363c; + --snippet-text-color: var(--block-text-color); + --snippet-highlight-color: #f7c590; + --pre-background-color: var(--snippet-background-color); + --pre-text-color: var(--snippet-text-color); + --border-color: #444444; + --table-border-color: #717171; + --tab-border-radius: 2px 2px 0 0; + --search-input-background-color: #303030; + --search-input-text-color: #d0d0d0; + --search-input-placeholder-color: #979797; + --search-tag-background-color: #c6c61e; + --search-tag-text-color: #282828; + --button-border-color: #909090; + --button-active-filter: brightness(96%); + --button-focus-filter: brightness(104%); + --invalid-tag-background-color: #ffe6e6; + --invalid-tag-text-color: #000000; + div.main-grid img { + filter: invert(100%) brightness(160%); + } +} + +/* + * Dark theme + */ +@media (prefers-color-scheme: dark) { + body { + --body-text-color: #e8e8e8; + --block-text-color: #e8e8e8; + --body-background-color: #222528; + --section-background-color: var(--body-background-color); + --detail-background-color: var(--body-background-color); + --code-background-color: #303940; + --mark-background-color: #313131; + --detail-block-color: #f4f4f4; + --navbar-background-color: #395A6F; + --navbar-text-color: #ffffff; + --subnav-background-color: #3d454d; + --subnav-link-color: #d8dcdf; + --member-heading-background-color: var(--subnav-background-color); + --selected-background-color: #f8981d; + --selected-text-color: #253441; + --selected-link-color: #4a698a; + --table-header-color: #38444d; + --even-row-color: #222528; + --odd-row-color: #2d3135; + --title-color: #fff; + --link-color: #94badb; + --link-color-active: #ffb45b; + --toc-background-color: #31363c; + --toc-highlight-color: var(--subnav-background-color); + --toc-hover-color: #3f4146; + --snippet-background-color: #2d363c; + --snippet-text-color: var(--block-text-color); + --snippet-highlight-color: #f7c590; + --pre-background-color: var(--snippet-background-color); + --pre-text-color: var(--snippet-text-color); + --border-color: #444444; + --table-border-color: #717171; + --tab-border-radius: 2px 2px 0 0; + --search-input-background-color: #303030; + --search-input-text-color: #d0d0d0; + --search-input-placeholder-color: #979797; + --search-tag-background-color: #c6c61e; + --search-tag-text-color: #282828; + --button-border-color: #909090; + --button-active-filter: brightness(96%); + --button-focus-filter: brightness(104%); + --invalid-tag-background-color: #ffe6e6; + --invalid-tag-text-color: #000000; + div.main-grid img { + filter: invert(100%) brightness(160%); + } + } + + body.theme-light { + --body-text-color: #282828; + --block-text-color: #282828; + --body-background-color: #ffffff; + --section-background-color: var(--body-background-color); + --detail-background-color: var(--body-background-color); + --code-background-color: #f5f5f5; + --mark-background-color: #f7f7f7; + --detail-block-color: #f4f4f4; + --navbar-background-color: #4D7A97; + --navbar-text-color: #ffffff; + --subnav-background-color: #dee3e9; + --subnav-link-color: #47688a; + --member-heading-background-color: var(--subnav-background-color); + --selected-background-color: #f8981d; + --selected-text-color: #253441; + --selected-link-color: #4a698a; + --table-header-color: #ebeff4; + --even-row-color: #ffffff; + --odd-row-color: #f0f0f2; + --title-color: #2c4557; + --link-color: #437291; + --link-color-active: #bb7a2a; + --toc-background-color: #f8f8f8; + --toc-highlight-color: var(--subnav-background-color); + --toc-hover-color: #e9ecf0; + --snippet-background-color: #f2f2f4; + --snippet-text-color: var(--block-text-color); + --snippet-highlight-color: #f7c590; + --pre-background-color: var(--snippet-background-color); + --pre-text-color: var(--snippet-text-color); + --border-color: #e6e6e6; + --table-border-color: #000000; + --tab-border-radius: 2px 2px 0 0; + --search-input-background-color: #ffffff; + --search-input-text-color: #000000; + --search-input-placeholder-color: #757575; + --search-tag-background-color: #ffff66; + --search-tag-text-color: var(--block-text-color); + --button-border-color: #b0b8c8; + --button-active-filter: brightness(96%); + --button-focus-filter: brightness(104%); + --invalid-tag-background-color: #ffe6e6; + --invalid-tag-text-color: #000000; + div.main-grid img { + filter: none; + } + } } /* * Styles for individual HTML elements. @@ -186,7 +355,7 @@ hr { */ .about-language { flex: 0 0 auto; - padding:0 20px; + padding:0 20px 0 10px; margin:0; font-size:0.915em; max-width: 50%; @@ -215,6 +384,7 @@ hr { height: 100%; max-width: var(--max-content-width); margin: var(--content-margin); + position: relative; } .top-nav { background-color:var(--navbar-background-color); @@ -236,6 +406,68 @@ hr { button#navbar-toggle-button { display:none; } +button#theme-button { + position: relative; + top: -9.5px; + width: 32px; + height: 32px; + padding: 6px; + margin-left: -6px; + background-color: transparent; + border: 1px solid transparent; + border-radius: 6px; + cursor: pointer; +} +button#theme-button:hover, +button#theme-button:focus-visible { + border: 1px solid var(--button-border-color); +} +button#theme-button img { + display: none; + width: 18px; +} +body.theme-light button#theme-button img.theme-light { + display: inline; +} +body.theme-dark button#theme-button img.theme-dark { + display: inline; +} +@media (prefers-color-scheme: dark) { + body.theme-os button#theme-button img.theme-dark { + display: inline; + } +} +@media (prefers-color-scheme: light) { + body.theme-os button#theme-button img.theme-light { + display: inline; + } +} +div#theme-panel { + display: none; + position: fixed; + z-index: 8; + background-color: var(--toc-background-color); + color: var(--body-text-color); + padding: 4px; + white-space: nowrap; + border: 1px solid var(--border-color); + border-radius: 4px; + box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); +} +div#theme-panel div:first-child { + font-weight: bold; + font-size: 16px; +} +div#theme-panel div { + padding: 8px; +} +div#theme-panel label { + margin-right: 8px; + cursor: pointer; +} +div#theme-panel input { + margin-right: 4px; +} ul.nav-list { display:inline-flex; margin:0; @@ -252,28 +484,25 @@ ul.nav-list li { div.sub-nav { background-color:var(--subnav-background-color); width:100%; - overflow:hidden; font-size:var(--nav-font-size); - height: var(--sub-nav-height); + min-height: var(--sub-nav-height); } ol.sub-nav-list { flex: 1 1 90%; - line-height: 1.8; - display: inline-flex; + line-height: 1.7; overflow: auto; - scroll-snap-type: x mandatory; - scroll-padding-left: 13px; - scrollbar-width: none; padding-left:6px; - white-space: nowrap; - margin:0; + margin: 4px 0; + min-height: 28px; } ol.sub-nav-list::-webkit-scrollbar { display: none; } ol.sub-nav-list li { list-style:none; - scroll-snap-align: start; + display: inline-block; + padding: 2px 0; + margin-right: -4px; } ol.sub-nav-list li:not(:first-child) { background: url("right.svg") no-repeat 3px; @@ -281,6 +510,17 @@ ol.sub-nav-list li:not(:first-child) { padding-left: 17px; list-style: none; } +body.theme-dark ol.sub-nav-list li:not(:first-child) { + background-image: var(--right-svg-dark); +} +@media (prefers-color-scheme: dark) { + ol.sub-nav-list li:not(:first-child) { + background-image: var(--right-svg-dark); + } + body.theme-light ol.sub-nav-list li:not(:first-child) { + background-image: url("right.svg"); + } +} ol.sub-nav-list a { padding: 3px; } @@ -290,7 +530,8 @@ ol.sub-nav-list a.current-selection { } .sub-nav .nav-list-search { flex: 1 1 10%; - margin: 0 15px; + margin: 4.5px 15px auto 5px; + padding: 1px 0; position:relative; white-space: nowrap; } @@ -362,7 +603,7 @@ body.class-declaration-page section.detail > h3:target { } body.class-declaration-page section.detail:target > h3 > a.anchor-link > img, body.class-declaration-page section.detail > h3:target > a.anchor-link > img { - filter: invert(100%) sepia(4%) saturate(98%) hue-rotate(212deg) brightness(160%) contrast(160%); + filter: invert(100%) brightness(160%); } h1 > sup { font-size: small; @@ -1015,7 +1256,7 @@ li.ui-static-link a, li.ui-static-link a:visited { .ui-autocomplete .search-result-desc { font-size: var(--nav-font-size); padding: 2px 4px; - color: #404040; + color: var(--block-text-color); overflow: hidden; text-overflow: ellipsis; } @@ -1023,7 +1264,7 @@ li.ui-static-link a, li.ui-static-link a:visited { font-weight:bold; } .ui-menu .ui-state-active .search-result-desc { - color: #383838; + color: var(--selected-text-color); } .ui-menu .ui-menu-item-wrapper { padding: 3px 4px; @@ -1042,6 +1283,17 @@ input[type="text"] { font-size: var(--nav-font-size); height: 19px; } +body.theme-dark input[type="text"] { + background-image: var(--glass-svg-dark); +} +@media (prefers-color-scheme: dark) { + input[type="text"] { + background-image: var(--glass-svg-dark); + } + body.theme-light input[type="text"] { + background-image: url('glass.svg'); + } +} input#page-search-input { width: calc(180px + 10vw); margin: 10px 0; @@ -1069,6 +1321,21 @@ input#reset-search, input.reset-filter, input#page-search-reset { font-size:0; visibility:hidden; } +body.theme-dark input#reset-search, +body.theme-dark input.reset-filter, +body.theme-dark input#page-search-reset { + background-image: var(--x-svg-dark); +} +@media (prefers-color-scheme: dark) { + input#reset-search, input.reset-filter, input#page-search-reset { + background-image: var(--x-svg-dark); + } + body.theme-light input#reset-search, + body.theme-light input.reset-filter, + body.theme-light input#page-search-reset { + background-image: url('x.svg'); + } +} input#reset-search { position:absolute; right:5px; @@ -1101,6 +1368,7 @@ select#search-modules { } kbd { background-color: #eeeeee; + color: #282828; border: 1px solid #b0b0b0; border-radius: 3px; padding: 0 4px; @@ -1109,11 +1377,13 @@ kbd { font-weight: bold; } .search-tag-result:target { - background-color:var(--search-tag-highlight-color); + background-color:var(--search-tag-background-color); + color:var(--search-tag-text-color); } dd > span:target, h1 > span:target { - background-color: var(--search-tag-highlight-color); + background-color: var(--search-tag-background-color); + color:var(--search-tag-text-color); } section.class-description dd > span:target, section.class-description h1 > span:target { @@ -1160,6 +1430,7 @@ div#result-container { #result-container div.result-table > a.search-result-link:focus-visible, #result-container div.result-table > a.search-result-link.selected { background-color: var(--selected-background-color); + color: var(--selected-text-color); outline: none; } #result-container div.result-table > a.search-result-link .search-result-label { @@ -1168,7 +1439,6 @@ div#result-container { } #result-container div.result-table > a.search-result-link .search-result-desc { font-size: var(--nav-font-size); - color: #404040; overflow: hidden; text-overflow: ellipsis; } @@ -1502,17 +1772,6 @@ table.striped > tbody > tr > th { .top-nav nav.toc ol.toc-list li { font-size: 1.04em; } - nav.toc a:link, nav.toc a:visited { - text-decoration:none; - color:var(--link-color); - } - nav.toc a[href]:hover, nav.toc a[href]:focus { - text-decoration:none; - color:var(--link-color-active); - } - :root { - scroll-behavior: auto; - } header { max-height: 100vh; overflow-y: visible; @@ -1603,7 +1862,6 @@ table.striped > tbody > tr > th { } @media screen and (max-width: 800px) { .about-language { - padding: 0 16px; max-width: 90%; } ul.nav-list li { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/sun.svg b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/sun.svg new file mode 100644 index 0000000000000..e8fa03499acc3 --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/sun.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/x.svg b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/x.svg index 1efb410924132..34a942ffff10b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/x.svg +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/x.svg @@ -8,6 +8,6 @@ --> - - - \ No newline at end of file + + + diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java index 21f1267361954..7bc4da604196c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java @@ -115,6 +115,12 @@ public static DocPath indexN(int n) { /** The name of the right pointing angle icon. */ public static final DocPath RIGHT_SVG = DocPath.create("right.svg"); + /** The name of the moon icon for the dark theme. */ + public static final DocPath MOON_SVG = DocPath.create("moon.svg"); + + /** The name of the sun icon for the light theme. */ + public static final DocPath SUN_SVG = DocPath.create("sun.svg"); + /** The name of the syntax highlighting style sheet. */ public static final DocPath HIGHLIGHT_CSS = DocPath.create("highlight.css"); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlAttr.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlAttr.java index 10aa7c0c57b26..2ef3ae9db2a06 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlAttr.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlAttr.java @@ -203,6 +203,7 @@ public String toString() { public enum InputType { CHECKBOX, + RADIO, RESET, TEXT; diff --git a/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java b/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java index ee1fa538a57d6..ba846c293a23b 100644 --- a/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java +++ b/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java @@ -143,6 +143,9 @@ void run() throws Exception { "search-result-desc", "search-result-label", "search-result-link", "selected", "sort-asc", "sort-desc", "two-column-search-results", "visible"); + // used for themes + removeAll(styleSheetNames, "theme-dark", "theme-light", "theme-os"); + // very JDK specific styleSheetNames.remove("module-graph"); styleSheetNames.remove("sealed-graph"); diff --git a/test/langtools/jdk/javadoc/doclet/testNavigation/TestModuleNavigation.java b/test/langtools/jdk/javadoc/doclet/testNavigation/TestModuleNavigation.java index 2614b352b7127..b4f28b36f3f36 100644 --- a/test/langtools/jdk/javadoc/doclet/testNavigation/TestModuleNavigation.java +++ b/test/langtools/jdk/javadoc/doclet/testNavigation/TestModuleNavigation.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8196027 8196202 8320458 + * @bug 8196027 8196202 8320458 8342705 * @summary test navigation links * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main @@ -87,6 +87,9 @@ public void testSingleModule(Path base) throws Exception {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("overview-tree.html", true, @@ -98,6 +101,9 @@ public void testSingleModule(Path base) throws Exception {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("deprecated-list.html", true, @@ -109,6 +115,9 @@ public void testSingleModule(Path base) throws Exception {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("index-all.html", true, @@ -120,6 +129,9 @@ public void testSingleModule(Path base) throws Exception {
  • Search
  • Help
  • +
  • """); checkOutput("search.html", true, @@ -131,6 +143,9 @@ public void testSingleModule(Path base) throws Exception {
  • Index
  • Help
  • +
  • """); checkOutput("help-doc.html", true, @@ -142,6 +157,9 @@ public void testSingleModule(Path base) throws Exception {
  • Index
  • Search
  • +
  • """); checkOutput("m/p1/package-summary.html", true, @@ -154,6 +172,9 @@ public void testSingleModule(Path base) throws Exception {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("m/p1/A.html", true, @@ -166,6 +187,9 @@ public void testSingleModule(Path base) throws Exception {
  • Index
  • Search
  • Help
  • +
  • """); } diff --git a/test/langtools/jdk/javadoc/doclet/testNavigation/TestNavigation.java b/test/langtools/jdk/javadoc/doclet/testNavigation/TestNavigation.java index f7cbb78fbeb44..5be754a3163c6 100644 --- a/test/langtools/jdk/javadoc/doclet/testNavigation/TestNavigation.java +++ b/test/langtools/jdk/javadoc/doclet/testNavigation/TestNavigation.java @@ -25,6 +25,7 @@ * @test * @bug 7025314 8023700 7198273 8025633 8026567 8081854 8196027 8182765 * 8196200 8196202 8223378 8258659 8261976 8320458 8329537 8350638 + * 8342705 * @summary Make sure the Next/Prev Class links iterate through all types. * Make sure the navagation is 2 columns, not 3. * @library /tools/lib ../../lib @@ -70,6 +71,9 @@ public void testOverview(Path base) {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("pkg/package-summary.html", true, @@ -81,6 +85,9 @@ public void testOverview(Path base) {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("pkg/A.html", true, @@ -92,6 +99,9 @@ public void testOverview(Path base) {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("pkg/C.html", true, @@ -103,6 +113,9 @@ public void testOverview(Path base) {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("pkg/E.html", true, @@ -114,6 +127,9 @@ public void testOverview(Path base) {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("pkg/I.html", true, @@ -339,6 +355,9 @@ public void testSinglePackage(Path base) {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("pkg/A.html", true, @@ -350,6 +369,9 @@ public void testSinglePackage(Path base) {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("pkg/C.html", true, @@ -361,6 +383,9 @@ public void testSinglePackage(Path base) {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("pkg/E.html", true, @@ -372,6 +397,9 @@ public void testSinglePackage(Path base) {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("pkg/I.html", true, @@ -411,6 +439,9 @@ public void testUnnamedPackage(Path base) throws Exception {
  • Index
  • Search
  • Help
  • +
  • """, """