Different theme for personal message topics list?

Hi, is there any way to use a different theme just for the personal messages topics list? I am currently using Sam’s Sam's Simple Theme which I and my community strongly prefer for the /latest list, since it prints out the OP and most recent poster usernames in text, and it eliminates the clutter of the list of the frequent posters avatars that nobody cares about. Unfortunately that same paradigm falls apart for the /my/messages list, especially when the creator of the PM topic is the same as the most recent poster:

So in the case of /my/messages ideally I would like to just inject the td.posters.topic-list-data column from the default Discourse theme into this view. But if that’s too much work it would be nice to have the option to somehow switch to the default Discourse theme for the PM view.

There are other custom themes that have this same issue such as Kris’s Minima, a minimal theme for Discourse .

Hello :wave:

It can be possible with override the theme so you have to forked it first or create a request to the theme. In the custom template you can use the following to change only the pm topic list items.

{{#if topic.isPrivateMessage}}
...
{{/if}}

Hide something on pm topic list item.

{{#unless topic.isPrivateMessage}}
...
{{/unless}}
3 Likes

Thanks very much, I was able to make it almost work with a theme component:

<script type='text/x-handlebars' data-template-name='topic-list-header.raw'>
    <tr class="topic-list-header-row">
      {{~raw-plugin-outlet name="topic-list-header-before"~}}
      {{#if bulkSelectEnabled}}
        <div class="bulk-select">
          {{#if canBulkSelect}}
            {{raw "flat-button" class="bulk-select" icon="list" title="topics.bulk.toggle"}}
          {{/if}}
        </div>
      {{/if}}
      {{raw "topic-list-header-column" order='default' name='topic.title' bulkSelectEnabled=bulkSelectEnabled showBulkToggle=toggleInTitle canBulkSelect=canBulkSelect}}
      {{#if showLikes}}
          {{raw "topic-list-header-column" sortable='true' order='likes' number='true' forceName=(theme-i18n 'likes')}}
      {{/if}}
      {{#if showOpLikes}}
          {{raw "topic-list-header-column" sortable='true' order='op_likes' number='true' forceName=(theme-i18n 'likes')}}
      {{/if}}
      {{#if topic.isPrivateMessage}}
          {{raw "topic-list-header-column" order='posters' forceName='Participants'}}
      {{/if}}
      {{raw "topic-list-header-column" sortable='true' number='true' order='posts' forceName='Replies'}}
      {{raw "topic-list-header-column" sortable='true' order='activity' forceName='Last Post'}}
    </tr>
</script>


<script type='text/x-handlebars' data-template-name='list/topic-list-item.raw'>
    {{#if bulkSelectEnabled}}
      <td class="bulk-select topic-list-data">
        <label for="bulk-select-{{topic.id}}">
          <input type="checkbox" class="bulk-select" id="bulk-select-{{topic.id}}">
        </label>
      </td>
    {{/if}}
    
    <td class='main-link clearfix topic-list-data'>
      {{~raw-plugin-outlet name="topic-list-before-status"}}
      {{raw "topic-status" topic=topic}}
      {{~topic-link topic class="raw-link raw-topic-link"}}
      {{~#if showTopicPostBadges}}
        {{~raw "topic-post-badges" unreadPosts=topic.unread_posts unseen=topic.unseen url=topic.lastUnreadUrl newDotText=newDotText}}
      {{~/if}}
      {{discourse-tags topic mode="list" tagsForUser=tagsForUser}}
      {{#if expandPinned}}
        {{raw "list/topic-excerpt" topic=topic}}
      {{/if}}
      <div class='creator'>
        {{#unless hideCategory}}
          {{#unless topic.isPinnedUncategorized}}
            {{category-link topic.category}}
          {{/unless}}
        {{/unless}}
        {{~#if topic.creator ~}}
          <a href="/u/{{topic.creator.username}}" data-auto-route="true" data-user-card="{{topic.creator.username}}">{{topic.creator.username}}</a> <a href={{topic.url}}>{{format-date topic.createdAt format="tiny"}}</a>
        {{~/if ~}}
        {{raw "list/action-list" topic=topic postNumbers=topic.liked_post_numbers className="likes" icon="heart"}}
      </div>
    </td>
    
    {{#if showLikes}}
      <td class="num likes topic-list-data">
        {{#if hasLikes}}
          <a href='{{topic.summaryUrl}}'>
            {{number topic.like_count}} {{d-icon "heart"}}
          </a>
        {{/if}}
      </td>
    {{/if}}
    
    {{#if showOpLikes}}
      <td class="num likes topic-list-data">
        {{#if hasOpLikes}}
          <a href='{{topic.summaryUrl}}'>
            {{number topic.op_like_count}} {{d-icon "heart"}}
          </a>
        {{/if}}
      </td>
    {{/if}}
    
    {{#if topic.isPrivateMessage}}
      {{raw "list/posters-column" posters=topic.featuredUsers}}
    {{/if}}
    
    {{raw "list/posts-count-column" topic=topic}}
    
    <td class="last-post topic-list-data">
      <div class='poster-avatar'>
        <a href="{{topic.lastPostUrl}}" data-user-card="{{topic.last_poster_username}}">{{avatar topic.lastPosterUser imageSize="medium"}}</a>
      </div>
      <div class='poster-info'>
        <a href="{{topic.lastPostUrl}}">
          {{format-date topic.bumpedAt format="tiny"}}
        </a>
        <span class='editor'><a href="/u/{{topic.last_poster_username}}" data-auto-route="true" data-user-card="{{topic.last_poster_username}}">{{topic.last_poster_username}}</a></span>
      </div>
    </td>
</script>

It looks like the #if topic.isPrivateMessage statement doesn’t work for the topic-list-header, so I have the PM participants’ avatars showing as expected, but the headers are missing a <td> so everything is offset.

So my lazy solution is to not use the {{#if topic.isPrivateMessage}} logic and simply put posters.topic-list-data in both /latest and in /my/messages.

<script type='text/x-handlebars' data-template-name='topic-list-header.raw'>
<tr class="topic-list-header-row">
  {{~raw-plugin-outlet name="topic-list-header-before"~}}

{{#if bulkSelectEnabled}}
  <th class="bulk-select topic-list-data">
    {{#if canBulkSelect}}
      {{raw "flat-button" class="bulk-select" icon="list" title="topics.bulk.toggle"}}
    {{/if}}
  </th>
{{/if}}
{{raw "topic-list-header-column" order='default' name=listTitle bulkSelectEnabled=bulkSelectEnabled showBulkToggle=toggleInTitle canBulkSelect=canBulkSelect canDoBulkActions=canDoBulkActions showTopicsAndRepliesToggle=showTopicsAndRepliesToggle newListSubset=newListSubset newRepliesCount=newRepliesCount newTopicsCount=newTopicsCount}}

{{#if showPosters}}
  {{raw "topic-list-header-column" order='posters' forceName='Participants'}}
{{/if}}
  {{#if showLikes}}
      {{raw "topic-list-header-column" sortable='true' order='likes' number='true' forceName='thanks'}}
  {{/if}}
  {{#if showOpLikes}}
      {{raw "topic-list-header-column" sortable='true' order='op_likes' number='true' forceName='thanks'}}
  {{/if}}
  {{raw "topic-list-header-column" sortable='true' number='true' order='posts' forceName='Replies'}}
  {{raw "topic-list-header-column" sortable='true' order='activity' forceName='Last Post'}}
</tr>
</script>



<script type='text/x-handlebars' data-template-name='list/topic-list-item.raw'>
{{~raw-plugin-outlet name="topic-list-before-columns"}}

{{#if bulkSelectEnabled}}
  <td class="bulk-select topic-list-data">
    <label for="bulk-select-{{topic.id}}">
      <input type="checkbox" class="bulk-select" id="bulk-select-{{topic.id}}">
    </label>
  </td>
{{/if}}

<td class='main-link clearfix topic-list-data'>
  {{~raw-plugin-outlet name="topic-list-before-status"}}
  {{raw "topic-status" topic=topic}}
  {{~topic-link topic class="raw-link raw-topic-link"}}
  {{~#if showTopicPostBadges}}
    {{~raw "topic-post-badges" unreadPosts=topic.unread_posts unseen=topic.unseen url=topic.lastUnreadUrl newDotText=newDotText}}
  {{~/if}}
  {{discourse-tags topic mode="list" tagsForUser=tagsForUser}}
  {{#if expandPinned}}
    {{raw "list/topic-excerpt" topic=topic}}
  {{/if}}
  <div class='creator'>
    {{#unless hideCategory}}
      {{#unless topic.isPinnedUncategorized}}
        {{category-link topic.category}}
      {{/unless}}
    {{/unless}}
    {{~#if topic.creator ~}}
      <a href="/u/{{topic.creator.username}}" data-auto-route="true" data-user-card="{{topic.creator.username}}">{{topic.creator.username}}</a> <a href={{topic.url}}>{{format-date topic.createdAt format="tiny"}}</a>
    {{~/if ~}}
    {{raw "list/action-list" topic=topic postNumbers=topic.liked_post_numbers className="likes" icon="heart"}}
  </div>
</td>

{{#if showPosters}}
  {{raw "list/posters-column" posters=topic.featuredUsers}}
{{/if}}

{{#if showLikes}}
  <td class="num likes topic-list-data">
    {{#if hasLikes}}
      <a href='{{topic.summaryUrl}}'>
        {{number topic.like_count}} {{d-icon "heart"}}
      </a>
    {{/if}}
  </td>
{{/if}}

{{#if showOpLikes}}
  <td class="num likes topic-list-data">
    {{#if hasOpLikes}}
      <a href='{{topic.summaryUrl}}'>
        {{number topic.op_like_count}} {{d-icon "heart"}}
      </a>
    {{/if}}
  </td>
{{/if}}

{{raw "list/posts-count-column" topic=topic}}

<td class="last-post topic-list-data">
  <div class='poster-avatar'>
    <a href="{{topic.lastPostUrl}}" data-user-card="{{topic.last_poster_username}}">{{avatar topic.lastPosterUser imageSize="medium"}}</a>
  </div>
  <div class='poster-info'>
    <a href="{{topic.lastPostUrl}}">
      {{format-date topic.bumpedAt format="tiny"}}
    </a>
    <span class='editor'><a href="/u/{{topic.last_poster_username}}" data-auto-route="true" data-user-card="{{topic.last_poster_username}}">{{topic.last_poster_username}}</a></span>
  </div>
</td>

</script>

But my users don’t like the visual clutter in /latest, so I’m hiding it there via CSS:

.navigation-topics .topic-list .topic-list-data.posters {
    display: none;
}

If anybody has any tips for implementing the logic in the handlebars override I would still prefer that, rather then wasting CPU cycles generating the posters.topic-list-data and then hiding it.

You’re right; the topic data is unavailable in the header, which makes sense!

CSS can be a solution. Keep the condition in topic-list-item, and render it by default for the header.

{{raw "topic-list-header-column" order='posters' forceName='Participants'}}

And with CSS, you can say, "Select the list that doesn’t have (not has) the posters rows and hide it "

.topic-list:not(:has(.topic-list-body .topic-list-data.posters))
  .topic-list-header
  .topic-list-data.posters {
  display: none;
}

Does it work for you?

1 Like

Hi there, thanks a lot, that’s a very good idea. Something didn’t work with the CSS as suggested as it still shows the empty Participants column in /latest, but my original CSS does seem to work fine to hide it only there:

.navigation-topics .topic-list .topic-list-data.posters {
    display: none;
}

Any disadvantages to that?

I’m confused, it works for me :thinking:

Latest:
image

Message:
image

Hmm, would it maybe be because you don’t have the condition in topic-list-item ?

I do have the condition. You would not see the participants column in the messages list from my screenshots otherwise!

I think what you described above is the CSS not being applied.
Here is what I have:

image

You can see that the CSS is applied on the /latest page.

Make sure you copy-paste the CSS properly at the right place!

2 Likes

Thanks a lot for the specific help, I’m not at my computer right now but I’ll try it again as soon as I get back.

1 Like

I’m not sure what to think, it’s definitely not working for me.

Just to confirm, are you also using Sam’s Simple Theme?

Also, did you put the handlebars code in Head or Header?

Really appreciate your time and help.

Yes, I’m using Sam’s theme.

I’ve created a theme component to put the CSS and script there, attached to Sam’s theme.

CSS
.topic-list:not(:has(.topic-list-body .topic-list-data.posters))
  .topic-list-header-row
  .topic-list-data.posters {
  display: none;
}
Head
<script type='text/x-handlebars' data-template-name='topic-list-header.raw'>
    <tr class="topic-list-header-row">
      {{~raw-plugin-outlet name="topic-list-header-before"~}}
      {{#if bulkSelectEnabled}}
        <div class="bulk-select">
          {{#if canBulkSelect}}
            {{raw "flat-button" class="bulk-select" icon="list" title="topics.bulk.toggle"}}
          {{/if}}
        </div>
      {{/if}}
      {{raw "topic-list-header-column" order='default' name='topic.title' bulkSelectEnabled=bulkSelectEnabled showBulkToggle=toggleInTitle canBulkSelect=canBulkSelect}}
      {{#if showLikes}}
          {{raw "topic-list-header-column" sortable='true' order='likes' number='true' forceName=(theme-i18n 'likes')}}
      {{/if}}
      {{#if showOpLikes}}
          {{raw "topic-list-header-column" sortable='true' order='op_likes' number='true' forceName=(theme-i18n 'likes')}}
      {{/if}}
      {{raw "topic-list-header-column" order='posters' forceName='Participants'}}
      {{raw "topic-list-header-column" sortable='true' number='true' order='posts' forceName='Replies'}}
      {{raw "topic-list-header-column" sortable='true' order='activity' forceName='Last Post'}}
    </tr>
</script>

<script type='text/x-handlebars' data-template-name='list/topic-list-item.raw'>
    {{#if bulkSelectEnabled}}
      <td class="bulk-select topic-list-data">
        <label for="bulk-select-{{topic.id}}">
          <input type="checkbox" class="bulk-select" id="bulk-select-{{topic.id}}">
        </label>
      </td>
    {{/if}}
    
    <td class='main-link clearfix topic-list-data'>
      {{~raw-plugin-outlet name="topic-list-before-status"}}
      {{raw "topic-status" topic=topic}}
      {{~topic-link topic class="raw-link raw-topic-link"}}
      {{~#if showTopicPostBadges}}
        {{~raw "topic-post-badges" unreadPosts=topic.unread_posts unseen=topic.unseen url=topic.lastUnreadUrl newDotText=newDotText}}
      {{~/if}}
      {{discourse-tags topic mode="list" tagsForUser=tagsForUser}}
      {{#if expandPinned}}
        {{raw "list/topic-excerpt" topic=topic}}
      {{/if}}
      <div class='creator'>
        {{#unless hideCategory}}
          {{#unless topic.isPinnedUncategorized}}
            {{category-link topic.category}}
          {{/unless}}
        {{/unless}}
        {{~#if topic.creator ~}}
          <a href="/u/{{topic.creator.username}}" data-auto-route="true" data-user-card="{{topic.creator.username}}">{{topic.creator.username}}</a> <a href={{topic.url}}>{{format-date topic.createdAt format="tiny"}}</a>
        {{~/if ~}}
        {{raw "list/action-list" topic=topic postNumbers=topic.liked_post_numbers className="likes" icon="heart"}}
      </div>
    </td>
    
    {{#if showLikes}}
      <td class="num likes topic-list-data">
        {{#if hasLikes}}
          <a href='{{topic.summaryUrl}}'>
            {{number topic.like_count}} {{d-icon "heart"}}
          </a>
        {{/if}}
      </td>
    {{/if}}
    
    {{#if showOpLikes}}
      <td class="num likes topic-list-data">
        {{#if hasOpLikes}}
          <a href='{{topic.summaryUrl}}'>
            {{number topic.op_like_count}} {{d-icon "heart"}}
          </a>
        {{/if}}
      </td>
    {{/if}}
    
    {{#if topic.isPrivateMessage}}
      {{raw "list/posters-column" posters=topic.featuredUsers}}
    {{/if}}
    
    {{raw "list/posts-count-column" topic=topic}}
    
    <td class="last-post topic-list-data">
      <div class='poster-avatar'>
        <a href="{{topic.lastPostUrl}}" data-user-card="{{topic.last_poster_username}}">{{avatar topic.lastPosterUser imageSize="medium"}}</a>
      </div>
      <div class='poster-info'>
        <a href="{{topic.lastPostUrl}}">
          {{format-date topic.bumpedAt format="tiny"}}
        </a>
        <span class='editor'><a href="/u/{{topic.last_poster_username}}" data-auto-route="true" data-user-card="{{topic.last_poster_username}}">{{topic.last_poster_username}}</a></span>
      </div>
    </td>
</script>
2 Likes

Thanks again for the help. It’s behaving the same way, there is a Participants column header in /latest which makes the columns misaligned with the topic list columns. I must have some other customizations in other components that are conflicting.

Are there any potential problems or disadvantages with this CSS solution?

As I see you using Firefox so it might cause the :has selector is not working on your side. It’s only supported from Firefox 121.

4 Likes

That would explain it! And it was working in Chromium, but I assumed that was because I wasn’t logged in there as the administrator. I’m using Firefox 115 ESR from Debian 12. Thanks so much, I was going crazy with that. :wink:

2 Likes

Oh really. I did not know, and it’s pretty disappointing to be honest :sweat_smile:. I will definitively test more often on Firefox next time. Thanks for the feedback!

4 Likes

There’s an additional CSS improvement that I’d like to implement to make this more useful: On wider browser windows it now shows the PM participants as expected:

But on narrower windows it reduces the number of participant avatars to only one, so we end up with the same problem as described in the first post of this topic:

Is there a way to fix this via CSS so that on narrower windows it hides the Replies column and hides the avatar in the Last Post column, thus leaving more space for the Participants column?

Can yo try this CSS?

@include breakpoint(extra-large, $sidebar: true) {
  .user-messages-page .topic-list {
    .posts {
      display: none;
    }
    
    .posters {
      width: 146px;
      text-align: inherit;
    }
    
    .last-post {
        width: auto;
        
        .poster-avatar {
            display: none;
        }
    }
    
    .topic-list-header .topic-list-data.activity {
      width: auto;
    }
    
    .topic-list-data.posters {
      a:not(.latest) {
        display: inherit;
      }
      
      a.latest {
        width: auto;
      }
    }
  }
}
1 Like

Thank you! Almost perfect, except that with widths between about 1380px - 1020px it still shows all the columns and reduces the participant avatars to just one. More narrow than that does work great.

Replace medium with extra-large in breakpoint(). It should now start from <= 1140px. The original behavior that hides the participant’s avatars happens at this breakpoint, actually. Does it work?

1 Like