Implemented home page with TradingView widgets
This commit is contained in:
parent
f042523799
commit
295a8a1363
|
|
@ -1,18 +1,52 @@
|
||||||
import React from 'react'
|
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 Home = () => {
|
||||||
|
const scriptUrl = `https://s3.tradingview.com/external-embedding/embed-widget-`;
|
||||||
return (
|
return (
|
||||||
<div className="flex min-h-screen home-wrapper">
|
<div className="flex min-h-screen home-wrapper">
|
||||||
<div className="flex flex-col items-center justify-center w-full">
|
<section className="grid w-full gap-8 home-section">
|
||||||
<h1 className="text-4xl font-bold mb-4">Welcome to OpenStock</h1>
|
<div className="md:col-span-1 xl:col-span-1">
|
||||||
<p className="text-lg mb-8 text-center max-w-2xl">
|
<TradingViewWidget
|
||||||
OpenStock is an open-source alternative to expensive market platforms.
|
title="Market Overview"
|
||||||
Track real-time prices, set personalized alerts, and explore detailed company insights.
|
scriptUrl={`${scriptUrl}market-overview.js`}
|
||||||
</p>
|
config={MARKET_OVERVIEW_WIDGET_CONFIG}
|
||||||
<Button>Get Started</Button>
|
className="custom-chart"
|
||||||
</div>
|
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>
|
</div>
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
export default Home
|
export default Home
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
@ -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
|
||||||
342
lib/constants.ts
342
lib/constants.ts
|
|
@ -1,5 +1,339 @@
|
||||||
export const NAV_ITEMS = [
|
export const NAV_ITEMS = [
|
||||||
{href: "/", label: 'Dashboard'},
|
{ href: '/', label: 'Dashboard' },
|
||||||
{href: "/search", label: 'Search'},
|
{ href: '/search', label: 'Search' },
|
||||||
{href: "/watchlist", label: 'Watchlist'},
|
{ 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',
|
||||||
|
];
|
||||||
Loading…
Reference in New Issue