mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-04 20:43:04 +00:00
move album header color methods to composables
This commit is contained in:
+1
-16
@@ -37,17 +37,13 @@ import Tabs from "@/components/RightSideBar/Tabs.vue";
|
|||||||
import useContextStore from "@/stores/context";
|
import useContextStore from "@/stores/context";
|
||||||
import useQStore from "@/stores/queue";
|
import useQStore from "@/stores/queue";
|
||||||
|
|
||||||
import { isSameRoute } from "@/composables/perks";
|
|
||||||
import useShortcuts from "@/composables/useKeyboard";
|
import useShortcuts from "@/composables/useKeyboard";
|
||||||
|
|
||||||
const context_store = useContextStore();
|
const context_store = useContextStore();
|
||||||
const queue = useQStore();
|
const queue = useQStore();
|
||||||
const app_dom = document.getElementById("app");
|
const app_dom = document.getElementById("app");
|
||||||
const route = useRoute();
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
// function to add the
|
|
||||||
|
|
||||||
queue.readQueue();
|
queue.readQueue();
|
||||||
useShortcuts(useQStore);
|
useShortcuts(useQStore);
|
||||||
|
|
||||||
@@ -57,18 +53,7 @@ app_dom.addEventListener("click", (e) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function removeHighlight(route: RouteLocationNormalized) {
|
router.afterEach(() => {
|
||||||
setTimeout(() => {
|
|
||||||
router.push({ name: route.name, params: route.params });
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
router.afterEach((to, from) => {
|
|
||||||
const h_hash = to.query.highlight as string;
|
|
||||||
|
|
||||||
if (h_hash) removeHighlight(to);
|
|
||||||
if (isSameRoute(to, from)) return;
|
|
||||||
|
|
||||||
document.getElementById("acontent")?.scrollTo(0, 0);
|
document.getElementById("acontent")?.scrollTo(0, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -9,13 +9,9 @@
|
|||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<div class="art rounded">
|
<div class="art rounded">
|
||||||
<img
|
<img :src="imguri + album.image" alt="" class="rounded shadow-lg" />
|
||||||
:src="imguri + album.image"
|
|
||||||
alt=""
|
|
||||||
class="rounded shadow-lg"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="info" :class="{ nocontrast: isLight() }">
|
<div class="info" :class="{ nocontrast: isLight(album.colors[0]) }">
|
||||||
<div class="top">
|
<div class="top">
|
||||||
<div class="h">
|
<div class="h">
|
||||||
<span v-if="album.is_soundtrack">Soundtrack</span>
|
<span v-if="album.is_soundtrack">Soundtrack</span>
|
||||||
@@ -36,7 +32,7 @@
|
|||||||
<PlayBtnRect
|
<PlayBtnRect
|
||||||
:source="playSources.album"
|
:source="playSources.album"
|
||||||
:store="useAlbumStore"
|
:store="useAlbumStore"
|
||||||
:background="getButtonColor()"
|
:background="getButtonColor(album.colors)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -53,6 +49,7 @@ import { formatSeconds } from "../../composables/perks";
|
|||||||
import { paths } from "@/config";
|
import { paths } from "@/config";
|
||||||
import { AlbumInfo } from "../../interfaces";
|
import { AlbumInfo } from "../../interfaces";
|
||||||
import PlayBtnRect from "../shared/PlayBtnRect.vue";
|
import PlayBtnRect from "../shared/PlayBtnRect.vue";
|
||||||
|
import { getButtonColor, isLight } from "../../composables/colors/album";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
album: AlbumInfo;
|
album: AlbumInfo;
|
||||||
@@ -81,96 +78,6 @@ function handleVisibilityState(state: boolean) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useVisibility(albumheaderthing, handleVisibilityState);
|
useVisibility(albumheaderthing, handleVisibilityState);
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns `true` if the rgb color passed is light.
|
|
||||||
*
|
|
||||||
* @param {string} rgb The color to check whether it's light or dark.
|
|
||||||
* @returns {boolean} true if color is light, false if color is dark.
|
|
||||||
*/
|
|
||||||
function isLight(rgb: string = props.album.colors[0]): boolean {
|
|
||||||
if (rgb == null || undefined) return false;
|
|
||||||
|
|
||||||
const [r, g, b] = rgb.match(/\d+/g)!.map(Number);
|
|
||||||
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
|
|
||||||
|
|
||||||
return brightness > 170;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface BtnColor {
|
|
||||||
color: string;
|
|
||||||
isDark: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the first contrasting color in the album colors.
|
|
||||||
*
|
|
||||||
* @param {string[]} colors The album colors to choose from.
|
|
||||||
* @returns {BtnColor} A color to use as the play button background
|
|
||||||
*/
|
|
||||||
function getButtonColor(colors: string[] = props.album.colors): BtnColor {
|
|
||||||
const base_color = colors[0];
|
|
||||||
if (colors.length === 0) return { color: "#fff", isDark: true };
|
|
||||||
|
|
||||||
for (let i = 0; i < colors.length; i++) {
|
|
||||||
if (theyContrast(base_color, colors[i])) {
|
|
||||||
return {
|
|
||||||
color: colors[i],
|
|
||||||
isDark: isLight(colors[i]),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
color: "#fff",
|
|
||||||
isDark: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the luminance of a color.
|
|
||||||
* @param r The red value of the color.
|
|
||||||
* @param g The green value of the color.
|
|
||||||
* @param b The blue value of the color.
|
|
||||||
*/
|
|
||||||
function luminance(r: any, g: any, b: any) {
|
|
||||||
let a = [r, g, b].map(function (v) {
|
|
||||||
v /= 255;
|
|
||||||
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
||||||
});
|
|
||||||
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a contrast ratio of `color1`:`color2`
|
|
||||||
* @param {string} color1 The first color
|
|
||||||
* @param {string} color2 The second color
|
|
||||||
*/
|
|
||||||
function contrast(color1: number[], color2: number[]): number {
|
|
||||||
let lum1 = luminance(color1[0], color1[1], color1[2]);
|
|
||||||
let lum2 = luminance(color2[0], color2[1], color2[2]);
|
|
||||||
let brightest = Math.max(lum1, lum2);
|
|
||||||
let darkest = Math.min(lum1, lum2);
|
|
||||||
return (brightest + 0.05) / (darkest + 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a rgb color string to an array of the form: `[r, g, b]`
|
|
||||||
* @param rgb The color to convert
|
|
||||||
* @returns {number[]} The array representation of the color
|
|
||||||
*/
|
|
||||||
function rgbToArray(rgb: string): number[] {
|
|
||||||
return rgb.match(/\d+/g)!.map(Number);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the `color2` contrast with `color1`.
|
|
||||||
* @param color1 The first color
|
|
||||||
* @param color2 The second color
|
|
||||||
*/
|
|
||||||
function theyContrast(color1: string, color2: string) {
|
|
||||||
return contrast(rgbToArray(color1), rgbToArray(color2)) > 3;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="folder">
|
<div class="folder">
|
||||||
<div class="table rounded" v-if="tracks.length">
|
<div class="table rounded" v-if="tracks.length">
|
||||||
<div class="header" v-if="disc">
|
<div class="header" v-if="disc && !album.info.is_single">
|
||||||
<div class="disc-number">Disc {{ disc }}</div>
|
<div class="disc-number">Disc {{ disc }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="songlist">
|
<div class="songlist">
|
||||||
@@ -37,6 +37,7 @@ import useQStore from "@/stores/queue";
|
|||||||
import useAlbumStore from "@/stores/pages/album";
|
import useAlbumStore from "@/stores/pages/album";
|
||||||
|
|
||||||
const queue = useQStore();
|
const queue = useQStore();
|
||||||
|
const album = useAlbumStore();
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
tracks: Track[];
|
tracks: Track[];
|
||||||
@@ -91,7 +92,6 @@ function updateQueue(track: Track) {
|
|||||||
queue.play(index);
|
queue.play(index);
|
||||||
break;
|
break;
|
||||||
case "AlbumView":
|
case "AlbumView":
|
||||||
const album = useAlbumStore();
|
|
||||||
const tindex = album.tracks.findIndex((t) => t.trackid === track.trackid);
|
const tindex = album.tracks.findIndex((t) => t.trackid === track.trackid);
|
||||||
|
|
||||||
queue.playFromAlbum(
|
queue.playFromAlbum(
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
/**
|
||||||
|
* Returns `true` if the rgb color passed is light.
|
||||||
|
*
|
||||||
|
* @param {string} rgb The color to check whether it's light or dark.
|
||||||
|
* @returns {boolean} true if color is light, false if color is dark.
|
||||||
|
*/
|
||||||
|
export function isLight(rgb: string): boolean {
|
||||||
|
if (rgb == null || undefined) return false;
|
||||||
|
|
||||||
|
const [r, g, b] = rgb.match(/\d+/g)!.map(Number);
|
||||||
|
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
|
||||||
|
|
||||||
|
return brightness > 170;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BtnColor {
|
||||||
|
color: string;
|
||||||
|
isDark: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first contrasting color in the album colors.
|
||||||
|
*
|
||||||
|
* @param {string[]} colors The album colors to choose from.
|
||||||
|
* @returns {BtnColor} A color to use as the play button background
|
||||||
|
*/
|
||||||
|
export function getButtonColor(colors: string[]): BtnColor {
|
||||||
|
const base_color = colors[0];
|
||||||
|
if (colors.length === 0) return { color: "#fff", isDark: true };
|
||||||
|
|
||||||
|
for (let i = 0; i < colors.length; i++) {
|
||||||
|
if (theyContrast(base_color, colors[i])) {
|
||||||
|
return {
|
||||||
|
color: colors[i],
|
||||||
|
isDark: isLight(colors[i]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
color: "#fff",
|
||||||
|
isDark: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the luminance of a color.
|
||||||
|
* @param r The red value of the color.
|
||||||
|
* @param g The green value of the color.
|
||||||
|
* @param b The blue value of the color.
|
||||||
|
*/
|
||||||
|
export function luminance(r: any, g: any, b: any) {
|
||||||
|
let a = [r, g, b].map(function (v) {
|
||||||
|
v /= 255;
|
||||||
|
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
||||||
|
});
|
||||||
|
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a contrast ratio of `color1`:`color2`
|
||||||
|
* @param {string} color1 The first color
|
||||||
|
* @param {string} color2 The second color
|
||||||
|
*/
|
||||||
|
export function contrast(color1: number[], color2: number[]): number {
|
||||||
|
let lum1 = luminance(color1[0], color1[1], color1[2]);
|
||||||
|
let lum2 = luminance(color2[0], color2[1], color2[2]);
|
||||||
|
let brightest = Math.max(lum1, lum2);
|
||||||
|
let darkest = Math.min(lum1, lum2);
|
||||||
|
return (brightest + 0.05) / (darkest + 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a rgb color string to an array of the form: `[r, g, b]`
|
||||||
|
* @param rgb The color to convert
|
||||||
|
* @returns {number[]} The array representation of the color
|
||||||
|
*/
|
||||||
|
export function rgbToArray(rgb: string): number[] {
|
||||||
|
return rgb.match(/\d+/g)!.map(Number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the `color2` contrast with `color1`.
|
||||||
|
* @param color1 The first color
|
||||||
|
* @param color2 The second color
|
||||||
|
*/
|
||||||
|
export function theyContrast(color1: string, color2: string) {
|
||||||
|
return contrast(rgbToArray(color1), rgbToArray(color2)) > 3;
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import state from "../state";
|
import state from "../state";
|
||||||
import { AlbumInfo, Track } from "../../interfaces";
|
import { AlbumInfo, Track } from "../../interfaces";
|
||||||
import useAxios from "../useAxios";
|
import useAxios from "./useAxios";
|
||||||
import { NotifType, useNotifStore } from "@/stores/notification";
|
import { NotifType, useNotifStore } from "@/stores/notification";
|
||||||
|
|
||||||
const getAlbumData = async (hash: string, ToastStore: typeof useNotifStore) => {
|
const getAlbumData = async (hash: string, ToastStore: typeof useNotifStore) => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Folder, Track } from "@/interfaces";
|
import { Folder, Track } from "@/interfaces";
|
||||||
import state from "../state";
|
import state from "../state";
|
||||||
import useAxios from "../useAxios";
|
import useAxios from "./useAxios";
|
||||||
|
|
||||||
export default async function (path: string) {
|
export default async function (path: string) {
|
||||||
interface FolderData {
|
interface FolderData {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Artist } from "../../interfaces";
|
|||||||
import { Playlist, Track } from "../../interfaces";
|
import { Playlist, Track } from "../../interfaces";
|
||||||
import { Notification, NotifType } from "../../stores/notification";
|
import { Notification, NotifType } from "../../stores/notification";
|
||||||
import state from "../state";
|
import state from "../state";
|
||||||
import useAxios from "../useAxios";
|
import useAxios from "./useAxios";
|
||||||
/**
|
/**
|
||||||
* Creates a new playlist on the server.
|
* Creates a new playlist on the server.
|
||||||
* @param playlist_name The name of the playlist to create.
|
* @param playlist_name The name of the playlist to create.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { FetchProps } from "../interfaces";
|
import { FetchProps } from "../../interfaces";
|
||||||
import axios, { AxiosError, AxiosResponse } from "axios";
|
import axios, { AxiosError, AxiosResponse } from "axios";
|
||||||
|
|
||||||
export default async (args: FetchProps) => {
|
export default async (args: FetchProps) => {
|
||||||
Reference in New Issue
Block a user