DiscoTOC style is broken if there is no reply on mobile

AI-generated summary

The discussion highlights an issue with the DiscoTOC style on mobile devices when there are no replies in a topic. Don explains that the .with-topic-progress class, which triggers the DiscoTOC style, is only added if there is more than one post. This causes the TOC to break on mobile, although it works fine on desktop. JammyDodger confirms encountering the same issue. alltiagocom provides a custom solution using CSS and JavaScript to make the TOC sticky and visible even without replies. Don suggests a CSS-only approach by applying the same styles to .topic-navigation as those used for .with-topic-progress. chapoi mentions that this issue should be fixed with a pull request on GitHub.

Hello :wave:

DiscoTOC style is connected to the .with-topic-progress class which is added to .topic-navigation if there are more than 1 post in the topic. So without reply the DiscoTOC style will broke.

I think TOC should also be active if there is no reply in a topic because it doesn’t related with the reply counts. On desktop it works fine topics with no reply too.

Here is a topic for testing: Customizing the topic list

I think that would be consider to change this behaviour.

It’s probably not a new thing but I didn’t notice it yet. Now we started it using more actively.

Thanks :slight_smile:

7 Likes

I’ve just run into this here too. :cry: (iPhone/Safari) It’d be great if this could be fixed. Scrolling to the bottom of a long doc to get to the toc is a bit cumbersome.

3 Likes

With my basic coding skills and some ChatGPT talk, I made it work, I believe.

Created a custom component and put this in the CSS tab:

@media (max-width: 767px) {
    #topic-progress-wrapper.sticky-bottom {
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        z-index: 1000;
    }
}

and this in the JS tab

import { apiInitializer } from "discourse/lib/api";

export default apiInitializer((api) => {
  api.onPageChange(() => {
    const observer = new MutationObserver(() => {
      const wrapper = document.getElementById("topic-progress-wrapper");
      const tocButton = wrapper?.querySelector(".d-toc-mini button");

      if (wrapper) {
        if (tocButton) {
          wrapper.classList.add("sticky-bottom");
        } else {
          wrapper.classList.remove("sticky-bottom");
        }
      }
    });

    observer.observe(document.body, {
      childList: true,
      subtree: true,
    });
  });
});

This seems to be working just fine even without a reply.
Again, I’m no expert, I’m just a good “asker” and after a little bit of “back and forth” with ChatGPT with the right questions and challenges, it seems to be working.

If anyone who is an expert in JavaScript and CSS wants to improve it, please share.


So, if you want:

  1. The text “Table of Contents” next to the icon
  2. Expanded headings
  3. Sticky button without relying on any replies, the full CSS is this:
/* expands all headings in table of content sidebar */
#d-toc li.d-toc-item > ul {
  max-height: 500em !important;
  overflow: visible !important;
  opacity: 1 !important;
}

@media screen and (max-width: 767px) {
    /* makes the wrapper including the table of contents button, sticky to the bottom */
    #topic-progress-wrapper.sticky-bottom {
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        z-index: 1000;
    }

    /* add "table ot contents" to the button after the icon */
    .d-toc-mini button::after {
        content: "Table of Contents";
        margin-left: 5px;
        font-size: 14px;
        vertical-align: middle;
    }
}

The JavaScript doesn’t change.

1 Like

Hello :wave:

This is great thanks, but I think we can make it with only CSS too. :thinking: We just have to use the same CSS on .topic-navigation which used on .with-topic-progress. The missing .with-topic-progress class is blocking the style if there is no reply in the topic.

Something like this should work.

Mobile CSS

// Sticky Topic Navigation
.container.posts .topic-navigation:not(.with-topic-progress) {
  position: sticky;
  bottom: calc(env(safe-area-inset-bottom) + var(--composer-height, 0px));
  z-index: z("timeline");
  pointer-events: none; // the wrapper can block mobile controls
  
  > * {
    pointer-events: auto; // this unsets the above rule so the child elements are interactive
  }
  
  // Add TOC Style
  .d-toc-wrapper {
    position: fixed;
    margin-top: 0.25em;
    height: calc(100vh - 50px - var(--header-offset));
    opacity: 0.5;
    right: -100vw;
    top: var(--header-offset);
    width: 75vw;
    max-width: 350px;
    background-color: var(--secondary);
    box-shadow: var(--shadow-dropdown);
    z-index: z("modal", "overlay");
    transition: all 0.2s ease-in-out;

    .d-toc-main {
      width: 100%;
      padding: 0.5em;
      height: 100%;

      #d-toc {
        max-height: calc(100% - 3em);
      }
    }

    &.overlay {
      right: 0;
      width: 75vw;
      opacity: 1;

      .d-toc-main #d-toc li.d-toc-item ul {
        transition: none;
      }
    }

    a.scroll-to-bottom,
    a.d-toc-close {
      display: inline-block;
      padding: 0.5em;
    }

    .d-toc-icons {
      text-align: right;
    }
  }
}

// RTL Support
.rtl {
  .topic-navigation .d-toc-wrapper {
    right: unset;
    left: -100vw;

    &.overlay {
      right: unset;
      left: 0;
    }
  }
}
1 Like

Should be fixed with

https://github.com/discourse/DiscoTOC/pull/124

2 Likes

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.