Layout scaffolding for Web apps.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

143 lines
2.8 KiB

  1. import * as React from 'react'
  2. import styled, {createGlobalStyle} from 'styled-components'
  3. import TopBar from '../../widgets/TopBar'
  4. import {minWidthFactor} from '../../utilities/mixins';
  5. import {configVar, loadConfig} from '../../utilities/helpers'
  6. const Config = createGlobalStyle({
  7. ...loadConfig(),
  8. })
  9. const DisableScrolling = createGlobalStyle({
  10. 'body': {
  11. overflow: 'hidden',
  12. [minWidthFactor(3)]: {
  13. overflow: 'auto',
  14. },
  15. },
  16. })
  17. const ContentBase = styled('main')({
  18. boxSizing: 'border-box',
  19. [minWidthFactor(3)]: {
  20. paddingLeft: `calc(50% - ${configVar('base-width')} * 0.5)`,
  21. },
  22. })
  23. const SidebarOverflow = styled('div')({
  24. width: '100%',
  25. height: '100%',
  26. overflow: 'auto',
  27. // overflow: 'overlay',
  28. position: 'relative',
  29. zIndex: 1,
  30. scrollbarWidth: 'none',
  31. '::-webkit-scrollbar': {
  32. display: 'none',
  33. },
  34. })
  35. const SidebarBase = styled('div')({
  36. boxSizing: 'border-box',
  37. position: 'fixed',
  38. top: 0,
  39. left: '-100%',
  40. width: '100%',
  41. height: '100%',
  42. '> *': {
  43. display: 'block',
  44. width: '100%',
  45. height: '100%',
  46. backgroundColor: 'white',
  47. },
  48. [minWidthFactor(3)]: {
  49. width: `calc(50% - ${configVar('base-width')} * 0.5)`,
  50. left: 0,
  51. },
  52. })
  53. const OpenSidebarBase = styled(SidebarBase)({
  54. left: 0,
  55. })
  56. export const SidebarMainContainer = styled('div')({
  57. width: '100%',
  58. margin: '0 auto',
  59. padding: '0 1rem',
  60. boxSizing: 'border-box',
  61. maxWidth: `calc(${configVar('base-width')} * 2)`,
  62. [minWidthFactor(3)]: {
  63. width: `${configVar('base-width')}`,
  64. marginRight: 0,
  65. },
  66. })
  67. export const ContentContainer = styled('div')({
  68. padding: '0 1rem',
  69. boxSizing: 'border-box',
  70. width: '100%',
  71. maxWidth: `calc(${configVar('base-width')} * 2)`,
  72. marginRight: 'auto',
  73. marginLeft: 'auto',
  74. [minWidthFactor(3)]: {
  75. marginLeft: 0,
  76. },
  77. })
  78. type Props = {
  79. brand?: React.ReactNode,
  80. sidebarMain?: React.ReactChild,
  81. sidebarMainOpen?: boolean,
  82. menuLink?: React.ReactNode,
  83. userLink?: React.ReactNode,
  84. topBarCenter?: React.ReactChild,
  85. topBarComponent?: React.ElementType,
  86. sidebarMainComponent?: React.ElementType,
  87. }
  88. export const Layout: React.FC<Props> = ({
  89. brand,
  90. sidebarMain,
  91. sidebarMainOpen,
  92. menuLink,
  93. userLink,
  94. topBarCenter,
  95. children,
  96. topBarComponent: TopBarComponent = 'div',
  97. sidebarMainComponent: SidebarMainComponent = 'div',
  98. }) => {
  99. const LeftSidebarComponent = sidebarMainOpen ? OpenSidebarBase : SidebarBase
  100. return (
  101. <>
  102. <Config />
  103. {
  104. sidebarMainOpen
  105. && (
  106. <DisableScrolling />
  107. )
  108. }
  109. <TopBar
  110. span="wide"
  111. brand={brand}
  112. menuLink={menuLink}
  113. userLink={userLink}
  114. baseComponent={TopBarComponent}
  115. >
  116. {topBarCenter}
  117. </TopBar>
  118. <LeftSidebarComponent>
  119. <SidebarMainComponent>
  120. <SidebarOverflow>
  121. {sidebarMain}
  122. </SidebarOverflow>
  123. </SidebarMainComponent>
  124. </LeftSidebarComponent>
  125. <ContentBase>
  126. {children}
  127. </ContentBase>
  128. </>
  129. )
  130. }