mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1183619 - add a new contact form visual refresh, ui-r=vicky, r=dmose
This commit is contained in:
parent
d4e320ed46
commit
4ce7f6413b
@ -2,6 +2,11 @@
|
||||
* 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/. */
|
||||
|
||||
html {
|
||||
font-size: 10px;
|
||||
font-family: sans-serif; /* XXX will be changed to a system font in bug 1191398 */
|
||||
}
|
||||
|
||||
.contact-import-spinner {
|
||||
display: none;
|
||||
}
|
||||
@ -281,8 +286,26 @@ html[dir="rtl"] .contact > .dropdown-menu {
|
||||
top: auto;
|
||||
}
|
||||
|
||||
.contact-form > .button-group {
|
||||
margin-top: 1rem;
|
||||
.contact-form {
|
||||
padding: 14px; /* Override based on spacing in Mockup */
|
||||
}
|
||||
/* This will effect the header displayed at the top of the contact details form
|
||||
*/
|
||||
.contact-form header {
|
||||
text-align: center;
|
||||
font-size: 1.3rem;
|
||||
font-weight: 500;
|
||||
color: #4a4a4a;
|
||||
}
|
||||
|
||||
.contact-form .form-content-container {
|
||||
height: 24.1rem; /* This height is needed to keep the panel height at 400px and
|
||||
the bottom elements at the bottom of the panel
|
||||
Can likely go away if we switched this pane to flexbox model */
|
||||
padding-top: 4px; /* Based on spacing in Mockup
|
||||
replaced margin-top
|
||||
See http://stackoverflow.com/questions/6204670/css-clean-solution-to-the-margin-collapse-issue-when-floating-an-element
|
||||
*/
|
||||
}
|
||||
|
||||
.contacts-gravatar-promo {
|
||||
|
@ -15,6 +15,8 @@ body {
|
||||
.panel {
|
||||
/* hide the extra margin space that the panel resizer now wants to show */
|
||||
overflow: hidden;
|
||||
font: menu;
|
||||
background-color: #fbfbfb;
|
||||
}
|
||||
|
||||
/* Notifications displayed over tabs */
|
||||
@ -83,8 +85,6 @@ body {
|
||||
|
||||
.tab-view > li {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
line-height: 1.2rem;
|
||||
text-align: center;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
@ -252,20 +252,26 @@ html[dir="rtl"] .tab-view li:nth-child(2).selected ~ .slide-bar {
|
||||
display: block;
|
||||
width: 100%;
|
||||
outline: none;
|
||||
border-radius: 2px;
|
||||
margin: 5px 0;
|
||||
border: 1px solid #ccc;
|
||||
height: 24px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.content-area input:invalid {
|
||||
border-radius: 4px;
|
||||
margin: 10px 0;
|
||||
border: 1px solid #c3c3c3;
|
||||
height: 2.6rem;
|
||||
padding: 0 6px;
|
||||
font-size: 1.1rem;
|
||||
color: #4a4a4a;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.content-area input::-moz-placeholder {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.content-area input:not(.pristine):invalid {
|
||||
border-color: #d74345;
|
||||
box-shadow: 0 0 4px #c43c3e;
|
||||
border: 0.1rem solid #d13f1a;
|
||||
}
|
||||
|
||||
.content-area input:focus {
|
||||
border: 0.1rem solid #5cccee;
|
||||
}
|
||||
|
||||
/* Rooms */
|
||||
@ -475,11 +481,17 @@ html[dir="rtl"] .tab-view li:nth-child(2).selected ~ .slide-bar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.button-group > .button {
|
||||
flex: 1;
|
||||
margin: 0 7px;
|
||||
margin: 0 5px;
|
||||
min-height: 3rem;
|
||||
font-size: 1.2rem;
|
||||
line-height: 1rem;
|
||||
font-weight: 300;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.button-group > .button:first-child {
|
||||
@ -494,11 +506,11 @@ html[dir="rtl"] .tab-view li:nth-child(2).selected ~ .slide-bar {
|
||||
padding: 2px 5px;
|
||||
background-color: #fbfbfb;
|
||||
color: #333;
|
||||
border: 1px solid #c1c1c1;
|
||||
border-radius: 2px;
|
||||
min-height: 26px;
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.2rem;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
@ -507,27 +519,39 @@ html[dir="rtl"] .tab-view li:nth-child(2).selected ~ .slide-bar {
|
||||
|
||||
.button:hover:active {
|
||||
background-color: #ccc;
|
||||
color: #111;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.button.button-accept {
|
||||
background-color: #5bc0a4;
|
||||
border-color: #5bc0a4;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.button.button-accept:hover {
|
||||
background-color: #47b396;
|
||||
border-color: #47b396;
|
||||
background-color: #00a9dc;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.button.button-accept:hover,
|
||||
.button.button-accept:hover:active {
|
||||
background-color: #3aa689;
|
||||
border-color: #3aa689;
|
||||
background-color: #5cccee;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.button.button-cancel {
|
||||
background-color: #ebebeb;
|
||||
border: 0;
|
||||
color: #000;
|
||||
width: 105px; /* based on fixed width of Cancel button from mockup */
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.button.button-cancel:hover,
|
||||
.button.button-cancel:hover:active {
|
||||
background-color: #dcd6d6;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.button.button-cancel:disabled {
|
||||
background-color: #ebebeb;
|
||||
color: #c3c3c3;
|
||||
}
|
||||
|
||||
.button-close {
|
||||
background-color: transparent;
|
||||
background-image: url(../shared/img/icons-10x10.svg#close);
|
||||
|
@ -740,31 +740,40 @@ loop.contacts = (function(_, mozL10n) {
|
||||
render: function() {
|
||||
let cx = React.addons.classSet;
|
||||
let phoneOrEmailRequired = !this.state.email && !this.state.tel;
|
||||
let contactFormMode = "contact-form-mode-" + this.props.mode;
|
||||
let contentAreaClassesLiteral = {
|
||||
"content-area": true,
|
||||
"contact-form": true
|
||||
};
|
||||
contentAreaClassesLiteral[contactFormMode] = true;
|
||||
let contentAreaClasses = cx(contentAreaClassesLiteral);
|
||||
|
||||
return (
|
||||
React.createElement("div", {className: "content-area contact-form"},
|
||||
React.createElement("div", {className: contentAreaClasses},
|
||||
React.createElement("header", null, this.props.mode == "add"
|
||||
? mozL10n.get("add_contact_button")
|
||||
? mozL10n.get("add_contact_title")
|
||||
: mozL10n.get("edit_contact_title")),
|
||||
React.createElement("label", null, mozL10n.get("edit_contact_name_label")),
|
||||
React.createElement("input", {className: cx({pristine: this.state.pristine}),
|
||||
pattern: "\\s*\\S.*",
|
||||
ref: "name",
|
||||
required: true,
|
||||
type: "text",
|
||||
valueLink: this.linkState("name")}),
|
||||
React.createElement("label", null, mozL10n.get("edit_contact_email_label")),
|
||||
React.createElement("input", {className: cx({pristine: this.state.pristine}),
|
||||
ref: "email",
|
||||
required: phoneOrEmailRequired,
|
||||
type: "email",
|
||||
valueLink: this.linkState("email")}),
|
||||
React.createElement("label", null, mozL10n.get("new_contact_fxos_phone_placeholder")),
|
||||
React.createElement("input", {className: cx({pristine: this.state.pristine}),
|
||||
ref: "tel",
|
||||
required: phoneOrEmailRequired,
|
||||
type: "tel",
|
||||
valueLink: this.linkState("tel")}),
|
||||
React.createElement("div", {className: cx({"form-content-container": true})},
|
||||
React.createElement("input", {className: cx({pristine: this.state.pristine}),
|
||||
pattern: "\\s*\\S.*",
|
||||
placeholder: mozL10n.get("contact_form_name_placeholder"),
|
||||
ref: "name",
|
||||
required: true,
|
||||
type: "text",
|
||||
valueLink: this.linkState("name")}),
|
||||
React.createElement("input", {className: cx({pristine: this.state.pristine}),
|
||||
placeholder: mozL10n.get("contact_form_email_placeholder"),
|
||||
ref: "email",
|
||||
required: phoneOrEmailRequired,
|
||||
type: "email",
|
||||
valueLink: this.linkState("email")}),
|
||||
React.createElement("input", {className: cx({pristine: this.state.pristine}),
|
||||
placeholder: mozL10n.get("contact_form_fxos_phone_placeholder"),
|
||||
ref: "tel",
|
||||
required: phoneOrEmailRequired,
|
||||
type: "tel",
|
||||
valueLink: this.linkState("tel")})
|
||||
),
|
||||
React.createElement(ButtonGroup, null,
|
||||
React.createElement(Button, {additionalClass: "button-cancel",
|
||||
caption: mozL10n.get("cancel_button"),
|
||||
|
@ -740,31 +740,40 @@ loop.contacts = (function(_, mozL10n) {
|
||||
render: function() {
|
||||
let cx = React.addons.classSet;
|
||||
let phoneOrEmailRequired = !this.state.email && !this.state.tel;
|
||||
let contactFormMode = "contact-form-mode-" + this.props.mode;
|
||||
let contentAreaClassesLiteral = {
|
||||
"content-area": true,
|
||||
"contact-form": true
|
||||
};
|
||||
contentAreaClassesLiteral[contactFormMode] = true;
|
||||
let contentAreaClasses = cx(contentAreaClassesLiteral);
|
||||
|
||||
return (
|
||||
<div className="content-area contact-form">
|
||||
<div className={contentAreaClasses}>
|
||||
<header>{this.props.mode == "add"
|
||||
? mozL10n.get("add_contact_button")
|
||||
? mozL10n.get("add_contact_title")
|
||||
: mozL10n.get("edit_contact_title")}</header>
|
||||
<label>{mozL10n.get("edit_contact_name_label")}</label>
|
||||
<input className={cx({pristine: this.state.pristine})}
|
||||
pattern="\s*\S.*"
|
||||
ref="name"
|
||||
required
|
||||
type="text"
|
||||
valueLink={this.linkState("name")} />
|
||||
<label>{mozL10n.get("edit_contact_email_label")}</label>
|
||||
<input className={cx({pristine: this.state.pristine})}
|
||||
ref="email"
|
||||
required={phoneOrEmailRequired}
|
||||
type="email"
|
||||
valueLink={this.linkState("email")} />
|
||||
<label>{mozL10n.get("new_contact_fxos_phone_placeholder")}</label>
|
||||
<input className={cx({pristine: this.state.pristine})}
|
||||
ref="tel"
|
||||
required={phoneOrEmailRequired}
|
||||
type="tel"
|
||||
valueLink={this.linkState("tel")} />
|
||||
<div className={cx({"form-content-container": true})}>
|
||||
<input className={cx({pristine: this.state.pristine})}
|
||||
pattern="\s*\S.*"
|
||||
placeholder={mozL10n.get("contact_form_name_placeholder")}
|
||||
ref="name"
|
||||
required
|
||||
type="text"
|
||||
valueLink={this.linkState("name")} />
|
||||
<input className={cx({pristine: this.state.pristine})}
|
||||
placeholder={mozL10n.get("contact_form_email_placeholder")}
|
||||
ref="email"
|
||||
required={phoneOrEmailRequired}
|
||||
type="email"
|
||||
valueLink={this.linkState("email")} />
|
||||
<input className={cx({pristine: this.state.pristine})}
|
||||
placeholder={mozL10n.get("contact_form_fxos_phone_placeholder")}
|
||||
ref="tel"
|
||||
required={phoneOrEmailRequired}
|
||||
type="tel"
|
||||
valueLink={this.linkState("tel")} />
|
||||
</div>
|
||||
<ButtonGroup>
|
||||
<Button additionalClass="button-cancel"
|
||||
caption={mozL10n.get("cancel_button")}
|
||||
|
@ -8,7 +8,8 @@ describe("loop.contacts", function() {
|
||||
var expect = chai.expect;
|
||||
var TestUtils = React.addons.TestUtils;
|
||||
|
||||
var fakeAddContactButtonText = "Fake Add Contact";
|
||||
var fakeAddContactButtonText = "Fake Add Contact Button";
|
||||
var fakeAddContactTitleText = "Fake Add Contact Title";
|
||||
var fakeEditContactButtonText = "Fake Edit Contact";
|
||||
var fakeDoneButtonText = "Fake Done";
|
||||
// The fake contacts array is copied each time mozLoop.contacts.getAll() is called.
|
||||
@ -86,7 +87,9 @@ describe("loop.contacts", function() {
|
||||
navigator.mozLoop = {
|
||||
getStrings: function(entityName) {
|
||||
var textContentValue = "fakeText";
|
||||
if (entityName == "add_contact_button") {
|
||||
if (entityName == "add_contact_title") {
|
||||
textContentValue = fakeAddContactTitleText;
|
||||
} else if (entityName == "add_contact_button") {
|
||||
textContentValue = fakeAddContactButtonText;
|
||||
} else if (entityName == "edit_contact_title") {
|
||||
textContentValue = fakeEditContactButtonText;
|
||||
@ -400,7 +403,7 @@ describe("loop.contacts", function() {
|
||||
|
||||
var header = view.getDOMNode().querySelector("header");
|
||||
expect(header).to.not.equal(null);
|
||||
expect(header.textContent).to.eql(fakeAddContactButtonText);
|
||||
expect(header.textContent).to.eql(fakeAddContactTitleText);
|
||||
});
|
||||
|
||||
it("should render name input", function() {
|
||||
|
@ -18,6 +18,7 @@
|
||||
var AvailabilityDropdown = loop.panel.AvailabilityDropdown;
|
||||
var PanelView = loop.panel.PanelView;
|
||||
var SignInRequestView = loop.panel.SignInRequestView;
|
||||
var ContactDetailsForm = loop.contacts.ContactDetailsForm;
|
||||
var ContactDropdown = loop.contacts.ContactDropdown;
|
||||
var ContactDetail = loop.contacts.ContactDetail;
|
||||
// 1.2. Conversation Window
|
||||
@ -787,6 +788,18 @@
|
||||
notifications: new loop.shared.models.NotificationCollection([{level: "error", message: "Import error"}]),
|
||||
roomStore: roomStore,
|
||||
selectedTab: "contacts"})
|
||||
),
|
||||
React.createElement(FramedExample, {cssClass: "fx-embedded-panel", dashed: true, height: 400,
|
||||
summary: "Contact Form - Add", width: 332},
|
||||
React.createElement("div", {className: "panel"},
|
||||
React.createElement(PanelView, {client: mockClient,
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopLoggedIn,
|
||||
notifications: notifications,
|
||||
roomStore: roomStore,
|
||||
selectedTab: "contacts_add",
|
||||
userProfile: {email: "test@example.com"}})
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
var AvailabilityDropdown = loop.panel.AvailabilityDropdown;
|
||||
var PanelView = loop.panel.PanelView;
|
||||
var SignInRequestView = loop.panel.SignInRequestView;
|
||||
var ContactDetailsForm = loop.contacts.ContactDetailsForm;
|
||||
var ContactDropdown = loop.contacts.ContactDropdown;
|
||||
var ContactDetail = loop.contacts.ContactDetail;
|
||||
// 1.2. Conversation Window
|
||||
@ -788,6 +789,18 @@
|
||||
roomStore={roomStore}
|
||||
selectedTab="contacts" />
|
||||
</Example>
|
||||
<FramedExample cssClass="fx-embedded-panel" dashed={true} height={400}
|
||||
summary="Contact Form - Add" width={332}>
|
||||
<div className="panel">
|
||||
<PanelView client={mockClient}
|
||||
dispatcher={dispatcher}
|
||||
mozLoop={mockMozLoopLoggedIn}
|
||||
notifications={notifications}
|
||||
roomStore={roomStore}
|
||||
selectedTab="contacts_add"
|
||||
userProfile={{email: "test@example.com"}} />
|
||||
</div>
|
||||
</FramedExample>
|
||||
</Section>
|
||||
|
||||
<Section name="Availability Dropdown">
|
||||
|
@ -91,13 +91,13 @@ contacts_search_placesholder=Search…
|
||||
## LOCALIZATION NOTE (new_contact_button): This is the button to open the
|
||||
## new contact sub-panel.
|
||||
new_contact_button=New Contact
|
||||
## LOCALIZATION NOTE (new_contact_name_placeholder, new_contact_email_placeholder):
|
||||
## These are the placeholders for the fields for entering a new contact. Click
|
||||
## the 'New Contact' button to see the fields.
|
||||
new_contact_name_placeholder=Name
|
||||
new_contact_email_placeholder=Email
|
||||
new_contact_fxos_phone_placeholder=Firefox OS Phone
|
||||
new_contact_phone_placeholder2=Phone
|
||||
## LOCALIZATION NOTE (contact_form_*_placeholder):
|
||||
## These are the placeholders for the inputs for entering or editing a contact
|
||||
## Click the 'New Contact' button to see the fields.
|
||||
contact_form_name_placeholder=Name
|
||||
contact_form_email_placeholder=Email
|
||||
contact_form_fxos_phone_placeholder=Firefox OS Phone
|
||||
contact_form_phone_placeholder2=Phone
|
||||
|
||||
contacts_blocked_contacts=Blocked Contacts
|
||||
|
||||
@ -105,6 +105,9 @@ contacts_blocked_contacts=Blocked Contacts
|
||||
## This is the button to actually add the new contact. Click the 'New Contact'
|
||||
## button to see the fields.
|
||||
add_contact_button=Add Contact
|
||||
## LOCALIZATION NOTE(add_contact_title): This is the subtitle of the add contact
|
||||
## panel. It is displayed when Add Contact is selected.
|
||||
add_contact_title=Add Contact
|
||||
### LOCALIZATION NOTE (valid_email_text_description): This is displayed when
|
||||
### the user enters an invalid email address, preventing the addition of the
|
||||
### contact.
|
||||
|
Loading…
Reference in New Issue
Block a user