* chore: only set visibility for container particles * create reusable controls indicator for reply or new * compress the size of top bar * refactor: restructure state, routing, and more * introduce stream compose flow * feat: compose new stream full flow * implement stream player * fix: prevent redirect for signed object urls * fix: implement stream playback cleaner structure * refactor: layout file name * feat: show stream name in breadcrumbs * chore: tweak padding * chore: adjust position of audio bars * feat: show latest particle preview in stream list * fix: remove console log * refactor: reorder classes * fix: avoid passing in updated_at to firestore particle * refactor: extract properties for container particles to flat fields in firestore * make the stream previews look alive * feat: show audio bars during audio clip playback * feat: order streams by last child creation * feat: playback where I left off * chore: remove unused store * fix: recording mode not using shared state * chore: clean unused variable * remove unused imports * fix: improve controls indicator immersion * feat: show playback progress in bar & auto-play text * feat: auto-exit stream on playback completion * fix: jittery media playback progress * fix: navigate during state change is invalid with react router * fix: buggy exit progress when changing clips * feat: add app icon * update package.json info * feat: only show streams visible to me * feat: show seen indicator on particles * fix: prevent unnecessary effects * fix: play new particle after playback is ended * use contols indicator for exit timer
70 lines
2.0 KiB
TypeScript
70 lines
2.0 KiB
TypeScript
import { Video, Mic } from "lucide-react";
|
|
import { cn } from "@/lib/utils";
|
|
import { useMediaSettingsStore } from "@/stores/media-settings-store";
|
|
import { Button } from "@/components/ui/button";
|
|
import { PropsWithChildren } from "react";
|
|
|
|
interface ControlsIndicatorProps extends PropsWithChildren {
|
|
type: "reply" | "new";
|
|
}
|
|
export default function ControlsIndicator({ type, children }: ControlsIndicatorProps) {
|
|
const recordingMode = useMediaSettingsStore((s) => s.recordingMode);
|
|
const setRecordingMode = useMediaSettingsStore((s) => s.setRecordingMode);
|
|
|
|
return (
|
|
<div className="flex items-center gap-2 text-xs rounded-full pl-1 pr-3 py-1 bg-black/30 backdrop-blur-sm m-2">
|
|
<Button
|
|
onClick={() =>
|
|
setRecordingMode(recordingMode === "video" ? "audio" : "video")
|
|
}
|
|
title={
|
|
recordingMode === "video"
|
|
? "Switch to audio-only"
|
|
: "Switch to video"
|
|
}
|
|
variant="secondary"
|
|
className={cn(
|
|
"text-xs rounded-full",
|
|
"text-muted-foreground hover:text-white/90",
|
|
)}
|
|
>
|
|
{recordingMode === "video" ? (
|
|
<>
|
|
<Video className="h-3.5 w-3.5" />
|
|
<p>Video</p>
|
|
</>
|
|
) : (
|
|
<>
|
|
<Mic className="h-3.5 w-3.5" />
|
|
<span>Audio</span>
|
|
</>
|
|
)}
|
|
</Button>
|
|
{children ? <div className="flex-1">{children}</div> :
|
|
<div className="flex-1" />
|
|
}
|
|
{children && <span className="text-muted-foreground">·</span>}
|
|
<div className="text-muted-foreground">
|
|
Hold{" "}
|
|
<kbd
|
|
className={cn(
|
|
"bg-muted rounded px-1.5 py-0.5 font-mono",
|
|
)}
|
|
>
|
|
`
|
|
</kbd>{" "}
|
|
to {type === "reply" ? "reply " : "start "}
|
|
· Press{" "}
|
|
<kbd
|
|
className={cn(
|
|
"bg-muted rounded px-1.5 py-0.5 font-mono",
|
|
)}
|
|
>
|
|
T
|
|
</kbd>{" "}
|
|
for text
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|