I have a hard time just creating a basic Electron app with a Neutrino JS-based build process without getting errors. Any advice and help is much appreciated.
Category: javascript
Category Added in a WPeMatico Campaign
How can I write a JSDocs for TypeScript Generics?
I am trying to a JSDocs for the isEqual(object1: T, object2: T)
but I am getting a warning: The type ‘T’ is undefined .eslintjsdoc/no-undefined-types.
How can I fix this eslint warning here?
/**
* isEqual - Check if two objects are equal
* @param {T} object1 - Object 1
* @param {T} object2 - Object 2
* @returns {boolean} - True if objects are equal
*/
export function isEqual<T>(object1: T, object2: T): boolean {
if (!isObject(object1) || !isObject(object2)) {
return object1 === object2;
}
const keys1 = Object.keys(object1) as Array<keyof typeof object1>;
const keys2 = Object.keys(object2) as Array<keyof typeof object2>;
if (keys1.length !== keys2.length) {
return false;
}
for (const key of keys1) {
const val1 = object1[key];
const val2 = object2[key];
const areObjects = isObject(val1) && isObject(val2);
if ((areObjects && !isEqual(val1, val2)) || (!areObjects && val1 !== val2)) {
return false;
}
}
return true;
}
/**
* isObject - Check if value is an object
* @param {unknown} value - Value to check
* @returns {boolean} - True if value is an object
*/
function isObject(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null;
}
Tailwind Merge with Colors on Text and Text Shadows
tl;dr I have a text-shadow
utility class in my tailwind.config.ts
that allows me to change both the dimensions and colors of the shadow. I’m using Tailwind Merge, I can’t figure out how to stop text-shadow-{size/color}
from conflicting with text-{color}
.
The Problem
Often in CSS, using text shadows is very helpful for adding cool designs around text or even adding contrast for the text, rather than using a drop shadow. I’ve been created a text-shadow
utility class to my Tailwind Config a while ago, and it works great, until I use it on a component that utilizes Tailwind Merge. Tailwind Merge is a great package, but—when using custom utility classes—it can get confused.
The Solution
Naturally, my goal was to use extendTailwindMerge
to correct this issue. The documentation on configuring Tailwind Merge is well detailed, but since it only gives foo
, bar
, and baz
for examples, I was a bit confused how to do something specific.
The Ask
Please look at my tailwind.config.ts
and custom twMerge()
function and let me know if you have any ideas. Thanks!
The Code
// tailwind.config.ts
// * Types
import type { Config } from 'tailwindcss'
import type { CSSRuleObject, ThemeConfig } from 'tailwindcss/types/config'
/**
* ### Decimal Alpha to HEX
* - Converts an RGB decimal alpha value to hexidecimal alpha format
* @param decimalAlpha
* @returns
*/
export function decimalAlphaToHex(decimalAlpha: number): string {
// Ensure the input is within the valid range
if (decimalAlpha < 0 || decimalAlpha > 1)
throw new Error('Decimal alpha value must be between 0 and 1')
// Convert decimal alpha to a hexadecimal value
const alphaHex = Math.floor(decimalAlpha * 255)
.toString(16)
.toUpperCase()
// Ensure the hexadecimal value is two digits long (e.g., 0A instead of A)
if (alphaHex.length < 2) {
return '0' + alphaHex
} else {
return alphaHex
}
}
type GetTheme = <
TDefaultValue =
| Partial<
ThemeConfig & {
extend: Partial<ThemeConfig>
}
>
| undefined,
>(
path?: string | undefined,
defaultValue?: TDefaultValue | undefined,
) => TDefaultValue
// * Plugins
import plugin from 'tailwindcss/plugin'
import headlessui from '@headlessui/tailwindcss'
// @ts-ignore
import { default as flattenColorPalette } from 'tailwindcss/lib/util/flattenColorPalette'
const config: Config = {
content: [
'./components/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
textShadow: {
sm: '0 0 0.125rem var(--tw-text-shadow, hsl(0 0% 0% / 0.25))',
DEFAULT: '0 0 0.25rem var(--tw-text-shadow, hsl(0 0% 0% / 0.25))',
md: '0 0 0.5rem var(--tw-text-shadow, hsl(0 0% 0% / 0.25))',
lg: '0 0 0.75rem var(--tw-text-shadow, hsl(0 0% 0% / 0.25))',
xl: '0 0 1rem var(--tw-text-shadow, hsl(0 0% 0% / 0.25))',
'2xl': '0 0 2rem var(--tw-text-shadow, hsl(0 0% 0% / 0.25))',
'3xl': '0 0 3rem var(--tw-text-shadow, hsl(0 0% 0% / 0.25))',
none: 'none',
},
},
plugins: [
plugin(function ({ matchUtilities, theme }) {
const colors: { [key: string]: string } = {},
opacities: { [key: string]: string } = flattenColorPalette(
theme('opacity'),
),
opacityEntries = Object.entries(opacities)
Object.entries(flattenColorPalette(theme('colors'))).forEach((color) => {
const [key, value] = color
if (typeof key !== 'string' || typeof value !== 'string') return null
colors[key] = value.replace(' / <alpha-value>', '')
if (value.startsWith('#') && value.length === 7)
opacityEntries.forEach(([opacityKey, opacityValue]) => {
colors[`${key}/${opacityKey}`] = `${value}${decimalAlphaToHex(
Number(opacityValue),
)}`
})
if (value.startsWith('#') && value.length === 4)
opacityEntries.forEach(([opacityKey, opacityValue]) => {
colors[`${key}/${opacityKey}`] = `${value}${value.slice(
1,
)}${decimalAlphaToHex(Number(opacityValue))}`
})
if (value.startsWith('rgb') || value.startsWith('hsl'))
opacityEntries.forEach(([opacityKey, opacityValue]) => {
colors[`${key}/${opacityKey}`] = `${value.slice(
0,
-1,
)} / ${opacityValue})`.replace(' / <alpha-value>', '')
})
})
matchUtilities(
{
'text-shadow': (value) => {
const cssProperties: CSSRuleObject = {}
if (
typeof value === 'string' &&
(value.startsWith('#') ||
value.startsWith('rgb') ||
value.startsWith('hsl'))
) {
cssProperties['--tw-text-shadow-color'] = value
} else {
cssProperties['text-shadow'] = value
}
return cssProperties
},
},
{ values: { ...theme('textShadow'), ...colors } },
)
}),
],
}
export default config
My Best Attempt
// utils/custom-tailwind-merge.ts
import { extendTailwindMerge } from 'tailwind-merge'
import colors from 'tailwindcss/colors'
const colorList: { [key: string]: string[] }[] = []
Object.entries(colors).forEach(([colorName, valueList]) => {
if (
colorName === 'inherit' ||
colorName === 'transparent' ||
colorName === 'white' ||
colorName === 'black'
)
return
return colorList.push({ [colorName]: Object.keys(valueList) })
})
type AdditionalClassGroupIds = 'text-shadow'
export const twMerge = extendTailwindMerge<AdditionalClassGroupIds>({
extend: {
classGroups: {
'text-shadow': [
'sm',
'DEFAULT',
'md',
'lg',
'xl',
'2xl',
'3xl',
'none',
...colorList,
'transparent',
'white',
'black',
],
},
},
})
// components/link.tsx
import type { LinkProps } from '@/typings/components'
import { twMerge } from '@/utils/custom-tailwind-merge'
export default function Link({ children, className }: LinkProps) {
const defaultClasses = 'text-blue-500'
return (
<a className={twMerge(defaultClasses, className)}>{children}</a>
)
}
Pin section and change tabs on vertical scroll with GSAP or just javascript
Can you help me with this – when I reach What We Do section I need to pin it and scroll through the four tabs on left (and add class to each one) and then unpin and go to Latest Insights section.
Thanks a lot!
Displaying JSON data with Vue3
This is weird, but it is the first time I have dealt with JSON in Vue3, and it doesn’t seem to be reacting as I expected.
I have some JSON in a Vue DataObject called dataObject
data() {
return {
dataObject: {}
}
},
My JSON data looks, something, like this,
{
"myDataList": [
{
"list_item_1_1": "1234",
"list_item_1_2": "2023-09-21T09:06:13.000Z",
...
"list_item_1_6": [
{
"inline_list_item_1_6_1": "ABCD",
...
}
],
},
{
"list_item_2_1": "EFGH",
"list_item_2_2": "5678",
"list_item_2_3": "IJKL",
...
"list_item_2_8": {
"list_item_2_8_1": "OK",
"list_item_2_8_2": "MAYBE",
"list_item_2_8_3": "9011"
},
},
{
...
}
]
}
Now for some reason I can’t reach into the data and pull out, for example, list_item_2_8
. As this is Vue I am using <p>Data Value: {{this.dataObject.1.list_item_2_8}</p>
, however this gives me an Unexpected token
error in the console. When I run this through a JSON tool, this configuration of JSON is valid…
StackOverflow, Google, JSONFormatter.org and JSONQueryTool.com
Could someone point me in the right direction please? What am I doing wrong?
D3.js transition only works for the deleted Elements
When I update my data source, the transition only works for the deleted elements, but not for the updated elements.
I have inserted a .transition()
in the “deleted section” and in the “update section”. I suspect that the transition()
function in my update section is being used incorrectly.
No error is displayed, which could help me to solve the problem.
Can someone please help me?
// Data
const data1 = {
"name": "TOPICS",
"id": 1,
"children": [{
"name": "Topic A",
"id": 2,
"children": [{
"name": "Sub A1",
"id": 5,
"size": 4
}, {
"name": "Sub A2",
"id": 6,
"size": 4
}]
}, {
"name": "Topic B",
"id": 3,
"children": [{
"name": "Sub B1",
"id": 7,
"size": 3
}, {
"name": "Sub B2",
"id": 8,
"size": 3
}, {
"name": "Sub B3",
"id": 9,
"size": 3
}]
}, {
"name": "Topic C",
"id": 4,
"children": [{
"name": "Sub A3",
"id": 10,
"size": 4
}, {
"name": "Sub A4",
"id": 11,
"size": 4
}]
}]
};
const data2 = {
"name": "TOPICS",
"id": 1,
"children": [{
"name": "Topic A",
"id": 2,
"children": [{
"name": "Sub A1",
"id": 5,
"size": 4
}, {
"name": "Sub A2",
"id": 6,
"size": 4
}]
}, {
"name": "Topic B",
"id": 3,
"children": [{
"name": "Sub B1",
"id": 7,
"size": 3
}, {
"name": "Sub B2",
"id": 8,
"size": 3
}, {
"name": "Sub B3",
"id": 9,
"size": 3
}]
}]
};
//-------------------------------------------------------------------------------------------
// Declare variables
let i_region_static_id = "sunburst",
parentDiv = document.getElementById(i_region_static_id),
width = parentDiv.clientWidth,
height = 450,
root,
x,
y,
color = d3.scaleOrdinal(d3.schemeCategory10);
maxRadius = (Math.min(width, height) / 2) - 5;
const partition = d3.partition();
//-----------------------------------------------------------------------------------
// SVG-Element
let svg = d3.select('#' + i_region_static_id).append('svg')
.style('width', width)
.style('height', height)
.attr('viewBox', `${-width / 2} ${-height / 2} ${width} ${height}`)
//-----------------------------------------------------------------------------------
// X-Scale
x = d3.scaleLinear()
.range([0, 2 * Math.PI])
.clamp(true);
//-----------------------------------------------------------------------------------
// Y-Scale
y = d3.scaleSqrt()
.range([maxRadius * .1, maxRadius]);
//-----------------------------------------------------------------------------------
// Create Arc generator
const arc = d3.arc()
.startAngle(d => x(d.x0))
.endAngle(d => x(d.x1))
.innerRadius(d => Math.max(0, y(d.y0)))
.outerRadius(d => Math.max(0, y(d.y1)))
//-------------------------------------------------------------------------------------------
// Initialize and Update sun
function update_sun(pData) {
const valueAccessor = (d) => d.size;
root = d3.hierarchy(pData); //set data
valueAccessor == null ? root.count() : root.sum((d) => Math.max(0, valueAccessor(d)));
// Sort Nodes
root.sort((d) => d3.descending(d.value))
const slice = svg.selectAll('g.slice')
.data(
partition(root).descendants(),
function(d) { return d.data.id; }
);
//-------------------------------------------------------------------------------------------
// Enter Section
const newSlice = slice.enter()
.append('g').attr('class', 'slice')
.attr('display', d => d.depth < 2 ? null : 'none') // Hide levels lower depth
newSlice.append('path')
.attr('class', 'main-arc')
.style('fill', d => (d.data.color == undefined) ? color((d.children ? d : d.parent).data.name) : d.data.color) //set source color, otherwise default color
.attr('d', arc);
// Update Section
slice.select('path')
.style('fill', d => (d.data.color == undefined) ? color((d.children ? d : d.parent).data.name) : d.data.color)
.each(function(d) {
this.x0 = d.x;
this.dx0 = d.dx;
})
.transition().duration(1000)
.attrTween("d", function(d) { return function() { return arc(d); }; })
// Delete Section
slice.exit().transition().duration(500).style("fill-opacity", 0.2).remove();
}
//-------------------------------------------------------------------------------------------
update_sun(data1)
let i = 0;
d3.interval(() => {
if (i++ % 2 === 0) {
console.log("data2")
update_sun(data2);
} else {
console.log("data1")
update_sun(data1);
}
}, 4000)
.slice .main-arc {
stroke: #fff;
stroke-width: 1px;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="sun.css">
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<div id="sunburst"></div>
<script src="https://d3js.org/d3.v7.js" charset="utf-8"></script>
</body>
</html>
Webauthn AuthenticatorAttestationResponse “getPublicKey” returns a restricted object?
I’m trying to implement passkeys for my web app according to these guides, and I’m primarily working on the registration flow. After I’ve created the passkey using navigator.credential.create
, I try obtaining the newly generated public key using the getPublicKey
method on the returned response attribute. However, when I try inspecting the object, my browser says:
Restricted { }
According to MDN, this object should be an ArrayBuffer. In order to send it to the server I try to convert it to a base64-encoded string, however whenever I try to do something with this, the browser throws an error saying I can’t access this object.
I’ve already worked around this by sending the attestationObject
to the server and having the server decode it, but according to everything I’ve read, I should be able to do this client-side. Am I missing something obvious, or is this expected behavior?
TypeError: Cannot read properties of undefined (reading ‘map’) in react dev
in this the code is working normally when the api call is not done but when i make the call then it first render the normal code but after the api call it’s not re-render the fetched data.
enter image description here
enter image description here
please describe me the problem and how can i solve this as i am beginner in the react.
Typescript join
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Today's Date</title>
<script>
let competitionToday = "no competition"
alert("Today there is " + competitionToday + "on");
</script>
</head>
<body>
</body>
</html>
I can’t figure out why the
alert("Today there is " + competitionToday + "on");
is only alerting:
“Today there is no competition”
not:
“Today there is no competition on”
Change the path of images in JSON returned using AJAX
I want to change image whenever I choose the color the view so I write an Ajax to return the product of that color. Here the code :
$(document).on('change', '#colorId', function () {
GetImages(colorIds)
});
function GetImages(productId)
{
$.ajax({
url: '@Url.Action("GetImages","ProductView")',
type: 'GET',
data: { id : productId },
success: function (data) {
console.log("Hello " + data);
var images = [
data.image1,
data.image2,
data.image3,
data.image4
];
var image = document.querySelectorAll('#product-imgs .product-preview .image');
for (var i = 0; i < images.length; i++) {
image.src = '/Contents/img/' + images[i].split('/').pop();
}
}
})
}
Here the json return JsonResult. As you can see its include 4 images path. So I want to change in the view below by the image path that I received in Json
<div class="col-md-5 col-md-push-2">
<div id="product-main-img">
<div class="product-preview">
<img class="image" src="~/Contents/img/@Model.ProductItems.Image1" alt="">
</div>
<div class="product-preview">
<img class="image" src="~/Contents/img/@Model.ProductItems.Image2" alt="">
</div>
<div class="product-preview">
<img class="image" src="~/Contents/img/@Model.ProductItems.Image3" alt="">
</div>
<div class="product-preview">
<img class="image" src="~/Contents/img/@Model.ProductItems.Image4" alt="">
</div>
</div>
</div>
<!-- /Product main img -->
<!-- Product thumb imgs -->
<div class="col-md-2 col-md-pull-5">
<div id="product-imgs">
<div class="product-preview">
<img class="image" src="~/Contents/img/@Model.ProductItems.Image1" alt="">
</div>
<div class="product-preview">
<img class="image" src="~/Contents/img/@Model.ProductItems.Image2" alt="">
</div>
<div class="product-preview">
<img class="image" src="~/Contents/img/@Model.ProductItems.Image3" alt="">
</div>
<div class="product-preview">
<img class="image" src="~/Contents/img/@Model.ProductItems.Image4" alt="">
</div>
</div>
</div>
I have tried many way but still doesn’t work. When I change
var image = document.querySelector('.image');
Its only change one image. Does anyone know solutions? I will appreciate any instructions. Thanks for your reading.
lora-packet configure Join Accept
I’m trying to configure the Join Accept using the lora-packet library as follows:
const NetIdHexString = "001122"; //network identifier
const AppNonceHexString = "334455"; // or JoinNonce non-repeating value provided by Join Server
const NetIdBuffer = Buffer.from(NetIdHexString, "hex");
const AppNonceBuffer = Buffer.from(AppNonceHexString, "hex");
const sessionKeys = lora_packet.generateSessionKeys10(AppKey, NetIdBuffer, AppNonceBuffer, Buffer.from(devNonce, "hex"));
keysInstance.setSessionKeys(sessionKeys.AppSKey, sessionKeys.NwkSKey);
if (debugMode) {
console.log("AppSKey:", sessionKeys.AppSKey.toString("hex"));
console.log("NwkSKey:", sessionKeys.NwkSKey.toString("hex"));
}
const constructedPacket = lora_packet.fromFields(
{
MType: "Join Accept", // (default)
NetID: NetIdBuffer,
AppNonce: AppNonceBuffer,
DevAddr: Buffer.from("01766f7f", "hex"), // big-endian
DLSettings: 0,
RxDelay: 0
},
null, // AppSKey
null, // NwkSKey
AppKey
);
if (debugMode) {
console.log("constructedPacket.toString()=n" + constructedPacket);
}
const base64 = constructedPacket.getPHYPayload().toString('base64');
if (debugMode) {
console.log("wireFormatPacket.toString()=" + constructedPacket.getPHYPayload().toString("hex") + " base64= " + base64 + " wireFormatPacket length:" + constructedPacket.MACPayloadWithMIC.length);
}
But when I check it in the LoRaWAN 1.0.x packet decoder, I get a message that the MIC is incorrect. What am I doing wrong?
Im trying to check constructedPacket.MACPayloadwithMIC but its inccorect too.
Why Javascript multiple async awaits behaves differently when it awaits promises vs when it awaits functions returning promises?
I have the below code with both the implementations.
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('promise 1');
}, 1000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('promise 2');
}, 1000);
})
const p1func = () => new Promise((resolve, reject) => {
setTimeout(() => {
resolve('promise 1 func');
}, 1000);
});
const p2func = () => new Promise((resolve, reject) => {
setTimeout(() => {
resolve('promise 2 func');
}, 1000);
})
async function TestPromise() {
console.log("started");
const val = await p1;
console.log(val);
const val2 = await p2;
console.log(val2);
//checkpoint 1: reaches this point in 1 second
const val3 = await p1func();
console.log(val3);
const val4 = await p2func();
console.log(val4);
//from checkpoint 1, it takes 2 seconds to reach here
}
TestPromise();
When I ran the code I noticed that when js awaits 2 promises, it starts executing them parallelly & completes within 1 second(asynchronously). When the functions returning promises were run JS ran them one by one(synchronously).Is JS engine detecting 2 awaits on promises prior run inorder to be able to execute them parallelly? Why can’t it do the same with functions returning promises?
JavaScript Web Audio API – Sampling Problem and FFT
I am having a problem with the Web Audio API where the audio sampling rate is incorrect on an Android phone using Chrome, Opera and Edge browser, but it works fine using the Firefox browser.
I am recoding the microphone into an array using Web Audio API as follows, where just snippets of my code have been included, as I cannot paste all of it, but this is just to show which functions I am using.
let audioContext;
dataArrayFft = new Float32Array(bufferLength);
audioContext = new (window.AudioContext || window.webkitAudioContext)({ sampleRate:48000});
analyser = audioContext.createAnalyser();
const source = audioContext.createMediaStreamSource(stream);
source.connect(analyser);
I then call the following routine periodically (30Hz) to update my chart.js:
analyser.getFloatFrequencyData(dataArrayFft);
The code works fine on my PC using the Chrome browser and shows the full FFT spectrum up to 24kHz with a 48kHz sampling rate.
With my Android phone I point each of the browsers (Chromer, Opera, Firefox, Edge) to my laptop IP address (https://192.168.1.149:3000) to view the web page on my phone to test my app.
The following IMAGE 1 shows the app running in the Chrome browser on my Windows 10 laptop and it is working as expected.
The following images 2,3,4 show my Android phone viewing the web page on my laptop and as you can see for Chrome, Opera and Edge (IMAGES 2,3,5) the FFT spectrum rolls off at 8kHz but for Firefox (IMAGE 4) it shows the full spectrum as expected and I have confirmed it works by using a signal generator.
I do not understand why it works as expected on Firefox but there is this 8kHz limit on the other browsers indicating the sampling rate is being limited to 16kHz? Any thoughts on what this problem could be caused by?
How do i make a vertical bar to reveal the image underneath? [closed]
I have a little bit of a problem and i don t know how to approach it. So basically I have to pictures of a car, identical, one is scratched and one is not. The two images are overlaped and have a vertical bar in the middle. To the left of the bar only the scratched image is visible to the right only the normal one. As i drag the bar to the left, what is to the right of the car turns into the normal image. Vice versa if i move the bar to the right, whatever is to the left of the bar turns into the scratched car.
I have tried a lot of things but nothing seemed to work.
Typescript: matches 2 arrays [duplicate]
I need to find out if 2 arrays match (have common elements) in one or more elements.
Is there a more elegant way than the 2 loops?
In Java I would use a stream with lambda.
lst1.stream ().anyMatch (c -> lst2.contains (c))
But I am not sure hot to do that in Typescript/Javascript.
let lst1 : string [] = ["aaa", "bbb", "ccc"];
let lst2 : string [] = ["ddd", "eee", "bbb"]; // 1 match at "bbb"
let matches : boolean = false;
for (let a of this.lst1)
{
for (let b of this.lst2)
{
if (a == b)
{
matches = true;
}
}
}