Skip to content

Commit

Permalink
Merge pull request #71 from mml-io/feature/avatar-client-example
Browse files Browse the repository at this point in the history
Add Avatar Client to Examples #67
  • Loading branch information
MarcusLongmuir authored Nov 20, 2023
2 parents 887ef97 + f7e7e1c commit 6ba5288
Show file tree
Hide file tree
Showing 26 changed files with 412 additions and 179 deletions.
98 changes: 98 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 10 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
}
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.4.2",
"@fortawesome/free-regular-svg-icons": "^6.4.2",
"@fortawesome/free-solid-svg-icons": "^6.4.2",
"@fortawesome/react-fontawesome": "^0.2.0",
"@mdx-js/loader": "^2.3.0",
"@mdx-js/react": "^2.3.0",
"@mml-io/3d-web-client-core": "0.9.0",
Expand Down Expand Up @@ -48,16 +52,17 @@
"@monaco-editor/react": "^4.5.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@types/codemirror": "5.60.10",
"@types/js-beautify": "^1.14.1",
"@types/node": "^18.16.3",
"@types/react": "^18.2.0",
"@types/three": "^0.153.0",
"@types/react-syntax-highlighter": "^15.5.8",
"@types/codemirror": "5.60.10",
"@types/js-beautify": "^1.14.1",
"@types/three": "^0.153.0",
"@typescript-eslint/eslint-plugin": "5.59.2",
"@typescript-eslint/parser": "5.59.2",
"autoprefixer": "^10.4.14",
"canvas": "^2.11.2",
"cross-env": "7.0.3",
"eslint-config-prettier": "8.8.0",
"eslint-config-standard": "17.0.0",
"eslint-import-resolver-typescript": "3.5.5",
Expand All @@ -75,7 +80,6 @@
"prettier-plugin-tailwindcss": "^0.2.8",
"raw-loader": "^4.0.2",
"tailwindcss": "^3.3.2",
"typescript": "5.0.4",
"cross-env": "7.0.3"
"typescript": "5.0.4"
}
}
}
8 changes: 4 additions & 4 deletions src/components/AnimatedExampleView/AnimatedExampleView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import * as React from "react";
import { useCallback, useEffect, useRef, useState } from "react";

import { AnimatedEditorContainer, CodemirrorEditor } from "@/src/components/AnimatedEditor";
import { ExampleAvatarClient } from "@/src/components/AnimatedExampleView/ExampleAvatarClient";
import { LocalAvatarServer } from "@/src/components/AnimatedExampleView/LocalAvatar/LocalAvatarServer";
import { ExampleAvatarClient } from "@/src/components/ExampleView/ExampleAvatarClient";

import { ExampleClient } from "./ExampleClient";
import { ExampleFloatingClient } from "../ExampleView/ExampleFloatingClient";

function createDocumentCode(code: string): string {
return `${'<m-plane color="white" width="20" height="20" rx="-90" y="-0.1"></m-plane><m-light type="point" x="10" y="10" z="10"></m-light>'}${code}`;
Expand Down Expand Up @@ -103,7 +103,7 @@ export function AnimatedExampleView() {
{networkedDOMDocument && (
<>
<div className="relative h-[50%] w-[50%]">
<ExampleClient clientId={0} key={0} document={networkedDOMDocument} />
<ExampleFloatingClient clientId={0} key={0} document={networkedDOMDocument} />
</div>
<div className="relative h-[50%] w-[50%]">
<ExampleAvatarClient
Expand All @@ -126,7 +126,7 @@ export function AnimatedExampleView() {
/>
</div>
<div className="relative h-[50%] w-[50%]">
<ExampleClient clientId={3} key={3} document={networkedDOMDocument} />
<ExampleFloatingClient clientId={3} key={3} document={networkedDOMDocument} />
</div>
</>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,9 @@ export class LocalAvatarServer {

removeClient(clientId: number) {
this.callbacks.delete(clientId);

this.callbacks.forEach((callback) => {
callback(clientId, null);
});
}
}
135 changes: 73 additions & 62 deletions src/components/ExampleView/DocsExampleView.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,41 @@
"use client";

import { faArrowRotateRight } from "@fortawesome/free-solid-svg-icons/faArrowRotateRight";
import { faPlus } from "@fortawesome/free-solid-svg-icons/faPlus";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { EditableNetworkedDOM } from "@mml-io/networked-dom-document";
import { IframeObservableDOMFactory } from "@mml-io/networked-dom-web-runner";
import * as React from "react";
import { useCallback, useEffect, useState } from "react";
import { twMerge } from "tailwind-merge";

import { ExampleClient } from "@/src/components/AnimatedExampleView/ExampleClient";
import ExampleClientsSection from "@/src/components/ExampleView/ExampleClientsSection";
import HTMLEditor from "@/src/components/ExampleView/HTMLEditor";
import { getClientIdFunctionGenerator } from "@/src/util/clients-utils";
import { CLIENT_TYPES, ClientType } from "@/types/docs-reference";

function createDocumentCode(code: string, lightOn: boolean): string {
return `${
lightOn &&
'<m-plane color="white" width="20" height="20" rx="-90"></m-plane><m-light type="point" x="10" y="10" z="10"></m-light>'
}${code}`;
}
const getNextClientId = getClientIdFunctionGenerator();

export type DocsExampleViewProps = {
code: string;
initialClientCount?: number;
baseScene: boolean;
initialClients: ClientType[];
baseScene?: boolean;
description: string;
showClientsControls?: boolean;
};

export function DocsExampleView(props: DocsExampleViewProps) {
const [clients, setClients] = useState<{ type: ClientType; id: number }[]>(() =>
props.initialClients.map((type) => ({
type,
id: getNextClientId(),
})),
);

const [code, setCode] = useState(props.code);
const [networkedDOMDocument, setNetworkedDOMDocument] = useState<EditableNetworkedDOM | null>(
null,
);
const [clients, setClients] = useState<number[]>([
...Array(props.initialClientCount ?? 1).keys(),
]);
const [showAddButtons, setShowAddButtons] = useState(false);

const { baseScene } = props;

Expand All @@ -40,7 +45,7 @@ export function DocsExampleView(props: DocsExampleViewProps) {
IframeObservableDOMFactory,
true,
);
document.load(createDocumentCode(code, baseScene));
document.load(code);
setNetworkedDOMDocument(document);

return () => {
Expand All @@ -49,74 +54,80 @@ export function DocsExampleView(props: DocsExampleViewProps) {
}, []);

useEffect(() => {
networkedDOMDocument?.load(createDocumentCode(code, baseScene));
}, [code, baseScene]);
networkedDOMDocument?.load(code);
}, [code]);

const handleResetClick = useCallback(() => {
setCode(props.code);
}, []);

const addNewClient = () => {
setClients((oldClients) => [...oldClients, oldClients.length]);
const handlePlusButton = () => {
if (clients.length >= 4) return;
setShowAddButtons((prev) => !prev);
};

const removeClient = () => {
setClients((oldClients) => oldClients.slice(0, oldClients.length - 1));
const addNewClient = (clientType: ClientType) => {
if (clients.length >= 4) return;
const newClient = {
type: clientType,
id: getNextClientId(),
};
setClients((oldClients) => [...oldClients, newClient]);
setShowAddButtons(false);
};

const removeClient = (elemId: number) => {
setClients((oldClients) => oldClients.filter(({ id }) => id !== elemId));
};

return (
<>
<div className="relative h-[50px] border-[1px] border-b-0 border-editor-border bg-white px-[17px] pt-[14px] leading-[19px] text-black dark:border-editor-border-dark dark:bg-editor-bg dark:text-white">
<div className="relative">
<div className="relative flex h-[50px] justify-between border-[1px] border-b-0 border-editor-border bg-white px-[17px] pt-[14px] leading-[19px] text-black dark:border-editor-border-dark dark:bg-editor-bg dark:text-white">
{props.description}
<button
onClick={handleResetClick}
className="top-[17px absolute right-[17px] h-[16px] w-[17px]"
>
<img
className="invert filter dark:filter-none"
src="/images/hero/resetButton.svg"
alt="reset"
width={17}
height={16}
/>
</button>
<div>
<button
onClick={handlePlusButton}
className={twMerge("mr-2", clients.length >= 4 && "opacity-30")}
>
<FontAwesomeIcon icon={faPlus} />
</button>
<button onClick={handleResetClick}>
<FontAwesomeIcon icon={faArrowRotateRight} />
</button>
</div>
</div>
<div className="relative flex h-[370px] flex-row border-[1px] border-editor-border dark:border-editor-border-dark">
<div className="h-full w-0 flex-[0_0_60%] border-r-[1px] border-editor-border dark:border-editor-border-dark">
<div className="h-full w-0 flex-[0_0_50%] border-r-[1px] border-editor-border dark:border-editor-border-dark">
<div className="flex h-[35px] border-b-[1px] border-editor-border bg-white dark:border-editor-border-dark dark:bg-editor-bg">
<span className="inline-block h-full w-[83px] border-b-[3px] bg-transparent pt-2 text-center text-[13px] text-editor-title">
CODE
</span>
</div>
<HTMLEditor className="h-[332px]" code={code} setCode={setCode} />
</div>
<div className="relative flex h-full flex-[0_0_40%] flex-col">
{networkedDOMDocument && (
<>
{clients.map((clientId, index) => {
const isLast = index === clients.length - 1 && index !== 0;
return (
<ExampleClient
clientId={clientId}
clientsNumber={clients.length}
key={clientId}
document={networkedDOMDocument}
>
{props.showClientsControls && (isLast || clientId === 0) && (
<button
className="absolute right-0 top-0 mr-1 mt-1 border-[1px] border-editor-border bg-white px-[10px] py-[3px] text-[13px] text-black dark:border-editor-border-dark dark:bg-editor-bg dark:text-white"
onClick={isLast ? removeClient : addNewClient}
>
{isLast ? "Remove client" : "Add new client"}
</button>
)}
</ExampleClient>
);
})}
</>
)}
</div>
<ExampleClientsSection
baseScene={baseScene}
networkedDOMDocument={networkedDOMDocument}
clients={clients}
removeClient={removeClient}
/>
</div>
</>
{showAddButtons && (
<div className="absolute right-2 top-10 z-20 border-[1px] border-editor-border dark:border-editor-border-dark">
<button
className="block w-full bg-white px-[10px] py-[3px] text-[13px] text-black dark:border-editor-border-dark dark:bg-editor-bg dark:text-white"
onClick={() => addNewClient(CLIENT_TYPES.FLOATING)}
>
New client
</button>
<button
className="block w-full border-t-[1px] border-editor-border bg-white px-[10px] py-[3px] text-[13px] text-black dark:border-editor-border-dark dark:bg-editor-bg dark:text-white"
onClick={() => addNewClient(CLIENT_TYPES.AVATAR)}
>
New Avatar client
</button>
</div>
)}
</div>
);
}
Loading

0 comments on commit 6ba5288

Please sign in to comment.