tanstackReactHonoExampleREADME.md2 matches
16In 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.
1718However in Val Town you need to handle this yourself, and it can be suprisingly difficult to read and serve files in a Val Town Project. This template uses helper functions from [stevekrouse/utils/serve-public](https://www.val.town/x/stevekrouse/utils/branch/main/code/serve-public/README.md), which handle reading project files in a way that will work across branches and forks, automatically transpiles typescript to javascript, and assigns content-types based on the file's extension.
1920### `index.html`
26## CRUD API Routes
2728This 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.
2930## Errors
tanstackReactHonoExampleREADME.md2 matches
45* `migrations.ts` - code to set up the database tables the app needs
6* `queries.ts` - functions to run queries against those tables, which are imported and used in the main Hono server in `/backend/index.ts`
78## Migrations
18The queries file is where running the migrations happen in this app. It'd also be reasonable for that to happen in index.ts, or as is said above, for that line to be commented out, and only run when actual changes are made to your database schema.
1920The queries file exports functions to get and write data. It relies on shared types and data imported from the `/shared` directory.
tanstackReactHonoExamplequeries.ts2 matches
34// Fetch messages query
5export function useMessages(initialData?: Message[]) {
6return useQuery({
7queryKey: ["messages"],
2021// Post message mutation
22export function usePostMessage() {
23const queryClient = useQueryClient();
24
tanstackReactHonoExamplequeries.ts2 matches
11await createTables();
1213export async function getMessages(limit = MESSAGE_LIMIT) {
14const messages = await db
15.select()
22}
2324export async function insertMessage(content: string) {
25await db
26.insert(schema.messages)
2import { db } from "./db.ts";
34export async function createTables() {
5// Create messages table
6await db.run(sql`
3import { usePostMessage } from "../lib/queries.ts";
45export function MessageInput() {
6const [message, setMessage] = React.useState("");
7const postMessage = usePostMessage();
tanstackReactHonoExampleApp.tsx3 matches
5import { useMessages } from "../lib/queries.ts";
67export function App(
8{ initialMessages = [], thisProjectURL }: { initialMessages?: Message[]; thisProjectURL?: string },
9) {
48}
4950function MessageList({ messages }: { messages: Message[] }) {
51const displayedMessages = messages.slice(0, MESSAGE_LIMIT);
52return (
57}
5859function MessageItem({ message }) {
60const formattedDate = new Date(message.timestamp).toLocaleString();
61
ChatHTMLRenderer.tsx6 matches
22readResource: (serverName: string, uri: string) => Promise<string>;
2324// Utility functions
25log: (level: "debug" | "info" | "warning" | "error", message: string, data?: any) => void;
2640* - Handles iframe communication via postMessage
41*/
42export default function HTMLRenderer({ html, mcpClients = [], className = "" }: HTMLRendererProps) {
43const iframeRef = useRef<HTMLIFrameElement>(null);
44const containerRef = useRef<HTMLDivElement>(null);
132},
133134// Utility functions
135log: (level: "debug" | "info" | "warning" | "error", message: string, data?: any) => {
136console[level](`[HTMLRenderer] ${message}`, data);
154}, [mcpClients, isFullscreen]);
155156// Fullscreen functionality
157const enterFullscreen = useCallback(() => {
158const container = containerRef.current;
218const methodFunc = (mcpContext as any)[method];
219220if (typeof methodFunc !== "function") {
221throw new Error(`Unknown MCP API method: ${method}`);
222}
365<script>
366// Update fullscreen controls based on state
367async function updateFullscreenControls() {
368const controls = document.getElementById('fullscreenControls');
369const isFs = await window.mcpContext.isFullscreen();
Work_Time_Calculator_2main.tsx7 matches
1function parseTimeRanges(daySchedule) {
2// console.log(`Parsing schedule: ${daySchedule}`);
3const timeRanges = daySchedule.match(/(\d{1,2}(?::\d{2})?(?:am|pm)?)/g);
53}
5455function convertTo24HourFormat(time) {
56if (!time) {
57throw new Error("Invalid time input: time is undefined or empty");
91}
9293function calculateDuration(day, startTime, endTime) {
94console.log(`calculateDuration: Calculating duration on ${day} from ${startTime} to ${endTime}`);
95const start24 = convertTo24HourFormat(startTime);
112}
113114function calculateDailyTotal(day, parsedSchedule) {
115console.log(`calculateDailyTotal: Calculating daily total for ${day}`, parsedSchedule);
116let totalMinutes = 0;
130}
131132function calculateWeeklyTotal(day, dailyTotals) {
133console.log(`calculateWeeklyTotal: Calculating weekly total for daily totals for ${day} is`, dailyTotals);
134let totalHours = 0;
148}
149150function isValidDay(day) {
151const validDays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
152return validDays.includes(day.charAt(0).toUpperCase() + day.slice(1).toLowerCase());
153}
154155function calculateWorkTime(schedule) {
156const dailyTotals = [];
157const scheduleArray = schedule.split("\n").filter(Boolean);
54}.`;
5556function generateHtmlShell(sourceUrl: string): string {
57return `
58<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>AuraTask - AI Todo</title>
72<div class="modal-overlay" id="chat-modal"><div class="modal-content"><div class="chat-header"><h3>Chat with Aura</h3></div><div id="chat-log"></div><form id="chat-form"><input type="text" id="chat-input" placeholder="Ask Aura to do something..." required><button type="submit" class="btn btn-primary">Send</button></form></div></div>
73<script>
74(function() {
75const API_URL = '${sourceUrl}';
76const STORE_KEYS = { projects: 'aura_projects_v1', tasks: 'aura_tasks_v1' };
83const genId = () => Date.now().toString(36) + Math.random().toString(36).substr(2, 9);
84
85function checkTaskLoad() {
86if (tasks.filter(t => !t.isCompleted).length >= ACTIVE_TASK_WARNING_THRESHOLD) {
87return confirm("You have a lot of active tasks. Are you sure you want to add more? It might be a good time to complete some items first.");
90}
9192function loadState() {
93projects = getStore(STORE_KEYS.projects);
94tasks = getStore(STORE_KEYS.tasks);
99}
100101function render() {
102renderSidebar();
103renderTaskList();
105}
106107function toggleLoading(btn, show) {
108if (!btn) return;
109isLoading = show;
112}
113114function updateUIElements() {
115const todayStr = new Date().toISOString().split("T")[0];
116const todayTasks = tasks.filter(t => !t.isCompleted && t.dueDate === todayStr);
126}
127128function renderSidebar() {
129const mainViews = [
130{id:'today',name:'Today',icon:'M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1z'},
135}
136137function renderTaskList() {
138const container = $("#task-list");
139let filteredTasks = [], title = 'Tasks';
158}
159160function renderChatLog() {
161const log = $("#chat-log");
162log.innerHTML = conversationHistory.map((msg, idx) => {
170}
171172function addMessageToChat(sender, text, plan = null, requiresConfirmation = false) {
173conversationHistory.push({ sender, text, plan, requiresConfirmation });
174renderChatLog();
175}
176177function executePlan(plan) {
178plan.forEach(action => {
179if (action.operation === 'CREATE_TASK') {
191}
192193function handleAddTask(e) {
194e.preventDefault();
195if (!checkTaskLoad()) return;
204}
205206function handleTaskClick(e) {
207const target = e.target, taskItem = target.closest(".task-item");
208if (!taskItem) return;
223}
224225function openEditModal(task) {
226$("#edit-task-id").value = task.id;
227$("#edit-task-content").value = task.content;
232}
233234function handleUpdateTask(e) {
235e.preventDefault();
236const taskId = $("#edit-task-id").value, task = tasks.find(t => t.id === taskId);
245}
246247async function handleChatSubmit(e) {
248e.preventDefault();
249const input = $("#chat-input"), userMessage = input.value.trim();
268}
269270function handlePlanConfirm(e) {
271const action = e.target.dataset.planAction, idx = e.target.dataset.planIdx;
272if (!action || !idx) return;
277}
278279async function triggerProjectSynthesis() {
280if (!checkTaskLoad()) return;
281const goal = $("#synthesis-goal-input").value.trim();
307}
308309async function triggerDailyRebalance() {
310const todayStr = new Date().toISOString().split("T")[0];
311const todayTasks = tasks.filter(t => !t.isCompleted && t.dueDate === todayStr);
339}
340341function bindEventListeners() {
342document.body.addEventListener('click', e => {
343if (e.target.closest('[data-view]')) {
371}
372373export default async function(req: Request): Promise<Response> {
374const openai = new OpenAI();
375const url = new URL(req.url);