Launcher: UI rework

Fixed help modal header margins for title and close button. Help menu titles now have same padding from both sides. Scroll fixed in chrome. Problem in Safari.

Change-Id: I2987ea93379e385125e81ec37b9f0bb61a6d7797
diff --git a/core/installer/welcome/static/launcher.css b/core/installer/welcome/static/launcher.css
index bc716c8..d6038f9 100644
--- a/core/installer/welcome/static/launcher.css
+++ b/core/installer/welcome/static/launcher.css
@@ -3,23 +3,32 @@
   --pico-color: unset;
 }
 
+:root {
+  --bg: #d6d6d6;
+  --bodyBg: #3a3a3a;
+  --text: #3a3a3a;
+  --formText: #d6d6d6;
+  --button: #7f9f7f;
+  --logo: #d4888d;
+  --fontSize: 14px;
+}
+
 body {
   margin: 0;
   padding: 0;
-  font-family: Arial, sans-serif;
+  font-family: Hack, monospace;
   display: flex;
   height: 100vh;
-  padding-left: 10px !important;
-  padding-right: 10px !important;
-  background-color: black;
+  padding-left: 5px !important;
+  padding-right: 5px !important;
+  background-color: var(--bodyBg);
+  overflow-x: hidden;
+  overflow-y: hidden;
 }
 
 #left-panel {
   width: 80px;
-  background-color: #f0f0f0;
-  border-radius: 10px;
-  border-width: 1px;
-  border-color: black;
+  background-color: var(--bg);
   display: flex;
   flex-direction: column;
   align-items: center;
@@ -31,15 +40,50 @@
   display: flex;
   flex-direction: column;
   align-items: center;
+  overflow-y: auto;
+  overflow-x: hidden;
+  padding-top: 3px;
+  width: 95% !important;
+  /* scrollbar-width: thin;
+  scrollbar-color: var(--bodyBg) var(--bg); */
 }
 
+.scrollbar-custom {
+  scrollbar-width: thin;
+  scrollbar-color: var(--bodyBg) var(--bg);
+}
+
+/* .app-list:hover::-webkit-scrollbar {
+  width: 6px;
+  scrollbar-color: var(--bodyBg) var(--bg);
+} */
+
+.scrollbar-custom::-webkit-scrollbar {
+  width: 6px;
+}
+
+.scrollbar-custom::-webkit-scrollbar-track {
+  background-color: var(--bg) !important;
+}
+
+.scrollbar-custom::-webkit-scrollbar-thumb {
+  background-color: var(--bodyBg) !important;
+  border-radius: 4px !important;
+}
+
+.scrollbar-custom::-webkit-scrollbar-thumb:hover {
+  background-color: var(--bodyBg);
+}
+
+/* .layout-scrollbar::-webkit-scrollbar-thumb:active {
+  background-color: var(--bodyBg);
+} */
+
 #right-panel {
   flex: 1;
-  background-color: #f0f0f0;
-  margin: 5px;
+  background-color: none !important;
+  margin: 5px 0 5px 5px;
   padding: 2px;
-  border-radius: 10px;
-  border-color: black;
 }
 
 .appFrame {
@@ -49,30 +93,28 @@
   border: 0;
 }
 
-.app-icon-tooltip {
-  position: relative;
-  display: inline-block;
-  align-items: flex-start;
+.app-icon {
+  /* position: relative; */
+  /* display: inline-block; */
+  display: flex;
+  flex-direction: column;
+  align-items: center;
   justify-content: center;
-  cursor: initial;
+  /* cursor: initial; */
   width: 80px !important;
   height: 50px !important;
   margin-bottom: 10px !important;
   cursor: pointer !important;
-  --pico-background-color: unset !important;
-  --pico-color: unset !important;
+  /* --pico-background-color: unset !important;
+  --pico-color: unset !important; */
 }
 
 .tooltip {
   position: absolute;
   width: 200px;
-  border-radius: 0 10px 10px 0;
-  top: 70%;
-  left: 98%;
+  left: 90px;
   transform: translateY(-50%);
-  background-color: black;
-  color: white;
-  box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
+  background-color: var(--bodyBg);
   padding: 5px;
   z-index: 1;
   display: flex;
@@ -88,56 +130,45 @@
   margin-top: 5px !important;
   padding: 0 !important;
   border: 0 !important;
-  margin-bottom: 5px !important;
+  margin-bottom: 1px !important;
   width: 100% !important;
-  color: white !important;
+  background-color: var(--button) !important;
+  color: var(--bodyBg) !important;
+  border-radius: 0 !important;
   cursor: pointer !important;
   font-size: 16px !important;
 }
 
-.icon {
-  display: flex;
-  justify-content: center;
-  align-items: center !important;
-}
-
 .tooltip p {
-  color: white;
+  color: var(--formText);
   margin: 0;
   cursor: auto;
+  font-size: var(--fontSize);
 }
 
-.app-icon-tooltip:hover {
+.app-icon:hover {
   transform: scale(1.15);
 }
 
-.app-icon-tooltip .background-glow {
-  position: absolute;
-  top: 0;
-  left: 4px;
-  right: 4px;
-  bottom: 0;
-  background: rgba(0, 0, 0, 0);
-  pointer-events: none;
-  border-radius: 5px;
-  box-shadow: 0px 0px 7px 7px black;
-}
-
 .modal-left {
-  width: 30%;
   overflow-y: auto;
   float: left;
   margin-left: 0px;
+  padding-right: 10px;
   background-color: #fbfcfc;
   border-radius: 2px;
 }
 
 .modal-right {
-  /* flex: 1; */
-  width: 70%;
+  flex: 1;
+  /* width: 70%; */
   overflow-y: auto;
   float: right;
   margin-left: 2px;
+  color: var(--bg);
+  padding-left: 10px;
+  padding-right: 10px;
+  font-size: 16px !important;
 }
 
 .app-help-modal {
@@ -173,6 +204,12 @@
   align-items: center;
   position: relative;
   margin-bottom: 2px !important;
+  background-color: var(--bodyBg) !important;
+}
+
+header h4 {
+  color: var(--formText) !important;
+  padding-left: 10px;
 }
 
 .close-button {
@@ -185,7 +222,7 @@
   height: 1.5em;
   position: absolute;
   top: 11px;
-  right: 5px;
+  right: 28px;
 }
 
 .modal-article {
@@ -194,6 +231,8 @@
   min-height: 90% !important;
   max-height: 90% !important;
   overflow: hidden;
+  padding-left: 5px !important;
+  padding-right: 5px !important;
 }
 
 .help-content {
@@ -204,19 +243,21 @@
   width: 50px;
   height: 50px;
   border-radius: 50%;
-  background-color: #ccc;
+  background-color: var(--bodyBg);
   display: flex;
   justify-content: center;
   align-items: center;
+  margin-top: 2px;
 }
 
-.circle p {
+#user-initial {
   font-size: 24px;
   text-align: center;
   line-height: 50px;
   margin: 0;
   position: relative;
   display: inline-block;
+  color: var(--logo);
 }
 
 .user-circle {
@@ -232,7 +273,7 @@
   margin-top: 2px !important;
   margin-bottom: 4px !important;
   border-width: 2px !important;
-  border-color: black !important;
+  border-color: var(--bodyBg) !important;
   width: 100% !important;
 }
 
@@ -245,7 +286,7 @@
 
 .modal-left ul li {
   list-style: none !important;
-  padding-inline-start: 19px !important;
+  padding-inline-start: 10px !important;
   margin-bottom: 0px;
   font-size: 16px !important;
 }
@@ -254,19 +295,17 @@
   --pico-text-decoration: none;
   cursor: pointer;
 }
-
 .modal-left ul li a[aria-current] {
   color: var(--pico-primary);
 }
 
 .tooltip-user {
   position: absolute;
-  top: 54px;
-  left: 90px;
+  top: 45px;
+  left: 85.5px;
   transform: translateY(-50%);
   width: 234px;
-  background-color: black;
-  box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
+  background-color: var(--bodyBg);
   padding: 5px;
   z-index: 1;
   display: flex;
@@ -274,7 +313,6 @@
   align-items: center;
   visibility: hidden;
   opacity: 0;
-  border-radius: 0 0 10px 0;
   cursor: auto;
 }
 
@@ -284,9 +322,11 @@
   border: 0 !important;
   margin-bottom: 5px !important;
   width: 100% !important;
-  color: white !important;
   cursor: pointer !important;
   font-size: 19px !important;
+  border-radius: 0;
+  background-color: var(--button);
+  color: var(--text) !important;
 }
 
 .tooltip-user p {
@@ -294,4 +334,5 @@
   margin: 0;
   cursor: auto;
   font-size: 19px;
+  color: var(--logo);
 }
diff --git a/core/installer/welcome/static/launcher.js b/core/installer/welcome/static/launcher.js
index cbd35fd..ed54a70 100644
--- a/core/installer/welcome/static/launcher.js
+++ b/core/installer/welcome/static/launcher.js
@@ -1,74 +1,92 @@
+function showTooltip(obj) {
+  obj.style.visibility = 'visible';
+  obj.style.opacity = '1';
+}
+function hideTooltip(obj) {
+  obj.style.visibility = 'hidden';
+  obj.style.opacity = '0';
+}
+
 document.addEventListener("DOMContentLoaded", function () {
   document.getElementById('appFrame-default').contentDocument.write("Welcome to the dodo: application launcher, think of it as your desktop environment. You can launch applications from left-hand side dock. You should setup VPN clients on your devices, so you can install applications from Application Manager and access your private network. Instructions on how to do that can be viewed by clicking <b>Help</b> button after hovering over <b>Headscale</b> icon in the dock.");
-
-  function showTooltip(obj) {
-    obj.style.visibility = 'visible';
-    obj.style.opacity = '1';
-  }
-  function hideTooltip(obj) {
-    obj.style.visibility = 'hidden';
-    obj.style.opacity = '0';
-  }
-
+  document.getElementById('appFrame-default').style.backgroundColor = '#d6d6d6';
+  const icons = document.querySelectorAll(".app-icon");
   const circle = document.querySelector(".user-circle");
   const tooltipUser = document.querySelector("#tooltip-user");
-  [
-    ['mouseenter', () => showTooltip(tooltipUser)],
-    ['mouseleave', () => hideTooltip(tooltipUser)],
-  ].forEach(([event, listener]) => {
-    circle.addEventListener(event, listener);
+  const initial = document.getElementById('user-initial');
+
+  circle.addEventListener('mouseenter', () => {
+    icons.forEach(icon => {
+      const tooltip = icon.nextElementSibling;
+      hideTooltip(tooltip);
+    });
+    showTooltip(tooltipUser);
+    initial.style.color = "#7f9f7f";
   });
 
-  const iframes = {};
-  const rightPanel = document.getElementById('right-panel');
+  circle.addEventListener('mouseleave', () => {
+    hideTooltip(tooltipUser);
+    initial.style.color = "#d4888d";
+  });
 
-  function showIframe(appId) {
-    document.querySelectorAll('.appFrame').forEach(iframe => {
-      iframe.style.display = iframe.id === `appFrame-${appId}` ? 'block' : 'none';
-    });
-  }
+  let hideTimeout;
+  let activeTooltip;
 
-  function createIframe(appId, appUrl) {
-    const iframe = document.createElement('iframe');
-    iframe.id = `appFrame-${appId}`;
-    iframe.className = 'appFrame';
-    iframe.src = appUrl;
-    iframe.style.display = 'none';
-    rightPanel.appendChild(iframe);
-    iframes[appId] = iframe;
-  }
-
-  const icons = document.querySelectorAll(".app-icon-tooltip");
   icons.forEach(function (icon) {
     icon.addEventListener("click", function (event) {
       event.stopPropagation();
       const appUrl = this.getAttribute("data-app-url");
       const appId = this.getAttribute("data-app-id");
-      if (!appUrl) {
-        const modalId = `modal-${this.querySelector('.help-button').id.replace('help-button-', '')}`;
+      const modalId = this.getAttribute("data-modal-id");
+
+      if (!appUrl && modalId) {
         openModal(document.getElementById(modalId));
       } else {
         if (!iframes[appId]) createIframe(appId, appUrl);
         showIframe(appId);
-      }
-      document.querySelectorAll(".app-icon-tooltip .background-glow").forEach((e) => e.remove());
-      const glow = document.createElement('div');
-      glow.classList.add("background-glow");
-      glow.setAttribute("style", "transform: none; transform-origin: 50% 50% 0px;")
-      this.appendChild(glow);
+        document.querySelectorAll(".app-icon").forEach((icon) => {
+          icon.style.color = "var(--bodyBg)";
+        });
+        this.style.color = "var(--button)";
+      };
     });
-    const tooltip = icon.querySelector('.tooltip');
-    tooltip.addEventListener("click", function (event) {
-      event.stopPropagation();
-    });
+
+    const tooltip = icon.nextElementSibling;
     [
-      ['mouseenter', () => showTooltip(tooltip)],
-      ['mouseleave', () => hideTooltip(tooltip)],
-      ['focus', () => showTooltip(tooltip)],
-      ['blur', () => hideTooltip(tooltip)],
+      ['mouseenter', () => {
+        clearTimeout(hideTimeout);
+        if (activeTooltip && activeTooltip !== tooltip) {
+          hideTooltip(activeTooltip);
+        };
+        const rect = icon.getBoundingClientRect();
+        tooltip.style.top = `${rect.top + 26}px`;
+        showTooltip(tooltip);
+        activeTooltip = tooltip;
+      }],
+      ['mouseleave', () => {
+        hideTimeout = setTimeout(() => {
+          hideTooltip(tooltip);
+          if (activeTooltip === tooltip) {
+            activeTooltip = null;
+          };
+        }, 200);
+      }],
     ].forEach(([event, listener]) => {
       icon.addEventListener(event, listener);
     });
+
+    tooltip.addEventListener('mouseenter', () => {
+      clearTimeout(hideTimeout);
+    });
+
+    tooltip.addEventListener('mouseleave', () => {
+      hideTimeout = setTimeout(() => {
+        hideTooltip(tooltip);
+        if (activeTooltip === tooltip) {
+          activeTooltip = null;
+        };
+      }, 200);
+    });
   });
 
   let visibleModal = undefined;
@@ -77,6 +95,7 @@
     modal.setAttribute("open", true);
     visibleModal = modal;
   };
+
   const closeModal = function (modal) {
     modal.removeAttribute("open");
     modal.setAttribute("close", true);
@@ -84,6 +103,7 @@
   };
 
   const helpButtons = document.querySelectorAll('.help-button');
+
   helpButtons.forEach(function (button) {
     button.addEventListener('click', function (event) {
       event.stopPropagation();
@@ -101,19 +121,33 @@
   });
 
   const modalHelpButtons = document.querySelectorAll('.title-menu');
+
   modalHelpButtons.forEach(function (button) {
     button.addEventListener('click', function (event) {
       event.stopPropagation();
       const helpTitle = button.getAttribute('id');
       const helpTitleId = helpTitle.substring('title-'.length);
       const helpContentId = 'help-content-' + helpTitleId;
-      const allContentElements = document.querySelectorAll('.help-content');
+      let clDiv = document.getElementById(helpContentId).parentNode;
+      const allContentElements = clDiv.querySelectorAll('.help-content');
+
       allContentElements.forEach(function (contentElement) {
         contentElement.style.display = "none";
       });
-      modalHelpButtons.forEach(function (button) {
+
+      let currentHelpTitle = button;
+      while (currentHelpTitle && !currentHelpTitle.classList.contains('modal-left')) {
+        currentHelpTitle = currentHelpTitle.parentNode;
+        if (currentHelpTitle === document.body) {
+          currentHelpTitle = null;
+          break;
+        }
+      }
+
+      currentHelpTitle.querySelectorAll('.title-menu').forEach(function (button) {
         button.removeAttribute("aria-current");
       });
+
       document.getElementById(helpContentId).style.display = 'block';
       button.setAttribute("aria-current", "page");
     });
@@ -126,13 +160,32 @@
   });
 
   document.addEventListener("click", (event) => {
-    if (visibleModal === null) return;
+    if (visibleModal === null || visibleModal === undefined) return;
     const modalContent = visibleModal.querySelector("article");
     const closeButton = visibleModal.querySelector(".close-button");
     if (!modalContent.contains(event.target) || closeButton.contains(event.target)) {
       closeModal(visibleModal);
     }
   });
+
+  const iframes = {};
+  const rightPanel = document.getElementById('right-panel');
+
+  function showIframe(appId) {
+    document.querySelectorAll('.appFrame').forEach(iframe => {
+      iframe.style.display = iframe.id === `appFrame-${appId}` ? 'block' : 'none';
+    });
+  };
+
+  function createIframe(appId, appUrl) {
+    const iframe = document.createElement('iframe');
+    iframe.id = `appFrame-${appId}`;
+    iframe.className = 'appFrame';
+    iframe.src = appUrl;
+    iframe.style.display = 'none';
+    rightPanel.appendChild(iframe);
+    iframes[appId] = iframe;
+  };
 });
 
 function copyToClipboard(elem, text) {
@@ -140,7 +193,7 @@
   elem.setAttribute("data-tooltip", "Copied");
   elem.setAttribute("data-placement", "bottom");
   setTimeout(() => {
-	elem.removeAttribute("data-tooltip");
-	elem.removeAttribute("data-placement");
+    elem.removeAttribute("data-tooltip");
+    elem.removeAttribute("data-placement");
   }, 500);
-}
+};