pom-tool 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +3 -0
  2. package/dist/index.js +31 -25
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  A small **Node.js CLI** (TypeScript + pnpm) for running Pomodoro timers in your terminal, with optional **Bark** notifications synced to your phone.
4
4
 
5
+ ![pom-tool](./asset/pom.png)
6
+ ![phone](./asset/phone.jpg)
7
+
5
8
  ## Features
6
9
 
7
10
  - **Run a Pomodoro for N minutes**
package/dist/index.js CHANGED
@@ -54,10 +54,10 @@ async function main() {
54
54
  await runPomodoro(minutes);
55
55
  }
56
56
  function printHelp() {
57
- console.log(renderPanel("pom-tool", [
58
- `${label("Usage")} ${style("pom <minutes>", "cyan")} Start a Pomodoro timer`,
59
- ` ${style("pom status", "cyan")} Show Pomodoro averages`,
60
- ` ${style("pom bark [--url URL]", "cyan")} Configure Bark notifications`,
57
+ console.log(renderKeyValuePanel("pom-tool", [
58
+ ["Usage", `${style("pom <minutes>", "cyan")} Start a Pomodoro timer`],
59
+ ["", `${style("pom status", "cyan")} Show Pomodoro averages`],
60
+ ["", `${style("pom bark [--url URL]", "cyan")} Configure Bark notifications`],
61
61
  ]));
62
62
  }
63
63
  async function ensureDataDir() {
@@ -104,9 +104,9 @@ async function configureBark(args) {
104
104
  }
105
105
  validateBarkUrl(barkUrl);
106
106
  await saveConfig({ ...currentConfig, barkUrl });
107
- console.log(renderPanel("Bark", [
108
- `${label("Status")} ${style("saved", "green")}`,
109
- `${label("URL")} ${maskBarkUrl(barkUrl)}`,
107
+ console.log(renderKeyValuePanel("Bark", [
108
+ ["Status", style("saved", "green")],
109
+ ["URL", maskBarkUrl(barkUrl)],
110
110
  ]));
111
111
  }
112
112
  function readFlagValue(args, flag) {
@@ -148,10 +148,10 @@ async function runPomodoro(minutes) {
148
148
  const { config } = await readStore();
149
149
  const totalSeconds = minutes * 60;
150
150
  const startedAt = new Date();
151
- console.log(renderPanel("🍅 Pomodoro", [
152
- `${label("Duration")} ${style(formatMinutes(minutes), "cyan")}`,
153
- `${label("Started")} ${formatClockTime(startedAt)}`,
154
- `${label("Bark")} ${config.barkUrl ? style("enabled", "green") : style("disabled", "gray")}`,
151
+ console.log(renderKeyValuePanel("🍅 Pomodoro", [
152
+ ["Duration", style(formatMinutes(minutes), "cyan")],
153
+ ["Started", formatClockTime(startedAt)],
154
+ ["Bark", config.barkUrl ? style("enabled", "green") : style("disabled", "gray")],
155
155
  ]));
156
156
  const interrupted = await startCountdown(totalSeconds);
157
157
  if (interrupted) {
@@ -166,10 +166,10 @@ async function runPomodoro(minutes) {
166
166
  });
167
167
  await notifyPomodoroFinished(minutes, finishedAt);
168
168
  process.stdout.write("\n");
169
- console.log(renderPanel("🍅 Completed", [
170
- `${label("Logged")} ${style(formatMinutes(minutes), "green")}`,
171
- `${label("Finished")} ${formatClockTime(finishedAt)}`,
172
- `${label("Saved")} ${style("session recorded", "green")}`,
169
+ console.log(renderKeyValuePanel("🍅 Completed", [
170
+ ["Logged", style(formatMinutes(minutes), "green")],
171
+ ["Finished", formatClockTime(finishedAt)],
172
+ ["Saved", style("session recorded", "green")],
173
173
  ]));
174
174
  await sendBarkNotification(config.barkUrl, "Pomodoro finished", `${minutes} minute${minutes === 1 ? "" : "s"} completed at ${formatClockTime(finishedAt)}`);
175
175
  }
@@ -251,13 +251,13 @@ async function showStatus() {
251
251
  const last7Total = sumMinutesSince(sessions, daysAgo(today, 6));
252
252
  const last30Total = sumMinutesSince(sessions, daysAgo(today, 29));
253
253
  const lastSession = getLastSession(sessions);
254
- console.log(renderPanel("Pomodoro Status", [
255
- `${label("Today")} ${style(formatMinutesDecimal(todayTotal), "green")}`,
256
- `${label("7d avg")} ${style(`${formatMinutesDecimal(last7Total / 7)}/day`, "cyan")}`,
257
- `${label("30d avg")} ${style(`${formatMinutesDecimal(last30Total / 30)}/day`, "cyan")}`,
258
- `${label("Sessions")} ${style(String(sessions.length), "blue")}`,
259
- `${label("Bark")} ${config.barkUrl ? style("configured", "green") : style("not configured", "gray")}`,
260
- `${label("Last done")} ${lastSession ? formatSessionTime(lastSession.completedAt) : style("none yet", "gray")}`,
254
+ console.log(renderKeyValuePanel("Pomodoro Status", [
255
+ ["Today", style(formatMinutesDecimal(todayTotal), "green")],
256
+ ["7d avg", style(`${formatMinutesDecimal(last7Total / 7)}/day`, "cyan")],
257
+ ["30d avg", style(`${formatMinutesDecimal(last30Total / 30)}/day`, "cyan")],
258
+ ["Sessions", style(String(sessions.length), "blue")],
259
+ ["Bark", config.barkUrl ? style("configured", "green") : style("not configured", "gray")],
260
+ ["Last done", lastSession ? formatSessionTime(lastSession.completedAt) : style("none yet", "gray")],
261
261
  ]));
262
262
  }
263
263
  function sumMinutesSince(sessions, since) {
@@ -314,9 +314,6 @@ function formatClockTime(date) {
314
314
  function toIsoSeconds(date) {
315
315
  return date.toISOString().replace(/\.\d{3}Z$/, "Z");
316
316
  }
317
- function label(text) {
318
- return style(text.padEnd(9, " "), "gray");
319
- }
320
317
  function renderPanel(title, lines) {
321
318
  const width = Math.max(title.length, ...lines.map(stripAnsi).map((line) => line.length));
322
319
  const top = `+${"-".repeat(width + 2)}+`;
@@ -324,6 +321,15 @@ function renderPanel(title, lines) {
324
321
  const body = lines.map((line) => `| ${padAnsi(line, width)} |`);
325
322
  return [top, header, top, ...body, top].join("\n");
326
323
  }
324
+ function renderKeyValuePanel(title, rows) {
325
+ const labelWidth = Math.max(...rows.map(([labelText]) => labelText.length));
326
+ const lines = rows.map(([labelText, valueText]) => renderKeyValueLine(labelText, valueText, labelWidth));
327
+ return renderPanel(title, lines);
328
+ }
329
+ function renderKeyValueLine(labelText, valueText, labelWidth) {
330
+ const key = labelText ? style(labelText.padEnd(labelWidth, " "), "gray") : " ".repeat(labelWidth);
331
+ return `${key} ${valueText}`;
332
+ }
327
333
  function padAnsi(value, width) {
328
334
  const visible = stripAnsi(value).length;
329
335
  return `${value}${" ".repeat(Math.max(0, width - visible))}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pom-tool",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "A small Node.js CLI for running Pomodoro timers in your terminal.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,7 +23,7 @@
23
23
  "author": "AlucPro",
24
24
  "repository": {
25
25
  "type": "git",
26
- "url": "https://github.com/AlucPro/pom-tool.git"
26
+ "url": "git+https://github.com/AlucPro/pom-tool.git"
27
27
  },
28
28
  "homepage": "https://github.com/AlucPro/pom-tool",
29
29
  "bugs": {
@@ -38,4 +38,4 @@
38
38
  "ts-node": "^10.9.2",
39
39
  "typescript": "^5.8.2"
40
40
  }
41
- }
41
+ }