FKB Pro - 소셜 테마

scss 코드에서 유일한 작은 문제는 줄바꿈이 자동으로 이루어지지 않아서 단어가 잘린다는 거예요 :wink:

무슨 뜻이에요? 스크린샷을 보내실 수 있나요?

내 핸드폰의 스크린샷입니다. 카테고리 이름이 전체적으로 표시되지 않는 것을 확인할 수 있습니다.

1개의 좋아요

이것은 코어에서 의도적으로 설정된 동작입니다. 단축되는 대신 카테고리 이름이 새 줄로 줄바꿈되기를 원하신다면 다음을 시도해 보세요:

.category-heading {
  &.--has-logo {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: var(--space-4);
  }
  &__content {
    min-width: 0;
    .badge-category__wrapper {
      max-width: 100%;
      white-space: normal;
      overflow-wrap: anywhere;
      .badge-category {
        &.--style-emoji,
        &.--style-icon {
          align-items: baseline;
        }
      }
    }
  }
}
3개의 좋아요

대단해요, 작동하네요! @Don 당신은 정말 최고입니다 :clap:

1개의 좋아요

태블릿 버전에는 카테고리 설명이 없지만, 모바일 버전에는 있는 것을 확인했습니다. 모바일 버전에서도 동일한 방식으로 처리하는 것이 좋다고 생각합니다. :thinking:

또한 중첩된 답변을 사용하면 아바타가 약간 크게 표시되는 작은 표시 오류가 있는 것 같습니다.

저만 그런 건지 모르겠어요?

고마워요 @gilles! 이 부분에 대한 업데이트를 병합했어요…

2개의 좋아요

테스트해봤는데 문제없어요. @Don 님, 빠른 대응 감사합니다 :clap: :+1:

1개의 좋아요

@Don 데스크톱 모드에서 사이드바 없이 PC를 사용할 때 작은 표시 버그를 발견했습니다. 참고용입니다 :wink:

1개의 좋아요

감사합니다. 여기에서 수정했습니다: FIX: Enhance category heading styles in SCSS · VaperinaDEV/fkb-pro-theme@95a3c25 · GitHub

4개의 좋아요

테스트 완료 및 승인 :+1:

1개의 좋아요

방금 이 프로그램을 설치했습니다. 설치 직후 오른쪽에 fakebook 패널이 있었던 것 같은데, 제 환경에서는 사라진 상태입니다. 어떤 설정을 건드렸는지, 어떻게 다시 표시할 수 있는지 모르겠습니다.

안녕하세요 :waving_hand: 오른쪽 하단에 이 섹션을 전환할 수 있는 버튼이 있습니다.

테마를 업데이트했습니다: DEV: Improve FKB panel and right sidebar layout handling - Pull Request #78 - VaperinaDEV/fkb-pro-theme - GitHub

2개의 좋아요

아, 있네요 – 감사합니다! 음, 실수로 누른 건가요? 아니면 모바일에서 이 내용을 열었을 때 꺼진 건가요? 몇 가지 실험을 해보고 다시 알려드리겠습니다.

1개의 좋아요

네, 모바일에서는 렌더링이 안 돼요.

아, 맞아요. 물론이죠.

제가 모바일에서 포럼을 읽을 때 데스크톱에서는 내게 비활성화된 건 아닌지 가능성이 있다고 생각했거든요. 하지만 방금 그 테스트를 해봤는데, 패널이 비활성화되지는 않았어요. 그래서 내 데스크톱에서 패널이 비활성화된 건 정말 수수께끼네요 – 아마도 실수로 비활성화 화살표를 클릭한 것 같아요.

1개의 좋아요

Don님, 안녕하세요! FKB Pro 테마를 정말 좋아하고 있습니다.

간단한 요청이 하나 있습니다. 토픽 카드에서 마지막 게시자뿐 아니라 여러 참가자의 아바타를 표시할 수 있는 설정을 추가할 수 있을까요?

단일 아바타는 매우 깔끔해 보이지만, 여러 참가자를 표시하면 토론이 얼마나 활발한지 훨씬 더 잘 전달됩니다. 이 기능을 전환할 수 있는 토글 버튼이 있다면 정말 좋겠습니다!

훌륭한 작업에 감사드립니다! Leo

@Don 님, 안녕하세요! FKB pro 테마에 대해 개인적으로 작은 수정을 하나 했습니다. 태블릿과 데스크톱에서는 오른쪽 아래에, 모바일에서는 왼쪽 아래에 채팅 플로팅 버튼을 배치했고, ‘주제 만들기’ 버튼과 동일한 효과를 적용했습니다.

제 컴포넌트 코드(CSS)는 다음과 같습니다:

/* ========================================================= */
/* 1. 메인 플로팅 버튼 (메신저/디스코드 스타일) */
/* ========================================================= */
.header-dropdown-toggle.chat-header-icon {
    position: fixed !important;
    bottom: 60px !important;
    right: 20px !important;
    z-index: 9999 !important;
    
    /* 완벽한 치수 (원형) */
    width: 60px !important;
    height: 60px !important;
    min-width: 60px !important;
    min-height: 60px !important;
    border-radius: 50% !important;
    
    /* 선명한 파란색과 컬러 섀도우 */
    background: #0084ff !important;
    box-shadow: 0 4px 14px rgba(0, 132, 255, 0.4), 0 2px 4px rgba(0, 0, 0, 0.1) !important;
    
    /* 마진 정리 */
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    padding: 0 !important;
    margin: 0 !important;
    border: none !important;
    
    /* 부드러운 전환 */
    transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275), opacity 0.3s ease, box-shadow 0.2s ease !important;
}

/* 모바일(화면 <= 640px)에서의 특정 위치 */
@media (max-width: 640px) {
    .header-dropdown-toggle.chat-header-icon {
        bottom: 80px !important; 
        left: 20px !important;   /* 오른쪽에 다시 배치하려면 right: 20px으로 변경 */
    }
}

/* 호버 효과 (가벼운 확대) */
.header-dropdown-toggle.chat-header-icon:hover {
    transform: scale(1.08) !important;
    box-shadow: 0 6px 20px rgba(0, 132, 255, 0.5), 0 4px 8px rgba(0, 0, 0, 0.15) !important;
}

/* ========================================================= */
/* 2. DISCOURSE 기본 회색 배경 제거                            */
/* ========================================================= */
.header-dropdown-toggle.chat-header-icon .icon,
.header-dropdown-toggle.chat-header-icon span:not(.badge-notification):not(.chat-badge):not([class*="unread"]):not([class*="count"]) {
    background-color: transparent !important;
    box-shadow: none !important;
    border: none !important;
}

/* ========================================================= */
/* 3. 아이콘(버블) 완벽하게 중앙 정렬                          */
/* ========================================================= */
.header-dropdown-toggle.chat-header-icon .d-icon,
.header-dropdown-toggle.chat-header-icon svg {
    position: absolute !important;
    top: 50% !important;
    left: 50% !important;
    transform: translate(-50%, -50%) !important; 
    
    margin: 0 !important;
    padding: 0 !important;
    width: 32px !important;
    height: 32px !important;
    color: #ffffff !important;
    
    filter: drop-shadow(0 2px 2px rgba(0, 0, 0, 0.1)) !important;
}

/* ========================================================= */
/* 4. 알림 배지 (초록색 카운터 + 숫자 표시)                   */
/* ========================================================= */
.header-dropdown-toggle.chat-header-icon .badge-notification,
.header-dropdown-toggle.chat-header-icon .chat-badge,
.header-dropdown-toggle.chat-header-icon .unread-notifications,
.header-dropdown-toggle.chat-header-icon [class*="badge"],
.d-header-icons .header-dropdown-toggle.chat-header-icon .badge-notification {
    position: absolute !important;
    top: -4px !important;
    right: -4px !important;
    left: auto !important;
    margin: 0 !important;
    z-index: 10 !important; 
    
    /* 강제 적용된 초록색 */
    background-color: #53A548 !important;  
    background: #53A548 !important;
    color: #ffffff !important;
    
    /* 숫자가 보이도록 강제 적용된 타이포그래피 */
    font-size: 13px !important;
    font-weight: bold !important;
    line-height: 18px !important;
    letter-spacing: normal !important;
    text-indent: 0 !important;
    
    /* 치수와 형태 */
    padding: 0 6px !important;
    min-width: 22px !important;
    height: 22px !important;
    border-radius: 50px !important;
    border: 2px solid #ffffff !important;
    box-sizing: border-box !important;
    
    /* 숫자 중앙 정렬 */
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    white-space: nowrap !important;
    overflow: visible !important;
    
    /* 초록색 펄스 애니메이션 (keyframes와 연결됨) */
    animation: badge-pulse 2s infinite !important; 
}

/* 모든 자식 요소(Discourse가 숫자를 span으로 감싸는 경우)가 표시되도록 강제 */
.header-dropdown-toggle.chat-header-icon .badge-notification *,
.header-dropdown-toggle.chat-header-icon .chat-badge *,
.header-dropdown-toggle.chat-header-icon [class*="badge"] * {
    color: #ffffff !important;
    background: transparent !important;
    display: inline-block !important;
    visibility: visible !important;
    opacity: 1 !important;
    font-size: inherit !important;
}
/* ========================================================= */
/* 5. 수정된 애니메이션 (레이더 효과 & 바운스)                 */
/* ========================================================= */

/* 5.1 - 빨간 배지 주위의 레이더 파동 (펄스) */
.header-dropdown-toggle.chat-header-icon .badge-notification,
.header-dropdown-toggle.chat-header-icon .chat-badge,
.header-dropdown-toggle.chat-header-icon .chat-channel-unread-indicator {
    animation: badge-pulse 2s infinite !important;
    transform-origin: center !important;
}

/* 5.2 - 메시지가 있을 때 파란 버튼 전체에 적용되는 바운스 효과 */
.header-dropdown-toggle.chat-header-icon:has(.badge-notification),
.header-dropdown-toggle.chat-header-icon:has(.chat-badge),
.header-dropdown-toggle.chat-header-icon:has(.chat-channel-unread-indicator) {
    animation: chat-bounce 3s infinite !important;
}

/* --- KEYFRAMES 정의 (수정 금지) --- */

/* 파동 정의: 표시 버그를 피하기 위해 box-shadow만 사용 */
@keyframes badge-pulse {
    0% {
        box-shadow: 0 0 0 0 rgba(250, 62, 62, 0.8);
    }
    70% {
        box-shadow: 0 0 0 10px rgba(250, 62, 62, 0);
    }
    100% {
        box-shadow: 0 0 0 0 rgba(250, 62, 62, 0);
    }
}

/* 바운스 정의: 버튼이 3초마다 살짝 점프 */
@keyframes chat-bounce {
    0%, 20%, 50%, 80%, 100% { 
        transform: translateY(0); 
    }
    40% { 
        transform: translateY(-6px); 
    }
    60% { 
        transform: translateY(-3px); 
    }
}
/* ========================================================= */
/* 6. 채널 목록 및 개인 메시지에서의 펄스 효과                 */
/* ========================================================= */

/* 6.1 - 목록 컨테이너의 오버플로우 허용 */
.chat-channel-row,
.chat-channel-list-item,
.chat-drawer-container .chat-channel-unread-indicator,
.chat-channel-row .chat-channel-unread-indicator {
    overflow: visible !important;
}

/* 6.2 - 표시 점의 스타일 및 마진 */
.chat-channel-row .chat-channel-unread-indicator,
.chat-channel-row .badge-notification,
.chat-channel-row .unread-indicator,
.chat-drawer-container .chat-channel-unread-indicator,
.chat-full-page .chat-channel-unread-indicator,
.chat-channel-list-item .chat-channel-unread-indicator {
    animation: list-dot-pulse 1.8s infinite !important;
    border-radius: 50% !important;
    position: relative !important;
    overflow: visible !important;
    margin: 0 6px !important; /* 텍스트와 날짜에 붙지 않도록 간격 확보 */
}

/* 6.3 - 조정된 애니메이션 (최대 6px의 더 컴팩트한 파동) */
@keyframes list-dot-pulse {
    0% {
        box-shadow: 0 0 0 0 rgba(0, 132, 255, 0.7); /* 점의 색상에 맞춰 적응 */
    }
    70% {
        box-shadow: 0 0 0 6px rgba(0, 132, 255, 0); /* 줄 안에 머물도록 반경 축소 */
    }
    100% {
        box-shadow: 0 0 0 0 rgba(0, 132, 255, 0);
    }
}

그리고 JS 코드는 다음과 같습니다:

import { apiInitializer } from "discourse/lib/api";

export default apiInitializer((api) => {
    let lastScrollTop = 0;
    let isHiddenByScroll = false;

    // 1. 스크롤 핸들러 (모바일에서만 활성)
    window.addEventListener("scroll", () => {
        const isMobile = window.innerWidth <= 640;
        const floatBtn = document.querySelector('.header-dropdown-toggle.chat-header-icon');

        if (!floatBtn) return;

        // 컴퓨터인 경우 버튼이 항상 표시되도록 확인
        if (!isMobile) {
            if (isHiddenByScroll) {
                floatBtn.style.setProperty('transform', 'translateY(0) scale(1)', 'important');
                floatBtn.style.setProperty('opacity', '1', 'important');
                isHiddenByScroll = false;
            }
            return;
        }

        const currentScrollTop = window.pageYOffset || document.documentElement.scrollTop;

        // 아래로 스크롤하는 경우 (100px 초과 시)
        if (currentScrollTop > lastScrollTop && currentScrollTop > 100) {
            if (!isHiddenByScroll) {
                floatBtn.style.setProperty('transform', 'translateY(100px) scale(0.8)', 'important');
                floatBtn.style.setProperty('opacity', '0', 'important');
                isHiddenByScroll = true;
            }
        } 
        // 위로 스크롤하는 경우
        else if (currentScrollTop < lastScrollTop) {
            if (isHiddenByScroll) {
                floatBtn.style.setProperty('transform', 'translateY(0) scale(1)', 'important');
                floatBtn.style.setProperty('opacity', '1', 'important');
                isHiddenByScroll = false;
            }
        }
        lastScrollTop = currentScrollTop <= 0 ? 0 : currentScrollTop;
    }, { passive: true });

    // 2. 기본 표시를 관리하기 위한 MutationObserver
    const observer = new MutationObserver(() => {
        const chatOpen = document.querySelector('.chat-drawer, .d-chat-floating-panel, .chat-widget, .chat-panel, .chat-out-of-container, .chat-full-page');
        const isChatRoute = window.location.pathname.startsWith('/chat');
        const hasFullPageClass = document.body.classList.contains('has-full-page-chat');
        
        const isMobile = window.innerWidth <= 640;
        const isTopicRoute = window.location.pathname.includes('/t/') || document.body.classList.contains('archetype-regular');
        const hideOnMobileTopic = isMobile && isTopicRoute;

        const floatBtn = document.querySelector('.header-dropdown-toggle.chat-header-icon');
        
        if (floatBtn) {
            if (chatOpen || isChatRoute || hasFullPageClass || hideOnMobileTopic) {
                floatBtn.style.setProperty('display', 'none', 'important');
            } else {
                floatBtn.style.setProperty('display', 'flex', 'important');
                
                // 모바일/데스크톱 위치의 깔끔한 관리
                if (isMobile) {
                    floatBtn.style.setProperty('left', '10px', 'important'); // 더 이동하려면 값 변경
                    floatBtn.style.removeProperty('right');
                } else {
                    floatBtn.style.setProperty('right', '20px', 'important');
                    floatBtn.style.removeProperty('left');
                }
            }
        }
    });

    observer.observe(document.body, { childList: true, subtree: true, attributes: true });
});