Skip to content

Commit

Permalink
Page Preview Thumbnail (elastic#375)
Browse files Browse the repository at this point in the history
* Created dom_preview and page_preview components

* temporarily display page number on non active pages. Need to fix page thumbnail width issue

* Added page number to page controls

* Rendered preview for all pages instead of just the active one

* Fixed background color on thumbnails. Added box-shadow to active page

* Removed background color from page controls

* Changed background color on page controls

* Changed prop 'id' to 'elementId' in dom_preview

* Removed unused style in page_manager.less

* Removed jQuery from dom_preview

* Updated styles for page preview

* Added text styles back to page-index

* Removed unused code

* Hides element controls in page preview

* Removed debounce for page preview update

* Changes propTypes and observer to static variables. Disconnects observer on unmount

* Added radix to parseInt in dom_preview

* Added debounce to update function in dom_preview

* Updated styles for page manager. References css variables instead of hard-coded values
  • Loading branch information
cqliu1 authored and w33ble committed Mar 30, 2018
1 parent 2bdf774 commit 2f114fb
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 25 deletions.
86 changes: 86 additions & 0 deletions public/components/dom_preview/dom_preview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React from 'react';
import PropTypes from 'prop-types';
import { debounce } from 'lodash';

export class DomPreview extends React.Component {
static container = null;
static content = null;
static observer = null;

static propTypes = {
elementId: PropTypes.string.isRequired,
height: PropTypes.number.isRequired,
setPagePreviewWidth: PropTypes.func,
};

componentDidMount() {
const original = document.querySelector(`#${this.props.elementId}`);

const update = this.update(original);
update();

const slowUpdate = debounce(update, 250);

this.observer = new MutationObserver(slowUpdate);
// configuration of the observer:
const config = { attributes: true, childList: true, subtree: true };
// pass in the target node, as well as the observer options
this.observer.observe(original, config);
}

componentWillUnmount() {
this.observer.disconnect();
}

update = original => () => {
const thumb = original.cloneNode(true);

const originalStyle = window.getComputedStyle(original, null);
const originalWidth = parseInt(originalStyle.getPropertyValue('width'), 10);
const originalHeight = parseInt(originalStyle.getPropertyValue('height'), 10);

const thumbHeight = this.props.height;
const scale = thumbHeight / originalHeight;
const thumbWidth = originalWidth * scale;

if (this.content) {
if (this.content.hasChildNodes()) this.content.removeChild(this.content.firstChild);
this.content.appendChild(thumb);
}
// Copy canvas data
const originalCanvas = original.querySelectorAll('canvas');
const thumbCanvas = thumb.querySelectorAll('canvas');

// Cloned canvas elements are blank and need to be explicitly redrawn
if (originalCanvas.length > 0) {
Array.from(originalCanvas).map((img, i) =>
thumbCanvas[i].getContext('2d').drawImage(img, 0, 0)
);
}

this.props.setPagePreviewWidth(thumbWidth + 2);

this.container.style.cssText = `width: ${thumbWidth}; height: ${thumbHeight}; overflow: 'hidden',`;

this.content.style.cssText = `transform: scale(${scale}); transform-origin: top left; height: ${originalHeight}; width: ${originalWidth};`;

thumb.style.cssText = 'top: 0; left: 0;';
};

render() {
return (
<div
ref={container => {
this.container = container;
}}
className="dom-preview"
>
<div
ref={content => {
this.content = content;
}}
/>
</div>
);
}
}
3 changes: 3 additions & 0 deletions public/components/dom_preview/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { DomPreview as Component } from './dom_preview';

export const DomPreview = Component;
1 change: 1 addition & 0 deletions public/components/element_wrapper/element_controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export const ElementControls = pure(props => {
<RemoveIcon
style={{ position: 'absolute', top: -20, right: -20 }}
onClick={removeHandler}
className={'canvas__element--remove-icon'}
/>
)}
</div>
Expand Down
24 changes: 12 additions & 12 deletions public/components/page_manager/page_manager.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import React from 'react';
import PropTypes from 'prop-types';
import { ConfirmModal } from '../confirm_modal';
import { RemoveIcon } from '../remove_icon';
import { Link } from '../link';
import { PageControls } from './page_controls';
import { PagePreview } from '../page_preview';
import './page_manager.less';

export class PageManager extends React.PureComponent {
Expand Down Expand Up @@ -39,14 +38,15 @@ export class PageManager extends React.PureComponent {
params={{ id: workpadId, page: pageNumber }}
aria-label={`Load page number ${pageNumber}`}
>
<div className={`canvas__page-manager--page ${page.id === selectedPage ? 'active' : ''}`}>
<RemoveIcon
className="canvas__page-manager--page-remove"
onClick={this.confirmDelete(page.id)}
/>
<div className="canvas__page-manager--page-index">{pageNumber}</div>
<PageControls pageId={page.id} movePage={movePage} duplicatePage={duplicatePage} />
</div>
<PagePreview
page={page}
height={94}
pageNumber={pageNumber}
movePage={movePage}
duplicatePage={duplicatePage}
selectedPage={selectedPage}
confirmDelete={this.confirmDelete}
/>
</Link>
);
};
Expand All @@ -58,8 +58,8 @@ export class PageManager extends React.PureComponent {
<div className="canvas__page-manager">
<div className="canvas__page-manager--pages">
{pages.map(this.renderPage)}
<div className="canvas__page-manager--page" onClick={addPage}>
<div className="canvas__page-manager--page-index">+</div>
<div className="canvas__page-manager--page-add" onClick={addPage}>
<i className="fa fa-plus-circle" />
</div>
</div>

Expand Down
47 changes: 35 additions & 12 deletions public/components/page_manager/page_manager.less
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
@import (reference) "../../style/variables";
@import (reference) '../../style/variables';

.canvas__page-manager {
.canvas__page-manager--pages {
white-space: nowrap;
overflow-y: hidden;
overflow-x: auto;
max-height: 148px;
max-height: @spacingXXXL * 3;
padding-top: @spacingS;
margin-bottom: @spacingS;
}

.canvas__page-manager--pages a {
box-shadow: none;
padding-left: @spacingXS;
}

.canvas__page-manager--page.active {
background-color: @trueWhite !important;
color: @textMain !important;
box-shadow: 0 0 1px 2px @blue;
}

.canvas__page-manager--page:hover {
Expand All @@ -21,16 +24,15 @@
}

.canvas__page-manager--page {
background-color: @darkGrey;
position: relative;
color: @mediumGrey;
border: @borderStyle;
display: inline-block;
vertical-align: top;
font-weight: bold;
text-align: center;
width: 77px;
height: 100px;
width: @spacingXXXXL;
height: @spacingXXXL * 2;
margin: 0 @spacingM @spacingS 0;
cursor: pointer;

Expand All @@ -41,6 +43,8 @@
position: absolute;
text-align: center;
width: 100%;
background-color: @darkestGrey;
opacity: 0.75;

> * {
padding: @spacingXS;
Expand Down Expand Up @@ -68,17 +72,36 @@
.canvas__page-manager--page-remove {
display: none;
position: absolute;
top: -8px;
right: -12px;
top: -@spacingS;
right: -@spacingXS * 3;
}

.canvas__page-manager--page-controls {
display: none;
}

.canvas__page-manager--page-index {
line-height: 100px;
font-size: @textLarge;
overflow: hidden;
height: @spacingXXXL * 2;
}

.canvas--interactable-actions,
.canvas--interactable-meta,
.canvas--interactable-resize,
.canvas__element--remove-icon {
display: none;
}
}

.canvas__page-manager--page-add {
display: inline-block;
line-height: @spacingXXL * 2;
font-size: @textXXLarge;
padding: 0 @spacingS;
color: @mediumGrey;

&:hover {
color: @trueWhite;
}
}
}
4 changes: 4 additions & 0 deletions public/components/page_preview/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { compose, withState } from 'recompose';
import { PagePreview as Component } from './page_preview';

export const PagePreview = compose(withState('width', 'setWidth', 77))(Component);
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import React from 'react';
import PropTypes from 'prop-types';

export const PageControls = ({ pageId, duplicatePage, movePage }) => (
export const PageControls = ({ pageId, pageNumber, duplicatePage, movePage }) => (
<div className="canvas__page-manager--page-controls">
{`${pageNumber}`}
<br />
<span
className="fa fa-angle-double-left canvas__page-manager--page-move"
onClick={() => movePage(pageId, -1)}
Expand All @@ -17,6 +19,7 @@ export const PageControls = ({ pageId, duplicatePage, movePage }) => (

PageControls.propTypes = {
pageId: PropTypes.string.isRequired,
pageNumber: PropTypes.number.isRequired,
duplicatePage: PropTypes.func.isRequired,
movePage: PropTypes.func.isRequired,
};
59 changes: 59 additions & 0 deletions public/components/page_preview/page_preview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { DomPreview } from '../dom_preview';
import { RemoveIcon } from '../remove_icon';
import { PageControls } from './page_controls';

export class PagePreview extends PureComponent {
static propTypes = {
page: PropTypes.object.isRequired,
height: PropTypes.number.isRequired,
pageNumber: PropTypes.number.isRequired,
movePage: PropTypes.func,
duplicatePage: PropTypes.func,
selectedPage: PropTypes.string,
confirmDelete: PropTypes.func,
width: PropTypes.number,
setWidth: PropTypes.func,
};

render() {
const {
page,
pageNumber,
height,
selectedPage,
movePage,
duplicatePage,
confirmDelete,
width,
setWidth,
} = this.props;

return (
<div
className={`canvas__page-manager--page ${page.id === selectedPage ? 'active' : ''}`}
style={{ width: width, backgroundColor: page.style.background }}
>
<div className="canvas__page-manager--page-index" style={{ width: width }}>
<DomPreview
elementId={page.id}
pageNumber={pageNumber}
height={height}
setPagePreviewWidth={width => setWidth(width)}
/>
</div>
<RemoveIcon
className="canvas__page-manager--page-remove"
onClick={confirmDelete(page.id)}
/>
<PageControls
pageId={page.id}
pageNumber={pageNumber}
movePage={movePage}
duplicatePage={duplicatePage}
/>
</div>
);
}
}
1 change: 1 addition & 0 deletions public/components/page_stack/page_stack.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const PageStack = ({ pages, selectedPageId, height, width }) => {
return pages.map(page => (
<div
key={page.id}
id={page.id}
className="canvas__page"
style={{
top: selectedPageId === page.id ? undefined : '-9999999px',
Expand Down

0 comments on commit 2f114fb

Please sign in to comment.