Shell script to convert all files in directory to webp, with default params, or standard cwebp params passed from command.
#!/bin/bash
PARAMS=('-m 6 -q 70 -mt -af -progress')
if [ $# -ne 0 ]; then
PARAMS=$@;
fi
cd $(pwd)
shopt -s globstar nullglob nocaseglob extglobTo fix problems with globstar(especially on MacOS), use this gist.
A TypeScript type alias called Prettify.
It takes a type as its argument and returns a new type that has the same properties as the original type,
but the properties are not intersected. This means that the new type is easier to read and understand.
type Prettify<T> = {
[K in keyof T]: T[K];
} & {};For deeply nested types:
type Prettify<T> = {
[K in keyof T]: T[K] extends object ? Prettify<T[K]> : T[K];
} & {};Use case
Suppose we have a type that has many intersections:
export type SimpleShape = {
color: string;
} & {
size: number;
} & {
shape: 'circle' | 'square';
};When we hover over the type SimpleShape with many intersections, it can be difficult to see the resolved type. It would be helpful if there was a way to prettify the display of these types.
With Prettify we can exactly do so, using:
type Shape = Prettify<SimpleShape>;
// ^? type Shape = {
// color: string;
// size: number;
// shape: "circle" | "square";
// }Pick keys from an object to construct a picked object, with full type support.
const pick = <T, K extends keyof T>(obj: T, keys: K[]) =>
keys.reduce(
(pickedObj, currentKey) => {
pickedObj[currentKey] = obj[currentKey];
return pickedObj;
},
{} as Pick<T, K>
);Example Usage
const x = { a: 1, b: 2, c: 3 };
const y = pick(x, ['b']);
// { b: 2 }Download and save a file using streams in Node.js, great for downloading large files without clogging up memory.
import { createWriteStream } from 'node:fs';
import { Readable } from 'node:stream';
import { finished } from 'node:stream/promises';
export const downloadFile = async (
url: string,
fileName: string,
encoding: string
) => {
const writeStream = createWriteStream(fileName, { encoding });
// Use body since it is a readable stream
console.log('Starting File download...');
const { body } = await fetch(url);
if (body) {
// Pipe body to the writestream
await finished(Readable.fromWeb(body as any).pipe(writeStream));
console.log('File download successful!');
} else {
throw new Error('File empty!');
}
};Paste the following code in the global CSS file:
@font-face {
font-family: 'Inter';
font-weight: 100 900;
font-display: swap;
font-style: normal;
font-named-instance: 'Regular';
src: url('/fonts/Inter.var.woff2') format('woff2');
}Extract all the keys of a certain type T from object O.
type KeysOfType<O, T> = {
[K in keyof O]: O[K] extends T ? K : never;
}[keyof O & string];Use case
Suppose we have a type User like so:
type User = {
id: string;
name: string;
isAdmin: boolean;
isEnabled: boolean;
hasVerifiedEmail: boolean;
};And we want to extract all the boolean fields from User and put them in a new type called UserFlags. We can do so by:
type UserFlags = KeysOfType<User, boolean>;
// ^? type UserFlags = "isAdmin" | "isEnabled" | "hasVerifiedEmail"Check if an element is in the browser viewport or not.
const isInViewport = (element: HTMLElement) => {
const { top, right, bottom, left } = element.getBoundingClientRect();
return (
top >= 0 &&
left >= 0 &&
bottom <= window.innerHeight &&
right <= window.innerWidth
);
};Get date formatted with ordinals (st, nd, rd, th, etc) using JavaScript's Intl.
const getFormattedDate = (dateString: string, locale = 'en-IN') => {
const ordinalMap: Partial<Record<Intl.LDMLPluralRule, string>> = {
one: 'st',
two: 'nd',
few: 'rd',
other: 'th',
};
const ordinalPluralRules = new Intl.PluralRules(locale, { type: 'ordinal' });
const formatter = new Intl.DateTimeFormat(locale, {
day: 'numeric',
month: 'long',
year: 'numeric',
});
const dateParts = formatter.formatToParts(new Date(dateString));
// Modify day part by adding ordinal
const dayPart = dateParts.find((p) => p.type === 'day')!;
const ordinal = ordinalMap[ordinalPluralRules.select(Number(dayPart.value))];
dayPart.value = dayPart.value + ordinal;
return dateParts.map((p) => p.value).join('');
};Example usage and outputs:
getFormattedDate('03-22-2023');
// "22nd March 2023"
getFormattedDate('08-17-2023', 'en-US');
// "August 17th, 2023"
getFormattedDate('12-31-2023', 'en-GB');
// "31st December 2023"Limitations
This logic only works for English locales and might not work for others like French, German, etc.
Display prices with the Rupee symbol, Indian numeric system commas and 2 decimal digits:
const displayInr = (amount: number) =>
'₹ ' +
new Intl.NumberFormat('en-IN', {
maximumFractionDigits: 2,
minimumFractionDigits: 2,
}).format(amount);Example usage and outputs:
displayInr(23);
// "₹ 23.00"
displayInr(1007.5);
// "₹ 1,007.50"
displayInr(1299999.98999);
// "₹ 12,99,999.99"Wait for a period of time in JavaScript.
export const delay = async (millis: number) =>
new Promise((resolve) => setTimeout(resolve, millis));Example Usage
// Wait for 2 seconds
await delay(2000);Bonus: Node.js
If in node, you could also just do
import { setTimeout as delay } from 'node:timers/promises';
// Wait for 2 seconds
await delay(2000);Convert a timestamp in millis to a particular timezone using JavaScript's Intl.
const getDateForTimeZone = (
millis: number,
tz: string,
locale = 'en-IN'
): string => {
const dateFormatter = new Intl.DateTimeFormat(locale, {
timeZone: tz,
day: 'numeric',
month: 'short',
year: 'numeric',
});
const timeFormatter = new Intl.DateTimeFormat(locale, {
timeZone: tz,
timeStyle: 'short',
});
const timezoneFormatter = new Intl.DateTimeFormat(locale, {
timeZone: tz,
timeZoneName: 'long',
});
return [
`${dateFormatter.format(millis)}`,
`${timeFormatter.format(millis).toUpperCase()}`,
`${timezoneFormatter.formatToParts(millis).find((p) => p.type === 'timeZoneName')?.value || ''}`,
].join(' ');
};Example usage and outputs:
getDateForTimeZone(1690113193308, 'Asia/Kolkata');
// 23 Jul 2023 5:23 PM India Standard Time
getDateForTimeZone(1690113193308, 'America/Chicago', 'en-US');
// Jul 23, 2023 6:53 AM Central Daylight Time
getDateForTimeZone(1690113193308, 'Europe/Paris', 'fr-FR');
// 23 juil. 2023 13:53 heure d’été d’Europe centraleconst copyToClipboard = async (textToCopy: string) => {
if (!navigator.clipboard)
throw Error('Clipboard API not supported in current browser');
if (!window.isSecureContext) throw Error('Can only copy in secure contexts');
await navigator.clipboard.writeText(textToCopy);
};Fallback Copy (Deprecated)
const fallbackCopyToClipboard = (textToCopy: string) => {
// Create textarea in Document, focus and select
let textArea = document.createElement('textarea');
textArea.value = textToCopy;
textArea.style.position = 'fixed';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
let successful = document.execCommand('copy');
if (!successful) {
throw new Error('execCommand failed to copy to clipboard');
}
} catch (err) {
throw new Error(`execCommand failed: ${err}`);
} finally {
// Remove the created Textarea
document.body.removeChild(textArea);
}
};Simple version
export const cn = (...classes: (boolean | string)[]) =>
classes.filter(Boolean).join(' ');Advanced version with twMerge
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...classes: ClassValue[]) {
return twMerge(clsx(classes));
}const convertBase64toBlob = (base64String: string, mimeType: string) => {
const byteCharacters = atob(base64String);
const byteArrays = [];
const sliceSize = 512;
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
return new Blob(byteArrays, { type: mimeType });
};