setup electron multi-window architecture (#102)
* prototype with two windows * use deps in separate window render process * enhance autoplay into desktop overlay * fix: autoplay window not applying tailwind styles
This commit was merged in pull request #102.
This commit is contained in:
@@ -4,7 +4,6 @@ import { List, LayoutGrid } from "lucide-react";
|
||||
import { particlePath } from "@/lib/particle-path";
|
||||
import { ParticleListView } from "@/features/particles/particle-list-view";
|
||||
import { ParticleGridView } from "@/features/particles/particle-grid-view";
|
||||
import { AutoplayOverlay } from "@/features/particles/autoplay-overlay";
|
||||
import ControlsIndicator from "@/features/compose/controls-indicator";
|
||||
import { ComposeOverlay } from "./compose/compose-overlay";
|
||||
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
||||
@@ -71,7 +70,6 @@ export default function NetworkRoot() {
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
|
||||
<AutoplayOverlay 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">
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { X, Mic } from "lucide-react";
|
||||
import { useAutoplayStore } from "@/stores/autoplay-store";
|
||||
import { useDownloadUrl } from "@/hooks/use-download-url";
|
||||
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||
import { Small } from "@/components/ui/typography";
|
||||
import { getInitials } from "@/lib/utils";
|
||||
import { useNetwork } from "@/hooks/use-networks";
|
||||
|
||||
interface AutoplayOverlayProps {
|
||||
networkId: string;
|
||||
}
|
||||
|
||||
export function AutoplayOverlay({ networkId }: AutoplayOverlayProps) {
|
||||
const activeParticle = useAutoplayStore((s) => s.activeParticle);
|
||||
const streamId = useAutoplayStore((s) => s.streamId);
|
||||
const stop = useAutoplayStore((s) => s.stop);
|
||||
const { data: url } = useDownloadUrl(activeParticle?.properties.object_id);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const network = useNetwork(networkId);
|
||||
|
||||
if (!activeParticle || !url) return null;
|
||||
|
||||
const isVideo = activeParticle.properties.mime_type?.startsWith("video/");
|
||||
const creator = network?.humans?.find((h) => h.id === activeParticle.created_by_human_id);
|
||||
const senderInitials = creator ? getInitials(creator.email) : activeParticle.created_by_human_id.slice(0, 2).toUpperCase();
|
||||
const senderName = creator?.email_prefix ?? activeParticle.created_by_human_id;
|
||||
|
||||
const handleClick = () => {
|
||||
stop();
|
||||
if (streamId) {
|
||||
navigate(`/${networkId}/${streamId}`);
|
||||
}
|
||||
};
|
||||
|
||||
const closeButton = (
|
||||
<button
|
||||
className="absolute top-1 right-1 z-10 rounded-full bg-black/50 p-0.5 text-white hover:bg-black/70"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
stop();
|
||||
}}
|
||||
>
|
||||
<X className="size-3.5" />
|
||||
</button>
|
||||
);
|
||||
|
||||
const senderBar = (
|
||||
<div className="flex items-center gap-2 px-3 py-2">
|
||||
<Avatar size="sm">
|
||||
<AvatarFallback className="bg-primary/10 text-primary text-[10px] font-medium">
|
||||
{senderInitials}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<Small className="truncate text-muted-foreground">{senderName}</Small>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="absolute bottom-4 right-4 z-40 w-52 cursor-pointer overflow-hidden rounded-xl bg-card text-card-foreground shadow-lg ring-1 ring-foreground/10"
|
||||
onClick={handleClick}
|
||||
>
|
||||
{isVideo ? (
|
||||
<div className="relative">
|
||||
{closeButton}
|
||||
<video
|
||||
src={url}
|
||||
autoPlay
|
||||
playsInline
|
||||
onEnded={stop}
|
||||
className="w-full object-cover"
|
||||
/>
|
||||
{senderBar}
|
||||
</div>
|
||||
) : (
|
||||
<div className="relative">
|
||||
{closeButton}
|
||||
<div className="flex items-center gap-2 px-3 py-3">
|
||||
<Avatar size="sm">
|
||||
<AvatarFallback className="bg-primary/10 text-primary text-[10px] font-medium">
|
||||
{senderInitials}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="min-w-0 flex-1">
|
||||
<Small className="truncate font-medium">{senderName}</Small>
|
||||
</div>
|
||||
</div>
|
||||
<audio src={url} autoPlay onEnded={stop} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -94,7 +94,7 @@ function StreamRow({
|
||||
const userId = user?.id ?? "";
|
||||
const network = useNetwork(networkId);
|
||||
|
||||
useStreamAutoplay(latestChild, particle);
|
||||
useStreamAutoplay(latestChild, particle, networkId, network);
|
||||
|
||||
const expiringSoon = useExpiringSoon(
|
||||
particle.last_child_created_at,
|
||||
|
||||
@@ -27,7 +27,7 @@ export const StreamCard = forwardRef<HTMLDivElement, StreamCardProps>(function S
|
||||
const userId = useAuthStore((s) => s.user?.id) ?? "";
|
||||
const network = useNetwork(networkId);
|
||||
|
||||
useStreamAutoplay(latestChild, particle);
|
||||
useStreamAutoplay(latestChild, particle, networkId, network);
|
||||
|
||||
const expiringSoon = useExpiringSoon(
|
||||
particle.last_child_created_at,
|
||||
|
||||
Reference in New Issue
Block a user