Admin Chat Preview: fix for widescreen & add animation
Turns out that the chat preview was broken on big screens. The website screenshot didn’t span the whole width and the chat was getting cut off. Fixes: - preserve 16:10 browser aspect ratio - rename zoom to 1:1 - hide 1:1 mode on big screens that don’t need it - scale the website screenshot to the full width - scale the website screenshot in 1:1 mode with the chat - make color picker work with changes - use dynamic height in the form preview
This commit is contained in:
parent
577bb5f723
commit
5239c83e71
4 changed files with 143 additions and 99 deletions
|
@ -5,7 +5,7 @@ class App.ChannelChat extends App.ControllerSubContent
|
||||||
'change .js-params': 'updateParams'
|
'change .js-params': 'updateParams'
|
||||||
'input .js-params': 'updateParams'
|
'input .js-params': 'updateParams'
|
||||||
'submit .js-demo-head': 'onUrlSubmit'
|
'submit .js-demo-head': 'onUrlSubmit'
|
||||||
'click .js-selectBrowserWidth': 'selectBrowserWidth'
|
'click .js-selectBrowserSize': 'selectBrowserSize'
|
||||||
'click .js-swatch': 'usePaletteColor'
|
'click .js-swatch': 'usePaletteColor'
|
||||||
'click .js-toggle-chat': 'toggleChat'
|
'click .js-toggle-chat': 'toggleChat'
|
||||||
'change .js-chatSetting input': 'toggleChatSetting'
|
'change .js-chatSetting input': 'toggleChatSetting'
|
||||||
|
@ -104,8 +104,7 @@ class App.ChannelChat extends App.ControllerSubContent
|
||||||
]
|
]
|
||||||
|
|
||||||
isOpen: true
|
isOpen: true
|
||||||
browserWidth: 1280
|
browserSize: 'desktop'
|
||||||
browserWidthMax: 1280
|
|
||||||
previewUrl: ''
|
previewUrl: ''
|
||||||
previewScale: 1
|
previewScale: 1
|
||||||
|
|
||||||
|
@ -167,45 +166,33 @@ class App.ChannelChat extends App.ControllerSubContent
|
||||||
$(window).off 'resize.chat-designer'
|
$(window).off 'resize.chat-designer'
|
||||||
@website.off('click.eyedropper')
|
@website.off('click.eyedropper')
|
||||||
|
|
||||||
selectBrowserWidth: (event) =>
|
selectBrowserSize: (event) =>
|
||||||
tab = $(event.target).closest('[data-value]')
|
tab = $(event.target).closest('[data-size]')
|
||||||
|
|
||||||
# select tab
|
# select tab
|
||||||
tab.addClass('is-selected').siblings().removeClass('is-selected')
|
tab.addClass('is-selected').siblings().removeClass('is-selected')
|
||||||
@browserWidth = tab.attr('data-value')
|
@browserSize = tab.attr('data-size')
|
||||||
@updatePreview()
|
@updatePreview()
|
||||||
|
|
||||||
updatePreview: (animate = true) =>
|
updatePreview: (animate = true) =>
|
||||||
width = parseInt @browserWidth, 10
|
|
||||||
|
|
||||||
# reset zoom
|
# reset zoom
|
||||||
@chat
|
@chat
|
||||||
.removeClass('is-fullscreen')
|
.removeClass('is-fullscreen')
|
||||||
.toggleClass('no-transition', !animate)
|
.toggleClass('no-transition', !animate)
|
||||||
.css 'transform', "translateY(#{ @getChatOffset() }px)"
|
.css 'transform', "translateY(#{ @getChatOffset() }px)"
|
||||||
@browser.css('width', '')
|
@browser.attr('data-size', @browserSize)
|
||||||
@website.css
|
|
||||||
transform: ''
|
|
||||||
width: ''
|
|
||||||
height: ''
|
|
||||||
@previewScale = 1
|
@previewScale = 1
|
||||||
|
|
||||||
return if @browserWidth is 'fit'
|
switch @browserSize
|
||||||
|
when 'mobile'
|
||||||
if width < @el.width() && width == 375
|
|
||||||
@chat.addClass('is-fullscreen').css 'transform', "translateY(#{ @getChatOffset(true) }px)"
|
@chat.addClass('is-fullscreen').css 'transform', "translateY(#{ @getChatOffset(true) }px)"
|
||||||
@browser.css('width', "#{ width }px")
|
when '1:1'
|
||||||
else
|
@previewScale = Math.max(1, 1280/@el.width())
|
||||||
if @el.width() > width && width == @browserWidthMax
|
@website.css 'transform', "scale(#{ @previewScale })"
|
||||||
@previewScale = 1
|
when 'desktop'
|
||||||
else
|
scale = Math.min(1, @el.width()/1280) # don't use it for the previewScale (used for the color picker)
|
||||||
@previewScale = @el.width()/width
|
@website.css 'transform', ''
|
||||||
|
@chat.css 'transform', "translateY(#{ @getChatOffset() * scale }px) scale(#{ scale })"
|
||||||
@chat.css 'transform', "translateY(#{ @getChatOffset() * @previewScale }px) scale(#{ @previewScale })"
|
|
||||||
@website.css
|
|
||||||
transform: "scale(#{ @previewScale })"
|
|
||||||
width: @el.width() / @previewScale
|
|
||||||
height: @browserBody.height() / @previewScale
|
|
||||||
|
|
||||||
getChatOffset: (fullscreen) ->
|
getChatOffset: (fullscreen) ->
|
||||||
return 0 if @isOpen
|
return 0 if @isOpen
|
||||||
|
@ -296,8 +283,11 @@ class App.ChannelChat extends App.ControllerSubContent
|
||||||
@eyedropper.addClass('is-active')
|
@eyedropper.addClass('is-active')
|
||||||
|
|
||||||
onColorPicked: (event) =>
|
onColorPicked: (event) =>
|
||||||
x = event.pageX - @website.offset().left
|
website_x = @website.position().left
|
||||||
y = event.pageY - @website.offset().top
|
website_y = @website.position().top
|
||||||
|
|
||||||
|
relative_x = event.pageX - @browserBody.offset().left
|
||||||
|
relative_y = event.pageY - @browserBody.offset().top
|
||||||
|
|
||||||
image = new Image()
|
image = new Image()
|
||||||
image.src = @_screenshotSource
|
image.src = @_screenshotSource
|
||||||
|
@ -305,11 +295,11 @@ class App.ChannelChat extends App.ControllerSubContent
|
||||||
canvas = document.createElement('canvas')
|
canvas = document.createElement('canvas')
|
||||||
ctx = canvas.getContext('2d')
|
ctx = canvas.getContext('2d')
|
||||||
|
|
||||||
canvas.width = image.width
|
canvas.width = @browserBody.width()
|
||||||
canvas.height = image.height
|
canvas.height = @browserBody.height()
|
||||||
|
|
||||||
ctx.drawImage(image, 0, 0, @previewScale * canvas.width, @previewScale * canvas.height)
|
ctx.drawImage(image, website_x, website_y, @website.width() * @previewScale, @website.width() * @previewScale)
|
||||||
pixels = ctx.getImageData(x, y, 1, 1).data
|
pixels = ctx.getImageData(relative_x, relative_y, 1, 1).data
|
||||||
|
|
||||||
@colorField.val("rgb(#{pixels.slice(0,3).join(',')})").trigger('change')
|
@colorField.val("rgb(#{pixels.slice(0,3).join(',')})").trigger('change')
|
||||||
|
|
||||||
|
|
|
@ -19,16 +19,17 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="formGroup-label"><%- @T('Preview Width') %></label>
|
<label class="formGroup-label"><%- @T('Preview Width') %></label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<div class="select-tabs js-selectBrowserWidth">
|
<div class="select-tabs js-selectBrowserSize">
|
||||||
<div class="tab" data-value="375">iPhone 6</div>
|
<div class="tab" data-size="mobile">Mobile</div>
|
||||||
<div class="tab" data-value="fit">1:1</div>
|
<div class="tab" data-size="1:1">1:1</div>
|
||||||
<div class="tab is-selected" data-value="1280">MacBook</div>
|
<div class="tab is-selected" data-size="desktop">Desktop</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label for="preview-iframe" class="formGroup-label"><%- @T('Preview') %></label>
|
<label for="preview-iframe" class="formGroup-label"><%- @T('Preview') %></label>
|
||||||
<div class="browser chat-demo js-browser">
|
<div class="browser chat-demo js-browser" data-size="desktop">
|
||||||
|
<div class="browser-ratio">
|
||||||
<form class="browser-head js-demo-head" novalidate>
|
<form class="browser-head js-demo-head" novalidate>
|
||||||
<div class="browser-input">
|
<div class="browser-input">
|
||||||
<input type="url" class="js-testurl-input" id="preview-iframe" value="<%= @previewUrl %>" placeholder="www.zammad.org">
|
<input type="url" class="js-testurl-input" id="preview-iframe" value="<%= @previewUrl %>" placeholder="www.zammad.org">
|
||||||
|
@ -38,7 +39,7 @@
|
||||||
</form>
|
</form>
|
||||||
<div class="browser-body js-browserBody">
|
<div class="browser-body js-browserBody">
|
||||||
<div class="browser-website js-website">
|
<div class="browser-website js-website">
|
||||||
<img class="js-screenshot">
|
<img class="browser-website-background js-screenshot">
|
||||||
</div>
|
</div>
|
||||||
<style>@import "/assets/chat/chat.css";</style>
|
<style>@import "/assets/chat/chat.css";</style>
|
||||||
<div class="chat-demo-animationHolder">
|
<div class="chat-demo-animationHolder">
|
||||||
|
@ -79,6 +80,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<form class="js-params">
|
<form class="js-params">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
|
|
|
@ -117,7 +117,8 @@
|
||||||
|
|
||||||
<label class="formGroup-label"><%- @T('Preview') %></label>
|
<label class="formGroup-label"><%- @T('Preview') %></label>
|
||||||
|
|
||||||
<div class="browser form-demo js-browser">
|
<div class="browser js-browser">
|
||||||
|
<div class="browser-ratio">
|
||||||
<div class="browser-body js-browserBody">
|
<div class="browser-body js-browserBody">
|
||||||
<div class="browser-website centered vertical fit">
|
<div class="browser-website centered vertical fit">
|
||||||
<div class="btn js-formBtn"><%- @T('Feedback') %></div>
|
<div class="btn js-formBtn"><%- @T('Feedback') %></div>
|
||||||
|
@ -126,6 +127,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<h3><%- @T('Requirements') %></h3>
|
<h3><%- @T('Requirements') %></h3>
|
||||||
<p><%- @T("Zammad Forms requires jQuery. If you don't already use it on your website include it like this:") %></p>
|
<p><%- @T("Zammad Forms requires jQuery. If you don't already use it on your website include it like this:") %></p>
|
||||||
<pre><code class="language-html js-code"><script src="https://code.jquery.com/jquery-2.1.4.min.js"></script></code></pre>
|
<pre><code class="language-html js-code"><script src="https://code.jquery.com/jquery-2.1.4.min.js"></script></code></pre>
|
||||||
|
|
|
@ -10040,32 +10040,82 @@ output {
|
||||||
|
|
||||||
.browser {
|
.browser {
|
||||||
margin: 0 0 20px;
|
margin: 0 0 20px;
|
||||||
border: 1px solid hsl(0,0%,90%);
|
|
||||||
border-radius: 5px;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: 500ms;
|
|
||||||
|
&[data-size] {
|
||||||
|
padding-bottom: 65%; // 16:10 aspect ratio;
|
||||||
|
|
||||||
|
.browser-ratio {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
transition: 500ms;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.browser-body {
|
.browser-body {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-size="mobile"] .browser-ratio {
|
||||||
|
width: 375px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-ratio {
|
||||||
|
border: 1px solid hsl(0,0%,90%);
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: #{1280 + $sidebarWidth + $navigationWidth}) {
|
||||||
|
// hide 1:1 button when it gets inrelevant
|
||||||
|
[data-size="1:1"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.browser[data-size="mobile"] .browser-ratio {
|
||||||
|
width: 500px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.browser-body {
|
||||||
|
flex: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 450px;
|
padding: 20px;
|
||||||
|
|
||||||
|
&-inner {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.browser-website {
|
.browser-website {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
transform-origin: left top;
|
transform-origin: right bottom;
|
||||||
|
transition: 500ms;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
&.is-picking {
|
&.is-picking {
|
||||||
cursor: image_url("/assets/images/eyedropper.gif") 0 15, auto;
|
cursor: image_url("/assets/images/eyedropper.gif") 0 15, auto;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
&-background {
|
||||||
vertical-align: bottom;
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
object-position: left top;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue