Send MediaRecorder audio chunks with Websockets

I’m trying to send audio chunks recorded with MediaRecorder to the server and then to another client using Websockets and play it there.

The first chunk gets played normally but then I get Error decoding audio data: EncodingError: Failed to execute 'decodeAudioData' on 'BaseAudioContext': Unable to decode audio data

This is my code:

Recording:

      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      const mediaRecorder = new MediaRecorder(stream, {
        mimeType: "audio/webm",
      });
      mediaRecorder.ondataavailable = async (event) => {
        if (event.data.size > 0) {
          const b64 = await blobToBase64(event.data);
          sendMessage({
            payload: {
              base64: b64,
            },
          });
        }
      };

      mediaRecorder.start(250);

Playing:

   const arrayBuffer = base64ToArrayBuffer(message.payload.base64);
   const audioContext = new AudioContext();
   const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
   const source = audioContext.createBufferSource();
   source.buffer = audioBuffer;
   source.connect(audioContext.destination);
   source.start();

Helper functions:

const base64ToArrayBuffer = (base64: string): ArrayBuffer => {
  const binaryString = window.atob(base64);
  const len = binaryString.length;
  const bytes = new Uint8Array(len);
  for (let i = 0; i < len; i++) {
    bytes[i] = binaryString.charCodeAt(i);
  }
  return bytes.buffer;
};

  const blobToBase64 = (blob: Blob): Promise<string> => {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.readAsDataURL(blob);
      reader.onloadend = () => resolve(reader.result as string);
      reader.onerror = reject;
    });
  };


The assigned innerHTML results in a different structure

I tried assigning <p><div></div>Hello</p> to innerHTML, but it resulted in a different structure: <p></p><div></div>Hello<p></p>. Is this a bug or expected behavior? Can’t a <div> element be placed inside <p> element?

Code:

const div = document.createElement("div")
div.innerHTML = "<p><div></div>Hello</p>";
console.log(div.innerHTML);

Expected Output:

<p><div></div>Hello</p>

Result I get:

<p></p><div></div>Hello<p></p>

video using MediaSource API showing unending loading screen

I am trying to build a small streaming project using the MediaSource API.
I have a segmented video called earth into 6 segments of around 6 seconds each.
With the current project structure

vids/  
 earth/  
    playlist.json  
    segments/
      segment-000.mp4
      segment-001.mp4
      segment-002.mp4
      segment-003.mp4
      segment-004.mp4
      segment-005.mp4
      segment-006.mp4
index.js
index.html

the playlist.json file is as such

{
  "segments": [
    {
      "url": "http://localhost:3000/vids/earth/segments/segment-000.mp4"
    },
    {
      "url": "http://localhost:3000/vids/earth/segments/segment-001.mp4"
    },
    {
      "url": "http://localhost:3000/vids/earth/segments/segment-002.mp4"
    },
    {
      "url": "http://localhost:3000/vids/earth/segments/segment-003.mp4"
    },
    {
      "url": "http://localhost:3000/vids/earth/segments/segment-004.mp4"
    },
    {
      "url": "http://localhost:3000/vids/earth/segments/segment-005.mp4"
    },
    {
      "url": "http://localhost:3000/vids/earth/segments/segment-006.mp4"
    }
  ]
}

The index.js file is the server code

const express = require('express');
const path = require('path');

const app = express();
const PORT = 3000;

app.get('/index', (req, res)=> res.sendFile(path.join(__dirname, 'index.html')));
app.get('/earth', (req, res)=> res.sendFile(path.join(__dirname, 'earth.mp4')))
app.use('/vids', express.static(path.join(__dirname, 'vids')));
app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

Finally the index.html file

<!DOCTYPE html>
<html>
<head>
  <title>Streaming App</title>
  <style>
    video {
      width: 100%;
      max-width: 800px;
    }
  </style>
</head>
<body>
  <h1>Streaming App</h1>
  <div id="video-container">
    <video id="video-player" controls></video>
  </div>
  <script>
    const videoPlayer = document.getElementById('video-player');

    let playlist;
    let currentSegmentIndex = 0;
    let mediaSource = null;
    let sourceBuffer = null;

    // Fetch playlist
    fetch('/vids/earth/playlist.json')
        .then(response => response.json())
        .then(data => {
            playlist = data;
            initMediaSource();
        })
        .catch(error => console.error('Error fetching playlist:', error));

    // Initialize the MediaSource API
    function initMediaSource() {
        mediaSource = new MediaSource();
        videoPlayer.src = URL.createObjectURL(mediaSource);
        mediaSource.addEventListener('sourceopen', () => {
            sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E"');
            loadNextVideoSegment();
        });
    }

    // Load the next video segment
    function loadNextVideoSegment() {
        if (currentSegmentIndex < playlist.segments.length) {
            const segmentUrl = playlist.segments[currentSegmentIndex].url;
            fetch(segmentUrl)
                .then(response => response.arrayBuffer())
                .then(data => {
                    sourceBuffer.appendBuffer(data);
                    currentSegmentIndex++;
                })
                .catch(error => console.error('Error loading video segment:', error));
        } else {
            mediaSource.endOfStream();
        }
    }

    // Move to the next segment when the current one ends
    videoPlayer.addEventListener('ended', () => {
        loadNextVideoSegment();
    });
  </script>
</body>
</html>

With this code when clicking the play button, in FF it displays an unending loading screen

How to create responsive header like the Valorant site?

I just started to code for 2 months and I’m trying to copy the responsiveness of the official valorant website header. I only managed to copy where the header list like [Game Info, Media, News, Leaderboards, Support, Our socials, Esports] will be responsive. When it is fullscreen, everything is visible but if user reduce the browser the header lists will slowly reduce.

My Problem:
There is search icon in the header, it will expand if user clicks it. My problem is that reduce the browser but dont click the search icon yet. When the browser is reduced, click the search icon. After clicking, it will push away towards right the globe and play now button. While in the official valorant site it will reduce the header list.

Official Valorant Site – When size is reduced
enter image description here

My Clone Site – When size is reduced
enter image description here

https://codepen.io/gmadrian2000/pen/gOVqPaW

    <header>
        <nav>
            <div class="riot-logo">
                <img src="img/logo-white.png" alt="Riot Games Logo" class="logo-default">
                <img src="img/logo-red.png" alt="Riot Games Logo" class="logo-hover">
                <i class="material-icons">arrow_drop_down</i>
            </div>
            <div class="valorant-logo">
                <a href="index.html"><img src="img/valorant-logo.png" alt="Valorant Logo"></a>
            </div>
            <ul class="nav-list">
                <li class="drop-down">
                    <a href="">Game Info<i class="material-icons">arrow_drop_down</i></a>
                    <div class="dropdown-content">
                        <div class="dropdown-top-border"></div>
                        <ul>
                            <li><a href="#">Agents</a></li>
                            <li><a href="#">Maps</a></li>
                            <li><a href="#">Arsenal</a></li>
                            <li><a href="#">Premier</a></li>
                        </ul>
                    </div>
                </li>
                <li><a href="#">Media</a></li>
                <li><a href="#">News</a></li>
                <li><a href="#">Leaderboards</a></li>
                <li class="drop-down">
                    <a href="#">Support<i class="material-icons">arrow_drop_down</i></a>
                    <div class="dropdown-content">
                        <div class="dropdown-top-border"></div>
                        <ul>
                            <li><a href="#">Specs</a></li>
                            <li><a href="#">Support<i class="material-icons">arrow_outward</i></a></li>
                            <li><a href="#">Community Code</a></li>
                        </ul>
                    </div>
                </li>
                <li class="drop-down">
                    <a href="#">Our Socials<i class="material-icons">arrow_drop_down</i></a>
                    <div class="dropdown-content">
                        <div class="dropdown-top-border"></div>
                        <ul>
                            <li><a href="#">X<i class="material-icons">arrow_outward</i></a></li>
                            <li><a href="#">Youtube<i class="material-icons">arrow_outward</i></a></li>
                            <li><a href="#">Instagram<i class="material-icons">arrow_outward</i></a></li>
                            <li><a href="#">Facebook<i class="material-icons">arrow_outward</i></a></li>
                            <li><a href="#">Discord<i class="material-icons">arrow_outward</i></a></li>
                        </ul>
                    </div>
                </li>
                <li><a href="#">Esports<i class="material-icons">arrow_outward</i></a></li>
                <li class="drop-down more-dropdown">
                    <a href="#">MORE<i class="material-icons">arrow_drop_down</i></a>
                    <div class="dropdown-content">
                        <div class="dropdown-top-border"></div>
                        <ul class="more-list">
                            <!-- Moved items will appear here -->
                        </ul>
                    </div>
                </li>
            </ul>
            <div class="search-container">
                <i class="material-icons search-icon">search</i>
                <input type="text" class="search-input">
                <button class="close-btn">
                    <i class="material-icons close">close</i>
                </button>
            </div>       
            <i class="material-icons language">language</i>
            <a class="play-now-btn">Play Now</a>
        </nav>
    </header>

CSS:

header {
  width: 100%;
  background-color: rgb(24, 20, 20);
  text-transform: uppercase;
  position: fixed;
  z-index: 2;
}

/* Header Icon Styles */
header i.material-icons {
  color: gray;
  font-size: 1.125rem;
  vertical-align: middle;
}

nav {
  display: flex;
  align-items: center;
  margin: 0 2.5%;
}

/* Riot Logo and valorant Logo Image */
.riot-logo img,
.valorant-logo img {
  width: 100%;
  height: auto;
}

/* Riot Logo Container */
.riot-logo {
  width: 5em;
  height: auto;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  margin-right: 2.5em;
}

/* Hover Effects for Riot Logo */
.riot-logo img.logo-hover {
  display: none;
}

.riot-logo:hover img.logo-hover {
  display: block;
}

.riot-logo:hover img.logo-default {
  display: none;
}

.riot-logo:hover i.material-icons {
  color: rgb(247, 67, 67);
}

/* Valorant Logo Container */
.valorant-logo {
  width: 1.7em;
  height: 1.5em;
  flex-shrink: 0;
  margin-right: 2em;
}

/* Nav List */
.nav-list {
  list-style-type: none;
  display: flex;
  font-size: 0.8rem;
  font-weight: 600;
  flex-shrink: 0;
  margin: 0;
  padding: 0;
  align-items: center;
  margin-right: auto;
}

.nav-list li a {
  text-decoration: none;
  padding: 0.8em 1em;
  color: white;
  letter-spacing: 1px;
}

.nav-list li {
  padding: 2.5em 0;
  margin-right: 1em;
}

/* Hover Effects for Nav List */
.nav-list > li > a:hover {
  background-color: rgb(66, 60, 60);
  color: rgb(247, 67, 67);
  border-radius: 10px;
}

.nav-list > li:hover {
  position: relative;
}

.nav-list > li:hover::after {
  content: "";
  position: absolute;
  bottom: 5px;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  height: 4px;
  background-color: rgb(247, 67, 67);
  border-radius: 10px;
}

.nav-list li a:hover i.material-icons {
  color: white;
}

/* Searchbar Styles */
.search-container {
  display: flex;
  align-items: center;
  background-color: #312f2f;
  border-radius: 15px;
  transition: all 0.7s ease;
  overflow: hidden;
  width: 50px;
  justify-content: flex-start;
  margin-right: 0.5em;
  flex-shrink: 0;
  padding: 12px 0;
  justify-self: end;
}

.search-container .search-icon {
  color: white;
  font-size: 1.5rem;
  cursor: pointer;
  padding: 0 13px;
}

.search-input {
  border: none; 
  outline: none;
  color: white;
  background-color: #312f2f;
  font-size: 1rem;
}

.close-btn {
  background: none;
  border: none;
  cursor: pointer;
  padding: 0 13px 0 5px; 
}

.close-btn .close {
  color: gray;
  font-size: 1.4rem;
}

.search-container.active {
  width: 240px;
}

.search-container.active .search-input {
  width: 100%;
  opacity: 1;
}

/* Language Icon */
.material-icons.language {
  color: white;
  margin-right: 12px;
}

/* Play Now Button */
.play-now-btn {
  text-decoration: none;
  padding: 0.5em 1.2em;
  background-color: rgb(247, 67, 67);
  border-radius: 12px;
  flex-shrink: 0;
  font-size: 14px;
}

/* Dropdown Styles */
.dropdown-content i.material-icons {
  font-size: 0.6rem;
  vertical-align: top;
}

.dropdown-content {
  display: none;
  position: absolute;
  background-color: rgb(54, 53, 53);
  min-width: 200px;
  z-index: 100;
  border-radius: 5px;
  margin-top: 23px;
}

.dropdown-top-border {
  height: 4px;
  background-color: rgb(247, 67, 67);
  width: 100%;
  border-radius: 2px 2px 0 0;
}

.dropdown-content ul {
  padding: 1.2em;
}

.dropdown-content li {
  list-style-type: none;
  margin-right: 0;
  padding: 0;
}

.nav-list li .dropdown-content a {
  color: rgb(194, 189, 189);
  padding: 1em 1em;
  text-decoration: none;
  display: block;
  font-size: 0.8rem;
  font-weight: 100;
  border-radius: 5px;
}

.nav-list li .dropdown-content a:hover {
  background-color: rgb(76, 73, 73);
  color: white;
}

.nav-list li:hover .dropdown-content {
  display: block;
}

/* Styling for "MORE" dropdown */
.more-dropdown {
  display: none;
}

.more-dropdown .dropdown-content {
  position: absolute;
  background-color: rgb(54, 53, 53);
  min-width: 150px;
  z-index: 100;
  border-radius: 5px;
  margin-top: 23px;
}

.more-dropdown .dropdown-content ul {
  padding: 1em;
}

.more-dropdown .dropdown-content ul li {
  list-style-type: none;
  padding: 0.5em 0;
  display: block;
}

.more-dropdown .dropdown-content ul li a {
  color: rgb(194, 189, 189);
  text-decoration: none;
  display: block;
  font-size: 0.8rem;
  border-radius: 5px;
}

.more-dropdown .dropdown-content ul li a:hover {
  background-color: rgb(76, 73, 73);
  color: white;
}

JS:

const nav = document.querySelector('nav');
const navList = document.querySelector('.nav-list');
const moreDropdown = document.querySelector('.more-dropdown');
const moreList = document.querySelector('.more-list');
const searchContainer = document.querySelector('.search-container');
const searchIcon = document.querySelector('.search-icon');
const closeButton = document.querySelector('.close-btn');
const searchInput = document.querySelector('.search-input');

// Function to adjust nav items
function adjustNavItems() {
    // Move items back from "MORE" dropdown to navList
    moreDropdown.style.display = 'none';
    while (moreList.firstChild) {
        navList.insertBefore(moreList.firstChild, moreDropdown);
    }

    // Shift items to "MORE" if nav overflows
    while (nav.scrollWidth > nav.clientWidth ) {
        moreDropdown.style.display = 'inline-block';
        moreList.insertBefore(navList.children[navList.children.length - 2], moreList.firstChild);
    }
}

// Event listeners
window.addEventListener('resize', adjustNavItems);
window.addEventListener('load', adjustNavItems);

searchIcon.addEventListener('click', () => {
  searchContainer.classList.add('active');
  searchInput.focus();
  
  
});

closeButton.addEventListener('click', () => {
    searchContainer.classList.remove('active');
    searchInput.value = ""; // Clear the input field
    
});

Note: Use HTML,CSS,JS only

How to avoid FOUC when conditionally rendering content based on localStorage state using Svelte?

I display some content to the user and the user chooses to hide it. I record their decision in localStorage so that when they come back to the website their choice is persisted. I’m not interested in a solution that relies on encoding this information into the URL.

When the page loads again, I read from localStorage. I must do this in onMount because the Svelte Component is rendered server-side and then hydrated. As a result, the component defaults to the server’s state and then changes to reflect knowledge gained by accessing localStorage only after the component has mounted.

Here is an example:

<script lang="ts">
    import { onMount } from "svelte";
    
    let isHidden = $state(false);

    onMount(async () => {
        isHidden = localStorage.getItem('isHidden') === "false";
    });

    function toggle() {
        isHidden = !isHidden;
        localStorage.setItem('isHidden', `${isHidden}`);
    }
</script>

<button onclick={toggle}>
    Toggle
</button>

{#if !isHidden}
    <div>Content</div>
{/if}

This example results in Content flickering from visible to hidden if localStorage is set to true.

The way I worked around this issue is by following Svelte’s guidance for avoiding FOUC (Flash Of Un-styled Content) with dark mode: https://flowbite.com/docs/customize/dark-mode/#dark-mode-switcher

I put a script in <head> which reads the localStorage value and conditionally sets a class on the document. I gave content a named class and used global CSS to control its visibility based on the document class.

<head>
    <meta charset="utf-8" />
    <link rel="icon" href="%sveltekit.assets%/favicon.png" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    %sveltekit.head%

    <script>
        if (localStorage.getItem('isHidden') === 'false') {
            document.documentElement.classList.add('isHidden');
        } else {
            document.documentElement.classList.remove('isHidden')
        }
    </script>
</head>

.isHidden .content {
    display: none;
}

<script lang="ts">
    function toggle() {
        const isHidden = document.documentElement.classList.toggle('isHidden');
        localStorage.setItem('isHidden', `${isHidden}`);
    }
</script>

<button onclick={toggle}>
    Toggle
</button>

<div class="content">Content</div>

This solution works, but breaks encapsulation quite heavily.

I was wondering if there were solutions which respected encapsulation?

Changed the country for price calculation [closed]

I developed a JS script to calculate the price based on its weight, however I cannot change the country in the calculation, it remains on the default one.
I use a json file to retrieve the prices, weights, countries.

<select name="country" id="country" class="form-control">
    <option value="BE">Belgique</option>
    <option value="FR">France</option>
</select>

My js script

window.addEventListener('load', () => {

  let country = document.getElementById('country').value;

  document.getElementById('country').addEventListener('change', function() {
    let country = this.value;

  });

  function getShippingPrice(weight) {
    // Sort the shippingPrices array by weight in descending order
    shippingPrices.sort((a, b) => b.weight - a.weight);
    //console.log(shippingPrices);
    let closestLowerWeight = null;

    for (let i = 0; i < shippingPrices.length; i++) {
      if (shippingPrices[i].country === country) {
        if (shippingPrices[i].weight <= weight) {
          closestLowerWeight = shippingPrices[i];
          break; // Stop searching when we find a weight less than or equal to the target weight
        }
      }
    }

    if (closestLowerWeight) {
      return closestLowerWeight.price; //+ ' €';
    }

    // If no match is found, you can handle this case, e.g., return a default price
    return "Price not found for this weight";
  }
});

Data

var shippingPrices = [{"country":"BE","price":10,"weight":0.11},{"country":"BE","price":20,"weight":10},{"country":"BE","price":30,"weight":30},{"country":"BE","price":50,"weight":50},{"country":"BE","price":85,"weight":100},{"country":"FR","price":5,"weight":0.11}];

If I change country no calculation it does not change country
Best Regards

Webpack 5 splitChunks.chunks = “all” causes modules not to load

I am trying to set up webpack to build my source code into its own output bundle, and output all node_modules to their own separate vendor file(s). I am using webpack-bundle-analyzer to see what’s happening. Without an optimization property, I get this kind of output:

// webpack.config.js

module.exports = {
    entry: path.resolve(__dirname, "wwwroot", "js", "index.js"),
    output: {
        path: path.resolve(__dirname, "wwwroot", "dist"),
        filename: "[name].bundle.js",
        chunkFilename: "[name].bundle.js",
    },
    cache: {
        type: "filesystem",
        allowCollectingMemory: true,
    },
    module: {
        rules: [...],
    },
};

Gives this output:

enter image description here

You can see the main.bundle.js includes all my src files (in wwwroot/js), but it also includes a bunch of code from node_modules, and it blows up the size to 6MB. This is not what I want – main.bundle.js should include only my source code. In this case, main.bundle.js looks like this at a glance:

enter image description here

However, it does work, i.e. the webpage loads with <script src="~/dist/main.bundle.js"></script>, all the associated modules are pulled in, and everything functions.

Using optimization and chunks: all

Using some optimization, I can get the bundle to ouput the main.bundle.js with only my source code packed into it, and all the node_modules separate:

// webpack.config.js

module.exports = {
    // ... identical to above, plus:
    optimization: {
        splitChunks: {
            chunks: "all",
            maxInitialRequests: Infinity,
            minSize: 0,
            cacheGroups: {
                vendor: {
                    test: /[\/]node_modules[\/]/,
                    reuseExistingChunk: true,
                    name(module) {
                        return module
                            .identifier()
                            .split("node_modules")
                            .reduceRight((item) => item)
                            .replace(".js", "");
                    },
                },
            },
        },
    },
};

The use of chunks: all, maxInitialRequests: Infinity, minSize: 0 is what does just the trick to get me my desired output: my source code only within main.bundle.js, and the node_modules packaged up separately. (That idea came from this question):

enter image description here

My main.bundle.js here is about 500kb, and a quick glimpse of it looks like this:

enter image description here

The problem is, this doesn’t work. The webpack loads, and pulls in main.bundle.js, but it doesn’t seem to ever run. I.e. throwing a console.log('find me') into my entry of index.js makes it into the main.bundle.js, but that code is never executed, even though the script is pulled into the page.

The critical piece seems to be chunks: all – when I use this, the bundle is split nicely as shown in the second image above, but the code never runs. When I don’t use this, the code is not split nicely between source code and node_modules, but the code does run (regardless of minSize or maxInitialRequests.

For good measure I tried chunks: initial, and while the organization of node modules is a bit different, the result is the same – nice small main.bundle.js, that doesn’t actually run:

enter image description here

What am I doing wrong that chunks: "all" / "initial" causes the main bundle to be pulled into the page, but never run?

vue3 – responsive background image from variable

I’m using Laravel and Vue, in the blade template I’m calling a Vue component which I’m passing some props too, to try and be able to update the background image depending on window width:

Blade Template:

<component 
    bg="{{ asset('/images/desktopBG.webp') }}"
    bgm="{{ asset('/images/mobileBG.webp') }}"
></component>

Component:

import { defineProps, computed } from 'vue';
const props = defineProps([ 'bg', 'bgm' ]);

const responsiveBG = computed(onresize = () => {
    if (window.innerWidth < 768) {
        console.log('background', props.bgm)
        return {'--bg-color': props.bgm}
    } else {
        console.log('background', props.bg)
        return {'--bg-color': props.bg}
    }
})

<template>
    <section id="container" :style="{backgroundImage: responsiveBG}"><section> 
</template>

The props are pulling through fine which I can see when console logging and it updates on window resizing, but I can’t get it to be added a background image never mind change depending on the window width.

Any help would be appreciated? thanks

How to have a pop-up for a download on my navbar?

I am looking to have a pop-up when someone clicks on my download button on my navbar, but I have been having problems when trying to make it work.
Here’s a example website. (rubberduckvba. com) I cant link it, it gets marked as spam.

I know I am asking for someone to just write the code, but even just tips would be great =)

I have tried to make a div for each and make it hidden or visible depending if the user clicked it, but I could not get js to recognise the div I wanted.

fetch('navbar.html').then(res => res.text()).then(text => {
  let oldelem = document.querySelector("script#navbar");
  let newelem = document.createElement("div");
  newelem.innerHTML = text;
  oldelem.parentNode.replaceChild(newelem, oldelem); // Now that the navbar is loaded, set the active link
  const currentPage = window.location.pathname.split("/").pop();
  const navLinks = document.querySelectorAll("nav a.nav-link");
  navLinks.forEach(link => {
    if (link.getAttribute("data-page") === currentPage) {
      link.classList.add("active");
    }
  });
});

marked.use({
  breaks: true
})
async function fetchReadme() {
  try {
    const response = await fetch('https://raw.githubusercontent.com/RanchoDVT/Comp-V5/dev/README.md');
    if (!response.ok) throw new Error('README not found');
    const text = await response.text();
    document.getElementById('readme-content').innerHTML = marked.parse(text);
  } catch (error) {
    console.error('Error fetching README:', error);
  }
}

async function fetchChangelog() {
  try {
    const response = await fetch('https://raw.githubusercontent.com/RanchoDVT/Comp-V5/dev/changelog.md');
    if (!response.ok) throw new Error('Changelog not found');
    const text = await response.text();
    document.getElementById('changelog-content').innerHTML = marked.parse(text);
  } catch (error) {
    console.error('Error fetching changelog:', error);
  }
}

document.addEventListener('DOMContentLoaded', () => {
  if (document.getElementById('readme-content')) {
    fetchReadme();
  }
  if (document.getElementById('changelog-content')) {
    fetchChangelog();
  }
});


// I hate js, why do I need a DOM loader check?
document.addEventListener('DOMContentLoaded', function() {

  var configForm = document.getElementById('config-form');
  var copyButton = document.getElementById('copy-button');
  var configOutput = document.getElementById('config-output');


  if (configForm) {
    configForm.addEventListener('submit', async function(event) {
      event.preventDefault();
      // Function to get the latest release version from GitHub
      async function getLatestReleaseVersion() {
        const response = await fetch('https://api.github.com/repos/RanchoDVT/Comp-V5/releases/latest', {
          method: 'GET',
          headers: {
            'User-Agent': 'JavaScript'
          }
        });

        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }

        const data = await response.json();
        const latestTag = data.tag_name;
        return latestTag;
      }
      const formData = new FormData(event.target);
      config = `MOTOR_CONFIG
{
  FRONT_LEFT_MOTOR
  {
      PORT=${formData.get('front_left_port')}
      GEAR_RATIO=${formData.get('front_left_gear_ratio')}
      REVERSED=${formData.has('front_left_reversed')}
  }
  FRONT_RIGHT_MOTOR
  {
      PORT=${formData.get('front_right_port')}
      GEAR_RATIO=${formData.get('front_right_gear_ratio')}
      REVERSED=${formData.has('front_right_reversed')}
  }
  REAR_LEFT_MOTOR
  {
      PORT=${formData.get('rear_left_port')}
      GEAR_RATIO=${formData.get('rear_left_gear_ratio')}
      REVERSED=${formData.has('rear_left_reversed')}
  }
  REAR_RIGHT_MOTOR
  {
      PORT=${formData.get('rear_right_port')}
      GEAR_RATIO=${formData.get('rear_right_gear_ratio')}
      REVERSED=${formData.has('rear_right_reversed')}
  }
  INERTIAL
  {
      PORT=${formData.get('inertial_port')}
  }
  Rear_Bumper
  {
      PORT=${formData.get('rear_bumper_port')}
  }
  PRINTLOGO=${formData.has('print_logo')}
  LOGTOFILE=${formData.has('log_to_file')}
  MAXOPTIONSSIZE=${formData.get('max_options_size')}
  POLLINGRATE=${formData.get('polling_rate')}
  CTRLR1POLLINGRATE=${formData.get('ctrlr1_polling_rate')}
  VERSION=${await getLatestReleaseVersion()}
}`
      completeCheck = true;

      configOutput.textContent = config;

      // Show the copy button once the config is generated
      copyButton.style.display = 'inline-block';
    });
  }

  if (copyButton) {
    copyButton.addEventListener('click', function() {
      if (configOutput.textContent) {
        navigator.clipboard.writeText(configOutput.textContent)
          .then(() => {
            console.debug('Config copied to clipboard!');
            const button =
              document.querySelector('copyButton');
            copyButton.innerHTML = 'Copied! ✅';
          })
          .catch(err => {
            console.error('Error copying text (Thats one rare error!): ', err);
          });
      }
    });
  }
});
html {
  background-color: black;
  color: white;
  font-family: 'Segoe UI', Tahoma;
  scroll-behavior: smooth;
  padding-bottom: 2%;
  box-sizing: border-box;
}

nav {
  list-style: none;
  border-radius: 4px;
  overflow: hidden;
  background-color: #38444d;
}

nav li {
  float: left;
}

footer {
  position: fixed;
  left: 0;
  bottom: 0;
  width: 100%;
  background-color: #38444d;
  backdrop-filter: 8;
  color: white;
  text-align: center;
}

nav li a,
.nav-link.dropbtn {
  /* Add .nav-link.dropbtn */
  display: inline-block;
  cursor: pointer;
  color: white;
  text-align: center;
  padding: 14px 16px;
  text-decoration: none;
  border-right: 1px solid #bbb;
}

.active {
  background-color: rgb(170, 96, 36);
}

li a:hover:not(.active) {
  background-color: lightslategray;
}

nav li.dropdown {
  display: inline-block;
}

nav li:last-child a {
  border-left: 1px solid #bbb;
  border-right: none;
}

.dropdown-content {
  display: none;
  position: absolute;
  min-width: 160px;
  padding: 8px 0px;
  background-color: lightslategrey;
  border-radius: 8px;
}

.dropdown-content a {
  background-color: lightslategrey;
  padding: 12px 16px;
  text-decoration: none;
  display: block;
  text-align: left;
  border: none;
  /* Remove borders */
}

.dropdown:hover .dropdown-content {
  display: block;
  position: absolute;
  padding: 8px 0px;
  background-color: lightslategrey;
  border-radius: 8px;
}

input {
  background: black;
  color: white;
  border: white;
  border-style: solid;
  border-width: thin
}

select {
  background: black;
  color: white;
}

.config-output {
  border-bottom: 1px solid white;
  padding-top: 10px;
  padding-bottom: 10px;
  margin-bottom: 20px;
  white-space: pre-wrap;
  /* Ensures text wraps properly (Who thought this was a good idea???)*/
  overflow-x: auto;
  /* Handles horizontal overflow (Same with this!!!)*/
}

button {
  background: black;
  color: white;
  border: white;
  border-style: solid;
  border-width: thin;
}

.form-group {
  margin-bottom: 15px;
}

a {
  color: #7bbaeb;
}
<link rel="stylesheet" href="style.css">
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="main.js"></script>
<script id="navbar" src="main.js"></script>
<!-- navbar fetched from site -->
<nav>
  <li><a class="nav-link" data-page="index.html" href="index.html">Home</a></li>
  <li class="dropdown">
    <a class="nav-link" data-page="projects.html" href="projects.html">Projects</a>
    <div class="dropdown-content">
      <a target="_blank" href="https://github.com/Voidless7125/Comp-V5">Comp V3</a>
      <a target="_blank" href="https://github.com/RanchoDVT/Vex-SDK">Custom SDK</a>
      <a target="_blank" href="https://ranchodvt.github.io/Comp-V5/">This website!</a>
    </div>
  </li>
  <li class="dropdown">
    <a class="nav-link">Downloads (WIP popup)</a>
    <div class="dropdown-content">
      <a>Comp_V3 Stable</a>
      <a>Comp_V3 Pre-Release</a>
      <a>Custom SDK Stable</a>
    </div>
  </li>
  <li><a class="nav-link" data-page="features.html" href="features.html">Features</a></li>
  <li><a class="nav-link" data-page="contact.html" href="contact.html">Contact</a></li>
  <li style="float: right;"><a class="nav-link" data-page="about.html" href="about.html">About</a></li>
</nav>
<!-- end navbar -->
<div id="readme-content"></div>
<footer>Copyright © 2024 Voidless7125</footer>

Laggy/Glitchy CSS Animations only on Firefox with Intersection Observer

I’m utilizing Intersection Observer API to hide the website header logo when it’s not over (or close to being over) a background image.

Works well on Google Chrome, other chromium browsers and Safari (at the least mobile version) but the CSS animations play extremely laggy and sometimes delayed on Firefox. In fact sometimes it doesn’t even trigger, it just freezes.

The CSS animations display fine when it’s not triggered by Intersection Observer adding a class. (i.e.: the blue box in the example below has the fade-in class by default and the animation plays smoothly when you refresh the page and it fades in.)

I’m using Firefox 132.0.1 (64-bit).
I’ve asked others to test the website and the results were the same across.

Here is a sample page I made replicating the issue with a blue square as the header logo and red rectangle as the background image region:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Scroll Test for StackOverflow</title>
    <style>
        .header-background{
            height: 500px;
            background-color:red;
        }
        .logo-container{
            position: fixed;
            top:2%;
            left: 50%;
            transform: translate(-50%, 0);
            width: 80px;
            height: 80px;
            background-color: blue;
        }
        .logo.logo-container{
            position: absolute;
        }
        .container{
            height: 2000px;
        }

        @keyframes fade-in{
            from{opacity:0;}
            to{opacity: 1;}
        }
        @keyframes fade-out{
            from{opacity: 1;}
            to{opacity: 0;} 
        }
        .fade-in{
            opacity: 0;
            animation-name: fade-in;
            animation-duration: 0.4s;
            animation-timing-function: ease-out;
            animation-fill-mode: forwards;
        }
        .fade-out{
            opacity: 1;
            animation-name: fade-out;
            animation-duration: 0.2s;
            animation-timing-function: ease-out;
            animation-fill-mode: forwards;
        }
    </style>
</head>
<body>


    <div class="container">
        <div class="headerhide" id="headerhide">
            <div class="logo-container">
                <div class="logo"></div>
            </div>
        </div>

        <div class="header-background" id="region"></div>
    </div>

    <script>
        const header = document.getElementById("headerhide");
        const region = document.querySelector(".header-background");

        const observer = new IntersectionObserver(([entry]) =>{
            header.classList.toggle("fade-out", !entry.isIntersecting);
            header.classList.toggle("fade-in", entry.isIntersecting);
            
        },
            {
                threshold: 0.2,
            }
        )
        observer.observe(region)
    </script>
    
</body>
</html>

(edit: also on JSFiddle: https://jsfiddle.net/ob2t6wn3/3/)

(the CSS and js is normally in different files but for the example’s sake I put them all in the html)

Things I’ve tried:

Checking if it’s a Firefox settings issue, I ruled out the privacy.fingerprintingProtection flag in about:config and Firefox Sync because disabling either or both did not solve the issue. I couldn’t think of any other setting that could be causing this.

Adding will-change: opacity; to the CSS class, didn’t work.

Adding a slight transform animation to trigger hardware acceleration but didn’t work, adding a translateZ(0) also didn’t work.

Adding debounce to the JavaScript function didn’t work (although I’m not entirely sure if I did it correctly, I’ve started learning JavaScript 3 days ago.)

Using 2 observers to toggle the different classes, didn’t work.

edit: I tried using CSS transitions instead of keyframes but that didn’t fix it either.

Thanks in advance.

Invariant Violation: requireNativeComponent: “RNSScreenContentWrapper” was not found in the UIManager

I was searching for 3 days for the sulotion but i din’t find it!
NOTE!!:
i use expo-cli and physical device (Expo Go), and javascirpt
I tried all these solutions:

npx expo install react-native-screens react-native-safe-area-context
npx expo install react-native-screens
npx expo install react-native-screens@lastet

the problem

i feel so tired and i hope to help me

Function isn’t getting triggered onClick isn’t working on dropdown

OnClick isn’t working in div dropdown functionality

<div  onClick={()=>console.log('hello')}  key={item} className="text-white  hover:bg-slate-700 hover:cursor-pointer">
import React, { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { toggleMenu } from "../utils/AppSlice";
import search_icon from "../assets/download.png";
import { autosuggest } from "../utils/constants";
import { cacheResults, removecacheResults } from "../utils/searchSlice";

const Header = () => {
  const dispatch = useDispatch();
  const [searchText, setsearchText] = useState("");
  const [searchapiText, setsearchapiText] = useState([]);
  const [showserchResults, setshowserchResults] = useState(false);
  const [LRU, setLRU] = useState([]);
  const [pops, setpop] = useState(null);

  const cache = useSelector((store) => store.search.searchState);
  // console.log(cache)
  const handleclick = () => {
    dispatch(toggleMenu());
  };

  const handleitemClick =() =>{
    console.log('tiem')
    // setsearchText(item)
  }
  const autosuggestionsapi = async () => {
    const autosuggestions = autosuggest + searchText;
    // console.log('API Call - '+searchText)
    const api = await fetch(autosuggestions);
    const json_data = await api.json();
    setsearchapiText(json_data[1]);

    if (LRU.length >= 6) {
      setLRU((prevItems) => {
        const poppedElement = prevItems[0];
        setpop(poppedElement);
        const updatedElement = prevItems.slice(1);
        return updatedElement;
      });
    }
    setLRU((items) => {
      const newitems = items;
      newitems.push(searchText);
      return newitems;
    });
    dispatch(
      cacheResults({
        [searchText]: json_data[1],
      }),
    );
  };
  const handleKeyPress = (event) => {
    if (event.key === 'Enter') {
      window.location.href = `/search?q=${searchText}`;  
    }
  };

  useEffect(() => {
    const timer = setTimeout(() => {
      if (cache[searchText]) {
        setsearchapiText(cache[searchText]);
      } else {
        autosuggestionsapi();
      }
    }, 200);
    if (pops !== null) {
      const updatedCache = { ...cache };
      delete updatedCache[pops];
      dispatch(removecacheResults(updatedCache));
      setpop(null);
    }
    return () => {
      clearTimeout(timer);
    };
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [searchText, pops]);
  return (
    <div className="fixed w-screen z-10">
      <div className="grid grid-cols-12 bg-black shadow-lg py-2 px-4 ">
        <div className="md:col-span-2 col-span-3 flex">
          <img
            onClick={() => handleclick()}
            className="md:h-7 h-6  md:mt-4 mt-5 cursor-pointer rounded-full"
            alt="hamburger"
            src="some_image"
          />
          <a href="/">
            <img
              className="h-16"
              alt="logo"
              src="some_image"
            />
          </a>
        </div>
        <div className="md:col-span-9 col-span-7 md:-ml-0 -ml-28">
          <div className="flex ">
            <input
              value={searchText}
              onChange={(e) => setsearchText(e.target.value)}
              onFocus={() => {
                setshowserchResults(true);
              }}
              onKeyPress={handleKeyPress}  
              onBlur={() => setshowserchResults(false)}
              className="h-10 mt-3 w-1/2 ml-28 rounded-l-full border border-gray-500 text-gray-500 px-5 py-2 bg-black"
              placeholder="Search"
              type="text"
            />

            <a href={"/search?q="+searchText}>
              <button className="mt-3">
                <img
                  alt="search"
                  className="md:h-[2.6rem] h-[2.5rem] border  border-gray-500 rounded-r-full bg-gray-900"
                  src={search_icon}
                />
              </button>
            </a>
          </div>
          {**showserchResults && searchapiText.length > 0 && (
            <div className="flex flex-col gap-1 rounded-lg fixed bg-custom-grey w-[16rem] md:w-[18rem] lg:w-[25rem] xl:w-[33rem] z-10 ml-28 md:ml-32 px-7 py-2 mt-2">
              {searchapiText.map((item) => (
                <div  onClick={()=>console.log('hello')}  key={item} className="text-white  hover:bg-slate-700 hover:cursor-pointer">
                  {' '+item}
                </div>
              ))}**
            </div>
          )}
        </div>

        <div className="flex md:col-span-1 col-span-2 md:mt-0 mt-1 ">
          <img
            className="h-8 mt-3 rounded-full"
            alt="user-icon"
            src="some_image"
          />
        </div>
      </div>
    </div>
  );
};

export default Header;

How to properly append a script dynamically using vanilla javascript? [duplicate]

I’m trying to make an SPA with dynamic content in vanilla js and made these functions below. ${script.src} shows the correct js file but the code inside it doesn’t take effect. I had another console.log inside the js file which didn’t show in the console. I am now confused why this code adds the correct script line in the html but the code inside the js file/script doesn’t take effect. I tried the js file in a separate static html and it works. So the code isn’t the issue but how the script is appended. Can anybody tell me what I’m missing?

const renderContent = (route) => {
    fetch("site/pages" + route + ".html")
        .then(response => response.text())
        .then(html => {
            app.innerHTML = html;
            loadScript(route, app);
        })
        .catch(error => console.error("Error loading HTML:", error));
};
const loadScript = (page, app) => {
    const script = document.createElement('script');
    script.src = 'site/js' + page + '.js';
    script.type = 'text/javascript';
    script.defer = true;
    script.onload = () => {
        console.log(`Script loaded and executed: ${script.src}`);
    };
    script.onerror = () => {
        console.error(`Failed to load script: ${script.src}`);
    };

    app.appendChild(script);
};

SCF/ACF date field won’t work in excluding posts from loop

I’m currently building a website where I need to show coming events. I’m building the website on the Salient WordPress theme, and trying to customize it a bit with some code in a child theme.

I’m changing the build in blog post loop of the theme, to show events instead. Within the code I made some few changes to sort them in the correct order (nog publish date, but event date) but I can’t seem to figure out how to exclude events that have their date passed.

if( $orderby !== ‘view_count’ ) {

$today = date(‘l j F’);
$nectar_blog_arr = array(
‘post_type’ => ‘evenement’,
‘posts_per_page’ => $posts_per_page,
‘post_status’ => ‘publish’,
‘meta-key’ => ‘event_startdate’,
‘meta_query’ => array(
‘relation’ => ‘AND’,
‘date_clause’ => array(
‘key’ => ‘event_startdate’,
‘value’ => $today,
‘type’ => ‘DATE’,
‘compare’ => ‘>=’
),

),
‘orderby’ => array(
‘date_clause’ => ‘ASC’,
),
‘offset’ => $post_offset,
‘category_name’ => $category,
‘paged’ => $paged
);

Any tips or tricks?

Note: I tried many pieces of code that I found on this form, or other website, but some codes just breaks the loop, and won’t show the loop at all. Without any PHP errors as well. Weird right?

Thanks in advance for all the help and suggestions!

Schedule checkbox to check/uncheck background automatically

Below script was working fine yesterday, and today I have got an error:

Exception: This script has too many triggers. Triggers must be deleted from the script before more can be added.

function chEcked() {
  SpreadsheetApp.getActive().getSheetByName('To-do').getRange("F1").setValue(true);
  SpreadsheetApp.getActive().getSheetByName('OverDate').getRange("F1").setValue(true);
}

function unchEcked() {
  SpreadsheetApp.getActive().getSheetByName('To-do').getRange("F1").setValue(false);
  SpreadsheetApp.getActive().getSheetByName('OverDate').getRange("F1").setValue(true);
}

ScriptApp.newTrigger("unchEcked").timeBased().atHour(23).nearMinute(50).everyDays(1).create();

ScriptApp.newTrigger("chEcked").timeBased().atHour(18).nearMinute(50).everyDays(1).create();

What I want to do is have this script run every day at a specific time.
I know if I delete the old trigger, the script will execute successfully, but I can’t do it manually every day.
Would you modify the script to meet my need?