diff --git a/packages/app/src/components/LiveChat/index.jsx b/packages/app/src/components/LiveChat/index.jsx index 797f2609..4df8d662 100644 --- a/packages/app/src/components/LiveChat/index.jsx +++ b/packages/app/src/components/LiveChat/index.jsx @@ -2,6 +2,8 @@ import React from "react" import * as antd from "antd" import classnames from "classnames" import { io } from "socket.io-client" +import { TransitionGroup, CSSTransition } from "react-transition-group" + import config from "config" import SessionModel from "models/session" @@ -26,9 +28,13 @@ export default class LiveChat extends React.Component { connectionEnd: false, roomInfo: null, timeline: [], + temporalTimeline: [], writtedMessage: "", + maxTemporalLines: this.props.maxTemporalLines ?? 10, } + debouncedIntervalTimelinePurge = null + timelineRef = React.createRef() joinSocketRoom = async () => { @@ -75,7 +81,6 @@ export default class LiveChat extends React.Component { socket.on("message", (message) => { this.pushToTimeline(message) - this.scrollTimelineToBottom() }) socket.connect() @@ -90,8 +95,6 @@ export default class LiveChat extends React.Component { message }) - this.scrollTimelineToBottom() - // remove writted message this.setState({ writtedMessage: "" @@ -101,9 +104,63 @@ export default class LiveChat extends React.Component { pushToTimeline = (message) => { const { timeline } = this.state + if (typeof message.key === "undefined") { + message.key = this.state.timeline.length + } + this.setState({ timeline: [...timeline, message] }) + + if (this.props.floatingMode) { + if (this.state.temporalTimeline.length >= this.state.maxTemporalLines) { + this.setState({ + temporalTimeline: this.state.temporalTimeline.slice(1) + }) + } + + // calculate duration based on message length (Minimum 3 second, maximum 10 seconds) + const calculatedDuration = Math.min(Math.max(message.content.length * 0.1, 3), 10) * 1000 + + const temporalLine = { + expireTime: Date.now() + calculatedDuration, + duration: calculatedDuration, + messageKey: message.key + } + + this.setState({ + temporalTimeline: [...this.state.temporalTimeline, temporalLine] + }) + + if (this.debouncedIntervalTimelinePurge) { + clearInterval(this.debouncedIntervalTimelinePurge) + } + + this.debouncedIntervalTimelinePurge = setInterval(this.purgeLastTemporalLine, 3000) + } + + this.scrollTimelineToBottom() + } + + purgeLastTemporalLine = () => { + if (!this.props.floatingMode) { + return false + } + + const { temporalTimeline } = this.state + + if (temporalTimeline.length === 0) { + clearInterval(this.debouncedIntervalTimelinePurge) + return false + } + + const lastTemporalLine = temporalTimeline[0] + + if (lastTemporalLine.expireTime < Date.now()) { + this.setState({ + temporalTimeline: temporalTimeline.slice(1) + }) + } } handleInputChange = (e) => { @@ -128,9 +185,13 @@ export default class LiveChat extends React.Component { } scrollTimelineToBottom = () => { - if (this.timelineRef.current) { - this.timelineRef.current.scrollTo({ - top: this.timelineRef.current.scrollHeight, + const scrollingElement = document.getElementById("liveChat_timeline") + + console.log(`Scrolling to bottom`, scrollingElement) + + if (scrollingElement) { + scrollingElement.scrollTo({ + top: scrollingElement.scrollHeight, behavior: "smooth" }) } @@ -138,10 +199,18 @@ export default class LiveChat extends React.Component { componentDidMount = async () => { await this.joinSocketRoom() + + app.ctx = { + submit: this.submitMessage + } } componentWillUnmount() { this.state.socket.close() + + if (this.debouncedIntervalTimelinePurge) { + clearInterval(this.debouncedIntervalTimelinePurge) + } } render() { @@ -161,6 +230,31 @@ export default class LiveChat extends React.Component { } + if (this.props.floatingMode) { + return
+ + { + this.state.temporalTimeline.map((line, index) => { + return + + + }) + } + +
+ } + return
{ this.state.timeline.map((line, index) => { diff --git a/packages/app/src/components/LiveChat/index.less b/packages/app/src/components/LiveChat/index.less index 43d6ddd6..acc6eb3b 100644 --- a/packages/app/src/components/LiveChat/index.less +++ b/packages/app/src/components/LiveChat/index.less @@ -14,8 +14,35 @@ align-items: center; } + &.floating { + .textRoom_line { + display: relative; + + background-color: rgba(var(--layoutBackgroundColor), 0.7); + backdrop-filter: blur(20px); + } + + .liveChat_timeline { + display: flex; + + flex-direction: column; + padding-top: 0; + + overflow-x: hidden; + overflow-y: hidden; + + //justify-content: flex-end; + + margin-bottom: 0; + + transition: all 250ms ease-in-out; + } + } + .liveChat_timeline { + position: relative; height: 100%; + overflow-y: scroll; margin-bottom: 70px;