Refactor: Album interface elements become Section
This is to make way for real the real album view.
This commit is contained in:
parent
84974ad057
commit
2f7cf1830f
@ -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());
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -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
|
||||||
|
|||||||
@ -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
|
|
||||||
});
|
|
||||||
@ -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)]
|
|
||||||
)
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
@ -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';
|
||||||
|
|||||||
@ -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: {
|
||||||
84
packages/gallery/src/interface/sectionView.js
Normal file
84
packages/gallery/src/interface/sectionView.js
Normal 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
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user