Javi

GreaseMonkey: ArchDaily gallery

Jan 16th, 2026 (edited)
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.37 KB | None | 0 0
  1. // ==UserScript==
  2. // @name ArchDaily Image Gallery (Adaptive)
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.2
  5. // @description Replace page with adaptive image gallery from figure imgs (ArchDaily)
  6. // @author You
  7. // @match https://www.archdaily.com/*/*
  8. // @grant none
  9. // @run-at document-end
  10. // ==/UserScript==
  11.  
  12. // https://www.archdaily.com/1037995/kulhad-pavilion-wallmakers
  13. // const text = [...document.querySelectorAll('article p')].map(p=>p.innerText).filter(t=>t.length>10).join();
  14. // const images= [...document.querySelectorAll('.gallery-thumbs li a')].map(a=>a.href)
  15.  
  16. (function() {
  17. 'use strict';
  18.  
  19. // Wait for page to fully load
  20. function initGallery() {
  21. // Auto-detect images from ArchDaily figure imgs or global images array
  22. const title = document.querySelector('h1').innerText;
  23. const text = [...document.querySelectorAll('article p')].map(p=>p.innerText).filter(t=>t.length>10).join();
  24. let sources = [...document.querySelectorAll('.gallery-thumbs-link picture img')].map(i=>i.src).filter(s=>s).map(s=>s.replace('medium_jpg', 'slideshow'));
  25. let images = sources;
  26.  
  27.  
  28. // Final dedupe and validation
  29. /*
  30. images = images.filter((src, index, self) =>
  31. src && src.trim && src.trim() !== '' && self.indexOf(src) === index
  32. );
  33. */
  34. if (!images.length) {
  35. console.log('No valid images found, retrying...');
  36. return false; // Not ready yet
  37. }
  38.  
  39. // Determine optimal layout based on image count
  40. const count = images.length;
  41. let gridConfig = {
  42. columns: 'repeat(auto-fit, minmax(250px, 1fr))',
  43. minSize: '250px',
  44. gap: '15px',
  45. height: '200px'
  46. };
  47.  
  48. if (count === 1) {
  49. gridConfig = {
  50. columns: '1fr',
  51. minSize: '100%',
  52. gap: '0',
  53. height: 'auto',
  54. maxHeight: '80vh'
  55. };
  56. } else if (count === 2) {
  57. gridConfig = {
  58. columns: 'repeat(2, 1fr)',
  59. minSize: '300px',
  60. gap: '20px',
  61. height: '400px'
  62. };
  63. } else if (count <= 4) {
  64. gridConfig = {
  65. columns: 'repeat(2, 1fr)',
  66. minSize: '300px',
  67. gap: '15px',
  68. height: '300px'
  69. };
  70. } else if (count <= 6) {
  71. gridConfig = {
  72. columns: 'repeat(3, 1fr)',
  73. minSize: '280px',
  74. gap: '15px',
  75. height: '250px'
  76. };
  77. } else if (count <= 12) {
  78. gridConfig = {
  79. columns: 'repeat(auto-fit, minmax(300px, 1fr))',
  80. minSize: '300px',
  81. gap: '15px',
  82. height: '220px'
  83. };
  84. }
  85.  
  86. // Replace entire page content
  87. document.documentElement.innerHTML = `
  88. <!DOCTYPE html>
  89. <html>
  90. <head>
  91. <style>
  92. * { box-sizing: border-box; }
  93. body {
  94. margin: 0; padding: 20px;
  95. font-family: Arial, sans-serif;
  96. background: #222; color: white;
  97. }
  98. .gallery {
  99. display: grid;
  100. grid-template-columns: ${gridConfig.columns};
  101. gap: ${gridConfig.gap};
  102. max-width: 1400px;
  103. margin: 0 auto;
  104. }
  105. .gallery img {
  106. width: 100%;
  107. height: ${gridConfig.height};
  108. ${gridConfig.maxHeight ? 'max-height: ' + gridConfig.maxHeight + ';' : ''}
  109. object-fit: cover;
  110. border-radius: 8px;
  111. cursor: pointer;
  112. box-shadow: 0 4px 12px rgba(0,0,0,0.5);
  113. transition: transform 0.3s ease;
  114. }
  115. .gallery img:hover { transform: scale(1.02); }
  116. .info-bar {
  117. font-size: 120%;
  118. text-align: left;
  119. margin-bottom: 20px;
  120. padding: 2em;
  121. background: rgba(255,255,255,0.1);
  122. color: #ccc;
  123. border-radius: 8px;
  124. max-width: 1400px;
  125. margin: 0 auto 20px;
  126. }
  127. h1 {
  128. text-align : center;key
  129. }
  130. .modal {
  131. display: none;
  132. position: fixed;
  133. top: 0; left: 0;
  134. width: 100%; height: 100%;
  135. background: rgba(0,0,0,0.95);
  136. z-index: 9999;
  137. }
  138. .modal img {
  139. max-width: 90%;
  140. max-height: 90%;
  141. position: absolute;
  142. top: 50%; left: 50%;
  143. transform: translate(-50%, -50%);
  144. border-radius: 8px;
  145. }
  146. .close {
  147. position: absolute;
  148. top: 20px; right: 30px;
  149. color: white;
  150. font-size: 40px;
  151. font-weight: bold;
  152. cursor: pointer;
  153. }
  154. .nav-btn {
  155. position: absolute;
  156. top: 50%;
  157. transform: translateY(-50%);
  158. background: rgba(255,255,255,0.2);
  159. border: none;
  160. color: white;
  161. font-size: 24px;
  162. padding: 15px 20px;
  163. cursor: pointer;
  164. border-radius: 50%;
  165. width: 60px;
  166. height: 60px;
  167. display: flex;
  168. align-items: center;
  169. justify-content: center;
  170. transition: background 0.3s;
  171. }
  172. .nav-btn:hover { background: rgba(255,255,255,0.4); }
  173. .prev { left: 30px; }
  174. .next { right: 30px; }
  175. .counter {
  176. position: absolute;
  177. bottom: 30px;
  178. left: 50%;
  179. transform: translateX(-50%);
  180. background: rgba(0,0,0,0.7);
  181. padding: 10px 20px;
  182. border-radius: 20px;
  183. font-size: 18px;
  184. }
  185. @media (max-width: 768px) {
  186. .gallery {
  187. grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)) !important;
  188. }
  189. .gallery img {
  190. height: 150px !important;
  191. }
  192. }
  193. </style>
  194. </head>
  195. <body>
  196. <div class="info-bar">
  197. <h1>${title}</h1>
  198. <i>${text}</i>
  199. </div>
  200. <div class="gallery"></div>
  201. <div class="modal">
  202. <span class="close">&times;</span>
  203. <img id="modalImg">
  204. <button class="nav-btn prev">‹</button>
  205. <button class="nav-btn next">›</button>
  206. <div class="counter" id="counter"></div>
  207. </div>
  208. </body>
  209. </html>`;
  210.  
  211. // Elements
  212. const gallery = document.querySelector('.gallery');
  213. const modal = document.querySelector('.modal');
  214. const modalImg = document.getElementById('modalImg');
  215. const closeBtn = document.querySelector('.close');
  216. const prevBtn = document.querySelector('.prev');
  217. const nextBtn = document.querySelector('.next');
  218. const counter = document.getElementById('counter');
  219.  
  220. let currentIndex = 0;
  221. const imageSources = images; // Store reference
  222.  
  223. // Build gallery
  224. images.forEach((src, i) => {
  225. const img = document.createElement('img');
  226. img.src = src;
  227. img.alt = `Image ${i + 1}`;
  228. img.onclick = () => openModal(i);
  229. gallery.appendChild(img);
  230. });
  231.  
  232. // Modal controls
  233. function openModal(index) {
  234. currentIndex = index;
  235. modal.style.display = 'block';
  236. modalImg.src = imageSources[currentIndex];
  237. updateCounter();
  238. }
  239.  
  240. function updateCounter() {
  241. counter.textContent = `${currentIndex + 1} / ${imageSources.length}`;
  242. }
  243.  
  244. function showPrev() {
  245. currentIndex = (currentIndex - 1 + imageSources.length) % imageSources.length;
  246. modalImg.src = imageSources[currentIndex];
  247. updateCounter();
  248. }
  249.  
  250. function showNext() {
  251. currentIndex = (currentIndex + 1) % imageSources.length;
  252. modalImg.src = imageSources[currentIndex];
  253. updateCounter();
  254. }
  255.  
  256. closeBtn.onclick = () => modal.style.display = 'none';
  257. prevBtn.onclick = showPrev;
  258. nextBtn.onclick = showNext;
  259. modal.onclick = e => { if (e.target === modal) modal.style.display = 'none'; };
  260.  
  261. document.addEventListener('keydown', function(e) {
  262. if (modal.style.display === 'block') {
  263. if (e.key === 'ArrowLeft') showPrev();
  264. if (e.key === 'ArrowRight') showNext();
  265. if (e.key === 'Escape') modal.style.display = 'none';
  266. }
  267. }, true);
  268.  
  269. return true; // Success
  270. }
  271.  
  272. // Wait for full load with retries
  273. function waitForLoad() {
  274. if (document.readyState === 'complete' || document.readyState === 'interactive') {
  275. const maxAttempts = 5; // 5 seconds
  276. let attempts = 0;
  277.  
  278. function tryInit() {
  279. try {
  280. attempts++;
  281. if (initGallery() || attempts >= maxAttempts) {
  282. if (attempts >= maxAttempts) {
  283. alert('Gallery failed to initialize - page might not have images');
  284. }
  285. return;
  286. }
  287. setTimeout(tryInit, 100);
  288. } catch (e) {
  289. console.error('*********** ', e);
  290. alert('Error.', e);
  291. }
  292. }
  293. tryInit();
  294. } else {
  295. setTimeout(waitForLoad, 100);
  296. }
  297. }
  298.  
  299. // Start waiting
  300. if (document.readyState === 'loading') {
  301. document.addEventListener('DOMContentLoaded', waitForLoad);
  302. window.addEventListener('load', waitForLoad);
  303. } else {
  304. waitForLoad();
  305. }
  306. })();
Advertisement
Add Comment
Please, Sign In to add comment