PageSourceSearch

https://parkminkyu.github.io/assets/js/main.js

js parkminkyu.github.io collected 2026-10-03 09:44:30 UTC 4,059 bytes, 116 lines download raw bytes

1(function () {
2  'use strict';
3
4  // -----------------------------
5  // Theme toggle
6  // -----------------------------
7  var root = document.documentElement;
8  var themeBtn = document.getElementById('theme-toggle');
9  if (themeBtn) {
10    themeBtn.addEventListener('click', function () {
11      var current = root.getAttribute('data-theme') === 'dark' ? 'dark' : 'light';
12      var next = current === 'dark' ? 'light' : 'dark';
13      root.setAttribute('data-theme', next);
14      try { localStorage.setItem('theme', next); } catch (e) {}
15    });
16  }
17
18  // -----------------------------
19  // Mobile menu
20  // -----------------------------
21  var menuBtn = document.getElementById('menu-toggle');
22  var mobileMenu = document.getElementById('mobile-menu');
23  if (menuBtn && mobileMenu) {
24    menuBtn.addEventListener('click', function () {
25      var open = mobileMenu.classList.toggle('open');
26      mobileMenu.hidden = !open;
27      menuBtn.setAttribute('aria-expanded', open ? 'true' : 'false');
28    });
29  }
30
31  // -----------------------------
32  // Search panel
33  // -----------------------------
34  var searchBtn = document.getElementById('search-toggle');
35  var searchPanel = document.getElementById('search-panel');
36  var searchClose = document.getElementById('search-close');
37  var searchInput = document.getElementById('lunr-input');
38
39  function openSearch() {
40    if (!searchPanel) return;
41    searchPanel.hidden = false;
42    if (searchInput) setTimeout(function () { searchInput.focus(); }, 50);
43  }
44  function closeSearch() {
45    if (!searchPanel) return;
46    searchPanel.hidden = true;
47  }
48  if (searchBtn) searchBtn.addEventListener('click', openSearch);
49  if (searchClose) searchClose.addEventListener('click', closeSearch);
50  document.addEventListener('keydown', function (e) {
51    if (e.key === '/' && document.activeElement && document.activeElement.tagName !== 'INPUT' && document.activeElement.tagName !== 'TEXTAREA') {
52      e.preventDefault();
53      openSearch();
54    } else if (e.key === 'Escape' && searchPanel && !searchPanel.hidden) {
55      closeSearch();
56    }
57  });
58
59  // -----------------------------
60  // Reading progress on post pages
61  // -----------------------------
62  var progressEl = document.getElementById('reading-progress');
63  if (progressEl) {
64    var ticking = false;
65    var update = function () {
66      var doc = document.documentElement;
67      var body = document.body;
68      var scrollTop = window.pageYOffset || doc.scrollTop || body.scrollTop || 0;
69      var docHeight = Math.max(
70        body.scrollHeight, doc.scrollHeight,
71        body.offsetHeight, doc.offsetHeight
72      );
73      var winHeight = window.innerHeight || doc.clientHeight;
74      var trackable = docHeight - winHeight;
75      var pct = trackable > 0 ? (scrollTop / trackable) * 100 : 0;
76      if (pct < 0) pct = 0;
77      if (pct > 100) pct = 100;
78      progressEl.style.width = pct + '%';
79      ticking = false;
80    };
81    var onScroll = function () {
82      if (!ticking) {
83        window.requestAnimationFrame(update);
84        ticking = true;
85      }
86    };
87    window.addEventListener('scroll', onScroll, { passive: true });
88    window.addEventListener('resize', onScroll);
89    update();
90  }
91
92  // -----------------------------
93  // Disqus lazy load on click
94  // -----------------------------
95  document.querySelectorAll('.show-comments').forEach(function (btn) {
96    btn.addEventListener('click', function () {
97      var c = document.getElementById('comments');
98      if (c) c.style.display = 'block';
99      btn.style.display = 'none';
100    });
101  });
102
103  // -----------------------------
104  // Smooth scroll for in-page anchors
105  // -----------------------------
106  document.querySelectorAll('a[href^="#"]').forEach(function (link) {
107    link.addEventListener('click', function (e) {
108      var href = link.getAttribute('href');
109      if (href.length <= 1) return;
110      var target = document.querySelector(href);
111      if (!target) return;
112      e.preventDefault();
113      target.scrollIntoView({ behavior: 'smooth', block: 'start' });
114    });
115  });
116})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.