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
11const MAX_SELECTIONS = 2;
12
13function labelPredicate(label) {
14 return label === "Father" || label === "Mother" || /^Parent/.test(label);
15}
16
17async function* crawlWikipedia(
18 url: string,
19 generation: number = 0,
50}
51
52function App() {
53 const [url, setUrl] = useState("");
54 const [nodes, setNodes] = useState([]);
139 });
140
141 cyRef.current.on("tap", "node", function(evt) {
142 if (isCytoscapeDisabled) return;
143 const node = evt.target;
163 });
164
165 cyRef.current.on("layoutstop", function() {
166 cyRef.current.center();
167 cyRef.current.fit();
378}
379
380function client() {
381 createRoot(document.getElementById("root")).render(<App />);
382}
386}
387
388async function server(req: Request): Promise<Response> {
389 const url = new URL(req.url);
390
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
1// This approach uses the Lucia authentication library with a custom ValTownAdapter.
2// It provides signup, login, and logout functionality with session management.
3// The main tradeoff is the complexity of setting up Lucia, but it offers robust auth features.
4
34}
35
36// Helper function for redirects
37function redirect(url: string, status = 302): Response {
38 return new Response(null, {
39 status,
127}
128
129function transformIntoDatabaseSession(raw: SessionSchema): DatabaseSession {
130 const { id, user_id: userId, expires_at: expiresAtUnix, ...attributes } = raw;
131 return {
137}
138
139function transformIntoDatabaseUser(raw: UserSchema): DatabaseUser {
140 const { id, ...attributes } = raw;
141 return {
145}
146
147function escapeName(val: string): string {
148 return "`" + val + "`";
149}
3import { email } from "https://esm.town/v/std/email";
4
5async function fetchStories(type: string, count: number) {
6 const response = await fetch(`https://hacker-news.firebaseio.com/v0/${type}stories.json`);
7 const storyIds = await response.json();
15}
16
17function createStoryHTML(story: any) {
18 return `
19 <li>
28}
29
30function createEmailContent(
31 topStories: any[],
32 newStories: any[],
118}
119
120export default async function server(req: Request) {
121 try {
122 const topStories = await fetchStories("top", 20);
44}
45
46function parseCsv(csv: string): TaxBracket[] {
47 const lines = csv.trim().split("\n");
48 const headers = lines.shift()?.split(",");
59}
60
61function calculateTax(
62 income: number,
63 filingStatus: string,
91};
92
93function generateHtml(taxBrackets: TaxBracket[], selectedFilingStatus: string): string {
94 let tableRows = "";
95 for (let income = 0; income <= 1000000; income += 1000) {
147}
148
149export default async function main(req: Request): Promise<Response> {
150 const taxBrackets = parseCsv(csvData);
151 const url = new URL(req.url);
19import { renderToString } from "npm:react-dom/server";
20
21function printItinerary() {
22 const rows = itinerary.trim().split("\n").map(row => row.split(","));
23 const headers = rows[0];
99};
100
101function Header() {
102 return <h1>Travel App</h1>;
103}
104
105function App() {
106 const sampleDay: TravelDay = {
107 date: "2023-07-15",
127}
128
129function client() {
130 createRoot(document.getElementById("root")).render(<App />);
131}
135}
136
137async function server(request: Request) {
138 return (new Response(
139 `<html>
19import React from "https://esm.sh/react@18.2.0";
20
21function App() {
22 const mapRef = React.useRef(null);
23 const [map, setMap] = React.useState(null);
259}
260
261function client() {
262 ReactDOM.createRoot(document.getElementById("root")).render(React.createElement(App));
263}
267}
268
269export default async function server(request: Request): Promise<Response> {
270 const url = new URL(request.url);
271
10const TITLE_SELECTOR = "#firstHeading > span";
11
12function labelPredicate(label) {
13 return label === "Father" || label === "Mother" || /^Parent/.test(label) || label === "Children" || /^Child/.test(label);
14}
15
16async function* crawlWikipedia(
17 url: string,
18 generation: number = 0,
60}
61
62function App() {
63 const [url, setUrl] = useState("");
64 const [nodes, setNodes] = useState([]);
148 });
149
150 cyRef.current.on("tap", "node", function(evt) {
151 if (isCytoscapeDisabled) return;
152 const node = evt.target;
154 });
155
156 cyRef.current.on("layoutstop", function() {
157 cyRef.current.center();
158 cyRef.current.fit();
255}
256
257function client() {
258 createRoot(document.getElementById("root")).render(<App />);
259}
263}
264
265async function server(req: Request): Promise<Response> {
266 const url = new URL(req.url);
267