diff --git a/locales/en-US/server.ftl b/locales/en-US/server.ftl index 269736918a..2d02cd46f1 100644 --- a/locales/en-US/server.ftl +++ b/locales/en-US/server.ftl @@ -11,10 +11,13 @@ gSettings = Settings gSignIn = Sign In ## Header -signInButton = - .aria-label = Sign In -settingsButton = - .aria-label = Settings +buttonSettings = + .title = Settings +buttonSignIn = + .title = Sign In +screenshotsLogo = + .title = Screenshots Home + ## Footer @@ -125,7 +128,17 @@ shotPageEditButton = .title = Edit this image shotPagefavoriteButton = .title = Favorite this shot +shotPageBackToHomeButton = + .title = Homepage +shotPageAllShotsButton = + .title = All Shots +shotPageAllShots = All Shots shotPageDownload = Download +# Note: Draw text is used on shot page as a verb (action) +shotPageDraw = Draw +# Note: Favorite text is used on shot page as a verb (action) +shotPageFavorite = Favorite +shotPageDelete = Delete shotPageScreenshotsDescription = Screenshots made simple. Take, save, and share screenshots without leaving Firefox. shotPageUpsellFirefox = Get Firefox now shotPageDMCAMessage = This shot is no longer available due to a third party intellectual property claim. @@ -285,6 +298,8 @@ shotIndexPageNoShotsInvitation = Go on, create some. shotIndexPageLookingForShots = Looking for your shots… shotIndexPageNoSearchResultsIntro = Hmm shotIndexPageNoSearchResults = We canʼt find any shots that match your search. +shotIndexPageMyShotsButton = + .title = My Shots shotIndexPageClearSearchButton = .title = Clear search shotIndexPageConfirmShotDelete = Delete this shot? diff --git a/server/src/delete-shot-button.js b/server/src/delete-shot-button.js index f9221bea23..e3a2347b88 100644 --- a/server/src/delete-shot-button.js +++ b/server/src/delete-shot-button.js @@ -78,10 +78,14 @@ exports.DeleteShotButton = class DeleteShotButton extends React.Component { return (
- + ref={this.trashButtonRef}> + + Delete + + { confirmationPanel }
diff --git a/server/src/header.js b/server/src/header.js new file mode 100644 index 0000000000..a1fe1086bc --- /dev/null +++ b/server/src/header.js @@ -0,0 +1,21 @@ +const React = require("react"); +const PropTypes = require("prop-types"); +const { Localized } = require("fluent-react/compat"); + +exports.Header = function Header(props) { + const logo = props.hasLogo ?
+ +
: null; + + return
+ {logo} + {props.children} +
; +}; + +exports.Header.propTypes = { + hasLogo: PropTypes.bool, + children: PropTypes.node.isRequired, +}; diff --git a/server/src/pages/homepage/homepage-header.js b/server/src/pages/homepage/homepage-header.js new file mode 100644 index 0000000000..4da4f83bba --- /dev/null +++ b/server/src/pages/homepage/homepage-header.js @@ -0,0 +1,52 @@ +const React = require("react"); +const PropTypes = require("prop-types"); +const { Localized } = require("fluent-react/compat"); +const { SignInButton } = require("../../signin-button.js"); +const sendEvent = require("../../browser-send-event.js"); +const { Header } = require("../../header.js"); + +exports.HomePageHeader = class HomePageHeader extends React.Component { + constructor(props) { + super(props); + } + + onClickMyShots() { + sendEvent("goto-myshots", "homepage", {useBeacon: true}); + } + + renderFxASignIn() { + return ( + this.props.isFirefox && this.props.isOwner ? + : null + ); + } + + render() { + let myShots; + if (this.props.isOwner) { + myShots = + + + My Shots + + + ; + } + + const signin = this.renderFxASignIn(); + return ( +
+
+ { myShots } + { signin } +
+
+ ); + } +}; + +exports.HomePageHeader.propTypes = { + hasFxa: PropTypes.bool, + isOwner: PropTypes.bool, + isFirefox: PropTypes.bool, +}; diff --git a/server/src/pages/homepage/view.js b/server/src/pages/homepage/view.js index 27212cdbc2..dbc722c2b6 100644 --- a/server/src/pages/homepage/view.js +++ b/server/src/pages/homepage/view.js @@ -3,9 +3,9 @@ const PropTypes = require("prop-types"); const reactruntime = require("../../reactruntime"); const classnames = require("classnames"); const sendEvent = require("../../browser-send-event.js"); -const { SignInButton } = require("../../signin-button.js"); const { Footer } = require("../../footer-view.js"); const { Localized } = require("fluent-react/compat"); +const { HomePageHeader } = require("./homepage-header"); class Head extends React.Component { generateFullLink(link) { @@ -48,11 +48,6 @@ Head.propTypes = { }; class Body extends React.Component { - onClickMyShots() { - sendEvent("goto-myshots", "homepage", {useBeacon: true}); - window.location = "/shots"; - } - onClickInstallFirefox() { sendEvent("click-install-firefox-home", {useBeacon: true}); } @@ -79,46 +74,25 @@ class Body extends React.Component { } render() { - let myShots; - if (this.props.showMyShots) { - myShots = - - My Shots - - ; - } - const signin = (this.props.isFirefox && this.props.showMyShots) ? : null; const is57 = this.props.isFirefox && this.props.firefoxVersion >= 57; return (
-
- -
-
-
-
-
-

Firefox Screenshots

- -

Screenshots made simple. Take, save, and share screenshots without leaving Firefox.

-
- { this.renderGetFirefox() } -
-
+ +
+
+
+
+

Firefox Screenshots

+ +

Screenshots made simple. Take, save, and share screenshots without leaving Firefox.

+
+ { this.renderGetFirefox() }
+
-
+

How Screenshots Works

diff --git a/server/src/pages/not-found/view.js b/server/src/pages/not-found/view.js index 989bfb0e14..f5a53802aa 100644 --- a/server/src/pages/not-found/view.js +++ b/server/src/pages/not-found/view.js @@ -3,6 +3,7 @@ const { Footer } = require("../../footer-view.js"); const { Localized } = require("fluent-react/compat"); const React = require("react"); const PropTypes = require("prop-types"); +const { Header } = require("../../header.js"); class Head extends React.Component { render() { @@ -28,9 +29,7 @@ class Body extends React.Component { return (
- +
diff --git a/server/src/pages/shot/shotpage-header.js b/server/src/pages/shot/shotpage-header.js new file mode 100644 index 0000000000..87d0b3e539 --- /dev/null +++ b/server/src/pages/shot/shotpage-header.js @@ -0,0 +1,199 @@ +/* globals controller */ +const React = require("react"); +const PropTypes = require("prop-types"); +const { Localized } = require("fluent-react/compat"); +const sendEvent = require("../../browser-send-event.js"); +const { SignInButton } = require("../../signin-button.js"); +const { Header } = require("../../header.js"); +const { TimeDiff } = require("./time-diff"); + +exports.ShotPageHeader = class ShotPageHeader extends React.Component { + constructor(props) { + super(props); + } + + renderMyShotsText() { + // FIXME: this means that on someone else's shot they won't see a My Shots link: + if (!this.props.isOwner) { + return ( + + + + + Firefox + + + Screenshots + + + + + ); + } + return ( + + + + All Shots + + + + ); + } + + onClickMyShots() { + if (this.props.isOwner) { + sendEvent("goto-myshots", "navbar", {useBeacon: true}); + } else { + sendEvent("goto-homepage", "navbar", {useBeacon: true}); + } + } + + renderShotInfo() { + const shot = this.props.shot; + const linkTextShort = shot.urlDisplay; + const timeDiff = ; + let expirationSubtitle; + if (this.props.expireTime === null) { + expirationSubtitle = does not expire; + } else { + const expired = this.props.expireTime < Date.now(); + const expireTimeDiff = ; + if (expired) { + expirationSubtitle = expired {expireTimeDiff}; + } else { + expirationSubtitle = expires {expireTimeDiff}; + } + } + + return ( +
+
+ +
+ { linkTextShort ? { linkTextShort } : null } + { timeDiff } + { expirationSubtitle } +
+
+
+ ); + } + + onClickOrigUrl(label) { + if (this.props.isOwner) { + sendEvent("view-original", `${label}-owner`, {useBeacon: true}); + } else { + sendEvent("view-original", `${label}-non-owner`, {useBeacon: true}); + } + // Note: we allow the default action to continue + } + + renderFxASignIn() { + return ( + this.props.isOwner ? +
+ +
: null + ); + } + + render() { + const myShotsText = this.renderMyShotsText(); + const signin = this.renderFxASignIn(); + const shotInfo = this.renderShotInfo(); + return ( +
+ { myShotsText } + { shotInfo } +
+ { this.props.children } + { signin } +
+
+ ); + } +}; + +exports.ShotPageHeader.propTypes = { + children: PropTypes.node.isRequired, + isOwner: PropTypes.bool, + shot: PropTypes.object, + isFxaAuthenticated: PropTypes.bool, + expireTime: PropTypes.number, +}; + +class EditableTitle extends React.Component { + + constructor(props) { + super(props); + this.state = {isEditing: false, isSaving: false, minWidth: 200}; + } + + UNSAFE_componentWillReceiveProps(nextProps) { + // When the save completes, this component just gets updated with the new title + if (this.state.isSaving && this.state.isSaving === nextProps.title) { + this.setState({isSaving: false}); + } + } + + render() { + if (this.state.isEditing) { + return this.renderEditing(); + } + let className = "shot-title"; + const handlers = {}; + if (this.props.isOwner) { + className += " editable"; + handlers.onClick = this.onClick.bind(this); + } + if (this.state.isSaving) { + className += " saving"; + } + return this.titleElement = titleElement} className={className} {...handlers}>{this.state.isSaving || this.props.title}; + } + + renderEditing() { + return
+ this.textInput = input} + className="shot-title-input" + style={{minWidth: this.state.minWidth}} + type="text" defaultValue={this.props.title} autoFocus="true" + onBlur={this.onExit.bind(this)} onKeyUp={this.onKeyUp.bind(this)} onFocus={this.onFocus} /> +
; + } + + onClick() { + if (!this.state.isEditing) { + this.setState({minWidth: this.titleElement.offsetWidth }); + } + this.setState({isEditing: true}); + } + + onExit() { + const val = this.textInput.value; + + if (val.trim() === "") { + this.setState({isEditing: false, isSaving: false}); + } else { + controller.setTitle(val); + this.setState({isEditing: false, isSaving: val}); + } + } + + onFocus(event) { + event.target.select(); + } + + onKeyUp(event) { + if ((event.key || event.code) === "Escape") { + this.setState({isEditing: false}); + } + } + +} + +EditableTitle.propTypes = { + isOwner: PropTypes.bool, + title: PropTypes.string, +}; diff --git a/server/src/pages/shot/view.js b/server/src/pages/shot/view.js index 2d1ef184bc..d71fbc9aeb 100644 --- a/server/src/pages/shot/view.js +++ b/server/src/pages/shot/view.js @@ -4,14 +4,13 @@ const PropTypes = require("prop-types"); const { Localized } = require("fluent-react/compat"); const { Footer } = require("../../footer-view"); const sendEvent = require("../../browser-send-event.js"); -const { ShareButton } = require("../../share-buttons"); -const { SignInButton } = require("../../signin-button.js"); const { PromoDialog } = require("./promo-dialog"); const { DeleteShotButton } = require("../../delete-shot-button"); const { TimeDiff } = require("./time-diff"); const reactruntime = require("../../reactruntime"); const { Editor } = require("./editor"); const { isValidClipImageUrl } = require("../../../shared/shot"); +const { ShotPageHeader } = require("./shotpage-header"); class Clip extends React.Component { constructor(props) { @@ -337,34 +336,29 @@ class Body extends React.Component { , ]; - const linkTextShort = shot.urlDisplay; - - const timeDiff = ; - let expirationSubtitle; - if (this.props.expireTime === null) { - expirationSubtitle = does not expire; - } else { - const expired = this.props.expireTime < Date.now(); - const expireTimeDiff = ; - if (expired) { - expirationSubtitle = expired {expireTimeDiff}; - } else { - expirationSubtitle = expires {expireTimeDiff}; - } - } - let favoriteShotButton = null; let trashOrFlagButton = null; let editButton = null; const highlight = this.state.highlightEditButton ?
: null; - const activeFavClass = this.props.expireTime ? "" : "is-fav"; const shouldShow = this.props.isFxaAuthenticated ? "" : "hidden"; - favoriteShotButton =
; + + favoriteShotButton =
+
; + + const downloadButton =
+ +
; if (this.props.isOwner) { trashOrFlagButton = ; - editButton =
+ editButton = this.props.enableAnnotations ?
- + -
; - } - - let myShotsHref = "/shots"; - let myShotsText = My Shots; - // FIXME: this means that on someone else's shot they won't see a My Shots link: - if (!this.props.isOwner) { - myShotsText = - - Firefox - - - Screenshots - - ; - myShotsHref = "/"; + { highlight } +
: null; } let clip; @@ -407,52 +394,21 @@ class Body extends React.Component { } let renderGetFirefox = this.props.userAgent && (this.props.userAgent + "").search(/firefox\/\d{1,255}/i) === -1; - let renderExtensionNotification = !(this.props.isExtInstalled || renderGetFirefox); if (this.props.isMobile || this.state.closeBanner) { - renderGetFirefox = renderExtensionNotification = false; + renderGetFirefox = false; } - const noText = this.props.abTests && this.props.abTests.downloadText - && this.props.abTests.downloadText.value === "no-download-text"; - const signIn = this.props.isOwner ? -
- -
: null; return ( { renderGetFirefox ? this.renderFirefoxRequired() : null }
-
- { myShotsText } -
-
- -
- { linkTextShort ? { linkTextShort } : null } - { timeDiff } - { expirationSubtitle } -
-
-
-
- { favoriteShotButton } - { trashOrFlagButton } - { this.props.enableAnnotations ? editButton : null } - { highlight } - - - - - { !noText && - Download } - - - { signIn } -
-
+ + { favoriteShotButton } + { editButton } + { downloadButton } + { trashOrFlagButton } +
{ this.props.isOwner && this.props.loginFailed ? : null } { errorMessages } @@ -524,15 +480,6 @@ class Body extends React.Component { this.props.controller.changeShotExpiration(this.props.shot, this.props.defaultExpiration); } - onClickMyShots() { - if (this.props.isOwner) { - sendEvent("goto-myshots", "navbar", {useBeacon: true}); - } else { - sendEvent("goto-homepage", "navbar", {useBeacon: true}); - } - // Note: we allow the default action to continue - } - onClickOrigUrl(label) { if (this.props.isOwner) { sendEvent("view-original", `${label}-owner`, {useBeacon: true}); @@ -555,6 +502,7 @@ class Body extends React.Component { onClickDownload() { sendEvent("download", "navbar"); + location.href = this.props.downloadUrl; } onClickFeedback() { @@ -589,82 +537,6 @@ Body.propTypes = { userLocales: PropTypes.array, }; - -class EditableTitle extends React.Component { - - constructor(props) { - super(props); - this.state = {isEditing: false, isSaving: false, minWidth: 200}; - } - - UNSAFE_componentWillReceiveProps(nextProps) { - // When the save completes, this component just gets updated with the new title - if (this.state.isSaving && this.state.isSaving === nextProps.title) { - this.setState({isSaving: false}); - } - } - - render() { - if (this.state.isEditing) { - return this.renderEditing(); - } - let className = "shot-title"; - const handlers = {}; - if (this.props.isOwner) { - className += " editable"; - handlers.onClick = this.onClick.bind(this); - } - if (this.state.isSaving) { - className += " saving"; - } - return this.titleElement = titleElement} className={className} {...handlers}>{this.state.isSaving || this.props.title}; - } - - renderEditing() { - return
- this.textInput = input} - className="shot-title-input" - style={{minWidth: this.state.minWidth}} - type="text" defaultValue={this.props.title} autoFocus="true" - onBlur={this.onExit.bind(this)} onKeyUp={this.onKeyUp.bind(this)} onFocus={this.onFocus} /> -
; - } - - onClick() { - if (!this.state.isEditing) { - this.setState({minWidth: this.titleElement.offsetWidth }); - } - this.setState({isEditing: true}); - } - - onExit() { - const val = this.textInput.value; - - if (val.trim() === "") { - this.setState({isEditing: false, isSaving: false}); - } else { - controller.setTitle(val); - this.setState({isEditing: false, isSaving: val}); - } - } - - onFocus(event) { - event.target.select(); - } - - onKeyUp(event) { - if ((event.key || event.code) === "Escape") { - this.setState({isEditing: false}); - } - } - -} - -EditableTitle.propTypes = { - isOwner: PropTypes.bool, - title: PropTypes.string, -}; - class LoginFailedWarning extends React.Component { render() { return diff --git a/server/src/pages/shotindex/myshots-header.js b/server/src/pages/shotindex/myshots-header.js new file mode 100644 index 0000000000..dd4d078af9 --- /dev/null +++ b/server/src/pages/shotindex/myshots-header.js @@ -0,0 +1,23 @@ +const React = require("react"); +const PropTypes = require("prop-types"); +const { SignInButton } = require("../../signin-button.js"); +const { Header } = require("../../header.js"); + +exports.MyShotsHeader = function MyShotsHeader(props) { + const signin = props.enableUserSettings && props.hasDeviceId ? + : null; + + return ( +
+
+ { signin } +
+
+ ); +}; + +exports.MyShotsHeader.propTypes = { + hasFxa: PropTypes.bool, + hasDeviceId: PropTypes.bool, + enableUserSettings: PropTypes.bool, +}; diff --git a/server/src/pages/shotindex/view.js b/server/src/pages/shotindex/view.js index ac1edecfb1..2ae6f20fe8 100644 --- a/server/src/pages/shotindex/view.js +++ b/server/src/pages/shotindex/view.js @@ -5,12 +5,12 @@ const { Footer } = require("../../footer-view.js"); const React = require("react"); const PropTypes = require("prop-types"); const { ShareButton } = require("../../share-buttons"); -const { SignInButton } = require("../../signin-button.js"); const Masonry = require("react-masonry-component"); const { Localized } = require("fluent-react/compat"); const { isValidClipImageUrl } = require("../../../shared/shot"); const { getThumbnailDimensions } = require("../../../shared/thumbnailGenerator"); const { DeleteShotButton } = require("../../delete-shot-button"); +const { MyShotsHeader } = require("./myshots-header"); class Head extends React.Component { @@ -39,11 +39,9 @@ class Body extends React.Component { return (
-
-

Firefox Screenshots Beta

- {this.props.enableUserSettings && this.props.hasDeviceId ? this.renderFxASignIn() : null} - {this.props.disableSearch ? null : this.renderSearchForm()} -
+ + { this.props.disableSearch ? null : this.renderSearchForm() }
{ this.renderShots() }
@@ -203,15 +201,9 @@ class Body extends React.Component { ); } - renderFxASignIn() { - return ( - - ); - } - renderSearchForm() { return ( -
+ this.searchInput = searchInput} maxLength="100" placeholder="search my shots" defaultValue={this.state.defaultSearch} onChange={this.onChangeSearch.bind(this)} /> diff --git a/server/src/signin-button.js b/server/src/signin-button.js index 7873a23f86..a04fb06924 100644 --- a/server/src/signin-button.js +++ b/server/src/signin-button.js @@ -17,8 +17,8 @@ exports.SignInButton = class SignInButton extends React.Component { render() { if (this.state.displaySettings) { - return - + return + Settings @@ -26,22 +26,22 @@ exports.SignInButton = class SignInButton extends React.Component { ; } - const logInURI = "/api/fxa-oauth/login/" + this.props.initiatePage; - return - - - Sign In - - - ; + const logInURI = "/api/fxa-oauth/login/" + this.props.initialPage; + return + + + Sign In + + + ; } clickHandler(event) { - sendEvent("fxa-signin", this.props.initiatePage, {useBeacon: true}); + sendEvent("fxa-signin", this.props.initialPage, {useBeacon: true}); } }; exports.SignInButton.propTypes = { - initiatePage: PropTypes.string, + initialPage: PropTypes.string, isAuthenticated: PropTypes.bool, }; diff --git a/static/css/frame.scss b/static/css/frame.scss index 219b81236c..cc582161d7 100644 --- a/static/css/frame.scss +++ b/static/css/frame.scss @@ -1,23 +1,43 @@ @import "partials/partials"; @import "partials/delete-confirmation"; -.frame-header { - @include respond-to("medium") { - @include flex-container(row, space-between, stretch); - height: $grid-unit * 5; - } - - @include respond-to("small") { - @include flex-container(row, space-between, stretch, wrap); - } -} - .alt-notification { @include flex-container(row, flex-start, center); min-height: 55px; padding: 5px 20px; } +.back-to-home { + @include respond-to("small") { + background-size: 24px auto; + padding-left: 40px; + border: 0; + } + + background-position: left center; + background-image: url("../img/icon-screenshot.svg"); + background-repeat: no-repeat; + background-size: 36px auto; + padding-left: 52px; + margin: 0 16px; + + span { + display: block; + text-align: left; + margin: 0; + font-size: 24px; + font-weight: bold; + &.small-text { + font-size: 17px; + padding-left: 0; + } + } + + .sub { + font-size: 12px; + } +} + .shot-main-actions { @include respond-to("medium") { @@ -47,75 +67,16 @@ } } -.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 flex-container(row, flex-end, center); @include respond-to("small") { - padding-right: $grid-unit * 0.5; - - .download-text { - display: none; - } - - #downloadIcon { - margin-right: 0; - } + flex-wrap: wrap; + justify-content: flex-start; } - - @include flex-container(row, flex-end, center); - padding-right: $grid-unit * 1.5; } .shot-info { @@ -128,87 +89,16 @@ } } -.fav-wrapper { - &:active, - &:hover { - background-color: $light-hover; - } - border-radius: $border-radius; - margin-right: $grid-unit * 0.5; -} -.favorite { - background: url("../img/icon-heart.svg"); - background-size: 20px 20px; - background-position: center; - background-repeat: no-repeat; - filter: brightness(2.4); - - &.is-fav { - filter: brightness(1); - } -} - -.delete-confirmation-dialog { - &.right-align { - top: 48px; - } -} - - -.back-to-index { - @include respond-to("small") { - background-position: left -5px center; - background-repeat: no-repeat; - background-size: 36px auto; - height: 32px; - padding-left: 28px; - } - - @include flex-container(row, flex-start, center); - background-image: url("../img/shots.svg"); - background-position: left center; - background-repeat: no-repeat; - background-size: 46px 46px; - height: 46px; - line-height: 46px; - padding: 0 0 0 46px; -} - -.back-to-home { - @include respond-to("small") { - background-position: left center; - background-repeat: no-repeat; - background-size: 24px auto; - height: 32px; - padding-left: 30px; - } - - background-image: url("../img/new-scissors-icon.svg"); - background-position: left bottom; - background-repeat: no-repeat; - background-size: 30px auto; - height: 34px; - padding-left: 42px; - - > span { - display: block; - text-align: left; - } - - .sub { - font-size: 12px; - } -} - .shot-title, .shot-subtitle { overflow-x: hidden; text-overflow: ellipsis; white-space: nowrap; + margin: 0; + max-width: 600px; } .shot-title { - @include respond-to("small") { font-size: 20px; line-height: 20px; @@ -216,7 +106,7 @@ } font-size: 28px; - font-weight: 300; + font-weight: bold; line-height: 28px; padding-bottom: 8px; @@ -237,11 +127,79 @@ } } +.shot-subtitle { + @include flex-container(row, flex-start, center); + font-size: 15px; +} + +.shot-title-input { + border-radius: $border-radius; + border: 1px solid $active-blue; + font-size: 24px; + font-weight: 300; + height: 32px; + margin: 0 0 4px -6px; + padding: 0 5px; + overflow: auto; +} + .subtitle-link, .time-diff { margin-right: 8px; } +.promo-panel { + position: absolute; + top: 90px; + right: -30px; + 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; + } +} + +.delete-confirmation-dialog { + &.right-align { + top: 88px; + } +} + .keep-for-form { @include flex-container(row, flex-start, center); @@ -344,7 +302,6 @@ display: none; } -.edit, .pen-button, .text-button, .highlight-button { @@ -359,10 +316,9 @@ background-image: url("../img/edit-highlight.svg"); height: 17px; width: 17px; - position: relative; - left: -31px; - top: -5px; - margin-right: -17px; + position: absolute; + left: 50px; + top: 20px; cursor: pointer; } diff --git a/static/css/home.scss b/static/css/home.scss index 766fb18df0..8c89b15dac 100644 --- a/static/css/home.scss +++ b/static/css/home.scss @@ -25,66 +25,8 @@ body { position: relative; } -/* Navigation Bar */ - -nav { - align-items: center; - background-color: #fff; - box-shadow: rgba(0, 0, 0, 0.09) 0 3px 6px; - display: flex; - height: 82px; - position: fixed; - width: 100%; - z-index: 1000; -} - -.myshots-text { - cursor: pointer; -} - -.header-logo { - -ms-flex-align: end; - align-items: flex-end; - display: -ms-flexbox; - display: flex; -} - -.nav-links { - -ms-flex-align: end; - -ms-flex-pack: end; - -ms-flex: 1; - align-items: flex-end; - display: -ms-flexbox; - display: flex; - flex: 1; - justify-content: flex-end; -} - -.screenshots-logo { - background-image: url("../img/landing-Screenshot-logo.svg"); - background-repeat: no-repeat; - background-size: contain; - height: 37px; - position: relative; - width: 390px; -} - -.nav-links a { - color: #4a4a4a; - cursor: pointer; - text-decoration: none; -} - -.nav-links a:first-child { - margin-right: 71px; -} - /* Header Banner */ -.banner-spacer { - height: 82px; -} - .banner { align-items: center; background-color: #04d1e6; @@ -431,24 +373,6 @@ section .container { } @media (max-width: 768px) { - - .nav-links { - display: none; - } - - .screenshots-logo { - max-width: 90%; - margin: 0 auto; - position: relative; - top: 20px; - } - - .container { - flex-direction: column; - justify-content: center; - text-align: center; - } - .banner { background-image: url("../img/landing-screenshots_mobile.svg"); background-repeat: no-repeat; @@ -462,7 +386,7 @@ section .container { } .banner-spacer { - height: 60px; + height: 74px; } .banner-container { diff --git a/static/css/partials/_delete-confirmation.scss b/static/css/partials/_delete-confirmation.scss index df12472d6d..5b768827b6 100644 --- a/static/css/partials/_delete-confirmation.scss +++ b/static/css/partials/_delete-confirmation.scss @@ -58,7 +58,7 @@ } &.right-align { - left: -281px; + left: -255px; .triangle { left: 292px; } diff --git a/static/css/partials/_header.scss b/static/css/partials/_header.scss new file mode 100644 index 0000000000..191fbb38bb --- /dev/null +++ b/static/css/partials/_header.scss @@ -0,0 +1,148 @@ +.header-panel { + @include respond-to("medium") { + @include flex-container(row, space-between, center); + height: $grid-unit * 5; + } + + @include respond-to("small") { + @include flex-container(row, space-between, center, wrap); + height: 100%; + } + + @include respond-to("large") { + @include flex-container(row, center, center); + } + + display: flex; + height: 96px; + background-color: $light-default; + width: 100%; + + .logo { + display: flex; + padding: 0 16px; + flex: 1; + .screenshots-logo { + background-image: url("../img/landing-Screenshot-logo.svg"); + background-repeat: no-repeat; + background-size: contain; + height: $grid-unit * 1.5; + position: relative; + width: 318px; + } + + @include respond-to("small") { + margin: $grid-unit auto; + } + } + + .alt-actions { + display: flex; + align-items: center; + margin-right: $grid-unit * 1.5; + } + + a.nav-button { + &:focus { + outline: 1px dotted $black; + } + } + + .nav-button { + @include flex-container(column, center, center); + color: #4a4a4a; + cursor: pointer; + text-decoration: none; + background-color: transparent; + border: 0; + outline: none; + display: flex; + flex-basis: 96px; + font-size: 14px; + color: #2a2a2e; + font-weight: bold; + height: 96px; + width: 96px; + text-align: center; + background-size: 24px 24px; + background-position: center 24px; + background-repeat: no-repeat; + + &:active, + &:hover { + background-color: $light-hover; + } + + &.hidden { + display: none; + } + + &.icon-shots { + background-image: url("../img/icon-shots.svg"); + } + + &.icon-settings { + background-image: url("../img/icon-settings.svg"); + } + + .icon-favorite { + background-image: url("../img/icon-heart.svg"); + } + + &.icon-trash { + background-image: url("../img/icon-trash.svg"); + } + + &.icon-edit { + background-image: url("../img/icon-pen.svg"); + } + + &.icon-download { + background-image: url("../img/icon-download.svg"); + } + + .icon-favorite { + &.favorite { + width: 24px; + height: 24px; + margin: 0 0 8px; + background-size: 24px 24px; + filter: brightness(2.4); + + &.is-fav { + filter: brightness(1); + } + } + } + + span { + margin-top: 30px; + color: #2a2a2e; + overflow: hidden; + text-overflow: ellipsis; + width: 96px; + } + + .favorite-text { + &.favorite { + margin-top: 0; + color: #95929a; + + &.is-fav { + color: #4a4a4a; + } + } + } + } + + .nav-link { + @include flex-container(column, center, center); + color: $black; + border-right: 1px solid $light-border; + height: 96px; + &:active, + &:hover { + background-color: $light-hover; + } + } +} diff --git a/static/css/partials/_partials.scss b/static/css/partials/_partials.scss index 7b6b5e5ce1..7eb6684d0b 100644 --- a/static/css/partials/_partials.scss +++ b/static/css/partials/_partials.scss @@ -10,7 +10,7 @@ @import "buttons"; @import "large-icon-block"; @import "share-panel"; -@import "signin-fxa"; +@import "header"; // Theme @import "theme"; diff --git a/static/css/partials/_signin-fxa.scss b/static/css/partials/_signin-fxa.scss deleted file mode 100644 index 72d2fb194c..0000000000 --- a/static/css/partials/_signin-fxa.scss +++ /dev/null @@ -1,19 +0,0 @@ -.signin-button, -.settings-button { - cursor: pointer; - text-decoration: none; - position: absolute; - right: 0; - - span { - color: #4a4a4a; - } -} - -.shot-fxa-signin { - a.signin-button, - a.settings-button { - position: relative; - padding: 10px; - } -} diff --git a/static/css/shot-index.scss b/static/css/shot-index.scss index 16a4f199f6..11d54a524f 100644 --- a/static/css/shot-index.scss +++ b/static/css/shot-index.scss @@ -7,9 +7,7 @@ background: $light-default; } -#shot-index-header, #shot-index { - @include respond-to("small") { width: 480px; } @@ -23,50 +21,31 @@ } } -#shot-index-header { - @include respond-to("small") { - @include flex-container(column, flex-start, center); - } - @include respond-to("medium") { - @include flex-container(row, center, center); - } +#search-form { + @include flex-container(row, flex-start, stretch); + position: absolute; + right: 150px; + top: 40px; - @include respond-to("large") { - @include flex-container(row, center, center); + @include respond-to("small") { + right: 100px; + top: 60px; } - margin: 40px auto 15px; - position: relative; - - form { - @include respond-to("small") { - position: relative; - - input[type="search"] { - margin: 20px 0 10px; - width: 320px; - } - } - - @include flex-container(row, flex-start, stretch); + .clear-search { + width: 28px; + height: 28px; + background: transparent; + border: 0; + background-image: url("../img/icon-clear.svg"); + background-size: 12px 12px; + background-repeat: no-repeat; + background-position: center top 5px; position: absolute; right: 0; - - .clear-search { - width: 28px; - height: 28px; - background: transparent; - border: 0; - background-image: url("../img/icon-clear.svg"); - background-size: 12px 12px; - background-repeat: no-repeat; - background-position: center top 5px; - position: absolute; - right: 0; - opacity: 0; - transition: opacity $bezier 150ms; - } + opacity: 0; + transition: opacity $bezier 150ms; } input[type="search"] { @@ -95,34 +74,9 @@ } } -h1 { - background-image: url("../img/new-scissors-icon.svg"); - background-position: left center; - background-repeat: no-repeat; - background-size: 25px auto; - font-size: 30px; - font-weight: 400; - margin: 0; - padding: 0 0 0 32px; - text-align: center; - - .default-color-scheme & a { - color: $dark-default; - } - - sup { - background: $active-blue; - border-radius: 2px; - color: #fff; - font-size: 14px; - padding: 2px 4px; - text-transform: uppercase; - } -} - #shot-index { @include flex-container(column, flex-start, stretch); - margin: 0 auto; + margin: 10px auto; } .shot { diff --git a/static/img/icon-copy.svg b/static/img/icon-copy.svg new file mode 100755 index 0000000000..d48de4e177 --- /dev/null +++ b/static/img/icon-copy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/img/icon-download.svg b/static/img/icon-download.svg old mode 100644 new mode 100755 index 934c0af9ea..d1eb55eece --- a/static/img/icon-download.svg +++ b/static/img/icon-download.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/static/img/icon-heart.svg b/static/img/icon-heart.svg old mode 100644 new mode 100755 diff --git a/static/img/icon-pen.svg b/static/img/icon-pen.svg new file mode 100755 index 0000000000..a6c60cde0b --- /dev/null +++ b/static/img/icon-pen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/img/icon-screenshot.svg b/static/img/icon-screenshot.svg new file mode 100755 index 0000000000..eb89e3aabb --- /dev/null +++ b/static/img/icon-screenshot.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/img/icon-settings.svg b/static/img/icon-settings.svg new file mode 100755 index 0000000000..633075605a --- /dev/null +++ b/static/img/icon-settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/img/icon-share.svg b/static/img/icon-share.svg old mode 100644 new mode 100755 diff --git a/static/img/icon-shots.svg b/static/img/icon-shots.svg new file mode 100755 index 0000000000..c946c315bb --- /dev/null +++ b/static/img/icon-shots.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/img/icon-sync.svg b/static/img/icon-sync.svg new file mode 100755 index 0000000000..94efe0ce5e --- /dev/null +++ b/static/img/icon-sync.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/img/icon-trash.svg b/static/img/icon-trash.svg old mode 100644 new mode 100755 diff --git a/static/img/landing-Screenshot-logo.svg b/static/img/landing-Screenshot-logo.svg old mode 100644 new mode 100755 diff --git a/static/img/new-scissors-icon.svg b/static/img/new-scissors-icon.svg deleted file mode 100644 index 762443fa57..0000000000 --- a/static/img/new-scissors-icon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file