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

Commit

Permalink
Merge pull request #528 from k88hudson/empty-case
Browse files Browse the repository at this point in the history
feat(content): Empty case for highlights
  • Loading branch information
k88hudson committed Apr 15, 2016
2 parents 6644bcf + e355547 commit 3bff338
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 31 deletions.
19 changes: 14 additions & 5 deletions content-src/components/Spotlight/Spotlight.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ const SpotlightItem = React.createClass({
getDefaultProps() {
return {
onClick: function() {},
onDelete: function() {}
onDelete: function() {},
bestImage: {}
};
},
render() {
const site = this.props;
const image = site.bestImage;
const imageUrl = image.url;
const description = site.description;
const description = site.description || site.url;
const isPortrait = image.height > image.width;

let contextMessage;
Expand All @@ -33,9 +34,17 @@ const SpotlightItem = React.createClass({
contextMessage = "Visited recently";
}

const style = {};

if (imageUrl) {
style.backgroundImage = `url(${imageUrl})`;
} else {
style.backgroundColor = site.backgroundColor;
}

return (<li className="spotlight-item">
<a onClick={this.props.onClick} href={site.url} ref="link">
<div className={classNames("spotlight-image", {portrait: isPortrait})} style={{backgroundImage: `url(${imageUrl})`}} ref="image">
<div className={classNames("spotlight-image", {portrait: isPortrait})} style={style} ref="image">
<SiteIcon className="spotlight-icon" height={40} width={40} site={site} ref="icon" showBackground={true} border={false} faviconSize={32} />
</div>
<div className="spotlight-details">
Expand All @@ -56,10 +65,10 @@ const SpotlightItem = React.createClass({

SpotlightItem.propTypes = {
url: React.PropTypes.string.isRequired,
bestImage: React.PropTypes.object.isRequired,
bestImage: React.PropTypes.object,
favicon_url: React.PropTypes.string,
title: React.PropTypes.string.isRequired,
description: React.PropTypes.string.isRequired,
description: React.PropTypes.string,
onDelete: React.PropTypes.func,
onClick: React.PropTypes.func
};
Expand Down
20 changes: 18 additions & 2 deletions content-src/lib/shim.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,15 @@ module.exports = function() {
const action = JSON.parse(event.detail);
switch (action.type) {
case "TOP_FRECENT_SITES_REQUEST":
dispatch({type: "TOP_FRECENT_SITES_RESPONSE", data: fakeData.TopSites.rows});
dispatch({type: "TOP_FRECENT_SITES_RESPONSE", data: fakeData.TopSites.rows.map(site => {
return Object.assign({}, site, {
// images: [],
// favicon: null,
// favicon_url: null,
// favicon_colors: null,
// description: null
});
})});
break;
case "RECENT_BOOKMARKS_REQUEST":
if (action.meta && action.meta.append) {
Expand All @@ -37,7 +45,15 @@ module.exports = function() {
}
break;
case "FRECENT_LINKS_REQUEST":
dispatch({type: "FRECENT_LINKS_RESPONSE", data: fakeData.FrecentHistory.rows});
dispatch({type: "FRECENT_LINKS_RESPONSE", data: fakeData.FrecentHistory.rows.map(site => {
return Object.assign({}, site, {
// images: [],
// favicon: null,
// favicon_url: null,
// favicon_colors: null,
// description: null
});
})});
break;
}
}, false);
Expand Down
62 changes: 47 additions & 15 deletions content-src/selectors/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,57 @@ const urlParse = require("url-parse");
const SPOTLIGHT_LENGTH = module.exports.SPOTLIGHT_LENGTH = 3;
const TOP_SITES_LENGTH = module.exports.TOP_SITES_LENGTH = 6;
const BACKGROUND_FADE = 0.5;
const DEFAULT_FAVICON_BG_COLOR = [255, 255, 255];
const DEFAULT_FAVICON_BG_COLOR = [150, 150, 150];

module.exports.justDispatch = (() => ({}));

function getBackgroundRGB(site) {
if (site.favicon_colors && site.favicon_colors[0] && site.favicon_colors[0].color) {
return site.favicon_colors[0].color;
}

const favicon = site.favicon_url || site.favicon;
const parsedUrl = site.parsedUrl || urlParse(site.url || "") ;
const label = prettyUrl(parsedUrl.hostname);
return favicon ? DEFAULT_FAVICON_BG_COLOR : getRandomColor(label);
}

module.exports.getBackgroundRGB = getBackgroundRGB;

function isValidSpotlightSite(site) {
return (site.bestImage &&
site.title &&
site.description &&
site.title !== site.description);
}

const selectSpotlight = module.exports.selectSpotlight = createSelector(
[state => state.FrecentHistory, state => state.Blocked],
[
state => state.FrecentHistory,
state => state.Blocked
],
(FrecentHistory, Blocked) => {
const rows = FrecentHistory.rows
.filter(site => !Blocked.urls.has(site.url))
.map(site => {
const newProps = {};
const bestImage = getBestImage(site.images);
return Object.assign({}, site, {bestImage});
if (bestImage) {
newProps.bestImage = bestImage;
}
newProps.backgroundColor = toRGBString(...getBackgroundRGB(site, [200, 200, 200]), BACKGROUND_FADE - 0.1);
return Object.assign({}, site, newProps);
})
.filter(site => {
return (
site.bestImage &&
site.title &&
site.description &&
site.title !== site.description
);
.sort((site1, site2) => {
const site1Valid = isValidSpotlightSite(site1);
const site2Valid = isValidSpotlightSite(site2);
if (site1Valid && site2Valid) {
return 0;
} else if (site2Valid) {
return 1;
} else {
return -1;
}
});
return Object.assign({}, FrecentHistory, {rows});
}
Expand Down Expand Up @@ -67,16 +98,15 @@ module.exports.selectNewTabSites = createSelector(
}
);

module.exports.selectSiteIcon = createSelector(
const selectSiteIcon = createSelector(
site => site,
site => {
const favicon = site.favicon_url || site.favicon;
const parsedUrl = site.parsedUrl || urlParse(site.url || "") ;
const label = prettyUrl(parsedUrl.hostname);
let background = favicon ? DEFAULT_FAVICON_BG_COLOR : getRandomColor(label);
try { background = site.favicon_colors[0].color || background; } catch (e) {/**/}
const backgroundColor = toRGBString(...background, favicon ? BACKGROUND_FADE : 1);
const fontColor = getBlackOrWhite(...background);
const backgroundRGB = getBackgroundRGB(site);
const backgroundColor = toRGBString(...backgroundRGB, favicon ? BACKGROUND_FADE : 1);
const fontColor = getBlackOrWhite(...backgroundRGB);
const firstLetter = prettyUrl(parsedUrl.hostname)[0];
return {
url: site.url,
Expand All @@ -89,4 +119,6 @@ module.exports.selectSiteIcon = createSelector(
}
);

module.exports.selectSiteIcon = selectSiteIcon;
module.exports.selectSiteIcon.BACKGROUND_FADE = BACKGROUND_FADE;
module.exports.DEFAULT_FAVICON_BG_COLOR = DEFAULT_FAVICON_BG_COLOR;
68 changes: 59 additions & 9 deletions content-test/selectors/selectors.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ const {
selectSpotlight,
selectNewTabSites,
selectSiteIcon,
SPOTLIGHT_LENGTH
getBackgroundRGB,
SPOTLIGHT_LENGTH,
DEFAULT_FAVICON_BG_COLOR
} = require("selectors/selectors");
const {rawMockData, createMockProvider} = require("test/test-utils");

Expand Down Expand Up @@ -54,12 +56,14 @@ describe("selectors", () => {
// Tests that provided sites don't get selected, because they don't
// match the conditions for spotlight to use them
function assertInvalidSite(site) {
const testSite = Object.assign({}, validSpotlightSite, site);
const emptyState = selectSpotlight({
FrecentHistory: {rows: [testSite]},
const invalidSite = Object.assign({}, validSpotlightSite, site);
const result = selectSpotlight({
FrecentHistory: {rows: [invalidSite, validSpotlightSite]},
Blocked: {urls: new Set()}
});
assert.lengthOf(emptyState.rows, 0);
assert.lengthOf(result.rows, 2);
assert.equal(result.rows[0].url, validSpotlightSite.url);
assert.equal(result.rows[1].url, invalidSite.url);
}

it("should have the same properties as History", () => {
Expand All @@ -72,23 +76,50 @@ describe("selectors", () => {
assert.property(site.bestImage, "url");
});
});
it("should skip sites that do not have a title", () => {
it("should add a backgroundColor for items that dont have an image", () => {
const site = {
url: "https://foo.com",
favicon_colors: [{color: [11, 11, 11]}]
};
const results = selectSpotlight({
FrecentHistory: {rows: [site]},
Blocked: {urls: new Set()}
});
assert.deepEqual(results.rows[0].backgroundColor, "rgba(11, 11, 11, 0.4)");
});
it("should use a fallback bg color if no favicon_colors are available", () => {
const site = {url: "https://foo.com"};
const results = selectSpotlight({
FrecentHistory: {rows: [site]},
Blocked: {urls: new Set()}
});
assert.ok(results.rows[0].backgroundColor, "should have a bg color");
});
it("should sort sites that do not have a title to the end", () => {
assertInvalidSite({
title: null
});
});
it("should skip sites that do not have a description", () => {
it("should sort sites that do not have a description to the end", () => {
assertInvalidSite({
description: null
});
});
it("should skip sites for which the title equals the description", () => {
it("should sort sites for which the title equals the description to the end", () => {
assertInvalidSite({
title: "foo",
description: "foo"
});
});
it("should skip sites that do not have an images prop or an empty array", () => {
it("should sort sites that do not have an images prop or an empty array to the end", () => {
assertInvalidSite({
images: null
});
assertInvalidSite({
images: []
});
});
it("should append History sites to the end", () => {
assertInvalidSite({
images: null
});
Expand Down Expand Up @@ -219,3 +250,22 @@ describe("selectors", () => {
});
});
});

describe("getBackgroundRGB", () => {
it("should use favicon_colors if available", () => {
assert.deepEqual(
getBackgroundRGB({url: "http://foo.com", favicon_colors: [{color: [11, 11, 11]}]}),
[11, 11, 11]
);
});
it("should use a default bg if a favicon is supplied", () => {
const result = getBackgroundRGB({url: "http://foo.com", favicon_url: "adsd.ico"});
assert.ok(result);
assert.deepEqual(result, DEFAULT_FAVICON_BG_COLOR);
});
it("should use a random color if no favicon_colors or favicon", () => {
const result = getBackgroundRGB({url: "http://foo.com"});
assert.ok(result);
assert.notDeepEqual(result, DEFAULT_FAVICON_BG_COLOR);
});
});

0 comments on commit 3bff338

Please sign in to comment.