Merge _configs/ into config/ for single configuration directory. Update all path references. Changes: - Move _configs/* to config/ - Update .gitignore for new patterns - No code references to _configs/ found Impact: -1 root directory (layout_conventions.md compliance)
169 lines
5.6 KiB
JavaScript
169 lines
5.6 KiB
JavaScript
/**
|
||
* Shared Header Component for SYNTAXIS Branding Galleries
|
||
* Handles navigation, dark mode, and palette modal
|
||
*/
|
||
|
||
function initializeSharedHeader() {
|
||
// Restore dark mode preference
|
||
if (localStorage.getItem('darkMode') === 'true') {
|
||
document.body.classList.add('dark-mode');
|
||
}
|
||
updateDarkModeText();
|
||
|
||
// Set active button based on current page
|
||
updateActiveNavButton();
|
||
}
|
||
|
||
function toggleDarkMode() {
|
||
document.body.classList.toggle('dark-mode');
|
||
localStorage.setItem('darkMode', document.body.classList.contains('dark-mode'));
|
||
updateDarkModeText();
|
||
}
|
||
|
||
function updateDarkModeText() {
|
||
const isDarkMode = document.body.classList.contains('dark-mode');
|
||
const toggleBtn = document.querySelector('[data-toggle="dark-mode"]');
|
||
if (toggleBtn) {
|
||
toggleBtn.textContent = isDarkMode ? '☀️ Light Mode' : '🌙 Dark Mode';
|
||
}
|
||
}
|
||
|
||
function updateActiveNavButton() {
|
||
const currentPage = window.location.pathname.split('/').pop() || 'index.html';
|
||
const navButtons = document.querySelectorAll('[data-nav-button]');
|
||
|
||
navButtons.forEach(btn => {
|
||
const target = btn.getAttribute('data-nav-button');
|
||
if (currentPage.includes(target) ||
|
||
(currentPage === '' && target === 'branding') ||
|
||
(currentPage.includes('branding') && target === 'branding') ||
|
||
(currentPage.includes('animated') && target === 'animated')) {
|
||
btn.classList.add('active');
|
||
} else {
|
||
btn.classList.remove('active');
|
||
}
|
||
});
|
||
}
|
||
|
||
function openPaletteModal() {
|
||
const modal = document.getElementById('palette-modal');
|
||
if (modal) {
|
||
modal.style.display = 'flex';
|
||
document.body.style.overflow = 'hidden';
|
||
}
|
||
}
|
||
|
||
function closePaletteModal() {
|
||
const modal = document.getElementById('palette-modal');
|
||
if (modal) {
|
||
modal.style.display = 'none';
|
||
document.body.style.overflow = 'auto';
|
||
}
|
||
}
|
||
|
||
// Close modal on escape key
|
||
document.addEventListener('keydown', function(event) {
|
||
if (event.key === 'Escape') {
|
||
closePaletteModal();
|
||
}
|
||
});
|
||
|
||
// Close modal on outside click
|
||
document.addEventListener('click', function(event) {
|
||
const modal = document.getElementById('palette-modal');
|
||
if (modal && event.target === modal) {
|
||
closePaletteModal();
|
||
}
|
||
});
|
||
|
||
function toggleInfoNote() {
|
||
const note = document.getElementById('info-note');
|
||
const btn = document.querySelector('.toggle-note-btn');
|
||
if (note && btn) {
|
||
note.classList.toggle('visible');
|
||
const isVisible = note.classList.contains('visible');
|
||
btn.textContent = isVisible ? '🔼 Hide Note' : '💡 Show Animation Note';
|
||
localStorage.setItem('infoNoteVisible', isVisible);
|
||
}
|
||
}
|
||
|
||
function restoreInfoNoteState() {
|
||
const note = document.getElementById('info-note');
|
||
const btn = document.querySelector('.toggle-note-btn');
|
||
if (note && btn) {
|
||
const wasVisible = localStorage.getItem('infoNoteVisible') === 'true';
|
||
if (wasVisible) {
|
||
note.classList.add('visible');
|
||
btn.textContent = '🔼 Hide Note';
|
||
} else {
|
||
btn.textContent = '💡 Show Animation Note';
|
||
}
|
||
}
|
||
}
|
||
|
||
function copyFilename(filename) {
|
||
navigator.clipboard
|
||
.writeText(filename)
|
||
.then(() => {
|
||
const toast = document.createElement("div");
|
||
toast.className = "copy-toast";
|
||
toast.textContent = `✓ ${filename} copied!`;
|
||
document.body.appendChild(toast);
|
||
setTimeout(() => toast.remove(), 3000);
|
||
})
|
||
.catch(() => {
|
||
const toast = document.createElement("div");
|
||
toast.className = "copy-toast";
|
||
toast.style.background = "#EF4444";
|
||
toast.textContent = "✗ Error copying";
|
||
document.body.appendChild(toast);
|
||
setTimeout(() => toast.remove(), 3000);
|
||
});
|
||
}
|
||
|
||
// Initialize on DOM content loaded
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
initializeSharedHeader();
|
||
restoreInfoNoteState();
|
||
|
||
// Add click handlers to .main-logo-meta elements
|
||
document.querySelectorAll('.main-logo-meta').forEach(element => {
|
||
element.addEventListener('click', function() {
|
||
// Try to get the filepath from the sibling object element
|
||
const card = this.closest('.main-logo-card');
|
||
let filepath = null;
|
||
|
||
if (card) {
|
||
const objectElement = card.querySelector('object[data]');
|
||
if (objectElement) {
|
||
filepath = objectElement.getAttribute('data');
|
||
}
|
||
}
|
||
|
||
// If filepath not found, extract filename from the text (e.g., "syntax_logo.svg • 800×200px" -> "syntax_logo.svg")
|
||
if (!filepath) {
|
||
const text = this.textContent.trim();
|
||
filepath = text.split(' •')[0].trim();
|
||
}
|
||
|
||
copyFilename(filepath);
|
||
});
|
||
});
|
||
|
||
// Add click handlers to .card-meta-filename elements
|
||
document.querySelectorAll('.card-meta-filename').forEach(element => {
|
||
element.addEventListener('click', function() {
|
||
// Extract filepath from data attribute (e.g., "syntax_logos_anim/syntax_logo_a.svg")
|
||
const filepath = this.getAttribute('data-filepath');
|
||
if (filepath) {
|
||
copyFilename(filepath);
|
||
} else {
|
||
// Fallback: extract filename from the text (e.g., "📄 syntax_logo_a.svg" -> "syntax_logo_a.svg")
|
||
const text = this.textContent.trim();
|
||
const filename = text.replace(/^[📄\s]+/, '').trim();
|
||
copyFilename(filename);
|
||
}
|
||
});
|
||
});
|
||
});
|