Skip to content

Commit 25d479a

Browse files
committed
feat(admin-ui): improve mobile layout
1 parent 931e1d0 commit 25d479a

9 files changed

Lines changed: 186 additions & 34 deletions

File tree

apps/sensenet/src/components/ContentBreadcrumbs.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,24 @@ import { getPrimaryActionUrl } from '../services'
99
import { BatchActions } from './BatchActions'
1010
import { BreadcrumbItem, Breadcrumbs } from './Breadcrumbs'
1111

12-
const useStyles = makeStyles(() => {
12+
const useStyles = makeStyles((theme) => {
1313
return createStyles({
1414
buttonsWrapper: {
1515
display: 'flex',
1616
alignItems: 'center',
1717
marginLeft: '10px',
18+
minWidth: 0,
19+
overflow: 'hidden',
20+
[theme.breakpoints.down('sm')]: {
21+
marginLeft: 0,
22+
width: '100%',
23+
'& .MuiBreadcrumbs-ol': {
24+
flexWrap: 'nowrap',
25+
overflowX: 'auto',
26+
overflowY: 'hidden',
27+
maxWidth: '100%',
28+
},
29+
},
1830
},
1931
})
2032
})

apps/sensenet/src/components/appbar/desktop-app-bar.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ import { clsx } from 'clsx'
77
import React, { useContext, useEffect, useState } from 'react'
88
import { Link } from 'react-router-dom'
99
import logo from '../../assets/sensenet_white.png'
10-
import { ResponsivePersonalSettings } from '../../context'
10+
import { ResponsiveContext, ResponsivePersonalSettings } from '../../context'
1111
import { globals, useGlobalStyles } from '../../globalStyles'
1212
import { CommandPalette } from '../command-palette/CommandPalette'
1313
import { DesktopNavMenu } from './desktop-nav-menu'
1414

15-
const useStyles = makeStyles(() => {
15+
const useStyles = makeStyles((theme) => {
1616
return createStyles({
1717
appBar: {
1818
position: 'relative',
@@ -38,9 +38,18 @@ const useStyles = makeStyles(() => {
3838
fontSize: '18px',
3939
fontWeight: 500,
4040
fontFamily: 'Roboto,Helvetica,Arial,sans-serif',
41+
whiteSpace: 'nowrap',
42+
overflow: 'hidden',
43+
textOverflow: 'ellipsis',
44+
maxWidth: '36vw',
4145
'&:hover': {
4246
cursor: 'pointer',
4347
},
48+
[theme.breakpoints.down('sm')]: {
49+
maxWidth: '28vw',
50+
marginRight: '0.5rem',
51+
fontSize: '13px',
52+
},
4453
},
4554
})
4655
})
@@ -49,6 +58,7 @@ const PORTAL_SETTING_PATH = '/Root/System/Settings/Portal.settings'
4958

5059
export const DesktopAppBar: React.FunctionComponent<{ openDrawer?: () => void }> = (props) => {
5160
const personalSettings = useContext(ResponsivePersonalSettings)
61+
const device = useContext(ResponsiveContext)
5262
const classes = useStyles()
5363
const globalClasses = useGlobalStyles()
5464
const repository = useRepository()
@@ -110,7 +120,7 @@ export const DesktopAppBar: React.FunctionComponent<{ openDrawer?: () => void }>
110120
<Link to="/" className={`${globalClasses.centeredVertical} ${classes.logo}`}>
111121
<img src={logo} alt="logo" data-test="sensenet-logo" width="29" height="32" />
112122
</Link>
113-
{personalSettings.drawer.type === 'temporary' ? (
123+
{personalSettings.drawer.enabled && (personalSettings.drawer.type === 'temporary' || device === 'mobile') ? (
114124
<IconButton
115125
onClick={() => {
116126
props.openDrawer && props.openDrawer()

apps/sensenet/src/components/content/AUIApplicationView.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -362,10 +362,7 @@ export const AUIApplicationView: React.FC = () => {
362362

363363
const applicationHtml = content?.Html?.trim() ?? ''
364364
const adminUiUrl = window.location.origin
365-
const bridgeLocation = useMemo(
366-
() => createBridgeLocation(adminUiUrl, routerLocation),
367-
[adminUiUrl, routerLocation.hash, routerLocation.pathname, routerLocation.search],
368-
)
365+
const bridgeLocation = useMemo(() => createBridgeLocation(adminUiUrl, routerLocation), [adminUiUrl, routerLocation])
369366
const bridgeTheme = useMemo(() => createBridgeTheme(theme.palette.type), [theme.palette.type])
370367
const srcDoc = useMemo(
371368
() =>

apps/sensenet/src/components/content/Explore.tsx

Lines changed: 93 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { createStyles, makeStyles, Theme, useTheme } from '@material-ui/core'
1+
import { createStyles, IconButton, makeStyles, SwipeableDrawer, Theme, Tooltip, useTheme } from '@material-ui/core'
2+
import MenuIcon from '@material-ui/icons/Menu'
23
import { ODataFieldParameter, ODataParams } from '@sensenet/client-core'
34
import { PathHelper } from '@sensenet/client-utils'
45
import { GenericContent } from '@sensenet/default-content-types'
@@ -16,8 +17,8 @@ import { clsx } from 'clsx'
1617
import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'
1718
import { useHistory } from 'react-router'
1819
import { GridKeyEnum } from '../../../src/components/grid/enums/GridKey.enum'
19-
import { ResponsivePersonalSettings } from '../../context'
20-
import { useGlobalStyles } from '../../globalStyles'
20+
import { ResponsiveContext, ResponsivePersonalSettings } from '../../context'
21+
import { globals, useGlobalStyles } from '../../globalStyles'
2122
import { useQuery, useSelectionService, useSnRoute } from '../../hooks'
2223
import { getPrimaryActionUrl, navigateToAction } from '../../services'
2324
import { ContentBreadcrumbs } from '../ContentBreadcrumbs'
@@ -72,21 +73,34 @@ const useStyles = makeStyles<Theme, { width: number }>((theme) =>
7273
boxSizing: 'border-box',
7374
borderBottom: theme.palette.type === 'light' ? '1px solid #DBDBDB' : '1px solid rgba(255, 255, 255, 0.11)',
7475
justifyContent: 'start',
76+
minHeight: globals.common.drawerItemHeight,
77+
overflow: 'hidden',
78+
},
79+
breadcrumbsContent: {
80+
minWidth: 0,
81+
overflow: 'hidden',
82+
flexGrow: 1,
7583
},
7684
treeAndDatagridWrapper: {
7785
display: 'flex',
7886
width: '100%',
7987
height: '100%',
8088
position: 'relative',
81-
overflow: 'auto',
89+
overflow: 'hidden',
90+
minWidth: 0,
8291
},
8392
exploreContainer: {
8493
display: 'flex',
8594
flexFlow: 'column',
8695
width: '100%',
96+
minWidth: 0,
97+
flexGrow: 1,
8798
position: 'relative',
8899
overflow: 'hidden',
89100
borderLeft: theme.palette.type === 'light' ? '1px solid #DBDBDB' : '1px solid rgba(255, 255, 255, 0.11)',
101+
[theme.breakpoints.down('sm')]: {
102+
borderLeft: 'none',
103+
},
90104
},
91105
simpleTree: {
92106
width: ({ width }) => `${width}px`,
@@ -121,6 +135,30 @@ const useStyles = makeStyles<Theme, { width: number }>((theme) =>
121135
borderLeft: '1px dashed #cececeff',
122136
},
123137
},
138+
mobileTreeButton: {
139+
display: 'none',
140+
flexShrink: 0,
141+
marginLeft: '4px',
142+
[theme.breakpoints.down('sm')]: {
143+
display: 'inline-flex',
144+
},
145+
},
146+
mobileTreePaper: {
147+
width: '86vw',
148+
maxWidth: 360,
149+
backgroundColor: theme.palette.background.default,
150+
overflow: 'hidden',
151+
},
152+
mobileTreeHeader: {
153+
height: globals.common.drawerItemHeight,
154+
borderBottom: theme.palette.type === 'light' ? '1px solid #DBDBDB' : '1px solid rgba(255, 255, 255, 0.11)',
155+
padding: '0 12px',
156+
fontWeight: 500,
157+
},
158+
mobileTreeContent: {
159+
height: `calc(100% - ${globals.common.drawerItemHeight}px)`,
160+
overflow: 'auto',
161+
},
124162
resizeButton: {
125163
position: 'sticky',
126164
top: 0,
@@ -247,6 +285,9 @@ export function Explore({
247285
const classes = useStyles({ width })
248286
const globalClasses = useGlobalStyles()
249287
const isResizing = useRef(false)
288+
const device = useContext(ResponsiveContext)
289+
const [mobileTreeOpened, setMobileTreeOpened] = useState(false)
290+
const isMobile = device === 'mobile'
250291

251292
const handleMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
252293
isResizing.current = true
@@ -370,6 +411,22 @@ export function Explore({
370411
)
371412
}
372413

414+
const handleTreeNavigate = (item: GenericContent) => {
415+
onNavigate(item)
416+
setMobileTreeOpened(false)
417+
}
418+
419+
const renderTree = () => (
420+
<SimpleTree
421+
onItemClick={handleTreeNavigate}
422+
parentPath={PathHelper.isAncestorOf(rootPath, currentPath) ? rootPath : currentPath}
423+
activeItemPath={currentPath}
424+
loadSettings={loadTreeSettings}
425+
onNavigate={handleTreeNavigate}
426+
rootLoaded={false}
427+
/>
428+
)
429+
373430
return (
374431
<LoadSettingsContextProvider
375432
key={JSON.stringify(currentChildrenLoadSettings)}
@@ -379,33 +436,48 @@ export function Explore({
379436
<CurrentChildrenProvider loadSettings={loadChildrenSettings} alwaysRefresh={alwaysRefreshChildren}>
380437
<CurrentAncestorsProvider root={rootPath}>
381438
<div className={clsx(classes.breadcrumbsWrapper, globalClasses.centeredVertical)}>
382-
<ContentBreadcrumbs
383-
onItemClick={(i) => {
384-
onNavigate(i.content)
385-
}}
386-
batchActions={true}
387-
/>
439+
{hasTree && isMobile ? (
440+
<Tooltip title="Open tree" placement="bottom">
441+
<IconButton
442+
className={classes.mobileTreeButton}
443+
size="small"
444+
aria-label="Open tree"
445+
onClick={() => setMobileTreeOpened(true)}>
446+
<MenuIcon fontSize="small" />
447+
</IconButton>
448+
</Tooltip>
449+
) : null}
450+
<div className={classes.breadcrumbsContent}>
451+
<ContentBreadcrumbs
452+
onItemClick={(i) => {
453+
onNavigate(i.content)
454+
}}
455+
batchActions={true}
456+
/>
457+
</div>
388458
</div>
389459

390460
<div className={`${classes.treeAndDatagridWrapper} leftTree theme-${theme.palette.type} `}>
391-
{hasTree && (
461+
{hasTree && !isMobile && (
392462
<div className={classes.simpleTree}>
393463
<div className={classes.resizeButton} onMouseDown={handleMouseDown}>
394464
<div className={classes.symbol}>&#8596;</div>
395465
</div>
396-
<SimpleTree
397-
onItemClick={(item) => {
398-
onNavigate(item)
399-
}}
400-
parentPath={PathHelper.isAncestorOf(rootPath, currentPath) ? rootPath : currentPath}
401-
activeItemPath={currentPath}
402-
loadSettings={loadTreeSettings}
403-
onNavigate={onNavigate}
404-
rootLoaded={false}
405-
/>
466+
{renderTree()}
406467
</div>
407468
)}
408469
<div className={classes.exploreContainer}>{renderContent()}</div>
470+
{hasTree && isMobile ? (
471+
<SwipeableDrawer
472+
open={mobileTreeOpened}
473+
onOpen={() => setMobileTreeOpened(true)}
474+
onClose={() => setMobileTreeOpened(false)}
475+
ModalProps={{ keepMounted: true }}
476+
PaperProps={{ className: classes.mobileTreePaper }}>
477+
<div className={clsx(classes.mobileTreeHeader, globalClasses.centeredVertical)}>Content tree</div>
478+
<div className={classes.mobileTreeContent}>{renderTree()}</div>
479+
</SwipeableDrawer>
480+
) : null}
409481
</div>
410482
</CurrentAncestorsProvider>
411483
</CurrentChildrenProvider>

apps/sensenet/src/components/grid/Grid.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { GridProps } from './Props/GridProps'
2121
import { useGridLoading } from './Providers/GridLoadingProvider'
2222

2323
const SMALL_SCREEN_COL_FILTER = ['Id', 'Actions']
24+
const MOBILE_SCREEN_COL_FIELDS = ['0', 'Icon', 'DisplayName', 'Name', 'Actions']
2425

2526
export function Grid<T extends GenericContent = GenericContent>(props: GridProps<T>) {
2627
const { isGridLoading, setIsGridLoading } = useGridLoading()
@@ -167,7 +168,10 @@ export function Grid<T extends GenericContent = GenericContent>(props: GridProps
167168

168169
const updateColumnDefsBasedOnWindowSize = useCallback(() => {
169170
const width = window.innerWidth
170-
if (width < 1536) {
171+
if (width < 600) {
172+
const mobileCols = props.colDef.filter((col) => MOBILE_SCREEN_COL_FIELDS.includes(col.field || ''))
173+
setColumnDefs(mobileCols.length ? mobileCols : props.colDef.slice(0, 3))
174+
} else if (width < 1536) {
171175
const filteredCols = props.colDef.filter((col) => !SMALL_SCREEN_COL_FILTER.includes(col.field || ''))
172176
setColumnDefs(filteredCols)
173177
} else {
@@ -196,9 +200,9 @@ export function Grid<T extends GenericContent = GenericContent>(props: GridProps
196200

197201
useEffect(() => {
198202
if (gridApi.current) {
199-
gridApi.current.setColumnDefs([...props.colDef])
203+
updateColumnDefsBasedOnWindowSize()
200204
}
201-
}, [props.colDef])
205+
}, [props.colDef, updateColumnDefsBasedOnWindowSize])
202206

203207
const onSortChanged = useCallback(() => {
204208
if (columnApi.current) {

apps/sensenet/src/components/layout/DesktopLayout.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { createStyles, makeStyles, Theme } from '@material-ui/core'
22
import { useInjector, useRepository } from '@sensenet/hooks-react'
33
import { clsx } from 'clsx'
44
import React, { useContext, useEffect, useState } from 'react'
5-
import { ResponsivePersonalSettings } from '../../context'
5+
import { ResponsiveContext, ResponsivePersonalSettings } from '../../context'
66
import { globals, useGlobalStyles } from '../../globalStyles'
77
import { CustomActionCommandProvider } from '../../services/CommandProviders/CustomActionCommandProvider'
88
import { DesktopAppBar } from '../appbar/desktop-app-bar'
@@ -47,12 +47,14 @@ const useStyles = makeStyles((theme: Theme) => {
4747

4848
export const DesktopLayout: React.FunctionComponent = (props) => {
4949
const settings = useContext(ResponsivePersonalSettings)
50+
const device = useContext(ResponsiveContext)
5051
const repo = useRepository()
5152
const { openDialog, closeLastDialog } = useDialog()
5253
const customActionService = useInjector().getInstance(CustomActionCommandProvider)
5354
const [tempDrawerOpened, setTempDrawerOpened] = useState(false)
5455
const classes = useStyles()
5556
const globalClasses = useGlobalStyles()
57+
const useTemporaryDrawer = settings.drawer.type === 'temporary' || device === 'mobile'
5658

5759
useEffect(() => {
5860
const observables = [
@@ -99,7 +101,7 @@ export const DesktopLayout: React.FunctionComponent = (props) => {
99101
<div className={classes.drawerandContentSlot}>
100102
{settings.drawer.enabled ? (
101103
<>
102-
{settings.drawer.type === 'temporary' ? (
104+
{useTemporaryDrawer ? (
103105
<TemporaryDrawer
104106
onClose={() => setTempDrawerOpened(false)}
105107
onOpen={() => setTempDrawerOpened(true)}

apps/sensenet/src/components/view-controls/common/styles.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,20 @@ const useStyles = makeStyles((theme) => {
88
overflowY: 'auto',
99
maxWidth: '100%',
1010
maxHeight: `calc(100% - ${globals.common.formActionButtonsHeight}px - ${globals.common.formTitleHeight}px)`,
11+
[theme.breakpoints.down('sm')]: {
12+
padding: '12px',
13+
maxHeight: `calc(100% - ${globals.common.formActionButtonsHeight}px - ${globals.common.formTitleHeight}px)`,
14+
},
1115
},
1216
actionButtonWrapper: {
1317
padding: '8px',
1418
paddingRight: '39px',
1519
borderTop: theme.palette.type === 'light' ? '1px solid #DBDBDB' : '1px solid rgba(255, 255, 255, 0.11)',
1620
marginTop: 'auto',
21+
[theme.breakpoints.down('sm')]: {
22+
paddingRight: '8px',
23+
flexWrap: 'wrap',
24+
},
1725
},
1826
})
1927
})

apps/sensenet/src/components/view-controls/common/view-title.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,21 @@ const useStyles = makeStyles((theme) => {
2424
borderBottom: theme.palette.type === 'light' ? '1px solid #DBDBDB' : '1px solid rgba(255, 255, 255, 0.11)',
2525
display: 'flex',
2626
flexDirection: 'column',
27+
minWidth: 0,
28+
[theme.breakpoints.down('sm')]: {
29+
fontSize: '16px',
30+
},
2731
},
2832
textBolder: {
2933
fontWeight: 500,
3034
textAlign: 'center',
35+
overflowWrap: 'anywhere',
3136
},
3237
actionBar: {
3338
display: 'flex',
3439
marginBottom: '6px',
40+
flexWrap: 'wrap',
41+
justifyContent: 'center',
3542
},
3643
typeinfo: {
3744
fontSize: '12px',
@@ -44,6 +51,9 @@ const useStyles = makeStyles((theme) => {
4451
},
4552
viewTitle: {
4653
padding: '6px',
54+
maxWidth: '100%',
55+
boxSizing: 'border-box',
56+
overflowWrap: 'anywhere',
4757
},
4858
})
4959
})

0 commit comments

Comments
 (0)