fix(style): Seperate CSS style to src\styles
This commit is contained in:
@@ -1,4 +1,11 @@
|
|||||||
---
|
---
|
||||||
|
import type { Translations } from '../i18n/translations'
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
t: Translations['preview']
|
||||||
|
}
|
||||||
|
|
||||||
|
const { t } = Astro.props
|
||||||
const slides = [
|
const slides = [
|
||||||
"/assets/preview-phone.png",
|
"/assets/preview-phone.png",
|
||||||
"/assets/preview-phone.png",
|
"/assets/preview-phone.png",
|
||||||
@@ -6,60 +13,48 @@ const slides = [
|
|||||||
]
|
]
|
||||||
---
|
---
|
||||||
|
|
||||||
<section class="bg-[#fef0eb] w-full flex flex-col gap-[60px] items-center pt-16 lg:pt-[120px] px-4 lg:px-[130px] overflow-hidden">
|
<section class="app-preview">
|
||||||
<!-- Heading -->
|
<div class="app-preview__header">
|
||||||
<div class="flex flex-col gap-[40px] items-start overflow-clip w-full max-w-[940px] mx-auto">
|
<p class="app-preview__title">
|
||||||
<p class="font-bold text-[#1a1a1a] text-[32px] md:text-[40px] lg:text-[48px] text-center tracking-[-1.16px] leading-[1.2] w-full">
|
{t.title}
|
||||||
A Familiar App Experience, Reimagined with a Modern Look
|
|
||||||
</p>
|
</p>
|
||||||
<p class="font-normal text-[#7a726d] text-[18px] text-center tracking-[-0.33px] leading-[1.5] w-full">
|
<p class="app-preview__description">
|
||||||
TalkPro keeps the communication experience familiar while refining the visual layer with updated icons, colors, spacing, and interface details.
|
{t.description}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Carousel -->
|
<div class="app-preview__carousel" id="carousel">
|
||||||
<div class="flex gap-[20px] items-end justify-center shrink-0 w-full" id="carousel">
|
<div class="app-preview__side-phone">
|
||||||
|
<img id="phone-left" alt="" class="app-preview__phone-image" src={slides[slides.length - 1]} />
|
||||||
<!-- Left phone (hidden on mobile) -->
|
|
||||||
<div class="hidden lg:block relative h-[396px] w-[336px] opacity-20 shrink-0 overflow-hidden pointer-events-none transition-opacity duration-300">
|
|
||||||
<img id="phone-left" alt="" class="absolute h-[175.34%] left-0 max-w-none top-[-0.03%] w-full transition-opacity duration-300" src={slides[slides.length - 1]} />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Prev button (hidden on mobile) -->
|
<div class="app-preview__control-wrap">
|
||||||
<div class="hidden lg:flex items-end self-stretch shrink-0">
|
<div class="app-preview__control-inner">
|
||||||
<div class="flex items-center justify-center h-full">
|
<button id="btn-prev" class="app-preview__button">
|
||||||
<button id="btn-prev" class="bg-[#f08458] flex items-center justify-center rounded-[9999px] size-[48px] hover:bg-[#e07a3b] active:scale-95 transition-all shrink-0 cursor-pointer">
|
<img alt={t.previous} class="app-preview__button-icon" src="/assets/preview-arrow-left.svg" />
|
||||||
<img alt="Previous" class="block size-[24px]" src="/assets/preview-arrow-left.svg" />
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Center phone -->
|
<div class="app-preview__center-phone">
|
||||||
<div class="relative w-full lg:w-[459px] aspect-[459/542] lg:aspect-auto lg:h-[542px] shrink-0 overflow-hidden pointer-events-none">
|
<img id="phone-center" alt={t.phoneAlt} class="app-preview__phone-image" src={slides[0]} />
|
||||||
<img id="phone-center" alt="TalkPro app preview" class="absolute h-[175.34%] left-0 max-w-none top-[-0.03%] w-full transition-opacity duration-300" src={slides[0]} />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Next button (hidden on mobile) -->
|
<div class="app-preview__control-wrap">
|
||||||
<div class="hidden lg:flex items-end self-stretch shrink-0">
|
<div class="app-preview__control-inner">
|
||||||
<div class="flex items-center justify-center h-full">
|
<button id="btn-next" class="app-preview__button">
|
||||||
<button id="btn-next" class="bg-[#f08458] flex items-center justify-center rounded-[9999px] size-[48px] hover:bg-[#e07a3b] active:scale-95 transition-all shrink-0 cursor-pointer">
|
<img alt={t.next} class="app-preview__button-icon app-preview__button-icon--next" src="/assets/preview-arrow-right.svg" />
|
||||||
<img alt="Next" class="block size-[24px] rotate-180" src="/assets/preview-arrow-right.svg" />
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Right phone (hidden on mobile) -->
|
<div class="app-preview__side-phone">
|
||||||
<div class="hidden lg:block relative h-[396px] w-[336px] opacity-20 shrink-0 overflow-hidden pointer-events-none transition-opacity duration-300">
|
<img id="phone-right" alt="" class="app-preview__phone-image" src={slides[1]} />
|
||||||
<img id="phone-right" alt="" class="absolute h-[175.34%] left-0 max-w-none top-[-0.03%] w-full transition-opacity duration-300" src={slides[1]} />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const slides: string[] = (window as any).__carouselSlides || [];
|
|
||||||
|
|
||||||
// Read slides injected via data attribute
|
|
||||||
const carousel = document.getElementById('carousel')!;
|
const carousel = document.getElementById('carousel')!;
|
||||||
const allSlides: string[] = JSON.parse(carousel.dataset.slides || '[]');
|
const allSlides: string[] = JSON.parse(carousel.dataset.slides || '[]');
|
||||||
|
|
||||||
|
|||||||
@@ -1,47 +1,44 @@
|
|||||||
---
|
---
|
||||||
const halftone = "/assets/core-halftone-bg.png";
|
import type { Translations } from '../i18n/translations'
|
||||||
const iconPrivate = "/assets/core-icon-private.png";
|
|
||||||
const iconGroups = "/assets/core-icon-groups.png";
|
|
||||||
const iconChannels = "/assets/core-icon-channels.png";
|
|
||||||
const iconVoice = "/assets/core-icon-voice.png";
|
|
||||||
const iconVideo = "/assets/core-icon-video.png";
|
|
||||||
const iconMedia = "/assets/core-icon-media.png";
|
|
||||||
|
|
||||||
const cards = [
|
export interface Props {
|
||||||
{ img: iconPrivate, title: 'Private Messaging', desc: 'Stay connected through fast and familiar one-on-one conversations.' },
|
t: Translations['core']
|
||||||
{ img: iconGroups, title: 'Group Chats', desc: 'Create spaces for friends, teams, communities, and shared discussions.' },
|
}
|
||||||
{ img: iconChannels, title: 'Channels', desc: 'Follow updates, announcements, and content from the people or communities you care about.' },
|
|
||||||
{ img: iconVoice, title: 'Voice Calls', desc: 'Talk in real time whenever messages are not enough.' },
|
const { t } = Astro.props
|
||||||
{ img: iconVideo, title: 'Video Calls', desc: 'Connect face-to-face with a simple and reliable video call experience.' },
|
const halftone = "/assets/core-halftone-bg.png";
|
||||||
{ img: iconMedia, title: 'Media Sharing', desc: 'Share photos, videos, files, and updates in your conversations.' },
|
const icons = [
|
||||||
|
"/assets/core-icon-private.png",
|
||||||
|
"/assets/core-icon-groups.png",
|
||||||
|
"/assets/core-icon-channels.png",
|
||||||
|
"/assets/core-icon-voice.png",
|
||||||
|
"/assets/core-icon-video.png",
|
||||||
|
"/assets/core-icon-media.png",
|
||||||
]
|
]
|
||||||
---
|
---
|
||||||
|
|
||||||
<section id="features" class="relative w-full flex flex-col gap-[60px] items-center py-16 lg:py-[120px] overflow-hidden">
|
<section id="features" class="features">
|
||||||
<!-- Background halftone -->
|
<img alt="" class="features__bg" src={halftone} />
|
||||||
<img alt="" class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 h-[1319px] w-[2363px] object-cover pointer-events-none opacity-20" src={halftone} />
|
|
||||||
|
|
||||||
<!-- Section header -->
|
<div class="features__header">
|
||||||
<div class="relative flex flex-col gap-[24px] items-center justify-end overflow-clip w-full max-w-[1280px] mx-auto px-4 lg:px-[180px]">
|
<div class="section-eyebrow">
|
||||||
<div class="bg-white border border-[#fbbfa3] flex items-center justify-center px-[24px] py-[12px] rounded-[9999px] shrink-0">
|
<span class="section-eyebrow__text">{t.eyebrow}</span>
|
||||||
<span class="font-bold text-[#f08458] text-[14px] text-center tracking-[-0.04px] whitespace-nowrap leading-normal">CORE FEATURES</span>
|
|
||||||
</div>
|
</div>
|
||||||
<p class="font-bold text-[#1a1a1a] text-[32px] md:text-[40px] lg:text-[48px] text-center tracking-[-1.16px] leading-[1.2] w-full">Everything You Need to Communicate</p>
|
<p class="features__title">{t.title}</p>
|
||||||
<p class="font-normal text-[#7a726d] text-[18px] text-center tracking-[-0.33px] leading-[1.5] w-full">
|
<p class="features__description">
|
||||||
Different identities, different conversations, and different privacy levels should not be forced into one flat interface. TalkPro lets them exist in order inside one platform.
|
{t.description}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Card grid -->
|
<div class="features__grid">
|
||||||
<div class="relative grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-[22px] w-full max-w-[1280px] mx-auto px-4 lg:px-0">
|
{t.cards.map((card, index) => (
|
||||||
{cards.map(card => (
|
<div class="feature-card">
|
||||||
<div class="bg-[rgba(255,255,255,0.78)] flex flex-col gap-[16px] items-center p-[32px] rounded-[30px]">
|
<div class="feature-card__icon-frame">
|
||||||
<div class="relative shrink-0 size-[160px] overflow-hidden">
|
<img alt={card.title} class="feature-card__icon" src={icons[index]} />
|
||||||
<img alt={card.title} class="absolute inset-0 max-w-none size-full object-contain" src={card.img} />
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-[12px] items-start text-center w-full">
|
<div class="feature-card__copy">
|
||||||
<p class="font-bold text-[#2e2a28] text-[24px] tracking-[-0.5px] leading-normal w-full">{card.title}</p>
|
<p class="feature-card__title">{card.title}</p>
|
||||||
<p class="font-normal text-[#7a726d] text-[15px] tracking-[-0.13px] leading-[1.5] w-full">{card.desc}</p>
|
<p class="feature-card__description">{card.desc}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
---
|
---
|
||||||
|
import type { Translations } from '../i18n/translations'
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
t: Translations['download']
|
||||||
|
}
|
||||||
|
|
||||||
|
const { t } = Astro.props
|
||||||
const bgPattern = "/assets/cta-bg-pattern.svg";
|
const bgPattern = "/assets/cta-bg-pattern.svg";
|
||||||
const talkproLogo = "/assets/cta-talkpro-logo.svg";
|
const talkproLogo = "/assets/cta-talkpro-logo.svg";
|
||||||
const androidIcon = "/assets/cta-android-icon.svg";
|
const androidIcon = "/assets/cta-android-icon.svg";
|
||||||
@@ -6,54 +13,50 @@ const appleIcon = "/assets/cta-apple-icon.svg";
|
|||||||
const phoneArt = "/assets/cta-phone-art.png";
|
const phoneArt = "/assets/cta-phone-art.png";
|
||||||
---
|
---
|
||||||
|
|
||||||
<section id="download" class="relative bg-white border-t border-[#eec8b8] w-full flex items-center justify-center overflow-hidden min-h-[400px] lg:h-[600px]">
|
<section id="download" class="download-cta">
|
||||||
<!-- Background pattern -->
|
<img alt="" class="download-cta__pattern" src={bgPattern} />
|
||||||
<img alt="" class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 h-[923px] w-full max-w-[1920px] pointer-events-none" src={bgPattern} />
|
|
||||||
|
|
||||||
<div class="relative flex flex-col lg:flex-row items-center gap-8 lg:gap-0 w-full max-w-[1280px] mx-auto px-4 lg:px-0 py-12 lg:py-0">
|
<div class="download-cta__inner">
|
||||||
<!-- Left: download panel -->
|
<div class="download-cta__content">
|
||||||
<div class="flex flex-1 flex-col gap-[36px] items-start justify-center min-w-0 overflow-clip">
|
<div class="section-eyebrow">
|
||||||
<div class="bg-white border border-[#fbbfa3] flex items-center justify-center px-[24px] py-[12px] rounded-[9999px] shrink-0">
|
<span class="section-eyebrow__text">{t.eyebrow}</span>
|
||||||
<span class="font-bold text-[#f08458] text-[14px] text-center tracking-[-0.04px] whitespace-nowrap leading-normal">DOWNLOAD</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col gap-[16px] items-start w-full">
|
<div class="download-cta__copy">
|
||||||
<div class="flex gap-[20px] items-start shrink-0 flex-wrap">
|
<div class="download-cta__heading">
|
||||||
<p class="font-bold text-[#1a1a1a] text-[32px] md:text-[40px] lg:text-[48px] tracking-[-1.16px] leading-[1.2] whitespace-nowrap">Download</p>
|
<p class="download-cta__title">{t.title}</p>
|
||||||
<div class="relative shrink-0 h-[72px] w-[188px]">
|
<div class="download-cta__logo-frame">
|
||||||
<img alt="TalkPro" class="absolute inset-0 block max-w-none size-full" src={talkproLogo} />
|
<img alt={t.logoAlt} class="download-cta__logo" src={talkproLogo} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="font-normal text-[#7a726d] text-[18px] tracking-[-0.33px] leading-[1.5] max-w-[542px]">
|
<p class="download-cta__description">
|
||||||
Download TalkPro and experience a cleaner, simpler, and more modern way to stay connected.
|
{t.description}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Store badges -->
|
<div class="store-badges">
|
||||||
<div class="flex flex-wrap gap-[16px] items-center overflow-clip shrink-0 w-full">
|
<div class="store-badge store-badge--android">
|
||||||
<div class="bg-[#f28a4b] border border-[#c5834e] flex gap-[8px] h-[70px] items-center overflow-clip px-[16px] py-[12px] rounded-[20px] w-full sm:w-[260px] shrink-0">
|
<img alt={t.androidAlt} class="store-badge__icon" src={androidIcon} />
|
||||||
<img alt="Android" class="block shrink-0 size-[44px]" src={androidIcon} />
|
<div class="store-badge__copy">
|
||||||
<div class="flex flex-col gap-[3px] items-start overflow-clip shrink-0 whitespace-nowrap">
|
<p class="store-badge__platform">{t.android}</p>
|
||||||
<p class="font-semibold text-[#ffd6bc] text-[11px] tracking-[0.05px] leading-normal">ANDROID</p>
|
<p class="store-badge__label">{t.androidCta}</p>
|
||||||
<p class="font-semibold text-white text-[15px] tracking-[-0.13px] leading-normal">APK Coming Soon</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-[#383838] border border-[#141414] flex gap-[8px] h-[70px] items-center overflow-clip px-[16px] py-[12px] rounded-[20px] w-full sm:w-[260px] shrink-0">
|
<div class="store-badge store-badge--ios">
|
||||||
<div class="bg-[#151515] flex items-center justify-center rounded-[12px] shrink-0 size-[44px]">
|
<div class="store-badge__icon-frame">
|
||||||
<img alt="Apple" class="block h-[27px] w-[22px]" src={appleIcon} />
|
<img alt={t.appleAlt} class="store-badge__apple-icon" src={appleIcon} />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-[3px] items-start overflow-clip shrink-0 whitespace-nowrap">
|
<div class="store-badge__copy">
|
||||||
<p class="font-semibold text-[#ccc] text-[11px] tracking-[0.05px] leading-normal">IOS</p>
|
<p class="store-badge__platform">{t.ios}</p>
|
||||||
<p class="font-semibold text-white text-[15px] tracking-[-0.13px] leading-normal">Coming on App Store</p>
|
<p class="store-badge__label">{t.iosCta}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Right: phone art (hidden on mobile) -->
|
<div class="download-cta__phone">
|
||||||
<div class="hidden lg:block relative shrink-0 h-[510px] w-[418px]">
|
<div class="download-cta__phone-crop">
|
||||||
<div class="absolute inset-0 overflow-hidden pointer-events-none">
|
<img alt={t.phoneAlt} class="download-cta__phone-image" src={phoneArt} />
|
||||||
<img alt="TalkPro on phone" class="absolute h-[136.1%] left-[3.8%] max-w-none top-[-18.05%] w-[92.43%]" src={phoneArt} />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,64 +1,44 @@
|
|||||||
---
|
---
|
||||||
|
import type { Translations } from '../i18n/translations'
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
t: Translations['experience']
|
||||||
|
}
|
||||||
|
|
||||||
|
const { t } = Astro.props
|
||||||
|
const images = ["/assets/exp-card-1.png", "/assets/exp-card-2.png", "/assets/exp-card-3.png"]
|
||||||
|
const imageClasses = ['experience-card__image--one', 'experience-card__image--two', 'experience-card__image--three']
|
||||||
---
|
---
|
||||||
|
|
||||||
<section id="experience" class="bg-white w-full flex flex-col items-center justify-center py-16 lg:py-[120px]">
|
<section id="experience" class="experience">
|
||||||
<div class="flex flex-col gap-[40px] items-center justify-center w-full max-w-[1008px] mx-auto px-4 lg:px-0">
|
<div class="experience__inner">
|
||||||
<p class="font-bold text-[#1a1a1a] text-[32px] md:text-[40px] lg:text-[48px] text-center tracking-[-1.16px] leading-[1.2] w-full">
|
<p class="experience__title">
|
||||||
A Cleaner, More Comfortable Messaging Experience
|
{t.title}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="flex flex-col items-start w-full">
|
<div class="experience__body">
|
||||||
<!-- 3 cards row -->
|
<div class="experience__grid">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 w-full">
|
{t.cards.map((card, index) => (
|
||||||
|
<div class="experience-card">
|
||||||
<!-- Card 1: Clear Interface -->
|
<div class={`experience-card__media ${index > 0 ? 'experience-card__media--tinted' : ''}`}>
|
||||||
<div class="bg-gradient-to-b from-[#fef0eb] to-white flex flex-col gap-[36px] items-center overflow-clip pb-[36px] px-[36px] rounded-tl-[30px] rounded-tr-[30px] w-full">
|
<div class="experience-card__media-crop">
|
||||||
<div class="relative h-[232px] shrink-0 w-full">
|
<img
|
||||||
<div class="absolute inset-0 overflow-hidden pointer-events-none">
|
alt={card.alt}
|
||||||
<img alt="Clear interface screenshot" class="absolute h-[298.5%] left-0 max-w-none top-[-58.58%] w-full" src="/assets/exp-card-1.png" />
|
class={`experience-card__image ${imageClasses[index]}`}
|
||||||
|
src={images[index]}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-[16px] items-start overflow-clip text-center w-full">
|
<div class="experience-card__copy">
|
||||||
<p class="font-semibold text-[#0d0d0d] text-[24px] tracking-[-0.47px] leading-[1.4] w-full">Clear Interface</p>
|
<p class="experience-card__title">{card.title}</p>
|
||||||
<p class="font-medium text-[#7a726d] text-[16px] tracking-[-0.18px] leading-[1.5] w-full">A clean layout that makes conversations easy to follow.</p>
|
<p class="experience-card__description">{card.desc}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Card 2: Smooth Navigation -->
|
<p class="experience__caption">
|
||||||
<div class="bg-gradient-to-b from-[#fef0eb] to-white flex flex-col gap-[36px] items-center overflow-clip pb-[36px] px-[36px] rounded-tl-[30px] rounded-tr-[30px] w-full">
|
{t.caption}
|
||||||
<div class="bg-[#ffeddf] flex flex-col items-start w-full">
|
|
||||||
<div class="relative h-[232px] shrink-0 w-full">
|
|
||||||
<div class="absolute inset-0 overflow-hidden pointer-events-none">
|
|
||||||
<img alt="Smooth navigation screenshot" class="absolute h-[411.28%] left-[-5.95%] max-w-none top-[-335.6%] w-[137.79%]" src="/assets/exp-card-2.png" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col gap-[16px] items-start overflow-clip text-center w-full">
|
|
||||||
<p class="font-semibold text-[#0d0d0d] text-[24px] tracking-[-0.47px] leading-[1.4] w-full">Smooth Navigation</p>
|
|
||||||
<p class="font-medium text-[#7a726d] text-[16px] tracking-[-0.18px] leading-[1.5] w-full">Move between chats, groups, and channels with familiar controls.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Card 3: Refined Visual Design -->
|
|
||||||
<div class="bg-gradient-to-b from-[#fef0eb] to-white flex flex-col gap-[36px] items-center overflow-clip pb-[36px] px-[36px] rounded-tl-[30px] rounded-tr-[30px] w-full">
|
|
||||||
<div class="bg-[#ffeddf] flex flex-col h-[232px] items-start overflow-clip w-full">
|
|
||||||
<div class="flex-1 min-h-0 relative w-full">
|
|
||||||
<div class="absolute inset-0 overflow-hidden pointer-events-none">
|
|
||||||
<img alt="Refined visual design screenshot" class="absolute h-[298.5%] left-0 max-w-none top-[-99.23%] w-full" src="/assets/exp-card-3.png" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col gap-[16px] items-start overflow-clip text-center w-full">
|
|
||||||
<p class="font-semibold text-[#0d0d0d] text-[24px] tracking-[-0.47px] leading-[1.4] w-full">Refined Visual Design</p>
|
|
||||||
<p class="font-medium text-[#7a726d] text-[16px] tracking-[-0.18px] leading-[1.5] w-full">Modern icons, colors, and interface details create a more polished experience.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Footer caption -->
|
|
||||||
<p class="font-normal text-[#7a726d] text-[18px] text-center tracking-[-0.33px] leading-[1.5] w-full mt-0">
|
|
||||||
TalkPro is designed with clarity in mind. Every screen is built to help users focus on their conversations, reduce distractions, and move naturally between chats, groups, channels, and calls.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,65 +1,66 @@
|
|||||||
---
|
---
|
||||||
|
import type { Translations } from '../i18n/translations'
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
t: Translations['footer']
|
||||||
|
}
|
||||||
|
|
||||||
|
const { t } = Astro.props
|
||||||
const logoFull = "/assets/footer-logo.png";
|
const logoFull = "/assets/footer-logo.png";
|
||||||
const androidIcon = "/assets/footer-android-icon.svg";
|
const androidIcon = "/assets/footer-android-icon.svg";
|
||||||
const appleIcon = "/assets/footer-apple-icon.svg";
|
const appleIcon = "/assets/footer-apple-icon.svg";
|
||||||
---
|
---
|
||||||
|
|
||||||
<footer class="bg-[#fef0eb] w-full flex flex-col items-center justify-center py-16 lg:py-[120px]">
|
<footer class="site-footer">
|
||||||
<div class="flex flex-col gap-[36px] items-start w-full max-w-[1280px] mx-auto px-4 lg:px-0">
|
<div class="site-footer__inner">
|
||||||
<!-- Top row -->
|
<div class="site-footer__top">
|
||||||
<div class="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-10 lg:gap-0 w-full">
|
<div class="site-footer__brand">
|
||||||
<!-- Brand col -->
|
<div class="site-footer__logo-frame">
|
||||||
<div class="flex flex-col gap-[24px] items-start overflow-clip shrink-0">
|
<img alt={t.logoAlt} class="site-footer__logo" src={logoFull} />
|
||||||
<div class="relative h-[64px] w-[220px]">
|
|
||||||
<img alt="TalkPro" class="absolute inset-0 max-w-none object-cover size-full pointer-events-none" src={logoFull} />
|
|
||||||
</div>
|
</div>
|
||||||
<p class="font-normal text-[#7a726d] text-[14px] tracking-[-0.09px] leading-[1.5] max-w-[320px]">
|
<p class="site-footer__description">
|
||||||
TalkPro is a modern communication app designed for messaging, group conversations, channels, voice calls, and video calls.
|
{t.description}
|
||||||
</p>
|
</p>
|
||||||
<!-- Store badges -->
|
<div class="store-badges">
|
||||||
<div class="flex flex-wrap gap-[16px] items-center overflow-clip shrink-0 w-full">
|
<div class="store-badge store-badge--android">
|
||||||
<div class="bg-[#f28a4b] border border-[#c5834e] flex gap-[8px] h-[70px] items-center overflow-clip px-[16px] py-[12px] rounded-[20px] w-full sm:w-[260px] shrink-0">
|
<img alt="Android" class="store-badge__icon" src={androidIcon} />
|
||||||
<img alt="Android" class="block shrink-0 size-[44px]" src={androidIcon} />
|
<div class="store-badge__copy">
|
||||||
<div class="flex flex-col gap-[3px] items-start overflow-clip shrink-0 whitespace-nowrap">
|
<p class="store-badge__platform">{t.android}</p>
|
||||||
<p class="font-semibold text-[#ffd6bc] text-[11px] tracking-[0.05px] leading-normal">ANDROID</p>
|
<p class="store-badge__label">{t.androidCta}</p>
|
||||||
<p class="font-semibold text-white text-[15px] tracking-[-0.13px] leading-normal">APK Coming Soon</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-[#383838] border border-[#141414] flex gap-[8px] h-[70px] items-center overflow-clip px-[16px] py-[12px] rounded-[20px] w-full sm:w-[260px] shrink-0">
|
<div class="store-badge store-badge--ios">
|
||||||
<div class="bg-[#151515] flex items-center justify-center rounded-[12px] shrink-0 size-[44px]">
|
<div class="store-badge__icon-frame">
|
||||||
<img alt="Apple" class="block h-[27px] w-[22px]" src={appleIcon} />
|
<img alt="Apple" class="store-badge__apple-icon" src={appleIcon} />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-[3px] items-start overflow-clip shrink-0 whitespace-nowrap">
|
<div class="store-badge__copy">
|
||||||
<p class="font-semibold text-[#ccc] text-[11px] tracking-[0.05px] leading-normal">IOS</p>
|
<p class="store-badge__platform">{t.ios}</p>
|
||||||
<p class="font-semibold text-white text-[15px] tracking-[-0.13px] leading-normal">Coming on App Store</p>
|
<p class="store-badge__label">{t.iosCta}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Link cols -->
|
<div class="site-footer__links">
|
||||||
<div class="flex gap-[32px] items-center leading-normal shrink-0">
|
<div class="site-footer__link-column">
|
||||||
<div class="flex flex-col gap-[24px] items-start overflow-clip w-[160px]">
|
<a href="#download" class="site-footer__link">{t.links.download}</a>
|
||||||
<a href="#download" class="font-normal text-[#4a4a4a] text-[14px] whitespace-nowrap hover:text-[#f28a4b] transition-colors">Download</a>
|
<a href="#features" class="site-footer__link">{t.links.features}</a>
|
||||||
<a href="#features" class="font-normal text-[#4a4a4a] text-[14px] whitespace-nowrap hover:text-[#f28a4b] transition-colors">Features</a>
|
<a href="#" class="site-footer__link">{t.links.about}</a>
|
||||||
<a href="#" class="font-normal text-[#4a4a4a] text-[14px] whitespace-nowrap hover:text-[#f28a4b] transition-colors">About</a>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-[24px] items-start overflow-clip w-[160px]">
|
<div class="site-footer__link-column">
|
||||||
<p class="font-medium text-[#4a4a4a] text-[14px] whitespace-nowrap">Contact</p>
|
<p class="site-footer__text site-footer__text--heading">{t.links.contact}</p>
|
||||||
<p class="font-normal text-[#4a4a4a] text-[14px] whitespace-nowrap">email@hotmail.com</p>
|
<p class="site-footer__text">{t.email}</p>
|
||||||
<p class="font-normal text-[#4a4a4a] text-[14px] whitespace-nowrap">+01 123 45562334</p>
|
<p class="site-footer__text">{t.phone}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Divider -->
|
<div class="site-footer__divider"></div>
|
||||||
<div class="w-full h-px bg-[#e3d9d1]"></div>
|
|
||||||
|
|
||||||
<!-- Bottom row -->
|
<div class="site-footer__bottom">
|
||||||
<div class="flex gap-[20px] items-center overflow-clip w-full">
|
<p class="site-footer__legal">{t.copyright}</p>
|
||||||
<p class="font-normal text-[#7a726d] text-[14px] tracking-[-0.09px] whitespace-nowrap leading-normal">© 2026 TalkPro. All rights reserved.</p>
|
<div class="site-footer__spacer"></div>
|
||||||
<div class="flex-1 min-w-0"></div>
|
<p class="site-footer__legal">{t.legal}</p>
|
||||||
<p class="font-normal text-[#7a726d] text-[14px] tracking-[-0.09px] whitespace-nowrap leading-normal">Terms of Use · Privacy Policy · Support</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -1,72 +1,110 @@
|
|||||||
---
|
---
|
||||||
|
import { getLocalePath, languageLabels, languageNames, languages, type Lang, type Translations } from '../i18n/translations'
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
lang: Lang
|
||||||
|
t: Translations['header']
|
||||||
|
}
|
||||||
|
|
||||||
|
const { lang, t } = Astro.props
|
||||||
const logoIcon = "/assets/header-logo-icon.png";
|
const logoIcon = "/assets/header-logo-icon.png";
|
||||||
const logoWordmark = "/assets/header-logo-wordmark.svg";
|
const logoWordmark = "/assets/header-logo-wordmark.svg";
|
||||||
const globeIcon = "/assets/header-globe.svg";
|
const globeIcon = "/assets/header-globe.svg";
|
||||||
|
const navItems = [
|
||||||
|
{ href: '#hero', label: t.nav.home },
|
||||||
|
{ href: '#features', label: t.nav.features },
|
||||||
|
{ href: '#experience', label: t.nav.experience },
|
||||||
|
{ href: '#use-cases', label: t.nav.useCases },
|
||||||
|
{ href: '#reliability', label: t.nav.reliability },
|
||||||
|
]
|
||||||
|
const languageOptions = languages.map(item => ({
|
||||||
|
lang: item,
|
||||||
|
href: getLocalePath(item),
|
||||||
|
label: `${languageLabels[item]} - ${languageNames[item]}`,
|
||||||
|
}))
|
||||||
---
|
---
|
||||||
|
|
||||||
<header id="site-header" class="bg-white border-b border-[#e3d9d1] w-full sticky top-0 z-50">
|
<header id="site-header" class="site-header">
|
||||||
<!-- Main bar -->
|
<div class="site-header__bar">
|
||||||
<div class="flex items-center w-full max-w-[1280px] mx-auto px-4 lg:px-6 h-[72px] gap-6">
|
<div class="site-header__brand">
|
||||||
<!-- Logo -->
|
<a href={getLocalePath(lang)} class="site-logo">
|
||||||
<div class="flex flex-1 items-center min-w-0">
|
<div class="site-logo__icon-frame">
|
||||||
<a href="/" class="relative h-[42px] w-[143px] shrink-0 block">
|
<img alt={t.logoIconAlt} class="site-logo__icon" src={logoIcon} />
|
||||||
<div class="absolute h-[42px] left-0 top-0 w-[53px] overflow-hidden">
|
|
||||||
<img alt="TalkPro icon" class="absolute h-[126.98%] left-0 max-w-none top-[-13.49%] w-full" src={logoIcon} />
|
|
||||||
</div>
|
</div>
|
||||||
<div class="absolute inset-[26.97%_0_7.92%_45.45%]">
|
<div class="site-logo__wordmark-frame">
|
||||||
<img alt="TalkPro" class="absolute block inset-0 max-w-none size-full" src={logoWordmark} />
|
<img alt={t.logoAlt} class="site-logo__wordmark" src={logoWordmark} />
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Desktop nav -->
|
<nav class="site-nav" aria-label={t.navLabel}>
|
||||||
<nav class="hidden lg:flex items-center gap-[32px] shrink-0" aria-label="Main navigation">
|
{navItems.map((item, index) => (
|
||||||
<a href="#hero" class="font-semibold text-[14px] text-[#f28a4b] tracking-[-0.09px] whitespace-nowrap leading-normal" data-nav-link>Home</a>
|
<a href={item.href} class={`site-nav__link ${index === 0 ? 'is-active' : ''}`} data-nav-link>{item.label}</a>
|
||||||
<a href="#features" class="font-semibold text-[14px] text-[#7a726d] tracking-[-0.09px] whitespace-nowrap leading-normal hover:text-[#f28a4b] transition-colors" data-nav-link>Features</a>
|
))}
|
||||||
<a href="#experience" class="font-semibold text-[14px] text-[#7a726d] tracking-[-0.09px] whitespace-nowrap leading-normal hover:text-[#f28a4b] transition-colors" data-nav-link>Experience</a>
|
|
||||||
<a href="#use-cases" class="font-semibold text-[14px] text-[#7a726d] tracking-[-0.09px] whitespace-nowrap leading-normal hover:text-[#f28a4b] transition-colors" data-nav-link>Use Cases</a>
|
|
||||||
<a href="#reliability" class="font-semibold text-[14px] text-[#7a726d] tracking-[-0.09px] whitespace-nowrap leading-normal hover:text-[#f28a4b] transition-colors" data-nav-link>Reliability</a>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- Actions -->
|
<div class="site-header__actions">
|
||||||
<div class="flex flex-1 gap-[12px] items-center justify-end min-w-0">
|
<div class="language-switcher">
|
||||||
<!-- Language button (desktop only) -->
|
<button
|
||||||
<button class="hidden lg:flex border border-[rgba(46,42,40,0.3)] gap-[8px] h-[43px] items-center justify-center pl-[12px] pr-[16px] rounded-[17px] shrink-0 hover:border-[#f28a4b] transition-colors">
|
id="language-toggle"
|
||||||
<img alt="Language" class="block size-[26px] object-contain" src={globeIcon} />
|
class="language-switcher__button"
|
||||||
<span class="font-semibold text-[14px] text-[#2e2a28] tracking-[-0.09px] whitespace-nowrap leading-[14px]">EN</span>
|
type="button"
|
||||||
|
aria-label={t.languageAlt}
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-controls="language-menu"
|
||||||
|
>
|
||||||
|
<img alt="" class="language-switcher__icon" src={globeIcon} />
|
||||||
|
<span class="language-switcher__current">{languageLabels[lang]}</span>
|
||||||
</button>
|
</button>
|
||||||
<!-- Download button (desktop only) -->
|
<div id="language-menu" class="language-switcher__menu is-hidden" aria-hidden="true">
|
||||||
<a href="#download" class="hidden lg:flex bg-[#f28a4b] items-center justify-center px-[22px] py-[13px] rounded-[17px] shrink-0 hover:bg-[#e07a3b] transition-colors">
|
{languageOptions.map(option => (
|
||||||
<span class="font-bold text-[14px] text-white leading-normal whitespace-nowrap">Download</span>
|
<a
|
||||||
|
href={option.href}
|
||||||
|
class={`language-switcher__option ${option.lang === lang ? 'is-active' : ''}`}
|
||||||
|
aria-current={option.lang === lang ? 'page' : undefined}
|
||||||
|
>
|
||||||
|
{option.label}
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a href="#download" class="site-header__download">
|
||||||
|
<span class="site-header__download-label">{t.download}</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- Hamburger toggle (mobile only) -->
|
|
||||||
<button
|
<button
|
||||||
id="menu-toggle"
|
id="menu-toggle"
|
||||||
class="lg:hidden flex flex-col justify-center gap-[5px] w-[40px] h-[40px] p-[8px] shrink-0"
|
class="menu-toggle"
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="Open menu"
|
aria-label={t.openMenu}
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-controls="mobile-nav"
|
aria-controls="mobile-nav"
|
||||||
|
data-open-label={t.openMenu}
|
||||||
|
data-close-label={t.closeMenu}
|
||||||
>
|
>
|
||||||
<span id="bar-1" class="block w-full h-[2px] bg-[#2e2a28] rounded-sm transition-all duration-[240ms] origin-center"></span>
|
<span id="bar-1" class="menu-toggle__bar"></span>
|
||||||
<span id="bar-2" class="block w-full h-[2px] bg-[#2e2a28] rounded-sm transition-all duration-[240ms]"></span>
|
<span id="bar-2" class="menu-toggle__bar"></span>
|
||||||
<span id="bar-3" class="block w-full h-[2px] bg-[#2e2a28] rounded-sm transition-all duration-[240ms] origin-center"></span>
|
<span id="bar-3" class="menu-toggle__bar"></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Mobile nav drawer -->
|
<div id="mobile-nav" class="mobile-nav is-hidden" aria-hidden="true">
|
||||||
<div id="mobile-nav" class="hidden lg:!hidden border-t border-[#e3d9d1] bg-white" aria-hidden="true">
|
<ul class="mobile-nav__list">
|
||||||
<ul class="flex flex-col px-6 py-4 list-none m-0 p-0 px-6 py-4">
|
{navItems.map((item, index) => (
|
||||||
<li><a href="#hero" class="block py-4 font-semibold text-[16px] text-[#2e2a28] border-b border-[#e3d9d1]" data-nav-link>Home</a></li>
|
<li><a href={item.href} class={`mobile-nav__link ${index === navItems.length - 1 ? 'mobile-nav__link--last' : ''}`} data-nav-link>{item.label}</a></li>
|
||||||
<li><a href="#features" class="block py-4 font-semibold text-[16px] text-[#2e2a28] border-b border-[#e3d9d1]" data-nav-link>Features</a></li>
|
))}
|
||||||
<li><a href="#experience" class="block py-4 font-semibold text-[16px] text-[#2e2a28] border-b border-[#e3d9d1]" data-nav-link>Experience</a></li>
|
<li class="mobile-nav__languages">
|
||||||
<li><a href="#use-cases" class="block py-4 font-semibold text-[16px] text-[#2e2a28] border-b border-[#e3d9d1]" data-nav-link>Use Cases</a></li>
|
{languages.map(item => (
|
||||||
<li><a href="#reliability" class="block py-4 font-semibold text-[16px] text-[#2e2a28]" data-nav-link>Reliability</a></li>
|
<a href={getLocalePath(item)} class={`mobile-nav__language-link ${item === lang ? 'is-active' : ''}`} aria-current={item === lang ? 'page' : undefined}>
|
||||||
<li class="mt-4 mb-2">
|
{languageNames[item]}
|
||||||
<a href="#download" class="block text-center bg-[#f28a4b] text-white font-bold text-[15px] py-[14px] px-6 rounded-[17px] hover:bg-[#e07a3b] transition-colors">
|
</a>
|
||||||
Download
|
))}
|
||||||
|
</li>
|
||||||
|
<li class="mobile-nav__download-item">
|
||||||
|
<a href="#download" class="mobile-nav__download">
|
||||||
|
{t.download}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -79,13 +117,28 @@ const globeIcon = "/assets/header-globe.svg";
|
|||||||
const bar1 = document.getElementById('bar-1') as HTMLSpanElement;
|
const bar1 = document.getElementById('bar-1') as HTMLSpanElement;
|
||||||
const bar2 = document.getElementById('bar-2') as HTMLSpanElement;
|
const bar2 = document.getElementById('bar-2') as HTMLSpanElement;
|
||||||
const bar3 = document.getElementById('bar-3') as HTMLSpanElement;
|
const bar3 = document.getElementById('bar-3') as HTMLSpanElement;
|
||||||
|
const languageToggle = document.getElementById('language-toggle') as HTMLButtonElement | null;
|
||||||
|
const languageMenu = document.getElementById('language-menu') as HTMLDivElement | null;
|
||||||
|
|
||||||
|
function closeLanguageMenu() {
|
||||||
|
if (!languageToggle || !languageMenu) return;
|
||||||
|
languageToggle.setAttribute('aria-expanded', 'false');
|
||||||
|
languageMenu.classList.add('is-hidden');
|
||||||
|
languageMenu.setAttribute('aria-hidden', 'true');
|
||||||
|
}
|
||||||
|
|
||||||
|
function openLanguageMenu() {
|
||||||
|
if (!languageToggle || !languageMenu) return;
|
||||||
|
languageToggle.setAttribute('aria-expanded', 'true');
|
||||||
|
languageMenu.classList.remove('is-hidden');
|
||||||
|
languageMenu.removeAttribute('aria-hidden');
|
||||||
|
}
|
||||||
|
|
||||||
function openMenu() {
|
function openMenu() {
|
||||||
toggle.setAttribute('aria-expanded', 'true');
|
toggle.setAttribute('aria-expanded', 'true');
|
||||||
toggle.setAttribute('aria-label', 'Close menu');
|
toggle.setAttribute('aria-label', toggle.dataset.closeLabel || 'Close menu');
|
||||||
nav.classList.remove('hidden');
|
nav.classList.remove('is-hidden');
|
||||||
nav.removeAttribute('aria-hidden');
|
nav.removeAttribute('aria-hidden');
|
||||||
// Animate to X
|
|
||||||
bar1.style.transform = 'translateY(7px) rotate(45deg)';
|
bar1.style.transform = 'translateY(7px) rotate(45deg)';
|
||||||
bar2.style.opacity = '0';
|
bar2.style.opacity = '0';
|
||||||
bar3.style.transform = 'translateY(-7px) rotate(-45deg)';
|
bar3.style.transform = 'translateY(-7px) rotate(-45deg)';
|
||||||
@@ -93,10 +146,9 @@ const globeIcon = "/assets/header-globe.svg";
|
|||||||
|
|
||||||
function closeMenu() {
|
function closeMenu() {
|
||||||
toggle.setAttribute('aria-expanded', 'false');
|
toggle.setAttribute('aria-expanded', 'false');
|
||||||
toggle.setAttribute('aria-label', 'Open menu');
|
toggle.setAttribute('aria-label', toggle.dataset.openLabel || 'Open menu');
|
||||||
nav.classList.add('hidden');
|
nav.classList.add('is-hidden');
|
||||||
nav.setAttribute('aria-hidden', 'true');
|
nav.setAttribute('aria-hidden', 'true');
|
||||||
// Reset bars
|
|
||||||
bar1.style.transform = '';
|
bar1.style.transform = '';
|
||||||
bar2.style.opacity = '';
|
bar2.style.opacity = '';
|
||||||
bar3.style.transform = '';
|
bar3.style.transform = '';
|
||||||
@@ -106,11 +158,23 @@ const globeIcon = "/assets/header-globe.svg";
|
|||||||
toggle.getAttribute('aria-expanded') === 'true' ? closeMenu() : openMenu();
|
toggle.getAttribute('aria-expanded') === 'true' ? closeMenu() : openMenu();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Close when any nav link is clicked
|
languageToggle?.addEventListener('click', event => {
|
||||||
|
event.stopPropagation();
|
||||||
|
languageToggle.getAttribute('aria-expanded') === 'true' ? closeLanguageMenu() : openLanguageMenu();
|
||||||
|
});
|
||||||
|
|
||||||
|
languageMenu?.addEventListener('click', event => event.stopPropagation());
|
||||||
|
|
||||||
|
document.addEventListener('click', closeLanguageMenu);
|
||||||
|
|
||||||
|
document.addEventListener('keydown', event => {
|
||||||
|
if (event.key === 'Escape') closeLanguageMenu();
|
||||||
|
});
|
||||||
|
|
||||||
nav.querySelectorAll('a').forEach(a => a.addEventListener('click', closeMenu));
|
nav.querySelectorAll('a').forEach(a => a.addEventListener('click', closeMenu));
|
||||||
|
|
||||||
// Close when resized past mobile breakpoint
|
|
||||||
window.addEventListener('resize', () => {
|
window.addEventListener('resize', () => {
|
||||||
if (window.innerWidth >= 1024) closeMenu();
|
if (window.innerWidth >= 1024) closeMenu();
|
||||||
|
if (window.innerWidth < 1024) closeLanguageMenu();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,57 +1,56 @@
|
|||||||
---
|
---
|
||||||
|
import type { Translations } from '../i18n/translations'
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
t: Translations['hero']
|
||||||
|
}
|
||||||
|
|
||||||
|
const { t } = Astro.props
|
||||||
const heroBg = "/assets/hero-bg.png";
|
const heroBg = "/assets/hero-bg.png";
|
||||||
const phoneMockup = "/assets/hero-phone.png";
|
const phoneMockup = "/assets/hero-phone.png";
|
||||||
---
|
---
|
||||||
|
|
||||||
<section id="hero" class="relative w-full flex items-start justify-center min-h-[600px] lg:h-[891px] overflow-hidden">
|
<section id="hero" class="hero">
|
||||||
<img alt="" class="absolute inset-0 max-w-none object-cover size-full pointer-events-none" src={heroBg} />
|
<img alt="" class="hero__bg" src={heroBg} />
|
||||||
|
|
||||||
<div class="relative flex flex-col-reverse lg:flex-row gap-[40px] items-start w-full max-w-[1280px] mx-auto px-4 lg:px-0 h-full">
|
<div class="hero__inner">
|
||||||
<!-- Phone mockup -->
|
<div class="hero__phone-column">
|
||||||
<div class="hidden lg:flex flex-1 items-center min-w-0 pt-[60px] h-full">
|
<div class="hero__phone-frame">
|
||||||
<div class="relative w-full" style="aspect-ratio: 673/1108;">
|
<div class="hero__phone-crop">
|
||||||
<div class="absolute inset-0 overflow-hidden pointer-events-none">
|
<img alt={t.phoneAlt} class="hero__phone" src={phoneMockup} />
|
||||||
<img alt="TalkPro app on iPhone" class="absolute h-[114.36%] left-[-2.67%] max-w-none top-[-7.18%] w-[105.35%]" src={phoneMockup} />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Hero copy -->
|
<div class="hero__content">
|
||||||
<div class="flex flex-col gap-[60px] h-full items-start justify-center overflow-clip shrink-0 w-full lg:w-[660px] py-8 lg:py-[80px]">
|
<div class="hero__badge">
|
||||||
<!-- Pill -->
|
<p class="hero__badge-text">{t.badge}</p>
|
||||||
<div class="bg-white border border-[#f08458] flex items-center overflow-clip px-[16px] py-[12px] rounded-[999px] shrink-0">
|
|
||||||
<p class="font-bold text-[#0d0d0d] text-[14px] tracking-[-0.09px] leading-normal">✦ Available on iOS and Android</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col gap-[24px] items-start shrink-0 w-full">
|
<div class="hero__copy">
|
||||||
<div class="font-bold text-[#2e2a28] text-[40px] md:text-[56px] lg:text-[72px] tracking-[-1.61px] w-full">
|
<div class="hero__title">
|
||||||
<p class="leading-[1.1] mb-0">A Modern Way to</p>
|
<p class="hero__title-line">{t.titleLine1}</p>
|
||||||
<p class="leading-[1.1]">Stay Connected</p>
|
<p class="hero__title-line">{t.titleLine2}</p>
|
||||||
</div>
|
</div>
|
||||||
<p class="font-normal text-[#7a726d] text-[18px] tracking-[-0.33px] leading-[1.5] w-full">
|
<p class="hero__description">
|
||||||
TalkPro is a modern messaging app designed for clear, simple, and reliable communication. From private chats to group conversations, channels, voice calls, and video calls, TalkPro helps people stay connected in one familiar experience.
|
{t.description}
|
||||||
</p>
|
</p>
|
||||||
<div class="flex flex-wrap gap-[14px] items-center overflow-clip shrink-0">
|
<div class="hero__actions">
|
||||||
<a href="#download" class="bg-[#f28a4b] flex items-center justify-center overflow-clip px-[24px] py-[14px] rounded-[17px] shrink-0 hover:bg-[#e07a3b] transition-colors">
|
<a href="#download" class="hero__button hero__button--primary">
|
||||||
<span class="font-bold text-white text-[15px] tracking-[-0.13px] leading-normal">Download TalkPro ↓</span>
|
<span class="hero__button-label">{t.download}</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="#features" class="bg-[rgba(255,255,255,0.55)] border border-[#e3d9d1] flex items-center justify-center overflow-clip px-[24px] py-[14px] rounded-[17px] shrink-0 hover:bg-white transition-colors">
|
<a href="#features" class="hero__button hero__button--secondary">
|
||||||
<span class="font-bold text-[#2e2a28] text-[15px] tracking-[-0.13px] leading-normal">Explore Features →</span>
|
<span class="hero__button-label">{t.explore}</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Tags -->
|
<div class="hero__tags">
|
||||||
<div class="flex flex-wrap gap-[10px] items-center overflow-clip shrink-0">
|
{t.tags.map(tag => (
|
||||||
<div class="bg-[rgba(255,255,255,0.68)] border border-white flex items-center overflow-clip px-[14px] py-[9px] rounded-[999px] shrink-0">
|
<div class="hero__tag">
|
||||||
<span class="font-bold text-[#7a726d] text-[14px] tracking-[-0.09px] whitespace-nowrap leading-normal">Identity Layer</span>
|
<span class="hero__tag-text">{tag}</span>
|
||||||
</div>
|
|
||||||
<div class="bg-[rgba(255,255,255,0.68)] border border-white flex items-center overflow-clip px-[14px] py-[9px] rounded-[999px] shrink-0">
|
|
||||||
<span class="font-bold text-[#7a726d] text-[14px] tracking-[-0.09px] whitespace-nowrap leading-normal">AI Native Messaging</span>
|
|
||||||
</div>
|
|
||||||
<div class="bg-[rgba(255,255,255,0.68)] border border-white flex items-center overflow-clip px-[14px] py-[9px] rounded-[999px] shrink-0">
|
|
||||||
<span class="font-bold text-[#7a726d] text-[14px] tracking-[-0.09px] whitespace-nowrap leading-normal">Adaptive Privacy</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,96 +1,58 @@
|
|||||||
---
|
---
|
||||||
|
import type { Translations } from '../i18n/translations'
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
t: Translations['trust']
|
||||||
|
}
|
||||||
|
|
||||||
|
const { t } = Astro.props
|
||||||
|
const iconClasses = [
|
||||||
|
'trust-card__icon--one',
|
||||||
|
'trust-card__icon--two',
|
||||||
|
'trust-card__icon--three',
|
||||||
|
'trust-card__icon--four',
|
||||||
|
]
|
||||||
---
|
---
|
||||||
|
|
||||||
<section id="reliability" class="bg-white w-full flex flex-col items-center justify-center py-16 px-4 lg:p-[120px]">
|
<section id="reliability" class="trust">
|
||||||
<div class="flex flex-col gap-[40px] items-start w-full max-w-[1280px] mx-auto">
|
<div class="trust__inner">
|
||||||
|
<div class="trust__header">
|
||||||
<!-- Header -->
|
<div class="section-eyebrow">
|
||||||
<div class="flex flex-col gap-[24px] items-start overflow-clip w-full">
|
<span class="section-eyebrow__text">{t.eyebrow}</span>
|
||||||
<div class="bg-white border border-[#fbbfa3] flex items-center justify-center px-[24px] py-[12px] rounded-[9999px] shrink-0">
|
|
||||||
<span class="font-bold text-[#f08458] text-[14px] text-center tracking-[-0.04px] whitespace-nowrap leading-normal">RELIABILITY</span>
|
|
||||||
</div>
|
</div>
|
||||||
<p class="font-bold text-[#1a1a1a] text-[32px] md:text-[40px] lg:text-[48px] tracking-[-1.16px] leading-[1.2] w-full">Built with User Trust in Mind</p>
|
<p class="trust__title">{t.title}</p>
|
||||||
<p class="font-normal text-[#7a726d] text-[18px] tracking-[-0.33px] leading-[1.5] w-full">
|
<p class="trust__description">
|
||||||
TalkPro is designed with a privacy-conscious approach and a focus on dependable communication. The app keeps the user experience simple while supporting the core communication features people expect from a modern messaging platform.
|
{t.description}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 4-column feature row -->
|
<div class="trust__grid">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:flex lg:gap-[24px] lg:items-center gap-8 justify-center w-full">
|
{t.cards.map((card, index) => (
|
||||||
|
<>
|
||||||
<!-- Card 1: Privacy-Conscious Design -->
|
<div class="trust-card">
|
||||||
<div class="flex flex-1 flex-col gap-[16px] items-center justify-end min-w-0 p-[24px] rounded-[30px]">
|
<div class="trust-card__icon-frame">
|
||||||
<div class="relative shrink-0 size-[128px]">
|
<div class="trust-card__icon-crop">
|
||||||
<div class="absolute inset-0 overflow-hidden pointer-events-none">
|
<img
|
||||||
<img alt="" class="absolute h-[174.55%] left-[-31.48%] max-w-none top-[7.04%] w-[312.73%]" src="/assets/trust-icon-sprite.png" />
|
alt=""
|
||||||
|
class={`trust-card__icon ${iconClasses[index]}`}
|
||||||
|
src={index === 3 ? "/assets/trust-icon-improvement.png" : "/assets/trust-icon-sprite.png"}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-[8px] items-start w-full">
|
<div class="trust-card__copy">
|
||||||
<p class="font-semibold text-[#0d0d0d] text-[16px] leading-[22px] w-full">Privacy-Conscious Design</p>
|
<p class="trust-card__title">{card.title}</p>
|
||||||
<p class="font-medium text-[#7a726d] text-[15px] leading-[1.5] w-full">Built with careful consideration for user communication and data handling.</p>
|
<p class="trust-card__description">{card.desc}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{index < t.cards.length - 1 && (
|
||||||
<!-- Divider -->
|
<div class="trust__divider">
|
||||||
<div class="hidden lg:block relative h-[118px] shrink-0 w-0">
|
<div class="trust__divider-frame">
|
||||||
<div class="absolute inset-[0_-0.5px]">
|
<img alt="" class="trust__divider-image" src="/assets/trust-divider.svg" />
|
||||||
<img alt="" class="block max-w-none size-full" src="/assets/trust-divider.svg" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
<!-- Card 2: Minimal and Focused -->
|
</>
|
||||||
<div class="flex flex-1 flex-col gap-[16px] items-center justify-end min-w-0 p-[24px] rounded-[30px]">
|
))}
|
||||||
<div class="relative shrink-0 size-[128px]">
|
|
||||||
<div class="absolute inset-0 overflow-hidden pointer-events-none">
|
|
||||||
<img alt="" class="absolute h-[187.32%] left-[-164.72%] max-w-none top-[3.1%] w-[335.61%]" src="/assets/trust-icon-sprite.png" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col gap-[8px] items-start w-full">
|
|
||||||
<p class="font-semibold text-[#0d0d0d] text-[16px] leading-[22px] w-full">Minimal and Focused</p>
|
|
||||||
<p class="font-medium text-[#7a726d] text-[15px] leading-[1.5] w-full">Designed around essential messaging features without unnecessary complexity.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Divider -->
|
|
||||||
<div class="hidden lg:block relative h-[118px] shrink-0 w-0">
|
|
||||||
<div class="absolute inset-[0_-0.5px]">
|
|
||||||
<img alt="" class="block max-w-none size-full" src="/assets/trust-divider.svg" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Card 3: Reliable Experience -->
|
|
||||||
<div class="flex flex-1 flex-col gap-[16px] items-center justify-end min-w-0 p-[24px] rounded-[30px]">
|
|
||||||
<div class="relative shrink-0 size-[128px]">
|
|
||||||
<div class="absolute inset-0 overflow-hidden pointer-events-none">
|
|
||||||
<img alt="" class="absolute h-[211.46%] left-[-187.93%] max-w-none top-[-105.62%] w-[378.86%]" src="/assets/trust-icon-sprite.png" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col gap-[8px] items-start w-full">
|
|
||||||
<p class="font-semibold text-[#0d0d0d] text-[16px] leading-[22px] w-full">Reliable Experience</p>
|
|
||||||
<p class="font-medium text-[#7a726d] text-[15px] leading-[1.5] w-full">Focused on providing a stable and familiar communication experience.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Divider -->
|
|
||||||
<div class="hidden lg:block relative h-[118px] shrink-0 w-0">
|
|
||||||
<div class="absolute inset-[0_-0.5px]">
|
|
||||||
<img alt="" class="block max-w-none size-full" src="/assets/trust-divider.svg" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Card 4: Continuous Improvement -->
|
|
||||||
<div class="flex flex-1 flex-col gap-[16px] items-center justify-end min-w-0 p-[24px] rounded-[30px]">
|
|
||||||
<div class="relative shrink-0 size-[128px]">
|
|
||||||
<div class="absolute inset-0 overflow-hidden pointer-events-none">
|
|
||||||
<img alt="" class="absolute left-[4.14%] max-w-none size-full top-0" src="/assets/trust-icon-improvement.png" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col gap-[8px] items-start w-full">
|
|
||||||
<p class="font-semibold text-[#0d0d0d] text-[16px] leading-[22px] w-full">Continuous Improvement</p>
|
|
||||||
<p class="font-medium text-[#7a726d] text-[15px] leading-[1.5] w-full">TalkPro will continue to improve its interface, features, and overall user experience.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,36 +1,35 @@
|
|||||||
---
|
---
|
||||||
const rows = [
|
import type { Translations } from '../i18n/translations'
|
||||||
{ title: 'Personal Conversations', desc: 'Message friends, family, and close contacts in a simple private chat experience.' },
|
|
||||||
{ title: 'Communities', desc: 'Join group conversations and stay active in shared interest spaces.' },
|
export interface Props {
|
||||||
{ title: 'Teams and Projects', desc: 'Coordinate discussions, updates, and quick decisions in group chats.' },
|
t: Translations['useCases']
|
||||||
{ title: 'News and Updates', desc: 'Follow channels for announcements, information, and community content.' },
|
}
|
||||||
]
|
|
||||||
|
const { t } = Astro.props
|
||||||
---
|
---
|
||||||
|
|
||||||
<section id="use-cases" class="bg-[#fef0eb] w-full flex items-start justify-center py-16 lg:py-[120px] px-4 lg:px-[130px]">
|
<section id="use-cases" class="use-cases">
|
||||||
<div class="flex flex-col lg:flex-row lg:gap-[40px] lg:items-center gap-8 w-full max-w-[1280px] mx-auto">
|
<div class="use-cases__inner">
|
||||||
<!-- Left: heading -->
|
<div class="use-cases__copy">
|
||||||
<div class="flex flex-col gap-[24px] items-start overflow-clip shrink-0 w-full lg:w-[540px] lg:shrink-0">
|
<div class="section-eyebrow">
|
||||||
<div class="bg-white border border-[#fbbfa3] flex items-center justify-center px-[24px] py-[12px] rounded-[9999px] shrink-0">
|
<span class="section-eyebrow__text">{t.eyebrow}</span>
|
||||||
<span class="font-bold text-[#f08458] text-[14px] text-center tracking-[-0.04px] whitespace-nowrap leading-normal">USE CASES</span>
|
|
||||||
</div>
|
</div>
|
||||||
<p class="font-bold text-[#1a1a1a] text-[32px] md:text-[40px] lg:text-[48px] tracking-[-1.16px] leading-[1.2] w-full">
|
<p class="use-cases__title">
|
||||||
Made for Personal, Social, and Community Communication
|
{t.title}
|
||||||
</p>
|
</p>
|
||||||
<p class="font-normal text-[#7a726d] text-[18px] tracking-[-0.33px] leading-[1.5] w-full">
|
<p class="use-cases__description">
|
||||||
With separate spaces for every context, TalkPro keeps your personal, social, and professional communications distinct and organized.
|
{t.description}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Right: rows -->
|
<div class="use-cases__rows">
|
||||||
<div class="flex flex-1 flex-col items-start min-w-0 overflow-clip rounded-[30px] gap-px">
|
{t.rows.map(row => (
|
||||||
{rows.map(row => (
|
<div class="use-case-row">
|
||||||
<div class="bg-[#faede8] flex flex-col sm:flex-row sm:h-[120px] items-stretch overflow-clip w-full shrink-0">
|
<div class="use-case-row__title-cell">
|
||||||
<div class="bg-[#f08458] flex items-center px-[24px] sm:px-[36px] py-[16px] sm:py-[24px] shrink-0 w-full sm:w-[300px]">
|
<p class="use-case-row__title">{row.title}</p>
|
||||||
<p class="flex-1 font-semibold text-[18px] sm:text-[20px] text-white tracking-[-0.6px] leading-normal min-w-0">{row.title}</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-white flex flex-1 items-center min-w-0 px-[24px] sm:px-[36px] py-[16px] sm:py-[24px]">
|
<div class="use-case-row__description-cell">
|
||||||
<p class="font-medium text-[#7a726d] text-[15px] leading-[1.5] flex-1 min-w-0">{row.desc}</p>
|
<p class="use-case-row__description">{row.desc}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -1,83 +1,61 @@
|
|||||||
---
|
---
|
||||||
|
import type { Translations } from '../i18n/translations'
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
t: Translations['why']
|
||||||
|
}
|
||||||
|
|
||||||
|
const { t } = Astro.props
|
||||||
const underline = "/assets/why-underline.svg";
|
const underline = "/assets/why-underline.svg";
|
||||||
const iconSimple = "/assets/why-icon-simple.svg";
|
const icons = [
|
||||||
const iconFamiliar = "/assets/why-icon-familiar.svg";
|
"/assets/why-icon-simple.svg",
|
||||||
const iconConn = "/assets/why-icon-connected.svg";
|
"/assets/why-icon-familiar.svg",
|
||||||
const iconModern = "/assets/why-icon-modern.svg";
|
"/assets/why-icon-connected.svg",
|
||||||
|
"/assets/why-icon-modern.svg",
|
||||||
|
]
|
||||||
|
const iconClasses = ['why-card__icon--square', 'why-card__icon--familiar', 'why-card__icon--square', 'why-card__icon--modern']
|
||||||
---
|
---
|
||||||
|
|
||||||
<section class="bg-white w-full flex flex-col items-center justify-center py-16 lg:py-[120px]">
|
<section class="why">
|
||||||
<div class="flex flex-col gap-[40px] items-start w-full max-w-[1280px] mx-auto px-4 lg:px-0">
|
<div class="why__inner">
|
||||||
|
<div class="why__intro">
|
||||||
<!-- Header row -->
|
<div class="why__copy">
|
||||||
<div class="flex flex-col lg:flex-row gap-[36px] items-start overflow-clip w-full">
|
<div class="section-eyebrow">
|
||||||
<!-- Left: pill + heading + description -->
|
<span class="section-eyebrow__text">{t.eyebrow}</span>
|
||||||
<div class="flex flex-1 flex-col gap-[36px] items-start min-w-0">
|
|
||||||
<div class="bg-white border border-[#fbbfa3] flex items-center justify-center px-[24px] py-[12px] rounded-[9999px] shrink-0">
|
|
||||||
<span class="font-bold text-[#f08458] text-[14px] text-center tracking-[-0.04px] whitespace-nowrap leading-normal">WHY TALKPRO</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-[24px] items-start w-full">
|
<div class="why__text">
|
||||||
<div class="font-bold text-[#1a1a1a] text-[32px] md:text-[40px] lg:text-[48px] tracking-[-1.16px] w-full">
|
<div class="why__title">
|
||||||
<p class="leading-[1.2] mb-0">Designed for the Way</p>
|
<p class="why__title-line">{t.titleLine1}</p>
|
||||||
<p class="leading-[1.2]">People Communicate Today</p>
|
<p class="why__title-line">{t.titleLine2}</p>
|
||||||
</div>
|
</div>
|
||||||
<!-- Underline decoration -->
|
<div class="why__underline">
|
||||||
<div class="relative h-0 w-[295.5px] shrink-0">
|
<div class="why__underline-frame">
|
||||||
<div class="absolute inset-[-0.5px_0]">
|
<img alt="" class="why__underline-image" src={underline} />
|
||||||
<img alt="" class="block max-w-none size-full" src={underline} />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="font-normal text-[#7a726d] text-[18px] tracking-[-0.33px] leading-[1.5] w-full">
|
<p class="why__description">
|
||||||
Communication today happens across personal conversations, communities, work groups, and content channels. TalkPro brings these essential communication experiences together in a simple and familiar interface, making it easier for users to connect, share, and stay updated.
|
{t.description}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Right: illustration -->
|
<div class="why__illustration">
|
||||||
<div class="hidden lg:block relative shrink-0 size-[480px]">
|
<img alt={t.illustrationAlt} class="why__illustration-image" src="/assets/why-illustration.png" />
|
||||||
<img alt="People communicating with TalkPro" class="absolute inset-0 size-full object-contain" src="/assets/why-illustration.png" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 2×2 card grid -->
|
<div class="why__grid">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 w-full">
|
{t.cards.map((card, index) => (
|
||||||
<div class="bg-[#fef0eb] border border-[#e8e4de] flex gap-[24px] h-auto md:h-[152px] items-center min-w-0 overflow-clip p-[36px] rounded-[30px]">
|
<div class="why-card">
|
||||||
<div class="bg-[#f08458] aspect-square h-[80px] flex items-center justify-center overflow-clip rounded-[9999px] shrink-0">
|
<div class="why-card__icon-frame">
|
||||||
<img alt="" class="block size-[44px]" src={iconSimple} />
|
<img alt="" class={`why-card__icon ${iconClasses[index]}`} src={icons[index]} />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-1 flex-col gap-[12px] items-start min-w-0 overflow-clip">
|
<div class="why-card__copy">
|
||||||
<p class="font-semibold text-[#0d0d0d] text-[24px] tracking-[-0.47px] leading-[20px] w-full">Simple</p>
|
<p class="why-card__title">{card.title}</p>
|
||||||
<p class="font-medium text-[#7a726d] text-[16px] tracking-[-0.18px] leading-[1.5] w-full">An easy-to-use experience designed for everyday communication.</p>
|
<p class="why-card__description">{card.desc}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-[#fef0eb] border border-[#e8e4de] flex gap-[24px] h-auto md:h-[152px] items-center min-w-0 overflow-clip p-[36px] rounded-[30px]">
|
))}
|
||||||
<div class="bg-[#f08458] aspect-square h-[80px] flex items-center justify-center overflow-clip rounded-[9999px] shrink-0">
|
|
||||||
<img alt="" class="block" style="width:38px;height:40px;" src={iconFamiliar} />
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-1 flex-col gap-[12px] items-start min-w-0 overflow-clip">
|
|
||||||
<p class="font-semibold text-[#0d0d0d] text-[24px] tracking-[-0.47px] leading-[20px] w-full">Familiar</p>
|
|
||||||
<p class="font-medium text-[#7a726d] text-[16px] tracking-[-0.18px] leading-[1.5] w-full">A messaging structure that feels natural from the first use.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="bg-[#fef0eb] border border-[#e8e4de] flex gap-[24px] h-auto md:h-[152px] items-center min-w-0 overflow-clip p-[36px] rounded-[30px]">
|
|
||||||
<div class="bg-[#f08458] aspect-square h-[80px] flex items-center justify-center overflow-clip rounded-[9999px] shrink-0">
|
|
||||||
<img alt="" class="block size-[44px]" src={iconConn} />
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-1 flex-col gap-[12px] items-start min-w-0 overflow-clip">
|
|
||||||
<p class="font-semibold text-[#0d0d0d] text-[24px] tracking-[-0.47px] leading-[20px] w-full">Connected</p>
|
|
||||||
<p class="font-medium text-[#7a726d] text-[16px] tracking-[-0.18px] leading-[1.5] w-full">Private chats, groups, channels, voice, and video in one app.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="bg-[#fef0eb] border border-[#e8e4de] flex gap-[24px] h-auto md:h-[152px] items-center min-w-0 overflow-clip p-[36px] rounded-[30px]">
|
|
||||||
<div class="bg-[#f08458] aspect-square h-[80px] flex items-center justify-center overflow-clip rounded-[9999px] shrink-0">
|
|
||||||
<img alt="" class="block" style="width:24px;height:44px;" src={iconModern} />
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-1 flex-col gap-[12px] items-start min-w-0 overflow-clip">
|
|
||||||
<p class="font-semibold text-[#0d0d0d] text-[24px] tracking-[-0.47px] leading-[20px] w-full">Modern</p>
|
|
||||||
<p class="font-medium text-[#7a726d] text-[16px] tracking-[-0.18px] leading-[1.5] w-full">A refined interface with clean visuals and smooth interaction.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -3,16 +3,23 @@ import '../styles/global.css'
|
|||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
title?: string
|
title?: string
|
||||||
|
description?: string
|
||||||
|
lang?: string
|
||||||
}
|
}
|
||||||
const { title = 'Talk Pro — One User. Multiple Worlds.' } = Astro.props
|
|
||||||
|
const {
|
||||||
|
title = 'Talk Pro - One User. Multiple Worlds.',
|
||||||
|
description = 'Talk Pro is a modern messaging app for private chats, group conversations, channels, voice and video calls.',
|
||||||
|
lang = 'en',
|
||||||
|
} = Astro.props
|
||||||
---
|
---
|
||||||
|
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang={lang}>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta name="description" content="Talk Pro is a modern messaging app for private chats, group conversations, channels, voice and video calls." />
|
<meta name="description" content={description} />
|
||||||
<title>{title}</title>
|
<title>{title}</title>
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
@@ -25,7 +32,6 @@ const { title = 'Talk Pro — One User. Multiple Worlds.' } = Astro.props
|
|||||||
const header = document.getElementById('site-header');
|
const header = document.getElementById('site-header');
|
||||||
const getOffset = () => header ? header.offsetHeight : 0;
|
const getOffset = () => header ? header.offsetHeight : 0;
|
||||||
|
|
||||||
// Smooth scroll with header offset
|
|
||||||
document.querySelectorAll('a[href^="#"]').forEach(link => {
|
document.querySelectorAll('a[href^="#"]').forEach(link => {
|
||||||
link.addEventListener('click', e => {
|
link.addEventListener('click', e => {
|
||||||
const href = link.getAttribute('href');
|
const href = link.getAttribute('href');
|
||||||
@@ -38,7 +44,6 @@ const { title = 'Talk Pro — One User. Multiple Worlds.' } = Astro.props
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Active nav highlighting via IntersectionObserver
|
|
||||||
const navLinks = document.querySelectorAll('[data-nav-link]');
|
const navLinks = document.querySelectorAll('[data-nav-link]');
|
||||||
const sections = Array.from(navLinks)
|
const sections = Array.from(navLinks)
|
||||||
.map(l => document.querySelector(l.getAttribute('href') ?? ''))
|
.map(l => document.querySelector(l.getAttribute('href') ?? ''))
|
||||||
@@ -52,8 +57,7 @@ const { title = 'Talk Pro — One User. Multiple Worlds.' } = Astro.props
|
|||||||
if (!visible) return;
|
if (!visible) return;
|
||||||
navLinks.forEach(link => {
|
navLinks.forEach(link => {
|
||||||
const active = link.getAttribute('href') === `#${visible.target.id}`;
|
const active = link.getAttribute('href') === `#${visible.target.id}`;
|
||||||
link.classList.toggle('!text-[#f28a4b]', active);
|
link.classList.toggle('is-active', active);
|
||||||
link.classList.toggle('text-[#7a726d]', !active);
|
|
||||||
});
|
});
|
||||||
}, { rootMargin: '-30% 0px -60% 0px', threshold: 0 });
|
}, { rootMargin: '-30% 0px -60% 0px', threshold: 0 });
|
||||||
sections.forEach(s => observer.observe(s));
|
sections.forEach(s => observer.observe(s));
|
||||||
|
|||||||
@@ -10,17 +10,21 @@ import Trust from '../components/Trust.astro'
|
|||||||
import AppPreview from '../components/AppPreview.astro'
|
import AppPreview from '../components/AppPreview.astro'
|
||||||
import DownloadCTA from '../components/DownloadCTA.astro'
|
import DownloadCTA from '../components/DownloadCTA.astro'
|
||||||
import Footer from '../components/Footer.astro'
|
import Footer from '../components/Footer.astro'
|
||||||
|
import { defaultLang, getTranslations } from '../i18n/translations'
|
||||||
|
|
||||||
|
const lang = defaultLang
|
||||||
|
const t = getTranslations(lang)
|
||||||
---
|
---
|
||||||
|
|
||||||
<Base>
|
<Base lang={lang} title={t.meta.title} description={t.meta.description}>
|
||||||
<Header />
|
<Header lang={lang} t={t.header} />
|
||||||
<Hero />
|
<Hero t={t.hero} />
|
||||||
<WhyTalkPro />
|
<WhyTalkPro t={t.why} />
|
||||||
<CoreSystem />
|
<CoreSystem t={t.core} />
|
||||||
<Experience />
|
<Experience t={t.experience} />
|
||||||
<UseCases />
|
<UseCases t={t.useCases} />
|
||||||
<Trust />
|
<Trust t={t.trust} />
|
||||||
<AppPreview />
|
<AppPreview t={t.preview} />
|
||||||
<DownloadCTA />
|
<DownloadCTA t={t.download} />
|
||||||
<Footer />
|
<Footer t={t.footer} />
|
||||||
</Base>
|
</Base>
|
||||||
|
|||||||
@@ -1 +1,10 @@
|
|||||||
/* UnoCSS handles reset and utilities via astro.config.mjs injectReset */
|
/* UnoCSS handles reset and utilities via astro.config.mjs injectReset */
|
||||||
|
@import './header.css';
|
||||||
|
@import './hero.css';
|
||||||
|
@import './sections.css';
|
||||||
|
@import './download.css';
|
||||||
|
@import './footer.css';
|
||||||
|
@import './why.css';
|
||||||
|
@import './features.css';
|
||||||
|
@import './trust.css';
|
||||||
|
@import './preview.css';
|
||||||
|
|||||||
Reference in New Issue
Block a user