164 lines
5.3 KiB
JavaScript
164 lines
5.3 KiB
JavaScript
const sections = {
|
||
drive: 'drive/drive.html',
|
||
tasks: 'tasks/tasks.html',
|
||
mail: 'mail/mail.html',
|
||
chat: 'chat/chat.html',
|
||
};
|
||
const sectionCache = {};
|
||
|
||
function getBasePath() {
|
||
// All static assets (HTML, CSS, JS) are served from the site root.
|
||
// Returning a leading slash ensures URLs like "/drive/drive.html" resolve correctly
|
||
return '/';
|
||
}
|
||
|
||
// Preload chat CSS to avoid flash on first load
|
||
function preloadChatCSS() {
|
||
const chatCssPath = getBasePath() + 'chat/chat.css';
|
||
const existing = document.querySelector(`link[href="${chatCssPath}"]`);
|
||
if (!existing) {
|
||
const link = document.createElement('link');
|
||
link.rel = 'stylesheet';
|
||
link.href = chatCssPath;
|
||
document.head.appendChild(link);
|
||
}
|
||
}
|
||
|
||
async function loadSectionHTML(path) {
|
||
const fullPath = getBasePath() + path;
|
||
const response = await fetch(fullPath);
|
||
if (!response.ok) throw new Error('Failed to load section: ' + fullPath);
|
||
return await response.text();
|
||
}
|
||
|
||
async function switchSection(section) {
|
||
const mainContent = document.getElementById('main-content');
|
||
|
||
try {
|
||
const htmlPath = sections[section];
|
||
console.log('Loading section:', section, 'from', htmlPath);
|
||
// Resolve CSS path relative to the base directory.
|
||
const cssPath = getBasePath() + htmlPath.replace('.html', '.css');
|
||
|
||
// Preload chat CSS if the target is chat
|
||
if (section === 'chat') {
|
||
preloadChatCSS();
|
||
}
|
||
|
||
// Remove any existing section CSS
|
||
document.querySelectorAll('link[data-section-css]').forEach(link => link.remove());
|
||
|
||
// Load CSS first (skip if already loaded)
|
||
let cssLink = document.querySelector(`link[href="${cssPath}"]`);
|
||
if (!cssLink) {
|
||
cssLink = document.createElement('link');
|
||
cssLink.rel = 'stylesheet';
|
||
cssLink.href = cssPath;
|
||
cssLink.setAttribute('data-section-css', 'true');
|
||
document.head.appendChild(cssLink);
|
||
}
|
||
|
||
// Hide previously loaded sections and show the requested one
|
||
// Ensure a container exists for sections
|
||
let container = document.getElementById('section-container');
|
||
if (!container) {
|
||
container = document.createElement('div');
|
||
container.id = 'section-container';
|
||
mainContent.appendChild(container);
|
||
}
|
||
|
||
const targetDiv = document.getElementById(`section-${section}`);
|
||
|
||
if (targetDiv) {
|
||
// Section already loaded: hide others, show this one
|
||
container.querySelectorAll('.section').forEach(div => {
|
||
div.style.display = 'none';
|
||
});
|
||
targetDiv.style.display = 'block';
|
||
} else {
|
||
// Show loading placeholder inside the container
|
||
const loadingDiv = document.createElement('div');
|
||
loadingDiv.className = 'loading';
|
||
loadingDiv.textContent = 'Loading…';
|
||
container.appendChild(loadingDiv);
|
||
|
||
// Load HTML
|
||
const html = await loadSectionHTML(htmlPath);
|
||
// Create wrapper for the new section
|
||
const wrapper = document.createElement('div');
|
||
wrapper.id = `section-${section}`;
|
||
wrapper.className = 'section';
|
||
wrapper.innerHTML = html;
|
||
|
||
// Hide any existing sections
|
||
container.querySelectorAll('.section').forEach(div => {
|
||
div.style.display = 'none';
|
||
});
|
||
|
||
// Remove loading placeholder
|
||
container.removeChild(loadingDiv);
|
||
|
||
// Add the new section to the container and cache it
|
||
container.appendChild(wrapper);
|
||
sectionCache[section] = wrapper;
|
||
|
||
// Ensure the new section is visible with a fast GSAP fade-in
|
||
gsap.fromTo(
|
||
wrapper,
|
||
{ opacity: 0 },
|
||
{ opacity: 1, duration: 0.15, ease: 'power2.out' }
|
||
);
|
||
}
|
||
|
||
// Then load JS after HTML is inserted (skip if already loaded)
|
||
// Resolve JS path relative to the base directory.
|
||
const jsPath = getBasePath() + htmlPath.replace('.html', '.js');
|
||
const existingScript = document.querySelector(`script[src="${jsPath}"]`);
|
||
if (!existingScript) {
|
||
const script = document.createElement('script');
|
||
script.src = jsPath;
|
||
script.defer = true;
|
||
document.body.appendChild(script);
|
||
}
|
||
window.history.pushState({}, '', `#${section}`);
|
||
Alpine.initTree(mainContent);
|
||
const inputEl = document.getElementById('messageInput');
|
||
if (inputEl) {
|
||
inputEl.focus();
|
||
}
|
||
} catch (err) {
|
||
console.error('Error loading section:', err);
|
||
mainContent.innerHTML = `<div class="error">Failed to load ${section} section</div>`;
|
||
}
|
||
}
|
||
|
||
// Handle initial load based on URL hash
|
||
function getInitialSection() {
|
||
// 1️⃣ Prefer hash fragment (e.g., #chat)
|
||
let section = window.location.hash.substring(1);
|
||
// 2️⃣ Fallback to pathname segments (e.g., /chat)
|
||
if (!section) {
|
||
const parts = window.location.pathname.split('/').filter(p => p);
|
||
const last = parts[parts.length - 1];
|
||
if (['drive', 'tasks', 'mail', 'chat'].includes(last)) {
|
||
section = last;
|
||
}
|
||
}
|
||
// 3️⃣ As a last resort, inspect the full URL for known sections
|
||
if (!section) {
|
||
const match = window.location.href.match(/\/(drive|tasks|mail|chat)(?:\.html)?(?:[?#]|$)/i);
|
||
if (match) {
|
||
section = match[1].toLowerCase();
|
||
}
|
||
}
|
||
// Default to chat if nothing matches
|
||
return section || 'chat';
|
||
}
|
||
window.addEventListener('DOMContentLoaded', () => {
|
||
switchSection(getInitialSection());
|
||
});
|
||
|
||
// Handle browser back/forward navigation
|
||
window.addEventListener('popstate', () => {
|
||
switchSection(getInitialSection());
|
||
});
|