개인 메시지 주제 목록에 다른 테마 적용 가능한가요?

안녕하세요, 개인 메시지(PM) 주제 목록에만 다른 테마를 사용할 수 있는 방법이 있을까요? 현재 저는 Sam의 Sam's Simple Theme 테마를 사용 중인데, /latest 목록에서는 OP(최초 게시자)와 최신 게시자의 사용자명을 텍스트로 표시하고, 아무도 신경 쓰지 않는 활발한 게시자들의 아바타 목록이라는 불필요한 요소를 제거하기 때문에 저와 커뮤니티 모두 이 테마를 매우 선호합니다. 불행히도 같은 방식은 /my/messages 목록에서는 제대로 작동하지 않는데, 특히 PM 주제를 생성한 사람이 최신 게시자와 동일할 때 문제가 발생합니다:

image

따라서 /my/messages의 경우, 이상적으로는 기본 Discourse 테마의 td.posters.topic-list-data 컬럼을 이 뷰에 주입하는 것이 좋겠습니다. 하지만 그 작업이 너무 번거롭다면, PM 뷰에 한해서만 기본 Discourse 테마로 전환할 수 있는 옵션이 있으면 좋겠습니다.

Kris의 Minima Theme 와 같은 다른 커스텀 테마들도 동일한 문제를 겪고 있습니다.

안녕하세요 :wave:

테마를 오버라이드(overriding)하면 가능하지만, 먼저 포크를 해야 하거나 테마에 대한 요청을 생성해야 합니다. 사용자 정의 템플릿에서는 다음 코드를 사용하여 개인 메시지(PM) 주제 목록 항목만 변경할 수 있습니다.

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

PM 주제 목록 항목에서 특정 요소를 숨기기:

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

많은 도움 주셔서 감사합니다. 테마 컴포넌트를 사용하여 거의 정상 작동하게 만들었습니다:

<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>

#if topic.isPrivateMessage 문이 topic-list-header에서는 작동하지 않는 것 같습니다. 그래서 개인 메시지(PM) 참가자의 아바타는 예상대로 표시되지만, 헤더에 <td>가 하나 빠져서 모든 것이 어긋나 있습니다.

그래서 저는 게으른 해결책으로 {{#if topic.isPrivateMessage}} 로직을 사용하지 않고, 단순히 posters.topic-list-data를 /latest와 /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>

하지만 사용자들은 /latest의 시각적 혼란을 좋아하지 않기 때문에, 저는 CSS를 사용하여 그곳에서 이를 숨기고 있습니다:

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

handlebars 오버라이드에서 로직을 구현하는 방법에 대한 팁이 있다면, posters.topic-list-data를 생성했다가 나중에 숨기는 것보다 CPU 사이클을 낭비하지 않는 그 방식이 더 좋겠습니다.

맞아요. 헤더에서는 토픽 데이터를 사용할 수 없으니, 그럴 수 있죠!

CSS가 해결책이 될 수 있습니다. 조건을 topic-list-item에 유지하고, 헤더에는 기본적으로 렌더링되도록 하세요.

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

그리고 CSS를 사용하여 "포스터(posters) 행이 없는 목록을 선택하고 숨기세요"라고 지정할 수 있습니다.

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

이렇게 하면 작동하나요?

안녕하세요, 정말 좋은 아이디어네요. 감사합니다. 다만 제안하신 CSS는 적용해도 /latest 페이지에서 여전히 비어 있는 참가자 열이 표시되어 원하는 대로 작동하지 않았습니다. 하지만 제가 원래 사용하던 CSS는 해당 페이지에서만 해당 열을 숨기는 데 정상적으로 작동하네요:

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

이렇게 사용하는 데 단점이 있을까요?

혼란스럽네요, 제 환경에서는 잘 작동하는데 :thinking:

최신 버전:

메시지:

음, 혹시 topic-list-item에 해당 조건이 없어서 그런 걸까요?

저는 해당 문제가 실제로 있습니다. 그렇지 않았다면 스크린샷에서 메시지 목록의 참가자 열이 보이지 않았을 것입니다!

위에서 설명하신 내용은 CSS가 적용되지 않는 문제인 것 같습니다.
제가 가진 내용은 다음과 같습니다:

/latest 페이지에서는 CSS가 적용되는 것을 볼 수 있습니다.

CSS를 올바른 위치에 제대로 복사해서 붙여넣었는지 확인하세요!

구체적인 도움 주셔서 정말 감사합니다. 지금은 컴퓨터 앞에 없지만, 돌아오면 바로 다시 시도해 보겠습니다.

어떤 생각을 해야 할지 모르겠네요. 제 환경에서는 확실히 작동하지 않습니다.

확인 차 여쭤보는데, 혹시 Sam’s Simple Theme을 사용 중이신가요?

그리고 핸들바 코드(Handlebars code)를 Head에 넣으셨나요, 아니면 Header에 넣으셨나요?

시간 내어 도와주셔서 정말 감사합니다.

네, Sam의 테마를 사용 중입니다.

CSS와 스크립트를 넣기 위해 Sam의 테마에 연결된 테마 컴포넌트를 만들었습니다.

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>

도움 주셔서 다시 한번 감사합니다. 동작 방식은 동일하며, /latest 페이지에 참여자 열 헤더가 있어 주제 목록의 열 정렬이 어긋나고 있습니다. 다른 컴포넌트에서 설정한 커스터마이징이 충돌을 일으키고 있는 것 같습니다.

이 CSS 솔루션에는 잠재적인 문제점이나 단점이 있을까요?

Firefox를 사용하시는 것 같으니, :has 선택기가 작동하지 않는 원인이 될 수 있습니다. 이 선택기는 Firefox 121부터만 지원됩니다.

그렇다면 설명이 되네요! Chromium에서는 작동했는데, 관리자 계정으로 로그인되어 있지 않아서 그런 줄 알았거든요. 저는 Debian 12에서 Firefox 115 ESR을 사용 중입니다. 정말 감사합니다. 그 문제로 머리가快要 아팠습니다. :wink:

정말요? 몰랐네요. 솔직히 좀 실망스럽긴 합니다 :sweat_smile:. 다음에는 더 자주 Firefox에서 테스트해봐야겠어요. 피드백 감사합니다!

이 기능을 더 유용하게 만들기 위해 적용하고 싶은 추가적인 CSS 개선 사항이 있습니다: 더 넓은 브라우저 창에서는 예상대로 PM 참여자가 표시됩니다:

하지만 더 좁은 창에서는 참여자 아바타가 단 하나만 표시되므로, 이 토픽의 첫 번째 게시물에서 설명된 것과 동일한 문제가 발생합니다:

좁은 창에서는 답글 열을 숨기고 마지막 게시물 열의 아바타를 숨김으로써 참여자 열에 더 많은 공간을 확보할 수 있도록 CSS로 이 문제를 해결할 방법이 있을까요?

이 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;
      }
    }
  }
}

감사합니다! 거의 완벽하지만, 폭이 약 1380px~1020px 사이일 때는 여전히 모든 열이 표시되고 참가자 아바타가 하나만 표시됩니다. 그보다 좁으면 아주 잘 작동합니다.

breakpoint()에서 medium을 extra-large로 교체하세요. 이제 <= 1140px부터 시작해야 합니다. 실제로 참가자의 아바타를 숨기는 원래 동작은 이 브레이크포인트에서 발생합니다. 제대로 작동합니까?