mirror of
https://github.com/Poniverse/Pony.fm.git
synced 2024-11-25 06:27:59 +01:00
Further design changes
This commit is contained in:
parent
22818261ee
commit
4c025dd1e9
11 changed files with 445 additions and 79 deletions
|
@ -52,6 +52,7 @@
|
|||
new FileAsset('scripts/base/moment.js'),
|
||||
new FileAsset('scripts/base/soundmanager2-nodebug.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/angular-ui-sortable.js'),
|
||||
new FileAsset('scripts/base/angular-ui-date.js'),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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 [
|
||||
'$locationProvider', '$stateProvider', '$dialogProvider'
|
||||
|
|
|
@ -5,6 +5,7 @@ angular.module('ponyfm').directive 'pfmFavouriteButton', () ->
|
|||
resource: '=resource',
|
||||
class: '@class',
|
||||
type: '@type'
|
||||
replace: true
|
||||
|
||||
controller: [
|
||||
'$scope', 'favourites', 'auth'
|
||||
|
|
|
@ -4,6 +4,7 @@ angular.module('ponyfm').directive 'pfmTrackPlayer', () ->
|
|||
scope:
|
||||
track: '=track',
|
||||
class: '@class'
|
||||
replace: true
|
||||
|
||||
controller: [
|
||||
'$scope', 'player'
|
||||
|
|
|
@ -2,5 +2,6 @@ angular.module('ponyfm').filter 'trust', [
|
|||
'$sce'
|
||||
($sce) ->
|
||||
(input) ->
|
||||
console.log input
|
||||
$sce.trustAsHtml input
|
||||
]
|
193
public/scripts/base/bindonce.js
Normal file
193
public/scripts/base/bindonce.js
Normal 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});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
|
@ -13,15 +13,131 @@
|
|||
line-height: normal;
|
||||
overflow: hidden;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.revealable {
|
||||
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 {
|
||||
border: 2px solid @blue;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #555;
|
||||
float: right;
|
||||
.box-sizing(border-box);
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
background: #eee;
|
||||
padding: 3px;
|
||||
z-index: 500;
|
||||
text-decoration: none;
|
||||
font-size: 10pt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,10 +11,6 @@ html body {
|
|||
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 {
|
||||
> a {
|
||||
display: block;
|
||||
|
|
|
@ -2,6 +2,66 @@
|
|||
@import-once 'mixins';
|
||||
@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;
|
||||
|
||||
.tracks-listing.four-columns {
|
||||
|
@ -25,6 +85,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
html .single-player .play-button {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.single-player, .tracks-listing li .image {
|
||||
float: left;
|
||||
width: @icon-size;
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
<div class="comments">
|
||||
<div class="alert alert-info" ng-show="resource.comments.count == 0">
|
||||
<div class="comments" bindonce>
|
||||
<h2>All Comments ({{resource.comments.length}})</h2>
|
||||
<div class="alert alert-info" ng-show="resource.comments.length == 0">
|
||||
There are no comments yet!
|
||||
</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">
|
||||
<div class="form-row">
|
||||
<textarea ng-model="content"></textarea>
|
||||
<input type="text" ng-model="content" placeholder="Write a comment..." />
|
||||
</div>
|
||||
<button type="submit" class="btn" ng-class="{disabled: content.length == 0}">Post Comment</button>
|
||||
</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>
|
|
@ -1,80 +1,72 @@
|
|||
<div class="track-details" xmlns="http://www.w3.org/1999/html">
|
||||
<div class="track-toolbar btn-group pull-right">
|
||||
<pfm-favourite-button resource="track" type="track"></pfm-favourite-button>
|
||||
<div class="dropdown">
|
||||
<div class="track-details" bindonce="track">
|
||||
<ul class="dropdowns">
|
||||
<li class="dropdown">
|
||||
<a href="#" class="btn btn-small btn-info dropdown-toggle">
|
||||
Downloads <i class="caret"></i>
|
||||
Downloads
|
||||
</a>
|
||||
<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>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="btn btn-small dropdown-toggle" ng-show="auth.isLogged">
|
||||
Add to Playlist <i class="caret"></i>
|
||||
Add to Playlist
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li 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()">
|
||||
<span ng-hide="playlist.message">{{playlist.title}}</span>
|
||||
<li bindonce ng-repeat="playlist in playlists">
|
||||
<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" bo-text="playlist.title"></span>
|
||||
<span ng-show="playlist.message">{{playlist.message}}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li><a href="#" class="btn-primary" pfm-eat-click ng-click="addToNewPlaylist()">Add to New Playlist</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li><a href="#" class="btn">Share or Embed</a></li>
|
||||
<li><pfm-favourite-button resource="track" type="track"></pfm-favourite-button></li>
|
||||
</ul>
|
||||
|
||||
<pfm-track-player track="track"></pfm-track-player>
|
||||
<h1>
|
||||
{{track.title}}
|
||||
<span class="subtitle">
|
||||
<span ng-show="track.album">
|
||||
from: <a href="{{track.album.url}}">{{track.album.title}}</a>
|
||||
<header>
|
||||
<pfm-track-player track="track"></pfm-track-player>
|
||||
<h1 bo-text="track.title"></h1>
|
||||
<h2>
|
||||
<span bo-show="track.album">
|
||||
from: <a bo-href="track.album.url" bo-text="track.album.title"></a>
|
||||
</span>
|
||||
|
||||
by: <a href="{{track.user.url}}">{{track.user.name}}</a>
|
||||
</span>
|
||||
</h1>
|
||||
by: <a bo-href="track.user.url" bo-text="track.user.name"></a>
|
||||
</h2>
|
||||
</header>
|
||||
|
||||
<div class="stretch-to-bottom">
|
||||
<div class="row-fluid">
|
||||
<div class="span8">
|
||||
<div class="description">
|
||||
<p ng-bind-html-unsafe="track.description | noHTML | newlines"></p>
|
||||
</div>
|
||||
<div class="stretch-to-bottom details-columns">
|
||||
<div class="right">
|
||||
<img class="cover" bo-src="track.covers.normal" />
|
||||
|
||||
<div ng-show="track.is_vocal && track.lyrics.length" class="lyrics-panel">
|
||||
<h2>Lyrics</h2>
|
||||
<div class="lyrics revealable">
|
||||
<div class="reveal">
|
||||
<a href="#">Click to reveal full lyrics...</a>
|
||||
</div>
|
||||
<p class="content" ng-bind-html="track.lyrics | noHTML | newlines | trust"></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 bo-show="track.is_vocal && track.lyrics.length" class="lyrics-panel">
|
||||
<h2>Lyrics</h2>
|
||||
<div class="lyrics revealable">
|
||||
<div class="reveal">
|
||||
<a href="#">Click to reveal full lyrics...</a>
|
||||
</div>
|
||||
<p class="content" bo-html="track.lyrics | noHTML | newlines"></p>
|
||||
</div>
|
||||
|
||||
<h2>Comments</h2>
|
||||
<pfm-comments type="track" resource="track"></pfm-comments>
|
||||
</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>
|
||||
<pfm-comments type="track" resource="track"></pfm-comments>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
Loading…
Reference in a new issue