Merge pull request #4 from ravixalgorithm/homepage

Implemented home page with TradingView widgets
This commit is contained in:
Mr. Algorithm 2025-09-30 10:37:28 +05:30 committed by GitHub
commit 8411bea110
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 441 additions and 13 deletions

View File

@ -1,18 +1,52 @@
import React from 'react'
import {Button} from "../../components/ui/button";
import TradingViewWidget from "@/components/TradingViewWidget";
import {MARKET_DATA_WIDGET_CONFIG, MARKET_OVERVIEW_WIDGET_CONFIG, TOP_STORIES_WIDGET_CONFIG} from "@/lib/constants";
const Home = () => {
const scriptUrl = `https://s3.tradingview.com/external-embedding/embed-widget-`;
return (
<div className="flex min-h-screen home-wrapper">
<div className="flex flex-col items-center justify-center w-full">
<h1 className="text-4xl font-bold mb-4">Welcome to OpenStock</h1>
<p className="text-lg mb-8 text-center max-w-2xl">
OpenStock is an open-source alternative to expensive market platforms.
Track real-time prices, set personalized alerts, and explore detailed company insights.
</p>
<Button>Get Started</Button>
</div>
<section className="grid w-full gap-8 home-section">
<div className="md:col-span-1 xl:col-span-1">
<TradingViewWidget
title="Market Overview"
scriptUrl={`${scriptUrl}market-overview.js`}
config={MARKET_OVERVIEW_WIDGET_CONFIG}
className="custom-chart"
height={600}
/>
</div>
<div className="md:col-span-1 xl:col-span-2">
<TradingViewWidget
title="Stock Heatmap"
scriptUrl={`${scriptUrl}stock-heatmap.js`}
config={MARKET_OVERVIEW_WIDGET_CONFIG}
className="custom-chart"
height={600}
/>
</div>
</section>
<section className="grid w-full gap-8 home-section">
<div className="md:col-span-1 xl:col-span-2">
<TradingViewWidget
scriptUrl={`${scriptUrl}market-quotes.js`}
config={MARKET_DATA_WIDGET_CONFIG}
height={600}
/>
</div>
<div className="md:col-span-1 xl:col-span-1">
<TradingViewWidget
scriptUrl={`${scriptUrl}timeline.js`}
config={TOP_STORIES_WIDGET_CONFIG}
height={600}
/>
</div>
</section>
</div>
)
}
export default Home

View File

@ -0,0 +1,30 @@
'use client';
import React, { memo } from 'react';
import useTradingViewWidget from "@/hooks/useTradingViewWidget";
import {cn} from "@/lib/utils";
interface TradingViewWidgetProps{
title: string;
scriptUrl: string;
config: Record<string, unknown>;
height?: number;
className?: string;
}
const TradingViewWidget = ({title, scriptUrl, config, height = 600, className}: TradingViewWidgetProps) => {
const containerRef = useTradingViewWidget(scriptUrl, config, height);
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>
</div>
);
}
export default memo(TradingViewWidget);

View File

@ -0,0 +1,30 @@
'use client';
import { useEffect, useRef } from "react";
const useTradingViewWidget = (scriptUrl: string, config: Record<string, unknown>, height = 600) => {
const containerRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
if (!containerRef.current) return;
if (containerRef.current.dataset.loaded) return;
containerRef.current.innerHTML = `<div class="tradingview-widget-container__widget" style="width: 100%; height: ${height}px;"></div>`;
const script = document.createElement("script");
script.src = scriptUrl;
script.async = true;
script.innerHTML = JSON.stringify(config);
containerRef.current.appendChild(script);
containerRef.current.dataset.loaded = 'true';
return () => {
if(containerRef.current) {
containerRef.current.innerHTML = '';
delete containerRef.current.dataset.loaded;
}
}
}, [scriptUrl, config, height])
return containerRef;
}
export default useTradingViewWidget

View File

@ -1,5 +1,339 @@
export const NAV_ITEMS = [
{href: "/", label: 'Dashboard'},
{href: "/search", label: 'Search'},
{href: "/watchlist", label: 'Watchlist'},
]
{ href: '/', label: 'Dashboard' },
{ href: '/search', label: 'Search' },
{ href: '/watchlist', label: 'Watchlist' },
];
// Sign-up form select options
export const INVESTMENT_GOALS = [
{ value: 'Growth', label: 'Growth' },
{ value: 'Income', label: 'Income' },
{ value: 'Balanced', label: 'Balanced' },
{ value: 'Conservative', label: 'Conservative' },
];
export const RISK_TOLERANCE_OPTIONS = [
{ value: 'Low', label: 'Low' },
{ value: 'Medium', label: 'Medium' },
{ value: 'High', label: 'High' },
];
export const PREFERRED_INDUSTRIES = [
{ value: 'Technology', label: 'Technology' },
{ value: 'Healthcare', label: 'Healthcare' },
{ value: 'Finance', label: 'Finance' },
{ value: 'Energy', label: 'Energy' },
{ value: 'Consumer Goods', label: 'Consumer Goods' },
];
export const ALERT_TYPE_OPTIONS = [
{ value: 'upper', label: 'Upper' },
{ value: 'lower', label: 'Lower' },
];
export const CONDITION_OPTIONS = [
{ value: 'greater', label: 'Greater than (>)' },
{ value: 'less', label: 'Less than (<)' },
];
// TradingView Charts
export const MARKET_OVERVIEW_WIDGET_CONFIG = {
colorTheme: 'dark', // dark mode
dateRange: '12M', // last 12 months
locale: 'en', // language
largeChartUrl: '', // link to a large chart if needed
isTransparent: true, // makes background transparent
showFloatingTooltip: true, // show tooltip on hover
plotLineColorGrowing: '#0FEDBE', // line color when price goes up
plotLineColorFalling: '#0FEDBE', // line color when price falls
gridLineColor: 'rgba(240, 243, 250, 0)', // grid line color
scaleFontColor: '#DBDBDB', // font color for scale
belowLineFillColorGrowing: 'rgba(41, 98, 255, 0.12)', // fill under line when growing
belowLineFillColorFalling: 'rgba(41, 98, 255, 0.12)', // fill under line when falling
belowLineFillColorGrowingBottom: 'rgba(41, 98, 255, 0)',
belowLineFillColorFallingBottom: 'rgba(41, 98, 255, 0)',
symbolActiveColor: 'rgba(15, 237, 190, 0.05)', // highlight color for active symbol
tabs: [
{
title: 'Financial',
symbols: [
{ s: 'NYSE:JPM', d: 'JPMorgan Chase' },
{ s: 'NYSE:WFC', d: 'Wells Fargo Co New' },
{ s: 'NYSE:BAC', d: 'Bank Amer Corp' },
{ s: 'NYSE:HSBC', d: 'Hsbc Hldgs Plc' },
{ s: 'NYSE:C', d: 'Citigroup Inc' },
{ s: 'NYSE:MA', d: 'Mastercard Incorporated' },
],
},
{
title: 'Technology',
symbols: [
{ s: 'NASDAQ:AAPL', d: 'Apple' },
{ s: 'NASDAQ:GOOGL', d: 'Alphabet' },
{ s: 'NASDAQ:MSFT', d: 'Microsoft' },
{ s: 'NASDAQ:FB', d: 'Meta Platforms' },
{ s: 'NYSE:ORCL', d: 'Oracle Corp' },
{ s: 'NASDAQ:INTC', d: 'Intel Corp' },
],
},
{
title: 'Services',
symbols: [
{ s: 'NASDAQ:AMZN', d: 'Amazon' },
{ s: 'NYSE:BABA', d: 'Alibaba Group Hldg Ltd' },
{ s: 'NYSE:T', d: 'At&t Inc' },
{ s: 'NYSE:WMT', d: 'Walmart' },
{ s: 'NYSE:V', d: 'Visa' },
],
},
],
support_host: 'https://www.tradingview.com', // TradingView host
backgroundColor: '#141414', // background color
width: '100%', // full width
height: 600, // height in px
showSymbolLogo: true, // show logo next to symbols
showChart: true, // display mini chart
};
export const HEATMAP_WIDGET_CONFIG = {
dataSource: 'SPX500',
blockSize: 'market_cap_basic',
blockColor: 'change',
grouping: 'sector',
isTransparent: true,
locale: 'en',
symbolUrl: '',
colorTheme: 'dark',
exchanges: [],
hasTopBar: false,
isDataSetEnabled: false,
isZoomEnabled: true,
hasSymbolTooltip: true,
isMonoSize: false,
width: '100%',
height: '600',
};
export const TOP_STORIES_WIDGET_CONFIG = {
displayMode: 'regular',
feedMode: 'market',
colorTheme: 'dark',
isTransparent: true,
locale: 'en',
market: 'stock',
width: '100%',
height: '600',
};
export const MARKET_DATA_WIDGET_CONFIG = {
title: 'Stocks',
width: '100%',
height: 600,
locale: 'en',
showSymbolLogo: true,
colorTheme: 'dark',
isTransparent: false,
backgroundColor: '#0F0F0F',
symbolsGroups: [
{
name: 'Financial',
symbols: [
{ name: 'NYSE:JPM', displayName: 'JPMorgan Chase' },
{ name: 'NYSE:WFC', displayName: 'Wells Fargo Co New' },
{ name: 'NYSE:BAC', displayName: 'Bank Amer Corp' },
{ name: 'NYSE:HSBC', displayName: 'Hsbc Hldgs Plc' },
{ name: 'NYSE:C', displayName: 'Citigroup Inc' },
{ name: 'NYSE:MA', displayName: 'Mastercard Incorporated' },
],
},
{
name: 'Technology',
symbols: [
{ name: 'NASDAQ:AAPL', displayName: 'Apple' },
{ name: 'NASDAQ:GOOGL', displayName: 'Alphabet' },
{ name: 'NASDAQ:MSFT', displayName: 'Microsoft' },
{ name: 'NASDAQ:FB', displayName: 'Meta Platforms' },
{ name: 'NYSE:ORCL', displayName: 'Oracle Corp' },
{ name: 'NASDAQ:INTC', displayName: 'Intel Corp' },
],
},
{
name: 'Services',
symbols: [
{ name: 'NASDAQ:AMZN', displayName: 'Amazon' },
{ name: 'NYSE:BABA', displayName: 'Alibaba Group Hldg Ltd' },
{ name: 'NYSE:T', displayName: 'At&t Inc' },
{ name: 'NYSE:WMT', displayName: 'Walmart' },
{ name: 'NYSE:V', displayName: 'Visa' },
],
},
],
};
export const SYMBOL_INFO_WIDGET_CONFIG = (symbol: string) => ({
symbol: symbol.toUpperCase(),
colorTheme: 'dark',
isTransparent: true,
locale: 'en',
width: '100%',
height: 170,
});
export const CANDLE_CHART_WIDGET_CONFIG = (symbol: string) => ({
allow_symbol_change: false,
calendar: false,
details: true,
hide_side_toolbar: true,
hide_top_toolbar: false,
hide_legend: false,
hide_volume: false,
hotlist: false,
interval: 'D',
locale: 'en',
save_image: false,
style: 1,
symbol: symbol.toUpperCase(),
theme: 'dark',
timezone: 'Etc/UTC',
backgroundColor: '#141414',
gridColor: '#141414',
watchlist: [],
withdateranges: false,
compareSymbols: [],
studies: [],
width: '100%',
height: 600,
});
export const BASELINE_WIDGET_CONFIG = (symbol: string) => ({
allow_symbol_change: false,
calendar: false,
details: false,
hide_side_toolbar: true,
hide_top_toolbar: false,
hide_legend: false,
hide_volume: false,
hotlist: false,
interval: 'D',
locale: 'en',
save_image: false,
style: 10,
symbol: symbol.toUpperCase(),
theme: 'dark',
timezone: 'Etc/UTC',
backgroundColor: '#141414',
gridColor: '#141414',
watchlist: [],
withdateranges: false,
compareSymbols: [],
studies: [],
width: '100%',
height: 600,
});
export const TECHNICAL_ANALYSIS_WIDGET_CONFIG = (symbol: string) => ({
symbol: symbol.toUpperCase(),
colorTheme: 'dark',
isTransparent: 'true',
locale: 'en',
width: '100%',
height: 400,
interval: '1h',
largeChartUrl: '',
});
export const COMPANY_PROFILE_WIDGET_CONFIG = (symbol: string) => ({
symbol: symbol.toUpperCase(),
colorTheme: 'dark',
isTransparent: 'true',
locale: 'en',
width: '100%',
height: 440,
});
export const COMPANY_FINANCIALS_WIDGET_CONFIG = (symbol: string) => ({
symbol: symbol.toUpperCase(),
colorTheme: 'dark',
isTransparent: 'true',
locale: 'en',
width: '100%',
height: 464,
displayMode: 'regular',
largeChartUrl: '',
});
export const POPULAR_STOCK_SYMBOLS = [
// Tech Giants (the big technology companies)
'AAPL',
'MSFT',
'GOOGL',
'AMZN',
'TSLA',
'META',
'NVDA',
'NFLX',
'ORCL',
'CRM',
// Growing Tech Companies
'ADBE',
'INTC',
'AMD',
'PYPL',
'UBER',
'ZOOM',
'SPOT',
'SQ',
'SHOP',
'ROKU',
// Newer Tech Companies
'SNOW',
'PLTR',
'COIN',
'RBLX',
'DDOG',
'CRWD',
'NET',
'OKTA',
'TWLO',
'ZM',
// Consumer & Delivery Apps
'DOCU',
'PTON',
'PINS',
'SNAP',
'LYFT',
'DASH',
'ABNB',
'RIVN',
'LCID',
'NIO',
// International Companies
'XPEV',
'LI',
'BABA',
'JD',
'PDD',
'TME',
'BILI',
'DIDI',
'GRAB',
'SE',
];
export const NO_MARKET_NEWS =
'<p class="mobile-text" style="margin:0 0 20px 0;font-size:16px;line-height:1.6;color:#4b5563;">No market news available today. Please check back tomorrow.</p>';
export const WATCHLIST_TABLE_HEADER = [
'Company',
'Symbol',
'Price',
'Change',
'Market Cap',
'P/E Ratio',
'Alert',
'Action',
];