From 1019f7fb61cc4287b59914e20c88038f2a823d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D0=B0=D1=81=D1=83=D0=BB?= Date: Thu, 5 Dec 2024 17:13:46 +0300 Subject: [PATCH 1/3] feat: layout polishing, removed rerenders, added index kyes --- .../ActionsToolbar/PlayerControl/index.tsx | 2 +- .../Universe/Graph/Cubes/Text/index.tsx | 7 +- .../mindset/components/Header/index.tsx | 1 + .../mindset/components/LandingPage/index.tsx | 46 ++------ .../mindset/components/MediaPlayer/index.tsx | 10 +- .../PlayerContols/Controls/index.tsx | 104 ++++++++++++++++++ .../ProgressBar/Markers}/Marker/index.tsx | 0 .../ProgressBar/Markers/index.tsx | 22 ++++ .../PlayerContols/ProgressBar/index.tsx | 10 +- .../components/PlayerContols/index.tsx | 90 +-------------- .../Transcript/Viewer/Paragraph/index.tsx | 51 +++++++++ .../Sidebar/Transcript/Viewer/index.tsx | 42 +------ .../components/Sidebar/Transcript/index.tsx | 39 +++---- .../mindset/components/Sidebar/index.tsx | 7 +- .../mindset/components/VideoCard/index.tsx | 1 - src/network/fetchSourcesData/index.ts | 8 +- 16 files changed, 236 insertions(+), 204 deletions(-) create mode 100644 src/components/mindset/components/PlayerContols/Controls/index.tsx rename src/components/mindset/components/{ => PlayerContols/ProgressBar/Markers}/Marker/index.tsx (100%) create mode 100644 src/components/mindset/components/PlayerContols/ProgressBar/Markers/index.tsx create mode 100644 src/components/mindset/components/Sidebar/Transcript/Viewer/Paragraph/index.tsx diff --git a/src/components/App/ActionsToolbar/PlayerControl/index.tsx b/src/components/App/ActionsToolbar/PlayerControl/index.tsx index ec9de2600..a4e65546b 100644 --- a/src/components/App/ActionsToolbar/PlayerControl/index.tsx +++ b/src/components/App/ActionsToolbar/PlayerControl/index.tsx @@ -54,7 +54,7 @@ export const PlayerControl = () => { const showPlayer = (sidebarIsOpen && selectedNode?.ref_id !== playingNode?.ref_id) || (playingNode && !sidebarIsOpen) - const isMindset = window.location?.hostname === 'graphmindset.sphinx.chat' + const isMindset = window.location?.hostname === 'graphmindset.sphinx.chat' || window.location.hostname === 'localhost' return miniPlayerIsVisible && playingNode && showPlayer && !isMindset ? ( diff --git a/src/components/Universe/Graph/Cubes/Text/index.tsx b/src/components/Universe/Graph/Cubes/Text/index.tsx index ede72b2d8..31518e065 100644 --- a/src/components/Universe/Graph/Cubes/Text/index.tsx +++ b/src/components/Universe/Graph/Cubes/Text/index.tsx @@ -77,7 +77,7 @@ export const TextNode = memo(({ node, hide, ignoreDistance }: Props) => { const { texture } = useTexture(node.properties?.image_url || '') - const { normalizedSchemasByType } = useSchemaStore((s) => s) + const { normalizedSchemasByType, getNodeKeysByType } = useSchemaStore((s) => s) useFrame(({ camera, clock }) => { const { selectedNode, hoveredNode, activeEdge } = useGraphStore.getState() @@ -148,7 +148,10 @@ export const TextNode = memo(({ node, hide, ignoreDistance }: Props) => { const Icon = primaryIcon ? Icons[primaryIcon] : null const iconName = Icon ? primaryIcon : 'NodesIcon' - const sanitizedNodeName = removeEmojis(String(node?.properties?.name || '')) + const keyProperty = getNodeKeysByType(node.node_type) || '' + + const sanitizedNodeName = + keyProperty && node?.properties ? removeEmojis(String(node?.properties[keyProperty] || '')) : '' const uniforms = { u_texture: { value: texture }, diff --git a/src/components/mindset/components/Header/index.tsx b/src/components/mindset/components/Header/index.tsx index 280530014..43565241e 100644 --- a/src/components/mindset/components/Header/index.tsx +++ b/src/components/mindset/components/Header/index.tsx @@ -22,6 +22,7 @@ const Head = styled(Flex).attrs({ justify: 'flex-start', })` height: 64px; + box-sizing: border-box; padding: 20px 23px; gap: 0px; z-index: 50; diff --git a/src/components/mindset/components/LandingPage/index.tsx b/src/components/mindset/components/LandingPage/index.tsx index 7c33fbcbd..6980905e5 100644 --- a/src/components/mindset/components/LandingPage/index.tsx +++ b/src/components/mindset/components/LandingPage/index.tsx @@ -8,11 +8,11 @@ import { getNodes, getSchemaAll } from '~/network/fetchSourcesData' import { useDataStore } from '~/stores/useDataStore' import { useMindsetStore } from '~/stores/useMindsetStore' import { useSchemaStore } from '~/stores/useSchemaStore' -import { SubmitErrRes } from '~/types' +import { FetchDataResponse, Node, SubmitErrRes } from '~/types' import { colors } from '~/utils/colors' import { ChevronRight } from '../Icon/ChevronRight' -import { isValidMediaUrl } from './utils' import { VideoCard } from '../VideoCard' +import { isValidMediaUrl } from './utils' export type FormData = { input: string @@ -22,26 +22,6 @@ export type FormData = { latitude: string } -interface EpisodeProperties { - date: number - episode_title: string - image_url: string - media_url: string - pubkey: string - source_link: string - status: string -} - -interface Node { - node_type: string - properties?: EpisodeProperties -} - -export interface ApiResponse { - edges: never[] - nodes: Node[] -} - const handleSubmitForm = async (data: FieldValues): Promise => { const endPoint = 'add_node' @@ -65,22 +45,18 @@ export const LandingPage = () => { const [inputValue, setInputValue] = useState('') const [error, setError] = useState(false) const [requestError, setRequestError] = useState('') - const [episodes, setEpisodes] = useState([]) + const [episodes, setEpisodes] = useState([]) const { setRunningProjectId } = useDataStore((s) => s) const { setSelectedEpisodeId, setSelectedEpisodeLink } = useMindsetStore((s) => s) const { setSchemas } = useSchemaStore((s) => s) - const filterAndSortEpisodes = (data: ApiResponse): EpisodeProperties[] => - data.nodes - .filter((node) => node.node_type.toLowerCase() === 'episode' && node.properties?.date) - .map((node) => node.properties!) - .sort((a, b) => b.date - a.date) - .slice(0, 3) + const filterAndSortEpisodes = (data: FetchDataResponse): Node[] => + data.nodes.filter((node) => node.node_type.toLowerCase() === 'episode' && node.properties?.date).slice(0, 3) useEffect(() => { const fetchSchemaData = async () => { try { - const res: ApiResponse = await getNodes() + const res: FetchDataResponse = await getNodes() const topEpisodes = filterAndSortEpisodes(res) @@ -161,11 +137,11 @@ export const LandingPage = () => { {episodes.map((episode) => ( handleSubmit(episode?.source_link)} - subtitle="Subtitle for episode seed" - title={(episode?.episode_title as string) || ''} + key={episode?.ref_id} + imageUrl={episode?.properties?.image_url || ''} + onClick={() => handleSubmit(episode?.properties?.source_link)} + subtitle="" + title={episode?.properties?.episode_title || ''} /> ))} diff --git a/src/components/mindset/components/MediaPlayer/index.tsx b/src/components/mindset/components/MediaPlayer/index.tsx index a073e4c97..b7b106db2 100644 --- a/src/components/mindset/components/MediaPlayer/index.tsx +++ b/src/components/mindset/components/MediaPlayer/index.tsx @@ -89,13 +89,13 @@ const MediaPlayerComponent = ({ mediaUrl }: Props) => { setIsPlaying(!isPlaying) } - const handlePlay = () => { + const handlePlay = useCallback(() => { setIsPlaying(true) - } + }, [setIsPlaying]) - const handlePause = () => { + const handlePause = useCallback(() => { setIsPlaying(false) - } + }, [setIsPlaying]) const handleError = () => { setHasError(true) @@ -123,8 +123,6 @@ const MediaPlayerComponent = ({ mediaUrl }: Props) => { } else { setActiveEdge(null) } - - // find playing link and set it to state } } diff --git a/src/components/mindset/components/PlayerContols/Controls/index.tsx b/src/components/mindset/components/PlayerContols/Controls/index.tsx new file mode 100644 index 000000000..8abd7e388 --- /dev/null +++ b/src/components/mindset/components/PlayerContols/Controls/index.tsx @@ -0,0 +1,104 @@ +import { IconButton } from '@mui/material' +import { memo } from 'react' +import styled from 'styled-components' +import PauseIcon from '~/components/Icons/PauseIcon' +import PlayIcon from '~/components/Icons/PlayIcon' +import { Flex } from '~/components/common/Flex' +import { usePlayerStore } from '~/stores/usePlayerStore' +import { colors } from '~/utils/colors' + +export const Controls = memo(() => { + const { isPlaying, playerRef } = usePlayerStore((s) => s) + + const handleRewind = () => { + if (playerRef) { + const newTime = playerRef.getCurrentTime() - 15 + + playerRef.seekTo(newTime, 'seconds') + } + } + + const handleFastForward = () => { + if (playerRef) { + const newTime = playerRef.getCurrentTime() + 15 + + playerRef.seekTo(newTime, 'seconds') + } + } + + const togglePlay = () => { + if (playerRef) { + if (isPlaying) { + playerRef.getInternalPlayer().pauseVideo() + + return + } + + playerRef.getInternalPlayer().playVideo() + } + } + + return ( + + + + + + {isPlaying ? : } + + + + + + ) +}) + +Controls.displayName = 'Controls' + +const Wrapper = styled(Flex).attrs({ + direction: 'row', + align: 'center', + justify: 'flex-start', +})` + width: 142px; + height: 54px; + background: ${colors.BG1}; + border-radius: 40px; + margin-right: 54px; + color: ${colors.white}; + font-size: 20px; + padding: 12px; + justify-content: space-between; + box-sizing: border-box; +` + +const Action = styled(IconButton)` + && { + font-size: 36px; + padding: 2px; + overflow: hidden; + } +` + +const RewindIconWrapper = styled.div` + display: flex; + align-items: center; + justify-content: center; + margin: 1px 0 0 1px; + cursor: pointer; + img { + width: 20px; + height: auto; + } +` + +const ForwardIconWrapper = styled.div` + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + img { + width: 24px; + height: auto; + } +` diff --git a/src/components/mindset/components/Marker/index.tsx b/src/components/mindset/components/PlayerContols/ProgressBar/Markers/Marker/index.tsx similarity index 100% rename from src/components/mindset/components/Marker/index.tsx rename to src/components/mindset/components/PlayerContols/ProgressBar/Markers/Marker/index.tsx diff --git a/src/components/mindset/components/PlayerContols/ProgressBar/Markers/index.tsx b/src/components/mindset/components/PlayerContols/ProgressBar/Markers/index.tsx new file mode 100644 index 000000000..8f7e3f868 --- /dev/null +++ b/src/components/mindset/components/PlayerContols/ProgressBar/Markers/index.tsx @@ -0,0 +1,22 @@ +import { memo } from 'react' +import { NodeExtended } from '~/types' +import { Marker } from './Marker' + +type Props = { + markers: NodeExtended[] + duration: number +} + +export const Markers = memo(({ markers, duration }: Props) => ( + <> + {markers.map((node) => { + const position = ((node?.start || 0) / duration) * 100 + const type = node?.node_type || '' + const img = node?.properties?.image_url || '' + + return + })} + +)) + +Markers.displayName = 'Markers' diff --git a/src/components/mindset/components/PlayerContols/ProgressBar/index.tsx b/src/components/mindset/components/PlayerContols/ProgressBar/index.tsx index 557cb22da..c7b57145a 100644 --- a/src/components/mindset/components/PlayerContols/ProgressBar/index.tsx +++ b/src/components/mindset/components/PlayerContols/ProgressBar/index.tsx @@ -3,7 +3,7 @@ import styled from 'styled-components' import { Flex } from '~/components/common/Flex' import { NodeExtended } from '~/types' import { colors } from '~/utils' -import { Marker } from '../../Marker' +import { Markers } from './Markers' type Props = { duration: number @@ -18,13 +18,7 @@ export const ProgressBar = ({ duration, markers, handleProgressChange, playingTI return ( - {markers.map((node) => { - const position = ((node?.start || 0) / duration) * 100 - const type = node?.node_type || '' - const img = node?.properties?.image_url || '' - - return - })} + ) } diff --git a/src/components/mindset/components/PlayerContols/index.tsx b/src/components/mindset/components/PlayerContols/index.tsx index b14bc3b7f..8a15165e1 100644 --- a/src/components/mindset/components/PlayerContols/index.tsx +++ b/src/components/mindset/components/PlayerContols/index.tsx @@ -1,12 +1,10 @@ -import { IconButton } from '@mui/material' import { useCallback, useEffect, useState } from 'react' import styled from 'styled-components' -import PauseIcon from '~/components/Icons/PauseIcon' -import PlayIcon from '~/components/Icons/PlayIcon' import { Flex } from '~/components/common/Flex' import { usePlayerStore } from '~/stores/usePlayerStore' import { NodeExtended } from '~/types' import { colors } from '~/utils/colors' +import { Controls } from './Controls' import { ProgressBar } from './ProgressBar' type Props = { @@ -14,7 +12,7 @@ type Props = { } export const PlayerControl = ({ markers }: Props) => { - const { isPlaying, setIsPlaying, playingNode, playerRef } = usePlayerStore((s) => s) + const { playingNode, playerRef } = usePlayerStore((s) => s) const [currentTime, setCurrentTime] = useState(0) const showPlayer = playingNode @@ -42,45 +40,11 @@ export const PlayerControl = ({ markers }: Props) => { return () => clearInterval(interval) }, [playerRef, setCurrentTime]) - const handleRewind = () => { - if (playerRef) { - const newTime = playerRef.getCurrentTime() - 15 - - playerRef.seekTo(newTime, 'seconds') - } - } - - const handleFastForward = () => { - if (playerRef) { - const newTime = playerRef.getCurrentTime() + 15 - - playerRef.seekTo(newTime, 'seconds') - } - } - const duration = playerRef?.getDuration() || 0 return showPlayer ? ( - - - - - { - setIsPlaying(!isPlaying) - e.stopPropagation() - }} - size="small" - > - {isPlaying ? : } - - - - - - + (({ active, start, text }, ref) => ( + + {start} + + {text} + + +)) + +ParagraphComponent.displayName = 'ParagraphComponent' + +export const Paragraph = memo(ParagraphComponent, (prevProps, nextProps) => prevProps.active === nextProps.active) + +const StyledParagraph = styled(Flex)` + flex-direction: row; + align-items: flex-start; + font-size: 14px; + padding: 8px 24px; + &.active { + background: ${colors.AI_HIGHLIGHT}; + } +` + +const Start = styled.span` + background: ${colors.lightBlue100}; + color: ${colors.lightBlue500}; + padding: 2px; + margin-right: 8px; + border-radius: 4px; +` + +const Words = styled.div` + margin: 0 2px; + word-break: break-word; + + &.active { + background: ${colors.AI_HIGHLIGHT}; + } +` diff --git a/src/components/mindset/components/Sidebar/Transcript/Viewer/index.tsx b/src/components/mindset/components/Sidebar/Transcript/Viewer/index.tsx index 39abaafd6..a1c91fe68 100644 --- a/src/components/mindset/components/Sidebar/Transcript/Viewer/index.tsx +++ b/src/components/mindset/components/Sidebar/Transcript/Viewer/index.tsx @@ -1,10 +1,8 @@ -import clsx from 'clsx' import { useEffect, useRef, useState } from 'react' import styled from 'styled-components' -import { Flex } from '~/components/common/Flex' import { usePlayerStore } from '~/stores/usePlayerStore' -import { colors } from '~/utils' import { secondsToMediaTime } from '~/utils/secondsToMediaTime' +import { Paragraph } from './Paragraph' type Props = { transcriptString: string @@ -101,49 +99,19 @@ export const Viewer = ({ transcriptString }: Props) => { - {start} - - {i.text} - - + active={isActive} + start={start} + text={i.text} + /> ) })} ) } -const Paragraph = styled(Flex)` - flex-direction: row; - align-items: flex-start; - font-size: 14px; - padding: 8px 24px; - &.active { - background: ${colors.AI_HIGHLIGHT}; - } -` - const Wrapper = styled.div` width: 100%; height: 100%; overflow: scroll; padding-right: 4px; ` - -const Start = styled.span` - background: ${colors.lightBlue100}; - color: ${colors.lightBlue500}; - padding: 2px; - margin-right: 8px; - border-radius: 4px; -` - -const Words = styled.div` - margin: 0 2px; - word-break: break-word; - - &.active { - background: ${colors.AI_HIGHLIGHT}; - } -` diff --git a/src/components/mindset/components/Sidebar/Transcript/index.tsx b/src/components/mindset/components/Sidebar/Transcript/index.tsx index 568d5b23f..d77f9820d 100644 --- a/src/components/mindset/components/Sidebar/Transcript/index.tsx +++ b/src/components/mindset/components/Sidebar/Transcript/index.tsx @@ -46,28 +46,29 @@ export const Transcript = () => { }, [playerRef, setCurrentTime]) return ( - - Transcript - {clips.map((clip) => { - const timestamp: string | undefined = clip?.properties?.timestamp + currentTime && ( + + Transcript + {clips.map((clip) => { + const timestamp: string | undefined = clip?.properties?.timestamp - const [start, end] = timestamp - ? (timestamp as string).split('-').map(Number) // Directly convert to numbers - : [0, 0] + const [start, end] = timestamp + ? (timestamp as string).split('-').map(Number) // Directly convert to numbers + : [0, 0] - if (start <= currentTime * 1000 && currentTime * 1000 < end) { - // Multiply playingTime by 1000 to match millisecond format - return ( - - {!clip.properties?.transcript && clip?.properties?.text && {clip?.properties?.text}} - {clip.properties?.transcript && } - - ) - } + if (start <= currentTime * 1000 && currentTime * 1000 < end) { + // Multiply playingTime by 1000 to match millisecond format + return ( + + {clip.properties?.transcript && } + + ) + } - return null - })} - + return null + })} + + ) ) } diff --git a/src/components/mindset/components/Sidebar/index.tsx b/src/components/mindset/components/Sidebar/index.tsx index ea894294d..60af49b0b 100644 --- a/src/components/mindset/components/Sidebar/index.tsx +++ b/src/components/mindset/components/Sidebar/index.tsx @@ -24,7 +24,7 @@ export const SideBar = () => { const Wrapper = styled(Flex)(({ theme }) => ({ position: 'relative', display: 'flex', - padding: '20px', + padding: '33px 20px 20px 20px', background: 'transparent', width: '100%', @@ -45,16 +45,15 @@ const Summary = styled(Text)` ` const EpisodeTitle = styled(Text)` - margin-top: 20px; font-size: 14px; font-weight: 700; line-height: 16.94px; + margin-bottom: 12px; ` const MediaWrapper = styled(Flex)(({ theme }) => ({ width: '100%', - margin: '16px auto', - zIndex: 29, + margin: '0 auto 16px', [theme.breakpoints.up('sm')]: { width: '390px', }, diff --git a/src/components/mindset/components/VideoCard/index.tsx b/src/components/mindset/components/VideoCard/index.tsx index d40c096d6..69c4f4378 100644 --- a/src/components/mindset/components/VideoCard/index.tsx +++ b/src/components/mindset/components/VideoCard/index.tsx @@ -69,7 +69,6 @@ const TextWrapper = styled(Flex)` ` const CardTitle = styled.p` - font-family: Inter; font-size: 16px; font-weight: 500; line-height: 19px; diff --git a/src/network/fetchSourcesData/index.ts b/src/network/fetchSourcesData/index.ts index 9b0b4bb94..1a41c5d0f 100644 --- a/src/network/fetchSourcesData/index.ts +++ b/src/network/fetchSourcesData/index.ts @@ -1,5 +1,6 @@ import { SchemaExtended } from '~/components/ModalsContainer/BlueprintModal/types' import { + FetchDataResponse, FetchEdgesResponse, FetchEdgeTypesResponse, FetchRadarResponse, @@ -10,7 +11,6 @@ import { SubmitErrRes, } from '~/types' import { api } from '../api' -import { ApiResponse } from '~/components/mindset/components/LandingPage' type TradarParams = { skip?: string @@ -180,10 +180,10 @@ export interface UpdateSchemaParams { } } -export const getNodes = async (): Promise => { - const url = `/prediction/graph/search?node_type=['Episode']&&include_properties=true&&includecontent=true` +export const getNodes = async (): Promise => { + const url = `/prediction/graph/search?node_type=['Episode']&include_properties=true&includeContent=true&sort_by=date` - const response = await api.get(url) + const response = await api.get(url) return response } From a2fa0e44a616100252acfdc5754d1ecb29b27f0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D0=B0=D1=81=D1=83=D0=BB?= Date: Thu, 5 Dec 2024 17:18:03 +0300 Subject: [PATCH 2/3] feat: update condition --- .../components/Sidebar/Transcript/index.tsx | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/components/mindset/components/Sidebar/Transcript/index.tsx b/src/components/mindset/components/Sidebar/Transcript/index.tsx index d77f9820d..c2245e2dd 100644 --- a/src/components/mindset/components/Sidebar/Transcript/index.tsx +++ b/src/components/mindset/components/Sidebar/Transcript/index.tsx @@ -45,31 +45,29 @@ export const Transcript = () => { return () => clearInterval(interval) }, [playerRef, setCurrentTime]) - return ( - currentTime && ( - - Transcript - {clips.map((clip) => { - const timestamp: string | undefined = clip?.properties?.timestamp + return currentTime ? ( + + Transcript + {clips.map((clip) => { + const timestamp: string | undefined = clip?.properties?.timestamp - const [start, end] = timestamp - ? (timestamp as string).split('-').map(Number) // Directly convert to numbers - : [0, 0] + const [start, end] = timestamp + ? (timestamp as string).split('-').map(Number) // Directly convert to numbers + : [0, 0] - if (start <= currentTime * 1000 && currentTime * 1000 < end) { - // Multiply playingTime by 1000 to match millisecond format - return ( - - {clip.properties?.transcript && } - - ) - } + if (start <= currentTime * 1000 && currentTime * 1000 < end) { + // Multiply playingTime by 1000 to match millisecond format + return ( + + {clip.properties?.transcript && } + + ) + } - return null - })} - - ) - ) + return null + })} + + ) : null } const Wrapper = styled(Flex)` From 525f52fe20871a9ef4df414f1ff23e0f89ebdc63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D0=B0=D1=81=D1=83=D0=BB?= Date: Thu, 5 Dec 2024 17:25:55 +0300 Subject: [PATCH 3/3] feat: fixed unit tests --- src/components/App/ActionsToolbar/PlayerControl/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/App/ActionsToolbar/PlayerControl/index.tsx b/src/components/App/ActionsToolbar/PlayerControl/index.tsx index a4e65546b..ec9de2600 100644 --- a/src/components/App/ActionsToolbar/PlayerControl/index.tsx +++ b/src/components/App/ActionsToolbar/PlayerControl/index.tsx @@ -54,7 +54,7 @@ export const PlayerControl = () => { const showPlayer = (sidebarIsOpen && selectedNode?.ref_id !== playingNode?.ref_id) || (playingNode && !sidebarIsOpen) - const isMindset = window.location?.hostname === 'graphmindset.sphinx.chat' || window.location.hostname === 'localhost' + const isMindset = window.location?.hostname === 'graphmindset.sphinx.chat' return miniPlayerIsVisible && playingNode && showPlayer && !isMindset ? (