How to validate json of specific class which contains attribute of unknown type

I have a class which has an attribute of type unknown.

class A {
  known_attribue: 'string';
  unknown_attribute_name:unknown;
}

I need to validate a json and return values which are of type A.

for instance consider the following json

const x = {
  a : 'value1',
  c:[
     {
       known_attribue:'known_value1'
       unknown_attribute_name: {
         attr1 = 'attribute1_value1';
         attr2 = 'attribute2_value1';
       }
    }
  ],
  d: {
       known_attribue:'known_value2'
       unknown_attribute_name: {
         attr3 = 'attribute3_value1';
       }
    }
}

The result should be

[
{
       known_attribue:'known_value2'
       unknown_attribute_name: {
         attr3 = 'attribute3_value1';
       }
}, 
{
       known_attribue:'known_value1'
       unknown_attribute_name: {
         attr1 = 'attribute1_value1';
         attr2 = 'attribute2_value1';
       }
}
]

Sample JSON data

Could someone please help me with this? Have tried lots of approaches but failed to get the results. Any help is highly appreciated.

Form not submitting when pressing enter key?

Form won’t submit when pressing enter? It should work because other forums suggest that it should work without any config? Don’t want to add any extra javascript.
I’m on bootstrap

 <h1>Signup</h1>
    <form method="post" action="/signup">
    <label for="username">username:</label>
    <input type="text" name="username" /><br />
    <label for="password">password:</label>
    <input type="password" name="password" /><br />
    <input type="submit"/>
</form>
     <br> <h1>Login</h1>
  <form method="post" action="/login">
    <label for="username">username:</label>
    <input type="text" name="username" /><br />
    <label for="password">password:</label>
    <input type="password" name="password" /><br />
    <input type="submit"/>
</form>

I tested for syntax errors and other stack overflow question’s but none solved my problem

Accessing Class Properties without this Keyword in JavaScript

I’m encountering a confusing situation while working with a JavaScript class. My class properties, which are assigned to specific DOM elements in the constructor, seem to be accessible in the class methods without using the this keyword. This confounds me, as I thought this was necessary for accessing class properties.

Here’s the class for context:

class Reminder {
constructor() {
    this.inputField = document.querySelector('#inputField');
    this.itemList = document.querySelector('#itemList');
    this.msg = document.querySelector('#msg');
    // Other properties...
}

loadReminders() {
    // Some code...
    itemList.appendChild(li);
    // Some more code...
}

addReminder() {
    if (inputField.value === '') {
        msg.classList.add('error');
        msg.textContent = "No input received";
        msg.style.display = 'block';
        setTimeout(() => msg.style.display = 'none', 1000);
        return false;
    }

    // Other code...
    itemList.appendChild(li);
    inputField.value = '';
    // Rest of the code...
}

// Other methods...

}

In loadReminders and addReminder methods, I’m able to directly reference inputField, msg, and itemList without any qualifying this keyword, and there is no error.

What’s more intriguing is that these properties are not declared globally anywhere else in the script. Is there an implicit binding or scope rule in JavaScript that I’m not aware of that’s causing this behavior?

Insights into why these class properties are accessible without the this keyword would be greatly appreciated!

Rotate a string in JavaScript

I’m new to coding.
I want to write a JS program to rotate a string (in the right direction) periodically by removing the last character every time and attaching it to the front. But when I run my code, a whole line or the whole page will be filled with the string. What’s wrong with my code?

I defined a function that: 1. stores the content of an HTML p element in a variable; 2. changes the value of the variable to a new string with the last character of the original string attached to its front; 3. changes the content of the p element into the new string, and 4. repeats this process using the setInterval method.

function animation() {

  var text = document.getElementsByTagName("p")[0].innerHTML;

  setInterval(function() {

    text = text.substring(text.length - 1, 0) + text.substring(0, text.length - 2);
    document.getElementsByTagName("p")[0].innerHTML = text;

  }, 100);

}
<body onload="animation()">
  <p>JavaScript</p>
</body>

Result:
Result

Form Switch Component and Default Values doesn’t showing

I’m working with React JS and GraphQL, and I’m creating this table component. Inside the table, there are many switch components, and their values are coming from the API.

enter image description here

And also, here’s the respons from API :

{
  "data": {
    "getMenuPermissionsList": [
      {
        "idMenu": "1",
        "menuName": "Dashboard",
        "permissions": [
          {
            "add": false,
            "view": true,
            "delete": false,
            "modify": false,
            "export": false
          }
        ]
      },
      {
        "idMenu": "4",
        "menuName": "Konfigurasi",
        "permissions": []
      },
      {
        "idMenu": "24",
        "menuName": "Layanan Operasional",
        "permissions": []
      },
      {
        "idMenu": "7",
        "menuName": "Layanan Pasien",
        "permissions": [
          {
            "add": false,
            "view": true,
            "delete": false,
            "modify": false,
            "export": false
          }
        ]
      }
    ]
  }
}

Problem

I am using react-hook-form library for receiving default values from permissions that will be render to switch component :

const history = useHistory();
  const { data: getMenuPerms, loading: getMenuPermsLoading, error: getMenuPermsError } = useQuery(GET_MENU_PERMISSIONS_LOGGED_IN);
  const initialValues = getMenuPerms?.getMenuPermissionsLoggedin;

  useEffect(() => {
    document.title = "Tambah Group Role";
  }, []);

  const { register, handleSubmit, control, watch } = useForm({
    defaultValues: {
      perms: initialValues?.flatMap((menu) =>
        menu?.subMenu.flatMap((perm) =>
          perm?.permissions.map((val) => ({
            view: val.view,
            add: val.add,
            modify: val.modify,
            delete: val.delete,
            export: val.export,
            permission: val.permission
          }))
        )
      )
    }
  });
  
  const { fields } = useFieldArray({
    name: "perms",
    control
  });
  
  useEffect(() => {
    console.log(`permswatch: ${watch("perms")}`);
  }, [watch]);

And then, the initialValues and fields becomes value for TableRole props.

<TableRole
      checked={initialValues}
      fields={fields}
      register={register}
 />

And the result comes like this :

enter image description here

Here is the complete code :

formKontrolHakAksesTambah.js

import React, { useState, useEffect, useReducer } from "react";
import { Row, Col, Card, Container } from "react-bootstrap";
import { FormCreateGroup } from "../../../component/GrupDanHakAkses/Form";
import { useMutation, useQuery } from "@apollo/client";
import { CREATE_USER_GROUP, ASSIGN_PERMS } from "../../../gql/mutation";
import { GET_ALL_USER_GROUP, GET_MENU_PERMISSIONS_LOGGED_IN } from "../../../gql/query";
import { FaSave } from "react-icons/fa";

import Swal from "sweetalert2";
import { useHistory } from "react-router-dom";
import { Loading } from "../../../component/Common";
import styles from "./formAkses.module.scss";
import { TableRole } from "../../../component/GrupDanHakAkses/Table";
import Divider from "../../../component/Common/Page/Divider";
import ButtonSecondary from "../../../component/Common/Button/ButtonSecondary";
import { useForm, useFieldArray } from "react-hook-form";
import ButtonPrimary from "../../../component/Common/Button/ButtonPrimary";

const FormKontrolDanHakAksesTambah = () => {
  const history = useHistory();
  const { data: getMenuPerms, loading: getMenuPermsLoading, error: getMenuPermsError } = useQuery(GET_MENU_PERMISSIONS_LOGGED_IN);
  const initialValues = getMenuPerms?.getMenuPermissionsLoggedin;

  useEffect(() => {
    document.title = "Tambah Group Role";
  }, []);

  const { register, handleSubmit, control, watch } = useForm({
    defaultValues: {
      perms: initialValues?.flatMap((menu) =>
        menu?.subMenu.flatMap((perm) =>
          perm?.permissions.map((val) => ({
            view: val.view,
            add: val.add,
            modify: val.modify,
            delete: val.delete,
            export: val.export,
            permission: val.permission
          }))
        )
      )
    }
  });
  
  const { fields } = useFieldArray({
    name: "perms",
    control
  });
  
  useEffect(() => {
    console.log(`permswatch: ${watch("perms")}`);
  }, [watch]);

  // state for input form group and switches
  const [value, setValue] = useState({
    groupId: "",
    groupName: "",
    groupDesc: "",
  });

  const onChange = (event) => {
    setValue({
      ...value,
      [event.target.name]: event.target.value,
    });
  };
  
  const [createUserGroup, { loading: loadingCreateUserGroup }] = useMutation(
    CREATE_USER_GROUP,
    {
      onCompleted: () => {
        history.push("/konfigurasi/grup-dan-hak-akses-pengguna");
      },
      onError: (err) => {
        console.error(err.message);
      },
    }
  );

  const [assignPermission, { loading: assignPermsLoading }] = useMutation(
    ASSIGN_PERMS,
    {
      onCompleted: (data) => {
        console.log(data);
      },
      onError: (err) => {
        console.error(JSON.stringify(err, null, 2));
      },
    }
  );

  if (loadingCreateUserGroup || assignPermsLoading)
    return (
      <>
        <Loading />
      </>
    );

  const handleSubmitGroupBaru = async (e) => {
    e.preventDefault();

    if (
      value.groupId === "" ||
      value.groupName === "" ||
      value.groupDesc === ""
    ) {
      // Menampilkan pesan error jika ada field yang kosong
      Swal.fire({
        icon: "error",
        title: "Silakan lengkapi semua field",
      });
      return;
    }

    try {
      // Membuat promise untuk mutasi createUserGroup
      const createGroupPromise = createUserGroup({
        variables: {
          input: {
            groupId: value.groupId,
            groupName: value.groupName,
            groupDesc: value.groupDesc,
          },
        },
        awaitRefetchQueries: true,
        refetchQueries: [{ query: GET_ALL_USER_GROUP }, "getAllUserGroup"],
      });

      // Menunggu hasil promise mutasi createUserGroup
      const {
        data: {
          createUserGroup: { groupId },
        },
      } = await createGroupPromise;

      // Membuat promise untuk mutasi assignPermission
      const assignPermissionPromise = assignPermission({
        variables: {
          input: {
            groupId: groupId,
            permissionCodes: []
          },
        },
      });

      // Menunggu hasil promise mutasi assignPermission
      await assignPermissionPromise;

      Swal.fire({
        icon: "success",
        title: "Akun Grup berhasil ditambahkan",
        showConfirmButton: false,
        timer: 1500,
      });
    } catch (err) {
      Swal.fire({
        icon: "error",
        title: err.message,
      });
    }
  };

  return (
    <>
      <section className={`${styles.FormAksi}`}>
        <Container className={`${styles.container}`}>
          <Row>
            <Col>
              <Card className={`${styles.customCard}`}>
                <Card.Title className={`${styles.customCardHeader}`}>
                  <p className="text-uppercase base-lg text-semi-bold">
                    Informasi Grup Akun
                  </p>
                </Card.Title>
                <Card.Body>
                  <FormCreateGroup onChange={onChange} value={value} />
                </Card.Body>
              </Card>
            </Col>
          </Row>
          <Row>
            <Col>
              <Card className="border-0 mt-5">
                <Card.Title>
                  <p className="text-uppercase base-lg text-semi-bold mt-2 mx-2">
                    Kontrol Akses
                  </p>
                </Card.Title>
                <Card.Body>
                  { getMenuPermsLoading && <Loading/> }
                  { getMenuPermsError && <p>{getMenuPermsError.message}</p> }
                  <TableRole
                    checked={initialValues}
                    fields={fields}
                    register={register}
                  />
                </Card.Body>
              </Card>
            </Col>
          </Row>
        </Container>

        <Divider className="my-3" />

        <div className="d-flex justify-content-end">
          <ButtonSecondary
            variant="solid"
            wider="true"
            onClick={handleSubmitGroupBaru}
            className="mt-5"
          >
            {" "}
            <FaSave className="mx-2" /> SIMPAN PERUBAHAN
          </ButtonSecondary>
        </div>
      </section>
    </>
  );
};

export default FormKontrolDanHakAksesTambah;

TableRole.js :

import React, { Fragment, useRef, useEffect } from "react";
import { Table, Form } from "react-bootstrap";
import { useFieldArray, useForm } from "react-hook-form";

export default function TableRole({ checked, register, fields }) {
  const tableHeader = [
    "No",
    "Menu",
    "Sub Menu",
    "Lihat",
    "Tambah",
    "Ubah",
    "Hapus",
    "Export"
  ];

  return (
    <Table className="table-responsive">
      <thead
        style={{ backgroundColor: "#ECEFF1" }}
        className="txt-blue-grey-700 base-md text-bold"
      >
        <tr>
          {tableHeader.map((header, index) => (
            <th
              key={index}
              className="txt-blue-grey-700 base-md text-bold text-center"
              style={{ padding: "0.75rem" }}
            >
              {header}
            </th>
          ))}
        </tr>
      </thead>
      <tbody className="text-center">
        {checked?.map((row) => (
            <React.Fragment key={row.id}>
              <RoleRow
                fields={fields}
                register={register}
                row={row}
              />
            </React.Fragment>
          ))}
      </tbody>
    </Table>
  );
}

const RoleRow = ({ row, register, fields, defaultValues }) => (
    <>
      <tr>
        <td rowSpan={row.subMenu.length + 1}>{row.idMenu}</td>
        <td rowSpan={row.subMenu.length + 1}>{row.menuName}</td>
      </tr>
      {
          row.subMenu.map((subMenuItem) => (
            <>
              <tr key={subMenuItem.idMenu}>
                <td>{subMenuItem.menuName}</td>
                {
                  fields?.map((value) => (
                      <PermissionCheckbox value={value} register={register} fields={fields} />
                    ))
                }
              </tr>
            </>
          ))
        }
    </>
);

const PermissionCheckbox = ({ fields, register, value }) => {
  return (
    <>
      {
        fields.map((item, index) => {
          return (
            <Fragment key={`perms.${index}.permission`}>
                <td>
                  <Form.Check
                    id={`lihat-${item.id}`}
                    type="switch"
                    value={value}
                    {...register(`perms.${index}.view`)}
                  />
                </td>
                <td>
                  <Form.Check
                    id={`tambah-${item.id}`}
                    type="switch"
                    {...register(`perms.${index}.add`)}
                  />
                </td>
                <td>
                  <Form.Check
                    id={`ubah-${item.id}`}
                    type="switch"
                    {...register(`perms.${index}.modify`)}
                  />
                </td>
                <td>
                  <Form.Check
                    id={`hapus-${item.id}`}
                    type="switch"
                    {...register(`perms.${index}.delete`)}
                  />
                </td>
                <td>
                  <Form.Check
                    id={`export-${item.id}`}
                    type="switch"
                    {...register(`perms.${index}.export`)}
                  />
                </td>
            </Fragment>
          )
        })
      }
    </>
  );
};

Question

How can I handle default values from the parent and pass the data to the child component (TableRole) using react-hook-form? Additionally, how can the TableRole component read the data that is coming from the API ?

Two identical blur() calls, one works, one doesn’t

I am calling two very similar blur() functions where one works and one doesn’t. The only difference between the two calls is literally the name of the id. One is named lighting-upgrade and one is hvac-upgrade. I cannot see a reason id=lighting-upgrade is working and id=hvac-upgrade is not.

The <select> in HTML:

<select id="lighting-upgrade" name="lighting">
  <optgroup>
    <option value="option1">Incandescent</option>
    <option value="option2">Fluorescent</option>
  <optgroup>
</select>
<input id="insulation-cost" type="number" name="insulation-cost">

<select id="hvac-upgrade" name="hvac">
  <optgroup>
    <option value="option1">RTU-80-Furnace</option>
    <option value="option2">RTU-92-Furnace</option>
  <optgroup>
</select>
<input id="lighting-cost" type="number" name="lighting-cost">

The constants I’m using:

 const lighting_upgrade = {
    option1: {type:"Incandescent", savings:0.1},
    option2: {type:"Fluorescent", savings:0.21}
};
const hvac_upgrade = {
  option1: {type:"RTU-80-Furnace", savings:0.1},
  option2: {type:"RTU-92-Furnace", savings:0.18}
};

The javascript call:

** this call works **

  $("#lighting-cost").blur(function() {
    var option_selected  = $("#lighting-upgrade option:selected").val();
    var percent_savings  = lighting_upgrade[option_selected].savings;

** this call does not works **

  $("#hvac-cost").blur(function() {
    var option_selected  = $("#hvac-upgrade option:selected").val();
    var percent_savings  = hvac_upgrade[option_selected].savings; 

Using console.log this is the error I’m getting:

tool.js:155 Uncaught TypeError: Cannot read properties of undefined (reading 'savings')
    at HTMLInputElement.<anonymous>

I’m not seeing the problem.

 const lighting_upgrade = {
    option1: {type:"Incandescent", savings:0.1},
    option2: {type:"Fluorescent", savings:0.21}
};

const hvac_upgrade = {
  option1: {type:"RTU-80-Furnace", savings:0.1},
  option2: {type:"RTU-92-Furnace", savings:0.18}
};

$(function() {
 $("#lighting-cost").blur(function() {
    var option_selected  = $("#lighting-upgrade option:selected").val();
    var percent_savings  = lighting_upgrade[option_selected].savings;
  });
  
  $("#hvac-cost").blur(function() {
    var option_selected  = $("#hvac-upgrade option:selected").val();
    var percent_savings  = hvac_upgrade[option_selected].savings;
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select id="lighting-upgrade" name="lighting">
  <optgroup>
    <option value="option1">Incandescent</option>
    <option value="option2">Fluorescent</option>
  <optgroup>
</select>
<input id="insulation-cost" type="number" name="insulation-cost">

<select id="hvac-upgrade" name="hvac">
  <optgroup>
    <option value="option1">RTU-80-Furnace</option>
    <option value="option2">RTU-92-Furnace</option>
  <optgroup>
</select>
<input id="lighting-cost" type="number" name="lighting-cost">

Hydration error in Next.js when I refresh after changing language(except english) using next-translate/useTranslation

I’m having trouble with the useTranslation hook from the next-translate package in my Next.js application. While all my languages are being recognized, I encounter a hydration error whenever I change the language and refresh the page.

Here’s the setup I have in my i18n.js file located at the root:

module.exports = {
  locales: ["ar", "en","es"],
  defaultLocale: "en",
  pages: {
    "*": ["common"],
  },
};

I’m using useTranslation in my components as follows:

import useTranslation from "next-translate/useTranslation";

const ComponentName = () => {
  const { t } = useTranslation("common");
  // rest of the component
}

I’ve placed all my translations inside the public folder. When I change the language, I store the new language in local storage.

The issue arises when I change the language and then refresh the page. I get a hydration error because the server side language is detected as English, while the client has the custom language I had selected and stored in local storage.

Is there a way to solve this problem such that the server side recognizes the selected language upon refreshing? I have tried all the ways. Any help or guidance is greatly appreciated.
https://drive.google.com/file/d/1WSBKdXKTpOlQv6g2v1c2KpnZaZjecHhf/view?usp=sharing – here is my folder strucutre

I implemented multi-language support using the next-translate/useTranslation hook in my Next.js application. I stored the selected language in local storage when changing languages. I expected the application to maintain the selected language even after a page refresh, seamlessly translating the page to the chosen language.On refreshing the page after changing the language, I encountered a hydration error. The server side detected English (the default language) while the client had the custom language I selected, causing a mismatch.

how to leave a photo slideshow and find the last picture shown?

i created a slideshow to randomly show photos on the web – and use for that a somewhat particular setup. pressing the ESCAPE key interrupts the show, and here comes the problem : i want the subsequently loaded new HTML page with its photo to correspond with the last photo shown in the slideshow, the one that was interrupted with ESCAPE – but instead equal the freshly loaded page and its photo with the very first photo in the slideshow started much beforehand.

all photos are stored on a linux apache web server. a single HTML file ./slsh.html serves as slideshow page while a random photo series is generated by periodically creating a symbolic link randomly to one of many photos kept in a subdirectory. the name of the symbolic link however never really changes and is static in that sense as ./slsh.jpg

a cronjob starts a bash script every 10 minutes that does the symbolic linking approximately every 1.5sec for some 10min. importantly photos are loaded into the browser window as background pictures every 9sec via a javascript refresh function. i had described this setup in more detail in the past here :

How to force-reload background image in <div> using CSS and Javascript

here my current HTML, CSS and JS excerpts :

<script>

  // KEYS
  window.addEventListener("keydown", keysPressed, false);
  window.addEventListener("keyup", keysReleased, false);
  var keys = [];
  function keysPressed( event) {
      keys[ event.keyCode] = true;
  
      if (event.keyCode == 27 || event.keyCode == 36) { //go to UID html : ESCAPE,HOME keys
          window.location.href = "./html/20070828-001264-012.html";
          event.preventDefault();
      }
      else if (event.keyCode == 81) { //go to main.html : q key
          window.location.href = "./main.html";
          event.preventDefault();
      }
      else if (event.keyCode == 13) { //refresh URL : ENTER
          location.reload();
          event.preventDefault();
      }
      else if (event.keyCode == 32 || event.keyCode == 39) { //load next=newest slsh.jpg : SPACEBAR,RIGHTARROW
          NextDivPic();
          event.preventDefault();
      }
  };
  
  function keysReleased(event) { // mark keys that were released
      keys[event.keyCode] = false;
  };


  // TIMER fx
  var timerId;
  var timerIdArray = [];
  timerId = setInterval('refresh()', 8888);
  timerIdArray.push( timerId);


  // REFRESH fx
  function refresh() {
      var timestamp = new Date().getTime();
      document.getElementById("a").style.backgroundImage = "url(./slsh.jpg?t=" + timestamp + ")";
  }

  // NEXT DIV PIC fx
  function NextDivPic() {
      // see -->  https://www.scaler.com/topics/javascript-clearinterval/
      for(var i=0;i<timerIdArray.length;i++){
          clearInterval(timerIdArray[i]);
      };
      timerId = setInterval('refresh()', 9000);
      timerIdArray.push( timerId);
      var timestamp = new Date().getTime();
      document.getElementById("a").style.backgroundImage = "url(./slsh.jpg?t=" + timestamp + ")";
      event.preventDefault();
  }

  // document.addEventListener('DOMContentLoaded', function NextDivPic() );

</script>
<style type="text/css">

  body, html {
      height: 100%;
      margin: 0;
  }

  .bg {

      /* The image used */
      background-image: url('./slsh.jpg');
      
      /* Full height */
      height: 100%; 
      
      /* Center and scale the image nicely */
      background-position: center;
      background-repeat: no-repeat;
      background-size: contain;
      background-color: rgb(10,10,10);

  }

</style>
<html>
<head>
  <title>20070828-001264-012</title>
</head>
<body id="body" onload="NextDivPic()">
  <div class="bg" id="a" onclick="NextDivPic()"></div>
</body>
</html>

i am aware that in the current situation no information can be reliably provided about the newest slideshow picture shown for 9sec in the browser window as it is periodically loaded via that non-specific symbolic link ./slsh.jpg. the window.location.href variable points incorrectly to : “./html/20070828-001264-012.html” which in fact was the UID of the very first photo shown many cycles earlier when the browser had started the slideshow and the HTML file ./slsh.html was loaded a first time and stored as such in the browser cache.

the aforementioned cronjob script updates both the particular HTML file every 1.5sec and inserts each time a new UID such as : “./html/19910000-000101-021.html” and also synchronously relinks the symbolic link ./slsh.jpg to the JPG file in question such as ./subdir/19910000-000101-021.jpg. it’s just that the photo displayed in the browser for 9sec is not in sync with the UIDs chosen by the cronjob script every 1.5sec. therefore do the UID of the photo depicted and the UID of the current slsh.html and slsh.jpg very likely not correspond with each other at the moment of pressing the ESCAPE key !

in my setup i conveniently just reload the BACKGROUND image always under the same symbolic link name though every time linked to a new photo. reloading the entire HTML page after pressing ESCAPE wouldn’t help here because things are not in sync as said above. still, how could i find out about the UID of the last depicted photo in the current scenario ? is there a way to look behind the symbolic link on the apache serve and find out about the real physical JPG file and its associated UID ? would including of the UID in the photo META data help here ? but then how do we read such data at background picture refresh time ? any suggestions ?

Problem with generating a file in SVG (snap.svg) and PDF (jspdf) in JS

I have two problems.

  1. The quality of the numerical value in the generated PDF file. The code responsible for this is
function generatePDF() {
  if (eanCode !== '') {
    const pdf = new jsPDF('p', 'mm', 'a4');

    // Ustalenie szerokości i wysokości obrazu na podstawie proporcji formatu A4
    const a4Width = 210;
    const a4Height = 297;

    // Pobranie danych obrazu z canvas
    const canvas = document.getElementById('eanCanvas');
    const imageData = canvas.toDataURL('image/jpeg', 1.0); // Ustawienie jakości na maksymalną (1.0)

    // Obliczenie proporcji skalowania na podstawie szerokości obrazu
    const scale = a4Width / canvas.width;

    // Dodanie obrazu do PDF z zastosowaną skalą
    pdf.addImage(imageData, 'JPEG', 0, 0, canvas.width * scale, canvas.height * scale);

    // Ustawienie maksymalnej jakości tekstu
    pdf.setProperties({
      compress: true, // Kompresja pliku PDF
      precision: 4, // Precyzja tekstu (4 miejsca po przecinku)
    });

    // Zapisanie pliku PDF
    pdf.save('ean_code.pdf');
  }
}
  1. Problem generating SVG file.
function generateSVG() {
  const eanType = eanTypeSelect.value;
  const eanCode = eanInput.value;
  const width = parseInt(widthInput.value);
  const height = parseInt(heightInput.value);
  const margin = parseInt(marginInput.value);
  const barColor = barColorInput.value;
  const bgColor = bgColorInput.value;
  const fontOptions = fontOptionsInput.value;
  const font = fontInput.value;
  const textAlign = textAlignInput.value;
  const textPosition = textPositionInput.value;
  const textMargin = parseInt(textMarginInput.value);
  const fontSize = parseInt(fontSizeInput.value);

  const svg = Snap(width + margin * 2, height + margin * 2);

  // Ustawianie tła
  const background = svg.rect(0, 0, width + margin * 2, height + margin * 2).attr({
    fill: bgColor,
  });

  // Generowanie kodu EAN
  JsBarcode(svg, eanCode, {
    format: eanType,
    displayValue: true,
    lineColor: barColor,
    width: width,
    height: height,
    margin: margin,
    background: bgColor,
    fontOptions: fontOptions,
    font: font,
    textAlign: textAlign,
    textPosition: textPosition,
    textMargin: textMargin,
    fontSize: fontSize,
  });

// Pobieranie kodu SVG
  const svgData = svg.toString();

  // Tworzenie obiektu Blob
  const blob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' });

  // Tworzenie adresu URL dla Blob
  const url = URL.createObjectURL(blob);

  // Tworzenie elementu link do pobrania
  const link = document.createElement('a');
  link.href = url;
  link.download = 'ean_code.svg';
  document.body.appendChild(link);

  // Kliknięcie na link, aby rozpocząć pobieranie
  link.click();

  // Usunięcie linku z dokumentu
  document.body.removeChild(link);

  // Zwalnianie zasobu Blob poprzez usuwanie adresu URL
  URL.revokeObjectURL(url);
}

I’ve tried various libraries, but I’m running out of ideas. For PDF generation I use jsPDF, for SVG generation I use Snap.svg

The code fragments come from the JS file which is the EAN code generator. I want to save codes in PDF and SVG files. I am using the latest versions of the jsPDF and Snap.svg libraries

How does Metamask store passwords securely without prompting each time? Alternative to keyringControl for a similar feature?

I’m curious about the password handling mechanism in Metamask, the cryptocurrency wallet and browser extension. I’ve noticed that after initially entering the password, Metamask doesn’t ask for it again each time I open the extension. I believe the accounts are managed through KeyringControl, but I’m wondering how the storage works to maintain this behavior. Can someone explain the underlying mechanism that allows Metamask/UniSat to remember the password and avoid prompting the user each time? Are there any security considerations or best practices related to this feature?

Furthermore, I’ve observed that the password is stored within the KeyringController class, but I’m curious about the process by which it gets restored after the extension is closed.

enter image description here

I would like to know if there are alternative approaches to implementing a similar feature in my own application without utilizing KeyringControl. Due to security concerns, I realized storing the password in the Redux state or localStorage is not an option. What other options or best practices should I consider to provide a seamless login experience for my users while maintaining a high level of security?

SyntaxError: JSON Parse error: Unexpected token: < When sending base64 data to NodeJS backend

If a base64 string is manually defined as a const, then the following code works fine. However, when I switch to using state, then I get the error SyntaxError: JSON Parse error: Unexpected token: <. Below is the full code for selecting and then uploading images. I don’t know why it doesn’t work when using state.

import React, { Component } from "react";

import {
  StyleSheet,
  Text,
  View,
  PixelRatio,
  TouchableOpacity,
  Image,
  TextInput,
} from "react-native";

import { Camera } from "expo-camera";
import * as ImagePicker from "expo-image-picker";
export default class Project extends Component {
  constructor() {
    super();

    this.state = {
      ImageSource: null,

      data: null,

      Image_TAG: "",

      ImageData: null,

      imageInfo: null,

      ServerImage: null,
    };
  }

  getPermissionAsync = async () => {
    // Camera roll Permission
    if (Platform.OS === "android") {
      const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL);
      if (status !== "granted") {
        alert("Sorry, we need camera roll permissions to make this work!");
      }
    }
    // Camera Permission
    const { status } = await Permissions.askAsync(
      Permissions.CAMERA,
      Permissions.AUDIO_RECORDING
    );
    this.setState({ hasPermission: status === "granted" });
  };

  handleCameraType = () => {
    const { cameraType } = this.state;

    this.setState({
      cameraType:
        cameraType === Camera.Constants.Type.back
          ? Camera.Constants.Type.front
          : Camera.Constants.Type.back,
    });
  };

  pickImage = async () => {
    let response = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.Images,
      allowsEditing: true,
      aspect: [1, 1],
      quality: 1,
      base64: true,
    });
    if (!response.canceled) {
      this.setState({
        ImageSource: response.uri,
        data: response.data,
        ImageData: response.assets[0].base64,
        imageInfo: response.assets[0],
      });
    }
  };

  getImage = async () => {
    const mybody = {};
    const response = await fetch(
      `https://coral-app-n96bn.ondigitalocean.app/groupchat/getimage`,
      {
        method: "POST",
        credentials: "include",
        headers: {
          "Content-Type": "application/json",
        },
        body: mybody,
      }
    );
    const jsonData = await response.json();
    this.setState({
      ServerImage: jsonData[0].image_base64,
    });
  };

  uploadImageToServer = async () => {
    let apiUrl = `https://coral-app-n96bn.ondigitalocean.app/groupchat/uploadimage`;
    const uri = this.state.ImageSource;
    const myBase64 = this.state.ImageData;

    let options = {
      method: "POST",
      credentials: "include",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ uri: uri, base64: myBase64 }),
    };

    return fetch(apiUrl, options)
      .then((response) => response.json())
      .then((response) => {
        console.log("status: " + response.status);
        console.log("body: " + JSON.stringify(response, null, 4));
      })
      .catch((err) => {
        console.log("ERROR: " + err);
      });
  };

  render() {
    return (
      <View style={styles.container}>
        <TouchableOpacity onPress={this.pickImage.bind(this)}>
          <View style={styles.ImageContainer}>
            {this.state.ImageSource === null ? (
              <Text>Select a Photo</Text>
            ) : (
              <Image
                style={styles.ImageContainer}
                source={{ uri: this.state.ImageSource }}
              />
            )}
          </View>
        </TouchableOpacity>

        <TextInput
          placeholder="Enter Image Name "
          onChangeText={(data) => this.setState({ Image_TAG: data })}
          underlineColorAndroid="transparent"
          style={styles.TextInputStyle}
        />

        <TouchableOpacity
          onPress={this.uploadImageToServer}
          activeOpacity={0.6}
          style={styles.button}
        >
          <Text style={styles.TextStyle}> UPLOAD IMAGE TO SERVER </Text>
        </TouchableOpacity>

        <TouchableOpacity
          onPress={this.getImage}
          activeOpacity={0.6}
          style={styles.button}
        >
          <Text style={styles.TextStyle}> Get Image from SERVER </Text>
        </TouchableOpacity>
        <View style={styles.ImageContainer}>
          {this.state.ServerImage === null ? (
            <Text>Server photo will appear here</Text>
          ) : (
            <Image
              style={styles.ImageContainer}
              source={{
                uri: `data:image/jpeg;base64,${this.state.ServerImage}`,
              }}
            />
          )}
        </View>

        <View style={styles.ImageContainer}>
          {this.state.ImageData === null ? (
            <Text>Selected photo will appear here</Text>
          ) : (
            <Image
              style={styles.ImageContainer}
              source={{ uri: this.state.ImageData }}
            />
          )}
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    backgroundColor: "#FFF8E1",
    paddingTop: 20,
  },

  ImageContainer: {
    borderRadius: 10,
    width: 250,
    height: 250,
    borderColor: "#9B9B9B",
    borderWidth: 1 / PixelRatio.get(),
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "#CDDC39",
  },

  TextInputStyle: {
    textAlign: "center",
    height: 40,
    width: "80%",
    borderRadius: 10,
    borderWidth: 1,
    borderColor: "#028b53",
    marginTop: 20,
  },

  button: {
    width: "80%",
    backgroundColor: "#00BCD4",
    borderRadius: 7,
    marginTop: 20,
  },

  TextStyle: {
    color: "#fff",
    textAlign: "center",
    padding: 10,
  },
});

This is the backend controller:

module.exports.uploadImage = async (req, res) => {
  const uploadImageQuery = await pool.query(
    "INSERT INTO practice_pics(image, image_base64) values($1, $2) RETURNING id",
    [req.body.uri, req.body.base64]
  );

  const newImage = uploadImageQuery.rows[0].id;

  res.json({
    ...req.body,
    body: req.body,
    status: newImage,
  });
};

I’m using Expo (react native) and an express server with Postgres database.

Should node JS projects that do not use TS still install the @type packages?

I’m wondering if this is why half my IDE doesn’t work… I’m working in an 8 year react app built with JS without the types, navigation is a nightmare. I tried to install @types/react but it wouldn’t let me, it conflicted with backbone, an old limb hanging off the app with gangrene.

Thus, do these type dev only installations provide any benefit to the developer if writing a JS app, or are they only beneficial to TS projects?

My suspicion is there is some benefit to imports and IDE functionality, but obviously not typing.

Using latest intelliJ Idea, trying to cleanup a monstrous project.

How can I display a page beside a sidebar when I click on the menu item?

I have a sidebar (taken from Bootstrap sidebars). When I click on an item in the menu, I’d like to see the related page on the right side of the sidebar, so I’d like to see it where all that white space is. I don’t know if you need React or if you can just do it with Javascript code

Currently, to test, I’ve created a page called try.html which opens when I click One > Try.

How can I display the try.html page on the right side of the sidebar?

index.html

<!doctype html>
<html lang="en" data-bs-theme="auto">
  <head><script src="../assets/js/color-modes.js"></script>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
    <meta name="generator" content="Hugo 0.112.5">
    <title>Sidebars · Bootstrap v5.3</title>

    <link rel="canonical" href="https://getbootstrap.com/docs/5.3/examples/sidebars/">

    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script>
    

    

<link href="../assets/dist/css/bootstrap.min.css" rel="stylesheet">


    
    <!-- Custom styles for this template -->
    <link href="sidebars.css" rel="stylesheet">
  </head>
  <body>


    
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="bootstrap" viewBox="0 0 118 94">
    <title>Bootstrap</title>
    <path fill-rule="evenodd" clip-rule="evenodd" d="M24.509 0c-6.733 0-11.715 5.893-11.492 12.284.214 6.14-.064 14.092-2.066 20.577C8.943 39.365 5.547 43.485 0 44.014v5.972c5.547.529 8.943 4.649 10.951 11.153 2.002 6.485 2.28 14.437 2.066 20.577C12.794 88.106 17.776 94 24.51 94H93.5c6.733 0 11.714-5.893 11.491-12.284-.214-6.14.064-14.092 2.066-20.577 2.009-6.504 5.396-10.624 10.943-11.153v-5.972c-5.547-.529-8.934-4.649-10.943-11.153-2.002-6.484-2.28-14.437-2.066-20.577C105.214 5.894 100.233 0 93.5 0H24.508zM80 57.863C80 66.663 73.436 72 62.543 72H44a2 2 0 01-2-2V24a2 2 0 012-2h18.437c9.083 0 15.044 4.92 15.044 12.474 0 5.302-4.01 10.049-9.119 10.88v.277C75.317 46.394 80 51.21 80 57.863zM60.521 28.34H49.948v14.934h8.905c6.884 0 10.68-2.772 10.68-7.727 0-4.643-3.264-7.207-9.012-7.207zM49.948 49.2v16.458H60.91c7.167 0 10.964-2.876 10.964-8.281 0-5.406-3.903-8.178-11.425-8.178H49.948z"></path>
  </symbol>
  <symbol id="home" viewBox="0 0 16 16">
    <path d="M8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4.5a.5.5 0 0 0 .5-.5v-4h2v4a.5.5 0 0 0 .5.5H14a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146zM2.5 14V7.707l5.5-5.5 5.5 5.5V14H10v-4a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5v4H2.5z"/>
  </symbol>
  <symbol id="speedometer2" viewBox="0 0 16 16">
    <path d="M8 4a.5.5 0 0 1 .5.5V6a.5.5 0 0 1-1 0V4.5A.5.5 0 0 1 8 4zM3.732 5.732a.5.5 0 0 1 .707 0l.915.914a.5.5 0 1 1-.708.708l-.914-.915a.5.5 0 0 1 0-.707zM2 10a.5.5 0 0 1 .5-.5h1.586a.5.5 0 0 1 0 1H2.5A.5.5 0 0 1 2 10zm9.5 0a.5.5 0 0 1 .5-.5h1.5a.5.5 0 0 1 0 1H12a.5.5 0 0 1-.5-.5zm.754-4.246a.389.389 0 0 0-.527-.02L7.547 9.31a.91.91 0 1 0 1.302 1.258l3.434-4.297a.389.389 0 0 0-.029-.518z"/>
    <path fill-rule="evenodd" d="M0 10a8 8 0 1 1 15.547 2.661c-.442 1.253-1.845 1.602-2.932 1.25C11.309 13.488 9.475 13 8 13c-1.474 0-3.31.488-4.615.911-1.087.352-2.49.003-2.932-1.25A7.988 7.988 0 0 1 0 10zm8-7a7 7 0 0 0-6.603 9.329c.203.575.923.876 1.68.63C4.397 12.533 6.358 12 8 12s3.604.532 4.923.96c.757.245 1.477-.056 1.68-.631A7 7 0 0 0 8 3z"/>
  </symbol>
  <symbol id="table" viewBox="0 0 16 16">
    <path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2zm15 2h-4v3h4V4zm0 4h-4v3h4V8zm0 4h-4v3h3a1 1 0 0 0 1-1v-2zm-5 3v-3H6v3h4zm-5 0v-3H1v2a1 1 0 0 0 1 1h3zm-4-4h4V8H1v3zm0-4h4V4H1v3zm5-3v3h4V4H6zm4 4H6v3h4V8z"/>
  </symbol>
  <symbol id="people-circle" viewBox="0 0 16 16">
    <path d="M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/>
    <path fill-rule="evenodd" d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1z"/>
  </symbol>
  <symbol id="grid" viewBox="0 0 16 16">
    <path d="M1 2.5A1.5 1.5 0 0 1 2.5 1h3A1.5 1.5 0 0 1 7 2.5v3A1.5 1.5 0 0 1 5.5 7h-3A1.5 1.5 0 0 1 1 5.5v-3zM2.5 2a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3zm6.5.5A1.5 1.5 0 0 1 10.5 1h3A1.5 1.5 0 0 1 15 2.5v3A1.5 1.5 0 0 1 13.5 7h-3A1.5 1.5 0 0 1 9 5.5v-3zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3zM1 10.5A1.5 1.5 0 0 1 2.5 9h3A1.5 1.5 0 0 1 7 10.5v3A1.5 1.5 0 0 1 5.5 15h-3A1.5 1.5 0 0 1 1 13.5v-3zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3zm6.5.5A1.5 1.5 0 0 1 10.5 9h3a1.5 1.5 0 0 1 1.5 1.5v3a1.5 1.5 0 0 1-1.5 1.5h-3A1.5 1.5 0 0 1 9 13.5v-3zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3z"/>
  </symbol>
</svg>

<main class="d-flex flex-nowrap">



  <div class="b-example-divider b-example-vr"></div>

  <div class="flex-shrink-0 p-3" style="width: 280px;">
    <a href="/" class="d-flex align-items-center pb-3 mb-3 link-body-emphasis text-decoration-none border-bottom">
      <svg class="bi pe-none me-2" width="30" height="24"><use xlink:href="#bootstrap"/></svg>
      <span class="fs-5 fw-semibold">Dashboard</span>
    </a>
    <ul class="list-unstyled ps-0">
      <li class="mb-1">
        <button class="btn btn-toggle d-inline-flex align-items-center rounded border-0 collapsed" data-bs-toggle="collapse" data-bs-target="#home-collapse" aria-expanded="true">
          One
        </button>
        <div class="collapse show" id="home-collapse">
          <ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small">
            <li><a href="try.html" class="link-body-emphasis d-inline-flex text-decoration-none rounded">Try</a></li>
            <li><a href="#" class="link-body-emphasis d-inline-flex text-decoration-none rounded">aaaaaaa</a></li>
            <li><a href="#" class="link-body-emphasis d-inline-flex text-decoration-none rounded">bbbbbbbbb</a></li>
          </ul>
        </div>
      </li>
      <li class="mb-1">
        <button class="btn btn-toggle d-inline-flex align-items-center rounded border-0 collapsed" data-bs-toggle="collapse" data-bs-target="#dashboard-collapse" aria-expanded="false">
          Two
        </button>
        <div class="collapse" id="dashboard-collapse">
          <ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small">
            <li><a href="#" class="link-body-emphasis d-inline-flex text-decoration-none rounded">Overview</a></li>
            <li><a href="#" class="link-body-emphasis d-inline-flex text-decoration-none rounded">Weekly</a></li>
            <li><a href="#" class="link-body-emphasis d-inline-flex text-decoration-none rounded">Monthly</a></li>
            <li><a href="#" class="link-body-emphasis d-inline-flex text-decoration-none rounded">Annually</a></li>
          </ul>
        </div>
      </li>
      <li class="mb-1">
        <button class="btn btn-toggle d-inline-flex align-items-center rounded border-0 collapsed" data-bs-toggle="collapse" data-bs-target="#orders-collapse" aria-expanded="false">
          Orders
        </button>
        <div class="collapse" id="orders-collapse">
          <ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small">
            <li><a href="#" class="link-body-emphasis d-inline-flex text-decoration-none rounded">New</a></li>
            <li><a href="#" class="link-body-emphasis d-inline-flex text-decoration-none rounded">Processed</a></li>
            <li><a href="#" class="link-body-emphasis d-inline-flex text-decoration-none rounded">Shipped</a></li>
            <li><a href="#" class="link-body-emphasis d-inline-flex text-decoration-none rounded">Returned</a></li>
          </ul>
        </div>
      </li>
      <li class="border-top my-3"></li>
      <li class="mb-1">
        <button class="btn btn-toggle d-inline-flex align-items-center rounded border-0 collapsed" data-bs-toggle="collapse" data-bs-target="#account-collapse" aria-expanded="false">
          Account
        </button>
        <div class="collapse" id="account-collapse">
          <ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small">
            <li><a href="#" class="link-dark d-inline-flex text-decoration-none rounded">New...</a></li>
            <li><a href="#" class="link-dark d-inline-flex text-decoration-none rounded">Profile</a></li>
            <li><a href="#" class="link-dark d-inline-flex text-decoration-none rounded">Settings</a></li>
            <li><a href="#" class="link-dark d-inline-flex text-decoration-none rounded">Sign out</a></li>
          </ul>
        </div>
      </li>
    </ul>
  </div>


  <div class="b-example-divider b-example-vr"></div>
</main>
<script src="../assets/dist/js/bootstrap.bundle.min.js"></script>

    <script src="sidebars.js"></script></body>


  </body>
</html>

sidebars.js

/* global bootstrap: false */
(() => {
  'use strict'
  const tooltipTriggerList = Array.from(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
  tooltipTriggerList.forEach(tooltipTriggerEl => {
    new bootstrap.Tooltip(tooltipTriggerEl)
  })
})()

try.html

<!doctype html>
<html lang="en" data-bs-theme="auto">
  <head>
  </head>
  <body>

    <p>Provaaaaaaaaaaaaaaaaa</p>
    
  </body>
</html>

sidebars.css

.bd-placeholder-img {
  font-size: 1.125rem;
  text-anchor: middle;
  -webkit-user-select: none;
  -moz-user-select: none;
  user-select: none;
}

@media (min-width: 768px) {
  .bd-placeholder-img-lg {
    font-size: 3.5rem;
  }
}

.b-example-divider {
  width: 100%;
  height: 3rem;
  background-color: rgba(0, 0, 0, .1);
  border: solid rgba(0, 0, 0, .15);
  border-width: 1px 0;
  box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15);
}

.b-example-vr {
  flex-shrink: 0;
  width: 1.5rem;
  height: 100vh;
}

.bi {
  vertical-align: -.125em;
  fill: currentColor;
}

.nav-scroller {
  position: relative;
  z-index: 2;
  height: 2.75rem;
  overflow-y: hidden;
}

.nav-scroller .nav {
  display: flex;
  flex-wrap: nowrap;
  padding-bottom: 1rem;
  margin-top: -1px;
  overflow-x: auto;
  text-align: center;
  white-space: nowrap;
  -webkit-overflow-scrolling: touch;
}

.btn-bd-primary {
  --bd-violet-bg: #712cf9;
  --bd-violet-rgb: 112.520718, 44.062154, 249.437846;

  --bs-btn-font-weight: 600;
  --bs-btn-color: var(--bs-white);
  --bs-btn-bg: var(--bd-violet-bg);
  --bs-btn-border-color: var(--bd-violet-bg);
  --bs-btn-hover-color: var(--bs-white);
  --bs-btn-hover-bg: #6528e0;
  --bs-btn-hover-border-color: #6528e0;
  --bs-btn-focus-shadow-rgb: var(--bd-violet-rgb);
  --bs-btn-active-color: var(--bs-btn-hover-color);
  --bs-btn-active-bg: #5a23c8;
  --bs-btn-active-border-color: #5a23c8;
}
.bd-mode-toggle {
  z-index: 1500;
}

.dropdown-toggle { outline: 0; }

.btn-toggle {
  padding: .25rem .5rem;
  font-weight: 600;
  color: var(--bs-emphasis-color);
  background-color: transparent;
}
.btn-toggle:hover,
.btn-toggle:focus {
  color: rgba(var(--bs-emphasis-color-rgb), .85);
  background-color: var(--bs-tertiary-bg);
}

.btn-toggle::before {
  width: 1.25em;
  line-height: 0;
  content: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='rgba%280,0,0,.5%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/%3e%3c/svg%3e");
  transition: transform .35s ease;
  transform-origin: .5em 50%;
}

[data-bs-theme="dark"] .btn-toggle::before {
  content: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='rgba%28255,255,255,.5%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/%3e%3c/svg%3e");
}

.btn-toggle[aria-expanded="true"] {
  color: rgba(var(--bs-emphasis-color-rgb), .85);
}
.btn-toggle[aria-expanded="true"]::before {
  transform: rotate(90deg);
}

.btn-toggle-nav a {
  padding: .1875rem .5rem;
  margin-top: .125rem;
  margin-left: 1.25rem;
}
.btn-toggle-nav a:hover,
.btn-toggle-nav a:focus {
  background-color: var(--bs-tertiary-bg);
}

.scrollarea {
  overflow-y: auto;
}