Compare commits

..

9 Commits

34 changed files with 13363 additions and 34 deletions

View File

@ -1,4 +1,5 @@
[ignore]
.*/www/.*
[include]
[libs]
./flow-typed

19
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,19 @@
Please make sure you are testing with the latest [release of html2canvas](https://github.com/niklasvh/html2canvas/releases).
Old versions are not supported and issues reported for them will be closed.
# Please follow the general troubleshooting steps first:
- [ ] You are using the latest [version](https://github.com/niklasvh/html2canvas/releases)
- [ ] You are testing using the non-minified version of html2canvas and checked any potential issues reported in the console
<!-- You can erase any parts of this template not applicable to your Issue. -->
### Bug reports:
Please replace this line with a brief summary of your issue **AND** if possible an example on [jsfiddle](https://jsfiddle.net/).
### Specifications:
* html2canvas version tested with:
* Browser & version:
* Operating system:

37
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,37 @@
A similar PR may already be submitted!
Please search among the [Pull request](https://github.com/niklasvh/html2canvas/pulls) before creating one.
Thanks for submitting a pull request! Please provide enough information so that others can review your pull request:
Before opening a pull request, please make sure all the tests pass locally by running `npm test`.
**Summary**
<!-- Summary of the PR -->
This PR fixes/implements the following **bugs/features**
* [ ] Bug 1
* [ ] Bug 2
* [ ] Feature 1
* [ ] Feature 2
* [ ] Breaking changes
<!-- You can skip this if you're fixing a typo or adding an app to the Showcase. -->
Explain the **motivation** for making this change. What existing problem does the pull request solve?
<!-- Example: When "Adding a function to do X", explain why it is necessary to have a way to do X. -->
**Test plan (required)**
Demonstrate how the issue/feature can be replicated. For most cases, simply adding an appropriate html/css template into the [reftests](https://github.com/niklasvh/html2canvas/tree/master/tests/reftests) should be sufficient. Please see other tests there for reference.
**Code formatting**
Please make sure that code adheres to the project code formatting. Running `npm run format` will automatically format your code correctly.
**Closing issues**
<!-- Put `closes #XXXX` in your comment to auto-close the issue that your PR fixes (if such). -->
Fixes #

View File

@ -3,12 +3,13 @@ examples/
scripts/
src/
tests/
.github/
*.iml
.babelrc
.idea/
.npmignore
.jshintrc
.eslintrc
.travis.yml
karma.js
karma.config.js
karma.conf.js
webpack.config.js

View File

@ -1,6 +1,11 @@
### Changelog ###
#### v1.0.0-alpha2 - TBD ####
#### v1.0.0-alpha3 - TBD ####
* Disable `foreignObjectRendering` by default (#1295)
* Fix background-size when using background-origin and background-size: cover/contain (#1299)
* Added support for background-origin: content-box (#1299)
#### v1.0.0-alpha2 - 7.12.2017 ####
* Fix scroll positions for CanvasRenderer (#1259)
* Fix `data-html2canvas-ignore` attribute (#1253)
* Fix decimal `letter-spacing` values (#1293)

38
docs/about.md Normal file
View File

@ -0,0 +1,38 @@
---
title: "About"
---
Before you get started with the script, there are a few things that are good to know regarding the
script and some of its limitations.
# Introduction
The script allows you to take "screenshots" of webpages or parts of it, directly on the users browser.
The screenshot is based on the DOM and as such may not be 100% accurate to the real representation
as it does not make an actual screenshot, but builds the screenshot based on the information
available on the page.
# How it works
The script traverses through the DOM of the page it is loaded on. It gathers information on all the elements
there, which it then uses to build a representation of the page. In other words, it does not actually take a
screenshot of the page, but builds a representation of it based on the properties it reads from the DOM.
As a result, it is only able to render correctly properties that it understands, meaning there are many
CSS properties which do not work. For a full list of supported CSS properties, check out the
[support features](/features/) page.
# Limitations
All the images that the script uses need to reside under the [same origin](http://en.wikipedia.org/wiki/Same_origin_policy)
for it to be able to read them without the assistance of a [proxy](/proxy/). Similarly, if you have other `canvas`
elements on the page, which have been tainted with cross-origin content, they will become dirty and no longer readable by html2canvas.
The script doesn't render plugin content such as Flash or Java applets.
# Browser compatibility
The library should work fine on the following browsers (with `Promise` polyfill):
- Firefox 3.5+
- Google Chrome
- Opera 12+
- IE9+
- Edge
- Safari 6+

25
docs/configuration.md Normal file
View File

@ -0,0 +1,25 @@
---
title: "Configuration"
---
These are all of the available configuration options.
| Name | Type | Default | Description |
| ------------- |:-------------:| :------: | ----------- |
| async | Boolean | `true` | Whether to parse and render the element asynchronously
| allowTaint | Boolean | `false` | Whether to allow cross-origin images to taint the canvas
| backgroundColor | String | `#ffffff` | Canvas background color, if none is specified in DOM. Set undefined for transparent
| canvas | `HTMLCanvasElement` | `null` | Existing `canvas` element to use as a base for drawing on
| foreignObjectRendering | Boolean | `false` | Whether to use ForeignObject rendering if the browser supports it
| imageTimeout | Number | `15000` | Timeout for loading an image (in milliseconds). Set to `0` to disable timeout.
| proxy | String | `null` | Url to the [proxy](/proxy/) which is to be used for loading cross-origin images. If left empty, cross-origin images won't be loaded.
| removeContainer | Boolean | `true` | Whether to cleanup the cloned DOM elements html2canvas creates temporarily
| scale | Number | `window.devicePixelRatio` | The scale to use for rendering. Defaults to the browsers device pixel ratio.
| width | Number | `Element` width | The width of the `canvas`
| height | Number | `Element` height | The height of the `canvas`
| x | Number | `Element` x-offset | Crop canvas x-coordinate
| y | Number | `Element` y-offset| Crop canvas y-coordinate
| scrollX | Number | `Element` scrollX | The x-scroll position to used when rendering element, (for example if the Element uses `position: fixed`)
| scrollY | Number | `Element` scrollY | The y-scroll position to used when rendering element, (for example if the Element uses `position: fixed`)
| windowWidth | Number | `Window.innerWidth` | Window width to use when rendering `Element`, which may affect things like Media queries
| windowHeight | Number | `Window.innerHeight` | Window height to use when rendering `Element`, which may affect things like Media queries

72
docs/features.md Normal file
View File

@ -0,0 +1,72 @@
---
title: "Features"
---
Below is a list of all the supported CSS properties and values.
- background
- background-clip (**Does not support `text`**)
- background-color
- background-image
- url()
- linear-gradient()
- background-origin
- background-position
- background-size
- border
- border-color
- border-radius
- border-style (**Only supports `solid`**)
- border-width
- bottom
- box-sizing
- content (**Does not support `attr()`**)
- color
- display
- flex
- float
- font
- font-family
- font-size
- font-style
- font-variant
- font-weight
- height
- left
- letter-spacing
- margin
- max-height
- max-width
- min-height
- min-width
- opacity
- overflow
- padding
- position
- right
- text-align
- text-decoration
- text-decoration-color
- text-decoration-line
- text-decoration-style (**Only supports `solid`**)
- text-shadow
- text-transform
- top
- transform (**Limited support**)
- visibility
- white-space
- width
- word-spacing
- z-index
## Unsupported CSS properties
These CSS properties are **NOT** currently supported
- [background-blend-mode](https://github.com/niklasvh/html2canvas/issues/966)
- [border-image](https://github.com/niklasvh/html2canvas/issues/1287)
- [box-shadow](https://github.com/niklasvh/html2canvas/pull/1086)
- [filter](https://github.com/niklasvh/html2canvas/issues/493)
- [font-variant-ligatures](https://github.com/niklasvh/html2canvas/pull/1085)
- [list-style](https://github.com/niklasvh/html2canvas/issues/177)
- word-break
- [writing-mode](https://github.com/niklasvh/html2canvas/issues/1258)

25
docs/getting-started.md Normal file
View File

@ -0,0 +1,25 @@
---
title: "Getting Started"
---
# Installing
You can install `html2canvas` through npm or [download a built release](https://github.com/niklasvh/html2canvas/releases).
### npm
npm install html2canvas
```javascript
import html2canvas from 'html2canvas';
```
# Usage
To render an `element` with html2canvas with some (optional) [options](/configuration/), simply call `html2canvas(element, options);`
```javascript
html2canvas(document.body).then(function(canvas) {
document.body.appendChild(canvas);
});
```

11
docs/proxy.md Normal file
View File

@ -0,0 +1,11 @@
---
title: "Proxy"
---
html2canvas does not get around content policy restrictions set by your browser. Drawing images that reside outside of
the origin of the current page taint the canvas that they are drawn upon. If the canvas gets tainted,
it cannot be read anymore. If you wish to load images that reside outside of your pages origin, you can use a proxy to load the images.
# Available proxies
- [node.js](https://github.com/niklasvh/html2canvas-proxy-nodejs)

View File

@ -3,7 +3,7 @@
"name": "html2canvas",
"description": "Screenshots with JavaScript",
"main": "dist/npm/index.js",
"version": "1.0.0-alpha.2",
"version": "1.0.0-alpha.3",
"author": {
"name": "Niklas von Hertzen",
"email": "niklasvh@gmail.com",
@ -65,7 +65,7 @@
"build": "rimraf dist/ && node scripts/create-reftest-list && npm run build:npm && npm run build:browser",
"build:npm": "babel src/ -d dist/npm/ --plugins=dev-expression,transform-es2015-modules-commonjs && replace-in-file __VERSION__ '\"$npm_package_version\"' dist/npm/index.js",
"build:browser": "webpack",
"format": "prettier --single-quote --no-bracket-spacing --tab-width 4 --print-width 100 --write \"{src,tests,scripts}/**/*.js\"",
"format": "prettier --single-quote --no-bracket-spacing --tab-width 4 --print-width 100 --write \"{src,www,tests,scripts}/**/*.js\"",
"flow": "flow",
"lint": "eslint src/**",
"test": "npm run flow && npm run lint && npm run test:node && npm run karma",

View File

@ -63,9 +63,11 @@ export class FontMetrics {
return {baseline, middle};
}
getMetrics(font: Font) {
if (this._data[`${font.fontFamily} ${font.fontSize}`] === undefined) {
this._data[`${font.fontFamily} ${font.fontSize}`] = this._parseMetrics(font);
const key = `${font.fontFamily} ${font.fontSize}`;
if (this._data[key] === undefined) {
this._data[key] = this._parseMetrics(font);
}
return this._data[`${font.fontFamily} ${font.fontSize}`];
return this._data[key];
}
}

View File

@ -20,19 +20,13 @@ import type NodeContainer from './NodeContainer';
import type StackingContext from './StackingContext';
import type {TextBounds} from './TextBounds';
import {
Bounds,
parsePathForBorder,
calculateContentBox,
calculatePaddingBox,
calculatePaddingBoxPath
} from './Bounds';
import {Bounds, parsePathForBorder, calculateContentBox, calculatePaddingBoxPath} from './Bounds';
import {FontMetrics} from './Font';
import {parseGradient} from './Gradient';
import TextContainer from './TextContainer';
import {
BACKGROUND_ORIGIN,
calculateBackgroungPositioningArea,
calculateBackgroungPaintingArea,
calculateBackgroundPosition,
calculateBackgroundRepeatPath,
@ -221,16 +215,17 @@ export default class Renderer {
renderBackgroundRepeat(container: NodeContainer, background: BackgroundImage) {
const image = this.options.imageStore.get(background.source.args[0]);
if (image) {
const bounds = container.bounds;
const paddingBox = calculatePaddingBox(bounds, container.style.border);
const backgroundImageSize = calculateBackgroundSize(background, image, bounds);
// TODO support CONTENT_BOX
const backgroundPositioningArea =
container.style.background.backgroundOrigin === BACKGROUND_ORIGIN.BORDER_BOX
? bounds
: paddingBox;
const backgroundPositioningArea = calculateBackgroungPositioningArea(
container.style.background.backgroundOrigin,
container.bounds,
container.style.padding,
container.style.border
);
const backgroundImageSize = calculateBackgroundSize(
background,
image,
backgroundPositioningArea
);
const position = calculateBackgroundPosition(
background.position,
backgroundImageSize,
@ -241,11 +236,11 @@ export default class Renderer {
position,
backgroundImageSize,
backgroundPositioningArea,
bounds
container.bounds
);
const offsetX = Math.round(paddingBox.left + position.x);
const offsetY = Math.round(paddingBox.top + position.y);
const offsetX = Math.round(backgroundPositioningArea.left + position.x);
const offsetY = Math.round(backgroundPositioningArea.top + position.y);
this.target.renderRepeat(path, image, backgroundImageSize, offsetX, offsetY);
}
}

View File

@ -66,7 +66,7 @@ const html2canvas = (element: HTMLElement, conf: ?Options): Promise<*> => {
imageTimeout: 15000,
proxy: null,
removeContainer: true,
foreignObjectRendering: true,
foreignObjectRendering: false,
scale: defaultView.devicePixelRatio || 1,
target: new CanvasRenderer(config.canvas),
x: left,

View File

@ -1,14 +1,22 @@
/* @flow */
'use strict';
import type {Path} from '../drawing/Path';
import type {Bounds, BoundCurves} from '../Bounds';
import type {BoundCurves} from '../Bounds';
import type ResourceLoader, {ImageElement} from '../ResourceLoader';
import type {Border} from './border';
import type {Padding} from './padding';
import Color from '../Color';
import Length from '../Length';
import Size from '../drawing/Size';
import Vector from '../drawing/Vector';
import {calculateBorderBoxPath, calculatePaddingBoxPath} from '../Bounds';
import {
calculateBorderBoxPath,
calculatePaddingBoxPath,
calculatePaddingBox,
Bounds
} from '../Bounds';
import {PADDING_SIDES} from './padding';
export type Background = {
backgroundImage: Array<BackgroundImage>,
@ -121,7 +129,6 @@ export const calculateBackgroungPaintingArea = (
curves: BoundCurves,
clip: BackgroundClip
): Path => {
// TODO support CONTENT_BOX
switch (clip) {
case BACKGROUND_CLIP.BORDER_BOX:
return calculateBorderBoxPath(curves);
@ -131,6 +138,34 @@ export const calculateBackgroungPaintingArea = (
}
};
export const calculateBackgroungPositioningArea = (
backgroundOrigin: BackgroundOrigin,
bounds: Bounds,
padding: Padding,
border: Array<Border>
): Bounds => {
const paddingBox = calculatePaddingBox(bounds, border);
switch (backgroundOrigin) {
case BACKGROUND_ORIGIN.BORDER_BOX:
return bounds;
case BACKGROUND_ORIGIN.CONTENT_BOX:
const paddingLeft = padding[PADDING_SIDES.LEFT].getAbsoluteValue(bounds.width);
const paddingRight = padding[PADDING_SIDES.RIGHT].getAbsoluteValue(bounds.width);
const paddingTop = padding[PADDING_SIDES.TOP].getAbsoluteValue(bounds.width);
const paddingBottom = padding[PADDING_SIDES.BOTTOM].getAbsoluteValue(bounds.width);
return new Bounds(
paddingBox.left + paddingLeft,
paddingBox.top + paddingTop,
paddingBox.width - paddingLeft - paddingRight,
paddingBox.height - paddingTop - paddingBottom
);
case BACKGROUND_ORIGIN.PADDING_BOX:
default:
return paddingBox;
}
};
export const calculateBackgroundPosition = (
position: [Length, Length],
size: Size,

View File

@ -2,6 +2,13 @@
'use strict';
import Length from '../Length';
export const PADDING_SIDES = {
TOP: 0,
RIGHT: 1,
BOTTOM: 2,
LEFT: 3
};
const SIDES = ['top', 'right', 'bottom', 'left'];
export type Padding = Array<Length>;

View File

@ -0,0 +1,34 @@
<!doctype html>
<html>
<head>
<script type="text/javascript" src="../../test.js"></script>
<style>
div {
display: inline-block;
width: 100px;
height: 100px;
border: 15px solid blue;
padding: 10px;
margin: 5px;
background-image: url(../../assets/image.jpg);
}
</style>
</head>
<body>
<div style="background-repeat: no-repeat; background-origin: content-box"></div>
<div style="background-repeat: no-repeat; background-origin: padding-box"></div>
<div style="background-repeat: no-repeat; background-origin: border-box"></div>
<div style="background-repeat: no-repeat; background-origin: content-box; background-size: cover"></div>
<div style="background-repeat: no-repeat; background-origin: padding-box; background-size: cover"></div>
<div style="background-repeat: no-repeat; background-origin: border-box; background-size: cover"></div>
<div style="background-repeat: no-repeat; background-origin: content-box; background-size: contain"></div>
<div style="background-repeat: no-repeat; background-origin: padding-box; background-size: contain"></div>
<div style="background-repeat: no-repeat; background-origin: border-box; background-size: contain"></div>
<div style="background-repeat: no-repeat; background-origin: content-box; background-position: 15px 20px"></div>
<div style="background-repeat: no-repeat; background-origin: padding-box; background-position: 15px 20px"></div>
<div style="background-repeat: no-repeat; background-origin: border-box; background-position: 15px 20px"></div>
<div style="background-repeat: repeat; background-origin: content-box"></div>
<div style="background-repeat: repeat; background-origin: padding-box"></div>
<div style="background-repeat: repeat; background-origin: border-box"></div>
</body>
</html>

View File

@ -44,7 +44,14 @@ module.exports = [
libraryTarget: 'umd'
},
module: modules,
plugins: plugins.concat([new UglifyJSPlugin(), new webpack.BannerPlugin(banner)])
plugins: [
new webpack.DefinePlugin({
'__DEV__': false,
'__VERSION__': JSON.stringify(pkg.version)
}),
new UglifyJSPlugin(),
new webpack.BannerPlugin(banner)
]
},
{
entry: './src/renderer/RefTestRenderer.js',

8
www/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Project dependencies
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
.cache/
# Build directory
public/
.DS_Store
yarn-error.log

22
www/LICENSE Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 gatsbyjs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

13
www/README.md Normal file
View File

@ -0,0 +1,13 @@
# gatsby-starter-default
The default Gatsby starter
For an overview of the project structure please refer to the [Gatsby documentation - Building with Components](https://www.gatsbyjs.org/docs/building-with-components/)
Install this starter (assuming Gatsby is installed) by running from your CLI:
```
gatsby new gatsby-example-site
```
## Deploy
[![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/gatsbyjs/gatsby-starter-default)

7
www/gatsby-browser.js Normal file
View File

@ -0,0 +1,7 @@
/**
* Implement Gatsby's Browser APIs in this file.
*
* See: https://www.gatsbyjs.org/docs/browser-apis/
*/
// You can delete this file if you're not using it

42
www/gatsby-config.js Normal file
View File

@ -0,0 +1,42 @@
module.exports = {
siteMetadata: {
title: `Gatsby Default Starter`
},
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/../docs/`
}
},
`gatsby-plugin-catch-links`,
`gatsby-plugin-react-helmet`,
`gatsby-plugin-glamor`,
{
resolve: `gatsby-plugin-typography`,
options: {
pathToConfigModule: `src/utils/typography.js`
}
},
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
{
resolve: `gatsby-remark-prismjs`,
options: {
// Class prefix for <pre> tags containing syntax highlighting;
// defaults to 'language-' (eg <pre class="language-js">).
// If your site loads Prism into the browser at runtime,
// (eg for use with libraries like react-live),
// you may use this to prevent Prism from re-processing syntax.
// This is an uncommon use-case though;
// If you're unsure, it's best to use the default value.
classPrefix: 'language-'
}
}
]
}
}
]
};

52
www/gatsby-node.js Normal file
View File

@ -0,0 +1,52 @@
/**
* Implement Gatsby's Node APIs in this file.
*
* See: https://www.gatsbyjs.org/docs/node-apis/
*/
// You can delete this file if you're not using it
const {createFilePath} = require(`gatsby-source-filesystem`);
const path = require('path');
exports.onCreateNode = ({node, getNode, boundActionCreators}) => {
const {createNodeField} = boundActionCreators;
if (node.internal.type === `MarkdownRemark`) {
const slug = createFilePath({node, getNode});
createNodeField({
node,
name: `slug`,
value: slug
});
}
};
exports.createPages = ({graphql, boundActionCreators}) => {
const {createPage} = boundActionCreators;
return new Promise((resolve, reject) => {
graphql(`
{
allMarkdownRemark {
edges {
node {
fields {
slug
}
}
}
}
}
`).then(result => {
result.data.allMarkdownRemark.edges.map(({node}) => {
createPage({
path: node.fields.slug,
component: path.resolve(__dirname, `./src/templates/docs.js`),
context: {
// Data passed to context is available in page queries as GraphQL variables.
slug: node.fields.slug
}
});
});
resolve();
});
});
};

7
www/gatsby-ssr.js Normal file
View File

@ -0,0 +1,7 @@
/**
* Implement Gatsby's SSR (Server Side Rendering) APIs in this file.
*
* See: https://www.gatsbyjs.org/docs/ssr-apis/
*/
// You can delete this file if you're not using it

12062
www/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

27
www/package.json Normal file
View File

@ -0,0 +1,27 @@
{
"name": "html2canvas-website",
"description": "https://html2canvas.hertzen.com",
"version": "1.0.0",
"private": true,
"author": "Niklas von Hertzen",
"dependencies": {
"gatsby": "^1.9.127",
"gatsby-link": "^1.6.30",
"gatsby-plugin-catch-links": "^1.0.13",
"gatsby-plugin-glamor": "^1.6.9",
"gatsby-plugin-react-helmet": "^1.0.8",
"gatsby-plugin-typography": "^1.7.10",
"gatsby-remark-prismjs": "^1.2.10",
"gatsby-source-filesystem": "^1.5.9",
"gatsby-transformer-remark": "^1.7.23",
"typography": "^0.16.6",
"typography-theme-github": "^0.15.10"
},
"license": "MIT",
"main": "n/a",
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"test": "echo \"Error: no test specified\" && exit 1"
}
}

View File

@ -0,0 +1,52 @@
import React from 'react';
import Link from 'gatsby-link';
const lineLinkStyle = {
lineHeight: '44px',
height: '44px',
padding: '0 30px',
display: 'block',
'&:hover': {
backgroundColor: 'rgba(0,0,0,0.05)'
},
transition: '.3s ease-out'
};
const navStyle = {
height: '100%',
width: '300px',
position: 'fixed',
top: 0,
left: 0,
backgroundColor: '#fff',
boxShadow:
'0 2px 2px 0 rgba(0,0,0,0.14), 0 1px 5px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.2)'
};
const links = [
{href: '/about', text: 'About'},
{href: '/getting-started', text: 'Getting started'},
{href: '/configuration', text: 'Configuration'},
{href: '/features', text: 'Features'},
{href: '/proxy', text: 'Proxy'},
{href: '/faq', text: 'FAQ'}
];
export default () =>
<div style={navStyle}>
<ul
style={{
listStyle: 'none',
margin: 0,
padding: 0
}}
>
{links.map(({href, text}, i) =>
<li style={{padding: 0, margin: 0}} key={i}>
<Link to={href} css={lineLinkStyle}>
{text}
</Link>
</li>
)}
</ul>
</div>;

624
www/src/layouts/index.css Normal file
View File

@ -0,0 +1,624 @@
html {
font-family: sans-serif;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
}
article,
aside,
details,
figcaption,
figure,
footer,
header,
main,
menu,
nav,
section,
summary {
display: block;
}
audio,
canvas,
progress,
video {
display: inline-block;
}
audio:not([controls]) {
display: none;
height: 0;
}
progress {
vertical-align: baseline;
}
[hidden],
template {
display: none;
}
a {
background-color: transparent;
-webkit-text-decoration-skip: objects;
}
a:active,
a:hover {
outline-width: 0;
}
abbr[title] {
border-bottom: none;
text-decoration: underline;
text-decoration: underline dotted;
}
b,
strong {
font-weight: inherit;
font-weight: bolder;
}
dfn {
font-style: italic;
}
h1 {
font-size: 2em;
margin: .67em 0;
}
mark {
background-color: #ff0;
color: #000;
}
small {
font-size: 80%;
}
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -.25em;
}
sup {
top: -.5em;
}
img {
border-style: none;
}
svg:not(:root) {
overflow: hidden;
}
code,
kbd,
pre,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
figure {
margin: 1em 40px;
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
button,
input,
optgroup,
select,
textarea {
font: inherit;
margin: 0;
}
optgroup {
font-weight: 700;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
[type=reset],
[type=submit],
button,
html [type=button] {
-webkit-appearance: button;
}
[type=button]::-moz-focus-inner,
[type=reset]::-moz-focus-inner,
[type=submit]::-moz-focus-inner,
button::-moz-focus-inner {
border-style: none;
padding: 0;
}
[type=button]:-moz-focusring,
[type=reset]:-moz-focusring,
[type=submit]:-moz-focusring,
button:-moz-focusring {
outline: 1px dotted ButtonText;
}
fieldset {
border: 1px solid silver;
margin: 0 2px;
padding: .35em .625em .75em;
}
legend {
box-sizing: border-box;
color: inherit;
display: table;
max-width: 100%;
padding: 0;
white-space: normal;
}
textarea {
overflow: auto;
}
[type=checkbox],
[type=radio] {
box-sizing: border-box;
padding: 0;
}
[type=number]::-webkit-inner-spin-button,
[type=number]::-webkit-outer-spin-button {
height: auto;
}
[type=search] {
-webkit-appearance: textfield;
outline-offset: -2px;
}
[type=search]::-webkit-search-cancel-button,
[type=search]::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-input-placeholder {
color: inherit;
opacity: .54;
}
::-webkit-file-upload-button {
-webkit-appearance: button;
font: inherit;
}
html {
font: 112.5%/1.45em georgia, serif;
box-sizing: border-box;
overflow-y: scroll;
}
* {
box-sizing: inherit;
}
*:before {
box-sizing: inherit;
}
*:after {
box-sizing: inherit;
}
body {
color: hsla(0, 0%, 0%, 0.8);
font-family: georgia, serif;
font-weight: normal;
word-wrap: break-word;
font-kerning: normal;
-moz-font-feature-settings: "kern", "liga", "clig", "calt";
-ms-font-feature-settings: "kern", "liga", "clig", "calt";
-webkit-font-feature-settings: "kern", "liga", "clig", "calt";
font-feature-settings: "kern", "liga", "clig", "calt";
}
img {
max-width: 100%;
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
h1 {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
color: inherit;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
font-weight: bold;
text-rendering: optimizeLegibility;
font-size: 2.25rem;
line-height: 1.1;
}
h2 {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
color: inherit;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
font-weight: bold;
text-rendering: optimizeLegibility;
font-size: 1.62671rem;
line-height: 1.1;
}
h3 {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
color: inherit;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
font-weight: bold;
text-rendering: optimizeLegibility;
font-size: 1.38316rem;
line-height: 1.1;
}
h4 {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
color: inherit;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
font-weight: bold;
text-rendering: optimizeLegibility;
font-size: 1rem;
line-height: 1.1;
}
h5 {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
color: inherit;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
font-weight: bold;
text-rendering: optimizeLegibility;
font-size: 0.85028rem;
line-height: 1.1;
}
h6 {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
color: inherit;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
font-weight: bold;
text-rendering: optimizeLegibility;
font-size: 0.78405rem;
line-height: 1.1;
}
hgroup {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
ul {
margin-left: 1.45rem;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
list-style-position: outside;
list-style-image: none;
}
ol {
margin-left: 1.45rem;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
list-style-position: outside;
list-style-image: none;
}
dl {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
dd {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
p {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
figure {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
pre {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
font-size: 0.85rem;
line-height: 1.42;
background: hsla(0, 0%, 0%, 0.04);
border-radius: 3px;
overflow: auto;
word-wrap: normal;
padding: 1.45rem;
}
table {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
font-size: 1rem;
line-height: 1.45rem;
border-collapse: collapse;
width: 100%;
}
fieldset {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
blockquote {
margin-left: 1.45rem;
margin-right: 1.45rem;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
form {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
noscript {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
iframe {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
hr {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: calc(1.45rem - 1px);
background: hsla(0, 0%, 0%, 0.2);
border: none;
height: 1px;
}
address {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
b {
font-weight: bold;
}
strong {
font-weight: bold;
}
dt {
font-weight: bold;
}
th {
font-weight: bold;
}
li {
margin-bottom: calc(1.45rem / 2);
}
ol li {
padding-left: 0;
}
ul li {
padding-left: 0;
}
li > ol {
margin-left: 1.45rem;
margin-bottom: calc(1.45rem / 2);
margin-top: calc(1.45rem / 2);
}
li > ul {
margin-left: 1.45rem;
margin-bottom: calc(1.45rem / 2);
margin-top: calc(1.45rem / 2);
}
blockquote *:last-child {
margin-bottom: 0;
}
li *:last-child {
margin-bottom: 0;
}
p *:last-child {
margin-bottom: 0;
}
li > p {
margin-bottom: calc(1.45rem / 2);
}
code {
font-size: 0.85rem;
line-height: 1.45rem;
}
kbd {
font-size: 0.85rem;
line-height: 1.45rem;
}
samp {
font-size: 0.85rem;
line-height: 1.45rem;
}
abbr {
border-bottom: 1px dotted hsla(0, 0%, 0%, 0.5);
cursor: help;
}
acronym {
border-bottom: 1px dotted hsla(0, 0%, 0%, 0.5);
cursor: help;
}
abbr[title] {
border-bottom: 1px dotted hsla(0, 0%, 0%, 0.5);
cursor: help;
text-decoration: none;
}
thead {
text-align: left;
}
td,
th {
text-align: left;
border-bottom: 1px solid hsla(0, 0%, 0%, 0.12);
font-feature-settings: "tnum";
-moz-font-feature-settings: "tnum";
-ms-font-feature-settings: "tnum";
-webkit-font-feature-settings: "tnum";
padding-left: 0.96667rem;
padding-right: 0.96667rem;
padding-top: 0.725rem;
padding-bottom: calc(0.725rem - 1px);
}
th:first-child,
td:first-child {
padding-left: 0;
}
th:last-child,
td:last-child {
padding-right: 0;
}
tt,
code {
background-color: hsla(0, 0%, 0%, 0.04);
border-radius: 3px;
font-family: "SFMono-Regular", Consolas, "Roboto Mono", "Droid Sans Mono",
"Liberation Mono", Menlo, Courier, monospace;
padding: 0;
padding-top: 0.2em;
padding-bottom: 0.2em;
}
pre code {
background: none;
line-height: 1.42;
}
code:before,
code:after,
tt:before,
tt:after {
letter-spacing: -0.2em;
content: " ";
}
pre code:before,
pre code:after,
pre tt:before,
pre tt:after {
content: "";
}
@media only screen and (max-width: 480px) {
html {
font-size: 100%;
}
}

25
www/src/layouts/index.js Normal file
View File

@ -0,0 +1,25 @@
import React from 'react';
import PropTypes from 'prop-types';
import Helmet from 'react-helmet';
import Navigation from '../components/navigation';
require('prismjs/themes/prism-solarizedlight.css');
import './index.css';
const TemplateWrapper = ({children}) =>
<div>
<Helmet
title="Gatsby Default Starter"
meta={[
{name: 'description', content: 'Sample'},
{name: 'keywords', content: 'sample, something'}
]}
/>
<Navigation />
{children()}
</div>;
TemplateWrapper.propTypes = {
children: PropTypes.func
};
export default TemplateWrapper;

9
www/src/pages/404.js Normal file
View File

@ -0,0 +1,9 @@
import React from 'react';
const NotFoundPage = () =>
<div>
<h1>NOT FOUND</h1>
<p>You just hit a route that doesn&#39;t exist... the sadness.</p>
</div>;
export default NotFoundPage;

12
www/src/pages/index.js Normal file
View File

@ -0,0 +1,12 @@
import React from 'react';
import Link from 'gatsby-link';
const IndexPage = () =>
<div>
<h1>Hi people</h1>
<p>Welcome to your new Gatsby site.</p>
<p>Now go build something great.</p>
<Link to="/page-2/">Go to page 2</Link>
</div>;
export default IndexPage;

47
www/src/templates/docs.js Normal file
View File

@ -0,0 +1,47 @@
import React from 'react';
export default ({data}) => {
const post = data.markdownRemark;
return (
<div>
<div
style={{
marginLeft: '300px',
background: '#01579b',
marginBottom: '1.45rem',
color: '#fff'
}}
>
{' '}<div css={{width: '85%', margin: '0 auto'}}>
<h1 css={{padding: '20px 0'}}>
{post.frontmatter.title}
</h1>
</div>
</div>
<div
style={{
margin: '0 auto',
maxWidth: 960,
marginLeft: '300px',
paddingTop: 0
}}
>
<div
css={{width: '85%', margin: '0 auto'}}
dangerouslySetInnerHTML={{__html: post.html}}
/>
</div>
</div>
);
};
export const query = graphql`
query DocsQuery($slug: String!) {
markdownRemark(fields: {slug: {eq: $slug}}) {
html
frontmatter {
title
}
}
}
`;

View File

@ -0,0 +1,6 @@
import Typography from 'typography';
import githubTheme from 'typography-theme-github';
const typography = new Typography(githubTheme);
export default typography;