Members
AUTO_PAUSE_ON_TAB_SWITCH :boolean
When true, pauses a running timer automatically when the browser tab becomes hidden (visibilitychange → document.hidden). The pause is silent; the event is recorded in the console log via wlLog.info but no UI notification appears. Set to false to disable. Override in 00-config.local.js.
Type:
- boolean
- Default Value:
- false
- Source:
(constant) CAL_ACCOUNT_LABELS :Object.<string, string>
Maps raw Outlook account keys (lowercase) to human-readable labels shown in the calendar strip. The PowerShell server sends the DisplayName field; this map handles display-name variants, email domains, and substring matches.
Add an entry for each calendar account you want labelled; unknown accounts are shown without a label badge.
Type:
- Object.<string, string>
- Source:
(constant) COLLAPSE_PREFIX
localStorage key prefix for section open/collapsed state.
- Source:
(constant) DAILY_GOAL_MS :number
Daily tracking goal in milliseconds. The header pace bar fills proportionally as today's logged time approaches this value. Default: 7 hours 30 minutes. Override in 00-config.local.js.
Type:
- number
- Source:
(constant) DEFAULT_WORK_LOCATION
Location id used for any day that has no stored value.
- Source:
(constant) ICON_ACTIVITY
Activity-line SVG icon for the section header (Lucide-style, 24×24 viewBox, 1.5px stroke).
- Source:
JIRA_BASE :string
Base URL for Jira ticket links. Ticket keys found in task names are
converted to <a href="${JIRA_BASE}/${key}"> anchors.
Set to '' to disable link generation.
Override in src/js/00-config.local.js (gitignored) — copy from
src/js/00-config.local.example.js and set your real instance URL.
Type:
- string
- Source:
(constant) MIGRATIONS :Array.<Migration>
Type:
- Array.<Migration>
- Source:
(constant) RAPID_SIG_SHORTCUTS :Object.<string, string>
Signifier shortcode map for quick-capture inline tokens.
Maps !<shortcode> tokens to signifier values used on entry objects.
Unmapped tokens are left in the text unchanged.
Type:
- Object.<string, string>
- Source:
(constant) STORE_BLOCKS :string
localStorage key for the time-block array.
Type:
- string
- Source:
(constant) TF_PANE_IDS
Maps each view to the DOM id of the pane that hosts it.
- Source:
(constant) TF_STRIP_END
21:00 in minutes from midnight — right edge of the day-overview strip.
- Source:
(constant) TF_STRIP_START
07:00 in minutes from midnight — left edge of the day-overview strip.
- Source:
(constant) TF_VIEWS
Ordered list of view ids — drives the segmented control and keyboard nav.
- Source:
(constant) TF_VIEW_LABELS
Display labels for the segmented control. Static so we avoid recomputing on every render.
- Source:
WEATHER_LAT :number
Latitude of the work location (decimal degrees). Default used when the server is not running; normally set via config.local.ps1.
Type:
- number
- Source:
WEATHER_LON :number
Longitude of the work location (decimal degrees). Default used when the server is not running; normally set via config.local.ps1.
Type:
- number
- Source:
WEATHER_NAME :string
Display name for the work location shown next to the weather widget. Default used when the server is not running; normally set via config.local.ps1.
Type:
- string
- Source:
(constant) WORK_LOCATIONS :Readonly.<Record.<string, {emoji: string, label: string}>>
Work-location presets keyed by their stored id. Each entry carries the emoji and human-readable label shown in the date-nav header. The first key is the default applied to any day with no stored location.
Type:
- Readonly.<Record.<string, {emoji: string, label: string}>>
- Source:
_boardDragTaskId
Shared drag-state for board column DnD (set by dragstart, read by drop).
- Source:
_heroStopped :boolean
Type:
- boolean
- Source:
_heroStoppedEntry :Object|null
The log entry that was just stopped. Kept so the Undo action can recover it and the stopped panel can display the correct task name / session range.
Type:
- Object | null
- Source:
_heroStoppedTimer :number|null
Type:
- number | null
- Source:
_qcFilterCat :string|null
Active category chip selection. Serves two purposes:
- filters the task list to show only that category, and
- tags any ad-hoc log entry created via "Log without tracking". null means "All" (no filter; entry falls back to selectedTag).
Type:
- string | null
- Source:
_qcSearch :string
Type:
- string
- Source:
_qcTickInterval :number|null
Type:
- number | null
- Source:
_rapidOpen :boolean
Type:
- boolean
- Source:
catManageOpen
Controls whether the epic manage row (rename/delete/add) is expanded.
- Source:
doneHistoryOpen
Whether the Done column's older-history expander is open.
- Source:
emergencyMode :boolean
True while the focus/emergency overlay is visible.
Type:
- boolean
- Source:
planTasks :Array.<Object>
Plan task list — each item:
{ id, text, status, tag, date, [billable], [notionUrl], [emoji], [checkpoints], [parentId], [priority] }
Type:
- Array.<Object>
- Source:
wipWarnDismissed
Whether the WIP-over warning banner has been dismissed this render cycle.
- Source:
Methods
_heroBindCatPicker(wrap)
Binds open/close/select keyboard and pointer events on a .hero-cat-wrap element.
Parameters:
| Name | Type | Description |
|---|---|---|
wrap |
HTMLElement | The |
- Source:
_heroCancelStoppedTimer()
Cancels the auto-dismiss timer (called by Undo / Done buttons).
- Source:
_heroCatSelect(newTag)
Updates the active entry's category, persists, and re-renders.
Parameters:
| Name | Type | Description |
|---|---|---|
newTag |
string | Category ID to apply. |
- Source:
_heroFillIdle()
Updates the idle panel: logged-today total and last-session time.
- Source:
_heroFillPaused()
Updates the paused panel with the frozen clock and task details.
- Source:
_heroFillRunning()
Updates the running panel: category dot + task title + started-at sub-line.
- Source:
_heroFillStopped()
Updates the stopped panel with the session summary.
- Source:
_heroHandleDone()
Dismiss the stopped confirmation panel immediately (same as auto-dismiss).
- Source:
_heroHandleStart()
Handles the "▶ Start tracking" button. Uses the composer input if it has text; otherwise focuses the plan input.
- Source:
_heroHandleUndo()
Undo the just-stopped entry: remove it from entries and optionally restart the timer if the entry had been running (i.e. it had no prior tsEnd).
- Source:
_heroLastNoteText(entryId) → {string}
Returns "↳ last note X ago" text for the most recent session-note on an entry, or an empty string when no session notes have been added yet.
Parameters:
| Name | Type | Description |
|---|---|---|
entryId |
string | ID of the active log entry. |
- Source:
Returns:
- Type
- string
_heroRenderRecentChips()
Builds the recent-task chip strip in the idle panel. Shows up to 3 distinct recent entries with their category dot.
- Source:
_heroSessionCount(entry) → {number}
Returns the number of distinct time entries today for the same task text.
Parameters:
| Name | Type | Description |
|---|---|---|
entry |
Object |
- Source:
Returns:
- Type
- number
_heroSetCategory(elId, tag, interactiveopt)
Fills a category display cell with the dot + label (and optional caret/picker).
Parameters:
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
elId |
string | ID of the |
||
tag |
string | Category ID. |
||
interactive |
boolean |
<optional> |
false | When true, renders a caret button and picker panel. |
- Source:
_heroShowPanel(id, visible)
Parameters:
| Name | Type | Description |
|---|---|---|
id |
string | Element ID. |
visible |
boolean | Whether to show the element. |
- Source:
_heroStartFromChip(text, tag)
Starts tracking from a recent-chip click. Re-uses the existing entry (no duplicate) and starts the timer.
Parameters:
| Name | Type | Description |
|---|---|---|
text |
string | Task description. |
tag |
string | Category ID. |
- Source:
_qcActivateRow(rowId, text, tag, isActive)
Starts or switches to a task from the quick-capture list. If the row is already the active timer, just closes the modal. For plan-task rows a fresh time entry is created.
Parameters:
| Name | Type | Description |
|---|---|---|
rowId |
string | Row ID from the data attribute. |
text |
string | Task description. |
tag |
string | Category ID. |
isActive |
boolean | Whether this is the currently-running task. |
- Source:
_qcBindTaskListEvents(el)
Attaches click listeners to task-row action buttons and their parent rows. Separated from rendering so each has a single responsibility.
Parameters:
| Name | Type | Description |
|---|---|---|
el |
HTMLElement | The #qcTaskList container element. |
- Source:
_qcBuildTaskGroups(searchLower, todayKey) → {Object}
Collects and deduplicates the three task groups for the current filter state. Pure data function — performs no DOM operations.
Parameters:
| Name | Type | Description |
|---|---|---|
searchLower |
string | Lower-cased search string; empty string means no filter. |
todayKey |
string | Date key for today in YYYY-MM-DD format. |
- Source:
Returns:
- Type
- Object
_qcLogOnly()
Handles the "Log without tracking" footer button and Enter keypress.
Parses inline shorthand tokens from the input before creating the entry:
#<cat> overrides category, !<sig> sets the signifier,
><date> sets the entry date (today / tomorrow / YYYY-MM-DD / weekday).
- Non-empty text after token stripping → creates a log entry (no timer) and closes.
- Only tokens, no text → refocuses the input so the user adds a description.
- Completely empty input → closes and focuses the ad-hoc row in the time log.
- Source:
_qcRenderAll()
Re-renders all dynamic regions of the quick-capture modal.
- Source:
_qcRenderCatChips()
Renders the "All" chip plus one chip per category. The active chip is highlighted; clicking a chip filters the task list.
- Source:
_qcRenderRunningStrip()
Shows or hides the running strip. When a timer is active the strip displays the current task and elapsed time. When idle the strip is hidden and the pulsing-dot class is removed.
- Source:
_qcRenderTaskList()
Orchestrates data collection, rendering, and event binding for the task list. Delegates each concern to a single-purpose helper.
- Source:
_qcRenderTokenPreview(parsed)
Renders colored pill badges below the search input for any recognised inline tokens in the current input value. Hides the preview container when no tokens are active (e.g. on modal open or after the field is cleared).
Parameters:
| Name | Type | Description |
|---|---|---|
parsed |
Object | Result of parseRapidTokens() for the current raw input value. |
- Source:
_qcStartTick()
Starts a 1-second interval to update the elapsed-time label in the running strip.
- Source:
_qcStopTick()
Clears the running-strip interval.
- Source:
_qcTaskListHtml(groups, search) → {string}
Renders the task list HTML string from pre-built group data. Receives all inputs as parameters — performs no DOM or module-state reads.
Parameters:
| Name | Type | Description |
|---|---|---|
groups |
Object | |
search |
string | Original (un-lowercased) search string for the empty-state message. |
- Source:
Returns:
HTML string ready for assignment to el.innerHTML.
- Type
- string
_qcTaskRowHtml(rowId, text, cat, isActive) → {string}
Returns the HTML for one task row in the task list. The action button is opacity-0 and revealed on row hover via CSS.
Parameters:
| Name | Type | Description |
|---|---|---|
rowId |
string | Unique row key: entry ID or 'plan:' + plan-task ID. |
text |
string | Task/entry description text. |
cat |
Object | Resolved category. |
isActive |
boolean | True when this row matches the currently-running entry. |
- Source:
Returns:
HTML string.
- Type
- string
_qcUpdateElapsed()
Updates only the elapsed-time label; called every second by the ticker.
- Source:
activeTimerDurationMs(entry) → {number}
Returns the effective tracked duration (ms) of an active-timer entry, honouring pause state — matches the formula used by renderFlowHeader so the strip bar and Flow-view duration freeze while paused.
Parameters:
| Name | Type | Description |
|---|---|---|
entry |
object |
- Source:
Returns:
0 if no timer is active for this entry.
- Type
- number
addEntry(withTimer)
Creates a new log entry from the capture input's current value.
Optionally starts the timer on the new entry (withTimer = true), in which
case any running timer is stopped first and the matching plan task is
auto-promoted to "in progress".
Parameters:
| Name | Type | Description |
|---|---|---|
withTimer |
boolean | If true, start the timer on the new entry. |
- Source:
addLogNote()
Reads the note input, appends a note to logNotes, persists, and re-renders.
- Source:
addPlanTask() → {void}
Reads the plan-input field and adds a new "todo" task to today's plan. Inherits the currently selected tag and that category's billable default. No-ops if the input is empty.
- Source:
Returns:
- Type
- void
(async) addTaskToNotion(task) → {Promise.<string>}
Adds a work-log task to Notion as a child page under the matching project.
The project is looked up server-side by matching the task's category label to a
Notion project's Epic field. Uses /api/notion-add-task (Notion REST API, no AI).
Parameters:
| Name | Type | Description |
|---|---|---|
task |
Object | Plan task object with at least |
- Source:
Throws:
-
If the API call fails or no URL is returned.
- Type
- Error
Returns:
The URL of the newly created Notion page.
- Type
- Promise.<string>
applyTime(baseTsMs, timeStr) → {number}
Replaces the hours/minutes of a base timestamp with values parsed from a "HH:MM" string, returning the resulting timestamp in milliseconds.
Parameters:
| Name | Type | Description |
|---|---|---|
baseTsMs |
number | Base Unix timestamp (ms) that supplies the date. |
timeStr |
string | Time string in "HH:MM" format. |
- Source:
Returns:
New Unix timestamp (ms) with the updated time.
- Type
- number
autoCarryTasks() → {number|undefined}
Carries unfinished plan tasks from past days into today — runs once per day
(guarded by a localStorage flag). Deduplicates by text, preserving the most
recent past status and status-comment history. Checkpoints are carried forward
with done reset to false for a fresh day.
- Source:
Returns:
Number of tasks newly carried, or undefined if carry has already run today.
- Type
- number | undefined
billBtnHtml(t, status) → {string}
Builds the billable toggle button HTML for a task row. Returns empty string for pending/blocked/upcoming tasks where billing is irrelevant.
Parameters:
| Name | Type | Description |
|---|---|---|
t |
Object | The plan task. |
status |
string | The task's current status. |
- Source:
Returns:
HTML button element, or ''.
- Type
- string
bindBoardColumnDnD()
Makes each rendered board card draggable and wires its dragstart/dragend.
Called once per renderPlan() cycle after columns are populated.
Static column drop-zone listeners are set up once in initBoardColumnDnD().
- Source:
bindPlanEvents(lists)
Binds all plan list event handlers after each render.
Parameters:
| Name | Type | Description |
|---|---|---|
lists |
Array.<HTMLElement> | Column list elements (To Do, In Progress, Done). |
- Source:
bindSignifierClicks()
Attaches click and keyboard listeners to all .esig elements after a render.
- Source:
buildBillableSummaryParts(mergedEntries, getCatLabel) → {Array.<string>}
Builds the parts of the pasteable billable summary from merged billable
entries. Categorised tasks are grouped as Category (task1, task2);
uncategorised tasks (no tag or other) are listed bare. Order of first
appearance is preserved and duplicate task names are de-duplicated.
Parameters:
| Name | Type | Description |
|---|---|---|
mergedEntries |
Array.<Object> | Output of mergeAdjacentEntries. |
getCatLabel |
function | Resolves a category key to its display label. Injected so this function stays free of global state. |
- Source:
Returns:
Summary parts, ready to be joined with , .
- Type
- Array.<string>
(async) buildBridge(meeting, expandedEl, bridgeBtn, onDismiss) → {Promise.<void>}
Determines the next task to transition to and delegates to fetchBridge. If multiple tasks are in-flight the user picks from a list; a single in-progress task is auto-selected; the only remaining task is auto-selected.
Parameters:
| Name | Type | Description |
|---|---|---|
meeting |
Object | The meeting that just ended. |
expandedEl |
HTMLElement | Container for the bridge content. |
bridgeBtn |
HTMLElement | "Build bridge" button (disabled during fetch). |
onDismiss |
function | Callback to dismiss the banner. |
- Source:
Returns:
- Type
- Promise.<void>
buildDailyLogItems(dateKey) → {Array.<{ts: number, type: string, entryId: (string|undefined), parentEntryId: (string|undefined), color: string, text: string, sub: string}>}
Builds a chronologically sorted array of feed items for the Log view. Merges time entries, log notes, and task status comments for the given day.
Item types:
'entry'— a time-tracked entry; includesentryId.'note'— a freeform log note; text is wrapped in<em>.'session-note'— a note attached to a running/completed entry; includesparentEntryId. Renderers nest these inside their parent entry row rather than as standalone timeline rows.'task'— a plan-task status comment.
Parameters:
| Name | Type | Description |
|---|---|---|
dateKey |
string | YYYY-MM-DD date string. |
- Source:
Returns:
- Type
- Array.<{ts: number, type: string, entryId: (string|undefined), parentEntryId: (string|undefined), color: string, text: string, sub: string}>
buildSessionNotesHtml(notes) → {string}
Builds the HTML fragment for a list of session-notes nested under a parent entry row. Returns an empty string when there are no notes.
Parameters:
| Name | Type | Description |
|---|---|---|
notes |
Array.<object> | Session-note items for one parent entry. |
- Source:
Returns:
HTML string, or '' if notes is empty.
- Type
- string
calAccountLabel(account) → {string|null}
Resolves a human-readable account label for an Outlook calendar account.
The PowerShell server sends the raw DisplayName which may be an email
address, a display name, or free-form company text. Tries three strategies
in order: exact match, email domain extraction, and substring match.
Parameters:
| Name | Type | Description |
|---|---|---|
account |
string | null | Raw Outlook account identifier. |
- Source:
Returns:
Display label (e.g. "LähiTapiola"), or null if unknown.
- Type
- string | null
calcMonthSummaryStats(allEntries, monthPrefix, isBillable) → {Object}
Computes monthly summary statistics from a flat entries array. Pure: takes
its own data dependency, no DOM, no module globals. Excludes entries with
no tsEnd (still running) or signifier === 'cancelled'.
Parameters:
| Name | Type | Description |
|---|---|---|
allEntries |
Array.<Object> | The full entries array to filter. |
monthPrefix |
string | Date prefix |
isBillable |
function | Predicate identifying
billable entries; the caller supplies the project's |
- Source:
Returns:
- Type
- Object
calcMonthTaskCounts(allTasks, monthPrefix) → {Object}
Computes open / done / migrated task counts for a given month. Pure.
_migrated (programmatic) and signifier === 'migrated' (BuJo marker)
both count toward the migrated total.
Parameters:
| Name | Type | Description |
|---|---|---|
allTasks |
Array.<Object> | The full plan-tasks array. |
monthPrefix |
string | Date prefix |
- Source:
Returns:
- Type
- Object
calcStreak() → {number}
Counts consecutive days with at least one logged entry, looking backwards from yesterday. Today is excluded so the streak only increments once the day has been completed.
- Source:
Returns:
- Type
- number
(async) callClaudeWithNotion(prompt, optsopt) → {Promise.<string>}
Calls the Claude API with a Notion MCP server attached, via the local proxy
at /api/notion-ai (API keys never exposed to the browser).
Used for the URL-bookmarking form — task imports use addTaskToNotion instead.
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
prompt |
string | User prompt text. |
|
opts |
Object |
<optional> |
Optional overrides ( |
- Source:
Throws:
-
If the API returns a non-OK status.
- Type
- Error
Returns:
The concatenated text content of the response.
- Type
- Promise.<string>
carryMigTask(task)
Duplicates the task into next month (first day) and marks original as migrated.
Parameters:
| Name | Type | Description |
|---|---|---|
task |
Object |
- Source:
checkBlockNotifications()
Checks all of today's time blocks and acts on ones that have just become active:
- Meeting blocks: auto-starts a log entry and timer at the scheduled start time.
- Task blocks: prompts the user to switch/start within a 3-minute window.
Each block is only acted on once (tracked in
notifiedBlocks). No-ops when not viewing today.
- Source:
checkChime(elapsedMs)
Fires an audible chime if the elapsed time has crossed a configured interval boundary since the last chime. No-ops when the timer is paused.
Parameters:
| Name | Type | Description |
|---|---|---|
elapsedMs |
number | Elapsed time in milliseconds. |
- Source:
checkNewDay()
Formerly showed a "new day" banner prompting the user to export yesterday's log. The banner was removed — end-of-day modal handles exports now. Kept as a no-op stub to avoid removing the call sites.
- Source:
checkPomoWeeklyClear()
Clears the pomodoro log when a new ISO week begins. Compares the stored week key against the current ISO week; if they differ, the log is removed and the new week key is saved.
- Source:
(async) clearDirHandle() → {Promise.<void>}
Clears the persisted FSA directory handle from both IndexedDB and the in-memory cache so future exports fall back to browser downloads.
- Source:
Returns:
- Type
- Promise.<void>
closeAllEditors()
Closes every open inline time-editor panel and restores the display spans.
- Source:
closeMigration()
Closes the migration overlay.
- Source:
closeRapid()
Hides the quick-capture overlay and stops the elapsed ticker.
- Source:
closeTrackerForm() → {void}
Hides the new-tracker form and resets the open-state flag.
- Source:
Returns:
- Type
- void
commitBannerNote()
Saves a timestamped note attached to the currently-active timer entry. The note is stored in logNotes (type: 'session-note') and rendered nested under its parent entry in the flow/log views, rather than as a standalone time-tracked entry. No-ops when there is no active timer or the note is empty.
- Source:
computeDayBounds(dayEntries, timedEntries, opts) → {Object}
Computes the day's start and end timestamps for the plaintext export header.
Start: the supplied day start (today only) or, failing that, the earliest entry start. End: the latest tracked end among timed entries, extended by the active timer's effective end so "Ended:" reflects work still in progress.
Pure: all environmental inputs (day start, the active timer, the current time)
are injected via opts so the function can be unit-tested without globals.
Parameters:
| Name | Type | Description | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
dayEntries |
Array.<Object> | All entries for the viewed day. |
|||||||||||||||
timedEntries |
Array.<Object> | Entries with a real tracked duration ( |
|||||||||||||||
opts |
Object | Injected environment. Properties
|
- Source:
Returns:
Day bounds in ms.
- Type
- Object
config(cfg)
Logs a snapshot of runtime configuration at startup in a collapsed group. Called once by 07-lifecycle.js after state is loaded.
Parameters:
| Name | Type | Description |
|---|---|---|
cfg |
Object | Key/value pairs to display (e.g. version, entry count). |
cycleSignifier(entryId)
Advances an entry's signifier one step through SIG_CYCLE and persists the change. Wraps from the last value back to null (no signifier).
Parameters:
| Name | Type | Description |
|---|---|---|
entryId |
string | ID of the entry to update. |
- Source:
debug(msg, dataopt)
Emits a debug-level message, visible only when DevTools verbose level is on.
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
msg |
string | Human-readable message. |
|
data |
* |
<optional> |
Optional value to attach to the log line. |
dk(d) → {string}
Formats a Date as YYYY-MM-DD using local calendar date. Uses local date components (getFullYear / getMonth / getDate) so the returned string always matches the date the user sees on their clock, regardless of timezone.
Parameters:
| Name | Type | Description |
|---|---|---|
d |
Date | Date to format. |
- Source:
Returns:
e.g. '2026-05-26'
- Type
- string
Example
dk(new Date(2026, 4, 26, 12, 0, 0)) // → '2026-05-26' (noon local)
dk(new Date(2026, 11, 31, 23, 59, 0)) // → '2026-12-31' (11 PM local)
dk(new Date(2026, 0, 1, 0, 0, 0)) // → '2026-01-01' (midnight local)
drawPomoSegments()
Redraws all pomodoro SVG segments to reflect the current remaining time. Each minute is a sector; filled sectors fade as time elapses.
- Source:
dropMigTask(task)
Archives (drops) the task by marking it done and migrated.
Parameters:
| Name | Type | Description |
|---|---|---|
task |
Object |
- Source:
durLabel(tsStart, tsEnd) → {string}
Builds an HTML <span class="etime-dur"> containing the human-readable
duration between two timestamps. Returns an empty string if the duration
is zero or negative.
Parameters:
| Name | Type | Description |
|---|---|---|
tsStart |
number | Start Unix timestamp (ms). |
tsEnd |
number | End Unix timestamp (ms). |
- Source:
Returns:
HTML string, or '' if duration ≤ 0.
- Type
- string
ensureDayStarted() → {void}
Records start-of-day silently (no backup-restore dialog) if the day has not already been started. Called automatically when the first task timer begins.
- Source:
Returns:
- Type
- void
enterEmergency()
Activates focus/emergency mode: hides the main UI, shows the overlay, moves the pomodoro section into the overlay, and focuses the next-action input. The previously saved next-action note is restored if one exists for the active entry.
- Source:
eodKey(dayopt) → {string}
Returns the localStorage key for a given day's end-of-day timestamp.
Parameters:
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
day |
Date |
<optional> |
viewDate | Day to key by; defaults to the day in view. |
- Source:
Returns:
Key in the format wl_eod_YYYY-MM-DD.
- Type
- string
error(msg, dataopt)
Emits an error — something that broke or produced an incorrect result.
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
msg |
string | Human-readable message. |
|
data |
* |
<optional> |
Optional value to attach to the log line. |
escHtml(s) → {string}
Escapes a string for safe insertion as HTML text content.
Parameters:
| Name | Type | Description |
|---|---|---|
s |
string | Raw string to escape. |
- Source:
Returns:
HTML-escaped string safe for insertion into the DOM.
- Type
- string
Example
escHtml('<b>bold</b>') // → '<b>bold</b>'
escHtml('a & b') // → 'a & b'
escHtml('"quoted"') // → '"quoted"'
escHtml(42) // → '42'
exitEmergency()
Deactivates focus/emergency mode: restores the main UI, saves the next-action note, moves the pomodoro section back to its normal position, and auto-expands the active task's checkpoint list so the user can pick up where they left off.
- Source:
exportBackup()
Exports a full JSON backup of all application state: entries, categories, plan tasks, time blocks, pomodoro log, dev log, distractions, and hidden quick-pick items. Triggers a file download or writes to the save folder.
- Source:
exportTxt()
Exports the currently viewed day's log as a plaintext file. Groups entries by category and task, includes a header with day start/end times and tracked time totals, and appends a pasteable billable summary. Writes to the user's chosen save folder via the File System Access API, or falls back to a browser download.
- Source:
(async) fetchAndRenderCalendar() → {Promise.<void>}
Fetches today's meetings from the local PowerShell proxy (/api/calendar),
caches the result, filters out user-hidden meetings, and calls
renderCalStrip. Logs a warning and shows a fallback message on error.
- Source:
Returns:
- Type
- Promise.<void>
(async) fetchBridge(meeting, task, expandedEl, bridgeBtn, onDismiss) → {Promise.<void>}
Calls the Claude API via /api/ai to generate 3 concrete physical steps for
transitioning from the ended meeting to the next task. Displays the result in
expandedEl; falls back to copying the prompt to the clipboard on API error.
Parameters:
| Name | Type | Description |
|---|---|---|
meeting |
Object | The meeting that just ended. |
task |
Object | The next plan task to transition to. |
expandedEl |
HTMLElement | Container for the bridge content. |
bridgeBtn |
HTMLElement | "Build bridge" button (disabled during fetch). |
onDismiss |
function | Callback to dismiss the banner. |
- Source:
Returns:
- Type
- Promise.<void>
fetchCalendarEvents()
Fetches today's Finnish flag days, public holidays, and notable days from the
Nimipäivärajapinta Typesense API, displaying the first match in #liveFlagDay.
If today has no event, shows the next upcoming one. Falls back to the hardcoded
FLAG_DAYS_FIXED list if the API is unreachable.
- Source:
fetchNameday()
Fetches today's Finnish and Swedish name days from the Nimipäivärajapinta API
and renders them in #liveNameday. Falls back to an "API unavailable" note
on error.
- Source:
fetchWeather()
Fetches current weather, hourly precipitation probability, and sunrise/sunset
data from the Open-Meteo API for the configured location (WEATHER_LAT,
WEATHER_LON) and populates #liveWeather, #liveRain, and
#liveSunrise. No-ops gracefully on file: protocol or network error.
- Source:
findLargestGap(dateKey) → {Object|null}
Finds the largest untracked gap (≥ 15 min) today, including gaps between consecutive completed entries AND the trailing gap from the most recent entry's end to now (which is often the most actionable). Returns null for past days — only actionable today.
Parameters:
| Name | Type | Description |
|---|---|---|
dateKey |
string | YYYY-MM-DD. |
- Source:
Returns:
- Type
- Object | null
flatSort(tasks) → {Array.<Object>}
Sorts a flat list of plan tasks by status order and priority, inserting child tasks immediately after their parent. Tasks matching the currently running timer text are sorted first. Orphaned children (whose parent has been deleted or moved) are appended at the end.
Parameters:
| Name | Type | Description |
|---|---|---|
tasks |
Array.<Object> | Array of plan task objects to sort. |
- Source:
Returns:
New sorted array with children interleaved after parents.
- Type
- Array.<Object>
fmtAgo(ts, nowopt) → {string}
Formats a past timestamp as a relative "ago" string for the last-note reference line.
Uses an injected now parameter so it is fully unit-testable without mocking Date.now.
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
ts |
number | Unix timestamp in milliseconds of the past event. |
|
now |
number |
<optional> |
Current time in ms; defaults to Date.now(). |
- Source:
Returns:
'just now' | 'X min ago' | 'Xh ago'
- Type
- string
Example
fmtAgo(Date.now() - 30000) // → 'just now'
fmtAgo(Date.now() - 2 * 60000) // → '2 min ago'
fmtAgo(Date.now() - 90 * 60000) // → '1h ago'
fmtDur(ms) → {string}
Formats a duration in milliseconds as a compact human-readable string ("Xh Ym"). Used throughout the UI for tracked-time display in the timeline, chart, and plan.
Parameters:
| Name | Type | Description |
|---|---|---|
ms |
number | Duration in milliseconds. |
- Source:
Returns:
e.g. '1h 30m', '45m', '2h'
- Type
- string
Example
fmtDur(0) // → '0m'
fmtDur(45 * 60 * 1000) // → '45m'
fmtDur(90 * 60 * 1000) // → '1h 30m'
fmtDur(120 * 60 * 1000) // → '2h'
fmtDurLong(ms) → {string}
Formats a duration in milliseconds as a human-readable string using the long "min" suffix. Used in plaintext exports where readability matters more than compactness.
Parameters:
| Name | Type | Description |
|---|---|---|
ms |
number | Duration in milliseconds. |
- Source:
Returns:
e.g. '1h 30min', '45min', '2h'
- Type
- string
Example
fmtDurLong(0) // → '0min'
fmtDurLong(45 * 60 * 1000) // → '45min'
fmtDurLong(90 * 60 * 1000) // → '1h 30min'
fmtDurLong(120 * 60 * 1000) // → '2h'
fmtElapsed(ms) → {string}
Formats a duration in milliseconds as a compact time string.
Parameters:
| Name | Type | Description |
|---|---|---|
ms |
number | Duration in milliseconds. |
- Source:
Returns:
'MM:SS' for durations under an hour; 'HH:MM:SS' otherwise.
- Type
- string
Example
fmtElapsed(0) // → '00:00'
fmtElapsed(90 * 1000) // → '01:30'
fmtElapsed(3600 * 1000) // → '01:00:00'
fmtElapsed(5461 * 1000) // → '01:31:01'
fmtHm(ts) → {string}
Formats a Unix timestamp (ms) as HH:MM in local time.
Parameters:
| Name | Type | Description |
|---|---|---|
ts |
number |
- Source:
Returns:
- Type
- string
fmtLabel(d) → {string}
Returns a human-readable day label: 'today', 'yesterday', or a short locale date string.
Parameters:
| Name | Type | Description |
|---|---|---|
d |
Date |
- Source:
Returns:
- Type
- string
fmtMD(d) → {string}
Formats a Date as a zero-padded "MM-DD" string used as flag-day map keys.
Parameters:
| Name | Type | Description |
|---|---|---|
d |
Date | The date to format. |
- Source:
Returns:
e.g. "06-04" for the 4th of June.
- Type
- string
fmtTime(ts) → {string}
Formats a Unix timestamp as HH:MM in 24-hour local time.
Parameters:
| Name | Type | Description |
|---|---|---|
ts |
number | Unix timestamp in milliseconds. |
- Source:
Returns:
e.g. '09:30'
- Type
- string
Example
fmtTime(new Date('2026-05-25T09:05:00').getTime()) // → '09:05'
fmtTime(new Date('2026-05-25T14:30:00').getTime()) // → '14:30'
focusTabAt(nextIndex)
Selects the view at index nextIndex in TF_VIEWS, focuses its tab button,
and re-renders. Shared by the keyboard handler in initTodayFlow().
Parameters:
| Name | Type | Description |
|---|---|---|
nextIndex |
number |
- Source:
formatGroupedLines(catOrder, catGrouped, fmtDuration, getCatLabel) → {Array.<string>}
Renders the grouped-by-category structure into indented text lines: one line per category (with its total), each followed by its indented task lines.
Pure: the duration formatter and category-label resolver are injected so this function has no dependency on global state and can be unit-tested directly.
Parameters:
| Name | Type | Description |
|---|---|---|
catOrder |
Array.<string> | Category keys in display order. |
catGrouped |
Object | Grouping produced by groupEntriesByCategory. |
fmtDuration |
function | Formats a duration in ms (e.g. |
getCatLabel |
function | Resolves a category key to its label. |
- Source:
Returns:
The body lines for the export file.
- Type
- Array.<string>
getCat(id) → {Object}
Returns the category object for id, falling back to 'other' if not found.
The returned colour is always sanitised through safeCssColor.
Parameters:
| Name | Type | Description |
|---|---|---|
id |
string | Category ID. |
- Source:
Returns:
- Type
- Object
getDayStart(dayopt) → {number|null}
Retrieves a given day's recorded start-of-day timestamp from localStorage.
Parameters:
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
day |
Date |
<optional> |
viewDate | Day to read; defaults to the day in view. |
- Source:
Returns:
Unix timestamp (ms), or null if not yet set.
- Type
- number | null
getElapsedMs() → {number}
Returns the total elapsed milliseconds for the active timer. Accounts for accumulated time from previous pause/resume cycles. Returns 0 if no timer is active.
- Source:
Returns:
Elapsed time in milliseconds.
- Type
- number
getEodTs(dayopt) → {number|null}
Retrieves a given day's recorded end-of-day timestamp from localStorage.
Parameters:
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
day |
Date |
<optional> |
viewDate | Day to read; defaults to the day in view. |
- Source:
Returns:
Unix timestamp (ms), or null if not yet set.
- Type
- number | null
getFlagDays(year) → {Object.<string, string>}
Returns an object mapping "MM-DD" strings to Finnish flag-day names for the given year. Combines fixed dates with computed moveable feasts.
Parameters:
| Name | Type | Description |
|---|---|---|
year |
number | The full 4-digit year. |
- Source:
Returns:
Map of "MM-DD" → event name.
- Type
- Object.<string, string>
getFlowView() → {'flow'|'log'|'blocks'|'month'}
Returns the persisted view preference, defaulting to 'flow'.
- Source:
Returns:
- Type
- 'flow' | 'log' | 'blocks' | 'month'
getHandoffNote(entryText) → {string|null}
Retrieves the stored handoff note for a given entry text. The lookup is case-insensitive and trims whitespace.
Parameters:
| Name | Type | Description |
|---|---|---|
entryText |
string | The entry text to look up. |
- Source:
Returns:
The stored note, or null if none exists.
- Type
- string | null
getISOWeek(d) → {number}
Returns the ISO 8601 week number for a given date.
Parameters:
| Name | Type | Description |
|---|---|---|
d |
Date | The date to evaluate. |
- Source:
Returns:
ISO week number (1–53).
- Type
- number
getIterationExpiry(completedDay) → {string|null}
Returns the first iteration expiry date that is strictly later than
completedDay, or null if none is configured beyond that date.
Parameters:
| Name | Type | Description |
|---|---|---|
completedDay |
string | Completion date in "YYYY-MM-DD" format. |
- Source:
Returns:
The next expiry date, or null.
- Type
- string | null
getMeetingKey(m) → {string}
Returns a stable string key for a meeting used to deduplicate bridge banners.
Parameters:
| Name | Type | Description |
|---|---|---|
m |
Object | Meeting object. |
- Source:
Returns:
- Type
- string
getMigrationRecord() → {Object}
Returns the migration completion record (map of YYYY-MM → boolean).
- Source:
Returns:
- Type
- Object
getMoonData(date) → {Object}
Calculates moon phase, illumination percentage, and zodiac sign for a date using a simplified version of the Meeus algorithm.
Parameters:
| Name | Type | Description |
|---|---|---|
date |
Date | The date to evaluate. |
- Source:
Returns:
emoji = phase emoji, phase = phase name, illum = illumination (%),
sign = [symbol, name] of the current zodiac sign.
- Type
- Object
getReflectionForDate(dateKey) → {Object|null}
Returns the stored reflection record for a given day, or null if none exists.
Parameters:
| Name | Type | Description |
|---|---|---|
dateKey |
string | YYYY-MM-DD date string. |
- Source:
Returns:
- Type
- Object | null
(async) getSavedDir() → {Promise.<(FileSystemDirectoryHandle|null)>}
Retrieves the previously granted File System Access directory handle from IndexedDB (with an in-memory cache).
- Source:
Returns:
The handle, or null if none saved.
- Type
- Promise.<(FileSystemDirectoryHandle|null)>
getSeenEnded() → {Set.<string>}
Returns the set of meeting keys (subject|start) that have already triggered
a bridge banner in this session, loaded from localStorage.
- Source:
Returns:
- Type
- Set.<string>
getViewLocation() → {string}
Resolves the work location for the currently viewed day.
- Source:
Returns:
A location id present in WORK_LOCATIONS.
- Type
- string
groupEntriesByCategory(dayEntries) → {Object}
Groups a day's log entries by category and, within each category, by task
(case-insensitively), preserving first-seen order. Accumulates tracked time
(where tsEnd > ts) per task and per category.
Pure data transform — reads only entry fields and performs no formatting, so the caller decides how to render the durations and labels.
Parameters:
| Name | Type | Description |
|---|---|---|
dayEntries |
Array.<Object> | Entries for the viewed day. |
- Source:
Returns:
catOrder is the list of
category keys in first-seen order; catGrouped[catKey] is
{ totalMs, tasks: { [taskKey]: { label, totalMs, hasTime } }, taskOrder }.
- Type
- Object
groupTasksByColumn(viewKey) → {Object}
Partitions today's plan tasks into the three kanban column groups.
Parameters:
| Name | Type | Description |
|---|---|---|
viewKey |
string | Date key (YYYY-MM-DD) for the current view. |
- Source:
Returns:
- Type
- Object
handleMoodSelect(mood, icon)
Handles a mood selection from the banner dropdown. Records a distraction or parked thought as an entry (for distracted/parked moods), triggers the hook panel for 'interesting', and sets focus mode for 'focus'. Closes the panel afterwards.
Parameters:
| Name | Type | Description |
|---|---|---|
mood |
string | One of 'distracted' | 'parked' | 'focus' | 'interesting'. |
icon |
string | Emoji icon for the mood. |
- Source:
heroEnterStopped(entry)
Called by stopTimer() just before activeTimer is cleared. Shows the stopped confirmation panel and arms the 6s auto-dismiss.
Parameters:
| Name | Type | Description |
|---|---|---|
entry |
Object | The log entry that was just stopped. |
- Source:
heroGetState() → {'idle'|'running'|'paused'|'stopped'}
Derives the current hero state from module-level timer variables.
- Source:
Returns:
- Type
- 'idle' | 'running' | 'paused' | 'stopped'
heroUpdateClock()
Updates the running-state elapsed clock without a full render. Only touches the clock element so the DOM churn stays minimal.
- Source:
hideHandoffInput()
Hides and clears the handoff-note text field.
- Source:
(async) importBackup(file) → {Promise.<void>}
Restores application state from a JSON backup file previously created by exportBackup. Reads the file, validates its structure via validateBackupFile, asks the user to confirm, writes all arrays to their localStorage keys, then reloads the page so state is re-initialised cleanly from the restored data.
Assumption: import is a full replace, not a merge. All data currently in the affected localStorage keys is overwritten after the user confirms. If selective-date merging is ever needed, add a merge mode option here and update the confirmation dialog accordingly.
Parameters:
| Name | Type | Description |
|---|---|---|
file |
File | The .json backup file selected by the user. |
- Source:
Returns:
- Type
- Promise.<void>
info(msg, dataopt)
Emits an informational message.
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
msg |
string | Human-readable message. |
|
data |
* |
<optional> |
Optional value to attach to the log line. |
initBannerControls()
Binds all interactive controls on the V5 timer banner:
mood dropdown, quick-note input, and Break / Lunch / Meeting utility pills.
Called once from 07-lifecycle.js after DOMContentLoaded is guaranteed.
- Source:
initBoardColumnDnD()
Registers dragover, dragleave, and drop listeners on the three static board
column lists. Called exactly once on DOMContentLoaded from 07-lifecycle.js.
Card draggable wiring (re-rendered each cycle) stays in bindBoardColumnDnD().
- Source:
initHero()
Binds all Hero Card button events. Called once from DOMContentLoaded in 07-lifecycle.js.
- Source:
initLocation() → {void}
Binds the location toggle button. Called exactly once from the boot sequence in 07-lifecycle.js; there is no re-invocation path, so the click listener is attached without a guard. If a future caller invokes this more than once, add a removeEventListener (or an "already bound" flag) first to avoid duplicate handlers. Safe to call when the button is missing.
- Source:
Returns:
- Type
- void
initMigration()
Initialises the migration overlay: wires close button and optionally shows a last-day-of-month banner once per month.
- Source:
initMonthlyLog() → {void}
Bootstraps the Monthly Log feature. The Monthly Log is now the "Month" tab in Today's Flow; its visibility and rendering are driven by renderTodayFlow(). Month sync happens in initTodayFlow() when the Month tab is clicked. This function is kept as a no-op so the call site in 07-lifecycle.js does not need to change.
- Source:
Returns:
- Type
- void
initPomo(mins)
Initialises (or re-initialises) the pomodoro timer for the given duration. Clears any running interval, resets state, and highlights the matching duration button.
Parameters:
| Name | Type | Description |
|---|---|---|
mins |
number | Session duration in minutes. |
- Source:
initRapid()
Registers all event listeners for the quick-capture overlay. Called once on DOMContentLoaded.
- Source:
initSprints() → {void}
Registers all sprint UI event listeners: the sprint mode button, start, cancel, and Enter-key shortcut on the intention input. Called once on DOMContentLoaded.
- Source:
Returns:
- Type
- void
initTodayFlow()
Binds the static listeners exactly once on DOMContentLoaded:
- Log-note input/button (static HTML, never recreated)
- Segmented-control click + keyboard nav, delegated off the stable #tfHeader container so we survive its innerHTML being rewritten by every renderFlowHeader() call. Avoids the listener-accumulation bug that occurred when binding happened inside render functions.
- Source:
initTrackers() → {void}
Bootstraps the Trackers feature: performs the initial render and wires up the "+ New" button to toggle the tracker form open/closed. Called once on DOMContentLoaded.
- Source:
Returns:
- Type
- void
isEntryBillable(entry) → {boolean}
Determines whether a log entry is billable, using a three-tier lookup:
- The entry's own
billableflag (if explicitly set). - The matching plan task's
billableflag. - The category default.
Assumption: entries and tasks where billable is undefined are treated as
billable by default. This preserves backward compatibility with data created
before the billable flag was introduced — older entries must not silently
disappear from billing reports after an upgrade.
If the default should change to non-billable, a migration of existing
localStorage data is required (see DATA.md § wl_entries).
Parameters:
| Name | Type | Description |
|---|---|---|
entry |
Object | Log entry object. |
- Source:
Returns:
True if the entry should be counted as billable.
- Type
- boolean
isToday(d) → {boolean}
Returns true if d falls on today's calendar date (UTC).
Parameters:
| Name | Type | Description |
|---|---|---|
d |
Date |
- Source:
Returns:
- Type
- boolean
jiraTicketHtml(text) → {string}
Returns HTML for a task text string, converting any leading Jira ticket key
(e.g. AITO-1234) into a clickable link. The remainder of the text is
HTML-escaped and appended.
Parameters:
| Name | Type | Description |
|---|---|---|
text |
string | Raw task text, possibly starting with a Jira key. |
- Source:
Returns:
HTML string.
- Type
- string
lastWeekday(year, month, weekday) → {Date}
Returns the date of the last occurrence of a weekday in the given month.
Parameters:
| Name | Type | Description |
|---|---|---|
year |
number | Full 4-digit year. |
month |
number | Month (1 = January … 12 = December). |
weekday |
number | Day of week (0 = Sunday … 6 = Saturday). |
- Source:
Returns:
- Type
- Date
load()
Loads all persistent state from localStorage into module-level variables. Invalid records are dropped per-item (rather than rejecting entire arrays) and any drops are reported via wlLog.warn so data-quality issues are visible in DevTools rather than silently disappearing. Falls back to the last snapshot if entries are missing from primary storage.
- Source:
loadBlocks()
Loads time blocks from localStorage into blocks, filtering invalid entries.
Drops are reported via wlLog.warn so data-quality issues are visible in DevTools.
Applies a one-time migration to shift existing block slots by +2 when the
time-block grid start time changed from 08:00 to 07:00.
- Source:
loadExpiryDates()
Loads iteration expiry dates from localStorage into _expiryDates.
Seeds localStorage with EXPIRY_SEED on first run.
- Source:
loadLocationMap() → {Record.<string, string>}
Reads the stored location map from localStorage. Returns an empty map (and logs a warning) if the value is missing or corrupt, so a single bad write can never break the header render.
- Source:
Returns:
Date-key → location-id map.
- Type
- Record.<string, string>
loadPlan() → {void}
Loads plan tasks from localStorage into planTasks, filtering out invalid
entries via validPlanTask. Drops are reported via wlLog.warn so data-quality
issues are visible in DevTools. Resets to empty array on parse error.
- Source:
Returns:
- Type
- void
loadReflection()
Loads reflection data from localStorage into _reflData.
- Source:
loadSprintLog() → {void}
Loads sprint history from localStorage into the module-level sprintLog array.
Falls back to an empty array and logs a warning on parse failure.
- Source:
Returns:
- Type
- void
loadTrackers() → {void}
Loads the trackers array from localStorage into the module-level trackers variable.
Falls back to an empty array and logs a warning on parse failure.
- Source:
Returns:
- Type
- void
locationFor(map, dateKey) → {string}
Resolves the stored work location for a given day, falling back to the default when the day is unset or holds an unknown value.
Parameters:
| Name | Type | Description |
|---|---|---|
map |
Record.<string, string> | Date-key → location-id map. |
dateKey |
string | Day key in YYYY-MM-DD form (see dk). |
- Source:
Returns:
A valid location id present in WORK_LOCATIONS.
- Type
- string
Example
locationFor({ '2026-06-03': 'office' }, '2026-06-03') // → 'office'
locationFor({}, '2026-06-03') // → 'remote'
locationFor({ '2026-06-03': 'bogus' }, '2026-06-03') // → 'remote'
logUtilEntry(kind)
Logs a short well-known activity (break / lunch / meeting) as a new entry while keeping the active timer running. The active timer is NOT stopped so the user can resume without friction.
Parameters:
| Name | Type | Description |
|---|---|---|
kind |
'break' | 'lunch' | 'meeting' | Activity type. |
- Source:
mergeAdjacentEntries(entries, gapMsopt) → {Array.<Object>}
Merges same-task entries that are separated by no more than gapMs into a
single block, carrying the merged end time on a _end property.
Two entries merge only when they share the same task text and the same
category (tag, with a missing tag normalised to other). Category is part
of the key so that two adjacent entries with the same label but different
categories are not collapsed — otherwise the later category would be lost from
the exported billable summary, which reads tag from the merged block.
Rationale for the gap: the default 30-minute window matches the billing rounding unit — splitting a task at a gap shorter than one slot would produce two entries that each round to the same half-hour anyway, while making the summary harder to read. Input is not mutated; entries are sorted by start time first.
Parameters:
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
entries |
Array.<Object> | Entries to merge (each with |
||
gapMs |
number |
<optional> |
1800000 | Maximum gap, in ms, to bridge (default 30 min). |
- Source:
Returns:
New entry objects, each with a _end timestamp.
- Type
- Array.<Object>
mergeDevLog()
Merges the hardcoded DEV_CHANGES array into the persisted dev log in
localStorage, adding only entries whose id is not already stored.
Maintains chronological sort order by id.
- Source:
migrateEntryDatesToLocal()
Fixes entry date fields that were stored using UTC midnight instead of the
user's local calendar date.
Background: dk() previously called toISOString() (UTC). For UTC+ users
(e.g., Finland, UTC+2/+3), entries logged between local midnight and 02:00–03:00
were stored under the previous day's UTC date. This migration re-derives date
from the entry's ts timestamp using the now-correct local dk().
Safe to run multiple times — entries already on the correct local date are untouched.
- Source:
migrateStorage()
Runs all pending schema migrations. Safe to call multiple times — migrations are skipped if the source key is absent or the destination key already has data.
- Source:
mlDaysInMonth(y, m) → {number}
Returns the number of days in a given month.
Parameters:
| Name | Type | Description |
|---|---|---|
y |
number | Full year (e.g. 2026). |
m |
number | Month index, 0-based (0 = January). |
- Source:
Returns:
Day count (28–31).
- Type
- number
mlHeatColor(hours) → {string}
Maps a logged-hours value to a CSS colour for the heatmap grid. Thresholds: 0h → bg3 (empty), <2h → faint blue, <5h → mid blue, <7h → strong blue, ≥7h → solid blue.
Parameters:
| Name | Type | Description |
|---|---|---|
hours |
number | Total logged hours for a single day. |
- Source:
Returns:
A CSS colour value (variable or rgba/hex string).
- Type
- string
mlHoursForDay(dateKey) → {number}
Sums tracked milliseconds for all non-cancelled entries on a given day.
Parameters:
| Name | Type | Description |
|---|---|---|
dateKey |
string |
- Source:
Returns:
Total hours (as a float).
- Type
- number
moveTaskToColumn(taskId, newStatus)
Moves a task to a new board column, updating its status and timer state. Dropping into In Progress stops any running timer, creates a new time entry, and starts tracking. Dropping into Done or To Do stops the active timer.
Parameters:
| Name | Type | Description |
|---|---|---|
taskId |
string | The plan task ID to move. |
newStatus |
string | Target status: 'todo' | 'inprogress' | 'done'. |
- Source:
nearestWeekday(from, weekday) → {Date}
Returns the first date on or after from that falls on the given weekday.
Parameters:
| Name | Type | Description |
|---|---|---|
from |
Date | Start date (inclusive). |
weekday |
number | Day of week (0 = Sunday … 6 = Saturday). |
- Source:
Returns:
- Type
- Date
nextDistinctColor() → {string}
Returns the next visually distinct colour from the palette for a new category. Falls back to golden-angle HSL generation once all palette colours are in use.
- Source:
Returns:
A CSS colour string (hex or hsl).
- Type
- string
nextLocation(loc) → {string}
Returns the next location id when toggling, cycling through the keys of
WORK_LOCATIONS. With the two presets this flips Remote ↔ Office.
An unrecognised loc (indexOf → -1) is treated as "before the first" and
wraps to the first location, so the toggle always recovers to a valid state.
Parameters:
| Name | Type | Description |
|---|---|---|
loc |
string | Current location id. |
- Source:
Returns:
The following location id (wraps around).
- Type
- string
Example
nextLocation('remote') // → 'office'
nextLocation('office') // → 'remote'
nextLocation('bogus') // → 'remote' (unknown input recovers to the first)
notifyPomodoroEnd() → {void}
Called from pomoDone() when the Pomodoro ring reaches zero.
Fires the registered _onSprintEnd callback if one is set, then clears it
so it cannot fire twice.
- Source:
Returns:
- Type
- void
notionBtnHtml(t) → {string}
Builds the Notion send/link button HTML for a task row. Shows a link icon if already sent; send icon otherwise.
Parameters:
| Name | Type | Description |
|---|---|---|
t |
Object | The plan task. |
- Source:
Returns:
HTML button element.
- Type
- string
nthWeekday(year, month, weekday, n) → {Date}
Returns the date of the nth occurrence of a weekday in the given month.
Parameters:
| Name | Type | Description |
|---|---|---|
year |
number | Full 4-digit year. |
month |
number | Month (1 = January … 12 = December). |
weekday |
number | Day of week (0 = Sunday … 6 = Saturday). |
n |
number | 1-based occurrence index (1 = first, 2 = second, …). |
- Source:
Returns:
- Type
- Date
openBlockEmojiPicker(bid, anchor)
Opens a floating emoji picker anchored below anchor for a time block.
Identical behaviour to openEmojiPicker but operates on blocks instead
of planTasks. Calling again for the same block ID closes the picker.
Parameters:
| Name | Type | Description |
|---|---|---|
bid |
string | Block ID. |
anchor |
HTMLElement | Element to position the picker below. |
- Source:
openEmojiPicker(pid, anchor)
Opens a floating emoji picker anchored below the given element. Includes a free-text input for custom emoji and a grid of common choices. Calling again for the same task ID closes the picker.
Parameters:
| Name | Type | Description |
|---|---|---|
pid |
string | Plan task ID. |
anchor |
HTMLElement | Element to position the picker below. |
- Source:
openEodModal()
Opens the end-of-day modal: auto-exports the time log and JSON backup, saves the EOD timestamp, populates handoff notes for unfinished tasks, renders today's dev changelog entries, and lists the test areas to review.
- Source:
openExpiryModal()
Opens the iteration-expiry editor modal, pre-filling the textarea with the current expiry dates (one per line).
- Source:
openIDB() → {Promise.<IDBDatabase>}
Opens (or creates) the IndexedDB database used to persist the FSA directory handle.
- Source:
Returns:
Resolves with the opened database instance.
- Type
- Promise.<IDBDatabase>
openMigration()
Opens the migration modal and populates it with open (unresolved) tasks for the current month. Alerts if there is nothing to migrate.
- Source:
openRapid()
Opens the quick-capture overlay and focuses the search input.
- Source:
openReflection(onCompleteopt)
Opens the end-of-day reflection overlay.
Resets star ratings to 0, attaches Save/Skip handlers that call onComplete
when dismissed.
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
onComplete |
function |
<optional> |
Callback invoked after Save or Skip. |
- Source:
openSprintSetup() → {void}
Shows the sprint setup panel, clears the intention input, resets the duration selection to 25 minutes, and focuses the intention field.
- Source:
Returns:
- Type
- void
openTrackerForm() → {void}
Shows and populates the new-tracker form inside #trackerNewForm. Pre-fills the colour picker with the first category's colour. Attaches Save / Cancel / keyboard listeners.
- Source:
Returns:
- Type
- void
parseRapidTokens(raw, cats, nowopt) → {Object}
Parses inline shorthand tokens from a raw quick-capture input string and returns a clean text plus structured token values.
Supported tokens (each stripped from the returned text):
#<cat>— Category: matched against category ids and labels (case-insensitive; prefix match as fallback). Last occurrence wins.!<sig>— Signifier shortcode (see RAPID_SIG_SHORTCUTS). Last occurrence wins.><date>— Date pointer: today, tomorrow, YYYY-MM-DD, or weekday mon–sun (next occurrence). Last occurrence wins.
Unrecognised tokens are left in the text unchanged so the user sees them and can correct them without data being silently discarded.
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
raw |
string | Raw input text that may contain inline shorthand tokens. |
|
cats |
Array.<{id: string, label: string}> | Available categories for |
|
now |
Date |
<optional> |
Reference date for relative date resolution; defaults to new Date(). |
- Source:
Returns:
- Type
- Object
partitionSessionNotes(allItems) → {Object}
Partitions a flat item list from buildDailyLogItems into two structures:
non-session-note items (the main timeline rows) and a lookup of session-note
items keyed by their parentEntryId. Session-notes render nested inside
their parent entry row rather than as standalone timeline entries.
Parameters:
| Name | Type | Description |
|---|---|---|
allItems |
Array.<object> | Items returned by buildDailyLogItems. |
- Source:
Returns:
- Type
- Object
patchCarriedTasks()
Applies data migrations and status patches to today's plan tasks after carry-over:
- Stamps
billable: trueon tasks/categories that predate the feature. - Stamps
completedAton done tasks missing a timestamp. - Promotes today's task status to match the most recent past version when that version was pending/blocked/upcoming or in-progress.
- Source:
pausePomo()
Pauses the pomodoro timer without resetting the remaining time.
- Source:
pauseTimer()
Pauses the running timer, accumulating elapsed time so it can be resumed. No-ops if no timer is active or it is already paused.
- Source:
(async) pickSaveFolder() → {Promise.<void>}
Prompts the user to select a save folder via the File System Access API and persists the resulting directory handle. Shows a fallback alert in browsers that do not support the API.
- Source:
Returns:
- Type
- Promise.<void>
playChime()
Plays two soft sine-wave tones (528 Hz then 660 Hz) using the Web Audio API to signal an elapsed-time milestone. Silently skips if Web Audio is unavailable (e.g. browser privacy settings).
- Source:
playPomoBeep()
Plays three short 660 Hz beeps spaced 350 ms apart using the Web Audio API to signal pomodoro completion. Silently skips if Web Audio is unavailable.
- Source:
pomoAddTime()
Adds 120 seconds to the current running session without resetting segments. No-op if the timer is not running.
- Source:
pomoAffirmation(totalopt, leftopt) → {string}
Returns a progress-aware affirmation string based on elapsed time. Default parameters let callers pass explicit values (useful for testing).
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
total |
number |
<optional> |
Total session seconds; defaults to pomoTotal. |
left |
number |
<optional> |
Remaining seconds; defaults to pomoLeft. |
- Source:
Returns:
Short motivational phrase.
- Type
- string
pomoBuildDateRange() → {Array.<string>}
Builds an array of POMO_SPARKLINE_DAYS date strings ending today, oldest first.
- Source:
Returns:
Array of YYYY-MM-DD strings.
- Type
- Array.<string>
pomoDone()
Called when the pomodoro timer reaches zero. Plays the completion beep, briefly animates the time display, and appends a session record to the pomodoro log in localStorage.
- Source:
pomoGap(n) → {number}
Returns the angular gap (in radians) between pomodoro timer segments. Smaller gaps are used for higher segment counts to keep them visually distinct.
Parameters:
| Name | Type | Description |
|---|---|---|
n |
number | Number of segments (minutes). |
- Source:
Returns:
Gap in radians.
- Type
- number
pomoGetLog() → {Array.<{ts: number, mins: number, task: (string|null)}>}
Reads and validates the pomodoro session log from localStorage. Invalid records are dropped and reported via wlLog.warn.
- Source:
Returns:
Session log entries.
- Type
- Array.<{ts: number, mins: number, task: (string|null)}>
pomoSessionsOnDate(log, dateKey) → {number}
Returns the number of completed pomodoro sessions on the given date.
Parameters:
| Name | Type | Description |
|---|---|---|
log |
Array.<PomoSessionEntry> | Session log. |
dateKey |
string | Date in YYYY-MM-DD format. |
- Source:
Returns:
- Type
- number
pomoSparkColours() → {Object}
Reads the --pomo-spark-fill and --pomo-spark-empty CSS variables for the active colour scheme. Falls back to hardcoded values when CSS vars are unavailable (e.g. headless test environments).
- Source:
Returns:
- Type
- Object
pomoTapOut()
Ends the session early, logs a partial session, and transitions to done state. Records the elapsed minutes (minimum 1) so the session appears in the log.
- Source:
positionNowLine()
Positions the "now" indicator line in the time-block grid to reflect the
current time. Hides the line when outside the grid's time range
(TB_START–TB_END).
- Source:
prioBtnHtml(t) → {string}
Builds the priority toggle button HTML for a task row. Click cycles: normal (0) → high (1) → low (-1) → normal.
Parameters:
| Name | Type | Description |
|---|---|---|
t |
Object | The plan task. |
- Source:
Returns:
HTML button element.
- Type
- string
readCollapseState(sectionId, defaultCollapsed) → {boolean}
Reads the stored collapsed state for a section from localStorage.
Parameters:
| Name | Type | Description |
|---|---|---|
sectionId |
string | The section element's |
defaultCollapsed |
boolean | Value to use when nothing is stored. |
- Source:
Returns:
Whether the section should be collapsed.
- Type
- boolean
readOptionalLogForBackup(storeKey, label) → {Array}
Reads and parses an optional JSON-array log from localStorage for inclusion in a backup. If the stored value is present but not valid JSON, the failure is logged via wlLog (so the data loss is diagnosable rather than silent) and an empty array is returned so the rest of the backup still succeeds. Absent keys legitimately yield an empty array.
Parameters:
| Name | Type | Description |
|---|---|---|
storeKey |
string | The localStorage key to read. |
label |
string | Human-readable log name for the warning message. |
- Source:
Returns:
The parsed array, or [] if absent or unparseable.
- Type
- Array
refreshPomoDashboard()
Full Pomodoro dashboard refresh: redraws the 28-day sparkline, ribbon footer, and composer task label. Called on module load and after every session completion.
- Source:
render()
Full application re-render: updates the date label, timer bar, stat counters, sub-stats, time-log list, chart, quick-pick, plan, completed section, and time-block view. Call whenever persistent state changes.
Design trade-off: full DOM re-render on every change rather than targeted
updates. Keeps state reasoning simple for a single-user personal tool where
the entry list is small (typically < 50 items per day). If performance becomes
a concern, the innermost timelineEl.querySelectorAll event-binding loop is the first
candidate for optimisation (see phase 6 below).
- Source:
renderBoardDoneHistory(doneListEl, viewKey)
Appends the collapsible "older history" expander to the Done column list. Shows completed tasks from prior dates, grouped by day, within the active iteration.
Parameters:
| Name | Type | Description |
|---|---|---|
doneListEl |
HTMLElement | The |
viewKey |
string | The current view date key (YYYY-MM-DD). |
- Source:
renderCalStrip(meetings)
Renders the calendar meetings strip for today. Sorts meetings by start time, marks past meetings grey/italic, pulses ongoing meetings, and provides ▶ start and ✕ hide buttons per meeting.
Parameters:
| Name | Type | Description |
|---|---|---|
meetings |
Array.<Object> | Array of meeting objects from the PS server. |
- Source:
renderChart(list)
Renders the time-tracking bar chart for the currently viewed day.
Decorates the active timer's entry with a synthetic tsEnd so live time
appears in real-time. Respects chartMode ('task' | 'category').
Parameters:
| Name | Type | Description |
|---|---|---|
list |
Array.<Object> | The array of log entries to chart. |
- Source:
renderCompleted()
Renders the completed-tasks section for the currently viewed date. Shows tasks that were completed on or before the view date and whose iteration expiry date has not yet passed. Deduplicates by task text, keeping only the most recently completed version. Hides the section when there are no matching tasks.
- Source:
renderDayStrip(dateKey)
Renders the compact day-overview strip: hour-tick labels, entry footprints, and (today only) a live "now" cursor.
Parameters:
| Name | Type | Description |
|---|---|---|
dateKey |
string | YYYY-MM-DD. |
- Source:
renderEmergencyCps()
Renders the checkpoint list inside the focus-mode overlay for the currently active task. Hides the wrapper if the task has no checkpoints. Each checkpoint cycles through three states on click: false → 'partial' → true.
- Source:
renderEodBtn()
Updates the "end the day" button to show the end time recorded for the day in view (if any) or its default label, and dims the button once a time is set.
- Source:
renderFlagDay()
No longer actively used — fetchCalendarEvents handles flag-day display.
Kept as a no-op stub so call sites don't need to be removed.
- Source:
renderFlowHeader(dateKey, activeView)
Renders the section header: icon, title, tracked/billable totals, and the Flow / Log / Blocks segmented control.
Parameters:
| Name | Type | Description |
|---|---|---|
dateKey |
string | |
activeView |
'flow' | 'log' | 'blocks' |
- Source:
renderFlowView(dateKey)
Renders the Flow view: a vertical list where each entry's accent strip height is proportional to its duration (height = max(64, 0.6 × minutes) px), giving longer tasks more visual weight.
Parameters:
| Name | Type | Description |
|---|---|---|
dateKey |
string |
- Source:
renderFolderStatus()
Updates the #folderStatus element to show the currently selected save
folder name (green) or a "pick save folder" prompt (default colour).
- Source:
renderGapReminder(dateKey)
Renders or hides the gap-reminder banner.
Parameters:
| Name | Type | Description |
|---|---|---|
dateKey |
string |
- Source:
renderHeroCard()
Switches the root card's state-modifier class and makes the matching inner panel visible. Updates all dynamic content for the current state.
- Source:
renderLocation() → {void}
Updates the date-nav location button to reflect the viewed day's location. No-ops when the button is absent (e.g. in a reduced test DOM).
- Source:
Returns:
- Type
- void
renderMigrationStep()
Renders the current migration step (or the "done" screen when all resolved).
- Source:
renderMonthlyCalendar(calEl, year, month) → {void}
Renders the heatmap calendar grid: navigation header, day labels, day cells,
and the colour legend. Binds cell-click (navigate to that day) and prev/next
month buttons. Writes its full HTML to calEl.
Implicit dependency: the prev/next handlers mutate module-level _mlYear /
_mlMonth and then call renderMonthlyLog() to re-render the whole view.
Both globals must therefore be in scope when this function is called.
Parameters:
| Name | Type | Description |
|---|---|---|
calEl |
HTMLElement | The |
year |
number | Full year to render. |
month |
number | Month index, 0-based. |
- Source:
- See:
Returns:
- Type
- void
renderMonthlyLog() → {void}
Orchestrates the Monthly Log view: resolves DOM targets and delegates each panel to a single-purpose renderer.
- Source:
Returns:
- Type
- void
renderMonthlySummary(sumEl, monthPrefix) → {void}
Renders the time-totals summary panel: total logged, billable, top category.
Writes its full HTML to sumEl. No event binding. Early-returns if sumEl
is absent so a partial DOM doesn't throw on innerHTML assignment.
Parameters:
| Name | Type | Description |
|---|---|---|
sumEl |
HTMLElement | The |
monthPrefix |
string | Date prefix |
- Source:
Returns:
- Type
- void
renderMonthlyTasks(taskEl, monthPrefix) → {void}
Renders the task-inventory panel: open / done / migrated counts plus
a "Run Migration" button. Writes its full HTML to taskEl and binds
the button to openMigration() if that helper is loaded. Early-returns
if taskEl is absent so a partial DOM doesn't throw on innerHTML.
Parameters:
| Name | Type | Description |
|---|---|---|
taskEl |
HTMLElement | The |
monthPrefix |
string | Date prefix |
- Source:
Returns:
- Type
- void
renderMoon()
Renders today's moon phase, illumination, and zodiac sign into #liveMoon.
No-ops if the element is absent.
- Source:
renderPlan()
Re-renders the entire plan UI as a 3-column kanban board (To Do / In Progress / Done). Pending and blocked tasks absorb into the To Do column with their existing badge treatment. The Done column shows today's completed tasks and a collapsible history expander for older ones.
Design trade-off: full DOM re-render on every state change rather than targeted updates. Acceptable for a personal tool where the task list is small (< 20 items).
- Source:
renderPomoLog()
Renders the pomodoro session history list inside #pomoLog.
Shows date/time, duration, and the task that was active during each session.
- Source:
renderPomoRibbon()
Renders the ribbon footer below the 4-column grid:
#pomoRibbonDots: last-5-session dot sequence (● filled, · empty slot)#pomoRibbonPill: "Peak Focus" pill when today matches the all-time high, otherwise "N sessions today", hidden when no sessions today#pomoRibbonLink: "View all N sessions ↓" button that scrolls#pomoLog
Each element is individually guarded — no-op when absent from the DOM.
- Source:
renderPomoSparkline()
Draws a 28-day focus density bar chart on the #pomoSparkline canvas.
Each bar represents one calendar day; bar height is proportional to the
number of completed pomodoro sessions on that day.
No-op when the canvas element is absent or the 2D context is unavailable.
- Source:
renderQuickPick()
Renders the "recent tasks" quick-pick bar below the capture input. Deduplicates entries by text, hides manually-dismissed tasks and tasks past their iteration expiry, and caps the list at 16 items.
- Source:
renderReflStars(elId, current)
Renders a 1–5 star row inside elId, marking stars up to current as active.
Parameters:
| Name | Type | Description |
|---|---|---|
elId |
string | ID of the container element. |
current |
number | Currently selected value (0 = none selected). |
- Source:
renderRow(t) → {string}
Builds the HTML string for a single plan task row. Handles two layout branches: pending/blocked (compact) and normal (full). Reads module-level state variables for edit mode, checkpoint open state, and pending comment state so re-renders are always consistent.
Parameters:
| Name | Type | Description |
|---|---|---|
t |
Object | The plan task object to render. |
- Source:
Returns:
HTML string for one .plan-item element (and optional split row).
- Type
- string
renderSodBtn() → {void}
Updates the session chip to show the start time recorded for the day in view (with a green dot), or the default "start the day" label when that day has no recorded start. The button's text content is its accessible name; no static aria-label is used so screen readers announce the current state ("started HH:MM" or "start the day").
- Source:
Returns:
- Type
- void
renderSprintDurations() → {void}
Renders the duration chip row inside #sprintDurations, marking the currently selected duration active. Attaches click listeners to each chip.
- Source:
Returns:
- Type
- void
renderTimeblock()
Renders the full time-block grid for the currently viewed date: time labels, grid rows, planned blocks (with drag-to-move), live timer block, a "now" line, and the plan-task drag targets. Also handles drag-and-drop wiring for moving existing blocks and dropping tasks from the plan list.
- Source:
renderTodayFlow()
Renders the Today's Flow section: header, day-overview strip, gap reminder, and the active view pane (Flow / Log / Blocks / Month). Called from render() on every state change and when the view toggle fires.
- Source:
renderTrackRecent()
Renders the "+ TRACK RECENT" strip inside #planTrackRecent.
Shows chips for the most recent unique time-log entries from today so the
user can restart a timer with a single click without re-typing.
Limits to 5 entries; hidden when no entries exist for today.
- Source:
renderTrackers() → {void}
Renders all tracker cards into #trackerList. Each card shows a 28-day hit/partial/miss grid, current streak, and total hit count. Attaches delete-button listeners after render.
- Source:
Returns:
- Type
- void
resetPomo()
Resets the pomodoro timer to the full configured duration without starting it.
- Source:
resolveCarryStatus(todayTask, prev) → {string|null}
Determines the carry-forward status a today-task should adopt based on its most recent past peer, implementing the following rules:
pendingorblockedprev overridestodoorinprogresstoday — the task is still blocked so the blocking state wins.upcomingprev overrides only atodotoday — a todo placeholder created from an even-older copy should reflect the more recent intent to defer. It must NOT overrideinprogress, because the user explicitly started the task and a reload must not undo that.inprogressprev promotes atodotoday — the task was already being worked on and the carry placeholder should show that.
Returns null when no change is needed.
Parameters:
| Name | Type | Description |
|---|---|---|
todayTask |
Object | Today's task object. |
prev |
Object | Most recent past task with the same text (case-insensitive). |
- Source:
Returns:
The new status to apply, or null for no change.
- Type
- string | null
Example
resolveCarryStatus({ status: 'todo' }, { status: 'upcoming' }) // → 'upcoming'
resolveCarryStatus({ status: 'inprogress' }, { status: 'upcoming' }) // → null
resolveCarryStatus({ status: 'todo' }, { status: 'pending' }) // → 'pending'
resolveRapidDate(token, nowopt) → {string|null}
Resolves a >date shorthand token to a YYYY-MM-DD date key.
Supported tokens: 'today', 'tomorrow', exact 'YYYY-MM-DD', and weekday abbreviations
'mon'–'sun' (resolves to the next occurrence, never today).
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
token |
string | Raw date token (without the leading |
|
now |
Date |
<optional> |
Reference date for relative resolution; defaults to new Date(). |
- Source:
Returns:
Resolved date key, or null if the token is unrecognised.
- Type
- string | null
resumeTimer()
Resumes a paused timer from where it left off. No-ops if no timer is active or it is not paused.
- Source:
resumeTimerIfActive()
Called at startup to reconnect the tick interval when the app is reloaded with an active timer persisted in localStorage. If the entry the timer was tracking no longer exists the timer is cleared. No-ops if no timer is active.
- Source:
roundToNearest30(ts) → {number}
Rounds a timestamp to the nearest 30-minute clock mark.
Tie-breaking rule (at exactly 15 min into a 30-min slot): rounds DOWN. Rationale: conservative for billing — a task must exceed the midpoint of the slot before the next slot is claimed.
Assumption: rounding ties (exactly 15 min past a slot start) are resolved in favour of the earlier slot to avoid inflating billable time. This matches the intent documented in DATA.md under wl_entries.ts.
Parameters:
| Name | Type | Description |
|---|---|---|
ts |
number | Unix timestamp in milliseconds. |
- Source:
Returns:
Rounded Unix timestamp in milliseconds.
- Type
- number
roundToNearest30IfBillable(ts, entry) → {number}
Rounds ts to the nearest 30-minute mark only when entry is billable.
Non-billable entries keep their exact timestamps for accurate reporting.
Parameters:
| Name | Type | Description |
|---|---|---|
ts |
number | Unix timestamp in milliseconds. |
entry |
object | null | Work-log entry; if null, always rounds. |
- Source:
Returns:
Timestamp, conditionally rounded.
- Type
- number
roundUp30(ms) → {number}
Rounds a duration up to the nearest 30-minute slot, with a minimum of 30 min. Used for billing time estimates — even a 1-second task costs one half-hour slot.
Assumption: billing granularity is 30 minutes and the minimum billable unit is 30 minutes. Changing this assumption requires updating both this function and any UI that displays billable totals (e.g. the billable-time section in exports).
Parameters:
| Name | Type | Description |
|---|---|---|
ms |
number | Duration in milliseconds. |
- Source:
Returns:
Duration rounded up to nearest 30-min slot, in milliseconds.
- Type
- number
Example
roundUp30(0) // → 1_800_000 (30 min — minimum)
roundUp30(1) // → 1_800_000 (1 ms still costs one slot)
roundUp30(30 * 60 * 1000) // → 1_800_000 (exactly 30 min stays at 30 min)
roundUp30(30 * 60 * 1000 + 1) // → 3_600_000 (30 min + 1 ms rounds up to 60 min)
safeCssColor(c) → {string}
Returns c if it is a safe CSS colour (hex or hsl()), otherwise returns a neutral fallback.
Prevents malformed user-supplied colour values from breaking layout or injecting CSS.
Parameters:
| Name | Type | Description |
|---|---|---|
c |
string | CSS colour string to validate. |
- Source:
Returns:
A safe CSS colour string.
- Type
- string
Example
safeCssColor('#7B61FF') // → '#7B61FF'
safeCssColor('hsl(200,60%,50%)') // → 'hsl(200,60%,50%)'
safeCssColor('red') // → '#888780' (name blocked)
safeCssColor('') // → '#888780'
safeRoundedStart() → {number}
Returns a rounded start timestamp that does not overlap any existing entry for today. Prevents new entries from appearing to start before a prior entry's end time.
- Source:
Returns:
Unix timestamp in milliseconds.
- Type
- number
save()
Persists entries, active timer, and categories to localStorage. Refuses to overwrite existing non-empty data with an empty array to guard against accidental data loss if save() is called before load() completes.
Assumption: an empty entries array in memory while localStorage still holds
data means save() was called before load() finished (e.g. a race during init),
not that the user intentionally deleted everything. Intentional clearing goes
through a dedicated wipe path that bypasses this guard.
- Source:
saveBlocks()
Persists the current blocks array to localStorage.
- Source:
saveEodHandoffNotes()
Reads all handoff-note inputs in the EOD modal and persists their values to
the wl_handoff localStorage key. Empty values are removed from the map.
- Source:
saveExpiryDates()
Reads the expiry-date textarea, validates each line against YYYY-MM-DD format, deduplicates and sorts the valid dates, persists them to localStorage, and closes the modal. Invalid lines are surfaced in the feedback element but not saved.
- Source:
saveHandoffNote(entryText, note)
Persists a handoff note for a given entry text. Pass an empty string or falsy value to delete the stored note. The key is stored case-insensitively.
Parameters:
| Name | Type | Description |
|---|---|---|
entryText |
string | The entry text to associate the note with. |
note |
string | The note to save; falsy removes the stored note. |
- Source:
saveLocationMap(map) → {void}
Persists the location map to localStorage.
Parameters:
| Name | Type | Description |
|---|---|---|
map |
Record.<string, string> | Date-key → location-id map. |
- Source:
Returns:
- Type
- void
saveMigrationRecord(rec)
Persists the migration completion record to localStorage.
Parameters:
| Name | Type | Description |
|---|---|---|
rec |
Object | Map of YYYY-MM → boolean. |
- Source:
savePlan() → {void}
Persists the current planTasks array to localStorage.
- Source:
Returns:
- Type
- void
saveReflection()
Persists the current _reflData map to localStorage.
- Source:
saveSnapshot()
Writes a recoverable snapshot of today's log entries to localStorage every 30 minutes. The snapshot contains both a human-readable plaintext summary and the raw entry/category arrays so data can be recovered after accidental clearing. No-ops when there are no entries for today.
Assumption: 30 minutes is an acceptable data-loss window for a personal work log used in a single browser tab. Browser crashes, accidental page reloads, and mis-clicks on "clear data" are the main risks; all are adequately covered by a 30-minute recovery point. If higher durability is needed, reduce the interval in the setInterval call in 07-lifecycle.js.
- Source:
saveSprintLog() → {void}
Persists the current sprintLog array to localStorage.
- Source:
Returns:
- Type
- void
saveTaskNotionUrl(taskId, url)
Persists the Notion page URL on a plan task so the per-task button changes to an "open in Notion" link on next render.
Parameters:
| Name | Type | Description |
|---|---|---|
taskId |
string | Plan task ID. |
url |
string | Notion page URL returned by the API. |
- Source:
saveTrackerForm() → {void}
Reads the new-tracker form, validates inputs, pushes the tracker to the
trackers array, persists it, and re-renders. Shows an alert if no category
is selected; focuses the name field if the name is empty.
- Source:
Returns:
- Type
- void
saveTrackers() → {void}
Persists the current trackers array to localStorage.
- Source:
Returns:
- Type
- void
scheduleMigTask(task, dateStr)
Reschedules the task to the given date and marks it as migrated.
Parameters:
| Name | Type | Description |
|---|---|---|
task |
Object | |
dateStr |
string | YYYY-MM-DD |
- Source:
sectorPath(cx, cy, r, a1, a2) → {string}
Builds an SVG path string for a pie-chart sector (filled segment).
Parameters:
| Name | Type | Description |
|---|---|---|
cx |
number | Centre x coordinate. |
cy |
number | Centre y coordinate. |
r |
number | Radius. |
a1 |
number | Start angle in radians (0 = 12 o'clock). |
a2 |
number | End angle in radians. |
- Source:
Returns:
SVG path d attribute value.
- Type
- string
setBlockEmoji(bid, emoji)
Saves an emoji to a time block and closes the picker. Pass null or an empty string to remove the block's emoji.
Parameters:
| Name | Type | Description |
|---|---|---|
bid |
string | Block ID. |
emoji |
string | null | Emoji character to assign, or null to remove. |
- Source:
setFavicon(state)
Updates the browser favicon to a coloured dot reflecting the timer state. Skips redundant redraws by tracking the last rendered state.
Parameters:
| Name | Type | Description |
|---|---|---|
state |
'active' | 'paused' | 'hyperfocus' | 'idle' | Current timer state. |
- Source:
setFlowView(view)
Persists the active view selection.
Parameters:
| Name | Type | Description |
|---|---|---|
view |
'flow' | 'log' | 'blocks' |
- Source:
setPomoFavicon()
Redraws the browser favicon as a depleting wedge mirroring the remaining pomodoro time. Silently skips when the canvas API is unavailable.
- Source:
setSeenEnded(s)
Persists the set of seen-ended meeting keys to localStorage.
Parameters:
| Name | Type | Description |
|---|---|---|
s |
Set.<string> | Updated set to persist. |
- Source:
setTaskEmoji(pid, emoji)
Saves an emoji to a plan task and closes the picker. Pass null or an empty string to remove the task's emoji.
Parameters:
| Name | Type | Description |
|---|---|---|
pid |
string | Plan task ID. |
emoji |
string | null | Emoji character to assign, or null to remove. |
- Source:
showBridgeBanner(meeting)
Shows the post-meeting bridge banner for the given meeting. Queues the meeting if another banner is already visible.
Parameters:
| Name | Type | Description |
|---|---|---|
meeting |
Object | The ended meeting. |
- Source:
showHandoffInput()
Shows the handoff-note text field in the timer bar so the user can record what a future self (or colleague) should know before picking this task up again.
- Source:
showSprintReview() → {void}
Stops the main timer and renders the sprint review panel inside #sprintReview.
Populates the intention label, wires outcome buttons (yes / partly / no),
and on save: appends the sprint to sprintLog, tags the entry with the
outcome, persists both, hides the panel, and triggers a full render.
- Source:
Returns:
- Type
- void
sigHtml(entry) → {string}
Returns the HTML string for the clickable signifier widget on one entry row.
Parameters:
| Name | Type | Description |
|---|---|---|
entry |
Object | Log entry object. |
- Source:
Returns:
HTML string for a <span> button.
- Type
- string
sigSymbol(entry) → {string}
Returns the display symbol for an entry's signifier.
Parameters:
| Name | Type | Description |
|---|---|---|
entry |
Object | Log entry object. |
- Source:
Returns:
Unicode BuJo symbol (○ ★ → ✗ !) or '●' for the billable default.
- Type
- string
sigTitle(entry) → {string}
Returns the accessible title string for an entry's signifier.
Parameters:
| Name | Type | Description |
|---|---|---|
entry |
Object | Log entry object. |
- Source:
Returns:
- Type
- string
slotToTime(slot) → {string}
Converts a 0-based half-hour slot index to an "HH:MM" label.
Slot 0 = TB_START:00, slot 2 = TB_START+1:00, etc.
Parameters:
| Name | Type | Description |
|---|---|---|
slot |
number | 0-based slot index. |
- Source:
Returns:
"HH:MM" formatted time string.
- Type
- string
sodKey(dayopt) → {string}
Returns the localStorage key for a given day's start-of-day timestamp.
Parameters:
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
day |
Date |
<optional> |
viewDate | Day to key by; defaults to the day in view so the session chip reflects whichever day the user has navigated to. |
- Source:
Returns:
Key in the format wl_sod_YYYY-MM-DD.
- Type
- string
startPomo()
Starts the pomodoro countdown. Resets to full duration if already at zero. Fires pomoDone and clears the interval when time runs out.
- Source:
startSprint() → {void}
Commits a new sprint: reads the intention from the input, creates a time-log
entry, starts the main timer, starts the Pomodoro for _sprintDuration
minutes, and sets _onSprintEnd so the review panel is shown when the ring
reaches zero. No-ops with a focus call if the intention field is empty.
- Source:
Returns:
- Type
- void
startTimer(entryId)
Starts (or restarts) the timer for the given entry. Clears any existing interval, resets the chime state, and begins a 1-second tick. Persists state and updates the UI immediately.
Parameters:
| Name | Type | Description |
|---|---|---|
entryId |
string | ID of the log entry to time. |
- Source:
statusOpts(cur) → {string}
Builds the
Parameters:
| Name | Type | Description |
|---|---|---|
cur |
string | The task's current status value. |
- Source:
Returns:
HTML option elements.
- Type
- string
stopTimer()
Stops the active timer, stamps the log entry with an end time (rounded to
the nearest 30 min for billable entries), clears activeTimer, and
triggers a full render. Resets the timer bar colour and closes the park
capture input if open. No-ops if no timer is active.
- Source:
(async) storeDirHandle(handle) → {Promise.<void>}
Persists a File System Access directory handle to IndexedDB for reuse across sessions, and updates the in-memory cache.
Parameters:
| Name | Type | Description |
|---|---|---|
handle |
FileSystemDirectoryHandle | The directory handle to store. |
- Source:
Returns:
- Type
- Promise.<void>
stripJiraPrefix(text) → {string}
Removes a leading Jira issue key (e.g. ABC-123: or ABC-123 ) from a task
label, leaving the human-readable summary. Used when building the pasteable
billable summary so issue keys do not clutter the client-facing line.
Parameters:
| Name | Type | Description |
|---|---|---|
text |
string | The raw task label. |
- Source:
Returns:
The label with any leading Jira key stripped and trimmed.
- Type
- string
Example
stripJiraPrefix('PROJ-42: Fix login') // → 'Fix login'
stripJiraPrefix('Write tests') // → 'Write tests'
stripPct(mins) → {number}
Converts a minutes-from-midnight value to a percentage across the strip range. Clamped to [0, 100].
Parameters:
| Name | Type | Description |
|---|---|---|
mins |
number |
- Source:
Returns:
- Type
- number
tbOverlaps(newStartMins, newEndMins, dateKey, excludeIdopt) → {string}
Returns a comma-separated string of task names that overlap a proposed time range, checking both planned blocks and logged time entries. Returns an empty string if there are no overlaps.
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
newStartMins |
number | Proposed start time in minutes from midnight. |
|
newEndMins |
number | Proposed end time in minutes from midnight. |
|
dateKey |
string | Date string in YYYY-MM-DD format. |
|
excludeId |
string |
<optional> |
Block ID to exclude from the check (when moving). |
- Source:
Returns:
Overlapping task names, or '' if none.
- Type
- string
tbStartBlock(blockId, overrideTsopt)
Starts a timer for the given time block: creates (or promotes) the matching
plan task to "in progress", stops any running timer, creates a new log entry,
and starts the tick interval. Uses overrideTs as the entry start time so
elapsed time is counted from the scheduled start, not wall-clock now.
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
blockId |
string | ID of the time block to start. |
|
overrideTs |
number |
<optional> |
Optional explicit start timestamp (ms). Defaults to |
- Source:
tickClock()
Updates the live clock display (date, time, ISO week), the time-block "now" line, and block notifications. Also detects midnight rollover: carries unfinished plan tasks to the new day and re-renders the UI.
- Source:
tickTimer()
Called every second by the timer interval. Updates the timer bar text, the live time-block element, the tab title/favicon, the bar colour, and checks whether a chime should fire. Also refreshes the focus-mode overlay when it is open. Errors are caught and logged so a single bad tick cannot stop the interval.
- Source:
timeToSlot(hhmm, m2opt) → {number}
Converts a time value to a 0-based slot index relative to TB_START.
Accepts either an "HH:MM" string or two separate (hours, minutes) arguments.
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
hhmm |
string | number | "HH:MM" string, or hours when |
|
m2 |
number |
<optional> |
Minutes (only when |
- Source:
Returns:
0-based slot index.
- Type
- number
toTimeInput(ts) → {string}
Converts a Unix timestamp (ms) to an HH:MM string suitable for an
<input type="time"> value.
Parameters:
| Name | Type | Description |
|---|---|---|
ts |
number | Unix timestamp in milliseconds. |
- Source:
Returns:
Local time formatted as "HH:MM".
- Type
- string
toggleViewLocation() → {void}
Toggles the currently viewed day to the next location (Remote ↔ Office), persists it, logs the decision, and re-renders the header button.
- Source:
Returns:
- Type
- void
totalISOWeeks(year) → {number}
Returns the total number of ISO weeks in a given year (52 or 53). Uses the fact that Dec 28 is always in the last ISO week.
Parameters:
| Name | Type | Description |
|---|---|---|
year |
number | The full 4-digit year. |
- Source:
Returns:
52 or 53.
- Type
- number
trackerDayStatus(tracker, dateKey) → {'hit'|'partial'|'miss'}
Returns 'hit' | 'partial' | 'miss' for a given tracker on a given day.
Parameters:
| Name | Type | Description |
|---|---|---|
tracker |
Object | Tracker object with tags and targetMinutes. |
dateKey |
string | YYYY-MM-DD date key. |
- Source:
Returns:
- Type
- 'hit' | 'partial' | 'miss'
trackerStreak(tracker) → {number}
Calculates the current consecutive "hit" streak for a tracker, ending today. Walks backwards day-by-day (up to 60 days) and stops at the first non-hit day.
Parameters:
| Name | Type | Description |
|---|---|---|
tracker |
Object | Tracker object with |
- Source:
Returns:
Number of consecutive hit days ending today.
- Type
- number
triggerPortableDeploy()
Fire-and-forget portable deploy: calls POST /api/portable-deploy to trigger
the PowerShell build script, then displays a transient top-right toast with the
result (success, failure, or server unreachable). Never throws.
- Source:
tsToMins(ts) → {number}
Converts a Unix timestamp (ms) to minutes-from-midnight in local time.
Parameters:
| Name | Type | Description |
|---|---|---|
ts |
number |
- Source:
Returns:
- Type
- number
updateHeaderTracking()
No-op: the header tracked-total and pace bar were removed in the top-zone redesign (ITEM 1). Kept so tickClock() and tickTimer() call sites remain unchanged.
- Source:
updateLiveBlock()
Updates the live time-block element in the time-block view to reflect the current elapsed time of the active timer. No-ops if the live block element or the active timer's entry cannot be found.
- Source:
updatePomoDisplay()
Refreshes the pomodoro timer display: updates the countdown text, redraws segments, sets the state-modifier class on the pomo-body, and updates button labels and status text to reflect the current state.
- Source:
updatePomoTaskLabel()
Updates #pomoTaskLabel (composer column) with the text of the currently
running timer entry. Clears the label when no timer is active.
- Source:
updateTabAndFavicon()
Synchronises the browser tab title and favicon with the current timer state. Adds a ▶/⏸/🔴 prefix and shows the elapsed time and task name in the title. Switches to hyperfocus state (red) after HYPERFOCUS_MINS minutes for non-meeting tasks.
- Source:
updateTimerArc(elapsedMs)
Updates the SVG arc on the timer circle to reflect elapsed time relative to the hyperfocus threshold. The arc fills 0→100% of the circle circumference (2πr ≈ 150.8 px for r=24) as elapsed time goes from 0 to HYPERFOCUS_MINS.
Parameters:
| Name | Type | Description |
|---|---|---|
elapsedMs |
number | Elapsed time in milliseconds. |
- Source:
updateTimerBar()
Shows or hides the timer bar and updates the pause/resume button label. Also enables or disables the "make it interesting" hook button.
- Source:
updateTimerBarColor()
No-op: #timerBar was replaced by the Hero Card whose colour is driven by
CSS state-modifier classes (hero-card--running, --paused, etc.).
Kept so existing call-sites in tickTimer compile without changes.
- Source:
updateTimerBtn(running)
Updates the main start-timer button's label and disabled state.
Parameters:
| Name | Type | Description |
|---|---|---|
running |
boolean | True if a timer is currently active. |
- Source:
validBlock(b) → {boolean}
Returns true if b is a well-formed timeblock record.
Parameters:
| Name | Type | Description |
|---|---|---|
b |
* | Candidate value parsed from JSON. |
- Source:
Returns:
True if the timeblock is well-formed.
- Type
- boolean
validCalendarMeeting(meeting) → {boolean}
Returns true if meeting is a well-formed Outlook calendar event object
as returned by the PowerShell /api/calendar endpoint.
Required fields: subject (string), start (string), end (string).
Optional fields (joinUrl, account) are not validated here — their
absence is handled gracefully by renderCalStrip.
Parameters:
| Name | Type | Description |
|---|---|---|
meeting |
* | Candidate meeting object from the calendar API response. |
- Source:
Returns:
True if the meeting object is well-formed.
- Type
- boolean
Example
validCalendarMeeting({ subject: 'Standup', start: '2026-05-28T09:00', end: '2026-05-28T09:30' })
// → true
validCalendarMeeting(null) // → false
validCalendarMeeting({ subject: 'x' }) // → false (missing start/end)
validCalendarMeeting({ subject: 42, start: '2026-05-28T09:00', end: '2026-05-28T09:30' })
// → false (subject not a string)
validCategory(c) → {boolean}
Returns true if c is a well-formed category object.
Parameters:
| Name | Type | Description |
|---|---|---|
c |
* | Candidate value parsed from JSON. |
- Source:
Returns:
True if the category is well-formed.
- Type
- boolean
validEntry(e) → {boolean}
Returns true if e is a well-formed work-log entry safe to load from localStorage.
Parameters:
| Name | Type | Description |
|---|---|---|
e |
* | Candidate value parsed from JSON. |
- Source:
Returns:
True if the entry is well-formed.
- Type
- boolean
Example
validEntry({ id: '1', text: 'Write report', ts: 1234567890, date: '2026-05-25' }) // → true
validEntry(null) // → false
validEntry({ id: 1, text: 'x', ts: 0, date: '2026-05-25' }) // → false (numeric id)
validEntry({ id: '1', text: 'x', ts: 0, date: '25-05-2026' }) // → false (wrong date format)
validJiraCsvRow(row) → {boolean}
Returns true if row — a single object produced by parseCSV() — contains
at least the key and summary columns that jiraParseAndRender() expects.
The Jira CSV export uses several possible column names for the same field
(matching the lenient lookup in jiraParseAndRender):
- Key column:
Issue key,Key, orIssue Key - Summary column:
Summaryorsummary
A row that has neither column set (e.g. from a semicolon-delimited file parsed as single-column rows) fails validation and triggers a warning.
Parameters:
| Name | Type | Description |
|---|---|---|
row |
* | Single row object from |
- Source:
Returns:
True if the row has the key and summary fields Jira import needs.
- Type
- boolean
Example
validJiraCsvRow({ 'Issue key': 'AITO-1', Summary: 'Fix login bug', Status: 'Open' })
// → true
validJiraCsvRow({ Key: 'PROJ-2', Summary: 'Add dark mode', Status: 'To Do' })
// → true
validJiraCsvRow({}) // → false (no key or summary)
validJiraCsvRow({ 'Issue key': 'AITO-1' }) // → false (missing summary)
validJiraCsvRow({ Summary: 'Fix login bug' }) // → false (missing key)
validPlanTask(t) → {boolean}
Returns true if t is a well-formed plan task with a recognised status value.
Parameters:
| Name | Type | Description |
|---|---|---|
t |
* | Candidate value parsed from JSON. |
- Source:
Returns:
True if the plan task is well-formed.
- Type
- boolean
Example
validPlanTask({ id: 'pk1', text: 'Build form', date: '2026-05-25', status: 'todo' }) // → true
validPlanTask({ id: 'pk1', text: 'x', date: '2026-05-25', status: 'finished' }) // → false (unknown status)
validPlanTask(null) // → false
validPomoEntry(e) → {boolean}
Returns true if e is a valid Pomodoro session log entry.
Parameters:
| Name | Type | Description |
|---|---|---|
e |
* | Candidate value. |
- Source:
Returns:
True if the Pomodoro entry is well-formed.
- Type
- boolean
validTimer(t) → {boolean}
Returns true if t is a resumable timer state.
Handles both running (startTs is set) and paused (paused=true, accumulatedMs is set) forms.
Parameters:
| Name | Type | Description |
|---|---|---|
t |
* | Candidate value parsed from JSON. |
- Source:
Returns:
True if the timer state is well-formed.
- Type
- boolean
Example
validTimer({ entryId: 'e1', startTs: 1234567890 }) // → true (running)
validTimer({ entryId: 'e1', paused: true, accumulatedMs: 900000 }) // → true (paused)
validTimer({ entryId: 'e1' }) // → false (neither running nor paused)
validTimer(null) // → false
validWeatherResponse(data) → {boolean}
Returns true if data is a well-formed Open-Meteo forecast response
containing the fields that fetchWeather() reads.
Required shape:
data.current.temperature_2m— numberdata.current.weather_code— numberdata.hourly.time— arraydata.hourly.precipitation_probability— array
The daily block is optional (used only when present).
Parameters:
| Name | Type | Description |
|---|---|---|
data |
* | Value parsed from the Open-Meteo JSON response. |
- Source:
Returns:
True if the response is a usable forecast object.
- Type
- boolean
Example
validWeatherResponse({
current: { temperature_2m: 15, weather_code: 3 },
hourly: { time: ['2026-05-28T00:00'], precipitation_probability: [10] },
}) // → true
validWeatherResponse(null) // → false
validWeatherResponse({ current: {} }) // → false (missing hourly)
validWeatherResponse({ hourly: { time: [], precipitation_probability: [] } })
// → false (missing current)
validateBackupFile(backup) → {Object}
Validates a parsed JSON backup object created by exportBackup().
Separated from the import flow so the validation logic can be unit-tested
without any browser APIs. importBackup() calls this before writing to
localStorage.
Parameters:
| Name | Type | Description |
|---|---|---|
backup |
* | Parsed backup object (typically from |
- Source:
Returns:
{ valid: true } when the backup is usable;
{ valid: false, error: string } with a human-readable reason otherwise.
- Type
- Object
Example
validateBackupFile({ version: '1', entries: [], categories: [], planTasks: [] })
// → { valid: true }
validateBackupFile(null)
// → { valid: false, error: 'Not a valid backup object.' }
validateBackupFile({ version: '2', entries: [], categories: [], planTasks: [] })
// → { valid: false, error: 'Unrecognised backup version "2"...' }
validateBackupFile({ version: '1', entries: [], categories: [] })
// → { valid: false, error: '...missing required field "planTasks".' }
viewEntries() → {Array.<object>}
Returns entries for the currently viewed date, sorted newest-first.
- Source:
Returns:
- Type
- Array.<object>
warn(msg, dataopt)
Emits a warning — something unexpected but non-fatal.
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
msg |
string | Human-readable message. |
|
data |
* |
<optional> |
Optional value to attach to the log line. |
weatherEmoji(code) → {string}
Maps a WMO weather interpretation code to a representative emoji.
Parameters:
| Name | Type | Description |
|---|---|---|
code |
number | WMO weather code (0 = clear sky, 95+ = thunderstorm). |
- Source:
Returns:
A single weather emoji character.
- Type
- string
writeCollapseState(sectionId, collapsed) → {void}
Writes the collapsed state for a section to localStorage.
Parameters:
| Name | Type | Description |
|---|---|---|
sectionId |
string | The section element's |
collapsed |
boolean | Whether the section is now collapsed. |
- Source:
Returns:
- Type
- void
(async) writeExportFile(subfolder, filename, blob) → {Promise.<void>}
Writes a Blob to subfolder/filename inside the user's chosen FSA directory.
Creates the subfolder if it does not exist. Falls back to a browser <a>
download if the FSA handle is missing or permission is not granted.
Parameters:
| Name | Type | Description |
|---|---|---|
subfolder |
string | Name of the subfolder to write into. |
filename |
string | Name of the file to create or overwrite. |
blob |
Blob | File content. |
- Source:
Returns:
- Type
- Promise.<void>
Type Definitions
Migration
Describes one key-rename migration.
Type:
- Object
- Source:
PomoSessionEntry
Type:
- Object
Properties:
| Name | Type | Description |
|---|---|---|
ts |
number | Unix timestamp ms when the session was logged. |
mins |
number | Duration of the session in minutes. |
task |
string | null | Task name linked to the session, or null if none. |
- Source: