@rewrlution/papyrus-cli 0.0.4 → 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.
- package/README.md +4 -8
- package/dist/cli.js +0 -4
- package/dist/cli.js.map +1 -1
- package/dist/commands/auth/logout.js +2 -0
- package/dist/commands/auth/logout.js.map +1 -1
- package/dist/commands/journal/app.d.ts +1 -0
- package/dist/commands/journal/app.js +22 -0
- package/dist/commands/journal/app.js.map +1 -0
- package/dist/commands/journal/edit.js +8 -10
- package/dist/commands/journal/edit.js.map +1 -1
- package/dist/commands/journal/index.js +9 -10
- package/dist/commands/journal/index.js.map +1 -1
- package/dist/commands/journal/show.js +8 -14
- package/dist/commands/journal/show.js.map +1 -1
- package/dist/components/AppLayout.d.ts +32 -0
- package/dist/components/AppLayout.js +34 -0
- package/dist/components/AppLayout.js.map +1 -0
- package/dist/components/Divider.d.ts +7 -0
- package/dist/components/Divider.js +19 -0
- package/dist/components/Divider.js.map +1 -0
- package/dist/components/JournalBrowser.d.ts +14 -0
- package/dist/components/JournalBrowser.js +102 -0
- package/dist/components/JournalBrowser.js.map +1 -0
- package/dist/components/JournalList.d.ts +16 -0
- package/dist/components/JournalList.js +73 -0
- package/dist/components/JournalList.js.map +1 -0
- package/dist/components/JournalViewer.d.ts +5 -23
- package/dist/components/JournalViewer.js +73 -80
- package/dist/components/JournalViewer.js.map +1 -1
- package/dist/components/LoginForm.js +2 -2
- package/dist/components/LoginForm.js.map +1 -1
- package/dist/components/LogoCompact.d.ts +5 -0
- package/dist/components/LogoCompact.js +11 -0
- package/dist/components/LogoCompact.js.map +1 -0
- package/dist/components/RegisterForm.js +2 -2
- package/dist/components/RegisterForm.js.map +1 -1
- package/dist/components/StatusMessage.d.ts +2 -1
- package/dist/components/StatusMessage.js +3 -3
- package/dist/components/StatusMessage.js.map +1 -1
- package/dist/lib/api/index.js +1 -2
- package/dist/lib/api/index.js.map +1 -1
- package/dist/lib/auth/require-auth.js +4 -5
- package/dist/lib/auth/require-auth.js.map +1 -1
- package/dist/utils/alternate-screen.d.ts +46 -0
- package/dist/utils/alternate-screen.js +60 -0
- package/dist/utils/alternate-screen.js.map +1 -0
- package/dist/utils/date.js +3 -4
- package/dist/utils/date.js.map +1 -1
- package/dist/utils/editor.js +0 -1
- package/dist/utils/editor.js.map +1 -1
- package/dist/utils/journal-preview.d.ts +15 -0
- package/dist/utils/journal-preview.js +34 -0
- package/dist/utils/journal-preview.js.map +1 -0
- package/dist/utils/journal-preview.test.d.ts +1 -0
- package/dist/utils/journal-preview.test.js +62 -0
- package/dist/utils/journal-preview.test.js.map +1 -0
- package/dist/utils/messages.d.ts +43 -0
- package/dist/utils/messages.js +72 -0
- package/dist/utils/messages.js.map +1 -0
- package/dist/utils/text.d.ts +25 -0
- package/dist/utils/text.js +51 -0
- package/dist/utils/text.js.map +1 -0
- package/dist/utils/text.test.d.ts +1 -0
- package/dist/utils/text.test.js +47 -0
- package/dist/utils/text.test.js.map +1 -0
- package/package.json +3 -2
- package/dist/commands/journal/list.d.ts +0 -1
- package/dist/commands/journal/list.js +0 -20
- package/dist/commands/journal/list.js.map +0 -1
- package/dist/components/Browser.d.ts +0 -29
- package/dist/components/Browser.js +0 -124
- package/dist/components/Browser.js.map +0 -1
- package/dist/components/BrowserFooter.d.ts +0 -6
- package/dist/components/BrowserFooter.js +0 -6
- package/dist/components/BrowserFooter.js.map +0 -1
- package/dist/components/BrowserHeader.d.ts +0 -6
- package/dist/components/BrowserHeader.js +0 -6
- package/dist/components/BrowserHeader.js.map +0 -1
- package/dist/components/JournalListView.d.ts +0 -10
- package/dist/components/JournalListView.js +0 -40
- package/dist/components/JournalListView.js.map +0 -1
package/dist/utils/editor.js
CHANGED
|
@@ -52,7 +52,6 @@ export function openInEditor(content, baseFilename = 'papyrus.md') {
|
|
|
52
52
|
fs.writeFileSync(tempFile, content, 'utf-8');
|
|
53
53
|
try {
|
|
54
54
|
const editor = detectEditor();
|
|
55
|
-
console.log(`Opening in ${editor}...`);
|
|
56
55
|
// Determine args based on editor
|
|
57
56
|
const args = editor === 'code' ? ['--wait', tempFile] : [tempFile];
|
|
58
57
|
const result = spawnSync(editor, args, {
|
package/dist/utils/editor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor.js","sourceRoot":"","sources":["../../src/utils/editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;;;GAIG;AACH,MAAM,OAAO,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;AAEzD;;;;;GAKG;AACH,SAAS,UAAU,CAAC,MAAc;IAChC,OAAO,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,SAAS,CAAC;AACnD,CAAC;AAED,SAAS,WAAW,CAAC,MAAc;IACjC,uEAAuE;IACvE,IAAI,MAAM,KAAK,SAAS,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,oEAAoE;IACpE,yFAAyF;IACzF,4DAA4D;IAC5D,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,EAAE;QAC9C,KAAK,EAAE,QAAQ;QACf,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC;QACzB,OAAO,EAAE,IAAI;KACd,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;YACxB,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CACb,8EAA8E,CAC/E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,OAAe,EACf,eAAuB,YAAY;IAEnC,mBAAmB;IACnB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;IAC9C,MAAM,YAAY,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC3D,MAAM,cAAc,GAAG,GAAG,IAAI,IAAI,YAAY,GAAG,GAAG,EAAE,CAAC;IACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC,CAAC;IAExD,wBAAwB;IACxB,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAE7C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"editor.js","sourceRoot":"","sources":["../../src/utils/editor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract first non-empty line from journal content.
|
|
3
|
+
* Skips YAML frontmatter and returns the first line of actual content.
|
|
4
|
+
*
|
|
5
|
+
* @param content - Full journal content (may include frontmatter)
|
|
6
|
+
* @returns First non-empty content line, or "(empty)" if none found
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* extractPreview('---\ndate: 2025-01-01\n---\n\nHello World\n')
|
|
10
|
+
* // Returns: "Hello World"
|
|
11
|
+
*
|
|
12
|
+
* extractPreview('---\ndate: 2025-01-01\n---\n\n')
|
|
13
|
+
* // Returns: "(empty)"
|
|
14
|
+
*/
|
|
15
|
+
export declare function extractPreview(content: string): string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract first non-empty line from journal content.
|
|
3
|
+
* Skips YAML frontmatter and returns the first line of actual content.
|
|
4
|
+
*
|
|
5
|
+
* @param content - Full journal content (may include frontmatter)
|
|
6
|
+
* @returns First non-empty content line, or "(empty)" if none found
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* extractPreview('---\ndate: 2025-01-01\n---\n\nHello World\n')
|
|
10
|
+
* // Returns: "Hello World"
|
|
11
|
+
*
|
|
12
|
+
* extractPreview('---\ndate: 2025-01-01\n---\n\n')
|
|
13
|
+
* // Returns: "(empty)"
|
|
14
|
+
*/
|
|
15
|
+
export function extractPreview(content) {
|
|
16
|
+
const lines = content.split('\n');
|
|
17
|
+
// Skip frontmatter (between --- markers)
|
|
18
|
+
let inFrontmatter = false;
|
|
19
|
+
for (const line of lines) {
|
|
20
|
+
if (line.trim() === '---') {
|
|
21
|
+
inFrontmatter = !inFrontmatter;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (inFrontmatter)
|
|
25
|
+
continue;
|
|
26
|
+
// Return first non-empty line
|
|
27
|
+
const trimmed = line.trim();
|
|
28
|
+
if (trimmed) {
|
|
29
|
+
return trimmed;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return '(empty)';
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=journal-preview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journal-preview.js","sourceRoot":"","sources":["../../src/utils/journal-preview.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAElC,yCAAyC;IACzC,IAAI,aAAa,GAAG,KAAK,CAAC;IAC1B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC;YAC1B,aAAa,GAAG,CAAC,aAAa,CAAC;YAC/B,SAAS;QACX,CAAC;QACD,IAAI,aAAa;YAAE,SAAS;QAE5B,8BAA8B;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,OAAO,CAAC;QACjB,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { extractPreview } from './journal-preview.js';
|
|
3
|
+
describe('extractPreview', () => {
|
|
4
|
+
it('should extract first line after frontmatter', () => {
|
|
5
|
+
const content = `---
|
|
6
|
+
created_at: "2025-01-01T00:00:00Z"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
This is the first line
|
|
10
|
+
This is the second line`;
|
|
11
|
+
expect(extractPreview(content)).toBe('This is the first line');
|
|
12
|
+
});
|
|
13
|
+
it('should skip empty lines after frontmatter', () => {
|
|
14
|
+
const content = `---
|
|
15
|
+
created_at: "2025-01-01T00:00:00Z"
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
This is the first line`;
|
|
21
|
+
expect(extractPreview(content)).toBe('This is the first line');
|
|
22
|
+
});
|
|
23
|
+
it('should work with content without frontmatter', () => {
|
|
24
|
+
const content = `This is the first line
|
|
25
|
+
This is the second line`;
|
|
26
|
+
expect(extractPreview(content)).toBe('This is the first line');
|
|
27
|
+
});
|
|
28
|
+
it('should return "(empty)" for empty content', () => {
|
|
29
|
+
expect(extractPreview('')).toBe('(empty)');
|
|
30
|
+
});
|
|
31
|
+
it('should return "(empty)" for content with only frontmatter', () => {
|
|
32
|
+
const content = `---
|
|
33
|
+
created_at: "2025-01-01T00:00:00Z"
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
`;
|
|
37
|
+
expect(extractPreview(content)).toBe('(empty)');
|
|
38
|
+
});
|
|
39
|
+
it('should return "(empty)" for content with only whitespace', () => {
|
|
40
|
+
const content = `
|
|
41
|
+
|
|
42
|
+
`;
|
|
43
|
+
expect(extractPreview(content)).toBe('(empty)');
|
|
44
|
+
});
|
|
45
|
+
it('should handle CJK characters', () => {
|
|
46
|
+
const content = `---
|
|
47
|
+
created_at: "2025-01-01T00:00:00Z"
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
今日はとても良い天気でした`;
|
|
51
|
+
expect(extractPreview(content)).toBe('今日はとても良い天気でした');
|
|
52
|
+
});
|
|
53
|
+
it('should handle emoji', () => {
|
|
54
|
+
const content = `---
|
|
55
|
+
created_at: "2025-01-01T00:00:00Z"
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
🎉 Today was a great day!`;
|
|
59
|
+
expect(extractPreview(content)).toBe('🎉 Today was a great day!');
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
//# sourceMappingURL=journal-preview.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journal-preview.test.js","sourceRoot":"","sources":["../../src/utils/journal-preview.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,OAAO,GAAG;;;;;wBAKI,CAAC;QAErB,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,OAAO,GAAG;;;;;;uBAMG,CAAC;QAEpB,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,OAAO,GAAG;wBACI,CAAC;QAErB,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,OAAO,GAAG;;;;CAInB,CAAC;QAEE,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,OAAO,GAAG;;KAEf,CAAC;QAEF,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,OAAO,GAAG;;;;cAIN,CAAC;QAEX,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,OAAO,GAAG;;;;0BAIM,CAAC;QAEvB,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consistent messaging utilities for non-interactive console output.
|
|
3
|
+
*
|
|
4
|
+
* Use these functions for simple, transactional commands (logout, edit, etc.)
|
|
5
|
+
* For interactive/rich UI, use Ink components (StatusMessage, SyncProgress, etc.)
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Display a success message with compact spacing
|
|
9
|
+
* @param message The success message to display
|
|
10
|
+
*/
|
|
11
|
+
export declare function success(message: string): void;
|
|
12
|
+
/**
|
|
13
|
+
* Display an error message with optional hint, then exit
|
|
14
|
+
* @param message The error message to display
|
|
15
|
+
* @param hint Optional hint message to help the user
|
|
16
|
+
* @param exitCode Exit code (default: 1)
|
|
17
|
+
*/
|
|
18
|
+
export declare function error(message: string, hint?: string, exitCode?: number): never;
|
|
19
|
+
/**
|
|
20
|
+
* Display an informational message with compact spacing
|
|
21
|
+
* @param message The info message to display
|
|
22
|
+
*/
|
|
23
|
+
export declare function info(message: string): void;
|
|
24
|
+
/**
|
|
25
|
+
* Display a warning message with compact spacing (non-fatal)
|
|
26
|
+
* @param message The warning message to display
|
|
27
|
+
*/
|
|
28
|
+
export declare function warn(message: string): void;
|
|
29
|
+
/**
|
|
30
|
+
* Display a hint/tip message with compact spacing
|
|
31
|
+
* @param message The hint message to display
|
|
32
|
+
*/
|
|
33
|
+
export declare function hint(message: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* Display statistics or metrics with compact spacing
|
|
36
|
+
* @param message The stats message to display
|
|
37
|
+
*/
|
|
38
|
+
export declare function stats(message: string): void;
|
|
39
|
+
/**
|
|
40
|
+
* Display a special/celebratory message (e.g., first-time creation)
|
|
41
|
+
* @param message The message to display
|
|
42
|
+
*/
|
|
43
|
+
export declare function sparkles(message: string): void;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consistent messaging utilities for non-interactive console output.
|
|
3
|
+
*
|
|
4
|
+
* Use these functions for simple, transactional commands (logout, edit, etc.)
|
|
5
|
+
* For interactive/rich UI, use Ink components (StatusMessage, SyncProgress, etc.)
|
|
6
|
+
*/
|
|
7
|
+
const icons = {
|
|
8
|
+
success: '✅',
|
|
9
|
+
error: '❌',
|
|
10
|
+
info: '📖',
|
|
11
|
+
warning: '⚠️',
|
|
12
|
+
hint: '💡',
|
|
13
|
+
stats: '📊',
|
|
14
|
+
sparkles: '✨',
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Display a success message with compact spacing
|
|
18
|
+
* @param message The success message to display
|
|
19
|
+
*/
|
|
20
|
+
export function success(message) {
|
|
21
|
+
console.log(`${icons.success} ${message}`);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Display an error message with optional hint, then exit
|
|
25
|
+
* @param message The error message to display
|
|
26
|
+
* @param hint Optional hint message to help the user
|
|
27
|
+
* @param exitCode Exit code (default: 1)
|
|
28
|
+
*/
|
|
29
|
+
export function error(message, hint, exitCode = 1) {
|
|
30
|
+
console.error(`${icons.error} ${message}`);
|
|
31
|
+
if (hint) {
|
|
32
|
+
console.error(`${icons.hint} ${hint}`);
|
|
33
|
+
}
|
|
34
|
+
console.error('');
|
|
35
|
+
process.exit(exitCode);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Display an informational message with compact spacing
|
|
39
|
+
* @param message The info message to display
|
|
40
|
+
*/
|
|
41
|
+
export function info(message) {
|
|
42
|
+
console.log(`${icons.info} ${message}`);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Display a warning message with compact spacing (non-fatal)
|
|
46
|
+
* @param message The warning message to display
|
|
47
|
+
*/
|
|
48
|
+
export function warn(message) {
|
|
49
|
+
console.warn(`${icons.warning} ${message}`);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Display a hint/tip message with compact spacing
|
|
53
|
+
* @param message The hint message to display
|
|
54
|
+
*/
|
|
55
|
+
export function hint(message) {
|
|
56
|
+
console.log(`${icons.hint} ${message}`);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Display statistics or metrics with compact spacing
|
|
60
|
+
* @param message The stats message to display
|
|
61
|
+
*/
|
|
62
|
+
export function stats(message) {
|
|
63
|
+
console.log(`${icons.stats} ${message}`);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Display a special/celebratory message (e.g., first-time creation)
|
|
67
|
+
* @param message The message to display
|
|
68
|
+
*/
|
|
69
|
+
export function sparkles(message) {
|
|
70
|
+
console.log(`${icons.sparkles} ${message}`);
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/utils/messages.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,KAAK,GAAG;IACZ,OAAO,EAAE,GAAG;IACZ,KAAK,EAAE,GAAG;IACV,IAAI,EAAE,IAAI;IACV,OAAO,EAAE,IAAI;IACb,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,IAAI;IACX,QAAQ,EAAE,GAAG;CACL,CAAC;AAEX;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,OAAe;IACrC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,OAAO,IAAI,OAAO,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,KAAK,CACnB,OAAe,EACf,IAAa,EACb,WAAmB,CAAC;IAEpB,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,KAAK,IAAI,OAAO,EAAE,CAAC,CAAC;IAC3C,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,IAAI,CAAC,OAAe;IAClC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,IAAI,OAAO,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,IAAI,CAAC,OAAe;IAClC,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,OAAO,IAAI,OAAO,EAAE,CAAC,CAAC;AAC9C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,IAAI,CAAC,OAAe;IAClC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,IAAI,OAAO,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,KAAK,CAAC,OAAe;IACnC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,IAAI,OAAO,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAe;IACtC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,QAAQ,IAAI,OAAO,EAAE,CAAC,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Truncate text to fit within maxWidth, handling wide characters.
|
|
3
|
+
* Uses string-width to properly measure CJK and emoji characters.
|
|
4
|
+
*
|
|
5
|
+
* @param text - The text to truncate
|
|
6
|
+
* @param maxWidth - Maximum width in columns
|
|
7
|
+
* @returns Truncated text with ellipsis if needed
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* truncateToWidth('Hello World', 8) // "Hello W…"
|
|
11
|
+
* truncateToWidth('你好世界', 6) // "你好…" (CJK chars are 2 columns each)
|
|
12
|
+
*/
|
|
13
|
+
export declare function truncateToWidth(text: string, maxWidth: number): string;
|
|
14
|
+
/**
|
|
15
|
+
* Pad text to exact width, handling wide characters.
|
|
16
|
+
*
|
|
17
|
+
* @param text - The text to pad
|
|
18
|
+
* @param targetWidth - Target width in columns
|
|
19
|
+
* @returns Padded text (or truncated if too long)
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* padToWidth('Hello', 10) // "Hello " (5 spaces added)
|
|
23
|
+
* padToWidth('你好', 6) // "你好 " (2 spaces added, CJK chars are 2 columns each)
|
|
24
|
+
*/
|
|
25
|
+
export declare function padToWidth(text: string, targetWidth: number): string;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import stringWidth from 'string-width';
|
|
2
|
+
/**
|
|
3
|
+
* Truncate text to fit within maxWidth, handling wide characters.
|
|
4
|
+
* Uses string-width to properly measure CJK and emoji characters.
|
|
5
|
+
*
|
|
6
|
+
* @param text - The text to truncate
|
|
7
|
+
* @param maxWidth - Maximum width in columns
|
|
8
|
+
* @returns Truncated text with ellipsis if needed
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* truncateToWidth('Hello World', 8) // "Hello W…"
|
|
12
|
+
* truncateToWidth('你好世界', 6) // "你好…" (CJK chars are 2 columns each)
|
|
13
|
+
*/
|
|
14
|
+
export function truncateToWidth(text, maxWidth) {
|
|
15
|
+
if (maxWidth <= 0)
|
|
16
|
+
return '';
|
|
17
|
+
const width = stringWidth(text);
|
|
18
|
+
if (width <= maxWidth) {
|
|
19
|
+
return text;
|
|
20
|
+
}
|
|
21
|
+
// Build string char by char, checking width
|
|
22
|
+
let result = '';
|
|
23
|
+
for (const char of text) {
|
|
24
|
+
const testStr = result + char;
|
|
25
|
+
if (stringWidth(testStr) > maxWidth - 1) {
|
|
26
|
+
// -1 for ellipsis
|
|
27
|
+
return result + '…';
|
|
28
|
+
}
|
|
29
|
+
result = testStr;
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Pad text to exact width, handling wide characters.
|
|
35
|
+
*
|
|
36
|
+
* @param text - The text to pad
|
|
37
|
+
* @param targetWidth - Target width in columns
|
|
38
|
+
* @returns Padded text (or truncated if too long)
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* padToWidth('Hello', 10) // "Hello " (5 spaces added)
|
|
42
|
+
* padToWidth('你好', 6) // "你好 " (2 spaces added, CJK chars are 2 columns each)
|
|
43
|
+
*/
|
|
44
|
+
export function padToWidth(text, targetWidth) {
|
|
45
|
+
const width = stringWidth(text);
|
|
46
|
+
if (width >= targetWidth) {
|
|
47
|
+
return truncateToWidth(text, targetWidth);
|
|
48
|
+
}
|
|
49
|
+
return text + ' '.repeat(targetWidth - width);
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/utils/text.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,cAAc,CAAC;AAEvC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,QAAgB;IAC5D,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAE7B,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,KAAK,IAAI,QAAQ,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,4CAA4C;IAC5C,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC;QAC9B,IAAI,WAAW,CAAC,OAAO,CAAC,GAAG,QAAQ,GAAG,CAAC,EAAE,CAAC;YACxC,kBAAkB;YAClB,OAAO,MAAM,GAAG,GAAG,CAAC;QACtB,CAAC;QACD,MAAM,GAAG,OAAO,CAAC;IACnB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,WAAmB;IAC1D,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,KAAK,IAAI,WAAW,EAAE,CAAC;QACzB,OAAO,eAAe,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,GAAG,KAAK,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { truncateToWidth, padToWidth } from './text.js';
|
|
3
|
+
describe('truncateToWidth', () => {
|
|
4
|
+
it('should return text as-is when it fits', () => {
|
|
5
|
+
expect(truncateToWidth('Hello', 10)).toBe('Hello');
|
|
6
|
+
});
|
|
7
|
+
it('should truncate text with ellipsis when too long', () => {
|
|
8
|
+
expect(truncateToWidth('Hello World', 8)).toBe('Hello W…');
|
|
9
|
+
});
|
|
10
|
+
it('should handle empty string', () => {
|
|
11
|
+
expect(truncateToWidth('', 5)).toBe('');
|
|
12
|
+
});
|
|
13
|
+
it('should handle zero maxWidth', () => {
|
|
14
|
+
expect(truncateToWidth('Hello', 0)).toBe('');
|
|
15
|
+
});
|
|
16
|
+
it('should handle CJK characters (wide chars)', () => {
|
|
17
|
+
// 你好 = 2 chars × 2 columns = 4 columns
|
|
18
|
+
expect(truncateToWidth('你好世界', 5)).toBe('你好…');
|
|
19
|
+
});
|
|
20
|
+
it('should handle emoji (wide chars)', () => {
|
|
21
|
+
// 👋 = 2 columns, space = 1, 'He' = 2, ellipsis = 1 → total 6
|
|
22
|
+
expect(truncateToWidth('👋 Hello', 6)).toBe('👋 He…');
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
describe('padToWidth', () => {
|
|
26
|
+
it('should pad text with spaces to reach target width', () => {
|
|
27
|
+
expect(padToWidth('Hello', 10)).toBe('Hello ');
|
|
28
|
+
});
|
|
29
|
+
it('should return text as-is when already at target width', () => {
|
|
30
|
+
expect(padToWidth('Hello', 5)).toBe('Hello');
|
|
31
|
+
});
|
|
32
|
+
it('should truncate text when too long', () => {
|
|
33
|
+
expect(padToWidth('Hello World', 8)).toBe('Hello W…');
|
|
34
|
+
});
|
|
35
|
+
it('should handle empty string', () => {
|
|
36
|
+
expect(padToWidth('', 5)).toBe(' ');
|
|
37
|
+
});
|
|
38
|
+
it('should handle CJK characters (wide chars)', () => {
|
|
39
|
+
// 你好 = 2 chars × 2 columns = 4 columns, need 2 more spaces to reach 6
|
|
40
|
+
expect(padToWidth('你好', 6)).toBe('你好 ');
|
|
41
|
+
});
|
|
42
|
+
it('should handle emoji (wide chars)', () => {
|
|
43
|
+
// 👋 = 2 columns, need 3 more spaces to reach 5
|
|
44
|
+
expect(padToWidth('👋', 5)).toBe('👋 ');
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=text.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.test.js","sourceRoot":"","sources":["../../src/utils/text.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAExD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,eAAe,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,eAAe,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,uCAAuC;QACvC,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,8DAA8D;QAC9D,MAAM,CAAC,eAAe,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,sEAAsE;QACtE,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,gDAAgD;QAChD,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rewrlution/papyrus-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "AI-powered developer journaling CLI",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"journal",
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
},
|
|
14
14
|
"type": "module",
|
|
15
15
|
"bin": {
|
|
16
|
-
"pp": "./dist/cli.js",
|
|
17
16
|
"paper": "./dist/cli.js",
|
|
18
17
|
"papyrus": "./dist/cli.js"
|
|
19
18
|
},
|
|
@@ -25,6 +24,7 @@
|
|
|
25
24
|
"LICENSE"
|
|
26
25
|
],
|
|
27
26
|
"dependencies": {
|
|
27
|
+
"ansi-escapes": "^7.2.0",
|
|
28
28
|
"axios": "^1.13.2",
|
|
29
29
|
"chalk": "^5.6.2",
|
|
30
30
|
"commander": "^14.0.2",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"ink-text-input": "^6.0.0",
|
|
37
37
|
"jwt-decode": "^4.0.0",
|
|
38
38
|
"react": "^19.2.3",
|
|
39
|
+
"string-width": "^8.1.0",
|
|
39
40
|
"@rewrlution/papyrus-shared": "0.0.1"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function listEntries(): Promise<void>;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { render } from 'ink';
|
|
3
|
-
import React from 'react';
|
|
4
|
-
import { Browser } from '../../components/Browser.js';
|
|
5
|
-
import { journalStore } from '../../lib/storage/index.js';
|
|
6
|
-
export async function listEntries() {
|
|
7
|
-
try {
|
|
8
|
-
// Load all journal entries
|
|
9
|
-
const journals = journalStore.list();
|
|
10
|
-
// Render the interactive browser
|
|
11
|
-
const { waitUntilExit } = render(React.createElement(Browser, { journals }));
|
|
12
|
-
await waitUntilExit();
|
|
13
|
-
}
|
|
14
|
-
catch (error) {
|
|
15
|
-
console.error(`\n❌ Error: Failed to list journal entries`);
|
|
16
|
-
console.error(`${error.message}\n`);
|
|
17
|
-
process.exit(1);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
//# sourceMappingURL=list.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/commands/journal/list.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC;QACH,2BAA2B;QAC3B,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC;QAErC,iCAAiC;QACjC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAC9B,KAAK,CAAC,aAAa,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,CAAC,CAC3C,CAAC;QAEF,MAAM,aAAa,EAAE,CAAC;IACxB,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC3D,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { type JournalFileInfo } from '../lib/storage/journal-storage.js';
|
|
3
|
-
interface BrowserProps {
|
|
4
|
-
journals: JournalFileInfo[];
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* Interactive browser for navigating and reading journal entries.
|
|
8
|
-
*
|
|
9
|
-
* Features:
|
|
10
|
-
* - List view with keyboard navigation (↑/↓ or j/k)
|
|
11
|
-
* - Reader view with full journal content
|
|
12
|
-
* - Circular navigation (wrap around at top/bottom)
|
|
13
|
-
* - Today marker for current date's entry
|
|
14
|
-
* - Virtual scrolling for large journal collections
|
|
15
|
-
* - Press Enter to read, q to return to list or quit
|
|
16
|
-
*
|
|
17
|
-
* Architecture:
|
|
18
|
-
* 1. BrowserHeader - Shows total journal count
|
|
19
|
-
* 2. JournalListView - Virtual scrolling list of journals
|
|
20
|
-
* 3. BrowserFooter - Keyboard shortcuts reference
|
|
21
|
-
* 4. JournalViewer - Full journal reader (opens when selecting entry)
|
|
22
|
-
*
|
|
23
|
-
* State Management:
|
|
24
|
-
* - viewMode: 'list' | 'reader' - Current view
|
|
25
|
-
* - selectedIndex: number - Currently selected journal in list
|
|
26
|
-
* - selectedJournal: JournalFileInfo | null - Journal being read
|
|
27
|
-
*/
|
|
28
|
-
export declare const Browser: React.FC<BrowserProps>;
|
|
29
|
-
export {};
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Box, Text, useInput, useApp } from 'ink';
|
|
3
|
-
import { useState } from 'react';
|
|
4
|
-
import { journalStore } from '../lib/storage/index.js';
|
|
5
|
-
import { getTodayDate } from '../utils/date.js';
|
|
6
|
-
import { BrowserFooter } from './BrowserFooter.js';
|
|
7
|
-
import { BrowserHeader } from './BrowserHeader.js';
|
|
8
|
-
import { JournalListView } from './JournalListView.js';
|
|
9
|
-
import { JournalViewer } from './JournalViewer.js';
|
|
10
|
-
/**
|
|
11
|
-
* Interactive browser for navigating and reading journal entries.
|
|
12
|
-
*
|
|
13
|
-
* Features:
|
|
14
|
-
* - List view with keyboard navigation (↑/↓ or j/k)
|
|
15
|
-
* - Reader view with full journal content
|
|
16
|
-
* - Circular navigation (wrap around at top/bottom)
|
|
17
|
-
* - Today marker for current date's entry
|
|
18
|
-
* - Virtual scrolling for large journal collections
|
|
19
|
-
* - Press Enter to read, q to return to list or quit
|
|
20
|
-
*
|
|
21
|
-
* Architecture:
|
|
22
|
-
* 1. BrowserHeader - Shows total journal count
|
|
23
|
-
* 2. JournalListView - Virtual scrolling list of journals
|
|
24
|
-
* 3. BrowserFooter - Keyboard shortcuts reference
|
|
25
|
-
* 4. JournalViewer - Full journal reader (opens when selecting entry)
|
|
26
|
-
*
|
|
27
|
-
* State Management:
|
|
28
|
-
* - viewMode: 'list' | 'reader' - Current view
|
|
29
|
-
* - selectedIndex: number - Currently selected journal in list
|
|
30
|
-
* - selectedJournal: JournalFileInfo | null - Journal being read
|
|
31
|
-
*/
|
|
32
|
-
export const Browser = ({ journals }) => {
|
|
33
|
-
// State management
|
|
34
|
-
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
35
|
-
const [viewMode, setViewMode] = useState('list');
|
|
36
|
-
const [selectedJournal, setSelectedJournal] = useState(null);
|
|
37
|
-
const [journalContent, setJournalContent] = useState('');
|
|
38
|
-
const { exit } = useApp();
|
|
39
|
-
const today = getTodayDate();
|
|
40
|
-
// Keyboard input handlers
|
|
41
|
-
useInput((input, key) => {
|
|
42
|
-
// Handle list view navigation
|
|
43
|
-
if (viewMode === 'list') {
|
|
44
|
-
// Navigate up (↑ or k)
|
|
45
|
-
if (key.upArrow || input === 'k') {
|
|
46
|
-
handleNavigateUp();
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
// Navigate down (↓ or j)
|
|
50
|
-
if (key.downArrow || input === 'j') {
|
|
51
|
-
handleNavigateDown();
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
// Open journal (Enter or Space)
|
|
55
|
-
if (key.return || input === ' ') {
|
|
56
|
-
handleOpenJournal();
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
// Quit from list view (q or Escape)
|
|
60
|
-
if (input === 'q' || key.escape) {
|
|
61
|
-
exit();
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
// Note: Reader view keyboard handling is done by JournalViewer component
|
|
66
|
-
// It will call handleBackToList() when user presses 'q'
|
|
67
|
-
});
|
|
68
|
-
// Navigation handlers
|
|
69
|
-
const handleNavigateUp = () => {
|
|
70
|
-
setSelectedIndex((current) => {
|
|
71
|
-
const next = current - 1;
|
|
72
|
-
// Circular navigation: if at top, wrap to bottom
|
|
73
|
-
if (next < 0) {
|
|
74
|
-
return journals.length - 1;
|
|
75
|
-
}
|
|
76
|
-
return next;
|
|
77
|
-
});
|
|
78
|
-
};
|
|
79
|
-
const handleNavigateDown = () => {
|
|
80
|
-
setSelectedIndex((current) => {
|
|
81
|
-
const next = current + 1;
|
|
82
|
-
// Circular navigation: if at bottom, wrap to top
|
|
83
|
-
if (next >= journals.length) {
|
|
84
|
-
return 0;
|
|
85
|
-
}
|
|
86
|
-
return next;
|
|
87
|
-
});
|
|
88
|
-
};
|
|
89
|
-
const handleOpenJournal = () => {
|
|
90
|
-
const journal = journals[selectedIndex];
|
|
91
|
-
if (journal) {
|
|
92
|
-
try {
|
|
93
|
-
// Load journal content
|
|
94
|
-
const content = journalStore.load(journal.date);
|
|
95
|
-
if (content) {
|
|
96
|
-
setSelectedJournal(journal);
|
|
97
|
-
setJournalContent(content);
|
|
98
|
-
setViewMode('reader');
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
catch (error) {
|
|
102
|
-
// If loading fails, stay in list view
|
|
103
|
-
// The error will be visible in the console
|
|
104
|
-
console.error(`Failed to load journal: ${error}`);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
const handleBackToList = () => {
|
|
109
|
-
setViewMode('list');
|
|
110
|
-
setSelectedJournal(null);
|
|
111
|
-
setJournalContent('');
|
|
112
|
-
};
|
|
113
|
-
// Empty state
|
|
114
|
-
if (journals.length === 0) {
|
|
115
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", padding: 1, children: [_jsx(Text, { color: "yellow", children: "No journal entries yet." }), _jsx(Text, { dimColor: true, children: " Run 'papyrus add' to create your first entry." }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Press 'q' to quit" }) })] }));
|
|
116
|
-
}
|
|
117
|
-
// Reader view
|
|
118
|
-
if (viewMode === 'reader' && selectedJournal) {
|
|
119
|
-
return (_jsx(JournalViewer, { date: selectedJournal.date, content: journalContent, onExit: handleBackToList }));
|
|
120
|
-
}
|
|
121
|
-
// List view (default)
|
|
122
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(BrowserHeader, { totalJournals: journals.length }), _jsx(JournalListView, { journals: journals, selectedIndex: selectedIndex, todayDate: today, windowSize: 10 }), _jsx(BrowserFooter, { shortcuts: "\u2191\u2193/jk Navigate \u2022 Enter Read \u2022 q Quit" })] }));
|
|
123
|
-
};
|
|
124
|
-
//# sourceMappingURL=Browser.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Browser.js","sourceRoot":"","sources":["../../src/components/Browser.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAClD,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,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAQnD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,OAAO,GAA2B,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;IAC9D,mBAAmB;IACnB,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,eAAe,EAAE,kBAAkB,CAAC,GACzC,QAAQ,CAAyB,IAAI,CAAC,CAAC;IACzC,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAS,EAAE,CAAC,CAAC;IAEjE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC;IAC1B,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAE7B,0BAA0B;IAC1B,QAAQ,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACtB,8BAA8B;QAC9B,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;YACxB,uBAAuB;YACvB,IAAI,GAAG,CAAC,OAAO,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;gBACjC,gBAAgB,EAAE,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,yBAAyB;YACzB,IAAI,GAAG,CAAC,SAAS,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;gBACnC,kBAAkB,EAAE,CAAC;gBACrB,OAAO;YACT,CAAC;YAED,gCAAgC;YAChC,IAAI,GAAG,CAAC,MAAM,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;gBAChC,iBAAiB,EAAE,CAAC;gBACpB,OAAO;YACT,CAAC;YAED,oCAAoC;YACpC,IAAI,KAAK,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;gBAChC,IAAI,EAAE,CAAC;gBACP,OAAO;YACT,CAAC;QACH,CAAC;QAED,yEAAyE;QACzE,wDAAwD;IAC1D,CAAC,CAAC,CAAC;IAEH,sBAAsB;IACtB,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC5B,gBAAgB,CAAC,CAAC,OAAO,EAAE,EAAE;YAC3B,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,CAAC;YACzB,iDAAiD;YACjD,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;gBACb,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;YAC7B,CAAC;YACD,OAAO,IAAI,CAAC;QACd,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,iDAAiD;YACjD,IAAI,IAAI,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;gBAC5B,OAAO,CAAC,CAAC;YACX,CAAC;YACD,OAAO,IAAI,CAAC;QACd,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,uBAAuB;gBACvB,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAChD,IAAI,OAAO,EAAE,CAAC;oBACZ,kBAAkB,CAAC,OAAO,CAAC,CAAC;oBAC5B,iBAAiB,CAAC,OAAO,CAAC,CAAC;oBAC3B,WAAW,CAAC,QAAQ,CAAC,CAAC;gBACxB,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,sCAAsC;gBACtC,2CAA2C;gBAC3C,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,kBAAkB,CAAC,IAAI,CAAC,CAAC;QACzB,iBAAiB,CAAC,EAAE,CAAC,CAAC;IACxB,CAAC,CAAC;IAEF,cAAc;IACd,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,WAAW,EAAC,OAAO,EAAC,OAAO,EAAE,CAAC,aACxD,KAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,wCAA+B,EACnD,KAAC,IAAI,IAAC,QAAQ,qEAAsD,EACpE,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,IAAI,IAAC,QAAQ,wCAAyB,GACnC,IACF,CACP,CAAC;IACJ,CAAC;IAED,cAAc;IACd,IAAI,QAAQ,KAAK,QAAQ,IAAI,eAAe,EAAE,CAAC;QAC7C,OAAO,CACL,KAAC,aAAa,IACZ,IAAI,EAAE,eAAe,CAAC,IAAI,EAC1B,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,gBAAgB,GACxB,CACH,CAAC;IACJ,CAAC;IAED,sBAAsB;IACtB,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,KAAC,aAAa,IAAC,aAAa,EAAE,QAAQ,CAAC,MAAM,GAAI,EAEjD,KAAC,eAAe,IACd,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,aAAa,EAC5B,SAAS,EAAE,KAAK,EAChB,UAAU,EAAE,EAAE,GACd,EAEF,KAAC,aAAa,IAAC,SAAS,EAAC,0DAAsC,GAAG,IAC9D,CACP,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { Box, Text } from 'ink';
|
|
3
|
-
export const BrowserFooter = ({ shortcuts }) => {
|
|
4
|
-
return (_jsx(Box, { marginTop: 1, borderStyle: "round", borderColor: "gray", paddingX: 1, children: _jsx(Text, { dimColor: true, children: shortcuts }) }));
|
|
5
|
-
};
|
|
6
|
-
//# sourceMappingURL=BrowserFooter.js.map
|