Compare commits

..

3 commits

Author SHA1 Message Date
5e6c2c3c3f Put the new item preview in a Turbo frame
Nice, gotta say, this is a pretty neat way of making things feel more
app-y! There's some missing pieces here about like, loading state etc,
but the vibes are pretty good, and the implementation was dead-easy!
2024-07-01 13:48:20 -07:00
a8b4f9be65 [WIP] Add species/color picker for simplified item page preview
Still a lot missing here, like choosing the right default for Baby etc
items, and saving the user's preferences. But it's a start!
2024-06-30 23:34:27 -07:00
7733e9a8c4 [WIP] Start replacing item page preview with simpler HTML-based version
Just stripping out the big React component, and having Rails output it!

There's a lot of work rn in extracting the Impress 2020 dependency from
the `wardrobe-2020` React app, and I'm just curious to see if we can
simplify it at all by pulling this stuff *way* back to basics, and
deleting the item page part of `wardrobe-2020` altogether.

In this draft, we regress a lot of functionality: it just shows the
item on a Blue Acara, with no ability to change it! I'm gonna play with
putting more of that back in.

I also haven't actually removed any of the item page React code; I just
stopped calling it. That can be a cleanup for another time, once we're
confident in this experiment!
2024-06-30 23:09:28 -07:00
5 changed files with 94 additions and 123 deletions

View file

@ -43,7 +43,6 @@
/* When item names get long, don't let the buttons wrap to give the /* When item names get long, don't let the buttons wrap to give the
* item names more space. The names should wrap more instead! */ * item names more space. The names should wrap more instead! */
text-wrap: nowrap text-wrap: nowrap
margin: .25em
tbody tbody
tr tr
@ -56,12 +55,14 @@
th th
text-align: left text-align: left
.name-cell
text-wrap: nowrap
.thumbnail-cell img .thumbnail-cell img
outline: 1px solid $soft-border-color outline: 1px solid $soft-border-color
.actions-cell
button, a.button
/* Bootstrap's Purple 600 */
+awesome-button-color(#59359a)
tr[data-item-owned] tr[data-item-owned]
color: #aaa color: #aaa
@ -114,15 +115,6 @@
text-decoration-line: underline text-decoration-line: underline
text-decoration-style: dotted text-decoration-style: dotted
.actions-cell
button, a.button
&[data-action-kind=bulk-nc-mall]
/* Bootstrap's Purple 600 */
+awesome-button-color(#59359a)
&[data-complexity="high"]
width: 70%
/* For wearable items that belong to a specific set that all come together, /* For wearable items that belong to a specific set that all come together,
* like a Paint Brush. */ * like a Paint Brush. */
&[data-group-type="bundle"] &[data-group-type="bundle"]

View file

@ -194,34 +194,50 @@ module ItemsHelper
end end
def dyeworks_nc_total_for(items) def dyeworks_nc_total_for(items)
dyeworks_items_nc_total_for(items) + dyeworks_potions_nc_total(items.size)
end
def dyeworks_items_nc_total_for(items)
nc_total_for items.map(&:dyeworks_base_item) nc_total_for items.map(&:dyeworks_base_item)
end end
def dyeworks_average_num_potions_for(items) def dyeworks_potions_nc_total(num_items)
# Compute the number of expected potions for each (inverse of the odds), dyeworks_potions_nc_breakdown(num_items)[:nc_total]
# sum them, then round up.
items.map { |i| 1 / i.dyeworks_odds }.sum.ceil
end end
def dyeworks_estimated_potions_cost_for(items) def dyeworks_potions_nc_summary(num_items)
# NOTE: You could do bundles too, but let's just keep it simple. dyeworks_potions_nc_breakdown(num_items)[:summary]
dyeworks_average_num_potions_for(items) * 125
end end
def complexity_for(items) def dyeworks_potions_nc_breakdown(num_items)
max_name_length = items.map(&:name).map(&:length).max nc_total = 0
max_name_length >= 40 ? "high" : "low" summaries = []
end
def probability(p) # For every 10 potions, buy a 10-Bundle for 900 NC.
case p while num_items >= 10
when 1 nc_total += 900
"100%" summaries << "10-Bundle (900 NC)"
when 0 num_items -= 10
"0%"
else
"#{p.numerator} in #{p.denominator}"
end end
# For every remaining 5 potions, buy a 5-Bundle for 500 NC.
while num_items >= 5
nc_total += 500
summaries << "5-Bundle (500 NC)"
num_items -= 5
end
# For every remaining potion, buy each directly for 125 NC.
if num_items >= 1
nc_total += num_items * 125
summaries << "#{pluralize num_items, "potion"} (#{num_items * 125} NC)"
num_items = 0
end
summaries << "0 NC" if summaries.empty?
summary = summaries.join(", ")
{nc_total:, summary:}
end end
private private

View file

@ -17,8 +17,6 @@ class Item < ApplicationRecord
has_many :swf_assets, :through => :parent_swf_asset_relationships has_many :swf_assets, :through => :parent_swf_asset_relationships
belongs_to :dyeworks_base_item, class_name: "Item", belongs_to :dyeworks_base_item, class_name: "Item",
default: -> { inferred_dyeworks_base_item }, optional: true default: -> { inferred_dyeworks_base_item }, optional: true
has_many :dyeworks_variants, class_name: "Item",
inverse_of: :dyeworks_base_item
attr_writer :current_body_id, :owned, :wanted attr_writer :current_body_id, :owned, :wanted

View file

@ -70,39 +70,19 @@ class Item
match(DYEWORKS_LIMITED_FINAL_DATE_PATTERN) match(DYEWORKS_LIMITED_FINAL_DATE_PATTERN)
return nil if match.nil? return nil if match.nil?
# Parse this "<Month> <Day>" date as the *next* such date, with some # Parse this "<Month> <Day>" date as the *next* such date: parse it as
# wiggle room for the possibility that it recently passed and Owls hasn't # this year at first, then add a year if it turns out to be in the past.
# updated yet: parse it as this year at first, then add a year if that
# turns out to be more than 3 months ago. (That way, if it's currently
# December 2024, then events ending in Jan will be read as Jan 2025, and
# events ending in Nov will be read as Nov 2024.)
# #
# NOTE: This could return strange results if the Owls date contains # NOTE: This could return strange results if the Owls date contains
# something surprising! But the heuristic nature helps with e.g. # something surprising! But the heuristic nature helps with e.g.
# flexibility if they abbreviate months, so let's lean into `Date.parse`. # flexibility if they abbreviate months, so let's lean into `Date.parse`.
begin match => {month:, day:}
match => {month:, day:} date = Date.parse("#{month} #{day}, #{Date.today.year}")
date = Date.parse("#{month} #{day}, #{Date.today.year}") date += 1.year if date < Date.today
date += 1.year if date < Date.today - 3.months
rescue Date::Error
Rails.logger.warn "Could not parse Dyeworks final date: " +
"#{nc_trade_value.value_text.inspect}"
return nil
end
date date
end end
# The probability of getting this item when dyeing the base item.
def dyeworks_odds
return nil unless dyeworks?
num_variants = dyeworks_base_item.dyeworks_variants.count
raise "Item's Dyeworks base has *no* variants??" if num_variants < 1
Rational(1, num_variants)
end
# Infer what base item this Dyeworks item probably relates to, based on # Infer what base item this Dyeworks item probably relates to, based on
# their names. We only use this when a new item is modeled to initialize # their names. We only use this when a new item is modeled to initialize
# the `dyeworks_base_item` relationship in the database; after that, we # the `dyeworks_base_item` relationship in the database; after that, we

View file

@ -11,20 +11,17 @@
[nc]: https://secure.nc.neopets.com/get-neocash [nc]: https://secure.nc.neopets.com/get-neocash
[gc]: https://secure.nc.neopets.com/nickcash-cards [gc]: https://secure.nc.neopets.com/nickcash-cards
%table.item-list{"data-complexity": complexity_for(@items[:nc_mall])} %table.item-list
%thead %thead
%tr %tr
%td %td
%th.name-cell %th
Total: #{nc_total_for @items_needed[:nc_mall]} NC Total: #{nc_total_for @items_needed[:nc_mall]} NC
(#{pluralize @items_needed[:nc_mall].size, "item"}) (#{pluralize @items_needed[:nc_mall].size, "item"})
%td.actions-cell %td.actions-cell
- if @items_needed[:nc_mall].present? - if @items_needed[:nc_mall].present?
%button{ %button{onclick: "alert('Todo!')"}
onclick: "alert('Todo!')",
data: {"action-kind": "bulk-nc-mall"},
}
= cart_icon alt: "" = cart_icon alt: ""
Buy all in NC Mall Buy all in NC Mall
%tbody %tbody
@ -37,41 +34,34 @@
- if @items[:dyeworks].present? - if @items[:dyeworks].present?
%h2 Dyeworks items %h2 Dyeworks items
:markdown :markdown
These are recolored "Dyeworks" variants of items. Dyeworks is a game of These are recolored "Dyeworks" variants of items. First get the "base"
chance: if you have the "base" item and a Dyeworks Hue Brew Potion, you can item, then get a Dyeworks Hue Brew Potion, and combine them in the
[combine them][dyeworks] to receive a random color variant. You keep both [Dyeworks][dyeworks] section of the NC Mall! Potions can also be bought in
the new item *and* the base item. bundles of 5 or 10.
If you don't get the color you want, you can use another potion to try
again. It's also common for users to exchange the variants they don't want
via "NC Trading". Potions can be bought individually, or in bundles of 5
or 10.
[dyeworks]: https://www.neopets.com/mall/dyeworks/ [dyeworks]: https://www.neopets.com/mall/dyeworks/
%table.item-list{"data-complexity": complexity_for(@items[:dyeworks])} %table.item-list
%thead %thead
%tr %tr
%td.thumbnail-cell %td.thumbnail-cell
= image_tag "https://images.neopets.com/items/mall_80x80_cleaning.gif", = image_tag "https://images.neopets.com/items/mall_80x80_cleaning.gif",
alt: "Dyeworks Hue Brew Potion" alt: "Dyeworks Hue Brew Potion"
%th.name-cell %th
Total: #{dyeworks_nc_total_for @items_needed[:dyeworks]} NC Total: #{dyeworks_nc_total_for @items_needed[:dyeworks]} NC
+ = surround "(", ")" do
%span.price-breakdown{ %span.price-breakdown{
title: "At least #{pluralize @items_needed[:dyeworks].size, 'potion'}, " + title: "#{dyeworks_items_nc_total_for(@items_needed[:dyeworks])} NC"
"average " + }<
"#{dyeworks_average_num_potions_for @items_needed[:dyeworks]}, " + #{pluralize @items_needed[:dyeworks].size, "item"}
"could be more. 125 NC per potion, but cheaper in bundles." +
} %span.price-breakdown{
?? potions title: dyeworks_potions_nc_summary(@items_needed[:dyeworks].size)
(~#{dyeworks_estimated_potions_cost_for @items_needed[:dyeworks]} NC) }<
#{pluralize @items_needed[:dyeworks].size, "potion"}
%td.actions-cell %td.actions-cell
- if @items_needed[:dyeworks].present? - if @items_needed[:dyeworks].present?
%button{ %button{onclick: "alert('Todo!')"}
onclick: "alert('Todo!')",
data: {"action-kind": "bulk-nc-mall"},
}
= cart_icon alt: "" = cart_icon alt: ""
Buy all in NC Mall Buy all in NC Mall
%tbody %tbody
@ -80,40 +70,36 @@
- base_item = item.dyeworks_base_item - base_item = item.dyeworks_base_item
- content_for :subtitle, flush: true do - content_for :subtitle, flush: true do
= link_to base_item, target: "_blank" do = link_to base_item.name, base_item, target: "_blank"
#{probability item.dyeworks_odds} chance + 1 potion
- if item.dyeworks_permanent? - if item.dyeworks_permanent?
%span.dyeworks-timeframe{ %span.dyeworks-timeframe{
title: "This recipe is NOT currently scheduled to be removed " + title: "This recipe is NOT currently scheduled to be removed " +
"from Dyeworks. It might not stay forever, but it's also " + "from Dyeworks. It might not stay forever, but it's also " +
"not part of a known limited-time event, like most " + "not part of a known limited-time event, like most " +
"Dyeworks items are. (Thanks Owls team!)" "Dyeworks items are. (Thanks Owls team!)"
} }
(Always available) (Permanent)
- elsif item.dyeworks_limited_final_date.present? - elsif item.dyeworks_limited_final_date.present?
%span.dyeworks-timeframe{ %span.dyeworks-timeframe{
title: "This recipe is part of a limited-time Dyeworks " + title: "This recipe is part of a limited-time Dyeworks " +
"event. The last day you can dye this is " + "event. The last day you can dye this is " +
"#{item.dyeworks_limited_final_date.to_fs(:long)}. " + "#{item.dyeworks_limited_final_date.to_fs(:month_and_day)}. " +
"(Thanks Owls team!)" "(Thanks Owls team!)"
} }
(Limited-time: #{item.dyeworks_limited_final_date.to_fs(:month_and_day)}) (Thru #{item.dyeworks_limited_final_date.to_fs(:month_and_day)})
- elsif item.dyeworks_limited? - elsif item.dyeworks_limited?
%span.dyeworks-timeframe{ %span.dyeworks-timeframe{
title: "This recipe is part of a limited-time Dyeworks " + title: "This recipe is part of a limited-time Dyeworks " +
"event, and is scheduled to be removed from the NC Mall " + "event, and is scheduled to be removed from the NC Mall " +
"soon. (Thanks Owls team!)" "soon. (Thanks Owls team!)"
} }
(Limited-time) (Limited-time)
%button{onclick: "alert('Todo!')"} %button{onclick: "alert('Todo!')"}
= cart_icon alt: "" = cart_icon alt: ""
Buy base (#{item.dyeworks_base_item.current_nc_price} NC) Buy base (#{item.dyeworks_base_item.current_nc_price} NC)
= button_link_to "NC Trades",
item_trades_path(item, type: "offering"),
target: "_blank", icon: search_icon
- if @items[:np].present? - if @items[:np].present?
%h2 Neopoint items %h2 Neopoint items
:markdown :markdown
@ -126,11 +112,11 @@
[tp]: https://www.neopets.com/island/tradingpost.phtml?type=browse [tp]: https://www.neopets.com/island/tradingpost.phtml?type=browse
[ag]: https://www.neopets.com/genie.phtml [ag]: https://www.neopets.com/genie.phtml
%table.item-list{"data-complexity": complexity_for(@items[:np])} %table.item-list
%thead %thead
%tr %tr
%td %td
%th.name-cell{colspan: 2} %th{colspan: 2}
Total: #{pluralize @items_needed[:np].size, "item"} Total: #{pluralize @items_needed[:np].size, "item"}
%tbody %tbody
- @items[:np].each do |item| - @items[:np].each do |item|
@ -153,7 +139,6 @@
%table.item-list{ %table.item-list{
"data-group-type": "bundle", "data-group-type": "bundle",
"data-group-owned": items.all?(&:owned?), "data-group-owned": items.all?(&:owned?),
"data-complexity": complexity_for(items),
} }
%thead %thead
%tr %tr
@ -210,10 +195,10 @@
[owls]: https://www.neopets.com/~owls [owls]: https://www.neopets.com/~owls
%table.item-list{"data-complexity": complexity_for(@items[:other_nc])} %table.item-list
%thead %thead
%td %td
%th.name-cell{colspan: 2} %th{colspan: 2}
Total: #{pluralize @items_needed[:other_nc].size, "item"} Total: #{pluralize @items_needed[:other_nc].size, "item"}
%tbody %tbody
- @items[:other_nc].each do |item| - @items[:other_nc].each do |item|