go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/ui/src/common/layouts/base_layout.tsx (about) 1 // Copyright 2023 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 import { styled } from '@mui/material'; 16 import Box from '@mui/material/Box'; 17 import { Outlet } from 'react-router-dom'; 18 import { useLocalStorage } from 'react-use'; 19 20 import { AppBar } from './app_bar'; 21 import { drawerWidth } from './constants'; 22 import { Sidebar } from './side_bar'; 23 24 const Main = styled('main', { shouldForwardProp: (prop) => prop !== 'open' })<{ 25 open?: boolean; 26 }>(({ theme, open }) => ({ 27 flexGrow: 1, 28 transition: theme.transitions.create('margin', { 29 easing: theme.transitions.easing.sharp, 30 duration: theme.transitions.duration.leavingScreen, 31 }), 32 marginLeft: `-${drawerWidth}px`, 33 ...(open && { 34 transition: theme.transitions.create('margin', { 35 easing: theme.transitions.easing.easeOut, 36 duration: theme.transitions.duration.enteringScreen, 37 }), 38 marginLeft: 0, 39 }), 40 })); 41 42 export const SIDE_BAR_OPEN_CACHE_KEY = 'side-bar-open'; 43 44 export const BaseLayout = () => { 45 const [sidebarOpen = true, setSidebarOpen] = useLocalStorage<boolean>( 46 SIDE_BAR_OPEN_CACHE_KEY, 47 ); 48 49 return ( 50 <Box sx={{ display: 'flex', pt: 6 }}> 51 <AppBar open={sidebarOpen} handleSidebarChanged={setSidebarOpen} /> 52 <Sidebar open={sidebarOpen} /> 53 <Main open={sidebarOpen}> 54 {/* Do not conditionally render the <Outlet /> base on the navigation 55 ** state. Otherwise the page state will be reset if a page navigates 56 ** to itself, which can happen when the query search param is updated. 57 ** In the worst case, this may lead to infinite reload if the query 58 ** search param is updated when the component is mounted. */} 59 <Outlet /> 60 </Main> 61 </Box> 62 ); 63 };