Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,8 @@ dist-ssr

# Test coverage
coverage

# Local Agent Skills
.agents/
skills-lock.json

5 changes: 4 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
<meta name="description" content="An AI-powered trading discipline copilot providing institutional-grade analysis and live global market overlays." />
<meta name="theme-color" content="#000000" />
<title>AI Trading Copilot — Discipline-Driven Market Intelligence</title>
<!-- Performance: preconnect to CDN used for globe assets -->
<!-- Performance: preconnect to CDN used for globe assets and Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
Comment on lines +11 to +14

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)(index\.html|tokens\.css|dashboard\.css|sidebar\.css|index\.css|auth-layout\.css|.*\.css)$' || true

echo "== index preconnect/stylesheet =="
if [ -f index.html ]; then
  sed -n '1,35p' index.html
fi

echo "== font variable and hardcoded Inter usage =="
rg -n "font-family-base|--font-family-base|font-family:.*Inter|font-family:\s*['\"]*Inter|['\"]Inter['\"]|--font-family-mono|Plus Jakarta Sans|Plus+Jakarta" -S --glob '*.css' --glob 'index.html' .

echo "== relevant CSS snippets =="
for f in tokens.css dashboard.css sidebar.css index.css auth-layout.css; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    rg -n -C 2 "font-family|variable|Inter|Plus|sans-serif" "$f" || true
  fi
done

Repository: TradeDisciplineAI/frontned

Length of output: 3145


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
import re

index = Path("index.html").read_text()
stylesheet = re.search(r'<link[^>]*href="([^"]*fonts\.googleapis\.com[^"]*)"[^>]*rel="stylesheet"', index)
loaded = []
if stylesheet:
    loaded = re.findall(r'family=([^:&#]+)', stylesheet.group(1))

css = []
for p in Path(".").rglob("*.css"):
    if ".git" in p.parts:
        continue
    txt = p.read_text(errors="ignore")
    hits = [("tokens base" if "--font-variable-base" in txt else None, txt)]
    css.append((p, txt))

base_var_pat = re.compile(r"--font-family-base\s*:\s*([^;]+)")
hardcoded_inter = re.compile(r"font-family\s*:\s*['\"]Inter['\"]|font-family\s*:\s*[^;]*['\"]Inter['\"]")
plus_fallback = re.compile(r"font-family\s*:\s*var\(--font-family-base,\s*['\"]Plus Jakarta Sans['\"]|font-family\s*:\s*['\"]Plus Jakarta Sans['\"]")

print(f"Google Fonts stylesheet loaded families: {loaded}")
print(f"inter preload present: {'Inter' in loaded}")
print()

for p, txt in css:
    base = base_var_pat.search(txt)
    if base:
        print(f"tokens base value in {p}: {base.group(1).strip()}")
    matches = list(hardcoded_inter.finditer(txt))
    if matches or plus_fallback.search(txt):
        print(f"{p}: hardcoded Inter occurrences={len(matches)}")
        for m in matches:
            line = txt[:m.start()].count("\n") + 1
            print(f"  line {line}: {txt.splitlines()[line-1].strip()}")
        if plus_fallback.search(txt):
            line = txt[:next(plus_fallback.finditer(txt)).start()].count("\n") + 1
            print(f"  line {line}: {txt.splitlines()[line-1].strip()}")

print()
print("Dashboard fallback analysis:")
dashboard = Path("src/styles/components/dashboard.css").read_text(errors="ignore")
var_decl = re.search(r":root\s*\{[^}]*--font-family-base\s*:", dashboard)
print(f"dashboard defines --font-family-base locally: {bool(var_decl)}")
PY

Repository: TradeDisciplineAI/frontned

Length of output: 1192


Load Inter for the theme’s base font.

tokens.css sets --font-family-base to start with Inter, and dashboard.css relies on that variable. If the variable is absent, it falls back to Plus Jakarta Sans, which this stylesheet already loads but is not the configured base font. Add the Inter Google Fonts stylesheet/preconnect so dashboard matches the rest of the UI; keep the existing Plus Jakarta Sans link only if this fallback behavior is intentional.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@index.html` around lines 11 - 14, Update the Google Fonts setup near the
existing font links to load Inter, including the required preconnect if needed,
so the configured --font-family-base resolves consistently with dashboard.css.
Retain the existing Plus Jakarta Sans font only if it is intentionally required
as a fallback.

<link rel="preconnect" href="https://unpkg.com" crossorigin />
<link rel="dns-prefetch" href="https://unpkg.com" />
</head>
Expand Down
2 changes: 1 addition & 1 deletion src/components/PortfolioView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ export const PortfolioView: React.FC = () => {
</button>
</form>
{isFull && (
<p style={{ color: '#f59e0b', fontSize: '0.8rem', marginTop: '8px', marginContent: 0 }}>
<p style={{ color: '#f59e0b', fontSize: '0.8rem', marginTop: '8px', margin: 0 }}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Conflicting marginTop and margin — the 8px top margin is silently dropped.

React applies inline style keys in order, so margin: 0 (a shorthand) overrides the earlier marginTop: '8px', resetting the top margin to 0. Keep only one. If the 8px gap is intended:

🎨 Proposed fix
-            <p style={{ color: '`#f59e0b`', fontSize: '0.8rem', marginTop: '8px', margin: 0 }}>
+            <p style={{ color: '`#f59e0b`', fontSize: '0.8rem', marginTop: '8px', marginBottom: 0 }}>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<p style={{ color: '#f59e0b', fontSize: '0.8rem', marginTop: '8px', margin: 0 }}>
<p style={{ color: '`#f59e0b`', fontSize: '0.8rem', marginTop: '8px', marginBottom: 0 }}>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/PortfolioView.tsx` at line 181, Update the inline style on the
paragraph in PortfolioView to remove the conflicting margin declaration and
preserve the intended 8px top spacing, using a single consistent margin
property.

💡 Your portfolio capacity is full (5/5 symbols limit). Remove an existing stock to
add a new one.
</p>
Expand Down
314 changes: 96 additions & 218 deletions src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
import React from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import {
Zap,
Search,
LayoutGrid,
PieChart,
LineChart,
Bot,
Globe,
Settings,
LogOut,
} from 'lucide-react';
import type { UserResponse } from '@/features/auth/auth.types';
import { ROUTES } from '@/constants/routes.constants';
import '@/styles/components/sidebar.css';

interface SidebarProps {
user: UserResponse | null;
Expand All @@ -12,243 +24,109 @@ export const Sidebar: React.FC<SidebarProps> = ({ user, onLogout }) => {
const navigate = useNavigate();
const location = useLocation();

const isDashboardActive = location.pathname === ROUTES.DASHBOARD;
const isExploreActive = location.pathname === ROUTES.EXPLORE;
const isDashboardActive = location.pathname === ROUTES.DASHBOARD;

return (
<aside
style={{
width: '320px',
background: 'var(--color-bg-secondary)',
backdropFilter: 'blur(20px)',
borderRight: '1px solid var(--color-border-subtle)',
padding: '30px 24px',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
flexShrink: 0,
minHeight: '100vh',
}}
>
<div>
{/* Brand Header */}
<div style={{ marginBottom: '32px', display: 'flex', alignItems: 'center', gap: '10px' }}>
<div
style={{
width: '12px',
height: '12px',
borderRadius: '50%',
background: 'var(--color-brand-teal)',
boxShadow: '0 0 10px var(--color-brand-teal)',
}}
/>
<h2
style={{
fontSize: '1.2rem',
fontWeight: 800,
margin: 0,
letterSpacing: '0.05em',
color: '#ffffff',
}}
>
TRADING COPILOT
</h2>
</div>
const username = user?.username || 'Anjal Dev VK';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Hardcoded developer name as username fallback.

'Anjal Dev VK' will be displayed for any user without a username, leaking a personal placeholder into production UI. Use a generic fallback.

✏️ Proposed fix
-  const username = user?.username || 'Anjal Dev VK';
+  const username = user?.username || 'Guest';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const username = user?.username || 'Anjal Dev VK';
const username = user?.username || 'Guest';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Sidebar.tsx` at line 30, Replace the personal fallback in the
username assignment within the Sidebar component with a generic user-facing
fallback, while preserving the existing user?.username value whenever it is
available.


{/* User Session Status */}
<div
style={{
marginBottom: '24px',
padding: '16px',
background: 'rgba(13, 148, 136, 0.08)',
border: '1px solid rgba(13, 148, 136, 0.2)',
borderRadius: '12px',
}}
>
<div
style={{
fontSize: '0.75rem',
textTransform: 'uppercase',
color: 'var(--color-brand-teal)',
fontWeight: 700,
letterSpacing: '0.05em',
}}
>
Session Status
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginTop: '6px' }}>
<div
style={{
width: '8px',
height: '8px',
borderRadius: '50%',
background: user ? '#10b981' : '#ef4444',
}}
/>
<span style={{ fontSize: '0.9rem', fontWeight: 600 }}>
{user ? 'Logged In' : 'Not Logged In'}
</span>
return (
<aside className="vercel-sidebar">
{/* Scrollable Navigation Area */}
<div className="sidebar-scrollable-content">
{/* Top Workspace Header Selector */}
<div className="sidebar-workspace-bar">
<div className="sidebar-workspace-info">
<div className="sidebar-workspace-avatar">
<Zap size={12} strokeWidth={2.5} />
</div>
<span className="sidebar-workspace-name">{username}</span>
</div>
<span className="sidebar-workspace-badge">Pro</span>
</div>

{/* Profile Card */}
{user && (
<div style={{ display: 'flex', flexDirection: 'column', gap: '14px' }}>
<div
style={{
fontSize: '0.75rem',
textTransform: 'uppercase',
color: '#9ca3af',
fontWeight: 700,
letterSpacing: '0.05em',
}}
>
Trader Profile
</div>
<div
style={{
display: 'flex',
flexDirection: 'column',
gap: '8px',
background: 'rgba(255, 255, 255, 0.02)',
padding: '16px',
border: '1px solid rgba(255, 255, 255, 0.04)',
borderRadius: '12px',
}}
>
<p style={{ margin: 0, fontSize: '0.9rem' }}>
<strong style={{ color: '#9ca3af' }}>User:</strong> {user.username}
</p>
<p style={{ margin: 0, fontSize: '0.9rem', wordBreak: 'break-all' }}>
<strong style={{ color: '#9ca3af' }}>Email:</strong> {user.email}
</p>
<p style={{ margin: 0, fontSize: '0.9rem' }}>
<strong style={{ color: '#9ca3af' }}>Role:</strong> {user.role}
</p>
<p style={{ margin: 0, fontSize: '0.9rem' }}>
<strong style={{ color: '#9ca3af' }}>Verified:</strong>{' '}
{user.is_verified ? 'Yes' : 'No'}
</p>
</div>
{/* Search Input Box */}
<div className="sidebar-search-box">
<div className="sidebar-search-placeholder">
<Search size={13} strokeWidth={2} />
<span>Find</span>
</div>
)}
<span className="sidebar-search-key">F</span>
</div>

{/* Navigation Links */}
<div style={{ marginTop: '24px', display: 'flex', flexDirection: 'column', gap: '8px' }}>
<div
style={{
fontSize: '0.75rem',
textTransform: 'uppercase',
color: '#9ca3af',
fontWeight: 700,
letterSpacing: '0.05em',
marginBottom: '4px',
}}
{/* Sidebar Navigation */}
<div className="sidebar-nav-list">
<button
className={`sidebar-nav-item ${isExploreActive ? 'active' : ''}`}
onClick={() => navigate(ROUTES.EXPLORE)}
>
Navigation
</div>
<div className="sidebar-item-left">
<span className="sidebar-item-icon">
<LayoutGrid size={15} strokeWidth={2} />
</span>
<span>Explore Markets</span>
</div>
</button>

<button
className={`sidebar-nav-item ${isDashboardActive ? 'active' : ''}`}
onClick={() => navigate(ROUTES.DASHBOARD)}
style={{
display: 'flex',
alignItems: 'center',
gap: '10px',
width: '100%',
background: isDashboardActive ? 'rgba(255, 255, 255, 0.05)' : 'transparent',
border: isDashboardActive
? '1px solid rgba(255, 255, 255, 0.08)'
: '1px solid transparent',
color: isDashboardActive ? '#ffffff' : '#9ca3af',
padding: '10px 14px',
borderRadius: '8px',
cursor: 'pointer',
fontWeight: 600,
textAlign: 'left',
transition: 'all 0.2s',
}}
onMouseOver={(e) => {
if (!isDashboardActive) {
e.currentTarget.style.background = 'rgba(255, 255, 255, 0.03)';
e.currentTarget.style.color = '#ffffff';
}
}}
onMouseOut={(e) => {
if (!isDashboardActive) {
e.currentTarget.style.background = 'transparent';
e.currentTarget.style.color = '#9ca3af';
}
}}
>
📊 Dashboard
<div className="sidebar-item-left">
<span className="sidebar-item-icon">
<PieChart size={15} strokeWidth={2} />
</span>
<span>Portfolio</span>
</div>
</button>

<button
onClick={() => navigate(ROUTES.EXPLORE)}
style={{
display: 'flex',
alignItems: 'center',
gap: '10px',
width: '100%',
background: isExploreActive ? 'rgba(255, 255, 255, 0.05)' : 'transparent',
border: isExploreActive
? '1px solid rgba(255, 255, 255, 0.08)'
: '1px solid transparent',
color: isExploreActive ? '#ffffff' : '#9ca3af',
padding: '10px 14px',
borderRadius: '8px',
cursor: 'pointer',
fontWeight: 600,
textAlign: 'left',
transition: 'all 0.2s',
}}
onMouseOver={(e) => {
if (!isExploreActive) {
e.currentTarget.style.background = 'rgba(255, 255, 255, 0.03)';
e.currentTarget.style.color = '#ffffff';
}
}}
onMouseOut={(e) => {
if (!isExploreActive) {
e.currentTarget.style.background = 'transparent';
e.currentTarget.style.color = '#9ca3af';
}
}}
>
🌍 Explore Markets
<button className="sidebar-nav-item">
<div className="sidebar-item-left">
<span className="sidebar-item-icon">
<LineChart size={15} strokeWidth={2} />
</span>
<span>Analytics</span>
</div>
</button>

<button className="sidebar-nav-item">
<div className="sidebar-item-left">
<span className="sidebar-item-icon">
<Bot size={15} strokeWidth={2} />
</span>
<span>AI Discipline</span>
</div>
<span className="sidebar-badge-beta">Beta</span>
</button>

<div className="sidebar-divider" />

<button className="sidebar-nav-item">
<div className="sidebar-item-left">
<span className="sidebar-item-icon">
<Globe size={15} strokeWidth={2} />
</span>
<span>Global Feeds</span>
</div>
</button>

<button className="sidebar-nav-item">
<div className="sidebar-item-left">
<span className="sidebar-item-icon">
<Settings size={15} strokeWidth={2} />
</span>
<span>Settings</span>
</div>
</button>
</div>
</div>

{/* Logout Button */}
<button
type="button"
onClick={onLogout}
style={{
width: '100%',
background: 'rgba(239, 68, 68, 0.1)',
border: '1px solid rgba(239, 68, 68, 0.2)',
color: '#ef4444',
padding: '12px',
borderRadius: '10px',
cursor: 'pointer',
fontWeight: 700,
fontSize: '0.95rem',
transition: 'all 0.2s',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: '8px',
}}
onMouseOver={(e) => {
e.currentTarget.style.background = 'rgba(239, 68, 68, 0.2)';
}}
onMouseOut={(e) => {
e.currentTarget.style.background = 'rgba(239, 68, 68, 0.1)';
}}
>
Logout
</button>
{/* Pinned Logout Button at Bottom of Sidebar */}
<div className="sidebar-pinned-bottom">
<button className="sidebar-logout-full-btn" onClick={onLogout}>
<LogOut size={14} strokeWidth={2} />
<span>Log Out</span>
</button>
</div>
</aside>
);
};
Loading
Loading