-
Notifications
You must be signed in to change notification settings - Fork 96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NEW Add ViewModeToggle component #560
NEW Add ViewModeToggle component #560
Conversation
Added |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work! I've left a couple of minor comments.
It also looks like your IDE isn't respecting the editorconfig rules (2 spaces for indentation) - perhaps you could tweak this so it's consistently using it?
let classNames = 'btn btn-secondary icon-view last font-icon-edit-write'; | ||
if (activeState === 'edit') { | ||
classNames += ' viewMode-selected'; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can use the classnames
library for this, it's already part of admin
@@ -123,6 +125,7 @@ class Preview extends Component { | |||
<div className="btn-toolbar"> | |||
{this.renderBackButton()} | |||
{this.buildToolbarButtons()} | |||
<ViewModeToggle id="view-mode-toggle-in-preview-nb" area={'preview'} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally we'd use the injector to inject a ViewModeToggle prop into Preview which would allow devs to customise this component in the Preview implementation if they wanted to. For example:
import { inject } from 'lib/Injector';
// ...
render() {
const { ViewModeComponent } = this.props;
return (
// ..
<ViewModeComponent { ...props } />
// ...
Preview.propTypes = {
ViewModeComponent: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired,
};
// ...
export default inject(
['ViewModeToggle'],
(ViewModeToggle) => ({
ViewModeComponent: ViewModeToggle
}),
'Admin.Preview'
);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'll also need to register the component with Injector in src/boot/registerComponents.js
client/src/styles/bundle.scss
Outdated
@@ -59,6 +59,8 @@ | |||
@import "../components/Toolbar/Toolbar"; | |||
@import "../components/TreeDropdownField/TreeDropdownField"; | |||
@import "../components/UsedOnTable/UsedOnTable"; | |||
@import "../components/IframeDialog/IframeDialog"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this referenced somewhere else?
background: rgba(255, 255, 255, 0); | ||
|
||
&::before { | ||
content: "Screen size too small"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any way of adding this with javascript or PHP? We can't make this string translatable if it's in CSS
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than having a :before
pseudo element, you could have a span styled the same and injected to the .disabled-tooltip
div element, this will enable translatable strings and not require any hacks.
If you want the hacked version, use the attr()
css function and pick an arbitrary attribute to get the translation string from.
9bc8727
to
4ab0615
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I glazed over the test file, I'll review it when I get more time
Overall it's a decent implementation - the main blocker for me is that the "tooltip" for disabled options could be improved.
import { selectEditMode, selectPreviewMode, selectSplitMode } from 'state/viewMode/viewModeActions'; | ||
import classNames from 'classnames'; | ||
|
||
/* global window */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a need to declare the window global anymore?
case 'preview': | ||
return 'font-icon-eye'; | ||
default: | ||
return 'font-icon-columns'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the indent for these lines seem off, they're 4 spaces instead of 2.
Could you have a map of the classes somewhere? possibly provided through props, or another extensible means. It would make customising the icons by an external author possible.
case 'preview': | ||
return i18n._t('Admin.PREVIEW_MODE', 'Preview mode'); | ||
default: | ||
return i18n._t('Admin.SPLIT_MODE', 'Split mode'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar with the above comment
background: rgba(255, 255, 255, 0); | ||
|
||
&::before { | ||
content: "Screen size too small"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than having a :before
pseudo element, you could have a span styled the same and injected to the .disabled-tooltip
div element, this will enable translatable strings and not require any hacks.
If you want the hacked version, use the attr()
css function and pick an arbitrary attribute to get the translation string from.
display: none; | ||
background: #555; | ||
left: 47%; | ||
top: -6px; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you implement the span
suggestion above, you can then use borders to implement the "speech bubble" effect which will reduce a lot of this juggling around with css3 rotate and other specific pixel placements.
export function selectEditMode() { | ||
return { | ||
type: ACTION_TYPES.SELECT_EDIT, | ||
payload: null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can just omit the payload for all these actions...
Also indent is all over the place for this file
export function enableOrDisableSplitMode(panelWidth) { | ||
return { | ||
type: ACTION_TYPES.SPLIT_AVAILABLE, | ||
panelWidth |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
put panelWidth in a payload object:
{
type: ACTION_SOMETHING,
payload: { panelWidth },
};
I remember silverstripe-admin had a click simulator somewhere... maybe it was removed because it didn't prove useful. |
4ab0615
to
a255c32
Compare
Hi @flamerohr, thanks a lot for your feedback. I have addressed most things you mentioned - as well as changed the component to use Dropdown instead of PopoverField @lukereative. Unfortunately, yarn throws an error when I try to add enzyme to the dev-dependencies: |
If approved I suggest we implement this in https://github.com/silverstripe/silverstripe-versioned-admin. A PR was made to silverstripe/silverstripe-campaign-admin#109 already. |
That would become a weird circular dependency with the Does injector return
That's a shame, you can add |
I don't think that means move the component to versioned-admin, but add the view mode toggle to history viewer in versioned-admin when merged here |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved with the condition of moving enzyme to dev-dependencies
Sweet, that makes more sense |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking great! Super minor comments
dropdownMenuProps | ||
} = this.props; | ||
let { className } = this.props; | ||
className = classNames(className); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a little confusing - firstly we dereference a prop then we reassign it, unclear as to whether this reassigns the prop which we shouldn't really be doing, I assume it doesn't but only the local variable. Could you instead create a const dropdownClassName = classNames(className);
maybe?
left: 0; | ||
right: 0; | ||
height: 37px; | ||
background: rgba(255, 255, 255, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you could probably use some variables for this, and for the #555
lower. See $gray-darker
etc in variables.scss and maybe use darken($gray-dark, 10%)
if you need to
@@ -0,0 +1 @@ | |||
export const SPLITMODE_BREAKPOINT = 800; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be good to add a comment describing what this is for too :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd love to see this configurable somehow (maybe stored in the redux store instead), but out of scope for this pull request I think
SELECT_EDIT: 'SELECT_EDIT', | ||
SELECT_PREVIEW: 'SELECT_PREVIEW', | ||
SELECT_SPLIT: 'SELECT_SPLIT', | ||
SPLIT_AVAILABLE: 'SPLIT_AVAILABLE', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation is out here
a255c32
to
6b14802
Compare
Added all requested styling improvements. |
a31c6d5
to
f5d203f
Compare
f5d203f
to
9394667
Compare
This React component allows users to toggle between split, edit, and preview mode. It utilises Reactstrap's Dropdown, connects to a Redux store, and its test cases introduce a dependency on the JS testing utility Enzyme.
9394667
to
5108734
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some last requests for SCSS reusability =)
We could write tests for the reducer too, but it's not totally necessary and would only really be for the ACTION_TYPES.SPLIT_AVAILABLE
case
@@ -0,0 +1,122 @@ | |||
.viewmode-dropdown-toggle { | |||
margin-left: auto; | |||
font-size: 13px; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could use $font-size-base
here
} | ||
|
||
.viewModeToggle-chosenView-title { | ||
font-size: 10px; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$font-size-xxs
|
||
.viewModeToggle-chosenView-title { | ||
font-size: 10px; | ||
line-height: 10px; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there's an appropriate line-height variable in _variables.scss or _bootstrap-variables.scss in admin that'd be ideal to use
|
||
.viewmode-dropdown-toggle { | ||
&:before { | ||
font-size: 18px; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$h3-font-size: 17px
or $h2-font-size: 19px
- if you could use one of those we'd be reducing customisation away from core
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125), 0 0 0 0.2rem rgba(86, 107, 141, 0.5); | ||
border-color: #e7ebf0; | ||
background-color: transparent; | ||
color: #566b8d; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any way we can swap these out for variables, or even darken()
or lighten()
calls on variables that are close to these values already?
} | ||
|
||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one empty line at the end would be cool
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks awesome!
This React component allows users to toggle between split, edit, and preview mode.
It utilises Reactstrap's
PopoverFieldDropdown, connects to a Redux store.ViewModeToggle component:
ViewModeToggle component on hover:
Edit view mode chosen and split view mode enabled:
Edit view mode chosen and split view mode disabled:
Preview view mode chosen and hover on disabled split mode:
Sample of ViewModeToggle rendered within Preview component (split mode view chosen)
Sample of ViewModeToggle rendered within CampaignAdminList component
Important: The test cases introduce a dependency on the JS testing utility Enzyme (recommended by React for shallow rendering, see https://reactjs.org/docs/test-utils.html#overview)
A couple of other things to note:
The value for the minimum screen width to enable split view mode is derived from the CSS variableThe value for the minimum screen width is based on the prior CSS variablemedia-breakpoint-down(md)
and currently hard coded inviewModeReducer.js
media-breakpoint-down(md)
used in the media query, minus the width of the expended cms-panel. It is stored in the newly addedconstants.js
file and is used in theviewModeReducer.js
Rather than using Reactstrap's
ToolTip
component, this implementation using the samediv
and styling as the current PHP implementation of the toggle. As a consequence the height for of 37px for this div is hard coded to 'disable' the split view option when the screen width is too narrow. While the first approach is preferable, i.e. using the button's disable property in combination with Reactstrap's ToolTip, no events are fired on the disabled button which is why the latter approach was chosen.Within
ViewModeToggle-test.js
the creation of the shallow renderedwrapper
is repeated for each test group. To avoid unnecessary repetition, , the wrapper could be defined outside of the test groups. In this case the props need to be defined before the wrapper is created. As the tests use rely on different prop values, this would need to be changed within the inidividual tests.