diff --git a/packages/extension-polkagate/src/components/Convictions.tsx b/packages/extension-polkagate/src/components/Convictions.tsx index 47c83dd35..52b43647c 100644 --- a/packages/extension-polkagate/src/components/Convictions.tsx +++ b/packages/extension-polkagate/src/components/Convictions.tsx @@ -18,7 +18,7 @@ interface Props { export const DEFAULT_CONVICTION = 1; -export default function Convictions ({ address, children, conviction, setConviction, style }: Props): React.ReactElement { +export default function Convictions({ address, children, conviction, setConviction, style }: Props): React.ReactElement { const { t } = useTranslation(); const theme = useTheme(); @@ -39,14 +39,13 @@ export default function Convictions ({ address, children, conviction, setConvict const info = useMemo((): string => { const newText = convictionOptions?.find(({ value }) => value === (conviction || DEFAULT_CONVICTION))?.text; const match = newText?.match(/\(([^)]+)\)/); - const result = match ? match[1] : '0 days'; - return 'Tokens will be locked for ' + result; + return match ? match[1] : '0 days'; }, [conviction, convictionOptions]); const marks = useMemo(() => convictionOptions?.map(({ value }) => ({ label: `${value} X`, value: value as number })) - , [convictionOptions]); + , [convictionOptions]); const valuetext = useCallback((value: number) => { return `${value} X`; @@ -84,6 +83,7 @@ export default function Convictions ({ address, children, conviction, setConvict size='small' step={null} sx={{ + mx:'10px', '& .MuiSlider-rail': { color: 'action.focus' // Non-selected track color }, @@ -97,9 +97,17 @@ export default function Convictions ({ address, children, conviction, setConvict valueLabelDisplay='auto' /> {children} - - {t(info)} - + + + + {t('Tokens will be locked for')} + + + + {info} + + + ); } diff --git a/packages/extension-polkagate/src/fullscreen/governance/components/DraggableModalWithTitle.tsx b/packages/extension-polkagate/src/fullscreen/governance/components/DraggableModalWithTitle.tsx new file mode 100644 index 000000000..90a1fffa1 --- /dev/null +++ b/packages/extension-polkagate/src/fullscreen/governance/components/DraggableModalWithTitle.tsx @@ -0,0 +1,106 @@ +// Copyright 2019-2024 @polkadot/extension-polkagate authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +/* eslint-disable react/jsx-max-props-per-line */ + +import type { IconDefinition } from '@fortawesome/fontawesome-svg-core'; + +import { Box, Modal, useTheme } from '@mui/material'; +import React, { useCallback, useMemo, useState } from 'react'; + +import ModalTitleWithDrag from '../../partials/ModalTitleWithDrag'; + +interface Props { + width?: number; + maxHeight?: number; + minHeight?: number; + children: React.ReactElement; + open: boolean; + onClose: () => void + title: string; + icon?: string | IconDefinition; +} + +export function DraggableModalWithTitle ({ children, icon, maxHeight = 740, minHeight = 615, onClose, open, title, width = 500 }: Props): React.ReactElement { + const theme = useTheme(); + + const isDarkMode = useMemo(() => theme.palette.mode === 'dark', [theme.palette.mode]); + + const [isDragging, setIsDragging] = useState(false); + const initialX = (window.innerWidth - width) / 2; + const initialY = (window.innerHeight - maxHeight) / 2; + + const [modalPosition, setModalPosition] = useState({ x: initialX, y: initialY }); + const [dragStartPosition, setDragStartPosition] = useState({ x: 0, y: 0 }); + + const handleMouseDown = useCallback((e: { clientX: number; clientY: number; }) => { + setIsDragging(true); + setDragStartPosition({ x: e.clientX, y: e.clientY }); + }, []); + + const _onClose = useCallback((_event: unknown, reason: string) => { + if (reason && reason === 'backdropClick') { + return; + } + + onClose(); + }, [onClose]); + + const handleMouseMove = useCallback((e: { clientX: number; clientY: number; }) => { + if (isDragging) { + const dx = e.clientX - dragStartPosition.x; + const dy = e.clientY - dragStartPosition.y; + + setModalPosition((prevPosition) => ({ + x: prevPosition.x + dx, + y: prevPosition.y + dy + })); + setDragStartPosition({ x: e.clientX, y: e.clientY }); + } + }, [dragStartPosition, isDragging]); + + const handleMouseUp = useCallback(() => { + setIsDragging(false); + }, []); + + const style = { + '&:focus': { + outline: 'none' // Remove outline when Box is focused + }, + bgcolor: 'background.default', + border: isDarkMode ? '0.5px solid' : 'none', + borderColor: 'secondary.light', + borderRadius: '10px', + boxShadow: 24, + cursor: isDragging ? 'grabbing' : 'grab', + left: modalPosition.x, + maxHeight: `${maxHeight}px`, + minHeight: `${minHeight}px`, + pb: 3, + position: 'absolute', + pt: 2, + px: 4, + top: modalPosition.y, + width: `${width}px` + }; + + return ( + + + + {children} + + + ); +} diff --git a/packages/extension-polkagate/src/fullscreen/governance/post/castVote/index.tsx b/packages/extension-polkagate/src/fullscreen/governance/post/castVote/index.tsx index b5abaadcc..e13196e98 100644 --- a/packages/extension-polkagate/src/fullscreen/governance/post/castVote/index.tsx +++ b/packages/extension-polkagate/src/fullscreen/governance/post/castVote/index.tsx @@ -18,8 +18,7 @@ import { cryptoWaitReady } from '@polkadot/util-crypto'; import { useInfo, useProxies, useTranslation } from '../../../../hooks'; import { PROXY_TYPE } from '../../../../util/constants'; import { amountToHuman, amountToMachine } from '../../../../util/utils'; -import SimpleModalTitle from '../../../partials/SimpleModalTitle'; -import { DraggableModal } from '../../components/DraggableModal'; +import { DraggableModalWithTitle } from '../../components/DraggableModalWithTitle'; import SelectProxyModal2 from '../../components/SelectProxyModal2'; import WaitScreen from '../../partials/WaitScreen'; import { getVoteType } from '../../utils/util'; @@ -187,13 +186,8 @@ export default function Index ({ address, cantModify, hasVoted, myVote, notVoted }, [notVoted, step]); return ( - + <> - {step === STEPS.ABOUT && } - + ); } diff --git a/packages/extension-polkagate/src/fullscreen/partials/ModalTitleWithDrag.tsx b/packages/extension-polkagate/src/fullscreen/partials/ModalTitleWithDrag.tsx new file mode 100644 index 000000000..504f458bb --- /dev/null +++ b/packages/extension-polkagate/src/fullscreen/partials/ModalTitleWithDrag.tsx @@ -0,0 +1,70 @@ +// Copyright 2019-2024 @polkadot/extension-polkagate authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +/* eslint-disable react/jsx-max-props-per-line */ + +import type { IconDefinition, IconProp } from '@fortawesome/fontawesome-svg-core'; + +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Close as CloseIcon, DragIndicator as DragIndicatorIcon } from '@mui/icons-material'; +import { Divider, Grid, IconButton, Typography, useTheme } from '@mui/material'; +import React from 'react'; + +import { Infotip2, VaadinIcon } from '../../components'; +import { useTranslation } from '../../hooks'; + +interface Props { + onClose: () => void; + title: string; + icon?: string | IconDefinition; + onMouseDown: (e: { clientX: number; clientY: number; }) => void; + onMouseMove?: (e: { clientX: number; clientY: number; }) => void; + onMouseUp?: () => void +} + +export default function ModalTitleWithDrag ({ icon, onClose, onMouseDown, onMouseMove, onMouseUp, title }: Props): React.ReactElement { + const theme = useTheme(); + const { t } = useTranslation(); + + const isIconVaadin = typeof icon === 'string' && icon?.startsWith('vaadin'); + const isIconFontAwesome = !!icon; + + return ( + + + {icon && + <> + {isIconVaadin + ? + : isIconFontAwesome + ? + : <> + } + } + + {title} + + + + + + + + + + + + + + + ); +}