当然可以。我会为您创建一个在 Bun 环境下使用 HTMX 和 UnoCSS 的完整案例,包括创建一个复杂的表格,其中包含图形显示和 Markdown 编辑功能。这个例子会涉及到服务器端和客户端的代码。

首先,让我们设置项目结构:

project/
├── src/
│   ├── index.ts
│   ├── routes/
│   │   └── table.ts
│   └── views/
│       ├── layout.ts
│       └── table.ts
├── public/
│   └── scripts/
│       ├── marked.min.js
│       └── chart.min.js
├── package.json
└── tsconfig.json

现在,让我们逐步实现各个部分:

  1. 安装依赖:
bun add hono @hono/node-server htmx.org unocss marked chart.js
bun add -d @types/marked @types/chart.js
  1. 配置 tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ES2022",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "strict": true,
    "jsx": "react-jsx",
    "jsxImportSource": "hono/jsx"
  }
}
  1. 创建主服务器文件 src/index.ts
import { serve } from "@hono/node-server";
import { Hono } from "hono";
import { serveStatic } from "hono/serve-static.bun";
import { tableRoutes } from "./routes/table";
import { layout } from "./views/layout";
 
const app = new Hono();
 
app.use("/public/*", serveStatic({ root: "./" }));
app.route("/", tableRoutes);
 
app.get("*", (c) => c.html(layout("404 Not Found", "<h1>404 Not Found</h1>")));
 
serve(app);
console.log("Server is running on http://localhost:3000");
  1. 创建表格路由 src/routes/table.ts
import { Hono } from "hono";
import { tableView } from "../views/table";
 
const app = new Hono();
 
type TableData = {
  id: number;
  name: string;
  value: number;
  description: string;
};
 
const tableData: TableData[] = [
  { id: 1, name: "Item 1", value: 100, description: "This is item 1" },
  { id: 2, name: "Item 2", value: 200, description: "This is item 2" },
  { id: 3, name: "Item 3", value: 300, description: "This is item 3" },
];
 
app.get("/", (c) => c.html(tableView(tableData)));
 
app.post("/update-cell", async (c) => {
  const { id, field, value } = await c.req.parseBody();
  const item = tableData.find((item) => item.id === parseInt(id as string));
  if (item && field in item) {
    (item as any)[field] = value;
    return c.html(value as string);
  }
  return c.text("Error updating cell", 400);
});
 
app.get("/chart-data", (c) => {
  const chartData = {
    labels: tableData.map((item) => item.name),
    datasets: [
      {
        label: "Values",
        data: tableData.map((item) => item.value),
        backgroundColor: "rgba(75, 192, 192, 0.6)",
      },
    ],
  };
  return c.json(chartData);
});
 
export { app as tableRoutes };
  1. 创建布局文件 src/views/layout.ts
export const layout = (title: string, content: string) => `
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>${title}</title>
  <script src="https://unpkg.com/htmx.org@1.9.6"></script>
  <script src="https://unpkg.com/hyperscript.org@0.9.11"></script>
  <script src="https://cdn.jsdelivr.net/npm/@unocss/runtime"></script>
  <script src="/public/scripts/marked.min.js"></script>
  <script src="/public/scripts/chart.min.js"></script>
  <script>
    htmx.onLoad(function(content) {
      Un.attach(content); // Attach UnoCSS to dynamically loaded content
    });
  </script>
</head>
<body>
  <div class="container mx-auto p-4">
    ${content}
  </div>
</body>
</html>
`;
  1. 创建表格视图 src/views/table.ts
import { html } from "hono/html";
 
type TableData = {
  id: number;
  name: string;
  value: number;
  description: string;
};
 
export const tableView = (data: TableData[]) => html`
  <h1 class="text-2xl font-bold mb-4">Complex Table Example</h1>
  <table class="w-full border-collapse border border-gray-300">
    <thead>
      <tr class="bg-gray-100">
        <th class="border border-gray-300 p-2">ID</th>
        <th class="border border-gray-300 p-2">Name</th>
        <th class="border border-gray-300 p-2">Value</th>
        <th class="border border-gray-300 p-2">Description</th>
        <th class="border border-gray-300 p-2">Chart</th>
      </tr>
    </thead>
    <tbody>
      ${data.map(
        (item) => html`
          <tr>
            <td class="border border-gray-300 p-2">${item.id}</td>
            <td class="border border-gray-300 p-2">${item.name}</td>
            <td class="border border-gray-300 p-2">
              <span
                hx-target="this"
                hx-swap="outerHTML"
                hx-trigger="dblclick"
                hx-get="/edit-value?id=${item.id}&value=${item.value}"
              >
                ${item.value}
              </span>
            </td>
            <td class="border border-gray-300 p-2">
              <div
                class="markdown-content"
                hx-target="this"
                hx-swap="outerHTML"
                hx-trigger="dblclick"
                hx-get="/edit-description?id=${item.id}"
              >
                ${item.description}
              </div>
            </td>
            <td class="border border-gray-300 p-2">
              <canvas
                id="chart-${item.id}"
                width="100"
                height="50"
                hx-trigger="load"
                hx-get="/chart-data"
                hx-swap="none"
                _="on htmx:afterOnLoad
                    set data to event.detail.xhr.response
                    call renderChart(#chart-${item.id}, data)"
              ></canvas>
            </td>
          </tr>
        `
      )}
    </tbody>
  </table>
  <script>
    function renderChart(canvas, data) {
      new Chart(canvas, {
        type: 'bar',
        data: JSON.parse(data),
        options: {
          responsive: true,
          maintainAspectRatio: false,
          scales: {
            y: {
              beginAtZero: true
            }
          }
        }
      });
    }
 
    document.body.addEventListener('htmx:afterSwap', function(event) {
      if (event.detail.target.classList.contains('markdown-content')) {
        event.detail.target.innerHTML = marked.parse(event.detail.target.textContent);
      }
    });
  </script>
`;
  1. 添加编辑值和描述的路由处理程序到 src/routes/table.ts
app.get("/edit-value", (c) => {
  const id = c.req.query("id");
  const value = c.req.query("value");
  return c.html(`
    <input
      type="number"
      value="${value}"
      hx-post="/update-cell"
      hx-trigger="blur"
      hx-target="this"
      hx-swap="outerHTML"
      name="value"
      _="on htmx:afterRequest remove me"
    >
    <input type="hidden" name="id" value="${id}">
    <input type="hidden" name="field" value="value">
  `);
});
 
app.get("/edit-description", (c) => {
  const id = c.req.query("id");
  const item = tableData.find((item) => item.id === parseInt(id as string));
  if (!item) return c.text("Item not found", 404);
  return c.html(`
    <textarea
      hx-post="/update-cell"
      hx-trigger="blur"
      hx-target="this"
      hx-swap="outerHTML"
      name="description"
      _="on htmx:afterRequest remove me"
    >${item.description}</textarea>
    <input type="hidden" name="id" value="${id}">
    <input type="hidden" name="field" value="description">
  `);
});
  1. public/scripts/ 目录下添加 marked.min.jschart.min.js 文件。

这个完整的案例展示了如何在 Bun 环境下使用 HTMX 和 UnoCSS 创建一个复杂的表格,包括以下功能:

  1. 使用 HTMX 进行局部更新和动态加载内容。
  2. 在单元格中显示图表(使用 Chart. Js)。
  3. 允许编辑数值和 Markdown 格式的描述。
  4. 使用 UnoCSS 进行样式设置。

要运行这个项目,请确保您已经安装了 Bun,然后在项目根目录下运行:

bun run src/index.ts

这个例子应该能够帮助您理解如何在 Bun 环境下使用 HTMX 和 UnoCSS 创建复杂的交互式表格。您可以根据需要进一步扩展和定制这个示例。