tuiboard 0.8.1 → 0.8.2

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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,17 @@ All notable changes to **tuiboard** are documented here.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.8.2] - 2026-06-04
9
+
10
+ ### Changed
11
+ - **Consistent date shortcuts everywhere.** `m` now means "tomorrow" in every
12
+ date input (the schedule modal, the new-event/edit modals, and quick-add),
13
+ matching the board's `m` = tomorrow key — so `t`/`m` = today/tomorrow whether
14
+ you press them on a card or type them into a field. `tm`/`tom`/`tomorrow`/
15
+ `domani` still work as aliases. Hints and the help screen updated to lead with
16
+ `m`. (Audit of all shortcut surfaces found this was the only divergence; the
17
+ rest — `t`, `-`/empty to clear, weekdays, ±N — were already aligned.)
18
+
8
19
  ## [0.8.1] - 2026-06-04
9
20
 
10
21
  ### Added
@@ -152,6 +163,7 @@ First public release on npm. This entry captures the full feature set at launch.
152
163
 
153
164
  Built with [OpenTUI](https://opentui.com) + SolidJS on Bun.
154
165
 
166
+ [0.8.2]: https://github.com/NazzarenoGiannelli/tuiboard/releases/tag/v0.8.2
155
167
  [0.8.1]: https://github.com/NazzarenoGiannelli/tuiboard/releases/tag/v0.8.1
156
168
  [0.8.0]: https://github.com/NazzarenoGiannelli/tuiboard/releases/tag/v0.8.0
157
169
  [0.7.3]: https://github.com/NazzarenoGiannelli/tuiboard/releases/tag/v0.7.3
package/README.md CHANGED
@@ -261,14 +261,15 @@ show in the picker. Append tokens to the title to set the **time** and **date**:
261
261
 
262
262
  ```
263
263
  Standup 9:00-9:30 # today (or the viewed day), 09:00–09:30
264
- Lunch tomorrow 12-13 # tomorrow, 12:00–13:00
264
+ Lunch m 12-13 # tomorrow (m), 12:00–13:00
265
265
  Review 2026-06-10 15-16 # that date, 15:00–16:00
266
266
  Call +3 16:00-16:30 # in 3 days · lun = next Monday also works
267
267
  Holiday 2026-12-25 allday # an all-day event (no time)
268
268
  ```
269
269
 
270
270
  The date defaults to whichever day the Agenda is showing; an explicit date token
271
- (`t` / `tm` / `+N` / weekday / `YYYY-MM-DD`) overrides it. The time is taken from
271
+ (`t` / `m` / `+N` / weekday / `YYYY-MM-DD` the same `t`/`m` = today/tomorrow as
272
+ the board keys) overrides it. The time is taken from
272
273
  the clicked slot, or `HH:MM-HH:MM`. Add **`allday`** (or `all-day`) anywhere in
273
274
  the title to create an all-day event instead — it lands in the top chip strip.
274
275
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tuiboard",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
4
4
  "description": "Terminal kanban for markdown task boards, with optional Today/Tomorrow planner, 24h agenda + calendar overlay, and a live Claude Code agent view. Use only the panels you want.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -0,0 +1,64 @@
1
+ import { describe, expect, it } from "bun:test";
2
+
3
+ import { isoToday, isoTomorrow } from "./index";
4
+ import { parseDateShortcut, parseQuickAdd, parseTimeBlockShortcut } from "./parsers";
5
+
6
+ describe("parseDateShortcut", () => {
7
+ it("maps t / today / oggi to today", () => {
8
+ expect(parseDateShortcut("t")).toBe(isoToday());
9
+ expect(parseDateShortcut("today")).toBe(isoToday());
10
+ expect(parseDateShortcut("oggi")).toBe(isoToday());
11
+ });
12
+
13
+ it("maps m to tomorrow (consistent with the board's m key)", () => {
14
+ expect(parseDateShortcut("m")).toBe(isoTomorrow());
15
+ });
16
+
17
+ it("keeps tm / tom / tomorrow / domani as tomorrow aliases", () => {
18
+ expect(parseDateShortcut("tm")).toBe(isoTomorrow());
19
+ expect(parseDateShortcut("tom")).toBe(isoTomorrow());
20
+ expect(parseDateShortcut("tomorrow")).toBe(isoTomorrow());
21
+ expect(parseDateShortcut("domani")).toBe(isoTomorrow());
22
+ });
23
+
24
+ it("is case-insensitive", () => {
25
+ expect(parseDateShortcut("M")).toBe(isoTomorrow());
26
+ expect(parseDateShortcut("T")).toBe(isoToday());
27
+ });
28
+
29
+ it("clears on empty / dash, fails on garbage", () => {
30
+ expect(parseDateShortcut("")).toBeUndefined();
31
+ expect(parseDateShortcut("-")).toBeUndefined();
32
+ expect(parseDateShortcut("zzz")).toBeNull();
33
+ });
34
+
35
+ it("parses ISO dates literally", () => {
36
+ expect(parseDateShortcut("2026-06-10")).toBe("2026-06-10");
37
+ });
38
+ });
39
+
40
+ describe("parseQuickAdd date tokens", () => {
41
+ it("treats a standalone m as tomorrow and strips it from the title", () => {
42
+ const r = parseQuickAdd("Pay invoice m");
43
+ expect(r.scheduled).toBe(isoTomorrow());
44
+ expect(r.title).toBe("Pay invoice");
45
+ });
46
+
47
+ it("treats a standalone t as today", () => {
48
+ const r = parseQuickAdd("Standup t");
49
+ expect(r.scheduled).toBe(isoToday());
50
+ expect(r.title).toBe("Standup");
51
+ });
52
+ });
53
+
54
+ describe("parseTimeBlockShortcut", () => {
55
+ it("parses loose H-H ranges and HH:MM-HH:MM", () => {
56
+ expect(parseTimeBlockShortcut("9-11")).toEqual({ startMin: 540, endMin: 660 });
57
+ expect(parseTimeBlockShortcut("09:30-10:45")).toEqual({ startMin: 570, endMin: 645 });
58
+ });
59
+
60
+ it("clears on empty / dash", () => {
61
+ expect(parseTimeBlockShortcut("")).toBeUndefined();
62
+ expect(parseTimeBlockShortcut("-")).toBeUndefined();
63
+ });
64
+ });
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Date input shortcuts:
5
5
  * t → today
6
- * tm | tom → tomorrow
6
+ * m | tm | tom → tomorrow (m matches the board's `m` = tomorrow key)
7
7
  * -N → N days ago
8
8
  * +N → N days ahead
9
9
  * lun/mar/.../dom → next weekday (Italian short)
@@ -47,7 +47,8 @@ export function parseDateShortcut(input: string): string | undefined | null {
47
47
  if (s === "-") return undefined;
48
48
 
49
49
  if (s === "t" || s === "today" || s === "oggi") return isoToday();
50
- if (s === "tm" || s === "tom" || s === "tomorrow" || s === "domani") return isoTomorrow();
50
+ // `m` mirrors the board's `m` = tomorrow key; `tm`/`tom`/… kept as aliases.
51
+ if (s === "m" || s === "tm" || s === "tom" || s === "tomorrow" || s === "domani") return isoTomorrow();
51
52
 
52
53
  // Relative ±N
53
54
  const rel = s.match(/^([+-])(\d+)$/);
@@ -167,7 +168,7 @@ export interface QuickAddResult {
167
168
  * Parse a free-form quick-add string. Recognized tokens:
168
169
  * @name → assignee
169
170
  * #tag → tag
170
- * t, tm, +N → scheduled date shortcut
171
+ * t, m, +N → scheduled date shortcut (m = tomorrow, matches the board key)
171
172
  * YYYY-MM-DD → scheduled date literal
172
173
  * HH:MM-HH:MM → time block (also sets scheduled to today if missing)
173
174
  * 9-11 → 09:00-11:00 time block
@@ -220,10 +221,10 @@ export function parseQuickAdd(input: string): QuickAddResult {
220
221
  }
221
222
  continue;
222
223
  }
223
- // Date: t, tm, +N, YYYY-MM-DD
224
+ // Date: t, m/tm, +N, YYYY-MM-DD
224
225
  const lower = tok.toLowerCase();
225
226
  if (
226
- lower === "t" || lower === "tm" || lower === "tom" ||
227
+ lower === "t" || lower === "m" || lower === "tm" || lower === "tom" ||
227
228
  lower === "today" || lower === "tomorrow" ||
228
229
  lower === "oggi" || lower === "domani" ||
229
230
  /^[+-]\d+$/.test(lower) ||
package/src/ui/Modal.tsx CHANGED
@@ -139,7 +139,7 @@ function AddModal(props: { store: TuiStore; columnIndex: number }) {
139
139
  return (
140
140
  <DialogShell
141
141
  title="New task"
142
- hint="Quick syntax: @assignee #tag t/tm/+N HH:MM-HH:MM 🔺 · Enter to add, Esc to cancel"
142
+ hint="Quick syntax: @assignee #tag t/m/+N HH:MM-HH:MM 🔺 · Enter to add, Esc to cancel"
143
143
  width={70}
144
144
  >
145
145
  <input
@@ -195,7 +195,7 @@ function ScheduleModal(props: { store: TuiStore; modal: Extract<NonNullable<TuiS
195
195
  function submit(text: string) {
196
196
  const d = parseDateShortcut(text);
197
197
  if (d === null) {
198
- setError(`Cannot parse "${text}". Try: t · tm · +3 · lun · 2026-06-15`);
198
+ setError(`Cannot parse "${text}". Try: t · m · +3 · lun · 2026-06-15`);
199
199
  return;
200
200
  }
201
201
  const n = props.store.applyToMarkedOr(props.modal.ref, (r) =>
@@ -208,7 +208,7 @@ function ScheduleModal(props: { store: TuiStore; modal: Extract<NonNullable<TuiS
208
208
  return (
209
209
  <DialogShell
210
210
  title={markedCount > 1 ? `Schedule · ${markedCount} tasks` : "Schedule"}
211
- hint="t = today · tm = tomorrow · +3 = in 3 days · lun = next Monday · 2026-06-15 · empty/-clear · Esc to cancel"
211
+ hint="t = today · m = tomorrow · +3 = in 3 days · lun = next Monday · 2026-06-15 · empty/-clear · Esc to cancel"
212
212
  width={70}
213
213
  >
214
214
  <input
@@ -370,7 +370,7 @@ function EventModal(props: { store: TuiStore }) {
370
370
  fallback={
371
371
  <DialogShell
372
372
  title="New event"
373
- hint={`${formatHm(picker()!.startMin)}-${formatHm(picker()!.endMin)} · add a time, a date (tm · +3 · 2026-06-10), or "allday" · Enter add · Esc`}
373
+ hint={`${formatHm(picker()!.startMin)}-${formatHm(picker()!.endMin)} · add a time, a date (m · +3 · 2026-06-10), or "allday" · Enter add · Esc`}
374
374
  >
375
375
  <input
376
376
  focused
@@ -452,7 +452,7 @@ function EventEditModal(props: { store: TuiStore }) {
452
452
  <Show when={sel()}>
453
453
  <DialogShell
454
454
  title={`Edit event · ${shortDate(sel()!.dateIso)}`}
455
- hint="change title, HH:MM-HH:MM, and/or a date (tm · +3 · lun · 2026-06-10) · Enter save · Esc"
455
+ hint="change title, HH:MM-HH:MM, and/or a date (m · +3 · lun · 2026-06-10) · Enter save · Esc"
456
456
  >
457
457
  <input
458
458
  focused
@@ -813,7 +813,7 @@ function HelpModal(props: { store: TuiStore }) {
813
813
  <span style={{ fg: T.text }}>{" Enter Toggle done\n"}</span>
814
814
  <span style={{ fg: T.text }}>{" o Open detail view\n"}</span>
815
815
  <span style={{ fg: T.text }}>{" e Edit task text\n"}</span>
816
- <span style={{ fg: T.text }}>{" s Schedule date modal (t/tm/+N/lun/YYYY-MM-DD)\n"}</span>
816
+ <span style={{ fg: T.text }}>{" s Schedule date modal (t/m/+N/lun/YYYY-MM-DD — same t/m as the board)\n"}</span>
817
817
  <span style={{ fg: T.text }}>{" t Set scheduled = today\n"}</span>
818
818
  <span style={{ fg: T.text }}>{" m Set scheduled = tomorrow\n"}</span>
819
819
  <span style={{ fg: T.text }}>{" . Schedule now — time block at next 15-min slot (30min)\n"}</span>