diff --git a/app/library/Assets.php b/app/library/Assets.php index 0e313a3a..2a2b6b24 100644 --- a/app/library/Assets.php +++ b/app/library/Assets.php @@ -57,6 +57,7 @@ new FileAsset('scripts/base/angular-ui-sortable.js'), new FileAsset('scripts/base/angular-ui-date.js'), new FileAsset('scripts/base/angular-ui-router.js'), + new FileAsset('scripts/base/angularytics.js'), new AssetCollection([ new GlobAsset('scripts/shared/*.coffee'), new GlobAsset('scripts/shared/*.js'), diff --git a/app/models/Entities/Track.php b/app/models/Entities/Track.php index aa4f2612..72c658d1 100644 --- a/app/models/Entities/Track.php +++ b/app/models/Entities/Track.php @@ -68,22 +68,17 @@ ->groupBy('id') ->orderBy('plays', 'desc') ->take(20); - return $query->get(['*', DB::raw('count(*) as plays')]); + + $results = []; + + foreach($query->get(['*', DB::raw('count(*) as plays')]) as $track) { + $results[] = self::mapPublicTrackSummary($track); + } + + return $results; }); - $results = []; - $i = 0; - - foreach($tracks as $track) { - if ($i < $count) { - $results[] = self::mapPublicTrackSummary($track); - $i++; - } else { - break; - } - } - - return $results; + return $tracks; } public static function mapPublicTrackShow($track) { diff --git a/app/views/shared/_app_layout.blade.php b/app/views/shared/_app_layout.blade.php index a41c7b3c..aa7ceb2a 100644 --- a/app/views/shared/_app_layout.blade.php +++ b/app/views/shared/_app_layout.blade.php @@ -54,8 +54,8 @@ @if (Auth::check()) -
  • Account
  • Favourites
  • +
  • Account
  • @endif
  • About
  • @@ -103,6 +103,20 @@ }; + + {{ Assets::scriptIncludes() }} diff --git a/public/scripts/app/app.coffee b/public/scripts/app/app.coffee index c28f1e22..a66de181 100644 --- a/public/scripts/app/app.coffee +++ b/public/scripts/app/app.coffee @@ -1,10 +1,18 @@ window.pfm.preloaders = {} -module = angular.module 'ponyfm', ['ui.bootstrap', 'ui.state', 'ui.date', 'ui.sortable', 'pasvaz.bindonce'] +module = angular.module 'ponyfm', ['ui.bootstrap', 'ui.state', 'ui.date', 'ui.sortable', 'pasvaz.bindonce', 'angularytics'] + +module.run [ + 'Angularytics', + (analyitcs) -> + analyitcs.init() +] module.config [ - '$locationProvider', '$stateProvider', '$dialogProvider' - (location, state, $dialogProvider) -> + '$locationProvider', '$stateProvider', '$dialogProvider', 'AngularyticsProvider' + (location, state, $dialogProvider, analytics) -> + + analytics.setEventHandlers ['Google'] # Upload @@ -178,6 +186,7 @@ module.config [ state.state 'home', url: '/' templateUrl: '/templates/home/index.html' + controller: 'home' # Final catch-all for aritsts state.state 'content.artist', diff --git a/public/scripts/app/controllers/home.coffee b/public/scripts/app/controllers/home.coffee new file mode 100644 index 00000000..aedb8829 --- /dev/null +++ b/public/scripts/app/controllers/home.coffee @@ -0,0 +1,15 @@ +window.pfm.preloaders['home'] = [ + 'dashboard' + (dashboard) -> dashboard.refresh(true) +] + +angular.module('ponyfm').controller "home", [ + '$scope', 'dashboard' + ($scope, dashboard) -> + $scope.recentTracks = null + $scope.popularTracks = null + + dashboard.refresh().done (res) -> + $scope.recentTracks = res.recent_tracks + $scope.popularTracks = res.popular_tracks +] \ No newline at end of file diff --git a/public/scripts/base/angularytics.js b/public/scripts/base/angularytics.js new file mode 100644 index 00000000..5f6aafb5 --- /dev/null +++ b/public/scripts/base/angularytics.js @@ -0,0 +1,122 @@ +(function () { + angular.module('angularytics', []).provider('Angularytics', function () { + var eventHandlersNames = ['Google']; + this.setEventHandlers = function (handlers) { + if (angular.isString(handlers)) { + handlers = [handlers]; + } + eventHandlersNames = []; + angular.forEach(handlers, function (handler) { + eventHandlersNames.push(capitalizeHandler(handler)); + }); + }; + var capitalizeHandler = function (handler) { + return handler.charAt(0).toUpperCase() + handler.substring(1); + }; + var pageChangeEvent = '$locationChangeSuccess'; + this.setPageChangeEvent = function (newPageChangeEvent) { + pageChangeEvent = newPageChangeEvent; + }; + this.$get = [ + '$injector', + '$rootScope', + '$location', + function ($injector, $rootScope, $location) { + var eventHandlers = []; + angular.forEach(eventHandlersNames, function (handler) { + eventHandlers.push($injector.get('Angularytics' + handler + 'Handler')); + }); + var forEachHandlerDo = function (action) { + angular.forEach(eventHandlers, function (handler) { + action(handler); + }); + }; + $rootScope.$on(pageChangeEvent, function () { + forEachHandlerDo(function (handler) { + var url = $location.path(); + if (url) { + handler.trackPageView(url); + } + }); + }); + var service = {}; + service.init = function () { + }; + service.trackEvent = function (category, action, opt_label, opt_value, opt_noninteraction) { + forEachHandlerDo(function (handler) { + if (category && action) { + handler.trackEvent(category, action, opt_label, opt_value, opt_noninteraction); + } + }); + }; + return service; + } + ]; + }); +}()); +(function () { + angular.module('angularytics').factory('AngularyticsConsoleHandler', [ + '$log', + function ($log) { + var service = {}; + service.trackPageView = function (url) { + $log.log('URL visited', url); + }; + service.trackEvent = function (category, action, opt_label, opt_value, opt_noninteraction) { + $log.log('Event tracked', category, action, opt_label, opt_value, opt_noninteraction); + }; + return service; + } + ]); +}()); +(function () { + angular.module('angularytics').factory('AngularyticsGoogleHandler', [ + '$log', + function ($log) { + var service = {}; + service.trackPageView = function (url) { + _gaq.push([ + '_set', + 'page', + url + ]); + _gaq.push([ + '_trackPageview', + url + ]); + }; + service.trackEvent = function (category, action, opt_label, opt_value, opt_noninteraction) { + _gaq.push([ + '_trackEvent', + category, + action, + opt_label, + opt_value, + opt_noninteraction + ]); + }; + return service; + } + ]).factory('AngularyticsGoogleUniversalHandler', function () { + var service = {}; + service.trackPageView = function (url) { + ga('set', 'page', url); + ga('send', 'pageview', url); + }; + service.trackEvent = function (category, action, opt_label, opt_value, opt_noninteraction) { + ga('send', 'event', category, action, opt_label, opt_value, { 'nonInteraction': opt_noninteraction }); + }; + return service; + }); +}()); +(function () { + angular.module('angularytics').filter('trackEvent', [ + 'Angularytics', + function (Angularytics) { + return function (entry, category, action, opt_label, opt_value, opt_noninteraction) { + Angularytics.trackEvent(category, action, opt_label, opt_value, opt_noninteraction); + return entry; + }; + } + ]); +}()); \ No newline at end of file diff --git a/public/styles/app.less b/public/styles/app.less index babef2c2..ec6534e6 100644 --- a/public/styles/app.less +++ b/public/styles/app.less @@ -1,6 +1,7 @@ @import url(http://fonts.googleapis.com/css?family=Josefin+Sans); @import 'base/bootstrap/bootstrap'; +@import 'base/bootstrap/responsive'; @import 'base/font-awesome/font-awesome'; @import 'variables'; @import 'mixins'; diff --git a/public/styles/body.less b/public/styles/body.less index 266a64ab..e1c1df6a 100644 --- a/public/styles/body.less +++ b/public/styles/body.less @@ -24,6 +24,24 @@ a { } } +.about-page { + h2 { + margin: 0px; + margin-bottom: 5px; + font-size: 13pt; + color: #C2889C; + line-height: normal; + overflow: hidden; + font-weight: normal; + } +} + +.welcome { + padding: 5px; + margin-bottom: 10px; + background: lighten(@pfm-purple, 30%); +} + .revealable { font-size: 10pt; color: #222; diff --git a/public/styles/content.less b/public/styles/content.less index a80e73be..4ab5f5eb 100644 --- a/public/styles/content.less +++ b/public/styles/content.less @@ -2,6 +2,37 @@ @import-once 'mixins'; @import-once 'variables'; +@media (max-width: 1300px) and (min-width: 720px) { + html { + .albums-listing, .playlists-listing, .artist-listing { + &.two-columns li { + width: auto; + float: none; + } + + li { + width: 33.33333%; + } + } + } +} + +@media (max-width: 720px) { + html { + .albums-listing, .playlists-listing, .artist-listing { + &.two-columns li { + width: auto; + float: none; + } + + li { + width: auto; + float: none; + } + } + } +} + .albums-listing, .playlists-listing, .artist-listing { margin: 0px; padding: 0px; @@ -180,6 +211,46 @@ @icon-size: 42px; +@media (max-width: 1300px) and (min-width: 720px) { + html { + .tracks-listing { + &.four-columns li { + width: 33.333%; + } + + &.three-columns li { + width: 50%; + } + + &.two-columns li { + width: auto; + float: none; + } + } + } +} + +@media (max-width: 720px) { + html { + .tracks-listing { + &.four-columns li { + width: auto; + float: none; + } + + &.three-columns li { + width: auto; + float: none; + } + + &.two-columns li { + width: auto; + float: none; + } + } + } +} + .tracks-listing.four-columns { li { float: left; diff --git a/public/styles/layout.less b/public/styles/layout.less index 3823a28f..fd7bd95c 100644 --- a/public/styles/layout.less +++ b/public/styles/layout.less @@ -174,8 +174,12 @@ header { } } - li.uploader { - a { + li.none { + span { + display: block; + padding: 5px 25px; + color: #555; + font-style: italic; } } } diff --git a/public/templates/artists/list.html b/public/templates/artists/list.html index 586bb5f5..d0991dfe 100644 --- a/public/templates/artists/list.html +++ b/public/templates/artists/list.html @@ -1,16 +1,18 @@ - + \ No newline at end of file diff --git a/public/templates/dashboard/index.html b/public/templates/dashboard/index.html index ebb8aef0..dbc3c7c6 100644 --- a/public/templates/dashboard/index.html +++ b/public/templates/dashboard/index.html @@ -1,5 +1,5 @@ -
    -
    +
    +

    see more @@ -9,7 +9,7 @@

    -