fix(payment): keep subscription plan titles readable

This commit is contained in:
BayinForge
2026-07-29 21:23:16 +08:00
parent 5a6143097d
commit 0ee9ea5765
3 changed files with 130 additions and 7 deletions
@@ -14,12 +14,12 @@
<!-- Header: name + badge + price -->
<div class="mb-3 flex items-start justify-between gap-2">
<div class="min-w-0 flex-1">
<div class="flex items-center gap-2">
<h3 class="truncate text-base font-bold text-gray-900 dark:text-white">{{ plan.name }}</h3>
<span :class="['shrink-0 rounded-full px-2 py-0.5 text-[11px] font-medium', badgeLightClass]">
{{ pLabel }}
</span>
</div>
<h3
:title="plan.name"
class="h-12 min-w-0 break-words [overflow-wrap:anywhere] text-base font-bold leading-6 text-gray-900 dark:text-white line-clamp-2"
>
{{ plan.name }}
</h3>
<p v-if="plan.description" class="mt-0.5 text-xs leading-relaxed text-gray-500 dark:text-dark-400 line-clamp-2">
{{ plan.description }}
</p>
@@ -30,7 +30,12 @@
<span :class="['text-2xl font-extrabold tracking-tight', textClass]">{{ plan.price }}</span>
<span v-if="plan.currency" class="text-xs font-medium text-gray-400 dark:text-dark-500">{{ plan.currency }}</span>
</div>
<span class="text-[11px] text-gray-400 dark:text-dark-500">/ {{ validitySuffix }}</span>
<div class="flex items-center justify-end gap-1">
<span :class="['inline-flex shrink-0 rounded-full px-2 py-0.5 text-[11px] font-medium', badgeLightClass]">
{{ pLabel }}
</span>
<span class="text-[11px] text-gray-400 dark:text-dark-500">/ {{ validitySuffix }}</span>
</div>
<div v-if="plan.original_price" class="mt-0.5 flex items-center justify-end gap-1.5">
<span class="text-xs text-gray-400 line-through dark:text-dark-500">{{ planCurrencySymbol }}{{ plan.original_price }}<template v-if="plan.currency"> {{ plan.currency }}</template></span>
<span :class="['rounded px-1 py-0.5 text-[10px] font-semibold', discountClass]">{{ discountText }}</span>
@@ -86,4 +86,66 @@ describe("SubscriptionPlanCard", () => {
expect(mountPlanCard("openai", { currency: "USD" }).text()).toContain("$10USD");
expect(mountPlanCard("openai", { currency: "" }).text()).toContain("$10");
});
it.each([
["long Chinese", "企业全球加速专业订阅套餐(含高级模型与优先支持)"],
["long English", "Enterprise Global Acceleration Subscription with Priority Support"],
["unbroken token", "EnterpriseGlobalAccelerationSubscriptionWithPrioritySupport1234567890"],
])("keeps the full %s plan title accessible in a bounded two-line area", (_label, name) => {
const wrapper = mountPlanCard("openai", { name });
const title = wrapper.get("h3");
expect(title.text()).toBe(name);
expect(title.attributes("title")).toBe(name);
expect(title.classes()).toEqual(expect.arrayContaining([
"min-w-0",
"h-12",
"break-words",
"line-clamp-2",
"[overflow-wrap:anywhere]",
]));
expect(title.classes()).not.toContain("truncate");
});
it("keeps title, badge, price, description, and purchase action in separate bounded regions", () => {
const wrapper = mountPlanCard("openai", {
name: "Enterprise Global Acceleration Subscription with Priority Support",
price: 123.45,
currency: "USD",
description: "Includes advanced models and priority support.",
});
const title = wrapper.get("h3");
const badge = wrapper.findAll("span").find((node) => node.text() === "OpenAI");
const price = wrapper.findAll("span").find((node) => node.text() === "123.45");
expect(title.element.parentElement?.classList).toContain("min-w-0");
expect(title.element.parentElement?.classList).toContain("flex-1");
expect(badge?.classes()).toContain("shrink-0");
expect([...(badge?.element.parentElement?.classList ?? [])]).toEqual(expect.arrayContaining([
"flex",
"items-center",
"justify-end",
]));
expect(badge?.element.parentElement?.textContent).toContain("/ 30payment.days");
expect(badge?.element.parentElement?.parentElement?.classList).toContain("shrink-0");
expect(price?.element.parentElement?.parentElement?.classList).toContain("shrink-0");
expect(wrapper.get("p").text()).toBe("Includes advanced models and priority support.");
expect(wrapper.get("button").text()).toBe("payment.subscribeNow");
});
it("keeps short plan titles compact and aligned", () => {
const wrapper = mountPlanCard("openai", { name: "Pro", description: "" });
const title = wrapper.get("h3");
const badge = wrapper.findAll("span").find((node) => node.text() === "OpenAI");
expect(title.text()).toBe("Pro");
expect(title.attributes("title")).toBe("Pro");
expect(title.classes()).toEqual(expect.arrayContaining(["text-base", "font-bold", "h-12"]));
expect([...(badge?.element.parentElement?.classList ?? [])]).toEqual(expect.arrayContaining([
"flex",
"items-center",
"justify-end",
]));
expect(badge?.element.parentElement?.textContent).toContain("/ 30payment.days");
});
});