Public
HTTP (deprecated)
Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
Readme

Bookmarklet Manager

Write your bookmarklets in val.town.

Usage

You val should export an anonymous function, containing the code that will run when the bookmarklet is triggered.

export default () => { alert("Hi mom!"); }

Make sure that your val is either unlisted or public, then navigate to https://pomdtr-bookmarklets.web.val.run/v/:author/:name to generate the bookmarklet link.

Sharing a bookmarklet

Make sure that your val is public, and add a #bookmarklet tag anywhere in the code.

export default () => { alert("Hi mom!"); } // #bookmarklet

It should automatically appears on https://pomdtr-bookmarklets.web.val.run.

⚠️ If you are using the Arc Browser, you can use the Powerlet extension to install bookmarklets.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/** @jsxImportSource https://esm.sh/hono@3.9.2/jsx **/
import { api } from "https://esm.town/v/pomdtr/api";
import { extractValInfo } from "https://esm.town/v/pomdtr/extractValInfo";
import { Hono } from "npm:hono";
import { jsxRenderer } from "npm:hono/jsx-renderer";
import { minify } from "npm:terser";
const app = new Hono();
async function bookmarkletUrl(author: string, name: string) {
const { code } = await api(`/v1/alias/${author}/${name}`);
const { code: minifedCode } = await minify(`(${code})();`);
return `javascript:${encodeURIComponent(minifedCode)}`;
}
app.get(
"/*",
jsxRenderer(({ children }) => {
return (
<html>
<head>
<title>Bookmarklets</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css" />
<link rel="icon" href="https://fav.farm/🔖" />
</head>
<body>
<main class="container">
{children}
</main>
</body>
</html>
);
}),
);
const root = extractValInfo(import.meta.url);
app.get("/", async c => {
const { data: vals } = await api(`/v1/search/vals?query=${encodeURIComponent("#bookmarklet")}`);
const bookmarklets = await Promise.all(
vals.filter(
val => val.author.username != root.author || val.name != root.name,
).map(async val => {
try {
const url = await bookmarkletUrl(val.author.username, val.name);
return { val, url };
} catch (error) {
console.error(error);
return { val, error };
}
}),
);
return c.render(
<>
<h1>Bookmarklets</h1>
<table>
<thead>
<th scope="col">Bookmarklet</th>
<th scope="col">Val</th>
</thead>
<tbody>
{bookmarklets.map(({ val, url: bookmarkletUrl }) => {
const bookmarkletVal = {
label: `@${val.author.username}/${val.name}`,
url: new URL(`https://val.town/v/${val.author.username}/${val.name}`).href,
};
return (
<tr>
<td>
<a href={bookmarkletUrl}>{bookmarkletVal.label}</a>
</td>
<td>
<a href={bookmarkletVal.url}>View Val</a>
</td>
</tr>
);
})}
</tbody>
</table>
<a href={root.htmlUrl}>Add your bookmarklet to this list</a>
</>,
);
});
app.get("/v/:author/:name", async c => {
const { author, name } = c.req.param();
const { privacy } = await api(`/v1/alias/${author}/${name}`);
if (privacy === "private") {
return c.notFound();
}
const label = `@${author}/${name}`;
const url = await bookmarkletUrl(author, name);
return c.render(
<a href={url}>{label}</a>,
);
});
export default app.fetch;
vladimyr-bookmarklets.web.val.run
March 8, 2024