From 890cde4ed6a79153847480a0b8e801d07a4e8d47 Mon Sep 17 00:00:00 2001 From: Frederik Pytlick Date: Fri, 6 Oct 2023 21:31:50 +0200 Subject: [PATCH 1/8] #16 - Updated context menu's --- package-lock.json | 89 +++++++++++ package.json | 1 + src/components/base/modal.vue | 53 +++++++ src/components/base/select.vue | 50 +++++++ src/components/base/toast.vue | 122 +++++++++++++++ src/components/files/ContextMenu.vue | 46 +++--- src/components/files/File.vue | 50 +++++-- src/components/files/FileBrowser.vue | 212 ++++++++++++++++++++++----- src/components/files/Folder.vue | 47 +++--- src/layouts/FooterSidebar.astro | 81 ---------- src/layouts/LayoutSidebar.astro | 2 +- src/lib/contextMenu.ts | 7 + src/lib/items/files.ts | 31 ++-- src/lib/items/folders.ts | 85 +++++++++-- src/pages/u/folder/[id].astro | 2 +- src/pages/u/index.astro | 2 +- 16 files changed, 683 insertions(+), 197 deletions(-) create mode 100644 src/components/base/modal.vue create mode 100644 src/components/base/select.vue create mode 100644 src/components/base/toast.vue create mode 100644 src/lib/contextMenu.ts diff --git a/package-lock.json b/package-lock.json index 2bafe10..d18c15e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "@astrojs/vue": "^3.0.0", "@tauri-apps/api": "^1.5.0", "@vercel/blob": "^0.13.0", + "@vueuse/core": "^10.4.1", "astro": "^3.2.2", "flowbite": "^1.8.1", "flowbite-typography": "^1.0.3", @@ -1693,6 +1694,11 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.0.tgz", "integrity": "sha512-MFETx3tbTjE7Uk6vvnWINA/1iJ7LuMdO4fcq8UfF0pRbj01aGLduVvQcRyswuACJdpnHgg8E3rQLhaRdNEJS0w==" }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.17", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.17.tgz", + "integrity": "sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA==" + }, "node_modules/@types/yargs": { "version": "17.0.26", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.26.tgz", @@ -1996,6 +2002,89 @@ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz", "integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==" }, + "node_modules/@vueuse/core": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.4.1.tgz", + "integrity": "sha512-DkHIfMIoSIBjMgRRvdIvxsyboRZQmImofLyOHADqiVbQVilP8VVHDhBX2ZqoItOgu7dWa8oXiNnScOdPLhdEXg==", + "dependencies": { + "@types/web-bluetooth": "^0.0.17", + "@vueuse/metadata": "10.4.1", + "@vueuse/shared": "10.4.1", + "vue-demi": ">=0.14.5" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/core/node_modules/vue-demi": { + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", + "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.4.1.tgz", + "integrity": "sha512-2Sc8X+iVzeuMGHr6O2j4gv/zxvQGGOYETYXEc41h0iZXIRnRbJZGmY/QP8dvzqUelf8vg0p/yEA5VpCEu+WpZg==", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.4.1.tgz", + "integrity": "sha512-vz5hbAM4qA0lDKmcr2y3pPdU+2EVw/yzfRsBdu+6+USGa4PxqSQRYIUC9/NcT06y+ZgaTsyURw2I9qOFaaXHAg==", + "dependencies": { + "vue-demi": ">=0.14.5" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared/node_modules/vue-demi": { + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", + "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", diff --git a/package.json b/package.json index 8db8f9e..b88e31e 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "@astrojs/vue": "^3.0.0", "@tauri-apps/api": "^1.5.0", "@vercel/blob": "^0.13.0", + "@vueuse/core": "^10.4.1", "astro": "^3.2.2", "flowbite": "^1.8.1", "flowbite-typography": "^1.0.3", diff --git a/src/components/base/modal.vue b/src/components/base/modal.vue new file mode 100644 index 0000000..51d98ac --- /dev/null +++ b/src/components/base/modal.vue @@ -0,0 +1,53 @@ + + + diff --git a/src/components/base/select.vue b/src/components/base/select.vue new file mode 100644 index 0000000..f38147a --- /dev/null +++ b/src/components/base/select.vue @@ -0,0 +1,50 @@ + + + diff --git a/src/components/base/toast.vue b/src/components/base/toast.vue new file mode 100644 index 0000000..f14b56a --- /dev/null +++ b/src/components/base/toast.vue @@ -0,0 +1,122 @@ + + + + + diff --git a/src/components/files/ContextMenu.vue b/src/components/files/ContextMenu.vue index 1fb9656..58cf86b 100644 --- a/src/components/files/ContextMenu.vue +++ b/src/components/files/ContextMenu.vue @@ -1,32 +1,30 @@ diff --git a/src/components/files/File.vue b/src/components/files/File.vue index f7a1399..ddd515a 100644 --- a/src/components/files/File.vue +++ b/src/components/files/File.vue @@ -1,17 +1,49 @@ diff --git a/src/components/files/Folder.vue b/src/components/files/Folder.vue index 43912fc..a1f16b3 100644 --- a/src/components/files/Folder.vue +++ b/src/components/files/Folder.vue @@ -1,17 +1,19 @@ + + diff --git a/src/components/files/ContextMenu.vue b/src/components/base/contextMenu.vue similarity index 100% rename from src/components/files/ContextMenu.vue rename to src/components/base/contextMenu.vue diff --git a/src/components/files/FileBrowser.vue b/src/components/files/FileBrowser.vue deleted file mode 100644 index c793b71..0000000 --- a/src/components/files/FileBrowser.vue +++ /dev/null @@ -1,277 +0,0 @@ - - diff --git a/src/components/item/Browser.vue b/src/components/item/Browser.vue new file mode 100644 index 0000000..5f771ad --- /dev/null +++ b/src/components/item/Browser.vue @@ -0,0 +1,191 @@ + + diff --git a/src/components/item/file/EditModal.vue b/src/components/item/file/EditModal.vue new file mode 100644 index 0000000..3ae3f4d --- /dev/null +++ b/src/components/item/file/EditModal.vue @@ -0,0 +1,71 @@ + + + diff --git a/src/components/files/File.vue b/src/components/item/file/File.vue similarity index 51% rename from src/components/files/File.vue rename to src/components/item/file/File.vue index ddd515a..6e13352 100644 --- a/src/components/files/File.vue +++ b/src/components/item/file/File.vue @@ -1,5 +1,6 @@ diff --git a/src/components/files/NoFiles.vue b/src/components/item/file/NoFiles.vue similarity index 100% rename from src/components/files/NoFiles.vue rename to src/components/item/file/NoFiles.vue diff --git a/src/components/item/folder/CreateModal.vue b/src/components/item/folder/CreateModal.vue new file mode 100644 index 0000000..d40c325 --- /dev/null +++ b/src/components/item/folder/CreateModal.vue @@ -0,0 +1,100 @@ + + + diff --git a/src/components/item/folder/EditModal.vue b/src/components/item/folder/EditModal.vue new file mode 100644 index 0000000..6380203 --- /dev/null +++ b/src/components/item/folder/EditModal.vue @@ -0,0 +1,105 @@ + + + diff --git a/src/components/files/Folder.vue b/src/components/item/folder/Folder.vue similarity index 55% rename from src/components/files/Folder.vue rename to src/components/item/folder/Folder.vue index a1f16b3..66151b9 100644 --- a/src/components/files/Folder.vue +++ b/src/components/item/folder/Folder.vue @@ -1,5 +1,6 @@ @@ -53,19 +76,42 @@ import { type PropType, computed, ref } from 'vue'; import { FolderClass } from '@lib/items/folders'; import { url } from '@lib/helpers'; -import ContextMenu from './ContextMenu.vue'; +import ContextMenu from '@components/base/contextMenu.vue'; +import BaseConfirmModal, { ConfirmModalType } from '@components/base/confirmModal.vue'; +import EditFolderModal from './EditModal.vue'; +import { t } from '@lib/i18n'; +import { removeItem } from '@stores/items'; const folderContextMenu = ref>(); +defineEmits(['update:modelValue']); const props = defineProps({ modelValue: { type: Object as PropType, required: true, }, }); -defineEmits(['update:modelValue']); const classes = computed(() => { return props.modelValue.colorClass; }); + +const showDeleteModal = ref(false); +async function deleteFolder() { + try { + await props.modelValue.delete(); + + removeItem(props.modelValue); + + // TODO: Show success toast + } catch (e) { + console.error('Error: ' + e); + + // TODO: Show error toast + } + + showDeleteModal.value = false; +} + +const showEditModal = ref(false); diff --git a/src/lang/da.ts b/src/lang/da.ts index 2029975..fd1134b 100644 --- a/src/lang/da.ts +++ b/src/lang/da.ts @@ -46,11 +46,21 @@ export default { fileBrowser: { file: { uploadFile: 'Upload fil', + renameFile: 'Omdøb fil', + name: 'Navn', + delete: 'Slet', + rename: 'Omdøb', + areYouSureYouWantToDeleteThisFile: 'Er du sikker på, at du vil slette denne fil?', }, folder: { name: 'Navn', createFolder: 'Opret mappe', create: 'Opret', + edit: 'Rediger', + share: 'Del', + delete: 'Slet', + openInNewTab: 'Åben i ny fane', + areYouSureYouWantToDeleteThisFolder: 'Er du sikker på, at du vil slette denne mappe?', color: { name: 'Farve', required: 'Farve er påkrævet', @@ -88,4 +98,6 @@ export default { toggleThemeMode: 'Lys / mørk tilstand', }, }, + yesImSure: 'Ja, jeg er sikker', + noCancel: 'Nej, annuller', }; diff --git a/src/lang/en.ts b/src/lang/en.ts index f0b0230..40275fc 100644 --- a/src/lang/en.ts +++ b/src/lang/en.ts @@ -46,11 +46,21 @@ export default { fileBrowser: { file: { uploadFile: 'Upload file', + renameFile: 'Rename file', + name: 'Name', + delete: 'Delete', + rename: 'Rename', + areYouSureYouWantToDeleteThisFile: 'Are you sure you want to delete this file?', }, folder: { name: 'Name', createFolder: 'Create folder', create: 'Create', + edit: 'Edit', + share: 'Share', + delete: 'Delete', + openInNewTab: 'Open in new tab', + areYouSureYouWantToDeleteThisFolder: 'Are you sure you want to delete this folder?', color: { name: 'Color', required: 'Color is required', @@ -88,4 +98,6 @@ export default { toggleThemeMode: 'Light / dark mode', }, }, + yesImSure: 'Yes, I am sure', + noCancel: 'No, cancel', }; diff --git a/src/lib/items/files.ts b/src/lib/items/files.ts index 3303981..339f766 100644 --- a/src/lib/items/files.ts +++ b/src/lib/items/files.ts @@ -22,6 +22,52 @@ export class FileClass extends ItemClass { }); } + async update(input: { name: string }) { + const response = await fetch(api('blob'), { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'include', + body: JSON.stringify({ + id: this.id, + name: input.name, + }), + }); + + if (!response.ok) { + if (response.status >= 400 && response.status < 500) { + const json = await response.json(); + + throw new Error(json.error); + } + + throw new Error(await response.text()); + } + + return new FileClass(await response.json()); + } + + async delete() { + const response = await fetch(api('blob/' + this.id), { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'include', + }); + + if (!response.ok) { + if (response.status >= 400 && response.status < 500) { + const json = await response.json(); + + throw new Error(json.error); + } + + throw new Error(await response.text()); + } + } + get blobUrl() { return this._blobUrl; } diff --git a/src/lib/items/folders.ts b/src/lib/items/folders.ts index d3000c0..5a1e966 100644 --- a/src/lib/items/folders.ts +++ b/src/lib/items/folders.ts @@ -48,37 +48,51 @@ export class FolderClass extends ItemClass { return new FolderClass(returnedFolder); } - async delete() { - return await fetch(api('folder/' + this.id), { - method: 'DELETE', + async update(input: { name: string; color: FolderColor }) { + const response = await fetch(api('folder'), { + method: 'PUT', headers: { 'Content-Type': 'application/json', }, credentials: 'include', - }) - .then(async (response) => { - if (!response.ok) { - if (response.status >= 400 && response.status < 500) { - const json = await response.json(); + body: JSON.stringify({ + id: this.id, + name: input.name, + color: input.color, + }), + }); - throw new Error(json.error); - } + if (!response.ok) { + if (response.status >= 400 && response.status < 500) { + const json = await response.json(); - throw new Error(await response.text()); - } + throw new Error(json.error); + } - return response.json(); - }) - .then((data) => { - console.log('Success:', data); + throw new Error(await response.text()); + } - return true; - }) - .catch((error) => { - console.error('Error:', error); + return new FolderClass(await response.json()); + } - return false; - }); + async delete() { + const response = await fetch(api('folder/' + this.id), { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'include', + }); + + if (!response.ok) { + if (response.status >= 400 && response.status < 500) { + const json = await response.json(); + + throw new Error(json.error); + } + + throw new Error(await response.text()); + } } get color() { @@ -89,12 +103,6 @@ export class FolderClass extends ItemClass { return FolderColors[this._color]; } - private static randomColor() { - return Object.keys(FolderColors)[ - Math.floor(Math.random() * Object.keys(FolderColors).length) - ] as FolderColor; - } - static isFolder(object: any): object is FolderType { if (!ItemClass.isItem(object)) return false; diff --git a/src/pages/u/folder/[id].astro b/src/pages/u/folder/[id].astro index 13cf3bf..1dc8dea 100644 --- a/src/pages/u/folder/[id].astro +++ b/src/pages/u/folder/[id].astro @@ -1,6 +1,6 @@ --- import LayoutSidebar from '@layouts/LayoutSidebar.astro'; -import FileBrowser from '@components/files/FileBrowser.vue'; +import Browser from '@components/item/Browser.vue'; // @ts-ignore https://github.com/withastro/language-tools/issues/476 import { api, url } from '@lib/helpers'; import { FolderClass } from '@lib/items/folders'; @@ -37,6 +37,6 @@ const user = Astro.locals.user as User;
- +
diff --git a/src/pages/u/index.astro b/src/pages/u/index.astro index 7217976..9050989 100644 --- a/src/pages/u/index.astro +++ b/src/pages/u/index.astro @@ -1,6 +1,6 @@ --- import LayoutSidebar from '@layouts/LayoutSidebar.astro'; -import FileBrowser from '@components/files/FileBrowser.vue'; +import Browser from '@components/item/Browser.vue'; // We can safely cast this as we know that middleware would have already checked for a valid user const user = Astro.locals.user as User; @@ -8,6 +8,6 @@ const user = Astro.locals.user as User;
- +
diff --git a/src/stores/items.ts b/src/stores/items.ts new file mode 100644 index 0000000..f43a2ae --- /dev/null +++ b/src/stores/items.ts @@ -0,0 +1,16 @@ +import { map } from 'nanostores'; +import type { ItemClass } from '@lib/items/items'; + +export const itemsStore = map>({}); + +export function addItem(item: ItemClass) { + itemsStore.setKey(item.id, item); +} + +export function updateItem(item: ItemClass) { + itemsStore.setKey(item.id, item); +} + +export function removeItem(item: ItemClass) { + itemsStore.setKey(item.id, undefined); +} diff --git a/tsconfig.json b/tsconfig.json index a2b7fc2..e8aedb7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,8 @@ "paths": { "@components/*": ["src/components/*"], "@layouts/*": ["src/layouts/*"], - "@lib/*": ["src/lib/*"] + "@lib/*": ["src/lib/*"], + "@stores/*": ["src/stores/*"] }, "strictNullChecks": true, "verbatimModuleSyntax": true, From 7c5509ffeb924aea7ccbc3456c0fa4a7c2bd9779 Mon Sep 17 00:00:00 2001 From: Frederik Pytlick Date: Mon, 9 Oct 2023 09:39:05 +0200 Subject: [PATCH 4/8] #16 - Last changes before review --- src/components/item/Browser.vue | 5 +---- src/components/item/file/EditModal.vue | 5 +---- src/components/item/folder/CreateModal.vue | 5 +---- src/components/item/folder/EditModal.vue | 7 ++----- src/lang/da.ts | 1 + src/lang/en.ts | 1 + 6 files changed, 7 insertions(+), 17 deletions(-) diff --git a/src/components/item/Browser.vue b/src/components/item/Browser.vue index 5f771ad..5d5b78f 100644 --- a/src/components/item/Browser.vue +++ b/src/components/item/Browser.vue @@ -104,10 +104,7 @@ getItems(); async function getItems() { try { const response = await fetch( - /* TODO: use api function */ - `http://localhost:3000/api/${ - FolderClass.isFolder(props.modelValue) ? `${props.modelValue.id}` : '' - }`, + api(`item/${FolderClass.isFolder(props.modelValue) ? `${props.modelValue.id}` : ''}`), { method: 'GET', headers: { diff --git a/src/components/item/file/EditModal.vue b/src/components/item/file/EditModal.vue index 3ae3f4d..21ad0c2 100644 --- a/src/components/item/file/EditModal.vue +++ b/src/components/item/file/EditModal.vue @@ -52,10 +52,7 @@ async function updateFile() { updateItem(updatedFile); - /*toasts.value.push({ - message: `Folder ${folder.value.name} created`, - type: ToastType.Success, - });*/ + // TODO: Show success toast closeUpdateFileModal(); } catch (e) {} diff --git a/src/components/item/folder/CreateModal.vue b/src/components/item/folder/CreateModal.vue index d40c325..a9690df 100644 --- a/src/components/item/folder/CreateModal.vue +++ b/src/components/item/folder/CreateModal.vue @@ -83,10 +83,7 @@ async function createFolder() { addItem(createdFolder); - /*toasts.value.push({ - message: `Folder ${folder.value.name} created`, - type: ToastType.Success, - });*/ + // TODO: Show success toast closeCreateFolderModal(); } catch (e) {} diff --git a/src/components/item/folder/EditModal.vue b/src/components/item/folder/EditModal.vue index 6380203..9b49922 100644 --- a/src/components/item/folder/EditModal.vue +++ b/src/components/item/folder/EditModal.vue @@ -1,6 +1,6 @@