Decli-Tech/Coding-Projects
0
1<!DOCTYPE html>2<html lang="en">3<head>4 <meta charset="UTF-8">5 <meta name="viewport" content="width=device-width, initial-scale=1.0">6 <title>Screenshot Gallery</title>7 <script src="https://cdn.tailwindcss.com"></script>8 <style>9 /* Ensure html and body take full height */10 html, body {11 height: 100%;12 margin: 0;13 padding: 0;14 background-color: #1a202c; /* Dark background */15 }16 /* Ensure the grid container takes full height */17 #screenshot-grid {18 19 }20 /* Style for individual grid items */21 .grid-item {22 border-radius:12px;23 }24 25 .grid-item:hover {26 filter: brightness(1.2);27 }28 /* Style for images within grid items */29 .grid-item img {30 31 }32 </style>33</head>34<body class="bg-gray-900 text-gray-100">35 <header class="p-4 flex justify-between items-center border-b border-gray-700">36 <h1 class="text-2xl font-bold"><span class="font-normal">Made with</span> DeepSite</h1>37 <p class="max-sm:text-xs max-sm:w-40">⚠️ Do not share personal information. User-submitted apps may contain malicious code.</p>38 <a href="https://huggingface.co/spaces/enzostvs/deepsite" target="_blank" rel="noopener noreferrer" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">39 Open DeepSite40 </a>41 </header>42 <div id="screenshot-grid" class="grid grid-cols-2 sm:grid-cols-3 2xl:grid-cols-4 gap-2 p-4">43 <!-- Screenshots will be loaded here -->44 </div>45 46 <script>47 async function loadScreenshots() {48 try {49 const response = await fetch('screenshots.json');50 if (!response.ok) {51 throw new Error(`HTTP error! status: ${response.status}`);52 }53 // Read the JSON body ONCE54 const screenshotsData = await response.json();55 // screenshotsData is now an array of objects: [{filename: "...", rating: N}, ...]56 57 const grid = document.getElementById('screenshot-grid');58 grid.innerHTML = ''; // Clear existing content59 const fragment = document.createDocumentFragment(); // Create a fragment60 61 // No need to filter/sort here, assuming screenshots.json is already sorted and correct62 if (!Array.isArray(screenshotsData)) {63 throw new Error("screenshots.json is not a valid array.");64 }65 66 // Build elements in the fragment67 screenshotsData.forEach(item => {68 if (!item || typeof item.filename !== 'string' || !item.filename.endsWith('.png')) {69 console.warn("Skipping invalid item in screenshots.json:", item);70 return;71 }72 // --- Filter by rating ---73 if (typeof item.rating !== 'number' || item.rating < 50) {74 // console.log(`Skipping ${item.filename} due to rating: ${item.rating}`);75 return; // Skip items with rating below 50 or invalid rating76 }77 // --- End filter ---78 79 const filename = item.filename;80 // const rating = item.rating; // Rating is available if needed for display81 82 const gridItem = document.createElement('div');83 gridItem.className = 'grid-item relative'; // Added relative for potential badge positioning84 85 const img = document.createElement('img');86 img.src = `screenshots/${filename}`;87 img.alt = `Screenshot of ${filename.replace(/^space-|-/g, ' ').replace('.png', '')}`; // Improved alt text88 img.loading = 'lazy'; // Lazy load images89 img.decoding = 'async'; // Hint for async decoding90 img.className = 'w-full h-auto object-cover rounded-lg shadow-md'; // Added some styling91 92 // Create the link element93 const link = document.createElement('a');94 95 // Parse filename to create the URL (remove 'space-' prefix and '.png' suffix)96 try {97 const namePart = filename.replace(/^space-/, '').replace(/\.png$/, '');98 // Replace the *first* hyphen only to separate owner/repo99 const parts = namePart.split(/-(.+)/); // Split on the first hyphen100 if (parts.length >= 2 && parts[0] && parts[1]) {101 const username = parts[0];102 const spacename = parts[1];103 link.href = `https://huggingface.co/spaces/${username}/${spacename}`;104 link.target = '_blank'; // Open in new tab105 link.rel = 'noopener noreferrer'; // Security best practice106 } else {107 // Handle cases where the format might be unexpected108 console.warn(`Could not parse username/spacename from: ${filename}`);109 // Make it non-clickable by just appending the image110 gridItem.appendChild(img);111 fragment.appendChild(gridItem); // Add directly to fragment112 return; // Skip appending link for this item113 }114 } catch (e) {115 console.error(`Error parsing filename: ${filename}`, e);116 // Append image directly if parsing fails117 gridItem.appendChild(img);118 fragment.appendChild(gridItem); // Add directly to fragment119 return; // Skip appending link for this item120 }121 122 link.appendChild(img); // Place the image inside the link123 gridItem.appendChild(link); // Place the link (with image) inside the grid item124 125 // Optional: Display rating badge (Example)126 // if (typeof rating === 'number') {127 // const badge = document.createElement('span');128 // badge.className = 'absolute top-2 right-2 bg-blue-500 text-white text-xs font-bold px-2 py-1 rounded-full';129 // badge.textContent = rating;130 // gridItem.appendChild(badge);131 // }132 133 fragment.appendChild(gridItem); // Add the item to the fragment134 });135 136 // Append the fragment to the grid once137 grid.appendChild(fragment);138 139 } catch (error) {140 console.error('Failed to load screenshots:', error);141 const grid = document.getElementById('screenshot-grid');142 grid.innerHTML = '<p class="text-red-500 text-center col-span-3">Failed to load screenshots. Check console for details.</p>';143 }144 }145 146 document.addEventListener('DOMContentLoaded', loadScreenshots);147 </script>148</body>149</html>150 