blob: 8388b7bc12f135ae3972a05bf4b939680141e749 [file] [log] [blame]
import React, { useState } from 'react'
import {
Home,
Settings,
BarChart3,
PieChart,
TrendingUp,
Activity,
BookOpen,
Users,
Upload,
Image,
Video,
ChevronDown,
User
} from 'lucide-react'
import './App.css'
function App() {
const [activeTab, setActiveTab] = useState('image')
const [expandedMenu, setExpandedMenu] = useState('dashboard')
const [activePage, setActivePage] = useState('dashboard') // 新增:当前激活的页面
const [isDragOver, setIsDragOver] = useState(false)
const [isUploading, setIsUploading] = useState(false)
const [uploadedFiles, setUploadedFiles] = useState([])
const [uploadProgress, setUploadProgress] = useState(0)
const validateFiles = (files) => {
const validImageTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp']
const validVideoTypes = ['video/mp4', 'video/mov', 'video/avi']
const validTypes = activeTab === 'video' ? validVideoTypes : validImageTypes
const maxSize = activeTab === 'video' ? 2 * 1024 * 1024 * 1024 : 32 * 1024 * 1024 // 2GB for video, 32MB for images
const invalidFiles = files.filter(file => {
return !validTypes.includes(file.type) || file.size > maxSize
})
if (invalidFiles.length > 0) {
alert(`发现 ${invalidFiles.length} 个无效文件,请检查文件格式和大小`)
return false
}
return true
}
const simulateUpload = (files) => {
setIsUploading(true)
setUploadProgress(0)
setUploadedFiles(files)
// 模拟上传进度
const interval = setInterval(() => {
setUploadProgress(prev => {
if (prev >= 100) {
clearInterval(interval)
setIsUploading(false)
alert(`成功上传了 ${files.length} 个文件`)
return 100
}
return prev + 10
})
}, 200)
}
const handleFileUpload = () => {
if (isUploading) return
const input = document.createElement('input')
input.type = 'file'
input.accept = activeTab === 'video' ? 'video/*' : 'image/*'
input.multiple = activeTab === 'image'
input.onchange = (e) => {
const files = Array.from(e.target.files)
if (files.length > 0 && validateFiles(files)) {
simulateUpload(files)
}
}
input.click()
}
const handleDragOver = (e) => {
e.preventDefault()
e.stopPropagation()
setIsDragOver(true)
}
const handleDragLeave = (e) => {
e.preventDefault()
e.stopPropagation()
setIsDragOver(false)
}
const handleDrop = (e) => {
e.preventDefault()
e.stopPropagation()
setIsDragOver(false)
if (isUploading) return
const files = Array.from(e.dataTransfer.files)
if (files.length > 0 && validateFiles(files)) {
simulateUpload(files)
}
}
const clearUploadedFiles = () => {
setUploadedFiles([])
}
const removeFile = (indexToRemove) => {
setUploadedFiles(prev => prev.filter((_, index) => index !== indexToRemove))
}
const menuItems = [
{ id: 'home', label: '首页', icon: Home },
{ id: 'notebooks', label: '笔记管理', icon: BookOpen },
{
id: 'dashboard',
label: '数据看板',
icon: BarChart3,
submenu: [
{ id: 'overview', label: '账号概况' },
{ id: 'content', label: '内容分析' },
{ id: 'fans', label: '粉丝数据' }
]
},
{ id: 'activity', label: '活动中心', icon: Activity },
{ id: 'notes', label: '笔记灵感', icon: BookOpen },
{ id: 'creator', label: '创作学院', icon: Users },
{ id: 'journal', label: '创作日刊', icon: BookOpen }
]
const toggleMenu = (menuId) => {
setExpandedMenu(expandedMenu === menuId ? null : menuId)
}
// 新增:处理页面切换的函数
const handlePageChange = (pageId) => {
setActivePage(pageId)
// 如果点击的是有子菜单的项目,也要展开子菜单
const menuItem = menuItems.find(item => item.id === pageId)
if (menuItem && menuItem.submenu) {
setExpandedMenu(pageId)
}
}
return (
<div className="app">
{/* Header */}
<header className="header">
<div className="header-left">
<div className="logo">小红书</div>
<h1 className="header-title">创作服务平台</h1>
</div>
<div className="header-right">
<div className="user-info">
<User size={16} />
<span>小红薯63081EA1</span>
</div>
</div>
</header>
{/* Sidebar */}
<aside className="sidebar">
<button className="publish-btn">发布笔记</button>
<nav className="nav-menu">
{menuItems.map((item) => (
<div key={item.id} className="nav-item">
<a
href="#"
className={`nav-link ${activePage === item.id ? 'active' : ''}`}
onClick={(e) => {
e.preventDefault()
if (item.submenu) {
toggleMenu(item.id)
} else {
handlePageChange(item.id)
}
}}
>
<item.icon size={16} />
<span>{item.label}</span>
{item.submenu && <ChevronDown size={16} style={{ marginLeft: 'auto', transform: expandedMenu === item.id ? 'rotate(180deg)' : 'rotate(0deg)', transition: 'transform 0.3s ease' }} />}
</a>
{item.submenu && expandedMenu === item.id && (
<div className="nav-submenu">
{item.submenu.map((subItem) => (
<a
key={subItem.id}
href="#"
className={`nav-link ${activePage === subItem.id ? 'active' : ''}`}
onClick={(e) => {
e.preventDefault()
handlePageChange(subItem.id)
}}
>
{subItem.label}
</a>
))}
</div>
)}
</div>
))}
</nav>
</aside> {/* Main Content */}
<main className="main-content">
<div className="content-wrapper">
{activePage === 'dashboard' || activePage === 'overview' || activePage === 'content' || activePage === 'fans' ? (
// 上传页面内容(数据看板相关页面显示上传功能)
<>
{/* Upload Tabs */}
<div className="upload-tabs">
<button
className={`upload-tab ${activeTab === 'video' ? 'active' : ''}`}
onClick={() => setActiveTab('video')}
>
上传视频
</button>
<button
className={`upload-tab ${activeTab === 'image' ? 'active' : ''}`}
onClick={() => setActiveTab('image')}
>
上传图文
</button>
</div>
{/* Upload Area */}
<div
className={`upload-area ${isDragOver ? 'drag-over' : ''}`}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
>
<div className="upload-icon">
{activeTab === 'video' ? <Video /> : <Image />}
</div>
<h2 className="upload-title">
{activeTab === 'video' ? '拖拽视频到此处或点击上传' : '拖拽图片到此处或点击上传'}
</h2>
<p className="upload-subtitle">
{activeTab === 'video' ? '(需支持上传格式)' : '(需支持上传格式)'}
</p>
<button
className={`upload-btn ${isUploading ? 'uploading' : ''}`}
onClick={handleFileUpload}
disabled={isUploading}
>
{isUploading ? `上传中... ${uploadProgress}%` : (activeTab === 'video' ? '上传视频' : '上传图片')}
</button>
{/* Upload Progress Bar */}
{isUploading && (
<div className="progress-container">
<div className="progress-bar">
<div
className="progress-fill"
style={{ width: `${uploadProgress}%` }}
></div>
</div>
<div className="progress-text">{uploadProgress}%</div>
</div>
)}
</div>
{/* File Preview Area */}
{uploadedFiles.length > 0 && (
<div className="file-preview-area">
<div className="preview-header">
<h3 className="preview-title">已上传文件 ({uploadedFiles.length})</h3>
<button className="clear-files-btn" onClick={clearUploadedFiles}>
清除所有
</button>
</div>
<div className="file-grid">
{uploadedFiles.map((file, index) => (
<div key={index} className="file-item">
<button
className="remove-file-btn"
onClick={() => removeFile(index)}
title="删除文件"
>
×
</button>
{file.type?.startsWith('image/') ? (
<div className="file-thumbnail">
<img src={URL.createObjectURL(file)} alt={file.name} />
</div>
) : (
<div className="file-thumbnail video-thumbnail">
<Video size={24} />
</div>
)}
<div className="file-info">
<div className="file-name" title={file.name}>
{file.name.length > 20 ? file.name.substring(0, 17) + '...' : file.name}
</div>
<div className="file-size">
{(file.size / 1024 / 1024).toFixed(2)} MB
</div>
</div>
</div>
))}
</div>
</div>
)}
{/* Upload Info */}
<div className="upload-info fade-in" key={activeTab}>
{activeTab === 'image' ? (
<>
<div className="info-item">
<h3 className="info-title">图片大小</h3>
<p className="info-desc">
支持上传的图片大小,<br />
最大32MB的图片文件
</p>
</div>
<div className="info-item">
<h3 className="info-title">图片格式</h3>
<p className="info-desc">
支持上传的图片格式:<br />
推荐使用pngjpgjpegwebp,不支持giflive及其他转化的动图
</p>
</div>
<div className="info-item">
<h3 className="info-title">图片分辨率</h3>
<p className="info-desc">
不要竖图片尺寸,推荐上传3:4尺寸之间,分辨率不低于720*960的图片,<br />
超过17张的时候图片将自动压缩至相配尺寸
</p>
</div>
</>
) : (
<>
<div className="info-item">
<h3 className="info-title">视频大小</h3>
<p className="info-desc">
支持种类5分钟内视频,<br />
最大2GB的视频文件
</p>
</div>
<div className="info-item">
<h3 className="info-title">视频格式</h3>
<p className="info-desc">
支持常用视频格式:<br />
推荐使用mp4mov
</p>
</div>
<div className="info-item">
<h3 className="info-title">视频分辨率</h3>
<p className="info-desc">
推荐上传720P (1280*720) 及以上视频,<br />
超过1080P的视频可能可能导致上传稍慢且消耗流量
</p>
</div>
</>
)}
</div>
</>
) : (
// 其他页面的内容
<div className="page-content">
<div className="page-header">
<h1 className="page-title">
{activePage === 'home' && '首页'}
{activePage === 'notebooks' && '笔记管理'}
{activePage === 'activity' && '活动中心'}
{activePage === 'notes' && '笔记灵感'}
{activePage === 'creator' && '创作学院'}
{activePage === 'journal' && '创作日刊'}
</h1>
</div>
<div className="page-body">
<div className="placeholder-content">
<div className="placeholder-icon">
{activePage === 'home' && <Home size={48} />}
{activePage === 'notebooks' && <BookOpen size={48} />}
{activePage === 'activity' && <Activity size={48} />}
{activePage === 'notes' && <BookOpen size={48} />}
{activePage === 'creator' && <Users size={48} />}
{activePage === 'journal' && <BookOpen size={48} />}
</div>
<h3 className="placeholder-title">
{activePage === 'home' && '欢迎来到小红书创作平台'}
{activePage === 'notebooks' && '笔记管理功能开发中'}
{activePage === 'activity' && '活动中心功能开发中'}
{activePage === 'notes' && '笔记灵感功能开发中'}
{activePage === 'creator' && '创作学院功能开发中'}
{activePage === 'journal' && '创作日刊功能开发中'}
</h3>
<p className="placeholder-desc">
{activePage === 'home' && '在这里您可以管理您的创作内容,查看数据分析,获取创作灵感。'}
{activePage === 'notebooks' && '这里将显示您的所有笔记,支持编辑、删除、分类等操作。'}
{activePage === 'activity' && '这里将展示最新的平台活动,让您参与更多有趣的创作活动。'}
{activePage === 'notes' && '这里将为您提供创作灵感和写作建议,帮助您创作更好的内容。'}
{activePage === 'creator' && '这里将提供创作技巧教学和平台规则说明,助您成为优秀创作者。'}
{activePage === 'journal' && '这里将展示创作相关的最新资讯和平台动态。'}
</p>
</div>
</div>
</div>
)}
</div>
</main>
</div>
)
}
export default App