Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/concrete-utopia/utopia in…
Browse files Browse the repository at this point in the history
…to tests/pupeteer-test-logging
  • Loading branch information
bkrmendy committed Jan 25, 2024
2 parents 0dc0140 + e1f98aa commit 3c4609d
Show file tree
Hide file tree
Showing 35 changed files with 784 additions and 360 deletions.
2 changes: 1 addition & 1 deletion editor/liveblocks.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export type ConnectionInfo = {
id: number
startedAt: number
lastSeen: number
colorIndex: number | null
}

// Optionally, UserMeta represents static/readonly metadata on each user, as
Expand All @@ -83,7 +84,6 @@ export type UserMeta = {
id: string // Accessible through `user.id`
name: string | null
avatar: string | null
colorIndex: number | null
}

// Optionally, the type of custom events broadcast and listened to in this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,6 @@
.lb-comment-avatar {
inline-size: var(--lb-comment-avatar-size);
flex: none;
visibility: hidden; /* we're rolling our own avatars, for now we just ignore the default LB ones */
}
.lb-comment-details-labels {
gap: calc(0.5 * var(--lb-spacing));
Expand Down
51 changes: 19 additions & 32 deletions editor/src/components/canvas/controls/comment-indicator.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { ThreadData } from '@liveblocks/client'
import { Comment } from '@liveblocks/react-comments'
import type { CommentProps } from '@liveblocks/react-comments'
import { AnimatePresence, motion, useAnimate } from 'framer-motion'
import type { CSSProperties } from 'react'
import React from 'react'
import type { ThreadMetadata } from '../../../../liveblocks.config'
import type { ThreadMetadata, UserMeta } from '../../../../liveblocks.config'
import { useEditThreadMetadata, useStorage } from '../../../../liveblocks.config'
import {
getCollaboratorById,
Expand Down Expand Up @@ -37,7 +38,6 @@ import {
} from '../../../core/shared/multiplayer'
import { useMyUserId } from '../../../core/shared/multiplayer-hooks'
import { optionalMap } from '../../../core/shared/optional-utils'
import type { CommentWrapperProps } from '../../../utils/multiplayer-wrapper'
import { MultiplayerWrapper, baseMultiplayerAvatarStyle } from '../../../utils/multiplayer-wrapper'
import { when } from '../../../utils/react-conditionals'
import { UtopiaStyles, colorTheme } from '../../../uuiui'
Expand Down Expand Up @@ -92,8 +92,6 @@ CommentIndicators.displayName = 'CommentIndicators'

interface TemporaryCommentIndicatorProps {
position: CanvasPoint
bgColor: string
fgColor: string
avatarUrl: string | null
initials: string
}
Expand Down Expand Up @@ -123,14 +121,12 @@ function useCommentBeingComposed(): TemporaryCommentIndicatorProps | null {
if (collaborator == null) {
return {
initials: 'AN',
color: multiplayerColorFromIndex(null),
avatar: null,
}
}

return {
initials: multiplayerInitialsFromName(normalizeMultiplayerName(collaborator.name)),
color: multiplayerColorFromIndex(collaborator.colorIndex),
avatar: collaborator.avatar,
}
}, [collabs, myUserId])
Expand All @@ -141,8 +137,6 @@ function useCommentBeingComposed(): TemporaryCommentIndicatorProps | null {

return {
position: location,
bgColor: collaboratorInfo.color.background,
fgColor: collaboratorInfo.color.foreground,
avatarUrl: collaboratorInfo.avatar,
initials: collaboratorInfo.initials,
}
Expand All @@ -161,8 +155,6 @@ const CommentIndicatorsInner = React.memo(() => {
<CommentIndicatorUI
position={temporaryIndicatorData.position}
resolved={false}
bgColor={temporaryIndicatorData.bgColor}
fgColor={temporaryIndicatorData.fgColor}
avatarUrl={temporaryIndicatorData.avatarUrl}
avatarInitials={temporaryIndicatorData.initials}
isActive={true}
Expand All @@ -177,8 +169,6 @@ CommentIndicatorsInner.displayName = 'CommentIndicatorInner'
interface CommentIndicatorUIProps {
position: CanvasPoint
resolved: boolean
bgColor: string
fgColor: string
avatarInitials: string
avatarUrl?: string | null
isActive: boolean
Expand Down Expand Up @@ -232,8 +222,7 @@ function useIndicatorStyle(
}

export const CommentIndicatorUI = React.memo<CommentIndicatorUIProps>((props) => {
const { position, bgColor, fgColor, avatarUrl, avatarInitials, resolved, isActive, isRead } =
props
const { position, avatarUrl, avatarInitials, resolved, isActive, isRead } = props

const style = useIndicatorStyle(position, {
isRead: isRead ?? true,
Expand All @@ -246,7 +235,7 @@ export const CommentIndicatorUI = React.memo<CommentIndicatorUIProps>((props) =>
return (
<div style={style}>
<MultiplayerAvatar
color={{ background: bgColor, foreground: fgColor }}
color={multiplayerColorFromIndex(null)}
picture={avatarUrl}
name={avatarInitials}
/>
Expand Down Expand Up @@ -347,10 +336,6 @@ const CommentIndicator = React.memo(({ thread }: CommentIndicatorProps) => {
],
)

// This is a hack: when the comment is unread, we show a dark background, so we need light foreground colors.
// So we trick the Liveblocks Comment component and lie to it that the theme is dark mode.
const dataThemeProp = isRead ? {} : { 'data-theme': 'dark' }

const style = useIndicatorStyle(dragPosition ?? location, {
isRead: isRead,
resolved: thread.metadata.resolved,
Expand All @@ -377,7 +362,7 @@ const CommentIndicator = React.memo(({ thread }: CommentIndicatorProps) => {
overflow: 'auto',
background: 'transparent',
}}
{...dataThemeProp}
forceDarkMode={!isRead}
/>
</div>
)
Expand Down Expand Up @@ -582,11 +567,13 @@ function useHover() {

type CommentIndicatorWrapper = {
thread: ThreadData<ThreadMetadata>
user: UserMeta | null
expanded: boolean
} & CommentWrapperProps
forceDarkMode: boolean
} & CommentProps

const CommentIndicatorWrapper = React.memo((props: CommentIndicatorWrapper) => {
const { thread, expanded, user, ...commentProps } = props
const { thread, expanded, user, forceDarkMode, ...commentProps } = props

const [avatarRef, animateAvatar] = useAnimate()

Expand All @@ -605,8 +592,14 @@ const CommentIndicatorWrapper = React.memo((props: CommentIndicatorWrapper) => {
)
}, [expanded, avatarRef, animateAvatar])

// This is a hack: when the comment is unread, we show a dark background, so we need light foreground colors.
// So we trick the Liveblocks Comment component and lie to it that the theme is dark mode.
const updatedCommentProps = forceDarkMode
? { ...commentProps, 'data-theme': 'dark' }
: commentProps

if (user == null) {
return <Comment {...commentProps} />
return <Comment {...updatedCommentProps} />
}

return (
Expand All @@ -626,7 +619,7 @@ const CommentIndicatorWrapper = React.memo((props: CommentIndicatorWrapper) => {
>
<MultiplayerAvatar
name={multiplayerInitialsFromName(normalizeMultiplayerName(user.name))}
color={multiplayerColorFromIndex(user.colorIndex)}
color={multiplayerColorFromIndex(null)}
picture={user.avatar}
style={{ outline: 'none' }}
/>
Expand Down Expand Up @@ -654,17 +647,11 @@ const CommentIndicatorWrapper = React.memo((props: CommentIndicatorWrapper) => {
}}
transition={{ duration: animDuration }}
>
<Comment {...commentProps} />
<CommentRepliesCounter thread={thread} />
<Comment {...updatedCommentProps} />
<CommentRepliesCounter thread={thread} forceDarkMode={forceDarkMode} />
</motion.div>,
)}
</AnimatePresence>
</div>
)
})

function getCanvasHeight(): number {
const canvasDiv = document.getElementById('canvas-root')
const canvasHeight = canvasDiv?.clientHeight ?? 0
return canvasHeight
}
14 changes: 4 additions & 10 deletions editor/src/components/canvas/controls/comment-popup.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { CommentData } from '@liveblocks/client'
import type { ComposerSubmitComment } from '@liveblocks/react-comments'
import { Composer } from '@liveblocks/react-comments'
import { Comment, Composer } from '@liveblocks/react-comments'
import { useAtom } from 'jotai'
import type { CSSProperties } from 'react'
import React, { useRef } from 'react'
Expand All @@ -22,7 +22,7 @@ import * as EP from '../../../core/shared/element-path'
import { emptyComments, jsExpressionValue } from '../../../core/shared/element-template'
import { create } from '../../../core/shared/property-path'
import { assertNever } from '../../../core/shared/utils'
import { CommentWrapper, MultiplayerWrapper } from '../../../utils/multiplayer-wrapper'
import { MultiplayerWrapper } from '../../../utils/multiplayer-wrapper'
import { when } from '../../../utils/react-conditionals'
import { Button, FlexRow, Icn, Tooltip, UtopiaStyles, colorTheme } from '../../../uuiui'
import {
Expand Down Expand Up @@ -376,11 +376,9 @@ const CommentThread = React.memo(({ comment }: CommentThreadProps) => {
onScroll={onScroll}
>
{thread.comments.map((c) => {
const user = getCollaboratorById(collabs, c.userId)
return (
<CommentWrapper
<Comment
key={c.id}
user={user}
comment={c}
onCommentDelete={onCommentDelete}
style={{ background: colorTheme.bg1.value }}
Expand Down Expand Up @@ -546,9 +544,6 @@ ListShadow.displayName = 'ListShadow'

const HeaderComment = React.memo(
({ comment, enabled }: { comment: CommentData; enabled: boolean }) => {
const collabs = useStorage((storage) => storage.collaborators)
const user = getCollaboratorById(collabs, comment.userId)

if (!enabled) {
return null
}
Expand All @@ -567,8 +562,7 @@ const HeaderComment = React.memo(
transform: 'scale(1.01)',
}}
>
<CommentWrapper
user={user}
<Comment
comment={comment}
style={{ background: colorTheme.bg1.value, color: colorTheme.fg1.value }}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,39 @@ import React from 'react'
import type { ThreadData } from '@liveblocks/client'
import type { ThreadMetadata } from '../../../../liveblocks.config'
import { useColorTheme } from '../../../uuiui'
import { darkColorThemeCssVariables } from '../../../uuiui/styles/theme/utopia-theme'
import { dark } from '../../../uuiui/styles/theme/dark'
import { useTheme } from '@emotion/react'
import { Substores, useEditorState } from '../../editor/store/store-hook'
import { getCurrentTheme } from '../../editor/store/editor-state'

interface CommentRepliesCounterProps {
thread: ThreadData<ThreadMetadata>
forceDarkMode?: boolean
}

export const CommentRepliesCounter = React.memo((props: CommentRepliesCounterProps) => {
const colorTheme = useColorTheme()

const theme = useEditorState(
Substores.userState,
(store) => getCurrentTheme(store.userState),
'CommentRepliesCounter theme',
)

const color = React.useMemo(() => {
// If we don't force dark mode because of a blue background, we can just use foreground color
if (!props.forceDarkMode) {
return colorTheme.fg6.value
}
// In dark mode we need a lighter foreground which is visible well on blue background
if (theme === 'dark') {
return colorTheme.fg2.value
}
// In light mode we need a light background color, so it is visible on blue background
return colorTheme.bg3.value
}, [colorTheme, theme, props.forceDarkMode])

const repliesCount = props.thread.comments.filter((c) => c.deletedAt == null).length - 1

if (repliesCount <= 0) {
Expand All @@ -21,7 +46,7 @@ export const CommentRepliesCounter = React.memo((props: CommentRepliesCounterPro
style={{
paddingLeft: 44,
fontSize: 9,
color: colorTheme.fg6.value,
color: color,
marginBottom: 8,
}}
>
Expand Down
36 changes: 28 additions & 8 deletions editor/src/components/canvas/multiplayer-presence.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ import {
} from '../../../liveblocks.config'
import {
getCollaborator,
getConnectionById,
useAddMyselfToCollaborators,
useCanComment,
useMyUserAndPresence,
useConnections,
} from '../../core/commenting/comment-hooks'
import { MetadataUtils } from '../../core/model/element-metadata-utils'
import { mapDropNulls } from '../../core/shared/array-utils'
Expand All @@ -32,7 +34,9 @@ import {
windowPoint,
zeroRectIfNullOrInfinity,
} from '../../core/shared/math-utils'
import type { MultiplayerColor } from '../../core/shared/multiplayer'
import {
excludeMyConnection,
isPlayerOnAnotherRemixRoute,
multiplayerColorFromIndex,
normalizeOthersList,
Expand Down Expand Up @@ -173,13 +177,15 @@ const MultiplayerCursors = React.memo(() => {
const me = useSelf()
const collabs = useStorage((store) => store.collaborators)
const others = useOthers((list) => {
const presences = normalizeOthersList(me.id, list)
const presences = excludeMyConnection(me.id, me.connectionId, list)
return presences.map((p) => ({
presenceInfo: p,
userInfo: getCollaborator(collabs, p),
}))
})

const connections = useConnections()

return (
<div
style={{
Expand All @@ -206,7 +212,10 @@ const MultiplayerCursors = React.memo(() => {
<MultiplayerCursor
key={`cursor-${other.presenceInfo.id}`}
name={other.userInfo.name}
colorIndex={other.userInfo.colorIndex}
colorIndex={
getConnectionById(connections, other.userInfo.id, other.presenceInfo.connectionId)
?.colorIndex ?? null
}
position={position}
userId={other.userInfo.id}
/>
Expand Down Expand Up @@ -433,12 +442,19 @@ const FollowingOverlay = React.memo(() => {
dispatch([switchEditorMode(EditorModes.selectMode(null, false, 'none'))])
}, [dispatch])

const followedUserColor = React.useMemo(() => {
return multiplayerColorFromIndex(followedUser?.colorIndex ?? null)
}, [followedUser])
const connections = useConnections()

const followedUserColor: MultiplayerColor = React.useMemo(() => {
if (followed == null) {
return multiplayerColorFromIndex(null)
} else {
return multiplayerColorFromIndex(
getConnectionById(connections, followed.id, followed.connectionId)?.colorIndex ?? null,
)
}
}, [connections, followed])

const collabs = useStorage((store) => store.collaborators)
const connections = useStorage((store) => store.connections)

const { user: myUser, presence: myPresence } = useMyUserAndPresence()
const others = useOthers((list) =>
Expand Down Expand Up @@ -564,15 +580,19 @@ const MultiplayerShadows = React.memo(() => {
}))
})

const connections = useConnections()

const shadows = React.useMemo(() => {
return others.flatMap(
(other) =>
other.presenceInfo.presence.activeFrames?.map((activeFrame) => ({
activeFrame: activeFrame,
colorIndex: other.userInfo.colorIndex,
colorIndex:
getConnectionById(connections, other.userInfo.id, other.presenceInfo.connectionId)
?.colorIndex ?? null,
})) ?? [],
)
}, [others])
}, [connections, others])

const myActiveFrames = useEditorState(
Substores.restOfEditor,
Expand Down
Loading

0 comments on commit 3c4609d

Please sign in to comment.