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/values-tmpl/dodo-app.cue b/core/installer/values-tmpl/dodo-app.cue
index ddd3b17..fbbd8ad 100644
--- a/core/installer/values-tmpl/dodo-app.cue
+++ b/core/installer/values-tmpl/dodo-app.cue
@@ -172,8 +172,7 @@
 
 help: [{
 	title: "How to use"
-	contents: """
-	Clone: git clone ssh://\(_domain):\(input.sshPort)/app  <button onClick='copyToClipboard(this, "git clone ssh://\(_domain):\(input.sshPort)/app")'><svg width='24px' height='24px' viewBox='-2.4 -2.4 28.80 28.80' fill='none' xmlns='http://www.w3.org/2000/svg'><g id='SVGRepo_bgCarrier' stroke-width='0'></g><g id='SVGRepo_tracerCarrier' stroke-linecap='round' stroke-linejoin='round'></g><g id='SVGRepo_iconCarrier'> <path fill-rule='evenodd' clip-rule='evenodd' d='M19.5 16.5L19.5 4.5L18.75 3.75H9L8.25 4.5L8.25 7.5L5.25 7.5L4.5 8.25V20.25L5.25 21H15L15.75 20.25V17.25H18.75L19.5 16.5ZM15.75 15.75L15.75 8.25L15 7.5L9.75 7.5V5.25L18 5.25V15.75H15.75ZM6 9L14.25 9L14.25 19.5L6 19.5L6 9Z' fill='#080341'></path> </g></svg></button>  
-	Server public key: \(input.ssKeys.public)
+	"contents": """
+	Clone: git clone ssh://\(_domain):\(input.sshPort)/app <div onClick='copyToClipboard(this, "git clone ssh://\(_domain):\(input.sshPort)/app")' style='display: inline-block; cursor: pointer;'> <svg width='26px' height='26px' viewBox='-0 -0 28.80 28.80' fill='#7f9f7f' xmlns='http://www.w3.org/2000/svg' style='outline: none;'> <g id='SVGRepo_bgCarrier' stroke-width='0'></g> <g id='SVGRepo_tracerCarrier' stroke-linecap='round' stroke-linejoin='round'></g> <g id='SVGRepo_iconCarrier'> <path fill-rule='evenodd' clip-rule='evenodd' d='M19.5 16.5L19.5 4.5L18.75 3.75H9L8.25 4.5L8.25 7.5L5.25 7.5L4.5 8.25V20.25L5.25 21H15L15.75 20.25V17.25H18.75L19.5 16.5ZM15.75 15.75L15.75 8.25L15 7.5L9.75 7.5V5.25L18 5.25V15.75H15.75ZM6 9L14.25 9L14.25 19.5L6 19.5L6 9Z' fill='#7f9f7f'></path> </g> </svg> </div>  Server public key: \(input.ssKeys.public)
 	"""
 }]
diff --git a/core/installer/values-tmpl/headscale.cue b/core/installer/values-tmpl/headscale.cue
index ec06383..5071b4a 100644
--- a/core/installer/values-tmpl/headscale.cue
+++ b/core/installer/values-tmpl/headscale.cue
@@ -5,7 +5,7 @@
 
 name: "headscale"
 namespace: "app-headscale"
-icon: "<svg xmlns='http://www.w3.org/2000/svg' width='50' height='50' viewBox='0 0 48 48'><circle cx='24' cy='24' r='4.5' fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round'/><circle cx='38' cy='24' r='4.5' fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round'/><circle cx='38' cy='10' r='4.5' fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round'/><circle cx='24' cy='10' r='4.5' fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round'/><circle cx='10' cy='10' r='4.5' fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round'/><circle cx='10' cy='24' r='4.5' fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round'/><circle cx='10' cy='38' r='4.5' fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round'/><circle cx='24' cy='38' r='4.5' fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round'/><circle cx='38' cy='38' r='4.5' fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round'/><circle cx='24' cy='38' r='2' fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round'/><circle cx='24' cy='24' r='2' fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round'/><circle cx='10' cy='24' r='2' fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round'/><circle cx='38' cy='24' r='2' fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round'/></svg>"
+icon: "<svg xmlns='http://www.w3.org/2000/svg' width='50' height='50' viewBox='0 0 48 48'><circle cx='24' cy='24' r='4.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='38' cy='24' r='4.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='38' cy='10' r='4.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='24' cy='10' r='4.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='10' cy='10' r='4.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='10' cy='24' r='4.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='10' cy='38' r='4.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='24' cy='38' r='4.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='38' cy='38' r='4.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='24' cy='38' r='2' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='24' cy='24' r='2' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='10' cy='24' r='2' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='38' cy='24' r='2' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/></svg>"
 
 images: {
 	headscale: {
diff --git a/core/installer/welcome/launcher-tmpl/launcher.html b/core/installer/welcome/launcher-tmpl/launcher.html
index 91562f5..6d404ad 100644
--- a/core/installer/welcome/launcher-tmpl/launcher.html
+++ b/core/installer/welcome/launcher-tmpl/launcher.html
@@ -5,13 +5,14 @@
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>dodo: Launcher</title>
     <link rel="stylesheet" type="text/css" href="/static/pico.2.0.6.min.css">
-    <link rel="stylesheet" type="text/css" href="/static/launcher.css?v=0.0.2">
+    <link rel="stylesheet" type="text/css" href="/static/launcher.css?v=0.0.13">
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/hack-font/3.3.0/web/hack.min.css">
 </head>
 <body class="container-fluid">
     <div id="left-panel">
         <div class="user-circle">
             <div class="circle">
-                <p>{{ GetUserInitials .LoggedInUsername }}</p>
+                <p id="user-initial">{{ GetUserInitials .LoggedInUsername }}</p>
                 <div class="tooltip-user" id="tooltip-user">
                     <p>{{ .LoggedInUsername }}</p>
                     <a href="{{ .LogoutURL }}" role="button" id="logout-button">Log Out</a>
@@ -19,28 +20,26 @@
             </div>
         </div>
         <hr class="separator">
-        <div class="app-list">
+        <div class="app-list scrollbar-custom">
             {{range .AllAppsInfo}}
-                <div class="app-icon-tooltip" data-app-id="{{ .Id }}" data-app-url="{{ .URL }}">
-                    <div class="icon">
-                        {{.Icon}}
-                    </div>
-                    <div class="tooltip">
-                        <p>{{ .Name }}</p>
-                        {{ if .DisplayURL }}
-                            <p>{{ .DisplayURL }}</p>
-                        {{ end }}
-                        {{ if .Help }}
-                            <button class="help-button" id="help-button-{{ CleanAppName .Id }}">Help</button>
-                        {{ end }}
-                    </div>
-                </div>
+            <div class="app-icon" data-app-id="{{ .Id }}" data-app-url="{{ .URL }}" {{ if not .URL }}data-modal-id="modal-{{ CleanAppName .Id }}"{{ end }}>
+                {{.Icon}}
+            </div>
+            <div class="tooltip">
+                <p>{{ .Name }}</p>
+                {{ if .DisplayURL }}
+                    <p>{{ .DisplayURL }}</p>
+                {{ end }}
+                {{ if .Help }}
+                    <button class="help-button" id="help-button-{{ CleanAppName .Id }}">Help</button>
+                {{ end }}
+            </div>
                 <dialog class="app-help-modal" id="modal-{{ CleanAppName .Id }}" close>
                     <article class="modal-article">
                         <header>
                             <h4>{{ .Name }}</h4>
                             <button class="close-button" id="close-help-{{ CleanAppName .Id }}">
-                                <svg xmlns="http://www.w3.org/2000/svg" width="1.5em" height="1.5em" viewBox="0 0 32 32"><path fill="black" d="M16 2C8.2 2 2 8.2 2 16s6.2 14 14 14s14-6.2 14-14S23.8 2 16 2m5.4 21L16 17.6L10.6 23L9 21.4l5.4-5.4L9 10.6L10.6 9l5.4 5.4L21.4 9l1.6 1.6l-5.4 5.4l5.4 5.4z"/></svg>
+                                <svg xmlns="http://www.w3.org/2000/svg" width="1.5em" height="1.5em" viewBox="0 0 32 32"><path fill="#d4888d" d="M16 2C8.2 2 2 8.2 2 16s6.2 14 14 14s14-6.2 14-14S23.8 2 16 2m5.4 21L16 17.6L10.6 23L9 21.4l5.4-5.4L9 10.6L10.6 9l5.4 5.4L21.4 9l1.6 1.6l-5.4 5.4l5.4 5.4z"/></svg>
                             </button>
                         </header>
                         <div class="app-help-modal-article">
@@ -81,6 +80,6 @@
             {{ template "help-content-template" (dict "Help" $h.Children "First" false) }}
         {{ end }}
     {{ end }}
-    <script src="/static/launcher.js?v=0.0.3"></script>
+    <script src="/static/launcher.js?v=0.0.13"></script>
 </body>
 </html>
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);
-}
+};