1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/** @jsx jsx **/
/** @jsx jsx */
import { renderToString } from "npm:react-dom/server";
import { jsx } from "https://deno.land/x/hono@v3.11.7/middleware.ts";
import { Hono } from "https://deno.land/x/hono@v3.11.7/mod.ts";
import debounce from "npm:lodash.debounce";
const app = new Hono();
const Layout = ({ children, title = "Counter Example" }) => (
<html lang="en">
<head>
<title>{title}</title>
<script src="https://unpkg.com/htmx.org@1.9.9"></script>
</head>
<body>
{children}
</body>
</html>
);
const Counter = ({ value }) => (
<div id="counterSection">
<div class="text-xl">Counter: {value}</div>
<form hx-post="/increment" hx-swap="outerHTML" hx-target="#counterSection">
<input type="hidden" name="counter" value={value} />
<button>++</button>
</form>
<form hx-post="/decrement" hx-swap="outerHTML" hx-target="#counterSection">
<input type="hidden" name="counter" value={value} />
<button>--</button>
</form>
</div>
);
const Home = ({ counter }) => (
<main>
<Counter value={counter} />
</main>
);
app.get("/", (c) => {
const counter = 0;
return c.html(
<Layout>
<Home counter={counter} />
</Layout>,
);
});
let counter = 0;
let pendingClicks = 0;
const updateCounter = debounce(() => {
counter += pendingClicks;
pendingClicks = 0;
}, 500);
app.post("/increment", async (c) => {
const body = await c.req.parseBody();
const currentCounter = parseInt(body.counter, 10);
pendingClicks++;
updateCounter();
return c.html(<Counter value={currentCounter + pendingClicks} />);
});
app.post("/decrement", async (c) => {
const body = await c.req.parseBody();
const currentCounter = parseInt(body.counter, 10);
pendingClicks--;
updateCounter();
return c.html(<Counter value={currentCounter + pendingClicks} />);
});
export default app.fetch;