Merge branch 'develop' into feature/better.select

This commit is contained in:
Devin Howard 2017-01-10 18:01:56 -05:00
commit 17adf5a6c5
16 changed files with 833 additions and 364 deletions

View file

@ -27,6 +27,7 @@ gem 'rack-cors'
gem 'redis'
gem 'slack-notifier'
gem 'snorlax'
gem 'puma'
# asset stuff
gem 'jquery-rails'
@ -44,7 +45,6 @@ group :test do
end
group :development, :test do
gem 'puma'
gem 'better_errors'
gem 'binding_of_caller'
gem 'pry-byebug'

View file

@ -1,3 +1,3 @@
web: bundle exec rails server -p $PORT
web: bundle exec puma -p $PORT
worker: bundle exec rake jobs:work

View file

@ -63,7 +63,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
The license can be read [here][license].
Copyright (c) 2016 Connor Turland
Copyright (c) 2017 Connor Turland
[site-beta]: http://metamaps.cc
[license]: https://github.com/metamaps/metamaps/blob/develop/LICENSE

View file

@ -0,0 +1,263 @@
.emoji-mart,
.emoji-mart * {
box-sizing: border-box;
line-height: 1.15;
}
.emoji-mart {
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif;
font-size: 16px;
display: inline-block;
color: #222427;
border: 1px solid #d9d9d9;
border-radius: 5px;
background: #fff;
}
.emoji-mart .emoji-mart-emoji {
padding: 6px;
}
.emoji-mart-bar:first-child {
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
.emoji-mart-bar:last-child {
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
.emoji-mart-anchors {
display: flex;
justify-content: space-between;
padding: 0 6px;
color: #858585;
line-height: 0;
}
.emoji-mart-anchor {
position: relative;
flex: 1;
text-align: center;
padding: 12px 4px;
overflow: hidden;
transition: color .1s ease-out;
}
.emoji-mart-anchor:hover,
.emoji-mart-anchor-selected {
color: #464646;
}
.emoji-mart-anchor-selected .emoji-mart-anchor-bar {
bottom: 0;
}
.emoji-mart-anchor-bar {
position: absolute;
bottom: -3px; left: 0;
width: 100%; height: 3px;
background-color: #464646;
}
.emoji-mart-anchors i {
display: inline-block;
width: 100%;
max-width: 22px;
}
.emoji-mart-anchors svg {
fill: currentColor;
}
.emoji-mart-scroll {
overflow-y: scroll;
height: 270px;
padding: 0 6px 6px 6px;
border: solid #d9d9d9;
border-width: 1px 0;
}
.emoji-mart-search {
font-size: 16px;
display: block;
width: 100%;
padding: .2em .6em;
margin-top: 6px;
border-radius: 25px;
border: 1px solid #d9d9d9;
outline: 0;
}
.emoji-mart-category .emoji-mart-emoji span {
z-index: 1;
position: relative;
}
.emoji-mart-category .emoji-mart-emoji:hover:before {
z-index: 0;
content: "";
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
background-color: #f4f4f4;
border-radius: 100%;
}
.emoji-mart-category-label {
z-index: 2;
position: relative;
position: -webkit-sticky;
top: 0;
}
.emoji-mart-category-label span {
display: block;
width: 100%;
font-weight: 500;
padding: 5px 6px;
background-color: #fff;
background-color: rgba(255, 255, 255, .95);
}
.emoji-mart-emoji {
position: relative;
display: inline-block;
font-size: 0;
}
.emoji-mart-no-results {
font-size: 14px;
text-align: center;
padding-top: 70px;
color: #858585;
}
.emoji-mart-no-results span {
display: inline-block;
vertical-align: middle;
}
.emoji-mart-preview {
position: relative;
height: 70px;
}
.emoji-mart-preview-emoji,
.emoji-mart-preview-data,
.emoji-mart-preview-skins {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.emoji-mart-preview-emoji {
left: 12px;
}
.emoji-mart-preview-data {
left: 68px; right: 12px;
word-break: break-word;
}
.emoji-mart-preview-skins {
right: 30px;
text-align: right;
}
.emoji-mart-preview-name {
font-size: 14px;
}
.emoji-mart-preview-shortname {
font-size: 12px;
color: #888;
}
.emoji-mart-preview-shortname + .emoji-mart-preview-shortname,
.emoji-mart-preview-shortname + .emoji-mart-preview-emoticon,
.emoji-mart-preview-emoticon + .emoji-mart-preview-emoticon {
margin-left: .5em;
}
.emoji-mart-preview-emoticon {
font-size: 11px;
color: #bbb;
}
.emoji-mart-title span {
display: inline-block;
vertical-align: middle;
}
.emoji-mart-title .emoji-mart-emoji {
padding: 0;
}
.emoji-mart-title-label {
color: #999A9C;
font-size: 26px;
font-weight: 300;
}
.emoji-mart-skin-swatches {
font-size: 0;
padding: 2px 0;
border: 1px solid #d9d9d9;
border-radius: 12px;
background-color: #fff;
}
.emoji-mart-skin-swatches-opened .emoji-mart-skin-swatch {
width: 16px;
padding: 0 2px;
}
.emoji-mart-skin-swatches-opened .emoji-mart-skin-swatch-selected:after {
opacity: .75;
}
.emoji-mart-skin-swatch {
display: inline-block;
width: 0;
vertical-align: middle;
transition-property: width, padding;
transition-duration: .125s;
transition-timing-function: ease-out;
}
.emoji-mart-skin-swatch:nth-child(1) { transition-delay: 0 }
.emoji-mart-skin-swatch:nth-child(2) { transition-delay: .03s }
.emoji-mart-skin-swatch:nth-child(3) { transition-delay: .06s }
.emoji-mart-skin-swatch:nth-child(4) { transition-delay: .09s }
.emoji-mart-skin-swatch:nth-child(5) { transition-delay: .12s }
.emoji-mart-skin-swatch:nth-child(6) { transition-delay: .15s }
.emoji-mart-skin-swatch-selected {
position: relative;
width: 16px;
padding: 0 2px;
}
.emoji-mart-skin-swatch-selected:after {
content: "";
position: absolute;
top: 50%; left: 50%;
width: 4px; height: 4px;
margin: -2px 0 0 -2px;
background-color: #fff;
border-radius: 100%;
pointer-events: none;
opacity: 0;
transition: opacity .2s ease-out;
}
.emoji-mart-skin {
display: inline-block;
width: 100%; padding-top: 100%;
max-width: 12px;
border-radius: 100%;
}
.emoji-mart-skin-tone-1 { background-color: #ffc93a }
.emoji-mart-skin-tone-2 { background-color: #fadcbc }
.emoji-mart-skin-tone-3 { background-color: #e0bb95 }
.emoji-mart-skin-tone-4 { background-color: #bf8f68 }
.emoji-mart-skin-tone-5 { background-color: #9b643d }
.emoji-mart-skin-tone-6 { background-color: #594539 }

View file

@ -1,323 +0,0 @@
.collaborator-video {
z-index: 1;
position: absolute;
width: 150px;
height: 150px;
cursor: default;
color: #FFF;
}
.collaborator-video .video-receive {
position: absolute;
width: 160px;
padding: 20px 20px 20px 170px;
background: #424242;
height: 110px;
border-top-left-radius: 75px;
border-bottom-left-radius: 75px;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
}
.collaborator-video .video-receive .video-statement {
margin-bottom: 10px;
}
.collaborator-video .video-receive .btn-group .btn-yes {
margin-right: 10px;
}
.collaborator-video .video-receive .btn-group .btn-no {
background-color: #c04f4f;
}
.collaborator-video .video-receive .btn-group .btn-no:hover {
background-color: #A54242;
}
.collaborator-video .video-cutoff {
width: 150px;
height: 150px;
overflow: hidden;
border-radius: 75px;
z-index: 0;
position: relative;
-webkit-box-shadow: 0px 6px 3px rgba(0, 0, 0, 0.23), 10px 10px 10px rgba(0, 0, 0, 0.19);
-moz-box-shadow: 0px 6px 3px rgba(0, 0, 0, 0.23), 10px 10px 10px rgba(0, 0, 0, 0.19);
box-shadow: 0px 6px 3px rgba(0, 0, 0, 0.23), 10px 10px 10px rgba(0, 0, 0, 0.19);
}
.collaborator-video .video-cutoff video {
height: 150px;
margin-left: -25px;
}
.collaborator-video .video-cutoff .collaborator-video-avatar {
position: absolute;
top: 0;
left: 0;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-o-user-select: none;
user-select: none;
-webkit-user-drag: none;
display: none;
}
.collaborator-video .video-audio {
position: absolute;
width: 24px;
height: 24px;
top: 85%;
right: 0px;
cursor: pointer;
background: url(<%= asset_path 'audio_sprite.png' %>) no-repeat;
}
.collaborator-video .video-audio:hover {
background-position-x: -24px;
}
.collaborator-video .video-audio.active {
background-position-y: -24px;
}
.collaborator-video .video-video {
position: absolute;
width: 24px;
height: 24px;
top: 85%;
left: 0px;
cursor: pointer;
background: url(<%= asset_path 'camera_sprite.png' %>) no-repeat;
}
.collaborator-video .video-video:hover {
background-position-x: -24px;
}
.collaborator-video .video-video.active {
background-position-y: -24px;
}
.collaborator-video.my-video {
left: 30px;
top: 72px;
}
#chat-box-wrapper {
height: 100%;
float: right;
}
.chat-box {
position: relative;
display: flex;
flex-direction: column;
z-index: 1;
width: 300px;
height: 100%;
background: #424242;
box-shadow: -8px 0px 16px 2px rgba(0, 0, 0, 0.23);
}
.chat-box .chat-button {
position: absolute;
top: 50%;
left: -36px;
width: 36px;
height: 49px;
background: url(<%= asset_path 'junto.png' %>) no-repeat 2px 9px, url(<%= asset_path 'tray_tab.png' %>) no-repeat;
cursor: pointer;
}
.chat-box .chat-button.active {
background: url(<%= asset_path 'junto_spinner_dark.gif' %>) no-repeat 2px 8px, url(<%= asset_path 'tray_tab.png' %>) no-repeat !important;
}
.chat-box .chat-button .chat-unread {
background: #DAB539;
position: absolute;
top: -3px;
left: -11px;
width: 20px;
height: 20px;
border-radius: 11px;
border: 2px solid #424242;
color: #424242;
text-align: center;
font-size: 12px;
font-weight: bold;
line-height: 20px;
}
.chat-box .junto-header {
width: 276px;
padding: 16px 8px 16px 16px;
font-size: 16px;
text-align: left;
font-weight: bold;
background-color: #000000;
color: #f5f5f5;
box-shadow: 0px 6px 3px rgba(0, 0, 0, 0.23);
}
.chat-box .junto-header .cursor-toggle {
width: 32px;
height: 32px;
margin-right: 8px;
margin-top: -8px;
float: right;
background: url(<%= asset_path 'cursor_sprite.png' %>) no-repeat;
}
.chat-box .junto-header .cursor-toggle:hover {
background-position-x: -32px;
}
.chat-box .junto-header .cursor-toggle.active {
background-position-y: -32px;
}
.chat-box .junto-header .video-toggle {
width: 32px;
height: 32px;
margin-right: 10px;
margin-top: -8px;
float: right;
background: url(<%= asset_path 'video_sprite.png' %>) no-repeat;
}
.chat-box .junto-header .video-toggle:hover {
background-position-x: -32px;
}
.chat-box .junto-header .video-toggle.active {
background-position-y: -32px;
}
.chat-box .participants {
width: 100%;
min-height: 150px;
padding: 16px 0px 16px 0px;
text-align: left;
color: #f5f5f5;
overflow-y: auto;
}
.chat-box .participants .conversation-live {
padding: 5px 10px 5px 10px;
background: #c04f4f;
margin: 5px 10px;
border-radius: 2px;
}
.chat-box .participants .conversation-live .call-action {
float: right;
cursor: pointer;
color: #EBFF00;
}
.chat-box .participants .participant {
width: 89%;
padding: 8px 8px 2px 8px;
color: #f5f5f5;
font-family: arial, sans-serif;
font-size: 13px;
line-height: 14px;
}
.chat-box .participants .participant .chat-participant-image {
width: 15%;
float: left;
overflow: hidden;
color: #BBB;
padding-top: 2px;
}
.chat-box .participants .participant .chat-participant-image img {
width: 32px;
height: 32px;
border-radius: 18px;
}
.chat-box .participants .participant .chat-participant-name {
width: 53%;
float: left;
font-size: 13px;
font-weight: bold;
margin-top: 12px;
padding: 2px 8px 0;
text-align: left;
}
.chat-box .participants .participant .chat-participant-invite-call,
.chat-box .participants .participant .chat-participant-invite-join
{
float: right;
background: #4FC059 url(<%= asset_path 'invitepeer16.png' %>) no-repeat center center;
}
.chat-box .participants .participant .chat-participant-invite-call.pending,
.chat-box .participants .participant .chat-participant-invite-join.pending {
background: #dab539 url(<%= asset_path 'ellipsis.gif' %>) no-repeat center center;
}
.chat-box .participants .participant .chat-participant-participating {
float: right;
margin-top: 14px;
}
.chat-box .participants .participant .chat-participant-participating .green-dot {
background: #4fc059;
width: 12px;
height: 12px;
border-radius: 6px;
}
.chat-box .chat-header {
width: 276px;
padding: 16px 8px 16px 16px;
font-size: 16px;
text-align: left;
font-weight: bold;
background-color: #000000;
color: #f5f5f5;
box-shadow: 0px 6px 3px rgba(0, 0, 0, 0.23);
}
.chat-box .chat-header .sound-toggle {
width: 24px;
height: 24px;
margin-right: 10px;
margin-top: -2px;
float: right;
background: url(<%= asset_path 'sound_sprite.png' %>) no-repeat;
}
.chat-box .chat-header .sound-toggle:hover {
background-position-x: -24px;
}
.chat-box .chat-header .sound-toggle.active {
background-position-y: -24px;
}
.chat-box .chat-input {
min-height: 80px;
width: 94%;
padding: 8px 3% 8px 3%;
font-size: 13px;
outline: none;
resize: none;
}
.chat-box .chat-messages {
width: 100%;
padding: 16px 0px 0px 0px;
overflow-y: auto;
flex-grow: 1;
}
.chat-box .chat-messages .chat-message {
width: 89%;
padding: 8px 8px 2px 8px;
color: #f5f5f5;
font-family: arial, sans-serif;
font-size: 13px;
line-height: 14px;
}
.chat-box .chat-messages .chat-message a:link {
color: #4fb5c0;
text-decoration: underline;
}
.chat-box .chat-messages .chat-message a:visited {
color: #aea9fd;
text-decoration: underline;
}
.chat-box .chat-messages .chat-message a:hover {
color: #dab539;
text-decoration: underline;
}
.chat-box .chat-messages .chat-message .chat-message-user {
width: 15%;
float: left;
overflow: hidden;
color: #BBB;
padding-top: 2px;
}
.chat-box .chat-messages .chat-message .chat-message-user img {
border: 2px solid #424242;
width: 32px;
height: 32px;
border-radius: 18px;
}
.chat-box .chat-messages .chat-message .chat-message-text {
width: 73%;
float: left;
margin-top: 12px;
padding: 2px 8px 0;
text-align: left;
word-wrap: break-word;
}
.chat-box .chat-messages .chat-message .chat-message-time {
float: right;
font-size: 10px;
color: #757575;
}

View file

@ -0,0 +1,370 @@
.collaborator-video {
z-index: 1;
position: absolute;
width: 150px;
height: 150px;
cursor: default;
color: #FFF;
.video-receive {
position: absolute;
width: 160px;
padding: 20px 20px 20px 170px;
background: #424242;
height: 110px;
border-top-left-radius: 75px;
border-bottom-left-radius: 75px;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
.video-statement {
margin-bottom: 10px;
}
.btn-group {
.btn-yes {
margin-right: 10px;
}
.btn-no {
background-color: #c04f4f;
&:hover {
background-color: #A54242;
}
}
}
}
.video-cutoff {
width: 150px;
height: 150px;
overflow: hidden;
border-radius: 75px;
z-index: 0;
position: relative;
-webkit-box-shadow: 0px 6px 3px rgba(0, 0, 0, 0.23), 10px 10px 10px rgba(0, 0, 0, 0.19);
-moz-box-shadow: 0px 6px 3px rgba(0, 0, 0, 0.23), 10px 10px 10px rgba(0, 0, 0, 0.19);
box-shadow: 0px 6px 3px rgba(0, 0, 0, 0.23), 10px 10px 10px rgba(0, 0, 0, 0.19);
video {
height: 150px;
margin-left: -25px;
}
.collaborator-video-avatar {
position: absolute;
top: 0;
left: 0;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-o-user-select: none;
user-select: none;
-webkit-user-drag: none;
display: none;
}
}
.video-audio {
position: absolute;
width: 24px;
height: 24px;
top: 85%;
right: 0px;
cursor: pointer;
background: url(<%= asset_path 'audio_sprite.png' %>) no-repeat;
}
.video-audio:hover {
background-position-x: -24px;
}
.video-audio.active {
background-position-y: -24px;
}
.video-video {
position: absolute;
width: 24px;
height: 24px;
top: 85%;
left: 0px;
cursor: pointer;
background: url(<%= asset_path 'camera_sprite.png' %>) no-repeat;
}
.video-video:hover {
background-position-x: -24px;
}
.video-video.active {
background-position-y: -24px;
}
}
.collaborator-video.my-video {
left: 30px;
top: 72px;
}
#chat-box-wrapper {
height: 100%;
float: right;
}
.chat-box {
position: relative;
display: flex;
flex-direction: column;
z-index: 1;
width: 300px;
height: 100%;
background: #424242;
box-shadow: -8px 0px 16px 2px rgba(0, 0, 0, 0.23);
.chat-button {
position: absolute;
top: 50%;
left: -36px;
width: 36px;
height: 49px;
background: url(<%= asset_path 'junto.png' %>) no-repeat 2px 9px, url(<%= asset_path 'tray_tab.png' %>) no-repeat;
cursor: pointer;
&.active {
background: url(<%= asset_path 'junto_spinner_dark.gif' %>) no-repeat 2px 8px, url(<%= asset_path 'tray_tab.png' %>) no-repeat !important;
}
.chat-unread {
background: #DAB539;
position: absolute;
top: -3px;
left: -11px;
width: 20px;
height: 20px;
border-radius: 11px;
border: 2px solid #424242;
color: #424242;
text-align: center;
font-size: 12px;
font-weight: bold;
line-height: 20px;
}
}
.junto-header {
width: 276px;
padding: 16px 8px 16px 16px;
font-size: 16px;
text-align: left;
font-weight: bold;
background-color: #000000;
color: #f5f5f5;
box-shadow: 0px 6px 3px rgba(0, 0, 0, 0.23);
.cursor-toggle {
width: 32px;
height: 32px;
margin-right: 8px;
margin-top: -8px;
float: right;
background: url(<%= asset_path 'cursor_sprite.png' %>) no-repeat;
}
.cursor-toggle:hover {
background-position-x: -32px;
}
.cursor-toggle.active {
background-position-y: -32px;
}
.video-toggle {
width: 32px;
height: 32px;
margin-right: 10px;
margin-top: -8px;
float: right;
background: url(<%= asset_path 'video_sprite.png' %>) no-repeat;
}
.video-toggle:hover {
background-position-x: -32px;
}
.video-toggle.active {
background-position-y: -32px;
}
}
.participants {
width: 100%;
min-height: 150px;
padding: 16px 0px 16px 0px;
text-align: left;
color: #f5f5f5;
overflow-y: auto;
.conversation-live {
padding: 5px 10px 5px 10px;
background: #c04f4f;
margin: 5px 10px;
border-radius: 2px;
}
.conversation-live .call-action {
float: right;
cursor: pointer;
color: #EBFF00;
}
.participant {
width: 89%;
padding: 8px 8px 2px 8px;
color: #f5f5f5;
font-family: arial, sans-serif;
font-size: 13px;
line-height: 14px;
.chat-participant-image {
width: 15%;
float: left;
overflow: hidden;
color: #BBB;
padding-top: 2px;
}
.chat-participant-image img {
width: 32px;
height: 32px;
border-radius: 18px;
}
.chat-participant-name {
width: 53%;
float: left;
font-size: 13px;
font-weight: bold;
margin-top: 12px;
padding: 2px 8px 0;
text-align: left;
}
.chat-participant-invite-call,
.chat-participant-invite-join
{
float: right;
background: #4FC059 url(<%= asset_path 'invitepeer16.png' %>) no-repeat center center;
}
.chat-participant-invite-call.pending,
.chat-participant-invite-join.pending {
background: #dab539 url(<%= asset_path 'ellipsis.gif' %>) no-repeat center center;
}
.chat-participant-participating {
float: right;
margin-top: 14px;
}
.chat-participant-participating .green-dot {
background: #4fc059;
width: 12px;
height: 12px;
border-radius: 6px;
}
}
}
.chat-header {
width: 276px;
padding: 16px 8px 16px 16px;
font-size: 16px;
text-align: left;
font-weight: bold;
background-color: #000000;
color: #f5f5f5;
box-shadow: 0px 6px 3px rgba(0, 0, 0, 0.23);
.sound-toggle {
width: 24px;
height: 24px;
margin-right: 10px;
margin-top: -2px;
float: right;
background: url(<%= asset_path 'sound_sprite.png' %>) no-repeat;
}
.sound-toggle:hover {
background-position-x: -24px;
}
.sound-toggle.active {
background-position-y: -24px;
}
}
$chat_font_size: 16px;
.chat-input {
min-height: 80px;
width: 88%;
padding: 8px 9% 8px 3%;
font-size: $chat_font_size;
outline: none;
resize: none;
}
.chat-messages {
width: 100%;
padding: 16px 0px;
overflow-y: auto;
flex-grow: 1;
.chat-message {
width: 89%;
padding: 8px 8px 2px 8px;
color: #f5f5f5;
font-family: arial, sans-serif;
font-size: $chat_font_size;
line-height: $chat_font_size + 1px;
a:link {
color: #4fb5c0;
text-decoration: underline;
}
a:visited {
color: #aea9fd;
text-decoration: underline;
}
a:hover {
color: #dab539;
text-decoration: underline;
}
.chat-message-user {
width: 12%;
float: left;
overflow: hidden;
color: #BBB;
padding-top: 2px;
}
.chat-message-user img {
border: 2px solid #424242;
width: 28px;
height: 28px;
border-radius: 16px;
}
.chat-message-meta {
padding: 0 8px;
float: left;
}
.chat-message-username {
color: #4fc059;
}
.chat-message-text {
width: 80%;
float: left;
padding: 2px 8px 0;
text-align: left;
word-wrap: break-word;
}
.chat-message-time {
font-size: 12px;
color: #757575;
}
}
}
.new-message-area {
position: relative;
.extra-message-options {
height: 20px;
position: absolute;
right: 2px;
bottom: 74px;
.emoji-picker-button {
font-size: 16px;
line-height: 20px;
cursor: pointer;
padding: 4px;
}
}
}
}

View file

@ -10,6 +10,6 @@
Metamaps.Loading.setup()
</script>
<%= render :partial => 'layouts/googleanalytics' if Rails.env.production? %>
<%= render :partial => 'layouts/googleanalytics' if ENV["GA_TRACKING_CODE"].present? %>
</body>
</html>

View file

@ -3,16 +3,13 @@
# Google analytics, rendered on every page
#%>
<script type="text/javascript">
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-35984510-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl.' : 'http://') + 'stats.g.doubleclick.net/dc.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
ga('create', '<%= ENV["GA_TRACKING_CODE"] %>', 'auto');
ga('send', 'pageview');
</script>

View file

@ -6,4 +6,4 @@ test:
production:
adapter: redis
url: redis://localhost:6379/1
url: <%= ENV['REDISTOGO_URL'] %>

View file

@ -3,6 +3,8 @@
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb
config.action_cable.allowed_request_origins = ['https://metamaps.herokuapp.com', 'http://metamaps.herokuapp.com', 'https://metamaps.cc']
# log to stdout
logger = Logger.new(STDOUT)
logger.formatter = config.log_formatter

View file

@ -103,7 +103,7 @@ server to see what problems show up:
#### Upstart service for delayed_worker:
Put the following code into `/etc/init/metamaps_delayed_worker.conf`:
If your system uses upstart for init scripts, put the following code into `/etc/init/metamaps_delayed_job.conf`:
description "Delayed Jobs Worker for Metamaps"
@ -128,3 +128,30 @@ Then start the service and check the last ten lines of the log file to make sure
sudo service metamaps_delayed_job start
tail /var/log/upstart/metamaps_delayed_job.log
#### Systemd service for delayed_worker:
If your system uses systemd for init scripts, ptu the following code into `/etc/systemd/system/metamaps_delayed_job.service`:
[Unit]
Description=metamaps delayed job service
After=network-online.target
[Service]
ExecStart=/usr/local/rvm/gems/ruby-2.3.0@metamaps/bin/bundle exec rails jobs:work
WorkingDirectory=/home/metamaps/metamaps
Restart=always
User=metamaps
Group=metamaps
Environment=HOME=/home/metamaps
Environment=PATH="/usr/local/rvm/gems/ruby-2.3.0@metamaps/bin:/usr/local/rvm/gems/ruby-2.3.0@global/bin:/usr/local/rvm/rubies/ruby-2.3.0/bin:/usr/local/rvm/bin:/usr/local/bin:/usr/bin:/bin"
Environment=GEM_PATH="/usr/local/rvm/gems/ruby-2.3.0@metamaps:/usr/local/rvm/gems/ruby-2.3.0@global"
Environment=RAILS_ENV="production"
[Install]
WantedBy=multi-user.target
Then start the service and check the last ten lines of the log file to make sure it's running OK:
sudo systemctl start metamaps_delayed_job
# ??? how the heck do you check systemd logs??

View file

@ -1,6 +1,14 @@
/* global $ */
import { Parser, HtmlRenderer } from 'commonmark'
import { emojiIndex } from 'emoji-mart'
import { escapeRegExp } from 'lodash'
const emojiToShortcodes = {}
Object.keys(emojiIndex.emojis).forEach(key => {
const emoji = emojiIndex.emojis[key]
emojiToShortcodes[emoji.native] = emoji.colons
})
const Util = {
// helper function to determine how many lines are needed
@ -150,6 +158,29 @@ const Util = {
canvas.scale(oldAttr.scaleX, oldAttr.scaleY)
const newAttr = Util.logCanvasAttributes(canvas)
canvas.translate(newAttr.centreCoords.x - oldAttr.centreCoords.x, newAttr.centreCoords.y - oldAttr.centreCoords.y)
},
removeEmoji: function(withEmoji) {
let text = withEmoji
Object.keys(emojiIndex.emojis).forEach(key => {
const emoji = emojiIndex.emojis[key]
text = text.replace(new RegExp(escapeRegExp(emoji.native), 'g'), emoji.colons)
})
return text
},
addEmoji: function(withoutEmoji, opts = { emoticons: false }) {
let text = withoutEmoji
Object.keys(emojiIndex.emojis).forEach(key => {
const emoji = emojiIndex.emojis[key]
text = text.replace(new RegExp(escapeRegExp(emoji.colons), 'g'), emoji.native)
})
if (opts.emoticons) {
Object.keys(emojiIndex.emoticons).forEach(emoticon => {
const key = emojiIndex.emoticons[emoticon]
const emoji = emojiIndex.emojis[key]
text = text.replace(new RegExp(escapeRegExp(emoticon), 'g'), emoji.native)
})
}
return text
}
}

View file

@ -1,5 +1,6 @@
import React from 'react'
import Autolinker from 'autolinker'
import Util from '../../Metamaps/Util'
const linker = new Autolinker({ newWindow: true, truncate: 50, email: false, phone: false })
@ -18,15 +19,19 @@ function formatDate(created_at) {
}
const Message = props => {
const { user_image, user_name, message, created_at } = props
const messageHtml = {__html: linker.link(message)}
const { user_image, user_name, message, created_at, heading } = props
const messageHtml = {__html: linker.link(Util.addEmoji(message, { emoticons: false }))}
return (
<div className="chat-message">
<div className="chat-message-user">
<img src={user_image} title={user_name} />
{heading && <img src={user_image} />}
</div>
{heading && <div className="chat-message-meta">
<span className='chat-message-username'>{user_name}</span>&nbsp;
<span className='chat-message-time'>{formatDate(created_at)}</span>
</div>}
<div className="chat-message-text" dangerouslySetInnerHTML={messageHtml}></div>
<div className="chat-message-time">{formatDate(created_at)}</div>
<div className="clearfloat"></div>
</div>
)

View file

@ -0,0 +1,70 @@
import React, { PropTypes, Component } from 'react'
import { Emoji, Picker } from 'emoji-mart'
import Util from '../../Metamaps/Util'
class NewMessage extends Component {
constructor(props) {
super(props)
this.state = {
showEmojiPicker: false
}
}
toggleEmojiPicker = () => {
this.setState({ showEmojiPicker: !this.state.showEmojiPicker })
}
textAreaValue = () => {
return Util.addEmoji(this.props.messageText)
}
handleClick = (emoji, event) => {
const { messageText } = this.props
this.props.handleChange({ target: {
value: messageText + emoji.colons
}})
this.setState({ showEmojiPicker: false })
this.props.focusMessageInput()
}
render = () => {
return (
<div className="new-message-area">
<Picker set="emojione"
onClick={this.handleClick}
style={{
display: this.state.showEmojiPicker ? 'block' : 'none',
maxWidth: '100%'
}}
emoji="upside_down_face"
title="Emoji"
/>
<div className="extra-message-options">
<span className="emoji-picker-button" onClick={this.toggleEmojiPicker}><Emoji size={24} emoji="upside_down_face" /></span>
</div>
<textarea value={this.textAreaValue()}
onChange={this.props.handleChange}
{...this.props.textAreaProps}
/>
</div>
)
}
}
NewMessage.propTypes = {
messageText: PropTypes.string,
handleChange: PropTypes.func,
focusMessageInput: PropTypes.func,
textAreaProps: PropTypes.shape({
className: PropTypes.string,
ref: PropTypes.func,
placeholder: PropTypes.string,
onKeyUp: PropTypes.func,
onFocus: PropTypes.func,
onBlur: PropTypes.func
})
}
export default NewMessage

View file

@ -2,6 +2,24 @@ import React, { PropTypes, Component } from 'react'
import Unread from './Unread'
import Participant from './Participant'
import Message from './Message'
import NewMessage from './NewMessage'
import Util from '../../Metamaps/Util'
function makeList(messages) {
let currentHeader
return messages ? messages.map(m => {
let heading = false
if (!currentHeader) {
heading = true
currentHeader = m
} else {
// not same user or time diff of greater than 3 minutes
heading = m.user_id !== currentHeader.user_id || Math.floor(Math.abs(new Date(currentHeader.created_at) - new Date(m.created_at)) / 60000) > 3
currentHeader = heading ? m : currentHeader
}
return <Message {...m} key={m.id} heading={heading}/>
}) : null
}
class MapChat extends Component {
constructor(props) {
@ -13,7 +31,7 @@ class MapChat extends Component {
messageText: '',
alertSound: true, // whether to play sounds on arrival of new messages or not
cursorsShowing: true,
videosShowing: true
videosShowing: true
}
}
@ -24,7 +42,7 @@ class MapChat extends Component {
messageText: '',
alertSound: true, // whether to play sounds on arrival of new messages or not
cursorsShowing: true,
videosShowing: true
videosShowing: true
})
}
@ -78,12 +96,17 @@ class MapChat extends Component {
handleTextareaKeyUp = e => {
if (e.which === 13) {
e.preventDefault()
const text = this.state.messageText
const text = Util.removeEmoji(this.state.messageText)
this.props.handleInputMessage(text)
this.setState({ messageText: '' })
}
}
focusMessageInput = () => {
if (!this.messageInput) return
this.messageInput.focus()
}
render = () => {
const rightOffset = this.state.open ? '0' : '-300px'
const { conversationLive, isParticipating, participants, messages, inviteACall, inviteToJoin } = this.props
@ -100,12 +123,12 @@ class MapChat extends Component {
<div className="participants">
{conversationLive && <div className="conversation-live">
LIVE
{isParticipating && <span className="call-action leave" onClick={this.props.leaveCall}>
LEAVE
</span>}
{!isParticipating && <span className="call-action join" onClick={this.props.joinCall}>
JOIN
</span>}
{isParticipating && <span className="call-action leave" onClick={this.props.leaveCall}>
LEAVE
</span>}
{!isParticipating && <span className="call-action join" onClick={this.props.joinCall}>
JOIN
</span>}
</div>}
{participants.map(participant => <Participant
key={participant.id}
@ -124,17 +147,20 @@ class MapChat extends Component {
<div className="tooltips">Chat</div>
<Unread count={unreadMessages} />
</div>
<div className="chat-messages" ref={div => this.messagesDiv = div}>
{messages.map(message => <Message key={message.id} {...message} />)}
<div className="chat-messages" ref={div => { this.messagesDiv = div }}>
{makeList(messages)}
</div>
<textarea className="chat-input"
ref={textarea => this.messageInput = textarea}
placeholder="Send a message..."
value={this.state.messageText}
onChange={this.handleChange('messageText')}
onKeyUp={this.handleTextareaKeyUp}
onFocus={this.props.inputFocus}
onBlur={this.props.inputBlur}
<NewMessage messageText={this.state.messageText}
focusMessageInput={this.focusMessageInput}
handleChange={this.handleChange('messageText')}
textAreaProps={{
className: 'chat-input',
ref: textarea => { this.messageInput = textarea },
placeholder: 'Send a message...',
onKeyUp: this.handleTextareaKeyUp,
onFocus: this.props.inputFocus,
onBlur: this.props.inputBlur
}}
/>
</div>
)
@ -152,7 +178,7 @@ MapChat.propTypes = {
inviteToJoin: PropTypes.func,
videoToggleClick: PropTypes.func,
cursorToggleClick: PropTypes.func,
soundToggleClick: PropTypes.func,
soundToggleClick: PropTypes.func,
participants: PropTypes.arrayOf(PropTypes.shape({
color: PropTypes.string, // css color
id: PropTypes.number,

View file

@ -27,9 +27,10 @@
"babel-preset-es2015": "6.18.0",
"babel-preset-react": "6.16.0",
"backbone": "1.0.0",
"clipboard-js": "git://github.com/devvmh/clipboard.js#patch-1",
"clipboard-js": "0.3.2",
"commonmark": "0.27.0",
"csv-parse": "1.1.7",
"emoji-mart": "^0.3.5",
"getScreenMedia": "git://github.com/devvmh/getScreenMedia#patch-1",
"hark": "git://github.com/devvmh/hark#patch-1",
"howler": "2.0.2",