设置的窗口 怎么悬浮?

受到 @knight 大佬的启发(参见#19),我实现了这个功能。

已封装为插件,更好的兼容性和更多功能,参见:开发了一个设置面板悬浮的插件

效果:

方法:

  1. 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;
}
  1. 新建一个dataviewjs文件,比如panels/设置面板.md,代码如下
```dataviewjs
// 把设置面板转换为悬浮窗
dv.el('div', app.setting.modalEl.parentElement);
```

没错,就只有一句话

  1. 新建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默认的的设置面板共存,不冲突。

  1. 更进一步,如果我想点击左下角的设置按钮也弹出悬浮面板该怎么办呢?

首先,新建一个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,点设置按钮,悬浮设置面板已经弹出了。

注意:代码中,:point_down: 指向的位置需要根据情况改成你自己的。

至此,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的脚本
```

如图

结束。

5 个赞