feat: browser-aware CTAs, tidier hero demo, comparison guides link

- Hero CTAs: the install buttons are compact (just the browser name) so all
  three fit one line; JS detects the visitor's browser and expands that one
  to the full "Add to X" call to action. Unknown browsers stay compact.
- Hero demo: caption now sits directly under the two windows (absolutely
  positioned to the card cascade) instead of far below the tall scene. The
  scene keeps a fixed height that already fits the open popup, so the
  vertically centered hero never jumps when the popup toggles.
- The background window now also shows a (non-interactive) extension icon,
  making it clear both browsers have KoalaSync installed.
- Escape now also closes the demo popup.
- Added a link from the comparison table to the fuller alternatives/guides
  hub, localized in all 15 languages.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
KoalaDev
2026-07-06 16:03:48 +02:00
parent fd0ad310ce
commit db70828c82
18 changed files with 139 additions and 31 deletions
+26
View File
@@ -78,6 +78,23 @@ document.addEventListener('DOMContentLoaded', () => {
});
}
// Highlight the CTA for the visitor's browser: it expands to the full
// "Add to X" label while the others stay compact. Unknown browsers keep
// all three compact.
try {
const ua = navigator.userAgent;
let detected = null;
if (/Firefox\//.test(ua) && !/Seamonkey\//.test(ua)) {
detected = 'firefox';
} else if (/Chrome\//.test(ua) || /Chromium\//.test(ua) || /Edg\//.test(ua) || /OPR\//.test(ua)) {
detected = 'chrome';
}
if (detected) {
const btn = document.querySelector('.btn-install[data-browser="' + detected + '"]');
if (btn) btn.classList.add('is-detected');
}
} catch (_) { /* leave all buttons compact */ }
// Open collapsed section blocks when the URL directly targets them
const hashCollapseMap = { '#faq': 'faq-collapse', '#self-hosting': 'selfhost-collapse' };
const collapseId = hashCollapseMap[window.location.hash];
@@ -809,6 +826,15 @@ document.addEventListener('DOMContentLoaded', () => {
});
}
// Escape closes the popup as well
document.addEventListener('keydown', (e) => {
if (e.key !== 'Escape') return;
if (!scene.classList.contains('popup-open')) return;
userTookOver = true;
finishDemo();
setPopupOpen(false);
});
const runDemo = async () => {
if (demoStarted || userTookOver || reduceMotion) return;
demoStarted = true;
+2 -1
View File
@@ -222,5 +222,6 @@
"FAQ_HIDE_ALL": "Fragen ausblenden",
"SELF_SHOW_SETUP": "Setup-Anleitung anzeigen",
"SELF_HIDE_SETUP": "Setup-Anleitung ausblenden",
"HERO_TRUST": "Kostenlos · Open Source · Kein Account nötig"
"HERO_TRUST": "Kostenlos · Open Source · Kein Account nötig",
"COMP_MORE_GUIDES": "Ausführlicher Vergleich und weitere Alternativen"
}
+2 -1
View File
@@ -222,5 +222,6 @@
"FAQ_HIDE_ALL": "Hide questions",
"SELF_SHOW_SETUP": "Show setup guide",
"SELF_HIDE_SETUP": "Hide setup guide",
"HERO_TRUST": "Free · Open source · No account needed"
"HERO_TRUST": "Free · Open source · No account needed",
"COMP_MORE_GUIDES": "Full comparison and more alternatives"
}
+2 -1
View File
@@ -222,5 +222,6 @@
"FAQ_HIDE_ALL": "Ocultar preguntas",
"SELF_SHOW_SETUP": "Mostrar guía de instalación",
"SELF_HIDE_SETUP": "Ocultar guía de instalación",
"HERO_TRUST": "Gratis · Código abierto · Sin cuenta"
"HERO_TRUST": "Gratis · Código abierto · Sin cuenta",
"COMP_MORE_GUIDES": "Comparativa completa y más alternativas"
}
+2 -1
View File
@@ -222,5 +222,6 @@
"FAQ_HIDE_ALL": "Masquer les questions",
"SELF_SHOW_SETUP": "Afficher le guide d'installation",
"SELF_HIDE_SETUP": "Masquer le guide d'installation",
"HERO_TRUST": "Gratuit · Open source · Sans compte"
"HERO_TRUST": "Gratuit · Open source · Sans compte",
"COMP_MORE_GUIDES": "Comparatif complet et autres alternatives"
}
+2 -1
View File
@@ -222,5 +222,6 @@
"FAQ_HIDE_ALL": "Nascondi le domande",
"SELF_SHOW_SETUP": "Mostra la guida all'installazione",
"SELF_HIDE_SETUP": "Nascondi la guida",
"HERO_TRUST": "Gratuito · Open source · Senza account"
"HERO_TRUST": "Gratuito · Open source · Senza account",
"COMP_MORE_GUIDES": "Confronto completo e altre alternative"
}
+2 -1
View File
@@ -222,5 +222,6 @@
"FAQ_HIDE_ALL": "質問を隠す",
"SELF_SHOW_SETUP": "セットアップガイドを表示",
"SELF_HIDE_SETUP": "ガイドを隠す",
"HERO_TRUST": "無料 · オープンソース · アカウント不要"
"HERO_TRUST": "無料 · オープンソース · アカウント不要",
"COMP_MORE_GUIDES": "詳しい比較とその他の選択肢"
}
+2 -1
View File
@@ -222,5 +222,6 @@
"FAQ_HIDE_ALL": "질문 숨기기",
"SELF_SHOW_SETUP": "설치 가이드 보기",
"SELF_HIDE_SETUP": "가이드 숨기기",
"HERO_TRUST": "무료 · 오픈소스 · 계정 불필요"
"HERO_TRUST": "무료 · 오픈소스 · 계정 불필요",
"COMP_MORE_GUIDES": "전체 비교 및 다른 대안 보기"
}
+2 -1
View File
@@ -222,5 +222,6 @@
"FAQ_HIDE_ALL": "Vragen verbergen",
"SELF_SHOW_SETUP": "Installatiehandleiding tonen",
"SELF_HIDE_SETUP": "Handleiding verbergen",
"HERO_TRUST": "Gratis · Open source · Geen account nodig"
"HERO_TRUST": "Gratis · Open source · Geen account nodig",
"COMP_MORE_GUIDES": "Volledige vergelijking en meer alternatieven"
}
+2 -1
View File
@@ -222,5 +222,6 @@
"FAQ_HIDE_ALL": "Ukryj pytania",
"SELF_SHOW_SETUP": "Pokaż instrukcję instalacji",
"SELF_HIDE_SETUP": "Ukryj instrukcję",
"HERO_TRUST": "Za darmo · Open source · Bez konta"
"HERO_TRUST": "Za darmo · Open source · Bez konta",
"COMP_MORE_GUIDES": "Pełne porównanie i więcej alternatyw"
}
+2 -1
View File
@@ -222,5 +222,6 @@
"FAQ_HIDE_ALL": "Ocultar perguntas",
"SELF_SHOW_SETUP": "Mostrar guia de configuração",
"SELF_HIDE_SETUP": "Ocultar guia",
"HERO_TRUST": "Grátis · Código aberto · Sem conta"
"HERO_TRUST": "Grátis · Código aberto · Sem conta",
"COMP_MORE_GUIDES": "Comparação completa e mais alternativas"
}
+2 -1
View File
@@ -222,5 +222,6 @@
"FAQ_HIDE_ALL": "Ocultar perguntas",
"SELF_SHOW_SETUP": "Mostrar guia de configuração",
"SELF_HIDE_SETUP": "Ocultar guia",
"HERO_TRUST": "Grátis · Open source · Sem conta"
"HERO_TRUST": "Grátis · Open source · Sem conta",
"COMP_MORE_GUIDES": "Comparação completa e mais alternativas"
}
+2 -1
View File
@@ -222,5 +222,6 @@
"FAQ_HIDE_ALL": "Скрыть вопросы",
"SELF_SHOW_SETUP": "Показать инструкцию по установке",
"SELF_HIDE_SETUP": "Скрыть инструкцию",
"HERO_TRUST": "Бесплатно · Открытый код · Без аккаунта"
"HERO_TRUST": "Бесплатно · Открытый код · Без аккаунта",
"COMP_MORE_GUIDES": "Полное сравнение и другие альтернативы"
}
+2 -1
View File
@@ -222,5 +222,6 @@
"FAQ_HIDE_ALL": "Soruları gizle",
"SELF_SHOW_SETUP": "Kurulum rehberini göster",
"SELF_HIDE_SETUP": "Rehberi gizle",
"HERO_TRUST": "Ücretsiz · Açık kaynak · Hesap gerekmez"
"HERO_TRUST": "Ücretsiz · Açık kaynak · Hesap gerekmez",
"COMP_MORE_GUIDES": "Tam karşılaştırma ve diğer alternatifler"
}
+2 -1
View File
@@ -222,5 +222,6 @@
"FAQ_HIDE_ALL": "Приховати запитання",
"SELF_SHOW_SETUP": "Показати інструкцію з налаштування",
"SELF_HIDE_SETUP": "Приховати інструкцію",
"HERO_TRUST": "Безкоштовно · Відкритий код · Без акаунта"
"HERO_TRUST": "Безкоштовно · Відкритий код · Без акаунта",
"COMP_MORE_GUIDES": "Повне порівняння та інші альтернативи"
}
+2 -1
View File
@@ -222,5 +222,6 @@
"FAQ_HIDE_ALL": "收起问题",
"SELF_SHOW_SETUP": "显示部署指南",
"SELF_HIDE_SETUP": "收起指南",
"HERO_TRUST": "免费 · 开源 · 无需账号"
"HERO_TRUST": "免费 · 开源 · 无需账号",
"COMP_MORE_GUIDES": "完整对比与更多替代方案"
}
+62 -6
View File
@@ -653,6 +653,21 @@ html.theme-light .koala-speech-bubble::after {
transform: translateY(-2px);
}
/* Install buttons: compact by default (just the browser name) so all three
CTAs fit one line; the detected browser expands to the full call to action.
The GitHub button stays compact always. */
.btn-label-full { display: none; }
.btn-install:not(.is-detected),
.btn-compact {
padding: 0.62rem 1.05rem;
font-size: 0.9rem;
gap: 0.4rem;
}
.btn-install.is-detected .btn-label-short { display: none; }
.btn-install.is-detected .btn-label-full { display: inline; }
.version-badge {
display: inline-block;
background: rgba(99, 102, 241, 0.1);
@@ -3078,6 +3093,28 @@ html:not(.lang-de) [lang="de"] {
transition: opacity 0.2s ease;
}
/* Link from the comparison table to the fuller guides/alternatives hub */
.comparison-guides-link {
text-align: center;
margin: 2rem 0 0;
}
.comparison-guides-link a {
display: inline-flex;
align-items: center;
gap: 0.45rem;
color: var(--accent);
text-decoration: none;
font-weight: 600;
font-size: 0.95rem;
transition: gap 0.2s ease, opacity 0.2s ease;
}
.comparison-guides-link a:hover {
gap: 0.7rem;
opacity: 0.85;
}
.table-footnotes:hover {
opacity: 0.95;
}
@@ -3504,14 +3541,14 @@ header[id] {
container-type: inline-size;
}
/* Fixed scene height: stays below the left hero column's height so it never
drives the grid row, and never changes when the popup toggles (no vertical
jumping). The popup is bottom-anchored and simply grows upwards on open. */
/* Fixed height that already fits the open popup, so toggling it never changes
layout (the vertically centered hero never jumps). The caption is absolutely
positioned right under the cards instead of after the tall scene, and the
empty lower area is the invisible room the popup drops into. */
.hero-demo-scene {
position: relative;
width: 100%;
height: 500px;
height: max(calc(66cqw + 78px), 500px);
height: max(calc(59cqw + 100px), 548px);
}
/* While initializing, suppress all transitions so the popup can start closed
@@ -3755,11 +3792,23 @@ header[id] {
transition: opacity 0.3s;
}
.hero-demo-scene:not(.popup-open) .demo-ext-launcher::after {
.hero-demo-scene:not(.popup-open) .demo-ext-launcher:not(.demo-ext-static)::after {
opacity: 1;
animation: demoBlink 1.4s ease-in-out infinite;
}
/* Card B shows the same extension icon, purely to signal the friend has it
installed too. It is not interactive and does not blink or glow. */
.demo-ext-static,
.demo-ext-static:hover {
cursor: default;
border-color: rgba(255, 255, 255, 0.12);
transform: none;
box-shadow: none;
}
.demo-ext-static::after { display: none; }
/* Abstract "video" artwork with a slow cinematic pan/zoom while playing */
.demo-video {
position: relative;
@@ -4023,7 +4072,14 @@ header[id] {
}
/* Caption below the scene */
/* Caption sits absolutely right below the card cascade (matching the cards'
bottom edge, which scales with the container width), so the tall scene that
reserves popup room does not push it far away. */
.demo-hint {
position: absolute;
left: 0;
right: 0;
top: calc(59cqw + 82px);
margin: 0;
text-align: center;
font-size: 0.82rem;
+21 -10
View File
@@ -300,17 +300,19 @@
</a>
</div>
<div class="cta-group">
<a href="https://chromewebstore.google.com/detail/koalasync/obbnmkmlaaddodakcbdljknjpagklifc" class="btn btn-primary">
<img src="{{ASSET_PATH}}assets/chrome.svg" alt="Chrome" width="20" height="20">
<span>{{ADD_TO_CHROME}}</span>
<a href="https://chromewebstore.google.com/detail/koalasync/obbnmkmlaaddodakcbdljknjpagklifc" class="btn btn-primary btn-install" data-browser="chrome">
<img src="{{ASSET_PATH}}assets/chrome.svg" alt="" width="20" height="20">
<span class="btn-label-short">Chrome</span>
<span class="btn-label-full">{{ADD_TO_CHROME}}</span>
</a>
<a href="https://addons.mozilla.org/de/firefox/addon/koalasync/" class="btn btn-firefox">
<img src="{{ASSET_PATH}}assets/firefox.svg" alt="Firefox" width="20" height="20">
<span>{{ADD_TO_FIREFOX}}</span>
<a href="https://addons.mozilla.org/de/firefox/addon/koalasync/" class="btn btn-firefox btn-install" data-browser="firefox">
<img src="{{ASSET_PATH}}assets/firefox.svg" alt="" width="20" height="20">
<span class="btn-label-short">Firefox</span>
<span class="btn-label-full">{{ADD_TO_FIREFOX}}</span>
</a>
<a href="https://github.com/Shik3i/KoalaSync/releases" target="_blank" rel="noopener" class="btn btn-secondary" style="display: inline-flex; align-items: center; gap: 8px;">
<a href="https://github.com/Shik3i/KoalaSync/releases" target="_blank" rel="noopener" class="btn btn-secondary btn-compact" style="display: inline-flex; align-items: center; gap: 8px;">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" width="20" height="20" aria-hidden="true" style="display: block;"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
GitHub Releases
<span>GitHub Releases</span>
</a>
</div>
<p class="cta-trust">{{HERO_TRUST}}</p>
@@ -387,6 +389,9 @@
<span class="demo-tab-dots" aria-hidden="true"><i></i><i></i><i></i></span>
<span class="demo-tab-title"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="11" height="11" aria-hidden="true"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/></svg> <span class="demo-title-text-ep1">Stranger Things - S4E1</span></span>
<span class="demo-tab-user demo-user-b">🐶 HappyDog</span>
<span class="demo-ext-launcher demo-ext-static" aria-hidden="true" title="KoalaSync is installed here too">
<img src="{{ASSET_PATH}}assets/NewLogoIcon.webp" alt="" width="16" height="16" loading="eager" decoding="async">
</span>
</div>
<div class="demo-video">
<div class="demo-video-art" aria-hidden="true"></div>
@@ -730,8 +735,8 @@
<div class="demo-cursor" id="demo-cursor" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M5 2l13 11.5-6 .7 3.4 6.3-2.6 1.4-3.4-6.4L5 19.5z" fill="#f8fafc" stroke="#0f172a" stroke-width="1.4" stroke-linejoin="round"/></svg>
</div>
<p class="demo-hint" id="demo-hint">{{DEMO_HINT}}</p>
</div>
<p class="demo-hint" id="demo-hint">{{DEMO_HINT}}</p>
</div>
</div>
</header>
@@ -964,11 +969,17 @@
<a href="https://www.teleparty.com/privacy" target="_blank" rel="noopener noreferrer">teleparty.com/privacy</a>
</p>
<p id="footnote-3">
<sup>[3]</sup>
<sup>[3]</sup>
<span>{{COMP_FOOTNOTE_4}}</span>
</p>
</div>
</div>
<p class="comparison-guides-link" data-reveal>
<a href="{{ASSET_PATH}}{{LANG_PREFIX}}alternatives">
<span>{{COMP_MORE_GUIDES}}</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="15" height="15" aria-hidden="true"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
</a>
</p>
</div>
</section>