This commit is contained in:
Tom Moor
2017-10-22 17:16:57 -07:00
parent aceaf261d2
commit 802ce10f14
10 changed files with 146 additions and 149 deletions

View File

@ -1,37 +0,0 @@
// flow-typed signature: 7ee00cf01ba33eeba35dee9d286ece86
// flow-typed version: 0d0440f3d3/react-helmet_v3.x.x/flow_>=v0.26.x
declare module 'react-helmet' {
declare type Props = {
htmlAttributes?: Object,
title?: string,
defaultTitle?: string,
titleTemplate?: string,
base?: Object,
meta?: Array<Object>,
link?: Array<Object>,
script?: Array<Object>,
noscript?: Array<Object>,
style?: Array<Object>,
onChangeClientState?: (newState: Object, addedTags: Object, removeTags: Object) => void | mixed,
};
declare interface HeadAttribute {
toString(): string;
toComponent(): React$Element<*>;
}
declare interface Head {
htmlAttributes: HeadAttribute;
title: HeadAttribute;
base: HeadAttribute;
meta: HeadAttribute;
link: HeadAttribute;
script: HeadAttribute;
style: HeadAttribute;
}
declare class Helmet extends React$Component {
static rewind(): Head;
props: Props;
}
declare var exports: typeof Helmet;
}

View File

@ -46,7 +46,7 @@ if (process.env.NODE_ENV === 'development') {
// use the same as in webpack
publicPath: config.output.publicPath,
// options for formating the statistics
// options for formatting the statistics
stats: {
colors: true,
},

27
server/pages/About.js Normal file
View File

@ -0,0 +1,27 @@
// @flow
import React from 'react';
import styled from 'styled-components';
import Grid from 'styled-components-grid';
import { Helmet } from 'react-helmet';
const Header = styled.div`
width: 100%;
padding: 3em;
text-align: center;
`;
export default function About() {
return (
<Grid>
<Helmet>
<title>About</title>
</Helmet>
<Header>
<h1>About Atlas</h1>
<p>
Just a proof of concept for multiple pages.
</p>
</Header>
</Grid>
);
}

View File

@ -28,6 +28,7 @@ export default function Home() {
Atlas is fast, really fast. Weve trimmed 100ms and 50ms there to make sure that documents load instantly, search is speedy and there are keyboard shortcuts for everything.
</p>
</Unit>
<Unit size={{ desktop: 1 / 2 }}>
<h2>Markdown Support</h2>
<p>
@ -35,6 +36,33 @@ export default function Home() {
</p>
</Unit>
<Unit size={{ desktop: 1 / 2 }} />
<Unit size={{ desktop: 1 / 2 }} />
<Unit size={{ desktop: 1 / 2 }}>
<h2>Markdown Support</h2>
<p>
Documents are stored in Markdown and you can export them at any time. Markdown shortcuts are also built right into the editor so you can easily format using markdown syntax or our GUI.
</p>
</Unit>
<Unit size={{ desktop: 1 / 3 }}>
<h2>Powerful Search</h2>
<p>
Built-in search makes that one document easy to find in a large knowledgebase.
</p>
</Unit>
<Unit size={{ desktop: 1 / 3 }}>
<h2>API & Integrations</h2>
<p>
Atlas is built on its own API, treat Atlas as a CMS or automatically great documents from outside events.
</p>
</Unit>
<Unit size={{ desktop: 1 / 3 }}>
<h2>Open Source</h2>
<p>
Want to contribute or host Atlas yourself? All of the code is on GitHub.
</p>
</Unit>
</Grid>
);
}

27
server/pages/Pricing.js Normal file
View File

@ -0,0 +1,27 @@
// @flow
import React from 'react';
import styled from 'styled-components';
import Grid from 'styled-components-grid';
import { Helmet } from 'react-helmet';
const Header = styled.div`
width: 100%;
padding: 3em;
text-align: center;
`;
export default function Pricing() {
return (
<Grid>
<Helmet>
<title>Pricing</title>
</Helmet>
<Header>
<h1>Pricing</h1>
<p>
Just a proof of concept for multiple pages.
</p>
</Header>
</Grid>
);
}

View File

@ -1,6 +1,7 @@
// @flow
import React from 'react';
import { Helmet } from 'react-helmet';
import Navigation from './Navigation';
type Props = {
children?: React$Element<*>,
@ -19,6 +20,7 @@ export default function Layout({ children }: Props) {
{'{{CSS}}'}
</head>
<body>
<Navigation />
{children}
</body>
</html>

View File

@ -0,0 +1,14 @@
// @flow
import React from 'react';
export default function Navigation() {
return (
<nav>
<a href="/">Atlas</a>
<ul>
<li><a href="/about">About</a></li>
<li><a href="/pricing">Pricing</a></li>
</ul>
</nav>
);
}

View File

@ -1,49 +1,27 @@
// @flow
import React from 'react';
import path from 'path';
import fs from 'fs';
import httpErrors from 'http-errors';
import Koa from 'koa';
import Router from 'koa-router';
import sendfile from 'koa-sendfile';
import ReactDOMServer from 'react-dom/server';
import subdomainRedirect from './middlewares/subdomainRedirect';
import { Helmet } from 'react-helmet';
import renderpage from './utils/renderpage';
import { ServerStyleSheet, StyleSheetManager } from 'styled-components';
import Layout from './pages/components/Layout';
import Home from './pages/Home';
import About from './pages/About';
import Pricing from './pages/Pricing';
const isProduction = process.env.NODE_ENV === 'production';
const koa = new Koa();
const router = new Router();
const sheet = new ServerStyleSheet();
const readFile = src => {
return new Promise((resolve, reject) => {
fs.readFile(src, { encoding: 'utf8' }, (err, data) => {
if (err) return reject(err);
resolve(data);
});
});
};
const renderPage = children => {
const html = ReactDOMServer.renderToString(
<StyleSheetManager sheet={sheet.instance}>
<Layout>
{children}
</Layout>
</StyleSheetManager>
);
// helmet returns an object of meta tags with toString methods, urgh.
const helmet = Helmet.renderStatic();
let head = '';
Object.keys(helmet).forEach(key => (head += helmet[key].toString()));
return html
.replace('{{CSS}}', sheet.getStyleTags())
.replace('{{HEAD}}', head);
const renderapp = async ctx => {
if (isProduction) {
await sendfile(ctx, path.join(__dirname, '../dist/index.html'));
} else {
await sendfile(ctx, path.join(__dirname, './static/dev.html'));
}
};
router.get('/_health', ctx => (ctx.body = 'OK'));
@ -61,33 +39,28 @@ if (process.env.NODE_ENV === 'production') {
});
}
// static pages
router.get('/about', ctx => renderpage(ctx, <About />));
router.get('/pricing', ctx => renderpage(ctx, <Pricing />));
// home page
router.get('/', async ctx => {
if (ctx.cookies.get('loggedIn')) {
if (isProduction) {
ctx.body = await readFile(path.join(__dirname, '../dist/index.html'));
} else {
ctx.body = await readFile(path.join(__dirname, './static/dev.html'));
}
await renderapp(ctx);
} else {
ctx.body = await renderPage(<Home />);
await renderpage(ctx, <Home />);
}
if (!ctx.status) ctx.throw(httpErrors.NotFound());
});
// catch all for react app
router.get('*', async ctx => {
if (isProduction) {
ctx.body = await readFile(path.join(__dirname, '../dist/index.html'));
} else {
ctx.body = await readFile(path.join(__dirname, './static/dev.html'));
}
await renderapp(ctx);
if (!ctx.status) ctx.throw(httpErrors.NotFound());
});
// middleware
koa.use(subdomainRedirect());
koa.use(router.routes());
// 404 handler
koa.use(async () => {
throw httpErrors.NotFound();
});

View File

@ -1,64 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<title>Atlas</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://unpkg.com/tachyons@4.8.1/css/tachyons.min.css">
</head>
</head>
<body class="sans-serif dark-gray">
<section class="fl w-100 pa6 tc">
<h1 class="f2">Your teams knowledge base</h1>
<p class="f4 mid-gray">Documentation, meeting notes, playbooks, onboarding, work logs, brainstorming, decisions, &amp; more…</p>
<a href="" class="bg-dark-gray br2 pa2 white no-underline">Sign In</a>
</section>
<section class="fl w-100">
<div class="fl w-50-l pa6">
</div>
<div class="fl w-50-l pa6 bg-light-gray">
<h2 class="f3">Blazing Fast</h2>
<p>Atlas is fast, really fast. Weve trimmed 100ms and 50ms there to make sure that documents load instantly, search is speedy and there are keyboard shortcuts for everything.</p>
</div>
</section>
<section class="fl w-100">
<div class="fl w-50-l pa6 bg-light-gray">
<h2 class="f3">Markdown Support</h2>
<p>Documents are stored in Markdown and you can export them at any time. Markdown shortcuts are also built right into the editor so you can easily format using markdown syntax or our GUI.</p>
</div>
<div class="fl w-50-l pa6">
</div>
</section>
<section class="fl w-100">
<div class="fl w-50-l pa6">
</div>
<div class="fl w-50-l pa6 bg-light-gray">
<h2 class="f3">Beautiful Editor</h2>
<p>We built a custom editor from the ground up to be great looking, extensible, and a pleasure to use whether you're typing up quick notes or pages of documentation.</p>
</div>
</section>
<div class="fl w-33-l pa5">
<h2 class="f4">Powerful Search</h2>
<p>Built-in search makes that one document easy to find in a large knowledgebase.</p>
</div>
<div class="fl w-33-l pa5">
<h2 class="f4">API &amp; Integrations</h2>
<p>Atlas is built on it's own API, treat Atlas as a CMS or automatically great documents from outside events.</p>
</div>
<div class="fl w-33-l pa5">
<h2 class="f4">Open Source</h2>
<p>Want to contribute or host Atlas yourself? All of the code is on GitHub.</p>
</div>
<footer class="fl w-100">
<ul>
<li>About Us</li>
<li>Pricing</li>
<li>Contact</li>
</ul>
</footer>
</body>
</html>

View File

@ -0,0 +1,27 @@
// @flow
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { Helmet } from 'react-helmet';
import { ServerStyleSheet, StyleSheetManager } from 'styled-components';
import Layout from '../pages/components/Layout';
const sheet = new ServerStyleSheet();
export default function renderpage(ctx: Object, children: React$Element<*>) {
const html = ReactDOMServer.renderToString(
<StyleSheetManager sheet={sheet.instance}>
<Layout>
{children}
</Layout>
</StyleSheetManager>
);
// helmet returns an object of meta tags with toString methods, urgh.
const helmet = Helmet.renderStatic();
let head = '';
Object.keys(helmet).forEach(key => (head += helmet[key].toString()));
ctx.body = html
.replace('{{CSS}}', sheet.getStyleTags())
.replace('{{HEAD}}', head);
}