diff --git a/app/assets/stylesheets/components/_action_bar.scss b/app/assets/stylesheets/components/_action_bar.scss index 8ab99e05..bb2950c5 100644 --- a/app/assets/stylesheets/components/_action_bar.scss +++ b/app/assets/stylesheets/components/_action_bar.scss @@ -1,7 +1,7 @@ @use "../tools/functions" as *; .c-action-bar { - padding: spacing("narrow"); + padding: spacing("tiny") spacing("narrow"); border-radius: border-radius("medium"); background: var(--action-bar-bg-color); } diff --git a/app/assets/stylesheets/components/_button.scss b/app/assets/stylesheets/components/_button.scss index 0f061a45..01a441a4 100644 --- a/app/assets/stylesheets/components/_button.scss +++ b/app/assets/stylesheets/components/_button.scss @@ -8,6 +8,10 @@ padding: spacing("tiny") spacing("narrow"); cursor: pointer; font-size: font-size("medium"); + + &:hover { + text-decoration: none; + } } .c-button--primary { diff --git a/app/assets/stylesheets/components/_list.scss b/app/assets/stylesheets/components/_list.scss index c4b386ce..19f3227f 100644 --- a/app/assets/stylesheets/components/_list.scss +++ b/app/assets/stylesheets/components/_list.scss @@ -25,6 +25,12 @@ text-transform: uppercase; } +.c-list__item__subtext { + display: inline-block; + margin-top: spacing("tiny"); + color: var(--list-subtext-color); +} + .c-list--border-none .c-list__item { border-bottom: none; } diff --git a/app/assets/stylesheets/elements/_content.scss b/app/assets/stylesheets/elements/_content.scss index d6cd65ed..72d63ea9 100644 --- a/app/assets/stylesheets/elements/_content.scss +++ b/app/assets/stylesheets/elements/_content.scss @@ -37,7 +37,7 @@ a { } a:hover { - color: var(--link-active-color); + text-decoration: underline; } a.is-active { diff --git a/app/assets/stylesheets/settings/_dark_theme.scss b/app/assets/stylesheets/settings/_dark_theme.scss index ae0c85e6..dc157258 100644 --- a/app/assets/stylesheets/settings/_dark_theme.scss +++ b/app/assets/stylesheets/settings/_dark_theme.scss @@ -54,6 +54,7 @@ --list-border-color: #{$grey-800}; --list-active-color: #{$primary-color}; --list-grouped-bg-color: #{$grey-900}; + --list-subtext-color: #{$grey-400}; /* Table */ --table-border-color: #{$grey-900}; diff --git a/app/assets/stylesheets/settings/_light_theme.scss b/app/assets/stylesheets/settings/_light_theme.scss index 37263f2e..0e30a2bc 100644 --- a/app/assets/stylesheets/settings/_light_theme.scss +++ b/app/assets/stylesheets/settings/_light_theme.scss @@ -54,6 +54,7 @@ --list-border-color: #{$grey-200}; --list-active-color: #{$primary-color}; --list-grouped-bg-color: #{$grey-100}; + --list-subtext-color: #{$grey-500}; /* Table */ --table-border-color: #{$grey-200}; diff --git a/app/helpers/song_helper.rb b/app/helpers/song_helper.rb index 775b3ac4..83826634 100644 --- a/app/helpers/song_helper.rb +++ b/app/helpers/song_helper.rb @@ -8,8 +8,8 @@ def song_json_builder(song, for_api: false) Jbuilder.new do |json| json.call(song, :id, :name, :duration) json.url need_transcode?(song) ? transcoded_stream_url : stream_url - json.album_name song.album.title - json.artist_name song.artist.title + json.album_name song.album.name + json.artist_name song.artist.name json.is_favorited song.is_favorited.nil? ? Current.user.favorited?(song) : song.is_favorited json.format need_transcode?(song) ? Stream::TRANSCODE_FORMAT : song.format json.album_image_url do diff --git a/app/javascript/controllers/mixins/event_handler.js b/app/javascript/controllers/mixins/event_handler.js index e3205889..0cacf2f4 100644 --- a/app/javascript/controllers/mixins/event_handler.js +++ b/app/javascript/controllers/mixins/event_handler.js @@ -22,6 +22,8 @@ class EventHandler { const handler = { listener (event) { if (targetMatching) { + if (event.target.dataset.preventDelegation) { return } + const target = event.target.closest(targetMatching) if (!target) { return } } diff --git a/app/models/album.rb b/app/models/album.rb index 139b4596..4dcc7108 100644 --- a/app/models/album.rb +++ b/app/models/album.rb @@ -1,11 +1,16 @@ # frozen_string_literal: true class Album < ApplicationRecord + UNKNOWN_NAME = "Unknown Album" + include SearchableConcern include ImageableConcern include FilterableConcern include SortableConcern + after_initialize :set_default_name, if: :new_record? + + validates :name, presence: true validates :name, uniqueness: {scope: :artist} has_many :songs, -> { order(:discnum, :tracknum) }, inverse_of: :album, dependent: :destroy @@ -18,11 +23,13 @@ class Album < ApplicationRecord sort_by :name, :year, :created_at sort_by_associations artist: :name - def title - is_unknown? ? I18n.t("label.unknown_album") : name + def unknown? + name == UNKNOWN_NAME end - def is_unknown? - name.blank? + private + + def set_default_name + self.name ||= UNKNOWN_NAME end end diff --git a/app/models/artist.rb b/app/models/artist.rb index a049a087..51d0cfa4 100644 --- a/app/models/artist.rb +++ b/app/models/artist.rb @@ -1,10 +1,17 @@ # frozen_string_literal: true class Artist < ApplicationRecord + UNKNOWN_NAME = "Unknown Artist" + VARIOUS_NAME = "Various Artists" + include SearchableConcern include ImageableConcern include SortableConcern + after_initialize :set_default_name, if: :new_record? + + validates :name, presence: true + has_many :albums, dependent: :destroy has_many :songs @@ -12,15 +19,8 @@ class Artist < ApplicationRecord sort_by :name, :created_at - def title - return I18n.t("label.various_artists") if is_various? - return I18n.t("label.unknown_artist") if is_unknown? - - name - end - - def is_unknown? - name.blank? + def unknown? + name == UNKNOWN_NAME end def all_albums @@ -30,4 +30,10 @@ def all_albums def appears_on_albums Album.joins(:songs).where("albums.artist_id != ? AND songs.artist_id = ?", id, id).distinct end + + private + + def set_default_name + self.name ||= various? ? VARIOUS_NAME : UNKNOWN_NAME + end end diff --git a/app/models/concerns/imageable_concern.rb b/app/models/concerns/imageable_concern.rb index 97e9ddbc..f33e9d92 100644 --- a/app/models/concerns/imageable_concern.rb +++ b/app/models/concerns/imageable_concern.rb @@ -16,6 +16,6 @@ def attach_image_from_discogs private def needs_image_from_discogs? - Setting.discogs_token.present? && !has_image? && !is_unknown? + Setting.discogs_token.present? && !has_image? && !unknown? end end diff --git a/app/models/media.rb b/app/models/media.rb index e690faee..0137b80a 100644 --- a/app/models/media.rb +++ b/app/models/media.rb @@ -61,14 +61,13 @@ def remove_files(file_paths) end def attach(file_info) - artist = Artist.find_or_create_by!(name: file_info[:artist_name]) + artist = Artist.find_or_create_by!(name: file_info[:artist_name] || Artist::UNKNOWN_NAME) + various_artist = Artist.find_or_create_by!(various: true) if various_artist?(file_info) - album = if various_artist?(file_info) - various_artist = Artist.find_or_create_by!(is_various: true) - Album.find_or_initialize_by(artist: various_artist, name: file_info[:album_name]) - else - Album.find_or_initialize_by(artist: artist, name: file_info[:album_name]) - end + album = Album.find_or_initialize_by( + artist: various_artist || artist, + name: file_info[:album_name] || Album::UNKNOWN_NAME + ) album.update!(album_info(file_info)) album.update!(image: file_info[:image]) unless album.has_image? diff --git a/app/views/albums/_album.html.erb b/app/views/albums/_album.html.erb index 357a25e0..ddbf5503 100644 --- a/app/views/albums/_album.html.erb +++ b/app/views/albums/_album.html.erb @@ -3,7 +3,7 @@ <%= image_tag image_url_for(album), class: "u-image-fluid" %> <% end %>
<%= link_to album.title, album_path(album) %>
-<%= album.artist.title %>
+<%= link_to album.name, album_path(album) %>
+<%= album.artist.name %>
<%= @album.artist.title %>
+<%= @album.artist.name %>
<%= link_to album.title, album_path(album) %>
+<%= link_to album.name, album_path(album) %>
<%= link_to artist.title, artist_path(artist) %>
+<%= link_to artist.name, artist_path(artist) %>