mirror of
https://github.com/taskgenius/taskgenius-plugin.git
synced 2026-07-22 06:40:25 +00:00
refactor(quick-capture): migrate to QuickCaptureModalWithSwitch and improve UI
- Update all imports from QuickCaptureModal to QuickCaptureModalWithSwitch - Conditionally show clear button only when both file and inline modes are available - Hide tab container when only one mode is available (aria-hidden attribute) - Adjust modal height from 750px to 700px for better viewport fit - Add CSS rule to hide modal title when containing hidden elements - Clean up formatting and spacing consistency
This commit is contained in:
parent
0ae3957144
commit
ab8af59b34
8 changed files with 134 additions and 119 deletions
|
|
@ -22,7 +22,7 @@ import { DayView } from "./views/day-view";
|
|||
import { AgendaView } from "./views/agenda-view";
|
||||
import { YearView } from "./views/year-view";
|
||||
import TaskProgressBarPlugin from "@/index";
|
||||
import { QuickCaptureModal } from "@/components/features/quick-capture/modals/QuickCaptureModal";
|
||||
import { QuickCaptureModal } from "@/components/features/quick-capture/modals/QuickCaptureModalWithSwitch";
|
||||
// Import algorithm functions (optional for now, could be used within views)
|
||||
// import { calculateEventLayout, determineEventColor } from './algorithm';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { App, Component, setIcon } from "obsidian";
|
|||
import { Task } from "@/types/task"; // Adjust path
|
||||
import { KanbanCardComponent } from "./kanban-card";
|
||||
import TaskProgressBarPlugin from "@/index"; // Adjust path
|
||||
import { QuickCaptureModal } from "@/components/features/quick-capture/modals/QuickCaptureModal"; // Import QuickCaptureModal
|
||||
import { QuickCaptureModal } from "@/components/features/quick-capture/modals/QuickCaptureModalWithSwitch"; // Import QuickCaptureModal
|
||||
import { t } from "@/translations/helper"; // Import translation helper
|
||||
|
||||
const BATCH_SIZE = 20; // Number of cards to load at a time
|
||||
|
|
@ -45,7 +45,7 @@ export class KanbanColumnComponent extends Component {
|
|||
override onload(): void {
|
||||
this.element = this.containerEl.createDiv({
|
||||
cls: "tg-kanban-column",
|
||||
attr: { "data-status-name": this.statusName },
|
||||
attr: {"data-status-name": this.statusName},
|
||||
});
|
||||
|
||||
// Hide column if no tasks and hideEmptyColumns is enabled
|
||||
|
|
@ -122,7 +122,7 @@ export class KanbanColumnComponent extends Component {
|
|||
new QuickCaptureModal(
|
||||
this.app,
|
||||
this.plugin,
|
||||
{ status: taskStatusSymbol },
|
||||
{status: taskStatusSymbol},
|
||||
true
|
||||
).open();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Setting, TextAreaComponent, Notice, setIcon } from "obsidian";
|
||||
import type TaskProgressBarPlugin from "@/index";
|
||||
import { t } from "@/translations/helper";
|
||||
import { QuickCaptureModal } from "@/components/features/quick-capture/modals/QuickCaptureModal";
|
||||
import { QuickCaptureModal } from "@/components/features/quick-capture/modals/QuickCaptureModalWithSwitch";
|
||||
|
||||
export class TaskCreationGuide {
|
||||
private plugin: TaskProgressBarPlugin;
|
||||
|
|
@ -37,18 +37,18 @@ export class TaskCreationGuide {
|
|||
*/
|
||||
private renderTaskFormats(containerEl: HTMLElement) {
|
||||
const formatsSection = containerEl.createDiv("task-formats-section");
|
||||
formatsSection.createEl("h3", { text: t("Task Format Examples") });
|
||||
formatsSection.createEl("h3", {text: t("Task Format Examples")});
|
||||
|
||||
// Basic task format
|
||||
const basicFormat = formatsSection.createDiv("format-example");
|
||||
basicFormat.createEl("h4", { text: t("Basic Task") });
|
||||
basicFormat.createEl("h4", {text: t("Basic Task")});
|
||||
basicFormat.createEl("code", {
|
||||
text: "- [ ] Complete project documentation",
|
||||
});
|
||||
|
||||
// Emoji format
|
||||
const emojiFormat = formatsSection.createDiv("format-example");
|
||||
emojiFormat.createEl("h4", { text: t("With Emoji Metadata") });
|
||||
emojiFormat.createEl("h4", {text: t("With Emoji Metadata")});
|
||||
emojiFormat.createEl("code", {
|
||||
text: "- [ ] Complete project documentation 📅 2024-01-15 🔺 #project/docs",
|
||||
});
|
||||
|
|
@ -62,14 +62,14 @@ export class TaskCreationGuide {
|
|||
|
||||
// Dataview format
|
||||
const dataviewFormat = formatsSection.createDiv("format-example");
|
||||
dataviewFormat.createEl("h4", { text: t("With Dataview Metadata") });
|
||||
dataviewFormat.createEl("h4", {text: t("With Dataview Metadata")});
|
||||
dataviewFormat.createEl("code", {
|
||||
text: "- [ ] Complete project documentation [due:: 2024-01-15] [priority:: high] [project:: docs]",
|
||||
});
|
||||
|
||||
// Mixed format
|
||||
const mixedFormat = formatsSection.createDiv("format-example");
|
||||
mixedFormat.createEl("h4", { text: t("Mixed Format") });
|
||||
mixedFormat.createEl("h4", {text: t("Mixed Format")});
|
||||
mixedFormat.createEl("code", {
|
||||
text: "- [ ] Complete project documentation 📅 2024-01-15 [priority:: high] @work",
|
||||
});
|
||||
|
|
@ -81,42 +81,42 @@ export class TaskCreationGuide {
|
|||
|
||||
// Status markers
|
||||
const statusSection = formatsSection.createDiv("status-markers");
|
||||
statusSection.createEl("h4", { text: t("Task Status Markers") });
|
||||
statusSection.createEl("h4", {text: t("Task Status Markers")});
|
||||
|
||||
const statusList = statusSection.createEl("ul", { cls: "status-list" });
|
||||
const statusList = statusSection.createEl("ul", {cls: "status-list"});
|
||||
const statusMarkers = [
|
||||
{ marker: "[ ]", description: t("Not started") },
|
||||
{ marker: "[x]", description: t("Completed") },
|
||||
{ marker: "[/]", description: t("In progress") },
|
||||
{ marker: "[?]", description: t("Planned") },
|
||||
{ marker: "[-]", description: t("Abandoned") },
|
||||
{marker: "[ ]", description: t("Not started")},
|
||||
{marker: "[x]", description: t("Completed")},
|
||||
{marker: "[/]", description: t("In progress")},
|
||||
{marker: "[?]", description: t("Planned")},
|
||||
{marker: "[-]", description: t("Abandoned")},
|
||||
];
|
||||
|
||||
statusMarkers.forEach((status) => {
|
||||
const item = statusList.createEl("li");
|
||||
item.createEl("code", { text: status.marker });
|
||||
item.createEl("code", {text: status.marker});
|
||||
item.createSpan().setText(" - " + status.description);
|
||||
});
|
||||
|
||||
// Metadata symbols
|
||||
const metadataSection = formatsSection.createDiv("metadata-symbols");
|
||||
metadataSection.createEl("h4", { text: t("Common Metadata Symbols") });
|
||||
metadataSection.createEl("h4", {text: t("Common Metadata Symbols")});
|
||||
|
||||
const symbolsList = metadataSection.createEl("ul", {
|
||||
cls: "symbols-list",
|
||||
});
|
||||
const symbols = [
|
||||
{ symbol: "📅", description: t("Due date") },
|
||||
{ symbol: "🛫", description: t("Start date") },
|
||||
{ symbol: "⏳", description: t("Scheduled date") },
|
||||
{ symbol: "🔺", description: t("High priority") },
|
||||
{ symbol: "⏫", description: t("Higher priority") },
|
||||
{ symbol: "🔼", description: t("Medium priority") },
|
||||
{ symbol: "🔽", description: t("Lower priority") },
|
||||
{ symbol: "⏬", description: t("Lowest priority") },
|
||||
{ symbol: "🔁", description: t("Recurring task") },
|
||||
{ symbol: "#", description: t("Project/tag") },
|
||||
{ symbol: "@", description: t("Context") },
|
||||
{symbol: "📅", description: t("Due date")},
|
||||
{symbol: "🛫", description: t("Start date")},
|
||||
{symbol: "⏳", description: t("Scheduled date")},
|
||||
{symbol: "🔺", description: t("High priority")},
|
||||
{symbol: "⏫", description: t("Higher priority")},
|
||||
{symbol: "🔼", description: t("Medium priority")},
|
||||
{symbol: "🔽", description: t("Lower priority")},
|
||||
{symbol: "⏬", description: t("Lowest priority")},
|
||||
{symbol: "🔁", description: t("Recurring task")},
|
||||
{symbol: "#", description: t("Project/tag")},
|
||||
{symbol: "@", description: t("Context")},
|
||||
];
|
||||
|
||||
symbols.forEach((symbol) => {
|
||||
|
|
@ -134,7 +134,7 @@ export class TaskCreationGuide {
|
|||
const quickCaptureSection = containerEl.createDiv(
|
||||
"quick-capture-section"
|
||||
);
|
||||
quickCaptureSection.createEl("h3", { text: t("Quick Capture") });
|
||||
quickCaptureSection.createEl("h3", {text: t("Quick Capture")});
|
||||
|
||||
const demoContent = quickCaptureSection.createDiv("demo-content");
|
||||
demoContent.createEl("p", {
|
||||
|
|
@ -179,7 +179,7 @@ export class TaskCreationGuide {
|
|||
*/
|
||||
private renderInteractivePractice(containerEl: HTMLElement) {
|
||||
const practiceSection = containerEl.createDiv("practice-section");
|
||||
practiceSection.createEl("h3", { text: t("Try It Yourself") });
|
||||
practiceSection.createEl("h3", {text: t("Try It Yourself")});
|
||||
|
||||
practiceSection.createEl("p", {
|
||||
text: t("Practice creating a task with the format you prefer:"),
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ export interface TaskMetadata {
|
|||
* Provides shared functionality and state management
|
||||
*/
|
||||
const LAST_USED_MODE_KEY = "task-genius.lastUsedQuickCaptureMode";
|
||||
|
||||
export abstract class BaseQuickCaptureModal extends Modal {
|
||||
plugin: TaskProgressBarPlugin;
|
||||
protected markdownEditor: EmbeddableMarkdownEditor | null = null;
|
||||
|
|
@ -154,7 +155,7 @@ export abstract class BaseQuickCaptureModal extends Modal {
|
|||
* Called when the modal is opened
|
||||
*/
|
||||
onOpen() {
|
||||
const { contentEl } = this;
|
||||
const {contentEl} = this;
|
||||
this.modalEl.toggleClass("quick-capture-modal", true);
|
||||
this.modalEl.toggleClass(`quick-capture-${this.currentMode}`, true);
|
||||
|
||||
|
|
@ -277,18 +278,21 @@ export abstract class BaseQuickCaptureModal extends Modal {
|
|||
|
||||
if (!(this.fileModeAvailable && this.inlineModeAvailable)) {
|
||||
tabContainer.classList.add("is-hidden");
|
||||
tabContainer.setAttribute("aria-hidden", "true");
|
||||
}
|
||||
|
||||
// Right side: Clear button with improved styling
|
||||
const clearButton = this.headerContainer.createEl("button", {
|
||||
text: t("Clear"),
|
||||
cls: ["quick-capture-clear", "clickable-icon"],
|
||||
attr: {
|
||||
"aria-label": t("Clear all content"),
|
||||
type: "button",
|
||||
},
|
||||
});
|
||||
clearButton.addEventListener("click", () => this.handleClear());
|
||||
if (this.fileModeAvailable && this.inlineModeAvailable) {
|
||||
const clearButton = this.headerContainer.createEl("button", {
|
||||
text: t("Clear"),
|
||||
cls: ["quick-capture-clear", "clickable-icon"],
|
||||
attr: {
|
||||
"aria-label": t("Clear all content"),
|
||||
type: "button",
|
||||
},
|
||||
});
|
||||
clearButton.addEventListener("click", () => this.handleClear());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -350,12 +354,15 @@ export abstract class BaseQuickCaptureModal extends Modal {
|
|||
|
||||
// Save current state
|
||||
const savedContent = this.capturedContent;
|
||||
const savedMetadata = { ...this.taskMetadata };
|
||||
const savedMetadata = {...this.taskMetadata};
|
||||
|
||||
// Update mode
|
||||
this.currentMode = mode;
|
||||
// Persist last used mode to local storage
|
||||
try { this.app.saveLocalStorage(LAST_USED_MODE_KEY, mode); } catch {}
|
||||
try {
|
||||
this.app.saveLocalStorage(LAST_USED_MODE_KEY, mode);
|
||||
} catch {
|
||||
}
|
||||
|
||||
// Update modal classes
|
||||
this.modalEl.removeClass(
|
||||
|
|
@ -632,44 +639,44 @@ export abstract class BaseQuickCaptureModal extends Modal {
|
|||
* Sanitize filename
|
||||
*/
|
||||
|
||||
/**
|
||||
* Map UI status (symbol or text) to textual metadata
|
||||
*/
|
||||
protected mapStatusToText(status?: string): string {
|
||||
if (!status) return "not-started";
|
||||
if (status.length > 1) return status; // already textual
|
||||
switch (status) {
|
||||
case "x":
|
||||
case "X":
|
||||
return "completed";
|
||||
case "/":
|
||||
case ">":
|
||||
return "in-progress";
|
||||
case "?":
|
||||
return "planned";
|
||||
case "-":
|
||||
return "cancelled";
|
||||
case " ":
|
||||
default:
|
||||
return "not-started";
|
||||
}
|
||||
/**
|
||||
* Map UI status (symbol or text) to textual metadata
|
||||
*/
|
||||
protected mapStatusToText(status?: string): string {
|
||||
if (!status) return "not-started";
|
||||
if (status.length > 1) return status; // already textual
|
||||
switch (status) {
|
||||
case "x":
|
||||
case "X":
|
||||
return "completed";
|
||||
case "/":
|
||||
case ">":
|
||||
return "in-progress";
|
||||
case "?":
|
||||
return "planned";
|
||||
case "-":
|
||||
return "cancelled";
|
||||
case " ":
|
||||
default:
|
||||
return "not-started";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract #tags from content for frontmatter tags array
|
||||
* Simple regex scan; remove leading '#', dedupe
|
||||
*/
|
||||
protected extractTagsFromContentForFrontmatter(content: string): string[] {
|
||||
if (!content) return [];
|
||||
const tagRegex = /(^|\s)#([A-Za-z0-9_\/-]+)/g;
|
||||
const results = new Set<string>();
|
||||
let match: RegExpExecArray | null;
|
||||
while ((match = tagRegex.exec(content)) !== null) {
|
||||
const tag = match[2];
|
||||
if (tag) results.add(tag);
|
||||
}
|
||||
return Array.from(results);
|
||||
/**
|
||||
* Extract #tags from content for frontmatter tags array
|
||||
* Simple regex scan; remove leading '#', dedupe
|
||||
*/
|
||||
protected extractTagsFromContentForFrontmatter(content: string): string[] {
|
||||
if (!content) return [];
|
||||
const tagRegex = /(^|\s)#([A-Za-z0-9_\/-]+)/g;
|
||||
const results = new Set<string>();
|
||||
let match: RegExpExecArray | null;
|
||||
while ((match = tagRegex.exec(content)) !== null) {
|
||||
const tag = match[2];
|
||||
if (tag) results.add(tag);
|
||||
}
|
||||
return Array.from(results);
|
||||
}
|
||||
|
||||
protected sanitizeFilename(filename: string): string {
|
||||
return filename
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import { Task } from "@/types/task";
|
|||
import { TimeComponent } from "@/types/time-parsing";
|
||||
import { t } from "@/translations/helper";
|
||||
import TaskProgressBarPlugin from "@/index";
|
||||
import { QuickCaptureModal } from "@/components/features/quick-capture/modals/QuickCaptureModal";
|
||||
import { QuickCaptureModal } from "@/components/features/quick-capture/modals/QuickCaptureModalWithSwitch";
|
||||
import {
|
||||
createEmbeddableMarkdownEditor,
|
||||
EmbeddableMarkdownEditor,
|
||||
|
|
@ -219,7 +219,7 @@ export class TimelineSidebarView extends ItemView {
|
|||
|
||||
// Add collapse button to header
|
||||
const headerLeft = this.quickInputHeaderEl.createDiv("quick-input-header-left");
|
||||
|
||||
|
||||
const collapseBtn = headerLeft.createDiv("quick-input-collapse-btn");
|
||||
setIcon(collapseBtn, "chevron-down");
|
||||
collapseBtn.setAttribute("aria-label", t("Collapse quick input"));
|
||||
|
|
@ -303,7 +303,7 @@ export class TimelineSidebarView extends ItemView {
|
|||
private async loadEvents(): Promise<void> {
|
||||
// Get tasks from the plugin's dataflow
|
||||
let allTasks: Task[] = [];
|
||||
|
||||
|
||||
if (this.plugin.dataflowOrchestrator) {
|
||||
try {
|
||||
allTasks = await this.plugin.dataflowOrchestrator.getQueryAPI().getAllTasks();
|
||||
|
|
@ -317,10 +317,10 @@ export class TimelineSidebarView extends ItemView {
|
|||
// Filter tasks based on showCompletedTasks setting
|
||||
const shouldShowCompletedTasks =
|
||||
this.plugin.settings.timelineSidebar.showCompletedTasks;
|
||||
|
||||
|
||||
// Get abandoned status markers to filter out
|
||||
const abandonedStatuses = this.plugin.settings.taskStatuses.abandoned.split("|");
|
||||
|
||||
|
||||
const filteredTasks = shouldShowCompletedTasks
|
||||
? allTasks
|
||||
: allTasks.filter((task) => {
|
||||
|
|
@ -343,7 +343,7 @@ export class TimelineSidebarView extends ItemView {
|
|||
// Convert tasks to timeline events
|
||||
timelineFilteredTasks.forEach((task) => {
|
||||
const dates = this.extractDatesFromTask(task);
|
||||
dates.forEach(({ date, type }) => {
|
||||
dates.forEach(({date, type}) => {
|
||||
const event: EnhancedTimelineEvent = {
|
||||
id: `${task.id}-${type}`,
|
||||
content: task.content,
|
||||
|
|
@ -402,11 +402,11 @@ export class TimelineSidebarView extends ItemView {
|
|||
const currentPriority =
|
||||
DATE_TYPE_PRIORITY[
|
||||
current.type as keyof typeof DATE_TYPE_PRIORITY
|
||||
] || 0;
|
||||
] || 0;
|
||||
const highestPriority =
|
||||
DATE_TYPE_PRIORITY[
|
||||
highest.type as keyof typeof DATE_TYPE_PRIORITY
|
||||
] || 0;
|
||||
] || 0;
|
||||
|
||||
return currentPriority > highestPriority
|
||||
? current
|
||||
|
|
@ -502,7 +502,7 @@ export class TimelineSidebarView extends ItemView {
|
|||
// Determine if this is a time range
|
||||
// Check if the time component is marked as a range OR if we have an explicit end time
|
||||
const isRange = relevantTimeComponent.isRange || !!relevantEndTime;
|
||||
|
||||
|
||||
// If the time component is a range but we don't have enhancedDates.endDateTime,
|
||||
// create the end time from the range partner
|
||||
if (relevantTimeComponent.isRange && !relevantEndTime && relevantTimeComponent.rangePartner) {
|
||||
|
|
@ -530,30 +530,30 @@ export class TimelineSidebarView extends ItemView {
|
|||
task: Task
|
||||
): Array<{ date: Date; type: string }> {
|
||||
// Task-level deduplication: ensure each task appears only once in timeline
|
||||
|
||||
|
||||
// Check if task has enhanced metadata with time components
|
||||
const enhancedMetadata = task.metadata as any;
|
||||
const timeComponents = enhancedMetadata?.timeComponents;
|
||||
const enhancedDates = enhancedMetadata?.enhancedDates;
|
||||
|
||||
|
||||
// For completed tasks: prioritize due date, fallback to completed date
|
||||
if (task.completed) {
|
||||
if (task.metadata.dueDate) {
|
||||
// Use enhanced due datetime if available, otherwise use original timestamp
|
||||
const dueDate = enhancedDates?.dueDateTime || new Date(task.metadata.dueDate);
|
||||
return [{ date: dueDate, type: "due" }];
|
||||
return [{date: dueDate, type: "due"}];
|
||||
} else if (task.metadata.completedDate) {
|
||||
return [{ date: new Date(task.metadata.completedDate), type: "completed" }];
|
||||
return [{date: new Date(task.metadata.completedDate), type: "completed"}];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// For non-completed tasks: select single highest priority date with enhanced datetime support
|
||||
const dates: Array<{ date: Date; type: string }> = [];
|
||||
|
||||
if (task.metadata.dueDate) {
|
||||
// Use enhanced due datetime if available
|
||||
const dueDate = enhancedDates?.dueDateTime || new Date(task.metadata.dueDate);
|
||||
dates.push({ date: dueDate, type: "due" });
|
||||
dates.push({date: dueDate, type: "due"});
|
||||
}
|
||||
if (task.metadata.scheduledDate) {
|
||||
// Use enhanced scheduled datetime if available
|
||||
|
|
@ -571,7 +571,7 @@ export class TimelineSidebarView extends ItemView {
|
|||
type: "start",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// For non-completed tasks, select the highest priority date
|
||||
if (dates.length > 0) {
|
||||
const highestPriorityDate = dates.reduce((highest, current) => {
|
||||
|
|
@ -581,7 +581,7 @@ export class TimelineSidebarView extends ItemView {
|
|||
});
|
||||
return [highestPriorityDate];
|
||||
}
|
||||
|
||||
|
||||
// Fallback: if no planning dates exist, use deduplication for edge cases
|
||||
const allDates: Array<{ date: Date; type: string }> = [];
|
||||
if (task.metadata.completedDate) {
|
||||
|
|
@ -590,7 +590,7 @@ export class TimelineSidebarView extends ItemView {
|
|||
type: "completed",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return this.deduplicateDatesByPriority(allDates);
|
||||
}
|
||||
|
||||
|
|
@ -679,7 +679,7 @@ export class TimelineSidebarView extends ItemView {
|
|||
private renderEventTime(timeEl: HTMLElement, event: EnhancedTimelineEvent): void {
|
||||
if (event.timeInfo?.timeComponent) {
|
||||
// Use parsed time component for accurate display
|
||||
const { timeComponent, isRange, endTime } = event.timeInfo;
|
||||
const {timeComponent, isRange, endTime} = event.timeInfo;
|
||||
|
||||
if (isRange && endTime) {
|
||||
// Display time range
|
||||
|
|
@ -697,7 +697,8 @@ export class TimelineSidebarView extends ItemView {
|
|||
: `${minutes}m`;
|
||||
timeEl.setAttribute("data-duration", duration);
|
||||
}
|
||||
} catch (_) {}
|
||||
} catch (_) {
|
||||
}
|
||||
} else {
|
||||
// Display single time
|
||||
timeEl.setText(this.formatTimeComponent(timeComponent));
|
||||
|
|
@ -753,12 +754,12 @@ export class TimelineSidebarView extends ItemView {
|
|||
private formatTimeComponent(timeComponent: TimeComponent): string {
|
||||
const hour = timeComponent.hour.toString().padStart(2, '0');
|
||||
const minute = timeComponent.minute.toString().padStart(2, '0');
|
||||
|
||||
|
||||
if (timeComponent.second !== undefined) {
|
||||
const second = timeComponent.second.toString().padStart(2, '0');
|
||||
return `${hour}:${minute}:${second}`;
|
||||
}
|
||||
|
||||
|
||||
return `${hour}:${minute}`;
|
||||
}
|
||||
|
||||
|
|
@ -770,14 +771,14 @@ export class TimelineSidebarView extends ItemView {
|
|||
// Get the primary time for sorting - use enhanced time if available
|
||||
const timeA = a.timeInfo?.primaryTime || a.time;
|
||||
const timeB = b.timeInfo?.primaryTime || b.time;
|
||||
|
||||
|
||||
// Sort by time of day (earlier times first)
|
||||
const timeComparison = timeA.getTime() - timeB.getTime();
|
||||
|
||||
|
||||
if (timeComparison !== 0) {
|
||||
return timeComparison;
|
||||
}
|
||||
|
||||
|
||||
// If times are equal, sort by task content for consistent ordering
|
||||
return a.content.localeCompare(b.content);
|
||||
});
|
||||
|
|
@ -844,7 +845,7 @@ export class TimelineSidebarView extends ItemView {
|
|||
events.forEach((event) => {
|
||||
const time = event.timeInfo?.primaryTime || event.time;
|
||||
const timeKey = this.getTimeGroupKey(time, event);
|
||||
|
||||
|
||||
if (!timeGroups.has(timeKey)) {
|
||||
timeGroups.set(timeKey, []);
|
||||
}
|
||||
|
|
@ -871,7 +872,7 @@ export class TimelineSidebarView extends ItemView {
|
|||
// Use the formatted time component for precise grouping
|
||||
return this.formatTimeComponent(event.timeInfo.timeComponent);
|
||||
}
|
||||
|
||||
|
||||
// Fallback to hour:minute format
|
||||
return moment(time).format("HH:mm");
|
||||
}
|
||||
|
|
@ -881,20 +882,20 @@ export class TimelineSidebarView extends ItemView {
|
|||
*/
|
||||
private renderTimeGroup(containerEl: HTMLElement, timeKey: string, events: EnhancedTimelineEvent[]): void {
|
||||
const groupEl = containerEl.createDiv("timeline-time-group");
|
||||
|
||||
|
||||
// Time group header
|
||||
const groupHeaderEl = groupEl.createDiv("timeline-time-group-header");
|
||||
const timeEl = groupHeaderEl.createDiv("timeline-time-group-time");
|
||||
timeEl.setText(timeKey);
|
||||
timeEl.addClass("timeline-event-time");
|
||||
timeEl.addClass("timeline-event-time-group");
|
||||
|
||||
|
||||
const countEl = groupHeaderEl.createDiv("timeline-time-group-count");
|
||||
countEl.setText(`${events.length} events`);
|
||||
|
||||
// Events in the group
|
||||
const groupEventsEl = groupEl.createDiv("timeline-time-group-events");
|
||||
|
||||
|
||||
events.forEach((event) => {
|
||||
const eventEl = groupEventsEl.createDiv("timeline-event timeline-event-grouped");
|
||||
eventEl.setAttribute("data-event-id", event.id);
|
||||
|
|
@ -1132,7 +1133,7 @@ export class TimelineSidebarView extends ItemView {
|
|||
// For canvas files, open directly
|
||||
const leaf = this.app.workspace.getLeaf("tab");
|
||||
await leaf.openFile(file);
|
||||
this.app.workspace.setActiveLeaf(leaf, { focus: true });
|
||||
this.app.workspace.setActiveLeaf(leaf, {focus: true});
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1152,7 +1153,7 @@ export class TimelineSidebarView extends ItemView {
|
|||
},
|
||||
});
|
||||
// Focus the editor after opening
|
||||
this.app.workspace.setActiveLeaf(leafToUse, { focus: true });
|
||||
this.app.workspace.setActiveLeaf(leafToUse, {focus: true});
|
||||
}
|
||||
|
||||
private async handleQuickCapture(): Promise<void> {
|
||||
|
|
@ -1191,7 +1192,7 @@ export class TimelineSidebarView extends ItemView {
|
|||
);
|
||||
if (todayEl) {
|
||||
this.isAutoScrolling = true;
|
||||
todayEl.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
todayEl.scrollIntoView({behavior: "smooth", block: "start"});
|
||||
setTimeout(() => {
|
||||
this.isAutoScrolling = false;
|
||||
}, 1000);
|
||||
|
|
@ -1211,7 +1212,7 @@ export class TimelineSidebarView extends ItemView {
|
|||
if (this.isAutoScrolling) return;
|
||||
|
||||
// Implement infinite scroll or lazy loading if needed
|
||||
const { scrollTop, scrollHeight, clientHeight } =
|
||||
const {scrollTop, scrollHeight, clientHeight} =
|
||||
this.timelineContainerEl;
|
||||
|
||||
// Load more events when near bottom
|
||||
|
|
@ -1230,7 +1231,7 @@ export class TimelineSidebarView extends ItemView {
|
|||
task: Task,
|
||||
event?: EnhancedTimelineEvent
|
||||
): Promise<void> {
|
||||
const updatedTask = { ...task, completed: !task.completed };
|
||||
const updatedTask = {...task, completed: !task.completed};
|
||||
|
||||
if (updatedTask.completed) {
|
||||
updatedTask.metadata.completedDate = Date.now();
|
||||
|
|
@ -1259,7 +1260,7 @@ export class TimelineSidebarView extends ItemView {
|
|||
taskId: task.id,
|
||||
updates: updatedTask,
|
||||
});
|
||||
|
||||
|
||||
if (!result.success) {
|
||||
console.error("Failed to toggle task completion:", result.error);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import {
|
|||
} from "@/components/features/task/view/details";
|
||||
import "../styles/view.css";
|
||||
import TaskProgressBarPlugin from "../index";
|
||||
import { QuickCaptureModal } from "@/components/features/quick-capture/modals/QuickCaptureModal";
|
||||
import { QuickCaptureModal } from "@/components/features/quick-capture/modals/QuickCaptureModalWithSwitch";
|
||||
import { t } from "@/translations/helper";
|
||||
import {
|
||||
getViewSettingOrDefault,
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@
|
|||
.quick-capture-modal.quick-capture-file {
|
||||
width: 800px;
|
||||
max-width: 90vw;
|
||||
height: 750px;
|
||||
height: 700px;
|
||||
max-height: 80vh;
|
||||
min-height: fit-content;
|
||||
}
|
||||
|
|
@ -515,6 +515,10 @@
|
|||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.quick-capture-modal .modal-title:has(.is-hidden) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.quick-capture-modal .modal-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue