diff --git a/CLAUDE.md b/CLAUDE.md
index a7c2285..ead826e 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -65,12 +65,13 @@ The extension exposes these REST endpoints:
- Active note tracking with tab highlighting
- Content persistence across sidebar open/close cycles
- Real-time tab rendering on note operations
-- Button layout: Save/Rename/LoRA submenu on left, Refresh/Delete on right
+- Button layout: Save/Rename/LoRA submenu on left, Delete on right, Zoom in/out and Refresh in tabs area
- **Search Functionality**: Live search through note content with highlighted results and line navigation
- **Unsaved Changes Tracking**: Visual indicators (*) for modified notes
- **Content Preservation**: Tab switching preserves unsaved content
- **Change Detection**: Automatic tracking of modifications vs saved state
- **Append Integration**: Submenu with three formatting options for appending LoRA lists (extensible for other content types)
+- **Font Size Control**: Zoom in/out buttons with persistent settings storage (8-24px range)
### Search Functionality
- **Search Input**: Located below button container with "Search lines..." placeholder
diff --git a/js/extension.js b/js/extension.js
index 64b4f99..563df44 100644
--- a/js/extension.js
+++ b/js/extension.js
@@ -24,6 +24,8 @@ class NotesSidebar {
this.searchResults = null;
this.isInitialized = false;
this.sidebarElement = null;
+ this.currentFontSize = app.extensionManager.setting.get('Notes Sidebar.Font Size') || 14;
+ this.leftButtonContainer = null;
// Listen to state changes
this.store.addEventListener('stateChanged', (event) => {
@@ -162,15 +164,41 @@ class NotesSidebar {
this.tabsContainer.appendChild(newTabBtn);
- // Right side: refresh button
+ // Right side: zoom controls and refresh button
+ const rightControls = document.createElement('div');
+ rightControls.style.display = 'flex';
+ rightControls.style.gap = '10px';
+
+ // Zoom button group
+ const zoomButtonGroup = document.createElement('div');
+ zoomButtonGroup.className = 'notes-button-group';
+
+ const zoomOutBtn = document.createElement('button');
+ zoomOutBtn.innerHTML = '';
+ zoomOutBtn.className = 'notes-btn';
+ zoomOutBtn.title = 'Zoom Out';
+ zoomOutBtn.onclick = () => this.zoomOut();
+
+ const zoomInBtn = document.createElement('button');
+ zoomInBtn.innerHTML = '';
+ zoomInBtn.className = 'notes-btn';
+ zoomInBtn.title = 'Zoom In';
+ zoomInBtn.onclick = () => this.zoomIn();
+
+ zoomButtonGroup.appendChild(zoomOutBtn);
+ zoomButtonGroup.appendChild(zoomInBtn);
+
const refreshBtn = document.createElement('button');
refreshBtn.innerHTML = '';
refreshBtn.className = 'notes-btn refresh';
refreshBtn.title = 'Refresh';
refreshBtn.onclick = () => this.refreshNotes();
+ rightControls.appendChild(zoomButtonGroup);
+ rightControls.appendChild(refreshBtn);
+
tabsWrapper.appendChild(this.tabsContainer);
- tabsWrapper.appendChild(refreshBtn);
+ tabsWrapper.appendChild(rightControls);
parent.appendChild(tabsWrapper);
}
@@ -178,8 +206,8 @@ class NotesSidebar {
const buttonContainer = document.createElement('div');
buttonContainer.className = 'notes-button-container';
- const leftButtonContainer = document.createElement('div');
- leftButtonContainer.className = 'notes-button-group';
+ this.leftButtonContainer = document.createElement('div');
+ this.leftButtonContainer.className = 'notes-button-group';
const rightButtonContainer = document.createElement('div');
rightButtonContainer.className = 'notes-button-group';
@@ -205,12 +233,12 @@ class NotesSidebar {
this.deleteBtn.onclick = () => this.deleteActiveNote();
this.deleteBtn.disabled = true;
- leftButtonContainer.appendChild(this.saveBtn);
- leftButtonContainer.appendChild(this.renameBtn);
+ this.leftButtonContainer.appendChild(this.saveBtn);
+ this.leftButtonContainer.appendChild(this.renameBtn);
// Append menu will be added later after textarea is created
rightButtonContainer.appendChild(this.deleteBtn);
- buttonContainer.appendChild(leftButtonContainer);
+ buttonContainer.appendChild(this.leftButtonContainer);
buttonContainer.appendChild(rightButtonContainer);
parent.appendChild(buttonContainer);
@@ -254,6 +282,9 @@ class NotesSidebar {
this.textArea.className = 'notes-textarea';
this.textArea.placeholder = 'Select a note to start editing...';
+ // Apply saved font size
+ this.updateFontSize();
+
// Initialize as disabled (will be enabled reactively if there's an active note)
this.textArea.disabled = true;
@@ -267,9 +298,8 @@ class NotesSidebar {
this.appendMenu = new AppendMenu(this.textArea, () => this.onTextAreaChange());
// Add append menu to the left button container
- const leftButtonContainer = this.sidebarElement.querySelector('.notes-button-group');
- if (leftButtonContainer) {
- leftButtonContainer.appendChild(this.appendMenu.createMenuElements());
+ if (this.leftButtonContainer) {
+ this.leftButtonContainer.appendChild(this.appendMenu.createMenuElements());
}
this.contentArea.appendChild(this.textArea);
@@ -599,6 +629,28 @@ class NotesSidebar {
});
}
+ zoomIn() {
+ if (this.currentFontSize < 24) { // Max font size
+ this.currentFontSize += 1;
+ this.updateFontSize();
+ }
+ }
+
+ zoomOut() {
+ if (this.currentFontSize > 8) { // Min font size
+ this.currentFontSize -= 1;
+ this.updateFontSize();
+ }
+ }
+
+ updateFontSize() {
+ if (this.textArea) {
+ this.textArea.style.fontSize = `${this.currentFontSize}px`;
+ }
+ // Save to settings
+ app.extensionManager.setting.set('Notes Sidebar.Font Size', this.currentFontSize);
+ }
+
}
@@ -617,6 +669,17 @@ app.registerExtension({
{ value: "both", text: "Ctrl+S (note + workflow)" }
],
defaultValue: "note_only"
+ },
+ {
+ id: "Notes Sidebar.Font Size",
+ name: "Notes Font Size",
+ type: "slider",
+ attrs: {
+ min: 8,
+ max: 24,
+ step: 1
+ },
+ defaultValue: 14
}
],
async setup() {
diff --git a/js/notes-sidebar.css b/js/notes-sidebar.css
index b3e89aa..6f3318b 100644
--- a/js/notes-sidebar.css
+++ b/js/notes-sidebar.css
@@ -142,6 +142,23 @@
border-right: none;
}
+.notes-btn:first-child {
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+}
+
+.notes-btn:last-child {
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+}
+
+.notes-submenu-container:last-child .notes-btn {
+ border-top-left-radius: 0px;
+ border-bottom-left-radius: 0px;
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+}
+
/* Refresh button is standalone and needs group-like styling */
.notes-btn.refresh {
border: 1px solid #444;
@@ -154,14 +171,11 @@
display: inline-block;
}
-.notes-submenu-container .notes-btn {
- border-right: 1px solid #444;
-}
-
-.notes-submenu-container .notes-btn:last-child {
+.notes-submenu-container:last-child .notes-btn {
border-right: none;
}
+
.notes-submenu {
position: absolute;
top: calc(100% + 2px);