@rewrlution/papyrus-cli 0.0.5 → 0.0.6

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 (79) hide show
  1. package/README.md +4 -8
  2. package/dist/cli.js +0 -4
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/auth/logout.js +2 -0
  5. package/dist/commands/auth/logout.js.map +1 -1
  6. package/dist/commands/journal/app.d.ts +1 -0
  7. package/dist/commands/journal/app.js +22 -0
  8. package/dist/commands/journal/app.js.map +1 -0
  9. package/dist/commands/journal/edit.js +8 -10
  10. package/dist/commands/journal/edit.js.map +1 -1
  11. package/dist/commands/journal/index.js +9 -10
  12. package/dist/commands/journal/index.js.map +1 -1
  13. package/dist/commands/journal/show.js +8 -14
  14. package/dist/commands/journal/show.js.map +1 -1
  15. package/dist/components/AppLayout.d.ts +32 -0
  16. package/dist/components/AppLayout.js +34 -0
  17. package/dist/components/AppLayout.js.map +1 -0
  18. package/dist/components/Divider.d.ts +7 -0
  19. package/dist/components/Divider.js +19 -0
  20. package/dist/components/Divider.js.map +1 -0
  21. package/dist/components/JournalBrowser.d.ts +14 -0
  22. package/dist/components/JournalBrowser.js +102 -0
  23. package/dist/components/JournalBrowser.js.map +1 -0
  24. package/dist/components/JournalList.d.ts +16 -0
  25. package/dist/components/JournalList.js +73 -0
  26. package/dist/components/JournalList.js.map +1 -0
  27. package/dist/components/JournalViewer.d.ts +5 -23
  28. package/dist/components/JournalViewer.js +73 -80
  29. package/dist/components/JournalViewer.js.map +1 -1
  30. package/dist/components/LoginForm.js +2 -2
  31. package/dist/components/LoginForm.js.map +1 -1
  32. package/dist/components/LogoCompact.d.ts +5 -0
  33. package/dist/components/LogoCompact.js +11 -0
  34. package/dist/components/LogoCompact.js.map +1 -0
  35. package/dist/components/RegisterForm.js +2 -2
  36. package/dist/components/RegisterForm.js.map +1 -1
  37. package/dist/components/StatusMessage.d.ts +2 -1
  38. package/dist/components/StatusMessage.js +3 -3
  39. package/dist/components/StatusMessage.js.map +1 -1
  40. package/dist/lib/auth/require-auth.js +4 -5
  41. package/dist/lib/auth/require-auth.js.map +1 -1
  42. package/dist/utils/alternate-screen.d.ts +46 -0
  43. package/dist/utils/alternate-screen.js +60 -0
  44. package/dist/utils/alternate-screen.js.map +1 -0
  45. package/dist/utils/date.js +3 -4
  46. package/dist/utils/date.js.map +1 -1
  47. package/dist/utils/editor.js +0 -1
  48. package/dist/utils/editor.js.map +1 -1
  49. package/dist/utils/journal-preview.d.ts +15 -0
  50. package/dist/utils/journal-preview.js +34 -0
  51. package/dist/utils/journal-preview.js.map +1 -0
  52. package/dist/utils/journal-preview.test.d.ts +1 -0
  53. package/dist/utils/journal-preview.test.js +62 -0
  54. package/dist/utils/journal-preview.test.js.map +1 -0
  55. package/dist/utils/messages.d.ts +43 -0
  56. package/dist/utils/messages.js +72 -0
  57. package/dist/utils/messages.js.map +1 -0
  58. package/dist/utils/text.d.ts +25 -0
  59. package/dist/utils/text.js +51 -0
  60. package/dist/utils/text.js.map +1 -0
  61. package/dist/utils/text.test.d.ts +1 -0
  62. package/dist/utils/text.test.js +47 -0
  63. package/dist/utils/text.test.js.map +1 -0
  64. package/package.json +3 -2
  65. package/dist/commands/journal/list.d.ts +0 -1
  66. package/dist/commands/journal/list.js +0 -20
  67. package/dist/commands/journal/list.js.map +0 -1
  68. package/dist/components/Browser.d.ts +0 -29
  69. package/dist/components/Browser.js +0 -124
  70. package/dist/components/Browser.js.map +0 -1
  71. package/dist/components/BrowserFooter.d.ts +0 -6
  72. package/dist/components/BrowserFooter.js +0 -6
  73. package/dist/components/BrowserFooter.js.map +0 -1
  74. package/dist/components/BrowserHeader.d.ts +0 -6
  75. package/dist/components/BrowserHeader.js +0 -6
  76. package/dist/components/BrowserHeader.js.map +0 -1
  77. package/dist/components/JournalListView.d.ts +0 -10
  78. package/dist/components/JournalListView.js +0 -40
  79. package/dist/components/JournalListView.js.map +0 -1
package/README.md CHANGED
@@ -61,9 +61,7 @@ This opens your default editor. Write your thoughts, save, and close.
61
61
  ### 4. Browse Your Journals
62
62
 
63
63
  ```bash
64
- papyrus list
65
- # Or use the short alias
66
- papyrus ls
64
+ papyrus app
67
65
  ```
68
66
 
69
67
  Use arrow keys or `j/k` to navigate, press `Enter` to read an entry.
@@ -147,14 +145,12 @@ papyrus show -d yesterday
147
145
  - `0` - Jump to start of line
148
146
  - `q` or `Esc` - Quit
149
147
 
150
- #### `papyrus list` or `papyrus ls`
148
+ #### `papyrus app`
151
149
 
152
- Browse all journal entries interactively.
150
+ Launch the Papyrus TUI to browse and read journal entries interactively.
153
151
 
154
152
  ```bash
155
- papyrus list
156
- # Or
157
- papyrus ls
153
+ papyrus app
158
154
  ```
159
155
 
160
156
  **Features:**
package/dist/cli.js CHANGED
@@ -1,10 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { jsx as _jsx } from "react/jsx-runtime";
3
2
  import { Command } from 'commander';
4
- import { render } from 'ink';
5
3
  import { registerJournalCommands, registerAuthCommands, } from './commands/index.js';
6
- import { Logo } from './components/Logo.js';
7
- render(_jsx(Logo, {}));
8
4
  const program = new Command();
9
5
  program
10
6
  .name('papyrus')
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.tsx"],"names":[],"mappings":";;AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,EACL,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAE5C,MAAM,CAAC,KAAC,IAAI,KAAG,CAAC,CAAC;AAEjB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,iCAAiC,CAAC;KAC9C,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,uBAAuB,CAAC,OAAO,CAAC,CAAC;AAEjC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EACL,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,iCAAiC,CAAC;KAC9C,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,uBAAuB,CAAC,OAAO,CAAC,CAAC;AAEjC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -1,5 +1,7 @@
1
1
  import { api } from '../../lib/api/index.js';
2
+ import * as msg from '../../utils/messages.js';
2
3
  export function logout() {
3
4
  api.logout();
5
+ msg.success('Logged out successfully');
4
6
  }
5
7
  //# sourceMappingURL=logout.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../../src/commands/auth/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAE7C,MAAM,UAAU,MAAM;IACpB,GAAG,CAAC,MAAM,EAAE,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../../src/commands/auth/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAC7C,OAAO,KAAK,GAAG,MAAM,yBAAyB,CAAC;AAE/C,MAAM,UAAU,MAAM;IACpB,GAAG,CAAC,MAAM,EAAE,CAAC;IACb,GAAG,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function launchApp(): Promise<void>;
@@ -0,0 +1,22 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { render } from 'ink';
3
+ import React from 'react';
4
+ import { JournalBrowser } from '../../components/JournalBrowser.js';
5
+ import { journalStore } from '../../lib/storage/index.js';
6
+ import { withAlternateScreen } from '../../utils/alternate-screen.js';
7
+ import * as msg from '../../utils/messages.js';
8
+ export async function launchApp() {
9
+ try {
10
+ // Load all journal entries
11
+ const journals = journalStore.list();
12
+ // Render the journal browser in alternate screen
13
+ await withAlternateScreen(async () => {
14
+ const { waitUntilExit } = render(React.createElement(JournalBrowser, { journals }));
15
+ await waitUntilExit();
16
+ });
17
+ }
18
+ catch (error) {
19
+ msg.error(`Failed to launch Papyrus app: ${error.message}`);
20
+ }
21
+ }
22
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../../src/commands/journal/app.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,GAAG,MAAM,yBAAyB,CAAC;AAE/C,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,IAAI,CAAC;QACH,2BAA2B;QAC3B,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC;QAErC,iDAAiD;QACjD,MAAM,mBAAmB,CAAC,KAAK,IAAI,EAAE;YACnC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAC9B,KAAK,CAAC,aAAa,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,CAAC,CAClD,CAAC;YACF,MAAM,aAAa,EAAE,CAAC;QACxB,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,GAAG,CAAC,KAAK,CAAC,iCAAiC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC"}
@@ -2,6 +2,7 @@
2
2
  import { journalStore } from '../../lib/storage/index.js';
3
3
  import { formatDate, parseDate } from '../../utils/date.js';
4
4
  import { openInEditor } from '../../utils/editor.js';
5
+ import * as msg from '../../utils/messages.js';
5
6
  import { JOURNAL_TEMPATE, stripTemplateComments, } from '../../utils/template.js';
6
7
  export function editJournalEntry(options) {
7
8
  const { date: inputDate, createIfMissing } = options;
@@ -15,17 +16,15 @@ export function editJournalEntry(options) {
15
16
  if (!entry) {
16
17
  if (!createIfMissing) {
17
18
  // amend: fail if entry doesn't exist
18
- console.error(`\n❌ Error: No journal entry found for ${date}.\n` +
19
- `💡 Use 'papyrus add -d ${date}' to create a new entry.\n`);
20
- process.exit(1);
19
+ msg.error(`No journal entry found for ${date}`, `Use 'papyrus add -d ${date}' to create a new entry`);
21
20
  }
22
21
  // add: create new entry
23
22
  isNew = true;
24
23
  entry = '';
25
- console.log(`\n✨ Creating new entry for ${displayDate}...\n`);
24
+ msg.sparkles(`Creating new entry for ${displayDate}...`);
26
25
  }
27
26
  else {
28
- console.log(`\n📖 Loading existing entry for ${displayDate}...\n`);
27
+ msg.info(`Loading existing entry for ${displayDate}...`);
29
28
  }
30
29
  // 3. Append hint comments for user guidance
31
30
  const contentWithHints = `${entry}\n${JOURNAL_TEMPATE}`;
@@ -33,19 +32,18 @@ export function editJournalEntry(options) {
33
32
  const editedContent = openInEditor(contentWithHints, `papyrus-${date}.md`);
34
33
  const finalContent = stripTemplateComments(editedContent);
35
34
  if (!finalContent.trim()) {
36
- console.log('⚠️ No content written. Entry not saved.\n');
35
+ msg.warn('No content written. Entry not saved');
37
36
  return;
38
37
  }
39
38
  journalStore.create(date, finalContent);
40
39
  // 5. Show success message with stats
41
40
  const words = countWords(finalContent);
42
41
  const chars = finalContent.length;
43
- console.log(`\n✅ Journal entry ${isNew ? 'created' : 'updated'} for ${date}`);
44
- console.log(`📊 Words: ${words} | Characters: ${chars}\n`);
42
+ msg.success(`Journal entry ${isNew ? 'created' : 'updated'} for ${date}`);
43
+ msg.stats(`Words: ${words} | Characters: ${chars}`);
45
44
  }
46
45
  catch (error) {
47
- console.error(`\n❌ Error: ${error.message}\n`);
48
- process.exit(1);
46
+ msg.error(error.message);
49
47
  }
50
48
  }
51
49
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../../src/commands/journal/edit.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EACL,eAAe,EACf,qBAAqB,GACtB,MAAM,yBAAyB,CAAC;AAOjC,MAAM,UAAU,gBAAgB,CAAC,OAAoB;IACnD,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;IAErD,IAAI,CAAC;QACH,6BAA6B;QAC7B,MAAM,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;QAClC,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAErC,uCAAuC;QACvC,IAAI,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,KAAK,GAAG,KAAK,CAAC;QAElB,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,CAAC,eAAe,EAAE,CAAC;gBACrB,qCAAqC;gBACrC,OAAO,CAAC,KAAK,CACX,yCAAyC,IAAI,KAAK;oBAChD,0BAA0B,IAAI,4BAA4B,CAC7D,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,wBAAwB;YACxB,KAAK,GAAG,IAAI,CAAC;YACb,KAAK,GAAG,EAAE,CAAC;YACX,OAAO,CAAC,GAAG,CAAC,8BAA8B,WAAW,OAAO,CAAC,CAAC;QAChE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,mCAAmC,WAAW,OAAO,CAAC,CAAC;QACrE,CAAC;QAED,4CAA4C;QAC5C,MAAM,gBAAgB,GAAG,GAAG,KAAK,KAAK,eAAe,EAAE,CAAC;QAExD,iBAAiB;QACjB,MAAM,aAAa,GAAG,YAAY,CAAC,gBAAgB,EAAE,WAAW,IAAI,KAAK,CAAC,CAAC;QAC3E,MAAM,YAAY,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAAC;QAE1D,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;YAC1D,OAAO;QACT,CAAC;QAED,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAExC,qCAAqC;QACrC,MAAM,KAAK,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;QACvC,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC;QAElC,OAAO,CAAC,GAAG,CACT,qBAAqB,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,QAAQ,IAAI,EAAE,CACjE,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,kBAAkB,KAAK,IAAI,CAAC,CAAC;IAC7D,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,cAAc,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;QAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,IAAI;SACR,IAAI,EAAE;SACN,KAAK,CAAC,KAAK,CAAC;SACZ,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;AAC9C,CAAC"}
1
+ {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../../src/commands/journal/edit.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,GAAG,MAAM,yBAAyB,CAAC;AAC/C,OAAO,EACL,eAAe,EACf,qBAAqB,GACtB,MAAM,yBAAyB,CAAC;AAOjC,MAAM,UAAU,gBAAgB,CAAC,OAAoB;IACnD,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;IAErD,IAAI,CAAC;QACH,6BAA6B;QAC7B,MAAM,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;QAClC,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAErC,uCAAuC;QACvC,IAAI,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,KAAK,GAAG,KAAK,CAAC;QAElB,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,CAAC,eAAe,EAAE,CAAC;gBACrB,qCAAqC;gBACrC,GAAG,CAAC,KAAK,CACP,8BAA8B,IAAI,EAAE,EACpC,uBAAuB,IAAI,yBAAyB,CACrD,CAAC;YACJ,CAAC;YAED,wBAAwB;YACxB,KAAK,GAAG,IAAI,CAAC;YACb,KAAK,GAAG,EAAE,CAAC;YACX,GAAG,CAAC,QAAQ,CAAC,0BAA0B,WAAW,KAAK,CAAC,CAAC;QAC3D,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,IAAI,CAAC,8BAA8B,WAAW,KAAK,CAAC,CAAC;QAC3D,CAAC;QAED,4CAA4C;QAC5C,MAAM,gBAAgB,GAAG,GAAG,KAAK,KAAK,eAAe,EAAE,CAAC;QAExD,iBAAiB;QACjB,MAAM,aAAa,GAAG,YAAY,CAAC,gBAAgB,EAAE,WAAW,IAAI,KAAK,CAAC,CAAC;QAC3E,MAAM,YAAY,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAAC;QAE1D,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC;YACzB,GAAG,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;YAChD,OAAO;QACT,CAAC;QAED,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAExC,qCAAqC;QACrC,MAAM,KAAK,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;QACvC,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC;QAElC,GAAG,CAAC,OAAO,CAAC,iBAAiB,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,QAAQ,IAAI,EAAE,CAAC,CAAC;QAC1E,GAAG,CAAC,KAAK,CAAC,UAAU,KAAK,kBAAkB,KAAK,EAAE,CAAC,CAAC;IACtD,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,IAAI;SACR,IAAI,EAAE;SACN,KAAK,CAAC,KAAK,CAAC;SACZ,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;AAC9C,CAAC"}
@@ -1,9 +1,17 @@
1
1
  import { addEntry } from './add.js';
2
2
  import { amendEntry } from './amend.js';
3
- import { listEntries } from './list.js';
3
+ import { launchApp } from './app.js';
4
4
  import { showEntry } from './show.js';
5
5
  import { syncEntries } from './sync.js';
6
6
  export function registerJournalCommands(program) {
7
+ program
8
+ .command('app')
9
+ .description('Launch the Papyrus TUI to browse and manage journal entries')
10
+ .action(async () => await launchApp());
11
+ program
12
+ .command('sync')
13
+ .description('Sync journals with server (requires authentication)')
14
+ .action(async () => await syncEntries());
7
15
  program
8
16
  .command('add')
9
17
  .description('Create a new journal entry')
@@ -19,14 +27,5 @@ export function registerJournalCommands(program) {
19
27
  .description('Display a journal entry')
20
28
  .option('-d, --date <date>', 'Date of the entry to show (default: today)', 'today')
21
29
  .action(async (options) => await showEntry(options));
22
- program
23
- .command('list')
24
- .alias('ls')
25
- .description('List all local journal entries')
26
- .action(async () => await listEntries());
27
- program
28
- .command('sync')
29
- .description('Sync journals with server (requires authentication)')
30
- .action(async () => await syncEntries());
31
30
  }
32
31
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/journal/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,UAAU,uBAAuB,CAAC,OAAgB;IACtD,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,4BAA4B,CAAC;SACzC,MAAM,CAAC,mBAAmB,EAAE,qCAAqC,EAAE,OAAO,CAAC;SAC3E,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAEtD,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,kCAAkC,CAAC;SAC/C,MAAM,CACL,mBAAmB,EACnB,6CAA6C,EAC7C,OAAO,CACR;SACA,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;IAExD,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,yBAAyB,CAAC;SACtC,MAAM,CACL,mBAAmB,EACnB,4CAA4C,EAC5C,OAAO,CACR;SACA,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IAEvD,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,KAAK,CAAC,IAAI,CAAC;SACX,WAAW,CAAC,gCAAgC,CAAC;SAC7C,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,WAAW,EAAE,CAAC,CAAC;IAE3C,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,qDAAqD,CAAC;SAClE,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,WAAW,EAAE,CAAC,CAAC;AAC7C,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/journal/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,UAAU,uBAAuB,CAAC,OAAgB;IACtD,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,6DAA6D,CAAC;SAC1E,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,SAAS,EAAE,CAAC,CAAC;IAEzC,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,qDAAqD,CAAC;SAClE,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,WAAW,EAAE,CAAC,CAAC;IAE3C,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,4BAA4B,CAAC;SACzC,MAAM,CAAC,mBAAmB,EAAE,qCAAqC,EAAE,OAAO,CAAC;SAC3E,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAEtD,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,kCAAkC,CAAC;SAC/C,MAAM,CACL,mBAAmB,EACnB,6CAA6C,EAC7C,OAAO,CACR;SACA,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;IAExD,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,yBAAyB,CAAC;SACtC,MAAM,CACL,mBAAmB,EACnB,4CAA4C,EAC5C,OAAO,CACR;SACA,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;AACzD,CAAC"}
@@ -1,9 +1,7 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { render } from 'ink';
3
- import React from 'react';
4
- import { JournalViewer } from '../../components/JournalViewer.js';
5
2
  import { journalStore } from '../../lib/storage/index.js';
6
3
  import { formatDate, parseDate } from '../../utils/date.js';
4
+ import * as msg from '../../utils/messages.js';
7
5
  export async function showEntry(options) {
8
6
  const dateInput = options.date;
9
7
  try {
@@ -12,24 +10,20 @@ export async function showEntry(options) {
12
10
  const displayDate = formatDate(date);
13
11
  // 2. Check if entry exists
14
12
  if (!journalStore.exists(date)) {
15
- console.error(`\n❌ Error: No journal entry found for ${displayDate}`);
16
- console.error(`💡 Run 'papyrus add -d ${date}' to create one.\n`);
17
- process.exit(1);
13
+ msg.error(`No journal entry found for ${displayDate}`, `Run 'papyrus add -d ${date}' to create one`);
18
14
  }
19
15
  // 3. Load the entry
20
16
  const content = journalStore.load(date);
21
17
  if (!content) {
22
- console.error(`\n❌ Error: Failed to load journal entry for ${date}\n`);
23
- process.exit(1);
18
+ msg.error(`Failed to load journal entry for ${date}`);
24
19
  }
25
- // 4. Display the entry
26
- const { waitUntilExit } = render(React.createElement(JournalViewer, { date, content }));
27
- await waitUntilExit();
20
+ // 4. Output the journal content
21
+ console.log(`\n# ${displayDate}\n`);
22
+ console.log(content);
23
+ console.log('');
28
24
  }
29
25
  catch (error) {
30
- console.error(`\n❌ Error: ${error.message}`);
31
- console.error('💡 Use formats like: today, yesterday, tomorrow, or YYYYMMDD (e.g., 20260104)\n');
32
- process.exit(1);
26
+ msg.error(error.message, 'Use formats like: today, yesterday, tomorrow, or YYYYMMDD (e.g., 20260104)');
33
27
  }
34
28
  }
35
29
  //# sourceMappingURL=show.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"show.js","sourceRoot":"","sources":["../../../src/commands/journal/show.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAG5D,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAoB;IAClD,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAE/B,IAAI,CAAC;QACH,6BAA6B;QAC7B,MAAM,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;QAClC,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAErC,2BAA2B;QAC3B,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,OAAO,CAAC,KAAK,CAAC,yCAAyC,WAAW,EAAE,CAAC,CAAC;YACtE,OAAO,CAAC,KAAK,CAAC,0BAA0B,IAAI,oBAAoB,CAAC,CAAC;YAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,oBAAoB;QACpB,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,+CAA+C,IAAI,IAAI,CAAC,CAAC;YACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,uBAAuB;QACvB,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAC9B,KAAK,CAAC,aAAa,CAAC,aAAa,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CACtD,CAAC;QAEF,MAAM,aAAa,EAAE,CAAC;IACxB,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,cAAc,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7C,OAAO,CAAC,KAAK,CACX,iFAAiF,CAClF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"show.js","sourceRoot":"","sources":["../../../src/commands/journal/show.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,GAAG,MAAM,yBAAyB,CAAC;AAG/C,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAoB;IAClD,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAE/B,IAAI,CAAC;QACH,6BAA6B;QAC7B,MAAM,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;QAClC,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAErC,2BAA2B;QAC3B,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,GAAG,CAAC,KAAK,CACP,8BAA8B,WAAW,EAAE,EAC3C,uBAAuB,IAAI,iBAAiB,CAC7C,CAAC;QACJ,CAAC;QAED,oBAAoB;QACpB,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,oCAAoC,IAAI,EAAE,CAAC,CAAC;QACxD,CAAC;QAED,gCAAgC;QAChC,OAAO,CAAC,GAAG,CAAC,OAAO,WAAW,IAAI,CAAC,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,GAAG,CAAC,KAAK,CACP,KAAK,CAAC,OAAO,EACb,4EAA4E,CAC7E,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ interface AppLayoutProps {
3
+ headerContent: React.ReactNode;
4
+ footerContent: React.ReactNode;
5
+ children: React.ReactNode;
6
+ }
7
+ /**
8
+ * App layout with sticky header and footer.
9
+ *
10
+ * Provides a consistent frame for all screens:
11
+ * ┌────────────────────────────────┐
12
+ * │ Logo │
13
+ * │ ──────────────────────────── │
14
+ * │ [Custom Header Content] │ ← Passed as headerContent prop
15
+ * │ ──────────────────────────── │
16
+ * ├────────────────────────────────┤
17
+ * │ │
18
+ * │ [Children Content] │ ← Passed as children
19
+ * │ │
20
+ * ├────────────────────────────────┤
21
+ * │ ──────────────────────────── │
22
+ * │ [Custom Footer Content] │ ← Passed as footerContent prop
23
+ * └────────────────────────────────┘
24
+ *
25
+ * Benefits:
26
+ * - Reusable across all screens (list, viewer, etc.)
27
+ * - Consistent layout structure
28
+ * - Sticky header/footer with flexbox
29
+ * - No duplicate layout code
30
+ */
31
+ export declare const AppLayout: React.FC<AppLayoutProps>;
32
+ export {};
@@ -0,0 +1,34 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, useStdout } from 'ink';
3
+ import { Divider } from './Divider.js';
4
+ import { LogoCompact } from './LogoCompact.js';
5
+ /**
6
+ * App layout with sticky header and footer.
7
+ *
8
+ * Provides a consistent frame for all screens:
9
+ * ┌────────────────────────────────┐
10
+ * │ Logo │
11
+ * │ ──────────────────────────── │
12
+ * │ [Custom Header Content] │ ← Passed as headerContent prop
13
+ * │ ──────────────────────────── │
14
+ * ├────────────────────────────────┤
15
+ * │ │
16
+ * │ [Children Content] │ ← Passed as children
17
+ * │ │
18
+ * ├────────────────────────────────┤
19
+ * │ ──────────────────────────── │
20
+ * │ [Custom Footer Content] │ ← Passed as footerContent prop
21
+ * └────────────────────────────────┘
22
+ *
23
+ * Benefits:
24
+ * - Reusable across all screens (list, viewer, etc.)
25
+ * - Consistent layout structure
26
+ * - Sticky header/footer with flexbox
27
+ * - No duplicate layout code
28
+ */
29
+ export const AppLayout = ({ headerContent, footerContent, children, }) => {
30
+ const { stdout } = useStdout();
31
+ const terminalHeight = stdout?.rows || 24;
32
+ return (_jsxs(Box, { flexDirection: "column", height: terminalHeight - 2, borderStyle: "round", borderColor: "blue", paddingX: 1, children: [_jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [_jsx(LogoCompact, {}), _jsx(Divider, {}), headerContent, _jsx(Divider, {})] }), _jsx(Box, { flexDirection: "column", flexGrow: 1, flexShrink: 1, children: children }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [_jsx(Divider, {}), footerContent] })] }));
33
+ };
34
+ //# sourceMappingURL=AppLayout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AppLayout.js","sourceRoot":"","sources":["../../src/components/AppLayout.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAGrC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAQ/C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,MAAM,SAAS,GAA6B,CAAC,EAClD,aAAa,EACb,aAAa,EACb,QAAQ,GACT,EAAE,EAAE;IACH,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IAC/B,MAAM,cAAc,GAAG,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;IAE1C,OAAO,CACL,MAAC,GAAG,IACF,aAAa,EAAC,QAAQ,EACtB,MAAM,EAAE,cAAc,GAAG,CAAC,EAC1B,WAAW,EAAC,OAAO,EACnB,WAAW,EAAC,MAAM,EAClB,QAAQ,EAAE,CAAC,aAGX,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,UAAU,EAAE,CAAC,aACvC,KAAC,WAAW,KAAG,EACf,KAAC,OAAO,KAAG,EACV,aAAa,EACd,KAAC,OAAO,KAAG,IACP,EAGN,KAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,YACnD,QAAQ,GACL,EAGN,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,UAAU,EAAE,CAAC,aACvC,KAAC,OAAO,KAAG,EACV,aAAa,IACV,IACF,CACP,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ /**
3
+ * Horizontal divider for separating sections within a unified box
4
+ * Uses box-drawing characters for clean visual separation
5
+ * Automatically adjusts to terminal width
6
+ */
7
+ export declare const Divider: React.FC;
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Text } from 'ink';
3
+ import { useMemo } from 'react';
4
+ /**
5
+ * Horizontal divider for separating sections within a unified box
6
+ * Uses box-drawing characters for clean visual separation
7
+ * Automatically adjusts to terminal width
8
+ */
9
+ export const Divider = () => {
10
+ const dividerLine = useMemo(() => {
11
+ const terminalWidth = process.stdout.columns || 120;
12
+ // Account for box border (2 chars) and padding (2 chars)
13
+ const availableWidth = terminalWidth - 4;
14
+ // Create divider line that fits exactly
15
+ return '─'.repeat(Math.max(0, availableWidth));
16
+ }, []);
17
+ return _jsx(Text, { dimColor: true, children: dividerLine });
18
+ };
19
+ //# sourceMappingURL=Divider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Divider.js","sourceRoot":"","sources":["../../src/components/Divider.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC3B,OAAc,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEvC;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAa,GAAG,EAAE;IACpC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE;QAC/B,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,GAAG,CAAC;QACpD,yDAAyD;QACzD,MAAM,cAAc,GAAG,aAAa,GAAG,CAAC,CAAC;QACzC,wCAAwC;QACxC,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC;IACjD,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,KAAC,IAAI,IAAC,QAAQ,kBAAE,WAAW,GAAQ,CAAC;AAC7C,CAAC,CAAC"}
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import { type JournalFileInfo } from '../lib/storage/journal-storage.js';
3
+ interface JournalBrowserProps {
4
+ journals: JournalFileInfo[];
5
+ }
6
+ /**
7
+ * Journal browser - shows all journals with navigation.
8
+ *
9
+ * Uses AppLayout for consistent layout structure.
10
+ * Handles list navigation and state management.
11
+ * Can switch to viewer mode when opening a journal.
12
+ */
13
+ export declare const JournalBrowser: React.FC<JournalBrowserProps>;
14
+ export {};
@@ -0,0 +1,102 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text, useInput, useApp, useStdout } from 'ink';
3
+ import { useState } from 'react';
4
+ import { journalStore } from '../lib/storage/index.js';
5
+ import { getTodayDate } from '../utils/date.js';
6
+ import { AppLayout } from './AppLayout.js';
7
+ import { JournalList } from './JournalList.js';
8
+ import { JournalViewer } from './JournalViewer.js';
9
+ /**
10
+ * Journal browser - shows all journals with navigation.
11
+ *
12
+ * Uses AppLayout for consistent layout structure.
13
+ * Handles list navigation and state management.
14
+ * Can switch to viewer mode when opening a journal.
15
+ */
16
+ export const JournalBrowser = ({ journals }) => {
17
+ const { exit } = useApp();
18
+ const { stdout } = useStdout();
19
+ const [selectedIndex, setSelectedIndex] = useState(0);
20
+ const [viewMode, setViewMode] = useState('list');
21
+ const [viewerContent, setViewerContent] = useState('');
22
+ const [viewerDate, setViewerDate] = useState('');
23
+ const today = getTodayDate();
24
+ const terminalHeight = stdout?.rows || 24;
25
+ // Calculate available height for journal list
26
+ // Terminal height - header (logo 1 + divider 1 + title 1 + divider 1 = 4)
27
+ // - footer (divider 1 + shortcuts 1 = 2)
28
+ // - borders (2)
29
+ // - content margins (2)
30
+ const availableHeight = Math.max(5, terminalHeight - 10);
31
+ // Navigation handlers
32
+ const handleNavigateUp = () => {
33
+ setSelectedIndex((current) => {
34
+ const next = current - 1;
35
+ // Circular navigation: wrap to bottom if at top
36
+ return next < 0 ? journals.length - 1 : next;
37
+ });
38
+ };
39
+ const handleNavigateDown = () => {
40
+ setSelectedIndex((current) => {
41
+ const next = current + 1;
42
+ // Circular navigation: wrap to top if at bottom
43
+ return next >= journals.length ? 0 : next;
44
+ });
45
+ };
46
+ const handleOpenJournal = () => {
47
+ const journal = journals[selectedIndex];
48
+ if (journal) {
49
+ try {
50
+ const content = journalStore.load(journal.date);
51
+ if (content) {
52
+ setViewerDate(journal.date);
53
+ setViewerContent(content);
54
+ setViewMode('viewer');
55
+ }
56
+ }
57
+ catch (error) {
58
+ console.error(`Failed to load journal: ${error}`);
59
+ }
60
+ }
61
+ };
62
+ const handleBackToList = () => {
63
+ setViewMode('list');
64
+ setViewerContent('');
65
+ setViewerDate('');
66
+ };
67
+ // Keyboard input handlers (only for list view)
68
+ useInput((input, key) => {
69
+ // Only handle keyboard in list view
70
+ if (viewMode !== 'list')
71
+ return;
72
+ // Navigate up (↑ or k)
73
+ if (key.upArrow || input === 'k') {
74
+ handleNavigateUp();
75
+ return;
76
+ }
77
+ // Navigate down (↓ or j)
78
+ if (key.downArrow || input === 'j') {
79
+ handleNavigateDown();
80
+ return;
81
+ }
82
+ // Open journal (Enter)
83
+ if (key.return) {
84
+ handleOpenJournal();
85
+ return;
86
+ }
87
+ // Quit (q or Escape)
88
+ if (input === 'q' || key.escape) {
89
+ exit();
90
+ return;
91
+ }
92
+ });
93
+ // Viewer mode - show journal content
94
+ if (viewMode === 'viewer' && viewerDate && viewerContent) {
95
+ return (_jsx(JournalViewer, { date: viewerDate, content: viewerContent, onExit: handleBackToList }));
96
+ }
97
+ // List mode - show journal list
98
+ const headerContent = (_jsxs(Box, { children: [_jsx(Text, { bold: true, color: "cyan", children: "Browse Your Journals" }), _jsxs(Text, { dimColor: true, children: [" (", journals.length, " entries)"] })] }));
99
+ const footerContent = (_jsx(Text, { dimColor: true, children: "\u2191\u2193/jk Navigate \u2022 Enter Read \u2022 q Quit" }));
100
+ return (_jsx(AppLayout, { headerContent: headerContent, footerContent: footerContent, children: _jsx(JournalList, { journals: journals, selectedIndex: selectedIndex, todayDate: today, availableHeight: availableHeight }) }));
101
+ };
102
+ //# sourceMappingURL=JournalBrowser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JournalBrowser.js","sourceRoot":"","sources":["../../src/components/JournalBrowser.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAC7D,OAAc,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAExC,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAQnD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,cAAc,GAAkC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;IAC5E,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC;IAC1B,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IAE/B,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAW,MAAM,CAAC,CAAC;IAC3D,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvD,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAEjD,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAC7B,MAAM,cAAc,GAAG,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;IAE1C,8CAA8C;IAC9C,0EAA0E;IAC1E,yDAAyD;IACzD,gCAAgC;IAChC,wCAAwC;IACxC,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,GAAG,EAAE,CAAC,CAAC;IAEzD,sBAAsB;IACtB,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC5B,gBAAgB,CAAC,CAAC,OAAO,EAAE,EAAE;YAC3B,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,CAAC;YACzB,gDAAgD;YAChD,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,kBAAkB,GAAG,GAAG,EAAE;QAC9B,gBAAgB,CAAC,CAAC,OAAO,EAAE,EAAE;YAC3B,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,CAAC;YACzB,gDAAgD;YAChD,OAAO,IAAI,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,iBAAiB,GAAG,GAAG,EAAE;QAC7B,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAC;QACxC,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAChD,IAAI,OAAO,EAAE,CAAC;oBACZ,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;oBAC5B,gBAAgB,CAAC,OAAO,CAAC,CAAC;oBAC1B,WAAW,CAAC,QAAQ,CAAC,CAAC;gBACxB,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,2BAA2B,KAAK,EAAE,CAAC,CAAC;YACpD,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC5B,WAAW,CAAC,MAAM,CAAC,CAAC;QACpB,gBAAgB,CAAC,EAAE,CAAC,CAAC;QACrB,aAAa,CAAC,EAAE,CAAC,CAAC;IACpB,CAAC,CAAC;IAEF,+CAA+C;IAC/C,QAAQ,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACtB,oCAAoC;QACpC,IAAI,QAAQ,KAAK,MAAM;YAAE,OAAO;QAEhC,uBAAuB;QACvB,IAAI,GAAG,CAAC,OAAO,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;YACjC,gBAAgB,EAAE,CAAC;YACnB,OAAO;QACT,CAAC;QAED,yBAAyB;QACzB,IAAI,GAAG,CAAC,SAAS,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;YACnC,kBAAkB,EAAE,CAAC;YACrB,OAAO;QACT,CAAC;QAED,uBAAuB;QACvB,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YACf,iBAAiB,EAAE,CAAC;YACpB,OAAO;QACT,CAAC;QAED,qBAAqB;QACrB,IAAI,KAAK,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YAChC,IAAI,EAAE,CAAC;YACP,OAAO;QACT,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,qCAAqC;IACrC,IAAI,QAAQ,KAAK,QAAQ,IAAI,UAAU,IAAI,aAAa,EAAE,CAAC;QACzD,OAAO,CACL,KAAC,aAAa,IACZ,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,gBAAgB,GACxB,CACH,CAAC;IACJ,CAAC;IAED,gCAAgC;IAChC,MAAM,aAAa,GAAG,CACpB,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,MAAM,qCAEhB,EACP,MAAC,IAAI,IAAC,QAAQ,yBAAI,QAAQ,CAAC,MAAM,iBAAiB,IAC9C,CACP,CAAC;IAEF,MAAM,aAAa,GAAG,CACpB,KAAC,IAAI,IAAC,QAAQ,+EAA4C,CAC3D,CAAC;IAEF,OAAO,CACL,KAAC,SAAS,IAAC,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,YACnE,KAAC,WAAW,IACV,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,aAAa,EAC5B,SAAS,EAAE,KAAK,EAChB,eAAe,EAAE,eAAe,GAChC,GACQ,CACb,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import { type JournalFileInfo } from '../lib/storage/journal-storage.js';
3
+ interface JournalListProps {
4
+ journals: JournalFileInfo[];
5
+ selectedIndex: number;
6
+ todayDate: string;
7
+ availableHeight: number;
8
+ }
9
+ /**
10
+ * Journal list view with viewport-based rendering.
11
+ *
12
+ * Only renders journals that fit in the available height, centered around
13
+ * the selected item. Shows date and content preview for each journal.
14
+ */
15
+ export declare const JournalList: React.FC<JournalListProps>;
16
+ export {};
@@ -0,0 +1,73 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text, useStdout } from 'ink';
3
+ import { journalStore } from '../lib/storage/index.js';
4
+ import { formatDate } from '../utils/date.js';
5
+ import { extractPreview } from '../utils/journal-preview.js';
6
+ import { truncateToWidth, padToWidth } from '../utils/text.js';
7
+ // Column widths for alignment
8
+ const SELECTION_INDICATOR_WIDTH = 2; // "> " or " "
9
+ const DATE_COLUMN_WIDTH = 27; // "December 31, 2025 ●" = 20 chars + padding
10
+ const BORDER_AND_PADDING = 4; // Box borders and padding
11
+ /**
12
+ * Journal list view with viewport-based rendering.
13
+ *
14
+ * Only renders journals that fit in the available height, centered around
15
+ * the selected item. Shows date and content preview for each journal.
16
+ */
17
+ export const JournalList = ({ journals, selectedIndex, todayDate, availableHeight, }) => {
18
+ const { stdout } = useStdout();
19
+ const terminalWidth = stdout?.columns || 120;
20
+ // Calculate which journals to show (viewport around selection)
21
+ const getVisibleJournals = () => {
22
+ const maxItems = Math.max(3, availableHeight); // At least show 3 items
23
+ if (journals.length <= maxItems) {
24
+ // All journals fit, show everything
25
+ return { visible: journals, startIndex: 0 };
26
+ }
27
+ // Center the selection in the viewport
28
+ const halfWindow = Math.floor(maxItems / 2);
29
+ let start = selectedIndex - halfWindow;
30
+ // Keep viewport within bounds
31
+ if (start < 0) {
32
+ start = 0;
33
+ }
34
+ else if (start + maxItems > journals.length) {
35
+ start = journals.length - maxItems;
36
+ }
37
+ return {
38
+ visible: journals.slice(start, start + maxItems),
39
+ startIndex: start,
40
+ };
41
+ };
42
+ const { visible, startIndex } = getVisibleJournals();
43
+ // Calculate available width for preview
44
+ const availableWidthForPreview = terminalWidth -
45
+ SELECTION_INDICATOR_WIDTH -
46
+ DATE_COLUMN_WIDTH -
47
+ BORDER_AND_PADDING;
48
+ return (_jsx(Box, { flexDirection: "column", children: visible.map((journal, viewportIndex) => {
49
+ const actualIndex = startIndex + viewportIndex;
50
+ const isSelected = actualIndex === selectedIndex;
51
+ const isToday = journal.date === todayDate;
52
+ const formattedDate = formatDate(journal.date);
53
+ // Load journal content and extract preview
54
+ let preview = '';
55
+ try {
56
+ const content = journalStore.load(journal.date);
57
+ if (content) {
58
+ preview = extractPreview(content);
59
+ }
60
+ }
61
+ catch {
62
+ preview = '(error loading)';
63
+ }
64
+ // Format date with today indicator as one unit
65
+ const dateWithIndicator = isToday
66
+ ? `${formattedDate} ●`
67
+ : formattedDate;
68
+ const paddedDate = padToWidth(dateWithIndicator, DATE_COLUMN_WIDTH);
69
+ const truncatedPreview = truncateToWidth(preview, availableWidthForPreview);
70
+ return (_jsxs(Box, { children: [_jsx(Text, { color: isSelected ? 'cyan' : 'white', children: isSelected ? '> ' : ' ' }), _jsx(Text, { color: isSelected ? 'cyan' : 'white', children: paddedDate }), _jsx(Text, { dimColor: true, children: truncatedPreview })] }, journal.date));
71
+ }) }));
72
+ };
73
+ //# sourceMappingURL=JournalList.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JournalList.js","sourceRoot":"","sources":["../../src/components/JournalList.tsx"],"names":[],"mappings":"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"}
@@ -1,32 +1,14 @@
1
+ import React from 'react';
1
2
  interface JournalViewerProps {
2
3
  date: string;
3
4
  content: string;
4
5
  onExit?: () => void;
5
6
  }
6
7
  /**
7
- * Interactive journal viewer with keyboard navigation and scrolling.
8
+ * Journal viewer - displays full journal content with scrolling.
8
9
  *
9
- * Features:
10
- * - Virtual scrolling (only renders visible lines for performance)
11
- * - Horizontal panning for long lines (no text wrapping)
12
- * - Line numbers for easy reference
13
- * - Sticky header with date and position indicator
14
- * - Sticky footer with keyboard shortcuts
15
- * - Multiple navigation methods (arrows, vim keys, page up/down)
16
- *
17
- * Architecture:
18
- * 1. Split content into lines (memoized for performance)
19
- * 2. Calculate viewport dimensions based on terminal size
20
- * 3. Track scroll position (vertical and horizontal)
21
- * 4. Only render visible slice of content (virtual scrolling)
22
- * 5. Update scroll position on keyboard input
23
- *
24
- * Key Design Decisions:
25
- * - Each content line = 1 display row (no wrapping, use horizontal panning instead)
26
- * - Line numbers always correspond to content lines (1:1 mapping)
27
- * - Progress calculated from last visible line (shows 100% when viewing all content)
28
- * - Auto-reset horizontal position when moving vertically (better UX)
29
- * - React keys use line numbers (unique, stable identifiers)
10
+ * Uses AppLayout for consistent layout structure.
11
+ * Handles viewer-specific navigation and scrolling.
30
12
  */
31
- export declare const JournalViewer: ({ date, content, onExit, }: JournalViewerProps) => import("react/jsx-runtime").JSX.Element;
13
+ export declare const JournalViewer: React.FC<JournalViewerProps>;
32
14
  export {};