Polish landing copy, footer links, and buy button behavior.
Rewrite feature descriptions in narrative style, open buy links in a new tab, update support email, rename key action to Choose key, and remove privacy policy from the footer. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -9,7 +9,6 @@ const FOOTER_LINK_KEYS = [
|
||||
"faq",
|
||||
"enterKey",
|
||||
"support",
|
||||
"privacy",
|
||||
] as const;
|
||||
|
||||
const FOOTER_HREFS: Record<(typeof FOOTER_LINK_KEYS)[number], string> = {
|
||||
@@ -18,7 +17,6 @@ const FOOTER_HREFS: Record<(typeof FOOTER_LINK_KEYS)[number], string> = {
|
||||
faq: SITE_LINKS.faq,
|
||||
enterKey: SITE_LINKS.enterKey,
|
||||
support: SITE_LINKS.support,
|
||||
privacy: SITE_LINKS.privacy,
|
||||
};
|
||||
|
||||
export function Footer() {
|
||||
@@ -30,7 +28,14 @@ export function Footer() {
|
||||
<p className={styles.copy}>© TTRPGPlayer</p>
|
||||
<nav className={styles.links} aria-label={copy.footer.aria}>
|
||||
{FOOTER_LINK_KEYS.map((key) => (
|
||||
<a key={key} className={styles.link} href={FOOTER_HREFS[key]}>
|
||||
<a
|
||||
key={key}
|
||||
className={styles.link}
|
||||
href={FOOTER_HREFS[key]}
|
||||
{...(key === "buy"
|
||||
? { target: "_blank", rel: "noopener noreferrer" }
|
||||
: undefined)}
|
||||
>
|
||||
{copy.footer.links[key]}
|
||||
</a>
|
||||
))}
|
||||
|
||||
@@ -43,6 +43,7 @@ export function Header() {
|
||||
href={SITE_LINKS.buy}
|
||||
variant="secondary"
|
||||
className={styles.actionBtn}
|
||||
newTab
|
||||
>
|
||||
{copy.cta.buy}
|
||||
</Button>
|
||||
|
||||
@@ -13,7 +13,7 @@ export function CtaBanner() {
|
||||
<h2 className={styles.title}>{copy.ctaBanner.title}</h2>
|
||||
<div className={styles.actions}>
|
||||
<Button href={SITE_LINKS.download}>{copy.cta.download}</Button>
|
||||
<Button href={SITE_LINKS.buy} variant="secondary">
|
||||
<Button href={SITE_LINKS.buy} variant="secondary" newTab>
|
||||
{copy.cta.buyLicense}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -25,7 +25,7 @@ export function Hero() {
|
||||
|
||||
<div className={styles.cta}>
|
||||
<Button href={SITE_LINKS.download}>{copy.cta.downloadFree}</Button>
|
||||
<Button href={SITE_LINKS.buy} variant="secondary">
|
||||
<Button href={SITE_LINKS.buy} variant="secondary" newTab>
|
||||
{copy.cta.buyLicense}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -64,6 +64,7 @@ export function Pricing() {
|
||||
<Button
|
||||
href={SITE_LINKS.buy}
|
||||
variant={recommended ? "gold" : "secondary"}
|
||||
newTab
|
||||
>
|
||||
{copy.cta.buy}
|
||||
</Button>
|
||||
|
||||
@@ -11,6 +11,7 @@ type ButtonProps = {
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
type?: "button" | "submit";
|
||||
newTab?: boolean;
|
||||
};
|
||||
|
||||
function join(...parts: (string | undefined)[]): string {
|
||||
@@ -24,12 +25,19 @@ export function Button({
|
||||
className,
|
||||
onClick,
|
||||
type = "button",
|
||||
newTab = false,
|
||||
}: ButtonProps) {
|
||||
const cls = join(styles.button, styles[variant], className);
|
||||
|
||||
if (href) {
|
||||
return (
|
||||
<a className={cls} href={href}>
|
||||
<a
|
||||
className={cls}
|
||||
href={href}
|
||||
{...(newTab
|
||||
? { target: "_blank", rel: "noopener noreferrer" }
|
||||
: undefined)}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
|
||||
@@ -7,8 +7,7 @@ export const SITE_LINKS = {
|
||||
download: "#platforms",
|
||||
buy: "https://donate.stream/ttrpgplayer",
|
||||
enterKey: "#pricing",
|
||||
support: "mailto:support@ttrpgplayer.example",
|
||||
privacy: "#",
|
||||
support: "mailto:fontosh.ivan@gmail.com",
|
||||
} as const;
|
||||
|
||||
/** Same feed as electron-builder `publish.url` in dnd_player/package.json */
|
||||
|
||||
+22
-24
@@ -118,26 +118,26 @@ const ru = {
|
||||
editor: {
|
||||
title: "Редактор кампаний",
|
||||
description:
|
||||
"Граф сцен и переходов, ветвления, превью медиа, музыка сцены и кампании, импорт и экспорт .ttrpg.zip, поиск и управление медиа.",
|
||||
tags: "Граф сцен · переходы · медиа",
|
||||
"Планируйте кампанию как граф сцен: связывайте локации, закладывайте развилки сюжета, прикрепляйте карты и музыку — и собирайте материалы партии до первого броска костей.",
|
||||
tags: "Граф сцен · ветвления · медиа",
|
||||
},
|
||||
control: {
|
||||
title: "Пульт управления",
|
||||
description:
|
||||
"Переключение сцен одной кнопкой, предпросмотр экрана игроков, сюжетная линия, авто- и ручное управление музыкой, запуск и остановка демонстрации.",
|
||||
tags: "Переключить · музыка · сюжетная линия",
|
||||
"Ведите сессию из одного окна: переключайте сцены, следите за экраном игроков, держите ход сюжета под рукой и управляйте музыкой, пока стол ждёт вашего следующего хода.",
|
||||
tags: "Сцены · музыка · сюжетная линия",
|
||||
},
|
||||
presentation: {
|
||||
title: "Экран презентации",
|
||||
description:
|
||||
"Отдельное окно для второго монитора, проектора или ТВ. Только карта или видео сцены, синхронные эффекты и оверлеи, поддержка поворота 0°/90°/180°/270°.",
|
||||
tags: "Карта · видео · второй монитор",
|
||||
"Вынесите карту и атмосферу на второй монитор, проектор или ТВ — игроки видят только задуманное для сцены, без панелей редактора, с поворотом экрана под ваш стол.",
|
||||
tags: "Второй экран · карта · атмосфера",
|
||||
},
|
||||
atmosphere: {
|
||||
title: "Атмосфера за столом",
|
||||
description:
|
||||
"Туман, дождь, огонь, вода, молния, луч света, заморозка, облако яда, эффекты действий, кисть мастера, ластик, очистка эффектов и музыка сцены плюс фон кампании.",
|
||||
tags: "Туман · дождь · огонь · кисть",
|
||||
"Оживите карту погодой и светом, дорисуйте от руки то, что видят игроки, и меняйте настроение сцены музыкой — от тихой таверны до грозы над полем боя.",
|
||||
tags: "Погода · свет · музыка сцены",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -173,7 +173,7 @@ const ru = {
|
||||
pricing: {
|
||||
title: "Выберите ключ мастера",
|
||||
subtitle:
|
||||
"Активируйте продуктовый ключ в приложении: Настройки → Указать ключ",
|
||||
"Активируйте продуктовый ключ в приложении: Настройки → Выбрать ключ",
|
||||
recommendedBadge: "⭐ Рекомендуем",
|
||||
tiers: {
|
||||
basic: {
|
||||
@@ -225,7 +225,7 @@ const ru = {
|
||||
activate: {
|
||||
question: "Как активировать лицензию?",
|
||||
answer:
|
||||
"В приложении откройте Настройки → Указать ключ и вставьте ключ формата TTRPG-….",
|
||||
"В приложении откройте Настройки → Выбрать ключ и вставьте ключ формата TTRPG-….",
|
||||
},
|
||||
os: {
|
||||
question: "На каких ОС работает приложение?",
|
||||
@@ -243,9 +243,8 @@ const ru = {
|
||||
download: "Скачать",
|
||||
buy: "Купить",
|
||||
faq: "FAQ",
|
||||
enterKey: "Указать ключ",
|
||||
enterKey: "Выбрать ключ",
|
||||
support: "Поддержка",
|
||||
privacy: "Политика конфиденциальности",
|
||||
},
|
||||
},
|
||||
localeSwitcher: {
|
||||
@@ -373,26 +372,26 @@ const en: SiteCopy = {
|
||||
editor: {
|
||||
title: "Campaign editor",
|
||||
description:
|
||||
"Scene graph and transitions, branching, media previews, scene and campaign audio, import and export of .ttrpg.zip, search and media management.",
|
||||
tags: "Scene graph · transitions · media",
|
||||
"Plan your campaign as a scene graph: link locations, lay out story branches, attach maps and music — and gather session materials before the first roll.",
|
||||
tags: "Scene graph · branching · media",
|
||||
},
|
||||
control: {
|
||||
title: "Control panel",
|
||||
description:
|
||||
"One-click scene switching, player screen preview, story timeline, automatic and manual music control, start and stop presentation.",
|
||||
tags: "Switch · music · story line",
|
||||
"Run the session from one window: switch scenes, watch the player screen, keep the story beat at hand and control music while the table waits for your next move.",
|
||||
tags: "Scenes · music · story line",
|
||||
},
|
||||
presentation: {
|
||||
title: "Presentation screen",
|
||||
description:
|
||||
"Separate window for a second monitor, projector or TV. Scene map or video only, synced effects and overlays, rotation 0°/90°/180°/270°.",
|
||||
tags: "Map · video · second monitor",
|
||||
"Send the map and atmosphere to a second monitor, projector or TV — players see only what the scene calls for, with no editor panels and rotation to fit your table setup.",
|
||||
tags: "Second screen · map · atmosphere",
|
||||
},
|
||||
atmosphere: {
|
||||
title: "Atmosphere at the table",
|
||||
description:
|
||||
"Fog, rain, fire, water, lightning, sunbeam, freeze, poison cloud, action effects, GM brush, eraser, clear effects, scene music plus campaign ambience.",
|
||||
tags: "Fog · rain · fire · brush",
|
||||
"Bring the map to life with weather and light, sketch what players see by hand, and shift the mood with scene music — from a quiet tavern to a storm over the battlefield.",
|
||||
tags: "Weather · light · scene music",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -427,7 +426,7 @@ const en: SiteCopy = {
|
||||
},
|
||||
pricing: {
|
||||
title: "Choose your GM key",
|
||||
subtitle: "Activate your product key in the app: Settings → Enter key",
|
||||
subtitle: "Activate your product key in the app: Settings → Choose key",
|
||||
recommendedBadge: "⭐ Recommended",
|
||||
tiers: {
|
||||
basic: {
|
||||
@@ -479,7 +478,7 @@ const en: SiteCopy = {
|
||||
activate: {
|
||||
question: "How do I activate a license?",
|
||||
answer:
|
||||
"In the app, open Settings → Enter key and paste a key in the TTRPG-… format.",
|
||||
"In the app, open Settings → Choose key and paste a key in the TTRPG-… format.",
|
||||
},
|
||||
os: {
|
||||
question: "Which operating systems are supported?",
|
||||
@@ -496,9 +495,8 @@ const en: SiteCopy = {
|
||||
download: "Download",
|
||||
buy: "Buy",
|
||||
faq: "FAQ",
|
||||
enterKey: "Enter key",
|
||||
enterKey: "Choose key",
|
||||
support: "Support",
|
||||
privacy: "Privacy policy",
|
||||
},
|
||||
},
|
||||
localeSwitcher: {
|
||||
|
||||
Reference in New Issue
Block a user