当然, 我们可以在主功能菜单中添加选择模板和设计新模板的功能按钮。这将使用户更容易自定义他们的博客外观。让我们来实现这个功能:
- 首先, 更新
src/components/Blog.tsx文件, 在主导航中添加新的按钮:
import React from 'react'
import { Theme } from '../types'
import { ThemeSelector } from './ThemeSelector'
interface BlogProps {
posts: Post[]
user: User | null
theme: Theme
availableThemes: string[]
}
export const Blog: React.FC<BlogProps> = ({ posts, user, theme, availableThemes }) => {
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}>
<h1 className={`text-4xl font-bold ${theme.colors.primary}`}>My Blog</h1>
<nav className="mt-4 space-x-4">
<a href="/" className={theme.colors.primary}>Home</a>
<a href="/stats" className={theme.colors.primary}>Statistics</a>
<a href="/select-theme" className={theme.colors.primary}>Select Theme</a>
<a href="/design-theme" className={theme.colors.primary}>Design New Theme</a>
{user ? (
<span>Welcome, {user.name}! <a href="/logout" className={theme.colors.secondary}>Logout</a></span>
) : (
<a href="/login" className={theme.colors.primary}>Login</a>
)}
</nav>
</div>
</header>
{/* 其余的组件内容保持不变 */}
</div>
)
}- 创建一个新的组件
src/components/ThemeSelector.tsx用于主题选择:
import React from 'react'
import { Theme } from '../types'
interface ThemeSelectorProps {
themes: Theme[]
currentTheme: string
onThemeChange: (themeName: string) => void
}
export const ThemeSelector: React.FC<ThemeSelectorProps> = ({ themes, currentTheme, onThemeChange }) => {
return (
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
{themes.map((theme) => (
<div
key={theme.name}
className={`p-4 rounded-lg cursor-pointer ${
theme.name === currentTheme ? 'ring-2 ring-blue-500' : ''
}`}
style={{ backgroundColor: theme.colors.background }}
onClick={() => onThemeChange(theme.name)}
>
<h3 className="text-lg font-semibold" style={{ color: theme.colors.primary }}>
{theme.name}
</h3>
<div className="mt-2 flex space-x-2">
<div className="w-6 h-6 rounded-full" style={{ backgroundColor: theme.colors.primary }}></div>
<div className="w-6 h-6 rounded-full" style={{ backgroundColor: theme.colors.secondary }}></div>
<div className="w-6 h-6 rounded-full" style={{ backgroundColor: theme.colors.accent }}></div>
</div>
</div>
))}
</div>
)
}- 创建一个新的组件
src/components/ThemeDesigner.tsx用于设计新主题:
import React, { useState } from 'react'
import { Theme } from '../types'
interface ThemeDesignerProps {
onSave: (theme: Theme) => void
}
export const ThemeDesigner: React.FC<ThemeDesignerProps> = ({ onSave }) => {
const [themeName, setThemeName] = useState('')
const [backgroundColor, setBackgroundColor] = useState('#ffffff')
const [textColor, setTextColor] = useState('#000000')
const [primaryColor, setPrimaryColor] = useState('#3b82f6')
const [secondaryColor, setSecondaryColor] = useState (' #6b7280 ')
const [accentColor, setAccentColor] = useState (' #f59e0b ')
const handleSave = () => {
const newTheme: Theme = {
name: themeName,
colors: {
background: `bg-[${backgroundColor}]`,
text: `text-[${textColor}]`,
primary: `text-[${primaryColor}]`,
secondary: `text-[${secondaryColor}]`,
accent: `text-[${accentColor}]`,
},
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-[${primaryColor}] text-white rounded hover:bg-opacity-90`,
input: `px-3 py-2 border border-[${secondaryColor}] rounded focus:ring-2 focus:ring-[${primaryColor}]`,
card: `bg-[${backgroundColor}] shadow rounded-lg overflow-hidden`,
}
}
onSave(newTheme)
}
return (
<div className="space-y-4">
<input
type="text"
placeholder="Theme Name"
value={themeName}
onChange={(e) => setThemeName(e.target.value)}
className="w-full px-3 py-2 border rounded"
/>
<div>
<label>Background Color:</label>
<input
type="color"
value={backgroundColor}
onChange={(e) => setBackgroundColor(e.target.value)}
/>
</div>
<div>
<label>Text Color:</label>
<input
type="color"
value={textColor}
onChange={(e) => setTextColor(e.target.value)}
/>
</div>
<div>
<label>Primary Color:</label>
<input
type="color"
value={primaryColor}
onChange={(e) => setPrimaryColor(e.target.value)}
/>
</div>
<div>
<label>Secondary Color:</label>
<input
type="color"
value={secondaryColor}
onChange={(e) => setSecondaryColor(e.target.value)}
/>
</div>
<div>
<label>Accent Color:</label>
<input
type="color"
value={accentColor}
onChange={(e) => setAccentColor(e.target.value)}
/>
</div>
<button onClick={handleSave} className="px-4 py-2 bg-blue-500 text-white rounded">
Save Theme
</button>
</div>
)
}- 更新
src/index.ts以添加新的路由:
import { Elysia } from 'elysia'
import { html } from '@elysiajs/html'
import { staticPlugin } from '@elysiajs/static'
import { renderToString } from 'react-dom/server'
import { Blog } from './components/Blog'
import { ThemeSelector } from './components/ThemeSelector'
import { ThemeDesigner } from './components/ThemeDesigner'
Import { themes } from './themes'
// ... 其他导入和设置
const app = new Elysia()
.use(html())
.use(staticPlugin())
// ... 其他中间件和路由
.get ('/select-theme', ({ html }) => {
const themeSelector = renderToString(
<ThemeSelector
themes={Object.values(themes)}
currentTheme={cookie.theme || 'classic'}
onThemeChange={(themeName) => {
// 这里应该是客户端JavaScript,用于更新主题
// 在服务端渲染中,我们可以提供一个表单来提交主题更改
}}
/>
)
return html(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Select Theme</title>
<link rel="stylesheet" href="/uno.css">
</head>
<body>
<div class="container mx-auto p-4">
<h1 class="text-2xl font-bold mb-4">Select Theme</h1>
<form method="POST" action="/change-theme">
${themeSelector}
<button type="submit" class="mt-4 px-4 py-2 bg-blue-500 text-white rounded">
Apply Theme
</button>
</form>
</div>
</body>
</html>
`)
})
.get('/design-theme', ({ html }) => {
const themeDesigner = renderToString(
<ThemeDesigner
onSave={(theme) => {
// 这里应该是客户端JavaScript,用于保存新主题
// 在服务端渲染中,我们可以提供一个表单来提交新主题
}}
/>
)
return html(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Design New Theme</title>
<link rel="stylesheet" href="/uno.css">
</head>
<body>
<div class="container mx-auto p-4">
<h1 class="text-2xl font-bold mb-4">Design New Theme</h1>
<form method="POST" action="/save-theme">
${themeDesigner}
</form>
</div>
</body>
</html>
`)
})
.post('/change-theme', ({ body, set, cookie }) => {
const { theme } = body as { theme: string }
cookie.theme = theme
set.redirect = '/'
})
.post('/save-theme', ({ body, set }) => {
// 这里应该处理保存新主题的逻辑
// 可能需要将新主题保存到数据库或文件系统
set.redirect = '/select-theme'
})
.listen(3000)- 更新
src/themes/index.ts文件以导出所有主题:
import classicTheme from './classic'
import modernDarkTheme from './modernDark'
import natureGreenTheme from './natureGreen'
import vibrantTheme from './vibrant'
export const themes = {
classic: classicTheme,
modernDark: modernDarkTheme,
natureGreen: natureGreenTheme,
Vibrant: vibrantTheme,
}这些更改添加了以下功能:
- 在主导航中添加了”Select Theme”和”Design New Theme”按钮。
- 创建了一个主题选择器页面, 用户可以在预定义的主题中选择。
- 创建了一个主题设计器页面, 用户可以创建自定义主题。
- 添加了处理主题更改和保存新主题的路由。
要使这个功能完全工作, 你还需要:
- 实现保存自定义主题的后端逻辑。
- 添加客户端 JavaScript 以增强用户体验, 例如实时预览主题更改。
- 考虑添加主题预览功能, 让用户在应用主题之前可以看到效果。
- 实现主题编辑功能, 允许用户修改现有主题。
- 添加主题分享功能, 让用户可以与他人分享自己创建的主题。
这些添加的功能大大增强了博客系统的可定制性, 让用户可以更容易地个性化他们的博客外观。