好的,让我们继续前端页面和组件的开发。

第四部分:前端页面和组件

  1. 首先,在 src/views/layouts/main.eta 中创建主布局:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><%= it.title %></title>
    <script src="https://unpkg.com/htmx.org@1.9.6"></script>
    <link rel="stylesheet" href="/styles/main.css">
</head>
<body>
    <%~ includeFile('../partials/header.eta') %>
    
    <main>
        <%~ it.body %>
    </main>
    
    <%~ includeFile('../partials/footer.eta') %>
</body>
</html>
  1. 创建 src/views/partials/header.eta
<header>
    <nav>
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/posts">Posts</a></li>
            <% if (it.user) { %>
                <li><a href="/profile">Profile</a></li>
                <li><a href="/logout">Logout</a></li>
            <% } else { %>
                <li><a href="/login">Login</a></li>
                <li><a href="/register">Register</a></li>
            <% } %>
        </ul>
    </nav>
</header>
  1. 创建 src/views/partials/footer.eta
<footer>
    <p>&copy; 2023 My Blog. All rights reserved.</p>
</footer>
  1. 创建 src/views/home.eta
<% layout('./layouts/main.eta', { title: 'Home' }) %>
 
<h1>Welcome to My Blog</h1>
<p>This is the home page of our blog.</p>
 
<h2>Recent Posts</h2>
<div id="recent-posts">
    <% it.posts.forEach(post => { %>
        <article>
            <h3><a href="/posts/<%= post.id %>"><%= post.title %></a></h3>
            <p><%= post.content.substring(0, 100) %>...</p>
        </article>
    <% }) %>
</div>
  1. 创建 src/views/login.eta
<% layout('./layouts/main.eta', { title: 'Login' }) %>
 
<h1>Login</h1>
<form hx-post="/login" hx-swap="outerHTML">
    <div>
        <label for="username">Username:</label>
        <input type="text" id="username" name="username" required>
    </div>
    <div>
        <label for="password">Password:</label>
        <input type="password" id="password" name="password" required>
    </div>
    <button type="submit">Login</button>
</form>
  1. 创建 src/views/post.eta
<% layout('./layouts/main.eta', { title: it.post.title }) %>
 
<article>
    <h1><%= it.post.title %></h1>
    <p>By <%= it.post.author %> on <%= new Date(it.post.createdAt).toLocaleDateString() %></p>
    <div><%= it.post.content %></div>
</article>
 
<% if (it.user && it.user.id === it.post.authorId) { %>
    <div>
        <button hx-get="/posts/<%= it.post.id %>/edit" hx-target="body">Edit</button>
        <button hx-delete="/posts/<%= it.post.id %>" hx-confirm="Are you sure you want to delete this post?">Delete</button>
    </div>
<% } %>
 
<h2>Comments</h2>
<div id="comments">
    <!-- 这里可以添加评论列表和评论表单 -->
</div>
  1. 更新 src/index.ts 以使用 Eta 模板引擎:
import { Elysia } from "elysia";
import { html } from "@elysiajs/html";
import { staticPlugin } from "@elysiajs/static";
import { authRoutes } from "./routes/auth";
import { postRoutes } from "./routes/posts";
import { migrate } from "drizzle-orm/libsql/migrator";
import { db } from "./db";
import { renderFile } from "eta";
import path from "path";
 
// 运行迁移
await migrate(db, { migrationsFolder: "./drizzle" });
 
const app = new Elysia()
  .use(html())
  .use(staticPlugin())
  .use(authRoutes)
  .use(postRoutes)
  .get("/", async ({ set }) => {
    const posts = await db.select().from(posts).limit(5).all();
    set.headers['Content-Type'] = 'text/html';
    return await renderFile(path.join(__dirname, "views", "home.eta"), { posts });
  })
  .get("/login", async ({ set }) => {
    set.headers['Content-Type'] = 'text/html';
    return await renderFile(path.join(__dirname, "views", "login.eta"), {});
  })
  .get("/posts/:id", async ({ params, set }) => {
    const post = await db.select().from(posts).where(eq(posts.id, parseInt(params.id))).get();
    if (!post) {
      set.status = 404;
      return "Post not found";
    }
    set.headers['Content-Type'] = 'text/html';
    return await renderFile(path.join(__dirname, "views", "post.eta"), { post });
  })
  .listen(3000);
 
console.log(`Server is running at ${app.server?.hostname}:${app.server?.port}`);
  1. 创建 public/styles/main.css 文件并添加一些基本样式:
body {
    font-family: Arial, sans-serif;
    line-height: 1.6;
    margin: 0;
    padding: 0;
}
 
header {
    background-color: #333;
    color: #fff;
    padding: 1rem;
}
 
nav ul {
    list-style-type: none;
    padding: 0;
}
 
nav ul li {
    display: inline;
    margin-right: 10px;
}
 
nav ul li a {
    color: #fff;
    text-decoration: none;
}
 
main {
    padding: 2rem;
}
 
footer {
    background-color: #333;
    color: #fff;
    text-align: center;
    padding: 1rem;
    position: fixed;
    bottom: 0;
    width: 100%;
}

这就是前端页面和组件开发的基本结构。我们创建了主布局、部分视图(header 和 footer)以及几个主要页面(首页、登录页和文章页)。我们还更新了主应用文件以使用 Eta 模板引擎渲染这些页面。

接下来,我们将继续完善认证和授权部分。需要我继续吗?