diff --git a/ci.sh b/ci.sh index 5c97c09..d83add2 100755 --- a/ci.sh +++ b/ci.sh @@ -3,10 +3,12 @@ set -euxo pipefail # Install build dependencies +rustup update +rustup default stable rustup target add wasm32-unknown-unknown # Emit versions -rustup show active-toolchain +rustup show npm version # Install project dependencies diff --git a/studio-frontend/src/app/app.element.ts b/studio-frontend/src/app/app.element.ts index 622c554..e1ce04e 100644 --- a/studio-frontend/src/app/app.element.ts +++ b/studio-frontend/src/app/app.element.ts @@ -1,12 +1,17 @@ import { on } from "@storyteller/framework"; import * as studio from "@storyteller/studio"; import { + type EntitySelectEvent, type SceneSavedEvent, type SceneStateEvent, SceneState, StudioMode, } from "@storyteller/studio"; -import { StudioURLParams } from "@storyteller/studio-web"; +import { + SceneHierarchyElement, + type SceneObject, + StudioURLParams, +} from "@storyteller/studio-web"; import { CanvasProvider } from "@storyteller/studio-web/canvas-provider"; import { match } from "@storyteller/utility"; import { LitElement, html, nothing } from "lit"; @@ -33,6 +38,9 @@ export class AppElement extends LitElement { @state() showHelp = false; @state() loading = true; + @state() selection?: SceneObject; + + #hierarchy = createRef(); #params = new StudioURLParams(); #canvasProvider: Ref = createRef(); @@ -79,6 +87,15 @@ export class AppElement extends LitElement { }); } + @on("entity-select") + onEntitySelected({ detail: id }: EntitySelectEvent): void { + if (!id) { + this.selection = undefined; + } else { + this.selection = this.#hierarchy.value?.entityMap.get(id); + } + } + toggleHelp(): void { this.showHelp = !this.showHelp; } @@ -122,9 +139,16 @@ export class AppElement extends LitElement { ${this.#params.mode === StudioMode.Editor ? html` - - - + + + ` : nothing} diff --git a/studio-ui/src/lib/button.element.scss b/studio-ui/src/lib/button.element.scss index 2939af9..a171b45 100644 --- a/studio-ui/src/lib/button.element.scss +++ b/studio-ui/src/lib/button.element.scss @@ -31,6 +31,12 @@ color: #FFFF; } +:host(.disabled), +:host(.disabled:hover) { + background: #0003; + color: #FFF6; +} + .icon { fill: currentColor; } diff --git a/studio-ui/src/lib/button.element.ts b/studio-ui/src/lib/button.element.ts index a50ec94..73d6f5b 100644 --- a/studio-ui/src/lib/button.element.ts +++ b/studio-ui/src/lib/button.element.ts @@ -1,5 +1,5 @@ import { on } from "@storyteller/framework"; -import { LitElement, html, nothing, unsafeCSS } from "lit"; +import { LitElement, type PropertyValues, html, nothing, unsafeCSS } from "lit"; import { customElement, property } from "lit/decorators.js"; import styles from "./button.element.scss?inline"; @@ -11,10 +11,21 @@ export class ButtonElement extends LitElement { static override styles = unsafeCSS(styles); @property() icon?: string; + @property({ type: Boolean }) disabled = false; override role = "button"; override tabIndex = 0; + protected override willUpdate(changes: PropertyValues): void { + if (changes.has("disabled")) { + this.ariaDisabled = this.disabled ? "true" : null; + this.tabIndex = this.disabled ? -1 : 0; + this.classList.toggle("disabled", this.disabled); + } + + super.willUpdate(changes); + } + @on("keydown") onKeyDown(event: KeyboardEvent) { if (/^( |Enter)$/.test(event.key)) { diff --git a/studio-web/src/lib/scene-hierarchy.element.ts b/studio-web/src/lib/scene-hierarchy.element.ts index 7b14c1a..5d06e05 100644 --- a/studio-web/src/lib/scene-hierarchy.element.ts +++ b/studio-web/src/lib/scene-hierarchy.element.ts @@ -14,7 +14,7 @@ import styles from "./scene-hierarchy.element.scss?inline"; import "@storyteller/studio-ui/tree"; -interface SceneObject extends Omit { +export interface SceneObject extends Omit { icon?: string; children: SceneObject[]; } diff --git a/studio/src/inspector/wasm.rs b/studio/src/inspector/wasm.rs index 286619a..062a56b 100644 --- a/studio/src/inspector/wasm.rs +++ b/studio/src/inspector/wasm.rs @@ -131,6 +131,7 @@ pub(super) fn notify_entity_spawn_changes( mut l_missing_parents: Local>, q_window: Query<&Window, With>, q_inspectables: Query<(Entity, &SceneElement)>, + q_element_changes: Query>, q_others: Query>, q_names: Query<&Name>, q_parents: Query<&Children>, @@ -146,6 +147,7 @@ pub(super) fn notify_entity_spawn_changes( ent, type_, &q_inspectables, + &q_element_changes, &q_names, &q_parents, &q_children, @@ -166,6 +168,7 @@ pub(super) fn notify_entity_spawn_changes( ent, SceneElement::Generic, &q_inspectables, + &q_element_changes, &q_names, &q_parents, &q_children, @@ -204,11 +207,12 @@ fn build_scene_object( ent: Entity, type_: SceneElement, q_inspectables: &Query<(Entity, &SceneElement)>, + q_element_changes: &Query>, q_names: &Query<&Name>, q_parents: &Query<&Children>, q_children: &Query<&Parent>, ) -> Option { - if notified.contains(&ent) { + if notified.contains(&ent) && !q_element_changes.contains(ent) { return None; } diff --git a/studio/src/scene.rs b/studio/src/scene.rs index 9cd07df..c3665e8 100644 --- a/studio/src/scene.rs +++ b/studio/src/scene.rs @@ -233,13 +233,13 @@ pub struct ImportSceneEvent(pub String); derive(Serialize_repr, Deserialize_repr) )] #[derive(Component, Clone, Copy, Debug, PartialEq, Eq)] +#[allow(dead_code)] // Some variants only used in `wasm`, some planned for later use pub enum SceneElement { Generic, Mesh, Skeleton, Bone, Light, - #[allow(dead_code)] // TODO: Will be used for camera animation Camera, } @@ -395,17 +395,8 @@ fn tag_scene_elements( mesh_entities: Query>>, ) { for (e, children) in q_named_non_primitives.iter() { - let mut has_mesh = false; - for child in children { - if mesh_entities.contains(*child) { - has_mesh = true; - break; - } - } - if has_mesh { + if children.iter().any(|child| mesh_entities.contains(*child)) { cmd.entity(e).insert(SceneElement::Mesh); - } else { - cmd.entity(e).insert(SceneElement::Generic); } } }