This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "furumusic"
|
name = "furumusic"
|
||||||
version = "0.2.15"
|
version = "0.3.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
description = "Reusable web-app boilerplate: auth, OIDC/SSO, admin panel, user management, i18n, PostgreSQL"
|
description = "Reusable web-app boilerplate: auth, OIDC/SSO, admin panel, user management, i18n, PostgreSQL"
|
||||||
|
|
||||||
|
|||||||
@@ -273,6 +273,7 @@ translations! {
|
|||||||
player_library: "Library" , "Библиотека";
|
player_library: "Library" , "Библиотека";
|
||||||
player_artists: "Artists" , "Артисты";
|
player_artists: "Artists" , "Артисты";
|
||||||
player_global_library: "Global" , "Global";
|
player_global_library: "Global" , "Global";
|
||||||
|
player_featured_only_artists: "Featured only" , "Только фиты";
|
||||||
player_release: "Release" , "Релиз";
|
player_release: "Release" , "Релиз";
|
||||||
player_releases: "Releases" , "Релизы";
|
player_releases: "Releases" , "Релизы";
|
||||||
player_tracks: "Tracks" , "Треки";
|
player_tracks: "Tracks" , "Треки";
|
||||||
|
|||||||
@@ -2048,6 +2048,17 @@ document.addEventListener('alpine:init', () => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isFeaturedOnlyArtist(artist) {
|
||||||
|
return Number(artist?.release_count || 0) <= 0 && Number(artist?.track_count || 0) > 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
shouldShowFeaturedSeparator(index) {
|
||||||
|
if (!(this.view === 'artists' || this.view === 'my_uploads') || index <= 0) return false;
|
||||||
|
const current = this.artists[index];
|
||||||
|
const previous = this.artists[index - 1];
|
||||||
|
return this.isFeaturedOnlyArtist(current) && !this.isFeaturedOnlyArtist(previous);
|
||||||
|
},
|
||||||
|
|
||||||
async openArtist(id, options = {}) {
|
async openArtist(id, options = {}) {
|
||||||
this._beginNavigation('#artist/' + id, options);
|
this._beginNavigation('#artist/' + id, options);
|
||||||
this.searchQuery = '';
|
this.searchQuery = '';
|
||||||
|
|||||||
+29
-22
@@ -523,29 +523,36 @@
|
|||||||
<div>
|
<div>
|
||||||
<h1 class="section-title" x-text="$store.library.view === 'my_uploads' ? '{{ t.player_my_uploads }}' : '{{ t.player_global_library }}'"></h1>
|
<h1 class="section-title" x-text="$store.library.view === 'my_uploads' ? '{{ t.player_my_uploads }}' : '{{ t.player_global_library }}'"></h1>
|
||||||
<div class="card-grid">
|
<div class="card-grid">
|
||||||
<template x-for="artist in $store.library.artists" :key="artist.id">
|
<template x-for="(artist, idx) in $store.library.artists" :key="artist.id">
|
||||||
<div class="card" @click="$store.library.openArtist(artist.id)">
|
<div class="artist-grid-entry">
|
||||||
<div class="card-img">
|
<div class="artist-section-divider"
|
||||||
<template x-if="artist.image_url">
|
x-show="$store.library.shouldShowFeaturedSeparator(idx)"
|
||||||
<img :src="artist.image_url" :alt="artist.name" loading="lazy">
|
x-cloak>
|
||||||
</template>
|
<span>{{ t.player_featured_only_artists }}</span>
|
||||||
<template x-if="!artist.image_url">
|
</div>
|
||||||
<span class="placeholder-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="8" r="4"/><path d="M20 21a8 8 0 10-16 0"/></svg></span>
|
<div class="card" @click="$store.library.openArtist(artist.id)">
|
||||||
</template>
|
<div class="card-img">
|
||||||
<button class="artist-follow-card-btn"
|
<template x-if="artist.image_url">
|
||||||
:class="{ followed: $store.follows.has(artist.id) }"
|
<img :src="artist.image_url" :alt="artist.name" loading="lazy">
|
||||||
@click.stop="$store.follows.toggle(artist.id)"
|
</template>
|
||||||
:title="$store.follows.has(artist.id) ? '{{ t.player_unfollow_artist }}' : '{{ t.player_follow_artist }}'">
|
<template x-if="!artist.image_url">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<span class="placeholder-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="8" r="4"/><path d="M20 21a8 8 0 10-16 0"/></svg></span>
|
||||||
<path d="M16 21v-2a4 4 0 00-4-4H6a4 4 0 00-4 4v2"/>
|
</template>
|
||||||
<circle cx="9" cy="7" r="4"/>
|
<button class="artist-follow-card-btn"
|
||||||
<path x-show="!$store.follows.has(artist.id)" d="M19 8v6M16 11h6"/>
|
:class="{ followed: $store.follows.has(artist.id) }"
|
||||||
<path x-show="$store.follows.has(artist.id)" d="M16 11l2 2 4-5"/>
|
@click.stop="$store.follows.toggle(artist.id)"
|
||||||
</svg>
|
:title="$store.follows.has(artist.id) ? '{{ t.player_unfollow_artist }}' : '{{ t.player_follow_artist }}'">
|
||||||
</button>
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M16 21v-2a4 4 0 00-4-4H6a4 4 0 00-4 4v2"/>
|
||||||
|
<circle cx="9" cy="7" r="4"/>
|
||||||
|
<path x-show="!$store.follows.has(artist.id)" d="M19 8v6M16 11h6"/>
|
||||||
|
<path x-show="$store.follows.has(artist.id)" d="M16 11l2 2 4-5"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="card-title" x-text="artist.name"></div>
|
||||||
|
<div class="card-subtitle" x-text="artist.release_count + ' {{ t.player_releases_count }} · ' + artist.track_count + ' {{ t.player_tracks_count }}'"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-title" x-text="artist.name"></div>
|
|
||||||
<div class="card-subtitle" x-text="artist.release_count + ' {{ t.player_releases_count }} · ' + artist.track_count + ' {{ t.player_tracks_count }}'"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -513,6 +513,31 @@ button.user-stat:hover {
|
|||||||
gap: 20px;
|
gap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.artist-grid-entry {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
.artist-section-divider {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
min-height: 28px;
|
||||||
|
margin: 2px 0 -2px;
|
||||||
|
color: var(--text-subdued);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.artist-section-divider::before,
|
||||||
|
.artist-section-divider::after {
|
||||||
|
content: "";
|
||||||
|
flex: 1;
|
||||||
|
height: 1px;
|
||||||
|
background: var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
|||||||
Reference in New Issue
Block a user