mirror of
https://github.com/Poniverse/Pony.fm.git
synced 2025-02-19 19:34:23 +01:00
Coloured top bars for artists
This commit is contained in:
parent
fa7eb96ea6
commit
b98a776db7
12 changed files with 159 additions and 16 deletions
|
@ -7,7 +7,9 @@
|
||||||
"url": "ssh://git@phabricator.poniverse.net/diffusion/PF/pony-fm.git"
|
"url": "ssh://git@phabricator.poniverse.net/diffusion/PF/pony-fm.git"
|
||||||
},
|
},
|
||||||
"packages": {},
|
"packages": {},
|
||||||
"dependencies": {},
|
"dependencies": {
|
||||||
|
"color-thief": "github:logic-dev/color-thief"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"angular": "1.5.6",
|
"angular": "1.5.6",
|
||||||
"angular-chart.js": "1.0.0-alpha6",
|
"angular-chart.js": "1.0.0-alpha6",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="resource-details artist-details" ng-class="::{'x-archived': artist.is_archived}">
|
<div class="resource-details artist-details" ng-class="::{'x-archived': artist.is_archived}">
|
||||||
|
|
||||||
<header ng-style="{'background-image': 'linear-gradient(180deg, ' + artist.avatar_colors[0] + ' 15%, ' + artist.avatar_colors[1] + ' 100%)'}">
|
<header ng-style="headerStyle">
|
||||||
<img src="{{artist.avatars.normal}}">
|
<img src="{{artist.avatars.normal}}" id="avatar">
|
||||||
<div class="artist-right">
|
<div class="artist-right">
|
||||||
<h1>{{artist.name}}<i class="material-icons admin-star" ng-show="::artist.isAdmin" data-title="Admin" bs-tooltip>verified_user</i></h1>
|
<h1>{{artist.name}}<i class="material-icons admin-star" ng-show="::artist.isAdmin" data-title="Admin" bs-tooltip>verified_user</i></h1>
|
||||||
<p class="follower-count">
|
<p class="follower-count">
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
'other': '{} followers'}">
|
'other': '{} followers'}">
|
||||||
</ng-pluralize>
|
</ng-pluralize>
|
||||||
</p>
|
</p>
|
||||||
<a href="#" class="btn btn-default" ng-class="{'btn-primary': !artist.user_data.is_following}" ng-show="auth.isLogged && auth.user.id != artist.id" pfm-eat-click ng-click="toggleFollow()">
|
<a href="#" class="btn btn-default btn-flat" ng-class="{'btn-primary': !artist.user_data.is_following}" ng-show="auth.isLogged && auth.user.id != artist.id" pfm-eat-click ng-click="toggleFollow()">
|
||||||
<span ng-if="!artist.user_data.is_following">Follow</span>
|
<span ng-if="!artist.user_data.is_following">Follow</span>
|
||||||
<span ng-if="artist.user_data.is_following">Following!</span>
|
<span ng-if="artist.user_data.is_following">Following!</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -42,6 +42,7 @@ require 'script!../base/marked'
|
||||||
require 'script!../base/moment'
|
require 'script!../base/moment'
|
||||||
require '../base/soundmanager2-nodebug'
|
require '../base/soundmanager2-nodebug'
|
||||||
require 'script!../base/tumblr'
|
require 'script!../base/tumblr'
|
||||||
|
require 'color-thief';
|
||||||
require 'angular-strap'
|
require 'angular-strap'
|
||||||
# Just ignore this, blame webpack
|
# Just ignore this, blame webpack
|
||||||
require '../../../../node_modules/angular-strap/dist/angular-strap.tpl'
|
require '../../../../node_modules/angular-strap/dist/angular-strap.tpl'
|
||||||
|
|
|
@ -42,7 +42,7 @@ module.exports = angular.module('ponyfm').controller "application", [
|
||||||
notifications.markAllAsRead()
|
notifications.markAllAsRead()
|
||||||
|
|
||||||
$scope.notifActive = false
|
$scope.notifActive = false
|
||||||
|
|
||||||
$scope.notifPulloutToggle = () ->
|
$scope.notifPulloutToggle = () ->
|
||||||
$scope.notifActive = !$scope.notifActive
|
$scope.notifActive = !$scope.notifActive
|
||||||
|
|
||||||
|
@ -98,6 +98,9 @@ module.exports = angular.module('ponyfm').controller "application", [
|
||||||
$scope.notifActive = false
|
$scope.notifActive = false
|
||||||
$scope.isPinnedPlaylistSelected = false
|
$scope.isPinnedPlaylistSelected = false
|
||||||
|
|
||||||
|
if oldState.name.indexOf('content.artist.') != -1 && newState.name.indexOf('content.artist.') == -1
|
||||||
|
$('.top-bar').css('background': '')
|
||||||
|
|
||||||
if newState.name == 'content.playlist'
|
if newState.name == 'content.playlist'
|
||||||
$scope.isPinnedPlaylistSelected = playlists.isPlaylistPinned newParams.id
|
$scope.isPinnedPlaylistSelected = playlists.isPlaylistPinned newParams.id
|
||||||
|
|
||||||
|
|
|
@ -21,13 +21,144 @@ window.pfm.preloaders['artist'] = [
|
||||||
]
|
]
|
||||||
|
|
||||||
module.exports = angular.module('ponyfm').controller "artist", [
|
module.exports = angular.module('ponyfm').controller "artist", [
|
||||||
'$scope', 'artists', '$state', 'follow'
|
'$scope', 'artists', '$state', 'follow', '$rootScope'
|
||||||
($scope, artists, $state, follow) ->
|
($scope, artists, $state, follow, $rootScope) ->
|
||||||
updateArtist = (force = false) ->
|
updateArtist = (force = false) ->
|
||||||
artists.fetch($state.params.slug, force)
|
artists.fetch($state.params.slug, force)
|
||||||
.done (artistResponse) ->
|
.done (artistResponse) ->
|
||||||
$scope.artist = artistResponse.artist
|
$scope.artist = artistResponse.artist
|
||||||
|
|
||||||
|
tempImg = document.createElement('img')
|
||||||
|
tempImg.setAttribute 'src', artistResponse.artist.avatars.small
|
||||||
|
tempImg.addEventListener 'load', ->
|
||||||
|
colorThief = new ColorThief();
|
||||||
|
palette = colorThief.getPalette(tempImg, 2)
|
||||||
|
$('.top-bar').css('background': selectHeaderColour(palette[0], palette[1]))
|
||||||
|
$scope.headerStyle = {'background-image': createGradient(palette[0], palette[1])}
|
||||||
|
$scope.$apply()
|
||||||
|
|
||||||
|
rgbArrayToCss = (array) ->
|
||||||
|
'rgb(' + array[0] + ',' + array[1] + ',' + array[2] + ')'
|
||||||
|
|
||||||
|
hslArrayToCss = (array) ->
|
||||||
|
'hsl(' + array[0] + ',' + array[1] + '%,' + array[2] + '%)'
|
||||||
|
|
||||||
|
dimColor = (colour) ->
|
||||||
|
hsl = rgbToHsl(colour)
|
||||||
|
|
||||||
|
if hsl[2] >= 50
|
||||||
|
hsl[2] = 50
|
||||||
|
if hsl[1] <= 20
|
||||||
|
hsl[1] = 30
|
||||||
|
return hslToRgb(hsl)
|
||||||
|
else
|
||||||
|
return colour
|
||||||
|
|
||||||
|
createGradient = (vib, dark) ->
|
||||||
|
if $(window).width() <= 480
|
||||||
|
'linear-gradient(180deg, ' + rgbArrayToCss(vib) + ' 5%, ' + rgbArrayToCss(dimColor(dark)) + ' 95%)'
|
||||||
|
else
|
||||||
|
'linear-gradient(170deg, ' + rgbArrayToCss(vib) + ' 15%, ' + rgbArrayToCss(dark) + ' 110%)'
|
||||||
|
|
||||||
|
findHighestSaturation = (hsl1, hsl2) ->
|
||||||
|
if hsl1[1] > hsl2[1]
|
||||||
|
return hsl1
|
||||||
|
else
|
||||||
|
return hsl2
|
||||||
|
|
||||||
|
findBestColour = (hsl1, hsl2) ->
|
||||||
|
maxLumin = 60
|
||||||
|
mid = 40
|
||||||
|
best = undefined
|
||||||
|
|
||||||
|
if Math.abs(hsl1[2] - mid) < Math.abs(hsl2[2] - mid)
|
||||||
|
best = hsl1
|
||||||
|
else
|
||||||
|
best = findHighestSaturation(hsl1, hsl2)
|
||||||
|
|
||||||
|
if best[2] > maxLumin
|
||||||
|
best[2] = maxLumin
|
||||||
|
|
||||||
|
return best
|
||||||
|
|
||||||
|
|
||||||
|
selectHeaderColour = (colour1, colour2) ->
|
||||||
|
hsl1 = rgbToHsl(colour1)
|
||||||
|
hsl2 = rgbToHsl(colour2)
|
||||||
|
out = rgbArrayToCss(hslToRgb(findBestColour(hsl1, hsl2)))
|
||||||
|
return out
|
||||||
|
|
||||||
|
rgbToHsl = (rgbArr) ->
|
||||||
|
r1 = rgbArr[0] / 255
|
||||||
|
g1 = rgbArr[1] / 255
|
||||||
|
b1 = rgbArr[2] / 255
|
||||||
|
maxColor = Math.max(r1, g1, b1)
|
||||||
|
minColor = Math.min(r1, g1, b1)
|
||||||
|
L = (maxColor + minColor) / 2
|
||||||
|
S = 0
|
||||||
|
H = 0
|
||||||
|
if maxColor != minColor
|
||||||
|
if L < 0.5
|
||||||
|
S = (maxColor - minColor) / (maxColor + minColor)
|
||||||
|
else
|
||||||
|
S = (maxColor - minColor) / (2.0 - maxColor - minColor)
|
||||||
|
if r1 == maxColor
|
||||||
|
H = (g1 - b1) / (maxColor - minColor)
|
||||||
|
else if g1 == maxColor
|
||||||
|
H = 2.0 + (b1 - r1) / (maxColor - minColor)
|
||||||
|
else
|
||||||
|
H = 4.0 + (r1 - g1) / (maxColor - minColor)
|
||||||
|
L = L * 100
|
||||||
|
S = S * 100
|
||||||
|
H = H * 60
|
||||||
|
if H < 0
|
||||||
|
H += 360
|
||||||
|
|
||||||
|
round = (value, decimals) ->
|
||||||
|
Number Math.round(value + 'e' + decimals) + 'e-' + decimals
|
||||||
|
|
||||||
|
[round(H, 6), round(S, 6), round(L, 6)]
|
||||||
|
|
||||||
|
toPercent = (amount, limit) ->
|
||||||
|
amount / limit
|
||||||
|
|
||||||
|
hueToRgb = (p, q, t) ->
|
||||||
|
if t < 0
|
||||||
|
t += 1
|
||||||
|
if t > 1
|
||||||
|
t -= 1
|
||||||
|
if t < 1 / 6
|
||||||
|
return p + (q - p) * 6 * t
|
||||||
|
if t < 1 / 2
|
||||||
|
return q
|
||||||
|
if t < 2 / 3
|
||||||
|
return p + (q - p) * (2 / 3 - t) * 6
|
||||||
|
|
||||||
|
p
|
||||||
|
|
||||||
|
hslToRgb = (bits) ->
|
||||||
|
rgb = []
|
||||||
|
v = undefined
|
||||||
|
q = undefined
|
||||||
|
p = undefined
|
||||||
|
hsl =
|
||||||
|
h: toPercent(parseInt(bits[0], 10) % 360, 360)
|
||||||
|
s: toPercent(parseInt(bits[1], 10) % 101, 100)
|
||||||
|
l: toPercent(parseInt(bits[2], 10) % 101, 100)
|
||||||
|
if hsl.s == 0
|
||||||
|
v = parseInt(Math.round(255 * hsl.l))
|
||||||
|
rgb[0] = v
|
||||||
|
rgb[1] = v
|
||||||
|
rgb[2] = v
|
||||||
|
else
|
||||||
|
q = if hsl.l < 0.5 then hsl.l * (1 + hsl.s) else hsl.l + hsl.s - (hsl.l * hsl.s)
|
||||||
|
p = 2 * hsl.l - q
|
||||||
|
rgb[0] = parseInt((hueToRgb(p, q, hsl.h + 1 / 3) * 256).toFixed(0), 10)
|
||||||
|
rgb[1] = parseInt((hueToRgb(p, q, hsl.h) * 256).toFixed(0), 10)
|
||||||
|
rgb[2] = parseInt((hueToRgb(p, q, hsl.h - (1 / 3)) * 256).toFixed(0), 10)
|
||||||
|
|
||||||
|
rgb
|
||||||
|
|
||||||
$scope.toggleFollow = () ->
|
$scope.toggleFollow = () ->
|
||||||
follow.toggle('artist', $scope.artist.id).then (res) ->
|
follow.toggle('artist', $scope.artist.id).then (res) ->
|
||||||
$scope.artist.user_data.is_following = res.is_followed
|
$scope.artist.user_data.is_following = res.is_followed
|
||||||
|
|
|
@ -236,6 +236,11 @@ html body {
|
||||||
|
|
||||||
&.btn-flat {
|
&.btn-flat {
|
||||||
box-shadow: 0 0 0 transparent !important;
|
box-shadow: 0 0 0 transparent !important;
|
||||||
|
background-color: transparent;
|
||||||
|
|
||||||
|
&.btn-default:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
input.search-input {
|
input.search-input {
|
||||||
background: lighten(@pfm-logo-purple, 10%);
|
background: rgba(255,255,255,0.15);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border: 0;
|
border: 0;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
|
5
resources/assets/styles/content.less
vendored
5
resources/assets/styles/content.less
vendored
|
@ -160,9 +160,10 @@
|
||||||
|
|
||||||
&.artist-details {
|
&.artist-details {
|
||||||
> header {
|
> header {
|
||||||
padding: 15px;
|
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
|
padding: 25px;
|
||||||
|
margin: -15px -15px 10px;
|
||||||
|
|
||||||
> img {
|
> img {
|
||||||
width: 150px;
|
width: 150px;
|
||||||
|
@ -229,7 +230,7 @@
|
||||||
|
|
||||||
> header {
|
> header {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
background: #eee;
|
background: #ddd;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
|
1
resources/assets/styles/embed.less
vendored
1
resources/assets/styles/embed.less
vendored
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
@import 'https://fonts.googleapis.com/css?family=Material+Icons';
|
@import 'https://fonts.googleapis.com/css?family=Material+Icons';
|
||||||
@import 'base/bootstrap/bootstrap';
|
@import 'base/bootstrap/bootstrap';
|
||||||
@import 'base/font-awesome/font-awesome';
|
|
||||||
@import 'variables';
|
@import 'variables';
|
||||||
@import 'mixins';
|
@import 'mixins';
|
||||||
|
|
||||||
|
|
4
resources/assets/styles/layout.less
vendored
4
resources/assets/styles/layout.less
vendored
|
@ -89,7 +89,6 @@ header {
|
||||||
width: (@pfm-sidebar-size);
|
width: (@pfm-sidebar-size);
|
||||||
height: 64px;
|
height: 64px;
|
||||||
line-height: 42px;
|
line-height: 42px;
|
||||||
background: @pfm-logo-purple;
|
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 24pt;
|
font-size: 24pt;
|
||||||
font-weight: lighter;
|
font-weight: lighter;
|
||||||
|
@ -99,7 +98,7 @@ header {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: darken(@pfm-logo-purple, 15%);
|
background: rgba(0,0,0,0.3);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
@ -267,6 +266,7 @@ header {
|
||||||
height: @pfm-top-bar-size;
|
height: @pfm-top-bar-size;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
transition: background 0.5s @swift-ease-in-out;
|
||||||
.material-shadow(1);
|
.material-shadow(1);
|
||||||
|
|
||||||
.burger-wrapper {
|
.burger-wrapper {
|
||||||
|
|
4
resources/assets/styles/mobile.less
vendored
4
resources/assets/styles/mobile.less
vendored
|
@ -216,8 +216,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
> header {
|
> header {
|
||||||
margin-bottom: 0px;
|
margin: 0 !important;
|
||||||
padding-bottom: 40px !important;
|
padding: 20px 0 40px !important;
|
||||||
|
|
||||||
> img {
|
> img {
|
||||||
float: none !important;
|
float: none !important;
|
||||||
|
|
|
@ -13,7 +13,8 @@ module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.ProvidePlugin({
|
new webpack.ProvidePlugin({
|
||||||
$: "jquery",
|
$: "jquery",
|
||||||
jQuery: "jquery"
|
jQuery: "jquery",
|
||||||
|
ColorThief: "color-thief"
|
||||||
}),
|
}),
|
||||||
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
|
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in a new issue