Obsidian插件样式:定制Note Toolbar布局以模拟Cmenu显示

Note Toolbar 它可以为不同的文件夹配置不同的工具栏,并能够在文件夹之间自适应切换,而且可以非常方便的编辑工具栏按钮。

不过我比较喜欢cmenu插件那种简洁的按钮格式,于是修改了下插件样式,可以用下面的样式定制 Note Toolbar 布局以模拟 Cmenu 显示,效果如下。

Pasted image 20250111124810

对应设置如下:

样式设置

您可以将 Note Toolbar 的显示样式更改为类似于 Cmenu 插件的样式。这种设置仅在工具栏名称中包含“cmenu”时生效。

File-20241214040035122


File-20241214045617628

  • 将工具栏的位置设置为“置顶(固定位置)”即可,其他设置保持默认。
  • 注意:目前,该设置暂不支持移动端,因此建议在移动设备上隐藏此工具栏。

:green_circle: 自带的分割符和行号符可以正常运行

CSS 样式

对应的 Style Setting 设置有如下:

File-20250106071657423

cmenu 对齐方式:flex-start、flex-end、space-around、space-between、space-evenly

Pasted image 20250106191826

图片来自《深入解析 CSS》P137 5.4.1 理解弹性容器的属性

/* @settings
name: Note Toolbar 仿 cMenu 的菜单栏
id: Note Toolbar 仿 cMenu 的菜单栏
settings:
-
  id: cmenu-note-toolbar-width
  title: cmenu宽度
  type:  variable-number
  default: 460
  format: px
- 
  id: cmenu-flex-just-content
  title: cmenu对齐方式
  description: 
  type: variable-select
  default: flex-start
  options:
      - flex-start
      - flex-end
      - space-around
      - space-between
      - space-evenly
*/

body {
  --cmenu-note-toolbar-width: 460px;
  --cmenu-flex-justily-content: flex-start;
}

/* note toolbar 像 cmenu那样显示 */
div[data-name *="cmenu"] {
  z-index: var(--layer-status-bar);
  position: absolute;
  bottom: 60px;
  width: 100% !important;
  pointer-events: none !important;
  display: flex;
  justify-content: center !important;
  background-color: transparent !important;

  div.callout, .callout-content {
    background-color: transparent !important;
    border: 0 !important;
    margin: 0 !important;
    opacity: 1 !important;
    /* width: fit-content;
    height: fit-content; */
  }

  ul[role="menu"] {
    pointer-events: auto !important;

    width: fit-content;
    max-width: var(--cmenu-note-toolbar-width);
    /* display: grid !important;
    grid-template-columns: repeat(10, minmax(0, 1fr)); */
    display: flex;
    flex-flow: row wrap;
    justify-content: var(--cmenu-flex-just-content);
    gap: 8px 5px !important;

    padding: 10px !important;
    transition: 200ms ease;
    height: auto;
    border-radius: 6px;

    z-index: var(--layer-status-bar);
    box-shadow: 0px 3px 30px rgb(31 38 135 / 15%);
    margin: 33px !important;
    border: 1px solid var(--background-modifier-border);

    /* 添加毛玻璃效果 */
    background-color: rgba(255, 255, 255, 0.1) !important;
    backdrop-filter: blur(10px);


    li {
      border-radius: 6px;
      background-color: var(--background-secondary);

      &>span {
        width: 40px;
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 6px !important;

        svg {
          transform: scale(1.2);
        }

      }

      .cg-note-toolbar-item-label {
        display: none;
      }
    }

  }

}

原文链接:PKMer_Obsidian 插件样式:修改 note toolbar 插件布局像 cmenu 那样显示

1 个赞

大佬,您好,我根据您的设计做了一些改动,使工具栏支持拖动和折叠,效果如图
image
image
image

拖动到右侧可以竖排显示

下面是调整后的css,添加了一些样式设置
/* @settings
name: Note Toolbar 仿 cMenu 的菜单栏
id: Note Toolbar 仿 cMenu 的菜单栏
settings:
-
  id: cmenu-note-toolbar-width
  title: cmenu宽度
  type:  variable-number
  default: 460
  format: px
- 
  id: cmenu-flex-just-content
  title: cmenu对齐方式
  description: 
  type: variable-select
  default: flex-start
  options:
      - flex-start
      - flex-end
      - space-around
      - space-between
      - space-evenly
*/

body {
  --cmenu-note-toolbar-width: 460px;
  --cmenu-flex-justily-content: flex-start;
}

/* note toolbar 像 cmenu那样显示 */
div[data-name *="cmenu"] {
  z-index: var(--layer-status-bar);
  position: absolute;
  bottom: 60px;
  width: 100% !important;
  pointer-events: none !important;
  display: flex;
  justify-content: center !important;
  background-color: transparent !important;

  div.callout, .callout-content {
    background-color: transparent !important;
    border: 0 !important;
    margin: 0 !important;
    opacity: 1 !important;
  }

  ul[role="menu"] {
    pointer-events: auto !important;

    width: fit-content;
    max-width: var(--cmenu-note-toolbar-width);
    display: flex;
    flex-flow: row wrap;
    justify-content: var(--cmenu-flex-just-content);
    gap: 4px !important;

    padding: 6px !important;
    transition: 200ms ease;
    height: auto;
    border-radius: 6px;

    z-index: var(--layer-status-bar);
    margin: 20px !important;
    border: 1px solid var(--background-modifier-border);

    /* 添加毛玻璃效果 */
    backdrop-filter: blur(10px);
    background-color: transparent;

    li {
      border-radius: 6px;
      background-color: var(--background-secondary);

      &>span {
        width: 30px;
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 3px !important;

        svg {
          transform: scale(1.2);
        }
      }

      .cg-note-toolbar-item-label {
        display: none;
      }
      
      /* 拖动手柄样式 - 与其他按钮保持一致 */
      &.toolbar-handle {
        background-color: var(--background-secondary) !important;
        cursor: move !important;
        order: -2;
        
        &:hover {
          background-color: var(--background-modifier-hover) !important;
        }

        &>span {
          color: var(--text-normal) !important;
        }

        /* 添加拖动图标 */
        &>span>svg {
          opacity: 0.7;
        }

        &:hover>span>svg {
          opacity: 1;
          color: var(--text-normal);
        }
      }

      /* 折叠按钮样式 - 与其他按钮保持一致 */
      &.toolbar-toggle {
        background-color: var(--background-secondary) !important;
        cursor: pointer !important;
        order: -1;
        
        &:hover {
          background-color: var(--background-modifier-hover) !important;
        }

        &>span {
          transition: transform 200ms ease;
          color: var(--text-normal) !important;
        }

        &>span>svg {
          opacity: 0.7;
        }

        &:hover>span>svg {
          opacity: 1;
        }

        &.is-collapsed>span {
          transform: rotate(180deg);
        }
      }
    }
    
    /* 折叠状态 */
    &.is-collapsed {
      li:not(.toolbar-handle):not(.toolbar-toggle) {
        display: none !important;
      }
    }
    
    /* 拖动状态 */
    &.is-dragging {
      z-index: calc(var(--layer-status-bar) + 10);
    }
  }
  
  /* 自定义位置 */
  &.has-custom-position {
    position: fixed !important;
    bottom: auto !important;
    justify-content: flex-start !important;
    width: auto !important;
    
    ul[role="menu"] {
      margin: 0 !important;
    }
  }
}

/* 响应式适配 */
@media (max-width: 768px) {
  div[data-name *="cmenu"] ul[role="menu"] {
    max-width: calc(100vw - 40px);
    margin: 15px !important;
    padding: 5px !important;
  }
}

/* 防止拖动时选中文本 */
body.dragging-toolbar {
  user-select: none !important;
  -webkit-user-select: none !important;
}
下面是JavaScript脚本,放在库中即可
// 工具栏增强脚本 - 最简单直接的拖动实现
(function() {
    'use strict';
    
    let toolbar = null;
    let container = null;
    let isDragging = false;
    let lastX = 0;
    let lastY = 0;
    let isCollapsed = false;
    
    function init() {
        console.log('🔧 初始化工具栏增强');
        findToolbar();
        
        const observer = new MutationObserver(() => {
            if (!document.querySelector('.toolbar-handle')) {
                setTimeout(findToolbar, 1000);
            }
        });
        observer.observe(document.body, { childList: true, subtree: true });
    }
    
    function findToolbar() {
        container = document.querySelector('div[data-name*="cmenu"]');
        toolbar = container?.querySelector('ul[role="menu"]');
        
        if (!toolbar) {
            setTimeout(findToolbar, 1000);
            return;
        }
        
        if (!toolbar.querySelector('.toolbar-handle')) {
            createButtons();
        } else {
            bindExisting();
        }
    }
    
    function createButtons() {
        // 拖动手柄
        const handle = document.createElement('li');
        handle.className = 'toolbar-handle';
        handle.innerHTML = `<span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="9" cy="12" r="1"/><circle cx="9" cy="5" r="1"/><circle cx="9" cy="19" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="15" cy="5" r="1"/><circle cx="15" cy="19" r="1"/></svg></span>`;
        
        // 折叠按钮
        const toggle = document.createElement('li');
        toggle.className = 'toolbar-toggle';
        toggle.innerHTML = `<span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6,9 12,15 18,9"/></svg></span>`;
        
        toolbar.insertBefore(toggle, toolbar.firstChild);
        toolbar.insertBefore(handle, toolbar.firstChild);
        
        bindEvents(handle, toggle);
        console.log('✅ 按钮已创建');
    }
    
    function bindExisting() {
        const handle = toolbar.querySelector('.toolbar-handle');
        const toggle = toolbar.querySelector('.toolbar-toggle');
        bindEvents(handle, toggle);
        console.log('✅ 重新绑定按钮');
    }
    
    function bindEvents(handle, toggle) {
        // 拖动开始
        handle.addEventListener('mousedown', function(e) {
            e.preventDefault();
            e.stopPropagation();
            
            isDragging = true;
            lastX = e.clientX;
            lastY = e.clientY;
            
            // 首次拖动时,计算并存储容器内边距导致的偏移
            if (!container.dataset.offsetX) {
                const toolbarInContainer = container.querySelector('ul[role="menu"]');
                if (toolbarInContainer) {
                    const containerRect = container.getBoundingClientRect();
                    const toolbarRect = toolbarInContainer.getBoundingClientRect();
                    container.dataset.offsetX = (toolbarRect.left - containerRect.left).toString();
                    container.dataset.offsetY = (toolbarRect.top - containerRect.top).toString();
                } else {
                    container.dataset.offsetX = '0';
                    container.dataset.offsetY = '0';
                }
            }

            // 只在第一次拖动时切换到固定定位
            if (!container.classList.contains('has-custom-position')) {
                const rect = container.getBoundingClientRect();
                container.classList.add('has-custom-position');
                container.style.left = rect.left + 'px';
                container.style.top = rect.top + 'px';
            }
            
            toolbar.classList.add('is-dragging');
            document.body.classList.add('dragging-toolbar');
            
            console.log('🎯 开始拖动');
        });
        
        // 折叠功能
        toggle.addEventListener('click', function(e) {
            e.preventDefault();
            e.stopPropagation();
            
            isCollapsed = !isCollapsed;
            
            if (isCollapsed) {
                toolbar.classList.add('is-collapsed');
                toggle.classList.add('is-collapsed');
            } else {
                toolbar.classList.remove('is-collapsed');
                toggle.classList.remove('is-collapsed');
            }
            
            console.log('🔄 切换折叠');
        });
        
        // 防止默认行为
        handle.ondragstart = () => false;
        handle.onselectstart = () => false;
    }
    
    // 全局鼠标移动 - 使用相对移动
    document.addEventListener('mousemove', function(e) {
        if (!isDragging) return;
        
        // 计算鼠标移动的距离
        const deltaX = e.clientX - lastX;
        const deltaY = e.clientY - lastY;
        
        // 更新记录的鼠标位置
        lastX = e.clientX;
        lastY = e.clientY;
        
        // 获取当前位置
        const currentLeft = parseInt(container.style.left) || 0;
        const currentTop = parseInt(container.style.top) || 0;
        
        // 计算新位置
        let newLeft = currentLeft + deltaX;
        let newTop = currentTop + deltaY;

        // --- 智能边界检测 ---
        const rootEl = document.documentElement;
        const leftSidebar = document.querySelector('.mod-left-split');
        const rightSidebar = document.querySelector('.mod-right-split');
        const titleBar = document.querySelector('.workspace-tabs'); 
        const statusBar = document.querySelector('.status-bar');

        const bounds = {
            left: leftSidebar && leftSidebar.classList.contains('is-open') ? leftSidebar.getBoundingClientRect().right : (document.querySelector('.workspace-ribbon')?.getBoundingClientRect().right || 0),
            right: rightSidebar && rightSidebar.classList.contains('is-open') ? rightSidebar.getBoundingClientRect().left : rootEl.clientWidth,
            top: titleBar ? titleBar.getBoundingClientRect().bottom : 0,
            bottom: statusBar ? statusBar.getBoundingClientRect().top : rootEl.clientHeight
        };
        
        // 获取容器尺寸和内边距偏移
        const containerRect = container.getBoundingClientRect();
        const offsetX = parseFloat(container.dataset.offsetX) || 0;
        const offsetY = parseFloat(container.dataset.offsetY) || 0;

        // 边界限制 (考虑内边距补偿)
        const minLeft = bounds.left - offsetX;
        const maxLeft = bounds.right - containerRect.width;
        const minTop = bounds.top - offsetY;
        const maxTop = bounds.bottom - containerRect.height;

        newLeft = Math.max(minLeft, Math.min(newLeft, maxLeft));
        newTop = Math.max(minTop, Math.min(newTop, maxTop));
        
        // 应用新位置
        container.style.left = newLeft + 'px';
        container.style.top = newTop + 'px';
    });
    
    // 全局鼠标释放
    document.addEventListener('mouseup', function() {
        if (!isDragging) return;
        
        isDragging = false;
        toolbar.classList.remove('is-dragging');
        document.body.classList.remove('dragging-toolbar');
        
        console.log('✅ 拖动结束');
    });
    
    // 重置功能
    window.resetToolbar = function() {
        container.classList.remove('has-custom-position');
        container.style.left = '';
        container.style.top = '';
        toolbar.classList.remove('is-collapsed');
        const toggle = document.querySelector('.toolbar-toggle');
        if (toggle) toggle.classList.remove('is-collapsed');
        isCollapsed = false;
        console.log('🔄 工具栏已重置');
    };
    
    init();
    console.log('✅ 工具栏增强脚本加载完成');
})();
2 个赞

厉害厉害 收藏了