Search
ical_subscribe
@moe
@jsxImportSource https://esm.sh/preact
HTTP
/** @jsxImportSource https://esm.sh/preact */
import { reactResponse } from "https://esm.town/v/moe/responses"
export default (req: Request) => {
const calendarUrl = url.searchParams.get("url")
return reactResponse(
<html>
honoBasicAuthMiddleware
@jdan
honoBasicAuthMiddleware You should use https://hono.dev/middleware/builtin/basic-auth instead. Used to authenticate your HTTP vals build with Hono behind a username/password challenge. Browsers store this information alongside your other passwords. Usage In basicAuthButton , I secure two routes (one for viewing a value, one for updating it) behind a username/password combo stores in my Env variables. /** @jsxImportSource npm:hono@3/jsx */
import { honoBasicAuthMiddleware } from "https://esm.town/v/jdan/honoBasicAuthMiddleware";
import { blob } from "https://esm.town/v/std/blob?v=12";
import { Hono } from "npm:hono";
/** Authenticate the URL */
const secretUsername = Deno.env.get("BUTTON_USERNAME");
const secretPassword = Deno.env.get("BUTTON_PASSWORD");
app.use(honoBasicAuthMiddleware(secretUsername, secretPassword));
app.get("/", async (c) => {
const lastPressed = await blob.getJSON(blobStorageKey) || "Never";
return c.html(
<div>
<h1>Last Pressed: {lastPressed}</h1>
<form method="POST" action="/press">
<input type="submit" />
</form>
</div>,
);
});
Script
You should use https://hono.dev/middleware/builtin/basic-auth instead.
Used to authenticate your HTTP vals build with Hono behind a username/password challenge. Browsers store this information alongside your other passwords.
![Screenshot 2024-05-25 at 7.30.11 AM.png](https://imagedelivery.net/iHX6Ovru0O7AjmyT5yZRoA/ad83e938-8062-44d4-c8f2-5039780bf300/public)
minifyHTML
@yieldray
Usage: import { minifyHTML } from "https://esm.town/v/yieldray/minifyHTML";
const minified = await minifyHTML("<html>...</html>", { ...options }); As an API: import { runVal } from "https://esm.town/v/std/runVal";
const minified = awaitrunVal("yieldray.minifyHTML", "<html>...</html>", { ...options });
Script
minify_css_level_3: boolean;
* Minify JavaScript in <script> tags using minify-js.
* Only <script> tags with a valid or no MIME type is considered to contain JavaScript, as per the specification.
minify_js: boolean;
* Remove all bangs.
tuna
@jxnblk
🐟 Simple CSS library for Val Town import { css } from "https://esm.town/v/jxnblk/tuna";
const styles = css({
body: { // special keyword for <body> element
fontFamily: "system-ui, sans-serif",
margin: 0,
backgroundColor: "#f5f5f5",
},
container: {
padding: 32, // numbers are converted to pixel units
margin: "0 auto",
maxWidth: 1024,
},
input: {
fontFamily: "inherit",
fontSize: "inherit",
lineHeight: "1.5",
padding: "2px 8px",
border: "1px solid #ccc",
borderRadius: "4px",
},
}); // JSX example
const html = render(
<div className={styles.container}>
<style {...styles.tag} />
<h1>Tuna Example</h1>
<input
type="text"
defaultValue="hi"
className={styles.input}
/>
</div>
); // get raw CSS string
styles.css Nested selectors and pseudoselectors const styles = css({
button: {
background-color: "tomato",
"&:hover": {
background-color: "magenta",
},
"& > svg": {
fill: "currentColor",
},
},
}); Media queries const styles = css({
box: {
padding: 16,
"@media screen and (min-width: 768px)": {
padding: 32,
"&:hover": {
color: "tomato",
},
},
}
}); Limitations Does not support HTML element selectors (other than body ) Tests: https://www.val.town/v/jxnblk/tuna_tests
Script
const nested = NESTED_RE.test(key);
const media = MEDIA_RE.test(key);
// consider: typeof val === "object";
if (nested) {
// e.g. `&:hover`
d3ChordDiagram
@fil
D3 Chord diagram Example taken from the D3 Gallery , and rendered (server-side) as a static SVG served through the web end point .
HTTP
# D3 Chord diagram
Example taken from the [D3 Gallery](https://observablehq.com/@d3/chord-diagram/2?intent=fork), and rendered (server-side) as a static SVG served through the [web end point](https://fil-d3ChordDiagram.web.val.run).
![](https://fil-d3ChordDiagram.web.val.run)
import { svgServer } from "https://esm.town/v/fil/svgServer";
export async function d3ChordDiagram(req) {
// Import D3 and create a DOM document for server-side-rendering.
const d3 = await import("npm:d3");
const document = await import("https://esm.sh/linkedom@0.15").then((l) =>
gifStory
@substrate
Generates a story and then a storyboard with 5 animated frames. Note : You'll need to fork this example (and un-comment some code) to run it with new input. Currently it renders cached output, for demo purposes (running takes 30-60s). 🪩 To fork, sign up for Substrate to get your own API key and $50 free credits
HTTP (deprecated)
"The sound of rushing water grows louder as the traveler follows the winding path.",
"A massive waterfall comes into view, cascading down a rocky slope.",
"The roar of the falls subsides as the traveler rounds a bend in the path.",
"imageDescriptions": [
"A dense jungle with towering trees and vines",
InjectHTMLElementStream
@andreterron
Inject HTML Element Stream Use InjectHTMLElementStream to inject an HTML element inside the <body /> or <html /> tag of a streamed HTML string.
Script
# Inject HTML Element Stream
Use `InjectHTMLElementStream` to inject an HTML element inside the `<body />` or `<html />` tag of a streamed HTML string.
createTibberApi
@chrstnst
An interactive, runnable TypeScript val by chrstnst
Script
export async function createTibberApi(config: Config) {
const { default: axios } = await import("https://esm.sh/axios");
const client = axios.create({
baseURL: "https://api.tibber.com/v1-beta",
method: "POST",
authorization: `Bearer ${config.token}`,
const query = async <R>(q: string): Promise<R> => {
const { data } = await client.post("/gql", { query: q });
return data;
return { query };
variedPractice
@petermillspaugh
@jsxImportSource https://esm.sh/react
Script
/** @jsxImportSource https://esm.sh/react */
import { generateLessonHtml } from "https://esm.town/v/petermillspaugh/lessonTemplate";
import { renderToString } from "npm:react-dom/server";
* Note: this lesson is a work in progress 👷♂️
const TITLE = "Varied practice";
ValTownPrompt
@stevekrouse
An interactive, runnable TypeScript val by stevekrouse
Script
export const ValTownPrompt = `CONTEXT:
- Val Town is a social programming environment
- Vals are JavaScript & TypeScript code that run server-side
- Users create vals by creating variables \`export const foo = 1 // creates a public val named foo\`
- You can reference your own vals: \`@me.foo // returns 1\`
fileInputUploadExample
@stevekrouse
Example of an HTML Form with a File Upload, handled by the server The key step was setting enctype="multipart/form-data" on the <form> element. If you skip that step, you'll only get the file's name on the server. Limitation on files > 1mb Currently (as of 4/14/24) this only works for small files (< 1mb). For larger files you get an error: {"statusCode":413,"error":"Payload Too Large","message":"request entity too large"} . A workaround is to upload to another service client-side, send the URL from that service to your Val Town server, and then fetch the file server-side (helper: @stevekrouse/uploadTo0x0).
HTTP (deprecated)
Currently (as of 4/14/24) this only works for small files (< 1mb). For larger files you get an error: `{"statusCode":413,"error":"Payload Too Large","message":"request entity too large"}`.
A workaround is to upload to another service client-side, send the URL from that service to your Val Town server, and then fetch the file server-side (helper: @stevekrouse/uploadTo0x0).
counterscaleWeeklyReport
@benvinegar
// borrowed from: https://github.com/benvinegar/counterscale/blob/main/app/analytics/query.ts#L24
Cron
// cf account id
const accountId = process.env.counterscaleCfAccountId;
const url = `https://api.cloudflare.com/client/v4/accounts/${accountId}/analytics_engine/sql`;
// query counts grouped by site over last 7 days
const query = `
fetchBcycleCounts
@jonbo
An interactive, runnable TypeScript val by jonbo
Script
export const fetchBcycleCounts = (async () => {
const tokenResponse = await fetch(
"https://boulder.bcycle.com/api/bearertoken/getclient?_=1673303289964",
headers: {
accept: "*/*",
generation
@petermillspaugh
@jsxImportSource https://esm.sh/react
Script
/** @jsxImportSource https://esm.sh/react */
import { generateLessonHtml } from "https://esm.town/v/petermillspaugh/lessonTemplate";
import { renderToString } from "npm:react-dom/server";
* Note: this lesson is a work in progress 👷♂️
const TITLE = "Generation";
meyerWebCSSReset
@rodrigotello
CSS Reset Eric A. Meyer's CSS reset.
Script
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
vertical-align: baseline;
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;