jetpackjules Claude commited on
Commit
196cdf6
Β·
1 Parent(s): 13cc81b

Add stunning row styling and arrow indicators to Investment Performance table

Browse files

- Added transparent green/red row backgrounds based on profit/loss
- Replaced +/- symbols with up/down arrow indicators (πŸ”Ί/πŸ”»)
- Added rounded corners and modern styling to table
- Converted from Dataframe to HTML component for full styling control
- Each row now has visual color coding: green for profits, red for losses
- Enhanced visual impact with gradient headers and hover effects

πŸ€– Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

Files changed (1) hide show
  1. app.py +123 -10
app.py CHANGED
@@ -432,21 +432,77 @@ def refresh_investment_performance_table():
432
  pl_dollars = sold_value - investment
433
  pl_percent = (pl_dollars / investment * 100) if investment > 0 else 0
434
 
435
- # Color indicator
436
- pl_indicator = "🟒" if pl_dollars > 0 else "πŸ”΄" if pl_dollars < 0 else "βšͺ"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
437
 
438
  invested_data.append({
439
- 'Symbol': f"{pl_indicator} {symbol}",
440
  'Status': status,
441
  'IPO Price': f"${ipo_price:.2f}" if ipo_price > 0 else 'N/A',
442
  'Buy Price': f"${avg_buy_price:.2f}",
443
  'Sell Price': f"${avg_sell_price:.2f}" if avg_sell_price > 0 else 'N/A',
444
  'Investment': f"${investment:.2f}",
445
- 'P&L ($)': f"${pl_dollars:+.2f}",
446
- 'P&L (%)': f"{pl_percent:+.2f}%"
 
447
  })
448
 
449
- return pd.DataFrame(invested_data)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
450
 
451
  def refresh_vm_stats():
452
  """Refresh VM statistics"""
@@ -782,6 +838,63 @@ custom_css = """
782
  .status-wrong { color: #8b949e !important; }
783
  .status-unknown { color: #ff0080 !important; }
784
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
785
  .profit-positive { color: #00d647 !important; font-weight: 600 !important; }
786
  .profit-negative { color: #ff0080 !important; font-weight: 600 !important; }
787
  .profit-neutral { color: #8b949e !important; }
@@ -934,9 +1047,9 @@ def create_dashboard():
934
  gr.Markdown("## 🎯 IPO Investment Performance")
935
  gr.Markdown("### Track profit/loss on your IPO investments with real-time market data")
936
 
937
- investment_performance_table = gr.Dataframe(
938
- label="IPO Investment P&L Analysis",
939
- elem_classes=["gr-dataframe"]
940
  )
941
  refresh_investment_btn = gr.Button("πŸ”„ Refresh Investment Performance", variant="primary", size="lg")
942
 
@@ -1070,7 +1183,7 @@ def create_dashboard():
1070
 
1071
  # Investment Performance tab
1072
  refresh_investment_btn.click(
1073
- fn=refresh_investment_performance_table,
1074
  outputs=[investment_performance_table]
1075
  )
1076
 
 
432
  pl_dollars = sold_value - investment
433
  pl_percent = (pl_dollars / investment * 100) if investment > 0 else 0
434
 
435
+ # Format P&L with arrows and colors
436
+ if pl_dollars > 0:
437
+ pl_arrow = "πŸ”Ί"
438
+ pl_color = "#00d647"
439
+ row_bg = "rgba(0, 214, 71, 0.1)"
440
+ elif pl_dollars < 0:
441
+ pl_arrow = "πŸ”»"
442
+ pl_color = "#ff0080"
443
+ row_bg = "rgba(255, 0, 128, 0.1)"
444
+ else:
445
+ pl_arrow = ""
446
+ pl_color = "#8b949e"
447
+ row_bg = "rgba(139, 148, 158, 0.05)"
448
+
449
+ # Format P&L values with styled arrows
450
+ pl_dollar_str = f"<span style='color: {pl_color}; font-weight: 600;'>{pl_arrow} ${abs(pl_dollars):.2f}</span>"
451
+ pl_percent_str = f"<span style='color: {pl_color}; font-weight: 600;'>{pl_arrow} {abs(pl_percent):.2f}%</span>"
452
 
453
  invested_data.append({
454
+ 'Symbol': symbol,
455
  'Status': status,
456
  'IPO Price': f"${ipo_price:.2f}" if ipo_price > 0 else 'N/A',
457
  'Buy Price': f"${avg_buy_price:.2f}",
458
  'Sell Price': f"${avg_sell_price:.2f}" if avg_sell_price > 0 else 'N/A',
459
  'Investment': f"${investment:.2f}",
460
+ 'P&L ($)': pl_dollar_str,
461
+ 'P&L (%)': pl_percent_str,
462
+ '_row_bg': row_bg # Store background color for styling
463
  })
464
 
465
+ df = pd.DataFrame(invested_data)
466
+ return df
467
+
468
+ def refresh_investment_performance_html():
469
+ """Return styled HTML table for investment performance"""
470
+ df = refresh_investment_performance_table()
471
+
472
+ if df.empty:
473
+ return "<div style='text-align: center; padding: 2rem; color: #666;'>No trading data available</div>"
474
+
475
+ # Build HTML table
476
+ html = '<table class="investment-table">'
477
+
478
+ # Header
479
+ html += '<thead><tr>'
480
+ for col in df.columns:
481
+ if not col.startswith('_'): # Skip internal columns
482
+ html += f'<th>{col}</th>'
483
+ html += '</tr></thead>'
484
+
485
+ # Body
486
+ html += '<tbody>'
487
+ for _, row in df.iterrows():
488
+ # Determine row class based on P&L
489
+ row_class = ""
490
+ pl_str = str(row.get('P&L ($)', ''))
491
+ if 'πŸ”Ί' in pl_str:
492
+ row_class = "profit-row"
493
+ elif 'πŸ”»' in pl_str:
494
+ row_class = "loss-row"
495
+ else:
496
+ row_class = "neutral-row"
497
+
498
+ html += f'<tr class="{row_class}">'
499
+ for col in df.columns:
500
+ if not col.startswith('_'): # Skip internal columns
501
+ html += f'<td>{row[col]}</td>'
502
+ html += '</tr>'
503
+
504
+ html += '</tbody></table>'
505
+ return html
506
 
507
  def refresh_vm_stats():
508
  """Refresh VM statistics"""
 
838
  .status-wrong { color: #8b949e !important; }
839
  .status-unknown { color: #ff0080 !important; }
840
 
841
+ /* Investment Performance Table Styling */
842
+ .investment-table {
843
+ width: 100%;
844
+ border-collapse: separate;
845
+ border-spacing: 0;
846
+ background: white;
847
+ border-radius: 16px;
848
+ overflow: hidden;
849
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
850
+ }
851
+
852
+ .investment-table th {
853
+ background: linear-gradient(135deg, #0070f3 0%, #0051a5 100%);
854
+ color: white;
855
+ padding: 1rem;
856
+ font-weight: 600;
857
+ text-align: left;
858
+ border: none;
859
+ }
860
+
861
+ .investment-table th:first-child {
862
+ border-top-left-radius: 16px;
863
+ }
864
+
865
+ .investment-table th:last-child {
866
+ border-top-right-radius: 16px;
867
+ }
868
+
869
+ .investment-table td {
870
+ padding: 1rem;
871
+ border-bottom: 1px solid #f5f5f5;
872
+ font-weight: 500;
873
+ }
874
+
875
+ .profit-row {
876
+ background: rgba(0, 214, 71, 0.1) !important;
877
+ border-left: 4px solid #00d647;
878
+ }
879
+
880
+ .loss-row {
881
+ background: rgba(255, 0, 128, 0.1) !important;
882
+ border-left: 4px solid #ff0080;
883
+ }
884
+
885
+ .neutral-row {
886
+ background: rgba(139, 148, 158, 0.05) !important;
887
+ border-left: 4px solid #8b949e;
888
+ }
889
+
890
+ .investment-table tr:last-child td:first-child {
891
+ border-bottom-left-radius: 16px;
892
+ }
893
+
894
+ .investment-table tr:last-child td:last-child {
895
+ border-bottom-right-radius: 16px;
896
+ }
897
+
898
  .profit-positive { color: #00d647 !important; font-weight: 600 !important; }
899
  .profit-negative { color: #ff0080 !important; font-weight: 600 !important; }
900
  .profit-neutral { color: #8b949e !important; }
 
1047
  gr.Markdown("## 🎯 IPO Investment Performance")
1048
  gr.Markdown("### Track profit/loss on your IPO investments with real-time market data")
1049
 
1050
+ investment_performance_table = gr.HTML(
1051
+ label="IPO Investment P&L Analysis",
1052
+ value="<div style='text-align: center; padding: 2rem; color: #666;'>Click Refresh to load investment performance data</div>"
1053
  )
1054
  refresh_investment_btn = gr.Button("πŸ”„ Refresh Investment Performance", variant="primary", size="lg")
1055
 
 
1183
 
1184
  # Investment Performance tab
1185
  refresh_investment_btn.click(
1186
+ fn=refresh_investment_performance_html,
1187
  outputs=[investment_performance_table]
1188
  )
1189