Layout scaffolding for Web apps.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 

159 lignes
2.9 KiB

  1. import * as React from 'react'
  2. import styled from 'styled-components'
  3. import {minWidthFactor} from '../../utilities/mixins';
  4. import {configVar} from '../../utilities/helpers'
  5. const Base = styled('div')({
  6. position: 'fixed',
  7. top: 0,
  8. left: 0,
  9. width: '100%',
  10. height: 'var(--height-topbar, 4rem)',
  11. zIndex: 2,
  12. '> *': {
  13. display: 'block',
  14. width: '100%',
  15. height: '100%',
  16. backgroundColor: 'white',
  17. },
  18. '~ *': {
  19. paddingTop: 'var(--height-topbar, 4rem)',
  20. },
  21. '~ main ~ *': {
  22. paddingTop: 0,
  23. },
  24. [minWidthFactor(3)]: {
  25. '~ main ~ *': {
  26. paddingTop: 'var(--height-topbar, 4rem)',
  27. },
  28. },
  29. })
  30. const Container = styled('div')({
  31. padding: '0 1rem',
  32. boxSizing: 'border-box',
  33. margin: '0 auto',
  34. maxWidth: `calc(${configVar('base-width')} * 3)`,
  35. width: '100%',
  36. height: '100%',
  37. display: 'flex',
  38. alignItems: 'center',
  39. position: 'relative',
  40. zIndex: 1,
  41. })
  42. const NarrowContainer = styled(Container)({
  43. maxWidth: configVar('base-width'),
  44. })
  45. const WideContainer = styled(Container)({
  46. [minWidthFactor(3)]: {
  47. maxWidth: `calc(${configVar('base-width')} * 3)`,
  48. },
  49. })
  50. const BrandContainer = styled('div')({
  51. })
  52. const CenterContainer = styled('div')({
  53. flex: 'auto',
  54. padding: '0 1rem',
  55. boxSizing: 'border-box',
  56. ':first-child': {
  57. paddingLeft: 0,
  58. },
  59. })
  60. const ActionContainer = styled('div')({
  61. display: 'flex',
  62. alignItems: 'center',
  63. justifyContent: 'flex-end',
  64. height: '100%',
  65. whiteSpace: 'nowrap',
  66. [minWidthFactor(2)]: {
  67. minWidth: '8rem',
  68. },
  69. })
  70. const LinkContainer = styled('div')({
  71. width: 'var(--height-topbar, 4rem)',
  72. height: '100%',
  73. '> *': {
  74. width: '100%',
  75. height: '100%',
  76. display: 'inline-grid',
  77. placeContent: 'center',
  78. },
  79. })
  80. const MenuLinkContainer = styled(LinkContainer)({
  81. [minWidthFactor(3)]: {
  82. position: 'absolute',
  83. left: -999999,
  84. },
  85. })
  86. const CONTAINER_COMPONENTS = {
  87. narrow: NarrowContainer,
  88. normal: Container,
  89. wide: WideContainer,
  90. }
  91. type Props = {
  92. span?: keyof typeof CONTAINER_COMPONENTS,
  93. brand?: React.ReactNode,
  94. menuLink?: React.ReactNode,
  95. userLink?: React.ReactNode,
  96. baseComponent?: React.ElementType,
  97. }
  98. const TopBar: React.FC<Props> = ({
  99. span = 'normal',
  100. brand,
  101. menuLink,
  102. userLink,
  103. children,
  104. baseComponent: BaseComponent = 'div',
  105. }) => {
  106. const { [span as keyof typeof CONTAINER_COMPONENTS]: ContainerComponent = Container } = CONTAINER_COMPONENTS
  107. return (
  108. <Base>
  109. <BaseComponent>
  110. <ContainerComponent>
  111. {
  112. Boolean(brand as unknown)
  113. && (
  114. <BrandContainer>
  115. {brand}
  116. </BrandContainer>
  117. )
  118. }
  119. <CenterContainer>
  120. {children}
  121. </CenterContainer>
  122. <ActionContainer>
  123. {
  124. Boolean(menuLink as unknown)
  125. && (
  126. <MenuLinkContainer>
  127. {menuLink}
  128. </MenuLinkContainer>
  129. )
  130. }
  131. {
  132. Boolean(userLink as unknown)
  133. && (
  134. <LinkContainer>
  135. {userLink}
  136. </LinkContainer>
  137. )
  138. }
  139. </ActionContainer>
  140. </ContainerComponent>
  141. </BaseComponent>
  142. </Base>
  143. )
  144. }
  145. export default TopBar