12const GRID_SIZE = 8;
13
14function App() {
15 const [audioEnabled, setAudioEnabled] = useState(false);
16 const [audioState, setAudioState] = useState("Initializing");
248}
249
250function client() {
251 createRoot(document.getElementById("root")).render(<App />);
252}
253if (typeof document !== "undefined") { client(); }
254
255export default async function server(request: Request): Promise<Response> {
256 return new Response(
257 `
25];
26
27function App() {
28 const [audioEnabled, setAudioEnabled] = useState(false);
29 const [timeline, setTimeline] = useState([]);
230}
231
232function client() {
233 createRoot(document.getElementById("root")).render(<App />);
234}
235if (typeof document !== "undefined") { client(); }
236
237export default async function server(request: Request): Promise<Response> {
238 return new Response(
239 `
17];
18
19function App() {
20 const [username, setUsername] = useState("stevekrouse");
21 const [contributionData, setContributionData] = useState(null);
323}
324
325function client() {
326 createRoot(document.getElementById("root")).render(<App />);
327}
328if (typeof document !== "undefined") { client(); }
329
330export default async function server(request: Request): Promise<Response> {
331 if (request.method === "POST" && new URL(request.url).pathname === "/contributions") {
332 const { username } = await request.json();
359}
360
361async function fetchGitHubContributions(username: string) {
362 const query = `
363 query($username: String!) {
8import _ from "npm:lodash@4";
9
10async function main(req: Request): Promise<Response> {
11 const { readable, writable } = new TransformStream();
12 const writer = writable.getWriter();
20 <script>
21 // Scroll to the bottom of the page when the page changes.
22 (new MutationObserver(function (mutationsList, observer) {
23 window.scrollTo({ left: 0, top: document.body.scrollHeight, behavior: "instant" });
24 })).observe(document, { childList: true, characterData: true, subtree: true });
47 Your response should start with \`\`\`ts and end with \`\`\`, so full code fences.
48 There should be no comments like "more content here", it should be complete and directly runnable.
49 The val should have an "export default async function main". The val should return a valid HTML website.
50 Prefer using Tailwind. Put frontend functions in a <script> tag, using dangerouslySetInnerHTML. Don't use Hono. Don't use Response.redirect.
51 `.replace("\n", " "),
52 },
6};
7
8export default async function(req: Request): Promise<Response> {
9 let key = new URL(req.url).pathname;
10 let url = await blob.getJSON(genKey(key));
5import { renderToString } from "npm:react-dom/server";
6
7function StatusRow({ rows }: { rows: any[] }) {
8 return (
9 <div className="w-full flex flex-col space-y-2">
28}
29
30function StatusSection({ url, rows }) {
31 const sectionRows = rows.filter(row => row[0] === url);
32 const percentUp = Math.round((sectionRows.filter(row => row[1]).length / sectionRows.length) * 100);
44}
45
46export default async function(req: Request): Promise<Response> {
47 const { rows } = await sqlite.execute(
48 "select url, ok, duration, timestamp from uptime order by timestamp desc limit 200",
1export function extractValInfo(url: string | URL) {
2 const { pathname, search } = new URL(url);
3 const [author, filename] = pathname.split("/").slice(-2);
42const urnIcon = "⚱️";
43
44function App() {
45 const [tributeCount, setTributeCount] = useState(0);
46 const [eulogyMessage, setEulogyMessage] = useState("");
113 const end = Date.now() + (5 * 1000);
114
115 (function frame() {
116 confetti({
117 particleCount: 20,
143 const defaults = { startVelocity: 15, spread: 360, ticks: 60, zIndex: 0 };
144
145 function randomInRange(min: number, max: number) {
146 return Math.random() * (max - min) + min;
147 }
148
149 const interval = setInterval(function() {
150 const timeLeft = animationEnd - Date.now();
151
176 const animationEnd = Date.now() + duration;
177
178 function randomInRange(min: number, max: number) {
179 return Math.random() * (max - min) + min;
180 }
181
182 (function frame() {
183 const timeLeft = animationEnd - Date.now();
184
211 };
212
213 function fire(particleRatio: number, opts: any) {
214 confetti(Object.assign({}, defaults, opts, {
215 particleCount: Math.floor(count * particleRatio),
253 const smokeColors = ["#a0a0a0", "#b0b0b0", "#c0c0c0", "#d0d0d0"];
254
255 function randomInRange(min: number, max: number) {
256 return Math.random() * (max - min) + min;
257 }
258
259 (function frame() {
260 const timeLeft = animationEnd - Date.now();
261
482}
483
484function client() {
485 createRoot(document.getElementById("root")).render(<App />);
486}
488if (typeof document !== "undefined") { client(); }
489
490export default async function server(request: Request): Promise<Response> {
491 return new Response(
492 `
29];
30
31function App() {
32 const [clickCount, setClickCount] = useState(0);
33 const [splashMessage, setSplashMessage] = useState("");
89 const end = Date.now() + (5 * 1000);
90
91 (function frame() {
92 confetti({
93 particleCount: 50,
117 const defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 0 };
118
119 function randomInRange(min: number, max: number) {
120 return Math.random() * (max - min) + min;
121 }
122
123 const interval = setInterval(function() {
124 const timeLeft = animationEnd - Date.now();
125
150 const animationEnd = Date.now() + duration;
151
152 function randomInRange(min: number, max: number) {
153 return Math.random() * (max - min) + min;
154 }
155
156 (function frame() {
157 const timeLeft = animationEnd - Date.now();
158
186 };
187
188 function fire(particleRatio: number, opts: any) {
189 confetti(Object.assign({}, defaults, opts, {
190 particleCount: Math.floor(count * particleRatio),
440}
441
442function client() {
443 createRoot(document.getElementById("root")).render(<App />);
444}
446if (typeof document !== "undefined") { client(); }
447
448export default async function server(request: Request): Promise<Response> {
449 return new Response(
450 `
33- [x] fix wonky sidebar separator height problem (thanks to @stevekrouse)
34- [x] make result tables scrollable
35- [x] add export to CSV, and JSON (CSV and JSON helper functions written in [this val](https://www.val.town/v/nbbaier/sqliteExportHelpers). Thanks to @pomdtr for merging the initial version!)
36- [x] add listener for cmd+enter to submit query