diff options
| author | Leonardo Bishop <me@leonardobishop.com> | 2024-03-13 17:35:05 +0000 |
|---|---|---|
| committer | Leonardo Bishop <me@leonardobishop.com> | 2024-03-13 17:35:05 +0000 |
| commit | ba28c0148cab26fcaf523e84731ffb7c416b3338 (patch) | |
| tree | a26135e7aa07f53c36292117eff84d0b22e6dd92 | |
| parent | 1d2fd8e82f4d2ccfa4cf9e434a05e43250162449 (diff) | |
Add import page
| -rw-r--r-- | assets/base.css | 4 | ||||
| -rw-r--r-- | components/base/Button.vue | 24 | ||||
| -rw-r--r-- | components/header/SiteHeader.vue | 3 | ||||
| -rw-r--r-- | components/loader/LoaderDiscardSessionModal.vue | 48 | ||||
| -rw-r--r-- | components/loader/LoaderFileSystemButton.vue | 2 | ||||
| -rw-r--r-- | components/loader/LoaderImportButton.vue | 9 | ||||
| -rw-r--r-- | components/loader/LoaderNetworkButton.vue | 8 | ||||
| -rw-r--r-- | components/loader/LoaderTestDataButton.vue | 2 | ||||
| -rw-r--r-- | middleware/editor.global.ts | 4 | ||||
| -rw-r--r-- | pages/import.vue | 143 | ||||
| -rw-r--r-- | stores/session.ts | 4 |
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 |
