1# Image generated from a path name powered by fal.ai
2
3https://maxm-imggenurl.web.val.run/firefly.jpg
1import { generateImage } from "https://esm.town/v/isidentical/falImageGen?v=11";
2import { blob } from "https://esm.town/v/std/blob?v=12";
3
4const genKey = (key: string): string => {
5 return "genImageCache-v1-" + key;
6};
7
10 let url = await blob.getJSON(genKey(key));
11 if (!url) {
12 let resp = await generateImage(`generate the image you would expect if the url path was: "${key}"`);
13 url = resp.url;
14 await blob.setJSON(genKey(key), url);
15 }
16 return new Response((await fetch(url)).body, { headers: { "content-type": "image/jpg" } });
17}
4
5<div align="center">
6<img src="https://imagedelivery.net/iHX6Ovru0O7AjmyT5yZRoA/67a1d35e-c37c-41a4-0e5a-03a9ba585d00/public" width="700px"/>
7</div>
3View and interact with your Val Town SQLite data. It's based off Steve's excellent [SQLite Admin](https://www.val.town/v/stevekrouse/sqlite_admin?v=46) val, adding the ability to run SQLite queries directly in the interface. This new version has a revised UI and that's heavily inspired by [LibSQL Studio](https://github.com/invisal/libsql-studio) by [invisal](https://github.com/invisal). This is now more an SPA, with tables, queries and results showing up on the same page.
4
5
6
7## Install
11 let html = `<h1>${valTownInspo.title}</h1>
12 <p>${valTownInspo.description}</p>
13 <a href="https://val.town/${valTownInspo.val}"><img src="${valTownInspo.image}" style="max-width:576px"/></a>
14 <p><a href="https://www.val.town/settings/intervals">Unsubscribe here</a></p>`;
15
16You can try a demo at <https://pomdtr-lastloginhonoexample.web.val.run> (see @pomdtr/lastLoginHonoExample for code)
17
18
19
20## Usage
8
9<div align="center">
10<img src="https://imagedelivery.net/iHX6Ovru0O7AjmyT5yZRoA/67a1d35e-c37c-41a4-0e5a-03a9ba585d00/public" width="500px"/>
11</div>
3This is a lightweight Blob Admin interface to view and debug your Blob data.
4
5
6
7Use this button to install the val:
1const image =
2 "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=";
3
4function base64ToUint8Array(base64: string): Uint8Array {
13
14export default async function(req: Request): Promise<Response> {
15 const imageData = base64ToUint8Array(image);
16 return new Response(imageData, {
17 headers: {
18 "Content-Type": "image/jpeg",
19 "Content-Length": imageData.length.toString(),
20 // "Access-Control-Allow-Origin": "null",
21 },
517 margin: 0;
518 background-color: var(--page);
519 background-image: radial-gradient(#222 1px, transparent 0px);
520 background-size: 1rem 1rem;
521 color: var(-text);
562
563canvas {
564 image-rendering: pixelated;
565 width: 100%;
566 pointer-events: none;