From b6db59c593b3ae2c5967685aa8d0f32e72dc52b4 Mon Sep 17 00:00:00 2001 From: Aleix Date: Fri, 16 May 2025 15:47:51 +0200 Subject: [PATCH] refactor: add components folder with statusBar --- components/statusBar/status-bar-controller.ts | 107 +++++++++++ components/statusBar/status-bar-view.ts | 107 +++++++++++ main.ts | 6 +- services/status-service.ts | 9 +- ui/components/status-bar.ts | 169 ------------------ 5 files changed, 221 insertions(+), 177 deletions(-) create mode 100644 components/statusBar/status-bar-controller.ts create mode 100644 components/statusBar/status-bar-view.ts delete mode 100644 ui/components/status-bar.ts diff --git a/components/statusBar/status-bar-controller.ts b/components/statusBar/status-bar-controller.ts new file mode 100644 index 0000000..72098bf --- /dev/null +++ b/components/statusBar/status-bar-controller.ts @@ -0,0 +1,107 @@ +import { NoteStatusSettings } from '../../models/types'; +import { StatusService } from '../../services/status-service'; +import { StatusBarView } from './status-bar-view'; + +/** + * Controller for the status bar + */ +export class StatusBarController { + private view: StatusBarView; + private settings: NoteStatusSettings; + private statusService: StatusService; + private currentStatuses: string[] = ['unknown']; + + constructor(statusBarEl: HTMLElement, settings: NoteStatusSettings, statusService: StatusService) { + this.view = new StatusBarView(statusBarEl); + this.settings = settings; + this.statusService = statusService; + + // Register right-click handler for force refresh + this.setupContextMenu(statusBarEl); + + this.update(['unknown']); + } + + /** + * Set up right-click context menu for force refresh + */ + private setupContextMenu(element: HTMLElement): void { + element.addEventListener('contextmenu', (e) => { + e.preventDefault(); + window.dispatchEvent(new CustomEvent('note-status:force-refresh')); + }); + } + + /** + * Update the status bar with new statuses + */ + public update(statuses: string[]): void { + this.currentStatuses = statuses; + this.render(); + } + + /** + * Render the status bar + */ + private render(): void { + this.view.reset(); + + if (!this.settings.showStatusBar) { + this.view.hide(); + return; + } + + if (!this.settings.useMultipleStatuses) { + this.renderStatuses([this.currentStatuses[0]]); + } else { + this.renderStatuses(this.currentStatuses); + } + + this.handleAutoHide(); + } + + /** + * Render statuses - handles both single and multiple status cases + */ + private renderStatuses(statuses: string[]): void { + const statusDetails = statuses.map(status => { + const statusObj = this.statusService.getAllStatuses().find(s => s.name === status); + return { + name: status, + icon: this.statusService.getStatusIcon(status), + tooltipText: statusObj?.description ? `${status} - ${statusObj.description}` : status + }; + }); + + this.view.renderStatuses(statusDetails); + } + + /** + * Handle auto-hide behavior + */ + private handleAutoHide(): void { + const onlyUnknown = this.currentStatuses.length === 1 && + this.currentStatuses[0] === 'unknown'; + + if (this.settings.autoHideStatusBar && onlyUnknown) { + this.view.hide(); + } else { + this.view.show(); + } + } + + /** + * Update settings reference + */ + public updateSettings(settings: NoteStatusSettings): void { + this.settings = settings; + this.render(); + } + + /** + * Clean up when plugin is unloaded + */ + public unload(): void { + this.view.destroy(); + } +} \ No newline at end of file diff --git a/components/statusBar/status-bar-view.ts b/components/statusBar/status-bar-view.ts new file mode 100644 index 0000000..8dc46f3 --- /dev/null +++ b/components/statusBar/status-bar-view.ts @@ -0,0 +1,107 @@ +import { setTooltip } from 'obsidian'; + +/** + * Renders the status bar UI + */ +export class StatusBarView { + private element: HTMLElement; + + constructor(element: HTMLElement) { + this.element = element; + this.element.addClass('note-status-bar'); + } + + /** + * Clears the element and resets CSS classes + */ + reset(): void { + this.element.empty(); + this.element.removeClass('left', 'hidden', 'auto-hide', 'visible'); + this.element.addClass('note-status-bar'); + } + + /** + * Hide the status bar + */ + hide(): void { + this.element.addClass('hidden'); + this.element.removeClass('visible'); + } + + /** + * Show the status bar + */ + show(): void { + this.element.removeClass('hidden'); + this.element.addClass('visible'); + } + + + renderStatuses(statuses: Array<{name: string, icon: string, tooltipText: string}>): void { + if (statuses.length === 1) { + this.renderSingleStatus(statuses[0].name, statuses[0].icon, statuses[0].tooltipText); + } else { + this.renderMultipleStatuses(statuses); + } + } + + /** + * Render a single status + */ + private renderSingleStatus(status: string, icon: string, tooltipText: string): void { + const statusText = this.element.createEl('span', { + text: `Status: ${status}`, + cls: `note-status-${status}` + }); + setTooltip(statusText, tooltipText); + + const statusIcon = this.element.createEl('span', { + text: icon, + cls: `note-status-icon status-${status}` + }); + setTooltip(statusIcon, tooltipText); + } + + /** + * Render multiple statuses + */ + private renderMultipleStatuses(statuses: Array<{name: string, icon: string, tooltipText: string}>): void { + this.element.createEl('span', { + text: 'Statuses: ', + cls: 'note-status-label' + }); + + const badgesContainer = this.element.createEl('span', { + cls: 'note-status-badges' + }); + + statuses.forEach(status => this.createStatusBadge(badgesContainer, status)); + } + + /** + * Create a status badge for multiple status display + */ + private createStatusBadge(container: HTMLElement, status: {name: string, icon: string, tooltipText: string}): void { + const badge = container.createEl('span', { + cls: `note-status-badge status-${status.name}` + }); + setTooltip(badge, status.tooltipText); + + badge.createEl('span', { + text: status.icon, + cls: 'note-status-badge-icon' + }); + + badge.createEl('span', { + text: status.name, + cls: 'note-status-badge-text' + }); + } + + /** + * Clean up the element + */ + destroy(): void { + this.element.empty(); + } +} \ No newline at end of file diff --git a/main.ts b/main.ts index 1aa13f6..4af3dcd 100644 --- a/main.ts +++ b/main.ts @@ -12,7 +12,6 @@ import { StatusService } from './services/status-service'; import { StyleService } from './services/style-service'; // UI Components -import { StatusBar } from './ui/components/status-bar'; import { StatusDropdown } from './ui/components/status-dropdown'; import { StatusPaneView } from './ui/components/status-pane-view'; import { ExplorerIntegration } from './ui/integrations/explorer-integration'; @@ -20,6 +19,7 @@ import { StatusContextMenu } from './ui/menus/status-context-menu'; // Settings import { NoteStatusSettingTab } from './settings/settings-tab'; +import { StatusBarController } from 'components/statusBar/status-bar-controller'; /** * Main plugin class for Note Status functionality @@ -28,7 +28,7 @@ export default class NoteStatus extends Plugin { settings: NoteStatusSettings; statusService: StatusService; styleService: StyleService; - statusBar: StatusBar; + statusBar: StatusBarController; statusDropdown: StatusDropdown; explorerIntegration: ExplorerIntegration; statusContextMenu: StatusContextMenu; @@ -105,7 +105,7 @@ export default class NoteStatus extends Plugin { */ private initializeUI(): void { // Init basic UI components - this.statusBar = new StatusBar(this.addStatusBarItem(), this.settings, this.statusService); + this.statusBar = new StatusBarController(this.addStatusBarItem(), this.settings, this.statusService); this.statusDropdown = new StatusDropdown(this.app, this.settings, this.statusService); // Initialize explorer integration with a slight delay to ensure UI elements are ready diff --git a/services/status-service.ts b/services/status-service.ts index 487737d..c63c1d3 100644 --- a/services/status-service.ts +++ b/services/status-service.ts @@ -383,11 +383,10 @@ export class StatusService { // General UI refresh window.dispatchEvent(new CustomEvent('note-status:refresh-ui')); - // If it's the active file, ensure status bar and toolbar are updated - const activeFile = this.app.workspace.getActiveFile(); - if (activeFile && files.some(f => f.path === activeFile.path)) { - const statuses = this.getFileStatuses(activeFile); - this.notifyStatusChanged(statuses, activeFile) + // Notify status changes for each modified file + for (const file of files) { + const statuses = this.getFileStatuses(file); + this.notifyStatusChanged(statuses, file); } } diff --git a/ui/components/status-bar.ts b/ui/components/status-bar.ts deleted file mode 100644 index ef34278..0000000 --- a/ui/components/status-bar.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { setTooltip } from 'obsidian'; -import { NoteStatusSettings } from '../../models/types'; -import { StatusService } from '../../services/status-service'; - -/** - * Handles the status bar functionality - */ -export class StatusBar { - private statusBarEl: HTMLElement; - private settings: NoteStatusSettings; - private statusService: StatusService; - private currentStatuses: string[] = ['unknown']; - - constructor(statusBarEl: HTMLElement, settings: NoteStatusSettings, statusService: StatusService) { - this.statusBarEl = statusBarEl; - this.settings = settings; - this.statusService = statusService; - - this.statusBarEl.addClass('note-status-bar'); - this.setupContextMenu(); - this.update(['unknown']); - } - - /** - * Set up right-click context menu for force refresh - */ - private setupContextMenu(): void { - this.statusBarEl.addEventListener('contextmenu', (e) => { - e.preventDefault(); - window.dispatchEvent(new CustomEvent('note-status:force-refresh')); - }); - } - - /** - * Update the status bar with new statuses - */ - public update(statuses: string[]): void { - this.currentStatuses = statuses; - this.render(); - } - - /** - * Render the status bar based on current settings and statuses - */ - public render(): void { - this.statusBarEl.empty(); - this.resetClasses(); - - if (!this.settings.showStatusBar) { - this.statusBarEl.addClass('hidden'); - return; - } - - // Select display mode based on number of statuses and settings - if (this.currentStatuses.length === 1 || !this.settings.useMultipleStatuses) { - this.renderSingleStatus(); - } else { - this.renderMultipleStatuses(); - } - - this.handleAutoHide(); - } - - /** - * Reset CSS classes to their default state - */ - private resetClasses(): void { - this.statusBarEl.removeClass('left', 'hidden', 'auto-hide', 'visible'); - this.statusBarEl.addClass('note-status-bar'); - } - - /** - * Render a single status display - */ - private renderSingleStatus(): void { - const primaryStatus = this.currentStatuses[0]; - const statusObj = this.statusService.getAllStatuses().find(s => s.name === primaryStatus); - const tooltipText = statusObj?.description - ? `${primaryStatus} - ${statusObj.description}` - : primaryStatus; - - // Create status text - const statusText = this.statusBarEl.createEl('span', { - text: `Status: ${primaryStatus}`, - cls: `note-status-${primaryStatus}` - }); - setTooltip(statusText, tooltipText); - - // Create status icon - const statusIcon = this.statusBarEl.createEl('span', { - text: this.statusService.getStatusIcon(primaryStatus), - cls: `note-status-icon status-${primaryStatus}` - }); - setTooltip(statusIcon, tooltipText); - } - - /** - * Render multiple statuses display - */ - private renderMultipleStatuses(): void { - this.statusBarEl.createEl('span', { - text: 'Statuses: ', - cls: 'note-status-label' - }); - - const badgesContainer = this.statusBarEl.createEl('span', { - cls: 'note-status-badges' - }); - - this.currentStatuses.forEach(status => - this.createStatusBadge(badgesContainer, status)); - } - - /** - * Create a status badge for multiple status display - */ - private createStatusBadge(container: HTMLElement, status: string): void { - const statusObj = this.statusService.getAllStatuses().find(s => s.name === status); - const tooltipText = statusObj?.description - ? `${status} - ${statusObj.description}` - : status; - - const badge = container.createEl('span', { - cls: `note-status-badge status-${status}` - }); - setTooltip(badge, tooltipText); - - badge.createEl('span', { - text: this.statusService.getStatusIcon(status), - cls: 'note-status-badge-icon' - }); - - badge.createEl('span', { - text: status, - cls: 'note-status-badge-text' - }); - } - - /** - * Handle auto-hide behavior - */ - private handleAutoHide(): void { - const onlyUnknown = this.currentStatuses.length === 1 && - this.currentStatuses[0] === 'unknown'; - - if (this.settings.autoHideStatusBar && onlyUnknown) { - this.statusBarEl.addClass('hidden'); - this.statusBarEl.removeClass('visible'); - } else { - this.statusBarEl.removeClass('hidden'); - this.statusBarEl.addClass('visible'); - } - } - - /** - * Update settings reference - */ - public updateSettings(settings: NoteStatusSettings): void { - this.settings = settings; - this.render(); - } - - /** - * Clean up when plugin is unloaded - */ - public unload(): void { - this.statusBarEl.empty(); - } -} \ No newline at end of file