Fix layout and UI visibility for viewer mode (#125)

This commit is contained in:
Danny McGee
2024-04-05 23:32:03 -04:00
committed by GitHub
parent a6ad9cec34
commit 5cd98b4a35
8 changed files with 236 additions and 196 deletions
+11 -9
View File
@@ -6,15 +6,17 @@ $hierarchy-width: 290px;
--sidebar-width: 300px;
--timeline-height: min-content;
display: grid;
width: 100vw;
height: 100vh;
grid-template: {
areas:
"viewport sidebar"
"timeline timeline";
rows: minmax(0, 1fr) var(--timeline-height);
columns: minmax(0, 1fr) var(--sidebar-width);
&.editor-mode {
display: grid;
width: 100vw;
height: 100vh;
grid-template: {
areas:
"viewport sidebar"
"timeline timeline";
rows: minmax(0, 1fr) var(--timeline-height);
columns: minmax(0, 1fr) var(--sidebar-width);
}
}
.viewport { grid-area: viewport; }
+2
View File
@@ -145,6 +145,8 @@ export class AppElement extends LitElement {
class=${classMap({
"app-root": true,
"debug-mode": this.debugMode,
"viewer-mode": this.params.mode === StudioMode.Viewer,
"editor-mode": this.params.mode === StudioMode.Editor,
})}
>
<sts-iframe-messaging-bridge></sts-iframe-messaging-bridge>
-16
View File
@@ -1,19 +1,3 @@
:host {
padding: 20px 30px;
border-radius: 0.5rem;
font: {
family: "Fira Sans", sans-serif;
size: 15px;
weight: 400;
}
background: #0006;
backdrop-filter: blur(16px);
pointer-events: auto;
}
th {
text-align: start;
color: #FFFC;
+38 -25
View File
@@ -1,38 +1,51 @@
import { inject } from "@storyteller/framework";
import { StudioMode } from "@storyteller/studio";
import { STUDIO_PARAMS, type StudioParams } from "@storyteller/studio-web";
import { LitElement, html, unsafeCSS, nothing, HTMLTemplateResult } from "lit";
import { customElement } from "lit/decorators.js";
import { isDevEnvironment } from "./util";
import styles from "./help.element.scss?inline";
import { isDevEnvironment } from "./util";
@customElement("sts-help")
export class HelpElement extends LitElement {
static override styles = unsafeCSS(styles);
@inject(STUDIO_PARAMS)
_params!: StudioParams;
protected override render = () => html`
<table>
${section("Navigation", [
{ name: "Pan View", controls: "MMB" },
{ name: "Orbit around point", controls: "Alt + LMB" },
{ name: "Zoom", controls: ["Alt + RMB", "Scroll"]},
{ name: "Free fly", controls: "W, A, S, D, E, Q" },
{ name: "Free look", controls: ["RMB", "Shift"] },
])}
${section("Interaction", [
{ name: "Select", controls: "LMB" },
{ name: "Clear selection", controls: "Esc" },
{ name: "Focus selection", controls: "F" },
{ name: "Delete selection", controls: "Delete" },
])}
${section("Animation Timeline", [
{ name: "Pan", controls: ["MMB", "Scroll"] },
{ name: "Zoom", controls: "Ctrl + Scroll" },
])}
${isDevEnvironment()
? section("Developer", [
{ name: "Toggle debug info", controls: html`Ctrl + &grave;` }
])
: nothing}
</table>
<sts-dialog-base>
<sts-dialog-header icon="question">
Help
</sts-dialog-header>
<table>
${section("Navigation", [
{ name: "Pan View", controls: "MMB" },
{ name: "Orbit around point", controls: "Alt + LMB" },
{ name: "Zoom", controls: ["Alt + RMB", "Scroll"]},
{ name: "Free fly", controls: "W, A, S, D, E, Q" },
{ name: "Free look", controls: ["RMB", "Shift"] },
])}
${this._params.mode === StudioMode.Editor ? html`
${section("Interaction", [
{ name: "Select", controls: "LMB" },
{ name: "Clear selection", controls: "Esc" },
{ name: "Focus selection", controls: "F" },
{ name: "Delete selection", controls: "Delete" },
])}
${section("Animation Timeline", [
{ name: "Pan", controls: ["MMB", "Scroll"] },
{ name: "Zoom", controls: "Ctrl + Scroll" },
])}
${isDevEnvironment()
? section("Developer", [
{ name: "Toggle debug info", controls: html`Ctrl + &grave;` }
])
: nothing}
` : nothing}
</table>
</sts-dialog-base>
`;
}
+168 -143
View File
@@ -1,6 +1,6 @@
import { bind, inject, observe } from "@storyteller/framework";
import * as studio from "@storyteller/studio";
import { BlockingCommand, TransformSpace, TransformType } from "@storyteller/studio";
import { BlockingCommand, StudioMode, TransformSpace, TransformType } from "@storyteller/studio";
import {
SCENE_DATA_PROVIDER,
STUDIO_PARAMS,
@@ -25,6 +25,7 @@ import "@storyteller/studio-ui/toolbar";
import "./anim-timeline-controls.element";
import "./studio-viewport.element.scss";
import { match } from "@storyteller/utility";
@customElement("sts-studio-viewport")
export class StudioViewportElement extends LitElement {
@@ -51,6 +52,7 @@ export class StudioViewportElement extends LitElement {
#fileTriggerRef = createRef<ButtonElement>();
#mediaLibraryTriggerRef = createRef<ButtonElement>();
#helpDialogTriggerRef = createRef<ButtonElement>();
get #selectedObject() {
return this._sceneData.selectedObject;
@@ -80,156 +82,173 @@ export class StudioViewportElement extends LitElement {
.skyboxId=${this._params.skybox ?? "test_scene"}
.mode=${this._params.mode}
>
<div class="main-menu abs h-start v-start offset">
<sts-button
${ref(this.#fileTriggerRef)}
dropdown
icon="file"
>
File
</sts-button>
<sts-button
icon="question"
@click=${() => {
// TODO
}}
>
Help
</sts-button>
</div>
<sts-toolbar class="top-toolbar abs h-center v-start">
<sts-toolbar-group>
${match (this._params.mode, {
[StudioMode.Headless]: () => nothing,
[StudioMode.Viewer]: () => html`
<sts-button
${ref(this.#mediaLibraryTriggerRef)}
secondary
icon="plus-large"
title="Add asset from Media Library"
></sts-button>
</sts-toolbar-group>
<hr />
<sts-toolbar-group>
<sts-button
class="primitive"
icon="cube"
title="Cube"
@click=${() => studio.dispatchBlockingCommand(BlockingCommand.Cube)}
></sts-button>
<sts-button
class="primitive"
icon="cylinder"
title="Cylinder"
@click=${() => studio.dispatchBlockingCommand(BlockingCommand.Cylinder)}
></sts-button>
<sts-button
class="primitive"
icon="sphere"
title="Sphere"
@click=${() => studio.dispatchBlockingCommand(BlockingCommand.Sphere)}
></sts-button>
<sts-button
class="primitive"
icon="torus"
title="Torus"
@click=${() => studio.dispatchBlockingCommand(BlockingCommand.Torus)}
></sts-button>
</sts-toolbar-group>
<hr />
<sts-toolbar-group>
<sts-select class="transform-space"
title="Transform space"
.value=${bind(this, "_transformSpace")}
${ref(this.#helpDialogTriggerRef)}
class="abs h-start v-start offset"
icon="question"
@click=${() => {
// TODO
}}
>
<sts-option .value=${TransformSpace.Local}>
<sts-icon icon="xform-local"></sts-icon>
Local
</sts-option>
<sts-option .value=${TransformSpace.World}>
<sts-icon icon="globe"></sts-icon>
Global
</sts-option>
</sts-select>
<sts-radio-group
title="Transform type"
.value=${bind(this, "_transformType")}
>
<sts-radio .value=${TransformType.Translate}>
<sts-icon icon="up-down-left-right">Translate</sts-icon>
</sts-radio>
<sts-radio .value=${TransformType.Rotate}>
<sts-icon icon="rotate">Rotate</sts-icon>
</sts-radio>
<sts-radio .value=${TransformType.Scale}>
<sts-icon icon="scale">Scale</sts-icon>
</sts-radio>
</sts-radio-group>
</sts-toolbar-group>
<hr />
<sts-toolbar-group>
<sts-button class="stylize" primary>
Stylize <sts-icon icon="chevron-right"></sts-icon>
Help
</sts-button>
</sts-toolbar-group>
</sts-toolbar>
<div class="abs h-end v-start offset">
<sts-button>Switch to Camera View</sts-button>
</div>
<sts-anim-timeline-controls
class="timeline-controls abs h-center v-end"
></sts-anim-timeline-controls>
${this.#selectedObject != null ? html`
<div class="inspector abs h-end v-end offset">
<header class="inspector__header">
<div class="object-name">
${this.#selectedObject.icon != null ? html`
<sts-icon .icon=${this.#selectedObject.icon}></sts-icon>
` : nothing}
<h3>${this.#selectedObject.name}</h3>
</div>
`,
[StudioMode.Editor]: () => html`
<div class="main-menu abs h-start v-start offset">
<sts-button
class="swap-object"
icon="swap"
${ref(this.#fileTriggerRef)}
dropdown
icon="file"
>
Swap object
File
</sts-button>
</header>
<sts-entity-inspector></sts-entity-inspector>
<footer class="inspector__footer">
${this.#selectedEntityInTracklist ? html`
<sts-button
class="add-keyframe"
keybind="K"
@click=${() => this._timeline.addKeyframe()}
>
Add Keyframe
</sts-button>
` : this._sceneData.selectedEntity != null ? html`
<sts-button
class="add-to-timeline"
@click=${() => this._timeline.addTrack(this._sceneData.selectedEntity!)}
>
Add to Timeline
</sts-button>
` : nothing}
<sts-button
class="delete"
icon="trash"
title="Delete Entity"
></sts-button>
</footer>
</div>
` : nothing}
${ref(this.#helpDialogTriggerRef)}
icon="question"
@click=${() => {
// TODO
}}
>
Help
</sts-button>
</div>
<sts-toolbar class="top-toolbar abs h-center v-start">
<sts-toolbar-group>
<sts-button
${ref(this.#mediaLibraryTriggerRef)}
secondary
icon="plus-large"
title="Add asset from Media Library"
></sts-button>
</sts-toolbar-group>
<hr />
<sts-toolbar-group>
<sts-button
class="primitive"
icon="cube"
title="Cube"
@click=${() => studio.dispatchBlockingCommand(BlockingCommand.Cube)}
></sts-button>
<sts-button
class="primitive"
icon="cylinder"
title="Cylinder"
@click=${() => studio.dispatchBlockingCommand(BlockingCommand.Cylinder)}
></sts-button>
<sts-button
class="primitive"
icon="sphere"
title="Sphere"
@click=${() => studio.dispatchBlockingCommand(BlockingCommand.Sphere)}
></sts-button>
<sts-button
class="primitive"
icon="torus"
title="Torus"
@click=${() => studio.dispatchBlockingCommand(BlockingCommand.Torus)}
></sts-button>
</sts-toolbar-group>
<hr />
<sts-toolbar-group>
<sts-select class="transform-space"
title="Transform space"
.value=${bind(this, "_transformSpace")}
>
<sts-option .value=${TransformSpace.Local}>
<sts-icon icon="xform-local"></sts-icon>
Local
</sts-option>
<sts-option .value=${TransformSpace.World}>
<sts-icon icon="globe"></sts-icon>
Global
</sts-option>
</sts-select>
<sts-radio-group
title="Transform type"
.value=${bind(this, "_transformType")}
>
<sts-radio .value=${TransformType.Translate}>
<sts-icon icon="up-down-left-right">Translate</sts-icon>
</sts-radio>
<sts-radio .value=${TransformType.Rotate}>
<sts-icon icon="rotate">Rotate</sts-icon>
</sts-radio>
<sts-radio .value=${TransformType.Scale}>
<sts-icon icon="scale">Scale</sts-icon>
</sts-radio>
</sts-radio-group>
</sts-toolbar-group>
<hr />
<sts-toolbar-group>
<sts-button class="stylize" primary>
Stylize <sts-icon icon="chevron-right"></sts-icon>
</sts-button>
</sts-toolbar-group>
</sts-toolbar>
<div class="abs h-end v-start offset">
<sts-button>Switch to Camera View</sts-button>
</div>
<sts-anim-timeline-controls
class="timeline-controls abs h-center v-end"
></sts-anim-timeline-controls>
${this.#selectedObject != null ? html`
<div class="inspector abs h-end v-end offset">
<header class="inspector__header">
<div class="object-name">
${this.#selectedObject.icon != null ? html`
<sts-icon .icon=${this.#selectedObject.icon}></sts-icon>
` : nothing}
<h3>${this.#selectedObject.name}</h3>
</div>
<sts-button
class="swap-object"
icon="swap"
>
Swap object
</sts-button>
</header>
<sts-entity-inspector></sts-entity-inspector>
<footer class="inspector__footer">
${this.#selectedEntityInTracklist ? html`
<sts-button
class="add-keyframe"
keybind="K"
@click=${() => this._timeline.addKeyframe()}
>
Add Keyframe
</sts-button>
` : this._sceneData.selectedEntity != null ? html`
<sts-button
class="add-to-timeline"
@click=${() => this._timeline.addTrack(this._sceneData.selectedEntity!)}
>
Add to Timeline
</sts-button>
` : nothing}
<sts-button
class="delete"
icon="trash"
title="Delete Entity"
></sts-button>
</footer>
</div>
` : nothing}
`,
})}
</sts-studio>
<sts-menu
@@ -283,6 +302,12 @@ export class StudioViewportElement extends LitElement {
tag="sts-media-library-dialog"
nonBlocking
></sts-dialog>
<sts-dialog
.trigger=${this.#helpDialogTriggerRef}
tag="sts-help"
skipWrapper
></sts-dialog>
`;
}
}
@@ -1,5 +1,5 @@
import * as studio from "@storyteller/studio";
import { LitElement, type PropertyValues, html, nothing, unsafeCSS, TemplateResult } from "lit";
import { LitElement, type PropertyValues, html, nothing, unsafeCSS, TemplateResult, css } from "lit";
import { type Ref, createRef, ref } from "lit/directives/ref.js";
import { customElement, property, state } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
@@ -22,6 +22,12 @@ enum InspectorMode {
@customElement("sts-temp-video-preview")
export class TempVideoPreview extends LitElement {
static override styles = css`
:host {
display: none;
}
`;
@property({ attribute: false })
trigger?: Ref<HTMLElement>;
@@ -1,4 +1,6 @@
.overlay-stack {
width: 0;
height: 0;
isolation: isolate;
z-index: 99999;
}
@@ -1,16 +1,22 @@
import { on } from "@storyteller/framework";
import * as studio from "@storyteller/studio";
import { SceneState, type SceneStateEvent } from "@storyteller/studio";
import { LitElement, nothing } from "lit";
import { LitElement, css, nothing } from "lit";
import { customElement } from "lit/decorators.js";
@customElement("sts-iframe-messaging-bridge")
export class IframeMessagingBridgeElement extends LitElement {
static override styles = css`
:host {
display: none;
}
`;
#parentWindow?: Window;
override connectedCallback(): void {
console.log('window.parent', window.parent);
try {
if (
window.parent