Error getting theme setting: TypeError: Cannot read properties of undefined (reading 'transaction'). Error loading novels: TypeError: Cannot read properties of undefined (reading 'transaction'). Error initializing application: [object DOMException]. send the fully working full code.

'use strict';
    (async function() {

      /**
       * IndexedDB Utilities
       */
      let db;
      const DB_VERSION = 2;

      const openDatabase = () => {
        return new Promise((resolve, reject) => {
          const request = indexedDB.open('MonochrmeNovelsDB', DB_VERSION);

          request.onupgradeneeded = function(event) {
            const db = event.target.result;
            if (event.oldVersion < 1) {
              // Initial creation of object stores
              const novelsStore = db.createObjectStore('novels', { keyPath: 'id', autoIncrement: true });
              novelsStore.createIndex('name', 'name', { unique: true });
              novelsStore.createIndex('nameLower', 'nameLower', { unique: false });
              novelsStore.createIndex('coverUrl', 'coverUrl', { unique: true });
              novelsStore.createIndex('pdfUrl', 'pdfUrl', { unique: true });
              novelsStore.createIndex('timestamp', 'timestamp', { unique: false });

              const settingsStore = db.createObjectStore('settings', { keyPath: 'key' });

            } else if (event.oldVersion < 2) {
              // Upgrade logic for version 2
              const transaction = event.target.transaction;
              const novelsStore = transaction.objectStore('novels');
              // Add a new index or make changes as needed
              if (!novelsStore.indexNames.contains('nameLower')) {
                novelsStore.createIndex('nameLower', 'nameLower', { unique: false });
              }
            }
            // Future upgrades can be handled here
          };

          request.onsuccess = function(event) {
            db = event.target.result;
            resolve(db);
          };

          request.onerror = function(event) {
            reject(event.target.error);
          };
        });
      };

      const countNovels = () => {
        return new Promise((resolve, reject) => {
          const transaction = db.transaction('novels', 'readonly');
          const store = transaction.objectStore('novels');
          const countRequest = store.count();
          countRequest.onsuccess = function() {
            resolve(countRequest.result);
          };
          countRequest.onerror = function() {
            reject(countRequest.error);
          };
        });
      };

      const getAllNovels = () => {
        return new Promise((resolve, reject) => {
          const transaction = db.transaction('novels', 'readonly');
          const store = transaction.objectStore('novels');
          const getAllRequest = store.getAll();
          getAllRequest.onsuccess = function() {
            resolve(getAllRequest.result);
          };
          getAllRequest.onerror = function(event) {
            reject(event.target.error);
          };
        });
      };

      const getNovels = (offset, limit) => {
        return new Promise((resolve, reject) => {
          const transaction = db.transaction('novels', 'readonly');
          const store = transaction.objectStore('novels');
          const index = store.index('name');

          const result = [];
          let advanced = false;
          index.openCursor().onsuccess = function(event) {
            const cursor = event.target.result;
            if (cursor) {
              if (!advanced && offset > 0) {
                advanced = true;
                cursor.advance(offset);
                return;
              }
              result.push(cursor.value);
              if (result.length < limit) {
                cursor.continue();
              } else {
                resolve(result);
              }
            } else {
              resolve(result);
            }
          };
          index.openCursor().onerror = function(event) {
            reject(event.target.error);
          };
        });
      };

      const getNovelsByNameIncludes = (searchTerm, offset, limit) => {
        return new Promise((resolve, reject) => {
          const transaction = db.transaction('novels', 'readonly');
          const store = transaction.objectStore('novels');
          const index = store.index('nameLower');

          const lowerSearchTerm = searchTerm.toLowerCase();
          const result = [];
          index.openCursor().onsuccess = function(event) {
            const cursor = event.target.result;
            if (cursor) {
              if (cursor.value.nameLower.includes(lowerSearchTerm)) {
                if (offset > 0) {
                  offset--;
                } else {
                  result.push(cursor.value);
                }
              }
              if (result.length < limit) {
                cursor.continue();
              } else {
                resolve(result);
              }
            } else {
              resolve(result);
            }
          };
          index.openCursor().onerror = function(event) {
            reject(event.target.error);
          };
        });
      };

      const bulkAddNovels = (novels) => {
        return new Promise((resolve, reject) => {
          const transaction = db.transaction('novels', 'readwrite');
          const store = transaction.objectStore('novels');

          const promises = novels.map((novel) => {
            return new Promise((res, rej) => {
              const request = store.put(novel);
              request.onsuccess = function() {
                res();
              };
              request.onerror = function(event) {
                console.error('Failed to add novel:', novel.name, event.target.error);
                res(); // Resolve even on error to continue
              };
            });
          });

          Promise.allSettled(promises).then(() => {
            resolve();
          }).catch((error) => {
            reject(error);
          });
        });
      };

      const clearNovels = () => {
        return new Promise((resolve, reject) => {
          const transaction = db.transaction('novels', 'readwrite');
          const store = transaction.objectStore('novels');
          const clearRequest = store.clear();
          clearRequest.onsuccess = function() {
            resolve();
          };
          clearRequest.onerror = function(event) {
            reject(event.target.error);
          };
        });
      };

      const getSetting = (key) => {
        return new Promise((resolve, reject) => {
          const transaction = db.transaction('settings', 'readonly');
          const store = transaction.objectStore('settings');
          const getRequest = store.get(key);
          getRequest.onsuccess = function() {
            resolve(getRequest.result ? getRequest.result.value : null);
          };
          getRequest.onerror = function(event) {
            reject(event.target.error);
          };
        });
      };

      const putSetting = (key, value) => {
        return new Promise((resolve, reject) => {
          const transaction = db.transaction('settings', 'readwrite');
          const store = transaction.objectStore('settings');
          const putRequest = store.put({ key: key, value: value });
          putRequest.onsuccess = function() {
            resolve();
          };
          putRequest.onerror = function(event) {
            reject(event.target.error);
          };
        });
      };

      /**
       * Constants and Variables
       */
      const PAGE_SIZE = 20;
      let currentPage = 0;
      let isLoading = false;
      let hasMore = true;
      let currentSearchTerm = '';

      const PLACEHOLDER_IMAGE = 'https://via.placeholder.com/500x700?text=No+Image';

      /**
       * Debounce Function to Limit Function Execution Rate
       * @param {Function} func
       * @param {number} delay
       * @returns {Function}
       */
      const debounce = (func, delay) => {
        let debounceTimer;
        return function(...args) {
          const context = this;
          clearTimeout(debounceTimer);
          debounceTimer = setTimeout(() => func.apply(context, args), delay);
        }
      };

      /**
       * Utility: Delay Function
       * @param {number} ms
       * @returns {Promise}
       */
      const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

      /**
       * Utility: Retry Operation with Exponential Backoff (3 Attempts)
       * @param {Function} operation
       * @param {number} attempts
       * @param {number} delayDuration
       * @returns {Promise}
       */
      const retryOperation = async (operation, attempts = 3, delayDuration = 1500) => {
        for (let i = 0; i < attempts; i++) {
          try {
            return await operation();
          } catch (error) {
            if (i === attempts - 1) throw error;
            await delay(delayDuration * Math.pow(2, i)); // Exponential backoff
          }
        }
      };

      /**
       * Initialize Intersection Observer for Infinite Scroll using Sentinel Element
       */
      const setupSentinelObserver = () => {
        const sentinel = document.getElementById('sentinel');
        if (!('IntersectionObserver' in window)) {
          // Fallback if IntersectionObserver is not supported
          window.addEventListener('scroll', onScrollLoadNextPage);
          return;
        }

        const sentinelObserver = new IntersectionObserver((entries) => {
          entries.forEach(entry => {
            if (entry.isIntersecting && hasMore && !isLoading) {
              loadNextPageWrapper();
            }
          });
        }, {
          rootMargin: '100px',
          threshold: 0
        });
        sentinelObserver.observe(sentinel);
      };

      // Fallback function for scroll event
      let scrollTimeout;
      const onScrollLoadNextPage = () => {
        if (scrollTimeout) {
          clearTimeout(scrollTimeout);
        }
        scrollTimeout = setTimeout(() => {
          if (window.scrollY + window.innerHeight >= document.body.scrollHeight - 100 && hasMore && !isLoading) {
            loadNextPageWrapper();
          }
        }, 200);
      };

      /**
       * Load Next Page Wrapper to prevent concurrent invocations
       */
      let loadNextPageQueue = Promise.resolve();
      const loadNextPageWrapper = () => {
        loadNextPageQueue = loadNextPageQueue.then(() => loadNextPage());
      };

      /**
       * Load Next Page of Novels from IndexedDB
       */
      const loadNextPage = async () => {
        if (isLoading) return; // Prevent multiple simultaneous loads
        isLoading = true;
        showLoader();

        try {
          let novels;

          if (currentSearchTerm === '') {
            novels = await getNovels(currentPage * PAGE_SIZE, PAGE_SIZE);
          } else {
            novels = await getNovelsByNameIncludes(currentSearchTerm, currentPage * PAGE_SIZE, PAGE_SIZE);
          }

          if (novels.length < PAGE_SIZE) {
            hasMore = false; // No more novels to load
          }

          if (novels.length > 0) {
            appendNovelsToDisplay(novels);
            currentPage++;
          } else {
            if (currentPage === 0) {
              showTemporaryError('No novels found for the given search term.', 5000);
            }
          }

          // Edge case: Load more if content doesn't fill viewport
          if (document.body.scrollHeight <= window.innerHeight && hasMore && !isLoading) {
            loadNextPageWrapper();
          }

        } catch (error) {
          console.error('Error loading novels:', error);
          showTemporaryError('An error occurred while loading novels.', 5000);
        } finally {
          hideLoader();
          isLoading = false;
        }
      };

      /**
       * Show Loader
       */
      const showLoader = () => {
        document.getElementById('loader').classList.add('visible');
      };

      /**
       * Hide Loader
       */
      const hideLoader = () => {
        document.getElementById('loader').classList.remove('visible');
      };

      /**
       * Display Error Message Temporarily
       * @param {string} message
       * @param {number} duration - Duration in milliseconds
       */
      const showTemporaryError = (message, duration = 5000) => {
        const content = document.getElementById('content');
        // Remove existing error messages
        const existingErrors = content.querySelectorAll('.error-message');
        existingErrors.forEach(error => error.remove());

        const errorDiv = document.createElement('div');
        errorDiv.className = 'error-message';
        errorDiv.setAttribute('role', 'alert');
        errorDiv.textContent = message;

        content.prepend(errorDiv);

        // Fade out after specified duration
        setTimeout(() => {
          errorDiv.classList.add('fade-out');
          // Remove from DOM after fade-out transition
          setTimeout(() => {
            errorDiv.remove();
          }, 500);
        }, duration);
      };

      /**
       * Append Novels to Display
       * @param {Array} novels
       */
      const appendNovelsToDisplay = novels => {
        const content = document.getElementById('content');
        const fragment = document.createDocumentFragment();

        novels.forEach(novel => {
          const card = createNovelCard(novel);
          fragment.appendChild(card);
        });

        content.appendChild(fragment);
        if (window.AOS) {
          AOS.refresh();
        }

        // Lazy load images
        lazyLoadImages();
      };

      /**
       * Create Novel Card Element
       * @param {Object} novel
       * @returns {HTMLElement}
       */
      const createNovelCard = (novel) => {
        const card = document.createElement('div');
        card.className = 'card';
        card.setAttribute('tabindex', '0');
        card.setAttribute('role', 'button');
        card.setAttribute('aria-labelledby', `novel-title-${encodeURIComponent(novel.name)}`);
        card.setAttribute('data-aos', 'fade-up');

        const imageContainer = document.createElement('div');
        imageContainer.className = 'card__image-container';

        const image = document.createElement('img');
        image.className = 'card__image';
        image.dataset.src = novel.coverUrl || PLACEHOLDER_IMAGE;
        image.alt = `Cover of ${novel.name}`;
        image.loading = 'lazy';
        image.onerror = function() {
          this.src = PLACEHOLDER_IMAGE;
        };

        imageContainer.appendChild(image);
        card.appendChild(imageContainer);

        const content = document.createElement('div');
        content.className = 'card__content';

        const title = document.createElement('h2');
        title.id = `novel-title-${encodeURIComponent(novel.name)}`;
        title.className = 'card__title';
        title.textContent = novel.name;

        content.appendChild(title);
        card.appendChild(content);

        // Event Listener to Open Modal
        const openModalEvent = (e) => {
          if (e.type === 'click' || (e.type === 'keypress' && (e.key === 'Enter' || e.key === ' '))) {
            e.preventDefault();
            showModal(novel);
          }
        };

        card.addEventListener('click', openModalEvent);
        card.addEventListener('keypress', openModalEvent);

        return card;
      };

      /**
       * Lazy Load Images using Intersection Observer
       */
      const lazyLoadImages = () => {
        const images = document.querySelectorAll('img[data-src]');
        const config = {
          rootMargin: '50px 0px',
          threshold: 0.01
        };

        let observer;
        if ('IntersectionObserver' in window) {
          observer = new IntersectionObserver((entries, self) => {
            entries.forEach(entry => {
              if (entry.isIntersecting) {
                preloadImage(entry.target);
                self.unobserve(entry.target);
              }
            });
          }, config);

          images.forEach(image => {
            observer.observe(image);
          });
        } else {
          // Fallback for browsers without IntersectionObserver support
          images.forEach(image => {
            preloadImage(image);
          });
        }
      };

      const preloadImage = (img) => {
        img.src = img.dataset.src;
        img.onload = () => {
          img.removeAttribute('data-src');
        };
      };

      /**
       * Utility: Escape HTML to Prevent XSS
       * @param {string} str
       * @returns {string}
       */
      const escapeHTML = (str) => {
        if (!str) return '';
        return str.replace(/&/g, "&amp;")
                  .replace(/</g, "&lt;")
                  .replace(/>/g, "&gt;")
                  .replace(/"/g, "&quot;")
                  .replace(/'/g, "&#039;");
      };

      /**
       * Modal Functionality
       */
      const modal = document.getElementById('modal');
      const modalTitle = document.getElementById('modal-title');
      const modalLink = document.getElementById('modal-link');
      const closeBtn = document.querySelector('.close');

      /**
       * Show Modal with Novel Details
       * @param {Object} novel
       */
      const showModal = (novel) => {
        modalTitle.textContent = novel.name;
        modalLink.setAttribute('href', novel.pdfUrl);
        modal.classList.add('show');
        modal.setAttribute('aria-hidden', 'false');
        document.body.style.overflow = 'hidden'; // Prevent background scrolling
        closeBtn.focus(); // Focus on close button for accessibility

        // Trap focus inside modal
        document.addEventListener('focus', trapFocus, true);
      };

      /**
       * Close Modal
       */
      const closeModal = () => {
        modal.classList.remove('show');
        modal.setAttribute('aria-hidden', 'true');
        document.body.style.overflow = 'auto';

        // Remove focus trap
        document.removeEventListener('focus', trapFocus, true);
      };

      const trapFocus = (event) => {
        if (!modal.contains(event.target)) {
          event.stopPropagation();
          closeBtn.focus();
        }
      };

      closeBtn.addEventListener('click', closeModal);

      window.addEventListener('click', (event) => {
        if (event.target === modal) {
          closeModal();
        }
      });

      window.addEventListener('keydown', (event) => {
        if (event.key === 'Escape' && modal.classList.contains('show')) {
          closeModal();
        }
      });

      /**
       * Search Functionality
       */
      const searchInput = document.getElementById('search-input');

      const handleSearch = debounce(async () => {
        currentSearchTerm = searchInput.value.trim();
        currentPage = 0;
        hasMore = true;

        const content = document.getElementById('content');
        content.innerHTML = ''; // Clear existing content

        // Reload the first page with the new search term
        await loadNextPage();
      }, 300); // 300ms debounce delay

      searchInput.addEventListener('input', handleSearch);

      /**
       * Refresh Data Functionality
       */
      const refreshButton = document.getElementById('refresh-button');
      refreshButton.addEventListener('click', async () => {
        showConfirmationModal('Are you sure you want to refresh the data? This may take a few moments.', async () => {
          isLoading = true;
          showLoader();
          hasMore = true;
          currentPage = 0;
          refreshButton.disabled = true;

          try {
            // Clear existing data
            await clearNovels();

            // Fetch and parse fresh data
            await fetchAndStoreNovels();

            // Reload the first page of novels
            document.getElementById('content').innerHTML = ''; // Clear existing content

            await loadNextPage();

            // Show success toast
            showToast('Data refreshed successfully!', 'success');
          } catch (error) {
            console.error('Error refreshing data:', error);
            showTemporaryError('Failed to refresh data. Please try again later.', 5000);
            // Show error toast
            showToast('Failed to refresh data.', 'error');
          } finally {
            hideLoader();
            isLoading = false;
            refreshButton.disabled = false;
          }
        });
      });

      /**
       * Show Confirmation Modal
       * @param {string} message
       * @param {Function} onConfirm
       */
      const showConfirmationModal = (message, onConfirm) => {
        const confirmationModal = document.createElement('div');
        confirmationModal.className = 'modal';
        confirmationModal.setAttribute('role', 'dialog');
        confirmationModal.setAttribute('aria-modal', 'true');

        const modalContent = document.createElement('div');
        modalContent.className = 'modal-content';

        const modalMessage = document.createElement('p');
        modalMessage.textContent = message;

        const modalButtons = document.createElement('div');
        modalButtons.className = 'modal-buttons';

        const confirmButton = document.createElement('button');
        confirmButton.textContent = 'Confirm';
        confirmButton.className = 'button confirm-button';

        const cancelButton = document.createElement('button');
        cancelButton.textContent = 'Cancel';
        cancelButton.className = 'button cancel-button';

        modalButtons.appendChild(confirmButton);
        modalButtons.appendChild(cancelButton);

        modalContent.appendChild(modalMessage);
        modalContent.appendChild(modalButtons);
        confirmationModal.appendChild(modalContent);
        document.body.appendChild(confirmationModal);
        document.body.style.overflow = 'hidden';

        confirmButton.focus();

        const closeConfirmationModal = () => {
          confirmationModal.remove();
          document.body.style.overflow = 'auto';
        };

        confirmButton.addEventListener('click', () => {
          closeConfirmationModal();
          onConfirm();
        });

        cancelButton.addEventListener('click', closeConfirmationModal);

        window.addEventListener('keydown', (event) => {
          if (event.key === 'Escape') {
            closeConfirmationModal();
          }
        });

        window.addEventListener('click', (event) => {
          if (event.target === confirmationModal) {
            closeConfirmationModal();
          }
        });
      };

      /**
       * Initialize Application
       */
      const initializeApp = async () => {
        try {
          // Open the database
          await openDatabase();

          // Check if any novels are already stored in IndexedDB
          const count = await countNovels();
          if (count === 0) {
            // Fetch and store data from the external website
            await fetchAndStoreNovels();
          } else {
            // Validate existing data
            const novels = await getAllNovels();
            if (!validateNovels(novels)) {
              await clearNovels();
              await fetchAndStoreNovels();
            }
          }

          // Load the first page of novels
          await loadNextPage();

          // Edge case: Load more if content doesn't fill viewport
          if (document.body.scrollHeight <= window.innerHeight && hasMore && !isLoading) {
            loadNextPageWrapper();
          }
        } catch (error) {
          console.error('Error initializing application:', error);
          showTemporaryError('Failed to load novels. Please try refreshing the page.', 5000);
          // Show error toast
          showToast('Failed to load novels.', 'error');
        }
      };

      /**
       * Fetch and Store Novels
       */
      const fetchAndStoreNovels = async () => {
        try {
          const html = await retryOperation(() => fetchHTML('https://jnovels.com/top-light-novels-to-read/'));
          let novels = parseHTML(html);

          if (novels.length === 0) {
            throw new Error('No novels found on the target page.');
          }

          showProgress();
          updateProgress(0);

          // Bulk upsert novels to IndexedDB
          const novelsToAdd = novels.map((novel, index) => {
            const escapedName = escapeHTML(novel.name);
            const escapedCoverUrl = escapeHTML(novel.coverUrl);
            const escapedPdfUrl = escapeHTML(novel.pdfUrl);
            return {
              id: index,
              name: escapedName,
              nameLower: escapedName.toLowerCase(),
              coverUrl: escapedCoverUrl,
              pdfUrl: escapedPdfUrl,
              timestamp: Date.now()
            };
          });

          await bulkAddNovelsWithProgress(novelsToAdd, (progress) => {
            updateProgress(progress);
          });

          console.log('Novels fetched and stored successfully:', novelsToAdd.length);

          // Show success toast
          showToast('Novels fetched and stored successfully.', 'success');

        } catch (error) {
          console.error('Error fetching or storing novels:', error);
          showTemporaryError('Failed to fetch and store novels. Please try again later.', 5000);
          // Show error toast
          showToast('Failed to fetch and store novels.', 'error');
        } finally {
          hideProgress();
        }
      };

      const bulkAddNovelsWithProgress = async (novels, progressCallback) => {
        const total = novels.length;
        let completed = 0;

        return new Promise((resolve, reject) => {
          const transaction = db.transaction('novels', 'readwrite');
          const store = transaction.objectStore('novels');

          transaction.oncomplete = function() {
            resolve();
          };

          transaction.onerror = function(event) {
            reject(event.target.error);
          };

          novels.forEach((novel) => {
            const request = store.put(novel);
            request.onsuccess = function() {
              completed++;
              const progress = (completed / total) * 100;
              progressCallback(progress);
            };
            request.onerror = function(event) {
              console.error('Failed to add novel:', novel.name, event.target.error);
              completed++;
              const progress = (completed / total) * 100;
              progressCallback(progress);
            };
          });
        });
      };

      /**
       * Fetch HTML Content from the URL
       * @param {string} url
       * @returns {Promise<string>}
       */
      const fetchHTML = async (url) => {
        try {
          const response = await fetch(url, { cache: 'no-cache' });

          if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
          }

          const htmlContent = await response.text();

          if (!htmlContent || typeof htmlContent !== 'string') {
            throw new Error('Fetched content is invalid or empty.');
          }

          return htmlContent;
        } catch (error) {
          console.error('Error fetching HTML:', error);
          throw error; // Re-throw to be handled by caller
        }
      };

      /**
       * Parse Fetched HTML to Extract Novel Data
       * @param {string} html
       * @returns {Array<Object>}
       */
      const parseHTML = (html) => {
        const parser = new DOMParser();
        const doc = parser.parseFromString(html, 'text/html');
        const novels = [];
        const uniqueNovels = new Set();

        // Select all h3 tags as they contain the novel names and links
        const h3Elements = doc.querySelectorAll('h3');

        h3Elements.forEach((h3Element) => {
          try {
            const aTag = h3Element.querySelector('a');
            const spanTag = h3Element.querySelector('span');

            if (!aTag || !spanTag) return; // Skip if either tag is missing

            const name = spanTag.textContent.trim();
            const pdfLink = aTag.getAttribute('href').trim();

            // The cover image is inside the following p tag
            let pElement = h3Element.nextElementSibling;
            while (pElement && pElement.tagName.toLowerCase() !== 'p') {
              pElement = pElement.nextElementSibling;
            }
            if (!pElement) return; // Skip if p tag is missing

            const imgTag = pElement.querySelector('img');
            if (!imgTag) return; // Skip if img tag is missing

            let coverUrl = imgTag.getAttribute('src') || imgTag.getAttribute('data-src');
            if (!coverUrl) return; // Skip if cover URL is missing

            // Handle different URL formats
            if (coverUrl.startsWith('//')) {
              coverUrl = `https:${coverUrl}`;
            } else if (coverUrl.startsWith('/')) {
              coverUrl = `https://jnovels.com${coverUrl}`;
            } else if (!coverUrl.startsWith('http')) {
              // Handle relative URLs without leading '/'
              coverUrl = `https://jnovels.com/${coverUrl}`;
            }

            // Validate extracted data
            if (name && pdfLink && coverUrl) {
              const novelKey = `${name}-${coverUrl}-${pdfLink}`;
              if (!uniqueNovels.has(novelKey)) {
                uniqueNovels.add(novelKey);
                novels.push({
                  name,
                  coverUrl,
                  pdfUrl: pdfLink
                });
              }
            } else {
              console.warn('Incomplete novel data found and skipped:', { name, pdfLink, coverUrl });
            }
          } catch (error) {
            // Skip any malformed entries
            console.error('Error parsing a novel entry:', error);
          }
        });

        return novels;
      };

      /**
       * Update Progress Bar
       * @param {number} percentage
       */
      const updateProgress = (percentage) => {
        document.getElementById('progress-bar').style.width = `${percentage}%`;
        document.getElementById('progress-text').textContent = `${Math.round(percentage)}%`;
      };

      /**
       * Show Progress Bar and Text
       */
      const showProgress = () => {
        document.getElementById('progress-container').style.display = 'block';
        document.getElementById('progress-text').style.display = 'block';
      };

      /**
       * Hide Progress Bar and Text
       */
      const hideProgress = () => {
        document.getElementById('progress-container').style.display = 'none';
        document.getElementById('progress-text').style.display = 'none';
      };

      /**
       * Validate Novels
       * @param {Array<Object>} novels
       * @returns {boolean}
       */
      const validateNovels = (novels) => {
        for (const novel of novels) {
          if (!novel.name || !novel.coverUrl || !novel.pdfUrl || !novel.timestamp) {
            return false;
          }
        }
        return true;
      };

      /**
       * Toast Notification Functionality
       */
      const showToast = (message, type = 'success') => {
        const toastContainer = document.getElementById('toast-container');
        const toast = document.createElement('div');
        toast.className = `toast ${type}`;

        let iconSVG = '';

        if (type === 'success') {
          iconSVG = `
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
              <path d="M20.285,6.708l-11.7,11.7l-5.566-5.566c-0.391-0.391-1.023-0.391-1.414,0s-0.391,1.023,0,1.414l6.28,6.28
              c0.391,0.391,1.023,0.391,1.414,0l12.544-12.544C20.676,7.731,20.676,7.1,20.285,6.708z"/>
            </svg>
          `;
        } else if (type === 'error') {
          iconSVG = `
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
              <path d="M12,0C5.373,0,0,5.373,0,12s5-12,12-12S5.373,0,12,0z M16.242,16.242
              c0.391,0.391,0.391,1.023,0,1.414c-0.391,0.391-1,0.391-1.414,0L12,13.414l-2.828,2.828c-0.391,0.391-1,0.391-1.414,0
              c-0.391-0.391-0.391-1,0-1.414L10.586,12l-2.828-2.828c-0.391-0.391-0.391-1,0-1.414s1-0.391,1.414,0L12,10.586
              l2.828-2.828c0.391-0.391,1-0.391,1.414,0s0.391,1,0,1.414L13.414,12l2.828,2.828C16.633,15.219,16.633,15.851,16.242,16.242z"/>
            </svg>
          `;
        }

        toast.innerHTML = `${iconSVG} ${message}`;
        toast.classList.add('show');
        toastContainer.appendChild(toast);

        // Remove toast after 5 seconds
        setTimeout(() => {
          toast.classList.remove('show');
          setTimeout(() => {
            toast.remove();
          }, 500);
        }, 5000);
      };

      /**
       * Initialize Theme Toggle
       */
      const initializeTheme = async () => {
        const themeToggle = document.getElementById('theme-toggle');
        let currentTheme;
        try {
          currentTheme = await getSetting('theme') || 'dark';
        } catch (error) {
          console.error('Error getting theme setting:', error);
          currentTheme = 'dark';
        }

        if (currentTheme === 'light') {
          document.body.setAttribute('data-theme', 'light');
          themeToggle.checked = true;
        } else {
          document.body.setAttribute('data-theme', 'dark');
          themeToggle.checked = false;
        }

        themeToggle.addEventListener('change', async () => {
          const newTheme = themeToggle.checked ? 'light' : 'dark';
          document.body.setAttribute('data-theme', newTheme);
          try {
            await putSetting('theme', newTheme);
          } catch (error) {
            console.error('Error saving theme setting:', error);
          }
        });
      };

      /**
       * Initialize Menu Button and Menu
       */
      const initializeMenu = () => {
        const menuButton = document.getElementById('menu-button');
        const menu = document.getElementById('menu');
        const settingsPanel = document.getElementById('settings-panel');
        const settingsPanelClose = document.querySelector('.settings-panel__close');

        menuButton.addEventListener('click', () => {
          menu.classList.toggle('open');
          if (menu.classList.contains('open')) {
            document.body.style.overflow = 'hidden';
          } else {
            document.body.style.overflow = 'auto';
          }
        });

        const menuItems = menu.querySelectorAll('.menu__item');
        menuItems.forEach(menuItem => {
          menuItem.addEventListener('click', async (e) => {
            const target = e.target.getAttribute('data-target');
            if (target === 'home') {
              // Redirect to the first page where all novels are displayed
              currentSearchTerm = '';
              currentPage = 0;
              hasMore = true;
              document.getElementById('content').innerHTML = '';
              await loadNextPage();
            } else if (target === 'settings') {
              settingsPanel.classList.add('open');
              document.body.style.overflow = 'hidden';
            }
            menu.classList.remove('open');
            document.body.style.overflow = 'auto';
          });
        });

        settingsPanelClose.addEventListener('click', () => {
          settingsPanel.classList.remove('open');
          document.body.style.overflow = 'auto';
        });

        window.addEventListener('click', (event) => {
          if (event.target === settingsPanel) {
            settingsPanel.classList.remove('open');
            document.body.style.overflow = 'auto';
          }
        });

        window.addEventListener('keydown', (event) => {
          if (event.key === 'Escape' && settingsPanel.classList.contains('open')) {
            settingsPanel.classList.remove('open');
            document.body.style.overflow = 'auto';
          }
        });
      };

      /**
       * Initialize AOS and Start the Application once the DOM is fully loaded
       */
      document.addEventListener('DOMContentLoaded', () => {
        // Initialize AOS if available
        if (window.AOS) {
          AOS.init({
            duration: 800,
            easing: 'ease-in-out',
            once: true,
          });
        }

        setupSentinelObserver();
        initializeTheme();
        initializeMenu();
        initializeApp();
      });

    })();