Newest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/** @jsxImportSource https://esm.sh/hono/jsx */
import { HTTPException } from "https://deno.land/x/hono@v4.0.7/http-exception.ts";
import { type FC } from "https://deno.land/x/hono@v4.0.7/jsx/index.ts";
import type { Context } from "https://deno.land/x/hono@v4.0.7/mod.ts";
import { html } from "https://esm.town/v/stevekrouse/html";
type Handler =
| ((ctx: Context) => Response | Promise<Response>)
| ((ctx: Context) => JSX.Element | Promise<JSX.Element>);
export function createRoute(handler: Handler) {
return async (ctx: Context) => {
const res = await handler(ctx);
if (res instanceof Response) {
return res;
}
return ctx.render(res);
};
}
Fork
1
2
3
4
import { modifyFetchHandler } from "https://esm.town/v/andreterron/codeOnValTown?v=45";
import dateme from "https://esm.town/v/stevekrouse/dateme";
export default modifyFetchHandler(dateme);
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
/** @jsxImportSource https://esm.sh/react */
const tabs = { "/home": "Home", "/browse": "Browse", "/faq": "FAQ" };
export default function({ activeTab, children }) {
return (
<html>
<head>
<title>Date Me Directory</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="https://cdn.tailwindcss.com" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/quicklink/2.3.0/quicklink.umd.js"></script>
<script
dangerouslySetInnerHTML={{
__html: `window.addEventListener('load', () => {
quicklink.listen();
});`,
}}
>
</script>
</head>
<body>
<div className="p-4 gap-x-4 flex items-center">
{Object.entries(tabs).map(([link, title]) => (
<a
href={link}
key={link}
className={`${activeTab === link ? "" : "text-gray-400 hover:text-gray-500"}`}
>
{title === "Home" ? <div className="font-bold text-black">Date Me Directory</div> : title}
</a>
))}
<a
href="https://noteforms.com/forms/submit-your-date-me-profile"
className="px-2 py-1 border-blue-500 text-blue-500 border border-2 hover:bg-blue-100 rounded-md font-bold rounded ml-4"
>
Submit <span className="hidden md:inline">your doc</span>
</a>
</div>
{children}
</body>
</html>
);
}
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
/** @jsxImportSource https://esm.sh/react */
import { Action, handler } from "https://esm.town/v/pomdtr/ssr";
import { sqlite } from "https://esm.town/v/std/sqlite?v=4";
import Layout from "https://esm.town/v/stevekrouse/dateme_layout";
import { zip } from "npm:lodash-es";
export const action: Action = async (req: Request, ctx) => {
const url = new URL(req.url);
const search = url.searchParams;
let { columns, rows } = await sqlite.execute({
sql: `select * from datemedocs
where
Location like ?
and Age >= ?
and Age <= ?
and Gender like ?
and InterestedIn like ?
`,
args: [
"%" + (search.get("location") ?? "") + "%",
search.get("min-age") ?? 0,
search.get("max-age") ?? 100,
"%" + (search.get("desired-gender") ?? "") + "%",
"%" + (search.get("gender") ?? "") + "%",
],
});
const profiles = rows.map(row =>
Object.fromEntries(zip(
columns,
row.map(d => {
try {
return JSON.parse(d);
} catch (_) {
return d;
}
}),
))
);
return ctx.render({
search: {
gender: search.get("gender"),
desiredGender: search.get("desired-gender"),
minAge: search.get("min-age") ?? 0,
maxAge: search.get("max-age") ?? 100,
location: search.get("location"),
},
profiles,
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
/** @jsxImportSource https://esm.sh/react */
import { handler } from "https://esm.town/v/pomdtr/ssr";
import date_me_doc_locations from "https://esm.town/v/stevekrouse/date_me_doc_locations";
import Layout from "https://esm.town/v/stevekrouse/dateme_layout";
export function Home(props) {
return (
<Layout activeTab={props.route}>
<div className="max-w-lg mx-auto p-10">
<div className="mb-10">
<div className="text-4xl font-bold mb-4">
Date thoughtfully
</div>
<div className="text-lg ">
Date Me Docs are long-form, earnest dating profiles for romantic partners.
</div>
</div>
<form className="space-y-4" action="/browse">
<div className="flex text-xl space-x-2">
<div>I'm</div>
<select name="gender" className="border border-gray-300">
<option value="" className="text-gray-500">...</option>
<option value="m">male</option>
<option value="f">female</option>
<option value="nb">non-binary</option>
</select>
</div>
<div className="flex text-xl space-x-2">
<div>Looking for</div>
<select name="desired-gender" className="border border-gray-300">
<option value="">...</option>
<option value="m">male</option>
<option value="f">female</option>
<option value="nb">non-binary</option>
</select>
</div>
<div className="flex text-xl space-x-2">
<div>Between</div>
<input defaultValue={18} type="number" name="min-age" className="w-12 h-min border border-gray-300"></input>
<div>and</div>
<input defaultValue={70} type="number" name="max-age" className="w-12 border border-gray-300"></input>
<div>years old</div>
</div>
<div className="flex text-xl space-x-2">
<div>In</div>
<select name="location" className="border border-gray-300">
<option value="">...</option>
{date_me_doc_locations.map(
(location) => <option key={location} value={location}>{location}</option>,

"Code on Val Town" Response modifier

Appends the "Code on Val Town" ribbon to an HTTP Response.

Usage

  • new modifyResponse(res, { handle: "andre", name: "foo" }) - define which val to link to;
  • new modifyResponse(res) - infer the val from the call stack.

Example: @andreterron/openable_res

import { modifyResponse } from "https://esm.town/v/andreterron/codeOnVT_modifyResponse";
import { html } from "https://esm.town/v/stevekrouse/html?v=5";

export default async (req: Request): Promise<Response> => {
  return modifyResponse(html(`
    <h2>Hello world!</h2>
    <style>* { font-family: sans-serif }</style>
  `));
};
Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { InjectCodeOnValTownStream } from "https://esm.town/v/andreterron/InjectCodeOnValTownStream";
import { ValRef } from "https://esm.town/v/andreterron/ValRef";
/**
* @param res Response
* @param val Define which val should open. Defaults to the root reference.
*/
export function modifyResponse(
res: Response,
val?: ValRef,
) {
if (res.headers.get("Content-Type") !== "text/html") {
return res;
}
return new Response(
res.body
.pipeThrough(new TextDecoderStream())
.pipeThrough(new InjectCodeOnValTownStream(val))
.pipeThrough(new TextEncoderStream()),
res,
);
}

Injects the "Code on Val Town" ribbon on an HTML string stream

Usage

  • new InjectCodeOnValTownStream({ handle: "andre", name: "foo" }) - define which val to link to;
  • new InjectCodeOnValTownStream() - infer the val from the call stack.

Example: @andreterron/openable_stream

import { InjectCodeOnValTownStream } from "https://esm.town/v/andreterron/InjectCodeOnValTownStream";
import { blob } from "https://esm.town/v/std/blob?v=11";
import { html } from "https://esm.town/v/stevekrouse/html?v=5";

export default async (req: Request): Promise<Response> => {
  await blob.set(
    "openable_test",
    `<h2>Hello world!</h2>
    <style>* { font-family: sans-serif }</style>`,
  );

  const value = await blob.get("openable_test");

  return html(
    value.body
      .pipeThrough(new TextDecoderStream())
      .pipeThrough(new InjectCodeOnValTownStream())
      .pipeThrough(new TextEncoderStream()),
  );
};
Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { ribbonElement } from "https://esm.town/v/andreterron/codeOnVT_ribbonElement";
import { InjectHTMLElementStream } from "https://esm.town/v/andreterron/InjectHTMLElementStream";
import { rootValRef } from "https://esm.town/v/andreterron/rootValRef";
import { ValRef } from "https://esm.town/v/andreterron/ValRef";
/**
* @param val Define which val should open. Defaults to the root reference.
*/
export class InjectCodeOnValTownStream extends InjectHTMLElementStream {
constructor(val?: ValRef) {
const valRef = val?.handle && val?.name ? val : rootValRef();
const element = valRef ? ribbonElement(valRef) : "";
super(element);
}
}

"Code on Val Town" Ribbon HTML Element

Ribbon element used by @andreterron/codeOnValTown

Usage

  • ribbonElement({ handle: "andre", name: "foo" }) - define which val to link to;
  • ribbonElement() - infer the val from the call stack.

Example: @andreterron/openable_element

import { ribbonElement } from "https://esm.town/v/andreterron/codeOnVT_ribbonElement";
import { html } from "https://esm.town/v/stevekrouse/html?v=5";

export default async (req: Request): Promise<Response> => {
  return html(`
    <h2>Hello world!</h2>
    <style>* { font-family: sans-serif }</style>
    ${ribbonElement()}
  `);
};
Readme
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
import { rootValRef } from "https://esm.town/v/andreterron/rootValRef";
import { ValRef } from "https://esm.town/v/andreterron/ValRef";
export function ribbonElement(val?: ValRef) {
const valRef = val?.handle && val?.name ? val : rootValRef();
if (!valRef) {
console.error("Failed to infer val. Please set the val parameter to the desired `{ handle, name }`");
return "";
}
const valSlug = `${valRef.handle}/${valRef.name}`;
return `
<div id="code-on-vt-host">
<template shadowrootmode="open">
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/github-fork-ribbon-css/0.2.3/gh-fork-ribbon.min.css"
/>
<style>
@media (max-width: 768px) {
.github-fork-ribbon {
display: none !important;
}
}
</style>
<a
href="https://www.val.town/v/${valSlug}"
target="_blank"
class="github-fork-ribbon"
data-ribbon="Code on Val Town"
title="Code on Val Town"
>
Code on Val Town
</a>
</template>
</div>`;
}
1
2
3
4
5
6
7
8
9
10
11
12
import { rootRef } from "https://esm.town/v/andreterron/rootRef";
import { ValRef } from "https://esm.town/v/andreterron/ValRef";
export function rootValRef(): ValRef | undefined {
const val = rootRef();
return val
? {
handle: val.userHandle,
name: val.valName,
}
: undefined;
}
1
2
3
4
export interface ValRef {
handle: string;
name: string;
}