-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #15 from HF6-PROJECT/kbi-9
feat: Files & Folders
- Loading branch information
Showing
18 changed files
with
761 additions
and
231 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<template> | ||
<div class="relative" v-on:contextmenu.prevent="openMenu"> | ||
<slot name="content"></slot> | ||
<div | ||
v-if="showMenu" | ||
ref="menu" | ||
v-on:blur="closeMenu" | ||
tabindex="-1" | ||
:style="{ top: `${top}px`, left: `${left}px` }" | ||
class="absolute z-10 block w-44 divide-y divide-gray-100 rounded-lg bg-white shadow dark:divide-gray-600 dark:bg-gray-700" | ||
> | ||
<slot name="menu"></slot> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { ref, onMounted, nextTick } from 'vue'; | ||
const menu = ref<HTMLElement | null>(null); | ||
const showMenu = ref(false); | ||
const top = ref(0); | ||
const left = ref(0); | ||
onMounted(() => console.log(menu.value)); | ||
function setMenu(y: number, x: number) { | ||
top.value = y; | ||
left.value = x; | ||
} | ||
function closeMenu() { | ||
showMenu.value = false; | ||
} | ||
function openMenu(e: MouseEvent) { | ||
showMenu.value = true; | ||
nextTick(() => { | ||
if (!menu.value) return; | ||
menu.value.focus(); | ||
setMenu(e.offsetY, e.offsetX); | ||
}); | ||
} | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<template> | ||
<a | ||
href="#" | ||
class="block max-w-sm rounded-lg border border-gray-200 bg-white p-6 shadow hover:bg-gray-100 dark:border-gray-700 dark:bg-gray-800 dark:hover:bg-gray-700" | ||
> | ||
<h5 class="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white"> | ||
{{ modelValue.name }} | ||
</h5> | ||
</a> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { type PropType } from 'vue'; | ||
import { FileClass } from '@lib/items/files'; | ||
defineProps({ | ||
modelValue: { | ||
type: Object as PropType<FileClass>, | ||
required: true, | ||
}, | ||
}); | ||
defineEmits(['update:modelValue']); | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
<template> | ||
<template v-if="!items.length"> | ||
<NoFiles /> | ||
</template> | ||
<template v-else> | ||
<div class="flex flex-wrap gap-3"> | ||
<!-- prettier-ignore-attribute --> | ||
<Folder | ||
v-for="folder in folders" | ||
:key="folder.id" | ||
v-model="(items[getItemIndex(folder)] as FolderClass)" | ||
/> | ||
</div> | ||
<div class="mt-3 flex flex-wrap gap-3"> | ||
<!-- prettier-ignore-attribute --> | ||
<File | ||
v-for="file in files" | ||
:key="file.id" | ||
v-model="(items[getItemIndex(file)] as FileClass)" | ||
/> | ||
</div> | ||
</template> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { computed, ref, type PropType } from 'vue'; | ||
import NoFiles from './NoFiles.vue'; | ||
import Folder from './Folder.vue'; | ||
import File from './File.vue'; | ||
import { ItemClass } from '@lib/items/items'; | ||
import { ItemFactory } from '@lib/items/factory'; | ||
import { FolderClass, type FolderType } from '@lib/items/folders'; | ||
import { FileClass } from '@lib/items/files'; | ||
import { api } from '@lib/helpers'; | ||
const props = defineProps({ | ||
modelValue: { | ||
type: Object as PropType<FolderType>, | ||
required: false, | ||
}, | ||
}); | ||
/** | ||
* Items | ||
*/ | ||
const items = ref<ItemClass[]>([]); | ||
getItems(); | ||
function getItems() { | ||
fetch(api(`item${FolderClass.isFolder(props.modelValue) ? `/${props.modelValue.id}` : ''}`), { | ||
method: 'GET', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
credentials: 'include', | ||
}) | ||
.then(async (response) => { | ||
if (!response.ok) { | ||
if (response.status >= 400 && response.status < 500) { | ||
throw new Error((await response.json()).error); | ||
} | ||
throw new Error(await response.text()); | ||
} | ||
const rawItems = await response.json(); | ||
for (const rawItem of rawItems) { | ||
if (!ItemClass.isItem(rawItem)) continue; | ||
const item = ItemFactory.getItemFromObject(rawItem); | ||
if (item === null) continue; | ||
items.value.push(item); | ||
} | ||
return items.value; | ||
}) | ||
.catch((error) => { | ||
console.error('Error:', error); | ||
}); | ||
} | ||
function getItemIndex(item: ItemClass) { | ||
return items.value.findIndex((i) => i.id === item.id); | ||
} | ||
/** | ||
* Folders | ||
*/ | ||
const folders = computed(() => { | ||
return items.value.filter((item) => item instanceof FolderClass) as FolderClass[]; | ||
}); | ||
/** | ||
* Files | ||
*/ | ||
const files = computed(() => { | ||
return items.value.filter((item) => item instanceof FileClass) as FileClass[]; | ||
}); | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
<template> | ||
<ContextMenu> | ||
<template v-slot:content> | ||
<a :href="url(`u/folder/${modelValue.id}`)"> | ||
<button | ||
type="button" | ||
:class="classes" | ||
class="h-[40px] rounded-lg bg-gradient-to-br px-5 py-2.5 text-center text-sm font-medium text-white hover:bg-gradient-to-bl focus:outline-none focus:ring-4 focus:ring-blue-300 dark:focus:ring-blue-800" | ||
> | ||
{{ modelValue.name }} | ||
</button> | ||
</a> | ||
</template> | ||
<template v-slot:menu> | ||
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200"> | ||
<li> | ||
<a | ||
:href="url(`u/folder/${modelValue.id}`)" | ||
target="_blank" | ||
class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white" | ||
>Open in new tab</a | ||
> | ||
</li> | ||
<li> | ||
<a | ||
href="#" | ||
class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white" | ||
>Change Name</a | ||
> | ||
</li> | ||
</ul> | ||
<div class="py-2"> | ||
<a | ||
href="#" | ||
class="block px-4 py-2 text-sm text-red-500 hover:bg-gray-100 dark:text-red-500 dark:hover:bg-gray-600" | ||
>Delete</a | ||
> | ||
</div> | ||
</template> | ||
</ContextMenu> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { type PropType, computed } from 'vue'; | ||
import { FolderClass } from '@lib/items/folders'; | ||
import { url } from '@lib/helpers'; | ||
import ContextMenu from './ContextMenu.vue'; | ||
const props = defineProps({ | ||
modelValue: { | ||
type: Object as PropType<FolderClass>, | ||
required: true, | ||
}, | ||
}); | ||
defineEmits(['update:modelValue']); | ||
const classes = computed(() => { | ||
return props.modelValue.colorClass; | ||
}); | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<template> | ||
<div class="flex w-full items-center justify-center"> | ||
<label | ||
for="dropzone-file" | ||
class="dark:hover:bg-bray-800 flex h-64 w-full cursor-pointer flex-col items-center justify-center rounded-lg border-2 border-dashed border-gray-300 bg-gray-50 hover:bg-gray-100 dark:border-gray-600 dark:bg-gray-700 dark:hover:border-gray-500 dark:hover:bg-gray-600" | ||
> | ||
<div class="flex flex-col items-center justify-center pb-6 pt-5"> | ||
<svg | ||
class="mb-4 h-8 w-8 text-gray-500 dark:text-gray-400" | ||
aria-hidden="true" | ||
xmlns="http://www.w3.org/2000/svg" | ||
fill="none" | ||
viewBox="0 0 20 16" | ||
> | ||
<path | ||
stroke="currentColor" | ||
stroke-linecap="round" | ||
stroke-linejoin="round" | ||
stroke-width="2" | ||
d="M13 13h3a3 3 0 0 0 0-6h-.025A5.56 5.56 0 0 0 16 6.5 5.5 5.5 0 0 0 5.207 5.021C5.137 5.017 5.071 5 5 5a4 4 0 0 0 0 8h2.167M10 15V6m0 0L8 8m2-2 2 2" | ||
/> | ||
</svg> | ||
<p class="mb-2 text-sm text-gray-500 dark:text-gray-400"> | ||
<span class="font-semibold">Click to upload</span> or drag and drop | ||
</p> | ||
<p class="text-xs text-gray-500 dark:text-gray-400"> | ||
SVG, PNG, JPG or GIF (MAX. 800x400px) | ||
</p> | ||
</div> | ||
<input id="dropzone-file" type="file" class="hidden" /> | ||
</label> | ||
</div> | ||
</template> | ||
|
||
<script setup lang="ts"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { FileClass } from './files'; | ||
import { FolderClass } from './folders'; | ||
import { type ItemType } from './items'; | ||
|
||
export class ItemFactory { | ||
static getItemFromObject(object: ItemType) { | ||
if (FolderClass.isFolder(object)) return new FolderClass(object); | ||
if (FileClass.isFile(object)) return new FileClass(object); | ||
|
||
console.error('ItemClass.getItemFromObject: Invalid object'); | ||
return null; | ||
} | ||
} |
Oops, something went wrong.