Making custom changes to the sidebar programmatically

This is a great feature, but what if the content of a custom sidebar section needs to be created programmatically? I have achieved this in a way similar to @Olya_Fursova above, only that the content is generated by querying the API and then rendering links, some to categories and some directly to certain topics. Two problems I encountered are:

  • If the sidebar is hidden when the page is initially rendered, the dynamic content won’t be shown since the sidebar container is not present. Also, when the sidebar is initially shown but then collapsed and shown again, the dynamic content is gone because the sidebar container is re-rendered without the custom logi being executed. Question: is there any way to hook into the sidebar rendering process to execute my custom code whenever the sidebar is shown?
  • When the links I add to the sidebar programmatically are clicked, the complete page is refreshed. Question: is there any way to prevent a complete page refresh when one of my custom links in the sidebar is clicked?

It would be really fantastic if there was a way to modify the sidebar programmatically!

2 Likes

We’ve built an API for adding custom sidebar sections as well

There are some examples in the comments here: https://github.com/discourse/discourse/blob/00ab94bf53b784478d0aa7744bf3bb2d5b527580/app/assets/javascripts/discourse/app/lib/plugin-api.js#L2036

This is marked as experimental but it should be safe to use (we use it to add chat content to the sidebar when enabled, for example)

6 Likes

This looks interesting, thanks! Will take some time to really grasp it though, e.g. I don’t really get the hang of the routing yet. Also, it looks like the links in a section can only be a flat list, right? What I am currently trying to achieve is something like this, i.e. one level of indention:

image

Is this something I can achieve with the new API for custom sidebar sections?

1 Like

No, we haven’t built any sort of indentation into the sidebar by default… but as long as you can get your sections in the order that you want with the API, I think the indenting can probably be handled with styling in CSS?

Having looked into it a bit further, I am confident that this will work, yes! My challenge now is that the list of links is dynamic and can potentially change with each page change. My naive approach of calling api.addSidebarSection from within api.onPageChange does not work because (a) the sidebar is only refreshed when it is re-rendered by hiding and showing it again and (b) the sections are repeated because api.addSidebarSection does not care if the name key is reused.

Any chance I can achieve a sidebar section that is updated on each page transition with the new API?

1 Like

You may take a look on how chat-plugin is integrated with sidebar:

In this case, state of links are kept in service object and whenever state is changed, sidebar is updated:

A potential solution would be to subscribe to page change event and update links. Pseudocode may look like:

import { tracked } from "@glimmer/tracking";

api.addSidebarSection(
  (BaseCustomSidebarSection, BaseCustomSidebarSectionLink) => {
    const TestSectionLink = class extends BaseCustomSidebarSectionLink {
      // define your custom link properties here
    };

    const SidebarTestSection = class extends BaseCustomSidebarSection {
      @tracked links = [];

      constructor() {
        super(...arguments);

        this.#updateLinks();
        this.onAppEvent("page:changed", () => this.#updateLinks());
      }

      get newLinksArray() {
        // list of links based on current URL
      }

      #updateLinks() {
        this.links = this.newLinksArray.map(
          (link) =>
            new TestSectionLink({
              link,
            })
        );
      }

      get sectionLinks() {
        return this.links;
      }
    };
    return SidebarTestSection;
  }
);
4 Likes