Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Genesys PGR
Genesys Website
Commits
3d02490e
Commit
3d02490e
authored
Jan 26, 2019
by
Matija Obreza
Browse files
Merge branch '192-map-click-accessions-list' into 'master'
Map click accessions list Closes
#192
See merge request genesys-pgr/genesys-ui!192
parents
800310cb
3eb4c959
Changes
11
Hide whitespace changes
Inline
Side-by-side
locales/en/translations.json
View file @
3d02490e
...
...
@@ -1476,7 +1476,7 @@
"NumericListDimension"
:
"NumericListDimension"
,
"StringListDimension"
:
"StringListDimension"
},
"showRun"
:
"Show
run info
"
,
"showRun"
:
"Show"
,
"executionRunsLoaded"
:
"Execution runs loaded successfully"
}
}
...
...
src/accessions/actions/public.ts
View file @
3d02490e
...
...
@@ -9,8 +9,9 @@ import AccessionFilter from 'model/accession/AccessionFilter';
import
AccessionDetails
from
'
model/accession/AccessionDetails
'
;
import
AccessionMapInfo
from
'
model/accession/AccessionMapInfo
'
;
import
AccessionAuditLog
from
'
model/accession/AccessionAuditLog
'
;
import
MapLayer
from
'
model/genesys/MapTileLayer
'
;
import
{
RECEIVE_ACCESSIONS
,
RECEIVE_ACCESSION
,
RECEIVE_ACCESSION_OVERVIEW
,
APPEND_ACCESSIONS
,
RECEIVE_ACCESSION_MAPINFO
,
RECEIVE_ACCESSION_AUDIT_LOG
}
from
'
accessions/constants
'
;
import
{
RECEIVE_ACCESSIONS
,
RECEIVE_ACCESSION
,
RECEIVE_ACCESSION_OVERVIEW
,
APPEND_ACCESSIONS
,
RECEIVE_ACCESSION_MAPINFO
,
RECEIVE_ACCESSION_AUDIT_LOG
,
RECEIVE_TILE_LAYER
}
from
'
accessions/constants
'
;
import
AccessionService
from
'
service/genesys/AccessionService
'
;
import
{
showSnackbar
}
from
'
actions/snackbar
'
;
import
Page
from
'
model/Page
'
;
...
...
@@ -199,3 +200,13 @@ export const overviewAccessions = (filterCode: string) => (dispatch) => {
dispatch
(
receiveAccessionOverview
(
null
,
error
));
});
};
// TileLayers
const
receiveTileLayerInfo
=
(
tileLayer
:
MapLayer
)
=>
({
type
:
RECEIVE_TILE_LAYER
,
payload
:
{
tileLayer
},
});
export
const
updateTileLayerInfo
=
(
tileLayer
:
MapLayer
)
=>
(
dispatch
)
=>
{
return
dispatch
(
receiveTileLayerInfo
(
tileLayer
));
};
src/accessions/constants.ts
View file @
3d02490e
export
const
RECEIVE_ACCESSIONS
=
'
accessions/RECEIVE_ACCESSIONS
'
;
export
const
APPEND_ACCESSIONS
=
'
accessions/APPEND_ACCESSIONS
'
;
export
const
RECEIVE_ACCESSION_OVERVIEW
=
'
accessions/RECEIVE_ACCESSION_OVERVIEW
'
;
export
const
RECEIVE_TILE_LAYER
=
'
accessions/RECEIVE_TILE_LAYER
'
;
export
const
RECEIVE_ACCESSION_AUDIT_LOG
=
'
accessions/RECEIVE_ACCESSION_AUDIT_LOG
'
;
export
const
RECEIVE_ACCESSION
=
'
accessions/RECEIVE_ACCESSION
'
;
export
const
RECEIVE_ACCESSION_MAPINFO
=
'
accessions/RECEIVE_ACCESSION_MAPINFO
'
;
...
...
src/accessions/reducers/public.ts
View file @
3d02490e
import
update
from
'
immutability-helper
'
;
import
{
IReducerAction
}
from
'
model/common.model
'
;
import
{
RECEIVE_ACCESSIONS
,
RECEIVE_ACCESSION
,
RECEIVE_ACCESSION_OVERVIEW
,
APPEND_ACCESSIONS
,
RECEIVE_ACCESSION_MAPINFO
,
RECEIVE_ACCESSION_AUDIT_LOG
}
from
'
accessions/constants
'
;
import
{
RECEIVE_ACCESSIONS
,
RECEIVE_ACCESSION
,
RECEIVE_ACCESSION_OVERVIEW
,
APPEND_ACCESSIONS
,
RECEIVE_ACCESSION_MAPINFO
,
RECEIVE_ACCESSION_AUDIT_LOG
,
RECEIVE_TILE_LAYER
,
}
from
'
accessions/constants
'
;
import
FilteredPage
from
'
model/FilteredPage
'
;
import
Accession
from
'
model/accession/Accession
'
;
import
AccessionMapInfo
from
'
model/accession/AccessionMapInfo
'
;
import
AccessionOverview
from
'
model/accession/AccessionOverview
'
;
import
AccessionAuditLog
from
'
model/accession/AccessionAuditLog
'
;
import
MapLayer
,
{
AVAILABLE_LAYERS
}
from
'
model/genesys/MapTileLayer
'
;
const
INITIAL_STATE
:
{
accession
:
Accession
;
...
...
@@ -17,6 +26,7 @@ const INITIAL_STATE: {
pagedError
:
any
;
overview
:
AccessionOverview
;
mapInfo
:
AccessionMapInfo
;
mapLayers
:
MapLayer
[]
}
=
{
accession
:
null
,
auditLog
:
null
,
...
...
@@ -25,6 +35,7 @@ const INITIAL_STATE: {
pagedError
:
null
,
overview
:
null
,
mapInfo
:
null
,
mapLayers
:
AVAILABLE_LAYERS
,
};
function
publicAccessions
(
state
=
INITIAL_STATE
,
action
:
IReducerAction
)
{
...
...
@@ -109,6 +120,16 @@ function publicAccessions(state = INITIAL_STATE, action: IReducerAction) {
overview
:
{
$set
:
null
},
});
}
case
RECEIVE_TILE_LAYER
:
{
const
{
tileLayer
}
=
action
.
payload
;
const
indexToUpdate
=
state
.
mapLayers
.
findIndex
((
layerItem
)
=>
layerItem
.
name
===
tileLayer
.
name
);
return
update
(
state
,
{
mapLayers
:
{
[
indexToUpdate
]:
{
$set
:
tileLayer
},
},
});
}
default
:
return
state
;
...
...
src/accessions/ui/MapPage.tsx
View file @
3d02490e
...
...
@@ -8,19 +8,20 @@ import { loadAccessionsMapInfo } from 'accessions/actions/public';
import
AccessionFilter
from
'
model/accession/AccessionFilter
'
;
import
Loading
from
'
ui/common/Loading
'
;
import
AccessionMapInfo
from
'
model/accession/AccessionMapInfo
'
;
import
PageLayout
from
'
ui/layout/PageLayout
'
;
import
ContentHeader
from
'
ui/common/heading/ContentHeader
'
;
import
MapLayer
from
'
model/genesys/MapTileLayer
'
;
import
Button
from
'
@material-ui/core/Button
'
;
import
Tabs
,
{
Tab
}
from
'
ui/common/Tabs
'
;
import
PrettyFilters
from
'
ui/common/filter/PrettyFilters
'
;
import
ButtonBar
from
'
ui/common/buttons/ButtonBar
'
;
import
ContentLayout
from
'
ui/layout/ContentLayout
'
;
import
MapConfigSection
from
'
./c/MapConfigSection
'
;
import
AccessionService
from
'
service/genesys/AccessionService
'
;
let
Map
;
let
TileLayer
;
let
Popup
;
let
Marker
;
let
Rectangle
;
const
popupContentLimit
=
11
;
...
...
@@ -33,6 +34,7 @@ interface IMapPageProps {
currentTab
:
string
;
filterCode
:
string
;
loadAccessionsMapInfo
:
any
;
mapLayers
:
MapLayer
[];
}
const
styles
=
(
theme
)
=>
({
...
...
@@ -54,7 +56,8 @@ class BrowsePage extends React.Component<IMapPageProps, any> {
];
public
state
=
{
popupPosition
:
[],
clickLocation
:
[],
searchBox
:
null
,
geoData
:
[],
otherCount
:
0
,
};
...
...
@@ -64,8 +67,8 @@ class BrowsePage extends React.Component<IMapPageProps, any> {
if
(
typeof
window
!==
'
undefined
'
)
{
Map
=
require
(
'
react-leaflet
'
).
Map
;
TileLayer
=
require
(
'
react-leaflet
'
).
TileLayer
;
Marker
=
require
(
'
react-leaflet
'
).
Marker
;
Popup
=
require
(
'
react-leaflet
'
).
Popup
;
Rectangle
=
require
(
'
react-leaflet
'
).
Rectangle
;
}
}
...
...
@@ -103,21 +106,27 @@ class BrowsePage extends React.Component<IMapPageProps, any> {
console
.
log
(
e
);
const
width
=
Math
.
pow
(
2
,
currentZoom
-
2
);
console
.
log
(
`zoom=
${
currentZoom
}
width=
${
width
}
diff=
${
3
/
width
}
`
);
const
searchBounds
:
number
[][]
=
[
[
e
.
latlng
.
lat
-
(
3
/
width
),
correctLng
-
(
3
/
width
)
],
[
e
.
latlng
.
lat
+
(
3
/
width
),
correctLng
+
(
3
/
width
)
],
];
const
filterWithGeo
=
{
...
filter
,
geo
:
{
longitude
:
{
ge
:
correctLng
-
(
3
/
currentZoom
)
,
le
:
correctLng
+
(
3
/
currentZoom
)
,
ge
:
searchBounds
[
0
][
1
]
,
le
:
searchBounds
[
1
][
1
]
,
},
latitude
:
{
ge
:
e
.
latlng
.
lat
-
(
3
/
currentZoom
)
,
le
:
e
.
latlng
.
lat
+
(
3
/
currentZoom
)
,
ge
:
searchBounds
[
0
][
0
]
,
le
:
searchBounds
[
1
][
0
]
,
},
},
};
AccessionService
.
geoJson
(
filterWithGeo
,
popupContentLimit
)
.
then
((
res
)
=>
this
.
setState
({
popupPosi
tion
:
[
e
.
latlng
.
lat
,
e
.
latlng
.
lng
],
geoData
:
res
.
geoJson
,
otherCount
:
res
.
otherCount
}));
.
then
((
res
)
=>
this
.
setState
({
clickLoca
tion
:
[
e
.
latlng
.
lat
,
e
.
latlng
.
lng
],
searchBox
:
searchBounds
,
geoData
:
res
.
geoJson
,
otherCount
:
res
.
otherCount
}));
},
200
);
}
...
...
@@ -129,10 +138,10 @@ class BrowsePage extends React.Component<IMapPageProps, any> {
}
public
render
()
{
const
{
popupPosition
,
geoData
,
otherCount
}
=
this
.
state
;
const
{
searchBox
,
geoData
,
otherCount
}
=
this
.
state
;
const
position
=
[
30
,
0
];
const
{
mapInfo
,
currentTab
,
classes
,
filterCode
,
t
}
=
this
.
props
;
const
{
mapInfo
,
mapLayers
,
currentTab
,
classes
,
filterCode
,
t
}
=
this
.
props
;
if
(
!
mapInfo
)
{
return
<
Loading
/>;
...
...
@@ -142,8 +151,11 @@ class BrowsePage extends React.Component<IMapPageProps, any> {
const
layerUrl
=
`{s}/acn/tile/{z}/{x}/{y}?f=
${
filterCode
?
filterCode
:
''
}
`
;
// `&color=${color}`;
return
(
<
PageLayout
withFooter
>
<
ContentHeader
title
=
{
t
(
'
accessions.public.p.browse.title
'
)
}
subTitle
=
{
t
(
'
accessions.public.p.browse.subTitle
'
)
}
/>
<
ContentLayout
right
=
{
<
MapConfigSection
/>
}
rightAlwaysCollapsible
customHeaderHeight
>
<
Tabs
tab
=
{
currentTab
}
actions
=
{
...
...
@@ -174,18 +186,16 @@ class BrowsePage extends React.Component<IMapPageProps, any> {
zoom
=
{
3
}
minZoom
=
{
2
}
maxZoom
=
{
14
}
bounds
=
{
mapInfo
.
bounds
}
>
<
TileLayer
zIndex
=
{
0
}
opacity
=
{
0.50
}
attribution
=
{
'
© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors
'
}
url
=
{
'
https://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png
'
}
/>
{
mapLayers
&&
mapLayers
.
filter
((
layer
)
=>
layer
.
enabled
).
map
((
layer
,
index
)
=>
<
TileLayer
zIndex
=
{
index
+
1
}
key
=
{
layer
.
name
}
{
...
layer
}
/>)
}
<
TileLayer
opacity
=
{
0.50
}
maxZoom
=
{
7
}
attribution
=
{
'
© worldclim.org
'
}
url
=
{
'
https://{s}.tile.genesys-pgr.org/worldclim1.4/bio1/{z}/{x}/{y}.png
'
}
subdomains
=
{
[
'
a
'
,
'
b
'
,
'
c
'
,
'
d
'
]
}
/>
<
TileLayer
zIndex
=
{
mapLayers
.
length
+
1
}
updateInterval
=
{
1000
}
updateWhenZooming
=
{
false
}
attribution
=
"&copy Accession localities from <a href="/">Genesys PGR</a>"
...
...
@@ -193,25 +203,29 @@ class BrowsePage extends React.Component<IMapPageProps, any> {
subdomains
=
{
mapInfo
.
tileServers
}
/>
{
geoData
&&
geoData
.
length
>
0
&&
<
Marker
position
=
{
popupPosition
}
ref
=
{
(
marker
)
=>
marker
&&
marker
.
leafletElement
.
openPopup
()
}
>
<
Rectangle
bounds
=
{
searchBox
}
ref
=
{
(
marker
)
=>
marker
&&
marker
.
leafletElement
.
openPopup
()
}
>
<
Popup
open
>
<
div
>
{
geoData
.
map
((
feature
)
=>
(<
div
><
Link
to
=
{
`/a/
${
feature
.
properties
.
uuid
}
`
}
>
{
`
${
feature
.
properties
.
accessionNumber
}
${
feature
.
properties
.
instCode
}
`
}
</
Link
></
div
>))
}
{
otherCount
>
0
&&
<
div
>
{
t
(
'
accessions.public.p.map.andMore
'
,
{
otherMore
:
otherCount
})
}
</
div
>
}
</
div
>
</
Popup
>
</
Marker
>
</
Rectangle
>
}
</
Map
>
}
</
div
>
</
Page
Layout
>
</
Content
Layout
>
);
}
}
const
mapStateToProps
=
(
state
,
ownProps
)
=>
({
mapInfo
:
state
.
accessions
.
public
.
mapInfo
||
undefined
,
mapLayers
:
state
.
accessions
.
public
.
mapLayers
,
filterCode
:
ownProps
.
match
.
params
.
filterCode
||
''
,
currentTab
:
ownProps
.
match
.
params
.
tab
||
'
map
'
,
// current tab, or ownProps.location.pathname
});
...
...
src/accessions/ui/c/MapConfigSection.tsx
0 → 100644
View file @
3d02490e
import
*
as
React
from
'
react
'
;
import
{
connect
}
from
'
react-redux
'
;
// model
import
MapLayer
from
'
model/genesys/MapTileLayer
'
;
// ui
import
withStyles
from
'
@material-ui/core/styles/withStyles
'
;
import
ExpandFiltersComponent
from
'
ui/common/filter/ExpandFiltersComponent
'
;
import
{
Divider
}
from
'
@material-ui/core
'
;
import
MapLayerConfig
from
'
./MapLayerConfig
'
;
/*tslint:disable*/
const
styles
=
(
theme
)
=>
({
root
:
{
overflow
:
'
hidden
'
as
'
hidden
'
,
},
layersTitle
:
{
paddingLeft
:
'
8px
'
,
fontSize
:
'
15px
'
,
fontWeight
:
700
,
lineHeight
:
'
40px
'
,
color
:
'
#81807f
'
,
textTransform
:
'
uppercase
'
as
'
uppercase
'
,
},
});
interface
IMapConfigSectionProps
extends
React
.
ClassAttributes
<
any
>
{
classes
:
any
;
mapLayers
:
MapLayer
[];
}
class
MapConfigSection
extends
React
.
Component
<
IMapConfigSectionProps
>
{
public
render
()
{
const
{
classes
,
mapLayers
}
=
this
.
props
;
return
(
<
div
className
=
{
classes
.
root
}
>
<
ExpandFiltersComponent
title
=
"Configure map"
/>
<
span
className
=
{
classes
.
layersTitle
}
>
Layers
</
span
>
<
Divider
/>
{
mapLayers
.
map
((
layer
)
=>
<
MapLayerConfig
layer
=
{
layer
}
/>)
}
</
div
>
);
}
}
const
mapStateToProps
=
(
state
,
ownProps
)
=>
({
mapLayers
:
state
.
accessions
.
public
.
mapLayers
,
});
export
default
connect
(
mapStateToProps
,
null
)(
withStyles
(
styles
)(
MapConfigSection
));
\ No newline at end of file
src/accessions/ui/c/MapLayerConfig.tsx
0 → 100644
View file @
3d02490e
import
*
as
React
from
'
react
'
;
import
{
bindActionCreators
}
from
'
redux
'
;
import
{
connect
}
from
'
react-redux
'
;
import
{
translate
}
from
'
react-i18next
'
;
import
withStyles
from
'
@material-ui/core/styles/withStyles
'
;
// actions
import
{
updateTileLayerInfo
}
from
'
accessions/actions/public
'
;
// model
import
MapLayer
from
'
model/genesys/MapTileLayer
'
;
// ui
import
CollapsibleComponentSearch
from
'
ui/common/filter/CollapsibleComponentSearch
'
;
import
{
Slider
}
from
'
@material-ui/lab
'
;
import
FormControlLabel
from
'
@material-ui/core/FormControlLabel
'
;
import
Checkbox
from
'
@material-ui/core/Checkbox
'
;
import
{
Divider
}
from
'
@material-ui/core
'
;
/*tslint:disable*/
const
styles
=
(
theme
)
=>
({
root
:
{
color
:
'
initial
'
as
'
initial
'
,
whiteSpace
:
'
initial
'
as
'
initial
'
,
'
& > div > div > span
'
:
{
color
:
'
initial
'
as
'
initial
'
,
fontWeight
:
500
,
}
},
rootOpened
:
{
backgroundColor
:
'
#e9e9e9
'
,
},
content
:
{
backgroundColor
:
'
#f3f2ee
'
,
margin
:
'
0 -20px -20px -20px
'
,
padding
:
'
0 20px 20px 20px
'
,
},
opacitySlider
:
{
padding
:
'
8px
'
,
display
:
'
flex
'
as
'
flex
'
,
alignItems
:
'
center
'
as
'
center
'
},
opacitySliderLabel
:
{
flexShrink
:
0
,
fontSize
:
'
12px
'
,
position
:
'
relative
'
as
'
relative
'
,
left
:
'
-8px
'
,
},
description
:
{
margin
:
'
0 -20px
'
,
padding
:
'
8px 20px
'
,
whiteSpace
:
'
initial
'
as
'
initial
'
,
},
statusCheckbox
:
{
width
:
'
100%
'
,
display
:
'
flex
'
as
'
flex
'
,
justifyContent
:
'
space-between
'
as
'
space-between
'
,
flexDirection
:
'
row-reverse
'
as
'
row-reverse
'
,
marginLeft
:
'
0px
'
,
},
copyright
:
{
color
:
'
grey
'
,
fontSize
:
'
12px
'
,
}
});
/*tslint:enable*/
interface
IMapLayerConfigProps
extends
React
.
ClassAttributes
<
any
>
{
title
:
string
;
classes
:
any
;
t
:
any
;
layer
:
MapLayer
;
updateTileLayerInfo
:
(
layerInfo
:
MapLayer
)
=>
void
;
}
class
MapLayerConfig
extends
React
.
Component
<
IMapLayerConfigProps
>
{
public
state
=
{
show
:
false
,
};
public
componentWillMount
()
{
const
{
layer
}
=
this
.
props
;
if
(
layer
&&
layer
.
enabled
)
{
this
.
setState
({
show
:
true
});
}
}
public
render
()
{
const
{
classes
,
layer
,
t
}
=
this
.
props
;
const
{
show
}
=
this
.
state
;
return
(
<
div
className
=
{
`
${
classes
.
root
}
${
show
&&
classes
.
rootOpened
}
`
}
>
<
CollapsibleComponentSearch
title
=
{
layer
.
title
}
collapsed
=
{
!
show
}
onToggleCollapsed
=
{
(
show
)
=>
this
.
setState
({
show
})
}
>
<
Divider
style
=
{
{
margin
:
'
0 -20px
'
}
}
/>
<
div
className
=
{
classes
.
content
}
>
<
div
className
=
{
classes
.
description
}
>
<
div
>
{
t
(
layer
.
description
)
}
</
div
>
</
div
>
<
div
className
=
{
classes
.
opacitySlider
}
>
<
div
className
=
{
classes
.
opacitySliderLabel
}
>
{
`Opacity:
${
Number
(
layer
.
opacity
).
toFixed
(
2
)
}
`
}
</
div
>
<
Slider
min
=
{
0
}
step
=
{
0.05
}
max
=
{
1.0
}
onChange
=
{
this
.
handleSliderChange
}
value
=
{
layer
.
opacity
}
color
=
"#88ba42"
/>
</
div
>
<
FormControlLabel
className
=
{
classes
.
statusCheckbox
}
label
=
"Enabled"
control
=
{
<
Checkbox
checked
=
{
layer
.
enabled
}
onChange
=
{
this
.
handleCheckBoxChange
}
/>
}
/>
</
div
>
<
span
className
=
{
`float-right
${
classes
.
copyright
}
`
}
>
{
layer
.
attribution
}
</
span
>
</
CollapsibleComponentSearch
>
</
div
>
);
}
private
handleSliderChange
=
(
e
,
value
)
=>
{
const
{
updateTileLayerInfo
,
layer
}
=
this
.
props
;
updateTileLayerInfo
({...
layer
,
opacity
:
value
});
}
private
handleCheckBoxChange
=
(
e
,
value
)
=>
{
const
{
updateTileLayerInfo
,
layer
}
=
this
.
props
;
updateTileLayerInfo
({...
layer
,
enabled
:
value
});
}
}
const
mapDispatchToProps
=
(
dispatch
)
=>
bindActionCreators
({
updateTileLayerInfo
,
},
dispatch
);
export
default
translate
()(
connect
(
null
,
mapDispatchToProps
)(
withStyles
(
styles
)(
MapLayerConfig
)));
src/model/genesys/MapTileLayer.ts
0 → 100644
View file @
3d02490e
class
MapLayer
{
public
name
:
string
;
public
title
:
string
;
public
description
:
string
;
public
url
:
string
;
public
enabled
:
boolean
;
public
opacity
:
number
;
public
attribution
:
string
;
public
maxZoom
:
number
;
public
subdomains
:
string
[];
public
constructor
()
{
this
.
enabled
=
false
;
this
.
opacity
=
0.5
;
this
.
attribution
=
'
© worldclim.org
'
;
this
.
maxZoom
=
7
;
this
.
subdomains
=
[
'
a
'
,
'
b
'
,
'
c
'
,
'
d
'
];
}
}
const
layerNames
=
[
'
bio1
'
,
'
bio5
'
,
'
bio6
'
,
'
bio12
'
,
'
bio13
'
,
'
bio14
'
];
export
const
AVAILABLE_LAYERS
=
layerNames
.
map
((
layerName
)
=>
({
...
new
MapLayer
(),
name
:
layerName
,
title
:
`accessions.climate.
${
layerName
}
`
,
description
:
`accessions.climateDescription.
${
layerName
}
`
,
url
:
`https://{s}.tile.genesys-pgr.org/worldclim1.4/
${
layerName
}
/{z}/{x}/{y}.png`
,
}));
export
default
MapLayer
;
src/ui/common/filter/CollapsibleComponentSearch.tsx
View file @
3d02490e
...
...
@@ -8,6 +8,7 @@ import Divider from '@material-ui/core/Divider';
interface
ICollapsibleComponentSearch
extends
React
.
ClassAttributes
<
any
>
{
classes
:
any
;
title
:
string
;
onToggleCollapsed
?:
(
show
:
boolean
)
=>
void
;
collapsed
?:
boolean
;
t
:
any
;
}
...
...
@@ -36,7 +37,11 @@ class CollapsibleComponentSearch extends React.Component<ICollapsibleComponentSe
}
private
toggleCollapsed
=
()
=>
{
const
{
onToggleCollapsed
}
=
this
.
props
;
const
show
=
!
this
.
state
.
show
;
if
(
onToggleCollapsed
)
{
onToggleCollapsed
(
show
);
}
this
.
setState
({
show
});
}
...
...
src/ui/layout/ContentLayout.tsx
View file @
3d02490e
...
...
@@ -22,11 +22,12 @@ interface IContentLayoutProps extends React.Props<any> {
children
?:
any
;
left
?:
any
;
right
?:
any
;
rightAlwaysCollapsible
?:
boolean
;
className
?:
string
;
customHeaderHeight
?:
boolean
;
}
const
ContentLayout
=
({
classes
,
children
=
null
,
left
=
null
,
right
=
null
,
customHeaderHeight
=
false
,
className
=
''
}:
IContentLayoutProps
)
=>
{
const
ContentLayout
=
({
classes
,
children
=
null
,
left
=
null
,
right
=
null
,
rightAlwaysCollapsible
=
false
,
customHeaderHeight
=
false
,
className
=
''
}:
IContentLayoutProps
)
=>
{
return
(
<
div
className
=
{
className
}
>
<
div
className
=
{
classes
.
root
}
>
...
...
@@ -36,7 +37,7 @@ const ContentLayout = ({classes, children = null, left = null, right = null, cus
{
children
}
</
main
>
)
}
{
right
&&
(<
SidebarWrapper
sidebarContent
=
{
right
}
customHeight
=
{
customHeaderHeight
}
right
/>)
}
{
right
&&
(<
SidebarWrapper
sidebarContent
=
{
right
}
customHeight
=
{
customHeaderHeight
}
right
alwaysCollapsible
=
{
rightAlwaysCollapsible
}
/>)
}
</
div
>
</
div
>
);
...
...
src/ui/layout/sidebar/SidebarWrapper.tsx
View file @
3d02490e
...
...
@@ -18,6 +18,7 @@ interface ISidebarProps extends React.ClassAttributes<any> {
width
:
Breakpoint
;
customHeight
?:
boolean
;
right
?:
boolean
;
alwaysCollapsible
?:
boolean
;
}
const
mobile
=
[
'
sm
'
,
'
xs
'
]
as
Breakpoint
[];
...
...
@@ -45,12 +46,17 @@ const styles = (theme) => ({
[
theme
.
breakpoints
.
down
(
'
sm
'
)]:
{
maxWidth
:
'
90%
'
,
position
:
'
fixed
'
as
'
fixed
'
,
zIndex
:
1
5
,
zIndex
:
1
250
,
},
[
theme
.
breakpoints
.
down
(
'
xs
'
)]:
{
maxWidth
:
'
100%
'
,
}
},
drawerAlwaysCollapsible
:
{
maxWidth
:
'
90%
'
,
position
:
'
fixed
'
as
'
fixed
'
,
zIndex
:
1250
,
},
drawerHeightV2
:
{
top
:
'
83px
'
,
height
:
'
calc(100vh - 83px)
'
,
...
...
@@ -112,6 +118,9 @@ const styles = (theme) => ({
minHeight
:
'
calc(100% - 3rem)
'
,
},
},
sidebarContentsAlwaysCollapsible
:
{
minHeight
:
'
calc(100% - 3rem)
'
,
},
sidebarContentsCollapsed
:
{
minHeight
:
'
calc(100% - 52px)
'
,
whiteSpace
:
'
nowrap
'
as
'
nowrap
'
,
...
...
@@ -152,6 +161,12 @@ const styles = (theme) => ({
display
:
'
block
'
as
'
block
'
,
},
},
collapseButtonAlwaysCollapsible
:{
display
:
'
block
'
as
'
block
'
,
'
& > span
'
:
{
fontSize
:
'
1.5rem
'
,
},
},
buttonCollapsed
:
{
top
:
'
100%
'
,
transition
:
theme
.
transitions
.
create
(
'
width
'
,
{
...
...
@@ -192,13 +207,14 @@ class SidebarWrapper extends React.Component<ISidebarProps, any> {
}
public
render
()
{
const
{
sidebarContent
,
classes
,
isOpen
,
width
,
customHeight
,
right
=
false
}
=
this
.
props
;
const
isMobile
=
mobile
.
indexOf
(
width
)
!==
-
1
;
<