From d24cc2cc1a6ff15bbce5241e7758a21e4e33f96e Mon Sep 17 00:00:00 2001 From: Chung Leong Date: Tue, 29 Jan 2019 21:26:49 +0100 Subject: [PATCH] Implemented image dialog box (issue #17). --- src/front-end.jsx | 1 + src/pages/post-page.jsx | 15 ++++----- src/routing.js | 3 ++ src/style.scss | 59 ++++++++++++++++++++++++++++++++++++ src/widgets/image-dialog.jsx | 57 ++++++++++++++++++++++++++++++++++ src/widgets/post-view.jsx | 39 +++++++++++++++++++++++- 6 files changed, 166 insertions(+), 8 deletions(-) create mode 100644 src/widgets/image-dialog.jsx diff --git a/src/front-end.jsx b/src/front-end.jsx index adc3d28..96aeda3 100644 --- a/src/front-end.jsx +++ b/src/front-end.jsx @@ -47,6 +47,7 @@ class FrontEnd extends PureComponent {
+
); } diff --git a/src/pages/post-page.jsx b/src/pages/post-page.jsx index aa46d09..8c54cb3 100644 --- a/src/pages/post-page.jsx +++ b/src/pages/post-page.jsx @@ -52,14 +52,15 @@ class PostPage extends AsyncComponent { } // see how recently a category was visited - let historyIndex = (c) => { - - return _.findLastIndex(route.history, { params: { categorySlug: c.slug }}); + let historyIndex = (category) => { + let predicate = { params: { categorySlug: category.slug }}; + return _.findLastIndex(route.history, predicate); }; // see how deep a category is - let depth = (c) => { - if (c.parent) { - let parent = _.find(allCategories, { id: c.parent }); + let depth = (category) => { + if (category.parent) { + let predicate = { id: category.parent }; + let parent = _.find(allCategories, predicate); if (parent) { return depth(parent) + 1; } @@ -97,7 +98,7 @@ class PostPageSync extends PureComponent { let { route, categories, post, author, tags, comments } = this.props; let trail = [ { label: 'Categories' } ]; for (let category of categories) { - let label = _.get(c, 'name', ''); + let label = _.get(category, 'name', ''); let url = route.prefetchObjectURL(category); trail.push({ label, url }); } diff --git a/src/routing.js b/src/routing.js index d25e22b..d2ddbe4 100644 --- a/src/routing.js +++ b/src/routing.js @@ -190,6 +190,9 @@ class Route { node.attribs.target = '_blank'; } } + if (_.startsWith(node.attribs.href, '/wp-content/')) { + node.attribs.href = siteURL + node.attribs.href; + } if (_.startsWith(node.attribs.href, '/')) { // strip off page number node.attribs.href = node.attribs.href.replace(/\/\d+\/?$/, ''); diff --git a/src/style.scss b/src/style.scss index 9ad3d26..bdabcc8 100644 --- a/src/style.scss +++ b/src/style.scss @@ -320,6 +320,65 @@ A { } } +.overlay { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; +} + +.image-dialog { + .background, .foreground { + position: fixed; + left: 0; + top: 0; + right: 0; + bottom: 0; + } + + .background { + background-color: #ffffff; + opacity: 0.5; + } + + .foreground { + display: flex; + align-items: center; + justify-content: center; + pointer-events: none; + + .box { + position: relative; + pointer-events: auto; + background: #66023c; + border-color: 1px solid black; + padding: 1em 1em 1em 1em; + box-shadow: 2px 2px 10px #000000; + max-width: 90%; + color: #cccccc; + + .image { + display: block; + border: 1px solid #000000; + max-width: 100%; + max-height: 80vh; + height: auto; + } + + .close-button { + position: absolute; + font-size: 0.75em; + padding: 0.25em 0.25em 0.25em 0.25em; + margin: -0.25em -0.25em -0.25em -0.25em; + right: 0.35em; + top: 0.35em; + cursor: pointer; + } + } + } +} + @media only screen and (max-width: 800px) { .page-container { transition: margin-left 0.3s; diff --git a/src/widgets/image-dialog.jsx b/src/widgets/image-dialog.jsx new file mode 100644 index 0000000..de4a78a --- /dev/null +++ b/src/widgets/image-dialog.jsx @@ -0,0 +1,57 @@ +import _ from 'lodash'; +import React, { PureComponent } from 'react'; +import ReactDOM from 'react-dom'; + +class ImageDialog extends PureComponent { + + render() { + let { imageURL } = this.props; + if (!imageURL) { + return null; + } + let container = document.getElementById('overlay'); + let dialog = this.renderDialog(); + return ReactDOM.createPortal(dialog, container); + } + + renderDialog() { + let { imageURL } = this.props; + return ( +
+
+
+
+
+ +
+ +
+
+
+ ); + } + + handleCloseClick = (evt) => { + let { onClose } = this.props; + if (onClose) { + onClose({ + type: 'close', + target: this, + }); + } + } +} + +if (process.env.NODE_ENV !== 'production') { + const PropTypes = require('prop-types'); + + ImageDialog.propTypes = { + imageURL: PropTypes.string, + onClose: PropTypes.func, + }; +} + +export { + ImageDialog as default, + ImageDialog, +}; diff --git a/src/widgets/post-view.jsx b/src/widgets/post-view.jsx index c6a4fbb..ef2d413 100644 --- a/src/widgets/post-view.jsx +++ b/src/widgets/post-view.jsx @@ -3,10 +3,18 @@ import Moment from 'moment'; import React, { PureComponent } from 'react'; import HTML from 'widgets/html'; +import ImageDialog from 'widgets/image-dialog'; class PostView extends PureComponent { static displayName = 'PostView'; + constructor(props) { + super(props); + this.state = { + imageURL: null, + }; + } + render() { let { post, author, transform } = this.props; let title = _.get(post, 'title.rendered', ''); @@ -23,12 +31,41 @@ class PostView extends PureComponent {
{name}

-
+
+ {this.renderImageDialog()}
); } + + renderImageDialog() { + let { imageURL } = this.state; + return ; + } + + handleClick = (evt) => { + let target = evt.target; + let container = evt.currentTarget; + if (target.tagName === 'IMG') { + let link; + for (let p = target; p && p !== container; p = p.parentNode) { + if (p.tagName === 'A') { + link = p; + break; + } + } + if (link) { + let imageURL = link.href; + this.setState({ imageURL }); + evt.preventDefault(); + } + } + } + + handleDialogClose = (evt) => { + this.setState({ imageURL: null }); + } } if (process.env.NODE_ENV !== 'production') {