main.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // Dean Attali / Beautiful Jekyll 2016
  2. var main = {
  3. bigImgEl : null,
  4. numImgs : null,
  5. init : function() {
  6. // Shorten the navbar after scrolling a little bit down
  7. $(window).scroll(function() {
  8. if ($(".navbar").offset().top > 50) {
  9. $(".navbar").addClass("top-nav-short");
  10. } else {
  11. $(".navbar").removeClass("top-nav-short");
  12. }
  13. });
  14. // On mobile, hide the avatar when expanding the navbar menu
  15. $('#main-navbar').on('show.bs.collapse', function () {
  16. $(".navbar").addClass("top-nav-expanded");
  17. });
  18. $('#main-navbar').on('hidden.bs.collapse', function () {
  19. $(".navbar").removeClass("top-nav-expanded");
  20. });
  21. // On mobile, when clicking on a multi-level navbar menu, show the child links
  22. $('#main-navbar').on("click", ".navlinks-parent", function(e) {
  23. var target = e.target;
  24. $.each($(".navlinks-parent"), function(key, value) {
  25. if (value == target) {
  26. $(value).parent().toggleClass("show-children");
  27. } else {
  28. $(value).parent().removeClass("show-children");
  29. }
  30. });
  31. });
  32. // Ensure nested navbar menus are not longer than the menu header
  33. var menus = $(".navlinks-container");
  34. if (menus.length > 0) {
  35. var navbar = $("#main-navbar").find("ul");
  36. var fakeMenuHtml = "<li class='fake-menu' style='display:none;'><a></a></li>";
  37. navbar.append(fakeMenuHtml);
  38. var fakeMenu = $(".fake-menu");
  39. $.each(menus, function(i) {
  40. var parent = $(menus[i]).find(".navlinks-parent");
  41. var children = $(menus[i]).find(".navlinks-children a");
  42. var words = [];
  43. $.each(children, function(idx, el) { words = words.concat($(el).text().trim().split(/\s+/)); });
  44. var maxwidth = 0;
  45. $.each(words, function(id, word) {
  46. fakeMenu.html("<a>" + word + "</a>");
  47. var width = fakeMenu.width();
  48. if (width > maxwidth) {
  49. maxwidth = width;
  50. }
  51. });
  52. $(menus[i]).css('min-width', maxwidth + 'px')
  53. });
  54. fakeMenu.remove();
  55. }
  56. // show the big header image
  57. main.initImgs();
  58. },
  59. initImgs : function() {
  60. // If the page was large images to randomly select from, choose an image
  61. if ($("#header-big-imgs").length > 0) {
  62. main.bigImgEl = $("#header-big-imgs");
  63. main.numImgs = main.bigImgEl.attr("data-num-img");
  64. // 2fc73a3a967e97599c9763d05e564189
  65. // set an initial image
  66. var imgInfo = main.getImgInfo();
  67. var src = imgInfo.src;
  68. var desc = imgInfo.desc;
  69. var position = imgInfo.position;
  70. main.setImg(src, desc, position);
  71. // For better UX, prefetch the next image so that it will already be loaded when we want to show it
  72. var getNextImg = function() {
  73. var imgInfo = main.getImgInfo();
  74. var src = imgInfo.src;
  75. var desc = imgInfo.desc;
  76. var position = imgInfo.position;
  77. var prefetchImg = new Image();
  78. prefetchImg.src = src;
  79. // if I want to do something once the image is ready: `prefetchImg.onload = function(){}`
  80. setTimeout(function(){
  81. var img = $("<div></div>").addClass("big-img-transition").css("background-image", 'url(' + src + ')');
  82. if (position !== undefined) {
  83. img.css("background-position", position);
  84. }
  85. $(".intro-header.big-img").prepend(img);
  86. setTimeout(function(){ img.css("opacity", "1"); }, 50);
  87. // after the animation of fading in the new image is done, prefetch the next one
  88. //img.one("transitioned webkitTransitionEnd oTransitionEnd MSTransitionEnd", function(){
  89. setTimeout(function() {
  90. main.setImg(src, desc, position);
  91. img.remove();
  92. getNextImg();
  93. }, 1000);
  94. //});
  95. }, 6000);
  96. };
  97. // If there are multiple images, cycle through them
  98. if (main.numImgs > 1) {
  99. getNextImg();
  100. }
  101. }
  102. },
  103. getImgInfo : function() {
  104. var randNum = Math.floor((Math.random() * main.numImgs) + 1);
  105. var src = main.bigImgEl.attr("data-img-src-" + randNum);
  106. var desc = main.bigImgEl.attr("data-img-desc-" + randNum);
  107. var position = main.bigImgEl.attr("data-img-position-" + randNum);
  108. return {
  109. src : src,
  110. desc : desc,
  111. position : position
  112. }
  113. },
  114. setImg : function(src, desc, position) {
  115. $(".intro-header.big-img").css("background-image", 'url(' + src + ')');
  116. if (position !== undefined) {
  117. $(".intro-header.big-img").css("background-position", position);
  118. }
  119. else {
  120. // Remove background-position if added to the prev image.
  121. $(".intro-header.big-img").css("background-position", "");
  122. }
  123. if (typeof desc !== typeof undefined && desc !== false) {
  124. // Check for Markdown link
  125. var mdLinkRe = /\[(.*?)\]\((.+?)\)/;
  126. if (desc.match(mdLinkRe)) {
  127. // Split desc into parts, extracting md links
  128. var splitDesc = desc.split(mdLinkRe);
  129. // Build new description
  130. var imageDesc = $(".img-desc");
  131. splitDesc.forEach(function (element, index){
  132. // Check element type. If links every 2nd element is link text, and every 3rd link url
  133. if (index % 3 === 0) {
  134. // Regular text, just append it
  135. imageDesc.append(element);
  136. }
  137. if (index % 3 === 1) {
  138. // Link text - do nothing at the moment
  139. }
  140. if (index % 3 === 2) {
  141. // Link url - Create anchor tag with text
  142. var link = $("<a>", {
  143. "href": element,
  144. "target": "_blank",
  145. "rel": "noopener noreferrer"
  146. }).text(splitDesc[index - 1]);
  147. imageDesc.append(link);
  148. }
  149. });
  150. imageDesc.show();
  151. } else {
  152. $(".img-desc").text(desc).show();
  153. }
  154. } else {
  155. $(".img-desc").hide();
  156. }
  157. }
  158. };
  159. // 2fc73a3a967e97599c9763d05e564189
  160. document.addEventListener('DOMContentLoaded', main.init);
  161. /**
  162. * Add copy button to code block
  163. */
  164. document.addEventListener('DOMContentLoaded', () => {
  165. const highlights = document.querySelectorAll('.row div.highlight');
  166. const copyText = '📋';
  167. const copiedText = '✔️';
  168. highlights.forEach((highlight) => {
  169. const copyButton = document.createElement('button');
  170. copyButton.innerHTML = copyText;
  171. copyButton.classList.add('copyCodeButton');
  172. highlight.appendChild(copyButton);
  173. const codeBlock = highlight.querySelector('code[data-lang]');
  174. if (!codeBlock) return;
  175. copyButton.addEventListener('click', () => {
  176. // Create a deep clone of the code block
  177. const codeBlockClone = codeBlock.cloneNode(true);
  178. // Remove line number elements from the clone
  179. const lineNumbers = codeBlockClone.querySelectorAll('.ln');
  180. lineNumbers.forEach(ln => ln.remove());
  181. // Get the text content, splitting by lines, trimming each line, and joining back
  182. const codeText = codeBlockClone.textContent
  183. .split('\n') // Split into lines
  184. .map(line => line.trim()) // Trim each line
  185. .join('\n'); // Join lines back with newline
  186. navigator.clipboard.writeText(codeText)
  187. .then(() => {
  188. copyButton.textContent = copiedText;
  189. setTimeout(() => {
  190. copyButton.textContent = copyText;
  191. }, 1000);
  192. })
  193. .catch((err) => {
  194. alert('Failed to copy text');
  195. console.error('Something went wrong', err);
  196. });
  197. });
  198. });
  199. });