From 29559a13261071ae7fa0bf5cdf90da91ffec1fe9 Mon Sep 17 00:00:00 2001 From: CM Lubinski Date: Wed, 4 Oct 2017 15:40:02 -0400 Subject: [PATCH 1/4] Turn off lint warnings about import names. We use a pattern of export MyComponent = ... default export withRouter(MyComponent) Relatively often, and we *intentionally* import the wrapped version as "MyComponent". --- ui/.eslintrc | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/.eslintrc b/ui/.eslintrc index 74a949123..138b0b50b 100644 --- a/ui/.eslintrc +++ b/ui/.eslintrc @@ -17,6 +17,7 @@ /* TODO: These rules should be packaged */ "no-unsafe-innerhtml/no-unsafe-innerhtml" : 2, "react/jsx-filename-extension": [1, {"extensions": [".js", ".jsx"]}], + "import/no-named-as-default": 0, "scanjs-rules/assign_to_hostname" : 2, "scanjs-rules/assign_to_href" : 2, "scanjs-rules/assign_to_location" : 2, From c2b4d0db59a54eb4a0a200d61e4d89f137bf6978 Mon Sep 17 00:00:00 2001 From: CM Lubinski Date: Thu, 5 Oct 2017 09:10:38 -0400 Subject: [PATCH 2/4] Refactor search component to contain fewer styles. We want to re-use this component on the home page, but we'll need to restyle it. We can use the same markup if we pull the styles out into the stylesheet. --- ui/components/navbar.js | 12 ++++++--- ui/components/search/search.js | 47 +++++++++++++++++--------------- ui/css/_header.scss | 49 ++++++++++++++++++++++++++++++++++ ui/css/_search.scss | 38 -------------------------- ui/css/main.scss | 1 - 5 files changed, 83 insertions(+), 64 deletions(-) delete mode 100644 ui/css/_search.scss diff --git a/ui/components/navbar.js b/ui/components/navbar.js index 530db8930..4c8d050f1 100644 --- a/ui/components/navbar.js +++ b/ui/components/navbar.js @@ -1,15 +1,21 @@ import PropTypes from 'prop-types'; import React from 'react'; -import SearchContainer from './search/search'; +import Search from './search/search'; import { Link } from '../routes'; export default function Navbar({ showSearch }) { let searchContainer; if (showSearch) { - searchContainer = ; + const buttonContent = ( + Submit search + ); + searchContainer = ( +
+ +
+ ); } - return (
diff --git a/ui/components/search/search.js b/ui/components/search/search.js index 1c89ff899..4bd1d7550 100644 --- a/ui/components/search/search.js +++ b/ui/components/search/search.js @@ -52,36 +52,39 @@ export class Search extends React.Component { render() { return ( -
-
- - {this.hiddenFields()} - -
-
+
+ + {this.hiddenFields()} + +
); } } Search.propTypes = { + buttonContent: PropTypes.node, + placeholder: PropTypes.string, router: PropTypes.shape({ pathname: PropTypes.string.isRequired, query: PropTypes.shape({}).isRequired, }).isRequired, }; +Search.defaultProps = { + buttonContent: null, + placeholder: 'Search', +}; export default withRouter(Search); diff --git a/ui/css/_header.scss b/ui/css/_header.scss index 81649375b..0cb01293a 100644 --- a/ui/css/_header.scss +++ b/ui/css/_header.scss @@ -48,3 +48,52 @@ padding-left: 1rem; } } + +.header-search-form { + @extend .pr2; + @extend .no-print; + position: absolute; + right: 0; + + form { + @extend .mb0; + @extend .flex; + @extend .items-center; + } + + .search-input { + @extend .gray-border; + @include font-source-sans-pro(); + border: 1px solid; + border-right: 0; + border-bottom-left-radius: 5px; + border-top-left-radius: 5px; + font-size: 0.75rem; + padding: 0.54rem; + width: 20rem; + } + + .search-submit { + @extend .gray-border; + background-color: $color-white; + border: 1px solid; + border-left: 0; + border-bottom-right-radius: 5px; + border-top-right-radius: 5px; + padding: 0.54rem; + } +} + +@media (max-width: 52em) { + .header-search-form { + position: relative; + + .search-input { + padding: 0.56rem; + } + + .search-submit { + padding: 0.57rem; + } + } +} diff --git a/ui/css/_search.scss b/ui/css/_search.scss deleted file mode 100644 index 92d8d464a..000000000 --- a/ui/css/_search.scss +++ /dev/null @@ -1,38 +0,0 @@ -.search-form { - position: absolute; - right: 0; - - .search-input { - @include font-source-sans-pro(); - border: 1px solid; - border-right: 0; - border-bottom-left-radius: 5px; - border-top-left-radius: 5px; - font-size: 0.75rem; - padding: 0.54rem; - width: 20rem; - } - - .search-submit { - background-color: $color-white; - border: 1px solid; - border-left: 0; - border-bottom-right-radius: 5px; - border-top-right-radius: 5px; - padding: 0.54rem; - } -} - -@media (max-width: 52em) { - .search-form { - position: relative; - - .search-input { - padding: 0.56rem; - } - - .search-submit { - padding: 0.57rem; - } - } -} diff --git a/ui/css/main.scss b/ui/css/main.scss index 60e505006..f3c61e4f0 100644 --- a/ui/css/main.scss +++ b/ui/css/main.scss @@ -30,4 +30,3 @@ @import 'policies'; @import 'homepage'; @import 'loading-indicator'; -@import 'search'; From 4d781fcc71880515b7d1cc9b69e50a474e2b1717 Mon Sep 17 00:00:00 2001 From: CM Lubinski Date: Thu, 5 Oct 2017 09:12:49 -0400 Subject: [PATCH 3/4] Swap search box on homepage for full-text search. Previously, we had been searching over topics, but that proved confusing for our users. This reuses the existing Search component (which appears on the top of each page) but with slightly different styles. This does not resolve the multiple search boxes issue (#513). --- ui/css/_button-like.scss | 1 + ui/css/_homepage.scss | 12 ++++++++++++ ui/pages/index.js | 33 +++++---------------------------- 3 files changed, 18 insertions(+), 28 deletions(-) diff --git a/ui/css/_button-like.scss b/ui/css/_button-like.scss index c79cfc097..ff25df3a7 100644 --- a/ui/css/_button-like.scss +++ b/ui/css/_button-like.scss @@ -5,4 +5,5 @@ color: $color-white; background-color: $color-primary; + border-color: $color-white; } diff --git a/ui/css/_homepage.scss b/ui/css/_homepage.scss index f050582ed..c89a73206 100644 --- a/ui/css/_homepage.scss +++ b/ui/css/_homepage.scss @@ -27,6 +27,18 @@ border-top: 1px solid $color-gray-light; border-bottom: 1px solid $color-gray-light; } + + .search-input { + @extend .p1; + @extend .col-3; + @extend .mr1; + } + + .search-submit { + @extend .button-like; + @extend .border; + @extend .h5; + } } @media (max-width: 52em) { diff --git a/ui/pages/index.js b/ui/pages/index.js index 254d5efaa..390b86dae 100644 --- a/ui/pages/index.js +++ b/ui/pages/index.js @@ -2,10 +2,8 @@ import PropTypes from 'prop-types'; import React from 'react'; import wrapPage from '../components/app-wrapper'; -import ConditionalRender from '../components/conditional-render'; -import FallbackView from '../components/filters/fallback-view'; -import TopicAutocomplete from '../components/homepage/topic-autocomplete'; import NewPolicyView from '../components/homepage/new-policy-view'; +import Search from '../components/search/search'; import { homepageData } from '../queries'; @@ -13,32 +11,11 @@ export function Homepage({ recentPolicies }) { return (
-
+

Find policies and requirements that apply to your agency.

-
-

What topics are you interested in?

- -
- -
-
-
- -
-
- -
-
-
+
+

What are you interested in finding?

+
From c9d22cfa8437926340eac193dff7807c88fdbc07 Mon Sep 17 00:00:00 2001 From: CM Lubinski Date: Thu, 5 Oct 2017 10:13:02 -0400 Subject: [PATCH 4/4] Add tests for new properties on search component. --- ui/__tests__/components/search/search.test.js | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/ui/__tests__/components/search/search.test.js b/ui/__tests__/components/search/search.test.js index fc3923e2a..1d383b324 100644 --- a/ui/__tests__/components/search/search.test.js +++ b/ui/__tests__/components/search/search.test.js @@ -3,6 +3,9 @@ import React from 'react'; import { Search } from '../../../components/search/search'; +const blankRouter = { pathname: '', query: {} }; + + describe('', () => { describe('actionPath()', () => { it('returns /requirements/ by default', () => { @@ -99,4 +102,37 @@ describe('', () => { }); }); }); + + describe('buttonContent prop', () => { + it('can be a React.Component', () => { + const params = { + buttonContent:
Content!
, + router: blankRouter, + }; + const rendered = shallow(); + expect(rendered.find('button .content-here')).toHaveLength(1); + const content = rendered.find('button .content-here').first(); + expect(content.text()).toEqual('Content!'); + expect(content.name()).toEqual('div'); + }); + + it('can be plain text', () => { + const params = { buttonContent: 'I am a button', router: blankRouter }; + const button = shallow().find('button').first(); + expect(button.text()).toEqual('I am a button'); + }); + }); + + describe('placeholder prop', () => { + it('has a sane default', () => { + const input = shallow() + .find('[type="text"]').first(); + expect(input.prop('placeholder')).toEqual('Search'); + }); + it('can be configured', () => { + const input = shallow() + .find('[type="text"]').first(); + expect(input.prop('placeholder')).toEqual('Hiya!'); + }); + }); });