diff --git a/package-lock.json b/package-lock.json index 2bafe10..1a7c207 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,12 +16,15 @@ "@astrojs/ts-plugin": "^1.1.3", "@astrojs/vercel": "^5.0.1", "@astrojs/vue": "^3.0.0", + "@nanostores/vue": "^0.10.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", "jose": "^4.15.1", + "nanostores": "^0.9.3", "tailwind-scrollbar": "^3.0.5", "tailwindcss": "^3.3.3", "typescript": "^5.2.2", @@ -1246,6 +1249,28 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "node_modules/@nanostores/vue": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@nanostores/vue/-/vue-0.10.0.tgz", + "integrity": "sha512-832RAUbzRfHPs1CdqVEwfvgB2+RD/INji4Zo8bUSEfRO2pQRMMeq479gydnohGpRaa0oNwlfKo7TGFXCghq/1g==", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@nanostores/logger": ">=0.2.3", + "@vue/devtools-api": ">=6.5.0", + "nanostores": ">=0.9.2", + "vue": ">=3.3.1" + }, + "peerDependenciesMeta": { + "@nanostores/logger": { + "optional": true + }, + "@vue/devtools-api": { + "optional": true + } + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1693,6 +1718,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 +2026,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", @@ -5876,6 +5989,20 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/nanostores": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/nanostores/-/nanostores-0.9.3.tgz", + "integrity": "sha512-KobZjcVyNndNrb5DAjfs0WG0lRcZu5Q1BOrfTOxokFLi25zFrWPjg+joXC6kuDqNfSt9fQwppyjUBkRPtsL+8w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "engines": { + "node": "^16.0.0 || ^18.0.0 || >=20.0.0" + } + }, "node_modules/napi-build-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", diff --git a/package.json b/package.json index 8db8f9e..8e23002 100644 --- a/package.json +++ b/package.json @@ -35,12 +35,15 @@ "@astrojs/ts-plugin": "^1.1.3", "@astrojs/vercel": "^5.0.1", "@astrojs/vue": "^3.0.0", + "@nanostores/vue": "^0.10.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", "jose": "^4.15.1", + "nanostores": "^0.9.3", "tailwind-scrollbar": "^3.0.5", "tailwindcss": "^3.3.3", "typescript": "^5.2.2", diff --git a/src/components/base/confirmModal.vue b/src/components/base/confirmModal.vue new file mode 100644 index 0000000..048bc9b --- /dev/null +++ b/src/components/base/confirmModal.vue @@ -0,0 +1,86 @@ + + + + + diff --git a/src/components/base/contextMenu.vue b/src/components/base/contextMenu.vue new file mode 100644 index 0000000..58cf86b --- /dev/null +++ b/src/components/base/contextMenu.vue @@ -0,0 +1,57 @@ + + + diff --git a/src/components/base/modal.vue b/src/components/base/modal.vue new file mode 100644 index 0000000..fdeef2d --- /dev/null +++ b/src/components/base/modal.vue @@ -0,0 +1,76 @@ + + + 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 deleted file mode 100644 index 1fb9656..0000000 --- a/src/components/files/ContextMenu.vue +++ /dev/null @@ -1,47 +0,0 @@ - - - diff --git a/src/components/files/File.vue b/src/components/files/File.vue deleted file mode 100644 index f7a1399..0000000 --- a/src/components/files/File.vue +++ /dev/null @@ -1,23 +0,0 @@ - - - diff --git a/src/components/files/FileBrowser.vue b/src/components/files/FileBrowser.vue deleted file mode 100644 index 4ebccea..0000000 --- a/src/components/files/FileBrowser.vue +++ /dev/null @@ -1,103 +0,0 @@ - - - diff --git a/src/components/files/Folder.vue b/src/components/files/Folder.vue deleted file mode 100644 index 43912fc..0000000 --- a/src/components/files/Folder.vue +++ /dev/null @@ -1,60 +0,0 @@ - - - diff --git a/src/components/item/Browser.vue b/src/components/item/Browser.vue new file mode 100644 index 0000000..4935a90 --- /dev/null +++ b/src/components/item/Browser.vue @@ -0,0 +1,189 @@ + + + diff --git a/src/components/item/file/EditModal.vue b/src/components/item/file/EditModal.vue new file mode 100644 index 0000000..dac4d4a --- /dev/null +++ b/src/components/item/file/EditModal.vue @@ -0,0 +1,82 @@ + + + diff --git a/src/components/item/file/File.vue b/src/components/item/file/File.vue new file mode 100644 index 0000000..be9808b --- /dev/null +++ b/src/components/item/file/File.vue @@ -0,0 +1,88 @@ + + + diff --git a/src/components/files/NoFiles.vue b/src/components/item/file/NoFiles.vue similarity index 57% rename from src/components/files/NoFiles.vue rename to src/components/item/file/NoFiles.vue index 73c2215..06177c1 100644 --- a/src/components/files/NoFiles.vue +++ b/src/components/item/file/NoFiles.vue @@ -27,9 +27,44 @@ SVG, PNG, JPG or GIF (MAX. 800x400px)

- + - + diff --git a/src/components/item/folder/CreateModal.vue b/src/components/item/folder/CreateModal.vue new file mode 100644 index 0000000..eee6849 --- /dev/null +++ b/src/components/item/folder/CreateModal.vue @@ -0,0 +1,116 @@ + + + diff --git a/src/components/item/folder/EditModal.vue b/src/components/item/folder/EditModal.vue new file mode 100644 index 0000000..f19495a --- /dev/null +++ b/src/components/item/folder/EditModal.vue @@ -0,0 +1,121 @@ + + + diff --git a/src/components/item/folder/Folder.vue b/src/components/item/folder/Folder.vue new file mode 100644 index 0000000..085b663 --- /dev/null +++ b/src/components/item/folder/Folder.vue @@ -0,0 +1,104 @@ + + + diff --git a/src/lang/da.ts b/src/lang/da.ts index db707ce..7f62c62 100644 --- a/src/lang/da.ts +++ b/src/lang/da.ts @@ -43,6 +43,48 @@ export default { submit: 'Nulstil adgangskode', }, }, + 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', + editFolder: 'Rediger 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', + red: 'Rød', + orange: 'Orange', + amber: 'Rav', + yellow: 'Gul', + lime: 'Lime', + green: 'Grøn', + emerald: 'Smaragd', + teal: 'Blågrøn', + cyan: 'Cyan', + sky: 'Himmelblå', + blue: 'Blå', + indigo: 'Indigo', + violet: 'Violet', + purple: 'Lilla', + fuchsia: 'Fuchsia', + pink: 'Pink', + rose: 'Rose', + }, + }, + }, layout: { sr: { signOut: 'Log ud', @@ -57,4 +99,8 @@ export default { toggleThemeMode: 'Lys / mørk tilstand', }, }, + confirmModal: { + yesImSure: 'Ja, jeg er sikker', + noCancel: 'Nej, annuller', + }, }; diff --git a/src/lang/en.ts b/src/lang/en.ts index 332ade0..413b0dd 100644 --- a/src/lang/en.ts +++ b/src/lang/en.ts @@ -43,6 +43,48 @@ export default { submit: 'Reset password', }, }, + 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', + editFolder: 'Edit 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', + red: 'Red', + orange: 'Orange', + amber: 'Amber', + yellow: 'Yellow', + lime: 'Lime', + green: 'Green', + emerald: 'Emerald', + teal: 'Teal', + cyan: 'Cyan', + sky: 'Sky', + blue: 'Blue', + indigo: 'Indigo', + violet: 'Violet', + purple: 'Purple', + fuchsia: 'Fuchsia', + pink: 'Pink', + rose: 'Rose', + }, + }, + }, layout: { sr: { signOut: 'Sign out', @@ -57,4 +99,8 @@ export default { toggleThemeMode: 'Light / dark mode', }, }, + confirmModal: { + yesImSure: 'Yes, I am sure', + noCancel: 'No, cancel', + }, }; diff --git a/src/layouts/FooterSidebar.astro b/src/layouts/FooterSidebar.astro index f2b8d3c..3828ee1 100644 --- a/src/layouts/FooterSidebar.astro +++ b/src/layouts/FooterSidebar.astro @@ -2,85 +2,4 @@ import CopyrightNotice from '@components/CopyrightNotice.astro'; --- - - diff --git a/src/layouts/LayoutSidebar.astro b/src/layouts/LayoutSidebar.astro index 3d44a07..cee6d39 100644 --- a/src/layouts/LayoutSidebar.astro +++ b/src/layouts/LayoutSidebar.astro @@ -13,7 +13,7 @@ import SideBar from './SideBar.astro';
diff --git a/src/lib/contextMenu.ts b/src/lib/contextMenu.ts new file mode 100644 index 0000000..56f65cf --- /dev/null +++ b/src/lib/contextMenu.ts @@ -0,0 +1,14 @@ +import { useEventBus, type EventBusKey } from '@vueuse/core'; +import { isModalOpen } from '@stores/modal'; + +const contextMenuOpenEvent: EventBusKey<{ name: 'contextMenuOpen' }> = Symbol('contextMenuOpen'); + +const bus = useEventBus(contextMenuOpenEvent); + +isModalOpen.listen((isOpen) => { + if (isOpen) { + bus.emit(); + } +}); + +export default bus; diff --git a/src/lib/items/files.ts b/src/lib/items/files.ts index 021f950..339f766 100644 --- a/src/lib/items/files.ts +++ b/src/lib/items/files.ts @@ -1,5 +1,7 @@ import { ItemClass, type ItemType } from './items'; -import { FolderClass } from './folders'; +import { type FolderType } from './folders'; +import { upload } from '@vercel/blob/client'; +import { api } from '@lib/helpers'; export class FileClass extends ItemClass { private _blobUrl: string; @@ -10,23 +12,60 @@ export class FileClass extends ItemClass { this._blobUrl = fileObject.blobUrl; } - static create(name: string, parent: FolderClass | null) { - // TODO: Send request to create folder - - // Placeholder for now - const returnedFile = { - id: 1, - name: name, - mimeType: 'application/vnd.cloudstore.folder', - ownerId: 43535, - parentId: parent?.id || null, - deletedAt: null, - createdAt: new Date(), - updatedAt: new Date(), - blobUrl: 'https://www.google.com', - }; - - return new FileClass(returnedFile); + static async create(file: File, parent: FolderType | null) { + await upload(file.name, file, { + access: 'public', + handleUploadUrl: api('blob'), + clientPayload: JSON.stringify({ + parentId: parent?.id ?? null, + }), + }); + } + + 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() { diff --git a/src/lib/items/folders.ts b/src/lib/items/folders.ts index 951629b..ac06f04 100644 --- a/src/lib/items/folders.ts +++ b/src/lib/items/folders.ts @@ -1,3 +1,4 @@ +import { api } from '@lib/helpers'; import { ItemClass, type ItemType } from './items'; export class FolderClass extends ItemClass { @@ -9,23 +10,78 @@ export class FolderClass extends ItemClass { this._color = folderObject.color; } - static create(name: string, parent: FolderClass | null) { - // TODO: Send request to create folder - - // Placeholder for now - const returnedFolder = { - id: 1, - name: name, - mimeType: 'application/vnd.cloudstore.folder', - ownerId: 43535, - parentId: parent?.id || null, - deletedAt: null, - createdAt: new Date(), - updatedAt: new Date(), - color: FolderClass.randomColor(), - }; - - return new FolderClass(returnedFolder); + static async create(input: { name: string; parent: FolderType | null; color: FolderColor }) { + const response = await fetch(api('folder'), { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'include', + body: JSON.stringify({ + name: input.name, + parentId: input.parent?.id ?? null, + color: input.color, + }), + }); + + 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 FolderClass(await response.json()); + } + + async update(input: { name: string; color: FolderColor }) { + const response = await fetch(api('folder'), { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'include', + body: JSON.stringify({ + id: this.id, + name: input.name, + color: input.color, + }), + }); + + 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 FolderClass(await response.json()); + } + + 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() { @@ -36,12 +92,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; @@ -59,7 +109,7 @@ export type FolderType = { color: FolderColor; } & ItemType; -const FolderColors = { +export const FolderColors = { red: 'from-red-500 to-orange-500', orange: 'from-orange-500 to-amber-500', amber: 'from-amber-500 to-yellow-500', @@ -78,5 +128,5 @@ const FolderColors = { pink: 'from-pink-500 to-rose-500', rose: 'from-rose-500 to-red-500', }; -type FolderColor = keyof typeof FolderColors; +export type FolderColor = keyof typeof FolderColors; type FolderColorValue = (typeof FolderColors)[FolderColor]; diff --git a/src/lib/items/items.ts b/src/lib/items/items.ts index 29d1b7d..b371378 100644 --- a/src/lib/items/items.ts +++ b/src/lib/items/items.ts @@ -35,6 +35,10 @@ export abstract class ItemClass { return this._name; } + protected set name(value: string) { + this._name = value; + } + get mimeType() { return this._mimeType; } diff --git a/src/pages/u/folder/[id].astro b/src/pages/u/folder/[id].astro index c1c1c64..e9b19c8 100644 --- a/src/pages/u/folder/[id].astro +++ b/src/pages/u/folder/[id].astro @@ -1,6 +1,7 @@ --- import LayoutSidebar from '@layouts/LayoutSidebar.astro'; -import FileBrowser from '@components/files/FileBrowser.vue'; +// @ts-ignore +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'; @@ -36,7 +37,7 @@ const user = Astro.locals.user as User; --- -
- +
+
diff --git a/src/pages/u/index.astro b/src/pages/u/index.astro index 891cda0..e3fa003 100644 --- a/src/pages/u/index.astro +++ b/src/pages/u/index.astro @@ -1,13 +1,14 @@ --- import LayoutSidebar from '@layouts/LayoutSidebar.astro'; -import FileBrowser from '@components/files/FileBrowser.vue'; +// @ts-ignore +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; --- -
- +
+
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/src/stores/modal.ts b/src/stores/modal.ts new file mode 100644 index 0000000..7312a06 --- /dev/null +++ b/src/stores/modal.ts @@ -0,0 +1,3 @@ +import { atom } from 'nanostores'; + +export const isModalOpen = atom(false); 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,