diff --git a/CHANGELOG.md b/CHANGELOG.md index 4575fc2e..85d9e536 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ # CHANGELOG +## Unreleased +- Adapt layout for mobile [#134](https://github.com/CartoDB/carto-react-template/pull/134) ## 1.0.0-beta4 (2020-11-25) - Update @carto/react dependency to 1.0.0-beta5 @@ -10,4 +12,4 @@ - Fix routes with missing slash [#125](https://github.com/CartoDB/carto-react-template/pull/125) ## 1.0.0-beta1 (2020-11-20) -- Initial version: 2 templates, simple and full app \ No newline at end of file +- Initial version: 2 templates, simple and full app diff --git a/template-sample-app/template/public/logo-xs.svg b/template-sample-app/template/public/logo-xs.svg new file mode 100644 index 00000000..3e6a95a1 --- /dev/null +++ b/template-sample-app/template/public/logo-xs.svg @@ -0,0 +1,10 @@ + + + Logo/Negative/Symbol + + + + \ No newline at end of file diff --git a/template-sample-app/template/src/App.js b/template-sample-app/template/src/App.js index 0c01aaa6..6a07e786 100644 --- a/template-sample-app/template/src/App.js +++ b/template-sample-app/template/src/App.js @@ -50,7 +50,7 @@ function App() { return ( - +
{routing}
diff --git a/template-sample-app/template/src/components/common/Header.js b/template-sample-app/template/src/components/common/Header.js index 4a1cba33..236478a7 100644 --- a/template-sample-app/template/src/components/common/Header.js +++ b/template-sample-app/template/src/components/common/Header.js @@ -1,21 +1,27 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { AppBar, - Tab, - Tabs, - Toolbar, + Drawer, + Divider, + Hidden, Grid, + IconButton, Link, makeStyles, + Tab, + Tabs, + Toolbar, Typography, - Divider, } from '@material-ui/core'; +import MenuIcon from '@material-ui/icons/Menu'; import UserMenu from 'components/views/UserMenu'; import { NavLink, useLocation } from 'react-router-dom'; const useStyles = makeStyles((theme) => ({ navBar: { boxShadow: 'none', + zIndex: theme.zIndex.modal + 1, + overflow: 'hidden', }, navTabs: { '& .MuiTabs-indicator': { @@ -25,6 +31,12 @@ const useStyles = makeStyles((theme) => ({ divider: { margin: theme.spacing(0, 3), }, + menuButton: { + marginRight: theme.spacing(2), + }, + drawer: { + minWidth: 260, + }, title: { '& h1': { fontWeight: theme.typography.fontWeightRegular, @@ -35,48 +47,112 @@ const useStyles = makeStyles((theme) => ({ marginRight: theme.spacing(2), verticalAlign: 'bottom', }, + + '& img + hr': { + display: 'inline-block', + height: '1em', + marginRight: theme.spacing(2), + verticalAlign: 'text-bottom' + } }, }, })); +const NavigationMenu = (props) => { + const { location, column: vertical } = props; + const classes = useStyles(); + + return ( + + + + + + + {/* Auto import links */} + + + + ); +}; + export function Header() { const classes = useStyles(); const location = useLocation(); + const [drawerOpen, setDrawerOpen] = useState(false); + + useEffect(() => { + setDrawerOpen(false); + }, [location]); + + const handleDrawerToggle = () => { + setDrawerOpen(!drawerOpen); + }; return ( + + + + + - CARTO + + CARTO + + + CARTO + + React Demo - - - - - - - {/* Auto import links */} - - - + + + + + + + + + + + + + diff --git a/template-sample-app/template/src/components/views/Main.js b/template-sample-app/template/src/components/views/Main.js index 1979e3d7..e16daf18 100644 --- a/template-sample-app/template/src/components/views/Main.js +++ b/template-sample-app/template/src/components/views/Main.js @@ -1,75 +1,138 @@ -import React from 'react'; +import React, { useState } from 'react'; import { Outlet } from 'react-router-dom'; +import { useDispatch, useSelector } from 'react-redux'; +import { Box, Drawer, Grid, Hidden, Paper, Portal, Snackbar, Toolbar, useTheme, useMediaQuery } from '@material-ui/core'; import { makeStyles } from '@material-ui/core/styles'; -import { Grid, Snackbar } from '@material-ui/core'; +import { Alert } from '@material-ui/lab'; +import { + ExpandLess as ExpandLessIcon, + ExpandMore as ExpandMoreIcon, +} from '@material-ui/icons'; +import { GeocoderWidget } from '@carto/react/widgets'; import { Map } from 'components/common/Map'; import { Legend } from 'components/legends/Legend'; -import { GeocoderWidget } from '@carto/react/widgets'; import { getLayers } from 'components/layers'; -import { useDispatch, useSelector } from 'react-redux'; -import { Alert } from '@material-ui/lab'; import { setError } from 'config/appSlice'; +const drawerWidth = 350; + const useStyles = makeStyles((theme) => ({ - contentWrapper: { - display: 'flex', - flexDirection: 'row', - flex: 1, - alignItems: 'start', - justifyContent: 'space-between', - overflow: 'hidden', + drawer: { + [theme.breakpoints.up('sm')]: { + width: drawerWidth, + flexShrink: 0, + }, }, - sidebarWrapper: { - position: 'relative', - width: '350px', - height: '100%', - backgroundColor: theme.palette.common.white, - boxShadow: theme.shadows[3], - overflow: 'auto', + drawerPaper: { + width: drawerWidth, + }, + widgetDrawerToggle: { + position: 'absolute', + bottom: 0, + width: '100%', zIndex: 1, + textAlign: 'center', + }, + bottomSheet: { + maxHeight: 'calc(100% - 48px)', + }, + bottomSheetContent: { + minHeight: theme.spacing(16) }, mapWrapper: { position: 'relative', - width: 'calc(100% - 350px)', - height: '100%', + flex: 1, overflow: 'hidden', }, legend: { position: 'absolute', bottom: theme.spacing(3.5), right: theme.spacing(4), + + [theme.breakpoints.down('sm')]: { + bottom: theme.spacing(9), + right: theme.spacing(2), + }, }, geocoder: { position: 'absolute', top: theme.spacing(3), left: theme.spacing(3), - }, + + [theme.breakpoints.down('xs')]: { + width: `calc(100% - ${theme.spacing(6)}px)` + } + } })); export default function Main() { const dispatch = useDispatch(); const error = useSelector((state) => state.app.error); + const [widgetsDrawerOpen, setWidgetsDrawerOpen] = useState(false); const classes = useStyles(); + const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down('xs')); + const mobileContainer = React.useRef(null); + const desktopContainer = React.useRef(null); const handleClose = () => { dispatch(setError(null)); }; + const handleWidgetsDrawerToggle = () => { + setWidgetsDrawerOpen(!widgetsDrawerOpen); + }; + const onGeocoderWidgetError = (error) => { dispatch(setError(`Geocoding error: ${error.message}`)); }; return ( - - - - + + + @@ -80,4 +143,4 @@ export default function Main() { ); -} +}; \ No newline at end of file diff --git a/template-sample-app/template/src/components/views/UserMenu.js b/template-sample-app/template/src/components/views/UserMenu.js index c545a68d..d34cbf12 100644 --- a/template-sample-app/template/src/components/views/UserMenu.js +++ b/template-sample-app/template/src/components/views/UserMenu.js @@ -2,22 +2,17 @@ import React, { useState } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { makeStyles } from '@material-ui/core/styles'; -import { Avatar, Grid, Link, Menu, MenuItem, Typography } from '@material-ui/core'; +import { Avatar, Grid, Hidden, Link, Menu, MenuItem, Typography } from '@material-ui/core'; import { OAuthLogin } from '@carto/react/oauth'; import { logout } from '@carto/react/redux'; const useStyles = makeStyles((theme) => ({ - root: { - flexGrow: 1, - }, - menuButton: { - marginRight: theme.spacing(2), - }, avatar: { cursor: 'pointer', width: theme.spacing(4.5), height: theme.spacing(4.5), + marginLeft: theme.spacing(1), }, })); @@ -61,51 +56,44 @@ function UserMenu() { // Display User menu, with name, avatar + an attached menu for user-related options return ( -
- + - - - {user.username} - + + + + {user.username} + + + - - - - - - Logout - Go to CARTO - - - -
+ + + Logout + Go to CARTO + + ); } diff --git a/template-skeleton/template/public/logo-xs.svg b/template-skeleton/template/public/logo-xs.svg new file mode 100644 index 00000000..3e6a95a1 --- /dev/null +++ b/template-skeleton/template/public/logo-xs.svg @@ -0,0 +1,10 @@ + + + Logo/Negative/Symbol + + + + \ No newline at end of file diff --git a/template-skeleton/template/src/components/common/Header.js b/template-skeleton/template/src/components/common/Header.js index 4429a6f2..e44c82f3 100644 --- a/template-skeleton/template/src/components/common/Header.js +++ b/template-skeleton/template/src/components/common/Header.js @@ -1,30 +1,42 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { AppBar, + Drawer, + Divider, + Hidden, + Grid, + IconButton, Tab, Tabs, Toolbar, - Grid, Link, makeStyles, Typography, - Divider, } from '@material-ui/core'; +import MenuIcon from '@material-ui/icons/Menu'; import UserMenu from 'components/views/UserMenu'; import { NavLink, useLocation } from 'react-router-dom'; const useStyles = makeStyles((theme) => ({ navBar: { boxShadow: 'none', + zIndex: theme.zIndex.modal + 1, + overflow: 'hidden', }, navTabs: { '& .MuiTabs-indicator': { backgroundColor: theme.palette.common.white, - } + }, }, divider: { margin: theme.spacing(0, 3), }, + menuButton: { + marginRight: theme.spacing(2), + }, + drawer: { + minWidth: 260, + }, title: { '& h1': { fontWeight: theme.typography.fontWeightRegular, @@ -35,39 +47,105 @@ const useStyles = makeStyles((theme) => ({ marginRight: theme.spacing(2), verticalAlign: 'bottom', }, + + '& img + hr': { + display: 'inline-block', + height: '1em', + marginRight: theme.spacing(2), + verticalAlign: 'text-bottom', + }, }, }, })); +const NavigationMenu = (props) => { + const { location, column: vertical } = props; + const classes = useStyles(); + + return ( + + + + + {/* Auto import links */} + + + + ); +}; + export function Header() { const classes = useStyles(); const location = useLocation(); + const [drawerOpen, setDrawerOpen] = useState(false); + + useEffect(() => { + setDrawerOpen(false); + }, [location]); + + const handleDrawerToggle = () => { + setDrawerOpen(!drawerOpen); + }; return ( + + + + + - CARTO + + CARTO + + + CARTO + + React Demo - - - + + + + + - - {/* Auto import links */} - - - + + + + + + + diff --git a/template-skeleton/template/src/components/views/Main.js b/template-skeleton/template/src/components/views/Main.js index 7e9d78ff..5fa2340a 100644 --- a/template-skeleton/template/src/components/views/Main.js +++ b/template-skeleton/template/src/components/views/Main.js @@ -1,69 +1,138 @@ -import React from 'react'; +import React, { useState } from 'react'; import { Outlet } from 'react-router-dom'; +import { useDispatch, useSelector } from 'react-redux'; import { makeStyles } from '@material-ui/core/styles'; -import { Grid, Snackbar } from '@material-ui/core'; -import { Map } from 'components/common/Map'; +import { + Box, + Drawer, + Grid, + Hidden, + Paper, + Portal, + Snackbar, + Toolbar, + useTheme, + useMediaQuery, +} from '@material-ui/core'; +import { Alert } from '@material-ui/lab'; +import { + ExpandLess as ExpandLessIcon, + ExpandMore as ExpandMoreIcon, +} from '@material-ui/icons'; import { GeocoderWidget } from '@carto/react/widgets'; +import { Map } from 'components/common/Map'; import { getLayers } from 'components/layers'; -import { useDispatch, useSelector } from 'react-redux'; -import { Alert } from '@material-ui/lab'; import { setError } from 'config/appSlice'; +const drawerWidth = 350; + const useStyles = makeStyles((theme) => ({ - contentWrapper: { - display: 'flex', - flexDirection: 'row', - flex: 1, - alignItems: 'start', - justifyContent: 'space-between', - overflow: 'hidden', + drawer: { + [theme.breakpoints.up('sm')]: { + width: drawerWidth, + flexShrink: 0, + }, }, - sidebarWrapper: { - position: 'relative', - width: '350px', - height: '100%', - backgroundColor: theme.palette.common.white, - boxShadow: theme.shadows[3], - overflow: 'auto', + drawerPaper: { + width: drawerWidth, + }, + widgetDrawerToggle: { + position: 'absolute', + bottom: 0, + width: '100%', zIndex: 1, + textAlign: 'center', + }, + bottomSheet: { + maxHeight: 'calc(100% - 48px)', + }, + bottomSheetContent: { + minHeight: theme.spacing(16), }, mapWrapper: { position: 'relative', - width: 'calc(100% - 350px)', - height: '100%', + flex: 1, overflow: 'hidden', }, geocoder: { position: 'absolute', top: theme.spacing(3), left: theme.spacing(3), + + [theme.breakpoints.down('xs')]: { + width: `calc(100% - ${theme.spacing(6)}px)`, + }, }, })); export default function Main() { const dispatch = useDispatch(); const error = useSelector((state) => state.app.error); + const [widgetsDrawerOpen, setWidgetsDrawerOpen] = useState(false); const classes = useStyles(); + const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down('xs')); + const mobileContainer = React.useRef(null); + const desktopContainer = React.useRef(null); const handleClose = () => { dispatch(setError(null)); }; + const handleWidgetsDrawerToggle = () => { + setWidgetsDrawerOpen(!widgetsDrawerOpen); + }; + const onGeocoderWidgetError = (error) => { dispatch(setError(`Geocoding error: ${error.message}`)); }; return ( - - - - + + + diff --git a/template-skeleton/template/src/components/views/UserMenu.js b/template-skeleton/template/src/components/views/UserMenu.js index c545a68d..667ea9d4 100644 --- a/template-skeleton/template/src/components/views/UserMenu.js +++ b/template-skeleton/template/src/components/views/UserMenu.js @@ -2,22 +2,25 @@ import React, { useState } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { makeStyles } from '@material-ui/core/styles'; -import { Avatar, Grid, Link, Menu, MenuItem, Typography } from '@material-ui/core'; +import { + Avatar, + Grid, + Hidden, + Link, + Menu, + MenuItem, + Typography, +} from '@material-ui/core'; import { OAuthLogin } from '@carto/react/oauth'; import { logout } from '@carto/react/redux'; const useStyles = makeStyles((theme) => ({ - root: { - flexGrow: 1, - }, - menuButton: { - marginRight: theme.spacing(2), - }, avatar: { cursor: 'pointer', width: theme.spacing(4.5), height: theme.spacing(4.5), + marginLeft: theme.spacing(1), }, })); @@ -61,51 +64,43 @@ function UserMenu() { // Display User menu, with name, avatar + an attached menu for user-related options return ( -
- + - - - {user.username} - + + + + {user.username} + + + - - - - - - Logout - Go to CARTO - - - -
+ + + Logout + Go to CARTO + + ); }