From bd26b2800e2675613c6990673ad0b7b5175aa841 Mon Sep 17 00:00:00 2001 From: Leonardo Bishop Date: Wed, 13 Mar 2024 19:33:33 +0000 Subject: Add zip export --- components/export/ExportModal.vue | 10 +++++- components/export/ExportZipButton.vue | 18 ++++++++++ components/export/ExportZipModal.vue | 67 ++++++++++++++++++++++++++++++++++ data/testData.json | 2 +- lib/questsLoader.ts | 22 ++++++++++-- package-lock.json | 68 +++++++++++++++++++++++++++++++++++ package.json | 2 ++ pages/import.vue | 4 +++ plugins/jszip.ts | 5 +++ stores/export.ts | 31 ++++++++++++++++ stores/session.ts | 12 +++---- utils/zipExporter.ts | 33 +++++++++++++++++ 12 files changed, 264 insertions(+), 10 deletions(-) create mode 100644 components/export/ExportZipButton.vue create mode 100644 components/export/ExportZipModal.vue create mode 100644 plugins/jszip.ts create mode 100644 stores/export.ts create mode 100644 utils/zipExporter.ts diff --git a/components/export/ExportModal.vue b/components/export/ExportModal.vue index 8bc6936..1d09914 100644 --- a/components/export/ExportModal.vue +++ b/components/export/ExportModal.vue @@ -41,6 +41,10 @@ defineExpose({ You did not start this session by importing from file system.

+

+ + Not yet implemented. +

@@ -56,6 +60,10 @@ defineExpose({

Send to Server

Upload your quest configuration to the server, which can be downloaded and automatically applied in-game.

+

+ + Not yet implemented. +

@@ -73,7 +81,7 @@ defineExpose({
-
diff --git a/components/export/ExportZipButton.vue b/components/export/ExportZipButton.vue new file mode 100644 index 0000000..8fb6f60 --- /dev/null +++ b/components/export/ExportZipButton.vue @@ -0,0 +1,18 @@ + + + \ No newline at end of file diff --git a/components/export/ExportZipModal.vue b/components/export/ExportZipModal.vue new file mode 100644 index 0000000..b84690d --- /dev/null +++ b/components/export/ExportZipModal.vue @@ -0,0 +1,67 @@ + + + + + \ No newline at end of file diff --git a/data/testData.json b/data/testData.json index 268a780..23f4604 100644 --- a/data/testData.json +++ b/data/testData.json @@ -384,7 +384,7 @@ "items": { "coolsword": { "type": "defined", - "configuration": { + "item": { "type": "DIAMOND_SWORD", "name": "Super cool sword" } diff --git a/lib/questsLoader.ts b/lib/questsLoader.ts index 296afc3..f49dce5 100644 --- a/lib/questsLoader.ts +++ b/lib/questsLoader.ts @@ -1,4 +1,4 @@ -import type { EditorQuest, EditorTask, EditorCategory } from '../stores/session'; +import type { EditorQuest, EditorTask, EditorCategory, EditorItem } from '../stores/session'; export function loadQuestsFromJson(config: any): EditorQuest[] { return Object.keys(config).map((questid: any) => { @@ -74,7 +74,7 @@ export function loadItemsFromJson(config: any): EditorItem[] { return { id: itemid, type: item.type, - config: item.config, + config: item.item, }; }); } @@ -119,4 +119,22 @@ export function mapJsonQuestToYamlObject(quest: EditorQuest): any { ...(quest.options.lockedDisplay && { lockedDisplay: quest.options.lockedDisplay }), }, } +} + +export function mapJsonCategoryToYamlObject(category: EditorCategory): any { + return { + display: { + name: category.display.name, + type: category.display.type, + lore: category.display.lore, + }, + "permission-required": category.permissionRequired, + } +} + +export function mapJsonItemToYamlObject(item: EditorItem): any { + return { + type: item.type, + item: item.config + } } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 11c78fb..9d2ce49 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,8 @@ "@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/vue-fontawesome": "^3.0.6", "@pinia/nuxt": "^0.5.1", + "file-saver": "^2.0.5", + "jszip": "^3.10.1", "nuxt": "^3.10.3", "pinia": "^2.1.7", "vue": "^3.4.15", @@ -5844,6 +5846,11 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" + }, "node_modules/file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -6440,6 +6447,11 @@ "resolved": "https://registry.npmjs.org/image-meta/-/image-meta-0.2.0.tgz", "integrity": "sha512-ZBGjl0ZMEMeOC3Ns0wUF/5UdUmr3qQhBSCniT0LxOgGGIRHiNFOkMtIHB7EOznRU47V2AxPgiVP+s+0/UCU0Hg==" }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" + }, "node_modules/immutable": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", @@ -6881,6 +6893,44 @@ "node >= 0.2.0" ] }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -6976,6 +7026,14 @@ "node": ">= 0.8.0" } }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/lilconfig": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", @@ -9187,6 +9245,11 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -10448,6 +10511,11 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", diff --git a/package.json b/package.json index bd11781..ef5b178 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,8 @@ "@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/vue-fontawesome": "^3.0.6", "@pinia/nuxt": "^0.5.1", + "file-saver": "^2.0.5", + "jszip": "^3.10.1", "nuxt": "^3.10.3", "pinia": "^2.1.7", "vue": "^3.4.15", diff --git a/pages/import.vue b/pages/import.vue index f977538..7397358 100644 --- a/pages/import.vue +++ b/pages/import.vue @@ -37,6 +37,10 @@ const discardSessionModal = ref |

Retrieve from In-Game

Download quest data uploaded from in-game.

+

+ + Not yet implemented. +

diff --git a/plugins/jszip.ts b/plugins/jszip.ts new file mode 100644 index 0000000..edf0206 --- /dev/null +++ b/plugins/jszip.ts @@ -0,0 +1,5 @@ +import JSZip from "jszip" + +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.vueApp.use(JSZip) +}) diff --git a/stores/export.ts b/stores/export.ts new file mode 100644 index 0000000..3f48aa3 --- /dev/null +++ b/stores/export.ts @@ -0,0 +1,31 @@ +import { defineStore } from 'pinia' + +export type ZipLoaderStatus = 'inactive' | 'preparing' | 'compressing' | 'ready' | 'failed'; + +export const useExportStore = defineStore('export', { + state: () => ({ + zip: { + status: 'inactive' as ZipLoaderStatus, + contents: null as Blob | null, + } + }), + getters: { + getZipStatus: (state) => () => { + return state.zip.status; + }, + getZipContents: (state) => () => { + return state.zip.contents; + }, + }, + actions: { + setZipStatus(status: ZipLoaderStatus) { + this.zip.status = status; + if (status === 'inactive' || status === 'preparing') { + this.zip.contents = null; + } + }, + setZipContents(contents: Blob) { + this.zip.contents = contents; + }, + } +}); diff --git a/stores/session.ts b/stores/session.ts index 876b6b0..50bcde7 100644 --- a/stores/session.ts +++ b/stores/session.ts @@ -111,14 +111,14 @@ export const useSessionStore = defineStore('session', { getSessionType: (state) => () => { return state.sessionType }, - getQuests(): EditorQuest[] { - return this.session.quests + getQuests: (state) => () => { + return state.session.quests }, - getCategories(): EditorCategory[] { - return this.session.categories + getCategories: (state) => () => { + return state.session.categories }, - getItems(): EditorItem[] { - return this.session.items + getItems: (state) => () => { + return state.session.items }, getQuestById: (state) => (id: string) => { if (!id) return null; diff --git a/utils/zipExporter.ts b/utils/zipExporter.ts new file mode 100644 index 0000000..635e89d --- /dev/null +++ b/utils/zipExporter.ts @@ -0,0 +1,33 @@ +import JSZip from "jszip"; +import { stringify } from "yaml"; +import { mapJsonCategoryToYamlObject, mapJsonItemToYamlObject, mapJsonQuestToYamlObject } from "~/lib/questsLoader"; + +//TODO include the main configuration +export async function prepareZip(quests: EditorQuest[], categories: EditorCategory[], items: EditorItem[]) { + const transformedQuests = Object.fromEntries(quests.map((quest) => [quest.id, stringify(mapJsonQuestToYamlObject(quest))])); + const transformedItems = Object.fromEntries(items.map((item) => [item.id, stringify(mapJsonItemToYamlObject(item))])); + const transformedCategories = stringify(Object.fromEntries(categories.map((category) => [category.id, mapJsonCategoryToYamlObject(category)]))); + + return { + transformedQuests, + transformedItems, + transformedCategories + } +} + +export async function createZip(quests: { [key: string]: string }, categories: string, items: { [key: string]: string }) { + const zip = new JSZip(); + + zip.file("categories.yml", categories); + + const questsDirectory = zip.folder("quests"); + Object.entries(quests).forEach(([key, value]) => { + questsDirectory?.file(`${key}.yml`, value) + }) + const itemsDirectory = zip.folder("items"); + Object.entries(items).forEach(([key, value]) => { + itemsDirectory?.file(`${key}.yml`, value) + }) + + return await zip.generateAsync({ type: "blob" }); +} \ No newline at end of file -- cgit v1.2.3-70-g09d2