Skip to content

Instantly share code, notes, and snippets.

@yalamber
Created May 3, 2019 09:45
Show Gist options
  • Save yalamber/d436025368069d692bf84449385cdaa7 to your computer and use it in GitHub Desktop.
Save yalamber/d436025368069d692bf84449385cdaa7 to your computer and use it in GitHub Desktop.
Slate Firebase storage image upload
import React from 'react';
import { getEventRange, getEventTransfer } from 'slate-react';
import { Circle } from 'rc-progress';
import imageExtensions from 'image-extensions';
import isUrl from 'is-url';
import styled from '@emotion/styled';
const Image = styled('img')`
display: block;
max-width: 100%;
max-height: 20em;
box-shadow: ${props => (props.selected ? '0 0 0 2px blue;' : (props.status === 'error'? '0 0 0 2px red;': 'none'))};
`;
const LoadingIndicator = ({children, progress}) => {
return (
<div style={{position: 'relative', display: 'inline-block'}}>
<Circle percent={progress} style={{maxWidth: '20%', position: 'absolute', zIndex:2, margin: 'auto auto', }} strokeWidth="10" strokeColor="#60A677" />
<div style={{opacity: 0.5}}>
{children}
</div>
</div>
)
}
export default function FirebaseImgUpload(options) {
const app = options.firebaseApp;
const storageRef = app.storage().ref();
const pluginHelpers = {
isImage(url) {
return imageExtensions.includes(pluginHelpers.getExtension(url));
},
getExtension(url) {
return new URL(url).pathname.split('.').pop();
},
insertImage(file) {
return (editor, src, target) => {
if (target) {
editor.select(target);
}
editor.insertBlock({
type: 'image',
data: { src, status: 'loading' },
});
editor.wrapBlock({
type: 'loadingIndicator',
data: {progress: 0}
});
//upload image
let ref = storageRef.child(`images/${file.name}`);
let uploadTask = ref.putString(src, 'data_url');
uploadTask.on('state_changed', function (snapshot) {
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
//update progress bar
editor.unwrapBlock('loadingIndicator').wrapBlock({
type: 'loadingIndicator',
data: {progress}
});
}, function (error) {
// Handle unsuccessful uploads
editor.setBlocks({ data: { src, status: 'error' }});
}, function () {
// Handle successful uploads on complete
// For instance, get the download URL: https://firebasestorage.googleapis.com/...
uploadTask.snapshot.ref.getDownloadURL().then(function (downloadURL) {
//update Image
console.log('Updated with uploaded image');
editor.unwrapBlock("loadingIndicator");
editor.setBlocks({ data: { src: downloadURL, status: 'loaded' }});
});
});
}
},
onDropOrPaste(event, editor, next) {
const target = getEventRange(event, editor)
if (!target && event.type === 'drop') return next()
const transfer = getEventTransfer(event)
const { type, text, files } = transfer
if (type === 'files') {
for (const file of files) {
const reader = new FileReader()
const [mime] = file.type.split('/')
if (mime !== 'image') continue
reader.addEventListener('load', () => {
editor.command(pluginHelpers.insertImage(file), reader.result, target)
})
reader.readAsDataURL(file)
}
return
}
if (type === 'text') {
if (!isUrl(text)) return next();
if (!pluginHelpers.isImage(text)) return next();
editor.command(pluginHelpers.insertImage, text, target);
return;
}
next();
},
renderNode(props, editor, next) {
const { attributes, node, isFocused } = props
switch (node.type) {
case 'image': {
const src = node.data.get('src');
const status = node.data.get('status');
return <Image src={src} selected={isFocused} {...attributes} status={status} />;
}
case 'loadingIndicator': {
const progress = node.data.get('progress');
return <LoadingIndicator {...props} progress={progress} />
}
default: {
return next();
}
}
}
}
// Return our "plugin" object, containing the `onKeyDown` handler.
return {
onDrop: pluginHelpers.onDropOrPaste,
onPaste: pluginHelpers.onDropOrPaste,
renderNode: pluginHelpers.renderNode
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment