From 6acbac462e5b0ef096cfbd5a519118ecf8c78de6 Mon Sep 17 00:00:00 2001 From: Oskar Krawczyk Date: Mon, 29 Jun 2026 11:22:02 +0200 Subject: [PATCH] Added navigating panes by arrows --- .gitignore | 1 + package-lock.json | 6 +++--- src/ui/App.tsx | 8 ++++++++ src/ui/components/Results.tsx | 13 ++++++++++--- src/ui/components/SearchBar.tsx | 6 ++++++ src/ui/components/TextField.tsx | 15 +++++++++++++-- src/ui/keymap.ts | 8 ++++++-- 7 files changed, 47 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 3bdd52e..c073aad 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/ dist/ .DS_Store +package-lock.json diff --git a/package-lock.json b/package-lock.json index 16ab523..7aa3504 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "torlink", + "name": "torlnk", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "torlink", + "name": "torlnk", "version": "1.0.0", "license": "MIT", "dependencies": { @@ -16,7 +16,7 @@ "webtorrent": "^2.4.1" }, "bin": { - "torlink": "dist/index.js" + "torlnk": "dist/index.js" }, "devDependencies": { "@types/node": "^25.9.2", diff --git a/src/ui/App.tsx b/src/ui/App.tsx index d8ae956..b1ece3c 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -302,6 +302,14 @@ export function App({ setRegion(region === "sidebar" ? "content" : "sidebar"); return; } + if (key.rightArrow) { + if (region === "sidebar") setRegion("content"); + return; + } + if (key.leftArrow) { + if (region === "content") setRegion("sidebar"); + return; + } if (key.escape) { if (captureMode === "esc") return; if (region === "content") { diff --git a/src/ui/components/Results.tsx b/src/ui/components/Results.tsx index d8f1c4c..2dc6cc2 100644 --- a/src/ui/components/Results.tsx +++ b/src/ui/components/Results.tsx @@ -100,6 +100,7 @@ export function Results() { submitQuery, section, region, + setRegion, setCaptureMode, startDownload, contentWidth, @@ -155,9 +156,13 @@ export function Results() { setMode("search"); return; } + if (key.upArrow) { + if (results.length > 0 && clamped > 0) setCursor(clamped - 1); + else setMode("search"); + return; + } if (results.length === 0) return; - if (key.upArrow) setCursor(wrapStep(clamped, -1, results.length)); - else if (key.downArrow) setCursor(wrapStep(clamped, 1, results.length)); + if (key.downArrow) setCursor(wrapStep(clamped, 1, results.length)); else if (key.pageUp) setCursor(Math.max(0, clamped - pageJump)); else if (key.pageDown) setCursor(Math.min(results.length - 1, clamped + pageJump)); else if (key.return) { @@ -271,12 +276,14 @@ export function Results() { editing={mode === "search"} placeholder={PLACEHOLDER} onSubmit={onSubmit} + onExitDown={() => setMode("list")} + onExitLeft={() => setRegion("sidebar")} /> diff --git a/src/ui/components/SearchBar.tsx b/src/ui/components/SearchBar.tsx index 93f2b2c..186e031 100644 --- a/src/ui/components/SearchBar.tsx +++ b/src/ui/components/SearchBar.tsx @@ -10,6 +10,8 @@ interface SearchBarProps { editing: boolean; onSubmit: (value: string) => void; onChange?: (value: string) => void; + onExitDown?: () => void; + onExitLeft?: () => void; } export function SearchBar({ @@ -19,6 +21,8 @@ export function SearchBar({ editing, onSubmit, onChange, + onExitDown, + onExitLeft, }: SearchBarProps) { return ( @@ -31,6 +35,8 @@ export function SearchBar({ placeholder={placeholder} onSubmit={onSubmit} onChange={onChange} + onExitDown={onExitDown} + onExitLeft={onExitLeft} /> ) : value ? ( {value} diff --git a/src/ui/components/TextField.tsx b/src/ui/components/TextField.tsx index aed39d7..4fedafc 100644 --- a/src/ui/components/TextField.tsx +++ b/src/ui/components/TextField.tsx @@ -7,6 +7,8 @@ export interface TextFieldProps { placeholder?: string; onChange?: (value: string) => void; onSubmit?: (value: string) => void; + onExitDown?: () => void; + onExitLeft?: () => void; } interface Edit { @@ -48,6 +50,8 @@ export function TextField({ placeholder = "", onChange, onSubmit, + onExitDown, + onExitLeft, }: TextFieldProps) { const [value, setValue] = useState(defaultValue); const [cursor, setCursor] = useState(defaultValue.length); @@ -60,8 +64,11 @@ export function TextField({ useInput( (input, key) => { - if (key.upArrow || key.downArrow || key.tab || (key.ctrl && input === "c")) + if (key.downArrow) { + onExitDown?.(); return; + } + if (key.upArrow || key.tab || (key.ctrl && input === "c")) return; if (key.return) { onSubmit?.(value); @@ -91,7 +98,11 @@ export function TextField({ } if (key.leftArrow) { - setCursor(Math.max(0, cursor - 1)); + if (cursor === 0) { + onExitLeft?.(); + return; + } + setCursor(cursor - 1); return; } if (key.rightArrow) { diff --git a/src/ui/keymap.ts b/src/ui/keymap.ts index 564915b..df676b8 100644 --- a/src/ui/keymap.ts +++ b/src/ui/keymap.ts @@ -14,7 +14,7 @@ export const HELP_GROUPS: HelpGroup[] = [ { title: "Navigate", hints: [ - { keys: "↑ ↓", label: "Move" }, + { keys: "↑ ↓ ← →", label: "Navigate content and panes" }, { keys: "↵", label: "Open" }, { keys: "tab", label: "Switch pane" }, { keys: "esc", label: "Back" }, @@ -48,6 +48,8 @@ export const HELP_GROUPS: HelpGroup[] = [ }, ]; +const NAVIGATE: Hint = { keys: "↑ ↓ ← →", label: "Navigate content and panes" }; + const ALWAYS: Hint = { keys: "?", label: "Keys" }; const SWITCH: Hint = { keys: "tab", label: "Switch pane" }; @@ -60,7 +62,7 @@ export function footerHints( ): Hint[] { if (region === "sidebar") { return [ - { keys: "↑↓", label: "Move" }, + NAVIGATE, { keys: "↵", label: "Open" }, SWITCH, ALWAYS, @@ -81,6 +83,7 @@ export function footerHints( } if (downloadFocus === "recent") { return [ + NAVIGATE, { keys: "d", label: "Download again" }, { keys: "c", label: "Remove" }, { keys: "x", label: "Clear" }, @@ -91,6 +94,7 @@ export function footerHints( return [{ keys: "p", label: "Pause" }, { keys: "c", label: "Cancel" }, SWITCH, ALWAYS]; } return [ + NAVIGATE, { keys: "d", label: "Download" }, { keys: "/", label: "Search" }, { keys: "m", label: "Paste magnet" },