client/src/navigation/button.tsx (72 lines of code) (raw):

import React from "react"; import { css } from "@emotion/react"; import { pinboard } from "../../colours"; import { neutral, palette, space } from "@guardian/source-foundations"; import { agateSans } from "../../fontNormaliser"; const numberedBubble = css` top: -4px; min-width: ${space[2]}px; padding: 0 ${space[1]}px; height: ${space[4]}px; border-radius: ${space[3]}px; `; const unnumberedBubble = css` top: 0px; height: ${space[2]}px; width: ${space[2]}px; border-radius: ${space[4]}px; `; interface NavButtonProps { onClick?: () => void; icon: React.FC; hoverParent?: boolean; unreadCount?: number | null; title?: string; } export const NavButton = ({ onClick, icon: Icon, hoverParent, unreadCount, title, }: NavButtonProps) => ( <span title={title} onClick={onClick} css={css` position: relative; height: 24px; width: 24px; border-radius: 24px; ${hoverParent ? "*:hover > &" : "&:hover"} { background-color: ${pinboard[800]}; cursor: pointer; } display: flex; justify-content: center; align-items: center; fill: ${neutral[20]}; `} > {unreadCount !== null && unreadCount !== undefined && ( // TODO merge this CSS with the notification bubble in floaty <div css={css` ${unreadCount > 0 ? numberedBubble : unnumberedBubble}; position: absolute; left: ${space[3]}px; border: 2px solid ${pinboard[500]}; user-select: none; background-color: ${palette.neutral[20]}; ${agateSans.xxsmall({ lineHeight: "regular" })} color: ${palette.neutral[100]}; text-align: center; ${hoverParent ? "*:hover > * > &" : "*:hover > &"} { border-color: ${pinboard[800]}; } `} > {unreadCount > 0 && unreadCount} </div> )} <Icon /> </span> );