| 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 /> |
| 推荐使用png、jpg、jpeg、webp,不支持gif、live及其他转化的动图 |
| </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 /> |
| 推荐使用mp4、mov |
| </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 |