简介
部署方式
第一种对于没有基础的最为适用, 使用1Panel面板一键部署
bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)"安装过程中会提示安装docker, 安装完成后前往应用商店安装即可
第二种方式适用于稍微有点基础的, 也是最受欢迎最方便的, 使用docker安装(这里以ubuntu示例)
一. 以 root 登录服务器安装 Docker
- 更新你的包索引
apt update- 安装一些必要的依赖
apt install apt-transport-https ca-certificates curl software-properties-common- 添加Docker的官方GPG密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -- 设置仓库
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"- 更新包索引
apt update- 安装Docker CE(Community Edition)
apt install docker-ce docker-ce-cli containerd.io- 启动Docker
systemctl start docker- 设置Docker开机启动
systemctl enable docker二. 在Docker中执行一键安装脚本
在终端中输入
docker run -d \
--name upage \
--restart unless-stopped \
-p 3000:3000 \
-e LLM_PROVIDER=OpenAI \
-e PROVIDER_BASE_URL= \
-e PROVIDER_API_KEY= \
-e LLM_DEFAULT_MODEL= \
-e LLM_MINOR_MODEL= \
-v ./data:/app/data \
-v ./logs:/app/logs \
-v ./storage:/app/storage \
halohub/upage:latest参数的注释
| 参数 | 说明 |
| name upage | 容器名称 |
| restart unless-stopped | 重启方式 |
| -p 3000:3000 | 内外端口 |
| -e LLM_PROVIDER=OpenAI | 接入的AI |
| -e PROVIDER_BASE_URL | 接入地址 |
| -e PROVIDER_API_KEY | 接入的API Key |
| -e LLM_DEFAULT_MODEL | 主要模型 |
| -e LLM_MINOR_MODEL | 次要模型 |
| -v ./data:/app/data | 挂载数据的目录 |
| -v ./logs:/app/logs | 挂载日志目录 |
| -v ./storage:/app/storage | 挂载存储目录 |
| halohub/upage:latest | 下载的版本 |
三. 用Nginx设置反向代理即可访问
- 前往Nginx配置文件夹目录
cd /etc/nginx/sites-available- 使用nano创建并配置conf
sudo nano www.example.com (其中www.example.com为你的域名)3.在创建的新文件中,输入以下内容
server {
listen 80;
server_name www.example.com;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://127.0.0.1:3000;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}第三种方式是以源码方式部署, 适用于有一些技术的人使用
前置条件
Git
Nodejs
pnpm
PM2
部署方法
- 克隆代码
git clone https://github.com/halo-dev/upage.git
cd upage- 安装依赖
pnpm install- 配置环境变量
cp .env.example .env# 基础配置
PORT=3000
NODE_ENV=production
OPERATING_ENV=production
LOG_LEVEL=info
USAGE_LOG_FILE=true
MAX_UPLOAD_SIZE_MB=5
STORAGE_DIR=./storage
# AI 提供商配置
LLM_PROVIDER=OpenAI
PROVIDER_BASE_URL=your-openai-api-base-url
PROVIDER_API_KEY=your-openai-api-key
LLM_DEFAULT_MODEL=your-default-model
LLM_MINOR_MODEL=your-minor-model- 生成 Prisma 客户端
pnpm setup- 使用环境
1. 开发模式 通过浏览器输入 http://localhost:5173 访问
pnpm dev2. 生产模式 通过浏览器输入 http://localhost:3000 访问
pnpm buildpnpm preview- 通过PM2监控服务
创建 ecosystem.config.js 文件
module.exports = {
apps: [{
name: 'upage',
script: './server.mjs',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'production',
OPERATING_ENV: 'production',
PORT: 3000,
LLM_PROVIDER: 'OpenAI',
PROVIDER_BASE_URL: '接入地址',
PROVIDER_API_KEY: '接入的API Key',
LLM_DEFAULT_MODEL: '主要模型',
LLM_MINOR_MODEL: '次要模型',
}
}]
};- 启动
pm2 start ecosystem.config.js- 查看日志
pm2 logs upage- 监控
pm2 monitUpage的更新方式
# 拉取最新代码
git pull origin main
# 安装依赖
pnpm install
# 构建项目
pnpm build
# 开发环境使用
pnpm dev
# 生产环境使用
pnpm preview
# 或者如果使用 PM2
pm2 restart upage故障排除
- 如果依赖安装失败,可以尝试清除 pnpm 缓存:
pnpm store prune
pnpm install- 如果构建失败,可以尝试清除构建缓存:
pnpm clean
pnpm build- 如果遇到数据库相关错误,可以尝试重新初始化数据库
请注意,这将清空所有数据并重置数据库pnpm prisma migrate reset
- 使用检查日志文件以获取更多错误信息
cat logs/combined-*.log
cat logs/error-*.log调用自己的Ollama API
因为OpenAI已经不对国内用户开放API所以可以部署Ollama来供Upage调用
同样也可以提供其他依赖AI的程序调用
Ollama部署教程 请点击
更改配置文件.env中的参数
LLM_PROVIDER: 'Ollama',
PROVIDER_BASE_URL: 'http://IP:PROT',
PROVIDER_API_KEY: '接入的API Key', #删除此行
LLM_DEFAULT_MODEL: 'deepseek-r1',
LLM_MINOR_MODEL: 'deepseek-r1',修改完成后重启 UPage
Upage 生产的代码演示
在UPage中输入默认的语句 创建个人使用的落地页,展示我的作品以及联系方式 后生成了数套代码
请自行保存为HTML来查看效果
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>个人作品集</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: #f8f9fa;
color: #333;
line-height: 1.6;
}
header {
background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
color: white;
padding: 2rem 1rem;
text-align: center;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.profile-container {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.profile-img {
width: 150px;
height: 150px;
border-radius: 50%;
object-fit: cover;
border: 5px solid white;
margin-bottom: 1rem;
}
h1 {
font-size: 2.5rem;
margin-bottom: 0.5rem;
}
.tagline {
font-size: 1.2rem;
font-weight: 300;
}
nav {
background-color: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
position: sticky;
top: 0;
z-index: 100;
}
.nav-container {
max-width: 1200px;
margin: 0 auto;
display: flex;
justify-content: center;
}
.nav-links {
display: flex;
list-style: none;
}
.nav-links li {
padding: 1rem 0;
}
.nav-links a {
text-decoration: none;
color: #333;
font-weight: 500;
padding: 0.5rem 1rem;
transition: all 0.3s ease;
}
.nav-links a:hover {
background-color: #f1f1f1;
border-radius: 5px;
}
.nav-links a.active {
background-color: #2575fc;
color: white;
border-radius: 5px;
}
main {
max-width: 1200px;
margin: 2rem auto;
padding: 0 1rem;
}
.section-title {
text-align: center;
margin-bottom: 2rem;
color: #2575fc;
position: relative;
padding-bottom: 0.5rem;
}
.section-title::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 50px;
height: 3px;
background-color: #2575fc;
}
.portfolio-filter {
display: flex;
justify-content: center;
flex-wrap: wrap;
margin-bottom: 2rem;
}
.filter-btn {
padding: 0.5rem 1rem;
margin: 0.5rem;
background: #fff;
border: 1px solid #ddd;
border-radius: 30px;
cursor: pointer;
transition: all 0.3s ease;
}
.filter-btn:hover, .filter-btn.active {
background: #2575fc;
color: white;
border-color: #2575fc;
}
.portfolio-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
}
.portfolio-item {
background-color: #fff;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease;
}
.portfolio-item:hover {
transform: translateY(-5px);
}
.portfolio-img {
width: 100%;
height: 200px;
object-fit: cover;
}
.portfolio-content {
padding: 1.5rem;
}
.portfolio-title {
font-size: 1.2rem;
margin-bottom: 0.5rem;
color: #2575fc;
}
.portfolio-desc {
color: #666;
margin-bottom: 1rem;
font-size: 0.9rem;
}
.portfolio-tags {
display: flex;
flex-wrap: wrap;
margin-bottom: 1rem;
}
.portfolio-tag {
background-color: #f1f1f1;
color: #666;
padding: 0.2rem 0.5rem;
border-radius: 30px;
font-size: 0.8rem;
margin: 0 0.2rem;
}
.portfolio-link {
display: inline-block;
padding: 0.5rem 1rem;
background-color: #2575fc;
color: white;
text-decoration: none;
border-radius: 5px;
font-weight: 500;
transition: background-color 0.3s ease;
}
.portfolio-link:hover {
background-color: #1a67d9;
}
.contact-section {
background-color: #fff;
padding: 3rem 0;
margin: 3rem 0;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.contact-container {
max-width: 1200px;
margin: 0 auto;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}
.contact-info h3 {
margin-bottom: 1.5rem;
color: #2575fc;
}
.contact-detail {
display: flex;
align-items: center;
margin-bottom: 1rem;
}
.contact-icon {
width: 40px;
height: 40px;
background-color: #f1f1f1;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 1rem;
color: #2575fc;
}
.contact-text h4 {
font-size: 1rem;
margin-bottom: 0.2rem;
}
.contact-text p {
color: #666;
font-size: 0.9rem;
}
.contact-form {
background-color: #f8f9fa;
padding: 2rem;
border-radius: 8px;
}
.contact-form h3 {
margin-bottom: 1.5rem;
color: #2575fc;
}
.form-group {
margin-bottom: 1.5rem;
}
.form-control {
width: 100%;
padding: 0.8rem;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 1rem;
}
.form-control:focus {
outline: none;
border-color: #2575fc;
}
textarea.form-control {
min-height: 150px;
resize: vertical;
}
.btn {
display: inline-block;
padding: 0.8rem 1.5rem;
background-color: #2575fc;
color: white;
text-decoration: none;
border-radius: 5px;
font-weight: 500;
transition: background-color 0.3s ease;
border: none;
cursor: pointer;
}
.btn:hover {
background-color: #1a67d9;
}
footer {
background-color: #333;
color: white;
text-align: center;
padding: 2rem 1rem;
margin-top: 3rem;
}
.social-links {
margin-bottom: 1.5rem;
}
.social-link {
display: inline-block;
width: 40px;
height: 40px;
background-color: #2575fc;
color: white;
text-decoration: none;
margin: 0 0.5rem;
border-radius: 50%;
line-height: 40px;
transition: background-color 0.3s ease;
}
.social-link:hover {
background-color: #1a67d9;
}
.copyright {
margin-top: 1.5rem;
font-size: 0.9rem;
color: #aaa;
}
@media (max-width: 768px) {
.portfolio-grid {
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}
.contact-container {
grid-template-columns: 1fr;
}
.nav-container {
flex-direction: column;
align-items: center;
}
.nav-links {
width: 100%;
flex-wrap: wrap;
}
.nav-links li {
margin: 0.5rem;
}
}
</style>
</head>
<body>
<header>
<div class="profile-container">
<!-- 这里放置你的头像图片 -->
<img src="https://via.placeholder.com/150" alt="个人头像" class="profile-img">
<h1>你的名字</h1>
<p class="tagline">专业领域 | 职业身份</p>
</div>
</header>
<nav>
<div class="nav-container">
<ul class="nav-links">
<li><a href="#home" class="active">首页</a></li>
<li><a href="#portfolio">作品集</a></li>
<li><a href="#about">关于我</a></li>
<li><a href="#contact">联系方式</a></li>
</ul>
</div>
</nav>
<main>
<section id="home">
<h2 class="section-title">欢迎来到我的个人作品集</h2>
<p>这里展示了我最新的作品和项目,以及我的联系方式。</p>
</section>
<section id="portfolio">
<h2 class="section-title">作品集</h2>
<div class="portfolio-filter">
<button class="filter-btn active">全部</button>
<button class="filter-btn">网页设计</button>
<button class="filter-btn">UI/UX 设计</button>
<button class="filter-btn">品牌设计</button>
<button class="filter-btn">插画</button>
</div>
<div class="portfolio-grid">
<!-- 项目1 -->
<div class="portfolio-item">
<img src="https://via.placeholder.com/400x300" alt="项目图片" class="portfolio-img">
<div class="portfolio-content">
<h3 class="portfolio-title">项目标题</h3>
<p class="portfolio-desc">项目描述内容,简短介绍项目的背景和目标。</p>
<div class="portfolio-tags">
<span class="portfolio-tag">网页设计</span>
<span class="portfolio-tag">响应式</span>
</div>
<a href="#" class="portfolio-link">查看项目</a>
</div>
</div>
<!-- 项目2 -->
<div class="portfolio-item">
<img src="https://via.placeholder.com/400x300" alt="项目图片" class="portfolio-img">
<div class="portfolio-content">
<h3 class="portfolio-title">项目标题</h3>
<p class="portfolio-desc">项目描述内容,简短介绍项目的背景和目标。</p>
<div class="portfolio-tags">
<span class="portfolio-tag">UI设计</span>
<span class="portfolio-tag">用户体验</span>
</div>
<a href="#" class="portfolio-link">查看项目</a>
</div>
</div>
<!-- 项目3 -->
<div class="portfolio-item">
<img src="https://via.placeholder.com/400x300" alt="项目图片" class="portfolio-img">
<div class="portfolio-content">
<h3 class="portfolio-title">项目标题</h3>
<p class="portfolio-desc">项目描述内容,简短介绍项目的背景和目标。</p>
<div class="portfolio-tags">
<span class="portfolio-tag">品牌设计</span>
<span class="portfolio-tag">标识设计</span>
</div>
<a href="#" class="portfolio-link">查看项目</a>
</div>
</div>
<!-- 项目4 -->
<div class="portfolio-item">
<img src="https://via.placeholder.com/400x300" alt="项目图片" class="portfolio-img">
<div class="portfolio-content">
<h3 class="portfolio-title">项目标题</h3>
<p class="portfolio-desc">项目描述内容,简短介绍项目的背景和目标。</p>
<div class="portfolio-tags">
<span class="portfolio-tag">网页设计</span>
<span class="portfolio-tag">前端开发</span>
</div>
<a href="#" class="portfolio-link">查看项目</a>
</div>
</div>
<!-- 项目5 -->
<div class="portfolio-item">
<img src="https://via.placeholder.com/400x300" alt="项目图片" class="portfolio-img">
<div class="portfolio-content">
<h3 class="portfolio-title">项目标题</h3>
<p class="portfolio-desc">项目描述内容,简短介绍项目的背景和目标。</p>
<div class="portfolio-tags">
<span class="portfolio-tag">UI/UX设计</span>
<span class="portfolio-tag">用户研究</span>
</div>
<a href="#" class="portfolio-link">查看项目</a>
</div>
</div>
<!-- 项目6 -->
<div class="portfolio-item">
<img src="https://via.placeholder.com/400x300" alt="项目图片" class="portfolio-img">
<div class="portfolio-content">
<h3 class="portfolio-title">项目标题</h3>
<p class="portfolio-desc">项目描述内容,简短介绍项目的背景和目标。</p>
<div class="portfolio-tags">
<span class="portfolio-tag">插画</span>
<span class="portfolio-tag">数字绘画</span>
</div>
<a href="#" class="portfolio-link">查看项目</a>
</div>
</div>
</div>
</section>
<section id="about">
<h2 class="section-title">关于我</h2>
<p>这里是关于你的详细介绍,包括你的教育背景、工作经验、专业技能和个人风格等。</p>
</section>
<section id="contact">
<div class="contact-section">
<div class="contact-container">
<div class="contact-info">
<h3>联系信息</h3>
<div class="contact-detail">
<div class="contact-icon">??</div>
<div class="contact-text">
<h4>电子邮件</h4>
<p>your.email@example.com</p>
</div>
</div>
<div class="contact-detail">
<div class="contact-icon">??</div>
<div class="contact-text">
<h4>电话</h4>
<p>+86 123 4567 890</p>
</div>
</div>
<div class="contact-detail">
<div class="contact-icon">??</div>
<div class="contact-text">
<h4>地址</h4>
<p>中国,某个城市</p>
</div>
</div>
<div class="contact-detail">
<div class="contact-icon">??</div>
<div class="contact-text">
<h4>社交媒体</h4>
<p>链接到你的社交媒体账号</p>
</div>
</div>
</div>
<div class="contact-form">
<h3>发送消息</h3>
<form>
<div class="form-group">
<input type="text" class="form-control" placeholder="你的名字">
</div>
<div class="form-group">
<input type="email" class="form-control" placeholder="你的邮箱">
</div>
<div class="form-group">
<textarea class="form-control" placeholder="你的消息"></textarea>
</div>
<button type="submit" class="btn">发送消息</button>
</form>
</div>
</div>
</div>
</section>
</main>
<footer>
<div class="social-links">
<a href="#" class="social-link">f</a>
<a href="#" class="social-link">in</a>
<a href="#" class="social-link">ig</a>
<a href="#" class="social-link">tw</a>
</div>
<p class="copyright">? 2023 你的名字。保留所有权利。</p>
</footer>
<script>
// 简单的导航菜单交互
document.addEventListener('DOMContentLoaded', function() {
const navLinks = document.querySelectorAll('.nav-links a');
navLinks.forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
// 移除所有链接的active类
navLinks.forEach(item => item.classList.remove('active'));
// 为当前点击的链接添加active类
this.classList.add('active');
// 在实际应用中,这里应该平滑滚动到对应的部分
// window.location.hash = this.getAttribute('href').substring(1);
});
});
// 简单的过滤器功能
const filterButtons = document.querySelectorAll('.filter-btn');
const portfolioItems = document.querySelectorAll('.portfolio-item');
filterButtons.forEach(button => {
button.addEventListener('click', function() {
// 移除所有按钮的active类
filterButtons.forEach(btn => btn.classList.remove('active'));
// 为当前点击的按钮添加active类
this.classList.add('active');
const filter = this.textContent;
portfolioItems.forEach(item => {
if (filter === '全部') {
item.style.display = 'block';
} else {
const tags = item.querySelector('.portfolio-tags');
if (tags) {
const tagsArray = Array.from(tags.querySelectorAll('span'));
if (tagsArray.some(tag => tag.textContent === filter)) {
item.style.display = 'block';
} else {
item.style.display = 'none';
}
} else {
item.style.display = 'none';
}
}
});
});
});
// 表单提交处理
const contactForm = document.querySelector('.contact-form form');
if (contactForm) {
contactForm.addEventListener('submit', function(e) {
e.preventDefault();
alert('消息已发送!在实际应用中,这里应该有表单提交的处理逻辑。');
});
}
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>个人作品集</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<style>
/* 基础样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #333;
background-color: #f9f9f9;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* 导航栏样式 */
header {
background-color: #fff;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
position: fixed;
width: 100%;
top: 0;
z-index: 1000;
}
nav {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 0;
}
.logo {
font-size: 24px;
font-weight: 700;
color: #3498db;
text-decoration: none;
}
.nav-links {
display: flex;
list-style: none;
}
.nav-links li {
margin-left: 30px;
}
.nav-links a {
text-decoration: none;
color: #333;
font-weight: 500;
transition: color 0.3s;
}
.nav-links a:hover {
color: #3498db;
}
/* 英雄区域样式 */
.hero {
padding: 150px 0 100px;
text-align: center;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
}
.hero h1 {
font-size: 48px;
margin-bottom: 20px;
color: #2c3e50;
}
.hero p {
font-size: 20px;
color: #7f8c8d;
max-width: 700px;
margin: 0 auto;
}
/* 作品集过滤器 */
.portfolio-filter {
margin: 40px 0;
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 10px;
}
.filter-btn {
background-color: #fff;
border: 1px solid #ddd;
padding: 8px 20px;
border-radius: 30px;
cursor: pointer;
transition: all 0.3s;
}
.filter-btn:hover, .filter-btn.active {
background-color: #3498db;
color: #fff;
border-color: #3498db;
}
/* 作品网格 */
.portfolio-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 30px;
margin-top: 40px;
}
.portfolio-item {
background-color: #fff;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
transition: transform 0.3s, box-shadow 0.3s;
}
.portfolio-item:hover {
transform: translateY(-10px);
box-shadow: 0 15px 30px rgba(0,0,0,0.15);
}
.portfolio-img {
width: 100%;
height: 250px;
object-fit: cover;
}
.portfolio-content {
padding: 20px;
}
.portfolio-title {
font-size: 22px;
margin-bottom: 10px;
color: #2c3e50;
}
.portfolio-desc {
color: #7f8c8d;
margin-bottom: 15px;
}
.portfolio-tags {
display: flex;
flex-wrap: wrap;
margin-bottom: 15px;
}
.portfolio-tag {
background-color: #ecf0f1;
color: #7f8c8d;
padding: 4px 10px;
border-radius: 15px;
font-size: 12px;
margin-right: 5px;
margin-bottom: 5px;
}
.portfolio-link {
display: inline-block;
background-color: #3498db;
color: #fff;
padding: 8px 20px;
border-radius: 30px;
text-decoration: none;
font-weight: 500;
transition: background-color 0.3s;
}
.portfolio-link:hover {
background-color: #2980b9;
}
/* 关于我部分 */
.about {
padding: 80px 0;
background-color: #fff;
}
.about-content {
display: flex;
align-items: center;
gap: 50px;
}
.about-img {
flex: 1;
}
.about-img img {
width: 100%;
border-radius: 10px;
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}
.about-text {
flex: 1;
}
.about-text h2 {
font-size: 36px;
margin-bottom: 20px;
color: #2c3e50;
}
.about-text p {
margin-bottom: 20px;
color: #555;
}
/* 联系部分 */
.contact {
padding: 80px 0;
background-color: #f5f7fa;
}
.contact-form {
max-width: 600px;
margin: 0 auto;
background-color: #fff;
padding: 40px;
border-radius: 10px;
box-shadow: 0 5px 15px rgba(0,0,0,0.05);
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
}
.form-group input,
.form-group textarea {
width: 100%;
padding: 12px;
border: 1px solid #ddd;
border-radius: 5px;
font-family: inherit;
}
.form-group textarea {
height: 150px;
resize: vertical;
}
.submit-btn {
background-color: #3498db;
color: #fff;
border: none;
padding: 12px 30px;
border-radius: 30px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: background-color 0.3s;
}
.submit-btn:hover {
background-color: #2980b9;
}
/* 页脚 */
footer {
background-color: #2c3e50;
color: #ecf0f1;
padding: 40px 0;
text-align: center;
}
.social-icons {
margin-bottom: 20px;
}
.social-icons a {
display: inline-block;
color: #fff;
font-size: 20px;
margin: 0 10px;
text-decoration: none;
transition: color 0.3s;
}
.social-icons a:hover {
color: #3498db;
}
.copyright {
font-size: 14px;
color: #bdc3c7;
}
/* 响应式设计 */
@media (max-width: 768px) {
.hero h1 {
font-size: 36px;
}
.about-content {
flex-direction: column;
}
.portfolio-grid {
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}
.nav-links {
display: none;
}
.menu-toggle {
display: block;
font-size: 24px;
cursor: pointer;
}
}
</style>
</head>
<body>
<!-- 导航栏 -->
<header>
<div class="container">
<nav>
<a href="#" class="logo">个人作品集</a>
<ul class="nav-links">
<li><a href="#home">首页</a></li>
<li><a href="#portfolio">作品集</a></li>
<li><a href="#about">关于我</a></li>
<li><a href="#contact">联系方式</a></li>
</ul>
</nav>
</div>
</header>
<!-- 英雄区域 -->
<section class="hero" id="home">
<div class="container">
<h1>欢迎来到我的作品集</h1>
<p>我是一名专业的设计师,专注于创造美观且功能性强的数字体验。浏览我的作品,了解我的创意过程。</p>
</div>
</section>
<!-- 作品集部分 -->
<section class="portfolio" id="portfolio">
<div class="container">
<h2 style="text-align: center; margin-bottom: 40px; color: #2c3e50; font-size: 36px;">我的作品</h2>
<!-- 过滤器 -->
<div class="portfolio-filter">
<button class="filter-btn active" data-filter="all">全部</button>
<button class="filter-btn" data-filter="web">网页设计</button>
<button class="filter-btn" data-filter="app">应用设计</button>
<button class="filter-btn" data-filter="brand">品牌设计</button>
<button class="filter-btn" data-filter="ui">UI/UX设计</button>
</div>
<!-- 作品网格 -->
<div class="portfolio-grid">
<!-- 作品1 -->
<div class="portfolio-item" data-category="web">
<img src="https://images.unsplash.com/photo-1547658719-da2b51169166?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60" alt="网页设计项目" class="portfolio-img">
<div class="portfolio-content">
<h3 class="portfolio-title">电子商务网站设计</h3>
<p class="portfolio-desc">为时尚品牌打造的现代电子商务平台,注重用户体验和转化率。</p>
<div class="portfolio-tags">
<span class="portfolio-tag">网页设计</span>
<span class="portfolio-tag">UX研究</span>
<span class="portfolio-tag">前端开发</span>
</div>
<a href="#" class="portfolio-link">查看详情</a>
</div>
</div>
<!-- 作品2 -->
<div class="portfolio-item" data-category="app">
<img src="https://images.unsplash.com/photo-1512820790803-83ca734da794?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60" alt="应用设计项目" class="portfolio-img">
<div class="portfolio-content">
<h3 class="portfolio-title">健康管理APP</h3>
<p class="portfolio-desc">一款帮助用户追踪健康数据和健身目标的应用程序,界面简洁易用。</p>
<div class="portfolio-tags">
<span class="portfolio-tag">应用设计</span>
<span class="portfolio-tag">交互设计</span>
<span class="portfolio-tag">UI设计</span>
</div>
<a href="#" class="portfolio-link">查看详情</a>
</div>
</div>
<!-- 作品3 -->
<div class="portfolio-item" data-category="brand">
<img src="https://images.unsplash.com/photo-1560419340-f0a57133592d?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60" alt="品牌设计项目" class="portfolio-img">
<div class="portfolio-content">
<h3 class="portfolio-title">咖啡品牌重塑</h3>
<p class="portfolio-desc">为知名咖啡连锁店重新设计品牌形象,包括标志、色彩和整体视觉识别系统。</p>
<div class="portfolio-tags">
<span class="portfolio-tag">品牌设计</span>
<span class="portfolio-tag">标志设计</span>
<span class="portfolio-tag">色彩系统</span>
</div>
<a href="#" class="portfolio-link">查看详情</a>
</div>
</div>
<!-- 作品4 -->
<div class="portfolio-item" data-category="ui">
<img src="https://images.unsplash.com/photo-1555066931-4365d14bab8c?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60" alt="UI/UX设计项目" class="portfolio-img">
<div class="portfolio-content">
<h3 class="portfolio-title">金融平台用户界面</h3>
<p class="portfolio-desc">为在线金融服务平台设计直观易用的用户界面,提高用户满意度和任务完成率。</p>
<div class="portfolio-tags">
<span class="portfolio-tag">UI设计</span>
<span class="portfolio-tag">UX设计</span>
<span class="portfolio-tag">用户研究</span>
</div>
<a href="#" class="portfolio-link">查看详情</a>
</div>
</div>
<!-- 作品5 -->
<div class="portfolio-item" data-category="web">
<img src="https://images.unsplash.com/photo-1551650975-87deedd944c3?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60" alt="网页设计项目" class="portfolio-img">
<div class="portfolio-content">
<h3 class="portfolio-title">教育平台设计</h3>
<p class="portfolio-desc">为在线教育平台设计的响应式界面,支持多种设备上的学习体验。</p>
<div class="portfolio-tags">
<span class="portfolio-tag">网页设计</span>
<span class="portfolio-tag">响应式设计</span>
<span class="portfolio-tag">内容架构</span>
</div>
<a href="#" class="portfolio-link">查看详情</a>
</div>
</div>
<!-- 作品6 -->
<div class="portfolio-item" data-category="app">
<img src="https://images.unsplash.com/photo-1545239351-1196d5a22b1b?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60" alt="应用设计项目" class="portfolio-img">
<div class="portfolio-content">
<h3 class="portfolio-title">旅行规划应用</h3>
<p class="portfolio-desc">一款帮助用户规划旅行和管理行程的应用,提供直观的地图和日历视图。</p>
<div class="portfolio-tags">
<span class="portfolio-tag">应用设计</span>
<span class="portfolio-tag">地图集成</span>
<span class="portfolio-tag">任务管理</span>
</div>
<a href="#" class="portfolio-link">查看详情</a>
</div>
</div>
</div>
</div>
</section>
<!-- 关于我部分 -->
<section class="about" id="about">
<div class="container">
<div class="about-content">
<div class="about-img">
<img src="https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80" alt="关于我">
</div>
<div class="about-text">
<h2>关于我</h2>
<p>我是一名充满激情的设计师,拥有超过5年的设计经验。我的职业生涯专注于创造引人入胜的用户体验和视觉吸引力强的设计。</p>
<p>我擅长理解客户需求并将其转化为创新的设计解决方案。我相信设计不仅仅是外观,更是关于如何改善人们的生活和工作方式。</p>
<p>在我的职业生涯中,我有幸与各种规模的公司合作,从初创企业到大型企业,帮助他们通过设计提升品牌价值和用户参与度。</p>
<a href="#" class="portfolio-link">下载简历</a>
</div>
</div>
</div>
</section>
<!-- 联系部分 -->
<section class="contact" id="contact">
<div class="container">
<h2 style="text-align: center; margin-bottom: 40px; color: #2c3e50; font-size: 36px;">联系我</h2>
<div class="contact-form">
<div class="form-group">
<label for="name">姓名</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">电子邮箱</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="message">留言</label>
<textarea id="message" name="message" required></textarea>
</div>
<button type="submit" class="submit-btn">发送消息</button>
</div>
</div>
</section>
<!-- 页脚 -->
<footer>
<div class="container">
<div class="social-icons">
<a href="#"><i class="fab fa-facebook-f"></i></a>
<a href="#"><i class="fab fa-twitter"></i></a>
<a href="#"><i class="fab fa-instagram"></i></a>
<a href="#"><i class="fab fa-linkedin-in"></i></a>
</div>
<p class="copyright">© 2023 个人作品集. 保留所有权利。</p>
</div>
</footer>
<script>
// 简单的过滤器功能
document.addEventListener('DOMContentLoaded', function() {
const filterButtons = document.querySelectorAll('.filter-btn');
const portfolioItems = document.querySelectorAll('.portfolio-item');
filterButtons.forEach(button => {
button.addEventListener('click', function() {
// 移除所有按钮的active类
filterButtons.forEach(btn => btn.classList.remove('active'));
// 给当前按钮添加active类
this.classList.add('active');
const filter = this.getAttribute('data-filter');
portfolioItems.forEach(item => {
if (filter === 'all') {
item.style.display = 'block';
} else {
if (item.getAttribute('data-category') === filter) {
item.style.display = 'block';
} else {
item.style.display = 'none';
}
}
});
});
});
// 平滑滚动
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
document.querySelector(this.getAttribute('href')).scrollIntoView({
behavior: 'smooth'
});
});
});
});
</script>
</body>
</html><!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>个人网站</title>
<style>
/* CSS变量定义 */
:root {
--primary-color: #3498db;
--secondary-color: #2980b9;
--dark-color: #2c3e50;
--light-color: #ecf0f1;
--text-color: #333;
--text-light: #777;
--border-radius: 4px;
--box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
--transition: all 0.3s ease;
}
/* 重置样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: var(--text-color);
background-color: var(--light-color);
overflow-x: hidden;
}
/* 布局容器 */
.container {
width: 90%;
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* 导航栏样式 */
header {
background-color: var(--dark-color);
color: white;
padding: 20px 0;
position: fixed;
width: 100%;
top: 0;
left: 0;
z-index: 1000;
box-shadow: var(--box-shadow);
}
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
color: white;
text-decoration: none;
}
.nav-links {
display: flex;
list-style: none;
}
.nav-links li {
margin-left: 30px;
}
.nav-links a {
color: white;
text-decoration: none;
font-weight: 500;
transition: var(--transition);
}
.nav-links a:hover {
color: var(--primary-color);
}
.hamburger {
display: none;
cursor: pointer;
font-size: 1.5rem;
}
/* 页面内容 */
main {
margin-top: 100px;
}
section {
padding: 80px 0;
}
.section-title {
text-align: center;
margin-bottom: 50px;
}
/* 英雄区域 */
#hero {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--light-color);
}
.hero-content {
text-align: center;
}
.hero-content h1 {
font-size: 3rem;
margin-bottom: 20px;
}
.hero-content p {
font-size: 1.2rem;
margin-bottom: 30px;
}
/* 关于部分 */
#about {
background-color: white;
}
.about-content {
display: flex;
align-items: center;
justify-content: space-between;
}
.about-text {
flex: 1;
padding-right: 40px;
}
.about-text h2 {
font-size: 2rem;
margin-bottom: 20px;
}
.skills-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 20px;
}
.skill-item {
background-color: #eee;
padding: 20px;
border-radius: var(--border-radius);
text-align: center;
}
.skill-item i {
font-size: 2rem;
color: var(--primary-color);
margin-bottom: 10px;
}
/* 项目部分 */
.projects-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 30px;
}
.project-card {
background-color: white;
border-radius: var(--border-radius);
overflow: hidden;
box-shadow: var(--box-shadow);
}
.project-image {
height: 200px;
background-color: #eee;
background-size: cover;
background-position: center;
}
.project-content {
padding: 20px;
}
.project-content h3 {
font-size: 1.2rem;
margin-bottom: 10px;
}
/* 联系部分 */
#contact {
background-color: var(--light-color);
}
.contact-form {
max-width: 600px;
margin: 0 auto;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: 500;
}
.form-group input,
.form-group textarea {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: var(--border-radius);
}
.form-group textarea {
height: 150px;
}
.submit-btn {
background-color: var(--primary-color);
color: white;
border: none;
padding: 10px 30px;
border-radius: var(--border-radius);
cursor: pointer;
font-weight: 500;
transition: var(--transition);
}
.submit-btn:hover {
background-color: var(--secondary-color);
}
/* 页脚 */
footer {
background-color: var(--dark-color);
color: white;
padding: 40px 0;
text-align: center;
}
.social-links {
margin-bottom: 20px;
}
.social-links a {
color: white;
margin: 0 10px;
font-size: 1.5rem;
text-decoration: none;
}
/* 动画效果 */
.animate-on-scroll {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.5s ease, transform 0.5s ease;
}
.animate-on-scroll.active {
opacity: 1;
transform: translateY(0);
}
/* 响应式设计 */
@media (max-width: 768px) {
.navbar {
display: flex;
flex-direction: column;
align-items: flex-start;
}
.hamburger {
display: block;
position: absolute;
top: 20px;
right: 20px;
}
.nav-links {
width: 100%;
flex-direction: column;
display: none;
margin-top: 20px;
}
.nav-links.active {
display: flex;
}
.nav-links li {
margin: 10px 0;
}
.about-content {
flex-direction: column;
}
.about-text {
padding-right: 0;
margin-bottom: 30px;
}
}
/* 页面加载动画 */
.page-loading {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: var(--dark-color);
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
transition: background-color 0.5s ease;
}
</style>
<script>
// 页面加载动画
document.addEventListener('DOMContentLoaded', function() {
// 显示加载动画,然后在一段时间后隐藏
const loadingScreen = document.querySelector('.page-loading');
setTimeout(function() {
loadingScreen.style.display = 'none';
}, 1500);
// 响应式导航菜单
const hamburger = document.querySelector('.hamburger');
const navLinks = document.querySelector('.nav-links');
hamburger.addEventListener('click', function() {
navLinks.classList.toggle('active');
});
// 平滑滚动
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function(e) {
e.preventDefault();
document.querySelector(this.getAttribute('href')).scrollIntoView({
behavior: 'smooth'
});
// 如果是在移动设备上,点击菜单项后关闭菜单
if (window.innerWidth <= 768) {
navLinks.classList.remove('active');
}
});
});
// 滚动时添加导航栏样式
const navbar = document.querySelector('.navbar');
window.addEventListener('scroll', function() {
if (window.scrollY > 50) {
navbar.style.background = 'rgba(44, 62, 80, 0.9)';
navbar.style.padding = '10px 0';
} else {
navbar.style.background = 'var(--dark-color)';
navbar.style.padding = '20px 0';
}
});
// 滚动动画
const animateOnScroll = function() {
const elements = document.querySelectorAll('.animate-on-scroll');
elements.forEach(element => {
const elementPosition = element.getBoundingClientRect().top;
const screenPosition = window.innerHeight * 0.85;
if (elementPosition < screenPosition) {
element.classList.add('active');
}
});
};
// 初始调用一次
animateOnScroll();
// 添加滚动事件监听器
window.addEventListener('scroll', animateOnScroll);
});
</script>
</head>
<body>
<!-- 页面加载动画 -->
<div class="page-loading">
<div class="spinner"></div>
</div>
<!-- 导航栏 -->
<header>
<div class="container">
<nav class="navbar">
<a href="#" class="logo">个人网站</a>
<ul class="nav-links">
<li><a href="#hero">首页</a></li>
<li><a href="#about">关于</a></li>
<li><a href="#projects">项目</a></li>
<li><a href="#contact">联系</a></li>
</ul>
<div class="hamburger">
☰
</div>
</nav>
</div>
</header>
<!-- 主要内容 -->
<main>
<!-- 英雄区域 -->
<section id="hero">
<div class="container">
<div class="hero-content animate-on-scroll">
<h1>欢迎来到我的个人网站</h1>
<p>我是前端开发工程师,专注于创建美观且功能强大的Web应用。</p>
<a href="#about" class="btn">了解更多</a>
</div>
</div>
</section>
<!-- 关于部分 -->
<section id="about">
<div class="container">
<h2 class="section-title">关于我</h2>
<div class="about-content">
<div class="about-text animate-on-scroll">
<h2>我是谁?</h2>
<p>我是一名前端开发工程师,拥有丰富的Web开发经验。我热爱创造能够改变人们生活方式的产品,并致力于通过代码解决实际问题。</p>
<p>我的专长包括HTML、CSS、JavaScript以及各种前端框架和库。我始终关注最新的Web技术趋势,并不断学习和提升自己的技能。</p>
</div>
<div class="skills-container">
<div class="skill-item animate-on-scroll">
<i>HTML5</i>
<p>精通</p>
</div>
<div class="skill-item animate-on-scroll">
<i>CSS3</i>
<p>精通</p>
</div>
<div class="skill-item animate-on