mirror of
https://github.com/taskgenius/taskgenius-plugin.git
synced 2026-07-22 06:40:25 +00:00
feat(fluent): add custom button support to top navigation
Extend FluentTopNavigation to support dynamic custom buttons that can be registered by views or components. Features include: - CustomNavButton interface for button configuration - Custom buttons container in navigation bar - Register/unregister methods for button management - Integration with FluentComponentManager - Styling for custom button container
This commit is contained in:
parent
bcd3f2bf95
commit
2177d9ad31
4 changed files with 138 additions and 1 deletions
|
|
@ -6,6 +6,7 @@ import {
|
|||
Platform,
|
||||
Component,
|
||||
TFile,
|
||||
ExtraButtonComponent,
|
||||
} from "obsidian";
|
||||
import TaskProgressBarPlugin from "@/index";
|
||||
import { Task } from "@/types/task";
|
||||
|
|
@ -14,6 +15,13 @@ import { Events, on } from "@/dataflow/events/Events";
|
|||
|
||||
export type ViewMode = "list" | "kanban" | "tree" | "calendar";
|
||||
|
||||
export interface CustomNavButton {
|
||||
id: string;
|
||||
icon: string;
|
||||
tooltip: string;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
export function isCompletedMark(
|
||||
plugin: TaskProgressBarPlugin,
|
||||
mark: string
|
||||
|
|
@ -39,6 +47,8 @@ export class TopNavigation extends Component {
|
|||
private notificationCount = 0;
|
||||
private availableModes: ViewMode[] = ["list", "kanban", "tree", "calendar"];
|
||||
private viewTabsContainer: HTMLElement | null = null;
|
||||
private customButtonsContainer: HTMLElement | null = null;
|
||||
private customButtons: Map<string, { buttonEl: HTMLElement; config: CustomNavButton }> = new Map();
|
||||
|
||||
constructor(
|
||||
containerEl: HTMLElement,
|
||||
|
|
@ -197,6 +207,11 @@ export class TopNavigation extends Component {
|
|||
cls: "fluent-nav-right",
|
||||
});
|
||||
|
||||
// Custom buttons container (for dynamic buttons from views)
|
||||
this.customButtonsContainer = rightSection.createDiv({
|
||||
cls: "fluent-nav-custom-buttons",
|
||||
});
|
||||
|
||||
// Notification button
|
||||
const notificationBtn = rightSection.createDiv({
|
||||
cls: "fluent-nav-icon-button",
|
||||
|
|
@ -422,4 +437,76 @@ export class TopNavigation extends Component {
|
|||
public getCurrentViewMode(): ViewMode {
|
||||
return this.currentViewMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom button in the top navigation
|
||||
*/
|
||||
public registerCustomButton(config: CustomNavButton): void {
|
||||
if (!this.customButtonsContainer) {
|
||||
console.warn("[FluentTopNavigation] Custom buttons container not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if button already exists
|
||||
if (this.customButtons.has(config.id)) {
|
||||
console.warn(`[FluentTopNavigation] Button with id "${config.id}" already registered`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create button container
|
||||
const buttonContainer = this.customButtonsContainer.createDiv({
|
||||
cls: "fluent-nav-custom-button-wrapper",
|
||||
});
|
||||
|
||||
// Create button using ExtraButtonComponent
|
||||
const button = new ExtraButtonComponent(buttonContainer)
|
||||
.setIcon(config.icon)
|
||||
.setTooltip(config.tooltip)
|
||||
.onClick(config.onClick);
|
||||
|
||||
// Store reference
|
||||
this.customButtons.set(config.id, {
|
||||
buttonEl: buttonContainer,
|
||||
config: config,
|
||||
});
|
||||
|
||||
console.log(`[FluentTopNavigation] Registered custom button: ${config.id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a custom button by ID
|
||||
*/
|
||||
public unregisterCustomButton(id: string): void {
|
||||
const button = this.customButtons.get(id);
|
||||
if (!button) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove DOM element
|
||||
button.buttonEl.remove();
|
||||
|
||||
// Remove from map
|
||||
this.customButtons.delete(id);
|
||||
|
||||
console.log(`[FluentTopNavigation] Unregistered custom button: ${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all custom buttons
|
||||
*/
|
||||
public clearCustomButtons(): void {
|
||||
if (!this.customButtonsContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove all button elements
|
||||
this.customButtons.forEach((button) => {
|
||||
button.buttonEl.remove();
|
||||
});
|
||||
|
||||
// Clear map
|
||||
this.customButtons.clear();
|
||||
|
||||
console.log("[FluentTopNavigation] Cleared all custom buttons");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import { filterTasks } from "@/utils/task/task-filter-utils";
|
|||
import { RootFilterState } from "@/components/features/task/filter/ViewTaskFilter";
|
||||
import { QuickCaptureModal } from "@/components/features/quick-capture/modals/QuickCaptureModalWithSwitch";
|
||||
import { t } from "@/translations/helper";
|
||||
import { ViewMode } from "../components/FluentTopNavigation";
|
||||
import { ViewMode, TopNavigation } from "../components/FluentTopNavigation";
|
||||
import { TaskSelectionManager } from "@/components/features/task/selection/TaskSelectionManager";
|
||||
|
||||
type ManagedViewComponent = {
|
||||
|
|
@ -85,6 +85,9 @@ export class FluentComponentManager extends Component {
|
|||
// Track currently visible component
|
||||
private currentVisibleComponent: ManagedViewComponent | null = null;
|
||||
|
||||
// Top Navigation reference (for registering custom buttons)
|
||||
private topNavigation: TopNavigation | null = null;
|
||||
|
||||
// View handlers
|
||||
private viewHandlers: {
|
||||
onTaskSelected: (task: Task) => void;
|
||||
|
|
@ -121,6 +124,14 @@ export class FluentComponentManager extends Component {
|
|||
this.viewHandlers = viewHandlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the TopNavigation reference for managing custom buttons
|
||||
*/
|
||||
public setTopNavigation(nav: TopNavigation): void {
|
||||
this.topNavigation = nav;
|
||||
console.log("[FluentComponentManager] TopNavigation reference set");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all view components
|
||||
*/
|
||||
|
|
@ -447,6 +458,12 @@ export class FluentComponentManager extends Component {
|
|||
console.log("[FluentComponent] Hiding all components");
|
||||
this.hideAllComponents();
|
||||
|
||||
// Clear custom buttons from TopNavigation before switching views
|
||||
// They will be re-registered by the new view if needed
|
||||
if (this.topNavigation) {
|
||||
this.topNavigation.clearCustomButtons();
|
||||
}
|
||||
|
||||
// Check if current view supports multiple view modes and we're in a non-list mode
|
||||
const viewModes = this.getAvailableModesForView(viewId, project);
|
||||
|
||||
|
|
@ -588,6 +605,12 @@ export class FluentComponentManager extends Component {
|
|||
targetComponent.containerEl.show();
|
||||
this.currentVisibleComponent = targetComponent;
|
||||
|
||||
// Set TopNavigation reference for ContentComponent to enable custom buttons
|
||||
if (targetComponent === this.contentComponent && this.topNavigation) {
|
||||
console.log("[FluentComponent] Setting TopNavigation reference for ContentComponent");
|
||||
this.contentComponent.setTopNavigation(this.topNavigation);
|
||||
}
|
||||
|
||||
// Set view mode first for ContentComponent
|
||||
if (typeof targetComponent.setViewMode === "function") {
|
||||
console.log(
|
||||
|
|
@ -685,6 +708,11 @@ export class FluentComponentManager extends Component {
|
|||
// Hide current component
|
||||
this.hideAllComponents();
|
||||
|
||||
// Clear custom buttons before switching view modes
|
||||
if (this.topNavigation) {
|
||||
this.topNavigation.clearCustomButtons();
|
||||
}
|
||||
|
||||
// Based on the current view mode, show the appropriate component
|
||||
switch (viewMode) {
|
||||
case "list":
|
||||
|
|
@ -693,6 +721,12 @@ export class FluentComponentManager extends Component {
|
|||
if (!this.contentComponent) return;
|
||||
|
||||
this.contentComponent.containerEl.show();
|
||||
|
||||
// Set TopNavigation reference to enable custom buttons
|
||||
if (this.topNavigation) {
|
||||
this.contentComponent.setTopNavigation(this.topNavigation);
|
||||
}
|
||||
|
||||
this.contentComponent.setViewMode(viewId as any);
|
||||
this.contentComponent.setIsTreeView(viewMode === "tree");
|
||||
|
||||
|
|
|
|||
|
|
@ -943,6 +943,10 @@ export class FluentTaskView extends ItemView {
|
|||
this.addChild(this.componentManager);
|
||||
this.componentManager.initializeViewComponents();
|
||||
|
||||
// Set TopNavigation reference in ComponentManager
|
||||
this.componentManager.setTopNavigation(this.topNavigation);
|
||||
console.log("[Task Genius] TopNavigation reference passed to ComponentManager");
|
||||
|
||||
// Sidebar toggle in header and responsive collapse
|
||||
console.log("[Task Genius] Creating sidebar toggle");
|
||||
this.layoutManager.createSidebarToggle();
|
||||
|
|
|
|||
|
|
@ -521,6 +521,18 @@ button.fluent-new-task-btn:hover {
|
|||
gap: 12px;
|
||||
}
|
||||
|
||||
/* Custom buttons container (for dynamic buttons from views) */
|
||||
.fluent-nav-custom-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.fluent-nav-custom-button-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.fluent-nav-icon-button {
|
||||
position: relative;
|
||||
width: 36px;
|
||||
|
|
|
|||
Loading…
Reference in a new issue