chore: 添加 .gitignore 规则,包含前端、pnpm、Node.js 和 AI 工具

This commit is contained in:
2026-03-20 09:14:58 +08:00
parent bf294f9f50
commit 176a727f6e
50 changed files with 6436 additions and 0 deletions

173
src/pages/DeveloperPage.jsx Normal file
View File

@@ -0,0 +1,173 @@
import { useState, useEffect } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { FiPlus, FiTerminal } from 'react-icons/fi';
import { FaPuzzlePiece } from 'react-icons/fa';
import Layout from '../components/Layout.jsx';
import { mySkills } from '../data/developerData.js';
import MySkillsPage from './developer/MySkillsPage.jsx';
import UploadSkillPage from './developer/UploadSkillPage.jsx';
import NewVersionPage from './developer/NewVersionPage.jsx';
import DevDocsPage from './developer/DevDocsPage.jsx';
import DevAccountPage from './developer/DevAccountPage.jsx';
import SkillEditorPage from './developer/SkillEditorPage.jsx';
function DeveloperPage() {
const location = useLocation();
const navigate = useNavigate();
const [currentPage, setCurrentPage] = useState(() => {
return localStorage.getItem('developer_currentPage') || 'mySkills';
});
const [currentSkillId, setCurrentSkillId] = useState(() => {
const saved = localStorage.getItem('developer_currentSkillId');
return saved ? JSON.parse(saved) : null;
});
const [newVersionSkillName, setNewVersionSkillName] = useState('');
useEffect(() => {
if (location.state?.fromHome) {
setCurrentPage('mySkills');
setCurrentSkillId(null);
navigate('.', { replace: true, state: {} });
}
}, [location.state, navigate, setCurrentPage, setCurrentSkillId]);
useEffect(() => {
localStorage.setItem('developer_currentPage', currentPage);
}, [currentPage]);
useEffect(() => {
localStorage.setItem('developer_currentSkillId', JSON.stringify(currentSkillId));
}, [currentSkillId]);
const switchPage = (pageId, data = {}) => {
setCurrentPage(pageId);
if (data.skillId !== undefined) {
setCurrentSkillId(data.skillId);
}
};
const openSkillEditor = (skillId) => {
setCurrentSkillId(skillId);
setCurrentPage('skillEditor');
};
const createNewProject = () => {
setCurrentPage('uploadSkill');
};
const openNewVersionPage = (skillName) => {
setNewVersionSkillName(skillName);
setCurrentPage('newVersion');
};
const handleBack = () => {
setCurrentPage('mySkills');
setCurrentSkillId(null);
};
const handleNewVersionBack = () => {
setCurrentPage('skillEditor');
setNewVersionSkillName('');
};
const renderPage = () => {
switch (currentPage) {
case 'mySkills':
return <MySkillsPage onSkillClick={openSkillEditor} />;
case 'uploadSkill':
return <UploadSkillPage />;
case 'devDocs':
return <DevDocsPage />;
case 'devAccount':
return <DevAccountPage />;
case 'skillEditor':
return <SkillEditorPage skillId={currentSkillId} onBack={handleBack} onUploadNewVersion={openNewVersionPage} />;
case 'newVersion':
return <NewVersionPage skillName={newVersionSkillName} onBack={handleNewVersionBack} />;
default:
return <div>Page not found</div>;
}
};
const getPageTitle = () => {
const titles = {
mySkills: '我的技能',
uploadSkill: '创建技能',
newVersion: '上传新版本',
devDocs: '开发文档',
devAccount: '开发者设置',
skillEditor: '技能详情'
};
return titles[currentPage] || '';
};
const sidebar = (
<>
<div className="chat-sidebar-header">
<div className="sidebar-brand">
<div className="sidebar-logo-icon">
<span></span>
<span></span>
</div>
<div className="sidebar-brand-text">
<div className="sidebar-logo">GrandClaw</div>
<div className="sidebar-subtitle">技能开发台</div>
</div>
</div>
<div className="sidebar-divider"></div>
<button className="btn btn-primary" style={{ width: '100%' }} onClick={createNewProject}>
<span style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '6px' }}>
<FiPlus /> 创建技能
</span>
</button>
</div>
<div className="chat-sidebar-content">
{mySkills.map(skill => (
<div
key={skill.id}
className={`conversation-item ${currentSkillId === skill.id && currentPage === 'skillEditor' ? 'active' : ''}`}
onClick={() => openSkillEditor(skill.id)}
>
<div className="conversation-title">{skill.name}</div>
<div className="conversation-time">{skill.status === 'published' ? '已发布' : '草稿'}</div>
</div>
))}
</div>
<div className="chat-sidebar-nav">
<div
className={`chat-nav-item ${currentPage === 'mySkills' ? 'active' : ''}`}
onClick={() => switchPage('mySkills')}
>
<span className="chat-nav-icon"><FaPuzzlePiece /></span>
<span className="chat-nav-text">我的技能</span>
</div>
<div
className={`chat-nav-item ${currentPage === 'devDocs' ? 'active' : ''}`}
onClick={() => switchPage('devDocs')}
>
<span className="chat-nav-icon"><FiTerminal /></span>
<span className="chat-nav-text">开发文档</span>
</div>
</div>
<div className="chat-sidebar-user" onClick={() => switchPage('devAccount')}>
<div className="user-avatar"></div>
<div className="chat-sidebar-user-info">
<div className="chat-sidebar-user-name">张三</div>
<div className="chat-sidebar-user-role">开发者</div>
</div>
</div>
</>
);
return (
<Layout
sidebar={sidebar}
headerTitle={getPageTitle()}
sidebarClassName="chat-sidebar"
>
{renderPage()}
</Layout>
);
}
export default DeveloperPage;