受到 @knight 大佬的启发(参见#19),我实现了这个功能。
已封装为插件,更好的兼容性和更多功能,参见:开发了一个设置面板悬浮的插件
效果:
方法:
- css片段增加如下样式
/* 隐藏原设置窗口的背景遮罩和关闭按钮 */
.float-settings-popover :is(.modal-bg, .modal-close-button) {
display: none;
}
/* 修改默认原设置窗口的宽高以适应hoverEditor */
.float-settings-popover .modal.mod-sidebar-layout {
max-width: 100%;
max-height: 100%;
width: 100%;
height: 100%;
border: 0;
border-radius: none;
}
/* 不显示popover右侧滚动条 */
.float-settings-popover .markdown-preview-view::-webkit-scrollbar{
display: none;
}
- 新建一个dataviewjs文件,比如panels/设置面板.md,代码如下
```dataviewjs
// 把设置面板转换为悬浮窗
dv.el('div', app.setting.modalEl.parentElement);
```
没错,就只有一句话
- 新建quickadd capture,如图
capture的内容如下
```js quickadd
// 设置面板路径,这里的路径改成 👇 你自己的
const settingPanelPath = "panels/设置面板.md";
// 窗口默认宽度
const defaultWidth = 932.667;
// 窗口默认高度
const defaultHeight = 583.333;
// 获取hoverEditor对象
const hoverEditor = app.plugins.plugins['obsidian-hover-editor'];
if(!hoverEditor){
new Notice("Hover Editor插件未安装或未开启");
return;
}
const onShow = () => {
// 获取当前悬浮窗实例
const lastPopover = hoverEditor.activePopovers.last();
// 设置弹窗样式
const setPopoverStyle = () => {
lastPopover.hoverEl.classList.add('float-settings-popover')
lastPopover.hoverEl.style.width = defaultWidth+'px';
lastPopover.hoverEl.style.height = defaultHeight+'px';
//lastPopover.hoverEl.style.overflow='hidden';
const top = (window.innerHeight - defaultHeight)/2;
lastPopover.hoverEl.style.top = (top > 0 ? top : 0) + 'px';
const left = (window.innerWidth -defaultWidth)/2;
lastPopover.hoverEl.style.left= (left > 0 ? left : 0) + 'px';
}
setPopoverStyle();
// 悬浮窗隐藏事件
const onHide = function(){
var a;
this.oldPopover = null,
((a = this.parent) == null ? void 0 : a.hoverPopover) === this && (this.parent.hoverPopover = null);
// 恢复原设置窗口
app.setting.close();
};
// 绑定onHide到刚打开的悬浮窗实例上
lastPopover.onHide = onHide.bind(lastPopover)
}
// 打开设置面板
if(document.querySelector('.float-settings-popover')) return;
app.setting.openTabById(app.setting.lastTabId||"about");
hoverEditor.spawnPopover(undefined, onShow).openFile(app.vault.getAbstractFileByPath(settingPanelPath), {state:{mode:"preview"}});
```
点亮这个闪电按钮,会在ob命令面板中把你刚才的capture注册为命令,然后使用起来就更方便了。另外,如果想使用第4步,这个操作也是必须的。
到这里,你就可以通过刚才新建的命令,使用设置悬浮面板了,这个设置悬浮面板和ob默认的的设置面板共存,不冲突。
- 更进一步,如果我想点击左下角的设置按钮也弹出悬浮面板该怎么办呢?
首先,新建一个quickadd宏,如下图
然后,在宏中新建一个capture即可
这个capture的内容是
```js quickadd
// 手机端不需要
if(app.isMobile) return;
// 你刚才设定的打开悬浮设置窗口的命令名称 👇 注意,QuickAdd: 前缀是必须的
const commandName = "QuickAdd: open floating settings";
// 获取旧设置按钮
const settingText = moment.locale() === 'zh-cn' ? '设置' : (moment.locale() === 'zh-tw' ? '設定' : 'Settings');
let settingBtn = app.workspace.leftRibbon.containerEl.querySelector("[aria-label="+settingText+"]");
if(!settingBtn) settingBtn = app.workspace.leftRibbon.containerEl.querySelector(".side-dock-settings").lastElementChild;
if(!settingBtn) {
new Notice("未找到设置按钮");
return;
}
// 深拷贝旧设置按钮,为了消除旧设置按钮的点击事件
const newSettingBtn = settingBtn.cloneNode(true);
settingBtn.parentNode.replaceChild(newSettingBtn, settingBtn);
// 通过命令名称执行命令,注意,多个名称相同时,只获取第一个
const executeQuickAddCommandByName = (name)=>{
const commands = app.commands.listCommands().filter(f=>f.id.startsWith("quickadd:choice:") && f.name===name);
if(commands.length === 0) return;
app.commands.executeCommand(commands[0]);
}
// 给新设置按钮绑定点击事件
newSettingBtn.addEventListener('click',()=>{
app.setting.openTabById(app.setting.lastTabId||"about");
executeQuickAddCommandByName(commandName);
});
```
也可以使用下面这段代码,下面这段代码通过重写app.setting.open
函数实现,不需要重置设置按钮,兼容性更好。(推荐)
```js quickadd
// 手机端不需要
if(app.isMobile) return;
// 你刚才设定的打开悬浮设置窗口的命令名称 👇
const commandName = "QuickAdd: open floating settings";
// 通过命令名称执行命令,注意,多个名称相同时,只获取第一个
const executeQuickAddCommandByName = (name)=>{
const commands = app.commands.listCommands().filter(f=>f.id.startsWith("quickadd:choice:") && f.name===name);
if(commands.length === 0) return;
app.commands.executeCommand(commands[0]);
}
// 给新设置按钮绑定点击事件
app.setting.open = ()=>{
app.setting.openTabById(app.setting.lastTabId||"about");
executeQuickAddCommandByName(commandName);
};
```
然后,点击宏管理,开启加载时自动执行,如图
重启obsidian,点设置按钮,悬浮设置面板已经弹出了。
注意:代码中, 指向的位置需要根据情况改成你自己的。
至此,quickadd实现方式已全部结束。
另外,也可以用RunJS插件实现,点这里查看
RunJS插件实现更简单,区别是把代码中的QuickAdd:前缀改为RunJS:前缀,及quickadd:choice:前缀改为runjs:command,RunJS方式简单易操作。只需要新建runjs文件比如,runjs/floating-settings.md,然后把3和4的代码分别输入其中,然后在runjs配置中设置步骤3的脚本为命令,步骤4的脚本为加载时执行即可。
runjs代码用法如下
```js RunJS="open floating settings"
//这里填入步骤3的脚本
```
```js RunJS="listen settings button onload"
//这里填入步骤4的脚本
```
如图
结束。