Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Files & Folders #15

Merged
merged 10 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
373 changes: 161 additions & 212 deletions package-lock.json

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,26 @@
},
"dependencies": {
"@astrojs/check": "^0.2.0",
"@astrojs/node": "^6.0.0",
"@astrojs/node": "^6.0.2",
"@astrojs/sitemap": "^3.0.0",
"@astrojs/tailwind": "^5.0.0",
"@astrojs/ts-plugin": "^1.1.3",
"@astrojs/vercel": "^5.0.1",
"@astrojs/vue": "^3.0.0",
"@tauri-apps/api": "^1.4.0",
"@vercel/blob": "^0.12.5",
"astro": "^3.1.1",
"@tauri-apps/api": "^1.5.0",
"@vercel/blob": "^0.13.0",
"astro": "^3.2.2",
"flowbite": "^1.8.1",
"flowbite-typography": "^1.0.3",
"jose": "^4.14.6",
"jose": "^4.15.1",
"tailwind-scrollbar": "^3.0.5",
"tailwindcss": "^3.3.3",
"typescript": "^5.2.2",
"vite": "^4.4.9",
"vue": "^3.3.4"
},
"devDependencies": {
"@tauri-apps/cli": "^1.4.0",
"@tauri-apps/cli": "^1.5.1",
"dotenv": "^16.3.1",
"prettier": "^3.0.3",
"prettier-plugin-astro": "^0.12.0",
Expand Down
7 changes: 0 additions & 7 deletions src/components/Dashboard.astro

This file was deleted.

47 changes: 47 additions & 0 deletions src/components/files/ContextMenu.vue
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>
23 changes: 23 additions & 0 deletions src/components/files/File.vue
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>
103 changes: 103 additions & 0 deletions src/components/files/FileBrowser.vue
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;
kristianbinau marked this conversation as resolved.
Show resolved Hide resolved

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>
60 changes: 60 additions & 0 deletions src/components/files/Folder.vue
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
kristianbinau marked this conversation as resolved.
Show resolved Hide resolved
>
</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
kristianbinau marked this conversation as resolved.
Show resolved Hide resolved
>
</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
kristianbinau marked this conversation as resolved.
Show resolved Hide resolved
>
</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>
35 changes: 35 additions & 0 deletions src/components/files/NoFiles.vue
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
kristianbinau marked this conversation as resolved.
Show resolved Hide resolved
</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>
2 changes: 1 addition & 1 deletion src/lang/da.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export default {
openUserMenu: 'Åben brugermenu',
},
link: {
dashboard: 'Hjem',
myfiles: 'Mine Filer',
settings: 'Indstillinger',
signOut: 'Log ud',
},
Expand Down
2 changes: 1 addition & 1 deletion src/lang/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export default {
openUserMenu: 'Open user menu',
},
link: {
dashboard: 'Dashboard',
myfiles: 'My Files',
settings: 'Settings',
signOut: 'Sign out',
},
Expand Down
2 changes: 1 addition & 1 deletion src/layouts/SideBar.astro
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import { t } from '@lib/i18n';
d="M12 2.252A8.014 8.014 0 0117.748 8H12V2.252z"></path></svg
>
<span class="ml-3" sidebar-toggle-item
>{t('layout.link.dashboard', Astro.locals.currentLocale)}</span
>{t('layout.link.myfiles', Astro.locals.currentLocale)}</span
>
</a>
</li>
Expand Down
13 changes: 13 additions & 0 deletions src/lib/items/factory.ts
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;
}
}
Loading