(fix): fullscreen popovers not showing (qol): update todo
This commit is contained in:
parent
05c186e04e
commit
bd1622d63a
9 changed files with 87 additions and 68 deletions
4
bun.lock
4
bun.lock
|
|
@ -256,7 +256,7 @@
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"@tensamin/ttp-core": "https://git.methanium.net/tensamin/ttp/archive/0.0.17.tar.gz",
|
"@tensamin/ttp-core": "https://git.methanium.net/tensamin/ttp/archive/0.0.17.tar.gz",
|
||||||
"@tensamin/ui": "https://git.methanium.net/tensamin/ui/archive/0.0.30.tar.gz",
|
"@tensamin/ui": "https://git.methanium.net/tensamin/ui/archive/0.0.31.tar.gz",
|
||||||
},
|
},
|
||||||
"packages": {
|
"packages": {
|
||||||
"@antfu/ni": ["@antfu/ni@25.0.0", "", { "dependencies": { "ansis": "^4.0.0", "fzf": "^0.5.2", "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" }, "bin": { "na": "bin/na.mjs", "ni": "bin/ni.mjs", "nr": "bin/nr.mjs", "nci": "bin/nci.mjs", "nlx": "bin/nlx.mjs", "nun": "bin/nun.mjs", "nup": "bin/nup.mjs" } }, "sha512-9q/yCljni37pkMr4sPrI3G4jqdIk074+iukc5aFJl7kmDCCsiJrbZ6zKxnES1Gwg+i9RcDZwvktl23puGslmvA=="],
|
"@antfu/ni": ["@antfu/ni@25.0.0", "", { "dependencies": { "ansis": "^4.0.0", "fzf": "^0.5.2", "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" }, "bin": { "na": "bin/na.mjs", "ni": "bin/ni.mjs", "nr": "bin/nr.mjs", "nci": "bin/nci.mjs", "nlx": "bin/nlx.mjs", "nun": "bin/nun.mjs", "nup": "bin/nup.mjs" } }, "sha512-9q/yCljni37pkMr4sPrI3G4jqdIk074+iukc5aFJl7kmDCCsiJrbZ6zKxnES1Gwg+i9RcDZwvktl23puGslmvA=="],
|
||||||
|
|
@ -697,7 +697,7 @@
|
||||||
|
|
||||||
"@tensamin/ttp-core": ["@tensamin/ttp-core@https://git.methanium.net/tensamin/ttp/archive/0.0.17.tar.gz", { "dependencies": { "@eslint/js": "^10.0.1", "@typescript-eslint/parser": "^8.59.1", "@webtransport-bun/webtransport": "^0.3.0", "globals": "^17.5.0", "typescript": "^6.0.3", "typescript-eslint": "^8.59.1", "zod": "^4.4.1" } }, "sha512-smyx+04hSnWM1oyWJfJrRWmxu7OInwyHeIlaD1h3tUrkrSxiKWHl1qCmxVO1bC+cDwyUXhJ5HUnNCbx1aWx7Dg=="],
|
"@tensamin/ttp-core": ["@tensamin/ttp-core@https://git.methanium.net/tensamin/ttp/archive/0.0.17.tar.gz", { "dependencies": { "@eslint/js": "^10.0.1", "@typescript-eslint/parser": "^8.59.1", "@webtransport-bun/webtransport": "^0.3.0", "globals": "^17.5.0", "typescript": "^6.0.3", "typescript-eslint": "^8.59.1", "zod": "^4.4.1" } }, "sha512-smyx+04hSnWM1oyWJfJrRWmxu7OInwyHeIlaD1h3tUrkrSxiKWHl1qCmxVO1bC+cDwyUXhJ5HUnNCbx1aWx7Dg=="],
|
||||||
|
|
||||||
"@tensamin/ui": ["@tensamin/ui@https://git.methanium.net/tensamin/ui/archive/0.0.30.tar.gz", { "dependencies": { "@base-ui/react": "^1.3.0", "@fontsource-variable/inter": "^5.2.6", "@tauri-apps/api": "^2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", "date-fns": "^4.1.0", "embla-carousel-react": "^8.6.0", "input-otp": "^1.4.2", "lucide-react": "^1.8.0", "next-themes": "^0.4.6", "react-day-picker": "^9.14.0", "react-resizable-panels": "^4.10.0", "recharts": "3.8.0", "shadcn": "^3.5.0", "sonner": "^2.0.7", "tailwind-merge": "^3.5.0", "tw-animate-css": "^1.3.0", "vaul": "^1.1.2" }, "peerDependencies": { "react": "^19.2.0", "react-dom": "^19.2.0" } }, "sha512-dlJBw7M/GFGHveJrL6uZA2d9yjAJ9F8QNJ2NfqCHTwzMoF6Y2ESHdeKZE5wBr2BEh9ublNqAGpN0TGD3iDV8rQ=="],
|
"@tensamin/ui": ["@tensamin/ui@https://git.methanium.net/tensamin/ui/archive/0.0.31.tar.gz", { "dependencies": { "@base-ui/react": "^1.3.0", "@fontsource-variable/inter": "^5.2.6", "@tauri-apps/api": "^2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", "date-fns": "^4.1.0", "embla-carousel-react": "^8.6.0", "input-otp": "^1.4.2", "lucide-react": "^1.8.0", "next-themes": "^0.4.6", "react-day-picker": "^9.14.0", "react-resizable-panels": "^4.10.0", "recharts": "3.8.0", "shadcn": "^3.5.0", "sonner": "^2.0.7", "tailwind-merge": "^3.5.0", "tw-animate-css": "^1.3.0", "vaul": "^1.1.2" }, "peerDependencies": { "react": "^19.2.0", "react-dom": "^19.2.0" } }, "sha512-I2FhsDtR5ElHwCasf6CfFCiyr5T2Cp9MQ2uAhcMnoNZ0tsK0mJhs+Rz9nUDmysydNyqOj8j/uC0CYXnnG1pCxQ=="],
|
||||||
|
|
||||||
"@tensamin/user": ["@tensamin/user@workspace:packages/user"],
|
"@tensamin/user": ["@tensamin/user@workspace:packages/user"],
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@
|
||||||
"jsonc-parser": "^3.3.1"
|
"jsonc-parser": "^3.3.1"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"@tensamin/ui": "https://git.methanium.net/tensamin/ui/archive/0.0.30.tar.gz",
|
"@tensamin/ui": "https://git.methanium.net/tensamin/ui/archive/0.0.31.tar.gz",
|
||||||
"@tensamin/ttp-core": "https://git.methanium.net/tensamin/ttp/archive/0.0.17.tar.gz"
|
"@tensamin/ttp-core": "https://git.methanium.net/tensamin/ttp/archive/0.0.17.tar.gz"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
import { Button, Popover, PopoverContent, PopoverTrigger } from "@tensamin/ui";
|
import { Button, Popover, PopoverContent, PopoverTrigger } from "@tensamin/ui";
|
||||||
import Wrapper from "@tensamin/user/wrapper";
|
import Wrapper from "@tensamin/user/wrapper";
|
||||||
import { Mail } from "lucide-react";
|
import { Mail } from "lucide-react";
|
||||||
import { sendCallInvite } from "../../store";
|
import { sendCallInvite, useCall } from "../../store";
|
||||||
import { log, toast } from "@tensamin/shared/log";
|
import { log, toast } from "@tensamin/shared/log";
|
||||||
import { useSession } from "@tensamin/storage/session";
|
import { useSession } from "@tensamin/storage/session";
|
||||||
|
|
||||||
|
|
@ -13,6 +14,12 @@ export default function InviteButton({
|
||||||
iconSize?: number;
|
iconSize?: number;
|
||||||
}) {
|
}) {
|
||||||
const { contacts } = useSession();
|
const { contacts } = useSession();
|
||||||
|
const screenRef = useCall((state) => state.screenRef);
|
||||||
|
const [portalContainer, setPortalContainer] = useState<HTMLElement>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setPortalContainer(screenRef?.current ?? undefined);
|
||||||
|
}, [screenRef]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover>
|
<Popover>
|
||||||
|
|
@ -23,7 +30,10 @@ export default function InviteButton({
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<PopoverContent className="flex w-40 flex-col gap-0.5 p-1!">
|
<PopoverContent
|
||||||
|
className="flex w-40 flex-col gap-0.5 p-1!"
|
||||||
|
portalProps={{ container: portalContainer }}
|
||||||
|
>
|
||||||
{contacts.map((contact) => (
|
{contacts.map((contact) => (
|
||||||
<Wrapper
|
<Wrapper
|
||||||
key={contact.user_id}
|
key={contact.user_id}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Button, Popover, PopoverContent, PopoverTrigger } from "@tensamin/ui";
|
import { Button, Popover, PopoverContent, PopoverTrigger } from "@tensamin/ui";
|
||||||
import { MonitorDot, ScreenShare } from "lucide-react";
|
import { MonitorDot, ScreenShare } from "lucide-react";
|
||||||
import { toast } from "@tensamin/shared/log";
|
import { toast } from "@tensamin/shared/log";
|
||||||
|
|
@ -14,9 +14,15 @@ export default function ScreenshareButton({
|
||||||
iconSize?: number;
|
iconSize?: number;
|
||||||
}) {
|
}) {
|
||||||
const isScreensharing = useCall((state) => state.screenShareEnabled);
|
const isScreensharing = useCall((state) => state.screenShareEnabled);
|
||||||
|
const screenRef = useCall((state) => state.screenRef);
|
||||||
|
const [portalContainer, setPortalContainer] = useState<HTMLElement>();
|
||||||
const [dialogOpen, setDialogOpen] = useState(false);
|
const [dialogOpen, setDialogOpen] = useState(false);
|
||||||
const [menuOpen, setMenuOpen] = useState(false);
|
const [menuOpen, setMenuOpen] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setPortalContainer(screenRef?.current ?? undefined);
|
||||||
|
}, [screenRef]);
|
||||||
|
|
||||||
async function startWebShare() {
|
async function startWebShare() {
|
||||||
try {
|
try {
|
||||||
await setScreenShareEnabled(true, {
|
await setScreenShareEnabled(true, {
|
||||||
|
|
@ -66,7 +72,10 @@ export default function ScreenshareButton({
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<PopoverContent className="flex w-40 flex-col gap-2">
|
<PopoverContent
|
||||||
|
className="flex w-40 flex-col gap-2"
|
||||||
|
portalProps={{ container: portalContainer }}
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
disabled={isScreensharing}
|
disabled={isScreensharing}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -101,6 +110,7 @@ export default function ScreenshareButton({
|
||||||
open={dialogOpen}
|
open={dialogOpen}
|
||||||
onOpenChange={setDialogOpen}
|
onOpenChange={setDialogOpen}
|
||||||
isScreensharing={isScreensharing}
|
isScreensharing={isScreensharing}
|
||||||
|
portalContainer={portalContainer}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -60,10 +60,12 @@ export default function ScreenShareDialog({
|
||||||
open,
|
open,
|
||||||
onOpenChange,
|
onOpenChange,
|
||||||
isScreensharing,
|
isScreensharing,
|
||||||
|
portalContainer,
|
||||||
}: {
|
}: {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onOpenChange: (open: boolean) => void;
|
onOpenChange: (open: boolean) => void;
|
||||||
isScreensharing: boolean;
|
isScreensharing: boolean;
|
||||||
|
portalContainer?: HTMLElement;
|
||||||
}) {
|
}) {
|
||||||
const {
|
const {
|
||||||
getScreenShareCapabilities,
|
getScreenShareCapabilities,
|
||||||
|
|
@ -191,7 +193,10 @@ export default function ScreenShareDialog({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||||
<DialogContent className="max-w-3xl gap-0 overflow-hidden p-0">
|
<DialogContent
|
||||||
|
className="max-w-3xl gap-0 overflow-hidden p-0"
|
||||||
|
portalProps={{ container: portalContainer }}
|
||||||
|
>
|
||||||
<DialogHeader className="p-4 pb-3">
|
<DialogHeader className="p-4 pb-3">
|
||||||
<DialogTitle>Share your screen</DialogTitle>
|
<DialogTitle>Share your screen</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import MuteButton from "./buttons/mute";
|
||||||
import DeafButton from "./buttons/deaf";
|
import DeafButton from "./buttons/deaf";
|
||||||
import { Room, Track } from "livekit-client";
|
import { Room, Track } from "livekit-client";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { ResponsiveContainer, AreaChart, Area } from "recharts";
|
import { AreaChart, Area } from "recharts";
|
||||||
import LeaveButton from "./buttons/leave";
|
import LeaveButton from "./buttons/leave";
|
||||||
|
|
||||||
export default function SidebarBox() {
|
export default function SidebarBox() {
|
||||||
|
|
@ -122,55 +122,44 @@ export function TinyPingGraph() {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{data.length > 1 && (
|
{data.length > 1 && (
|
||||||
<ResponsiveContainer
|
<AreaChart
|
||||||
width="100%"
|
width={96}
|
||||||
height="100%"
|
height={24}
|
||||||
minWidth={0}
|
data={data}
|
||||||
minHeight={24}
|
margin={{ top: 2, right: 0, bottom: 2, left: 0 }}
|
||||||
>
|
>
|
||||||
<AreaChart
|
<defs>
|
||||||
data={data}
|
<linearGradient id="pingGradient" x1="0" y1="0" x2="0" y2="1">
|
||||||
margin={{ top: 2, right: 0, bottom: 2, left: 0 }}
|
<stop
|
||||||
>
|
offset="0%"
|
||||||
<defs>
|
stopColor="currentColor"
|
||||||
<linearGradient
|
stopOpacity={0.35}
|
||||||
id="pingGradient"
|
/>
|
||||||
x1="0"
|
<stop
|
||||||
y1="0"
|
offset="70%"
|
||||||
x2="0"
|
stopColor="currentColor"
|
||||||
y2="1"
|
stopOpacity={0.08}
|
||||||
>
|
/>
|
||||||
<stop
|
<stop
|
||||||
offset="0%"
|
offset="100%"
|
||||||
stopColor="currentColor"
|
stopColor="currentColor"
|
||||||
stopOpacity={0.35}
|
stopOpacity={0}
|
||||||
/>
|
/>
|
||||||
<stop
|
</linearGradient>
|
||||||
offset="70%"
|
</defs>
|
||||||
stopColor="currentColor"
|
|
||||||
stopOpacity={0.08}
|
|
||||||
/>
|
|
||||||
<stop
|
|
||||||
offset="100%"
|
|
||||||
stopColor="currentColor"
|
|
||||||
stopOpacity={0}
|
|
||||||
/>
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
|
|
||||||
<Area
|
<Area
|
||||||
type="monotone"
|
type="monotone"
|
||||||
dataKey="ping"
|
dataKey="ping"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
strokeWidth={2}
|
strokeWidth={2}
|
||||||
fill="url(#pingGradient)"
|
fill="url(#pingGradient)"
|
||||||
fillOpacity={1}
|
fillOpacity={1}
|
||||||
dot={false}
|
dot={false}
|
||||||
activeDot={false}
|
activeDot={false}
|
||||||
isAnimationActive={false}
|
isAnimationActive={false}
|
||||||
/>
|
/>
|
||||||
</AreaChart>
|
</AreaChart>
|
||||||
</ResponsiveContainer>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -522,7 +522,9 @@ export function triggerCallLayoutCalculation() {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setScreenRef(screenRef: React.RefObject<HTMLDivElement | null> | null) {
|
export function setScreenRef(
|
||||||
|
screenRef: React.RefObject<HTMLDivElement | null> | null,
|
||||||
|
) {
|
||||||
useCall.setState({ screenRef });
|
useCall.setState({ screenRef });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1093,7 +1095,8 @@ export function useInitializeCall() {
|
||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener("fullscreenchange", handleFullscreenChange);
|
document.addEventListener("fullscreenchange", handleFullscreenChange);
|
||||||
return () => document.removeEventListener("fullscreenchange", handleFullscreenChange);
|
return () =>
|
||||||
|
document.removeEventListener("fullscreenchange", handleFullscreenChange);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// esc key listener
|
// esc key listener
|
||||||
|
|
@ -1107,7 +1110,7 @@ export function useInitializeCall() {
|
||||||
useCall.setState({ callIsFullscreen: false });
|
useCall.setState({ callIsFullscreen: false });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener("keydown", onKeyDown);
|
window.addEventListener("keydown", onKeyDown);
|
||||||
return () => window.removeEventListener("keydown", onKeyDown);
|
return () => window.removeEventListener("keydown", onKeyDown);
|
||||||
}, [location.pathname]);
|
}, [location.pathname]);
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
- Call invite popup
|
- Call invite popup
|
||||||
- Save call invite in `calls` array
|
- Save call invite in `calls` array
|
||||||
- Sounds
|
- Sounds
|
||||||
- Fullscreen button for screenshares
|
|
||||||
- Admin call actions
|
- Admin call actions
|
||||||
- Timeout
|
- Timeout
|
||||||
- Disconnect
|
- Disconnect
|
||||||
|
|
|
||||||
|
|
@ -105,14 +105,17 @@ export default function Screen() {
|
||||||
messagesRef.current = messages;
|
messagesRef.current = messages;
|
||||||
}, [messages]);
|
}, [messages]);
|
||||||
|
|
||||||
const getItemKey = React.useCallback((index: number) => {
|
const getItemKey = React.useCallback(
|
||||||
if (shouldShowConversationStart && index === 0) {
|
(index: number) => {
|
||||||
return "conversation-start";
|
if (shouldShowConversationStart && index === 0) {
|
||||||
}
|
return "conversation-start";
|
||||||
|
}
|
||||||
|
|
||||||
const messageIndex = shouldShowConversationStart ? index - 1 : index;
|
const messageIndex = shouldShowConversationStart ? index - 1 : index;
|
||||||
return messagesRef.current[messageIndex]?.send_time ?? index;
|
return messagesRef.current[messageIndex]?.send_time ?? index;
|
||||||
}, [shouldShowConversationStart]);
|
},
|
||||||
|
[shouldShowConversationStart],
|
||||||
|
);
|
||||||
|
|
||||||
const setMeasurementRef = React.useCallback(
|
const setMeasurementRef = React.useCallback(
|
||||||
(sendTime: number, element: HTMLDivElement | null) => {
|
(sendTime: number, element: HTMLDivElement | null) => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue