Javascript – Sidebar that expands/collapses on mouseover, storing state when routing between pages

I am working on a multi-page web app in HTML/CSS/JS + jQuery. I am trying to build a sidebar component that expands and collapses on mouseover / mouseout. The sidebar has links to other pages on the application. The expand/collapse is working nicely, except for a very specific use case, and I’m totally stumped.

I’m using a variable mini to keep track of whether the sidebar is in collapsed (mini) or expanded state. I dynamically update the sidebar width based on whether mini is true or false, so when the user moves the mouse over the sidebar, mini = false and the sidebar expands…and when the user moves the mouse out of the sidebar, mini = true and the sidebar collapses.

The bug:

  1. The user hovers mouse over sidebar to expand it

  2. The user clicks on a link and gets routed to a new page

  3. The user keeps the mouse hovering over the sidebar, so that when they land on the new page, the mouse is still over the sidebar

  4. Now, the expand/collapse function is working inversely, so that when the user moves the mouse away, the menu expands, and when the user moves the mouse into the div, the menu collapses and disappears. Frustrating!

I think what’s happening is that the sidebar is built in the collapsed state on page load by default. Somehow I need to be able to determine whether the user has the mouse hovering inside the sidebar div on page load, so I can build the sidebar accordingly. I’d super appreciate any ideas! See below for my code. I’m not able to simulate the page routing, but the overall idea should be clear. In my code example, the sidebar functions are working as intended, so I’ve included screen grabs of what happens in the actual application with the page routing enabled. See below. Thanks!

enter image description here
enter image description here

var mini = true;
const logo = $("#nav-logo");
let activeState = false;
let activePage;
let iconsArr = [
  "#dashboard-icon",
  "#projects-icon",
  "#assess-icon",
  "#config-icon",
];

let listItemsArr = [
  "#dashboard-list-item",
  "#projects-list-item",
  "#assess-list-item",
  "#config-list-item",
];

$(function() {
  attachClickListeners();
});

const toggleSidebar = () => {
  if (mini) {
    // sidebar
    $("#mySidebar").css("width", "225px");
    // main
    $("#main").css("margin-left", "225px");
    // logo
    $("#nav-logo").attr("src", "https://www.creativefabrica.com/wp-content/uploads/2018/11/Company-business-generic-logo-by-DEEMKA-STUDIO.jpg");
    $("#nav-logo").css("width", "120px");
    // Logo text
    $("#logo-text-container").show();
    // list item styling
    $(".list-item").css("padding-left", "12px");
    $(".list-item").css("margin-bottom", "4px");
    $(".list-item-text").show();
    // Active state and page
    if (activePage != undefined) {
      // Remove active state from non-active items
      listItemsArr.forEach((item) => {
        if (item[1] != activePage[0]) {
          $(item).removeClass("active");
        }
      });

      // Add active class
      $(`#${activePage}-icon`).removeClass("active");
      $(`#${activePage}-list-item`).addClass("active");
    }

    // mini variable
    this.mini = false;
  } else {
    // sidebar
    $("#mySidebar").css("width", "60px");
    // main
    $("#main").css("margin-left", "60px");
    // logo
    $("#nav-logo").attr("src", "https://www.creativefabrica.com/wp-content/uploads/2018/11/Company-business-generic-logo-by-DEEMKA-STUDIO.jpg");
    $("#nav-logo").css("width", "30px");
    // logo text
    $("#logo-text-container").hide();
    // list item styling
    $(".list-item").css("padding-left", "0px");
    $(".list-item").css("margin-bottom", "6px");
    $(".list-item-text").hide();

    // Active state and page
    if (activePage != undefined) {
      // Active state and page
      if (activePage != undefined) {
        // Remove active state from non-active items
        iconsArr.forEach((item) => {
          if (item[1] != activePage[0]) {
            $(item).removeClass("active");
          }
        });

        // Add active class to active item
        $(`#${activePage}-icon`).addClass("active");
        $(`#${activePage}-list-item`).removeClass("active");
      }
    }

    // mini variable
    this.mini = true;
  }
};

const attachClickListeners = () => {
  $("#dashboard-list-item").off();
  $("#dashboard-list-item").on("click", () => {
    if (!activeState) {
      activeState = true;
    }
    toggleActiveState("#dashboard-icon");
    activePage = "dashboard";
  });

  $("#projects-list-item").off();
  $("#projects-list-item").on("click", () => {
    if (!activeState) {
      activeState = true;
    }
    toggleActiveState("#projects-icon");
    activePage = "projects";
  });

  $("#assess-list-item").off();
  $("#assess-list-item").on("click", () => {
    if (!activeState) {
      activeState = true;
    }
    toggleActiveState("#assess-icon");
    activePage = "assess";
  });

  $("#config-list-item").off();
  $("#config-list-item").on("click", () => {
    if (!activeState) {
      activeState = true;
    }
    toggleActiveState("#config-icon");
    activePage = "config";
  });
};

const toggleActiveState = (id) => {
  let element = $(id);

  iconsArr.forEach((item) => {
    if (item === id) {
      $(element).addClass("active");
    } else {
      $(item).removeClass("active");
    }
  });
};
.active {
  background: lightblue;
}

main .sidebar {
  position: absolute;
  top: 0;
  right: 25px;
  font-size: 36px;
  margin-left: 50px;
}

#main {
  padding: 16px;
  margin-left: 85px;
  transition: margin-left 0.5s;
}

body {
  font-family: "Poppins", sans-serif;
  font-size: 14px;
  font-weight: 400;
}

.sidebar {
  height: 100vh;
  width: 60px;
  position: fixed;
  transition: 0.5s ease;
  left: 0;
  top: 0;
  /* padding-left: 15px; */
  padding-top: 9px;
  background-color: #fafafa;
  border-right: 1px solid #e6e6e6;
  white-space: nowrap;
  overflow-x: hidden;
  z-index: 1;
}

#nav-logo,
#logo-text {
  transition: 0.5s ease;
}

.body-text {
  height: 100%;
  width: 100%;
  margin-left: 250px;
  padding-top: 1px;
  padding-left: 25px;
}

#nav-logo {
  width: 30px;
  margin-left: 15px;
}

#logo-text-container {
  margin-left: 30px;
  display: none;
}

#logo-text {
  font-size: 18px;
  margin-block-start: 0em;
}

.list-item {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  cursor: pointer;
  border: 1px solid transparent;
  border-radius: 100px;
  margin-bottom: 7px;
}

.list-item:hover {
  background: lightblue;
}

.list-item-text {
  font-size: 14px;
  margin-top: 15px !important;
  display: none;
}

.li-text-margin-left {
  margin-left: 7px;
}

#add-assessment-list-item-text {
  margin-left: 4px;
}

#projects-list-item-text {
  margin-left: 1px;
}

#nav-menu-items {
  padding-inline-start: 7px;
  width: 206px;
  transition: 0.5s ease;
}

#nav-menu-items i {
  font-size: 1.2rem;
  /* margin-right: 0.7rem; */
  padding: 10px 10px;
  border-radius: 60px;
}

.list-item-text {
  margin-block-start: 0.2em;
}
<link href="https://kit.fontawesome.com/ee3b09a28a.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<!-- Sidebar -->
<div id="mySidebar" class="sidebar" onmouseover="toggleSidebar()" onmouseout="toggleSidebar()">
  <!-- Expanded Logo Image -->
  <div id="logo-image-container">
    <img src="https://www.creativefabrica.com/wp-content/uploads/2018/11/Company-business-generic-logo-by-DEEMKA-STUDIO.jpg" id="nav-logo" />
  </div>
  <!-- /Expanded Logo Image -->
  <!--  Expanded Logo Image Text -->
  <div id="logo-text-container">
    <p id="logo-text">Logo Text</p>
  </div>
  <!--  /Expanded Logo Image Text -->

  <!-- Menu Items -->
  <ul id="nav-menu-items">
    <li class="list-item" id="dashboard-list-item">
      <i class="fa-duotone fa-table-columns" id="dashboard-icon"></i>
      <p class="list-item-text li-text-margin-left">Dashboard</p>
    </li>

    <li class="list-item" id="projects-list-item">
      <i class="fa-duotone fa-rectangle-history-circle-user" id="projects-icon"></i>
      <p class="list-item-text" id="projects-list-item-text">Projects</p>
    </li>

    <li class="list-item" id="assess-list-item">
      <i class="fa-duotone fa-address-card" id="assess-icon"></i>
      <p class="list-item-text" id="add-assessment-list-item-text">
        Add Assessment
      </p>
    </li>

    <li class="list-item" id="config-list-item">
      <i class="fa-duotone fa-folder-gear" id="config-icon"></i>
      <p class="list-item-text li-text-margin-left">Configuration</p>
    </li>
  </ul>
  <!-- /Menu Items -->
</div>
<!-- /Sidebar -->

<!-- Main -->
<div id="main">
  <h2>Open/Collapse Sidebar on Hover</h2>
  <p>Hover over any part of the sidebar to open the it.</p>
  <p>To close the sidebar, move your mouse out of the sidebar.</p>
</div>
<!-- /Main -->

ERROR:failed to solve: process “/bin/bash -ol pipefail -c npm run build” did not complete successfully: exit code: 1 while deploying nextjs on railway


[stage-0 8/10] RUN –mount=type=cache,id=s/8a557944-4c41-4e06-8de9-06bfcc5e8aaf-next/cache,target=/app/.next/cache –mount=type=cache,id=s/8a557944-4c41-4e06-8de9-06bfcc5e8aaf-node_modules/cache,target=/app/node_modules/.cache npm run build:

17.62

17.62 Import trace for requested module:

17.62 ./node_modules/@clerk/shared/dist/react/index.mjs

17.62 ./node_modules/@clerk/clerk-react/dist/esm/hooks/useOrganization.js

17.62 ./node_modules/@clerk/clerk-react/dist/esm/hooks/index.js

17.62 ./node_modules/@clerk/clerk-react/dist/esm/index.js

17.62 ./app/(auth)/sign-up/[[…sign-up]]/page.jsx

17.62

17.62

17.62 > Build failed because of webpack errors


Dockerfile:24


22 | # build phase

23 | COPY . /app/.

24 | >>> RUN –mount=type=cache,id=s/8a557944-4c41-4e06-8de9-06bfcc5e8aaf-next/cache,target=/app/.next/cache –mount=type=cache,id=s/8a557944-4c41-4e06-8de9-06bfcc5e8aaf-node_modules/cache,target=/app/node_modules/.cache npm run build

25 |

26 |


ERROR: failed to solve: process “/bin/bash -ol pipefail -c npm run build” did not complete successfully: exit code: 1

Error: Docker build failed

i’m facing this error deploying in railway.app

UseEffect return statement call twice when update the state value

When I click NewTab button, newtab state will change and I want to call useEffect when newTab state change, so it will goBack(), and will call return statement as well, but somehow return statement executing twice, with both old value and new value (false , true respectively).

Here is my problem statement.

const App = () => {
    const [newTab, setNewTab] = useState(false);

    useEffect(() => {
       if (newTab) {
         navigation.goBack();
       }

        return () => { // call twice first get false, and second time get true
            if (newTab == false) {
                //clear the redux data
            }
        }
    }, [newTab]);

    return (
        <View>
            <TouchableOpacity
               onPress={() => {
                  navigation.goBack();
               }}>
            GoBack
        </TouchableOpacity>

            <TouchableOpacity
                onPress={() => {
                    setNewTab(true);
                    //Code for the push data in Redux store
                }}>
                NewTab
            </TouchableOpacity>
        </View>
    )
}

export default App();

How to write condition of localStorage inside ejs page

How can I check if an item is set in localStorage inside a ejs page? Currently I am using

<% if (localStorage.getItem('wishlistState') === null) { %>
           //code to write          
 <% } %>

in here it is not entering to condition,it shows localStorage is undefined,so what is the solution for checking inside a ejs page

Is there a way to handle a dialog html element submission with a form that doesn’t reload the page?

I am creating a library project, wherein the user can add books through a html dialog element where i have nested a form. Submission of the form creates a libraryCard element using javascript that should be appended to the bookStorage div, displaying as a book on the shelf of the library.

The element creation works fine but as soon as i submit the form the page gets reloaded and the dynamically created elements get deleted from the DOM. One solution i found was using event.preventDefault() but event has apparently been deprecated. I have attached my implementation details below.

<div class="bookStorage">
            <div class="card">
                <p><span class="field">Book Name :</span> <span class="valueName">The Kingdom of Fantasy</span></p>
                <p><span class="field">Author :</span> <span class="valueAuthor">Elisabetta Dami</span></p>
                <p><span class="field">Number of pages :</span> <span class="valuePages">320</span></p>
            </div>
            <div class="card">
                <p><span class="field">Book Name :</span> <span class="valueName">Prisoner of Askaban</span></p>
                <p><span class="field">Author :</span> <span class="valueAuthor">JK Rowling</span></p>
                <p><span class="field">Number of pages :</span> <span class="valuePages">270</span></p>
            </div>
        </div>

Javascript :

const addBookButton = document.querySelector('.addBook');
const closeDialogButton = document.querySelector('dialog button');
const dialog = document.querySelector('dialog');
const form = document.querySelector('form');

addBookButton.addEventListener('click', () => {
    dialog.showModal();
});

closeDialogButton.addEventListener('click', () => {
    dialog.close();
})

form.addEventListener('submit', () => {
    var author = document.getElementById('authorName');
    var book = document.getElementById('bookName');
    var noOfPages = document.getElementById('pages');

    book = new Book(book.value, author.value, noOfPages.value);
    createBookCard(book);

    return false;
});

Book is a object constructor and createBookCard is another function that uses the form’s input values to create the book card.

How to use javascript to remove focus/hover state on click in mobile

I have a tooltip that appears on hover. The problem is that in order to remove focus/hover state in mobile, you have to click outside of the .explanation div. I want to mak it so that you can also close it my

<div class="main">
  <div>
    <h5>h5 text</h5>
      <div class="explanation">
        <div>
          <p>An explanatory paragraph <a>x</a>
          </p>
        </div>
      </div>
  </div>
</div>

css looks like this:

.main {
  .explanation {
    &::before {
      content: "[hover to show]";
    }

    p {
      background: #edf6ff;
      display: none;
      margin: 0;
      padding: 12px;
      position: relative;
      width: 200px;
      
      a {
        
          content: '[close]';
          outline: 5px solid blue;
          position: absolute;
          top: -5px;
          right: -20px;
        }
    }

    &:hover p {
      display: block;
    }
  }
}

jsfiddle here

This works perfectly on desktop, but ON MOBILE I want to be able to remove the focus on the element by clicking on the [x] a tag. You can already close it by clicking anywhere else, but I want to be able to click the X (which is inside) to close as well.

I figure it will be something like:

const closeButton = document.querySelector(
    '.main .explanation p a'
);

const main = document.querySelector('.main');

closeButton.addEventListener('click', removeFocus, false);

function removeFocus(event) {
    main.blur();
    event.preventDefault();
}

But this doesn’t do anything, at least not in Chrome. How can I toggle off the hover state on mobile?

jQuery to HTML interface – How can you fix intermittent function?

I have code taken straight from W3schools – I was learning about basic JS/HTML forms. All I wanted to do was pull data from two text field inputs and multiply them together.

The code I found functions intermittently, and I can see no rhyme or reason to why. When it does not work, it does not return “NaN” – it seemingly just does nothing.

NOTE: I have wrapped the .js in a “$(document).ready(function()…”

Here’s the full code:

<html>
<head>
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
    <style>
        html {
            margin: 20px;
        }
    </style>
</head>
<body>

<form>
    1st Number : <input type="text" id="firstNumber" /><br>
    2nd Number: <input type="text" id="secondNumber" /><br>
    <input type="button" onClick="multiplyBy()" Value="Multiply" />
    <input type="button" onClick="divideBy()" Value="Divide" />
</form>
<p>The Result is: <br>
    <span id = "result"></span>
</p>

<script src="tb2.js" type="text/javascript" ></script> 
</body>
</html>

$(document).ready(function () {
    function multiplyBy()
    {
            num1 = document.getElementById("firstNumber").value;
            num2 = document.getElementById("secondNumber").value;
            document.getElementById("result").innerHTML = num1 * num2;
    }
 
    function divideBy() 
    { 
            num1 = document.getElementById("firstNumber").value;
            num2 = document.getElementById("secondNumber").value;
    document.getElementById("result").innerHTML = num1 / num2;
    }
});

Earlier it worked, then I changed some variable names and it broke. Troubleshooting this, I changed:

"<script src="https://www.     .com/tb2.js" type="text/javascript" ></script> 
</body>"

to:

<script src="tb2.js" type="text/javascript" ></script>

That fixed it again. Trying to understand the issue, I tried another browser (NetSurfer) – the code that is presently running in Chrome didn’t work there.

I’ve slightly abridged the story and steps taken (I’ve been fiddling with this and researching for 6 hours,) but I want to know what is causing this erratic function – any help will be much appreciated.

Chromium Extension to parse page source for keywords

I am trying to create a chromium extension that will find keywords located in the page source. They would appear as ‘”keywords”: [these, are, keyword, examples, etc]’. I want to parse through the csv portion and have the results show up line by line in a popup or sidebar.

I’ve been stumbling my way through JavaScript using stackoverflow and ChatGPT. I can paste this script into the console and it will give the results I am looking for, but when I try it in my script nothing happens.

// contentScript.js

// Specify the keyword with a colon
const keyword = '"keywords":';

// Get the text content of the entire webpage
const pageText = document.body.innerText;

// Check if the keyword is present in the page text
const keywordIndex = pageText.indexOf(keyword);

if (keywordIndex !== -1) {
  // Find the content within brackets following the keyword
  const startIndex = pageText.indexOf('[', keywordIndex);
  const endIndex = pageText.indexOf(']', keywordIndex);

  if (startIndex !== -1 && endIndex !== -1 && startIndex < endIndex) {
    const rawResults = pageText.substring(startIndex + 1, endIndex); //          Remove the leading '['
    const resultsArray = rawResults.split(',').map(value =>     value.trim().replace(/"/g, '')); // Split, trim, and remove quotations

    // Send the results to the background script
    chrome.runtime.sendMessage({ results: resultsArray });
  } else {
    console.log(`No results found following "${keyword}".`);
  }
} else {
  console.log(`"${keyword}" not found on the webpage.`);
}

Throwing a function is giving weird behavior in Javascript/Typescript

Below is a simplification of how my code is

class A {
 public static doCleanup() { ... }
}

class B {
 public run() {
  try {
    this.doSomeWork();
  } catch(err) {
    console.log(err);
  }
 }

 doSomeWork() {
  // Does something and when encounters a error
  throw this.myError(someArgs);
 }

 myError(someArgs) {
   A.doCleanup();
   console.log('HI');
   return new CustomError();
 }
}

let foo = new B();
foo.run();

When I run this code, in the doSomeWork when the throw statement is executed, myError function doesn’t run, but instead the control immediately goes inside the catch block and the err variable is undefined.
But if I remove the A.doCleanup() line myError runs fine without any issue.
What is happening?

Three Js plane color is darker when add lights

import * as THREE from 'three';
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js'; 
import * as dat from 'dat.gui';


const renderer = new THREE.WebGL1Renderer();

renderer.shadowMap.enabled = true

renderer.setSize(window.innerWidth,window.innerHeight)

document.body.appendChild(renderer.domElement)

const scene  = new THREE.Scene()

const camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth/window.innerHeight,
    0.1,
    1000

)

const orbit = new OrbitControls(camera,renderer.domElement)

const axeHelper = new THREE.AxesHelper(5);
scene.add(axeHelper)

// scene.background = new THREE.Color(0XFFFFFF)

camera.position.set(-10,30,30)
orbit.update();

// Box
const boxGeometry =new THREE.BoxGeometry();
const boxMeterial = new THREE.MeshBasicMaterial({color:0x00FF00});
const box = new THREE.Mesh(boxGeometry,boxMeterial);
scene.add(box)

// paper
const planeGeometry = new THREE.PlaneGeometry(30,30);
const planeMaterial = new THREE.MeshLambertMaterial({color: 0xFFFFFF,side: THREE.DoubleSide});
const plane = new THREE.Mesh(planeGeometry,planeMaterial);
scene.add(plane); 
plane.rotation.x = -0.5 * Math.PI
plane.receiveShadow = true 

// Grid helper
const gridHelper = new THREE.GridHelper(30);
scene.add(gridHelper);

// Sphere
const sphereGeometry = new THREE.SphereGeometry(4,50,50);
const sphereMeterial = new THREE.MeshStandardMaterial({color:0x0000FF });
const sphere = new THREE.Mesh(sphereGeometry,sphereMeterial);
sphere.castShadow = true
scene.add(sphere);

sphere.position.set(-10,10,0);

// // Ambient Light
const ambientLight = new THREE.AmbientLight(0x222222 );
scene.add(ambientLight);

// // Direction Lights
const directionalLight = new THREE.DirectionalLight( 0xFFFFFF, 0.8 );
directionalLight.position.set(-30,50,0)
directionalLight.castShadow = true;
directionalLight.shadow.camera.bottom =-12
scene.add( directionalLight ) ;


//  Direction Light Helper
const dLightHelper = new THREE.DirectionalLightHelper(directionalLight,5);
scene.add(dLightHelper)

//  Direction Light Shadow Helper
const dLightShadowHelper = new THREE.CameraHelper(directionalLight.shadow.camera);
scene.add(dLightShadowHelper)





// Controller
const gui = new dat.GUI();
const options = {
    sphereColor: '#ffea00',
    wireframe:false,
    speed:0.01,
}

gui.addColor(options,'sphereColor').onChange(function(e){
    sphere.material.color.set(e);
})

gui.add(options,'wireframe').onChange(function(e){
    sphere.material.wireframe = e;
})

gui.add(options,'speed',0,0.1)



// box.rotation.x = 5;
// box.rotation.y = 5;

let step = 0;
let speed  = 0.1;
// Box animation
function animate(time) {
    box.rotation.x = time/1000;
    box.rotation.y = time/1000;
    renderer.render(scene,camera);

    step += options.speed;
    sphere.position.y = 10 * Math.abs(Math.sin(step))
}

renderer.render(scene,camera);


renderer.setAnimationLoop(animate);


plane color is very darker

I am using a MacBook M1 and these days I am following three js tutorials, i have rewritten the code like that tutorial but my three JS render screens are much darker after adding lights, I can’t find the solution to this.

I want to add more color to the plane materila because before adding lights it’s look like white color now it look like gray color therefore shadows are not clear, I am following the tutorial to do this but in that tutorial the plane color is white

How do I get this if script to work in js and html? [duplicate]

I’m trying to make a simple HTML game, but I have to use a little bit of javascript in order to make it work. However, I keep on making some sort of mistake, causing the js to not work. Basically, when you hover over a link, it gives you an alert, so I’m trying to make it to where after you hover over it once, it won’t alert you again until the page reloads. However, it doesn’t seem to be working. If anyone has any fixes, please answer this with the fix.

let hover1 = 0;

function hoverAlert() {
    if (hover1 === 0) {
        alert('Test Alert');
    }
    let hover1 = 1;
}

I tried the above script, expecting it to only show the alert, but instead, it wouldn’t show me an alert at all.