aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/base/Modal.vue6
-rw-r--r--components/export/ExportButton.vue15
-rw-r--r--components/export/ExportModal.vue173
-rw-r--r--components/header/SiteHeader.vue10
-rw-r--r--components/loader/LoaderImportButton.vue7
5 files changed, 208 insertions, 3 deletions
diff --git a/components/base/Modal.vue b/components/base/Modal.vue
index f7b6df3..f3a32d0 100644
--- a/components/base/Modal.vue
+++ b/components/base/Modal.vue
@@ -62,7 +62,11 @@ const model = defineModel();
}
.header {
- border-bottom: 1px solid var(--color-border);
margin-bottom: 1rem;
}
+
+:deep(.header) h2 {
+ font-weight: 600;
+ border-bottom: none;
+}
</style> \ No newline at end of file
diff --git a/components/export/ExportButton.vue b/components/export/ExportButton.vue
new file mode 100644
index 0000000..51c4b0a
--- /dev/null
+++ b/components/export/ExportButton.vue
@@ -0,0 +1,15 @@
+<script setup lang="ts">
+import type ExportModal from './ExportModal.vue';
+
+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" />
+
+ <ExportModal ref="exportModal" />
+</template> \ No newline at end of file
diff --git a/components/export/ExportModal.vue b/components/export/ExportModal.vue
new file mode 100644
index 0000000..8bc6936
--- /dev/null
+++ b/components/export/ExportModal.vue
@@ -0,0 +1,173 @@
+<script setup lang="ts">
+const session = useSessionStore();
+
+const showModal = ref(false);
+
+const open = () => {
+ showModal.value = true;
+}
+
+const { canUseFsApi } = getBrowserCapabilities();
+const isUsingFsMode = computed(() => session.getSessionType() === 'filesystem');
+
+defineExpose({
+ open
+})
+</script>
+
+<template>
+ <Modal v-model="showModal">
+ <template v-slot:header>
+ <h2>Export quest configuration</h2>
+ </template>
+
+ <div id="export">
+ <p>Use one of the options below to export quest configuration data.</p>
+
+ <div id="export-options">
+ <div class="row-container export-row">
+ <div id="icon">
+ <font-awesome-icon :icon="['fas', 'hard-drive']" />
+ </div>
+
+ <div id="description">
+ <p id="subtitle">Write to File System</p>
+ <p>Write directly to the Quests data directory you opened.</p>
+ <p class="error" v-if="!canUseFsApi">
+ <font-awesome-icon :icon="['fas', 'xmark']" />
+ Your browser is not capable of using this mode.
+ </p>
+ <p class="error" v-if="canUseFsApi && !isUsingFsMode">
+ <font-awesome-icon :icon="['fas', 'xmark']" />
+ You did not start this session by importing from file system.
+ </p>
+ </div>
+
+ <div id="button-group">
+ <Button type="solid" label="Continue" :disabled="true" />
+ </div>
+ </div>
+ <div class="row-container export-row">
+ <div id="icon">
+ <font-awesome-icon :icon="['fas', 'upload']" />
+ </div>
+
+ <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>
+ </div>
+
+ <div id="button-group">
+ <Button type="solid" label="Continue" :disabled="true" />
+ </div>
+ </div>
+ <div class="row-container export-row">
+ <div id="icon">
+ <font-awesome-icon :icon="['fas', 'file-zipper']" />
+ </div>
+
+ <div id="description">
+ <p id="subtitle">Download as ZIP</p>
+ <p>Download your quest configuration as a ZIP file.</p>
+ </div>
+
+ <div id="button-group">
+ <Button type="solid" label="Continue" :disabled="true" />
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div id="controls" class="control-group">
+ <Button :icon="['fas', 'xmark']" :label="'Cancel'" @click="showModal = false"></Button>
+ </div>
+ </Modal>
+</template>
+
+<style scoped>
+#export-container {
+ display: flex;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+}
+
+#export-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;
+ gap: 0.5rem;
+
+ #icon {
+ flex-basis: 3rem;
+ flex-shrink: 0;
+ font-size: 2rem;
+ color: var(--color-text-mute);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ #description {
+ flex-grow: 1;
+ }
+
+ #button-group {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ }
+}
+
+.export-row {
+ border-bottom: 1px solid var(--color-border-soft);
+}
+
+.export-row:first-child {
+ border-top: 1px solid var(--color-border-soft);
+}
+
+.error {
+ color: var(--color-false);
+}
+
+#export {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
+
+#title {
+ font-weight: bold;
+ font-size: 1.5rem;
+}
+
+#subtitle {
+ font-weight: bold;
+ font-size: 1.1rem;
+}
+
+b {
+ font-weight: bold;
+}
+
+hr {
+ width: 100%;
+}
+
+#controls {
+ display: flex;
+ justify-content: flex-end;
+ margin-top: 1rem;
+}
+</style> \ No newline at end of file
diff --git a/components/header/SiteHeader.vue b/components/header/SiteHeader.vue
index afd85b8..22ee209 100644
--- a/components/header/SiteHeader.vue
+++ b/components/header/SiteHeader.vue
@@ -1,7 +1,11 @@
<script setup land="ts">
+const session = useSessionStore();
+
const navigateHome = () => {
navigateTo('/');
}
+
+const sessionType = computed(() => session.getSessionType());
</script>
<template>
@@ -14,8 +18,12 @@ const navigateHome = () => {
<code>Preview</code>
</div>
- <div id="controls">
+ <div id="controls" v-if="sessionType === 'none'">
+ <LoaderImportButton :isPrimaryAction="true" />
+ </div>
+ <div id="controls" v-if="sessionType !== 'none'">
<LoaderImportButton />
+ <ExportButton />
</div>
</header>
</template>
diff --git a/components/loader/LoaderImportButton.vue b/components/loader/LoaderImportButton.vue
index 48bcb8d..ff6d0ad 100644
--- a/components/loader/LoaderImportButton.vue
+++ b/components/loader/LoaderImportButton.vue
@@ -1,9 +1,14 @@
<script setup lang="ts">
+defineProps({
+ isPrimaryAction: Boolean
+})
+
const navigateToImport = async () => {
navigateTo('/import');
}
</script>
<template>
- <Button type="solid" :icon="['fas', 'file-import']" label="Import" @click="navigateToImport" />
+ <Button :type="isPrimaryAction ? 'solid' : 'text'" :icon="['fas', 'file-import']" label="Import"
+ @click="navigateToImport" />
</template> \ No newline at end of file