@mrck-labs/vanaheim-shared 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -128,6 +128,17 @@ function formatTimeHHMM(date) {
128
128
  const d = typeof date === "string" ? new Date(date) : date;
129
129
  return d.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
130
130
  }
131
+ function formatTimeShort(date) {
132
+ const d = typeof date === "string" ? new Date(date) : date;
133
+ return d.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" });
134
+ }
135
+ function formatDateDisplay(date) {
136
+ return date.toLocaleDateString("en-US", {
137
+ weekday: "long",
138
+ month: "short",
139
+ day: "numeric"
140
+ });
141
+ }
131
142
  function formatTimeWithSeconds(date) {
132
143
  const d = typeof date === "string" ? new Date(date) : date;
133
144
  return d.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" });
@@ -254,6 +265,7 @@ function formatTimeLocalized(date, format = "short") {
254
265
  }
255
266
  export {
256
267
  addDays,
268
+ formatDateDisplay,
257
269
  formatDateHeader,
258
270
  formatDateLocalized,
259
271
  formatDateLong,
@@ -266,6 +278,7 @@ export {
266
278
  formatRelativeTimeExtended,
267
279
  formatTimeHHMM,
268
280
  formatTimeLocalized,
281
+ formatTimeShort,
269
282
  formatTimeWithSeconds,
270
283
  formatWeekRange,
271
284
  getEndOfDayISO,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/date/index.ts"],"sourcesContent":["/**\n * Date Utilities\n *\n * Pure functions for date manipulation and formatting.\n * Works in both Node.js and browser/React Native environments.\n *\n * @example\n * import { getTodayString, addDays, formatRelativeTime } from '@mrck-labs/vanaheim-shared/date'\n *\n * const today = getTodayString() // \"2024-12-16\"\n * const nextWeek = addDays(today, 7) // \"2024-12-23\"\n */\n\n// ============================================================================\n// Core Utilities\n// ============================================================================\n\n/**\n * Normalize a date to midnight (00:00:00.000)\n */\nexport function normalizeToMidnight(date: Date): Date {\n const d = new Date(date)\n d.setHours(0, 0, 0, 0)\n return d\n}\n\n/**\n * Get today's date normalized to midnight\n */\nexport function getTodayMidnight(): Date {\n return normalizeToMidnight(new Date())\n}\n\n/**\n * Format a Date object to YYYY-MM-DD string\n * @example formatDateString(new Date()) => \"2024-12-16\"\n */\nexport function formatDateString(date: Date): string {\n return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`\n}\n\n/**\n * Get today's local date string (YYYY-MM-DD)\n */\nexport function getTodayString(): string {\n return formatDateString(new Date())\n}\n\n/**\n * Parse a YYYY-MM-DD string to a local Date object\n * Avoids timezone issues by appending T00:00:00\n */\nexport function parseLocalDate(dateStr: string): Date {\n return new Date(dateStr + 'T00:00:00')\n}\n\n// ============================================================================\n// Date Checks\n// ============================================================================\n\n/**\n * Check if a date string is today\n */\nexport function isToday(dateStr: string | null): boolean {\n if (!dateStr) return false\n return dateStr === getTodayString()\n}\n\n/**\n * Check if a date string is in the past (before today)\n */\nexport function isOverdue(dateStr: string | null): boolean {\n if (!dateStr) return false\n return dateStr < getTodayString()\n}\n\n/**\n * Check if a date is due within a threshold of days\n * @param dateStr - Date in YYYY-MM-DD format\n * @param daysThreshold - Number of days to check (default: 7)\n */\nexport function isDueSoon(dateStr: string | null, daysThreshold: number = 7): boolean {\n if (!dateStr) return false\n if (isOverdue(dateStr)) return false\n\n const today = getTodayMidnight()\n const targetDate = parseLocalDate(dateStr)\n const diffMs = targetDate.getTime() - today.getTime()\n const diffDays = Math.ceil(diffMs / (1000 * 60 * 60 * 24))\n\n return diffDays >= 0 && diffDays <= daysThreshold\n}\n\n// ============================================================================\n// Date Arithmetic\n// ============================================================================\n\n/**\n * Add days to a date string\n * @param dateStr - Date in YYYY-MM-DD format\n * @param days - Number of days to add (can be negative)\n * @returns New date string in YYYY-MM-DD format\n */\nexport function addDays(dateStr: string, days: number): string {\n const date = parseLocalDate(dateStr)\n date.setDate(date.getDate() + days)\n return formatDateString(date)\n}\n\n/**\n * Subtract days from a date string\n */\nexport function subtractDays(dateStr: string, days: number): string {\n return addDays(dateStr, -days)\n}\n\n/**\n * Get yesterday's date string (YYYY-MM-DD)\n */\nexport function getYesterdayString(): string {\n return subtractDays(getTodayString(), 1)\n}\n\n/**\n * Get tomorrow's date string (YYYY-MM-DD)\n */\nexport function getTomorrowString(): string {\n return addDays(getTodayString(), 1)\n}\n\n// ============================================================================\n// ISO String Helpers (for database queries)\n// ============================================================================\n\n/**\n * Get start of day as ISO string\n * @param dateStr - Date in YYYY-MM-DD format\n * @returns ISO string like \"2024-12-15T00:00:00.000Z\"\n */\nexport function getStartOfDayISO(dateStr: string): string {\n const date = parseLocalDate(dateStr)\n return new Date(date.getFullYear(), date.getMonth(), date.getDate()).toISOString()\n}\n\n/**\n * Get end of day as ISO string\n * @param dateStr - Date in YYYY-MM-DD format\n * @returns ISO string like \"2024-12-15T23:59:59.999Z\"\n */\nexport function getEndOfDayISO(dateStr: string): string {\n const date = parseLocalDate(dateStr)\n return new Date(\n date.getFullYear(),\n date.getMonth(),\n date.getDate(),\n 23,\n 59,\n 59,\n 999\n ).toISOString()\n}\n\n// ============================================================================\n// Week Utilities\n// ============================================================================\n\n/**\n * Get the start of the week (Monday) for a given date\n */\nexport function getWeekStart(date: Date): Date {\n const d = new Date(date)\n const day = d.getDay()\n const diff = d.getDate() - day + (day === 0 ? -6 : 1) // Monday\n d.setDate(diff)\n d.setHours(0, 0, 0, 0)\n return d\n}\n\n/**\n * Get the end of the week (Sunday) for a given week start\n */\nexport function getWeekEnd(weekStart: Date): Date {\n const d = new Date(weekStart)\n d.setDate(d.getDate() + 6)\n return d\n}\n\n/**\n * Get the start of the previous week\n */\nexport function getPreviousWeek(weekStart: Date): Date {\n const d = new Date(weekStart)\n d.setDate(d.getDate() - 7)\n return d\n}\n\n/**\n * Get the start of the next week\n */\nexport function getNextWeek(weekStart: Date): Date {\n const d = new Date(weekStart)\n d.setDate(d.getDate() + 7)\n return d\n}\n\n/**\n * Get start of week (Monday) as date string\n */\nexport function getWeekStartString(baseDate: Date = new Date()): string {\n return formatDateString(getWeekStart(baseDate))\n}\n\n/**\n * Get end of week (Sunday) as date string\n */\nexport function getWeekEndString(baseDate: Date = new Date()): string {\n return formatDateString(getWeekEnd(getWeekStart(baseDate)))\n}\n\n/**\n * Format a week range for display\n * @example \"Dec 2 - 8, 2024\" or \"Nov 25 - Dec 1, 2024\"\n */\nexport function formatWeekRange(weekStart: Date): string {\n const weekEnd = getWeekEnd(weekStart)\n const startMonth = weekStart.toLocaleDateString('en-US', { month: 'short' })\n const endMonth = weekEnd.toLocaleDateString('en-US', { month: 'short' })\n\n if (startMonth === endMonth) {\n return `${startMonth} ${weekStart.getDate()} - ${weekEnd.getDate()}, ${weekStart.getFullYear()}`\n }\n\n return `${startMonth} ${weekStart.getDate()} - ${endMonth} ${weekEnd.getDate()}, ${weekStart.getFullYear()}`\n}\n\n// ============================================================================\n// Display Formatting\n// ============================================================================\n\n/**\n * Format a date string for display with full weekday\n * @example \"Monday, December 15, 2024\"\n */\nexport function formatFullDate(dateStr: string): string {\n const date = parseLocalDate(dateStr)\n return date.toLocaleDateString('en-US', {\n weekday: 'long',\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n })\n}\n\n/**\n * Format date for display in long form\n * @example \"Monday, 9 December\"\n */\nexport function formatDateLong(dateStr: string): string {\n const date = parseLocalDate(dateStr)\n return date.toLocaleDateString('en-GB', {\n weekday: 'long',\n day: 'numeric',\n month: 'long',\n })\n}\n\n/**\n * Format month and year\n * @example \"December 2024\"\n */\nexport function formatMonthYear(date: Date): string {\n return date.toLocaleDateString('en-US', {\n month: 'long',\n year: 'numeric',\n })\n}\n\n/**\n * Format a date/time to HH:MM format\n * Use this for formatting Date objects or ISO strings to time display\n * @example formatTimeHHMM(new Date()) => \"14:30\"\n *\n * Note: For formatting seconds (e.g., timer display), use formatTime from utils\n */\nexport function formatTimeHHMM(date: Date | string): string {\n const d = typeof date === 'string' ? new Date(date) : date\n return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n}\n\n/**\n * Format a date/time to HH:MM:SS format\n */\nexport function formatTimeWithSeconds(date: Date | string): string {\n const d = typeof date === 'string' ? new Date(date) : date\n return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' })\n}\n\n// ============================================================================\n// Contextual Formatting\n// ============================================================================\n\n/**\n * Format a date string for display as a header\n * Returns \"Overdue\", \"Today\", \"Tomorrow\", or formatted date\n */\nexport function formatDateHeader(dateStr: string): string {\n const today = getTodayString()\n\n if (dateStr < today) {\n return 'Overdue'\n }\n\n if (dateStr === today) {\n return 'Today'\n }\n\n const tomorrowStr = getTomorrowString()\n if (dateStr === tomorrowStr) {\n return 'Tomorrow'\n }\n\n const date = parseLocalDate(dateStr)\n return date.toLocaleDateString('en-US', {\n weekday: 'long',\n month: 'short',\n day: 'numeric',\n })\n}\n\n/**\n * Format a due date for display in task items (simple string version)\n * Returns \"Overdue\", \"Today\", \"Tomorrow\", or formatted date\n *\n * Note: For version that returns { text, isOverdue }, use formatDueDate from utils/formatters\n */\nexport function formatDueDateString(dateStr: string | null): string {\n if (!dateStr) return 'No due date'\n\n const today = getTodayString()\n const tomorrowStr = getTomorrowString()\n\n if (dateStr < today) {\n const date = parseLocalDate(dateStr)\n return `Overdue • ${date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}`\n }\n\n if (dateStr === today) {\n return 'Today'\n }\n\n if (dateStr === tomorrowStr) {\n return 'Tomorrow'\n }\n\n const date = parseLocalDate(dateStr)\n const currentYear = new Date().getFullYear()\n const dateYear = date.getFullYear()\n\n return date.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: dateYear !== currentYear ? 'numeric' : undefined,\n })\n}\n\n/**\n * Format a date/time as relative time string (extended version)\n * Accepts both Date objects and ISO strings\n * @example \"Just now\", \"5m ago\", \"2h ago\", \"3d ago\"\n *\n * Note: For simple string input, you can also use formatRelativeTime from utils/formatters\n */\nexport function formatRelativeTimeExtended(dateStr: string | Date): string {\n const date = typeof dateStr === 'string' ? new Date(dateStr) : dateStr\n const now = new Date()\n const diffMs = now.getTime() - date.getTime()\n const diffMins = Math.floor(diffMs / 60000)\n const diffHours = Math.floor(diffMins / 60)\n const diffDays = Math.floor(diffHours / 24)\n\n if (diffMins < 1) return 'Just now'\n if (diffMins < 60) return `${diffMins}m ago`\n if (diffHours < 24) return `${diffHours}h ago`\n if (diffDays < 7) return `${diffDays}d ago`\n return date.toLocaleDateString()\n}\n\n/**\n * Format a due date relative to today with contextual prefix\n * @example \"Due today\", \"Due tomorrow\", \"Due in 3 days\", \"2 days overdue\"\n */\nexport function formatRelativeDueDate(\n dateStr: string,\n options?: {\n duePrefix?: string\n overduePrefix?: string\n }\n): string {\n const { duePrefix = 'Due', overduePrefix = '' } = options || {}\n const date = parseLocalDate(dateStr)\n const now = normalizeToMidnight(new Date())\n\n const diffMs = date.getTime() - now.getTime()\n const diffDays = Math.round(diffMs / (1000 * 60 * 60 * 24))\n\n if (diffDays < 0) {\n const absDays = Math.abs(diffDays)\n return overduePrefix\n ? `${overduePrefix} ${absDays} day${absDays !== 1 ? 's' : ''} overdue`\n : `${absDays} day${absDays !== 1 ? 's' : ''} overdue`\n }\n if (diffDays === 0) return `${duePrefix} today`\n if (diffDays === 1) return `${duePrefix} tomorrow`\n if (diffDays <= 7) return `${duePrefix} in ${diffDays} days`\n\n return date.toLocaleDateString('en-GB', { day: 'numeric', month: 'short' })\n}\n\n/**\n * Format a pay/income date relative to today\n * @example \"Today\", \"Tomorrow\", \"In 3 days\", \"2 days ago\"\n */\nexport function formatRelativePayDate(dateStr: string): string {\n const date = parseLocalDate(dateStr)\n const now = normalizeToMidnight(new Date())\n\n const diffMs = date.getTime() - now.getTime()\n const diffDays = Math.round(diffMs / (1000 * 60 * 60 * 24))\n\n if (diffDays < 0) {\n const absDays = Math.abs(diffDays)\n return `${absDays} day${absDays !== 1 ? 's' : ''} ago`\n }\n if (diffDays === 0) return 'Today'\n if (diffDays === 1) return 'Tomorrow'\n if (diffDays <= 7) return `In ${diffDays} days`\n\n return date.toLocaleDateString('en-GB', { day: 'numeric', month: 'short' })\n}\n\n// ============================================================================\n// Localized Formatting\n// ============================================================================\n\nexport type DateFormat = 'short' | 'medium' | 'long' | 'weekday'\nexport type TimeFormat = 'short' | 'withSeconds'\n\n/**\n * Format a date with various preset formats\n */\nexport function formatDateLocalized(date: Date | string, format: DateFormat = 'medium'): string {\n const d = typeof date === 'string' ? new Date(date) : date\n\n switch (format) {\n case 'short':\n return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })\n case 'medium':\n return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })\n case 'long':\n return d.toLocaleDateString('en-US', {\n weekday: 'long',\n month: 'long',\n day: 'numeric',\n year: 'numeric',\n })\n case 'weekday':\n return d.toLocaleDateString('en-US', { weekday: 'short' })\n default:\n return d.toLocaleDateString()\n }\n}\n\n/**\n * Format a time with various preset formats\n */\nexport function formatTimeLocalized(date: Date | string, format: TimeFormat = 'short'): string {\n const d = typeof date === 'string' ? new Date(date) : date\n\n switch (format) {\n case 'short':\n return d.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: true })\n case 'withSeconds':\n return d.toLocaleTimeString('en-US', {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: true,\n })\n default:\n return d.toLocaleTimeString()\n }\n}\n\n"],"mappings":"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","names":["date"]}
1
+ {"version":3,"sources":["../../src/date/index.ts"],"sourcesContent":["/**\n * Date Utilities\n *\n * Pure functions for date manipulation and formatting.\n * Works in both Node.js and browser/React Native environments.\n *\n * @example\n * import { getTodayString, addDays, formatRelativeTime } from '@mrck-labs/vanaheim-shared/date'\n *\n * const today = getTodayString() // \"2024-12-16\"\n * const nextWeek = addDays(today, 7) // \"2024-12-23\"\n */\n\n// ============================================================================\n// Core Utilities\n// ============================================================================\n\n/**\n * Normalize a date to midnight (00:00:00.000)\n */\nexport function normalizeToMidnight(date: Date): Date {\n const d = new Date(date)\n d.setHours(0, 0, 0, 0)\n return d\n}\n\n/**\n * Get today's date normalized to midnight\n */\nexport function getTodayMidnight(): Date {\n return normalizeToMidnight(new Date())\n}\n\n/**\n * Format a Date object to YYYY-MM-DD string\n * @example formatDateString(new Date()) => \"2024-12-16\"\n */\nexport function formatDateString(date: Date): string {\n return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`\n}\n\n/**\n * Get today's local date string (YYYY-MM-DD)\n */\nexport function getTodayString(): string {\n return formatDateString(new Date())\n}\n\n/**\n * Parse a YYYY-MM-DD string to a local Date object\n * Avoids timezone issues by appending T00:00:00\n */\nexport function parseLocalDate(dateStr: string): Date {\n return new Date(dateStr + 'T00:00:00')\n}\n\n// ============================================================================\n// Date Checks\n// ============================================================================\n\n/**\n * Check if a date string is today\n */\nexport function isToday(dateStr: string | null): boolean {\n if (!dateStr) return false\n return dateStr === getTodayString()\n}\n\n/**\n * Check if a date string is in the past (before today)\n */\nexport function isOverdue(dateStr: string | null): boolean {\n if (!dateStr) return false\n return dateStr < getTodayString()\n}\n\n/**\n * Check if a date is due within a threshold of days\n * @param dateStr - Date in YYYY-MM-DD format\n * @param daysThreshold - Number of days to check (default: 7)\n */\nexport function isDueSoon(dateStr: string | null, daysThreshold: number = 7): boolean {\n if (!dateStr) return false\n if (isOverdue(dateStr)) return false\n\n const today = getTodayMidnight()\n const targetDate = parseLocalDate(dateStr)\n const diffMs = targetDate.getTime() - today.getTime()\n const diffDays = Math.ceil(diffMs / (1000 * 60 * 60 * 24))\n\n return diffDays >= 0 && diffDays <= daysThreshold\n}\n\n// ============================================================================\n// Date Arithmetic\n// ============================================================================\n\n/**\n * Add days to a date string\n * @param dateStr - Date in YYYY-MM-DD format\n * @param days - Number of days to add (can be negative)\n * @returns New date string in YYYY-MM-DD format\n */\nexport function addDays(dateStr: string, days: number): string {\n const date = parseLocalDate(dateStr)\n date.setDate(date.getDate() + days)\n return formatDateString(date)\n}\n\n/**\n * Subtract days from a date string\n */\nexport function subtractDays(dateStr: string, days: number): string {\n return addDays(dateStr, -days)\n}\n\n/**\n * Get yesterday's date string (YYYY-MM-DD)\n */\nexport function getYesterdayString(): string {\n return subtractDays(getTodayString(), 1)\n}\n\n/**\n * Get tomorrow's date string (YYYY-MM-DD)\n */\nexport function getTomorrowString(): string {\n return addDays(getTodayString(), 1)\n}\n\n// ============================================================================\n// ISO String Helpers (for database queries)\n// ============================================================================\n\n/**\n * Get start of day as ISO string\n * @param dateStr - Date in YYYY-MM-DD format\n * @returns ISO string like \"2024-12-15T00:00:00.000Z\"\n */\nexport function getStartOfDayISO(dateStr: string): string {\n const date = parseLocalDate(dateStr)\n return new Date(date.getFullYear(), date.getMonth(), date.getDate()).toISOString()\n}\n\n/**\n * Get end of day as ISO string\n * @param dateStr - Date in YYYY-MM-DD format\n * @returns ISO string like \"2024-12-15T23:59:59.999Z\"\n */\nexport function getEndOfDayISO(dateStr: string): string {\n const date = parseLocalDate(dateStr)\n return new Date(\n date.getFullYear(),\n date.getMonth(),\n date.getDate(),\n 23,\n 59,\n 59,\n 999\n ).toISOString()\n}\n\n// ============================================================================\n// Week Utilities\n// ============================================================================\n\n/**\n * Get the start of the week (Monday) for a given date\n */\nexport function getWeekStart(date: Date): Date {\n const d = new Date(date)\n const day = d.getDay()\n const diff = d.getDate() - day + (day === 0 ? -6 : 1) // Monday\n d.setDate(diff)\n d.setHours(0, 0, 0, 0)\n return d\n}\n\n/**\n * Get the end of the week (Sunday) for a given week start\n */\nexport function getWeekEnd(weekStart: Date): Date {\n const d = new Date(weekStart)\n d.setDate(d.getDate() + 6)\n return d\n}\n\n/**\n * Get the start of the previous week\n */\nexport function getPreviousWeek(weekStart: Date): Date {\n const d = new Date(weekStart)\n d.setDate(d.getDate() - 7)\n return d\n}\n\n/**\n * Get the start of the next week\n */\nexport function getNextWeek(weekStart: Date): Date {\n const d = new Date(weekStart)\n d.setDate(d.getDate() + 7)\n return d\n}\n\n/**\n * Get start of week (Monday) as date string\n */\nexport function getWeekStartString(baseDate: Date = new Date()): string {\n return formatDateString(getWeekStart(baseDate))\n}\n\n/**\n * Get end of week (Sunday) as date string\n */\nexport function getWeekEndString(baseDate: Date = new Date()): string {\n return formatDateString(getWeekEnd(getWeekStart(baseDate)))\n}\n\n/**\n * Format a week range for display\n * @example \"Dec 2 - 8, 2024\" or \"Nov 25 - Dec 1, 2024\"\n */\nexport function formatWeekRange(weekStart: Date): string {\n const weekEnd = getWeekEnd(weekStart)\n const startMonth = weekStart.toLocaleDateString('en-US', { month: 'short' })\n const endMonth = weekEnd.toLocaleDateString('en-US', { month: 'short' })\n\n if (startMonth === endMonth) {\n return `${startMonth} ${weekStart.getDate()} - ${weekEnd.getDate()}, ${weekStart.getFullYear()}`\n }\n\n return `${startMonth} ${weekStart.getDate()} - ${endMonth} ${weekEnd.getDate()}, ${weekStart.getFullYear()}`\n}\n\n// ============================================================================\n// Display Formatting\n// ============================================================================\n\n/**\n * Format a date string for display with full weekday\n * @example \"Monday, December 15, 2024\"\n */\nexport function formatFullDate(dateStr: string): string {\n const date = parseLocalDate(dateStr)\n return date.toLocaleDateString('en-US', {\n weekday: 'long',\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n })\n}\n\n/**\n * Format date for display in long form\n * @example \"Monday, 9 December\"\n */\nexport function formatDateLong(dateStr: string): string {\n const date = parseLocalDate(dateStr)\n return date.toLocaleDateString('en-GB', {\n weekday: 'long',\n day: 'numeric',\n month: 'long',\n })\n}\n\n/**\n * Format month and year\n * @example \"December 2024\"\n */\nexport function formatMonthYear(date: Date): string {\n return date.toLocaleDateString('en-US', {\n month: 'long',\n year: 'numeric',\n })\n}\n\n/**\n * Format a date/time to HH:MM format\n * Use this for formatting Date objects or ISO strings to time display\n * @example formatTimeHHMM(new Date()) => \"14:30\"\n *\n * Note: For formatting seconds (e.g., timer display), use formatTime from utils\n */\nexport function formatTimeHHMM(date: Date | string): string {\n const d = typeof date === 'string' ? new Date(date) : date\n return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n}\n\n/**\n * Format time in short format (12h without seconds)\n * @example formatTimeShort(new Date()) => \"2:30 PM\"\n */\nexport function formatTimeShort(date: Date | string): string {\n const d = typeof date === 'string' ? new Date(date) : date\n return d.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })\n}\n\n/**\n * Format a Date object for display in readable format\n * @example formatDateDisplay(new Date()) => \"Monday, Dec 22\"\n */\nexport function formatDateDisplay(date: Date): string {\n return date.toLocaleDateString('en-US', {\n weekday: 'long',\n month: 'short',\n day: 'numeric',\n })\n}\n\n/**\n * Format a date/time to HH:MM:SS format\n */\nexport function formatTimeWithSeconds(date: Date | string): string {\n const d = typeof date === 'string' ? new Date(date) : date\n return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' })\n}\n\n// ============================================================================\n// Contextual Formatting\n// ============================================================================\n\n/**\n * Format a date string for display as a header\n * Returns \"Overdue\", \"Today\", \"Tomorrow\", or formatted date\n */\nexport function formatDateHeader(dateStr: string): string {\n const today = getTodayString()\n\n if (dateStr < today) {\n return 'Overdue'\n }\n\n if (dateStr === today) {\n return 'Today'\n }\n\n const tomorrowStr = getTomorrowString()\n if (dateStr === tomorrowStr) {\n return 'Tomorrow'\n }\n\n const date = parseLocalDate(dateStr)\n return date.toLocaleDateString('en-US', {\n weekday: 'long',\n month: 'short',\n day: 'numeric',\n })\n}\n\n/**\n * Format a due date for display in task items (simple string version)\n * Returns \"Overdue\", \"Today\", \"Tomorrow\", or formatted date\n *\n * Note: For version that returns { text, isOverdue }, use formatDueDate from utils/formatters\n */\nexport function formatDueDateString(dateStr: string | null): string {\n if (!dateStr) return 'No due date'\n\n const today = getTodayString()\n const tomorrowStr = getTomorrowString()\n\n if (dateStr < today) {\n const date = parseLocalDate(dateStr)\n return `Overdue • ${date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}`\n }\n\n if (dateStr === today) {\n return 'Today'\n }\n\n if (dateStr === tomorrowStr) {\n return 'Tomorrow'\n }\n\n const date = parseLocalDate(dateStr)\n const currentYear = new Date().getFullYear()\n const dateYear = date.getFullYear()\n\n return date.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: dateYear !== currentYear ? 'numeric' : undefined,\n })\n}\n\n/**\n * Format a date/time as relative time string (extended version)\n * Accepts both Date objects and ISO strings\n * @example \"Just now\", \"5m ago\", \"2h ago\", \"3d ago\"\n *\n * Note: For simple string input, you can also use formatRelativeTime from utils/formatters\n */\nexport function formatRelativeTimeExtended(dateStr: string | Date): string {\n const date = typeof dateStr === 'string' ? new Date(dateStr) : dateStr\n const now = new Date()\n const diffMs = now.getTime() - date.getTime()\n const diffMins = Math.floor(diffMs / 60000)\n const diffHours = Math.floor(diffMins / 60)\n const diffDays = Math.floor(diffHours / 24)\n\n if (diffMins < 1) return 'Just now'\n if (diffMins < 60) return `${diffMins}m ago`\n if (diffHours < 24) return `${diffHours}h ago`\n if (diffDays < 7) return `${diffDays}d ago`\n return date.toLocaleDateString()\n}\n\n/**\n * Format a due date relative to today with contextual prefix\n * @example \"Due today\", \"Due tomorrow\", \"Due in 3 days\", \"2 days overdue\"\n */\nexport function formatRelativeDueDate(\n dateStr: string,\n options?: {\n duePrefix?: string\n overduePrefix?: string\n }\n): string {\n const { duePrefix = 'Due', overduePrefix = '' } = options || {}\n const date = parseLocalDate(dateStr)\n const now = normalizeToMidnight(new Date())\n\n const diffMs = date.getTime() - now.getTime()\n const diffDays = Math.round(diffMs / (1000 * 60 * 60 * 24))\n\n if (diffDays < 0) {\n const absDays = Math.abs(diffDays)\n return overduePrefix\n ? `${overduePrefix} ${absDays} day${absDays !== 1 ? 's' : ''} overdue`\n : `${absDays} day${absDays !== 1 ? 's' : ''} overdue`\n }\n if (diffDays === 0) return `${duePrefix} today`\n if (diffDays === 1) return `${duePrefix} tomorrow`\n if (diffDays <= 7) return `${duePrefix} in ${diffDays} days`\n\n return date.toLocaleDateString('en-GB', { day: 'numeric', month: 'short' })\n}\n\n/**\n * Format a pay/income date relative to today\n * @example \"Today\", \"Tomorrow\", \"In 3 days\", \"2 days ago\"\n */\nexport function formatRelativePayDate(dateStr: string): string {\n const date = parseLocalDate(dateStr)\n const now = normalizeToMidnight(new Date())\n\n const diffMs = date.getTime() - now.getTime()\n const diffDays = Math.round(diffMs / (1000 * 60 * 60 * 24))\n\n if (diffDays < 0) {\n const absDays = Math.abs(diffDays)\n return `${absDays} day${absDays !== 1 ? 's' : ''} ago`\n }\n if (diffDays === 0) return 'Today'\n if (diffDays === 1) return 'Tomorrow'\n if (diffDays <= 7) return `In ${diffDays} days`\n\n return date.toLocaleDateString('en-GB', { day: 'numeric', month: 'short' })\n}\n\n// ============================================================================\n// Localized Formatting\n// ============================================================================\n\nexport type DateFormat = 'short' | 'medium' | 'long' | 'weekday'\nexport type TimeFormat = 'short' | 'withSeconds'\n\n/**\n * Format a date with various preset formats\n */\nexport function formatDateLocalized(date: Date | string, format: DateFormat = 'medium'): string {\n const d = typeof date === 'string' ? new Date(date) : date\n\n switch (format) {\n case 'short':\n return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })\n case 'medium':\n return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })\n case 'long':\n return d.toLocaleDateString('en-US', {\n weekday: 'long',\n month: 'long',\n day: 'numeric',\n year: 'numeric',\n })\n case 'weekday':\n return d.toLocaleDateString('en-US', { weekday: 'short' })\n default:\n return d.toLocaleDateString()\n }\n}\n\n/**\n * Format a time with various preset formats\n */\nexport function formatTimeLocalized(date: Date | string, format: TimeFormat = 'short'): string {\n const d = typeof date === 'string' ? new Date(date) : date\n\n switch (format) {\n case 'short':\n return d.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: true })\n case 'withSeconds':\n return d.toLocaleTimeString('en-US', {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: true,\n })\n default:\n return d.toLocaleTimeString()\n }\n}\n\n"],"mappings":"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","names":["date"]}
package/dist/index.d.mts CHANGED
@@ -1,8 +1,8 @@
1
- export { s as BankConnection, B as BankConnectionStatus, t as BankTransaction, k as ChatConversation, m as ChatMessage, C as ChatMessageRole, o as EFLink, u as ExchangeRate, a as Expense, E as ExpenseCategory, F as FocusCategory, h as FocusSession, j as FocusSessionFilters, g as FocusSessionStatus, d as Income, I as IncomeCategory, q as LieuDay, L as LieuDayType, l as NewChatConversation, n as NewChatMessage, p as NewEFLink, b as NewExpense, N as NewExpenseCategory, f as NewFocusCategory, i as NewFocusSession, e as NewIncome, c as NewIncomeCategory, r as NewLieuDay, S as Setting, T as TransactionType } from './database-BKc0Oj26.mjs';
1
+ export { s as BankConnection, B as BankConnectionStatus, t as BankTransaction, k as ChatConversation, m as ChatMessage, C as ChatMessageRole, O as DailyPlan, M as DailyPriority, o as EFLink, K as ExchangeRate, a as Expense, E as ExpenseCategory, Y as FocusArea, F as FocusCategory, h as FocusSession, j as FocusSessionFilters, g as FocusSessionStatus, H as HealthCategory, z as HealthCompletion, G as HealthCompletionFilters, w as HealthFrequencyConfig, v as HealthFrequencyType, x as HealthHabit, D as HealthHabitFilters, J as HealthStats, d as Income, I as IncomeCategory, q as LieuDay, L as LieuDayType, U as MealPlan, R as MealType, l as NewChatConversation, n as NewChatMessage, P as NewDailyPlan, p as NewEFLink, b as NewExpense, N as NewExpenseCategory, f as NewFocusCategory, i as NewFocusSession, u as NewHealthCategory, A as NewHealthCompletion, y as NewHealthHabit, e as NewIncome, c as NewIncomeCategory, r as NewLieuDay, V as NewMealPlan, a4 as NewNote, a2 as NewNoteFolder, X as NewPrepSession, _ as NewWeeklyPlan, a3 as Note, a5 as NoteFilters, a1 as NoteFolder, a0 as NoteType, Q as ParsedDailyPlan, $ as ParsedWeeklyPlan, W as PrepSession, S as Setting, T as TransactionType, Z as WeeklyPlan } from './database-koVAareN.mjs';
2
2
  export { ApiKeyInfo, CloudAgent, CloudAgentConversation, CloudAgentMessage, CloudAgentMessageType, CloudAgentModel, CloudAgentPrompt, CloudAgentSource, CloudAgentStatus, CloudAgentTarget, IssueQueryOptions, LINEAR_PRIORITY_LABELS, LaunchAgentRequest, LinearIssue, LinearPriority, LinearProject, LinearState, LinearStateType, LinearUser, ListAgentsResponse, ModelsResponse, PaginatedIssues } from './types/index.mjs';
3
- export { API_URLS, CLOUD_AGENT_STATUSES, CLOUD_AGENT_STATUS_COLORS, CLOUD_AGENT_STATUS_EMOJI, CURRENCIES, CURRENCY_NAMES, CURRENCY_SYMBOLS, Currency, DEFAULT_FOCUS_DURATIONS, FOCUS_STATUS, FREQUENCIES, FREQUENCY_LABELS, FREQUENCY_MULTIPLIERS, FocusDuration, FocusStatus, Frequency, LINEAR_PRIORITIES, LINEAR_PRIORITY_COLORS, LinearPriorityValue, SETTING_KEYS, SettingKey } from './constants/index.mjs';
4
- export { calculateFocusStats, calculateLieuBalance, calculateMonthlyExpenses, calculateMonthlyIncome, calculateMonthlySavings, calculateSavingsRate, formatCurrency, formatDate, formatDueDate, formatDuration, formatRelativeTime, formatTime, formatTotalTime, generateId, generateRandomColor, generateShortId, getRepoName, isNonEmptyString, isPositiveNumber, isValidCurrency, isValidEmail, isValidFrequency, isValidISODate, isValidUrl, toMonthlyAmount, toYearlyAmount, truncate } from './utils/index.mjs';
3
+ export { API_URLS, CLOUD_AGENT_STATUSES, CLOUD_AGENT_STATUS_COLORS, CLOUD_AGENT_STATUS_EMOJI, CURRENCIES, CURRENCY_NAMES, CURRENCY_SYMBOLS, Currency, DAY_OPTIONS, DEFAULT_FOCUS_DURATIONS, FOCUS_STATUS, FREQUENCIES, FREQUENCY_LABELS, FREQUENCY_MULTIPLIERS, FREQUENCY_OPTIONS, FocusDuration, FocusStatus, Frequency, HEALTH_FREQUENCY_LABELS, HEALTH_FREQUENCY_TYPES, LINEAR_PRIORITIES, LINEAR_PRIORITY_COLORS, LinearPriorityValue, PRESET_COLORS, PRESET_ICONS, SETTING_KEYS, SettingKey } from './constants/index.mjs';
4
+ export { WeeklyProgressItem, calculateFocusStats, calculateLieuBalance, calculateMonthlyExpenses, calculateMonthlyIncome, calculateMonthlySavings, calculateSavingsRate, calculateWeeklyProgress, formatCurrency, formatDate, formatDueDate, formatDuration, formatRelativeTime, formatTime, formatTotalTime, generateId, generateRandomColor, generateShortId, getFrequencyDescription, getRepoName, isNonEmptyString, isPositiveNumber, isValidCurrency, isValidEmail, isValidFrequency, isValidISODate, isValidUrl, parseFrequencyConfig, shouldDoOnDate, shouldDoToday, stringifyFrequencyConfig, toMonthlyAmount, toYearlyAmount, truncate } from './utils/index.mjs';
5
5
  export { QueryKeys, queryKeys } from './query/index.mjs';
6
6
  export { ActiveSession, TimerStatus, activeSessionAtom, elapsedSecondsAtom, formattedElapsedAtom, formattedRemainingAtom, progressAtom, progressPercentAtom, remainingSecondsAtom, targetSecondsAtom, timerStatusAtom } from './atoms/index.mjs';
7
- export { DateFormat, TimeFormat, addDays, formatDateHeader, formatDateLocalized, formatDateLong, formatDateString, formatDueDateString, formatFullDate, formatMonthYear, formatRelativeDueDate, formatRelativePayDate, formatRelativeTimeExtended, formatTimeHHMM, formatTimeLocalized, formatTimeWithSeconds, formatWeekRange, getEndOfDayISO, getNextWeek, getPreviousWeek, getStartOfDayISO, getTodayMidnight, getTodayString, getTomorrowString, getWeekEnd, getWeekEndString, getWeekStart, getWeekStartString, getYesterdayString, isDueSoon, isOverdue, isToday, normalizeToMidnight, parseLocalDate, subtractDays } from './date/index.mjs';
7
+ export { DateFormat, TimeFormat, addDays, formatDateDisplay, formatDateHeader, formatDateLocalized, formatDateLong, formatDateString, formatDueDateString, formatFullDate, formatMonthYear, formatRelativeDueDate, formatRelativePayDate, formatRelativeTimeExtended, formatTimeHHMM, formatTimeLocalized, formatTimeShort, formatTimeWithSeconds, formatWeekRange, getEndOfDayISO, getNextWeek, getPreviousWeek, getStartOfDayISO, getTodayMidnight, getTodayString, getTomorrowString, getWeekEnd, getWeekEndString, getWeekStart, getWeekStartString, getYesterdayString, isDueSoon, isOverdue, isToday, normalizeToMidnight, parseLocalDate, subtractDays } from './date/index.mjs';
8
8
  import 'jotai';
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- export { s as BankConnection, B as BankConnectionStatus, t as BankTransaction, k as ChatConversation, m as ChatMessage, C as ChatMessageRole, o as EFLink, u as ExchangeRate, a as Expense, E as ExpenseCategory, F as FocusCategory, h as FocusSession, j as FocusSessionFilters, g as FocusSessionStatus, d as Income, I as IncomeCategory, q as LieuDay, L as LieuDayType, l as NewChatConversation, n as NewChatMessage, p as NewEFLink, b as NewExpense, N as NewExpenseCategory, f as NewFocusCategory, i as NewFocusSession, e as NewIncome, c as NewIncomeCategory, r as NewLieuDay, S as Setting, T as TransactionType } from './database-BKc0Oj26.js';
1
+ export { s as BankConnection, B as BankConnectionStatus, t as BankTransaction, k as ChatConversation, m as ChatMessage, C as ChatMessageRole, O as DailyPlan, M as DailyPriority, o as EFLink, K as ExchangeRate, a as Expense, E as ExpenseCategory, Y as FocusArea, F as FocusCategory, h as FocusSession, j as FocusSessionFilters, g as FocusSessionStatus, H as HealthCategory, z as HealthCompletion, G as HealthCompletionFilters, w as HealthFrequencyConfig, v as HealthFrequencyType, x as HealthHabit, D as HealthHabitFilters, J as HealthStats, d as Income, I as IncomeCategory, q as LieuDay, L as LieuDayType, U as MealPlan, R as MealType, l as NewChatConversation, n as NewChatMessage, P as NewDailyPlan, p as NewEFLink, b as NewExpense, N as NewExpenseCategory, f as NewFocusCategory, i as NewFocusSession, u as NewHealthCategory, A as NewHealthCompletion, y as NewHealthHabit, e as NewIncome, c as NewIncomeCategory, r as NewLieuDay, V as NewMealPlan, a4 as NewNote, a2 as NewNoteFolder, X as NewPrepSession, _ as NewWeeklyPlan, a3 as Note, a5 as NoteFilters, a1 as NoteFolder, a0 as NoteType, Q as ParsedDailyPlan, $ as ParsedWeeklyPlan, W as PrepSession, S as Setting, T as TransactionType, Z as WeeklyPlan } from './database-koVAareN.js';
2
2
  export { ApiKeyInfo, CloudAgent, CloudAgentConversation, CloudAgentMessage, CloudAgentMessageType, CloudAgentModel, CloudAgentPrompt, CloudAgentSource, CloudAgentStatus, CloudAgentTarget, IssueQueryOptions, LINEAR_PRIORITY_LABELS, LaunchAgentRequest, LinearIssue, LinearPriority, LinearProject, LinearState, LinearStateType, LinearUser, ListAgentsResponse, ModelsResponse, PaginatedIssues } from './types/index.js';
3
- export { API_URLS, CLOUD_AGENT_STATUSES, CLOUD_AGENT_STATUS_COLORS, CLOUD_AGENT_STATUS_EMOJI, CURRENCIES, CURRENCY_NAMES, CURRENCY_SYMBOLS, Currency, DEFAULT_FOCUS_DURATIONS, FOCUS_STATUS, FREQUENCIES, FREQUENCY_LABELS, FREQUENCY_MULTIPLIERS, FocusDuration, FocusStatus, Frequency, LINEAR_PRIORITIES, LINEAR_PRIORITY_COLORS, LinearPriorityValue, SETTING_KEYS, SettingKey } from './constants/index.js';
4
- export { calculateFocusStats, calculateLieuBalance, calculateMonthlyExpenses, calculateMonthlyIncome, calculateMonthlySavings, calculateSavingsRate, formatCurrency, formatDate, formatDueDate, formatDuration, formatRelativeTime, formatTime, formatTotalTime, generateId, generateRandomColor, generateShortId, getRepoName, isNonEmptyString, isPositiveNumber, isValidCurrency, isValidEmail, isValidFrequency, isValidISODate, isValidUrl, toMonthlyAmount, toYearlyAmount, truncate } from './utils/index.js';
3
+ export { API_URLS, CLOUD_AGENT_STATUSES, CLOUD_AGENT_STATUS_COLORS, CLOUD_AGENT_STATUS_EMOJI, CURRENCIES, CURRENCY_NAMES, CURRENCY_SYMBOLS, Currency, DAY_OPTIONS, DEFAULT_FOCUS_DURATIONS, FOCUS_STATUS, FREQUENCIES, FREQUENCY_LABELS, FREQUENCY_MULTIPLIERS, FREQUENCY_OPTIONS, FocusDuration, FocusStatus, Frequency, HEALTH_FREQUENCY_LABELS, HEALTH_FREQUENCY_TYPES, LINEAR_PRIORITIES, LINEAR_PRIORITY_COLORS, LinearPriorityValue, PRESET_COLORS, PRESET_ICONS, SETTING_KEYS, SettingKey } from './constants/index.js';
4
+ export { WeeklyProgressItem, calculateFocusStats, calculateLieuBalance, calculateMonthlyExpenses, calculateMonthlyIncome, calculateMonthlySavings, calculateSavingsRate, calculateWeeklyProgress, formatCurrency, formatDate, formatDueDate, formatDuration, formatRelativeTime, formatTime, formatTotalTime, generateId, generateRandomColor, generateShortId, getFrequencyDescription, getRepoName, isNonEmptyString, isPositiveNumber, isValidCurrency, isValidEmail, isValidFrequency, isValidISODate, isValidUrl, parseFrequencyConfig, shouldDoOnDate, shouldDoToday, stringifyFrequencyConfig, toMonthlyAmount, toYearlyAmount, truncate } from './utils/index.js';
5
5
  export { QueryKeys, queryKeys } from './query/index.js';
6
6
  export { ActiveSession, TimerStatus, activeSessionAtom, elapsedSecondsAtom, formattedElapsedAtom, formattedRemainingAtom, progressAtom, progressPercentAtom, remainingSecondsAtom, targetSecondsAtom, timerStatusAtom } from './atoms/index.js';
7
- export { DateFormat, TimeFormat, addDays, formatDateHeader, formatDateLocalized, formatDateLong, formatDateString, formatDueDateString, formatFullDate, formatMonthYear, formatRelativeDueDate, formatRelativePayDate, formatRelativeTimeExtended, formatTimeHHMM, formatTimeLocalized, formatTimeWithSeconds, formatWeekRange, getEndOfDayISO, getNextWeek, getPreviousWeek, getStartOfDayISO, getTodayMidnight, getTodayString, getTomorrowString, getWeekEnd, getWeekEndString, getWeekStart, getWeekStartString, getYesterdayString, isDueSoon, isOverdue, isToday, normalizeToMidnight, parseLocalDate, subtractDays } from './date/index.js';
7
+ export { DateFormat, TimeFormat, addDays, formatDateDisplay, formatDateHeader, formatDateLocalized, formatDateLong, formatDateString, formatDueDateString, formatFullDate, formatMonthYear, formatRelativeDueDate, formatRelativePayDate, formatRelativeTimeExtended, formatTimeHHMM, formatTimeLocalized, formatTimeShort, formatTimeWithSeconds, formatWeekRange, getEndOfDayISO, getNextWeek, getPreviousWeek, getStartOfDayISO, getTodayMidnight, getTodayString, getTomorrowString, getWeekEnd, getWeekEndString, getWeekStart, getWeekStartString, getYesterdayString, isDueSoon, isOverdue, isToday, normalizeToMidnight, parseLocalDate, subtractDays } from './date/index.js';
8
8
  import 'jotai';
package/dist/index.js CHANGED
@@ -27,14 +27,20 @@ __export(src_exports, {
27
27
  CURRENCIES: () => CURRENCIES,
28
28
  CURRENCY_NAMES: () => CURRENCY_NAMES,
29
29
  CURRENCY_SYMBOLS: () => CURRENCY_SYMBOLS,
30
+ DAY_OPTIONS: () => DAY_OPTIONS,
30
31
  DEFAULT_FOCUS_DURATIONS: () => DEFAULT_FOCUS_DURATIONS,
31
32
  FOCUS_STATUS: () => FOCUS_STATUS,
32
33
  FREQUENCIES: () => FREQUENCIES,
33
34
  FREQUENCY_LABELS: () => FREQUENCY_LABELS,
34
35
  FREQUENCY_MULTIPLIERS: () => FREQUENCY_MULTIPLIERS,
36
+ FREQUENCY_OPTIONS: () => FREQUENCY_OPTIONS,
37
+ HEALTH_FREQUENCY_LABELS: () => HEALTH_FREQUENCY_LABELS,
38
+ HEALTH_FREQUENCY_TYPES: () => HEALTH_FREQUENCY_TYPES,
35
39
  LINEAR_PRIORITIES: () => LINEAR_PRIORITIES,
36
40
  LINEAR_PRIORITY_COLORS: () => LINEAR_PRIORITY_COLORS,
37
41
  LINEAR_PRIORITY_LABELS: () => LINEAR_PRIORITY_LABELS,
42
+ PRESET_COLORS: () => PRESET_COLORS,
43
+ PRESET_ICONS: () => PRESET_ICONS,
38
44
  SETTING_KEYS: () => SETTING_KEYS,
39
45
  activeSessionAtom: () => activeSessionAtom,
40
46
  addDays: () => addDays,
@@ -44,9 +50,11 @@ __export(src_exports, {
44
50
  calculateMonthlyIncome: () => calculateMonthlyIncome,
45
51
  calculateMonthlySavings: () => calculateMonthlySavings,
46
52
  calculateSavingsRate: () => calculateSavingsRate,
53
+ calculateWeeklyProgress: () => calculateWeeklyProgress,
47
54
  elapsedSecondsAtom: () => elapsedSecondsAtom,
48
55
  formatCurrency: () => formatCurrency,
49
56
  formatDate: () => formatDate,
57
+ formatDateDisplay: () => formatDateDisplay,
50
58
  formatDateHeader: () => formatDateHeader,
51
59
  formatDateLocalized: () => formatDateLocalized,
52
60
  formatDateLong: () => formatDateLong,
@@ -63,6 +71,7 @@ __export(src_exports, {
63
71
  formatTime: () => formatTime,
64
72
  formatTimeHHMM: () => formatTimeHHMM,
65
73
  formatTimeLocalized: () => formatTimeLocalized,
74
+ formatTimeShort: () => formatTimeShort,
66
75
  formatTimeWithSeconds: () => formatTimeWithSeconds,
67
76
  formatTotalTime: () => formatTotalTime,
68
77
  formatWeekRange: () => formatWeekRange,
@@ -72,6 +81,7 @@ __export(src_exports, {
72
81
  generateRandomColor: () => generateRandomColor,
73
82
  generateShortId: () => generateShortId,
74
83
  getEndOfDayISO: () => getEndOfDayISO,
84
+ getFrequencyDescription: () => getFrequencyDescription,
75
85
  getNextWeek: () => getNextWeek,
76
86
  getPreviousWeek: () => getPreviousWeek,
77
87
  getRepoName: () => getRepoName,
@@ -95,11 +105,15 @@ __export(src_exports, {
95
105
  isValidISODate: () => isValidISODate,
96
106
  isValidUrl: () => isValidUrl,
97
107
  normalizeToMidnight: () => normalizeToMidnight,
108
+ parseFrequencyConfig: () => parseFrequencyConfig,
98
109
  parseLocalDate: () => parseLocalDate,
99
110
  progressAtom: () => progressAtom,
100
111
  progressPercentAtom: () => progressPercentAtom,
101
112
  queryKeys: () => queryKeys,
102
113
  remainingSecondsAtom: () => remainingSecondsAtom,
114
+ shouldDoOnDate: () => shouldDoOnDate,
115
+ shouldDoToday: () => shouldDoToday,
116
+ stringifyFrequencyConfig: () => stringifyFrequencyConfig,
103
117
  subtractDays: () => subtractDays,
104
118
  targetSecondsAtom: () => targetSecondsAtom,
105
119
  timerStatusAtom: () => timerStatusAtom,
@@ -153,8 +167,98 @@ var FREQUENCY_MULTIPLIERS = {
153
167
  weekly: 52,
154
168
  "one-time": 1
155
169
  };
170
+ var FREQUENCY_OPTIONS = [
171
+ { value: "monthly", label: "Monthly" },
172
+ { value: "yearly", label: "Yearly" },
173
+ { value: "6-monthly", label: "Every 6 Months" },
174
+ { value: "weekly", label: "Weekly" },
175
+ { value: "one-time", label: "One Time" }
176
+ ];
156
177
  var DEFAULT_FOCUS_DURATIONS = [15, 25, 30, 45, 60, 90];
157
178
  var FOCUS_STATUS = ["active", "completed", "abandoned"];
179
+ var HEALTH_FREQUENCY_TYPES = [
180
+ "daily",
181
+ "specific_days",
182
+ "times_per_week",
183
+ "times_per_month"
184
+ ];
185
+ var HEALTH_FREQUENCY_LABELS = {
186
+ daily: "Daily",
187
+ specific_days: "Specific Days",
188
+ times_per_week: "Times per Week",
189
+ times_per_month: "Times per Month"
190
+ };
191
+ var DAY_OPTIONS = [
192
+ { value: 0, label: "Sun" },
193
+ { value: 1, label: "Mon" },
194
+ { value: 2, label: "Tue" },
195
+ { value: 3, label: "Wed" },
196
+ { value: 4, label: "Thu" },
197
+ { value: 5, label: "Fri" },
198
+ { value: 6, label: "Sat" }
199
+ ];
200
+ var PRESET_COLORS = [
201
+ "#10B981",
202
+ // Emerald
203
+ "#3B82F6",
204
+ // Blue
205
+ "#F59E0B",
206
+ // Amber
207
+ "#EF4444",
208
+ // Red
209
+ "#8B5CF6",
210
+ // Purple
211
+ "#EC4899",
212
+ // Pink
213
+ "#14B8A6",
214
+ // Teal
215
+ "#F97316",
216
+ // Orange
217
+ "#6366F1",
218
+ // Indigo
219
+ "#84CC16"
220
+ // Lime
221
+ ];
222
+ var PRESET_ICONS = [
223
+ "\u{1F4DD}",
224
+ // Writing/Notes
225
+ "\u{1F4BB}",
226
+ // Coding/Tech
227
+ "\u{1F3A8}",
228
+ // Design/Art
229
+ "\u{1F4CA}",
230
+ // Analytics/Data
231
+ "\u{1F527}",
232
+ // Tools/Settings
233
+ "\u{1F4DA}",
234
+ // Learning/Docs
235
+ "\u{1F4A1}",
236
+ // Ideas/Lightbulb
237
+ "\u{1F680}",
238
+ // Launch/Start
239
+ "\u26A1",
240
+ // Fast/Energy
241
+ "\u{1F3AF}",
242
+ // Target/Goal
243
+ "\u{1F48A}",
244
+ // Health/Medicine
245
+ "\u{1F957}",
246
+ // Food/Diet
247
+ "\u{1F4A7}",
248
+ // Water/Hydration
249
+ "\u{1F3C3}",
250
+ // Exercise/Running
251
+ "\u{1F634}",
252
+ // Sleep/Rest
253
+ "\u{1F9D8}",
254
+ // Meditation/Mindfulness
255
+ "\u{1F4AA}",
256
+ // Strength/Fitness
257
+ "\u{1F34E}",
258
+ // Health/Food
259
+ "\u{1F517}"
260
+ // Links/Connections
261
+ ];
158
262
  var LINEAR_PRIORITIES = [0, 1, 2, 3, 4];
159
263
  var LINEAR_PRIORITY_COLORS = {
160
264
  0: "#6b7280",
@@ -420,6 +524,69 @@ function calculateFocusStats(sessions) {
420
524
  };
421
525
  }
422
526
 
527
+ // src/utils/health.ts
528
+ function parseFrequencyConfig(config) {
529
+ if (!config) return null;
530
+ try {
531
+ return JSON.parse(config);
532
+ } catch {
533
+ return null;
534
+ }
535
+ }
536
+ function stringifyFrequencyConfig(config) {
537
+ if (!config) return null;
538
+ return JSON.stringify(config);
539
+ }
540
+ function getFrequencyDescription(habit) {
541
+ const config = parseFrequencyConfig(habit.frequencyConfig);
542
+ switch (habit.frequencyType) {
543
+ case "daily":
544
+ return "Every day";
545
+ case "specific_days": {
546
+ if (!config?.days) return "Specific days";
547
+ const dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
548
+ return config.days.map((d) => dayNames[d]).join(", ");
549
+ }
550
+ case "times_per_week":
551
+ return `${config?.target || 1}x per week`;
552
+ case "times_per_month":
553
+ return `${config?.target || 1}x per month`;
554
+ default:
555
+ return "Unknown";
556
+ }
557
+ }
558
+ function shouldDoOnDate(habit, date) {
559
+ const dayOfWeek = date.getDay();
560
+ switch (habit.frequencyType) {
561
+ case "daily":
562
+ return true;
563
+ case "specific_days": {
564
+ const config = parseFrequencyConfig(habit.frequencyConfig);
565
+ return config?.days?.includes(dayOfWeek) ?? false;
566
+ }
567
+ case "times_per_week":
568
+ case "times_per_month":
569
+ return true;
570
+ default:
571
+ return true;
572
+ }
573
+ }
574
+ function shouldDoToday(habit) {
575
+ return shouldDoOnDate(habit, /* @__PURE__ */ new Date());
576
+ }
577
+ function calculateWeeklyProgress(habit, weekCompletionCount) {
578
+ const config = parseFrequencyConfig(habit.frequencyConfig);
579
+ const target = config?.target ?? 1;
580
+ const completed = weekCompletionCount;
581
+ return {
582
+ habit,
583
+ target,
584
+ completed,
585
+ remaining: Math.max(0, target - completed),
586
+ isComplete: completed >= target
587
+ };
588
+ }
589
+
423
590
  // src/query/index.ts
424
591
  var queryKeys = {
425
592
  // -------------------------------------------------------------------------
@@ -646,6 +813,94 @@ var queryKeys = {
646
813
  all: ["linear"],
647
814
  issues: (filters) => [...queryKeys.linear.all, "issues", filters],
648
815
  projects: () => [...queryKeys.linear.all, "projects"]
816
+ },
817
+ // -------------------------------------------------------------------------
818
+ // Nutrition Module
819
+ // -------------------------------------------------------------------------
820
+ ingredients: {
821
+ all: ["ingredients"],
822
+ lists: () => [...queryKeys.ingredients.all, "list"],
823
+ list: (filters) => [...queryKeys.ingredients.lists(), filters],
824
+ detail: (id) => [...queryKeys.ingredients.all, "detail", id]
825
+ },
826
+ recipes: {
827
+ all: ["recipes"],
828
+ lists: () => [...queryKeys.recipes.all, "list"],
829
+ list: (filters) => [...queryKeys.recipes.lists(), filters],
830
+ detail: (id) => [...queryKeys.recipes.all, "detail", id]
831
+ },
832
+ foodLogs: {
833
+ all: ["foodLogs"],
834
+ lists: () => [...queryKeys.foodLogs.all, "list"],
835
+ list: (filters) => [...queryKeys.foodLogs.lists(), filters],
836
+ forDate: (date) => [...queryKeys.foodLogs.all, "date", date]
837
+ },
838
+ nutritionGoals: {
839
+ all: ["nutritionGoals"],
840
+ active: () => [...queryKeys.nutritionGoals.all, "active"]
841
+ },
842
+ nutritionStats: {
843
+ all: ["nutritionStats"],
844
+ forDate: (date) => [...queryKeys.nutritionStats.all, date]
845
+ },
846
+ // -------------------------------------------------------------------------
847
+ // Planning Module - Daily Plans
848
+ // -------------------------------------------------------------------------
849
+ dailyPlans: {
850
+ all: ["dailyPlans"],
851
+ forDate: (date) => [...queryKeys.dailyPlans.all, date],
852
+ forRange: (startDate, endDate) => [...queryKeys.dailyPlans.all, "range", startDate, endDate]
853
+ },
854
+ // -------------------------------------------------------------------------
855
+ // Planning Module - Meal Plans
856
+ // -------------------------------------------------------------------------
857
+ mealPlans: {
858
+ all: ["mealPlans"],
859
+ lists: () => [...queryKeys.mealPlans.all, "list"],
860
+ forDate: (date) => [...queryKeys.mealPlans.all, "date", date],
861
+ forRange: (startDate, endDate) => [...queryKeys.mealPlans.all, "range", startDate, endDate],
862
+ detail: (id) => [...queryKeys.mealPlans.all, "detail", id]
863
+ },
864
+ // -------------------------------------------------------------------------
865
+ // Planning Module - Prep Sessions
866
+ // -------------------------------------------------------------------------
867
+ prepSessions: {
868
+ all: ["prepSessions"],
869
+ lists: () => [...queryKeys.prepSessions.all, "list"],
870
+ forDate: (date) => [...queryKeys.prepSessions.all, "date", date],
871
+ forRange: (startDate, endDate) => [...queryKeys.prepSessions.all, "range", startDate, endDate],
872
+ detail: (id) => [...queryKeys.prepSessions.all, "detail", id]
873
+ },
874
+ // -------------------------------------------------------------------------
875
+ // Planning Module - Grocery List
876
+ // -------------------------------------------------------------------------
877
+ groceryList: {
878
+ all: ["groceryList"],
879
+ forWeek: (weekStart, weekEnd) => [...queryKeys.groceryList.all, weekStart, weekEnd]
880
+ },
881
+ // -------------------------------------------------------------------------
882
+ // Planning Module - Weekly Plans
883
+ // -------------------------------------------------------------------------
884
+ weeklyPlans: {
885
+ all: ["weeklyPlans"],
886
+ forWeek: (weekStart) => [...queryKeys.weeklyPlans.all, weekStart],
887
+ forRange: (startWeek, endWeek) => [...queryKeys.weeklyPlans.all, "range", startWeek, endWeek]
888
+ },
889
+ // -------------------------------------------------------------------------
890
+ // Planning Module - Notes
891
+ // -------------------------------------------------------------------------
892
+ noteFolders: {
893
+ all: ["noteFolders"],
894
+ list: () => [...queryKeys.noteFolders.all, "list"],
895
+ detail: (id) => [...queryKeys.noteFolders.all, "detail", id]
896
+ },
897
+ notes: {
898
+ all: ["notes"],
899
+ lists: () => [...queryKeys.notes.all, "list"],
900
+ list: (filters) => [...queryKeys.notes.lists(), filters],
901
+ detail: (id) => [...queryKeys.notes.all, "detail", id],
902
+ pinned: () => [...queryKeys.notes.all, "pinned"],
903
+ recent: () => [...queryKeys.notes.all, "recent"]
649
904
  }
650
905
  };
651
906
 
@@ -806,6 +1061,17 @@ function formatTimeHHMM(date) {
806
1061
  const d = typeof date === "string" ? new Date(date) : date;
807
1062
  return d.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
808
1063
  }
1064
+ function formatTimeShort(date) {
1065
+ const d = typeof date === "string" ? new Date(date) : date;
1066
+ return d.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" });
1067
+ }
1068
+ function formatDateDisplay(date) {
1069
+ return date.toLocaleDateString("en-US", {
1070
+ weekday: "long",
1071
+ month: "short",
1072
+ day: "numeric"
1073
+ });
1074
+ }
809
1075
  function formatTimeWithSeconds(date) {
810
1076
  const d = typeof date === "string" ? new Date(date) : date;
811
1077
  return d.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" });
@@ -939,14 +1205,20 @@ function formatTimeLocalized(date, format = "short") {
939
1205
  CURRENCIES,
940
1206
  CURRENCY_NAMES,
941
1207
  CURRENCY_SYMBOLS,
1208
+ DAY_OPTIONS,
942
1209
  DEFAULT_FOCUS_DURATIONS,
943
1210
  FOCUS_STATUS,
944
1211
  FREQUENCIES,
945
1212
  FREQUENCY_LABELS,
946
1213
  FREQUENCY_MULTIPLIERS,
1214
+ FREQUENCY_OPTIONS,
1215
+ HEALTH_FREQUENCY_LABELS,
1216
+ HEALTH_FREQUENCY_TYPES,
947
1217
  LINEAR_PRIORITIES,
948
1218
  LINEAR_PRIORITY_COLORS,
949
1219
  LINEAR_PRIORITY_LABELS,
1220
+ PRESET_COLORS,
1221
+ PRESET_ICONS,
950
1222
  SETTING_KEYS,
951
1223
  activeSessionAtom,
952
1224
  addDays,
@@ -956,9 +1228,11 @@ function formatTimeLocalized(date, format = "short") {
956
1228
  calculateMonthlyIncome,
957
1229
  calculateMonthlySavings,
958
1230
  calculateSavingsRate,
1231
+ calculateWeeklyProgress,
959
1232
  elapsedSecondsAtom,
960
1233
  formatCurrency,
961
1234
  formatDate,
1235
+ formatDateDisplay,
962
1236
  formatDateHeader,
963
1237
  formatDateLocalized,
964
1238
  formatDateLong,
@@ -975,6 +1249,7 @@ function formatTimeLocalized(date, format = "short") {
975
1249
  formatTime,
976
1250
  formatTimeHHMM,
977
1251
  formatTimeLocalized,
1252
+ formatTimeShort,
978
1253
  formatTimeWithSeconds,
979
1254
  formatTotalTime,
980
1255
  formatWeekRange,
@@ -984,6 +1259,7 @@ function formatTimeLocalized(date, format = "short") {
984
1259
  generateRandomColor,
985
1260
  generateShortId,
986
1261
  getEndOfDayISO,
1262
+ getFrequencyDescription,
987
1263
  getNextWeek,
988
1264
  getPreviousWeek,
989
1265
  getRepoName,
@@ -1007,11 +1283,15 @@ function formatTimeLocalized(date, format = "short") {
1007
1283
  isValidISODate,
1008
1284
  isValidUrl,
1009
1285
  normalizeToMidnight,
1286
+ parseFrequencyConfig,
1010
1287
  parseLocalDate,
1011
1288
  progressAtom,
1012
1289
  progressPercentAtom,
1013
1290
  queryKeys,
1014
1291
  remainingSecondsAtom,
1292
+ shouldDoOnDate,
1293
+ shouldDoToday,
1294
+ stringifyFrequencyConfig,
1015
1295
  subtractDays,
1016
1296
  targetSecondsAtom,
1017
1297
  timerStatusAtom,