Skip to content

Commit 865b75c

Browse files
committed
fix(admin-ui): improve mobile header controls
1 parent cf172e1 commit 865b75c

8 files changed

Lines changed: 157 additions & 86 deletions

File tree

.env.example

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ SENSENET_DEV_PORT=3000
1414
# Development Settings (for hot reload)
1515
CHOKIDAR_USEPOLLING=true
1616
WATCHPACK_POLLING=true
17+
DISABLE_VIEW_OPTIONS_MENU=false
18+
WEBPACK_DEV_SERVER_CLIENT_WEB_SOCKET_URL=auto://0.0.0.0:0/ws
1719

1820
# Database Settings (if using database service)
1921
# DB_PASSWORD=YourPassword123!
@@ -28,4 +30,4 @@ WATCHPACK_POLLING=true
2830

2931
# Backend API URL (if connecting to external backend)
3032
# REACT_APP_SERVICE_URL=https://dev.demo.sensenet.com
31-
# REACT_APP_IDENTITY_SERVER_URL=https://is.demo.sensenet.com
33+
# REACT_APP_IDENTITY_SERVER_URL=https://is.demo.sensenet.com

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,20 @@ const useStyles = makeStyles((theme) => {
2525
minHeight: '42px',
2626
paddingLeft: '6px',
2727
paddingRight: 0,
28+
[theme.breakpoints.down('sm')]: {
29+
paddingLeft: '2px',
30+
},
2831
},
2932
logo: {
3033
marginRight: '21px',
34+
[theme.breakpoints.down('sm')]: {
35+
marginRight: '4px',
36+
},
37+
},
38+
drawerButton: {
39+
padding: '8px',
40+
marginRight: '2px',
41+
flex: '0 0 auto',
3142
},
3243
commandPaletteReplacement: {
3344
flex: 1,
@@ -46,9 +57,7 @@ const useStyles = makeStyles((theme) => {
4657
cursor: 'pointer',
4758
},
4859
[theme.breakpoints.down('sm')]: {
49-
maxWidth: '28vw',
50-
marginRight: '0.5rem',
51-
fontSize: '13px',
60+
display: 'none',
5261
},
5362
},
5463
})
@@ -122,6 +131,7 @@ export const DesktopAppBar: React.FunctionComponent<{ openDrawer?: () => void }>
122131
</Link>
123132
{personalSettings.drawer.enabled && (personalSettings.drawer.type === 'temporary' || device === 'mobile') ? (
124133
<IconButton
134+
className={classes.drawerButton}
125135
onClick={() => {
126136
props.openDrawer && props.openDrawer()
127137
}}>

apps/sensenet/src/components/appbar/desktop-nav-menu.tsx

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,24 @@ const useStyles = makeStyles((theme: Theme) =>
2222
cursor: 'pointer',
2323
marginRight: '16px',
2424
padding: '7px',
25+
[theme.breakpoints.down('sm')]: {
26+
marginRight: '6px',
27+
},
2528
},
2629
navMenu: {
2730
height: '100%',
2831
width: '140px',
2932
background: theme.palette.background.default,
33+
flex: '0 0 auto',
34+
[theme.breakpoints.down('sm')]: {
35+
width: '112px',
36+
},
37+
},
38+
navMenuCompact: {
39+
width: '76px',
40+
[theme.breakpoints.down('sm')]: {
41+
width: '70px',
42+
},
3043
},
3144
paper: {
3245
marginRight: theme.spacing(2),
@@ -77,6 +90,7 @@ const useStyles = makeStyles((theme: Theme) =>
7790
)
7891

7992
export const DesktopNavMenu: FunctionComponent = () => {
93+
const isViewOptionsMenuDisabled = process.env.DISABLE_VIEW_OPTIONS_MENU === 'true'
8094
const personalSettings = usePersonalSettings()
8195
const injector = useInjector()
8296
const classes = useStyles()
@@ -134,15 +148,17 @@ export const DesktopNavMenu: FunctionComponent = () => {
134148
}
135149

136150
return (
137-
<div className={clsx(globalClasses.centered, classes.navMenu)}>
151+
<div className={clsx(globalClasses.centered, classes.navMenu, isViewOptionsMenuDisabled && classes.navMenuCompact)}>
138152
<>
139-
<IconButton
140-
aria-label={localization.topMenu.openViewOptions}
141-
aria-controls={openViewOptions ? 'menu-list-grow' : undefined}
142-
className={classes.viewOptions}
143-
onClick={() => handleToggle(setOpenViewOptions)}>
144-
<TuneOutlined />
145-
</IconButton>
153+
{!isViewOptionsMenuDisabled ? (
154+
<IconButton
155+
aria-label={localization.topMenu.openViewOptions}
156+
aria-controls={openViewOptions ? 'menu-list-grow' : undefined}
157+
className={classes.viewOptions}
158+
onClick={() => handleToggle(setOpenViewOptions)}>
159+
<TuneOutlined />
160+
</IconButton>
161+
) : null}
146162
<UserAvatar
147163
user={user!}
148164
repositoryUrl={repo.configuration.repositoryUrl}
@@ -231,7 +247,7 @@ export const DesktopNavMenu: FunctionComponent = () => {
231247
</div>
232248
</Paper>
233249
) : null}
234-
{openViewOptions ? (
250+
{!isViewOptionsMenuDisabled && openViewOptions ? (
235251
<Paper className={classes.popperViewWrapper}>
236252
<div className={classes.popper}>
237253
<ClickAwayListener onClickAway={() => handleClose(setOpenViewOptions)}>

apps/sensenet/src/components/command-palette/CommandPalette.tsx

Lines changed: 104 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createStyles, IconButton, makeStyles, Tooltip } from '@material-ui/core'
1+
import { createStyles, IconButton, makeStyles } from '@material-ui/core'
22
import Clear from '@material-ui/icons/Clear'
33
import Search from '@material-ui/icons/Search'
44
import { debounce } from '@sensenet/client-utils'
@@ -10,7 +10,7 @@ import Autosuggest, { SuggestionSelectedEventData, SuggestionsFetchRequestedPara
1010
import { useHistory } from 'react-router-dom'
1111
import { ResponsiveContext, ResponsivePersonalSettings } from '../../context'
1212
import { globals } from '../../globalStyles'
13-
import { useLocalization, useSelectionService, useSnRoute, useTheme } from '../../hooks'
13+
import { useLocalization, useSelectionService, useSnRoute } from '../../hooks'
1414
import { CommandProviderManager } from '../../services'
1515
import { ContentContextMenu } from '../context-menu/content-context-menu'
1616
import { CommandPaletteHitsContainer } from './CommandPaletteHitsContainer'
@@ -26,7 +26,7 @@ export interface CommandPaletteItem {
2626
parameters?: string[]
2727
}
2828

29-
const useStyles = makeStyles(() => {
29+
const useStyles = makeStyles((theme) => {
3030
return createStyles({
3131
buttonWrapper: {
3232
display: 'flex',
@@ -37,6 +37,9 @@ const useStyles = makeStyles(() => {
3737
'& .MuiIconButton-root': {
3838
color: globals.common.headerText,
3939
},
40+
[theme.breakpoints.down('sm')]: {
41+
flex: '0 0 auto',
42+
},
4043
},
4144
iconButton: {
4245
color: globals.common.headerText,
@@ -48,6 +51,23 @@ const useStyles = makeStyles(() => {
4851
width: '50%',
4952
marginRight: '9px',
5053
},
54+
mobileComboBox: {
55+
position: 'absolute',
56+
top: globals.common.headerHeight,
57+
left: 0,
58+
right: 0,
59+
zIndex: theme.zIndex.appBar + 1,
60+
width: 'auto',
61+
marginRight: 0,
62+
padding: '6px 8px',
63+
boxSizing: 'border-box',
64+
backgroundColor: globals.common.headerBackground,
65+
boxShadow: theme.shadows[2],
66+
},
67+
mobileOpenButton: {
68+
padding: '8px',
69+
marginRight: '2px',
70+
},
5171
input: {
5272
color: 'white',
5373
backgroundColor: '#016ea5ff',
@@ -94,7 +114,6 @@ export const CommandPalette = () => {
94114
const [items, setItems] = useState<CommandPaletteItem[]>([])
95115
const [inputValue, setInputValue] = useState('')
96116
const localization = useLocalization().commandPalette
97-
const theme = useTheme()
98117
const history = useHistory()
99118
const classes = useStyles()
100119
const device = useContext(ResponsiveContext)
@@ -237,6 +256,8 @@ export const CommandPalette = () => {
237256
}
238257

239258
const actionMode = inputValue.startsWith('>')
259+
const isMobile = device === 'mobile'
260+
const showCollapsedMobileSearch = isMobile && !isOpened
240261
const actionContextHeader = actionMode ? (
241262
<div className={classes.actionContextHeader} data-test="command-palette-action-context">
242263
{activeContent ? (
@@ -255,72 +276,87 @@ export const CommandPalette = () => {
255276

256277
return (
257278
<div className={classes.buttonWrapper}>
258-
<div ref={containerRef} className={classes.comboBox} data-test="command-box">
259-
<Autosuggest<CommandPaletteItem>
260-
theme={{
261-
suggestionsList: {
262-
listStyle: 'none',
263-
margin: 0,
264-
padding: 0,
265-
},
266-
inputFocused: {
267-
outlineWidth: 0,
268-
},
269-
}}
270-
alwaysRenderSuggestions={isOpened}
271-
suggestions={items}
272-
highlightFirstSuggestion={true}
273-
onSuggestionSelected={handleSelectSuggestion}
274-
onSuggestionsFetchRequested={handleSuggestionsFetchRequested}
275-
onSuggestionsClearRequested={() => setItems([])}
276-
getSuggestionValue={(suggestion) => suggestion.primaryText}
277-
renderSuggestion={(suggestion, params) => (
278-
<CommandPaletteSuggestion
279-
suggestion={suggestion}
280-
params={params}
281-
onOpenContextMenu={handleOpenSuggestionContextMenu}
282-
/>
279+
{showCollapsedMobileSearch ? (
280+
<IconButton
281+
aria-label={localization.title}
282+
title={localization.title}
283+
className={classes.mobileOpenButton}
284+
onClick={() => setIsOpened(true)}
285+
data-test="command-palette-mobile-open">
286+
<Search />
287+
</IconButton>
288+
) : (
289+
<div
290+
ref={containerRef}
291+
className={clsx(classes.comboBox, isMobile && classes.mobileComboBox)}
292+
data-test="command-box">
293+
<Autosuggest<CommandPaletteItem>
294+
theme={{
295+
suggestionsList: {
296+
listStyle: 'none',
297+
margin: 0,
298+
padding: 0,
299+
},
300+
inputFocused: {
301+
outlineWidth: 0,
302+
},
303+
}}
304+
alwaysRenderSuggestions={isOpened}
305+
suggestions={items}
306+
highlightFirstSuggestion={true}
307+
onSuggestionSelected={handleSelectSuggestion}
308+
onSuggestionsFetchRequested={handleSuggestionsFetchRequested}
309+
onSuggestionsClearRequested={() => setItems([])}
310+
getSuggestionValue={(suggestion) => suggestion.primaryText}
311+
renderSuggestion={(suggestion, params) => (
312+
<CommandPaletteSuggestion
313+
suggestion={suggestion}
314+
params={params}
315+
onOpenContextMenu={handleOpenSuggestionContextMenu}
316+
/>
317+
)}
318+
renderSuggestionsContainer={(params) => (
319+
<CommandPaletteHitsContainer {...params} header={actionContextHeader} />
320+
)}
321+
inputProps={{
322+
className: `${classes.input} ${inputValue ? classes.inputOpened : ''}`,
323+
value: inputValue,
324+
placeholder: localization.title,
325+
onChange: (_ev, changeEvent) => {
326+
setInputValue(changeEvent.newValue)
327+
},
328+
id: 'CommandBoxInput',
329+
spellCheck: false,
330+
onBlur: () => {
331+
if (!isContextMenuInteractingRef.current) {
332+
setIsOpened(false)
333+
}
334+
},
335+
}}
336+
/>
337+
{!inputValue && (
338+
<IconButton
339+
title={localization.title}
340+
style={{ position: 'absolute', right: '8px', zIndex: 2, top: '50%', transform: 'translateY(-50%)' }}
341+
onMouseDown={(ev) => ev.preventDefault()}>
342+
<Search />
343+
</IconButton>
283344
)}
284-
renderSuggestionsContainer={(params) => (
285-
<CommandPaletteHitsContainer {...params} header={actionContextHeader} />
345+
{inputValue && (
346+
<IconButton
347+
title={localization.clear}
348+
style={{ position: 'absolute', right: '8px', zIndex: 2, top: '50%', transform: 'translateY(-50%)' }}
349+
onClick={() => {
350+
setInputValue('')
351+
setItems([])
352+
handleSuggestionsFetchRequested({ value: '', reason: 'input-changed' })
353+
}}
354+
onMouseDown={(ev) => ev.preventDefault()}>
355+
<Clear />
356+
</IconButton>
286357
)}
287-
inputProps={{
288-
className: `${classes.input} ${inputValue ? classes.inputOpened : ''}`,
289-
value: inputValue,
290-
placeholder: 'Search',
291-
onChange: (_ev, changeEvent) => {
292-
setInputValue(changeEvent.newValue)
293-
},
294-
id: 'CommandBoxInput',
295-
spellCheck: false,
296-
onBlur: () => {
297-
if (!isContextMenuInteractingRef.current) {
298-
setIsOpened(false)
299-
}
300-
},
301-
}}
302-
/>
303-
{!inputValue && (
304-
<IconButton
305-
title={'search'}
306-
style={{ position: 'absolute', right: '0px', zIndex: 2, top: '50%', transform: 'translateY(-50%)' }}>
307-
<Search />
308-
</IconButton>
309-
)}
310-
{inputValue && (
311-
<IconButton
312-
title={localization.clear}
313-
style={{ position: 'absolute', right: '0px', zIndex: 2, top: '50%', transform: 'translateY(-50%)' }}
314-
onClick={() => {
315-
setInputValue('')
316-
setItems([])
317-
handleSuggestionsFetchRequested({ value: '', reason: 'input-changed' })
318-
}}
319-
onMouseDown={(ev) => ev.preventDefault()}>
320-
<Clear />
321-
</IconButton>
322-
)}
323-
</div>
358+
</div>
359+
)}
324360
{contextMenuContent ? (
325361
<ContentContextMenu
326362
isOpened={isContextMenuOpened}

apps/sensenet/src/components/command-palette/CommandPaletteHitsContainer.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ export const CommandPaletteHitsContainer: FunctionComponent<
1616
square={true}
1717
style={{
1818
position: 'absolute',
19-
zIndex: 1,
20-
left: device === 'mobile' ? '64px' : undefined,
21-
width: device === 'mobile' ? 'calc(100% - 80px)' : '100%',
19+
zIndex: device === 'mobile' ? 1301 : 1,
20+
left: device === 'mobile' ? 0 : undefined,
21+
width: '100%',
2222
}}>
2323
<>
2424
{options.header}

apps/sensenet/webpack.common.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ module.exports = {
6060
new webpack.EnvironmentPlugin({
6161
APP_VERSION: require('./package.json').version,
6262
AUTH_TYPE: process.env.AUTH_TYPE || 'SNAuth', // Default to SNAuth if not specified
63+
DISABLE_VIEW_OPTIONS_MENU: process.env.DISABLE_VIEW_OPTIONS_MENU || 'false',
6364
}),
6465
new MonacoWebpackPlugin({
6566
languages: ['json', 'xml', 'html', 'javascript', 'markdown'],

apps/sensenet/webpack.dev.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const common = require('./webpack.common.js')
55

66
module.exports = (env) => {
77
const disableDevReload = process.env.DISABLE_DEV_RELOAD === 'true'
8+
const clientWebSocketURL = process.env.WEBPACK_DEV_SERVER_CLIENT_WEB_SOCKET_URL || 'auto://0.0.0.0:0/ws'
89

910
return mergeWithCustomize({
1011
customizeArray: customizeArray({
@@ -20,6 +21,9 @@ module.exports = (env) => {
2021
liveReload: !disableDevReload,
2122
open: true,
2223
allowedHosts: process.env.ALLOWED_HOSTS || 'auto',
24+
client: {
25+
webSocketURL: clientWebSocketURL,
26+
},
2327
},
2428
output: {
2529
filename: 'static/js/[name].js',

0 commit comments

Comments
 (0)