customer chat

This commit is contained in:
Felix Niklas 2015-10-06 21:51:28 +02:00
parent ed1de38ce7
commit c97f4ef8f8
31 changed files with 872 additions and 168 deletions

View file

@ -15,5 +15,5 @@ App.Config.set( 'Admin', { prio: 9000, parent: '', name: 'Admin', translate: tru
App.Config.set( 'New', { prio: 20000, parent: '', name: 'New', translate: true, target: '#new', class: 'add' }, 'NavBarRight' ) App.Config.set( 'New', { prio: 20000, parent: '', name: 'New', translate: true, target: '#new', class: 'add' }, 'NavBarRight' )
App.Config.set( 'Misc', { prio: 90000, parent: '', name: 'Tools', translate: true, target: '#tools', child: true, class: 'tools' }, 'NavBar' ) App.Config.set( 'Misc', { prio: 90000, parent: '', name: 'Tools', translate: true, target: '#tools', child: true, class: 'tools' }, 'NavBar' )
#App.Config.set( 'Misc1', { prio: 1600, parent: '#tools', name: 'Test 1', target: '#test1', role: [ 'Admin' ] }, 'NavBar' ) App.Config.set( 'Misc1', { prio: 1600, parent: '#tools', name: 'Test 1', target: '#test1', role: [ 'Admin' ] }, 'NavBar' )
#App.Config.set( 'Misc2', { prio: 1700, parent: '#tools', name: 'Test 2', target: '#test2', role: [ 'Admin' ] }, 'NavBar' ) App.Config.set( 'Misc2', { prio: 1700, parent: '#tools', name: 'Test 2', target: '#test2', role: [ 'Admin' ] }, 'NavBar' )

View file

@ -1657,4 +1657,370 @@ class PrimaryEmailRef extends App.ControllerContent
App.Config.set( 'layout_ref/primary_email', PrimaryEmailRef, 'Routes' ) App.Config.set( 'layout_ref/primary_email', PrimaryEmailRef, 'Routes' )
class App.CustomerChatRef extends App.ControllerContent
@extend Spine.Events
questions: [
{
question: "Der dümmste Bauer hat die dicksten ..?"
answers: ["Kartoffeln"]
},
{
question: "Welchen Wein besang einst Udo Jürgens?"
answers: ["griechisch"]
},
{
question: "Was behandelt ein Logopäde?"
answers: ["Sprachstörung"]
},
{
question: "In welcher Stadt ist das Porsche Stammwerk?"
answers: ["Stuttgart"]
},
{
question: "Wer erfand den legendären C64-Computer?"
answers: ["Commodore"]
},
{
question: 'Im Englischen steht "Lost And Found" für ..?'
answers: ["Fundbüro"]
},
{
question: 'Welches Möbelstück ist und war besonders in Sigmund Freuds Arbeitszimmer bekannt?'
answers: ["Couch"]
},
{
question: 'Wenn es einem gut geht, lebt man "wie die Made im .."?'
answers: ["Speck"]
},
{
question: 'Von welcher Sportart handelt der US-amerikanische Film "Rocky"?'
answers: ["Boxen"]
},
{
question: 'Wo soll man hingehen, wenn man sich weit entfernen soll? Dahin wo ..?'
answers: ["Pfeffer", "wächst"]
},
{
question: 'Welches internationale Autokennzeichen hat Spanien?'
answers: ["ES"]
},
{
question: 'Wenn man sich ärgert sagt man "Verdammt und .."?'
answers: ["zugenäht"]
},
{
question: 'Bei welchem Spiel muss man ohne zu zittern Stäbchen sammeln?'
answers: ["Mikado"]
},
{
question: 'Wann wurde Znuny gegründet?'
answers: ["2012"]
}
]
constructor: ->
super
@i = 0
@chatWindows = []
@totalQuestions = 7
@answered = 0
@correct = 0
@wrong = 0
@maxChats = 4;
@render()
render: ->
@html App.view('layout_ref/customer_chat')()
@addChat()
# @testChat @chatWindows[0], 100
@initQuiz()
testChat: (chat, count) ->
for i in [0..count]
text = @questions[Math.floor(Math.random() * @questions.length)].question
chat.addMessage text, if i % 2 then 'customer' else 'agent'
addChat: ->
chat = new chatWindowRef
name: "Quizmaster-#{ ++@i }"
@on 'layout-has-changed', @propagateLayoutChange
@$('.chat-workspace').append(chat.el)
@chatWindows.push chat
propagateLayoutChange: (event) =>
# adjust scroll position on layoutChange
console.log "propagateLayoutChange", event
for chat in @chatWindows
chat.trigger 'layout-changed'
initQuiz: ->
@chatWindows[0].addStatusMessage('To start the quiz type <strong>Start</strong>')
@chatWindows[0].bind "answer", @startQuiz
startQuiz: (answer) =>
return false unless answer is "Start"
@chatWindows[0].unbind "answer"
@nextQuestion()
nextQuestion: ->
if not @questions.length
@currentChat.addStatusMessage("Du hast #{ @correct } von #{ @totalQuestions } Fragen richtig beantwortet!")
for chat in @chatWindows
chat.unbind "answer"
if chat is not @currentChat
chat.goOffline()
return
if @chatWindows.length < @maxChats and Math.random() < 0.2
@addChat()
randomWindowId = @chatWindows.length-1
else
# maybe take a chat offline
if @chatWindows.length > 1 and Math.random() > 0.85
randomWindowId = Math.floor(Math.random()*@chatWindows.length)
[killedChat] = @chatWindows.splice randomWindowId, 1
killedChat.goOffline()
randomWindowId = Math.floor(Math.random()*@chatWindows.length)
randomQuestionId = Math.floor(Math.random()*@questions.length)
@currentQuestion = @questions.splice(randomQuestionId, 1)[0]
newChat = @chatWindows[randomWindowId]
messageDelay = 500
if newChat != @currentChat
@currentChat.unbind("answer") if @currentChat
@currentChat = newChat
@currentChat.bind "answer", @onQuestionAnswer
messageDelay = 1500
@currentChat.showWritingLoader()
setTimeout @currentChat.receiveMessage, messageDelay + Math.random() * 1000, @currentQuestion.question
onQuestionAnswer: (answer) =>
match = false
for text in @currentQuestion.answers
if answer.match( new RegExp(text,'i') )
match = true
@answered++
if match
@correct++
@currentChat.receiveMessage _.shuffle(['😀','😃','😊','😍','😎','😏','👍','😌','😇','👌'])[0]
else
@wrong++
@currentChat.receiveMessage _.shuffle(['👎','💩','😰','😩','😦','😧','😟','😠','😡','😞','😢','😒','😕'])[0]
if @answerd is @totalQuestions
@finishQuiz()
else
@nextQuestion()
App.Config.set( 'layout_ref/customer_chat', App.CustomerChatRef, 'Routes' )
App.Config.set( 'Chat', { prio: 300, parent: '', name: 'Customer Chat', target: '#layout_ref/customer_chat', switch: true, counter: true, role: ['Agent'], class: 'chat' }, 'NavBar' )
# App.Config.set( 'Chat', { controller: 'CustomerChatRef', authentication: true }, 'permanentTask' )
class chatWindowRef extends Spine.Controller
@extend Spine.Events
className: 'chat-window'
events:
'keydown .js-customerChatInput': 'onKeydown'
'focus .js-customerChatInput': 'clearUnread'
'click': 'clearUnread'
'click .js-send': 'sendMessage'
'click .js-close': 'close'
elements:
'.js-customerChatInput': 'input'
'.js-status': 'status'
'.js-body': 'body'
'.js-scrollHolder': 'scrollHolder'
sound:
message: new Audio('assets/sounds/chat_message.mp3')
window: new Audio('assets/sounds/chat_new.mp3')
constructor: ->
super
@showTimeEveryXMinutes = 1
@lastTimestamp
@lastAddedType
@render()
@sound.window.play()
@on 'layout-change', @scrollToBottom
render: ->
@html App.view('layout_ref/customer_chat_window')
name: @options.name
@el.one 'transitionend', @onTransitionend
# make sure animation will run
setTimeout (=> @el.addClass('is-open')), 0
# @addMessage 'Hello. My name is Roger, how can I help you?', 'agent'
onTransitionend: (event) =>
# chat window is done with animation - adjust scroll-bars
# of sibling chat windows
@trigger 'layout-has-changed'
if event.data and event.data.callback
event.data.callback()
close: =>
@el.one 'transitionend', { callback: @release }, @onTransitionend
@el.removeClass('is-open')
release: =>
@trigger 'closed'
super
clearUnread: =>
@$('.chat-message--new').removeClass('chat-message--new')
@updateModified(false)
onKeydown: (event) =>
TABKEY = 9;
ENTERKEY = 13;
switch event.keyCode
when TABKEY
allChatInputs = $('.js-customerChatInput').not('[disabled="disabled"]')
chatCount = allChatInputs.size()
index = allChatInputs.index(@input)
if chatCount > 1
switch index
when chatCount-1
if !event.shiftKey
# State: tab without shift on last input
# Jump to first input
event.preventDefault()
allChatInputs.eq(0).focus()
when 0
if event.shiftKey
# State: tab with shift on first input
# Jump to last input
event.preventDefault()
allChatInputs.eq(chatCount-1).focus()
when ENTERKEY
if !event.shiftKey
event.preventDefault()
@sendMessage()
sendMessage: =>
return if !@input.html()
@addMessage @input.html(), 'agent'
@trigger "answer", @input.html()
@input.html('')
updateModified: (state) =>
@status.toggleClass('is-modified', state)
receiveMessage: (message) =>
isFocused = @input.is(':focus')
@removeWritingLoader()
@addMessage(message, 'customer', !isFocused)
if !isFocused
@updateModified(true)
@sound.message.play()
addMessage: (message, sender, isNew) =>
@maybeAddTimestamp()
@lastAddedType = sender
@body.append App.view('layout_ref/customer_chat_message')
message: message
sender: sender
isNew: isNew
timestamp: Date.now()
@scrollToBottom()
showWritingLoader: =>
@maybeAddTimestamp()
@body.append App.view('layout_ref/customer_chat_loader')()
@scrollToBottom()
removeWritingLoader: =>
@$('.js-loader').remove()
goOffline: =>
@addStatusMessage("<strong>#{ @options.name }</strong>'s connection got closed")
@status.attr('data-status', 'offline')
@el.addClass('is-offline')
@input.attr('disabled', true)
maybeAddTimestamp: ->
timestamp = Date.now()
if !@lastTimestamp or timestamp - @lastTimestamp > @showTimeEveryXMinutes * 60000
label = 'Today'
time = new Date().toTimeString().substr(0,5)
if @lastAddedType is 'timestamp'
# update last time
@updateLastTimestamp label, time
@lastTimestamp = timestamp
else
@addTimestamp label, time
@lastTimestamp = timestamp
@lastAddedType = 'timestamp'
addTimestamp: (label, time) =>
@body.append App.view('layout_ref/customer_chat_timestamp')
label: label
time: time
updateLastTimestamp: (label, time) ->
@body
.find('.js-timestamp')
.last()
.replaceWith App.view('layout_ref/customer_chat_timestamp')
label: label
time: time
addStatusMessage: (message) ->
@body.append App.view('layout_ref/customer_chat_status_message')
message: message
@scrollToBottom()
scrollToBottom: ->
@scrollHolder.scrollTop(@scrollHolder.prop('scrollHeight'))
App.Config.set( 'LayoutRef', { prio: 1700, parent: '#current_user', name: 'Layout Reference', translate: true, target: '#layout_ref', role: [ 'Admin' ] }, 'NavBarRight' ) App.Config.set( 'LayoutRef', { prio: 1700, parent: '#current_user', name: 'Layout Reference', translate: true, target: '#layout_ref', role: [ 'Admin' ] }, 'NavBarRight' )

View file

@ -4,7 +4,7 @@
<li <% if item.active: %>class="active"<% end %>> <li <% if item.active: %>class="active"<% end %>>
<a class="horizontal center" href="<%= item.target %>"> <a class="horizontal center" href="<%= item.target %>">
<span class="local u-textTruncate"><%- @T(item.name) %></span> <span class="local u-textTruncate"><%- @T(item.name) %></span>
<span class="badge"><%= item.count %></span> <span class="badge badge--text"><%= item.count %></span>
</a> </a>
</li> </li>
<% end %> <% end %>

View file

@ -0,0 +1,24 @@
<div class="chat main">
<div class="page-header">
<div class="page-header-title">
<h1>Customer Chat</h1>
</div>
<div class="page-header-center">
<div class="status-fields">
<div class="status-field">
<span class="badge">0</span> Waiting Customers
</div>
<div class="status-field">
<span class="badge">15</span> Chatting Customers
</div>
<div class="status-field">
<span class="badge">5</span> Active Agents
</div>
</div>
</div>
<div class="page-header-meta">
<div class="btn btn--action" data-type="settings"><%= @T('Settings') %></div>
</div>
</div>
<div class="chat-workspace"></div>
</div>

View file

@ -0,0 +1,7 @@
<div class="chat-message chat-message--customer chat-message--loader js-loader">
<div class="chat-loader">
<%- @Icon('loading') %>
<%- @Icon('loading') %>
<%- @Icon('loading') %>
</div>
</div>

View file

@ -0,0 +1 @@
<div class="chat-message chat-message--<%= @sender %><%= ' chat-message--new' if @isNew %>"><%- @message %></div>

View file

@ -0,0 +1 @@
<div class="chat-status-message"><%- @message %></div>

View file

@ -0,0 +1 @@
<div class="chat-timestamp js-timestamp"><span class="chat-timestamp-label"><%= @label %></span> <%= @time %></div>

View file

@ -0,0 +1,20 @@
<div class="chat-header">
<div class="chat-status js-status" data-status="online">
<div class="chat-status-holder">
<%- @Icon('status') %>
<%- @Icon('status-modified-outer-circle') %>
<%- @Icon('status-modified-inner-circle') %>
</div>
</div>
<div class="chat-name"><%- @name %></div>
<div class="chat-close js-close">
<%- @Icon('diagonal-cross') %>
</div>
</div>
<div class="chat-body-holder js-scrollHolder">
<div class="chat-body js-body"></div>
</div>
<div class="chat-controls">
<div class="chat-input form-control form-control--small form-control--multiline js-customerChatInput" contenteditable="true"></div>
<div class="btn btn--primary btn--slim btn--small js-send"><%= @T('Send') %></div>
</div>

View file

@ -4,6 +4,7 @@
<ul> <ul>
<li><a href="#layout_ref/customer_chat">Customer Chat</a></li>
<li><a href="#layout_ref/ticket_zoom">Ticket Zoom</a></li> <li><a href="#layout_ref/ticket_zoom">Ticket Zoom</a></li>
<li><a href="#layout_ref/primary_email">Primary Email (New/Edit User)</a></li> <li><a href="#layout_ref/primary_email">Primary Email (New/Edit User)</a></li>
<li><a href="#layout_ref/merge_customer">Merge Customer</a></li> <li><a href="#layout_ref/merge_customer">Merge Customer</a></li>

View file

@ -1,6 +1,6 @@
<% for item in @items: %> <% for item in @items: %>
<% if item.child: %> <% if item.child: %>
<li class="dropdown <%= item.class %> <% if @open_tab[item.target] : %>open<% end %>"> <li class="dropdown <% if @open_tab[item.target] : %>open<% end %>">
<a href="<%= item.target %>" class="dropdown-toggle" data-toggle="dropdown"> <a href="<%= item.target %>" class="dropdown-toggle" data-toggle="dropdown">
<%- @Icon(item.class, 'nav-icon') %> <%- @Icon(item.class, 'nav-icon') %>
<span class="nav-item-name flex"> <span class="nav-item-name flex">
@ -16,17 +16,26 @@
<% if item.navheader: %> <% if item.navheader: %>
<li class="dropdown-header"><%- @T( item.navheader ) %></li> <li class="dropdown-header"><%- @T( item.navheader ) %></li>
<% end %> <% end %>
<li class="<% if @active_tab[item.target] : %>active<% end %>"><a href="<%= item.target %>"><%- @T( item.name ) %><% if item['count'] isnt undefined: %><span class="badge count"><%= item['count'] %></span><% end %></a></li> <li class="<% if @active_tab[item.target] : %>active<% end %>"><a href="<%= item.target %>"><%- @T( item.name ) %><% if item['count'] isnt undefined: %><span class="badge badge--text count"><%= item['count'] %></span><% end %></a></li>
<% end %> <% end %>
</ul> </ul>
</li> </li>
<% else: %> <% else: %>
<li class="<%= item.class %> <% if @active_tab[item.target] : %>active<% end %>"> <li<% ' class="active"' if @active_tab[item.target] %>>
<a class="horizontal center" href="<%= item.target %>"> <a class="horizontal center" href="<%= item.target %>">
<%- @Icon(item.class, 'nav-icon') %> <%- @Icon(item.class, 'nav-icon') %>
<span class="nav-item-name"> <span class="nav-item-name">
<%- @T(item.name) %> <%- @T(item.name) %>
</span> </span>
<% if item.counter: %>
<span class="counter badge badge--big"></span>
<% end %>
<% if item.switch: %>
<div class="zammad-switch zammad-switch--dark zammad-switch--small">
<input type="checkbox" id="<%- item.class %>-switch">
<label for="<%- item.class %>-switch"></label>
</div>
<% end %>
</a> </a>
</li> </li>
<% end %> <% end %>

View file

@ -20,7 +20,7 @@
<li class="<% if @active_tab[item.target] : %>active<% end %>"> <li class="<% if @active_tab[item.target] : %>active<% end %>">
<a href="<%= item.target %>" class="horizontal center"> <a href="<%= item.target %>" class="horizontal center">
<span class="flex u-textTruncate"><% if item.translate: %><%- @T( item.name ) %><% else: %><%= item.name %><% end %></span> <span class="flex u-textTruncate"><% if item.translate: %><%- @T( item.name ) %><% else: %><%= item.name %><% end %></span>
<% if item['count'] isnt undefined: %><span class="badge count"><%= item['count'] %></span><% end %> <% if item['count'] isnt undefined: %><span class="badge badge--text count"><%= item['count'] %></span><% end %>
<% if item.iconClass: %><%- @Icon(item.iconClass) %><% end %> <% if item.iconClass: %><%- @Icon(item.iconClass) %><% end %>
</a> </a>
</li> </li>

View file

@ -3513,51 +3513,6 @@ a.label:focus {
.label-danger[href]:focus { .label-danger[href]:focus {
background-color: #c9302c; background-color: #c9302c;
} }
.badge {
display: inline-block;
min-width: 10px;
padding: 3px 7px;
font-size: 12px;
font-weight: bold;
line-height: 1;
color: #fff;
text-align: center;
white-space: nowrap;
vertical-align: baseline;
background-color: #777;
border-radius: 10px;
}
.badge:empty {
display: none;
}
.btn .badge {
position: relative;
top: -1px;
}
.btn-xs .badge {
top: 0;
padding: 1px 5px;
}
a.badge:hover,
a.badge:focus {
color: #fff;
text-decoration: none;
cursor: pointer;
}
.list-group-item.active > .badge,
.nav-pills > .active > a > .badge {
color: #337ab7;
background-color: #fff;
}
.list-group-item > .badge {
float: right;
}
.list-group-item > .badge + .badge {
margin-right: 5px;
}
.nav-pills > li > a > .badge {
margin-left: 3px;
}
.jumbotron { .jumbotron {
padding: 30px 15px; padding: 30px 15px;
margin-bottom: 30px; margin-bottom: 30px;

View file

@ -8,9 +8,6 @@
font-style: normal; font-style: normal;
} }
@font-face { @font-face {
font-family: 'Fira Sans'; font-family: 'Fira Sans';
src: url('fonts/FiraSans-Regular.eot'); src: url('fonts/FiraSans-Regular.eot');
@ -21,8 +18,15 @@
font-style: normal; font-style: normal;
} }
@font-face {
font-family: 'Fira Sans';
src: url('fonts/FiraSans-Medium.eot');
src: url('fonts/FiraSans-Medium.woff2') format('woff2'),
url('fonts/FiraSans-Medium.woff') format('woff'),
url('fonts/FiraSans-Medium.ttf') format('truetype');
font-weight: 500;
font-style: normal;
}
@font-face { @font-face {
font-family: 'Fira Sans'; font-family: 'Fira Sans';

View file

@ -2,6 +2,7 @@
.icon-arrow-left { width: 7px; height: 13px; } .icon-arrow-left { width: 7px; height: 13px; }
.icon-arrow-right { width: 7px; height: 13px; } .icon-arrow-right { width: 7px; height: 13px; }
.icon-arrow-up { width: 13px; height: 7px; } .icon-arrow-up { width: 13px; height: 7px; }
.icon-chat { width: 24px; height: 24px; }
.icon-checkbox-checked { width: 11px; height: 11px; } .icon-checkbox-checked { width: 11px; height: 11px; }
.icon-checkbox { width: 11px; height: 11px; } .icon-checkbox { width: 11px; height: 11px; }
.icon-checkmark { width: 16px; height: 14px; } .icon-checkmark { width: 16px; height: 14px; }
@ -55,9 +56,6 @@
.icon-phone { width: 17px; height: 17px; } .icon-phone { width: 17px; height: 17px; }
.icon-plus-small { width: 16px; height: 16px; } .icon-plus-small { width: 16px; height: 16px; }
.icon-plus { width: 20px; height: 20px; } .icon-plus { width: 20px; height: 20px; }
.icon-priority-modified-inner-circle { width: 16px; height: 16px; }
.icon-priority-modified-outer-circle { width: 16px; height: 16px; }
.icon-priority { width: 16px; height: 16px; }
.icon-radio-checked { width: 11px; height: 11px; } .icon-radio-checked { width: 11px; height: 11px; }
.icon-radio { width: 11px; height: 11px; } .icon-radio { width: 11px; height: 11px; }
.icon-received-calls { width: 17px; height: 17px; } .icon-received-calls { width: 17px; height: 17px; }
@ -67,11 +65,11 @@
.icon-reply { width: 16px; height: 16px; } .icon-reply { width: 16px; height: 16px; }
.icon-signout { width: 15px; height: 19px; } .icon-signout { width: 15px; height: 19px; }
.icon-split { width: 16px; height: 16px; } .icon-split { width: 16px; height: 16px; }
.icon-status-modified-inner-circle { width: 16px; height: 16px; }
.icon-status-modified-outer-circle { width: 16px; height: 16px; }
.icon-status { width: 16px; height: 16px; } .icon-status { width: 16px; height: 16px; }
.icon-stopwatch { width: 77px; height: 83px; } .icon-stopwatch { width: 77px; height: 83px; }
.icon-switchView { width: 19px; height: 18px; } .icon-switchView { width: 19px; height: 18px; }
.icon-task-state-modified-inner-circle { width: 16px; height: 16px; }
.icon-task-state-modified-outer-circle { width: 16px; height: 16px; }
.icon-task-state { width: 16px; height: 16px; } .icon-task-state { width: 16px; height: 16px; }
.icon-team { width: 16px; height: 16px; } .icon-team { width: 16px; height: 16px; }
.icon-templates { width: 24px; height: 24px; } .icon-templates { width: 24px; height: 24px; }

View file

@ -46,6 +46,10 @@ p {
} }
} }
strong {
font-weight: 500;
}
.text-muted { .text-muted {
color: hsl(60,1%,74%); color: hsl(60,1%,74%);
} }
@ -320,6 +324,11 @@ span[data-tooltip]:hover:before {
box-shadow: 0 0 0 3px hsl(201,62%,90%); box-shadow: 0 0 0 3px hsl(201,62%,90%);
} }
&.btn--small {
padding-top: 5px;
padding-bottom: 4px;
}
&.btn--slim { &.btn--slim {
padding-left: 12px; padding-left: 12px;
padding-right: 12px; padding-right: 12px;
@ -356,7 +365,7 @@ span[data-tooltip]:hover:before {
font-size: 12px; font-size: 12px;
letter-spacing: 0.05em; letter-spacing: 0.05em;
height: 31px; height: 31px;
padding: 6px 11px !important; padding: 2px 11px 0 !important;
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
@ -589,6 +598,78 @@ span[data-tooltip]:hover:before {
} }
} }
.status-fields {
display: flex;
}
.status-field {
background: hsl(210,7%,95%);
color: hsl(0,0%,66%);
padding: 8px 10px 6px;
border: 1px solid hsl(0,0%,91%);
box-shadow: 0 1px rgba(0,0,0,.02) inset;
&:not(:last-child):not(:only-child) {
border-right: none;
}
&:first-child {
border-radius: 5px 0 0 5px;
}
&:last-child {
border-radius: 0 5px 5px 0;
}
&:only-child {
border-radius: 5px;
}
.badge {
background: hsl(210,5%,77%);
}
}
.badge {
display: inline-block;
min-width: 18px;
padding: 3px 5px;
font-size: 12px;
font-weight: 500;
line-height: 1;
color: #fff;
text-align: center;
white-space: nowrap;
vertical-align: top;
border-radius: 9px;
background: hsl(198,18%,86%);
margin-right: 3px;
&:empty {
display: none;
}
&.badge--big {
min-width: 22px;
font-size: 14px;
border-radius: 11px;
padding: 5px 7px 3px;
}
&.badge--text {
min-width: 0;
padding: 0;
margin-right: 5px;
font-size: inherit;
font-weight: normal;
text-align: left;
color: #d0d2d3;
background: none;
border-radius: 0;
}
}
table { table {
table-layout: fixed; table-layout: fixed;
@ -864,6 +945,7 @@ label,
/* circumventing the label:not(.inline-label) selector because it's too strong */ /* circumventing the label:not(.inline-label) selector because it's too strong */
.inline-label, .inline-label,
.label.label-success,
.label.label-warning, .label.label-warning,
.label.label-danger { .label.label-danger {
font-size: inherit; font-size: inherit;
@ -882,11 +964,16 @@ label,
cursor: pointer; cursor: pointer;
} }
.label.label-success,
.label.label-warning, .label.label-warning,
.label.label-danger { .label.label-danger {
background: none; background: none;
} }
.label.label-success {
color: $supergood-color;
}
.label.label-warning { .label.label-warning {
color: $ok-color; color: $ok-color;
} }
@ -1130,12 +1217,12 @@ textarea,
.form-control, .form-control,
.checkbox.form-group .checkbox { .checkbox.form-group .checkbox {
display: block; display: block;
padding: 6px 12px; padding: 7px 12px;
width: 100%; width: 100%;
height: 41px; height: 41px;
font-size: 14px; font-size: 14px;
font-weight: normal; font-weight: normal;
line-height: 27px; line-height: 25px;
color: #555; color: #555;
background: white; background: white;
border: 1px solid hsl(0, 0%, 90%); border: 1px solid hsl(0, 0%, 90%);
@ -1146,15 +1233,19 @@ textarea,
appearance: none; appearance: none;
&.form-control--small { &.form-control--small {
padding: 0 8px; padding: 5px 8px 4px;
height: 31px; height: 31px;
line-height: 29px; line-height: 20px;
} }
&.form-control--inline { &.form-control--inline {
display: inline-block; display: inline-block;
width: auto; width: auto;
} }
&.form-control--multiline {
height: auto;
}
} }
input[type=url] { input[type=url] {
@ -1575,6 +1666,17 @@ kbd {
.page-header-title h1 { .page-header-title h1 {
margin-top: 9px; margin-top: 9px;
margin-bottom: 7px;
}
.page-header-center {
justify-self: center;
padding-left: 9px;
margin: 0 auto;
& + .page-header-meta {
margin-left: 0;
}
} }
.page-header-meta { .page-header-meta {
@ -1991,6 +2093,21 @@ ol.tabs li {
} }
} }
.icon-status-modified-inner-circle {
position: absolute;
left: 0;
top: 0;
will-change: opacity;
transform: translateZ(0);
animation: fade 1.8s ease-in-out infinite;
}
@keyframes fade {
54% { opacity: 1 }
90% { opacity: 0 }
to { opacity: 1 }
}
.icon-checkbox, .icon-checkbox,
.icon-checkbox-checked { .icon-checkbox-checked {
fill: white; fill: white;
@ -2164,6 +2281,16 @@ footer {
flex-shrink: 0; flex-shrink: 0;
} }
.main-navigation .badge {
background: $ok-color;
color: hsl(233,10%,16%);
margin-right: 8px;
}
.main-navigation .zammad-switch {
height: 22px;
}
.main-navigation > li > a { .main-navigation > li > a {
padding: 0 15px; padding: 0 15px;
height: 48px; height: 48px;
@ -2326,21 +2453,6 @@ footer {
height: 12px; height: 12px;
} }
.nav-tab-icon .modified-inner-circle {
position: absolute;
left: 0;
top: 0;
will-change: opacity;
transform: translateZ(0);
animation: fade 1.8s ease-in-out infinite;
}
@keyframes fade {
54% { opacity: 1 }
90% { opacity: 0 }
to { opacity: 1 }
}
.nav-tab-icon .icon.icon-loading { .nav-tab-icon .icon.icon-loading {
animation: rotateplane 1.2s infinite ease-in-out; animation: rotateplane 1.2s infinite ease-in-out;
fill: $supergood-color; fill: $supergood-color;
@ -2866,18 +2978,6 @@ footer {
border-top: none; border-top: none;
} }
.badge {
min-width: 0;
padding: 0;
margin-right: 5px;
font-size: inherit;
font-weight: normal;
text-align: left;
color: #d0d2d3;
background: none;
border-radius: 0;
}
.nav-pills > li > a > .badge { .nav-pills > li > a > .badge {
margin-left: auto; margin-left: auto;
} }
@ -3162,7 +3262,7 @@ footer {
} }
.time.stat-widget .stat-amount { .time.stat-widget .stat-amount {
margin-top: 8px; margin-top: 12px;
text-align: center; text-align: center;
font-size: 30px; font-size: 30px;
color: white; color: white;
@ -5843,11 +5943,36 @@ output {
} }
} }
.zammad-switch label { .zammad-switch {
position: relative; width: 50px;
width: 48px;
height: 30px; height: 30px;
border-radius: 15px; border-radius: 15px;
overflow: hidden;
&.zammad-switch--small {
width: 40px;
height: 24px;
border-radius: 12px;
}
&.zammad-switch--dark {
label {
background: hsl(234,10%,5%);
}
label:before {
background: hsl(233,10%,10%);
}
label:after {
background: hsl(234,10%,19%);
}
}
}
.zammad-switch label {
position: relative;
width: 100%;
height: 100%;
border-radius: inherit;
outline: none; outline: none;
cursor: pointer; cursor: pointer;
background: hsl(0,0%,90%); background: hsl(0,0%,90%);
@ -5859,7 +5984,7 @@ output {
} }
.zammad-switch input:checked + label { .zammad-switch input:checked + label {
background: hsl(200,71%,59%); background: $supergood-color;
} }
.zammad-switch input:focus + label { .zammad-switch input:focus + label {
@ -5876,8 +6001,8 @@ output {
} }
.zammad-switch label:before { .zammad-switch label:before {
width: 46px; width: calc(100% - 2px);
height: 28px; height: calc(100% - 2px);
left: 1px; left: 1px;
top: 1px; top: 1px;
border-radius: inherit; border-radius: inherit;
@ -5891,9 +6016,9 @@ output {
} }
.zammad-switch label:after { .zammad-switch label:after {
width: 28px; width: calc(60% - 2px);
height: 28px; height: calc(100% - 2px);
border-radius: 100%; border-radius: inherit;
left: 1px; left: 1px;
top: 1px; top: 1px;
box-shadow: box-shadow:
@ -5903,7 +6028,7 @@ output {
} }
.zammad-switch input:checked + label:after { .zammad-switch input:checked + label:after {
transform: translateX(18px); transform: translateX(70%);
} }
.horizontal-filter-text { .horizontal-filter-text {
@ -6545,6 +6670,222 @@ output {
} }
} }
.chat {
background: white;
flex: 1;
display: flex;
flex-direction: column;
.page-header {
margin: 15px 6px 5px;
}
}
.chat-workspace {
display: flex;
flex-wrap: wrap;
padding: 0 0 10px;
margin: 0 -4px;
flex: 1;
}
.chat-window {
flex: 0 1 0;
overflow: hidden;
padding: 10px;
display: flex;
flex-direction: column;
color: hsl(0,0%,33%);
transition: all 500ms;
transform: scale(0);
&.is-open {
flex: 1 0 25%;
transform: scale(1);
}
&.is-offline {
.chat-body-holder,
.chat-controls {
opacity: 0.5;
}
}
}
.chat-header {
padding: 12px 40px;
background: hsl(210,8%,95%);
border: 1px solid hsl(0,0%,91%);
border-radius: 3px 3px 0 0;
position: relative;
line-height: 13px;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex-shrink: 0;
}
.chat-status,
.chat-close {
position: absolute;
top: 0;
padding-top: inherit;
padding-bottom: inherit;
padding-left: 10px;
padding-right: 10px;
}
.chat-status {
left: 0;
top: -1px;
&[data-status='online'] .icon {
fill: $supergood-color;
}
&[data-status='offline'] .icon {
fill: $superbad-color;
}
.icon-status-modified-inner-circle,
.icon-status-modified-outer-circle {
display: none;
}
&.is-modified {
.icon-status {
display: none;
}
.icon-status-modified-inner-circle,
.icon-status-modified-outer-circle {
display: block;
}
}
}
.chat-status-holder {
position: relative;
}
.chat-close {
right: 0;
cursor: pointer;
.icon {
fill: hsl(197,19%,78%);
}
&:hover {
background: hsl(197,18%,96%);
}
}
.chat-body-holder {
flex: 1;
background: hsl(210,17%,98%);
font-size: 13px;
line-height: 18px;
overflow: auto;
border-right: 1px solid hsl(0,0%,91%);
border-left: 1px solid hsl(0,0%,91%);
position: relative;
}
.chat-body {
padding: 10px;
display: flex;
flex-direction: column;
align-items: flex-start;
position: absolute;
width: 100%;
top: 0;
left: 0;
}
.chat-timestamp {
font-size: 12px;
color: hsl(10,5%,78%);
margin-bottom: 4px;
align-self: center;
}
.chat-timestamp-label {
font-weight: 500;
}
.chat-message {
max-width: 90%;
background: white;
padding: 6px 12px;
border-radius: 16px;
margin-bottom: 4px;
}
.chat-message--customer.chat-message--new {
font-weight: 500;
}
.chat-message--agent {
margin-left: auto;
background: hsl(199,44%,93%);
align-self: flex-end;
}
.chat-message--agent + .chat-message--customer,
.chat-message--customer + .chat-message--agent {
margin-top: 10px;
}
.chat-status-message {
align-self: center;
background: hsl(197,18%,92%);
padding: 6px 12px;
margin: 4px 0 10px;
border-radius: 3px;
}
.chat-loader {
margin-right: -4px;
.icon {
fill: hsl(0,0%,90%);
margin-left: -4px;
vertical-align: middle;
animation: fadeInDown 300ms both;
animation: ease-in-out load-fade 600ms infinite alternate;
}
.icon + .icon {
animation-delay: .13s;
}
.icon + .icon + .icon {
animation-delay: .26s;
}
}
@keyframes load-fade {
from { opacity: .5; transform: scale(0.6); }
67% { opacity: 1; transform: scale(1); }
}
.chat-controls {
display: flex;
align-items: flex-start;
padding: 10px;
border: 1px solid hsl(0,0%,91%);
border-radius: 0 0 3px 3px;
flex-shrink: 0;
}
.chat-input {
margin-right: 10px;
max-height: 50vh;
overflow: auto;
}
/* /*
---------------- ----------------

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.3.3 (12072) - http://www.bohemiancoding.com/sketch -->
<title>chat</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="chat" sketch:type="MSArtboardGroup" fill="#50E3C2">
<path d="M2,5.00585866 C2,3.89805351 2.89821238,3 3.99079514,3 L20.0092049,3 C21.1086907,3 22,3.89706013 22,5.00585866 L22,14.9941413 C22,16.1019465 21.1017876,17 20.0092049,17 L3.99079514,17 C2.89130934,17 2,16.1029399 2,14.9941413 L2,5.00585866 Z M12,17 L18,21 L18,17 L12,17 Z" id="Chat" sketch:type="MSShapeGroup"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 955 B

View file

@ -6,7 +6,7 @@
<defs></defs> <defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage"> <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="dashboard" sketch:type="MSArtboardGroup" fill="#50E3C2"> <g id="dashboard" sketch:type="MSArtboardGroup" fill="#50E3C2">
<path d="M11.9671579,2 C6.44426901,2 1.9671579,6.47711111 1.9671579,12 C1.9671579,17.5228889 6.44426901,22 11.9671579,22 C17.490269,22 21.9671579,17.5228889 21.9671579,12 C21.9671579,6.47711111 17.490269,2 11.9671579,2 L11.9671579,2 L11.9671579,2 Z M11.9671579,20.1248889 C10.5864912,20.1248889 9.4671579,19.0055556 9.4671579,17.6248889 C9.4671579,17.52 11.9671579,9.18755556 11.9671579,9.18755556 C11.9671579,9.18755556 14.4671579,17.52 14.4671579,17.6248889 C14.4671579,19.0055556 13.3478246,20.1248889 11.9671579,20.1248889 L11.9671579,20.1248889 L11.9671579,20.1248889 Z M18.3391579,15.9544444 C19.0533801,14.8064444 19.4671579,13.452 19.4671579,12 C19.4671579,7.85777778 16.1096023,4.5 11.9671579,4.5 C7.82493568,4.5 4.4671579,7.85777778 4.4671579,12 C4.4671579,13.452 4.88093568,14.8064444 5.59493568,15.9544444 L4.57871346,16.6853333 C3.71804679,15.3302222 3.2171579,13.7242222 3.2171579,12 C3.2171579,7.16755556 7.13471346,3.25 11.9671579,3.25 C16.7998246,3.25 20.7171579,7.16755556 20.7171579,12 C20.7171579,13.7242222 20.2160468,15.3302222 19.3553801,16.6853333 L18.3391579,15.9544444 L18.3391579,15.9544444 Z" sketch:type="MSShapeGroup"></path> <path d="M11.9671579,2 C6.44426901,2 1.9671579,6.47711111 1.9671579,12 C1.9671579,17.5228889 6.44426901,22 11.9671579,22 C17.490269,22 21.9671579,17.5228889 21.9671579,12 C21.9671579,6.47711111 17.490269,2 11.9671579,2 L11.9671579,2 L11.9671579,2 Z M9.82400492,11.1709229 C9.89058924,11.0792774 17.3644383,5.38592124 17.3644383,5.38592124 C17.3644383,5.38592124 14.2592811,14.2533179 14.1926968,14.3449633 C13.3162384,15.5513048 11.6276721,15.8187474 10.4213306,14.942289 C9.21498916,14.0658307 8.94754654,12.3772644 9.82400492,11.1709229 Z M19.4671579,12 C19.4671579,7.85777778 16.1096023,4.5 11.9671579,4.5 C7.82493568,4.5 4.4671579,7.85777778 4.4671579,12 C4.4671579,13.452 4.88093568,14.8064444 5.59493568,15.9544444 L4.57871346,16.6853333 C3.71804679,15.3302222 3.2171579,13.7242222 3.2171579,12 C3.2171579,7.16755556 7.13471346,3.25 11.9671579,3.25 C16.7998246,3.25 20.7171579,7.16755556 20.7171579,12 C20.7171579,13.7242222 20.2160468,15.3302222 19.3553801,16.6853333 L18.3391579,15.9544444 C19.0533801,14.8064444 19.4671579,13.452 19.4671579,12 Z" sketch:type="MSShapeGroup"></path>
</g> </g>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.3.3 (12072) - http://www.bohemiancoding.com/sketch -->
<title>priority</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="priority" sketch:type="MSArtboardGroup" fill="#50E3C2">
<path d="M8.00000001,13.5 C11.0375661,13.5 13.5,11.0375661 13.5,8.00000001 C13.5,4.96243388 11.0375661,2.50000001 8.00000001,2.50000001 C4.96243388,2.50000001 2.50000001,4.96243388 2.50000001,8.00000001 C2.50000001,11.0375661 4.96243388,13.5 8.00000001,13.5 Z M8.00000001,11.0833333 C9.70287799,11.0833333 11.0833333,9.70287799 11.0833333,8.00000001 C11.0833333,6.29712203 9.70287799,4.91666667 8.00000001,4.91666667 C6.29712203,4.91666667 4.91666667,6.29712203 4.91666667,8.00000001 C4.91666667,9.70287799 6.29712203,11.0833333 8.00000001,11.0833333 Z" id="Oval-2" sketch:type="MSShapeGroup"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"> <svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.3.3 (12072) - http://www.bohemiancoding.com/sketch --> <!-- Generator: Sketch 3.3.3 (12072) - http://www.bohemiancoding.com/sketch -->
<title>priority-modified-inner-circle</title> <title>status-modified-inner-circle</title>
<desc>Created with Sketch.</desc> <desc>Created with Sketch.</desc>
<defs></defs> <defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage"> <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="priority-modified-inner-circle" sketch:type="MSArtboardGroup" fill="#50E3C2"> <g id="status-modified-inner-circle" sketch:type="MSArtboardGroup" fill="#50E3C2">
<circle id="Oval-2" sketch:type="MSShapeGroup" cx="8" cy="8" r="3"></circle> <circle id="Oval-2" sketch:type="MSShapeGroup" cx="8" cy="8" r="3"></circle>
</g> </g>
</g> </g>

Before

Width:  |  Height:  |  Size: 759 B

After

Width:  |  Height:  |  Size: 755 B

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"> <svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.3.3 (12072) - http://www.bohemiancoding.com/sketch --> <!-- Generator: Sketch 3.3.3 (12072) - http://www.bohemiancoding.com/sketch -->
<title>priority-modified-outer-circle</title> <title>status-modified-outer-circle</title>
<desc>Created with Sketch.</desc> <desc>Created with Sketch.</desc>
<defs></defs> <defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage"> <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="priority-modified-outer-circle" sketch:type="MSArtboardGroup" fill="#50E3C2"> <g id="status-modified-outer-circle" sketch:type="MSArtboardGroup" fill="#50E3C2">
<path d="M8,14 C11.3137085,14 14,11.3137085 14,8 C14,4.6862915 11.3137085,2 8,2 C4.6862915,2 2,4.6862915 2,8 C2,11.3137085 4.6862915,14 8,14 Z M8,13 C10.7614237,13 13,10.7614237 13,8 C13,5.23857625 10.7614237,3 8,3 C5.23857625,3 3,5.23857625 3,8 C3,10.7614237 5.23857625,13 8,13 Z" id="Oval-2" sketch:type="MSShapeGroup"></path> <path d="M8,14 C11.3137085,14 14,11.3137085 14,8 C14,4.6862915 11.3137085,2 8,2 C4.6862915,2 2,4.6862915 2,8 C2,11.3137085 4.6862915,14 8,14 Z M8,13 C10.7614237,13 13,10.7614237 13,8 C13,5.23857625 10.7614237,3 8,3 C5.23857625,3 3,5.23857625 3,8 C3,10.7614237 5.23857625,13 8,13 Z" id="Oval-2" sketch:type="MSShapeGroup"></path>
</g> </g>
</g> </g>

Before

Width:  |  Height:  |  Size: 1,011 B

After

Width:  |  Height:  |  Size: 1,007 B

View file

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.3.3 (12072) - http://www.bohemiancoding.com/sketch -->
<title>task-state-modified-inner-circle</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="task-state-modified-inner-circle" sketch:type="MSArtboardGroup" fill="#50E3C2">
<circle id="Oval-2" sketch:type="MSShapeGroup" cx="8" cy="8" r="3"></circle>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 763 B

View file

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.3.3 (12072) - http://www.bohemiancoding.com/sketch -->
<title>task-state-modified-outer-circle</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="task-state-modified-outer-circle" sketch:type="MSArtboardGroup" fill="#50E3C2">
<path d="M8,14 C11.3137085,14 14,11.3137085 14,8 C14,4.6862915 11.3137085,2 8,2 C4.6862915,2 2,4.6862915 2,8 C2,11.3137085 4.6862915,14 8,14 Z M8,13 C10.7614237,13 13,10.7614237 13,8 C13,5.23857625 10.7614237,3 8,3 C5.23857625,3 3,5.23857625 3,8 C3,10.7614237 5.23857625,13 8,13 Z" id="Oval-2" sketch:type="MSShapeGroup"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1,015 B

Binary file not shown.

Binary file not shown.