Add deck analysis panel with mana production/consumption bars and oracle text search

Threads a new produced_mana/produces_colorless field through the whole card
read path (ingest, library, filters, decks, search) so the deck view can
show what colors a deck's manabase actually produces, alongside its existing
color identity. Also adds a mana consumption bar (colored casting costs of
nonland spells) and stacks the mana curve histogram by color. Adds an
oracle-text substring filter to the library search, mirroring the existing
location filter. Rearranges the deck sidebar list into two rows (name, then
format chip + actions) so long names and action buttons no longer collide,
and removes the drop shadows from the commander hero panel/image.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-08 23:54:47 -05:00
parent 4ac536caa2
commit e3f8a299de
17 changed files with 1054 additions and 161 deletions

View File

@@ -91,6 +91,14 @@ pub struct CardRef {
/// URL of the *back face* image for the same printing (transform / modal
/// double-faced / reversible cards), or empty for single-faced cards.
pub back_image_uri: String,
/// WUBRG bitmask of colors this card can *produce* (lands, mana rocks,
/// dorks, etc.) — independent of `colors`/`color_identity`, which
/// describe what color the card *is*, not what it taps for.
pub produced_mana: ColorSet,
/// Whether this card can produce colorless mana (Scryfall's
/// `produced_mana` including "C"), tracked separately since colorless
/// isn't a WUBRG bit.
pub produces_colorless: bool,
}
/// A library row: a card the user owns, with quantity and its deck memberships.
@@ -155,6 +163,16 @@ pub struct LibraryStats {
pub colorless_count: i64,
}
/// Distinct type/subtype/keyword values found among *owned* cards, sorted.
/// Powers autocomplete for the library filter panel — e.g. no point
/// suggesting "Phyrexian" as a subtype if you don't own any.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct LibraryFacets {
pub types: Vec<String>,
pub subtypes: Vec<String>,
pub keywords: Vec<String>,
}
/// Criteria for searching the owned library. All fields are optional; an empty
/// filter matches every owned card.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
@@ -184,4 +202,6 @@ pub struct LibraryFilter {
/// Case-insensitive substring match against the card's stored location
/// (e.g. "Box 1"). Cards with no location set never match a non-empty value.
pub location: Option<String>,
/// Case-insensitive substring match against the card's oracle rules text.
pub oracle_text: Option<String>,
}