@tooee/view 0.1.0

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.
@@ -0,0 +1,61 @@
1
+ import { readdirSync, statSync } from "fs";
2
+ import { join } from "path";
3
+ import { createFileProvider } from "./default-provider.js";
4
+ const SUPPORTED_EXTENSIONS = new Set([
5
+ "md",
6
+ "mdx",
7
+ "markdown",
8
+ "ts",
9
+ "tsx",
10
+ "js",
11
+ "jsx",
12
+ "json",
13
+ "txt",
14
+ "css",
15
+ "html",
16
+ "yaml",
17
+ "yml",
18
+ "toml",
19
+ "sh",
20
+ "bash",
21
+ "zsh",
22
+ "go",
23
+ "rs",
24
+ "py",
25
+ "rb",
26
+ "c",
27
+ "cpp",
28
+ "h",
29
+ "hpp",
30
+ "java",
31
+ "kt",
32
+ "swift",
33
+ "sql",
34
+ ]);
35
+ export function listDirectoryFiles(dirPath) {
36
+ const entries = readdirSync(dirPath);
37
+ const files = [];
38
+ for (const entry of entries) {
39
+ if (entry.startsWith("."))
40
+ continue;
41
+ const fullPath = join(dirPath, entry);
42
+ try {
43
+ const stat = statSync(fullPath);
44
+ if (!stat.isFile())
45
+ continue;
46
+ }
47
+ catch {
48
+ continue;
49
+ }
50
+ const ext = entry.split(".").pop()?.toLowerCase();
51
+ if (!ext || !SUPPORTED_EXTENSIONS.has(ext))
52
+ continue;
53
+ files.push({ name: entry, path: fullPath });
54
+ }
55
+ files.sort((a, b) => a.name.localeCompare(b.name));
56
+ return files;
57
+ }
58
+ export function createDirectoryFileProvider(filePath) {
59
+ return createFileProvider(filePath);
60
+ }
61
+ //# sourceMappingURL=directory-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory-provider.js","sourceRoot":"","sources":["../src/directory-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAE1D,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,IAAI;IACJ,KAAK;IACL,UAAU;IACV,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,KAAK;IACL,MAAM;IACN,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,KAAK;IACL,MAAM;IACN,IAAI;IACJ,MAAM;IACN,KAAK;IACL,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,GAAG;IACH,KAAK;IACL,GAAG;IACH,KAAK;IACL,MAAM;IACN,IAAI;IACJ,OAAO;IACP,KAAK;CACN,CAAC,CAAA;AAOF,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,CAAA;IACpC,MAAM,KAAK,GAAqB,EAAE,CAAA;IAElC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAQ;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QACrC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAA;YAC/B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;gBAAE,SAAQ;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,SAAQ;QACV,CAAC;QACD,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,CAAA;QACjD,IAAI,CAAC,GAAG,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAQ;QACpD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAA;IAC7C,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;IAClD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,QAAgB;IAC1D,OAAO,kBAAkB,CAAC,QAAQ,CAAC,CAAA;AACrC,CAAC"}
@@ -0,0 +1,10 @@
1
+ export { View } from "./View.jsx";
2
+ export { DirectoryView } from "./DirectoryView.jsx";
3
+ export { launch, launchDirectory } from "./launch.jsx";
4
+ export type { ViewLaunchOptions } from "./launch.jsx";
5
+ export { createFileProvider, createStdinProvider, createTableFileProvider, createTableStdinProvider } from "./default-provider.js";
6
+ export { listDirectoryFiles } from "./directory-provider.js";
7
+ export type { DirectoryEntry } from "./directory-provider.js";
8
+ export type { AnyContent, Content, ContentChunk, ContentFormat, ContentProvider, ContentRenderer, ContentRendererProps, CustomContent, ViewContent, ViewContentProvider, ColumnDef, TableRow, } from "./types.js";
9
+ export { getTextContent, isBuiltinContent, isCustomContent } from "./types.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACtD,YAAY,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AACrD,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAA;AAClI,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAC7D,YAAY,EACV,UAAU,EACV,OAAO,EACP,YAAY,EACZ,aAAa,EACb,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,SAAS,EACT,QAAQ,GACT,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export { View } from "./View.jsx";
2
+ export { DirectoryView } from "./DirectoryView.jsx";
3
+ export { launch, launchDirectory } from "./launch.jsx";
4
+ export { createFileProvider, createStdinProvider, createTableFileProvider, createTableStdinProvider } from "./default-provider.js";
5
+ export { listDirectoryFiles } from "./directory-provider.js";
6
+ export { getTextContent, isBuiltinContent, isCustomContent } from "./types.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAEtD,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAA;AAClI,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAgB5D,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1,14 @@
1
+ import type { ActionDefinition } from "@tooee/commands";
2
+ import type { ContentProvider, ContentRenderer } from "./types.js";
3
+ export interface ViewLaunchOptions {
4
+ contentProvider: ContentProvider;
5
+ actions?: ActionDefinition[];
6
+ renderers?: Record<string, ContentRenderer>;
7
+ }
8
+ export interface DirectoryLaunchOptions {
9
+ dirPath: string;
10
+ actions?: ActionDefinition[];
11
+ }
12
+ export declare function launch(options: ViewLaunchOptions): Promise<void>;
13
+ export declare function launchDirectory(options: DirectoryLaunchOptions): Promise<void>;
14
+ //# sourceMappingURL=launch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launch.d.ts","sourceRoot":"","sources":["../src/launch.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAGvD,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAElE,MAAM,WAAW,iBAAiB;IAChC,eAAe,EAAE,eAAe,CAAA;IAChC,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAA;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;CAC5C;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAA;CAC7B;AAED,wBAAsB,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQtE;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAOpF"}
package/dist/launch.js ADDED
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx } from "@opentui/react/jsx-runtime";
2
+ import { launchCli } from "@tooee/shell";
3
+ import { View } from "./View.jsx";
4
+ import { DirectoryView } from "./DirectoryView.jsx";
5
+ export async function launch(options) {
6
+ await launchCli(_jsx(View, { contentProvider: options.contentProvider, actions: options.actions, renderers: options.renderers }));
7
+ }
8
+ export async function launchDirectory(options) {
9
+ await launchCli(_jsx(DirectoryView, { dirPath: options.dirPath, actions: options.actions }));
10
+ }
11
+ //# sourceMappingURL=launch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launch.js","sourceRoot":"","sources":["../src/launch.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAExC,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAcnD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,OAA0B;IACrD,MAAM,SAAS,CACb,KAAC,IAAI,IACH,eAAe,EAAE,OAAO,CAAC,eAAe,EACxC,OAAO,EAAE,OAAO,CAAC,OAAO,EACxB,SAAS,EAAE,OAAO,CAAC,SAAS,GAC5B,CACH,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAA+B;IACnE,MAAM,SAAS,CACb,KAAC,aAAa,IACZ,OAAO,EAAE,OAAO,CAAC,OAAO,EACxB,OAAO,EAAE,OAAO,CAAC,OAAO,GACxB,CACH,CAAA;AACH,CAAC"}
@@ -0,0 +1,71 @@
1
+ import type { ReactNode } from "react";
2
+ import type { ColumnDef, TableRow } from "@tooee/renderers";
3
+ export type Content = MarkdownContent | CodeContent | TextContent | ImageContent | TableContent;
4
+ export type ContentFormat = Content["format"];
5
+ interface BaseContent {
6
+ title?: string;
7
+ getTextContent?: () => string;
8
+ }
9
+ export interface MarkdownContent extends BaseContent {
10
+ format: "markdown";
11
+ markdown: string;
12
+ }
13
+ export interface CodeContent extends BaseContent {
14
+ format: "code";
15
+ code: string;
16
+ language?: string;
17
+ }
18
+ export interface TextContent extends BaseContent {
19
+ format: "text";
20
+ text: string;
21
+ }
22
+ export interface ImageContent extends BaseContent {
23
+ format: "image";
24
+ src: string;
25
+ }
26
+ export interface TableContent extends BaseContent {
27
+ format: "table";
28
+ columns: ColumnDef[];
29
+ rows: TableRow[];
30
+ }
31
+ export interface CustomContent<T = unknown> {
32
+ format: string;
33
+ data: T;
34
+ title?: string;
35
+ getTextContent?: () => string;
36
+ }
37
+ /** Content or custom content — used where custom formats are accepted */
38
+ export type AnyContent = Content | CustomContent;
39
+ export interface ContentRendererProps {
40
+ content: CustomContent;
41
+ lineCount: number;
42
+ cursor?: number;
43
+ selectionStart?: number;
44
+ selectionEnd?: number;
45
+ }
46
+ export type ContentRenderer = (props: ContentRendererProps) => ReactNode;
47
+ export type AppendableFormat = Extract<ContentFormat, "markdown" | "code" | "text">;
48
+ export type ContentChunk = {
49
+ type: "append";
50
+ format: AppendableFormat;
51
+ data: string;
52
+ language?: string;
53
+ } | {
54
+ type: "replace";
55
+ content: AnyContent;
56
+ } | {
57
+ type: "patch";
58
+ apply: (current: AnyContent | null) => AnyContent;
59
+ };
60
+ export interface ContentProvider {
61
+ load(): AnyContent | Promise<AnyContent> | AsyncIterable<ContentChunk>;
62
+ format?: string;
63
+ title?: string;
64
+ }
65
+ export type ViewContent = Content;
66
+ export type ViewContentProvider = ContentProvider;
67
+ export type { ColumnDef, TableRow } from "@tooee/renderers";
68
+ export declare function isBuiltinContent(content: AnyContent): content is Content;
69
+ export declare function isCustomContent(content: AnyContent): content is CustomContent;
70
+ export declare function getTextContent(content: AnyContent): string;
71
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,48 @@
1
+ // === Utilities ===
2
+ const BUILTIN_FORMATS = new Set(["markdown", "code", "text", "image", "table"]);
3
+ export function isBuiltinContent(content) {
4
+ return BUILTIN_FORMATS.has(content.format);
5
+ }
6
+ export function isCustomContent(content) {
7
+ return !BUILTIN_FORMATS.has(content.format);
8
+ }
9
+ export function getTextContent(content) {
10
+ if (content.getTextContent) {
11
+ return content.getTextContent();
12
+ }
13
+ if (isCustomContent(content)) {
14
+ return "";
15
+ }
16
+ switch (content.format) {
17
+ case "markdown":
18
+ return content.markdown;
19
+ case "code":
20
+ return content.code;
21
+ case "text":
22
+ return content.text;
23
+ case "image":
24
+ return content.src;
25
+ case "table": {
26
+ const headers = content.columns.map((column) => column.header ?? column.key);
27
+ const rowLines = content.rows.map((row) => content.columns.map((column) => stringifyCell(row[column.key])).join("\t"));
28
+ return [headers.join("\t"), ...rowLines].join("\n");
29
+ }
30
+ default:
31
+ return "";
32
+ }
33
+ }
34
+ function stringifyCell(value) {
35
+ if (value == null)
36
+ return "";
37
+ if (typeof value === "string")
38
+ return value;
39
+ if (typeof value === "number" || typeof value === "boolean")
40
+ return String(value);
41
+ try {
42
+ return JSON.stringify(value);
43
+ }
44
+ catch {
45
+ return String(value);
46
+ }
47
+ }
48
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAmGA,oBAAoB;AAEpB,MAAM,eAAe,GAAgB,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAA;AAE5F,MAAM,UAAU,gBAAgB,CAAC,OAAmB;IAClD,OAAO,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;AAC5C,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAmB;IACjD,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;AAC7C,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAmB;IAChD,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,OAAO,OAAO,CAAC,cAAc,EAAE,CAAA;IACjC,CAAC;IAED,IAAI,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAA;IACX,CAAC;IAED,QAAQ,OAAO,CAAC,MAAM,EAAE,CAAC;QACvB,KAAK,UAAU;YACb,OAAO,OAAO,CAAC,QAAQ,CAAA;QACzB,KAAK,MAAM;YACT,OAAO,OAAO,CAAC,IAAI,CAAA;QACrB,KAAK,MAAM;YACT,OAAO,OAAO,CAAC,IAAI,CAAA;QACrB,KAAK,OAAO;YACV,OAAO,OAAO,CAAC,GAAG,CAAA;QACpB,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,GAAG,CAAC,CAAA;YAC5E,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CACxC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAC3E,CAAA;YACD,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACrD,CAAC;QACD;YACE,OAAO,EAAE,CAAA;IACb,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,EAAE,CAAA;IAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IAC3C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAA;IACjF,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAA;IACtB,CAAC;AACH,CAAC"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@tooee/view",
3
+ "version": "0.1.0",
4
+ "description": "Terminal content viewer for markdown, code, images, and tables",
5
+ "license": "MIT",
6
+ "author": "Gareth Andrew",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/gingerhendrix/tooee.git",
10
+ "directory": "packages/view"
11
+ },
12
+ "homepage": "https://github.com/gingerhendrix/tooee",
13
+ "bugs": "https://github.com/gingerhendrix/tooee/issues",
14
+ "keywords": ["tui", "terminal", "cli", "opentui", "markdown", "syntax-highlighting", "image", "viewer"],
15
+ "type": "module",
16
+ "exports": {
17
+ ".": {
18
+ "import": {
19
+ "@tooee/source": "./src/index.ts",
20
+ "default": "./dist/index.js"
21
+ }
22
+ }
23
+ },
24
+ "files": ["dist", "src"],
25
+ "scripts": {
26
+ "typecheck": "tsc --noEmit"
27
+ },
28
+ "dependencies": {
29
+ "@tooee/commands": "0.0.0",
30
+ "@tooee/config": "0.0.0",
31
+ "@tooee/layout": "0.0.0",
32
+ "@tooee/overlays": "0.0.0",
33
+ "@tooee/renderers": "0.0.0",
34
+ "@tooee/themes": "0.0.0",
35
+ "@tooee/shell": "0.0.0",
36
+ "marked": "^16.3.0"
37
+ },
38
+ "devDependencies": {
39
+ "@opentui/core": "^0.1.67",
40
+ "@opentui/react": "^0.1.67",
41
+ "@types/bun": "^1.3.5",
42
+ "@types/react": "^19.1.10",
43
+ "typescript": "^5.8.3"
44
+ },
45
+ "peerDependencies": {
46
+ "@opentui/core": "^0.1.67",
47
+ "@opentui/react": "^0.1.67",
48
+ "react": "^18.0.0 || ^19.0.0"
49
+ }
50
+ }
@@ -0,0 +1,68 @@
1
+ import { useState, useMemo } from "react"
2
+ import { useCommand } from "@tooee/commands"
3
+ import { View } from "./View.jsx"
4
+ import { listDirectoryFiles, type DirectoryEntry } from "./directory-provider.js"
5
+ import type { AnyContent, ContentProvider } from "./types.js"
6
+ import { createFileProvider } from "./default-provider.js"
7
+
8
+ function createDirectoryFileProvider(
9
+ entry: DirectoryEntry,
10
+ index: number,
11
+ total: number,
12
+ ): ContentProvider {
13
+ const inner = createFileProvider(entry.path)
14
+ return {
15
+ async load(): Promise<AnyContent> {
16
+ const result = inner.load()
17
+ const content = result instanceof Promise ? await result : result as AnyContent
18
+ return {
19
+ ...content,
20
+ title: `${entry.name} (${index + 1}/${total})`,
21
+ }
22
+ },
23
+ }
24
+ }
25
+
26
+ interface DirectoryViewProps {
27
+ dirPath: string
28
+ actions?: import("@tooee/commands").ActionDefinition[]
29
+ }
30
+
31
+ export function DirectoryView({ dirPath, actions }: DirectoryViewProps) {
32
+ const files = useMemo(() => listDirectoryFiles(dirPath), [dirPath])
33
+ const [currentIndex, setCurrentIndex] = useState(0)
34
+
35
+ const contentProvider = useMemo(
36
+ () =>
37
+ files.length > 0
38
+ ? createDirectoryFileProvider(files[currentIndex], currentIndex, files.length)
39
+ : null,
40
+ [files, currentIndex],
41
+ )
42
+
43
+ useCommand({
44
+ id: "dir.next-file",
45
+ title: "Next file",
46
+ hotkey: "l",
47
+ modes: ["cursor"],
48
+ handler: () => setCurrentIndex((i) => Math.min(i + 1, files.length - 1)),
49
+ })
50
+
51
+ useCommand({
52
+ id: "dir.prev-file",
53
+ title: "Previous file",
54
+ hotkey: "h",
55
+ modes: ["cursor"],
56
+ handler: () => setCurrentIndex((i) => Math.max(i - 1, 0)),
57
+ })
58
+
59
+ if (files.length === 0 || !contentProvider) {
60
+ return (
61
+ <box>
62
+ <text content="No viewable files in directory" />
63
+ </box>
64
+ )
65
+ }
66
+
67
+ return <View contentProvider={contentProvider} actions={actions} />
68
+ }