@hanzo/ui 5.1.8 → 5.3.0

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.
Files changed (272) hide show
  1. package/dist/3d/button.js +1 -0
  2. package/dist/3d/button.mjs +1 -0
  3. package/dist/3d/card.js +1 -0
  4. package/dist/3d/card.mjs +1 -0
  5. package/dist/3d/carousel.js +1 -0
  6. package/dist/3d/carousel.mjs +1 -0
  7. package/dist/3d/grid.js +1 -0
  8. package/dist/3d/grid.mjs +1 -0
  9. package/dist/3d/index.js +1 -0
  10. package/dist/3d/index.mjs +1 -0
  11. package/dist/3d/marquee.js +1 -0
  12. package/dist/3d/marquee.mjs +1 -0
  13. package/dist/3d/pin.js +1 -0
  14. package/dist/3d/pin.mjs +1 -0
  15. package/dist/animation/apple-cards-carousel.js +1 -0
  16. package/dist/animation/apple-cards-carousel.mjs +1 -0
  17. package/dist/animation/apple-hello-effect.js +1 -0
  18. package/dist/animation/apple-hello-effect.mjs +1 -0
  19. package/dist/animation/beam.js +1 -0
  20. package/dist/animation/beam.mjs +1 -0
  21. package/dist/animation/cursor.js +1 -0
  22. package/dist/animation/cursor.mjs +1 -0
  23. package/dist/animation/index.js +2 -0
  24. package/dist/animation/index.mjs +2 -0
  25. package/dist/animation/testimonials.js +1 -0
  26. package/dist/animation/testimonials.mjs +1 -0
  27. package/dist/animation/tooltip.js +1 -0
  28. package/dist/animation/tooltip.mjs +1 -0
  29. package/dist/avatar.js +1 -1
  30. package/dist/avatar.mjs +1 -1
  31. package/dist/chunk-266OC746.mjs +2 -0
  32. package/dist/chunk-2B7NONPA.mjs +1 -0
  33. package/dist/chunk-2SI3T6F4.mjs +1 -0
  34. package/dist/chunk-37TVHMP2.mjs +1 -0
  35. package/dist/chunk-4A27XTBF.js +12 -0
  36. package/dist/chunk-4CJ44NSE.js +1 -0
  37. package/dist/chunk-4SKGA2GA.mjs +1 -0
  38. package/dist/chunk-4TE2JWNG.js +1 -0
  39. package/dist/chunk-4XCQFT2C.mjs +1 -0
  40. package/dist/chunk-4YMLAU5Z.js +1 -0
  41. package/dist/chunk-5RACWNGV.mjs +1 -0
  42. package/dist/chunk-A3S2QAGG.mjs +3 -0
  43. package/dist/chunk-B3L4REN3.js +1 -0
  44. package/dist/chunk-B4RJSSWX.js +1 -0
  45. package/dist/chunk-B7LBF7R7.js +1 -0
  46. package/dist/chunk-BIWGFJPQ.mjs +1 -0
  47. package/dist/chunk-BOBL44QL.mjs +2 -0
  48. package/dist/chunk-BUMLLGES.mjs +1 -0
  49. package/dist/chunk-BYFLZ6DP.js +1 -0
  50. package/dist/chunk-C66RILAI.mjs +42 -0
  51. package/dist/chunk-CDBOLI7U.js +42 -0
  52. package/dist/chunk-CDO4BR6V.js +1 -0
  53. package/dist/chunk-CGUI5CEC.mjs +1 -0
  54. package/dist/chunk-CICZVOAY.js +1 -0
  55. package/dist/chunk-DB3WJTS4.js +1 -0
  56. package/dist/chunk-DKL2FM7J.mjs +1 -0
  57. package/dist/chunk-DNYROKHM.mjs +1 -0
  58. package/dist/chunk-DRLJ6Z7Q.js +1 -0
  59. package/dist/chunk-DYF5HRXR.mjs +1 -0
  60. package/dist/chunk-EATSKPYS.js +10 -0
  61. package/dist/chunk-EGN6SLB7.js +3 -0
  62. package/dist/chunk-EK5T4DQ2.js +2 -0
  63. package/dist/chunk-ELR6GOUX.mjs +1 -0
  64. package/dist/chunk-EQAPJD4H.mjs +1 -0
  65. package/dist/chunk-FCHJPQ73.mjs +1 -0
  66. package/dist/chunk-FE2O6776.js +1 -0
  67. package/dist/chunk-FIN2IX2D.mjs +1 -0
  68. package/dist/chunk-FQO25CNQ.mjs +1 -0
  69. package/dist/chunk-FX7VUERX.mjs +2 -0
  70. package/dist/chunk-G4X4J5EW.js +1 -0
  71. package/dist/chunk-GFWDGZO7.mjs +1 -0
  72. package/dist/chunk-GTFU3T2U.mjs +1 -0
  73. package/dist/chunk-GTUCZ5TW.js +1 -0
  74. package/dist/chunk-HEZV2WAY.js +2 -0
  75. package/dist/chunk-HIDGPSBX.js +1 -0
  76. package/dist/chunk-HLJAWNJK.js +1 -0
  77. package/dist/chunk-HM47SDFC.mjs +1 -0
  78. package/dist/chunk-HQGRRTIW.mjs +2 -0
  79. package/dist/chunk-J4DJZHOE.js +2 -0
  80. package/dist/chunk-J5KX3VTM.js +1 -0
  81. package/dist/chunk-JNNKXOA3.js +1 -0
  82. package/dist/chunk-JRWBF5SH.js +1 -0
  83. package/dist/chunk-JTTJLJON.js +2 -0
  84. package/dist/chunk-JZGTSHZ4.js +1 -0
  85. package/dist/chunk-LADFCKQD.mjs +1 -0
  86. package/dist/chunk-LHKPSY4L.js +1 -0
  87. package/dist/chunk-LMOX4GTY.js +1 -0
  88. package/dist/chunk-LYXX7LU2.js +6 -0
  89. package/dist/chunk-M4GZKMQS.mjs +6 -0
  90. package/dist/chunk-MJDVKTGX.mjs +1 -0
  91. package/dist/chunk-MPZRRATY.mjs +1 -0
  92. package/dist/chunk-MUI6SJLP.js +1 -0
  93. package/dist/chunk-NBXNOMXS.mjs +2 -0
  94. package/dist/chunk-NE7ICOQE.mjs +2 -0
  95. package/dist/chunk-NL5ZWDIJ.mjs +1 -0
  96. package/dist/chunk-NS6CEKHH.mjs +1 -0
  97. package/dist/chunk-O6RJT46G.js +1 -0
  98. package/dist/chunk-OC34KEWQ.mjs +1 -0
  99. package/dist/chunk-OL63HLUI.js +2 -0
  100. package/dist/chunk-OLTPOUB2.js +2 -0
  101. package/dist/chunk-OQOBF7QQ.js +1 -0
  102. package/dist/chunk-OY2LIJR2.mjs +2 -0
  103. package/dist/chunk-PE5GANLF.mjs +1 -0
  104. package/dist/chunk-PIDMTL36.mjs +1 -0
  105. package/dist/chunk-QGHPGSQL.mjs +2 -0
  106. package/dist/chunk-QLB43TFO.mjs +1 -0
  107. package/dist/chunk-R2JKVWNB.js +2 -0
  108. package/dist/chunk-RAT4U2JG.mjs +1 -0
  109. package/dist/chunk-RBURLSG7.js +2 -0
  110. package/dist/chunk-RO3D3W57.js +1 -0
  111. package/dist/chunk-RPOB4E3W.js +1 -0
  112. package/dist/chunk-RVPP46TI.js +2 -0
  113. package/dist/chunk-S2UB25HB.mjs +12 -0
  114. package/dist/chunk-SCYHSLR2.js +2 -0
  115. package/dist/chunk-SRPQZYB6.js +1 -0
  116. package/dist/chunk-TCTFHNND.js +1 -0
  117. package/dist/chunk-TG6V2JL2.js +1 -0
  118. package/dist/chunk-TGL6VBFN.js +1 -0
  119. package/dist/chunk-TNF5G2ZW.mjs +1 -0
  120. package/dist/chunk-TXND3LRQ.mjs +1 -0
  121. package/dist/chunk-U7CUKU4W.mjs +1 -0
  122. package/dist/chunk-UPRWI4ON.mjs +2 -0
  123. package/dist/chunk-V23X5ZD6.mjs +2 -0
  124. package/dist/chunk-VFFLOHVQ.mjs +1 -0
  125. package/dist/chunk-VHB7M646.mjs +10 -0
  126. package/dist/chunk-VJDDFZ7N.mjs +2 -0
  127. package/dist/chunk-VN2BKXHJ.js +1 -0
  128. package/dist/chunk-VT77IEYF.mjs +1 -0
  129. package/dist/chunk-VTJ6QUCR.js +1 -0
  130. package/dist/chunk-VUIJAFJC.js +1 -0
  131. package/dist/chunk-WN767YS2.mjs +2 -0
  132. package/dist/chunk-WREKV6XQ.mjs +1 -0
  133. package/dist/chunk-XBDQSMTI.js +2 -0
  134. package/dist/chunk-XFK7RTKE.js +1 -0
  135. package/dist/chunk-XJTWK37Q.mjs +2 -0
  136. package/dist/chunk-XMYCJ2B5.js +1 -0
  137. package/dist/chunk-XOGRJZXX.mjs +1 -0
  138. package/dist/chunk-XOQCRR5Q.js +2 -0
  139. package/dist/chunk-Y6SIRKG3.js +2 -0
  140. package/dist/chunk-YLY2B6UX.mjs +1 -0
  141. package/dist/chunk-YQUF7KPG.mjs +1 -0
  142. package/dist/chunk-Z3DNBRF4.js +1 -0
  143. package/dist/chunk-ZA3JIBDG.js +1 -0
  144. package/dist/chunk-ZDOIGP2L.js +1 -0
  145. package/dist/code/block.js +1 -0
  146. package/dist/code/block.mjs +1 -0
  147. package/dist/code/compare.js +1 -0
  148. package/dist/code/compare.mjs +1 -0
  149. package/dist/code/diff.js +1 -0
  150. package/dist/code/diff.mjs +1 -0
  151. package/dist/code/editor.js +1 -0
  152. package/dist/code/editor.mjs +1 -0
  153. package/dist/code/explorer.js +1 -0
  154. package/dist/code/explorer.mjs +1 -0
  155. package/dist/code/index.js +1 -0
  156. package/dist/code/index.mjs +1 -0
  157. package/dist/code/preview.js +1 -0
  158. package/dist/code/preview.mjs +1 -0
  159. package/dist/code/snippet.js +1 -0
  160. package/dist/code/snippet.mjs +1 -0
  161. package/dist/code/tabs.js +1 -0
  162. package/dist/code/tabs.mjs +1 -0
  163. package/dist/code/terminal.js +1 -0
  164. package/dist/code/terminal.mjs +1 -0
  165. package/dist/device/index.js +1 -0
  166. package/dist/device/index.mjs +0 -0
  167. package/dist/dock/basic.js +1 -0
  168. package/dist/dock/basic.mjs +1 -0
  169. package/dist/dock/index.js +1 -0
  170. package/dist/dock/index.mjs +1 -0
  171. package/dist/dock/limelight-nav.js +1 -0
  172. package/dist/dock/limelight-nav.mjs +1 -0
  173. package/dist/dock/macos.js +1 -0
  174. package/dist/dock/macos.mjs +1 -0
  175. package/dist/dock/menu.js +1 -0
  176. package/dist/dock/menu.mjs +1 -0
  177. package/dist/dock/message.js +1 -0
  178. package/dist/dock/message.mjs +1 -0
  179. package/dist/finance/AdvancedChart.js +1 -0
  180. package/dist/finance/AdvancedChart.mjs +1 -0
  181. package/dist/finance/CompanyProfile.js +1 -0
  182. package/dist/finance/CompanyProfile.mjs +1 -0
  183. package/dist/finance/CryptoScreener.js +1 -0
  184. package/dist/finance/CryptoScreener.mjs +1 -0
  185. package/dist/finance/Financials.js +1 -0
  186. package/dist/finance/Financials.mjs +1 -0
  187. package/dist/finance/ForexScreener.js +1 -0
  188. package/dist/finance/ForexScreener.mjs +1 -0
  189. package/dist/finance/MarketOverview.js +1 -0
  190. package/dist/finance/MarketOverview.mjs +1 -0
  191. package/dist/finance/NewsTimeline.js +1 -0
  192. package/dist/finance/NewsTimeline.mjs +1 -0
  193. package/dist/finance/OrderEntry.js +1 -0
  194. package/dist/finance/OrderEntry.mjs +1 -0
  195. package/dist/finance/OrdersHistory.js +1 -0
  196. package/dist/finance/OrdersHistory.mjs +1 -0
  197. package/dist/finance/PositionsList.js +1 -0
  198. package/dist/finance/PositionsList.mjs +1 -0
  199. package/dist/finance/StockScreener.js +1 -0
  200. package/dist/finance/StockScreener.mjs +1 -0
  201. package/dist/finance/SymbolInfo.js +1 -0
  202. package/dist/finance/SymbolInfo.mjs +1 -0
  203. package/dist/finance/TechnicalAnalysis.js +1 -0
  204. package/dist/finance/TechnicalAnalysis.mjs +1 -0
  205. package/dist/finance/TickerTape.js +1 -0
  206. package/dist/finance/TickerTape.mjs +1 -0
  207. package/dist/finance/TradingPanel.js +1 -0
  208. package/dist/finance/TradingPanel.mjs +1 -0
  209. package/dist/finance/index.js +1 -0
  210. package/dist/finance/index.mjs +1 -0
  211. package/dist/form/index.js +1 -0
  212. package/dist/form/index.mjs +1 -0
  213. package/dist/index.js +1 -1
  214. package/dist/index.mjs +1 -1
  215. package/dist/navigation/index.js +1 -0
  216. package/dist/navigation/index.mjs +1 -0
  217. package/dist/pattern/grid.js +1 -0
  218. package/dist/pattern/grid.mjs +1 -0
  219. package/dist/pattern/index.js +1 -0
  220. package/dist/pattern/index.mjs +1 -0
  221. package/dist/primitives/index.js +1 -1
  222. package/dist/primitives/index.mjs +1 -1
  223. package/dist/project/gantt.js +1 -0
  224. package/dist/project/gantt.mjs +1 -0
  225. package/dist/project/index.js +1 -0
  226. package/dist/project/index.mjs +1 -0
  227. package/dist/project/kanban.js +1 -0
  228. package/dist/project/kanban.mjs +1 -0
  229. package/dist/project/list.js +1 -0
  230. package/dist/project/list.mjs +1 -0
  231. package/dist/ui/announcement.js +1 -0
  232. package/dist/ui/announcement.mjs +1 -0
  233. package/dist/ui/avatar-group.js +1 -0
  234. package/dist/ui/avatar-group.mjs +1 -0
  235. package/dist/ui/banner.js +1 -0
  236. package/dist/ui/banner.mjs +1 -0
  237. package/dist/ui/cursor.js +1 -0
  238. package/dist/ui/cursor.mjs +1 -0
  239. package/dist/ui/index.js +1 -0
  240. package/dist/ui/index.mjs +1 -0
  241. package/dist/ui/marquee.js +1 -0
  242. package/dist/ui/marquee.mjs +1 -0
  243. package/dist/ui/pill.js +1 -0
  244. package/dist/ui/pill.mjs +1 -0
  245. package/dist/ui/spinner.js +1 -0
  246. package/dist/ui/spinner.mjs +1 -0
  247. package/dist/ui/tags.js +1 -0
  248. package/dist/ui/tags.mjs +1 -0
  249. package/dist/ui/ticker.js +1 -0
  250. package/dist/ui/ticker.mjs +1 -0
  251. package/finance/README.md +164 -0
  252. package/finance/components/AdvancedChart.tsx +58 -0
  253. package/finance/components/CompanyProfile.tsx +65 -0
  254. package/finance/components/CryptoScreener.tsx +55 -0
  255. package/finance/components/Financials.tsx +71 -0
  256. package/finance/components/ForexScreener.tsx +56 -0
  257. package/finance/components/MarketOverview.tsx +114 -0
  258. package/finance/components/NewsTimeline.tsx +54 -0
  259. package/finance/components/OrderEntry.tsx +157 -0
  260. package/finance/components/OrdersHistory.tsx +103 -0
  261. package/finance/components/PositionsList.tsx +85 -0
  262. package/finance/components/StockScreener.tsx +56 -0
  263. package/finance/components/SymbolInfo.tsx +62 -0
  264. package/finance/components/TechnicalAnalysis.tsx +74 -0
  265. package/finance/components/TickerTape.tsx +66 -0
  266. package/finance/components/TradingPanel.tsx +238 -0
  267. package/finance/components/index.ts +40 -0
  268. package/finance/index.ts +23 -0
  269. package/package.json +127 -6
  270. package/style/theme-provider.tsx +1 -1
  271. package/dist/chunk-BBXIHLTX.mjs +0 -1
  272. 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
+ }