@hanzo/ui 5.1.8 → 5.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/3d/button.js +1 -0
- package/dist/3d/button.mjs +1 -0
- package/dist/3d/card.js +1 -0
- package/dist/3d/card.mjs +1 -0
- package/dist/3d/carousel.js +1 -0
- package/dist/3d/carousel.mjs +1 -0
- package/dist/3d/grid.js +1 -0
- package/dist/3d/grid.mjs +1 -0
- package/dist/3d/index.js +1 -0
- package/dist/3d/index.mjs +1 -0
- package/dist/3d/marquee.js +1 -0
- package/dist/3d/marquee.mjs +1 -0
- package/dist/3d/pin.js +1 -0
- package/dist/3d/pin.mjs +1 -0
- package/dist/animation/apple-cards-carousel.js +1 -0
- package/dist/animation/apple-cards-carousel.mjs +1 -0
- package/dist/animation/apple-hello-effect.js +1 -0
- package/dist/animation/apple-hello-effect.mjs +1 -0
- package/dist/animation/beam.js +1 -0
- package/dist/animation/beam.mjs +1 -0
- package/dist/animation/cursor.js +1 -0
- package/dist/animation/cursor.mjs +1 -0
- package/dist/animation/index.js +2 -0
- package/dist/animation/index.mjs +2 -0
- package/dist/animation/testimonials.js +1 -0
- package/dist/animation/testimonials.mjs +1 -0
- package/dist/animation/tooltip.js +1 -0
- package/dist/animation/tooltip.mjs +1 -0
- package/dist/avatar.js +1 -1
- package/dist/avatar.mjs +1 -1
- package/dist/chunk-266OC746.mjs +2 -0
- package/dist/chunk-2B7NONPA.mjs +1 -0
- package/dist/chunk-2SI3T6F4.mjs +1 -0
- package/dist/chunk-37TVHMP2.mjs +1 -0
- package/dist/chunk-4A27XTBF.js +12 -0
- package/dist/chunk-4CJ44NSE.js +1 -0
- package/dist/chunk-4SKGA2GA.mjs +1 -0
- package/dist/chunk-4TE2JWNG.js +1 -0
- package/dist/chunk-4XCQFT2C.mjs +1 -0
- package/dist/chunk-4YMLAU5Z.js +1 -0
- package/dist/chunk-5RACWNGV.mjs +1 -0
- package/dist/chunk-A3S2QAGG.mjs +3 -0
- package/dist/chunk-B3L4REN3.js +1 -0
- package/dist/chunk-B4RJSSWX.js +1 -0
- package/dist/chunk-B7LBF7R7.js +1 -0
- package/dist/chunk-BIWGFJPQ.mjs +1 -0
- package/dist/chunk-BOBL44QL.mjs +2 -0
- package/dist/chunk-BUMLLGES.mjs +1 -0
- package/dist/chunk-BYFLZ6DP.js +1 -0
- package/dist/chunk-C66RILAI.mjs +42 -0
- package/dist/chunk-CDBOLI7U.js +42 -0
- package/dist/chunk-CDO4BR6V.js +1 -0
- package/dist/chunk-CGUI5CEC.mjs +1 -0
- package/dist/chunk-CICZVOAY.js +1 -0
- package/dist/chunk-DB3WJTS4.js +1 -0
- package/dist/chunk-DKL2FM7J.mjs +1 -0
- package/dist/chunk-DNYROKHM.mjs +1 -0
- package/dist/chunk-DRLJ6Z7Q.js +1 -0
- package/dist/chunk-DYF5HRXR.mjs +1 -0
- package/dist/chunk-EATSKPYS.js +10 -0
- package/dist/chunk-EGN6SLB7.js +3 -0
- package/dist/chunk-EK5T4DQ2.js +2 -0
- package/dist/chunk-ELR6GOUX.mjs +1 -0
- package/dist/chunk-EQAPJD4H.mjs +1 -0
- package/dist/chunk-FCHJPQ73.mjs +1 -0
- package/dist/chunk-FE2O6776.js +1 -0
- package/dist/chunk-FIN2IX2D.mjs +1 -0
- package/dist/chunk-FQO25CNQ.mjs +1 -0
- package/dist/chunk-FX7VUERX.mjs +2 -0
- package/dist/chunk-G4X4J5EW.js +1 -0
- package/dist/chunk-GFWDGZO7.mjs +1 -0
- package/dist/chunk-GTFU3T2U.mjs +1 -0
- package/dist/chunk-GTUCZ5TW.js +1 -0
- package/dist/chunk-HEZV2WAY.js +2 -0
- package/dist/chunk-HIDGPSBX.js +1 -0
- package/dist/chunk-HLJAWNJK.js +1 -0
- package/dist/chunk-HM47SDFC.mjs +1 -0
- package/dist/chunk-HQGRRTIW.mjs +2 -0
- package/dist/chunk-J4DJZHOE.js +2 -0
- package/dist/chunk-J5KX3VTM.js +1 -0
- package/dist/chunk-JNNKXOA3.js +1 -0
- package/dist/chunk-JRWBF5SH.js +1 -0
- package/dist/chunk-JTTJLJON.js +2 -0
- package/dist/chunk-JZGTSHZ4.js +1 -0
- package/dist/chunk-LADFCKQD.mjs +1 -0
- package/dist/chunk-LHKPSY4L.js +1 -0
- package/dist/chunk-LMOX4GTY.js +1 -0
- package/dist/chunk-LYXX7LU2.js +6 -0
- package/dist/chunk-M4GZKMQS.mjs +6 -0
- package/dist/chunk-MJDVKTGX.mjs +1 -0
- package/dist/chunk-MPZRRATY.mjs +1 -0
- package/dist/chunk-MUI6SJLP.js +1 -0
- package/dist/chunk-NBXNOMXS.mjs +2 -0
- package/dist/chunk-NE7ICOQE.mjs +2 -0
- package/dist/chunk-NL5ZWDIJ.mjs +1 -0
- package/dist/chunk-NS6CEKHH.mjs +1 -0
- package/dist/chunk-O6RJT46G.js +1 -0
- package/dist/chunk-OC34KEWQ.mjs +1 -0
- package/dist/chunk-OL63HLUI.js +2 -0
- package/dist/chunk-OLTPOUB2.js +2 -0
- package/dist/chunk-OQOBF7QQ.js +1 -0
- package/dist/chunk-OY2LIJR2.mjs +2 -0
- package/dist/chunk-PE5GANLF.mjs +1 -0
- package/dist/chunk-PIDMTL36.mjs +1 -0
- package/dist/chunk-QGHPGSQL.mjs +2 -0
- package/dist/chunk-QLB43TFO.mjs +1 -0
- package/dist/chunk-R2JKVWNB.js +2 -0
- package/dist/chunk-RAT4U2JG.mjs +1 -0
- package/dist/chunk-RBURLSG7.js +2 -0
- package/dist/chunk-RO3D3W57.js +1 -0
- package/dist/chunk-RPOB4E3W.js +1 -0
- package/dist/chunk-RVPP46TI.js +2 -0
- package/dist/chunk-S2UB25HB.mjs +12 -0
- package/dist/chunk-SCYHSLR2.js +2 -0
- package/dist/chunk-SRPQZYB6.js +1 -0
- package/dist/chunk-TCTFHNND.js +1 -0
- package/dist/chunk-TG6V2JL2.js +1 -0
- package/dist/chunk-TGL6VBFN.js +1 -0
- package/dist/chunk-TNF5G2ZW.mjs +1 -0
- package/dist/chunk-TXND3LRQ.mjs +1 -0
- package/dist/chunk-U7CUKU4W.mjs +1 -0
- package/dist/chunk-UPRWI4ON.mjs +2 -0
- package/dist/chunk-V23X5ZD6.mjs +2 -0
- package/dist/chunk-VFFLOHVQ.mjs +1 -0
- package/dist/chunk-VHB7M646.mjs +10 -0
- package/dist/chunk-VJDDFZ7N.mjs +2 -0
- package/dist/chunk-VN2BKXHJ.js +1 -0
- package/dist/chunk-VT77IEYF.mjs +1 -0
- package/dist/chunk-VTJ6QUCR.js +1 -0
- package/dist/chunk-VUIJAFJC.js +1 -0
- package/dist/chunk-WN767YS2.mjs +2 -0
- package/dist/chunk-WREKV6XQ.mjs +1 -0
- package/dist/chunk-XBDQSMTI.js +2 -0
- package/dist/chunk-XFK7RTKE.js +1 -0
- package/dist/chunk-XJTWK37Q.mjs +2 -0
- package/dist/chunk-XMYCJ2B5.js +1 -0
- package/dist/chunk-XOGRJZXX.mjs +1 -0
- package/dist/chunk-XOQCRR5Q.js +2 -0
- package/dist/chunk-Y6SIRKG3.js +2 -0
- package/dist/chunk-YLY2B6UX.mjs +1 -0
- package/dist/chunk-YQUF7KPG.mjs +1 -0
- package/dist/chunk-Z3DNBRF4.js +1 -0
- package/dist/chunk-ZA3JIBDG.js +1 -0
- package/dist/chunk-ZDOIGP2L.js +1 -0
- package/dist/code/block.js +1 -0
- package/dist/code/block.mjs +1 -0
- package/dist/code/compare.js +1 -0
- package/dist/code/compare.mjs +1 -0
- package/dist/code/diff.js +1 -0
- package/dist/code/diff.mjs +1 -0
- package/dist/code/editor.js +1 -0
- package/dist/code/editor.mjs +1 -0
- package/dist/code/explorer.js +1 -0
- package/dist/code/explorer.mjs +1 -0
- package/dist/code/index.js +1 -0
- package/dist/code/index.mjs +1 -0
- package/dist/code/preview.js +1 -0
- package/dist/code/preview.mjs +1 -0
- package/dist/code/snippet.js +1 -0
- package/dist/code/snippet.mjs +1 -0
- package/dist/code/tabs.js +1 -0
- package/dist/code/tabs.mjs +1 -0
- package/dist/code/terminal.js +1 -0
- package/dist/code/terminal.mjs +1 -0
- package/dist/device/index.js +1 -0
- package/dist/device/index.mjs +0 -0
- package/dist/dock/basic.js +1 -0
- package/dist/dock/basic.mjs +1 -0
- package/dist/dock/index.js +1 -0
- package/dist/dock/index.mjs +1 -0
- package/dist/dock/limelight-nav.js +1 -0
- package/dist/dock/limelight-nav.mjs +1 -0
- package/dist/dock/macos.js +1 -0
- package/dist/dock/macos.mjs +1 -0
- package/dist/dock/menu.js +1 -0
- package/dist/dock/menu.mjs +1 -0
- package/dist/dock/message.js +1 -0
- package/dist/dock/message.mjs +1 -0
- package/dist/finance/AdvancedChart.js +1 -0
- package/dist/finance/AdvancedChart.mjs +1 -0
- package/dist/finance/CompanyProfile.js +1 -0
- package/dist/finance/CompanyProfile.mjs +1 -0
- package/dist/finance/CryptoScreener.js +1 -0
- package/dist/finance/CryptoScreener.mjs +1 -0
- package/dist/finance/Financials.js +1 -0
- package/dist/finance/Financials.mjs +1 -0
- package/dist/finance/ForexScreener.js +1 -0
- package/dist/finance/ForexScreener.mjs +1 -0
- package/dist/finance/MarketOverview.js +1 -0
- package/dist/finance/MarketOverview.mjs +1 -0
- package/dist/finance/NewsTimeline.js +1 -0
- package/dist/finance/NewsTimeline.mjs +1 -0
- package/dist/finance/OrderEntry.js +1 -0
- package/dist/finance/OrderEntry.mjs +1 -0
- package/dist/finance/OrdersHistory.js +1 -0
- package/dist/finance/OrdersHistory.mjs +1 -0
- package/dist/finance/PositionsList.js +1 -0
- package/dist/finance/PositionsList.mjs +1 -0
- package/dist/finance/StockScreener.js +1 -0
- package/dist/finance/StockScreener.mjs +1 -0
- package/dist/finance/SymbolInfo.js +1 -0
- package/dist/finance/SymbolInfo.mjs +1 -0
- package/dist/finance/TechnicalAnalysis.js +1 -0
- package/dist/finance/TechnicalAnalysis.mjs +1 -0
- package/dist/finance/TickerTape.js +1 -0
- package/dist/finance/TickerTape.mjs +1 -0
- package/dist/finance/TradingPanel.js +1 -0
- package/dist/finance/TradingPanel.mjs +1 -0
- package/dist/finance/index.js +1 -0
- package/dist/finance/index.mjs +1 -0
- package/dist/form/index.js +1 -0
- package/dist/form/index.mjs +1 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/navigation/index.js +1 -0
- package/dist/navigation/index.mjs +1 -0
- package/dist/pattern/grid.js +1 -0
- package/dist/pattern/grid.mjs +1 -0
- package/dist/pattern/index.js +1 -0
- package/dist/pattern/index.mjs +1 -0
- package/dist/primitives/index.js +1 -1
- package/dist/primitives/index.mjs +1 -1
- package/dist/project/gantt.js +1 -0
- package/dist/project/gantt.mjs +1 -0
- package/dist/project/index.js +1 -0
- package/dist/project/index.mjs +1 -0
- package/dist/project/kanban.js +1 -0
- package/dist/project/kanban.mjs +1 -0
- package/dist/project/list.js +1 -0
- package/dist/project/list.mjs +1 -0
- package/dist/ui/announcement.js +1 -0
- package/dist/ui/announcement.mjs +1 -0
- package/dist/ui/avatar-group.js +1 -0
- package/dist/ui/avatar-group.mjs +1 -0
- package/dist/ui/banner.js +1 -0
- package/dist/ui/banner.mjs +1 -0
- package/dist/ui/cursor.js +1 -0
- package/dist/ui/cursor.mjs +1 -0
- package/dist/ui/index.js +1 -0
- package/dist/ui/index.mjs +1 -0
- package/dist/ui/marquee.js +1 -0
- package/dist/ui/marquee.mjs +1 -0
- package/dist/ui/pill.js +1 -0
- package/dist/ui/pill.mjs +1 -0
- package/dist/ui/spinner.js +1 -0
- package/dist/ui/spinner.mjs +1 -0
- package/dist/ui/tags.js +1 -0
- package/dist/ui/tags.mjs +1 -0
- package/dist/ui/ticker.js +1 -0
- package/dist/ui/ticker.mjs +1 -0
- package/finance/README.md +164 -0
- package/finance/components/AdvancedChart.tsx +58 -0
- package/finance/components/CompanyProfile.tsx +65 -0
- package/finance/components/CryptoScreener.tsx +55 -0
- package/finance/components/Financials.tsx +71 -0
- package/finance/components/ForexScreener.tsx +56 -0
- package/finance/components/MarketOverview.tsx +114 -0
- package/finance/components/NewsTimeline.tsx +54 -0
- package/finance/components/OrderEntry.tsx +157 -0
- package/finance/components/OrdersHistory.tsx +103 -0
- package/finance/components/PositionsList.tsx +85 -0
- package/finance/components/StockScreener.tsx +56 -0
- package/finance/components/SymbolInfo.tsx +62 -0
- package/finance/components/TechnicalAnalysis.tsx +74 -0
- package/finance/components/TickerTape.tsx +66 -0
- package/finance/components/TradingPanel.tsx +238 -0
- package/finance/components/index.ts +40 -0
- package/finance/index.ts +23 -0
- package/package.json +129 -3
- package/style/theme-provider.tsx +1 -1
- package/dist/chunk-BBXIHLTX.mjs +0 -1
- package/dist/chunk-EZN2P3FV.js +0 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef, memo } from 'react'
|
|
4
|
+
|
|
5
|
+
function AdvancedChart({ symbol = 'NASDAQ:AAPL' }: { symbol?: string }) {
|
|
6
|
+
const container = useRef<HTMLDivElement>(null)
|
|
7
|
+
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (!container.current) return
|
|
10
|
+
|
|
11
|
+
// Check if widget is already initialized using data attribute
|
|
12
|
+
if (container.current.dataset.initialized === 'true') {
|
|
13
|
+
return // Widget already initialized, skip
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Mark as initialized before adding script
|
|
17
|
+
container.current.dataset.initialized = 'true'
|
|
18
|
+
|
|
19
|
+
const script = document.createElement('script')
|
|
20
|
+
script.src = 'https://s3.tradingview.com/external-embedding/embed-widget-advanced-chart.js'
|
|
21
|
+
script.type = 'text/javascript'
|
|
22
|
+
script.async = true
|
|
23
|
+
script.innerHTML = JSON.stringify({
|
|
24
|
+
width: '100%',
|
|
25
|
+
height: '600',
|
|
26
|
+
symbol,
|
|
27
|
+
interval: 'D',
|
|
28
|
+
timezone: 'Etc/UTC',
|
|
29
|
+
theme: 'dark',
|
|
30
|
+
style: '1',
|
|
31
|
+
locale: 'en',
|
|
32
|
+
allow_symbol_change: true,
|
|
33
|
+
calendar: false,
|
|
34
|
+
support_host: 'https://www.tradingview.com',
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
container.current.appendChild(script)
|
|
38
|
+
|
|
39
|
+
// Cleanup function
|
|
40
|
+
return () => {
|
|
41
|
+
if (container.current) {
|
|
42
|
+
// Remove initialization flag on unmount
|
|
43
|
+
delete container.current.dataset.initialized
|
|
44
|
+
// Remove all scripts
|
|
45
|
+
const scripts = container.current.querySelectorAll('script')
|
|
46
|
+
scripts.forEach((s) => s.remove())
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}, [symbol])
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div className="tradingview-widget-container w-full h-[600px]" ref={container}>
|
|
53
|
+
<div className="tradingview-widget-container__widget h-full"></div>
|
|
54
|
+
</div>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export default memo(AdvancedChart)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef } from 'react'
|
|
4
|
+
|
|
5
|
+
export interface CompanyProfileProps {
|
|
6
|
+
symbol?: string
|
|
7
|
+
width?: string | number
|
|
8
|
+
height?: string | number
|
|
9
|
+
locale?: string
|
|
10
|
+
colorTheme?: 'light' | 'dark'
|
|
11
|
+
isTransparent?: boolean
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default function CompanyProfile({
|
|
15
|
+
symbol = 'NASDAQ:AAPL',
|
|
16
|
+
width = '100%',
|
|
17
|
+
height = '100%',
|
|
18
|
+
locale = 'en',
|
|
19
|
+
colorTheme = 'dark',
|
|
20
|
+
isTransparent = false
|
|
21
|
+
}: CompanyProfileProps) {
|
|
22
|
+
const containerRef = useRef<HTMLDivElement>(null)
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!containerRef.current) return
|
|
26
|
+
|
|
27
|
+
// Check if widget is already initialized using data attribute
|
|
28
|
+
if (containerRef.current.dataset.initialized === 'true') {
|
|
29
|
+
return // Widget already initialized, skip
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Mark as initialized before adding script
|
|
33
|
+
containerRef.current.dataset.initialized = 'true'
|
|
34
|
+
|
|
35
|
+
const script = document.createElement('script')
|
|
36
|
+
script.src = 'https://s3.tradingview.com/external-embedding/embed-widget-symbol-profile.js'
|
|
37
|
+
script.async = true
|
|
38
|
+
script.innerHTML = JSON.stringify({
|
|
39
|
+
width,
|
|
40
|
+
height,
|
|
41
|
+
colorTheme,
|
|
42
|
+
isTransparent,
|
|
43
|
+
symbol,
|
|
44
|
+
locale,
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
containerRef.current.appendChild(script)
|
|
48
|
+
|
|
49
|
+
return () => {
|
|
50
|
+
if (containerRef.current) {
|
|
51
|
+
// Remove initialization flag on unmount
|
|
52
|
+
delete containerRef.current.dataset.initialized
|
|
53
|
+
// Remove all scripts
|
|
54
|
+
const scripts = containerRef.current.querySelectorAll('script')
|
|
55
|
+
scripts.forEach((s) => s.remove())
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}, [symbol, width, height, locale, colorTheme, isTransparent])
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<div className="tradingview-widget-container" ref={containerRef}>
|
|
62
|
+
<div className="tradingview-widget-container__widget"></div>
|
|
63
|
+
</div>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef, memo } from 'react'
|
|
4
|
+
|
|
5
|
+
function CryptoScreener() {
|
|
6
|
+
const container = useRef<HTMLDivElement>(null)
|
|
7
|
+
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (!container.current) return
|
|
10
|
+
|
|
11
|
+
// Check if widget is already initialized using data attribute
|
|
12
|
+
if (container.current.dataset.initialized === 'true') {
|
|
13
|
+
return // Widget already initialized, skip
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Mark as initialized before adding script
|
|
17
|
+
container.current.dataset.initialized = 'true'
|
|
18
|
+
|
|
19
|
+
const script = document.createElement('script')
|
|
20
|
+
script.src = 'https://s3.tradingview.com/external-embedding/embed-widget-screener.js'
|
|
21
|
+
script.type = 'text/javascript'
|
|
22
|
+
script.async = true
|
|
23
|
+
script.innerHTML = JSON.stringify({
|
|
24
|
+
defaultColumn: 'overview',
|
|
25
|
+
screener_type: 'crypto_mkt',
|
|
26
|
+
displayCurrency: 'USD',
|
|
27
|
+
colorTheme: 'dark',
|
|
28
|
+
isTransparent: false,
|
|
29
|
+
locale: 'en',
|
|
30
|
+
width: '100%',
|
|
31
|
+
height: 550,
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
container.current.appendChild(script)
|
|
35
|
+
|
|
36
|
+
// Cleanup function
|
|
37
|
+
return () => {
|
|
38
|
+
if (container.current) {
|
|
39
|
+
// Remove initialization flag on unmount
|
|
40
|
+
delete container.current.dataset.initialized
|
|
41
|
+
// Remove all scripts
|
|
42
|
+
const scripts = container.current.querySelectorAll('script')
|
|
43
|
+
scripts.forEach((s) => s.remove())
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}, [])
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div className="tradingview-widget-container w-full" ref={container}>
|
|
50
|
+
<div className="tradingview-widget-container__widget"></div>
|
|
51
|
+
</div>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default memo(CryptoScreener)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef } from 'react'
|
|
4
|
+
|
|
5
|
+
export interface FinancialsProps {
|
|
6
|
+
symbol?: string
|
|
7
|
+
width?: string | number
|
|
8
|
+
height?: string | number
|
|
9
|
+
locale?: string
|
|
10
|
+
colorTheme?: 'light' | 'dark'
|
|
11
|
+
isTransparent?: boolean
|
|
12
|
+
displayMode?: 'regular' | 'compact' | 'adaptive'
|
|
13
|
+
largeChartUrl?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default function Financials({
|
|
17
|
+
symbol = 'NASDAQ:AAPL',
|
|
18
|
+
width = '100%',
|
|
19
|
+
height = '500',
|
|
20
|
+
locale = 'en',
|
|
21
|
+
colorTheme = 'dark',
|
|
22
|
+
isTransparent = false,
|
|
23
|
+
displayMode = 'adaptive',
|
|
24
|
+
largeChartUrl = ''
|
|
25
|
+
}: FinancialsProps) {
|
|
26
|
+
const containerRef = useRef<HTMLDivElement>(null)
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (!containerRef.current) return
|
|
30
|
+
|
|
31
|
+
// Check if widget is already initialized using data attribute
|
|
32
|
+
if (containerRef.current.dataset.initialized === 'true') {
|
|
33
|
+
return // Widget already initialized, skip
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Mark as initialized before adding script
|
|
37
|
+
containerRef.current.dataset.initialized = 'true'
|
|
38
|
+
|
|
39
|
+
const script = document.createElement('script')
|
|
40
|
+
script.src = 'https://s3.tradingview.com/external-embedding/embed-widget-financials.js'
|
|
41
|
+
script.async = true
|
|
42
|
+
script.innerHTML = JSON.stringify({
|
|
43
|
+
colorTheme,
|
|
44
|
+
isTransparent,
|
|
45
|
+
largeChartUrl,
|
|
46
|
+
displayMode,
|
|
47
|
+
width,
|
|
48
|
+
height,
|
|
49
|
+
symbol,
|
|
50
|
+
locale,
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
containerRef.current.appendChild(script)
|
|
54
|
+
|
|
55
|
+
return () => {
|
|
56
|
+
if (containerRef.current) {
|
|
57
|
+
// Remove initialization flag on unmount
|
|
58
|
+
delete containerRef.current.dataset.initialized
|
|
59
|
+
// Remove all scripts
|
|
60
|
+
const scripts = containerRef.current.querySelectorAll('script')
|
|
61
|
+
scripts.forEach((s) => s.remove())
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}, [symbol, width, height, locale, colorTheme, isTransparent, displayMode, largeChartUrl])
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<div className="tradingview-widget-container w-full h-[500px]" ref={containerRef}>
|
|
68
|
+
<div className="tradingview-widget-container__widget h-full"></div>
|
|
69
|
+
</div>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef, memo } from 'react'
|
|
4
|
+
|
|
5
|
+
function ForexScreener() {
|
|
6
|
+
const container = useRef<HTMLDivElement>(null)
|
|
7
|
+
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (!container.current) return
|
|
10
|
+
|
|
11
|
+
// Check if widget is already initialized using data attribute
|
|
12
|
+
if (container.current.dataset.initialized === 'true') {
|
|
13
|
+
return // Widget already initialized, skip
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Mark as initialized before adding script
|
|
17
|
+
container.current.dataset.initialized = 'true'
|
|
18
|
+
|
|
19
|
+
const script = document.createElement('script')
|
|
20
|
+
script.src = 'https://s3.tradingview.com/external-embedding/embed-widget-screener.js'
|
|
21
|
+
script.type = 'text/javascript'
|
|
22
|
+
script.async = true
|
|
23
|
+
script.innerHTML = JSON.stringify({
|
|
24
|
+
market: 'forex',
|
|
25
|
+
showToolbar: true,
|
|
26
|
+
defaultColumn: 'overview',
|
|
27
|
+
defaultScreen: 'general',
|
|
28
|
+
isTransparent: false,
|
|
29
|
+
locale: 'en',
|
|
30
|
+
colorTheme: 'dark',
|
|
31
|
+
width: '100%',
|
|
32
|
+
height: 550,
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
container.current.appendChild(script)
|
|
36
|
+
|
|
37
|
+
// Cleanup function
|
|
38
|
+
return () => {
|
|
39
|
+
if (container.current) {
|
|
40
|
+
// Remove initialization flag on unmount
|
|
41
|
+
delete container.current.dataset.initialized
|
|
42
|
+
// Remove all scripts
|
|
43
|
+
const scripts = container.current.querySelectorAll('script')
|
|
44
|
+
scripts.forEach((s) => s.remove())
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}, [])
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<div className="tradingview-widget-container w-full" ref={container}>
|
|
51
|
+
<div className="tradingview-widget-container__widget"></div>
|
|
52
|
+
</div>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default memo(ForexScreener)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef, memo } from 'react'
|
|
4
|
+
|
|
5
|
+
function MarketOverview() {
|
|
6
|
+
const container = useRef<HTMLDivElement>(null)
|
|
7
|
+
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (!container.current) return
|
|
10
|
+
|
|
11
|
+
// Check if widget is already initialized using data attribute
|
|
12
|
+
if (container.current.dataset.initialized === 'true') {
|
|
13
|
+
return // Widget already initialized, skip
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Mark as initialized before adding script
|
|
17
|
+
container.current.dataset.initialized = 'true'
|
|
18
|
+
|
|
19
|
+
const script = document.createElement('script')
|
|
20
|
+
script.src = 'https://s3.tradingview.com/external-embedding/embed-widget-market-overview.js'
|
|
21
|
+
script.type = 'text/javascript'
|
|
22
|
+
script.async = true
|
|
23
|
+
script.innerHTML = JSON.stringify({
|
|
24
|
+
colorTheme: 'dark',
|
|
25
|
+
dateRange: '12M',
|
|
26
|
+
locale: 'en',
|
|
27
|
+
largeChartUrl: '',
|
|
28
|
+
isTransparent: false,
|
|
29
|
+
showFloatingTooltip: false,
|
|
30
|
+
plotLineColorGrowing: 'rgba(41, 98, 255, 1)',
|
|
31
|
+
plotLineColorFalling: 'rgba(41, 98, 255, 1)',
|
|
32
|
+
gridLineColor: 'rgba(240, 243, 250, 0)',
|
|
33
|
+
scaleFontColor: '#DBDBDB',
|
|
34
|
+
belowLineFillColorGrowing: 'rgba(41, 98, 255, 0.12)',
|
|
35
|
+
belowLineFillColorFalling: 'rgba(41, 98, 255, 0.12)',
|
|
36
|
+
belowLineFillColorGrowingBottom: 'rgba(41, 98, 255, 0)',
|
|
37
|
+
belowLineFillColorFallingBottom: 'rgba(41, 98, 255, 0)',
|
|
38
|
+
symbolActiveColor: 'rgba(41, 98, 255, 0.12)',
|
|
39
|
+
tabs: [
|
|
40
|
+
{
|
|
41
|
+
title: 'Indices',
|
|
42
|
+
symbols: [
|
|
43
|
+
{ s: 'FOREXCOM:SPXUSD', d: 'S&P 500 Index' },
|
|
44
|
+
{ s: 'FOREXCOM:NSXUSD', d: 'US 100 Cash CFD' },
|
|
45
|
+
{ s: 'FOREXCOM:DJI', d: 'Dow Jones Industrial Average Index' },
|
|
46
|
+
{ s: 'INDEX:NKY', d: 'Japan 225' },
|
|
47
|
+
{ s: 'INDEX:DEU40', d: 'DAX Index' },
|
|
48
|
+
{ s: 'FOREXCOM:UKXGBP', d: 'FTSE 100 Index' },
|
|
49
|
+
],
|
|
50
|
+
originalTitle: 'Indices',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
title: 'Futures',
|
|
54
|
+
symbols: [
|
|
55
|
+
{ s: 'BMFBOVESPA:ISP1!', d: 'S&P 500' },
|
|
56
|
+
{ s: 'BMFBOVESPA:EUR1!', d: 'Euro' },
|
|
57
|
+
{ s: 'CMCMARKETS:GOLD', d: 'Gold' },
|
|
58
|
+
{ s: 'PYTH:WTI3!', d: 'WTI Crude Oil' },
|
|
59
|
+
{ s: 'BMFBOVESPA:CCM1!', d: 'Corn' },
|
|
60
|
+
],
|
|
61
|
+
originalTitle: 'Futures',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
title: 'Bonds',
|
|
65
|
+
symbols: [
|
|
66
|
+
{ s: 'EUREX:FGBL1!', d: 'Euro Bund' },
|
|
67
|
+
{ s: 'EUREX:FBTP1!', d: 'Euro BTP' },
|
|
68
|
+
{ s: 'EUREX:FGBM1!', d: 'Euro BOBL' },
|
|
69
|
+
],
|
|
70
|
+
originalTitle: 'Bonds',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
title: 'Forex',
|
|
74
|
+
symbols: [
|
|
75
|
+
{ s: 'FX:EURUSD', d: 'EUR to USD' },
|
|
76
|
+
{ s: 'FX:GBPUSD', d: 'GBP to USD' },
|
|
77
|
+
{ s: 'FX:USDJPY', d: 'USD to JPY' },
|
|
78
|
+
{ s: 'FX:USDCHF', d: 'USD to CHF' },
|
|
79
|
+
{ s: 'FX:AUDUSD', d: 'AUD to USD' },
|
|
80
|
+
{ s: 'FX:USDCAD', d: 'USD to CAD' },
|
|
81
|
+
],
|
|
82
|
+
originalTitle: 'Forex',
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
support_host: 'https://www.tradingview.com',
|
|
86
|
+
backgroundColor: '#0f0f0f',
|
|
87
|
+
width: '100%',
|
|
88
|
+
height: '550',
|
|
89
|
+
showSymbolLogo: true,
|
|
90
|
+
showChart: true,
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
container.current.appendChild(script)
|
|
94
|
+
|
|
95
|
+
// Cleanup function
|
|
96
|
+
return () => {
|
|
97
|
+
if (container.current) {
|
|
98
|
+
// Remove initialization flag on unmount
|
|
99
|
+
delete container.current.dataset.initialized
|
|
100
|
+
// Remove all scripts
|
|
101
|
+
const scripts = container.current.querySelectorAll('script')
|
|
102
|
+
scripts.forEach((s) => s.remove())
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}, [])
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<div className="tradingview-widget-container w-full" ref={container}>
|
|
109
|
+
<div className="tradingview-widget-container__widget"></div>
|
|
110
|
+
</div>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export default memo(MarketOverview)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef, memo } from 'react'
|
|
4
|
+
|
|
5
|
+
function NewsTimeline() {
|
|
6
|
+
const container = useRef<HTMLDivElement>(null)
|
|
7
|
+
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (!container.current) return
|
|
10
|
+
|
|
11
|
+
// Check if widget is already initialized using data attribute
|
|
12
|
+
if (container.current.dataset.initialized === 'true') {
|
|
13
|
+
return // Widget already initialized, skip
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Mark as initialized before adding script
|
|
17
|
+
container.current.dataset.initialized = 'true'
|
|
18
|
+
|
|
19
|
+
const script = document.createElement('script')
|
|
20
|
+
script.src = 'https://s3.tradingview.com/external-embedding/embed-widget-timeline.js'
|
|
21
|
+
script.type = 'text/javascript'
|
|
22
|
+
script.async = true
|
|
23
|
+
script.innerHTML = JSON.stringify({
|
|
24
|
+
displayMode: 'regular',
|
|
25
|
+
feedMode: 'all_symbols',
|
|
26
|
+
colorTheme: 'dark',
|
|
27
|
+
isTransparent: false,
|
|
28
|
+
locale: 'en',
|
|
29
|
+
width: '100%',
|
|
30
|
+
height: 550,
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
container.current.appendChild(script)
|
|
34
|
+
|
|
35
|
+
// Cleanup function
|
|
36
|
+
return () => {
|
|
37
|
+
if (container.current) {
|
|
38
|
+
// Remove initialization flag on unmount
|
|
39
|
+
delete container.current.dataset.initialized
|
|
40
|
+
// Remove all scripts
|
|
41
|
+
const scripts = container.current.querySelectorAll('script')
|
|
42
|
+
scripts.forEach((s) => s.remove())
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}, [])
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<div className="tradingview-widget-container w-full" ref={container}>
|
|
49
|
+
<div className="tradingview-widget-container__widget"></div>
|
|
50
|
+
</div>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export default memo(NewsTimeline)
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react'
|
|
4
|
+
|
|
5
|
+
export interface OrderEntryProps {
|
|
6
|
+
symbol: string
|
|
7
|
+
accountBalance: number
|
|
8
|
+
onPlaceOrder: (order: {
|
|
9
|
+
symbol: string
|
|
10
|
+
side: 'buy' | 'sell'
|
|
11
|
+
orderType: 'market' | 'limit'
|
|
12
|
+
shares: number
|
|
13
|
+
limitPrice?: number
|
|
14
|
+
}) => void
|
|
15
|
+
disabled?: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function OrderEntry({
|
|
19
|
+
symbol,
|
|
20
|
+
accountBalance,
|
|
21
|
+
onPlaceOrder,
|
|
22
|
+
disabled = false
|
|
23
|
+
}: OrderEntryProps) {
|
|
24
|
+
const [orderType, setOrderType] = useState<'market' | 'limit'>('market')
|
|
25
|
+
const [orderSide, setOrderSide] = useState<'buy' | 'sell'>('buy')
|
|
26
|
+
const [shares, setShares] = useState('')
|
|
27
|
+
const [limitPrice, setLimitPrice] = useState('')
|
|
28
|
+
|
|
29
|
+
const getTickerFromSymbol = (symbol: string) => {
|
|
30
|
+
return symbol.split(':')[1] || symbol
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const handlePlaceOrder = () => {
|
|
34
|
+
if (!shares || (orderType === 'limit' && !limitPrice)) return
|
|
35
|
+
|
|
36
|
+
onPlaceOrder({
|
|
37
|
+
symbol,
|
|
38
|
+
side: orderSide,
|
|
39
|
+
orderType,
|
|
40
|
+
shares: parseInt(shares),
|
|
41
|
+
limitPrice: orderType === 'limit' ? parseFloat(limitPrice) : undefined
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
// Reset form
|
|
45
|
+
setShares('')
|
|
46
|
+
setLimitPrice('')
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<div className="p-4 space-y-4">
|
|
51
|
+
{/* Account Balance */}
|
|
52
|
+
<div className="bg-white/5 rounded-lg p-3">
|
|
53
|
+
<div className="text-xs text-white/60 mb-1">Buying Power</div>
|
|
54
|
+
<div className="text-lg font-semibold text-white">
|
|
55
|
+
${accountBalance.toLocaleString()}
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
{/* Buy/Sell Toggle */}
|
|
60
|
+
<div className="grid grid-cols-2 gap-2">
|
|
61
|
+
<button
|
|
62
|
+
onClick={() => setOrderSide('buy')}
|
|
63
|
+
disabled={disabled}
|
|
64
|
+
className={`py-2.5 rounded-lg font-semibold transition-all ${
|
|
65
|
+
orderSide === 'buy'
|
|
66
|
+
? 'bg-success text-white'
|
|
67
|
+
: 'bg-white/5 text-white/60 hover:bg-white/10'
|
|
68
|
+
} disabled:opacity-50 disabled:cursor-not-allowed`}
|
|
69
|
+
>
|
|
70
|
+
Buy
|
|
71
|
+
</button>
|
|
72
|
+
<button
|
|
73
|
+
onClick={() => setOrderSide('sell')}
|
|
74
|
+
disabled={disabled}
|
|
75
|
+
className={`py-2.5 rounded-lg font-semibold transition-all ${
|
|
76
|
+
orderSide === 'sell'
|
|
77
|
+
? 'bg-danger text-white'
|
|
78
|
+
: 'bg-white/5 text-white/60 hover:bg-white/10'
|
|
79
|
+
} disabled:opacity-50 disabled:cursor-not-allowed`}
|
|
80
|
+
>
|
|
81
|
+
Sell
|
|
82
|
+
</button>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
{/* Order Type */}
|
|
86
|
+
<div>
|
|
87
|
+
<label className="text-xs text-white/60 mb-2 block">Order Type</label>
|
|
88
|
+
<div className="grid grid-cols-2 gap-2">
|
|
89
|
+
<button
|
|
90
|
+
onClick={() => setOrderType('market')}
|
|
91
|
+
disabled={disabled}
|
|
92
|
+
className={`py-2 rounded-lg text-sm font-medium transition-all ${
|
|
93
|
+
orderType === 'market'
|
|
94
|
+
? 'bg-white/10 text-white'
|
|
95
|
+
: 'bg-white/5 text-white/60 hover:bg-white/10'
|
|
96
|
+
} disabled:opacity-50 disabled:cursor-not-allowed`}
|
|
97
|
+
>
|
|
98
|
+
Market
|
|
99
|
+
</button>
|
|
100
|
+
<button
|
|
101
|
+
onClick={() => setOrderType('limit')}
|
|
102
|
+
disabled={disabled}
|
|
103
|
+
className={`py-2 rounded-lg text-sm font-medium transition-all ${
|
|
104
|
+
orderType === 'limit'
|
|
105
|
+
? 'bg-white/10 text-white'
|
|
106
|
+
: 'bg-white/5 text-white/60 hover:bg-white/10'
|
|
107
|
+
} disabled:opacity-50 disabled:cursor-not-allowed`}
|
|
108
|
+
>
|
|
109
|
+
Limit
|
|
110
|
+
</button>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
{/* Shares */}
|
|
115
|
+
<div>
|
|
116
|
+
<label className="text-xs text-white/60 mb-2 block">Shares</label>
|
|
117
|
+
<input
|
|
118
|
+
type="number"
|
|
119
|
+
value={shares}
|
|
120
|
+
onChange={(e) => setShares(e.target.value)}
|
|
121
|
+
disabled={disabled}
|
|
122
|
+
className="w-full bg-white/5 border border-white/10 rounded-lg px-4 py-2.5 text-white focus:outline-none focus:border-success disabled:opacity-50 disabled:cursor-not-allowed"
|
|
123
|
+
placeholder="0"
|
|
124
|
+
/>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
{/* Limit Price */}
|
|
128
|
+
{orderType === 'limit' && (
|
|
129
|
+
<div>
|
|
130
|
+
<label className="text-xs text-white/60 mb-2 block">Limit Price</label>
|
|
131
|
+
<input
|
|
132
|
+
type="number"
|
|
133
|
+
value={limitPrice}
|
|
134
|
+
onChange={(e) => setLimitPrice(e.target.value)}
|
|
135
|
+
disabled={disabled}
|
|
136
|
+
className="w-full bg-white/5 border border-white/10 rounded-lg px-4 py-2.5 text-white focus:outline-none focus:border-success disabled:opacity-50 disabled:cursor-not-allowed"
|
|
137
|
+
placeholder="0.00"
|
|
138
|
+
step="0.01"
|
|
139
|
+
/>
|
|
140
|
+
</div>
|
|
141
|
+
)}
|
|
142
|
+
|
|
143
|
+
{/* Place Order Button */}
|
|
144
|
+
<button
|
|
145
|
+
onClick={handlePlaceOrder}
|
|
146
|
+
disabled={disabled || !shares || (orderType === 'limit' && !limitPrice)}
|
|
147
|
+
className={`w-full py-3 rounded-lg font-semibold transition-all ${
|
|
148
|
+
orderSide === 'buy'
|
|
149
|
+
? 'bg-success hover:bg-success/90 text-white'
|
|
150
|
+
: 'bg-danger hover:bg-danger/90 text-white'
|
|
151
|
+
} disabled:opacity-50 disabled:cursor-not-allowed`}
|
|
152
|
+
>
|
|
153
|
+
{orderSide === 'buy' ? 'Buy' : 'Sell'} {getTickerFromSymbol(symbol)}
|
|
154
|
+
</button>
|
|
155
|
+
</div>
|
|
156
|
+
)
|
|
157
|
+
}
|