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.
 
 
 

139 lines
2.5 KiB

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