Back to packages list

Vals using react-dom/server

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
/** @jsxImportSource https://esm.sh/react */
import { renderToString } from "npm:react-dom/server";
export default async function(req: Request) {
return new Response(
renderToString(
<html>
<head>
<meta charSet="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tahir's TIL</title>
</head>
<body
style={{ padding: "30px", width: "300px", margin: "0 auto", fontFamily: "sans-serif", textAlign: "center" }}
>
<script>
console.log('This will run when the page loads');
// Other inline scripts here
</script>
<h1>Tahir's TIL</h1>
<p>Web, design and data tips</p>
<div style={{ display: "flex", flexDirection: "column", gap: "15px" }}>
<a href="https://ourworldindata.org/electric-car-sales" style={itemStyle}>
Over 90% of new cars are electric in Norway + Our World in Data make beautiful charts
</a>
<a
href="https://webkit.org/blog/15131/speedometer-3-0-the-best-way-yet-to-measure-browser-performance/"
style={itemStyle}
>
Speedometer 3.0 - Browser Performance benchmarks by Apple, Google, Mozilla and Microsoft. Includes 4
charting libraries
</a>
<a href="https://www.typewolf.com/site-of-the-day/" style={itemStyle}>
Typewolf Site of the Day. Inspiration for font pairings
</a>
<a href="https://deadsimplesites.com/" style={itemStyle}>DSS Dead Simple Sites.</a>
<a href="https://www.csscade.com/" style={itemStyle}>CSS is awesome - CSSCade</a>
<a href="https://djr.com/job-clarendon" style={itemStyle}>
Job Clarendon is a stunning typeface that pays homage to job printing
</a>
<a href="https://courses.nan.fyi/login" style={itemStyle}>Interactive SVG Animations Course</a>
<a href="https://htmx.org/examples/active-search/" style={itemStyle}>HTMX Active Search</a>
<a href="https://www.bram.us/2024/02/18/custom-highlight-api-for-syntax-highlighting/" style={itemStyle}>
Search and highlight text
</a>
<a href="https://www.bram.us/2024/02/18/custom-highlight-api-for-syntax-highlighting/" style={itemStyle}>
Custom highlight API - Display style and script blocks
</a>
<a href="https://docs.val.town/quickstarts/first-website/" style={itemStyle}>
Building websites with Val.town is fast
</a>
<p>Notes: Asking ChatGPT to explain code is a great and fun way to learn</p>
</div>
</body>
</html>,
),
{
headers: {
"Content-Type": "text/html",
},
},
);
}
const itemStyle = {
padding: "10px",
color: "#222",
// backgroundColor: "#ff748d",
backgroundColor: "rgba(0, 0, 0, 0.02)",
borderRadius: "2px",
textDecoration: "none",
// boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)",
};
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
100
/** @jsxImportSource https://esm.sh/react */
import { renderToString } from "npm:react-dom/server";
export default async function(req: Request) {
return new Response(
renderToString(
<html>
<head>
<meta charSet="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tahir's TIL</title>
</head>
<body
style={{
maxWidth: "70ch",
padding: "3em 1em",
margin: "auto",
lineHeight: "1.75",
fontSize: "1.25em",
fontFamily: "sans-serif",
}}
>
<h1>Tahir's TIL</h1>
<h3>Design, Web and Data Things</h3>
<div style={{ display: "flex", flexDirection: "column", gap: "15px" }}>
<a href="https://github.com/Little-Languages/quiver" style={itemStyle}>
declarative arrows for the web. ⤵
</a>
<a href="https://github.com/steveruizok/perfect-arrows" style={itemStyle}>
Draw perfect arrows between points and shapes. By the the creator of tldraw.
</a>
<a href="https://news.ycombinator.com/item?id=32972004" style={itemStyle}>
58 bytes of CSS to look great nearly everywhere
</a>
<a href="https://maxbo.me/a-html-file-is-all-you-need" style={itemStyle}>
A HTML file is all you need. Lot's of useful client side JavaScript examples including charts, Python and
SQLite.
</a>
<a href="https://developer.mozilla.org/en-US/blog/color-palettes-css-color-mix/" style={itemStyle}>
color-mix() allows you to mix colours in CSS using 3 colour spaces: srgb, oklab or hsl
</a>
<a href="https://www.val.town/v/tfayyaz/honoJsDialogShowModal" style={itemStyle}>
val.town demo - Hono JS Dialog Show Modal
</a>
<a href="https://www.val.town/v/tfayyaz/honoJsInClientTemplate" style={itemStyle}>
Simple Hono JS val.town Template with client side JavaScript using html Helper
</a>
<a href="https://ourworldindata.org/electric-car-sales" style={itemStyle}>
Over 90% of new cars are electric in Norway + Our World in Data make beautiful charts
</a>
<a
href="https://webkit.org/blog/15131/speedometer-3-0-the-best-way-yet-to-measure-browser-performance/"
style={itemStyle}
>
Speedometer 3.0 - Browser Performance benchmarks by Apple, Google, Mozilla and Microsoft. Includes 4
charting libraries
</a>
<a href="https://www.typewolf.com/site-of-the-day/" style={itemStyle}>
Typewolf Site of the Day. Inspiration for font pairings
</a>
<a href="https://deadsimplesites.com/" style={itemStyle}>DSS Dead Simple Sites.</a>
<a href="https://www.csscade.com/" style={itemStyle}>CSS is awesome - CSSCade</a>
<a href="https://djr.com/job-clarendon" style={itemStyle}>
Job Clarendon is a stunning typeface that pays homage to job printing
</a>
<a href="https://courses.nan.fyi/login" style={itemStyle}>Interactive SVG Animations Course</a>
<a href="https://htmx.org/examples/active-search/" style={itemStyle}>HTMX Active Search</a>
<a href="https://www.bram.us/2024/02/18/custom-highlight-api-for-syntax-highlighting/" style={itemStyle}>
Search and highlight text
</a>
<a href="https://www.bram.us/2024/02/18/custom-highlight-api-for-syntax-highlighting/" style={itemStyle}>
Custom highlight API - Display style and script blocks
</a>
<a href="https://docs.val.town/quickstarts/first-website/" style={itemStyle}>
Building websites with Val.town is fast
</a>
<p>Notes: Asking ChatGPT to explain code is a great and fun way to learn</p>
</div>
</body>
</html>,
),
{
headers: {
"Content-Type": "text/html",
},
},
);
}
const itemStyle = {
padding: "10px",
color: "#222",
// backgroundColor: "#ff748d",
backgroundColor: "rgba(0, 0, 0, 0.02)",
background: "colorMix(in srgb, blue, white 80%)",
borderTop: "2px solid rgba(0, 0, 0, 0.20)",
borderRadius: "2px",
textDecoration: "none",
// boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)",
};
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
/** @jsxImportSource https://esm.sh/react */
import { renderToString } from "npm:react-dom/server";
export default async function(req: Request) {
return new Response(
renderToString(
<html>
<head>
<meta charSet="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Joe Schmo</title>
</head>
<body
style={{ padding: "30px", width: "300px", margin: "0 auto", fontFamily: "sans-serif", textAlign: "center" }}
>
<h1>Joe Schmo</h1>
<p>Just an average Joe</p>
<div style={{ display: "flex", flexDirection: "column", gap: "15px" }}>
<a href="https://www.instagram.com/joeschmo" style={itemStyle}>Instagram</a>
<a href="https://github.com/joeschmo" style={itemStyle}>Github</a>
<a href="https://www.linkedin.com/in/joeschmo" style={itemStyle}>LinkedIn</a>
<a href="https://twitter.com/joeschmo" style={itemStyle}>Twitter</a>
<a href="https://www.youtube.com/joeschmo" style={itemStyle}>YouTube</a>
</div>
</body>
</html>,
),
{
headers: {
"Content-Type": "text/html",
},
},
);
}
const itemStyle = {
padding: "10px",
color: "white",
backgroundColor: "#ff748d",
borderRadius: "20px",
textDecoration: "none",
boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)",
};
1
2
3
4
5
6
7
8
9
/** @jsxImportSource https://esm.sh/react */
import { renderToString } from "npm:react-dom/server";
export const reactExample = () =>
new Response(renderToString(<div>Test {1 + 1}</div>), {
headers: {
"Content-Type": "text/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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/** @jsxImportSource https://esm.sh/react */
import { renderToString } from "npm:react-dom/server";
export const personalWebsite = (request: Request) => {
return new Response(
renderToString(
<html>
<head>
<title>Will Krouse</title>
<style
dangerouslySetInnerHTML={{
__html:
`:root{--slate1: hsl(200, 7%, 8.8%);--slate2: hsl(195, 7.1%, 11%);--slate3: hsl(197, 6.8%, 13.6%);--slate4: hsl(198, 6.6%, 15.8%);--slate5: hsl(199, 6.4%, 17.9%);--slate6: hsl(201, 6.2%, 20.5%);--slate7: hsl(203, 6%, 24.3%);--slate8: hsl(20
}}
>
</style>
</head>
<body>
<h1>Will Krouse</h1>
<a href="https://twitter.com/Willthereader" target="_blank">Twitter</a>{" "}
<a href="https://github.com/wkrouse" target="_blank">Github</a>
<p>
Hi, I'm Will, a 24-year-old autistic individual in Florida. I love reading, playing board games, tennis, and
pickleball.
</p>
<p>
I'm learning to code. My favorite part are the meta-skills. For example, the debugging mindset is always
useful for fixing problems.
</p>
<p>
I find the complexity of current events and politics really interesting. I enjoy articles that significantly
change my understanding. I really like{" "}
<a className="text-blue-500 hover:underline" href="https://www.readtangle.com">Tangle</a>{" "}
because it offers perspectives from all sides. I dislike when people assume the worst of their opponents and
when I can't tell who's right because no one addresses the best arguments from their opponents.
</p>
<p>
I am on the autism spectrum, so I sometimes misunderstand people's tones and vibes or send the wrong ones.
Your patience and feedback are appreciated!
</p>
<p>
I built{" "}
<a className="text-blue-500 hover:underline" href="https://www.val.town/v/willthereader/personalWebsite">
this site
</a>{" "}
on Val Town .
</p>
<h2>Projects</h2>
<div>
<div>
3/6/2024 -{" "}
<a href="https://news.ycombinator.com/item?id=39618062">
Bringing My OCD Online: Userscripts for Immersive Forum Browsing
</a>
</div>
</div>
</body>
</html>,
),
{
headers: { "Content-Type": "text/html" },
},
);
};

stevekrouse.com - my personal website

This val hosts my personal website. The view data is stored in Val Town SQLite - @std/sqlite.

It used to live on Github Pages, which is why I proxy over requests to certain blog posts over to the Github Pages site still.

Todos

  • Speed up page load by loading sqlite data later like in @healeycodes/steve_web
  • Store more (legally storable) analytics data, and maybe make a sparkline!
  • Add some sort of way to contact me
  • Move over all my blog posts from Github Pages (maybe into @std/blob as a CMS?)
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
100
/** @jsxImportSource https://esm.sh/react */
import { email } from "https://esm.town/v/std/email?v=11";
import { sqlite } from "https://esm.town/v/std/sqlite?v=5";
import { ReloadScriptReactElement } from "https://esm.town/v/stevekrouse/ReloadScript";
import tailwindURL from "https://esm.town/v/stevekrouse/tailwindURL";
import { renderToString } from "npm:react-dom/server";
const linkClass = "text-blue-500 hover:underline";
const Link = (
{ children, href }: {
children?: React.ReactNode;
href: string;
},
) => <a className={linkClass} href={href}>{children}</a>;
const dateClass = "text-xs text-gray-400 font-mono mr-1 hidden sm:inline-block";
async function getHits() {
const [, , { rows: [[allHits]] }, { rows: [[todayHits]] }] = await sqlite.batch([
"CREATE TABLE IF NOT EXISTS stevekrouse_com_hits (timestamp DATETIME DEFAULT CURRENT_TIMESTAMP)",
"INSERT INTO stevekrouse_com_hits DEFAULT VALUES",
"SELECT COUNT(*) FROM stevekrouse_com_hits where timestamp > datetime('now', '-28 day')",
"SELECT COUNT(*) from stevekrouse_com_hits where timestamp > datetime('now', '-1 day')",
]);
if (allHits % 100 === 0) email({ subject: `You got ${todayHits} hits today! (${allHits} total)` });
return { allHits, todayHits };
}
export default async (request: Request) => {
const url = new URL(request.url);
console.log(url);
if (url.pathname === "/favicon.ico") return new Response(null, { status: 404 });
if (url.pathname !== "/")
return fetch(
`https://stevekrouse.github.io/${url.pathname}${url.search}`,
request as any as RequestInit,
);
const { allHits, todayHits } = await getHits();
return new Response(
renderToString(
<html>
<head>
<title>Steve Krouse</title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<script src={tailwindURL} />
{url.searchParams.get("dev")
? <ReloadScriptReactElement vals={[{ valName: "dot_com", userHandle: "stevekrouse" }]} />
: null}
</head>
<body>
<div className="max-w-3xl p-10 space-y-4 mx-auto">
<h1 className="text-orange-600 text-2xl font-medium">Steve Krouse</h1>
<div>
👋 Hi, I'm Steve. I live in Prospect Heights, Brooklyn.
</div>
<div>
I build <Link href="https://val.town">Val Town</Link>, a social website to code in the cloud.
</div>
<div>
This site was{" "}
<Link href="https://www.val.town/v/stevekrouse/dot_com">built in Val Town</Link>. It was viewed{" "}
{todayHits} times today, and {allHits} times this month.
</div>
<div>
<h2 className="text-xl mb-1">Projects</h2>
<ul>
<li className="pb-2 sm:pb-1">
<span className={dateClass}>2022 Jul -</span>
<Link href="https://val.town">Val Town</Link>
</li>
<li className="pb-2 sm:pb-1">
<span className={dateClass}>2022 Sep -</span>
<Link href="https://dateme.directory">Date Me Directory</Link>
</li>
<li className="pb-2 sm:pb-1">
<span className={dateClass}>2022 Jan -</span>
<Link href="https://twitter.com/stevekrouse/status/1520162279899078657">Zaplib</Link>
</li>
<li className="pb-2 sm:pb-1">
<span className={dateClass}>2021 Mar -</span>
<Link href="http://updates.compose.run">Compose</Link>
</li>
<li className="pb-2 sm:pb-1">
<span className={dateClass}>2017 Jul -</span>
<Link href="https://futureofcoding.org/">Future of Coding</Link>
</li>
<li className="pb-2 sm:pb-1">
<span className={dateClass}>2016 May -</span>
<Link href="https://github.com/stevekrouse/woofjs">WoofJS</Link>
</li>
<li className="pb-2 sm:pb-1">
<span className={dateClass}>2015 Sep -</span>
<Link href="http://coding.space">The Coding Space Curriculum</Link>
</li>
<li className="pb-2 sm:pb-1">
<span className={dateClass}>2015 Jul -</span>
<Link href="http://thecodingspace.com">The Coding Space</Link>
</li>
<li className="pb-2 sm:pb-1">
<span className={dateClass}>2014 Jan -</span>Software Engineer @{" "}
<Link href="https://looker.com/">Looker</Link>
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
/** @jsxImportSource https://esm.sh/react */
import { renderToString } from "npm:react-dom/server";
export const personalWebsite = (request: Request) => {
return new Response(
renderToString(
<html>
<head>
<title>Will Krouse</title>
<style
dangerouslySetInnerHTML={{
__html:
`:root{--slate1: hsl(200, 7%, 8.8%);--slate2: hsl(195, 7.1%, 11%);--slate3: hsl(197, 6.8%, 13.6%);--slate4: hsl(198, 6.6%, 15.8%);--slate5: hsl(199, 6.4%, 17.9%);--slate6: hsl(201, 6.2%, 20.5%);--slate7: hsl(203, 6%, 24.3%);--slate8: hsl(20
}}
>
</style>
</head>
<body>
<h1>Will Krouse</h1>
<p>
Hi, I'm Will. I'm 24 and autistic. I live in Boca Raton. I love reading. I like playing board games, card
games, tennis, and pickleball.
</p>
<p>
I'm learning how to program. My favorite part about programming are the valuable meta skills I learn along
the way. For example, I'm finding the debugging mindset to fix code is useful for fixing problems in
general.
</p>
<h1>Projects</h1>
<ul>
<li>
<a href="https://news.ycombinator.com/item?id=39618062">
Bringing My OCD Online: Userscripts for Immersive Forum Browsing
</a>
</li>
</ul>
</body>
</html>,
),
{
headers: { "Content-Type": "text/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
/** @jsxImportSource https://esm.sh/react */
import { renderToString } from "npm:react-dom/server";
function HelloWorld() {
return (
<h1 className="text-3xl font-bold underline">
Hello world! Cleaned up, w/ props
</h1>
);
}
function Html({ content }) {
return (
<>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<main>
{content}
</main>
</body>
</>
);
}
function reactExample(request: Request) {
const renderedString = renderToString(<Html content={<HelloWorld />} />);
const response = new Response(renderedString, {
headers: {
"Content-Type": "text/html",
},
});
return response;
}
export default reactExample;
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
/** @jsxImportSource https://esm.sh/react */
import { renderToString } from "npm:react-dom/server";
export const personalWebsite = (request: Request) => {
return new Response(
renderToString(
<html>
<head>
<title>Will Krouse</title>
<style
dangerouslySetInnerHTML={{
__html:
`:root{--slate1: hsl(200, 7%, 8.8%);--slate2: hsl(195, 7.1%, 11%);--slate3: hsl(197, 6.8%, 13.6%);--slate4: hsl(198, 6.6%, 15.8%);--slate5: hsl(199, 6.4%, 17.9%);--slate6: hsl(201, 6.2%, 20.5%);--slate7: hsl(203, 6%, 24.3%);--slate8: hsl(20
}}
>
</style>
</head>
<body>
<h1>Will Krouse</h1>
<a href="https://twitter.com/Willthereader" target="_blank">Twitter</a>{" "}
<a href="https://github.com/wkrouse" target="_blank">Github</a>
<p>
Hi, I'm Will, a 24-year-old autistic individual in Florida. I love reading. I enjoy playing board games,
tennis, and pickleball.
</p>
<p>
I'm learning to code. My favorite part are the meta-skills. For example, the debugging mindset is always
useful for fixing problems.
</p>
<p>
I find the complexity of current events and politics really interesting. I enjoy articles that significantly
change my understanding. I really like{" "}
<a className="text-blue-500 hover:underline" href="https://www.readtangle.com">Tangle</a>{" "}
because it offers perspectives from all sides. I dislike when people assume the worst of their opponents and
when I can't tell who's right because no one addresses the best arguments from their opponents.
</p>
<p>
I am on the autism spectrum, so I sometimes misunderstand people's tones and vibes or send the wrong ones.
Your patience and feedback are appreciated!
</p>
<p>
I built{" "}
<a className="text-blue-500 hover:underline" href="https://www.val.town/v/willthereader/personalWebsite">
this site
</a>{" "}
on Val Town.
</p>
<h2>Projects</h2>
<div>
<div>
3/6/2024 -{" "}
<a href="https://news.ycombinator.com/item?id=39618062">
Bringing My OCD Online: Userscripts for Immersive Forum Browsing
</a>
</div>
</div>
<h2>Credit</h2>
<div>
<div>
<p>
I copied the formatting from{" "}
<a className="text-blue-500 hover:underline" href="https://vbud.dev/">Valjean Clark</a>{" "}
and was inspired by his design.
</p>
</div>
</div>
</body>
</html>,
),
{
headers: { "Content-Type": "text/html" },
},
);
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/** @jsxImportSource https://esm.sh/react */
import { renderToString } from 'npm:react-dom/server';
export const testWebsite = (request: Request) => {
// convert to Response
return new Response(renderToString(
<html>
<head>
<title>Page Title</title>
</head>
<body>
<span style={{ color: "red" }}>H</span> <span style={{ color: "blue" }}>e</span>{" "}
<span style={{ color: "green" }}>l</span> <span style={{ color: "red" }}>l</span>{" "}
<span style={{ color: "green" }}>o</span>
</body>
</html>), {
headers: { 'Content-Type': 'text/html' }
}
);
};

stevekrouse.com - my personal website

This val hosts my personal website. The view data is stored in Val Town SQLite - @std/sqlite.

It used to live on Github Pages, which is why I proxy over requests to certain blog posts over to the Github Pages site still.

Todos

  • Speed up page load by loading sqlite data later like in @healeycodes/steve_web
  • Store more (legally storable) analytics data, and maybe make a sparkline!
  • Add some sort of way to contact me
  • Move over all my blog posts from Github Pages (maybe into @std/blob as a CMS?)
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
100
/** @jsxImportSource https://esm.sh/react */
import { email } from "https://esm.town/v/std/email?v=11";
import { sqlite } from "https://esm.town/v/std/sqlite?v=5";
import { ReloadScriptReactElement } from "https://esm.town/v/stevekrouse/ReloadScript";
import tailwindURL from "https://esm.town/v/stevekrouse/tailwindURL";
import { renderToString } from "npm:react-dom/server";
const linkClass = "text-blue-500 hover:underline";
const Link = (
{ children, href }: {
children?: React.ReactNode;
href: string;
},
) => <a className={linkClass} href={href}>{children}</a>;
const dateClass = "text-xs text-gray-400 font-mono mr-1 hidden sm:inline-block";
async function getHits() {
const [, , { rows: [[allHits]] }, { rows: [[todayHits]] }] = await sqlite.batch([
"CREATE TABLE IF NOT EXISTS stevekrouse_com_hits (timestamp DATETIME DEFAULT CURRENT_TIMESTAMP)",
"INSERT INTO stevekrouse_com_hits DEFAULT VALUES",
"SELECT COUNT(*) FROM stevekrouse_com_hits where timestamp > datetime('now', '-28 day')",
"SELECT COUNT(*) from stevekrouse_com_hits where timestamp > datetime('now', '-1 day')",
]);
if (allHits % 100 === 0) email({ subject: `You got ${todayHits} hits today! (${allHits} total)` });
return { allHits, todayHits };
}
export default async (request: Request) => {
const url = new URL(request.url);
if (url.pathname === "/favicon.ico") return new Response(null, { status: 404 });
if (url.pathname !== "/")
return fetch(
`https://stevekrouse.github.io/${url.pathname}${url.search}`,
request as any as RequestInit,
);
const { allHits, todayHits } = await getHits();
return new Response(
renderToString(
<html>
<head>
<title>Steve Krouse</title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<script src={tailwindURL} />
{url.searchParams.get("dev")
? <ReloadScriptReactElement vals={[{ valName: "dot_com", userHandle: "stevekrouse" }]} />
: null}
</head>
<body>
<div className="max-w-3xl p-10 space-y-4 mx-auto">
<h1 className="text-orange-600 text-2xl font-medium">Steve Krouse</h1>
<div>
👋 Hi, I'm Steve. I live in Prospect Heights, Brooklyn.
</div>
<div>
I build <Link href="https://val.town">Val Town</Link>, a social website to code in the cloud.
</div>
<div>
This site was{" "}
<Link href="https://www.val.town/v/stevekrouse/dot_com">built in Val Town</Link>. It was viewed{" "}
{todayHits} times today, and {allHits} times this month.
</div>
<div>
<h2 className="text-xl mb-1">Projects</h2>
<ul>
<li className="pb-2 sm:pb-1">
<span className={dateClass}>2022 Jul -</span>
<Link href="https://val.town">Val Town</Link>
</li>
<li className="pb-2 sm:pb-1">
<span className={dateClass}>2022 Sep -</span>
<Link href="https://dateme.directory">Date Me Directory</Link>
</li>
<li className="pb-2 sm:pb-1">
<span className={dateClass}>2022 Jan -</span>
<Link href="https://twitter.com/stevekrouse/status/1520162279899078657">Zaplib</Link>
</li>
<li className="pb-2 sm:pb-1">
<span className={dateClass}>2021 Mar -</span>
<Link href="http://updates.compose.run">Compose</Link>
</li>
<li className="pb-2 sm:pb-1">
<span className={dateClass}>2017 Jul -</span>
<Link href="https://futureofcoding.org/">Future of Coding</Link>
</li>
<li className="pb-2 sm:pb-1">
<span className={dateClass}>2016 May -</span>
<Link href="https://github.com/stevekrouse/woofjs">WoofJS</Link>
</li>
<li className="pb-2 sm:pb-1">
<span className={dateClass}>2015 Sep -</span>
<Link href="http://coding.space">The Coding Space Curriculum</Link>
</li>
<li className="pb-2 sm:pb-1">
<span className={dateClass}>2015 Jul -</span>
<Link href="http://thecodingspace.com">The Coding Space</Link>
</li>
<li className="pb-2 sm:pb-1">
<span className={dateClass}>2014 Jan -</span>Software Engineer @{" "}
<Link href="https://looker.com/">Looker</Link>
</li>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/** @jsxImportSource https://esm.sh/react */
import { renderToString } from 'npm:react-dom/server';
export const testWebsite = (request: Request) => {
// convert to Response
return new Response(renderToString(
<html>
<head>
<title>Page Title</title>
</head>
<body>
<span style={{ color: "red" }}>H</span> <span style={{ color: "blue" }}>e</span>{" "}
<span style={{ color: "green" }}>l</span> <span style={{ color: "red" }}>l</span>{" "}
<span style={{ color: "green" }}>o</span>
</body>
</html>), {
headers: { 'Content-Type': 'text/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
51
52
53
54
/** @jsxImportSource https://esm.sh/react */
import { modifyFetchHandler } from "https://esm.town/v/andreterron/codeOnValTown?v=46";
import { sqlite } from "https://esm.town/v/std/sqlite?v=4";
import tailwindURL from "https://esm.town/v/stevekrouse/tailwindURL";
import { renderToString } from "npm:react-dom/server";
export const reactExample = modifyFetchHandler(async (request: Request) => {
const url = new URL(request.url);
if (url.pathname === "/favicon.ico") return new Response(null, { status: 404 });
const [, , data] = await sqlite.batch([
"CREATE TABLE IF NOT EXISTS stevekrouse_com_hits (timestamp DATETIME DEFAULT CURRENT_TIMESTAMP)",
"INSERT INTO stevekrouse_com_hits DEFAULT VALUES",
"SELECT COUNT(*) FROM stevekrouse_com_hits",
]);
const hits = data.rows[0][0];
return new Response(
renderToString(
<html>
<head>
<title>Steve Krouse</title>
<script src={tailwindURL} />
</head>
<body>
<div className="max-w-md p-10 space-y-2">
<div>
hi, I'm Steve 👋
</div>
<div>
i work at{" "}
<a href="https://val.town" className="text-blue-500 hover:text-blue-700">val town</a>, a social website to
code in the cloud. i tweet at{" "}
<a href="https://twitter.com/stevekrouse" className="text-blue-500 hover:text-blue-700">@stevekrouse</a>
</div>
<div>
{hits.toString()} hits |{" "}
<a
href="https://stevekrouse.github.io/"
className="text-blue-500 hover:text-blue-700"
style={{ transform: "rotate(90deg)" }}
>
previous version
</a>
</div>
</div>
</body>
</html>,
),
{
headers: {
"Content-Type": "text/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
51
52
53
54
55
/** @jsxImportSource https://esm.sh/react */
import { modifyFetchHandler } from "https://esm.town/v/andreterron/codeOnValTown?v=46";
import { email } from "https://esm.town/v/std/email?v=11";
import { sqlite } from "https://esm.town/v/std/sqlite";
import tailwindURL from "https://esm.town/v/stevekrouse/tailwindURL";
import { renderToString } from "npm:react-dom/server";
const linkClass = "text-blue-500 hover:underline";
async function getHits() {
const [, , { rows: [[allHits]] }, { rows: [[todayHits]] }] = await sqlite.batch([
"CREATE TABLE IF NOT EXISTS stevekrouse_com_hits (timestamp DATETIME DEFAULT CURRENT_TIMESTAMP)",
"INSERT INTO stevekrouse_com_hits DEFAULT VALUES",
"SELECT COUNT(*) FROM stevekrouse_com_hits",
"SELECT COUNT(*) from stevekrouse_com_hits where timestamp > datetime('now', '-1 day')",
]);
if (allHits % 100 === 0) email({ subject: `You got ${todayHits} hits today! (${allHits} total)` });
return { allHits, todayHits };
}
export const reactExample = modifyFetchHandler(async (request: Request) => {
const url = new URL(request.url);
if (url.pathname === "/favicon.ico") return new Response(null, { status: 404 });
const { allHits, todayHits } = await getHits();
return new Response(
renderToString(
<html>
<head>
<title>Steve Krouse</title>
<script src={tailwindURL} />
</head>
<body>
<div className="max-w-3xl p-10 space-y-4 mx-auto">
<h1 className="text-orange-600 text-2xl font-medium">Steve Krouse</h1>
<div>
👋 Hi, I'm Steve. I live in Prospect Heights, Brooklyn.
</div>
<div>
I'm build{" "}
<a href="https://val.town" className={linkClass}>Val Town</a>, a social website to code in the cloud.
</div>
<div>
This site got {todayHits} hits today, and {allHits} since March 2024.
</div>
</div>
</body>
</html>,
),
{
headers: {
"Content-Type": "text/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
/** @jsxImportSource https://esm.sh/react */
import { lessons } from "https://esm.town/v/petermillspaugh/lessons";
import { email as sendEmail } from "https://esm.town/v/std/email?v=11";
import { renderToString } from "npm:react-dom/server";
export async function sendLessonResponses({ email, lesson, formData }) {
const fillBlankResponse = formData.get("fill-in-the-blank") as string;
const reflectionResponse = formData.get("reflection") as string;
const jsx = (
<>
<h1>Your responses for lesson {Number(lesson) + 1}: {lessons[lesson].title}</h1>
<h2>Fill-in-the-blank</h2>
<p>
<strong>Prompt:</strong> {lessons[lesson].fillBlank}
</p>
<p>
<strong>Your response:</strong> {fillBlankResponse}
</p>
<h2>Review</h2>
{lessons[lesson].quiz.map(({ question, answer }) => (
<>
<h3>{question}</h3>
<p>
<strong>Your response:</strong> {formData.get(`ANSWER-${question}`) as string}
</p>
<p>
<strong>Answer:</strong> {answer}
</p>
</>
))}
<h2>Reflection</h2>
<p>{reflectionResponse}</p>
</>
);
await sendEmail({
to: email,
from: {
name: "Make It Stick (in 10 days, via email)",
email: "petermillspaugh.sendLesson@valtown.email",
},
replyTo: "pete@petemillspaugh.com",
subject: `Your responses for lesson ${Number(lesson) + 1}: ${lessons[lesson].title}`,
html: renderToString(jsx),
});
}