mirror of https://github.com/sgoudham/carbon.git
Background image settings (#169)
* Implement drag-n-drop image for backgrounds - Closes #122 * In progress * Add background-size, background-position settings * Add ReactCrop * Remove old bg sizing sliders * Add resize observer * Fix typo * Disable select on sliders * onAspectRatioChange hook * Rename to backgroundColor * Fix state issues * Add backgroundMode toggle * Rename ColorPicker * Add upload-image margin * Minor font-size change * Fix buildmain
parent
77af47b59e
commit
cbc6824b83
@ -0,0 +1,208 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import enhanceWithClickOutside from 'react-click-outside'
|
||||||
|
import { SketchPicker } from 'react-color'
|
||||||
|
import WindowPointer from './WindowPointer'
|
||||||
|
import ImagePicker from './ImagePicker'
|
||||||
|
import { COLORS } from '../lib/constants'
|
||||||
|
import { parseRGBA, capitalizeFirstLetter } from '../lib/util'
|
||||||
|
|
||||||
|
class BackgroundSelect extends React.Component {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.state = { isVisible: false, selectedTab: 'color' }
|
||||||
|
this.toggle = this.toggle.bind(this)
|
||||||
|
this.selectTab = this.selectTab.bind(this)
|
||||||
|
this.handlePickColor = this.handlePickColor.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle() {
|
||||||
|
this.setState({ isVisible: !this.state.isVisible })
|
||||||
|
}
|
||||||
|
|
||||||
|
selectTab(name) {
|
||||||
|
if (this.props.config.backgroundMode !== name) {
|
||||||
|
this.props.onChange({ backgroundMode: name })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClickOutside() {
|
||||||
|
this.setState({ isVisible: false })
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePickColor(color) {
|
||||||
|
this.props.onChange({ backgroundColor: parseRGBA(color.rgb) })
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="bg-select-container">
|
||||||
|
<div className="bg-select-display">
|
||||||
|
<div className="bg-select-label">
|
||||||
|
<span>BG</span>
|
||||||
|
</div>
|
||||||
|
<div className="bg-color-container" onClick={this.toggle}>
|
||||||
|
<div className="bg-color-alpha" />
|
||||||
|
<div className="bg-color" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="bg-select-pickers" hidden={!this.state.isVisible}>
|
||||||
|
<WindowPointer fromLeft="15px" />
|
||||||
|
<div className="picker-tabs">
|
||||||
|
{['color', 'image'].map((tab, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className={`picker-tab ${this.props.config.backgroundMode === tab ? 'active' : ''}`}
|
||||||
|
onClick={this.selectTab.bind(null, tab)}
|
||||||
|
>
|
||||||
|
{capitalizeFirstLetter(tab)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="picker-tabs-contents">
|
||||||
|
<div style={this.props.config.backgroundMode === 'color' ? {} : { display: 'none' }}>
|
||||||
|
<SketchPicker
|
||||||
|
color={this.props.config.backgroundColor}
|
||||||
|
onChangeComplete={this.handlePickColor}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style={this.props.config.backgroundMode === 'image' ? {} : { display: 'none' }}>
|
||||||
|
<ImagePicker
|
||||||
|
onChange={this.props.onChange}
|
||||||
|
imageDataURL={this.props.config.backgroundImage}
|
||||||
|
aspectRatio={this.props.config.aspectRatio}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<style jsx>{`
|
||||||
|
.bg-select-container {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-select-display {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
width: 72px;
|
||||||
|
border: 0.5px 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: 0.5px solid ${COLORS.SECONDARY};
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-color-container {
|
||||||
|
position: relative;
|
||||||
|
width: 34px;
|
||||||
|
margin-bottom: 1px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 0px 2px 2px 0px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-color {
|
||||||
|
border-radius: 0px 2px 2px 0px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
left: 0px;
|
||||||
|
${this.props.config.backgroundMode === 'image'
|
||||||
|
? `background: url(${this.props.config.backgroundImage});
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;`
|
||||||
|
: `background: ${this.props.config.backgroundColor || config.backgroundColor};
|
||||||
|
background-size: auto;
|
||||||
|
background-repeat: repeat;`};
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-color-alpha {
|
||||||
|
border-radius: 0px 2px 2px 0px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
left: 0px;
|
||||||
|
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==)
|
||||||
|
left center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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: 0.5px 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO remove once base64 url issue fixed in react-color */
|
||||||
|
/* prettier-ignore */
|
||||||
|
.bg-select-pickers :global(.sketch-picker > div:nth-child(2) > div:nth-child(1) > div:nth-child(2) > div > div:nth-child(1) > div),
|
||||||
|
.bg-select-pickers :global(.sketch-picker > div:nth-child(2) > div:nth-child(2) > div:nth-child(1)) {
|
||||||
|
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==)
|
||||||
|
left center !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>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default enhanceWithClickOutside(BackgroundSelect)
|
@ -1,141 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import enhanceWithClickOutside from 'react-click-outside'
|
|
||||||
import { SketchPicker } from 'react-color'
|
|
||||||
import WindowPointer from './WindowPointer'
|
|
||||||
import { COLORS } from '../lib/constants'
|
|
||||||
import { parseRGBA } from '../lib/util'
|
|
||||||
|
|
||||||
class ColorPicker extends React.Component {
|
|
||||||
constructor() {
|
|
||||||
super()
|
|
||||||
this.state = { isVisible: false }
|
|
||||||
this.toggle = this.toggle.bind(this)
|
|
||||||
this.handlePickColor = this.handlePickColor.bind(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
toggle() {
|
|
||||||
this.setState({ isVisible: !this.state.isVisible })
|
|
||||||
}
|
|
||||||
|
|
||||||
handleClickOutside() {
|
|
||||||
this.setState({ isVisible: false })
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePickColor(color) {
|
|
||||||
this.props.onChange(parseRGBA(color.rgb))
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="colorpicker-container">
|
|
||||||
<div className="colorpicker-display">
|
|
||||||
<div className="colorpicker-label">
|
|
||||||
<span>BG</span>
|
|
||||||
</div>
|
|
||||||
<div className="bg-color-container" onClick={this.toggle}>
|
|
||||||
<div className="bg-color-alpha" />
|
|
||||||
<div className="bg-color" style={{ background: this.props.bg }} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="colorpicker-picker" hidden={!this.state.isVisible}>
|
|
||||||
<WindowPointer fromLeft="15px" />
|
|
||||||
<SketchPicker color={this.props.bg} onChangeComplete={this.handlePickColor} />
|
|
||||||
</div>
|
|
||||||
<style jsx>{`
|
|
||||||
.colorpicker-container {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.colorpicker-display {
|
|
||||||
display: flex;
|
|
||||||
height: 100%;
|
|
||||||
width: 72px;
|
|
||||||
border: 0.5px solid ${COLORS.SECONDARY};
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.colorpicker-label {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
user-select: none;
|
|
||||||
cursor: default;
|
|
||||||
height: 100%;
|
|
||||||
padding: 0 8px;
|
|
||||||
border-right: 0.5px solid ${COLORS.SECONDARY};
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-color-container {
|
|
||||||
position: relative;
|
|
||||||
width: 34px;
|
|
||||||
margin-bottom: 1px;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 0px 2px 2px 0px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-color {
|
|
||||||
border-radius: 0px 2px 2px 0px;
|
|
||||||
position: absolute;
|
|
||||||
top: 0px;
|
|
||||||
right: 0px;
|
|
||||||
bottom: 0px;
|
|
||||||
left: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-color-alpha {
|
|
||||||
border-radius: 0px 2px 2px 0px;
|
|
||||||
position: absolute;
|
|
||||||
top: 0px;
|
|
||||||
right: 0px;
|
|
||||||
bottom: 0px;
|
|
||||||
left: 0px;
|
|
||||||
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==)
|
|
||||||
left center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.colorpicker-picker {
|
|
||||||
position: absolute;
|
|
||||||
margin-left: 36px;
|
|
||||||
margin-top: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* react-color overrides */
|
|
||||||
.colorpicker-picker :global(.sketch-picker) {
|
|
||||||
border: 0.5px solid ${COLORS.SECONDARY} !important;
|
|
||||||
border-radius: 3px !important;
|
|
||||||
background: #1a1a1a !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.colorpicker-picker > :global(.sketch-picker > div:nth-child(3) > div > div > span) {
|
|
||||||
color: ${COLORS.SECONDARY} !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO remove once base64 url issue fixed in react-color */
|
|
||||||
/* prettier-ignore */
|
|
||||||
.colorpicker-picker > :global(.sketch-picker > div:nth-child(2) > div:nth-child(1) > div:nth-child(2) > div > div:nth-child(1) > div),
|
|
||||||
.colorpicker-picker > :global(.sketch-picker > div:nth-child(2) > div:nth-child(2) > div:nth-child(1)) {
|
|
||||||
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==)
|
|
||||||
left center !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.colorpicker-picker > :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 */
|
|
||||||
.colorpicker-picker :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>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default enhanceWithClickOutside(ColorPicker)
|
|
@ -0,0 +1,188 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import ReactCrop, { makeAspectCrop } from 'react-image-crop'
|
||||||
|
import Slider from './Slider'
|
||||||
|
import { COLORS } from '../lib/constants'
|
||||||
|
|
||||||
|
const getCroppedImg = (imageDataURL, pixelCrop) => {
|
||||||
|
const canvas = document.createElement('canvas')
|
||||||
|
canvas.width = pixelCrop.width
|
||||||
|
canvas.height = pixelCrop.height
|
||||||
|
const ctx = canvas.getContext('2d')
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const image = new Image()
|
||||||
|
image.src = imageDataURL
|
||||||
|
image.onload = () => {
|
||||||
|
ctx.drawImage(
|
||||||
|
image,
|
||||||
|
pixelCrop.x,
|
||||||
|
pixelCrop.y,
|
||||||
|
pixelCrop.width,
|
||||||
|
pixelCrop.height,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
pixelCrop.width,
|
||||||
|
pixelCrop.height
|
||||||
|
)
|
||||||
|
|
||||||
|
resolve(canvas.toDataURL('image/jpeg'))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const INITIAL_STATE = { crop: null, imageAspectRatio: null, pixelCrop: null }
|
||||||
|
|
||||||
|
export default class extends React.Component {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.state = INITIAL_STATE
|
||||||
|
this.selectImage = this.selectImage.bind(this)
|
||||||
|
this.removeImage = this.removeImage.bind(this)
|
||||||
|
this.onImageLoaded = this.onImageLoaded.bind(this)
|
||||||
|
this.onCropChange = this.onCropChange.bind(this)
|
||||||
|
this.onDragEnd = this.onDragEnd.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
if (this.state.crop && this.props.aspectRatio != nextProps.aspectRatio) {
|
||||||
|
// update crop for editor container aspect-ratio change
|
||||||
|
this.setState({
|
||||||
|
crop: makeAspectCrop(
|
||||||
|
{
|
||||||
|
...this.state.crop,
|
||||||
|
aspect: nextProps.aspectRatio
|
||||||
|
},
|
||||||
|
this.state.imageAspectRatio
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectImage(e) {
|
||||||
|
const file = e.target.files[0]
|
||||||
|
|
||||||
|
const reader = new FileReader()
|
||||||
|
reader.onload = e =>
|
||||||
|
this.props.onChange({ backgroundImage: e.target.result, backgroundImageSelection: null })
|
||||||
|
reader.readAsDataURL(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
removeImage() {
|
||||||
|
this.setState(INITIAL_STATE, () => {
|
||||||
|
this.props.onChange({
|
||||||
|
backgroundMode: 'color',
|
||||||
|
backgroundImage: null,
|
||||||
|
backgroundImageSelection: null
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onImageLoaded(image) {
|
||||||
|
const imageAspectRatio = image.width / image.height
|
||||||
|
const initialCrop = {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 100,
|
||||||
|
aspect: this.props.aspectRatio
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
imageAspectRatio,
|
||||||
|
crop: makeAspectCrop(initialCrop, imageAspectRatio)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onCropChange(crop, pixelCrop) {
|
||||||
|
this.setState({
|
||||||
|
crop: { ...crop, aspect: this.props.aspectRatio },
|
||||||
|
pixelCrop
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async onDragEnd() {
|
||||||
|
if (this.state.pixelCrop) {
|
||||||
|
const croppedImg = await getCroppedImg(this.props.imageDataURL, this.state.pixelCrop)
|
||||||
|
this.props.onChange({ backgroundImageSelection: croppedImg })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let content = (
|
||||||
|
<div className="upload-image">
|
||||||
|
<span>Click the button below to upload a background image</span>
|
||||||
|
<input type="file" accept="image/x-png,image/jpeg,image/jpg" onChange={this.selectImage} />
|
||||||
|
<style jsx>{`
|
||||||
|
.upload-image {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
if (this.props.imageDataURL) {
|
||||||
|
content = (
|
||||||
|
<div className="settings-container">
|
||||||
|
<div className="image-container">
|
||||||
|
<div className="label">
|
||||||
|
<span>Background image</span>
|
||||||
|
<a href="#" onClick={this.removeImage}>
|
||||||
|
×
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<ReactCrop
|
||||||
|
src={this.props.imageDataURL}
|
||||||
|
onImageLoaded={this.onImageLoaded}
|
||||||
|
crop={this.state.crop}
|
||||||
|
onChange={this.onCropChange}
|
||||||
|
onDragEnd={this.onDragEnd}
|
||||||
|
minHeight={10}
|
||||||
|
minWidth={10}
|
||||||
|
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>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="image-picker-container">{content}</div>
|
||||||
|
<style jsx>{`
|
||||||
|
.image-picker-container {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,163 @@
|
|||||||
|
.ReactCrop {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
cursor: crosshair;
|
||||||
|
overflow: hidden;
|
||||||
|
max-width: 100%;
|
||||||
|
background-color: #000; }
|
||||||
|
.ReactCrop:focus {
|
||||||
|
outline: none; }
|
||||||
|
.ReactCrop--disabled {
|
||||||
|
cursor: inherit; }
|
||||||
|
.ReactCrop__image {
|
||||||
|
display: block;
|
||||||
|
max-width: 100%; }
|
||||||
|
.ReactCrop--crop-invisible .ReactCrop__image {
|
||||||
|
opacity: 0.5; }
|
||||||
|
.ReactCrop__crop-selection {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
transform: translate3d(0, 0, 0);
|
||||||
|
box-sizing: border-box;
|
||||||
|
cursor: move;
|
||||||
|
box-shadow: 0 0 0 9999em rgba(0, 0, 0, 0.5);
|
||||||
|
border: 1px solid;
|
||||||
|
border-image-source: url("data:image/gif;base64,R0lGODlhCgAKAJECAAAAAP///////wAAACH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OEI5RDc5MTFDNkE2MTFFM0JCMDZEODI2QTI4MzJBOTIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OEI5RDc5MTBDNkE2MTFFM0JCMDZEODI2QTI4MzJBOTIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuZGlkOjAyODAxMTc0MDcyMDY4MTE4MDgzQzNDMjA5MzREQ0ZDIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAyODAxMTc0MDcyMDY4MTE4MDgzQzNDMjA5MzREQ0ZDIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Af/+/fz7+vn49/b19PPy8fDv7u3s6+rp6Ofm5eTj4uHg397d3Nva2djX1tXU09LR0M/OzczLysnIx8bFxMPCwcC/vr28u7q5uLe2tbSzsrGwr66trKuqqainpqWko6KhoJ+enZybmpmYl5aVlJOSkZCPjo2Mi4qJiIeGhYSDgoGAf359fHt6eXh3dnV0c3JxcG9ubWxramloZ2ZlZGNiYWBfXl1cW1pZWFdWVVRTUlFQT05NTEtKSUhHRkVEQ0JBQD8+PTw7Ojk4NzY1NDMyMTAvLi0sKyopKCcmJSQjIiEgHx4dHBsaGRgXFhUUExIREA8ODQwLCgkIBwYFBAMCAQAAIfkEBQoAAgAsAAAAAAoACgAAAhWEERkn7W3ei7KlagMWF/dKgYeyGAUAIfkEBQoAAgAsAAAAAAoACgAAAg+UYwLJ7RnQm7QmsCyVKhUAIfkEBQoAAgAsAAAAAAoACgAAAhCUYgLJHdiinNSAVfOEKoUCACH5BAUKAAIALAAAAAAKAAoAAAIRVISAdusPo3RAzYtjaMIaUQAAIfkEBQoAAgAsAAAAAAoACgAAAg+MDiem7Q8bSLFaG5il6xQAIfkEBQoAAgAsAAAAAAoACgAAAg+UYRLJ7QnQm7SmsCyVKhUAIfkEBQoAAgAsAAAAAAoACgAAAhCUYBLJDdiinNSEVfOEKoECACH5BAUKAAIALAAAAAAKAAoAAAIRFISBdusPo3RBzYsjaMIaUQAAOw==");
|
||||||
|
border-image-slice: 1;
|
||||||
|
border-image-repeat: repeat; }
|
||||||
|
.ReactCrop--disabled .ReactCrop__crop-selection {
|
||||||
|
cursor: inherit; }
|
||||||
|
.ReactCrop__drag-handle {
|
||||||
|
position: absolute;
|
||||||
|
width: 9px;
|
||||||
|
height: 9px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.7);
|
||||||
|
box-sizing: border-box;
|
||||||
|
outline: 1px solid transparent; }
|
||||||
|
.ReactCrop .ord-nw {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
margin-top: -5px;
|
||||||
|
margin-left: -5px;
|
||||||
|
cursor: nw-resize; }
|
||||||
|
.ReactCrop .ord-n {
|
||||||
|
top: 0;
|
||||||
|
left: 50%;
|
||||||
|
margin-top: -5px;
|
||||||
|
margin-left: -5px;
|
||||||
|
cursor: n-resize; }
|
||||||
|
.ReactCrop .ord-ne {
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
margin-top: -5px;
|
||||||
|
margin-right: -5px;
|
||||||
|
cursor: ne-resize; }
|
||||||
|
.ReactCrop .ord-e {
|
||||||
|
top: 50%;
|
||||||
|
right: 0;
|
||||||
|
margin-top: -5px;
|
||||||
|
margin-right: -5px;
|
||||||
|
cursor: e-resize; }
|
||||||
|
.ReactCrop .ord-se {
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
margin-bottom: -5px;
|
||||||
|
margin-right: -5px;
|
||||||
|
cursor: se-resize; }
|
||||||
|
.ReactCrop .ord-s {
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
margin-bottom: -5px;
|
||||||
|
margin-left: -5px;
|
||||||
|
cursor: s-resize; }
|
||||||
|
.ReactCrop .ord-sw {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
margin-bottom: -5px;
|
||||||
|
margin-left: -5px;
|
||||||
|
cursor: sw-resize; }
|
||||||
|
.ReactCrop .ord-w {
|
||||||
|
top: 50%;
|
||||||
|
left: 0;
|
||||||
|
margin-top: -5px;
|
||||||
|
margin-left: -5px;
|
||||||
|
cursor: w-resize; }
|
||||||
|
.ReactCrop__disabled .ReactCrop__drag-handle {
|
||||||
|
cursor: inherit; }
|
||||||
|
.ReactCrop__drag-bar {
|
||||||
|
position: absolute; }
|
||||||
|
.ReactCrop__drag-bar.ord-n {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 6px;
|
||||||
|
margin-top: -3px; }
|
||||||
|
.ReactCrop__drag-bar.ord-e {
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 6px;
|
||||||
|
height: 100%;
|
||||||
|
margin-right: -3px; }
|
||||||
|
.ReactCrop__drag-bar.ord-s {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 6px;
|
||||||
|
margin-bottom: -3px; }
|
||||||
|
.ReactCrop__drag-bar.ord-w {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 6px;
|
||||||
|
height: 100%;
|
||||||
|
margin-left: -3px; }
|
||||||
|
.ReactCrop--new-crop .ReactCrop__drag-bar,
|
||||||
|
.ReactCrop--new-crop .ReactCrop__drag-handle,
|
||||||
|
.ReactCrop--fixed-aspect .ReactCrop__drag-bar {
|
||||||
|
display: none; }
|
||||||
|
.ReactCrop--fixed-aspect .ReactCrop__drag-handle.ord-n,
|
||||||
|
.ReactCrop--fixed-aspect .ReactCrop__drag-handle.ord-e,
|
||||||
|
.ReactCrop--fixed-aspect .ReactCrop__drag-handle.ord-s,
|
||||||
|
.ReactCrop--fixed-aspect .ReactCrop__drag-handle.ord-w {
|
||||||
|
display: none; }
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.ReactCrop__drag-handle {
|
||||||
|
width: 17px;
|
||||||
|
height: 17px; }
|
||||||
|
.ReactCrop .ord-nw {
|
||||||
|
margin-top: -9px;
|
||||||
|
margin-left: -9px; }
|
||||||
|
.ReactCrop .ord-n {
|
||||||
|
margin-top: -9px;
|
||||||
|
margin-left: -9px; }
|
||||||
|
.ReactCrop .ord-ne {
|
||||||
|
margin-top: -9px;
|
||||||
|
margin-right: -9px; }
|
||||||
|
.ReactCrop .ord-e {
|
||||||
|
margin-top: -9px;
|
||||||
|
margin-right: -9px; }
|
||||||
|
.ReactCrop .ord-se {
|
||||||
|
margin-bottom: -9px;
|
||||||
|
margin-right: -9px; }
|
||||||
|
.ReactCrop .ord-s {
|
||||||
|
margin-bottom: -9px;
|
||||||
|
margin-left: -9px; }
|
||||||
|
.ReactCrop .ord-sw {
|
||||||
|
margin-bottom: -9px;
|
||||||
|
margin-left: -9px; }
|
||||||
|
.ReactCrop .ord-w {
|
||||||
|
margin-top: -9px;
|
||||||
|
margin-left: -9px; }
|
||||||
|
.ReactCrop__drag-bar.ord-n {
|
||||||
|
height: 14px;
|
||||||
|
margin-top: -7px; }
|
||||||
|
.ReactCrop__drag-bar.ord-e {
|
||||||
|
width: 14px;
|
||||||
|
margin-right: -7px; }
|
||||||
|
.ReactCrop__drag-bar.ord-s {
|
||||||
|
height: 14px;
|
||||||
|
margin-bottom: -7px; }
|
||||||
|
.ReactCrop__drag-bar.ord-w {
|
||||||
|
width: 14px;
|
||||||
|
margin-left: -7px; } }
|
Loading…
Reference in New Issue