update editor and extraction value

This commit is contained in:
kvan7
2026-09-03 20:05:05 -05:00
parent 9b3cd173d9
commit 1d32c4874f
10 changed files with 670 additions and 47 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

+227 -30
View File
@@ -1,36 +1,12 @@
import { init, STAT_BY_REF } from "@/assets/data";
import { init } from "@/assets/data";
import { ItemCategory } from "@/parser";
import { ParsedModifier } from "@/parser/advanced-mod-desc";
import { ModifierType, StatCalculated } from "@/parser/modifiers";
import { ModifierType } from "@/parser/modifiers";
import { __testExports } from "@/parser/Parser";
import { createTestItem, makeCalcStat } from "@specs/helper";
import { setupTests } from "@specs/vitest.setup";
import { beforeEach, describe, expect, it } from "vitest";
function makeCalcStat(ref: string, value: number): StatCalculated {
const stat = STAT_BY_REF(ref)!;
return {
stat,
type: ModifierType.Augment,
sources: [
{
contributes: {
value,
},
modifier: {
info: {
type: ModifierType.Augment,
tags: [],
},
stats: [],
},
stat: {
stat,
},
},
],
} as unknown as StatCalculated;
}
describe("determineAugments", () => {
beforeEach(async () => {
setupTests();
@@ -46,7 +22,7 @@ describe("determineAugments", () => {
type: ModifierType.Augment,
},
} as unknown as ParsedModifier,
makeCalcStat("#% increased Physical Damage", 36),
[makeCalcStat("#% increased Physical Damage", 36, ModifierType.Augment)],
);
expect(result.map((augment) => augment.refName)).toEqual(expectedRef);
@@ -61,7 +37,7 @@ describe("determineAugments", () => {
type: ModifierType.Augment,
},
} as unknown as ParsedModifier,
makeCalcStat("#% to Lightning Resistance", 10),
[makeCalcStat("#% to Lightning Resistance", 10, ModifierType.Augment)],
);
expect(result.map((augment) => augment.refName)).toEqual(expectedRef);
@@ -98,3 +74,224 @@ describe("BFS", () => {
},
);
});
describe("parseAugmentSockets", () => {
beforeEach(async () => {
setupTests();
await init("en");
});
it("should skip for items without sockets", () => {
const item = createTestItem();
const result = __testExports.parseAugmentSockets([], item);
expect(result).toEqual("PARSER_SKIPPED");
});
it.each([
[["Sockets: S"], 1],
[["Sockets: S S"], 2],
[["Sockets: S S S"], 3],
[["Sockets: S S S S"], 4],
[["Sockets: S S S S S"], 5],
])(
"%#. should add correct augment socket count(%o -> %o)",
(lines, expected) => {
const item = createTestItem();
item.category = ItemCategory.Gloves;
const result = __testExports.parseAugmentSockets(lines, item);
expect(result).toEqual("SECTION_PARSED");
expect(item.augmentSockets?.normal).toEqual(1);
expect(item.augmentSockets?.empty).toEqual(0);
expect(item.augmentSockets?.current).toEqual(expected);
expect(
item.augmentSockets?.augments.every((v) => v === null),
).toBeTruthy();
expect(item.augmentSockets?.augments.length).toEqual(expected);
},
);
it("should add sockets on non-socket section", () => {
const item = createTestItem();
item.category = ItemCategory.Gloves;
const result = __testExports.parseAugmentSockets(["text"], item);
expect(result).toEqual("SECTION_SKIPPED");
expect(item.augmentSockets?.normal).toEqual(1);
expect(item.augmentSockets?.empty).toEqual(1);
expect(item.augmentSockets?.current).toEqual(0);
expect(item.augmentSockets?.augments.every((v) => v === null)).toBeTruthy();
expect(item.augmentSockets?.augments.length).toEqual(1);
});
});
describe("applyAugmentSockets", () => {
beforeEach(async () => {
setupTests();
await init("en");
});
it("should do nothing on item without sockets", () => {
const item = createTestItem();
__testExports.applyAugmentSockets(item);
expect(item).toEqual(createTestItem());
});
it("should set empty on item with no augment stats", () => {
const item = createTestItem();
item.category = ItemCategory.Gloves;
item.augmentSockets = {
empty: 0,
current: 2,
normal: 2,
augments: [null, null],
};
__testExports.applyAugmentSockets(item);
expect(item.augmentSockets.empty).toEqual(2);
expect(item.augmentSockets.current).toEqual(2);
expect(item.augmentSockets.normal).toEqual(2);
expect(item.augmentSockets.augments.every((v) => v === null)).toBeTruthy();
});
it("should apply correct augment to item", () => {
const item = createTestItem();
item.category = ItemCategory.Bow;
item.augmentSockets = {
empty: 0,
current: 2,
normal: 2,
augments: [null, null],
};
const stat = makeCalcStat(
"#% increased Physical Damage",
18,
ModifierType.Augment,
);
item.statsByType = [stat];
item.newMods = [
{
info: {
type: ModifierType.Augment,
tags: [],
},
stats: [stat.sources[0].stat],
},
];
__testExports.applyAugmentSockets(item);
expect(item.augmentSockets.empty).toEqual(1);
expect(item.augmentSockets.current).toEqual(2);
expect(item.augmentSockets.normal).toEqual(2);
expect(item.augmentSockets.augments[0]?.refName).toEqual(
"Greater Iron Rune",
);
expect(item.augmentSockets.augments[1]).toBeNull();
});
it("should apply multiple different augments to item", () => {
const item = createTestItem();
item.category = ItemCategory.Bow;
item.augmentSockets = {
empty: 0,
current: 2,
normal: 2,
augments: [null, null],
};
const stat1 = makeCalcStat(
"#% increased Physical Damage",
18,
ModifierType.Augment,
);
const stat2 = makeCalcStat(
"Bow Attacks fire # additional Arrows",
1,
ModifierType.Augment,
);
item.statsByType = [stat1, stat2];
item.newMods = [
{
info: {
type: ModifierType.Augment,
tags: [],
},
stats: [stat1.sources[0].stat, stat2.sources[0].stat],
},
];
__testExports.applyAugmentSockets(item);
expect(item.augmentSockets.empty).toEqual(0);
expect(item.augmentSockets.current).toEqual(2);
expect(item.augmentSockets.normal).toEqual(2);
expect(
item.augmentSockets.augments.some(
(i) => i?.refName === "Greater Iron Rune",
),
).toBeTruthy();
expect(
item.augmentSockets.augments.some(
(i) => i?.refName === "Countess Seske's Rune of Archery",
),
).toBeTruthy();
});
it("should join multiline augments", () => {
const item = createTestItem();
item.category = ItemCategory.Staff;
item.augmentSockets = {
empty: 0,
current: 2,
normal: 2,
augments: [null, null],
};
const stat1 = makeCalcStat(
"Meta Skills gain #% increased Energy",
40,
ModifierType.Augment,
);
const stat2 = makeCalcStat(
"#% increased Spirit",
-25,
ModifierType.Augment,
);
const stat3 = makeCalcStat(
"#% increased Mana Regeneration Rate",
20,
ModifierType.Augment,
);
item.statsByType = [stat1, stat2, stat3];
item.newMods = [
{
info: {
type: ModifierType.Augment,
tags: [],
},
stats: [
stat1.sources[0].stat,
stat2.sources[0].stat,
stat3.sources[0].stat,
],
},
];
__testExports.applyAugmentSockets(item);
expect(item.augmentSockets.empty).toEqual(0);
expect(item.augmentSockets.current).toEqual(2);
expect(item.augmentSockets.normal).toEqual(2);
expect(
item.augmentSockets.augments.some(
(i) => i?.refName === "Idol of the Martyr",
),
).toBeTruthy();
expect(
item.augmentSockets.augments.some(
(i) => i?.refName === "Lesser Inspiration Rune",
),
).toBeTruthy();
});
});
+78
View File
@@ -1333,3 +1333,81 @@ CharmQuality.prefixCount = 1;
CharmQuality.suffixCount = 1;
// #endregion CharmQuality
// #region BowThreeAugments
export const BowThreeAugments = new TestItem(`Item Class: Bows
Rarity: Rare
Oblivion Branch
Obliterator Bow
--------
Quality: +20% (augmented)
Physical Damage: 288-534 (augmented)
Fire Damage: 47-92 (fire)
Critical Hit Chance: 8.45% (augmented)
Attacks per Second: 1.27 (augmented)
--------
Requires: Level 78, 163 Dex
--------
Sockets: S S S
--------
Item Level: 80
--------
38% increased Physical Damage (rune)
Bow Attacks fire an additional Arrow (rune)
--------
{ Implicit Modifier }
50% reduced Projectile Range
--------
{ Prefix Modifier "Cruel" (Tier: 3) — Damage, Physical, Attack }
151(135-154)% increased Physical Damage
{ Desecrated Prefix Modifier "Razor-sharp" (Tier: 3) — Damage, Physical, Attack }
Adds 21(16-24) to 39(28-42) Physical Damage
{ Prefix Modifier "Blasting" (Tier: 3) — Damage, Elemental, Fire, Attack }
Adds 47(47-59) to 92(74-97) Fire Damage
{ Suffix Modifier "of Renown" (Tier: 2) — Attack, Speed }
15(14-16)% increased Attack Speed
{ Suffix Modifier "of the Vampire" (Tier: 1) — Life, Physical, Attack }
Leeches 9.6(9-9.9)% of Physical Damage as Life
{ Crafted Suffix Modifier "of Calamity" (Tier: 3) — Attack, Critical }
+3.45(3.11-3.8)% to Critical Hit Chance
--------
Corrupted
`);
BowThreeAugments.category = ItemCategory.Bow;
BowThreeAugments.rarity = ItemRarity.Rare;
BowThreeAugments.itemLevel = 80;
BowThreeAugments.quality = 20;
BowThreeAugments.weaponPHYSICAL = 411;
BowThreeAugments.weaponFIRE = 69.5;
BowThreeAugments.weaponELEMENTAL = BowThreeAugments.weaponFIRE;
BowThreeAugments.weaponCRIT = 8.45;
BowThreeAugments.weaponAS = 1.27;
BowThreeAugments.requires = {
level: 78,
str: 0,
dex: 163,
int: 0,
};
BowThreeAugments.info.refName = "Obliterator Bow";
BowThreeAugments.sectionCount = 9;
BowThreeAugments.prefixCount = 3;
BowThreeAugments.suffixCount = 3;
BowThreeAugments.implicitCount = 1;
BowThreeAugments.augmentSockets = {
empty: 0,
current: 3,
normal: 2,
augments: [
createEditorItem("Perfect Iron Rune", "20% increased Physical Damage", 20),
createEditorItem("Greater Iron Rune", "18% increased Physical Damage", 18),
createEditorItem(
"Countess Seske's Rune of Archery",
"Bow Attacks fire an additional Arrow",
1,
),
],
};
// #endregion BowThreeAugments
+67
View File
@@ -1,4 +1,9 @@
import { STAT_BY_REF } from "@/assets/data";
import { ItemCategory } from "@/parser";
import { ParsedModifier } from "@/parser/advanced-mod-desc";
import { ModifierType, StatCalculated } from "@/parser/modifiers";
import { createVirtualItem, ParsedItem } from "@/parser/ParsedItem";
import { ParsedStat } from "@/parser/stat-translations";
import { FilterTag, StatFilter } from "@/web/price-check/filters/interfaces";
export function createTestStatFilter(): StatFilter {
@@ -43,9 +48,71 @@ export function createTestItem(): ParsedItem {
info: {
refName: "test",
namespace: "ITEM",
craftable: {
category: ItemCategory.Unknown,
},
name: "",
icon: "",
tags: [],
},
};
}
export function createParsedStat(
statRef: string,
value: number | [number, number],
): ParsedStat {
const stat = STAT_BY_REF(statRef)!;
return {
stat,
translation: stat.matchers[0],
roll: {
unscalable: false,
dp: stat.dp || false,
value: Array.isArray(value) ? (value[0] + value[1]) / 2 : value,
min: Array.isArray(value) ? value[0] : value,
max: Array.isArray(value) ? value[1] : value,
},
};
}
export function createParsedModifier(
statRef: string,
value: number | [number, number],
type: ModifierType = ModifierType.Explicit,
): ParsedModifier {
return {
info: {
type,
tags: [],
},
stats: [createParsedStat(statRef, value)],
};
}
export function makeCalcStat(
ref: string,
value: number,
type: ModifierType = ModifierType.Explicit,
): StatCalculated {
const parsedStat = createParsedStat(ref, value);
return {
stat: parsedStat.stat,
type,
sources: [
{
contributes: parsedStat.roll,
modifier: {
info: {
type,
tags: [],
},
stats: [parsedStat],
},
stat: parsedStat,
},
],
};
}
+78 -15
View File
@@ -44,6 +44,7 @@ import { calcPropPercentile, QUALITY_STATS } from "./calc-q20";
import { AppConfig } from "@/web/Config";
import { buildEditorItems, getSavedAugments } from "./augment-builder";
import { useAugment } from "@/web/price-check/item-editor/augment";
import { combinations } from "./utils";
type SectionParseResult =
| "SECTION_PARSED"
@@ -855,14 +856,16 @@ function parseAugmentSockets(section: string[], item: ParsedItem) {
empty: 0,
current,
normal: categoryMax,
augments: Array(categoryMax).fill(null),
augments: Array(current).fill(null),
};
} else {
item.augmentSockets = {
empty: 0,
current,
normal: categoryMax,
augments: Array(categoryMax).fill(null),
augments: Array(categoryMax > current ? categoryMax : current).fill(
null,
),
};
}
@@ -1322,23 +1325,44 @@ function applyAugmentSockets(item: ParsedItem) {
const augmentMods = item.newMods.filter(
(mod) => mod.info.type === ModifierType.Augment,
);
console.log(augmentMods);
const augmentStats = item.statsByType.filter(
(calc) => calc.type === ModifierType.Augment,
);
const augments: Array<EditorItem | null> = augmentMods
.map((mod) => {
const stat = augmentStats.find(
(stat) => stat.sources[0].stat === mod.stats[0],
);
if (!stat) return [];
console.log(augmentStats);
let statCombinations = combinations(augmentStats)
.filter((f) => f.length)
.toSorted((a, b) => b.length - a.length);
const augs: BaseType[][] = [];
for (let i = 0; i < statCombinations.length; ) {
const foundAugs = determineAugments(augmentMods[0], statCombinations[i]);
if (foundAugs.length) {
augs.push(foundAugs);
for (const combStat of statCombinations[i]) {
// drop any that we use here
statCombinations = statCombinations.filter(
(f) => f.find((s) => s === combStat) === undefined,
);
}
i = 0;
continue;
}
i++;
}
const augments: Array<EditorItem | null> = augs
.map((augGroup) => {
return buildEditorItems(
determineAugments(mod, stat),
augGroup,
item.category ?? ItemCategory.Unknown,
true,
);
})
.flat();
console.log(augments);
if (
augments.length <
Math.max(item.augmentSockets.current, item.augmentSockets.normal)
@@ -2133,21 +2157,58 @@ function modifiedBfs(
function determineAugments(
mod: ParsedModifier,
statCalc: StatCalculated,
statCalcs: StatCalculated[],
): BaseType[] {
if (mod.info.type !== ModifierType.Augment) return [];
const augmentAppliedValue = statCalc.sources[0].contributes?.value;
const augmentAppliedValue = statCalcs
.map((s) => s.sources[0].contributes?.value)
.filter((v) => v !== undefined);
const augmentTradeId = statCalc.stat.trade.ids[ModifierType.Augment][0];
const possibleAugments = AUGMENT_DATA_BY_TRADE_ID[augmentTradeId];
// const augmentTradeId = statCalcs[0].stat.trade.ids[ModifierType.Augment][0];
// const possibleAugments = AUGMENT_DATA_BY_TRADE_ID[augmentTradeId];
const allTradeIds = statCalcs.map(
(c) => c.stat.trade.ids[ModifierType.Augment][0],
);
const allPossibleAugments = allTradeIds.map(
(id) => AUGMENT_DATA_BY_TRADE_ID[id],
);
const augmentRefSets = allPossibleAugments.map(
(augGroup) => new Set(augGroup.map((a) => a.refName)),
);
console.log(augmentRefSets);
const morePossibleAugments = augmentRefSets.reduce((acc, set) => {
return set.intersection(acc);
}, augmentRefSets[0]);
console.log("morePossibleAugments", morePossibleAugments);
// intersect all possible augments
const possibleAugments = allPossibleAugments
.map((augGroup) =>
augGroup.filter((aug) => morePossibleAugments.has(aug.refName)),
)
.find((f) => f.length);
console.log(possibleAugments);
if (!possibleAugments) return [];
// something like "Raven-Touched"
if (!augmentAppliedValue) {
if (!augmentAppliedValue || !augmentAppliedValue.length) {
const singleAugment = possibleAugments[0];
return [ITEM_BY_REF("ITEM", singleAugment.refName)![0]];
}
if (augmentAppliedValue.length > 1) {
const likelyAugment = possibleAugments.find(
(aug) =>
new Set(aug.values).intersection(new Set(augmentAppliedValue)).size ===
augmentAppliedValue.length,
);
if (!likelyAugment) return [];
return [ITEM_BY_REF("ITEM", likelyAugment.refName)![0]];
}
// // Calculate how many of this augment are in the item
const availableAugmentValues = possibleAugments
.map((augment) => {
@@ -2166,7 +2227,7 @@ function determineAugments(
// BFS to find all combinations with minimum count
const likelyValues =
modifiedBfs(augmentAppliedValue, [], availableAugmentValues) ?? [];
modifiedBfs(augmentAppliedValue[0], [], availableAugmentValues) ?? [];
return likelyValues.map((v) => {
const augment = possibleAugments.find((aug) =>
@@ -2206,4 +2267,6 @@ export const __testExports = {
parseTrials,
determineAugments,
modifiedBfs,
parseAugmentSockets,
applyAugmentSockets,
};
+6
View File
@@ -0,0 +1,6 @@
export function combinations<T>(arr: T[]): T[][] {
return arr.reduce<T[][]>(
(acc, curr) => [...acc, ...acc.map((a) => [...a, curr])],
[[]],
);
}
+76
View File
@@ -356,6 +356,78 @@ export const usePoeninja = createGlobalState(() => {
return currency;
}
function toDivine(value: CurrencyValue): CurrencyValue {
if (value.currency === "div") return value;
if (xchgRate.value) {
if (xchgRateCurrency.value !== value.currency) {
throw new Error(
`Cannot convert ${value.currency} to div, current core currency is ${xchgRateCurrency.value}`,
);
}
return {
min: value.min / xchgRate.value,
max: value.max / xchgRate.value,
currency: "div",
};
}
return value;
}
function addPrice(
addend1: CurrencyValue,
addend2: CurrencyValue,
): CurrencyValue {
const addend1Div = toDivine(addend1);
const addend2Div = toDivine(addend2);
return autoCurrency([
addend1Div.min + addend2Div.min,
addend1Div.max + addend2Div.max,
]);
}
function subtractPrice(
minuend: CurrencyValue,
subtrahend: CurrencyValue,
): CurrencyValue {
const minuendDiv = toDivine(minuend);
const subtrahendDiv = toDivine(subtrahend);
return autoCurrency([
minuendDiv.min - subtrahendDiv.max,
minuendDiv.max - subtrahendDiv.min,
]);
}
function comparePrice(
left: CurrencyValue,
op: ">" | ">=" | "==" | "===" | "<=" | "<",
right: CurrencyValue,
): boolean {
const leftDiv = toDivine(left);
const rightDiv = toDivine(right);
switch (op) {
case ">":
return leftDiv.min > rightDiv.max;
case ">=":
return leftDiv.min >= rightDiv.max;
case "==":
return leftDiv.min === rightDiv.max && leftDiv.max === rightDiv.min;
case "===":
return (
left.currency === right.currency &&
leftDiv.min === rightDiv.max &&
leftDiv.max === rightDiv.min
);
case "<=":
return leftDiv.max <= rightDiv.min;
case "<":
return leftDiv.max < rightDiv.min;
}
}
setInterval(() => {
load();
}, RETRY_INTERVAL_MS);
@@ -384,6 +456,10 @@ export const usePoeninja = createGlobalState(() => {
initialLoading: () => isLoading.value && !PRICES_DB.length,
availableCoreCurrencies: readonly(availableCoreCurrencies),
ITEM_DROP,
// math
addPrice,
subtractPrice,
comparePrice,
};
});
@@ -0,0 +1,116 @@
<template>
<div
v-if="extractionProfits"
class="p-2 border-2 rounded mt-2 flex items-center gap-1"
:class="{
'border-red-500 border': extractionProfits,
'border-gray-600 border-dashed': !extractionProfits,
}"
>
<div class="text-2xl">Σ</div>
<item-quick-price
:price="augmentPrice"
:item-img="'/images/augments/rune.png'"
:currency-text="false"
:show-arrow="false"
/>
<i class="fa-solid fa-minus mr-2" />
<item-quick-price
:price="extractionOrb"
:item-img="'/images/extractor.png'"
:currency-text="false"
:show-arrow="false"
/>
<i class="fa-solid fa-equals mr-2" />
<item-quick-price
:price="profitValue"
:currency-text="false"
:show-img="false"
:show-arrow="false"
/>
</div>
</template>
<script lang="ts">
import { ParsedItem } from "@/parser";
import { computed, defineComponent, PropType } from "vue";
import { PricingResult } from "./pathofexile-trade";
import { useI18nNs } from "@/web/i18n";
import { CurrencyValue, usePoeninja } from "@/web/background/Prices";
import ItemQuickPrice from "@/web/ui/ItemQuickPrice.vue";
export default defineComponent({
components: {
ItemQuickPrice,
},
props: {
item: {
type: Object as PropType<ParsedItem>,
required: true,
},
firstResult: {
type: Object as PropType<PricingResult>,
required: false,
},
},
setup(props) {
const { findPriceByQuery, autoCurrency, comparePrice, subtractPrice } =
usePoeninja();
const extractionOrb = computed(() => {
const price = findPriceByQuery({
ns: "ITEM",
name: "Orb of Extraction",
});
return autoCurrency(price?.primaryValue || 99999);
});
const augmentPrice = computed(() => {
if (!props.item.augmentSockets) return autoCurrency(0);
const price = props.item.augmentSockets.augments.reduce(
(sum, augment) => {
if (!augment) return sum;
const price = findPriceByQuery({
ns: "ITEM",
name: augment.refName,
});
if (!price) return sum;
return sum + price.primaryValue;
},
0,
);
return autoCurrency(price);
});
const profitValue = computed(() =>
subtractPrice(augmentPrice.value, extractionOrb.value),
);
const firstResultValue = computed<CurrencyValue | null>(() => {
if (!props.firstResult || !props.firstResult.normalizedPrice) return null;
const num = Number.parseFloat(props.firstResult.normalizedPrice);
if (Number.isNaN(num)) return null;
return {
min: num,
max: num,
currency: props.firstResult.normalizedPriceCurrency!.id,
};
});
const { t } = useI18nNs("trade_result");
return {
t,
extractionOrb,
augmentPrice,
profitValue,
extractionProfits: computed(() => {
if (!firstResultValue.value) return false;
return comparePrice(firstResultValue.value, "<", profitValue.value);
}),
};
},
});
</script>
@@ -92,6 +92,9 @@
</div>
</div>
<!-- Extraction Value -->
<extraction-value :item="item" :first-result="groupedResults.at(0)" />
<!-- ADDED AUGMENTS COST -->
<div
v-if="addedAugments && addedAugments.length"
@@ -151,6 +154,7 @@ import TradeItem from "./TradeItem.vue";
import { useTradeApi } from "./trade-api";
import { GEM, GRANTS_REAL_SKILL } from "@/parser/meta";
import ItemSumPrice from "@/web/ui/ItemSumPrice.vue";
import ExtractionValue from "./ExtractionValue.vue";
const slowdown = artificialSlowdown(900);
@@ -158,6 +162,7 @@ const SHOW_RESULTS = 20;
export default defineComponent({
components: {
ExtractionValue,
ItemQuickPrice,
ItemSumPrice,
OnlineFilter,
+17 -2
View File
@@ -1,11 +1,18 @@
<template>
<div class="flex items-center gap-x-1">
<slot name="item">
<div class="flex items-center justify-center shrink-0" :class="imgSize">
<div
v-if="showImg"
class="flex items-center justify-center shrink-0"
:class="imgSize"
>
<ui-item-img :icon="itemImg" overflow-hidden />
</div>
</slot>
<i class="fas fa-arrow-right text-gray-600 px-1 text-sm"></i>
<i
v-if="showArrow"
class="fas fa-arrow-right text-gray-600 px-1 text-sm"
></i>
<div class="whitespace-nowrap overflow-hidden">
<span v-if="approx && !isRange" class="text-gray-600 font-sans">~ </span>
<span :class="{ [$style.golden]: isValuable, 'px-1': minText === '?' }">{{
@@ -89,6 +96,14 @@ export default defineComponent({
type: Object as PropType<BaseType>,
default: undefined,
},
showImg: {
type: Boolean,
default: true,
},
showArrow: {
type: Boolean,
default: true,
},
},
setup(props) {
const minText = computed(() =>