diff --git a/docs/METRICS.md b/docs/METRICS.md index 641a40f89a..6bb72c0038 100644 --- a/docs/METRICS.md +++ b/docs/METRICS.md @@ -315,6 +315,7 @@ These are events that an add-on user can encounter on a shot they own 32. [x] Click the download button `web/download/navbar` 33. [x] Visit an image directly, when the image isn't embedded directly in a Screenshots shot page, `web/visit/direct-view-owner` 34. [x] View an image directly, when the image is being shown as part of a Facebook/Twitter style preview (the og:image or twitter:image), `web/visit/direct-view-embedded-owner` +35. [x] Close new edit tools promotion dialog, `web/promo-closed` #### Shot Index (My Shots) diff --git a/locales/en-US/server.ftl b/locales/en-US/server.ftl index 8457301d2e..a56cacbc02 100644 --- a/locales/en-US/server.ftl +++ b/locales/en-US/server.ftl @@ -175,6 +175,14 @@ timeDiffFutureDays = { $number -> errorThirdPartyCookiesEnabled = If you took this shot and cannot delete it, you may need to temporarily enable third party cookies from your browser’s preferences. +## Shot Page New Feature Promotion Dialog. +# Note: If possible, choose a short translation to better fit into the card. +promoTitle = Take Note! +promoMessage = Updated editing tools let you crop, highlight, and even add text to your shot. +promoLink = Give them a try +promoCloseButton = + .title = Close notification + ## Annotations annotationPenButton = diff --git a/server/src/pages/shot/controller.js b/server/src/pages/shot/controller.js index 3559dbbfd2..67cc655f1a 100644 --- a/server/src/pages/shot/controller.js +++ b/server/src/pages/shot/controller.js @@ -20,6 +20,22 @@ function shouldHighlightEditIcon(model) { return !hasSeen; } +function shouldShowPromo(model) { + if (!model.isOwner || !model.enableAnnotations) { + return false; + } + let show = false; + const count = localStorage.hasSeenPromoDialog; + if (!count) { + localStorage.hasSeenPromoDialog = 1; + show = true; + } else if (count < 3) { + localStorage.hasSeenPromoDialog = parseInt(count, 10) + 1; + show = true; + } + return show; +} + exports.launch = function(data) { const firstSet = !model; model = data; @@ -57,6 +73,7 @@ exports.launch = function(data) { } } model.highlightEditButton = shouldHighlightEditIcon(model); + model.promoDialog = shouldShowPromo(model); if (firstSet) { refreshHash(); } diff --git a/server/src/pages/shot/promo-dialog.js b/server/src/pages/shot/promo-dialog.js new file mode 100644 index 0000000000..47545ed709 --- /dev/null +++ b/server/src/pages/shot/promo-dialog.js @@ -0,0 +1,40 @@ +const React = require("react"); +const PropTypes = require("prop-types"); +const { Localized } = require("fluent-react/compat"); +const sendEvent = require("../../browser-send-event.js"); + +exports.PromoDialog = class PromoDialog extends React.Component { + constructor(props) { + super(props); + } + + render() { + if (this.props.display) { + return
+ + + + +

Take Note!

+
+ +

+ Updated editing tools let you crop, highlight, and even add text to your shot. +

+
+

Give them a try

+
; + } + return null; + } + + closePanel(event) { + this.props.promoClose(); + sendEvent("promo-closed"); + } +}; + +exports.PromoDialog.propTypes = { + display: PropTypes.bool, + promoClose: PropTypes.func +}; diff --git a/server/src/pages/shot/view.js b/server/src/pages/shot/view.js index ec3e931f48..3c7758ea77 100644 --- a/server/src/pages/shot/view.js +++ b/server/src/pages/shot/view.js @@ -5,6 +5,7 @@ const { Localized } = require("fluent-react/compat"); const { Footer } = require("../../footer-view"); const sendEvent = require("../../browser-send-event.js"); const { ShareButton } = require("../../share-buttons"); +const { PromoDialog } = require("./promo-dialog"); const { DeleteShotButton } = require("../../delete-shot-button"); const { TimeDiff } = require("./time-diff"); const reactruntime = require("../../reactruntime"); @@ -181,7 +182,8 @@ class Body extends React.Component { } componentDidMount() { - this.setState({highlightEditButton: this.props.highlightEditButton}); + this.setState({highlightEditButton: this.props.highlightEditButton || this.props.promoDialog}); + this.setState({promoDialog: this.props.promoDialog}); } doCloseBanner() { @@ -358,9 +360,13 @@ class Body extends React.Component { clickDeleteHandler={ this.clickDeleteHandler.bind(this) } confirmDeleteHandler={ this.confirmDeleteHandler.bind(this) } cancelDeleteHandler={ this.cancelDeleteHandler.bind(this) } />; - editButton = - - ; + + editButton =
+ + + + +
; } else { trashOrFlagButton = @@ -408,6 +414,7 @@ class Body extends React.Component { const noText = this.props.abTests && this.props.abTests.downloadText && this.props.abTests.downloadText.value === "no-download-text"; + return ( { renderGetFirefox ? this.renderFirefoxRequired() : null } @@ -452,6 +459,12 @@ class Body extends React.Component { ); } + promoClose() { + this.setState({promoDialog: false}); + // set counter to max to stop showing notification again + localStorage.hasSeenPromoDialog = 3; + } + onMouseOverHighlight() { this.editButton.style.backgroundColor = "#ededf0"; } @@ -480,6 +493,10 @@ class Body extends React.Component { this.setState({imageEditing: true}); sendEvent("start-annotations", "navbar"); } + // Close promo dialog if user clicked edit after seeing new edit tool promo + if (this.props.promoDialog) { + this.promoClose(); + } } onClickSave(dataUrl, dimensions) { @@ -555,6 +572,7 @@ Body.propTypes = { enableAnnotations: PropTypes.bool, expireTime: PropTypes.number, highlightEditButton: PropTypes.bool, + promoDialog: PropTypes.bool, id: PropTypes.string, isExtInstalled: PropTypes.bool, isMobile: PropTypes.bool, diff --git a/static/css/frame.scss b/static/css/frame.scss index fd66210072..f73ee6f614 100644 --- a/static/css/frame.scss +++ b/static/css/frame.scss @@ -47,11 +47,61 @@ } } +.promo-panel { + position: absolute; + top: 45px; + right: -45px; + border-radius: 3px; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.3), 0 0 20px rgba(0, 0, 0, 0.2); + width: 150px; + z-index: 999; + padding: 5px; + text-align: center; + + .title { + font-size: 14px; + line-height: 14px; + margin: 5px; + } + + .message { + font-size: 12px; + margin: 5px 2px; + } + + .message-text { + margin: 0 2px; + } + + a.box-close { + position: absolute; + top: 2px; + right: 2px; + cursor: pointer; + color: $black; + width: 15px; + height: 15px; + line-height: 12px; + } + + .box-close:before { + content: "×"; + } + + .box-close:hover { + background-color: $light-hover; + } +} + .shot-alt-actions { #downloadIcon { margin-right: 4px; } + .edit-shot-button { + position: relative; + } + @include respond-to("small") { padding-right: $grid-unit * 0.5;