UI styling, main workspace layout (#119)

This commit is contained in:
Danny McGee
2024-04-05 20:15:09 -04:00
committed by GitHub
parent c5a0250d9f
commit bfc638b644
57 changed files with 2004 additions and 694 deletions
@@ -3,12 +3,9 @@
display: flex;
flex-direction: column;
gap: var(--padding);
gap: 1rem;
overflow: auto;
--background-color: var(--color-panel-background);
color: #FFFC;
color: #FFF;
&::-webkit-scrollbar {
width: 0.5rem;
@@ -32,13 +29,3 @@
*, *::before, *::after {
box-sizing: border-box;
}
.container {
background-color: var(--background-color);
border-radius: var(--corner-radius);
display: flex;
flex-direction: column;
justify-content: flex-end;
padding: var(--padding);
gap: var(--padding);
}
@@ -1,5 +1,5 @@
import { inject } from "@storyteller/framework";
import { LitElement, type PropertyValues, html, unsafeCSS, nothing } from "lit";
import { inject, observe } from "@storyteller/framework";
import { LitElement, html, unsafeCSS, nothing } from "lit";
import { customElement } from "lit/decorators.js";
import { SCENE_DATA_PROVIDER, type SceneDataProvider } from "../scene-data-provider.element";
@@ -16,89 +16,69 @@ import styles from "./entity-inspector.element.scss?inline";
export class EntityInspectorElement extends LitElement {
static override styles = unsafeCSS(styles);
@observe(["selectionComponents"])
@inject(SCENE_DATA_PROVIDER)
_sceneData?: SceneDataProvider;
_sceneData!: SceneDataProvider;
override connectedCallback(): void {
this._sceneData?.addEventListener("property-changes", this.onProviderChanges);
super.connectedCallback();
}
protected override render = () => html`
${this._sceneData
?.selectionComponents
.slice()
.sort((a, b) => {
const ordA = COMPONENT_SORT_ORDER.indexOf(a.name);
const ordB = COMPONENT_SORT_ORDER.indexOf(b.name);
override disconnectedCallback(): void {
this._sceneData?.removeEventListener("property-changes", this.onProviderChanges);
super.disconnectedCallback();
}
if (ordA === -1) return Infinity;
if (ordB === -1) return -Infinity;
onProviderChanges = ({ detail: changes }: CustomEvent<PropertyValues<SceneDataProvider>>) => {
if (changes.has("selectionComponents"))
this.requestUpdate();
}
return ordA - ordB;
})
.map(({ name, value }) => {
switch (name) {
// TODO?
// case "bevy_core::name::Name": {
// return html`
// <sts-name-inspector
// .value=${value.name}
// ></sts-name-inspector>
// `;
// }
case "bevy_transform::components::transform::Transform": {
return html`
<sts-transform-inspector
.translation=${value.translation}
.rotation=${value.rotation}
.scale=${value.scale}
></sts-transform-inspector>
`;
}
case "bevy_pbr::pbr_material::StandardMaterial": {
const { colorSpace, baseColor } = isLinear(value.base_color)
? { colorSpace: "linear", baseColor: value.base_color.RgbaLinear }
: { colorSpace: "srgb", baseColor: value.base_color.Rgba };
protected override render () {
let components = this._sceneData
?.selectionComponents
.slice()
.sort((a, b) => {
const ordA = COMPONENT_SORT_ORDER.indexOf(a.name);
const ordB = COMPONENT_SORT_ORDER.indexOf(b.name);
if (ordA === -1) return Infinity;
if (ordB === -1) return -Infinity;
return ordA - ordB;
})
.map(({ name, value }) => {
switch (name) {
case "bevy_core::name::Name": {
return html`
<sts-name-inspector
.value=${value.name}
></sts-name-inspector>
`;
return html`
<sts-material-inspector
.baseColor=${baseColor}
.colorSpace=${colorSpace}
.roughness=${value.perceptual_roughness}
.metallic=${value.metallic}
.reflectance=${value.reflectance}
></sts-material-inspector>
`;
}
default: {
return nothing;
// return html`
// <h3>Unknown Component: ${name}</h3>
// <pre>${JSON.stringify({ name, value }, null, " ")}</pre>
// `;
}
}
case "bevy_transform::components::transform::Transform": {
return html`
<sts-transform-inspector
.translation=${value.translation}
.rotation=${value.rotation}
.scale=${value.scale}
></sts-transform-inspector>
`;
}
case "bevy_pbr::pbr_material::StandardMaterial": {
const { colorSpace, baseColor } = isLinear(value.base_color)
? { colorSpace: "linear", baseColor: value.base_color.RgbaLinear }
: { colorSpace: "srgb", baseColor: value.base_color.Rgba };
return html`
<sts-material-inspector
.baseColor=${baseColor}
.colorSpace=${colorSpace}
.roughness=${value.perceptual_roughness}
.metallic=${value.metallic}
.reflectance=${value.reflectance}
></sts-material-inspector>
`;
}
default: {
return nothing;
// return html`
// <h3>Unknown Component: ${name}</h3>
// <pre>${JSON.stringify({ name, value }, null, " ")}</pre>
// `;
}
}
}).filter((value) => value !== nothing) || [];
if (components?.length === 0) {
return nothing;
})
?? nothing
}
return html`
<div class="container">
${components
}
</div>
`;
}
}
const COMPONENT_SORT_ORDER: Array<InspectorComponent["name"]> = [
@@ -11,7 +11,7 @@
h4 {
font-weight: 500;
margin: 0 0 1rem;
margin: 0 0 0.5rem;
}
.fields {
@@ -2,30 +2,41 @@
:host {
display: flex;
gap: 0.25rem;
gap: 0.5rem;
}
.field {
display: flex;
width: math.div(1, 3) * 100%;
border-radius: 0.5rem;
overflow: hidden;
outline: transparent 2px solid {
offset: -2px;
}
transition: outline-color 100ms linear;
&--x:focus-within { outline-color: var(--axis-red) }
&--y:focus-within { outline-color: var(--axis-green) }
&--z:focus-within { outline-color: var(--axis-blue) }
}
.label {
display: flex;
align-items: center;
padding: 0 0.375rem;
font: {
size: math.div(14, 16) * 1rem;
weight: 500;
}
&--x { background: var(--axis-red) }
&--y { background: var(--axis-green) }
&--z { background: var(--axis-blue) }
}
.input {
padding: 0.5rem;
width: math.div(1, 3) * 100%;
border-left-width: 4px;
&:nth-of-type(1) {
border-left-color: rgb(220, 53, 69);
&:focus {
border-left-color: rgb(255, 48, 68);
}
}
&:nth-of-type(2) {
border-left-color: rgb(25, 135, 84);
&:focus {
border-left-color: rgb(0, 187, 100);
}
}
&:nth-of-type(3) {
border-left-color: rgb(13, 110, 253);
&:focus {
border-left-color: rgb(47, 131, 255);
}
}
flex: 1 0 0;
border-radius: 0;
border: none;
outline: none !important;
}
@@ -46,36 +46,44 @@ export class QuatInspectorElement extends LitElement {
}
protected override render = (): TemplateResult => html`
<sts-scalar-field
class="input"
aria-label="X"
format="1.1-2 °"
emitOn="change"
.step=${1}
.microStep=${0.1}
.value=${this._eulerX}
@value-change=${this.#emitUpdate(RotationAxis.X)}
></sts-scalar-field>
<sts-scalar-field
class="input"
aria-label="Y"
format="1.1-2 °"
emitOn="change"
.step=${1}
.microStep=${0.1}
.value=${this._eulerY}
@value-change=${this.#emitUpdate(RotationAxis.Y)}
></sts-scalar-field>
<sts-scalar-field
class="input"
aria-label="Z"
format="1.1-2 °"
emitOn="change"
.step=${1}
.microStep=${0.1}
.value=${this._eulerZ}
@value-change=${this.#emitUpdate(RotationAxis.Z)}
></sts-scalar-field>
<label class="field field--x">
<span class="label label--x">X</span>
<sts-scalar-field
class="input"
format="1.2-2 °"
emitOn="change"
.step=${1}
.microStep=${0.1}
.value=${this._eulerX}
@value-change=${this.#emitUpdate(RotationAxis.X)}
></sts-scalar-field>
</label>
<label class="field field--y">
<span class="label label--y">Y</span>
<sts-scalar-field
class="input"
format="1.2-2 °"
emitOn="change"
.step=${1}
.microStep=${0.1}
.value=${this._eulerY}
@value-change=${this.#emitUpdate(RotationAxis.Y)}
></sts-scalar-field>
</label>
<label class="field field--z">
<span class="label label--z">Z</span>
<sts-scalar-field
class="input"
format="1.2-2 °"
emitOn="change"
.step=${1}
.microStep=${0.1}
.value=${this._eulerZ}
@value-change=${this.#emitUpdate(RotationAxis.Z)}
></sts-scalar-field>
</label>
`;
}
@@ -22,43 +22,57 @@ h4 {
position: relative;
width: 100%;
padding: 0 {
block-start: math.div(14, 16) + 0.333rem !important;
block-start: math.div(17, 16) + 0.25rem !important;
}
margin: 0;
gap: 0.25rem;
gap: 0.5rem;
border: none;
legend {
position: absolute;
inset-block-start: 0;
margin-block-end: 0.333rem;
color: #FFF9;
font-size: math.div(14, 16) * 1rem;
padding: 0;
color: #FFF;
font: {
size: math.div(14, 16) * 1rem;
weight: 600;
}
}
.field {
display: flex;
width: math.div(1, 3) * 100%;
border-radius: 0.5rem;
overflow: hidden;
outline: transparent 2px solid {
offset: -2px;
}
transition: outline-color 100ms linear;
&--x:focus-within { outline-color: var(--axis-red) }
&--y:focus-within { outline-color: var(--axis-green) }
&--z:focus-within { outline-color: var(--axis-blue) }
}
.label {
display: flex;
align-items: center;
padding: 0 0.375rem;
font: {
size: math.div(14, 16) * 1rem;
weight: 500;
}
&--x { background: var(--axis-red) }
&--y { background: var(--axis-green) }
&--z { background: var(--axis-blue) }
}
.input {
padding: 0.5rem;
width: math.div(1, 3) * 100%;
border-left-width: 4px;
&:nth-of-type(1) {
border-left-color: rgb(220, 53, 69);
&:focus {
border-left-color: rgb(255, 48, 68);
}
}
&:nth-of-type(2) {
border-left-color: rgb(25, 135, 84);
&:focus {
border-left-color: rgb(0, 187, 100);
}
}
&:nth-of-type(3) {
border-left-color: rgb(13, 110, 253);
&:focus {
border-left-color: rgb(47, 131, 255);
}
}
flex: 1 0 0;
border-radius: 0;
border: none;
outline: none !important;
}
}
@@ -39,7 +39,6 @@ export class TransformInspectorElement extends LitElement {
}
protected override render = () => html`
<h4>Transform</h4>
<div
class="fieldset"
role="group"
@@ -48,31 +47,44 @@ export class TransformInspectorElement extends LitElement {
<legend id=${this.#positionLabelId}>
Position
</legend>
<sts-scalar-field
class="input"
aria-label="X"
.step=${0.01}
.microStep=${0.001}
.value=${this.translation.x}
@value-change=${this.updateField("translation.x")}
></sts-scalar-field>
<sts-scalar-field
class="input"
aria-label="Y"
.step=${0.01}
.microStep=${0.001}
.value=${this.translation.y}
@value-change=${this.updateField("translation.y")}
></sts-scalar-field>
<sts-scalar-field
class="input"
aria-label="Z"
.step=${0.01}
.microStep=${0.001}
.value=${this.translation.z}
@value-change=${this.updateField("translation.z")}
></sts-scalar-field>
<label class="field field--x">
<span class="label label--x">X</span>
<sts-scalar-field
class="input"
format="1.3"
.step=${0.01}
.microStep=${0.001}
.value=${this.translation.x}
@value-change=${this.updateField("translation.x")}
></sts-scalar-field>
</label>
<label class="field field--y">
<span class="label label--y">Y</span>
<sts-scalar-field
class="input"
format="1.3"
.step=${0.01}
.microStep=${0.001}
.value=${this.translation.y}
@value-change=${this.updateField("translation.y")}
></sts-scalar-field>
</label>
<label class="field field--z">
<span class="label label--z">Z</span>
<sts-scalar-field
class="input"
format="1.3"
.step=${0.01}
.microStep=${0.001}
.value=${this.translation.z}
@value-change=${this.updateField("translation.z")}
></sts-scalar-field>
</label>
</div>
<div
class="fieldset"
role="group"
@@ -86,6 +98,7 @@ export class TransformInspectorElement extends LitElement {
@value-change=${this.updateField("rotation")}
></sts-quat-inspector>
</div>
<div
class="fieldset"
role="group"
@@ -94,30 +107,42 @@ export class TransformInspectorElement extends LitElement {
<legend id=${this.#scaleLabelId}>
Scale
</legend>
<sts-scalar-field
class="input"
aria-label="X"
.step=${0.1}
.microStep=${0.01}
.value=${this.scale.x}
@value-change=${this.updateField("scale.x")}
></sts-scalar-field>
<sts-scalar-field
class="input"
aria-label="Y"
.step=${0.1}
.microStep=${0.01}
.value=${this.scale.y}
@value-change=${this.updateField("scale.y")}
></sts-scalar-field>
<sts-scalar-field
class="input"
aria-label="Z"
.step=${0.1}
.microStep=${0.01}
.value=${this.scale.z}
@value-change=${this.updateField("scale.z")}
></sts-scalar-field>
<label class="field field--x">
<span class="label label--x">X</span>
<sts-scalar-field
class="input"
format="1.3"
.step=${0.1}
.microStep=${0.01}
.value=${this.scale.x}
@value-change=${this.updateField("scale.x")}
></sts-scalar-field>
</label>
<label class="field field--y">
<span class="label label--y">Y</span>
<sts-scalar-field
class="input"
format="1.3"
.step=${0.1}
.microStep=${0.01}
.value=${this.scale.y}
@value-change=${this.updateField("scale.y")}
></sts-scalar-field>
</label>
<label class="field field--z">
<span class="label label--z">Z</span>
<sts-scalar-field
class="input"
format="1.3"
.step=${0.1}
.microStep=${0.01}
.value=${this.scale.z}
@value-change=${this.updateField("scale.z")}
></sts-scalar-field>
</label>
</div>
`;
}