Bug 1550883 - Add line-clamp ellipsis, anonymous images and bug fixes to Activity Stream r=r1cky

Differential Revision: https://phabricator.services.mozilla.com/D30729

--HG--
rename : browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSImage/DSImage.scss => browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSImage/_DSImage.scss
extra : moz-landing-system : lando
This commit is contained in:
Ed Lee 2019-05-10 22:33:17 +00:00
parent e22c732ca4
commit 11dad352f4
17 changed files with 170 additions and 165 deletions

View File

@ -18,6 +18,7 @@ export class _StartupOverlay extends React.PureComponent {
this.state = { this.state = {
emailInput: "", emailInput: "",
overlayRemoved: false, overlayRemoved: false,
deviceId: "",
flowId: "", flowId: "",
flowBeginTime: 0, flowBeginTime: 0,
}; };
@ -31,8 +32,8 @@ export class _StartupOverlay extends React.PureComponent {
const fxaParams = "entrypoint=activity-stream-firstrun&form_type=email"; const fxaParams = "entrypoint=activity-stream-firstrun&form_type=email";
const response = await fetch(`${this.props.fxa_endpoint}/metrics-flow?${fxaParams}&${this.utmParams}`, {credentials: "omit"}); const response = await fetch(`${this.props.fxa_endpoint}/metrics-flow?${fxaParams}&${this.utmParams}`, {credentials: "omit"});
if (response.status === 200) { if (response.status === 200) {
const {flowId, flowBeginTime} = await response.json(); const {deviceId, flowId, flowBeginTime} = await response.json();
this.setState({flowId, flowBeginTime}); this.setState({deviceId, flowId, flowBeginTime});
} else { } else {
this.props.dispatch(ac.OnlyToMain({type: at.TELEMETRY_UNDESIRED_EVENT, data: {event: "FXA_METRICS_FETCH_ERROR", value: response.status}})); this.props.dispatch(ac.OnlyToMain({type: at.TELEMETRY_UNDESIRED_EVENT, data: {event: "FXA_METRICS_FETCH_ERROR", value: response.status}}));
} }
@ -132,6 +133,7 @@ export class _StartupOverlay extends React.PureComponent {
<input name="utm_campaign" type="hidden" value="firstrun" /> <input name="utm_campaign" type="hidden" value="firstrun" />
<input name="utm_medium" type="hidden" value="referral" /> <input name="utm_medium" type="hidden" value="referral" />
<input name="utm_term" type="hidden" value="trailhead-control" /> <input name="utm_term" type="hidden" value="trailhead-control" />
<input name="device_id" type="hidden" value={this.state.deviceId} />
<input name="flow_id" type="hidden" value={this.state.flowId} /> <input name="flow_id" type="hidden" value={this.state.flowId} />
<input name="flow_begin_time" type="hidden" value={this.state.flowBeginTime} /> <input name="flow_begin_time" type="hidden" value={this.state.flowBeginTime} />
<span className="error">{this.props.intl.formatMessage({id: "firstrun_invalid_input"})}</span> <span className="error">{this.props.intl.formatMessage({id: "firstrun_invalid_input"})}</span>

View File

@ -38,10 +38,12 @@ export class _Trailhead extends React.PureComponent {
isModalOpen: true, isModalOpen: true,
showCardPanel: true, showCardPanel: true,
showCards: false, showCards: false,
// The params below are for FxA metrics
deviceId: "",
flowId: "", flowId: "",
flowBeginTime: 0, flowBeginTime: 0,
}; };
this.didFetch = false; this.fxaMetricsInitialized = false;
} }
get dialog() { get dialog() {
@ -55,15 +57,15 @@ export class _Trailhead extends React.PureComponent {
link.rel = "localization"; link.rel = "localization";
}); });
if (this.props.fxaEndpoint && !this.didFetch) { if (this.props.fxaEndpoint && !this.fxaMetricsInitialized) {
try { try {
this.didFetch = true; this.fxaMetricsInitialized = true;
const url = new URL(`${this.props.fxaEndpoint}/metrics-flow?entrypoint=activity-stream-firstrun&form_type=email`); const url = new URL(`${this.props.fxaEndpoint}/metrics-flow?entrypoint=activity-stream-firstrun&form_type=email`);
this.addUtmParams(url); this.addUtmParams(url);
const response = await fetch(url, {credentials: "omit"}); const response = await fetch(url, {credentials: "omit"});
if (response.status === 200) { if (response.status === 200) {
const {flowId, flowBeginTime} = await response.json(); const {deviceId, flowId, flowBeginTime} = await response.json();
this.setState({flowId, flowBeginTime}); this.setState({deviceId, flowId, flowBeginTime});
} else { } else {
this.props.dispatch(ac.OnlyToMain({type: at.TELEMETRY_UNDESIRED_EVENT, data: {event: "FXA_METRICS_FETCH_ERROR", value: response.status}})); this.props.dispatch(ac.OnlyToMain({type: at.TELEMETRY_UNDESIRED_EVENT, data: {event: "FXA_METRICS_FETCH_ERROR", value: response.status}}));
} }
@ -194,6 +196,7 @@ export class _Trailhead extends React.PureComponent {
this.addUtmParams(url, true); this.addUtmParams(url, true);
if (action.addFlowParams) { if (action.addFlowParams) {
url.searchParams.append("device_id", this.state.deviceId);
url.searchParams.append("flow_id", this.state.flowId); url.searchParams.append("flow_id", this.state.flowId);
url.searchParams.append("flow_begin_time", this.state.flowBeginTime); url.searchParams.append("flow_begin_time", this.state.flowBeginTime);
} }
@ -232,9 +235,9 @@ export class _Trailhead extends React.PureComponent {
{this.getStringValue(content.learn.text)} {this.getStringValue(content.learn.text)}
</a> </a>
</div> </div>
<div className="trailheadForm"> <div role="group" aria-labelledby="joinFormHeader" aria-describedby="joinFormBody" className="trailheadForm">
<h3 data-l10n-id={content.form.title.string_id}>{this.getStringValue(content.form.title)}</h3> <h3 id="joinFormHeader" data-l10n-id={content.form.title.string_id}>{this.getStringValue(content.form.title)}</h3>
<p data-l10n-id={content.form.text.string_id}>{this.getStringValue(content.form.text)}</p> <p id="joinFormBody" data-l10n-id={content.form.text.string_id}>{this.getStringValue(content.form.text)}</p>
<form method="get" action={this.props.fxaEndpoint} target="_blank" rel="noopener noreferrer" onSubmit={this.onSubmit}> <form method="get" action={this.props.fxaEndpoint} target="_blank" rel="noopener noreferrer" onSubmit={this.onSubmit}>
<input name="service" type="hidden" value="sync" /> <input name="service" type="hidden" value="sync" />
<input name="action" type="hidden" value="email" /> <input name="action" type="hidden" value="email" />
@ -243,6 +246,7 @@ export class _Trailhead extends React.PureComponent {
<input name="utm_source" type="hidden" value="activity-stream" /> <input name="utm_source" type="hidden" value="activity-stream" />
<input name="utm_campaign" type="hidden" value="firstrun" /> <input name="utm_campaign" type="hidden" value="firstrun" />
<input name="utm_term" type="hidden" value={utm_term} /> <input name="utm_term" type="hidden" value={utm_term} />
<input name="device_id" type="hidden" value={this.state.deviceId} />
<input name="flow_id" type="hidden" value={this.state.flowId} /> <input name="flow_id" type="hidden" value={this.state.flowId} />
<input name="flow_begin_time" type="hidden" value={this.state.flowBeginTime} /> <input name="flow_begin_time" type="hidden" value={this.state.flowBeginTime} />
<input name="style" type="hidden" value="trailhead" /> <input name="style" type="hidden" value="trailhead" />

View File

@ -402,7 +402,7 @@
.inline-onboarding { .inline-onboarding {
&.activity-stream.welcome { &.activity-stream.welcome {
overflow: scroll; overflow-y: scroll;
} }
.modalOverlayInner { .modalOverlayInner {

View File

@ -78,10 +78,15 @@ export class DSImage extends React.PureComponent {
this.state.containerHeight * 2 this.state.containerHeight * 2
); );
img = (<img onError={this.onOptimizedImageError} src={source} srcSet={`${source2x} 2x`} />); img = (<img crossOrigin="anonymous"
onError={this.onOptimizedImageError}
src={source}
srcSet={`${source2x} 2x`} />);
} }
} else if (!this.state.nonOptimizedImageFailed) { } else if (!this.state.nonOptimizedImageFailed) {
img = (<img onError={this.onNonOptimizedImageError} src={this.props.source} />); img = (<img crossOrigin="anonymous"
onError={this.onNonOptimizedImageError}
src={this.props.source} />);
} else { } else {
// Remove the img element if both sources fail. Render a placeholder instead. // Remove the img element if both sources fail. Render a placeholder instead.
img = (<div className="broken-image" />); img = (<div className="broken-image" />);

View File

@ -10,7 +10,10 @@
// Note: lineHeight and fontSize should be unitless but can be derived from pixel values // Note: lineHeight and fontSize should be unitless but can be derived from pixel values
@mixin limit-visibile-lines($line-count, $line-height, $font-size) { @mixin limit-visibile-lines($line-count, $line-height, $font-size) {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: $font-size * 1px; font-size: $font-size * 1px;
-webkit-line-clamp: $line-count;
line-height: $line-height * 1px; line-height: $line-height * 1px;
max-height: 1em * $line-count * $line-height / $font-size; max-height: 1em * $line-count * $line-height / $font-size;
overflow: hidden; overflow: hidden;

View File

@ -1946,7 +1946,10 @@ main {
.ds-column-10 .ds-card-grid.ds-card-grid-divisible-by-4 .title, .ds-column-10 .ds-card-grid.ds-card-grid-divisible-by-4 .title,
.ds-column-11 .ds-card-grid.ds-card-grid-divisible-by-4 .title, .ds-column-11 .ds-card-grid.ds-card-grid-divisible-by-4 .title,
.ds-column-12 .ds-card-grid.ds-card-grid-divisible-by-4 .title { .ds-column-12 .ds-card-grid.ds-card-grid-divisible-by-4 .title {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 15px; font-size: 15px;
-webkit-line-clamp: 3;
line-height: 20px; line-height: 20px;
max-height: 4em; max-height: 4em;
overflow: hidden; } overflow: hidden; }
@ -1961,7 +1964,10 @@ main {
line-height: 1.538; line-height: 1.538;
margin: 8px 0; } margin: 8px 0; }
.ds-hero .excerpt { .ds-hero .excerpt {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 14px; font-size: 14px;
-webkit-line-clamp: 3;
line-height: 20px; line-height: 20px;
max-height: 4.28571em; max-height: 4.28571em;
overflow: hidden; overflow: hidden;
@ -2030,7 +2036,10 @@ main {
flex-direction: column; flex-direction: column;
justify-content: space-between; } justify-content: space-between; }
.ds-hero .wrapper .meta header { .ds-hero .wrapper .meta header {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 22px; font-size: 22px;
-webkit-line-clamp: 4;
line-height: 28px; line-height: 28px;
max-height: 5.09091em; max-height: 5.09091em;
overflow: hidden; overflow: hidden;
@ -2150,7 +2159,10 @@ main {
.ds-column-10 .ds-hero .wrapper .meta header, .ds-column-10 .ds-hero .wrapper .meta header,
.ds-column-11 .ds-hero .wrapper .meta header, .ds-column-11 .ds-hero .wrapper .meta header,
.ds-column-12 .ds-hero .wrapper .meta header { .ds-column-12 .ds-hero .wrapper .meta header {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 22px; font-size: 22px;
-webkit-line-clamp: 3;
line-height: 28px; line-height: 28px;
max-height: 3.81818em; max-height: 3.81818em;
overflow: hidden; } overflow: hidden; }
@ -2186,7 +2198,10 @@ main {
.ds-column-10 .ds-hero .cards .ds-card .title, .ds-column-10 .ds-hero .cards .ds-card .title,
.ds-column-11 .ds-hero .cards .ds-card .title, .ds-column-11 .ds-hero .cards .ds-card .title,
.ds-column-12 .ds-hero .cards .ds-card .title { .ds-column-12 .ds-hero .cards .ds-card .title {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 14px; font-size: 14px;
-webkit-line-clamp: 3;
line-height: 20px; line-height: 20px;
max-height: 4.28571em; max-height: 4.28571em;
overflow: hidden; } overflow: hidden; }
@ -2215,7 +2230,10 @@ main {
line-height: 20px; line-height: 20px;
position: relative; } position: relative; }
.ds-list:not(.ds-list-full-width) .ds-list-item-title { .ds-list:not(.ds-list-full-width) .ds-list-item-title {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 14px; font-size: 14px;
-webkit-line-clamp: 3;
line-height: 20px; line-height: 20px;
max-height: 4.28571em; max-height: 4.28571em;
overflow: hidden; } overflow: hidden; }
@ -2329,7 +2347,10 @@ main {
position: relative; } position: relative; }
.ds-list-full-width .ds-list-item-title { .ds-list-full-width .ds-list-item-title {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 17px; font-size: 17px;
-webkit-line-clamp: 3;
line-height: 24px; line-height: 24px;
max-height: 4.23529em; max-height: 4.23529em;
overflow: hidden; } overflow: hidden; }
@ -2356,7 +2377,10 @@ main {
justify-content: space-between; justify-content: space-between;
height: 100%; } height: 100%; }
.ds-list-item .ds-list-item-excerpt { .ds-list-item .ds-list-item-excerpt {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 14px; font-size: 14px;
-webkit-line-clamp: 2;
line-height: 20px; line-height: 20px;
max-height: 2.85714em; max-height: 2.85714em;
overflow: hidden; overflow: hidden;
@ -2368,7 +2392,10 @@ main {
margin: 0; } margin: 0; }
.ds-list-item .ds-list-item-info, .ds-list-item .ds-list-item-info,
.ds-list-item .ds-list-item-context { .ds-list-item .ds-list-item-context {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 14px; font-size: 14px;
-webkit-line-clamp: 1;
line-height: 20px; line-height: 20px;
max-height: 1.42857em; max-height: 1.42857em;
overflow: hidden; overflow: hidden;
@ -2636,13 +2663,19 @@ main {
flex-grow: 1; flex-grow: 1;
margin: 0 0 12px; } margin: 0 0 12px; }
.ds-card .meta .title { .ds-card .meta .title {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 17px; font-size: 17px;
-webkit-line-clamp: 3;
line-height: 24px; line-height: 24px;
max-height: 4.23529em; max-height: 4.23529em;
overflow: hidden; overflow: hidden;
font-weight: 600; } font-weight: 600; }
.ds-card .meta .excerpt { .ds-card .meta .excerpt {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 14px; font-size: 14px;
-webkit-line-clamp: 3;
line-height: 20px; line-height: 20px;
max-height: 4.28571em; max-height: 4.28571em;
overflow: hidden; } overflow: hidden; }
@ -3976,7 +4009,7 @@ a.firstrun-link {
text-align: center; } text-align: center; }
.inline-onboarding.activity-stream.welcome { .inline-onboarding.activity-stream.welcome {
overflow: scroll; } overflow-y: scroll; }
.inline-onboarding .modalOverlayInner { .inline-onboarding .modalOverlayInner {
position: absolute; } position: absolute; }

View File

@ -1949,7 +1949,10 @@ main {
.ds-column-10 .ds-card-grid.ds-card-grid-divisible-by-4 .title, .ds-column-10 .ds-card-grid.ds-card-grid-divisible-by-4 .title,
.ds-column-11 .ds-card-grid.ds-card-grid-divisible-by-4 .title, .ds-column-11 .ds-card-grid.ds-card-grid-divisible-by-4 .title,
.ds-column-12 .ds-card-grid.ds-card-grid-divisible-by-4 .title { .ds-column-12 .ds-card-grid.ds-card-grid-divisible-by-4 .title {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 15px; font-size: 15px;
-webkit-line-clamp: 3;
line-height: 20px; line-height: 20px;
max-height: 4em; max-height: 4em;
overflow: hidden; } overflow: hidden; }
@ -1964,7 +1967,10 @@ main {
line-height: 1.538; line-height: 1.538;
margin: 8px 0; } margin: 8px 0; }
.ds-hero .excerpt { .ds-hero .excerpt {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 14px; font-size: 14px;
-webkit-line-clamp: 3;
line-height: 20px; line-height: 20px;
max-height: 4.28571em; max-height: 4.28571em;
overflow: hidden; overflow: hidden;
@ -2033,7 +2039,10 @@ main {
flex-direction: column; flex-direction: column;
justify-content: space-between; } justify-content: space-between; }
.ds-hero .wrapper .meta header { .ds-hero .wrapper .meta header {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 22px; font-size: 22px;
-webkit-line-clamp: 4;
line-height: 28px; line-height: 28px;
max-height: 5.09091em; max-height: 5.09091em;
overflow: hidden; overflow: hidden;
@ -2153,7 +2162,10 @@ main {
.ds-column-10 .ds-hero .wrapper .meta header, .ds-column-10 .ds-hero .wrapper .meta header,
.ds-column-11 .ds-hero .wrapper .meta header, .ds-column-11 .ds-hero .wrapper .meta header,
.ds-column-12 .ds-hero .wrapper .meta header { .ds-column-12 .ds-hero .wrapper .meta header {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 22px; font-size: 22px;
-webkit-line-clamp: 3;
line-height: 28px; line-height: 28px;
max-height: 3.81818em; max-height: 3.81818em;
overflow: hidden; } overflow: hidden; }
@ -2189,7 +2201,10 @@ main {
.ds-column-10 .ds-hero .cards .ds-card .title, .ds-column-10 .ds-hero .cards .ds-card .title,
.ds-column-11 .ds-hero .cards .ds-card .title, .ds-column-11 .ds-hero .cards .ds-card .title,
.ds-column-12 .ds-hero .cards .ds-card .title { .ds-column-12 .ds-hero .cards .ds-card .title {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 14px; font-size: 14px;
-webkit-line-clamp: 3;
line-height: 20px; line-height: 20px;
max-height: 4.28571em; max-height: 4.28571em;
overflow: hidden; } overflow: hidden; }
@ -2218,7 +2233,10 @@ main {
line-height: 20px; line-height: 20px;
position: relative; } position: relative; }
.ds-list:not(.ds-list-full-width) .ds-list-item-title { .ds-list:not(.ds-list-full-width) .ds-list-item-title {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 14px; font-size: 14px;
-webkit-line-clamp: 3;
line-height: 20px; line-height: 20px;
max-height: 4.28571em; max-height: 4.28571em;
overflow: hidden; } overflow: hidden; }
@ -2332,7 +2350,10 @@ main {
position: relative; } position: relative; }
.ds-list-full-width .ds-list-item-title { .ds-list-full-width .ds-list-item-title {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 17px; font-size: 17px;
-webkit-line-clamp: 3;
line-height: 24px; line-height: 24px;
max-height: 4.23529em; max-height: 4.23529em;
overflow: hidden; } overflow: hidden; }
@ -2359,7 +2380,10 @@ main {
justify-content: space-between; justify-content: space-between;
height: 100%; } height: 100%; }
.ds-list-item .ds-list-item-excerpt { .ds-list-item .ds-list-item-excerpt {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 14px; font-size: 14px;
-webkit-line-clamp: 2;
line-height: 20px; line-height: 20px;
max-height: 2.85714em; max-height: 2.85714em;
overflow: hidden; overflow: hidden;
@ -2371,7 +2395,10 @@ main {
margin: 0; } margin: 0; }
.ds-list-item .ds-list-item-info, .ds-list-item .ds-list-item-info,
.ds-list-item .ds-list-item-context { .ds-list-item .ds-list-item-context {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 14px; font-size: 14px;
-webkit-line-clamp: 1;
line-height: 20px; line-height: 20px;
max-height: 1.42857em; max-height: 1.42857em;
overflow: hidden; overflow: hidden;
@ -2639,13 +2666,19 @@ main {
flex-grow: 1; flex-grow: 1;
margin: 0 0 12px; } margin: 0 0 12px; }
.ds-card .meta .title { .ds-card .meta .title {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 17px; font-size: 17px;
-webkit-line-clamp: 3;
line-height: 24px; line-height: 24px;
max-height: 4.23529em; max-height: 4.23529em;
overflow: hidden; overflow: hidden;
font-weight: 600; } font-weight: 600; }
.ds-card .meta .excerpt { .ds-card .meta .excerpt {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 14px; font-size: 14px;
-webkit-line-clamp: 3;
line-height: 20px; line-height: 20px;
max-height: 4.28571em; max-height: 4.28571em;
overflow: hidden; } overflow: hidden; }
@ -3979,7 +4012,7 @@ a.firstrun-link {
text-align: center; } text-align: center; }
.inline-onboarding.activity-stream.welcome { .inline-onboarding.activity-stream.welcome {
overflow: scroll; } overflow-y: scroll; }
.inline-onboarding .modalOverlayInner { .inline-onboarding .modalOverlayInner {
position: absolute; } position: absolute; }

View File

@ -1946,7 +1946,10 @@ main {
.ds-column-10 .ds-card-grid.ds-card-grid-divisible-by-4 .title, .ds-column-10 .ds-card-grid.ds-card-grid-divisible-by-4 .title,
.ds-column-11 .ds-card-grid.ds-card-grid-divisible-by-4 .title, .ds-column-11 .ds-card-grid.ds-card-grid-divisible-by-4 .title,
.ds-column-12 .ds-card-grid.ds-card-grid-divisible-by-4 .title { .ds-column-12 .ds-card-grid.ds-card-grid-divisible-by-4 .title {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 15px; font-size: 15px;
-webkit-line-clamp: 3;
line-height: 20px; line-height: 20px;
max-height: 4em; max-height: 4em;
overflow: hidden; } overflow: hidden; }
@ -1961,7 +1964,10 @@ main {
line-height: 1.538; line-height: 1.538;
margin: 8px 0; } margin: 8px 0; }
.ds-hero .excerpt { .ds-hero .excerpt {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 14px; font-size: 14px;
-webkit-line-clamp: 3;
line-height: 20px; line-height: 20px;
max-height: 4.28571em; max-height: 4.28571em;
overflow: hidden; overflow: hidden;
@ -2030,7 +2036,10 @@ main {
flex-direction: column; flex-direction: column;
justify-content: space-between; } justify-content: space-between; }
.ds-hero .wrapper .meta header { .ds-hero .wrapper .meta header {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 22px; font-size: 22px;
-webkit-line-clamp: 4;
line-height: 28px; line-height: 28px;
max-height: 5.09091em; max-height: 5.09091em;
overflow: hidden; overflow: hidden;
@ -2150,7 +2159,10 @@ main {
.ds-column-10 .ds-hero .wrapper .meta header, .ds-column-10 .ds-hero .wrapper .meta header,
.ds-column-11 .ds-hero .wrapper .meta header, .ds-column-11 .ds-hero .wrapper .meta header,
.ds-column-12 .ds-hero .wrapper .meta header { .ds-column-12 .ds-hero .wrapper .meta header {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 22px; font-size: 22px;
-webkit-line-clamp: 3;
line-height: 28px; line-height: 28px;
max-height: 3.81818em; max-height: 3.81818em;
overflow: hidden; } overflow: hidden; }
@ -2186,7 +2198,10 @@ main {
.ds-column-10 .ds-hero .cards .ds-card .title, .ds-column-10 .ds-hero .cards .ds-card .title,
.ds-column-11 .ds-hero .cards .ds-card .title, .ds-column-11 .ds-hero .cards .ds-card .title,
.ds-column-12 .ds-hero .cards .ds-card .title { .ds-column-12 .ds-hero .cards .ds-card .title {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 14px; font-size: 14px;
-webkit-line-clamp: 3;
line-height: 20px; line-height: 20px;
max-height: 4.28571em; max-height: 4.28571em;
overflow: hidden; } overflow: hidden; }
@ -2215,7 +2230,10 @@ main {
line-height: 20px; line-height: 20px;
position: relative; } position: relative; }
.ds-list:not(.ds-list-full-width) .ds-list-item-title { .ds-list:not(.ds-list-full-width) .ds-list-item-title {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 14px; font-size: 14px;
-webkit-line-clamp: 3;
line-height: 20px; line-height: 20px;
max-height: 4.28571em; max-height: 4.28571em;
overflow: hidden; } overflow: hidden; }
@ -2329,7 +2347,10 @@ main {
position: relative; } position: relative; }
.ds-list-full-width .ds-list-item-title { .ds-list-full-width .ds-list-item-title {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 17px; font-size: 17px;
-webkit-line-clamp: 3;
line-height: 24px; line-height: 24px;
max-height: 4.23529em; max-height: 4.23529em;
overflow: hidden; } overflow: hidden; }
@ -2356,7 +2377,10 @@ main {
justify-content: space-between; justify-content: space-between;
height: 100%; } height: 100%; }
.ds-list-item .ds-list-item-excerpt { .ds-list-item .ds-list-item-excerpt {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 14px; font-size: 14px;
-webkit-line-clamp: 2;
line-height: 20px; line-height: 20px;
max-height: 2.85714em; max-height: 2.85714em;
overflow: hidden; overflow: hidden;
@ -2368,7 +2392,10 @@ main {
margin: 0; } margin: 0; }
.ds-list-item .ds-list-item-info, .ds-list-item .ds-list-item-info,
.ds-list-item .ds-list-item-context { .ds-list-item .ds-list-item-context {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 14px; font-size: 14px;
-webkit-line-clamp: 1;
line-height: 20px; line-height: 20px;
max-height: 1.42857em; max-height: 1.42857em;
overflow: hidden; overflow: hidden;
@ -2636,13 +2663,19 @@ main {
flex-grow: 1; flex-grow: 1;
margin: 0 0 12px; } margin: 0 0 12px; }
.ds-card .meta .title { .ds-card .meta .title {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 17px; font-size: 17px;
-webkit-line-clamp: 3;
line-height: 24px; line-height: 24px;
max-height: 4.23529em; max-height: 4.23529em;
overflow: hidden; overflow: hidden;
font-weight: 600; } font-weight: 600; }
.ds-card .meta .excerpt { .ds-card .meta .excerpt {
-webkit-box-orient: vertical;
display: -webkit-box;
font-size: 14px; font-size: 14px;
-webkit-line-clamp: 3;
line-height: 20px; line-height: 20px;
max-height: 4.28571em; max-height: 4.28571em;
overflow: hidden; } overflow: hidden; }
@ -3976,7 +4009,7 @@ a.firstrun-link {
text-align: center; } text-align: center; }
.inline-onboarding.activity-stream.welcome { .inline-onboarding.activity-stream.welcome {
overflow: scroll; } overflow-y: scroll; }
.inline-onboarding .modalOverlayInner { .inline-onboarding .modalOverlayInner {
position: absolute; } position: absolute; }

View File

@ -2996,6 +2996,7 @@ class _StartupOverlay extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureC
this.state = { this.state = {
emailInput: "", emailInput: "",
overlayRemoved: false, overlayRemoved: false,
deviceId: "",
flowId: "", flowId: "",
flowBeginTime: 0 flowBeginTime: 0
}; };
@ -3013,10 +3014,12 @@ class _StartupOverlay extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureC
if (response.status === 200) { if (response.status === 200) {
const { const {
deviceId,
flowId, flowId,
flowBeginTime flowBeginTime
} = await response.json(); } = await response.json();
this.setState({ this.setState({
deviceId,
flowId, flowId,
flowBeginTime flowBeginTime
}); });
@ -3212,6 +3215,10 @@ class _StartupOverlay extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureC
name: "utm_term", name: "utm_term",
type: "hidden", type: "hidden",
value: "trailhead-control" value: "trailhead-control"
}), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
name: "device_id",
type: "hidden",
value: this.state.deviceId
}), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", { }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
name: "flow_id", name: "flow_id",
type: "hidden", type: "hidden",
@ -3310,10 +3317,12 @@ class _Trailhead extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureCompon
isModalOpen: true, isModalOpen: true,
showCardPanel: true, showCardPanel: true,
showCards: false, showCards: false,
// The params below are for FxA metrics
deviceId: "",
flowId: "", flowId: "",
flowBeginTime: 0 flowBeginTime: 0
}; };
this.didFetch = false; this.fxaMetricsInitialized = false;
} }
get dialog() { get dialog() {
@ -3327,9 +3336,9 @@ class _Trailhead extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureCompon
link.rel = "localization"; link.rel = "localization";
}); });
if (this.props.fxaEndpoint && !this.didFetch) { if (this.props.fxaEndpoint && !this.fxaMetricsInitialized) {
try { try {
this.didFetch = true; this.fxaMetricsInitialized = true;
const url = new URL(`${this.props.fxaEndpoint}/metrics-flow?entrypoint=activity-stream-firstrun&form_type=email`); const url = new URL(`${this.props.fxaEndpoint}/metrics-flow?entrypoint=activity-stream-firstrun&form_type=email`);
this.addUtmParams(url); this.addUtmParams(url);
const response = await fetch(url, { const response = await fetch(url, {
@ -3338,10 +3347,12 @@ class _Trailhead extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureCompon
if (response.status === 200) { if (response.status === 200) {
const { const {
deviceId,
flowId, flowId,
flowBeginTime flowBeginTime
} = await response.json(); } = await response.json();
this.setState({ this.setState({
deviceId,
flowId, flowId,
flowBeginTime flowBeginTime
}); });
@ -3508,6 +3519,7 @@ class _Trailhead extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureCompon
this.addUtmParams(url, true); this.addUtmParams(url, true);
if (action.addFlowParams) { if (action.addFlowParams) {
url.searchParams.append("device_id", this.state.deviceId);
url.searchParams.append("flow_id", this.state.flowId); url.searchParams.append("flow_id", this.state.flowId);
url.searchParams.append("flow_begin_time", this.state.flowBeginTime); url.searchParams.append("flow_begin_time", this.state.flowBeginTime);
} }
@ -3564,10 +3576,15 @@ class _Trailhead extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureCompon
target: "_blank", target: "_blank",
rel: "noopener noreferrer" rel: "noopener noreferrer"
}, this.getStringValue(content.learn.text))), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", { }, this.getStringValue(content.learn.text))), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
role: "group",
"aria-labelledby": "joinFormHeader",
"aria-describedby": "joinFormBody",
className: "trailheadForm" className: "trailheadForm"
}, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h3", { }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h3", {
id: "joinFormHeader",
"data-l10n-id": content.form.title.string_id "data-l10n-id": content.form.title.string_id
}, this.getStringValue(content.form.title)), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("p", { }, this.getStringValue(content.form.title)), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("p", {
id: "joinFormBody",
"data-l10n-id": content.form.text.string_id "data-l10n-id": content.form.text.string_id
}, this.getStringValue(content.form.text)), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("form", { }, this.getStringValue(content.form.text)), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("form", {
method: "get", method: "get",
@ -3603,6 +3620,10 @@ class _Trailhead extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureCompon
name: "utm_term", name: "utm_term",
type: "hidden", type: "hidden",
value: utm_term value: utm_term
}), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", {
name: "device_id",
type: "hidden",
value: this.state.deviceId
}), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", { }), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", {
name: "flow_id", name: "flow_id",
type: "hidden", type: "hidden",
@ -7645,6 +7666,7 @@ class DSImage_DSImage extends external_React_default.a.PureComponent {
source = this.reformatImageURL(baseSource, this.state.containerWidth, this.state.containerHeight); source = this.reformatImageURL(baseSource, this.state.containerWidth, this.state.containerHeight);
source2x = this.reformatImageURL(baseSource, this.state.containerWidth * 2, this.state.containerHeight * 2); source2x = this.reformatImageURL(baseSource, this.state.containerWidth * 2, this.state.containerHeight * 2);
img = external_React_default.a.createElement("img", { img = external_React_default.a.createElement("img", {
crossOrigin: "anonymous",
onError: this.onOptimizedImageError, onError: this.onOptimizedImageError,
src: source, src: source,
srcSet: `${source2x} 2x` srcSet: `${source2x} 2x`
@ -7652,6 +7674,7 @@ class DSImage_DSImage extends external_React_default.a.PureComponent {
} }
} else if (!this.state.nonOptimizedImageFailed) { } else if (!this.state.nonOptimizedImageFailed) {
img = external_React_default.a.createElement("img", { img = external_React_default.a.createElement("img", {
crossOrigin: "anonymous",
onError: this.onNonOptimizedImageError, onError: this.onNonOptimizedImageError,
src: this.props.source src: this.props.source
}); });

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

View File

@ -1,142 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
## The following feature names must be treated as a brand, and kept in English.
## They cannot be:
## - Declined to adapt to grammatical case.
## - Transliterated.
## - Translated.
-facebook-container-brand-name = Facebook Container
-lockwise-brand-name = Firefox Lockwise
-monitor-brand-name = Firefox Monitor
-pocket-brand-name = Pocket
-send-brand-name = Firefox Send
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
## UI strings for the simplified onboarding modal
onboarding-button-label-learn-more = Learn More
onboarding-button-label-try-now = Try It Now
onboarding-button-label-get-started = Get Started
onboarding-welcome-header = Welcome to { -brand-short-name }
onboarding-welcome-body = Youve got the browser.<br/>Meet the rest of { -brand-product-name }.
onboarding-welcome-learn-more = Learn more about the benefits.
onboarding-join-form-header = Join { -brand-product-name }
onboarding-join-form-body = Enter your email address to get started.
onboarding-join-form-email =
.placeholder = Enter email
onboarding-join-form-email-error = Valid email required
onboarding-join-form-legal = By proceeding, you agree to the <a data-l10n-name="terms">Terms of Service</a> and <a data-l10n-name="privacy">Privacy Notice</a>.
onboarding-join-form-continue = Continue
onboarding-start-browsing-button-label = Start Browsing
## These are individual benefit messages shown with an image, title and
## description.
onboarding-benefit-products-title = Useful Products
onboarding-benefit-products-text = Get things done with a family of tools that respects your privacy across your devices.
onboarding-benefit-knowledge-title = Practical Knowledge
onboarding-benefit-knowledge-text = Learn everything you need to know to stay smarter and safer online.
onboarding-benefit-privacy-title = True Privacy
# "Personal Data Promise" should be treated as a brand and refers to a concept
# shown elsewhere to the user: "The Firefox Personal Data Promise is the way we
# honor your data in everything we make and do. We take less data. We keep it
# safe. And we make sure that we are transparent about how we use it."
onboarding-benefit-privacy-text = Everything we do honors our Personal Data Promise: Take less. Keep it safe. No secrets.
## These strings belong to the individual onboarding messages.
## Each message has a title and a description of what the browser feature is.
## Each message also has an associated button for the user to try the feature.
## The string for the button is found above, in the UI strings section
onboarding-private-browsing-title = Private Browsing
onboarding-private-browsing-text = Browse by yourself. Private Browsing with Content Blocking blocks online trackers that follow you around the web.
onboarding-screenshots-title = Screenshots
onboarding-screenshots-text = Take, save and share screenshots - without leaving { -brand-short-name }. Capture a region or an entire page as you browse. Then save to the web for easy access and sharing.
onboarding-addons-title = Add-ons
onboarding-addons-text = Add even more features that make { -brand-short-name } work harder for you. Compare prices, check the weather or express your personality with a custom theme.
onboarding-ghostery-title = Ghostery
onboarding-ghostery-text = Browse faster, smarter, or safer with extensions like Ghostery, which lets you block annoying ads.
# Note: "Sync" in this case is a generic verb, as in "to synchronize"
onboarding-fxa-title = Sync
onboarding-fxa-text = Sign up for a { -fxaccount-brand-name } and sync your bookmarks, passwords, and open tabs everywhere you use { -brand-short-name }.
onboarding-tracking-protection-title = Control How Youre Tracked
onboarding-tracking-protection-text = Dont like when ads follow you around? { -brand-short-name } helps you control how advertisers track your activity online.
onboarding-tracking-protection-button = { PLATFORM() ->
[windows] Update Options
*[other] Update Preferences
}
onboarding-data-sync-title = Take Your Settings with You
# "Sync" is short for synchronize.
onboarding-data-sync-text = Sync your bookmarks and passwords everywhere you use { -brand-product-name }.
onboarding-data-sync-button = Turn on { -sync-brand-short-name }
onboarding-firefox-monitor-title = Stay Alert to Data Breaches
onboarding-firefox-monitor-text = { -monitor-brand-name } monitors if your email has appeared in a data breach and alerts you if it appears in a new breach.
onboarding-firefox-monitor-button = Sign up for Alerts
onboarding-private-browsing-title = Browse Privately
onboarding-private-browsing-text = Private Browsing clears your search and browsing history to keep it secret from anyone who uses your computer.
onboarding-private-browsing-button = Open a Private Window
onboarding-firefox-send-title = Keep Your Shared Files Private
onboarding-firefox-send-text = { -send-brand-name } protects the files you share with end-to-end encryption and a link that automatically expires.
onboarding-firefox-send-button = Try { -send-brand-name }
onboarding-mobile-phone-title = Get { -brand-product-name } on Your Phone
onboarding-mobile-phone-text = Download { -brand-product-name } for iOS or Android and sync your data across devices.
# "Mobile" is short for mobile/cellular phone, "Browser" is short for web
# browser.
onboarding-mobile-phone-button = Download Mobile Browser
onboarding-privacy-right-title = Privacy is Your Right
onboarding-privacy-right-text = { -brand-short-name } treats your data with respect by taking less, protecting it, and being clear about how we use it.
onboarding-privacy-right-button = Learn More
onboarding-send-tabs-title = Instantly Send Yourself Tabs
# "Send Tabs" refers to "Send Tab to Device" feature that appears when opening a
# tab's context menu.
onboarding-send-tabs-text = Send Tabs instantly shares pages between your devices without having to copy, paste, or leave the browser.
onboarding-send-tabs-button = Start Using Send Tabs
onboarding-pocket-anywhere-title = Read and Listen Anywhere
# "downtime" refers to the user's free/spare time.
onboarding-pocket-anywhere-text = { -pocket-brand-name } saves your favorite stories so you can read, listen, and watch during your downtime, even if youre offline.
onboarding-pocket-anywhere-button = Try { -pocket-brand-name }
onboarding-lockwise-passwords-title = Take Your Passwords Everywhere
# "many places" conveys that Lockwise is available outside of Firefox.
onboarding-lockwise-passwords-text = { -lockwise-brand-name } saves your passwords in a secure place so you can easily log into your accounts.
onboarding-lockwise-passwords-button = Get { -lockwise-brand-name }
onboarding-facebook-container-title = Set Boundaries with Facebook
onboarding-facebook-container-text = { -facebook-container-brand-name } keeps your Facebook identity separate from everything else, making it harder to track you across the web.
onboarding-facebook-container-button = Add the Extension
## Message strings belonging to the Return to AMO flow
return-to-amo-sub-header = Great, youve got { -brand-short-name }
# <icon></icon> will be replaced with the icon belonging to the extension
#
# Variables:
# $addon-name (String) - Name of the add-on
return-to-amo-addon-header = Now lets get you <icon></icon><b>{ $addon-name }.</b>
return-to-amo-extension-button = Add the Extension
return-to-amo-get-started-button = Get Started with { -brand-short-name }

View File

@ -485,6 +485,16 @@ const OnboardingMessageProvider = {
} catch (e) { } catch (e) {
continue; continue;
} }
// We know we want to show this message, so translate message strings
const [primary_button_string, title_string, text_string] = await L10N.formatMessages([
{id: msg.content.primary_button.label.string_id},
{id: msg.content.title.string_id},
{id: msg.content.text.string_id, args: msg.content.text.args},
]);
translatedMessage.content.primary_button.label = primary_button_string.value;
translatedMessage.content.title = title_string.value;
translatedMessage.content.text = text_string.value;
} }
// Translate any secondary buttons separately // Translate any secondary buttons separately

View File

@ -192,7 +192,7 @@ section_menu_action_privacy_notice=Zásady ochrany osobních údajů
# firstrun of the browser, they give an introduction to Firefox and Sync. # firstrun of the browser, they give an introduction to Firefox and Sync.
firstrun_title=Vezměte si Firefox s sebou firstrun_title=Vezměte si Firefox s sebou
firstrun_content=Mějte své záložky, historii i uložená hesla s sebou na všech svých zařízeních. firstrun_content=Mějte své záložky, historii i uložená hesla s sebou na všech svých zařízeních.
firstrun_learn_more_link=Zjistěte více o účtech Firefoxu firstrun_learn_more_link=Zjistit více o účtech Firefoxu
# LOCALIZATION NOTE (firstrun_form_header and firstrun_form_sub_header): # LOCALIZATION NOTE (firstrun_form_header and firstrun_form_sub_header):
# firstrun_form_sub_header is a continuation of firstrun_form_header, they are one sentence. # firstrun_form_sub_header is a continuation of firstrun_form_header, they are one sentence.

View File

@ -95,7 +95,7 @@ window.gActivityStreamStrings = {
"section_menu_action_privacy_notice": "Zásady ochrany osobních údajů", "section_menu_action_privacy_notice": "Zásady ochrany osobních údajů",
"firstrun_title": "Vezměte si Firefox s sebou", "firstrun_title": "Vezměte si Firefox s sebou",
"firstrun_content": "Mějte své záložky, historii i uložená hesla s sebou na všech svých zařízeních.", "firstrun_content": "Mějte své záložky, historii i uložená hesla s sebou na všech svých zařízeních.",
"firstrun_learn_more_link": "Zjistěte více o účtech Firefoxu", "firstrun_learn_more_link": "Zjistit více o účtech Firefoxu",
"firstrun_form_header": "Zadejte svoji e-mailovou adresu", "firstrun_form_header": "Zadejte svoji e-mailovou adresu",
"firstrun_form_sub_header": "a používejte službu Firefox Sync.", "firstrun_form_sub_header": "a používejte službu Firefox Sync.",
"firstrun_email_input_placeholder": "E-mail", "firstrun_email_input_placeholder": "E-mail",

View File

@ -93,13 +93,14 @@ describe("<Trailhead>", () => {
data: {args: "https://example.com/path?foo=bar"}, data: {args: "https://example.com/path?foo=bar"},
}; };
wrapper.setState({ wrapper.setState({
deviceId: "abc",
flowId: "123", flowId: "123",
flowBeginTime: 456, flowBeginTime: 456,
}); });
wrapper.instance().onCardAction(action); wrapper.instance().onCardAction(action);
assert.calledOnce(onAction); assert.calledOnce(onAction);
const url = onAction.firstCall.args[0].data.args; const url = onAction.firstCall.args[0].data.args;
assert.equal(url, "https://example.com/path?foo=bar&utm_source=activity-stream&utm_campaign=firstrun&utm_medium=referral&utm_term=trailhead-join-card&flow_id=123&flow_begin_time=456"); assert.equal(url, "https://example.com/path?foo=bar&utm_source=activity-stream&utm_campaign=firstrun&utm_medium=referral&utm_term=trailhead-join-card&device_id=abc&flow_id=123&flow_begin_time=456");
}); });
it("should keep focus in dialog when blurring start button", () => { it("should keep focus in dialog when blurring start button", () => {

View File

@ -286,7 +286,7 @@ const TEST_GLOBAL = {
}, },
Sampling: { Sampling: {
ratioSample(seed, ratios) { ratioSample(seed, ratios) {
return 0; return Promise.resolve(0);
}, },
}, },
}; };