66 </a>
67 <a href="/frontend/gallery.html" class="flex items-center text-gray-700 hover:text-green-600">
68 <i class="fas fa-images mr-2 text-green-500"></i>
69 <span>Project Gallery</span>
70 </a>
23 else if (fileExtension === "css") contentType = "text/css";
24 else if (fileExtension === "js") contentType = "text/javascript";
25 else if (fileExtension === "svg") contentType = "image/svg+xml";
26
27 return new Response(content, {
5import * as db from "./db.ts";
6import { embedMetadata, handleFarcasterEndpoints, name } from "./farcaster.ts";
7import { handleImageEndpoints } from "./image.tsx";
8
9const app = new Hono();
10
11handleImageEndpoints(app);
12handleFarcasterEndpoints(app);
13
44 <meta name="fc:frame" content={JSON.stringify(embedMetadata(baseUrl, path))} />
45 <link rel="icon" href={baseUrl + "/icon"} />
46 <meta property="og:image" content={baseUrl + "/image"} />
47 </head>
48 <body class="bg-white text-black dark:bg-black dark:text-white">
5import satori from "npm:satori";
6
7export function handleImageEndpoints(app: Hono) {
8 const headers = {
9 "Content-Type": "image/png",
10 "cache-control": "public, max-age=86400",
11 };
12 app.get("/image", async (c) => {
13 return c.body(await homeImage(), 200, headers);
14 });
15 app.get("/icon", async (c) => {
16 return c.body(await iconImage(), 200, headers);
17 });
18}
19
20export async function homeImage() {
21 return await ogImage(
22 <div tw="w-full h-full flex justify-start items-end text-[100px] bg-black text-white p-[50px]">
23 <div tw="flex flex-col items-start gap-[10px]">
31}
32
33export async function iconImage() {
34 return await ogImage(
35 <div tw="w-full h-full flex justify-center items-center text-[100px] bg-black text-white p-[50px]">
36 <img tw="w-[350px] h-[350px]" src={base64Icon(SquareDashed)} />
45//////////
46
47export async function ogImage(body, options = {}) {
48 const svg = await satori(
49 body,
57 if (code === "emoji") {
58 const unicode = segment.codePointAt(0).toString(16).toUpperCase();
59 return `data:image/svg+xml;base64,` + btoa(await loadEmoji(unicode));
60 }
61 return "";
94 const base64 = Buffer.from(svg).toString("base64");
95 // console.log('getIconDataUrl', name, svg, base64)
96 return `data:image/svg+xml;base64,${base64}`;
97};
5export const name = "Mini App Starter";
6// export const iconUrl = "https://imgur.com/TrJLlwp.png";
7// export const ogImageUrl = "https://imgur.com/xKVOVUE.png";
8
9export function embedMetadata(baseUrl: string, path: string = "/") {
10 return {
11 version: "next",
12 imageUrl: baseUrl + "/image",
13 button: {
14 title: name,
17 name: name,
18 url: baseUrl + path,
19 splashImageUrl: baseUrl + "/icon",
20 splashBackgroundColor: "#111111",
21 },
55 "iconUrl": baseUrl + "/icon",
56 "homeUrl": baseUrl,
57 "splashImageUrl": baseUrl + "/icon",
58 "splashBackgroundColor": "#111111",
59 "primaryCategory": "developer-tools",
3It's common to have code and types that are needed on both the frontend and the backend. It's important that you write this code in a particularly defensive way because it's limited by what both environments support:
4
5
6
7For example, you *cannot* use the `Deno` keyword. For imports, you can't use `npm:` specifiers, so we reccomend `https://esm.sh` because it works on the server & client. You *can* use TypeScript because that is transpiled in `/backend/index.ts` for the frontend. Most code that works on the frontend tends to work in Deno, because Deno is designed to support "web-standards", but there are definitely edge cases to look out for.
21## `favicon.svg`
22
23As of this writing Val Town only supports text files, which is why the favicon is an SVG and not an .ico or any other binary image format. If you need binary file storage, check out [Blob Storage](https://docs.val.town/std/blob/).
24
25## `components/`
6 <title>React Hono Val Town Starter</title>
7 <link rel="stylesheet" href="/public/style.css">
8 <link rel="icon" href="/public/favicon.svg" sizes="any" type="image/svg+xml">
9 </head>
10 <body>
3View and interact with your Val Town SQLite data. It's based off Steve's excellent [SQLite Admin](https://www.val.town/v/stevekrouse/sqlite_admin?v=46) val, adding the ability to run SQLite queries directly in the interface. This new version has a revised UI and that's heavily inspired by [LibSQL Studio](https://github.com/invisal/libsql-studio) by [invisal](https://github.com/invisal). This is now more an SPA, with tables, queries and results showing up on the same page.
4
5
6
7## Install
54 .fc:focus{color:#e5e7eb;background:#374151;border-color:#2563eb;outline:0;box-shadow:0 0 0 .2rem rgba(37,99,235,.5)}
55 textarea.fc{min-height:120px}
56 select.fc{height:48px;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%239ca3af' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;padding-right:2.5rem}
57 .aB{display:inline-block;font-weight:600;text-align:center;white-space:nowrap;vertical-align:middle;user-select:none;border:1px solid transparent;padding:.75rem 1.5rem;font-size:1rem;line-height:1.5;border-radius:.3rem;transition:all .15s ease-in-out;cursor:pointer;font-family:inherit}
58 .aB-primary{background:#2563eb;color:#fff;border-color:#2563eb}.aB-primary:hover{background:#1d4ed8;border-color:#1d4ed8}