mirror of
https://github.com/Poniverse/Pony.fm.git
synced 2024-11-25 06:27:59 +01:00
Intermediate commit (power is going on and off)
This commit is contained in:
parent
8d3d126550
commit
21009713f3
21 changed files with 386 additions and 118 deletions
|
@ -26,6 +26,14 @@
|
|||
return $this->execute(new EditTrackCommand($id, Input::all()));
|
||||
}
|
||||
|
||||
public function getShow($id) {
|
||||
$track = Track::find($id);
|
||||
if (!$track || !$track->canView(Auth::user()))
|
||||
return $this->notFound('Track not found!');
|
||||
|
||||
return Response::json(['track' => Track::mapPublicTrackShow($track)], 200);
|
||||
}
|
||||
|
||||
public function getRecent() {
|
||||
$query = Track::summary()->with(['genre', 'user', 'cover'])->whereNotNull('published_at')->orderBy('published_at', 'desc')->take(15);
|
||||
if (!Auth::check() || !Auth::user()->can_see_explicit_content)
|
||||
|
@ -34,7 +42,7 @@
|
|||
$tracks = [];
|
||||
|
||||
foreach ($query->get() as $track) {
|
||||
$tracks[] = $this->mapPublicTrack($track);
|
||||
$tracks[] = Track::mapPublicTrackSummary($track);
|
||||
}
|
||||
|
||||
return Response::json($tracks, 200);
|
||||
|
@ -51,11 +59,10 @@
|
|||
|
||||
$totalCount = $query->count();
|
||||
$query->take(30)->skip(30 * ($page - 1));
|
||||
$tracks = [];
|
||||
|
||||
foreach ($query->get() as $track) {
|
||||
$tracks[] = $this->mapPublicTrack($track);
|
||||
}
|
||||
$tracks = [];
|
||||
foreach ($query->get() as $track)
|
||||
$tracks[] = Track::mapPublicTrackSummary($track);
|
||||
|
||||
return Response::json(["tracks" => $tracks, "current_page" => $page, "total_pages" => ceil($totalCount / 30)], 200);
|
||||
}
|
||||
|
@ -73,27 +80,9 @@
|
|||
|
||||
$this->applyFilters($query);
|
||||
|
||||
$dbTracks = $query->get();
|
||||
$tracks = [];
|
||||
|
||||
foreach ($dbTracks as $track) {
|
||||
$tracks[] = [
|
||||
'id' => $track->id,
|
||||
'title' => $track->title,
|
||||
'user_id' => $track->user_id,
|
||||
'slug' => $track->slug,
|
||||
'is_vocal' => $track->is_vocal,
|
||||
'is_explicit' => $track->is_explicit,
|
||||
'is_downloadable' => $track->is_downloadable,
|
||||
'is_published' => $track->isPublished(),
|
||||
'created_at' => $track->created_at,
|
||||
'published_at' => $track->published_at,
|
||||
'duration' => $track->duration,
|
||||
'genre_id' => $track->genre_id,
|
||||
'track_type_id' => $track->track_type_id,
|
||||
'cover_url' => $track->getCoverUrl(Image::SMALL)
|
||||
];
|
||||
}
|
||||
foreach ($query->get() as $track)
|
||||
$tracks[] = Track::mapPrivateTrackSummary($track);
|
||||
|
||||
return Response::json($tracks, 200);
|
||||
}
|
||||
|
@ -106,68 +95,9 @@
|
|||
if ($track->user_id != Auth::user()->id)
|
||||
return $this->notAuthorized();
|
||||
|
||||
$showSongs = [];
|
||||
foreach ($track->showSongs as $showSong) {
|
||||
$showSongs[] = ['id' => $showSong->id, 'title' => $showSong->title];
|
||||
}
|
||||
|
||||
return Response::json([
|
||||
'id' => $track->id,
|
||||
'title' => $track->title,
|
||||
'user_id' => $track->user_id,
|
||||
'slug' => $track->slug,
|
||||
'is_vocal' => (bool)$track->is_vocal,
|
||||
'is_explicit' => (bool)$track->is_explicit,
|
||||
'is_downloadable' => !$track->isPublished() ? true : (bool)$track->is_downloadable,
|
||||
'is_published' => $track->published_at != null,
|
||||
'created_at' => $track->created_at,
|
||||
'published_at' => $track->published_at,
|
||||
'duration' => $track->duration,
|
||||
'genre_id' => $track->genre_id,
|
||||
'track_type_id' => $track->track_type_id,
|
||||
'license_id' => $track->license_id != null ? $track->license_id : 3,
|
||||
'description' => $track->description,
|
||||
'lyrics' => $track->lyrics,
|
||||
'released_at' => $track->released_at,
|
||||
'cover_url' => $track->hasCover() ? $track->getCoverUrl(Image::NORMAL) : null,
|
||||
'real_cover_url' => $track->getCoverUrl(Image::NORMAL),
|
||||
'show_songs' => $showSongs,
|
||||
'album_id' => $track->album_id
|
||||
], 200);
|
||||
return Response::json(Track::mapPrivateTrackShow($track), 200);
|
||||
}
|
||||
|
||||
private function mapPublicTrack($track) {
|
||||
return [
|
||||
'id' => $track->id,
|
||||
'title' => $track->title,
|
||||
'user' => [
|
||||
'id' => $track->user->id,
|
||||
'name' => $track->user->display_name,
|
||||
'url' => $track->user->url
|
||||
],
|
||||
'url' => $track->url,
|
||||
'slug' => $track->slug,
|
||||
'is_vocal' => $track->is_vocal,
|
||||
'is_explicit' => $track->is_explicit,
|
||||
'is_downloadable' => $track->is_downloadable,
|
||||
'is_published' => $track->isPublished(),
|
||||
'published_at' => $track->published_at,
|
||||
'duration' => $track->duration,
|
||||
'genre' => $track->genre != null
|
||||
?
|
||||
[
|
||||
'id' => $track->genre->id,
|
||||
'slug' => $track->genre->slug,
|
||||
'name' => $track->genre->name
|
||||
] : null,
|
||||
'track_type_id' => $track->track_type_id,
|
||||
'covers' => [
|
||||
'thumbnail' => $track->getCoverUrl(Image::THUMBNAIL),
|
||||
'small' => $track->getCoverUrl(Image::SMALL),
|
||||
'normal' => $track->getCoverUrl(Image::NORMAL)
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
private function applyFilters($query) {
|
||||
if (Input::has('order')) {
|
||||
|
|
|
@ -7,4 +7,23 @@
|
|||
public function getIndex() {
|
||||
return View::make('tracks.index');
|
||||
}
|
||||
|
||||
public function getTrack($id, $slug) {
|
||||
$track = Track::find($id);
|
||||
if (!$track || !$track->canView(Auth::user()))
|
||||
App::abort(404);
|
||||
|
||||
if ($track->slug != $slug)
|
||||
return Redirect::action('TracksController@getTrack', [$id, $track->slug]);
|
||||
|
||||
return View::make('tracks.show');
|
||||
}
|
||||
|
||||
public function getShortlink($id) {
|
||||
$track = Track::find($id);
|
||||
if (!$track || !$track->canView(Auth::user()))
|
||||
App::abort(404);
|
||||
|
||||
return Redirect::action('TracksController@getTrack', [$id, $track->slug]);
|
||||
}
|
||||
}
|
|
@ -39,7 +39,7 @@
|
|||
}
|
||||
|
||||
public function getUrlAttribute() {
|
||||
return '/playlist/' . $this->id . '/' . $this->slug;
|
||||
return '/playlist/' . $this->id . '-' . $this->slug;
|
||||
}
|
||||
|
||||
public function getCoverUrl($type = Image::NORMAL) {
|
||||
|
|
|
@ -28,6 +28,84 @@
|
|||
return self::select('id', 'title', 'user_id', 'slug', 'is_vocal', 'is_explicit', 'created_at', 'published_at', 'duration', 'is_downloadable', 'genre_id', 'track_type_id', 'cover_id', 'album_id');
|
||||
}
|
||||
|
||||
public static function mapPublicTrackShow($track) {
|
||||
$returnValue = self::mapPublicTrackSummary($track);
|
||||
$returnValue['description'] = $track->description;
|
||||
$returnValue['lyrics'] = $track->lyrics;
|
||||
return $returnValue;
|
||||
}
|
||||
|
||||
public static function mapPublicTrackSummary($track) {
|
||||
return [
|
||||
'id' => $track->id,
|
||||
'title' => $track->title,
|
||||
'user' => [
|
||||
'id' => $track->user->id,
|
||||
'name' => $track->user->display_name,
|
||||
'url' => $track->user->url
|
||||
],
|
||||
'url' => $track->url,
|
||||
'slug' => $track->slug,
|
||||
'is_vocal' => $track->is_vocal,
|
||||
'is_explicit' => $track->is_explicit,
|
||||
'is_downloadable' => $track->is_downloadable,
|
||||
'is_published' => $track->isPublished(),
|
||||
'published_at' => $track->published_at,
|
||||
'duration' => $track->duration,
|
||||
'genre' => $track->genre != null
|
||||
?
|
||||
[
|
||||
'id' => $track->genre->id,
|
||||
'slug' => $track->genre->slug,
|
||||
'name' => $track->genre->name
|
||||
] : null,
|
||||
'track_type_id' => $track->track_type_id,
|
||||
'covers' => [
|
||||
'thumbnail' => $track->getCoverUrl(Image::THUMBNAIL),
|
||||
'small' => $track->getCoverUrl(Image::SMALL),
|
||||
'normal' => $track->getCoverUrl(Image::NORMAL)
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public static function mapPrivateTrackShow($track) {
|
||||
$showSongs = [];
|
||||
foreach ($track->showSongs as $showSong) {
|
||||
$showSongs[] = ['id' => $showSong->id, 'title' => $showSong->title];
|
||||
}
|
||||
|
||||
$returnValue = self::mapPrivateTrackSummary($track);
|
||||
$returnValue['album_id'] = $track->album_id;
|
||||
$returnValue['show_songs'] = $showSongs;
|
||||
$returnValue['real_cover_url'] = $track->getCoverUrl(Image::NORMAL);
|
||||
$returnValue['cover_url'] = $track->hasCover() ? $track->getCoverUrl(Image::NORMAL) : null;
|
||||
$returnValue['released_at'] = $track->released_at;
|
||||
$returnValue['lyrics'] = $track->lyrics;
|
||||
$returnValue['description'] = $track->description;
|
||||
$returnValue['is_downloadable'] = !$track->isPublished() ? true : (bool)$track->is_downloadable;
|
||||
$returnValue['license_id'] = $track->license_id != null ? $track->license_id : 3;
|
||||
return $returnValue;
|
||||
}
|
||||
|
||||
public static function mapPrivateTrackSummary($track) {
|
||||
return [
|
||||
'id' => $track->id,
|
||||
'title' => $track->title,
|
||||
'user_id' => $track->user_id,
|
||||
'slug' => $track->slug,
|
||||
'is_vocal' => $track->is_vocal,
|
||||
'is_explicit' => $track->is_explicit,
|
||||
'is_downloadable' => $track->is_downloadable,
|
||||
'is_published' => $track->isPublished(),
|
||||
'created_at' => $track->created_at,
|
||||
'published_at' => $track->published_at,
|
||||
'duration' => $track->duration,
|
||||
'genre_id' => $track->genre_id,
|
||||
'track_type_id' => $track->track_type_id,
|
||||
'cover_url' => $track->getCoverUrl(Image::SMALL)
|
||||
];
|
||||
}
|
||||
|
||||
protected $table = 'tracks';
|
||||
|
||||
public function genre() {
|
||||
|
@ -54,8 +132,15 @@
|
|||
return date('Y', strtotime($this->release_date));
|
||||
}
|
||||
|
||||
public function canView($user) {
|
||||
if ($this->isPublished())
|
||||
return true;
|
||||
|
||||
return $this->user_id == $user->id;
|
||||
}
|
||||
|
||||
public function getUrlAttribute() {
|
||||
return URL::to('/tracks/' . $this->id . '/' . $this->slug);
|
||||
return URL::to('/tracks/' . $this->id . '-' . $this->slug);
|
||||
}
|
||||
|
||||
public function getReleaseDate() {
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
Route::get('/tracks/popular', 'TracksController@getIndex');
|
||||
Route::get('/tracks/random', 'TracksController@getIndex');
|
||||
|
||||
Route::get('tracks/{id}-{slug}', 'TracksController@getTrack');
|
||||
Route::get('t{id}', 'TracksController@getShortlink' );
|
||||
|
||||
Route::get('/albums', 'AlbumsController@getIndex');
|
||||
Route::get('/artists', 'ArtistsController@getIndex');
|
||||
Route::get('/playlists', 'PlaylistsController@getIndex');
|
||||
|
@ -30,7 +33,6 @@
|
|||
|
||||
Route::get('u{id}/avatar_{type}.png', 'UsersController@getAvatar');
|
||||
|
||||
Route::get('playlist/{id}/{slug}', 'PlaylistsController@getPlaylist');
|
||||
Route::get('playlist/{id}-{slug}', 'PlaylistsController@getPlaylist');
|
||||
Route::get('p{id}', 'PlaylistsController@getShortlink');
|
||||
|
||||
|
@ -41,6 +43,7 @@
|
|||
|
||||
Route::get('/tracks/recent', 'Api\Web\TracksController@getRecent');
|
||||
Route::get('/tracks', 'Api\Web\TracksController@getIndex');
|
||||
Route::get('/tracks/{id}', 'Api\Web\TracksController@getShow')->where('id', '\d+');
|
||||
|
||||
Route::get('/dashboard', 'Api\Web\DashboardController@getIndex');
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
<li ng-class="{selected: $state.includes('home')}"><a href="/">Home</a></li>
|
||||
@endif
|
||||
<li><h3>Discover</h3></li>
|
||||
<li ng-class="{selected: $state.includes('tracks')}"><a href="/tracks">Music <i class="icon-music"></i></a></li>
|
||||
<li ng-class="{selected: $state.includes('tracks') || $state.includes('track')}"><a href="/tracks">Music <i class="icon-music"></i></a></li>
|
||||
<li ng-class="{selected: $state.includes('albums')}"><a href="/albums">Albums <i class="icon-music"></i></a></li>
|
||||
<li ng-class="{selected: $state.includes('playlists')}"><a href="/playlists">Playlists <i class="icon-music"></i></a></li>
|
||||
<li ng-class="{selected: $state.includes('artists')}"><a href="/artists">Artists <i class="icon-user"></i></a></li>
|
||||
|
|
6
app/views/tracks/show.blade.php
Normal file
6
app/views/tracks/show.blade.php
Normal file
|
@ -0,0 +1,6 @@
|
|||
@extends('shared._app_layout')
|
||||
|
||||
@section('app_content')
|
||||
<h1>Track Listing!</h1>
|
||||
<p>This page should be what search engines see</p>
|
||||
@endsection
|
|
@ -67,6 +67,11 @@ angular.module 'ponyfm', ['ui.bootstrap', 'ui.state', 'ui.date', 'ui.sortable'],
|
|||
|
||||
# Tracks
|
||||
|
||||
state.state 'track',
|
||||
url: '/tracks/{id:[^\-]+}-{slug}'
|
||||
templateUrl: '/templates/tracks/show.html'
|
||||
controller: 'track'
|
||||
|
||||
state.state 'tracks',
|
||||
url: '/tracks'
|
||||
templateUrl: '/templates/tracks/_layout.html'
|
||||
|
@ -104,7 +109,7 @@ angular.module 'ponyfm', ['ui.bootstrap', 'ui.state', 'ui.date', 'ui.sortable'],
|
|||
templateUrl: '/templates/playlists/index.html'
|
||||
|
||||
state.state 'playlist',
|
||||
url: '/playlist/:id/:slug'
|
||||
url: '/playlist/{id:[^\-]+}-{slug}'
|
||||
templateUrl: '/templates/playlists/show.html'
|
||||
controller: 'playlist'
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
angular.module('ponyfm').controller 'playlist', [
|
||||
'$scope', '$state'
|
||||
($scope, $state) ->
|
||||
console.log $state.params.id
|
||||
$scope.refresh = () ->
|
||||
$.getJSON('/api/web/playlists/show/' + $state.params.id)
|
||||
.done (playlist) -> $scope.$apply ->
|
||||
|
|
12
public/scripts/app/controllers/track.coffee
Normal file
12
public/scripts/app/controllers/track.coffee
Normal file
|
@ -0,0 +1,12 @@
|
|||
window.pfm.preloaders['track'] = [
|
||||
'tracks', '$state'
|
||||
(tracks, $state) ->
|
||||
tracks.fetch $state.params.id
|
||||
]
|
||||
|
||||
angular.module('ponyfm').controller "track", [
|
||||
'$scope', 'tracks', '$state'
|
||||
($scope, tracks, $state) ->
|
||||
tracks.fetch($state.params.id).done (trackResponse) ->
|
||||
$scope.track = trackResponse.track
|
||||
]
|
|
@ -1,14 +1,14 @@
|
|||
window.pfm.preloaders['tracks-list'] = [
|
||||
'tracks', '$state'
|
||||
(tracks, $state) ->
|
||||
$.when.all [tracks.loadFilters().then(->
|
||||
tracks.loadFilters().then(->
|
||||
if !tracks.mainQuery.hasLoadedFilters
|
||||
tracks.mainQuery.fromFilterString($state.params.filter)
|
||||
if $state.params.page
|
||||
tracks.mainQuery.setPage $state.params.page
|
||||
|
||||
tracks.mainQuery.fetch()
|
||||
)]
|
||||
)
|
||||
]
|
||||
|
||||
angular.module('ponyfm').controller "tracks-list", [
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
window.pfm.preloaders['tracks'] = [
|
||||
'tracks', '$state'
|
||||
(tracks) ->
|
||||
tracks.loadFilters()
|
||||
]
|
||||
|
||||
angular.module('ponyfm').controller "tracks", [
|
||||
'$scope', 'tracks', '$state'
|
||||
($scope, tracks, $state) ->
|
||||
|
@ -30,4 +36,6 @@ angular.module('ponyfm').controller "tracks", [
|
|||
|
||||
$scope.gotoPage = (page) ->
|
||||
$state.transitionTo 'tracks.search.list', {filter: $state.params.filter, page: page}
|
||||
|
||||
$scope.$on '$destroy', -> tracks.mainQuery = tracks.createQuery()
|
||||
]
|
2
public/scripts/app/filters/newlines.coffee
Normal file
2
public/scripts/app/filters/newlines.coffee
Normal file
|
@ -0,0 +1,2 @@
|
|||
angular.module('ponyfm').filter 'newlines', () ->
|
||||
(input) -> input.replace(/\n/g, '<br/>')
|
5
public/scripts/app/filters/noHTML.coffee
Normal file
5
public/scripts/app/filters/noHTML.coffee
Normal file
|
@ -0,0 +1,5 @@
|
|||
angular.module('ponyfm').filter 'noHTML', () ->
|
||||
(input) ->
|
||||
input.replace(/&/g, '&')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/</g, '<')
|
|
@ -1,7 +1,8 @@
|
|||
angular.module('ponyfm').factory('tracks', [
|
||||
'$rootScope', '$http', 'taxonomies'
|
||||
($rootScope, $http, taxonomies) ->
|
||||
def = null
|
||||
filterDef = null
|
||||
trackCache = {}
|
||||
|
||||
class Query
|
||||
cachedDef: null
|
||||
|
@ -97,7 +98,7 @@ angular.module('ponyfm').factory('tracks', [
|
|||
fetch: () ->
|
||||
return @cachedDef if @cachedDef
|
||||
@cachedDef = new $.Deferred()
|
||||
def = @cachedDef
|
||||
trackDef = @cachedDef
|
||||
|
||||
query = '/api/web/tracks?'
|
||||
parts = ['page=' + @page]
|
||||
|
@ -115,18 +116,28 @@ angular.module('ponyfm').factory('tracks', [
|
|||
for listener in @listeners
|
||||
listener tracks
|
||||
|
||||
def.resolve tracks
|
||||
trackDef.resolve tracks
|
||||
|
||||
def.promise()
|
||||
trackDef.promise()
|
||||
|
||||
self =
|
||||
filters: {}
|
||||
|
||||
createQuery: -> new Query self.filters
|
||||
loadFilters: ->
|
||||
return def if def
|
||||
fetch: (id, force) ->
|
||||
force = force || false
|
||||
return trackCache[id] if !force && trackCache[id]
|
||||
trackDef = new $.Deferred()
|
||||
$http.get('/api/web/tracks/' + id).success (track) ->
|
||||
trackDef.resolve track
|
||||
|
||||
def = new $.Deferred()
|
||||
trackCache[id] = trackDef.promise()
|
||||
|
||||
createQuery: -> new Query self.filters
|
||||
|
||||
loadFilters: ->
|
||||
return filterDef if filterDef
|
||||
|
||||
filterDef = new $.Deferred()
|
||||
self.filters.isVocal =
|
||||
type: 'single'
|
||||
values: [
|
||||
|
@ -174,9 +185,9 @@ angular.module('ponyfm').factory('tracks', [
|
|||
id: song.id
|
||||
|
||||
self.mainQuery = self.createQuery()
|
||||
def.resolve self
|
||||
filterDef.resolve self
|
||||
|
||||
def.promise()
|
||||
filterDef.promise()
|
||||
|
||||
self
|
||||
])
|
|
@ -9,6 +9,17 @@ window.handleResize = () ->
|
|||
if newHeight > 0
|
||||
$this.height newHeight
|
||||
|
||||
$('.revealable').each () ->
|
||||
$this = $ this
|
||||
$this.data 'real-height', $this.height()
|
||||
$this.css
|
||||
height: '15em'
|
||||
|
||||
$this.find('.reveal').click (e) ->
|
||||
e.preventDefault()
|
||||
$this.css {height: 'auto'}
|
||||
$(this).fadeOut 200
|
||||
|
||||
window.alignVertically = (element) ->
|
||||
$element = $(element)
|
||||
$parent = $element.parent()
|
||||
|
|
|
@ -98,11 +98,11 @@ html .dropdown-menu {
|
|||
|
||||
li.selected {
|
||||
a {
|
||||
background: @green;
|
||||
background: @blue;
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
background: fadeout(@green, 20%);
|
||||
background: fadeout(@blue, 20%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -191,22 +191,51 @@ html .dropdown-menu {
|
|||
}
|
||||
|
||||
html {
|
||||
.breadcrumb {
|
||||
.border-radius(0px);
|
||||
background: #eee;
|
||||
margin-bottom: 10px;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
border: none;
|
||||
background: #ccc;
|
||||
margin: 5px 0px;
|
||||
padding: 0px;
|
||||
overflow: hidden;
|
||||
|
||||
ul {
|
||||
.border-radius(0px);
|
||||
margin: 5px;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
|
||||
> li:first-child > a, > li:last-child > a {
|
||||
.border-radius(0px);
|
||||
}
|
||||
|
||||
li {
|
||||
display: block;
|
||||
float: left;
|
||||
|
||||
a {
|
||||
.border-radius(0px);
|
||||
border: none;
|
||||
padding: 1px 10px;
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
li.active a {
|
||||
background: #444;
|
||||
color: #ddd;
|
||||
}
|
||||
}
|
||||
|
||||
&.pagination-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
li a {
|
||||
.border-radius(0px);
|
||||
border: none;
|
||||
padding: 1px 10px;
|
||||
}
|
||||
|
||||
li.active a {
|
||||
background: #444;
|
||||
color: #ddd;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -403,12 +403,11 @@ header {
|
|||
}
|
||||
|
||||
.site-content {
|
||||
h1 {
|
||||
h1, h2 {
|
||||
border: none;
|
||||
background: none;
|
||||
color: #747474;
|
||||
font-weight: 300;
|
||||
font-size: 24px;
|
||||
line-height: normal;
|
||||
font-weight: normal;
|
||||
margin: 0px;
|
||||
|
@ -421,6 +420,27 @@ header {
|
|||
margin-top: 8px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 10pt;
|
||||
display: block;
|
||||
padding: 3px 0px;
|
||||
|
||||
a {
|
||||
float: none;
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 20px;
|
||||
border-bottom: 2px solid #ddd;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
> div > .tabs {
|
||||
|
@ -607,3 +627,7 @@ html {
|
|||
.upload-queue-leave {
|
||||
.transform(scale(1));
|
||||
}
|
||||
|
||||
.stretch-to-bottom {
|
||||
overflow-y: auto;
|
||||
}
|
|
@ -126,3 +126,63 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.track-details {
|
||||
.cover-image {
|
||||
img {
|
||||
.img-polaroid();
|
||||
}
|
||||
}
|
||||
|
||||
.lyrics {
|
||||
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 {
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
html {
|
||||
.track-toolbar {
|
||||
background: #eee;
|
||||
padding: 5px;
|
||||
|
||||
> .btn:first-child, > .btn:last-child {
|
||||
.border-radius(0px);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -54,7 +54,7 @@
|
|||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="pagination" ng-show="totalPages > 0">
|
||||
<div class="pagination" ng-show="totalPages > 1">
|
||||
<ul>
|
||||
<li ng-class="{disabled: !prevPage}"><a href="#" ng-click="gotoPage(prevPage);" pfm-eat-click>Prev</a></li>
|
||||
<li ng-repeat="page in pages" ng-class="{active: page == currentPage}">
|
||||
|
|
57
public/templates/tracks/show.html
Normal file
57
public/templates/tracks/show.html
Normal file
|
@ -0,0 +1,57 @@
|
|||
<div>
|
||||
<ul class="breadcrumb">
|
||||
<li><a href="/tracks">Tracks</a> <span class="divider">/</span></li>
|
||||
<li><a href="/tracks?filter=genres-{{track.genre.id}}">{{track.genre.name}}</a> <span class="divider">/</span></li>
|
||||
<li class="active">{{track.title}}</li>
|
||||
</ul>
|
||||
|
||||
<div class="track-toolbar btn-group pull-right">
|
||||
<a href="#" class="btn btn-small">
|
||||
Favourite This!
|
||||
<i class="icon-star-empty"></i>
|
||||
</a>
|
||||
<a href="#" class="btn btn-small">
|
||||
Add to Playlist <i class="caret"></i>
|
||||
</a>
|
||||
<div class="dropdown">
|
||||
<a href="#" class="btn btn-small btn-info dropdown-toggle">
|
||||
Downloads <i class="caret"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#"></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>
|
||||
{{track.title}}
|
||||
<span class="subtitle">
|
||||
by: <a href="{{track.user.url}}">{{track.user.name}}</a>
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<div class="track-details">
|
||||
<div class="row-fluid">
|
||||
<div class="span7">
|
||||
<div class="description">
|
||||
<p ng-bind-html-unsafe="track.description | noHTML | newlines"></p>
|
||||
</div>
|
||||
|
||||
<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-unsafe="track.lyrics | noHTML | newlines"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span5 cover-image">
|
||||
<img ng-src="{{track.covers.normal}}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Comments</h2>
|
||||
</div>
|
||||
</div>
|
Loading…
Reference in a new issue