CI / lint (push) Successful in 37s
CI / security (push) Successful in 25s
CI / test (push) Successful in 48s
CI / build (push) Successful in 21s
CI / e2e (push) Successful in 6m4s
Desktop Build / build-windows (push) Canceled after 0s
Desktop Build / build-linux (push) Canceled after 0s
80 lines
2.5 KiB
JavaScript
80 lines
2.5 KiB
JavaScript
// ObsiGate — Floating Action Button (FAB) to open/close the BooksLM AI sidebar.
|
|
// Always visible in the bottom-right corner; hides while BooksLM is open.
|
|
import booksLM from './bookslm.js';
|
|
import { state } from './state.js';
|
|
import { showToast, TabManager } from './ui.js';
|
|
import { t } from './i18n.js';
|
|
import { safeCreateIcons } from './utils.js';
|
|
|
|
let _fab = null;
|
|
|
|
// Mirror palette.js getCurrentFile(): prefer the active tab, then fall back to state.
|
|
function getCurrentFile() {
|
|
const id = TabManager._activeTabId;
|
|
if (id) {
|
|
const tab = TabManager._tabs.find((x) => x.id === id);
|
|
if (tab) return { vault: tab.vault, path: tab.path };
|
|
}
|
|
if (state.currentVault && state.currentPath) return { vault: state.currentVault, path: state.currentPath };
|
|
return null;
|
|
}
|
|
|
|
// The BooksLM panel is considered visible when it has `.open` without `.hidden`
|
|
// (the header toggle collapses it off-screen via `.hidden`).
|
|
function isBooksLmVisible() {
|
|
const panel = document.querySelector('.bookslm-panel');
|
|
return !!(panel && panel.classList.contains('open') && !panel.classList.contains('hidden'));
|
|
}
|
|
|
|
function syncVisibility() {
|
|
if (!_fab) return;
|
|
const visible = isBooksLmVisible();
|
|
_fab.hidden = visible;
|
|
const label = visible ? t('fab.close') : t('fab.open');
|
|
_fab.title = label;
|
|
_fab.setAttribute('aria-label', label);
|
|
}
|
|
|
|
async function onClick() {
|
|
const f = getCurrentFile();
|
|
if (!f) {
|
|
showToast(t('toast.no_open_file'), 'error');
|
|
return;
|
|
}
|
|
|
|
const sameDir = booksLM._isOpen && booksLM._vault === f.vault && booksLM._directory === f.path;
|
|
if (sameDir) {
|
|
// Already open for this directory: re-show a collapsed panel, or close it.
|
|
const panel = document.querySelector('.bookslm-panel');
|
|
if (panel && panel.classList.contains('hidden')) {
|
|
booksLM._toggleSidebar();
|
|
} else {
|
|
booksLM.close();
|
|
}
|
|
return;
|
|
}
|
|
|
|
await booksLM.open(f.vault, f.path);
|
|
}
|
|
|
|
export function initAIFab() {
|
|
if (_fab) return;
|
|
|
|
const btn = document.createElement('button');
|
|
btn.type = 'button';
|
|
btn.id = 'ai-fab';
|
|
btn.className = 'ai-fab';
|
|
btn.innerHTML = '<i data-lucide="bot" style="width:24px;height:24px"></i>';
|
|
document.body.appendChild(btn);
|
|
_fab = btn;
|
|
|
|
btn.addEventListener('click', onClick);
|
|
document.addEventListener('bookslm:opened', syncVisibility);
|
|
document.addEventListener('bookslm:closed', syncVisibility);
|
|
|
|
if (typeof safeCreateIcons === 'function') safeCreateIcons();
|
|
syncVisibility();
|
|
}
|
|
|
|
export default initAIFab;
|