48
49- **Backend**: Hono + SQLite + OpenAI
50- **Frontend**: React + TypeScript + TailwindCSS
51- **Offline**: Service Workers + Cache API
52- **Storage**: SQLite for persistence, localStorage for offline data
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import { useState } from "https://esm.sh/react@18.2.0";
3
4const lineage = {
16 return (
17 <div>
18 <h1>Val Town React + Hono Starter</h1>
19 I've been clicked <button onClick={() => setClicked((c) => c + 1)}>{clicked}</button> times
20
1# React Hono Starter
2
3This app is a starter template for client-side React and server-side Hono.
4
5## Getting started
13- The **client-side entrypoint** is [`/frontend/index.html`](/frontend/index.html)
14 - which in turn imports [`/frontend/index.tsx`](/frontend/index.tsx)
15 - which in turn imports the React app from [`/frontend/components/App.tsx`](/frontend/components/App.tsx).
16
17So if you wanted to get a sense of how this app comes together, we suggest reading the files in this order:
21## Further resources
22
23- [React Hono Example](https://www.val.town/x/stevekrouse/reactHonoExample) is a bigger example project, with a SQLite database table, queries, client-side CSS, a favicon, and shared code that runs on both client and server.
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import React, { useState, useEffect } from "https://esm.sh/react@18.2.0?deps=react@18.2.0";
3import { formatCurrency, calculateMonthlySavingsNeeded } from "../../shared/utils.ts";
4
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import React, { useState, useEffect } from "https://esm.sh/react@18.2.0?deps=react@18.2.0";
3import { GOAL_CATEGORIES, formatCurrency, formatDate, calculateDaysToGoal, calculateMonthlySavingsNeeded } from "../../shared/utils.ts";
4
46 }, [refreshTrigger]);
47
48 const handleSubmit = async (e: React.FormEvent) => {
49 e.preventDefault();
50
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import React, { useState, useEffect } from "https://esm.sh/react@18.2.0?deps=react@18.2.0";
3import { EXPENSE_CATEGORIES, formatCurrency, formatDate, getCategoryEmoji } from "../../shared/utils.ts";
4
36 }, [refreshTrigger]);
37
38 const handleSubmit = async (e: React.FormEvent) => {
39 e.preventDefault();
40
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import React, { useState, useEffect } from "https://esm.sh/react@18.2.0?deps=react@18.2.0";
3import { formatCurrency, formatDate, getCategoryEmoji } from "../../shared/utils.ts";
4
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import React, { useState, useEffect } from "https://esm.sh/react@18.2.0?deps=react@18.2.0";
3import Dashboard from "./Dashboard.tsx";
4import ExpenseForm from "./ExpenseForm.tsx";
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import React from "https://esm.sh/react@18.2.0?deps=react@18.2.0";
3import { createRoot } from "https://esm.sh/react-dom@18.2.0/client?deps=react@18.2.0,react-dom@18.2.0";
4import App from "./components/App.tsx";
5
6// Initialize the React app
7const root = createRoot(document.getElementById("root")!);
8root.render(<App />);
76 </div>
77
78 <!-- React and app scripts -->
79 <script type="module" src="/frontend/index.tsx"></script>
80</body>