1
0
mirror of https://github.com/chinchang/web-maker.git synced 2025-07-31 18:50:14 +02:00

Merge pull request #314 from chinchang/js13k

Js13k mode!!
This commit is contained in:
Kushagra Gour
2018-07-31 02:01:53 +05:30
committed by GitHub
31 changed files with 928 additions and 21849 deletions

View File

@@ -2,16 +2,12 @@ language: node_js
node_js:
- '10'
install:
- npm i -g npm@latest
- npm install -g eslint
- npm install -g babel-eslint
- npm install -g eslint-plugin-react
- npm install -g eslint-plugin-mocha
- npm install -g eslint-config-synacor
- yarn add global eslint
- yarn add global babel-eslint
- yarn add global eslint-plugin-react
- yarn add global eslint-plugin-mocha
- yarn add global eslint-config-synacor
script:
- npm run lint
- npm ci
- npm run test
cache:
directories:
- '$HOME/.npm'
- yarn run lint
- yarn run test
cache: yarn

View File

@@ -36,13 +36,14 @@ gulp.task('copyFiles', function() {
gulp.src('src/lib/transpilers/*').pipe(gulp.dest('app/lib/transpilers')),
gulp.src('src/lib/screenlog.js').pipe(gulp.dest('app/lib')),
gulp.src('icons/*').pipe(gulp.dest('app/icons')),
gulp.src('src/assets/*').pipe(gulp.dest('app/assets')),
gulp.src('src/templates/*').pipe(gulp.dest('app/templates')),
gulp
.src([
'src/preview.html',
'src/detached-window.js',
'src/icon-48.png',
'src/icon-128.png',
'src/patreon.png',
'manifest.json'
])
.pipe(gulp.dest('app')),

21667
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -61,6 +61,7 @@
"copy-webpack-plugin": "^4.5.1",
"esprima": "^4.0.0",
"firebase": "^5.0.4",
"jszip": "^3.1.5",
"preact": "^8.2.6",
"preact-compat": "^3.17.0",
"preact-portal": "^1.1.3",

23
src/assets/html5-logo.svg Executable file
View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="2000px"
height="2000px" viewBox="0 0 2000 2000" enable-background="new 0 0 2000 2000" xml:space="preserve">
<g id="Logo_artwork">
</g>
<g id="Guides_to_delete">
<g>
<polygon fill="#E34E26" points="352.732,1718.4 208.627,101.984 1791.373,101.984 1647.093,1718.528 999.615,1898.016 "/>
<polygon fill="#EF662A" points="1000,234.108 1000,1760.716 1523.565,1615.585 1646.918,234.108 "/>
<polygon fill="#FFFFFF" points="503.468,432.378 556.906,1031.897 1244.048,1031.897 1220.988,1289.041 999.744,1348.857
778.919,1289.128 764.155,1124.017 565.155,1124.017 593.611,1442.302 999.697,1555.086 1406.296,1442.302 1460.806,833.669
738.229,833.669 720.086,630.648 1478.168,630.648 1478.773,630.648 1496.532,432.378 "/>
<g>
<polygon fill="#EBEBEB" points="1000,432.378 503.468,432.378 556.906,1031.897 1000,1031.897 1000,833.669 738.229,833.669
720.086,630.648 1000,630.648 "/>
<polygon fill="#EBEBEB" points="1000,1348.771 999.744,1348.857 778.919,1289.128 764.155,1124.017 565.155,1124.017
593.611,1442.302 999.697,1555.086 1000,1555.001 "/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
src/assets/js13kgames.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

9
src/assets/preact-logo.svg Executable file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="256px" height="296px" viewBox="0 0 256 296" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
<g>
<polygon fill="#673AB8" points="128 0 256 73.8999491 256 221.699847 128 295.599796 0 221.699847 0 73.8999491"></polygon>
<path d="M34.8647584,220.478469 C51.8814262,242.25881 105.959701,225.662965 157.014868,185.774297 C208.070035,145.885628 237.255632,97.428608 220.238964,75.6482664 C203.222296,53.8679249 149.144022,70.4637701 98.0888543,110.352439 C47.0336869,150.241107 17.8480906,198.698127 34.8647584,220.478469 Z M42.1343351,214.798853 C36.4908625,207.575537 38.9565723,193.395881 49.7081913,175.544904 C61.0297348,156.747677 80.2490923,135.997367 103.76847,117.622015 C127.287848,99.2466634 152.071368,85.6181573 173.049166,79.1803727 C192.970945,73.066665 207.325915,74.1045667 212.969387,81.3278822 C218.61286,88.5511977 216.14715,102.730854 205.395531,120.581832 C194.073987,139.379058 174.85463,160.129368 151.335252,178.50472 C127.815874,196.880072 103.032354,210.508578 82.054556,216.946362 C62.1327769,223.06007 47.7778077,222.022168 42.1343351,214.798853 Z" fill="#FFFFFF"></path>
<path d="M220.238964,220.478469 C237.255632,198.698127 208.070035,150.241107 157.014868,110.352439 C105.959701,70.4637701 51.8814262,53.8679249 34.8647584,75.6482664 C17.8480906,97.428608 47.0336869,145.885628 98.0888543,185.774297 C149.144022,225.662965 203.222296,242.25881 220.238964,220.478469 Z M212.969387,214.798853 C207.325915,222.022168 192.970945,223.06007 173.049166,216.946362 C152.071368,210.508578 127.287848,196.880072 103.76847,178.50472 C80.2490923,160.129368 61.0297348,139.379058 49.7081913,120.581832 C38.9565723,102.730854 36.4908625,88.5511977 42.1343351,81.3278822 C47.7778077,74.1045667 62.1327769,73.066665 82.054556,79.1803727 C103.032354,85.6181573 127.815874,99.2466634 151.335252,117.622015 C174.85463,135.997367 194.073987,156.747677 205.395531,175.544904 C216.14715,193.395881 218.61286,207.575537 212.969387,214.798853 Z" fill="#FFFFFF"></path>
<path d="M127.551861,167.666971 C138.378632,167.666971 147.155465,158.890139 147.155465,148.063368 C147.155465,137.236596 138.378632,128.459764 127.551861,128.459764 C116.72509,128.459764 107.948257,137.236596 107.948257,148.063368 C107.948257,158.890139 116.72509,167.666971 127.551861,167.666971 L127.551861,167.666971 Z" fill="#FFFFFF"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@@ -62,7 +62,7 @@ export default class AddLibrary extends Component {
<h1>Add Library</h1>
<div class="flex">
<svg style="width: 30px; height: 30px;fill:#999">
<svg style="width: 30px; height: 30px;fill:rgb(255,255,255,0.2)">
<use xlinkHref="#search" />
</svg>
<LibraryAutoSuggest
@@ -123,7 +123,6 @@ export default class AddLibrary extends Component {
id="externalJsTextarea"
cols="30"
rows="5"
placeholder="Put each library in new line"
value={this.state.js}
/>
@@ -136,7 +135,6 @@ export default class AddLibrary extends Component {
id="externalCssTextarea"
cols="30"
rows="5"
placeholder="Put each library in new line"
value={this.state.css}
/>
</div>

View File

@@ -934,6 +934,7 @@ export default class ContentWrap extends Component {
<use xlinkHref="#chevron-icon" />
</svg>
<input
tabIndex={this.state.isConsoleOpen ? 0 : -1}
onKeyUp={this.evalConsoleExpr.bind(this)}
class="console-exec-input"
/>

View File

@@ -0,0 +1,32 @@
import { h } from 'preact';
import Modal from './Modal';
import { ItemTile } from './ItemTile';
import templates from '../templateList';
export function CreateNewModal({
show,
closeHandler,
onBlankTemplateSelect,
onTemplateSelect
}) {
return (
<Modal show={show} closeHandler={closeHandler} smll>
<div class="tac">
<button className="btn" onClick={onBlankTemplateSelect}>
Start a blank creation
</button>
</div>
<hr />
Or choose from a template:
<div class="saved-items-pane__container">
{templates.map(template => (
<ItemTile
item={template}
focusable
onClick={onTemplateSelect.bind(null, template)}
/>
))}
</div>
</Modal>
);
}

View File

@@ -1,21 +1,185 @@
import { h, Component } from 'preact';
import { Button } from './common';
class JS13K extends Component {
constructor(props) {
super(props);
const compoDate = new Date('August 13 2018 11:00 GMT');
var now = new Date();
var daysLeft;
if (+compoDate > +now) {
daysLeft = Math.floor((compoDate - now) / 1000 / 3600 / 24);
}
this.setState({
daysLeft
});
}
render() {
const codeSizeInKb = this.props.codeSize
? (this.props.codeSize / 1024).toFixed(2)
: 0;
return (
<div
role="button"
class="flex flex-v-center"
tabIndex="0"
onClick={this.props.onClick}
onBlur={this.props.onBlur}
>
<img src="assets/js13kgames.png" alt="JS13K Games logo" height="24" />{' '}
<div class="footer__js13k-days-left">
{this.state.daysLeft} days to go
</div>
<div
class="footer__js13k-code-size"
style={{
color: codeSizeInKb > 10 ? 'crimson' : 'limegreen'
}}
>
{codeSizeInKb} KB/ 13KB
</div>
<span
class="caret"
style={`transition:0.3s ease; transform-origin: center 2px; ${
this.props.isOpen ? 'transform:rotate(180deg);' : ''
}`}
/>
</div>
);
}
}
export default class Footer extends Component {
constructor(props) {
super(props);
this.state = {
isKeyboardShortcutsModalOpen: false
isKeyboardShortcutsModalOpen: false,
isJs13kDropdownOpen: false
};
}
layoutBtnClickhandler(layoutId) {
this.props.layoutBtnClickHandler(layoutId);
}
js13kClickHandler() {
// console.log(999);
this.setState({
isJs13kDropdownOpen: !this.state.isJs13kDropdownOpen
});
}
render() {
return (
<div id="footer" class="footer">
<div class="footer__right fr">
<div>
<a
href="https://webmakerapp.com/"
target="_blank"
rel="noopener noreferrer"
>
<div class="logo" />
</a>
&copy;
<span class="web-maker-with-tag">Web Maker</span> &nbsp;&nbsp;
<Button
onClick={this.props.helpBtnClickHandler}
data-event-category="ui"
data-event-action="helpButtonClick"
class="footer__link hint--rounded hint--top-right"
aria-label="Help"
>
<svg
style="width:20px; height:20px; vertical-align:text-bottom"
viewBox="0 0 24 24"
>
<path d="M15.07,11.25L14.17,12.17C13.45,12.89 13,13.5 13,15H11V14.5C11,13.39 11.45,12.39 12.17,11.67L13.41,10.41C13.78,10.05 14,9.55 14,9C14,7.89 13.1,7 12,7A2,2 0 0,0 10,9H8A4,4 0 0,1 12,5A4,4 0 0,1 16,9C16,9.88 15.64,10.67 15.07,11.25M13,19H11V17H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z" />
</svg>
</Button>
<Button
onClick={this.props.keyboardShortcutsBtnClickHandler}
data-event-category="ui"
data-event-action="keyboardShortcutButtonClick"
class="footer__link hint--rounded hint--top-right hide-on-mobile"
aria-label="Keyboard shortcuts"
>
<svg
style={{
width: '20px',
height: '20px',
verticalAlign: 'text-bottom'
}}
>
<use xlinkHref="#keyboard-icon" />
</svg>
</Button>
<a
class="footer__link hint--rounded hint--top-right"
aria-label="Tweet about 'Web Maker'"
href="http://twitter.com/share?url=https://webmakerapp.com/&text=Web Maker - A blazing fast %26 offline web playground! via @webmakerApp&related=webmakerApp&hashtags=web,frontend,playground,offline"
target="_blank"
rel="noopener noreferrer"
>
<svg
style={{
width: '20px',
height: '20px',
verticalAlign: 'text-bottom'
}}
>
<use xlinkHref="#twitter-icon" />
</svg>
</a>
<Button
onClick={this.props.supportDeveloperBtnClickHandler}
data-event-category="ui"
data-event-action="supportDeveloperFooterBtnClick"
class="footer__link ml-1 hint--rounded hint--top-right hide-on-mobile support-link"
aria-label="Support the developer by pledging some amount"
>
Donate
</Button>
</div>
{this.props.prefs.isJs13kModeOn ? (
<div class="flex flex-v-center">
<JS13K
isOpen={this.state.isJs13kDropdownOpen}
codeSize={this.props.codeSize}
onClick={this.js13kClickHandler.bind(this)}
onBlur={() =>
setTimeout(
() => this.setState({ isJs13kDropdownOpen: false }),
300
)
}
/>
{this.state.isJs13kDropdownOpen && (
<div className="js13k__dropdown">
<button
class="btn"
style={{
width: '200px',
display: 'block',
marginBottom: '16px'
}}
onClick={this.props.onJs13KDownloadBtnClick}
>
Download game as zip
</button>
<button
class="btn"
style={{ width: '200px', display: 'block' }}
onClick={this.props.onJs13KHelpBtnClick}
>
Help
</button>
</div>
)}
</div>
) : null}
<div class="footer__right">
<button
onClick={this.props.saveHtmlBtnClickHandler}
id="saveHtmlBtn"
@@ -150,72 +314,6 @@ export default class Footer extends Component {
</svg>
</Button>
</div>
<a
href="https://webmakerapp.com/"
target="_blank"
rel="noopener noreferrer"
>
<div class="logo" />
</a>
&copy;
<span class="web-maker-with-tag">Web Maker</span> &nbsp;&nbsp;
<Button
onClick={this.props.helpBtnClickHandler}
data-event-category="ui"
data-event-action="helpButtonClick"
class="footer__link hint--rounded hint--top-right"
aria-label="Help"
>
<svg
style="width:20px; height:20px; vertical-align:text-bottom"
viewBox="0 0 24 24"
>
<path d="M15.07,11.25L14.17,12.17C13.45,12.89 13,13.5 13,15H11V14.5C11,13.39 11.45,12.39 12.17,11.67L13.41,10.41C13.78,10.05 14,9.55 14,9C14,7.89 13.1,7 12,7A2,2 0 0,0 10,9H8A4,4 0 0,1 12,5A4,4 0 0,1 16,9C16,9.88 15.64,10.67 15.07,11.25M13,19H11V17H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z" />
</svg>
</Button>
<Button
onClick={this.props.keyboardShortcutsBtnClickHandler}
data-event-category="ui"
data-event-action="keyboardShortcutButtonClick"
class="footer__link hint--rounded hint--top-right hide-on-mobile"
aria-label="Keyboard shortcuts"
>
<svg
style={{
width: '20px',
height: '20px',
verticalAlign: 'text-bottom'
}}
>
<use xlinkHref="#keyboard-icon" />
</svg>
</Button>
<a
class="footer__link hint--rounded hint--top-right"
aria-label="Tweet about 'Web Maker'"
href="http://twitter.com/share?url=https://webmakerapp.com/&text=Web Maker - A blazing fast %26 offline web playground! via @webmakerApp&related=webmakerApp&hashtags=web,frontend,playground,offline"
target="_blank"
rel="noopener noreferrer"
>
<svg
style={{
width: '20px',
height: '20px',
verticalAlign: 'text-bottom'
}}
>
<use xlinkHref="#twitter-icon" />
</svg>
</a>
<Button
onClick={this.props.supportDeveloperBtnClickHandler}
data-event-category="ui"
data-event-action="supportDeveloperFooterBtnClick"
class="footer__link ml-1 hint--rounded hint--top-right hide-on-mobile support-link"
aria-label="Support the developer by pledging some amount"
>
Support the developer
</Button>
</div>
);
}

View File

@@ -0,0 +1,60 @@
import { h } from 'preact';
import { getHumanDate } from '../utils';
import Modal from './Modal';
export function ItemTile({
item,
onClick,
onForkBtnClick,
onRemoveBtnClick,
focusable
}) {
return (
<div
role={focusable ? 'button' : null}
tabindex={focusable ? 0 : null}
class="js-saved-item-tile saved-item-tile"
data-item-id={item.id}
onClick={onClick}
>
<div class="saved-item-tile__btns">
{onForkBtnClick ? (
<a
class="js-saved-item-tile__fork-btn saved-item-tile__btn hint--left hint--medium"
aria-label="Creates a duplicate of this creation (Ctrl/⌘ + F)"
onClick={onForkBtnClick}
>
Fork<span class="show-when-selected">(Ctrl/ + F)</span>
</a>
) : null}
{onRemoveBtnClick ? (
<a
class="js-saved-item-tile__remove-btn saved-item-tile__btn hint--left"
aria-label="Remove"
onClick={onRemoveBtnClick}
>
X
</a>
) : null}
</div>
<div className="flex flex-v-center">
{item.img ? (
<div>
<img
class="saved-item-tile__img"
height="40"
src={item.img}
alt=""
/>
</div>
) : null}
<h3 class="saved-item-tile__title">{item.title}</h3>
</div>
{item.updatedOn ? (
<div class="saved-item-tile__meta">
Last updated: {getHumanDate(item.updatedOn)}
</div>
) : null}
</div>
);
}

View File

@@ -0,0 +1,82 @@
import { h } from 'preact';
import Modal from './Modal';
export function Js13KModal({ show, closeHandler }) {
return (
<Modal show={show} closeHandler={closeHandler} small>
<div class="tac">
<div className="flex flex-v-center flex-h-center ">
<img
src="/icon-128.png"
alt="Web Maker logo"
height="100"
style="margin:0 0.5rem;"
/>
<h2>Web Maker</h2>
<span style="font-size:3rem;margin:0 1rem;">+</span>
<h2>JS13K Games</h2>
<img
src="assets/js13kgames-square-logo.png"
alt="JS13K Games logo"
height="100"
style="margin:0 0.5rem;"
/>
</div>
</div>
<div>
<p>
<strong>Js13kGames</strong> is a JavaScript coding competition for{' '}
<strong>HTML5 Game Developers</strong>. The fun part of the compo is
the file size limit set to <strong>13 kilobytes</strong>. The
competition will start at <strong>13:00 CEST, 13th August</strong> and
will end at <strong>13:00 CEST, 13th September 2018</strong>.
</p>
<p>
You have activated Web Maker's Js13kGames mode! This gives you some
extra support to build your awesome game right here. Constantly see
your game's zipped size in the footer. When you are done, download the
zip.{' '}
<a
href="https://medium.com/web-maker/js13kgames-jam-with-web-maker-a3389cf2cbb"
target="_blank"
rel="noopener"
>
Read more about this collaboration
</a>.
</p>
<ul>
<li>
<a
href="https://gamedevelopment.tutsplus.com/articles/how-to-minify-your-html5-game-for-the-js13kgames-competition--cms-21883"
target="_blank"
rel="noopener noreferrer"
>
Read Tuts+ Gamedev intro article
</a>
</li>
<li>
<a
href="http://js13kgames.github.io/resources/"
target="_blank"
rel="noopener"
>
Resources and useful tools
</a>
</li>
<li>
<a
href="http://2018.js13kgames.com/#rules"
target="_blank"
rel="noopener"
>
Compo rules
</a>
</li>
</ul>
<p>Have fun building games!</p>
</div>
</Modal>
);
}

View File

@@ -56,7 +56,9 @@ export default class Modal extends Component {
return (
<Portal into="body">
<div
class={`${this.props.extraClasses || ''} modal is-modal-visible`}
class={`${this.props.extraClasses || ''} modal is-modal-visible ${
this.props.small ? 'modal--small' : ''
}`}
ref={el => (this.overlayEl = el)}
onClick={this.onOverlayClick.bind(this)}
>

View File

@@ -7,6 +7,8 @@ function NotificationItem({ type, children }) {
strongTag = <strong>🔧 Bugfix</strong>;
} else if (type === 'a11y') {
strongTag = <strong> Accessibility</strong>;
} else if (type === 'ui') {
strongTag = <strong>🖥 Interface</strong>;
}
return (
<li>
@@ -101,7 +103,35 @@ export function Notifications(props) {
<div>
<h1>Whats new?</h1>
<Notification version="3.3.2" isLatest={true} {...props}>
<Notification version="3.4.0" isLatest={true} {...props}>
<li>
<strong>🎉 Js13kGames Mode</strong>: For all you Js13kGames compo
participants out there. Turn it on from Settings.{' '}
<a
href="https://medium.com/web-maker/js13kgames-jam-with-web-maker-a3389cf2cbb"
target="_blank"
rel="noopener"
>
Read more about it here.
</a>
</li>
<li>
<strong>🎉 Templates</strong>: Presenting, templates for major
libraries and frameworks. Hit the "New" button to explore.
</li>
<NotificationItem type="a11y">
Add missing focus rings around focusable element.
</NotificationItem>
<NotificationItem type="ui">
Migrate remaining interface elements to dark theme. Now complete app
is in dark theme.
</NotificationItem>
<NotificationItem type="bug">
Fix "Save as HTML" and "Take Screenshot" features in Chrome extension.
</NotificationItem>
</Notification>
<Notification version="3.3.2" {...props}>
<NotificationItem type="a11y">
Improper links are now buttons with proper focus indication and
screen-reader support. Thanks{' '}

View File

@@ -1,9 +1,10 @@
import { h, Component } from 'preact';
import { log, getHumanDate } from '../utils';
import { log } from '../utils';
import { trackEvent } from '../analytics';
import { itemService } from '../itemService';
import { alertsService } from '../notifications';
import { deferred } from '../deferred';
import { ItemTile } from './ItemTile';
export default class SavedItemPane extends Component {
constructor(props) {
@@ -230,32 +231,12 @@ export default class SavedItemPane extends Component {
<div class="mt-1">No match found.</div>
) : null}
{this.state.filteredItems.map(item => (
<div
class="js-saved-item-tile saved-item-tile"
data-item-id={item.id}
<ItemTile
item={item}
onClick={this.itemClickHandler.bind(this, item)}
>
<div class="saved-item-tile__btns">
<a
class="js-saved-item-tile__fork-btn saved-item-tile__btn hint--left hint--medium"
aria-label="Creates a duplicate of this creation (Ctrl/⌘ + F)"
onClick={this.itemForkBtnClickHandler.bind(this, item)}
>
Fork<span class="show-when-selected">(Ctrl/ + F)</span>
</a>
<a
class="js-saved-item-tile__remove-btn saved-item-tile__btn hint--left"
aria-label="Remove"
onClick={this.itemRemoveBtnClickHandler.bind(this, item)}
>
X
</a>
</div>
<h3 class="saved-item-tile__title">{item.title}</h3>
<span class="saved-item-tile__meta">
Last updated: {getHumanDate(item.updatedOn)}
</span>
</div>
onForkBtnClick={this.itemForkBtnClickHandler.bind(this, item)}
onRemoveBtnClick={this.itemRemoveBtnClickHandler.bind(this, item)}
/>
))}
{!this.items.length ? (
<h2 class="opacity--30">Nothing saved here.</h2>

View File

@@ -286,6 +286,14 @@ export default class Settings extends Component {
pref={this.props.prefs.isCodeBlastOn}
onChange={this.updateSetting.bind(this)}
/>
<CheckboxSetting
title="Get ready to build some games at JS13KGames"
label="Js13kGames Mode"
name="isJs13kModeOn"
pref={this.props.prefs.isJs13kModeOn}
onChange={this.updateSetting.bind(this)}
/>
</p>
<hr />
@@ -296,7 +304,7 @@ export default class Settings extends Component {
class="line"
title="This timeout is used to indentify a possible infinite loop and prevent it."
>
Maximum time allowed in a loop iteration
Maximum time allowed in a loop iteration{' '}
<input
type="number"
value={this.props.prefs.infiniteLoopTimeout}

View File

@@ -41,7 +41,11 @@ export function SupportDeveloperModal({ show, closeHandler }) {
rel="noopener noreferrer"
aria-label="Make a monthly pledge on Patreon"
>
<img src="patreon.png" height="60" alt="Become a patron image" />
<img
src="assets/patreon.png"
height="60"
alt="Become a patron image"
/>
<h3 class="onboard-selection-text">
Make a monthly pledge on Patreon
</h3>

View File

@@ -10,13 +10,16 @@ import SavedItemPane from './SavedItemPane.jsx';
import AddLibrary from './AddLibrary.jsx';
import Modal from './Modal.jsx';
import Login from './Login.jsx';
import { computeHtml, computeCss, computeJs } from '../computes';
import {
log,
generateRandomId,
semverCompare,
saveAsHtml,
handleDownloadsPermission,
downloadFile
downloadFile,
getCompleteHtml,
getFilenameFromUrl
} from '../utils';
import { itemService } from '../itemService';
import '../db';
@@ -38,7 +41,10 @@ import { Alerts } from './Alerts';
import Portal from 'preact-portal';
import { HelpModal } from './HelpModal';
import { OnboardingModal } from './OnboardingModal';
import { Js13KModal } from './Js13KModal';
import { CreateNewModal } from './CreateNewModal';
import { Icons } from './Icons';
import JSZip from 'jszip';
if (module.hot) {
require('preact/debug');
@@ -55,8 +61,7 @@ export default class App extends Component {
constructor() {
super();
this.AUTO_SAVE_INTERVAL = 15000; // 15 seconds
this.state = {
isSavedItemPaneOpen: false,
this.modalDefaultStates = {
isModalOpen: false,
isAddLibraryModalOpen: false,
isSettingsModalOpen: false,
@@ -68,6 +73,12 @@ export default class App extends Component {
isKeyboardShortcutsModalOpen: false,
isAskToImportModalOpen: false,
isOnboardModalOpen: false,
isJs13KModalOpen: false,
isCreateNewModalOpen: false
};
this.state = {
isSavedItemPaneOpen: false,
...this.modalDefaultStates,
prefs: {},
currentItem: {
title: '',
@@ -96,7 +107,8 @@ export default class App extends Component {
lightVersion: false,
lineWrap: true,
infiniteLoopTimeout: 1000,
layoutMode: 2
layoutMode: 2,
isJs13kModeOn: false
};
this.prefs = {};
@@ -484,16 +496,7 @@ export default class App extends Component {
}
this.setState({
isAddLibraryModalOpen: false,
isSettingsModalOpen: false,
isHelpModalOpen: false,
isNotificationsModalOpen: false,
isLoginModalOpen: false,
isProfileModalOpen: false,
isSupportDeveloperModalOpen: false,
isKeyboardShortcutsModalOpen: false,
isAskToImportModalOpen: false,
isOnboardModalOpen: false
...this.modalDefaultStates
});
}
onExternalLibChange(newValues) {
@@ -697,6 +700,9 @@ export default class App extends Component {
});
}
}
if (this.state.prefs.isJs13kModeOn) {
this.calculateCodeSize();
}
}
onCodeSettingsChange(type, settings) {
this.state.currentItem[`${type}Settings`] = {
@@ -824,10 +830,14 @@ export default class App extends Component {
'You have unsaved changes. Do you still want to create something new?'
);
if (shouldDiscard) {
this.createNewItem();
this.setState({
isCreateNewModalOpen: true
});
}
} else {
this.createNewItem();
this.setState({
isCreateNewModalOpen: true
});
}
}
openBtnClickHandler() {
@@ -973,6 +983,160 @@ export default class App extends Component {
this.state.currentItem.mainSizes = this.getMainPaneSizes();
}
/**
* Calculate byte size of a text snippet
* @author Lea Verou
* MIT License
*/
calculateTextSize(text) {
if (!text) {
return 0;
}
var crlf = /(\r?\n|\r)/g,
whitespace = /(\r?\n|\r|\s+)/g;
const ByteSize = {
count: function(text, options) {
// Set option defaults
options = options || {};
options.lineBreaks = options.lineBreaks || 1;
options.ignoreWhitespace = options.ignoreWhitespace || false;
var length = text.length,
nonAscii = length - text.replace(/[\u0100-\uFFFF]/g, '').length,
lineBreaks = length - text.replace(crlf, '').length;
if (options.ignoreWhitespace) {
// Strip whitespace
text = text.replace(whitespace, '');
return text.length + nonAscii;
} else {
return (
length +
nonAscii +
Math.max(0, options.lineBreaks * (lineBreaks - 1))
);
}
},
format: function(count, plainText) {
var level = 0;
while (count > 1024) {
count /= 1024;
level++;
}
// Round to 2 decimals
count = Math.round(count * 100) / 100;
level = ['', 'K', 'M', 'G', 'T'][level];
return (
(plainText ? count : '<strong>' + count + '</strong>') +
' ' +
level +
'B'
);
}
};
return ByteSize.count(text);
}
getExternalLibCode() {
const item = this.state.currentItem;
var libs = (item.externalLibs && item.externalLibs.js) || '';
libs += ('\n' + item.externalLibs && item.externalLibs.css) || '';
libs = libs.split('\n').filter(lib => lib);
return libs.map(lib =>
fetch(lib)
.then(res => res.text())
.then(data => {
return {
code: data,
fileName: getFilenameFromUrl(lib)
};
})
);
}
calculateCodeSize() {
const item = this.state.currentItem;
var htmlPromise = computeHtml(item.html, item.htmlMode);
var cssPromise = computeCss(item.css, item.cssMode);
var jsPromise = computeJs(item.js, item.jsMode, false);
Promise.all([
htmlPromise,
cssPromise,
jsPromise,
...this.getExternalLibCode()
]).then(result => {
var html = result[0].code || '',
css = result[1].code || '',
js = result[2].code || '';
var fileContent = getCompleteHtml(html, css, js, item, true);
var zip = new JSZip();
zip.file('index.html', fileContent);
for (let i = 3; i < result.length; i++) {
const externalLib = result[i];
zip.file(externalLib.fileName, externalLib.code);
}
// console.log('ORIGINAL', this.calculateTextSize(fileContent));
var promise = null;
if (0 && JSZip.support.uint8array) {
promise = zip.generateAsync({ type: 'uint8array' });
} else {
promise = zip.generateAsync({
type: 'base64',
compression: 'DEFLATE',
compressionOptions: {
level: 9
}
});
}
promise.then(data => {
const zipContent = data;
const size = this.calculateTextSize(atob(data));
this.setState({
codeSize: size
});
this.currentItemZipBase64Data = data;
});
});
}
js13KHelpBtnClickHandler() {
this.setState({
isJs13KModalOpen: true
});
}
js13KDownloadBtnClickHandler() {
const a = document.createElement('a');
a.setAttribute('download', this.state.currentItem.title);
a.href = 'data:application/zip;base64,' + this.currentItemZipBase64Data;
document.body.appendChild(a);
a.click();
a.remove();
}
blankTemplateSelectHandler() {
this.createNewItem();
this.setState({ isCreateNewModalOpen: false });
}
templateSelectHandler(template) {
fetch(`templates/template-${template.id}.json`)
.then(res => res.json())
.then(json => {
this.forkItem(json);
});
this.setState({ isCreateNewModalOpen: false });
}
render() {
return (
<div>
@@ -1006,6 +1170,7 @@ export default class App extends Component {
/>
<div class="global-console-container" id="globalConsoleContainerEl" />
<Footer
prefs={this.state.prefs}
layoutBtnClickHandler={this.layoutBtnClickHandler.bind(this)}
helpBtnClickHandler={() => this.setState({ isHelpModalOpen: true })}
settingsBtnClickHandler={() =>
@@ -1028,7 +1193,12 @@ export default class App extends Component {
screenshotBtnClickHandler={this.screenshotBtnClickHandler.bind(
this
)}
onJs13KHelpBtnClick={this.js13KHelpBtnClickHandler.bind(this)}
onJs13KDownloadBtnClick={this.js13KDownloadBtnClickHandler.bind(
this
)}
hasUnseenChangelog={this.state.hasUnseenChangelog}
codeSize={this.state.codeSize}
/>
</div>
@@ -1145,6 +1315,18 @@ export default class App extends Component {
closeHandler={() => this.setState({ isOnboardModalOpen: false })}
/>
<Js13KModal
show={this.state.isJs13KModalOpen}
closeHandler={() => this.setState({ isJs13KModalOpen: false })}
/>
<CreateNewModal
show={this.state.isCreateNewModalOpen}
closeHandler={() => this.setState({ isCreateNewModalOpen: false })}
onBlankTemplateSelect={this.blankTemplateSelectHandler.bind(this)}
onTemplateSelect={this.templateSelectHandler.bind(this)}
/>
<Portal into="body">
<div
class="modal-overlay"

View File

@@ -1,8 +1,10 @@
:root {
--color-text: #d4cde9;
--color-bg: #252637;
--color-sidebar: #3a2b63;
--color-popup: #3a2b63;
--code-font-size: 16px;
--color-button: #0074d9;
--color-button: #d3a447;
--color-focus-outline: #d3a447;
}
body {
@@ -23,12 +25,34 @@ h1 {
margin-top: 0;
}
select,
input,
textarea {
font-size: inherit;
color: var(--color-text);
background: rgba(0, 0, 0, 0.24);
border: 1px solid rgba(255, 255, 255, 0.09);
border-bottom-color: rgba(255, 255, 255, 0.17);
box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.2);
border-radius: 3px;
padding: 10px;
box-sizing: border-box;
}
[role='button'] {
cursor: pointer;
}
a {
text-decoration: none;
color: #d61237;
color: #f7ae2d;
cursor: pointer;
}
a:hover {
text-decoration: underline;
}
p {
line-height: 1.65;
}
@@ -131,7 +155,7 @@ button {
}
.support-link {
color: #d61237;
color: #f7ae2d;
}
@media screen and (max-width: 600px) {
@@ -158,7 +182,8 @@ button {
hr {
background: 0;
border: 0;
border-bottom: 1px solid #dedede;
border-bottom: 1px solid rgba(255, 255, 255, 0.12);
margin: 20px 0;
}
label {
@@ -192,14 +217,6 @@ a > svg {
fill: rgba(255, 255, 255, 0.2);
}
select,
input[type='text'],
input[type='number'],
textarea {
padding: 3px 5px;
font-size: inherit;
}
.hidden-select {
opacity: 0;
position: absolute;
@@ -213,6 +230,7 @@ textarea {
display: inline-block;
color: var(--color-button);
font-size: inherit;
background: transparent;
border: 3px solid var(--color-button);
border-radius: 5px;
padding: 9px 15px;
@@ -244,9 +262,9 @@ textarea {
box-shadow: 0 5px 5px 0 rgba(0, 0, 0, 0.25);
}
[class*='btn']:focus {
*:focus {
outline-width: 4px;
outline-color: #b76b29;
outline-color: var(--color-button);
outline-style: solid;
outline-offset: 1px;
}
@@ -573,6 +591,8 @@ body > #demo-frame {
}
.footer {
display: flex;
justify-content: space-between;
/* Because .console is 6 */
z-index: 6;
}
@@ -587,7 +607,8 @@ body > #demo-frame {
.btn--dark,
.main-header__btn-wrap > button {
box-sizing: content-box;
font-size: 0.8em;
text-transform: uppercase;
font-size: 12px;
font-weight: bold;
line-height: 20px;
height: 20px;
@@ -605,7 +626,6 @@ body > #demo-frame {
);
/*text-shadow: 0px 1px 1px rgba(0,0,0,1);*/
box-shadow: 0 -1px 0px 0 rgba(255, 255, 255, 0.15);
text-transform: uppercase;
}
.btn--dark > svg {
@@ -721,19 +741,20 @@ body > #demo-frame {
.item-title-input {
background: none;
border: 0;
border: 0 !important;
color: rgba(255, 255, 255, 0.6);
flex: 1;
padding: 3px 5px !important;
}
.search-input {
background: rgba(255, 255, 255, 0.1);
padding: 10px 20px;
border: 0;
/* background: rgba(255, 255, 255, 0.1); */
/* padding: 10px 20px; */
/* border: 0; */
width: 100%;
font-size: 16px;
color: white;
border-radius: 4px;
/* color: white; */
/* border-radius: 4px; */
}
.modal {
@@ -787,10 +808,10 @@ body > #demo-frame {
}
.modal__content {
background: #fdfdfd;
color: #444;
background: var(--color-popup);
color: var(--color-text);
position: relative;
border-radius: 8px;
border-radius: 5px;
opacity: 0;
padding: 3em;
font-size: 1.1em;
@@ -852,7 +873,8 @@ body > #demo-frame {
}
.pledge-modal .modal__content,
.ask-to-import-modal .modal__content {
.ask-to-import-modal .modal__content,
.modal--small .modal__content {
max-width: 800px;
}
@@ -868,7 +890,7 @@ body > #demo-frame {
width: 450px;
padding: 20px 30px;
z-index: 6;
background-color: var(--color-sidebar);
background-color: var(--color-popup);
transition: 0.3s cubic-bezier(1, 0.13, 0.21, 0.87);
transition-property: transform;
will-change: transform;
@@ -1011,6 +1033,10 @@ body > #demo-frame {
pointer-events: auto;
}
.saved-item-tile__img {
margin-right: 10px;
}
.saved-item-tile__btn {
padding: 7px 10px;
color: rgba(255, 255, 255, 0.3);
@@ -1028,11 +1054,12 @@ body > #demo-frame {
.saved-item-tile__title {
pointer-events: none;
font-size: 1.4em;
margin: 0 0 1em 0;
margin: 0;
opacity: 0.8;
}
.saved-item-tile__meta {
margin-top: 8px;
pointer-events: none;
opacity: 0.3;
}
@@ -1087,10 +1114,10 @@ body > #demo-frame {
}
.notification {
border: 1px solid #f1f1f1;
/* border: 1px solid #f1f1f1; */
border-radius: 5px;
padding: 20px;
background: #f8f6f9;
background: rgba(248, 246, 249, 0.05);
position: relative;
}
@@ -1103,7 +1130,7 @@ body > #demo-frame {
}
.notification__version {
background: #ff8c00;
background: #af6204;
color: white;
padding: 3px;
border-radius: 5px;
@@ -1174,7 +1201,7 @@ body > #demo-frame {
.dropdown__menu > li.selected > a,
.dropdown__menu > li > a:hover {
background: var(--color-sidebar);
background: var(--color-popup);
color: white;
}
@@ -1257,11 +1284,9 @@ body > #demo-frame {
}
.onboard-step {
background: #f7f2f1;
border: 1px solid #ecdede;
margin: 15px;
padding: 20px 30px;
background-color: white;
background-color: rgba(255, 255, 255, 0.1);
border-radius: 10px;
box-shadow: 0 16px 22px rgba(0, 0, 0, 0.1);
flex: 1;
@@ -1383,7 +1408,7 @@ body > #demo-frame {
}
.kbd-shortcut__keys {
background: rgba(0, 0, 0, 0.1);
background: rgba(0, 0, 0, 0.3);
border-radius: 3px;
padding: 3px 8px;
margin-right: 5px;
@@ -1434,7 +1459,7 @@ body > #demo-frame {
.social-login-btn--google {
background: white;
border: 2px solid currentColor;
color: inherit;
color: black;
}
body.is-logged-in .hide-on-login,
@@ -1476,12 +1501,12 @@ body:not(.is-app) .show-when-app {
border: 1px #aaa solid;
padding: 0 5px;
border-style: dashed;
color: #333;
color: #f7f7f7;
}
.help-text {
font-size: 0.9em;
color: #616465;
color: rgba(255, 255, 255, 0.5);
}
.social-login-btn:after,
@@ -1506,6 +1531,32 @@ body:not(.is-app) .show-when-app {
visibility: visible;
}
.footer__js13k-days-left {
padding: 1px 9px;
text-transform: uppercase;
background: #b12a34;
color: white;
border-radius: 3px;
letter-spacing: 0.7px;
}
.footer__js13k-code-size {
margin-left: 1rem;
}
.js13k__dropdown {
position: fixed;
display: inline-block;
background: var(--color-popup);
color: var(--color-text);
bottom: 35px;
padding: 16px;
border-radius: 4px;
box-shadow: 0 -7px 13px 2px rgba(0, 0, 0, 0.2);
left: 50%;
margin-left: -115px;
}
@media screen and (max-width: 600px) {
body {
font-size: 70%;

View File

@@ -44,7 +44,11 @@ function saveScreenshot(dataURI) {
'/temporary/' +
fileName;
chrome.downloads.download(
// HACK: because chrome.downloads isn't working on optional permissions
// anymore.
return window.open(filePath);
/* chrome.downloads.download(
{
url: filePath
},
@@ -55,7 +59,7 @@ function saveScreenshot(dataURI) {
window.open(filePath);
}
}
);
); */
}
function errorHandler(e) {

17
src/templateList.js Normal file
View File

@@ -0,0 +1,17 @@
export default [
{
id: 'preact',
title: 'Preact',
img: 'assets/preact-logo.svg'
},
{
id: 'react',
title: 'React',
img: 'assets/react-logo.svg'
},
{
id: 'kontra-game-engine',
title: 'Kontra Game Engine',
img: 'assets/html5-logo.svg'
}
];

View File

@@ -0,0 +1,18 @@
{
"title": "Kontra HTML5 game engine template",
"html": " <canvas></canvas>",
"css": "",
"js":
"// Learn More here -> https://straker.github.io/kontra/getting-started\nkontra.init();\n\nvar sprite = kontra.sprite({\n x: 100, // starting x,y position of the sprite\n y: 80,\n color: '#bad455', // fill color of the sprite rectangle\n width: 20, // width and height of the sprite rectangle\n height: 40,\n dx: 2, // move the sprite 2px to the right every frame\n});\n\nvar loop = kontra.gameLoop({ // create the main game loop\n update: function() { // update the game state\n sprite.update();\n\n // wrap the sprites position when it reaches\n // the edge of the screen\n if (sprite.x > kontra.canvas.width) {\n sprite.x = -sprite.width;\n }\n },\n render: function() { // render the game state\n sprite.render();\n }\n});\n\nloop.start(); // start the game",
"externalLibs": {
"js":
"https://unpkg.com/kontra@3.3.0/dist/core.js\nhttps://unpkg.com/kontra@3.3.0/dist/sprite.js\nhttps://unpkg.com/kontra@3.3.0/dist/gameLoop.js\nhttps://unpkg.com/kontra@3.3.0/dist/pointer.js",
"css": ""
},
"htmlMode": "html",
"cssMode": "css",
"jsMode": "js",
"sizes": ["33px", "33px", "calc(100% - 66px)"],
"mainSizes": [50, 50],
"layoutMode": 1
}

View File

@@ -0,0 +1,16 @@
{
"title": "Preact template",
"externalLibs": {
"js": "\nhttps://cdnjs.cloudflare.com/ajax/libs/preact/8.2.9/preact.min.js",
"css": ""
},
"sizes": ["calc(30% - 3px)", "30px", "calc(70% - 3px)"],
"mainSizes": [68.1051, 31.6949],
"htmlMode": "html",
"cssMode": "css",
"jsMode": "es6",
"layoutMode": 1,
"js":
"\nconst { h, Component, render, createElement } = window.preact;\nconst React = {createElement}\n\nclass App extends Component {\n constructor() {\n super();\n this.message = 'World';\n }\n render() {\n return (<div>Hello {this.message}</div>)\n }\n}\nrender(<App/>, window.root)\n\n",
"html": "<div id=\"root\"></div>\n"
}

View File

@@ -0,0 +1,18 @@
{
"title": "React template",
"externalLibs": {
"js":
"\nhttps://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.min.js\nhttps://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.min.js",
"css": ""
},
"updatedOn": 1531063870556,
"sizes": ["", "calc(17.4842% - 6px)", "calc(49.1221% - 3px)"],
"mainSizes": [68.1051, 31.6949],
"htmlMode": "html",
"cssMode": "css",
"jsMode": "es6",
"layoutMode": 1,
"js":
"class App extends React.Component {\n constructor() {\n super();\n this.message = 'World';\n }\n render() {\n return (<h1>Hello {this.message}</h1>);\n }\n}\nReactDOM.render(<App/>, window.root);\n\n\n",
"html": "<div id=\"root\"></div>\n"
}

View File

@@ -6,7 +6,7 @@ import { shallow, deep } from 'preact-render-spy';
describe('Initial Test of the Footer', () => {
test('Footer renders 1 link with an ID of notificationsBtn', () => {
const context = shallow(<Footer />);
const context = shallow(<Footer prefs={{}} />);
expect(context.find('#notificationsBtn').exists()).toBeTruthy();
});
});

View File

@@ -212,9 +212,13 @@ export function downloadFile(fileName, blob) {
a.click();
a.remove();
}
if (window.IS_EXTENSION) {
chrome.downloads.download(
{
// HACK: because chrome.downloads isn't working on optional permissions
// anymore.
downloadWithAnchor();
/* if (false && window.IS_EXTENSION) {
chrome.downloads.download({
url: window.URL.createObjectURL(blob),
filename: fileName,
saveAs: true
@@ -228,7 +232,7 @@ export function downloadFile(fileName, blob) {
);
} else {
downloadWithAnchor();
}
} */
}
export function writeFile(name, blob, cb) {
@@ -345,7 +349,9 @@ export function getCompleteHtml(html, css, js, item, isForExport) {
'<script src="' +
(chrome.extension
? chrome.extension.getURL('lib/screenlog.js')
: `${location.origin}${BASE_PATH}/lib/screenlog.js`) +
: `${location.origin}${
window.DEBUG ? '' : BASE_PATH
}/lib/screenlog.js`) +
'"></script>';
}
@@ -378,7 +384,7 @@ export function saveAsHtml(item) {
var htmlPromise = computeHtml(item.html, item.htmlMode);
var cssPromise = computeCss(item.css, item.cssMode);
var jsPromise = computeJs(item.js, item.jsMode, false);
Promise.all([htmlPromise, cssPromise, jsPromise]).then(function(result) {
Promise.all([htmlPromise, cssPromise, jsPromise]).then(result => {
var html = result[0].code,
css = result[1].code,
js = result[2].code;
@@ -443,6 +449,17 @@ export function handleDownloadsPermission() {
return d.promise;
}
/**
* Return the filename from a passed url.
* http://a.com/path/file.png -> file.png
*/
export function getFilenameFromUrl(url) {
if (!url) {
return '';
}
return url.match(/\/([^/]*)$/)[1];
}
if (window.IS_EXTENSION) {
document.body.classList.add('is-extension');
} else {

View File

@@ -1136,7 +1136,11 @@ babel-plugin-syntax-export-extensions@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721"
babel-plugin-syntax-jsx@^6.0.0, babel-plugin-syntax-jsx@^6.8.0:
babel-plugin-syntax-flow@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d"
babel-plugin-syntax-jsx@^6.0.0, babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
@@ -1356,6 +1360,13 @@ babel-plugin-transform-export-extensions@^6.22.0:
babel-plugin-syntax-export-extensions "^6.8.0"
babel-runtime "^6.22.0"
babel-plugin-transform-flow-strip-types@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf"
dependencies:
babel-plugin-syntax-flow "^6.18.0"
babel-runtime "^6.22.0"
babel-plugin-transform-inline-consecutive-adds@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.2.0.tgz#15dae78921057f4004f8eafd79e15ddc5f12f426"
@@ -1397,6 +1408,26 @@ babel-plugin-transform-react-constant-elements@^6.23.0:
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-react-display-name@^6.23.0:
version "6.25.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz#67e2bf1f1e9c93ab08db96792e05392bf2cc28d1"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-react-jsx-self@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz#df6d80a9da2612a121e6ddd7558bcbecf06e636e"
dependencies:
babel-plugin-syntax-jsx "^6.8.0"
babel-runtime "^6.22.0"
babel-plugin-transform-react-jsx-source@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz#66ac12153f5cd2d17b3c19268f4bf0197f44ecd6"
dependencies:
babel-plugin-syntax-jsx "^6.8.0"
babel-runtime "^6.22.0"
babel-plugin-transform-react-jsx@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz#840a028e7df460dfc3a2d29f0c0d91f6376e66a3"
@@ -1456,7 +1487,7 @@ babel-polyfill@^6.2.0:
core-js "^2.5.0"
regenerator-runtime "^0.10.5"
babel-preset-env@^1.3.3:
babel-preset-env@^1.3.3, babel-preset-env@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a"
dependencies:
@@ -1491,6 +1522,12 @@ babel-preset-env@^1.3.3:
invariant "^2.2.2"
semver "^5.3.0"
babel-preset-flow@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d"
dependencies:
babel-plugin-transform-flow-strip-types "^6.22.0"
babel-preset-jest@^21.2.0:
version "21.2.0"
resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-21.2.0.tgz#ff9d2bce08abd98e8a36d9a8a5189b9173b85638"
@@ -1526,6 +1563,17 @@ babel-preset-minify@^0.2.0:
babel-plugin-transform-undefined-to-void "^6.8.3"
lodash.isplainobject "^4.0.6"
babel-preset-react@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.24.1.tgz#ba69dfaea45fc3ec639b6a4ecea6e17702c91380"
dependencies:
babel-plugin-syntax-jsx "^6.3.13"
babel-plugin-transform-react-display-name "^6.23.0"
babel-plugin-transform-react-jsx "^6.24.1"
babel-plugin-transform-react-jsx-self "^6.22.0"
babel-plugin-transform-react-jsx-source "^6.22.0"
babel-preset-flow "^6.23.0"
babel-register@^6.24.1, babel-register@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071"
@@ -2467,6 +2515,10 @@ core-js@^2.4.0, core-js@^2.5.0:
version "2.5.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e"
core-js@~2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65"
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@@ -3242,6 +3294,10 @@ es6-promise@^4.0.5:
version "4.2.4"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29"
es6-promise@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6"
es6-set@~0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1"
@@ -4812,6 +4868,10 @@ ignore@^3.3.3, ignore@^3.3.5:
version "3.3.8"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.8.tgz#3f8e9c35d38708a3a7e0e9abb6c73e7ee7707b2b"
immediate@~3.0.5:
version "3.0.6"
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
immutability-helper@^2.1.2:
version "2.7.0"
resolved "https://registry.yarnpkg.com/immutability-helper/-/immutability-helper-2.7.0.tgz#4ea9916cc8f45142ec3e3f0fce75fa5d66fa1b38"
@@ -5752,6 +5812,16 @@ jsx-ast-utils@^2.0.1:
dependencies:
array-includes "^3.0.3"
jszip@^3.1.5:
version "3.1.5"
resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.1.5.tgz#e3c2a6c6d706ac6e603314036d43cd40beefdf37"
dependencies:
core-js "~2.3.0"
es6-promise "~3.0.2"
lie "~3.1.0"
pako "~1.0.2"
readable-stream "~2.0.6"
killable@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.0.tgz#da8b84bd47de5395878f95d64d02f2449fe05e6b"
@@ -5823,6 +5893,12 @@ levn@^0.3.0, levn@~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"
lie@~3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e"
dependencies:
immediate "~3.0.5"
liftoff@^2.1.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.5.0.tgz#2009291bb31cea861bbf10a7c15a28caf75c31ec"
@@ -6993,7 +7069,7 @@ package-json@^4.0.0:
registry-url "^3.0.3"
semver "^5.1.0"
pako@~1.0.5:
pako@~1.0.2, pako@~1.0.5:
version "1.0.6"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258"
@@ -7694,6 +7770,10 @@ process-nextick-args@^2.0.0, process-nextick-args@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
process-nextick-args@~1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
process@^0.11.10:
version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
@@ -7960,6 +8040,17 @@ readable-stream@~1.1.9:
isarray "0.0.1"
string_decoder "~0.10.x"
readable-stream@~2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e"
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.1"
isarray "~1.0.0"
process-nextick-args "~1.0.6"
string_decoder "~0.10.x"
util-deprecate "~1.0.1"
readdirp@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"