11---
22import Search from " ./Search.astro" ;
33import ThemeToggle from " ./ThemeToggle.astro" ;
4- import { SUPPORTED_LOCALES , LOCALE_NAMES } from ' ../data/locales' ;
5- import { getUIStrings } from ' ../locales/ui-strings' ;
64
7- interface Props {
8- currentLocale? : string ;
9- currentSlug? : string ;
10- }
11-
12- const { currentLocale, currentSlug } = Astro .props ;
13-
14- const base = import .meta .env .BASE_URL .replace (/ \/ + $ / , ' ' );
15-
16- // Compute cross-locale URLs
17- function getLocaleUrl(targetLocale : string | null ): string {
18- if (! currentSlug ) return targetLocale ? ` ${base }/${targetLocale }/ ` : ` ${base }/ ` ;
19- if (targetLocale ) {
20- return ` ${base }/${targetLocale }/${currentSlug } ` .replace (/ \/ + / g , ' /' );
21- }
22- // English — strip the locale prefix if present
23- return ` ${base }/${currentSlug } ` .replace (/ \/ + / g , ' /' );
24- }
25-
26- const ht = getUIStrings (currentLocale ).header ;
27-
28- // Prefix an internal /docs/... path with the current locale (for initial server render)
29- function localizeHref(path : string ): string {
30- if (! currentLocale ) return path ;
31- return path .replace (/ ^ (\/ docs\/ )/ , ` $1${currentLocale }/ ` );
32- }
33-
34- const docsHomePath = import .meta .env .BASE_URL ; // "/docs/"
35- const serverApiPath = ` ${base }/getting-started-with-server-side-api ` ;
36- const sdkItems = [
37- { label: " iOS" , path: ` ${base }/ios-sdk-overview ` },
38- { label: " Android" , path: ` ${base }/android-sdk-overview ` },
39- { label: " React Native" , path: ` ${base }/react-native-sdk-overview ` },
40- { label: " Flutter" , path: ` ${base }/flutter-sdk-overview ` },
41- { label: " Unity" , path: ` ${base }/unity-sdk-overview ` },
42- { label: " Kotlin Multiplatform" , path: ` ${base }/kmp-sdk-overview ` },
43- { label: " Capacitor" , path: ` ${base }/capacitor-sdk-overview ` },
5+ const links = [
6+ { label: " Documentation" , href: " /" , active: true },
7+ { label: " Blog" , href: " https://adapty.io/blog" , active: false },
8+ { label: " What's new" , href: " https://adapty.io/whats-new" , active: false },
9+ { label: " Glossary" , href: " https://adapty.io/glossary" , active: false },
10+ { label: " Pricing" , href: " https://adapty.io/pricing" , active: false },
4411];
45-
46- const englishUrl = getLocaleUrl (null );
47- const localeLinks = SUPPORTED_LOCALES .map (locale => ({
48- locale ,
49- label: LOCALE_NAMES [locale ],
50- href: getLocaleUrl (locale ),
51- active: currentLocale === locale ,
52- }));
5312---
5413
5514<header class =" header-main" data-nosnippet transition:persist >
@@ -63,12 +22,14 @@ const localeLinks = SUPPORTED_LOCALES.map(locale => ({
6322
6423 <!-- Desktop Navigation -->
6524 <nav class =" hidden lg:flex items-center gap-1 text-[14px] font-medium" >
66- <a href ={ localizeHref (docsHomePath )} data-nav-href ={ docsHomePath } class =" nav-link" data-i18n =" documentation" >{ ht .documentation } </a >
67-
25+ <a href ={ import .meta .env .BASE_URL } class =" nav-link" >
26+ Documentation
27+ </a >
28+
6829 <!-- Mobile SDK Dropdown -->
6930 <div class =" relative dropdown-container" >
7031 <button class =" dropdown-trigger nav-link" >
71- < span data-i18n = " mobileSdk " > { ht . mobileSdk } </ span >
32+ Mobile SDK
7233 <svg class =" dropdown-chevron" fill =" none" viewBox =" 0 0 24 24" stroke =" currentColor" >
7334 <path stroke-linecap =" round" stroke-linejoin =" round" stroke-width =" 2" d =" M19 9l-7 7-7-7" />
7435 </svg >
@@ -77,66 +38,49 @@ const localeLinks = SUPPORTED_LOCALES.map(locale => ({
7738 <!-- Dropdown Menu -->
7839 <div class =" dropdown-menu" >
7940 <div class =" dropdown-content" >
80- { sdkItems .map (item => (
81- <a
82- href = { localizeHref (item .path ).replace (/ \/ + / g , ' /' )}
83- data-nav-href = { item .path .replace (/ \/ + / g , ' /' )}
84- class = " dropdown-item"
85- >
41+ { [
42+ { label: " iOS" , href: ` ${import .meta .env .BASE_URL }/ios-sdk-overview ` },
43+ { label: " Android" , href: ` ${import .meta .env .BASE_URL }/android-sdk-overview ` },
44+ { label: " React Native" , href: ` ${import .meta .env .BASE_URL }/react-native-sdk-overview ` },
45+ { label: " Flutter" , href: ` ${import .meta .env .BASE_URL }/flutter-sdk-overview ` },
46+ { label: " Unity" , href: ` ${import .meta .env .BASE_URL }/unity-sdk-overview ` },
47+ { label: " Kotlin Multiplatform" , href: ` ${import .meta .env .BASE_URL }/kmp-sdk-overview ` },
48+ { label: " Capacitor" , href: ` ${import .meta .env .BASE_URL }/capacitor-sdk-overview ` }
49+ ].map (item => (
50+ <a href = { item .href .replace (/ \/ + / g , ' /' )} class = " dropdown-item" >
8651 { item .label }
8752 </a >
8853 ))}
8954 </div >
9055 </div >
9156 </div >
9257
93- <a href ={ localizeHref ( serverApiPath ). replace ( / \/ + / g , ' / ' ) } data-nav-href = { serverApiPath .replace (/ \/ + / g , ' /' )} class =" nav-link" data-i18n = " serverApi " > { ht . serverApi } </a >
58+ <a href ={ ` ${ import . meta . env . BASE_URL }/developer-cli ` .replace (/ \/ + / g , ' /' )} class =" nav-link" >CLI & APIs </a >
9459 <a href =" https://adapty.io/docs/whats-new" class =" nav-link" data-i18n =" whatsNew" >{ ht .whatsNew } </a >
9560 <a href =" https://adapty.featurebase.app" class =" nav-link" data-i18n =" supportForum" >{ ht .supportForum } </a >
9661 </nav >
9762 </div >
9863
9964 <!-- Search (Desktop) -->
10065 <div class =" hidden lg:flex flex-1 max-w-sm mx-8" >
101- <Search currentLocale = { currentLocale } />
66+ <Search />
10267 </div >
10368
10469 <!-- Auth Buttons & Theme Toggle -->
10570 <div class =" hidden lg:flex items-center gap-3" >
10671 <ThemeToggle />
107-
108- <!-- Language Switcher -->
109- <div class =" lang-switcher relative dropdown-container" >
110- <button class =" lang-trigger nav-link" aria-label =" Switch language" >
111- <span id =" lang-label" >{ currentLocale ? LOCALE_NAMES [currentLocale as keyof typeof LOCALE_NAMES ] ?? currentLocale : ' EN' } </span >
112- <svg class =" dropdown-chevron" fill =" none" viewBox =" 0 0 24 24" stroke =" currentColor" >
113- <path stroke-linecap =" round" stroke-linejoin =" round" stroke-width =" 2" d =" M19 9l-7 7-7-7" />
114- </svg >
115- </button >
116- <div class =" dropdown-menu lang-menu" >
117- <div class =" dropdown-content" >
118- <a
119- href ={ englishUrl }
120- class:list ={ [" dropdown-item" , ! currentLocale ? " lang-active" : " " ]}
121- data-locale =" "
122- >English</a >
123- { localeLinks .map (({ locale , label , href , active }) => (
124- <a
125- href = { href }
126- class :list = { [" dropdown-item" , active ? " lang-active" : " " ]}
127- data-locale = { locale }
128- >{ label } </a >
129- ))}
130- </div >
131- </div >
132- </div >
133-
134- <a href =" https://app.adapty.io/login" class =" nav-link" data-i18n =" signIn" >{ ht .signIn } </a >
135- <a
136- href =" https://app.adapty.io/registration"
72+ <a
73+ href =" https://app.adapty.io/login"
74+ class =" nav-link"
75+ >
76+ Sign In
77+ </a >
78+ <a
79+ href =" https://app.adapty.io/registration"
13780 class =" px-5 py-2.5 text-sm font-semibold text-white bg-[#6720ff] hover:bg-[#5816e8] dark:bg-purple-600 dark:hover:bg-purple-500 rounded-xl transition-all shadow-[0_4px_15px_-2px_rgba(103,32,255,0.3)] hover:shadow-[0_8px_25px_-5px_rgba(103,32,255,0.4)] active:scale-[0.98]"
138- data-i18n =" signUpFree"
139- >{ ht .signUpFree } </a >
81+ >
82+ Sign Up for Free
83+ </a >
14084 </div >
14185
14286 <!-- Mobile Search, Theme & Menu Buttons -->
@@ -346,17 +290,6 @@ const localeLinks = SUPPORTED_LOCALES.map(locale => ({
346290 background: var(--bg-hover);
347291 color: var(--text-primary);
348292 }
349-
350- .lang-active {
351- color: var(--accent-primary);
352- font-weight: 600;
353- }
354-
355- .lang-trigger {
356- gap: 0.375rem;
357- font-size: 0.8125rem;
358- min-width: 2.5rem;
359- }
360293</style >
361294
362295<script >
@@ -380,137 +313,4 @@ const localeLinks = SUPPORTED_LOCALES.map(locale => ({
380313
381314 initMobileThemeToggle();
382315 document.addEventListener('astro:page-load', initMobileThemeToggle);
383-
384- // Locale names map for client-side use
385- const LOCALE_NAMES_CLIENT: Record<string, string> = { zh: '中文' };
386-
387- // UI string translations for client-side sync (mirrors src/locales/ui-strings.ts)
388- const UI_STRINGS_CLIENT: Record<string, Record<string, string>> = {
389- zh: {
390- documentation: '文档',
391- mobileSdk: '移动端 SDK',
392- serverApi: '服务端 API',
393- whatsNew: '最新动态',
394- supportForum: '支持论坛',
395- signIn: '登录',
396- signUpFree: '免费注册',
397- searchPlaceholder: '搜索文档...',
398- searchNoResults: '未找到相关结果。',
399- },
400- en: {
401- documentation: 'Documentation',
402- mobileSdk: 'Mobile SDK',
403- serverApi: 'Server API',
404- whatsNew: "What's new",
405- supportForum: 'Support Forum',
406- signIn: 'Sign In',
407- signUpFree: 'Sign Up for Free',
408- searchPlaceholder: 'Search documentation...',
409- searchNoResults: 'No results found.',
410- },
411- };
412-
413- // Rewrite internal nav link hrefs to include (or strip) the current locale prefix
414- function syncNavLinks() {
415- const localeMatch = window.location.pathname.match(/\/docs\/([a-z]{2})(\/|$)/);
416- const locale = localeMatch ? localeMatch[1] : null;
417-
418- document.querySelectorAll<HTMLAnchorElement>('[data-nav-href]').forEach(el => {
419- const basePath = el.getAttribute('data-nav-href')!;
420- el.href = locale
421- ? basePath.replace(/^(\/docs\/)/, `$1${locale}/`)
422- : basePath;
423- });
424- }
425-
426- // Update nav text content based on current locale in URL
427- function syncHeaderI18n() {
428- const localeMatch = window.location.pathname.match(/\/docs\/([a-z]{2})\//);
429- const locale = localeMatch ? localeMatch[1] : 'en';
430- const strings = UI_STRINGS_CLIENT[locale] ?? UI_STRINGS_CLIENT.en;
431-
432- document.querySelectorAll<HTMLElement>('[data-i18n]').forEach(el => {
433- const key = el.dataset.i18n!;
434- if (strings[key]) el.textContent = strings[key];
435- });
436-
437- document.querySelectorAll<HTMLInputElement>('[data-i18n-placeholder]').forEach(el => {
438- const key = el.dataset.i18nPlaceholder!;
439- if (strings[key]) el.placeholder = strings[key];
440- });
441-
442- // Sync search Algolia index to the current locale.
443- // The header is transition:persist so data-index-name would otherwise stay
444- // at the value baked in at initial page render.
445- const searchInput = document.getElementById('search-input') as HTMLInputElement | null;
446- if (searchInput) {
447- const localeKey = `indexName${locale.charAt(0).toUpperCase() + locale.slice(1)}`;
448- const localeIndex = (searchInput.dataset as Record<string, string>)[localeKey];
449- const defaultIndex = searchInput.dataset.indexNameDefault ?? '';
450- searchInput.dataset.indexName = localeIndex || defaultIndex;
451- }
452-
453- // Sync "no results" text on the search results container.
454- const searchResultsEl = document.getElementById('search-results');
455- if (searchResultsEl && strings['searchNoResults']) {
456- searchResultsEl.dataset.noResults = strings['searchNoResults'];
457- }
458- }
459-
460- // Sync lang switcher label, active state, and hrefs based on current URL.
461- // Needed because the header is transition:persist and doesn't re-render on navigation.
462- function syncLangSwitcher() {
463- const path = window.location.pathname;
464- // Match /docs/zh/ — capture the base prefix and the locale code
465- const localeMatch = path.match(/^(.*\/docs\/)([a-z]{2})\//);
466- const currentLocale = localeMatch ? localeMatch[2] : null;
467- // Path without the locale prefix (the English equivalent)
468- const englishPath = localeMatch
469- ? path.replace(`${localeMatch[1]}${localeMatch[2]}/`, localeMatch[1])
470- : path;
471-
472- // Update button label
473- const labelEl = document.getElementById('lang-label');
474- if (labelEl) {
475- labelEl.textContent = currentLocale ? (LOCALE_NAMES_CLIENT[currentLocale] ?? currentLocale) : 'EN';
476- }
477-
478- // Update link hrefs and active classes
479- document.querySelectorAll<HTMLAnchorElement>('[data-locale]').forEach(el => {
480- const locale = el.dataset.locale ?? '';
481- const isActive = locale === (currentLocale ?? '');
482- el.classList.toggle('lang-active', isActive);
483-
484- // Recompute href to match current page
485- if (locale === '') {
486- el.href = englishPath;
487- } else if (!localeMatch && /^(.*\/docs)\/?$/.test(path)) {
488- // Docs root page — just prepend the locale
489- el.href = path.replace(/\/?$/, '') + '/' + locale + '/';
490- } else {
491- el.href = localeMatch
492- ? path.replace(`${localeMatch[1]}${localeMatch[2]}/`, `${localeMatch[1]}${locale}/`)
493- : path.replace(/^(.*\/docs\/)/, `$1${locale}/`);
494- }
495- });
496- }
497-
498- // Save preferred locale when user clicks a language switcher link
499- function initLangSwitcher() {
500- syncLangSwitcher();
501- syncHeaderI18n();
502- syncNavLinks();
503- document.querySelectorAll('[data-locale]').forEach(el => {
504- el.addEventListener('click', () => {
505- const locale = (el as HTMLElement).dataset.locale;
506- if (locale) {
507- localStorage.setItem('preferred-locale', locale);
508- } else {
509- localStorage.removeItem('preferred-locale');
510- }
511- });
512- });
513- }
514- initLangSwitcher();
515- document.addEventListener('astro:page-load', initLangSwitcher);
516316</script >
0 commit comments