mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-09-21 07:46:06 +08:00
feat(signatures): add signature support
Summary: Add signatures back in. Extract contenteditable css to its own file instead of being bundled with the composer. Test Plan: manual Reviewers: juan, bengotow Reviewed By: bengotow Differential Revision: https://phab.nylas.com/D2295
This commit is contained in:
parent
6a4613b4a1
commit
83b0a4db5f
|
@ -24,7 +24,7 @@
|
|||
font-size: @font-size-small;
|
||||
}
|
||||
|
||||
.compose-body #contenteditable {
|
||||
.compose-body .contenteditable {
|
||||
code.var {
|
||||
font: inherit;
|
||||
padding:0;
|
||||
|
|
|
@ -6,35 +6,10 @@ module.exports =
|
|||
DraftStore.registerExtension(SignatureDraftExtension)
|
||||
|
||||
@preferencesTab = new PreferencesUIStore.TabItem
|
||||
# TODO: Fix RetinaImg to handle plugin images
|
||||
icon: ->
|
||||
if process.platform is "win32"
|
||||
"nylas://composer-signature/images/ic-settings-signatures-win32@2x.png"
|
||||
else
|
||||
"nylas://composer-signature/images/ic-settings-signatures@2x.png"
|
||||
tabId: "Signatures"
|
||||
displayName: "Signatures"
|
||||
component: require "./preferences-signatures"
|
||||
|
||||
# TODO Re-enable when fixed!
|
||||
# PreferencesUIStore.registerPreferencesTab(@preferencesTab)
|
||||
|
||||
## TODO
|
||||
# PreferencesUIStore.registerPreferences "composer-signatures", [
|
||||
# {
|
||||
# section: PreferencesUIStore.Section.Signatures
|
||||
# type: "richtext"
|
||||
# label: "Signature:"
|
||||
# perAccount: true
|
||||
# defaultValue: "- Sent from N1"
|
||||
# }, {
|
||||
# section: PreferencesUIStore.Section.Signatures
|
||||
# type: "toggle"
|
||||
# label: "Include on replies"
|
||||
# defaultValue: true
|
||||
# }
|
||||
# ]
|
||||
|
||||
deactivate: ->
|
||||
DraftStore.unregisterExtension(SignatureDraftExtension)
|
||||
PreferencesUIStore.unregisterPreferencesTab(@preferencesTab.sectionId)
|
||||
|
|
|
@ -72,8 +72,7 @@ class PreferencesSignatures extends React.Component
|
|||
ref="signatureInput"
|
||||
value={@state.currentSignature}
|
||||
onChange={@_onEditSignature}
|
||||
spellcheck={false}
|
||||
floatingToolbar={false} />
|
||||
spellcheck={false} />
|
||||
|
||||
_onEditSignature: (event) =>
|
||||
html = event.target.value
|
||||
|
@ -97,7 +96,7 @@ class PreferencesSignatures extends React.Component
|
|||
<div className="section-title">
|
||||
Signature for: {@_renderAccountPicker()}
|
||||
</div>
|
||||
<div>
|
||||
<div className="signature-wrap">
|
||||
{@_renderCurrentSignature()}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
.container-signatures {
|
||||
max-width: 640px;
|
||||
|
||||
.signature-wrap {
|
||||
position: relative;
|
||||
border: 1px solid @input-border-color;
|
||||
padding: 10px;
|
||||
margin-top: 20px;
|
||||
min-height: 200px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.section-body {
|
||||
padding: 10px 0 0 0;
|
||||
|
||||
.menu {
|
||||
border: solid thin #CCC;
|
||||
margin-right: 5px;
|
||||
min-height: 200px;
|
||||
.menu-items {
|
||||
margin:0;
|
||||
padding:0;
|
||||
list-style: none;
|
||||
|
||||
li { padding: 6px; }
|
||||
}
|
||||
}
|
||||
.menu-horizontal {
|
||||
height: 100%;
|
||||
.menu-items {
|
||||
height:100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
li {
|
||||
text-align:center;
|
||||
width:40px;
|
||||
display:inline-block;
|
||||
padding:8px 16px 8px 16px;
|
||||
border-right: solid thin #CCC;
|
||||
}
|
||||
}
|
||||
}
|
||||
.signature-area {
|
||||
border: solid thin #CCC;
|
||||
min-height: 200px;
|
||||
}
|
||||
.menu-footer {
|
||||
border: solid thin #CCC;
|
||||
overflow: auto;
|
||||
}
|
||||
.signature-footer {
|
||||
border: solid thin #CCC;
|
||||
overflow: auto;
|
||||
|
||||
.edit-html-button {
|
||||
float: right;
|
||||
margin: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,12 +21,6 @@ body.platform-win32 {
|
|||
border: 0;
|
||||
}
|
||||
}
|
||||
.floating-toolbar {
|
||||
border-radius: 0;
|
||||
input, input:focus {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.composer-inner-wrap {
|
||||
|
@ -128,7 +122,7 @@ body.platform-win32 {
|
|||
padding-top: 12px;
|
||||
}
|
||||
|
||||
input, textarea, div[contenteditable] {
|
||||
input, textarea {
|
||||
color: @text-color;
|
||||
position: relative;
|
||||
display: block;
|
||||
|
@ -232,23 +226,9 @@ body.platform-win32 {
|
|||
}
|
||||
|
||||
div[contenteditable] {
|
||||
font-size: @font-size;
|
||||
line-height: 1.4;
|
||||
min-height: @compose-min-height;
|
||||
padding: @spacing-standard;
|
||||
padding-top: 20px;
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.contenteditable-container {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
spelling.misspelled {
|
||||
background: linear-gradient(45deg, transparent, transparent 49%, red 49%, transparent 51%);
|
||||
background-size: 2px 2px;
|
||||
background-position: bottom;
|
||||
background-repeat-y: no-repeat;
|
||||
padding: 20px @spacing-standard 0 @spacing-standard;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -291,17 +271,6 @@ body.platform-win32 {
|
|||
.compose-body {
|
||||
margin-bottom: 0;
|
||||
position: relative;
|
||||
|
||||
.contenteditable-container {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
|
||||
div[contenteditable] {
|
||||
height: auto;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -309,6 +278,8 @@ body.platform-win32 {
|
|||
.compose-body {
|
||||
div[contenteditable] {
|
||||
min-height: @line-height-computed;
|
||||
margin-bottom: 30px;
|
||||
padding: 20px @spacing-standard 0 @spacing-standard;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,7 +304,6 @@ body.platform-win32 {
|
|||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////
|
||||
// participants-text-field.cjsx //
|
||||
//////////////////////////////////
|
||||
|
@ -362,123 +332,3 @@ body.platform-win32 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////
|
||||
// floating-toolbar.cjsx //
|
||||
///////////////////////////
|
||||
.floating-toolbar {
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
|
||||
background: #fff;
|
||||
box-shadow: 0 10px 20px rgba(0,0,0,0.19), inset 0 0 1px rgba(0,0,0,0.5);
|
||||
border-radius: @border-radius-base;
|
||||
color: @text-color;
|
||||
|
||||
transition-duration: .15s;
|
||||
transition-property: opacity, margin;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
margin-top: 3px;
|
||||
|
||||
&.toolbar-visible {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.toolbar-pointer {
|
||||
position: absolute;
|
||||
width: 22.5px;
|
||||
height: 10px;
|
||||
background: transparent url('images/tooltip/tooltip-bg-pointer@2x.png') no-repeat;
|
||||
background-size: 22.5px 9.5px;
|
||||
margin-left: -11.2px;
|
||||
}
|
||||
|
||||
&.above {
|
||||
.toolbar-pointer {
|
||||
transform: rotate(0deg);
|
||||
bottom: -9px;
|
||||
}
|
||||
}
|
||||
&.below {
|
||||
.toolbar-pointer {
|
||||
transform: rotate(180deg);
|
||||
top: -9px;
|
||||
}
|
||||
}
|
||||
|
||||
.floating-toolbar-input {
|
||||
display: inline;
|
||||
// The hardcoded numbers here represent the widths of the various
|
||||
// icons and buttons that surround the input. They are hardcoded here
|
||||
// because CSS does the calculation for us that we'd otherwise have to
|
||||
// do in React before the element renders to the page.
|
||||
width: calc(~"100% - 62px");
|
||||
&.with-remove {
|
||||
width: calc(~"100% - 95px");
|
||||
}
|
||||
color: @text-color;
|
||||
}
|
||||
|
||||
@padding: 0.5em;
|
||||
.btn {
|
||||
background: transparent;
|
||||
font-size: 16px;
|
||||
height: auto;
|
||||
border-radius: 0;
|
||||
padding: @padding*0.75 @padding;
|
||||
margin: 0;
|
||||
color: @text-color;
|
||||
box-shadow: none;
|
||||
&:first-child {
|
||||
padding-left: 1.5*@padding;
|
||||
}
|
||||
&:last-child {
|
||||
padding-right: 1.5*@padding;
|
||||
}
|
||||
&:hover, &:active {
|
||||
color: lighten(@text-color-link, 10%);
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-btn-icon {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
padding: 0 @padding;
|
||||
}
|
||||
|
||||
button.btn.toolbar-btn {
|
||||
@padding-top: 4px;
|
||||
@padding-left: 8px;
|
||||
|
||||
width: 12.5px + 2*@padding-left;
|
||||
height: 12.5px + 2*@padding-top;
|
||||
margin: 7.5px 0;
|
||||
box-shadow: none;
|
||||
border: 0;
|
||||
border-right: 1px solid @border-color-divider;
|
||||
&:last-child { border-right: 0 }
|
||||
|
||||
background: no-repeat;
|
||||
background-size: 12.5px 12.5px;
|
||||
background-position: @padding-left @padding-top;
|
||||
&.btn-bold { background-image: url("images/composer/tooltip-bold-black@2x.png") }
|
||||
&.btn-italic { background-image: url("images/composer/tooltip-italic-black@2x.png") }
|
||||
&.btn-underline { background-image: url("images/composer/tooltip-underline-black@2x.png") }
|
||||
&.btn-link { background-image: url("images/composer/tooltip-link-black@2x.png") }
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background: no-repeat;
|
||||
background-size: 12.5px 12.5px;
|
||||
background-position: @padding-left @padding-top;
|
||||
&.btn-bold { background-image: url("images/composer/tooltip-bold-blue@2x.png") }
|
||||
&.btn-italic { background-image: url("images/composer/tooltip-italic-blue@2x.png") }
|
||||
&.btn-underline { background-image: url("images/composer/tooltip-underline-blue@2x.png") }
|
||||
&.btn-link { background-image: url("images/composer/tooltip-link-blue@2x.png") }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,65 +103,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.container-signatures {
|
||||
.contenteditable-container {
|
||||
border: 1px solid @input-border-color;
|
||||
padding: 10px;
|
||||
margin-top: 20px;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.section-body {
|
||||
padding: 10px 0 0 0;
|
||||
|
||||
.menu {
|
||||
border: solid thin #CCC;
|
||||
margin-right: 5px;
|
||||
min-height: 200px;
|
||||
.menu-items {
|
||||
margin:0;
|
||||
padding:0;
|
||||
list-style: none;
|
||||
|
||||
li { padding: 6px; }
|
||||
}
|
||||
}
|
||||
.menu-horizontal {
|
||||
height: 100%;
|
||||
.menu-items {
|
||||
height:100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
li {
|
||||
text-align:center;
|
||||
width:40px;
|
||||
display:inline-block;
|
||||
padding:8px 16px 8px 16px;
|
||||
border-right: solid thin #CCC;
|
||||
}
|
||||
}
|
||||
}
|
||||
.signature-area {
|
||||
border: solid thin #CCC;
|
||||
min-height: 200px;
|
||||
}
|
||||
.menu-footer {
|
||||
border: solid thin #CCC;
|
||||
overflow: auto;
|
||||
}
|
||||
.signature-footer {
|
||||
border: solid thin #CCC;
|
||||
overflow: auto;
|
||||
|
||||
.edit-html-button {
|
||||
float: right;
|
||||
margin: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.appearance-mode-switch {
|
||||
max-width:400px;
|
||||
text-align: right;
|
||||
|
|
|
@ -131,7 +131,7 @@ class Contenteditable extends React.Component
|
|||
<div className="contenteditable-container">
|
||||
{@_renderFloatingToolbar()}
|
||||
|
||||
<div id="contenteditable"
|
||||
<div className="contenteditable"
|
||||
ref="contenteditable"
|
||||
contentEditable
|
||||
spellCheck={false}
|
||||
|
|
147
static/components/contenteditable.less
Normal file
147
static/components/contenteditable.less
Normal file
|
@ -0,0 +1,147 @@
|
|||
.contenteditable-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
line-height: 1.4;
|
||||
position: relative;
|
||||
color: @text-color;
|
||||
font-size: @font-size;
|
||||
|
||||
div[contenteditable], .contenteditable {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
spelling.misspelled {
|
||||
background: linear-gradient(45deg, transparent, transparent 49%, red 49%, transparent 51%);
|
||||
background-size: 2px 2px;
|
||||
background-position: bottom;
|
||||
background-repeat-y: no-repeat;
|
||||
}
|
||||
|
||||
.floating-toolbar {
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
|
||||
background: #fff;
|
||||
box-shadow: 0 10px 20px rgba(0,0,0,0.19), inset 0 0 1px rgba(0,0,0,0.5);
|
||||
border-radius: @border-radius-base;
|
||||
color: @text-color;
|
||||
|
||||
transition-duration: .15s;
|
||||
transition-property: opacity, margin;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
margin-top: 3px;
|
||||
|
||||
&.toolbar-visible {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.toolbar-pointer {
|
||||
position: absolute;
|
||||
width: 22.5px;
|
||||
height: 10px;
|
||||
background: transparent url('images/tooltip/tooltip-bg-pointer@2x.png') no-repeat;
|
||||
background-size: 22.5px 9.5px;
|
||||
margin-left: -11.2px;
|
||||
}
|
||||
|
||||
&.above {
|
||||
.toolbar-pointer {
|
||||
transform: rotate(0deg);
|
||||
bottom: -9px;
|
||||
}
|
||||
}
|
||||
&.below {
|
||||
.toolbar-pointer {
|
||||
transform: rotate(180deg);
|
||||
top: -9px;
|
||||
}
|
||||
}
|
||||
|
||||
.floating-toolbar-input {
|
||||
border: 0;
|
||||
display: inline;
|
||||
// The hardcoded numbers here represent the widths of the various
|
||||
// icons and buttons that surround the input. They are hardcoded here
|
||||
// because CSS does the calculation for us that we'd otherwise have to
|
||||
// do in React before the element renders to the page.
|
||||
width: calc(~"100% - 62px");
|
||||
&.with-remove {
|
||||
width: calc(~"100% - 95px");
|
||||
}
|
||||
color: @text-color;
|
||||
}
|
||||
|
||||
@padding: 0.5em;
|
||||
.btn {
|
||||
background: transparent;
|
||||
font-size: 16px;
|
||||
height: auto;
|
||||
border-radius: 0;
|
||||
padding: @padding*0.75 @padding;
|
||||
margin: 0;
|
||||
color: @text-color;
|
||||
box-shadow: none;
|
||||
&:first-child {
|
||||
padding-left: 1.5*@padding;
|
||||
}
|
||||
&:last-child {
|
||||
padding-right: 1.5*@padding;
|
||||
}
|
||||
&:hover, &:active {
|
||||
color: lighten(@text-color-link, 10%);
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-btn-icon {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
padding: 0 @padding;
|
||||
}
|
||||
|
||||
button.btn.toolbar-btn {
|
||||
@padding-top: 4px;
|
||||
@padding-left: 8px;
|
||||
|
||||
width: 12.5px + 2*@padding-left;
|
||||
height: 12.5px + 2*@padding-top;
|
||||
margin: 7.5px 0;
|
||||
box-shadow: none;
|
||||
border: 0;
|
||||
border-right: 1px solid @border-color-divider;
|
||||
&:last-child { border-right: 0 }
|
||||
|
||||
background: no-repeat;
|
||||
background-size: 12.5px 12.5px;
|
||||
background-position: @padding-left @padding-top;
|
||||
&.btn-bold { background-image: url("images/composer/tooltip-bold-black@2x.png") }
|
||||
&.btn-italic { background-image: url("images/composer/tooltip-italic-black@2x.png") }
|
||||
&.btn-underline { background-image: url("images/composer/tooltip-underline-black@2x.png") }
|
||||
&.btn-link { background-image: url("images/composer/tooltip-link-black@2x.png") }
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background: no-repeat;
|
||||
background-size: 12.5px 12.5px;
|
||||
background-position: @padding-left @padding-top;
|
||||
&.btn-bold { background-image: url("images/composer/tooltip-bold-blue@2x.png") }
|
||||
&.btn-italic { background-image: url("images/composer/tooltip-italic-blue@2x.png") }
|
||||
&.btn-underline { background-image: url("images/composer/tooltip-underline-blue@2x.png") }
|
||||
&.btn-link { background-image: url("images/composer/tooltip-link-blue@2x.png") }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body.platform-win32 {
|
||||
.contenteditable-container {
|
||||
.floating-toolbar {
|
||||
border-radius: 0;
|
||||
input, input:focus {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,3 +27,4 @@
|
|||
@import "components/generated-form";
|
||||
@import "components/unsafe";
|
||||
@import "components/key-commands-region";
|
||||
@import "components/contenteditable";
|
||||
|
|
Loading…
Reference in a new issue