Bug 1514018 - Hero component refinement (WIP) (#4653)

- enforce image aspect ratios
- wire up links & add interaction states (active/focus/hover)
- generally tighten up styling
- set count of cards based on remote layout definition
- enforce character counts
This commit is contained in:
gavin lazar suntop 2019-01-15 08:56:29 -08:00 коммит произвёл GitHub
Родитель abb7a49a25
Коммит 915ef9df72
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
5 изменённых файлов: 131 добавлений и 74 удалений

Просмотреть файл

@ -18,6 +18,7 @@ export class _DiscoveryStreamBase extends React.PureComponent {
return (<CardGrid feed={component.feed} />);
case "Hero":
return (<Hero
title={component.header.title}
feed={component.feed}
style={component.properties.style}
items={component.properties.items} />);

Просмотреть файл

@ -3,14 +3,16 @@ import React from "react";
export class DSCard extends React.PureComponent {
render() {
return (
<div className="ds-card">
<img src={this.props.image_src} />
<a href={this.props.url} className="ds-card">
<div className="img-wrapper">
<div className="img" style={{backgroundImage: `url(${this.props.image_src}`}} />
</div>
<div className="meta">
<header>{this.props.title}</header>
<p>{this.props.excerpt}</p>
<p>{this.props.source}</p>
</div>
</div>
</a>
);
}
}

Просмотреть файл

@ -1,9 +1,24 @@
.ds-card {
img {
border: 5px solid transparent;
&:hover {
border: 5px solid $grey-30;
box-shadow: 0 1px 4px $grey-30;
border-radius: 4px;
}
.img-wrapper {
width: 100%;
border: 0.5px solid $black-10;
box-sizing: border-box;
border-radius: 4px;
margin: 0 0 12px;
}
.img {
height: 0;
padding-top: 50%; // 2:1 aspect ratio
background-repeat: no-repeat;
background-size: cover;
}
.meta {
@ -14,11 +29,20 @@
line-height: 24px;
font-size: 17px;
color: $grey-90;
&:hover {
color: $blue-60;
}
&:active {
color: $blue-70;
}
}
p {
font-size: 13px;
line-height: 20px;
color: $grey-50;
margin: 8px 0;
}
}

Просмотреть файл

@ -14,30 +14,35 @@ export class _Hero extends React.PureComponent {
}
let [heroRec, ...otherRecs] = feed.data.recommendations;
let truncateText = (text, cap) => `${text.substring(0, cap)}${text.length > cap ? `...` : ``}`;
// TODO: Let this count be determined by the endpoint
let cards = otherRecs.slice(1, 5).map((rec, index) => (
let cards = otherRecs.slice(1, this.props.items).map((rec, index) => (
<DSCard
key={`dscard-${index}`}
image_src={rec.image_src}
title={rec.title}
excerpt={rec.excerpt}
source="TODO: SOURCE" />
title={truncateText(rec.title, 44)}
url={rec.url}
source={truncateText(`TODO: SOURCE`, 22)} />
));
return (
<div className={`ds-hero ds-hero-${this.props.style}`}>
<div className="wrapper">
<img src={heroRec.image_src} />
<div className="meta">
<header>{heroRec.title}</header>
<p>{heroRec.excerpt}</p>
<p>TODO: SOURCE</p>
<div>
<div className="ds-header">{this.props.title}</div>
<div className={`ds-hero ds-hero-${this.props.style}`}>
<a href={heroRec.url} className="wrapper">
<div className="img-wrapper">
<div className="img" style={{backgroundImage: `url(${heroRec.image_src})`}} />
</div>
<div className="meta">
<header>{truncateText(heroRec.title, 28)}</header>
<p>{truncateText(heroRec.excerpt, 114)}</p>
<p>{truncateText(`TODO: SOURCE`, 22)}</p>
</div>
</a>
<div className="cards">
{ cards }
</div>
</div>
<div className="cards">
{ cards }
</div>
</div>
);
}

Просмотреть файл

@ -1,14 +1,63 @@
.ds-header {
font-size: 17px;
line-height: 24px;
color: $grey-90;
margin: 16px 0;
}
.ds-hero {
.img {
border: 0.5px solid $black-10;
box-sizing: border-box;
border-radius: 4px;
}
.ds-card {
border: 0;
&:hover {
border: 0;
box-shadow: none;
border-radius: 0;
}
.meta {
padding: 0;
}
}
// "1/3 width layout" (aka "Mobile First")
.wrapper {
img {
color: $grey-50;
margin: 18px 0;
padding: 20px 0;
border-top: 1px solid transparentize($grey-40, 0.64);
border-bottom: 1px solid transparentize($grey-40, 0.64);
.img-wrapper {
width: 100%;
height: auto;
}
.img {
height: 0;
padding-top: 50%; // 2:1 aspect ratio
background-repeat: no-repeat;
background-size: cover;
background-color: $grey-30;
}
.meta {
header {
font-size: 22px;
color: $grey-90;
&:hover {
color: $blue-60;
}
&:active {
color: $blue-70;
}
}
p {
@ -18,60 +67,51 @@
}
// "2/3 width layout"
.column-5 &,
.column-6 &,
.column-7 &,
.column-8 & {
.ds-column-5 &,
.ds-column-6 &,
.ds-column-7 &,
.ds-column-8 & {
.wrapper {
display: flex;
align-items: flex-start;
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-column-gap: 24px;
img {
width: 50%;
height: auto;
}
.meta {
width: 50%;
.img {
height: 0;
padding-top: 100%; // 1:1 aspect ratio
}
}
.cards {
display: flex;
flex-wrap: wrap;
.ds-card {
width: 50%;
padding: 12px;
&:nth-child(odd) {
padding: 12px 12px 12px 0;
}
&:nth-child(even) {
padding: 12px 0 12px 12px;
}
}
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-column-gap: 24px;
}
}
// "Full width layout"
.column-9 &,
.column-10 &,
.column-11 &,
.column-12 & {
.ds-column-9 &,
.ds-column-10 &,
.ds-column-11 &,
.ds-column-12 & {
.wrapper {
display: flex;
align-items: flex-start;
flex-direction: row-reverse;
img {
.img-wrapper {
width: 67%;
}
.img {
height: 0;
padding-top: 50%; // 2:1 aspect ratio
}
.meta {
width: 33%;
padding: 24px;
padding: 0 24px 0 0;
header {
font-size: 22px;
@ -84,24 +124,9 @@
}
.cards {
display: flex;
.ds-card {
width: 25%;
padding: 12px;
.meta {
padding: 0;
}
&:first-child {
padding: 12px 12px 12px 0;
}
&:last-child {
padding: 12px 0 12px 12px;
}
}
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-column-gap: 24px;
}
}
}