Skip to content
This repository has been archived by the owner on Oct 27, 2020. It is now read-only.

Commit

Permalink
SEO component
Browse files Browse the repository at this point in the history
  • Loading branch information
kremalicious committed Jun 18, 2019
1 parent 3024944 commit b811379
Show file tree
Hide file tree
Showing 16 changed files with 180 additions and 94 deletions.
33 changes: 0 additions & 33 deletions client/public/index.html
Expand Up @@ -12,39 +12,6 @@

<title>Commons</title>

<meta
content="A marketplace to find and publish open data sets in the Ocean Network."
name="description"
/>
<meta
content="https://commons.oceanprotocol.com/share.png"
name="image"
/>
<link href="https://commons.oceanprotocol.com" rel="canonical" />

<meta content="https://commons.oceanprotocol.com" property="og:url" />
<meta content="Commons" property="og:title" />
<meta
content="A marketplace to find and publish open data sets in the Ocean Network."
property="og:description"
/>
<meta
content="https://commons.oceanprotocol.com/share.png"
property="og:image"
/>

<meta content="summary_large_image" name="twitter:card" />
<meta content="@oceanprotocol" name="twitter:creator" />
<meta content="Commons" name="twitter:title" />
<meta
content="A marketplace to find and publish open data sets in the Ocean Network."
name="twitter:description"
/>
<meta
content="https://commons.oceanprotocol.com/share.png"
name="twitter:image"
/>

<style>
.loader {
display: block;
Expand Down
2 changes: 1 addition & 1 deletion client/public/manifest.json
Expand Up @@ -21,5 +21,5 @@
"start_url": ".",
"display": "standalone",
"theme_color": "#141414",
"background_color": "#141414"
"background_color": "#ffffff"
}
71 changes: 71 additions & 0 deletions client/src/components/atoms/Seo.tsx
@@ -0,0 +1,71 @@
import React from 'react'
import Helmet from 'react-helmet'
import { withRouter, RouteComponentProps } from 'react-router-dom'
import meta from '../../data/meta.json'
import imageDefault from '../../img/share.png'

const MetaTags = ({
title,
description,
url,
image
}: {
title: string
description: string
url: string
image: string
}) => (
<Helmet defaultTitle={meta.title} titleTemplate={`%s - ${meta.title}`}>
<html lang="en" />

{title && <title>{title}</title>}

{/* General tags */}
<meta name="description" content={description} />
<meta name="image" content={image} />
<link rel="canonical" href={url} />

{/* OpenGraph tags */}
<meta property="og:url" content={url} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={image} />

{/* Twitter Card tags */}
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:creator" content="@oceanprotocol" />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={image} />

{/* Prevent search engine indexing except for live */}
{window.location.hostname !== 'commons.oceanprotocol.com' && (
<meta name="robots" content="noindex,nofollow" />
)}
</Helmet>
)

interface SeoProps extends RouteComponentProps {
title?: string
description?: string
shareImage?: string
}

const Seo = ({ title, description, shareImage, location }: SeoProps) => {
title = title || meta.title
description = description || meta.description
shareImage = shareImage || meta.url + imageDefault

const url = meta.url + location.pathname + location.search

return (
<MetaTags
title={title}
description={description}
url={url}
image={shareImage}
/>
)
}

export default withRouter(Seo)
1 change: 0 additions & 1 deletion client/src/components/templates/Asset/index.tsx
Expand Up @@ -10,7 +10,6 @@ import CategoryImage from '../../atoms/CategoryImage'
import styles from './index.module.scss'

interface AssetProps {
location: Location
match: {
params: {
did: string
Expand Down
15 changes: 9 additions & 6 deletions client/src/components/templates/Channel.test.tsx
Expand Up @@ -4,19 +4,22 @@ import Channel from './Channel'
import { User } from '../../context'
import { createMemoryHistory } from 'history'
import { userMockConnected } from '../../../__mocks__/user-mock'
import { MemoryRouter } from 'react-router'

describe('Channel', () => {
it('renders without crashing', () => {
const history = createMemoryHistory()

const { container } = render(
<User.Provider value={userMockConnected}>
<Channel
match={{
params: { channel: 'ai-for-good' }
}}
history={history}
/>
<MemoryRouter>
<Channel
match={{
params: { channel: 'ai-for-good' }
}}
history={history}
/>
</MemoryRouter>
</User.Provider>
)
expect(container.firstChild).toBeInTheDocument()
Expand Down
15 changes: 11 additions & 4 deletions client/src/components/templates/Route.test.tsx
@@ -1,18 +1,25 @@
import React from 'react'
import { render } from '@testing-library/react'
import Route from './Route'
import { BrowserRouter as Router } from 'react-router-dom'

describe('Route', () => {
it('renders without crashing', () => {
const { container } = render(<Route title="Hello Title">Hello</Route>)
const { container } = render(
<Router>
<Route title="Hello Title">Hello</Route>
</Router>
)
expect(container.firstChild).toBeInTheDocument()
})

it('renders title & description', () => {
const { container } = render(
<Route title="Hello Title" description="Hello Description">
Hello
</Route>
<Router>
<Route title="Hello Title" description="Hello Description">
Hello
</Route>
</Router>
)
expect(container.querySelector('.title')).toHaveTextContent(
'Hello Title'
Expand Down
82 changes: 45 additions & 37 deletions client/src/components/templates/Route.tsx
@@ -1,51 +1,59 @@
import React from 'react'
import Helmet from 'react-helmet'
import Content from '../atoms/Content'
import styles from './Route.module.scss'
import meta from '../../data/meta.json'
import Markdown from '../atoms/Markdown'
import Seo from '../atoms/Seo'

interface RouteProps {
title: string
description?: string
image?: any
shareImage?: string
children: any
wide?: boolean
className?: string
}

const Route = ({
title,
description,
image,
shareImage,
wide,
children,
className
}: {
title: string
description?: string
image?: any
children: any
wide?: boolean
className?: string
}) => (
<div className={className}>
<Helmet defaultTitle={meta.title} titleTemplate={`%s - ${meta.title}`}>
{/* Strip HTML from passed title */}
<title>{title.replace(/(<([^>]+)>)/gi, '')}</title>
{description && <meta name="description" content={description} />}
</Helmet>

<article>
<header className={styles.header}>
<Content wide={wide}>
<h1 className={styles.title}>{title}</h1>

{image && image}

{description && (
<Markdown
text={description}
className={styles.description}
/>
)}
</Content>
</header>

{children}
</article>
</div>
)
}: RouteProps) => {
// Strip HTML from passed title
const titleSanitized = title.replace(/(<([^>]+)>)/gi, '')

return (
<div className={className}>
<Seo
title={titleSanitized}
description={description}
shareImage={shareImage}
/>

<article>
<header className={styles.header}>
<Content wide={wide}>
<h1 className={styles.title}>{titleSanitized}</h1>

{image && image}

{description && (
<Markdown
text={description}
className={styles.description}
/>
)}
</Content>
</header>

{children}
</article>
</div>
)
}

export default Route
1 change: 1 addition & 0 deletions client/src/data/meta.json
Expand Up @@ -2,6 +2,7 @@
"title": "Commons",
"description": "A marketplace to find and publish open data sets in the Ocean Network.",
"company": "Ocean Protocol Foundation Ltd.",
"url": "https://commons.oceanprotocol.com",
"social": [
{
"title": "Site",
Expand Down
Binary file added client/src/img/share.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 6 additions & 1 deletion client/src/routes/About.test.tsx
@@ -1,10 +1,15 @@
import React from 'react'
import { render } from '@testing-library/react'
import { MemoryRouter } from 'react-router'
import About from './About'

describe('About', () => {
it('renders without crashing', () => {
const { container } = render(<About />)
const { container } = render(
<MemoryRouter>
<About />
</MemoryRouter>
)
expect(container.firstChild).toBeInTheDocument()
})
})
6 changes: 3 additions & 3 deletions client/src/routes/Channels.test.tsx
@@ -1,5 +1,5 @@
import React from 'react'
import { BrowserRouter as Router } from 'react-router-dom'
import { MemoryRouter } from 'react-router'
import { render } from '@testing-library/react'
import Channels from './Channels'
import { User } from '../context'
Expand All @@ -9,9 +9,9 @@ describe('Channels', () => {
it('renders without crashing', () => {
const { container } = render(
<User.Provider value={userMockConnected}>
<Router>
<MemoryRouter>
<Channels />
</Router>
</MemoryRouter>
</User.Provider>
)
expect(container.firstChild).toBeInTheDocument()
Expand Down
7 changes: 5 additions & 2 deletions client/src/routes/Faucet.test.tsx
@@ -1,13 +1,16 @@
import React from 'react'
import { render, fireEvent } from '@testing-library/react'
import { MemoryRouter } from 'react-router'
import Faucet from './Faucet'
import { User } from '../context'
import { userMockConnected } from '../../__mocks__/user-mock'

const setup = () => {
const utils = render(
<User.Provider value={userMockConnected}>
<Faucet />
<MemoryRouter>
<Faucet />
</MemoryRouter>
</User.Provider>
)
const button = utils.getByText('Request Ether')
Expand All @@ -21,7 +24,7 @@ const setup = () => {

describe('Faucet', () => {
it('renders without crashing', () => {
const { container } = render(<Faucet />)
const { container } = setup()
expect(container.firstChild).toBeInTheDocument()
})

Expand Down
11 changes: 9 additions & 2 deletions client/src/routes/History.test.tsx
@@ -1,11 +1,16 @@
import React from 'react'
import { render } from '@testing-library/react'
import { MemoryRouter } from 'react-router'
import { User } from '../context'
import History from './History'

describe('History', () => {
it('renders without crashing', () => {
const { container } = render(<History />)
const { container } = render(
<MemoryRouter>
<History />
</MemoryRouter>
)
expect(container.firstChild).toBeInTheDocument()
})

Expand All @@ -27,7 +32,9 @@ describe('History', () => {

const { container } = render(
<User.Provider value={context}>
<History />
<MemoryRouter>
<History />
</MemoryRouter>
</User.Provider>
)
expect(container.querySelector('.message')).toBeInTheDocument()
Expand Down
7 changes: 6 additions & 1 deletion client/src/routes/NotFound.test.tsx
@@ -1,10 +1,15 @@
import React from 'react'
import { render } from '@testing-library/react'
import NotFound from './NotFound'
import { MemoryRouter } from 'react-router'

describe('NotFound', () => {
it('renders without crashing', () => {
const { container } = render(<NotFound />)
const { container } = render(
<MemoryRouter>
<NotFound />
</MemoryRouter>
)
expect(container.firstChild).toBeInTheDocument()
})
})

0 comments on commit b811379

Please sign in to comment.