← 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();
  }
})();