4chan post image grid

13/12/2024, 21:55:28

  1. // ==UserScript==
  2. // @name 4chan post image grid
  3. // @namespace Violentmonkey Scripts
  4. // @match https://boards.4chan.org/*
  5. // @grant none
  6. // @version 1.0
  7. // @author Anon
  8. // @description 13/12/2024, 21:55:28
  9. // ==/UserScript==
  10.  
  11.  
  12. let imageGrid = null;
  13. let imageGridContent = null;
  14. let imageModal = null;
  15. let modalImage = null;
  16. const thread = document.querySelector('.thread');
  17. if (!thread) return;
  18.  
  19.  
  20. // Image modal
  21. const openImageModal = (thumb) => {
  22. if (!modalImage) {
  23. imageModal = document.createElement('div');
  24. imageModal.classList = 'image-grid__modal';
  25. document.body.appendChild(imageModal);
  26.  
  27. modalImage = document.createElement('img');
  28. imageModal.appendChild(modalImage);
  29.  
  30. imageModal.addEventListener('click', () => imageModal.classList.remove('open'));
  31. }
  32.  
  33. modalImage.src = thumb.href;
  34. imageModal.classList.add('open');
  35. };
  36.  
  37.  
  38. // Image grid
  39. const populateImageGrid = () => {
  40. imageGridContent.innerHTML = '';
  41.  
  42. const thumbs = [...thread.querySelectorAll('.fileThumb')].map(thumb => {
  43. return thumb.cloneNode(true);
  44. });
  45.  
  46. thumbs.forEach(thumb => {
  47. imageGridContent.appendChild(thumb);
  48. thumb.addEventListener('click', (event) => {
  49. event.preventDefault();
  50. openImageModal(thumb)
  51. });
  52. });
  53. };
  54.  
  55. const buildImageGrid = () => {
  56. imageGrid = document.createElement('div');
  57. imageGrid.classList = 'image-grid open';
  58. document.body.appendChild(imageGrid);
  59. imageGrid.addEventListener('click', event => {
  60. if (event.target.closest('.image-grid__content')) return;
  61. imageGrid.classList.remove('open');
  62. })
  63.  
  64. imageGridContent = document.createElement('div');
  65. imageGridContent.classList = 'image-grid__content';
  66. imageGrid.appendChild(imageGridContent);
  67. populateImageGrid();
  68. }
  69.  
  70.  
  71. // Image grid button
  72. const gridButton = document.createElement('button');
  73. gridButton.textContent = 'Image Grid';
  74. gridButton.id = 'image-grid-button';
  75. document.body.appendChild(gridButton);
  76.  
  77. gridButton.addEventListener('click', (event) => {
  78. if (!imageGrid) {
  79. buildImageGrid();
  80. } else {
  81. imageGrid.classList.add('open');
  82. populateImageGrid();
  83. }
  84. });
  85.  
  86.  
  87. // Styles
  88. const style = document.createElement('style');
  89. style.innerHTML = `
  90. .thread {
  91. flex-direction: column;
  92. }
  93.  
  94. .thread .opContainer {
  95. order: 1;
  96. }
  97.  
  98. #image-grid-button {
  99. position: fixed;
  100. top: 4.5rem;
  101. right: 2rem;
  102. opacity: 0.5;
  103. padding: 0.4rem 0.6rem;
  104. background: white !important;
  105. border: none !important;
  106. border-radius: 0.2rem;
  107. transition: all ease 150ms;
  108. cursor: pointer;
  109. color: inherit;
  110. }
  111.  
  112. #image-grid-button:hover {
  113. opacity: 1;
  114. }
  115.  
  116. .image-grid {
  117. position: fixed;
  118. top: 0;
  119. left: 0;
  120. width: 100%;
  121. height: 100%;
  122. z-index: 100;
  123. background: rgba(0,0,0,0.8);
  124. display: none;
  125. }
  126.  
  127. .image-grid.open {
  128. display: flex;
  129. }
  130.  
  131. .image-grid__content {
  132. height: auto;
  133. width: auto;
  134. overflow: auto;
  135. background: rgba(255,255,255,0.1);
  136. margin: 3rem;
  137. display: flex;
  138. flex-wrap: wrap;
  139. gap: 10px;
  140. }
  141.  
  142. .image-grid__modal {
  143. position: fixed;
  144. z-index: 101;
  145. top: 0;
  146. left: 0;
  147. width: 100%;
  148. height: 100%;
  149. background: rgba(0,0,0,0.5);
  150. display: none;
  151. }
  152.  
  153. .image-grid__modal.open {
  154. display: block;
  155. }
  156.  
  157. .image-grid__modal img {
  158. width: 100%;
  159. height: 100%;
  160. object-fit: contain;
  161. }
  162. `;
  163.  
  164. document.head.appendChild(style);