mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-12 07:43:55 +00:00
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:
@@ -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.",
|
||||
|
||||
@@ -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>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user