好的,让我们继续前端页面和组件的开发。
第四部分:前端页面和组件
- 首先,在
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>- 创建
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>- 创建
src/views/partials/footer.eta:
<footer>
<p>© 2023 My Blog. All rights reserved.</p>
</footer>- 创建
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>- 创建
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>- 创建
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>- 更新
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}`);- 创建
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 模板引擎渲染这些页面。
接下来,我们将继续完善认证和授权部分。需要我继续吗?