1/** @jsxImportSource https://esm.sh/preact */
2import { makeBadge } from "npm:badge-maker";
3import { render } from "npm:preact-render-to-string";
4import prettyMilliseconds from "npm:pretty-ms";
5
1/** @jsxImportSource https://esm.sh/preact */
2import { expect } from "jsr:@std/expect";
3import { makeBadge } from "npm:badge-maker";
4import { render } from "npm:preact-render-to-string";
5import prettyMilliseconds from "npm:pretty-ms";
6import { parseProject } from "./project.ts";
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import Markdown from "https://esm.sh/react-markdown@9?deps=react@18.2.0";
3import { getProjectFiles, readFile } from "https://esm.town/v/stevekrouse/utils@196-main/serve-public/index.ts";
4import { renderToString } from "npm:react-dom@18.2.0/server";
5import { Layout } from "./Layout.tsx";
6
44}
45
46function html(children: React.ReactNode) {
47 return new Response(
48 renderToString(
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import { parseProject } from "https://esm.town/v/std/parseImportMeta/project";
3import { sqlite } from "https://esm.town/v/std/sqlite?v=6";
4import { html } from "https://esm.town/v/stevekrouse/html";
5import { renderToString } from "npm:react-dom@18.2.0/server";
6import config from "./config.json" with { type: "json" };
7import { SparklineSVG } from "./sparklineSVG";
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2export function SparklineSVG({ strokeWidth = 2, data = [], fill = "none", stroke = "black" }) {
3 const padding = 2;
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import React from "https://esm.sh/react@18.2.0";
3import type { Message } from "../shared/types.ts";
4
5export function MessageInput({ onSubmit }: { onSubmit: () => void }) {
6 const [message, setMessage] = React.useState("");
7
8 const handleSubmit = async (e: React.FormEvent) => {
9 e.preventDefault();
10 if (!message.trim()) return;
3This is a proof of concept, showing how to download Val Town projects as zip files. For now, I've hardcoded my username into the code, so you can only download my public/unlisted projects. To see it working, type the name of this project **getProjectsAsZips** and press download. Waalaah!
4
5If you fork this project, you can update the hardcoded username in <code> frontend/MessageInput.tsx</code>. I forked the [reactHonoStarter](https://www.val.town/x/stevekrouse/reactHonoStarter) to get started quickly (it's great), hence the weird naming and leftover code you'll see around this project.
6
7## Next Steps
11## Serving assets to the frontend
12
13This backend HTTP server is responsible for serving all static assets to the browser to render the app, including HTML, JavaScript (including all client-side React), CSS, and even the favicon SVG.
14
15In a normal server environment, you would likely use a middleware [like this one](https://hono.dev/docs/getting-started/nodejs#serve-static-files) to serve static files. Some frameworks or deployment platforms automatically make any content inside a `public/` folder public.
25## CRUD API Routes
26
27This app has two CRUD API routes: for reading and inserting into the messages table. They both speak JSON, which is standard. They import their functions from `/backend/database/queries.ts`. These routes are called from the React app to refresh and update data.
28
29## Errors
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import { createRoot } from "https://esm.sh/react-dom@18.2.0/client";
3import { App } from "./components/App.tsx";
4
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2
3import { createRoot } from "https://esm.sh/react-dom@18.2.0/client?deps=react@18.2.0";
4import React, { useEffect, useState } from "https://esm.sh/react@18.2.0?deps=react@18.2.0";
5import { type Review, REVIEW_LIMIT } from "../../shared/utils.ts";
6
38 };
39
40 const handleSubmit = async (e: React.FormEvent) => {
41 e.preventDefault();
42 try {