From 6dfd9cbbea792fcc51566e28bba5f327da7e2f29 Mon Sep 17 00:00:00 2001 From: zhwcreate <3331598351@qq.com> Date: Wed, 17 Jul 2024 12:08:30 +0800 Subject: [PATCH 1/4] feat: allow delete use file tree and allow keydowm to add --- .../extension/tree-view-api/index.tsx | 31 +++++++++----- src/components/file/fileItem/index.tsx | 14 ++++++- src/components/file/fileTree/index.tsx | 19 +-------- src/components/file/pendingFileItem/index.tsx | 40 +++++++++++++++++++ 4 files changed, 77 insertions(+), 27 deletions(-) create mode 100644 src/components/file/pendingFileItem/index.tsx diff --git a/src/components/extension/tree-view-api/index.tsx b/src/components/extension/tree-view-api/index.tsx index bbb622e..f075791 100644 --- a/src/components/extension/tree-view-api/index.tsx +++ b/src/components/extension/tree-view-api/index.tsx @@ -11,6 +11,7 @@ import React, { } from 'react'; import * as AccordionPrimitive from '@radix-ui/react-accordion'; import { FolderIcon, FolderOpenIcon } from 'lucide-react'; +import { RiDeleteBin6Line } from 'react-icons/ri'; import { Button } from '@/components/ui/button'; import { ScrollArea } from '@/components/ui/scroll-area'; @@ -227,13 +228,16 @@ const Folder = forwardRef - - {expendedItems?.includes(value) - ? (openIcon ?? ) - : (closeIcon ?? )} - {element} - - +
+ {expendedItems?.includes(value) + ? (openIcon ?? ) + : (closeIcon ?? )} + {element} +
+ { + e.stopPropagation(); + removeFileById(value); + }} + className=" pr-2 w-5 h-5 text-white/70 hover:text-white hidden group-hover:block" + /> + + {element && indicator &&
+ ); }, diff --git a/src/components/file/fileItem/index.tsx b/src/components/file/fileItem/index.tsx index 3d13740..7e98519 100644 --- a/src/components/file/fileItem/index.tsx +++ b/src/components/file/fileItem/index.tsx @@ -1,6 +1,7 @@ import React, { useRef } from 'react'; import { editor } from 'monaco-editor'; import { useDraggable } from '@dnd-kit/core'; +import { TiDocumentDelete } from 'react-icons/ti'; import { useActiveEditorStore, @@ -11,6 +12,7 @@ import { useSplitStore, } from '@/store/editorStore'; import { useDragIconStore } from '@/store/dragIconStore'; +import { useUploadFileDataStore } from '@/store/uploadFileDataStore'; import { addNewModel } from '@/components/editor/utils'; interface FileItemProps { file: any; @@ -53,6 +55,9 @@ export const FileItem: React.FC = ({ file, onMouseupFn }: FileIte dragIconRef.style.top = `${transform.y + clickClient.current.y + 5}px`; dragIconRef.innerHTML = `${file.filename}`; } + //used for fileTree + + const { removeFileById } = useUploadFileDataStore(); function handleFileItemMouseUp() { clickClient.current = { @@ -96,7 +101,7 @@ export const FileItem: React.FC = ({ file, onMouseupFn }: FileIte onMouseupFn && onMouseupFn(); handleFileItemMouseUp(); }} - className=" flex justify-start px-2 py-[0.2px] font-[250] text-[11.5px] w-full " + className=" group relative flex justify-between items-center px-2 py-[0.2px] font-[250] text-[11.5px] w-full " > = ({ file, onMouseupFn }: FileIte > {file.filename} + { + e.stopPropagation(); + removeFileById(file.id); + }} + className=" w-[15px] pr-[-4px] h-[15px] text-white/70 hover:text-white hidden group-hover:block" + /> ); }; diff --git a/src/components/file/fileTree/index.tsx b/src/components/file/fileTree/index.tsx index 88a0542..8f8cdbf 100644 --- a/src/components/file/fileTree/index.tsx +++ b/src/components/file/fileTree/index.tsx @@ -1,8 +1,8 @@ 'use client'; import { Tree, TreeViewElement, File, Folder } from '@/components/extension/tree-view-api'; +import { PendingFileItem } from '@/components/file/pendingFileItem'; import { FileItem } from '@/components/file/fileItem'; -import { useUploadFileDataStore } from '@/store/uploadFileDataStore'; type TOCProps = { toc: TreeViewElement[]; @@ -23,27 +23,12 @@ type TreeItemProps = { }; export const TreeItem = ({ elements }: TreeItemProps) => { - const { removeFileById, updateItem } = useUploadFileDataStore(); - return (
    {elements.map((element) => (
  • {element.status === 'pending' ? ( - { - if (e.target.value === '') { - removeFileById(element.id); - } else { - updateItem(element.id, { - filename: e.target.value, - status: 'success', - }); - } - }} - className=" px-px pl-2 pr-1 border-[1px] border-[#3f85f5] focus:outline-none focus:ring-1 focus:ring-[#3f85f5] ring-opacity-50 bg-transparent/30 text-[12px] font-[300]" - /> + ) : (element.children && element.children?.length > 0) || element.kind === 'directory' ? ( = ({ id }) => { + const { removeFileById, updateItem } = useUploadFileDataStore(); + const [fileName, setFileName] = useState(''); + const handleChangeStatus = () => { + if (fileName === '') { + removeFileById(id); + } else { + updateItem(id, { + filename: fileName, + status: 'success', + }); + } + }; + + return ( + { + if (e.key === 'Enter') { + handleChangeStatus(); + } + }} + onChange={(e) => { + setFileName(e.target.value); + }} + onBlur={() => { + handleChangeStatus(); + }} + className=" px-px pl-2 pr-1 border-[1px] border-[#3f85f5] focus:outline-none focus:ring-1 focus:ring-[#3f85f5] ring-opacity-50 bg-transparent/30 text-[12px] font-[300]" + /> + ); +}; From 90e72bd334535ebd7c896285251f5623ea7499b7 Mon Sep 17 00:00:00 2001 From: zhwcreate <3331598351@qq.com> Date: Wed, 17 Jul 2024 16:00:32 +0800 Subject: [PATCH 2/4] feat: realize linkage between file tree and editor --- src/components/file/fileItem/index.tsx | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/components/file/fileItem/index.tsx b/src/components/file/fileItem/index.tsx index 7e98519..8b3fcde 100644 --- a/src/components/file/fileItem/index.tsx +++ b/src/components/file/fileItem/index.tsx @@ -21,12 +21,13 @@ interface FileItemProps { export const FileItem: React.FC = ({ file, onMouseupFn }: FileItemProps) => { // used for editor - const { splitState } = useSplitStore(); - const { editors } = useEditorStore(); + const { splitState, removeSplit } = useSplitStore(); + const { editors, removeEditor } = useEditorStore(); const { activeEditor, activeEditorId } = useActiveEditorStore(); const { monacos } = useMonacoStore(); const { setActiveModel } = useActiveModelStore(); - const { models, setModels } = useModelsStore(); + const { models, setModels, removeModel, removeAllModel } = useModelsStore(); + const keepedEditorCount = splitState.filter((item) => item).length; // used for dnd const clickClient = useRef({ x: 0, @@ -120,6 +121,24 @@ export const FileItem: React.FC = ({ file, onMouseupFn }: FileIte onMouseUp={(e) => { e.stopPropagation(); removeFileById(file.id); + // 删除后更新editor + + editors.forEach((editor, editorId) => { + const newModels = removeModel(file.filename, editorId); + + if (newModels && newModels.filename) { + setActiveModel(newModels.filename, newModels.model, editorId); + editor && editor.setModel(newModels.model); + } else { + removeAllModel(editorId); + editor && editor.setModel(null); + + if (keepedEditorCount > 1) { + removeEditor(editorId); + removeSplit(editorId); + } + } + }); }} className=" w-[15px] pr-[-4px] h-[15px] text-white/70 hover:text-white hidden group-hover:block" /> From c21a4a0f5df3a84eac3c142f4555eb97953cdb1b Mon Sep 17 00:00:00 2001 From: zhwcreate <3331598351@qq.com> Date: Wed, 17 Jul 2024 17:05:04 +0800 Subject: [PATCH 3/4] feat: allow edit same name file --- src/components/edit/tabItem/index.tsx | 8 ++++---- src/components/edit/tabbar/index.tsx | 4 ++-- src/components/editor/utils.ts | 20 +++++++++++++++----- src/components/file/fileItem/index.tsx | 10 +++++----- src/store/editorStore.tsx | 24 +++++++++++++++--------- 5 files changed, 41 insertions(+), 25 deletions(-) diff --git a/src/components/edit/tabItem/index.tsx b/src/components/edit/tabItem/index.tsx index 0355b9d..74b7ed3 100644 --- a/src/components/edit/tabItem/index.tsx +++ b/src/components/edit/tabItem/index.tsx @@ -57,7 +57,7 @@ const Tab: React.FC = ({ const handleTabClick = (e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); - setActiveModel(filename, model, editorId); + setActiveModel(id, model, editorId); editor && editor.setModel(model); }; @@ -65,10 +65,10 @@ const Tab: React.FC = ({ e.preventDefault(); e.stopPropagation(); - const newModels = removeModel(filename, editorId); + const newModels = removeModel(id, editorId); - if (newModels && newModels.filename) { - setActiveModel(newModels.filename, newModels.model, editorId); + if (newModels && newModels.id) { + setActiveModel(newModels.id, newModels.model, editorId); editor && editor.setModel(newModels.model); } else { removeAllModel(editorId); diff --git a/src/components/edit/tabbar/index.tsx b/src/components/edit/tabbar/index.tsx index 9e9a257..348b919 100644 --- a/src/components/edit/tabbar/index.tsx +++ b/src/components/edit/tabbar/index.tsx @@ -57,7 +57,7 @@ export const TabBar: React.FC = ({ editorId }) => { useEffect(() => { setMockModelsForSort( models.map((item) => { - return { ...item, id: item.filename }; + return { ...item, id: item.id }; }), ); }, [models]); @@ -70,7 +70,7 @@ export const TabBar: React.FC = ({ editorId }) => { id={model.id} key={model.filename} filename={model.filename} - active={model.filename === activeModelId} + active={model.id === activeModelId} editorId={editorId} setActiveModel={setActiveModel} editor={editor} diff --git a/src/components/editor/utils.ts b/src/components/editor/utils.ts index 743b21b..4c7d9ec 100644 --- a/src/components/editor/utils.ts +++ b/src/components/editor/utils.ts @@ -6,7 +6,12 @@ export function setModelsFromInfo( modelsInfo: modelInfoType[], monaco: typeof monacoForType, editor: editor.IStandaloneCodeEditor, - setModels: (modelInfo: modelInfoType, model: editor.ITextModel, editorId: number) => void, + setModels: ( + modelInfo: modelInfoType, + model: editor.ITextModel, + editorId: number, + id: string, + ) => void, setActiveModel: (modelId: string, model: editor.ITextModel, editorId: number) => void, editorId: number, ) { @@ -19,16 +24,21 @@ export function addNewModel( modelInfo: modelInfoType, monaco: typeof monacoForType, editor: editor.IStandaloneCodeEditor, - setModels: (modelInfo: modelInfoType, model: editor.ITextModel, editorId: number) => void, + setModels: ( + modelInfo: modelInfoType, + model: editor.ITextModel, + editorId: number, + id: string, + ) => void, setActiveModel: (modelId: string, model: editor.ITextModel, editorId: number) => void, editorId: number, ) { - const modelUri = monaco.Uri.file(modelInfo.filename); + const modelUri = monaco.Uri.file(modelInfo.id); const model = monaco.editor.getModel(modelUri) || monaco.editor.createModel(modelInfo.value, modelInfo.language, modelUri); // console.log(monaco.editor.getModel(modelUri)); - setActiveModel(modelInfo.filename, model, editorId); - setModels(modelInfo, model, editorId); + setActiveModel(modelInfo.id, model, editorId); + setModels(modelInfo, model, editorId, modelInfo.id); editor.setModel(model); } diff --git a/src/components/file/fileItem/index.tsx b/src/components/file/fileItem/index.tsx index 8b3fcde..b0078aa 100644 --- a/src/components/file/fileItem/index.tsx +++ b/src/components/file/fileItem/index.tsx @@ -70,17 +70,17 @@ export const FileItem: React.FC = ({ file, onMouseupFn }: FileIte const willChangeEditorId = activeEditor ? activeEditorId : splitState.findIndex((item) => item); - const mathModel = models.filter((model) => model.filename === file.filename); + const mathModel = models.filter((model) => model.id === file.id); // console.log(splitState, mathModel[0], willChangeEditor, willChangeEditorId); if (mathModel.length > 0) { - mathModel[0].model && - setActiveModel(mathModel[0].filename, mathModel[0].model, willChangeEditorId); + mathModel[0].model && setActiveModel(mathModel[0].id, mathModel[0].model, willChangeEditorId); mathModel[0].model && setModels( - { filename: mathModel[0].filename, value: '', language: 'typescript' }, + { filename: mathModel[0].filename, value: '', language: 'typescript', id: file.id }, mathModel[0].model, willChangeEditorId, + file.id, ); willChangeEditor?.setModel(mathModel[0].model); } else { @@ -124,7 +124,7 @@ export const FileItem: React.FC = ({ file, onMouseupFn }: FileIte // 删除后更新editor editors.forEach((editor, editorId) => { - const newModels = removeModel(file.filename, editorId); + const newModels = removeModel(file.id, editorId); if (newModels && newModels.filename) { setActiveModel(newModels.filename, newModels.model, editorId); diff --git a/src/store/editorStore.tsx b/src/store/editorStore.tsx index 614f447..028a446 100644 --- a/src/store/editorStore.tsx +++ b/src/store/editorStore.tsx @@ -67,11 +67,12 @@ export const useMonacoStore = create((set, get) => ( return get().monacos[index] || null; }, })); - +// filename 为model对应文件名,id为uuid export type modelInfoType = { filename: string; language: string; value: string; + id: string; }; export type modelType = modelInfoType & { model: editor.ITextModel; usedBy: number[] }; @@ -81,8 +82,13 @@ interface ModelsState { models: modelsType | []; } interface ModelsAction { - setModels: (modelInfo: modelInfoType, model: editor.ITextModel, editorId: number) => void; - removeModel: (filename: string, editorId: number) => any; + setModels: ( + modelInfo: modelInfoType, + model: editor.ITextModel, + editorId: number, + id: string, + ) => void; + removeModel: (id: string, editorId: number) => any; removeAllModel: (editorId: number) => void; } export const useModelsStore = create((set, get) => ({ @@ -96,7 +102,7 @@ export const useModelsStore = create((set, get) => ( } set((state) => { - const existingModelIndex = state.models.findIndex((m) => m.filename === modelInfo.filename); + const existingModelIndex = state.models.findIndex((m) => m.id === modelInfo.id); if (existingModelIndex === -1) { return { @@ -124,21 +130,21 @@ export const useModelsStore = create((set, get) => ( }); }, - removeModel: (filename: string, editorId: number) => { + removeModel: (id: string, editorId: number) => { set((state) => { - const existingModelIndex = state.models.findIndex((m) => m.filename === filename); + const existingModelIndex = state.models.findIndex((m) => m.id === id); if (existingModelIndex !== -1) { const preModels = [...state.models]; if (preModels[existingModelIndex].usedBy.includes(editorId)) { preModels[existingModelIndex].usedBy = preModels[existingModelIndex].usedBy.filter( - (id) => id !== editorId, + (eid) => eid !== editorId, ); if (preModels[existingModelIndex].usedBy.length === 0) { return { - models: [...preModels.filter((model) => model.filename !== filename)], + models: [...preModels.filter((model) => model.id !== id)], }; } else { return { @@ -183,6 +189,7 @@ export const useModelsStore = create((set, get) => ( }, })); +// modelId原为model对应文件名,为满足打开多个同名文件修改为对应文件的uuid interface activeModelState { activeMap: { modelId: string; model: editor.ITextModel | null }[]; } @@ -194,7 +201,6 @@ interface activeModelAction { export const useActiveModelStore = create((set) => ({ activeMap: [], - setActiveModel: (modelId: string, model: editor.ITextModel, editorId: number) => set((state) => { const preActiveMap = [...state.activeMap]; From 9f29b88a5991f358a042ddfc7624f5b2e95b5312 Mon Sep 17 00:00:00 2001 From: zhwcreate <3331598351@qq.com> Date: Wed, 17 Jul 2024 17:52:08 +0800 Subject: [PATCH 4/4] fix: some bug --- src/app/edit/layout.tsx | 5 +++-- src/components/edit/tabbar/index.tsx | 4 ++-- src/components/editor/index.tsx | 23 ++--------------------- src/components/file/fileItem/index.tsx | 1 - 4 files changed, 7 insertions(+), 26 deletions(-) diff --git a/src/app/edit/layout.tsx b/src/app/edit/layout.tsx index c4ab960..9817fbf 100644 --- a/src/app/edit/layout.tsx +++ b/src/app/edit/layout.tsx @@ -94,16 +94,17 @@ const Page: React.FC<{ children: React.ReactNode }> = ({ children }) => { const willChangeEditor = editor; const willChangeEditorId = over.id; - const mathModel = models.filter((model) => model.filename === file.filename); + const mathModel = models.filter((model) => model.id === file.id); if (mathModel.length > 0) { mathModel[0].model && setActiveModel(mathModel[0].filename, mathModel[0].model, willChangeEditorId); mathModel[0].model && setModels( - { filename: mathModel[0].filename, value: '', language: 'typescript' }, + { filename: mathModel[0].filename, value: '', language: 'typescript', id: file.id }, mathModel[0].model, willChangeEditorId, + file.id, ); willChangeEditor?.setModel(mathModel[0].model); } else { diff --git a/src/components/edit/tabbar/index.tsx b/src/components/edit/tabbar/index.tsx index 348b919..af16033 100644 --- a/src/components/edit/tabbar/index.tsx +++ b/src/components/edit/tabbar/index.tsx @@ -57,7 +57,7 @@ export const TabBar: React.FC = ({ editorId }) => { useEffect(() => { setMockModelsForSort( models.map((item) => { - return { ...item, id: item.id }; + return { ...item }; }), ); }, [models]); @@ -68,7 +68,7 @@ export const TabBar: React.FC = ({ editorId }) => { return ( = ({ file, onMouseupFn }: FileIte onMouseUp={(e) => { e.stopPropagation(); removeFileById(file.id); - // 删除后更新editor editors.forEach((editor, editorId) => { const newModels = removeModel(file.id, editorId);