diff options
Diffstat (limited to 'src/components')
| -rw-r--r-- | src/components/Control/Modal.vue | 67 | ||||
| -rw-r--r-- | src/components/Editor/EditorPane.vue | 27 | ||||
| -rw-r--r-- | src/components/Editor/Quest/Modal/DeleteQuestModal.vue | 42 | ||||
| -rw-r--r-- | src/components/Editor/Quest/Modal/RenameQuestModal.vue | 59 | ||||
| -rw-r--r-- | src/components/Editor/Quest/QuestOptionsPanel.vue | 20 | ||||
| -rw-r--r-- | src/components/Editor/Quest/Task/Modal/ChangeTaskModal.vue | 59 | ||||
| -rw-r--r-- | src/components/Editor/Quest/Task/TaskConfiguration.vue | 18 |
7 files changed, 267 insertions, 25 deletions
diff --git a/src/components/Control/Modal.vue b/src/components/Control/Modal.vue new file mode 100644 index 0000000..d47d281 --- /dev/null +++ b/src/components/Control/Modal.vue @@ -0,0 +1,67 @@ +<script setup lang="ts"> +const model = defineModel(); + +</script> + +<template> + <div id="modal" class="modal" :class="{ 'is-active': model }"> + <div class="modal-background" @click="model = false"></div> + <div class="modal-content"> + <div class="header" v-if="$slots.header"> + <slot name="header" /> + </div> + <slot name="body" /> + <slot /> + </div> + </div> +</template> + +<style scoped> +#modal { + align-items: center; + justify-content: center; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1000; + background-color: rgba(0, 0, 0, 0.5); + transition: opacity 0.3s; + display: none; +} + +.modal-content { + background-color: var(--color-background); + border: 1px solid var(--color-border); + padding: 1rem; + width: 100%; + max-width: 600px; + max-height: 80%; + overflow-y: auto; + border-radius: 4px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); +} + +.modal-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + z-index: -1; +} + +.is-active { + opacity: 1 !important; + pointer-events: all !important; + display: flex !important; +} + +.header { + border-bottom: 1px solid var(--color-border); + margin-bottom: 1rem; +} + +</style>
\ No newline at end of file diff --git a/src/components/Editor/EditorPane.vue b/src/components/Editor/EditorPane.vue index 6245e56..22458cb 100644 --- a/src/components/Editor/EditorPane.vue +++ b/src/components/Editor/EditorPane.vue @@ -1,12 +1,14 @@ <script setup lang="ts"> import { useSessionStore } from '@/stores/session'; -import { computed } from 'vue'; +import { computed, ref } from 'vue'; import { stripColourCodes } from '@/lib/util'; import QuestOptionsPanel from '@/components/Editor/Quest/QuestOptionsPanel.vue'; import QuestTasksOptionsPanel from '@/components/Editor/Quest/QuestTasksOptionsPanel.vue'; import CategoryOptionsPanel from '@/components/Editor/Category/CategoryOptionsPanel.vue'; import CategoryChildrenOptionsPanel from '@/components/Editor/Category/CategoryChildrenOptionsPanel.vue'; import Button from '@/components/Control/Button.vue'; +import DeleteQuestModal from '@/components/Editor/Quest/Modal/DeleteQuestModal.vue'; +import RenameQuestModal from '@/components/Editor/Quest/Modal/RenameQuestModal.vue'; const sessionStore = useSessionStore(); @@ -30,6 +32,9 @@ const categoryFromSelectedQuest = computed(() => { return null; } }); + +const showDeleteModal = ref(false); +const showRenameModal = ref(false); </script> <template> @@ -55,7 +60,7 @@ const categoryFromSelectedQuest = computed(() => { <code>({{ selectedId }})</code> </template> </span> - <span id="controls"> + <span id="controls" class="control-group"> <Button v-if="selectedType === 'Quest'" :icon="['fas', 'fa-code']" @@ -64,10 +69,12 @@ const categoryFromSelectedQuest = computed(() => { <Button :icon="['fas', 'fa-pen']" :label="'Rename'" + @click="showRenameModal = true" ></Button> <Button :icon="['fas', 'fa-trash']" :label="'Delete'" + @click="showDeleteModal = true" ></Button> </span> </div> @@ -80,6 +87,17 @@ const categoryFromSelectedQuest = computed(() => { <CategoryChildrenOptionsPanel v-if="selectedType === 'Category'" :categoryId="selectedId" /> </div> </div> + + <DeleteQuestModal + v-if="selectedType === 'Quest'" + v-model="showDeleteModal" + :questId="selectedId" + /> + <RenameQuestModal + v-if="selectedType === 'Quest'" + v-model="showRenameModal" + :questId="selectedId" + /> </template> <style scoped> @@ -119,11 +137,6 @@ const categoryFromSelectedQuest = computed(() => { color: var(--color-text-mute); } } - - #controls { - display: flex; - gap: 1rem; - } } .none-selected { diff --git a/src/components/Editor/Quest/Modal/DeleteQuestModal.vue b/src/components/Editor/Quest/Modal/DeleteQuestModal.vue new file mode 100644 index 0000000..d0b0c5a --- /dev/null +++ b/src/components/Editor/Quest/Modal/DeleteQuestModal.vue @@ -0,0 +1,42 @@ +<script setup lang="ts"> +import Modal from '@/components/Control/Modal.vue'; +import Button from '@/components/Control/Button.vue'; + +const model = defineModel(); + +const emit = defineEmits(['delete']); + +defineProps({ + questId: String, +}); +</script> + +<template> + <Modal v-model="model"> + <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> + <div id="confirm" class="control-group"> + <Button + :icon="['fas', 'fa-times']" + :label="'Cancel'" + @click="model = false" + ></Button> + <Button + type="solid" + :icon="['fas', 'fa-trash']" + :label="'Delete'" + @click="emit('delete')" + ></Button> + </div> + </Modal> +</template> + +<style scoped> +#confirm { + display: flex; + justify-content: flex-end; + margin-top: 1rem; +} +</style>
\ No newline at end of file diff --git a/src/components/Editor/Quest/Modal/RenameQuestModal.vue b/src/components/Editor/Quest/Modal/RenameQuestModal.vue new file mode 100644 index 0000000..5b1e0ed --- /dev/null +++ b/src/components/Editor/Quest/Modal/RenameQuestModal.vue @@ -0,0 +1,59 @@ +<script setup lang="ts"> +import Modal from '@/components/Control/Modal.vue'; +import Button from '@/components/Control/Button.vue'; +import { ref } from 'vue'; + +const model = defineModel(); + +const emit = defineEmits(['update']); + +const props = defineProps({ + questId: String, +}); + +const newQuestId = ref(props.questId); +</script> + +<template> + <Modal v-model="model"> + <template v-slot:header> + <h2>Rename quest '{{ questId }}'</h2> + </template> + + <template v-slot:body> + <div id="body"> + <div class="option-group"> + <label for="new-type">New quest ID</label> + <input id="new-type" name="new-type" type="text" v-model="newQuestId" /> + </div> + <p>A Quest ID must be unique, alphanumeric, and not contain any spaces.</p> + <div id="confirm" class="control-group"> + <Button + :icon="['fas', 'fa-times']" + :label="'Cancel'" + @click="model = false" + ></Button> + <Button + type="solid" + :icon="['fas', 'fa-check']" + :label="'Rename'" + @click="emit('update', newQuestId)" + ></Button> + </div> + </div> + </template> + </Modal> +</template> + +<style scoped> +#confirm { + display: flex; + justify-content: flex-end; +} + +#body { + display: flex; + flex-direction: column; + gap: 0.5rem; +} +</style>
\ No newline at end of file diff --git a/src/components/Editor/Quest/QuestOptionsPanel.vue b/src/components/Editor/Quest/QuestOptionsPanel.vue index 3495d60..3c1e599 100644 --- a/src/components/Editor/Quest/QuestOptionsPanel.vue +++ b/src/components/Editor/Quest/QuestOptionsPanel.vue @@ -1,8 +1,9 @@ <script setup lang="ts"> import { useSessionStore, type EditorQuest } from '@/stores/session'; -import { computed } from 'vue'; +import { computed, ref } from 'vue'; import EditorOptionsPanel from '@/components/Editor/EditorOptionsPanel.vue'; import Checkbox from '@/components/Control/Checkbox.vue'; +import DeleteQuestModal from '@/components/Editor/Quest/Modal/DeleteQuestModal.vue'; const props = defineProps<{ questId: string; @@ -19,6 +20,8 @@ const knownCategories = computed(() => { const knownQuests = computed(() => { return sessionStore.session.quests.map((quest) => quest.id); }); + +const showDeleteModal = ref(false); </script> <template> @@ -121,6 +124,11 @@ const knownQuests = computed(() => { </div> </div> </EditorOptionsPanel> + + <DeleteQuestModal + v-model="showDeleteModal" + :questId="props.questId" + /> </template> <style src="vue-multiselect/dist/vue-multiselect.css" /> @@ -132,20 +140,10 @@ const knownQuests = computed(() => { gap: 1rem; } -.option-group { - display: flex; - flex-direction: column; - gap: 0.5rem; -} - .description { font-size: 0.8em; } -label { - font-weight: 700; -} - h2 { border-bottom: 1px solid var(--color-border); } diff --git a/src/components/Editor/Quest/Task/Modal/ChangeTaskModal.vue b/src/components/Editor/Quest/Task/Modal/ChangeTaskModal.vue new file mode 100644 index 0000000..f8ffef7 --- /dev/null +++ b/src/components/Editor/Quest/Task/Modal/ChangeTaskModal.vue @@ -0,0 +1,59 @@ +<script setup lang="ts"> +import Modal from '@/components/Control/Modal.vue'; +import Button from '@/components/Control/Button.vue'; +import { ref } from 'vue'; + +const model = defineModel(); + +const emit = defineEmits(['update']); + +defineProps({ + taskId: String, +}); + +const newType = ref(''); +</script> + +<template> + <Modal v-model="model"> + <template v-slot:header> + <h2>Change the task type of '{{ taskId }}'</h2> + </template> + + <template v-slot:body> + <div id="body"> + <div class="option-group"> + <label for="new-type">New type</label> + <input id="new-type" name="new-type" type="text" v-model="newType" /> + </div> + <p>Any configured options for this task will be overwritten.</p> + <div id="confirm" class="control-group"> + <Button + :icon="['fas', 'fa-times']" + :label="'Cancel'" + @click="model = false" + ></Button> + <Button + type="solid" + :icon="['fas', 'fa-check']" + :label="'Change'" + @click="emit('update', newType)" + ></Button> + </div> + </div> + </template> + </Modal> +</template> + +<style scoped> +#confirm { + display: flex; + justify-content: flex-end; +} + +#body { + display: flex; + flex-direction: column; + gap: 0.5rem; +} +</style>
\ No newline at end of file diff --git a/src/components/Editor/Quest/Task/TaskConfiguration.vue b/src/components/Editor/Quest/Task/TaskConfiguration.vue index c31a87d..7006f18 100644 --- a/src/components/Editor/Quest/Task/TaskConfiguration.vue +++ b/src/components/Editor/Quest/Task/TaskConfiguration.vue @@ -1,8 +1,9 @@ <script setup lang="ts"> import { useSessionStore, type EditorQuest } from '@/stores/session'; -import { computed } from 'vue'; +import { computed, ref } from 'vue'; import Button from '@/components/Control/Button.vue'; import TaskConfigurationRow from '@/components/Editor/Quest/Task/TaskConfigurationRow.vue'; +import ChangeTaskModal from './Modal/ChangeTaskModal.vue'; const props = defineProps<{ taskId: string; @@ -62,6 +63,8 @@ const deleteValue = (fieldName: string) => { delete sessionStore.getQuestById(props.quest.id)!.tasks[props.taskId].config[fieldName]; }; +const showChangeModal = ref(false); + </script> <template> @@ -75,10 +78,11 @@ const deleteValue = (fieldName: string) => { ({{ taskType }}) </code> </p> - <div id="task-controls"> + <div id="task-controls" class="control-group"> <Button :icon="['fas', 'fa-pen']" :label="'Change'" + @click="showChangeModal = true" ></Button> <Button :icon="['fas', 'fa-trash']" @@ -122,6 +126,11 @@ const deleteValue = (fieldName: string) => { </div> </div> </div> + + <ChangeTaskModal + v-model="showChangeModal" + :taskId="props.taskId" + /> </template> <style scoped> @@ -163,11 +172,6 @@ const deleteValue = (fieldName: string) => { color: var(--color-text-mute); } } - - #task-controls { - display: flex; - gap: 1rem; - } } } |
