update: 重构项目结构

This commit is contained in:
yuzhantian 2026-04-23 15:40:01 +08:00
parent c6726a385a
commit bc8404c965
8 changed files with 134 additions and 119 deletions

View File

@ -1,111 +1,12 @@
import { useState } from 'react'
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'
import CanvasArea from './components/CanvasArea'
import TopBar from './components/TopBar'
import SideBar from './components/SideBar'
import AIChatPanel from './components/AIChatPanel'
import Login from './components/auth/Login'
import Register from './components/auth/Register'
import Projects from './components/auth/Projects'
import Login from './pages/auth/Login'
import Register from './pages/auth/Register'
import Projects from './pages/app/Projects'
import MainApp from './pages/app/MainApp'
import './App.css'
// 模拟设计文件数据
const MOCK_DESIGN_FILES = [
{
name: 'text_1.html',
path: '/designs/text_1.html',
modified: new Date(),
content: '<div style="padding: 20px; font-family: Arial, sans-serif;"><h1>Hello World</h1><p>This is a test design file.</p></div>',
fileType: 'html',
relationships: {
parent: undefined,
children: ['text_1_1.html']
}
},
{
name: 'text_1_1.html',
path: '/designs/text_1_1.html',
modified: new Date(),
content: '<div style="padding: 20px; font-family: Arial, sans-serif;"><h1>Hello World - Version 1</h1><p>This is a modified version.</p></div>',
fileType: 'html',
relationships: {
parent: 'text_1.html',
children: ['text_1_1_1.html']
}
},
{
name: 'text_1_1_1.html',
path: '/designs/text_1_1_1.html',
modified: new Date(),
content: '<div style="padding: 20px; font-family: Arial, sans-serif;"><h1>Hello World - Version 1.1</h1><p>This is another modified version.</p></div>',
fileType: 'html',
relationships: {
parent: 'text_1_1.html',
children: []
}
},
{
name: 'text_2.html',
path: '/designs/text_2.html',
modified: new Date(),
content: '<div style="padding: 20px; font-family: Arial, sans-serif;"><h1>Another Design</h1><p>This is a different design file.</p></div>',
fileType: 'html',
relationships: {
parent: undefined,
children: []
}
}
]
// 主应用组件
const MainApp: React.FC = () => {
const [isChatVisible, setIsChatVisible] = useState(true)
const [selectedFrames, setSelectedFrames] = useState<string[]>([])
const [designFiles, setDesignFiles] = useState<any[]>(MOCK_DESIGN_FILES)
const toggleChat = () => {
setIsChatVisible(!isChatVisible)
}
const handleFrameSelect = (frames: string[]) => {
setSelectedFrames(frames)
}
const handleSelectNote = (frameName: string, note: string) => {
console.log('添加备注到设计元素:', frameName, note)
}
const handleCreateContext = (title: string, description: string) => {
console.log('创建上下文:', { title, description })
const newFrame = {
name: title,
path: `/context/${title}`,
modified: new Date(),
content: description,
fileType: 'html' as const,
size: description.length,
version: '1.0',
generation: 0,
branchIndex: 0,
parentDesign: null,
children: [],
relationships: {
parent: undefined,
children: []
}
}
setDesignFiles([...designFiles, newFrame])
}
return (
<div className="app-container">
<CanvasArea onFrameSelect={handleFrameSelect} designFiles={designFiles} setDesignFiles={setDesignFiles} />
<TopBar onToggleChat={toggleChat} isChatVisible={isChatVisible} />
<SideBar selectedFrames={selectedFrames} onSelectNote={handleSelectNote} onCreateContext={handleCreateContext} />
{isChatVisible && <AIChatPanel />}
</div>
)
}
// 路由保护组件
const ProtectedRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {

View File

@ -1,4 +1,4 @@
import { useState, useEffect } from 'react'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import './SideBar.css'
import { ArrowIcon, NoteIcon, CopyIcon, PaletteIcon, PushPinIcon, PlusIcon } from './Icons'

View File

@ -1,14 +1,14 @@
import { useRef, useEffect, useState, useCallback } from 'react'
import { TransformWrapper, TransformComponent, ReactZoomPanPinchRef } from 'react-zoom-pan-pinch'
import DesignFrame from './DesignFrame'
import ConnectionLines from './ConnectionLines'
import DesignFrame from '../../components/DesignFrame'
import ConnectionLines from '../../components/ConnectionLines'
import {
generateResponsiveConfig,
buildHierarchyTree,
calculateHierarchyPositions,
getHierarchicalPosition,
detectDesignRelationships
} from '../utils/gridLayout'
} from '../../utils/gridLayout'
import {
DesignFile,
CanvasConfig,
@ -20,10 +20,8 @@ import {
LayoutMode,
HierarchyTree,
ConnectionLine
} from '../types/canvas.types'
} from '../../types/canvas.types'
import {
ZoomInIcon,
ZoomOutIcon,
HomeIcon,
RefreshIcon,
GlobeIcon,
@ -32,9 +30,9 @@ import {
DesktopIcon,
TreeIcon,
LinkIcon
} from './Icons'
} from '../../components/Icons'
import { useTranslation } from 'react-i18next'
import './CanvasArea.css'
import '../../components/CanvasArea.css'
const CANVAS_CONFIG: CanvasConfig = {
frameSize: { width: 320, height: 400 },
@ -116,7 +114,7 @@ interface CanvasAreaProps {
setDesignFiles?: (files: DesignFile[]) => void
}
const CanvasArea: React.FC<CanvasAreaProps> = ({ onFrameSelect, designFiles: externalDesignFiles, setDesignFiles: externalSetDesignFiles }) => {
const CanvasArea: React.FC<CanvasAreaProps> = ({ onFrameSelect, designFiles: externalDesignFiles }) => {
const { t } = useTranslation()
const [designFiles, setDesignFiles] = useState<DesignFile[]>([])
const [selectedFrames, setSelectedFrames] = useState<string[]>([])
@ -170,7 +168,7 @@ const CanvasArea: React.FC<CanvasAreaProps> = ({ onFrameSelect, designFiles: ext
}, [useGlobalViewport, globalViewportMode, frameViewports])
const handleFrameViewportChange = useCallback((fileName: string, viewport: ViewportMode) => {
setFrameViewports(prev => ({
setFrameViewports((prev: FrameViewportState) => ({
...prev,
[fileName]: viewport
}))
@ -449,7 +447,7 @@ const CanvasArea: React.FC<CanvasAreaProps> = ({ onFrameSelect, designFiles: ext
y: mousePos.y - dragState.offset.y
}
setDragState(prev => ({
setDragState((prev: DragState) => ({
...prev,
currentPosition: newPosition
}))
@ -464,7 +462,7 @@ const CanvasArea: React.FC<CanvasAreaProps> = ({ onFrameSelect, designFiles: ext
y: Math.round(dragState.currentPosition.y / gridSize) * gridSize
}
setCustomPositions(prev => ({
setCustomPositions((prev: FramePositionState) => ({
...prev,
[dragState.draggedFrame!]: snappedPosition
}))

106
src/pages/app/MainApp.tsx Normal file
View File

@ -0,0 +1,106 @@
import { useState } from 'react'
import CanvasArea from './CanvasArea'
import TopBar from '../../components/TopBar'
import SideBar from '../../components/SideBar'
import AIChatPanel from '../../components/AIChatPanel'
import '../../App.css'
// 模拟设计文件数据
const MOCK_DESIGN_FILES = [
{
name: 'text_1.html',
path: '/designs/text_1.html',
modified: new Date(),
content: '<div style="padding: 20px; font-family: Arial, sans-serif;"><h1>Hello World</h1><p>This is a test design file.</p></div>',
fileType: 'html',
relationships: {
parent: undefined,
children: ['text_1_1.html']
}
},
{
name: 'text_1_1.html',
path: '/designs/text_1_1.html',
modified: new Date(),
content: '<div style="padding: 20px; font-family: Arial, sans-serif;"><h1>Hello World - Version 1</h1><p>This is a modified version.</p></div>',
fileType: 'html',
relationships: {
parent: 'text_1.html',
children: ['text_1_1_1.html']
}
},
{
name: 'text_1_1_1.html',
path: '/designs/text_1_1_1.html',
modified: new Date(),
content: '<div style="padding: 20px; font-family: Arial, sans-serif;"><h1>Hello World - Version 1.1</h1><p>This is another modified version.</p></div>',
fileType: 'html',
relationships: {
parent: 'text_1_1.html',
children: []
}
},
{
name: 'text_2.html',
path: '/designs/text_2.html',
modified: new Date(),
content: '<div style="padding: 20px; font-family: Arial, sans-serif;"><h1>Another Design</h1><p>This is a different design file.</p></div>',
fileType: 'html',
relationships: {
parent: undefined,
children: []
}
}
]
// 主应用组件
const MainApp: React.FC = () => {
const [isChatVisible, setIsChatVisible] = useState(true)
const [selectedFrames, setSelectedFrames] = useState<string[]>([])
const [designFiles, setDesignFiles] = useState<any[]>(MOCK_DESIGN_FILES)
const toggleChat = () => {
setIsChatVisible(!isChatVisible)
}
const handleFrameSelect = (frames: string[]) => {
setSelectedFrames(frames)
}
const handleSelectNote = (frameName: string, note: string) => {
console.log('添加备注到设计元素:', frameName, note)
}
const handleCreateContext = (title: string, description: string) => {
console.log('创建上下文:', { title, description })
const newFrame = {
name: title,
path: `/context/${title}`,
modified: new Date(),
content: description,
fileType: 'html' as const,
size: description.length,
version: '1.0',
generation: 0,
branchIndex: 0,
parentDesign: null,
children: [],
relationships: {
parent: undefined,
children: []
}
}
setDesignFiles([...designFiles, newFrame])
}
return (
<div className="app-container">
<CanvasArea onFrameSelect={handleFrameSelect} designFiles={designFiles} setDesignFiles={setDesignFiles} />
<TopBar onToggleChat={toggleChat} isChatVisible={isChatVisible} />
<SideBar selectedFrames={selectedFrames} onSelectNote={handleSelectNote} onCreateContext={handleCreateContext} />
{isChatVisible && <AIChatPanel />}
</div>
)
}
export default MainApp

View File

@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import './Auth.css';
import '../auth/Auth.css';
interface Project {
id: string;
@ -86,6 +86,11 @@ const Projects: React.FC = () => {
);
}
const handleProjectClick = (projectId: string) => {
// 跳转到canvas页面并传递项目ID
navigate(`/app?projectId=${projectId}`);
};
return (
<div className="projects-container">
<div className="projects-header">
@ -99,7 +104,12 @@ const Projects: React.FC = () => {
<div className="projects-empty"></div>
) : (
projects.map((project) => (
<div key={project.id} className="project-card">
<div
key={project.id}
className="project-card"
onClick={() => handleProjectClick(project.id)}
style={{ cursor: 'pointer' }}
>
<h3>{project.name}</h3>
<p>{project.description}</p>
<div className="project-meta">