WIP: Add initial meme generator! #748
3 changed files with 43 additions and 21 deletions
|
@ -4,6 +4,7 @@
|
||||||
// be a flex container for children
|
// be a flex container for children
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropzone {
|
.dropzone {
|
||||||
|
@ -12,6 +13,7 @@
|
||||||
flex: 1 0 auto;
|
flex: 1 0 auto;
|
||||||
// be a flex container for children
|
// be a flex container for children
|
||||||
display: flex;
|
display: flex;
|
||||||
|
padding: 1em;
|
||||||
-webkit-flex-direction: column;
|
-webkit-flex-direction: column;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -52,13 +54,17 @@
|
||||||
|
|
||||||
.dropzone-preview-image {
|
.dropzone-preview-image {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 1em;
|
width: 100%;
|
||||||
width: calc(100% - 2em);
|
}
|
||||||
|
|
||||||
|
.dropzone-preview-memeify {
|
||||||
|
margin-top: 3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropzone-memeify-button {
|
.dropzone-memeify-button {
|
||||||
background: #333;
|
background: $primary-color;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
font-size: .8em;
|
font-size: .8em;
|
||||||
padding: 3px 6px;
|
padding: 3px 6px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -67,6 +73,14 @@
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropzone-memeify-toolbar {
|
||||||
|
/* TODO: Cleanup `!important` */
|
||||||
|
background: $primary-color !important;
|
||||||
|
left: -1em !important;
|
||||||
|
right: -1em !important;
|
||||||
|
top: -4em !important;
|
||||||
|
}
|
||||||
|
|
||||||
.dropzone-instructions-display__chooser-label {
|
.dropzone-instructions-display__chooser-label {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,10 @@ import RichDraggable from './RichDraggable';
|
||||||
import EditableFontface, { PRESETS as FontPresets } from './EditableFontface';
|
import EditableFontface, { PRESETS as FontPresets } from './EditableFontface';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
faEdit,
|
|
||||||
faFont,
|
faFont,
|
||||||
|
faMinusCircle,
|
||||||
|
faPlusCircle,
|
||||||
} from '@fortawesome/free-solid-svg-icons';
|
} from '@fortawesome/free-solid-svg-icons';
|
||||||
library.add(faEdit);
|
|
||||||
library.add(faFont);
|
|
||||||
|
|
||||||
const getRasterizedCanvas = (contents, width, height) => {
|
const getRasterizedCanvas = (contents, width, height) => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
|
@ -30,10 +29,10 @@ const getRasterizedCanvas = (contents, width, height) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to match font kerning with the DOM.
|
// Attempt to match font kerning with the DOM.
|
||||||
contents = '<style>svg{font-kerning:normal}</style>' + contents;
|
const kerningAndPadding = '<style>svg{font-kerning:normal}body{padding:0;margin:0}</style>';
|
||||||
const svgContents = `<svg xmlns="http://www.w3.org/2000/svg" width="${width * 2}" height="${height * 2}">
|
const svgContents = `<svg xmlns="http://www.w3.org/2000/svg" width="${width * 2}" height="${height * 2}">
|
||||||
<foreignObject x="0" y="0" width="${width * 2}" height="${height * 2}" externalResourcesRequired="true">
|
<foreignObject x="0" y="0" width="${width * 2}" height="${height * 2}" externalResourcesRequired="true">
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml"><body>${contents}</body></html>
|
<html xmlns="http://www.w3.org/1999/xhtml"><head>${kerningAndPadding}</head><body>${contents}</body></html>
|
||||||
</foreignObject></svg>`;
|
</foreignObject></svg>`;
|
||||||
|
|
||||||
const pixelRatio = 2;
|
const pixelRatio = 2;
|
||||||
|
@ -153,13 +152,22 @@ export default class Creatify extends Component {
|
||||||
state,
|
state,
|
||||||
} = this;
|
} = this;
|
||||||
|
|
||||||
|
// TODO: Abstract into separate package & use CSS Modules.
|
||||||
|
const spacerCss = { width: '.3em' };
|
||||||
return (
|
return (
|
||||||
<div style={{ position: 'relative', flex: props.flex === true ? 1 : props.flex, display: props.flex ? 'flex' : 'block' }}>
|
<div style={{ position: 'relative', flex: props.flex === true ? 1 : props.flex, display: props.flex ? 'flex' : 'block' }}>
|
||||||
<div style={{ position: 'absolute', top: 0, left: 0, right: 0, background: '#333', zIndex: 2 }}>
|
<div className={props.toolbarClassName} style={{ alignItems: 'center', color: '#fff', display: 'flex', padding: '.3em', position: 'absolute', top: 0, left: 0, right: 0, background: '#333', flexDirection: 'row', zIndex: 2 }}>
|
||||||
{/*
|
<FontAwesomeIcon icon={faPlusCircle} size="2x" />
|
||||||
<button onClick={() => this.renderContents()}>Rasterize</button>
|
<div style={spacerCss} />
|
||||||
<Select isSearchable={false} options={state.fontOptions} onChange={(option) => this.setFont(option.fontName)} />
|
<FontAwesomeIcon icon={faMinusCircle} size="2x" />
|
||||||
*/}
|
<div style={spacerCss} />
|
||||||
|
<div style={{ flex: 1 }}>
|
||||||
|
<Select style={{ flex: 1 }} isSearchable={false} options={state.fontOptions} onChange={(option) => this.setFont(option.fontName)} />
|
||||||
|
</div>
|
||||||
|
<div style={spacerCss} />
|
||||||
|
<div onClick={() => this.renderContents()} style={{ alignItems: 'center', alignSelf: 'stretch', color: '#fff', border: '1px solid #fff', display: 'flex', padding: '.4em' }}>
|
||||||
|
<span>Finish</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div ref={me.contents} style={{ fontSize: '22px', overflow: 'hidden', transform: 'translateZ(0)', flex: 1 }}>
|
<div ref={me.contents} style={{ fontSize: '22px', overflow: 'hidden', transform: 'translateZ(0)', flex: 1 }}>
|
||||||
<RichDraggable bounds={state.bounds}>
|
<RichDraggable bounds={state.bounds}>
|
||||||
|
|
|
@ -154,7 +154,7 @@ class Dropzone extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
const memeifyContent = memeify && file && filePreview ? (
|
const memeifyContent = memeify && file && filePreview ? (
|
||||||
<Creatify flex>
|
<Creatify flex toolbarClassName={'dropzone-memeify-toolbar'}>
|
||||||
<div style={{ background: '#fff', flex: 1 }}>
|
<div style={{ background: '#fff', flex: 1 }}>
|
||||||
<img style={{ width: '100%' }} src={filePreview} />
|
<img style={{ width: '100%' }} src={filePreview} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -168,7 +168,12 @@ class Dropzone extends React.Component {
|
||||||
{isUpdate && fileExt === 'mp4' ? (
|
{isUpdate && fileExt === 'mp4' ? (
|
||||||
<p>Video updates are currently disabled. This feature will be available soon. You can edit metadata.</p>
|
<p>Video updates are currently disabled. This feature will be available soon. You can edit metadata.</p>
|
||||||
) : (
|
) : (
|
||||||
<div className='dropzone-wrapper'>
|
<div className={'dropzone-wrapper'}>
|
||||||
|
{ hasContent && !memeify && (
|
||||||
|
<div className={'dropzone-memeify-button'} onClick={() => this.setState({ memeify: !memeify })}>
|
||||||
|
<FontAwesomeIcon icon={faEdit} /> Memeify
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<form>
|
<form>
|
||||||
<input
|
<input
|
||||||
className='input-file'
|
className='input-file'
|
||||||
|
@ -182,7 +187,7 @@ class Dropzone extends React.Component {
|
||||||
</form>
|
</form>
|
||||||
<div className={dropZoneClassName} {...dropZoneHooks}>
|
<div className={dropZoneClassName} {...dropZoneHooks}>
|
||||||
{hasContent ? (
|
{hasContent ? (
|
||||||
<div className={'dropzone-preview-wrapper'}>
|
<div className={'dropzone-preview-wrapper' + (memeifyContent ? ' dropzone-preview-memeify' : '')}>
|
||||||
<DropzonePreviewImage {...dropZonePreviewProps} />
|
<DropzonePreviewImage {...dropZonePreviewProps} />
|
||||||
<div className={'dropzone-preview-overlay'}>
|
<div className={'dropzone-preview-overlay'}>
|
||||||
{ dragOver ? <DropzoneDropItDisplay /> : null }
|
{ dragOver ? <DropzoneDropItDisplay /> : null }
|
||||||
|
@ -192,11 +197,6 @@ class Dropzone extends React.Component {
|
||||||
message={fileExt === 'mp4' ? 'Drag & drop new thumbnail' : null}
|
message={fileExt === 'mp4' ? 'Drag & drop new thumbnail' : null}
|
||||||
/>
|
/>
|
||||||
) : null }
|
) : null }
|
||||||
{ !memeify && (
|
|
||||||
<div className={'dropzone-memeify-button'} onClick={() => this.setState({ memeify: !memeify })}>
|
|
||||||
<FontAwesomeIcon icon={faEdit} /> Memeify
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{memeifyContent}
|
{memeifyContent}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue