aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app.vue63
-rw-r--r--components/base/Button.vue13
-rw-r--r--components/base/Checkbox.vue4
-rw-r--r--components/base/ItemStack/ItemStackForm.vue262
-rw-r--r--components/base/ItemStack/ItemStackFormOptionLabel.vue18
-rw-r--r--components/base/ItemStack/ItemStackModal.vue60
-rw-r--r--components/base/ItemStack/ItemStackPicker.vue44
-rw-r--r--components/base/Modal.vue3
-rw-r--r--components/base/Pulser.vue6
-rw-r--r--components/base/TrueFalseSwitch.vue2
-rw-r--r--components/editor/EditorOptionsPanel.vue5
-rw-r--r--components/editor/EditorSidebar.vue41
-rw-r--r--components/editor/EditorSidebarCategory.vue16
-rw-r--r--components/editor/EditorSidebarItem.vue2
-rw-r--r--components/editor/EditorSidebarMainConfiguration.vue6
-rw-r--r--components/editor/EditorSidebarQuest.vue2
-rw-r--r--components/editor/category/EditorCategoryChildrenOptionsPanel.vue3
-rw-r--r--components/editor/category/EditorCategoryOptionsPanel.vue7
-rw-r--r--components/editor/quest/EditorQuestOptionsPanel.vue108
-rw-r--r--components/editor/quest/EditorQuestTasksOptionsPanel.vue32
-rw-r--r--components/editor/quest/modal/EditorQuestModalDelete.vue14
-rw-r--r--components/editor/quest/modal/EditorQuestModalDuplicate.vue12
-rw-r--r--components/editor/quest/modal/EditorQuestModalRename.vue12
-rw-r--r--components/editor/quest/modal/EditorQuestModalYaml.vue23
-rw-r--r--components/editor/task/EditorTaskConfiguration.vue93
-rw-r--r--components/editor/task/EditorTaskConfigurationRow.vue77
-rw-r--r--components/editor/task/modal/EditorTaskModalChange.vue24
-rw-r--r--components/editor/task/modal/EditorTaskModalCreate.vue25
-rw-r--r--components/export/ExportButton.vue11
-rw-r--r--components/export/ExportModal.vue12
-rw-r--r--components/export/ExportZipButton.vue4
-rw-r--r--components/export/ExportZipModal.vue18
-rw-r--r--components/footer/SiteFooter.vue14
-rw-r--r--components/header/PageHeader.vue2
-rw-r--r--components/header/SiteHeader.vue5
-rw-r--r--components/loader/LoaderDiscardSessionModal.vue24
-rw-r--r--components/loader/LoaderFileSystemButton.vue13
-rw-r--r--components/loader/LoaderFileSystemModal.vue29
-rw-r--r--components/loader/LoaderImportButton.vue16
-rw-r--r--components/loader/LoaderNetworkButton.vue5
-rw-r--r--components/loader/LoaderTestDataButton.vue4
-rw-r--r--components/loader/LoaderTestDataModal.vue16
-rw-r--r--layouts/default.vue5
-rw-r--r--layouts/editor.vue2
-rw-r--r--lib/enchantments.ts2
-rw-r--r--lib/itemflags.ts2
-rw-r--r--lib/materials.ts2
-rw-r--r--lib/questsLoader.ts67
-rw-r--r--middleware/editor.global.ts2
-rw-r--r--nuxt.config.ts22
-rw-r--r--pages/editor/category/[id].vue6
-rw-r--r--pages/editor/config.vue6
-rw-r--r--pages/editor/index.vue6
-rw-r--r--pages/editor/item/[id].vue9
-rw-r--r--pages/editor/quest/[id].vue45
-rw-r--r--pages/import.vue19
-rw-r--r--pages/index.vue39
-rw-r--r--plugins/fontawesome.ts80
-rw-r--r--plugins/jszip.ts6
-rw-r--r--plugins/multiselect.ts6
-rw-r--r--server.prepare.ts10
-rw-r--r--stores/export.ts6
-rw-r--r--stores/loader.ts8
-rw-r--r--stores/session.ts83
-rw-r--r--utils/loader.ts91
-rw-r--r--utils/util.ts27
-rw-r--r--utils/zipExporter.ts58
67 files changed, 1110 insertions, 649 deletions
diff --git a/app.vue b/app.vue
index c4ce487..2b58bf1 100644
--- a/app.vue
+++ b/app.vue
@@ -1,38 +1,45 @@
<script setup lang="ts">
-import '~/assets/main.css'
+import '~/assets/main.css';
useHead({
- link: [{
- rel: 'preconnect',
- href: 'https://rsms.me/'
- }, {
- rel: 'stylesheet',
- href: 'https://rsms.me/inter/inter.css',
- crossorigin: ''
- }, {
- rel: 'apple-touch-icon',
- sizes: '180x180',
- href: '/apple-touch-icon.png'
- }, {
- rel: 'icon',
- type: 'image/png',
- sizes: '32x32',
- href: '/favicon-32x32.png'
- }, {
- rel: 'icon',
- type: 'image/png',
- sizes: '16x16',
- href: '/favicon-16x16.png'
- }, {
- rel: 'manifest',
- href: '/site.webmanifest'
- }]
-})
+ link: [
+ {
+ rel: 'preconnect',
+ href: 'https://rsms.me/',
+ },
+ {
+ rel: 'stylesheet',
+ href: 'https://rsms.me/inter/inter.css',
+ crossorigin: '',
+ },
+ {
+ rel: 'apple-touch-icon',
+ sizes: '180x180',
+ href: '/apple-touch-icon.png',
+ },
+ {
+ rel: 'icon',
+ type: 'image/png',
+ sizes: '32x32',
+ href: '/favicon-32x32.png',
+ },
+ {
+ rel: 'icon',
+ type: 'image/png',
+ sizes: '16x16',
+ href: '/favicon-16x16.png',
+ },
+ {
+ rel: 'manifest',
+ href: '/site.webmanifest',
+ },
+ ],
+});
useSeoMeta({
title: 'Quests Web Editor',
ogTitle: 'Quests Web Editor',
-})
+});
</script>
<template>
diff --git a/components/base/Button.vue b/components/base/Button.vue
index a53e329..663ac47 100644
--- a/components/base/Button.vue
+++ b/components/base/Button.vue
@@ -13,7 +13,7 @@ const props = defineProps({
label: String,
icon: {
type: Array<String>,
- required: false
+ required: false,
},
disabled: Boolean,
});
@@ -28,8 +28,11 @@ const onClick = (event: MouseEvent) => {
</script>
<template>
- <a id="button" :class="{ text: type === 'text', solid: type === 'solid', disabled: disabled, [accent]: true }"
- @click.stop="onClick">
+ <a
+ id="button"
+ :class="{ text: type === 'text', solid: type === 'solid', disabled: disabled, [accent]: true }"
+ @click.stop="onClick"
+ >
<font-awesome-icon :icon="icon" v-if="icon" />
{{ label }}
</a>
@@ -68,7 +71,7 @@ const onClick = (event: MouseEvent) => {
color: var(--color-false);
&:hover {
- color: var(--color-false-hover)
+ color: var(--color-false-hover);
}
}
@@ -103,4 +106,4 @@ const onClick = (event: MouseEvent) => {
background-color: var(--color-border);
}
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/base/Checkbox.vue b/components/base/Checkbox.vue
index e0325e7..b262b8e 100644
--- a/components/base/Checkbox.vue
+++ b/components/base/Checkbox.vue
@@ -6,7 +6,6 @@ defineProps({
label: String,
description: String,
});
-
</script>
<template>
@@ -38,5 +37,4 @@ input {
.checkbox {
padding: 0 0 0 20px;
}
-
-</style> \ No newline at end of file
+</style>
diff --git a/components/base/ItemStack/ItemStackForm.vue b/components/base/ItemStack/ItemStackForm.vue
index ef13abd..ddf8144 100644
--- a/components/base/ItemStack/ItemStackForm.vue
+++ b/components/base/ItemStack/ItemStackForm.vue
@@ -16,25 +16,27 @@ const yamlCode = ref('');
const switchToYamlEditor = () => {
yamlCode.value = stringify({
- type: model.value.type || model.value.material || model.value.item || "",
- ...("name" in model.value && { name: model.value.name }),
- ...("lore" in model.value && { lore: model.value.lore }),
- ...("enchantments" in model.value && { enchantments: model.value.enchantments }),
- ...("itemflags" in model.value && { itemflags: model.value.itemflags }),
- ...("custommodeldata" in model.value && { custommodeldata: model.value.custommodeldata }),
- ...("unbreakable" in model.value && { unbreakable: model.value.unbreakable }),
- ...("attributemodifiers" in model.value && { attributemodifiers: model.value.attributemodifiers }),
- ...("owner-base64" in model.value && { ["owner-base64"]: model.value["owner-base64"] }),
- ...("owner-username" in model.value && { ["owner-username"]: model.value["owner-username"] }),
- ...("owner-uuid" in model.value && { ["owner-uuid"]: model.value["owner-uuid"] })
- })
+ type: model.value.type || model.value.material || model.value.item || '',
+ ...('name' in model.value && { name: model.value.name }),
+ ...('lore' in model.value && { lore: model.value.lore }),
+ ...('enchantments' in model.value && { enchantments: model.value.enchantments }),
+ ...('itemflags' in model.value && { itemflags: model.value.itemflags }),
+ ...('custommodeldata' in model.value && { custommodeldata: model.value.custommodeldata }),
+ ...('unbreakable' in model.value && { unbreakable: model.value.unbreakable }),
+ ...('attributemodifiers' in model.value && {
+ attributemodifiers: model.value.attributemodifiers,
+ }),
+ ...('owner-base64' in model.value && { ['owner-base64']: model.value['owner-base64'] }),
+ ...('owner-username' in model.value && { ['owner-username']: model.value['owner-username'] }),
+ ...('owner-uuid' in model.value && { ['owner-uuid']: model.value['owner-uuid'] }),
+ });
editAsYaml.value = true;
-}
+};
const switchToGuiEditor = () => {
parseAndSetYamlValues();
editAsYaml.value = false;
-}
+};
const parseAndSetYamlValues = (): boolean => {
let newValues;
@@ -45,19 +47,31 @@ const parseAndSetYamlValues = (): boolean => {
}
model.value.type = newValues.type;
- if ("name" in newValues) model.value.name = String(newValues.name);
- if ("lore" in newValues) model.value.lore = Array.isArray(newValues.lore) ? newValues.lore : [newValues.lore];
- if ("enchantments" in newValues) model.value.enchantments = Array.isArray(newValues.enchantments) ? newValues.enchantments : [newValues.enchantments];
- if ("itemflags" in newValues) model.value.itemflags = Array.isArray(newValues.itemflags) ? newValues.itemflags : [newValues.itemflags];
- if ("custommodeldata" in newValues) model.value.custommodeldata = Number(newValues.custommodeldata) || 0;
- if ("unbreakable" in newValues) model.value.unbreakable = !!newValues.unbreakable;
- if ("attributemodifiers" in newValues) model.value.attributemodifiers = Array.isArray(newValues.attributemodifiers) ? newValues.attributemodifiers : [newValues.attributemodifiers];
- if ("owner-base64" in newValues) model.value["owner-base64"] = String(newValues["owner-base64"]);
- if ("owner-username" in newValues) model.value["owner-username"] = String(newValues["owner-username"]);
- if ("owner-uuid" in newValues) model.value["owner-uuid"] = String(newValues["owner-uuid"]);
+ if ('name' in newValues) model.value.name = String(newValues.name);
+ if ('lore' in newValues)
+ model.value.lore = Array.isArray(newValues.lore) ? newValues.lore : [newValues.lore];
+ if ('enchantments' in newValues)
+ model.value.enchantments = Array.isArray(newValues.enchantments)
+ ? newValues.enchantments
+ : [newValues.enchantments];
+ if ('itemflags' in newValues)
+ model.value.itemflags = Array.isArray(newValues.itemflags)
+ ? newValues.itemflags
+ : [newValues.itemflags];
+ if ('custommodeldata' in newValues)
+ model.value.custommodeldata = Number(newValues.custommodeldata) || 0;
+ if ('unbreakable' in newValues) model.value.unbreakable = !!newValues.unbreakable;
+ if ('attributemodifiers' in newValues)
+ model.value.attributemodifiers = Array.isArray(newValues.attributemodifiers)
+ ? newValues.attributemodifiers
+ : [newValues.attributemodifiers];
+ if ('owner-base64' in newValues) model.value['owner-base64'] = String(newValues['owner-base64']);
+ if ('owner-username' in newValues)
+ model.value['owner-username'] = String(newValues['owner-username']);
+ if ('owner-uuid' in newValues) model.value['owner-uuid'] = String(newValues['owner-uuid']);
return true;
-}
+};
const itemName = computed({
get() {
@@ -70,7 +84,7 @@ const itemName = computed({
const isOptionSet = (option: string) => {
return option in model.value;
-}
+};
const setOption = (option: string, type: 'string' | 'string-list' | 'number' | 'boolean') => {
switch (type) {
@@ -87,11 +101,11 @@ const setOption = (option: string, type: 'string' | 'string-list' | 'number' | '
model.value[option] = [];
break;
}
-}
+};
const removeOption = (option: string) => {
delete model.value[option];
-}
+};
const itemType = computed({
get() {
@@ -114,8 +128,8 @@ const itemLore = computed({
},
set(newValue: string) {
model.value.lore = newValue.split('\n');
- }
-})
+ },
+});
const itemEnchantments = computed({
get() {
@@ -123,8 +137,8 @@ const itemEnchantments = computed({
},
set(newValue: any) {
model.value.enchantments = newValue;
- }
-})
+ },
+});
const itemCustomModelData = computed({
get() {
@@ -132,8 +146,8 @@ const itemCustomModelData = computed({
},
set(newValue: any) {
model.value.custommodeldata = newValue;
- }
-})
+ },
+});
const itemItemflags = computed({
get() {
@@ -141,8 +155,8 @@ const itemItemflags = computed({
},
set(newValue: any) {
model.value.itemflags = newValue;
- }
-})
+ },
+});
</script>
<template>
@@ -151,69 +165,163 @@ const itemItemflags = computed({
<div class="label-with-button">
<label for="itemstack-type">Type</label>
- <Button label="Edit as YAML" :icon="['fas', 'pencil']" @click="switchToYamlEditor()"></Button>
+ <Button
+ label="Edit as YAML"
+ :icon="['fas', 'pencil']"
+ @click="switchToYamlEditor()"
+ ></Button>
</div>
- <multiselect v-model="itemType" :options="materials" :searchable="true" placeholder="Choose a material" />
+ <multiselect
+ v-model="itemType"
+ :options="materials"
+ :searchable="true"
+ placeholder="Choose a material"
+ />
</div>
<div class="option-group" v-if="isOptionSet('name')">
- <ItemStackFormOptionLabel option="name" type="string" label="Name" :is-option-set-fn="isOptionSet"
- :set-option-fn="setOption" :remove-option-fn="removeOption" />
+ <ItemStackFormOptionLabel
+ option="name"
+ type="string"
+ label="Name"
+ :is-option-set-fn="isOptionSet"
+ :set-option-fn="setOption"
+ :remove-option-fn="removeOption"
+ />
- <input id="itemstack-name" name="itemstack-name" v-model="itemName" placeholder="Enter display name" />
+ <input
+ id="itemstack-name"
+ name="itemstack-name"
+ v-model="itemName"
+ placeholder="Enter display name"
+ />
</div>
<div class="option-group" v-if="isOptionSet('lore')">
- <ItemStackFormOptionLabel option="lore" type="string-list" label="Lore" :is-option-set-fn="isOptionSet"
- :set-option-fn="setOption" :remove-option-fn="removeOption" />
+ <ItemStackFormOptionLabel
+ option="lore"
+ type="string-list"
+ label="Lore"
+ :is-option-set-fn="isOptionSet"
+ :set-option-fn="setOption"
+ :remove-option-fn="removeOption"
+ />
- <textarea rows="5" id="itemstack-lore" name="itemstack-lore" v-model="itemLore" placeholder="Enter item lore" />
+ <textarea
+ rows="5"
+ id="itemstack-lore"
+ name="itemstack-lore"
+ v-model="itemLore"
+ placeholder="Enter item lore"
+ />
</div>
<div class="option-group" v-if="isOptionSet('enchantments')">
- <ItemStackFormOptionLabel option="enchantments" type="string-list" label="Enchantments"
- :is-option-set-fn="isOptionSet" :set-option-fn="setOption" :remove-option-fn="removeOption" />
+ <ItemStackFormOptionLabel
+ option="enchantments"
+ type="string-list"
+ label="Enchantments"
+ :is-option-set-fn="isOptionSet"
+ :set-option-fn="setOption"
+ :remove-option-fn="removeOption"
+ />
- <multiselect v-model="itemEnchantments" :options="enchantments" :searchable="true" :multiple="true"
- placeholder="Enter enchantment names" />
+ <multiselect
+ v-model="itemEnchantments"
+ :options="enchantments"
+ :searchable="true"
+ :multiple="true"
+ placeholder="Enter enchantment names"
+ />
</div>
<div class="option-group" v-if="isOptionSet('itemflags')">
- <ItemStackFormOptionLabel option="itemflags" type="string-list" label="Item flags" :is-option-set-fn="isOptionSet"
- :set-option-fn="setOption" :remove-option-fn="removeOption" />
+ <ItemStackFormOptionLabel
+ option="itemflags"
+ type="string-list"
+ label="Item flags"
+ :is-option-set-fn="isOptionSet"
+ :set-option-fn="setOption"
+ :remove-option-fn="removeOption"
+ />
- <multiselect v-model="itemItemflags" :options="itemflags" :searchable="true" :multiple="true"
- placeholder="Enter item flags" />
+ <multiselect
+ v-model="itemItemflags"
+ :options="itemflags"
+ :searchable="true"
+ :multiple="true"
+ placeholder="Enter item flags"
+ />
</div>
<div class="option-group" v-if="isOptionSet('custommodeldata')">
- <ItemStackFormOptionLabel option="custommodeldata" type="number" label="Custom model data"
- :is-option-set-fn="isOptionSet" :set-option-fn="setOption" :remove-option-fn="removeOption" />
+ <ItemStackFormOptionLabel
+ option="custommodeldata"
+ type="number"
+ label="Custom model data"
+ :is-option-set-fn="isOptionSet"
+ :set-option-fn="setOption"
+ :remove-option-fn="removeOption"
+ />
- <input id="itemstack-custommodeldata" name="itemstack-custommodeldata" v-model="itemCustomModelData" type="number"
- placeholder="Enter custom model data" />
+ <input
+ id="itemstack-custommodeldata"
+ name="itemstack-custommodeldata"
+ v-model="itemCustomModelData"
+ type="number"
+ placeholder="Enter custom model data"
+ />
</div>
<div>
- <Button v-if="!isOptionSet('name')" @click="setOption('name', 'string')" label="Add specific name"
- :icon="['fas', 'plus']"></Button>
- <Button v-if="!isOptionSet('lore')" @click="setOption('lore', 'string-list')" label="Add specific lore"
- :icon="['fas', 'plus']"></Button>
- <Button v-if="!isOptionSet('enchantments')" @click="setOption('enchantments', 'string-list')"
- label="Add specific enchantments" :icon="['fas', 'plus']"></Button>
- <Button v-if="!isOptionSet('itemflags')" @click="setOption('itemflags', 'string-list')"
- label="Add specific item flags" :icon="['fas', 'plus']"></Button>
- <Button v-if="!isOptionSet('custommodeldata')" @click="setOption('custommodeldata', 'string')"
- label="Add specific custom model data" :icon="['fas', 'plus']"></Button>
+ <Button
+ v-if="!isOptionSet('name')"
+ @click="setOption('name', 'string')"
+ label="Add specific name"
+ :icon="['fas', 'plus']"
+ ></Button>
+ <Button
+ v-if="!isOptionSet('lore')"
+ @click="setOption('lore', 'string-list')"
+ label="Add specific lore"
+ :icon="['fas', 'plus']"
+ ></Button>
+ <Button
+ v-if="!isOptionSet('enchantments')"
+ @click="setOption('enchantments', 'string-list')"
+ label="Add specific enchantments"
+ :icon="['fas', 'plus']"
+ ></Button>
+ <Button
+ v-if="!isOptionSet('itemflags')"
+ @click="setOption('itemflags', 'string-list')"
+ label="Add specific item flags"
+ :icon="['fas', 'plus']"
+ ></Button>
+ <Button
+ v-if="!isOptionSet('custommodeldata')"
+ @click="setOption('custommodeldata', 'string')"
+ label="Add specific custom model data"
+ :icon="['fas', 'plus']"
+ ></Button>
</div>
- <p>For
- <NuxtLink to="https://quests.leonardobishop.com/configuration/defining-items.html#unbreakable">
- unbreakable</NuxtLink>,
- <NuxtLink to="https://quests.leonardobishop.com/configuration/defining-items.html#attribute-modifiers">
- attribute-modifiers</NuxtLink>, and
- <NuxtLink to="https://quests.leonardobishop.com/configuration/defining-items.html#owner">owner</NuxtLink> please
- switch to YAML.
+ <p>
+ For
+ <NuxtLink
+ to="https://quests.leonardobishop.com/configuration/defining-items.html#unbreakable"
+ >
+ unbreakable</NuxtLink
+ >,
+ <NuxtLink
+ to="https://quests.leonardobishop.com/configuration/defining-items.html#attribute-modifiers"
+ >
+ attribute-modifiers</NuxtLink
+ >, and
+ <NuxtLink to="https://quests.leonardobishop.com/configuration/defining-items.html#owner"
+ >owner</NuxtLink
+ >
+ please switch to YAML.
</p>
</div>
@@ -222,7 +330,11 @@ const itemItemflags = computed({
<div class="label-with-button">
<label for="itemstack-name">YAML</label>
- <Button label="Use GUI editor" :icon="['fas', 'pencil']" @click="switchToGuiEditor"></Button>
+ <Button
+ label="Use GUI editor"
+ :icon="['fas', 'pencil']"
+ @click="switchToGuiEditor"
+ ></Button>
</div>
<textarea id="yaml-editor" rows="10" v-model="yamlCode"></textarea>
@@ -245,4 +357,4 @@ const itemItemflags = computed({
#yaml-editor {
font-family: monospace;
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/base/ItemStack/ItemStackFormOptionLabel.vue b/components/base/ItemStack/ItemStackFormOptionLabel.vue
index ab067f8..e334950 100644
--- a/components/base/ItemStack/ItemStackFormOptionLabel.vue
+++ b/components/base/ItemStack/ItemStackFormOptionLabel.vue
@@ -1,20 +1,24 @@
<script setup lang="ts">
defineProps<{
- option: string
- label: string
- type: string
+ option: string;
+ label: string;
+ type: string;
isOptionSetFn: (option: string) => boolean;
removeOptionFn: (option: string) => void;
setOptionFn: (option: string, type: any) => void;
-}>()
+}>();
</script>
<template>
<div class="label-with-button">
<label :for="'itemstack-' + option">{{ label }}</label>
- <Button v-if="isOptionSetFn(option)" label="Remove" :icon="['fas', 'minus']"
- @click="removeOptionFn(option)"></Button>
+ <Button
+ v-if="isOptionSetFn(option)"
+ label="Remove"
+ :icon="['fas', 'minus']"
+ @click="removeOptionFn(option)"
+ ></Button>
</div>
</template>
@@ -23,4 +27,4 @@ defineProps<{
display: flex;
justify-content: space-between;
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/base/ItemStack/ItemStackModal.vue b/components/base/ItemStack/ItemStackModal.vue
index 2a53926..e4e39e5 100644
--- a/components/base/ItemStack/ItemStackModal.vue
+++ b/components/base/ItemStack/ItemStackModal.vue
@@ -5,7 +5,7 @@ import materials from '@/lib/materials';
const model = defineModel();
const emit = defineEmits(['confirm']);
const props = defineProps<{
- value: any
+ value: any;
}>();
const session = useSessionStore();
@@ -17,15 +17,14 @@ const isQuestItem = computed(() => {
});
const isItemStack = computed(() => {
return (
- typeof value.value === 'object'
- && (
- value.value?.item !== undefined
- || value.value?.type !== undefined
- || value.value?.material !== undefined
- ))
+ typeof value.value === 'object' &&
+ (value.value?.item !== undefined ||
+ value.value?.type !== undefined ||
+ value.value?.material !== undefined)
+ );
});
const isMaterial = computed(() => {
- return typeof value.value === 'string' && materials.includes(value.value)
+ return typeof value.value === 'string' && materials.includes(value.value);
});
const selectedType = ref(
@@ -46,13 +45,15 @@ const selectedQuestItem = computed({
return value.value?.['quest-item'];
},
set(newValue: string) {
- value.value = {}
+ value.value = {};
if (newValue) {
value.value['quest-item'] = newValue;
}
- }
-})
-const knownQuestItems = computed(() => { return session.session.items.map((item) => item.id) });
+ },
+});
+const knownQuestItems = computed(() => {
+ return session.session.items.map((item) => item.id);
+});
const setSelectedType = (type: string) => {
if (type === 'questitem') {
@@ -78,21 +79,33 @@ const confirm = () => {
<template v-slot:body>
<div id="type">
- <span class="option" @click="setSelectedType('questitem')" :class="{ selected: selectedType === 'questitem' }">
+ <span
+ class="option"
+ @click="setSelectedType('questitem')"
+ :class="{ selected: selectedType === 'questitem' }"
+ >
<span>
<font-awesome-icon :icon="['fas', 'tag']" />
Quest Item
</span>
<p v-if="noTypeSelected">Re-use a quest item.</p>
</span>
- <span class="option" @click="setSelectedType('itemstack')" :class="{ selected: selectedType === 'itemstack' }">
+ <span
+ class="option"
+ @click="setSelectedType('itemstack')"
+ :class="{ selected: selectedType === 'itemstack' }"
+ >
<span>
<font-awesome-icon :icon="['fas', 'cube']" />
ItemStack
</span>
<p v-if="noTypeSelected">Define a new item stack.</p>
</span>
- <span class="option" @click="setSelectedType('material')" :class="{ selected: selectedType === 'material' }">
+ <span
+ class="option"
+ @click="setSelectedType('material')"
+ :class="{ selected: selectedType === 'material' }"
+ >
<span>
<font-awesome-icon :icon="['fas', 'apple-whole']" />
Material
@@ -103,7 +116,12 @@ const confirm = () => {
<div id="material" class="option-group" v-if="selectedType === 'material'">
<label for="material">Material</label>
- <multiselect v-model="value" :options="materials" :searchable="true" placeholder="Enter material name" />
+ <multiselect
+ v-model="value"
+ :options="materials"
+ :searchable="true"
+ placeholder="Enter material name"
+ />
<p>Any items of this material will be matched.</p>
</div>
@@ -113,8 +131,12 @@ const confirm = () => {
<div id="quest-item" class="option-group" v-if="selectedType === 'questitem'">
<label for="quest-item">Quest Item</label>
- <multiselect v-model="selectedQuestItem" :options="knownQuestItems" :searchable="true"
- placeholder="Enter quest item" />
+ <multiselect
+ v-model="selectedQuestItem"
+ :options="knownQuestItems"
+ :searchable="true"
+ placeholder="Enter quest item"
+ />
</div>
<div id="confirm" class="control-group">
@@ -174,4 +196,4 @@ const confirm = () => {
}
}
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/base/ItemStack/ItemStackPicker.vue b/components/base/ItemStack/ItemStackPicker.vue
index 2dc35d3..09c0130 100644
--- a/components/base/ItemStack/ItemStackPicker.vue
+++ b/components/base/ItemStack/ItemStackPicker.vue
@@ -13,11 +13,13 @@ const showItemStackModal = ref(false);
//TODO unshitify
const empty = computed(() => {
- return value.value === undefined
- || value.value === null
- || value.value === ''
- || (Array.isArray(value.value) && value.value.length === 0)
- || (typeof value.value === 'object' && Object.keys(value.value).length === 0);
+ return (
+ value.value === undefined ||
+ value.value === null ||
+ value.value === '' ||
+ (Array.isArray(value.value) && value.value.length === 0) ||
+ (typeof value.value === 'object' && Object.keys(value.value).length === 0)
+ );
});
const isQuestItem = computed(() => {
return value.value?.['quest-item'] !== undefined;
@@ -27,16 +29,12 @@ const isItemStack = computed(() => {
return false;
}
- const key = 'item' in value.value
- ? 'item'
- : 'type' in value.value
- ? 'type'
- : 'material'
+ const key = 'item' in value.value ? 'item' : 'type' in value.value ? 'type' : 'material';
- return (!!value.value[key]);
+ return !!value.value[key];
});
const isMaterial = computed(() => {
- return typeof value.value === 'string' && materials.includes(value.value)
+ return typeof value.value === 'string' && materials.includes(value.value);
});
const update = (newValue: any) => {
@@ -49,13 +47,19 @@ const update = (newValue: any) => {
<template>
<div class="itemstack" @click="showItemStackModal = true">
<span v-if="empty" class="empty">ItemStack...</span>
- <span v-if="isQuestItem" class="item"><font-awesome-icon :icon="['fas', 'tag']" /> Quest Item: {{
- value['quest-item'] }}</span>
- <span v-if="isItemStack" class="item"><font-awesome-icon :icon="['fas', 'cube']" /> ItemStack: {{ value.type ||
- value.item || value.material }}</span>
- <span v-if="isMaterial" class="item"><font-awesome-icon :icon="['fas', 'apple-whole']" /> {{ value }}</span>
- <span v-if="!empty && !isQuestItem && !isItemStack && !isMaterial" class="invalid"><font-awesome-icon
- :icon="['fas', 'triangle-exclamation']" /> Invalid ItemStack</span>
+ <span v-if="isQuestItem" class="item"
+ ><font-awesome-icon :icon="['fas', 'tag']" /> Quest Item: {{ value['quest-item'] }}</span
+ >
+ <span v-if="isItemStack" class="item"
+ ><font-awesome-icon :icon="['fas', 'cube']" /> ItemStack:
+ {{ value.type || value.item || value.material }}</span
+ >
+ <span v-if="isMaterial" class="item"
+ ><font-awesome-icon :icon="['fas', 'apple-whole']" /> {{ value }}</span
+ >
+ <span v-if="!empty && !isQuestItem && !isItemStack && !isMaterial" class="invalid"
+ ><font-awesome-icon :icon="['fas', 'triangle-exclamation']" /> Invalid ItemStack</span
+ >
</div>
<ItemStackModal v-model="showItemStackModal" :value="value" @confirm="update" />
@@ -94,4 +98,4 @@ const update = (newValue: any) => {
background-color: var(--color-hover);
}
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/base/Modal.vue b/components/base/Modal.vue
index f3a32d0..0edc297 100644
--- a/components/base/Modal.vue
+++ b/components/base/Modal.vue
@@ -1,6 +1,5 @@
<script setup lang="ts">
const model = defineModel();
-
</script>
<template>
@@ -69,4 +68,4 @@ const model = defineModel();
font-weight: 600;
border-bottom: none;
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/base/Pulser.vue b/components/base/Pulser.vue
index 796b3cc..c4151fb 100644
--- a/components/base/Pulser.vue
+++ b/components/base/Pulser.vue
@@ -12,7 +12,7 @@
height: 100px;
width: 100px;
- >div {
+ > div {
animation: growAndFade 3s infinite ease-out;
background-color: var(--color-primary);
border-radius: 50%;
@@ -37,7 +37,7 @@
@keyframes growAndFade {
0% {
- opacity: .25;
+ opacity: 0.25;
transform: scale(0);
}
@@ -53,4 +53,4 @@ body {
justify-content: center;
margin: 0;
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/base/TrueFalseSwitch.vue b/components/base/TrueFalseSwitch.vue
index 152efa3..46a9d9a 100644
--- a/components/base/TrueFalseSwitch.vue
+++ b/components/base/TrueFalseSwitch.vue
@@ -50,4 +50,4 @@ const invert = () => {
background-color: var(--color-hover);
}
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/editor/EditorOptionsPanel.vue b/components/editor/EditorOptionsPanel.vue
index 7cf8982..05d1f34 100644
--- a/components/editor/EditorOptionsPanel.vue
+++ b/components/editor/EditorOptionsPanel.vue
@@ -1,5 +1,4 @@
-<script setup lang="ts">
-</script>
+<script setup lang="ts"></script>
<template>
<div id="options-panel">
@@ -16,4 +15,4 @@
padding: 1rem;
height: 100%;
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/editor/EditorSidebar.vue b/components/editor/EditorSidebar.vue
index 7ac4996..9d5818d 100644
--- a/components/editor/EditorSidebar.vue
+++ b/components/editor/EditorSidebar.vue
@@ -10,19 +10,27 @@ const currentType = ref('quests' as 'quests' | 'items');
const setSelectedType = (type: 'quests' | 'items') => {
currentType.value = type;
-}
+};
</script>
<template>
<div id="sidebar-container">
<div id="selector">
- <span class="option" @click="setSelectedType('quests')" :class="{ selected: currentType === 'quests' }">
+ <span
+ class="option"
+ @click="setSelectedType('quests')"
+ :class="{ selected: currentType === 'quests' }"
+ >
<span>
<font-awesome-icon :icon="['far', 'compass']" />
Quests
</span>
</span>
- <span class="option" @click="setSelectedType('items')" :class="{ selected: currentType === 'items' }">
+ <span
+ class="option"
+ @click="setSelectedType('items')"
+ :class="{ selected: currentType === 'items' }"
+ >
<span>
<font-awesome-icon :icon="['fas', 'cubes']" />
Items
@@ -30,13 +38,22 @@ const setSelectedType = (type: 'quests' | 'items') => {
</span>
</div>
<div id="quests" v-if="currentType === 'quests'">
- <EditorSidebarCategory v-for="category in session.categories" :key="category.id" :category="category" />
+ <EditorSidebarCategory
+ v-for="category in session.categories"
+ :key="category.id"
+ :category="category"
+ />
<EditorSidebarQuest
- v-for="quest in session.quests.filter((q) => (!session.categories.some((c) => c.id === q.options.category)))"
- :key="quest.id" :quest="quest" />
- <p id="count">{{ session.quests.length }} quest{{ session.quests.length === 1 ? '' : 's' }}, {{
- session.categories.length }}
- categor{{ session.categories.length === 1 ? 'y' : 'ies' }}</p>
+ v-for="quest in session.quests.filter(
+ (q) => !session.categories.some((c) => c.id === q.options.category)
+ )"
+ :key="quest.id"
+ :quest="quest"
+ />
+ <p id="count">
+ {{ session.quests.length }} quest{{ session.quests.length === 1 ? '' : 's' }},
+ {{ session.categories.length }} categor{{ session.categories.length === 1 ? 'y' : 'ies' }}
+ </p>
</div>
<div id="items" v-if="currentType === 'items'">
<EditorSidebarItem v-for="item in session.items" :key="item.id" :item="item" />
@@ -88,7 +105,7 @@ const setSelectedType = (type: 'quests' | 'items') => {
transition: color 0.3s;
&:hover {
- color: var(--color-text)
+ color: var(--color-text);
}
}
}
@@ -105,7 +122,7 @@ const setSelectedType = (type: 'quests' | 'items') => {
border-top: 1px solid var(--color-border);
position: absolute;
bottom: 0;
- width: 100%
+ width: 100%;
}
#count {
@@ -115,4 +132,4 @@ const setSelectedType = (type: 'quests' | 'items') => {
color: var(--color-text-mute);
}
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/editor/EditorSidebarCategory.vue b/components/editor/EditorSidebarCategory.vue
index 27a5ce0..c5adbca 100644
--- a/components/editor/EditorSidebarCategory.vue
+++ b/components/editor/EditorSidebarCategory.vue
@@ -33,8 +33,11 @@ const selected = computed(() => {
<template>
<div id="category-container" :class="{ selected: selected }">
<span id="category-title" @click="setSelectedCategory">
- <font-awesome-icon @click.stop="expandCategory" class="category-icon"
- :icon="expanded ? ['fas', 'caret-down'] : ['fas', 'caret-up']" />
+ <font-awesome-icon
+ @click.stop="expandCategory"
+ class="category-icon"
+ :icon="expanded ? ['fas', 'caret-down'] : ['fas', 'caret-up']"
+ />
<span id="category-name">
<span id="category-display-name">{{ stripColorCodes(category.display.name) }}</span>
<code id="category-display-id">{{ category.id }}</code>
@@ -42,7 +45,12 @@ const selected = computed(() => {
</span>
</div>
<div v-if="expanded" id="quests">
- <EditorSidebarQuest class="quest" v-for="quest in questsInCategory" :key="quest.id" :quest="quest" />
+ <EditorSidebarQuest
+ class="quest"
+ v-for="quest in questsInCategory"
+ :key="quest.id"
+ :quest="quest"
+ />
</div>
</template>
@@ -91,4 +99,4 @@ const selected = computed(() => {
#category-container:hover {
background-color: var(--color-hover);
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/editor/EditorSidebarItem.vue b/components/editor/EditorSidebarItem.vue
index 55f81d0..0e0040d 100644
--- a/components/editor/EditorSidebarItem.vue
+++ b/components/editor/EditorSidebarItem.vue
@@ -63,4 +63,4 @@ const selected = computed(() => {
#item-container:hover {
background-color: var(--color-hover);
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/editor/EditorSidebarMainConfiguration.vue b/components/editor/EditorSidebarMainConfiguration.vue
index 9ebef0e..9bc9239 100644
--- a/components/editor/EditorSidebarMainConfiguration.vue
+++ b/components/editor/EditorSidebarMainConfiguration.vue
@@ -16,9 +16,7 @@ const selected = computed(() => {
<div id="container" :class="{ selected: selected }">
<span id="title" @click="setSelected">
<font-awesome-icon class="icon" :icon="['fas', 'wrench']" />
- <span id="name">
- Configuration
- </span>
+ <span id="name"> Configuration </span>
</span>
</div>
</template>
@@ -53,4 +51,4 @@ const selected = computed(() => {
#container:hover {
background-color: var(--color-hover);
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/editor/EditorSidebarQuest.vue b/components/editor/EditorSidebarQuest.vue
index fb21042..54814f0 100644
--- a/components/editor/EditorSidebarQuest.vue
+++ b/components/editor/EditorSidebarQuest.vue
@@ -64,4 +64,4 @@ const selected = computed(() => {
#quest-container:hover {
background-color: var(--color-hover);
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/editor/category/EditorCategoryChildrenOptionsPanel.vue b/components/editor/category/EditorCategoryChildrenOptionsPanel.vue
index 57dcef2..f4a73ff 100644
--- a/components/editor/category/EditorCategoryChildrenOptionsPanel.vue
+++ b/components/editor/category/EditorCategoryChildrenOptionsPanel.vue
@@ -18,8 +18,7 @@ const category = computed(() => {
<div id="options">
<h2>Quests in this category</h2>
<p>Drag to reorder.</p>
- <div class="option-group">
- </div>
+ <div class="option-group"></div>
</div>
</EditorOptionsPanel>
</template>
diff --git a/components/editor/category/EditorCategoryOptionsPanel.vue b/components/editor/category/EditorCategoryOptionsPanel.vue
index 112b063..c543f73 100644
--- a/components/editor/category/EditorCategoryOptionsPanel.vue
+++ b/components/editor/category/EditorCategoryOptionsPanel.vue
@@ -17,9 +17,12 @@ const category = computed(() => {
<EditorOptionsPanel v-if="category">
<div id="options">
<div class="option-group">
- <Checkbox id="category-permissionrequired" label="Require permission for category"
+ <Checkbox
+ id="category-permissionrequired"
+ label="Require permission for category"
description="Players must have permission to open and start quests in this category."
- v-model="category.permissionRequired" />
+ v-model="category.permissionRequired"
+ />
</div>
</div>
</EditorOptionsPanel>
diff --git a/components/editor/quest/EditorQuestOptionsPanel.vue b/components/editor/quest/EditorQuestOptionsPanel.vue
index 6c1c8b1..bc5f7ef 100644
--- a/components/editor/quest/EditorQuestOptionsPanel.vue
+++ b/components/editor/quest/EditorQuestOptionsPanel.vue
@@ -17,7 +17,6 @@ const knownCategories = computed(() => {
const knownQuests = computed(() => {
return sessionStore.session.quests.map((quest) => quest.id);
});
-
</script>
<template>
@@ -25,87 +24,126 @@ const knownQuests = computed(() => {
<div id="options">
<div class="option-group">
<label for="quest-category">Category</label>
- <multiselect id="quest-category" v-model="quest.options.category" :options="knownCategories" :searchable="true"
- placeholder="No category"></multiselect>
+ <multiselect
+ id="quest-category"
+ v-model="quest.options.category"
+ :options="knownCategories"
+ :searchable="true"
+ placeholder="No category"
+ ></multiselect>
</div>
<div class="option-group">
<label for="quest-requirements">Requirements</label>
- <multiselect id="quest-requirements" v-model="quest.options.requirements" :options="knownQuests"
- :searchable="true" :taggable="true" :multiple="true" placeholder="Add requirement"></multiselect>
+ <multiselect
+ id="quest-requirements"
+ v-model="quest.options.requirements"
+ :options="knownQuests"
+ :searchable="true"
+ :taggable="true"
+ :multiple="true"
+ placeholder="Add requirement"
+ ></multiselect>
<p class="description">
- This quest will only be available if the player has completed all of the quests listed above.
+ This quest will only be available if the player has completed all of the quests listed
+ above.
</p>
</div>
<h2>Quest options</h2>
<div class="option-group">
- <Checkbox id="quest-permissionrequired" label="Require permission to start quest"
- description="Players must have permission to start the quest." v-model="quest.options.permissionRequired" />
+ <Checkbox
+ id="quest-permissionrequired"
+ label="Require permission to start quest"
+ description="Players must have permission to start the quest."
+ v-model="quest.options.permissionRequired"
+ />
</div>
<div class="option-group">
- <Checkbox id="quest-cancellable" label="Allow players to cancel quest"
- description="Players can cancel the quest after they have started it." v-model="quest.options.cancellable" />
+ <Checkbox
+ id="quest-cancellable"
+ label="Allow players to cancel quest"
+ description="Players can cancel the quest after they have started it."
+ v-model="quest.options.cancellable"
+ />
</div>
<div class="option-group">
- <Checkbox id="quest-countstowardslimit" label="Count towards quest limit"
+ <Checkbox
+ id="quest-countstowardslimit"
+ label="Count towards quest limit"
description="Quest will count towards the player's quest started limit."
- v-model="quest.options.countsTowardsLimit" />
+ v-model="quest.options.countsTowardsLimit"
+ />
</div>
<div class="option-group">
- <Checkbox id="quest-repeatable" label="Allow players to repeat quest"
+ <Checkbox
+ id="quest-repeatable"
+ label="Allow players to repeat quest"
description="Quest can be completed again after it has been completed once."
- v-model="quest.options.repeatable" />
+ v-model="quest.options.repeatable"
+ />
</div>
<div class="option-group">
- <Checkbox id="quest-autostart" label="Automatically start quest"
+ <Checkbox
+ id="quest-autostart"
+ label="Automatically start quest"
description="Quest will start automatically when the player has unlocked it."
- v-model="quest.options.autostart" />
+ v-model="quest.options.autostart"
+ />
</div>
-
<h2>Cooldown</h2>
<div class="option-group">
- <Checkbox id="quest-cooldown" label="Enable cooldown"
+ <Checkbox
+ id="quest-cooldown"
+ label="Enable cooldown"
description="Players will have to wait a certain amount of time before they can start the quest again."
- v-model="quest.options.cooldown.enabled" />
+ v-model="quest.options.cooldown.enabled"
+ />
</div>
<div class="option-group">
- <label for="quest-cooldown-time">
- Cooldown (in seconds)
- </label>
- <input id="quest-cooldown-time" type="number" v-model="quest.options.cooldown.time"
- :disabled="!quest.options.cooldown.enabled" />
+ <label for="quest-cooldown-time"> Cooldown (in seconds) </label>
+ <input
+ id="quest-cooldown-time"
+ type="number"
+ v-model="quest.options.cooldown.time"
+ :disabled="!quest.options.cooldown.enabled"
+ />
<p class="description">
- Common values are: <code>3600</code> (1 hour), <code>86400</code> (24 hours), <code>604800</code> (7 days),
- <code>2592000</code> (30 days)
+ Common values are: <code>3600</code> (1 hour), <code>86400</code> (24 hours),
+ <code>604800</code> (7 days), <code>2592000</code> (30 days)
</p>
</div>
<h2>Time limit</h2>
<div class="option-group">
- <Checkbox id="quest-timelimit" label="Enable time limit"
+ <Checkbox
+ id="quest-timelimit"
+ label="Enable time limit"
description="Players will be required to complete the quest within a certain amount of time, otherwise it will be automatically cancelled."
- v-model="quest.options.timeLimit.enabled" />
+ v-model="quest.options.timeLimit.enabled"
+ />
</div>
<div class="option-group">
- <label for="quest-timelimit-time">
- Time limit (in seconds)
- </label>
- <input id="quest-timelimit-time" type="number" v-model="quest.options.timeLimit.time"
- :disabled="!quest.options.timeLimit.enabled" />
+ <label for="quest-timelimit-time"> Time limit (in seconds) </label>
+ <input
+ id="quest-timelimit-time"
+ type="number"
+ v-model="quest.options.timeLimit.time"
+ :disabled="!quest.options.timeLimit.enabled"
+ />
<p class="description">
- Common values are: <code>3600</code> (1 hour), <code>86400</code> (24 hours), <code>604800</code> (7 days),
- <code>2592000</code> (30 days)
+ Common values are: <code>3600</code> (1 hour), <code>86400</code> (24 hours),
+ <code>604800</code> (7 days), <code>2592000</code> (30 days)
</p>
</div>
</div>
diff --git a/components/editor/quest/EditorQuestTasksOptionsPanel.vue b/components/editor/quest/EditorQuestTasksOptionsPanel.vue
index cb4b109..a9e3ac3 100644
--- a/components/editor/quest/EditorQuestTasksOptionsPanel.vue
+++ b/components/editor/quest/EditorQuestTasksOptionsPanel.vue
@@ -29,22 +29,40 @@ const addTask = (newId: string, newType: string) => {
<template>
<EditorOptionsPanel v-if="quest">
<div id="options">
- <h2>Tasks <code>({{ Object.keys(quest.tasks).length }})</code></h2>
+ <h2>
+ Tasks <code>({{ Object.keys(quest.tasks).length }})</code>
+ </h2>
- <p v-if="Object.keys(quest.tasks).length === 0" class="error-text">This quest does not have any tasks.</p>
- <EditorTaskConfiguration v-for="(task, taskId) in quest.tasks" :key="taskId" :taskId="String(taskId)"
- :quest="quest" />
+ <p v-if="Object.keys(quest.tasks).length === 0" class="error-text">
+ This quest does not have any tasks.
+ </p>
+ <EditorTaskConfiguration
+ v-for="(task, taskId) in quest.tasks"
+ :key="taskId"
+ :taskId="String(taskId)"
+ :quest="quest"
+ />
<div id="controls">
- <Button id="add-task" :icon="['fas', 'plus']" type="solid" label="Add task" @click="showAddTaskModal = true" />
+ <Button
+ id="add-task"
+ :icon="['fas', 'plus']"
+ type="solid"
+ label="Add task"
+ @click="showAddTaskModal = true"
+ />
</div>
</div>
</EditorOptionsPanel>
- <EditorTaskModalCreate v-if="quest" v-model="showAddTaskModal" :questId="questId" @add="addTask" />
+ <EditorTaskModalCreate
+ v-if="quest"
+ v-model="showAddTaskModal"
+ :questId="questId"
+ @add="addTask"
+ />
</template>
-
<style scoped>
#options {
display: flex;
diff --git a/components/editor/quest/modal/EditorQuestModalDelete.vue b/components/editor/quest/modal/EditorQuestModalDelete.vue
index e81bcc7..c4e1682 100644
--- a/components/editor/quest/modal/EditorQuestModalDelete.vue
+++ b/components/editor/quest/modal/EditorQuestModalDelete.vue
@@ -13,10 +13,18 @@ defineProps({
<template v-slot:header>
<h2>Really delete quest '{{ questId }}'?</h2>
</template>
- <p>Are you sure you want to delete this quest? The quests editor does not have undo functionality (yet)! </p>
+ <p>
+ Are you sure you want to delete this quest? The quests editor does not have undo functionality
+ (yet)!
+ </p>
<div id="confirm" class="control-group">
<Button :icon="['fas', 'times']" :label="'Cancel'" @click="model = false"></Button>
- <Button type="solid" :icon="['fas', 'trash']" :label="'Delete'" @click="emit('delete')"></Button>
+ <Button
+ type="solid"
+ :icon="['fas', 'trash']"
+ :label="'Delete'"
+ @click="emit('delete')"
+ ></Button>
</div>
</Modal>
</template>
@@ -27,4 +35,4 @@ defineProps({
justify-content: flex-end;
margin-top: 1rem;
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/editor/quest/modal/EditorQuestModalDuplicate.vue b/components/editor/quest/modal/EditorQuestModalDuplicate.vue
index 73a2fd0..6c333fb 100644
--- a/components/editor/quest/modal/EditorQuestModalDuplicate.vue
+++ b/components/editor/quest/modal/EditorQuestModalDuplicate.vue
@@ -17,7 +17,6 @@ const newQuestId = ref(props.questId);
const isDuplicate = computed(() => {
return session.getQuestById(newQuestId.value!) !== undefined;
});
-
</script>
<template>
@@ -36,8 +35,13 @@ const isDuplicate = computed(() => {
<p>A Quest ID must be unique, alphanumeric, and not contain any spaces.</p>
<div id="confirm" class="control-group">
<Button :icon="['fas', 'times']" :label="'Cancel'" @click="model = false"></Button>
- <Button type="solid" :icon="['fas', 'check']" :label="'Duplicate'" :disabled="isDuplicate"
- @click="emit('duplicate', newQuestId)"></Button>
+ <Button
+ type="solid"
+ :icon="['fas', 'check']"
+ :label="'Duplicate'"
+ :disabled="isDuplicate"
+ @click="emit('duplicate', newQuestId)"
+ ></Button>
</div>
</div>
</template>
@@ -55,4 +59,4 @@ const isDuplicate = computed(() => {
flex-direction: column;
gap: 0.5rem;
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/editor/quest/modal/EditorQuestModalRename.vue b/components/editor/quest/modal/EditorQuestModalRename.vue
index 3d846aa..13c4810 100644
--- a/components/editor/quest/modal/EditorQuestModalRename.vue
+++ b/components/editor/quest/modal/EditorQuestModalRename.vue
@@ -17,7 +17,6 @@ const newQuestId = ref(props.questId);
const isDuplicate = computed(() => {
return session.getQuestById(newQuestId.value!) !== undefined;
});
-
</script>
<template>
@@ -36,8 +35,13 @@ const isDuplicate = computed(() => {
<p>A Quest ID must be unique, alphanumeric, and not contain any spaces.</p>
<div id="confirm" class="control-group">
<Button :icon="['fas', 'times']" :label="'Cancel'" @click="model = false"></Button>
- <Button type="solid" :icon="['fas', 'check']" :label="'Rename'" :disabled="isDuplicate"
- @click="emit('update', newQuestId)"></Button>
+ <Button
+ type="solid"
+ :icon="['fas', 'check']"
+ :label="'Rename'"
+ :disabled="isDuplicate"
+ @click="emit('update', newQuestId)"
+ ></Button>
</div>
</div>
</template>
@@ -55,4 +59,4 @@ const isDuplicate = computed(() => {
flex-direction: column;
gap: 0.5rem;
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/editor/quest/modal/EditorQuestModalYaml.vue b/components/editor/quest/modal/EditorQuestModalYaml.vue
index 365055c..c7c4936 100644
--- a/components/editor/quest/modal/EditorQuestModalYaml.vue
+++ b/components/editor/quest/modal/EditorQuestModalYaml.vue
@@ -6,7 +6,7 @@ const emit = defineEmits(['delete']);
const props = defineProps({
questId: {
required: true,
- type: String
+ type: String,
},
});
@@ -18,16 +18,16 @@ const yamlString = ref('');
const open = () => {
const quest = session.getQuestById(props.questId);
if (!quest) {
- return
+ return;
}
const mappedObject = mapJsonQuestToYamlObject(quest);
yamlString.value = stringify(mappedObject);
showModal.value = true;
-}
+};
defineExpose({
- open
-})
+ open,
+});
</script>
<template>
@@ -36,12 +36,19 @@ defineExpose({
<h2>YAML</h2>
</template>
- <p>YAML file for <code>{{ props.questId }}</code></p>
+ <p>
+ YAML file for <code>{{ props.questId }}</code>
+ </p>
<textarea rows="20" :value="yamlString" readonly />
<div id="confirm" class="control-group">
- <Button type="solid" :icon="['fas', 'check']" :label="'Close'" @click="showModal = false"></Button>
+ <Button
+ type="solid"
+ :icon="['fas', 'check']"
+ :label="'Close'"
+ @click="showModal = false"
+ ></Button>
</div>
</Modal>
</template>
@@ -56,4 +63,4 @@ defineExpose({
textarea {
width: 100%;
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/editor/task/EditorTaskConfiguration.vue b/components/editor/task/EditorTaskConfiguration.vue
index 5313767..dab5888 100644
--- a/components/editor/task/EditorTaskConfiguration.vue
+++ b/components/editor/task/EditorTaskConfiguration.vue
@@ -13,14 +13,21 @@ const taskType = computed(() => props.quest.tasks[props.taskId].config.type);
const taskDefintion = computed(() => sessionStore.getTaskDefinitionByTaskType(taskType.value));
const taskConfig = computed(() => {
- return Object.keys(props.quest.tasks[props.taskId].config).filter((fieldName) => fieldName !== 'type').reduce((acc, fieldName) => {
- acc[fieldName] = props.quest.tasks[props.taskId].config[fieldName];
- return acc;
- }, {} as { [key: string]: any });
+ return Object.keys(props.quest.tasks[props.taskId].config)
+ .filter((fieldName) => fieldName !== 'type')
+ .reduce(
+ (acc, fieldName) => {
+ acc[fieldName] = props.quest.tasks[props.taskId].config[fieldName];
+ return acc;
+ },
+ {} as { [key: string]: any }
+ );
});
const requiredFields = computed(() => {
- return Object.keys(taskDefintion.value.configuration).filter((fieldName) => taskDefintion.value.configuration[fieldName].required);
+ return Object.keys(taskDefintion.value.configuration).filter(
+ (fieldName) => taskDefintion.value.configuration[fieldName].required
+ );
});
// const givenRequiredFields = computed(() => {
@@ -32,13 +39,20 @@ const requiredFields = computed(() => {
// });
const remainingGivenFields = computed(() => {
- return Object.keys(taskConfig.value).filter((fieldName) => !requiredFields.value.includes(fieldName) && fieldName in taskDefintion.value.configuration);
+ return Object.keys(taskConfig.value).filter(
+ (fieldName) =>
+ !requiredFields.value.includes(fieldName) && fieldName in taskDefintion.value.configuration
+ );
});
-const configKeysOptions = computed(() => Object.keys(taskDefintion.value.configuration).filter((key) => !Object.keys(taskConfig.value).some((fieldName) => fieldName === key)));
+const configKeysOptions = computed(() =>
+ Object.keys(taskDefintion.value.configuration).filter(
+ (key) => !Object.keys(taskConfig.value).some((fieldName) => fieldName === key)
+ )
+);
// const configKeysOptions = computed(() => {
// const keys = Object.keys(taskDefintion.value.configuration).filter((key) => !Object.keys(taskConfig.value).some((fieldName) => fieldName === key));
-//
+//
// return keys.map((key) => {
// return {
// value: key,
@@ -49,7 +63,8 @@ const configKeysOptions = computed(() => Object.keys(taskDefintion.value.configu
// });
const onAddOption = (option: any) => {
- sessionStore.getQuestById(props.quest.id)!.tasks[props.taskId].config[option] = taskDefintion.value.configuration[option].default || null;
+ sessionStore.getQuestById(props.quest.id)!.tasks[props.taskId].config[option] =
+ taskDefintion.value.configuration[option].default || null;
};
const updateValue = (fieldName: string, value: any) => {
@@ -64,14 +79,14 @@ const showChangeModal = ref(false);
const updateTaskType = (newType: string) => {
sessionStore.getQuestById(props.quest.id)!.tasks[props.taskId].config = {
- type: newType
+ type: newType,
};
showChangeModal.value = false;
-}
+};
const deleteTaskType = (taskId: string) => {
delete sessionStore.getQuestById(props.quest.id)!.tasks[taskId];
-}
+};
</script>
<template>
@@ -82,43 +97,68 @@ const deleteTaskType = (taskId: string) => {
{{ props.taskId }}
</span>
<code>
- (<font-awesome-icon v-if="taskDefintion" id="task-icon" :icon="[taskDefintion.icon.style, taskDefintion.icon.name]" />{{ taskType }})
+ (<font-awesome-icon
+ v-if="taskDefintion"
+ id="task-icon"
+ :icon="[taskDefintion.icon.style, taskDefintion.icon.name]"
+ />{{ taskType }})
</code>
</p>
<div id="task-controls" class="control-group">
<Button :icon="['fas', 'pen']" :label="'Change'" @click="showChangeModal = true"></Button>
- <Button :icon="['fas', 'trash']" :label="'Delete'" @click="deleteTaskType(props.taskId)"></Button>
+ <Button
+ :icon="['fas', 'trash']"
+ :label="'Delete'"
+ @click="deleteTaskType(props.taskId)"
+ ></Button>
</div>
</div>
<div id="task-configuration">
<div v-if="!taskDefintion" class="error">
<font-awesome-icon id="error-icon" :icon="['fas', 'triangle-exclamation']" />
<p id="error-message">
- Unable to edit task <code>{{ props.taskId }}</code>.
+ Unable to edit task <code>{{ props.taskId }}</code
+ >.
</p>
<p id="error-description">
- The quests web editor does not know how to configure task
- type <code>{{ taskType }}</code> as it has no task definition.
+ The quests web editor does not know how to configure task type
+ <code>{{ taskType }}</code> as it has no task definition.
</p>
</div>
<div v-if="taskDefintion">
- <EditorTaskConfigurationRow v-for="fieldName in [...requiredFields, ...remainingGivenFields]"
- :key="`${quest.id}-${props.taskId}-${taskType}-${fieldName}`" :required="requiredFields.includes(fieldName)"
- :configKey="fieldName" :initialValue="taskConfig[fieldName]" :taskType="taskType"
- :type="(taskDefintion.configuration[fieldName].type as string)"
- @update="(newValue: any) => updateValue(fieldName, newValue)" @delete="() => deleteValue(fieldName)" />
+ <EditorTaskConfigurationRow
+ v-for="fieldName in [...requiredFields, ...remainingGivenFields]"
+ :key="`${quest.id}-${props.taskId}-${taskType}-${fieldName}`"
+ :required="requiredFields.includes(fieldName)"
+ :configKey="fieldName"
+ :initialValue="taskConfig[fieldName]"
+ :taskType="taskType"
+ :type="taskDefintion.configuration[fieldName].type as string"
+ @update="(newValue: any) => updateValue(fieldName, newValue)"
+ @delete="() => deleteValue(fieldName)"
+ />
<div id="add-option">
- <multiselect class="configuration-multiselect" :options="configKeysOptions" :searchable="true"
- @select="onAddOption" placeholder="Add option...">
+ <multiselect
+ class="configuration-multiselect"
+ :options="configKeysOptions"
+ :searchable="true"
+ @select="onAddOption"
+ placeholder="Add option..."
+ >
</multiselect>
</div>
</div>
</div>
</div>
- <EditorTaskModalChange v-model="showChangeModal" :taskId="props.taskId" :currentTaskType="taskType"
- :key="`change-task-${props.taskId}`" @update="updateTaskType" />
+ <EditorTaskModalChange
+ v-model="showChangeModal"
+ :taskId="props.taskId"
+ :currentTaskType="taskType"
+ :key="`change-task-${props.taskId}`"
+ @update="updateTaskType"
+ />
</template>
<style scoped>
@@ -133,7 +173,6 @@ const deleteTaskType = (taskId: string) => {
#error-message {
font-weight: 700;
}
-
}
#task-configuration-table {
diff --git a/components/editor/task/EditorTaskConfigurationRow.vue b/components/editor/task/EditorTaskConfigurationRow.vue
index c00896f..f400292 100644
--- a/components/editor/task/EditorTaskConfigurationRow.vue
+++ b/components/editor/task/EditorTaskConfigurationRow.vue
@@ -21,27 +21,37 @@ const emit = defineEmits(['update', 'delete']);
const sessionStore = useSessionStore();
const definition = computed(() => {
- const def = sessionStore.getTaskDefinitionByTaskType(props.taskType).configuration[props.configKey];
+ const def = sessionStore.getTaskDefinitionByTaskType(props.taskType).configuration[
+ props.configKey
+ ];
return { description: def.description, note: def.note };
});
const { description, note } = toRefs(definition.value);
const showDescription = ref(false);
-const currentValue = ref(props.initialValue ||
- (props.type === 'boolean'
- ? false
- : (props.type === 'material-list' || props.type === 'string-list'
- ? []
- : props.type === 'itemstack'
- ? null
- : ''
- )));
+const currentValue = ref(
+ props.initialValue ||
+ (props.type === 'boolean'
+ ? false
+ : props.type === 'material-list' || props.type === 'string-list'
+ ? []
+ : props.type === 'itemstack'
+ ? null
+ : '')
+);
if (props.initialValue !== currentValue.value) {
emit('update', currentValue.value);
}
-const error = computed(() => currentValue.value === undefined || currentValue.value === null || currentValue.value === '' || (Array.isArray(currentValue.value) && currentValue.value.length === 0) || (typeof currentValue.value === 'object' && Object.keys(currentValue.value).length === 0));
+const error = computed(
+ () =>
+ currentValue.value === undefined ||
+ currentValue.value === null ||
+ currentValue.value === '' ||
+ (Array.isArray(currentValue.value) && currentValue.value.length === 0) ||
+ (typeof currentValue.value === 'object' && Object.keys(currentValue.value).length === 0)
+);
const updateValue = (value: any) => {
currentValue.value = value;
};
@@ -53,7 +63,6 @@ watch(currentValue, () => {
const addValue = (searchQuery: any) => {
currentValue.value.push(searchQuery);
};
-
</script>
<template>
@@ -73,23 +82,49 @@ const addValue = (searchQuery: any) => {
<input v-else-if="props.type === 'number'" type="number" v-model="currentValue" />
<!-- Data type 'boolean' -->
- <TrueFalseSwitch v-else-if="props.type === 'boolean'" :value="!!currentValue" @update="updateValue" />
+ <TrueFalseSwitch
+ v-else-if="props.type === 'boolean'"
+ :value="!!currentValue"
+ @update="updateValue"
+ />
<!-- Data type 'material-list' -->
- <multiselect v-else-if="props.type === 'material-list'" v-model="currentValue" class="configuration-multiselect"
- :options="materials" :multiple="true" :taggable="true" :searchable="true" placeholder="Enter material name" />
+ <multiselect
+ v-else-if="props.type === 'material-list'"
+ v-model="currentValue"
+ class="configuration-multiselect"
+ :options="materials"
+ :multiple="true"
+ :taggable="true"
+ :searchable="true"
+ placeholder="Enter material name"
+ />
<!-- Data type 'string-list' -->
- <multiselect v-else-if="props.type === 'string-list'" v-model="currentValue" class="configuration-multiselect"
- :options="[]" @tag="addValue" :multiple="true" :taggable="true" :searchable="true"
- placeholder="Enter string" />
+ <multiselect
+ v-else-if="props.type === 'string-list'"
+ v-model="currentValue"
+ class="configuration-multiselect"
+ :options="[]"
+ @tag="addValue"
+ :multiple="true"
+ :taggable="true"
+ :searchable="true"
+ placeholder="Enter string"
+ />
<!-- Data type 'itemstack' -->
- <ItemStackPicker v-else-if="props.type === 'itemstack'" :value="currentValue" @update="updateValue" />
+ <ItemStackPicker
+ v-else-if="props.type === 'itemstack'"
+ :value="currentValue"
+ @update="updateValue"
+ />
<div v-if="showDescription || error" id="task-configuration-row-info">
<p v-if="error" class="error">A value is required.</p>
- <p>{{ description }} <i>{{ note }}</i></p>
+ <p>
+ {{ description }} <i>{{ note }}</i>
+ </p>
</div>
</div>
</div>
@@ -182,4 +217,4 @@ input {
.error {
color: var(--color-false);
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/editor/task/modal/EditorTaskModalChange.vue b/components/editor/task/modal/EditorTaskModalChange.vue
index 8ab5dbc..a6b05b8 100644
--- a/components/editor/task/modal/EditorTaskModalChange.vue
+++ b/components/editor/task/modal/EditorTaskModalChange.vue
@@ -18,7 +18,9 @@ const knownTaskTypes = computed(() => session.getKnownTaskTypes());
const newType = ref('');
const unknownTaskType = computed(() => !knownTaskTypes.value.includes(newType.value));
const noChange = computed(() => newType.value === props.currentTaskType);
-const newTypeDescription = computed(() => session.getTaskDefinitionByTaskType(newType.value)?.description);
+const newTypeDescription = computed(
+ () => session.getTaskDefinitionByTaskType(newType.value)?.description
+);
</script>
<template>
@@ -31,16 +33,26 @@ const newTypeDescription = computed(() => session.getTaskDefinitionByTaskType(ne
<div id="body">
<div class="option-group">
<label for="new-type">New type</label>
- <multiselect id="new-type" v-model="newType" :options="knownTaskTypes" :searchable="true"
- placeholder="Select a new type"></multiselect>
+ <multiselect
+ id="new-type"
+ v-model="newType"
+ :options="knownTaskTypes"
+ :searchable="true"
+ placeholder="Select a new type"
+ ></multiselect>
</div>
<p v-if="unknownTaskType" class="error-text">Invalid task type.</p>
<p v-if="newTypeDescription">{{ newTypeDescription }}</p>
<p>Any configured options for this task will be overwritten.</p>
<div id="confirm" class="control-group">
<Button :icon="['fas', 'times']" :label="'Cancel'" @click="model = false"></Button>
- <Button type="solid" :icon="['fas', 'check']" :label="'Change'" :disabled="unknownTaskType || noChange"
- @click="emit('update', newType)"></Button>
+ <Button
+ type="solid"
+ :icon="['fas', 'check']"
+ :label="'Change'"
+ :disabled="unknownTaskType || noChange"
+ @click="emit('update', newType)"
+ ></Button>
</div>
</div>
</template>
@@ -58,4 +70,4 @@ const newTypeDescription = computed(() => session.getTaskDefinitionByTaskType(ne
flex-direction: column;
gap: 0.5rem;
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/editor/task/modal/EditorTaskModalCreate.vue b/components/editor/task/modal/EditorTaskModalCreate.vue
index e5b2d7a..cdd955f 100644
--- a/components/editor/task/modal/EditorTaskModalCreate.vue
+++ b/components/editor/task/modal/EditorTaskModalCreate.vue
@@ -24,7 +24,9 @@ const unknownTaskType = computed(() => !knownTaskTypes.value.includes(newType.va
const invalidTaskId = computed(() => !validateTaskId(newId.value));
const duplicateTaskId = computed(() => knownTasks.value[newId.value] !== undefined);
-const newTypeDescription = computed(() => session.getTaskDefinitionByTaskType(newType.value)?.description);
+const newTypeDescription = computed(
+ () => session.getTaskDefinitionByTaskType(newType.value)?.description
+);
</script>
<template>
@@ -43,19 +45,26 @@ const newTypeDescription = computed(() => session.getTaskDefinitionByTaskType(ne
</div>
<div class="option-group">
<label for="new-type">Task type</label>
- <multiselect id="new-type" v-model="newType" :options="knownTaskTypes" :searchable="true"
- placeholder="Select a new type"></multiselect>
+ <multiselect
+ id="new-type"
+ v-model="newType"
+ :options="knownTaskTypes"
+ :searchable="true"
+ placeholder="Select a new type"
+ ></multiselect>
<p v-if="unknownTaskType" class="error-text">Invalid task type.</p>
</div>
<p v-if="newTypeDescription">{{ newTypeDescription }}</p>
<p>A task ID must be unique, alphanumeric, and not contain any spaces.</p>
<div id="confirm" class="control-group">
<Button :icon="['fas', 'times']" :label="'Cancel'" @click="model = false"></Button>
- <Button type="solid" :icon="['fas', 'check']" :label="'Confirm'"
+ <Button
+ type="solid"
+ :icon="['fas', 'check']"
+ :label="'Confirm'"
:disabled="unknownTaskType || invalidTaskId || duplicateTaskId"
- @click="emit('add', newId, newType)"></Button>
-
-
+ @click="emit('add', newId, newType)"
+ ></Button>
</div>
</div>
</template>
@@ -73,4 +82,4 @@ const newTypeDescription = computed(() => session.getTaskDefinitionByTaskType(ne
flex-direction: column;
gap: 0.5rem;
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/export/ExportButton.vue b/components/export/ExportButton.vue
index 51c4b0a..a3274c1 100644
--- a/components/export/ExportButton.vue
+++ b/components/export/ExportButton.vue
@@ -5,11 +5,16 @@ const exportModal = ref<InstanceType<typeof ExportModal> | null>(null);
const openExportModal = async () => {
exportModal.value?.open();
-}
+};
</script>
<template>
- <Button type="solid" :icon="['fas', 'file-export']" label="Save / Export" @click="openExportModal" />
+ <Button
+ type="solid"
+ :icon="['fas', 'file-export']"
+ label="Save / Export"
+ @click="openExportModal"
+ />
<ExportModal ref="exportModal" />
-</template> \ No newline at end of file
+</template>
diff --git a/components/export/ExportModal.vue b/components/export/ExportModal.vue
index 1d09914..7adb603 100644
--- a/components/export/ExportModal.vue
+++ b/components/export/ExportModal.vue
@@ -5,14 +5,14 @@ const showModal = ref(false);
const open = () => {
showModal.value = true;
-}
+};
const { canUseFsApi } = getBrowserCapabilities();
const isUsingFsMode = computed(() => session.getSessionType() === 'filesystem');
defineExpose({
- open
-})
+ open,
+});
</script>
<template>
@@ -58,7 +58,9 @@ defineExpose({
<div id="description">
<p id="subtitle">Send to Server</p>
- <p>Upload your quest configuration to the server, which can be downloaded and automatically applied in-game.
+ <p>
+ Upload your quest configuration to the server, which can be downloaded and
+ automatically applied in-game.
</p>
<p class="error">
<font-awesome-icon :icon="['fas', 'xmark']" />
@@ -178,4 +180,4 @@ hr {
justify-content: flex-end;
margin-top: 1rem;
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/export/ExportZipButton.vue b/components/export/ExportZipButton.vue
index 8fb6f60..65ab083 100644
--- a/components/export/ExportZipButton.vue
+++ b/components/export/ExportZipButton.vue
@@ -6,7 +6,7 @@ const exportZipModal = ref<InstanceType<typeof ExportZipModal> | null>(null);
const startZipExport = async () => {
exportZipModal.value?.open();
exportZipModal.value?.startExport();
-}
+};
</script>
<template>
@@ -15,4 +15,4 @@ const startZipExport = async () => {
<ExportZipModal ref="exportZipModal" />
</ClientOnly>
-</template> \ No newline at end of file
+</template>
diff --git a/components/export/ExportZipModal.vue b/components/export/ExportZipModal.vue
index b84690d..d7d7ab2 100644
--- a/components/export/ExportZipModal.vue
+++ b/components/export/ExportZipModal.vue
@@ -15,7 +15,11 @@ const startExport = async () => {
exportStore.setZipStatus('preparing');
- const { transformedQuests, transformedCategories, transformedItems } = await prepareZip(quests, categories, items);
+ const { transformedQuests, transformedCategories, transformedItems } = await prepareZip(
+ quests,
+ categories,
+ items
+ );
exportStore.setZipStatus('compressing');
@@ -25,20 +29,20 @@ const startExport = async () => {
exportStore.setZipContents(blob);
exportStore.setZipStatus('ready');
- saveAs(blob, "quests.zip");
+ saveAs(blob, 'quests.zip');
} catch {
exportStore.setZipStatus('failed');
}
-}
+};
const open = () => {
showModal.value = true;
-}
+};
defineExpose({
open,
- startExport
-})
+ startExport,
+});
</script>
<template>
@@ -64,4 +68,4 @@ defineExpose({
justify-content: flex-end;
margin-top: 1rem;
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/footer/SiteFooter.vue b/components/footer/SiteFooter.vue
index 2f31e4f..632131f 100644
--- a/components/footer/SiteFooter.vue
+++ b/components/footer/SiteFooter.vue
@@ -5,19 +5,17 @@ const runtimeConfig = useRuntimeConfig();
<template>
<footer id="footer">
- <p id="copyright-license">
- Released under the GPL-3.0 License.
- </p>
+ <p id="copyright-license">Released under the GPL-3.0 License.</p>
<p id="git-commit-hash">
<font-awesome-icon :icon="['fas', 'code-branch']" />
<NuxtLink to="https://github.com/LMBishop/quests-web-editor/">quests-web-editor</NuxtLink>
<span>@</span>
- <NuxtLink :to="`https://github.com/LMBishop/quests-web-editor/commit/${runtimeConfig.public.gitCommitHash}`">
+ <NuxtLink
+ :to="`https://github.com/LMBishop/quests-web-editor/commit/${runtimeConfig.public.gitCommitHash}`"
+ >
{{ runtimeConfig.public.gitCommitHashShort }}
</NuxtLink>
- <span>
- ({{ runtimeConfig.public.gitBranch }})
- </span>
+ <span> ({{ runtimeConfig.public.gitBranch }}) </span>
</p>
</footer>
</template>
@@ -49,4 +47,4 @@ const runtimeConfig = useRuntimeConfig();
text-decoration: none;
}
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/header/PageHeader.vue b/components/header/PageHeader.vue
index 3c616ca..7e024c6 100644
--- a/components/header/PageHeader.vue
+++ b/components/header/PageHeader.vue
@@ -53,4 +53,4 @@
font-size: 1.2rem;
color: var(--color-text-mute);
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/header/SiteHeader.vue b/components/header/SiteHeader.vue
index 22ee209..c1b2aa9 100644
--- a/components/header/SiteHeader.vue
+++ b/components/header/SiteHeader.vue
@@ -3,7 +3,7 @@ const session = useSessionStore();
const navigateHome = () => {
navigateTo('/');
-}
+};
const sessionType = computed(() => session.getSessionType());
</script>
@@ -53,7 +53,6 @@ const sessionType = computed(() => session.getSessionType());
font-size: 0.8rem;
color: var(--color-header-text-mute);
}
-
}
#logo {
@@ -82,4 +81,4 @@ header {
display: flex;
justify-content: space-between;
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/loader/LoaderDiscardSessionModal.vue b/components/loader/LoaderDiscardSessionModal.vue
index 845b10a..6f5ed02 100644
--- a/components/loader/LoaderDiscardSessionModal.vue
+++ b/components/loader/LoaderDiscardSessionModal.vue
@@ -5,7 +5,7 @@ const showModal = ref(false);
const open = () => {
showModal.value = true;
-}
+};
const confirm = () => {
session.setQuests([]);
@@ -16,11 +16,11 @@ const confirm = () => {
navigateToEditorPane(null);
showModal.value = false;
-}
+};
defineExpose({
- open
-})
+ open,
+});
</script>
<template>
@@ -29,12 +29,20 @@ defineExpose({
<h2>Discard current session</h2>
</template>
- <p>You are about to discard your current session. All changes will be lost.
- Do you want to continue?</p>
+ <p>
+ You are about to discard your current session. All changes will be lost. Do you want to
+ continue?
+ </p>
<div id="controls" class="control-group">
<Button :icon="['fas', 'xmark']" :label="'Cancel'" @click="showModal = false"></Button>
- <Button type="solid" accent="danger" :icon="['fas', 'trash']" :label="'Confirm'" @click="confirm"></Button>
+ <Button
+ type="solid"
+ accent="danger"
+ :icon="['fas', 'trash']"
+ :label="'Confirm'"
+ @click="confirm"
+ ></Button>
</div>
</Modal>
</template>
@@ -45,4 +53,4 @@ defineExpose({
justify-content: flex-end;
margin-top: 1rem;
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/loader/LoaderFileSystemButton.vue b/components/loader/LoaderFileSystemButton.vue
index 3a70860..58c470c 100644
--- a/components/loader/LoaderFileSystemButton.vue
+++ b/components/loader/LoaderFileSystemButton.vue
@@ -27,14 +27,19 @@ const openFileSystemPrompt = async () => {
console.error(e);
loaderStore.setFileSystemLoaderStatus('invalid');
}
-}
+};
</script>
<template>
<ClientOnly>
- <Button type="solid" :icon="['fas', 'folder-open']" label="Load" @click="openFileSystemPrompt"
- :disabled="!canUseFsApi" />
+ <Button
+ type="solid"
+ :icon="['fas', 'folder-open']"
+ label="Load"
+ @click="openFileSystemPrompt"
+ :disabled="!canUseFsApi"
+ />
<LoaderFileSystemModal ref="fileSystemModal" />
</ClientOnly>
-</template> \ No newline at end of file
+</template>
diff --git a/components/loader/LoaderFileSystemModal.vue b/components/loader/LoaderFileSystemModal.vue
index 25fcfa2..a3f133b 100644
--- a/components/loader/LoaderFileSystemModal.vue
+++ b/components/loader/LoaderFileSystemModal.vue
@@ -6,7 +6,7 @@ const showModal = ref(false);
const open = () => {
showModal.value = true;
-}
+};
const confirm = () => {
const categories = loader.getCategories();
@@ -21,7 +21,7 @@ const confirm = () => {
navigateToEditorPane(null);
showModal.value = false;
-}
+};
const status = computed(() => loader.getFileSystemLoaderStatus());
const questsCount = computed(() => loader.getQuests().length);
@@ -30,8 +30,8 @@ const itemsCount = computed(() => loader.getItems().length);
const path = computed(() => loader.getPath());
defineExpose({
- open
-})
+ open,
+});
</script>
<template>
@@ -50,7 +50,10 @@ defineExpose({
</div>
<div v-if="status === 'loaded'">
- <p>Parsing files in directory <code>{{ path }}</code>...</p>
+ <p>
+ Parsing files in directory <code>{{ path }}</code
+ >...
+ </p>
</div>
<div v-if="status === 'invalid'">
@@ -58,7 +61,10 @@ defineExpose({
</div>
<div v-if="status === 'valid'">
- <p>Successfully parsed directory <code>{{ path }}</code>.</p>
+ <p>
+ Successfully parsed directory <code>{{ path }}</code
+ >.
+ </p>
<ul>
<li>{{ categoriesCount }} categories loaded</li>
<li>{{ questsCount }} quests loaded</li>
@@ -69,8 +75,13 @@ defineExpose({
<div id="controls" class="control-group">
<Button :icon="['fas', 'xmark']" :label="'Cancel'" @click="showModal = false"></Button>
- <Button v-if="status === 'valid'" type="solid" :icon="['fas', 'check']" :label="'Confirm'"
- @click="confirm"></Button>
+ <Button
+ v-if="status === 'valid'"
+ type="solid"
+ :icon="['fas', 'check']"
+ :label="'Confirm'"
+ @click="confirm"
+ ></Button>
</div>
</Modal>
</template>
@@ -81,4 +92,4 @@ defineExpose({
justify-content: flex-end;
margin-top: 1rem;
}
-</style> \ No newline at end of file
+</style>
diff --git a/components/loader/LoaderImportButton.vue b/components/loader/LoaderImportButton.vue
index ff6d0ad..d0c4107 100644
--- a/components/loader/LoaderImportButton.vue
+++ b/components/loader/LoaderImportButton.vue
@@ -1,14 +1,18 @@
<script setup lang="ts">
defineProps({
- isPrimaryAction: Boolean
-})
+ isPrimaryAction: Boolean,
+});
const navigateToImport = async () => {
navigateTo('/import');
-}
+};
</script>
<template>
- <Button :type="isPrimaryAction ? 'solid' : 'text'" :icon="['fas', 'file-import']" label="Import"
- @click="navigateToImport" />
-</template> \ No newline at end of file
+ <Button
+ :type="isPrimaryAction ? 'solid' : 'text'"
+ :icon="['fas', 'file-import']"
+ label="Import"
+ @click="navigateToImport"
+ />
+</template>
diff --git a/components/loader/LoaderNetworkButton.vue b/components/loader/LoaderNetworkButton.vue
index 3364597..8cce5dc 100644
--- a/components/loader/LoaderNetworkButton.vue
+++ b/components/loader/LoaderNetworkButton.vue
@@ -1,8 +1,7 @@
-<script setup lang="ts">
-</script>
+<script setup lang="ts"></script>
<template>
<ClientOnly>
<Button type="solid" :icon="['fas', 'download']" label="Download" :disabled="true" />
</ClientOnly>
-</template> \ No newline at end of file
+</template>
diff --git a/components/loader/LoaderTestDataButton.vue b/components/loader/LoaderTestDataButton.vue
index 1e648d6..8ef8b3c 100644
--- a/components/loader/LoaderTestDataButton.vue
+++ b/components/loader/LoaderTestDataButton.vue
@@ -5,7 +5,7 @@ const testDataModal = ref<InstanceType<typeof LoaderTestDataModal> | null>(null)
const openTestDataModal = async () => {
testDataModal.value?.open();
-}
+};
</script>
<template>
@@ -14,4 +14,4 @@ const openTestDataModal = async () => {
<LoaderTestDataModal ref="testDataModal" />
</ClientOnly>
-</template> \ No newline at end of file
+</template>
diff --git a/components/loader/LoaderTestDataModal.vue b/components/loader/LoaderTestDataModal.vue
index 8b0df21..582e224 100644
--- a/components/loader/LoaderTestDataModal.vue
+++ b/components/loader/LoaderTestDataModal.vue
@@ -8,7 +8,7 @@ const showModal = ref(false);
const open = () => {
showModal.value = true;
-}
+};
const confirm = () => {
const quests = loadQuestsFromJson(testData.quests);
@@ -23,11 +23,11 @@ const confirm = () => {
navigateToEditorPane(null);
showModal.value = false;
-}
+};
defineExpose({
- open
-})
+ open,
+});
</script>
<template>
@@ -36,8 +36,10 @@ defineExpose({
<h2>Import test data</h2>
</template>
- <p>You can view a demo of the Quests editor by loading test data. This will replace your current workspace.
- Do you want to continue?</p>
+ <p>
+ You can view a demo of the Quests editor by loading test data. This will replace your current
+ workspace. Do you want to continue?
+ </p>
<div id="controls" class="control-group">
<Button :icon="['fas', 'xmark']" :label="'Cancel'" @click="showModal = false"></Button>
@@ -52,4 +54,4 @@ defineExpose({
justify-content: flex-end;
margin-top: 1rem;
}
-</style> \ No newline at end of file
+</style>
diff --git a/layouts/default.vue b/layouts/default.vue
index fef2da1..01e8484 100644
--- a/layouts/default.vue
+++ b/layouts/default.vue
@@ -1,5 +1,4 @@
-<script setup lang="ts">
-</script>
+<script setup lang="ts"></script>
<template>
<SiteHeader />
@@ -23,4 +22,4 @@
#content {
width: 100%;
}
-</style> \ No newline at end of file
+</style>
diff --git a/layouts/editor.vue b/layouts/editor.vue
index dbb53fa..a3dbf35 100644
--- a/layouts/editor.vue
+++ b/layouts/editor.vue
@@ -35,4 +35,4 @@ sessionStore.setTaskTypeAliases(taskDefinitions.aliases);
#editor-pane {
width: 100%;
}
-</style> \ No newline at end of file
+</style>
diff --git a/lib/enchantments.ts b/lib/enchantments.ts
index a770feb..9ee1994 100644
--- a/lib/enchantments.ts
+++ b/lib/enchantments.ts
@@ -1,3 +1,3 @@
import enchantments from '@/data/enchantments.json';
-export default enchantments; \ No newline at end of file
+export default enchantments;
diff --git a/lib/itemflags.ts b/lib/itemflags.ts
index a7ce433..d3b196d 100644
--- a/lib/itemflags.ts
+++ b/lib/itemflags.ts
@@ -1,3 +1,3 @@
import itemflags from '@/data/itemflags.json';
-export default itemflags; \ No newline at end of file
+export default itemflags;
diff --git a/lib/materials.ts b/lib/materials.ts
index 36c5aee..85f1094 100644
--- a/lib/materials.ts
+++ b/lib/materials.ts
@@ -1,3 +1,3 @@
import materials from '@/data/materials.json';
-export default materials; \ No newline at end of file
+export default materials;
diff --git a/lib/questsLoader.ts b/lib/questsLoader.ts
index f49dce5..28faeb7 100644
--- a/lib/questsLoader.ts
+++ b/lib/questsLoader.ts
@@ -14,12 +14,17 @@ export function loadQuestsFromJson(config: any): EditorQuest[] {
},
type: quest.display.type,
},
- tasks: Object.fromEntries(Object.keys(quest.tasks).map((taskId: string) => {
- return [taskId, {
- id: taskId,
- config: quest.tasks[taskId],
- } as EditorTask];
- })),
+ tasks: Object.fromEntries(
+ Object.keys(quest.tasks).map((taskId: string) => {
+ return [
+ taskId,
+ {
+ id: taskId,
+ config: quest.tasks[taskId],
+ } as EditorTask,
+ ];
+ })
+ ),
rewards: quest.rewards,
...(quest.startcommands && { startCommands: quest.startcommands }),
...(quest.startstring && { startString: quest.startstring }),
@@ -42,9 +47,15 @@ export function loadQuestsFromJson(config: any): EditorQuest[] {
},
sortOrder: quest.options['sort-order'] || 0,
autostart: quest.options.autostart || false,
- ...(quest.options['completed-display'] && { completedDisplay: quest.options['completed-display'] }),
- ...(quest.options['cooldown-display'] && { cooldownDisplay: quest.options['cooldown-display'] }),
- ...(quest.options['permission-display'] && { permissionDisplay: quest.options['permission-display'] }),
+ ...(quest.options['completed-display'] && {
+ completedDisplay: quest.options['completed-display'],
+ }),
+ ...(quest.options['cooldown-display'] && {
+ cooldownDisplay: quest.options['cooldown-display'],
+ }),
+ ...(quest.options['permission-display'] && {
+ permissionDisplay: quest.options['permission-display'],
+ }),
...(quest.options['locked-display'] && { lockedDisplay: quest.options['locked-display'] }),
},
} as EditorQuest;
@@ -82,14 +93,16 @@ export function loadItemsFromJson(config: any): EditorItem[] {
//TODO don't write fields if they're unchanged
export function mapJsonQuestToYamlObject(quest: EditorQuest): any {
return {
- tasks: Object.fromEntries(Object.keys(quest.tasks).map((taskId: string) => {
- return [taskId, quest.tasks[taskId].config]
- })),
+ tasks: Object.fromEntries(
+ Object.keys(quest.tasks).map((taskId: string) => {
+ return [taskId, quest.tasks[taskId].config];
+ })
+ ),
display: {
name: quest.display.name,
- "lore-normal": quest.display.lore.normal,
- "lore-started": quest.display.lore.started,
- type: quest.display.type
+ 'lore-normal': quest.display.lore.normal,
+ 'lore-started': quest.display.lore.started,
+ type: quest.display.type,
},
rewards: quest.rewards,
...(quest.startCommands && { startcommands: quest.startCommands }),
@@ -99,26 +112,28 @@ export function mapJsonQuestToYamlObject(quest: EditorQuest): any {
options: {
category: quest.options.category,
requires: quest.options.requirements,
- "permission-required": quest.options.permissionRequired,
+ 'permission-required': quest.options.permissionRequired,
cancellable: quest.options.cancellable,
- "counts-towards-limit": quest.options.countsTowardsLimit,
+ 'counts-towards-limit': quest.options.countsTowardsLimit,
repeatable: quest.options.repeatable,
cooldown: {
enabled: quest.options.cooldown.enabled,
time: quest.options.cooldown.time,
},
- "time-limit": {
+ 'time-limit': {
enabled: quest.options.timeLimit.enabled,
time: quest.options.timeLimit.time,
},
- "sort-order": quest.options.sortOrder,
+ 'sort-order': quest.options.sortOrder,
autostart: quest.options.autostart || false,
...(quest.options.completedDisplay && { completedDisplay: quest.options.completedDisplay }),
...(quest.options.cooldownDisplay && { cooldownDisplay: quest.options.cooldownDisplay }),
- ...(quest.options.permissionDisplay && { permissionDisplay: quest.options.permissionDisplay }),
+ ...(quest.options.permissionDisplay && {
+ permissionDisplay: quest.options.permissionDisplay,
+ }),
...(quest.options.lockedDisplay && { lockedDisplay: quest.options.lockedDisplay }),
},
- }
+ };
}
export function mapJsonCategoryToYamlObject(category: EditorCategory): any {
@@ -128,13 +143,13 @@ export function mapJsonCategoryToYamlObject(category: EditorCategory): any {
type: category.display.type,
lore: category.display.lore,
},
- "permission-required": category.permissionRequired,
- }
+ 'permission-required': category.permissionRequired,
+ };
}
export function mapJsonItemToYamlObject(item: EditorItem): any {
return {
type: item.type,
- item: item.config
- }
-} \ No newline at end of file
+ item: item.config,
+ };
+}
diff --git a/middleware/editor.global.ts b/middleware/editor.global.ts
index 82df54b..5d72273 100644
--- a/middleware/editor.global.ts
+++ b/middleware/editor.global.ts
@@ -1,4 +1,4 @@
-import { useSessionStore } from "@/stores/session";
+import { useSessionStore } from '@/stores/session';
export default defineNuxtRouteMiddleware((to, from) => {
const session = useSessionStore();
diff --git a/nuxt.config.ts b/nuxt.config.ts
index f748dc2..93a04fd 100644
--- a/nuxt.config.ts
+++ b/nuxt.config.ts
@@ -9,24 +9,22 @@ export default defineNuxtConfig({
modules: [
// ...
'@pinia/nuxt',
- 'nuxt-prepare'
- ],
- css: [
- '@fortawesome/fontawesome-svg-core/styles.css'
+ 'nuxt-prepare',
],
+ css: ['@fortawesome/fontawesome-svg-core/styles.css'],
build: {
transpile: [
- "@fortawesome/vue-fontawesome",
- "@fortawesome/fontawesome-svg-core",
- "@fortawesome/free-solid-svg-icons",
- "@fortawesome/free-regular-svg-icons",
+ '@fortawesome/vue-fontawesome',
+ '@fortawesome/fontawesome-svg-core',
+ '@fortawesome/free-solid-svg-icons',
+ '@fortawesome/free-regular-svg-icons',
],
},
runtimeConfig: {
public: {
gitCommitHash: process.env.GIT_COMMIT_HASH,
gitCommitHashShort: process.env.GIT_COMMIT_HASH_SHORT,
- gitBranch: process.env.GIT_BRANCH
- }
- }
-})
+ gitBranch: process.env.GIT_BRANCH,
+ },
+ },
+});
diff --git a/pages/editor/category/[id].vue b/pages/editor/category/[id].vue
index cf79f61..5558c53 100644
--- a/pages/editor/category/[id].vue
+++ b/pages/editor/category/[id].vue
@@ -2,8 +2,8 @@
import { useSessionStore } from '@/stores/session';
definePageMeta({
- layout: 'editor'
-})
+ layout: 'editor',
+});
const sessionStore = useSessionStore();
const route = useRoute();
@@ -44,4 +44,4 @@ const categoryName = sessionStore.getCategoryById(categoryId)?.display.name;
header {
border-bottom: 1px solid var(--color-border);
}
-</style> \ No newline at end of file
+</style>
diff --git a/pages/editor/config.vue b/pages/editor/config.vue
index 4dfc679..515cac9 100644
--- a/pages/editor/config.vue
+++ b/pages/editor/config.vue
@@ -1,7 +1,7 @@
<script setup lang="ts">
definePageMeta({
- layout: 'editor'
-})
+ layout: 'editor',
+});
</script>
<template>
@@ -14,4 +14,4 @@ definePageMeta({
#title {
text-align: center;
}
-</style> \ No newline at end of file
+</style>
diff --git a/pages/editor/index.vue b/pages/editor/index.vue
index 4e9815a..55c75f3 100644
--- a/pages/editor/index.vue
+++ b/pages/editor/index.vue
@@ -1,7 +1,7 @@
<script setup lang="ts">
definePageMeta({
- layout: 'editor'
-})
+ layout: 'editor',
+});
</script>
<template>
@@ -22,4 +22,4 @@ definePageMeta({
font-size: 1.5rem;
}
}
-</style> \ No newline at end of file
+</style>
diff --git a/pages/editor/item/[id].vue b/pages/editor/item/[id].vue
index 451a76d..d6656ab 100644
--- a/pages/editor/item/[id].vue
+++ b/pages/editor/item/[id].vue
@@ -2,8 +2,8 @@
import { useSessionStore } from '@/stores/session';
definePageMeta({
- layout: 'editor'
-})
+ layout: 'editor',
+});
const sessionStore = useSessionStore();
const route = useRoute();
@@ -24,8 +24,7 @@ const item = sessionStore.getItemById(itemId);
</span>
</PageHeader>
- <div id="options-container">
- </div>
+ <div id="options-container"></div>
</template>
<style scoped>
@@ -41,4 +40,4 @@ const item = sessionStore.getItemById(itemId);
header {
border-bottom: 1px solid var(--color-border);
}
-</style> \ No newline at end of file
+</style>
diff --git a/pages/editor/quest/[id].vue b/pages/editor/quest/[id].vue
index 34dafa8..8886dc5 100644
--- a/pages/editor/quest/[id].vue
+++ b/pages/editor/quest/[id].vue
@@ -4,8 +4,8 @@ import { computed, ref } from 'vue';
import type EditorQuestModalYaml from '~/components/editor/quest/modal/EditorQuestModalYaml.vue';
definePageMeta({
- layout: 'editor'
-})
+ layout: 'editor',
+});
const sessionStore = useSessionStore();
const route = useRoute();
@@ -13,7 +13,6 @@ const route = useRoute();
const questId = route.params.id as string;
const quest = sessionStore.getQuestById(questId);
-
const categoryFromSelectedQuest = computed(() => {
const quest = sessionStore.getQuestById(questId);
if (quest) {
@@ -48,7 +47,7 @@ const duplicateQuest = (oldId: string, newId: string) => {
const showYaml = () => {
yamlModal.value?.open();
-}
+};
</script>
<template>
@@ -65,9 +64,17 @@ const showYaml = () => {
</span>
<span id="controls" class="control-group">
<Button :icon="['fas', 'fa-code']" :label="'YAML'" @click="showYaml"></Button>
- <Button :icon="['fas', 'fa-copy']" :label="'Duplicate'" @click="showDuplicateModal = true"></Button>
+ <Button
+ :icon="['fas', 'fa-copy']"
+ :label="'Duplicate'"
+ @click="showDuplicateModal = true"
+ ></Button>
<Button :icon="['fas', 'fa-pen']" :label="'Rename'" @click="showRenameModal = true"></Button>
- <Button :icon="['fas', 'fa-trash']" :label="'Delete'" @click="showDeleteModal = true"></Button>
+ <Button
+ :icon="['fas', 'fa-trash']"
+ :label="'Delete'"
+ @click="showDeleteModal = true"
+ ></Button>
<Button type="solid" :disabled="true" :icon="['fas', 'fa-save']" :label="'Save'"></Button>
</span>
</PageHeader>
@@ -78,12 +85,24 @@ const showYaml = () => {
</div>
<EditorQuestModalYaml ref="yamlModal" :key="`yaml-quest-${questId}`" :questId="questId" />
- <EditorQuestModalDelete v-model="showDeleteModal" :key="`delete-quest-${questId}`" :questId="questId"
- @delete="() => questId && deleteQuest(questId)" />
- <EditorQuestModalRename v-model="showRenameModal" :key="`rename-quest-${questId}`" :questId="questId"
- @update="(newId: any) => questId && renameQuest(questId, newId)" />
- <EditorQuestModalDuplicate v-model="showDuplicateModal" :key="`duplicate-quest-${questId}`" :questId="questId"
- @duplicate="(newId: any) => questId && duplicateQuest(questId, newId)" />
+ <EditorQuestModalDelete
+ v-model="showDeleteModal"
+ :key="`delete-quest-${questId}`"
+ :questId="questId"
+ @delete="() => questId && deleteQuest(questId)"
+ />
+ <EditorQuestModalRename
+ v-model="showRenameModal"
+ :key="`rename-quest-${questId}`"
+ :questId="questId"
+ @update="(newId: any) => questId && renameQuest(questId, newId)"
+ />
+ <EditorQuestModalDuplicate
+ v-model="showDuplicateModal"
+ :key="`duplicate-quest-${questId}`"
+ :questId="questId"
+ @duplicate="(newId: any) => questId && duplicateQuest(questId, newId)"
+ />
</template>
<style scoped>
@@ -99,4 +118,4 @@ const showYaml = () => {
header {
border-bottom: 1px solid var(--color-border);
}
-</style> \ No newline at end of file
+</style>
diff --git a/pages/import.vue b/pages/import.vue
index 7397358..3cadb3d 100644
--- a/pages/import.vue
+++ b/pages/import.vue
@@ -2,8 +2,8 @@
import LoaderDiscardSessionModal from '~/components/loader/LoaderDiscardSessionModal.vue';
definePageMeta({
- layout: 'default'
-})
+ layout: 'default',
+});
const session = useSessionStore();
@@ -64,8 +64,17 @@ const discardSessionModal = ref<InstanceType<typeof LoaderDiscardSessionModal> |
</div>
<div id="button-group">
- <Button :icon="['fas', 'arrow-left']" label="Return to Session" @click="navigateToEditorPane(null)" />
- <Button accent="danger" :icon="['fas', 'trash']" label="Discard" @click="discardSessionModal?.open" />
+ <Button
+ :icon="['fas', 'arrow-left']"
+ label="Return to Session"
+ @click="navigateToEditorPane(null)"
+ />
+ <Button
+ accent="danger"
+ :icon="['fas', 'trash']"
+ label="Discard"
+ @click="discardSessionModal?.open"
+ />
</div>
</div>
</div>
@@ -144,4 +153,4 @@ const discardSessionModal = ref<InstanceType<typeof LoaderDiscardSessionModal> |
hr {
width: 100%;
}
-</style> \ No newline at end of file
+</style>
diff --git a/pages/index.vue b/pages/index.vue
index a64706a..d4a9b6d 100644
--- a/pages/index.vue
+++ b/pages/index.vue
@@ -1,7 +1,7 @@
<script setup lang="ts">
definePageMeta({
- layout: 'default'
-})
+ layout: 'default',
+});
</script>
<template>
@@ -9,30 +9,35 @@ definePageMeta({
<div id="welcome">
<img id="welcome-image" src="@/assets/quests-logo.png" alt="Quests logo" />
<b id="title">Welcome to the Quests Web Editor</b>
- <p>This is a work in progress build of the web editor for <a href="https://github.com/LMBishop/Quests">Quests</a>.
- It is <b>not</b> ready for use.
+ <p>
+ This is a work in progress build of the web editor for
+ <a href="https://github.com/LMBishop/Quests">Quests</a>. It is <b>not</b> ready for use.
</p>
- <p>If you would like to try this out, use the buttons in the top right corner to start a session.</p>
- <b id="subtitle">Cannot import from filesystem</b>
<p>
- If you cannot import from filesystem, then that means you are using a browser which does not implement the
- <a href="https://wicg.github.io/file-system-access/">File System Access API</a>. At the time of writing,
- only Chromium based browsers (Google Chrome, Microsoft Edge, Brave, etc.) implement this. This means if you
- use Firefox or Safari, you must switch browser to use this feature.
+ If you would like to try this out, use the buttons in the top right corner to start a
+ session.
</p>
+ <b id="subtitle">Cannot import from filesystem</b>
<p>
- You can instead load the test data instead by clicking the "Demo" button.
+ If you cannot import from filesystem, then that means you are using a browser which does not
+ implement the
+ <a href="https://wicg.github.io/file-system-access/">File System Access API</a>. At the time
+ of writing, only Chromium based browsers (Google Chrome, Microsoft Edge, Brave, etc.)
+ implement this. This means if you use Firefox or Safari, you must switch browser to use this
+ feature.
</p>
+ <p>You can instead load the test data instead by clicking the "Demo" button.</p>
<b id="subtitle">Light / dark theme</b>
<p>
- Note that the light theme of this website is a work in progress. Please use the dark theme. The colour scheme
- will automatically adjust based on your browsers preferences.
+ Note that the light theme of this website is a work in progress. Please use the dark theme.
+ The colour scheme will automatically adjust based on your browsers preferences.
</p>
<b id="subtitle">Source code</b>
<p>
- Just like Quests itself, the source code is <a href="https://github.com/LMBishop/quests-web-editor">available
- on GitHub</a>.
- Due to the volatile state of this project, if you would like to get involved please get in touch with me first.
+ Just like Quests itself, the source code is
+ <a href="https://github.com/LMBishop/quests-web-editor">available on GitHub</a>. Due to the
+ volatile state of this project, if you would like to get involved please get in touch with
+ me first.
</p>
</div>
</div>
@@ -74,4 +79,4 @@ definePageMeta({
font-weight: bold;
}
}
-</style> \ No newline at end of file
+</style>
diff --git a/plugins/fontawesome.ts b/plugins/fontawesome.ts
index f826370..f3b12d3 100644
--- a/plugins/fontawesome.ts
+++ b/plugins/fontawesome.ts
@@ -1,5 +1,5 @@
-import { library, config } from '@fortawesome/fontawesome-svg-core'
-import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
+import { library, config } from '@fortawesome/fontawesome-svg-core';
+import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import {
faAppleWhole,
faArrowLeft,
@@ -31,50 +31,50 @@ import {
faTrowel,
faUpload,
faWrench,
- faXmark
-} from '@fortawesome/free-solid-svg-icons'
-import { faCompass } from '@fortawesome/free-regular-svg-icons'
+ faXmark,
+} from '@fortawesome/free-solid-svg-icons';
+import { faCompass } from '@fortawesome/free-regular-svg-icons';
-config.autoAddCss = false
+config.autoAddCss = false;
// fas
-library.add(faPlus)
-library.add(faCheck)
-library.add(faCubes)
-library.add(faCubesStacked)
-library.add(faXmark)
-library.add(faSave)
-library.add(faFileExport)
-library.add(faFileImport)
-library.add(faDownload)
-library.add(faUpload)
-library.add(faFolder)
-library.add(faPencil)
-library.add(faCodeBranch)
-library.add(faFolderOpen)
-library.add(faFlaskVial)
-library.add(faTrash)
-library.add(faCaretDown)
-library.add(faFileZipper)
-library.add(faWrench)
-library.add(faHardDrive)
-library.add(faArrowLeft)
-library.add(faChevronRight)
-library.add(faCode)
-library.add(faCopy)
-library.add(faPen)
-library.add(faTag)
-library.add(faAppleWhole)
-library.add(faCube)
+library.add(faPlus);
+library.add(faCheck);
+library.add(faCubes);
+library.add(faCubesStacked);
+library.add(faXmark);
+library.add(faSave);
+library.add(faFileExport);
+library.add(faFileImport);
+library.add(faDownload);
+library.add(faUpload);
+library.add(faFolder);
+library.add(faPencil);
+library.add(faCodeBranch);
+library.add(faFolderOpen);
+library.add(faFlaskVial);
+library.add(faTrash);
+library.add(faCaretDown);
+library.add(faFileZipper);
+library.add(faWrench);
+library.add(faHardDrive);
+library.add(faArrowLeft);
+library.add(faChevronRight);
+library.add(faCode);
+library.add(faCopy);
+library.add(faPen);
+library.add(faTag);
+library.add(faAppleWhole);
+library.add(faCube);
// task type icons
-library.add(faTrowel)
-library.add(faBuildingColumns)
-library.add(faBoxesStacked)
+library.add(faTrowel);
+library.add(faBuildingColumns);
+library.add(faBoxesStacked);
// far
-library.add(faCompass)
+library.add(faCompass);
export default defineNuxtPlugin((nuxtApp) => {
- nuxtApp.vueApp.component('font-awesome-icon', FontAwesomeIcon, {})
-})
+ nuxtApp.vueApp.component('font-awesome-icon', FontAwesomeIcon, {});
+});
diff --git a/plugins/jszip.ts b/plugins/jszip.ts
index edf0206..775df43 100644
--- a/plugins/jszip.ts
+++ b/plugins/jszip.ts
@@ -1,5 +1,5 @@
-import JSZip from "jszip"
+import JSZip from 'jszip';
export default defineNuxtPlugin((nuxtApp) => {
- nuxtApp.vueApp.use(JSZip)
-})
+ nuxtApp.vueApp.use(JSZip);
+});
diff --git a/plugins/multiselect.ts b/plugins/multiselect.ts
index 5f76652..e86718a 100644
--- a/plugins/multiselect.ts
+++ b/plugins/multiselect.ts
@@ -1,5 +1,5 @@
-import Multiselect from 'vue-multiselect'
+import Multiselect from 'vue-multiselect';
export default defineNuxtPlugin((nuxtApp) => {
- nuxtApp.vueApp.component('multiselect', Multiselect, {})
-})
+ nuxtApp.vueApp.component('multiselect', Multiselect, {});
+});
diff --git a/server.prepare.ts b/server.prepare.ts
index a858e69..875889c 100644
--- a/server.prepare.ts
+++ b/server.prepare.ts
@@ -1,5 +1,5 @@
import { execSync } from 'child_process';
-import { defineNuxtPrepareHandler } from 'nuxt-prepare/config'
+import { defineNuxtPrepareHandler } from 'nuxt-prepare/config';
export default defineNuxtPrepareHandler(async () => {
const gitCommitHash = execSync('git rev-parse HEAD').toString().trim();
@@ -11,12 +11,12 @@ export default defineNuxtPrepareHandler(async () => {
public: {
gitCommitHash: gitCommitHash,
gitCommitHashShort: gitCommitHashShort,
- gitBranch: gitBranch
- }
+ gitBranch: gitBranch,
+ },
},
state: {
foo: 'bar',
},
- }
-}) \ No newline at end of file
+ };
+});
diff --git a/stores/export.ts b/stores/export.ts
index 3f48aa3..f0ff260 100644
--- a/stores/export.ts
+++ b/stores/export.ts
@@ -1,4 +1,4 @@
-import { defineStore } from 'pinia'
+import { defineStore } from 'pinia';
export type ZipLoaderStatus = 'inactive' | 'preparing' | 'compressing' | 'ready' | 'failed';
@@ -7,7 +7,7 @@ export const useExportStore = defineStore('export', {
zip: {
status: 'inactive' as ZipLoaderStatus,
contents: null as Blob | null,
- }
+ },
}),
getters: {
getZipStatus: (state) => () => {
@@ -27,5 +27,5 @@ export const useExportStore = defineStore('export', {
setZipContents(contents: Blob) {
this.zip.contents = contents;
},
- }
+ },
});
diff --git a/stores/loader.ts b/stores/loader.ts
index fe3742c..9d4b7ad 100644
--- a/stores/loader.ts
+++ b/stores/loader.ts
@@ -1,4 +1,4 @@
-import { defineStore } from 'pinia'
+import { defineStore } from 'pinia';
import type { EditorCategory, EditorItem } from './session';
export type FileSystemLoaderStatus = 'inactive' | 'pending' | 'loaded' | 'invalid' | 'valid';
@@ -11,7 +11,7 @@ export const useLoaderStore = defineStore('loader', {
quests: [] as EditorQuest[],
categories: [] as EditorCategory[],
items: [] as EditorItem[],
- }
+ },
}),
getters: {
getFileSystemLoaderStatus: (state) => () => {
@@ -50,6 +50,6 @@ export const useLoaderStore = defineStore('loader', {
},
setItems(items: EditorItem[]) {
this.fileSystem.items = items;
- }
- }
+ },
+ },
});
diff --git a/stores/session.ts b/stores/session.ts
index 50bcde7..c593b78 100644
--- a/stores/session.ts
+++ b/stores/session.ts
@@ -1,4 +1,4 @@
-import { defineStore } from 'pinia'
+import { defineStore } from 'pinia';
export interface EditorQuest {
id: string;
@@ -7,9 +7,9 @@ export interface EditorQuest {
lore: {
normal: string[];
started: string[];
- }
+ };
type: string;
- }
+ };
tasks: { [key: string]: EditorTask };
rewards: string[];
startCommands?: string[];
@@ -26,18 +26,18 @@ export interface EditorQuest {
cooldown: {
enabled: boolean;
time: number;
- }
+ };
timeLimit: {
enabled: boolean;
time: number;
- }
+ };
sortOrder: number;
autostart: boolean;
completedDisplay?: string;
cooldownDisplay?: string;
permissionDisplay?: string;
lockedDisplay?: string;
- }
+ };
}
export interface EditorTask {
@@ -45,7 +45,7 @@ export interface EditorTask {
config: {
type: string;
[key: string]: any;
- }
+ };
}
export interface EditorCategory {
@@ -54,14 +54,14 @@ export interface EditorCategory {
name: string;
lore: string[];
type: string;
- }
+ };
permissionRequired: string;
}
export interface EditorItem {
id: string;
type: string;
- config: any
+ config: any;
}
export interface TaskDefinition {
@@ -69,7 +69,7 @@ export interface TaskDefinition {
icon: {
style: string;
name: string;
- }
+ };
configuration: {
[key: string]: {
type: string | string[];
@@ -77,8 +77,8 @@ export interface TaskDefinition {
default?: any;
required?: boolean;
note?: string;
- }
- }
+ };
+ };
}
export interface QuestItemDefinition {
@@ -89,8 +89,8 @@ export interface QuestItemDefinition {
[key: string]: {
type: string | string[];
description: string;
- }
- }
+ };
+ };
}
export type SessionType = 'none' | 'filesystem' | 'demo';
@@ -104,69 +104,72 @@ export const useSessionStore = defineStore('session', {
items: [] as EditorItem[],
taskDefinitions: {} as { [key: string]: TaskDefinition },
taskTypeAliases: {} as { [key: string]: string },
- questItemDefinitions: {} as { [key: string]: QuestItemDefinition }
- }
+ questItemDefinitions: {} as { [key: string]: QuestItemDefinition },
+ },
}),
getters: {
getSessionType: (state) => () => {
- return state.sessionType
+ return state.sessionType;
},
getQuests: (state) => () => {
- return state.session.quests
+ return state.session.quests;
},
getCategories: (state) => () => {
- return state.session.categories
+ return state.session.categories;
},
getItems: (state) => () => {
- return state.session.items
+ return state.session.items;
},
getQuestById: (state) => (id: string) => {
if (!id) return null;
- return state.session.quests.find(quest => quest.id === id)
+ return state.session.quests.find((quest) => quest.id === id);
},
getCategoryById: (state) => (id: string) => {
if (!id) return null;
- return state.session.categories.find(quest => quest.id === id)
+ return state.session.categories.find((quest) => quest.id === id);
},
getItemById: (state) => (id: string) => {
if (!id) return null;
- return state.session.items.find(item => item.id === id);
+ return state.session.items.find((item) => item.id === id);
},
getQuestsInCategory: (state) => (id: string) => {
if (!id) return [];
- return state.session.quests.filter(quest => quest.options.category === id)
+ return state.session.quests.filter((quest) => quest.options.category === id);
},
getTaskDefinitions: (state) => {
- return state.session.taskDefinitions
+ return state.session.taskDefinitions;
},
getTaskDefinitionByTaskType: (state) => (type: string) => {
- return state.session.taskDefinitions[type] || state.session.taskDefinitions[state.session.taskTypeAliases[type]]
+ return (
+ state.session.taskDefinitions[type] ||
+ state.session.taskDefinitions[state.session.taskTypeAliases[type]]
+ );
},
getKnownTaskTypes: (state) => () => {
- return Object.keys(state.session.taskDefinitions)
+ return Object.keys(state.session.taskDefinitions);
},
getQuestItemDefintions: (state) => {
- return state.session.questItemDefinitions
+ return state.session.questItemDefinitions;
},
getQuestItemDefinitionByTaskType: (state) => (type: string) => {
- return state.session.questItemDefinitions[type]
+ return state.session.questItemDefinitions[type];
},
getKnownQuestItemTypes: (state) => () => {
- return Object.keys(state.session.questItemDefinitions)
- }
+ return Object.keys(state.session.questItemDefinitions);
+ },
},
actions: {
setSessionType(type: SessionType) {
- this.sessionType = type
+ this.sessionType = type;
},
setQuests(quests: EditorQuest[]) {
- this.session.quests = quests
+ this.session.quests = quests;
},
setCategories(categories: EditorCategory[]) {
- this.session.categories = categories
+ this.session.categories = categories;
},
setItems(items: EditorItem[]) {
- this.session.items = items
+ this.session.items = items;
},
setTaskDefinitions(definitions: { [key: string]: TaskDefinition }) {
this.session.taskDefinitions = definitions;
@@ -181,12 +184,12 @@ export const useSessionStore = defineStore('session', {
const quest = this.getQuestById(oldId);
if (!quest) return;
- quest.id = newId
+ quest.id = newId;
},
deleteQuest(id: string) {
- const index = this.session.quests.findIndex(quest => quest.id === id)
+ const index = this.session.quests.findIndex((quest) => quest.id === id);
if (index === -1) return;
- this.session.quests.splice(index, 1)
+ this.session.quests.splice(index, 1);
},
duplicateQuest(id: string, newQuestId: string) {
const quest = this.getQuestById(id);
@@ -195,6 +198,6 @@ export const useSessionStore = defineStore('session', {
const newQuest = JSON.parse(JSON.stringify(quest));
newQuest.id = newQuestId;
this.session.quests.push(newQuest);
- }
- }
+ },
+ },
});
diff --git a/utils/loader.ts b/utils/loader.ts
index 56e29fa..adfa40f 100644
--- a/utils/loader.ts
+++ b/utils/loader.ts
@@ -1,5 +1,5 @@
-import { parse } from "yaml";
-import { loadCategoriesFromJson, loadItemsFromJson, loadQuestsFromJson } from "~/lib/questsLoader";
+import { parse } from 'yaml';
+import { loadCategoriesFromJson, loadItemsFromJson, loadQuestsFromJson } from '~/lib/questsLoader';
export async function openFileSystem() {
try {
@@ -31,50 +31,57 @@ export async function enumerateQuestDirectory(dirHandle: any) {
throw Error('invalid quest directory');
}
- const [questFiles, itemFiles] = await Promise.all([questsDirectory ? listAllFilesAndDirs(questsDirectory) : [], itemsDirectory ? listAllFilesAndDirs(itemsDirectory) : []]);
- const [categories, quests, items] = await Promise.all([(async () => {
- if (!categoryFile) {
- return [];
- }
+ const [questFiles, itemFiles] = await Promise.all([
+ questsDirectory ? listAllFilesAndDirs(questsDirectory) : [],
+ itemsDirectory ? listAllFilesAndDirs(itemsDirectory) : [],
+ ]);
+ const [categories, quests, items] = await Promise.all([
+ (async () => {
+ if (!categoryFile) {
+ return [];
+ }
- const file: any = await categoryFile.getFile();
- const text: string = await file.text();
- const parsedYaml: any = parse(text);
+ const file: any = await categoryFile.getFile();
+ const text: string = await file.text();
+ const parsedYaml: any = parse(text);
- return loadCategoriesFromJson(parsedYaml.categories);
- })(),
- (async () => {
- if (!questFiles) {
- return [];
- }
+ return loadCategoriesFromJson(parsedYaml.categories);
+ })(),
+ (async () => {
+ if (!questFiles) {
+ return [];
+ }
- const allQuests = await Promise.all(questFiles.filter(({ name, handle, kind }) => name.endsWith('.yml')).map(async ({ name, handle, kind }) => {
- const file: any = await handle.getFile();
- const text: string = await file.text();
- return [
- name.replace('.yml', ''),
- parse(text)
- ];
- }))
+ const allQuests = await Promise.all(
+ questFiles
+ .filter(({ name, handle, kind }) => name.endsWith('.yml'))
+ .map(async ({ name, handle, kind }) => {
+ const file: any = await handle.getFile();
+ const text: string = await file.text();
+ return [name.replace('.yml', ''), parse(text)];
+ })
+ );
- return loadQuestsFromJson(Object.fromEntries(allQuests));
- })(),
- (async () => {
- if (!itemFiles) {
- return [];
- }
+ return loadQuestsFromJson(Object.fromEntries(allQuests));
+ })(),
+ (async () => {
+ if (!itemFiles) {
+ return [];
+ }
- const allItems = await Promise.all(itemFiles.filter(({ name, handle, kind }) => name.endsWith('.yml')).map(async ({ name, handle, kind }) => {
- const file: any = await handle.getFile();
- const text: string = await file.text();
- return [
- name.replace('.yml', ''),
- parse(text)
- ];
- }))
+ const allItems = await Promise.all(
+ itemFiles
+ .filter(({ name, handle, kind }) => name.endsWith('.yml'))
+ .map(async ({ name, handle, kind }) => {
+ const file: any = await handle.getFile();
+ const text: string = await file.text();
+ return [name.replace('.yml', ''), parse(text)];
+ })
+ );
- return loadItemsFromJson(Object.fromEntries(allItems));
- })()]);
+ return loadItemsFromJson(Object.fromEntries(allItems));
+ })(),
+ ]);
return { categories, quests, items };
}
@@ -84,10 +91,10 @@ async function listAllFilesAndDirs(dirHandle: any): Promise<any[]> {
for await (const [name, handle] of dirHandle) {
const { kind } = handle;
if (handle.kind === 'directory') {
- files.push(...await listAllFilesAndDirs(handle));
+ files.push(...(await listAllFilesAndDirs(handle)));
} else {
files.push({ name, handle, kind });
}
}
return files;
-} \ No newline at end of file
+}
diff --git a/utils/util.ts b/utils/util.ts
index 273191a..f5f7247 100644
--- a/utils/util.ts
+++ b/utils/util.ts
@@ -1,31 +1,34 @@
-const COLOR_CODE_REGEX = /&([0-9a-fk-or]|#[0-9A-F]{6})/ig;
+const COLOR_CODE_REGEX = /&([0-9a-fk-or]|#[0-9A-F]{6})/gi;
export function stripColorCodes(str: string): string {
return str.replace(COLOR_CODE_REGEX, '');
}
-export function navigateToEditorPane(type: 'quest' | 'category' | 'item' | 'config' | null, id?: string) {
+export function navigateToEditorPane(
+ type: 'quest' | 'category' | 'item' | 'config' | null,
+ id?: string
+) {
if (id) {
if (type === 'category') {
- navigateTo({ path: '/editor/category/' + id })
+ navigateTo({ path: '/editor/category/' + id });
} else if (type === 'quest') {
- navigateTo({ path: '/editor/quest/' + id })
+ navigateTo({ path: '/editor/quest/' + id });
} else if (type === 'item') {
- navigateTo({ path: '/editor/item/' + id })
+ navigateTo({ path: '/editor/item/' + id });
}
} else if (type === 'config') {
- navigateTo({ path: '/editor/config' })
+ navigateTo({ path: '/editor/config' });
} else if (!id && !type) {
- navigateTo({ path: '/editor' })
+ navigateTo({ path: '/editor' });
}
}
export type BrowserCapabilities = {
- canUseFsApi: boolean
-}
+ canUseFsApi: boolean;
+};
export function getBrowserCapabilities(): BrowserCapabilities {
return {
- canUseFsApi: typeof (window as any)?.showDirectoryPicker === 'function'
- }
-} \ No newline at end of file
+ canUseFsApi: typeof (window as any)?.showDirectoryPicker === 'function',
+ };
+}
diff --git a/utils/zipExporter.ts b/utils/zipExporter.ts
index 635e89d..3aff4b3 100644
--- a/utils/zipExporter.ts
+++ b/utils/zipExporter.ts
@@ -1,33 +1,53 @@
-import JSZip from "jszip";
-import { stringify } from "yaml";
-import { mapJsonCategoryToYamlObject, mapJsonItemToYamlObject, mapJsonQuestToYamlObject } from "~/lib/questsLoader";
+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)])));
+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
- }
+ transformedCategories,
+ };
}
-export async function createZip(quests: { [key: string]: string }, categories: string, items: { [key: string]: string }) {
+export async function createZip(
+ quests: { [key: string]: string },
+ categories: string,
+ items: { [key: string]: string }
+) {
const zip = new JSZip();
- zip.file("categories.yml", categories);
+ zip.file('categories.yml', categories);
- const questsDirectory = zip.folder("quests");
+ const questsDirectory = zip.folder('quests');
Object.entries(quests).forEach(([key, value]) => {
- questsDirectory?.file(`${key}.yml`, value)
- })
- const itemsDirectory = zip.folder("items");
+ questsDirectory?.file(`${key}.yml`, value);
+ });
+ const itemsDirectory = zip.folder('items');
Object.entries(items).forEach(([key, value]) => {
- itemsDirectory?.file(`${key}.yml`, value)
- })
+ itemsDirectory?.file(`${key}.yml`, value);
+ });
- return await zip.generateAsync({ type: "blob" });
-} \ No newline at end of file
+ return await zip.generateAsync({ type: 'blob' });
+}