This commit is contained in:
alexandrev-tibco
2026-02-04 13:42:36 +01:00
parent 6b405419cf
commit 379f935fe7
16 changed files with 597 additions and 87 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ const CONFIG = {
APP_NAME: 'PorfolioJournal',
TAGLINE: 'Your personal portfolio, thoughtfully tracked.',
DESCRIPTION: 'A calm, offline-first iOS app for tracking your portfolio with monthly check-ins, reflections, and long-term insights.',
APP_STORE_URL: 'https://apps.apple.com/app/porfoliojournal/id000000000',
APP_STORE_URL: 'https://apps.apple.com/us/app/portfolio-journal/id6757678318?pt=123456&ct=homepage_other&mt=8',
SUPPORT_EMAIL: 'support@portfoliojournal.app',
COMPANY_NAME: 'PorfolioJournal',
WEBSITE_URL: 'https://portfoliojournal.app',
+179
View File
@@ -6,6 +6,12 @@
(function() {
'use strict';
function trackEvent(eventName, props) {
if (window.plausible) {
window.plausible(eventName, { props: props || {} });
}
}
// Dark Mode Management
const DarkMode = {
STORAGE_KEY: 'pj-theme',
@@ -163,6 +169,17 @@
}
};
const ImageOptimization = {
init() {
document.querySelectorAll('img').forEach(img => {
if (img.closest('.hero')) return;
if (!img.hasAttribute('loading')) {
img.setAttribute('loading', 'lazy');
}
});
}
};
// Smooth Scroll
const SmoothScroll = {
init() {
@@ -182,6 +199,160 @@
}
};
// A/B Test: Hero Variants
const HeroABTest = {
STORAGE_KEY: 'pj-hero-variant',
init() {
if (!document.querySelector('.hero-variant-a-only, .hero-variant-b-only')) {
return;
}
let variant = 'a';
try {
variant = localStorage.getItem(this.STORAGE_KEY);
if (!variant) {
variant = Math.random() < 0.5 ? 'a' : 'b';
localStorage.setItem(this.STORAGE_KEY, variant);
}
} catch (err) {
variant = 'a';
}
document.body.classList.remove('hero-variant-a', 'hero-variant-b');
document.body.classList.add(`hero-variant-${variant}`);
trackEvent('AB Test', { variant });
}
};
// Analytics Events
const Analytics = {
init() {
this.trackAppStoreClicks();
this.trackScrollDepth();
this.trackFooterLinks();
},
trackAppStoreClicks() {
document.querySelectorAll('a[href*="apps.apple.com"]').forEach(link => {
link.addEventListener('click', () => {
let campaign = 'unknown';
try {
const url = new URL(link.href);
campaign = url.searchParams.get('ct') || 'unknown';
} catch (err) {
campaign = 'unknown';
}
trackEvent('AppStore Click', { location: campaign });
});
});
},
trackScrollDepth() {
const scrollDepths = [25, 50, 75, 100];
const tracked = new Set();
window.addEventListener('scroll', () => {
const scrollPercent = ((window.scrollY + window.innerHeight) / document.body.offsetHeight) * 100;
scrollDepths.forEach(depth => {
if (scrollPercent >= depth && !tracked.has(depth)) {
tracked.add(depth);
trackEvent('Deep Scroll', { depth: `${depth}%` });
}
});
});
},
trackFooterLinks() {
document.querySelectorAll('footer a').forEach(link => {
link.addEventListener('click', () => {
const destination = link.textContent.trim() || link.getAttribute('href');
trackEvent('Footer Link Click', { destination });
});
});
}
};
const ExitIntent = {
STORAGE_KEY: 'pj-exit-intent-shown',
init() {
this.modal = document.getElementById('exit-intent-modal');
if (!this.modal) return;
const closeBtn = this.modal.querySelector('[data-exit-close]');
if (closeBtn) {
closeBtn.addEventListener('click', () => this.close());
}
this.modal.addEventListener('click', (event) => {
if (event.target === this.modal) {
this.close();
}
});
document.addEventListener('mouseleave', (event) => {
if (event.clientY < 0) {
this.show();
}
});
},
show() {
try {
if (localStorage.getItem(this.STORAGE_KEY)) return;
} catch (err) {
return;
}
this.modal.classList.add('is-visible');
this.modal.setAttribute('aria-hidden', 'false');
try {
localStorage.setItem(this.STORAGE_KEY, 'true');
} catch (err) {
// ignore storage errors
}
trackEvent('Exit Intent', { action: 'shown' });
},
close() {
this.modal.classList.remove('is-visible');
this.modal.setAttribute('aria-hidden', 'true');
trackEvent('Exit Intent', { action: 'closed' });
}
};
const StickyCTA = {
init() {
this.el = document.getElementById('sticky-mobile-cta');
if (!this.el) return;
window.addEventListener('scroll', () => this.update());
this.update();
},
update() {
const scrollPercent = ((window.scrollY + window.innerHeight) / document.body.offsetHeight) * 100;
const isMobile = window.innerWidth <= 768;
const shouldShow = isMobile && scrollPercent > 50;
this.el.style.display = shouldShow ? 'block' : 'none';
this.el.setAttribute('aria-hidden', shouldShow ? 'false' : 'true');
}
};
const CTAActions = {
init() {
document.querySelectorAll('[data-cta="learn-more"]').forEach(button => {
button.addEventListener('click', () => {
const target = document.querySelector('.features-section');
if (target) {
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
trackEvent('CTA Click', { action: 'learn_more' });
}
});
});
}
};
// Cookie Notice (only if analytics enabled)
const CookieNotice = {
STORAGE_KEY: 'pj-cookies-accepted',
@@ -230,6 +401,7 @@
init() {
document.querySelectorAll('.faq-question').forEach(question => {
question.addEventListener('click', () => {
trackEvent('FAQ Click', { question: question.textContent.trim() });
const item = question.parentElement;
const isOpen = item.classList.contains('open');
@@ -263,9 +435,15 @@
DarkMode.updateToggleButton();
Navigation.init();
Content.init();
ImageOptimization.init();
SmoothScroll.init();
HeroABTest.init();
Analytics.init();
FAQ.init();
CookieNotice.init();
ExitIntent.init();
StickyCTA.init();
CTAActions.init();
// Setup theme toggle button
const themeToggle = document.querySelector('.theme-toggle');
@@ -277,4 +455,5 @@
// Expose necessary functions globally
window.DarkMode = DarkMode;
window.CookieNotice = CookieNotice;
window.trackEvent = trackEvent;
})();