好的,让我们来实现标签云和热门标签功能。这将帮助用户快速浏览热门话题,并提供一种视觉上吸引人的方式来展示博客的内容分布。
第十九部分:实现标签云和热门标签功能
- 首先,我们需要在数据库中添加标签相关的表。更新
src/db/schema.ts文件:
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
// ... 保留现有的表定义
export const tags = sqliteTable("tags", {
id: integer("id").primaryKey(),
name: text("name").notNull().unique(),
});
export const postTags = sqliteTable("post_tags", {
id: integer("id").primaryKey(),
postId: integer("post_id").notNull().references(() => posts.id),
tagId: integer("tag_id").notNull().references(() => tags.id),
});- 创建一个新的迁移文件来添加这些表。在
src/db/migrations目录下创建一个新文件,例如0004_add_tags.ts:
import { sqliteTable, integer, text } from "drizzle-orm/sqlite-core";
export async function up(db) {
await db.run(sql`
CREATE TABLE tags (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL UNIQUE
);
CREATE TABLE post_tags (
id INTEGER PRIMARY KEY,
post_id INTEGER NOT NULL,
tag_id INTEGER NOT NULL,
FOREIGN KEY (post_id) REFERENCES posts(id),
FOREIGN KEY (tag_id) REFERENCES tags(id)
);
`);
}
export async function down(db) {
await db.run(sql`
DROP TABLE post_tags;
DROP TABLE tags;
`);
}- 运行迁移:
bun run migrate- 更新
src/routes/posts.ts文件,添加标签相关的逻辑:
import { Elysia } from "elysia";
import { db } from "../db";
import { posts, users, categories, postCategories, tags, postTags } from "../db/schema";
import { eq, sql } from "drizzle-orm";
export const postRoutes = new Elysia()
// ... 保留现有的路由
.post("/posts", async ({ body, set }) => {
const { title, content, categoryIds, tags: tagNames } = body;
const post = await db.transaction(async (tx) => {
const [newPost] = await tx.insert(posts).values({
title,
content,
authorId: 1, // 假设用户已登录,这里应该使用实际的用户ID
createdAt: new Date(),
updatedAt: new Date(),
}).returning();
if (categoryIds && categoryIds.length > 0) {
await tx.insert(postCategories).values(
categoryIds.map(categoryId => ({
postId: newPost.id,
categoryId: parseInt(categoryId),
}))
);
}
if (tagNames && tagNames.length > 0) {
for (const tagName of tagNames) {
let [tag] = await tx.select().from(tags).where(eq(tags.name, tagName)).limit(1);
if (!tag) {
[tag] = await tx.insert(tags).values({ name: tagName }).returning();
}
await tx.insert(postTags).values({ postId: newPost.id, tagId: tag.id });
}
}
return newPost;
});
set.redirect = `/posts/${post.id}`;
})
// ... 保留其他路由- 创建一个新的路由文件
src/routes/tags.ts来处理标签相关的请求:
import { Elysia } from "elysia";
import { db } from "../db";
import { tags, postTags } from "../db/schema";
import { sql } from "drizzle-orm";
export const tagRoutes = new Elysia()
.get("/tags", async ({ render }) => {
const tagCounts = await db
.select({
id: tags.id,
name: tags.name,
count: sql<number>`count(${postTags.id})`.as('count'),
})
.from(tags)
.leftJoin(postTags, sql`${tags.id} = ${postTags.tagId}`)
.groupBy(tags.id)
.orderBy(sql`count DESC`)
.limit(20)
.all();
return render("tags/cloud", { tags: tagCounts });
});- 创建一个新的视图文件
src/views/tags/cloud.eta来显示标签云:
<% layout('../layouts/main.eta', { title: 'Tag Cloud' }) %>
<h1>Tag Cloud</h1>
<div class="tag-cloud">
<% it.tags.forEach(tag => { %>
<a href="/search?tag=<%= tag.name %>" class="tag" style="font-size: <%= 100 + tag.count * 20 %>%;">
<%= tag.name %>
</a>
<% }) %>
</div>- 更新
src/index.ts文件,添加新的标签路由:
import { tagRoutes } from "./routes/tags";
// ... 其他导入保持不变
app.use(tagRoutes);
// ... 其他代码保持不变- 更新
public/styles/main.css文件,添加标签云的样式:
/* ... 前面的样式保持不变 */
.tag-cloud {
display: flex;
flex-wrap: wrap;
justify-content: center;
padding: 20px;
}
.tag-cloud .tag {
display: inline-block;
margin: 5px;
padding: 5px 10px;
background-color: #f0f0f0;
border-radius: 15px;
color: #333;
text-decoration: none;
transition: background-color 0.3s ease;
}
.tag-cloud .tag:hover {
background-color: #e0e0e0;
}- 更新主布局文件
src/views/layouts/main.eta,添加标签云链接:
<header>
<nav>
<a href="/">Home</a>
<a href="/posts/new">New Post</a>
<% if (it.user) { %>
<a href="/logout">Logout</a>
<% } else { %>
<a href="/login">Login</a>
<a href="/register">Register</a>
<% } %>
<a href="/search">Advanced Search</a>
<a href="/tags">Tag Cloud</a>
</nav>
</header>- 更新
src/views/posts/new.eta和src/views/posts/edit.eta文件,添加标签输入字段:
<!-- ... 其他表单字段保持不变 -->
<div>
<label for="tags">Tags (comma separated):</label>
<input type="text" id="tags" name="tags" value="<%= it.post ? it.post.tags.join(', ') : '' %>">
</div>
<!-- ... -->这些更改实现了标签云和热门标签功能:
- 创建了新的数据库表来存储标签信息。
- 更新了文章创建和编辑功能,支持添加标签。
- 实现了一个标签云页面,显示最常用的标签。
- 添加了相应的样式,使标签云看起来更加美观。
主要改进包括:
- 用户可以为文章添加标签,提高内容的可发现性。
- 标签云提供了一种视觉上吸引人的方式来浏览博客的主题。
- 热门标签功能帮助用户快速了解博客的主要内容方向。
这个功能不仅提高了博客的可用性,还为用户提供了一种新的内容导航方式。
接下来,我们可以考虑添加以下功能:
- 用户头像上传
- 文章归档功能
- 评论系统
- 相关文章推荐
你希望继续哪个方向,或者有其他想法吗?