Make this more robust, visually appealing, fast, reliable, effective, efficient, modern, smooth.

Improve and refine this further.

Don't forget to focus on ui improvements too.

Use dexie and save the extracted data only.

Don't compromise.

Use the full potential of dexie.

After the data( not html content ) is stored successfully in the db, For future sessions use only the data from the db as the source if it's not corrupt or incomplete.

Find and all of those edge cases, bottlenecks, memory leaks, resources consumption, errors.

Send the fully working full codes in one html file.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Light Novels Gallery</title>
    <!-- Dexie.js CDN -->
    <script src="https://cdn.jsdelivr.net/npm/dexie@3.2.2/dist/dexie.min.js"></script>
    <style>
        body {
            font-family: 'Arial', sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #0e0e0e; /* Dark background for modern look */
            color: #ffffff; /* White text for better contrast */
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        .section-title {
            text-align: center;
            font-size: 2em;
            margin: 20px 0;
            color: #ff9800; /* Vibrant color for titles */
            border-bottom: 2px solid #ff9800;
            padding-bottom: 10px;
            width: 80%;
        }

        .container {
            max-width: 1200px;
            width: 90%;
            margin: 0 auto;
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
            grid-gap: 30px;
        }

        .novel-card {
            background-color: #1e1e1e;
            border-radius: 8px;
            overflow: hidden;
            transition: transform 0.3s ease, box-shadow 0.3s ease;
            display: flex;
            flex-direction: column;
        }

        .novel-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3);
        }

        .novel-card img {
            width: 100%;
            height: auto;
            object-fit: cover;
            flex-shrink: 0;
        }

        .novel-content {
            padding: 15px;
            flex-grow: 1;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
        }

        .novel-title {
            color: #ff9800;
            text-decoration: none;
            font-size: 1.2em;
            margin: 10px 0;
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            overflow: hidden;
        }

        .post-meta {
            font-size: 0.9em;
            color: #bbb;
            margin-top: 5px;
        }

        .loading {
            text-align: center;
            font-size: 1.5em;
            padding: 20px;
            width: 80%;
            margin: 20px auto;
        }

        .download-links {
            margin-top: 10px;
            display: flex;
            flex-wrap: wrap;
            gap: 5px;
        }

        .download-link {
            background-color: #ff9800;
            color: white;
            padding: 5px 10px;
            border-radius: 4px;
            text-decoration: none;
            font-size: 0.9em;
            transition: background-color 0.2s ease-in-out;
        }

        .download-link:hover {
            background-color: #ffa733;
        }

        /* Scrollbar Styles */
        ::-webkit-scrollbar {
            width: 8px;
        }

        ::-webkit-scrollbar-track {
            background: #1e1e1e;
        }

        ::-webkit-scrollbar-thumb {
            background: #ff9800;
            border-radius: 4px;
        }

        /* Responsive Design */
        @media (max-width: 768px) {
            .container {
                grid-template-columns: 1fr;
            }
        }
    </style>
</head>
<body>
    <div id="loading" class="loading">Loading...</div>
    <h2 class="section-title">New Updates</h2>
    <div id="updates" class="container"></div>
    <h2 class="section-title">Popular Light Novels</h2>
    <div id="popular" class="container"></div>

    <script>
        // Initialize Dexie.js
        const db = new Dexie("LightNovelsDB");
        db.version(1).stores({
            updates: '++id,title,link,imageUrl,date,downloadLinks',
            popular: '++id,title,link,imageUrl'
        });

        const PROXY_URL = 'https://api.codetabs.com/v1/proxy?quest=';
        const UPDATES_URL = 'https://jnovels.com/0m-light-novels/?a=light-novels';
        const POPULAR_URL = 'https://jnovels.com/top-light-novels-to-read/';

        function parseUpdatePost(element) {
            const title = element.querySelector('.post-title a')?.textContent.trim() || '';
            const link = element.querySelector('.post-title a')?.href || '';
            const imageUrl = element.querySelector('.featured-media img')?.src || '';
            const date = element.querySelector('.post-date')?.textContent.trim() || '';
            const downloadLinks = Array.from(element.querySelectorAll('.post-content p a'))
                .filter(a => a.textContent.match(/VOLUME|PDF|Download/i))
                .map(a => ({ href: a.href, text: a.textContent.trim() }));

            return { title, link, imageUrl, date, downloadLinks };
        }

        function renderUpdates(updates) {
            const container = document.getElementById('updates');
            container.innerHTML = updates.map(update => `
                <div class="novel-card">
                    <a href="${update.link}" target="_blank" rel="noopener noreferrer">
                        <img src="${update.imageUrl}" alt="${update.title}" loading="lazy">
                    </a>
                    <div class="novel-content">
                        <a href="${update.link}" target="_blank" rel="noopener noreferrer" class="novel-title">${update.title}</a>
                        <div class="post-meta">${update.date}</div>
                        <div class="download-links">
                            ${update.downloadLinks.length > 0 ? update.downloadLinks.map(link =>
                                `<a href="${link.href}" target="_blank" rel="noopener noreferrer" class="download-link">${link.text}</a>`
                            ).join('') : '<span style="color:#bbb">No download links found</span>'}
                        </div>
                    </div>
                </div>
            `).join('');
        }

        function renderPopular(novels) {
            const container = document.getElementById('popular');
            container.innerHTML = novels.map(novel => `
                <div class="novel-card">
                    <a href="${novel.link}" target="_blank" rel="noopener noreferrer">
                        <img src="${novel.imageUrl}" alt="${novel.title}" loading="lazy">
                    </a>
                    <div class="novel-content">
                        <a href="${novel.link}" target="_blank" rel="noopener noreferrer" class="novel-title">${novel.title}</a>
                    </div>
                </div>
            `).join('');
        }

        async function fetchData(url) {
            try {
                const response = await fetch(PROXY_URL + encodeURIComponent(url), { cache: "no-store" });
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }
                return await response.text();
            } catch (error) {
                console.error('Fetch error:', error);
                return null;
            }
        }

        async function fetchAndParseData(url, isUpdates = false) {
            const html = await fetchData(url);
            if (!html) return [];

            const parser = new DOMParser();
            const doc = parser.parseFromString(html, 'text/html');

            if (isUpdates) {
                const posts = doc.querySelectorAll('article');
                return Array.from(posts).map(parseUpdatePost).filter(item => item.title);
            } else {
                const novelElements = doc.querySelectorAll('h3 a[href*="jnovels.com"]');
                return Array.from(novelElements).map(element => ({
                    title: element.textContent.trim(),
                    link: element.href,
                    imageUrl: element.closest('div').querySelector('img')?.src || ''
                })).filter(novel => novel.title && novel.link);
            }
        }

        async function loadData() {
            try {
                const [updatesCount, popularCount] = await Promise.all([
                    db.updates.count(),
                    db.popular.count()
                ]);

                if (updatesCount > 0 && popularCount > 0) {
                    const [updates, popular] = await Promise.all([
                        db.updates.toArray(),
                        db.popular.toArray()
                    ]);
                    renderUpdates(updates);
                    renderPopular(popular);
                    document.getElementById('loading').style.display = 'none';
                } else {
                    fetchAndStoreData();
                }
            } catch (error) {
                console.error('Error loading from DB:', error);
                fetchAndStoreData();
            }
        }

        async function fetchAndStoreData() {
            const loadingIndicator = document.getElementById('loading');

            try {
                const [updates, popular] = await Promise.all([
                    fetchAndParseData(UPDATES_URL, true),
                    fetchAndParseData(POPULAR_URL)
                ]);

                if (updates.length > 0) {
                    await db.updates.clear();
                    await db.updates.bulkAdd(updates);
                    renderUpdates(updates);
                }

                if (popular.length > 0) {
                    await db.popular.clear();
                    await db.popular.bulkAdd(popular);
                    renderPopular(popular);
                }

                loadingIndicator.style.display = 'none';

            } catch (error) {
                loadingIndicator.style.display = 'none';
                loadingIndicator.textContent = 'Error loading data. Please try again later.';
                console.error('Error fetching or parsing data:', error);
            }
        }

        function handleVisibilityChange() {
            if (document.visibilityState === 'visible') {
                // Reload data if the tab becomes visible again
                loadData();
            }
        }

        // Initialize
        document.addEventListener('DOMContentLoaded', () => {
            loadData();
            document.addEventListener('visibilitychange', handleVisibilityChange);
        });
    </script>
</body>
</html>