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 我在桌面模式下发现了一个小的显示 bug,在没有侧边栏的电脑端会出现这个问题,仅供参考 :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 主题做了一点个人修改,添加了一个浮动聊天按钮:在平板和桌面上位于右下角,在移动端位于左下角,并且与“创建主题”按钮具有相同的动画效果。我觉得代码上可能还有更好的写法,但目前这样是能正常工作的 :rofl:

这是我的组件代码: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;
}

/* --- 定义关键帧(请勿修改) --- */

/* 定义波纹:仅使用 box-shadow 以避免显示 bug */
@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 });
});