Browse Source

add unique avatar support

Felix Niklas 10 years ago
parent
commit
db4df87be1

BIN
app/assets/images/avatar-bg.png


+ 18 - 0
app/assets/javascripts/app/controllers/layout_ref.js.coffee

@@ -14,6 +14,24 @@ class Content extends App.ControllerContent
     super
     @render()
 
+    for avatar in @$('.user.avatar')
+      avatar = $(avatar)
+      size = if avatar.hasClass('big') then 50 else 40
+      @createUniqueAvatar avatar, size, avatar.data('firstname'), avatar.data('lastname'), avatar.data('userid')
+
+  createUniqueAvatar: (holder, size, firstname, lastname, id) ->
+    width = 300
+    height = 226
+
+    holder.addClass 'unique'
+
+    rng = new Math.seedrandom(id);
+    x = rng() * (width - size)
+    y = rng() * (height - size)
+    holder.css('background-position', "-#{ x }px -#{ y }px")
+
+    holder.text(firstname[0] + lastname[0])
+
   render: ->
     @html App.view('layout_ref/content')()
 

+ 1 - 0
app/assets/javascripts/app/lib/base/seedrandom.min.js

@@ -0,0 +1 @@
+!function(a,b,c,d,e,f,g,h,i){function j(a){var b,c=a.length,e=this,f=0,g=e.i=e.j=0,h=e.S=[];for(c||(a=[c++]);d>f;)h[f]=f++;for(f=0;d>f;f++)h[f]=h[g=r&g+a[f%c]+(b=h[f])],h[g]=b;(e.g=function(a){for(var b,c=0,f=e.i,g=e.j,h=e.S;a--;)b=h[f=r&f+1],c=c*d+h[r&(h[f]=h[g=r&g+b])+(h[g]=b)];return e.i=f,e.j=g,c})(d)}function k(a,b){var c,d=[],e=typeof a;if(b&&"object"==e)for(c in a)try{d.push(k(a[c],b-1))}catch(f){}return d.length?d:"string"==e?a:a+"\0"}function l(a,b){for(var c,d=a+"",e=0;e<d.length;)b[r&e]=r&(c^=19*b[r&e])+d.charCodeAt(e++);return n(b)}function m(c){try{return a.crypto.getRandomValues(c=new Uint8Array(d)),n(c)}catch(e){return[+new Date,a,(c=a.navigator)&&c.plugins,a.screen,n(b)]}}function n(a){return String.fromCharCode.apply(0,a)}var o=c.pow(d,e),p=c.pow(2,f),q=2*p,r=d-1,s=c["seed"+i]=function(a,f,g){var h=[];f=1==f?{entropy:!0}:f||{};var r=l(k(f.entropy?[a,n(b)]:null==a?m():a,3),h),s=new j(h);return l(n(s.S),b),(f.pass||g||function(a,b,d){return d?(c[i]=a,b):a})(function(){for(var a=s.g(e),b=o,c=0;p>a;)a=(a+c)*d,b*=d,c=s.g(1);for(;a>=q;)a/=2,b/=2,c>>>=1;return(a+c)/b},r,"global"in f?f.global:this==c)};l(c[i](),b),g&&g.exports?g.exports=s:h&&h.amd&&h(function(){return s})}(this,[],Math,256,6,52,"object"==typeof module&&module,"function"==typeof define&&define,"random");

+ 28 - 0
app/assets/javascripts/app/views/layout_ref/content.jst.eco

@@ -14,6 +14,34 @@
 
   <hr>
 
+  <h2>Avatars</h2>
+
+  <p>
+    Users and customers might not have a profile images because:
+  </p>
+  <ol>
+    <li>They didn't upload one
+    <li>They didn't login using a authentication provider like facebook, twitter or google where we get an avatar
+    <li>They have no avatar associated with their email address (gravatar)
+  </ol>
+  <p>
+    They will get a random avatar consisting of a blured version of the Zammad logo and their initials.
+  </p>
+  <p>
+    The background is generated by using a <i>random numbers generator</i> (RNG) with the user-id as the <b>seed</b>. The RNG is then used to create the <code>x</code> and <code>y</code> position of the background. Since the user-id is unique and does not change it's guaranteed that the avatar background stays the same and this makes it possible to calculate the avatar on the client without having to store the coordinates on the server side.
+  </p>
+
+  <span class="user avatar" data-firstname="Hans" data-lastname="Huber" data-userid="5"></span>
+  <span class="user avatar" data-firstname="Rafael" data-lastname="Schweizer" data-userid="6"></span>
+  <span class="user avatar" data-firstname="Stefanie" data-lastname="Lingerl" data-userid="7"></span>
+  <span class="user avatar" data-firstname="Igor" data-lastname="Kaufer" data-userid="8"></span>
+  <span class="user avatar" data-firstname="Ina" data-lastname="Lingerl" data-userid="12"></span>
+  <span class="big user avatar" data-firstname="Andreas" data-lastname="Berger" data-userid="9"></span>
+  <span class="big user avatar" data-firstname="Luisa" data-lastname="Hofner" data-userid="10"></span>
+  <span class="big user avatar" data-firstname="Clara" data-lastname="Altman" data-userid="11"></span>
+
+  <hr>
+
   <h2>Headlines</h2>
   <h1>h1. Bootstrap heading</h1>
   <h2>h2. Bootstrap heading</h2>

+ 80 - 58
app/assets/stylesheets/zzz.css.erb

@@ -7,8 +7,6 @@ body {
 
 ol,
 ul {
-  list-style: none;
-  padding: 0;
 }
 
 a.create {
@@ -595,6 +593,7 @@ ol.tabs li {
 }
 
 .tabs {
+  padding: 0;
   margin-bottom: 20px;
   color: #b8b8b8;
   border: 1px solid rgba(0,8,14,.08);
@@ -1864,6 +1863,23 @@ footer {
     height: 50px;
   }
 
+  .unique.avatar {
+    background-image: url(<%= asset_path "avatar-bg.png" %>);
+    background-size: auto;
+    color: white;
+    line-height: 42px;
+    text-align: center;
+    font-size: 13px;
+    letter-spacing: 1px;
+    text-transform: uppercase;
+    text-shadow: 0 1px rgba(0,0,0,.2);
+  }
+
+  .unique.big.avatar {
+    font-size: 16px;
+    line-height: 52px;
+  }
+
 .sidebar {
   width: 32%;
   max-width: 300px;
@@ -3174,76 +3190,82 @@ footer {
       box-shadow: none;
     }
 
-.recipientList-entry .recipientList-iconSpacer {
-  width: 20px;
-  margin-left: -5px;
+.recipientList,
+.recipientList-organisationMembers {
+  list-style: none;
+  padding: 0;
 }
 
-.recipientList-entry .icon:not(.plus) {
-  opacity: 0.2;
-}
+  .recipientList-entry .recipientList-iconSpacer {
+    width: 20px;
+    margin-left: -5px;
+  }
 
-.recipientList-entry:hover .icon {
-  opacity: 1;
-}
+  .recipientList-entry .icon:not(.plus) {
+    opacity: 0.2;
+  }
 
-.recipientList-name {
-  margin-left: 10px;
-  margin-top: 2px;
-}
+  .recipientList-entry:hover .icon {
+    opacity: 1;
+  }
 
-.recipientList-detail {
-  opacity: 0.5;
-}
+  .recipientList-name {
+    margin-left: 10px;
+    margin-top: 2px;
+  }
 
-.recipientList-icon.plus {
-  margin-left: 13px;
-}
+  .recipientList-detail {
+    opacity: 0.5;
+  }
 
-.recipientList-new {
-  background: hsl(145,51%,45%);
-}
+  .recipientList-icon.plus {
+    margin-left: 13px;
+  }
 
-.dropdown .recipientList-new:hover {
-  background: hsl(147,52%,43%);
-}
+  .recipientList-new {
+    background: hsl(145,51%,45%);
+  }
 
-li.recipientList-controls,
-li.recipientList-controls:hover {
-  padding: 0;
-  background: hsl(206,7%,28%);
-}
+  .dropdown .recipientList-new:hover {
+    background: hsl(147,52%,43%);
+  }
 
-.recipientList-backClickArea {
-  height: 100%;
-  float: left;
-  padding: 0 10px;
-}
+  li.recipientList-controls,
+  li.recipientList-controls:hover {
+    padding: 0;
+    background: hsl(206,7%,28%);
+  }
 
-.recipientList-backButton {
-  padding: 5px 10px;
-  font-size: 12px;
-  color: white;
-  border-radius: 3px;
-  border: 1px solid hsl(234,10%,10%);
-  box-shadow: 0 1px rgba(255,255,255,.03) inset;
-}
+  .recipientList-backClickArea {
+    height: 100%;
+    float: left;
+    padding: 0 10px;
+  }
 
-.recipientList-backClickArea:active .recipientList-backButton {
-  background: hsl(206,7%,25%);
-  box-shadow: 0 1px rgba(0,0,0,.1) inset;
-}
+  .recipientList-backButton {
+    padding: 5px 10px;
+    font-size: 12px;
+    color: white;
+    border-radius: 3px;
+    border: 1px solid hsl(234,10%,10%);
+    box-shadow: 0 1px rgba(255,255,255,.03) inset;
+  }
 
-.recipientList-backButton .icon {
-  margin-bottom: -2px;
-}
+  .recipientList-backClickArea:active .recipientList-backButton {
+    background: hsl(206,7%,25%);
+    box-shadow: 0 1px rgba(0,0,0,.1) inset;
+  }
 
-.recipientList-organisationMembers {
-  position: absolute;
-  top: 0;
-  left: 0;
-  right: 0;
-}
+  .recipientList-backButton .icon {
+    margin-bottom: -2px;
+  }
+
+  .recipientList-organisationMembers {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+  }
 
 /*