Compare commits
No commits in common. "d34bebc336e5bccc5ddc53bc855ccc7ddfdbeffa" and "ecde507b60770c9233e0ece322641f85fc0f1e3e" have entirely different histories.
d34bebc336
...
ecde507b60
10 changed files with 28 additions and 162 deletions
|
@ -4,9 +4,6 @@
|
||||||
.item-list
|
.item-list
|
||||||
border-collapse: collapse
|
border-collapse: collapse
|
||||||
border: 1px solid $soft-border-color
|
border: 1px solid $soft-border-color
|
||||||
width: 60%
|
|
||||||
table-layout: auto
|
|
||||||
margin-bottom: 2em
|
|
||||||
|
|
||||||
td, th
|
td, th
|
||||||
border-top: 1px solid $soft-border-color
|
border-top: 1px solid $soft-border-color
|
||||||
|
@ -20,29 +17,20 @@
|
||||||
&:last-child
|
&:last-child
|
||||||
padding-right: .5em
|
padding-right: .5em
|
||||||
|
|
||||||
.thumbnail-cell
|
.thumbnail-cell img
|
||||||
|
display: block
|
||||||
width: 2.5em
|
width: 2.5em
|
||||||
height: 2.5em
|
height: 2.5em
|
||||||
|
|
||||||
img
|
|
||||||
display: block
|
|
||||||
width: 100%
|
|
||||||
height: 100%
|
|
||||||
|
|
||||||
.name-cell a
|
|
||||||
text-decoration: none
|
|
||||||
&:hover, &:focus
|
|
||||||
text-decoration: underline
|
|
||||||
|
|
||||||
.actions-cell
|
.actions-cell
|
||||||
text-align: right
|
text-align: right
|
||||||
padding-left: 1em
|
padding-left: 1em
|
||||||
font-size: 85%
|
font-size: 85%
|
||||||
|
|
||||||
tbody
|
.name-cell a
|
||||||
tr
|
text-decoration: none
|
||||||
&:hover, &:focus-within
|
&:hover
|
||||||
background: rgba($module-bg-color, 0.5)
|
text-decoration: underline
|
||||||
|
|
||||||
thead
|
thead
|
||||||
background: $module-bg-color
|
background: $module-bg-color
|
||||||
|
@ -50,23 +38,6 @@
|
||||||
th
|
th
|
||||||
text-align: left
|
text-align: left
|
||||||
|
|
||||||
.thumbnail-cell img
|
|
||||||
outline: 1px solid $soft-border-color
|
|
||||||
|
|
||||||
.actions-cell button
|
.actions-cell button
|
||||||
/* Bootstrap's Purple 600 */
|
/* Bootstrap's Purple 600 */
|
||||||
+awesome-button-color(#59359a)
|
+awesome-button-color(#59359a)
|
||||||
|
|
||||||
.special-color-explanation
|
|
||||||
text-wrap: balance
|
|
||||||
font-style: italic
|
|
||||||
|
|
||||||
/* For wearable items that belong to a specific set that all come together,
|
|
||||||
* like a Paint Brush. */
|
|
||||||
&[data-group-type="bundle"]
|
|
||||||
tbody
|
|
||||||
.thumbnail-cell
|
|
||||||
opacity: 0.65
|
|
||||||
|
|
||||||
tr:hover .thumbnail-cell
|
|
||||||
opacity: 0.85
|
|
||||||
|
|
|
@ -114,36 +114,18 @@ class ItemsController < ApplicationController
|
||||||
|
|
||||||
def sources
|
def sources
|
||||||
item_ids = params[:ids].split(",")
|
item_ids = params[:ids].split(",")
|
||||||
@items = Item.where(id: item_ids).includes(:nc_mall_record).order(:name).
|
@items = Item.where(id: item_ids).includes(:nc_mall_record).order(:name)
|
||||||
limit(50)
|
|
||||||
|
|
||||||
if @items.empty?
|
if @items.empty?
|
||||||
render file: "public/404.html", status: :not_found, layout: nil
|
render file: "public/404.html", status: :not_found, layout: nil
|
||||||
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).
|
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -2,34 +2,23 @@ require "addressable/template"
|
||||||
|
|
||||||
module ItemsHelper
|
module ItemsHelper
|
||||||
module PetTypeImage
|
module PetTypeImage
|
||||||
Template = Addressable::Template.new(
|
Format = 'https://pets.neopets.com/cp/%s/%i/%i.png'
|
||||||
"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)
|
||||||
|
@ -108,9 +97,8 @@ module ItemsHelper
|
||||||
SHOP_WIZARD_URL_TEMPLATE = Addressable::Template.new(
|
SHOP_WIZARD_URL_TEMPLATE = Addressable::Template.new(
|
||||||
"https://www.neopets.com/shops/wizard.phtml{?string}"
|
"https://www.neopets.com/shops/wizard.phtml{?string}"
|
||||||
)
|
)
|
||||||
def shop_wizard_url_for(item_or_name)
|
def shop_wizard_url_for(item)
|
||||||
item_or_name = item_or_name.name if item_or_name.is_a? Item
|
SHOP_WIZARD_URL_TEMPLATE.expand(string: item.name).to_s
|
||||||
SHOP_WIZARD_URL_TEMPLATE.expand(string: item_or_name).to_s
|
|
||||||
end
|
end
|
||||||
|
|
||||||
SUPER_SHOP_WIZARD_URL_TEMPLATE = Addressable::Template.new(
|
SUPER_SHOP_WIZARD_URL_TEMPLATE = Addressable::Template.new(
|
||||||
|
@ -123,9 +111,8 @@ module ItemsHelper
|
||||||
TRADING_POST_URL_TEMPLATE = Addressable::Template.new(
|
TRADING_POST_URL_TEMPLATE = Addressable::Template.new(
|
||||||
"https://www.neopets.com/island/tradingpost.phtml?type=browse&criteria=item_exact{&search_string}"
|
"https://www.neopets.com/island/tradingpost.phtml?type=browse&criteria=item_exact{&search_string}"
|
||||||
)
|
)
|
||||||
def trading_post_url_for(item_or_name)
|
def trading_post_url_for(item)
|
||||||
item_or_name = item_or_name.name if item_or_name.is_a? Item
|
TRADING_POST_URL_TEMPLATE.expand(search_string: item.name).to_s
|
||||||
TRADING_POST_URL_TEMPLATE.expand(search_string: item_or_name).to_s
|
|
||||||
end
|
end
|
||||||
|
|
||||||
AUCTION_GENIE_URL_TEMPLATE = Addressable::Template.new(
|
AUCTION_GENIE_URL_TEMPLATE = Addressable::Template.new(
|
||||||
|
@ -168,7 +155,9 @@ module ItemsHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def pet_type_image(pet_type, emotion, size)
|
def pet_type_image(pet_type, emotion, size)
|
||||||
src = pet_type_image_url(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)
|
||||||
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
|
||||||
|
|
|
@ -21,11 +21,6 @@ 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(' ')
|
||||||
|
|
|
@ -179,36 +179,6 @@ class Item < ApplicationRecord
|
||||||
nc_mall_record&.current_price
|
nc_mall_record&.current_price
|
||||||
end
|
end
|
||||||
|
|
||||||
# If this is a PB item, return the corresponding Color, inferred from the
|
|
||||||
# item name. If it's not a PB item, or we fail to infer, return nil.
|
|
||||||
def pb_color
|
|
||||||
return nil unless pb?
|
|
||||||
|
|
||||||
# NOTE: To handle colors like "Royalboy", where the items aren't consistent
|
|
||||||
# with the color name regarding whether or not there's spaces, we remove
|
|
||||||
# all spaces from the item name and color name when matching. We also
|
|
||||||
# hackily handle the fact that "Elderlyboy" color has items named "Elderly
|
|
||||||
# Male" (and same for Girl/Female) by replacing those words, too. These
|
|
||||||
# hacks could cause false matches in theory, but I'm not aware of any rn!
|
|
||||||
normalized_name = name.downcase.gsub("female", "girl").gsub("male", "boy").
|
|
||||||
gsub(/\s/, "")
|
|
||||||
|
|
||||||
Color.order(:name).
|
|
||||||
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
|
|
||||||
|
|
||||||
def restricted_zones(options={})
|
def restricted_zones(options={})
|
||||||
options[:scope] ||= Zone.all
|
options[:scope] ||= Zone.all
|
||||||
options[:scope].find(restricted_zone_ids)
|
options[:scope].find(restricted_zone_ids)
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
%tr
|
%tr
|
||||||
%td.thumbnail-cell
|
%td.thumbnail-cell= link_to item_thumbnail_for(item), item, target: "_blank"
|
||||||
= link_to item_thumbnail_for(item), item, target: "_blank",
|
|
||||||
tabindex: "-1"
|
|
||||||
%td.name-cell= link_to item.name, item, target: "_blank"
|
%td.name-cell= link_to item.name, item, target: "_blank"
|
||||||
%td.actions-cell= yield
|
%td.actions-cell= yield
|
||||||
|
|
|
@ -54,40 +54,13 @@
|
||||||
target: "_blank", icon: search_icon
|
target: "_blank", icon: search_icon
|
||||||
|
|
||||||
- if @pb_items.present?
|
- if @pb_items.present?
|
||||||
%h2 Paint Brush items
|
%h2 Paintbrush items
|
||||||
:markdown
|
:markdown
|
||||||
These items are part of a paint brush set. Once you paint your pet,
|
These items are part of a paintbrush set. Once you paint your pet,
|
||||||
these items will be semi-permanently added to your Closet, even if your
|
these items will be semi-permanently added to your Closet, even if your
|
||||||
pet changes color again! You can use this to mix-and-match styles for
|
pet changes color again! You can use this to mix-and-match styles for
|
||||||
"cross-paint" outfits.
|
"cross-paint" outfits.
|
||||||
- @pb_items_by_color.each do |color, items|
|
= render @pb_items
|
||||||
%table.item-list{"data-group-type": "bundle"}
|
|
||||||
%thead
|
|
||||||
%td.thumbnail-cell
|
|
||||||
- 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"})
|
|
||||||
%td.actions-cell
|
|
||||||
- if color.pb_item_name?
|
|
||||||
= button_link_to "Shops",
|
|
||||||
shop_wizard_url_for(color.pb_item_name),
|
|
||||||
target: "_blank", icon: search_icon
|
|
||||||
= button_link_to "Trades",
|
|
||||||
trading_post_url_for(color.pb_item_name),
|
|
||||||
target: "_blank", icon: search_icon
|
|
||||||
- else
|
|
||||||
.special-color-explanation
|
|
||||||
Get via Lab Ray, morphing potions, etc.
|
|
||||||
%tbody
|
|
||||||
- items.each do |item|
|
|
||||||
= render "item_list_row", item:
|
|
||||||
|
|
||||||
- if @other_nc_items.present?
|
- if @other_nc_items.present?
|
||||||
%h2 Neocash items (Capsules, Dyeworks, events, retired, etc.)
|
%h2 Neocash items (Capsules, Dyeworks, events, retired, etc.)
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
class AddPbItemNameToColors < ActiveRecord::Migration[7.1]
|
|
||||||
def change
|
|
||||||
add_column :colors, :pb_item_name, :string
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,5 +0,0 @@
|
||||||
class AddPbItemThumbnailUrlToColors < ActiveRecord::Migration[7.1]
|
|
||||||
def change
|
|
||||||
add_column :colors, :pb_item_thumbnail_url, :string
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[7.1].define(version: 2024_05_22_233638) do
|
ActiveRecord::Schema[7.1].define(version: 2024_05_11_003019) do
|
||||||
create_table "alt_styles", charset: "utf8mb4", collation: "utf8mb4_unicode_520_ci", force: :cascade do |t|
|
create_table "alt_styles", charset: "utf8mb4", collation: "utf8mb4_unicode_520_ci", force: :cascade do |t|
|
||||||
t.integer "species_id", null: false
|
t.integer "species_id", null: false
|
||||||
t.integer "color_id", null: false
|
t.integer "color_id", null: false
|
||||||
|
@ -76,8 +76,6 @@ ActiveRecord::Schema[7.1].define(version: 2024_05_22_233638) do
|
||||||
t.boolean "standard"
|
t.boolean "standard"
|
||||||
t.boolean "prank", default: false, null: false
|
t.boolean "prank", default: false, null: false
|
||||||
t.string "name", null: false
|
t.string "name", null: false
|
||||||
t.string "pb_item_name"
|
|
||||||
t.string "pb_item_thumbnail_url"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "contributions", id: :integer, charset: "utf8mb4", collation: "utf8mb4_unicode_520_ci", force: :cascade do |t|
|
create_table "contributions", id: :integer, charset: "utf8mb4", collation: "utf8mb4_unicode_520_ci", force: :cascade do |t|
|
||||||
|
|
Loading…
Reference in a new issue