/* THIS IS A GENERATED/BUNDLED FILE BY ESBUILD if you want to view the source, please visit the github repository of this plugin */ var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/main.ts var main_exports = {}; __export(main_exports, { default: () => ImmersePlugin }); module.exports = __toCommonJS(main_exports); var import_obsidian3 = require("obsidian"); // src/types.ts var DEFAULT_SETTINGS = { pomodoroWorkMinutes: 25, pomodoroBreakMinutes: 5, longBreakMinutes: 15, longBreakInterval: 4, enableSounds: true, enableCelebrations: true, defaultEstimateMinutes: 30, lists: [ { id: "work", name: "Work", color: "#6366f1", icon: "\u{1F4BC}" }, { id: "personal", name: "Personal", color: "#22c55e", icon: "\u{1F3E0}" }, { id: "learning", name: "Learning", color: "#f59e0b", icon: "\u{1F4DA}" } ], autoStartBreak: true, tickSoundEnabled: false, // Daily note logging logToDaily: false, // Task reminders enableReminders: true, defaultReminderMinutes: 15 }; var DEFAULT_DATA = { tasks: [], completedToday: 0, totalFocusMinutesToday: 0, streak: 0, lastActiveDate: "", pomodorosCompleted: 0 }; var VIEW_TYPE_IMMERSE = "immerse-view"; var CELEBRATION_MESSAGES = [ { emoji: "\u{1F4A5}", message: "Crushed it!" }, { emoji: "\u{1F525}", message: "On fire!" }, { emoji: "\u26A1", message: "Lightning fast!" }, { emoji: "\u{1F3AF}", message: "Bullseye!" }, { emoji: "\u{1F680}", message: "Blasting through!" }, { emoji: "\u{1F4AA}", message: "Strong work!" }, { emoji: "\u{1F31F}", message: "Stellar!" }, { emoji: "\u2728", message: "Brilliant!" }, { emoji: "\u{1F3C6}", message: "Champion!" }, { emoji: "\u{1F389}", message: "Well done!" } ]; var EARLY_FINISH_MESSAGES = [ { emoji: "\u26A1", message: "Speed demon! Finished early!" }, { emoji: "\u{1F3CE}\uFE0F", message: "Faster than expected!" }, { emoji: "\u{1F3AF}", message: "Under budget! Nice work!" } ]; var OVERTIME_MESSAGES = [ { emoji: "\u{1F4AA}", message: "Persistence pays off!" }, { emoji: "\u{1F3C3}", message: "Marathon runner!" }, { emoji: "\u{1F525}", message: "The grind is real!" } ]; // src/view.ts var import_obsidian2 = require("obsidian"); // src/modals.ts var import_obsidian = require("obsidian"); var QuickAddTaskModal = class extends import_obsidian.Modal { constructor(app, plugin) { super(app); this.taskText = ""; this.selectedList = "work"; this.scheduledDate = ""; this.scheduledTime = ""; this.reminderMinutes = 0; this.plugin = plugin; this.estimatedMinutes = plugin.settings.defaultEstimateMinutes; this.reminderMinutes = plugin.settings.defaultReminderMinutes; if (plugin.settings.lists.length > 0) { this.selectedList = plugin.settings.lists[0].id; } } onOpen() { const { contentEl } = this; contentEl.addClass("immerse-modal"); contentEl.createEl("h2", { text: "\u26A1 Add New Task" }); new import_obsidian.Setting(contentEl).setName("Task").addText((text) => { text.setPlaceholder("What do you need to do?").onChange((value) => this.taskText = value); text.inputEl.focus(); text.inputEl.addEventListener("keydown", (e) => { if (e.key === "Enter" && this.taskText.trim()) { this.submitTask(); } }); }); new import_obsidian.Setting(contentEl).setName("Estimated Time").setDesc("How long do you think this will take?").addDropdown((dropdown) => { const options = { "5": "5 min", "10": "10 min", "15": "15 min", "20": "20 min", "25": "25 min (1 pomodoro)", "30": "30 min", "45": "45 min", "50": "50 min (2 pomodoros)", "60": "1 hour", "90": "1.5 hours", "120": "2 hours", "180": "3 hours" }; Object.entries(options).forEach(([value, label]) => { dropdown.addOption(value, label); }); dropdown.setValue(this.estimatedMinutes.toString()); dropdown.onChange((value) => this.estimatedMinutes = parseInt(value)); }); new import_obsidian.Setting(contentEl).setName("List").addDropdown((dropdown) => { this.plugin.settings.lists.forEach((list) => { dropdown.addOption(list.id, `${list.icon} ${list.name}`); }); dropdown.setValue(this.selectedList); dropdown.onChange((value) => this.selectedList = value); }); new import_obsidian.Setting(contentEl).setName("\u{1F4C5} Scheduled Date").setDesc("Optional: When do you plan to work on this?").addText((text) => { text.setPlaceholder("YYYY-MM-DD").setValue(this.scheduledDate).onChange((value) => this.scheduledDate = value); text.inputEl.type = "date"; }); new import_obsidian.Setting(contentEl).setName("\u23F0 Scheduled Time").setDesc("Optional: What time?").addText((text) => { text.setPlaceholder("HH:mm").setValue(this.scheduledTime).onChange((value) => this.scheduledTime = value); text.inputEl.type = "time"; }); if (this.plugin.settings.enableReminders) { new import_obsidian.Setting(contentEl).setName("\u{1F514} Reminder").setDesc("Remind me before the scheduled time").addDropdown((dropdown) => { dropdown.addOption("0", "No reminder"); dropdown.addOption("5", "5 minutes before"); dropdown.addOption("10", "10 minutes before"); dropdown.addOption("15", "15 minutes before"); dropdown.addOption("30", "30 minutes before"); dropdown.addOption("60", "1 hour before"); dropdown.setValue(this.reminderMinutes.toString()); dropdown.onChange((value) => this.reminderMinutes = parseInt(value)); }); } const buttonContainer = contentEl.createEl("div", { cls: "immerse-modal-buttons" }); const cancelBtn = buttonContainer.createEl("button", { text: "Cancel", cls: "immerse-btn" }); cancelBtn.addEventListener("click", () => this.close()); const addBtn = buttonContainer.createEl("button", { text: "Add Task", cls: "immerse-btn immerse-btn-primary" }); addBtn.addEventListener("click", () => this.submitTask()); } submitTask() { if (this.taskText.trim()) { const task = this.plugin.createTask(this.taskText, this.estimatedMinutes, this.selectedList); if (this.scheduledDate) { task.scheduledDate = this.scheduledDate; } if (this.scheduledTime) { task.scheduledTime = this.scheduledTime; } if (this.reminderMinutes > 0 && this.scheduledDate && this.scheduledTime) { task.reminderMinutes = this.reminderMinutes; } this.plugin.addTask(task); new import_obsidian.Notice("\u2705 Task added!"); this.close(); } else { new import_obsidian.Notice("Please enter a task description"); } } onClose() { const { contentEl } = this; contentEl.empty(); } }; var EditTaskModal = class extends import_obsidian.Modal { constructor(app, plugin, task) { super(app); this.plugin = plugin; this.task = { ...task }; } onOpen() { const { contentEl } = this; contentEl.addClass("immerse-modal"); contentEl.createEl("h2", { text: "\u270F\uFE0F Edit Task" }); new import_obsidian.Setting(contentEl).setName("Task").addText((text) => text.setValue(this.task.text).onChange((value) => this.task.text = value)); new import_obsidian.Setting(contentEl).setName("Estimated Time").addDropdown((dropdown) => { const options = { "5": "5 min", "10": "10 min", "15": "15 min", "20": "20 min", "25": "25 min", "30": "30 min", "45": "45 min", "50": "50 min", "60": "1 hour", "90": "1.5 hours", "120": "2 hours", "180": "3 hours" }; Object.entries(options).forEach(([value, label]) => { dropdown.addOption(value, label); }); dropdown.setValue(this.task.estimatedMinutes.toString()); dropdown.onChange((value) => this.task.estimatedMinutes = parseInt(value)); }); new import_obsidian.Setting(contentEl).setName("List").addDropdown((dropdown) => { this.plugin.settings.lists.forEach((list) => { dropdown.addOption(list.id, `${list.icon} ${list.name}`); }); dropdown.setValue(this.task.list); dropdown.onChange((value) => this.task.list = value); }); new import_obsidian.Setting(contentEl).setName("Notes").setDesc("Add any additional details or links").addTextArea((textarea) => { textarea.setValue(this.task.notes).onChange((value) => this.task.notes = value); textarea.inputEl.rows = 4; }); new import_obsidian.Setting(contentEl).setName("\u{1F4C5} Scheduled Date").setDesc("Optional: When do you plan to work on this?").addText((text) => { text.setPlaceholder("YYYY-MM-DD").setValue(this.task.scheduledDate || "").onChange((value) => this.task.scheduledDate = value || void 0); text.inputEl.type = "date"; }); new import_obsidian.Setting(contentEl).setName("\u23F0 Scheduled Time").setDesc("Optional: What time?").addText((text) => { text.setPlaceholder("HH:mm").setValue(this.task.scheduledTime || "").onChange((value) => this.task.scheduledTime = value || void 0); text.inputEl.type = "time"; }); if (this.plugin.settings.enableReminders) { new import_obsidian.Setting(contentEl).setName("\u{1F514} Reminder").setDesc("Remind me before the scheduled time").addDropdown((dropdown) => { dropdown.addOption("0", "No reminder"); dropdown.addOption("5", "5 minutes before"); dropdown.addOption("10", "10 minutes before"); dropdown.addOption("15", "15 minutes before"); dropdown.addOption("30", "30 minutes before"); dropdown.addOption("60", "1 hour before"); dropdown.setValue((this.task.reminderMinutes || 0).toString()); dropdown.onChange((value) => { const minutes = parseInt(value); this.task.reminderMinutes = minutes > 0 ? minutes : void 0; }); }); } if (this.task.actualMinutes > 0) { new import_obsidian.Setting(contentEl).setName("Time Tracked").setDesc(`You've worked on this task for ${this.plugin.formatTimeHuman(this.task.actualMinutes)}`); } const buttonContainer = contentEl.createEl("div", { cls: "immerse-modal-buttons" }); const cancelBtn = buttonContainer.createEl("button", { text: "Cancel", cls: "immerse-btn" }); cancelBtn.addEventListener("click", () => this.close()); const saveBtn = buttonContainer.createEl("button", { text: "Save", cls: "immerse-btn immerse-btn-primary" }); saveBtn.addEventListener("click", () => { this.plugin.updateTask(this.task.id, this.task); new import_obsidian.Notice("\u2705 Task updated!"); this.close(); }); } onClose() { const { contentEl } = this; contentEl.empty(); } }; // src/view.ts var ImmerseView = class extends import_obsidian2.ItemView { constructor(leaf, plugin) { super(leaf); this.currentFilter = "all"; // References to elements that need frequent updates this.timerTimeEl = null; this.progressBarEl = null; this.actualTimeEl = null; this.pauseBtnEl = null; this.plugin = plugin; } getViewType() { return VIEW_TYPE_IMMERSE; } getDisplayText() { return "Immerse"; } getIcon() { return "zap"; } async onOpen() { this.refresh(); } // Light update - only updates timer display without rebuilding DOM updateTimerDisplay() { if (!this.timerTimeEl) return; this.timerTimeEl.textContent = this.plugin.formatTime(this.plugin.currentTimerSeconds); if (this.progressBarEl) { let progressPercent = 0; if (this.plugin.isBreakMode) { const breakDuration = this.plugin.pomodoroCount % this.plugin.settings.longBreakInterval === 0 ? this.plugin.settings.longBreakMinutes * 60 : this.plugin.settings.pomodoroBreakMinutes * 60; progressPercent = (breakDuration - this.plugin.currentTimerSeconds) / breakDuration * 100; } else { const workDuration = this.plugin.settings.pomodoroWorkMinutes * 60; progressPercent = (workDuration - this.plugin.currentTimerSeconds) / workDuration * 100; } this.progressBarEl.style.width = `${Math.min(Math.max(progressPercent, 0), 100)}%`; } if (this.actualTimeEl && this.plugin.activeTaskId) { const task = this.plugin.data.tasks.find((t) => t.id === this.plugin.activeTaskId); if (task) { this.actualTimeEl.textContent = `Actual: ${this.plugin.formatTimeHuman(task.actualMinutes)}`; } } } refresh() { const container = this.containerEl.children[1]; container.empty(); container.addClass("immerse-container"); this.timerTimeEl = null; this.progressBarEl = null; this.actualTimeEl = null; this.pauseBtnEl = null; this.renderHeader(container); this.renderStatsBar(container); this.renderActiveTask(container); this.renderTaskList(container); } renderHeader(container) { const header = container.createEl("div", { cls: "immerse-header" }); const titleSection = header.createEl("div", { cls: "immerse-title-section" }); titleSection.createEl("h2", { text: "\u26A1 Immerse", cls: "immerse-title" }); const today = new Date(); const dateStr = today.toLocaleDateString("en-US", { weekday: "long", month: "short", day: "numeric" }); titleSection.createEl("div", { text: dateStr, cls: "immerse-date" }); const actions = header.createEl("div", { cls: "immerse-header-actions" }); const addBtn = actions.createEl("button", { cls: "immerse-btn immerse-btn-primary" }); addBtn.innerHTML = "+ Add Task"; addBtn.addEventListener("click", () => { new QuickAddTaskModal(this.app, this.plugin).open(); }); } renderStatsBar(container) { const stats = this.plugin.getStats(); const statsBar = container.createEl("div", { cls: "immerse-stats-bar" }); const statItems = [ { label: "Pending", value: stats.pendingCount.toString(), icon: "\u{1F4CB}" }, { label: "Done Today", value: stats.completedToday.toString(), icon: "\u2705" }, { label: "Focus Time", value: this.plugin.formatTimeHuman(stats.totalFocusMinutesToday), icon: "\u23F1\uFE0F" }, { label: "Streak", value: `${stats.streak} days`, icon: "\u{1F525}" } ]; statItems.forEach((stat) => { const item = statsBar.createEl("div", { cls: "immerse-stat-item" }); item.createEl("div", { cls: "immerse-stat-icon", text: stat.icon }); item.createEl("div", { cls: "immerse-stat-value", text: stat.value }); item.createEl("div", { cls: "immerse-stat-label", text: stat.label }); }); } renderActiveTask(container) { const activeSection = container.createEl("div", { cls: "immerse-active-section" }); if (this.plugin.activeTaskId) { const task = this.plugin.data.tasks.find((t) => t.id === this.plugin.activeTaskId); if (task) { activeSection.addClass("immerse-has-active"); const activeCard = activeSection.createEl("div", { cls: "immerse-active-card" }); if (this.plugin.isBreakMode) { activeCard.addClass("immerse-break-card"); const breakLabel = this.plugin.currentTimerSeconds > 0 ? "\u2615 BREAK TIME" : "\u2728 BREAK COMPLETE"; activeCard.createEl("div", { cls: "immerse-active-label", text: breakLabel }); } else { const workLabel = this.plugin.currentTimerSeconds > 0 ? "\u{1F3AF} FOCUSING ON" : "\u{1F345} POMODORO COMPLETE"; activeCard.createEl("div", { cls: "immerse-active-label", text: workLabel }); } activeCard.createEl("div", { cls: "immerse-active-task-name", text: task.text }); const timerDisplay = activeCard.createEl("div", { cls: "immerse-timer-display" }); this.timerTimeEl = timerDisplay.createEl("span", { cls: "immerse-timer-time", text: this.plugin.formatTime(this.plugin.currentTimerSeconds) }); const progressWrap = activeCard.createEl("div", { cls: "immerse-progress-wrap" }); this.progressBarEl = progressWrap.createEl("div", { cls: "immerse-progress-bar" }); let progressPercent = 0; if (this.plugin.isBreakMode) { const breakDuration = this.plugin.pomodoroCount % this.plugin.settings.longBreakInterval === 0 ? this.plugin.settings.longBreakMinutes * 60 : this.plugin.settings.pomodoroBreakMinutes * 60; progressPercent = (breakDuration - this.plugin.currentTimerSeconds) / breakDuration * 100; } else { const workDuration = this.plugin.settings.pomodoroWorkMinutes * 60; progressPercent = (workDuration - this.plugin.currentTimerSeconds) / workDuration * 100; } this.progressBarEl.style.width = `${Math.min(Math.max(progressPercent, 0), 100)}%`; if (progressPercent >= 100) this.progressBarEl.addClass("immerse-overtime"); if (!this.plugin.isBreakMode) { const timeInfo = activeCard.createEl("div", { cls: "immerse-time-info" }); timeInfo.createEl("span", { text: `Est: ${this.plugin.formatTimeHuman(task.estimatedMinutes)}` }); this.actualTimeEl = timeInfo.createEl("span", { text: `Actual: ${this.plugin.formatTimeHuman(task.actualMinutes)}` }); } const controls = activeCard.createEl("div", { cls: "immerse-active-controls" }); if (this.plugin.isBreakMode) { if (this.plugin.currentTimerSeconds > 0) { this.pauseBtnEl = controls.createEl("button", { cls: "immerse-btn immerse-btn-secondary" }); this.pauseBtnEl.innerHTML = this.plugin.isTimerRunning ? "\u23F8 Pause" : "\u25B6 Resume"; this.pauseBtnEl.addEventListener("click", () => this.plugin.toggleTimer()); const skipBreakBtn = controls.createEl("button", { cls: "immerse-btn immerse-btn-primary" }); skipBreakBtn.innerHTML = "\u23ED Skip Break"; skipBreakBtn.addEventListener("click", () => { this.plugin.isBreakMode = false; this.plugin.startPomodoro(task.id); }); const stopBtn = controls.createEl("button", { cls: "immerse-btn immerse-btn-danger" }); stopBtn.innerHTML = "\u2715 Stop"; stopBtn.addEventListener("click", () => { this.plugin.isBreakMode = false; this.plugin.stopTimer(); }); } else { const resumeWorkBtn = controls.createEl("button", { cls: "immerse-btn immerse-btn-success" }); resumeWorkBtn.innerHTML = "\u25B6 Resume Work"; resumeWorkBtn.addEventListener("click", () => { this.plugin.isBreakMode = false; this.plugin.startPomodoro(task.id); }); const stopBtn = controls.createEl("button", { cls: "immerse-btn immerse-btn-danger" }); stopBtn.innerHTML = "\u2715 Stop"; stopBtn.addEventListener("click", () => { this.plugin.isBreakMode = false; this.plugin.stopTimer(); }); } } else { if (this.plugin.currentTimerSeconds > 0) { this.pauseBtnEl = controls.createEl("button", { cls: "immerse-btn immerse-btn-secondary" }); this.pauseBtnEl.innerHTML = this.plugin.isTimerRunning ? "\u23F8 Pause" : "\u25B6 Resume"; this.pauseBtnEl.addEventListener("click", () => this.plugin.toggleTimer()); const completeBtn = controls.createEl("button", { cls: "immerse-btn immerse-btn-success" }); completeBtn.innerHTML = "\u2713 Complete"; completeBtn.addEventListener("click", () => this.plugin.completeTask(task.id)); const stopBtn = controls.createEl("button", { cls: "immerse-btn immerse-btn-danger" }); stopBtn.innerHTML = "\u2715 Stop"; stopBtn.addEventListener("click", () => this.plugin.stopTimer()); } else { const startBreakBtn = controls.createEl("button", { cls: "immerse-btn immerse-btn-secondary" }); startBreakBtn.innerHTML = "\u2615 Start Break"; startBreakBtn.addEventListener("click", () => this.plugin.startBreak()); const continueBtn = controls.createEl("button", { cls: "immerse-btn immerse-btn-primary" }); continueBtn.innerHTML = "\u25B6 Continue Working"; continueBtn.addEventListener("click", () => this.plugin.startPomodoro(task.id)); const completeBtn = controls.createEl("button", { cls: "immerse-btn immerse-btn-success" }); completeBtn.innerHTML = "\u2713 Complete"; completeBtn.addEventListener("click", () => this.plugin.completeTask(task.id)); const stopBtn = controls.createEl("button", { cls: "immerse-btn immerse-btn-danger" }); stopBtn.innerHTML = "\u2715 Stop"; stopBtn.addEventListener("click", () => this.plugin.stopTimer()); } } } } else { const startPrompt = activeSection.createEl("div", { cls: "immerse-start-prompt" }); startPrompt.createEl("div", { cls: "immerse-prompt-icon", text: "\u26A1" }); startPrompt.createEl("div", { cls: "immerse-prompt-text", text: "Ready to focus?" }); startPrompt.createEl("div", { cls: "immerse-prompt-hint", text: "Click \u25B6 on a task to start a Pomodoro session" }); } } renderTaskList(container) { const listSection = container.createEl("div", { cls: "immerse-list-section" }); const filters = listSection.createEl("div", { cls: "immerse-filters" }); const filterOptions = [ { id: "all", label: "All Tasks" }, { id: "today", label: "Today" }, { id: "completed", label: "Completed" }, ...this.plugin.settings.lists.map((l) => ({ id: l.id, label: `${l.icon} ${l.name}` })) ]; filterOptions.forEach((opt) => { const btn = filters.createEl("button", { cls: `immerse-filter-btn ${this.currentFilter === opt.id ? "active" : ""}`, text: opt.label }); btn.addEventListener("click", () => { this.currentFilter = opt.id; this.refresh(); }); }); const taskList = listSection.createEl("div", { cls: "immerse-task-list" }); let tasks = this.plugin.data.tasks; if (this.currentFilter === "today") { tasks = this.plugin.getTodaysTasks(); } else if (this.currentFilter === "completed") { tasks = this.plugin.data.tasks.filter((t) => t.completed); } else if (this.currentFilter !== "all") { tasks = this.plugin.getTasksByList(this.currentFilter); } tasks = [...tasks].sort((a, b) => { if (a.completed !== b.completed) return a.completed ? 1 : -1; return b.createdAt - a.createdAt; }); if (tasks.length === 0) { const emptyState = taskList.createEl("div", { cls: "immerse-empty-state" }); emptyState.createEl("div", { cls: "immerse-empty-icon", text: "\u{1F4DD}" }); emptyState.createEl("div", { cls: "immerse-empty-text", text: "No tasks yet" }); emptyState.createEl("div", { cls: "immerse-empty-hint", text: "Add a task to get started!" }); } else { tasks.forEach((task) => this.renderTaskItem(taskList, task)); } } renderTaskItem(container, task) { const list = this.plugin.settings.lists.find((l) => l.id === task.list); const isOverdue = !task.completed && task.scheduledDate && task.scheduledTime && new Date(`${task.scheduledDate}T${task.scheduledTime}`).getTime() < Date.now(); const taskEl = container.createEl("div", { cls: `immerse-task-item ${task.completed ? "completed" : ""} ${task.isActive ? "active" : ""} ${isOverdue ? "overdue" : ""}` }); const checkbox = taskEl.createEl("div", { cls: "immerse-checkbox" }); checkbox.innerHTML = task.completed ? "\u2713" : ""; checkbox.style.borderColor = (list == null ? void 0 : list.color) || "#6366f1"; if (task.completed) { checkbox.style.backgroundColor = (list == null ? void 0 : list.color) || "#6366f1"; checkbox.style.color = "white"; } checkbox.addEventListener("click", (e) => { e.stopPropagation(); if (!task.completed) { this.plugin.completeTask(task.id); } }); const content = taskEl.createEl("div", { cls: "immerse-task-content" }); const taskHeader = content.createEl("div", { cls: "immerse-task-header" }); taskHeader.createEl("span", { cls: "immerse-task-text", text: task.text }); if (list) { const listBadge = taskHeader.createEl("span", { cls: "immerse-list-badge", text: `${list.icon} ${list.name}` }); listBadge.style.backgroundColor = list.color + "20"; listBadge.style.color = list.color; } const taskMeta = content.createEl("div", { cls: "immerse-task-meta" }); taskMeta.createEl("span", { text: `Est: ${this.plugin.formatTimeHuman(task.estimatedMinutes)}` }); if (task.actualMinutes > 0) { const actualSpan = taskMeta.createEl("span"); actualSpan.setText(`Actual: ${this.plugin.formatTimeHuman(task.actualMinutes)}`); if (task.actualMinutes > task.estimatedMinutes) { actualSpan.addClass("immerse-overtime-text"); } } if (task.scheduledDate) { const scheduleSpan = taskMeta.createEl("span", { cls: `immerse-schedule-badge ${isOverdue ? "overdue" : ""}` }); const dateStr = task.scheduledDate; const timeStr = task.scheduledTime || ""; if (isOverdue) { scheduleSpan.setText(`\u26A0\uFE0F OVERDUE: ${dateStr}${timeStr ? " " + timeStr : ""}`); } else { scheduleSpan.setText(`\u{1F4C5} ${dateStr}${timeStr ? " " + timeStr : ""}`); } if (task.reminderMinutes) { scheduleSpan.title = `Reminder set for ${task.reminderMinutes} min before`; } } const actions = taskEl.createEl("div", { cls: "immerse-task-actions" }); if (!task.completed) { const startBtn = actions.createEl("button", { cls: "immerse-task-btn", attr: { "aria-label": "Start Pomodoro" } }); startBtn.innerHTML = "\u25B6"; startBtn.addEventListener("click", (e) => { e.stopPropagation(); this.plugin.startPomodoro(task.id); }); const stopwatchBtn = actions.createEl("button", { cls: "immerse-task-btn", attr: { "aria-label": "Start Stopwatch" } }); stopwatchBtn.innerHTML = "\u23F1"; stopwatchBtn.addEventListener("click", (e) => { e.stopPropagation(); this.plugin.startTimer(task.id); }); } const editBtn = actions.createEl("button", { cls: "immerse-task-btn", attr: { "aria-label": "Edit" } }); editBtn.innerHTML = "\u270F\uFE0F"; editBtn.addEventListener("click", (e) => { e.stopPropagation(); new EditTaskModal(this.app, this.plugin, task).open(); }); const deleteBtn = actions.createEl("button", { cls: "immerse-task-btn immerse-delete-btn", attr: { "aria-label": "Delete" } }); deleteBtn.innerHTML = "\u{1F5D1}"; deleteBtn.addEventListener("click", (e) => { e.stopPropagation(); this.plugin.deleteTask(task.id); }); } }; // src/main.ts var ImmersePlugin = class extends import_obsidian3.Plugin { constructor() { super(...arguments); // Timer state this.timerInterval = null; this.currentTimerSeconds = 0; this.isTimerRunning = false; this.isBreakMode = false; this.activeTaskId = null; this.pomodoroCount = 0; // Timestamp-based tracking for reliable background timing this.timerStartTimestamp = 0; this.pausedTimeRemaining = 0; // Focus time tracking (in seconds for accuracy) this.focusSecondsToday = 0; this.secondsWorkedOnCurrentTask = 0; // Status bar element this.statusBarEl = null; // Reminder system this.reminderCheckInterval = null; this.notifiedReminders = /* @__PURE__ */ new Set(); } // Track which reminders have been shown async onload() { await this.loadAllData(); this.checkDailyReset(); document.addEventListener("visibilitychange", () => { if (!document.hidden && this.isTimerRunning) { this.syncTimerFromTimestamp(); } }); this.registerView( VIEW_TYPE_IMMERSE, (leaf) => new ImmerseView(leaf, this) ); this.addRibbonIcon("zap", "Open Immerse", () => { this.activateView(); }); this.addCommand({ id: "open-immerse", name: "Open Immerse Panel", callback: () => this.activateView() }); this.addCommand({ id: "quick-add-task", name: "Quick Add Task", callback: () => new QuickAddTaskModal(this.app, this).open() }); this.addCommand({ id: "start-focus-mode", name: "Start Focus Mode on Next Task", callback: () => this.startFocusOnNextTask() }); this.addCommand({ id: "toggle-timer", name: "Toggle Timer (Play/Pause)", callback: () => this.toggleTimer() }); this.addCommand({ id: "complete-current-task", name: "Complete Current Task", callback: () => this.completeActiveTask() }); this.addSettingTab(new ImmerseSettingTab(this.app, this)); this.createStatusBar(); if (this.settings.enableReminders) { this.startReminderSystem(); } } onunload() { this.stopTimer(); this.stopReminderSystem(); } async loadAllData() { const loaded = await this.loadData(); this.data = Object.assign({}, DEFAULT_DATA, (loaded == null ? void 0 : loaded.data) || {}); this.settings = Object.assign({}, DEFAULT_SETTINGS, (loaded == null ? void 0 : loaded.settings) || {}); if (!this.settings.lists || this.settings.lists.length === 0) { this.settings.lists = DEFAULT_SETTINGS.lists; } this.focusSecondsToday = (this.data.totalFocusMinutesToday || 0) * 60; } async saveAllData() { this.data.totalFocusMinutesToday = Math.floor(this.focusSecondsToday / 60); await this.saveData({ settings: this.settings, data: this.data }); } checkDailyReset() { const today = new Date().toDateString(); if (this.data.lastActiveDate !== today) { const yesterday = new Date(); yesterday.setDate(yesterday.getDate() - 1); if (this.data.lastActiveDate === yesterday.toDateString()) { this.data.streak++; } else if (this.data.lastActiveDate !== today) { this.data.streak = 0; } this.data.completedToday = 0; this.data.totalFocusMinutesToday = 0; this.focusSecondsToday = 0; this.data.lastActiveDate = today; this.saveAllData(); } } async activateView() { const { workspace } = this.app; let leaf = null; const leaves = workspace.getLeavesOfType(VIEW_TYPE_IMMERSE); if (leaves.length > 0) { leaf = leaves[0]; } else { leaf = workspace.getRightLeaf(false); if (leaf) { await leaf.setViewState({ type: VIEW_TYPE_IMMERSE, active: true }); } } if (leaf) { workspace.revealLeaf(leaf); } } // ============ Task Management ============ createTask(text, estimatedMinutes = this.settings.defaultEstimateMinutes, list = "work") { return { id: this.generateId(), text, completed: false, estimatedMinutes, actualMinutes: 0, createdAt: Date.now(), list, notes: "", isActive: false }; } generateId() { return Date.now().toString(36) + Math.random().toString(36).substr(2); } addTask(task) { this.data.tasks.push(task); this.saveAllData(); this.refreshView(); } updateTask(taskId, updates) { const task = this.data.tasks.find((t) => t.id === taskId); if (task) { Object.assign(task, updates); this.saveAllData(); this.refreshView(); } } deleteTask(taskId) { this.data.tasks = this.data.tasks.filter((t) => t.id !== taskId); if (this.activeTaskId === taskId) { this.stopTimer(); this.activeTaskId = null; } this.saveAllData(); this.refreshView(); } completeTask(taskId) { const task = this.data.tasks.find((t) => t.id === taskId); if (task && !task.completed) { task.completed = true; task.completedAt = Date.now(); task.isActive = false; this.data.completedToday++; this.data.lastActiveDate = new Date().toDateString(); if (this.settings.enableCelebrations) { this.showCelebration(task); } if (this.settings.enableSounds) { this.playCompletionSound(); } if (this.settings.logToDaily) { this.logTaskToDailyNote(task); } if (this.activeTaskId === taskId) { this.stopTimer(); this.activeTaskId = null; } this.saveAllData(); this.refreshView(); } } completeActiveTask() { if (this.activeTaskId) { this.completeTask(this.activeTaskId); } else { new import_obsidian3.Notice("No active task to complete"); } } // ============ Timer Management ============ // Sync timer based on timestamp when app returns from background syncTimerFromTimestamp() { if (!this.isTimerRunning) return; this.updateStatusBar(); this.updateTimerDisplay(); } startTimer(taskId) { const task = this.data.tasks.find((t) => t.id === taskId); if (!task) return; this.stopTimer(); this.activeTaskId = taskId; task.isActive = true; this.isBreakMode = false; this.currentTimerSeconds = 0; this.isTimerRunning = true; this.secondsWorkedOnCurrentTask = task.actualMinutes * 60; this.timerStartTimestamp = Date.now(); this.pausedTimeRemaining = 0; const initialSecondsWorked = this.secondsWorkedOnCurrentTask; let alertShown = false; this.refreshView(); this.updateStatusBar(); this.timerInterval = window.setInterval(() => { const now = Date.now(); const elapsedMs = now - this.timerStartTimestamp; const elapsedSeconds = Math.floor(elapsedMs / 1e3); this.currentTimerSeconds = elapsedSeconds; this.secondsWorkedOnCurrentTask = initialSecondsWorked + elapsedSeconds; task.actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60); const newFocusSeconds = Math.floor((this.data.totalFocusMinutesToday || 0) * 60) + elapsedSeconds; this.focusSecondsToday = newFocusSeconds; this.updateStatusBar(); this.updateTimerDisplay(); if (!alertShown && this.currentTimerSeconds >= task.estimatedMinutes * 60) { alertShown = true; if (this.settings.enableSounds) { this.playAlertSound(); } new import_obsidian3.Notice(`\u23F0 Time's up for: ${task.text}`); } }, 1e3); this.saveAllData(); } startPomodoro(taskId) { const task = this.data.tasks.find((t) => t.id === taskId); if (!task) return; this.stopTimer(); this.activeTaskId = taskId; task.isActive = true; this.isBreakMode = false; this.currentTimerSeconds = this.settings.pomodoroWorkMinutes * 60; this.isTimerRunning = true; this.secondsWorkedOnCurrentTask = Math.floor(task.actualMinutes * 60); this.timerStartTimestamp = Date.now(); this.pausedTimeRemaining = this.currentTimerSeconds; const initialSecondsWorked = this.secondsWorkedOnCurrentTask; this.refreshView(); this.updateStatusBar(); this.timerInterval = window.setInterval(() => { const now = Date.now(); const elapsedMs = now - this.timerStartTimestamp; const elapsedSeconds = Math.floor(elapsedMs / 1e3); this.currentTimerSeconds = Math.max(0, this.pausedTimeRemaining - elapsedSeconds); if (!this.isBreakMode) { this.secondsWorkedOnCurrentTask = initialSecondsWorked + elapsedSeconds; const actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60); if (task.actualMinutes !== actualMinutes) { task.actualMinutes = actualMinutes; } const newFocusSeconds = Math.floor((this.data.totalFocusMinutesToday || 0) * 60) + elapsedSeconds; this.focusSecondsToday = newFocusSeconds; } this.updateStatusBar(); this.updateTimerDisplay(); if (this.currentTimerSeconds <= 0) { this.handlePomodoroEnd(); } }, 1e3); } handlePomodoroEnd() { if (this.timerInterval) { window.clearInterval(this.timerInterval); this.timerInterval = null; } this.currentTimerSeconds = 0; this.isTimerRunning = false; this.updateStatusBar(); this.updateTimerDisplay(); if (!this.isBreakMode) { this.pomodoroCount++; this.data.pomodorosCompleted++; if (this.settings.enableSounds) { this.playAlertSound(); } new import_obsidian3.Notice("\u{1F345} Pomodoro complete! Time for a break."); if (this.settings.autoStartBreak) { this.startBreak(); } else { this.refreshView(); } } else { if (this.settings.enableSounds) { this.playAlertSound(); } new import_obsidian3.Notice("\u26A1 Break over! Ready to focus?"); this.refreshView(); } this.saveAllData(); } startBreak() { this.isBreakMode = true; this.isTimerRunning = true; const isLongBreak = this.pomodoroCount % this.settings.longBreakInterval === 0; this.currentTimerSeconds = (isLongBreak ? this.settings.longBreakMinutes : this.settings.pomodoroBreakMinutes) * 60; this.timerStartTimestamp = Date.now(); this.pausedTimeRemaining = this.currentTimerSeconds; new import_obsidian3.Notice(isLongBreak ? "\u2615 Long break time!" : "\u2615 Short break time!"); this.refreshView(); if (!this.timerInterval) { this.timerInterval = window.setInterval(() => { const now = Date.now(); const elapsedMs = now - this.timerStartTimestamp; const elapsedSeconds = Math.floor(elapsedMs / 1e3); this.currentTimerSeconds = Math.max(0, this.pausedTimeRemaining - elapsedSeconds); this.updateStatusBar(); this.updateTimerDisplay(); if (this.currentTimerSeconds <= 0) { this.handlePomodoroEnd(); } }, 1e3); } this.updateStatusBar(); } toggleTimer() { if (this.isTimerRunning && this.timerInterval) { window.clearInterval(this.timerInterval); this.timerInterval = null; this.isTimerRunning = false; this.pausedTimeRemaining = this.currentTimerSeconds; } else if (this.activeTaskId) { this.isTimerRunning = true; this.timerStartTimestamp = Date.now(); const task = this.data.tasks.find((t) => t.id === this.activeTaskId); const initialSecondsWorked = this.secondsWorkedOnCurrentTask; this.timerInterval = window.setInterval(() => { const now = Date.now(); const elapsedMs = now - this.timerStartTimestamp; const elapsedSeconds = Math.floor(elapsedMs / 1e3); this.currentTimerSeconds = Math.max(0, this.pausedTimeRemaining - elapsedSeconds); if (task && !this.isBreakMode) { this.secondsWorkedOnCurrentTask = initialSecondsWorked + elapsedSeconds; task.actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60); const newFocusSeconds = Math.floor((this.data.totalFocusMinutesToday || 0) * 60) + elapsedSeconds; this.focusSecondsToday = newFocusSeconds; } this.updateStatusBar(); this.updateTimerDisplay(); if (this.currentTimerSeconds <= 0) { this.handlePomodoroEnd(); } }, 1e3); } else { new import_obsidian3.Notice("No active task. Select a task first."); } this.updateStatusBar(); this.refreshView(); } stopTimer() { if (this.timerInterval) { window.clearInterval(this.timerInterval); this.timerInterval = null; } if (this.activeTaskId) { const task = this.data.tasks.find((t) => t.id === this.activeTaskId); if (task) { task.isActive = false; task.actualMinutes = 0; } } this.isTimerRunning = false; this.activeTaskId = null; this.secondsWorkedOnCurrentTask = 0; this.timerStartTimestamp = 0; this.pausedTimeRemaining = 0; this.updateStatusBar(); this.saveAllData(); this.refreshView(); } startFocusOnNextTask() { const pendingTasks = this.data.tasks.filter((t) => !t.completed); if (pendingTasks.length > 0) { this.startPomodoro(pendingTasks[0].id); } else { new import_obsidian3.Notice("No pending tasks. Add a task first!"); } } // ============ Status Bar Timer ============ createStatusBar() { this.statusBarEl = this.addStatusBarItem(); this.statusBarEl.addClass("immerse-status-bar"); this.updateStatusBar(); this.statusBarEl.addEventListener("click", () => { this.activateView(); }); } updateStatusBar() { if (!this.statusBarEl) return; if (this.activeTaskId) { const task = this.data.tasks.find((t) => t.id === this.activeTaskId); const taskName = this.isBreakMode ? "\u2615 Break" : (task == null ? void 0 : task.text.substring(0, 20)) || "Task"; const timeStr = this.formatTime(this.currentTimerSeconds); const icon = this.isTimerRunning ? "\u25B6" : "\u23F8"; this.statusBarEl.setText(`\u26A1 ${icon} ${timeStr} - ${taskName}${task && task.text.length > 20 ? "..." : ""}`); this.statusBarEl.addClass("immerse-status-active"); } else { this.statusBarEl.setText("\u26A1 Immerse"); this.statusBarEl.removeClass("immerse-status-active"); } } // ============ Reminder System ============ startReminderSystem() { this.reminderCheckInterval = window.setInterval(() => { this.checkReminders(); }, 3e4); this.checkReminders(); } stopReminderSystem() { if (this.reminderCheckInterval) { window.clearInterval(this.reminderCheckInterval); this.reminderCheckInterval = null; } } checkReminders() { if (!this.settings.enableReminders) return; const now = new Date(); const currentTime = now.getTime(); this.data.tasks.filter((task) => !task.completed && task.scheduledDate && task.scheduledTime).forEach((task) => { const reminderKey = `${task.id}-${task.scheduledDate}-${task.scheduledTime}`; if (this.notifiedReminders.has(reminderKey)) return; const scheduledDateTime = new Date(`${task.scheduledDate}T${task.scheduledTime}`); const scheduledTime = scheduledDateTime.getTime(); if (currentTime > scheduledTime) { this.showOverdueNotice(task); this.notifiedReminders.add(reminderKey); return; } if (task.reminderMinutes) { const reminderTime = scheduledTime - task.reminderMinutes * 60 * 1e3; if (currentTime >= reminderTime) { this.showReminder(task); this.notifiedReminders.add(reminderKey); } } }); } showReminder(task) { const timeStr = task.scheduledTime; new import_obsidian3.Notice(`\u{1F514} Reminder: "${task.text}" is scheduled for ${timeStr}`, 8e3); if (this.settings.enableSounds) { this.playAlertSound(); } } showOverdueNotice(task) { const dateStr = task.scheduledDate; const timeStr = task.scheduledTime; new import_obsidian3.Notice(`\u26A0\uFE0F Overdue: "${task.text}" was scheduled for ${dateStr} ${timeStr}`, 1e4); if (this.settings.enableSounds) { this.playAlertSound(); } } // ============ Sounds & Celebrations ============ showCelebration(task) { let messages = CELEBRATION_MESSAGES; let extraMessage = ""; if (task.actualMinutes < task.estimatedMinutes) { const saved = task.estimatedMinutes - task.actualMinutes; messages = EARLY_FINISH_MESSAGES; extraMessage = ` (${saved} min early!)`; } else if (task.actualMinutes > task.estimatedMinutes * 1.5) { messages = OVERTIME_MESSAGES; } const celebration = messages[Math.floor(Math.random() * messages.length)]; new import_obsidian3.Notice(`${celebration.emoji} ${celebration.message}${extraMessage}`); } playCompletionSound() { try { const audioContext = new (window.AudioContext || window.webkitAudioContext)(); const oscillator = audioContext.createOscillator(); const gainNode = audioContext.createGain(); oscillator.connect(gainNode); gainNode.connect(audioContext.destination); oscillator.frequency.setValueAtTime(800, audioContext.currentTime); oscillator.frequency.setValueAtTime(1e3, audioContext.currentTime + 0.1); oscillator.frequency.setValueAtTime(1200, audioContext.currentTime + 0.2); gainNode.gain.setValueAtTime(0.3, audioContext.currentTime); gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.3); oscillator.start(audioContext.currentTime); oscillator.stop(audioContext.currentTime + 0.3); } catch (e) { console.log("Audio not available"); } } playAlertSound() { try { const audioContext = new (window.AudioContext || window.webkitAudioContext)(); const oscillator = audioContext.createOscillator(); const gainNode = audioContext.createGain(); oscillator.connect(gainNode); gainNode.connect(audioContext.destination); oscillator.frequency.setValueAtTime(440, audioContext.currentTime); gainNode.gain.setValueAtTime(0.3, audioContext.currentTime); for (let i = 0; i < 3; i++) { oscillator.frequency.setValueAtTime(440, audioContext.currentTime + i * 0.3); oscillator.frequency.setValueAtTime(550, audioContext.currentTime + i * 0.3 + 0.15); } gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.9); oscillator.start(audioContext.currentTime); oscillator.stop(audioContext.currentTime + 0.9); } catch (e) { console.log("Audio not available"); } } // ============ Daily Note Logging ============ async logTaskToDailyNote(task) { try { const list = this.settings.lists.find((l) => l.id === task.list); const timeDiff = task.actualMinutes - task.estimatedMinutes; let timeComparison = ""; if (timeDiff < 0) { timeComparison = `${Math.abs(timeDiff)}min under estimate \u2728`; } else if (timeDiff > 0) { timeComparison = `${timeDiff}min over estimate`; } else { timeComparison = `exactly on target \u{1F3AF}`; } const completedTime = new Date(task.completedAt || Date.now()).toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: false }); const taskEntry = `- [x] ${task.text} | ${(list == null ? void 0 : list.icon) || "\u{1F4CB}"} ${(list == null ? void 0 : list.name) || "Task"} | \u23F1\uFE0F ${this.formatTimeHuman(task.actualMinutes)} / ${this.formatTimeHuman(task.estimatedMinutes)} (${timeComparison}) | \u2705 ${completedTime}`; await this.appendToDailyNote(taskEntry); } catch (e) { console.error("Failed to log task to daily note:", e); new import_obsidian3.Notice("Failed to log task to daily note. Make sure Daily Notes core plugin is enabled."); } } getDailyNoteSettings() { var _a, _b, _c; const dailyNotesPlugin = (_b = (_a = this.app.internalPlugins) == null ? void 0 : _a.plugins) == null ? void 0 : _b["daily-notes"]; if (!(dailyNotesPlugin == null ? void 0 : dailyNotesPlugin.enabled)) { return null; } const settings = (_c = dailyNotesPlugin.instance) == null ? void 0 : _c.options; return { folder: (settings == null ? void 0 : settings.folder) || "", format: (settings == null ? void 0 : settings.format) || "YYYY-MM-DD", template: (settings == null ? void 0 : settings.template) || "" }; } formatDailyNoteDate(format) { const now = new Date(); const year = now.getFullYear(); const month = now.getMonth() + 1; const day = now.getDate(); let result = format; result = result.replace(/YYYY/g, year.toString()); result = result.replace(/YY/g, year.toString().slice(-2)); result = result.replace(/MMMM/g, now.toLocaleDateString("en-US", { month: "long" })); result = result.replace(/MMM/g, now.toLocaleDateString("en-US", { month: "short" })); result = result.replace(/MM/g, month.toString().padStart(2, "0")); result = result.replace(/(? 0 ? `${hours}hr ${mins}min` : `${hours}hr`; } refreshView() { const leaves = this.app.workspace.getLeavesOfType(VIEW_TYPE_IMMERSE); leaves.forEach((leaf) => { if (leaf.view instanceof ImmerseView) { leaf.view.refresh(); } }); } // Light refresh - only updates timer display without rebuilding DOM updateTimerDisplay() { const leaves = this.app.workspace.getLeavesOfType(VIEW_TYPE_IMMERSE); leaves.forEach((leaf) => { if (leaf.view instanceof ImmerseView) { leaf.view.updateTimerDisplay(); } }); } getTasksByList(listId) { return this.data.tasks.filter((t) => t.list === listId); } getPendingTasks() { return this.data.tasks.filter((t) => !t.completed); } getTodaysTasks() { const today = new Date().toDateString(); return this.data.tasks.filter((t) => { if (t.scheduledDate === today) return true; if (!t.scheduledDate && !t.completed) return true; return false; }); } getStats() { const pending = this.getPendingTasks(); const totalEstimate = pending.reduce((sum, t) => sum + t.estimatedMinutes, 0); const completedTasks = this.data.tasks.filter((t) => t.completed); const avgAccuracy = completedTasks.length > 0 ? completedTasks.reduce((sum, t) => sum + t.estimatedMinutes / Math.max(t.actualMinutes, 1), 0) / completedTasks.length : 1; return { pendingCount: pending.length, completedToday: this.data.completedToday, totalEstimatedMinutes: totalEstimate, totalFocusMinutesToday: Math.floor(this.focusSecondsToday / 60), streak: this.data.streak, pomodorosCompleted: this.data.pomodorosCompleted, avgAccuracy: Math.round(avgAccuracy * 100) }; } }; var ImmerseSettingTab = class extends import_obsidian3.PluginSettingTab { constructor(app, plugin) { super(app, plugin); this.plugin = plugin; } display() { const { containerEl } = this; containerEl.empty(); containerEl.createEl("h1", { text: "\u26A1 Immerse Settings" }); containerEl.createEl("h2", { text: "\u{1F345} Pomodoro Timer" }); new import_obsidian3.Setting(containerEl).setName("Work Duration").setDesc("Length of each work session in minutes").addSlider((slider) => slider.setLimits(5, 60, 5).setValue(this.plugin.settings.pomodoroWorkMinutes).setDynamicTooltip().onChange(async (value) => { this.plugin.settings.pomodoroWorkMinutes = value; await this.plugin.saveAllData(); })); new import_obsidian3.Setting(containerEl).setName("Short Break Duration").setDesc("Length of short breaks in minutes").addSlider((slider) => slider.setLimits(1, 15, 1).setValue(this.plugin.settings.pomodoroBreakMinutes).setDynamicTooltip().onChange(async (value) => { this.plugin.settings.pomodoroBreakMinutes = value; await this.plugin.saveAllData(); })); new import_obsidian3.Setting(containerEl).setName("Long Break Duration").setDesc("Length of long breaks in minutes").addSlider((slider) => slider.setLimits(5, 30, 5).setValue(this.plugin.settings.longBreakMinutes).setDynamicTooltip().onChange(async (value) => { this.plugin.settings.longBreakMinutes = value; await this.plugin.saveAllData(); })); new import_obsidian3.Setting(containerEl).setName("Long Break Interval").setDesc("Number of pomodoros before a long break").addSlider((slider) => slider.setLimits(2, 6, 1).setValue(this.plugin.settings.longBreakInterval).setDynamicTooltip().onChange(async (value) => { this.plugin.settings.longBreakInterval = value; await this.plugin.saveAllData(); })); new import_obsidian3.Setting(containerEl).setName("Auto-start Breaks").setDesc("Automatically start break timer after work session").addToggle((toggle) => toggle.setValue(this.plugin.settings.autoStartBreak).onChange(async (value) => { this.plugin.settings.autoStartBreak = value; await this.plugin.saveAllData(); })); containerEl.createEl("h2", { text: "\u2699\uFE0F General" }); new import_obsidian3.Setting(containerEl).setName("Default Time Estimate").setDesc("Default estimated time for new tasks in minutes").addSlider((slider) => slider.setLimits(5, 120, 5).setValue(this.plugin.settings.defaultEstimateMinutes).setDynamicTooltip().onChange(async (value) => { this.plugin.settings.defaultEstimateMinutes = value; await this.plugin.saveAllData(); })); new import_obsidian3.Setting(containerEl).setName("Enable Sounds").setDesc("Play sounds for timer completion and task completion").addToggle((toggle) => toggle.setValue(this.plugin.settings.enableSounds).onChange(async (value) => { this.plugin.settings.enableSounds = value; await this.plugin.saveAllData(); })); new import_obsidian3.Setting(containerEl).setName("Enable Celebrations").setDesc("Show celebration messages when completing tasks").addToggle((toggle) => toggle.setValue(this.plugin.settings.enableCelebrations).onChange(async (value) => { this.plugin.settings.enableCelebrations = value; await this.plugin.saveAllData(); })); containerEl.createEl("h2", { text: "\u{1F4DD} Daily Note Integration" }); new import_obsidian3.Setting(containerEl).setName("Log completed tasks to daily note").setDesc("When you complete a task, add an entry to your daily note. Uses the core Daily Notes plugin settings.").addToggle((toggle) => toggle.setValue(this.plugin.settings.logToDaily).onChange(async (value) => { this.plugin.settings.logToDaily = value; await this.plugin.saveAllData(); })); const infoEl = containerEl.createEl("div", { cls: "setting-item-description" }); infoEl.style.marginTop = "-10px"; infoEl.style.marginBottom = "20px"; infoEl.innerHTML = ` This feature uses the Daily Notes core plugin. Configure your daily note folder, date format, and template in Settings \u2192 Core plugins \u2192 Daily notes. `; containerEl.createEl("h2", { text: "\u{1F4CB} Lists" }); this.plugin.settings.lists.forEach((list, index) => { new import_obsidian3.Setting(containerEl).setName(`${list.icon} ${list.name}`).addText((text) => text.setValue(list.name).setPlaceholder("List name").onChange(async (value) => { this.plugin.settings.lists[index].name = value; await this.plugin.saveAllData(); })).addText((text) => text.setValue(list.icon).setPlaceholder("Emoji").onChange(async (value) => { this.plugin.settings.lists[index].icon = value; await this.plugin.saveAllData(); })).addColorPicker((picker) => picker.setValue(list.color).onChange(async (value) => { this.plugin.settings.lists[index].color = value; await this.plugin.saveAllData(); })).addButton((btn) => btn.setIcon("trash").setTooltip("Delete list").onClick(async () => { this.plugin.settings.lists.splice(index, 1); await this.plugin.saveAllData(); this.display(); })); }); new import_obsidian3.Setting(containerEl).addButton((btn) => btn.setButtonText("+ Add List").onClick(async () => { this.plugin.settings.lists.push({ id: this.plugin.generateId(), name: "New List", color: "#6366f1", icon: "\u{1F4C1}" }); await this.plugin.saveAllData(); this.display(); })); containerEl.createEl("h2", { text: "\u{1F4D6} About" }); const aboutDiv = containerEl.createDiv({ cls: "immerse-about" }); aboutDiv.innerHTML = `
Immerse is heavily inspired by Blitzit, a fantastic productivity app that combines task management with focused time tracking.
This plugin brings similar functionality directly into Obsidian, allowing you to manage tasks, use the Pomodoro technique, and track your productivity without leaving your notes.
`; } };