infra: add linting and formatting for js projects (#230)
* wip * wip * wip * format * wip(mobile): lint and format * cleanup * nits * nits * idiomatic react * nit * format all root files
This commit was merged in pull request #230.
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
import { useCallback, useState } from "react";
|
||||
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
|
||||
import { CircleDot, CircleCheckBig } from "lucide-react";
|
||||
import { particlePath } from "@/lib/particle-path";
|
||||
import { ParticleListView } from "@/features/particles/particle-list-view";
|
||||
import { VideoAudioToggle } from "@/components/video-audio-toggle";
|
||||
import { ComposeOverlay } from "./compose/compose-overlay";
|
||||
import { useComposeIntentStore } from "@/stores/compose-intent-store";
|
||||
import { ComposeQuotaIndicator } from "./compose/compose-quota-indicator";
|
||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { useStreamParticles } from "@/hooks/use-stream-particles";
|
||||
import { useStreamKeyboardNav } from "@/hooks/use-stream-keyboard-nav";
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
import { CircleDot, CircleCheckBig } from 'lucide-react';
|
||||
import { particlePath } from '@/lib/particle-path';
|
||||
import { ParticleListView } from '@/features/particles/particle-list-view';
|
||||
import { VideoAudioToggle } from '@/components/video-audio-toggle';
|
||||
import { ComposeOverlay } from './compose/compose-overlay';
|
||||
import { useComposeIntentStore } from '@/stores/compose-intent-store';
|
||||
import { ComposeQuotaIndicator } from './compose/compose-quota-indicator';
|
||||
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { useStreamParticles } from '@/hooks/use-stream-particles';
|
||||
import { useStreamKeyboardNav } from '@/hooks/use-stream-keyboard-nav';
|
||||
|
||||
/**
|
||||
* Route-level component for /:networkId (index).
|
||||
@@ -17,28 +17,33 @@ import { useStreamKeyboardNav } from "@/hooks/use-stream-keyboard-nav";
|
||||
*/
|
||||
export default function NetworkRoot() {
|
||||
const { networkId } = useParams();
|
||||
if (!networkId)
|
||||
throw new Error('NetworkRoot requires a :networkId route param');
|
||||
const navigate = useNavigate();
|
||||
const path = particlePath(networkId!, []);
|
||||
const path = particlePath(networkId, []);
|
||||
|
||||
const [composeActive, setComposeActive] = useState(false);
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const statusTab: "open" | "closed" =
|
||||
searchParams.get("status") === "closed" ? "closed" : "open";
|
||||
const setStatusTab = (next: "open" | "closed") => {
|
||||
const statusTab: 'open' | 'closed' =
|
||||
searchParams.get('status') === 'closed' ? 'closed' : 'open';
|
||||
const setStatusTab = (next: 'open' | 'closed') => {
|
||||
setSearchParams(
|
||||
(prev) => {
|
||||
const params = new URLSearchParams(prev);
|
||||
if (next === "open") params.delete("status");
|
||||
else params.set("status", next);
|
||||
if (next === 'open') params.delete('status');
|
||||
else params.set('status', next);
|
||||
return params;
|
||||
},
|
||||
{ replace: true },
|
||||
);
|
||||
};
|
||||
|
||||
const { streams, isLoading, canLoadMore, loadMore } = useStreamParticles(path, {
|
||||
status: statusTab,
|
||||
});
|
||||
const { streams, isLoading, canLoadMore, loadMore } = useStreamParticles(
|
||||
path,
|
||||
{
|
||||
status: statusTab,
|
||||
},
|
||||
);
|
||||
|
||||
const { selectedIndex } = useStreamKeyboardNav({
|
||||
streams,
|
||||
@@ -55,11 +60,17 @@ export default function NetworkRoot() {
|
||||
<div className="flex shrink-0 items-center p-1 border-b">
|
||||
<Tabs
|
||||
value={statusTab}
|
||||
onValueChange={(v) => setStatusTab(v === "closed" ? "closed" : "open")}
|
||||
onValueChange={(v) =>
|
||||
setStatusTab(v === 'closed' ? 'closed' : 'open')
|
||||
}
|
||||
>
|
||||
<TabsList>
|
||||
<TabsTrigger value="open"><CircleDot className="size-3 text-green-500" /> Open</TabsTrigger>
|
||||
<TabsTrigger value="closed"><CircleCheckBig className="size-3" /> Closed</TabsTrigger>
|
||||
<TabsTrigger value="open">
|
||||
<CircleDot className="size-3 text-green-500" /> Open
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="closed">
|
||||
<CircleCheckBig className="size-3" /> Closed
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</div>
|
||||
@@ -68,7 +79,7 @@ export default function NetworkRoot() {
|
||||
<div className="min-h-0 flex-1 overflow-y-auto overscroll-contain pb-14 py-2">
|
||||
<ParticleListView
|
||||
streams={streams}
|
||||
networkId={networkId!}
|
||||
networkId={networkId}
|
||||
isLoading={isLoading}
|
||||
selectedIndex={selectedIndex}
|
||||
canLoadMore={canLoadMore}
|
||||
@@ -76,10 +87,10 @@ export default function NetworkRoot() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<ComposeOverlay networkId={networkId!} onActiveChange={setComposeActive} />
|
||||
<ComposeOverlay networkId={networkId} onActiveChange={setComposeActive} />
|
||||
{!composeActive && (
|
||||
<div className="pointer-events-none absolute inset-x-0 bottom-16 z-20 flex justify-center px-3">
|
||||
<ComposeQuotaIndicator networkId={networkId!} />
|
||||
<ComposeQuotaIndicator networkId={networkId} />
|
||||
</div>
|
||||
)}
|
||||
<div className="pointer-events-none absolute inset-x-0 bottom-0 z-20 flex justify-center p-3">
|
||||
@@ -98,39 +109,39 @@ function NetworkRootControls() {
|
||||
<span>
|
||||
<kbd className="rounded bg-white/10 px-1.5 py-0.5 font-mono text-xs">
|
||||
↑↓
|
||||
</kbd>{" "}
|
||||
</kbd>{' '}
|
||||
<kbd className="rounded bg-white/10 px-1.5 py-0.5 font-mono text-xs">
|
||||
Enter
|
||||
</kbd>{" "}
|
||||
</kbd>{' '}
|
||||
navigate
|
||||
</span>
|
||||
<span>
|
||||
<kbd className="rounded bg-white/10 px-1.5 py-0.5 font-mono text-xs">
|
||||
1–9
|
||||
</kbd>{" "}
|
||||
</kbd>{' '}
|
||||
jump
|
||||
</span>
|
||||
<VideoAudioToggle />
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => requestIntent("record")}
|
||||
onClick={() => requestIntent('record')}
|
||||
className="cursor-pointer rounded transition-colors hover:text-white/80"
|
||||
title="Start recording (or hold `)"
|
||||
>
|
||||
<kbd className="rounded bg-white/10 px-1.5 py-0.5 font-mono text-xs">
|
||||
Hold `
|
||||
</kbd>{" "}
|
||||
</kbd>{' '}
|
||||
to start
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => requestIntent("text")}
|
||||
onClick={() => requestIntent('text')}
|
||||
className="cursor-pointer rounded transition-colors hover:text-white/80"
|
||||
title="Compose text (or press T)"
|
||||
>
|
||||
<kbd className="rounded bg-white/10 px-1.5 py-0.5 font-mono text-xs">
|
||||
T
|
||||
</kbd>{" "}
|
||||
</kbd>{' '}
|
||||
text
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user