diff --git a/src/codeblocks/dateHeader/components/dateNavigator/DateNavigator.ts b/src/codeblocks/dateHeader/DateNavigator.ts similarity index 100% rename from src/codeblocks/dateHeader/components/dateNavigator/DateNavigator.ts rename to src/codeblocks/dateHeader/DateNavigator.ts diff --git a/src/codeblocks/dateHeader/components/dateNavigator/dateNavigator.types.ts b/src/codeblocks/dateHeader/dateNavigator.types.ts similarity index 100% rename from src/codeblocks/dateHeader/components/dateNavigator/dateNavigator.types.ts rename to src/codeblocks/dateHeader/dateNavigator.types.ts diff --git a/src/codeblocks/dateHeader/components/dateNavigator/dom/buildDateNavigatorDOM.ts b/src/codeblocks/dateHeader/dom/buildDateNavigatorDOM.ts similarity index 91% rename from src/codeblocks/dateHeader/components/dateNavigator/dom/buildDateNavigatorDOM.ts rename to src/codeblocks/dateHeader/dom/buildDateNavigatorDOM.ts index bec0f51..cd25d04 100644 --- a/src/codeblocks/dateHeader/components/dateNavigator/dom/buildDateNavigatorDOM.ts +++ b/src/codeblocks/dateHeader/dom/buildDateNavigatorDOM.ts @@ -1,6 +1,5 @@ -// src/components/dateNavigator/dom/buildDateNavigatorDOM.ts -import { formatDateForDisplay, parseDateISO } from "../../datePicker/datePickerUtils"; -import type { DateNavigatorDOMElements } from "../dateNavigator.types"; // Type only +import { formatDateForDisplay, parseDateISO } from "src/helpers/dateUtils"; +import type { DateNavigatorDOMElements } from "../dateNavigator.types"; //? Structure for the handlers needed by the builder export interface DateNavigatorHandlers { @@ -15,7 +14,7 @@ export function buildDateNavigatorDOM( initialIsoDate: string, handlers: DateNavigatorHandlers ): DateNavigatorDOMElements { - containerEl.empty(); // Clear container first + containerEl.empty(); const wrapper = containerEl.createDiv({ cls: "date-navigator-wrapper" }); const navRow = wrapper.createDiv({ cls: "date-nav-row" }); diff --git a/src/codeblocks/dateHeader/components/dateNavigator/eventHandlers/dateNavigationHandlers.ts b/src/codeblocks/dateHeader/eventHandlers/dateNavigationHandlers.ts similarity index 75% rename from src/codeblocks/dateHeader/components/dateNavigator/eventHandlers/dateNavigationHandlers.ts rename to src/codeblocks/dateHeader/eventHandlers/dateNavigationHandlers.ts index c959969..e93b401 100644 --- a/src/codeblocks/dateHeader/components/dateNavigator/eventHandlers/dateNavigationHandlers.ts +++ b/src/codeblocks/dateHeader/eventHandlers/dateNavigationHandlers.ts @@ -1,8 +1,7 @@ -// src/components/dateNavigator/eventHandlers/dateNavigationHandlers.ts import { App } from "obsidian"; -import { DatePickerModal } from "../../datePicker/DatePickerModal"; +import { DatePickerModal } from "src/components/DatePickerModal/DatePickerModal"; import { PluginState } from "src/pluginState"; -import { parseDateISO, formatDateISO } from "../../datePicker/datePickerUtils"; +import { parseDateISO, formatDateISO } from "src/helpers/dateUtils"; import { NavigationPeriod } from "../dateNavigator.types"; /** Updates the global plugin state with the new date and triggers necessary updates */ @@ -10,13 +9,10 @@ function updateGlobalDate(newDate: Date, pluginState: PluginState, app: App): vo const newIsoDate = formatDateISO(newDate); if (pluginState.selectedDate !== newIsoDate) { pluginState.selectedDate = newIsoDate; - // Optional: Force re-render if needed, maybe make this configurable - // app.workspace.getActiveViewOfType(MarkdownView)?.previewMode?.rerender(true); } - //todo: Could add dispatchEvent here for more reactive updates elsewhere } -/** //? Creates the handler for the "previous" button click */ +/** Creates the handler for the "previous" button click */ export function createPrevHandler( pluginState: PluginState, period: NavigationPeriod, @@ -49,7 +45,6 @@ export function createNextHandler( ): () => void { return () => { const currentDate = parseDateISO(pluginState.selectedDate) ?? new Date(); - //& console.log(`[DateNavHandlers] Next clicked. Current: ${formatDateISO(currentDate)}, Period: ${period}`); switch (period) { case 'day': currentDate.setUTCDate(currentDate.getUTCDate() + 1); @@ -72,8 +67,6 @@ export function createOpenModalHandler( ): () => void { return () => { new DatePickerModal(app, pluginState.selectedDate, (newIsoDate) => { - //? This is the callback executed when the modal confirms a selection - //? No need to call updateGlobalDate here, modal already did via pluginState setter updateDisplayCallback(newIsoDate); }).open(); }; diff --git a/src/codeblocks/dateHeader/index.ts b/src/codeblocks/dateHeader/index.ts index f09e2be..1c82ea8 100644 --- a/src/codeblocks/dateHeader/index.ts +++ b/src/codeblocks/dateHeader/index.ts @@ -1,6 +1,6 @@ import { MarkdownRenderChild, App } from 'obsidian'; -import { DateNavigator } from './components/dateNavigator/DateNavigator'; +import { DateNavigator } from './DateNavigator'; import { pluginState } from '../../pluginState'; /** diff --git a/src/codeblocks/dateHeader/components/datePicker/DatePickerModal.ts b/src/components/DatePickerModal/DatePickerModal.ts similarity index 98% rename from src/codeblocks/dateHeader/components/datePicker/DatePickerModal.ts rename to src/components/DatePickerModal/DatePickerModal.ts index 26f3a26..f8ab4ea 100644 --- a/src/codeblocks/dateHeader/components/datePicker/DatePickerModal.ts +++ b/src/components/DatePickerModal/DatePickerModal.ts @@ -3,7 +3,7 @@ import { buildDatePickerHeader } from "./dom/buildDatePickerHeader"; import { buildWeekdayHeaders } from "./dom/buildWeekdayHeaders"; import { buildCalendarGrid } from "./dom/buildCalendarGrid"; import { buildDatePickerFooter } from "./dom/buildDatePickerFooter"; -import { formatDateISO, parseDateISO } from "./datePickerUtils"; +import { formatDateISO, parseDateISO } from "src/helpers/dateUtils"; export class DatePickerModal extends Modal { private selectedDateObj: Date; //? Internal state as Date object diff --git a/src/components/DatePickerModal/datePickerUtils.ts b/src/components/DatePickerModal/datePickerUtils.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/codeblocks/dateHeader/components/datePicker/dom/buildCalendarGrid.ts b/src/components/DatePickerModal/dom/buildCalendarGrid.ts similarity index 98% rename from src/codeblocks/dateHeader/components/datePicker/dom/buildCalendarGrid.ts rename to src/components/DatePickerModal/dom/buildCalendarGrid.ts index 442e22b..ea21214 100644 --- a/src/codeblocks/dateHeader/components/datePicker/dom/buildCalendarGrid.ts +++ b/src/components/DatePickerModal/dom/buildCalendarGrid.ts @@ -1,4 +1,4 @@ -import { getISOWeekNumber } from "../datePickerUtils"; +import { getISOWeekNumber } from "src/helpers/dateUtils"; /** * Builds the main grid of days for the calendar month. diff --git a/src/codeblocks/dateHeader/components/datePicker/dom/buildDatePickerFooter.ts b/src/components/DatePickerModal/dom/buildDatePickerFooter.ts similarity index 86% rename from src/codeblocks/dateHeader/components/datePicker/dom/buildDatePickerFooter.ts rename to src/components/DatePickerModal/dom/buildDatePickerFooter.ts index 24640e1..a258ac8 100644 --- a/src/codeblocks/dateHeader/components/datePicker/dom/buildDatePickerFooter.ts +++ b/src/components/DatePickerModal/dom/buildDatePickerFooter.ts @@ -1,5 +1,4 @@ -// src/components/datePicker/dom/buildDatePickerFooter.ts -import { formatDateForDisplay } from "../datePickerUtils"; // Use consistent display formatting +import { formatDateForDisplay } from "src/helpers/dateUtils"; /** * Builds the footer section of the date picker modal (Selected Date Display, Confirm Button). diff --git a/src/codeblocks/dateHeader/components/datePicker/dom/buildDatePickerHeader.ts b/src/components/DatePickerModal/dom/buildDatePickerHeader.ts similarity index 100% rename from src/codeblocks/dateHeader/components/datePicker/dom/buildDatePickerHeader.ts rename to src/components/DatePickerModal/dom/buildDatePickerHeader.ts diff --git a/src/codeblocks/dateHeader/components/datePicker/dom/buildWeekdayHeaders.ts b/src/components/DatePickerModal/dom/buildWeekdayHeaders.ts similarity index 100% rename from src/codeblocks/dateHeader/components/datePicker/dom/buildWeekdayHeaders.ts rename to src/components/DatePickerModal/dom/buildWeekdayHeaders.ts diff --git a/src/components/TimePickerModal.ts b/src/components/TimePickerModal.ts deleted file mode 100644 index 8413c33..0000000 --- a/src/components/TimePickerModal.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { App, Modal, Notice, Setting } from "obsidian"; - -//? A very basic example modal for selecting a time. -export class TimePickerModal extends Modal { - private currentTime: string; // e.g., "HH:MM" - private onSelectCallback: (selectedTime: string) => void; - - constructor(app: App, initialTime: string | undefined, onSelect: (selectedTime: string) => void) { - super(app); - //? Basic validation or default - this.currentTime = initialTime && /^\d{2}:\d{2}$/.test(initialTime) ? initialTime : "12:00"; - this.onSelectCallback = onSelect; - } - - onOpen() { - const { contentEl } = this; - contentEl.empty(); - contentEl.addClass("time-picker-modal-content"); // For styling - - contentEl.createEl("h2", { text: "Select Time" }); - - // --- Basic Time Input (replace with better UI later) --- - let tempTime = this.currentTime; - new Setting(contentEl) - .setName("Time (HH:MM)") - .addText(text => text - .setValue(tempTime) - .setPlaceholder("HH:MM") - .onChange(value => { - // Basic format check - if (/^\d{1,2}:\d{1,2}$/.test(value)) { - // Format to HH:MM - const parts = value.split(':'); - const hh = parts[0].padStart(2,'0'); - const mm = parts[1].padStart(2,'0'); - // Basic hour/minute range check (can be improved) - if (parseInt(hh) >= 0 && parseInt(hh) <= 23 && parseInt(mm) >= 0 && parseInt(mm) <= 59) { - tempTime = `${hh}:${mm}`; - } else { - // Handle invalid range slightly? Or let confirm check. - } - } - })); - - // --- Action Buttons --- - new Setting(contentEl) - .addButton(button => button - .setButtonText("Cancel") - .onClick(() => this.close())) - .addButton(button => button - .setButtonText("Confirm") - .setCta() // Make it the primary action - .onClick(() => { - //? Final validation before confirming - if (/^\d{2}:\d{2}$/.test(tempTime)) { - this.onSelectCallback(tempTime); - this.close(); - } else { - new Notice("Invalid time format. Use HH:MM."); - } - })); - } - - onClose() { - this.contentEl.empty(); - } -} \ No newline at end of file diff --git a/src/components/TimePickerModal/TimePickerModal.ts b/src/components/TimePickerModal/TimePickerModal.ts new file mode 100644 index 0000000..ebf509c --- /dev/null +++ b/src/components/TimePickerModal/TimePickerModal.ts @@ -0,0 +1,64 @@ +import { App, Modal } from "obsidian"; +import { buildTimePickerDOM, buildTimePickerActions, TimePickerDOMElements } from "./dom/buildTimePickerDOM"; +import { parseTimeString, formatTimeString } from "./timePickerUtils"; + +export class TimePickerModal extends Modal { + private initialHour: number; + private initialMinute: number; + private onSelectCallback: (selectedTime: string) => void; + + //? References to the dropdown elements + private uiElements: TimePickerDOMElements | null = null; + + constructor(app: App, initialTime: string | undefined, onSelect: (selectedTime: string) => void) { + super(app); + this.onSelectCallback = onSelect; + + //? Parse initial time into numbers + const { hour, minute } = parseTimeString(initialTime ?? ""); // Provide default if undefined + this.initialHour = hour; + this.initialMinute = minute; + + } + + onOpen() { + const { contentEl } = this; + contentEl.empty(); + contentEl.addClass("time-picker-modal-content"); // For styling + + contentEl.createEl("h2", { text: "Select Time" }); + + // --- Build Dropdowns --- + this.uiElements = buildTimePickerDOM(contentEl, this.initialHour, this.initialMinute); + + // --- Build Actions --- + buildTimePickerActions(contentEl, this._handleCancel, this._handleConfirm); + } + + // --- Handlers --- + + private _handleCancel = (): void => { + this.close(); + }; + + private _handleConfirm = (): void => { + if (!this.uiElements) { + console.error("[TimePickerModal] Cannot confirm: UI elements not found."); + return; + } + //? Get current values from dropdowns + const selectedHour = this.uiElements.hourSelect.value; + const selectedMinute = this.uiElements.minuteSelect.value; + + //? Format the selected time + const selectedTime = formatTimeString(selectedHour, selectedMinute); + + this.onSelectCallback(selectedTime); // Pass HH:MM string back + this.close(); + }; + + onClose() { + this.contentEl.empty(); + this.uiElements = null; // Clear references + } +} \ No newline at end of file diff --git a/src/components/TimePickerModal/dom/buildTimePickerDOM.ts b/src/components/TimePickerModal/dom/buildTimePickerDOM.ts new file mode 100644 index 0000000..1535bdf --- /dev/null +++ b/src/components/TimePickerModal/dom/buildTimePickerDOM.ts @@ -0,0 +1,66 @@ +import { Setting } from "obsidian"; +import { createHourOptions, createMinuteOptions } from "../timePickerUtils"; + +//? Interface for the references to the created select elements +export interface TimePickerDOMElements { + hourSelect: HTMLSelectElement; + minuteSelect: HTMLSelectElement; +} + +/** + * Builds the core UI elements (dropdowns) for the Time Picker Modal. + * @param contentEl - The HTMLElement to append the controls to. + * @param initialHour - The initially selected hour (0-23). + * @param initialMinute - The initially selected minute (0-59). + * @returns Object containing references to the select elements. + */ +export function buildTimePickerDOM( + contentEl: HTMLElement, + initialHour: number, + initialMinute: number +): TimePickerDOMElements { + + // Use Obsidian's Setting components for structure and alignment + const setting = new Setting(contentEl) + .setName("Select Time") + .setClass("time-picker-controls"); // Add class for specific styling + + // --- Hour Dropdown --- + const hourSelect = document.createElement("select"); + hourSelect.classList.add("dropdown", "time-picker-select", "time-picker-hour"); + hourSelect.setAttribute("aria-label", "Hour"); + hourSelect.appendChild(createHourOptions(initialHour)); // Populate options + setting.controlEl.appendChild(hourSelect); // Add to setting's control area + + // --- Separator --- + const separator = document.createElement("span"); + separator.textContent = ":"; + separator.addClass("time-picker-separator"); + setting.controlEl.appendChild(separator); + + // --- Minute Dropdown --- + const minuteSelect = document.createElement("select"); + minuteSelect.classList.add("dropdown", "time-picker-select", "time-picker-minute"); + minuteSelect.setAttribute("aria-label", "Minute"); + minuteSelect.appendChild(createMinuteOptions(initialMinute)); // Populate options + setting.controlEl.appendChild(minuteSelect); + + return { hourSelect, minuteSelect }; +} + +/** Builds the action buttons (Cancel, Confirm) for the modal. */ +export function buildTimePickerActions( + contentEl: HTMLElement, + onCancel: () => void, + onConfirm: () => void +): void { + new Setting(contentEl) + .setClass("time-picker-actions") // Add class for styling + .addButton(button => button + .setButtonText("Cancel") + .onClick(onCancel)) + .addButton(button => button + .setButtonText("Confirm") + .setCta() // Make it the primary action + .onClick(onConfirm)); +} \ No newline at end of file diff --git a/src/components/TimePickerModal/timePickerUtils.ts b/src/components/TimePickerModal/timePickerUtils.ts new file mode 100644 index 0000000..98b36bb --- /dev/null +++ b/src/components/TimePickerModal/timePickerUtils.ts @@ -0,0 +1,60 @@ + +/** Generates