Update react-frontend example

This commit is contained in:
Danny McGee
2023-12-05 17:27:20 -05:00
parent 07456eabc7
commit 38a4141641
7 changed files with 172 additions and 70 deletions
+76 -8
View File
@@ -1,5 +1,58 @@
.root {
position: relative;
padding: 64px;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: 32px;
}
.thumbnail {
flex: 0 0 352px;
width: 352px;
height: 352px;
background: #444;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
&:hover {
background: #666;
}
}
.modalOverlay {
position: fixed;
inset: 0;
background: #2222227F;
backdrop-filter: blur(12px);
}
.modal {
position: fixed;
width: 1280px;
height: 720px;
top: calc(50vh - 360px);
left: calc(50vw - 640px);
border-radius: 16px;
overflow: hidden;
box-shadow:
0 0 16px rgba(0,0,0,0.17),
0 16px 48px rgba(0,0,0,0.3);
}
.loading {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: #222;
pointer-events: none;
transition: opacity 66.666ms linear;
}
.controls {
@@ -34,13 +87,28 @@
}
}
.loading {
.modalClose {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: #222;
pointer-events: none;
transition: opacity 66.666ms linear;
top: 16px;
right: 16px;
width: 48px;
height: 48px;
line-height: 48px;
border-radius: 50%;
appearance: none;
border: none;
padding: 0;
margin: 0;
background: #2222227F;
backdrop-filter: blur(16px);
font: unset {
family: inherit;
weight: 400;
size: 40px;
}
cursor: pointer;
&:hover {
background: #222222AA;
}
}
+65 -58
View File
@@ -2,6 +2,7 @@ import { type SceneStateEvent, SceneState } from "@storyteller/studio";
import { FormEvent, useState } from "react";
import StudioViewer from "./studio-viewer";
import StudioCanvasProvider from "./studio-canvas-provider";
import style from "./app.module.scss";
@@ -79,14 +80,10 @@ const SKYBOXES = [
];
export default () => {
const [objectId, setObjectId] = useState("desk");
const [skyboxId, setSkyboxId] = useState("test_scene");
const [objectId, setObjectId] = useState<string|null>(null);
const [skyboxId, setSkyboxId] = useState("meadow_4k");
const [loading, setLoading] = useState(true);
const onObjectSelect = (event: FormEvent<HTMLSelectElement>) => {
setObjectId((event.target as HTMLSelectElement).value)
}
const onSkyboxSelect = (event: FormEvent<HTMLSelectElement>) => {
setSkyboxId((event.target as HTMLSelectElement).value)
}
@@ -96,62 +93,72 @@ export default () => {
}
return (
<div className={style.root}>
<StudioViewer
objectId={objectId}
skyboxId={skyboxId}
onSceneStateChange={onSceneStateChange}
/>
<div
className={style.loading}
style={{
opacity: loading ? 1 : 0,
}}
>
<h1>Loading...</h1>
<StudioCanvasProvider>
<div className={style.root}>
{OBJECTS.map(({ id, label }) => (
<div
className={style.thumbnail}
key={id}
onClick={() => {
setLoading(true);
setObjectId(id);
}}
>
<h3>{label}</h3>
</div>
))}
</div>
<div className={style.controls}>
<label className={style.control}>
<span className={style.label}>Object</span>
<select
className={style.input}
name="object"
value={objectId}
disabled={loading}
onChange={onObjectSelect}
{!!objectId && <>
<div
className={style.modalOverlay}
onClick={() => setObjectId(null)}
/>
<div className={style.modal}>
<StudioViewer
objectId={objectId}
skyboxId={skyboxId}
onSceneStateChange={onSceneStateChange}
/>
<div
className={style.loading}
style={{
opacity: loading ? 1 : 0,
}}
>
{OBJECTS.map(({ id, label }) => (
<option
key={id}
value={id}
<h1>Loading...</h1>
</div>
<div className={style.controls}>
<label className={style.control}>
<span className={style.label}>Skybox</span>
<select
className={style.input}
name="skybox"
value={skyboxId}
disabled={loading}
onChange={onSkyboxSelect}
>
{label}
</option>
))}
</select>
</label>
<label className={style.control}>
<span className={style.label}>Skybox</span>
<select
className={style.input}
name="skybox"
value={skyboxId}
disabled={loading}
onChange={onSkyboxSelect}
{SKYBOXES.map(({ id, label }) => (
<option
key={id}
value={id}
>
{label}
</option>
))}
</select>
</label>
</div>
<button className={style.modalClose}
onClick={() => setObjectId(null)}
>
{SKYBOXES.map(({ id, label }) => (
<option
key={id}
value={id}
>
{label}
</option>
))}
</select>
</label>
</div>
</div>
&times;
</button>
</div>
</>}
</StudioCanvasProvider>
);
}
@@ -0,0 +1,15 @@
import { CanvasProviderElement } from "@storyteller/studio-web/canvas-provider";
import "@storyteller/studio-web/canvas-provider";
import React, { ReactNode, forwardRef } from "react";
export interface Props extends React.HTMLProps<CanvasProviderElement> {
children?: ReactNode | ReactNode[];
}
export default forwardRef<CanvasProviderElement, Props>(
({ children, ...props }, ref) => (
<sts-canvas-provider {...props} ref={ref}>
{children}
</sts-canvas-provider>
)
);
+4 -2
View File
@@ -1,9 +1,9 @@
import type { SceneStateEvent } from "@storyteller/studio";
import { ViewerElement } from "@storyteller/studio-web/viewer";
import "@storyteller/studio-web/viewer";
import { MutableRefObject, forwardRef, useEffect, useRef } from "react";
import React, { MutableRefObject, forwardRef, useEffect, useRef } from "react";
export interface Props {
export interface Props extends React.HTMLProps<ViewerElement> {
objectId: string;
skyboxId: string;
onSceneStateChange?(event: SceneStateEvent): void;
@@ -13,6 +13,7 @@ export default forwardRef<ViewerElement, Props>(({
objectId,
skyboxId,
onSceneStateChange,
...props
}, ref) => {
const viewerRef = useRef<ViewerElement>(null);
@@ -38,6 +39,7 @@ export default forwardRef<ViewerElement, Props>(({
return (
<sts-viewer
{...props}
ref={refCallback}
objectId={objectId}
skyboxId={skyboxId}
-1
View File
@@ -2,7 +2,6 @@ html, body {
width: 100%;
height: 100%;
margin: 0;
overflow: hidden;
font-family: "Fira Sans", sans-serif;
color-scheme: dark;
}
+5
View File
@@ -1,4 +1,5 @@
import { ViewerElement } from "@storyteller/studio-web";
import { CanvasProviderElement } from "@storyteller/studio-web/canvas-provider";
declare global {
export namespace JSX {
@@ -9,6 +10,10 @@ declare global {
React.HTMLAttributes<ViewerElement>,
ViewerElement,
>;
"sts-canvas-provider": React.DetailedHTMLProps<
React.HTMLAttributes<CanvasProviderElement>,
CanvasProviderElement,
>
}
}
}
+7 -1
View File
@@ -32,13 +32,14 @@
font-size: 16px;
padding: 10px 12px;
pointer-events: auto;
outline: 0 solid transparent;
// TODO: Copypasta
background: #0006;
color: #FFFC;
backdrop-filter: blur(16px);
transition: {
property: background, color;
property: background, color, outline-width, outline-color;
duration: 0.1s;
timing-function: linear;
}
@@ -62,6 +63,11 @@
color: #FFF;
}
&:has(:focus-visible) {
z-index: 1;
outline: 4px solid #2F83FFBF;
}
&:has(:checked) {
background: #7A2C34E3;
color: #FFF;