diff --git a/app/ContentAnalysisWrapper.js b/app/ContentAnalysisWrapper.js index 91cb6dba..3b17fd20 100644 --- a/app/ContentAnalysisWrapper.js +++ b/app/ContentAnalysisWrapper.js @@ -76,6 +76,10 @@ export default function HelpCenterWrapper() { console.log( "Marker button clicked", id, marker ); } } marksButtonStatus={ "enabled" } + helpText={ [ + "Enter the search term you'd like this post to be found with and see how it would rank. ", + Learn more about the Content Analysis Tool., + ] } /> ); } diff --git a/composites/Plugin/ContentAnalysis/components/ContentAnalysis.js b/composites/Plugin/ContentAnalysis/components/ContentAnalysis.js index 76b1c001..2936f00a 100644 --- a/composites/Plugin/ContentAnalysis/components/ContentAnalysis.js +++ b/composites/Plugin/ContentAnalysis/components/ContentAnalysis.js @@ -1,12 +1,15 @@ +/* External dependencies */ import React from "react"; import styled from "styled-components"; -import colors from "../../../../style-guide/colors.json"; import PropTypes from "prop-types"; - import { injectIntl, intlShape, defineMessages, FormattedMessage } from "react-intl"; + +/* Internal dependencies */ +import colors from "../../../../style-guide/colors.json"; import { makeOutboundLink } from "../../../../utils/makeOutboundLink"; import AnalysisResult from "../components/AnalysisResult.js"; import AnalysisCollapsible from "../components/AnalysisCollapsible.js"; +import HelpText, { HelpTextPropType } from "../../../../composites/Plugin/Shared/components/HelpText"; export const ContentAnalysisContainer = styled.div` width: 100%; @@ -205,21 +208,25 @@ class ContentAnalysis extends React.Component { * @returns {ReactElement} The rendered ContentAnalysis component. */ render() { - let problemsResults = this.props.problemsResults; - let improvementsResults = this.props.improvementsResults; - let goodResults = this.props.goodResults; - let considerationsResults = this.props.considerationsResults; - let errorsResults = this.props.errorsResults; - let headingLevel = this.props.headingLevel; - let errorsFound = errorsResults.length; - let problemsFound = problemsResults.length; - let improvementsFound = improvementsResults.length; - let considerationsFound = considerationsResults.length; - let goodResultsFound = goodResults.length; + const { + problemsResults, + improvementsResults, + goodResults, + considerationsResults, + errorsResults, + headingLevel, + helpText, + } = this.props; + const errorsFound = errorsResults.length; + const problemsFound = problemsResults.length; + const improvementsFound = improvementsResults.length; + const considerationsFound = considerationsResults.length; + const goodResultsFound = goodResults.length; // Analysis collapsibles are only rendered when there is at least one analysis result for that category present. return ( + { helpText && } { this.renderLanguageNotice() } { errorsFound > 0 && { - const component = createComponentWithIntl( - - ); - - let tree = component.toJSON(); - expect( tree ).toMatchSnapshot(); -} ); +describe( "ContentAnalysis", () => { + it( "the ContentAnalysis component without language notice matches the snapshot", () => { + const component = createComponentWithIntl( + + ); -test( "the ContentAnalysis component without problems matches the snapshot", () => { - const component = createComponentWithIntl( - - ); - - let tree = component.toJSON(); - expect( tree ).toMatchSnapshot(); -} ); + let tree = component.toJSON(); + expect( tree ).toMatchSnapshot(); + } ); -test( "the ContentAnalysis component without problems and improvements matches the snapshot", () => { - const component = createComponentWithIntl( - - ); - - let tree = component.toJSON(); - expect( tree ).toMatchSnapshot(); -} ); + it( "the ContentAnalysis component without problems matches the snapshot", () => { + const component = createComponentWithIntl( + + ); -test( "the ContentAnalysis component without problems, improvements and considerations matches the snapshot", () => { - const component = createComponentWithIntl( - - ); - - let tree = component.toJSON(); - expect( tree ).toMatchSnapshot(); -} ); + let tree = component.toJSON(); + expect( tree ).toMatchSnapshot(); + } ); -test( "the ContentAnalysis component without problems and considerations, but with improvements and good matches the snapshot", () => { - const component = createComponentWithIntl( - - ); - - let tree = component.toJSON(); - expect( tree ).toMatchSnapshot(); -} ); + it( "the ContentAnalysis component without problems and improvements matches the snapshot", () => { + const component = createComponentWithIntl( + + ); -test( "the ContentAnalysis component with specified header level matches the snapshot", () => { - const component = createComponentWithIntl( - - ); - - let tree = component.toJSON(); - expect( tree ).toMatchSnapshot(); -} ); + let tree = component.toJSON(); + expect( tree ).toMatchSnapshot(); + } ); -test( "the ContentAnalysis component with language notice matches the snapshot", () => { - const component = createComponentWithIntl( - - ); - - let tree = component.toJSON(); - expect( tree ).toMatchSnapshot(); -} ); + it( "the ContentAnalysis component without problems, improvements and considerations matches the snapshot", () => { + const component = createComponentWithIntl( + + ); -test( "the ContentAnalysis component with language notice for someone who can change the language matches the snapshot", () => { - const component = createComponentWithIntl( - - ); - - let tree = component.toJSON(); - expect( tree ).toMatchSnapshot(); -} ); + let tree = component.toJSON(); + expect( tree ).toMatchSnapshot(); + } ); -test( "the ContentAnalysis component with language notice for someone who cannot change the language matches the snapshot", () => { - const component = createComponentWithIntl( - - ); - - let tree = component.toJSON(); - expect( tree ).toMatchSnapshot(); -} ); + it( "the ContentAnalysis component without problems and considerations, but with improvements and good matches the snapshot", () => { + const component = createComponentWithIntl( + + ); -test( "the ContentAnalysis component with disabled buttons matches the snapshot", () => { - const component = createComponentWithIntl( - - ); - - let tree = component.toJSON(); - expect( tree ).toMatchSnapshot(); -} ); + let tree = component.toJSON(); + expect( tree ).toMatchSnapshot(); + } ); + + it( "the ContentAnalysis component with specified header level matches the snapshot", () => { + const component = createComponentWithIntl( + + ); + + let tree = component.toJSON(); + expect( tree ).toMatchSnapshot(); + } ); + + it( "the ContentAnalysis component with language notice matches the snapshot", () => { + const component = createComponentWithIntl( + + ); + + let tree = component.toJSON(); + expect( tree ).toMatchSnapshot(); + } ); + + it( "the ContentAnalysis component with language notice for someone who can change the language matches the snapshot", () => { + const component = createComponentWithIntl( + + ); + + let tree = component.toJSON(); + expect( tree ).toMatchSnapshot(); + } ); + + it( "the ContentAnalysis component with language notice for someone who cannot change the language matches the snapshot", () => { + const component = createComponentWithIntl( + + ); + + let tree = component.toJSON(); + expect( tree ).toMatchSnapshot(); + } ); + + it( "the ContentAnalysis component with disabled buttons matches the snapshot", () => { + const component = createComponentWithIntl( + + ); + + let tree = component.toJSON(); + expect( tree ).toMatchSnapshot(); + } ); + + it( "the ContentAnalysis component with hidden buttons matches the snapshot", () => { + const component = createComponentWithIntl( + + ); + + let tree = component.toJSON(); + expect( tree ).toMatchSnapshot(); + } ); + + it( "the ContentAnalysis component with HelpText matches the snapshot", () => { + const component = createComponentWithIntl( + with a link, + " and some more text.", + ] } + /> + ); -test( "the ContentAnalysis component with hidden buttons matches the snapshot", () => { - const component = createComponentWithIntl( - - ); - - let tree = component.toJSON(); - expect( tree ).toMatchSnapshot(); + let tree = component.toJSON(); + expect( tree ).toMatchSnapshot(); + } ); } ); diff --git a/composites/Plugin/ContentAnalysis/tests/__snapshots__/ContentAnalysisTest.js.snap b/composites/Plugin/ContentAnalysis/tests/__snapshots__/ContentAnalysisTest.js.snap index 528d4c75..5e96d239 100644 --- a/composites/Plugin/ContentAnalysis/tests/__snapshots__/ContentAnalysisTest.js.snap +++ b/composites/Plugin/ContentAnalysis/tests/__snapshots__/ContentAnalysisTest.js.snap @@ -1,6 +1,650 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`the ContentAnalysis component with disabled buttons matches the snapshot 1`] = ` +exports[`ContentAnalysis the ContentAnalysis component with HelpText matches the snapshot 1`] = ` +.c18 { + box-sizing: border-box; + min-width: 32px; + display: inline-block; + border: 1px solid #ccc; + background-color: #f7f7f7; + box-shadow: 0 1px 0 rgba( 204,204,204,0.7 ); + border-radius: 3px; + cursor: pointer; + padding: 0; + height: 24px; +} + +.c18:hover { + border-color: #fff; +} + +.c18:disabled { + background-color: #f7f7f7; + box-shadow: none; + border: none; + cursor: default; +} + +.c14 { + min-height: 24px; + padding: 0 4px 0 0; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; +} + +.c15 { + margin-top: 3px; + position: relative; + left: -1px; +} + +.c17 { + margin: 0 8px 0 11px; + -webkit-flex: 1 1 auto; + -ms-flex: 1 1 auto; + flex: 1 1 auto; +} + +.c10 { + color: #555; + border-color: #ccc; + background: #f7f7f7; + box-shadow: 0 1px 0 rgba( 204,204,204,1 ); +} + +.c5 { + font-size: 0.8rem; +} + +.c6:active { + box-shadow: inset 0 2px 5px -3px rgba( 0,0,0,0.5 ); +} + +.c7:hover { + color: #000; +} + +.c8::-moz-focus-inner { + border-width: 0; +} + +.c8:focus { + outline: none; + border-color: #0066cd; + box-shadow: 0 0 3px rgba( 8,74,103,0.8 ); +} + +.c9 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + vertical-align: middle; + border-width: 1px; + border-style: solid; + margin: 0; + padding: 4px 10px; + border-radius: 3px; + cursor: pointer; + box-sizing: border-box; + font-size: inherit; + font-family: inherit; + font-weight: inherit; + text-align: left; + overflow: visible; + min-height: 32px; +} + +.c9 svg { + -webkit-align-self: center; + -ms-flex-item-align: center; + align-self: center; +} + +.c2 { + background-color: #fff; +} + +.c12 { + white-space: nowrap; + text-overflow: ellipsis; + overflow-x: hidden; + -ms-flex-positive: 1; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; + font-size: 1.03em; + font-weight: 600; +} + +.c3 { + margin: 0; + font-weight: normal; +} + +.c4 { + width: 100%; + background-color: #fff; + padding: 0; + border-color: transparent; + border-radius: 0; + outline: none; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + box-shadow: none; + color: #0066cd; +} + +.c4:hover { + border-color: transparent; + color: #0066cd; +} + +.c4:active { + box-shadow: none; + background-color: #fff; + color: #0066cd; +} + +.c4 svg { + margin: 0 8px 0 -5px; + padding-bottom: 2px; + width: 20px; + height: 20px; +} + +.c4 span { + margin: 8px 0; + word-wrap: break-word; + font-size: 1.25em; + line-height: 1.25; + font-weight: inherit; +} + +.c13 { + margin: 0; + list-style: none; + padding: 0 16px 0 0; +} + +.c1 { + color: #646464; + font-size: 0.9em; +} + +.c0 { + width: 100%; + background-color: white; + max-width: 800px; + margin: 0 auto; +} + +.c11 { + width: 16px; + height: 16px; + -webkit-flex: none; + -ms-flex: none; + flex: none; +} + +.c16 { + width: 13px; + height: 13px; + -webkit-flex: none; + -ms-flex: none; + flex: none; +} + +.c19 { + width: 18px; + height: 18px; + -webkit-flex: none; + -ms-flex: none; + flex: none; +} + +@media all and ( -ms-high-contrast:none ),( -ms-high-contrast:active ) { + .c9::after { + display: inline-block; + content: ""; + min-height: 22px; + } +} + +
+

+ This is a text to help you + + with a link + + and some more text. +

+
+

+ +

+
    +
  • + + + +

    +

  • +
+
+
+

+ +

+
    +
  • + + + +

    + +

  • +
+
+
+

+ +

+
    +
  • + + + +

    +

  • +
+
+
+

+ +

+
    +
  • + + + +

    +

  • +
+
+
+

+ +

+
    +
  • + + + +

    +

  • +
  • + + + +

    + +

  • +
+
+
+`; + +exports[`ContentAnalysis the ContentAnalysis component with disabled buttons matches the snapshot 1`] = ` .c18 { box-sizing: border-box; min-width: 32px; @@ -645,7 +1289,7 @@ exports[`the ContentAnalysis component with disabled buttons matches the snapsho `; -exports[`the ContentAnalysis component with hidden buttons matches the snapshot 1`] = ` +exports[`ContentAnalysis the ContentAnalysis component with hidden buttons matches the snapshot 1`] = ` .c14 { min-height: 24px; padding: 0 4px 0 0; @@ -1210,7 +1854,7 @@ exports[`the ContentAnalysis component with hidden buttons matches the snapshot `; -exports[`the ContentAnalysis component with language notice for someone who can change the language matches the snapshot 1`] = ` +exports[`ContentAnalysis the ContentAnalysis component with language notice for someone who can change the language matches the snapshot 1`] = ` .c3 { border: 0; -webkit-clip: rect(1px,1px,1px,1px); @@ -1891,26 +2535,8 @@ exports[`the ContentAnalysis component with language notice for someone who can `; -exports[`the ContentAnalysis component with language notice for someone who cannot change the language matches the snapshot 1`] = ` -.c3 { - border: 0; - -webkit-clip: rect(1px,1px,1px,1px); - clip: rect(1px,1px,1px,1px); - -webkit-clip-path: inset(50%); - clip-path: inset(50%); - height: 1px; - margin: -1px; - overflow: hidden; - padding: 0; - position: absolute !important; - width: 1px; - word-wrap: normal !important; - -webkit-transform: translateY(1em); - -ms-transform: translateY(1em); - transform: translateY(1em); -} - -.c20 { +exports[`ContentAnalysis the ContentAnalysis component with language notice for someone who cannot change the language matches the snapshot 1`] = ` +.c18 { box-sizing: border-box; min-width: 32px; display: inline-block; @@ -1923,18 +2549,18 @@ exports[`the ContentAnalysis component with language notice for someone who cann height: 24px; } -.c20:hover { +.c18:hover { border-color: #fff; } -.c20:disabled { +.c18:disabled { background-color: #f7f7f7; box-shadow: none; border: none; cursor: default; } -.c16 { +.c14 { min-height: 24px; padding: 0 4px 0 0; display: -webkit-box; @@ -1947,49 +2573,49 @@ exports[`the ContentAnalysis component with language notice for someone who cann align-items: flex-start; } -.c17 { +.c15 { margin-top: 3px; position: relative; left: -1px; } -.c19 { +.c17 { margin: 0 8px 0 11px; -webkit-flex: 1 1 auto; -ms-flex: 1 1 auto; flex: 1 1 auto; } -.c12 { +.c10 { color: #555; border-color: #ccc; background: #f7f7f7; box-shadow: 0 1px 0 rgba( 204,204,204,1 ); } -.c7 { +.c5 { font-size: 0.8rem; } -.c8:active { +.c6:active { box-shadow: inset 0 2px 5px -3px rgba( 0,0,0,0.5 ); } -.c9:hover { +.c7:hover { color: #000; } -.c10::-moz-focus-inner { +.c8::-moz-focus-inner { border-width: 0; } -.c10:focus { +.c8:focus { outline: none; border-color: #0066cd; box-shadow: 0 0 3px rgba( 8,74,103,0.8 ); } -.c11 { +.c9 { display: -webkit-inline-box; display: -webkit-inline-flex; display: -ms-inline-flexbox; @@ -2018,17 +2644,17 @@ exports[`the ContentAnalysis component with language notice for someone who cann min-height: 32px; } -.c11 svg { +.c9 svg { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; } -.c4 { +.c2 { background-color: #fff; } -.c14 { +.c12 { white-space: nowrap; text-overflow: ellipsis; overflow-x: hidden; @@ -2041,12 +2667,12 @@ exports[`the ContentAnalysis component with language notice for someone who cann font-weight: 600; } -.c5 { +.c3 { margin: 0; font-weight: normal; } -.c6 { +.c4 { width: 100%; background-color: #fff; padding: 0; @@ -2061,25 +2687,25 @@ exports[`the ContentAnalysis component with language notice for someone who cann color: #0066cd; } -.c6:hover { +.c4:hover { border-color: transparent; color: #0066cd; } -.c6:active { +.c4:active { box-shadow: none; background-color: #fff; color: #0066cd; } -.c6 svg { +.c4 svg { margin: 0 8px 0 -5px; padding-bottom: 2px; width: 20px; height: 20px; } -.c6 span { +.c4 span { margin: 8px 0; word-wrap: break-word; font-size: 1.25em; @@ -2087,7 +2713,7 @@ exports[`the ContentAnalysis component with language notice for someone who cann font-weight: inherit; } -.c15 { +.c13 { margin: 0; list-style: none; padding: 0 16px 0 0; @@ -2106,12 +2732,7 @@ exports[`the ContentAnalysis component with language notice for someone who cann margin-left: 24px; } -.c2 { - color: #0066cd; - margin-left: 4px; -} - -.c13 { +.c11 { width: 16px; height: 16px; -webkit-flex: none; @@ -2119,7 +2740,7 @@ exports[`the ContentAnalysis component with language notice for someone who cann flex: none; } -.c18 { +.c16 { width: 13px; height: 13px; -webkit-flex: none; @@ -2127,7 +2748,7 @@ exports[`the ContentAnalysis component with language notice for someone who cann flex: none; } -.c21 { +.c19 { width: 18px; height: 18px; -webkit-flex: none; @@ -2136,7 +2757,7 @@ exports[`the ContentAnalysis component with language notice for someone who cann } @media all and ( -ms-high-contrast:none ),( -ms-high-contrast:active ) { - .c11::after { + .c9::after { display: inline-block; content: ""; min-height: 22px; @@ -2154,37 +2775,24 @@ exports[`the ContentAnalysis component with language notice for someone who cann English - . + . If this is not correct, contact your site administrator. - - Change language - - (Opens in a new browser tab) - -

  • `; -exports[`the ContentAnalysis component with language notice matches the snapshot 1`] = ` +exports[`ContentAnalysis the ContentAnalysis component with language notice matches the snapshot 1`] = ` .c18 { box-sizing: border-box; min-width: 32px; @@ -3217,7 +3825,7 @@ exports[`the ContentAnalysis component with language notice matches the snapshot

`; -exports[`the ContentAnalysis component with specified header level matches the snapshot 1`] = ` +exports[`ContentAnalysis the ContentAnalysis component with specified header level matches the snapshot 1`] = ` .c17 { box-sizing: border-box; min-width: 32px; @@ -3845,7 +4453,7 @@ exports[`the ContentAnalysis component with specified header level matches the s `; -exports[`the ContentAnalysis component without language notice matches the snapshot 1`] = ` +exports[`ContentAnalysis the ContentAnalysis component without language notice matches the snapshot 1`] = ` .c17 { box-sizing: border-box; min-width: 32px; @@ -4473,7 +5081,7 @@ exports[`the ContentAnalysis component without language notice matches the snaps `; -exports[`the ContentAnalysis component without problems and considerations, but with improvements and good matches the snapshot 1`] = ` +exports[`ContentAnalysis the ContentAnalysis component without problems and considerations, but with improvements and good matches the snapshot 1`] = ` .c17 { box-sizing: border-box; min-width: 32px; @@ -4947,7 +5555,7 @@ exports[`the ContentAnalysis component without problems and considerations, but `; -exports[`the ContentAnalysis component without problems and improvements matches the snapshot 1`] = ` +exports[`ContentAnalysis the ContentAnalysis component without problems and improvements matches the snapshot 1`] = ` .c17 { box-sizing: border-box; min-width: 32px; @@ -5421,7 +6029,7 @@ exports[`the ContentAnalysis component without problems and improvements matches `; -exports[`the ContentAnalysis component without problems matches the snapshot 1`] = ` +exports[`ContentAnalysis the ContentAnalysis component without problems matches the snapshot 1`] = ` .c17 { box-sizing: border-box; min-width: 32px; @@ -5960,7 +6568,7 @@ exports[`the ContentAnalysis component without problems matches the snapshot 1`] `; -exports[`the ContentAnalysis component without problems, improvements and considerations matches the snapshot 1`] = ` +exports[`ContentAnalysis the ContentAnalysis component without problems, improvements and considerations matches the snapshot 1`] = ` .c17 { box-sizing: border-box; min-width: 32px; diff --git a/composites/Plugin/Shared/components/HelpText.js b/composites/Plugin/Shared/components/HelpText.js new file mode 100644 index 00000000..0b4b371d --- /dev/null +++ b/composites/Plugin/Shared/components/HelpText.js @@ -0,0 +1,50 @@ +/* External dependencies */ +import React from "react"; +import PropTypes from "prop-types"; +import styled from "styled-components"; + +/* Internal dependencies */ +import colors from "../../../../style-guide/colors"; + +const YoastHelpText = styled.p` + color: ${ colors.$color_grey_text }; + font-size: 0.9em; +`; + +/** + * Returns the HelpText component. + * + * @param {Object} props Component props. + * + * @returns {ReactElement} HelpText component. + */ +export default class HelpText extends React.Component { + /** + * Renders a help text component. + * + * @returns {ReactElement} The rendered help text component. + */ + render() { + const { text } = this.props; + + return ( + + { text } + + ); + } +} + +/** + * React prop type for the help text. + * + * Use this in your components to pass along the text. + */ +export const HelpTextPropType = PropTypes.oneOfType( [ + PropTypes.string, + PropTypes.array, +] ); + +HelpText.propTypes = { + text: HelpTextPropType.isRequired, +}; diff --git a/composites/Plugin/Shared/tests/HelpTextTest.js b/composites/Plugin/Shared/tests/HelpTextTest.js new file mode 100644 index 00000000..1d4117d1 --- /dev/null +++ b/composites/Plugin/Shared/tests/HelpTextTest.js @@ -0,0 +1,26 @@ +/* External dependencies */ +import React from "react"; +import renderer from "react-test-renderer"; + +/* Internal dependencies */ +import HelpText from "../components/HelpText"; + +describe( "HelpText", () => { + it( "matches the snapshot by default", () => { + const component = renderer.create( + + ); + + let tree = component.toJSON(); + expect( tree ).toMatchSnapshot(); + } ); + + it( "matches the snapshot when an array is provided as text", () => { + const component = renderer.create( + with a link", " in the middle." ] } /> + ); + + let tree = component.toJSON(); + expect( tree ).toMatchSnapshot(); + } ); +} ); diff --git a/composites/Plugin/Shared/tests/__snapshots__/HelpTextTest.js.snap b/composites/Plugin/Shared/tests/__snapshots__/HelpTextTest.js.snap new file mode 100644 index 00000000..95cd3e88 --- /dev/null +++ b/composites/Plugin/Shared/tests/__snapshots__/HelpTextTest.js.snap @@ -0,0 +1,29 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`HelpText matches the snapshot by default 1`] = ` +.c0 { + color: #646464; + font-size: 0.9em; +} + +

+ Some help text. +

+`; + +exports[`HelpText matches the snapshot when an array is provided as text 1`] = ` +.c0 { + color: #646464; + font-size: 0.9em; +} + +

+ Text + <a href="https://www.example.com">with a link</a> + in the middle. +

+`;