From e197b7b98a1def15837f3958f6164180f526275c Mon Sep 17 00:00:00 2001 From: root Date: Fri, 27 Dec 2024 05:42:14 +0000 Subject: [PATCH 1/3] feat: Added Panel component to sistent Signed-off-by: root --- package-lock.json | 45 +++- package.json | 2 + src/custom/Panel/Panel.tsx | 237 ++++++++++++++++++ src/custom/Panel/index.tsx | 3 + src/custom/index.tsx | 1 + .../PanelDragHandle/PanelDragHandleIcon.tsx | 34 +++ src/icons/PanelDragHandle/index.tsx | 1 + 7 files changed, 320 insertions(+), 3 deletions(-) create mode 100644 src/custom/Panel/Panel.tsx create mode 100644 src/custom/Panel/index.tsx create mode 100644 src/icons/PanelDragHandle/PanelDragHandleIcon.tsx create mode 100644 src/icons/PanelDragHandle/index.tsx diff --git a/package-lock.json b/package-lock.json index 0034a390..ed4e5204 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,8 @@ "dependencies": { "js-yaml": "^4.1.0", "lodash": "^4.17.21", + "re-resizable": "^6.10.3", + "react-draggable": "^4.4.6", "react-share": "^5.1.0" }, "devDependencies": { @@ -4530,7 +4532,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", - "dev": true, "engines": { "node": ">=6" } @@ -11503,6 +11504,16 @@ "performance-now": "^2.1.0" } }, + "node_modules/re-resizable": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-6.10.3.tgz", + "integrity": "sha512-zvWb7X3RJMA4cuSrqoxgs3KR+D+pEXnGrD2FAD6BMYAULnZsSF4b7AOVyG6pC3VVNVOtlagGDCDmZSwWLjjBBw==", + "license": "MIT", + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -11559,6 +11570,20 @@ "react": "^18.2.0" } }, + "node_modules/react-draggable": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.6.tgz", + "integrity": "sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==", + "license": "MIT", + "dependencies": { + "clsx": "^1.1.1", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": ">= 16.3.0", + "react-dom": ">= 16.3.0" + } + }, "node_modules/react-error-boundary": { "version": "4.0.12", "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.12.tgz", @@ -17372,8 +17397,7 @@ "clsx": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", - "dev": true + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" }, "co": { "version": "4.6.0", @@ -22160,6 +22184,12 @@ "performance-now": "^2.1.0" } }, + "re-resizable": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-6.10.3.tgz", + "integrity": "sha512-zvWb7X3RJMA4cuSrqoxgs3KR+D+pEXnGrD2FAD6BMYAULnZsSF4b7AOVyG6pC3VVNVOtlagGDCDmZSwWLjjBBw==", + "requires": {} + }, "react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -22206,6 +22236,15 @@ "scheduler": "^0.23.0" } }, + "react-draggable": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.6.tgz", + "integrity": "sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==", + "requires": { + "clsx": "^1.1.1", + "prop-types": "^15.8.1" + } + }, "react-error-boundary": { "version": "4.0.12", "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.12.tgz", diff --git a/package.json b/package.json index 04cee394..8436340c 100644 --- a/package.json +++ b/package.json @@ -118,6 +118,8 @@ "dependencies": { "js-yaml": "^4.1.0", "lodash": "^4.17.21", + "re-resizable": "^6.10.3", + "react-draggable": "^4.4.6", "react-share": "^5.1.0" } } diff --git a/src/custom/Panel/Panel.tsx b/src/custom/Panel/Panel.tsx new file mode 100644 index 00000000..2de7e48e --- /dev/null +++ b/src/custom/Panel/Panel.tsx @@ -0,0 +1,237 @@ +import { ListItemProps, styled } from '@mui/material'; +import { Resizable } from 're-resizable'; +import React from 'react'; +import Draggable from 'react-draggable'; +import { Box, BoxProps, IconButton, ListItem, Tooltip } from '../../base'; +import { CloseIcon, CollapseAllIcon, ExpandAllIcon } from '../../icons'; +import { PanelDragHandleIcon } from '../../icons/PanelDragHandle'; +import { useTheme } from '../../theme'; +import { ErrorBoundary } from '../ErrorBoundary'; + +export const ListHeader = styled(ListItem)(({ theme }) => ({ + padding: theme.spacing(0.5, 0.5), + marginBlock: theme.spacing(1), + '& .MuiListItemText-primary': { + fontSize: '1rem', + textTransform: 'capitalize', + fontWeight: 700 + }, + cursor: 'pointer', + '&:hover': { + backgroundColor: theme.palette.action.hover + }, + '& .MuiSvgIcon-root': { + opacity: 0, + transition: 'opacity 0.2s' + }, + '&:hover .MuiSvgIcon-root': { + opacity: 1 + } +})); + +interface CustomListItemProps extends ListItemProps { + isVisible: boolean; +} + +// Use the new interface in the styled component +export const StyledListItem = styled(ListItem, { + shouldForwardProp: (props) => props !== 'isVisible' +})(({ theme, isVisible }) => ({ + padding: theme.spacing(0.05, 0.5), + fontStyle: isVisible ? 'normal' : 'italic', + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + '& .MuiSvgIcon-root': { + height: 20, + width: 20 + }, + '& .MuiListItemIcon-root': { + minWidth: 0, + opacity: isVisible ? 0.8 : 0.3 + }, + '& .MuiTypography-root': { + fontSize: '0.9rem', + opacity: isVisible ? 1 : 0.5 + } +})); + +type PanelProps = { + isOpen: boolean; + children: React.ReactNode; + areAllExpanded?: boolean; + toggleExpandAll?: () => void; + handleClose: () => void; + sx?: BoxProps['sx']; + id?: string; + intitialPosition?: { + left?: string | number; + right?: string | number; + top?: string | number; + bottom?: string | number; + }; +}; + +export const DrawerHeader = styled('div')(({ theme }) => ({ + display: 'flex', + alignItems: 'center', + padding: theme.spacing(4, 2), + alignContent: 'stretch', + justifyContent: 'space-between', + cursor: 'move', + background: + theme.palette.mode === 'light' + ? 'linear-gradient(90deg, #3B687B 0%, #507D90 100%)' + : 'linear-gradient(90deg, #28353A 0%, #3D4F57 100%)', + height: '3rem', + flexShrink: 0 +})); + +const PanelBody = styled(Box)(({ theme }) => ({ + padding: theme.spacing(2), + backgroundColor: theme.palette.background.surfaces, + overflow: 'auto', + flex: 1, + minHeight: 0 +})); + +// New container for Resizable content +const ResizableContent = styled('div')({ + height: '100%', + display: 'flex', + flexDirection: 'column', + minHeight: '3rem' +}); + +// // watches for the size of the element +// const useDimensions = (ref: React.RefObject) => { +// const [dimensions, setDimensions] = React.useState({ width: 0, height: 0 }); +// React.useEffect(() => { +// const { current } = ref; +// if (current) { +// const resizeObserver = new ResizeObserver((entries) => { +// entries.forEach((entry) => { +// setDimensions({ +// width: entry.contentRect.width, +// height: entry.contentRect.height +// }); +// }); +// }); +// resizeObserver.observe(current); +// return () => { +// resizeObserver.unobserve(current); +// }; +// } +// }, [ref]); +// return dimensions; +// }; + +const Panel_: React.FC = ({ + isOpen, + id = 'panel', + children, + areAllExpanded, + toggleExpandAll, + handleClose, + intitialPosition, + sx +}) => { + const theme = useTheme(); + // const mode = theme?.palette?.type; + if (!isOpen) return null; + return ( + // + + + { + window.dispatchEvent(new Event('panel-resize')); + }} + enable={{ + top: true, + right: true, + bottom: true, + left: true, + topRight: true, + bottomRight: true, + bottomLeft: true, + topLeft: true + }} + > + + +
+ + + {toggleExpandAll && ( + + + {areAllExpanded ? : } + + + )} + + +
+
+ + + +
+
+
+ + {children} +
+
+
+
+
+ //
+ ); +}; + +export const Panel: React.FC = ({ ...props }) => { + return ( + // + + // + ); +}; diff --git a/src/custom/Panel/index.tsx b/src/custom/Panel/index.tsx new file mode 100644 index 00000000..0abd9a3c --- /dev/null +++ b/src/custom/Panel/index.tsx @@ -0,0 +1,3 @@ +import { Panel } from './Panel'; + +export { Panel }; diff --git a/src/custom/index.tsx b/src/custom/index.tsx index ac4022ff..0da7c198 100644 --- a/src/custom/index.tsx +++ b/src/custom/index.tsx @@ -56,6 +56,7 @@ export { InputSearchField } from './InputSearchField'; export { LearningContent } from './LearningContent'; export { NavigationNavbar } from './NavigationNavbar'; export { Note } from './Note'; +export { Panel } from './Panel'; export { PerformersSection, PerformersSectionButton } from './PerformersSection'; export { SetupPreReq } from './SetupPrerequisite'; export { StyledChapter } from './StyledChapter'; diff --git a/src/icons/PanelDragHandle/PanelDragHandleIcon.tsx b/src/icons/PanelDragHandle/PanelDragHandleIcon.tsx new file mode 100644 index 00000000..b6fe307e --- /dev/null +++ b/src/icons/PanelDragHandle/PanelDragHandleIcon.tsx @@ -0,0 +1,34 @@ +import { FC } from 'react'; +import { IconProps } from '../types'; + +export const PanelDragHandleIcon: FC = ({ + height = 24, + width = 24, + fill = 'currentColor', + ...props +}) => { + return ( + + + + + + + + + + + ); +}; + +export default PanelDragHandleIcon; diff --git a/src/icons/PanelDragHandle/index.tsx b/src/icons/PanelDragHandle/index.tsx new file mode 100644 index 00000000..3abe60e3 --- /dev/null +++ b/src/icons/PanelDragHandle/index.tsx @@ -0,0 +1 @@ +export { default as PanelDragHandleIcon } from './PanelDragHandleIcon'; From 7061c6e2aa33c236373c21a8f5eef522c9336417 Mon Sep 17 00:00:00 2001 From: Vidit-Kushwaha Date: Fri, 27 Dec 2024 10:07:37 +0000 Subject: [PATCH 2/3] fix: seperated logic of styling in Panel Signed-off-by: Vidit-Kushwaha --- src/custom/Panel/Panel.tsx | 119 +----------------- src/custom/Panel/style.tsx | 80 ++++++++++++ .../PanelDragHandle/PanelDragHandleIcon.tsx | 2 +- 3 files changed, 85 insertions(+), 116 deletions(-) create mode 100644 src/custom/Panel/style.tsx diff --git a/src/custom/Panel/Panel.tsx b/src/custom/Panel/Panel.tsx index 2de7e48e..ff5c20d4 100644 --- a/src/custom/Panel/Panel.tsx +++ b/src/custom/Panel/Panel.tsx @@ -1,60 +1,12 @@ -import { ListItemProps, styled } from '@mui/material'; import { Resizable } from 're-resizable'; import React from 'react'; import Draggable from 'react-draggable'; -import { Box, BoxProps, IconButton, ListItem, Tooltip } from '../../base'; +import { Box, BoxProps, IconButton, Tooltip } from '../../base'; import { CloseIcon, CollapseAllIcon, ExpandAllIcon } from '../../icons'; import { PanelDragHandleIcon } from '../../icons/PanelDragHandle'; import { useTheme } from '../../theme'; import { ErrorBoundary } from '../ErrorBoundary'; - -export const ListHeader = styled(ListItem)(({ theme }) => ({ - padding: theme.spacing(0.5, 0.5), - marginBlock: theme.spacing(1), - '& .MuiListItemText-primary': { - fontSize: '1rem', - textTransform: 'capitalize', - fontWeight: 700 - }, - cursor: 'pointer', - '&:hover': { - backgroundColor: theme.palette.action.hover - }, - '& .MuiSvgIcon-root': { - opacity: 0, - transition: 'opacity 0.2s' - }, - '&:hover .MuiSvgIcon-root': { - opacity: 1 - } -})); - -interface CustomListItemProps extends ListItemProps { - isVisible: boolean; -} - -// Use the new interface in the styled component -export const StyledListItem = styled(ListItem, { - shouldForwardProp: (props) => props !== 'isVisible' -})(({ theme, isVisible }) => ({ - padding: theme.spacing(0.05, 0.5), - fontStyle: isVisible ? 'normal' : 'italic', - overflow: 'hidden', - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', - '& .MuiSvgIcon-root': { - height: 20, - width: 20 - }, - '& .MuiListItemIcon-root': { - minWidth: 0, - opacity: isVisible ? 0.8 : 0.3 - }, - '& .MuiTypography-root': { - fontSize: '0.9rem', - opacity: isVisible ? 1 : 0.5 - } -})); +import { DrawerHeader, PanelBody, ResizableContent } from './style'; type PanelProps = { isOpen: boolean; @@ -72,60 +24,6 @@ type PanelProps = { }; }; -export const DrawerHeader = styled('div')(({ theme }) => ({ - display: 'flex', - alignItems: 'center', - padding: theme.spacing(4, 2), - alignContent: 'stretch', - justifyContent: 'space-between', - cursor: 'move', - background: - theme.palette.mode === 'light' - ? 'linear-gradient(90deg, #3B687B 0%, #507D90 100%)' - : 'linear-gradient(90deg, #28353A 0%, #3D4F57 100%)', - height: '3rem', - flexShrink: 0 -})); - -const PanelBody = styled(Box)(({ theme }) => ({ - padding: theme.spacing(2), - backgroundColor: theme.palette.background.surfaces, - overflow: 'auto', - flex: 1, - minHeight: 0 -})); - -// New container for Resizable content -const ResizableContent = styled('div')({ - height: '100%', - display: 'flex', - flexDirection: 'column', - minHeight: '3rem' -}); - -// // watches for the size of the element -// const useDimensions = (ref: React.RefObject) => { -// const [dimensions, setDimensions] = React.useState({ width: 0, height: 0 }); -// React.useEffect(() => { -// const { current } = ref; -// if (current) { -// const resizeObserver = new ResizeObserver((entries) => { -// entries.forEach((entry) => { -// setDimensions({ -// width: entry.contentRect.width, -// height: entry.contentRect.height -// }); -// }); -// }); -// resizeObserver.observe(current); -// return () => { -// resizeObserver.unobserve(current); -// }; -// } -// }, [ref]); -// return dimensions; -// }; - const Panel_: React.FC = ({ isOpen, id = 'panel', @@ -137,10 +35,8 @@ const Panel_: React.FC = ({ sx }) => { const theme = useTheme(); - // const mode = theme?.palette?.type; if (!isOpen) return null; return ( - // = ({ )}
= ({ }} >
- + - {children}
- //
); }; export const Panel: React.FC = ({ ...props }) => { - return ( - // - - // - ); + return ; }; diff --git a/src/custom/Panel/style.tsx b/src/custom/Panel/style.tsx new file mode 100644 index 00000000..c94449de --- /dev/null +++ b/src/custom/Panel/style.tsx @@ -0,0 +1,80 @@ +import { ListItemProps } from '@mui/material'; +import { Box, ListItem } from '../../base'; +import { styled } from '../../theme'; + +export const ListHeader = styled(ListItem)(({ theme }) => ({ + padding: theme.spacing(0.5, 0.5), + marginBlock: theme.spacing(1), + '& .MuiListItemText-primary': { + fontSize: '1rem', + textTransform: 'capitalize', + fontWeight: 700 + }, + cursor: 'pointer', + '&:hover': { + backgroundColor: theme.palette.action.hover + }, + '& .MuiSvgIcon-root': { + opacity: 0, + transition: 'opacity 0.2s' + }, + '&:hover .MuiSvgIcon-root': { + opacity: 1 + } +})); + +interface CustomListItemProps extends ListItemProps { + isVisible: boolean; +} + +export const StyledListItem = styled(ListItem, { + shouldForwardProp: (props) => props !== 'isVisible' +})(({ theme, isVisible }) => ({ + padding: theme.spacing(0.05, 0.5), + fontStyle: isVisible ? 'normal' : 'italic', + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + '& .MuiSvgIcon-root': { + height: 20, + width: 20 + }, + '& .MuiListItemIcon-root': { + minWidth: 0, + opacity: isVisible ? 0.8 : 0.3 + }, + '& .MuiTypography-root': { + fontSize: '0.9rem', + opacity: isVisible ? 1 : 0.5 + } +})); + +export const DrawerHeader = styled('div')(({ theme }) => ({ + display: 'flex', + alignItems: 'center', + padding: theme.spacing(4, 2), + alignContent: 'stretch', + justifyContent: 'space-between', + cursor: 'move', + background: + theme.palette.mode === 'light' + ? 'linear-gradient(90deg, #3B687B 0%, #507D90 100%)' + : 'linear-gradient(90deg, #28353A 0%, #3D4F57 100%)', + height: '3rem', + flexShrink: 0 +})); + +export const PanelBody = styled(Box)(({ theme }) => ({ + padding: theme.spacing(2), + backgroundColor: theme.palette.background.surfaces, + overflow: 'auto', + flex: 1, + minHeight: 0 +})); + +export const ResizableContent = styled('div')({ + height: '100%', + display: 'flex', + flexDirection: 'column', + minHeight: '3rem' +}); diff --git a/src/icons/PanelDragHandle/PanelDragHandleIcon.tsx b/src/icons/PanelDragHandle/PanelDragHandleIcon.tsx index b6fe307e..31f4a9e2 100644 --- a/src/icons/PanelDragHandle/PanelDragHandleIcon.tsx +++ b/src/icons/PanelDragHandle/PanelDragHandleIcon.tsx @@ -4,7 +4,7 @@ import { IconProps } from '../types'; export const PanelDragHandleIcon: FC = ({ height = 24, width = 24, - fill = 'currentColor', + fill = '#E8EFF3', ...props }) => { return ( From 971c97dc4d4d8a02e0942dc951aa2019ad77f460 Mon Sep 17 00:00:00 2001 From: Vidit-Kushwaha Date: Mon, 30 Dec 2024 12:09:34 +0000 Subject: [PATCH 3/3] chore: Replace inline CSS with styled components in Panel component Signed-off-by: Vidit-Kushwaha --- src/custom/Panel/Panel.tsx | 61 ++++++++++++-------------------------- src/custom/Panel/style.tsx | 37 +++++++++++++++++++++++ 2 files changed, 56 insertions(+), 42 deletions(-) diff --git a/src/custom/Panel/Panel.tsx b/src/custom/Panel/Panel.tsx index ff5c20d4..cc0409f1 100644 --- a/src/custom/Panel/Panel.tsx +++ b/src/custom/Panel/Panel.tsx @@ -6,9 +6,17 @@ import { CloseIcon, CollapseAllIcon, ExpandAllIcon } from '../../icons'; import { PanelDragHandleIcon } from '../../icons/PanelDragHandle'; import { useTheme } from '../../theme'; import { ErrorBoundary } from '../ErrorBoundary'; -import { DrawerHeader, PanelBody, ResizableContent } from './style'; +import { + DragHandle, + DrawerHeader, + HeaderActionsContainer, + HeaderContainer, + PanelBody, + PanelContainer, + ResizableContent +} from './style'; -type PanelProps = { +export type PanelProps = { isOpen: boolean; children: React.ReactNode; areAllExpanded?: boolean; @@ -38,25 +46,7 @@ const Panel_: React.FC = ({ if (!isOpen) return null; return ( - + { @@ -86,37 +76,24 @@ const Panel_: React.FC = ({ )} - -
-
+ + + +
+ > -
+ {children} - +
); }; diff --git a/src/custom/Panel/style.tsx b/src/custom/Panel/style.tsx index c94449de..8f9daf8a 100644 --- a/src/custom/Panel/style.tsx +++ b/src/custom/Panel/style.tsx @@ -1,6 +1,7 @@ import { ListItemProps } from '@mui/material'; import { Box, ListItem } from '../../base'; import { styled } from '../../theme'; +import { PanelProps } from './Panel'; export const ListHeader = styled(ListItem)(({ theme }) => ({ padding: theme.spacing(0.5, 0.5), @@ -78,3 +79,39 @@ export const ResizableContent = styled('div')({ flexDirection: 'column', minHeight: '3rem' }); + +export const PanelContainer = styled(Box)<{ intitialPosition: PanelProps['intitialPosition'] }>( + ({ theme, intitialPosition }) => ({ + borderRadius: '8px', + overflow: 'hidden', + flexShrink: 0, + zIndex: 99999, + position: 'absolute', + backgroundColor: theme.palette.background.blur?.light, + boxShadow: '0 4px 16px #05003812', + maxHeight: '80%', + display: 'flex', + boxSizing: 'border-box', + ...intitialPosition + }) +); + +export const DragHandle = styled('div')({ + position: 'absolute', + top: '-3rem', + left: '50%' +}); + +export const HeaderActionsContainer = styled('div')({ + display: 'flex', + gap: '1rem', + justifyContent: 'flex-end', + alignItems: 'center' +}); + +export const HeaderContainer = styled('div')({ + display: 'flex', + justifyContent: 'end', + alignItems: 'center', + flex: '1' +});