Monorepo containing core modules of Zeichen.
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.

182 lines
3.6 KiB

  1. import * as React from 'react'
  2. import * as PropTypes from 'prop-types'
  3. import Link from 'next/link'
  4. import styled from 'styled-components'
  5. import Icon from '../Icon/Icon'
  6. const NoteLink = styled('a')({
  7. display: 'flex',
  8. textDecoration: 'none',
  9. color: 'inherit',
  10. height: '4rem',
  11. alignItems: 'center',
  12. position: 'relative',
  13. })
  14. const NoteLinkPrimary = styled('div')({
  15. display: 'block',
  16. })
  17. const NoteLinkTitle = styled('strong')({
  18. verticalAlign: 'middle',
  19. })
  20. const LinkContainer = styled('div')({
  21. position: 'relative',
  22. color: 'var(--color-primary, blue)',
  23. })
  24. const NoteActions = styled('div')({
  25. display: 'flex',
  26. position: 'absolute',
  27. alignItems: 'stretch',
  28. top: 0,
  29. right: 0,
  30. height: '100%',
  31. })
  32. const NoteAction = styled('button')({
  33. height: '100%',
  34. width: '4rem',
  35. background: 'transparent',
  36. border: 0,
  37. color: 'inherit',
  38. cursor: 'pointer',
  39. outline: 0,
  40. })
  41. const NoteLinkBackground = styled('span')({
  42. '::before': {
  43. content: "''",
  44. position: 'absolute',
  45. top: 0,
  46. left: 0,
  47. width: '0.25rem',
  48. height: '100%',
  49. display: 'block',
  50. backgroundColor: 'currentColor',
  51. },
  52. '::after': {
  53. content: "''",
  54. opacity: 0.125,
  55. backgroundColor: 'currentColor',
  56. top: 0,
  57. left: 0,
  58. width: '100%',
  59. height: '100%',
  60. position: 'absolute',
  61. },
  62. })
  63. const IconContainer = styled('span')({
  64. display: 'inline-block',
  65. verticalAlign: 'middle',
  66. marginRight: '0.5rem',
  67. })
  68. const NavbarItemContent = styled('span')({
  69. padding: '0 1rem',
  70. boxSizing: 'border-box',
  71. })
  72. const PostMeta = styled('small')({
  73. opacity: 0.5,
  74. height: '1.25rem',
  75. display: 'block',
  76. lineHeight: 1.25,
  77. })
  78. const propTypes = {
  79. active: PropTypes.bool,
  80. href: PropTypes.oneOfType([PropTypes.object, PropTypes.string]).isRequired,
  81. replace: PropTypes.bool,
  82. iconName: PropTypes.string,
  83. title: PropTypes.string,
  84. subtitle: PropTypes.node,
  85. actions: PropTypes.arrayOf(PropTypes.shape({
  86. id: PropTypes.string.isRequired,
  87. onClick: PropTypes.func,
  88. iconName: PropTypes.string,
  89. })),
  90. }
  91. type Props = PropTypes.InferProps<typeof propTypes>
  92. const SecondaryNavItem: React.FC<Props> = ({
  93. active = false,
  94. href,
  95. replace = false,
  96. iconName,
  97. title,
  98. subtitle,
  99. actions,
  100. }) => (
  101. <LinkContainer>
  102. {
  103. active
  104. && (
  105. <NoteLinkBackground />
  106. )
  107. }
  108. <Link
  109. href={href}
  110. replace={replace}
  111. passHref
  112. >
  113. <NoteLink>
  114. <NavbarItemContent>
  115. <NoteLinkPrimary>
  116. <IconContainer>
  117. {
  118. iconName
  119. && (
  120. <Icon
  121. name={iconName}
  122. />
  123. )
  124. }
  125. </IconContainer>
  126. <NoteLinkTitle
  127. style={{ opacity: title.length > 0 ? 1 : 0.5, }}
  128. >
  129. {title.length > 0 ? title : '(untitled)'}
  130. </NoteLinkTitle>
  131. </NoteLinkPrimary>
  132. {
  133. subtitle
  134. && (
  135. <React.Fragment>
  136. {' '}
  137. <PostMeta>
  138. {subtitle}
  139. </PostMeta>
  140. </React.Fragment>
  141. )
  142. }
  143. </NavbarItemContent>
  144. </NoteLink>
  145. </Link>
  146. {
  147. Array.isArray(actions)
  148. && (
  149. <NoteActions>
  150. {actions.map(a => (
  151. <NoteAction
  152. key={a.id}
  153. onClick={a.onClick}
  154. >
  155. <Icon
  156. name={a.iconName}
  157. />
  158. </NoteAction>
  159. ))}
  160. </NoteActions>
  161. )
  162. }
  163. </LinkContainer>
  164. )
  165. SecondaryNavItem.propTypes = propTypes
  166. export default SecondaryNavItem