페이지네이션이 불가능한 건가요, 아니면 어려운 건가요?

최근에 Discourse로 전환했는데, 커뮤니티에서 무한 스크롤을 어떻게 생각하느냐를 두고 의견이 갈리고 있습니다. 좋아하는 사용자도 있고, 신경 쓰지 않는 사용자도 있으며, 커뮤니티에 대한 실존적 위협이라고 여기는 사용자도 있습니다. 여기서 읽은 다른 토론들을 보면, 이 문제가 흔히 논쟁의 대상이 되는 것 같습니다.

이 소프트웨어의 개발진이 페이지네이션을 옵션으로 제공할 의사가 없다는 점은 이해합니다. 그 점은 존중할 수 있습니다. 현재 저는 몇 가지 플러그인과 레이아웃을 작성해 보았고, 코어 GitHub의 코드를 조금 살펴본 덕분에 소프트웨어에 대한 기본적인 이해를 갖추고 있습니다. 만약 커뮤니티가 계속 저항한다면, 페이지네이션 플러그인을 작성하는 것이 얼마나 어려울지 궁금합니다. 코어의 기본적인 Ruby 코드를 많이 다시 작성해야 할 가능성이 높을까요? 기존 코드 위에 얹어서 매끄럽게 실행할 수 있는 것일까요? 데이터베이스 구조가 실제로 페이지네이션 방식으로 쿼리하기에 매우 비효율적으로 설계된 것일까요?

코드를 가장 잘 아는 분들에게 이 작업을 수행할 수 있는 현실적인 가능성을 파악해 보고 싶었습니다.

개발은 내 강점이 아니지만, 활용할 수 있는 페이지가 이미 있는 것 같지 않나요?

예: https://meta.discourse.org/t/introducing-discourse-chat-beta/210734/?page=6

가장 큰 문제는 플러그인을 지속적으로 유지보수해야 하는 부담일 것 같습니다. 코어에서 아주 사소한 변경만으로도 UI의 상당 부분을 오버라이드해야 하기 때문에, 플러그인이 매우 자주 깨지는 문제가 발생할 수 있거든요.

이 문제는 기술적인 측면보다는 실용적, 경제적 측면에서 발생할 가능성이 더 높습니다. 거의 모든 경우에 커스터마이징은 가능하지만, 실제로 적용하기가 까다로운 것이죠.

그래도 도전해 보고 싶으시다면, 한번 시도해 보시고 제가 틀렸는지 알려주세요!

대신 페이지 기반의 포럼을 사용하는 더 쉬운 방법을 고려해 보시는 건 어떨까요? 그런 포럼은 꽤 많습니다.

채팅 구현에 페이지를 사용한다는 뜻인가요? 죄송하지만 무슨 말씀인지 잘 이해가 되지 않습니다.

아니, 내가 실수를 한 것 같아. :slight_smile:

특정 조건에서는 ?page=2를 붙일 수 있지만, 정확히 어떻게 작동하는지 기억이 안 나네. :slight_smile:

제가 아는 한, 해당 매개변수는 크롤러와 구형 및 지원되지 않는 브라우저에 제공되는 페이지에서만 작동합니다.

그들은 코모도어 64를 사용할 수 없다는 사실에 불만을 제기하는 바로 그 사용자들입니다. 매우 죄송하며 문제를 해결하기 위해 열심히 노력하고 있다고 말하면서 아무것도 하지 마세요. 무한 스크롤은 최소 10년 이상 업계 표준이었습니다.

또는, 그들이 왜 그것을 원하는지(아마도 해당 주제에서 특정 위치로 링크할 수 있도록 하기 위해서일까요?) 정확히 말해달라고 요청해 보세요. 그리고 이제 특정 게시물로 링크할 수 있으며 "이 페이지의 6번째 게시물"을 보는 것이 아니라는 것을 보여줄 수 있습니다. 하지만 그들은 여전히 그것이 10년 전과 정확히 같은 방식이 아니라는 사실에 매우 불만을 느낄 것입니다.

여기서 말씀하신 점이 매우 설득력 있다고 생각합니다. 결국 이 플러그인을 사용하면 업데이트를 전혀 하지 못하거나, 끝이 없는 작업이 될 수밖에 없습니다.

@pfaffman 님이 시사한 대로, 기술적 해결책보다 소통에 기반한 접근이 더 쉽겠습니다.

대부분의 사용자는 결국 익숙해지지 않을까 싶습니다. 그렇지 않을 경우에 대비해 다른 옵션들을 탐색해 보고 싶었을 뿐입니다.

이 작업이 얼마나 (비)현실적인지, 다른 분들의 의견도 계속 듣고 싶습니다.

개발 비용은 최소 1만 달러에서 최대 5만 달러까지 들 수 있습니다. 아마 커뮤니티에 이 비용을 마련해 달라고 요청할 수 있을 것입니다. 그리고 매년 유지보수비로 5,000달러를 더 요구하게 될 텐데, 무료 오픈소스 프로젝트를 비용이 많이 드는 악몽으로 만들어 버리는 셈이죠.

카테고리, 토픽, 게시글에 직접 링크할 수 있는 상황에서 '페이지네이션’의 장점이 잘 보이지 않습니다.

나는 “하이브리드” 구성 요소가 다소 실용적일 수 있다고 생각합니다.

토픽에서 N개의 게시글마다 "페이지네이터"를 삽입하는 방식입니다.

Post 1
Post 2 
...
Post 15

[*Page 1*] [Page 2] [Page 3] [Page 4]

Post 16

... 

Discourse의 무한 스크롤을 제거하는 것은 실용적이지 않은 시도이지만, “하이브리드” 페이지네이터(토픽 목록 변경이 있는 경우에도)를 만드는 구성 요소는 대략 2,000~5,000 범위에 있을 것입니다.

Sam, 당신의 메시지는 Natural breakpoints or "chapters" for long topics? 을 떠올리게 합니다. 이와 같은 기능의 결과를 매우 궁금해합니다. 그리고 페이지네이션이 그리운 사람들에게 좋은 대안이 될 수 있을 것 같습니다. 그들은 종종 페이지네이션을 그리워하는데, 이는 페이지가 단순히 끊김 지점(breakpoint)이기 때문입니다.

@piffy –

@ghassan은 현재(또는 최근에) 페이지네이션 플러그인을 개발하고 있습니다:

이것은 단일 주제에 페이지 내비게이션을 추가하는 것보다는 개별 주제를 연결하는 방법인 것 같습니다


페이지네이션에 대해 약간 진전을 보았습니다. 아이디어는 discourse에 내장된 ?page=x 기능을 사용하여 “페이지” 간을 이동하고, 다음 배치의 게시물을 로드하는 post-stream 함수를 오버라이드하여 추가 메시지 로딩을 기본적으로 차단하는 것이었습니다.

더 자세한 내용(및 미해결된 문제)은 아래를 참조하십시오.

각 주제 상단과 하단에 페이지네이션 버튼을 추가했습니다. 아직 해결하지 못한 점은 주제 내 총 페이지 수를 어떻게 가져와야 할지입니다. 이를 통해 몇 개의 버튼을 표시할지 알 수 있어야 합니다. 백엔드에서는 쉽게 가져올 수 있지만, 플러그인보다는 테마 컴포넌트로 구현하는 것이 더 좋으므로 구현 방법이 더 제한적입니다.

이 두 가지가 갖춰지면 대부분 기능적인 페이지네이션 시스템이 될 것 같습니다. 물론 마지막 페이지로 이동할 때 몇 개의 게시물을 표시할지 조절하거나, 삭제된 게시물이 페이지의 메시지 수에 포함되는지 여부 등 다듬어야 할 특이한 동작들이 있을 것입니다.

이 문제에 대해 주기적으로 다시 돌아와서 작업하고 있습니다. 깔끔한 솔루션에 도달할 수 있을지는 모르겠지만, 다소 어설프지만 대부분 기능적인 솔루션이 존재할 수 있다고 생각합니다

토픽에서 토픽으로 이동하는 내비게이션을 만들고(각 토픽에 이전/다음 버튼을 자동 삽입), 이렇게 하고 있습니다…

“연결된 토픽으로 답글” 기능을 재사용한 뒤, 링크를 다음과 같이 CSS로 스타일링했습니다 …

그리고 테마 설정에 다음 CSS를 추가했습니다 …

버튼을 위한 최소한의 CSS
.post-links-container {
    margin-left: var(--topic-body-width-padding);
    position: absolute;
    top: 37px;
    right: 30px;
}

.post-links-container ul li .d-icon {
    display: none;
}

.post-links-container .post-links {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
}

.post-links-container .post-links li:last-of-type {
    margin-bottom: 0;
}

.post-links-container ul li a[href] {
    align-items: center;
    border: 1px solid var(--primary-low-mid);
    background: var(--primary-very-low);
    border-bottom-width: 2px;
    border-radius: 3px;
    box-sizing: border-box;
    color: #009a49;
    display: inline-flex;
    font-family: monospace, monospace;
    font-size: var(--font-down-1);
    justify-content: center;
    line-height: var(--line-height-large);
    margin: 0 0.15em;
    min-width: 24px;
    padding: 0.15em 0.6em;
}

.post-links-container ul li a::after {
    content: " ->>";
    padding-left: 0.15em;
}

kbd {
    align-items: center;
    border: 1px solid var(--primary-low-mid);
    background: var(--primary-very-low);
    border-bottom-width: 2px;
    border-radius: 3px;
    box-sizing: border-box;
    color: var(--primary);
    display: inline-flex;
    font-family: monospace, monospace;
    font-size: var(--font-down-1);
    justify-content: center;
    line-height: var(--line-height-large);
    margin: 0 0.15em;
    min-width: 24px;
    padding: 0.15em 0.6em;
}

kbd a {
    padding: 0;
}

kbd a::before {
    content: "<<-";
    padding-right: 0.15em;
}

설치 방법 및 사용 중인 전체 CSS

/** 책이나 기타 토픽 시퀀싱을 위한 이전/다음 버튼 - 이 기능은 네이티브 Discourse 기능인 "연결된 토픽으로 답글" 선택기(컴포저 왼쪽 위)를 재사용하여 구축했습니다 **/
/** 내 Discourse에 이 기능을 설정하려면 **/
/** /admin/customize/site_texts/js.post.continue_discussion에 <kbd>%{postLink}</kbd>를 붙여넣으세요. **/
/** 그런 다음 2개의 카테고리를 만드세요: BOOKS(블로그 스타일 토픽 시퀀스용)와 STORIES(일반 토픽 스타일 토픽 시퀀스용). **/
/** https://meta.discourse.org/t/blog-post-styling/110841 테마 컴포넌트를 설치하세요 **/
/** 블로그 포스트 스타일링 테마 컴포넌트 설정에서 BOOKS 카테고리를(STORIES는 제외하고) 블로그 카테고리로 지정하세요. **/
/** 그런 다음 BOOK이라는 태그를 만들고, 블로그 포스트 스타일링 테마 컴포넌트 설정에서 이를 블로그 태그로 지정하세요 **/
/** 그리고 아래 CSS를 붙여넣는 것을 잊지 마세요! 이는 테마 헤더에 들어갑니다. **/
/** 물론 여기 있는 CSS는 다른 테마에서 올바르게 작동하려면 조정이 필요합니다. **/
/** 이제 STORIES 카테고리에서 내비게이션 버튼이 있는 토픽 시퀀스를 만들 수 있습니다. **/
/**   단, 해당 토픽은 그 외에는 일반 토픽 스타일로 표시됩니다. **/
/** BOOK 태그를 단순히 추가하기만 하면 STORIES 카테고리 토픽에도 블로그 스타일링을 적용할 수 있습니다. **/
/** BOOKS 카테고리에서 "연결된 토픽으로 답글"을 사용하여 작성하는 새 토픽에는 이미 내비게이션 버튼과 **/
/**   블로그 스타일링이 모두 적용되어 있습니다. **/
/** 데모는 https://meta.discourse.org/t/is-pagination-impossible-or-just-hard/231838/16 에서 확인하세요 **/



.tag-book,
.category-books {
    aside.sidebar,
    .topic-meta-data,
    .tag-book .topic-category .badge-wrapper,
    .category-books .topic-category .badge-wrapper {
    display:none !important;
    
    }
}

.tag-book .container.posts,
.category-books .container.posts {
    justify-content: unset;
    justify-items: unset;
    padding-left: 0;
    display: block;
}

.tag-book .container.posts .topic-post .row,
.category-books .container.posts .topic-post .row {
    display: block;
    justify-content: center;
}

.tag-book #topic-title .title-wrapper,
.category-books #topic-title .title-wrapper {
    display: block;
    margin: 0 auto;
}

.tag-book #topic-title,
.category-books #topic-title {
    display: block;
    margin: 0 auto;
}

.tag-book #topic-title h1,
.category-books #topic-title h1 {
    font-size: 2em;
    padding-right: 20px;
}

.tag-book #post_1 .topic-body,
.category-books #post_1 .topic-body {
    padding-top: 1em;
    border-top: none;
    max-width: 100%;
}

.tag-book #post_1 .topic-body .contents,
.category-books #post_1 .topic-body .contents {
    border-top: none;
    margin-left: 0;
    padding: 0;
}
  
.tag-book p,
.category-books p {
    /* 책 페이지의 본문 텍스트에 적용할 스타일을 여기에 입력하세요 */
}

/* 다음 버튼을 페이지 오른쪽 위에 배치 */
.tag-book .post-links-container,
.category-books .post-links-container {
    margin-left: var(--topic-body-width-padding);
    position: absolute;
    top: 1em;
    right: 30px;
}

/* 이전 버튼을 페이지 왼쪽 위에 배치 */
.category-stories .post-links-container {
    margin-left: var(--topic-body-width-padding);
    position: absolute;
    top: 2.5em;
    right: 30px;
}

/* 다음 버튼에서 링크 심볼 제거 */
.tag-book .post-links-container ul li .d-icon,
.category-books .post-links-container ul li .d-icon,
.category-stories .post-links-container ul li .d-icon {
    display: none;
}

.tag-book .post-links-container .post-links,
.category-books .post-links-container .post-links,
.category-stories .post-links-container .post-links {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
}

.tag-book .post-links-container .post-links li:last-of-type,
.category-books .post-links-container .post-links li:last-of-type,
.category-stories .post-links-container .post-links li:last-of-type {
    margin-bottom: 0;
}

/* 다음/진행 버튼 스타일링 */
.tag-book .post-links-container ul li a[href],
.category-books .post-links-container ul li a[href],
.category-stories .post-links-container ul li a[href] {
    align-items: center;
    border: 1px solid var(--primary-low-mid);
    background: var(--primary-very-low);
    border-bottom-width: 2px;
    border-radius: 3px;
    box-sizing: border-box;
    color: #009a49;
    display: inline-flex;
    font-family: monospace, monospace;
    font-size: var(--font-down-1);
    justify-content: center;
    line-height: var(--line-height-large);
    margin: 0 0.15em;
    min-width: 24px;
    padding: 0.15em 0.6em;
}

/* 다음 버튼에 오른쪽을 가리키는 화살표 추가 */
.tag-book .post-links-container ul li a::after,
.category-books .post-links-container ul li a::after,
.category-stories .post-links-container ul li a::after {
    content: " ->>";
    padding-left: 0.15em;
}

/* 또는 오른쪽 화살표에 이미지 사용 */
/*
.tag-book .post-links-container::after,
.category-books .post-links-container::after,
.category-stories .post-links-container::after {
    content: url('../../media/arrow-right.svg');
    display: inline-block;
    width: 12px;
    height: 12px;
}
*/

/* 이전/뒤로 버튼 스타일링 */
.tag-book kbd,
.category-books kbd,
.category-stories kbd {
    align-items: center;
    border: 1px solid var(--primary-low-mid);
    background: var(--primary-very-low);
    border-bottom-width: 2px;
    border-radius: 3px;
    box-sizing: border-box;
    color: var(--primary);
    display: inline-flex;
    font-size: var(--font-down-1);
    justify-content: center;
    line-height: var(--line-height-large);
    margin: 0;
    min-width: 24px;
    padding: 0.15em 0.6em;
}

.tag-book kbd a,
.category-books kbd a,
.category-stories kbd a {
    padding: 0;
}

/* 뒤로 버튼에 화살표 추가 */
.tag-book kbd a::before,
.category-books kbd a::before,
.category-stories kbd a::before {
    content: "<<-";
    padding-right: 0.15em;
}

/* 또는 왼쪽 화살표에 이미지 사용 */
/*
.tag-book kbd a::before,
.category-books kbd a::before,
.category-stories kbd a::before {
    content: url('../../media/arrow-left.svg');
    display: inline-block;
    width: 12px;
    height: 12px;
}
*/


결과물은 다음과 같습니다 …

여기서 실시간으로 테스트해 볼 수 있습니다 …

네, 이게 가장 좋은 접근 방식인 것 같아요. 무한 스크롤에 대해 정확히 어떤 점이 마음에 들지 않는지 파악하면, 대화를 더 생산적인 방향으로 이끌어갈 수 있을 거예요. 누락된 기능이 있다면 그에 상응하는 기능을 찾는 게 간단할 수도 있고, 작동하지 않는 부분이 있다면 우리가 개선할 수 있는 문제일 수도 있어요. 하지만 단순히 변화 자체를 반대하는 것이라면, 우리가 할 수 있는 일은 많지 않을 겁니다.

내가 생각할 수 있는 유일한 이유는, 광고주들이 무한 스크롤 로딩이 페이지 뷰와 동일하다고 동의하지 않을 수 있으므로, 더 많은 페이지 뷰로 계산해 보려는 시도일 것이다.

@piffy 님, 그 문제로 어떤 진전이 있었나요?

무한 스크롤은 너무 중독성이 강할 수 있다고 생각합니다. 페이지네이션을 좋아하는 이유는 잠시 멈추고 계속 읽을지 스스로에게 물어볼 수 있는 시간을 주기 때문이에요. 또한 긴 토론 스레드를 관리 가능한 단위로 나누어주어, 제 뇌에 스트레스와 부담을 덜어주는 것 같아요.

트위터 이후의 마이크로블로그 플랫폼 중 하나를 좋아하는데, 이 플랫폼은 무한 스크롤 대신 페이지네이션을 사용하기로 결정했어요. 저에게는 이것이 그들이 사회적이고 건강한 소셜 미디어 접근법을 시도하고 있다는 매우 명확한 신호로 다가왔어요.

이곳이 댓글을 남기기 적절한 곳인지 확신은 없어요. 다만, 왜 일부 사용자에게 이 기능이 중요한지에 대한 혼란을 풀어주는 데 도움이 될 수 있을 것 같아서요. 아직 그런 관점을 제공하는 사람을 본 적이 없었거든요.

다른 곳에서 Discourse를 사용해봤는데, 괜찮은 플랫폼이에요. 특히 커스터마이징이 얼마나 잘 되는지 정말 인상 깊었어요(예: 좋아요 기능을 제거할 수 있다는 점, 최고죠). 하지만 페이지네이션이 없다는 점은 저에게 치명적인 단점이 될 것 같아요.

좋은 광고입니다. 하지만 이 트위터 클론은 Discourse와 아무 관련이 없으며, 페이지네이션(즉, 페이지가 길고 불안정함)의 나쁜 예입니다.

전혀 불가능한 것은 아닙니다. 몇 년 전 제대로 된 페이지네이션 플러그인을 만들어 본 적이 있습니다 (죄송하지만 오픈소스로 공개하지는 않을 겁니다). 혹시 누군가 이를 시도하고 있다면, 학습용 프로젝트로라도, 제 코드를 보고 어떤 방향으로 나아가야 할지 알려드릴 수 있습니다. 하지만 프로덕션 사이트, 특히 규모가 있는 사이트에는 사용을 권장하지 않습니다.

*수정: 제 오래된 플러그인을 다시 살펴보니, 정말로 관심이 많지 않다면 학습용 프로젝트로도 권장하지 않습니다. 어렵거든요.

광고는 아니지만, 제가 제시한 관점에 대한 주의를 덜 분산시키고 싶으시다면 어떤 플랫폼에 대해 이야기했는지 모호하게 처리해 드릴 수 있습니다.