+1
This commit is contained in:
+273
-32
@@ -662,7 +662,33 @@ p {
|
||||
line-height: var(--line-height-relaxed);
|
||||
}
|
||||
|
||||
.hero-actions {
|
||||
.hero-features {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: var(--space-3);
|
||||
margin-bottom: var(--space-8);
|
||||
}
|
||||
|
||||
.feature-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: var(--space-2) var(--space-4);
|
||||
border-radius: var(--radius-full);
|
||||
background: rgba(88, 183, 122, 0.14);
|
||||
color: #1f6b44;
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .feature-badge {
|
||||
background: rgba(114, 211, 154, 0.2);
|
||||
color: #d6f4e5;
|
||||
}
|
||||
|
||||
.hero-actions,
|
||||
.hero-ctas {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
@@ -670,6 +696,106 @@ p {
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.app-store-badge img {
|
||||
height: 56px;
|
||||
width: auto;
|
||||
box-shadow: var(--shadow-md);
|
||||
border-radius: var(--radius-lg);
|
||||
}
|
||||
|
||||
.app-store-badge {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.cta-secondary {
|
||||
padding: 0.75rem 1.6rem;
|
||||
border-radius: var(--radius-md);
|
||||
border: 2px solid var(--color-primary);
|
||||
color: var(--color-primary);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
transition: all var(--transition-base);
|
||||
}
|
||||
|
||||
.cta-secondary:hover {
|
||||
background: var(--color-primary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.hero-social-proof {
|
||||
margin-top: var(--space-4);
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--color-text-tertiary);
|
||||
}
|
||||
|
||||
.hero-content-split {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||
gap: var(--space-12);
|
||||
align-items: center;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.hero-content-split .hero-app-icon {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.hero-content-split .hero-description,
|
||||
.hero-content-split .hero-features,
|
||||
.hero-content-split .hero-ctas,
|
||||
.hero-content-split .hero-social-proof {
|
||||
justify-content: flex-start;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.hero-media {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hero-video-placeholder {
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
aspect-ratio: 9 / 16;
|
||||
border-radius: var(--radius-2xl);
|
||||
background: var(--color-bg-secondary);
|
||||
border: 1px dashed var(--color-border-strong);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--color-text-tertiary);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.hero-content-split {
|
||||
grid-template-columns: 1fr;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero-content-split .hero-features,
|
||||
.hero-content-split .hero-ctas,
|
||||
.hero-content-split .hero-social-proof {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.hero-features {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hero-ctas {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.app-store-badge img {
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.hero-app-icon {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
@@ -690,6 +816,33 @@ p {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.features-cta {
|
||||
margin-top: var(--space-6);
|
||||
}
|
||||
|
||||
.footer-appstore {
|
||||
display: inline-flex;
|
||||
margin-top: var(--space-4);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
}
|
||||
|
||||
.hero-variant-a .hero-variant-b-only,
|
||||
.hero-variant-b .hero-variant-a-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.hero-variant-b-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.hero-variant-b .hero-variant-b-only {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hero-variant-b .hero {
|
||||
padding-top: calc(var(--nav-height) + var(--space-16));
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
Features Section
|
||||
======================================== */
|
||||
@@ -923,67 +1076,59 @@ p {
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
Testimonials Section
|
||||
Early Adopters Section
|
||||
======================================== */
|
||||
|
||||
.testimonials {
|
||||
.early-adopters {
|
||||
background: var(--color-bg-secondary);
|
||||
}
|
||||
|
||||
.testimonials-header {
|
||||
.early-adopters-header {
|
||||
text-align: center;
|
||||
max-width: 600px;
|
||||
max-width: 620px;
|
||||
margin: 0 auto var(--space-12);
|
||||
}
|
||||
|
||||
.testimonials-grid {
|
||||
.early-adopters-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-6);
|
||||
margin-bottom: var(--space-10);
|
||||
}
|
||||
|
||||
@media (max-width: 968px) {
|
||||
.testimonials-grid {
|
||||
.early-adopters-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.testimonials-grid {
|
||||
.early-adopters-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.testimonial-card {
|
||||
padding: var(--space-6);
|
||||
.early-adopter-card {
|
||||
padding: var(--space-8);
|
||||
background: var(--color-surface);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-xl);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.testimonial-stars {
|
||||
.early-adopter-icon {
|
||||
font-size: 1.6rem;
|
||||
display: inline-flex;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.early-adopter-card h3 {
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.early-adopters-cta {
|
||||
display: flex;
|
||||
gap: var(--space-1);
|
||||
margin-bottom: var(--space-4);
|
||||
color: var(--color-warning);
|
||||
}
|
||||
|
||||
.testimonial-stars svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.testimonial-text {
|
||||
font-size: var(--font-size-base);
|
||||
color: var(--color-text);
|
||||
margin-bottom: var(--space-4);
|
||||
line-height: var(--line-height-relaxed);
|
||||
}
|
||||
|
||||
.testimonial-author {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--color-text-tertiary);
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
@@ -1223,6 +1368,12 @@ p {
|
||||
color: var(--color-text-tertiary);
|
||||
}
|
||||
|
||||
.page-header-actions {
|
||||
margin-top: var(--space-6);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
Content Styles (for policy pages)
|
||||
======================================== */
|
||||
@@ -1686,6 +1837,96 @@ p {
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
Exit Intent Modal + Sticky CTA
|
||||
======================================== */
|
||||
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.65);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: var(--z-modal);
|
||||
padding: var(--space-6);
|
||||
}
|
||||
|
||||
.modal.is-visible {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: var(--color-surface);
|
||||
color: var(--color-text);
|
||||
padding: var(--space-8);
|
||||
border-radius: var(--radius-xl);
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
box-shadow: var(--shadow-xl);
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
position: absolute;
|
||||
top: var(--space-3);
|
||||
right: var(--space-3);
|
||||
font-size: 1.4rem;
|
||||
color: var(--color-text-tertiary);
|
||||
}
|
||||
|
||||
.modal-close:hover {
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.modal-cta {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color-primary);
|
||||
color: white;
|
||||
padding: 0.75rem 1.8rem;
|
||||
border-radius: var(--radius-md);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
}
|
||||
|
||||
.modal-cta:hover {
|
||||
background: var(--color-primary-hover);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.sticky-cta {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: var(--z-sticky);
|
||||
display: none;
|
||||
box-shadow: var(--shadow-lg);
|
||||
border-radius: var(--radius-full);
|
||||
}
|
||||
|
||||
.sticky-cta a {
|
||||
display: block;
|
||||
background: var(--color-primary);
|
||||
color: white;
|
||||
padding: 0.9rem 2rem;
|
||||
border-radius: var(--radius-full);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
}
|
||||
|
||||
.sticky-cta a:hover {
|
||||
background: var(--color-primary-hover);
|
||||
color: white;
|
||||
}
|
||||
|
||||
@media (min-width: 769px) {
|
||||
.sticky-cta {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
Utilities
|
||||
======================================== */
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="60" viewBox="0 0 180 60" role="img" aria-label="Download on the App Store">
|
||||
<rect width="180" height="60" rx="10" fill="#000" />
|
||||
<g fill="#fff">
|
||||
<path d="M46.64 20.5c.9-1.09 1.52-2.62 1.35-4.14-1.31.05-2.88.86-3.8 1.96-.83.97-1.56 2.52-1.36 4 1.4.11 2.94-.74 3.81-1.82z"/>
|
||||
<path d="M54.71 42.48c-1.01 1.5-2.08 2.98-3.72 3.01-1.63.03-2.15-.96-4.02-.96-1.87 0-2.44.93-3.98.99-1.6.06-2.8-1.61-3.83-3.08-2.2-3.22-3.88-9.28-1.62-13.23 1.06-1.88 2.96-3.08 5.02-3.11 1.57-.03 3.05 1.05 4.02 1.05.95 0 2.74-1.3 4.64-1.11.78.04 3 .3 4.4 2.45-.1.07-2.53 1.53-2.5 4.57.03 3.6 3.12 4.8 3.16 4.82-.03.09-.5 1.7-1.57 3.59z"/>
|
||||
</g>
|
||||
<text x="74" y="23" fill="#fff" font-family="-apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, Arial, sans-serif" font-size="11">Download on the</text>
|
||||
<text x="74" y="42" fill="#fff" font-family="-apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, Arial, sans-serif" font-size="18" font-weight="700">App Store</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
+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