Further design changes

This commit is contained in:
nelsonlaquet 2013-08-22 19:48:40 -05:00
parent 22818261ee
commit 4c025dd1e9
11 changed files with 445 additions and 79 deletions

View file

@ -52,6 +52,7 @@
new FileAsset('scripts/base/moment.js'), new FileAsset('scripts/base/moment.js'),
new FileAsset('scripts/base/soundmanager2-nodebug.js'), new FileAsset('scripts/base/soundmanager2-nodebug.js'),
new FileAsset('scripts/base/angular.js'), new FileAsset('scripts/base/angular.js'),
new FileAsset('scripts/base/bindonce.js'),
new FileAsset('scripts/base/ui-bootstrap-tpls-0.4.0.js'), new FileAsset('scripts/base/ui-bootstrap-tpls-0.4.0.js'),
new FileAsset('scripts/base/angular-ui-sortable.js'), new FileAsset('scripts/base/angular-ui-sortable.js'),
new FileAsset('scripts/base/angular-ui-date.js'), new FileAsset('scripts/base/angular-ui-date.js'),

View file

@ -1,6 +1,6 @@
window.pfm.preloaders = {} window.pfm.preloaders = {}
module = angular.module 'ponyfm', ['ui.bootstrap', 'ui.state', 'ui.date', 'ui.sortable'] module = angular.module 'ponyfm', ['ui.bootstrap', 'ui.state', 'ui.date', 'ui.sortable', 'pasvaz.bindonce']
module.config [ module.config [
'$locationProvider', '$stateProvider', '$dialogProvider' '$locationProvider', '$stateProvider', '$dialogProvider'

View file

@ -5,6 +5,7 @@ angular.module('ponyfm').directive 'pfmFavouriteButton', () ->
resource: '=resource', resource: '=resource',
class: '@class', class: '@class',
type: '@type' type: '@type'
replace: true
controller: [ controller: [
'$scope', 'favourites', 'auth' '$scope', 'favourites', 'auth'

View file

@ -4,6 +4,7 @@ angular.module('ponyfm').directive 'pfmTrackPlayer', () ->
scope: scope:
track: '=track', track: '=track',
class: '@class' class: '@class'
replace: true
controller: [ controller: [
'$scope', 'player' '$scope', 'player'

View file

@ -2,5 +2,6 @@ angular.module('ponyfm').filter 'trust', [
'$sce' '$sce'
($sce) -> ($sce) ->
(input) -> (input) ->
console.log input
$sce.trustAsHtml input $sce.trustAsHtml input
] ]

View file

@ -0,0 +1,193 @@
'use strict';
/**
* Bindonce - Zero watches binding for AngularJs
* @version v0.1.1 - 2013-05-07
* @link https://github.com/Pasvaz/bindonce
* @author Pasquale Vazzana <pasqualevazzana@gmail.com>
* @license MIT License, http://www.opensource.org/licenses/MIT
*/
angular.module('pasvaz.bindonce', [])
.directive('bindonce', function() {
var toBoolean = function(value) {
if (value && value.length !== 0) {
var v = angular.lowercase("" + value);
value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
} else {
value = false;
}
return value;
}
return {
restrict: "AM",
controller: ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
var showHideBinder = function(elm, attr, value)
{
var show = (attr == 'show') ? '' : 'none';
var hide = (attr == 'hide') ? '' : 'none';
elm.css('display', toBoolean(value) ? show : hide);
}
var classBinder = function(elm, value)
{
if (angular.isObject(value) && !angular.isArray(value)) {
var results = [];
angular.forEach(value, function(value, index) {
if (value) results.push(index);
});
value = results;
}
if (value) {
elm.addClass(angular.isArray(value) ? value.join(' ') : value);
}
}
var ctrl =
{
watcherRemover : undefined,
binders : [],
group : $attrs.boName,
element : $element,
ran : false,
addBinder : function(binder)
{
this.binders.push(binder);
// In case of late binding (when using the directive bo-name/bo-parent)
// it happens only when you use nested bindonce, if the bo-children
// are not dom children the linking can follow another order
if (this.ran)
{
this.runBinders();
}
},
setupWatcher : function(bindonceValue)
{
var that = this;
this.watcherRemover = $scope.$watch(bindonceValue, function(newValue)
{
if (newValue == undefined) return;
that.removeWatcher();
that.runBinders();
}, true);
},
removeWatcher : function()
{
if (this.watcherRemover != undefined)
{
this.watcherRemover();
this.watcherRemover = undefined;
}
},
runBinders : function()
{
for (var data in this.binders)
{
var binder = this.binders[data];
if (this.group && this.group != binder.group ) continue;
var value = $scope.$eval(binder.value);
switch(binder.attr)
{
case 'hide':
case 'show':
showHideBinder(binder.element, binder.attr, value);
break;
case 'class':
classBinder(binder.element, value);
break;
case 'text':
binder.element.text(value);
break;
case 'html':
binder.element.html(value);
break;
case 'src':
case 'href':
case 'alt':
case 'title':
case 'id':
case 'style':
case 'value':
binder.element.attr(binder.attr, value);
break;
}
}
this.ran = true;
this.binders = [];
}
}
return ctrl;
}],
link: function(scope, elm, attrs, bindonceController) {
var value = (attrs.bindonce) ? scope.$eval(attrs.bindonce) : true;
if (value != undefined)
{
bindonceController.runBinders();
}
else
{
bindonceController.setupWatcher(attrs.bindonce);
elm.bind("$destroy", bindonceController.removeWatcher);
}
}
};
});
angular.forEach({
'boShow' : 'show',
'boHide' : 'hide',
'boClass' : 'class',
'boText' : 'text',
'boHtml' : 'html',
'boSrc' : 'src',
'boHref' : 'href',
'boAlt' : 'alt',
'boTitle' : 'title',
'boId' : 'id',
'boStyle' : 'style',
'boValue' : 'value'
},
function(tag, attribute)
{
var childPriority = 200;
return angular.module('pasvaz.bindonce').directive(attribute, function()
{
return {
priority: childPriority,
require: '^bindonce',
link: function(scope, elm, attrs, bindonceController)
{
var name = attrs.boParent;
if (name && bindonceController.group != name)
{
var element = bindonceController.element.parent();
bindonceController = undefined;
var parentValue;
while (element[0].nodeType != 9 && element.length)
{
if ((parentValue = element.data('$bindonceController'))
&& parentValue.group == name)
{
bindonceController = parentValue
break;
}
element = element.parent();
}
if (!bindonceController)
{
throw Error("No bindonce controller: " + name);
}
}
bindonceController.addBinder({element: elm, attr:tag, value: attrs[attribute], group: name});
}
}
});
});

View file

@ -13,14 +13,130 @@
line-height: normal; line-height: normal;
overflow: hidden; overflow: hidden;
font-weight: normal; font-weight: normal;
}
}
a { .revealable {
color: #555;
float: right;
font-size: 10pt; font-size: 10pt;
color: #222;
position: relative;
overflow: hidden;
padding: 0px;
margin: 0px;
h2 {
}
.reveal {
#gradient>.vertical(rgba(255,255,255,0), rgba(255,255,255,1));
.box-sizing(border-box);
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
z-index: 400;
border: 2px solid #fff;
cursor: pointer;
&:hover { &:hover {
border: 2px solid @blue;
}
a {
.box-sizing(border-box);
display: block;
position: absolute;
bottom: 0px;
left: 0px;
width: 100%;
background: #eee;
padding: 3px;
z-index: 500;
text-decoration: none; text-decoration: none;
font-size: 10pt;
}
}
}
.details-columns {
.left {
margin-right: 310px;
margin-left: 5px;
}
.right {
float: right;
width: 290px;
height: 100%;
padding-right: 10px;
img.cover {
.img-polaroid();
padding: 2px;
}
.stats {
list-style: none;
padding: 0px;
margin: 0px;
font-size: 9pt;
color: #555;
li {
padding: 5px 0px;
margin: 0px;
border-bottom: 1px solid #ddd;
strong {
color: #111;
}
}
}
}
}
.comments {
form {
margin: 0px;
margin-bottom: 10px;
.form-row {
margin: 0px;
}
input[type=text] {
margin: 0px;
padding: 5px;
}
}
ul {
list-style: none;
margin: 0px;
padding: 0px;
li {
line-height: normal;
padding: 5px 0px;
margin: 0px;
overflow: hidden;
img {
.img-polaroid();
float: left;
padding: 1px;
height: 32px;
width: 32px;
}
.meta {
font-size: 8pt;
padding: 5px 0px;
}
.content {
margin-left: 42px;
} }
} }
} }

View file

@ -11,10 +11,6 @@ html body {
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
} }
header, .site-body {
.box-shadow(0 0 7px rgba(0, 0, 0, .6));
}
header { header {
> a { > a {
display: block; display: block;

View file

@ -2,6 +2,66 @@
@import-once 'mixins'; @import-once 'mixins';
@import-once 'variables'; @import-once 'variables';
.track-details {
> header {
padding: 5px;
background: #eee;
overflow: hidden;
margin-bottom: 10px;
h1 {
margin: 0px;
margin-left: 47px;
}
h2 {
margin: 0px;
margin-left: 47px;
padding: 0px;
font-weight: normal;
clear: none;
line-height: normal;
display: block;
float: none;
font-size: 8pt;
color: #777;
border: none;
a {
display: inline;
float: none;
color: #111;
}
}
}
h2 {
color: #C2889C;
font-size: 10pt;
border-bottom: 2px solid #ddd;
padding: 5px 0px;
margin: 0px;
margin-bottom: 5px;
line-height: normal;
}
.resource-toolbar {
.clearfix();
background: #eee;
list-style: none;
padding: 0px;
margin: 0px;
margin-bottom: 5px;
> li {
padding: 5px;
float: left;
margin: 0px;
}
}
}
@icon-size: 42px; @icon-size: 42px;
.tracks-listing.four-columns { .tracks-listing.four-columns {
@ -25,6 +85,10 @@
} }
} }
html .single-player .play-button {
display: block;
}
.single-player, .tracks-listing li .image { .single-player, .tracks-listing li .image {
float: left; float: left;
width: @icon-size; width: @icon-size;

View file

@ -1,21 +1,22 @@
<div class="comments"> <div class="comments" bindonce>
<div class="alert alert-info" ng-show="resource.comments.count == 0"> <h2>All Comments ({{resource.comments.length}})</h2>
<div class="alert alert-info" ng-show="resource.comments.length == 0">
There are no comments yet! There are no comments yet!
</div> </div>
<ul ng-show="resource.comments.length > 0">
<li ng-repeat="comment in resource.comments">
<div class="meta">
<a href="{{comment.user.url}}">{{comment.user.name}}</a> posted
{{comment.created_at.date | momentFromNow}}
</div>
<img ng-src="{{comment.user.avatars.thumbnail}}" />
<div class="content">{{comment.content}}</div>
</li>
</ul>
<form class="pfm-form" ng-submit="addComment()" ng-show="auth.isLogged"> <form class="pfm-form" ng-submit="addComment()" ng-show="auth.isLogged">
<div class="form-row"> <div class="form-row">
<textarea ng-model="content"></textarea> <input type="text" ng-model="content" placeholder="Write a comment..." />
</div> </div>
<button type="submit" class="btn" ng-class="{disabled: content.length == 0}">Post Comment</button>
</form> </form>
<ul ng-show="resource.comments.length > 0">
<li bindonce ng-repeat="comment in resource.comments">
<img bo-src="comment.user.avatars.thumbnail" />
<div class="content">
<a bo-href="comment.user.url" bo-text="comment.user.name"></a>
<span bo-text="comment.content"></span>
<div class="meta" bo-text="comment.created_at.date | momentFromNow">
</div>
</div>
</li>
</ul>
</div> </div>

View file

@ -1,80 +1,72 @@
<div class="track-details" xmlns="http://www.w3.org/1999/html"> <div class="track-details" bindonce="track">
<div class="track-toolbar btn-group pull-right"> <ul class="dropdowns">
<pfm-favourite-button resource="track" type="track"></pfm-favourite-button> <li class="dropdown">
<div class="dropdown">
<a href="#" class="btn btn-small btn-info dropdown-toggle"> <a href="#" class="btn btn-small btn-info dropdown-toggle">
Downloads <i class="caret"></i> Downloads
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li ng-repeat="format in track.formats"><a target="_blank" href="{{format.url}}">{{format.name}} <small>({{format.size}})</small></a></li> <li bindonce ng-repeat="format in track.formats"><a target="_blank" bo-href="format.url"><span bo-text="format.name"></span> <small bo-text="'(' + format.size + ')'"></small></a></li>
</ul> </ul>
</div> </li>
<div class="dropdown"> <li class="dropdown">
<a href="#" class="btn btn-small dropdown-toggle" ng-show="auth.isLogged"> <a href="#" class="btn btn-small dropdown-toggle" ng-show="auth.isLogged">
Add to Playlist <i class="caret"></i> Add to Playlist
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li ng-repeat="playlist in playlists"> <li bindonce ng-repeat="playlist in playlists">
<a ng-class="{disabled: playlist.message, 'btn-success': playlist.message}" href="{{playlist.url}}" pfm-eat-click ng-click="addToPlaylist(playlist); $event.stopPropagation()"> <a bo-class="{disabled: playlist.message, 'btn-success': playlist.message}" bo-href="playlist.url" pfm-eat-click ng-click="addToPlaylist(playlist); $event.stopPropagation()">
<span ng-hide="playlist.message">{{playlist.title}}</span> <span ng-hide="playlist.message" bo-text="playlist.title"></span>
<span ng-show="playlist.message">{{playlist.message}}</span> <span ng-show="playlist.message">{{playlist.message}}</span>
</a> </a>
</li> </li>
<li><a href="#" class="btn-primary" pfm-eat-click ng-click="addToNewPlaylist()">Add to New Playlist</a></li> <li><a href="#" class="btn-primary" pfm-eat-click ng-click="addToNewPlaylist()">Add to New Playlist</a></li>
</ul> </ul>
</div> </li>
</div> <li><a href="#" class="btn">Share or Embed</a></li>
<li><pfm-favourite-button resource="track" type="track"></pfm-favourite-button></li>
</ul>
<header>
<pfm-track-player track="track"></pfm-track-player> <pfm-track-player track="track"></pfm-track-player>
<h1> <h1 bo-text="track.title"></h1>
{{track.title}} <h2>
<span class="subtitle"> <span bo-show="track.album">
<span ng-show="track.album"> from: <a bo-href="track.album.url" bo-text="track.album.title"></a>
from: <a href="{{track.album.url}}">{{track.album.title}}</a>
</span> </span>
by: <a href="{{track.user.url}}">{{track.user.name}}</a> by: <a bo-href="track.user.url" bo-text="track.user.name"></a>
</span> </h2>
</h1> </header>
<div class="stretch-to-bottom"> <div class="stretch-to-bottom details-columns">
<div class="row-fluid"> <div class="right">
<div class="span8"> <img class="cover" bo-src="track.covers.normal" />
<div class="description">
<p ng-bind-html-unsafe="track.description | noHTML | newlines"></p> <ul class="stats">
<li>Published: <strong bo-text="track.published_at | pfmdate:'short'"></strong></li>
<li>Views: <strong bo-text="track.stats.views"></strong></li>
<li>Plays: <strong bo-text="track.stats.plays"></strong></li>
<li>Downloads: <strong bo-text="track.stats.downloads"></strong></li>
<li>Favourites: <strong bo-text="track.stats.favourites"></strong></li>
</ul>
</div>
<div class="left">
<div class="description" bo-show="track.description.length">
<h2>Description</h2>
<p bo-html="track.description | noHTML | newlines"></p>
</div> </div>
<div ng-show="track.is_vocal && track.lyrics.length" class="lyrics-panel"> <div bo-show="track.is_vocal && track.lyrics.length" class="lyrics-panel">
<h2>Lyrics</h2> <h2>Lyrics</h2>
<div class="lyrics revealable"> <div class="lyrics revealable">
<div class="reveal"> <div class="reveal">
<a href="#">Click to reveal full lyrics...</a> <a href="#">Click to reveal full lyrics...</a>
</div> </div>
<p class="content" ng-bind-html="track.lyrics | noHTML | newlines | trust"></p> <p class="content" bo-html="track.lyrics | noHTML | newlines"></p>
</div> </div>
</div> </div>
<h2>Comments</h2>
<pfm-comments type="track" resource="track"></pfm-comments> <pfm-comments type="track" resource="track"></pfm-comments>
</div> </div>
<div class="span4 cover-image">
<img ng-src="{{track.covers.normal}}" />
<div class="fb-like" data-href="{{track.url}}" data-send="false" data-layout="button_count" data-width="20" data-show-faces="false"></div>
<a href="https://twitter.com/share" class="twitter-share-button" data-url="{{track.url}}" data-text="{{track.title + ' by ' + track.user.name + ' on Pony.fm'}}" data-via="ponyfm">Tweet</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
<a href="#" class="btn btn-info">Share or Embed</a>
<h2>Stats</h2>
<ul class="stats">
<li>Published: <strong>{{track.published_at | pfmdate:"short"}}</strong></li>
<li>Views: <strong>{{track.stats.views}}</strong></li>
<li>Plays: <strong>{{track.stats.plays}}</strong></li>
<li>Downloads: <strong>{{track.stats.downloads}}</strong></li>
<li>Favourites: <strong>{{track.stats.favourites}}</strong></li>
</ul>
</div>
</div>
</div> </div>
</div> </div>