mirror of
https://github.com/outline/outline.git
synced 2025-03-28 14:34:35 +00:00
POC
This commit is contained in:
37
flow-typed/npm/react-helmet_v3.x.x.js
vendored
37
flow-typed/npm/react-helmet_v3.x.x.js
vendored
@ -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;
|
||||
}
|
@ -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
27
server/pages/About.js
Normal 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>
|
||||
);
|
||||
}
|
@ -28,6 +28,7 @@ export default function Home() {
|
||||
Atlas is fast, really fast. We’ve 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 it’s 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
27
server/pages/Pricing.js
Normal 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>
|
||||
);
|
||||
}
|
@ -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>
|
||||
|
14
server/pages/components/Navigation.js
Normal file
14
server/pages/components/Navigation.js
Normal 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>
|
||||
);
|
||||
}
|
@ -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();
|
||||
});
|
||||
|
@ -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 team’s knowledge base</h1>
|
||||
<p class="f4 mid-gray">Documentation, meeting notes, playbooks, onboarding, work logs, brainstorming, decisions, & 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. We’ve 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 & 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>
|
27
server/utils/renderpage.js
Normal file
27
server/utils/renderpage.js
Normal 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);
|
||||
}
|
Reference in New Issue
Block a user