MiniAppStarterindex.tsx3 matches
5import * as db from "./db.ts";
6import { embedMetadata, handleFarcasterEndpoints, name } from "./farcaster.ts";
7import { handleImageEndpoints } from "./image.tsx";
89const app = new Hono();
1011handleImageEndpoints(app);
12handleFarcasterEndpoints(app);
1344<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">
MiniAppStarterimage.tsx12 matches
5import satori from "npm:satori";
67export function handleImageEndpoints(app: Hono) {
8const headers = {
9"Content-Type": "image/png",
10"cache-control": "public, max-age=86400",
11};
12app.get("/image", async (c) => {
13return c.body(await homeImage(), 200, headers);
14});
15app.get("/icon", async (c) => {
16return c.body(await iconImage(), 200, headers);
17});
18}
1920export async function homeImage() {
21return 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}
3233export async function iconImage() {
34return 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//////////
4647export async function ogImage(body, options = {}) {
48const svg = await satori(
49body,
57if (code === "emoji") {
58const unicode = segment.codePointAt(0).toString(16).toUpperCase();
59return `data:image/svg+xml;base64,` + btoa(await loadEmoji(unicode));
60}
61return "";
94const base64 = Buffer.from(svg).toString("base64");
95// console.log('getIconDataUrl', name, svg, base64)
96return `data:image/svg+xml;base64,${base64}`;
97};
MiniAppStarterfarcaster.ts4 matches
5export const name = "Mini App Starter";
6// export const iconUrl = "https://imgur.com/TrJLlwp.png";
7// export const ogImageUrl = "https://imgur.com/xKVOVUE.png";
89export function embedMetadata(baseUrl: string, path: string = "/") {
10return {
11version: "next",
12imageUrl: baseUrl + "/image",
13button: {
14title: name,
17name: name,
18url: baseUrl + path,
19splashImageUrl: baseUrl + "/icon",
20splashBackgroundColor: "#111111",
21},
55"iconUrl": baseUrl + "/icon",
56"homeUrl": baseUrl,
57"splashImageUrl": baseUrl + "/icon",
58"splashBackgroundColor": "#111111",
59"primaryCategory": "developer-tools",
WillpersonalWebsiteHTTP1011 match
4849<h2>Credit</h2>
50<div><div><p>I copied image <a class="text-blue-500 hover:underline" href="https://medium.com/@prabathshalitha21/11-http-headers-http-status-codes-eb34449599fb/">11. HTTP Headers
51& HTTP Status Codes</a> which was written by <a class="text-blue-500 hover:underline" href="https://medium.com/@prabathshalitha21?source=post_page---byline--eb34449599fb---------------------------------------">Prabath Shalitha</a></p></div></div>
52
14- [Hono JSX Starter][]: Render Hono with JSX
15- [Hono Client Starter][]: Render Hono with JSX on the server and hydrate on the client
16- [SVG Starter][]: Render an SVG image response
17- [SVG PNG Starter][]: Render an SVG as a PNG image response
18- [Preact Starter][]: Render Preact on the server
19- [Preact Client Starter][]: Render Preact on the server and hydrate the app on the client
4647<!--
48- README card image
4950- [x] React Starter
OpenTownie_jacksonuseChatLogic.ts4 matches
9bearerToken: string;
10selectedFiles: string[];
11images: (string | null)[];
12soundEnabled: boolean;
13}
19bearerToken,
20selectedFiles,
21images,
22soundEnabled,
23}: UseChatLogicProps) {
43anthropicApiKey,
44selectedFiles,
45images: images
46.filter((img): img is string => {
47const isValid = typeof img === "string" && img.startsWith("data:");
48if (!isValid && img !== null) {
49console.warn("Invalid image format:", img?.substring(0, 50) + "...");
50}
51return isValid;
OpenTownie_jacksonTODOs.md2 matches
29- [x] File write as a code embed
30- [x] str_replace as a diff view
31- [x] make image drop area invisible and bigger
32- [x] Give it all the code (except maybe .txt files) as initial context (like cursor sonnet max)
33- [x] I seem to have lost the delete file tool and instructions, try to find them back in history or re-create?
55- [x] Create branch
56- [x] URL input + pathname
57- [x] Image upload controls
58- [x] Preview refresh button
59- [x] Audio controls
OpenTownie_jacksonsystem_prompt.txt2 matches
172173- **Redirects:** Use `return new Response(null, { status: 302, headers: { Location: "/place/to/redirect" }})` instead of `Response.redirect` which is broken
174- **Images:** Avoid external images or base64 images. Use emojis, unicode symbols, or icon fonts/libraries instead
175- **AI Image:** To inline generate an AI image use: `<img src="https://maxm-imggenurl.web.val.run/the-description-of-your-image" />`
176- **Storage:** DO NOT use the Deno KV module for storage
177- **Browser APIs:** DO NOT use the `alert()`, `prompt()`, or `confirm()` methods
OpenTownie_jacksonstyles.css11 matches
682background-color: var(--highlight);
683}
684.card-image {
685display: flex;
686align-items: center;
704}
705706.image-placeholder,
707.image-thumbnail {
708width: 40px;
709height: 40px;
711object-fit: cover;
712}
713.image-placeholder {
714background-color: var(--muted);
715}
722}
723724.image-row {
725display: flex;
726gap: var(--space-1);
727}
728.input-image {
729position: relative;
730border: 1px solid var(--muted);
731border-radius: 6px;
732}
733.remove-image-button {
734position: absolute;
735top: 0;
744opacity: 0;
745}
746.input-image:hover .remove-image-button {
747opacity: 1;
748}
749750.image-drop-overlay {
751position: fixed;
752top: 0;
761justify-content: center;
762}
763.image-drop-inner {
764padding: var(--space-2);
765background-color: var(--background);
766}
767768.transition, .input-box, .icon-button, .button, .remove-image-button {
769transition-property: color, background-color, border-color, opacity;
770transition-duration: 200ms;
OpenTownie_jacksonInputBox.tsx46 matches
2import { useRef, useState, useEffect } from "https://esm.sh/react@18.2.0?dev";
3import { PlusIcon, ArrowUpIcon, Square, XIcon } from "./icons.tsx";
4import { processFiles } from "../utils/images.ts";
56export function InputBox ({
11running,
12error,
13images,
14setImages,
15} : {
16value: string;
20running: boolean;
21error: any;
22images: (string|null)[];
23setImages: (images: (string|null)[]) => void;
24}) {
25const form = useRef(null);
57autoFocus={true}
58/>
59<ImageRow images={images} setImages={setImages} />
60<div className="toolbar">
61<UploadButton
62disabled={running}
63images={images}
64setImages={setImages}
65/>
66<div className="spacer" />
88}
8990export function ImageDropContainer ({
91images,
92setImages,
93running,
94children,
95}: {
96images: (string|null)[];
97setImages: (images: (string|null)[]) => void;
98running: boolean;
99children: React.ReactNode;
100}) {
101const dragging = useImageDrop({ images, setImages, running });
102103return (
105{children}
106{dragging && (
107<div className="image-drop-overlay">
108<div className="image-drop-inner">
109Drop images here to upload
110</div>
111</div>
115}
116117export function useImageDrop ({ images, setImages, running }: {
118images: (string|null)[];
119setImages(images: (string|null)[]) => void;
120running: boolean;
121}) {
143setDragging(false);
144if (e.dataTransfer?.files && !running) {
145processFiles(Array.from(e.dataTransfer.files), images, setImages);
146}
147}
164}
165166function ImageRow ({ images, setImages }: {
167images: (string|null)[];
168setImages: (images: (string|null)[]) => void;
169}) {
170return (
171<div className="image-row">
172{images.map((image, i) => (
173<Thumbnail
174key={i}
175image={image}
176onRemove={() => {
177setImages([
178...images.slice(0, i),
179...images.slice(i + 1),
180]);
181}}
186}
187188function Thumbnail ({ image, onRemove }: {
189image: string|null;
190onRemove: () => void;
191}) {
192if (!image) return null;
193194return (
195<div className="input-image">
196<img
197src={image}
198alt="User uploaded image"
199className="image-thumbnail"
200/>
201<button
202type="button"
203title="Remove image"
204className="remove-image-button"
205onClick={onRemove}
206>
212213function UploadButton ({
214images,
215setImages,
216disabled,
217}: {
218images: (string|null)[];
219setImages: (images: (string|null)[]) => void;
220disabled: boolean;
221}) {
226<button
227type="button"
228title="Upload image"
229disabled={disabled}
230onClick={e => {
234<PlusIcon />
235<div className="sr-only">
236Upload image
237</div>
238</button>
243onChange={e => {
244if (e.target.files) {
245processFiles(Array.from(e.target.files), images, setImages);
246}
247}}