/* Copyright (C) 2023-2026 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ 'use client' import { type ComponentProps, createContext, type ReactNode, useContext, useEffect, useState, } from 'react' import { ChevronDownIcon } from 'lucide-react' import { useTranslation } from 'react-i18next' import dayjs from '@/lib/dayjs' import { cn } from '@/lib/utils' import { Button } from '@/components/ui/button' import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from '@/components/ui/collapsible' import { Input } from '@/components/ui/input' import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from '@/components/ui/tooltip' export type WebPreviewContextValue = { url: string setUrl: (url: string) => void consoleOpen: boolean setConsoleOpen: (open: boolean) => void } const WebPreviewContext = createContext(null) const useWebPreview = () => { const context = useContext(WebPreviewContext) if (!context) { throw new Error('WebPreview components must be used within a WebPreview') } return context } export type WebPreviewProps = ComponentProps<'div'> & { defaultUrl?: string onUrlChange?: (url: string) => void } export const WebPreview = ({ className, children, defaultUrl = '', onUrlChange, ...props }: WebPreviewProps) => { const [url, setUrl] = useState(defaultUrl) const [consoleOpen, setConsoleOpen] = useState(false) const handleUrlChange = (newUrl: string) => { setUrl(newUrl) onUrlChange?.(newUrl) } const contextValue: WebPreviewContextValue = { url, setUrl: handleUrlChange, consoleOpen, setConsoleOpen, } return (
{children}
) } export type WebPreviewNavigationProps = ComponentProps<'div'> export const WebPreviewNavigation = ({ className, children, ...props }: WebPreviewNavigationProps) => (
{children}
) export type WebPreviewNavigationButtonProps = ComponentProps & { tooltip?: string } export const WebPreviewNavigationButton = ({ onClick, disabled, tooltip, children, ...props }: WebPreviewNavigationButtonProps) => ( } > {children}

{tooltip}

) export type WebPreviewUrlProps = ComponentProps export const WebPreviewUrl = ({ value, onChange, onKeyDown, ...props }: WebPreviewUrlProps) => { const { t } = useTranslation() const { url, setUrl } = useWebPreview() const [inputValue, setInputValue] = useState(url) // Sync input value with context URL when it changes externally useEffect(() => { setInputValue(url) }, [url]) const handleChange = (event: React.ChangeEvent) => { setInputValue(event.target.value) onChange?.(event) } const handleKeyDown = (event: React.KeyboardEvent) => { if (event.key === 'Enter') { const target = event.target as HTMLInputElement setUrl(target.value) } onKeyDown?.(event) } return ( ) } export type WebPreviewBodyProps = ComponentProps<'iframe'> & { loading?: ReactNode } export const WebPreviewBody = ({ className, loading, src, ...props }: WebPreviewBodyProps) => { const { t } = useTranslation() const { url } = useWebPreview() return (