Obotu commited on
Commit
2a8dd62
·
1 Parent(s): 50ad37f

feat: Implement initial web UI with HTML, CSS, and JavaScript, .

Browse files
.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ .venv
2
+ __pycache__
3
+ test_modal.py
4
+ ui/ __pycache__
data/activity.log ADDED
File without changes
index.html ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>MonteWalk</title>
7
+ <link rel="stylesheet" href="styles.css">
8
+ </head>
9
+ <body>
10
+ <div id="app">
11
+ <header>
12
+ <div class="logo">
13
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2">
14
+ <path d="M22 12h-4l-3 9L9 3l-3 9H2"></path>
15
+ </svg>
16
+ <h1>MonteWalk</h1>
17
+ </div>
18
+ <div class="status">
19
+ <span class="status-indicator"></span>
20
+ <span>SYSTEM ONLINE</span>
21
+ </div>
22
+ </header>
23
+
24
+ <main>
25
+ <div class="dashboard">
26
+ <div class="portfolio"></div>
27
+ <div class="watchlist"></div>
28
+ <div class="news"></div>
29
+ <div class="crypto"></div>
30
+ </div>
31
+ <div class="toolbox">
32
+ <h2>Toolbox</h2>
33
+ <div class="tool-grid"></div>
34
+ </div>
35
+ </main>
36
+
37
+ <div class="modal" id="tool-modal">
38
+ <div class="modal-content">
39
+ <button class="modal-close-btn" id="modal-close-btn">&times;</button>
40
+ <div id="tool-interface"></div>
41
+ </div>
42
+ </div>
43
+ </div>
44
+
45
+ <script src="scripts.js"></script>
46
+ </body>
47
+ </html>
scripts.js ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ document.addEventListener('DOMContentLoaded', () => {
2
+ const toolGrid = document.querySelector('.tool-grid');
3
+ const toolModal = document.getElementById('tool-modal');
4
+ const modalCloseBtn = document.getElementById('modal-close-btn');
5
+ const toolInterface = document.getElementById('tool-interface');
6
+
7
+ // Dummy data for tools (replace with actual data from backend)
8
+ const tools = [
9
+ { name: 'Get Price', description: 'Fetches real-time price data for a symbol.', category: 'Market Data' },
10
+ { name: 'Place Order', description: 'Places a trade order in the market.', category: 'Execution' },
11
+ { name: 'Portfolio Risk', description: 'Analyzes the risk of your portfolio.', category: 'Risk Management' },
12
+ { name: 'Run Backtest', description: 'Executes a backtest on a trading strategy.', category: 'Backtesting' },
13
+ { name: 'Analyze Ticker', description: 'Performs comprehensive analysis on a ticker.', category: 'Prompts' },
14
+ ];
15
+
16
+ // Render tool cards
17
+ tools.forEach(tool => {
18
+ const toolCard = document.createElement('div');
19
+ toolCard.classList.add('tool-card');
20
+ toolCard.innerHTML = `
21
+ <h3>${tool.name}</h3>
22
+ <p>${tool.description}</p>
23
+ <div class="tool-tags">
24
+ <span class="tool-tag">${tool.category}</span>
25
+ </div>
26
+ `;
27
+ toolCard.addEventListener('click', () => openToolModal(tool));
28
+ toolGrid.appendChild(toolCard);
29
+ });
30
+
31
+ // Open tool modal
32
+ function openToolModal(tool) {
33
+ toolInterface.innerHTML = `
34
+ <h2>${tool.name}</h2>
35
+ <p>${tool.description}</p>
36
+ <!-- Here you would dynamically create input fields based on the tool's signature -->
37
+ <div class="input-field">
38
+ <label for="symbol">Symbol:</label>
39
+ <input type="text" id="symbol" placeholder="e.g. AAPL">
40
+ </div>
41
+ <button id="run-tool-btn">Run Tool</button>
42
+ <pre id="tool-result"></pre>
43
+ `;
44
+ toolModal.classList.add('show');
45
+
46
+ document.getElementById('run-tool-btn').addEventListener('click', async () => {
47
+ const symbol = document.getElementById('symbol').value;
48
+ const resultElement = document.getElementById('tool-result');
49
+ resultElement.textContent = 'Running tool...';
50
+
51
+ // Example of calling a backend tool (requires window.openai to be available)
52
+ // if (window.openai && window.openai.callTool) {
53
+ // try {
54
+ // const result = await window.openai.callTool(tool.name.replace(/\s+/g, '_').toLowerCase(), { symbol: symbol });
55
+ // resultElement.textContent = JSON.stringify(result, null, 2);
56
+ // } catch (error) {
57
+ // resultElement.textContent = `Error: ${error.message}`;
58
+ // }
59
+ // } else {
60
+ // resultElement.textContent = 'MCP not available. Cannot call backend tools.';
61
+ // }
62
+ resultElement.textContent = `Simulating tool run for ${tool.name} with symbol: ${symbol}`;
63
+ });
64
+ }
65
+
66
+ // Close tool modal
67
+ modalCloseBtn.addEventListener('click', () => {
68
+ toolModal.classList.remove('show');
69
+ });
70
+
71
+ // Close modal on outside click
72
+ window.addEventListener('click', (event) => {
73
+ if (event.target === toolModal) {
74
+ toolModal.classList.remove('show');
75
+ }
76
+ });
77
+
78
+ // Dummy dashboard rendering (replace with actual data)
79
+ document.querySelector('.portfolio').innerHTML = '<div class="trading-card"><h3>Portfolio Overview</h3><p>Detailed portfolio data will go here.</p></div>';
80
+ document.querySelector('.watchlist').innerHTML = '<div class="trading-card"><h3>Watchlist</h3><p>Your watched symbols will appear here.</p></div>';
81
+ document.querySelector('.news').innerHTML = '<div class="trading-card"><h3>Intel Feed</h3><p>Latest market news and sentiment.</p></div>';
82
+ document.querySelector('.crypto').innerHTML = '<div class="trading-card"><h3>Crypto Movers</h3><p>Trending cryptocurrency data.</p></div>';
83
+ });
styles.css ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
2
+
3
+ :root {
4
+ --bg-primary: #0D0E12;
5
+ --bg-secondary: #12141A;
6
+ --bg-tertiary: #1A1C23;
7
+ --fill-primary: #242731;
8
+ --fill-secondary: #343845;
9
+
10
+ --text-primary: #F0F2F5;
11
+ --text-secondary: #A8B0BD;
12
+ --text-muted: #5F6572;
13
+ --text-disabled: #4A4E59;
14
+
15
+ --accent-primary: #4A55FF;
16
+ --accent-secondary: #8C54FF;
17
+ --accent-tertiary: #C247FF;
18
+
19
+ --danger: #FF4D4D;
20
+ --warning: #FFD166;
21
+ --success: #06D6A0;
22
+ --info: #00A2FF;
23
+
24
+ --font-sans: 'Inter', sans-serif;
25
+ --font-mono: 'JetBrains Mono', monospace;
26
+
27
+ --space-xs: 0.25rem;
28
+ --space-sm: 0.5rem;
29
+ --space-md: 1rem;
30
+ --space-lg: 1.5rem;
31
+ --space-xl: 2.5rem;
32
+
33
+ --radius-sm: 4px;
34
+ --radius-md: 8px;
35
+ --radius-lg: 16px;
36
+
37
+ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
38
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
39
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
40
+ --shadow-inner: inset 0 2px 4px 0 rgba(0, 0, 0, 0.05);
41
+ }
42
+
43
+ body {
44
+ background-color: var(--bg-primary);
45
+ color: var(--text-primary);
46
+ font-family: var(--font-sans);
47
+ margin: 0;
48
+ padding: var(--space-lg);
49
+ }
50
+
51
+ #app {
52
+ display: flex;
53
+ flex-direction: column;
54
+ gap: var(--space-lg);
55
+ }
56
+
57
+ header {
58
+ display: flex;
59
+ justify-content: space-between;
60
+ align-items: center;
61
+ border-bottom: 1px solid var(--fill-primary);
62
+ padding-bottom: var(--space-md);
63
+ }
64
+
65
+ .logo {
66
+ display: flex;
67
+ align-items: center;
68
+ gap: var(--space-md);
69
+ }
70
+
71
+ .logo h1 {
72
+ font-size: 1.25rem;
73
+ font-weight: 600;
74
+ margin: 0;
75
+ }
76
+
77
+ .status {
78
+ display: flex;
79
+ align-items: center;
80
+ gap: var(--space-sm);
81
+ font-family: var(--font-mono);
82
+ font-size: 0.8rem;
83
+ color: var(--success);
84
+ }
85
+
86
+ .status-indicator {
87
+ width: 8px;
88
+ height: 8px;
89
+ background-color: var(--success);
90
+ border-radius: 50%;
91
+ box-shadow: 0 0 8px var(--success);
92
+ }
93
+
94
+ main {
95
+ display: grid;
96
+ grid-template-columns: 3fr 1fr;
97
+ gap: var(--space-lg);
98
+ }
99
+
100
+ .dashboard {
101
+ display: grid;
102
+ grid-template-columns: 1fr 1fr;
103
+ grid-template-rows: auto auto;
104
+ gap: var(--space-lg);
105
+ }
106
+
107
+ .portfolio {
108
+ grid-column: 1 / -1;
109
+ }
110
+
111
+ .trading-card {
112
+ background-color: var(--bg-secondary);
113
+ border: 1px solid var(--fill-primary);
114
+ border-radius: var(--radius-lg);
115
+ padding: var(--space-lg);
116
+ }
117
+
118
+ .toolbox h2 {
119
+ margin-top: 0;
120
+ }
121
+
122
+ .tool-grid {
123
+ display: grid;
124
+ grid-template-columns: 1fr;
125
+ gap: var(--space-md);
126
+ }
127
+
128
+ .tool-card {
129
+ background-color: var(--bg-secondary);
130
+ border: 1px solid var(--fill-primary);
131
+ border-radius: var(--radius-lg);
132
+ padding: var(--space-lg);
133
+ cursor: pointer;
134
+ transition: all 0.2s ease-in-out;
135
+ }
136
+
137
+ .tool-card:hover {
138
+ border-color: var(--accent-primary);
139
+ transform: translateY(-2px);
140
+ }
141
+
142
+ .modal {
143
+ position: fixed;
144
+ top: 0;
145
+ left: 0;
146
+ width: 100%;
147
+ height: 100%;
148
+ background-color: rgba(0, 0, 0, 0.7);
149
+ display: none;
150
+ justify-content: center;
151
+ align-items: center;
152
+ z-index: 1000;
153
+ }
154
+
155
+ .modal.show {
156
+ display: flex;
157
+ }
158
+
159
+ .modal-content {
160
+ background-color: var(--bg-secondary);
161
+ padding: var(--space-xl);
162
+ border-radius: var(--radius-lg);
163
+ width: 90%;
164
+ max-width: 600px;
165
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
166
+ border: 1px solid var(--fill-primary);
167
+ position: relative;
168
+ }
169
+
170
+ .modal-close-btn {
171
+ position: absolute;
172
+ top: 1rem;
173
+ right: 1rem;
174
+ background: none;
175
+ border: none;
176
+ color: var(--text-secondary);
177
+ font-size: 1.5rem;
178
+ cursor: pointer;
179
+ }
tools/__pycache__/__init__.cpython-312.pyc CHANGED
Binary files a/tools/__pycache__/__init__.cpython-312.pyc and b/tools/__pycache__/__init__.cpython-312.pyc differ
 
tools/__pycache__/alpaca_broker.cpython-312.pyc CHANGED
Binary files a/tools/__pycache__/alpaca_broker.cpython-312.pyc and b/tools/__pycache__/alpaca_broker.cpython-312.pyc differ
 
tools/__pycache__/backtesting.cpython-312.pyc CHANGED
Binary files a/tools/__pycache__/backtesting.cpython-312.pyc and b/tools/__pycache__/backtesting.cpython-312.pyc differ
 
tools/__pycache__/crypto_data.cpython-312.pyc CHANGED
Binary files a/tools/__pycache__/crypto_data.cpython-312.pyc and b/tools/__pycache__/crypto_data.cpython-312.pyc differ
 
tools/__pycache__/execution.cpython-312.pyc CHANGED
Binary files a/tools/__pycache__/execution.cpython-312.pyc and b/tools/__pycache__/execution.cpython-312.pyc differ
 
tools/__pycache__/feature_engineering.cpython-312.pyc CHANGED
Binary files a/tools/__pycache__/feature_engineering.cpython-312.pyc and b/tools/__pycache__/feature_engineering.cpython-312.pyc differ
 
tools/__pycache__/logger.cpython-312.pyc CHANGED
Binary files a/tools/__pycache__/logger.cpython-312.pyc and b/tools/__pycache__/logger.cpython-312.pyc differ
 
tools/__pycache__/market_data.cpython-312.pyc CHANGED
Binary files a/tools/__pycache__/market_data.cpython-312.pyc and b/tools/__pycache__/market_data.cpython-312.pyc differ
 
tools/__pycache__/news_intelligence.cpython-312.pyc CHANGED
Binary files a/tools/__pycache__/news_intelligence.cpython-312.pyc and b/tools/__pycache__/news_intelligence.cpython-312.pyc differ
 
tools/__pycache__/portfolio_optimizer.cpython-312.pyc CHANGED
Binary files a/tools/__pycache__/portfolio_optimizer.cpython-312.pyc and b/tools/__pycache__/portfolio_optimizer.cpython-312.pyc differ
 
tools/__pycache__/resources.cpython-312.pyc CHANGED
Binary files a/tools/__pycache__/resources.cpython-312.pyc and b/tools/__pycache__/resources.cpython-312.pyc differ
 
tools/__pycache__/risk_engine.cpython-312.pyc CHANGED
Binary files a/tools/__pycache__/risk_engine.cpython-312.pyc and b/tools/__pycache__/risk_engine.cpython-312.pyc differ
 
tools/__pycache__/unusual_scanner.cpython-312.pyc CHANGED
Binary files a/tools/__pycache__/unusual_scanner.cpython-312.pyc and b/tools/__pycache__/unusual_scanner.cpython-312.pyc differ
 
tools/__pycache__/watchlist.cpython-312.pyc CHANGED
Binary files a/tools/__pycache__/watchlist.cpython-312.pyc and b/tools/__pycache__/watchlist.cpython-312.pyc differ
 
ui/tools.py CHANGED
@@ -15,37 +15,36 @@ def render_tools_tab(tools_map: Dict[str, List[Callable]]):
15
 
16
  # Modal with simpler structure - no nested groups
17
  with gr.Column(visible=True, elem_id="modal_wrapper", elem_classes="modal-wrapper") as modal:
18
- # Close button at top
19
- with gr.Row():
20
- gr.Markdown("") # Spacer
21
- close_button = gr.Button(" Close", size="sm", variant="secondary")
22
-
23
- # Title and description
24
- tool_title_md = gr.Markdown("## Tool Name")
25
- tool_desc_md = gr.Markdown("_Description_")
26
-
27
- gr.Markdown("---") # Divider
28
-
29
- # Inputs
30
- input_components = []
31
- for i in range(5):
32
- input_components.append(
33
- gr.Textbox(
34
- label=f"Parameter {i+1}",
35
- visible=True,
36
- interactive=True,
37
- elem_classes="modal-input"
 
 
 
 
 
 
 
 
 
38
  )
39
- )
40
-
41
- # Run button and output
42
- run_button = gr.Button("▶ Run Tool", variant="primary")
43
- output = gr.Textbox(
44
- label="Output",
45
- lines=10,
46
- interactive=False,
47
- max_lines=20
48
- )
49
 
50
  # Function to show modal with tool info (Content Only)
51
  def update_modal_content(tool: Callable):
@@ -264,7 +263,6 @@ def render_tools_tab(tools_map: Dict[str, List[Callable]]):
264
  padding: 0 !important;
265
  }
266
 
267
- /* Modal Styles */
268
  /* Modal Styles */
269
  .modal-wrapper {
270
  position: fixed !important;
@@ -272,14 +270,14 @@ def render_tools_tab(tools_map: Dict[str, List[Callable]]):
272
  left: 0 !important;
273
  width: 100vw !important;
274
  height: 100vh !important;
275
- background-color: rgba(0, 0, 0, 0.6) !important;
276
  backdrop-filter: blur(8px) !important;
277
  -webkit-backdrop-filter: blur(8px) !important;
278
  display: none !important; /* Hidden by default */
279
  justify-content: center !important;
280
  align-items: center !important;
281
  z-index: 9999 !important;
282
- transition: opacity 0.3s ease;
283
  opacity: 0;
284
  }
285
 
@@ -290,15 +288,15 @@ def render_tools_tab(tools_map: Dict[str, List[Callable]]):
290
  }
291
 
292
  .modal-content {
293
- background: var(--bg-secondary) !important;
294
- border: 1px solid var(--fill-secondary) !important;
295
- border-radius: var(--radius-lg) !important;
296
  padding: 0 !important;
297
- width: 90% !important;
298
- max-width: 600px !important;
299
  max-height: 85vh !important;
300
  overflow-y: auto !important;
301
- box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5) !important;
302
  position: relative !important;
303
  display: flex !important;
304
  flex-direction: column !important;
@@ -306,47 +304,25 @@ def render_tools_tab(tools_map: Dict[str, List[Callable]]):
306
  }
307
 
308
  @keyframes modalSlideIn {
309
- from { opacity: 0; transform: translateY(20px) scale(0.95); }
310
  to { opacity: 1; transform: translateY(0) scale(1); }
311
  }
312
 
313
- .modal-header {
314
- padding: var(--space-lg) !important;
315
- border-bottom: 1px solid var(--fill-primary) !important;
316
- display: flex !important;
317
- justify-content: space-between !important;
318
- align-items: center !important;
319
- background: rgba(255, 255, 255, 0.02) !important;
320
- }
321
-
322
- .modal-body {
323
- padding: var(--space-lg) !important;
324
- display: flex !important;
325
- flex-direction: column !important;
326
- gap: var(--space-md) !important;
327
  }
328
-
329
- .modal-close-btn {
330
- /* position: absolute !important; <-- REMOVED */
331
- background: transparent !important;
332
- border: 1px solid var(--fill-secondary) !important; /* Added border for visibility */
333
- color: var(--text-muted) !important;
334
- font-size: 1rem !important;
335
- cursor: pointer !important;
336
- padding: 0.25rem 0.75rem !important;
337
- border-radius: var(--radius-md) !important;
338
- transition: all 0.2s ease !important;
339
  }
340
-
341
- .modal-close-btn:hover {
342
- background: var(--fill-primary) !important;
343
- color: var(--text-primary) !important;
344
- border-color: var(--text-secondary) !important;
345
  }
346
-
347
- /* Hide Gradio's default close button if it appears */
348
- .modal-wrapper > .close {
349
- display: none !important;
350
  }
351
  </style>
352
  """)
 
15
 
16
  # Modal with simpler structure - no nested groups
17
  with gr.Column(visible=True, elem_id="modal_wrapper", elem_classes="modal-wrapper") as modal:
18
+ with gr.Column(elem_classes="modal-content"):
19
+ # Header: Title + Close Button
20
+ with gr.Row(elem_classes="modal-header"):
21
+ tool_title_md = gr.Markdown("## Tool Name", elem_classes="modal-title")
22
+ close_button = gr.Button("✕", size="sm", elem_classes="modal-close-btn")
23
+
24
+ # Body: Description + Inputs + Run + Output
25
+ with gr.Column(elem_classes="modal-body"):
26
+ tool_desc_md = gr.Markdown("_Description_")
27
+
28
+ # Inputs
29
+ input_components = []
30
+ for i in range(5):
31
+ input_components.append(
32
+ gr.Textbox(
33
+ label=f"Parameter {i+1}",
34
+ visible=True,
35
+ interactive=True,
36
+ elem_classes="modal-input"
37
+ )
38
+ )
39
+
40
+ # Run button and output
41
+ run_button = gr.Button("▶ Run Tool", variant="primary", size="lg")
42
+ output = gr.Textbox(
43
+ label="Output",
44
+ lines=8,
45
+ interactive=False,
46
+ max_lines=15
47
  )
 
 
 
 
 
 
 
 
 
 
48
 
49
  # Function to show modal with tool info (Content Only)
50
  def update_modal_content(tool: Callable):
 
263
  padding: 0 !important;
264
  }
265
 
 
266
  /* Modal Styles */
267
  .modal-wrapper {
268
  position: fixed !important;
 
270
  left: 0 !important;
271
  width: 100vw !important;
272
  height: 100vh !important;
273
+ background-color: rgba(0, 0, 0, 0.7) !important;
274
  backdrop-filter: blur(8px) !important;
275
  -webkit-backdrop-filter: blur(8px) !important;
276
  display: none !important; /* Hidden by default */
277
  justify-content: center !important;
278
  align-items: center !important;
279
  z-index: 9999 !important;
280
+ transition: opacity 0.2s ease;
281
  opacity: 0;
282
  }
283
 
 
288
  }
289
 
290
  .modal-content {
291
+ background: rgba(15, 23, 42, 0.95) !important; /* Dark slate with slight transparency */
292
+ border: 1px solid rgba(255, 255, 255, 0.1) !important;
293
+ border-radius: 16px !important;
294
  padding: 0 !important;
295
+ width: 100% !important;
296
+ max-width: 480px !important; /* Compact width */
297
  max-height: 85vh !important;
298
  overflow-y: auto !important;
299
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5) !important;
300
  position: relative !important;
301
  display: flex !important;
302
  flex-direction: column !important;
 
304
  }
305
 
306
  @keyframes modalSlideIn {
307
+ from { opacity: 0; transform: translateY(20px) scale(0.98); }
308
  to { opacity: 1; transform: translateY(0) scale(1); }
309
  }
310
 
311
+ /* Hide default Gradio close button */
312
+ .modal-wrapper > .close {
313
+ display: none !important;
 
 
 
 
 
 
 
 
 
 
 
314
  }
315
+
316
+ /* Custom Scrollbar for modal */
317
+ .modal-content::-webkit-scrollbar {
318
+ width: 6px;
 
 
 
 
 
 
 
319
  }
320
+ .modal-content::-webkit-scrollbar-track {
321
+ background: transparent;
 
 
 
322
  }
323
+ .modal-content::-webkit-scrollbar-thumb {
324
+ background-color: rgba(255, 255, 255, 0.1);
325
+ border-radius: 20px;
 
326
  }
327
  </style>
328
  """)