+1
This commit is contained in:
+1
-1
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user