Skip to content

Commit

Permalink
Add Tooltip and associated UI to switch between languages. Needs to b…
Browse files Browse the repository at this point in the history
…e hooked up @tmeasday
  • Loading branch information
domyen committed Jun 13, 2018
1 parent 93ae1a4 commit 7f1f9dd
Show file tree
Hide file tree
Showing 9 changed files with 627 additions and 26 deletions.
140 changes: 140 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
"polished": "^1.9.2",
"prismjs": "^1.13.0",
"prop-types": "^15.6.1",
"react": "^15.6.0",
"react": "^16.2.0",
"react-dom": "^16.4.1",
"react-github-button": "^0.1.11",
"react-helmet": "^5.2.0",
"react-popper": "^0.7.2",
"styled-components": "^3.2.5"
},
"keywords": [
Expand Down
111 changes: 86 additions & 25 deletions src/components/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import 'react-github-button/assets/style.css';
import Logo from './Logo';
import Link from './Link';
import Icon from './Icon';
import { typography, spacing, pageMargins, breakpoint } from './shared/styles';
import WithTooltip from './WithTooltip';
import { color, typography, spacing, pageMargins, breakpoint } from './shared/styles';

const LogoWrapper = styled(Logo)`
height: 20px;
Expand Down Expand Up @@ -75,12 +76,11 @@ const NavGroup = styled.div`
}
`;

// prettier-ignore
const Nav = styled.div`
height: 3rem;
position: relative;
text-align: center;
z-index: 3;
z-index: 3;
`;

const NavWrapper = styled.nav`
Expand All @@ -91,6 +91,47 @@ const NavWrapper = styled.nav`
}
`;

const TooltipList = styled.div`
width: 200px;
`;

const TooltipItem = styled.div`
display: flex;
flex-direction: row;
align-items: flex-start;
padding: 15px 15px;
&:not(:first-child) {
border-top: 1px solid ${color.mediumlight};
}
`;

const ViewLayerImage = styled.img`
width: 1rem;
height: 1rem;
margin-right: 8px;
`;

const Meta = styled.div``;

const Title = styled.div`
font-weight: ${typography.weight.extrabold};
font-size: ${typography.size.s2}px;
line-height: 1;
margin-bottom: 6px;
`;

const Detail = styled.div`
font-size: ${typography.size.s1}px;
line-height: 1;
`;

const LanguageLink = styled(Link)`
text-decoration: underline;
margin-right: 10px;
`;

const GitHubWrapper = styled.div`
${'' /* Overrides to make a medium sized button */};
.github-btn {
Expand All @@ -116,29 +157,49 @@ export default function Header({ githubUrl, inverse, ...props }) {
</NavItem>
</NavGroup>
<NavGroup right>
{/* TODO:
- Hide these links on the homepage
- Add Tooltip component to switch between view layers/languages
- React
- React
- Vue
- Add yours? (/contribute)
- English
- English
- Spanish
- Help translate (/contribute)
*/}
<NavItem showDesktop>
<NavLink className={inverse ? 'inverse' : 'tertiary'}>
<Icon icon="switchalt" />
React
</NavLink>
</NavItem>
<NavItem showDesktop>
<NavLink className={inverse ? 'inverse' : 'tertiary'}>
<Icon icon="comment" />
English
</NavLink>
<WithTooltip
placement="top"
mode="click"
startOpen
tooltip={
<TooltipList>
<TooltipItem>
<ViewLayerImage src="/logo-react.svg" alt="React" />
<Meta>
<Title>React</Title>
<Detail>
<LanguageLink className="tertiary">English</LanguageLink>
<LanguageLink className="tertiary">Español</LanguageLink>
</Detail>
</Meta>
</TooltipItem>
<TooltipItem>
<ViewLayerImage src="/logo-vue.svg" alt="Vue" />
<Meta>
<Title>Vue</Title>
<Detail>
<LanguageLink className="tertiary">English</LanguageLink>
</Detail>
</Meta>
</TooltipItem>
<TooltipItem>
<ViewLayerImage src="/logo-angular.svg" alt="Angular" />
<Meta>
<Title>Angular</Title>
<Detail>
<LanguageLink className="tertiary">Contributors wanted</LanguageLink>
</Detail>
</Meta>
</TooltipItem>
</TooltipList>
}
>
<NavLink className={inverse ? 'inverse' : 'tertiary'}>
<Icon icon="switchalt" />
React
</NavLink>
</WithTooltip>
</NavItem>
<NavItem>
<GitHubWrapper>
Expand Down
97 changes: 97 additions & 0 deletions src/components/Popper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Our wrapper around react-popper that does common stuff.

import React from 'react';
import PropTypes from 'prop-types';
import { Manager, Target, Popper, Arrow } from 'react-popper';
import styled, { css } from 'styled-components';
import { typography } from './shared/styles';

// We need to ensure these are inline block so they get the sizing from their
// children. An alternate approach if this is annoying is to make the children
// themselves the target/popper but this means we'd need a ref to them, which
// makes this a bit clunkier to use.
const StyledTarget = styled(Target)`
display: inline-block;
cursor: ${props => (props.mode === 'hover' ? 'default' : 'pointer')};
`;

const ifPlacementEquals = (placement, value, fallback = 0) => props =>
props['data-placement'].split('-')[0] === placement ? value : fallback;

const ArrowSpacing = 8;

const StyledArrow = styled.div`
position: absolute;
border-style: solid;
margin-bottom: ${ifPlacementEquals('top', '0', ArrowSpacing)}px;
margin-top: ${ifPlacementEquals('bottom', '0', ArrowSpacing)}px;
margin-right: ${ifPlacementEquals('left', '0', ArrowSpacing)}px;
margin-left: ${ifPlacementEquals('right', '0', ArrowSpacing)}px;
bottom: ${ifPlacementEquals('top', ArrowSpacing * -1, 'auto')}px;
top: ${ifPlacementEquals('bottom', ArrowSpacing * -1, 'auto')}px;
right: ${ifPlacementEquals('left', ArrowSpacing * -1, 'auto')}px;
left: ${ifPlacementEquals('right', ArrowSpacing * -1, 'auto')}px;
border-bottom-width: ${ifPlacementEquals('top', '0', ArrowSpacing)}px;
border-top-width: ${ifPlacementEquals('bottom', '0', ArrowSpacing)}px;
border-right-width: ${ifPlacementEquals('left', '0', ArrowSpacing)}px;
border-left-width: ${ifPlacementEquals('right', '0', ArrowSpacing)}px;
border-top-color: ${ifPlacementEquals('top', 'white', 'transparent')};
border-bottom-color: ${ifPlacementEquals('bottom', 'white', 'transparent')};
border-left-color: ${ifPlacementEquals('left', 'white', 'transparent')};
border-right-color: ${ifPlacementEquals('right', 'white', 'transparent')};
`;

const WrapperArrow = props => <Arrow {...props} component={StyledArrow} />;

// prettier-ignore
const StyledPopper = styled.div`
display: ${props => (props.hidden ? 'none' : 'inline-block')};
z-index: 2147483647;
${props => !props.hasChrome && css`
margin-bottom: ${ifPlacementEquals('top', 8)}px;
margin-bottom: ${ifPlacementEquals('top-start', 8)}px;
margin-top: ${ifPlacementEquals('bottom', 8)}px;
margin-top: ${ifPlacementEquals('bottom-start', 8)}px;
margin-left: ${ifPlacementEquals('right', 8)}px;
margin-right: ${ifPlacementEquals('left', 8)}px;
`}
${props => props.hasChrome && css`
margin-bottom: ${ifPlacementEquals('top', ArrowSpacing + 2)}px;
margin-top: ${ifPlacementEquals('bottom', ArrowSpacing + 2)}px;
margin-left: ${ifPlacementEquals('right', ArrowSpacing + 2)}px;
margin-right: ${ifPlacementEquals('left', ArrowSpacing + 2)}px;
background-image: linear-gradient(-1deg, rgba(248,248,248,0.97) 0%, rgba(255,255,255,0.97) 100%);
box-shadow: 0 2px 5px 0 rgba(0,0,0,0.05), 0 5px 15px 0 rgba(0,0,0,0.10);
border-radius: 4px;
font-size: ${typography.size.s1}px;
`}
`;

const RawPopperWithArrow = ({ children, hasChrome, ...props }) => (
<StyledPopper hasChrome={hasChrome} {...props}>
{children}
{hasChrome && <WrapperArrow data-placement={props['data-placement']} />}
</StyledPopper>
);

RawPopperWithArrow.propTypes = {
children: PropTypes.node.isRequired,
hasChrome: PropTypes.bool,
'data-placement': PropTypes.string,
};

RawPopperWithArrow.defaultProps = {
hasChrome: false,
'data-placement': 'top',
};

const PopperWithArrow = props => <Popper {...props} component={RawPopperWithArrow} />;

export { Manager, StyledTarget as Target, PopperWithArrow };
Loading

0 comments on commit 7f1f9dd

Please sign in to comment.