diff --git a/src/api/scene.js b/src/api/scene.js index 8e60b670..0c9f2c70 100644 --- a/src/api/scene.js +++ b/src/api/scene.js @@ -54,6 +54,27 @@ const updateScene = async (sceneId, userUID, sceneData, title, version) => { } }; +const updateSceneIdAndTitle = async (sceneId, title) => { + try { + const userScenesRef = collection(db, 'scenes'); + const sceneDocRef = doc(userScenesRef, sceneId); + + const sceneSnapshot = await getDoc(sceneDocRef); + if (sceneSnapshot.exists()) { + await updateDoc(sceneDocRef, { + title: title, + updateTimestamp: serverTimestamp() + }); + + console.log('Firebase updateDoc (sceneId and title) fired'); + } else { + throw new Error('No existing sceneSnapshot exists.'); + } + } catch (error) { + throw new Error(error); + } +}; + const isSceneAuthor = async ({ sceneId, authorId }) => { if (!sceneId || !authorId) { console.log('sceneId or authorId is not provided in isSceneAuthor'); @@ -111,5 +132,6 @@ export { getUserScenes, generateSceneId, isSceneAuthor, - getCommunityScenes + getCommunityScenes, + updateSceneIdAndTitle }; diff --git a/src/components/Main.js b/src/components/Main.js index 691dc161..7e7df92c 100644 --- a/src/components/Main.js +++ b/src/components/Main.js @@ -14,6 +14,7 @@ import { injectCSS } from '../lib/utils'; import { SignInModal } from './modals/SignInModal'; import { ProfileModal } from './modals/ProfileModal'; import { ScenesModal } from './modals/ScenesModal'; +import { SceneEditTitle } from './components/SceneEditTitle'; THREE.ImageUtils.crossOrigin = ''; // Megahack to include font-awesome. injectCSS( @@ -185,6 +186,8 @@ export default class Main extends Component { render() { const scene = this.state.sceneEl; const isEditor = !!this.state.inspectorEnabled; + const sceneData = AFRAME.scenes[0].getAttribute('metadata', 'sceneTitle'); + return (
@@ -239,6 +242,11 @@ export default class Main extends Component {
)} + {this.state.inspectorEnabled && ( +
+ +
+ )} {this.state.inspectorEnabled && (
diff --git a/src/components/components/SceneEditTitle/SceneEditTitle.component.jsx b/src/components/components/SceneEditTitle/SceneEditTitle.component.jsx new file mode 100644 index 00000000..bf02dc01 --- /dev/null +++ b/src/components/components/SceneEditTitle/SceneEditTitle.component.jsx @@ -0,0 +1,90 @@ +import React, { useEffect, useState } from 'react'; +import styles from './SceneEditTitle.module.scss'; +import { CheckMark32Icon, Cross32Icon, Edit32Icon } from '../../../icons'; +import { updateSceneIdAndTitle } from '../../../api/scene'; + +const SceneEditTitle = ({ sceneData }) => { + const [editMode, setEditMode] = useState(false); + const [title, setTitle] = useState(sceneData?.sceneTitle); + + useEffect(() => { + if (sceneData && sceneData.sceneTitle !== undefined) { + setTitle(sceneData.sceneTitle); + } + }, [sceneData?.sceneTitle]); + + useEffect(() => { + if (sceneData && sceneData.sceneTitle !== undefined) { + setTitle(sceneData.sceneTitle); + } + }, [sceneData?.sceneTitle]); + + const handleEditClick = () => { + setEditMode(true); + }; + + const handleSaveClick = async () => { + setEditMode(false); + + try { + await updateSceneIdAndTitle(sceneData?.sceneId, title); + + AFRAME.scenes[0].setAttribute('metadata', 'sceneTitle', title); + AFRAME.scenes[0].setAttribute('metadata', 'sceneId', sceneData?.sceneId); + } catch (error) { + console.error('Error with update title', error); + } + }; + + const handleCancelClick = () => { + if (sceneData && sceneData.sceneTitle !== undefined) { + setTitle(sceneData.sceneTitle); + } + setEditMode(false); + }; + + const handleChange = (event) => { + setTitle(event.target.value); + }; + + const handleKeyDown = (event) => { + if (event.key === 'Enter') { + handleSaveClick(); + } else if (event.key === 'Escape') { + handleCancelClick(); + } + }; + return ( +
+ {editMode ? ( +
+ +
+
+ +
+
+ +
+
+
+ ) : ( +
+

{title}

+ {!editMode && ( +
+ +
+ )} +
+ )} +
+ ); +}; + +export { SceneEditTitle }; diff --git a/src/components/components/SceneEditTitle/SceneEditTitle.module.scss b/src/components/components/SceneEditTitle/SceneEditTitle.module.scss new file mode 100644 index 00000000..0c723672 --- /dev/null +++ b/src/components/components/SceneEditTitle/SceneEditTitle.module.scss @@ -0,0 +1,104 @@ +.wrapper { + position: absolute; + left: 110px; + bottom: 34px; + display: flex; + justify-content: center; + align-items: center; + + .title { + width: 300px; + text-overflow: ellipsis; + overflow: hidden; + height: 24px; + font-size: 20px !important; + white-space: nowrap; + cursor: pointer; + } + + .edit { + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + } + + .buttons { + display: flex; + row-gap: 8px; + cursor: pointer; + transition: filter 0.2s, transform 0.2s; + + .check { + filter: brightness(90%); + &:hover { + filter: brightness(100%); + } + + &:focus { + outline: none; + } + + &:active { + filter: brightness(90%); + box-shadow: none; + } + } + + .cross { + filter: brightness(90%); + &:hover { + filter: brightness(100%); + } + + &:focus { + outline: none; + } + + &:active { + filter: brightness(90%); + box-shadow: none; + } + } + + svg { + width: 32px; + height: 32px; + } + } + + .readOnly { + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + transition: filter 0.2s, transform 0.2s; + filter: brightness(90%); + + &:hover { + filter: brightness(100%); + } + + &:focus { + outline: none; + } + + &:active { + filter: brightness(90%); + box-shadow: none; + } + } +} + +input { + background: none !important; + color: #fff !important; + font-size: 20px; + user-select: text; +} + +input::selection { + background-color: #774dee; + opacity: 0.4; + color: #ffffff; +} diff --git a/src/components/components/SceneEditTitle/index.js b/src/components/components/SceneEditTitle/index.js new file mode 100644 index 00000000..01897250 --- /dev/null +++ b/src/components/components/SceneEditTitle/index.js @@ -0,0 +1 @@ +export { SceneEditTitle } from './SceneEditTitle.component.jsx'; diff --git a/src/components/components/index.js b/src/components/components/index.js index c1989013..9bf2cae1 100644 --- a/src/components/components/index.js +++ b/src/components/components/index.js @@ -10,3 +10,4 @@ export { Logo } from './Logo'; export { ScreenshotButton } from './ScreenshotButton'; export { ProfileButton } from './ProfileButton'; export { SceneCard } from './SceneCard'; +export { SceneEditTitle } from './SceneEditTitle'; diff --git a/src/icons/icons.jsx b/src/icons/icons.jsx index 69a02873..dba69a3d 100644 --- a/src/icons/icons.jsx +++ b/src/icons/icons.jsx @@ -232,6 +232,40 @@ const Mangnifier20Icon = () => ( ); +const Edit32Icon = () => ( + + + +); + +const CheckMark32Icon = () => ( + + + +); + const Copy32Icon = () => (