44
55
66import React , { useEffect } from 'react' ;
7- import PropTypes , { element , node , object , shape , string } from 'prop-types' ;
7+ import PropTypes , { node , object , shape , string } from 'prop-types' ;
88import { Divider , Typography } from '@mui/joy' ;
9- import { cloneDeep } from 'lodash/lang.js ' ;
9+ import { cloneDeep , defaultsDeep } from 'lodash' ;
1010
1111import {
1212 dispatchSetMenu ,
@@ -153,69 +153,94 @@ function closeExpanded() {
153153 dispatchSetLayoutMode ( LO_MODE . expanded , LO_VIEW . none ) ;
154154}
155155
156- export function HydraLanding ( { icon, title, desc, bgImage, slotProps= { } , ...props } ) {
157-
158- const Greetings = ( ) => (
159- < Stacker startDecorator = { icon } direction = 'column' alignItems = 'start' >
160- < Typography level = 'h4' > { title || 'Welcome message here' } </ Typography >
161- < Typography level = 'body-md' > { desc || 'Additional description of this application' } </ Typography >
162- </ Stacker >
163- ) ;
164-
165- const mSlotProps = cloneDeep ( slotProps || { } ) ;
166- setIfUndefined ( mSlotProps , 'bgMonitorHint.sx.right' , 50 ) ;
167-
168- if ( bgImage ) {
169- setIfUndefined ( mSlotProps , 'bgContainer' , {
170- // TODO: move it to Landing page?
171- sx : { backgroundImage : `url(${ bgImage } )` , backgroundSize : 'cover' , backgroundPosition : 'center' , } ,
172- } ) ;
173- setIfUndefined ( mSlotProps , 'contentSection.sx' , ( theme ) => {
156+ const HydraAppBranding = ( { title, desc} ) => (
157+ < Stacker direction = 'column' alignItems = 'start' >
158+ < Typography level = 'h4' > { title || 'Welcome message here' } </ Typography >
159+ < Typography level = 'body-md' > { desc || 'Additional description of this application' } </ Typography >
160+ </ Stacker >
161+ ) ;
162+
163+ const defaultCommonProps = ( { title, desc} ) => ( {
164+ bgMonitorHint : { sx : { right : 50 } } ,
165+ topSection : { title, desc }
166+ } ) ;
167+
168+
169+ const defaultPropsWithoutBgImage = ( { icon} ) => ( {
170+ contentSection : { sx : { maxWidth : '80rem' , mx : 'auto' } } ,
171+ topSection : { component : HydraAppBranding } , // use custom topSection instead of DefaultAppBranding
172+ bottomSection : { icon }
173+ } ) ;
174+
175+ const defaultPropsWithBgImage = ( { bgImage} ) => ( {
176+ // visually combine topSection & bottomSection into contentSection that can contrast with the bgContainer
177+ bgContainer : {
178+ sx : {
179+ display : 'flex' , flexGrow : 1 ,
180+ backgroundImage : `url(${ bgImage } )` , backgroundSize : 'cover' , backgroundPosition : 'center'
181+ }
182+ } ,
183+ contentSection : {
184+ sx : ( theme ) => {
174185 // background image will remain same in both the theme modes, and we need text to contrast with the image,
175- // so we create a dark overlay and put text over it as if it's dark theme
186+ // so we create a translucent dark overlay and put text over it as if it's dark theme
176187 const darkPalette = theme . colorSchemes . dark . palette ;
177188 return {
178189 maxWidth : '56rem' , m : 'auto' ,
179- backgroundColor : hexColorWithAlpha ( darkPalette . background . surface . split ( ', ' ) ?. [ 1 ] ?. slice ( 0 , - 1 ) ?? '#000' , 0.6 ) ,
180- backdropFilter : 'blur(1px)' , // for glass-effect
181- '.MuiTypography-body-md, .MuiTypography-body-lg' : { color : darkPalette . text . secondary } ,
182- '.MuiTypography-h2' : { color : darkPalette . text . primary } ,
183- '.MuiTypography-colorPrimary' : { color : `rgb(${ darkPalette . primary . mainChannel } )` } ,
184- '.MuiDivider-root' : { backgroundColor : darkPalette . neutral . solidBg } ,
190+ backgroundColor : hexColorWithAlpha ( darkPalette . background . surface . split ( ', ' ) ?. [ 1 ] ?. slice ( 0 , - 1 ) ?? '#000' , 0.6 ) ,
191+ backdropFilter : 'blur(1px)' ,
192+ '.MuiTypography-body-md, .MuiTypography-body-lg' : { color : darkPalette . text . secondary } ,
193+ '.MuiTypography-h2' : { color : darkPalette . text . primary } ,
194+ '.MuiTypography-colorPrimary' : { color : `rgb(${ darkPalette . primary . mainChannel } )` } ,
195+ '.MuiDivider-root' : { backgroundColor : darkPalette . neutral . solidBg }
185196 } ;
186- } ) ;
187- setIfUndefined ( mSlotProps , 'contentSection.divider' , ( < Divider sx = { { width : '4rem' , alignSelf : 'center' } } /> ) ) ;
188- // TODO: need to adjust top section vs greetings logic
189- setIfUndefined ( mSlotProps , 'topSection.appTitle' , title ) ;
190- setIfUndefined ( mSlotProps , 'topSection.appDescription' , desc ) ;
191- setIfUndefined ( mSlotProps , 'bottomSection' , { icon : false , slotProps : {
192- root : { sx : { py : 4 , pb : 0 , backgroundColor : 'transparent' } }
193- } } ) ;
194- }
195- else {
196- setIfUndefined ( mSlotProps , 'topSection.component' , Greetings ) ; // use custom topSection
197- setIfUndefined ( mSlotProps , 'contentSection.sx' , { maxWidth : '80em' , mx : 'auto' } ) ; // limit page's width
197+ } ,
198+ divider : < Divider sx = { { width : '4rem' , alignSelf : 'center' } } />
199+ } ,
200+ bottomSection : {
201+ icon : false , // to prevent default being applied (on undefined)
202+ slotProps : {
203+ root : { sx : { py : 4 , pb : 0 , backgroundColor : 'transparent' } }
204+ }
198205 }
206+ } ) ;
207+
208+
209+ export function HydraLanding ( { icon, title, desc, bgImage, slotProps= { } , ...props } ) {
210+ const mSlotProps = cloneDeep ( slotProps ) ;
211+ defaultsDeep ( mSlotProps , defaultCommonProps ( { title, desc} ) ) ;
212+
213+ bgImage
214+ ? defaultsDeep ( mSlotProps , defaultPropsWithBgImage ( { bgImage} ) )
215+ : defaultsDeep ( mSlotProps , defaultPropsWithoutBgImage ( { icon} ) ) ;
199216
200217 return < LandingPage slotProps = { mSlotProps } { ...props } /> ;
201218}
202219
203220HydraLanding . propTypes = {
204- icon : element ,
221+ icon : node ,
205222 title : string ,
206223 desc : node ,
224+ bgImage : string ,
207225 ...LandingPage . propTypes ,
208226} ;
209227
210228
211229export function applyLayoutFix ( { slotProps, props} ) {
212230 const mSlotProps = cloneDeep ( slotProps || { } ) ;
231+ defaultsDeep ( mSlotProps , {
232+ banner : {
233+ slotProps : {
234+ // Adjust banner for appIcon
235+ icon : {
236+ style : { marginTop : - 40 } , // Won't take precedence if defined in sx
237+ sx : { color : 'primary.softActiveColor' } // Same as active tab's font color
238+ } ,
239+ tabs : { pl : '120px' }
240+ }
241+ } ,
242+ landing : { title : props ?. appTitle }
243+ } ) ;
213244
214- // adjust banner for appIcon
215- setIfUndefined ( mSlotProps , 'banner.slotProps.icon.style.marginTop' , - 40 ) ; //won't take precedence if defined in sx
216- setIfUndefined ( mSlotProps , 'banner.slotProps.icon.sx' , { color : 'primary.softActiveColor' } ) ; //same as active tab's font color
217- setIfUndefined ( mSlotProps , 'banner.slotProps.tabs.pl' , '120px' ) ;
218-
219- setIfUndefined ( mSlotProps , 'landing.title' , props ?. appTitle ) ;
220245 return mSlotProps ;
221246}
0 commit comments