diff options
| author | Leonardo Bishop <me@leonardobishop.com> | 2024-03-12 17:48:23 +0000 |
|---|---|---|
| committer | Leonardo Bishop <me@leonardobishop.com> | 2024-03-12 17:48:23 +0000 |
| commit | addf95bc7e1e694cd9ba7797c8b0847bfecaf54c (patch) | |
| tree | 422e96cb24eb3b3ec9d4c96de555b8fa14239c59 /components/editor/task/EditorTaskConfigurationRow.vue | |
| parent | 8664ad155c89d47affd94f8b0385ebf39841f1f8 (diff) | |
Add nuxt prefixes back to component file names
Diffstat (limited to 'components/editor/task/EditorTaskConfigurationRow.vue')
| -rw-r--r-- | components/editor/task/EditorTaskConfigurationRow.vue | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/components/editor/task/EditorTaskConfigurationRow.vue b/components/editor/task/EditorTaskConfigurationRow.vue new file mode 100644 index 0000000..666669d --- /dev/null +++ b/components/editor/task/EditorTaskConfigurationRow.vue @@ -0,0 +1,185 @@ +<script setup lang="ts"> +import { useSessionStore } from '@/stores/session'; +import { computed, ref, toRefs, watch } from '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', '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" class="configuration-multiselect" + :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" class="configuration-multiselect" + :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); +} +</style>
\ No newline at end of file |
