remove dup index

D David Veksler · 1 year ago 6a2d00b6cdeedcf9e907aa840789b15ee4ab19d1
Parent: e5f68a4bf

3 files changed +5 −629

Diff

diff --git a/.claude/settings.local.json b/.claude/settings.local.json
index 0f299b3..3793c52 100644
--- a/.claude/settings.local.json
+++ b/.claude/settings.local.json
@@ -1,7 +1,10 @@
 {
   "permissions": {
     "allow": [
-      "WebFetch(domain:medium.com)"
+      "WebFetch(domain:medium.com)",
+      "Bash(git add:*)",
+      "Bash(git mv:*)",
+      "Bash(git rebase:*)"
     ],
     "deny": []
   }
diff --git a/index2.php b/index2.php
deleted file mode 100644
index c3e5850..0000000
--- a/index2.php
+++ /dev/null
@@ -1,627 +0,0 @@
-<?php
-// Set content type and encoding
-header('Content-Type: text/html; charset=utf-8');
-
-// --- Configuration ---
-$excludedItems = [
-    '.',
-    '..',
-    'index.php',
-    'browse.html',
-    'images',
-    'LICENSE',
-    'README.md',
-    'PROMPT.txt',
-    'history_tree_style.css',
-    'safety_data.js',
-];
-
-$cheatsheetDir = '.';
-$scheme = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
-$host = $_SERVER['HTTP_HOST'];
-$scriptDir = dirname($_SERVER['SCRIPT_NAME']);
-$baseUrl = rtrim($scheme . '://' . $host . $scriptDir, '/') . '/';
-
-// --- !!! Action Needed: Define Categories !!! ---
-// You need a way to map filenames or metadata to categories.
-// Example: Simple mapping (replace with your logic)
-function getCategoryForFile(string $filename): string {
-    $filenameLower = strtolower($filename);
-    if (str_contains($filenameLower, 'ai') || str_contains($filenameLower, 'safety')) return 'ai';
-    if (str_contains($filenameLower, 'bitcoin') || str_contains($filenameLower, 'crypto')) return 'crypto';
-    if (str_contains($filenameLower, 'leadership')) return 'leadership';
-    if (str_contains($filenameLower, 'buddhism') || str_contains($filenameLower, 'judaism') || str_contains($filenameLower, 'philosophy') || str_contains($filenameLower, 'objectivism') || str_contains($filenameLower, 'capitalism')) return 'philosophy';
-    if (str_contains($filenameLower, 'database') || str_contains($filenameLower, 'postgres') || str_contains($filenameLower, 'versioncontrol') || str_contains($filenameLower, 'sql')) return 'tech';
-    return 'other'; // Default category
-}
-
-// --- Helper Function: Extract Metadata ---
-function extractMetadata(string $filepath): array {
-    global $baseUrl, $scheme, $host;
-
-    $filename = basename($filepath);
-    $metadata = [
-        'id' => 'cs-' . pathinfo($filename, PATHINFO_FILENAME), // Unique ID for JS targeting
-        'title' => pathinfo($filename, PATHINFO_FILENAME),
-        'description' => 'Explore this cheatsheet to learn more.',
-        'image' => null,
-        'url' => $baseUrl . $filename,
-        'category' => getCategoryForFile($filename), // Assign category
-        'error' => null
-    ];
-
-    $content = @file_get_contents($filepath);
-    if ($content === false) {
-        $metadata['error'] = "Could not read file: " . $filename;
-        return $metadata;
-    }
-
-    $dom = new DOMDocument();
-    @$dom->loadHTML($content, LIBXML_NOERROR | LIBXML_NOWARNING);
-    $xpath = new DOMXPath($dom);
-
-    $titleNode = $xpath->query('//title')->item(0);
-    if ($titleNode) $metadata['title'] = trim($titleNode->textContent);
-
-    $descNode = $xpath->query('//meta[@name="description"]/@content')->item(0);
-    if ($descNode) {
-        $metadata['description'] = trim($descNode->nodeValue);
-    } else {
-        $ogDescNode = $xpath->query('//meta[@property="og:description"]/@content')->item(0);
-        if ($ogDescNode) $metadata['description'] = trim($ogDescNode->nodeValue);
-    }
-
-    $imgNode = $xpath->query('//meta[@property="og:image"]/@content')->item(0);
-    if ($imgNode) {
-        $imageUrl = trim($imgNode->nodeValue);
-        if (!preg_match('/^https?:\/\//i', $imageUrl)) {
-             if (str_starts_with($imageUrl, '/')) {
-                 $metadata['image'] = $scheme . '://' . $host . $imageUrl;
-             } else {
-                 $absoluteImagePath = realpath(dirname(__FILE__)) . '/' . $imageUrl;
-                 if (file_exists($absoluteImagePath)) {
-                    $metadata['image'] = $baseUrl . $imageUrl;
-                 } else {
-                     error_log("Relative image path not found: " . $imageUrl . " in " . $filename);
-                 }
-             }
-        } else {
-            $metadata['image'] = $imageUrl;
-        }
-    }
-
-    if (mb_strlen($metadata['description']) > 150) {
-        $metadata['description'] = mb_substr($metadata['description'], 0, 147) . '...';
-    }
-
-    return $metadata;
-}
-
-// --- Main Logic: Scan Directory and Build Cheatsheet List ---
-$cheatsheets = [];
-$errors = [];
-$categories = ['all']; // Start with 'all'
-
-try {
-    $files = scandir($cheatsheetDir);
-    if ($files === false) throw new Exception("Could not scan directory: " . $cheatsheetDir);
-
-    foreach ($files as $file) {
-        $filePath = $cheatsheetDir . '/' . $file;
-        if (in_array($file, $excludedItems, true) || !is_file($filePath) || !is_readable($filePath)) continue;
-
-        if (str_ends_with(strtolower($file), '.html')) {
-            $meta = extractMetadata($filePath);
-            if ($meta['error']) {
-                $errors[] = $meta['error'];
-            } else {
-                $cheatsheets[] = $meta;
-                if (!in_array($meta['category'], $categories)) {
-                    $categories[] = $meta['category'];
-                }
-            }
-        }
-    }
-    sort($categories); // Sort categories alphabetically (optional)
-    // Sort cheatsheets alphabetically by title
-    usort($cheatsheets, fn($a, $b) => strcasecmp($a['title'], $b['title']));
-
-} catch (Exception $e) {
-    $errors[] = "An error occurred: " . $e->getMessage();
-}
-
-?>
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="UTF-8">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-
-    <!-- Metadata -->
-    <title>David Veksler's Interactive Cheatsheet Gallery</title>
-    <meta name="description" content="Explore an interactive gallery of expertly crafted cheatsheets by David Veksler. Filter by topic and view details dynamically. Custom design services available.">
-    <meta name="keywords" content="interactive cheatsheets, portfolio, gallery, filter, javascript gallery, cheatsheet design, information design, david veksler, tech, philosophy, ai safety, bitcoin, leadership, custom cheatsheets">
-    <!-- Other meta tags (author, canonical, OG, Twitter) remain similar -->
-    <link rel="canonical" href="<?php echo htmlspecialchars($baseUrl); ?>">
-    <meta property="og:title" content="David Veksler's Interactive Cheatsheet Gallery">
-    <meta property="og:description" content="Explore an interactive gallery of expertly crafted cheatsheets. Filter by topic, view details dynamically.">
-    <meta property="og:image" content="<?php echo htmlspecialchars($baseUrl); ?>images/cheatsheets-og-gallery.png"> <!-- Suggest creating a gallery-specific OG image -->
-    <meta property="og:image:alt" content="Interactive Cheatsheet Gallery Showcase">
-    <!-- Twitter card meta -->
-
-    <!-- Bootstrap CSS & Icons -->
-    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
-    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css">
-
-    <!-- Custom CSS for Awesome Gallery -->
-    <style>
-        :root {
-            --gallery-bg-start: #f8f9fa;
-            --gallery-bg-end: #e9ecef;
-            --card-hover-scale: 1.03;
-            --card-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
-            --card-hover-shadow: 0 8px 25px rgba(0, 0, 0, 0.12);
-            --expanded-view-bg: rgba(255, 255, 255, 0.98);
-            --expanded-view-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
-            --filter-active-bg: #0d6efd;
-            --filter-active-color: #fff;
-        }
-        html { scroll-behavior: smooth; }
-        body {
-            display: flex;
-            flex-direction: column;
-            min-height: 100vh;
-            background-image: linear-gradient(135deg, var(--gallery-bg-start) 0%, var(--gallery-bg-end) 100%);
-            overflow-x: hidden; /* Prevent horizontal scroll during animations */
-        }
-        .main-content { flex: 1; }
-        .navbar { background-image: linear-gradient(to bottom, #343a40, #212529); }
-
-        /* --- Filter Buttons --- */
-        .filter-buttons .btn {
-            margin: 0.25rem;
-            transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
-        }
-        .filter-buttons .btn.active {
-            background-color: var(--filter-active-bg);
-            color: var(--filter-active-color);
-            border-color: var(--filter-active-bg);
-        }
-
-        /* --- Portfolio Grid & Items --- */
-        #cheatsheetGrid {
-            position: relative; /* Needed for positioning expanded item */
-        }
-        .portfolio-item {
-            /* Styles for the column */
-            transition: opacity 0.4s ease-out, transform 0.4s ease-out;
-        }
-        .portfolio-item.filtered-out {
-             opacity: 0;
-             transform: scale(0.9);
-             /* We'll add d-none via JS after transition */
-             pointer-events: none; /* Avoid interacting while hiding */
-             position: absolute; /* Take out of flow smoothly */
-             z-index: -1;
-        }
-        .portfolio-card {
-            cursor: pointer;
-            border-radius: 8px;
-            overflow: hidden;
-            background-color: #fff;
-            box-shadow: var(--card-shadow);
-            transition: transform 0.3s ease-out, box-shadow 0.3s ease-out;
-            height: 100%; /* Fill the column height */
-            display: flex;
-            flex-direction: column;
-        }
-        .portfolio-card:hover {
-            transform: scale(var(--card-hover-scale));
-            box-shadow: var(--card-hover-shadow);
-            z-index: 10; /* Bring slightly forward on hover */
-        }
-        .card-thumbnail {
-            aspect-ratio: 16 / 9;
-            background-color: #e9ecef;
-            background-size: cover;
-            background-position: center;
-            display: flex;
-            align-items: center;
-            justify-content: center;
-            color: #adb5bd;
-            border-bottom: 1px solid #dee2e6;
-        }
-         .card-thumbnail::before { /* Placeholder Icon */
-             font-family: 'bootstrap-icons';
-             content: "\F48B"; /* bi-image-alt */
-             font-size: 2.5rem;
-             opacity: 0.5;
-        }
-         /* Hide placeholder if image is set via style */
-         .card-thumbnail[style*="background-image"]::before {
-             display: none;
-         }
-        .portfolio-card .card-body {
-            padding: 1rem;
-            flex-grow: 1; /* Allow body to take remaining space */
-        }
-        .portfolio-card .card-title {
-            font-size: 1rem;
-            font-weight: 600;
-            margin-bottom: 0; /* Title is main element here */
-        }
-
-        /* --- Expanded View --- */
-        .expanded-view-container {
-             display: none; /* Hidden initially */
-             position: fixed; /* Overlay */
-             top: 0; left: 0; right: 0; bottom: 0;
-             background-color: rgba(0, 0, 0, 0.6); /* Dim background */
-             z-index: 1050; /* Above most content */
-             padding: 2rem;
-             overflow-y: auto;
-             cursor: pointer; /* Indicate clicking outside closes */
-        }
-        .expanded-view-content {
-            position: relative;
-            background-color: var(--expanded-view-bg);
-            border-radius: 10px;
-            box-shadow: var(--expanded-view-shadow);
-            max-width: 800px; /* Control max width */
-            margin: 2rem auto; /* Centered */
-            padding: 1.5rem 2rem;
-            cursor: default; /* Standard cursor inside content */
-            transform: scale(0.9);
-            opacity: 0;
-            transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275), opacity 0.3s ease-out; /* Nice bounce effect */
-        }
-        .expanded-view-container.visible {
-             display: block;
-        }
-         .expanded-view-container.visible .expanded-view-content {
-             transform: scale(1);
-             opacity: 1;
-        }
-
-        .expanded-view-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; border-bottom: 1px solid #eee; padding-bottom: 0.8rem;}
-        .expanded-view-title { font-size: 1.5rem; font-weight: 600; margin-bottom: 0; }
-        .expanded-view-close { font-size: 1.8rem; line-height: 1; background: none; border: none; opacity: 0.6; transition: opacity 0.2s; }
-        .expanded-view-close:hover { opacity: 1; }
-
-        .expanded-view-body { display: flex; flex-direction: column; gap: 1.5rem; }
-        .expanded-preview {
-            width: 100%;
-            aspect-ratio: 16 / 9;
-            background-color: #f0f0f0;
-            border-radius: 5px;
-            overflow: hidden;
-            display: flex; align-items: center; justify-content: center;
-        }
-        .expanded-preview iframe { width: 100%; height: 100%; border: none; }
-        .expanded-preview img { width: 100%; height: 100%; object-fit: cover; }
-         .expanded-description { color: #333; line-height: 1.6; }
-         .expanded-actions { text-align: center; margin-top: 1rem; }
-
-         /* Spinner for iframe loading */
-         .spinner-container { position: absolute; top:0; left:0; right:0; bottom:0; background:rgba(255,255,255,0.8); display: flex; align-items: center; justify-content: center; z-index: 5; opacity:0; transition: opacity 0.3s; pointer-events: none; }
-         .spinner-container.loading { opacity: 1; pointer-events: auto;}
-
-        /* Footer & Subtle CTA */
-        .footer { background-color: #e9ecef; color: #6c757d; border-top: 1px solid #ced4da; }
-        .cta-scroll-link { font-size: 0.9rem; text-decoration: none; }
-        .cta-scroll-link:hover { text-decoration: underline; }
-        .cta-section-bottom { border-top: 1px solid #dee2e6; padding-top: 2rem; padding-bottom: 1rem; margin-top: 3rem; }
-    </style>
-</head>
-<body class="d-flex flex-column min-vh-100">
-    <nav class="navbar navbar-expand-lg navbar-dark bg-dark sticky-top shadow-sm">
-        <div class="container">
-            <a class="navbar-brand" href="<?php echo htmlspecialchars($baseUrl); ?>">
-                 <i class="bi bi-grid-3x3-gap-fill me-2"></i>David Veksler's Interactive Gallery
-            </a>
-        </div>
-    </nav>
-
-    <main class="main-content container mt-4 mb-5">
-        <header class="text-center mb-4">
-            <h1 class="display-5 fw-bold">Cheatsheet Showcase</h1>
-            <p class="lead text-muted">Explore interactive examples. Filter by category or search.</p>
-             <a href="#custom-cheatsheets" class="cta-scroll-link link-secondary d-block mb-3"><i class="bi bi-tools me-1"></i>Need a custom cheatsheet?</a>
-        </header>
-
-        <!-- Filter Buttons -->
-        <div id="filterButtons" class="filter-buttons text-center mb-4">
-            <?php foreach ($categories as $category): ?>
-                <button class="btn btn-sm <?php echo ($category === 'all') ? 'btn-primary active' : 'btn-outline-secondary'; ?>" data-filter="<?php echo htmlspecialchars($category); ?>">
-                    <?php echo htmlspecialchars(ucfirst($category)); ?>
-                </button>
-            <?php endforeach; ?>
-        </div>
-
-         <!-- Text Filter Input (Optional) -->
-        <div class="row mb-4 justify-content-center">
-            <div class="col-md-8 col-lg-6">
-                <div class="input-group shadow-sm">
-                    <span class="input-group-text bg-white border-end-0" id="search-addon"><i class="bi bi-search text-primary"></i></span>
-                    <input type="search" id="searchInput" class="form-control border-start-0" placeholder="Search within category..." aria-label="Search cheatsheets" aria-describedby="search-addon">
-                </div>
-            </div>
-        </div>
-
-        <!-- Error Display -->
-        <?php if (!empty($errors)): ?>
-            <div class="alert alert-warning">... errors ...</div>
-        <?php endif; ?>
-        <?php if (empty($cheatsheets) && empty($errors)): ?>
-             <div class="alert alert-info text-center">No cheatsheet examples found.</div>
-        <?php endif; ?>
-
-        <!-- Cheatsheet Grid -->
-        <div id="cheatsheetGrid" class="row row-cols-1 row-cols-sm-2 row-cols-md-3 row-cols-lg-4 g-4">
-            <?php if (!empty($cheatsheets)): ?>
-                <?php foreach ($cheatsheets as $sheet): ?>
-                    <div class="col portfolio-item" data-category="<?php echo htmlspecialchars($sheet['category']); ?>" data-title="<?php echo htmlspecialchars(strtolower($sheet['title'])); ?>" id="<?php echo htmlspecialchars($sheet['id']); ?>">
-                        <div class="portfolio-card" role="button" tabindex="0" aria-label="View details for <?php echo htmlspecialchars($sheet['title']); ?>">
-                            <div class="card-thumbnail" <?php if (!empty($sheet['image'])): ?> style="background-image: url('<?php echo htmlspecialchars($sheet['image']); ?>');" <?php endif; ?>>
-                                <!-- Placeholder handled by CSS -->
-                            </div>
-                            <div class="card-body">
-                                <h5 class="card-title"><?php echo htmlspecialchars($sheet['title']); ?></h5>
-                            </div>
-                            <!-- Hidden data for expanded view -->
-                            <script type="application/json" class="cheatsheet-data">
-                                <?php echo json_encode([
-                                    'title' => $sheet['title'],
-                                    'description' => $sheet['description'],
-                                    'url' => $sheet['url'],
-                                    'image' => $sheet['image']
-                                ]); ?>
-                            </script>
-                        </div>
-                    </div>
-                <?php endforeach; ?>
-            <?php endif; ?>
-        </div>
-
-         <!-- No Results Message -->
-        <div id="noResults" class="alert alert-warning text-center mt-4 d-none" role="alert">
-            <i class="bi bi-emoji-frown me-2"></i>No cheatsheets match your criteria.
-        </div>
-
-        <!-- Call to Action Section -->
-         <section id="custom-cheatsheets" class="cta-section-bottom text-center">
-              <h3 class="h4 fw-normal mb-3">Need a Custom Cheatsheet?</h3>
-              <p class="text-muted mb-3 mx-auto" style="max-width: 600px;">I design professional, tailored cheatsheets for documentation, training, marketing, and more.</p>
-              <a href="https://www.linkedin.com/in/davidveksler/" target="_blank" rel="noopener noreferrer" class="btn btn-outline-primary btn-sm">
-                  <i class="bi bi-linkedin me-1"></i> Discuss Your Project on LinkedIn
-              </a>
-          </section>
-    </main>
-
-    <!-- Expanded View Structure (Initially Hidden) -->
-    <div id="expandedView" class="expanded-view-container">
-        <div class="expanded-view-content" role="dialog" aria-modal="true" aria-labelledby="expandedViewTitle">
-             <div class="expanded-view-header">
-                 <h2 id="expandedViewTitle" class="expanded-view-title">Cheatsheet Title</h2>
-                 <button type="button" class="expanded-view-close" aria-label="Close dialog">×</button>
-             </div>
-             <div class="expanded-view-body">
-                 <div class="expanded-preview">
-                     <!-- Content (image or iframe) added by JS -->
-                      <div class="spinner-container"><div class="spinner-border text-primary" role="status"><span class="visually-hidden">Loading...</span></div></div>
-                 </div>
-                 <p class="expanded-description">Description goes here...</p>
-             </div>
-             <div class="expanded-actions">
-                <a href="#" id="expandedViewLink" target="_blank" rel="noopener noreferrer" class="btn btn-primary">
-                    View Full Cheatsheet <i class="bi bi-box-arrow-up-right ms-1"></i>
-                </a>
-            </div>
-        </div>
-    </div>
-
-
-    <!-- Footer -->
-    <footer class="footer py-4 mt-auto border-top bg-light">
-        <div class="container text-center">
-            <p class="mb-2 text-muted">
-                Interactive Cheatsheet Gallery by David Veksler © <?php echo date("Y"); ?>
-            </p>
-            <div>
-              <a href="https://www.linkedin.com/in/davidveksler/" title="David Veksler on LinkedIn" target="_blank" rel="noopener noreferrer" class="mx-2 link-secondary"><i class="bi bi-linkedin"></i> LinkedIn</a>
-              <span class="text-muted mx-1">|</span>
-              <a href="<?php echo htmlspecialchars($baseUrl); ?>" title="Reload Gallery" class="mx-2 link-secondary"><i class="bi bi-collection"></i> Gallery Home</a>
-            </div>
-        </div>
-    </footer>
-
-    <!-- Bootstrap Bundle -->
-    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
-
-    <!-- Custom JS for Gallery -->
-    <script>
-        document.addEventListener('DOMContentLoaded', function() {
-            const grid = document.getElementById('cheatsheetGrid');
-            const items = grid.querySelectorAll('.portfolio-item');
-            const filterButtonsContainer = document.getElementById('filterButtons');
-            const searchInput = document.getElementById('searchInput');
-            const noResultsMessage = document.getElementById('noResults');
-            const expandedViewContainer = document.getElementById('expandedView');
-            const expandedViewContent = expandedViewContainer.querySelector('.expanded-view-content');
-            const expandedViewClose = expandedViewContainer.querySelector('.expanded-view-close');
-            const expandedViewTitle = expandedViewContainer.querySelector('#expandedViewTitle');
-            const expandedPreview = expandedViewContainer.querySelector('.expanded-preview');
-            const expandedDescription = expandedViewContainer.querySelector('.expanded-description');
-            const expandedLink = expandedViewContainer.querySelector('#expandedViewLink');
-            const spinnerContainer = expandedPreview.querySelector('.spinner-container');
-
-            let currentFilter = 'all'; // Track current category filter
-            let currentSearch = '';   // Track current search term
-
-            // --- Filtering Logic ---
-            function applyFilters() {
-                 let itemsVisible = 0;
-                 items.forEach(item => {
-                     const categoryMatch = currentFilter === 'all' || item.dataset.category === currentFilter;
-                     const searchMatch = currentSearch === '' || item.dataset.title.includes(currentSearch); // Simple title search
-
-                     const shouldShow = categoryMatch && searchMatch;
-
-                     if (shouldShow) {
-                         if (item.classList.contains('filtered-out')) {
-                             // Make visible: remove d-none first, then transition classes
-                             item.classList.remove('d-none');
-                             // Use setTimeout to allow the 'd-none' removal to render before starting transition
-                             setTimeout(() => {
-                                item.classList.remove('filtered-out');
-                                item.classList.remove('position-absolute'); // Restore flow
-                                item.classList.remove('z-index:-1')
-                                item.style.pointerEvents = '';
-                            }, 10); // Small delay
-                         }
-                         itemsVisible++;
-                     } else {
-                         if (!item.classList.contains('filtered-out')) {
-                            item.classList.add('filtered-out');
-                            // Add d-none after the transition might have completed
-                            item.addEventListener('transitionend', () => {
-                                if (item.classList.contains('filtered-out')) { // Check if still filtered out
-                                     item.classList.add('d-none');
-                                }
-                            }, { once: true });
-                         }
-                     }
-                 });
-
-                 noResultsMessage.classList.toggle('d-none', itemsVisible > 0);
-            }
-
-            // Category Filter Button Clicks
-            filterButtonsContainer.addEventListener('click', function(e) {
-                if (e.target.tagName === 'BUTTON') {
-                    const filterValue = e.target.dataset.filter;
-                    if (filterValue === currentFilter) return; // No change
-
-                    filterButtonsContainer.querySelector('.active').classList.remove('active', 'btn-primary');
-                    filterButtonsContainer.querySelector('.active').classList.add('btn-outline-secondary'); // Make previously active outlined
-                    e.target.classList.add('active', 'btn-primary');
-                    e.target.classList.remove('btn-outline-secondary'); // Make currently active primary
-
-                    currentFilter = filterValue;
-                    applyFilters();
-                }
-            });
-
-            // Search Input
-            searchInput.addEventListener('input', function() {
-                 currentSearch = searchInput.value.toLowerCase().trim();
-                 applyFilters();
-            });
-
-
-            // --- Expanded View Logic ---
-            function showExpandedView(itemData) {
-                expandedViewTitle.textContent = itemData.title;
-                expandedDescription.textContent = itemData.description;
-                expandedLink.href = itemData.url;
-                expandedPreview.innerHTML = ''; // Clear previous content
-
-                // Re-add spinner
-                expandedPreview.appendChild(spinnerContainer.cloneNode(true));
-                const currentSpinner = expandedPreview.querySelector('.spinner-container');
-                currentSpinner.classList.add('loading'); // Show spinner immediately
-
-                // Decide whether to show image or iframe
-                if (itemData.image) {
-                    const img = document.createElement('img');
-                    img.src = itemData.image;
-                    img.alt = `Preview for ${itemData.title}`;
-                    img.loading = 'lazy';
-                    img.onload = () => currentSpinner.classList.remove('loading'); // Hide spinner on load
-                    img.onerror = () => { // Fallback to iframe if image fails
-                        console.warn("Image failed to load, trying iframe:", itemData.image);
-                        loadIframePreview(itemData.url, currentSpinner);
-                    };
-                    expandedPreview.appendChild(img);
-                } else {
-                    // Load iframe directly if no image
-                   loadIframePreview(itemData.url, currentSpinner);
-                }
-
-                expandedViewContainer.classList.add('visible');
-                document.body.style.overflow = 'hidden'; // Prevent background scroll
-            }
-
-            function loadIframePreview(url, spinner) {
-                 const iframe = document.createElement('iframe');
-                 iframe.src = url;
-                 iframe.title = `Preview of ${expandedViewTitle.textContent}`;
-                 iframe.setAttribute('loading', 'lazy');
-                 iframe.setAttribute('frameborder', '0');
-                 iframe.setAttribute('referrerpolicy', 'no-referrer');
-                 // Hide spinner when iframe is considered loaded (this is not always perfect)
-                 iframe.onload = () => spinner.classList.remove('loading');
-                 expandedPreview.appendChild(iframe);
-            }
-
-
-            function closeExpandedView() {
-                 expandedViewContainer.classList.remove('visible');
-                 document.body.style.overflow = ''; // Restore scrolling
-                 // Optional: Clear content immediately or after transition
-                 // expandedPreview.innerHTML = '';
-            }
-
-            // Grid Item Clicks
-            grid.addEventListener('click', function(e) {
-                const card = e.target.closest('.portfolio-card');
-                if (card) {
-                    const dataElement = card.querySelector('.cheatsheet-data');
-                    if (dataElement) {
-                        try {
-                            const itemData = JSON.parse(dataElement.textContent);
-                            showExpandedView(itemData);
-                        } catch (err) {
-                            console.error("Failed to parse cheatsheet data:", err);
-                        }
-                    }
-                }
-            });
-
-            // Close button click
-            expandedViewClose.addEventListener('click', closeExpandedView);
-
-             // Click outside the content to close
-            expandedViewContainer.addEventListener('click', function(e) {
-                 if (e.target === expandedViewContainer) { // Only if clicking the backdrop itself
-                     closeExpandedView();
-                 }
-            });
-
-            // Keyboard accessibility for closing
-             expandedViewContainer.addEventListener('keydown', function(e) {
-                 if (e.key === 'Escape') {
-                     closeExpandedView();
-                 }
-            });
-
-             // Keyboard accessibility for opening
-             grid.addEventListener('keydown', function(e) {
-                  const card = e.target.closest('.portfolio-card');
-                  if (card && (e.key === 'Enter' || e.key === ' ')) {
-                      e.preventDefault(); // Prevent space from scrolling
-                      const dataElement = card.querySelector('.cheatsheet-data');
-                       if (dataElement) {
-                           try {
-                               const itemData = JSON.parse(dataElement.textContent);
-                               showExpandedView(itemData);
-                           } catch (err) { console.error("Failed to parse cheatsheet data:", err); }
-                       }
-                  }
-             });
-
-        });
-    </script>
-
-</body>
-</html>
\ No newline at end of file
diff --git a/sitemap.php b/sitemap.php
index a7aa40c..b7bc0ee 100644
--- a/sitemap.php
+++ b/sitemap.php
@@ -15,7 +15,7 @@ $excludedItems = [
     'PROMPT2.txt',
     'CLAUDE.md',
     'generate-image-previews.py',
-    'sitemap.xml',
+    'sitemap.php',
     // Add any other files you want to exclude from sitemap
 ];