aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeonardo Bishop <me@leonardobishop.com>2024-03-13 17:35:05 +0000
committerLeonardo Bishop <me@leonardobishop.com>2024-03-13 17:35:05 +0000
commitba28c0148cab26fcaf523e84731ffb7c416b3338 (patch)
treea26135e7aa07f53c36292117eff84d0b22e6dd92
parent1d2fd8e82f4d2ccfa4cf9e434a05e43250162449 (diff)
Add import page
-rw-r--r--assets/base.css4
-rw-r--r--components/base/Button.vue24
-rw-r--r--components/header/SiteHeader.vue3
-rw-r--r--components/loader/LoaderDiscardSessionModal.vue48
-rw-r--r--components/loader/LoaderFileSystemButton.vue2
-rw-r--r--components/loader/LoaderImportButton.vue9
-rw-r--r--components/loader/LoaderNetworkButton.vue8
-rw-r--r--components/loader/LoaderTestDataButton.vue2
-rw-r--r--middleware/editor.global.ts4
-rw-r--r--pages/import.vue143
-rw-r--r--stores/session.ts4
11 files changed, 242 insertions, 9 deletions
diff --git a/assets/base.css b/assets/base.css
index 221ff06..f50e84f 100644
--- a/assets/base.css
+++ b/assets/base.css
@@ -28,7 +28,9 @@
--c-brand-highlight: #9885e463;
--c-true: #2ecc71;
+ --c-true-dark: #279e59;
--c-false: #e74c3c;
+ --c-false-dark: #912e23;
}
/* semantic color variables for this project */
@@ -58,7 +60,9 @@
--color-hover: var(--c-brand-highlight);
--color-true: var(--c-true);
+ --color-true-hover: var(--c-true-dark);
--color-false: var(--c-false);
+ --color-false-hover: var(--c-false-dark);
--section-gap: 160px;
diff --git a/components/base/Button.vue b/components/base/Button.vue
index c7f7c50..827e201 100644
--- a/components/base/Button.vue
+++ b/components/base/Button.vue
@@ -5,6 +5,11 @@ const props = defineProps({
required: false,
default: 'text',
},
+ accent: {
+ type: String,
+ required: false,
+ default: 'normal',
+ },
label: String,
icon: Array<String>,
disabled: Boolean,
@@ -20,7 +25,8 @@ const onClick = (event: MouseEvent) => {
</script>
<template>
- <a id="button" :class="{ text: type === 'text', solid: type === 'solid', disabled: disabled }" @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" />
{{ label }}
</a>
@@ -55,6 +61,22 @@ const onClick = (event: MouseEvent) => {
}
}
+.text.danger {
+ color: var(--color-false);
+
+ &:hover {
+ color: var(--color-false-hover)
+ }
+}
+
+.solid.danger {
+ background-color: var(--color-false);
+
+ &:hover {
+ background-color: var(--color-false-hover);
+ }
+}
+
.solid {
background-color: var(--color-primary);
transition: background-color 0.3s;
diff --git a/components/header/SiteHeader.vue b/components/header/SiteHeader.vue
index 015af3d..afd85b8 100644
--- a/components/header/SiteHeader.vue
+++ b/components/header/SiteHeader.vue
@@ -15,8 +15,7 @@ const navigateHome = () => {
</div>
<div id="controls">
- <LoaderTestDataButton />
- <LoaderFileSystemButton />
+ <LoaderImportButton />
</div>
</header>
</template>
diff --git a/components/loader/LoaderDiscardSessionModal.vue b/components/loader/LoaderDiscardSessionModal.vue
new file mode 100644
index 0000000..845b10a
--- /dev/null
+++ b/components/loader/LoaderDiscardSessionModal.vue
@@ -0,0 +1,48 @@
+<script setup lang="ts">
+const session = useSessionStore();
+
+const showModal = ref(false);
+
+const open = () => {
+ showModal.value = true;
+}
+
+const confirm = () => {
+ session.setQuests([]);
+ session.setCategories([]);
+ session.setItems([]);
+ session.setSessionType('none');
+
+ navigateToEditorPane(null);
+
+ showModal.value = false;
+}
+
+defineExpose({
+ open
+})
+</script>
+
+<template>
+ <Modal v-model="showModal">
+ <template v-slot:header>
+ <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>
+
+ <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>
+ </div>
+ </Modal>
+</template>
+
+<style scoped>
+#controls {
+ display: flex;
+ justify-content: flex-end;
+ margin-top: 1rem;
+}
+</style> \ No newline at end of file
diff --git a/components/loader/LoaderFileSystemButton.vue b/components/loader/LoaderFileSystemButton.vue
index 0d02477..3a70860 100644
--- a/components/loader/LoaderFileSystemButton.vue
+++ b/components/loader/LoaderFileSystemButton.vue
@@ -32,7 +32,7 @@ const openFileSystemPrompt = async () => {
<template>
<ClientOnly>
- <Button type="solid" :icon="['fas', 'folder-open']" label="Import from Filesystem" @click="openFileSystemPrompt"
+ <Button type="solid" :icon="['fas', 'folder-open']" label="Load" @click="openFileSystemPrompt"
:disabled="!canUseFsApi" />
<LoaderFileSystemModal ref="fileSystemModal" />
diff --git a/components/loader/LoaderImportButton.vue b/components/loader/LoaderImportButton.vue
new file mode 100644
index 0000000..48bcb8d
--- /dev/null
+++ b/components/loader/LoaderImportButton.vue
@@ -0,0 +1,9 @@
+<script setup lang="ts">
+const navigateToImport = async () => {
+ navigateTo('/import');
+}
+</script>
+
+<template>
+ <Button type="solid" :icon="['fas', 'file-import']" label="Import" @click="navigateToImport" />
+</template> \ No newline at end of file
diff --git a/components/loader/LoaderNetworkButton.vue b/components/loader/LoaderNetworkButton.vue
new file mode 100644
index 0000000..3364597
--- /dev/null
+++ b/components/loader/LoaderNetworkButton.vue
@@ -0,0 +1,8 @@
+<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
diff --git a/components/loader/LoaderTestDataButton.vue b/components/loader/LoaderTestDataButton.vue
index b01b0ee..1e648d6 100644
--- a/components/loader/LoaderTestDataButton.vue
+++ b/components/loader/LoaderTestDataButton.vue
@@ -10,7 +10,7 @@ const openTestDataModal = async () => {
<template>
<ClientOnly>
- <Button :icon="['fas', 'flask-vial']" label="Demo" @click="openTestDataModal" />
+ <Button type="solid" :icon="['fas', 'flask-vial']" label="Demo" @click="openTestDataModal" />
<LoaderTestDataModal ref="testDataModal" />
</ClientOnly>
diff --git a/middleware/editor.global.ts b/middleware/editor.global.ts
index 18123ae..82df54b 100644
--- a/middleware/editor.global.ts
+++ b/middleware/editor.global.ts
@@ -3,11 +3,11 @@ import { useSessionStore } from "@/stores/session";
export default defineNuxtRouteMiddleware((to, from) => {
const session = useSessionStore();
- if (to.fullPath === '/' && session.getSessionType !== 'none') {
+ if (to.fullPath === '/' && session.getSessionType() !== 'none') {
return navigateTo('/editor');
}
- if (to.fullPath.startsWith('/editor') && session.getSessionType === 'none') {
+ if (to.fullPath.startsWith('/editor') && session.getSessionType() === 'none') {
return navigateTo('/');
}
});
diff --git a/pages/import.vue b/pages/import.vue
new file mode 100644
index 0000000..31d344d
--- /dev/null
+++ b/pages/import.vue
@@ -0,0 +1,143 @@
+<script setup lang="ts">
+import LoaderDiscardSessionModal from '~/components/loader/LoaderDiscardSessionModal.vue';
+
+definePageMeta({
+ layout: 'default'
+})
+
+const session = useSessionStore();
+
+const { canUseFsApi } = getBrowserCapabilities();
+const sessionType = computed(() => session.getSessionType());
+
+const discardSessionModal = ref<InstanceType<typeof LoaderDiscardSessionModal> | null>(null);
+</script>
+
+<template>
+ <div id="welcome-container">
+ <div id="welcome">
+ <b id="title">Import quest data</b>
+ <p>Use one of the options below to load quest configuration data.</p>
+ <div id="import-options">
+ <div class="row-container import-row">
+ <div id="description">
+ <p id="subtitle">Load from File System</p>
+ <p>Select the Quests plugin data directory to load data from.</p>
+ <p class="error" v-if="!canUseFsApi">
+ <font-awesome-icon :icon="['fas', 'xmark']" />
+ Your browser is not capable of using this mode.
+ </p>
+ </div>
+
+ <div id="button-group">
+ <LoaderFileSystemButton />
+ </div>
+ </div>
+ <div class="row-container import-row">
+ <div id="description">
+ <p id="subtitle">Retrieve from In-Game</p>
+ <p>Download quest data uploaded from in-game.</p>
+ </div>
+
+ <div id="button-group">
+ <LoaderNetworkButton />
+ </div>
+ </div>
+ <div class="row-container import-row">
+ <div id="description">
+ <p id="subtitle">Load Test Data</p>
+ <p>Get familiar with the Quests Web Editor by using test data.</p>
+ </div>
+
+ <div id="button-group">
+ <LoaderTestDataButton />
+ </div>
+ </div>
+ <div class="row-container" v-if="sessionType !== 'none'">
+ <div id="description">
+ <p>You are currently in a session.</p>
+ <p>Session type: {{ sessionType }}</p>
+ </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" />
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <LoaderDiscardSessionModal ref="discardSessionModal" />
+</template>
+
+<style lang="scss" scoped>
+#welcome-container {
+ display: flex;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+}
+
+#import-options {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+}
+
+.row-container {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+ padding: 1rem 0;
+
+ #button-group {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ }
+}
+
+.import-row {
+ border-bottom: 1px solid var(--color-border-soft);
+}
+
+.import-row:first-child {
+ border-top: 1px solid var(--color-border-soft);
+}
+
+.error {
+ color: var(--color-false);
+}
+
+#welcome {
+ display: flex;
+ flex-direction: column;
+ margin: 3rem 0;
+ gap: 1.5rem;
+ align-items: flex-start;
+ justify-content: flex-start;
+ max-width: 600px;
+ width: 100%;
+
+ #title {
+ font-weight: bold;
+ font-size: 1.5rem;
+ }
+
+ #subtitle {
+ font-weight: bold;
+ font-size: 1.1rem;
+ }
+
+ b {
+ font-weight: bold;
+ }
+}
+
+hr {
+ width: 100%;
+}
+</style> \ No newline at end of file
diff --git a/stores/session.ts b/stores/session.ts
index a0781bc..876b6b0 100644
--- a/stores/session.ts
+++ b/stores/session.ts
@@ -108,8 +108,8 @@ export const useSessionStore = defineStore('session', {
}
}),
getters: {
- getSessionType(): string {
- return this.sessionType
+ getSessionType: (state) => () => {
+ return state.sessionType
},
getQuests(): EditorQuest[] {
return this.session.quests