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 @@
+
{% 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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+