Replace file uploads with dropzone
This commit is contained in:
parent
b44886f0f5
commit
cc1c193fb1
@ -10,7 +10,7 @@ import { EventEmitter } from 'events';
|
|||||||
EventEmitter.defaultMaxListeners = 1000; // https://github.com/pouchdb/pouchdb/issues/6123
|
EventEmitter.defaultMaxListeners = 1000; // https://github.com/pouchdb/pouchdb/issues/6123
|
||||||
|
|
||||||
// Attach our root view to the DOM
|
// Attach our root view to the DOM
|
||||||
createView(GalleryView, {}).mount(document.querySelector('#app'));
|
createView(GalleryView, {}).mount(document.body);
|
||||||
|
|
||||||
// Start the router
|
// Start the router
|
||||||
router.start('home');
|
router.start('home');
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
<link rel="stylesheet" href="/assets/app.css">
|
<link rel="stylesheet" href="/assets/app.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id='app'></div>
|
|
||||||
<script src="/assets/app.bundle.js"></script>
|
<script src="/assets/app.bundle.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
75
packages/gallery/src/interface/dropzone.js
Normal file
75
packages/gallery/src/interface/dropzone.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import { prop, computed } from 'frptools';
|
||||||
|
import { injectStyle, el } from '../services/style';
|
||||||
|
|
||||||
|
const CSS_DROPZONE = {
|
||||||
|
width: '200px',
|
||||||
|
height: '200px',
|
||||||
|
border: '2px #666 dashed',
|
||||||
|
borderRadius: '5px'
|
||||||
|
};
|
||||||
|
|
||||||
|
const CSS_DROPZONE_ACTIVE = {
|
||||||
|
borderStyle: 'solid',
|
||||||
|
backgroundColor: '#eee'
|
||||||
|
};
|
||||||
|
|
||||||
|
export function Dropzone(vm, model) {
|
||||||
|
const { ondrop, ondragenter, ondragleave } = model;
|
||||||
|
|
||||||
|
const enterCounter = prop(0);
|
||||||
|
enterCounter.subscribe(() => vm.redraw());
|
||||||
|
|
||||||
|
function onDragOver(evt) {
|
||||||
|
// allows the browser to accept drops.
|
||||||
|
evt.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDragEnter() {
|
||||||
|
enterCounter(enterCounter() + 1);
|
||||||
|
|
||||||
|
if (ondragenter) {
|
||||||
|
ondragenter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDragLeave() {
|
||||||
|
enterCounter(enterCounter() - 1);
|
||||||
|
|
||||||
|
if (ondragleave) {
|
||||||
|
ondragleave();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDrop(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
enterCounter(0);
|
||||||
|
|
||||||
|
if (ondrop) {
|
||||||
|
ondrop(evt.dataTransfer.files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function render(vm, model) {
|
||||||
|
const { className, activeClassName, class: _class, children } = model;
|
||||||
|
|
||||||
|
const class_ = Object.assign(
|
||||||
|
{
|
||||||
|
[className || injectStyle(CSS_DROPZONE)]: true,
|
||||||
|
[activeClassName || injectStyle(CSS_DROPZONE_ACTIVE)]: enterCounter() > 0
|
||||||
|
},
|
||||||
|
_class || {}
|
||||||
|
);
|
||||||
|
|
||||||
|
return el(
|
||||||
|
'div',
|
||||||
|
{
|
||||||
|
class: class_,
|
||||||
|
ondragenter: onDragEnter,
|
||||||
|
ondragover: onDragOver,
|
||||||
|
ondragleave: onDragLeave,
|
||||||
|
ondrop: onDrop
|
||||||
|
},
|
||||||
|
...children
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -3,8 +3,9 @@ import { ImageType } from '../data/image.js';
|
|||||||
import { AlbumType } from '../data/album.js';
|
import { AlbumType } from '../data/album.js';
|
||||||
import { ThumbnailView } from './thumbnail.js';
|
import { ThumbnailView } from './thumbnail.js';
|
||||||
import { AlbumView } from './album.js';
|
import { AlbumView } from './album.js';
|
||||||
|
import { Dropzone } from './dropzone.js';
|
||||||
import { router, routeChanged } from '../services/router.js';
|
import { router, routeChanged } from '../services/router.js';
|
||||||
import { styled, el } from '../services/style.js';
|
import { injectStyle, styled, el } from '../services/style.js';
|
||||||
|
|
||||||
export function GalleryView(vm, model) {
|
export function GalleryView(vm, model) {
|
||||||
const { db } = model;
|
const { db } = model;
|
||||||
@ -28,8 +29,8 @@ export function GalleryView(vm, model) {
|
|||||||
let laCleanup = null;
|
let laCleanup = null;
|
||||||
let title = '';
|
let title = '';
|
||||||
|
|
||||||
function uploadImages(evt) {
|
function uploadImages(files) {
|
||||||
Array.from(evt.currentTarget.files).forEach(ImageType.upload);
|
Array.from(files).forEach(ImageType.upload);
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteImage(i) {
|
function deleteImage(i) {
|
||||||
@ -64,41 +65,60 @@ export function GalleryView(vm, model) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return function(vm, model, key, opts) {
|
function renderDropzone() {
|
||||||
return el('.gallery', [
|
return [
|
||||||
|
el('a', { href: router.href('images') }, 'Images'),
|
||||||
|
el('a', { href: router.href('albums') }, 'Albums'),
|
||||||
|
el('h1', title),
|
||||||
|
...(title === 'Images'
|
||||||
|
? data().map(i => {
|
||||||
|
return vw(
|
||||||
|
ThumbnailView,
|
||||||
|
{
|
||||||
|
doc: i,
|
||||||
|
showTags: true,
|
||||||
|
remove: deleteImage
|
||||||
|
},
|
||||||
|
i._hash()
|
||||||
|
);
|
||||||
|
})
|
||||||
|
: data().map(a => {
|
||||||
|
return vw(AlbumView, a, a._hash());
|
||||||
|
}))
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return function render(vm, params, key, opts) {
|
||||||
|
if (!data || !data.ready()) {
|
||||||
|
return el('h1', 'Loading...');
|
||||||
|
}
|
||||||
|
|
||||||
|
return el(
|
||||||
|
'.gallery',
|
||||||
|
{ class: slate },
|
||||||
header([
|
header([
|
||||||
el('div', { css: { fontSize: '20pt' } }, 'Gallery'),
|
el('div', { css: { fontSize: '20pt' } }, 'Gallery'),
|
||||||
el('button', { onclick: addAlbum }, 'Add Album'),
|
headerRight(
|
||||||
el('input#fInput', {
|
{
|
||||||
type: 'file',
|
css: { visibility: /* selectMode */ true ? 'visible' : 'hidden' }
|
||||||
multiple: true,
|
},
|
||||||
accept: 'image/jpeg',
|
[el('button', { onclick: addAlbum }, 'Add Album')]
|
||||||
onchange: uploadImages
|
)
|
||||||
})
|
|
||||||
]),
|
]),
|
||||||
...(!data || !data.ready()
|
vw(
|
||||||
? [el('h1', 'Loading...')]
|
Dropzone,
|
||||||
: [
|
{
|
||||||
el('a', { href: router.href('images') }, 'Images'),
|
className: slate,
|
||||||
el('a', { href: router.href('albums') }, 'Albums'),
|
activeClassName: 'dropHover',
|
||||||
el('h1', title),
|
ondrop: uploadImages,
|
||||||
...(title === 'Images'
|
type: 'file',
|
||||||
? data().map(i => {
|
multiple: true, // FIXME - these don't carry through to the input tag
|
||||||
return vw(
|
accept: 'image/jpeg',
|
||||||
ThumbnailView,
|
children: renderDropzone()
|
||||||
{
|
},
|
||||||
doc: i,
|
'dz'
|
||||||
showTags: true,
|
)
|
||||||
remove: deleteImage
|
);
|
||||||
},
|
|
||||||
i._id + i._rev
|
|
||||||
);
|
|
||||||
})
|
|
||||||
: data().map(a => {
|
|
||||||
return vw(AlbumView, a, a._id + a._rev);
|
|
||||||
}))
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,3 +129,15 @@ const header = styled({
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center'
|
alignItems: 'center'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const headerRight = styled({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center'
|
||||||
|
});
|
||||||
|
|
||||||
|
const slate = injectStyle({
|
||||||
|
display: 'flex',
|
||||||
|
flex: 1,
|
||||||
|
flexDirection: 'column'
|
||||||
|
// overflow: 'hidden',
|
||||||
|
});
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import find from 'pouchdb-find';
|
|||||||
import { log, warn } from './console.js';
|
import { log, warn } from './console.js';
|
||||||
import { isObject } from '../utils/comparators.js';
|
import { isObject } from '../utils/comparators.js';
|
||||||
import { LiveArray } from '../utils/livearray.js';
|
import { LiveArray } from '../utils/livearray.js';
|
||||||
import { deepAssign } from '../utils/conversion.js';
|
import { deepAssign, pouchDocHash } from '../utils/conversion.js';
|
||||||
|
|
||||||
export const PouchDB = core
|
export const PouchDB = core
|
||||||
.plugin(idb)
|
.plugin(idb)
|
||||||
@ -43,6 +43,10 @@ export class TypeSpec {
|
|||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_hash() {
|
||||||
|
return pouchDocHash(this);
|
||||||
|
}
|
||||||
|
|
||||||
async delete() {
|
async delete() {
|
||||||
return await this.update({ _deleted: true });
|
return await this.update({ _deleted: true });
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user