Merge pull request #4: navigate panes with the arrow keys

# Conflicts:
#	package-lock.json
This commit is contained in:
bairon.dev
2026-06-29 13:40:04 -04:00
6 changed files with 44 additions and 7 deletions
+1
View File
@@ -1,3 +1,4 @@
node_modules/ node_modules/
dist/ dist/
.DS_Store .DS_Store
package-lock.json
+8
View File
@@ -315,6 +315,14 @@ export function App({
setRegion(region === "sidebar" ? "content" : "sidebar"); setRegion(region === "sidebar" ? "content" : "sidebar");
return; return;
} }
if (key.rightArrow) {
if (region === "sidebar") setRegion("content");
return;
}
if (key.leftArrow) {
if (region === "content") setRegion("sidebar");
return;
}
if (key.escape) { if (key.escape) {
if (captureMode === "esc") return; if (captureMode === "esc") return;
if (region === "content") { if (region === "content") {
+10 -3
View File
@@ -113,6 +113,7 @@ export function Results() {
submitQuery, submitQuery,
section, section,
region, region,
setRegion,
setCaptureMode, setCaptureMode,
startDownload, startDownload,
copyMagnet, copyMagnet,
@@ -172,9 +173,13 @@ export function Results() {
setMode("search"); setMode("search");
return; return;
} }
if (key.upArrow) {
if (results.length > 0 && clamped > 0) setCursor(clamped - 1);
else setMode("search");
return;
}
if (results.length === 0) return; if (results.length === 0) return;
if (key.upArrow) setCursor(wrapStep(clamped, -1, results.length)); if (key.downArrow) setCursor(wrapStep(clamped, 1, results.length));
else if (key.downArrow) setCursor(wrapStep(clamped, 1, results.length));
else if (key.pageUp) setCursor(Math.max(0, clamped - pageJump)); 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.pageDown) setCursor(Math.min(results.length - 1, clamped + pageJump));
else if (key.return) { else if (key.return) {
@@ -292,12 +297,14 @@ export function Results() {
editing={mode === "search"} editing={mode === "search"}
placeholder={PLACEHOLDER} placeholder={PLACEHOLDER}
onSubmit={onSubmit} onSubmit={onSubmit}
onExitDown={() => setMode("list")}
onExitLeft={() => setRegion("sidebar")}
/> />
<Box marginTop={1}> <Box marginTop={1}>
<Panel <Panel
title={mode === "detail" ? "details" : browsing ? "latest" : "results"} title={mode === "detail" ? "details" : browsing ? "latest" : "results"}
width={contentWidth} width={contentWidth}
focused={focused} focused={focused && mode !== "search"}
count={mode === "detail" ? undefined : count} count={mode === "detail" ? undefined : count}
height={panelOuter} height={panelOuter}
> >
+6
View File
@@ -10,6 +10,8 @@ interface SearchBarProps {
editing: boolean; editing: boolean;
onSubmit: (value: string) => void; onSubmit: (value: string) => void;
onChange?: (value: string) => void; onChange?: (value: string) => void;
onExitDown?: () => void;
onExitLeft?: () => void;
} }
export function SearchBar({ export function SearchBar({
@@ -19,6 +21,8 @@ export function SearchBar({
editing, editing,
onSubmit, onSubmit,
onChange, onChange,
onExitDown,
onExitLeft,
}: SearchBarProps) { }: SearchBarProps) {
return ( return (
<Panel title="search" width={width} focused={editing} height={2}> <Panel title="search" width={width} focused={editing} height={2}>
@@ -31,6 +35,8 @@ export function SearchBar({
placeholder={placeholder} placeholder={placeholder}
onSubmit={onSubmit} onSubmit={onSubmit}
onChange={onChange} onChange={onChange}
onExitDown={onExitDown}
onExitLeft={onExitLeft}
/> />
) : value ? ( ) : value ? (
<Text wrap="truncate-end">{value}</Text> <Text wrap="truncate-end">{value}</Text>
+13 -2
View File
@@ -7,6 +7,8 @@ export interface TextFieldProps {
placeholder?: string; placeholder?: string;
onChange?: (value: string) => void; onChange?: (value: string) => void;
onSubmit?: (value: string) => void; onSubmit?: (value: string) => void;
onExitDown?: () => void;
onExitLeft?: () => void;
} }
interface Edit { interface Edit {
@@ -48,6 +50,8 @@ export function TextField({
placeholder = "", placeholder = "",
onChange, onChange,
onSubmit, onSubmit,
onExitDown,
onExitLeft,
}: TextFieldProps) { }: TextFieldProps) {
const [value, setValue] = useState(defaultValue); const [value, setValue] = useState(defaultValue);
const [cursor, setCursor] = useState(defaultValue.length); const [cursor, setCursor] = useState(defaultValue.length);
@@ -60,8 +64,11 @@ export function TextField({
useInput( useInput(
(input, key) => { (input, key) => {
if (key.upArrow || key.downArrow || key.tab || (key.ctrl && input === "c")) if (key.downArrow) {
onExitDown?.();
return; return;
}
if (key.upArrow || key.tab || (key.ctrl && input === "c")) return;
if (key.return) { if (key.return) {
onSubmit?.(value); onSubmit?.(value);
@@ -91,7 +98,11 @@ export function TextField({
} }
if (key.leftArrow) { if (key.leftArrow) {
setCursor(Math.max(0, cursor - 1)); if (cursor === 0) {
onExitLeft?.();
return;
}
setCursor(cursor - 1);
return; return;
} }
if (key.rightArrow) { if (key.rightArrow) {
+6 -2
View File
@@ -14,7 +14,7 @@ export const HELP_GROUPS: HelpGroup[] = [
{ {
title: "Navigate", title: "Navigate",
hints: [ hints: [
{ keys: "↑ ↓", label: "Move" }, { keys: "↑ ↓ ← →", label: "Navigate content and panes" },
{ keys: "↵", label: "Open" }, { keys: "↵", label: "Open" },
{ keys: "tab", label: "Switch pane" }, { keys: "tab", label: "Switch pane" },
{ keys: "esc", label: "Back" }, { keys: "esc", label: "Back" },
@@ -49,6 +49,8 @@ export const HELP_GROUPS: HelpGroup[] = [
}, },
]; ];
const NAVIGATE: Hint = { keys: "↑ ↓ ← →", label: "Navigate content and panes" };
const ALWAYS: Hint = { keys: "?", label: "Keys" }; const ALWAYS: Hint = { keys: "?", label: "Keys" };
const SWITCH: Hint = { keys: "tab", label: "Switch pane" }; const SWITCH: Hint = { keys: "tab", label: "Switch pane" };
@@ -61,7 +63,7 @@ export function footerHints(
): Hint[] { ): Hint[] {
if (region === "sidebar") { if (region === "sidebar") {
return [ return [
{ keys: "↑↓", label: "Move" }, NAVIGATE,
{ keys: "↵", label: "Open" }, { keys: "↵", label: "Open" },
SWITCH, SWITCH,
ALWAYS, ALWAYS,
@@ -82,6 +84,7 @@ export function footerHints(
} }
if (downloadFocus === "recent") { if (downloadFocus === "recent") {
return [ return [
NAVIGATE,
{ keys: "d", label: "Download again" }, { keys: "d", label: "Download again" },
{ keys: "c", label: "Remove" }, { keys: "c", label: "Remove" },
{ keys: "x", label: "Clear" }, { keys: "x", label: "Clear" },
@@ -92,6 +95,7 @@ export function footerHints(
return [{ keys: "p", label: "Pause" }, { keys: "c", label: "Cancel" }, SWITCH, ALWAYS]; return [{ keys: "p", label: "Pause" }, { keys: "c", label: "Cancel" }, SWITCH, ALWAYS];
} }
return [ return [
NAVIGATE,
{ keys: "d", label: "Download" }, { keys: "d", label: "Download" },
{ keys: "y", label: "Copy magnet" }, { keys: "y", label: "Copy magnet" },
{ keys: "/", label: "Search" }, { keys: "/", label: "Search" },