Compare commits

...

37 Commits

Author SHA1 Message Date
f347953042 Remove iOS 8.4 tests 2018-04-01 17:42:27 +08:00
48b4c20e24 v1.0.0-alpha.11 2018-04-01 17:14:38 +08:00
6341788edf Update package-lock.json 2018-04-01 17:09:49 +08:00
0e273418c7 IE11 Member not found fix Wrap accesing the cssText property in a try...catch (#1415)
* https://github.com/niklasvh/html2canvas/issues/1374 - Wrap accesing the cssText property in a try...catch
2018-04-01 16:49:23 +08:00
e6bbc1abb5 Merge pull request #1487 from mapleeit/support-blob-image-resources
support blob image resources in non-foreignObjectRendering mode
2018-04-01 16:43:40 +08:00
13bbc90048 support blob image resources in non-foreignObjectRendering mode 2018-03-30 16:37:18 +08:00
102b5a1282 v1.0.0-alpha.10 2018-02-15 22:50:40 +08:00
01e4920876 Fix window reference for node tests 2018-02-15 22:19:25 +08:00
da2794f7f7 Fix version logging (Fix #1421) 2018-02-15 22:07:40 +08:00
9fb9898894 Re-introduce onclone option (Fix #1434) 2018-02-15 21:40:48 +08:00
952eb4cf7c Fix Travis chrome tests 2018-02-15 21:28:11 +08:00
fad4f837c9 Add ignoreElements predicate function option 2018-02-15 21:26:09 +08:00
e6c44afca1 Merge pull request #1417 from eKoopmans/bugfix/underlines
Revert "Fix underlines, relative to 'bottom' baseline"
2018-02-15 21:00:48 +08:00
d023de0b99 Revert "Fix underlines, relative to 'bottom' baseline"
This reverts commit 0c8d38d9c0.
2018-01-26 18:10:15 +11:00
0f01810005 Update website styles 2018-01-08 22:21:11 +08:00
bf03cf5237 Make website responsive 2018-01-08 21:38:54 +08:00
a555dfc085 Revert "Revert "Update html2canvas version""
This reverts commit 69fb48969e.
2018-01-08 20:42:48 +08:00
69fb48969e Revert "Update html2canvas version"
This reverts commit c9a60c4ff9.

# Conflicts:
#	www/package-lock.json
#	www/package.json
2018-01-07 23:19:47 +08:00
974c35c368 Update website html2canvas package 2018-01-07 22:14:16 +08:00
0fe9632a32 v1.0.0-alpha.9 2018-01-07 20:56:59 +08:00
c9a60c4ff9 Update html2canvas version 2018-01-07 20:54:22 +08:00
4c14894a0a Correctly clone dynami CSSStyleSheets (Fix #1370) 2018-01-07 20:13:26 +08:00
8788a9f458 Add npm badges 2018-01-07 19:22:36 +08:00
e198eae398 Merge branch 'jkrielaars-border-radius' 2018-01-07 19:20:24 +08:00
474b5e81a7 Refactor border-radius update 2018-01-07 19:19:55 +08:00
b97972eeb6 updated calculation of border-radius 2018-01-04 08:59:38 +01:00
b7c7464c5f v1.0.0-alpha.8 2018-01-02 20:24:12 +08:00
ae019f174c Use correct doctype in cloned Document (Fix #1298) 2018-01-02 20:06:24 +08:00
ea6062c85b Fix individual border rendering (Fix #1349) 2018-01-02 20:04:28 +08:00
9a4a506366 v1.0.0-alpha.7 2017-12-31 20:22:20 +08:00
cb93b80d0d Add thai text test 2017-12-31 20:19:27 +08:00
79e1c857e6 Fix form input text positions (Fix #1338 #1347) 2017-12-31 19:38:31 +08:00
cc9d1f89dc Merge pull request #1348 from niklasvh/line-breaking
Implement unicode line-breaking
2017-12-31 19:14:26 +08:00
d0f7ecfa9a Update css-line-breaking to 1.0.1 2017-12-31 00:24:38 +08:00
1870433307 Implement unicode line-breaking 2017-12-31 00:14:21 +08:00
3a5ed43e97 Update package-lock.json 2017-12-29 19:15:49 +08:00
8429761e8f Fix tag names 2017-12-28 14:25:29 +08:00
40 changed files with 3477 additions and 1349 deletions

View File

@ -9,7 +9,7 @@ addons:
chrome: stable
firefox: latest
dist: trusty
sudo: false
sudo: true
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start

View File

@ -1,33 +1,54 @@
### Changelog ###
#### v1.0.0-alpha6 - 28.12.2017 ####
#### v1.0.0-alpha.11 - 1.4.2018 ####
* Fix IE11 member not found error
* Support blob image resources in non-foreignObjectRendering mode
#### v1.0.0-alpha.10 - 15.2.2018 ####
* Re-introduce `onclone` option (Fix #1434)
* Add `ignoreElements` predicate function option
* Fix version console logging
#### v1.0.0-alpha.9 - 7.1.2018 ####
* Fix dynamic style sheets
* Fix > 50% border-radius values
#### v1.0.0-alpha.8 - 2.1.2018 ####
* Use correct doctype in cloned Document (Fix #1298)
* Fix individual border rendering (Fix #1349)
#### v1.0.0-alpha.7 - 31.12.2017 ####
* Fix form input rendering (#1338)
* Improve word line breaking algorithm
#### v1.0.0-alpha.6 - 28.12.2017 ####
* Fix list-style: none (#1340)
* Extend supported values for pseudo element content
#### v1.0.0-alpha5 - 21.12.2017 ####
#### v1.0.0-alpha.5 - 21.12.2017 ####
* Fix underline positioning
* Fix canvas rendering on Chrome
* Fix overflow: auto
* Added support for rendering list-style
#### v1.0.0-alpha4 - 12.12.2017 ####
#### v1.0.0-alpha.4 - 12.12.2017 ####
* Fix rendering with multiple fonts defined (Fix #796)
* Add support for radial-gradients
* Fix logging option (#1302)
* Add support for rendering webgl canvas content (#646)
* Fix external SVG loading with proxies (#802)
#### v1.0.0-alpha3 - 9.12.2017 ####
#### v1.0.0-alpha.3 - 9.12.2017 ####
* 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 ####
#### v1.0.0-alpha.2 - 7.12.2017 ####
* Fix scroll positions for CanvasRenderer (#1259)
* Fix `data-html2canvas-ignore` attribute (#1253)
* Fix decimal `letter-spacing` values (#1293)
#### v1.0.0-alpha1 - 5.12.2017 ####
#### v1.0.0-alpha.1 - 5.12.2017 ####
* Complete rewrite of library
##### Breaking Changes #####
* Remove deprecated onrendered callback, calling `html2canvas` returns a `Promise<HTMLCanvasElement>`

View File

@ -3,7 +3,10 @@ html2canvas
[Homepage](https://html2canvas.hertzen.com) | [Downloads](https://github.com/niklasvh/html2canvas/releases) | [Questions](http://stackoverflow.com/questions/tagged/html2canvas?sort=newest) | [Donate](https://www.gittip.com/niklasvh/)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/niklasvh/html2canvas?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Build Status](https://travis-ci.org/niklasvh/html2canvas.svg)](https://travis-ci.org/niklasvh/html2canvas)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/niklasvh/html2canvas?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![Build Status](https://travis-ci.org/niklasvh/html2canvas.svg)](https://travis-ci.org/niklasvh/html2canvas)
[![NPM Downloads](https://img.shields.io/npm/dm/html2canvas.svg)](https://www.npmjs.org/package/html2canvas)
[![NPM Version](https://img.shields.io/npm/v/html2canvas.svg)](https://www.npmjs.org/package/html2canvas)
#### JavaScript HTML renderer ####

View File

@ -1,5 +1,5 @@
---
title: "Configuration"
title: "Options"
description: "Explore the different configuration options available for html2canvas"
previousUrl: "/getting-started"
previousTitle: "Getting Started"
@ -17,7 +17,9 @@ These are all of the available configuration options.
| canvas | `null` | Existing `canvas` element to use as a base for drawing on
| foreignObjectRendering | `false` | Whether to use ForeignObject rendering if the browser supports it
| imageTimeout | `15000` | Timeout for loading an image (in milliseconds). Set to `0` to disable timeout.
| ignoreElements | `(element) => false` | Predicate function which removes the matching elements from the render.
| logging | `true` | Enable logging for debug purposes
| onclone | `null` | Callback function which is called when the Document has been cloned for rendering, can be used to modify the contents that will be rendered without affecting the original source document.
| proxy | `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 | `true` | Whether to cleanup the cloned DOM elements html2canvas creates temporarily
| scale | `window.devicePixelRatio` | The scale to use for rendering. Defaults to the browsers device pixel ratio.

View File

@ -36,6 +36,7 @@ Below is a list of all the supported CSS properties and values.
- height
- left
- letter-spacing
- line-break
- list-style
- list-style-image
- list-style-position
@ -47,6 +48,7 @@ Below is a list of all the supported CSS properties and values.
- min-width
- opacity
- overflow
- overflow-wrap
- padding
- position
- right
@ -62,7 +64,9 @@ Below is a list of all the supported CSS properties and values.
- visibility
- white-space
- width
- word-break
- word-spacing
- word-wrap
- z-index
## Unsupported CSS properties
@ -76,8 +80,6 @@ These CSS properties are **NOT** currently supported
- [mix-blend-mode](https://github.com/niklasvh/html2canvas/issues/580)
- [object-fit](https://github.com/niklasvh/html2canvas/issues/1064)
- [repeating-linear-gradient()](https://github.com/niklasvh/html2canvas/issues/1162)
- word-break
- [word-wrap](https://github.com/niklasvh/html2canvas/issues/664)
- [writing-mode](https://github.com/niklasvh/html2canvas/issues/1258)
- [zoom](https://github.com/niklasvh/html2canvas/issues/732)

View File

@ -66,13 +66,6 @@ module.exports = function(config) {
platform: 'iOS',
version: '9.3',
device: 'iPhone 6 Plus Simulator'
},
'sl_ios_8.4_safari': {
base: 'SauceLabs',
browserName: 'Safari',
platform: 'iOS',
version: '8.4',
device: 'iPhone 5s Simulator'
}
};

3857
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
"name": "html2canvas",
"description": "Screenshots with JavaScript",
"main": "dist/npm/index.js",
"version": "1.0.0-alpha.6",
"version": "1.0.0-alpha.11",
"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,www,tests,scripts}/**/*.js\"",
"format": "prettier --single-quote --no-bracket-spacing --tab-width 4 --print-width 100 --write \"{src,www/src,tests,scripts}/**/*.js\"",
"flow": "flow",
"lint": "eslint src/**",
"test": "npm run flow && npm run lint && npm run test:node && npm run karma",
@ -77,6 +77,6 @@
"homepage": "https://html2canvas.hertzen.com",
"license": "MIT",
"dependencies": {
"punycode": "2.1.0"
"css-line-break": "1.0.1"
}
}

View File

@ -202,40 +202,32 @@ export const parseBoundCurves = (
borders: Array<Border>,
borderRadius: Array<BorderRadius>
): BoundCurves => {
const HALF_WIDTH = bounds.width / 2;
const HALF_HEIGHT = bounds.height / 2;
const tlh =
borderRadius[CORNER.TOP_LEFT][H].getAbsoluteValue(bounds.width) < HALF_WIDTH
? borderRadius[CORNER.TOP_LEFT][H].getAbsoluteValue(bounds.width)
: HALF_WIDTH;
const tlv =
borderRadius[CORNER.TOP_LEFT][V].getAbsoluteValue(bounds.height) < HALF_HEIGHT
? borderRadius[CORNER.TOP_LEFT][V].getAbsoluteValue(bounds.height)
: HALF_HEIGHT;
const trh =
borderRadius[CORNER.TOP_RIGHT][H].getAbsoluteValue(bounds.width) < HALF_WIDTH
? borderRadius[CORNER.TOP_RIGHT][H].getAbsoluteValue(bounds.width)
: HALF_WIDTH;
const trv =
borderRadius[CORNER.TOP_RIGHT][V].getAbsoluteValue(bounds.height) < HALF_HEIGHT
? borderRadius[CORNER.TOP_RIGHT][V].getAbsoluteValue(bounds.height)
: HALF_HEIGHT;
const brh =
borderRadius[CORNER.BOTTOM_RIGHT][H].getAbsoluteValue(bounds.width) < HALF_WIDTH
? borderRadius[CORNER.BOTTOM_RIGHT][H].getAbsoluteValue(bounds.width)
: HALF_WIDTH;
const brv =
borderRadius[CORNER.BOTTOM_RIGHT][V].getAbsoluteValue(bounds.height) < HALF_HEIGHT
? borderRadius[CORNER.BOTTOM_RIGHT][V].getAbsoluteValue(bounds.height)
: HALF_HEIGHT;
const blh =
borderRadius[CORNER.BOTTOM_LEFT][H].getAbsoluteValue(bounds.width) < HALF_WIDTH
? borderRadius[CORNER.BOTTOM_LEFT][H].getAbsoluteValue(bounds.width)
: HALF_WIDTH;
const blv =
borderRadius[CORNER.BOTTOM_LEFT][V].getAbsoluteValue(bounds.height) < HALF_HEIGHT
? borderRadius[CORNER.BOTTOM_LEFT][V].getAbsoluteValue(bounds.height)
: HALF_HEIGHT;
let tlh = borderRadius[CORNER.TOP_LEFT][H].getAbsoluteValue(bounds.width);
let tlv = borderRadius[CORNER.TOP_LEFT][V].getAbsoluteValue(bounds.height);
let trh = borderRadius[CORNER.TOP_RIGHT][H].getAbsoluteValue(bounds.width);
let trv = borderRadius[CORNER.TOP_RIGHT][V].getAbsoluteValue(bounds.height);
let brh = borderRadius[CORNER.BOTTOM_RIGHT][H].getAbsoluteValue(bounds.width);
let brv = borderRadius[CORNER.BOTTOM_RIGHT][V].getAbsoluteValue(bounds.height);
let blh = borderRadius[CORNER.BOTTOM_LEFT][H].getAbsoluteValue(bounds.width);
let blv = borderRadius[CORNER.BOTTOM_LEFT][V].getAbsoluteValue(bounds.height);
const factors = [];
factors.push((tlh + trh) / bounds.width);
factors.push((blh + brh) / bounds.width);
factors.push((tlv + blv) / bounds.height);
factors.push((trv + brv) / bounds.height);
const maxFactor = Math.max(...factors);
if (maxFactor > 1) {
tlh /= maxFactor;
tlv /= maxFactor;
trh /= maxFactor;
trv /= maxFactor;
brh /= maxFactor;
brv /= maxFactor;
blh /= maxFactor;
blv /= maxFactor;
}
const topWidth = bounds.width - trh;
const rightHeight = bounds.height - brv;

View File

@ -229,6 +229,23 @@ export class DocumentCloner {
return tempIframe;
}
if (node instanceof HTMLStyleElement && node.sheet && node.sheet.cssRules) {
const css = [].slice.call(node.sheet.cssRules, 0).reduce((css, rule) => {
try {
if (rule && rule.cssText) {
return css + rule.cssText;
}
return css;
} catch (err) {
this.logger.log('Unable to access cssText property', rule.name);
return css;
}
}, '');
const style = node.cloneNode(false);
style.textContent = css;
return style;
}
return node.cloneNode(false);
}
@ -259,8 +276,12 @@ export class DocumentCloner {
for (let child = node.firstChild; child; child = child.nextSibling) {
if (
child.nodeType !== Node.ELEMENT_NODE ||
// $FlowFixMe
(child.nodeName !== 'SCRIPT' && !child.hasAttribute(IGNORE_ATTRIBUTE))
(child.nodeName !== 'SCRIPT' &&
// $FlowFixMe
!child.hasAttribute(IGNORE_ATTRIBUTE) &&
(typeof this.options.ignoreElements !== 'function' ||
// $FlowFixMe
!this.options.ignoreElements(child)))
) {
if (!this.copyStyles || child.nodeName !== 'STYLE') {
clone.appendChild(this.cloneNode(child));
@ -598,14 +619,21 @@ export const cloneWindow = (
documentClone.documentElement.style.left = -bounds.left + 'px';
documentClone.documentElement.style.position = 'absolute';
}
const result = Promise.resolve([
cloneIframeContainer,
cloner.clonedReferenceElement,
cloner.resourceLoader
]);
const onclone = options.onclone;
return cloner.clonedReferenceElement instanceof cloneWindow.HTMLElement ||
cloner.clonedReferenceElement instanceof ownerDocument.defaultView.HTMLElement ||
cloner.clonedReferenceElement instanceof HTMLElement
? Promise.resolve([
cloneIframeContainer,
cloner.clonedReferenceElement,
cloner.resourceLoader
])
? typeof onclone === 'function'
? Promise.resolve().then(() => onclone(documentClone)).then(() => result)
: result
: Promise.reject(
__DEV__
? `Error finding the ${referenceElement.nodeName} in the cloned document`
@ -614,7 +642,7 @@ export const cloneWindow = (
});
documentClone.open();
documentClone.write('<!DOCTYPE html><html></html>');
documentClone.write(`${serializeDoctype(document.doctype)}<html></html>`);
// Chrome scrolls the parent document for some reason after the write to the cloned window???
restoreOwnerScroll(referenceElement.ownerDocument, scrollX, scrollY);
documentClone.replaceChild(
@ -626,3 +654,29 @@ export const cloneWindow = (
return iframeLoad;
});
};
const serializeDoctype = (doctype: ?DocumentType): string => {
let str = '';
if (doctype) {
str += '<!DOCTYPE ';
if (doctype.name) {
str += doctype.name;
}
if (doctype.internalSubset) {
str += doctype.internalSubset;
}
if (doctype.publicId) {
str += `"${doctype.publicId}"`;
}
if (doctype.systemId) {
str += `"${doctype.systemId}"`;
}
str += '>';
}
return str;
};

View File

@ -133,7 +133,7 @@ const inlineFormElement = (
if (value.length > 0 && body) {
const wrapper = node.ownerDocument.createElement('html2canvaswrapper');
copyCSSStyles(node.ownerDocument.defaultView.getComputedStyle(node, null), wrapper);
wrapper.style.position = 'fixed';
wrapper.style.position = 'absolute';
wrapper.style.left = `${container.bounds.left}px`;
wrapper.style.top = `${container.bounds.top}px`;
if (!allowLinebreak) {

View File

@ -7,7 +7,7 @@ export default class Logger {
id: ?string;
constructor(enabled: boolean, id: ?string, start: ?number) {
this.enabled = enabled;
this.enabled = typeof window !== 'undefined' && enabled;
this.start = start ? start : Date.now();
this.id = id;
}

View File

@ -7,9 +7,11 @@ import type {BorderRadius} from './parsing/borderRadius';
import type {DisplayBit} from './parsing/display';
import type {Float} from './parsing/float';
import type {Font} from './parsing/font';
import type {LineBreak} from './parsing/lineBreak';
import type {ListStyle} from './parsing/listStyle';
import type {Margin} from './parsing/margin';
import type {Overflow} from './parsing/overflow';
import type {OverflowWrap} from './parsing/overflowWrap';
import type {Padding} from './parsing/padding';
import type {Position} from './parsing/position';
import type {TextShadow} from './parsing/textShadow';
@ -17,6 +19,7 @@ import type {TextTransform} from './parsing/textTransform';
import type {TextDecoration} from './parsing/textDecoration';
import type {Transform} from './parsing/transform';
import type {Visibility} from './parsing/visibility';
import type {WordBreak} from './parsing/word-break';
import type {zIndex} from './parsing/zIndex';
import type {Bounds, BoundCurves} from './Bounds';
@ -34,9 +37,11 @@ import {parseDisplay, DISPLAY} from './parsing/display';
import {parseCSSFloat, FLOAT} from './parsing/float';
import {parseFont} from './parsing/font';
import {parseLetterSpacing} from './parsing/letterSpacing';
import {parseLineBreak} from './parsing/lineBreak';
import {parseListStyle} from './parsing/listStyle';
import {parseMargin} from './parsing/margin';
import {parseOverflow, OVERFLOW} from './parsing/overflow';
import {parseOverflowWrap} from './parsing/overflowWrap';
import {parsePadding} from './parsing/padding';
import {parsePosition, POSITION} from './parsing/position';
import {parseTextDecoration} from './parsing/textDecoration';
@ -44,6 +49,7 @@ import {parseTextShadow} from './parsing/textShadow';
import {parseTextTransform} from './parsing/textTransform';
import {parseTransform} from './parsing/transform';
import {parseVisibility, VISIBILITY} from './parsing/visibility';
import {parseWordBreak} from './parsing/word-break';
import {parseZIndex} from './parsing/zIndex';
import {parseBounds, parseBoundCurves, calculatePaddingBoxPath} from './Bounds';
@ -65,10 +71,12 @@ type StyleDeclaration = {
float: Float,
font: Font,
letterSpacing: number,
lineBreak: LineBreak,
listStyle: ListStyle | null,
margin: Margin,
opacity: number,
overflow: Overflow,
overflowWrap: OverflowWrap,
padding: Padding,
position: Position,
textDecoration: TextDecoration | null,
@ -76,6 +84,7 @@ type StyleDeclaration = {
textTransform: TextTransform,
transform: Transform,
visibility: Visibility,
wordBreak: WordBreak,
zIndex: zIndex
};
@ -134,12 +143,16 @@ export default class NodeContainer {
font: parseFont(style),
letterSpacing: parseLetterSpacing(style.letterSpacing),
listStyle: display === DISPLAY.LIST_ITEM ? parseListStyle(style) : null,
lineBreak: parseLineBreak(style.lineBreak),
margin: parseMargin(style),
opacity: parseFloat(style.opacity),
overflow:
INPUT_TAGS.indexOf(node.tagName) === -1
? parseOverflow(style.overflow)
: OVERFLOW.HIDDEN,
overflowWrap: parseOverflowWrap(
style.overflowWrap ? style.overflowWrap : style.wordWrap
),
padding: parsePadding(style),
position: position,
textDecoration: parseTextDecoration(style),
@ -147,6 +160,7 @@ export default class NodeContainer {
textTransform: parseTextTransform(style.textTransform),
transform: parseTransform(style),
visibility: parseVisibility(style.visibility),
wordBreak: parseWordBreak(style.wordBreak),
zIndex: parseZIndex(position !== POSITION.STATIC ? style.zIndex : 'auto')
};

View File

@ -165,7 +165,7 @@ export default class Renderer {
!container.style.background.backgroundColor.isTransparent() ||
container.style.background.backgroundImage.length;
const renderableBorders = container.style.border.filter(
const hasRenderableBorders = container.style.border.some(
border =>
border.borderStyle !== BORDER_STYLE.NONE && !border.borderColor.isTransparent()
);
@ -186,12 +186,17 @@ export default class Renderer {
});
}
renderableBorders.forEach((border, side) => {
this.renderBorder(border, side, container.curvedBounds);
container.style.border.forEach((border, side) => {
if (
border.borderStyle !== BORDER_STYLE.NONE &&
!border.borderColor.isTransparent()
) {
this.renderBorder(border, side, container.curvedBounds);
}
});
};
if (HAS_BACKGROUND || renderableBorders.length) {
if (HAS_BACKGROUND || hasRenderableBorders) {
const paths = container.parent ? container.parent.getClipPaths() : [];
if (paths.length) {
this.target.clip(paths, callback);

View File

@ -33,6 +33,10 @@ export default class ResourceLoader {
if (this.hasResourceInCache(src)) {
return src;
}
if (isBlobImage(src)) {
this.cache[src] = loadImage(src, this.options.imageTimeout || 0);
return src;
}
if (!isSVG(src) || FEATURES.SUPPORT_SVG_DRAWING) {
if (this.options.allowTaint === true || isInlineImage(src) || this.isSameOrigin(src)) {
@ -215,6 +219,7 @@ const INLINE_IMG = /^data:image\/.*/i;
const isInlineImage = (src: string): boolean => INLINE_IMG.test(src);
const isInlineBase64Image = (src: string): boolean => INLINE_BASE64.test(src);
const isBlobImage = (src: string): boolean => src.substr(0, 4) === 'blob';
const isSVG = (src: string): boolean =>
src.substr(-3).toLowerCase() === 'svg' || INLINE_SVG.test(src);

View File

@ -1,18 +1,12 @@
/* @flow */
'use strict';
import {ucs2} from 'punycode';
import type NodeContainer from './NodeContainer';
import {Bounds, parseBounds} from './Bounds';
import {TEXT_DECORATION} from './parsing/textDecoration';
import FEATURES from './Feature';
const UNICODE = /[^\u0000-\u00ff]/;
const hasUnicodeCharacters = (text: string): boolean => UNICODE.test(text);
const encodeCodePoint = (codePoint: number): string => ucs2.encode([codePoint]);
import {breakWords, toCodePoints, fromCodePoint} from './Unicode';
export class TextBounds {
text: string;
@ -29,9 +23,10 @@ export const parseTextBounds = (
parent: NodeContainer,
node: Text
): Array<TextBounds> => {
const codePoints = ucs2.decode(value);
const letterRendering = parent.style.letterSpacing !== 0 || hasUnicodeCharacters(value);
const textList = letterRendering ? codePoints.map(encodeCodePoint) : splitWords(codePoints);
const letterRendering = parent.style.letterSpacing !== 0;
const textList = letterRendering
? toCodePoints(value).map(i => fromCodePoint(i))
: breakWords(value, parent);
const length = textList.length;
const defaultView = node.parentNode ? node.parentNode.ownerDocument.defaultView : null;
const scrollX = defaultView ? defaultView.pageXOffset : 0;
@ -88,42 +83,3 @@ const getRangeBounds = (
range.setEnd(node, offset + length);
return Bounds.fromClientRect(range.getBoundingClientRect(), scrollX, scrollY);
};
const splitWords = (codePoints: Array<number>): Array<string> => {
const words = [];
let i = 0;
let onWordBoundary = false;
let word;
while (codePoints.length) {
if (isWordBoundary(codePoints[i]) === onWordBoundary) {
word = codePoints.splice(0, i);
if (word.length) {
words.push(ucs2.encode(word));
}
onWordBoundary = !onWordBoundary;
i = 0;
} else {
i++;
}
if (i >= codePoints.length) {
word = codePoints.splice(0, i);
if (word.length) {
words.push(ucs2.encode(word));
}
}
}
return words;
};
const isWordBoundary = (characterCode: number): boolean => {
return (
[
32, // <space>
13, // \r
10, // \n
9, // \t
45 // -
].indexOf(characterCode) !== -1
);
};

View File

@ -1,32 +1,27 @@
/* @flow */
'use strict';
export const fromCodePoint = (...codePoints: Array<number>): string => {
if (String.fromCodePoint) {
return String.fromCodePoint(...codePoints);
import NodeContainer from './NodeContainer';
import {LineBreaker, fromCodePoint, toCodePoints} from 'css-line-break';
import {OVERFLOW_WRAP} from './parsing/overflowWrap';
export {toCodePoints, fromCodePoint} from 'css-line-break';
export const breakWords = (str: string, parent: NodeContainer): Array<string> => {
const breaker = LineBreaker(str, {
lineBreak: parent.style.lineBreak,
wordBreak:
parent.style.overflowWrap === OVERFLOW_WRAP.BREAK_WORD
? 'break-word'
: parent.style.wordBreak
});
const words = [];
let bk;
while (!(bk = breaker.next()).done) {
words.push(bk.value.slice());
}
const length = codePoints.length;
if (!length) {
return '';
}
const codeUnits = [];
let index = -1;
let result = '';
while (++index < length) {
let codePoint = codePoints[index];
if (codePoint <= 0xffff) {
codeUnits.push(codePoint);
} else {
codePoint -= 0x10000;
codeUnits.push((codePoint >> 10) + 0xd800, codePoint % 0x400 + 0xdc00);
}
if (index + 1 === length || codeUnits.length > 0x4000) {
result += String.fromCharCode(...codeUnits);
codeUnits.length = 0;
}
}
return result;
return words;
};

View File

@ -14,8 +14,10 @@ export type Options = {
backgroundColor: string,
canvas: ?HTMLCanvasElement,
foreignObjectRendering: boolean,
ignoreElements?: HTMLElement => boolean,
imageTimeout: number,
logging: boolean,
onclone?: Document => void,
proxy: ?string,
removeContainer: ?boolean,
scale: number,
@ -32,14 +34,9 @@ export type Options = {
};
const html2canvas = (element: HTMLElement, conf: ?Options): Promise<*> => {
// eslint-disable-next-line no-console
if (typeof console === 'object' && typeof console.log === 'function') {
// eslint-disable-next-line no-console
console.log(`html2canvas ${__VERSION__}`);
}
const config = conf || {};
const logger = new Logger(typeof config.logging === 'boolean' ? config.logging : true);
logger.log(`html2canvas ${__VERSION__}`);
if (__DEV__ && typeof config.onrendered === 'function') {
logger.error(

19
src/parsing/lineBreak.js Normal file
View File

@ -0,0 +1,19 @@
/* @flow */
'use strict';
export const LINE_BREAK = {
NORMAL: 'normal',
STRICT: 'strict'
};
export type LineBreak = $Values<typeof LINE_BREAK>;
export const parseLineBreak = (wordBreak: string): LineBreak => {
switch (wordBreak) {
case 'strict':
return LINE_BREAK.STRICT;
case 'normal':
default:
return LINE_BREAK.NORMAL;
}
};

View File

@ -0,0 +1,19 @@
/* @flow */
'use strict';
export const OVERFLOW_WRAP = {
NORMAL: 0,
BREAK_WORD: 1
};
export type OverflowWrap = $Values<typeof OVERFLOW_WRAP>;
export const parseOverflowWrap = (overflow: string): OverflowWrap => {
switch (overflow) {
case 'break-word':
return OVERFLOW_WRAP.BREAK_WORD;
case 'normal':
default:
return OVERFLOW_WRAP.NORMAL;
}
};

22
src/parsing/word-break.js Normal file
View File

@ -0,0 +1,22 @@
/* @flow */
'use strict';
export const WORD_BREAK = {
NORMAL: 'normal',
BREAK_ALL: 'break-all',
KEEP_ALL: 'keep-all'
};
export type WordBreak = $Values<typeof WORD_BREAK>;
export const parseWordBreak = (wordBreak: string): WordBreak => {
switch (wordBreak) {
case 'break-all':
return WORD_BREAK.BREAK_ALL;
case 'keep-all':
return WORD_BREAK.KEEP_ALL;
case 'normal':
default:
return WORD_BREAK.NORMAL;
}
};

View File

@ -250,7 +250,7 @@ export default class CanvasRenderer implements RenderTarget<HTMLCanvasElement> {
const {baseline} = this.options.fontMetrics.getMetrics(font);
this.rectangle(
text.bounds.left,
Math.round(text.bounds.top + text.bounds.height - baseline),
Math.round(text.bounds.top + baseline),
text.bounds.width,
1,
textDecorationColor

View File

@ -5,7 +5,7 @@
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="../../test.js"></script>
<style type="text/css">
div {
.box {
width: 200px;
height: 200px;
display: inline-block;
@ -63,6 +63,21 @@
border-radius: 200px;
}
.gauge{
display: inline-block;
width: 100px;
height: 50px;
background: green;
margin-bottom: 20px;
}
.gauge1{ border-radius: 25px 25px 0 0 / 25px 25px 0 0; }
.gauge2{ border-radius: 100px 100px 0 0 / 50px 50px 0 0; }
.gauge3{ border-radius: 100px 100px 0 0 / 100px 100px 0 0; }
.gauge4{ border-radius: 300px 100px 0 0 / 100px 100px 0 0; }
.gauge5{ border-radius: 400px 400px 50px 50px / 50px 50px 50px 50px; }
html {
background: #3a84c3;
}
@ -70,11 +85,16 @@
</head>
<body>
<div class="box1">&nbsp;</div>
<div class="box2">&nbsp;</div>
<div class="box3">&nbsp;</div>
<div class="box4">&nbsp;</div>
<div class="box5">&nbsp;</div>
<div class="box6">&nbsp;</div>
<div class="box box1">&nbsp;</div>
<div class="box box2">&nbsp;</div>
<div class="box box3">&nbsp;</div>
<div class="box box4">&nbsp;</div>
<div class="box box5">&nbsp;</div>
<div class="box box6">&nbsp;</div>
<div class="gauge gauge1"></div>
<div class="gauge gauge2"></div>
<div class="gauge gauge3"></div>
<div class="gauge gauge4"></div>
<div class="gauge gauge5"></div>
</body>
</html>

View File

@ -12,6 +12,7 @@
margin: 10px;
background:#6F428C;
border-style: solid;
border-width: 0;
}
.box1 {
@ -33,6 +34,12 @@
border-color: green;
}
.box5 {
border-style: none;
border-bottom: 50px solid #807d32;
border-bottom-width: 50px;
}
html {
background: #3a84c3;
}
@ -43,5 +50,6 @@
<div class="box2">&nbsp;</div>
<div class="box3">&nbsp;</div>
<div class="box4">&nbsp;</div>
<div class="box5">&nbsp;</div>
</body>
</html>

View File

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<title>Dynamic style</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="../test.js"></script>
<style id="style">
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v18/CWB0XYA8bzo0kSThX0UTuA.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215;
}
body { font-family: "Roboto", serif }
div {
padding: 20px;
}
.div1 {
background: darkred;
color: white;
}
@media (min-width: 10px) {
.div1 {
background: darkgreen;
}
}
</style>
<script>
document.querySelector('#style').sheet.insertRule(
'.div2 { background: darkgreen; color:white; }',
document.querySelector('#style').sheet.cssRules.length
);
</script>
</head>
<body>
<div class="div1">Static styles</div>
<div class="div2">Dynamic styles</div>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script type="text/javascript" src="../../test.js"></script>
</head>
<body>
<img src="../../assets/image.jpg" />
<img src="../../assets/image2.jpg" style="display:block;" />
<br>
</body>
</html>

View File

@ -4,7 +4,9 @@
<title>element render test</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script>
h2cOptions = {ignoreElements: function(element) {
return element.className === 'ignored';
}};
</script>
<script type="text/javascript" src="../../test.js"></script>
<style>
@ -15,7 +17,7 @@
background: green;
}
#ignored {
#ignored, .ignored {
background: red;
width: 100px;
height: 100px;
@ -32,10 +34,11 @@
<div id="ignored" data-html2canvas-ignore>
great failure
</div>
<div class="ignored">
ignore predicate
</div>
<div id="div1">
great success
</div>
</body>
</html>

View File

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<title>element render test</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script>
h2cOptions = {onclone: function(document) {
const remove = document.querySelector('.ignored');
remove.parentNode.removeChild(remove);
}};
</script>
<script type="text/javascript" src="../../test.js"></script>
<style>
#div1 {
width: 100px;
height: 100px;
background: green;
}
#ignored, .ignored {
background: red;
width: 100px;
height: 100px;
}
body, html {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div class="ignored">
ignore during onclone
</div>
<div id="div1">
great success
</div>
</body>
</html>

View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html>
<head>
<title>word-break</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="../../test.js"></script>
<style>
body {
font-family: Arial;
}
.test span {
line-break: normal;
}
.strict span {
line-break: strict;
}
p.test{
border: 1px solid gray;
color: blue;
width: 6em;
}
</style>
</head>
<body>
<!-- iteration marks -->
<p class="test" lang="ja">
<span>サンプルぁルぁルぁルぁルぁルぁルぁぁぁぁ文ンプル–文々サンプル文</span>
</p>
<p class="test strict" lang="ja">
<span>サンプルぁルぁルぁルぁルぁルぁルぁぁぁぁ文文文文文‐–〜゠サンプル文々サンプル文</span>
</p>
<hr />
</body>
</html>

View File

@ -0,0 +1,58 @@
<!DOCTYPE html>
<html>
<head>
<title>word-break</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="../../test.js"></script>
<style>
body {
font-family: Arial;
}
.normal {
width: 13em;
background: gold;
overflow-wrap: normal;
}
.break-word {
width: 13em;
background: lime;
overflow-wrap: break-word;
}
.word-normal {
width: 13em;
background: gold;
word-wrap: normal;
}
.word-break-word {
width: 13em;
background: lime;
word-wrap: break-word;
}
</style>
</head>
<body>
<div>
<p>1. <code>overflow-wrap: normal</code></p>
<p class="normal">FStrPrivFinÄndG (Gesetz zur Änderung des
Fernstraßenbauprivatfinanzierungsgesetzes
und straßenverkehrsrechtlicher Vorschriften)</p>
<p>2. <code>overflow-wrap: break-word</code></p>
<p class="break-word">FStrPrivFinÄndG (Gesetz zur Änderung des
Fernstraßenbauprivatfinanzierungsgesetzes
und straßenverkehrsrechtlicher Vorschriften)</p>
<p>3. <code>word-wrap: normal</code></p>
<p class="word-normal">FStrPrivFinÄndG (Gesetz zur Änderung des
Fernstraßenbauprivatfinanzierungsgesetzes
und straßenverkehrsrechtlicher Vorschriften)</p>
<p>4. <code>word-wrap: break-word</code></p>
<p class="word-break-word">FStrPrivFinÄndG (Gesetz zur Änderung des
Fernstraßenbauprivatfinanzierungsgesetzes
und straßenverkehrsrechtlicher Vorschriften)</p>
</div>
</body>
</html>

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<title>Thai text</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="../../test.js"></script>
<style>
.text-block {
width: 500px;
font-family: serif;
float:left;
text-align:justify;
}
</style>
</head>
<body>
<div id="text" class="text-block">
<p>.....</p>
<p>ทดสอบ แบบกำหนดรูปแบบ ทำ ที นี่ นู่น นั่น นี้ มี หรือ ไม่ </p>
<p>ภาษาไทย เป็นภาษาราชการของประเทศไทย และภาษาแม่ของชาวไทย และชนเชื้อสายอื่นในประเทศไทย ภาษาไทยเป็นภาษาในกลุ่มภาษาไท ซึ่งเป็นกลุ่มย่อยของตระกูลภาษาไท-กะได สันนิษฐานว่า ภาษาในตระกูลนี้มีถิ่นกำเนิดจากทางตอนใต้ของประเทศจีน และนักภาษาศาสตร์บางส่วนเสนอว่า ภาษาไทยน่าจะมีความเชื่อมโยงกับตระกูลภาษาออสโตร-เอเชียติก ตระกูลภาษาออสโตรนีเซียน และตระกูลภาษาจีน-ทิเบต</p>
<p>ภาษาไทยเป็นภาษาที่มีระดับเสียงของคำแน่นอนหรือวรรณยุกต์เช่นเดียวกับภาษาจีน และออกเสียงแยกคำต่อคำ ทำให้เป็นที่ลำบากของชาวต่างชาติเนื่องจากการออกเสียงวรรณยุกต์ที่เป็นเอกลักษณ์ของแต่ละคำ และการสะกดคำที่ซับซ้อน</p>
<p>คำว่า ไทย หมายความว่า อิสรภาพ เสรีภาพ หรืออีกความหมายหนึ่งคือ ใหญ่ ยิ่งใหญ่ เพราะการจะเป็นอิสระได้จะต้องมีกำลังที่มากกว่า แข็งแกร่งกว่า เพื่อป้องกันการรุกรานจากข้าศึก คำนี้เป็นคำไทยแท้ที่เกิดจากการสร้างคำที่เรียก "การลากคำเข้าวัด" ซึ่งเป็นการลากความวิธีหนึ่ง ตามหลักคติชนวิทยา คนไทยเป็นชนชาติที่นับถือกันว่า ภาษาบาลี ซึ่งเป็นภาษาที่บันทึกพระธรรมคำสอนของพระพุทธเจ้าเป็นภาษาอันศักดิ์สิทธิ์และเป็นมงคล เมื่อคนไทยต้องการตั้งชื่อประเทศว่า ไท ซึ่งเป็นคำไทยแท้ จึงเติมตัว ย เข้าไปข้างท้าย เพื่อให้มีลักษณะคล้ายคำในภาษาบาลี - สันสกฤตเพื่อความเป็นมงคลตามความเชื่อของตน ภาษาไทยจึงหมายถึงภาษาของชนชาติไทยผู้เป็นไทนั่นเอง</p>
</div>
</body>
</html>

View File

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html>
<head>
<title>word-break</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="../../test.js"></script>
<style>
body {
font-family: Arial;
}
.narrow {
padding: 5px;
border: 1px solid;
width: 8em;
}
.normal {
word-break: normal;
}
.breakAll {
word-break: break-all;
}
.keep {
word-break: keep-all;
}
</style>
</head>
<body>
<div>
<p>1. <code>word-break: normal</code></p>
<p class="normal narrow">This is a long and
Supercalifragilisticexpialidocious sentence.
次の単語グレートブリテンおよび北アイルランド連合王国で本当に大きな言葉</p>
<p>2. <code>word-break: break-all</code></p>
<p class="breakAll narrow">This is a long and
Supercalifragilisticexpialidocious sentence.
次の単語グレートブリテンおよび北アイルランド連合王国で本当に大きな言葉</p>
<p>3. <code>word-break: keep-all</code></p>
<p class="keep narrow">This is a long and
Supercalifragilisticexpialidocious sentence.
次の単語グレートブリテンおよび北アイルランド連合王国で本当に大きな言葉</p>
</div>
</body>
</html>

16
www/package-lock.json generated
View File

@ -2684,6 +2684,14 @@
"hyphenate-style-name": "1.0.2"
}
},
"css-line-break": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-1.0.1.tgz",
"integrity": "sha1-GfIGOjPpX7KDG4ZEbAuAwYivRQo=",
"requires": {
"base64-arraybuffer": "0.1.5"
}
},
"css-loader": {
"version": "0.26.4",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.26.4.tgz",
@ -4895,11 +4903,11 @@
"integrity": "sha1-nSLgyjKsyVs/RbjVtPb73AWv/VU="
},
"html2canvas": {
"version": "1.0.0-alpha.4",
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.0.0-alpha.4.tgz",
"integrity": "sha1-t1Q+6kUkAHitGEesk5CBpXUYCho=",
"version": "1.0.0-alpha.9",
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.0.0-alpha.9.tgz",
"integrity": "sha1-/2A9gINa/rbCdm6GEEdooc7xyAE=",
"requires": {
"punycode": "2.1.0"
"css-line-break": "1.0.1"
}
},
"htmlparser2": {

View File

@ -18,7 +18,7 @@
"gatsby-source-filesystem": "^1.5.9",
"gatsby-transformer-remark": "^1.7.23",
"gzip-size": "^4.1.0",
"html2canvas": "1.0.0-alpha.4",
"html2canvas": "^1.0.0-alpha.9",
"mkdirp": "^0.5.1",
"typography": "^0.16.6",
"typography-theme-github": "^0.15.10"
@ -28,7 +28,7 @@
"scripts": {
"copybuild": "mkdirp public/dist && cpy ../dist/*.js public/dist",
"build": "npm run copybuild && gatsby build",
"develop": "gatsby develop",
"start": "gatsby develop",
"test": "echo \"Error: no test specified\" && exit 1"
}
}

View File

@ -4,14 +4,25 @@ export default () =>
<footer
css={{
backgroundColor: '#558b2f',
color: 'rgba(255,255,255,0.8)',
color: 'rgba(255,255,255, 0.8)',
fontWeight: 300,
minHeight: '50px',
lineHeight: '50px',
padding: '10px 0px'
}}
>
<div css={{margin: '0 auto', width: '85%'}}>
<div
css={{
margin: '0 auto',
fontSize: '10.5px',
textAlign: 'center',
'@media(min-width: 1000px)': {
textAlign: 'left',
width: '85%',
fontSize: '14.5px'
}
}}
>
Created by{' '}
<a href="https://hertzen.com" css={{color: '#fff', fontWeight: 'bold'}}>
Niklas von Hertzen

View File

@ -1,6 +1,7 @@
import React from 'react';
import React, {Component} from 'react';
import Link from 'gatsby-link';
import logo from '../images/logo.svg';
import menu from '../images/ic_menu_black_24px.svg';
const lineLinkStyle = {
lineHeight: '44px',
@ -16,15 +17,17 @@ const lineLinkStyle = {
};
const navStyle = {
height: '100%',
width: '300px',
position: 'fixed',
top: 0,
left: 0,
'@media(min-width: 1000px)': {
position: 'fixed',
top: 0,
left: 0,
width: '300px',
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)',
height: '100%'
},
fontSize: '13px',
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)'
backgroundColor: '#fff'
};
const links = [
@ -36,31 +39,70 @@ const links = [
{href: '/faq', text: 'FAQ'}
];
export default () =>
<div css={navStyle}>
<Link to="/" css={{background: '#558b2f', display: 'block', padding: '24px 30px 24px'}}>
<img src={logo} css={{margin: 0}} />
</Link>
<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}
activeStyle={{
backgroundColor: '#7cb342',
color: '#fff'
export default class Navigation extends Component {
constructor(props) {
super(props);
this.state = {open: false};
}
render() {
return (
<div css={navStyle}>
<div
css={{
background: '#558b2f',
alignItems: 'center',
padding: '24px 30px 24px 0px',
display: 'flex',
'@media(min-width: 1000px)': {
padding: '24px 30px 24px 30px'
}
}}
>
<img
src={menu}
onClick={() => this.setState(s => ({open: !s.open}))}
css={{
width: '50px',
cursor: 'pointer',
margin: '0 20px 0',
display: 'block',
'@media(min-width: 1000px)': {
display: 'none'
}
}}
>
{text}
/>
<Link to="/">
<img src={logo} css={{margin: 0}} />
</Link>
</li>
)}
</ul>
</div>;
</div>
<ul
css={{
display: this.state.open ? 'block' : 'none',
listStyle: 'none',
margin: 0,
padding: 0,
'@media(min-width: 1000px)': {
display: 'block'
}
}}
>
{links.map(({href, text}, i) =>
<li style={{padding: 0, margin: 0}} key={i}>
<Link
to={href}
css={lineLinkStyle}
activeStyle={{
backgroundColor: '#7cb342',
color: '#fff'
}}
>
{text}
</Link>
</li>
)}
</ul>
</div>
);
}
}

View File

@ -0,0 +1,4 @@
<svg fill="#ffffff" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/>
</svg>

After

Width:  |  Height:  |  Size: 210 B

View File

@ -36,9 +36,22 @@ table {
border: 1px solid #ddd;
}
table tr:nth-child(odd) {
background-color: #f9f9f9;
}
th {
padding: 8px;
border: 1px solid #ddd;
border-bottom-width: 2px;
}
td {
padding: 8px;
}
th:first-child, td:first-child {
padding-left: 8px;
}
:not(pre) > code {

View File

@ -55,8 +55,24 @@ export default ({data}) => {
Screenshots with JavaScript
</h4>
<div css={{display: 'flex', justifyContent: 'center'}}>
<div>
<div
css={{
display: 'flex',
justifyContent: 'center',
flexDirection: 'column',
'@media(min-width: 1000px)': {
flexDirection: 'row'
}
}}
>
<div
css={{
display: 'none',
'@media(min-width: 1000px)': {
display: 'block'
}
}}
>
<h4>HTML</h4>
<div
css={{marginRight: '5px'}}
@ -70,7 +86,14 @@ export default ({data}) => {
}}
/>
</div>
<div>
<div
css={{
display: 'none',
'@media(min-width: 1000px)': {
display: 'block'
}
}}
>
<h4>JavaScript</h4>
<div
css={{marginLeft: '5px'}}
@ -101,14 +124,25 @@ export default ({data}) => {
Documentation
</Link>
</div>
<div css={{display: 'flex'}}>
<div
css={{
display: 'flex',
flexDirection: 'column',
'@media(min-width: 1000px)': {
flexDirection: 'row'
}
}}
>
<div
css={{
flex: 1,
backgroundColor: '#558b2f',
padding: '10px 20px',
borderRadius: '10px',
marginRight: '5px'
marginBottom: '10px',
'@media(min-width: 1000px)': {
marginRight: '5px'
}
}}
>
<Carbon />
@ -116,12 +150,16 @@ export default ({data}) => {
<div
css={{
flex: 1,
marginLeft: '5px',
backgroundColor: '#558b2f',
padding: '10px 20px',
borderRadius: '10px',
textAlign: 'left',
marginRight: '5px'
marginBottom: '10px',
'@media(min-width: 1000px)': {
marginLeft: '5px',
marginRight: '5px'
}
}}
>
<h6>Install NPM</h6>
@ -143,11 +181,14 @@ export default ({data}) => {
<div
css={{
flex: 1,
marginLeft: '5px',
backgroundColor: '#558b2f',
padding: '10px 20px',
borderRadius: '10px',
textAlign: 'left'
textAlign: 'left',
marginBottom: '10px',
'@media(min-width: 1000px)': {
marginLeft: '5px'
}
}}
>
<h5>Connect</h5>

View File

@ -19,7 +19,9 @@ export default ({data}) => {
<Navigation />
<div
css={{
marginLeft: '300px',
'@media(min-width: 1000px)': {
marginLeft: '300px'
},
display: 'flex',
minHeight: '100vh',
flexDirection: 'column'
@ -37,10 +39,23 @@ export default ({data}) => {
<div css={{maxWidth: '960px'}}>
<div css={{width: '85%', margin: '0 auto', display: 'flex'}}>
<div css={{flex: 1}}>
<h1 css={{padding: '20px 0'}}>
<h1
css={{
padding: '20px 0',
fontSize: '2.8rem',
'@media(min-width: 1000px)': {fontSize: '4.2rem'}
}}
>
{post.frontmatter.title}
</h1>
<h4 css={{fontWeight: 300, color: 'rgba(255, 255, 255, 0.6)'}}>
<h4
css={{
fontWeight: 300,
color: 'rgba(255, 255, 255, 0.6)',
fontSize: '1.8rem',
'@media(min-width: 1000px)': {fontSize: '2.28rem'}
}}
>
{post.frontmatter.description}
</h4>
</div>