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
end
# Group the items by category!
@nc_mall_items = @items.select(&:currently_in_mall?)
@other_nc_items = @items.select(&:nc?).reject(&:currently_in_mall?)
@np_items = @items.select(&:np?)
@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).
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"
end

View file

@ -2,23 +2,34 @@ require "addressable/template"
module ItemsHelper
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 = {
:happy => 1,
:sad => 2,
:angry => 3,
:ill => 4
happy: 1,
sad: 2,
angry: 3,
ill: 4,
}
Sizes = {
:face => 1,
:thumb => 2,
:zoom => 3,
:full => 4
face: 1,
thumb: 2,
zoom: 3,
full: 4,
face_2x: 6,
}
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
build_on_pet_types(Species.alphabetical) do |pet_type|
image = pet_type_image(pet_type, :happy, :zoom)
@ -157,9 +168,7 @@ module ItemsHelper
end
def pet_type_image(pet_type, emotion, size)
emotion_id = PetTypeImage::Emotions[emotion]
size_id = PetTypeImage::Sizes[size]
src = sprintf(PetTypeImage::Format, pet_type.basic_image_hash, emotion_id, size_id)
src = pet_type_image_url(pet_type, emotion:, size:)
human_name = pet_type.species.name.humanize
image_tag(src, :alt => human_name, :title => human_name)
end

View file

@ -21,6 +21,11 @@ class Color < ApplicationRecord
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
if name
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/, "")) }
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
pb_color&.pb_item_name
end

View file

@ -67,6 +67,10 @@
- if color.pb_item_thumbnail_url?
= image_tag color.pb_item_thumbnail_url,
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
#{color.pb_item_name || color.name.humanize}
(#{pluralize items.size, "item"})