get started v1.1

This commit is contained in:
Felix Niklas 2015-06-08 11:16:08 +02:00
parent 9da504152a
commit 60e4308f5c
5 changed files with 255 additions and 129 deletions

View file

@ -938,21 +938,34 @@ class cluesRef extends App.ControllerContent
clues: [
{
container: '.search'
container: '.user-menu'
headline: 'Persönliches Menü'
text: 'Hier findest du den Logout, den Weg zu deinen Einstellungen und deinen Verlauf.'
actions: [
'click .user .js-action',
'hover .user'
]
}
{
container: '.search-holder'
headline: 'Suche'
text: 'Hier finden sie alles!'
text: 'Um alles zu finden nutze den <kbd>*</kbd>-Platzhalter'
},
{
container: '.user-menu'
headline: 'Erstellen'
text: 'Hier können sie Tickets, Kunden und Organisationen anlegen.'
action: 'click .add .js-action'
text: 'Hier kannst du Tickets, Kunden und Organisationen anlegen.'
actions: [
'click .add .js-action',
'hover .add'
]
}
]
events:
'click .js-next': 'next'
'click .js-previous': 'previous'
'click .js-close': 'close'
constructor: ->
super
@ -965,7 +978,7 @@ class cluesRef extends App.ControllerContent
###
@options.onComplete = ->
@options.onComplete = -> null
@position = 0
@render()
@ -977,6 +990,10 @@ class cluesRef extends App.ControllerContent
event.stopPropagation()
@navigate -1
close: =>
@cleanUp()
@options.onComplete()
navigate: (direction) ->
@cleanUp()
@position += direction
@ -984,7 +1001,7 @@ class cluesRef extends App.ControllerContent
if @position < @clues.length
@render()
else
@onComplete()
@options.onComplete()
cleanUp: ->
clue = @clues[@position]
@ -992,66 +1009,147 @@ class cluesRef extends App.ControllerContent
container.removeClass('selected-clue')
# undo click perform by doing it again
if clue.action
@perform clue.action, container
if clue.actions
@perform clue.actions, container
@el.find('.clue').remove()
@$('.modal').remove()
render: ->
clue = @clues[@position]
container = $(clue.container)
container.addClass('selected-clue')
if clue.actions
@perform clue.actions, container
# calculate bounding box after actions
# to take toggled child nodes into account
boundingBox = @getVisibleBoundingBox(container.get(0))
center =
x: container.offset().left + container.width()/2
y: container.offset().top + container.height()/2
x: boundingBox.left + boundingBox.width/2
y: boundingBox.top + boundingBox.height/2
@html App.view('layout_ref/clues')
headline: clue.headline
text: clue.text
width: container.outerWidth()
height: container.outerHeight()
width: boundingBox.width
height: boundingBox.height
center: center
position: @position
max: @clues.length
if clue.action
@perform clue.action, container
@placeWindow(boundingBox)
@placeWindow(container)
placeWindow: (target) ->
modalElement = @$('.js-positionOrigin')
modal = modalElement.get(0).getBoundingClientRect()
position = ''
left = 0
top = 0
maxWidth = $(window).width()
maxHeight = $(window).height()
placeWindow: (container) ->
clueWindow = @el.find('.clue-window')
# see if we can place it above or below target
if clueWindow.outerHeight() + container.outerHeight() < $(window).outerHeight()
clueWindow.css('left', container.offset().left)
# below or above ?
if container.offset().top + container.outerHeight() + clueWindow.outerHeight() < $(window).outerHeight()
# place below
clueWindow.css('top', container.offset().top + container.outerHeight())
else
# place above
clueWindow.css('top', container.offset().top - container.outerHeight() - clueWindow.outerHeight())
else
clueWindow.css('top', container.offset().top)
# okay, let's try right or left then
if container.offset().left + container.outerWidth() + clueWindow.outerWidth() < $(window).outerWidth()
# place right
clueWindow.css('left', container.offset().left + container.outerWidth())
# try to place it parallel to the larger side
if target.height > target.width
# try to place it aside
# prefer right
if target.right + modal.width <= maxWidth
left = target.right
position = 'right'
else
# place left
clueWindow.css('left', container.offset().left - container.outerWidth() - clueWindow.outerWidth())
left = target.left - modal.width
position = 'left'
if position
top = target.top + target.height/2 - modal.height/2
else if target.height <= target.width or !position
# try to place it above or below
# prefer above
if target.top - modal.height >= 0
top = target.top - modal.height
position = 'above'
else
top = target.bottom
position = 'below'
if position
left = target.left + target.width/2 - modal.width/2
# keep it inside the window
# horizontal
if left < 0
moveArrow = modal.width/2 + left
left = 0
else if left + modal.width > maxWidth
moveArrow = modal.width/2 + maxWidth - (left + modal.width)
left = maxWidth - modal.width
if top < 0
moveArrow = modal.height/2 + height
top = 0
else if top + modal.height > maxHeight
moveArrow = modal.height/2 + maxHeight - (top + modal.height)
top = maxHeight - modal.height
# show window
clueWindow.addClass('is-visible')
modalElement
.addClass "is-visible is-#{ position }"
.css
'left': left
'top': top
if moveArrow
parameter = if position is 'above' or position is 'below' then 'left' else 'top'
console.log("move arrow", position, parameter, moveArrow)
modalElement.find('.js-arrow').css(parameter, moveArrow)
perform: (action, container) ->
getVisibleBoundingBox: (el) ->
###
getBoundingClientRect doesn't take
absolute-positioned child nodes into account
###
children = el.querySelectorAll('*')
bb = el.getBoundingClientRect()
dimensions =
left: bb.left,
right: bb.right,
top: bb.top,
bottom: bb.bottom
for child in children
continue if getComputedStyle(child).position is not 'absolute'
bb = child.getBoundingClientRect()
continue if bb.width is 0 or bb.height is 0
if bb.left < dimensions.left
dimensions.left = bb.left
if bb.top < dimensions.top
dimensions.top = bb.top
if bb.right > dimensions.right
dimensions.right = bb.right
if bb.bottom > dimensions.bottom
dimensions.bottom = bb.bottom
dimensions.width = dimensions.right - dimensions.left
dimensions.height = dimensions.bottom - dimensions.top
dimensions
perform: (actions, container) ->
for action in actions
eventName = action.substr 0, action.indexOf(' ')
selector = action.substr action.indexOf(' ') + 1
container.find(selector)[0][eventName]()
switch eventName
when 'click' then container.find(selector).trigger('click')
when 'hover' then container.find(selector).toggleClass('is-hovered')
App.Config.set( 'layout_ref/clues', cluesRef, 'Routes' )

View file

@ -1,22 +1,26 @@
<div class="clue">
<div class="clue-backdrop" style="background:
<div class="modal modal--clue">
<div class="modal-backdrop" style="background:
radial-gradient(
ellipse <%= @width + 400 %>px <%= @height + 400 %>px
at <%= @center.x %>px <%= @center.y %>px,
hsla(202,68%,54%,.4),
hsla(202,68%,54%,.8)
hsla(202,68%,54%,.9)
)
"></div>
<div class="clue-window">
<div class="clue-inner">
<div class="clue-header"><%= @headline %></div>
<div class="clue-body"><%= @text %></div>
<div class="clue-controls">
<div class="clue-control">
<div class="modal-spacer js-positionOrigin">
<div class="modal-content">
<div class="modal-arrow js-arrow"></div>
<div class="modal-close js-close">
<svg class="icon-diagonal-cross"><use xlink:href="#icon-diagonal-cross" /></svg>
</div>
<div class="modal-header"><%= @headline %></div>
<div class="modal-body"><%- @text %></div>
<div class="modal-controls">
<div class="modal-control">
<div class="<% if @position is 0: %>is-disabled <% end %>btn btn--text js-previous"><%- @T( 'Previous' ) %></div>
</div>
<div class="clue-control clue-count"><%= @position+1 %>/<%= @max %></div>
<div class="clue-control">
<div class="modal-control clue-count"><%= @position+1 %>/<%= @max %></div>
<div class="modal-control">
<% if @position+1 is @max: %>
<div class="btn btn--text js-next"><%- @T( 'Finish' ) %></div>
<% else: %>

View file

@ -718,15 +718,6 @@ code {
background-color: #f9f2f4;
border-radius: 4px;
}
kbd {
padding: 2px 4px;
font-size: 90%;
color: #fff;
background-color: #333;
border-radius: 3px;
-webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
}
kbd kbd {
padding: 0;
font-size: 100%;

View file

@ -19,6 +19,7 @@ body {
background: hsl(210,17%,98%);
height: 100%;
color: hsl(198,19%,72%);
word-break: break-all;
}
p {
@ -910,53 +911,71 @@ textarea,
@extend .zIndex-9;
}
.clue {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
.modal--clue {
display: flex;
align-items: center;
justify-content: center;
@extend .zIndex-8;
}
.clue-backdrop {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
.modal-backdrop {
bottom: 0;
}
.clue-window {
.modal-spacer {
position: absolute;
opacity: 1;
opacity: 0;
padding: 18px;
&.is-visible {
opacity: 1;
}
}
}
.clue-inner {
min-width: 260px;
padding: 24px 24px 14px;
background: white;
color: hsl(60,1%,34%);
.modal-arrow {
background: inherit;
width: 20px;
height: 20px;
position: absolute;
margin: -10px 0 53px -10px;
left: 0;
top: 50%;
transform: rotate(45deg);
}
.modal-spacer.is-above .modal-arrow {
left: 50%;
top: 100%;
background: hsl(210,5%,97%);
}
.modal-spacer.is-below .modal-arrow {
left: 50%;
top: 0;
}
.modal-spacer.is-left .modal-arrow {
left: 100%;
top: 50%;
}
.modal-content {
border: none;
width: 300px;
box-shadow:
0 8px 17px 0 rgba(0, 0, 0, 0.1),
0 6px 20px 0 rgba(0, 0, 0, 0.05);
}
}
.clue-controls {
.modal-controls {
background: hsl(210,5%,97%);
margin: 24px -24px -14px;
margin: 23px 0 0;
padding: 7px 10px;
display: flex;
align-items: center;
justify-content: space-between;
}
}
.clue-control {
.modal-control {
padding-left: 14px;
padding-right: 14px;
@ -964,15 +983,28 @@ textarea,
opacity: 1;
color: hsl(240,5%,83%);
}
}
}
.clue-header {
margin-bottom: 7px;
.modal-header {
padding-bottom: 7px;
font-size: 18px;
}
.modal-body {
max-width: 340px;
}
}
.clue-body {
max-width: 340px;
kbd {
background: hsl(200,8%,21%);
border-radius: 3px;
box-shadow: 0 1px 1px black;
color: white;
display: inline-block;
font-size: 12px;
margin: 0 1px;
padding: 0 4px;
vertical-align: top;
}
.form-stacked .checkbox label {
@ -1828,7 +1860,7 @@ footer {
}
.search {
padding: 7px 5px 4px 10px;
padding: 11px 5px 4px 10px;
border-bottom: 1px solid rgba(240, 250, 255, .05);
flex-shrink: 0;
display: flex;
@ -1837,8 +1869,7 @@ footer {
.search-holder {
flex: 1;
margin-right: 2px;
margin-top: 4px;
border-radius: 15px;
position: relative;
transition: 240ms;
}
@ -1900,7 +1931,7 @@ footer {
.search .logo {
position: relative;
@extend .u-clickable, .zIndex-5;
margin: 0 10px;
margin: -4px 10px 0 12px;
transition: 240ms;
}
@ -1983,7 +2014,8 @@ footer {
position: relative;
}
.user-menu > li:hover .list-button:before {
.user-menu > li:hover .list-button:before,
.user-menu > li.is-hovered .list-button:before {
content: '';
position: absolute;
top: 4px;
@ -1993,7 +2025,8 @@ footer {
background: white;
}
.user-menu li.add:hover .list-button:before {
.user-menu li.add:hover .list-button:before,
.user-menu li.add.is-hovered .list-button:before {
background: #38ae6a;
}
@ -2013,6 +2046,7 @@ footer {
}
.user-menu > li.add:hover .user-menu-icon.icon-plus,
.user-menu > li.add.is-hovered .user-menu-icon.icon-plus,
.user-menu > li.add.active .user-menu-icon.icon-plus {
fill: white;
}
@ -3425,7 +3459,6 @@ footer {
.attachment-name {
margin-right: 5px;
word-break: break-all;
@extend .u-highlight;
}
@ -4052,7 +4085,7 @@ footer {
border-radius: 0;
border: 1px solid hsl(0,0%,90%);
box-shadow: none;
color: hsl(206,7%,28%);
color: hsl(60,1%,34%);
word-wrap: break-word;
}
@ -4079,6 +4112,7 @@ footer {
.modal-body {
padding: 0 23px;
word-break: normal;
}
.modal-footer {
@ -4975,7 +5009,6 @@ label + .wizard-buttonList {
}
.name {
word-break: break-all;
@extend .u-highlight;
}
}

Binary file not shown.