Lint and fix issues, don't add linting yet though (#293)

* Lint and fix issue, don't add linting yet though

* Clean up

* Remove /about href
main
Michael Fix 7 years ago committed by GitHub
parent 083a0e8441
commit 5a4cdd7d7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -10,7 +10,7 @@ import { parseRGBA, capitalizeFirstLetter } from '../lib/util'
class BackgroundSelect extends React.PureComponent {
constructor(props) {
super(props)
this.state = { isVisible: false, selectedTab: 'color', mounted: false }
this.state = { isVisible: false, mounted: false }
this.toggle = this.toggle.bind(this)
this.selectTab = this.selectTab.bind(this)
this.handlePickColor = this.handlePickColor.bind(this)
@ -69,9 +69,9 @@ class BackgroundSelect extends React.PureComponent {
<div className="bg-select-pickers" hidden={!this.state.isVisible}>
<WindowPointer fromLeft="15px" />
<div className="picker-tabs">
{['color', 'image'].map((tab, i) => (
{['color', 'image'].map(tab => (
<div
key={i}
key={tab}
className={`picker-tab ${this.props.mode === tab ? 'active' : ''}`}
onClick={this.selectTab.bind(null, tab)}
>
@ -94,118 +94,120 @@ class BackgroundSelect extends React.PureComponent {
</div>
</div>
</div>
<style jsx>{`
.bg-select-container {
height: 100%;
}
.bg-select-display {
display: flex;
overflow: hidden;
height: 100%;
width: 72px;
border: 1px solid ${COLORS.SECONDARY};
border-radius: 3px;
}
.bg-select-label {
display: flex;
align-items: center;
justify-content: center;
user-select: none;
cursor: default;
height: 100%;
padding: 0 8px;
border-right: 1px solid ${COLORS.SECONDARY};
}
.bg-color-container {
position: relative;
width: 100%;
background: #fff;
cursor: pointer;
}
.bg-color {
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
${this.props.mode === 'image'
? `background: url(${this.props.image});
<style jsx>
{`
.bg-select-container {
height: 100%;
}
.bg-select-display {
display: flex;
overflow: hidden;
height: 100%;
width: 72px;
border: 1px solid ${COLORS.SECONDARY};
border-radius: 3px;
}
.bg-select-label {
display: flex;
align-items: center;
justify-content: center;
user-select: none;
cursor: default;
height: 100%;
padding: 0 8px;
border-right: 1px solid ${COLORS.SECONDARY};
}
.bg-color-container {
position: relative;
width: 100%;
background: #fff;
cursor: pointer;
}
.bg-color {
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
${this.props.mode === 'image'
? `background: url(${this.props.image});
background-size: cover;
background-repeat: no-repeat;`
: `background: ${background};`};
}
.bg-color-alpha {
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==);
}
.picker-tabs {
display: flex;
border-bottom: 1px solid ${COLORS.SECONDARY};
}
.picker-tab {
user-select: none;
cursor: pointer;
background: rgba(255, 255, 255, 0.165);
width: 50%;
text-align: center;
padding: 8px 0;
border-right: 1px solid ${COLORS.SECONDARY};
}
.picker-tab:last-child {
border-right: none;
}
.picker-tab.active {
background: none;
}
.bg-select-pickers {
position: absolute;
width: 222px;
margin-left: 36px;
margin-top: 4px;
border: 1px solid ${COLORS.SECONDARY};
border-radius: 3px;
background: #1a1a1a;
}
/* react-color overrides */
.bg-select-pickers :global(.sketch-picker) {
background: #1a1a1a !important;
padding: 8px 8px 0 !important;
margin: 0 auto 1px !important;
}
.bg-select-pickers :global(.sketch-picker > div:nth-child(3) > div > div > span) {
color: ${COLORS.SECONDARY} !important;
}
.bg-select-pickers :global(.sketch-picker > div:nth-child(3) > div > div > input) {
width: 100% !important;
box-shadow: none;
outline: none;
border-radius: 2px;
background: rgba(255, 255, 255, 0.165);
color: #fff !important;
}
/* prettier-ignore */
.bg-select-pickers :global(.sketch-picker > div:nth-child(2) > div:nth-child(1) > div:nth-child(2), .sketch-picker > div:nth-child(2) > div:nth-child(2)) {
: `background: ${background};`};
}
.bg-color-alpha {
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==);
}
.picker-tabs {
display: flex;
border-bottom: 1px solid ${COLORS.SECONDARY};
}
.picker-tab {
user-select: none;
cursor: pointer;
background: rgba(255, 255, 255, 0.165);
width: 50%;
text-align: center;
padding: 8px 0;
border-right: 1px solid ${COLORS.SECONDARY};
}
.picker-tab:last-child {
border-right: none;
}
.picker-tab.active {
background: none;
}
.bg-select-pickers {
position: absolute;
width: 222px;
margin-left: 36px;
margin-top: 4px;
border: 1px solid ${COLORS.SECONDARY};
border-radius: 3px;
background: #1a1a1a;
}
/* react-color overrides */
.bg-select-pickers :global(.sketch-picker) {
background: #1a1a1a !important;
padding: 8px 8px 0 !important;
margin: 0 auto 1px !important;
}
.bg-select-pickers :global(.sketch-picker > div:nth-child(3) > div > div > span) {
color: ${COLORS.SECONDARY} !important;
}
.bg-select-pickers :global(.sketch-picker > div:nth-child(3) > div > div > input) {
width: 100% !important;
box-shadow: none;
outline: none;
border-radius: 2px;
background: rgba(255, 255, 255, 0.165);
color: #fff !important;
}
/* prettier-ignore */
.bg-select-pickers :global(.sketch-picker > div:nth-child(2) > div:nth-child(1) > div:nth-child(2), .sketch-picker > div:nth-child(2) > div:nth-child(2)) {
background: #fff;
}
`}</style>
`}
</style>
</div>
)
}

@ -12,24 +12,26 @@ export default props => (
}}
>
<span>{props.title}</span>
<style jsx>{`
button {
cursor: pointer;
outline: none;
height: 100%;
padding: 0 16px;
border-radius: 3px;
user-select: none;
}
<style jsx>
{`
button {
cursor: pointer;
outline: none;
height: 100%;
padding: 0 16px;
border-radius: 3px;
user-select: none;
}
button:hover {
background: ${COLORS.HOVER} !important;
}
button:hover {
background: ${COLORS.HOVER} !important;
}
button > span {
font-size: 14px;
line-height: 1;
}
`}</style>
button > span {
font-size: 14px;
line-height: 1;
}
`}
</style>
</button>
)

@ -1,23 +1,14 @@
import { EOL } from 'os'
import * as hljs from 'highlight.js'
import React, { PureComponent } from 'react'
import Spinner from 'react-spinner'
import ResizeObserver from 'resize-observer-polyfill'
import toHash from 'tohash'
import debounce from 'lodash.debounce'
import ms from 'ms'
import WindowControls from '../components/WindowControls'
import Watermark from '../components/svg/Watermark'
import CodeMirror from '../lib/react-codemirror'
import {
COLORS,
DEFAULT_LANGUAGE,
LANGUAGES,
LANGUAGE_MODE_HASH,
LANGUAGE_NAME_HASH,
DEFAULT_SETTINGS
} from '../lib/constants'
import { COLORS, LANGUAGE_MODE_HASH, LANGUAGE_NAME_HASH, DEFAULT_SETTINGS } from '../lib/constants'
class Carbon extends PureComponent {
constructor(props) {
@ -130,120 +121,122 @@ class Carbon extends PureComponent {
<div className="alpha eliminateOnRender" />
<div className="bg" />
</div>
<style jsx>{`
#container {
position: relative;
min-width: ${config.widthAdjustment ? '90px' : '680px'};
max-width: 1024px; /* The Fallback */
max-width: 92vw;
padding: ${config.paddingVertical} ${config.paddingHorizontal};
}
#container :global(.watermark) {
fill-opacity: 0.3;
position: absolute;
z-index: 2;
bottom: calc(${config.paddingVertical} + 16px);
right: calc(${config.paddingHorizontal} + 16px);
}
#container #container-bg {
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
}
#container .white {
background: #fff;
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
}
#container .bg {
${this.props.config.backgroundMode === 'image'
? `background: url(${backgroundImage});
<style jsx>
{`
#container {
position: relative;
min-width: ${config.widthAdjustment ? '90px' : '680px'};
max-width: 1024px; /* The Fallback */
max-width: 92vw;
padding: ${config.paddingVertical} ${config.paddingHorizontal};
}
#container :global(.watermark) {
fill-opacity: 0.3;
position: absolute;
z-index: 2;
bottom: calc(${config.paddingVertical} + 16px);
right: calc(${config.paddingHorizontal} + 16px);
}
#container #container-bg {
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
}
#container .white {
background: #fff;
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
}
#container .bg {
${this.props.config.backgroundMode === 'image'
? `background: url(${backgroundImage});
background-size: cover;
background-repeat: no-repeat;`
: `background: ${this.props.config.backgroundColor || config.backgroundColor};
: `background: ${this.props.config.backgroundColor || config.backgroundColor};
background-size: auto;
background-repeat: repeat;`} position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
}
#container .alpha {
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==);
}
#container :global(.cm-s-dracula .CodeMirror-cursor) {
border-left: solid 2px #159588;
}
#container :global(.cm-s-solarized) {
box-shadow: none;
}
#container :global(.cm-s-solarized.cm-s-light) {
text-shadow: #eee8d5 0 1px;
}
#container :global(.CodeMirror-gutters) {
background-color: unset;
border-right: none;
}
#container :global(.CodeMirror__container) {
min-width: inherit;
position: relative;
z-index: 1;
border-radius: 5px;
${config.dropShadow
? `box-shadow: 0 ${config.dropShadowOffsetY} ${
config.dropShadowBlurRadius
} rgba(0, 0, 0, 0.55)`
: ''};
}
#container :global(.CodeMirror__container .CodeMirror) {
height: auto;
min-width: inherit;
padding: 18px 18px;
${config.lineNumbers ? 'padding-left: 12px;' : ''} border-radius: 5px;
font-family: ${config.fontFamily}, monospace !important;
font-size: ${config.fontSize};
font-variant-ligatures: contextual;
font-feature-settings: 'calt' 1;
user-select: none;
}
#container :global(.CodeMirror-scroll) {
overflow: hidden !important;
}
#container :global(.window-theme__sharp > .CodeMirror) {
border-radius: 0px;
}
#container :global(.window-theme__bw > .CodeMirror) {
border: 2px solid ${COLORS.SECONDARY};
}
#container :global(.window-controls + .CodeMirror__container > .CodeMirror) {
padding-top: 48px;
}
`}</style>
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
}
#container .alpha {
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==);
}
#container :global(.cm-s-dracula .CodeMirror-cursor) {
border-left: solid 2px #159588;
}
#container :global(.cm-s-solarized) {
box-shadow: none;
}
#container :global(.cm-s-solarized.cm-s-light) {
text-shadow: #eee8d5 0 1px;
}
#container :global(.CodeMirror-gutters) {
background-color: unset;
border-right: none;
}
#container :global(.CodeMirror__container) {
min-width: inherit;
position: relative;
z-index: 1;
border-radius: 5px;
${config.dropShadow
? `box-shadow: 0 ${config.dropShadowOffsetY} ${
config.dropShadowBlurRadius
} rgba(0, 0, 0, 0.55)`
: ''};
}
#container :global(.CodeMirror__container .CodeMirror) {
height: auto;
min-width: inherit;
padding: 18px 18px;
${config.lineNumbers ? 'padding-left: 12px;' : ''} border-radius: 5px;
font-family: ${config.fontFamily}, monospace !important;
font-size: ${config.fontSize};
font-variant-ligatures: contextual;
font-feature-settings: 'calt' 1;
user-select: none;
}
#container :global(.CodeMirror-scroll) {
overflow: hidden !important;
}
#container :global(.window-theme__sharp > .CodeMirror) {
border-radius: 0px;
}
#container :global(.window-theme__bw > .CodeMirror) {
border: 2px solid ${COLORS.SECONDARY};
}
#container :global(.window-controls + .CodeMirror__container > .CodeMirror) {
padding-top: 48px;
}
`}
</style>
</div>
)
}
@ -254,24 +247,26 @@ class Carbon extends PureComponent {
{content}
<div id="twitter-png-fix" />
</div>
<style jsx>{`
#section,
#export-container {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
overflow: hidden;
}
/* forces twitter to save images as png — https://github.com/dawnlabs/carbon/issues/86 */
#twitter-png-fix {
height: 1px;
width: 100%;
background: rgba(0, 0, 0, 0.01);
}
`}</style>
<style jsx>
{`
#section,
#export-container {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
overflow: hidden;
}
/* forces twitter to save images as png — https://github.com/dawnlabs/carbon/issues/86 */
#twitter-png-fix {
height: 1px;
width: 100%;
background: rgba(0, 0, 0, 0.01);
}
`}
</style>
</div>
)
}

@ -1,6 +1,5 @@
import React from 'react'
import Toggle from './Toggle'
import Arrowdown from './svg/Arrowdown'
class Collapse extends React.Component {
constructor(props) {

@ -10,13 +10,10 @@ class Dropdown extends PureComponent {
inputValue: this.props.selected.name,
itemsToShow: this.props.list
}
userInputtedValue = ''
onUserAction = changes => {
this.setState(({ inputValue, itemsToShow }) => {
const clearUserInput = changes.hasOwnProperty('isOpen')
if (changes.hasOwnProperty('inputValue')) {
if (Object.prototype.hasOwnProperty.call(changes, 'inputValue')) {
if (changes.type === Downshift.stateChangeTypes.keyDownEscape) {
inputValue = this.userInputtedValue
} else {
@ -30,7 +27,7 @@ class Dropdown extends PureComponent {
: this.props.list
if (
changes.hasOwnProperty('highlightedIndex') &&
Object.prototype.hasOwnProperty.call(changes, 'highlightedIndex') &&
(changes.type === Downshift.stateChangeTypes.keyDownArrowUp ||
changes.type === Downshift.stateChangeTypes.keyDownArrowDown)
) {
@ -38,7 +35,7 @@ class Dropdown extends PureComponent {
this.props.onChange(itemsToShow[changes.highlightedIndex])
}
if (changes.hasOwnProperty('isOpen')) {
if (Object.prototype.hasOwnProperty.call(changes, 'isOpen')) {
this.userInputtedValue = ''
// clear on open
@ -56,6 +53,8 @@ class Dropdown extends PureComponent {
})
}
userInputtedValue = ''
render() {
const { button, color, list, selected, onChange } = this.props
@ -122,13 +121,15 @@ const DropdownContainer = ({ children, innerRef, minWidth, ...rest }) => {
return (
<div {...rest} ref={innerRef} className="dropdown-container">
{children}
<style jsx>{`
.dropdown-container {
min-width: ${minWidth}px;
cursor: pointer;
user-select: none;
}
`}</style>
<style jsx>
{`
.dropdown-container {
min-width: ${minWidth}px;
cursor: pointer;
user-select: none;
}
`}
</style>
</div>
)
}
@ -150,40 +151,42 @@ const SelectedItem = ({ getButtonProps, getInputProps, children, isOpen, color,
className="dropdown-display-text"
/>
)}
<div role="button" className={`dropdown-arrow`}>
<div role="button" className="dropdown-arrow">
<ArrowDown fill={itemColor} />
</div>
<style jsx>{`
.dropdown-display {
display: flex;
align-items: center;
height: 100%;
border: 1px solid ${itemColor};
border-radius: 3px;
padding: 8px 16px;
outline: none;
}
.dropdown-display:hover {
background: ${COLORS.HOVER};
}
<style jsx>
{`
.dropdown-display {
display: flex;
align-items: center;
height: 100%;
border: 1px solid ${itemColor};
border-radius: 3px;
padding: 8px 16px;
outline: none;
}
.dropdown-display:hover {
background: ${COLORS.HOVER};
}
.dropdown-display.is-open {
border-radius: 3px 3px 0 0;
}
.dropdown-display.is-open {
border-radius: 3px 3px 0 0;
}
.dropdown-display-text {
flex-grow: 1;
color: ${itemColor};
background: transparent;
border: none;
outline: none;
font-size: inherit;
font-family: inherit;
}
.is-open > .dropdown-arrow {
transform: rotate(180deg);
}
`}</style>
.dropdown-display-text {
flex-grow: 1;
color: ${itemColor};
background: transparent;
border: none;
outline: none;
font-size: inherit;
font-family: inherit;
}
.is-open > .dropdown-arrow {
transform: rotate(180deg);
}
`}
</style>
</span>
)
}
@ -192,15 +195,17 @@ const ListItems = ({ children, color }) => {
return (
<ul role="listbox" className="dropdown-list">
{children}
<style jsx>{`
.dropdown-list {
margin-top: -1px;
border: 1px solid ${color || COLORS.SECONDARY};
border-radius: 0 0 3px 3px;
max-height: 350px;
overflow-y: scroll;
}
`}</style>
<style jsx>
{`
.dropdown-list {
margin-top: -1px;
border: 1px solid ${color || COLORS.SECONDARY};
border-radius: 0 0 3px 3px;
max-height: 350px;
overflow-y: scroll;
}
`}
</style>
</ul>
)
}
@ -212,27 +217,29 @@ const ListItem = ({ children, color, isHighlighted, isSelected, ...rest }) => {
<li {...rest} role="option" className="dropdown-list-item">
<span className="dropdown-list-item-text">{children}</span>
{isSelected ? <CheckMark /> : null}
<style jsx>{`
.dropdown-list-item {
display: flex;
align-items: center;
background: ${isHighlighted ? COLORS.HOVER : COLORS.BLACK};
padding: 8px 16px;
border-bottom: 1px solid ${itemColor};
}
<style jsx>
{`
.dropdown-list-item {
display: flex;
align-items: center;
background: ${isHighlighted ? COLORS.HOVER : COLORS.BLACK};
padding: 8px 16px;
border-bottom: 1px solid ${itemColor};
}
.dropdown-list-item:last-child {
border-bottom: none;
}
.dropdown-list-item:last-child {
border-bottom: none;
}
.dropdown-list-item:hover {
background: ${COLORS.HOVER};
}
.dropdown-list-item-text {
flex-grow: 1;
color: ${itemColor};
}
`}</style>
.dropdown-list-item:hover {
background: ${COLORS.HOVER};
}
.dropdown-list-item-text {
flex-grow: 1;
color: ${itemColor};
}
`}
</style>
</li>
)
}

@ -1,7 +1,6 @@
import React from 'react'
import { COLORS } from '../lib/constants'
import Checkmark from './svg/Checkmark'
import { EXPORT_SIZES } from '../lib/constants'
import { EXPORT_SIZES, COLORS } from '../lib/constants'
export default class extends React.Component {
constructor(props) {
@ -22,12 +21,16 @@ export default class extends React.Component {
}
renderExportSizes() {
return EXPORT_SIZES.map((exportSize, i) => {
return (
<div className="list-item" key={i} onClick={this.select.bind(null, exportSize.id)}>
<span style={{ ExportSize: exportSize.id }}>{exportSize.name}</span>
{this.props.selected === exportSize.id ? <Checkmark /> : null}
<style jsx>{`
return EXPORT_SIZES.map(exportSize => (
<div
className="list-item"
key={exportSize.id}
onClick={this.select.bind(null, exportSize.id)}
>
<span style={{ ExportSize: exportSize.id }}>{exportSize.name}</span>
{this.props.selected === exportSize.id ? <Checkmark /> : null}
<style jsx>
{`
.list-item {
display: flex;
align-items: center;
@ -44,10 +47,10 @@ export default class extends React.Component {
.list-item:last-of-type {
border-bottom: none;
}
`}</style>
</div>
)
})
`}
</style>
</div>
))
}
render() {
@ -63,25 +66,27 @@ export default class extends React.Component {
<span style={{ exportSize: selectedExportSize.id }}>{selectedExportSize.name}</span>
</div>
<div className="list">{this.renderExportSizes()}</div>
<style jsx>{`
.display {
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
user-select: none;
padding: 8px;
}
.list {
display: none;
margin-top: -1px;
max-height: 80px;
overflow-y: scroll;
}
.is-visible + .list {
display: block;
}
`}</style>
<style jsx>
{`
.display {
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
user-select: none;
padding: 8px;
}
.list {
display: none;
margin-top: -1px;
max-height: 80px;
overflow-y: scroll;
}
.is-visible + .list {
display: block;
}
`}
</style>
</div>
)
}

@ -21,28 +21,30 @@ export default class extends React.Component {
}
renderListItems() {
return FONTS.map((font, i) => (
<div className="list-item" key={i} onClick={this.select.bind(null, font.id)}>
return FONTS.map(font => (
<div className="list-item" key={font.id} onClick={this.select.bind(null, font.id)}>
<span style={{ fontFamily: font.id }}>{font.name}</span>
{this.props.selected === font.id ? <Checkmark /> : null}
<style jsx>{`
.list-item {
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
user-select: none;
padding: 8px 16px;
border-bottom: 1px solid ${COLORS.SECONDARY};
background: rgba(255, 255, 255, 0.165);
}
.list-item:first-of-type {
border-top: 1px solid ${COLORS.SECONDARY};
}
.list-item:last-of-type {
border-bottom: none;
}
`}</style>
<style jsx>
{`
.list-item {
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
user-select: none;
padding: 8px 16px;
border-bottom: 1px solid ${COLORS.SECONDARY};
background: rgba(255, 255, 255, 0.165);
}
.list-item:first-of-type {
border-top: 1px solid ${COLORS.SECONDARY};
}
.list-item:last-of-type {
border-bottom: none;
}
`}
</style>
</div>
))
}
@ -59,25 +61,27 @@ export default class extends React.Component {
<span style={{ fontFamily: selectedFont.id }}>{selectedFont.name}</span>
</div>
<div className="list">{this.renderListItems()}</div>
<style jsx>{`
.display {
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
user-select: none;
padding: 8px;
}
.list {
display: none;
margin-top: -1px;
max-height: 80px;
overflow-y: scroll;
}
.is-visible + .list {
display: block;
}
`}</style>
<style jsx>
{`
.display {
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
user-select: none;
padding: 8px;
}
.list {
display: none;
margin-top: -1px;
max-height: 80px;
overflow-y: scroll;
}
.is-visible + .list {
display: block;
}
`}
</style>
</div>
)
}

@ -4,7 +4,7 @@ import { COLORS } from '../lib/constants'
const Footer = () => (
<footer role="contentinfo" className="mt3">
<nav role="navigation" className="mt3">
<nav className="mt3">
<Link href="/about">
<a className="link">about</a>
</Link>
@ -22,33 +22,35 @@ const Footer = () => (
</a>{' '}
¬
</div>
<style jsx>{`
footer {
font-size: 14px;
}
<style jsx>
{`
footer {
font-size: 14px;
}
footer > div {
text-align: center;
color: ${COLORS.GRAY};
}
footer > div {
text-align: center;
color: ${COLORS.GRAY};
}
a {
margin-right: 16px;
}
a {
margin-right: 16px;
}
a:last-child {
margin-right: 0;
}
a:last-child {
margin-right: 0;
}
.dawn-link {
color: ${COLORS.PRIMARY};
text-decoration: none;
}
.dawn-link {
color: ${COLORS.PRIMARY};
text-decoration: none;
}
.dawn-link:hover {
color: #fff;
}
`}</style>
.dawn-link:hover {
color: #fff;
}
`}
</style>
</footer>
)

@ -14,25 +14,27 @@ const Header = ({ enableHeroText }) => (
</h2>
) : null}
</div>
<style jsx>{`
.header {
width: 656px;
}
<style jsx>
{`
.header {
width: 656px;
}
.header-content {
display: flex;
flex-direction: column;
align-items: center;
}
.header-content {
display: flex;
flex-direction: column;
align-items: center;
}
.header-content a {
height: 64px;
}
.header-content a {
height: 64px;
}
h2 {
text-align: center;
}
`}</style>
h2 {
text-align: center;
}
`}
</style>
</header>
)

@ -1,9 +1,7 @@
import React from 'react'
import ReactCrop, { makeAspectCrop } from 'react-image-crop'
import Slider from './Slider'
import RandomImage from './RandomImage'
import { COLORS } from '../lib/constants'
import { fileToDataURL } from '../lib/util'
const getCroppedImg = (imageDataURL, pixelCrop) => {
@ -12,7 +10,7 @@ const getCroppedImg = (imageDataURL, pixelCrop) => {
canvas.height = pixelCrop.height
const ctx = canvas.getContext('2d')
return new Promise((resolve, reject) => {
return new Promise(resolve => {
const image = new Image()
image.src = imageDataURL
image.onload = () => {
@ -47,7 +45,7 @@ export default class extends React.Component {
}
componentWillReceiveProps(nextProps) {
if (this.state.crop && this.props.aspectRatio != nextProps.aspectRatio) {
if (this.state.crop && this.props.aspectRatio !== nextProps.aspectRatio) {
// update crop for editor container aspect-ratio change
this.setState({
crop: makeAspectCrop(
@ -61,20 +59,17 @@ export default class extends React.Component {
}
}
selectImage(e) {
const file = e.target ? e.target.files[0] : e
return fileToDataURL(file).then(dataURL =>
this.props.onChange({ backgroundImage: dataURL, backgroundImageSelection: null })
)
async onDragEnd() {
if (this.state.pixelCrop) {
const croppedImg = await getCroppedImg(this.props.imageDataURL, this.state.pixelCrop)
this.props.onChange({ backgroundImageSelection: croppedImg })
}
}
removeImage() {
this.setState(INITIAL_STATE, () => {
this.props.onChange({
backgroundImage: null,
backgroundImageSelection: null
})
onCropChange(crop, pixelCrop) {
this.setState({
crop: { ...crop, aspect: this.props.aspectRatio },
pixelCrop
})
}
@ -93,18 +88,21 @@ export default class extends React.Component {
})
}
onCropChange(crop, pixelCrop) {
this.setState({
crop: { ...crop, aspect: this.props.aspectRatio },
pixelCrop
})
selectImage(e) {
const file = e.target ? e.target.files[0] : e
return fileToDataURL(file).then(dataURL =>
this.props.onChange({ backgroundImage: dataURL, backgroundImageSelection: null })
)
}
async onDragEnd() {
if (this.state.pixelCrop) {
const croppedImg = await getCroppedImg(this.props.imageDataURL, this.state.pixelCrop)
this.props.onChange({ backgroundImageSelection: croppedImg })
}
removeImage() {
this.setState(INITIAL_STATE, () => {
this.props.onChange({
backgroundImage: null,
backgroundImageSelection: null
})
})
}
render() {
@ -125,31 +123,33 @@ export default class extends React.Component {
</span>
<RandomImage onChange={this.selectImage} />
</div>
<style jsx>{`
.choose-image,
.random-image {
padding: 8px;
}
input {
cursor: pointer;
outline: none;
}
span {
display: block;
margin-bottom: 16px;
}
a {
text-decoration: underline;
}
hr {
border-bottom: none;
margin-bottom: 0;
}
`}</style>
<style jsx>
{`
.choose-image,
.random-image {
padding: 8px;
}
input {
cursor: pointer;
outline: none;
}
span {
display: block;
margin-bottom: 16px;
}
a {
text-decoration: underline;
}
hr {
border-bottom: none;
margin-bottom: 0;
}
`}
</style>
</div>
)
@ -174,31 +174,33 @@ export default class extends React.Component {
keepSelection
/>
</div>
<style jsx>{`
.settings-container img {
width: 100%;
}
.label {
user-select: none;
margin-bottom: 4px;
}
:global(.ReactCrop__image) {
user-select: none;
user-drag: none;
}
.image-container {
padding: 8px;
}
.image-container .label {
display: flex;
justify-content: space-between;
align-items: center;
}
`}</style>
<style jsx>
{`
.settings-container img {
width: 100%;
}
.label {
user-select: none;
margin-bottom: 4px;
}
:global(.ReactCrop__image) {
user-select: none;
user-drag: none;
}
.image-container {
padding: 8px;
}
.image-container .label {
display: flex;
justify-content: space-between;
align-items: center;
}
`}
</style>
</div>
)
}
@ -206,11 +208,13 @@ export default class extends React.Component {
return (
<div>
<div className="image-picker-container">{content}</div>
<style jsx>{`
.image-picker-container {
font-size: 12px;
}
`}</style>
<style jsx>
{`
.image-picker-container {
font-size: 12px;
}
`}
</style>
</div>
)
}

@ -1,5 +1,4 @@
import React from 'react'
import { Controls, ControlsBW } from './svg/Controls'
export default ({ language }) => (
<div className="language">

@ -1,5 +1,5 @@
import Head from 'next/head'
import { THEMES, COLORS } from '../lib/constants'
import { THEMES } from '../lib/constants'
import Reset from './style/Reset'
import Font from './style/Font'
import Typography from './style/Typography'
@ -39,11 +39,11 @@ export default () => (
/>
<link
rel="stylesheet"
href={`//cdnjs.cloudflare.com/ajax/libs/codemirror/5.30.0/theme/solarized.min.css`}
href="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.30.0/theme/solarized.min.css"
/>
{THEMES.filter(t => t.hasStylesheet !== false).map((theme, i) => (
{THEMES.filter(t => t.hasStylesheet !== false).map(theme => (
<link
key={i}
key={theme.id}
rel="stylesheet"
href={
theme.link ||
@ -55,10 +55,12 @@ export default () => (
<Reset />
<Font />
<Typography />
<style jsx>{`
.meta {
display: none;
}
`}</style>
<style jsx>
{`
.meta {
display: none;
}
`}
</style>
</div>
)

@ -2,25 +2,27 @@ const Overlay = props => (
<div className="dnd-container">
{props.isOver ? <div className="dnd-overlay">{props.title}</div> : null}
{props.children}
<style jsx>{`
.dnd-container {
position: relative;
}
<style jsx>
{`
.dnd-container {
position: relative;
}
.dnd-overlay {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
width: 100%;
height: 100%;
z-index: 999;
position: absolute;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.85);
}
`}</style>
.dnd-overlay {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
width: 100%;
height: 100%;
z-index: 999;
position: absolute;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.85);
}
`}
</style>
</div>
)

@ -11,13 +11,15 @@ export default ({ children, enableHeroText }) => (
<Footer />
<style jsx>{`
.main {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}
`}</style>
<style jsx>
{`
.main {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}
`}
</style>
</main>
)

@ -10,9 +10,8 @@ const WALLPAPER_COLLECTION_ID = 136026
const RANDOM_WALLPAPER_URL = `https://source.unsplash.com/collection/${WALLPAPER_COLLECTION_ID}/240x320`
const largerImage = url => url.replace(/w=\d+/, 'w=1920').replace(/&h=\d+/, '')
const smallerImage = url => url.replace(/w=\d+/, 'w=240')
export default class extends React.Component {
export default class RandomImage extends React.Component {
constructor(props) {
super(props)
this.state = { cacheIndex: 0, loading: false }
@ -22,9 +21,6 @@ export default class extends React.Component {
this.nextImage = this.nextImage.bind(this)
}
cache = []
imageUrls = {}
// fetch images in browser (we require window.FileReader)
componentDidMount() {
// clear cache when remounted
@ -39,7 +35,7 @@ export default class extends React.Component {
const res = await axios.get(`${RANDOM_WALLPAPER_URL}?sig=${sig}`, { responseType: 'blob' })
// image already in cache?
if (this.imageUrls[res.request.responseURL]) return
if (this.imageUrls[res.request.responseURL]) return undefined
this.imageUrls[res.request.responseURL] = true
return {
@ -48,6 +44,9 @@ export default class extends React.Component {
}
}
cache = []
imageUrls = {}
selectImage() {
this.setState({ loading: true })
axios
@ -85,27 +84,29 @@ export default class extends React.Component {
<span onClick={this.nextImage}>Try Another</span>
</div>
<div className="image">{this.state.loading && <Spinner />}</div>
<style jsx>{`
.image {
width: 100%;
height: 120px;
background: url(${bgImage});
background-size: cover;
background-repeat: no-repeat;
}
.controls {
display: flex;
justify-content: space-between;
margin-bottom: 4px;
}
span {
opacity: ${this.state.loading ? 0.5 : 1};
cursor: ${this.state.loading ? 'not-allowed' : 'pointer'};
user-select: none;
}
`}</style>
<style jsx>
{`
.image {
width: 100%;
height: 120px;
background: url(${bgImage});
background-size: cover;
background-repeat: no-repeat;
}
.controls {
display: flex;
justify-content: space-between;
margin-bottom: 4px;
}
span {
opacity: ${this.state.loading ? 0.5 : 1};
cursor: ${this.state.loading ? 'not-allowed' : 'pointer'};
user-select: none;
}
`}
</style>
</div>
)
}

@ -116,62 +116,64 @@ class Settings extends React.Component {
/>
</Collapse>
</div>
<style jsx>{`
.settings-container {
display: flex;
position: relative;
height: 100%;
width: 37px;
align-items: center;
justify-content: center;
border-radius: 3px;
color: #fff;
font-size: 12px;
}
<style jsx>
{`
.settings-container {
display: flex;
position: relative;
height: 100%;
width: 37px;
align-items: center;
justify-content: center;
border-radius: 3px;
color: #fff;
font-size: 12px;
}
.settings-display {
height: 100%;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid ${COLORS.SECONDARY};
border-radius: 3px;
user-select: none;
position: relative;
z-index: 1;
cursor: pointer;
}
.settings-display {
height: 100%;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid ${COLORS.SECONDARY};
border-radius: 3px;
user-select: none;
position: relative;
z-index: 1;
cursor: pointer;
}
.settings-display:hover {
background: ${COLORS.HOVER};
}
.settings-display:hover {
background: ${COLORS.HOVER};
}
.is-visible + .settings-settings {
display: block;
}
.is-visible + .settings-settings {
display: block;
}
.settings-settings {
display: none;
position: absolute;
top: 44px;
left: 0;
border: 1px solid ${COLORS.SECONDARY};
width: 184px;
border-radius: 3px;
background: ${COLORS.BLACK};
}
.settings-settings {
display: none;
position: absolute;
top: 44px;
left: 0;
border: 1px solid ${COLORS.SECONDARY};
width: 184px;
border-radius: 3px;
background: ${COLORS.BLACK};
}
.settings-settings > :global(div) {
border-bottom: solid 1px ${COLORS.SECONDARY};
}
.settings-settings > :global(div) {
border-bottom: solid 1px ${COLORS.SECONDARY};
}
.settings-settings > :global(div):first-child,
.settings-settings > :global(div):last-child,
.settings-settings > :global(.collapse) {
border-bottom: none;
}
`}</style>
.settings-settings > :global(div):first-child,
.settings-settings > :global(div):last-child,
.settings-settings > :global(.collapse) {
border-bottom: none;
}
`}
</style>
</div>
)
}

@ -27,49 +27,51 @@ export default class extends React.Component {
<div
className="slider-bg"
style={{
transform: `translate3d(${(parseInt(this.props.value) - minValue) *
transform: `translate3d(${(parseInt(this.props.value, 10) - minValue) *
1.0 /
(maxValue - minValue) *
100}%, 0px, 0px)`
}}
/>
<style jsx>{`
.slider {
position: relative;
height: 32px;
overflow: hidden;
user-select: none;
}
<style jsx>
{`
.slider {
position: relative;
height: 32px;
overflow: hidden;
user-select: none;
}
.slider:last-of-type {
border-bottom: 0;
}
.slider:last-of-type {
border-bottom: 0;
}
.label {
position: absolute;
left: 8px;
height: 32px;
line-height: 32px;
}
.label {
position: absolute;
left: 8px;
height: 32px;
line-height: 32px;
}
.slider input {
opacity: 0;
cursor: ew-resize;
position: relative;
height: 100%;
width: 100%;
}
.slider input {
opacity: 0;
cursor: ew-resize;
position: relative;
height: 100%;
width: 100%;
}
.slider-bg {
position: absolute;
top: 0;
bottom: 0;
pointer-events: none;
height: 32px;
width: 100%;
background: rgba(255, 255, 255, 0.165);
}
`}</style>
.slider-bg {
position: absolute;
top: 0;
bottom: 0;
pointer-events: none;
height: 32px;
width: 100%;
background: rgba(255, 255, 255, 0.165);
}
`}
</style>
</div>
)
}

@ -18,30 +18,32 @@ export default class extends React.Component {
}
renderThemes() {
return WINDOW_THEMES.map((theme, i) => {
return WINDOW_THEMES.map(theme => {
const Img = WINDOW_THEMES_MAP[theme]
return (
<div
className={`theme ${this.props.selected === theme ? 'selected' : ''}`}
key={i}
key={theme}
onClick={this.select.bind(null, theme)}
>
<Img />
<style jsx>{`
.theme {
cursor: pointer;
margin-right: 8px;
}
<style jsx>
{`
.theme {
cursor: pointer;
margin-right: 8px;
}
.theme:last-of-type {
margin-right: 0px;
}
.theme:last-of-type {
margin-right: 0px;
}
.selected :global(svg) {
border-radius: 3px;
border: solid 2px ${COLORS.SECONDARY};
}
`}</style>
.selected :global(svg) {
border-radius: 3px;
border: solid 2px ${COLORS.SECONDARY};
}
`}
</style>
</div>
)
})
@ -52,22 +54,24 @@ export default class extends React.Component {
<div className="window-theme">
<span className="label">Window theme</span>
<div className="themes">{this.renderThemes()}</div>
<style jsx>{`
.window-theme {
padding: 8px;
}
<style jsx>
{`
.window-theme {
padding: 8px;
}
.window-theme span {
display: inline-block;
margin-bottom: 8px;
}
.window-theme span {
display: inline-block;
margin-bottom: 8px;
}
.themes {
display: flex;
flex-direction: row;
width: 100%;
}
`}</style>
.themes {
display: flex;
flex-direction: row;
width: 100%;
}
`}
</style>
</div>
)
}

@ -13,19 +13,21 @@ export default class extends React.Component {
render() {
return (
<div className={'toggle ' + this.props.className} onClick={this.toggle}>
<div className={`toggle ${this.props.className}`} onClick={this.toggle}>
<span className="label">{this.props.label}</span>
{this.props.enabled ? <Checkmark /> : null}
<style jsx>{`
.toggle {
display: flex;
align-items: center;
justify-content: ${this.props.center ? 'center' : 'space-between'};
cursor: pointer;
user-select: none;
padding: 8px;
}
`}</style>
<style jsx>
{`
.toggle {
display: flex;
align-items: center;
justify-content: ${this.props.center ? 'center' : 'space-between'};
cursor: pointer;
user-select: none;
padding: 8px;
}
`}
</style>
</div>
)
}

@ -1,27 +1,30 @@
import React from 'react'
const Toolbar = props => (
<div id="toolbar">
{props.children}
<style jsx>{`
#toolbar {
width: 100%;
height: 40px; // TODO fix
margin-bottom: 16px;
display: flex;
position: relative;
z-index: 3;
font-size: 14px;
color: #fff;
}
<style jsx>
{`
#toolbar {
width: 100%;
height: 40px; // TODO fix
margin-bottom: 16px;
display: flex;
position: relative;
z-index: 3;
font-size: 14px;
color: #fff;
}
#toolbar > :global(div) {
margin-right: 8px;
}
#toolbar > :global(div) {
margin-right: 8px;
}
#toolbar > :global(div):last-child {
margin-right: 0px;
}
`}</style>
#toolbar > :global(div):last-child {
margin-right: 0px;
}
`}
</style>
</div>
)

@ -3,17 +3,19 @@ import React from 'react'
export default ({ fromLeft }) => (
<div style={{ left: fromLeft }}>
<div className="window-pointer" />
<style jsx>{`
.window-pointer {
width: 0px;
height: 0px;
border-style: solid;
border-width: 0 4px 5px 4px;
border-color: transparent transparent #fff transparent;
position: absolute;
top: -5px;
left: 15px;
}
`}</style>
<style jsx>
{`
.window-pointer {
width: 0px;
height: 0px;
border-style: solid;
border-width: 0 4px 5px 4px;
border-color: transparent transparent #fff transparent;
position: absolute;
top: -5px;
left: 15px;
}
`}
</style>
</div>
)

@ -1,91 +1,93 @@
export default () => (
<style jsx global>{`
@font-face {
font-family: 'Iosevka';
src: url('//cdn.jsdelivr.net/npm/@typopro/web-iosevka@3.7.5/TypoPRO-iosevka-term-bold.woff')
format('woff');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Hack';
src: url('//cdn.jsdelivr.net/font-hack/2.020/fonts/woff2/hack-regular-webfont.woff2?v=2.020')
format('woff2'),
url('//cdn.jsdelivr.net/font-hack/2.020/fonts/woff/hack-regular-webfont.woff?v=2.020')
<style jsx global>
{`
@font-face {
font-family: 'Iosevka';
src: url('//cdn.jsdelivr.net/npm/@typopro/web-iosevka@3.7.5/TypoPRO-iosevka-term-bold.woff')
format('woff');
font-weight: 400;
font-style: normal;
}
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Fira Code';
src: url('//cdn.rawgit.com/tonsky/FiraCode/1.204/distr/woff2/FiraCode-Regular.woff2')
format('woff2'),
url('//cdn.rawgit.com/tonsky/FiraCode/1.204/distr/woff/FiraCode-Regular.woff')
format('woff');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Hack';
src: url('//cdn.jsdelivr.net/font-hack/2.020/fonts/woff2/hack-regular-webfont.woff2?v=2.020')
format('woff2'),
url('//cdn.jsdelivr.net/font-hack/2.020/fonts/woff/hack-regular-webfont.woff?v=2.020')
format('woff');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Fira Code';
src: url('//cdn.rawgit.com/tonsky/FiraCode/1.204/distr/woff2/FiraCode-Regular.woff2')
format('woff2'),
url('//cdn.rawgit.com/tonsky/FiraCode/1.204/distr/woff/FiraCode-Regular.woff')
format('woff');
font-weight: 400;
font-style: normal;
}
/* latin */
@font-face {
font-family: 'Anonymous Pro';
font-style: normal;
font-weight: 400;
src: local('Anonymous Pro Regular'), local('AnonymousPro-Regular'),
url(//fonts.gstatic.com/s/anonymouspro/v11/Zhfjj_gat3waL4JSju74E3n3cbdKJftHIk87C9ihfO8.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;
}
/* latin */
@font-face {
font-family: 'Anonymous Pro';
font-style: normal;
font-weight: 400;
src: local('Anonymous Pro Regular'), local('AnonymousPro-Regular'),
url(//fonts.gstatic.com/s/anonymouspro/v11/Zhfjj_gat3waL4JSju74E3n3cbdKJftHIk87C9ihfO8.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;
}
/* latin */
@font-face {
font-family: 'Droid Sans Mono';
font-style: normal;
font-weight: 400;
src: local('Droid Sans Mono Regular'), local('DroidSansMono-Regular'),
url(//fonts.gstatic.com/s/droidsansmono/v9/ns-m2xQYezAtqh7ai59hJVlgUn8GogvcKKzoM9Dh-4E.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;
}
/* latin */
@font-face {
font-family: 'Droid Sans Mono';
font-style: normal;
font-weight: 400;
src: local('Droid Sans Mono Regular'), local('DroidSansMono-Regular'),
url(//fonts.gstatic.com/s/droidsansmono/v9/ns-m2xQYezAtqh7ai59hJVlgUn8GogvcKKzoM9Dh-4E.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;
}
/* latin */
@font-face {
font-family: 'Inconsolata';
font-style: normal;
font-weight: 400;
src: local('Inconsolata Regular'), local('Inconsolata-Regular'),
url(//fonts.gstatic.com/s/inconsolata/v16/BjAYBlHtW3CJxDcjzrnZCIgp9Q8gbYrhqGlRav_IXfk.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;
}
/* latin */
@font-face {
font-family: 'Inconsolata';
font-style: normal;
font-weight: 400;
src: local('Inconsolata Regular'), local('Inconsolata-Regular'),
url(//fonts.gstatic.com/s/inconsolata/v16/BjAYBlHtW3CJxDcjzrnZCIgp9Q8gbYrhqGlRav_IXfk.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;
}
/* latin */
@font-face {
font-family: 'Source Code Pro';
font-style: normal;
font-weight: 400;
src: local('Source Code Pro'), local('SourceCodePro-Regular'),
url(//fonts.gstatic.com/s/sourcecodepro/v7/mrl8jkM18OlOQN8JLgasD5bPFduIYtoLzwST68uhz_Y.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;
}
/* latin */
@font-face {
font-family: 'Source Code Pro';
font-style: normal;
font-weight: 400;
src: local('Source Code Pro'), local('SourceCodePro-Regular'),
url(//fonts.gstatic.com/s/sourcecodepro/v7/mrl8jkM18OlOQN8JLgasD5bPFduIYtoLzwST68uhz_Y.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;
}
/* latin */
@font-face {
font-family: 'Ubuntu Mono';
font-style: normal;
font-weight: 400;
src: local('Ubuntu Mono'), local('UbuntuMono-Regular'),
url(//fonts.gstatic.com/s/ubuntumono/v7/ViZhet7Ak-LRXZMXzuAfkYgp9Q8gbYrhqGlRav_IXfk.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;
}
`}</style>
/* latin */
@font-face {
font-family: 'Ubuntu Mono';
font-style: normal;
font-weight: 400;
src: local('Ubuntu Mono'), local('UbuntuMono-Regular'),
url(//fonts.gstatic.com/s/ubuntumono/v7/ViZhet7Ak-LRXZMXzuAfkYgp9Q8gbYrhqGlRav_IXfk.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;
}
`}
</style>
)

@ -1,195 +1,197 @@
import { COLORS } from '../../lib/constants'
export default () => (
<style jsx global>{`
/* http://meyerweb.com/eric/tools/css/reset/
<style jsx global>
{`
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font-weight: inherit;
font-family: inherit;
font-style: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block;
}
ol,
ul {
list-style: none;
}
blockquote,
q {
quotes: none;
}
blockquote:before,
blockquote:after,
q:before,
q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font-weight: inherit;
font-family: inherit;
font-style: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block;
}
ol,
ul {
list-style: none;
}
blockquote,
q {
quotes: none;
}
blockquote:before,
blockquote:after,
q:before,
q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
html,
body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
background: ${COLORS.BLACK};
color: white;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Ubuntu, 'Helvetica Neue',
sans-serif;
font-weight: 400;
font-style: normal;
text-transform: initial;
letter-spacing: initial;
overflow-y: auto;
min-width: 848px;
min-height: 704px;
}
html,
body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
background: ${COLORS.BLACK};
color: white;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Ubuntu, 'Helvetica Neue',
sans-serif;
font-weight: 400;
font-style: normal;
text-transform: initial;
letter-spacing: initial;
overflow-y: auto;
min-width: 848px;
min-height: 704px;
}
* {
box-sizing: border-box;
}
* {
box-sizing: border-box;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: 500;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: 500;
}
a {
color: inherit;
text-decoration: none;
cursor: pointer;
}
a {
color: inherit;
text-decoration: none;
cursor: pointer;
}
*::selection {
background: rgba(255, 255, 255, 0.99);
color: #121212;
}
*::selection {
background: rgba(255, 255, 255, 0.99);
color: #121212;
}
.link {
color: #fff;
text-decoration: none;
padding-bottom: 3px;
background: linear-gradient(
to right,
rgba(255, 255, 255, 0.7) 0%,
rgba(255, 255, 255, 0.7) 100%
);
background-size: 1px 1px;
background-position: 0 100%;
background-repeat: repeat-x;
}
.link {
color: #fff;
text-decoration: none;
padding-bottom: 3px;
background: linear-gradient(
to right,
rgba(255, 255, 255, 0.7) 0%,
rgba(255, 255, 255, 0.7) 100%
);
background-size: 1px 1px;
background-position: 0 100%;
background-repeat: repeat-x;
}
.link:hover {
color: ${COLORS.PRIMARY};
background: none;
}
`}</style>
.link:hover {
color: ${COLORS.PRIMARY};
background: none;
}
`}
</style>
)

@ -1,178 +1,180 @@
export default () => (
<style jsx global>{`
/* https://github.com/jxnblk/type-system
<style jsx global>
{`
/* https://github.com/jxnblk/type-system
Brent Jackson
License: MIT
*/
:root {
--h0: 4.5rem;
--h1: 3rem;
--h2: 2.25rem;
--h3: 1.5rem;
--h4: 1.125rem;
--h5: 0.75rem;
:root {
--h0: 4.5rem;
--h1: 3rem;
--h2: 2.25rem;
--h3: 1.5rem;
--h4: 1.125rem;
--h5: 0.75rem;
--lh: calc(4/3);
--mx: 32em;
--lh: calc(4 / 3);
--mx: 32em;
--m1: calc(2/3 * 1em);
--m2: calc(4/3 * 1em);
--m3: calc(8/3 * 1em);
--m4: calc(16/3 * 1em);
--x1: 0.5rem;
--x2: 1rem;
--x3: 2rem;
--x4: 4rem;
--x5: 8rem;
--x6: 16rem;
}
body {
font-size: var(--h4);
line-height: var(--lh);
margin: 2rem 0;
}
--m1: calc(2 / 3 * 1em);
--m2: calc(4 / 3 * 1em);
--m3: calc(8 / 3 * 1em);
--m4: calc(16 / 3 * 1em);
--x1: 0.5rem;
--x2: 1rem;
--x3: 2rem;
--x4: 4rem;
--x5: 8rem;
--x6: 16rem;
}
h1,
h2,
h3 {
margin-top: var(--m1);
margin-bottom: 0;
}
body {
font-size: var(--h4);
line-height: var(--lh);
margin: 2rem 0;
}
h4,
h5,
h6,
p,
dl,
ol,
ul,
blockquote {
margin-top: var(--m2);
margin-bottom: var(--m2);
}
h1,
h2,
h3 {
margin-top: var(--m1);
margin-bottom: 0;
}
h1 {
font-size: var(--h2);
}
h2,
h3 {
font-size: var(--h3);
}
h4 {
font-size: var(--h4);
}
h5,
h6 {
font-size: var(--h5);
}
h4,
h5,
h6,
p,
dl,
ol,
ul,
blockquote {
margin-top: var(--m2);
margin-bottom: var(--m2);
}
.h0 {
font-size: var(--h0);
}
.h1 {
font-size: var(--h1);
}
.h2 {
font-size: var(--h2);
}
.h3 {
font-size: var(--h3);
}
.h4 {
font-size: var(--h4);
}
.h5 {
font-size: var(--h5);
}
.h6 {
font-size: var(--h5);
}
h1 {
font-size: var(--h2);
}
h2,
h3 {
font-size: var(--h3);
}
h4 {
font-size: var(--h4);
}
h5,
h6 {
font-size: var(--h5);
}
@media screen and (min-width: 40em) {
.xh0 {
.h0 {
font-size: var(--h0);
}
.xh1 {
.h1 {
font-size: var(--h1);
}
.xh2 {
.h2 {
font-size: var(--h2);
}
.xh3 {
.h3 {
font-size: var(--h3);
}
.xh4 {
.h4 {
font-size: var(--h4);
}
.xh5 {
.h5 {
font-size: var(--h5);
}
.xh6 {
.h6 {
font-size: var(--h5);
}
}
.lh1 {
line-height: 1;
}
/* h0, h1, h3 */
.lh2 {
line-height: calc(7/6 * 1em);
}
/* For body copy */
.lh3 {
line-height: calc(16/9 * 1em);
}
@media screen and (min-width: 40em) {
.xh0 {
font-size: var(--h0);
}
.xh1 {
font-size: var(--h1);
}
.xh2 {
font-size: var(--h2);
}
.xh3 {
font-size: var(--h3);
}
.xh4 {
font-size: var(--h4);
}
.xh5 {
font-size: var(--h5);
}
.xh6 {
font-size: var(--h5);
}
}
.mt0 {
margin-top: 0;
}
.mb0 {
margin-bottom: 0;
}
.mt1 {
margin-top: var(--x1);
}
.mb1 {
margin-bottom: var(--x1);
}
.mt2 {
margin-top: var(--x2);
}
.mb2 {
margin-bottom: var(--x2);
}
.mt3 {
margin-top: var(--x3);
}
.mb3 {
margin-bottom: var(--x3);
}
.mt4 {
margin-top: var(--x4);
}
.mb4 {
margin-bottom: var(--x4);
}
.mt5 {
margin-top: var(--x5);
}
.mb5 {
margin-bottom: var(--x5);
}
.mt6 {
margin-top: var(--x6);
}
.mb6 {
margin-bottom: var(--x6);
}
.lh1 {
line-height: 1;
}
/* h0, h1, h3 */
.lh2 {
line-height: calc(7 / 6 * 1em);
}
/* For body copy */
.lh3 {
line-height: calc(16 / 9 * 1em);
}
.mx {
max-width: var(--mx);
}
.bold {
font-weight: bold;
}
`}</style>
.mt0 {
margin-top: 0;
}
.mb0 {
margin-bottom: 0;
}
.mt1 {
margin-top: var(--x1);
}
.mb1 {
margin-bottom: var(--x1);
}
.mt2 {
margin-top: var(--x2);
}
.mb2 {
margin-bottom: var(--x2);
}
.mt3 {
margin-top: var(--x3);
}
.mb3 {
margin-bottom: var(--x3);
}
.mt4 {
margin-top: var(--x4);
}
.mb4 {
margin-bottom: var(--x4);
}
.mt5 {
margin-top: var(--x5);
}
.mb5 {
margin-bottom: var(--x5);
}
.mt6 {
margin-top: var(--x6);
}
.mb6 {
margin-bottom: var(--x6);
}
.mx {
max-width: var(--mx);
}
.bold {
font-weight: bold;
}
`}
</style>
)

@ -1,22 +1,23 @@
/* global domtoimage */
const PORT = parseInt(process.env.PORT, 10) || 3000
const ARBITRARY_WAIT_TIME = 500
module.exports = browser => async (req, res) => {
let page = await browser.newPage()
let state = req.body.state
const page = await browser.newPage()
const { state } = req.body
if (!state) res.status(400).send()
try {
await page.goto(`http://localhost:${PORT}?state=${state}`)
await page.addScriptTag({ path: `./lib/customDomToImage.js` })
await page.addScriptTag({ path: './lib/customDomToImage.js' })
// wait for page to detect language
await delay(ARBITRARY_WAIT_TIME)
const targetElement = await page.$('#export-container')
let dataUrl = await page.evaluate(target => {
const dataUrl = await page.evaluate(target => {
const config = {
style: {
transform: 'scale(2)',

@ -30,7 +30,7 @@ const respondFail = (res, err) => {
}
console.error(`Error: ${err.message || JSON.stringify(err, null, 2)}`)
res.status(500).send()
return res.status(500).send()
}
module.exports = (req, res) => {
@ -38,7 +38,7 @@ module.exports = (req, res) => {
return res.status(400).send()
}
uploadImage(req.body.data)
return uploadImage(req.body.data)
.then(uploadTweet)
.then(extractImageUrl)
.then(respondSuccess.bind(null, res))

@ -30,7 +30,7 @@ async function image(state) {
return axios.post(`${DOMAIN}/image`, { state }).then(res => res.data.dataUrl)
}
const getGist = uid => {
function getGist(uid) {
return gistClient
.get(`/gists/${uid}`)
.then(res => res.data)
@ -41,10 +41,10 @@ const getGist = uid => {
// private
function openTwitterUrl(twitterUrl) {
const width = 575,
height = 400
const width = 575
const height = 400
const left = (window.outerWidth - width) / 2
const right = (window.outerHeight - height) / 2
const top = (window.outerHeight - height) / 2
const opts = `status=1,width=${width},height=${height},top=${top},left=${left}`
window.open(twitterUrl, 'twitter', opts)

@ -1,4 +1,4 @@
const colors = new Set([
export const colors = new Set([
'indian red',
'crimson',
'lightpink',
@ -595,6 +595,5 @@ const colors = new Set([
'whitesmoke'
])
export const validateColor = (str = '') => {
return /#\d{3,6}|rgba{0,1}\(.*?\)/gi.test(str) || colors.has(str.toLowerCase())
}
export const validateColor = (str = '') =>
/#\d{3,6}|rgba{0,1}\(.*?\)/gi.test(str) || colors.has(str.toLowerCase())

@ -73,22 +73,21 @@ const keysToQuery = keys =>
export const getQueryStringState = query => {
if (query.state) {
return deserializeState(query.state)
} else {
const state = mapper.map(mappings, query)
deserializeCode(state)
}
Object.keys(state).forEach(key => {
if (state[key] === '') state[key] = undefined
})
const state = mapper.map(mappings, query)
deserializeCode(state)
return state
}
Object.keys(state).forEach(key => {
if (state[key] === '') state[key] = undefined
})
return state
}
export const updateQueryString = state => {
// If react_perf is set as a queryParm, don't update
if (history.location.search.indexOf('react_perf') < 0) {
let mappedState = mapper.map(reverseMappings, state)
const mappedState = mapper.map(reverseMappings, state)
serializeCode(mappedState)
history.replace({

@ -1,4 +1,5 @@
import morph from 'morphmorph'
const KEY = 'CARBON_STATE'
const assign = morph.assign(KEY)
@ -6,7 +7,9 @@ const assign = morph.assign(KEY)
const parse = v => {
try {
return JSON.parse(v)
} catch (e) {}
} catch (e) {
// pass
}
}
const escapeHtml = s => {
@ -27,10 +30,9 @@ export const capitalizeFirstLetter = s => s.charAt(0).toUpperCase() + s.slice(1)
export const range = n => [...Array(n).keys()]
export const fileToDataURL = blob => {
return new Promise(res => {
export const fileToDataURL = blob =>
new Promise(res => {
const reader = new FileReader()
reader.onload = e => res(e.target.result)
reader.readAsDataURL(blob)
})
}

@ -1,4 +1,5 @@
import Document, { Head, Main, NextScript } from 'next/document'
export default class extends Document {
render() {
return (

@ -1,7 +1,4 @@
import Page from '../components/Page'
import Meta from '../components/Meta'
import Header from '../components/Header'
import Footer from '../components/Footer'
import { COLORS } from '../lib/constants'
export default () => (
@ -13,7 +10,10 @@ export default () => (
You know all of those code screenshots you see on Twitter? Although the code&apos;s
usually impressive, we saw room for improvement in the aesthetic department. Carbon is the
easiest way to create beautiful images of your source code. So what are you waiting for?
Go impress all of your followers with your newfound design prowess. <span>🎨</span>
Go impress all of your followers with your newfound design prowess.{' '}
<span role="img" aria-label="Palette">
🎨
</span>
</p>
</div>
<div className="mb4">
@ -23,12 +23,11 @@ export default () => (
<ul className="mt0 mb3">
<li>Drop a file into the editor</li>
<li>
Append a GitHub gist id to the url (<a
className="link"
href="/0db00e81d5416c339181e59481c74b59"
>
Append a GitHub gist id to the url (
<a className="link" href="/0db00e81d5416c339181e59481c74b59">
example
</a>)
</a>
)
</li>
<li>Paste your code directly</li>
</ul>
@ -56,24 +55,26 @@ export default () => (
</p>
</div>
</div>
<style jsx>{`
p,
li {
color: ${COLORS.GRAY};
}
<style jsx>
{`
p,
li {
color: ${COLORS.GRAY};
}
span {
color: #fff;
}
span {
color: #fff;
}
ul {
list-style-position: inside;
list-style-type: circle;
}
ul {
list-style-position: inside;
list-style-type: circle;
}
.about {
max-width: 632px;
}
`}</style>
.about {
max-width: 632px;
}
`}
</style>
</Page>
)

@ -14,7 +14,6 @@ import Settings from '../components/Settings'
import Toolbar from '../components/Toolbar'
import Overlay from '../components/Overlay'
import Carbon from '../components/Carbon'
import ArrowDown from '../components/svg/Arrowdown'
import api from '../lib/api'
import {
THEMES,
@ -23,14 +22,11 @@ import {
LANGUAGE_MIME_HASH,
LANGUAGE_MODE_HASH,
LANGUAGE_NAME_HASH,
DEFAULT_LANGUAGE,
DEFAULT_THEME,
DEFAULT_EXPORT_SIZE,
COLORS,
EXPORT_SIZES,
EXPORT_SIZES_HASH,
DEFAULT_CODE,
DEFAULT_BG_COLOR,
DEFAULT_SETTINGS
} from '../lib/constants'
import { getQueryStringState, updateQueryString, serializeState } from '../lib/routing'
@ -106,10 +102,10 @@ class Editor extends React.Component {
}
getCarbonImage({ format, type } = { format: 'png' }) {
//if safari, get image from api
// if safari, get image from api
if (
navigator.userAgent.indexOf('Safari') != -1 &&
navigator.userAgent.indexOf('Chrome') == -1 &&
navigator.userAgent.indexOf('Safari') !== -1 &&
navigator.userAgent.indexOf('Chrome') === -1 &&
format === 'png'
) {
const encodedState = serializeState(this.state)
@ -266,19 +262,21 @@ class Editor extends React.Component {
)}
</ReadFileDropContainer>
</div>
<style jsx>{`
#editor {
background: ${COLORS.BLACK};
border: 3px solid ${COLORS.SECONDARY};
border-radius: 8px;
padding: 16px;
}
<style jsx>
{`
#editor {
background: ${COLORS.BLACK};
border: 3px solid ${COLORS.SECONDARY};
border-radius: 8px;
padding: 16px;
}
.buttons {
display: flex;
margin-left: auto;
}
`}</style>
.buttons {
display: flex;
margin-left: auto;
}
`}
</style>
</Page>
)
}

@ -1,2 +1,3 @@
import Editor from './editor'
export default Editor

Loading…
Cancel
Save