From 03b3c0523f47daeb8166781bd78a66f56d610f3b Mon Sep 17 00:00:00 2001 From: Sudhanshu Tiwari Date: Wed, 21 Aug 2024 20:14:12 +0530 Subject: [PATCH 1/2] data: Redesign https://valadoc.org and make it mobile-responsive Redesign the sidebar, add and style a table of contents, and make valadoc.org mobile-responsive. --- data/images/clean.svg | 103 +------ data/images/coll_close.svg | 63 +---- data/images/coll_open.svg | 63 +---- data/images/magnifier.svg | 1 + data/images/purple-logo.svg | 12 + data/index.php | 62 +++-- data/scripts/valadoc.js | 130 +++++---- data/styles/main.css | 525 ++++++++++++++++++++++++++---------- 8 files changed, 528 insertions(+), 431 deletions(-) create mode 100644 data/images/magnifier.svg create mode 100644 data/images/purple-logo.svg diff --git a/data/images/clean.svg b/data/images/clean.svg index 46e8eff7..7e90a14c 100644 --- a/data/images/clean.svg +++ b/data/images/clean.svg @@ -1,102 +1 @@ - - - - - - - image/svg+xml - - elementary Symbolic Icon Theme - - - - elementary Symbolic Icon Theme - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/data/images/coll_close.svg b/data/images/coll_close.svg index 8ddd96b8..90196ebe 100644 --- a/data/images/coll_close.svg +++ b/data/images/coll_close.svg @@ -1,61 +1,4 @@ - - - - - - image/svg+xml - - elementary Symbolic Icon Theme - - - - elementary Symbolic Icon Theme - - - - - - - - - - + + + diff --git a/data/images/coll_open.svg b/data/images/coll_open.svg index 1cf11ae5..13438efe 100644 --- a/data/images/coll_open.svg +++ b/data/images/coll_open.svg @@ -1,61 +1,4 @@ - - - - - - image/svg+xml - - elementary Symbolic Icon Theme - - - - elementary Symbolic Icon Theme - - - - - - - - - - + + + diff --git a/data/images/magnifier.svg b/data/images/magnifier.svg new file mode 100644 index 00000000..ad809e02 --- /dev/null +++ b/data/images/magnifier.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/images/purple-logo.svg b/data/images/purple-logo.svg new file mode 100644 index 00000000..9496efc2 --- /dev/null +++ b/data/images/purple-logo.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/data/index.php b/data/index.php index 9ed30c13..d5b5458e 100644 --- a/data/index.php +++ b/data/index.php @@ -51,6 +51,7 @@ function get_title ($page) { + @@ -68,28 +69,43 @@ function get_title ($page) { +
+
+ Home
-
diff --git a/data/scripts/valadoc.js b/data/scripts/valadoc.js index f8e52820..a7b71f65 100644 --- a/data/scripts/valadoc.js +++ b/data/scripts/valadoc.js @@ -14,6 +14,16 @@ const html = { tooltipEl: initTooltip(), } +var width = (window.innerWidth > 0) ? window.innerWidth : screen.width +// 0 for mobile, 1 for desktop/laptop +var device = width < 992 ? 0 : 1 + +function toggle_mobile_nav (hamburgerIcon) { + hamburgerIcon.classList.toggle('nav-open'); + document.getElementById('mobile-menu-overlay').classList.toggle('nav-open'); + document.getElementById('overlay-background').classList.toggle('nav-open'); +} + /* * Makes a request to the server to get search results */ @@ -90,29 +100,32 @@ function setupLink (link) { return } - link.addEventListener('mouseleave', evt => { - evt.currentTarget.hovered = false - html.tooltipEl.reset(); - }) - - link.addEventListener('mouseenter', evt => { - // fullname = path without the / at the beginning and the .htm(l) - const target = evt.currentTarget - target.hovered = true - const fullname = link.pathname.substring(1).replace(/\.html?$/, '') - if (tooltipCache[fullname]) { - html.tooltipEl.show(tooltipCache[fullname], target) - } else { - fetch(`/tooltip.php?fullname=${encodeURIComponent(fullname)}`, { - method: 'POST' - }).then(res => res.text()).then(content => { - tooltipCache[fullname] = content - if (target.hovered) { - html.tooltipEl.show(content, target) - } - }) - } - }) + // show tooltip only if the device is not handheld + if (device == 1) { + link.addEventListener('mouseleave', evt => { + evt.currentTarget.hovered = false + html.tooltipEl.reset(); + }) + + link.addEventListener('mouseenter', evt => { + // fullname = path without the / at the beginning and the .htm(l) + const target = evt.currentTarget + target.hovered = true + const fullname = link.pathname.substring(1).replace(/\.html?$/, '') + if (tooltipCache[fullname]) { + html.tooltipEl.show(tooltipCache[fullname], target) + } else { + fetch(`/tooltip.php?fullname=${encodeURIComponent(fullname)}`, { + method: 'POST' + }).then(res => res.text()).then(content => { + tooltipCache[fullname] = content + if (target.hovered) { + html.tooltipEl.show(content, target) + } + }) + } + }) + } link.addEventListener('click', evt => { html.tooltipEl.reset() @@ -136,19 +149,20 @@ function loadPage (link, popped = false) { document.title = title // Init new tooltips - document.querySelectorAll('#content a').forEach(setupLink) + document.querySelectorAll('.site_content > div a').forEach(setupLink) + document.querySelectorAll('.site_content > ul a').forEach(setupLink) document.querySelectorAll('#content area').forEach(setupLink) }).catch(err => { html.content.innerHTML = `

Sorry, an error occurred

${err.message}

` }) - if (html.searchField.value === '') { + if (html.searchField[device].value === '') { fetch(sidebarUrl).then(res => res.text()).then(sidebar => { - html.navigation.innerHTML = sidebar + html.navigation[device].innerHTML = sidebar // Init new tooltips - document.querySelectorAll('#navigation-content a').forEach(setupLink) - document.querySelectorAll('#navigation-content area').forEach(setupLink) + document.querySelectorAll('.navigation-content a').forEach(setupLink) + document.querySelectorAll('.navigation-content area').forEach(setupLink) }).catch(err => { console.error('Unable to load sidebar') console.error(err) @@ -156,6 +170,14 @@ function loadPage (link, popped = false) { } evt.preventDefault() + + if (device == 0) { + var hamburgerIcon = document.getElementById('hamburger-icon'); + if(hamburgerIcon.classList.contains('nav-open')) { + toggle_mobile_nav(hamburgerIcon); + } + window.scrollTo(0,0); + } } } @@ -164,19 +186,16 @@ window.addEventListener('popstate', loadPage(window.location, true)) // Initialize everything when document is ready document.addEventListener('DOMContentLoaded', () => { // HTML elements - html.searchBox = document.getElementById('search-box') - html.searchField = document.getElementById('search-field') - html.searchResults = document.getElementById('search-results') - html.searchClear = document.getElementById('search-field-clear') - html.navigation = document.getElementById('navigation-content') + html.searchBox = document.getElementsByClassName('search-box') + html.searchField = document.getElementsByClassName('search-field') + html.searchResults = document.getElementsByClassName('search-results') + html.searchClear = document.getElementsByClassName('search-field-clear') + html.navigation = document.getElementsByClassName('navigation-content') html.searchFocused = null // The search result that is currently focused html.content = document.getElementById('content') - // Init search - html.searchBox.style.display = 'inline-block' // display it (we do it here, so the user without javascript won't see a non-working search box) - // We run a search when the value changes, after a given delay - html.searchField.addEventListener('keyup', evt => { + html.searchField[device].addEventListener('keyup', evt => { // only if the pressed key isn't up/down arrow, because we use them to select next/previous search result and not to trigger search if (evt.key !== "ArrowUp" && evt.key !== "ArrowDown") { updateSearch() @@ -184,22 +203,23 @@ document.addEventListener('DOMContentLoaded', () => { }) // clear search when clicking on the clear button - html.searchClear.addEventListener('click', () => { - html.searchField.value = '' - html.searchField.focus() // we focus search after clearing + html.searchClear[device].addEventListener('click', () => { + html.searchField[device].value = '' + html.searchField[device].focus() // we focus search after clearing updateSearch() }) - // Init tooltips - document.querySelectorAll('body > div a').forEach(setupLink) + // Init tooltips for laptop/desktop + document.querySelectorAll('.site_content > div a').forEach(setupLink) + document.querySelectorAll('.site_content > ul a').forEach(setupLink) document.querySelectorAll('body > div area').forEach(setupLink) // register some useful shortcuts document.addEventListener('keyup', evt => { switch (evt.key) { case "Escape": // Esc key - if (html.searchField === document.activeElement) { - html.searchField.value = '' + if (html.searchField[1] === document.activeElement) { + html.searchField[1].value = '' updateSearch() } break @@ -217,12 +237,12 @@ document.addEventListener('DOMContentLoaded', () => { html.searchFocused.className = html.searchFocused.className.replace(' search-selected', '') html.searchFocused = html.searchFocused.nextElementSibling html.searchFocused.className = html.searchFocused.className + ' search-selected' - } else if (document.activeElement === html.searchField) { + } else if (document.activeElement === html.searchField[1]) { // we focus the first element if we were in the search field if (html.searchFocused != null) { html.searchFocused.className = html.searchFocused.className.replace(' search-selected', '') } - html.searchFocused = html.searchResults.children[0] + html.searchFocused = html.searchResults[1].children[0] html.searchFocused.className = html.searchFocused.className + ' search-selected' } break @@ -233,7 +253,7 @@ document.addEventListener('DOMContentLoaded', () => { break case "Control": // ctrl case "/": // the "/" key - html.searchField.focus() // we focus the search + html.searchField[1].focus() // we focus the search break } }) @@ -251,14 +271,14 @@ document.addEventListener('DOMContentLoaded', () => { } const urlParams = parseQueryString(location.search) if (typeof urlParams.q !== 'undefined' && urlParams.q) { - html.searchField.value = urlParams.q + html.searchField[device].value = urlParams.q updateSearch() } }) let searchDelay function updateSearch () { - if (html.searchField == null || html.searchResults == null) { + if (html.searchField[device] == null || html.searchResults[device] == null) { return // Document isn't ready yet } @@ -266,18 +286,18 @@ function updateSearch () { clearTimeout(searchDelay) // reset the delay } - if (html.searchField.value != null && html.searchField.value !== '') { + if (html.searchField[device].value != null && html.searchField[device].value !== '') { // if search isn't empty, we display results after `config.searchDelay` milliseconds searchDelay = setTimeout(() => { - search(html.searchField.value).then(res => { - html.searchResults.innerHTML = res + search(html.searchField[device].value).then(res => { + html.searchResults[device].innerHTML = res }) - html.navigation.style.display = 'none' + html.navigation[device].style.display = 'none' }, config.searchDelay) } else { // if the search field is empty, we display the symbols list again - html.searchResults.innerHTML = '' - html.navigation.style.display = 'block' + html.searchResults[device].innerHTML = '' + html.navigation[device].style.display = 'block' html.searchFocused = null } } diff --git a/data/styles/main.css b/data/styles/main.css index 4610f437..042e7973 100644 --- a/data/styles/main.css +++ b/data/styles/main.css @@ -1,3 +1,7 @@ +* { + box-sizing: border-box; +} + html { color: #111; font-family: "Open Sans", "Droid Sans", Helvetica, sans-serif; @@ -7,111 +11,204 @@ html { body { margin: 0; - min-width: 720px; - padding: 48px 0 0; } a { - color: #08c; + color: #7239b3; text-decoration: none; } h2, h3 { font-family: "Droid Serif", serif; - font-weight: 300; } p { font-size: 14px; } +ul { + list-style: none; + padding: 0; +} + /*********** -* Nav Bar * +* Mobile Navbar * ***********/ - nav { + position: fixed; + display: flex; align-items: center; - background-color: #403757; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); + height: 45px; + width: 100vw; + padding: 0 15px; + background-color: #fff; + z-index: 300; +} + +#hamburger-icon { display: flex; - font-size: 16px; + flex-direction: column; + height: 25px; + width: 45px; justify-content: space-between; - padding: 9px 6px; + z-index: 300; +} + +#hamburger-icon:hover { + cursor: pointer; +} + +.bar1, .bar2, .bar3 { + background-color: #A56DE2; + height: 3px; + width: 100%; + transition: 0.3s; + z-index: 300; +} + +.nav-open .bar1 { + transform: translate(0, 12px) rotate(-45deg); +} + +.nav-open .bar2 { + opacity: 0; +} + +.nav-open .bar3 { + transform: translate(0, -10px) rotate(45deg); +} + +#nav-title { + margin-left: auto; +} + +#nav-title img { + display: block; + border-radius: 5px; + height: 35px; + width: 130px; +} + +#overlay-background { position: fixed; top: 0; - width: calc(100% - 12px); - z-index: 1000; + left: 0; + height: 3rem; + width: 3rem; + border-radius: 50%; + background: #fff; + background-size: cover; + background-position: center; + z-index: 100; + transform: scale(0); + transition: all 600ms cubic-bezier(0.86, 0, 0.07, 1); } -nav a, -nav a:visited, -nav a:active { - color: #fff; - padding: 0 8px; - text-decoration: none; +#overlay-background.nav-open { + transform: scale(150); } -nav a:hover { - opacity: 0.8; +#mobile-menu-overlay { + width: 100vw; + height: 100vh; + position: fixed; + visibility: hidden; + padding: 9vh 5vw 0 5vw; + overflow-y: auto; + font-size: 1.4em; + z-index: 200; + transform: translateX(-100vw); + transition: all 500ms cubic-bezier(0.68, -0.55, 0.265, 1.55); } -nav ul { - list-style: none; - margin: 0; - padding: 0; +#mobile-menu-overlay.nav-open { + visibility: visible; + transform: translateX(0); + transition: all 700ms cubic-bezier(0.68, -0.55, 0.265, 1.55); } -nav li, -nav span { - display: inline; +.search-results a { + color: #666; } -nav .title { - display: inline-block; - flex-grow: 1; +#mobile-menu-overlay > a { + margin: 2vh auto; + color: #7239b3; } -nav .title img { - vertical-align: middle; +#mobile-menu-overlay > a, #mobile-menu-overlay .search-box { + margin: 2vh auto; } -#search-box { - background-clip: padding-box; - background-color: #fff; - border: 1px solid rgba(0, 0, 0, 0.05); - border-radius: 3px; - display: none; +#mobile-menu-overlay ul { + margin-top: 2vh; } -#search-field { - background-color: transparent; - border: none; - font-size: 14px; - line-height: 26px; - padding-left: 6px; - width: 200px; - -webkit-appearance: none; +form { + width: 100%; + height: 50px; + margin: auto; } -#search-field::-webkit-search-cancel-button { - display: none; +.search-box { + width: 100%; + height: 100%; + position: relative; } -#search-field:focus { +.search-field { + display: inline-block; + width: 100%; + height: 100%; + border: 2px solid gray; + border-radius: 5px; + box-shadow: 3px #aaa; + font-size: 1em; + background-color: #E9E9E9; + color: #444; +} + +.search-field:focus{ outline: none; } -#search-field-clear { - cursor: pointer; - margin-right: 6px; - opacity: 0.3; - transition: all 200ms ease-in-out; +#mobile-menu-overlay .search-field { + padding: 0 50px; + border-radius: 10px; +} + +#mobile-menu-overlay .search-logo { + position: absolute; + left: 15px; + top: 8px; +} + +#mobile-menu-overlay .site_navigation a::before { + content: ""; + height: 16px; + width: 16px; vertical-align: middle; } -#search-field:focus ~ #search-field-clear { - opacity: 0.75; +.search-field-clear { + position: absolute; + height: 35px; + right: 5px; + top: 7px; + opacity: 0.5; +} + +.search-field:focus ~ .search-field-clear { + opacity: 1; +} + +.search-field-clear:hover { + cursor: pointer; +} + +input[type="search"]::-webkit-search-cancel-button { + display: none; } /*********** @@ -119,21 +216,20 @@ nav .title img { ***********/ #sidebar { - background-color: #f7f6f8; border-right: 1px solid #eceaf0; - display: inline-block; + display: none; overflow-y: auto; position: fixed; - top: 48px; - width: 240px; - height: calc(100% - 48px); + width: 20vw; + height: 100vh; + padding: 1vw 1vw 0 1vw; + font-size: 14px; } #sidebar a { color: #666; display: inline-block; text-decoration: none; - padding: 3px 6px; width: 100%; } @@ -156,8 +252,6 @@ nav .title img { } #sidebar ul { - font-size: 12px; - list-style: none; margin: 0; padding: 0; } @@ -191,6 +285,13 @@ nav .title img { vertical-align: middle; } +.title img { + display: block; + margin: auto; + width: 10vw; + border-radius: 5px; +} + #navigation-content { overflow: auto; } @@ -227,13 +328,22 @@ nav .title img { line-height: 21px; list-style: none; margin: 6px 3px; - padding-left: 6px; } .navi_inline { padding-left: 12px; } +.navi_inline li::before, +.navi_main li::before { + content: ""; + display: inline-block; + height: 16px; + width: 16px; + margin-right: 6px; + vertical-align: middle; +} + #sidebar .navi_main a { display: initial; padding: 0; @@ -247,14 +357,21 @@ nav .title img { padding: 6px; } -.navi_inline li::before, -.navi_main li::before { - content: ""; - display: inline-block; - height: 16px; - width: 16px; - margin-right: 6px; - vertical-align: middle; +::-webkit-scrollbar { + width: 10px; +} + + +::-webkit-scrollbar-track { + background: #f1f1f1; + } + +::-webkit-scrollbar-thumb { + background: #888; +} + +::-webkit-scrollbar-thumb:hover { + background: #555; } #sidebar .abstract_class > a, @@ -267,22 +384,20 @@ nav .title img { ***********/ #content-wrapper { - display: flex; - flex-direction: column; - margin-left: 240px; - min-height: calc(100vh - 48px); - text-align: left; - vertical-align: top; - width: calc(100% - 240px); - margin-bottom: 49px; + width: 100vw; + padding-top: 7vh; + min-height: 93vh; } #content { - flex: 1; - max-width: 1000px; - margin: 12px auto; - padding: 0 24px; - width: calc(100% - 48px); + width: 100%; + height: 100%; + display: flex; + padding: 2vh 20px; +} + +.site_content { + width: 100%; } #content h1 { @@ -298,6 +413,15 @@ nav .title img { margin-bottom: 6px; } +.toc { + margin: 20px auto; + line-height: 1.6; +} + +.toc h3, .toc ul { + margin: 0; +} + .highlight { border-radius: 6px; padding: 6px; @@ -359,6 +483,7 @@ nav .title img { display: block; margin: 0 auto; text-align: center; + overflow: auto; } .graph .node text { @@ -415,12 +540,6 @@ nav .title img { height: 10px; } -#logo { - float: left; - margin-left: 17px; - display: none; -} - #logo img { width: 203px; height: 52px; @@ -451,19 +570,47 @@ nav .title img { } footer { - background-color: #fafafa; - color: #666; - padding: 16px; - margin-left: 240px; - width: calc(100% - 240px - 32px); - margin-bottom: -48px; - margin-top: -49px; /* 1px extra gets rid of scrollbar when page is short enough not to need one */ + background-color: #7239b3; + color: #fafafa; + padding: 20px; + text-align: center; +} + +footer a { + color: #fafafa; +} + +footer p:nth-of-type(2) { + margin-top: 30px; +} + +footer ul { + display: flex; + justify-content: space-between; + padding: 5px; + margin: 20px auto; + width: 60%; +} + +.social-link { + color: #fff; + scale: 1.5; + transition: 0.2s; +} + +.social-link:hover { + color: #aaa; } .main_source { -moz-tab-size: 4; -o-tab-size: 4; tab-size: 4; + white-space: pre-wrap; +} + +.main_title { + margin-top: 2vh; } .main_type { @@ -559,9 +706,7 @@ div.leaf_brief_description { .main_parameter_table_name, .main_errordomain_table_name, .main_enum_table_name { - vertical-align: top; text-align: right; - font-size: 14px; font-weight: bold; width: 120px; padding-right: 10px; @@ -618,28 +763,33 @@ code { .box .headline { background-image: url("/images/coll_open.svg"); - background-position: calc(100% - 1px) center; + background-position: 0 1px; background-repeat: no-repeat; - background-color: #eef; - border: 1px solid #aaf; - margin: auto; - width: 90%; - margin-top: 20px; + background-size: 25px 25px; + cursor: pointer; + height: 30px; + width: fit-content; font-weight: bold; } +.headline:hover { + cursor: pointer; +} + +.headline h3 { + margin-left: 30px; + display: flex; + align-items: center; + height: 100%; +} + .box .content { - border: 1px solid #aaf; border-top: none; overflow: auto; display: none; margin: auto; - width: 90%; -} - -.box .column { - float: left; - width: 33%; + width: 100%; + padding: 0 20px; } .deprecated { @@ -809,19 +959,19 @@ a.abstract_class, @media (prefers-color-scheme: dark) { body { - background-color: #22222a; - color: #eee; - } - - nav { - background-color: #38304c; + background-color: #131416; + color: #fff; } #sidebar { - background-color: #22222a; + background-color: #1E1E1E; border-right-color: #111; } + .title img { + content: url("/images/logo.svg"); + } + #sidebar li:hover { background-color: rgba(0, 0, 0, 0.5); } @@ -829,11 +979,6 @@ a.abstract_class, background-color: #524a66 !important; } - li.namespace::before, - li.package_index::before { - filter: brightness(200%); - } - #sidebar a { color: #eee; } @@ -851,16 +996,6 @@ a.abstract_class, background-color: #111; } - .box .headline { - background-color: #112; - border-color: #446; - } - - footer { - background-color: #1a1a1a; - color: #eee; - } - .graph .node polygon { stroke: white; } @@ -891,3 +1026,121 @@ a.abstract_class, border: 1px solid #77c; } } + +/************* +* Responsive * +*************/ + +/* Medium devices (landscape tablets, 768px and up) */ +@media only screen and (min-width: 768px) { + + footer ul { + width: 50%; + } + +} + +/* All handheld devices */ +@media only screen and (max-width: 991px) { + + .search-field:focus { + background-color: #fff; + } + + .search-field-clear { + transform: scale(0.7); + } + + .site_navigation .package::before { + display: inline-block; + margin-right: 6px; + } + + .toc ul, .toc h3 { + font-size: 1.2em; + } + + footer { + height: 34vh; + } + +} + +/* Large devices (laptops/desktops, 992px and up) */ +@media only screen and (min-width: 992px) { + + nav, #hamburger-icon { + display: none; + } + + #sidebar { + display: block; + } + + .title { + margin: 5vh 0; + } + + form { + height: 30px; + } + + .search-logo { + position: relative; + bottom: 31px; + scale: 0.8; + } + + .search-field { + padding: 0 23px 0 30px; + border: none; + color: #444; + } + + .search-field-clear { + position: absolute; + right: 5px; + top: 5px; + height: 20px; + width: 20px; + } + + #content-wrapper { + width: 79vw; + margin-left: 20vw; + padding: 7vh 0 3vh 3vw; + min-height: 85vh; + } + + .site_content { + overflow-y: auto; + width: 62vw; + min-height: 100vh; + } + + .toc { + position: fixed; + top: 7vh; + height: 100vh; + padding: 0 1vw 0 1vw; + margin-left: 63vw; + width: 14vw; + } + + footer { + background-color: #7239b3; + color: #fafafa; + padding: 10px; + text-align: center; + margin-left: 20vw; + } + + footer ul { + width: 25%; + } + + footer p:nth-of-type(2) { + margin-top: 10px; + } + +} \ No newline at end of file From 57ef528e7a47b192d11e844cac40531af01b71d7 Mon Sep 17 00:00:00 2001 From: Sudhanshu Tiwari Date: Tue, 8 Oct 2024 20:26:59 +0530 Subject: [PATCH 2/2] data: Change color of links in dark mode --- data/styles/main.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/data/styles/main.css b/data/styles/main.css index 042e7973..2be1c961 100644 --- a/data/styles/main.css +++ b/data/styles/main.css @@ -963,6 +963,10 @@ a.abstract_class, color: #fff; } + a { + color: #cd9ef7; + } + #sidebar { background-color: #1E1E1E; border-right-color: #111;