[
  {
    "path": ".gitignore",
    "content": ".wrangler\nnode_modules\nyarn-error.log\nyarn.lock\nwrangler.toml"
  },
  {
    "path": "README.md",
    "content": "# Todo Example\n\nStack:\n\n* Hono\n* JSX (Hono middleware)\n* htmx\n* Zod\n* Cloudflare Workers\n* Cloudflare D1\n\n## Usage\n\nInstall:\n\n```\nnpm install\n```\n\nSetup:\n\n```\nwrangler d1 create todo\nwrangler d1 execute todo --local --file=todo.sql\n```\n\nDev:\n\n```\nnpm run dev\n```\n\nDeploy:\n\n```\nnpm run deploy\n```\n\n## Author\n\nYusuke Wada\n\n## License\n\nMIT"
  },
  {
    "path": "package.json",
    "content": "{\n  \"scripts\": {\n    \"dev\": \"wrangler dev --live-reload src/index.tsx\",\n    \"deploy\": \"wrangler deploy --minify src/index.tsx\"\n  },\n  \"dependencies\": {\n    \"@hono/zod-validator\": \"^0.1.9\",\n    \"hono\": \"^3.8.0-rc.2\",\n    \"zod\": \"^3.21.4\"\n  },\n  \"devDependencies\": {\n    \"@cloudflare/workers-types\": \"^4.20231002.0\",\n    \"wrangler\": \"^3.11.0\"\n  }\n}\n"
  },
  {
    "path": "src/components.tsx",
    "content": "import { html } from 'hono/html'\nimport { jsxRenderer } from 'hono/jsx-renderer'\n\nexport const renderer = jsxRenderer(({ children }) => {\n  return html`\n    <!DOCTYPE html>\n    <html>\n      <head>\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n        <script src=\"https://unpkg.com/htmx.org@1.9.3\"></script>\n        <script src=\"https://unpkg.com/hyperscript.org@0.9.9\"></script>\n        <script src=\"https://cdn.tailwindcss.com\"></script>\n        <title>Hono + htmx</title>\n      </head>\n      <body>\n        <div class=\"p-4\">\n          <h1 class=\"text-4xl font-bold mb-4\"><a href=\"/\">Todo</a></h1>\n          ${children}\n        </div>\n      </body>\n    </html>\n  `\n})\n\nexport const AddTodo = () => (\n  <form hx-post=\"/todo\" hx-target=\"#todo\" hx-swap=\"beforebegin\" _=\"on htmx:afterRequest reset() me\" class=\"mb-4\">\n    <div class=\"mb-2\">\n      <input name=\"title\" type=\"text\" class=\"bg-gray-50 border border-gray-300 text-gray-900 rounded-lg p-2.5\" />\n    </div>\n    <button class=\"text-white bg-blue-700 hover:bg-blue-800 rounded-lg px-5 py-2 text-center\" type=\"submit\">\n      Submit\n    </button>\n  </form>\n)\n\nexport const Item = ({ title, id }: { title: string; id: string }) => (\n  <p\n    hx-delete={`/todo/${id}`}\n    hx-swap=\"outerHTML\"\n    class=\"flex row items-center justify-between py-1 px-4 my-1 rounded-lg text-lg border bg-gray-100 text-gray-600 mb-2\"\n  >\n    {title}\n    <button class=\"font-medium\">Delete</button>\n  </p>\n)\n"
  },
  {
    "path": "src/index.tsx",
    "content": "import { Hono } from 'hono'\nimport { z } from 'zod'\nimport { zValidator } from '@hono/zod-validator'\n\nimport { renderer, AddTodo, Item } from './components'\n\ntype Bindings = {\n  DB: D1Database\n}\n\ntype Todo = {\n  title: string\n  id: string\n}\n\nconst app = new Hono<{ Bindings: Bindings }>()\n\napp.get('*', renderer)\n\napp.get('/', async (c) => {\n  const { results } = await c.env.DB.prepare(`SELECT id, title FROM todo;`).all<Todo>()\n  const todos = results\n  return c.render(\n    <div>\n      <AddTodo />\n      {todos.map((todo) => {\n        return <Item title={todo.title} id={todo.id} />\n      })}\n      <div id=\"todo\"></div>\n    </div>\n  )\n})\n\napp.post(\n  '/todo',\n  zValidator(\n    'form',\n    z.object({\n      title: z.string().min(1)\n    })\n  ),\n  async (c) => {\n    const { title } = c.req.valid('form')\n    const id = crypto.randomUUID()\n    await c.env.DB.prepare(`INSERT INTO todo(id, title) VALUES(?, ?);`).bind(id, title).run()\n    return c.html(<Item title={title} id={id} />)\n  }\n)\n\napp.delete('/todo/:id', async (c) => {\n  const id = c.req.param('id')\n  await c.env.DB.prepare(`DELETE FROM todo WHERE id = ?;`).bind(id).run()\n  c.status(200)\n  return c.body(null)\n})\n\nexport default app\n"
  },
  {
    "path": "todo.sql",
    "content": "CREATE TABLE todo (\n  id TEXT PRIMARY KEY,\n  title TEXT NOT NULL\n);"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"node\",\n    \"esModuleInterop\": true,\n    \"strict\": true,\n    \"lib\": [\n      \"esnext\"\n    ],\n    \"types\": [\n      \"@cloudflare/workers-types\"\n    ],\n    \"jsx\": \"react-jsx\",\n    \"jsxImportSource\": \"hono/jsx\"\n  },\n}"
  },
  {
    "path": "wrangler.sample.toml",
    "content": "name = \"todo\"\ncompatibility_date = \"2023-01-01\"\n\n[[d1_databases]]\nbinding = \"DB\" # i.e. available in your Worker on env.DB\ndatabase_name = \"todo\"\ndatabase_id = \"\"\npreview_database_id = \"local-todo\""
  }
]