get started v1.1
This commit is contained in:
parent
9da504152a
commit
60e4308f5c
5 changed files with 255 additions and 129 deletions
|
@ -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) ->
|
||||
eventName = action.substr 0, action.indexOf(' ')
|
||||
selector = action.substr action.indexOf(' ') + 1
|
||||
container.find(selector)[0][eventName]()
|
||||
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
|
||||
|
||||
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' )
|
||||
|
||||
|
|
|
@ -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: %>
|
||||
|
|
9
app/assets/stylesheets/bootstrap.css
vendored
9
app/assets/stylesheets/bootstrap.css
vendored
|
@ -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%;
|
||||
|
|
|
@ -19,6 +19,7 @@ body {
|
|||
background: hsl(210,17%,98%);
|
||||
height: 100%;
|
||||
color: hsl(198,19%,72%);
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
p {
|
||||
|
@ -910,69 +911,100 @@ textarea,
|
|||
@extend .zIndex-9;
|
||||
}
|
||||
|
||||
.clue {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@extend .zIndex-8;
|
||||
}
|
||||
|
||||
.clue-backdrop {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.clue-window {
|
||||
position: absolute;
|
||||
opacity: 1;
|
||||
padding: 18px;
|
||||
|
||||
&.is-visible {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.clue-inner {
|
||||
min-width: 260px;
|
||||
padding: 24px 24px 14px;
|
||||
background: white;
|
||||
color: hsl(60,1%,34%);
|
||||
box-shadow:
|
||||
0 8px 17px 0 rgba(0, 0, 0, 0.1),
|
||||
0 6px 20px 0 rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.clue-controls {
|
||||
background: hsl(210,5%,97%);
|
||||
margin: 24px -24px -14px;
|
||||
padding: 7px 10px;
|
||||
.modal--clue {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
justify-content: center;
|
||||
@extend .zIndex-8;
|
||||
|
||||
.clue-control {
|
||||
padding-left: 14px;
|
||||
padding-right: 14px;
|
||||
.modal-backdrop {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.btn.is-disabled {
|
||||
opacity: 1;
|
||||
color: hsl(240,5%,83%);
|
||||
.modal-spacer {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
padding: 18px;
|
||||
|
||||
&.is-visible {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
|
||||
.modal-controls {
|
||||
background: hsl(210,5%,97%);
|
||||
margin: 23px 0 0;
|
||||
padding: 7px 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.modal-control {
|
||||
padding-left: 14px;
|
||||
padding-right: 14px;
|
||||
|
||||
.btn.is-disabled {
|
||||
opacity: 1;
|
||||
color: hsl(240,5%,83%);
|
||||
}
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
padding-bottom: 7px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
max-width: 340px;
|
||||
}
|
||||
}
|
||||
|
||||
.clue-header {
|
||||
margin-bottom: 7px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.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.
Loading…
Reference in a new issue