From 667bbbebfa8cc58c21888329a913492a61a86a38 Mon Sep 17 00:00:00 2001
From: Paul Melnikow <github@paulmelnikow.com>
Date: Fri, 8 Mar 2019 00:02:23 -0500
Subject: [PATCH] Rewrite a bunch of components as functions, with consistent
 func style (#3177)

---
 frontend/components/badge-examples.js      | 121 ++--
 frontend/components/category-headings.js   |  46 +-
 frontend/components/common.js              |  48 +-
 frontend/components/dynamic-badge-maker.js |   6 +-
 frontend/components/footer.js              | 145 ++---
 frontend/components/header.js              |  26 +-
 frontend/components/meta.js                |  30 +-
 frontend/components/snippet.js             |  20 +-
 frontend/components/static-badge-maker.js  |   3 +-
 frontend/components/usage.js               | 652 ++++++++++-----------
 10 files changed, 550 insertions(+), 547 deletions(-)

diff --git a/frontend/components/badge-examples.js b/frontend/components/badge-examples.js
index d6e9efd353..f5aafed59b 100644
--- a/frontend/components/badge-examples.js
+++ b/frontend/components/badge-examples.js
@@ -5,7 +5,10 @@ import {
   badgeUrlFromPath,
   staticBadgeUrl,
 } from '../../core/badge-urls/make-badge-url'
-import { serviceDefinitionPropType } from '../lib/service-definitions/service-definition-prop-types'
+import {
+  serviceDefinitionPropType,
+  examplePropType,
+} from '../lib/service-definitions/service-definition-prop-types'
 import { Badge } from './common'
 import { StyledCode } from './snippet'
 
@@ -27,66 +30,70 @@ const ClickableCode = styled(StyledCode)`
   cursor: pointer;
 `
 
-export default class BadgeExamples extends React.Component {
-  static propTypes = {
-    definitions: PropTypes.arrayOf(serviceDefinitionPropType).isRequired,
-    baseUrl: PropTypes.string,
-    onClick: PropTypes.func.isRequired,
-  }
-
-  renderExample(exampleData) {
-    const { baseUrl, onClick } = this.props
-    const { title, example, preview } = exampleData
-
-    const { label, message, color, style, namedLogo } = preview
-    const previewUrl = staticBadgeUrl({
-      baseUrl,
-      label,
-      message,
-      color,
-      style,
-      namedLogo,
-    })
-
-    const { pattern, namedParams, queryParams } = example
-    const exampleUrl = badgeUrlFromPath({
-      baseUrl,
-      path: pattern,
-      namedParams,
-      queryParams,
-    })
+function Example({ baseUrl, onClick, exampleData }) {
+  const { title, example, preview } = exampleData
 
-    const key = `${title} ${previewUrl} ${exampleUrl}`
+  const { label, message, color, style, namedLogo } = preview
+  const previewUrl = staticBadgeUrl({
+    baseUrl,
+    label,
+    message,
+    color,
+    style,
+    namedLogo,
+  })
 
-    const handleClick = () => onClick(exampleData)
+  const { pattern, namedParams, queryParams } = example
+  const exampleUrl = badgeUrlFromPath({
+    baseUrl,
+    path: pattern,
+    namedParams,
+    queryParams,
+  })
 
-    return (
-      <tr key={key}>
-        <ClickableTh onClick={handleClick}>{title}:</ClickableTh>
-        <td>
-          <Badge clickable onClick={handleClick} src={previewUrl} />
-        </td>
-        <td>
-          <ClickableCode onClick={handleClick}>{exampleUrl}</ClickableCode>
-        </td>
-      </tr>
-    )
-  }
+  const handleClick = () => onClick(exampleData)
 
-  render() {
-    const { definitions } = this.props
+  return (
+    <tr>
+      <ClickableTh onClick={handleClick}>{title}:</ClickableTh>
+      <td>
+        <Badge clickable onClick={handleClick} src={previewUrl} />
+      </td>
+      <td>
+        <ClickableCode onClick={handleClick}>{exampleUrl}</ClickableCode>
+      </td>
+    </tr>
+  )
+}
+Example.propTypes = {
+  exampleData: examplePropType.isRequired,
+  baseUrl: PropTypes.string,
+  onClick: PropTypes.func.isRequired,
+}
 
-    const flattened = definitions.reduce((accum, current) => {
-      const { examples } = current
-      return accum.concat(examples)
-    }, [])
+export default function BadgeExamples({ definitions, baseUrl, onClick }) {
+  const flattened = definitions.reduce((accum, current) => {
+    const { examples } = current
+    return accum.concat(examples)
+  }, [])
 
-    return (
-      <ExampleTable>
-        <tbody>
-          {flattened.map(exampleData => this.renderExample(exampleData))}
-        </tbody>
-      </ExampleTable>
-    )
-  }
+  return (
+    <ExampleTable>
+      <tbody>
+        {flattened.map(exampleData => (
+          <Example
+            baseUrl={baseUrl}
+            exampleData={exampleData}
+            key={`${exampleData.title} ${exampleData.example.pattern}`}
+            onClick={onClick}
+          />
+        ))}
+      </tbody>
+    </ExampleTable>
+  )
+}
+BadgeExamples.propTypes = {
+  definitions: PropTypes.arrayOf(serviceDefinitionPropType).isRequired,
+  baseUrl: PropTypes.string,
+  onClick: PropTypes.func.isRequired,
 }
diff --git a/frontend/components/category-headings.js b/frontend/components/category-headings.js
index 179779a6e9..fc32411eca 100644
--- a/frontend/components/category-headings.js
+++ b/frontend/components/category-headings.js
@@ -4,9 +4,7 @@ import styled from 'styled-components'
 import { Link } from 'gatsby'
 import { H3 } from './common'
 
-const CategoryHeading = ({ category }) => {
-  const { id, name } = category
-
+export function CategoryHeading({ category: { id, name } }) {
   return (
     <Link to={`/category/${id}`}>
       <H3 id={id}>{name}</H3>
@@ -20,13 +18,15 @@ CategoryHeading.propTypes = {
   }).isRequired,
 }
 
-const CategoryHeadings = ({ categories }) => (
-  <div>
-    {categories.map(category => (
-      <CategoryHeading category={category} key={category.id} />
-    ))}
-  </div>
-)
+export function CategoryHeadings({ categories }) {
+  return (
+    <div>
+      {categories.map(category => (
+        <CategoryHeading category={category} key={category.id} />
+      ))}
+    </div>
+  )
+}
 CategoryHeadings.propTypes = {
   categories: PropTypes.arrayOf(CategoryHeading.propTypes.category).isRequired,
 }
@@ -62,19 +62,19 @@ const StyledNav = styled.nav`
   }
 `
 
-const CategoryNav = ({ categories }) => (
-  <StyledNav>
-    <ul>
-      {categories.map(({ id, name }) => (
-        <li key={id}>
-          <Link to={`/category/${id}`}>{name}</Link>
-        </li>
-      ))}
-    </ul>
-  </StyledNav>
-)
+export function CategoryNav({ categories }) {
+  return (
+    <StyledNav>
+      <ul>
+        {categories.map(({ id, name }) => (
+          <li key={id}>
+            <Link to={`/category/${id}`}>{name}</Link>
+          </li>
+        ))}
+      </ul>
+    </StyledNav>
+  )
+}
 CategoryNav.propTypes = {
   categories: PropTypes.arrayOf(CategoryHeading.propTypes.category).isRequired,
 }
-
-export { CategoryHeading, CategoryHeadings, CategoryNav }
diff --git a/frontend/components/common.js b/frontend/components/common.js
index df80a253cb..552d177b1b 100644
--- a/frontend/components/common.js
+++ b/frontend/components/common.js
@@ -2,27 +2,27 @@ import React from 'react'
 import PropTypes from 'prop-types'
 import styled, { css, createGlobalStyle } from 'styled-components'
 
-const noAutocorrect = Object.freeze({
+export const noAutocorrect = Object.freeze({
   autoComplete: 'off',
   autoCorrect: 'off',
   autoCapitalize: 'off',
   spellCheck: 'false',
 })
 
-const nonBreakingSpace = '\u00a0'
+export const nonBreakingSpace = '\u00a0'
 
-const GlobalStyle = createGlobalStyle`
+export const GlobalStyle = createGlobalStyle`
   * {
     box-sizing: border-box;
   }
 `
 
-const BaseFont = styled.div`
+export const BaseFont = styled.div`
   font-family: Lekton, sans-serif;
   color: #534;
 `
 
-const H2 = styled.h2`
+export const H2 = styled.h2`
   font-style: italic;
 
   margin-top: 12mm;
@@ -37,7 +37,7 @@ const H2 = styled.h2`
   }
 `
 
-const H3 = styled.h3`
+export const H3 = styled.h3`
   font-style: italic;
 `
 
@@ -54,18 +54,20 @@ const BadgeWrapper = styled.span`
     `};
 `
 
-const Badge = ({
+export function Badge({
   src,
   alt = '',
   display = 'inline',
   height = '20px',
   clickable = false,
   ...rest
-}) => (
-  <BadgeWrapper clickable={clickable} display={display} height={height}>
-    {src ? <img alt={alt} src={src} {...rest} /> : nonBreakingSpace}
-  </BadgeWrapper>
-)
+}) {
+  return (
+    <BadgeWrapper clickable={clickable} display={display} height={height}>
+      {src ? <img alt={alt} src={src} {...rest} /> : nonBreakingSpace}
+    </BadgeWrapper>
+  )
+}
 Badge.propTypes = {
   src: PropTypes.string.isRequired,
   alt: PropTypes.string,
@@ -74,7 +76,7 @@ Badge.propTypes = {
   clickable: PropTypes.bool,
 }
 
-const StyledInput = styled.input`
+export const StyledInput = styled.input`
   height: 15px;
   border: solid #b9a;
   border-width: 0 0 1px 0;
@@ -89,33 +91,19 @@ const StyledInput = styled.input`
   }
 `
 
-const InlineInput = styled(StyledInput)`
+export const InlineInput = styled(StyledInput)`
   width: 70px;
   margin-left: 5px;
   margin-right: 5px;
 `
 
-const BlockInput = styled(StyledInput)`
+export const BlockInput = styled(StyledInput)`
   width: 40%;
   background-color: transparent;
 `
 
-const VerticalSpace = styled.hr`
+export const VerticalSpace = styled.hr`
   border: 0;
   display: block;
   height: 3mm;
 `
-
-export {
-  noAutocorrect,
-  nonBreakingSpace,
-  GlobalStyle,
-  BaseFont,
-  H2,
-  H3,
-  Badge,
-  StyledInput,
-  InlineInput,
-  BlockInput,
-  VerticalSpace,
-}
diff --git a/frontend/components/dynamic-badge-maker.js b/frontend/components/dynamic-badge-maker.js
index 4baf5d15f5..e68f4f12de 100644
--- a/frontend/components/dynamic-badge-maker.js
+++ b/frontend/components/dynamic-badge-maker.js
@@ -3,7 +3,9 @@ import PropTypes from 'prop-types'
 import { dynamicBadgeUrl } from '../../core/badge-urls/make-badge-url'
 import { InlineInput } from './common'
 
-function DynamicBadgeMaker({ baseUrl = document.location.href }) {
+export default function DynamicBadgeMaker({
+  baseUrl = document.location.href,
+}) {
   const [values, setValues] = useState({
     datatype: '',
     label: '',
@@ -62,6 +64,7 @@ function DynamicBadgeMaker({ baseUrl = document.location.href }) {
       </select>{' '}
       {inputs.map(({ name, placeholder = name }) => (
         <InlineInput
+          key={name}
           name={name}
           onChange={onChange}
           placeholder={placeholder}
@@ -72,7 +75,6 @@ function DynamicBadgeMaker({ baseUrl = document.location.href }) {
     </form>
   )
 }
-export default DynamicBadgeMaker
 DynamicBadgeMaker.propTypes = {
   baseUrl: PropTypes.string,
 }
diff --git a/frontend/components/footer.js b/frontend/components/footer.js
index 64fa8a9deb..57a00c7f49 100644
--- a/frontend/components/footer.js
+++ b/frontend/components/footer.js
@@ -9,81 +9,82 @@ const SpacedA = styled.a`
   margin-right: 10px;
 `
 
-const Footer = ({ baseUrl }) => (
-  <section>
-    <H2 id="like-this">Like This?</H2>
+export default function Footer({ baseUrl }) {
+  return (
+    <section>
+      <H2 id="like-this">Like This?</H2>
 
-    <p>
-      <object
-        alt="Follow @shields_io"
-        data={badgeUrlFromPath({
-          baseUrl,
-          path: '/twitter/follow/shields_io',
-          queryParams: { label: 'Follow' },
-          style: 'social',
-        })}
-      />{' '}
-      {}
-      <object
-        alt="Donate to us!"
-        data={badgeUrlFromPath({
-          baseUrl,
-          path: '/opencollective/backers/shields',
-          queryParams: { link: 'https://opencollective.com/shields' },
-          style: 'social',
-        })}
-      />{' '}
-      {}
-      <object
-        alt="Donate to us!"
-        data={badgeUrlFromPath({
-          baseUrl,
-          path: '/opencollective/sponsors/shields',
-          queryParams: { link: 'https://opencollective.com/shields' },
-          style: 'social',
-        })}
-      />{' '}
-      {}
-      <object
-        alt="Fork on GitHub"
-        data={badgeUrlFromPath({
-          baseUrl,
-          path: '/github/forks/badges/shields',
-          queryParams: { label: 'Fork' },
-          style: 'social',
-        })}
-      />{' '}
-      {}
-      <object
-        alt="chat on Discord"
-        data={badgeUrlFromPath({
-          baseUrl,
-          path: '/discord/308323056592486420',
-          queryParams: {
-            label: 'Chat',
-            link: 'https://discord.gg/HjJCwm5',
-          },
-          style: 'social',
-        })}
-      />
-    </p>
+      <p>
+        <object
+          alt="Follow @shields_io"
+          data={badgeUrlFromPath({
+            baseUrl,
+            path: '/twitter/follow/shields_io',
+            queryParams: { label: 'Follow' },
+            style: 'social',
+          })}
+        />{' '}
+        {}
+        <object
+          alt="Donate to us!"
+          data={badgeUrlFromPath({
+            baseUrl,
+            path: '/opencollective/backers/shields',
+            queryParams: { link: 'https://opencollective.com/shields' },
+            style: 'social',
+          })}
+        />{' '}
+        {}
+        <object
+          alt="Donate to us!"
+          data={badgeUrlFromPath({
+            baseUrl,
+            path: '/opencollective/sponsors/shields',
+            queryParams: { link: 'https://opencollective.com/shields' },
+            style: 'social',
+          })}
+        />{' '}
+        {}
+        <object
+          alt="Fork on GitHub"
+          data={badgeUrlFromPath({
+            baseUrl,
+            path: '/github/forks/badges/shields',
+            queryParams: { label: 'Fork' },
+            style: 'social',
+          })}
+        />{' '}
+        {}
+        <object
+          alt="chat on Discord"
+          data={badgeUrlFromPath({
+            baseUrl,
+            path: '/discord/308323056592486420',
+            queryParams: {
+              label: 'Chat',
+              link: 'https://discord.gg/HjJCwm5',
+            },
+            style: 'social',
+          })}
+        />
+      </p>
 
-    <p>
-      What is your favorite badge service to use?
-      <br />
-      <a href="https://github.com/badges/shields/blob/master/CONTRIBUTING.md">
-        Tell us
-      </a>{' '}
-      and we might bring it to you!
-    </p>
+      <p>
+        What is your favorite badge service to use?
+        <br />
+        <a href="https://github.com/badges/shields/blob/master/CONTRIBUTING.md">
+          Tell us
+        </a>{' '}
+        and we might bring it to you!
+      </p>
 
-    <p>
-      <SpacedA href="https://status.shields.io/">Status</SpacedA>
-      <SpacedA href="https://github.com/badges/shields">GitHub</SpacedA>
-    </p>
-  </section>
-)
-export default Footer
+      <p>
+        <SpacedA href="https://status.shields.io/">Status</SpacedA>
+        <SpacedA href="https://github.com/badges/shields">GitHub</SpacedA>
+      </p>
+    </section>
+  )
+}
 Footer.propTypes = {
   baseUrl: PropTypes.string.isRequired,
 }
diff --git a/frontend/components/header.js b/frontend/components/header.js
index 6256e793c6..e1c3d5a2b7 100644
--- a/frontend/components/header.js
+++ b/frontend/components/header.js
@@ -8,17 +8,19 @@ const Highlights = styled.p`
   font-style: italic;
 `
 
-export default () => (
-  <section>
-    <Link to="/">
-      <Logo />
-    </Link>
+export default function Header() {
+  return (
+    <section>
+      <Link to="/">
+        <Logo />
+      </Link>
 
-    <VerticalSpace />
+      <VerticalSpace />
 
-    <Highlights>
-      Pixel-perfect &nbsp; Retina-ready &nbsp; Fast &nbsp; Consistent &nbsp;
-      Hackable &nbsp; No tracking
-    </Highlights>
-  </section>
-)
+      <Highlights>
+        Pixel-perfect &nbsp; Retina-ready &nbsp; Fast &nbsp; Consistent &nbsp;
+        Hackable &nbsp; No tracking
+      </Highlights>
+    </section>
+  )
+}
diff --git a/frontend/components/meta.js b/frontend/components/meta.js
index 68b5be1281..98ce45e968 100644
--- a/frontend/components/meta.js
+++ b/frontend/components/meta.js
@@ -6,16 +6,20 @@ const description = `We serve fast and scalable informational images as badges
 for GitHub, Travis CI, Jenkins, WordPress and many more services. Use them to
 track the state of your projects, or for promotional purposes.`
 
-export default () => (
-  <Helmet>
-    <title>Shields.io: Quality metadata badges for open source projects</title>
-    <meta charSet="utf-8" />
-    <meta content="width=device-width,initial-scale=1" name="viewport" />
-    <meta content={description} name="description" />
-    <link href={favicon} rel="icon" type="image/png" />
-    <link
-      href="https://fonts.googleapis.com/css?family=Lato|Lekton"
-      rel="stylesheet"
-    />
-  </Helmet>
-)
+export default function Meta() {
+  return (
+    <Helmet>
+      <title>
+        Shields.io: Quality metadata badges for open source projects
+      </title>
+      <meta charSet="utf-8" />
+      <meta content="width=device-width,initial-scale=1" name="viewport" />
+      <meta content={description} name="description" />
+      <link href={favicon} rel="icon" type="image/png" />
+      <link
+        href="https://fonts.googleapis.com/css?family=Lato|Lekton"
+        rel="stylesheet"
+      />
+    </Helmet>
+  )
+}
diff --git a/frontend/components/snippet.js b/frontend/components/snippet.js
index b9d8971b78..d34c94ca4f 100644
--- a/frontend/components/snippet.js
+++ b/frontend/components/snippet.js
@@ -18,7 +18,7 @@ const CodeContainer = styled.span`
     `};
 `
 
-const StyledCode = styled.code`
+export const StyledCode = styled.code`
   line-height: 1.2em;
   padding: 0.1em 0.3em;
 
@@ -30,17 +30,17 @@ const StyledCode = styled.code`
   white-space: nowrap;
 `
 
-const Snippet = ({ snippet, truncate = false, fontSize }) => (
-  <CodeContainer truncate={truncate}>
-    <ClickToSelect>
-      <StyledCode fontSize={fontSize}>{snippet}</StyledCode>
-    </ClickToSelect>
-  </CodeContainer>
-)
+export function Snippet({ snippet, truncate = false, fontSize }) {
+  return (
+    <CodeContainer truncate={truncate}>
+      <ClickToSelect>
+        <StyledCode fontSize={fontSize}>{snippet}</StyledCode>
+      </ClickToSelect>
+    </CodeContainer>
+  )
+}
 Snippet.propTypes = {
   snippet: PropTypes.string.isRequired,
   truncate: PropTypes.bool,
   fontSize: PropTypes.string,
 }
-
-export { Snippet, StyledCode }
diff --git a/frontend/components/static-badge-maker.js b/frontend/components/static-badge-maker.js
index f4e3d8a785..57927106dc 100644
--- a/frontend/components/static-badge-maker.js
+++ b/frontend/components/static-badge-maker.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
 import { staticBadgeUrl } from '../../core/badge-urls/make-badge-url'
 import { InlineInput } from './common'
 
-function StaticBadgeMaker({ baseUrl = document.location.href }) {
+export default function StaticBadgeMaker({ baseUrl = document.location.href }) {
   const [values, setValues] = useState({
     label: '',
     message: '',
@@ -61,7 +61,6 @@ function StaticBadgeMaker({ baseUrl = document.location.href }) {
     </form>
   )
 }
-export default StaticBadgeMaker
 StaticBadgeMaker.propTypes = {
   baseUrl: PropTypes.string,
 }
diff --git a/frontend/components/usage.js b/frontend/components/usage.js
index d06d142252..a0b584f335 100644
--- a/frontend/components/usage.js
+++ b/frontend/components/usage.js
@@ -38,372 +38,372 @@ const QueryParamDocumentation = styled.td`
   text-align: left;
 `
 
-const QueryParam = ({ snippet, documentation }) => (
-  <tr>
-    <QueryParamSyntax>
-      <Snippet snippet={snippet} />
-    </QueryParamSyntax>
-    <QueryParamDocumentation>{documentation}</QueryParamDocumentation>
-  </tr>
-)
+function QueryParam({ snippet, documentation }) {
+  return (
+    <tr>
+      <QueryParamSyntax>
+        <Snippet snippet={snippet} />
+      </QueryParamSyntax>
+      <QueryParamDocumentation>{documentation}</QueryParamDocumentation>
+    </tr>
+  )
+}
 QueryParam.propTypes = {
   snippet: PropTypes.string.isRequired,
   documentation: PropTypes.element.isRequired,
 }
 
-const EscapingConversion = ({ lhs, rhs }) => (
-  <tr>
-    <Lhs>{lhs}</Lhs>
-    <td>→</td>
-    <td>{rhs}</td>
-  </tr>
-)
+function EscapingConversion({ lhs, rhs }) {
+  return (
+    <tr>
+      <Lhs>{lhs}</Lhs>
+      <td>→</td>
+      <td>{rhs}</td>
+    </tr>
+  )
+}
 EscapingConversion.propTypes = {
   lhs: PropTypes.element.isRequired,
   rhs: PropTypes.element.isRequired,
 }
 
-const ColorExamples = ({ baseUrl, colors }) => (
-  <span>
-    {colors.map((color, i) => (
-      <Badge
-        alt={color}
-        key={color}
-        src={staticBadgeUrl({ baseUrl, label: '', message: color, color })}
-      />
-    ))}
-  </span>
-)
+function ColorExamples({ baseUrl, colors }) {
+  return (
+    <span>
+      {colors.map((color, i) => (
+        <Badge
+          alt={color}
+          key={color}
+          src={staticBadgeUrl({ baseUrl, label: '', message: color, color })}
+        />
+      ))}
+    </span>
+  )
+}
 ColorExamples.propTypes = {
   baseUrl: PropTypes.string.isRequired,
   colors: PropTypes.array.isRequired,
 }
 
-export default class Usage extends React.PureComponent {
-  static propTypes = {
-    baseUrl: PropTypes.string.isRequired,
-  }
+function StyleExamples({ baseUrl }) {
+  return (
+    <QueryParamTable>
+      <tbody>
+        {advertisedStyles.map(style => {
+          const snippet = `?style=${style}&logo=appveyor`
+          const badgeUrl = staticBadgeUrl({
+            baseUrl,
+            label: 'style',
+            message: style,
+            color: 'green',
+            namedLogo: 'appveyor',
+            style,
+          })
+          return (
+            <QueryParam
+              documentation={<Badge alt={style} src={badgeUrl} />}
+              key={style}
+              snippet={snippet}
+            />
+          )
+        })}
+      </tbody>
+    </QueryParamTable>
+  )
+}
+StyleExamples.propTypes = {
+  baseUrl: PropTypes.string.isRequired,
+}
 
-  renderStyleExamples() {
-    const { baseUrl } = this.props
-    return (
-      <QueryParamTable>
-        <tbody>
-          {advertisedStyles.map(style => {
-            const snippet = `?style=${style}&logo=appveyor`
-            const badgeUrl = staticBadgeUrl({
-              baseUrl,
-              label: 'style',
-              message: style,
-              color: 'green',
-              namedLogo: 'appveyor',
-              style,
-            })
-            return (
-              <QueryParam
-                documentation={<Badge alt={style} src={badgeUrl} />}
-                key={style}
-                snippet={snippet}
-              />
-            )
-          })}
-        </tbody>
-      </QueryParamTable>
-    )
-  }
+function NamedLogos() {
+  const renderLogo = logo => <LogoName key={logo}>{logo}</LogoName>
+  const [first, ...rest] = shieldsLogos
+  return [renderLogo(first)].concat(
+    rest.reduce((result, logo) => result.concat([', ', renderLogo(logo)]), [])
+  )
+}
+
+function StaticBadgeEscapingRules() {
+  return (
+    <EscapingRuleTable>
+      <tbody>
+        <EscapingConversion
+          key="dashes"
+          lhs={
+            <span>
+              Dashes <code>--</code>
+            </span>
+          }
+          rhs={
+            <span>
+              <code>-</code> Dash
+            </span>
+          }
+        />
+        <EscapingConversion
+          key="underscores"
+          lhs={
+            <span>
+              Underscores <code>__</code>
+            </span>
+          }
+          rhs={
+            <span>
+              <code>_</code> Underscore
+            </span>
+          }
+        />
+        <EscapingConversion
+          key="spaces"
+          lhs={
+            <span>
+              <code>_</code> or Space <code>&nbsp;</code>
+            </span>
+          }
+          rhs={
+            <span>
+              <code>&nbsp;</code> Space
+            </span>
+          }
+        />
+      </tbody>
+    </EscapingRuleTable>
+  )
+}
+
+export default function Usage({ baseUrl }) {
+  return (
+    <section>
+      <H2 id="your-badge">Your Badge</H2>
+
+      <H3>Static</H3>
+      <StaticBadgeMaker baseUrl={baseUrl} />
+
+      <VerticalSpace />
+
+      <p>Using dash "-" separator</p>
+      <p>
+        <Snippet snippet={`${baseUrl}/badge/<LABEL>-<MESSAGE>-<COLOR>.svg`} />
+      </p>
+      <StaticBadgeEscapingRules />
+      <p>Using query string parameters</p>
+      <p>
+        <Snippet
+          snippet={`${baseUrl}/static/v1.svg?label=<LABEL>&message=<MESSAGE>&color=<COLOR>`}
+        />
+      </p>
+
+      <H3 id="colors">Colors</H3>
+      <p>
+        <ColorExamples
+          baseUrl={baseUrl}
+          colors={[
+            'brightgreen',
+            'green',
+            'yellowgreen',
+            'yellow',
+            'orange',
+            'red',
+            'blue',
+            'lightgrey',
+          ]}
+        />
+        <br />
+        <ColorExamples
+          baseUrl={baseUrl}
+          colors={[
+            'success',
+            'important',
+            'critical',
+            'informational',
+            'inactive',
+          ]}
+        />
+        <br />
+        <ColorExamples
+          baseUrl={baseUrl}
+          colors={['blueviolet', 'ff69b4', '9cf']}
+        />
+      </p>
 
-  static renderNamedLogos() {
-    const renderLogo = logo => <LogoName key={logo}>{logo}</LogoName>
-    const [first, ...rest] = shieldsLogos
-    return [renderLogo(first)].concat(
-      rest.reduce((result, logo) => result.concat([', ', renderLogo(logo)]), [])
-    )
-  }
+      <H3>Endpoint (Beta)</H3>
 
-  static renderStaticBadgeEscapingRules() {
-    return (
-      <EscapingRuleTable>
+      <p>
+        <Snippet snippet={`${baseUrl}/endpoint.svg?url=<URL>&style<STYLE>`} />
+      </p>
+
+      <p>
+        Create badges from <Link to={'/endpoint'}>your own JSON endpoint</Link>.
+      </p>
+
+      <H3 id="dynamic-badge">Dynamic</H3>
+
+      <DynamicBadgeMaker baseUrl={baseUrl} />
+
+      <p>
+        <StyledCode>
+          {baseUrl}
+          /badge/dynamic/json.svg?url=&lt;URL&gt;&amp;label=&lt;LABEL&gt;&amp;query=&lt;
+          <a
+            href="https://www.npmjs.com/package/jsonpath"
+            target="_BLANK"
+            title="JSONdata syntax"
+          >
+            $.DATA.SUBDATA
+          </a>
+          &gt;&amp;color=&lt;COLOR&gt;&amp;prefix=&lt;PREFIX&gt;&amp;suffix=&lt;SUFFIX&gt;
+        </StyledCode>
+      </p>
+      <p>
+        <StyledCode>
+          {baseUrl}
+          /badge/dynamic/xml.svg?url=&lt;URL&gt;&amp;label=&lt;LABEL&gt;&amp;query=&lt;
+          <a
+            href="https://www.npmjs.com/package/xpath"
+            target="_BLANK"
+            title="XPath syntax"
+          >
+            //data/subdata
+          </a>
+          &gt;&amp;color=&lt;COLOR&gt;&amp;prefix=&lt;PREFIX&gt;&amp;suffix=&lt;SUFFIX&gt;
+        </StyledCode>
+      </p>
+      <p>
+        <StyledCode>
+          {baseUrl}
+          /badge/dynamic/yaml.svg?url=&lt;URL&gt;&amp;label=&lt;LABEL&gt;&amp;query=&lt;
+          <a
+            href="https://www.npmjs.com/package/jsonpath"
+            target="_BLANK"
+            title="JSONdata syntax"
+          >
+            $.DATA.SUBDATA
+          </a>
+          &gt;&amp;color=&lt;COLOR&gt;&amp;prefix=&lt;PREFIX&gt;&amp;suffix=&lt;SUFFIX&gt;
+        </StyledCode>
+      </p>
+
+      <VerticalSpace />
+
+      <H2 id="styles">Styles</H2>
+
+      <p>
+        The following styles are available. Flat is the default. Examples are
+        shown with an optional logo:
+      </p>
+      <StyleExamples baseUrl={baseUrl} />
+
+      <p>
+        Here are a few other parameters you can use: (connecting several with
+        "&" is possible)
+      </p>
+      <QueryParamTable>
         <tbody>
-          <EscapingConversion
-            key="dashes"
-            lhs={
+          <QueryParam
+            documentation={
               <span>
-                Dashes <code>--</code>
+                Override the default left-hand-side text (
+                <a href="https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding">
+                  URL-Encoding
+                </a>
+                {} needed for spaces or special characters!)
               </span>
             }
-            rhs={
+            key="label"
+            snippet="?label=healthinesses"
+          />
+          <QueryParam
+            documentation={
               <span>
-                <code>-</code> Dash
+                Insert one of the named logos from ({<NamedLogos />}) or{' '}
+                <a href="https://simpleicons.org/" target="_BLANK">
+                  simple-icons
+                </a>
+                . Simple-icons are referenced using names as they appear on the
+                simple-icons site. If the name includes spaces, replace them
+                with dashes (e.g:{' '}
+                <StyledCode>?logo=visual-studio-code</StyledCode>)
               </span>
             }
+            key="logo"
+            snippet="?logo=appveyor"
           />
-          <EscapingConversion
-            key="underscores"
-            lhs={
+          <QueryParam
+            documentation={<span>Insert custom logo image (≥ 14px high)</span>}
+            key="logoSvg"
+            snippet="?logo=data:image/png;base64,…"
+          />
+          <QueryParam
+            documentation={
               <span>
-                Underscores <code>__</code>
+                Set the color of the logo (hex, rgb, rgba, hsl, hsla and css
+                named colors supported)
               </span>
             }
-            rhs={
+            key="logoColor"
+            snippet="?logoColor=violet"
+          />
+          <QueryParam
+            documentation={
+              <span>Set the horizontal space to give to the logo</span>
+            }
+            key="logoWidth"
+            snippet="?logoWidth=40"
+          />
+          <QueryParam
+            documentation={
               <span>
-                <code>_</code> Underscore
+                Specify what clicking on the left/right of a badge should do
+                (esp. for social badge style)
               </span>
             }
+            key="link"
+            snippet="?link=http://left&amp;link=http://right"
           />
-          <EscapingConversion
-            key="spaces"
-            lhs={
+          <QueryParam
+            documentation={
               <span>
-                <code>_</code> or Space <code>&nbsp;</code>
+                Set background of the left part (hex, rgb, rgba, hsl, hsla and
+                css named colors supported). The legacy name "colorA" is also
+                supported.
               </span>
             }
-            rhs={
+            key="labelColor"
+            snippet="?labelColor=abcdef"
+          />
+          <QueryParam
+            documentation={
               <span>
-                <code>&nbsp;</code> Space
+                Set background of the right part (hex, rgb, rgba, hsl, hsla and
+                css named colors supported). The legacy name "colorB" is also
+                supported.
               </span>
             }
+            key="color"
+            snippet="?color=fedcba"
           />
-        </tbody>
-      </EscapingRuleTable>
-    )
-  }
-
-  render() {
-    const { baseUrl } = this.props
-    return (
-      <section>
-        <H2 id="your-badge">Your Badge</H2>
-
-        <H3>Static</H3>
-        <StaticBadgeMaker baseUrl={baseUrl} />
-
-        <VerticalSpace />
-
-        <p>Using dash "-" separator</p>
-        <p>
-          <Snippet snippet={`${baseUrl}/badge/<LABEL>-<MESSAGE>-<COLOR>.svg`} />
-        </p>
-        {this.constructor.renderStaticBadgeEscapingRules()}
-        <p>Using query string parameters</p>
-        <p>
-          <Snippet
-            snippet={`${baseUrl}/static/v1.svg?label=<LABEL>&message=<MESSAGE>&color=<COLOR>`}
-          />
-        </p>
-
-        <H3 id="colors">Colors</H3>
-        <p>
-          <ColorExamples
-            baseUrl={baseUrl}
-            colors={[
-              'brightgreen',
-              'green',
-              'yellowgreen',
-              'yellow',
-              'orange',
-              'red',
-              'blue',
-              'lightgrey',
-            ]}
-          />
-          <br />
-          <ColorExamples
-            baseUrl={baseUrl}
-            colors={[
-              'success',
-              'important',
-              'critical',
-              'informational',
-              'inactive',
-            ]}
-          />
-          <br />
-          <ColorExamples
-            baseUrl={baseUrl}
-            colors={['blueviolet', 'ff69b4', '9cf']}
+          <QueryParam
+            documentation={
+              <span>
+                Set the HTTP cache lifetime (rules are applied to infer a
+                default value on a per-badge basis, any values specified below
+                the default will be ignored). The legacy name "maxAge" is also
+                supported.
+              </span>
+            }
+            key="cacheSeconds"
+            snippet="?cacheSeconds=3600"
           />
-        </p>
-
-        <H3>Endpoint (Beta)</H3>
-
-        <p>
-          <Snippet snippet={`${baseUrl}/endpoint.svg?url=<URL>&style<STYLE>`} />
-        </p>
-
-        <p>
-          Create badges from{' '}
-          <Link to={'/endpoint'}>your own JSON endpoint</Link>.
-        </p>
-
-        <H3 id="dynamic-badge">Dynamic</H3>
-
-        <DynamicBadgeMaker baseUrl={baseUrl} />
-
-        <p>
-          <StyledCode>
-            {baseUrl}
-            /badge/dynamic/json.svg?url=&lt;URL&gt;&amp;label=&lt;LABEL&gt;&amp;query=&lt;
-            <a
-              href="https://www.npmjs.com/package/jsonpath"
-              target="_BLANK"
-              title="JSONdata syntax"
-            >
-              $.DATA.SUBDATA
-            </a>
-            &gt;&amp;color=&lt;COLOR&gt;&amp;prefix=&lt;PREFIX&gt;&amp;suffix=&lt;SUFFIX&gt;
-          </StyledCode>
-        </p>
-        <p>
-          <StyledCode>
-            {baseUrl}
-            /badge/dynamic/xml.svg?url=&lt;URL&gt;&amp;label=&lt;LABEL&gt;&amp;query=&lt;
-            <a
-              href="https://www.npmjs.com/package/xpath"
-              target="_BLANK"
-              title="XPath syntax"
-            >
-              //data/subdata
-            </a>
-            &gt;&amp;color=&lt;COLOR&gt;&amp;prefix=&lt;PREFIX&gt;&amp;suffix=&lt;SUFFIX&gt;
-          </StyledCode>
-        </p>
-        <p>
-          <StyledCode>
-            {baseUrl}
-            /badge/dynamic/yaml.svg?url=&lt;URL&gt;&amp;label=&lt;LABEL&gt;&amp;query=&lt;
-            <a
-              href="https://www.npmjs.com/package/jsonpath"
-              target="_BLANK"
-              title="JSONdata syntax"
-            >
-              $.DATA.SUBDATA
-            </a>
-            &gt;&amp;color=&lt;COLOR&gt;&amp;prefix=&lt;PREFIX&gt;&amp;suffix=&lt;SUFFIX&gt;
-          </StyledCode>
-        </p>
-
-        <VerticalSpace />
-
-        <H2 id="styles">Styles</H2>
-
-        <p>
-          The following styles are available. Flat is the default. Examples are
-          shown with an optional logo:
-        </p>
-        {this.renderStyleExamples()}
-
-        <p>
-          Here are a few other parameters you can use: (connecting several with
-          "&" is possible)
-        </p>
-        <QueryParamTable>
-          <tbody>
-            <QueryParam
-              documentation={
-                <span>
-                  Override the default left-hand-side text (
-                  <a href="https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding">
-                    URL-Encoding
-                  </a>
-                  {} needed for spaces or special characters!)
-                </span>
-              }
-              key="label"
-              snippet="?label=healthinesses"
-            />
-            <QueryParam
-              documentation={
-                <span>
-                  Insert one of the named logos from (
-                  {this.constructor.renderNamedLogos()}) or{' '}
-                  <a href="https://simpleicons.org/" target="_BLANK">
-                    simple-icons
-                  </a>
-                  . Simple-icons are referenced using names as they appear on
-                  the simple-icons site. If the name includes spaces, replace
-                  them with dashes (e.g:{' '}
-                  <StyledCode>?logo=visual-studio-code</StyledCode>)
-                </span>
-              }
-              key="logo"
-              snippet="?logo=appveyor"
-            />
-            <QueryParam
-              documentation={
-                <span>Insert custom logo image (≥ 14px high)</span>
-              }
-              key="logoSvg"
-              snippet="?logo=data:image/png;base64,…"
-            />
-            <QueryParam
-              documentation={
-                <span>
-                  Set the color of the logo (hex, rgb, rgba, hsl, hsla and css
-                  named colors supported)
-                </span>
-              }
-              key="logoColor"
-              snippet="?logoColor=violet"
-            />
-            <QueryParam
-              documentation={
-                <span>Set the horizontal space to give to the logo</span>
-              }
-              key="logoWidth"
-              snippet="?logoWidth=40"
-            />
-            <QueryParam
-              documentation={
-                <span>
-                  Specify what clicking on the left/right of a badge should do
-                  (esp. for social badge style)
-                </span>
-              }
-              key="link"
-              snippet="?link=http://left&amp;link=http://right"
-            />
-            <QueryParam
-              documentation={
-                <span>
-                  Set background of the left part (hex, rgb, rgba, hsl, hsla and
-                  css named colors supported). The legacy name "colorA" is also
-                  supported.
-                </span>
-              }
-              key="labelColor"
-              snippet="?labelColor=abcdef"
-            />
-            <QueryParam
-              documentation={
-                <span>
-                  Set background of the right part (hex, rgb, rgba, hsl, hsla
-                  and css named colors supported). The legacy name "colorB" is
-                  also supported.
-                </span>
-              }
-              key="color"
-              snippet="?color=fedcba"
-            />
-            <QueryParam
-              documentation={
-                <span>
-                  Set the HTTP cache lifetime (rules are applied to infer a
-                  default value on a per-badge basis, any values specified below
-                  the default will be ignored). The legacy name "maxAge" is also
-                  supported.
-                </span>
-              }
-              key="cacheSeconds"
-              snippet="?cacheSeconds=3600"
-            />
-          </tbody>
-        </QueryParamTable>
+        </tbody>
+      </QueryParamTable>
 
-        <p>
-          We support <code>.svg</code>, <code>.json</code>, <code>.png</code>{' '}
-          and a few others, but use them responsibly.
-        </p>
-      </section>
-    )
-  }
+      <p>
+        We support <code>.svg</code>, <code>.json</code>, <code>.png</code> and
+        a few others, but use them responsibly.
+      </p>
+    </section>
+  )
+}
+Usage.propTypes = {
+  baseUrl: PropTypes.string.isRequired,
 }
-- 
GitLab