Compare commits

...

2 Commits

19 changed files with 686 additions and 77 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 716 KiB

After

Width:  |  Height:  |  Size: 414 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 402 KiB

After

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 602 KiB

After

Width:  |  Height:  |  Size: 316 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 928 KiB

After

Width:  |  Height:  |  Size: 473 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 848 KiB

After

Width:  |  Height:  |  Size: 880 KiB

Binary file not shown.

View File

@@ -12,10 +12,16 @@ const imageClasses = ['experience-card__image--one', 'experience-card__image--tw
<section id="experience" class="experience"> <section id="experience" class="experience">
<div class="experience__inner"> <div class="experience__inner">
<div class="experience__heading">
<p class="experience__title"> <p class="experience__title">
{t.title} {t.title}
</p> </p>
<p class="experience__caption">
{t.caption}
</p>
</div>
<div class="experience__body"> <div class="experience__body">
<div class="experience__grid"> <div class="experience__grid">
{t.cards.map((card, index) => ( {t.cards.map((card, index) => (
@@ -36,10 +42,6 @@ const imageClasses = ['experience-card__image--one', 'experience-card__image--tw
</div> </div>
))} ))}
</div> </div>
<p class="experience__caption">
{t.caption}
</p>
</div> </div>
</div> </div>
</section> </section>

View File

@@ -13,7 +13,7 @@ const icons = [
"/assets/why-icon-connected.svg", "/assets/why-icon-connected.svg",
"/assets/why-icon-modern.svg", "/assets/why-icon-modern.svg",
] ]
const iconClasses = ['why-card__icon--square', 'why-card__icon--familiar', 'why-card__icon--square', 'why-card__icon--modern'] const iconClasses = ['why-card__icon--simple', 'why-card__icon--familiar', 'why-card__icon--connected', 'why-card__icon--modern']
--- ---
<section class="why"> <section class="why">

View File

@@ -1,4 +1,20 @@
export const languages = ["en", "zh-cn", "zh-tw", "ms", "ja", "ko"] as const; export const languages = [
"en",
"zh-cn",
"zh-tw",
"es",
"vi",
"ja",
"ko",
"pt",
"de",
"fr",
"hi",
"ar",
"ru",
"id",
"ur",
] as const;
export type Lang = (typeof languages)[number]; export type Lang = (typeof languages)[number];
@@ -8,18 +24,36 @@ export const languageLabels: Record<Lang, string> = {
en: "EN", en: "EN",
"zh-cn": "简中", "zh-cn": "简中",
"zh-tw": "繁中", "zh-tw": "繁中",
ms: "MS", es: "ES",
vi: "VI",
ja: "日本語", ja: "日本語",
ko: "한국어", ko: "한국어",
pt: "PT",
de: "DE",
fr: "FR",
hi: "हिन्दी",
ar: "العربية",
ru: "RU",
id: "ID",
ur: "اردو",
}; };
export const languageNames: Record<Lang, string> = { export const languageNames: Record<Lang, string> = {
en: "English", en: "English",
"zh-cn": "简体中文", "zh-cn": "简体中文",
"zh-tw": "繁體中文", "zh-tw": "繁體中文",
ms: "Bahasa Melayu", es: "Español",
vi: "Tiếng Việt",
ja: "日本語", ja: "日本語",
ko: "한국어", ko: "한국어",
pt: "Português",
de: "Deutsch",
fr: "Français",
hi: "हिन्दी",
ar: "العربية الفصحى",
ru: "Русский",
id: "Bahasa Indonesia",
ur: "اردو",
}; };
export function isLang(value: string | undefined): value is Lang { export function isLang(value: string | undefined): value is Lang {
@@ -30,6 +64,39 @@ export function getLocalePath(lang: Lang) {
return lang === defaultLang ? "/" : `/${lang}/`; return lang === defaultLang ? "/" : `/${lang}/`;
} }
const mergeTranslations = <T extends Record<string, unknown>>(base: T, override?: DeepPartial<T>): T => {
if (!override) return base;
const result = { ...base } as Record<string, unknown>;
Object.entries(override).forEach(([key, value]) => {
const baseValue = result[key];
if (
value &&
typeof value === "object" &&
!Array.isArray(value) &&
baseValue &&
typeof baseValue === "object" &&
!Array.isArray(baseValue)
) {
result[key] = mergeTranslations(baseValue as Record<string, unknown>, value as Record<string, unknown>);
} else if (value !== undefined) {
result[key] = value;
}
});
return result as T;
};
type DeepPartial<T> = {
[K in keyof T]?: T[K] extends Array<infer U>
? Array<DeepPartial<U>>
: T[K] extends Record<string, unknown>
? DeepPartial<T[K]>
: T[K];
};
export const translations = { export const translations = {
en: { en: {
meta: { meta: {
@@ -234,6 +301,98 @@ export const translations = {
legal: "Terms of Use · Privacy Policy · Support", legal: "Terms of Use · Privacy Policy · Support",
}, },
}, },
es: {
meta: {
title: "Talk Pro - Un usuario. Múltiples mundos.",
description:
"Talk Pro es una aplicación moderna de mensajería para chats privados, conversaciones grupales, canales, llamadas de voz y videollamadas.",
},
header: {
navLabel: "Navegación principal",
languageAlt: "Idioma",
openMenu: "Abrir menú",
closeMenu: "Cerrar menú",
nav: {
home: "Inicio",
features: "Funciones",
experience: "Experiencia",
useCases: "Casos de uso",
reliability: "Fiabilidad",
},
download: "Descargar",
},
hero: {
badge: "✦ Disponible en iOS y Android",
titleLine1: "Una forma moderna de",
titleLine2: "mantenerse conectado",
description:
"TalkPro es una aplicación moderna de mensajería diseñada para una comunicación clara, simple y confiable.",
tags: ["Capa de identidad", "Mensajería con IA", "Privacidad adaptativa"],
},
download: {
eyebrow: "DESCARGAR",
title: "Descargar",
description:
"Descarga TalkPro y vive una forma más limpia, simple y moderna de mantenerte conectado.",
android: "ANDROID",
androidCta: "APK próximamente",
ios: "IOS",
iosCta: "Consíguelo en App Store",
},
footer: {
links: { download: "Descargar", features: "Funciones", about: "Acerca de", contact: "Contacto" },
android: "ANDROID",
ios: "IOS",
copyright: "© 2026 TalkPro. Todos los derechos reservados.",
legal: "Términos de uso · Política de privacidad · Soporte",
},
},
vi: {
meta: {
title: "Talk Pro - Một người dùng. Nhiều thế giới.",
description:
"Talk Pro là ứng dụng nhắn tin hiện đại cho trò chuyện riêng tư, nhóm, kênh, cuộc gọi thoại và video.",
},
header: {
navLabel: "Điều hướng chính",
languageAlt: "Ngôn ngữ",
openMenu: "Mở menu",
closeMenu: "Đóng menu",
nav: {
home: "Trang chủ",
features: "Tính năng",
experience: "Trải nghiệm",
useCases: "Trường hợp dùng",
reliability: "Độ tin cậy",
},
download: "Tải xuống",
},
hero: {
badge: "✦ Có trên iOS và Android",
titleLine1: "Cách hiện đại để",
titleLine2: "luôn kết nối",
description:
"TalkPro là ứng dụng nhắn tin hiện đại được thiết kế cho giao tiếp rõ ràng, đơn giản và đáng tin cậy.",
tags: ["Lớp danh tính", "Nhắn tin AI native", "Quyền riêng tư thích ứng"],
},
download: {
eyebrow: "TẢI XUỐNG",
title: "Tải xuống",
description:
"Tải TalkPro và trải nghiệm cách kết nối sạch hơn, đơn giản hơn và hiện đại hơn.",
android: "ANDROID",
androidCta: "APK sắp ra mắt",
ios: "IOS",
iosCta: "Tải trên App Store",
},
footer: {
links: { download: "Tải xuống", features: "Tính năng", about: "Giới thiệu", contact: "Liên hệ" },
android: "ANDROID",
ios: "IOS",
copyright: "© 2026 TalkPro. Bảo lưu mọi quyền.",
legal: "Điều khoản sử dụng · Chính sách quyền riêng tư · Hỗ trợ",
},
},
"zh-cn": { "zh-cn": {
meta: { meta: {
title: "Talk Pro - 一个用户,多重场景。", title: "Talk Pro - 一个用户,多重场景。",
@@ -369,7 +528,7 @@ export const translations = {
title: "下载", title: "下载",
logoAlt: "TalkPro", logoAlt: "TalkPro",
description: "下载 TalkPro体验更清晰、更简单、更现代的连接方式。", description: "下载 TalkPro体验更清晰、更简单、更现代的连接方式。",
android: "ANDROID", android: "安卓",
androidCta: "APK 即将推出", androidCta: "APK 即将推出",
ios: "IOS", ios: "IOS",
iosCta: "在 App Store 上获取", iosCta: "在 App Store 上获取",
@@ -389,7 +548,7 @@ export const translations = {
}, },
email: "email@hotmail.com", email: "email@hotmail.com",
phone: "+01 123 45562334", phone: "+01 123 45562334",
android: "ANDROID", android: "安卓",
androidCta: "APK 即将推出", androidCta: "APK 即将推出",
ios: "IOS", ios: "IOS",
iosCta: "在 App Store 上获取", iosCta: "在 App Store 上获取",
@@ -532,7 +691,7 @@ export const translations = {
title: "下載", title: "下載",
logoAlt: "TalkPro", logoAlt: "TalkPro",
description: "下載 TalkPro體驗更清晰、更簡單、更現代的連結方式。", description: "下載 TalkPro體驗更清晰、更簡單、更現代的連結方式。",
android: "ANDROID", android: "安卓",
androidCta: "APK 即將推出", androidCta: "APK 即將推出",
ios: "IOS", ios: "IOS",
iosCta: "在 App Store 上取得", iosCta: "在 App Store 上取得",
@@ -552,7 +711,7 @@ export const translations = {
}, },
email: "email@hotmail.com", email: "email@hotmail.com",
phone: "+01 123 45562334", phone: "+01 123 45562334",
android: "ANDROID", android: "安卓",
androidCta: "APK 即將推出", androidCta: "APK 即將推出",
ios: "IOS", ios: "IOS",
iosCta: "在 App Store 上取得", iosCta: "在 App Store 上取得",
@@ -1141,7 +1300,7 @@ export const translations = {
logoAlt: "TalkPro", logoAlt: "TalkPro",
description: description:
"TalkPro를 다운로드하고 더 깔끔하고 단순하며 현대적인 연결 방식을 경험하세요.", "TalkPro를 다운로드하고 더 깔끔하고 단순하며 현대적인 연결 방식을 경험하세요.",
android: "ANDROID", android: "안드로이드",
androidCta: "APK 곧 출시", androidCta: "APK 곧 출시",
ios: "IOS", ios: "IOS",
iosCta: "App Store에서 받기", iosCta: "App Store에서 받기",
@@ -1161,7 +1320,7 @@ export const translations = {
}, },
email: "email@hotmail.com", email: "email@hotmail.com",
phone: "+01 123 45562334", phone: "+01 123 45562334",
android: "ANDROID", android: "안드로이드",
androidCta: "APK 곧 출시", androidCta: "APK 곧 출시",
ios: "IOS", ios: "IOS",
iosCta: "App Store에서 받기", iosCta: "App Store에서 받기",
@@ -1169,10 +1328,330 @@ export const translations = {
legal: "이용 약관 · 개인정보 처리방침 · 지원", legal: "이용 약관 · 개인정보 처리방침 · 지원",
}, },
}, },
pt: {
meta: {
title: "Talk Pro - Um usuário. Múltiplos mundos.",
description:
"Talk Pro é um aplicativo moderno de mensagens para conversas privadas, grupos, canais, chamadas de voz e vídeo.",
},
header: {
navLabel: "Navegação principal",
languageAlt: "Idioma",
openMenu: "Abrir menu",
closeMenu: "Fechar menu",
nav: { home: "Início", features: "Recursos", experience: "Experiência", useCases: "Casos de uso", reliability: "Confiabilidade" },
download: "Baixar",
},
hero: {
badge: "✦ Disponível para iOS e Android",
titleLine1: "Uma forma moderna de",
titleLine2: "ficar conectado",
description:
"TalkPro é um aplicativo moderno de mensagens criado para comunicação clara, simples e confiável.",
tags: ["Camada de identidade", "Mensagens com IA", "Privacidade adaptativa"],
},
download: {
eyebrow: "BAIXAR",
title: "Baixar",
description:
"Baixe o TalkPro e experimente uma forma mais limpa, simples e moderna de se conectar.",
android: "ANDROID",
androidCta: "APK em breve",
ios: "IOS",
iosCta: "Baixar na App Store",
},
footer: {
links: { download: "Baixar", features: "Recursos", about: "Sobre", contact: "Contato" },
android: "ANDROID",
ios: "IOS",
copyright: "© 2026 TalkPro. Todos os direitos reservados.",
legal: "Termos de uso · Política de privacidade · Suporte",
},
},
de: {
meta: {
title: "Talk Pro - Ein Nutzer. Mehrere Welten.",
description:
"Talk Pro ist eine moderne Messaging-App für private Chats, Gruppen, Kanäle, Sprach- und Videoanrufe.",
},
header: {
navLabel: "Hauptnavigation",
languageAlt: "Sprache",
openMenu: "Menü öffnen",
closeMenu: "Menü schließen",
nav: { home: "Start", features: "Funktionen", experience: "Erlebnis", useCases: "Anwendungsfälle", reliability: "Zuverlässigkeit" },
download: "Herunterladen",
},
hero: {
badge: "✦ Verfügbar für iOS und Android",
titleLine1: "Eine moderne Art,",
titleLine2: "verbunden zu bleiben",
description:
"TalkPro ist eine moderne Messaging-App für klare, einfache und zuverlässige Kommunikation.",
tags: ["Identitätsebene", "KI-native Nachrichten", "Adaptive Privatsphäre"],
},
download: {
eyebrow: "DOWNLOAD",
title: "Herunterladen",
description:
"Lade TalkPro herunter und erlebe eine klarere, einfachere und modernere Art, verbunden zu bleiben.",
android: "ANDROID",
androidCta: "APK bald verfügbar",
ios: "IOS",
iosCta: "Im App Store laden",
},
footer: {
links: { download: "Download", features: "Funktionen", about: "Über uns", contact: "Kontakt" },
android: "ANDROID",
ios: "IOS",
copyright: "© 2026 TalkPro. Alle Rechte vorbehalten.",
legal: "Nutzungsbedingungen · Datenschutzrichtlinie · Support",
},
},
fr: {
meta: {
title: "Talk Pro - Un utilisateur. Plusieurs mondes.",
description:
"Talk Pro est une application de messagerie moderne pour les discussions privées, les groupes, les canaux, les appels vocaux et vidéo.",
},
header: {
navLabel: "Navigation principale",
languageAlt: "Langue",
openMenu: "Ouvrir le menu",
closeMenu: "Fermer le menu",
nav: { home: "Accueil", features: "Fonctionnalités", experience: "Expérience", useCases: "Cas dusage", reliability: "Fiabilité" },
download: "Télécharger",
},
hero: {
badge: "✦ Disponible sur iOS et Android",
titleLine1: "Une façon moderne de",
titleLine2: "rester connecté",
description:
"TalkPro est une application de messagerie moderne conçue pour une communication claire, simple et fiable.",
tags: ["Couche didentité", "Messagerie native IA", "Confidentialité adaptative"],
},
download: {
eyebrow: "TÉLÉCHARGER",
title: "Télécharger",
description:
"Téléchargez TalkPro et découvrez une façon plus claire, simple et moderne de rester connecté.",
android: "ANDROID",
androidCta: "APK bientôt disponible",
ios: "IOS",
iosCta: "Disponible sur lApp Store",
},
footer: {
links: { download: "Télécharger", features: "Fonctionnalités", about: "À propos", contact: "Contact" },
android: "ANDROID",
ios: "IOS",
copyright: "© 2026 TalkPro. Tous droits réservés.",
legal: "Conditions dutilisation · Politique de confidentialité · Support",
},
},
hi: {
meta: {
title: "Talk Pro - एक उपयोगकर्ता. कई दुनिया.",
description:
"Talk Pro निजी चैट, समूह बातचीत, चैनल, वॉइस कॉल और वीडियो कॉल के लिए एक आधुनिक मैसेजिंग ऐप है।",
},
header: {
navLabel: "मुख्य नेविगेशन",
languageAlt: "भाषा",
openMenu: "मेनू खोलें",
closeMenu: "मेनू बंद करें",
nav: { home: "होम", features: "फ़ीचर", experience: "अनुभव", useCases: "उपयोग", reliability: "विश्वसनीयता" },
download: "डाउनलोड",
},
hero: {
badge: "✦ iOS और Android पर उपलब्ध",
titleLine1: "जुड़े रहने का",
titleLine2: "आधुनिक तरीका",
description:
"TalkPro स्पष्ट, सरल और भरोसेमंद संचार के लिए बनाया गया एक आधुनिक मैसेजिंग ऐप है।",
tags: ["पहचान परत", "AI नेटिव मैसेजिंग", "अनुकूल गोपनीयता"],
},
download: {
eyebrow: "डाउनलोड",
title: "डाउनलोड",
description:
"TalkPro डाउनलोड करें और जुड़े रहने का साफ, सरल और आधुनिक तरीका अनुभव करें।",
android: "एंड्रॉयड",
androidCta: "APK जल्द आ रहा है",
ios: "IOS",
iosCta: "App Store से पाएं",
},
footer: {
links: { download: "डाउनलोड", features: "फ़ीचर", about: "परिचय", contact: "संपर्क" },
android: "एंड्रॉयड",
ios: "IOS",
copyright: "© 2026 TalkPro. सर्वाधिकार सुरक्षित.",
legal: "उपयोग की शर्तें · गोपनीयता नीति · सहायता",
},
},
ar: {
meta: {
title: "Talk Pro - مستخدم واحد. عوالم متعددة.",
description:
"Talk Pro تطبيق مراسلة حديث للمحادثات الخاصة والمجموعات والقنوات والمكالمات الصوتية ومكالمات الفيديو.",
},
header: {
navLabel: "التنقل الرئيسي",
languageAlt: "اللغة",
openMenu: "فتح القائمة",
closeMenu: "إغلاق القائمة",
nav: { home: "الرئيسية", features: "الميزات", experience: "التجربة", useCases: "الاستخدامات", reliability: "الموثوقية" },
download: "تنزيل",
},
hero: {
badge: "✦ متوفر على iOS و Android",
titleLine1: "طريقة حديثة",
titleLine2: "للبقاء على اتصال",
description:
"TalkPro تطبيق مراسلة حديث مصمم لتواصل واضح وبسيط وموثوق.",
tags: ["طبقة الهوية", "مراسلة مدعومة بالذكاء الاصطناعي", "خصوصية تكيفية"],
},
download: {
eyebrow: "تنزيل",
title: "تنزيل",
description:
"نزّل TalkPro واختبر طريقة أوضح وأبسط وأكثر حداثة للبقاء على اتصال.",
android: "أندرويد",
androidCta: "APK قريبًا",
ios: "آي أو إس",
iosCta: "احصل عليه من App Store",
},
footer: {
links: { download: "تنزيل", features: "الميزات", about: "حول", contact: "اتصال" },
android: "أندرويد",
ios: "آي أو إس",
copyright: "© 2026 TalkPro. جميع الحقوق محفوظة.",
legal: "شروط الاستخدام · سياسة الخصوصية · الدعم",
},
},
ru: {
meta: {
title: "Talk Pro - Один пользователь. Несколько миров.",
description:
"Talk Pro — современное приложение для личных чатов, групп, каналов, голосовых и видеозвонков.",
},
header: {
navLabel: "Основная навигация",
languageAlt: "Язык",
openMenu: "Открыть меню",
closeMenu: "Закрыть меню",
nav: { home: "Главная", features: "Функции", experience: "Опыт", useCases: "Сценарии", reliability: "Надежность" },
download: "Скачать",
},
hero: {
badge: "✦ Доступно на iOS и Android",
titleLine1: "Современный способ",
titleLine2: "оставаться на связи",
description:
"TalkPro — современное приложение для ясного, простого и надежного общения.",
tags: ["Уровень идентичности", "AI-мессенджинг", "Адаптивная приватность"],
},
download: {
eyebrow: "СКАЧАТЬ",
title: "Скачать",
description:
"Скачайте TalkPro и попробуйте более чистый, простой и современный способ общения.",
android: "Андроид",
androidCta: "APK скоро",
ios: "IOS",
iosCta: "Загрузить в App Store",
},
footer: {
links: { download: "Скачать", features: "Функции", about: "О нас", contact: "Контакты" },
android: "Андроид",
ios: "IOS",
copyright: "© 2026 TalkPro. Все права защищены.",
legal: "Условия использования · Политика конфиденциальности · Поддержка",
},
},
id: {
meta: {
title: "Talk Pro - Satu pengguna. Banyak dunia.",
description:
"Talk Pro adalah aplikasi pesan modern untuk chat pribadi, grup, kanal, panggilan suara, dan panggilan video.",
},
header: {
navLabel: "Navigasi utama",
languageAlt: "Bahasa",
openMenu: "Buka menu",
closeMenu: "Tutup menu",
nav: { home: "Beranda", features: "Fitur", experience: "Pengalaman", useCases: "Penggunaan", reliability: "Keandalan" },
download: "Unduh",
},
hero: {
badge: "✦ Tersedia di iOS dan Android",
titleLine1: "Cara modern untuk",
titleLine2: "tetap terhubung",
description:
"TalkPro adalah aplikasi pesan modern yang dirancang untuk komunikasi yang jelas, sederhana, dan andal.",
tags: ["Lapisan identitas", "Pesan AI native", "Privasi adaptif"],
},
download: {
eyebrow: "UNDUH",
title: "Unduh",
description:
"Unduh TalkPro dan rasakan cara yang lebih bersih, sederhana, dan modern untuk tetap terhubung.",
android: "ANDROID",
androidCta: "APK segera hadir",
ios: "IOS",
iosCta: "Dapatkan di App Store",
},
footer: {
links: { download: "Unduh", features: "Fitur", about: "Tentang", contact: "Kontak" },
android: "ANDROID",
ios: "IOS",
copyright: "© 2026 TalkPro. Hak cipta dilindungi.",
legal: "Ketentuan Penggunaan · Kebijakan Privasi · Dukungan",
},
},
ur: {
meta: {
title: "Talk Pro - ایک صارف۔ کئی دنیائیں۔",
description:
"Talk Pro نجی چیٹس، گروپ گفتگو، چینلز، وائس کالز اور ویڈیو کالز کے لیے ایک جدید میسجنگ ایپ ہے۔",
},
header: {
navLabel: "مرکزی نیویگیشن",
languageAlt: "زبان",
openMenu: "مینو کھولیں",
closeMenu: "مینو بند کریں",
nav: { home: "ہوم", features: "خصوصیات", experience: "تجربہ", useCases: "استعمال", reliability: "اعتماد" },
download: "ڈاؤن لوڈ",
},
hero: {
badge: "✦ iOS اور Android پر دستیاب",
titleLine1: "جڑے رہنے کا",
titleLine2: "جدید طریقہ",
description:
"TalkPro واضح، سادہ اور قابل اعتماد رابطے کے لیے بنائی گئی ایک جدید میسجنگ ایپ ہے۔",
tags: ["شناختی تہہ", "AI نیٹو میسجنگ", "مطابقت پذیر رازداری"],
},
download: {
eyebrow: "ڈاؤن لوڈ",
title: "ڈاؤن لوڈ",
description:
"TalkPro ڈاؤن لوڈ کریں اور جڑے رہنے کا صاف، سادہ اور جدید طریقہ آزمائیں۔",
android: "اینڈرائیڈ",
androidCta: "APK جلد آ رہا ہے",
ios: "آئی او ایس",
iosCta: "App Store سے حاصل کریں",
},
footer: {
links: { download: "ڈاؤن لوڈ", features: "خصوصیات", about: "تعارف", contact: "رابطہ" },
android: "اینڈرائیڈ",
ios: "آئی او ایس",
copyright: "© 2026 TalkPro. جملہ حقوق محفوظ ہیں۔",
legal: "استعمال کی شرائط · رازداری کی پالیسی · سپورٹ",
},
},
} as const; } as const;
export type Translations = (typeof translations)[Lang]; export type Translations = (typeof translations)["en"];
export function getTranslations(lang: Lang): Translations { export function getTranslations(lang: Lang): Translations {
return translations[lang]; return mergeTranslations(translations.en, translations[lang] as DeepPartial<Translations>);
} }

View File

@@ -33,7 +33,9 @@ const {
const getOffset = () => header ? header.offsetHeight : 0; const getOffset = () => header ? header.offsetHeight : 0;
let activeScrollAnimation = 0; let activeScrollAnimation = 0;
const easeInCubic = (t: number) => t * t * t; const easeInOutCubic = (t: number) => (
t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2
);
const animateScrollTo = (targetTop: number) => { const animateScrollTo = (targetTop: number) => {
const startTop = window.scrollY; const startTop = window.scrollY;
@@ -54,7 +56,7 @@ const {
const step = (now: number) => { const step = (now: number) => {
const elapsed = now - startTime; const elapsed = now - startTime;
const progress = Math.min(elapsed / duration, 1); const progress = Math.min(elapsed / duration, 1);
const easedProgress = easeInCubic(progress); const easedProgress = easeInOutCubic(progress);
window.scrollTo(0, startTop + distance * easedProgress); window.scrollTo(0, startTop + distance * easedProgress);
@@ -77,6 +79,7 @@ const {
e.preventDefault(); e.preventDefault();
const top = target.getBoundingClientRect().top + window.scrollY - getOffset(); const top = target.getBoundingClientRect().top + window.scrollY - getOffset();
animateScrollTo(top); animateScrollTo(top);
history.pushState(null, '', href);
}); });
}); });

View File

@@ -185,10 +185,10 @@
.store-badge__platform { .store-badge__platform {
margin: 0; margin: 0;
font-size: 11px; font-size: 13px;
font-weight: 600; font-weight: 600;
line-height: normal; line-height: normal;
letter-spacing: 0.05px; letter-spacing: var(--ls-13);
} }
.store-badge--android .store-badge__platform { .store-badge--android .store-badge__platform {
@@ -213,9 +213,17 @@
display: block; display: block;
order: 1; order: 1;
flex-shrink: 0; flex-shrink: 0;
width: 240px;
height: 292px;
}
@media (min-width: 577px) {
.download-cta__phone {
width: min(418px, calc(100vw - 32px)); width: min(418px, calc(100vw - 32px));
height: auto;
aspect-ratio: 418 / 510; aspect-ratio: 418 / 510;
} }
}
.download-cta__phone-crop { .download-cta__phone-crop {
position: absolute; position: absolute;

View File

@@ -49,10 +49,10 @@
.features__description { .features__description {
width: 100%; width: 100%;
margin: 0; margin: 0;
font-size: 18px; font-size: 15px;
font-weight: 400; font-weight: 400;
line-height: 1.5; line-height: 1.5;
letter-spacing: var(--ls-18); letter-spacing: var(--ls-15);
color: #7a726d; color: #7a726d;
text-align: center; text-align: center;
} }
@@ -72,8 +72,8 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 16px; gap: 24px;
padding: 32px; padding: 36px;
background: rgba(255, 255, 255, 0.78); background: rgba(255, 255, 255, 0.78);
border-radius: 30px; border-radius: 30px;
} }
@@ -140,8 +140,8 @@
@media (min-width: 576px) { @media (min-width: 576px) {
.features__header, .features__header,
.features__grid { .features__grid {
padding-left: 28px; padding-left: 24px;
padding-right: 28px; padding-right: 24px;
} }
.features__title { .features__title {
@@ -188,6 +188,11 @@
font-size: 48px; font-size: 48px;
letter-spacing: var(--ls-48); letter-spacing: var(--ls-48);
} }
.features__description {
font-size: 18px;
letter-spacing: var(--ls-18);
}
} }
@media (min-width: 1280px) { @media (min-width: 1280px) {

View File

@@ -73,3 +73,7 @@ body {
--ls-71: -1.58px; --ls-71: -1.58px;
--ls-72: -1.61px; --ls-72: -1.61px;
} }
:target {
scroll-margin-top: 72px;
}

View File

@@ -145,7 +145,8 @@
right: 0; right: 0;
z-index: 60; z-index: 60;
width: 240px; width: 240px;
overflow: hidden; max-height: min(520px, calc(100vh - 96px));
overflow-y: auto;
background: #fff; background: #fff;
border: 1px solid #e3d9d1; border: 1px solid #e3d9d1;
border-radius: 18px; border-radius: 18px;
@@ -158,11 +159,11 @@
.language-switcher__option { .language-switcher__option {
display: block; display: block;
padding: 18px 24px; padding: 14px 24px;
font-size: 18px; font-size: 14px;
font-weight: 600; font-weight: 600;
line-height: normal; line-height: normal;
letter-spacing: var(--ls-18); letter-spacing: var(--ls-14);
color: #7a726d; color: #7a726d;
text-decoration: none; text-decoration: none;
transition: transition:
@@ -232,6 +233,8 @@
} }
.mobile-nav { .mobile-nav {
max-height: calc(100vh - 72px);
overflow-y: auto;
background: #fff; background: #fff;
border-top: 1px solid #e3d9d1; border-top: 1px solid #e3d9d1;
} }
@@ -257,6 +260,11 @@
color: #2e2a28; color: #2e2a28;
text-decoration: none; text-decoration: none;
border-bottom: 1px solid #e3d9d1; border-bottom: 1px solid #e3d9d1;
transition: color 160ms ease;
}
.mobile-nav__link.is-active {
color: #f28a4b;
} }
.mobile-nav__link--last { .mobile-nav__link--last {
@@ -264,18 +272,22 @@
} }
.mobile-nav__languages { .mobile-nav__languages {
display: flex; display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
align-items: center; align-items: center;
gap: 16px; gap: 12px 16px;
padding: 16px 0; padding: 16px 0;
border-top: 1px solid #e3d9d1; border-top: 1px solid #e3d9d1;
} }
.mobile-nav__language-link { .mobile-nav__language-link {
font-size: 15px; min-width: 0;
font-size: 14px;
font-weight: 600; font-weight: 600;
letter-spacing: var(--ls-15); line-height: 1.25;
letter-spacing: var(--ls-14);
color: #2e2a28; color: #2e2a28;
text-align: center;
text-decoration: none; text-decoration: none;
} }
@@ -285,14 +297,13 @@
@media (max-width: 500px) { @media (max-width: 500px) {
.mobile-nav__languages { .mobile-nav__languages {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-columns: repeat(3, minmax(0, 1fr));
align-items: center; }
gap: 12px 16px;
} }
.mobile-nav__language-link { @media (min-width: 501px) and (max-width: 1022px) {
text-align: center; .mobile-nav__languages {
grid-template-columns: repeat(5, minmax(0, 1fr));
} }
} }

View File

@@ -265,17 +265,30 @@
min-width: 0; min-width: 0;
height: 100%; height: 100%;
padding-top: 60px; padding-top: 60px;
overflow: hidden;
} }
.hero__phone-frame { .hero__phone-frame {
width: 100%; width: 100%;
height: auto; height: auto;
aspect-ratio: 673 / 1108; aspect-ratio: 116 / 191;
}
.hero__phone-crop {
position: relative;
inset: auto;
overflow: visible;
}
.hero__phone {
position: static;
width: 100%;
height: auto;
} }
.hero__content { .hero__content {
width: 660px; width: 660px;
padding: 80px 0; padding: 0;
} }
} }
@@ -295,6 +308,23 @@
.hero__inner { .hero__inner {
padding: 0; padding: 0;
} }
.hero__phone-column {
align-items: flex-start;
}
.hero__phone-frame {
flex: 1 0 0;
width: auto;
max-width: calc(955px * 116 / 191);
height: 955px;
aspect-ratio: 116 / 191;
}
.hero__phone {
width: 100%;
height: 100%;
}
} }
@media (min-width: 1376px) { @media (min-width: 1376px) {

View File

@@ -33,9 +33,10 @@
.app-preview__description { .app-preview__description {
width: 100%; width: 100%;
margin: 0; margin: 0;
font-size: 18px; font-size: 15px;
font-weight: 400; font-weight: 400;
line-height: 1.5; line-height: 1.5;
letter-spacing: var(--ls-15);
color: #7a726d; color: #7a726d;
text-align: center; text-align: center;
} }
@@ -214,6 +215,11 @@
font-size: 48px; font-size: 48px;
} }
.app-preview__description {
font-size: 18px;
letter-spacing: var(--ls-18);
}
.app-preview__side-phone, .app-preview__side-phone,
.app-preview__control-wrap { .app-preview__control-wrap {
display: flex; display: flex;

View File

@@ -18,6 +18,14 @@
margin: 0 auto; margin: 0 auto;
} }
.experience__heading {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
gap: 24px;
}
.experience__title { .experience__title {
width: 100%; width: 100%;
margin: 0; margin: 0;
@@ -49,7 +57,7 @@
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
width: 100%; width: 100%;
gap: 16px; gap: 36px;
padding: 0 0 36px; padding: 0 0 36px;
overflow: hidden; overflow: hidden;
background: linear-gradient(to bottom, #fef0eb, #fff); background: linear-gradient(to bottom, #fef0eb, #fff);
@@ -139,10 +147,10 @@
.experience__caption { .experience__caption {
width: 100%; width: 100%;
margin: 0; margin: 0;
font-size: 18px; font-size: 15px;
font-weight: 400; font-weight: 400;
line-height: 1.5; line-height: 1.5;
letter-spacing: var(--ls-18); letter-spacing: var(--ls-15);
color: #7a726d; color: #7a726d;
text-align: center; text-align: center;
} }
@@ -228,10 +236,10 @@
.use-cases__description { .use-cases__description {
width: 100%; width: 100%;
margin: 0; margin: 0;
font-size: 18px; font-size: 15px;
font-weight: 400; font-weight: 400;
line-height: 1.5; line-height: 1.5;
letter-spacing: var(--ls-18); letter-spacing: var(--ls-15);
color: #7a726d; color: #7a726d;
text-align: left; text-align: left;
} }
@@ -349,8 +357,8 @@
@media (min-width: 576px) { @media (min-width: 576px) {
.experience, .experience,
.use-cases { .use-cases {
padding-left: 28px; padding-left: 24px;
padding-right: 28px; padding-right: 24px;
} }
.experience__title, .experience__title,
@@ -436,6 +444,12 @@
font-size: 48px; font-size: 48px;
letter-spacing: var(--ls-48); letter-spacing: var(--ls-48);
} }
.experience__caption,
.use-cases__description {
font-size: 18px;
letter-spacing: var(--ls-18);
}
} }
@media (min-width: 1295px) { @media (min-width: 1295px) {

View File

@@ -40,10 +40,10 @@
.trust__description { .trust__description {
width: 100%; width: 100%;
margin: 0; margin: 0;
font-size: 18px; font-size: 15px;
font-weight: 400; font-weight: 400;
line-height: 1.5; line-height: 1.5;
letter-spacing: var(--ls-18); letter-spacing: var(--ls-15);
color: #7a726d; color: #7a726d;
} }
@@ -188,8 +188,8 @@
@media (min-width: 576px) { @media (min-width: 576px) {
.trust { .trust {
padding-left: 28px; padding-left: 24px;
padding-right: 28px; padding-right: 24px;
} }
.trust__title { .trust__title {
@@ -261,6 +261,11 @@
font-size: 48px; font-size: 48px;
letter-spacing: var(--ls-48); letter-spacing: var(--ls-48);
} }
.trust__description {
font-size: 18px;
letter-spacing: var(--ls-18);
}
} }
@media (min-width: 1376px) { @media (min-width: 1376px) {

View File

@@ -80,13 +80,20 @@
.why__description { .why__description {
width: 100%; width: 100%;
margin: 0; margin: 0;
font-size: 18px; font-size: 15px;
font-weight: 400; font-weight: 400;
line-height: 1.5; line-height: 1.5;
letter-spacing: var(--ls-18); letter-spacing: var(--ls-15);
color: #7a726d; color: #7a726d;
} }
@media (min-width: 1200px) {
.why__description {
font-size: 18px;
letter-spacing: var(--ls-18);
}
}
.why__illustration { .why__illustration {
position: relative; position: relative;
display: block; display: block;
@@ -119,8 +126,8 @@
display: flex; display: flex;
align-items: center; align-items: center;
min-width: 0; min-width: 0;
gap: 24px; gap: 20px;
padding: 36px; padding: 20px 16px;
overflow: clip; overflow: clip;
background: #fef0eb; background: #fef0eb;
border: 1px solid #e8e4de; border: 1px solid #e8e4de;
@@ -132,8 +139,8 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-shrink: 0; flex-shrink: 0;
width: 80px; width: 60px;
height: 80px; height: 60px;
overflow: clip; overflow: clip;
background: #f08458; background: #f08458;
border-radius: 9999px; border-radius: 9999px;
@@ -143,19 +150,24 @@
display: block; display: block;
} }
.why-card__icon--square { .why-card__icon--simple {
width: 44px; width: 33.001px;
height: 44px; height: 32.973px;
} }
.why-card__icon--familiar { .why-card__icon--familiar {
width: 38px; width: 28.5px;
height: 40px; height: 30px;
}
.why-card__icon--connected {
width: 33px;
height: 32.936px;
} }
.why-card__icon--modern { .why-card__icon--modern {
width: 24px; width: 18.125px;
height: 44px; height: 33px;
} }
.why-card__copy { .why-card__copy {
@@ -194,6 +206,35 @@
padding-right: 20px; padding-right: 20px;
} }
.why-card {
gap: 24px;
}
.why-card__icon-frame {
width: 80px;
height: 80px;
}
.why-card__icon--simple {
width: 44.001px;
height: 43.964px;
}
.why-card__icon--familiar {
width: 38px;
height: 40px;
}
.why-card__icon--connected {
width: 44px;
height: 43.914px;
}
.why-card__icon--modern {
width: 24.168px;
height: 44px;
}
.why__title { .why__title {
font-size: 32px; font-size: 32px;
letter-spacing: var(--ls-32); letter-spacing: var(--ls-32);
@@ -202,8 +243,8 @@
@media (min-width: 576px) { @media (min-width: 576px) {
.why { .why {
padding-left: 28px; padding-left: 24px;
padding-right: 28px; padding-right: 24px;
} }
.why__title { .why__title {
@@ -228,6 +269,7 @@
} }
.why-card { .why-card {
padding: 36px;
min-height: 152px; min-height: 152px;
} }