diff --git a/docs/_includes/search-toggle.html b/docs/_includes/search-toggle.html new file mode 100644 index 000000000000..caa11c63c46f --- /dev/null +++ b/docs/_includes/search-toggle.html @@ -0,0 +1,5 @@ +
+ + + +
diff --git a/docs/_includes/sidebar-search.html b/docs/_includes/sidebar-search.html new file mode 100644 index 000000000000..a365c812e031 --- /dev/null +++ b/docs/_includes/sidebar-search.html @@ -0,0 +1,13 @@ + diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index e0ed71b46818..07f9f23bdbbf 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -2,7 +2,7 @@ - + Expensify Help @@ -12,6 +12,7 @@ + {% seo %} @@ -25,11 +26,20 @@ - - - +
+
+ + + +
+ + {% include search-toggle.html %} +
+ + {% include sidebar-search.html id="sidebar-layer" %} +
{% if page.url == "/" or page.url contains "/hubs/" %} diff --git a/docs/_sass/_colors.scss b/docs/_sass/_colors.scss index d9fa10d24b8e..fe88f2152e0e 100644 --- a/docs/_sass/_colors.scss +++ b/docs/_sass/_colors.scss @@ -3,7 +3,9 @@ $color-green-icons: #8B9C8F; $color-green-borders: #1A3D32; $color-green-highlightBG: #07271F; $color-green-appBG: #061B09; +$color-green-hover: #00a862; $color-light-gray-green: #AFBBB0; $color-blue300: #5AB0FF; $color-blue200: #B0D9FF; $color-white: #E7ECE9; +$color-gray-label: #afbbb0; diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index ebf96476bc0d..720bc95c0732 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -1,9 +1,11 @@ @import 'breakpoints'; @import 'colors'; @import 'fonts'; +@import 'search-bar'; $color-appBG: $color-green-appBG; $color-highlightBG: $color-green-highlightBG; +$color-accent : $color-green400; $color-borders: $color-green-borders; $color-icons: $color-green-icons; $color-text: $color-white; @@ -11,6 +13,8 @@ $color-link: $color-blue300; $color-link-hovered: $color-blue200; $color-success: $color-green400; $color-text-supporting: $color-light-gray-green; +$color-green-hover: $color-green-hover; +$color-gray-label: $color-gray-label; * { margin: 0; @@ -182,6 +186,18 @@ button { align-content: center; } +.flex { + display: -webkit-box; + display: -moz-box; + display: -ms-flexbox; + display: -moz-flex; + display: -webkit-flex; + display: flex; + -webkit-flex-flow: row wrap; + flex-flow: row wrap; + align-content: space-between; +} + #lhn { position: fixed; background-color: $color-highlightBG; @@ -524,6 +540,7 @@ button { .base-icon { width: 20px; height: 20px; + cursor: pointer; } .homepage { diff --git a/docs/_sass/_search-bar.scss b/docs/_sass/_search-bar.scss new file mode 100644 index 000000000000..ace3a7b99ace --- /dev/null +++ b/docs/_sass/_search-bar.scss @@ -0,0 +1,197 @@ +@import 'breakpoints'; +@import 'colors'; +@import 'fonts'; + +$color-appBG: $color-green-appBG; +$color-highlightBG: $color-green-highlightBG; +$color-accent : $color-green400; +$color-borders: $color-green-borders; +$color-icons: $color-green-icons; +$color-text: $color-white; +$color-link: $color-blue300; +$color-link-hovered: $color-blue200; +$color-success: $color-green400; +$color-text-supporting: $color-light-gray-green; +$color-green-hover: $color-green-hover; +$color-gray-label: $color-gray-label; + +.search-icon { + margin: auto 0px; +} + +#sidebar-search { + background-color: $color-appBG; + width: 375px; + height: 100vh; + position: fixed; + display: block; + top: 0; + right: 0; +} + +@media only screen and (max-width: $breakpoint-tablet) { + #sidebar-search { + width: 100%; + } +} + +.searchbar-title-wrapper { + padding: 20px; +} + +.search-title { + font-size: 17px; + padding-bottom: 20px; +} + +#toggle-search-close { + margin: auto; + margin-left: 0px; + margin-right: 10px; +} + +/* Sidebar Layer */ +#sidebar-layer { + position: fixed; + + /* Sit on top of the page content */ + display: none; + + /* Hidden by default */ + width: 100%; + + /* Full width (cover the whole page) */ + height: 100%; + + /* Full height (cover the whole page) */ + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.4); + z-index: 2; +} + +/* All gsc id & class are Google Search relate gcse_0 is the search bar parent & gcse_1 is the search result list parent */ +#___gcse_0 { + margin-left: 20px; +} + +/* This input is in #___gcse_0 search bar */ +input#gsc-i-id1.gsc-input { + background-color: $color-appBG; + color: #E7ECE9; + font-family: "ExpensifyNeue", "Segoe UI Emoji", "Noto Color Emoji" !important; +} + +/* These below #gsc-iw-id1, .gsc-input-box & .gsib_a are inner wrapper of search bar input */ +#gsc-iw-id1 { + background-color: $color-appBG; + border-bottom: $color-borders 2px solid; + border-bottom-left-radius: 0px; + + &:focus-within { + border-bottom: $color-accent 2px solid; + } +} + +.gsc-input-box .gsib_a { + padding: 5px 9px 4px 0px; +} + +.search-icon { + margin-left: auto; +} + +/* This is the close icon on search bar */ +.gsib_b .gsst_a .gscb_a { + color: $color-icons; + + &:hover { + color: $color-text; + } +} + +/* This is to manage hover on parent close icon and make it the same effect on close icon */ +.gsst_a:hover { + + .gscb_a { + color: $color-text !important; + } +} + +/* Manage Google Search label animation */ +input#gsc-i-id1:focus+label.search-label, +input#gsc-i-id1:valid+label.search-label, +input#gsc-i-id1:active+label.search-label { + transform: translateY(-100%) scale(0.80); +} + +label.search-label { + display: block; + position: absolute; + margin-top: -20px; + font-size: 15px; + font-family: "ExpensifyNeue", "Segoe UI Emoji", "Noto Color Emoji"; + transform: translateY(-50%); + left: 20px; + color: $color-gray-label; + transform-origin: left top; + user-select: none; + transition: transform 150ms cubic-bezier(0.4, 0, 0.2, 1), color 150ms cubic-bezier(0.4, 0, 0.2, 1), top 500ms; +} + +/* Hide the relevance, Ads, Branding, find more button & etc sections */ +.gsc-above-wrapper-area, +.gsc-webResult.gsc-result .gsc-url-top, +.gsc-results-wrapper-visible .gsc-adBlock, +.gcsc-more-maybe-branding-root, +.gcsc-find-more-on-google-root { + display: none; +} + +.gsc-control-cse { + background-color: $color-appBG; + border: $color-appBG; + font-family: "ExpensifyNeue", "Helvetica Neue", "Helvetica", Arial, sans-serif !important; + max-height: 80vh; + overflow-y: scroll; +} + +.gs-title { + font-weight: bold; +} + +/* Change the Google Search Button icon into Expensify icon button */ +.gsc-search-button.gsc-search-button-v2 { + padding: 10px; + margin-top: -7px; + margin-left: 15px; + margin-right: 20px; + border-radius: 25px; + background-color: $color-green400; + cursor: pointer; + width: 40px; + height: 40px; +} + +.gsc-search-button.gsc-search-button-v2:hover { + background-color: $color-green-hover; +} + +.gsc-search-button.gsc-search-button-v2 svg { + fill: $color-text; + height: auto; + width: auto; +} + +/* Change the path of the Google Search Button icon into Expensify icon */ +.gsc-search-button.gsc-search-button-v2 svg path { + d: path('M8 1c3.9 0 7 3.1 7 7 0 1.4-.4 2.7-1.1 3.8l5.2 5.2c.6.6.6 1.5 0 2.1-.6.6-1.5.6-2.1 0l-5.2-5.2C10.7 14.6 9.4 15 8 15c-3.9 0-7-3.1-7-7s3.1-7 7-7zm0 3c2.2 0 4 1.8 4 4s-1.8 4-4 4-4-1.8-4-4 1.8-4 4-4z'); + fill-rule: evenodd; + clip-rule: evenodd; +} + +.gsc-resultsbox-visible .gsc-webResult .gsc-result { + border-bottom: none; +} diff --git a/docs/annotations.xml b/docs/annotations.xml new file mode 100644 index 000000000000..adb06b135f25 --- /dev/null +++ b/docs/annotations.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/docs/assets/images/close.svg b/docs/assets/images/close.svg new file mode 100644 index 000000000000..71e4df7ace0c --- /dev/null +++ b/docs/assets/images/close.svg @@ -0,0 +1,11 @@ + + + + + + diff --git a/docs/assets/images/search.svg b/docs/assets/images/search.svg new file mode 100644 index 000000000000..9680cc415454 --- /dev/null +++ b/docs/assets/images/search.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs/assets/js/main.js b/docs/assets/js/main.js index d5d462b83e50..2b9c0cc6fe8c 100644 --- a/docs/assets/js/main.js +++ b/docs/assets/js/main.js @@ -75,9 +75,93 @@ function injectFooterCopywrite() { footer.innerHTML = `©2008-${new Date().getFullYear()} Expensify, Inc.`; } +function openSidebar() { + document.getElementById('sidebar-layer').style.display = 'block'; + + // Make body unscrollable + const yAxis = document.documentElement.style.getPropertyValue('y-axis'); + const body = document.body; + body.style.position = 'fixed'; + body.style.top = `-${yAxis}`; +} + +function closeSidebar() { + document.getElementById('sidebar-layer').style.display = 'none'; + + // Make the body scrollable again + const body = document.body; + const scrollY = body.style.top; + + // Reset the position and top styles of the body element + body.style.position = ''; + body.style.top = ''; + + // Scroll to the original scroll position + window.scrollTo(0, parseInt(scrollY || '0', 10) * -1); +} + +// Function to adapt & fix cropped SVG viewBox from Google based on viewport (Mobile or Tablet-Desktop) +function changeSVGViewBoxGoogle() { + // Get all inline Google SVG elements on the page + const svgsGoogle = document.querySelectorAll('svg'); + + // Create a media query for screens wider than tablet + const mediaQuery = window.matchMedia('(min-width: 800px)'); + + // Check if the viewport is smaller than tablet + if (!mediaQuery.matches) { + Array.from(svgsGoogle).forEach((svg) => { + // Set the viewBox attribute to '0 0 13 13' to make the svg fit in the mobile view + svg.setAttribute('viewBox', '0 0 13 13'); + svg.setAttribute('height', '13'); + svg.setAttribute('width', '13'); + }); + } else { + Array.from(svgsGoogle).forEach((svg) => { + // Set the viewBox attribute to '0 0 20 20' to make the svg fit in the tablet-desktop view + svg.setAttribute('viewBox', '0 0 20 20'); + svg.setAttribute('height', '16'); + svg.setAttribute('width', '16'); + }); + } +} + +// Function to insert element after another +// In this case, we insert the label element after the Google Search Input so we can have the same label animation effect +function insertElementAfter(referenceNode, newNode) { + referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); +} + +// Need to wait up until page is load, so the svg viewBox can be changed +// And the search label can be inserted +window.addEventListener('load', () => { + changeSVGViewBoxGoogle(); + + // Add required into the search input + const searchInput = document.getElementById('gsc-i-id1'); + searchInput.setAttribute('required', ''); + + // Insert search label after the search input + const searchLabel = document.createElement('label'); + searchLabel.classList.add('search-label'); + searchLabel.innerHTML = 'Search for something...'; + insertElementAfter(searchInput, searchLabel); +}); + window.addEventListener('DOMContentLoaded', () => { injectFooterCopywrite(); + // Handle open & close the sidebar + const buttonOpenSidebar = document.getElementById('toggle-search-open'); + if (buttonOpenSidebar) { + buttonOpenSidebar.addEventListener('click', openSidebar); + } + + const buttonCloseSidebar = document.getElementById('toggle-search-close'); + if (buttonCloseSidebar) { + buttonCloseSidebar.addEventListener('click', closeSidebar); + } + if (window.tocbot) { window.tocbot.init({ // Where to render the table of contents. @@ -139,5 +223,8 @@ window.addEventListener('DOMContentLoaded', () => { const scrollingElement = e.target.scrollingElement; const scrollPercentageInArticleContent = clamp(scrollingElement.scrollTop - articleContent.offsetTop, 0, articleContent.scrollHeight) / articleContent.scrollHeight; lhnContent.scrollTop = scrollPercentageInArticleContent * lhnContent.scrollHeight; + + // Count property of y-axis to keep scroll position & reference it later for making the body fixed when sidebar opened + document.documentElement.style.setProperty('y-axis', `${window.scrollY}px`); }); }); diff --git a/docs/context.xml b/docs/context.xml new file mode 100644 index 000000000000..bebbefab2bd3 --- /dev/null +++ b/docs/context.xml @@ -0,0 +1,33 @@ + + + Expensify Help Search + Help Search configuration details + + + + + + + + + + + + + + + + + + + + + + + + + + + + +