mirror of
https://github.com/taskgenius/taskgenius-plugin.git
synced 2026-07-22 06:40:25 +00:00
feat: support full featured modal
This commit is contained in:
parent
c96c425bdf
commit
bea3d11f88
8 changed files with 696 additions and 139 deletions
|
|
@ -71,7 +71,8 @@ export class MarkdownRendererComponent extends Component {
|
|||
constructor(
|
||||
private app: App,
|
||||
container: HTMLElement,
|
||||
sourcePath: string = ""
|
||||
sourcePath: string = "",
|
||||
private hideMarks: boolean = true
|
||||
) {
|
||||
super();
|
||||
this.container = container;
|
||||
|
|
@ -131,6 +132,11 @@ export class MarkdownRendererComponent extends Component {
|
|||
* Split markdown content into blocks based on double line breaks
|
||||
*/
|
||||
private splitIntoBlocks(markdown: string): string[] {
|
||||
if (!this.hideMarks) {
|
||||
return markdown
|
||||
.split(/\n\s*\n/)
|
||||
.filter((block) => block.trim().length > 0);
|
||||
}
|
||||
// Split on double newlines (paragraph breaks)
|
||||
return clearAllMarks(markdown)
|
||||
.split(/\n\s*\n/)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,12 @@
|
|||
import { App, Modal, Setting, TFile, Notice } from "obsidian";
|
||||
import {
|
||||
App,
|
||||
Modal,
|
||||
Setting,
|
||||
TFile,
|
||||
Notice,
|
||||
Platform,
|
||||
MarkdownRenderer,
|
||||
} from "obsidian";
|
||||
import {
|
||||
createEmbeddableMarkdownEditor,
|
||||
EmbeddableMarkdownEditor,
|
||||
|
|
@ -7,6 +15,17 @@ import TaskProgressBarPlugin from "../index";
|
|||
import { saveCapture } from "../utils/fileUtils";
|
||||
import { FileSuggest } from "../editor-ext/quickCapture";
|
||||
import { t } from "../translations/helper";
|
||||
import { MarkdownRendererComponent } from "./MarkdownRenderer";
|
||||
|
||||
interface TaskMetadata {
|
||||
startDate?: Date;
|
||||
dueDate?: Date;
|
||||
scheduledDate?: Date;
|
||||
priority?: number;
|
||||
project?: string;
|
||||
context?: string;
|
||||
recurrence?: string;
|
||||
}
|
||||
|
||||
export class QuickCaptureModal extends Modal {
|
||||
plugin: TaskProgressBarPlugin;
|
||||
|
|
@ -14,18 +33,41 @@ export class QuickCaptureModal extends Modal {
|
|||
capturedContent: string = "";
|
||||
|
||||
tempTargetFilePath: string = "";
|
||||
taskMetadata: TaskMetadata = {};
|
||||
useFullFeaturedMode: boolean = false;
|
||||
|
||||
constructor(app: App, plugin: TaskProgressBarPlugin) {
|
||||
previewContainerEl: HTMLElement | null = null;
|
||||
markdownRenderer: MarkdownRendererComponent | null = null;
|
||||
constructor(
|
||||
app: App,
|
||||
plugin: TaskProgressBarPlugin,
|
||||
metadata?: TaskMetadata,
|
||||
useFullFeaturedMode: boolean = false
|
||||
) {
|
||||
super(app);
|
||||
this.plugin = plugin;
|
||||
|
||||
this.tempTargetFilePath = this.plugin.settings.quickCapture.targetFile;
|
||||
|
||||
if (metadata) {
|
||||
this.taskMetadata = metadata;
|
||||
}
|
||||
|
||||
this.useFullFeaturedMode = useFullFeaturedMode && !Platform.isMobile;
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
const { contentEl } = this;
|
||||
this.modalEl.toggleClass("quick-capture-modal", true);
|
||||
|
||||
if (this.useFullFeaturedMode) {
|
||||
this.modalEl.toggleClass(["quick-capture-modal", "full"], true);
|
||||
this.createFullFeaturedModal(contentEl);
|
||||
} else {
|
||||
this.createSimpleModal(contentEl);
|
||||
}
|
||||
}
|
||||
|
||||
createSimpleModal(contentEl: HTMLElement) {
|
||||
this.titleEl.createDiv({
|
||||
text: t("Capture to"),
|
||||
});
|
||||
|
|
@ -44,68 +86,7 @@ export class QuickCaptureModal extends Modal {
|
|||
cls: "quick-capture-modal-editor",
|
||||
});
|
||||
|
||||
// Create the markdown editor with our EmbeddableMarkdownEditor
|
||||
setTimeout(() => {
|
||||
this.markdownEditor = createEmbeddableMarkdownEditor(
|
||||
this.app,
|
||||
editorContainer,
|
||||
{
|
||||
placeholder: this.plugin.settings.quickCapture.placeholder,
|
||||
|
||||
onEnter: (editor, mod, shift) => {
|
||||
if (mod) {
|
||||
// Submit on Cmd/Ctrl+Enter
|
||||
this.handleSubmit();
|
||||
return true;
|
||||
}
|
||||
// Allow normal Enter key behavior
|
||||
return false;
|
||||
},
|
||||
|
||||
onEscape: (editor) => {
|
||||
// Close the modal on Escape
|
||||
this.close();
|
||||
},
|
||||
|
||||
onSubmit: (editor) => {
|
||||
this.handleSubmit();
|
||||
},
|
||||
|
||||
onChange: (update) => {
|
||||
// Handle changes if needed
|
||||
this.capturedContent = this.markdownEditor?.value || "";
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
this.markdownEditor?.scope.register(
|
||||
["Alt"],
|
||||
"c",
|
||||
(e: KeyboardEvent) => {
|
||||
e.preventDefault();
|
||||
if (!this.markdownEditor) return false;
|
||||
if (this.markdownEditor.value.trim() === "") {
|
||||
this.close();
|
||||
return true;
|
||||
} else {
|
||||
this.handleSubmit();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
);
|
||||
this.markdownEditor?.scope.register(
|
||||
["Alt"],
|
||||
"x",
|
||||
(e: KeyboardEvent) => {
|
||||
e.preventDefault();
|
||||
targetFileEl.focus();
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
// Focus the editor when it's created
|
||||
this.markdownEditor?.editor?.focus();
|
||||
}, 50);
|
||||
this.setupMarkdownEditor(editorContainer, targetFileEl);
|
||||
|
||||
// Create button container
|
||||
const buttonContainer = contentEl.createDiv({
|
||||
|
|
@ -137,6 +118,289 @@ export class QuickCaptureModal extends Modal {
|
|||
);
|
||||
}
|
||||
|
||||
createFullFeaturedModal(contentEl: HTMLElement) {
|
||||
// Create a layout container with two panels
|
||||
const layoutContainer = contentEl.createDiv({
|
||||
cls: "quick-capture-layout",
|
||||
});
|
||||
|
||||
// Create left panel for configuration
|
||||
const configPanel = layoutContainer.createDiv({
|
||||
cls: "quick-capture-config-panel",
|
||||
});
|
||||
|
||||
// Create right panel for editor
|
||||
const editorPanel = layoutContainer.createDiv({
|
||||
cls: "quick-capture-editor-panel",
|
||||
});
|
||||
|
||||
// Target file selector
|
||||
const targetFileContainer = configPanel.createDiv({
|
||||
cls: "quick-capture-target-container",
|
||||
});
|
||||
|
||||
targetFileContainer.createDiv({
|
||||
text: t("Target File:"),
|
||||
cls: "quick-capture-section-title",
|
||||
});
|
||||
|
||||
const targetFileEl = targetFileContainer.createEl("div", {
|
||||
cls: "quick-capture-target",
|
||||
attr: {
|
||||
contenteditable: "true",
|
||||
spellcheck: "false",
|
||||
},
|
||||
text: this.tempTargetFilePath,
|
||||
});
|
||||
|
||||
new FileSuggest(
|
||||
this.app,
|
||||
targetFileEl,
|
||||
this.plugin.settings.quickCapture,
|
||||
(file: TFile) => {
|
||||
targetFileEl.textContent = file.path;
|
||||
this.tempTargetFilePath = file.path;
|
||||
this.markdownEditor?.editor?.focus();
|
||||
}
|
||||
);
|
||||
|
||||
// Task metadata configuration
|
||||
configPanel.createDiv({
|
||||
text: t("Task Properties"),
|
||||
cls: "quick-capture-section-title",
|
||||
});
|
||||
|
||||
// Start Date
|
||||
new Setting(configPanel).setName(t("Start Date")).addText((text) => {
|
||||
text.setPlaceholder("YYYY-MM-DD")
|
||||
.setValue(
|
||||
this.taskMetadata.startDate
|
||||
? this.formatDate(this.taskMetadata.startDate)
|
||||
: ""
|
||||
)
|
||||
.onChange((value) => {
|
||||
if (value) {
|
||||
this.taskMetadata.startDate = this.parseDate(value);
|
||||
} else {
|
||||
this.taskMetadata.startDate = undefined;
|
||||
}
|
||||
this.updatePreview();
|
||||
});
|
||||
text.inputEl.type = "date";
|
||||
});
|
||||
|
||||
// Due Date
|
||||
new Setting(configPanel).setName(t("Due Date")).addText((text) => {
|
||||
text.setPlaceholder("YYYY-MM-DD")
|
||||
.setValue(
|
||||
this.taskMetadata.dueDate
|
||||
? this.formatDate(this.taskMetadata.dueDate)
|
||||
: ""
|
||||
)
|
||||
.onChange((value) => {
|
||||
if (value) {
|
||||
this.taskMetadata.dueDate = this.parseDate(value);
|
||||
} else {
|
||||
this.taskMetadata.dueDate = undefined;
|
||||
}
|
||||
this.updatePreview();
|
||||
});
|
||||
text.inputEl.type = "date";
|
||||
});
|
||||
|
||||
// Scheduled Date
|
||||
new Setting(configPanel)
|
||||
.setName(t("Scheduled Date"))
|
||||
.addText((text) => {
|
||||
text.setPlaceholder("YYYY-MM-DD")
|
||||
.setValue(
|
||||
this.taskMetadata.scheduledDate
|
||||
? this.formatDate(this.taskMetadata.scheduledDate)
|
||||
: ""
|
||||
)
|
||||
.onChange((value) => {
|
||||
if (value) {
|
||||
this.taskMetadata.scheduledDate =
|
||||
this.parseDate(value);
|
||||
} else {
|
||||
this.taskMetadata.scheduledDate = undefined;
|
||||
}
|
||||
this.updatePreview();
|
||||
});
|
||||
text.inputEl.type = "date";
|
||||
});
|
||||
|
||||
// Priority
|
||||
new Setting(configPanel)
|
||||
.setName(t("Priority"))
|
||||
.addDropdown((dropdown) => {
|
||||
dropdown
|
||||
.addOption("", t("None"))
|
||||
.addOption("5", t("Highest"))
|
||||
.addOption("4", t("High"))
|
||||
.addOption("3", t("Medium"))
|
||||
.addOption("2", t("Low"))
|
||||
.addOption("1", t("Lowest"))
|
||||
.setValue(this.taskMetadata.priority?.toString() || "")
|
||||
.onChange((value) => {
|
||||
this.taskMetadata.priority = value
|
||||
? parseInt(value)
|
||||
: undefined;
|
||||
this.updatePreview();
|
||||
});
|
||||
});
|
||||
|
||||
// Project
|
||||
new Setting(configPanel).setName(t("Project")).addText((text) => {
|
||||
text.setPlaceholder(t("Project name"))
|
||||
.setValue(this.taskMetadata.project || "")
|
||||
.onChange((value) => {
|
||||
this.taskMetadata.project = value || undefined;
|
||||
this.updatePreview();
|
||||
});
|
||||
});
|
||||
|
||||
// Context
|
||||
new Setting(configPanel).setName(t("Context")).addText((text) => {
|
||||
text.setPlaceholder(t("Context"))
|
||||
.setValue(this.taskMetadata.context || "")
|
||||
.onChange((value) => {
|
||||
this.taskMetadata.context = value || undefined;
|
||||
this.updatePreview();
|
||||
});
|
||||
});
|
||||
|
||||
// Recurrence
|
||||
new Setting(configPanel).setName(t("Recurrence")).addText((text) => {
|
||||
text.setPlaceholder(t("e.g., every day, every week"))
|
||||
.setValue(this.taskMetadata.recurrence || "")
|
||||
.onChange((value) => {
|
||||
this.taskMetadata.recurrence = value || undefined;
|
||||
this.updatePreview();
|
||||
});
|
||||
});
|
||||
|
||||
// Create editor container in the right panel
|
||||
const editorContainer = editorPanel.createDiv({
|
||||
cls: "quick-capture-modal-editor",
|
||||
});
|
||||
|
||||
editorPanel.createDiv({
|
||||
text: t("Task Content"),
|
||||
cls: "quick-capture-section-title",
|
||||
});
|
||||
|
||||
this.previewContainerEl = editorPanel.createDiv({
|
||||
cls: "preview-container",
|
||||
});
|
||||
|
||||
this.markdownRenderer = new MarkdownRendererComponent(
|
||||
this.app,
|
||||
this.previewContainerEl,
|
||||
"",
|
||||
false
|
||||
);
|
||||
|
||||
this.setupMarkdownEditor(editorContainer);
|
||||
|
||||
// Create button container
|
||||
const buttonContainer = contentEl.createDiv({
|
||||
cls: "quick-capture-modal-buttons",
|
||||
});
|
||||
|
||||
// Create the buttons
|
||||
const submitButton = buttonContainer.createEl("button", {
|
||||
text: t("Capture"),
|
||||
cls: "mod-cta",
|
||||
});
|
||||
submitButton.addEventListener("click", () => this.handleSubmit());
|
||||
|
||||
const cancelButton = buttonContainer.createEl("button", {
|
||||
text: t("Cancel"),
|
||||
});
|
||||
cancelButton.addEventListener("click", () => this.close());
|
||||
}
|
||||
|
||||
updatePreview() {
|
||||
if (this.previewContainerEl) {
|
||||
this.markdownRenderer?.render(
|
||||
this.processContentWithMetadata(this.capturedContent)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
setupMarkdownEditor(container: HTMLElement, targetFileEl?: HTMLElement) {
|
||||
// Create the markdown editor with our EmbeddableMarkdownEditor
|
||||
setTimeout(() => {
|
||||
this.markdownEditor = createEmbeddableMarkdownEditor(
|
||||
this.app,
|
||||
container,
|
||||
{
|
||||
placeholder: this.plugin.settings.quickCapture.placeholder,
|
||||
|
||||
onEnter: (editor, mod, shift) => {
|
||||
if (mod) {
|
||||
// Submit on Cmd/Ctrl+Enter
|
||||
this.handleSubmit();
|
||||
return true;
|
||||
}
|
||||
// Allow normal Enter key behavior
|
||||
return false;
|
||||
},
|
||||
|
||||
onEscape: (editor) => {
|
||||
// Close the modal on Escape
|
||||
this.close();
|
||||
},
|
||||
|
||||
onSubmit: (editor) => {
|
||||
this.handleSubmit();
|
||||
},
|
||||
|
||||
onChange: (update) => {
|
||||
// Handle changes if needed
|
||||
this.capturedContent = this.markdownEditor?.value || "";
|
||||
|
||||
if (this.updatePreview) {
|
||||
this.updatePreview();
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
this.markdownEditor?.scope.register(
|
||||
["Alt"],
|
||||
"c",
|
||||
(e: KeyboardEvent) => {
|
||||
e.preventDefault();
|
||||
if (!this.markdownEditor) return false;
|
||||
if (this.markdownEditor.value.trim() === "") {
|
||||
this.close();
|
||||
return true;
|
||||
} else {
|
||||
this.handleSubmit();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
if (targetFileEl) {
|
||||
this.markdownEditor?.scope.register(
|
||||
["Alt"],
|
||||
"x",
|
||||
(e: KeyboardEvent) => {
|
||||
e.preventDefault();
|
||||
targetFileEl.focus();
|
||||
return true;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Focus the editor when it's created
|
||||
this.markdownEditor?.editor?.focus();
|
||||
}, 50);
|
||||
}
|
||||
|
||||
async handleSubmit() {
|
||||
const content =
|
||||
this.capturedContent.trim() ||
|
||||
|
|
@ -149,7 +413,8 @@ export class QuickCaptureModal extends Modal {
|
|||
}
|
||||
|
||||
try {
|
||||
await saveCapture(this.app, content, {
|
||||
const processedContent = this.processContentWithMetadata(content);
|
||||
await saveCapture(this.app, processedContent, {
|
||||
...this.plugin.settings.quickCapture,
|
||||
targetFile: this.tempTargetFilePath,
|
||||
});
|
||||
|
|
@ -160,6 +425,137 @@ export class QuickCaptureModal extends Modal {
|
|||
}
|
||||
}
|
||||
|
||||
processContentWithMetadata(content: string): string {
|
||||
// Split content into lines
|
||||
const lines = content.split("\n");
|
||||
const processedLines: string[] = [];
|
||||
const indentationRegex = /^(\s+)/;
|
||||
|
||||
for (const line of lines) {
|
||||
if (!line.trim()) {
|
||||
processedLines.push(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for indentation to identify sub-tasks
|
||||
const indentMatch = line.match(indentationRegex);
|
||||
const isSubTask = indentMatch && indentMatch[1].length > 0;
|
||||
|
||||
// Check if line is already a task or a list item
|
||||
const isTaskOrList = line
|
||||
.trim()
|
||||
.match(/^(-|\d+\.|\*|\+)(\s+\[[-x ]\])?/);
|
||||
|
||||
if (isSubTask) {
|
||||
// Don't add metadata to sub-tasks
|
||||
processedLines.push(line);
|
||||
} else if (isTaskOrList) {
|
||||
// If it's a task, add metadata
|
||||
if (line.trim().match(/^(-|\d+\.|\*|\+)\s+\[[-x ]\]/)) {
|
||||
processedLines.push(this.addMetadataToTask(line));
|
||||
} else {
|
||||
// If it's a list item but not a task, convert to task and add metadata
|
||||
const listPrefix = line
|
||||
.trim()
|
||||
.match(/^(-|\d+\.|\*|\+)/)?.[0];
|
||||
const restOfLine = line
|
||||
.trim()
|
||||
.substring(listPrefix?.length || 0)
|
||||
.trim();
|
||||
processedLines.push(
|
||||
this.addMetadataToTask(
|
||||
`${listPrefix} [ ] ${restOfLine}`
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Not a list item or task, convert to task and add metadata
|
||||
processedLines.push(this.addMetadataToTask(`- [ ] ${line}`));
|
||||
}
|
||||
}
|
||||
|
||||
return processedLines.join("\n");
|
||||
}
|
||||
|
||||
addMetadataToTask(taskLine: string): string {
|
||||
const metadata = this.generateMetadataString();
|
||||
if (!metadata) return taskLine;
|
||||
|
||||
return `${taskLine} ${metadata}`.trim();
|
||||
}
|
||||
|
||||
generateMetadataString(): string {
|
||||
const metadata: string[] = [];
|
||||
|
||||
// Format dates to strings in YYYY-MM-DD format
|
||||
if (this.taskMetadata.startDate) {
|
||||
metadata.push(`🛫 ${this.formatDate(this.taskMetadata.startDate)}`);
|
||||
}
|
||||
|
||||
if (this.taskMetadata.dueDate) {
|
||||
metadata.push(`📅 ${this.formatDate(this.taskMetadata.dueDate)}`);
|
||||
}
|
||||
|
||||
if (this.taskMetadata.scheduledDate) {
|
||||
metadata.push(
|
||||
`⏳ ${this.formatDate(this.taskMetadata.scheduledDate)}`
|
||||
);
|
||||
}
|
||||
|
||||
// Add priority if set
|
||||
if (this.taskMetadata.priority) {
|
||||
let priorityMarker = "";
|
||||
switch (this.taskMetadata.priority) {
|
||||
case 5:
|
||||
priorityMarker = "🔺";
|
||||
break; // Highest
|
||||
case 4:
|
||||
priorityMarker = "⏫";
|
||||
break; // High
|
||||
case 3:
|
||||
priorityMarker = "🔼";
|
||||
break; // Medium
|
||||
case 2:
|
||||
priorityMarker = "🔽";
|
||||
break; // Low
|
||||
case 1:
|
||||
priorityMarker = "⏬";
|
||||
break; // Lowest
|
||||
}
|
||||
if (priorityMarker) {
|
||||
metadata.push(priorityMarker);
|
||||
}
|
||||
}
|
||||
|
||||
// Add project if set
|
||||
if (this.taskMetadata.project) {
|
||||
metadata.push(`#project/${this.taskMetadata.project}`);
|
||||
}
|
||||
|
||||
// Add context if set
|
||||
if (this.taskMetadata.context) {
|
||||
metadata.push(`@${this.taskMetadata.context}`);
|
||||
}
|
||||
|
||||
// Add recurrence if set
|
||||
if (this.taskMetadata.recurrence) {
|
||||
metadata.push(`🔁 ${this.taskMetadata.recurrence}`);
|
||||
}
|
||||
|
||||
return metadata.join(" ");
|
||||
}
|
||||
|
||||
formatDate(date: Date): string {
|
||||
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(
|
||||
2,
|
||||
"0"
|
||||
)}-${String(date.getDate()).padStart(2, "0")}`;
|
||||
}
|
||||
|
||||
parseDate(dateString: string): Date {
|
||||
return new Date(dateString);
|
||||
}
|
||||
|
||||
onClose() {
|
||||
const { contentEl } = this;
|
||||
|
||||
|
|
@ -171,5 +567,10 @@ export class QuickCaptureModal extends Modal {
|
|||
|
||||
// Clear the content
|
||||
contentEl.empty();
|
||||
|
||||
if (this.markdownRenderer) {
|
||||
this.markdownRenderer.unload();
|
||||
this.markdownRenderer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
144
src/index.ts
144
src/index.ts
|
|
@ -301,6 +301,83 @@ export default class TaskProgressBarPlugin extends Plugin {
|
|||
this.activateTaskView();
|
||||
},
|
||||
});
|
||||
|
||||
// Add a global command for quick capture from anywhere
|
||||
this.addCommand({
|
||||
id: "global-quick-capture",
|
||||
name: t("Quick capture (Global)"),
|
||||
callback: () => {
|
||||
// Get the active leaf if available
|
||||
const activeLeaf =
|
||||
this.app.workspace.getActiveViewOfType(MarkdownView);
|
||||
|
||||
if (activeLeaf && activeLeaf.editor) {
|
||||
// If we're in a markdown editor, use the editor command
|
||||
const editorView = activeLeaf.editor.cm as EditorView;
|
||||
|
||||
// Import necessary functions dynamically to avoid circular dependencies
|
||||
|
||||
try {
|
||||
// Show the quick capture panel
|
||||
editorView.dispatch({
|
||||
effects: toggleQuickCapture.of(true),
|
||||
});
|
||||
} catch (e) {
|
||||
// No quick capture state found, try to add the extension first
|
||||
// This is a simplified approach and might not work in all cases
|
||||
this.registerEditorExtension([
|
||||
quickCaptureExtension(this.app, this),
|
||||
]);
|
||||
|
||||
// Try again after registering the extension
|
||||
setTimeout(() => {
|
||||
try {
|
||||
editorView.dispatch({
|
||||
effects: toggleQuickCapture.of(true),
|
||||
});
|
||||
} catch (e) {
|
||||
new Notice(
|
||||
t(
|
||||
"Could not open quick capture panel in the current editor"
|
||||
)
|
||||
);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
} else {
|
||||
// No active markdown view, show a floating capture window instead
|
||||
// Create a simple modal with capture functionality
|
||||
new QuickCaptureModal(this.app, this).open();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Add command for full-featured task capture
|
||||
this.addCommand({
|
||||
id: "full-featured-task-capture",
|
||||
name: t("Task capture with metadata"),
|
||||
callback: () => {
|
||||
// Create a modal with full task metadata options
|
||||
new QuickCaptureModal(this.app, this, {}, true).open();
|
||||
},
|
||||
});
|
||||
|
||||
// Add command for toggling task filter
|
||||
this.addCommand({
|
||||
id: "toggle-task-filter",
|
||||
name: t("Toggle task filter panel"),
|
||||
editorCallback: (editor, ctx) => {
|
||||
const view = editor.cm as EditorView;
|
||||
|
||||
if (view) {
|
||||
view.dispatch({
|
||||
effects: toggleTaskFilter.of(
|
||||
!view.state.field(taskFilterState)
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
registerCommands() {
|
||||
|
|
@ -473,73 +550,6 @@ export default class TaskProgressBarPlugin extends Plugin {
|
|||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Add a global command for quick capture from anywhere
|
||||
this.addCommand({
|
||||
id: "global-quick-capture",
|
||||
name: t("Quick capture (Global)"),
|
||||
callback: () => {
|
||||
// Get the active leaf if available
|
||||
const activeLeaf =
|
||||
this.app.workspace.getActiveViewOfType(MarkdownView);
|
||||
|
||||
if (activeLeaf && activeLeaf.editor) {
|
||||
// If we're in a markdown editor, use the editor command
|
||||
const editorView = activeLeaf.editor.cm as EditorView;
|
||||
|
||||
// Import necessary functions dynamically to avoid circular dependencies
|
||||
|
||||
try {
|
||||
// Show the quick capture panel
|
||||
editorView.dispatch({
|
||||
effects: toggleQuickCapture.of(true),
|
||||
});
|
||||
} catch (e) {
|
||||
// No quick capture state found, try to add the extension first
|
||||
// This is a simplified approach and might not work in all cases
|
||||
this.registerEditorExtension([
|
||||
quickCaptureExtension(this.app, this),
|
||||
]);
|
||||
|
||||
// Try again after registering the extension
|
||||
setTimeout(() => {
|
||||
try {
|
||||
editorView.dispatch({
|
||||
effects: toggleQuickCapture.of(true),
|
||||
});
|
||||
} catch (e) {
|
||||
new Notice(
|
||||
t(
|
||||
"Could not open quick capture panel in the current editor"
|
||||
)
|
||||
);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
} else {
|
||||
// No active markdown view, show a floating capture window instead
|
||||
// Create a simple modal with capture functionality
|
||||
new QuickCaptureModal(this.app, this).open();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Add command for toggling task filter
|
||||
this.addCommand({
|
||||
id: "toggle-task-filter",
|
||||
name: t("Toggle task filter panel"),
|
||||
editorCallback: (editor, ctx) => {
|
||||
const view = editor.cm as EditorView;
|
||||
|
||||
if (view) {
|
||||
view.dispatch({
|
||||
effects: toggleTaskFilter.of(
|
||||
!view.state.field(taskFilterState)
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
registerEditorExt() {
|
||||
|
|
|
|||
|
|
@ -102,7 +102,9 @@ export class TaskView extends ItemView {
|
|||
.onClick(() => {
|
||||
const modal = new QuickCaptureModal(
|
||||
this.plugin.app,
|
||||
this.plugin
|
||||
this.plugin,
|
||||
{},
|
||||
true
|
||||
);
|
||||
modal.open();
|
||||
});
|
||||
|
|
@ -215,7 +217,12 @@ export class TaskView extends ItemView {
|
|||
this.detailsToggleBtn.toggleClass("panel-toggle-btn", true);
|
||||
|
||||
this.addAction("check-square", "capture", () => {
|
||||
const modal = new QuickCaptureModal(this.plugin.app, this.plugin);
|
||||
const modal = new QuickCaptureModal(
|
||||
this.plugin.app,
|
||||
this.plugin,
|
||||
{},
|
||||
true
|
||||
);
|
||||
modal.open();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,3 +100,72 @@
|
|||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
/* Full-featured modal styles */
|
||||
.quick-capture-modal.full {
|
||||
width: 80vw;
|
||||
max-width: 900px;
|
||||
}
|
||||
|
||||
.quick-capture-layout {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
gap: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.quick-capture-config-panel {
|
||||
flex: 1;
|
||||
border-right: 1px solid var(--background-modifier-border);
|
||||
padding-right: 16px;
|
||||
overflow-y: auto;
|
||||
max-width: 40%;
|
||||
}
|
||||
|
||||
.quick-capture-editor-panel {
|
||||
flex: 1.5;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.quick-capture-section-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
font-size: var(--font-ui-medium);
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.quick-capture-target-container {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.quick-capture-modal.full .quick-capture-modal-editor {
|
||||
min-height: 200px;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: var(--radius-s);
|
||||
padding: 8px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
/* Mobile optimization */
|
||||
@media (max-width: 768px) {
|
||||
.quick-capture-modal.full {
|
||||
width: 95vw;
|
||||
}
|
||||
|
||||
.quick-capture-layout {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.quick-capture-config-panel {
|
||||
max-width: 100%;
|
||||
border-right: none;
|
||||
border-bottom: 1px solid var(--background-modifier-border);
|
||||
padding-right: 0;
|
||||
padding-bottom: 16px;
|
||||
margin-bottom: 16px;
|
||||
max-height: 40%;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,10 @@
|
|||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: var(--size-4-2);
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--size-2-1);
|
||||
}
|
||||
|
||||
.tag-list-item {
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@
|
|||
background-color: var(--background-modifier-active-hover);
|
||||
padding: var(--size-2-1) var(--size-2-3);
|
||||
border-radius: var(--radius-s);
|
||||
opacity: 0.5;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.task-item:hover .task-date {
|
||||
|
|
|
|||
64
styles.css
64
styles.css
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue