feat(bookslm): bouton toggle cacher/afficher la sidebar dans le header
CI / lint (push) Successful in 37s
CI / security (push) Successful in 24s
CI / test (push) Successful in 49s
CI / build (push) Successful in 22s
CI / e2e (push) Successful in 6m16s
Desktop Build / build-windows (push) Canceled after 0s
Desktop Build / build-linux (push) Canceled after 0s
CI / lint (push) Successful in 37s
CI / security (push) Successful in 24s
CI / test (push) Successful in 49s
CI / build (push) Successful in 22s
CI / e2e (push) Successful in 6m16s
Desktop Build / build-windows (push) Canceled after 0s
Desktop Build / build-linux (push) Canceled after 0s
Même mécanisme que le sidebar de navigation gauche : - Bouton .bookslm-btn-toggle dans le header (icône panel-right-close/open) - Toggle la classe .hidden sur le panel, persiste dans localStorage - État restauré au prochain open() - Le panel reste monté (pas de teardown), juste slid off-screen - CSS : .bookslm-panel.open.hidden → translateX(100%) - CSS : .bookslm-btn-toggle suit le pattern .sidebar-toggle-btn i18n : bookslm.toggle_sidebar ajouté (fr + en) Import safeCreateIcons ajouté pour rafraîchir l'icône Lucide au toggle. Vérifié : - pytest : 504 passed (zéro régression) - ruff : All checks passed - frontend unit : 7 passed - validate-imports : 30 modules / 204 exports - pane-manager JSDOM : 9/9
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
// BooksLM — Directory-scoped AI chat panel (style NotebookLM)
|
||||
import { t } from './i18n.js';
|
||||
import { buildAIPickerUI } from './ai.js';
|
||||
import { safeCreateIcons } from './utils.js';
|
||||
|
||||
class BooksLM {
|
||||
constructor() {
|
||||
@@ -43,6 +44,14 @@ class BooksLM {
|
||||
// Open with animation
|
||||
requestAnimationFrame(() => {
|
||||
this._panel.classList.add('open');
|
||||
// Apply persisted hidden state (user toggled off in a previous session)
|
||||
try {
|
||||
const savedHidden = localStorage.getItem('obsigate-bookslm-hidden');
|
||||
if (savedHidden === 'true') {
|
||||
this._panel.classList.add('hidden');
|
||||
this._updateToggleIcon();
|
||||
}
|
||||
} catch { /* */ }
|
||||
});
|
||||
this._isOpen = true;
|
||||
|
||||
@@ -77,6 +86,39 @@ class BooksLM {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the BooksLM sidebar visibility (collapsed/hidden to the right edge
|
||||
* while the panel stays mounted). The state is persisted in localStorage so
|
||||
* the user choice survives page reloads — same UX as the left sidebar toggle.
|
||||
*
|
||||
* The panel stays in the DOM (no teardown); only a CSS transform is applied,
|
||||
* which is what makes this fast and matches the right-sidebar pattern in
|
||||
* ObsiGate.
|
||||
*/
|
||||
_toggleSidebar() {
|
||||
if (!this._panel) return;
|
||||
const isHidden = this._panel.classList.toggle('hidden');
|
||||
try {
|
||||
localStorage.setItem('obsigate-bookslm-hidden', isHidden ? 'true' : 'false');
|
||||
} catch { /* */ }
|
||||
this._updateToggleIcon();
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap the toggle icon between "panel-right-close" (visible) and
|
||||
* "panel-right-open" (hidden) so the button visually reflects the state.
|
||||
*/
|
||||
_updateToggleIcon() {
|
||||
if (!this._panel) return;
|
||||
const btn = this._panel.querySelector('.bookslm-btn-toggle');
|
||||
if (!btn) return;
|
||||
const isHidden = this._panel.classList.contains('hidden');
|
||||
const icon = btn.querySelector('i[data-lucide]');
|
||||
if (!icon) return;
|
||||
icon.setAttribute('data-lucide', isHidden ? 'panel-right-open' : 'panel-right-close');
|
||||
if (typeof safeCreateIcons === 'function') safeCreateIcons();
|
||||
}
|
||||
|
||||
newConversation() {
|
||||
this._messages = [];
|
||||
this._saveHistory();
|
||||
@@ -117,6 +159,9 @@ class BooksLM {
|
||||
panel.className = 'bookslm-panel';
|
||||
panel.innerHTML = `
|
||||
<div class="bookslm-header">
|
||||
<button class="bookslm-btn-toggle" title="${t('bookslm.toggle_sidebar')}" aria-label="${t('bookslm.toggle_sidebar')}">
|
||||
<i data-lucide="panel-right-close" style="width:16px;height:16px"></i>
|
||||
</button>
|
||||
<span>📚</span>
|
||||
<span class="bookslm-title"></span>
|
||||
<span class="bookslm-picker-host" style="margin-left:auto"></span>
|
||||
@@ -144,6 +189,7 @@ class BooksLM {
|
||||
panel.querySelector('.bookslm-btn-close').addEventListener('click', () => this.close());
|
||||
panel.querySelector('.bookslm-btn-new').addEventListener('click', () => this.newConversation());
|
||||
panel.querySelector('.bookslm-btn-export').addEventListener('click', () => this.exportConversation());
|
||||
panel.querySelector('.bookslm-btn-toggle').addEventListener('click', () => this._toggleSidebar());
|
||||
panel.querySelector('.bookslm-btn-fullscreen').addEventListener('click', () => {
|
||||
this._isFullscreen = !this._isFullscreen;
|
||||
panel.classList.toggle('fullscreen', this._isFullscreen);
|
||||
|
||||
Reference in New Issue
Block a user