Countdown script in header duplicating avatar dropdown?

AI-generated summary

A user, ncaming215, created a countdown script in their Discourse header, which rendered correctly at first but duplicated the avatar dropdown when navigating to a topic. The user eventually fixed the issue using api.onPageChange(() => {.

The countdown script displays a banner with a countdown to an event, in this case, a sports game. Other users, such as Heliosurge and Firepup650, suggested releasing the code as a theme component, despite the bug that made the avatar menu unclickable.

ncaming215 shared the corrected code, which includes the fix using api.onPageChange(() => {. However, the user noted that the avatar menu still remains unclickable, and any corrections to this issue would be appreciated.

The code creates a countdown banner with a background text, foreground text, and a countdown container. It also includes styles for the banner and its elements.

I have the following script running in my header, and it’s rendering just fine.

But when I navigate to a topic, the avatar dropdown replicates like this:

Hoping it’s a simple fix, but maybe I’m trying to make Discourse do too much w/ a component.

<script>
document.addEventListener('DOMContentLoaded', function() {
    // Create Countdown HTML with Styling
    var countdownHtml = `
        <div id="countdown-banner" style="position: relative; display: inline-block; margin-left: 20px; vertical-align: middle;">
            <span id="background-text" style="opacity: 0.2; color: gray; font-size: 4.5em; position: absolute; left: 0; top: -31px; z-index: 1;">
                DET vs. DAL <i class="fas fa-football-ball"></i>
            </span>
            <div id="foreground-text" style="color: white; position: relative; z-index: 2; display: flex; align-items: center;">
                <span id="countdown-container" style="background-color: #0076B6; padding: 5px 10px; border-radius: 5px; margin-right: 10px;">
                    Lions at Cowboys: <span id="countdown" style="font-family: 'LCD', 'Courier New', monospace;"></span>
                </span>
                <a href="https://thedenforum.com/t/official-lions-vs-cowboys-game-day-thread-2023/30290" style="background-color: #0076B6; color: white; padding: 5px 10px; border-radius: 5px; text-decoration: none;">
                    Game Thread
                </a>
            </div>
        </div>`;

    // Insert the Countdown Banner next to the logo
    var headerLogo = document.querySelector('.d-header .title');
    if (headerLogo) {
        headerLogo.insertAdjacentHTML('afterend', countdownHtml);
    } else {
        console.error("Header logo not found");
    }

    // Countdown Functionality
    const eventTime = new Date('December 30, 2023 20:00:00 GMT-0400').getTime();
    const countdownElement = document.getElementById('countdown');

    if (!countdownElement) {
        console.error("Countdown element not found");
        return;
    }

    function updateCountdown() {
        const now = new Date().getTime();
        const distance = eventTime - now;

        if (distance < 0) {
            countdownElement.innerHTML = "The Game Has started!";
            clearInterval(interval);
            return;
        }

        const days = Math.floor(distance / (1000 * 60 * 60 * 24));
        const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
        const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
        const seconds = Math.floor((distance % (1000 * 60)) / 1000);

        countdownElement.innerHTML = days + "d " + hours + "h " + minutes + "m " + seconds + "s ";
    }

    var interval = setInterval(updateCountdown, 1000);
});
</script>

Solved! I fixed it using api.onPageChange(() => { if anyone else tries getting too fancy for their own good and encounters the same.

That looks pretty cool.

So this banner does a countdown in this case til the game starts?(sports)

This could be tt start of a pretty cool Customization > Theme component a commerce type site or what not could use it as a countdown for launch or upcoming sale.

Can you post your code with the fix implemented plz

I gave up on it because it renders the avatar menu unclickable. I tried everything to fix with no luck, so gave up, otherwise I’d submit it!

Perhaps you could release it as is, with a disclaimer on it about the bugs it causes to others could potentially try to fix it?

Might be an idea to try maybe in header?

Here’s the code for all who have asked.

<script type="text/discourse-plugin" version="0.8">
    api.onPageChange(() => {
        // Ensure the banner is only added once
        if (document.getElementById('countdown-banner')) return;

        // Create the countdown banner
        const countdownBanner = document.createElement('div');
        countdownBanner.id = 'countdown-banner';
        countdownBanner.style.cssText = 'position: relative; display: inline-block; margin-left: 20px; vertical-align: middle;';
        countdownBanner.innerHTML = `
            <span id="background-text" style="opacity: 0.2; color: gray; font-size: 4.5em; position: absolute; left: 0; top: -31px; z-index: 1;">
                DET vs. DAL <i class="fas fa-football-ball"></i>
            </span>
            <div id="foreground-text" style="color: white; position: relative; z-index: 2; display: flex; align-items: center;">
                <span id="countdown-container" style="background-color: #0076B6; padding: 5px 10px; border-radius: 5px; margin-right: 10px;">
                    Lions at Cowboys: <span id="countdown" style="font-family: 'LCD', 'Courier New', monospace;"></span>
                </span>
                <a href="[URL]" style="background-color: #0076B6; color: white; padding: 5px 10px; border-radius: 5px; text-decoration: none;">
                    Game Thread
                </a>
            </div>
        `;

        // Find the header logo and insert the countdown banner
        const headerLogo = document.querySelector('.d-header .title');
        if (headerLogo) {
            headerLogo.insertAdjacentElement('afterend', countdownBanner);
        }

        // Initialize the countdown
        const eventTime = new Date('December 30, 2024 20:00:00 GMT-0400').getTime();
        const countdownElement = document.getElementById('countdown');
        setInterval(() => {
            const now = new Date().getTime();
            const distance = eventTime - now;

            if (!countdownElement) return;

            if (distance < 0) {
                countdownElement.innerHTML = "The Game Has started!";
                return;
            }

            const days = Math.floor(distance / (1000 * 60 * 60 * 24));
            const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
            const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
            const seconds = Math.floor((distance % (1000 * 60)) / 1000);

            countdownElement.innerHTML = days + "d " + hours + "h " + minutes + "m " + seconds + "s ";
        }, 1000);
    });
</script>

CSS …

#countdown-container, #countdown-banner a {
    background-color: #0076B6; /* Solid background color */
    opacity: 0.8; /* Adjust transparency */
    /* Other styling... */
}


#countdown-container {
    background-color: rgba(0, 118, 182, 0.3); /* Slightly transparent background */
    padding: 5px 10px;
    border-radius: 5px;
    margin-right: 10px;
}

#countdown-banner a {
    background-color: rgba(0, 118, 182, 0.3); /* Slightly transparent background */
    color: white;
    padding: 5px 10px;
    border-radius: 5px;
    text-decoration: none;
    transition: background-color 0.3s;
}

#countdown-banner a:hover {
    background-color: rgba(0, 95, 138, 0.3); /* Slightly darker on hover with transparency */
}


#countdown-banner {
    font-family: Arial, sans-serif;
    position: relative;
    display: inline-block;
    margin-left: 20px;
    vertical-align: middle;
}

#background-text {
    font-family: 'Impact', sans-serif;
    font-size: 5em; /* Size of the text */
    color: gray; /* Changed to gray */
    opacity: 0.5; /* Adjust opacity for visibility */
    position: absolute;
    left: 0;
    top: -30px; /* More significantly shifted up */
    z-index: 1;
    font-weight: bold; /* Bold font */
}

#foreground-text {
    color: white;
    position: relative;
    z-index: 2;
    padding-left: 140px; /* Adjust based on actual layout */
}

#countdown {
    font-family: 'LCD', 'Courier New', monospace;
    font-size: 1.2em;
}

Please note I never did get the avatar menu to become clickable. :confused: … if you can correct and share, that’d be amazing!