Skip to content

Commit

Permalink
[Canvas] Adds workpad-level CSS (#24143)
Browse files Browse the repository at this point in the history
* adds global, workpad css styling feature

* fixes checkered position and default CSS in textarea

* adds global, workpad css styling feature

* fixes checkered position and default CSS in textarea

* Added global styles to page manager

* Added 'apply stylesheet' button

* fix after rebase

* change style to css

* move default workpad CSS class to constant

* unwind the empty page color pieces
  • Loading branch information
Ryan Keairns authored Dec 3, 2018
1 parent 47c163b commit cfb1404
Show file tree
Hide file tree
Showing 12 changed files with 183 additions and 101 deletions.
1 change: 1 addition & 0 deletions x-pack/plugins/canvas/common/lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export const LOCALSTORAGE_LASTPAGE = 'canvas:lastpage';
export const FETCH_TIMEOUT = 30000; // 30 seconds
export const CANVAS_USAGE_TYPE = 'canvas';
export const SECURITY_AUTH_MESSAGE = 'Authentication failed';
export const DEFAULT_WORKPAD_CSS = '.canvasPage {\n\n}';
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const PageConfig = ({
<h4>Page</h4>
</EuiTitle>
<EuiSpacer size="m" />
<EuiFormRow label="Background">
<EuiFormRow label="Background color">
<ColorPickerMini onChange={setBackground} value={background} />
</EuiFormRow>
{/* No need to show the transition for the first page because transitions occur when
Expand Down
17 changes: 11 additions & 6 deletions x-pack/plugins/canvas/public/components/page_manager/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,17 @@ import { canUserWrite } from '../../state/selectors/app';
import { getSelectedPage, getWorkpad, getPages, isWriteable } from '../../state/selectors/workpad';
import { PageManager as Component } from './page_manager';

const mapStateToProps = state => ({
isWriteable: isWriteable(state) && canUserWrite(state),
pages: getPages(state),
selectedPage: getSelectedPage(state),
workpadId: getWorkpad(state).id,
});
const mapStateToProps = state => {
const { id, css } = getWorkpad(state);

return {
isWriteable: isWriteable(state) && canUserWrite(state),
pages: getPages(state),
selectedPage: getSelectedPage(state),
workpadId: id,
workpadCSS: css,
};
};

const mapDispatchToProps = dispatch => ({
addPage: () => dispatch(pageActions.addPage()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { EuiIcon, EuiFlexGroup, EuiFlexItem, EuiText, EuiToolTip } from '@elastic/eui';
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
import Style from 'style-it';
import { ConfirmModal } from '../confirm_modal';
import { Link } from '../link';
import { PagePreview } from '../page_preview';
Expand All @@ -25,6 +26,7 @@ export class PageManager extends React.PureComponent {
selectedPage: PropTypes.string,
deleteId: PropTypes.string,
setDeleteId: PropTypes.func.isRequired,
workpadCSS: PropTypes.string,
};

state = {
Expand Down Expand Up @@ -157,7 +159,7 @@ export class PageManager extends React.PureComponent {
};

render() {
const { pages, addPage, deleteId, isWriteable } = this.props;
const { pages, addPage, deleteId, isWriteable, workpadCSS } = this.props;
const { showTrayPop } = this.state;

return (
Expand All @@ -168,16 +170,22 @@ export class PageManager extends React.PureComponent {
<Droppable droppableId="droppable-page-manager" direction="horizontal">
{provided => (
<div
className={`canvasPageManager__pageList ${
showTrayPop ? 'canvasPageManager--trayPop' : ''
}`}
ref={el => {
this.pageListRef = el;
provided.innerRef(el);
}}
{...provided.droppableProps}
>
{pages.map(this.renderPage)}
{Style.it(
workpadCSS,
<div
className={`canvasPageManager__pageList ${
showTrayPop ? 'canvasPageManager--trayPop' : ''
}`}
>
{pages.map(this.renderPage)}
</div>
)}
{provided.placeholder}
</div>
)}
Expand Down
6 changes: 4 additions & 2 deletions x-pack/plugins/canvas/public/components/workpad/workpad.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Shortcuts } from 'react-shortcuts';
import Style from 'style-it';
import { WorkpadPage } from '../workpad_page';
import { Fullscreen } from '../fullscreen';
import { setDocTitle } from '../../lib/doc_title';
Expand Down Expand Up @@ -75,7 +76,8 @@ export const Workpad = props => {
: {};

// NOTE: the data-shared-* attributes here are used for reporting
return (
return Style.it(
workpad.css,
<div
className={`canvasWorkpad ${isFullscreen ? 'fullscreen' : ''}`}
style={fsStyle}
Expand Down Expand Up @@ -128,5 +130,5 @@ Workpad.propTypes = {
nextPage: PropTypes.func.isRequired,
previousPage: PropTypes.func.isRequired,
fetchAllRenderables: PropTypes.func.isRequired,
style: PropTypes.object,
css: PropTypes.object,
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
import { connect } from 'react-redux';

import { get } from 'lodash';
import { sizeWorkpad, setName } from '../../state/actions/workpad';
import { sizeWorkpad, setName, setWorkpadCSS } from '../../state/actions/workpad';
import { getWorkpad } from '../../state/selectors/workpad';

import { DEFAULT_WORKPAD_CSS } from '../../../common/lib/constants';
import { WorkpadConfig as Component } from './workpad_config';

const mapStateToProps = state => {
Expand All @@ -21,12 +21,14 @@ const mapStateToProps = state => {
width: get(workpad, 'width'),
height: get(workpad, 'height'),
},
css: get(workpad, 'css', DEFAULT_WORKPAD_CSS),
};
};

const mapDispatchToProps = {
setSize: size => sizeWorkpad(size),
setName: name => setName(name),
setWorkpadCSS: css => setWorkpadCSS(css),
};

export const WorkpadConfig = connect(
Expand Down
213 changes: 130 additions & 83 deletions x-pack/plugins/canvas/public/components/workpad_config/workpad_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import {
EuiFieldText,
Expand All @@ -17,96 +17,143 @@ import {
EuiSpacer,
EuiTitle,
EuiToolTip,
EuiTextArea,
EuiAccordion,
EuiText,
EuiButton,
} from '@elastic/eui';
import { DEFAULT_WORKPAD_CSS } from '../../../common/lib/constants';

export const WorkpadConfig = ({ size, name, setSize, setName }) => {
const rotate = () => setSize({ width: size.height, height: size.width });
export class WorkpadConfig extends PureComponent {
static propTypes = {
size: PropTypes.object.isRequired,
name: PropTypes.string.isRequired,
css: PropTypes.string,
setSize: PropTypes.func.isRequired,
setName: PropTypes.func.isRequired,
setWorkpadCSS: PropTypes.func.isRequired,
};

const badges = [
{
name: '1080p',
size: { height: 1080, width: 1920 },
},
{
name: '720p',
size: { height: 720, width: 1280 },
},
{
name: 'A4',
size: { height: 842, width: 590 },
},
{
name: 'US Letter',
size: { height: 792, width: 612 },
},
];
state = {
css: this.props.css,
};

return (
<div>
<EuiTitle size="xs">
<h4>Workpad</h4>
</EuiTitle>
render() {
const { size, name, setSize, setName, setWorkpadCSS } = this.props;
const { css } = this.state;
const rotate = () => setSize({ width: size.height, height: size.width });

<EuiSpacer size="m" />
const badges = [
{
name: '1080p',
size: { height: 1080, width: 1920 },
},
{
name: '720p',
size: { height: 720, width: 1280 },
},
{
name: 'A4',
size: { height: 842, width: 590 },
},
{
name: 'US Letter',
size: { height: 792, width: 612 },
},
];

<EuiFormRow label="Name" compressed>
<EuiFieldText value={name} onChange={e => setName(e.target.value)} />
</EuiFormRow>
return (
<div>
<EuiTitle size="xs">
<h4>Workpad</h4>
</EuiTitle>

<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem>
<EuiFormRow label="Width" compressed>
<EuiFieldNumber
onChange={e => setSize({ width: Number(e.target.value), height: size.height })}
value={size.width}
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormRow hasEmptyLabelSpace>
<EuiToolTip position="bottom" content="Flip the width and height">
<EuiButtonIcon
iconType="merge"
color="text"
onClick={rotate}
aria-label="Swap Page Dimensions"
style={{ marginBottom: 12 }}
<EuiSpacer size="m" />

<EuiFormRow label="Name" compressed>
<EuiFieldText value={name} onChange={e => setName(e.target.value)} />
</EuiFormRow>

<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem>
<EuiFormRow label="Width" compressed>
<EuiFieldNumber
onChange={e => setSize({ width: Number(e.target.value), height: size.height })}
value={size.width}
/>
</EuiToolTip>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow label="Height" compressed>
<EuiFieldNumber
onChange={e => setSize({ height: Number(e.target.value), width: size.width })}
value={size.height}
/>
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormRow hasEmptyLabelSpace>
<EuiToolTip position="bottom" content="Flip the width and height">
<EuiButtonIcon
iconType="merge"
color="text"
onClick={rotate}
aria-label="Swap Page Dimensions"
style={{ marginBottom: 12 }}
/>
</EuiToolTip>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow label="Height" compressed>
<EuiFieldNumber
onChange={e => setSize({ height: Number(e.target.value), width: size.width })}
value={size.height}
/>
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGroup>

<EuiSpacer size="m" />
<EuiSpacer size="s" />

<div>
{badges.map((badge, i) => (
<EuiBadge
key={`page-size-badge-${i}`}
color="hollow"
onClick={() => setSize(badge.size)}
aria-label={`Preset Page Size: ${badge.name}`}
onClickAriaLabel={`Set page size to ${badge.name}`}
>
{badge.name}
</EuiBadge>
))}
</div>
</div>
);
};
<div>
{badges.map((badge, i) => (
<EuiBadge
key={`page-size-badge-${i}`}
color="hollow"
onClick={() => setSize(badge.size)}
aria-label={`Preset Page Size: ${badge.name}`}
onClickAriaLabel={`Set page size to ${badge.name}`}
>
{badge.name}
</EuiBadge>
))}
</div>

<EuiSpacer size="m" />

WorkpadConfig.propTypes = {
size: PropTypes.object.isRequired,
name: PropTypes.string.isRequired,
setSize: PropTypes.func.isRequired,
setName: PropTypes.func.isRequired,
};
<EuiAccordion
id="accordion-global-css"
className="canvasArg__accordion"
buttonContent={
<EuiToolTip
content="Apply styles to all pages in this workpad"
position="left"
className="canvasArg__tooltip"
>
<EuiText size="s" color="subdued">
Global CSS overrides
</EuiText>
</EuiToolTip>
}
>
<div className="canvasArg__content">
<EuiTextArea
aria-label="Apply styles to all pages in this workpad"
value={css}
onChange={e => this.setState({ css: e.target.value })}
rows={10}
/>
<EuiSpacer size="s" />
<EuiButton size="s" onClick={() => setWorkpadCSS(css || DEFAULT_WORKPAD_CSS)}>
Apply stylesheet
</EuiButton>
<EuiSpacer size="xs" />
</div>
</EuiAccordion>
</div>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
position: absolute;
top: 0;
transform-style: preserve-3d !important;
background-color: $euiColorEmptyShade;
}

.canvasPage--isEditable {
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/canvas/public/state/actions/workpad.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const setName = createAction('setName');
export const setWriteable = createAction('setWriteable');
export const setColors = createAction('setColors');
export const setRefreshInterval = createAction('setRefreshInterval');
export const setWorkpadCSS = createAction('setWorkpadCSS');

export const initializeWorkpad = createThunk('initializeWorkpad', ({ dispatch }) => {
dispatch(fetchAllRenderables());
Expand Down
Loading

0 comments on commit cfb1404

Please sign in to comment.