diff options
| author | Leonardo Bishop <me@leonardobishop.com> | 2024-03-10 00:13:25 +0000 |
|---|---|---|
| committer | Leonardo Bishop <me@leonardobishop.com> | 2024-03-10 00:13:25 +0000 |
| commit | 9a11e0f4a38297006b89cc7bb2a60734111582e0 (patch) | |
| tree | 5ebddde79e67b659714b5dbdbfcea289f06a4ae5 /components/Editor/Quest/Task/TaskConfigurationRow.vue | |
| parent | 817478f3cf357fc09778d9dc3cf67a667e21f042 (diff) | |
Migrate to nuxt
Diffstat (limited to 'components/Editor/Quest/Task/TaskConfigurationRow.vue')
| -rw-r--r-- | components/Editor/Quest/Task/TaskConfigurationRow.vue | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/components/Editor/Quest/Task/TaskConfigurationRow.vue b/components/Editor/Quest/Task/TaskConfigurationRow.vue new file mode 100644 index 0000000..f68ce97 --- /dev/null +++ b/components/Editor/Quest/Task/TaskConfigurationRow.vue @@ -0,0 +1,195 @@ +<script setup lang="ts"> +import { useSessionStore } from '@/stores/session'; +import { computed, ref, toRefs, watch } from 'vue'; +import TrueFalseSwitch from '@/components/Control/TrueFalseSwitch.vue'; +import ItemStackPicker from '@/components/Control/ItemStackPicker.vue'; +import materials from '@/lib/materials'; + +const props = defineProps({ + taskType: { + type: String, + required: true, + }, + configKey: { + type: String, + required: true, + }, + initialValue: null, + type: String, + required: Boolean, +}); +const emit = defineEmits(['update', 'delete']); + +const sessionStore = useSessionStore(); + +const definition = computed(() => { + 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 + : '' + ))); + +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)); +const updateValue = (value: any) => { + currentValue.value = value; +}; + +watch(currentValue, () => { + emit('update', currentValue.value); +}); + +const addValue = (searchQuery: any) => { + currentValue.value.push(searchQuery); +}; + +</script> + +<template> + <div id="task-configuration-row"> + <div id="key"> + <div id="delete" @click="emit('delete')" v-if="!props.required" class="delete"> + <font-awesome-icon :icon="['fas', 'fa-xmark']" /> + </div> + <p id="name" @click="showDescription = !showDescription">{{ props.configKey }}</p> + </div> + <div id="value"> + <div id="value-container"> + <!-- Data type 'string' --> + <input v-if="props.type === 'string'" v-model="currentValue" /> + + <!-- Data type 'number' --> + <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" /> + + <!-- Data type 'material-list' --> + <multiselect v-else-if="props.type === 'material-list'" v-model="currentValue" + :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" :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" /> + + <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> + </div> + </div> + </div> + </div> +</template> + +<style scoped> +#task-configuration-row { + display: flex; + flex-direction: row; + transition: background-color 0.3s; + border-bottom: 1px solid var(--color-border); + + #key { + width: 25%; + background-color: var(--color-background); + display: flex; + flex-direction: row; + align-items: center; + user-select: none; + + #delete { + display: flex; + align-items: center; + justify-content: center; + width: 20px; + height: 100%; + cursor: pointer; + color: var(--color-text-mute); + border-right: 1px solid var(--color-border); + background-color: var(--color-background-soft); + transition: color 0.3s; + + &:hover { + color: var(--color-false); + } + } + + #name { + display: flex; + align-items: center; + font-size: 0.8rem; + padding: 0.5rem; + width: 100%; + height: 100%; + font-family: monospace; + cursor: pointer; + transition: background-color 0.3s; + + &:hover { + background-color: var(--color-hover); + } + } + } + + #value { + width: 75%; + background-color: var(--color-background); + border-left: 1px solid var(--color-border); + + #value-container { + display: flex; + flex-direction: column; + height: 100%; + } + } +} + +#task-configuration-row:hover { + background-color: var(--color-hover); +} + +#task-configuration-row-info { + padding: 0.25rem 0.5rem; + font-size: 0.8em; + background-color: var(--color-background); + border-top: 1px solid var(--color-border); +} + +input { + width: 100%; + padding: 0.5rem; + border-radius: 0; + border: none; + font-family: monospace; + font-size: 0.8rem; + height: 40px; +} + +.error { + color: var(--color-false); +} + +.multiselect::v-deep .multiselect__tags { + border: unset !important; + border-radius: 0px !important; +} + +.multiselect::v-deep .multiselect__select { + background: unset !important; +} +</style>
\ No newline at end of file |
