Skip to content

Commit e9bb674

Browse files
authored
fix: Adjust sidebar resizing and responsiveness (#3639)
* adjust sidebar expand and collapse * adjust resize handler * adjust sidebar tabclick behaviour * remove unused values * adjust mobile view * update sidebar file * fix errors * fix overflow * remove console statement
1 parent 4e87c1a commit e9bb674

File tree

9 files changed

+167
-96
lines changed

9 files changed

+167
-96
lines changed

src/app/services/slices/sidebar-properties.slice.ts

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,30 @@ const sidebarPropertiesSlice = createSlice({
1515
name: 'sidebarProperties',
1616
initialState,
1717
reducers: {
18-
toggleSidebar: (state, action: PayloadAction<ISidebarProps>) => {
19-
state.showSidebar = action.payload.showSidebar;
20-
state.mobileScreen = action.payload.mobileScreen;
18+
toggleSidebar: (state, action: PayloadAction<Partial<ISidebarProps>>) => {
19+
state.showSidebar = action.payload.showSidebar !== undefined ? action.payload.showSidebar : !state.showSidebar;
20+
state.mobileScreen = action.payload.mobileScreen !== undefined ? action.payload.mobileScreen : state.mobileScreen;
2121
}
2222
},
2323
extraReducers: (builder) => {
2424
builder
2525
.addCase(QUERY_GRAPH_RUNNING, (state) => {
2626
if (state.mobileScreen) {
27-
return {
28-
...state,
29-
showSidebar: false
30-
}
27+
state.showSidebar = false;
3128
}
3229
})
3330
.addCase(SET_SAMPLE_QUERY_SUCCESS, (state) => {
3431
if (state.mobileScreen) {
35-
return {
36-
...state,
37-
showSidebar: false
38-
}
32+
state.showSidebar = false;
3933
}
4034
})
4135
.addCase(QUERY_GRAPH_SUCCESS, (state) => {
4236
if (state.mobileScreen) {
43-
return {
44-
...state,
45-
showSidebar: false
46-
}
37+
state.showSidebar = false;
4738
}
48-
})
39+
});
4940
}
50-
})
41+
});
5142

5243
export const { toggleSidebar } = sidebarPropertiesSlice.actions
5344
export default sidebarPropertiesSlice.reducer;

src/app/views/App.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import { substituteTokens } from '../utils/token-helpers';
3434
import { parse, ParsedMessageResult } from './query-runner/util/iframe-message-parser';
3535
import { Layout } from './layout/Layout';
3636
import { KeyboardCopyEvent } from './common/copy-button/KeyboardCopyEvent';
37-
import { useDetectMobileScreen } from '../utils/useDetectMobileScreen';
3837
export interface IAppProps {
3938
theme?: ITheme;
4039
styles?: object;

src/app/views/layout/Layout.tsx

Lines changed: 99 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import CollectionPermissionsProvider from '../../services/context/collection-per
55
import { PopupsProvider } from '../../services/context/popups-context';
66
import { ValidationProvider } from '../../services/context/validation-context/ValidationProvider';
77
import { setSampleQuery } from '../../services/slices/sample-query.slice';
8-
import { toggleSidebar } from '../../services/slices/sidebar-properties.slice'; // Import sidebar action
8+
import { toggleSidebar } from '../../services/slices/sidebar-properties.slice';
99
import { translateMessage } from '../../utils/translate-messages';
1010
import { StatusMessages, TermsOfUseMessage } from '../app-sections';
1111
import Notification from '../common/banners/Notification';
@@ -31,11 +31,13 @@ export const Layout = (props: LayoutProps) => {
3131
const dispatch = useAppDispatch();
3232
const sampleQuery = useAppSelector((state) => state.sampleQuery);
3333
const { mobileScreen, showSidebar } = useAppSelector((state) => state.sidebarProperties);
34+
const [initialSidebarWidth, setInitialSidebarWidth] = useState(456);
35+
const [sidebarElement, setSidebarElement] = useState<HTMLElement | null>(null);
3436

3537
const {
3638
handleRef: sidebarHandleRef,
3739
wrapperRef: sidebarWrapperRef,
38-
elementRef: sidebarElementRef,
40+
elementRef: storeSidebarElement,
3941
setValue: setSidebarColumnSize
4042
} = useResizeHandle({
4143
variableName: SIDEBAR_SIZE_CSS_VAR,
@@ -53,68 +55,120 @@ export const Layout = (props: LayoutProps) => {
5355
}, [sampleBody]);
5456

5557
useEffect(() => {
56-
if (mobileScreen) {
57-
dispatch(toggleSidebar({ showSidebar: false, mobileScreen: true }));
58+
if (!mobileScreen) {
59+
setSidebarColumnSize(456);
60+
setInitialSidebarWidth(456);
61+
} else {
5862
setSidebarColumnSize(0);
5963
}
60-
}, [mobileScreen, dispatch]);
64+
}, [mobileScreen]);
65+
6166

6267
const handleOnEditorChange = (value?: string) => {
6368
setSampleBody(value!);
6469
};
6570

6671
const handleToggleSelect = (toggled: boolean) => {
67-
setSidebarColumnSize(toggled ? 456 : 5);
72+
if (mobileScreen) {
73+
dispatch(toggleSidebar({ showSidebar: toggled, mobileScreen: true }));
74+
setSidebarColumnSize(toggled ? window.innerWidth : 0);
75+
} else {
76+
if (toggled) {
77+
setSidebarColumnSize(initialSidebarWidth > 456 ? initialSidebarWidth : 456);
78+
} else {
79+
setSidebarColumnSize(48);
80+
}
81+
}
6882
};
6983

70-
const resetSidebarArea = () => {
71-
setSidebarColumnSize(456);
84+
const handleResizeStart = (event: React.MouseEvent) => {
85+
event.preventDefault();
86+
87+
if (!sidebarElement) {return;}
88+
89+
const startX = event.clientX;
90+
const startWidth = parseInt(getComputedStyle(sidebarElement).width, 10);
91+
92+
const onMouseMove = (moveEvent: MouseEvent) => {
93+
const newWidth = startWidth + (moveEvent.clientX - startX);
94+
updateSidebarSize(newWidth);
95+
};
96+
97+
const onMouseUp = () => {
98+
window.removeEventListener('mousemove', onMouseMove);
99+
window.removeEventListener('mouseup', onMouseUp);
100+
};
101+
102+
window.addEventListener('mousemove', onMouseMove);
103+
window.addEventListener('mouseup', onMouseUp);
72104
};
73105

74-
return (
75-
<PopupsProvider>
76-
<div className={layoutStyles.container}>
77-
<MainHeader />
78-
<div id='content-ref' className={mergeClasses(layoutStyles.content, resizeStyles)} ref={sidebarWrapperRef}>
79-
{showSidebar && (
80-
<div id='sidebar-ref' className={layoutStyles.sidebar} ref={sidebarElementRef}>
81-
<Sidebar handleToggleSelect={handleToggleSelect} />
82-
<LayoutResizeHandler position='end' ref={sidebarHandleRef} onDoubleClick={resetSidebarArea} />
83-
</div>
84-
)}
85-
<div id='main-content' className={layoutStyles.mainContent}>
86-
<div style={{ margin: '0 10px' }}>
87-
<Notification
88-
header={translateMessage('Banner notification 1 header')}
89-
content={translateMessage('Banner notification 1 content')}
90-
link={translateMessage('Banner notification 1 link')}
91-
linkText={translateMessage('Banner notification 1 link text')}
92-
/>
93-
</div>
94106

95-
<ValidationProvider>
107+
const updateSidebarSize = (newSize: number) => {
108+
const minSize = 48;
109+
const maxSize = window.innerWidth * 0.5;
110+
111+
const finalSize = Math.max(minSize, Math.min(maxSize, newSize));
112+
113+
setSidebarColumnSize(finalSize);
114+
115+
if (finalSize > 48) {
116+
setInitialSidebarWidth(finalSize);
117+
}
118+
};
119+
120+
return (
121+
<>
122+
<PopupsProvider>
123+
<div className={layoutStyles.container}>
124+
<MainHeader />
125+
<div id='content-ref' className={mergeClasses(layoutStyles.content, resizeStyles)} ref={sidebarWrapperRef}>
126+
{showSidebar && (
127+
<div id='sidebar-ref' className={layoutStyles.sidebar} ref={storeSidebarElement}>
128+
<Sidebar handleToggleSelect={handleToggleSelect} />
129+
{!mobileScreen && (
130+
<LayoutResizeHandler
131+
position="end"
132+
ref={sidebarHandleRef}
133+
onDoubleClick={() => updateSidebarSize(456)}
134+
onMouseDown={handleResizeStart}
135+
/>
136+
)}
137+
</div>
138+
)}
139+
<div id='main-content' className={layoutStyles.mainContent}>
96140
<div style={{ margin: '0 10px' }}>
97-
<QueryRunner onSelectVerb={props.handleSelectVerb} />
141+
<Notification
142+
header={translateMessage('Banner notification 1 header')}
143+
content={translateMessage('Banner notification 1 content')}
144+
link={translateMessage('Banner notification 1 link')}
145+
linkText={translateMessage('Banner notification 1 link text')}
146+
/>
98147
</div>
99-
<div id='request-response-area' className={layoutStyles.requestResponseArea}>
100-
<div id='request-area' className={layoutStyles.requestArea}>
101-
<Request handleOnEditorChange={handleOnEditorChange} sampleQuery={sampleQuery} />
102-
</div>
148+
<ValidationProvider>
103149
<div style={{ margin: '0 10px' }}>
104-
<StatusMessages />
150+
<QueryRunner onSelectVerb={props.handleSelectVerb} />
105151
</div>
106-
<div id='response-area' className={layoutStyles.responseArea}>
107-
<QueryResponse />
152+
<div id='request-response-area' className={layoutStyles.requestResponseArea}>
153+
<div id='request-area' className={layoutStyles.requestArea}>
154+
<Request handleOnEditorChange={handleOnEditorChange} sampleQuery={sampleQuery} />
155+
</div>
156+
<div style={{ margin: '0 10px' }}>
157+
<StatusMessages />
158+
</div>
159+
<div id='response-area' className={layoutStyles.responseArea}>
160+
<QueryResponse />
161+
</div>
108162
</div>
109-
</div>
110-
</ValidationProvider>
163+
</ValidationProvider>
164+
</div>
111165
</div>
166+
<TermsOfUseMessage />
112167
</div>
113-
<TermsOfUseMessage />
114-
</div>
115-
<CollectionPermissionsProvider>
116-
<PopupsWrapper />
117-
</CollectionPermissionsProvider>
118-
</PopupsProvider>
168+
<CollectionPermissionsProvider>
169+
<PopupsWrapper />
170+
</CollectionPermissionsProvider>
171+
</PopupsProvider>
172+
</>
119173
);
120174
};

src/app/views/layout/LayoutResizeHandler.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { makeResetStyles, tokens, useFluent } from '@fluentui/react-components';
22
import * as React from 'react';
3+
import { useAppSelector } from '../../../store';
34

45
interface HandleProps {
56
position: 'start' | 'end' | 'top' | 'bottom';
67
onDoubleClick?: () => void;
8+
onMouseDown?: (event: React.MouseEvent) => void;
79
}
810

911
const useHoverStyles = makeResetStyles({
@@ -13,16 +15,21 @@ const useHoverStyles = makeResetStyles({
1315
})
1416
export const LayoutResizeHandler = React.forwardRef<HTMLDivElement, HandleProps>(
1517
(props, ref) => {
16-
const { position, ...rest } = props;
18+
const { position,onMouseDown, ...rest } = props;
1719
const { dir } = useFluent();
18-
const hoverStyles = useHoverStyles()
20+
const hoverStyles = useHoverStyles();
21+
const mobileScreen = useAppSelector((state) => state.sidebarProperties.mobileScreen);
1922

2023
const handleClick = (event: React.MouseEvent) => {
2124
if (event.detail === 2) {
2225
props.onDoubleClick?.();
2326
}
2427
};
2528

29+
if (mobileScreen) {
30+
return null;
31+
}
32+
2633
const positioningAttr =
2734
dir === 'ltr'
2835
? position === 'start'
@@ -38,7 +45,7 @@ export const LayoutResizeHandler = React.forwardRef<HTMLDivElement, HandleProps>
3845
[positioningAttr]: '-5px',
3946
top: '50%',
4047
transform: 'translateY(-50%)',
41-
width: '3px',
48+
width: '6px',
4249
height: '100%',
4350
cursor: 'col-resize'
4451
}
@@ -56,6 +63,7 @@ export const LayoutResizeHandler = React.forwardRef<HTMLDivElement, HandleProps>
5663
{...rest}
5764
ref={ref}
5865
onClick={handleClick}
66+
onMouseDown={onMouseDown}
5967
tabIndex={0}
6068
className={hoverStyles}
6169
style={{

src/app/views/layout/LayoutStyles.tsx

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,42 @@ export const useLayoutStyles = makeStyles({
1111
display: 'flex',
1212
flexDirection: 'column',
1313
padding: tokens.spacingHorizontalS,
14-
height: '100vh'
14+
height: '100vh',
15+
overflow: 'hidden'
1516
},
1617
content: {
1718
display: 'flex',
18-
overflowY: 'hidden'
19+
flex: 1,
20+
overflowY: 'hidden',
21+
minWidth: 0
1922
},
2023
sidebar: {
2124
flex: '0 0 auto',
22-
flexBasis: `clamp(min(29%, var(${SIDEBAR_SIZE_CSS_VAR})), var(${SIDEBAR_SIZE_CSS_VAR}), 60%)`,
25+
flexBasis: `clamp(48px, var(${SIDEBAR_SIZE_CSS_VAR}), 50vw)`,
26+
maxWidth: '50vw',
27+
minWidth: '48px',
2328
position: 'relative',
24-
height: 'calc(100vh - 98px)'
29+
height: 'calc(100vh - 98px)',
30+
overflow: 'hidden',
31+
transition: 'flex-basis 0.2s ease-in-out',
32+
33+
'@media (max-width: 768px)': {
34+
flexBasis: '100vw',
35+
maxWidth: '100vw',
36+
minWidth: '100vw',
37+
position: 'absolute',
38+
left: 0,
39+
zIndex: 1000,
40+
backgroundColor: 'white'
41+
}
2542
},
2643
mainContent: {
2744
flex: '1 1 auto',
2845
display: 'flex',
2946
flexDirection: 'column',
30-
minHeight: '300px',
31-
height: 'calc(100vh - 120px)'
47+
minWidth: '300px',
48+
height: 'calc(100vh - 98px)',
49+
overflow: 'hidden'
3250
},
3351
requestResponseArea: {
3452
flex: '1',
@@ -41,7 +59,7 @@ export const useLayoutStyles = makeStyles({
4159
flex: '1',
4260
display: 'flex',
4361
flexDirection: 'column',
44-
maxHeight: '55%',
62+
maxHeight: '60%',
4563
overflow: 'hidden',
4664
borderRadius: tokens.borderRadiusMedium,
4765
padding: tokens.spacingHorizontalS
@@ -50,7 +68,7 @@ export const useLayoutStyles = makeStyles({
5068
flex: '1',
5169
display: 'flex',
5270
flexDirection: 'column',
53-
maxHeight: '37%',
71+
maxHeight: '40%',
5472
overflow: 'hidden',
5573
borderRadius: tokens.borderRadiusMedium,
5674
padding: tokens.spacingHorizontalS

src/app/views/main-header/MainHeader.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const useStyles = makeStyles({
3737
display: 'none',
3838
cursor: 'pointer',
3939

40-
'@media (max-width: 480px)': {
40+
'@media (max-width: 768px)': {
4141
display: 'block'
4242
}
4343
}
@@ -49,7 +49,7 @@ const MainHeader = ()=>{
4949
const mobileScreen = useAppSelector((state) => state.sidebarProperties.mobileScreen);
5050

5151
const handleSidebarToggle = () => {
52-
dispatch(toggleSidebar({ showSidebar: true, mobileScreen: true }));
52+
dispatch(toggleSidebar({ mobileScreen: true }));
5353
};
5454

5555
return (

src/app/views/query-response/pivot-items/pivot-item.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ export const GetPivotItems = () => {
124124
return (
125125
<div className={styles.container}>
126126
{mobileScreen ? (
127-
<Overflow minimumVisible={1}>
127+
<Overflow minimumVisible={2}>
128128
<TabList selectedValue={selectedValue} onTabSelect={onTabSelect} size='small'>
129129
{tabs.map((tab) => (
130130
<OverflowItem key={tab.id} id={tab.id} priority={tab.id === selectedValue ? 2 : 1}>

0 commit comments

Comments
 (0)