eldestBronzePtarmiganmain.tsx37 matches
1/**
2* This dating app allows users to upload photos of their bedside table and phone case.
3* It uses Val Town's SQLite for data persistence and blob storage for image uploads.
4* The app includes a simple matching algorithm based on common items in bedside tables.
5*/
12const [user, setUser] = useState(null);
13const [matches, setMatches] = useState([]);
14const [bedsideImage, setBedsideImage] = useState(null);
15const [phoneCaseImage, setPhoneCaseImage] = useState(null);
1617useEffect(() => {
25const userData = await response.json();
26setUser(userData);
27setBedsideImage(userData.bedsideImage);
28setPhoneCaseImage(userData.phoneCaseImage);
29}
30};
38};
3940const handleImageUpload = async (event, type) => {
41const file = event.target.files[0];
42const formData = new FormData();
43formData.append('image', file);
44formData.append('type', type);
4552const result = await response.json();
53if (type === 'bedside') {
54setBedsideImage(result.imageUrl);
55} else {
56setPhoneCaseImage(result.imageUrl);
57}
58}
65<div>
66<h2>Welcome, {user.name}!</h2>
67<div className="image-upload">
68<h3>Your Bedside Table</h3>
69{bedsideImage ? (
70<img src={bedsideImage} alt="Bedside Table" className="uploaded-image" />
71) : (
72<input type="file" onChange={(e) => handleImageUpload(e, 'bedside')} />
73)}
74</div>
75<div className="image-upload">
76<h3>Your Phone Case</h3>
77{phoneCaseImage ? (
78<img src={phoneCaseImage} alt="Phone Case" className="uploaded-image" />
79) : (
80<input type="file" onChange={(e) => handleImageUpload(e, 'phonecase')} />
81)}
82</div>
86<div key={match.id} className="match">
87<h4>{match.name}</h4>
88<img src={match.bedsideImage} alt="Bedside Table" className="match-image" />
89<img src={match.phoneCaseImage} alt="Phone Case" className="match-image" />
90</div>
91))}
118id INTEGER PRIMARY KEY AUTOINCREMENT,
119name TEXT NOT NULL,
120bedsideImage TEXT,
121phoneCaseImage TEXT
122)
123`);
131id: 1,
132name: "John Doe",
133bedsideImage: "https://maxm-imggenurl.web.val.run/a-simple-bedside-table-with-a-lamp-and-book",
134phoneCaseImage: "https://maxm-imggenurl.web.val.run/a-plain-black-phone-case"
135};
136return new Response(JSON.stringify(user), { headers: { 'Content-Type': 'application/json' } });
140// In a real app, you'd implement a matching algorithm. Here we're returning dummy data.
141const matches = [
142{ id: 2, name: "Jane Smith", bedsideImage: "https://maxm-imggenurl.web.val.run/a-bedside-table-with-plants-and-a-clock", phoneCaseImage: "https://maxm-imggenurl.web.val.run/a-colorful-floral-phone-case" },
143{ id: 3, name: "Bob Johnson", bedsideImage: "https://maxm-imggenurl.web.val.run/a-messy-bedside-table-with-many-gadgets", phoneCaseImage: "https://maxm-imggenurl.web.val.run/a-rugged-outdoor-phone-case" }
144];
145return new Response(JSON.stringify(matches), { headers: { 'Content-Type': 'application/json' } });
148if (path === '/upload' && request.method === 'POST') {
149const formData = await request.formData();
150const image = formData.get('image') as File;
151const type = formData.get('type') as string;
152153if (image && type) {
154const imageBuffer = await image.arrayBuffer();
155const imageKey = `${KEY}_${type}_${Date.now()}`;
156await blob.set(imageKey, imageBuffer);
157const imageUrl = `https://val.town/v/${KEY}/blobs/${imageKey}`;
158159// Update user's image in the database
160await sqlite.execute(`
161UPDATE ${KEY}_users
162SET ${type === 'bedside' ? 'bedsideImage' : 'phoneCaseImage'} = ?
163WHERE id = 1
164`, [imageUrl]);
165166return new Response(JSON.stringify({ imageUrl }), { headers: { 'Content-Type': 'application/json' } });
167}
168206}
207208.image-upload {
209margin-bottom: 20px;
210}
211212.uploaded-image, .match-image {
213max-width: 200px;
214max-height: 200px;
1interface WikipediaImage {
2source: string;
3width: number;
9pageId: number;
10extract: string;
11image?: WikipediaImage;
12url: string;
13}
1415export const fetchWikipediaImage = async (request: Request): Promise<Response> => {
16const url = new URL(request.url);
17const pageName = url.searchParams.get("title");
30return formatResponse(pageData, format);
31} catch (error) {
32console.error("Error fetching Wikipedia image:", error);
33return new Response("An error occurred while fetching the image", { status: 500 });
34}
35};
63apiUrl.searchParams.append("action", "query");
64apiUrl.searchParams.append("titles", searchResult.title);
65apiUrl.searchParams.append("prop", "pageimages|extracts|info|images|pageprops");
66apiUrl.searchParams.append("piprop", "original|name");
67apiUrl.searchParams.append("pithumbsize", "1000");
89const page = pages[0] as any;
9091const image = await getImageFromPage(page);
9293return {
95pageId: page.pageid,
96extract: page.extract || "No description available.",
97image: image,
98url: page.fullurl,
99};
100}
101102async function getImageFromPage(page: any): Promise<WikipediaImage | undefined> {
103console.log("Page data:", JSON.stringify(page, null, 2));
104105// Check for page_image in pageprops (this is usually the main image)
106if (page.pageprops && page.pageprops.page_image) {
107const imageData = await getImageInfo(page.pageprops.page_image);
108if (imageData) return imageData;
109}
110111// If no main image found, try the original image
112if (page.original) {
113return {
118}
119120// If still no image, try the images array
121if (page.images && page.images.length > 0) {
122for (const image of page.images) {
123const imageData = await getImageInfo(image.title);
124if (imageData) return imageData;
125}
126}
127128console.log("No image found for the page.");
129return undefined;
130}
131132async function getImageInfo(filename: string): Promise<WikipediaImage | undefined> {
133// Remove 'File:' prefix if it exists
134filename = filename.replace(/^File:/, "");
137apiUrl.searchParams.append("action", "query");
138apiUrl.searchParams.append("titles", `File:${filename}`);
139apiUrl.searchParams.append("prop", "imageinfo");
140apiUrl.searchParams.append("iiprop", "url|size");
141apiUrl.searchParams.append("format", "json");
144const data = await response.json();
145146console.log("Image info response:", JSON.stringify(data, null, 2));
147148const pages = Object.values(data.query.pages);
149if (pages.length > 0) {
150const page = pages[0] as any;
151if (page.imageinfo && page.imageinfo[0]) {
152const imageInfo = page.imageinfo[0];
153return {
154source: imageInfo.url,
155width: imageInfo.width,
156height: imageInfo.height,
157};
158}
159}
160161console.log("No image info found for:", filename);
162return undefined;
163}
168): Response {
169const responseData = {
170imageUrl: pageData.image ? pageData.image.source : "No image available",
171pageTitle: pageData.title,
172pageUrl: pageData.url,
186<h2>${responseData.pageTitle}</h2>
187${
188responseData.imageUrl !== "No image available"
189? `<img src="${responseData.imageUrl}" alt="${responseData.pageTitle}" style="max-width: 100%; height: auto;"/>`
190: "<p>No image available</p>"
191}
192<p>${responseData.extract}</p>
198});
199default:
200return new Response(responseData.imageUrl, {
201headers: { "Content-Type": "text/plain" },
202});
22borderWindowOuter: `inset -1px -1px ${colors.windowFrame}, inset 1px 1px ${colors.buttonFace}`,
23minimizeIcon:
24"data:image/svg+xml;charset=utf-8,%3Csvg width='6' height='2' viewBox='0 0 6 2' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Crect width='6' height='2' fill='black'/%3E %3C/svg%3E",
25maximizeIcon:
26"data:image/svg+xml;charset=utf-8,%3Csvg width='9' height='8' viewBox='0 0 9 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 2V7V8H1H8H9V7V2V0H8H1H0V2ZM8 7V2H1V7H8Z' fill='black'/%3E %3C/svg%3E",
27closeIcon:
28"data:image/svg+xml;charset=utf-8,%3Csvg width='8' height='7' viewBox='0 0 8 7' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 0H1H2V1H3V2H4H5V1H6V0H7H8V1H7V2H6V3H5V4H6V5H7V6H8V7H7H6V6H5V5H4H3V6H2V7H1H0V6H1V5H2V4H3V3H2V2H1V1H0V0Z' fill='black'/%3E %3C/svg%3E",
29elementSpacing: 8,
30};
122<TitleBarControl
123style={{
124backgroundImage: `url(${tokens.minimizeIcon})`,
125backgroundRepeat: "no-repeat",
126// // Only a single value is supported
139<TitleBarControl
140style={{
141backgroundImage: `url(${tokens.maximizeIcon})`,
142backgroundRepeat: "no-repeat",
143// backgroundPosition: "top 2px left 3x",
155marginLeft={2}
156style={{
157backgroundImage: `url(${tokens.closeIcon})`,
158backgroundRepeat: "no-repeat",
159// backgroundPosition: "top 3px left 4px",
285286return c.body(svg, 200, {
287"Content-Type": "image/svg+xml",
288});
289});
modifyImageREADME.md2 matches
1Code from https://deno.com/blog/build-image-resizing-api
23Useful for compressing an image before sending to chatgpt4v, for example
modifyImagemain.tsx6 matches
1import { ImageMagick, initializeImageMagick, MagickGeometry } from "https://deno.land/x/imagemagick_deno@0.0.14/mod.ts";
23export async function modifyImage(
4file: File,
5params: { width: number; height: number },
6) {
7const imageBuffer = new Uint8Array(await file.arrayBuffer());
8const sizingData = new MagickGeometry(
9params.width,
12sizingData.ignoreAspectRatio = params.height > 0 && params.width > 0;
13return new Promise<File>((resolve) => {
14ImageMagick.read(imageBuffer, (image) => {
15image.resize(sizingData);
16image.write((data) => resolve(new File([data], file.name, { type: file.type })));
17});
18});
thomasResumeHandlermain.tsx4 matches
16<meta name="viewport" content="width=device-width, initial-scale=1.0">
17<title>hello, resume</title>
18<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><text y='50%' font-size='24' text-anchor='middle' x='50%' dy='.3em'>📄</text></svg>">
19<style>
20${helloResume}
29}
3031// Add OG image URL and custom title to the config
32const ogImageUrl = 'https://tseeley.com/images/ufoog.JPG'; // Replace with your actual OG image URL
33const customTitle = `resume ✦ thomas seeley`; // You can customize this as needed
3435const resumeHTML = renderResume({
36...config,
37ogImageUrl,
38customTitle
39});
10* Create a [Val Town API token](https://www.val.town/settings/api), open the browser preview of this val, and use the API token as the password to log in.
1112<img width=500 src="https://imagedelivery.net/iHX6Ovru0O7AjmyT5yZRoA/7077d1b5-1fa7-4a9b-4b93-f8d01d3e4f00/public"/>
dailyStandupBotREADME.md1 match
3Every weekday at 9am EDT send a message to our team's #engineering Discord channel to start a thread to remind us to do our standup.
45
67Slack version: @mikker/dailySlackRoundup
sqliteExplorerAppREADME.md1 match
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.
45
67## Install
infiniteSVGGraphREADME.md2 matches
1# [Infinite SVG Graph](https://maxm-infinitesvggraph.web.val.run/)
23[](https://maxm-infinitesvggraph.web.val.run/)
45A connected graph of AI-generated SVG images.
67Ask it to make any kind of SVG. Add your contribution to the graph. Make it POP!