Skip to content
This repository has been archived by the owner on Feb 29, 2020. It is now read-only.

Commit

Permalink
feat(system-addon): Closes #2818 Port Highlight card UI to system addon
Browse files Browse the repository at this point in the history
  • Loading branch information
sarracini committed Jul 18, 2017
1 parent 2b33af1 commit 23e6333
Show file tree
Hide file tree
Showing 14 changed files with 303 additions and 58 deletions.
1 change: 1 addition & 0 deletions system-addon/content-src/activity-stream.scss
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,4 @@ a {
@import './components/ContextMenu/ContextMenu';
@import './components/PreferencesPane/PreferencesPane';
@import './components/ConfirmDialog/ConfirmDialog';
@import './components/Card/Card';
71 changes: 71 additions & 0 deletions system-addon/content-src/components/Card/Card.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
const React = require("react");
const LinkMenu = require("content-src/components/LinkMenu/LinkMenu");
const shortURL = require("content-src/lib/short-url");
const {FormattedMessage} = require("react-intl");
const cardContextTypes = require("./types");

/**
* Card component.
* Cards are found within a Section component and contain information about a link such
* as preview image, page title, page description, and some context about if the page
* was visited, bookmarked, trending etc...
* Each Section can make an unordered list of Cards which will create one instane of
* this class. Each card will then get a context menu which reflects the actions that
* can be done on this Card.
*/
class Card extends React.Component {
constructor(props) {
super(props);
this.state = {showContextMenu: false, activeCard: null};
}
toggleContextMenu(event, index) {
this.setState({showContextMenu: true, activeCard: index});
}
setBackgroundImageStyle(image) {
const style = {};
if (image) {
style.backgroundImage = `url(${image})`;
} else {
style.display = "none";
}
return style;
}
render() {
const {index, link, dispatch} = this.props;
const isContextMenuOpen = this.state.showContextMenu && this.state.activeCard === index;
const hostname = shortURL(link);
const {icon, intlID} = cardContextTypes[link.type];

return (<li className={`card-outer${isContextMenuOpen ? " active" : ""}`}>
<a href={link.url}>
<div className="card">
<div className="card-preview-image" style={this.setBackgroundImageStyle(link.image)} />
<div className="card-details">
<div className="card-host-name"> {hostname} </div>
<h4 className="card-title"> {link.title} </h4>
<p className={`card-description${link.image ? "" : " full-height"}`}> {link.description} </p>
<div className="card-context">
<span className={`card-context-icon icon icon-${icon}`} />
<div className="card-context-label"><FormattedMessage id={intlID} defaultMessage="Visited" /></div>
</div>
</div>
</div>
</a>
<button className="context-menu-button"
onClick={e => {
e.preventDefault();
this.toggleContextMenu(e, index);
}}>
<span className="sr-only">{`Open context menu for ${link.title}`}</span>
</button>
<LinkMenu
dispatch={dispatch}
visible={isContextMenuOpen}
onUpdate={val => this.setState({showContextMenu: val})}
index={index}
site={link}
options={link.context_menu_options} />
</li>);
}
}
module.exports = Card;
110 changes: 110 additions & 0 deletions system-addon/content-src/components/Card/_Card.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
.card-outer {
$card-width: $grid-unit * 2 + $base-gutter;
$card-height: 266px;
$card-preview-image-height: 122px;
$card-description-height: 34px;
$card-description-height-max: 200px;

background: $white;
display: inline-block;
margin-inline-end: $base-gutter;
width: $card-width;
border-radius: $border-radius;
border-color: $faintest-black;
height: $card-height;
position: relative;
@include context-menu-button;

.card {
height: 100%;
border-radius: $border-radius;
}

> a {
display: block;
color: inherit;
height: 100%;
outline: none;
position: absolute;

&.active, &:focus {
.card {
@include fade-in;
}
}
}

&:hover, &:focus, &.active {
outline: none;
@include fade-in;
@include context-menu-button-hover;
}

.card-preview-image {
position: relative;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
height: $card-preview-image-height;
border-bottom-color: $faintest-black;
border-bottom-style: solid;
border-bottom-width: 1px;
border-radius: $border-radius $border-radius 0 0;
}

.card-details {
padding: 10px 16px 12px;
}

.card-host-name {
color: $mid-light-grey;
font-size: 10px;
padding-bottom: 4px;
text-transform: uppercase;
}

.card-title {
margin: 0 0 2px;
font-size: inherit;
word-wrap: break-word;
}

.card-description {
font-size: 12px;
margin: 0;
word-wrap: break-word;
overflow: hidden;
line-height: 18px;
max-height: $card-description-height;

&.full-height {
max-height: $card-description-height-max;
}
}

.card-context {
padding: 16px 16px 14px 14px;
position: absolute;
bottom: 0;
left: 0;
right: 0;
color: $light-grey;
font-size: 11px;
display: flex;
align-items: center;
}

.card-context-icon {
opacity: 0.5;
font-size: 13px;
margin-inline-end: 6px;
display: block;
}

.card-context-label {
flex-grow: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
14 changes: 14 additions & 0 deletions system-addon/content-src/components/Card/types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
history: {
intlID: "type_label_visited",
icon: "historyItem"
},
bookmark: {
intlID: "type_label_bookmarked",
icon: "bookmark"
},
trending: {
intlID: "type_label_recommended",
icon: "trending"
}
};
10 changes: 5 additions & 5 deletions system-addon/content-src/components/Sections/Sections.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
const React = require("react");
const {connect} = require("react-redux");
const {FormattedMessage} = require("react-intl");
const Card = require("content-src/components/Card/Card");

class Section extends React.Component {
render() {
const {title, initialized, rows, infoOption} = this.props;
const {title, icon, initialized, rows, infoOption, dispatch} = this.props;
// <Section> <-- React component
// <section> <-- HTML5 element
// Dummy component, finished card component needs to be substituted in here
return (<section>
<div className="section-top-bar">
<h3 className="section-title"><FormattedMessage {...title} /></h3>
<h3 className="section-title"><span className={`icon icon-small-spacer icon-${icon}`} /><FormattedMessage {...title} /></h3>
{infoOption && <span className="section-info-option">
<span className="sr-only"><FormattedMessage id="section_info_option" /></span>
<img className="info-option-icon" />
Expand All @@ -31,7 +31,7 @@ class Section extends React.Component {
</span>}
</div>
{initialized && (<ul className="section-list" style={{padding: 0}}>
{rows.map(url => url && <img style={{maxHeight: "10em"}} src={url} />)}
{rows.map((link, index) => link && <Card index={index} dispatch={dispatch} link={link} />)}
</ul>)}
</section>);
}
Expand All @@ -42,7 +42,7 @@ class Sections extends React.Component {
const sections = this.props.Sections;
return (
<div className="sections-list">
{sections.map(section => <Section key={section.id} {...section} />)}
{sections.map(section => <Section key={section.id} {...section} dispatch={this.props.dispatch} />)}
</div>
);
}
Expand Down
3 changes: 2 additions & 1 deletion system-addon/content-src/components/Sections/_Sections.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.sections-list {

.section-top-bar {
position: relative;

Expand Down Expand Up @@ -35,6 +34,7 @@
}

.info-option {
z-index: 9999;
position: absolute;
background: $white;
border: solid 1px $faintest-black;
Expand Down Expand Up @@ -71,6 +71,7 @@
}

.section-list {
width: $wrapper-card-outer;
clear: both;
margin: 0;
}
Expand Down
41 changes: 5 additions & 36 deletions system-addon/content-src/components/TopSites/_TopSites.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
.top-sites-list {
$top-sites-size: $grid-unit;
$top-sites-border-radius: 6px;
$inner-box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
$top-sites-title-height: 30px;
$top-sites-vertical-space: 18px;
$screenshot-size: cover;
Expand Down Expand Up @@ -38,48 +37,18 @@

&.active, &:focus {
.tile {
box-shadow: inset $inner-box-shadow, 0 0 0 5px $faintest-black;
transition: box-shadow 150ms;
@include fade-in;
}
}
}

.context-menu-button {
cursor: pointer;
position: absolute;
top: -($context-menu-button-size / 2);
offset-inline-end: -($context-menu-button-size / 2);
width: $context-menu-button-size;
height: $context-menu-button-size;
background-color: $white;
background-image: url('#{$image-path}glyph-more-16.svg');
background-position: 65%;
background-repeat: no-repeat;
background-clip: padding-box;
border: $context-menu-button-border;
border-radius: 100%;
box-shadow: $context-menu-button-boxshadow;
transform: scale(0.25);
opacity: 0;
transition-property: transform, opacity;
transition-duration: 200ms;
z-index: 399;
@include context-menu-button;

&:focus, &:active {
transform: scale(1);
opacity: 1;
}
}

&:hover, &:active, &:focus, &.active {
&:hover, &:focus, &.active {
.tile {
box-shadow: inset $inner-box-shadow, 0 0 0 5px $faintest-black;
transition: box-shadow 150ms;
}
.context-menu-button {
transform: scale(1);
opacity: 1;
@include fade-in;
}
@include context-menu-button-hover;
}

.tile {
Expand Down
31 changes: 25 additions & 6 deletions system-addon/content-src/styles/_icons.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
margin-inline-end: 8px;
}

&.icon-small-spacer {
margin-inline-end: 6px;
}

&.icon-bookmark {
background-image: url('#{$image-path}glyph-bookmark-16.svg');
}
Expand Down Expand Up @@ -51,11 +55,26 @@
background-image: url('#{$image-path}glyph-pocket-16.svg');
}

&.icon-pin-small {
background-image: url('#{$image-path}glyph-pin-12.svg');
background-size: $smaller-icon-size;
height: $smaller-icon-size;
width: $smaller-icon-size;
}
&.icon-highlights {
background-image: url('#{$image-path}glyph-highlights-16.svg');
}

&.icon-historyItem {
background-image: url('#{$image-path}glyph-historyItem-16.svg');
}

&.icon-trending {
background-image: url('#{$image-path}glyph-trending-16.svg');
}

&.icon-now {
background-image: url('#{$image-path}glyph-now-16.svg');
}

&.icon-pin-small {
background-image: url('#{$image-path}glyph-pin-12.svg');
background-size: $smaller-icon-size;
height: $smaller-icon-size;
width: $smaller-icon-size;
}
}
Loading

0 comments on commit 23e6333

Please sign in to comment.