feat(pricing): link master keys to VK market products (v1.0.6)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ivan Fontosh
2026-09-13 15:38:16 +08:00
parent b79eaf6765
commit 96344a8d5e
6 changed files with 35 additions and 13 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "ttrpg-player-landing", "name": "ttrpg-player-landing",
"private": true, "private": true,
"version": "1.0.5", "version": "1.0.6",
"description": "Marketing landing for TTRPG Player (НРИ Плеер)", "description": "Marketing landing for TTRPG Player (НРИ Плеер)",
"type": "module", "type": "module",
"scripts": { "scripts": {
+5 -1
View File
@@ -1,4 +1,5 @@
import { import {
PRICING_TIER_BUY_URLS,
PRICING_TIER_IDS, PRICING_TIER_IDS,
RECOMMENDED_PRICING_TIER, RECOMMENDED_PRICING_TIER,
} from "../../data/siteContent"; } from "../../data/siteContent";
@@ -60,7 +61,10 @@ export function Pricing() {
<li key={feature}>{feature}</li> <li key={feature}>{feature}</li>
))} ))}
</ul> </ul>
<BuyButton variant={recommended ? "gold" : "secondary"}> <BuyButton
href={PRICING_TIER_BUY_URLS[id]}
variant={recommended ? "gold" : "secondary"}
>
{copy.cta.buy} {copy.cta.buy}
</BuyButton> </BuyButton>
</article> </article>
+3 -7
View File
@@ -1,28 +1,24 @@
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import { CROWDFUNDING_URL } from "../../data/siteContent";
import { Button } from "./Button"; import { Button } from "./Button";
type BuyButtonVariant = "primary" | "secondary" | "ghost" | "gold"; type BuyButtonVariant = "primary" | "secondary" | "ghost" | "gold";
type BuyButtonProps = { type BuyButtonProps = {
href: string;
children: ReactNode; children: ReactNode;
variant?: BuyButtonVariant; variant?: BuyButtonVariant;
className?: string; className?: string;
}; };
export function BuyButton({ export function BuyButton({
href,
children, children,
variant = "secondary", variant = "secondary",
className, className,
}: BuyButtonProps) { }: BuyButtonProps) {
return ( return (
<Button <Button href={href} variant={variant} className={className} newTab>
href={CROWDFUNDING_URL}
variant={variant}
className={className}
newTab
>
{children} {children}
</Button> </Button>
); );
+6
View File
@@ -103,6 +103,12 @@ export const PRICING_TIER_IDS = ["basic", "master", "legend"] as const;
export type PricingTierId = (typeof PRICING_TIER_IDS)[number]; export type PricingTierId = (typeof PRICING_TIER_IDS)[number];
export const PRICING_TIER_BUY_URLS = {
basic: "https://vk.ru/market/product/bazovy-klyuch-238917656-13366032",
master: "https://vk.ru/market/product/klyuch-mastera-238917656-13366158",
legend: "https://vk.ru/market/product/legenda-nri-238917656-13366160",
} as const satisfies Record<PricingTierId, string>;
export const RECOMMENDED_PRICING_TIER: PricingTierId = "master"; export const RECOMMENDED_PRICING_TIER: PricingTierId = "master";
export const FAQ_IDS = [ export const FAQ_IDS = [
+2 -2
View File
@@ -24,7 +24,7 @@ const ru = {
navAria: "Основная навигация", navAria: "Основная навигация",
cta: { cta: {
download: "Скачать", download: "Скачать",
buy: "Поддержать", buy: "Купить",
downloadFree: "Скачать бесплатно", downloadFree: "Скачать бесплатно",
buyLicense: "Поддержать проект", buyLicense: "Поддержать проект",
downloadForOs: "Скачать для моей ОС", downloadForOs: "Скачать для моей ОС",
@@ -294,7 +294,7 @@ const en: SiteCopy = {
navAria: "Main navigation", navAria: "Main navigation",
cta: { cta: {
download: "Download", download: "Download",
buy: "Support", buy: "Buy",
downloadFree: "Download free", downloadFree: "Download free",
buyLicense: "Support the project", buyLicense: "Support the project",
downloadForOs: "Download for my OS", downloadForOs: "Download for my OS",
+18 -2
View File
@@ -9,6 +9,7 @@ import {
FEATURE_VARIANTS, FEATURE_VARIANTS,
NAV_LINK_KEYS, NAV_LINK_KEYS,
NAV_HREFS, NAV_HREFS,
PRICING_TIER_BUY_URLS,
PRICING_TIER_IDS, PRICING_TIER_IDS,
RECOMMENDED_PRICING_TIER, RECOMMENDED_PRICING_TIER,
REQUIRED_SECTION_IDS, REQUIRED_SECTION_IDS,
@@ -76,6 +77,21 @@ describe("siteContent", () => {
assert.equal(VK_URL, "https://vk.com/ttrpgplayer"); assert.equal(VK_URL, "https://vk.com/ttrpgplayer");
}); });
it("maps each pricing tier to a VK market product url", () => {
assert.equal(
PRICING_TIER_BUY_URLS.basic,
"https://vk.ru/market/product/bazovy-klyuch-238917656-13366032",
);
assert.equal(
PRICING_TIER_BUY_URLS.master,
"https://vk.ru/market/product/klyuch-mastera-238917656-13366158",
);
assert.equal(
PRICING_TIER_BUY_URLS.legend,
"https://vk.ru/market/product/legenda-nri-238917656-13366160",
);
});
it("maps each feature variant to a screenshot asset", () => { it("maps each feature variant to a screenshot asset", () => {
for (const variant of FEATURE_VARIANTS) { for (const variant of FEATURE_VARIANTS) {
assert.match(SCREENSHOT_SRC[variant], /^\/images\/screenshot-.+\.png$/u); assert.match(SCREENSHOT_SRC[variant], /^\/images\/screenshot-.+\.png$/u);
@@ -103,8 +119,8 @@ describe("i18n messages", () => {
it("documents download and support labels in both locales", () => { it("documents download and support labels in both locales", () => {
assert.equal(MESSAGES.ru.cta.download, "Скачать"); assert.equal(MESSAGES.ru.cta.download, "Скачать");
assert.equal(MESSAGES.en.cta.download, "Download"); assert.equal(MESSAGES.en.cta.download, "Download");
assert.equal(MESSAGES.ru.cta.buy, "Поддержать"); assert.equal(MESSAGES.ru.cta.buy, "Купить");
assert.equal(MESSAGES.en.cta.buy, "Support"); assert.equal(MESSAGES.en.cta.buy, "Buy");
}); });
}); });