diff --git a/websites/apidocs/Templates/LuceneTemplateAssets/styles/main.css b/websites/apidocs/Templates/LuceneTemplateAssets/styles/main.css index d5504cb40a..b420cbfe95 100644 --- a/websites/apidocs/Templates/LuceneTemplateAssets/styles/main.css +++ b/websites/apidocs/Templates/LuceneTemplateAssets/styles/main.css @@ -17,159 +17,788 @@ * under the License. */ -/* .navbar-inverse { - background: #4a95da; - background: rgb(44, 95, 163); - background: -moz-linear-gradient(top, rgba(44, 95, 163, 1) 0%, rgba(64, 150, 238, 1) 100%); - background: -webkit-linear-gradient(top, rgba(44, 95, 163, 1) 0%, rgba(64, 150, 238, 1) 100%); - background: linear-gradient(to bottom, rgba(44, 95, 163, 1) 0%, rgba(64, 150, 238, 1) 100%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#2c5fa3', endColorstr='#4096ee', GradientType=0); - border-color:white; +/* 0. Design tokens / variables (centralized) */ +:root { + /* sizes */ + --nav-h: 80px; + --brand-h: 55px; + --submenu-min-width: 260px; + --ribbon-safe-zone: 0; + --nav-wrap-extra: 0; /* default extra offset when navbar wraps */ + + /* colors */ + --color-bg: #ffffff; + --color-primary: #0095eb; + --color-primary-contrast: #ffffff; + --color-muted: #143653; + --color-muted-2: #0f2a40; + --color-border: #e5e7eb; + --color-subnav-bg: #f7f7f7; + --color-breadcrumb: #bbb; + --color-ribbon-bg: #1764aa; + + /* shadows & z-index */ + --shadow-lg: 0 8px 24px rgba(0,0,0,.12); + --shadow-ribbon: 4px 4px 10px rgba(0,0,0,.8); + --z-nav: 1000; + --z-dropdown: 1001; + --z-ribbon: 9999; +} + +/* Respect reduced motion preference */ +@media (prefers-reduced-motion: reduce) { + * { + transition: none !important; + animation: none !important; } - .navbar-inverse .navbar-nav>li>a, .navbar-inverse .navbar-text { - color: #fff; +} + +/* 1. Navbar & Header + ------------------ */ + +/* 1.1 Basic header / navbar */ +nav.navbar { + background: var(--color-bg); + min-height: var(--nav-h); + margin-bottom: 8px !important; +} + +#wrapper > header, +header { + position: relative; + z-index: var(--z-nav); + margin-bottom: 0; + background: var(--color-bg); +} + +/* 1.2.1 Brand/logo sizing */ +.navbar-brand { + height: var(--nav-h); +} + +.navbar-header .navbar-brand img { + height: var(--brand-h); + width: auto; + margin: calc((var(--nav-h) - var(--brand-h))/2) 10px; + display: block; +} + +/* 1.2.2 Nav links vertical centering on >=768 */ +@media (min-width:768px) { + header ul.navbar-nav > li > a { + padding-top: calc((var(--nav-h) - 34px)/2); + padding-bottom: calc((var(--nav-h) - 34px)/2); + line-height: 34px; + font-size: 16px; + font-weight: 600; } - .navbar-inverse .navbar-nav>.active>a { - background-color: #1764AA; + /* small gap after last item */ + #navbar > ul.navbar-nav { + margin-right: 6px !important; } - .navbar-inverse .navbar-nav>.active>a:focus, .navbar-inverse .navbar-nav>.active>a:hover { - background-color: #1764AA; - } */ +} -.btn-primary:hover { - background-color: #1764aa; +/* 1.2.3 Ensure the nav list never inherits stray margins */ +#navbar .navbar-nav { + margin: 0 !important; } -button, -a { - color: #0098ff; + +/* 1.2.4 Clear default body padding reserved for fixed navbars */ +body { + padding-top: 0 !important; } -button:hover, -button:focus, -a:hover, -a:focus { - color: #0098ff; + +/* 1.3 Collapsed / desktop toggle behavior (JS toggles #autocollapse.collapsed) */ +#autocollapse.collapsed .navbar-toggle { + display: block !important; + visibility: visible !important; + opacity: 1; + z-index: 2001; } -a:hover { - text-decoration: underline; + +#autocollapse.collapsed #navbar { + display: none; } -.expand-stub + a { - font-weight: normal; + +#autocollapse.collapsed #navbar.collapse.in { + display: block !important; } -nav.navbar { - background-color: white; - min-height: 80px; + +/* 1.3.1 Desktop shows nav, hides hamburger */ +#autocollapse:not(.collapsed) #navbar { + display: block !important; } -.navbar-brand { - height: 80px; + +#autocollapse:not(.collapsed) .navbar-toggle { + display: none !important; } -.navbar-header .navbar-brand img { - width: 300px; - height: 55px; - margin: 10px 10px 10px 0px; + +/* 1.4 Hamburger button appearance */ +#autocollapse .navbar-toggle { + background: transparent; + border: 1px solid var(--color-primary); + border-radius: 4px; + padding: 10px 12px; + line-height: 1; + margin-top: 18px; + transition: box-shadow .12s ease, border-color .12s ease; +} + + #autocollapse .navbar-toggle:focus, + #autocollapse .navbar-toggle:focus-visible { + outline: none; + box-shadow: 0 0 0 3px rgba(0,149,235,0.18); + border-color: #00598d; + } + +#autocollapse .navbar-toggle .icon-bar { + width: 24px; + height: 3px; + background-color: var(--color-primary); } -.navbar-toggle .icon-bar { - margin-top: 2px; - background-color: #0095eb; + +#autocollapse .navbar-toggle .icon-bar + .icon-bar { + margin-top: 4px; } -.navbar-toggle { - border-color: #0095eb; + +/* 1.5 Ensure hamburger hidden on desktop */ +#autocollapse:not(.collapsed) .navbar-toggle { + display: none !important; } -header ul.navbar-nav { - /*font-size: 1.2em;*/ - float: right; + +/* 2. ASF Dropdown + ---------------- */ + +/* 2.1 Base structure */ +.navbar-nav > li.nav-asf { + position: relative; +} + +.navbar-nav > li.nav-asf > .expand-stub { + display: none !important; +} + +.navbar-nav .nav-asf > a { + display: flex; + align-items: center; + gap: .35rem; font-weight: 600; } -/* Keep Fork me on Github from overlapping menu */ -@media screen and (min-width: 768px) and (max-width: 1400px) { - header #navbar, header button.navbar-toggle { - margin-right: 150px !important; + +.navbar-nav .nav-asf > a .lucene-caret { + display: inline-block; + width: 1em; + text-align: center; +} + +/* 2.2 Submenu style (unified across desktop & mobile) */ +.navbar-nav > li.nav-asf > ul.nav.level2.asf-menu > li > a { + font-size: 15px; + line-height: 1.34; + font-weight: 500; + color: var(--color-muted); + opacity: .95; + padding: .48rem .9rem; + white-space: nowrap; +} + +.navbar-nav > li.nav-asf > ul.nav.level2.asf-menu > li > a:hover { + background: #f2f6fb; + color: var(--color-muted-2); +} + +/* 2.3 Desktop hover dropdown (>=768) — overlay with fade/slide */ +@media (min-width:768px) { + #autocollapse:not(.collapsed) .navbar-nav > li.nav-asf > a .lucene-caret::after { + content: "▾"; } - header #navbar.in, header #navbar.collapsing { - margin-right: 0 !important; + + #autocollapse:not(.collapsed) .navbar-nav > li.nav-asf:hover > a .lucene-caret::after, + #autocollapse:not(.collapsed) .navbar-nav > li.nav-asf:focus-within > a .lucene-caret::after { + content: "▴"; + } + + #autocollapse:not(.collapsed) .navbar-nav > li.nav-asf > ul.nav.level2.asf-menu { + position: absolute; + top: 100%; + left: 0; + min-width: var(--submenu-min-width); + background: var(--color-bg); + border: 1px solid var(--color-border); + border-radius: 8px; + padding: .35rem 0; + box-shadow: var(--shadow-lg); + opacity: 0; + pointer-events: none; + transform: translateY(6px); + transition: transform .16s ease, opacity .16s ease; + z-index: var(--z-dropdown); + } + + #autocollapse:not(.collapsed) .navbar-nav > li.nav-asf:hover > ul.nav.level2.asf-menu, + #autocollapse:not(.collapsed) .navbar-nav > li.nav-asf:focus-within > ul.nav.level2.asf-menu { + opacity: 1; + pointer-events: auto; + transform: translateY(0); + } + + /* Ensure desktop dropdown does not affect layout (overlay) */ + #autocollapse:not(.collapsed) .navbar-nav > li.nav-asf > ul.nav.level2.asf-menu { + display: block; } } -.sidefilter { - top: 120px; +/* 2.4 Mobile accordion closed by default */ +#autocollapse.collapsed .navbar-nav > li.nav-asf > a { + justify-content: flex-start; + width: 100%; +} + +#autocollapse.collapsed .navbar-nav > li.nav-asf > a .lucene-caret::after { + content: "▸"; +} + +#autocollapse.collapsed .navbar-nav > li.nav-asf.is-open > a .lucene-caret::after { + content: "▾"; +} + +/* 2.4.1 Animated accordion implementation */ +#autocollapse.collapsed .navbar-nav > li.nav-asf > ul.nav.level2.asf-menu { + position: static !important; + max-height: 0; + overflow: hidden; + transition: max-height .25s ease; + margin-left: .5rem; + padding-left: .5rem; + border-left: none; } -.sidetoc { - top: 180px; - background-color: rgb(247, 247, 247); +#autocollapse.collapsed .navbar-nav > li.nav-asf.is-open > ul.nav.level2.asf-menu { + max-height: 1000px; } -body .toc { - background-color: rgb(247, 247, 247); +/* 2.5 Collapsed column layout (centered column, left-aligned items) */ +#autocollapse.collapsed #navbar .navbar-nav { + float: none !important; + width: min(560px, 90vw); + margin: 8px auto; + text-align: left; +} + +/* 2.6 Unified left-start & submenu indent variables for collapsed */ +#autocollapse.collapsed { + --m-left: 16px; + --submenu-indent: 24px; +} + +#autocollapse.collapsed .navbar-nav > li > a { + display: block; + padding: 10px 12px 10px var(--m-left); +} + +#autocollapse.collapsed .navbar-nav > li.nav-asf > a { + gap: .35rem; + padding-left: var(--m-left); +} + +#autocollapse.collapsed .navbar-nav > li.nav-asf > ul.nav.level2.asf-menu > li > a { + padding: 8px 12px 8px calc(var(--m-left) + var(--submenu-indent)); +} + +/* 2.7 768–1199: force full navbar (no compact/hamburger), sticky header and reduced button height */ +@media (min-width:768px) and (max-width:1199px) { + /* Force full navbar visible and hide hamburger regardless of the JS .collapsed state */ + #autocollapse .navbar-toggle { + display: none !important; + visibility: hidden !important; + opacity: 0 !important; + margin-right: 0 !important; + position: static !important; + z-index: auto !important; + } + + /* Make header sticky in this range (restore desktop sticky behaviour) */ + header.is-sticky, #wrapper > header.is-sticky { + position: sticky !important; + top: 0 !important; + z-index: var(--z-nav); + background: var(--color-bg); + } + + header.is-sticky nav.navbar { + box-shadow: 0 1px 0 rgba(0,0,0,.06); + margin-bottom: 0 !important; + } + + /* Reduce nav button height further to keep more content visible when the nav wraps under the logo */ + header ul.navbar-nav > li > a { + padding-top: 6px; + padding-bottom: 6px; + line-height: 30px; + font-size: 15px; + font-weight: 600; + } + + /* Ensure navbar items layout behaves like desktop (allow wrapping but avoid the collapsed centered column) */ + #autocollapse .navbar-nav { + float: none !important; + width: auto !important; + margin: 0 !important; + text-align: left !important; + white-space: normal; + } + + #autocollapse.collapsed #navbar .navbar-nav { + width: auto !important; + margin: 0 !important; + } + + /* Keep submenu/padding sensible in this width range */ + #autocollapse.collapsed .navbar-nav > li.nav-asf > a { + padding-left: 12px; + } + + #autocollapse.collapsed .navbar-nav > li.nav-asf > ul.nav.level2.asf-menu > li > a { + padding: 6px 12px 6px calc(12px + 24px); + } + + /* tuned extra offset only in this wrap range */ + :root { + --nav-wrap-extra: 20px; + } + + html { + scroll-padding-top: calc(var(--nav-h) + var(--nav-wrap-extra) + 4px); + } + + .sidefilter { + top: calc(var(--nav-h) + 40px + var(--nav-wrap-extra)) !important; + } + + .sidetoc { + top: calc(var(--nav-h) + 100px + var(--nav-wrap-extra)) !important; + } + + /* 2.8.1 Reduce padding to avoid shrinking */ + @media (min-width:768px) and (max-width:991px) { + body #autocollapse .navbar-nav > li > a { + padding-left: 9px !important; + padding-right: 9px !important; + } + } + /* Reverting the earlier */ + @media (min-width:992px) { + body #autocollapse .navbar-nav > li > a { + padding-left: 15px !important; + padding-right: 15px !important; + } + } } -.sidefilter { - background-color: rgb(247, 247, 247); +/* 3. Sticky header for desktop (>=1200) (JS still toggles .is-sticky) */ +#wrapper > header.is-sticky, +header.is-sticky { + position: sticky; + top: 0; + z-index: var(--z-nav); + background: var(--color-bg); } -.level0.breadcrumb .level1.breadcrumb { - display: inline; +header.is-sticky nav.navbar { + box-shadow: 0 1px 0 rgba(0,0,0,.06); + margin-bottom: 0 !important; } -.level0.breadcrumb .level1.breadcrumb > li:before { - content: "\00a0/"; - padding: 0 5px; - color: #ccc; +/* 4. GitHub ribbon + ---------------------------------------- */ +#forkongithub { + display: block; } -/* FORK ME ON GITHUB */ #forkongithub a { - background: #1764aa; - color: #fff; + background: var(--color-ribbon-bg); + color: var(--color-primary-contrast); text-decoration: none; - font-family: arial, sans-serif; - text-align: center; font-weight: bold; padding: 5px 40px; font-size: 1rem; line-height: 2rem; position: relative; - transition: 0.5s; -} -#forkongithub a:hover { - background: black; - color: #fff; + transition: .5s; + font-family: arial,sans-serif; + text-align: center; } -#forkongithub a::before, -#forkongithub a::after { + +#forkongithub a::before, #forkongithub a::after { content: ""; width: 100%; display: block; position: absolute; - top: 1px; left: 0; height: 1px; - background: #fff; + background: var(--color-primary-contrast); +} + +#forkongithub a::before { + top: 1px; } + #forkongithub a::after { bottom: 1px; top: auto; } -@media screen and (min-width: 768px) { + +#forkongithub a:hover { + background: black; + color: var(--color-primary-contrast); +} + +@media (min-width:768px) { #forkongithub { position: fixed; - display: block; top: 0; right: 0; width: 200px; + height: 150px; overflow: hidden; - height: 200px; - z-index: 9999; + z-index: var(--z-ribbon); } + #forkongithub a { width: 200px; position: absolute; top: 40px; right: -40px; transform: rotate(45deg); - -webkit-transform: rotate(45deg); - -ms-transform: rotate(45deg); - -moz-transform: rotate(45deg); - -o-transform: rotate(45deg); - box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.8); + box-shadow: var(--shadow-ribbon); + } +} + +/* 4.1 Keep a safe margin for the ribbon on mid widths so the nav doesn't collide */ +@media (min-width:768px) and (max-width:1500px) { + #autocollapse:not(.collapsed) #navbar, + #autocollapse:not(.collapsed) .navbar-toggle { + margin-right: var(--ribbon-safe-zone) !important; + } + /* except when the collapse is open */ + #autocollapse:not(.collapsed) #navbar.in, + #autocollapse:not(.collapsed) #navbar.collapsing { + margin-right: 0 !important; + } +} + +/* 5. Subnav / breadcrumb / spacing rules + ------------------------------------------------------- */ +.subnav.navbar { + margin: 0 0 16px 0 !important; + min-height: 40px; + border: none; + box-shadow: none; + background: var(--color-bg); + position: relative; + z-index: 900; + background-color: var(--color-subnav-bg) !important; + border-bottom: 1px solid #e5e7e5 !important; + box-shadow: inset 0 1px 0 rgba(255,255,255,.5); +} + +.subnav.navbar .container { + padding: 8px 0; +} + +.subnav.navbar .breadcrumb { + margin: 0; + background: transparent; + padding: 0; +} + +.subnav.navbar .breadcrumb > li + li:before { + content: "/"; + color: var(--color-breadcrumb); + padding: 0 6px; +} + +.subnav.navbar .breadcrumb > li { + display: inline-block; +} + +/* 5.1 Breadcrumb padding adjustments */ +.subnav.navbar #breadcrumb { + padding-left: 28px; +} + +@media (min-width:1200px) { + .subnav.navbar #breadcrumb { + padding-left: 34px; } } + +@media (min-width:1600px) { + .subnav.navbar #breadcrumb { + padding-left: 40px; + } +} + +/* 6. First-content padding / margin-collapse prevention + ---------------------------------------------------- */ +.container.body-content, +.content.wrap, +.home-section:first-of-type, +.container.body-content:first-of-type, +.content.wrap:first-of-type, +.article.row.grid:first-of-type { + overflow: auto !important; +} + +/* 6.1 Default small top padding */ +.container.body-content:first-of-type, +.content.wrap:first-of-type, +.article.row.grid:first-of-type { + padding-top: 8px !important; + margin-top: 0 !important; +} + +#homepage .home-section:first-of-type { + padding-top: 8px !important; + margin-top: 0 !important; + overflow: auto !important; +} + +#homepage .home-section:first-of-type .container > h1:first-child, +.container.body-content h1:first-child, +.content.wrap > h1:first-child, +.article.row.grid h1:first-child { + margin-top: 0 !important; +} + +#homepage .home-section:first-of-type h1:first-child { + /* 6.2 Making sure the first block starts without a gap */ + padding-top: 0 !important; + margin-top: 0 !important; +} + +.article.row.grid-right { + margin-top: 0px; +} + +/* 6.3 Layout should stay consistent after the header */ +#wrapper > header + * { + margin-top: 0 !important; +} + +#wrapper > header + *:not(.subnav):not(.navbar) { + padding-top: 8px !important; + overflow: auto; +} + +/* 6.5 Ensure header does not cover target */ +html { + scroll-padding-top: 84px; +} + +/* 7. Side TOC offsets (kept) */ +@media (max-width:1199px) { + .sidefilter { + top: calc(var(--nav-h) + 80px) !important; + } + + .sidetoc { + top: calc(var(--nav-h) + 140px) !important; + } +} + +@media (min-width:1200px) { + .sidefilter { + top: calc(var(--nav-h) + 40px) !important; + } + + .sidetoc { + top: calc(var(--nav-h) + 100px) !important; + } +} + +/* 8. Misc / defensive adjustments + ------------------------------- */ + +/* 8.1 Ensure top-level nav font weight control */ +header ul.navbar-nav { + font-weight: normal !important; +} + +header ul.navbar-nav > li > a { + font-weight: 600 !important; +} + +/* 8.2 Ensure ASF submenu tone consistent in both collapsed and desktop */ +#autocollapse .navbar-nav > li.nav-asf ul.asf-menu a { + font-size: 15px; + line-height: 1.34; + font-weight: 400; + color: var(--color-muted); + opacity: .95; +} + +/* 8.3 Hamburger ASF improvements */ +#autocollapse.collapsed .navbar-nav > li.nav-asf > a .lucene-caret { + margin-left: .1rem; +} + +#autocollapse.collapsed .navbar-nav > li.nav-asf > a .lucene-caret::after { + content: "▸"; +} + +#autocollapse.collapsed .navbar-nav > li.nav-asf.is-open > a .lucene-caret::after { + content: "▾"; +} + +/* 8.4 Defensive: ensure desktop ASF dropdowns overlay (consolidated) */ +#autocollapse:not(.collapsed) .navbar-nav > li.nav-asf > ul.nav.level2.asf-menu { + position: absolute; + top: 100%; + left: 0; + z-index: var(--z-dropdown); +} + +/* Accessibility: visible focus for keyboard users */ +a:focus-visible, +button:focus-visible { + outline: 3px solid rgba(0,0,0,0.12); + outline-offset: 2px; +} + +/* 8.6 Small-screen ToC bleeding prevention (fixed broken media query) */ +@media (max-width:767.98px) { + .sidenav .sidetoggle.collapse { + display: block !important; + height: 0 !important; + overflow: hidden !important; + visibility: hidden !important; + } + /* Open state */ + .sidenav .sidetoggle.collapse.in { + height: auto !important; + overflow: visible !important; + visibility: visible !important; + } + } + + /* 9. APIDOCS-ONLY — Search inserted into navbar as a nav item + The search input is styled to match nav links and participate in wrapping. + */ + + /* 9.1 MOBILE (≤767): search in hamburger, full width, should stay as it was */ + @media (max-width:767px) { + #autocollapse .navbar-form#search { + display: block !important; + float: none !important; + width: 100%; + padding: 10px 15px; + margin: 0; + border: 0; + box-shadow: none; + } + + #autocollapse #search .form-control { + width: 100% !important; + } + + #autocollapse .navbar-form.navbar-right { + margin: 0 !important; + } + } + + /* 9.2 APIDOCS 768–1199: Nav + Search wraps */ + @media (min-width:768px) and (max-width:1199px) { + /* SEARCH: float right on the first row (next to logo) */ + #autocollapse .navbar-form#search { + display: block !important; + float: right !important; /* put it on Row 1 */ + padding: 0 !important; + border: 0 !important; + box-shadow: none !important; + } + + /* Kill the 100% block width on DocFX/bootstrap overrides */ + #autocollapse #search .form-group { + display: inline-block !important; + width: auto !important; + margin: 0 !important; + } + /* Fixed, tidy input width (but still responsive) */ + #autocollapse #search .form-control { + width: 210px !important; + max-width: 40vw; + height: 34px; + line-height: 34px; + padding: 6px 10px; + border-radius: 4px; + border: 1px solid #dedede; + vertical-align: middle; + } + + /* NAVBAR-COLLAPSE becomes another row under the logo */ + #autocollapse .navbar-collapse { + clear: both; + width: 100%; + float: none; + display: block !important; /* override any previous flex */ + padding: 0; + border: 0; + box-shadow: none; + } + + /* Center nav items and search */ + #autocollapse ul.navbar-nav { + float: none; + display: flex; + align-items: center; + margin: 0; + padding: 0; + } + + #autocollapse ul.navbar-nav > li { + float: none; + } + + /* Making sure the right affix remains visible and not covered */ + .sideaffix { + margin-top: 100px !important; + } + } + + /* 9.2.1 Pushing the search box closer to the navbar, distance from ribbon*/ + @media (min-width:992px) and (max-width:1199px) { + .navbar-form.navbar-right { + margin: 2px 200px 6px 0 !important; /* gap from right edge */ + } + } + + /* 9.2.2 Reverts 9.2.1, as the sideaffix is no longer present + and search box is already closer to the navbar */ + @media (min-width:768px) and (max-width:991px) { + .navbar-form.navbar-right { + margin: 2px 50px 6px 0 !important; /* align with buttons + ribbon gap */ + } + } + + /* 9.3 >=1200: align search with nav text and keep away from ribbon + and makes it more centered to align with the navbar buttons */ + @media (min-width:1200px) { + #autocollapse .navbar-form.navbar-right { + display: block !important; + float: right; + margin: 22px 70px 18px 0 !important; + padding: 0 !important; + border: 0 !important; + box-shadow: none !important; + } + + #autocollapse #search .form-control { + width: auto !important; /* back to natural width */ + } + + /* Reverts 9.1 sideaffix margin change, so they are more uniform with the desktop mode one */ + .sideaffix { + margin-top: 50px !important; + } + } diff --git a/websites/apidocs/Templates/LuceneTemplateAssets/styles/main.js b/websites/apidocs/Templates/LuceneTemplateAssets/styles/main.js index 7cd0be20a4..341bebf8dd 100644 --- a/websites/apidocs/Templates/LuceneTemplateAssets/styles/main.js +++ b/websites/apidocs/Templates/LuceneTemplateAssets/styles/main.js @@ -17,40 +17,220 @@ * under the License. */ -$(function () { +/* 1. Mode controller (desktop vs mobile) — use matchMedia to align with CSS */ +(function () { + var ROOT_ID = 'autocollapse', COLLAPSED = 'collapsed', MODE = null; + // Keep readable constant in case you want to change breakpoint in one place + var DESKTOP_QUERY = '(min-width: 768px)'; + var scheduled = false; - var collapsed = 'collapsed'; - var navBarHeight = 80; - var firstRun = true; + function $(id) { return document.getElementById(id); } + function root() { return $(ROOT_ID); } + function nav() { return $('navbar'); } + function toggleBtn() { return document.querySelector('#' + ROOT_ID + ' .navbar-toggle'); } + function isPanelOpen() { var n = nav(); return !!(n && n.classList.contains('in')); } - renderAlerts(); + function setCollapseOpen(open) { + var n = nav(), btn = toggleBtn(); if (!n) return; + n.classList.add('collapse'); n.classList.remove('collapsing'); + if (open) { + n.classList.add('in'); n.style.display = 'block'; n.style.height = ''; + n.setAttribute('aria-expanded', 'true'); + if (btn) { btn.classList.remove('collapsed'); btn.setAttribute('aria-expanded', 'true'); } + } else { + n.classList.remove('in'); n.style.display = ''; n.style.height = ''; + n.setAttribute('aria-expanded', 'false'); + if (btn) { btn.classList.add('collapsed'); btn.setAttribute('aria-expanded', 'false'); } + } + } + + // Use matchMedia to determine desktop/mobile to match the CSS + function isDesktop() { + if (window.matchMedia) return window.matchMedia(DESKTOP_QUERY).matches; + // Fallback: numeric check (rarely used) + return (window.innerWidth || document.documentElement.clientWidth) >= 768; + } + + function decide() { + return isDesktop() ? 'desktop' : 'mobile'; + } + + function paint(mode) { + var r = root(); if (!r) return; + var isMobile = (mode === 'mobile'); + if (MODE !== mode) { + r.classList.toggle(COLLAPSED, isMobile); + setCollapseOpen(false); // never auto-open when switching + // When switching to desktop, ensure any mobile-only open states are cleared + if (!isMobile) { + try { + var opens = r.querySelectorAll('.nav-asf.is-open'); + for (var i = 0; i < opens.length; i++) opens[i].classList.remove('is-open'); + } catch (e) { /* defensive */ } + } + MODE = mode; + return; + } + r.classList.toggle(COLLAPSED, isMobile); + } + + function recalc() { + scheduled = false; + if (root() && root().classList.contains(COLLAPSED) && isPanelOpen()) return; + paint(decide()); + } + function schedule() { if (scheduled) return; scheduled = true; requestAnimationFrame(recalc); } + + if (document.readyState !== 'loading') schedule(); + else document.addEventListener('DOMContentLoaded', schedule); + window.addEventListener('resize', schedule); + window.addEventListener('orientationchange', schedule); + window.addEventListener('load', function () { schedule(); setTimeout(schedule, 150); }); +})(); + +/* 2. ASF dropdown wiring (mobile click/tap-to-toggle; caret normalization) */ +(function () { + function ready(fn) { if (document.readyState !== 'loading') fn(); else document.addEventListener('DOMContentLoaded', fn); } + ready(function () { + var r = document.getElementById('autocollapse'), wrap = document.getElementById('navbar'); + if (!r || !wrap) return; - function renderAlerts() { - $('.lucene-block').addClass('alert alert-info'); + function first(li, tag) { tag = tag.toUpperCase(); for (var i = 0; i < li.children.length; i++) { var c = li.children[i]; if (c.tagName && c.tagName.toUpperCase() === tag) return c; } return null; } + + function wire() { + var ul = wrap.querySelector('ul.navbar-nav'); if (!ul) return false; + var asf = null; + for (var i = 0; i < ul.children.length; i++) { + var li = ul.children[i]; if (li.tagName !== 'LI') continue; + var a = first(li, 'A'); if (a && a.textContent.trim().toUpperCase() === 'ASF') { asf = li; break; } + } + if (!asf) return false; + if (asf.getAttribute('data-asf-wired') === '1') return true; + asf.setAttribute('data-asf-wired', '1'); asf.classList.add('nav-asf'); + + var stub = first(asf, 'SPAN'); if (stub && /\bexpand-stub\b/.test(stub.className)) stub.style.display = 'none'; + var aTop = first(asf, 'A'); + + // Hide Bootstrap caret, ensure exactly one .lucene-caret + var old = aTop.querySelectorAll('.caret'); for (var k = 0; k < old.length; k++) old[k].style.display = 'none'; + var mine = aTop.querySelectorAll('.lucene-caret'); for (var x = 1; x < mine.length; x++) mine[x].remove(); + if (mine.length === 0) { var sp = document.createElement('span'); sp.className = 'lucene-caret'; aTop.appendChild(sp); } + + // Find submenu UL, mark as asf-menu + var sub = null; + for (var j = 0; j < asf.children.length; j++) { + var c = asf.children[j]; + if (c.tagName === 'UL' && /\bnav\b/.test(c.className) && /\blevel2\b/.test(c.className)) { sub = c; break; } + } + if (sub && sub.className.indexOf('asf-menu') === -1) sub.className += ' asf-menu'; + + // Mobile: click toggles .is-open; Desktop uses CSS :hover + aTop.addEventListener('click', function (ev) { + if (r.classList.contains('collapsed')) { ev.preventDefault(); ev.stopPropagation(); asf.classList.toggle('is-open'); } + }); + aTop.addEventListener('mousedown', function (ev) { if (r.classList.contains('collapsed')) ev.stopPropagation(); }); + + document.addEventListener('keydown', function (e) { if (e.key === 'Escape') asf.classList.remove('is-open'); }); + return true; } - //docfx has a hard coded value of 60px in height check for the nav bar - //but our nav bar is taller so we need to work around this - function fixAutoCollapseBug() { - //remove docfx's handler - $(window).off("resize"); - - autoCollapse(); - $(window).on('resize', autoCollapse); - - function autoCollapse() { - var navbar = $('#autocollapse'); - if (firstRun) { - firstRun = false; - setTimeout(autoCollapse, 310); - } - navbar.removeClass(collapsed); - if (navbar.height() > navBarHeight) { - navbar.addClass(collapsed); - } - } + if (!wire()) { + var obs = new MutationObserver(function () { if (wire()) obs.disconnect(); }); + obs.observe(wrap, { childList: true, subtree: true }); } + }); +})(); + +/* 3. Close hamburger when leaving mobile */ +(function () { + var ROOT_ID = 'autocollapse'; + var DESKTOP_QUERY = '(min-width: 768px)'; + var lastMode = null, rafScheduled = false; + + function $(sel, ctx) { return (ctx || document).querySelector(sel); } + function $id(id) { return document.getElementById(id); } + + function isDesktop() { + if (window.matchMedia) return window.matchMedia(DESKTOP_QUERY).matches; + return (window.innerWidth || document.documentElement.clientWidth) >= 768; + } + + function modeFromWidth() { + return isDesktop() ? 'desktop' : 'mobile'; + } + + function setCollapsed(root, collapsed) { + if (!root) return; + root.classList.toggle('collapsed', collapsed); + } + + function closeHamburger() { + var nav = $id('navbar'); + var btn = $('#' + ROOT_ID + ' .navbar-toggle'); + if (nav) { + nav.classList.add('collapse'); + nav.classList.remove('in', 'collapsing'); + nav.style.display = ''; + nav.style.height = ''; + nav.setAttribute('aria-expanded', 'false'); + } + if (btn) { + btn.classList.add('collapsed'); + btn.setAttribute('aria-expanded', 'false'); + } + // also close ASF mobile submenu if it was open + var asf = $('#' + ROOT_ID + ' .nav-asf'); + if (asf) asf.classList.remove('is-open'); + } + + function apply() { + rafScheduled = false; + var root = $id(ROOT_ID); + if (!root) return; + + var mode = modeFromWidth(); + if (mode !== lastMode) { + setCollapsed(root, mode === 'mobile'); + if (mode === 'desktop') closeHamburger(); + lastMode = mode; + } else { + setCollapsed(root, mode === 'mobile'); + } + } + + function schedule() { if (rafScheduled) return; rafScheduled = true; requestAnimationFrame(apply); } + + if (document.readyState !== 'loading') schedule(); else document.addEventListener('DOMContentLoaded', schedule); + window.addEventListener('load', function () { schedule(); setTimeout(schedule, 120); }); + + // on zoom/resize/orientation changes + window.addEventListener('resize', schedule); + window.addEventListener('orientationchange', schedule); +})(); + +/* 4. Sticky header toggler (desktop only; non-sticky in mobile) */ +(function () { + var ROOT_ID = 'autocollapse'; + + function updateSticky() { + var head = document.querySelector('#wrapper > header') || document.querySelector('header'); + var auto = document.getElementById(ROOT_ID); + if (!head || !auto) return; + var desktop = !auto.classList.contains('collapsed'); + head.classList.toggle('is-sticky', desktop); + } + + // Run now and whenever the collapsed state changes / viewport changes + if (document.readyState !== 'loading') updateSticky(); + else document.addEventListener('DOMContentLoaded', updateSticky); + window.addEventListener('load', updateSticky); + window.addEventListener('resize', updateSticky); + window.addEventListener('orientationchange', updateSticky); - fixAutoCollapseBug(); + // Watch for class changes on #autocollapse + var auto = document.getElementById(ROOT_ID); + if (auto) { + new MutationObserver(updateSticky).observe(auto, { attributes: true, attributeFilter: ['class'] }); + } +})(); -}) diff --git a/websites/apidocs/toc.yml b/websites/apidocs/toc.yml index 557f9860db..69fd8682fb 100644 --- a/websites/apidocs/toc.yml +++ b/websites/apidocs/toc.yml @@ -6,4 +6,19 @@ topicHref: ../../src/dotnet/tools/lucene-cli/docs/index.md - name: Lucene.Net Website href: https://lucenenet.apache.org/ - +- name: ASF + items: + - name: Foundation + href: https://www.apache.org/ + - name: Events + href: https://www.apache.org/events/ + - name: License + href: https://www.apache.org/licenses/ + - name: Thanks + href: https://www.apache.org/foundation/thanks.html + - name: Security + href: https://www.apache.org/security/ + - name: Sponsorship + href: https://www.apache.org/foundation/sponsorship.html + - name: Privacy Policy + href: https://privacy.apache.org/policies/privacy-policy-public.html diff --git a/websites/site/lucenetemplate/partials/head-content.tmpl.partial b/websites/site/lucenetemplate/partials/head-content.tmpl.partial index e63c0b4817..ce963d7e1e 100644 --- a/websites/site/lucenetemplate/partials/head-content.tmpl.partial +++ b/websites/site/lucenetemplate/partials/head-content.tmpl.partial @@ -12,6 +12,7 @@ + {{#_noindex}}{{/_noindex}} diff --git a/websites/site/lucenetemplate/partials/head.tmpl.partial b/websites/site/lucenetemplate/partials/head.tmpl.partial index dfe3e4e724..bf119ffb46 100644 --- a/websites/site/lucenetemplate/partials/head.tmpl.partial +++ b/websites/site/lucenetemplate/partials/head.tmpl.partial @@ -12,6 +12,7 @@ + {{#_noindex}}{{/_noindex}} diff --git a/websites/site/lucenetemplate/styles/main.css b/websites/site/lucenetemplate/styles/main.css index ef87175822..0c9f0f31ed 100644 --- a/websites/site/lucenetemplate/styles/main.css +++ b/websites/site/lucenetemplate/styles/main.css @@ -17,185 +17,678 @@ * under the License. */ -/* .navbar-inverse { - background: #4a95da; - background: rgb(44, 95, 163); - background: -moz-linear-gradient(top, rgba(44, 95, 163, 1) 0%, rgba(64, 150, 238, 1) 100%); - background: -webkit-linear-gradient(top, rgba(44, 95, 163, 1) 0%, rgba(64, 150, 238, 1) 100%); - background: linear-gradient(to bottom, rgba(44, 95, 163, 1) 0%, rgba(64, 150, 238, 1) 100%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#2c5fa3', endColorstr='#4096ee', GradientType=0); - border-color:white; +/* 0. Design tokens / variables (centralized) */ +:root { + /* sizes */ + --nav-h: 80px; + --brand-h: 55px; + --submenu-min-width: 260px; + --ribbon-safe-zone: 0; + --nav-wrap-extra: 0; /* default extra offset when navbar wraps */ + + /* colors */ + --color-bg: #ffffff; + --color-primary: #0095eb; + --color-primary-contrast: #ffffff; + --color-muted: #143653; + --color-muted-2: #0f2a40; + --color-border: #e5e7eb; + --color-subnav-bg: #f7f7f7; + --color-breadcrumb: #bbb; + --color-ribbon-bg: #1764aa; + + /* shadows & z-index */ + --shadow-lg: 0 8px 24px rgba(0,0,0,.12); + --shadow-ribbon: 4px 4px 10px rgba(0,0,0,.8); + --z-nav: 1000; + --z-dropdown: 1001; + --z-ribbon: 9999; +} + +/* Respect reduced motion preference */ +@media (prefers-reduced-motion: reduce) { + * { + transition: none !important; + animation: none !important; } - .navbar-inverse .navbar-nav>li>a, .navbar-inverse .navbar-text { - color: #fff; +} + +/* 1. Navbar & Header + ------------------ */ + +/* 1.1 Basic header / navbar */ +nav.navbar { + background: var(--color-bg); + min-height: var(--nav-h); + margin-bottom: 8px !important; /* consolidated */ +} + +#wrapper > header, +header { + position: relative; + z-index: var(--z-nav); + margin-bottom: 0; + background: var(--color-bg); +} + +/* 1.2.1 Brand/logo sizing */ +.navbar-brand { + height: var(--nav-h); +} + +.navbar-header .navbar-brand img { + height: var(--brand-h); + width: auto; + margin: calc((var(--nav-h) - var(--brand-h))/2) 10px; + display: block; +} + +/* 1.2.2 Nav links vertical centering on >=768 */ +@media (min-width:768px) { + header ul.navbar-nav > li > a { + padding-top: calc((var(--nav-h) - 34px)/2); + padding-bottom: calc((var(--nav-h) - 34px)/2); + line-height: 34px; + font-size: 16px; + font-weight: 600; } - .navbar-inverse .navbar-nav>.active>a { - background-color: #1764AA; + /* small gap after last item */ + #navbar > ul.navbar-nav { + margin-right: 6px !important; } - .navbar-inverse .navbar-nav>.active>a:focus, .navbar-inverse .navbar-nav>.active>a:hover { - background-color: #1764AA; - } */ +} -.btn-primary:hover { - background-color: #1764aa; +/* 1.2.3 Ensure the nav list never inherits stray margins */ +#navbar .navbar-nav { + margin: 0 !important; } -article.content {font-size: 15px} +/* 1.2.4 Clear default body padding reserved for fixed navbars */ +body { + padding-top: 0 !important; +} -a, a:hover, a:focus { - color: #0098ff; +/* 1.3 Collapsed / desktop toggle behavior (JS toggles #autocollapse.collapsed) */ +#autocollapse.collapsed .navbar-toggle { + display: block !important; + visibility: visible !important; + opacity: 1; + z-index: 2001; } -a:hover { - text-decoration: underline; + +#autocollapse.collapsed #navbar { + display: none; } -button { - color: #1764aa; +#autocollapse.collapsed #navbar.collapse.in { + display: block !important; } -button:hover, -button:focus { - color: #143653; - text-decoration: none; + +/* 1.3.1 Desktop shows nav, hides hamburger */ +#autocollapse:not(.collapsed) #navbar { + display: block !important; } -nav.navbar { - background-color: white; + +#autocollapse:not(.collapsed) .navbar-toggle { + display: none !important; } -.navbar-brand { - height: 80px; + +/* 1.4 Hamburger button appearance */ +#autocollapse .navbar-toggle { + background: transparent; + border: 1px solid var(--color-primary); + border-radius: 4px; + padding: 10px 12px; + line-height: 1; + margin-top: 18px; + transition: box-shadow .12s ease, border-color .12s ease; } -.navbar-header .navbar-brand img { - width: 300px; - height: 55px; - margin: 10px 10px 10px 0px; + + #autocollapse .navbar-toggle:focus, + #autocollapse .navbar-toggle:focus-visible { + outline: none; + box-shadow: 0 0 0 3px rgba(0,149,235,0.18); + border-color: #00598d; + } + +#autocollapse .navbar-toggle .icon-bar { + width: 24px; + height: 3px; + background-color: var(--color-primary); } -.navbar-toggle .icon-bar { - margin-top: 2px; - background-color: #0095eb; + +#autocollapse .navbar-toggle .icon-bar + .icon-bar { + margin-top: 4px; } -.navbar-toggle { - border-color: #0095eb; + +/* 1.5 Ensure hamburger hidden on desktop */ +#autocollapse:not(.collapsed) .navbar-toggle { + display: none !important; } -header ul.navbar-nav { - /* font-size:1.2em; */ - float: right; + +/* 2. ASF Dropdown + ---------------- */ + +/* 2.1 Base structure */ +.navbar-nav > li.nav-asf { + position: relative; +} + +.navbar-nav > li.nav-asf > .expand-stub { + display: none !important; +} + +.navbar-nav .nav-asf > a { + display: flex; + align-items: center; + gap: .35rem; font-weight: 600; } -.navbar-nav>li>a { - color:#177cc8; +.navbar-nav .nav-asf > a .lucene-caret { + display: inline-block; + width: 1em; + text-align: center; } -.navbar-nav>li>a:hover, .navbar-nav>li>a:focus { - color:#143653; + +/* 2.2 Submenu style (unified across desktop & mobile) */ +.navbar-nav > li.nav-asf > ul.nav.level2.asf-menu > li > a { + font-size: 15px; + line-height: 1.34; + font-weight: 500; + color: var(--color-muted); + opacity: .95; + padding: .48rem .9rem; + white-space: nowrap; +} + +.navbar-nav > li.nav-asf > ul.nav.level2.asf-menu > li > a:hover { + background: #f2f6fb; + color: var(--color-muted-2); } -@media screen and (min-width: 768px) { - header ul.navbar-nav { - padding-right: 100px; +/* 2.3 Desktop hover dropdown (>=768) — overlay with fade/slide */ +@media (min-width:768px) { + #autocollapse:not(.collapsed) .navbar-nav > li.nav-asf > a .lucene-caret::after { + content: "▾"; } + #autocollapse:not(.collapsed) .navbar-nav > li.nav-asf:hover > a .lucene-caret::after, + #autocollapse:not(.collapsed) .navbar-nav > li.nav-asf:focus-within > a .lucene-caret::after { + content: "▴"; + } + #autocollapse:not(.collapsed) .navbar-nav > li.nav-asf > ul.nav.level2.asf-menu { + position: absolute; + top: 100%; + left: 0; + min-width: var(--submenu-min-width); + background: var(--color-bg); + border: 1px solid var(--color-border); + border-radius: 8px; + padding: .35rem 0; + box-shadow: var(--shadow-lg); + opacity: 0; + pointer-events: none; + transform: translateY(6px); + transition: transform .16s ease, opacity .16s ease; + z-index: var(--z-dropdown); + } + #autocollapse:not(.collapsed) .navbar-nav > li.nav-asf:hover > ul.nav.level2.asf-menu, + #autocollapse:not(.collapsed) .navbar-nav > li.nav-asf:focus-within > ul.nav.level2.asf-menu { + opacity: 1; + pointer-events: auto; + transform: translateY(0); + } + /* Ensure desktop dropdown does not affect layout (overlay) */ + #autocollapse:not(.collapsed) .navbar-nav > li.nav-asf > ul.nav.level2.asf-menu { + display: block; + } +} + +/* 2.4 Mobile accordion closed by default */ +#autocollapse.collapsed .navbar-nav > li.nav-asf > a { + justify-content: flex-start; + width: 100%; +} + +#autocollapse.collapsed .navbar-nav > li.nav-asf > a .lucene-caret::after { + content: "▸"; +} + +#autocollapse.collapsed .navbar-nav > li.nav-asf.is-open > a .lucene-caret::after { + content: "▾"; +} + +/* 2.4.1 Animated accordion implementation */ +#autocollapse.collapsed .navbar-nav > li.nav-asf > ul.nav.level2.asf-menu { + position: static !important; + max-height: 0; + overflow: hidden; + transition: max-height .25s ease; + margin-left: .5rem; + padding-left: .5rem; + border-left: none; } -article img { - margin:15px 0 30px 0; +#autocollapse.collapsed .navbar-nav > li.nav-asf.is-open > ul.nav.level2.asf-menu { + max-height: 1000px; } -article[data-uid="contributing/setup-java-debugging"] img, -article[data-uid="quick-start/tutorial"] img { - border: solid 1px #dedcd3 +/* 2.5 Collapsed column layout (centered column, left-aligned items) */ +#autocollapse.collapsed #navbar .navbar-nav { + float: none !important; + width: min(560px, 90vw); + margin: 8px auto; + text-align: left; } -article[data-uid="quick-start/introduction"] .diagram{ - text-align:center; +/* 2.6 Unified left-start & submenu indent variables for collapsed */ +#autocollapse.collapsed { + --m-left: 16px; + --submenu-indent: 24px; +} + +#autocollapse.collapsed .navbar-nav > li > a { + display: block; + padding: 10px 12px 10px var(--m-left); } -article[data-uid="quick-start/introduction"] .diagram img{ - max-width:400px +#autocollapse.collapsed .navbar-nav > li.nav-asf > a { + gap: .35rem; + padding-left: var(--m-left); } -.sidefilter { - top: 120px; +#autocollapse.collapsed .navbar-nav > li.nav-asf > ul.nav.level2.asf-menu > li > a { + padding: 8px 12px 8px calc(var(--m-left) + var(--submenu-indent)); } -.sidetoc { - top: 180px; - background-color: rgb(247, 247, 247); +/* 2.7 768–1199: force full navbar (no compact/hamburger), sticky header and reduced button height */ +@media (min-width:768px) and (max-width:1199px) { + /* Force full navbar visible and hide hamburger regardless of the JS .collapsed state */ + #autocollapse .navbar-toggle { + display: none !important; + visibility: hidden !important; + opacity: 0 !important; + margin-right: 0 !important; + position: static !important; + z-index: auto !important; + } + + /* Make header sticky in this range (restore desktop sticky behaviour) */ + header.is-sticky, #wrapper > header.is-sticky { + position: sticky !important; + top: 0 !important; + z-index: var(--z-nav); + background: var(--color-bg); + } + + header.is-sticky nav.navbar { + box-shadow: 0 1px 0 rgba(0,0,0,.06); + margin-bottom: 0 !important; + } + + /* Reduce nav button height further to keep more content visible when the nav wraps under the logo */ + header ul.navbar-nav > li > a { + padding-top: 6px; + padding-bottom: 6px; + line-height: 30px; + font-size: 15px; + font-weight: 600; + } + + /* Ensure navbar items layout behaves like desktop (allow wrapping but avoid the collapsed centered column) */ + #autocollapse .navbar-nav { + float: none !important; + width: auto !important; + margin: 0 !important; + text-align: left !important; + white-space: normal; + } + + #autocollapse.collapsed #navbar .navbar-nav { + width: auto !important; + margin: 0 !important; + } + + /* Keep submenu/padding sensible in this width range */ + #autocollapse.collapsed .navbar-nav > li.nav-asf > a { + padding-left: 12px; + } + + #autocollapse.collapsed .navbar-nav > li.nav-asf > ul.nav.level2.asf-menu > li > a { + padding: 6px 12px 6px calc(12px + 24px); + } + + /* tuned extra offset only in this wrap range */ + :root { + --nav-wrap-extra: 20px; + } + + html { + scroll-padding-top: calc(var(--nav-h) + var(--nav-wrap-extra) + 4px); + } + + .sidefilter { + top: calc(var(--nav-h) + 40px + var(--nav-wrap-extra)) !important; + } + + .sidetoc { + top: calc(var(--nav-h) + 100px + var(--nav-wrap-extra)) !important; + } + + /* 2.8.1 Reduce padding to avoid shrinking */ + @media (min-width:768px) and (max-width:991px) { + body #autocollapse .navbar-nav > li > a { + padding-left: 9px !important; + padding-right: 9px !important; + } + } + /* Reverting the earlier */ + @media (min-width:992px) { + body #autocollapse .navbar-nav > li > a { + padding-left: 15px !important; + padding-right: 15px !important; + } + } + + /* 2.8.2 [Site Only] Fix the Home/About when Navbar wraps */ + :target::before { + content: ""; + display: block; + height: calc(var(--nav-h) + var(--nav-wrap-extra) * 0.1); + margin-top: calc((var(--nav-h) + var(--nav-wrap-extra) * 0.1) * -1); + visibility: hidden; + pointer-events: none; + } } -body .toc { - background-color: rgb(247, 247, 247); +/* 3. Sticky header for desktop (>=1200) (JS still toggles .is-sticky) */ +#wrapper > header.is-sticky, +header.is-sticky { + position: sticky; + top: 0; + z-index: var(--z-nav); + background: var(--color-bg); } -.sidefilter { - background-color: rgb(247, 247, 247); +header.is-sticky nav.navbar { + box-shadow: 0 1px 0 rgba(0,0,0,.06); + margin-bottom: 0 !important; } -.sideaffix > div.contribution > ul > li > a.contribution-link { - opacity:80%; +/* 4. GitHub ribbon + ---------------------------------------- */ +#forkongithub { + display: block; } -/* FORK ME ON GITHUB */ #forkongithub a { - background: #1764aa; - color: #fff; + background: var(--color-ribbon-bg); + color: var(--color-primary-contrast); text-decoration: none; - font-family: arial, sans-serif; - text-align: center; font-weight: bold; padding: 5px 40px; font-size: 1rem; line-height: 2rem; position: relative; - transition: 0.5s; -} -#forkongithub a:hover { - background: black; - color: #fff; + transition: .5s; + font-family: arial,sans-serif; + text-align: center; } -#forkongithub a::before, -#forkongithub a::after { + +#forkongithub a::before, #forkongithub a::after { content: ""; width: 100%; display: block; position: absolute; - top: 1px; left: 0; height: 1px; - background: #fff; + background: var(--color-primary-contrast); +} + +#forkongithub a::before { + top: 1px; } + #forkongithub a::after { bottom: 1px; top: auto; } -@media screen and (min-width: 768px) { + +#forkongithub a:hover { + background: black; + color: var(--color-primary-contrast); +} + +@media (min-width:768px) { #forkongithub { position: fixed; - display: block; top: 0; right: 0; width: 200px; - overflow: hidden; height: 150px; - z-index: 9999; + overflow: hidden; + z-index: var(--z-ribbon); } + #forkongithub a { width: 200px; position: absolute; top: 40px; right: -40px; transform: rotate(45deg); - -webkit-transform: rotate(45deg); - -ms-transform: rotate(45deg); - -moz-transform: rotate(45deg); - -o-transform: rotate(45deg); - box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.8); + box-shadow: var(--shadow-ribbon); + } +} + +/* 4.1 Keep a safe margin for the ribbon on mid widths so the nav doesn't collide */ +@media (min-width:768px) and (max-width:1500px) { + #autocollapse:not(.collapsed) #navbar, + #autocollapse:not(.collapsed) .navbar-toggle { + margin-right: var(--ribbon-safe-zone) !important; + } + /* except when the collapse is open */ + #autocollapse:not(.collapsed) #navbar.in, + #autocollapse:not(.collapsed) #navbar.collapsing { + margin-right: 0 !important; + } +} + +/* 5. Subnav / breadcrumb / spacing rules + ------------------------------------------------------- */ +.subnav.navbar { + margin: 0 0 16px 0 !important; + min-height: 40px; + border: none; + box-shadow: none; + background: var(--color-bg); + position: relative; + z-index: 900; + background-color: var(--color-subnav-bg) !important; + border-bottom: 1px solid #e5e7e5 !important; + box-shadow: inset 0 1px 0 rgba(255,255,255,.5); +} + +.subnav.navbar .container { + padding: 8px 0; +} + +.subnav.navbar .breadcrumb { + margin: 0; + background: transparent; + padding: 0; +} + +.subnav.navbar .breadcrumb > li + li:before { + content: "/"; + color: var(--color-breadcrumb); + padding: 0 6px; +} + +.subnav.navbar .breadcrumb > li { + display: inline-block; +} + +/* 5.1 Breadcrumb padding adjustments */ +.subnav.navbar #breadcrumb { + padding-left: 28px; +} + +@media (min-width:1200px) { + .subnav.navbar #breadcrumb { + padding-left: 34px; + } +} + +@media (min-width:1600px) { + .subnav.navbar #breadcrumb { + padding-left: 40px; + } +} + +/* 5.2 Hide subnav on homepage */ +#homepage .subnav.navbar { + display: none !important; +} + +/* 6. First-content padding / margin-collapse prevention + ---------------------------------------------------- */ +.container.body-content, +.content.wrap, +.home-section:first-of-type, +.container.body-content:first-of-type, +.content.wrap:first-of-type, +.article.row.grid:first-of-type { + overflow: visible !important; +} + +/* 6.1 Default small top padding */ +.container.body-content:first-of-type, +.content.wrap:first-of-type, +.article.row.grid:first-of-type { + padding-top: 8px !important; + margin-top: 0 !important; +} + +#homepage .home-section:first-of-type { + padding-top: 8px !important; + margin-top: 0 !important; + overflow: visible !important; +} + +#homepage .home-section:first-of-type .container > h1:first-child, +.container.body-content h1:first-child, +.content.wrap > h1:first-child, +.article.row.grid h1:first-child { + margin-top: 0 !important; +} + +#homepage .home-section:first-of-type h1:first-child { + /* 6.2 Making sure the first block starts without a gap */ + padding-top: 0 !important; + margin-top: 0 !important; +} + +.article.row.grid-right { + margin-top: 0px; +} + +/* 6.3 Layout should stay consistent after the header */ +#wrapper > header + * { + margin-top: 0 !important; +} + +#wrapper > header + *:not(.subnav):not(.navbar) { + padding-top: 8px !important; + overflow: auto; +} + +/* 6.5 Ensure header does not cover target */ +html { + scroll-padding-top: 84px; +} + +/* 7. Side TOC offsets */ +@media (max-width:1199px) { + .sidefilter { + top: calc(var(--nav-h) + 80px) !important; + } + + .sidetoc { + top: calc(var(--nav-h) + 140px) !important; } } -.home-section.books img {width:300px} +@media (min-width:1200px) { + .sidefilter { + top: calc(var(--nav-h) + 40px) !important; + } + .sidetoc { + top: calc(var(--nav-h) + 100px) !important; + } +} + +/* 8. Misc / defensive adjustments + ------------------------------- */ + +/* 8.1 Ensure top-level nav font weight control */ +header ul.navbar-nav { + font-weight: normal !important; +} + +header ul.navbar-nav > li > a { + font-weight: 600 !important; +} + +/* 8.2 Ensure ASF submenu tone consistent in both collapsed and desktop */ +#autocollapse .navbar-nav > li.nav-asf ul.asf-menu a { + font-size: 15px; + line-height: 1.34; + font-weight: 400; + color: var(--color-muted); + opacity: .95; +} + +/* 8.3 Hamburger ASF improvements */ +#autocollapse.collapsed .navbar-nav > li.nav-asf > a .lucene-caret { + margin-left: .1rem; +} -@media (min-width: 900px){ - .home-section.books .col-md-6 { width: 50%; } +#autocollapse.collapsed .navbar-nav > li.nav-asf > a .lucene-caret::after { + content: "▸"; } -@media (min-width:1200px){ - .home-section.books .container{width:970px} + +#autocollapse.collapsed .navbar-nav > li.nav-asf.is-open > a .lucene-caret::after { + content: "▾"; +} + +/* 8.4 Defensive: ensure desktop ASF dropdowns overlay (consolidated) */ +#autocollapse:not(.collapsed) .navbar-nav > li.nav-asf > ul.nav.level2.asf-menu { + position: absolute; + top: 100%; + left: 0; + z-index: var(--z-dropdown); +} + +/* Accessibility: visible focus for keyboard users */ +a:focus-visible, +button:focus-visible { + outline: 3px solid rgba(0,0,0,0.12); + outline-offset: 2px; +} + +/* 8.6 Small-screen ToC bleeding prevention (fixed broken media query) */ +@media (max-width:767.98px) { + .sidenav .sidetoggle.collapse { + display: block !important; + height: 0 !important; + overflow: hidden !important; + visibility: hidden !important; + } + /* Open state */ + .sidenav .sidetoggle.collapse.in { + height: auto !important; + overflow: visible !important; + visibility: visible !important; + } } diff --git a/websites/site/lucenetemplate/styles/main.js b/websites/site/lucenetemplate/styles/main.js new file mode 100644 index 0000000000..341bebf8dd --- /dev/null +++ b/websites/site/lucenetemplate/styles/main.js @@ -0,0 +1,236 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* 1. Mode controller (desktop vs mobile) — use matchMedia to align with CSS */ +(function () { + var ROOT_ID = 'autocollapse', COLLAPSED = 'collapsed', MODE = null; + // Keep readable constant in case you want to change breakpoint in one place + var DESKTOP_QUERY = '(min-width: 768px)'; + var scheduled = false; + + function $(id) { return document.getElementById(id); } + function root() { return $(ROOT_ID); } + function nav() { return $('navbar'); } + function toggleBtn() { return document.querySelector('#' + ROOT_ID + ' .navbar-toggle'); } + function isPanelOpen() { var n = nav(); return !!(n && n.classList.contains('in')); } + + function setCollapseOpen(open) { + var n = nav(), btn = toggleBtn(); if (!n) return; + n.classList.add('collapse'); n.classList.remove('collapsing'); + if (open) { + n.classList.add('in'); n.style.display = 'block'; n.style.height = ''; + n.setAttribute('aria-expanded', 'true'); + if (btn) { btn.classList.remove('collapsed'); btn.setAttribute('aria-expanded', 'true'); } + } else { + n.classList.remove('in'); n.style.display = ''; n.style.height = ''; + n.setAttribute('aria-expanded', 'false'); + if (btn) { btn.classList.add('collapsed'); btn.setAttribute('aria-expanded', 'false'); } + } + } + + // Use matchMedia to determine desktop/mobile to match the CSS + function isDesktop() { + if (window.matchMedia) return window.matchMedia(DESKTOP_QUERY).matches; + // Fallback: numeric check (rarely used) + return (window.innerWidth || document.documentElement.clientWidth) >= 768; + } + + function decide() { + return isDesktop() ? 'desktop' : 'mobile'; + } + + function paint(mode) { + var r = root(); if (!r) return; + var isMobile = (mode === 'mobile'); + if (MODE !== mode) { + r.classList.toggle(COLLAPSED, isMobile); + setCollapseOpen(false); // never auto-open when switching + // When switching to desktop, ensure any mobile-only open states are cleared + if (!isMobile) { + try { + var opens = r.querySelectorAll('.nav-asf.is-open'); + for (var i = 0; i < opens.length; i++) opens[i].classList.remove('is-open'); + } catch (e) { /* defensive */ } + } + MODE = mode; + return; + } + r.classList.toggle(COLLAPSED, isMobile); + } + + function recalc() { + scheduled = false; + if (root() && root().classList.contains(COLLAPSED) && isPanelOpen()) return; + paint(decide()); + } + function schedule() { if (scheduled) return; scheduled = true; requestAnimationFrame(recalc); } + + if (document.readyState !== 'loading') schedule(); + else document.addEventListener('DOMContentLoaded', schedule); + window.addEventListener('resize', schedule); + window.addEventListener('orientationchange', schedule); + window.addEventListener('load', function () { schedule(); setTimeout(schedule, 150); }); +})(); + +/* 2. ASF dropdown wiring (mobile click/tap-to-toggle; caret normalization) */ +(function () { + function ready(fn) { if (document.readyState !== 'loading') fn(); else document.addEventListener('DOMContentLoaded', fn); } + ready(function () { + var r = document.getElementById('autocollapse'), wrap = document.getElementById('navbar'); + if (!r || !wrap) return; + + function first(li, tag) { tag = tag.toUpperCase(); for (var i = 0; i < li.children.length; i++) { var c = li.children[i]; if (c.tagName && c.tagName.toUpperCase() === tag) return c; } return null; } + + function wire() { + var ul = wrap.querySelector('ul.navbar-nav'); if (!ul) return false; + var asf = null; + for (var i = 0; i < ul.children.length; i++) { + var li = ul.children[i]; if (li.tagName !== 'LI') continue; + var a = first(li, 'A'); if (a && a.textContent.trim().toUpperCase() === 'ASF') { asf = li; break; } + } + if (!asf) return false; + if (asf.getAttribute('data-asf-wired') === '1') return true; + asf.setAttribute('data-asf-wired', '1'); asf.classList.add('nav-asf'); + + var stub = first(asf, 'SPAN'); if (stub && /\bexpand-stub\b/.test(stub.className)) stub.style.display = 'none'; + var aTop = first(asf, 'A'); + + // Hide Bootstrap caret, ensure exactly one .lucene-caret + var old = aTop.querySelectorAll('.caret'); for (var k = 0; k < old.length; k++) old[k].style.display = 'none'; + var mine = aTop.querySelectorAll('.lucene-caret'); for (var x = 1; x < mine.length; x++) mine[x].remove(); + if (mine.length === 0) { var sp = document.createElement('span'); sp.className = 'lucene-caret'; aTop.appendChild(sp); } + + // Find submenu UL, mark as asf-menu + var sub = null; + for (var j = 0; j < asf.children.length; j++) { + var c = asf.children[j]; + if (c.tagName === 'UL' && /\bnav\b/.test(c.className) && /\blevel2\b/.test(c.className)) { sub = c; break; } + } + if (sub && sub.className.indexOf('asf-menu') === -1) sub.className += ' asf-menu'; + + // Mobile: click toggles .is-open; Desktop uses CSS :hover + aTop.addEventListener('click', function (ev) { + if (r.classList.contains('collapsed')) { ev.preventDefault(); ev.stopPropagation(); asf.classList.toggle('is-open'); } + }); + aTop.addEventListener('mousedown', function (ev) { if (r.classList.contains('collapsed')) ev.stopPropagation(); }); + + document.addEventListener('keydown', function (e) { if (e.key === 'Escape') asf.classList.remove('is-open'); }); + return true; + } + + if (!wire()) { + var obs = new MutationObserver(function () { if (wire()) obs.disconnect(); }); + obs.observe(wrap, { childList: true, subtree: true }); + } + }); +})(); + +/* 3. Close hamburger when leaving mobile */ +(function () { + var ROOT_ID = 'autocollapse'; + var DESKTOP_QUERY = '(min-width: 768px)'; + var lastMode = null, rafScheduled = false; + + function $(sel, ctx) { return (ctx || document).querySelector(sel); } + function $id(id) { return document.getElementById(id); } + + function isDesktop() { + if (window.matchMedia) return window.matchMedia(DESKTOP_QUERY).matches; + return (window.innerWidth || document.documentElement.clientWidth) >= 768; + } + + function modeFromWidth() { + return isDesktop() ? 'desktop' : 'mobile'; + } + + function setCollapsed(root, collapsed) { + if (!root) return; + root.classList.toggle('collapsed', collapsed); + } + + function closeHamburger() { + var nav = $id('navbar'); + var btn = $('#' + ROOT_ID + ' .navbar-toggle'); + if (nav) { + nav.classList.add('collapse'); + nav.classList.remove('in', 'collapsing'); + nav.style.display = ''; + nav.style.height = ''; + nav.setAttribute('aria-expanded', 'false'); + } + if (btn) { + btn.classList.add('collapsed'); + btn.setAttribute('aria-expanded', 'false'); + } + // also close ASF mobile submenu if it was open + var asf = $('#' + ROOT_ID + ' .nav-asf'); + if (asf) asf.classList.remove('is-open'); + } + + function apply() { + rafScheduled = false; + var root = $id(ROOT_ID); + if (!root) return; + + var mode = modeFromWidth(); + if (mode !== lastMode) { + setCollapsed(root, mode === 'mobile'); + if (mode === 'desktop') closeHamburger(); + lastMode = mode; + } else { + setCollapsed(root, mode === 'mobile'); + } + } + + function schedule() { if (rafScheduled) return; rafScheduled = true; requestAnimationFrame(apply); } + + if (document.readyState !== 'loading') schedule(); else document.addEventListener('DOMContentLoaded', schedule); + window.addEventListener('load', function () { schedule(); setTimeout(schedule, 120); }); + + // on zoom/resize/orientation changes + window.addEventListener('resize', schedule); + window.addEventListener('orientationchange', schedule); +})(); + +/* 4. Sticky header toggler (desktop only; non-sticky in mobile) */ +(function () { + var ROOT_ID = 'autocollapse'; + + function updateSticky() { + var head = document.querySelector('#wrapper > header') || document.querySelector('header'); + var auto = document.getElementById(ROOT_ID); + if (!head || !auto) return; + var desktop = !auto.classList.contains('collapsed'); + head.classList.toggle('is-sticky', desktop); + } + + // Run now and whenever the collapsed state changes / viewport changes + if (document.readyState !== 'loading') updateSticky(); + else document.addEventListener('DOMContentLoaded', updateSticky); + window.addEventListener('load', updateSticky); + window.addEventListener('resize', updateSticky); + window.addEventListener('orientationchange', updateSticky); + + // Watch for class changes on #autocollapse + var auto = document.getElementById(ROOT_ID); + if (auto) { + new MutationObserver(updateSticky).observe(auto, { attributes: true, attributeFilter: ['class'] }); + } +})(); + diff --git a/websites/site/toc.yml b/websites/site/toc.yml index ba188cbc22..a3dcaa1388 100644 --- a/websites/site/toc.yml +++ b/websites/site/toc.yml @@ -11,3 +11,19 @@ - name: Contributing href: contributing/ topicHref: contributing/index.md +- name: ASF + items: + - name: Foundation + href: https://www.apache.org/ + - name: Events + href: https://www.apache.org/events/ + - name: License + href: https://www.apache.org/licenses/ + - name: Thanks + href: https://www.apache.org/foundation/thanks.html + - name: Security + href: https://www.apache.org/security/ + - name: Sponsorship + href: https://www.apache.org/foundation/sponsorship.html + - name: Privacy Policy + href: https://privacy.apache.org/policies/privacy-policy-public.html