diff --git a/apps/web/package.json b/apps/web/package.json index a2b2347c..7d2ade8d 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -66,6 +66,7 @@ "next": "^14.2.32", "next-auth": "5.0.0-beta.29", "python-bridge": "^1.1.0", + "qrcode.react": "^4.2.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-resizable-layout": "^0.7.3", diff --git a/apps/web/src/components/common/QRCodeButton.tsx b/apps/web/src/components/common/QRCodeButton.tsx new file mode 100644 index 00000000..ab25ebab --- /dev/null +++ b/apps/web/src/components/common/QRCodeButton.tsx @@ -0,0 +1,198 @@ +import * as Popover from '@radix-ui/react-popover' +import type { CSSProperties } from 'react' +import { useState } from 'react' +import { QRCodeSVG } from 'qrcode.react' +import { useClipboard } from '@/hooks/useClipboard' + +export interface QRCodeButtonProps { + /** + * The URL to encode in the QR code and display + */ + url: string + + /** + * Optional custom styles for the trigger button + */ + style?: CSSProperties +} + +/** + * Button that opens a popover with a QR code for the share link + * Includes the URL text with a copy button + */ +export function QRCodeButton({ url, style }: QRCodeButtonProps) { + const [open, setOpen] = useState(false) + const { copied, copy } = useClipboard() + + const buttonStyles: CSSProperties = { + width: '100%', + cursor: 'pointer', + transition: 'all 0.2s ease', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + gap: '8px', + marginBottom: '6px', + border: '2px solid rgba(251, 146, 60, 0.4)', + background: 'linear-gradient(135deg, rgba(251, 146, 60, 0.2), rgba(251, 146, 60, 0.3))', + borderRadius: '8px', + padding: '10px 16px', + fontSize: '13px', + fontWeight: '600', + color: 'rgba(253, 186, 116, 1)', + ...style, + } + + const hoverStyles: CSSProperties = { + background: 'linear-gradient(135deg, rgba(251, 146, 60, 0.3), rgba(251, 146, 60, 0.4))', + borderColor: 'rgba(251, 146, 60, 0.6)', + } + + return ( + + + + + + + + {/* Title */} +
+ Scan to Join +
+ + {/* QR Code */} +
+ +
+ + {/* URL with copy button */} +
+
+ Or copy link: +
+ +
+ + +
+
+
+ ) +} diff --git a/apps/web/src/components/nav/RoomShareButtons.tsx b/apps/web/src/components/nav/RoomShareButtons.tsx index abb4a78a..c5e73da0 100644 --- a/apps/web/src/components/nav/RoomShareButtons.tsx +++ b/apps/web/src/components/nav/RoomShareButtons.tsx @@ -1,4 +1,5 @@ import { CopyButton } from '@/components/common/CopyButton' +import { QRCodeButton } from '@/components/common/QRCodeButton' export interface RoomShareButtonsProps { /** @@ -41,6 +42,8 @@ export function RoomShareButtons({ joinCode, shareUrl }: RoomShareButtonsProps) } copiedLabel="Link Copied!" /> + + ) }