토픽 미리보기 모달

이 테마 컴포넌트 설치

주제 미리보기 모달 – 주제 목록에서 벗어나지 않고 주제를 열고 상호작용

**주제 미리보기 모달(Topic Preview Modal)**이라는 새로운 Discourse 테마 컴포넌트를 만들었습니다.

개념은 꽤 단순합니다:

주제 목록에서 주제를 직접 네이티브 Discourse 모달로 열고, 주제를 읽으며 상호작용한 후, 목록에서 벗어나지 않고 그대로 탐색을 계속합니다.

이것은 Facebook-style Topic Modal - Is it better? 에서 시작되었지만, Discourse의 주제, 게시물 스트림, 컴포저, 모달, 북마크, 라우팅, 존재 상태, 읽음 추적 및 선취(prefetching) 시스템과 상당한 통합이 필요하게 되었습니다.


왜 만들었나요?

일반적인 Discourse 흐름은 다음과 같습니다:

  1. 주제 목록을 탐색합니다.
  2. 주제를 클릭합니다.
  3. Discourse가 /t/...로 이동합니다.
  4. 주제를 읽거나 답글을 쓰거나 상호작용합니다.
  5. 주제 목록으로 돌아갑니다.

많은 워크플로에서 이것은 완벽하게 괜찮습니다.

그러나 바쁜 주제 목록을 탐색할 때, 때로는 주제를 빠르게 검사하고, 몇 개의 게시물을 읽고, 최신 답글을 확인하거나, 무언가에 반응하거나, 간단한 질문에 답하고 싶을 뿐입니다.

이러한 사용 사례에서 주제 목록을 떠나는 것은 불필요하게 비용이 많이 듭니다.

따라서 이 컴포넌트의 목표는 주제 목록이 더 *수신함(inbox)*처럼 동작하도록 만드는 것이었습니다:

주제 목록 → 미리보기 → 상호작용 → 닫기 → 정확히 있던 곳에서 계속.


동작 방식

미리보기는 단순히 정적인 발췌문이 아닙니다.

네이티브 DModal 내부에서 실제 Discourse 게시물 컴포넌트를 렌더링합니다.

즉, 사용자는 다음을 수행할 수 있습니다:

  • 게시물 읽기
  • 주제 내 스크롤
  • 이전 게시물 로드
  • 아래에 더 많은 게시물 로드
  • 게시물에 반응
  • 게시물 북마크
  • 텍스트 인용
  • 주제에 답글
  • 개별 게시물에 답글
  • 허용되는 경우 게시물 편집
  • 허용되는 경우 게시물 삭제/복구
  • 게시물 플래그 설정
  • 게시물 히스토리 보기
  • 다양한 일반 게시물 작업 수행
  • 주제 존재 상태 확인
  • 같은 주제 내 다른 게시물로 링크 이동
  • 관련 게시물로 직접 점프
  • 필요 시 전체 주제 열기

미리보기가 실제 주제를 여는 것과 최대한 유사하게 느껴지도록 하는 것이 의도입니다.


두 가지 트리거 모드

미리보기를 여는 두 가지 방법이 있습니다.

1. 전체 주제 목록 행

이것이 기본값입니다.

주제 목록 행 전체가 클릭 가능해지지만, 다음과 같은 일반적인 상호작용 요소는 모달 트리거에서 제외됩니다:

  • 사용자 카드
  • 참여자
  • 카테고리 링크
  • 태그
  • 주제 상태 링크
  • 일괄 선택

이로 인해 주제 목록을 탐색할 때 경험이 매우 빨라집니다.

2. 명시적 확장 버튼

대신, 컴포넌트는 Discourse 플러그인 아웃렛을 통해 작은 확장 아이콘을 렌더링할 수 있습니다. 커스텀 테마는 트리거를 표시하기 위해 간단히 새로운 <PluginOutlet />를 생성할 수 있습니다.

이 모드에서는 일반적인 주제 목록 동작이 완전히 그대로 유지됩니다.

사용자는 확장 아이콘을 클릭하여 미리보기를 열고, 주제 제목을 클릭하면 여전히 일반적인 Discourse 네비게이션이 수행됩니다.

사이트가 표준 주제 목록 상호작용 모델을 유지하려는 경우에 유용합니다.

설정은 다음과 같습니다:

trigger_style:
  row

또는:

trigger_style:
  button

버튼 모드를 사용할 경우, 아웃렛도 설정할 수 있습니다.


미리보기는 사용자의 읽지 않은 위치에서 시작됩니다

중요한 세부 사항 중 하나는 모달이 단순히 첫 번째 게시물을 로드하지 않는다는 점입니다.

주제가 이미 부분적으로 읽혔다면, 미리보기는 다음을 계산합니다:

last_read_post_number + 1

그리고 해당 게시물 주변에서 엽니다.

따라서 주제에 200개의 게시물이 있고 사용자가 165번 게시물까지 읽었다면, 미리보기를 열면 166번 게시물 주변에서 시작됩니다.

이것은 실제 탐색에서 미리보기를 훨씬 유용하게 만듭니다.

또한 컴포넌트가 게시물 스트림의 양쪽을 처리해야 함을 의미합니다:

  • 필요할 때 이전 게시물 로드
  • 아래에 더 새로운 게시물 로드

이전 게시물 버튼은 현재 로드된 범위 위에 게시물이 있을 때 표시되며, IntersectionObserver 센티넬이 사용자가 하단에 도달하면 자동으로 더 많은 게시물을 로드합니다.


선취(Prefetching)

컴포넌트의 가장 큰 부분 중 하나는 선취 시스템입니다.

이러한 모달의 문제는 사용자가 즉각적인 느낌을 기대한다는 것입니다.

사용자가 클릭한 후에만 주제 로드를 시작하면, 모달이 네트워크를 기다리는 눈에 띄는 시간을 소비할 수 있습니다.

대신, 컴포넌트는 사용자가 목록을 탐색하는 동안 능동적으로 주제를 선취할 수 있습니다.

주제 행이 뷰포트에 접근하면, IntersectionObserver가 선취를 예약할 수 있습니다.

이것이 통제되지 않은 백그라운드 트래픽으로 변하지 않도록 몇 가지 안전 장치가 있습니다.

디바운싱

주제가 뷰포트에 잠시 나타났다고 해서 즉시 요청을 트리거하지 않습니다.

컴포넌트는 설정된 디바운스 기간을 기다립니다.

기본값:

400 ms

이것은 긴 주제 목록을 빠르게 스크롤할 때 특히 유용합니다.

루트 마진

선취는 주제가 실제로 뷰포트에 들어오기 전에 약간 시작될 수 있습니다.

기본값:

50 px

이것은 요청에 작은 선두 출발을 제공합니다.

동시 요청 제한

동시 선취의 수는 제한됩니다.

기본값:

2

설정은 1에서 6개의 동시 선취를 허용합니다.

분당 예산

또한 두 번째 보호 메커니즘이 있습니다:

max_prefetches_per_minute

기본값은 다음과 같습니다:

15

따라서 사용자가 수백 개의 주제를 계속 스크롤하더라도, 컴포넌트는 지속적으로 추측적 요청을 생성하지 않습니다.

0은 제한을 비활성화합니다.

선취를 완전히 비활성화할 수 있습니다

사이트가 추측적 네트워크 트래픽을 원하지 않는다면:

enable_prefetch = false

컴포넌트는 정상적으로 작동합니다. 주제는 단순히 미리보기가 열릴 때 로드됩니다.


선취 데이터는 일반 주제 네비게이션과 별도로 유지됩니다

여기에는 중요한 구현 세부 사항이 있습니다.

선취된 응답은 즉시 Discourse의 일반 topic_<id> 프리로드 키에 기록되지 않습니다.

대신, 컴포넌트는 자체 네임스페이스를 사용합니다:

topic-preview-modal:prefetch:<topicId>

사용자가 실제로 미리보기를 열었을 때만 선취된 프롬이즈가 코어 주제 프리로드 키로 승격됩니다.

이것은 의도적인 것입니다.

미리보기는 last_read_post_number + 1부터 시작하여 주제를 로드할 수 있으며, 그 미리보기 전용 응답이 일반 주제 루트 네비게이션으로 누출되는 것을 원하지 않습니다.

따라서 라이프사이클은 기본적으로 다음과 같습니다:

주제가 뷰포트에 진입
        ↓
선취
        ↓
비공개 프리로드 저장소
        ↓
사용자가 미리보기 열기
        ↓
프리로드 승격
        ↓
Topic.find()/PostStream이 동일한 프롬이즈 사용

이것은 또한 모달이 열기 전에 선취 요청이 완료될 때까지 기다릴 필요가 없음을 의미합니다.

모달은 동일한 프롬이즈가 계속 해결되는 동안 스켈레톤과 함께 즉시 열릴 수 있습니다.


모바일 지원

사실 이것이 구현에 훨씬 더 많은 시간을 들인 이유 중 하나였습니다.

초기 아이디어는 데스크톱에서 꽤 잘 작동했지만, 모바일에서는 다음과 관련된 여러 문제를 드러냈습니다:

  • 터치 상호작용
  • 모달 스크롤링
  • 포커스
  • 중첩 메뉴
  • 컴포저
  • 게시물 가시성
  • 이미지 로드
  • 성능

따라서 최종 구현은 모달을 완전히 별개의 미니 포럼으로 취급하는 것을 피합니다.

대신, 가능한 한 Discourse의 기존 인프라를 재사용합니다.


실제 Discourse 게시물 컴포넌트

모달은 단순화된 커스텀 템플릿을 사용하여 게시물을 재생성하지 않습니다.

Discourse의 실제 다음을 렌더링합니다:

Post
PostSmallAction

컴포넌트

이것은 중요합니다. 그렇지 않으면 미리보기가 곧 게시물 UI의 두 번째 구현이 될 것이기 때문입니다.

컴포넌트는 다음과 같은 것들을 포함한 관련 작업을 일반 게시물 컴포넌트로 전달합니다:

  • 답글
  • 편집
  • 삭제
  • 복구
  • 플래그
  • 히스토리
  • 북마크
  • 위키
  • 잠금/잠금 해제
  • 게시물 유형
  • 소유권 변경
  • 배지
  • 숨겨진 게시물
  • 인용

그 결과, 미리보기는 전통적인 “미리보기” 컴포넌트보다 일반 주제에 훨씬 더 유사하게 동작할 수 있습니다.


답글과 컴포저

컴포저는 더 복잡한 부분 중 하나입니다.

미리보기는 다음을 위해 일반 Discourse 컴포저를 열 수 있습니다:

주제에 답글

주제 컴포저는 주제 모델과 올바른 초안 정보와 함께 열립니다.

특정 게시물에 답글

게시물이 컴포저로 전달되므로 답글이 일반 게시물 답글처럼 동작합니다.

선택된 텍스트 인용

컴포넌트는 또한 PostTextSelection과 통합됩니다.

즉, 사용자는 미리보기 내에서 텍스트를 선택하고 Discourse의 일반 인용/답글 흐름을 사용할 수 있습니다.


중첩 모달

또 다른 까다로운 부분은 Discourse의 모달 시스템이었습니다.

게시물은 다른 모달과 다이얼로그를 열 수 있습니다:

  • 플래그 설정
  • 히스토리
  • 배지 관련 다이얼로그
  • 소유권 변경
  • 삭제 확인

이들이 정상적으로 전역 모달 서비스와 상호작용하도록 허용된다면, 그 중 하나를 여는 것이 전체 주제 미리보기를 닫을 수 있습니다.

이를 피하기 위해, 컴포넌트는 로컬 서브-모달 메커니즘을 생성합니다.

개념적으로:

주제 미리보기 모달
        │
        ├── 플래그 모달
        ├── 히스토리 모달
        ├── 삭제 확인
        ├── 배지 모달
        └── 기타 게시물 관련 모달

미리보기는 아래에 마운트된 상태로 유지됩니다.

컴포넌트는 활성인 동안 관련 모달 서비스 메서드를 일시적으로 패치하고, 파괴될 때 복원합니다.


모달 내부 라우팅

또 다른 중요한 세부 사항은 같은 주제 내 게시물로 가는 링크입니다.

예를 들어, 게시물이 다음으로 가는 링크를 포함한다면:

/t/my-topic/123

미리보기는 닫고 떠나야 할 필요가 없습니다.

대신, 컴포넌트는 같은 주제 내 네비게이션을 가로채고 모달 내부에서 요청된 게시물로 점프합니다.

특정 게시물 번호 없이 주제를 대상으로 하는 링크에도 동일하게 적용됩니다.

이것은 사용자를 미리보기 안에 유지시킵니다.

링크가 실제로 다른 주제로 가리킨다면, 컴포넌트는 먼저 일시적인 서비스 패치를 복원하고 닫은 후, 일반 Discourse 루트 전이를 허용합니다.

이 클리업이 중요한 이유는, 그렇지 않으면 실제 주제 루트가 초기화되는 동안 미리보기의 구독과 타이밍 트래커가 살아남을 수 있기 때문입니다.


읽음 추적 및 시간 추적

또한 미리보기가 Discourse의 관점에서 올바르게 동작하기를 원했습니다.

미리보기를 여는 것이 읽음 추적이 완전히 우회됨을 의미해서는 안 됩니다.

따라서 컴포넌트는 다음을 처리합니다:

  • 주제 방문 추적
  • 가시 게시물 추적
  • 주제 타이밍
  • 마지막 읽은 게시물 업데이트

타이밍 트래커는 실제로 어떤 게시물이 보이는지 결정하기 위해 IntersectionObserver를 사용합니다.

5초마다, 가시 게시물 타이밍이 다음으로 플러시됩니다:

/topics/timings

모달이 닫힐 때, 마지막 몇 초가 손실되지 않도록 마지막 플러시가 수행됩니다.

구현은 단일 타이밍 간격을 60초로 제한합니다.


주제 목록의 읽지 않은 상태 동기화 유지

여기에는 또 다른 미묘한 문제가 있었습니다.

Discourse의 주제 추적 상태만 업데이트하는 것으로 주제 목록 행에 직접 표시되는 읽지 않은 배지를 업데이트하는 데 충분하지 않습니다.

따라서 컴포넌트는 타이밍 정보가 플러시된 후 행과 연관된 실제 주제 객체를 업데이트합니다.

적절한 경우 다음과 같은 값을 업데이트합니다:

last_read_post_number
unread_posts
unread
new_posts

즉, 모달 내에서 주제를 읽은 후, 전체 페이지 새로 고침 없이 주제 목록이 즉시 새로운 읽음 상태를 반영할 수 있습니다.


게시물 가시성

미리보기는 개별 게시물이 언제 보이는지 결정하기 위해 공유된 IntersectionObserver를 사용합니다.

옵저버가 연결될 때 동기 가시성 검사도 있습니다.

이것은 게시물이 마운트될 때 이미 보이는 경우, 그러나 비동기 첫 번째 IntersectionObserver 콜백이 아직 트리거되지 않은 엣지 케이스를 처리합니다.

이것은 모달이 열릴 때 전체 주제가 이미 보이는 매우 짧은 주제에서 특히 관련이 있습니다.


성능 고려 사항

주요 목표 중 하나는 모달이 성능 집약적인 미니 주제 페이지가 되는 것을 피하는 것이었습니다.

이를 위해 몇 가지 특정 조치가 취해집니다.

점진적 렌더링

초기 로드는 즉시 모든 게시물을 렌더링하지 않습니다.

컴포넌트는 먼저 대상 위치에 도달할 만큼 충분한 게시물을 렌더링합니다.

나머지 게시물은 다음을 사용하여 점진적으로 렌더링됩니다:

requestIdleCallback

사용 가능한 경우, setTimeout으로 폴백합니다.

이것은 스트림 아래쪽에 있는 게시물 주변에서 긴 주제를 열 때 특히 유용합니다.

CSS 컨테이닝

게시물은 다음을 사용합니다:

contain: layout;
content-visibility: auto;
contain-intrinsic-size: 1px 180px;

이것은 브라우저가 현재 표시되지 않는 게시물에 대해 불필요한 렌더링 작업을 피할 수 있게 합니다.

지연 이미지

이미 로딩 모드가 지정되지 않은 이미지는 자동으로 다음이 부여됩니다:

loading="lazy"
decoding="async"

이것은 많은 이미지를 가진 긴 주제가 즉시 모든 것을 로드하는 것을 방지합니다.


로딩 상태

모달은 요청이 진행되는 동안 단순히 빈 흰색/빈 영역을 표시하지 않습니다.

다음과 같은 스켈레톤 UI가 있습니다:

  • 아바타 플레이스홀더
  • 사용자 이름/이름 플레이스홀더
  • 게시물 본문 플레이스홀더
  • 시머 애니메이션

시머는 다음을 존중합니다:

prefers-reduced-motion

따라서 감소된 모션을 요청한 사용자는 애니메이션이 비활성화됩니다.


스크롤 위치 안정성 유지

컴포넌트가 스크롤 위치를 수동으로 조작해야 하는 몇 가지 장소가 있습니다.

예를 들어, 이전 게시물을 로드할 때, 새로 삽입된 콘텐츠가 스크롤 높이를 증가시킵니다.

단순히 게시물을 앞에 추가하면 사용자의 현재 위치가 점프하게 됩니다.

따라서 컴포넌트는 이전 스크롤 높이를 기록하고 게시물이 삽입된 후 차이를 보상합니다.

이것은 현재 보이는 콘텐츠가 대략 같은 위치에 유지되도록 합니다.

특정 게시물로 점프할 때도 동일하게 적용됩니다.

컴포넌트는 렌더링 후 위치 결정 단계를 수행하고, 여전히 안정화될 수 있는 콘텐츠를 고려하여 후속 프레임에서 위치를 다시 검증합니다.


주제 존재 상태

관련 주제 데이터가 사용 가능한 경우, 미리보기는 모달 하단에 Discourse의 주제 존재 상태 정보도 표시할 수 있습니다.

따라서 사용자는 미리보기를 떠나지 않고도 현재 주제를 보고 있는 다른 사람이 누구인지 볼 수 있습니다.


모바일 메뉴 및 포커스와의 상호작용

모바일은 또 다른 문제 카테고리를 도입했습니다.

일부 Discourse UI 요소는 공유 모달/메뉴 서비스를 사용하며, 이러한 서비스는 주제 미리보기가 현재 중첩 탐색 컨텍스트로 작용하고 있다는 것을 반드시 알지 못합니다.

따라서 컴포넌트는 다음에 대한 추가 처리를 가지고 있습니다:

  • modal.close()
  • Float Kit 메뉴
  • 포커스 복원
  • 컴포저
  • 라이트박스 키보드 제어
  • 바디 스크롤 잠금

예를 들어, 메뉴가 내부적으로 전역 모달 닫기 메서드를 호출하려고 하면, 그것이 실수로 전체 주제 미리보기를 닫아서는 안 됩니다.

마찬가지로, 컴포저가 열려 있을 때, 포커스는 미리보기의 포커스 컨텍스트로 끌려가야 할 것이 아니라 컴포저 안에 남아 있어야 합니다.


설정

컴포넌트는 현재 다음 설정을 노출합니다:

설정 기본값 설명
trigger_style row 전체 행을 클릭 가능하게 하거나 명시적 버튼 사용
plugin_outlet topic-list-after-title 버튼 트리거가 사용하는 아웃렛
enable_prefetch true 백그라운드 주제 선취 활성화/비활성화
max_concurrent_prefetches 2 최대 동시 선취 요청 수
prefetch_debounce_ms 400 선취 시작 전 지연 시간
prefetch_root_margin_px 50 행이 뷰포트에 들어오기 전 이 픽셀 수만큼 선취 시작
max_prefetches_per_minute 15 분당 최대 추측적 요청 수

선취 제어는 의도적으로 설정 가능하게 만들어졌는데, 이는 다른 커뮤니티가 매우 다른 트래픽 패턴과 호스팅/네트워크 특성을 가질 수 있기 때문입니다.


주요 디자인 목표 중 하나: 일반 Discourse를 깨지 않기

컴포넌트를 Discourse의 기존 아키텍처에 최대한 가깝게 유지하려고 했습니다.

자체 게시물 렌더러, 자체 컴포저, 자체 주제 모델 또는 완전히 별개의 게시물 스트림을 구현하지 않습니다.

대신, Discourse의 기존 컴포넌트와 서비스 주위에 임시 탐색 컨텍스트를 구축합니다.

이것이 구현의 일부가 처음에 보이는 것보다 더 복잡한 이유이기도 합니다.

더 흥미로운 도전은 다음과 같았습니다:

주제가 실제로 다른 UI 컨텍스트 안에 표시되고 있으면서도, 거의 일반 Discourse 주제처럼 동작할 수 있는가?

이를 위해 Discourse의 전역 서비스와 로컬 미리보기 사이의 경계를 처리해야 했습니다.

18개의 좋아요

참고:

수학 계산에 문제가 있습니다. 하지만 이건 또 다른 엣지 케이스일 수 있죠.

1개의 좋아요

정말 범상치 않네요 :slight_smile: 이제 내 환경에서 어떻게 작동하게 할지 알아봐야겠어요 :slight_smile: @awesomerobot 테마에서 전체 행 클릭은 무엇에 의존하나요

api.renderInOutlet("topic-list-before-link", TopicListItemClick);
2개의 좋아요

Reddit 스타일 테마를 사용하시는 분들을 위해 작동하는 수정 방법을 공유합니다.

Reddit 스타일 테마 호환성

Reddit 스타일 테마를 사용하시는 분들을 위한 참고 사항입니다: 모달 버튼 자체는 작동하지만, 기본 행(row) 트리거는 작동하지 않습니다.

이유는 Reddit 스타일 테마가 표준 토픽 목록 행(row) 동작을 대체하고, 클릭을 토픽 카드 전체에 대해 처리하기 때문입니다. 이로 인해 모달의 일반 행 클릭 처리가 의도한 대로 작동하지 않습니다.

토픽 미리보기 모달(Topic Preview Modal) 설정을 다음과 같이 변경하면:

Trigger style: button
Plugin outlet: topic-list-after-title

정상적으로 작동합니다. 이는 Reddit 스타일 테마가 이미 topic-list-after-title 아웃렛을 포함하고 있기 때문입니다.

카드 전체 클릭 동작을 유지하기 위해, 저는 토픽 미리보기 모달을 버튼 모드로 유지하면서 Reddit 스타일의 기존 openTopic() 액션을 수정하여 모달의 작동하는 버튼을 트리거하도록 변경했습니다.

기존 Reddit 스타일 액션은 다음과 같습니다:

@action
openTopic(event) {
  if (
    (event.target.nodeName === "A" && !event.target.closest(".raw-link")) ||
    event.target.closest(".badge-wrapper")
  ) {
    return;
  }

  const { navigateToTopic, topic } = this.args.outletArgs;

  if (wantsNewWindow(event)) {
    window.open(topic.lastUnreadUrl, "_blank");
  } else {
    navigateToTopic(topic, topic.lastUnreadUrl);
  }
}

다음과 같이 변경했습니다:

@action
openTopic(event) {
  if (
    (event.target.nodeName === "A" && !event.target.closest(".raw-link")) ||
    event.target.closest(".badge-wrapper") ||
    event.target.closest(".topic-preview-modal__trigger-wrapper")
  ) {
    return;
  }

  const { navigateToTopic, topic } = this.args.outletArgs;

  if (wantsNewWindow(event)) {
    window.open(topic.lastUnreadUrl, "_blank");
    return;
  }

  const previewButton = event.currentTarget.querySelector(
    ".topic-preview-modal__trigger-wrapper--button"
  );

  if (previewButton) {
    event.preventDefault();
    event.stopPropagation();
    previewButton.click();
    return;
  }

  navigateToTopic(topic, topic.lastUnreadUrl);
}

모달의 버튼 트리거는 다음과 같이 렌더링됩니다:

<div class="topic-preview-modal__trigger-wrapper">
  <span
    role="button"
    class="topic-preview-modal__trigger-wrapper--button"
  >

따라서 이는 모달 로직을 재현하는 것이 아닙니다. 단순히 Reddit 스타일 카드 클릭이 기존에 작동하는 미리보기 버튼을 트리거하도록 하는 것입니다.

그 결과는 다음과 같습니다:

  • 토픽 카드 클릭 시 미리보기 모달이 열립니다.

  • 토픽 제목 클릭 시 미리보기 모달이 열립니다.

  • 미리보기 버튼은 여전히 작동합니다.

  • Cmd/Ctrl 클릭 시 여전히 새 탭에서 일반 토픽이 열립니다.

  • 카테고리 및 기타 일반 링크는 정상적으로 작동합니다.

  • 미리보기 버튼이 존재하지 않으면, Reddit 스타일은 일반 토픽 내비게이션으로 폴백됩니다.

즉, 근본적인 모달은 Reddit 스타일 테마와 잘 작동하며, 비호환성은 구체적으로 기본 행 트리거에 있습니다.

또한 버튼을 다음과 같이 숨겼습니다:

.topic-preview-modal__trigger-wrapper {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}
3개의 좋아요

이제 모달에서 중첩된 답글 기능이 제대로 작동하는지 테스트해 보겠습니다 :slight_smile:

1개의 좋아요

오, 정말 대단하시네요. 오랜만에 보는 가장 멋진 테마 컴포넌트인 것 같습니다.

다만, 더 넓거나 설정 가능한 폭이 있으면 좋겠어요. 토픽 보기에서 게시물의 폭과 동일하게 만들 수 있으면 좋겠습니다.

2개의 좋아요

최대 폭을 800px으로 조정했습니다

    .d-modal {
        --modal-max-width: 600px;
        --modal-width: 30em;
        --modal-min-width: 400px;
    }
1개의 좋아요

이것은 모든 모달에 적용될 것입니다…
아이콘이 덜 눈에 띄게 보이도록 하기 위해 이렇게 했습니다

.topic-preview-modal__trigger-wrapper--button .d-icon {
    fill: #888;
}

@media (width >= 40rem) {
  .d-modal.topic-preview-modal {
      --modal-max-width: 800px;
  }
}
2개의 좋아요

@Don 궁금한 점이 있습니다: 코어의 <PostList> 컴포넌트를 재사용하지 않은 이유는 무엇인가요?

1개의 좋아요

@Jagster, 보고해 주셔서 감사합니다. 수정 사항을 공유합니다: FIX: Replace visibility:hidden to allow MathJax rendering · VaperinaDEV/discourse-topic-preview-modal@f9eb70f · GitHub


@RGJ, 이 기능을 위한 설정을 추가했습니다.


좋은 질문입니다.

PostList/PostListItem은 초점 기반 요약 목록(초안, 북마크, 활동 피드)을 위해 만들어졌으며, 토픽의 실제 인터랙티브 게시물 스트림을 렌더링하기 위한 것이 아닙니다.

@post.excerpt/expandedExcerptDDecoratedHtml을 통해 렌더링하고, 아바타/제목 헤더 및 초점으로 확장하는 버튼을 포함합니다. 좋아요, 인용, 답변, 편집, 신고와 같은 인터랙티브 게시물 메커니즘이 전혀 없습니다.

PostList의 페이지네이션도 단방향(fetchMorePosts는 아래쪽으로만 추가)인 반면, 모달은 마지막 읽은 게시물에서 열리고 그 주위의 이전 및 다음 게시물을 모두 로드해야 합니다 - 이는 단순한 fetch-more 콜백이 아니라 실제 postStream 서비스의 갭 로딩(gap-loading)이 필요합니다.

따라서 PostList를 재사용했다면, 다른 용도로 만들어진 컴포넌트 위에 Post의 인터랙티브 동작 대부분과 postStream의 양방향 로딩을 다시 구현해야 했을 것입니다. 대신 실제 코어 Post 컴포넌트와 postStream을 직접 사용하면 모달이 실제 토픽 페이지와 동일하게 동작하도록 보장됩니다.

3개의 좋아요

중첩 뷰에서 이 기능을 작동하게 만들었습니다. 더 많은 테스트가 필요하고, 관리자 설정에 옵션을 추가해야 할 것 같습니다. 돈, 몇몇 사람들이 이 기능을 사용했는데, 매우 유창하고 스크롤하기가 쉬워서 사람들이 더 많이 요청하고 사이트에 더 오래 머무는 것으로 보입니다. 정말 훌륭한 작업을 해주셨네요!

4개의 좋아요

지금 테스트 중! UI가 정말 인상적으로 개선되었네요

2개의 좋아요

여기서 부스터가 절실히 필요한데, 그 응답 시간 때문에 좀 걱정되네요 — 혹시 살아계신가요? :laughing:

감사합니다 :sign_of_the_horns:

3개의 좋아요

질문: .topic-avatarborder-top이 스크롤 중 이전 게시글의 보이는 부분과 현재 게시글의 시작 부분 사이에 구분선처럼 보이는 이유는 무엇인가요? 이 border-top의 의도가 정말 그런 것인지, 아니면 어떤 위치 지정/오버플로우 규칙 때문에 이런 동작을 하는 것인가요?

@media (width >= 40rem) {
    .topic-avatar {
        border-top: 1px solid var(--content-border-color);
        padding-top: var(--space-4);
        width: var(--topic-avatar-width);
        float: left;
        z-index: 2;
        height: 100%;
        overflow-anchor: none;
    }
}
1개의 좋아요

페이지 전체 로딩을 기다리고 싶지 않을 때 게시물을 빠르게 검토하는 데 매우 유용할 것 같습니다. 토픽 목록 대신 알림 클릭 시 모달이 뜨도록 전환할 수 있는 옵션이 있으면 좋겠습니다.

1개의 좋아요

안녕하세요 @Don. 이 놀라운 컴포넌트를 24시간 동안 사용해 본 결과, 가장 마음에 들었던 점은 아래로 스와이프하여 닫는 기능이었어요. 엄지와 손을 움직일 필요가 없어서 사이트를 사용하는 것이 매우 쉬웠거든요. 다만, 긴 주제에서 위로 다시 스크롤하는 경험은 그렇게 좋지 않았어요.

이를 보완하기 위해 모바일에서 오른쪽으로 스와이프하여 닫는 기능을 추가했어요. 이는 매우 합리적인 설계라고 생각하며, 빠른 스크롤 등을 원하는 사용자에게도 제 생각에는 훌륭하게 작동합니다. 여러분의 의견은 어떠신가요?

테스트 링크는 https://www.carptalk-online.co.uk/ 이며, 당연히 모바일에서만 작동합니다.

3개의 좋아요

다미안, 당신의 포럼을 사용해 봤는데, 이 스와이프 동작이 정말 완벽합니다. 늘 그렇듯 잘하셨네요!

이 테마 구성 요소가 호라이즌(Horizon)에서도 작동할 수 있을지 궁금합니다. 두 가지 릴리스에서 테스트해 봤는데, 관리자 화면 상단에 오류가 표시됩니다. 호환성이 없는 것 같습니다.

작동할 수 있기를 바랍니다. 이 새로운 관점을 가지고 플레이해 볼 수 있다는 점이 정말 마음에 듭니다.

2개의 좋아요

어떤 오류가 발생하나요?

2개의 좋아요

안녕하세요 :waving_hand:

open_all_topic_links라는 새로운 설정을 추가했습니다.

이 설정을 활성화하면, 페이지 어디에 있든(게시글 본문, 알림, 사용자 카드, 검색 결과, 추천/관련 주제, 사이드바 등) 주제(topic)로 연결되는 모든 링크가 페이지에서 벗어나지 않고 미리보기 모달을 엽니다. 주제 목록 행뿐만 아니라 모든 링크가 해당 동작을 따릅니다. 특정 게시글로 연결되는 링크는 해당 게시글 위치로 스크롤된 모달을 엽니다. 주제 목록 내부와 이미 열려 있는 미리보기 모달 안의 링크는 기존 동작을 유지합니다.

5개의 좋아요

모달의 GOAT(최고)이시네요 :slight_smile: 모바일에서 오른쪽으로 스와이프하여 닫는 기능을 코어에 추가하고, 중첩 뷰(nested views)를 지원할 가능성은 없을까요? :eyes:

2개의 좋아요