mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-17 00:13:17 +00:00
Add Scalar input field
This commit is contained in:
@@ -6,6 +6,8 @@ import { v4 as uuid } from "uuid";
|
||||
|
||||
import { StandardMaterial, type Rgba } from "./inspector.types";
|
||||
|
||||
import "@storyteller/studio-ui/forms/scalar-field";
|
||||
|
||||
import styles from "./material-inspector.element.scss?inline";
|
||||
|
||||
@customElement("sts-material-inspector")
|
||||
@@ -47,15 +49,12 @@ export class MaterialInspectorElement extends LitElement {
|
||||
}
|
||||
|
||||
updateField(reflectPath: Exclude<keyof StandardMaterial, "base_color">) {
|
||||
return ({ detail }: CustomEvent<string>) => {
|
||||
const value = parseFloat(detail);
|
||||
if (Number.isFinite(value) && !Number.isNaN(value)) {
|
||||
studio.updateComponentField({
|
||||
component: "bevy_pbr::pbr_material::StandardMaterial",
|
||||
reflectPath,
|
||||
value,
|
||||
});
|
||||
}
|
||||
return ({ detail: value }: CustomEvent<number>) => {
|
||||
studio.updateComponentField({
|
||||
component: "bevy_pbr::pbr_material::StandardMaterial",
|
||||
reflectPath,
|
||||
value,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,32 +81,32 @@ export class MaterialInspectorElement extends LitElement {
|
||||
<label for=${this.#roughnessId}>
|
||||
Roughness
|
||||
</label>
|
||||
<sts-text-field
|
||||
<sts-scalar-field
|
||||
id=${this.#roughnessId}
|
||||
type="number"
|
||||
.value=${this.roughness.toString(10)}
|
||||
.min=${0} .max=${1}
|
||||
.value=${this.roughness}
|
||||
@value-change=${this.updateField("perceptual_roughness")}
|
||||
></sts-text-field>
|
||||
></sts-scalar-field>
|
||||
|
||||
<label for=${this.#metallicId}>
|
||||
Metallic
|
||||
</label>
|
||||
<sts-text-field
|
||||
<sts-scalar-field
|
||||
id=${this.#metallicId}
|
||||
type="number"
|
||||
.value=${this.metallic.toString(10)}
|
||||
.min=${0} .max=${1}
|
||||
.value=${this.metallic}
|
||||
@value-change=${this.updateField("metallic")}
|
||||
></sts-text-field>
|
||||
></sts-scalar-field>
|
||||
|
||||
<label for=${this.#reflectanceId}>
|
||||
Reflectance
|
||||
</label>
|
||||
<sts-text-field
|
||||
<sts-scalar-field
|
||||
id=${this.#reflectanceId}
|
||||
type="number"
|
||||
.value=${this.reflectance.toString(10)}
|
||||
.min=${0} .max=${1}
|
||||
.value=${this.reflectance}
|
||||
@value-change=${this.updateField("reflectance")}
|
||||
></sts-text-field>
|
||||
></sts-scalar-field>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -18,73 +18,25 @@ h4 {
|
||||
}
|
||||
|
||||
.fieldset {
|
||||
position: relative;
|
||||
padding-block-start: math.div(14, 16) + 0.333rem !important;
|
||||
|
||||
legend {
|
||||
position: absolute;
|
||||
inset-block-start: 0;
|
||||
}
|
||||
}
|
||||
|
||||
fieldset, .fieldset {
|
||||
display: flex;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
padding: 0 {
|
||||
block-start: math.div(14, 16) + 0.333rem !important;
|
||||
}
|
||||
margin: 0;
|
||||
gap: 0.25rem;
|
||||
border: none;
|
||||
|
||||
legend {
|
||||
position: absolute;
|
||||
inset-block-start: 0;
|
||||
margin-block-end: 0.333rem;
|
||||
color: #FFF9;
|
||||
font-size: math.div(14, 16) * 1rem;
|
||||
margin-block-end: 0.333rem;
|
||||
}
|
||||
|
||||
input {
|
||||
appearance: textfield;
|
||||
border-radius: 0.25rem;
|
||||
|
||||
background: #0004;
|
||||
border: 1px solid #FFF2;
|
||||
color: #FFFC;
|
||||
transition: {
|
||||
property: background-color, border-color, color;
|
||||
duration: 33.333ms;
|
||||
timing-function: linear;
|
||||
}
|
||||
|
||||
font: {
|
||||
family: "Fira Sans", sans-serif;
|
||||
size: math.div(15, 16) * 1rem;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: #FFF4;
|
||||
background: #0006;
|
||||
color: #FFFF;
|
||||
}
|
||||
|
||||
&::-webkit-outer-spin-button,
|
||||
&::-webkit-inner-spin-button {
|
||||
appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
sts-text-field::part(input) {
|
||||
flex: unset;
|
||||
width: 100%;
|
||||
|
||||
&::-webkit-outer-spin-button,
|
||||
&::-webkit-inner-spin-button {
|
||||
appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
input, sts-text-field {
|
||||
.input {
|
||||
padding: 0.5rem;
|
||||
width: math.div(1, 3) * 100%;
|
||||
border-left-width: 4px;
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import * as studio from "@storyteller/studio"
|
||||
import { LitElement, html, unsafeCSS } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { v4 as uuid } from "uuid";
|
||||
|
||||
import { type Quat, type Vec3 } from "./inspector.types";
|
||||
|
||||
import "@storyteller/studio-ui/forms/scalar-field";
|
||||
|
||||
import styles from "./transform-inspector.element.scss?inline";
|
||||
|
||||
@customElement("sts-transform-inspector")
|
||||
@@ -18,6 +22,10 @@ export class TransformInspectorElement extends LitElement {
|
||||
@property({ attribute: false })
|
||||
scale: Vec3 = { x: 1, y: 1, z: 1 };
|
||||
|
||||
#positionLabelId = uuid();
|
||||
#rotationLabelId = uuid();
|
||||
#scaleLabelId = uuid();
|
||||
|
||||
updateField(reflectPath: `${"translation"|"rotation"|"scale"}.${"x"|"y"|"z"}`) {
|
||||
return ({ detail }: CustomEvent<string>) => {
|
||||
const value = parseFloat(detail);
|
||||
@@ -33,61 +41,88 @@ export class TransformInspectorElement extends LitElement {
|
||||
|
||||
protected override render = () => html`
|
||||
<h4>Transform</h4>
|
||||
<div class="fieldset" role="group">
|
||||
<legend>Position</legend>
|
||||
<sts-text-field
|
||||
type="number"
|
||||
.value=${this.translation.x.toFixed(3)}
|
||||
<div
|
||||
class="fieldset"
|
||||
role="group"
|
||||
aria-labelledby=${this.#positionLabelId}
|
||||
>
|
||||
<legend id=${this.#positionLabelId}>
|
||||
Position
|
||||
</legend>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
aria-label="X"
|
||||
.value=${this.translation.x}
|
||||
@value-change=${this.updateField("translation.x")}
|
||||
></sts-text-field>
|
||||
<sts-text-field
|
||||
type="number"
|
||||
.value=${this.translation.y.toFixed(3)}
|
||||
></sts-scalar-field>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
aria-label="Y"
|
||||
.value=${this.translation.y}
|
||||
@value-change=${this.updateField("translation.y")}
|
||||
></sts-text-field>
|
||||
<sts-text-field
|
||||
type="number"
|
||||
.value=${this.translation.z.toFixed(3)}
|
||||
></sts-scalar-field>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
aria-label="Z"
|
||||
.value=${this.translation.z}
|
||||
@value-change=${this.updateField("translation.z")}
|
||||
></sts-text-field>
|
||||
></sts-scalar-field>
|
||||
</div>
|
||||
<div class="fieldset" role="group">
|
||||
<legend>Rotation</legend>
|
||||
<div
|
||||
class="fieldset"
|
||||
role="group"
|
||||
aria-labelledby=${this.#rotationLabelId}
|
||||
>
|
||||
<legend id=${this.#rotationLabelId}>
|
||||
Rotation
|
||||
</legend>
|
||||
<!-- TODO: This is not how quaternions work lol -->
|
||||
<sts-text-field
|
||||
type="number"
|
||||
.value=${this.rotation.x.toFixed(3)}
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
aria-label="X"
|
||||
.value=${this.rotation.x}
|
||||
@value-change=${this.updateField("rotation.x")}
|
||||
></sts-text-field>
|
||||
<sts-text-field
|
||||
type="number"
|
||||
.value=${this.rotation.y.toFixed(3)}
|
||||
></sts-scalar-field>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
aria-label="Y"
|
||||
.value=${this.rotation.y}
|
||||
@value-change=${this.updateField("rotation.y")}
|
||||
></sts-text-field>
|
||||
<sts-text-field
|
||||
type="number"
|
||||
.value=${this.rotation.z.toFixed(3)}
|
||||
></sts-scalar-field>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
aria-label="Z"
|
||||
.value=${this.rotation.z}
|
||||
@value-change=${this.updateField("rotation.z")}
|
||||
></sts-text-field>
|
||||
></sts-scalar-field>
|
||||
<!-- <input type="number" value=${this.rotation.w.toFixed(3)} /> -->
|
||||
</div>
|
||||
<div class="fieldset" role="group">
|
||||
<legend>Scale</legend>
|
||||
<sts-text-field
|
||||
type="number"
|
||||
.value=${this.scale.x.toFixed(3)}
|
||||
<div
|
||||
class="fieldset"
|
||||
role="group"
|
||||
aria-labelledby=${this.#scaleLabelId}
|
||||
>
|
||||
<legend id=${this.#scaleLabelId}>
|
||||
Scale
|
||||
</legend>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
aria-label="X"
|
||||
.value=${this.scale.x}
|
||||
@value-change=${this.updateField("scale.x")}
|
||||
></sts-text-field>
|
||||
<sts-text-field
|
||||
type="number"
|
||||
.value=${this.scale.y.toFixed(3)}
|
||||
></sts-scalar-field>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
aria-label="Y"
|
||||
.value=${this.scale.y}
|
||||
@value-change=${this.updateField("scale.y")}
|
||||
></sts-text-field>
|
||||
<sts-text-field
|
||||
type="number"
|
||||
.value=${this.scale.z.toFixed(3)}
|
||||
></sts-scalar-field>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
aria-label="Z"
|
||||
.value=${this.scale.z}
|
||||
@value-change=${this.updateField("scale.z")}
|
||||
></sts-text-field>
|
||||
></sts-scalar-field>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user