feat: 添加主页组件并设为默认首页

- 新增 HomePage.vue 主页组件 (玻璃态设计风格)
- GlobalSidebar logo 改为可点击跳转主页
- 默认页面从 writer 改为 home
- 新增玻璃态 CSS 变量支持

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
empty
2026-01-12 03:56:40 +08:00
parent 2c664f77d8
commit 4212b63df2
5 changed files with 621 additions and 27 deletions

View File

@@ -1,13 +1,18 @@
<template>
<aside class="sidebar">
<!-- Logo/Home -->
<div class="sidebar-logo" title="AI 写作工坊">
<button
class="sidebar-logo"
:class="{ active: currentPage === 'home' }"
title="主页"
@click="switchPage('home')"
>
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2L2 7L12 12L22 7L12 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2 17L12 22L22 17" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2 12L12 17L22 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
</button>
<!-- 导航项 -->
<nav class="sidebar-nav">
@@ -99,6 +104,10 @@ const switchPage = (page) => {
margin-bottom: var(--space-8);
color: var(--accent-primary);
transition: all var(--transition-normal);
background: transparent;
border: none;
border-radius: var(--radius-lg);
cursor: pointer;
}
.sidebar-logo:hover {
@@ -106,6 +115,10 @@ const switchPage = (page) => {
transform: scale(1.05);
}
.sidebar-logo.active {
background: var(--info-bg);
}
.sidebar-logo svg {
width: 100%;
height: 100%;

541
src/components/HomePage.vue Normal file
View File

@@ -0,0 +1,541 @@
<template>
<div class="home-page">
<!-- Dynamic Background Decor -->
<div class="bg-decor">
<div class="blob blob-1"></div>
<div class="blob blob-2"></div>
<div class="blob blob-3"></div>
</div>
<!-- Hero Section -->
<header class="home-hero glass">
<div class="hero-content">
<div class="hero-icon-wrapper">
<div class="hero-icon-glow"></div>
<div class="hero-icon">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2L2 7L12 12L22 7L12 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2 17L12 22L22 17" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2 12L12 17L22 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
</div>
<h1 class="hero-title">AI 写作工坊</h1>
<p class="hero-subtitle">结构化内容生成平台</p>
<p class="hero-description">
通过智能范式系统实现高质量规范化的内容生成
</p>
</div>
</header>
<!-- Stats Section -->
<section class="home-stats">
<div v-for="stat in statConfig" :key="stat.label" class="stat-card glass-card">
<div class="stat-icon" :style="{ color: stat.color }">
<IconLibrary :name="stat.icon" :size="24" />
</div>
<div class="stat-info">
<span class="stat-value text-glow" :style="{ '--glow-color': stat.color }">{{ stats[stat.key] }}</span>
<span class="stat-label">{{ stat.label }}</span>
</div>
</div>
</section>
<!-- Content Sections Grid -->
<div class="content-grid">
<!-- Quick Actions -->
<section class="home-section quick-actions-section">
<h2 class="section-title">
<IconLibrary name="sparkles" :size="18" />
<span>快速开始</span>
</h2>
<div class="action-list">
<button
v-for="action in quickActions"
:key="action.id"
@click="navigateTo(action.id)"
class="action-card glass-card"
>
<div class="action-icon-box" :style="{ background: action.gradient }">
<IconLibrary :name="action.icon" :size="24" />
</div>
<div class="action-content">
<h3 class="action-title">{{ action.title }}</h3>
<p class="action-desc">{{ action.description }}</p>
</div>
<div class="action-arrow-box">
<IconLibrary name="expand" :size="16" class="action-arrow" />
</div>
</button>
</div>
</section>
<!-- All Features -->
<section class="home-section all-features-section">
<h2 class="section-title">
<IconLibrary name="list" :size="18" />
<span>全部功能</span>
</h2>
<div class="feature-grid">
<button
v-for="feature in features"
:key="feature.id"
@click="navigateTo(feature.id)"
class="feature-card glass-card"
>
<div class="feature-icon-wrapper">
<IconLibrary :name="feature.icon" :size="24" />
</div>
<span class="feature-name">{{ feature.name }}</span>
</button>
</div>
</section>
</div>
<!-- Footer -->
<footer class="home-footer">
<div class="footer-divider"></div>
<p class="footer-text">Pro · 基于 DeepSeek API · 极简高效</p>
</footer>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useAppStore } from '../stores/app'
import { useDatabaseStore } from '../stores/database'
import { getParadigmList } from '../config/paradigms'
import IconLibrary from './icons/IconLibrary.vue'
const appStore = useAppStore()
const dbStore = useDatabaseStore()
// 统计数据
const stats = ref({
documents: 0,
materials: 0,
paradigms: 0
})
const statConfig = [
{ key: 'documents', label: '文稿', icon: 'folder', color: '#60a5fa' },
{ key: 'materials', label: '素材', icon: 'chart', color: '#34d399' },
{ key: 'paradigms', label: '范式', icon: 'analysis', color: '#c084fc' }
]
// 快速操作
const quickActions = [
{
id: 'writer',
title: 'AI 写作',
description: '智能生成高质量内容',
icon: 'edit',
gradient: 'linear-gradient(135deg, #3b82f6, #6366f1)'
},
{
id: 'rewrite',
title: '范式润色',
description: '按范式标准优化文章',
icon: 'sparkles',
gradient: 'linear-gradient(135deg, #f59e0b, #ef4444)'
},
{
id: 'analysis',
title: '范式库',
description: '管理和创建写作范式',
icon: 'analysis',
gradient: 'linear-gradient(135deg, #10b981, #06b6d4)'
}
]
// 全部功能
const features = [
{ id: 'writer', name: 'AI 写作', icon: 'edit' },
{ id: 'analysis', name: '范式库', icon: 'analysis' },
{ id: 'paradigmWriter', name: '范式写作', icon: 'article' },
{ id: 'documents', name: '文稿库', icon: 'folder' },
{ id: 'materials', name: '素材库', icon: 'chart' },
{ id: 'rewrite', name: '范式润色', icon: 'sparkles' },
{ id: 'compare', name: '对照检查', icon: 'compare' },
{ id: 'diffAnnotation', name: '差异标注', icon: 'chart' }
]
// 导航
const navigateTo = (page) => {
appStore.setCurrentPage(page)
}
// 加载统计数据
onMounted(() => {
// 获取范式数量
const defaultParadigms = getParadigmList()
const customParadigms = JSON.parse(localStorage.getItem('customParadigms') || '[]')
stats.value.paradigms = defaultParadigms.length + customParadigms.length
// 获取文稿和素材数量
stats.value.documents = dbStore.documents?.length || 0
stats.value.materials = dbStore.references?.length || 0
})
</script>
<style scoped>
.home-page {
flex: 1;
overflow-y: auto;
padding: var(--space-8);
background: var(--bg-primary);
position: relative;
z-index: 1;
}
/* Background Decor */
.bg-decor {
position: fixed;
inset: 0;
overflow: hidden;
z-index: -1;
pointer-events: none;
}
.blob {
position: absolute;
width: 400px;
height: 400px;
background: radial-gradient(circle, rgba(96, 165, 250, 0.15) 0%, transparent 70%);
border-radius: 50%;
filter: blur(60px);
animation: float 20s infinite alternate cubic-bezier(0.45, 0, 0.55, 1);
}
.blob-1 { top: -100px; left: -100px; animation-delay: 0s; }
.blob-2 { bottom: -150px; right: -100px; background: radial-gradient(circle, rgba(192, 132, 252, 0.1) 0%, transparent 70%); animation-delay: -5s; }
.blob-3 { top: 20%; right: 10%; background: radial-gradient(circle, rgba(52, 211, 153, 0.08) 0%, transparent 70%); animation-delay: -10s; }
@keyframes float {
from { transform: translate(0, 0) scale(1); }
to { transform: translate(100px, 50px) scale(1.1); }
}
/* Glass Effect */
.glass {
background: var(--glass-bg);
backdrop-filter: blur(var(--glass-blur));
-webkit-backdrop-filter: blur(var(--glass-blur));
border: 1px solid var(--glass-border);
box-shadow: var(--shadow-xl);
}
.glass-card {
background: var(--glass-bg);
backdrop-filter: blur(var(--glass-blur));
-webkit-backdrop-filter: blur(var(--glass-blur));
border: 1px solid var(--glass-border);
transition: all var(--transition-normal);
}
.glass-card:hover {
background: var(--glass-bg-hover);
border-color: rgba(255, 255, 255, 0.2);
transform: translateY(-4px);
box-shadow: var(--shadow-xl), var(--shadow-glow);
}
/* Hero Section */
.home-hero {
text-align: center;
padding: var(--space-12) var(--space-6);
margin-bottom: var(--space-10);
border-radius: var(--radius-2xl);
position: relative;
overflow: hidden;
}
.home-hero::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg, rgba(96, 165, 250, 0.05) 0%, transparent 50%, rgba(192, 132, 252, 0.05) 100%);
}
.hero-content {
position: relative;
z-index: 2;
max-width: 600px;
margin: 0 auto;
}
.hero-icon-wrapper {
position: relative;
display: inline-flex;
margin-bottom: var(--space-6);
}
.hero-icon-glow {
position: absolute;
inset: -10px;
background: var(--accent-primary);
filter: blur(20px);
opacity: 0.3;
border-radius: var(--radius-xl);
}
.hero-icon {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
width: 80px;
height: 80px;
background: linear-gradient(135deg, var(--accent-primary), #c084fc);
border-radius: var(--radius-xl);
color: white;
box-shadow: 0 10px 25px rgba(96, 165, 250, 0.4);
}
.hero-title {
font-size: var(--text-3xl);
font-weight: var(--font-bold);
color: var(--text-primary);
margin-bottom: var(--space-2);
letter-spacing: -0.02em;
}
.hero-subtitle {
font-size: var(--text-lg);
font-weight: var(--font-medium);
color: var(--accent-primary);
margin-bottom: var(--space-4);
background: linear-gradient(90deg, var(--accent-primary), #c084fc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.hero-description {
font-size: var(--text-base);
color: var(--text-secondary);
line-height: 1.6;
}
/* Stats Section */
.home-stats {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--space-6);
margin-bottom: var(--space-10);
}
.stat-card {
display: flex;
align-items: center;
gap: var(--space-4);
padding: var(--space-6);
border-radius: var(--radius-xl);
}
.stat-icon {
display: flex;
align-items: center;
justify-content: center;
width: 52px;
height: 52px;
background: rgba(255, 255, 255, 0.05);
border-radius: var(--radius-lg);
flex-shrink: 0;
}
.stat-info {
display: flex;
flex-direction: column;
}
.stat-value {
font-size: var(--text-2xl);
font-weight: var(--font-bold);
color: var(--text-primary);
line-height: 1;
margin-bottom: var(--space-1);
}
.text-glow {
text-shadow: 0 0 10px var(--glow-color, rgba(96, 165, 250, 0.3));
}
.stat-label {
font-size: var(--text-xs);
color: var(--text-muted);
font-weight: var(--font-medium);
text-transform: uppercase;
letter-spacing: 0.1em;
}
/* Content Grid */
.content-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--space-8);
}
.section-title {
display: flex;
align-items: center;
gap: var(--space-2);
font-size: var(--text-sm);
font-weight: var(--font-semibold);
color: var(--text-primary);
margin-bottom: var(--space-5);
text-transform: uppercase;
letter-spacing: 0.05em;
opacity: 0.8;
}
/* Quick Actions */
.action-list {
display: flex;
flex-direction: column;
gap: var(--space-4);
}
.action-card {
display: flex;
align-items: center;
gap: var(--space-5);
padding: var(--space-5);
border-radius: var(--radius-xl);
cursor: pointer;
text-align: left;
width: 100%;
}
.action-icon-box {
display: flex;
align-items: center;
justify-content: center;
width: 56px;
height: 56px;
border-radius: var(--radius-lg);
color: white;
flex-shrink: 0;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}
.action-content {
flex: 1;
min-width: 0;
}
.action-title {
font-size: var(--text-base);
font-weight: var(--font-semibold);
color: var(--text-primary);
margin-bottom: var(--space-1);
}
.action-desc {
font-size: var(--text-sm);
color: var(--text-muted);
}
.action-arrow-box {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: var(--radius-full);
background: rgba(255, 255, 255, 0.05);
color: var(--text-muted);
transition: all var(--transition-fast);
}
.action-card:hover .action-arrow-box {
background: var(--accent-primary);
color: white;
transform: translateX(4px);
}
/* Feature Grid */
.feature-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
gap: var(--space-4);
}
.feature-card {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--space-3);
padding: var(--space-6) var(--space-4);
border-radius: var(--radius-xl);
cursor: pointer;
}
.feature-icon-wrapper {
display: flex;
align-items: center;
justify-content: center;
width: 48px;
height: 48px;
background: rgba(255, 255, 255, 0.05);
border-radius: var(--radius-lg);
color: var(--text-secondary);
transition: all var(--transition-normal);
}
.feature-card:hover .feature-icon-wrapper {
background: var(--accent-primary);
color: white;
transform: scale(1.1) rotate(5deg);
}
.feature-name {
font-size: var(--text-sm);
font-weight: var(--font-medium);
color: var(--text-secondary);
text-align: center;
}
.feature-card:hover .feature-name {
color: var(--text-primary);
}
/* Footer */
.home-footer {
margin-top: var(--space-12);
text-align: center;
}
.footer-divider {
height: 1px;
background: linear-gradient(90deg, transparent, var(--border-default), transparent);
margin-bottom: var(--space-6);
}
.footer-text {
font-size: var(--text-xs);
color: var(--text-muted);
letter-spacing: 0.02em;
}
/* Responsive */
@media (max-width: 1024px) {
.content-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 768px) {
.home-stats {
grid-template-columns: 1fr;
gap: var(--space-4);
}
.hero-title {
font-size: var(--text-2xl);
}
.feature-grid {
grid-template-columns: repeat(2, 1fr);
}
}
</style>