好的,让我们针对用户体验提升的四个方面进行优化:夜间模式切换、全站搜索功能、文章推荐系统和阅读进度指示器。这些功能将显著提升用户的使用体验。
- 夜间模式切换
首先,我们需要创建一个夜间模式的主题:
// src/themes/nightMode.ts
export default {
name: 'Night Mode',
colors: {
background: 'bg-gray-900',
text: 'text-gray-200',
primary: 'text-blue-400',
secondary: 'text-gray-400',
accent: 'text-yellow-400',
},
layout: {
container: 'max-w-4xl mx-auto px-4',
header: 'py-6',
main: 'py-8',
footer: 'py-6 text-center',
},
components: {
button: 'px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700',
input: 'px-3 py-2 bg-gray-800 border border-gray-700 rounded focus:ring-2 focus:ring-blue-500',
card: 'bg-gray-800 shadow rounded-lg overflow-hidden',
}
}然后,更新 Blog 组件以包含夜间模式切换按钮:
// src/components/Blog.tsx
import React, { useState, useEffect } from 'react'
import { Theme } from '../types'
interface BlogProps {
// ... 其他 props
initialTheme: Theme
}
export const Blog: React.FC<BlogProps> = ({ /* 其他 props */, initialTheme }) => {
const [theme, setTheme] = useState(initialTheme)
const toggleNightMode = () => {
const newTheme = theme.name === 'Night Mode' ? themes.default : themes.nightMode
setTheme(newTheme)
document.cookie = `theme=${newTheme.name};path=/;max-age=31536000`
}
return (
<div className={`min-h-screen flex flex-col ${theme.colors.background} ${theme.colors.text}`}>
<header className={theme.layout.header}>
<div className={theme.layout.container}>
{/* ... 其他头部内容 */}
<button onClick={toggleNightMode} className={theme.components.button}>
{theme.name === 'Night Mode' ? '☀️ Light Mode' : '🌙 Night Mode'}
</button>
</div>
</header>
{/* ... 其他内容 */}
</div>
)
}- 全站搜索功能
为了实现全站搜索,我们需要创建一个搜索 API 和搜索组件:
// src/index.ts
import { like } from 'drizzle-orm'
// ... 其他导入
app.get('/api/search', async ({ query }) => {
const { q } = query
if (!q) return []
const searchResults = await db.select()
.from(posts)
.where(or(
like(posts.title, `%${q}%`),
like(posts.content, `%${q}%`)
))
.limit(10)
.all()
return searchResults
})创建搜索组件:
// src/components/Search.tsx
import React, { useState } from 'react'
import { Theme } from '../types'
interface SearchProps {
theme: Theme
}
export const Search: React.FC<SearchProps> = ({ theme }) => {
const [query, setQuery] = useState('')
const [results, setResults] = useState([])
const handleSearch = async () => {
const response = await fetch(`/api/search?q=${encodeURIComponent(query)}`)
const data = await response.json()
setResults(data)
}
return (
<div>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search..."
className={theme.components.input}
/>
<button onClick={handleSearch} className={theme.components.button}>Search</button>
<ul className="mt-4">
{results.map((result) => (
<li key={result.id} className={theme.components.card + ' p-4 mb-2'}>
<a href={`/post/${result.id}`} className={theme.colors.primary}>
{result.title}
</a>
</li>
))}
</ul>
</div>
)
}- 文章推荐系统
为了实现简单的文章推荐,我们可以基于标签相似度来推荐文章:
// src/index.ts
app.get('/api/post/:id/recommendations', async ({ params }) => {
const postId = parseInt(params.id)
// 获取当前文章的标签
const currentPostTags = await db.select()
.from(postTags)
.where(eq(postTags.postId, postId))
.all()
const tagIds = currentPostTags.map(pt => pt.tagId)
// 查找具有相同标签的其他文章
const recommendedPosts = await db.select({
id: posts.id,
title: posts.title,
tagCount: sql`count(${postTags.tagId})`.as('tag_count'),
})
.from(posts)
.innerJoin(postTags, eq(posts.id, postTags.postId))
.where(and(
inArray(postTags.tagId, tagIds),
ne(posts.id, postId)
))
.groupBy(posts.id)
.orderBy(desc(sql`tag_count`), desc(posts.createdAt))
.limit(5)
.all()
return recommendedPosts
})然后在文章页面中显示推荐文章:
// src/components/PostDetail.tsx
import React, { useEffect, useState } from 'react'
import { Theme, Post } from '../types'
interface PostDetailProps {
post: Post
theme: Theme
}
export const PostDetail: React.FC<PostDetailProps> = ({ post, theme }) => {
const [recommendations, setRecommendations] = useState([])
useEffect(() => {
fetch(`/api/post/${post.id}/recommendations`)
.then(res => res.json())
.then(setRecommendations)
}, [post.id])
return (
<div>
{/* 文章内容 */}
<h1 className={`text-2xl font-bold ${theme.colors.primary}`}>{post.title}</h1>
<div className={theme.colors.text}>{post.content}</div>
{/* 推荐文章 */}
<div className="mt-8">
<h2 className={`text-xl font-semibold ${theme.colors.secondary}`}>Recommended Articles</h2>
<ul className="mt-4">
{recommendations.map((rec) => (
<li key={rec.id} className={theme.components.card + ' p-4 mb-2'}>
<a href={`/post/${rec.id}`} className={theme.colors.primary}>
{rec.title}
</a>
</li>
))}
</ul>
</div>
</div>
)
}- 阅读进度指示器
我们可以创建一个阅读进度指示器组件:
// src/components/ReadingProgress.tsx
import React, { useState, useEffect } from 'react'
import { Theme } from '../types'
interface ReadingProgressProps {
theme: Theme
}
export const ReadingProgress: React.FC<ReadingProgressProps> = ({ theme }) => {
const [progress, setProgress] = useState(0)
useEffect(() => {
const updateProgress = () => {
const scrollTop = window.scrollY
const docHeight = document.documentElement.scrollHeight - window.innerHeight
const scrollPercent = scrollTop / docHeight
setProgress(scrollPercent * 100)
}
window.addEventListener('scroll', updateProgress)
return () => window.removeEventListener('scroll', updateProgress)
}, [])
return (
<div className="fixed top-0 left-0 w-full h-1 bg-gray-200">
<div
className={`h-full ${theme.colors.primary}`}
style={{ width: `${progress}%` }}
></div>
</div>
)
}然后在 Blog 组件中使用这个进度指示器:
// src/components/Blog.tsx
import { ReadingProgress } from './ReadingProgress'
export const Blog: React.FC<BlogProps> = ({ /* 其他 props */ }) => {
return (
<div className={`min-h-screen flex flex-col ${theme.colors.background} ${theme.colors.text}`}>
<ReadingProgress theme={theme} />
{/* ... 其他内容 */}
</div>
)
}这些优化为博客系统添加了以下功能:
- 夜间模式切换:用户可以根据自己的喜好切换明暗主题。
- 全站搜索功能:用户可以快速找到感兴趣的文章。
- 文章推荐系统:基于标签相似度为用户推荐相关文章,增加用户停留时间。
- 阅读进度指示器:为用户提供直观的阅读进度反馈。
要进一步完善这些功能,你可以考虑:
- 为夜间模式添加自动切换功能,根据用户系统设置或时间自动切换。
- 改进搜索功能,添加高亮显示搜索词、搜索建议等功能。
- 优化推荐系统,考虑用户阅读历史、停留时间等因素。
- 为长文章添加目录功能,配合阅读进度指示器使用。
这些用户体验的优化将使你的博客系统更加用户友好,提高用户满意度和参与度。随着系统的发展,你可能还需要考虑性能优化,如延迟加载、代码分割等技术,以确保在添加新功能的同时保持良好的性能。