Use a pet face when there's no paint brush, in Item Getting Guide

Now, for colors like Mutant or Magma where there's no paint brush
image to show, we use a sample pet image instead, to help it have equal
visual weight and clarity as the cases with the paint brushes.

We do some cleverness in here to make sure to always show the relevant
species, if possible!
This commit is contained in:
Emi Matchu 2024-05-22 17:53:52 -07:00
parent 4e11ee4da7
commit d34bebc336
5 changed files with 53 additions and 12 deletions

View file

@ -122,13 +122,28 @@ class ItemsController < ApplicationController
return return
end end
# Group the items by category!
@nc_mall_items = @items.select(&:currently_in_mall?) @nc_mall_items = @items.select(&:currently_in_mall?)
@other_nc_items = @items.select(&:nc?).reject(&:currently_in_mall?) @other_nc_items = @items.select(&:nc?).reject(&:currently_in_mall?)
@np_items = @items.select(&:np?) @np_items = @items.select(&:np?)
@pb_items = @items.select(&:pb?) @pb_items = @items.select(&:pb?)
# Also, PB items have some special handling: we group them by color, then
# load example pet types for the colors that don't have paint brushes.
@pb_items_by_color = @pb_items.group_by(&:pb_color). @pb_items_by_color = @pb_items.group_by(&:pb_color).
sort_by { |color, items| color.name }.to_h sort_by { |color, items| color.name }.to_h
colors_without_thumbnails =
@pb_items_by_color.keys.reject(&:pb_item_thumbnail_url?)
@pb_color_pet_types = colors_without_thumbnails.map do |color|
# Infer the ideal species from the first item we can, then try to find a
# matching pet type to use as the thumbnail, if needed.
species = @pb_items_by_color[color].map(&:pb_species).select(&:present?)
.first
[color, color.example_pet_type(preferred_species: species)]
end.to_h
render layout: "application" render layout: "application"
end end

View file

@ -2,23 +2,34 @@ require "addressable/template"
module ItemsHelper module ItemsHelper
module PetTypeImage module PetTypeImage
Format = 'https://pets.neopets.com/cp/%s/%i/%i.png' Template = Addressable::Template.new(
"https://pets.neopets.com/cp/{hash}/{emotion}/{size}.png"
)
Emotions = { Emotions = {
:happy => 1, happy: 1,
:sad => 2, sad: 2,
:angry => 3, angry: 3,
:ill => 4 ill: 4,
} }
Sizes = { Sizes = {
:face => 1, face: 1,
:thumb => 2, thumb: 2,
:zoom => 3, zoom: 3,
:full => 4 full: 4,
face_2x: 6,
} }
end end
def pet_type_image_url(pet_type, emotion: :happy, size: :face)
PetTypeImage::Template.expand(
hash: pet_type.basic_image_hash || pet_type.image_hash,
emotion: PetTypeImage::Emotions[emotion],
size: PetTypeImage::Sizes[size],
).to_s
end
def standard_species_search_links def standard_species_search_links
build_on_pet_types(Species.alphabetical) do |pet_type| build_on_pet_types(Species.alphabetical) do |pet_type|
image = pet_type_image(pet_type, :happy, :zoom) image = pet_type_image(pet_type, :happy, :zoom)
@ -157,9 +168,7 @@ module ItemsHelper
end end
def pet_type_image(pet_type, emotion, size) def pet_type_image(pet_type, emotion, size)
emotion_id = PetTypeImage::Emotions[emotion] src = pet_type_image_url(pet_type, emotion:, size:)
size_id = PetTypeImage::Sizes[size]
src = sprintf(PetTypeImage::Format, pet_type.basic_image_hash, emotion_id, size_id)
human_name = pet_type.species.name.humanize human_name = pet_type.species.name.humanize
image_tag(src, :alt => human_name, :title => human_name) image_tag(src, :alt => human_name, :title => human_name)
end end

View file

@ -21,6 +21,11 @@ class Color < ApplicationRecord
end end
end end
def example_pet_type(preferred_species: Species.first)
pet_types.order([Arel.sql("species_id = ? DESC"), preferred_species.id],
"species_id ASC").first
end
def unfunny_human_name def unfunny_human_name
if name if name
name.split(' ').map { |word| word.capitalize }.join(' ') name.split(' ').map { |word| word.capitalize }.join(' ')

View file

@ -197,6 +197,14 @@ class Item < ApplicationRecord
find { |c| normalized_name.include?(c.name.downcase.gsub(/\s/, "")) } find { |c| normalized_name.include?(c.name.downcase.gsub(/\s/, "")) }
end end
# If this is a PB item, return the corresponding Species, inferred from the
# item name. If it's not a PB item, or we fail to infer, return nil.
def pb_species
return nil unless pb?
normalized_name = name.downcase
Species.order(:name).find { |s| normalized_name.include?(s.name.downcase) }
end
def pb_item_name def pb_item_name
pb_color&.pb_item_name pb_color&.pb_item_name
end end

View file

@ -67,6 +67,10 @@
- if color.pb_item_thumbnail_url? - if color.pb_item_thumbnail_url?
= image_tag color.pb_item_thumbnail_url, = image_tag color.pb_item_thumbnail_url,
alt: "Item thumbnail for #{color.pb_item_name}" alt: "Item thumbnail for #{color.pb_item_name}"
- else
= image_tag pet_type_image_url(@pb_color_pet_types[color], size: :face),
srcset: ["#{pet_type_image_url(@pb_color_pet_types[color], size: :face_2x)} 2x"],
alt: @pb_color_pet_types[color].human_name
%th %th
#{color.pb_item_name || color.name.humanize} #{color.pb_item_name || color.name.humanize}
(#{pluralize items.size, "item"}) (#{pluralize items.size, "item"})