diff --git a/src/editor/FileSelector.vue b/src/editor/FileSelector.vue index e332b2fb..6ea58bf0 100644 --- a/src/editor/FileSelector.vue +++ b/src/editor/FileSelector.vue @@ -4,7 +4,7 @@ import { computed, inject, ref, VNode, Ref } from 'vue' const store = inject('store') as Store -const pending = ref(false) +const pending = ref(false) const pendingFilename = ref('Comp.vue') const importMapFile = 'import-map.json' const showImportMap = inject('import-map') as Ref @@ -36,7 +36,7 @@ function startAddFile() { pending.value = true } -function cancelAddFile() { +function cancelNameFile() { pending.value = false } @@ -44,9 +44,10 @@ function focus({ el }: VNode) { ;(el as HTMLInputElement).focus() } -function doneAddFile() { +function doneNameFile() { if (!pending.value) return const filename = pendingFilename.value + const oldFilename = pending.value === true ? '' : pending.value if (!/\.(vue|js|ts|css|json)$/.test(filename)) { store.state.errors = [ @@ -55,14 +56,28 @@ function doneAddFile() { return } - if (filename in store.state.files) { + if (filename !== oldFilename && filename in store.state.files) { store.state.errors = [`File "${filename}" already exists.`] return } store.state.errors = [] - cancelAddFile() - store.addFile(filename) + cancelNameFile() + + if (filename === oldFilename) { + return + } + + if (oldFilename) { + store.renameFile(oldFilename, filename) + } else { + store.addFile(filename) + } +} + +function editFileName(file: string) { + pendingFilename.value = file + pending.value = file } const fileSel = ref(null) @@ -85,32 +100,35 @@ function horizontalScroll(e: WheelEvent) { @wheel="horizontalScroll" ref="fileSel" > -
- {{ - file === importMapFile ? 'Import Map' : file - }} - - - - - - -
-
- -
+
diff --git a/src/store.ts b/src/store.ts index 485c3b72..aaee2b31 100644 --- a/src/store.ts +++ b/src/store.ts @@ -67,6 +67,7 @@ export interface Store { setActive: (filename: string) => void addFile: (filename: string | File) => void deleteFile: (filename: string) => void + renameFile: (oldFilename: string, newFilename: string) => void getImportMap: () => any initialShowOutput: boolean initialOutputMode: OutputModes @@ -167,6 +168,42 @@ export class ReplStore implements Store { } } + renameFile(oldFilename: string, newFilename: string) { + const { files } = this.state + const file = files[oldFilename] + + if (!file) { + this.state.errors = [`Could not rename "${oldFilename}", file not found`] + return + } + + if (!newFilename || oldFilename === newFilename) { + this.state.errors = [`Cannot rename "${oldFilename}" to "${newFilename}"`] + return + } + + file.filename = newFilename + + const newFiles: Record = {} + + // Preserve iteration order for files + for (const name in files) { + if (name === oldFilename) { + newFiles[newFilename] = file + } else { + newFiles[name] = files[name] + } + } + + this.state.files = newFiles + + if (this.state.mainFile === oldFilename) { + this.state.mainFile = newFilename + } + + compileFile(this, file) + } + serialize() { const files = this.getFiles() const importMap = files['import-map.json']