add static pages

This commit is contained in:
cleverbeagle 2017-05-30 00:28:34 -05:00
parent bd78b8e4d7
commit 5ba5100a52
19 changed files with 320 additions and 7 deletions

View file

@ -0,0 +1,11 @@
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import getPrivateFile from '../../../modules/server/get-private-file';
import parseMarkdown from '../../../modules/parse-markdown';
Meteor.methods({
'utility.getPage': function utilityReadFileAsText(fileName) {
check(fileName, String);
return parseMarkdown(getPrivateFile(`pages/${fileName}.md`));
},
});

View file

@ -0,0 +1,8 @@
import { Parser, HtmlRenderer } from 'commonmark';
export default (markdown, options) => {
const reader = new Parser();
const writer = options ? new HtmlRenderer(options) : new HtmlRenderer();
const parsed = reader.parse(markdown);
return writer.render(parsed);
};

View file

@ -0,0 +1,3 @@
import fs from 'fs';
export default path => fs.readFileSync(`assets/app/${path}`, 'utf8');

View file

@ -5,3 +5,5 @@ import '../../api/OAuth/server/methods';
import '../../api/Users/server/methods';
import '../../api/Users/server/publications';
import '../../api/Utility/server/methods';

View file

@ -0,0 +1,16 @@
/* eslint-disable react/no-danger */
import React from 'react';
import PropTypes from 'prop-types';
import './Content.scss';
const Content = ({ content }) => (
<div className="Content" dangerouslySetInnerHTML={{ __html: content }} />
);
Content.propTypes = {
content: PropTypes.string.isRequired,
};
export default Content;

View file

@ -0,0 +1,36 @@
@import '../../stylesheets/mixins';
.Content {
max-width: 700px;
margin: 0 auto;
font-size: 14px;
line-height: 22px;
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 30px 0 20px;
}
p {
margin-bottom: 20px;
}
> *:first-child {
margin-top: 0px;
}
> *:last-child {
margin-bottom: 0px;
}
}
@include breakpoint(tablet) {
.Content {
font-size: 16px;
line-height: 22px;
}
}

View file

@ -39,7 +39,9 @@ body {
color: $gray-light;
}
a:hover {
a:hover,
a:active,
a:focus {
text-decoration: none;
color: $gray;
}

View file

@ -0,0 +1,24 @@
import React from 'react';
import PropTypes from 'prop-types';
import './PageHeader.scss';
const PageHeader = ({ title, subtitle }) => (
<div className="PageHeader">
<div className="PageHeader-container">
<h1>{title}</h1>
{subtitle ? <p>{subtitle}</p> : ''}
</div>
</div>
);
PageHeader.defaultProps = {
subtitle: '',
};
PageHeader.propTypes = {
title: PropTypes.string.isRequired,
subtitle: PropTypes.string,
};
export default PageHeader;

View file

@ -0,0 +1,47 @@
@import '../../stylesheets/mixins';
@import '../../stylesheets/colors';
.PageHeader {
border-bottom: 1px solid $gray-lighter;
padding: 0px 0 20px;
margin-bottom: 20px;
h1 {
font-size: 20px;
font-weight: 600;
margin: 0;
}
p {
font-size: 14px;
margin-top: 10px;
margin-bottom: 0;
color: $gray-light;
}
}
.PageHeader-container {
text-align: center;
}
@include breakpoint(tablet) {
.PageHeader {
padding: 10px 0 30px;
margin-bottom: 30px;
h1 {
font-size: 24px;
}
p {
font-size: 16px;
}
}
}
@include breakpoint(desktop) {
.PageHeader {
padding: 20px 0 40px;
margin-bottom: 40px;
}
}

View file

@ -21,6 +21,8 @@ import ResetPassword from '../../pages/ResetPassword/ResetPassword';
import Profile from '../../pages/Profile/Profile';
import NotFound from '../../pages/NotFound/NotFound';
import Footer from '../../components/Footer/Footer';
import Terms from '../../pages/Terms/Terms';
import Privacy from '../../pages/Privacy/Privacy';
import './App.scss';
@ -41,6 +43,8 @@ const App = props => (
<Public path="/logout" component={Logout} {...props} />
<Route name="recover-password" path="/recover-password" component={RecoverPassword} />
<Route name="reset-password" path="/reset-password/:token" component={ResetPassword} />
<Route name="terms" path="/terms" component={Terms} />
<Route name="privacy" path="/privacy" component={Privacy} />
<Route component={NotFound} />
</Switch>
</Grid>

View file

@ -15,6 +15,9 @@ const Index = () => (
<Button href="https://pup.cleverbeagle.com">Read the Docs</Button>
<Button href="https://github.com/cleverbeagle/pup"><i className="fa fa-star" /> Star on GitHub</Button>
</div>
<footer>
<p>Need help and want to stay accountable building your product? <a href="https://cleverbeagle.com?utm_source=pupappindex&utm_campaign=oss">Check out Clever Beagle</a>.</p>
</footer>
</div>
);

View file

@ -33,14 +33,23 @@
.btn {
border: none;
}
}
.btn:last-child {
background: darken($cb-blue, 20%);
color: lighten($cb-blue, 30%);
footer {
margin: 20px -20px -20px;
border-top: 1px solid darken($cb-blue, 10%);
padding: 20px;
&:hover {
color: #fff;
}
p {
font-size: 14px;
line-height: 22px;
color: lighten($cb-blue, 35%);
margin: 0;
}
p a {
color: lighten($cb-blue, 35%);
text-decoration: underline;
}
}
}
@ -48,11 +57,19 @@
@include breakpoint(tablet) {
.Index {
padding: 30px;
footer {
margin: 30px -30px -30px;
}
}
}
@include breakpoint(desktop) {
.Index {
padding: 40px;
footer {
margin: 40px -40px -40px;
}
}
}

View file

@ -0,0 +1,44 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Meteor } from 'meteor/meteor';
import { createContainer } from 'meteor/react-meteor-data';
import { ReactiveVar } from 'meteor/reactive-var';
import PageHeader from '../../components/PageHeader/PageHeader';
import Content from '../../components/Content/Content';
import './Page.scss';
const Page = ({ title, subtitle, content }) => (
<div className="Page">
<PageHeader title={title} subtitle={subtitle} />
<Content content={content} />
</div>
);
Page.defaultProps = {
subtitle: '',
};
Page.propTypes = {
title: PropTypes.string.isRequired,
subtitle: PropTypes.string,
content: PropTypes.string.isRequired,
};
const pageContent = new ReactiveVar('');
export default createContainer(({ content, page }) => {
window.scrollTo(0, 0); // Force window to top of page.
Meteor.call('utility.getPage', page, (error, response) => {
if (error) {
console.warn(error);
} else {
pageContent.set(response);
}
});
return {
content: content || pageContent.get(),
};
}, Page);

View file

@ -0,0 +1,11 @@
@import '../../stylesheets/mixins';
.Page {
margin-bottom: 0px;
}
@include breakpoint(tablet) {
.Page {
margin-bottom: 30px;
}
}

View file

@ -0,0 +1,14 @@
import React from 'react';
import Page from '../Page/Page';
const Privacy = () => (
<div className="Privacy">
<Page
title="Privacy Policy"
subtitle="Last updated May 29th, 2017"
page="privacy"
/>
</div>
);
export default Privacy;

View file

@ -0,0 +1,14 @@
import React from 'react';
import Page from '../Page/Page';
const Terms = () => (
<div className="Terms">
<Page
title="Terms of Service"
subtitle="Last updated May 29th, 2017"
page="terms"
/>
</div>
);
export default Terms;