From 38f82501e05246f5999fc4004a307e6a27abc8b1 Mon Sep 17 00:00:00 2001 From: Moment <73689580+xun082@users.noreply.github.com> Date: Sat, 20 Jul 2024 00:18:26 +0800 Subject: [PATCH] =?UTF-8?q?style:=20=F0=9F=8E=A8=20=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E9=87=8D=E6=9E=84,=E5=88=A0=E9=99=A4=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E6=B2=A1=E5=BF=85=E8=A6=81=E7=9A=84=E4=BB=A3=E7=A0=81=E5=B0=81?= =?UTF-8?q?=E8=A3=85=20(#75)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(main)/(router)/dashboard/page.tsx | 236 ++++++++---------- src/app/(main)/layout.tsx | 39 ++- src/app/edit/layout.tsx | 3 - src/app/layout.tsx | 9 +- src/components/main/sider/index.tsx | 78 ++---- .../modals/create-project-modal/index.tsx | 49 ++-- .../provider/modal-provider/index.tsx | 23 -- src/store/uploadFileDataStore.tsx | 119 +++------ src/utils/getLocalDirectory.ts | 68 ++--- src/utils/index.ts | 1 + src/utils/route.tsx | 56 +++++ 11 files changed, 328 insertions(+), 353 deletions(-) delete mode 100644 src/components/provider/modal-provider/index.tsx create mode 100644 src/utils/route.tsx diff --git a/src/app/(main)/(router)/dashboard/page.tsx b/src/app/(main)/(router)/dashboard/page.tsx index 7776405..30be0f0 100644 --- a/src/app/(main)/(router)/dashboard/page.tsx +++ b/src/app/(main)/(router)/dashboard/page.tsx @@ -1,152 +1,128 @@ 'use client'; -const TemplateCardData = [ - { - title: 'Node', - icon: 'https://lf-cdn.marscode.com.cn/obj/eden-cn/ljhwz_lkpkbvsj/ljhwZthlaukjlkulzlp/project_template/prod/e78a9920fc913dcd1b339f0ee1493e429fb237c8/images/native_nodejs/icon.svg', - }, - { - title: 'Vue3', - icon: 'https://lf-cdn.marscode.com.cn/obj/eden-cn/ljhwz_lkpkbvsj/ljhwZthlaukjlkulzlp/project_template/prod/e78a9920fc913dcd1b339f0ee1493e429fb237c8/images/native_nodejs/icon.svg', - }, - { - title: 'React', - icon: 'https://lf-cdn.marscode.com.cn/obj/eden-cn/ljhwz_lkpkbvsj/ljhwZthlaukjlkulzlp/project_template/prod/e78a9920fc913dcd1b339f0ee1493e429fb237c8/images/native_golang/icon.svg', - }, -]; -const LinkCardData = [ - { - linkText: 'Node1', - LinkUrl: 'https://www.baidu.com', - linkDesc: 'ai帮助你学习前端后端运维安全', - }, - { - linkText: 'Node2', - LinkUrl: 'https://www.baidu.com', - linkDesc: 'ai帮助你学习前端后端运维安全', - }, - { - linkText: 'Node3', - LinkUrl: 'https://www.baidu.com', - linkDesc: 'ai帮助你学习前端后端运维安全', - }, -]; +import React from 'react'; -function createTemplateCard(templateName: string, templateIconUrl: string) { - return ( -
-
-
- -
-
- {templateName} -
-
-
- 快速开始 {templateName} 开发 -
-
-
- 体验 -
-
-
- ); -} - -function createLinkCard(linkText: string, linkUrl: string, linkDesc: string) { - return ( - -
-
-
- {linkText} -
- - - -
-
- {linkDesc} -
-
-
- ); -} +import { TemplateCardData, LinkCardData } from '@/utils'; export default function DashboardPage() { return (
-
-
- 欢迎使用 Online Edit - +
+
+ 欢迎使用 Online Edit + 一款集成 AI 能力的 Online IDE,提供开箱即用的开发环境,简化开发过程,提高效率
- <> - -
-
-
-
- - <> -
- 创建您的项目 -
-
- 导入Git项目 -
- | -
- 选择更多模板 -
+ +
+
+
+
+
+ 创建您的项目 +
+
+ 导入Git项目 +
+ | +
+ 选择更多模板
- -

+

+

使用模板快速开始

-
- {TemplateCardData.map((item) => createTemplateCard(item.title, item.icon))} +
+ {TemplateCardData.map((item) => ( + + ))}
- <> -

阅读文档了解如何使用

-
- {LinkCardData.map((item) => createLinkCard(item.linkText, item.LinkUrl, item.linkDesc))} -
- + +

阅读文档了解如何使用

+
+ {LinkCardData.map((item) => ( + + ))} +
); } + +const TemplateCard: React.FC<{ title: string; icon: string }> = ({ title, icon }) => ( +
+
+
+ {title} +
+
+ {title} +
+
+
+ 快速开始 {title} 开发 +
+
+
+ 体验 +
+
+
+); + +const LinkCard: React.FC<{ linkText: string; linkUrl: string; linkDesc: string }> = ({ + linkText, + linkUrl, + linkDesc, +}) => ( + +
+
+
+ {linkText} +
+ + + +
+
+ {linkDesc} +
+
+
+); diff --git a/src/app/(main)/layout.tsx b/src/app/(main)/layout.tsx index a0ead09..122e4a7 100644 --- a/src/app/(main)/layout.tsx +++ b/src/app/(main)/layout.tsx @@ -1,23 +1,52 @@ +'use client'; + +import React, { useEffect } from 'react'; +import { usePathname } from 'next/navigation'; +import { motion, useAnimation } from 'framer-motion'; + import { Header } from '@/components/main/header'; -import { Sider } from '@/components/main/sider'; +import Sider from '@/components/main/sider'; export default function MainLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { + const pathname = usePathname(); + + const controls = useAnimation(); + + useEffect(() => { + controls.start({ + y: 0, + opacity: 1, + scale: 1, + transition: { ease: 'easeInOut', duration: 1 }, + }); + }, [pathname, controls]); + return (
-
+
- +
-
{children}
-
+
+ {' '} + + {children} + +
); diff --git a/src/app/edit/layout.tsx b/src/app/edit/layout.tsx index d011ee1..2dd5702 100644 --- a/src/app/edit/layout.tsx +++ b/src/app/edit/layout.tsx @@ -68,7 +68,6 @@ const Page: React.FC<{ children: React.ReactNode }> = ({ children }) => { }); }, [pathname, controls]); - // const { editors } = useEditorStore(); const { models, setModels } = useModelsStore(); const { setActiveModel } = useActiveModelStore(); @@ -80,8 +79,6 @@ const Page: React.FC<{ children: React.ReactNode }> = ({ children }) => { }; function handleFileDrop({ active, over }: any) { - // 清除dropIcon - dragIconRef.style.display = 'none'; dragIconRef.style.left = '0px'; dragIconRef.style.top = '0px'; diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 6e910de..d595cce 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,9 +1,7 @@ import type { Metadata } from 'next'; import { Inter } from 'next/font/google'; -import { NextDevtoolsProvider } from '@next-devtools/core'; import './globals.css'; -import { ModalProvider } from '@/components/provider/modal-provider'; const inter = Inter({ subsets: ['latin'] }); @@ -19,12 +17,7 @@ export default function RootLayout({ }>) { return ( - - - {children} - - - + {children} ); } diff --git a/src/components/main/sider/index.tsx b/src/components/main/sider/index.tsx index 39e7bb4..5950236 100644 --- a/src/components/main/sider/index.tsx +++ b/src/components/main/sider/index.tsx @@ -3,73 +3,47 @@ import Link from 'next/link'; import React from 'react'; import { usePathname } from 'next/navigation'; -import { GoFileDirectory } from 'react-icons/go'; -import { MdComputer } from 'react-icons/md'; import { Button } from '@/components/ui/button'; import { cn } from '@/utils'; -import { PATHS } from '@/utils'; +import { RouterDataList } from '@/utils'; import { useModal } from '@/hooks/useModal'; +import { CreateProjectModal } from '@/components/modals/create-project-modal'; -interface RouterData { - title: string; - icon: React.ReactNode; - link: string; -} - -const RouterDataList: RouterData[] = [ - { - title: '项目', - icon: , - link: PATHS.MAIN_DASHBOARD, - }, - { - title: '文档', - icon: , - link: PATHS.MAIN_TEMPLATES, - }, -]; - -const renderRouterDataList = (data: RouterData[], currentPath: string) => { - return data.map((item, index) => { - return ( - - {item.icon} - {item.title} - - ); - }); -}; - -interface SiderProps {} - -export const Sider: React.FC = () => { - const currentRoute = usePathname(); +const Sider: React.FC = () => { + const currentPath = usePathname(); const { onOpen } = useModal(); return ( ); }; + +export default Sider; diff --git a/src/components/modals/create-project-modal/index.tsx b/src/components/modals/create-project-modal/index.tsx index 9aed7de..6c36a9d 100644 --- a/src/components/modals/create-project-modal/index.tsx +++ b/src/components/modals/create-project-modal/index.tsx @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ 'use client'; import { useState } from 'react'; @@ -6,7 +5,7 @@ import { useRouter } from 'next/navigation'; import { AiOutlineLoading3Quarters } from 'react-icons/ai'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; -import { getDirectory } from '@/utils'; +import { getDirectory, DirectoryInterface } from '@/utils/getLocalDirectory'; import { useModal } from '@/hooks/useModal'; import { useUploadFileDataStore } from '@/store/uploadFileDataStore'; @@ -17,39 +16,39 @@ export const CreateProjectModal = () => { const router = useRouter(); const isModalOpen = isOpen && type === 'createProject'; + const handleUploadClick = async () => { + if (loading) return; + setLoading(true); + + try { + const res = await getDirectory(); + + if (res) { + const directoryData = Array.isArray(res) ? res : [res]; + setFileData(directoryData as DirectoryInterface[]); + onClose(); + router.push('edit/file'); + } + } catch (error) { + console.error('Failed to get directory:', error); + } finally { + setLoading(false); + } + }; + return ( - create Project + Create Project
{ - if (loading) return; - setLoading(true); - - let res = await getDirectory(); - - if (res) { - // @ts-expect-error - if (!Array.isArray(res)) res = [res]; - setTimeout(() => { - onClose(); - // @ts-expect-error - setFileData(res); - router.push('edit/file'); - }, 1000); - } - - setTimeout(() => { - setLoading(false); - }, 1000); - }} + onClick={handleUploadClick} className="flex justify-center flex-col items-center mt-2 gap-x-2 py-6 border-white/20 border-[1px] rounded-sm cursor-pointer" > {loading ? ( - + ) : ( <> { - const [isMounted, setIsMounted] = useState(false); - - useEffect(() => { - setIsMounted(true); - }, []); - - if (!isMounted) { - return null; - } - - return ( - <> - - - ); -}; diff --git a/src/store/uploadFileDataStore.tsx b/src/store/uploadFileDataStore.tsx index fd6748f..f4aa1c8 100644 --- a/src/store/uploadFileDataStore.tsx +++ b/src/store/uploadFileDataStore.tsx @@ -16,9 +16,7 @@ interface FileDataState { } function removeItemById(data: DirectoryInterface[], id: string): DirectoryInterface[] { - const dataArray = Array.isArray(data) ? data : [data]; - - return dataArray.reduce((acc: DirectoryInterface[], item) => { + return data.reduce((acc: DirectoryInterface[], item) => { if (item.id !== id) { if (item.children) { item.children = removeItemById(item.children, id); @@ -38,62 +36,50 @@ function addItem( parentId?: string, status?: string, ): DirectoryInterface[] { - parentId = parentId || data[0].id; - const newId = uuidv4(); const newEntry: DirectoryInterface = { id: newId, - filename: filename, + filename, kind: type, children: type === 'directory' ? [] : undefined, - status: status, + status, }; - data = Array.isArray(data) ? [...data] : [data]; - const isDuplicate = ( items: DirectoryInterface[], name: string, type: 'directory' | 'file', - ): boolean => { - return items.some((item) => item.filename === name && item.kind === type); - }; + ): boolean => items.some((item) => item.filename === name && item.kind === type); - let parentItem: DirectoryInterface | undefined; const findParentRecursive = ( items: DirectoryInterface[], id?: string, ): DirectoryInterface | undefined => { - for (let item of items) { - if (item.id === id) { - parentItem = item; - break; - } else if (item.children) { - findParentRecursive(item.children, id); + for (const item of items) { + if (item.id === id) return item; + + if (item.children) { + const found = findParentRecursive(item.children, id); + if (found) return found; } } - - return parentItem; }; + const findFileParent = ( items: DirectoryInterface[], id?: string, ): DirectoryInterface | undefined => { - for (let item of items) { - if (item.children?.some((item) => item.id === id)) { - parentItem = item; - break; - } else if (item.children) { - findFileParent(item.children, id); + for (const item of items) { + if (item.children?.some((child) => child.id === id)) return item; + + if (item.children) { + const found = findFileParent(item.children, id); + if (found) return found; } } - - return parentItem; }; - if (parentId) { - parentItem = findParentRecursive(data, parentId); - } + const parentItem = parentId ? findParentRecursive(data, parentId) : data[0]; if (parentItem) { if (parentItem.children && isDuplicate(parentItem.children, filename, type)) { @@ -103,30 +89,23 @@ function addItem( } if (parentItem.kind === 'file') { - const parentOfParentId = parentItem.id; - const parentOfParent = findFileParent(data, parentOfParentId); + const parentOfParent = findFileParent(data, parentItem.id); if (parentOfParent) { parentOfParent.children = [...(parentOfParent.children || []), newEntry]; - - return data; - } else { - return data; } } else { parentItem.children = [...(parentItem.children || []), newEntry]; - - return data; } } else { if (isDuplicate(data, filename, type)) { console.warn(`Item with name "${filename}" and type "${type}" already exists.`); - - return data; + } else { + data = [...data, newEntry]; } - - return [...data, newEntry]; } + + return data; } function updateItem( @@ -136,18 +115,14 @@ function updateItem( ): DirectoryInterface[] { return data.map((item) => { if (item.id === id) { - return { - ...item, - ...updatedProperties, - }; - } else if (item.children) { - return { - ...item, - children: updateItem(item.children, id, updatedProperties), - }; - } else { - return item; + return { ...item, ...updatedProperties }; + } + + if (item.children) { + return { ...item, children: updateItem(item.children, id, updatedProperties) }; } + + return item; }); } @@ -166,30 +141,18 @@ interface FileDataActions { export const useUploadFileDataStore = create((set) => ({ fileData: null, selected: '', - setSelected: (selected: string) => { - set({ selected }); - }, - setFileData: (fileData: DirectoryInterface[] | null) => { - set({ fileData }); - }, - removeFileById: (id: string) => { + setSelected: (selected: string) => set({ selected }), + setFileData: (fileData: DirectoryInterface[] | null) => set({ fileData }), + removeFileById: (id: string) => set((state) => ({ - fileData: removeItemById(state.fileData as DirectoryInterface[], id), - })); - }, - addFileOrFolder: ( - type: 'directory' | 'file', - filename: string, - parentId?: string, - status?: string, - ) => { + fileData: state.fileData ? removeItemById(state.fileData, id) : null, + })), + addFileOrFolder: (type, filename, parentId, status) => set((state) => ({ - fileData: addItem(state.fileData as DirectoryInterface[], type, filename, parentId, status), - })); - }, - updateItem: (id: string, updatedProperties: Partial) => { + fileData: state.fileData ? addItem(state.fileData, type, filename, parentId, status) : null, + })), + updateItem: (id, updatedProperties) => set((state) => ({ - fileData: updateItem(state.fileData as DirectoryInterface[], id, updatedProperties), - })); - }, + fileData: state.fileData ? updateItem(state.fileData, id, updatedProperties) : null, + })), })); diff --git a/src/utils/getLocalDirectory.ts b/src/utils/getLocalDirectory.ts index d46c0a8..01fbc68 100644 --- a/src/utils/getLocalDirectory.ts +++ b/src/utils/getLocalDirectory.ts @@ -3,7 +3,7 @@ import { v4 as uuidv4 } from 'uuid'; export interface FilerInterface { handler: FileSystemFileHandle; filename: string; - kind: string; + kind: 'file'; path: string; value: string; id: string; @@ -12,7 +12,7 @@ export interface FilerInterface { export interface DirectoryInterface { handler: FileSystemDirectoryHandle; filename: string; - kind: string; + kind: 'directory'; path: string; children: Array; id: string; @@ -20,19 +20,18 @@ export interface DirectoryInterface { export const DirectoryKeySet = new Set(); export const DirectoryMap = new Map(); -export let curDirectory: null | DirectoryInterface = null; +export let curDirectory: DirectoryInterface | null = null; export const getDirectory = async (id?: string): Promise => { if (id && DirectoryKeySet.has(id)) { - return DirectoryMap.get(id) as DirectoryInterface; + return DirectoryMap.get(id) || null; } let directoryHandler: FileSystemDirectoryHandle | null = null; try { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-expect-error - directoryHandler = await window.showDirectoryPicker({ + // 使用类型断言处理实验性 API + directoryHandler = await (window as any).showDirectoryPicker({ startIn: id ? DirectoryMap.get(id)?.handler : undefined, mode: 'readwrite', }); @@ -41,11 +40,10 @@ export const getDirectory = async (id?: string): Promise => { }; export const directoryDataFormatter = async ( - directoryHandler: FileSystemDirectoryHandle | FileSystemFileHandle, + handler: FileSystemDirectoryHandle | FileSystemFileHandle, path: string = '', children?: (FilerInterface | DirectoryInterface)[], ): Promise => { const id = uuidv4(); - const obj = { - handler: directoryHandler, - filename: directoryHandler.name, - kind: directoryHandler.kind, - path, - ...(directoryHandler.kind === 'directory' - ? { children: children || [], id } - : { value: await getFileContent(await directoryHandler.getFile()), id }), - }; - - return obj as FilerInterface | DirectoryInterface; + + if (handler.kind === 'directory') { + return { + handler: handler as FileSystemDirectoryHandle, + filename: handler.name, + kind: 'directory', + path, + children: children || [], + id, + }; + } else { + const fileHandler = handler as FileSystemFileHandle; + const value = await getFileContent(await fileHandler.getFile()); + + return { + handler: fileHandler, + filename: handler.name, + kind: 'file', + path, + value, + id, + }; + } }; export const getDirectoryHandlerDeep = async ( @@ -97,16 +107,16 @@ export const getDirectoryHandlerDeep = async ( path = path ? `${path}/${directoryHandler.name}` : directoryHandler.name; const children: (FilerInterface | DirectoryInterface)[] = []; - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-expect-error - for await (const handle of directoryHandler.values()) { + for await (const handle of ( + directoryHandler as any + ).values() as AsyncIterable) { if (handle.kind === 'directory' && handle.name !== 'node_modules') { - children.push(await getDirectoryHandlerDeep(handle, path)); + children.push(await getDirectoryHandlerDeep(handle as FileSystemDirectoryHandle, path)); } else if (handle.kind === 'file') { - children.push(await directoryDataFormatter(handle, path)); + children.push(await directoryDataFormatter(handle as FileSystemFileHandle, path)); } } - return directoryDataFormatter(directoryHandler, path, children) as unknown as DirectoryInterface; + return directoryDataFormatter(directoryHandler, path, children) as Promise; }; diff --git a/src/utils/index.ts b/src/utils/index.ts index e3159d7..25db3f6 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -2,3 +2,4 @@ export * from './cn'; export * from './constants'; export * from './editor'; export * from './getLocalDirectory'; +export * from './route'; diff --git a/src/utils/route.tsx b/src/utils/route.tsx new file mode 100644 index 0000000..edd4c90 --- /dev/null +++ b/src/utils/route.tsx @@ -0,0 +1,56 @@ +import { GoFileDirectory } from 'react-icons/go'; +import { MdComputer } from 'react-icons/md'; + +import { PATHS } from './constants'; + +interface RouterData { + title: string; + icon: React.ReactNode; + link: string; +} + +export const RouterDataList: RouterData[] = [ + { + title: '项目', + icon: , + link: PATHS.MAIN_DASHBOARD, + }, + { + title: '文档', + icon: , + link: PATHS.MAIN_TEMPLATES, + }, +]; + +export const TemplateCardData = [ + { + title: 'Node', + icon: 'https://lf-cdn.marscode.com.cn/obj/eden-cn/ljhwz_lkpkbvsj/ljhwZthlaukjlkulzlp/project_template/prod/e78a9920fc913dcd1b339f0ee1493e429fb237c8/images/native_nodejs/icon.svg', + }, + { + title: 'Vue3', + icon: 'https://lf-cdn.marscode.com.cn/obj/eden-cn/ljhwz_lkpkbvsj/ljhwZthlaukjlkulzlp/project_template/prod/e78a9920fc913dcd1b339f0ee1493e429fb237c8/images/native_nodejs/icon.svg', + }, + { + title: 'React', + icon: 'https://lf-cdn.marscode.com.cn/obj/eden-cn/ljhwz_lkpkbvsj/ljhwZthlaukjlkulzlp/project_template/prod/e78a9920fc913dcd1b339f0ee1493e429fb237c8/images/native_golang/icon.svg', + }, +]; + +export const LinkCardData = [ + { + linkText: 'Node1', + linkUrl: 'https://www.baidu.com', + linkDesc: 'ai帮助你学习前端后端运维安全', + }, + { + linkText: 'Node2', + linkUrl: 'https://www.baidu.com', + linkDesc: 'ai帮助你学习前端后端运维安全', + }, + { + linkText: 'Node3', + linkUrl: 'https://www.baidu.com', + linkDesc: 'ai帮助你学习前端后端运维安全', + }, +];