Search
weatherForecastDashboard
@bhavana
@jsxImportSource https://esm.sh/react@18.2.0
HTTP
import { createRoot } from "https://esm.sh/react-dom@18.2.0/client";
function WeatherDashboard() {
const [weather, setWeather] = useState(null);
useEffect(() => {
function handleClickOutside(event) {
if (suggestionRef.current && !suggestionRef.current.contains(event.target)) {
return () => document.removeEventListener('mousedown', handleClickOutside);
async function fetchLocationSuggestions(query) {
if (query.length < 2) {
fetchLocationSuggestions(value);
async function selectLocation(selectedLocation) {
setLocationInput(selectedLocation.name);
await fetchWeatherData(selectedLocation);
async function fetchWeatherData(coords) {
try {
setError('Failed to fetch weather data');
async function handleLocationSubmit(e) {
e.preventDefault();
</div>
function client() {
createRoot(document.getElementById("root")).render(<WeatherDashboard />);
if (typeof document !== "undefined") { client(); }
export default async function server(request: Request): Promise<Response> {
return new Response(`
satisfactoryBlushCatshark
@maxm
An interactive, runnable TypeScript val by maxm
Script
import { Buffer } from "node:buffer";
import { base58 } from "npm:@scure/base";
export function convertUUIDToToken(uuid: string): string {
return "vt_" + base58.encode(Buffer.from(uuid.replace(/-/g, ""), "hex"));
export function generateAndConvertUUIDs() {
const uuidBuffer = Buffer.alloc(16);
let tokenLength = 0;
svgMapOfCountry
@jdan
An interactive, runnable TypeScript val by jdan
Script
import { countryData } from "https://esm.town/v/jdan/countryData";
import { blob } from "https://esm.town/v/std/blob?v=10";
export async function svgMapOfCountry(country: string) {
const mapUrl = (await countryData())
.find((value) => value.countryLabel === country)
// Start SVG string without width and height, only viewBox
let svgString = `<svg viewBox="${viewBox}" xmlns="http://www.w3.org/2000/svg">\n`;
// Function to convert a ring to a path data string
const ringToPathD = (ring) => {
let d = `M ${ring[0][0]} ${90 - ring[0][1]} `;
convertRGBToHex
@rodrigotello
An interactive, runnable TypeScript val by rodrigotello
Script
export function convertRGBToHex(rgb) {
return ((rgb * 255) | (1 << 8)).toString(16).slice(1);
expiringBlob
@postpostscript
expiringBlob: create-and-forget blobs using UUIDv7 How it Works This tool uses UUIDv7s in blob keys with UNIX timestamps included to keep track of when they expire.
Since UUIDv7s are sortable and the blob list endpoint returns results alphabetically, cleanup (checking the blob list and deleting any expired keys) is efficient since any expired keys will be at the front of the results! Each ID is prefixed with a prefix (default: expireBlob: ) and can be suffixed with a label (parameter order depends on the method).
Example blob keys: expiringBlob:01944432-4837-7a99-94e6-e0e162554e21
^Prefix ^UUIDv7
expiringBlob:01944432-4837-7a99-94e6-e0e162554e21:aaaa
^Prefix ^UUIDv7 ^Label Methods createKey : generate a key you can use with @std/blob methods set or setJSON : generate a blob key and save content to it in one step cleanup : delete expired blobs. You can run this manually or periodically with a cron val . If using a custom prefix, make sure to pass it to this method so that the correct blob list is searched. By default, createKey , set , and setJSON will create keys that expire in an hour, but you can override this by passing the expireAt: Date | number parameter. For convenience, expireIn is provided with methods to create future dates for each of the following: expireIn.hours(2) expireIn.minutes(5) expireIn.seconds(45) expireIn.ms(500) To request data once you've saved it, use @std/blob's get and getJSON as usual with the key provided by set or setJSON ! Full Example import { cleanup, createKey, expireIn, set, setJSON } from "https://esm.town/v/postpostscript/expiringBlob";
import { blob } from "https://esm.town/v/std/blob";
const aaaa = createKey("aaaa"); // equivalent of createKey("aaaa", expireIn.hours(1))
await blob.setJSON(aaaa, {
x: 1,
});
console.log(aaaa, await blob.getJSON(aaaa));
// expiringBlob:01944432-4837-7a99-94e6-e0e162554e21:aaaa { x: 1 }
console.log(await set("bbbb", "test", expireIn.seconds(1)));
// expiringBlob:019443fb-6106-77f2-ab0c-5142b099c81a:bbbb
console.log(await setJSON("cccc", { x: 1 }, expireIn.seconds(1)));
// expiringBlob:019443fb-6327-733c-9a0b-c8b9ee9faef0:cccc
await cleanup();
// [no logs]
await new Promise((resolve) => setTimeout(resolve, 1000));
await cleanup();
// deleting expired blob: expiringBlob:019443fb-6106-77f2-ab0c-5142b099c81a:bbbb
// deleting expired blob: expiringBlob:019443fb-6327-733c-9a0b-c8b9ee9faef0:cccc Forkable Cron Example Create a cron val with the following code to periodically delete expired blobs: import { cleanup } from "https://esm.town/v/postpostscript/expiringBlob";
export default () => cleanup();
Script
export const PREFIX = "expiringBlob:";
export async function cleanup(prefix = PREFIX, $blob: BlobInterface = blob) {
let deletedAnyOverall = false;
return new Date(new Date().getTime() + value);
export function createKey(label?: string, expireAt: Date | number = expireIn.hours(1), prefix = PREFIX) {
if (label && (label.length - prefix.length) >= 36) {
return id;
export async function set(
label: string | undefined,
return id;
export async function setJSON(
label: string | undefined,
type BlobInterface = Pick<typeof blob, "set" | "setJSON" | "delete" | "list">;
async function* applicableBlobKeys(prefix = PREFIX, $blob: BlobInterface = blob): AsyncGenerator<string> {
for (const el of await $blob.list(prefix)) {
githubNormalizedJsonString
@stevekrouse
An interactive, runnable TypeScript val by stevekrouse
Script
export function githubNormalizedJsonString(payload: object) {
// GitHub sends its JSON with an indentation of 2 spaces and a line break at the end
const payloadString = JSON.stringify(payload, null, 2) + "\n";
btcPriceAlert
@Technoking
BTC Price Alert This val monitors the price of Bitcoin (BTC) and sends an email alert if the price fluctuates significantly. Specifically, it checks the current BTC price against the last recorded price and triggers an email notification if the change exceeds 20%. The email includes the new price, formatted as currency. Fork this val to get these notifications on your inbox.
Email
import { email } from "https://esm.town/v/std/email?v=9";
import { currency } from "https://esm.town/v/stevekrouse/currency";
export async function btcPriceAlert() {
const lastBtcPrice: number = await blob.getJSON("lastBtcPrice");
let btcPrice = await currency("usd", "btc");
getRotationFromFFmpegDisplayMatrixString
@seflless
An interactive, runnable TypeScript val by seflless
Script
export function getRotationFromFFmpegDisplayMatrixString(str: string) {
let elements = str.match(/[-+]?\d+/g)?.map(Number) || [];
if (elements.length !== 9) {
youtubeFeed
@pdebie
Fetches all videos for a Youtube channel, by using its RSS feed.
Script
import { fetchRss } from "https://esm.town/v/pdebie/fetchRss";
export function youtubeFeed(channelId: string, lastCheckDate?: string | number) {
return fetchRss(
"https://www.youtube.com/feeds/videos.xml?channel_id=" + channelId,
letterboxd
@javier
Gets a list with all the films a user has added to their public diary in Letterboxd. The result is a JSON file with the following structure: "updated_at": "2023-08-13",
"count": 470,
"films": [
{
"watched_on": "2022-10-24",
"title": "Aftersun (2022)",
"rating": 4.5,
"rewatched": false
},
{
"watched_on": "2021-03-20",
"title": "Le Trou (1960)",
"rating": 5,
"rewatched": true
},
...
{
"watched_on": "2020-09-13",
"title": "Tampopo (1985)",
"rating": 5,
"rewatched": false
}
]
} If you want to use it in the browser, just visit this URL: https://javier-letterboxdscrapper.web.val.run/?username={username}
Script
const rating = parseInt($(metadata).data("rating"), 10) / 2;
return { title, watched_on: watchedOn, rating, rewatched };
async function getFilms() {
const totalPages = await getTotalPages();
const films = [];
rssToBsky
@faekiva
[disc five] RssToBsky - This val periodically polls the "[disc five]" rss feed and posts the new items to bsky.
Cron
const rssFeeds: RSSEntry[] = [
["[disc five]", "https://www.discfive.com/rss/"],
export async function pollRSSFeeds({ lastRunAt }: Interval) {
const password = Deno.env.get(bskyPassword);
if (!password) {
mediainfo
@jamiedubs
Fetches details about media files (images, video, audio, etc) using Mediainfo.js . e.g. codecs used, duration, file sizes, ID3 tags, etc. Check out https://jamiedubs-mediainfo.web.val.run/ for a little interactive example Beta! API response not 100% stable, I might move things around still. Especially this summary field idea
HTTP
frameRate?: string;
function App({ initialUrl }: AppProps) {
// Bob Dylan mp3 found in an open directory
</html>
function summarizeMediaInfo(mediaInfo: MediaInfoResult): MediaSummary {
const summary: MediaSummary = {
return summary;
export default async function server(request: Request): Promise<Response> {
const url = new URL(request.url);
stopDeparturesSingleCountdown
@kognise
An interactive, runnable TypeScript val by kognise
Script
import { stopDepartures } from "https://esm.town/v/kognise/stopDepartures";
export async function stopDeparturesSingleCountdown(globalStopId: string) {
const res = await stopDepartures(globalStopId);
return res[0].itineraries[0].schedule_items.map((bus) => ({
FontPack
@rektdeckard
An interactive, runnable TypeScript val by rektdeckard
HTTP
let next = PUA_START;
function nextAvailableCodePoint() {
while (usedCodes.has(next)) {
inline?: boolean;
function bufferToBase64(buffer: ArrayBuffer) {
let binary = "";
return btoa(binary);
export default async function(
req: Request,
rimeRateLimitExceeded
@stevekrouse
An interactive, runnable TypeScript val by stevekrouse
Script
import { email } from "https://esm.town/v/std/email?v=9";
import { rimeUsage } from "https://esm.town/v/stevekrouse/rimeUsage";
export function rimeRateLimitExceeded(text: string) {
rimeUsage[new Date().toLocaleDateString()] =
(rimeUsage[new Date().toLocaleDateString()] || 0) +