open zip folder and unrolling folder
This commit is contained in:
@ -5,6 +5,7 @@
|
||||
<!-- Première section -->
|
||||
<div
|
||||
class="w-full sm:w-1/3 max-sm:h-2/5 p-4 sm:m-6 rounded-xl bg-NcBlack/40">
|
||||
<WebContentViewer zipUrl="http://localhost:8000/dummyZip.zip"/>
|
||||
</div>
|
||||
<!-- Deuxième section -->
|
||||
<div
|
||||
@ -17,12 +18,14 @@
|
||||
|
||||
<script>
|
||||
import FileTable from './components/FileTable.vue';
|
||||
import WebContentViewer from './components/WebContentViewer.vue';
|
||||
import './output.css';
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
FileTable,
|
||||
WebContentViewer
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
151
src/components/WebContentViewer.vue
Normal file
151
src/components/WebContentViewer.vue
Normal file
@ -0,0 +1,151 @@
|
||||
<template>
|
||||
<div class="flex flex-col h-full w-full border">
|
||||
<div class="flex h-12 items-center border-b border-gray-300">
|
||||
<div class="w-5/6 px-4 py-2 text-gray-500 font-semibold border-r border-gray-300">Nom</div>
|
||||
<div class="w-1/6 px-4 py-2 text-gray-500 font-semibold">Taille</div>
|
||||
</div>
|
||||
<div class="overflow-y-auto">
|
||||
<div v-for="(file, index) in sortedFiles" :key="file.fullPath" class="flex flex-col">
|
||||
<div
|
||||
class="flex items-center pl-4 cursor-pointer"
|
||||
@click="toggleFolder(file)"
|
||||
v-if="file.isDirectory"
|
||||
>
|
||||
<div class="w-5/6 flex items-center px-4 py-2 truncate">
|
||||
<span class="mr-2">{{ folderMap[file.fullPath] ? '-' : '+' }}</span>
|
||||
{{ file.fullPath }}
|
||||
</div>
|
||||
<div class="w-1/6 px-4 py-2">-</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center pl-4"
|
||||
v-else
|
||||
>
|
||||
<div class="w-5/6 flex items-center px-4 py-2 truncate">
|
||||
{{ file.fullPath }}
|
||||
</div>
|
||||
<div class="w-1/6 px-4 py-2">
|
||||
{{ formatFileSize(file.size) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import JSZip from 'jszip';
|
||||
|
||||
export default {
|
||||
name: 'WebContentViewer',
|
||||
data() {
|
||||
return {
|
||||
zipContent: [],
|
||||
folderMap: {}, // Map to track folder open/close state
|
||||
};
|
||||
},
|
||||
props: {
|
||||
zipUrl: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
sortedFiles() {
|
||||
const flattenAndSort = (files, parentPath = '') => {
|
||||
const flatList = [];
|
||||
files.forEach(file => {
|
||||
const fullPath = parentPath ? `${parentPath}/${file.name}` : file.name;
|
||||
|
||||
// Toujours ajouter le dossier parent
|
||||
flatList.push({
|
||||
...file,
|
||||
fullPath,
|
||||
parentPath,
|
||||
});
|
||||
|
||||
// Ajouter les enfants uniquement si le dossier est ouvert
|
||||
if (file.isDirectory && this.folderMap[fullPath] && file.children) {
|
||||
flatList.push(...flattenAndSort(file.children, fullPath));
|
||||
}
|
||||
});
|
||||
|
||||
return flatList.sort((a, b) => a.fullPath.localeCompare(b.fullPath));
|
||||
};
|
||||
|
||||
|
||||
return flattenAndSort(this.zipContent);
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
await this.loadZipContent();
|
||||
},
|
||||
methods: {
|
||||
async loadZipContent() {
|
||||
try {
|
||||
const response = await fetch(this.zipUrl);
|
||||
const zipData = await response.blob();
|
||||
const zip = await JSZip.loadAsync(zipData);
|
||||
|
||||
const files = [];
|
||||
zip.forEach((relativePath, file) => {
|
||||
const pathParts = relativePath.split('/').filter(Boolean);
|
||||
|
||||
let currentLevel = files;
|
||||
for (let i = 0; i < pathParts.length; i++) {
|
||||
const partName = pathParts[i];
|
||||
const isDirectory = i < pathParts.length - 1 || file.dir;
|
||||
let existing = currentLevel.find(f => f.name === partName && f.isDirectory === isDirectory);
|
||||
|
||||
if (!existing) {
|
||||
existing = {
|
||||
name: partName,
|
||||
isDirectory,
|
||||
size: isDirectory ? 0 : file._data.uncompressedSize,
|
||||
children: isDirectory ? [] : null,
|
||||
};
|
||||
currentLevel.push(existing);
|
||||
}
|
||||
|
||||
if (isDirectory) {
|
||||
currentLevel = existing.children;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.zipContent = files;
|
||||
|
||||
// Initialize folderMap
|
||||
const initializeFolderMap = (files, parentPath = '') => {
|
||||
files.forEach(file => {
|
||||
const fullPath = parentPath ? `${parentPath}/${file.name}` : file.name;
|
||||
this.$set(this.folderMap, fullPath, true);
|
||||
if (file.isDirectory && file.children) {
|
||||
initializeFolderMap(file.children, fullPath);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
initializeFolderMap(this.zipContent);
|
||||
} catch (error) {
|
||||
console.error('Erreur lors du chargement du contenu du ZIP :', error);
|
||||
}
|
||||
},
|
||||
formatFileSize(size) {
|
||||
if (size < 1024) return `${size} B`;
|
||||
if (size < 1024 * 1024) return `${(size / 1024).toFixed(2)} KB`;
|
||||
if (size < 1024 * 1024 * 1024) return `${(size / 1024 / 1024).toFixed(2)} MB`;
|
||||
return `${(size / 1024 / 1024 / 1024).toFixed(2)} GB`;
|
||||
},
|
||||
toggleFolder(file) {
|
||||
if (!file.isDirectory) return;
|
||||
const currentState = this.folderMap[file.fullPath];
|
||||
this.$set(this.folderMap, file.fullPath, !currentState);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Ajoutez ici des styles si nécessaire */
|
||||
</style>
|
235
src/output.css
235
src/output.css
@ -579,6 +579,10 @@ video {
|
||||
}
|
||||
}
|
||||
|
||||
.visible {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.fixed {
|
||||
position: fixed;
|
||||
}
|
||||
@ -591,62 +595,46 @@ video {
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
.m-6 {
|
||||
margin: 1.5rem;
|
||||
.mb-4 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.ml-2 {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.ml-4 {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.mr-2 {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.mr-4 {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.ml-3 {
|
||||
margin-left: 0.75rem;
|
||||
}
|
||||
|
||||
.ml-4 {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.mt-1 {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.ml-auto {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.mb-4 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.mt-4 {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.ml-6 {
|
||||
margin-left: 1.5rem;
|
||||
}
|
||||
|
||||
.mr-6 {
|
||||
margin-right: 1.5rem;
|
||||
}
|
||||
|
||||
.inline {
|
||||
display: inline;
|
||||
.mr-2 {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.h-10 {
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.h-12 {
|
||||
height: 3rem;
|
||||
}
|
||||
@ -659,58 +647,55 @@ video {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.h-10 {
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.h-1\/3 {
|
||||
height: 33.333333%;
|
||||
}
|
||||
|
||||
.h-2\/3 {
|
||||
height: 66.666667%;
|
||||
.h-5 {
|
||||
height: 1.25rem;
|
||||
}
|
||||
|
||||
.max-h-8 {
|
||||
max-height: 2rem;
|
||||
}
|
||||
|
||||
.w-1\/3 {
|
||||
width: 33.333333%;
|
||||
}
|
||||
|
||||
.w-1\/6 {
|
||||
width: 16.666667%;
|
||||
}
|
||||
|
||||
.w-12 {
|
||||
width: 3rem;
|
||||
}
|
||||
|
||||
.w-2\/3 {
|
||||
width: 66.666667%;
|
||||
}
|
||||
|
||||
.w-4\/6 {
|
||||
width: 66.666667%;
|
||||
}
|
||||
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.w-10 {
|
||||
width: 2.5rem;
|
||||
}
|
||||
|
||||
.w-16 {
|
||||
width: 4rem;
|
||||
.w-12 {
|
||||
width: 3rem;
|
||||
}
|
||||
|
||||
.w-4\/6 {
|
||||
width: 66.666667%;
|
||||
}
|
||||
|
||||
.w-96 {
|
||||
width: 24rem;
|
||||
}
|
||||
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.w-5 {
|
||||
width: 1.25rem;
|
||||
}
|
||||
|
||||
.w-5\/6 {
|
||||
width: 83.333333%;
|
||||
}
|
||||
|
||||
.flex-grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.rotate-90 {
|
||||
--tw-rotate: 90deg;
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
.transform {
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
@ -735,10 +720,6 @@ video {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.justify-start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.justify-end {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
@ -767,14 +748,14 @@ video {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.rounded-xl {
|
||||
border-radius: 0.75rem;
|
||||
}
|
||||
|
||||
.rounded-md {
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
|
||||
.rounded-xl {
|
||||
border-radius: 0.75rem;
|
||||
}
|
||||
|
||||
.border {
|
||||
border-width: 1px;
|
||||
}
|
||||
@ -787,6 +768,10 @@ video {
|
||||
border-right-width: 1px;
|
||||
}
|
||||
|
||||
.border-t {
|
||||
border-top-width: 1px;
|
||||
}
|
||||
|
||||
.border-gray-300 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(209 213 219 / var(--tw-border-opacity, 1));
|
||||
@ -797,6 +782,10 @@ video {
|
||||
background-color: rgb(23 23 23 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-NcBlack\/40 {
|
||||
background-color: rgb(23 23 23 / 0.4);
|
||||
}
|
||||
|
||||
.bg-black\/80 {
|
||||
background-color: rgb(0 0 0 / 0.8);
|
||||
}
|
||||
@ -806,10 +795,6 @@ video {
|
||||
background-color: rgb(219 234 254 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-NcBlue\/20 {
|
||||
background-color: rgb(0 114 195 / 0.2);
|
||||
}
|
||||
|
||||
.bg-blue-600 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(37 99 235 / var(--tw-bg-opacity, 1));
|
||||
@ -825,17 +810,14 @@ video {
|
||||
background-color: rgb(55 65 81 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-white {
|
||||
.bg-gray-50 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
|
||||
background-color: rgb(249 250 251 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-NcBlack\/20 {
|
||||
background-color: rgb(23 23 23 / 0.2);
|
||||
}
|
||||
|
||||
.bg-NcBlack\/40 {
|
||||
background-color: rgb(23 23 23 / 0.4);
|
||||
.bg-NcGray {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(33 33 33 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-opacity-50 {
|
||||
@ -860,34 +842,47 @@ video {
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.px-2 {
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
.pl-8 {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
.pl-4 {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
.text-lg {
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
.font-semibold {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.font-medium {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.font-semibold {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.text-NcBlue {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(0 114 195 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-gray-500 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(107 114 128 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-blue-600 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(37 99 235 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-gray-500 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(107 114 128 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-gray-700 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(55 65 81 / var(--tw-text-opacity, 1));
|
||||
@ -898,6 +893,11 @@ video {
|
||||
color: rgb(255 255 255 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-red-500 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(239 68 68 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.shadow-lg {
|
||||
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
|
||||
@ -916,6 +916,12 @@ video {
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
.transition-transform {
|
||||
transition-property: transform;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
.last\:border-b-0:last-child {
|
||||
border-bottom-width: 0px;
|
||||
}
|
||||
@ -940,6 +946,11 @@ video {
|
||||
background-color: rgb(209 213 219 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.hover\:bg-gray-100:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(243 244 246 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.focus\:outline-none:focus {
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
@ -957,14 +968,6 @@ video {
|
||||
}
|
||||
|
||||
@media not all and (min-width: 640px) {
|
||||
.max-sm\:h-1\/3 {
|
||||
height: 33.333333%;
|
||||
}
|
||||
|
||||
.max-sm\:h-2\/3 {
|
||||
height: 66.666667%;
|
||||
}
|
||||
|
||||
.max-sm\:h-2\/5 {
|
||||
height: 40%;
|
||||
}
|
||||
@ -973,14 +976,6 @@ video {
|
||||
height: 60%;
|
||||
}
|
||||
|
||||
.max-sm\:w-1\/3 {
|
||||
width: 33.333333%;
|
||||
}
|
||||
|
||||
.max-sm\:w-2\/3 {
|
||||
width: 66.666667%;
|
||||
}
|
||||
|
||||
.max-sm\:max-w-32 {
|
||||
max-width: 8rem;
|
||||
}
|
||||
@ -991,18 +986,6 @@ video {
|
||||
margin: 1.5rem;
|
||||
}
|
||||
|
||||
.sm\:ml-2 {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.sm\:mr-2 {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.sm\:h-full {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.sm\:w-1\/3 {
|
||||
width: 33.333333%;
|
||||
}
|
||||
@ -1014,14 +997,4 @@ video {
|
||||
.sm\:flex-row {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
@media not all and (min-width: 640px) {
|
||||
.sm\:max-sm\:w-1\/3 {
|
||||
width: 33.333333%;
|
||||
}
|
||||
|
||||
.sm\:max-sm\:w-2\/3 {
|
||||
width: 66.666667%;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user