feat(theming): Definitely not hacker mode. I don't know what you're talking about.

Summary: Add docs for new RetinaImg modes

Test Plan: Not much to test, except that it looks good!

Reviewers: evan

Reviewed By: evan

Differential Revision: https://phab.nylas.com/D1595
This commit is contained in:
Ben Gotow 2015-06-05 11:40:44 -07:00
parent ded4da1505
commit bc916a2530
43 changed files with 314 additions and 213 deletions

View file

@ -17,10 +17,10 @@ class AccountSidebarSheetItem extends React.Component
icon = <component selected={@props.select} />
else if _.isString(@props.item.icon)
icon = <RetinaImg name={@props.item.icon} fallback="folder.png" colorfill={@props.select} />
icon = <RetinaImg name={@props.item.icon} fallback="folder.png" mode={RetinaImg.Mode.ContentIsMask} />
else
icon = <RetinaImg name={"folder.png"} colorfill={@props.select} />
icon = <RetinaImg name={"folder.png"} mode={RetinaImg.Mode.ContentIsMask} />
<div className={classSet} onClick={@_onClick}>
{icon}

View file

@ -21,7 +21,7 @@ class AccountSidebarTagItem extends React.Component
'selected': @props.select
<div className={coontainerClass} onClick={@_onClick} id={@props.item.id}>
<RetinaImg name={"#{@props.item.id}.png"} fallback={'folder.png'} colorfill={@props.select} />
<RetinaImg name={"#{@props.item.id}.png"} fallback={'folder.png'} mode={RetinaImg.Mode.ContentIsMask} />
<span className="name"> {@props.item.name}</span>
{unread}
</div>

View file

@ -22,6 +22,7 @@
.item {
color: @text-color-subtle;
img.content-mask { background-color: @text-color-subtle; }
font-size: @font-size-small;
font-weight: 400;
padding: 0 @spacing-standard;
@ -47,9 +48,7 @@
&.selected {
background: @source-list-active-bg;
color: @source-list-active-color;
img.colorfill {
background: @source-list-active-color;
}
img.content-mask { background-color: @source-list-active-color; }
}
&:hover {

View file

@ -10,7 +10,7 @@ class ComposeButton extends React.Component
className="btn btn-toolbar"
data-tooltip="Compose new message"
onClick={@_onNewCompose}>
<RetinaImg name="toolbar-compose.png"/>
<RetinaImg name="toolbar-compose.png" mode={RetinaImg.Mode.ContentIsMask}/>
</button>
_onNewCompose: => Actions.composeNewBlankDraft()

View file

@ -155,7 +155,11 @@ class ComposerView extends React.Component
<span className="header-action"
data-tooltip="Popout composer"
style={{display: ((@props.mode is "fullwindow") and 'none' or 'initial'), paddingLeft: "1.5em"}}
onClick={@_popoutComposer}><RetinaImg name="composer-popout.png" style={{position: "relative", top: "-2px"}}/></span>
onClick={@_popoutComposer}>
<RetinaImg name="composer-popout.png"
mode={RetinaImg.Mode.ContentIsMask}
style={{position: "relative", top: "-2px"}}/>
</span>
</div>
@ -260,18 +264,18 @@ class ComposerView extends React.Component
<button className="btn btn-toolbar btn-trash" style={order: 100}
data-tooltip="Delete draft"
onClick={@_destroyDraft}><RetinaImg name="toolbar-trash.png" /></button>
onClick={@_destroyDraft}><RetinaImg name="toolbar-trash.png" mode={RetinaImg.Mode.ContentIsMask} /></button>
<button className="btn btn-toolbar btn-attach" style={order: 50}
data-tooltip="Attach file"
onClick={@_attachFile}><RetinaImg name="toolbar-attach.png"/></button>
onClick={@_attachFile}><RetinaImg name="toolbar-attach.png" mode={RetinaImg.Mode.ContentIsMask} /></button>
<div style={order: 0, flex: 1} />
<button className="btn btn-toolbar btn-emphasis btn-send" style={order: -100}
data-tooltip="Send message"
ref="sendButton"
onClick={@_sendDraft}><RetinaImg name="toolbar-send.png" /> Send</button>
onClick={@_sendDraft}><RetinaImg name="toolbar-send.png" mode={RetinaImg.Mode.ContentIsMask} /> Send</button>
</InjectedComponentSet>

View file

@ -70,6 +70,7 @@
.header-action {
color: @text-color-very-subtle;
img.content-mask { background-color: @text-color-very-subtle; }
font-size: @font-size-small;
padding-left: 1em;
&:hover {
@ -93,6 +94,7 @@
}
input, textarea, div[contenteditable] {
color: @text-color;
position: relative;
z-index: 1;
display: block;

View file

@ -3,114 +3,6 @@ _ = require "underscore"
{EventedIFrame} = require 'nylas-component-kit'
{Utils} = require 'nylas-exports'
EmailFixingStyles = """
<style>
/* Styles for an email iframe */
@font-face {
font-family: 'FaktPro';
font-style: normal;
font-weight: 300;
src: local('FaktPro-Blond'), url('fonts/Fakt/FaktPro-Blond.otf'), local('Comic Sans MS');
}
@font-face {
font-family: 'FaktPro';
font-style: normal;
font-weight: 400;
src: local('FaktPro-Normal'), url('fonts/Fakt/FaktPro-Normal.otf'), local('Comic Sans MS');
}
@font-face {
font-family: 'FaktPro';
font-style: normal;
font-weight: 500;
src: local('FaktPro-Medium'), url('fonts/Fakt/FaktPro-Medium.otf'), local('Comic Sans MS');
}
@font-face {
font-family: 'FaktPro';
font-style: normal;
font-weight: 600;
src: local('FaktPro-SemiBold'), url('fonts/Fakt/FaktPro-SemiBold.otf'), local('Comic Sans MS');
}
/* Clean Message Display */
html, body {
font-family: "FaktPro", "Helvetica", "Lucidia Grande", sans-serif;
font-size: 16px;
line-height: 1.5;
color: #313435;
border: 0;
margin: 0;
padding: 0;
-webkit-text-size-adjust: auto;
word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;
}
strong, b, .bold {
font-weight: 600;
}
body {
padding: 0;
margin: auto;
max-width: 840px;
overflow: hidden;
-webkit-font-smoothing: antialiased;
}
pre {
white-space: normal;
}
a {
color: #2794c3;
}
a:hover {
color: #1f7498;
}
a:visited {
color: #1f7498;
}
a img {
border-bottom: 0;
}
body.heightDetermined {
overflow-y: hidden;
}
div,pre {
max-width: 100%;
}
img {
max-width: 100%;
height: auto;
border: 0;
}
.gmail_extra,
.gmail_quote,
#divRplyFwdMsg,
blockquote {
display:none;
}
.show-quoted-text .gmail_extra,
.show-quoted-text .gmail_quote,
.show-quoted-text #divRplyFwdMsg,
.show-quoted-text blockquote {
display:inherit;
}
</style>
"""
class EmailFrame extends React.Component
@displayName = 'EmailFrame'
@ -140,7 +32,11 @@ class EmailFrame extends React.Component
wrapperClass = if @props.showQuotedText then "show-quoted-text" else ""
doc = React.findDOMNode(@).contentDocument
doc.open()
doc.write(EmailFixingStyles)
EmailFixingStyles = document.querySelector('[source-path*="email-frame.less"]')?.innerText
EmailFixingStyles = EmailFixingStyles.replace(/.ignore-in-parent-frame/g, '')
if (EmailFixingStyles)
doc.write("<style>#{EmailFixingStyles}</style>")
doc.write("<div id='inbox-html-wrapper' class='#{wrapperClass}'>#{@_emailContent()}</div>")
doc.close()

View file

@ -134,20 +134,20 @@ class MessageItem extends React.Component
_renderMessageActions: =>
<div className="message-actions-wrap">
<div className="message-actions-ellipsis" onClick={@_onShowActionsMenu}>
<RetinaImg name={"message-actions-ellipsis.png"}/>
<RetinaImg name={"message-actions-ellipsis.png"} mode={RetinaImg.Mode.ContentIsMask}/>
</div>
<InjectedComponentSet className="message-actions"
inline={true}
matching={role:"MessageAction"}
exposedProps={thread:@props.thread, message: @props.message}>
<button className="btn btn-icon" onClick={@_onReply}>
<RetinaImg name={"message-reply.png"}/>
<RetinaImg name={"message-reply.png"} mode={RetinaImg.Mode.ContentIsMask}/>
</button>
<button className="btn btn-icon" onClick={@_onReplyAll}>
<RetinaImg name={"message-reply-all.png"}/>
<RetinaImg name={"message-reply-all.png"} mode={RetinaImg.Mode.ContentIsMask}/>
</button>
<button className="btn btn-icon" onClick={@_onForward}>
<RetinaImg name={"message-forward.png"}/>
<RetinaImg name={"message-forward.png"} mode={RetinaImg.Mode.ContentIsMask}/>
</button>
</InjectedComponentSet>
</div>
@ -221,13 +221,13 @@ class MessageItem extends React.Component
<div className="collapse-control"
style={top: "4px", left: "-17px"}
onClick={=> @setState detailedHeaders: false}>
<RetinaImg name={"message-disclosure-triangle-active.png"}/>
<RetinaImg name={"message-disclosure-triangle-active.png"} mode={RetinaImg.Mode.ContentIsMask}/>
</div>
else
<div className="collapse-control inactive"
style={top: "3px"}
onClick={=> @setState detailedHeaders: true}>
<RetinaImg name={"message-disclosure-triangle.png"}/>
<RetinaImg name={"message-disclosure-triangle.png"} mode={RetinaImg.Mode.ContentIsMask}/>
</div>
# Eventually, _formatBody will run a series of registered body transformers.

View file

@ -98,7 +98,8 @@ class MessageList extends React.Component
if @_hasReplyArea()
<div className="footer-reply-area-wrap" onClick={@_onClickReplyArea}>
<div className="footer-reply-area">
<RetinaImg name="#{@_replyType()}-footer.png" /><span className="reply-text">Write a reply…</span>
<RetinaImg name="#{@_replyType()}-footer.png" mode={RetinaImg.Mode.ContentIsMask}/>
<span className="reply-text">Write a reply…</span>
</div>
</div>
else return <div></div>

View file

@ -10,7 +10,7 @@ class ArchiveButton extends React.Component
<button className="btn btn-toolbar btn-archive"
data-tooltip="Archive"
onClick={@_onArchive}>
<RetinaImg name="toolbar-archive.png" />
<RetinaImg name="toolbar-archive.png" mode={RetinaImg.Mode.ContentIsMask}/>
</button>
_onArchive: (e) =>

View file

@ -59,8 +59,8 @@ class ThreadTagsButton extends React.Component
render: =>
button = <button className="btn btn-toolbar">
<RetinaImg name="toolbar-tags.png"/>
<RetinaImg name="toolbar-chevron.png"/>
<RetinaImg name="toolbar-tags.png" mode={RetinaImg.Mode.ContentIsMask}/>
<RetinaImg name="toolbar-chevron.png" mode={RetinaImg.Mode.ContentIsMask}/>
</button>
headerComponents = [

View file

@ -42,6 +42,7 @@
.message-toolbar-arrow.down {
order:101;
margin-right: 0;
padding-top:6px;
}
.message-toolbar-arrow.up {
@ -130,6 +131,7 @@
.collapsed-from {
font-weight: @font-weight-semi-bold;
color: @text-color;
// min-width: 60px;
margin-right: 1em;
}
@ -249,10 +251,12 @@
.footer-reply-area-wrap {
width: 100%;
color: @text-color-very-subtle;
border-top: 1px solid @border-color-divider;
background: @background-primary;
color: @text-color-very-subtle;
img.content-mask { background-color:@text-color-very-subtle; }
&:hover {
cursor: default;
}
@ -371,7 +375,7 @@
.column-MessageListSidebar {
background-color: @background-off-primary;
overflow: auto;
border-left: 1px solid #ddd;
border-left: 1px solid @border-color-divider;
.flexbox-handle-horizontal div {
border-right: 0;
width: 1px;

View file

@ -23,8 +23,8 @@ class TemplatePicker extends React.Component
render: =>
button = <button className="btn btn-toolbar">
<RetinaImg name="toolbar-templates.png"/>
<RetinaImg name="toolbar-chevron.png"/>
<RetinaImg name="toolbar-templates.png" mode={RetinaImg.Mode.ContentIsMask}/>
<RetinaImg name="toolbar-chevron.png" mode={RetinaImg.Mode.ContentIsMask}/>
</button>
headerComponents = [

View file

@ -36,6 +36,7 @@ class ModeSwitch extends React.Component
<RetinaImg
data-mode={'list'}
name="toolbar-icon-listmode.png"
mode={RetinaImg.Mode.ContentIsMask}
active={@state.mode is 'list'}
onClick={@_onSetMode}
style={paddingRight:12} />
@ -45,14 +46,15 @@ class ModeSwitch extends React.Component
name="modeslider-knob.png"
className="handle"
style={top:4, left: knobX}/>
<RetinaImg
<RetinaImg
data-mode={'split'}
name="toolbar-icon-splitpanes.png"
name="toolbar-icon-splitpanes.png"
mode={RetinaImg.Mode.ContentIsMask}
active={@state.mode is 'split'}
onClick={@_onSetMode}
style={paddingLeft:12} />
</div>
_onStateChanged: =>
@setState(@_getStateFromStores())

View file

@ -20,15 +20,15 @@ class ModeToggle extends React.Component
render: =>
return <div></div> unless @state.visible
<div className="mode-toggle"
<div className="mode-toggle mode-#{@state.mode}"
style={order:51, marginTop:10, marginRight:14}
onClick={@_onToggleMode}>
<RetinaImg
name="toolbar-icon-toggle-pane.png"
colorfill={@state.mode is 'split'}
mode={RetinaImg.Mode.ContentIsMask}
onClick={@_onToggleMode} />
</div>
_onStateChanged: =>
@setState(@_getStateFromStores())

View file

@ -1,19 +1,14 @@
@import 'ui-variables';
.mode-switch {
z-index: 1000;
position: relative;
.handle {
position:absolute;
transition: left .2s ease-out;
}
}
.mode-toggle {
z-index: 1000;
position: relative;
.colorfill {
background-color: @component-active-color;
.content-mask {
background-color: @text-color-subtle;
}
}
.mode-toggle.mode-split {
.content-mask {
background-color: @component-active-color;
}
}

View file

@ -69,12 +69,12 @@ class ContainerView extends React.Component
if @state.page is 'welcome'
<div className="page" key={@state.page}>
<div className="quit" onClick={@_fireQuit}>
<RetinaImg name="onboarding-close.png"/>
<RetinaImg name="onboarding-close.png" mode={RetinaImg.Mode.ContentPreserve} />
</div>
<RetinaImg name="onboarding-logo.png" className="logo"/>
<h2>Welcome to Nylas</h2>
<RetinaImg name="onboarding-divider.png" />
<RetinaImg name="onboarding-divider.png" mode={RetinaImg.Mode.ContentPreserve} />
<form role="form" className="thin-container">
<div className="prompt">Enter your email address:</div>
@ -95,12 +95,12 @@ class ContainerView extends React.Component
else if @state.page == 'add-account'
<div className="page" key={@state.page}>
<div className="quit" onClick={@_fireDismiss}>
<RetinaImg name="onboarding-close.png"/>
<RetinaImg name="onboarding-close.png" mode={RetinaImg.Mode.ContentPreserve} />
</div>
<RetinaImg name="onboarding-logo.png" className="logo"/>
<RetinaImg name="onboarding-logo.png" className="logo" mode={RetinaImg.Mode.ContentPreserve} />
<h2>Connect an Account</h2>
<RetinaImg name="onboarding-divider.png" />
<RetinaImg name="onboarding-divider.png" mode={RetinaImg.Mode.ContentPreserve} />
<form role="form" className="thin-container">
<div className="prompt">Link accounts from other services to supercharge your email.</div>
@ -119,7 +119,7 @@ class ContainerView extends React.Component
})
}
<div className="back" onClick={@_fireMoveToPrevPage}>
<RetinaImg name="onboarding-back.png"/>
<RetinaImg name="onboarding-back.png" mode={RetinaImg.Mode.ContentPreserve} />
</div>
</div>

View file

@ -11,7 +11,7 @@
0% { transform: scale(1); }
50% { transform: scale(1.3); }
100% { transform: scale(1); }
}
}
@-webkit-keyframes fill {
0% { opacity: 0; border-width: @checkSize / 2; }
@ -22,7 +22,7 @@
.onboarding-container {
width:100%;
height:100%;
background-color: #f0f0f0;
background-color: @gray-lighter;
-webkit-animation: fadein 0.8s;
text-align: center;
@ -38,7 +38,7 @@
.logo {
padding-top:40px;
}
h2 {
margin-top: 27px;
margin-bottom: 90px;
@ -135,7 +135,7 @@
bottom: 9%;
box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.08);
}
&:after {
content: "";
position: absolute;
@ -152,7 +152,7 @@
-webkit-animation: fill 0.5s forwards;
-webkit-animation-delay: 0.8s;
}
.check-icon {
position: absolute;
z-index: 3;

View file

@ -52,6 +52,7 @@ class SearchBar extends React.Component
<RetinaImg className="search-accessory search"
name="searchloupe.png"
key="accessory"
mode={RetinaImg.Mode.ContentDark}
onClick={@_doSearch} />
<div className="search-accessory clear"
key="clear"

View file

@ -34,7 +34,10 @@ class SidebarFullContactDetails extends React.Component
profiles = @_profiles()
return profiles.map (profile) =>
<div className="social-profile">
<RetinaImg name="#{profile.typeId}-icon.png" className="social-icon" />
<RetinaImg
className="social-icon"
name="#{profile.typeId}-icon.png"
mode={RetinaImg.Mode.ContentIsMask} />
<div className="social-link">
<a href={profile.url}>{@_username(profile)}</a>
{@_twitterBio(profile)}

View file

@ -7,6 +7,10 @@
flex-shrink: 0;
.full-contact {
color: @text-color;
-webkit-user-select:text;
img.content-mask { background-color: @text-color; }
h1.name {
font-size: 20px;
font-weight: @font-weight-normal;
@ -41,7 +45,7 @@
.social-profile {
margin-top: 0.5em;
.social-icon {
padding-top: 6px;
margin-top: 6px;
float: left;
}
.social-link {

View file

@ -16,7 +16,7 @@ class ThreadBulkArchiveButton extends React.Component
className="btn btn-toolbar"
data-tooltip="Archive"
onClick={@_onArchive}>
<RetinaImg name="toolbar-archive.png" />
<RetinaImg name="toolbar-archive.png" mode={RetinaImg.Mode.ContentIsMask} />
</button>
_onArchive: =>
@ -55,11 +55,12 @@ DownButton = React.createClass
render: ->
<div className={@_classSet()} onClick={@_onClick}>
<RetinaImg name="toolbar-down-arrow.png"/>
<RetinaImg name="toolbar-down-arrow.png" mode={RetinaImg.Mode.ContentIsMask} />
</div>
_classSet: ->
classNames
"btn-icon": true
"message-toolbar-arrow": true
"down": true
"disabled": @state.disabled
@ -77,11 +78,12 @@ UpButton = React.createClass
render: ->
<div className={@_classSet()} onClick={@_onClick}>
<RetinaImg name="toolbar-up-arrow.png"/>
<RetinaImg name="toolbar-up-arrow.png" mode={RetinaImg.Mode.ContentIsMask} />
</div>
_classSet: ->
classNames
"btn-icon": true
"message-toolbar-arrow": true
"up": true
"disabled": @state.disabled

View file

@ -55,7 +55,9 @@ class ThreadList extends React.Component
if hasDraft
<div style={display: 'flex'}>
<ThreadListParticipants thread={thread} />
<RetinaImg name="icon-draft-pencil.png" className="draft-icon" />
<RetinaImg name="icon-draft-pencil.png"
className="draft-icon"
mode={RetinaImg.Mode.ContentPreserve} />
</div>
else
<ThreadListParticipants thread={thread} />

View file

@ -18,7 +18,7 @@
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;
color: #313435;
font-weight: @font-weight-normal;
text-align: center;

View file

@ -1 +1,50 @@
@background-primary: #ffffff;
@gray-base: #ffffff;
@gray-darker: darken(@gray-base, 13.5%); // #222
@gray-dark: darken(@gray-base, 20%); // #333
@gray: darken(@gray-base, 33.5%); // #555
@gray-light: darken(@gray-base, 46.7%); // #777
@gray-lighter: darken(@gray-base, 92.5%); // #eee
@white: #0a0b0c;
@background-off-primary: #333;
@background-secondary: #2D2D2D;
@background-tertiary: #6d7987;
@background-primary: #313131;
@background-color: darken(#313131, 15%);
@btn-default-bg-color: #404040;
@accent-primary: #5AA8FA;
@accent-primary-dark: #3087E1;
@text-color: #C2C2C2;
@text-color-subtle: fadeout(@text-color, 20%);
@text-color-very-subtle: fadeout(@text-color, 40%);
@text-color-inverse: white;
@text-color-inverse-subtle: fadeout(@text-color-inverse, 20%);
@text-color-inverse-very-subtle: fadeout(@text-color-inverse, 50%);
@text-color-heading: #FFF;
@border-primary-bg: lighten(@background-primary, 10%);
@border-secondary-bg: lighten(@background-secondary, 10%);
@border-tertiary-bg: lighten(@background-tertiary, 10%);
@border-color-divider: @border-secondary-bg;
@input-bg: #242424;
@input-border: @border-color-divider;
@list-bg: #333;
@list-border: #383838;
@list-selected-color: @text-color-inverse;
@toolbar-background-color: @background-secondary;
.thread-icon:not(.thread-icon-unread) {
-webkit-filter: invert(100%);
}
img.content-dark {
-webkit-filter: invert(100%);
}
img.content-light {
-webkit-filter: invert(100%);
}

View file

@ -52,6 +52,8 @@
{
label: 'Developer'
submenu: [
{ label: 'Toggle Hacker Theme', command: 'application:toggle-theme' }
{ type: 'separator' }
{ label: 'Open In Dev Mode...', command: 'application:open-dev' }
{ type: 'separator' }
{ label: 'Open Detailed Logs', command: 'window:open-errorreporter-logs' }

View file

@ -35,6 +35,8 @@
{
label: 'Developer'
submenu: [
{ label: 'Toggle Hacker Theme', command: 'application:toggle-theme' }
{ type: 'separator' }
{ label: 'Open In &Dev Mode...', command: 'application:open-dev' }
{ type: 'separator' }
{ label: 'Open Detailed Logs', command: 'window:open-errorreporter-logs' }

View file

@ -37,6 +37,8 @@
{
label: 'Developer'
submenu: [
{ label: 'Toggle Hacker Theme', command: 'application:toggle-theme' }
{ type: 'separator' }
{ label: 'Open In &Dev Mode...', command: 'application:open-dev' }
{ type: 'separator' }
{ label: 'Open Detailed Logs', command: 'window:open-errorreporter-logs' }

View file

@ -249,6 +249,14 @@ class Application
@windowManager.devMode = true
@windowManager.ensurePrimaryWindowOnscreen()
@on 'application:toggle-theme', =>
themes = @config.get('core.themes') ? []
if 'ui-dark' in themes
themes = _.without themes, 'ui-dark'
else
themes.push('ui-dark')
@config.set('core.themes', themes)
if process.platform is 'darwin'
@on 'application:about', -> Menu.sendActionToFirstResponder('orderFrontStandardAboutPanel:')
@on 'application:bring-all-windows-to-front', -> Menu.sendActionToFirstResponder('arrangeInFront:')

View file

@ -53,10 +53,10 @@ class EmptyState extends React.Component
{@state.message?.byline}
</div>
</div>
<RetinaImg name="blank-bottom-left.png" className="bottom-left"/>
<RetinaImg name="blank-top-left.png" className="top-left"/>
<RetinaImg name="blank-bottom-right.png" className="bottom-right"/>
<RetinaImg name="blank-top-right.png" className="top-right"/>
<RetinaImg mode={RetinaImg.Mode.ContentLight} name="blank-bottom-left.png" className="bottom-left"/>
<RetinaImg mode={RetinaImg.Mode.ContentLight} name="blank-top-left.png" className="top-left"/>
<RetinaImg mode={RetinaImg.Mode.ContentLight} name="blank-bottom-right.png" className="bottom-right"/>
<RetinaImg mode={RetinaImg.Mode.ContentLight} name="blank-top-right.png" className="top-right"/>
</div>
</div>

View file

@ -102,8 +102,9 @@ class Popover extends React.Component
pointerStyle =
'position': 'absolute'
'marginLeft': '50%'
'width': 22.5
'height': 11
'zoom': 0.5
'width': 45
'height': 21
'zIndex': 0
if @props.direction is 'up'

View file

@ -23,6 +23,12 @@ StylesImpactedByZoom = [
# constant at require-time
DEFAULT_RESOURCE_PATH = atom.getLoadSettings().resourcePath
Mode =
ContentPreserve: 'original'
ContentLight: 'light'
ContentDark: 'dark'
ContentIsMask: 'mask'
###
Public: RetinaImg wraps the DOM's standard `<img`> tag and implements a `UIImage` style
interface. Rather than specifying an image `src`, RetinaImg allows you to provide
@ -31,45 +37,84 @@ display based on pixel density. Given `image.png`, on a Retina screen, it looks
`image@2x.png`, `image.png`, `image@1x.png` in that order. It uses a lookup table and caches
image names, so images generally resolve immediately.
RetinaImg also introduces the concept of image `modes`. Specifying an image mode
is important for theming: it describes the content of your image, allowing theme
developers to properly adjust it. The four modes are described below:
- `ContentPreserve`: Your image contains color or should not be adjusted by any theme.
- `ContentLight`: Your image is a grayscale image with light colors, intended to be shown
against a dark background. If a theme developer changes the background to be light, they
can safely apply CSS filters to invert or darken this image. This mode adds the
`content-light` CSS class to the image.
- `ContentDark`: Your image is a grayscale image with dark colors, intended to be shown
against a light background. If a theme developer changes the background to be dark, they
can safely apply CSS filters to invert or brighten this image. This mode adds the
`content-dark` CSS class to the image.
- `ContentIsMask`: This image provides alpha information only, and color should
be based on the `background-color` of the RetinaImg. This mode adds the
`content-mask` CSS class to the image, and leverages `-webkit-mask-image`.
Example: Icons displayed within buttons specify ContentIsMask, and their
color is declared via CSS to be the same as the button text color. Changing
`@text-color-subtle` in a theme changes both button text and button icons!
```css
.btn-icon {
color: @text-color-subtle;
img.content-mask { background-color:@text-color-subtle; }
}
```
Section: Component Kit
###
class RetinaImg extends React.Component
@displayName: 'RetinaImg'
@Mode: Mode
###
Public: React `props` supported by RetinaImg:
- `mode` (required) One of the RetinaImg.Mode constants. See above for details.
- `name` (optional) A {String} image name to display.
- `url` (optional) A {String} url of an image to display.
May be an http, https, or `nylas://<packagename>/<path within package>` URL.
- `fallback` (optional) A {String} image name to use when `name` cannot be found.
- `selected` (optional) Appends "-selected" to the end of the image name when when true
- `active` (optional) Appends "-active" to the end of the image name when when true
- `colorfill` (optional) Adds -webkit-mask-image and other styles, and the .colorfill CSS
class, so that setting a CSS background color will colorfill the image.
- `style` (optional) An {Object} with additional styles to apply to the image.
- `resourcePath` (options) Changes the default lookup location used to find the images.
###
@propTypes:
mode: React.PropTypes.string.isRequired
name: React.PropTypes.string
url: React.PropTypes.string
className: React.PropTypes.string
style: React.PropTypes.object
fallback: React.PropTypes.string
selected: React.PropTypes.bool
active: React.PropTypes.bool
colorfill: React.PropTypes.bool
resourcePath: React.PropTypes.string
render: ->
path = @_pathFor(@props.name) ? @_pathFor(@props.fallback) ? ''
path = @props.url ? @_pathFor(@props.name) ? @_pathFor(@props.fallback) ? ''
pathIsRetina = path.indexOf('@2x') > 0
className = undefined
className = @props.className ? ''
style = @props.style ? {}
style.WebkitUserDrag = 'none'
style.zoom = if pathIsRetina then 0.5 else 1
if @props.colorfill
if @props.mode is Mode.ContentIsMask
style.WebkitMaskImage = "url('#{path}')"
style.objectPosition = "10000px"
className = "colorfill"
className += " content-mask"
else if @props.mode is Mode.ContentDark
className += " content-dark"
else if @props.mode is Mode.ContentLight
className += " content-light"
for key, val of style
val = "#{val}"

View file

@ -35,7 +35,9 @@ Token = React.createClass
<div {...@dragSourceFor('token')}
className={classes}
onClick={@_onSelect}>
<button className="action" onClick={@_onAction} style={marginTop: "2px"}><RetinaImg name="composer-caret.png" /></button>
<button className="action" onClick={@_onAction} style={marginTop: "2px"}>
<RetinaImg mode={RetinaImg.Mode.ContentIsMask} name="composer-caret.png" />
</button>
{@props.children}
</div>

View file

@ -21,7 +21,7 @@ class ToolbarBack extends React.Component
@displayName: 'ToolbarBack'
render: =>
<div className="item-back" onClick={@_onClick}>
<RetinaImg name="sheet-back.png" />
<RetinaImg name="sheet-back.png" mode={RetinaImg.Mode.ContentIsMask} />
</div>
_onClick: =>
@ -156,4 +156,4 @@ class Toolbar extends React.Component
state
module.exports = Toolbar
module.exports = Toolbar

View file

@ -285,6 +285,7 @@ class ThemeManager
reloadBaseStylesheets: ->
@requireStylesheet('../static/index')
@requireStylesheet('../static/email-frame')
if nativeStylesheetPath = fs.resolveOnLoadPath(process.platform, ['css', 'less'])
@requireStylesheet(nativeStylesheetPath)

View file

@ -46,10 +46,12 @@ button, html input[type="button"] {
color: @btn-default-text-color;
background: @btn-default-bg-color;
img.content-mask { background-color:@btn-default-text-color; }
&.btn-action {
color: @btn-action-text-color;
background: @btn-action-bg-color;
img.content-mask { background-color:@btn-action-text-color; }
}
&.btn-emphasis {
@ -58,7 +60,7 @@ button, html input[type="button"] {
color: @btn-emphasis-text-color;
font-weight: @font-weight-medium;
img {-webkit-filter: brightness(100);}
img.content-mask { background-color:@btn-emphasis-text-color; }
}
&.btn-emphasis:active {
@ -69,6 +71,7 @@ button, html input[type="button"] {
&.btn-danger, .btn-destructive {
color: @btn-danger-text-color;
background: @btn-danger-bg-color;
img.content-mask { background-color:@btn-danger-text-color; }
}
}
@ -88,6 +91,7 @@ button, html input[type="button"] {
border: 0;
box-shadow: none;
color: @text-color-subtle;
img.content-mask { background-color:@text-color-subtle; }
margin-right: 10px;
outline: none !important;
font-size: 20px;
@ -98,6 +102,7 @@ button, html input[type="button"] {
&.inverse {
color: @text-color-inverse;
img.content-mask { background-color:@text-color-inverse; }
&:hover {
color: white;
@ -105,16 +110,19 @@ button, html input[type="button"] {
&:active {
color: @text-color-inverse;
img.content-mask { background-color:@text-color-inverse; }
}
}
&:hover {
cursor: default;
color: @text-color-link;
img.content-mask { background-color:@text-color-link; }
box-shadow: none;
}
&:active {
color: @text-color-link-active;
img.content-mask { background-color:@text-color-link-active; }
box-shadow: none;
}
}

View file

@ -140,6 +140,11 @@
border-radius: 2px;
}
}
&.focused {
.checkmark .inner {
border:1px solid @accent-primary;
}
}
.checkmark {
padding: 12px;
@ -149,7 +154,7 @@
.inner {
width:14px;
height:14px;
border:1px solid @table-border-color;
border:1px solid @list-border;
border-radius: 2px;
background: transparent;
background-size: 12px 9px;

View file

@ -36,7 +36,7 @@
}
.popover-pointer {
background: transparent url('images/tooltip/tooltip-bg-pointer@2x.png') no-repeat;
background-size: 22.5px 10.5px;
-webkit-mask-image: url('images/tooltip/tooltip-bg-pointer@2x.png');
background-color: @background-color;
}
}

View file

@ -31,6 +31,7 @@
.token {
display: inline-block;
position: relative;
color: @text-color;
padding: 0.4em @spacing-half 0.4em @spacing-half;
padding-right: 1.5em;
margin: 0 5px 5px 0;

80
static/email-frame.less Normal file
View file

@ -0,0 +1,80 @@
@import 'variables/ui-variables';
@import 'ui-variables';
.ignore-in-parent-frame {
html, body {
font-family: "FaktPro", "Helvetica", "Lucidia Grande", sans-serif;
font-size: 16px;
line-height: 1.5;
color: @text-color;
background-color: transparent !important;
border: 0;
margin: 0;
padding: 0;
-webkit-text-size-adjust: auto;
word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;
}
strong, b, .bold {
font-weight: 600;
}
body {
padding: 0;
margin: auto;
max-width: 840px;
overflow: hidden;
-webkit-font-smoothing: antialiased;
}
pre {
white-space: normal;
}
a {
color: @text-color-link;
}
a:hover {
color: @text-color-link-hover;
}
a:visited {
color: darken(@text-color-link, 10%);
}
a img {
border-bottom: 0;
}
body.heightDetermined {
overflow-y: hidden;
}
div,pre {
max-width: 100%;
}
img {
max-width: 100%;
height: auto;
border: 0;
}
.gmail_extra,
.gmail_quote,
#divRplyFwdMsg,
blockquote {
display:none;
}
.show-quoted-text .gmail_extra,
.show-quoted-text .gmail_quote,
.show-quoted-text #divRplyFwdMsg,
.show-quoted-text blockquote {
display:inherit;
}
}

View file

@ -20,6 +20,7 @@ input[type="url"] {
font-size: @font-size-base;
line-height: @line-height-computed;
font-weight:400;
background: @input-bg;
&.input-bordered {
border-radius: @border-radius-base;

View file

@ -203,28 +203,6 @@
@standard-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.21);
@standard-shadow-up: 0 -1px 4px 0 rgba(0, 0, 0, 0.21);
//============================== Tables ===============================//
// Customizes the `.table` component with basic values, each used across
// all table variations.
//** Padding for `<th>`s and `<td>`s.
@table-cell-padding: 8px;
//** Padding for cells in `.table-condensed`.
@table-condensed-cell-padding: 5px;
//** Default background color used for all tables.
@table-bg: transparent;
//** Background color used for `.table-striped`.
@table-bg-accent: #f9f9f9;
//** Background color used for `.table-hover`.
@table-bg-hover: #f5f5f5;
@table-bg-active: @table-bg-hover;
//** Border color for table and cell borders.
@table-border-color: #ddd;
//=============================== Buttons ==============================//
@btn-shadow: @standard-shadow;

View file

@ -153,6 +153,7 @@ body.is-blurred {
order:-999;
padding-top: 5px;
padding-left: @spacing-three-quarters;
img.content-mask { background-color: @text-color-heading; }
flex-grow: 0;
flex-shrink: 0;
}