Refactor: Album interface elements become Section

This is to make way for real the real album view.
This commit is contained in:
Timothy Farrell 2017-12-31 17:24:58 -06:00
parent ef8df004d5
commit 490b788fd0
7 changed files with 111 additions and 191 deletions

View File

@ -1,79 +0,0 @@
import { defineView, defineElement as el } from '../utils/domvm.js';
import { ImageType } from '../data/image.js';
import { FileType } from '../data/file.js';
import { pouchDocArrayHash, pouchDocHash } from '../utils/conversion.js';
import { ThumbnailTemplate } from './components/thumbnail.js';
import { prop, computed } from 'frptools';
export function AlbumView(vm, params) {
const model = prop({}, pouchDocHash);
const images = prop([], pouchDocArrayHash);
const id = computed(pouchDocHash, [model]);
const members = computed(d => d.members, [model]); // always update
const title = computed(d => d.title, [model]); // always update
let laCleanup = null;
const refresh = _ => vm.redraw();
const subscriptions = [
images.subscribe(refresh),
model.subscribe(async album => {
if (!album.findImages) {
return;
}
const imagesLiveArray = await album.findImages(true);
if (laCleanup) {
laCleanup();
}
function refresh() {
images(imagesLiveArray());
vm.redraw();
}
laCleanup = imagesLiveArray.subscribe(refresh);
imagesLiveArray.ready.subscribe(refresh);
})
];
function removeImageFromAlbum(image) {
model().removeImage(image);
}
function removeAlbum(album) {
album.delete();
}
function uploadImages(album, evt) {
Array.from(evt.currentTarget.files).forEach(f => album.addImageBlob(f));
}
function cleanup() {
if (laCleanup) {
laCleanup();
}
subscriptions.forEach(s => s());
}
model(params);
return function() {
const album = model();
return el('.album', [
el('h2', title),
el('button', { onclick: [removeAlbum, album] }, 'X'),
el('input#fInput', {
type: 'file',
multiple: true,
accept: 'image/jpeg',
onchange: [uploadImages, album]
}),
...images().map(i => {
return ThumbnailTemplate(i, removeImageFromAlbum, i._hash());
})
]);
};
}

View File

@ -5,13 +5,14 @@ import {
subscribeToRender, subscribeToRender,
defineView, defineView,
nodeParentWithType, nodeParentWithType,
defineView as vw,
defineElement as el defineElement as el
} from '../utils/domvm.js'; } from '../utils/domvm.js';
import { error } from '../services/console.js'; import { error } from '../services/console.js';
import { ImageType } from '../data/image.js'; import { ImageType } from '../data/image.js';
import { pouchDocArrayHash, pouchDocHash, hashSet, extractID } from '../utils/conversion.js'; import { pouchDocArrayHash, pouchDocHash, hashSet, extractID } from '../utils/conversion.js';
import { AlbumTemplate } from './components/albumTemplate.js'; import { SectionView } from './sectionView.js';
import { Icon } from './components/icon.js'; import { Icon } from './components/icon.js';
import { injectStyle, styled } from '../services/style.js'; import { injectStyle, styled } from '../services/style.js';
import { CLICKABLE } from './styles.js'; import { CLICKABLE } from './styles.js';
@ -24,7 +25,8 @@ export function uploadImages(evt, files) {
} }
} }
export function AllImagesView(vm, params, key, { appbar }) { export function AllImagesView(vm, params, key, context) {
const { appbar } = context;
const model = prop({}, pouchDocHash); const model = prop({}, pouchDocHash);
const images = container([], pouchDocArrayHash); const images = container([], pouchDocArrayHash);
@ -42,6 +44,7 @@ export function AllImagesView(vm, params, key, { appbar }) {
.sort((a, b) => a[0].localeCompare(b[0])) .sort((a, b) => a[0].localeCompare(b[0]))
.map(([date, _images]) => ({ .map(([date, _images]) => ({
title: format(date, 'MMMM D, YYYY'), title: format(date, 'MMMM D, YYYY'),
sectionId: date,
images: _images images: _images
})); }));
}, },
@ -165,14 +168,18 @@ export function AllImagesView(vm, params, key, { appbar }) {
); );
}); });
function renderSection({ title, images: _images }) { function renderSection({ title, sectionId, images: _images }) {
return AlbumTemplate({ return vw(
SectionView,
{
title, title,
id: title,
photos: _images, photos: _images,
selectedIds, selectedIds,
selectMode: selectMode() selectMode: selectMode()
}); },
sectionId,
context
);
} }
return function() { return function() {
@ -182,8 +189,8 @@ export function AllImagesView(vm, params, key, { appbar }) {
onclick: { onclick: {
'.photoSelect .icon svg path': toggleSelect, '.photoSelect .icon svg path': toggleSelect,
'.photoSelect .icon': toggleSelect, '.photoSelect .icon': toggleSelect,
'.albumSelectButton .icon': toggleAll, '.sectionSelectButton .icon': toggleAll,
'.albumSelectButton .icon svg path': toggleAll, '.sectionSelectButton .icon svg path': toggleAll,
'.photoOverlay': photoClick '.photoOverlay': photoClick
}, },
onscroll: handleContentScroll onscroll: handleContentScroll

View File

@ -1,77 +0,0 @@
import {
defineView as vw,
defineElement as el,
patchRefStyle,
patchNodeStyle
} from '../../utils/domvm.js';
import { injectStyle, styled } from '../../services/style.js';
import { DEFAULT_TRANSITION, CLICKABLE } from '../styles.js';
import { Icon } from './icon.js';
import { AlbumPhotoTemplate } from './albumPhotoTemplate.js';
import { extractID } from '../../utils/conversion.js';
export function AlbumTemplate(params) {
const { id, title, photos, selectedIds, selectMode } = params;
const albumSelectButtonRef = `albSel${id}`;
function photoMap(doc) {
return vw(
AlbumPhotoTemplate,
{
doc,
isSelected: selectedIds.has(doc._id),
selectMode
},
doc._hash()
);
}
return Album(
{
onmouseenter: [patchRefStyle, albumSelectButtonRef, 'opacity: 0.7;'],
onmouseleave: [patchRefStyle, albumSelectButtonRef, 'opacity: 0;'],
_data: {
type: 'section',
sectionImageIds: photos.map(extractID)
}
},
[
albumTitle([
title,
albumSelectButton(
{
_ref: albumSelectButtonRef,
onmouseenter: [patchNodeStyle, 'opacity: 1;'],
onmouseleave: [patchNodeStyle, 'opacity: 0.7;'],
css: {
opacity: selectMode ? 0.7 : 0
},
class: 'albumSelectButton'
},
[Icon({ name: 'check_circle', size: 0.25 })]
)
]),
albumContent(photos.map(photoMap))
]
);
}
const Album = styled({
margin: '10px'
});
const albumTitle = styled({
display: 'flex',
alignItems: 'center'
});
const albumContent = styled({
display: 'flex',
alignItems: 'flex-start',
userSelect: 'none'
});
const albumSelectButton = styled(DEFAULT_TRANSITION, CLICKABLE, {
paddingLeft: '0.5em',
opacity: 0
});

View File

@ -1,14 +0,0 @@
import { defineView as vw, defineElement as el } from '../../utils/domvm.js';
import { AttachmentImageView } from './attachmentImage.js';
export function ThumbnailTemplate(doc, remove, key) {
return el('div', [
el(
`figure.image`,
{
onclick: { img: [remove, doc] }
},
[AttachmentImageView(doc)]
)
]);
}

View File

@ -10,7 +10,6 @@ import {
} from '../utils/domvm.js'; } from '../utils/domvm.js';
import { ImageType } from '../data/image.js'; import { ImageType } from '../data/image.js';
import { AlbumType } from '../data/album.js'; import { AlbumType } from '../data/album.js';
import { ThumbnailTemplate } from './components/thumbnail.js';
import { AllImagesView, uploadImages } from './allImages.js'; import { AllImagesView, uploadImages } from './allImages.js';
import { FocusView } from './focus.js'; import { FocusView } from './focus.js';
import { Dropzone } from './components/dropzone.js'; import { Dropzone } from './components/dropzone.js';

View File

@ -6,14 +6,14 @@ import {
patchRefStyleMap, patchRefStyleMap,
patchNodeStyle, patchNodeStyle,
subscribeToRender subscribeToRender
} from '../../utils/domvm.js'; } from '../utils/domvm.js';
import { router } from '../../services/router.js'; import { router } from '../services/router.js';
import { injectStyle, styled } from '../../services/style.js'; import { injectStyle, styled } from '../services/style.js';
import { DEFAULT_TRANSITION, CSS_FULL_SIZE, IMAGE_MARGIN, CLICKABLE } from '../styles.js'; import { DEFAULT_TRANSITION, CSS_FULL_SIZE, IMAGE_MARGIN, CLICKABLE } from './styles.js';
import { Icon } from './icon.js'; import { Icon } from './components/icon.js';
import { AttachmentImageView } from './attachmentImage.js'; import { AttachmentImageView } from './components/attachmentImage.js';
export function AlbumPhotoTemplate(vm, { doc }) { export function SectionPhoto(vm, { doc }) {
const photoSelectButtonRef = `pSB${doc._id}`; const photoSelectButtonRef = `pSB${doc._id}`;
const photoOverlayRef = `pBkd${doc._id}`; const photoOverlayRef = `pBkd${doc._id}`;
const href = router.href('focus', { id: doc._id }); const href = router.href('focus', { id: doc._id });
@ -26,7 +26,7 @@ export function AlbumPhotoTemplate(vm, { doc }) {
return photoContainer( return photoContainer(
{ {
href, href,
class: 'albumPhoto', class: 'sectionPhoto',
onmouseenter: [hover, true], onmouseenter: [hover, true],
onmouseleave: [hover, false], onmouseleave: [hover, false],
css: { css: {

View File

@ -0,0 +1,84 @@
import {
defineView as vw,
defineElement as el,
patchRefStyle,
patchNodeStyle
} from '../utils/domvm.js';
import { injectStyle, styled } from '../services/style.js';
import { DEFAULT_TRANSITION, CLICKABLE } from './styles.js';
import { Icon } from './components/icon.js';
import { SectionPhoto } from './sectionPhoto.js';
import { extractID } from '../utils/conversion.js';
export function SectionView(vm, params, key, context) {
const { appbar } = context;
const { title, photos } = params;
const sectionSelectButtonRef = `secSel${key}`;
return function render(vm, params) {
const { selectedIds, selectMode } = params;
function photoTemplate(doc) {
return vw(
SectionPhoto,
{
doc,
isSelected: selectedIds.has(doc._id),
selectMode
},
doc._hash(),
context
);
}
return sectionContainer(
{
class: 'section',
onmouseenter: [patchRefStyle, sectionSelectButtonRef, 'opacity: 0.7;'],
onmouseleave: [patchRefStyle, sectionSelectButtonRef, 'opacity: 0;'],
_data: {
type: 'section',
sectionImageIds: photos.map(extractID)
}
},
[
sectionTitle([
title,
sectionSelectButton(
{
class: 'sectionSelectButton',
_ref: sectionSelectButtonRef,
onmouseenter: [patchNodeStyle, 'opacity: 1;'],
onmouseleave: [patchNodeStyle, 'opacity: 0.7;'],
css: {
opacity: selectMode ? 0.7 : 0
}
},
[Icon({ name: 'check_circle', size: 0.25 })]
)
]),
sectionContent(photos.map(photoTemplate))
]
);
};
}
const sectionContainer = styled({
margin: '10px'
});
const sectionTitle = styled({
display: 'flex',
alignItems: 'center'
});
const sectionContent = styled({
display: 'flex',
alignItems: 'flex-start',
userSelect: 'none'
});
const sectionSelectButton = styled(DEFAULT_TRANSITION, CLICKABLE, {
paddingLeft: '0.5em',
opacity: 0
});