From 379f935fe70e13fd8088c3379e97e19052f8ed78 Mon Sep 17 00:00:00 2001 From: alexandrev-tibco Date: Wed, 4 Feb 2026 13:42:36 +0100 Subject: [PATCH] +1 --- about.html | 3 + assets/css/style.css | 305 ++++++++++++++++++++++++++---- assets/images/app-store-badge.svg | 9 + assets/js/config.js | 2 +- assets/js/main.js | 179 ++++++++++++++++++ changelog.html | 3 + delete-data.html | 3 + index.html | 145 +++++++++----- og-service/main.go | 2 +- press-kit.html | 3 + privacy.html | 6 + security.html | 3 + status.html | 3 + support.html | 6 + terms.html | 3 + website-share-page.html | 9 +- 16 files changed, 597 insertions(+), 87 deletions(-) create mode 100644 assets/images/app-store-badge.svg diff --git a/about.html b/about.html index e1bf19e..34f8fe5 100644 --- a/about.html +++ b/about.html @@ -20,8 +20,11 @@ + + + diff --git a/assets/css/style.css b/assets/css/style.css index 57c49f0..82d9e38 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -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 ======================================== */ diff --git a/assets/images/app-store-badge.svg b/assets/images/app-store-badge.svg new file mode 100644 index 0000000..ef8bd41 --- /dev/null +++ b/assets/images/app-store-badge.svg @@ -0,0 +1,9 @@ + + + + + + + Download on the + App Store + diff --git a/assets/js/config.js b/assets/js/config.js index c1d544c..3934971 100644 --- a/assets/js/config.js +++ b/assets/js/config.js @@ -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', diff --git a/assets/js/main.js b/assets/js/main.js index d8b9801..ae7195b 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -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; })(); diff --git a/changelog.html b/changelog.html index c9d3d75..8a42ecc 100644 --- a/changelog.html +++ b/changelog.html @@ -20,8 +20,11 @@ + + + diff --git a/delete-data.html b/delete-data.html index c7678ac..8d62404 100644 --- a/delete-data.html +++ b/delete-data.html @@ -20,8 +20,11 @@ + + + diff --git a/index.html b/index.html index 97452b1..137f791 100644 --- a/index.html +++ b/index.html @@ -20,8 +20,11 @@ + + + @@ -50,7 +53,7 @@
-
+

Build a calm portfolio habit with PorfolioJournal.

A focused iOS app for monthly portfolio check-ins, reflection notes, and long-term clarity. Stay present, track growth, and build a record of your financial decisions without noise.

-
-
+
+
+
+
+ +
+ + Offline-first portfolio journaling +
+

Build a calm portfolio habit with PorfolioJournal.

+

A focused iOS app for monthly portfolio check-ins, reflection notes, and long-term clarity. Stay present, track growth, and build a record of your financial decisions without noise.

+
+ ✓ Offline-first + ✓ No account required + ✓ Privacy-focused +
+
+ + Download on the App Store + + +
+

⭐⭐⭐⭐⭐ 5.0 rating on App Store

+
+
+
Video demo coming soon
+
+
+
+
+ +

Portfolio clarity, without the noise

Everything PorfolioJournal does is built around gentle monthly updates and a durable record of your progress.

+
@@ -202,46 +248,31 @@
-
+
-
-

Trusted by calm investors

-

Replace these with real reviews once you launch.

+
+

Join Early Adopters

+

Portfolio Journal just launched. Be part of the first wave of calm investors building better financial habits.

-
-
- -

“Finally, a portfolio app that feels like a journal. The monthly cadence keeps me grounded.”

-

— Camille R.

-
-
- -

“Offline-first is a game changer. I can keep sensitive notes without worrying about servers.”

-

— Jordan P.

-
-
- -

“The goals and snapshots make it easy to explain my progress over time.”

-

— Micah L.

-
+
+
+ 🎯 +

Shape the roadmap

+

Your feedback directly influences future features.

+
+
+ 💎 +

Early access perks

+

Get priority updates and launch pricing while we grow.

+
+
+ 🤝 +

Direct support

+

Talk directly with the developer for fast answers.

+
+
+
@@ -274,7 +305,7 @@
-
No analytics or tracking is enabled by default. If analytics are added later, you will be notified.
+
We use privacy-friendly website analytics to understand page usage and improve the experience. No personal data is shared with third parties.
@@ -287,7 +318,7 @@

Start your calm portfolio habit

Download PorfolioJournal and build a record of your investing journey that you will actually want to revisit.

@@ -304,6 +335,7 @@ PorfolioJournal

Calm, offline-first portfolio journaling for iOS.

+ Download on the App Store + + + + diff --git a/og-service/main.go b/og-service/main.go index 91b8af3..744bf16 100644 --- a/og-service/main.go +++ b/og-service/main.go @@ -321,7 +321,7 @@ func renderShareHTML(view shareView) string {
` + escapeHTML(view.PercentText) + `
` + escapeHTML(joinLabels(view.TargetDateLabel, view.EstimateDateLabel)) + `
- Download on the App Store + Download on the App Store ` diff --git a/press-kit.html b/press-kit.html index 8157d3c..cfc3261 100644 --- a/press-kit.html +++ b/press-kit.html @@ -20,8 +20,11 @@ + + + diff --git a/privacy.html b/privacy.html index 94a0ee0..abe0414 100644 --- a/privacy.html +++ b/privacy.html @@ -20,8 +20,11 @@ + + + @@ -58,6 +61,9 @@ Effective date: Applies to iOS app and this website +
diff --git a/security.html b/security.html index 6b69038..141844e 100644 --- a/security.html +++ b/security.html @@ -20,8 +20,11 @@ + + + diff --git a/status.html b/status.html index 725e981..e83e65b 100644 --- a/status.html +++ b/status.html @@ -20,8 +20,11 @@ + + + diff --git a/support.html b/support.html index cd0ad7f..b6b8919 100644 --- a/support.html +++ b/support.html @@ -20,8 +20,11 @@ + + + @@ -54,6 +57,9 @@

Support

We are here to help you stay on track with your portfolio journaling.

+
diff --git a/terms.html b/terms.html index d572124..5013734 100644 --- a/terms.html +++ b/terms.html @@ -20,8 +20,11 @@ + + + diff --git a/website-share-page.html b/website-share-page.html index 989b77b..8911852 100644 --- a/website-share-page.html +++ b/website-share-page.html @@ -35,9 +35,12 @@ + + +