custom amount ui prettier (#4556)

## Description:

fixed font, 
sizing, 
back box wrapping, 
remove "buy for" 
centre the text by removing the ^ v arrows

before:
<img width="939" height="491" alt="image"
src="https://github.com/user-attachments/assets/3c747341-5238-47e8-b455-ea5827669e75"
/>



after:
<img width="936" height="746" alt="image"
src="https://github.com/user-attachments/assets/4b64f34b-98e4-4519-85bd-1f5c2799babd"
/>

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory

## Please put your Discord username so you can be contacted if a bug or
regression is found:

w.o.n
This commit is contained in:
Ryan
2026-07-09 20:37:46 +01:00
committed by GitHub
parent 274b516ea3
commit 70d301fbb9
4 changed files with 60 additions and 52 deletions
+2 -2
View File
@@ -1310,7 +1310,6 @@
},
"store": {
"already_subscribed": "Already subscribed.",
"buy_for": "Buy for {price}",
"change_tier_failed": "Couldn't update your subscription. Please try again.",
"change_tier_success": "Switched to {tier}.",
"checkout_failed": "Failed to create checkout session.",
@@ -1319,7 +1318,7 @@
"confirm_purchase_title": "Confirm Purchase",
"confirm_upgrade": "Upgrade to {tier}? You'll be charged the prorated difference now.",
"currency_pack_purchase_success": "Currency pack purchase successful!",
"custom_amount": "Custom Amount",
"custom_amount": "Choose Amount",
"custom_currency_purchase_success": "Plutonium purchase successful!",
"effects": "Effects",
"flags": "Flags",
@@ -1332,6 +1331,7 @@
"no_subscriptions": "No subscriptions available. Check back later for new items.",
"packs": "Packs",
"patterns": "Skins",
"plutonium_amount": "Plutonium amount",
"price_per_month": "/mo",
"purchase_currency": "Purchase {currency}",
"purchase_failed": "Purchase failed. Please try again.",
+37 -48
View File
@@ -2,7 +2,9 @@ import { html, LitElement } from "lit";
import { customElement, state } from "lit/decorators.js";
import { createCustomCurrencyCheckout } from "../Api";
import { translateText } from "../Utils";
import "./CosmeticContainer";
import "./PlutoniumIcon";
import "./PurchaseButton";
// Fixed rate: 20 plutonium = $1.00 (5 cents each). Bounds and rate are
// enforced server-side; these are for UX only.
@@ -13,7 +15,6 @@ const MAX_PLUTONIUM = 2000;
export class CustomCurrencyCard extends LitElement {
/** Always a clamped integer in [MIN_PLUTONIUM, MAX_PLUTONIUM]. */
@state() private amount = 100;
@state() private busy = false;
createRenderRoot() {
return this;
@@ -36,73 +37,61 @@ export class CustomCurrencyCard extends LitElement {
this.amount = this.clamp(Number((e.target as HTMLInputElement).value));
}
private async buy() {
if (this.busy) return;
this.busy = true;
try {
const url = await createCustomCurrencyCheckout(this.amount);
if (url === false) {
alert(translateText("store.checkout_failed"));
return;
}
window.location.href = url;
} finally {
this.busy = false;
private buy = async () => {
const url = await createCustomCurrencyCheckout(this.amount);
if (url === false) {
alert(translateText("store.checkout_failed"));
return;
}
}
window.location.href = url;
};
render() {
const price = `$${this.priceDollars}`;
return html`
<div
class="relative flex flex-col items-center justify-between gap-2 p-3 w-48 rounded-xl border border-white/15 backdrop-blur-md"
style="background: linear-gradient(to top, rgba(80,80,80,0.55) 0%, rgba(15,15,20,0.85) 100%);"
<cosmetic-container
class="flex flex-col items-center justify-between gap-2 p-3 w-48 h-full"
.rarity=${"common"}
.name=${translateText("store.custom_amount")}
>
<div
class="text-xs font-bold uppercase tracking-wider text-center text-white/70 w-full"
class="relative flex flex-col items-center justify-center gap-1 w-full aspect-square bg-white/5 rounded-lg p-2 border border-white/10 overflow-hidden"
>
${translateText("store.custom_amount")}
</div>
<div class="flex flex-col items-center gap-2 w-full">
<plutonium-icon .size=${64}></plutonium-icon>
<span class="text-lg font-black text-green-400"
>${this.amount.toLocaleString()}</span
<label for="custom-plutonium-amount" class="sr-only"
>${translateText("store.plutonium_amount")}</label
>
<span class="text-[10px] font-bold text-white/50 uppercase"
>${translateText("cosmetics.hard")}</span
>
<input
type="range"
class="w-full accent-green-500 cursor-pointer"
min=${MIN_PLUTONIUM}
max=${MAX_PLUTONIUM}
step="1"
.value=${String(this.amount)}
@input=${this.onSlider}
/>
<input
id="custom-plutonium-amount"
type="number"
class="w-24 text-center bg-black/30 border border-white/20 rounded px-2 py-1 text-white text-sm"
aria-label=${translateText("store.custom_amount")}
class="custom-plutonium-input w-24 text-center bg-black/30 border border-green-500/30 rounded px-1 py-0.5 text-lg font-black text-green-400 outline-none focus:border-green-400 focus:ring-1 focus:ring-green-400/40"
aria-label=${translateText("store.plutonium_amount")}
min=${MIN_PLUTONIUM}
max=${MAX_PLUTONIUM}
step="1"
.value=${String(this.amount)}
@change=${this.onInputChange}
/>
<span class="text-[10px] font-bold text-white/50 uppercase"
>${translateText("cosmetics.hard")}</span
>
<input
type="range"
class="w-[90%] accent-green-500 cursor-pointer"
aria-label=${translateText("store.plutonium_amount")}
min=${MIN_PLUTONIUM}
max=${MAX_PLUTONIUM}
step="1"
.value=${String(this.amount)}
@input=${this.onSlider}
/>
</div>
<button
class="w-full mt-1 px-2 py-1.5 bg-green-500/20 text-green-400 border border-green-500/30 rounded-lg text-base font-bold cursor-pointer transition-all duration-200 hover:bg-green-500 hover:border-green-400 hover:text-white hover:shadow-[0_0_20px_rgba(74,222,128,0.6)] disabled:opacity-50 disabled:cursor-not-allowed"
?disabled=${this.busy}
@click=${this.buy}
>
${translateText("store.buy_for", { price })}
</button>
</div>
<purchase-button
.dollarPrice=${price}
.onPurchaseDollar=${this.buy}
></purchase-button>
</cosmetic-container>
`;
}
}
+10 -2
View File
@@ -184,6 +184,10 @@ export class PurchaseButton extends LitElement {
@property({ type: Object })
product: Product | null = null;
/** Price shown for a direct dollar checkout without a catalog product. */
@property({ type: String })
dollarPrice: string = "";
@property({ type: Number })
priceHard: number | null = null;
@@ -263,6 +267,9 @@ export class PurchaseButton extends LitElement {
}
private renderDollarButton() {
const price = this.dollarPrice || this.product?.price;
if (!price) return nothing;
return html`
<button
class="purchase-sparkle-btn relative overflow-hidden w-full px-2 py-1.5 bg-green-500/20 text-green-400 border border-green-500/30 rounded-lg text-base font-bold cursor-pointer transition-all duration-200
@@ -272,7 +279,7 @@ export class PurchaseButton extends LitElement {
<span class="purchase-sparkle-streak"></span>
${this.dollarLabelKey
? html`${translateText(this.dollarLabelKey)} `
: nothing}${this.product!.price}${this.priceSuffix}
: nothing}${price}${this.priceSuffix}
</button>
`;
}
@@ -310,7 +317,8 @@ export class PurchaseButton extends LitElement {
}
render() {
const hasDollar = this.product && this.onPurchaseDollar;
const hasDollar =
(this.product ?? this.dollarPrice) && this.onPurchaseDollar;
const hasHard = this.priceHard !== null && this.onPurchaseHard;
const hasSoft = this.priceSoft !== null && this.onPurchaseSoft;
+11
View File
@@ -58,6 +58,17 @@
color: var(--color-gray-400);
}
.custom-plutonium-input {
appearance: textfield;
-moz-appearance: textfield;
}
.custom-plutonium-input::-webkit-outer-spin-button,
.custom-plutonium-input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
button:not(:disabled),
[role="button"]:not(:disabled) {
cursor: pointer;