Skip to content

Commit 371de4c

Browse files
committed
Merge branch 'ADP-5686' into develop
# Conflicts: # src/components/Header.astro
2 parents 1246740 + 7999db3 commit 371de4c

46 files changed

Lines changed: 1049 additions & 369 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
openapi: 3.1.0
2+
info:
3+
title: Developer API
4+
version: 1.0.0
5+
servers:
6+
- url: https://api.adapty.io
7+
description: Production server
8+
paths: {}
9+
components:
10+
securitySchemes:
11+
apikeyAuth:
12+
type: apiKey
13+
in: header
14+
name: Authorization
259 KB
Loading
133 KB
Loading
659 KB
Loading
468 KB
Loading
324 KB
Loading
126 KB
Loading
294 KB
Loading
499 KB
Loading

src/components/Header.astro

Lines changed: 34 additions & 234 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,14 @@
11
---
22
import Search from "./Search.astro";
33
import 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

Comments
 (0)