Skip to content

Commit e33b91c

Browse files
committed
feat: support collapsible for input box in timeline sidebar
1 parent fb1c12c commit e33b91c

File tree

4 files changed

+454
-14
lines changed

4 files changed

+454
-14
lines changed

src/common/setting-definition.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,12 @@ export interface TimelineSidebarSettings {
497497
showCompletedTasks: boolean;
498498
focusModeByDefault: boolean;
499499
maxEventsToShow: number;
500+
// Quick input collapse settings
501+
quickInputCollapsed: boolean;
502+
quickInputDefaultHeight: number;
503+
quickInputAnimationDuration: number;
504+
quickInputCollapseOnCapture: boolean;
505+
quickInputShowQuickActions: boolean;
500506
}
501507

502508
/** OnCompletion Settings */
@@ -1240,6 +1246,12 @@ export const DEFAULT_SETTINGS: TaskProgressBarSettings = {
12401246
showCompletedTasks: true,
12411247
focusModeByDefault: false,
12421248
maxEventsToShow: 100,
1249+
// Quick input collapse defaults
1250+
quickInputCollapsed: false,
1251+
quickInputDefaultHeight: 150,
1252+
quickInputAnimationDuration: 300,
1253+
quickInputCollapseOnCapture: false,
1254+
quickInputShowQuickActions: true,
12431255
},
12441256

12451257
// File Filter Defaults

src/components/timeline-sidebar/TimelineSidebarView.ts

Lines changed: 169 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ export class TimelineSidebarView extends ItemView {
5252
private events: TimelineEvent[] = [];
5353
private isAutoScrolling: boolean = false;
5454

55+
// Collapse state management
56+
private isInputCollapsed: boolean = false;
57+
private tempEditorContent: string = "";
58+
private isAnimating: boolean = false;
59+
private collapsedHeaderEl: HTMLElement | null = null;
60+
private quickInputHeaderEl: HTMLElement | null = null;
61+
5562
// Debounced methods
5663
private debouncedRender = debounce(async () => {
5764
await this.loadEvents();
@@ -81,6 +88,9 @@ export class TimelineSidebarView extends ItemView {
8188
this.containerEl.empty();
8289
this.containerEl.addClass("timeline-sidebar-container");
8390

91+
// Restore collapsed state from settings
92+
this.isInputCollapsed = this.plugin.settings.timelineSidebar.quickInputCollapsed;
93+
8494
this.createHeader();
8595
this.createTimelineArea();
8696
this.createQuickInputArea();
@@ -177,14 +187,30 @@ export class TimelineSidebarView extends ItemView {
177187
"timeline-quick-input"
178188
);
179189

190+
// Create collapsed header (always exists but hidden when expanded)
191+
this.collapsedHeaderEl = this.quickInputContainerEl.createDiv(
192+
"quick-input-header-collapsed"
193+
);
194+
this.createCollapsedHeader();
195+
180196
// Input header with target info
181-
const inputHeaderEl =
197+
this.quickInputHeaderEl =
182198
this.quickInputContainerEl.createDiv("quick-input-header");
183199

184-
const headerTitle = inputHeaderEl.createDiv("quick-input-title");
200+
// Add collapse button to header
201+
const headerLeft = this.quickInputHeaderEl.createDiv("quick-input-header-left");
202+
203+
const collapseBtn = headerLeft.createDiv("quick-input-collapse-btn");
204+
setIcon(collapseBtn, "chevron-down");
205+
collapseBtn.setAttribute("aria-label", t("Collapse quick input"));
206+
this.registerDomEvent(collapseBtn, "click", () => {
207+
this.toggleInputCollapse();
208+
});
209+
210+
const headerTitle = headerLeft.createDiv("quick-input-title");
185211
headerTitle.setText(t("Quick Capture"));
186212

187-
const targetInfo = inputHeaderEl.createDiv("quick-input-target-info");
213+
const targetInfo = this.quickInputHeaderEl.createDiv("quick-input-target-info");
188214
this.updateTargetInfo(targetInfo);
189215

190216
// Editor container
@@ -218,8 +244,10 @@ export class TimelineSidebarView extends ItemView {
218244
}
219245
);
220246

221-
// Focus the editor
222-
this.markdownEditor?.editor?.focus();
247+
// Focus the editor if not collapsed
248+
if (!this.isInputCollapsed) {
249+
this.markdownEditor?.editor?.focus();
250+
}
223251
}, 50);
224252

225253
// Action buttons
@@ -242,6 +270,14 @@ export class TimelineSidebarView extends ItemView {
242270
this.registerDomEvent(fullModalBtn, "click", () => {
243271
new QuickCaptureModal(this.app, this.plugin, {}, true).open();
244272
});
273+
274+
// Apply initial collapsed state
275+
if (this.isInputCollapsed) {
276+
this.quickInputContainerEl.addClass("is-collapsed");
277+
this.collapsedHeaderEl?.show();
278+
} else {
279+
this.collapsedHeaderEl?.hide();
280+
}
245281
}
246282

247283
private loadEvents(): void {
@@ -636,8 +672,13 @@ export class TimelineSidebarView extends ItemView {
636672
await this.loadEvents();
637673
this.renderTimeline();
638674

639-
// Focus back to input
640-
this.markdownEditor.editor?.focus();
675+
// Check if we should collapse after capture
676+
if (this.plugin.settings.timelineSidebar.quickInputCollapseOnCapture) {
677+
this.toggleInputCollapse();
678+
} else {
679+
// Focus back to input
680+
this.markdownEditor.editor?.focus();
681+
}
641682
} catch (error) {
642683
console.error("Failed to capture:", error);
643684
}
@@ -782,4 +823,125 @@ export class TimelineSidebarView extends ItemView {
782823
await this.loadEvents();
783824
this.renderTimeline();
784825
}
826+
827+
// Create collapsed header content
828+
private createCollapsedHeader(): void {
829+
if (!this.collapsedHeaderEl) return;
830+
831+
// Expand button
832+
const expandBtn = this.collapsedHeaderEl.createDiv("collapsed-expand-btn");
833+
setIcon(expandBtn, "chevron-right");
834+
expandBtn.setAttribute("aria-label", t("Expand quick input"));
835+
this.registerDomEvent(expandBtn, "click", () => {
836+
this.toggleInputCollapse();
837+
});
838+
839+
// Title
840+
const titleEl = this.collapsedHeaderEl.createDiv("collapsed-title");
841+
titleEl.setText(t("Quick Capture"));
842+
843+
// Quick actions
844+
if (this.plugin.settings.timelineSidebar.quickInputShowQuickActions) {
845+
const quickActionsEl = this.collapsedHeaderEl.createDiv("collapsed-quick-actions");
846+
847+
// Quick capture button
848+
const quickCaptureBtn = quickActionsEl.createDiv("collapsed-quick-capture");
849+
setIcon(quickCaptureBtn, "plus");
850+
quickCaptureBtn.setAttribute("aria-label", t("Quick capture"));
851+
this.registerDomEvent(quickCaptureBtn, "click", () => {
852+
// Expand and focus editor
853+
if (this.isInputCollapsed) {
854+
this.toggleInputCollapse();
855+
setTimeout(() => {
856+
this.markdownEditor?.editor?.focus();
857+
}, 350); // Wait for animation
858+
}
859+
});
860+
861+
// More options button
862+
const moreOptionsBtn = quickActionsEl.createDiv("collapsed-more-options");
863+
setIcon(moreOptionsBtn, "more-horizontal");
864+
moreOptionsBtn.setAttribute("aria-label", t("More options"));
865+
this.registerDomEvent(moreOptionsBtn, "click", () => {
866+
new QuickCaptureModal(this.app, this.plugin, {}, true).open();
867+
});
868+
}
869+
}
870+
871+
// Toggle collapse state
872+
private toggleInputCollapse(): void {
873+
if (this.isAnimating) return;
874+
875+
this.isAnimating = true;
876+
this.isInputCollapsed = !this.isInputCollapsed;
877+
878+
// Save state to settings
879+
this.plugin.settings.timelineSidebar.quickInputCollapsed = this.isInputCollapsed;
880+
this.plugin.saveSettings();
881+
882+
if (this.isInputCollapsed) {
883+
this.handleCollapseEditor();
884+
} else {
885+
this.handleExpandEditor();
886+
}
887+
888+
// Reset animation flag after animation completes
889+
setTimeout(() => {
890+
this.isAnimating = false;
891+
}, this.plugin.settings.timelineSidebar.quickInputAnimationDuration);
892+
}
893+
894+
// Handle collapsing the editor
895+
private handleCollapseEditor(): void {
896+
// Save current editor content
897+
if (this.markdownEditor) {
898+
this.tempEditorContent = this.markdownEditor.value;
899+
}
900+
901+
// Add collapsed class for animation
902+
this.quickInputContainerEl.addClass("is-collapsing");
903+
this.quickInputContainerEl.addClass("is-collapsed");
904+
905+
// Show collapsed header after a slight delay
906+
setTimeout(() => {
907+
this.collapsedHeaderEl?.show();
908+
this.quickInputContainerEl.removeClass("is-collapsing");
909+
}, 50);
910+
911+
// Update collapse button icon
912+
const collapseBtn = this.quickInputHeaderEl?.querySelector(".quick-input-collapse-btn");
913+
if (collapseBtn) {
914+
setIcon(collapseBtn as HTMLElement, "chevron-right");
915+
collapseBtn.setAttribute("aria-label", t("Expand quick input"));
916+
}
917+
}
918+
919+
// Handle expanding the editor
920+
private handleExpandEditor(): void {
921+
// Hide collapsed header immediately
922+
this.collapsedHeaderEl?.hide();
923+
924+
// Remove collapsed class for animation
925+
this.quickInputContainerEl.addClass("is-expanding");
926+
this.quickInputContainerEl.removeClass("is-collapsed");
927+
928+
// Restore editor content
929+
if (this.markdownEditor && this.tempEditorContent) {
930+
this.markdownEditor.set(this.tempEditorContent, false);
931+
this.tempEditorContent = "";
932+
}
933+
934+
// Focus editor after animation
935+
setTimeout(() => {
936+
this.quickInputContainerEl.removeClass("is-expanding");
937+
this.markdownEditor?.editor?.focus();
938+
}, 50);
939+
940+
// Update collapse button icon
941+
const collapseBtn = this.quickInputHeaderEl?.querySelector(".quick-input-collapse-btn");
942+
if (collapseBtn) {
943+
setIcon(collapseBtn as HTMLElement, "chevron-down");
944+
collapseBtn.setAttribute("aria-label", t("Collapse quick input"));
945+
}
946+
}
785947
}

0 commit comments

Comments
 (0)