273 lines
5.2 KiB
JavaScript

import { prop, computed, container } from 'frptools';
import {
subscribeToRender,
defineView,
nodeParentWithType,
fullViewportSize,
defineElement as el,
injectView as iv
} from '../utils/domvm.js';
import { router } from '../services/router.js';
import { ImageType } from '../data/image.js';
import { pouchDocHash, pick } from '../utils/conversion.js';
import { AttachmentImageView } from './components/attachmentImage.js';
import { Overlay } from './components/overlay.js';
import { Icon } from './components/icon.js';
import { AppBar } from './components/appbar.js';
import { styled, injectStyle } from '../utils/style.js';
import { error } from '../utils/console.js';
import { CLICKABLE, FILL_STYLE } from './styles.js';
export function FocusView(vm, params) {
const id = prop();
const doc = prop({}, pouchDocHash);
const nextLink = prop();
const prevLink = prop();
const mouseActive = prop(true);
let mouseMoveTimeout = null;
const appBarStyle = computed(
mA => ({
position: 'fixed',
opacity: mA ? 1 : 0,
backgroundImage: 'linear-gradient(0deg,rgba(0,0,0,0),rgba(0,0,0,0.4))'
}),
[mouseActive],
s => s.opacity
);
const imageStyle = computed(
({ width: iw, height: ih }, { width: vw, height: vh }) => {
const imageRatio = iw / ih;
const windowRatio = vw / vh;
if (iw < vw && ih < vh) {
return {
height: ih,
width: iw
};
}
if (windowRatio > imageRatio) {
return {
height: vw / windowRatio,
width: vw / windowRatio * imageRatio
};
}
return {
height: vh * windowRatio / imageRatio,
width: vh * windowRatio
};
},
[doc, fullViewportSize]
);
function navBack() {
router.goto('home');
}
async function clickTrash() {
if (confirm('Delete this image?')) {
await ImageType.delete(id());
navBack();
}
}
const mouseLeave = () => {
mouseActive(false);
};
const mouseMove = () => {
if (mouseMoveTimeout !== null) {
clearTimeout(mouseMoveTimeout);
}
mouseMoveTimeout = setTimeout(mouseLeave, 3000);
mouseActive(true);
};
const mouseClick = () => {
if (mouseMoveTimeout !== null) {
clearTimeout(mouseMoveTimeout);
}
mouseActive(!mouseActive());
};
// Subscribe to our changables.
subscribeToRender(
vm,
[
doc,
nextLink,
prevLink,
appBarStyle,
// Look for our image and set it.
() =>
id.subscribe(async _id => {
if (!_id) {
return;
}
doc(await ImageType.find(_id));
const n = await ImageType.find(
{
originalDate: { $gte: doc().originalDate }
},
{
limit: 1,
skip: 1,
index: 'originalDate',
sort: [{ originalDate: 'asc' }]
}
);
const p = await ImageType.find(
{
originalDate: { $lte: doc().originalDate }
},
{
limit: 1,
skip: 1,
index: 'originalDate',
sort: [{ originalDate: 'desc' }]
}
);
nextLink(n.length ? router.href('focus', { id: n[0]._id }) : null);
prevLink(p.length ? router.href('focus', { id: p[0]._id }) : null);
})
],
true
);
// Watch for focus changes
vm.config({ hooks: { willUpdate: (vm, { vars }) => id(vars.id) } });
// Start navigation
id(params.vars.id);
mouseMove();
return function() {
const _id = doc() && doc()._id;
if (!_id) {
return Overlay('Loading...');
}
return focusContainer(
{
class: 'focus',
onmousemove: mouseMove,
onmouseleave: mouseLeave,
onclick: mouseClick
},
[
AppBar({
style: appBarStyle(),
title: '',
up: { action: navBack, fill: 'white' },
actions: [
trashButtonContainer(
{
onclick: clickTrash
},
[
Icon({
name: 'trash-alt',
size: 0.75,
fill: 'white',
style: { verticalAlign: 'middle' }
})
]
)
]
}),
focusContent([
prevLink()
? prevClickZone({ href: prevLink() }, [
Icon({
name: 'chevron-left',
size: 0.75,
fill: 'white'
})
])
: null,
AttachmentImageView({
src: _id ? doc().sizes.full : null,
style: imageStyle
}),
nextLink()
? nextClickZone({ href: nextLink() }, [
Icon({
name: 'chevron-right',
size: 0.75,
fill: 'white'
})
])
: null
])
]
);
};
}
const WIDE = injectStyle({ width: '100%' });
const TALL = injectStyle({ height: '100%' });
const CSS_CLICK_ZONE = {
position: 'absolute',
width: '33%',
height: '70%',
display: 'flex',
alignItems: 'center',
padding: '2em',
top: '15%',
transition: 'opacity .13s cubic-bezier(0.0,0.0,0.2,1)',
opacity: 0,
cursor: 'pointer',
':hover': {
opacity: 1
}
};
const trashButtonContainer = styled(
{
marginRight: '1em'
},
CLICKABLE
);
const focusContainer = styled(
{
display: 'flex',
overflow: 'hidden',
flexDirection: 'column',
alignItems: 'center',
backgroundColor: 'black'
},
FILL_STYLE
);
const focusContent = styled({
flex: 1,
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center'
});
const nextClickZone = styled(
'a',
{
right: '0px',
justifyContent: 'flex-end'
},
CSS_CLICK_ZONE
);
const prevClickZone = styled(
'a',
{
left: '0px',
justifyContent: 'flex-start'
},
CSS_CLICK_ZONE
);