backpack-ui
Version:
Lonely Planet's Components
326 lines (293 loc) • 7.27 kB
JSX
import React from "react";
import PropTypes from "prop-types";
import radium, { Style } from "radium";
import cn from "classnames";
import Link from "../link";
import Icon from "../icon";
import BulletDescription from "../bulletDescription";
import TextBubble from "../textBubble";
import Heading from "../heading";
import CoverPhoto from "../coverPhoto";
import colors from "../../styles/colors";
import timing from "../../styles/timing";
import {
fontWeightMedium,
fontSizeUppercase,
fontSizeHeading6,
fontSizeHeading7,
lineHeightHeading7,
fontSizeHeading8,
lineHeightHeading8,
} from "../../styles/typography";
import zIndex from "../../styles/zIndex";
import font from "../../utils/font";
import { rgba } from "../../utils/color";
import duration from "../../utils/time";
import iconFromString from "../../utils/icon";
import propTypes from "../../utils/propTypes";
import createQAHook from "../../utils/createQAHook";
const hoverStyles = {
default: {
".CoverPhoto": {
transform: "scale(1.03) !important",
},
},
light: {
".Heading": {
color: `${colors.linkPrimary} !important`,
},
},
};
const styles = {
container: {
default: {
display: "flex",
transition: `background-color ${timing.fast} linear, border-color ${timing.fast} linear`,
},
active: {
backgroundColor: colors.linkPrimary,
},
},
image: {
flexShrink: 0,
width: "116px",
},
imageAnchor: {
backgroundColor: colors.bgOverlay,
display: "block",
overflow: "hidden",
position: "relative",
width: "100%",
},
coverPhoto: {
transition: `transform ${timing.slow} ease-in-out`,
},
iconContainer: {
alignItems: "center",
backgroundColor: rgba(colors.bgOverlay, 0.15),
color: colors.textOverlay,
display: "flex",
fontSize: `${fontSizeHeading6}px`,
height: "100%",
justifyContent: "center",
left: 0,
position: "absolute",
top: 0,
transition: `opacity ${timing.default} ease`,
width: "100%",
},
imageText: {
bottom: "3px",
fontSize: `${fontSizeUppercase}px`,
fontWeight: fontWeightMedium,
position: "absolute",
right: "3px",
zIndex: zIndex.default,
},
content: {
alignItems: "center",
display: "flex",
flexGrow: 1,
justifyContent: "space-between",
},
title: {
default: {
display: "-webkit-box",
fontSize: `${fontSizeHeading7}px`,
lineHeight: lineHeightHeading7,
overflow: "hidden",
textOverflow: "ellipsis",
transition: `color ${timing.default} ease`,
WebkitBoxOrient: "vertical",
},
light: {
color: colors.textPrimary,
},
dark: {
color: colors.textOverlay,
},
active: {
color: colors.textOverlay,
},
},
textContainer: {
marginRight: "16px",
width: "100%",
},
textAnchor: {
display: "block",
paddingLeft: "16px",
width: "100%",
},
status: {
default: {
color: colors.textOverlay,
fontFamily: font("miller"),
fontSize: `${fontSizeHeading8}px`,
fontStyle: "italic",
lineHeight: lineHeightHeading8,
},
light: {
color: colors.textPrimary,
},
dark: {
color: colors.textOverlay,
},
},
descriptionIcon: {
backgroundColor: "transparent",
border: 0,
color: colors.accentGray,
cursor: "pointer",
fontSize: `${fontSizeHeading7}px`,
padding: 0,
transition: `color ${timing.default} ease-in-out`,
":hover": {
color: rgba(colors.accentGray, 0.5),
},
":active": {
color: rgba(colors.accentGray, 0.5),
},
":focus": {
color: rgba(colors.accentGray, 0.5),
},
},
};
const ThumbnailListItem = ({
title,
subtitle,
href,
onClick,
imagePath,
imageIcon,
imageIconLabel,
description,
descriptionIcon,
descriptionIconLabel,
onDescriptionIconClick,
runtime,
status,
lineClamp,
theme,
style,
qaHook,
}) => (
<div
className={cn("ListItem-thumbnail", theme && `ListItem-thumbnail--${theme}`)}
style={[
styles.container.default,
styles.container[theme],
style,
]}
>
<Style
scopeSelector=".ListItem-thumbnail:hover"
rules={hoverStyles.default}
/>
{theme === "light" &&
<Style
scopeSelector=".ListItem-thumbnail--light:hover"
rules={hoverStyles.light}
/>
}
<div style={styles.image}>
<Link
to={href}
onClick={onClick}
style={styles.imageAnchor}
qaHook={qaHook ? createQAHook("cover-image", "external", "link") : null}
>
<CoverPhoto
src={imagePath}
width={116}
height={64}
style={styles.coverPhoto}
/>
<div
style={[
styles.iconContainer,
{ opacity: imageIcon ? 1 : 0 },
]}
>
{imageIcon && iconFromString(imageIcon, { label: imageIconLabel })}
</div>
{typeof runtime === "number" &&
<TextBubble style={styles.imageText}>
{duration(runtime)}
</TextBubble>
}
</Link>
</div>
<div style={styles.content}>
<div style={styles.textContainer}>
<Link
to={href}
onClick={onClick}
style={styles.textAnchor}
qaHook={qaHook ? createQAHook(title, "external", "link") : null}
>
{status &&
<div
style={[
styles.status.default,
styles.status[theme],
]}
>
{status}
</div>
}
{description &&
<BulletDescription description={description} />
}
<Heading
level={5}
weight="thin"
override={{
...styles.title.default,
...styles.title[theme],
...(lineClamp ? { WebkitLineClamp: lineClamp } : {}),
}}
>
{title}
</Heading>
{subtitle &&
<BulletDescription description={subtitle} />
}
</Link>
</div>
{descriptionIcon && onDescriptionIconClick &&
<button
style={styles.descriptionIcon}
onClick={onDescriptionIconClick}
>
{iconFromString(descriptionIcon, { label: descriptionIconLabel })}
</button>
}
</div>
</div>
);
ThumbnailListItem.propTypes = {
title: PropTypes.string,
subtitle: PropTypes.arrayOf(PropTypes.string),
href: PropTypes.string,
onClick: PropTypes.func,
imagePath: PropTypes.string,
imageIcon: PropTypes.oneOf(Object.keys(Icon)),
imageIconLabel: PropTypes.string,
runtime: PropTypes.number,
description: PropTypes.arrayOf(PropTypes.string),
descriptionIcon: PropTypes.oneOf(Object.keys(Icon)),
descriptionIconLabel: PropTypes.string,
onDescriptionIconClick: PropTypes.func,
status: PropTypes.string,
lineClamp: PropTypes.number,
theme: PropTypes.oneOf(["light", "dark", "active"]),
style: propTypes.style,
qaHook: PropTypes.bool,
};
ThumbnailListItem.defaultProps = {
theme: "light",
lineClamp: 1,
qaHook: false,
};
export default radium(ThumbnailListItem);