@@ -23,7 +23,12 @@ export default function errorHandling() {
|
||||
}
|
||||
}
|
||||
|
||||
if (message.match('Authorization error')) {
|
||||
if (message.match(/Not found/i)) {
|
||||
ctx.status = 404;
|
||||
error = 'not_found';
|
||||
}
|
||||
|
||||
if (message.match(/Authorization error/i)) {
|
||||
ctx.status = 403;
|
||||
error = 'authorization_error';
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function About() {
|
||||
<Helmet>
|
||||
<title>About Us</title>
|
||||
</Helmet>
|
||||
<Header>
|
||||
<Header background="#F22C5F">
|
||||
<h1>About Us</h1>
|
||||
<p>The team behind Outline</p>
|
||||
</Header>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import { groupBy, map } from 'lodash';
|
||||
import format from 'date-fns/format';
|
||||
import styled from 'styled-components';
|
||||
import Grid from 'styled-components-grid';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import Markdown from './components/Markdown';
|
||||
import Header from './components/Header';
|
||||
import Content from './components/Content';
|
||||
|
||||
@@ -15,39 +16,84 @@ type Release = {
|
||||
created_at: string,
|
||||
};
|
||||
|
||||
function Changelog({ releases }: { releases: Release[] }) {
|
||||
type Props = { releases: Release[] };
|
||||
|
||||
function Changelog({ releases }: Props) {
|
||||
const categories = groupBy(releases, i =>
|
||||
format(new Date(i.created_at), 'MMMM, YYYY')
|
||||
);
|
||||
|
||||
return (
|
||||
<Grid>
|
||||
<Helmet>
|
||||
<title>Changelog</title>
|
||||
</Helmet>
|
||||
<Header>
|
||||
<Header background="#00ADFF">
|
||||
<h1>Changelog</h1>
|
||||
<p>
|
||||
We’re building in public. Here’s what we’ve been changing recently.
|
||||
</p>
|
||||
<p>We’re building in public. Here’s what has changed recently.</p>
|
||||
</Header>
|
||||
<Content>
|
||||
{releases.map(release => (
|
||||
<Article key={release.id}>
|
||||
<Heading id={release.name}>
|
||||
<a href={`#${release.name}`}>{release.name}</a>
|
||||
</Heading>
|
||||
<Time dateTime={release.created_at}>
|
||||
{format(new Date(release.created_at), 'MMMM Do, YYYY')}
|
||||
</Time>
|
||||
<ReactMarkdown source={release.body} />
|
||||
</Article>
|
||||
))}
|
||||
<Grid>
|
||||
<Grid.Unit
|
||||
size={{ tablet: 1 / 4 }}
|
||||
visible={{ mobile: false, tablet: true }}
|
||||
>
|
||||
<nav>
|
||||
{map(categories, (releases, category) => (
|
||||
<React.Fragment key={category}>
|
||||
<h3>{category.split(',')[0]}</h3>
|
||||
<List>
|
||||
{releases.map(release => (
|
||||
<li key={release.id}>
|
||||
<MenuItem href={`#${release.name}`}>
|
||||
{release.name}
|
||||
</MenuItem>
|
||||
</li>
|
||||
))}
|
||||
</List>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</nav>
|
||||
</Grid.Unit>
|
||||
<Grid.Unit size={{ tablet: 3 / 4 }}>
|
||||
{releases.map(release => (
|
||||
<Article key={release.id}>
|
||||
<Heading id={release.name}>
|
||||
<a href={`#${release.name}`}>{release.name}</a>
|
||||
</Heading>
|
||||
<Time dateTime={release.created_at}>
|
||||
{format(new Date(release.created_at), 'MMMM Do, YYYY')}
|
||||
</Time>
|
||||
<Markdown source={release.body} />
|
||||
</Article>
|
||||
))}
|
||||
</Grid.Unit>
|
||||
</Grid>
|
||||
</Content>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
const MenuItem = styled.a`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
color: ${props => props.theme.text};
|
||||
`;
|
||||
|
||||
const List = styled.ul`
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
`;
|
||||
|
||||
const Heading = styled.h1`
|
||||
margin-top: 0.5em;
|
||||
|
||||
a {
|
||||
color: ${props => props.theme.text};
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
@@ -66,13 +112,6 @@ const Article = styled.div`
|
||||
&:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
zoom: 50%;
|
||||
box-shadow: 0 10px 80px rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
`;
|
||||
|
||||
export default Changelog;
|
||||
|
||||
@@ -166,7 +166,7 @@ const Mask = styled.div`
|
||||
`;
|
||||
|
||||
const Features = styled.div`
|
||||
background: hsl(180, 58%, 85%);
|
||||
background: #00adff;
|
||||
padding: 0 2em;
|
||||
width: 100%;
|
||||
`;
|
||||
@@ -200,7 +200,7 @@ const Feature = styled(Grid.Unit)`
|
||||
`;
|
||||
|
||||
const Footer = styled.div`
|
||||
background: hsl(127, 58%, 85%);
|
||||
background: #aa34f0;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
padding: 4em 2em;
|
||||
@@ -210,6 +210,10 @@ const Footer = styled.div`
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
${breakpoint('tablet')`
|
||||
margin: 2em 0;
|
||||
padding: 6em 4em;
|
||||
|
||||
@@ -11,7 +11,7 @@ export default function Privacy() {
|
||||
<Helmet>
|
||||
<title>Privacy Policy</title>
|
||||
</Helmet>
|
||||
<Header>
|
||||
<Header background="#F4F7FA">
|
||||
<h1>Privacy Policy</h1>
|
||||
<p>How we collect and use your information</p>
|
||||
</Header>
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import breakpoint from 'styled-components-breakpoint';
|
||||
import styled from 'styled-components';
|
||||
import Centered from './Centered';
|
||||
|
||||
type Props = {
|
||||
children: React.Node,
|
||||
background?: string,
|
||||
};
|
||||
|
||||
const Header = ({ children }: Props) => {
|
||||
const Header = ({ children, background }: Props) => {
|
||||
return (
|
||||
<Wrapper>
|
||||
<Wrapper background={background}>
|
||||
<Centered>{children}</Centered>
|
||||
</Wrapper>
|
||||
);
|
||||
@@ -17,9 +19,25 @@ const Header = ({ children }: Props) => {
|
||||
|
||||
const Wrapper = styled.div`
|
||||
width: 100%;
|
||||
padding: 2em;
|
||||
background: ${props => props.theme.contentHeaderBackground};
|
||||
padding: 8em 0 3em;
|
||||
position: relative;
|
||||
|
||||
margin-top: -70px;
|
||||
margin-bottom: 2em;
|
||||
text-align: center;
|
||||
background: ${props => props.background || 'transparent'};
|
||||
z-index: -1;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -30px;
|
||||
width: 100vw;
|
||||
height: 100%;
|
||||
background: ${props => props.background || 'transparent'};
|
||||
z-index: -10;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 22px;
|
||||
@@ -29,9 +47,17 @@ const Wrapper = styled.div`
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.5em;
|
||||
font-size: 2em;
|
||||
margin: 0 0 0.1em;
|
||||
}
|
||||
|
||||
${breakpoint('tablet')`
|
||||
padding: 8em 3em 3em 3em;
|
||||
|
||||
h1 {
|
||||
font-size: 4em;
|
||||
}
|
||||
`};
|
||||
`;
|
||||
|
||||
export default Header;
|
||||
|
||||
@@ -78,7 +78,7 @@ function Layout({ children, loggedIn, sessions }: Props) {
|
||||
const Body = styled.body`
|
||||
padding: 0 30px;
|
||||
|
||||
${breakpoint('tablet')`
|
||||
${breakpoint('desktop')`
|
||||
padding: 0;
|
||||
`};
|
||||
`;
|
||||
|
||||
33
server/pages/components/Markdown.js
Normal file
33
server/pages/components/Markdown.js
Normal file
@@ -0,0 +1,33 @@
|
||||
// @flow
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export default styled(ReactMarkdown)`
|
||||
blockquote {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
background-color: ${props => props.theme.smoke};
|
||||
border-left: 6px solid ${props => props.theme.smokeDark};
|
||||
padding: 15px 30px 15px 15px;
|
||||
font-style: italic;
|
||||
font-size: 16px;
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
zoom: 50%;
|
||||
box-shadow: 0 10px 80px rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 15px;
|
||||
background: ${props => props.theme.smoke};
|
||||
padding: 2px 4px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
`;
|
||||
@@ -4,6 +4,7 @@ import { sortBy } from 'lodash';
|
||||
import styled from 'styled-components';
|
||||
import breakpoint from 'styled-components-breakpoint';
|
||||
import Centered from './Centered';
|
||||
import OutlineLogo from '../../../shared/components/OutlineLogo';
|
||||
import TeamLogo from '../../../shared/components/TeamLogo';
|
||||
import { fadeAndScaleIn } from '../../../shared/styles/animations';
|
||||
import {
|
||||
@@ -11,6 +12,7 @@ import {
|
||||
changelog,
|
||||
features,
|
||||
about,
|
||||
integrations,
|
||||
privacy,
|
||||
githubUrl,
|
||||
twitterUrl,
|
||||
@@ -36,20 +38,19 @@ function TopNavigation({ sessions, loggedIn }: Props) {
|
||||
|
||||
return (
|
||||
<Nav>
|
||||
<Brand href={process.env.URL}>Outline</Brand>
|
||||
<Brand href={process.env.URL}>
|
||||
<OutlineLogo size={18} fill="#000" /> Outline
|
||||
</Brand>
|
||||
<Menu>
|
||||
<MenuItemDesktop>
|
||||
<a href={features()}>Features</a>
|
||||
</MenuItemDesktop>
|
||||
<MenuItemDesktop>
|
||||
<a href={about()}>About</a>
|
||||
<a href={integrations()}>Integrations</a>
|
||||
</MenuItemDesktop>
|
||||
<MenuItemDesktop>
|
||||
<a href={changelog()}>Changelog</a>
|
||||
</MenuItemDesktop>
|
||||
<MenuItemDesktop>
|
||||
<a href={twitterUrl()}>Twitter</a>
|
||||
</MenuItemDesktop>
|
||||
<MenuItem>
|
||||
<a href={developers()}>API</a>
|
||||
</MenuItem>
|
||||
@@ -109,6 +110,9 @@ function BottomNavigation() {
|
||||
<div>
|
||||
<a href={privacy()}>Privacy</a>
|
||||
</div>
|
||||
<div>
|
||||
<a href={about()}>About</a>
|
||||
</div>
|
||||
</BottomNav>
|
||||
);
|
||||
}
|
||||
@@ -118,11 +122,11 @@ const MenuLinkStyle = props => `
|
||||
font-weight: 500;
|
||||
|
||||
a {
|
||||
color: ${props.theme.slate};
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: ${props.theme.slateDark};
|
||||
color: rgba(0, 0, 0, 0.4);
|
||||
text-decoration: underline;
|
||||
}
|
||||
`;
|
||||
@@ -142,17 +146,17 @@ const MenuItem = styled.li`
|
||||
props.highlighted &&
|
||||
`
|
||||
position: relative;
|
||||
border: 2px solid ${props.theme.slate};
|
||||
border: 2px solid rgba(0, 0, 0, 0.6);
|
||||
border-radius: 4px;
|
||||
padding: 6px 8px;
|
||||
margin-top: -6px;
|
||||
margin-bottom: -6px;
|
||||
|
||||
&:hover {
|
||||
border: 2px solid ${props.theme.slateDark};
|
||||
border: 2px solid rgba(0, 0, 0, 0.4);
|
||||
|
||||
> a {
|
||||
color: ${props.theme.slateDark};
|
||||
color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,6 +250,8 @@ const BottomNav = styled.nav`
|
||||
`;
|
||||
|
||||
const Brand = styled.a`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
text-decoration: none;
|
||||
|
||||
@@ -3,160 +3,20 @@ import * as React from 'react';
|
||||
import Grid from 'styled-components-grid';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import styled from 'styled-components';
|
||||
import Header from './components/Header';
|
||||
|
||||
const Container = styled.div`
|
||||
max-width: 720px;
|
||||
margin: 0 auto;
|
||||
padding: 0 2em;
|
||||
|
||||
pre {
|
||||
padding: 0.5em 1em;
|
||||
background: #f9fbfc;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #e8ebed;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
|
||||
thead {
|
||||
td {
|
||||
padding: 5px 12px 5px 0;
|
||||
border-bottom: 1px solid #ddd;
|
||||
vertical-align: bottom;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
tbody,
|
||||
thead {
|
||||
td {
|
||||
padding: 5px 12px 5px 0;
|
||||
}
|
||||
|
||||
td:last-child {
|
||||
width: 100%;
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
code {
|
||||
font-size: 1.08em;
|
||||
}
|
||||
}
|
||||
`;
|
||||
import Header from '../components/Header';
|
||||
import Content from '../components/Content';
|
||||
|
||||
export default function Pricing() {
|
||||
return (
|
||||
<Grid>
|
||||
<Helmet>
|
||||
<title>API Documentation - Outline</title>
|
||||
<title>API Reference - Outline</title>
|
||||
</Helmet>
|
||||
<Header>
|
||||
<h1>Documentation</h1>
|
||||
<p>The API is the heart and soul of Outline.</p>
|
||||
<Header background="#AA34F0">
|
||||
<h1>API Reference</h1>
|
||||
<p>Outline is built on an open, best-in-class, API</p>
|
||||
</Header>
|
||||
<Container>
|
||||
<p>
|
||||
As developers, it’s our mission to make the API as great as possible.
|
||||
While Outline is still in public beta, we might make small
|
||||
adjustments, including breaking changes to the API.
|
||||
</p>
|
||||
<h2>Making requests</h2>
|
||||
<p>
|
||||
Outline’s API follows simple RPC style conventions where each API
|
||||
endpoint is a method on{' '}
|
||||
<code>https://www.getoutline.com/api/<METHOD></code>. Both{' '}
|
||||
<code>GET</code> and <code>POST</code> methods are supported but it’s
|
||||
recommeded that you make all call using <code>POST</code>. Only HTTPS
|
||||
is supported in production.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For <code>GET</code> requests query string parameters are expected
|
||||
(e.g.
|
||||
<code>/api/document.info?id=...&token=...</code>). When making{' '}
|
||||
<code>POST</code> requests, request parameters are parsed depending on{' '}
|
||||
<code>Content-Type</code> header. To make a call using JSON payload,
|
||||
one must pass <code>Content-Type: application/json</code> header:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Example POST request:</strong>
|
||||
</p>
|
||||
<pre>
|
||||
<code>
|
||||
{`curl https://www.getoutline.com/api/documents.info
|
||||
-X POST
|
||||
-H 'authorization: Bearer API_KEY'
|
||||
-H 'content-type: application/json'
|
||||
-H 'accept: application/json'
|
||||
-d '{"id": "outline-api-NTpezNwhUP"}'
|
||||
`}
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<strong>Example GET request:</strong>
|
||||
</p>
|
||||
<pre>
|
||||
<code>
|
||||
{`curl https://www.getoutline.com/api/documents.info?id=outline-api-NTpezNwhUP&token=API_KEY
|
||||
`}
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
<h2>Authentication</h2>
|
||||
|
||||
<p>
|
||||
To access private API endpoints, you must provide a valid API key. You
|
||||
can create new API keys in your{' '}
|
||||
<a href={`${process.env.URL}/settings`}>account settings</a>. Be
|
||||
careful when handling your keys as they give access to all of your
|
||||
documents.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To authenticate with Outline API, you can supply the API key as a
|
||||
header (<code>Authorization: Bearer YOUR_API_KEY</code>) or as part of
|
||||
the payload using <code>token</code> parameter. If you’re making{' '}
|
||||
<code>GET</code> requests, header based authentication is recommended
|
||||
so that your keys don’t leak into logs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Some API endpoints allow unauhenticated requests for public resources
|
||||
and they can be called without an API key.
|
||||
</p>
|
||||
|
||||
<h2>Errors</h2>
|
||||
|
||||
<p>
|
||||
All successful API requests will be returned with <code>200</code>{' '}
|
||||
status code and <code>ok: true</code> in the response payload. If
|
||||
there’s an error while making the request, appropriate status code is
|
||||
returned with the <code>error</code> message:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
<code>
|
||||
{`{
|
||||
"ok": false,
|
||||
"error: "Not Found"
|
||||
}
|
||||
`}
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
<h2>Methods</h2>
|
||||
<Content>
|
||||
<Methods>
|
||||
<Method method="auth.info" label="Get current auth">
|
||||
<Description>
|
||||
@@ -166,6 +26,11 @@ export default function Pricing() {
|
||||
<Arguments />
|
||||
</Method>
|
||||
|
||||
<Method method="users.list" label="List team's users">
|
||||
<Description>List all of the users in the team.</Description>
|
||||
<Arguments pagination />
|
||||
</Method>
|
||||
|
||||
<Method method="users.info" label="Get current user">
|
||||
<Description>
|
||||
This method returns the profile info for the user identified by
|
||||
@@ -331,11 +196,11 @@ export default function Pricing() {
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
UUID - <code>id</code> field of the document
|
||||
UUID - <Code>id</Code> field of the document
|
||||
</li>
|
||||
<li>
|
||||
URI identifier - Human readable identifier used in Outline
|
||||
URLs (e.g. <code>outline-api-i48ZEZc5zjXndcP</code>)
|
||||
URLs (e.g. <Code>outline-api-i48ZEZc5zjXndcP</Code>)
|
||||
</li>
|
||||
</ul>
|
||||
</Description>
|
||||
@@ -360,14 +225,14 @@ export default function Pricing() {
|
||||
This method allows you to publish a new document under an existing
|
||||
collection. By default a document is set to the parent collection
|
||||
root. If you want to create a subdocument, you can pass{' '}
|
||||
<code>parentDocument</code> to set parent document.
|
||||
<Code>parentDocument</Code> to set parent document.
|
||||
</Description>
|
||||
<Arguments>
|
||||
<Argument
|
||||
id="collection"
|
||||
description={
|
||||
<span>
|
||||
<code>ID</code> of the collection to which the document is
|
||||
<Code>ID</Code> of the collection to which the document is
|
||||
created
|
||||
</span>
|
||||
}
|
||||
@@ -387,7 +252,7 @@ export default function Pricing() {
|
||||
id="parentDocument"
|
||||
description={
|
||||
<span>
|
||||
<code>ID</code> of the parent document within the collection
|
||||
<Code>ID</Code> of the parent document within the collection
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
@@ -395,7 +260,7 @@ export default function Pricing() {
|
||||
id="publish"
|
||||
description={
|
||||
<span>
|
||||
<code>true</code> by default. Pass <code>false</code> to
|
||||
<Code>true</Code> by default. Pass <Code>false</Code> to
|
||||
create a draft.
|
||||
</span>
|
||||
}
|
||||
@@ -422,7 +287,7 @@ export default function Pricing() {
|
||||
id="publish"
|
||||
description={
|
||||
<span>
|
||||
Pass <code>true</code> to publish a draft.
|
||||
Pass <Code>true</Code> to publish a draft.
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
@@ -430,7 +295,7 @@ export default function Pricing() {
|
||||
id="autosave"
|
||||
description={
|
||||
<span>
|
||||
Pass <code>true</code> to signify an autosave. This skips
|
||||
Pass <Code>true</Code> to signify an autosave. This skips
|
||||
creating a revision.
|
||||
</span>
|
||||
}
|
||||
@@ -439,7 +304,7 @@ export default function Pricing() {
|
||||
id="done"
|
||||
description={
|
||||
<span>
|
||||
Pass <code>true</code> to signify the end of an editing
|
||||
Pass <Code>true</Code> to signify the end of an editing
|
||||
session. This will trigger documents.update hooks.
|
||||
</span>
|
||||
}
|
||||
@@ -630,14 +495,6 @@ export default function Pricing() {
|
||||
</Arguments>
|
||||
</Method>
|
||||
|
||||
<Method method="team.users" label="List team's users">
|
||||
<Description>
|
||||
List team`s users. This endpoint is only available for admin
|
||||
users.
|
||||
</Description>
|
||||
<Arguments pagination />
|
||||
</Method>
|
||||
|
||||
<Method method="shares.list" label="List shared document links">
|
||||
<Description>
|
||||
List all your currently shared document links.
|
||||
@@ -666,13 +523,22 @@ export default function Pricing() {
|
||||
</Arguments>
|
||||
</Method>
|
||||
</Methods>
|
||||
</Container>
|
||||
</Content>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
const MethodList = styled.ul`
|
||||
margin-bottom: 80px;
|
||||
const MenuItem = styled.a`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
color: ${props => props.theme.text};
|
||||
`;
|
||||
|
||||
const List = styled.ul`
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
`;
|
||||
|
||||
const Methods = (props: { children: React.Node }) => {
|
||||
@@ -680,16 +546,26 @@ const Methods = (props: { children: React.Node }) => {
|
||||
const methods = children.map(child => child.props.method);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<MethodList>
|
||||
{methods.map(method => (
|
||||
<li key={method}>
|
||||
<a href={`#${method}`}>{method}</a>
|
||||
</li>
|
||||
))}
|
||||
</MethodList>
|
||||
{children}
|
||||
</div>
|
||||
<React.Fragment>
|
||||
<Grid>
|
||||
<Grid.Unit
|
||||
size={{ tablet: 1 / 4 }}
|
||||
visible={{ mobile: false, tablet: true }}
|
||||
>
|
||||
<nav>
|
||||
<h2>Reference</h2>
|
||||
<List>
|
||||
{methods.map(method => (
|
||||
<li key={method}>
|
||||
<MenuItem href={`#${method}`}>{method}</MenuItem>
|
||||
</li>
|
||||
))}
|
||||
</List>
|
||||
</nav>
|
||||
</Grid.Unit>
|
||||
<Grid.Unit size={{ tablet: 3 / 4 }}>{children}</Grid.Unit>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -716,8 +592,33 @@ type ArgumentsProps = {
|
||||
children?: React.Node | string,
|
||||
};
|
||||
|
||||
const Table = styled.table`
|
||||
border-collapse: collapse;
|
||||
|
||||
thead {
|
||||
td {
|
||||
padding: 5px 12px 5px 0;
|
||||
border-bottom: 1px solid #ddd;
|
||||
vertical-align: bottom;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
tbody,
|
||||
thead {
|
||||
td {
|
||||
padding: 5px 12px 5px 0;
|
||||
}
|
||||
|
||||
td:last-child {
|
||||
width: 100%;
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const Arguments = (props: ArgumentsProps) => (
|
||||
<table>
|
||||
<Table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Argument</td>
|
||||
@@ -733,9 +634,23 @@ const Arguments = (props: ArgumentsProps) => (
|
||||
)}
|
||||
{props.children}
|
||||
</tbody>
|
||||
</table>
|
||||
</Table>
|
||||
);
|
||||
|
||||
const Heading = styled.h3`
|
||||
code {
|
||||
font-size: 1em;
|
||||
padding: 2px 4px;
|
||||
background: #333;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
}
|
||||
`;
|
||||
|
||||
const Code = styled.code`
|
||||
font-size: 15px;
|
||||
`;
|
||||
|
||||
const Method = (props: MethodProps) => {
|
||||
const children = React.Children.toArray(props.children);
|
||||
const description = children.find(child => child.type === Description);
|
||||
@@ -743,13 +658,13 @@ const Method = (props: MethodProps) => {
|
||||
|
||||
return (
|
||||
<MethodContainer>
|
||||
<h3 id={props.method}>
|
||||
<code>{props.method}</code> - {props.label}
|
||||
</h3>
|
||||
<Heading id={props.method}>
|
||||
<code>{props.method}</code> {props.label}
|
||||
</Heading>
|
||||
<div>{description}</div>
|
||||
<Request>HTTP request & arguments</Request>
|
||||
<p>
|
||||
<code>{`${process.env.URL}/api/${props.method}`}</code>
|
||||
<Code>{`${process.env.URL}/api/${props.method}`}</Code>
|
||||
</p>
|
||||
{apiArgs}
|
||||
</MethodContainer>
|
||||
@@ -765,7 +680,7 @@ type ArgumentProps = {
|
||||
const Argument = (props: ArgumentProps) => (
|
||||
<tr>
|
||||
<td>
|
||||
<code>{props.id}</code>
|
||||
<Code>{props.id}</Code>
|
||||
</td>
|
||||
<td>
|
||||
<i>{props.required ? 'required' : 'optional'}</i>
|
||||
@@ -773,6 +688,7 @@ const Argument = (props: ArgumentProps) => (
|
||||
<td>{props.description}</td>
|
||||
</tr>
|
||||
);
|
||||
|
||||
const PaginationArguments = () => [
|
||||
<Argument id="offset" description="Pagination offset" />,
|
||||
<Argument id="limit" description="Pagination limit" />,
|
||||
169
server/pages/developers/index.js
Normal file
169
server/pages/developers/index.js
Normal file
@@ -0,0 +1,169 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import Grid from 'styled-components-grid';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import styled from 'styled-components';
|
||||
import Header from '../components/Header';
|
||||
import Content from '../components/Content';
|
||||
|
||||
export default function Pricing() {
|
||||
return (
|
||||
<Grid>
|
||||
<Helmet>
|
||||
<title>Developers - Outline</title>
|
||||
</Helmet>
|
||||
<Header background="#AA34F0">
|
||||
<h1>Developers</h1>
|
||||
<p>Outline is built on an open, best-in-class, API</p>
|
||||
</Header>
|
||||
<Content>
|
||||
<Grid>
|
||||
<Grid.Unit
|
||||
size={{ tablet: 1 / 4 }}
|
||||
visible={{ mobile: false, tablet: true }}
|
||||
>
|
||||
<nav>
|
||||
<h2>Introduction</h2>
|
||||
<List>
|
||||
<li>
|
||||
<MenuItem href="#requests">Making requests</MenuItem>
|
||||
</li>
|
||||
<li>
|
||||
<MenuItem href="#authentication">Authentication</MenuItem>
|
||||
</li>
|
||||
<li>
|
||||
<MenuItem href="#errors">Errors</MenuItem>
|
||||
</li>
|
||||
</List>
|
||||
<h2>API</h2>
|
||||
<List>
|
||||
<li>
|
||||
<MenuItem href="/developers/api">Reference</MenuItem>
|
||||
</li>
|
||||
</List>
|
||||
</nav>
|
||||
</Grid.Unit>
|
||||
<Grid.Unit size={{ tablet: 3 / 4 }}>
|
||||
<p>
|
||||
As developers, it’s our mission to make the API as great as
|
||||
possible. While Outline is still in public beta, we might make
|
||||
small adjustments, including breaking changes to the API.
|
||||
</p>
|
||||
|
||||
<h2>Making requests</h2>
|
||||
<p>
|
||||
Outline’s API follows simple RPC style conventions where each API
|
||||
endpoint is a method on{' '}
|
||||
<Code>https://www.getoutline.com/api/<METHOD></Code>. Both{' '}
|
||||
<Code>GET</Code> and <Code>POST</Code> methods are supported but
|
||||
it’s recommeded that you make all call using <Code>POST</Code>.
|
||||
Only HTTPS is supported in production.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For <Code>GET</Code> requests query string parameters are expected
|
||||
(e.g.
|
||||
<Code>/api/document.info?id=...&token=...</Code>). When making{' '}
|
||||
<Code>POST</Code> requests, request parameters are parsed
|
||||
depending on <Code>Content-Type</Code> header. To make a call
|
||||
using JSON payload, one must pass{' '}
|
||||
<Code>Content-Type: application/json</Code> header:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Example POST request:</strong>
|
||||
</p>
|
||||
<Pre>
|
||||
<Code>
|
||||
{`curl https://www.getoutline.com/api/documents.info
|
||||
-X POST
|
||||
-H 'authorization: Bearer API_KEY'
|
||||
-H 'content-type: application/json'
|
||||
-H 'accept: application/json'
|
||||
-d '{"id": "outline-api-NTpezNwhUP"}'
|
||||
`}
|
||||
</Code>
|
||||
</Pre>
|
||||
|
||||
<p>
|
||||
<strong>Example GET request:</strong>
|
||||
</p>
|
||||
<Pre>
|
||||
<Code>
|
||||
{`curl https://www.getoutline.com/api/documents.info?id=outline-api-NTpezNwhUP&token=API_KEY
|
||||
`}
|
||||
</Code>
|
||||
</Pre>
|
||||
|
||||
<h2>Authentication</h2>
|
||||
|
||||
<p>
|
||||
To access private API endpoints, you must provide a valid API key.
|
||||
You can create new API keys in your{' '}
|
||||
<a href={`${process.env.URL}/settings`}>account settings</a>. Be
|
||||
careful when handling your keys as they give access to all of your
|
||||
documents.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To authenticate with Outline API, you can supply the API key as a
|
||||
header (<Code>Authorization: Bearer YOUR_API_KEY</Code>) or as
|
||||
part of the payload using <Code>token</Code> parameter. If you’re
|
||||
making <Code>GET</Code> requests, header based authentication is
|
||||
recommended so that your keys don’t leak into logs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Some API endpoints allow unauhenticated requests for public
|
||||
resources and they can be called without an API key.
|
||||
</p>
|
||||
|
||||
<h2>Errors</h2>
|
||||
|
||||
<p>
|
||||
All successful API requests will be returned with <Code>200</Code>{' '}
|
||||
status code and <Code>ok: true</Code> in the response payload. If
|
||||
there’s an error while making the request, appropriate status code
|
||||
is returned with the <Code>error</Code> message:
|
||||
</p>
|
||||
|
||||
<Pre>
|
||||
<Code>
|
||||
{`{
|
||||
"ok": false,
|
||||
"error: "Not Found"
|
||||
}
|
||||
`}
|
||||
</Code>
|
||||
</Pre>
|
||||
</Grid.Unit>
|
||||
</Grid>
|
||||
</Content>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
const Pre = styled.pre`
|
||||
padding: 0.5em 1em;
|
||||
background: #f9fbfc;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #e8ebed;
|
||||
overflow: scroll;
|
||||
`;
|
||||
|
||||
const Code = styled.code`
|
||||
font-size: 15px;
|
||||
`;
|
||||
|
||||
const MenuItem = styled.a`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
color: ${props => props.theme.text};
|
||||
`;
|
||||
|
||||
const List = styled.ul`
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
`;
|
||||
48
server/pages/integrations/Integration.js
Normal file
48
server/pages/integrations/Integration.js
Normal file
@@ -0,0 +1,48 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import Grid from 'styled-components-grid';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import Markdown from '../components/Markdown';
|
||||
import Header from '../components/Header';
|
||||
import Content from '../components/Content';
|
||||
import Menu from './Menu';
|
||||
import integrations from './content';
|
||||
|
||||
type TIntegration = {
|
||||
slug: string,
|
||||
name: string,
|
||||
url: string,
|
||||
description: string,
|
||||
};
|
||||
|
||||
type Props = {
|
||||
integration: TIntegration,
|
||||
content: string,
|
||||
};
|
||||
|
||||
export default function Integration({ integration, content }: Props) {
|
||||
return (
|
||||
<Grid>
|
||||
<Helmet>
|
||||
<title>{integration.name} Integration – Outline</title>
|
||||
</Helmet>
|
||||
<Header background="#F4F7FA">
|
||||
<h1>{integration.name} Integration</h1>
|
||||
<p>{integration.description}</p>
|
||||
</Header>
|
||||
<Content>
|
||||
<Grid>
|
||||
<Grid.Unit
|
||||
size={{ tablet: 1 / 4 }}
|
||||
visible={{ mobile: false, tablet: true }}
|
||||
>
|
||||
<Menu integrations={integrations} active={integration.slug} />
|
||||
</Grid.Unit>
|
||||
<Grid.Unit size={{ tablet: 3 / 4 }}>
|
||||
<Markdown source={content} />
|
||||
</Grid.Unit>
|
||||
</Grid>
|
||||
</Content>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
57
server/pages/integrations/Menu.js
Normal file
57
server/pages/integrations/Menu.js
Normal file
@@ -0,0 +1,57 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { map, groupBy } from 'lodash';
|
||||
|
||||
type Props = {
|
||||
integrations: *,
|
||||
active: string,
|
||||
};
|
||||
|
||||
export default function IntegrationMenu({ integrations, active }: Props) {
|
||||
const categories = groupBy(integrations, i => i.category);
|
||||
|
||||
return (
|
||||
<nav>
|
||||
{map(categories, (integrations, category) => (
|
||||
<React.Fragment key={category}>
|
||||
<h3>{category}</h3>
|
||||
<List>
|
||||
{integrations.map(i => (
|
||||
<li key={i.slug}>
|
||||
<MenuItem
|
||||
href={`/integrations/${i.slug}`}
|
||||
active={i.slug === active}
|
||||
>
|
||||
<Logo src={`/images/${i.slug}.png`} alt={i.name} />
|
||||
<span>{i.name}</span>
|
||||
</MenuItem>
|
||||
</li>
|
||||
))}
|
||||
</List>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
||||
const MenuItem = styled.a`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
font-weight: ${props => (props.active ? '600' : 'inherit')};
|
||||
color: ${props => props.theme.text};
|
||||
`;
|
||||
|
||||
const Logo = styled.img`
|
||||
user-select: none;
|
||||
height: 18px;
|
||||
border-radius: 2px;
|
||||
margin-right: 8px;
|
||||
`;
|
||||
|
||||
const List = styled.ul`
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
`;
|
||||
7
server/pages/integrations/airtable.md
Normal file
7
server/pages/integrations/airtable.md
Normal file
@@ -0,0 +1,7 @@
|
||||
In an Outline document, paste a share link to an [Airtable](https://airtable.com) table and it will be immediately converted into an interactive, live embed.
|
||||
|
||||
Embedding a table in your knowledge base will stay upto date with your original data source automatically.
|
||||
|
||||

|
||||
|
||||
> This integration works without any additional settings or authentication.
|
||||
5
server/pages/integrations/codepen.md
Normal file
5
server/pages/integrations/codepen.md
Normal file
@@ -0,0 +1,5 @@
|
||||
In an Outline document, paste a share link to a [Codepen](https://codepen.io) card and it will be immediately converted into an embedded version where you can view the source or the result.
|
||||
|
||||
Pen's can be anything from a simple code snippet, to an embedded 3D graphic, visualization and more.
|
||||
|
||||
> This integration works without any additional settings or authentication.
|
||||
100
server/pages/integrations/content.json
Normal file
100
server/pages/integrations/content.json
Normal file
@@ -0,0 +1,100 @@
|
||||
[
|
||||
{
|
||||
"slug": "figma",
|
||||
"name": "Figma",
|
||||
"url": "https://figma.com",
|
||||
"category": "Design",
|
||||
"description": "Figma is a collaborative interface design tool"
|
||||
},
|
||||
{
|
||||
"slug": "framer",
|
||||
"name": "Framer",
|
||||
"url": "https://framer.com",
|
||||
"category": "Design",
|
||||
"description": "Framer is an interactive design and prototyping tool"
|
||||
},
|
||||
{
|
||||
"slug": "invision",
|
||||
"name": "InVision",
|
||||
"url": "https://invision.com",
|
||||
"category": "Design",
|
||||
"description": "InVision is an online design and prototyping tool"
|
||||
},
|
||||
{
|
||||
"slug": "marvel",
|
||||
"name": "Marvel",
|
||||
"url": "https://marvelapp.com",
|
||||
"category": "Design",
|
||||
"description": "The all-in-one platform powering design"
|
||||
},
|
||||
{
|
||||
"slug": "airtable",
|
||||
"name": "Airtable",
|
||||
"url": "https://airtable.com",
|
||||
"category": "Collaboration",
|
||||
"description": "Part spreadsheet, part database, and entirely flexible"
|
||||
},
|
||||
{
|
||||
"slug": "lucidchart",
|
||||
"name": "Lucidchart",
|
||||
"url": "https://lucidchart.com",
|
||||
"category": "Collaboration",
|
||||
"description": "Create flowcharts and technical diagrams with ease"
|
||||
},
|
||||
{
|
||||
"slug": "realtime-board",
|
||||
"name": "Realtime Board",
|
||||
"url": "https://realtimeboard.com",
|
||||
"category": "Collaboration",
|
||||
"description": "Simple whiteboarding for cross-functional team collaboration"
|
||||
},
|
||||
{
|
||||
"slug": "slack",
|
||||
"name": "Slack",
|
||||
"url": "https://slack.com",
|
||||
"category": "Collaboration",
|
||||
"description": "Chat, collaboration, and file sharing for teams"
|
||||
},
|
||||
{
|
||||
"slug": "trello",
|
||||
"name": "Trello",
|
||||
"url": "https://trello.com",
|
||||
"category": "Collaboration",
|
||||
"description": "Boards, lists, and cards to organize your projects"
|
||||
},
|
||||
{
|
||||
"slug": "typeform",
|
||||
"name": "Typeform",
|
||||
"url": "https://typeform.com",
|
||||
"category": "Collaboration",
|
||||
"description": "Data collection tool and surveys, for professionals"
|
||||
},
|
||||
{
|
||||
"slug": "codepen",
|
||||
"name": "Codepen",
|
||||
"url": "https://codepen.io",
|
||||
"category": "Developers",
|
||||
"description": "A social development environment and editor"
|
||||
},
|
||||
{
|
||||
"slug": "github-gist",
|
||||
"name": "GitHub Gist",
|
||||
"url": "https://gist.github.com",
|
||||
"category": "Developers",
|
||||
"description": "Sharable code snippets, hosted by GitHub"
|
||||
},
|
||||
{
|
||||
"slug": "mode-analytics",
|
||||
"name": "Mode Analytics",
|
||||
"url": "https://modeanalytics.com",
|
||||
"category": "Developers",
|
||||
"description": "Connect and analyze data from any data source"
|
||||
},
|
||||
{
|
||||
"slug": "numeracy",
|
||||
"name": "Numeracy",
|
||||
"url": "https://numeracy.io",
|
||||
"category": "Developers",
|
||||
"description": "A SQL pad for writing, iterating, and exploring data"
|
||||
}
|
||||
]
|
||||
7
server/pages/integrations/figma.md
Normal file
7
server/pages/integrations/figma.md
Normal file
@@ -0,0 +1,7 @@
|
||||
In an Outline document, paste a link to a [Figma](https://figma.com) design and we will instantly convert it to an interactive, live preview.
|
||||
|
||||
Because Figma is an online design tool you can see design work happening in realtime, right within Outline. Embed design specs, product designs, or marketing materials easily.
|
||||
|
||||

|
||||
|
||||
> This integration works without any additional settings or authentication.
|
||||
7
server/pages/integrations/framer.md
Normal file
7
server/pages/integrations/framer.md
Normal file
@@ -0,0 +1,7 @@
|
||||
In an Outline document, paste a link to a [Framer](https://framer.com) design or prototype hosted on Framer Cloud and it will be instantly turned into an interactive, live preview.
|
||||
|
||||
Host your prototypes, designs, and mocks inside Outline to document your product or design system. [Learn more about sharing links](https://blog.framer.com/framer-cloud-access-d6bdb192510d) with Framer cloud.
|
||||
|
||||

|
||||
|
||||
> This integration works without any additional settings or authentication.
|
||||
5
server/pages/integrations/github-gist.md
Normal file
5
server/pages/integrations/github-gist.md
Normal file
@@ -0,0 +1,5 @@
|
||||
In an Outline document, paste a link to a public [Gist](https://gist.github.com) and it will be immediately converted into an embedded version. Embedding code in your knowledge base is a great way to document best practices.
|
||||
|
||||
Outline also supports native code blocks, simply start a line with three backticks (```) to create a code block with syntax highlighting.
|
||||
|
||||
> This integration works without any additional settings or authentication.
|
||||
77
server/pages/integrations/index.js
Normal file
77
server/pages/integrations/index.js
Normal file
@@ -0,0 +1,77 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import { map, groupBy } from 'lodash';
|
||||
import styled from 'styled-components';
|
||||
import Grid from 'styled-components-grid';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import Header from '../components/Header';
|
||||
import Content from '../components/Content';
|
||||
import integrations from './content';
|
||||
|
||||
const categories = groupBy(integrations, i => i.category);
|
||||
|
||||
function Integrations() {
|
||||
return (
|
||||
<Grid>
|
||||
<Helmet>
|
||||
<title>Integrations</title>
|
||||
</Helmet>
|
||||
<Header background="#FFB500">
|
||||
<h1>Integrations</h1>
|
||||
<p>
|
||||
Outline is designed to integrate with your existing workflow and
|
||||
tools.
|
||||
</p>
|
||||
</Header>
|
||||
<Content>
|
||||
{map(categories, (integrations, category) => (
|
||||
<div key={category}>
|
||||
<h2>{category}</h2>
|
||||
<Category>
|
||||
{integrations.map(i => (
|
||||
<Grid.Unit size={{ desktop: 1 / 4 }} key={i.slug}>
|
||||
<Integration href={`/integrations/${i.slug}`}>
|
||||
<Logo src={`/images/${i.slug}.png`} alt={i.name} />
|
||||
<h3>{i.name}</h3>
|
||||
<p>{i.description}</p>
|
||||
</Integration>
|
||||
</Grid.Unit>
|
||||
))}
|
||||
</Category>
|
||||
</div>
|
||||
))}
|
||||
</Content>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
const Logo = styled.img`
|
||||
height: 60px;
|
||||
border-radius: 4px;
|
||||
`;
|
||||
|
||||
const Category = styled(Grid)`
|
||||
margin: 0 -1em;
|
||||
`;
|
||||
|
||||
const Integration = styled.a`
|
||||
display: block;
|
||||
padding: 2em 2em 1em;
|
||||
margin: 1em;
|
||||
border-radius: 4px;
|
||||
border: 2px solid ${props => props.theme.slateLight};
|
||||
color: ${props => props.theme.text};
|
||||
font-size: 16px;
|
||||
transition: background 200ms ease-in-out;
|
||||
|
||||
h3,
|
||||
p {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: ${props => props.theme.slateLight};
|
||||
}
|
||||
`;
|
||||
|
||||
export default Integrations;
|
||||
7
server/pages/integrations/invision.md
Normal file
7
server/pages/integrations/invision.md
Normal file
@@ -0,0 +1,7 @@
|
||||
In an Outline document, paste a share link to an [InVision](https://invision.com) prototype and it will be immediately converted into an interactive, live embed.
|
||||
|
||||
Embedding prototypes in your knowledge base is a great way to create product specs or document user feedback. [Learn more about sharing links](https://support.invisionapp.com/hc/en-us/sections/200697249-Sharing-Prototypes) from InVision.
|
||||
|
||||

|
||||
|
||||
> This integration works without any additional settings or authentication.
|
||||
7
server/pages/integrations/lucidchart.md
Normal file
7
server/pages/integrations/lucidchart.md
Normal file
@@ -0,0 +1,7 @@
|
||||
In an Outline document, paste a share link to a [Lucidchart](https://lucidchart.com) diagram or chart and it will be immediately converted into an interactive embedded version.
|
||||
|
||||
Embed diagrams in your knowledge base to commuicate flows, technical diagrams, and more alongside your written documentation
|
||||
|
||||

|
||||
|
||||
> This integration works without any additional settings or authentication.
|
||||
7
server/pages/integrations/marvel.md
Normal file
7
server/pages/integrations/marvel.md
Normal file
@@ -0,0 +1,7 @@
|
||||
In an Outline document, paste a share link to a [Marvel](https://marvelapp.com) prototype and it will be immediately converted into an interactive, live embed.
|
||||
|
||||
Embedding prototypes in your knowledge base is a great way to create product specs with engineers or document user feedback.
|
||||
|
||||

|
||||
|
||||
> This integration works without any additional settings or authentication.
|
||||
3
server/pages/integrations/mode-analytics.md
Normal file
3
server/pages/integrations/mode-analytics.md
Normal file
@@ -0,0 +1,3 @@
|
||||
In an Outline document, paste a link to a public [Mode Analytics](https://modeanalytics.com) report and it will be converted into an interactive, embedded graph or table. Embedded graphs are perfect for communicating business metrics and KPI's.
|
||||
|
||||
> This integration works without any additional settings or authentication.
|
||||
5
server/pages/integrations/numeracy.md
Normal file
5
server/pages/integrations/numeracy.md
Normal file
@@ -0,0 +1,5 @@
|
||||
In an Outline document, paste a link to any [Numeracy](https://numeracy.co) chart and it will be converted into an interactive, embedded chart or table. Embedding graphs are perfect for communicating business metrics and KPI's.
|
||||
|
||||

|
||||
|
||||
> This integration works without any additional settings or authentication.
|
||||
7
server/pages/integrations/realtime-board.md
Normal file
7
server/pages/integrations/realtime-board.md
Normal file
@@ -0,0 +1,7 @@
|
||||
In an Outline document, paste a share link to a [Realtime Board](https://realtimeboard.com/) whiteboard and it will be immediately converted into a realtime, interactive embed.
|
||||
|
||||
Embedded whiteboards in your knowledge base to commuicate plans and ideas, technical diagrams, designs, timelines and more alongside your written documentation
|
||||
|
||||

|
||||
|
||||
> This integration works without any additional settings or authentication.
|
||||
20
server/pages/integrations/slack.md
Normal file
20
server/pages/integrations/slack.md
Normal file
@@ -0,0 +1,20 @@
|
||||
## Sign In with Slack
|
||||
|
||||
Sign In with Slack means your team doesn't have to worry about invites, passwords, or managing new team members. Everyone on your team can login with their existing Slack account and will automatically join your private knowledgebase.
|
||||
|
||||
> Note: Your team will also get a matching custom subdomain that you can link to from elsewhere.
|
||||
|
||||
|
||||
## Search your Knowledgebase
|
||||
|
||||
Optionally [Connect to Slack](https://www.getoutline.com/settings/integrations/slack) to enable the `/outline` slack command. Once enabled team members can easily search your wiki from within Slack by typing `/outline search term`.
|
||||
|
||||

|
||||
|
||||
## Notifications
|
||||
|
||||
Outline can optionally post into any Slack #channel when documents are created or edited. You can also choose to route notifications based on the Collection.
|
||||
|
||||

|
||||
|
||||
> To setup channel notifications head to [your integration settings](https://www.getoutline.com/settings/integrations/slack) in the Outline admin
|
||||
5
server/pages/integrations/trello.md
Normal file
5
server/pages/integrations/trello.md
Normal file
@@ -0,0 +1,5 @@
|
||||
In an Outline document, paste a share link to a [Trello](https://trello.com) card and it will be immediately converted into an embedded preview.
|
||||
|
||||
Embed trello cards in your knowledge base to commuicate roadmap items, ideas, and more alongside your written documentation. Not sure how? [Learn more about sharing from Trello](https://help.trello.com/article/824-sharing-links-to-cards-and-boards).
|
||||
|
||||
> This integration works without any additional settings or authentication.
|
||||
5
server/pages/integrations/typeform.md
Normal file
5
server/pages/integrations/typeform.md
Normal file
@@ -0,0 +1,5 @@
|
||||
In an Outline document, paste a share link to a [Typeform survey](https://typeform.com) and it will be immediately converted into an embedded version of the survey. All you have to do is share the doc and wait for responses to roll in.
|
||||
|
||||

|
||||
|
||||
> This integration works without any additional settings or authentication.
|
||||
@@ -1,5 +1,7 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import fs from 'fs-extra';
|
||||
import { find } from 'lodash';
|
||||
import path from 'path';
|
||||
import Koa from 'koa';
|
||||
import Router from 'koa-router';
|
||||
@@ -18,7 +20,11 @@ import About from './pages/About';
|
||||
import Changelog from './pages/Changelog';
|
||||
import Privacy from './pages/Privacy';
|
||||
import Pricing from './pages/Pricing';
|
||||
import Api from './pages/Api';
|
||||
import Integrations from './pages/integrations';
|
||||
import integrations from './pages/integrations/content';
|
||||
import Integration from './pages/integrations/Integration';
|
||||
import Developers from './pages/developers';
|
||||
import Api from './pages/developers/Api';
|
||||
import SubdomainSignin from './pages/SubdomainSignin';
|
||||
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
@@ -34,7 +40,11 @@ const renderapp = async ctx => {
|
||||
};
|
||||
|
||||
// serve static assets
|
||||
koa.use(serve(path.resolve(__dirname, '../public')));
|
||||
koa.use(
|
||||
serve(path.resolve(__dirname, '../public'), {
|
||||
maxage: 60 * 60 * 24 * 30 * 1000,
|
||||
})
|
||||
);
|
||||
|
||||
router.get('/_health', ctx => (ctx.body = 'OK'));
|
||||
|
||||
@@ -54,8 +64,24 @@ if (process.env.NODE_ENV === 'production') {
|
||||
// static pages
|
||||
router.get('/about', ctx => renderpage(ctx, <About />));
|
||||
router.get('/pricing', ctx => renderpage(ctx, <Pricing />));
|
||||
router.get('/developers', ctx => renderpage(ctx, <Api />));
|
||||
router.get('/developers', ctx => renderpage(ctx, <Developers />));
|
||||
router.get('/developers/api', ctx => renderpage(ctx, <Api />));
|
||||
router.get('/privacy', ctx => renderpage(ctx, <Privacy />));
|
||||
router.get('/integrations/:slug', async ctx => {
|
||||
const slug = ctx.params.slug;
|
||||
const integration = find(integrations, i => i.slug === slug);
|
||||
if (!integration) throw new Error('Not found');
|
||||
|
||||
const content = await fs.readFile(
|
||||
path.resolve(__dirname, `pages/integrations/${slug}.md`)
|
||||
);
|
||||
|
||||
return renderpage(
|
||||
ctx,
|
||||
<Integration integration={integration} content={content} />
|
||||
);
|
||||
});
|
||||
router.get('/integrations', ctx => renderpage(ctx, <Integrations />));
|
||||
router.get('/changelog', async ctx => {
|
||||
const data = await fetch(
|
||||
'https://api.github.com/repos/outline/outline/releases'
|
||||
|
||||
Reference in New Issue
Block a user