← back to Osborne Redesign
assets/site.js
191 lines
// Osborne Partners Redesign — site shell + theme picker
(function () {
const THEMES = [
{ id: 'heritage', name: 'Heritage Navy', desc: 'Old-money trust' },
{ id: 'whisper', name: 'Whisper', desc: 'Swiss minimalism' },
{ id: 'broadsheet', name: 'Broadsheet', desc: 'Editorial · WSJ-grade' },
{ id: 'onyx', name: 'Onyx', desc: 'Black-tie luxury' },
{ id: 'pacific', name: 'Pacific', desc: 'Warm West Coast' },
{ id: 'atelier', name: 'Atelier', desc: 'Tech · data-forward' },
{ id: 'loro', name: 'Loro', desc: 'Quiet luxury' },
{ id: 'monolith', name: 'Monolith', desc: 'Architectural · brutalist' },
{ id: 'archive', name: 'Archive', desc: 'Vintage aristocracy' },
{ id: 'aurora', name: 'Aurora', desc: 'Refined glass · gradient' }
];
const NAV = [
{ href: 'index.html', label: 'Overview' },
{ href: 'history.html', label: 'History' },
{ href: 'team.html', label: 'Team' },
{ href: 'philosophy.html', label: 'Philosophy' },
{ href: 'performance.html', label: 'Performance' },
{ href: 'service-area.html', label: 'Service Area' },
{ href: 'clients.html', label: 'Clients' },
{ href: 'insights.html', label: 'Insights' },
{ href: 'videos.html', label: 'Videos' },
{ href: 'reports.html', label: 'Reports' },
{ href: 'contact.html', label: 'Contact' }
];
// ----- Theme application -----
function applyTheme(id, opts) {
document.documentElement.dataset.theme = id;
// Only persist when the user clicks a swatch (opts.persist === true),
// never for theme arrivals from a URL parameter.
if (opts && opts.persist) {
try { localStorage.setItem('opcm-theme', id); } catch (e) {}
}
document.querySelectorAll('.theme-swatch').forEach(s => {
s.classList.toggle('is-active', s.dataset.swatch === id);
});
const t = THEMES.find(x => x.id === id) || THEMES[0];
const labelEl = document.querySelector('.theme-picker__label .name');
const numEl = document.querySelector('.theme-picker__label .num');
if (labelEl) labelEl.textContent = t.name;
if (numEl) numEl.textContent = String(THEMES.findIndex(x => x.id === id) + 1).padStart(2, '0') + ' / 10';
}
function getInitialTheme() {
// URL parameter ALWAYS wins (so iframes / shared links render the right theme,
// and only persist when the user picks via the on-page swatches).
const url = new URLSearchParams(location.search).get('theme');
if (url && THEMES.some(t => t.id === url)) return url;
try {
const saved = localStorage.getItem('opcm-theme');
if (saved && THEMES.some(t => t.id === saved)) return saved;
} catch (e) {}
return 'heritage';
}
// ----- Header injection -----
function buildHeader(currentPage) {
const navHTML = NAV.map(item => {
const active = item.href === currentPage ? ' is-active' : '';
return `<a href="${item.href}" class="${active.trim()}">${item.label}</a>`;
}).join('');
return `
<header class="site-header">
<div class="site-header__inner">
<a href="index.html" class="brand">
<span>Osborne Partners</span>
<small>Capital Management · Est. 1937</small>
</a>
<nav class="site-nav">${navHTML}</nav>
<a class="site-cta" href="contact.html">Client Portal →</a>
</div>
</header>`;
}
// ----- Footer injection -----
function buildFooter() {
return `
<footer class="site-footer">
<div class="container">
<div class="site-footer__grid">
<div class="site-footer__col">
<div class="brand" style="margin-bottom:16px">
<span>Osborne Partners</span>
<small>Your wealth. Solved.</small>
</div>
<p style="font-size:14px;color:var(--ink-soft);line-height:1.6;max-width:380px">
A San Francisco wealth manager since 1937. We provide sophisticated investment management,
active financial planning, and family office services to over $2 billion in client assets.
</p>
</div>
<div class="site-footer__col">
<h4>Practice</h4>
<ul>
<li><a href="philosophy.html">Investment Philosophy</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="service-area.html">Service Area</a></li>
<li><a href="clients.html">Client Stories</a></li>
</ul>
</div>
<div class="site-footer__col">
<h4>Firm</h4>
<ul>
<li><a href="history.html">History</a></li>
<li><a href="team.html">Team</a></li>
<li><a href="insights.html">Insights</a></li>
<li><a href="reports.html">Reports</a></li>
</ul>
</div>
<div class="site-footer__col">
<h4>Visit</h4>
<ul>
<li>One Embarcadero Center</li>
<li>Suite 4100, San Francisco</li>
<li style="padding-top:12px">545 Middlefield Road</li>
<li>Suite 165, Menlo Park</li>
</ul>
</div>
</div>
<div class="site-footer__bar">
<span>© ${new Date().getFullYear()} Osborne Partners Capital Management, LLC</span>
<span>800.362.7734 · info@osbornepartners.com</span>
</div>
</div>
</footer>`;
}
// ----- Theme picker injection -----
function buildPicker() {
const swatches = THEMES.map((t, i) => `
<button class="theme-swatch" data-swatch="${t.id}" title="${t.name}">
<span class="theme-swatch__num">${String(i + 1).padStart(2, '0')}</span>
</button>`).join('');
return `
<div class="theme-picker" id="themePicker">
<div class="theme-picker__title">
<span>Theme</span>
<small>10 directions</small>
</div>
<div class="theme-picker__grid">${swatches}</div>
<div class="theme-picker__label">
<span class="name">Heritage Navy</span>
<span class="num">01 / 10</span>
</div>
</div>`;
}
// ----- Init -----
function init() {
const path = location.pathname.split('/').pop() || 'index.html';
// Header
const headerSlot = document.getElementById('site-header-slot');
if (headerSlot) headerSlot.outerHTML = buildHeader(path);
// Footer
const footerSlot = document.getElementById('site-footer-slot');
if (footerSlot) footerSlot.outerHTML = buildFooter();
// Theme picker
const pickerSlot = document.getElementById('theme-picker-slot');
if (pickerSlot) pickerSlot.outerHTML = buildPicker();
// Wire up swatches — clicking a swatch persists, so the choice sticks across navigation
document.querySelectorAll('.theme-swatch').forEach(s => {
s.addEventListener('click', () => applyTheme(s.dataset.swatch, { persist: true }));
});
applyTheme(getInitialTheme());
// Reveal-on-scroll for cards/timeline (subtle)
if ('IntersectionObserver' in window) {
const io = new IntersectionObserver((entries) => {
entries.forEach(e => { if (e.isIntersecting) e.target.classList.add('in-view'); });
}, { threshold: 0.12 });
document.querySelectorAll('.card,.timeline__item,.team-card,.case,.report-row,.news-card,.chart')
.forEach(el => io.observe(el));
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();