Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add meta tags for different routes #138

Merged
merged 1 commit into from
Jan 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"react-dev-utils": "^5.0.0",
"react-dom": "^16.7.0-alpha.0",
"react-draft-wysiwyg": "^1.12.11",
"react-helmet-async": "^0.2.0",
"react-infinite-scroller": "^1.2.4",
"react-lazyload": "^2.3.0",
"react-redux": "^5.0.7",
Expand Down
1 change: 1 addition & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Expand Down
11 changes: 11 additions & 0 deletions src/competitions/CompetitionListing/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import PropTypes from 'prop-types';
import Helmet from 'react-helmet-async';

import {
getAllCompetitions as getAllCompetitionsSelector,
Expand All @@ -20,6 +21,16 @@ const CompetitionListing = ({ isFetching, competitions, getAllCompetitions }) =>

return (
<div className={`${styles.container}`}>
<Helmet>
<title>Competitions | 1Ramp</title>
<meta name="title" content="Competitions | 1Ramp" />
<meta name="twitter:title" content="Competitions | 1Ramp" />
<meta name="og:title" content="Competitions | 1Ramp" />
<meta name="description" content="Participate in contests and win exciting prizes" />
<meta name="twitter:description" content="Participate in contests and win exciting prizes" />
<meta name="og:description" content="Participate in contests and win exciting prizes" />
<meta name="og:url" content="https://alpha.1ramp.io/competitions" />
</Helmet>
<div className="uk-grid">
{
competitions.map(competition => (
Expand Down
31 changes: 31 additions & 0 deletions src/competitions/CompetitionSingle/CompetitionMetaTags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import Helmet from 'react-helmet-async';
import PropTypes from 'prop-types';

const CompetitionMetaTags = ({ competition }) => {
const {
image, description, title, id,
} = competition;

return (
<Helmet>
<title>{title} | Competitions | 1Ramp</title>
<meta name="title" content={`${title} | Competitions | 1Ramp`} />
<meta name="og:title" content={`${title} | Competitions | 1Ramp`} />
<meta name="twitter:title" content={`${title} | Competitions | 1Ramp`} />
<meta name="description" content={description} />
<meta name="twitter:description" content={description} />
<meta name="og:description" content={description} />
<meta name="og:image" content={image} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image:url" content={image} />
<meta name="og:url" content={`https://alpha.1ramp.io/competitions/${id}`} />
</Helmet>
);
};

CompetitionMetaTags.propTypes = {
competition: PropTypes.shape().isRequired,
};

export default CompetitionMetaTags;
2 changes: 2 additions & 0 deletions src/competitions/CompetitionSingle/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import PostUserMeta from '../../post/PostUserMeta';
import Icon from '../../icons/Icon';
import UserAvatar from '../../components/UserAvatar';
import PrimaryButton from '../../components/buttons/PrimaryButton';
import CompetitionMetaTags from './CompetitionMetaTags';

import indexStyles from '../../styles/globals.scss';
import styles from './styles.scss';
Expand Down Expand Up @@ -55,6 +56,7 @@ const CompetitionSingle = ({
const canParticipate = isParticipatePossible(competition.starts_at, competition.ends_at);
return (
<div className={`${styles.wrapper} ${indexStyles.white}`}>
<CompetitionMetaTags competition={competition} />
<div className={styles.container}>
{/** Competition header with metadata */}
<PostUserMeta
Expand Down
8 changes: 8 additions & 0 deletions src/feed/Explore.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import InfiniteScroll from 'react-infinite-scroller';
import Helmet from 'react-helmet-async';

import styles from './styles.scss';
import * as userFeedActions from '../actions/userFeedActions';
Expand All @@ -20,6 +21,13 @@ const ExploreFeed = ({
);
return (
<div className={styles.feedPosts}>
<Helmet>
<title>Explore | 1Ramp</title>
<meta name="description" content="Explore what creators are sharing across all communities" />
<meta name="twitter:description" content="Explore what creators are sharing across all communities" />
<meta name="og:description" content="Explore what creators are sharing across all communities" />
<meta name="og:url" content="https://alpha.1ramp.io/feed/explore" />
</Helmet>
<InfiniteScroll
pageStart={0}
loadMore={() => loadExplorePosts(false)}
Expand Down
10 changes: 10 additions & 0 deletions src/feed/NewFeed.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import Helmet from 'react-helmet-async';

import * as userFeedActions from '../actions/userFeedActions';
import PostCard from '../post/PostCard';
Expand Down Expand Up @@ -42,6 +43,15 @@ class UserFeed extends React.Component {
render() {
return (
<div className={`uk-margin-top ${styles.feedContainer}`}>
<Helmet>
<title>New Posts | 1Ramp</title>
<meta name="description" content="See the latest posts on the 1Ramp platform" />
<meta name="twitter:title" content="New Posts | 1Ramp" />
<meta name="og:title" content="New Posts | 1Ramp" />
<meta name="twitter:description" content="See the latest posts on the 1Ramp platform" />
<meta name="og:description" content="See the latest posts on the 1Ramp platform" />
<meta name="og:url" content="https://alpha.1ramp.io/search" />
</Helmet>
{
this.props.userFeed.posts && this.props.userFeed.posts.map(post =>
<PostCard key={post} postPermlink={post} />)
Expand Down
11 changes: 11 additions & 0 deletions src/feed/TagFeed.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import Helmet from 'react-helmet-async';

import PostLoading from '../post/PostLoading';
import styles from './styles.scss';
Expand All @@ -17,8 +18,18 @@ const TagFeed = (props) => {
},
[tag],
);
const capitalizedTag = tag[0].toUpperCase() + tag.slice(1);
return (
<div className={styles.feedPosts}>
<Helmet>
<title>{capitalizedTag} | 1Ramp</title>
<meta name="description" content={`${capitalizedTag} on 1Ramp`} />
<meta name="twitter:title" content={`${capitalizedTag} | 1Ramp`} />
<meta name="og:title" content={`${capitalizedTag} | 1Ramp`} />
<meta name="twitter:description" content={`${capitalizedTag} on 1Ramp`} />
<meta name="og:description" content={`${capitalizedTag} on 1Ramp`} />
<meta name="og:url" content={`https://alpha.1ramp.io/feed/${props.match.params.tag}`} />
</Helmet>
{
props.feed.posts && props.feed.posts.map(post =>
<PostCard key={post} postPermlink={post} />)
Expand Down
5 changes: 5 additions & 0 deletions src/feed/UserFeed.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import InfiniteScroll from 'react-infinite-scroller';
import Helmet from 'react-helmet-async';

import styles from './styles.scss';
import * as userFeedActions from '../actions/userFeedActions';
Expand All @@ -23,6 +24,10 @@ const UserFeed = (props) => {
);
return (
<div className={styles.feedPosts}>
<Helmet>
<title>My Feed | 1Ramp</title>
<meta name="og:url" content="https://alpha.1ramp.io/feed" />
</Helmet>
<InfiniteScroll
pageStart={0}
loadMore={() => props.loadFeedsForUser(props.authUsername)}
Expand Down
29 changes: 24 additions & 5 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import en from 'javascript-time-ago/locale/en';
import showdown from 'showdown';
import Cookie from 'js-cookie';
import { ConnectedRouter } from 'connected-react-router';
import Helmet, { HelmetProvider } from 'react-helmet-async';

// import registerServiceWorker from './registerServiceWorker';
import Root from './components/root';
Expand Down Expand Up @@ -47,11 +48,29 @@ if (accessToken) {
}

ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={history}>
<Root />
</ConnectedRouter>
</Provider>,
<HelmetProvider>
{/* Default meta tags */}
<Helmet>
<meta name="title" content="Social media for creators - share content and earn rewards!" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="@the1ramp" />
<meta name="twitter:title" content="1Ramp" />
<meta name="twitter:description" content="Social media for creators - share content and earn rewards!" />
<meta name="twitter:creator" content="@the1ramp" />
<meta name="twitter:img:src" content="https://steemitimages.com/u/the1ramp/avatar/large" />
<meta name="og:title" content="1Ramp" />
<meta name="og:type" content="website" />
<meta name="og:url" content="https://alpha.1ramp.io" />
<meta name="og:image" content="https://steemitimages.com/u/the1ramp/avatar/large" />
<meta name="og:description" content="Social media for creators - share content and earn rewards!" />
<meta name="og:site_name" content="1Ramp" />
</Helmet>
<Provider store={store}>
<ConnectedRouter history={history}>
<Root />
</ConnectedRouter>
</Provider>
</HelmetProvider>,
document.getElementById('root'),
);
// registerServiceWorker();
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import Helmet from 'react-helmet-async';
import PropTypes from 'prop-types';

const MicroCommunityMetaTags = ({ community }) => {
const { name, description, tag } = community;
const image = community.image_url;
return (
<Helmet>
<title>{name} | Communities | 1Ramp</title>
<meta name="title" content={`${name} | Communities | 1Ramp`} />
<meta name="og:title" content={`${name} | Communitites | 1Ramp`} />
<meta name="twitter:title" content={`${name} | Communitites | 1Ramp`} />
<meta name="description" content={description} />
<meta name="twitter:description" content={description} />
<meta name="og:description" content={description} />
<meta name="og:image" content={image} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image:url" content={image} />
<meta name="og:url" content={`https://alpha.1ramp.io/communities/${tag}`} />
</Helmet>
);
};

MicroCommunityMetaTags.propTypes = {
community: PropTypes.shape().isRequired,
};

export default MicroCommunityMetaTags;
2 changes: 2 additions & 0 deletions src/microCommunities/MicroCommunitySingle/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';

import MicroCommunityMetaTags from './MicroCommunityMetaTags';
import Info from './MicroCommunityInfo';
import Posts from './MicroCommunityPosts';
import { getAllMicroCommunities } from '../actions';
Expand All @@ -25,6 +26,7 @@ const MicroCommunitySingle = ({ fetchAll, microCommunity }) => {
}
return (
<div className="uk-container">
<MicroCommunityMetaTags community={microCommunity} />
<div uk-grid="true" className="uk-margin-small-top">
<div className="uk-width-1-4@m">
<Info microCommunity={microCommunity} />
Expand Down
67 changes: 67 additions & 0 deletions src/post/PostSingle/PostMetaTags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React from 'react';
import Helmet from 'react-helmet-async';
import _ from 'lodash';
import PropTypes from 'prop-types';

import { getBodyTextOnly, getImagesFromBody } from '../utils';

const PostMetaTags = ({ post, postingUser }) => {
const {
title, body, author, permlink,
created,
} = post;

const lastUpdate = post.last_update;
const bodyText = getBodyTextOnly(body);
const titleTagContent = title.length ? title : bodyText;

let jsonMetadata;
try {
if (typeof post.json_metadata === 'string') {
jsonMetadata = JSON.parse(post.json_metadata);
} else {
jsonMetadata = post.json_metadata;
}
} catch (e) {
jsonMetadata = {};
}

let image = _.get(jsonMetadata, 'image[0]', '');

if ( // Image is null for some rare cases - prevent crash
!image || !image.length
) {
image = _.get(getImagesFromBody(body), '[0]', '');
}

const twitterHandle = _.get(postingUser, 'json_metadata.profile.twitter', false);
const tags = _.get(jsonMetadata, 'tags', []);

return (
<Helmet>
<title>{titleTagContent} - @{author} | 1Ramp</title>
<meta name="title" content={titleTagContent} />
<meta name="description" content={bodyText} />
<meta name="twitter:card" content={image ? 'summary_large_image' : 'summary'} />
<meta name="twitter:title" content={titleTagContent} />
<meta name="twitter:description" content={bodyText} />
{twitterHandle && <meta name="twitter:creator" content={`@${twitterHandle}`} />}
{image && <meta name="twitter:img:src" content={image} />}
<meta name="og:title" content={titleTagContent} />
<meta name="og:type" content="article" />
<meta name="og:url" content={`https://alpha.1ramp.io/@${author}/${permlink}`} />
{image && <meta name="og:image" content={image} />}
<meta name="og:description" content={bodyText} />
<meta name="article:published_time" content={created} />
<meta name="article:modified_time" content={lastUpdate} />
<meta name="article:tag" content={tags.join(',')} />
</Helmet>
);
};

PostMetaTags.propTypes = {
post: PropTypes.shape().isRequired,
postingUser: PropTypes.shape().isRequired,
};

export default PostMetaTags;
2 changes: 2 additions & 0 deletions src/post/PostSingle/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import PostUserMeta from '../PostUserMeta';
import { getCommunitiesForPost } from '../../utils/communityUtils';
import PostBody from '../PostBody';
import styles from './styles.scss';
import PostMetaTags from './PostMetaTags';

class PostSingle extends React.Component {
componentDidMount() {
Expand All @@ -21,6 +22,7 @@ class PostSingle extends React.Component {
const { body, author, permlink } = this.props.post;
return (
<div className={['uk-margin-bottom', styles.postSingleContainer].join(' ')}>
<PostMetaTags post={this.props.post} postingUser={this.props.postingUser} />
<div
className={[indexStyles.white].join(' ')}
>
Expand Down
37 changes: 37 additions & 0 deletions src/profile/UserProfile/UserProfileMetaTags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';
import _ from 'lodash';
import Helmet from 'react-helmet-async';
import PropTypes from 'prop-types';

const UserProfileMetaTags = ({ user }) => {
const { json_metadata, name } = user; // name is username

const fullName = _.get(json_metadata, 'profile.name', false);
const description = _.get(json_metadata, 'profile.about', '');
const twitterHandle = _.get(json_metadata, 'profile.twitter', false);
const title = fullName ? `${fullName} (@${name})` : `@${name}`;
const image = `https://steemitimages.com/u/${name}/avatar`;

return (
<Helmet>
<title>{title} | 1Ramp</title>
<meta name="description" content={description} />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content={`${title} | 1Ramp`} />
<meta name="twitter:description" content={description} />
{twitterHandle && <meta name="twitter:creator" content={`@${twitterHandle}`} />}
<meta name="twitter:img:src" content={image} />
<meta name="og:title" content={`${title} | 1Ramp`} />
<meta name="og:type" content="article" />
<meta name="og:url" content={`https://alpha.1ramp.io/@${name}`} />
<meta name="og:image" content={image} />
<meta name="og:description" content={description} />
</Helmet>
);
};

UserProfileMetaTags.propTypes = {
user: PropTypes.shape().isRequired,
};

export default UserProfileMetaTags;