mirror of
https://github.com/xlmnxp/extractify.zip.git
synced 2024-11-23 17:13:12 +03:00
support text editor (now it possible to view text files)
This commit is contained in:
parent
8b19f257ed
commit
dc764433ae
14
app.vue
14
app.vue
@ -17,8 +17,6 @@ let filesGridList = ref<any>([])
|
||||
let selectedList = ref<any>([]);
|
||||
let filesManager = new FilesManager(filesList);
|
||||
let history = new HistoryManager(filesManager);
|
||||
|
||||
const videoExtensions = ['mp4', 'avi', 'mov', 'mkv'];
|
||||
let mediaBlobUrl = ref('');
|
||||
|
||||
watchEffect(async () => {
|
||||
@ -27,7 +25,6 @@ watchEffect(async () => {
|
||||
filesList.value = [];
|
||||
|
||||
await filesManager.loadArchive(files.value?.[0]);
|
||||
|
||||
loadingModel.value = false;
|
||||
}
|
||||
})
|
||||
@ -68,7 +65,6 @@ watchEffect(async () => {
|
||||
// Experimental feature
|
||||
if (videoExtensions.includes(filesManager.getFile(selectedPath.value)?.extension?.toLowerCase())) {
|
||||
mediaBlobUrl.value = await filesManager.getFileBlobUrl(selectedPath.value) as string;
|
||||
console.log(mediaBlobUrl.value)
|
||||
}
|
||||
})
|
||||
|
||||
@ -162,15 +158,13 @@ function stepUp(path: string) {
|
||||
</v-row>
|
||||
</v-toolbar>
|
||||
<v-container>
|
||||
<template v-if="filesManager.getFile(selectedPath)?.isFolder || false">
|
||||
<template v-if="filesManager.getFile(selectedPath)?.isFolder">
|
||||
<v-list :selected="[selectedPath]">
|
||||
<v-row no-gutters>
|
||||
<v-col cols="6" lg="2" md="3" sm="6" v-for="file of filesGridList" style="text-align: center;">
|
||||
<v-list-item class="ma-2 pa-5 selectable" active-color="light-blue-darken-4" :value="file.path" rounded
|
||||
@click="selectedPath = file.path">
|
||||
<v-avatar class="mb-2" :color="file.isFolder ? 'light-blue-accent-4' : 'blue-grey-darken-1'">
|
||||
<v-icon color="white">{{ file.isFolder ? 'mdi-folder' : 'mdi-file' }}</v-icon>
|
||||
</v-avatar>
|
||||
<file-logo class="mb-2" :file="file" :key="file.path" />
|
||||
<p>{{ file.name }}</p>
|
||||
</v-list-item>
|
||||
</v-col>
|
||||
@ -181,6 +175,10 @@ function stepUp(path: string) {
|
||||
v-if="!filesManager.getFile(selectedPath)?.isFolder && videoExtensions.includes(filesManager.getFile(selectedPath)?.extension)">
|
||||
<MediaVideoPlayer :src="mediaBlobUrl"></MediaVideoPlayer>
|
||||
</template>
|
||||
<template
|
||||
v-if="!filesManager.getFile(selectedPath)?.isFolder && files.length && !videoExtensions.includes(filesManager.getFile(selectedPath)?.extension)">
|
||||
<TextEditor :file="filesManager.getFile(selectedPath)" :filesManager="filesManager"></TextEditor>
|
||||
</template>
|
||||
<template v-if="!files.length">
|
||||
<!-- tutorial drag and drop zipped file here and review it securely -->
|
||||
<v-row align="center" justify="center">
|
||||
|
27
components/file-logo.vue
Normal file
27
components/file-logo.vue
Normal file
@ -0,0 +1,27 @@
|
||||
<script lang="ts" setup>
|
||||
import { iFile } from '~/composables/worker/7zip-manager';
|
||||
|
||||
interface Props {
|
||||
file: iFile,
|
||||
}
|
||||
|
||||
let { file } = defineProps<Props>()
|
||||
|
||||
let icon = computed(() => {
|
||||
if (file.isFolder) return 'mdi-folder';
|
||||
|
||||
if (file.extension) {
|
||||
if (videoExtensions.includes(file.extension!)) return 'mdi-video';
|
||||
if (audioExtensions.includes(file.extension!)) return 'mdi-music';
|
||||
if (imageExtensions.includes(file.extension!)) return 'mdi-image';
|
||||
if (textExtensions.includes(file.extension!)) return 'mdi-file-document';
|
||||
}
|
||||
|
||||
return 'mdi-file';
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<v-avatar :color="file.isFolder ? 'light-blue-accent-4' : 'blue-grey-darken-1'">
|
||||
<v-icon color="white">{{ icon }}</v-icon>
|
||||
</v-avatar>
|
||||
</template>
|
40
components/text-editor.vue
Normal file
40
components/text-editor.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<script lang="ts" setup>
|
||||
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { FilesManager } from '~/composables/files-manager';
|
||||
// @ts-ignore
|
||||
import { iFile } from '~/composables/worker/7zip-manager';
|
||||
|
||||
interface Props {
|
||||
file: iFile,
|
||||
filesManager: FilesManager
|
||||
}
|
||||
|
||||
const editor = ref()
|
||||
|
||||
let { file, filesManager } = defineProps<Props>()
|
||||
|
||||
// files manager
|
||||
onMounted(async () => {
|
||||
const darkMode = window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
|
||||
let fileContent = await filesManager.getFileContent(file.path);
|
||||
monaco.editor.create(editor.value, {
|
||||
value: fileContent?.toString()!,
|
||||
language: file.extension,
|
||||
readOnly: true,
|
||||
theme: darkMode ? 'vs-dark' : 'vs-light'
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="editor" ref="editor"></div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
#editor {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
</style>
|
@ -14,15 +14,13 @@ let selectedPath = useSelectedPath();
|
||||
<template>
|
||||
<v-list :selected="[selectedPath]" density="compact" :nav="nav">
|
||||
<template v-for="file in filesList" :key="file.path">
|
||||
<v-list-item active-color="light-blue-darken-4" :active="selectedPath == file.path" :title="file.name" :subtitle="file.path"
|
||||
:value="file.path" @click="() => {
|
||||
<v-list-item active-color="light-blue-darken-4" :active="selectedPath == file.path" :title="file.name"
|
||||
:subtitle="file.path" :value="file.path" @click="() => {
|
||||
selectedPath = file.path;
|
||||
file.toggle = !file.toggle;
|
||||
}">
|
||||
<template v-slot:prepend>
|
||||
<v-avatar :color="file.isFolder ? 'light-blue-accent-4' : 'blue-grey-darken-1'">
|
||||
<v-icon color="white">{{ file.isFolder ? 'mdi-folder' : 'mdi-file' }}</v-icon>
|
||||
</v-avatar>
|
||||
<file-logo :file="file" :key="file.path" />
|
||||
</template>
|
||||
<template v-if="file.isFolder" v-slot:append>
|
||||
<v-icon>{{ `mdi-chevron-${file.toggle ? 'up' : 'down'}` }}</v-icon>
|
||||
|
@ -6,6 +6,11 @@ import * as Comlink from "comlink";
|
||||
import SevenZipWorker from "./worker/7zip-manager?worker";
|
||||
import { SevenZipManager, iFile } from "./worker/7zip-manager";
|
||||
|
||||
export const videoExtensions = ['mp4', 'avi', 'mov', 'mkv'];
|
||||
export const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||
export const audioExtensions = ['mp3', 'wav', 'ogg', 'flac'];
|
||||
export const textExtensions = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'md', 'js', 'ts', 'php', 'c', 'cpp', 'py', 'html', 'css', 'scss', 'sass', 'less', 'json', 'xml', 'sql', 'java', 'go', 'rb', 'sh', 'bat', 'ps1', 'cmd', 'yml', 'yaml', 'ini', 'toml', 'csv', 'tsv', 'gitignore', 'lock', 'htaccess', 'htpasswd', 'env', 'dockerfile', 'gitattributes', 'gitmodules', 'editorconfig', 'babelrc', 'eslintrc', 'eslintignore', 'prettierrc', 'prettierignore', 'stylelintrc', 'stylelintignore', 'postcssrc', 'postcss.config', 'jsx', 'tsx', 'license']
|
||||
|
||||
export class FilesManager {
|
||||
consoleOutputBuffer: string[] = [];
|
||||
path: Ref<string> = useSelectedPath();
|
||||
@ -68,4 +73,9 @@ export class FilesManager {
|
||||
if (!this.remoteSevenZipManager) return;
|
||||
return await this.remoteSevenZipManager.generateBlobUrl(JSON.stringify(this.getFile(path)) as any);
|
||||
}
|
||||
|
||||
async getFileContent(path: string) {
|
||||
if (!this.remoteSevenZipManager) return;
|
||||
return await this.remoteSevenZipManager.getFileContent(JSON.stringify(this.getFile(path)) as any);
|
||||
}
|
||||
}
|
@ -1,2 +1,4 @@
|
||||
import { FilesManager } from "./files-manager";
|
||||
|
||||
let selectedPath = ref("/")
|
||||
export const useSelectedPath = () => useState("selected-path", () => selectedPath)
|
@ -66,7 +66,7 @@ export class SevenZipManager {
|
||||
name: file.groups!.path.lastIndexOf('/') > -1 ? file.groups!.path.substring(file.groups!.path.lastIndexOf('/') + 1) : file.groups!.path,
|
||||
path: `/${file.groups!.path}`,
|
||||
isFolder: isFolder ? true : false,
|
||||
extension: isFolder ? "" : file.groups!.path.substring(file.groups!.path.lastIndexOf('.') + 1),
|
||||
extension: isFolder ? "" : file.groups!.path.substring(file.groups!.path.lastIndexOf('.') + 1).toLowerCase(),
|
||||
content: isFolder ? [] as any[] : undefined,
|
||||
}
|
||||
});
|
||||
@ -161,6 +161,23 @@ export class SevenZipManager {
|
||||
|
||||
return blobUrl;
|
||||
}
|
||||
|
||||
// get content from buffer (Experimental)
|
||||
async getFileContent(file: iFile) {
|
||||
if (!this.sevenZip) return;
|
||||
file = typeof file === "string" ? JSON.parse(file) : file;
|
||||
|
||||
// extract file from archive
|
||||
this.execute(['x', '-y', this.archiveName, file.path.substring(1)]);
|
||||
this.sevenZip.FS.chmod(file.path, 0o777);
|
||||
|
||||
// get file buffer
|
||||
const buffer = this.sevenZip.FS.readFile(file.path, { encoding: "utf8" });
|
||||
// remove the file after extract local blob url
|
||||
this.sevenZip.FS.unlink(file.path);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
Comlink.expose(SevenZipManager);
|
16
package-lock.json
generated
16
package-lock.json
generated
@ -15,13 +15,14 @@
|
||||
"7z-wasm": "^1.0.2",
|
||||
"comlink": "^4.4.1",
|
||||
"mime": "^3.0.0",
|
||||
"monaco-editor": "^0.45.0",
|
||||
"moveable": "^0.52.0",
|
||||
"sass": "^1.62.1",
|
||||
"selecto": "^1.26.2",
|
||||
"stateshot": "^1.3.5",
|
||||
"uuid": "^9.0.0",
|
||||
"vue-plyr": "^7.0.0",
|
||||
"vue3-selecto": "^1.12.2",
|
||||
"vue3-selecto": "^1.12.3",
|
||||
"vuetify": "^3.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -5254,6 +5255,11 @@
|
||||
"ufo": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/monaco-editor": {
|
||||
"version": "0.45.0",
|
||||
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.45.0.tgz",
|
||||
"integrity": "sha512-mjv1G1ZzfEE3k9HZN0dQ2olMdwIfaeAAjFiwNprLfYNRSz7ctv9XuCT7gPtBGrMUeV1/iZzYKj17Khu1hxoHOA=="
|
||||
},
|
||||
"node_modules/moveable": {
|
||||
"version": "0.52.0",
|
||||
"resolved": "https://registry.npmjs.org/moveable/-/moveable-0.52.0.tgz",
|
||||
@ -8499,11 +8505,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vue3-selecto": {
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmjs.org/vue3-selecto/-/vue3-selecto-1.12.2.tgz",
|
||||
"integrity": "sha512-GamgTxYLMnQ8/N1/lFeoyjcfzG7h7J9UUI1f+DH4CXBLq2EVOZ83CgG0TuOm1juxgNXbbmXcDIN72FRvUmTqKQ==",
|
||||
"version": "1.12.3",
|
||||
"resolved": "https://registry.npmjs.org/vue3-selecto/-/vue3-selecto-1.12.3.tgz",
|
||||
"integrity": "sha512-zIQLwuvjTNaivITLbBAnm6Sh8BFRG8QocNZLzKvqRIqnpRa2lvlIw9+l1wdI/84msh8cSNIdiWsgote62cgtHA==",
|
||||
"dependencies": {
|
||||
"selecto": "~1.26.2"
|
||||
"selecto": "~1.26.3"
|
||||
}
|
||||
},
|
||||
"node_modules/vuetify": {
|
||||
|
@ -25,13 +25,14 @@
|
||||
"7z-wasm": "^1.0.2",
|
||||
"comlink": "^4.4.1",
|
||||
"mime": "^3.0.0",
|
||||
"monaco-editor": "^0.45.0",
|
||||
"moveable": "^0.52.0",
|
||||
"sass": "^1.62.1",
|
||||
"selecto": "^1.26.2",
|
||||
"stateshot": "^1.3.5",
|
||||
"uuid": "^9.0.0",
|
||||
"vue-plyr": "^7.0.0",
|
||||
"vue3-selecto": "^1.12.2",
|
||||
"vue3-selecto": "^1.12.3",
|
||||
"vuetify": "^3.2.4"
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user