diff --git a/apps/extension/src/contentscript/multitable-panel/multitable-panel.tsx b/apps/extension/src/contentscript/multitable-panel/multitable-panel.tsx index 683e83cc..7800280e 100644 --- a/apps/extension/src/contentscript/multitable-panel/multitable-panel.tsx +++ b/apps/extension/src/contentscript/multitable-panel/multitable-panel.tsx @@ -2,12 +2,8 @@ import { EntitySourceType } from '@mweb/backend' import { useMutableWeb } from '@mweb/engine' import { EventEmitter as NEventEmitter } from 'events' import React, { FC, useEffect, useRef, useState } from 'react' -import Draggable from 'react-draggable' import styled from 'styled-components' import { NearNetworkId } from '../../common/networks' -import { getIsPanelUnpinned, removePanelUnpinnedFlag, setPanelUnpinnedFlag } from '../storage' -import { PinOutlineIcon, PinSolidIcon } from './assets/vectors' -import { Dropdown } from './components/dropdown' import { MutationEditorModal } from './components/mutation-editor-modal' import MutableOverlayContainer from './mutable-overlay-container' @@ -54,62 +50,6 @@ const WrapperPanel = styled.div<{ $isAnimated?: boolean }>` } ` -const Notch = styled.div<{ $isAnimated?: boolean; $isOpen?: boolean }>` - position: relative; - display: flex; - align-items: stretch; - -webkit-tap-highlight-color: rgba(255, 255, 255, 0); - -webkit-tap-highlight-color: transparent; - user-select: none; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-text-size-adjust: none; - -webkit-overflow-scrolling: touch; - - width: 318px; - height: 45px; - border-radius: ${(props) => (props.$isOpen ? '0' : '0 0 6px 6px')}; - background: #384bff; - box-shadow: 0 4px 5px rgb(45 52 60 / 10%), 0 4px 20px rgb(11 87 111 / 15%); - opacity: 0; - transform: translateY(-100%); - transition: ${(props) => - props.$isAnimated ? 'opacity 0.3s ease-in-out, transform 0.3s ease-in-out' : 'initial'}; - - justify-content: space-between; - padding: 4px 5px; - padding-top: 0; -` - -const NotchButtonWrapper = styled.div` - width: 16px; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - - &:hover, - &:focus { - opacity: 0.5; - } -` - -const IconWrapper = styled.div` - display: flex; - flex-direction: column; - align-items: center; - justify-content: space-between; -` - -const DragIcon = () => ( - - - - - -) - interface MultitablePanelProps { eventEmitter: NEventEmitter } @@ -117,20 +57,9 @@ interface MultitablePanelProps { export const MultitablePanel: FC = ({ eventEmitter }) => { const { mutations, allApps, selectedMutation, config } = useMutableWeb() const [isOverlayOpened, setIsOverlayOpened] = useState(false) - const [isPin, setPin] = useState(!getIsPanelUnpinned()) - const [isDragging, setIsDragging] = useState(false) - const [isNotchDisplayed, setIsNotchDisplayed] = useState(true) const [isModalOpen, setIsModalOpen] = useState(false) const notchRef = useRef(null) - useEffect(() => { - const timer = setTimeout(() => { - setIsNotchDisplayed(false) - }, 5000) - - return () => clearTimeout(timer) - }, [isPin]) - useEffect(() => { const openMutationPopupCallback = () => { setIsModalOpen(true) @@ -141,23 +70,6 @@ export const MultitablePanel: FC = ({ eventEmitter }) => { } }, [eventEmitter]) - const handleStartDrag = () => { - setIsDragging(true) - } - - const handleStopDrag = () => { - setIsDragging(false) - } - - const handlePin = () => { - if (isPin) { - setPanelUnpinnedFlag('unpin') - } else { - removePanelUnpinnedFlag() - } - setPin(!isPin) - } - const handleMutateButtonClick = () => { setIsModalOpen(true) setIsOverlayOpened(false) @@ -180,7 +92,7 @@ export const MultitablePanel: FC = ({ eventEmitter }) => { open={isOverlayOpened} handleMutateButtonClick={handleMutateButtonClick} /> - + {isModalOpen ? ( = ({ eventEmitter }) => { localMutations={mutations.filter((m) => m.source === EntitySourceType.Local)} onClose={handleModalClose} /> - ) : ( - - - - - - - - - - {isPin ? : } - - - - )} + ) : null} ) diff --git a/libs/shared-components/src/mini-overlay/assets/icons/icon-dropdown.tsx b/libs/shared-components/src/mini-overlay/assets/icons/icon-dropdown.tsx new file mode 100644 index 00000000..d7d29436 --- /dev/null +++ b/libs/shared-components/src/mini-overlay/assets/icons/icon-dropdown.tsx @@ -0,0 +1,17 @@ +import React from 'react' + +const IconDropdown = () => ( + + + + + +) + +export default IconDropdown diff --git a/libs/shared-components/src/mini-overlay/assets/icons/index.ts b/libs/shared-components/src/mini-overlay/assets/icons/index.ts index de426a00..ce32893b 100644 --- a/libs/shared-components/src/mini-overlay/assets/icons/index.ts +++ b/libs/shared-components/src/mini-overlay/assets/icons/index.ts @@ -13,6 +13,7 @@ import OpenOverlay from './open-overlay' import OpenOverlayWithCircle from './open-overlay-with-circle' import Logo from './logo' import PersonAddAlt from './person-add-alt' +import IconDropdown from './icon-dropdown' export { MutationFallbackIcon, @@ -30,4 +31,5 @@ export { OpenOverlayWithCircle, Logo, PersonAddAlt, + IconDropdown, } diff --git a/libs/shared-components/src/multitable-panel/assets/styles-dropdown.tsx b/libs/shared-components/src/multitable-panel/assets/styles-dropdown.tsx index 548014e2..52ba14dd 100644 --- a/libs/shared-components/src/multitable-panel/assets/styles-dropdown.tsx +++ b/libs/shared-components/src/multitable-panel/assets/styles-dropdown.tsx @@ -69,9 +69,11 @@ export const ButtonBack = styled.div` padding-bottom: 10px; padding-top: 10px; transition: all 0.2s ease; + svg { margin-right: 5px; } + &:hover { background: rgba(56, 75, 255, 0.1); border-radius: 4px; @@ -94,47 +96,39 @@ export const ButtonMutation = styled.div` padding-bottom: 10px; padding-top: 10px; transition: all 0.2s ease; + svg { margin-left: 5px; } + &:hover { background: rgba(56, 75, 255, 0.1); border-radius: 4px; } ` -export const ListMutations = styled.div` - width: 100%; - display: flex; - flex-direction: column; - gap: 3px; - z-index: 1; -` - export const InputBlock = styled.div<{ isActive?: boolean }>` display: flex; - padding: 2px 4px; cursor: pointer; - align-items: center; width: 100%; - color: ${(props) => (props.isActive ? '#384BFF' : '#7A818B')}; border-radius: 4px; - .inputMutation { - color: ${(props) => (props.isActive ? '#384BFF' : '#7A818B')}; - } - &:hover { background: #384bff; + color: #fff; - div, - span { + .inputMutation { color: #fff; } + .authorMutation { + color: #fff; + } + + div, svg { fill: #fff; @@ -143,6 +137,10 @@ export const InputBlock = styled.div<{ isActive?: boolean }>` } } } + + .inputMutation { + color: ${(props) => (props.isActive ? '#384BFF' : '#7A818B')}; + } ` export const InputIconWrapper = styled.div` display: flex; @@ -172,23 +170,20 @@ export const InputIconWrapper = styled.div` export const InputInfoWrapper = styled.div` display: flex; - padding: 4px; - padding-left: 6px; + margin-left: 10px; cursor: pointer; - position: relative; - flex-direction: column; align-items: flex-start; flex: 1; .inputMutationSelected { - color: rgba(34, 34, 34, 1); + color: #fff; } .authorMutationSelected { - color: #384bff; + color: #fff; } ` export const ImageBlock = styled.div` @@ -206,6 +201,77 @@ export const ImageBlock = styled.div` } ` +export const ListMutations = styled.div` + width: 100%; + display: flex; + flex-direction: column; + gap: 3px; + z-index: 1; + + .active-mutation { + background: #384bff; + color: #fff; + + svg path { + stroke: #fff; + fill: #384bff; + } + + &:hover { + background: #fff; + color: #384bff; + + svg path { + stroke: #384bff; + fill: #384bff; + } + + .infoSelected{ + .inputMutationSelected { + color: #384bff; + } + + .authorMutationSelected { + color: #384bff; + } + } + + .mutation-version-dropdown { + background: rgba(56, 75, 255, 0.1); + color: #384bff; + + svg path { + stroke: #384bff; + } + } + } +` + +export const SpanStyled = styled.span<{ $isWhite?: boolean }>` + display: flex; + align-items: center; + gap: 2px; + position: relative; + top: 0; + cursor: pointer; + left: ${({ $isWhite }) => ($isWhite ? `0` : '-6px')}; + justify-content: center; + padding: 2px 0; + padding-left: 4px; + width: 100%; + height: 100%; + border-radius: 4px; + font-size: 10px; + font-weight: 400; + text-align: left; + color: #ffffff; + background: ${({ $isWhite }) => ($isWhite ? `#FFFFFF` : '#384bff')}; + + svg path { + stroke: ${({ $isWhite }) => ($isWhite ? ` #7a818b` : '#FFFFFF')}; + } +` + export const AvalibleMutations = styled.div` width: 100%; background: #f8f9ff; @@ -215,7 +281,6 @@ export const AvalibleMutations = styled.div` flex-direction: column; box-sizing: border-box; padding: 10px; - z-index: 1; .avalibleMutationsInput { background: rgba(248, 249, 255, 1); @@ -236,6 +301,7 @@ export const AvalibleLableBlock = styled.div` align-items: center; justify-content: space-between; width: 100%; + .iconRotate { svg { transform: rotate(0deg); @@ -257,6 +323,7 @@ export const AvalibleArrowBlock = styled.div` justify-content: space-between; transition: all 0.2s ease; cursor: pointer; + svg { margin-left: 10px; transform: rotate(180deg); @@ -276,8 +343,8 @@ export const InputMutation = styled.span` color: rgba(34, 34, 34, 0.6); white-space: nowrap; - overflow: hidden; text-overflow: ellipsis; + column-gap: 8px; width: 180px; display: inline-flex; align-items: center; diff --git a/libs/shared-components/src/multitable-panel/components/dropdown.tsx b/libs/shared-components/src/multitable-panel/components/dropdown.tsx index 7f38169f..5549e096 100644 --- a/libs/shared-components/src/multitable-panel/components/dropdown.tsx +++ b/libs/shared-components/src/multitable-panel/components/dropdown.tsx @@ -33,6 +33,7 @@ import { import { Badge } from './badge' import { Image } from './image' import { ModalDelete } from './modal-delete' +import { MutationVersionDropdown } from './mutation-version-dropdown' const ModalConfirmBackground = styled.div` position: absolute; @@ -65,6 +66,8 @@ export const Dropdown: FC = ({ onMutateButtonClick }: DropdownPro } = useMutableWeb() const { deleteLocalMutation } = useDeleteLocalMutation() + const [expandedVersion, setExpandedVersion] = useState(false) + const toggleDropdown = () => setExpandedVersion(!expandedVersion) const recentlyUsedMutations = useMemo( () => @@ -168,11 +171,26 @@ export const Dropdown: FC = ({ onMutateButtonClick }: DropdownPro // fallbackUrl={defaultIcon} /> - handleMutationClick(mut.id)}> + handleMutationClick(mut.id)} + > {/* todo: mocked classname */} + + {mut.id === selectedMutation?.id ? ( + + ) : null} {mut.metadata ? mut.metadata.name : ''}{' '} {recentlyUsedMutations[mut.id]?.length === 2 ? ( mut.source === EntitySourceType.Local ? ( @@ -188,9 +206,9 @@ export const Dropdown: FC = ({ onMutateButtonClick }: DropdownPro {mut.authorId ? ( by {mut.authorId} diff --git a/libs/shared-components/src/multitable-panel/components/mutation-version-dropdown.tsx b/libs/shared-components/src/multitable-panel/components/mutation-version-dropdown.tsx new file mode 100644 index 00000000..9bddd354 --- /dev/null +++ b/libs/shared-components/src/multitable-panel/components/mutation-version-dropdown.tsx @@ -0,0 +1,207 @@ +import { useMutableWeb, useMutationVersions } from '@mweb/engine' +import React, { useState } from 'react' +import { FC } from 'react' +import { IconDropdown } from '../../mini-overlay/assets/icons' +import styled from 'styled-components' + +export const SpanStyled = styled.span<{ $isWhite?: boolean; $isExpanded?: boolean }>` + display: flex; + align-items: center; + gap: 2px; + cursor: pointer; + justify-content: ${({ $isExpanded }) => ($isExpanded ? `center` : 'flex-start')}; + padding-left: ${({ $isExpanded }) => ($isExpanded ? `4px` : '6px')}; + width: 100%; + height: 100%; + border-radius: 4px; + font-size: 10px; + font-weight: 400; + text-align: left; + color: #ffffff; + background: ${({ $isWhite }) => ($isWhite ? `#FFFFFF` : '#384bff')}; + + svg path { + stroke: ${({ $isWhite }) => ($isWhite ? ` #7a818b` : '#FFFFFF')}; + } +` + +export const OpenListDefault = styled.span` + cursor: pointer; + display: flex; + align-items: center; + justify-content: flex-end; + @keyframes rotateIsClose { + 0% { + transform: rotate(180deg); + } + + 50% { + transform: rotate(90deg); + } + + 100% { + transform: rotate(0deg); + } + } + animation: rotateIsClose 0.2s ease forwards; + transition: all 0.3s; + &:hover { + svg { + transform: scale(1.2); + } + } +` + +export const OpenList = styled.span` + cursor: pointer; + + display: flex; + align-items: center; + justify-content: flex-end; + @keyframes rotateIsOpen { + 0% { + transform: rotate(0deg); + } + + 50% { + transform: rotate(90deg); + } + + 100% { + transform: rotate(180deg); + } + } + animation: rotateIsOpen 0.2s ease forwards; + transition: all 0.3s; + &:hover { + svg { + transform: scale(1.2); + } + } +` + +export const DropdownContainer = styled.div<{ $expanded?: boolean }>` + position: absolute; + width: 100%; + width: 50px; + height: auto; + top: 24px; + left: 2px; + padding: 2px; + border-radius: 4px; + background: #fff; + display: flex; + flex-direction: column; + z-index: 2; + + box-shadow: ${({ $expanded }) => + $expanded + ? `0px 3px 7px 0px #2222221A, + 0px 12px 12px 0px #22222217, + 0px 27px 16px 0px #2222220D, + 0px 48px 19px 0px #22222203, + 0px 76px 21px 0px #22222200` + : 'none'}; + + cursor: pointer; +` + +export const DropdownItem = styled.div<{ $isActiveVersion?: boolean }>` + font-size: 10px; + font-weight: 400; + text-align: right; + color: ${({ $isActiveVersion }) => ($isActiveVersion ? `#384BFF` : '#7a818b')}; + padding: 4px; + + &:hover { + background: #1879ce1a; + color: #384bff; + } +` + +const LatestKey = 'latest' + +export const MutationVersionDropdown: FC<{ + mutationId: string | null + toggleDropdown: () => void + expanded: boolean + isWhite?: boolean +}> = ({ mutationId, isWhite, toggleDropdown, expanded }) => { + const { + switchMutationVersion, + selectedMutation, + mutationVersions: currentMutationVersions, + } = useMutableWeb() + const { mutationVersions, areMutationVersionsLoading } = useMutationVersions(mutationId) + + if (!mutationId) { + return null + } + + if (!selectedMutation || areMutationVersionsLoading) { + return + } + + const handleChange = (key: string) => { + if (selectedMutation?.id) { + switchMutationVersion(selectedMutation?.id, key === LatestKey ? null : key?.toString()) + } + } + + return ( + <> + 0 ? '50px' : '40px', + width: '100%', + display: 'inline-flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + position: 'relative', + boxSizing: isWhite ? 'border-box' : undefined, + marginLeft: isWhite ? '10px' : '', + borderRadius: isWhite ? '4px' : '', + }} + onClick={toggleDropdown} + > + 0} + className="mutation-version-dropdown" + > + {currentMutationVersions[mutationId] + ? `v${currentMutationVersions[mutationId]}` + : LatestKey} + {mutationVersions && mutationVersions.length > 0 ? ( + expanded ? ( + + + + ) : ( + + + + ) + ) : null} + + + {mutationVersions && mutationVersions.length > 0 + ? expanded && ( + + {mutationVersions.map((version) => ( + handleChange(version.version)} + key={version.version} + > + v{version.version} + + ))} + + ) + : null} + + + ) +}