keyboard-driven navigation

Resolves #66
This commit is contained in:
talksik
2026-03-30 12:51:15 -07:00
parent 14285575e4
commit 086cf4f1ee
7 changed files with 188 additions and 40 deletions
+21 -4
View File
@@ -1,4 +1,5 @@
import { useParams } from "react-router-dom";
import { useCallback, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { List, LayoutGrid } from "lucide-react";
import { particlePath } from "@/lib/particle-path";
import { ParticleListView } from "@/features/particles/particle-list-view";
@@ -8,6 +9,8 @@ import ControlsIndicator from "@/features/compose/controls-indicator";
import { ComposeOverlay } from "./compose/compose-overlay";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
import { useViewModeStore } from "@/stores/view-mode-store";
import { useStreamParticles } from "@/hooks/use-stream-particles";
import { useStreamKeyboardNav } from "@/hooks/use-stream-keyboard-nav";
/**
* Route-level component for /:networkId (index).
@@ -15,18 +18,32 @@ import { useViewModeStore } from "@/stores/view-mode-store";
*/
export default function NetworkRoot() {
const { networkId } = useParams();
const navigate = useNavigate();
const path = particlePath(networkId!, []);
const viewMode = useViewModeStore((s) => s.viewMode);
const setViewMode = useViewModeStore((s) => s.setViewMode);
const { streams } = useStreamParticles(path);
const [composeActive, setComposeActive] = useState(false);
const { selectedIndex } = useStreamKeyboardNav({
streams,
viewMode,
enabled: !composeActive,
onNavigate: useCallback(
(streamId: string) => navigate(`/${networkId}/${streamId}`),
[navigate, networkId],
),
});
return (
<div className="relative min-h-0 flex-1">
{/* Scrollable content */}
<div className="h-full overflow-y-auto overscroll-contain pt-10 pb-14">
{viewMode === "list" ? (
<ParticleListView path={path} />
<ParticleListView path={path} selectedIndex={selectedIndex} />
) : (
<ParticleGridView path={path} />
<ParticleGridView path={path} selectedIndex={selectedIndex} />
)}
</div>
@@ -51,7 +68,7 @@ export default function NetworkRoot() {
</div>
<AutoplayOverlay networkId={networkId!} />
<ComposeOverlay networkId={networkId!} />
<ComposeOverlay networkId={networkId!} onActiveChange={setComposeActive} />
<div className="pointer-events-none absolute inset-x-0 bottom-0 flex justify-center p-3">
<div className="pointer-events-auto">
<ControlsIndicator type={"new"} />