feat: implement expandable TradingView widgets with immersive full-screen mode

This commit is contained in:
Mr. Algorithm
2026-02-01 04:06:51 +05:30
parent bc56a585af
commit c2af42f260
2 changed files with 57 additions and 9 deletions

View File

@@ -39,6 +39,7 @@ export default async function StockDetails({ params }: StockDetailsPageProps) {
config={CANDLE_CHART_WIDGET_CONFIG(symbol)}
className="custom-chart"
height={600}
allowExpand={true}
/>
<TradingViewWidget
@@ -46,6 +47,7 @@ export default async function StockDetails({ params }: StockDetailsPageProps) {
config={BASELINE_WIDGET_CONFIG(symbol)}
className="custom-chart"
height={600}
allowExpand={true}
/>
</div>

View File

@@ -1,8 +1,10 @@
'use client';
import React, { memo } from 'react';
import React, { memo, useState, useEffect } from 'react';
import useTradingViewWidget from "@/hooks/useTradingViewWidget";
import {cn} from "@/lib/utils";
import { cn } from "@/lib/utils";
import { Maximize2, Minimize2 } from 'lucide-react';
import { Button } from '@/components/ui/button';
interface TradingViewWidgetProps {
title?: string;
@@ -10,19 +12,63 @@ interface TradingViewWidgetProps {
config: Record<string, unknown>;
height?: number;
className?: string;
allowExpand?: boolean;
}
const TradingViewWidget = ({ title, scriptUrl, config, height = 600, className }: TradingViewWidgetProps) => {
const containerRef = useTradingViewWidget(scriptUrl, config, height);
const TradingViewWidget = ({ title, scriptUrl, config, height = 600, className, allowExpand = false }: TradingViewWidgetProps) => {
const [isExpanded, setIsExpanded] = useState(false);
const [windowHeight, setWindowHeight] = useState(0);
useEffect(() => {
if (typeof window !== 'undefined') {
setWindowHeight(window.innerHeight);
const handleResize = () => setWindowHeight(window.innerHeight);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}
}, []);
const currentHeight = isExpanded ? windowHeight : height;
const widgetConfig = {
...config,
height: currentHeight,
width: "100%",
autosize: true,
};
const containerRef = useTradingViewWidget(scriptUrl, widgetConfig, currentHeight);
const toggleExpand = () => {
setIsExpanded(!isExpanded);
};
return (
<div className="w-full">
{title && <h3 className="font-semibold text-2xl text-gray-100 mb-5">{title}</h3>}
<div className={cn('tradingview-widget-container', className)} ref={containerRef}>
<div className="tradingview-widget-container__widget" style={{ height, width: "100%" }} />
<div className={cn("w-full transition-all duration-300", isExpanded && "fixed inset-0 z-[9999] bg-background")}>
<div className={cn("w-full relative group", isExpanded && "h-full w-full")}>
{title && !isExpanded && <h3 className="font-semibold text-2xl text-gray-100 mb-5">{title}</h3>}
{allowExpand && (
<Button
variant="ghost"
size="icon"
onClick={toggleExpand}
className={cn(
"absolute top-2 right-2 z-10 hover:bg-background/50 text-muted-foreground hover:text-foreground transition-all duration-200",
!isExpanded ? "opacity-0 group-hover:opacity-100" : "bg-background/20"
)}
title={isExpanded ? "Minimize" : "Click to expand"}
>
{isExpanded ? <Minimize2 className="h-6 w-6" /> : <Maximize2 className="h-6 w-6" />}
</Button>
)}
<div className={cn('tradingview-widget-container', className, isExpanded && "h-full")} ref={containerRef}>
<div className="tradingview-widget-container__widget" style={{ height: currentHeight, width: "100%" }} />
</div>
</div>
</div>
);
}
export default memo(TradingViewWidget);
export default memo(TradingViewWidget);