From b7463bed2321463664e8e8044c0c1f51ddfdc214 Mon Sep 17 00:00:00 2001 From: Ed Lee Date: Fri, 25 Jan 2019 15:37:38 +0000 Subject: [PATCH] Bug 1522752 - Add Snippets header, article sources and bug fixes to Activity Stream r=k88hudson Differential Revision: https://phabricator.services.mozilla.com/D17599 --HG-- extra : moz-landing-system : lando --- .../asrouter/components/Button/_Button.scss | 2 +- .../ConditionalWrapper/ConditionalWrapper.jsx | 2 + .../components/SnippetBase/_SnippetBase.scss | 2 +- .../templates/SimpleSnippet/SimpleSnippet.jsx | 55 ++- .../SimpleSnippet/SimpleSnippet.schema.json | 17 +- .../SimpleSnippet/_SimpleSnippet.scss | 44 ++ .../ASRouterAdmin/ASRouterAdmin.scss | 2 +- .../content-src/components/Base/Base.jsx | 18 +- .../content-src/components/Base/_Base.scss | 5 + .../content-src/components/Card/_Card.scss | 2 +- .../DiscoveryStreamBase.jsx | 8 +- .../DSCard/DSCard.jsx | 2 +- .../DiscoveryStreamComponents/Hero/Hero.jsx | 23 +- .../DiscoveryStreamComponents/Hero/_Hero.scss | 45 ++ .../DiscoveryStreamComponents/List/List.jsx | 10 +- .../DiscoveryStreamComponents/List/_List.scss | 156 ++++--- .../ErrorBoundary/_ErrorBoundary.scss | 4 + .../content-src/components/Search/Search.jsx | 2 +- .../components/Search/_Search.scss | 2 + .../newtab/content-src/lib/truncate-text.js | 3 + .../newtab/content-src/styles/_theme.scss | 2 +- .../styles/activity-stream-mac.scss | 2 +- .../newtab/css/activity-stream-linux.css | 209 +++++++--- .../newtab/css/activity-stream-linux.css.map | 24 +- .../newtab/css/activity-stream-mac.css | 211 +++++++--- .../newtab/css/activity-stream-mac.css.map | 26 +- .../newtab/css/activity-stream-windows.css | 209 +++++++--- .../css/activity-stream-windows.css.map | 24 +- .../data/content/activity-stream.bundle.js | 392 +++++++++++------- .../content/activity-stream.bundle.js.map | 2 +- .../components/newtab/lib/ActivityStream.jsm | 3 +- .../newtab/lib/DiscoveryStreamFeed.jsm | 65 ++- .../lib/SnippetsTestMessageProvider.jsm | 28 ++ .../components/newtab/lib/TopSitesFeed.jsm | 2 +- .../newtab/locales-src/az/strings.properties | 6 +- .../locales-src/es-CL/strings.properties | 3 + .../newtab/locales-src/fr/strings.properties | 1 + .../newtab/locales-src/gn/strings.properties | 4 +- .../newtab/locales-src/vi/strings.properties | 7 +- .../locales/az/activity-stream-strings.js | 9 +- .../locales/es-CL/activity-stream-strings.js | 2 +- .../locales/fr/activity-stream-strings.js | 2 +- .../locales/gn/activity-stream-strings.js | 5 +- .../locales/vi/activity-stream-strings.js | 8 +- .../browser_topsites_contextMenu_options.js | 4 +- .../test/browser/browser_topsites_section.js | 2 +- .../asrouter/templates/SimpleSnippet.test.jsx | 32 ++ .../content-src/lib/truncate-text.test.js | 37 ++ .../test/unit/lib/DiscoveryStreamFeed.test.js | 53 ++- .../newtab/test/unit/lib/TopSitesFeed.test.js | 6 + 50 files changed, 1331 insertions(+), 453 deletions(-) create mode 100644 browser/components/newtab/content-src/asrouter/components/ConditionalWrapper/ConditionalWrapper.jsx create mode 100644 browser/components/newtab/content-src/lib/truncate-text.js create mode 100644 browser/components/newtab/test/unit/content-src/lib/truncate-text.test.js diff --git a/browser/components/newtab/content-src/asrouter/components/Button/_Button.scss b/browser/components/newtab/content-src/asrouter/components/Button/_Button.scss index 6100691aaaab..5704663be394 100644 --- a/browser/components/newtab/content-src/asrouter/components/Button/_Button.scss +++ b/browser/components/newtab/content-src/asrouter/components/Button/_Button.scss @@ -41,7 +41,7 @@ } } -[lwt-newtab-brighttext] { +[lwt-newtab-brighttext]:not(.force-light-theme) { .secondary { background-color: $grey-10-10; diff --git a/browser/components/newtab/content-src/asrouter/components/ConditionalWrapper/ConditionalWrapper.jsx b/browser/components/newtab/content-src/asrouter/components/ConditionalWrapper/ConditionalWrapper.jsx new file mode 100644 index 000000000000..50771d16f725 --- /dev/null +++ b/browser/components/newtab/content-src/asrouter/components/ConditionalWrapper/ConditionalWrapper.jsx @@ -0,0 +1,2 @@ +// lifted from https://gist.github.com/kitze/23d82bb9eb0baabfd03a6a720b1d637f +export const ConditionalWrapper = ({condition, wrap, children}) => (condition ? wrap(children) : children); diff --git a/browser/components/newtab/content-src/asrouter/components/SnippetBase/_SnippetBase.scss b/browser/components/newtab/content-src/asrouter/components/SnippetBase/_SnippetBase.scss index 896d17639f94..35b2c4b5ea66 100644 --- a/browser/components/newtab/content-src/asrouter/components/SnippetBase/_SnippetBase.scss +++ b/browser/components/newtab/content-src/asrouter/components/SnippetBase/_SnippetBase.scss @@ -23,7 +23,7 @@ text-decoration: underline; } - [lwt-newtab-brighttext] & { + [lwt-newtab-brighttext]:not(.force-light-theme) & { font-weight: bold; } } diff --git a/browser/components/newtab/content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.jsx b/browser/components/newtab/content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.jsx index fdc6c2fd5eb3..41a8755b5958 100644 --- a/browser/components/newtab/content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.jsx +++ b/browser/components/newtab/content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.jsx @@ -1,4 +1,5 @@ import {Button} from "../../components/Button/Button"; +import {ConditionalWrapper} from "../../components/ConditionalWrapper/ConditionalWrapper"; import React from "react"; import {RichText} from "../../components/RichText/RichText"; import {safeURI} from "../../template-utils"; @@ -67,22 +68,64 @@ export class SimpleSnippet extends React.PureComponent { sendClick={props.sendClick} />); } + wrapSectionHeader(url) { + return function(children) { + return {children}; + }; + } + + wrapSnippetContent(children) { + return
{children}
; + } + + renderSectionHeader() { + const {props} = this; + + // an icon and text must be specified to render the section header + if (props.content.section_title_icon && props.content.section_title_text) { + const sectionTitleIcon = safeURI(props.content.section_title_icon); + const sectionTitleURL = props.content.section_title_url; + + return ( +
+

+ + + {props.content.section_title_text} + +

+
+ ); + } + + return null; + } + render() { const {props} = this; + const sectionHeader = this.renderSectionHeader(); let className = "SimpleSnippet"; + if (props.className) { className += ` ${props.className}`; } if (props.content.tall) { className += " tall"; } + if (sectionHeader) { + className += " has-section-header"; + } + return ( - -
- {this.renderTitle()}

{this.renderText()}

- {this.props.extraContent} -
- {
{this.renderButton()}
} + {sectionHeader} + + +
+ {this.renderTitle()}

{this.renderText()}

+ {this.props.extraContent} +
+ {
{this.renderButton()}
} +
); } } diff --git a/browser/components/newtab/content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.schema.json b/browser/components/newtab/content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.schema.json index 93116f2a48e6..66f3f8d2283e 100644 --- a/browser/components/newtab/content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.schema.json +++ b/browser/components/newtab/content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.schema.json @@ -97,6 +97,20 @@ "description": "Additional parameters for link action, example which specific menu the button should open" } } + }, + "section_title_icon": { + "type": "string", + "description": "Section title icon. 16x16px. SVG or PNG preferred. section_title_text must also be specified to display." + }, + "section_title_text": { + "type": "string", + "description": "Section title text. section_title_icon must also be specified to display." + }, + "section_title_url": { + "allOf": [ + {"$ref": "#/definitions/link_url"}, + {"description": "A url, section_title_text links to this"} + ] } }, "additionalProperties": false, @@ -105,6 +119,7 @@ "button_action": ["button_label"], "button_url": ["button_label"], "button_color": ["button_label"], - "button_background_color": ["button_label"] + "button_background_color": ["button_label"], + "section_title_url": ["section_title_text"] } } diff --git a/browser/components/newtab/content-src/asrouter/templates/SimpleSnippet/_SimpleSnippet.scss b/browser/components/newtab/content-src/asrouter/templates/SimpleSnippet/_SimpleSnippet.scss index 885470a6991b..b16f78dc93c8 100644 --- a/browser/components/newtab/content-src/asrouter/templates/SimpleSnippet/_SimpleSnippet.scss +++ b/browser/components/newtab/content-src/asrouter/templates/SimpleSnippet/_SimpleSnippet.scss @@ -1,3 +1,6 @@ +$section-header-height: 30px; +$icon-width: 54px; // width of primary icon + margin + .SimpleSnippet { &.tall { padding: 27px 0; @@ -88,4 +91,45 @@ .icon { align-self: flex-start; } + + &.has-section-header .innerWrapper { + // account for section header being 100% width + flex-wrap: wrap; + padding-top: 7px; + } + + // wrapper div added if section-header is displayed that allows icon/text/button + // to squish instead of wrapping. this is effectively replicating layout behavior + // when section-header is *not* present. + .innerContentWrapper { + align-items: center; + display: flex; + } + + .section-header { + flex: 0 0 100%; + margin-bottom: 10px; + } + + .section-title { + // color should match that of 'Recommended by Pocket' and 'Highlights' in newtab page + color: var(--newtab-section-header-text-color); + display: inline-block; + font-size: 13px; + font-weight: bold; + margin: 0; + + a { + color: var(--newtab-section-header-text-color); + font-weight: inherit; + text-decoration: none; + } + + .icon { + height: 16px; + margin-inline-end: 6px; + margin-top: -2px; + width: 16px; + } + } } diff --git a/browser/components/newtab/content-src/components/ASRouterAdmin/ASRouterAdmin.scss b/browser/components/newtab/content-src/components/ASRouterAdmin/ASRouterAdmin.scss index 678dc70505d2..1746068db596 100644 --- a/browser/components/newtab/content-src/components/ASRouterAdmin/ASRouterAdmin.scss +++ b/browser/components/newtab/content-src/components/ASRouterAdmin/ASRouterAdmin.scss @@ -92,7 +92,7 @@ background: $yellow-50; padding: 2px 5px; - [lwt-newtab-brighttext] & { + [lwt-newtab-brighttext]:not(.force-light-theme) & { color: $black; } } diff --git a/browser/components/newtab/content-src/components/Base/Base.jsx b/browser/components/newtab/content-src/components/Base/Base.jsx index a5600829eedb..590e337c97d0 100644 --- a/browser/components/newtab/content-src/components/Base/Base.jsx +++ b/browser/components/newtab/content-src/components/Base/Base.jsx @@ -136,6 +136,15 @@ export class BaseContent extends React.PureComponent { this.props.dispatch(ac.UserEvent({event: "OPEN_NEWTAB_PREFS"})); } + disableDarkTheme() { + // Dark themes are not supported in discovery stream view + // Add force-light-theme class to body tag to disable dark mode. See Bug 1519764 + const bodyClassNames = global.document.body.classList; + if (!bodyClassNames.contains("force-light-theme")) { + bodyClassNames.add("force-light-theme"); + } + } + render() { const {props} = this; const {App} = props; @@ -147,6 +156,10 @@ export class BaseContent extends React.PureComponent { const isDiscoveryStream = props.DiscoveryStream.config && props.DiscoveryStream.config.enabled; const searchHandoffEnabled = prefs["improvesearch.handoffToAwesomebar"]; + if (isDiscoveryStream) { + this.disableDarkTheme(); + } + const outerClassName = [ "outer-wrapper", shouldBeFixedToTop && "fixed-to-top", @@ -171,7 +184,10 @@ export class BaseContent extends React.PureComponent { } - {isDiscoveryStream ? : } + {isDiscoveryStream ? ( + + + ) : } diff --git a/browser/components/newtab/content-src/components/Base/_Base.scss b/browser/components/newtab/content-src/components/Base/_Base.scss index f7d9fc952425..980f61e41854 100644 --- a/browser/components/newtab/content-src/components/Base/_Base.scss +++ b/browser/components/newtab/content-src/components/Base/_Base.scss @@ -19,6 +19,11 @@ } } +.force-light-theme { + --newtab-background-color: #{$grey-10} !important; // sass-lint:disable-line no-important + --newtab-text-primary-color: #{$grey-90} !important; // sass-lint:disable-line no-important +} + main { margin: auto; // Offset the snippets container so things at the bottom of the page are still diff --git a/browser/components/newtab/content-src/components/Card/_Card.scss b/browser/components/newtab/content-src/components/Card/_Card.scss index 7e7ddfd5cb97..4b1300fcc2e1 100644 --- a/browser/components/newtab/content-src/components/Card/_Card.scss +++ b/browser/components/newtab/content-src/components/Card/_Card.scss @@ -71,7 +71,7 @@ overflow: hidden; position: relative; - [lwt-newtab-brighttext] & { + [lwt-newtab-brighttext]:not(.force-light-theme) & { background-color: $grey-60; } diff --git a/browser/components/newtab/content-src/components/DiscoveryStreamBase/DiscoveryStreamBase.jsx b/browser/components/newtab/content-src/components/DiscoveryStreamBase/DiscoveryStreamBase.jsx index 6d9466180862..a79a1012e7c2 100644 --- a/browser/components/newtab/content-src/components/DiscoveryStreamBase/DiscoveryStreamBase.jsx +++ b/browser/components/newtab/content-src/components/DiscoveryStreamBase/DiscoveryStreamBase.jsx @@ -113,7 +113,7 @@ export class _DiscoveryStreamBase extends React.PureComponent { }); } - renderComponent(component) { + renderComponent(component, embedWidth) { let rows; const {spocs} = this.props.DiscoveryStream; @@ -157,6 +157,8 @@ export class _DiscoveryStreamBase extends React.PureComponent { return ( = 9 ? `cards` : `list`} + feed={component.feed} title={component.header && component.header.title} data={component.data} border={component.properties.border} @@ -173,6 +175,8 @@ export class _DiscoveryStreamBase extends React.PureComponent { { styles[rowIndex] = [...styles[rowIndex] || [], component.styles]; return (
- {this.renderComponent(component)} + {this.renderComponent(component, row.width)}
); })} diff --git a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSCard/DSCard.jsx b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSCard/DSCard.jsx index 59cff16ca91a..9688f0502b8e 100644 --- a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSCard/DSCard.jsx +++ b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSCard/DSCard.jsx @@ -31,7 +31,7 @@ export class DSCard extends React.PureComponent {
{this.props.title}
-

{this.props.excerpt}

+ {this.props.excerpt &&

{this.props.excerpt}

} {this.props.context ? (

{this.props.context}

) : ( diff --git a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/Hero/Hero.jsx b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/Hero/Hero.jsx index cc610ada8f06..281839e9282e 100644 --- a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/Hero/Hero.jsx +++ b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/Hero/Hero.jsx @@ -1,6 +1,8 @@ import {actionCreators as ac} from "common/Actions.jsm"; import {DSCard} from "../DSCard/DSCard.jsx"; +import {List} from "../List/List.jsx"; import React from "react"; +import {truncateText} from "content-src/lib/truncate-text"; export class Hero extends React.PureComponent { constructor(props) { @@ -36,7 +38,6 @@ export class Hero extends React.PureComponent { let [heroRec, ...otherRecs] = data.recommendations.slice(0, this.props.items); this.heroRec = heroRec; - let truncateText = (text, cap) => `${text.substring(0, cap)}${text.length > cap ? `...` : ``}`; // Note that `{index + 1}` is necessary below for telemetry since we treat heroRec as index 0. let cards = otherRecs.map((rec, index) => ( @@ -49,10 +50,20 @@ export class Hero extends React.PureComponent { index={index + 1} type={this.props.type} dispatch={this.props.dispatch} - context={truncateText(rec.context || "", 22)} - source={truncateText(`TODO: SOURCE`, 22)} /> + context={truncateText(rec.context, 22)} + source={truncateText(rec.domain, 22)} /> )); + let list = ( + + ); + return (
{this.props.title}
@@ -67,12 +78,12 @@ export class Hero extends React.PureComponent { {heroRec.context ? (

{truncateText(heroRec.context, 22)}

) : ( -

{truncateText(`TODO: SOURCE`, 22)}

+

{truncateText(heroRec.domain, 22)}

)}
-
- { cards } +
+ { this.props.subComponentType === `cards` ? cards : list }
diff --git a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/Hero/_Hero.scss b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/Hero/_Hero.scss index cde5890d1551..64b72a44e9da 100644 --- a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/Hero/_Hero.scss +++ b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/Hero/_Hero.scss @@ -1,8 +1,24 @@ +$card-header-in-hero-font-size: 13; +$card-header-in-hero-line-height: 20; + .ds-hero { .img { @include image-as-background; } + header { + font-weight: 600; + } + + p { + line-height: 1.538; + } + + .ds-list { + border-top: 0; + padding-top: 0; + } + .ds-card { border: 0; @@ -14,6 +30,17 @@ .meta { padding: 0; + + .title { + // show only 2 lines of copy + @include limit-visibile-lines(2, $card-header-in-hero-line-height, $card-header-in-hero-font-size); + font-size: $card-header-in-hero-font-size * 1px; + line-height: $card-header-in-hero-line-height * 1px; + } + } + + .img-wrapper { + margin: 0 0 12px; } } @@ -29,6 +56,11 @@ border-top: $border-secondary; border-bottom: $border-secondary; + @at-root .ds-hero-no-border .wrapper { + border-top: 0; + border-bottom: 0; + } + &:hover .meta header { color: $blue-60; } @@ -72,6 +104,17 @@ grid-template-columns: repeat(2, 1fr); grid-column-gap: 24px; + .img-wrapper { + margin: 0; + grid-column: 2; + grid-row: 1; + } + + .meta { + grid-column: 1; + grid-row: 1; + } + .img { height: 0; padding-top: 100%; // 1:1 aspect ratio @@ -97,6 +140,7 @@ .img-wrapper { width: 67%; + margin: 0; } .img { @@ -114,6 +158,7 @@ p { font-size: 15px; + line-height: 1.6; } } } diff --git a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/List/List.jsx b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/List/List.jsx index 16c120aaf1f0..ad1057dc1e01 100644 --- a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/List/List.jsx +++ b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/List/List.jsx @@ -1,6 +1,7 @@ import {actionCreators as ac} from "common/Actions.jsm"; import {connect} from "react-redux"; import React from "react"; +import {truncateText} from "content-src/lib/truncate-text"; /** * @note exported for testing only @@ -39,6 +40,7 @@ export class ListItem extends React.PureComponent { {this.props.title} + {this.props.excerpt &&
{truncateText(this.props.excerpt, 90)}
}
{this.props.domain}
@@ -60,25 +62,29 @@ export function _List(props) { const recs = feed.data.recommendations; - let recMarkup = recs.slice(0, props.items).map((rec, index) => ( + let recMarkup = recs.slice(props.recStartingPoint, props.items).map((rec, index) => ( ) ); const listStyles = [ "ds-list", + props.fullWidth ? "ds-list-full-width" : "", + props.hasBorders ? "ds-list-borders" : "", props.hasImages ? "ds-list-images" : "", props.hasNumbers ? "ds-list-numbers" : "", ]; return (
{props.header && props.header.title ?
{props.header.title}
: null } -
    {recMarkup}
); } _List.defaultProps = { + recStartingPoint: 0, // Index of recommendations to start displaying from + fullWidth: false, // Display items taking up the whole column + hasBorders: false, // Display lines separating each item hasImages: false, // Display images for each item hasNumbers: false, // Display numbers for each item items: 6, // Number of stories to display. TODO: get from endpoint diff --git a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/List/_List.scss b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/List/_List.scss index 0afb5e1229ca..be2b234f3281 100644 --- a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/List/_List.scss +++ b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/List/_List.scss @@ -1,17 +1,44 @@ // Type sizes $item-font-size: 13; +$item-image-size: 72px; $item-line-height: 20; -.ds-list-border { - border: 0; - border-top: $border-secondary; +// XXX this is gross, and attaches the bottom-border to the item above. +// Ideally, we'd attach the top-border to the item that needs it. +// Unfortunately the border needs to go _above_ the row gap as currently +// set up, which means that some refactoring will be required to do this. +@mixin bottom-border-except-last-grid-row($columns) { + .ds-list-item:not(:nth-last-child(-n+#{$columns})) { + border-bottom: $border-secondary; + margin-bottom: -1px; // cancel out the pixel we used for the border - padding-top: 1px; + padding-bottom: 2px; + } +} - // Instead of using margin, we need to use these to override stuff that comes - // by default from
. - margin-block-start: 8px; - margin-block-end: 8px; +@mixin set-item-sizes($font-size, $line-height, $image-size) { + .ds-list-item { + // XXX see if we really want absolute units, maybe hoist somewhere central? + font-size: $font-size * 1px; + line-height: $line-height * 1px; + } + + .ds-list-item-excerpt { + @include limit-visibile-lines(2, $line-height, $font-size); + } + + .ds-list-item-info { + @include limit-visibile-lines(1, $line-height, $font-size); + } + + .ds-list-item-title { + @include limit-visibile-lines(2, $line-height, $font-size); + } + + .ds-list-image { + min-width: $image-size; + width: $image-size; + } } .ds-list { @@ -23,22 +50,35 @@ $item-line-height: 20; // regression detection? padding-inline-start: 0; - // "2/3 width layout" - .ds-column-5 &, - .ds-column-6 &, - .ds-column-7 &, - .ds-column-8 & { - grid-template-columns: repeat(2, 1fr); - grid-row-gap: 24px; + &:not(.ds-list-full-width) { + @include set-item-sizes($item-font-size, $item-line-height, $item-image-size); + + // "2/3 width layout" + .ds-column-5 &, + .ds-column-6 &, + .ds-column-7 &, + .ds-column-8 & { + grid-template-columns: repeat(2, 1fr); + } + + // "Full width layout" + .ds-column-9 &, + .ds-column-10 &, + .ds-column-11 &, + .ds-column-12 & { + grid-template-columns: repeat(3, 1fr); + grid-row-gap: 18px; + } + + .ds-list-item-excerpt { + display: none; + } } - // "Full width layout" - .ds-column-9 &, - .ds-column-10 &, - .ds-column-11 &, - .ds-column-12 & { - grid-template-columns: repeat(3, 1fr); - grid-row-gap: 18px; + &:not(.ds-list-images) { + .ds-list-image { + display: none; + } } a { @@ -47,12 +87,6 @@ $item-line-height: 20; } } -.ds-list-images { - .ds-list-item .ds-list-image { - display: block; - } -} - .ds-list-numbers { $counter-whitespace: ($item-line-height - $item-font-size) * 1px; $counter-size: ($item-font-size) * 2px + $counter-whitespace; @@ -90,22 +124,42 @@ $item-line-height: 20; } } -// XXX this is gross, and attaches the bottom-border to the item above. -// Ideally, we'd attach the top-border to the item that needs it. -// Unfortunately the border needs to go _above_ the row gap as currently -// set up, which means that some refactoring will be required to do this. -.ds-list-item:nth-child(-n+3) { // all but the last three items - border-bottom: $border-secondary; - margin-bottom: -1px; // cancel out the pixel we used for the border +.ds-list-borders { + border-top: $border-secondary; + padding-top: $item-line-height * 1px; - padding-bottom: 2px; + &.ds-list-full-width, + .ds-column-1 &, + .ds-column-2 &, + .ds-column-3 &, + .ds-column-4 & { + @include bottom-border-except-last-grid-row(1); + } + + &:not(.ds-list-full-width) { + // "2/3 width layout" + .ds-column-5 &, + .ds-column-6 &, + .ds-column-7 &, + .ds-column-8 & { + @include bottom-border-except-last-grid-row(2); + } + + // "Full width layout" + .ds-column-9 &, + .ds-column-10 &, + .ds-column-11 &, + .ds-column-12 & { + @include bottom-border-except-last-grid-row(3); + } + } +} + +.ds-list-full-width { + @include set-item-sizes(17, 24, $item-image-size * 2); } .ds-list-item { - // XXX see if we really want absolute units, maybe hoist somewhere central? - line-height: $item-line-height * 1px; - font-size: $item-font-size * 1px; - // reset some stuff from
  • . Should maybe be hoisted when we have better // regression detection? display: block; @@ -120,18 +174,17 @@ $item-line-height: 20; justify-content: space-between; } + .ds-list-item-excerpt { + color: var(--newtab-text-secondary-color); + margin-bottom: 8px; + } + .ds-list-item-info { - @include limit-visibile-lines(1, $item-line-height, $item-font-size); - - color: $grey-50; - - overflow: hidden; + color: var(--newtab-text-secondary-color); text-overflow: ellipsis; } .ds-list-item-title { - @include limit-visibile-lines(2, $item-line-height, $item-font-size); - margin-bottom: 8px; } @@ -141,15 +194,10 @@ $item-line-height: 20; } .ds-list-image { - $image-size: 72px; - @include image-as-background; - display: none; - height: $image-size; + height: $item-image-size; margin-inline-start: $item-font-size * 1px; - min-height: $image-size; - min-width: $image-size; - width: $image-size; + min-height: $item-image-size; } &:hover { diff --git a/browser/components/newtab/content-src/components/ErrorBoundary/_ErrorBoundary.scss b/browser/components/newtab/content-src/components/ErrorBoundary/_ErrorBoundary.scss index 26ce3e86e385..8607be7de43d 100644 --- a/browser/components/newtab/content-src/components/ErrorBoundary/_ErrorBoundary.scss +++ b/browser/components/newtab/content-src/components/ErrorBoundary/_ErrorBoundary.scss @@ -10,6 +10,10 @@ justify-items: center; line-height: $error-fallback-line-height; + &.borderless-error { + box-shadow: none; + } + a { color: var(--newtab-text-conditional-color); text-decoration: underline; diff --git a/browser/components/newtab/content-src/components/Search/Search.jsx b/browser/components/newtab/content-src/components/Search/Search.jsx index dc4eca0d68da..742db65811ec 100644 --- a/browser/components/newtab/content-src/components/Search/Search.jsx +++ b/browser/components/newtab/content-src/components/Search/Search.jsx @@ -146,7 +146,7 @@ export class _Search extends React.PureComponent { tabIndex="-1" title={this.props.intl.formatMessage({id: "search_web_placeholder"})}>
    {this.props.intl.formatMessage({id: "search_web_placeholder"})}
    -