File type check and command component
65
src/App.vue
@@ -1,9 +1,13 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
import Input from './components/Input.vue'
|
||||
import Node from './components/Node.vue'
|
||||
import Navbar from './components/Navbar.vue'
|
||||
import Directory from './components/Directory.vue'
|
||||
|
||||
import Input from './components/Input.vue'
|
||||
import Command from './components/Command.vue'
|
||||
|
||||
import Commands from './../constants/Commands.js'
|
||||
|
||||
const fileUploaded = ref(false)
|
||||
const fileInfo = ref(null)
|
||||
@@ -14,28 +18,12 @@ const fileChanged = (file) => {
|
||||
fileData.value = file[0]
|
||||
fileUploaded.value = true
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="bg-black">
|
||||
<div class="min-h-screen min-w-screen flex flex-col items-center bg-blue-100 dark:bg-blue-800/10 gap-10 py-10">
|
||||
<div class="w-full text-center flex items-center justify-center">
|
||||
<div class="flex items-center justify-center bg-white dark:bg-gray-900 rounded-lg overflow-hidden text-sm">
|
||||
<div class="px-4 py-2 dark:text-white hover:text-blue-300 dark:hover:text-white dark:hover:bg-gray-700 cursor-pointer">
|
||||
Home
|
||||
</div>
|
||||
<div class="px-4 py-2 dark:text-white hover:text-blue-300 dark:hover:text-white dark:hover:bg-gray-700 cursor-pointer">
|
||||
Guide
|
||||
</div>
|
||||
<div class="px-4 py-2 dark:text-white hover:text-blue-300 dark:hover:text-white dark:hover:bg-gray-700 cursor-pointer">
|
||||
Code
|
||||
</div>
|
||||
<div class="px-4 py-2 dark:text-white hover:text-blue-300 dark:hover:text-white dark:hover:bg-gray-700 cursor-pointer">
|
||||
About
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Navbar />
|
||||
<div v-if="!fileUploaded" class="flex-grow flex flex-col items-center justify-center w-full">
|
||||
<div class="flex flex-col items-center justify-center bg-white dark:bg-gray-900 gap-8 p-12 rounded-xl border-gray-200 shadow w-[500px]">
|
||||
<div class="space-y-3 text-center">
|
||||
@@ -52,9 +40,7 @@ const fileChanged = (file) => {
|
||||
<div class="text-gray-500 dark:text-gray-400 text-sm">
|
||||
Example of a valid tree command:
|
||||
</div>
|
||||
<div class="w-full rounded-lg bg-gray-600 dark:bg-gray-800 text-white px-5 py-3 text-sm select-all">
|
||||
tree -h -J -L 2 . > tree.json
|
||||
</div>
|
||||
<Command :command="Commands.EXAMPLE_COMMAND" />
|
||||
<div class="text-gray-500 dark:text-gray-400 text-sm">
|
||||
For a more detailed explanation of the tree command and
|
||||
the valid list of options, please refer to the
|
||||
@@ -64,40 +50,7 @@ const fileChanged = (file) => {
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="flex-grow flex flex-col items-center justify-start w-full">
|
||||
<div class="text-white flex items-center justify-center w-full px-12">
|
||||
<div class="w-full space-y-4">
|
||||
<div v-if="fileInfo" class="text-center">
|
||||
<div class="flex items-center justify-center gap-4 text-sm">
|
||||
<div class="flex items-center gap-2 bg-gray-900 px-4 py-2 rounded cursor-pointer"
|
||||
@click="fileUploaded = false">
|
||||
<div class="text-gray-200" >
|
||||
Upload another file
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 bg-gray-900 px-4 py-2 rounded">
|
||||
<div class="font-medium text-gray-500">
|
||||
Number of directories:
|
||||
</div>
|
||||
<span class="text-gray-400">
|
||||
{{ fileInfo.directories }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 bg-gray-900 px-4 py-2 rounded">
|
||||
<div class="font-medium text-gray-500">
|
||||
Number of files:
|
||||
</div>
|
||||
<span class="text-gray-400">
|
||||
{{ fileInfo.files }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="fileData" class="bg-gray-900 p-10 rounded-lg text-center">
|
||||
<Node :node="fileData" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Directory :fileInfo="fileInfo" :fileData="fileData" @upload-another="fileUploaded = false" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
BIN
src/assets/icons/archive.png
Normal file
|
After Width: | Height: | Size: 304 B |
BIN
src/assets/icons/audio.png
Normal file
|
After Width: | Height: | Size: 336 B |
BIN
src/assets/icons/database.png
Normal file
|
After Width: | Height: | Size: 170 B |
BIN
src/assets/icons/development.png
Normal file
|
After Width: | Height: | Size: 337 B |
BIN
src/assets/icons/executable.png
Normal file
|
After Width: | Height: | Size: 485 B |
BIN
src/assets/icons/file.png
Normal file
|
After Width: | Height: | Size: 193 B |
BIN
src/assets/icons/folder-closed.png
Normal file
|
After Width: | Height: | Size: 316 B |
BIN
src/assets/icons/folder-open.png
Normal file
|
After Width: | Height: | Size: 567 B |
BIN
src/assets/icons/image.png
Normal file
|
After Width: | Height: | Size: 828 B |
BIN
src/assets/icons/spreadsheet.png
Normal file
|
After Width: | Height: | Size: 163 B |
BIN
src/assets/icons/system.png
Normal file
|
After Width: | Height: | Size: 321 B |
BIN
src/assets/icons/text.png
Normal file
|
After Width: | Height: | Size: 209 B |
BIN
src/assets/icons/video.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
35
src/components/Command.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import CommandArgument from './CommandArgument.vue'
|
||||
|
||||
const props = defineProps({
|
||||
command: Object
|
||||
})
|
||||
|
||||
const fullCommand = computed(() => {
|
||||
const fullCommand = props.command.map(x => x.argument)
|
||||
return fullCommand.join(' ')
|
||||
})
|
||||
|
||||
const copyCommmandToClipboard = () => {
|
||||
console.log(fullCommand.value)
|
||||
}
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div class="w-full rounded-lg bg-gray-600 dark:bg-gray-800 text-white px-5 py-2 text-sm select-all relative">
|
||||
<div class="flex items-center gap-1">
|
||||
<CommandArgument
|
||||
v-for="argument in command"
|
||||
:argument="argument.argument"
|
||||
:description="argument.description"
|
||||
/>
|
||||
</div>
|
||||
<div class="absolute right-0 bottom-0 top-0 flex items-center justify-center">
|
||||
<div @click="copyCommmandToClipboard"
|
||||
class="bg-blue-800/10 hover:bg-blue-800/20 rounded border border-blue-900/20 my-1 mr-2 py-1 px-2 text-xs cursor-pointer select-none">
|
||||
Copy
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
22
src/components/CommandArgument.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
argument: String,
|
||||
description: String
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="group relative">
|
||||
<div v-if="description" class="py-1 hover:bg-gray-500 cursor-help rounded select-none">
|
||||
{{ argument }}
|
||||
</div>
|
||||
<div v-else class="py-1 select-none">
|
||||
{{ argument }}
|
||||
</div>
|
||||
<div v-if="description" class="absolute bottom-1/2 left-1/2 mb-4 -translate-x-1/2 hidden group-hover:block">
|
||||
<div class="text-center px-2 py-1 bg-gray-900 border border-gray-700 rounded text-xs whitespace-nowrap">
|
||||
{{ description }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
44
src/components/Directory.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<script setup>
|
||||
import Node from './Node.vue'
|
||||
|
||||
const props = defineProps({
|
||||
fileInfo: Object,
|
||||
fileData: Object,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="text-white flex items-center justify-center w-full px-12">
|
||||
<div class="w-full space-y-4">
|
||||
<div v-if="fileInfo" class="text-center">
|
||||
<div class="flex items-center justify-center gap-4 text-sm">
|
||||
<div class="flex items-center gap-2 bg-gray-900 px-4 py-2 rounded cursor-pointer"
|
||||
@click="$emit('upload-another')">
|
||||
<div class="text-gray-200" >
|
||||
Upload another file
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 bg-gray-900 px-4 py-2 rounded">
|
||||
<div class="font-medium text-gray-500">
|
||||
Number of directories:
|
||||
</div>
|
||||
<span class="text-gray-400">
|
||||
{{ fileInfo.directories }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 bg-gray-900 px-4 py-2 rounded">
|
||||
<div class="font-medium text-gray-500">
|
||||
Number of files:
|
||||
</div>
|
||||
<span class="text-gray-400">
|
||||
{{ fileInfo.files }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="fileData" class="bg-gray-900 p-10 rounded-lg text-center">
|
||||
<Node :node="fileData" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
19
src/components/Navbar.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<div class="w-full text-center flex items-center justify-center">
|
||||
<div class="flex items-center justify-center bg-white dark:bg-gray-900 rounded-lg overflow-hidden text-sm">
|
||||
<div class="px-4 py-2 dark:text-white hover:text-blue-300 dark:hover:text-white dark:hover:bg-gray-700 cursor-pointer">
|
||||
Home
|
||||
</div>
|
||||
<div class="px-4 py-2 dark:text-white hover:text-blue-300 dark:hover:text-white dark:hover:bg-gray-700 cursor-pointer">
|
||||
Guide
|
||||
</div>
|
||||
<div class="px-4 py-2 dark:text-white hover:text-blue-300 dark:hover:text-white dark:hover:bg-gray-700 cursor-pointer">
|
||||
Code
|
||||
</div>
|
||||
<div class="px-4 py-2 dark:text-white hover:text-blue-300 dark:hover:text-white dark:hover:bg-gray-700 cursor-pointer">
|
||||
About
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { ref } from 'vue'
|
||||
import Node from './Node.vue'
|
||||
import NodeIcon from './NodeIcon.vue'
|
||||
import NodeInfo from './NodeInfo.vue'
|
||||
|
||||
const open = ref(false)
|
||||
|
||||
@@ -12,56 +14,17 @@ const props = defineProps({
|
||||
node: Object
|
||||
})
|
||||
|
||||
const format = computed(() => {
|
||||
if (props.node.type === 'file'){
|
||||
const filename = props.node.name.split('.')
|
||||
return filename[filename.length - 1]
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="space-y-3 node">
|
||||
<div class="bg-gray-800 flex items-center justify-between px-3 py-3 rounded gap-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<div v-if="node.type === 'directory'" class="p-2 bg-gray-900 rounded h-5 w-5 text-xs flex items-center justify-center">
|
||||
D
|
||||
</div>
|
||||
<div v-if="node.type === 'file'" class="p-2 bg-gray-900 rounded h-5 w-5 text-xs flex items-center justify-center">
|
||||
F
|
||||
</div>
|
||||
<NodeIcon :name="node.name" :type="node.type" :open="open" />
|
||||
<div class="text-xs select-none">
|
||||
{{ node.name }}
|
||||
</div>
|
||||
<div v-if="node.size" class="bg-gray-900 rounded px-2 py-1">
|
||||
<div class="text-xs flex items-center gap-1">
|
||||
<div class="font-medium text-gray-400">
|
||||
Size:
|
||||
</div>
|
||||
<div class="text-gray-500">
|
||||
{{ node.size }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="node.contents" class="bg-gray-900 rounded px-2 py-1">
|
||||
<div class="text-xs flex items-center gap-1">
|
||||
<div class="font-medium text-gray-400">
|
||||
Items:
|
||||
</div>
|
||||
<div class="text-gray-500">
|
||||
{{ node.contents.length }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="format" class="bg-gray-900 rounded px-2 py-1">
|
||||
<div class="text-xs flex items-center gap-1 font-semibold text-gray-400">
|
||||
{{ format }}
|
||||
</div>
|
||||
</div>
|
||||
<NodeInfo :node="node" />
|
||||
</div>
|
||||
<div v-if="node.type === 'directory' && node.contents.length" @click="toggleOpen">
|
||||
<div v-if="!open" class="text-xs bg-gray-900 rounded flex items-center justify-center cursor-pointer px-2 py-1">
|
||||
@@ -72,7 +35,7 @@ const format = computed(() => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="open">
|
||||
<div v-if="open">
|
||||
<div v-if="node.type === 'directory'" class="node-list space-y-3">
|
||||
<Node v-for="node in node.contents" :node="node" />
|
||||
</div>
|
||||
|
||||
72
src/components/NodeIcon.vue
Normal file
@@ -0,0 +1,72 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
|
||||
import Constants from '../../constants/Constants.js';
|
||||
|
||||
import FolderOpen from '../assets/icons/folder-open.png'
|
||||
import FolderClosed from '../assets/icons/folder-closed.png'
|
||||
|
||||
import File from '../assets/icons/file.png'
|
||||
import Archive from '../assets/icons/Archive.png'
|
||||
import Audio from '../assets/icons/Audio.png'
|
||||
import Database from '../assets/icons/Database.png'
|
||||
import Development from '../assets/icons/Development.png'
|
||||
import Executable from '../assets/icons/Executable.png'
|
||||
import Image from '../assets/icons/Image.png'
|
||||
import SpreadSheet from '../assets/icons/SpreadSheet.png'
|
||||
import System from '../assets/icons/System.png'
|
||||
import Text from '../assets/icons/Text.png'
|
||||
import Video from '../assets/icons/Video.png'
|
||||
|
||||
const FORMAT_ICONS = {
|
||||
'archive': Archive,
|
||||
'audio': Audio,
|
||||
'database': Database,
|
||||
'development': Development,
|
||||
'executable': Executable,
|
||||
'image': Image,
|
||||
'spreadsheet': SpreadSheet,
|
||||
'system': System,
|
||||
'text': Text,
|
||||
'video': Video,
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
name: String,
|
||||
type: String,
|
||||
open: Boolean
|
||||
})
|
||||
|
||||
const format = computed(() => {
|
||||
if (props.type === 'file'){
|
||||
const filename = props.name.split('.')
|
||||
const format = filename[filename.length - 1]
|
||||
return Constants.FILE_TYPES[format]
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
})
|
||||
|
||||
const icon = computed(() => {
|
||||
let icon = null
|
||||
if (format.value) {
|
||||
icon = FORMAT_ICONS[format.value]
|
||||
} else {
|
||||
icon = File
|
||||
}
|
||||
return icon
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="type === 'directory'" class="h-6 w-6">
|
||||
<img v-if="open" :src="FolderOpen" alt="directory">
|
||||
<img v-else :src="FolderClosed" alt="directory">
|
||||
</div>
|
||||
<div v-if="type === 'file'">
|
||||
<div class="w-6 h-6">
|
||||
<img :src="icon" :alt="format">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
29
src/components/NodeInfo.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
node: Object
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="node.size" class="bg-gray-900 rounded px-2 py-1">
|
||||
<div class="text-xs flex items-center gap-1">
|
||||
<div class="font-medium text-gray-400">
|
||||
Size:
|
||||
</div>
|
||||
<div class="text-gray-500">
|
||||
{{ node.size }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="node.contents" class="bg-gray-900 rounded px-2 py-1">
|
||||
<div class="text-xs flex items-center gap-1">
|
||||
<div class="font-medium text-gray-400">
|
||||
Items:
|
||||
</div>
|
||||
<div class="text-gray-500">
|
||||
{{ node.contents.length }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||