Bug 1487857 - Part I: Rearranging devices setting view to new design. r=gl,flod

This is part 1 of implementing the redesigned device settings panel. In this patch we are rearranging the existing device settings view to match the new design.

Differential Revision: https://phabricator.services.mozilla.com/D15734

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Micah Tigley 2019-03-19 18:59:24 +00:00
Родитель cce04c17b8
Коммит ab764ec7dc
10 изменённых файлов: 779 добавлений и 174 удалений

Просмотреть файл

@ -70,41 +70,38 @@ responsive.customDeviceName=Custom Device
# name of the device we're staring from, such as "Apple iPhone 6".
responsive.customDeviceNameFromBase=%1$S (Custom)
# LOCALIZATION NOTE (responsive.addDevice): Button text that reveals a form to
# LOCALIZATION NOTE (responsive.addDevice2): Button text that reveals a form to
# be used for adding custom devices.
responsive.addDevice=Add Device
responsive.addDevice2=Add Custom Device
# LOCALIZATION NOTE (responsive.deviceAdderName): Label of form field for the
# name of a new device. The available width is very low, so you might see
# overlapping text if the length is much longer than 5 or so characters.
# name of a new device.
responsive.deviceAdderName=Name
# LOCALIZATION NOTE (responsive.deviceAdderSize): Label of form field for the
# size of a new device. The available width is very low, so you might see
# overlapping text if the length is much longer than 5 or so characters.
# size of a new device.
responsive.deviceAdderSize=Size
# LOCALIZATION NOTE (responsive.deviceAdderPixelRatio): Label of form field for
# the device pixel ratio of a new device. The available width is very low, so you
# might see overlapping text if the length is much longer than 5 or so
# characters.
responsive.deviceAdderPixelRatio=DPR
# LOCALIZATION NOTE (responsive.deviceAdderPixelRatio2): Label of form field for
# the device pixel ratio of a new device.
responsive.deviceAdderPixelRatio2=Device Pixel Ratio
# LOCALIZATION NOTE (responsive.deviceAdderUserAgent): Label of form field for
# the user agent of a new device. The available width is very low, so you might
# see overlapping text if the length is much longer than 5 or so characters.
responsive.deviceAdderUserAgent=UA
# LOCALIZATION NOTE (responsive.deviceAdderUserAgent2): Label of form field for
# the user agent of a new device.
responsive.deviceAdderUserAgent2=User Agent String
# LOCALIZATION NOTE (responsive.deviceAdderTouch): Label of form field for the
# touch input support of a new device. The available width is very low, so you
# might see overlapping text if the length is much longer than 5 or so
# characters.
responsive.deviceAdderTouch=Touch
# LOCALIZATION NOTE (responsive.deviceAdderTouch2): Label of form field for the
# touch input support of a new device.
responsive.deviceAdderTouch2=Touch Screen
# LOCALIZATION NOTE (responsive.deviceAdderSave): Button text that submits a
# form to add a new device.
responsive.deviceAdderSave=Save
# LOCALIZATION NOTE (responsive.deviceAdderCancel): Button text that cancels a
# form to add a new device.
responsive.deviceAdderCancel=Cancel
# LOCALIZATION NOTE (responsive.deviceDetails): Tooltip that appears when
# hovering on a device in the device modal. %1$S is the width of the device.
# %2$S is the height of the device. %3$S is the device pixel ratio value of the
@ -142,3 +139,11 @@ responsive.settingOnboarding.content=New: Change to left-alignment or edit reloa
responsive.customUserAgent=Custom User Agent
responsive.showUserAgentInput=Show user agent
# LOCALIZATION NOTE (responsive.deviceSettings): The header text for the device settings
# view.
responsive.deviceSettings=Device Settings
# LOCALIZATION NOTE (responsive.deviceNameAlreadyInUse): This is the text shown when adding a new
# device with an already existing device name.
responsive.deviceNameAlreadyInUse=Device name already in use

Просмотреть файл

@ -0,0 +1,79 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* eslint-env browser */
"use strict";
const { PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { getFormatStr } = require("../utils/l10n");
const Types = require("../types");
class Device extends PureComponent {
static get propTypes() {
return {
// props.children are the buttons rendered as part of custom device label.
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]),
device: PropTypes.shape(Types.devices).isRequired,
onDeviceCheckboxChange: PropTypes.func.isRequired,
};
}
constructor(props) {
super(props);
this.state = {
// Whether or not the device's input label is checked.
isChecked: this.props.device.isChecked,
};
this.onCheckboxChanged = this.onCheckboxChanged.bind(this);
}
onCheckboxChanged(e) {
this.setState(prevState => {
return { isChecked: !prevState.isChecked };
});
this.props.onDeviceCheckboxChange(e);
}
render() {
const { children, device } = this.props;
const details = getFormatStr(
"responsive.deviceDetails", device.width, device.height,
device.pixelRatio, device.userAgent, device.touch
);
return (
dom.label(
{
className: "device-label",
key: device.name,
title: details,
},
dom.input({
className: "device-input-checkbox",
name: device.name,
type: "checkbox",
value: device.name,
checked: device.isChecked,
onChange: this.onCheckboxChanged,
}),
dom.span({ className: "device-name" },
device.name
),
children
)
);
}
}
module.exports = Device;

Просмотреть файл

@ -0,0 +1,186 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* eslint-env browser */
"use strict";
const { createFactory, createRef, PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const ViewportDimension = createFactory(require("./ViewportDimension"));
const { getStr } = require("../utils/l10n");
const Types = require("../types");
class DeviceForm extends PureComponent {
static get propTypes() {
return {
buttonText: PropTypes.string,
formType: PropTypes.string.isRequired,
device: PropTypes.shape(Types.device).isRequired,
onSave: PropTypes.func.isRequired,
validateName: PropTypes.func.isRequired,
viewportTemplate: PropTypes.shape(Types.viewport).isRequired,
onDeviceFormHide: PropTypes.func.isRequired,
onDeviceFormShow: PropTypes.func.isRequired,
};
}
constructor(props) {
super(props);
const {
height,
width,
} = this.props.viewportTemplate;
this.state = {
isShown: false,
height,
width,
};
this.nameInputRef = createRef();
this.pixelRatioInputRef = createRef();
this.touchInputRef = createRef();
this.userAgentInputRef = createRef();
this.onChangeSize = this.onChangeSize.bind(this);
this.onDeviceFormHide = this.onDeviceFormHide.bind(this);
this.onDeviceFormShow = this.onDeviceFormShow.bind(this);
this.onDeviceFormSave = this.onDeviceFormSave.bind(this);
}
onChangeSize(_, width, height) {
this.setState({
width,
height,
});
}
onDeviceFormSave() {
if (!this.pixelRatioInputRef.current.checkValidity()) {
return;
}
if (!this.props.validateName(this.nameInputRef.current.value)) {
this.nameInputRef.current
.setCustomValidity(getStr("responsive.deviceNameAlreadyInUse"));
return;
}
this.props.onSave({
name: this.nameInputRef.current.value.trim(),
width: this.state.width,
height: this.state.height,
pixelRatio: parseFloat(this.pixelRatioInputRef.current.value),
userAgent: this.userAgentInputRef.current.value,
touch: this.touchInputRef.current.checked,
});
this.onDeviceFormHide();
}
onDeviceFormHide() {
this.setState({ isShown: false });
// Ensure that we have onDeviceFormHide before calling it.
if (this.props.onDeviceFormHide) {
this.props.onDeviceFormHide();
}
}
onDeviceFormShow() {
this.setState({ isShown: true });
// Ensure that we have onDeviceFormShow before calling it.
if (this.props.onDeviceFormShow) {
this.props.onDeviceFormShow();
}
}
render() {
const { buttonText, device, formType } = this.props;
const { isShown, width, height } = this.state;
if (!isShown) {
return (
dom.button(
{
id: `device-${formType}-button`,
className: "devtools-button",
onClick: this.onDeviceFormShow,
},
buttonText,
)
);
}
return (
dom.form({ id: "device-form" },
dom.label({ id: "device-form-name", className: formType },
dom.span({ className: "device-form-label" },
getStr("responsive.deviceAdderName")
),
dom.input({
defaultValue: device.name,
ref: this.nameInputRef,
})
),
dom.label({ id: "device-form-size" },
dom.span({ className: "device-form-label" },
getStr("responsive.deviceAdderSize")
),
ViewportDimension({
viewport: { width, height },
doResizeViewport: this.onChangeSize,
onRemoveDeviceAssociation: () => {},
})
),
dom.label({ id: "device-form-pixel-ratio" },
dom.span({ className: "device-form-label" },
getStr("responsive.deviceAdderPixelRatio2")
),
dom.input({
type: "number",
step: "any",
defaultValue: device.pixelRatio,
ref: this.pixelRatioInputRef,
})
),
dom.label({ id: "device-form-user-agent" },
dom.span({ className: "device-form-label" },
getStr("responsive.deviceAdderUserAgent2")
),
dom.input({
defaultValue: device.userAgent,
ref: this.userAgentInputRef,
})
),
dom.label({ id: "device-form-touch" },
dom.input({
defaultChecked: device.touch,
type: "checkbox",
ref: this.touchInputRef,
}),
dom.span({ className: "device-form-label" },
getStr("responsive.deviceAdderTouch2")
)
),
dom.div({ className: "device-form-buttons" },
dom.button({ id: "device-form-save", onClick: this.onDeviceFormSave },
getStr("responsive.deviceAdderSave")
),
dom.button({ id: "device-form-cancel", onClick: this.onDeviceFormHide },
getStr("responsive.deviceAdderCancel")
)
)
)
);
}
}
module.exports = DeviceForm;

Просмотреть файл

@ -0,0 +1,70 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* eslint-env browser */
"use strict";
const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const Types = require("../types");
const Device = createFactory(require("./Device"));
class DeviceList extends PureComponent {
static get propTypes() {
return {
devices: PropTypes.shape(Types.devices).isRequired,
onDeviceCheckboxChange: PropTypes.func.isRequired,
onRemoveCustomDevice: PropTypes.func.isRequired,
type: PropTypes.string.isRequired,
};
}
renderCustomDevice(device) {
const { onRemoveCustomDevice, onDeviceCheckboxChange, type } = this.props;
// Show a remove button for custom devices.
const removeDeviceButton = dom.button({
id: "device-editor-remove",
className: "device-remove-button devtools-button",
onClick: () => onRemoveCustomDevice(device),
});
return Device(
{
device,
key: device.name,
type,
onDeviceCheckboxChange,
},
removeDeviceButton
);
}
render() {
const { devices, type, onDeviceCheckboxChange } = this.props;
return (
dom.div({ className: "device-list"},
devices[type].map(device => {
if (type === "custom") {
return this.renderCustomDevice(device);
}
return Device({
device,
key: device.name,
type,
onDeviceCheckboxChange,
});
})
)
);
}
}
module.exports = DeviceList;

Просмотреть файл

@ -10,9 +10,10 @@ const { createFactory, PureComponent } = require("devtools/client/shared/vendor/
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const DeviceAdder = createFactory(require("./DeviceAdder"));
const DeviceForm = createFactory(require("./DeviceForm"));
const DeviceList = createFactory(require("./DeviceList"));
const { getStr, getFormatStr } = require("../utils/l10n");
const { getFormatStr, getStr } = require("../utils/l10n");
const Types = require("../types");
class DeviceModal extends PureComponent {
@ -31,7 +32,9 @@ class DeviceModal extends PureComponent {
constructor(props) {
super(props);
this.state = {};
this.state = {
isDeviceFormShown: false,
};
for (const type of this.props.devices.types) {
for (const device of this.props.devices[type]) {
this.state[device.name] = device.displayed;
@ -40,8 +43,11 @@ class DeviceModal extends PureComponent {
this.onAddCustomDevice = this.onAddCustomDevice.bind(this);
this.onDeviceCheckboxChange = this.onDeviceCheckboxChange.bind(this);
this.onDeviceFormShow = this.onDeviceFormShow.bind(this);
this.onDeviceFormHide = this.onDeviceFormHide.bind(this);
this.onDeviceModalSubmit = this.onDeviceModalSubmit.bind(this);
this.onKeyDown = this.onKeyDown.bind(this);
this.validateAddDeviceFormNameField = this.validateAddDeviceFormNameField.bind(this);
}
componentDidMount() {
@ -69,6 +75,14 @@ class DeviceModal extends PureComponent {
});
}
onDeviceFormShow() {
this.setState({ isDeviceFormShown: true });
}
onDeviceFormHide() {
this.setState({ isDeviceFormShown: false });
}
onDeviceModalSubmit() {
const {
devices,
@ -115,24 +129,100 @@ class DeviceModal extends PureComponent {
}
}
renderAddDeviceForm(devices, viewportTemplate) {
// If a device is currently selected, fold its attributes into a single object for use
// as the starting values of the form. If no device is selected, use the values for
// the current window.
const deviceTemplate = viewportTemplate;
if (viewportTemplate.device) {
const device = devices[viewportTemplate.deviceType].find(d => {
return d.name == viewportTemplate.device;
});
Object.assign(deviceTemplate, {
pixelRatio: device.pixelRatio,
userAgent: device.userAgent,
touch: device.touch,
name: getFormatStr("responsive.customDeviceNameFromBase", device.name),
});
} else {
Object.assign(deviceTemplate, {
pixelRatio: window.devicePixelRatio,
userAgent: navigator.userAgent,
touch: false,
name: getStr("responsive.customDeviceName"),
});
}
return (
DeviceForm({
formType: "add",
buttonText: getStr("responsive.addDevice2"),
device: deviceTemplate,
onDeviceFormHide: this.onDeviceFormHide,
onDeviceFormShow: this.onDeviceFormShow,
onSave: this.onAddCustomDevice,
validateName: this.validateAddDeviceFormNameField,
viewportTemplate,
})
);
}
renderDevices() {
const sortedDevices = {};
for (const type of this.props.devices.types) {
sortedDevices[type] = this.props.devices[type]
.sort((a, b) => a.name.localeCompare(b.name));
sortedDevices[type].forEach(device => {
device.isChecked = this.state[device.name];
});
}
return (
this.props.devices.types.map(type => {
return sortedDevices[type].length ?
dom.div(
{
className: `device-type device-type-${type}`,
key: type,
},
dom.header({ className: "device-header" }, type),
DeviceList({
devices: sortedDevices,
type,
onDeviceCheckboxChange: this.onDeviceCheckboxChange,
onRemoveCustomDevice: this.props.onRemoveCustomDevice,
})
)
:
null;
})
);
}
/**
* Validates the name field's value by checking if the added device's name already
* exists in the custom devices list.
*
* @param {String} value
* The input field value for the device name.
* @return {Boolean} true if device name is valid, false otherwise.
*/
validateAddDeviceFormNameField(value) {
const { devices } = this.props;
const nameFieldValue = value.trim();
const deviceFound = devices.custom.find(device => device.name == nameFieldValue);
return !deviceFound;
}
render() {
const {
deviceAdderViewportTemplate,
devices,
onRemoveCustomDevice,
onUpdateDeviceModal,
} = this.props;
const {
onAddCustomDevice,
} = this;
const sortedDevices = {};
for (const type of devices.types) {
sortedDevices[type] = Object.assign([], devices[type])
.sort((a, b) => a.name.localeCompare(b.name));
}
return (
dom.div(
{
@ -140,65 +230,26 @@ class DeviceModal extends PureComponent {
className: this.props.devices.isModalOpen ? "opened" : "closed",
},
dom.div({ className: "device-modal" },
dom.button({
id: "device-close-button",
className: "devtools-button",
onClick: () => onUpdateDeviceModal(false),
}),
dom.div({ className: "device-modal-content" },
devices.types.map(type => {
return dom.div(
{
className: `device-type device-type-${type}`,
key: type,
},
dom.header({ className: "device-header" },
type
),
sortedDevices[type].map(device => {
const details = getFormatStr(
"responsive.deviceDetails", device.width, device.height,
device.pixelRatio, device.userAgent, device.touch
);
let removeDeviceButton;
if (type == "custom") {
removeDeviceButton = dom.button({
className: "device-remove-button devtools-button",
onClick: () => onRemoveCustomDevice(device),
});
}
return dom.label(
{
className: "device-label",
key: device.name,
title: details,
},
dom.input({
className: "device-input-checkbox",
type: "checkbox",
value: device.name,
checked: this.state[device.name],
onChange: this.onDeviceCheckboxChange,
}),
dom.span(
{
className: "device-name",
},
device.name
),
removeDeviceButton
);
dom.div({ className: "device-modal-header" },
!this.state.isDeviceFormShown ?
dom.header({ className: "device-modal-title" },
getStr("responsive.deviceSettings"),
dom.button({
id: "device-close-button",
className: "devtools-button",
onClick: () => onUpdateDeviceModal(false),
})
);
})
)
:
null,
this.renderAddDeviceForm(devices, deviceAdderViewportTemplate)
),
dom.div({
className: `device-modal-content
${this.state.isDeviceFormShown ? " form-shown" : ""}`,
},
this.renderDevices()
),
DeviceAdder({
devices,
viewportTemplate: deviceAdderViewportTemplate,
onAddCustomDevice,
}),
dom.button(
{
id: "device-submit-button",

Просмотреть файл

@ -7,7 +7,9 @@
DevToolsModules(
'App.js',
'Browser.js',
'DeviceAdder.js',
'Device.js',
'DeviceForm.js',
'DeviceList.js',
'DeviceModal.js',
'DevicePixelRatioMenu.js',
'DeviceSelector.js',

Просмотреть файл

@ -11,6 +11,7 @@
--submit-button-active-color: var(--theme-body-color);
--viewport-active-color: #3b3b3b;
--input-invalid-border-color: var(--red-60);
--custom-device-button-hover: var(--grey-30);
}
:root.theme-dark {
@ -19,6 +20,7 @@
--submit-button-active-color: var(--theme-selection-color);
--viewport-active-color: #fcfcfc;
--input-invalid-border-color: var(--red-50);
--custom-device-button-hover: var(--grey-10-a20)
}
* {
@ -395,6 +397,8 @@ body,
}
.device-modal {
display: grid;
grid-template-rows: minmax(80px, auto) auto 20px;
background-color: var(--theme-toolbar-background);
border: 1px solid var(--theme-splitter-color);
border-radius: 2px;
@ -405,10 +409,12 @@ body,
bottom: 0;
left: 0;
right: 0;
width: 800px;
max-width: 90%;
height: 650px;
width: 90%;
height: 90%;
max-width: 750px;
max-height: 730px;
z-index: 1;
overflow: hidden;
}
/* Handles the opening/closing of the modal */
@ -432,12 +438,98 @@ body,
}
.device-modal-content {
display: flex;
flex-direction: column;
flex-wrap: wrap;
display: grid;
grid-row-gap: 30px;
overflow: auto;
height: 515px;
margin: 20px 20px 0;
height: 100%;
padding: 10px 32px 50px 32px;
}
.device-modal-content.form-shown {
padding-top: 30px;
}
/* On screens that are >750px*/
@media (min-width: 750px) {
#device-form {
grid-template-areas: "name size dpr"
"user-agent touch buttons";
}
#device-form-name input,
#device-form-user-agent input {
width: 350px;
}
.device-modal-content {
grid-template-columns: 1fr 1fr 1fr;
grid-template-areas: "phone phone custom"
"tablet laptop tv";
}
}
/* On screens that are between 450px and 749px */
@media (min-width: 450px) and (max-width: 749px) {
#device-form {
grid-template-areas: "name size"
"user-agent dpr"
"touch buttons";
grid-template-columns: 2fr 1fr;
}
#device-form-name {
grid-area: name;
}
#device-form-name input,
#device-form-user-agent input {
width: 100%;
}
.device-modal-content {
grid-template-columns: 1fr 1fr;
grid-template-areas: "phone phone"
"tablet laptop"
"tv custom";
}
}
/* On screens that are <450px */
@media (max-width: 449px) {
#device-form {
grid-template-areas: "name"
"size"
"dpr"
"user-agent"
"touch"
"buttons";
}
#device-form-name input,
#device-form-user-agent input {
width: 90%;
}
#device-form-size {
justify-self: unset;
}
.device-modal-content {
grid-template-areas: "phone"
"phone"
"tablet"
"laptop"
"tv"
"custom";
}
.device-type.device-type-phones .device-list {
grid-template-columns: 1fr;
}
.device-modal-header {
flex-direction: column;
}
}
#device-close-button {
@ -453,28 +545,65 @@ body,
.device-type {
display: flex;
flex-direction: column;
padding: 10px;
}
.device-header {
font-weight: bold;
font-size: 17px;
margin-bottom: 7px;
height: 20px;
text-transform: capitalize;
padding: 0 0 3px 23px;
}
.device-label {
color: var(--theme-body-color);
padding-bottom: 3px;
padding-bottom: 5px;
padding-top: 5px;
display: flex;
align-items: center;
/* Largest size without horizontal scrollbars */
max-width: 181px;
}
.device-label > button {
visibility: hidden;
}
.device-label:focus-within > button,
.device-label:hover > button {
visibility: visible;
}
.device-label:focus-within,
.device-label:hover {
background-color: var(--toolbarbutton-hover-background);
}
.device-modal-header {
display: flex;
justify-content: space-between;
z-index: 1;
}
.device-modal-header > #device-add-button {
margin: 30px 75px 0 30px;
}
.device-modal-header > #device-form {
margin-top: 15px;
}
.device-list {
display: grid;
font-size: 13px;
}
.device-input-checkbox {
margin-right: 5px;
}
.device-modal-title {
font-size: 22px;
margin: 30px 0 0px 30px;
}
.device-name {
flex: 1;
}
@ -506,85 +635,168 @@ body,
}
/**
* Device Adder
* Device Form
*/
#device-adder {
display: flex;
flex-direction: column;
margin: 0 20px;
#device-form {
display: grid;
width: 100%;
background-color: var(--theme-toolbar-background);
min-height: 150px;
padding-left: 20px;
padding-bottom: 10px;
border-bottom: 1px solid var(--theme-splitter-color);
overflow: auto;
}
#device-adder-content {
display: flex;
#device-add-button {
margin-right: 70px;
}
#device-adder-column-1 {
flex: 1;
margin-right: 10px;
}
#device-adder-column-2 {
flex: 2;
}
#device-adder button {
background-color: var(--theme-tab-toolbar-background);
#device-add-button,
#device-form button {
background-color: rgba(12, 12, 13, 0.1);
border: 1px solid var(--theme-splitter-color);
border-radius: 2px;
color: var(--theme-body-color);
margin: 0 auto;
cursor: pointer;
width: 167px;
height: 32px;
}
#device-adder label {
#device-editor-remove {
cursor: pointer;
}
#device-editor-remove.device-remove-button:focus-within,
#device-editor-remove.device-remove-button:hover {
background-color: var(--custom-device-button-hover);
}
#device-form label {
display: flex;
margin-bottom: 5px;
align-items: center;
flex-direction: column;
margin: 5px;
}
#device-adder label > input,
#device-adder label > .viewport-dimension {
flex: 1;
margin: 0;
}
#device-adder label > .viewport-dimension {
border-bottom: 1px solid transparent;
#device-form label > .viewport-dimension {
color: var(--theme-body-color-inactive);
display: flex;
align-items: center;
justify-content: center;
transition: all 0.25s ease;
}
#device-adder label > .viewport-dimension.editing {
border-bottom-color: var(--theme-selection-background);
}
#device-adder label > .viewport-dimension.editing.invalid {
border-bottom-color: #d92215;
}
#device-adder input {
#device-form input {
background: transparent;
border: 1px solid transparent;
border: 1px solid;
border-radius: 2px;
text-align: center;
color: var(--theme-body-color-inactive);
transition: all 0.25s ease;
}
#device-adder input:focus {
color: var(--viewport-active-color);
#device-form #device-form-name input,
#device-form #device-form-user-agent input {
text-align: left;
padding-left: 12px;
padding-right: 12px;
}
#device-adder label > input:focus,
#device-adder label > .viewport-dimension:focus {
border-bottom: 1px solid var(--theme-selection-background);
#device-form input:focus {
color: var(--viewport-active-color);
border-color: var(--blue-55);
}
#device-form label > input:focus,
#device-form label > .viewport-dimension:focus {
outline: none;
}
.device-adder-label {
display: inline-block;
margin-right: 5px;
min-width: 35px;
#device-form-pixel-ratio {
grid-area: dpr;
}
#device-form-pixel-ratio input {
-moz-appearance: textfield;
}
#device-form-user-agent {
grid-area: user-agent;
}
#device-form-name input,
#device-form-pixel-ratio input,
#device-form-user-agent input,
#device-form-size input {
height: 35px;
}
#device-form #device-form-touch {
flex-direction: row;
grid-area: touch;
}
#device-form-touch .device-form-label {
align-self: center;
margin-left: 5px;
}
#device-form #device-form-save {
background-color: #0060DF;
color: #fff;
border:1px solid #0060DF;
width: 50px;
}
#device-form-size {
grid-area: size;
}
#device-form-size input,
#device-form #device-form-cancel {
width: 60px;
}
#device-form-save,
#device-form-cancel {
align-self: center;
}
.device-form-buttons {
display: flex;
grid-area: buttons;
justify-content: space-evenly;
width: 154px;
}
.device-form-label {
display: inline-block;
margin: 0 5px 5px 0;
min-width: 35px;
font-size: 13px;
}
/* Device Types */
.device-type-phones {
grid-area: phone;
}
.device-type-phones .device-list {
grid-template-columns: repeat(2, auto);
}
.device-type-custom {
grid-area: custom;
align-self: start;
}
.device-type-tablets {
grid-area: tablet;
}
.device-type-laptops {
grid-area: laptop;
}
.device-type-televisions {
grid-area: tv;
}

Просмотреть файл

@ -37,7 +37,7 @@ addRDMTask(TEST_URL, async function({ ui }) {
await openDeviceModal(ui);
info("Reveal device adder form, check that defaults match the viewport");
const adderShow = document.getElementById("device-adder-show");
const adderShow = document.getElementById("device-add-button");
adderShow.click();
testDeviceAdder(ui, {
name: "Custom Device",
@ -82,7 +82,7 @@ addRDMTask(TEST_URL, async function({ ui }) {
await openDeviceModal(ui);
info("Reveal device adder form, check that defaults are based on selected device");
const adderShow = document.getElementById("device-adder-show");
const adderShow = document.getElementById("device-add-button");
adderShow.click();
testDeviceAdder(ui, Object.assign({}, device, {
name: "Test Device (Custom)",
@ -126,7 +126,7 @@ addRDMTask(TEST_URL, async function({ ui }) {
await openDeviceModal(ui);
info("Reveal device adder form");
const adderShow = document.querySelector("#device-adder-show");
const adderShow = document.querySelector("#device-add-button");
adderShow.click();
info("Fill out device adder form by setting details to unicode device and save");
@ -171,12 +171,12 @@ addRDMTask(TEST_URL, async function({ ui }) {
function testDeviceAdder(ui, expected) {
const { document } = ui.toolWindow;
const nameInput = document.querySelector("#device-adder-name input");
const nameInput = document.querySelector("#device-form-name input");
const [ widthInput, heightInput ] =
document.querySelectorAll("#device-adder-size input");
const pixelRatioInput = document.querySelector("#device-adder-pixel-ratio input");
const userAgentInput = document.querySelector("#device-adder-user-agent input");
const touchInput = document.querySelector("#device-adder-touch input");
document.querySelectorAll("#device-form-size input");
const pixelRatioInput = document.querySelector("#device-form-pixel-ratio input");
const userAgentInput = document.querySelector("#device-form-user-agent input");
const touchInput = document.querySelector("#device-form-touch input");
is(nameInput.value, expected.name, "Device name matches");
is(parseInt(widthInput.value, 10), expected.width, "Width matches");

Просмотреть файл

@ -39,14 +39,14 @@ addRDMTask(TEST_URL, async function({ ui }) {
await openDeviceModal(ui);
info("Reveal device adder form");
let adderShow = document.querySelector("#device-adder-show");
let adderShow = document.querySelector("#device-add-button");
adderShow.click();
info("Add test device 1");
await addDeviceInModal(ui, device1);
info("Reveal device adder form");
adderShow = document.querySelector("#device-adder-show");
adderShow = document.querySelector("#device-add-button");
adderShow.click();
info("Add test device 2");

Просмотреть файл

@ -480,12 +480,12 @@ function addDeviceInModal(ui, device) {
ui.toolWindow.require("devtools/client/shared/vendor/react-dom-test-utils");
const { document, store } = ui.toolWindow;
const nameInput = document.querySelector("#device-adder-name input");
const nameInput = document.querySelector("#device-form-name input");
const [ widthInput, heightInput ] =
document.querySelectorAll("#device-adder-size input");
const pixelRatioInput = document.querySelector("#device-adder-pixel-ratio input");
const userAgentInput = document.querySelector("#device-adder-user-agent input");
const touchInput = document.querySelector("#device-adder-touch input");
document.querySelectorAll("#device-form-size input");
const pixelRatioInput = document.querySelector("#device-form-pixel-ratio input");
const userAgentInput = document.querySelector("#device-form-user-agent input");
const touchInput = document.querySelector("#device-form-touch input");
nameInput.value = device.name;
Simulate.change(nameInput);
@ -503,7 +503,7 @@ function addDeviceInModal(ui, device) {
Simulate.change(touchInput);
const existingCustomDevices = store.getState().devices.custom.length;
const adderSave = document.querySelector("#device-adder-save");
const adderSave = document.querySelector("#device-form-save");
const saved = waitUntilState(store, state =>
state.devices.custom.length == existingCustomDevices + 1
);