feat: support image lightbox viewer and file download (#151)
* feat: add lightbox overlay with nice mechanics * ui tweak for top bar in stream view * support locally downloading attachments
This commit was merged in pull request #151.
This commit is contained in:
@@ -24,6 +24,7 @@ import { StreamPresenceProvider, useStreamPresence, useStreamComposing, useStrea
|
||||
import { ComposingIndicator } from "@/components/composing-indicator";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useMount } from "react-use";
|
||||
import { usePlaybackStore } from "@/stores/playback-store";
|
||||
|
||||
function getReactions(particle: Particle): Record<string, string[]> | undefined {
|
||||
if (isParticleDeleted(particle)) return undefined;
|
||||
@@ -192,6 +193,8 @@ function StreamViewInner({ path, streamParticle }: StreamViewProps) {
|
||||
|
||||
const [composeActive, setComposeActive] = useState(false);
|
||||
const [composeStep, setComposeStep] = useState<ComposeStep>("idle");
|
||||
const playbackSuspended = usePlaybackStore((s) => s.suspendCount > 0);
|
||||
const playbackBlocked = composeActive || playbackSuspended;
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [fastPlayback, setFastPlayback] = useState(false);
|
||||
const [showKeybindings, setShowKeybindings] = useState(false);
|
||||
@@ -243,11 +246,11 @@ function StreamViewInner({ path, streamParticle }: StreamViewProps) {
|
||||
setProgress(0);
|
||||
}, [currentParticle?.id]);
|
||||
|
||||
// Pause/resume playback when compose overlay opens/closes
|
||||
// Pause/resume playback when compose overlay or lightbox is open.
|
||||
useEffect(() => {
|
||||
if (composeActive) pause();
|
||||
if (playbackBlocked) pause();
|
||||
else resume();
|
||||
}, [composeActive, pause, resume]);
|
||||
}, [playbackBlocked, pause, resume]);
|
||||
|
||||
// Playback keyboard: arrows, escape, hold-space-to-pause
|
||||
useEffect(() => {
|
||||
@@ -261,7 +264,7 @@ function StreamViewInner({ path, streamParticle }: StreamViewProps) {
|
||||
}
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (composeActive) return;
|
||||
if (playbackBlocked) return;
|
||||
if (isInputTarget(e)) return;
|
||||
|
||||
switch (e.key) {
|
||||
@@ -313,7 +316,7 @@ function StreamViewInner({ path, streamParticle }: StreamViewProps) {
|
||||
};
|
||||
|
||||
const handleKeyUp = (e: KeyboardEvent) => {
|
||||
if (composeActive) return;
|
||||
if (playbackBlocked) return;
|
||||
if (isInputTarget(e)) return;
|
||||
|
||||
if (e.key === " ") {
|
||||
@@ -333,22 +336,7 @@ function StreamViewInner({ path, streamParticle }: StreamViewProps) {
|
||||
window.removeEventListener("keyup", handleKeyUp);
|
||||
};
|
||||
},
|
||||
[composeActive, next, prev, pause, resume, navigate, networkId, streamParticle.id, setShowKeybindings, handleToggleReaction, recordingMode, setRecordingMode],
|
||||
);
|
||||
|
||||
// Click-to-navigate: left 30% = prev, right 70% = next
|
||||
// Suppressed when the user has selected text (drag-to-select)
|
||||
const handlePlaybackClick = useCallback(
|
||||
(e: React.MouseEvent<HTMLDivElement>) => {
|
||||
const selection = window.getSelection();
|
||||
if (selection && selection.toString().length > 0) return;
|
||||
|
||||
const rect = e.currentTarget.getBoundingClientRect();
|
||||
const x = (e.clientX - rect.left) / rect.width;
|
||||
if (x < 0.3) prev();
|
||||
else if (x > 0.7) next();
|
||||
},
|
||||
[prev, next],
|
||||
[playbackBlocked, next, prev, pause, resume, navigate, networkId, streamParticle.id, setShowKeybindings, handleToggleReaction, recordingMode, setRecordingMode],
|
||||
);
|
||||
|
||||
if (children.length === 0) {
|
||||
@@ -430,10 +418,7 @@ function StreamViewInner({ path, streamParticle }: StreamViewProps) {
|
||||
{/* Main playback area */}
|
||||
<div className="flex-1 overflow-hidden">
|
||||
{currentParticle && (
|
||||
<div
|
||||
className="relative flex h-full w-full cursor-pointer items-center justify-center"
|
||||
onClick={handlePlaybackClick}
|
||||
>
|
||||
<div className="relative flex h-full w-full cursor-pointer items-center justify-center">
|
||||
{renderParticle(currentParticle)}
|
||||
|
||||
{fastPlayback && (
|
||||
|
||||
Reference in New Issue
Block a user