124 lines
3.3 KiB
Vue
124 lines
3.3 KiB
Vue
<template>
|
|
<div class="sidebar-form">
|
|
<template v-for="form of formFields">
|
|
<component
|
|
:is="form.component"
|
|
:name="form.name"
|
|
:label="form.label"
|
|
:value="form.value"
|
|
:type="form.type"
|
|
@update="(value: string) => propertyChanged(form.name, value)"
|
|
></component>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { GameObject } from '@freeblox/engine';
|
|
import type { Component } from 'vue';
|
|
import { computed } from 'vue';
|
|
import Field from '../form/Field.vue';
|
|
import { Color, Euler, Vector3 } from 'three';
|
|
import Vector3Field from '../form/Vector3Field.vue';
|
|
import Checkbox from '../form/Checkbox.vue';
|
|
import ColorPicker from '../form/ColorPicker.vue';
|
|
|
|
interface FormItem {
|
|
name: string;
|
|
label: string;
|
|
value: unknown;
|
|
type?: unknown;
|
|
component: Component;
|
|
}
|
|
|
|
const props = defineProps<{
|
|
selection: GameObject[];
|
|
}>();
|
|
|
|
const emit = defineEmits<{
|
|
(e: 'update', item: GameObject, property: string, value: string): void;
|
|
}>();
|
|
|
|
const propertyChanged = (property: string, value: string) => {
|
|
const object = props.selection[0];
|
|
emit('update', object, property, value);
|
|
};
|
|
|
|
function toCapitalizedWords(name: string) {
|
|
const words = name.match(/[A-Za-z][a-z]*/g) || [];
|
|
|
|
return words.map(capitalize).join(' ');
|
|
}
|
|
|
|
function capitalize(word: string) {
|
|
return word.charAt(0).toUpperCase() + word.substring(1);
|
|
}
|
|
|
|
const formFields = computed(() => {
|
|
// TODO: multi-edit
|
|
const object = props.selection[0];
|
|
if (!object) return [];
|
|
const fields: FormItem[] = [];
|
|
|
|
object.properties
|
|
.filter((item) => item.definition.exposed && item.definition.name)
|
|
.forEach((property) => {
|
|
if (
|
|
property.definition.type === String ||
|
|
property.definition.type === Number
|
|
) {
|
|
fields.push({
|
|
name: property.definition.name!,
|
|
label: toCapitalizedWords(property.definition.name!),
|
|
value: (object as unknown as Record<string, unknown>)[
|
|
property.definition.name!
|
|
],
|
|
type: property.definition.type === String ? 'string' : 'number',
|
|
component: Field,
|
|
});
|
|
}
|
|
|
|
if (
|
|
property.definition.type === Vector3 ||
|
|
property.definition.type === Euler
|
|
) {
|
|
fields.push({
|
|
name: property.definition.name!,
|
|
label: toCapitalizedWords(property.definition.name!),
|
|
value: (object as unknown as Record<string, unknown>)[
|
|
property.definition.name!
|
|
],
|
|
type: property.definition.type === Vector3 ? 'vector' : 'euler',
|
|
component: Vector3Field,
|
|
});
|
|
}
|
|
|
|
if (property.definition.type === Color) {
|
|
fields.push({
|
|
name: property.definition.name!,
|
|
label: toCapitalizedWords(property.definition.name!),
|
|
value: (object as unknown as Record<string, unknown>)[
|
|
property.definition.name!
|
|
],
|
|
component: ColorPicker,
|
|
});
|
|
}
|
|
|
|
if (property.definition.type === Boolean) {
|
|
fields.push({
|
|
name: property.definition.name!,
|
|
label: toCapitalizedWords(property.definition.name!),
|
|
value: (object as unknown as Record<string, unknown>)[
|
|
property.definition.name!
|
|
],
|
|
component: Checkbox,
|
|
});
|
|
}
|
|
});
|
|
|
|
return fields;
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss"></style>
|