Fix Tailwind CSS styling configuration
- Add tailwind.config.ts with proper content paths and theme config - Add postcss.config.js for Tailwind and autoprefixer processing - Downgrade tailwindcss to v3.4.17 and add missing PostCSS dependencies - Update Dockerfile to clarify build process - Fix UI styling issues in Docker environment
This commit is contained in:
124
app/api/session-status/route.ts
Normal file
124
app/api/session-status/route.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { tradingViewAutomation } from '../../../lib/tradingview-automation'
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
console.log('📊 Getting TradingView session status...')
|
||||
|
||||
// Initialize if not already done (Docker-safe initialization)
|
||||
if (!tradingViewAutomation['browser']) {
|
||||
console.log('🐳 Initializing TradingView automation in Docker environment...')
|
||||
await tradingViewAutomation.init()
|
||||
}
|
||||
|
||||
// Get lightweight session information without navigation
|
||||
const sessionInfo = await tradingViewAutomation.getQuickSessionStatus()
|
||||
|
||||
// Determine connection status based on browser state and URL
|
||||
let connectionStatus = 'unknown'
|
||||
if (sessionInfo.browserActive) {
|
||||
if (sessionInfo.currentUrl.includes('tradingview.com')) {
|
||||
connectionStatus = 'connected'
|
||||
} else if (sessionInfo.currentUrl) {
|
||||
connectionStatus = 'disconnected'
|
||||
} else {
|
||||
connectionStatus = 'unknown'
|
||||
}
|
||||
} else {
|
||||
connectionStatus = 'disconnected'
|
||||
}
|
||||
|
||||
const response = {
|
||||
success: true,
|
||||
session: {
|
||||
...sessionInfo,
|
||||
connectionStatus,
|
||||
lastChecked: new Date().toISOString(),
|
||||
dockerEnv: process.env.DOCKER_ENV === 'true',
|
||||
environment: process.env.NODE_ENV || 'development'
|
||||
}
|
||||
}
|
||||
|
||||
console.log('✅ Session status retrieved:', response.session)
|
||||
return NextResponse.json(response)
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to get session status:', error)
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to get session status',
|
||||
session: {
|
||||
isAuthenticated: false,
|
||||
hasSavedCookies: false,
|
||||
hasSavedStorage: false,
|
||||
cookiesCount: 0,
|
||||
currentUrl: '',
|
||||
connectionStatus: 'error',
|
||||
lastChecked: new Date().toISOString(),
|
||||
dockerEnv: process.env.DOCKER_ENV === 'true',
|
||||
environment: process.env.NODE_ENV || 'development'
|
||||
}
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { action } = await request.json()
|
||||
console.log(`🔧 Session action requested: ${action} (Docker: ${process.env.DOCKER_ENV === 'true'})`)
|
||||
|
||||
// Initialize if not already done (Docker-safe initialization)
|
||||
if (!tradingViewAutomation['browser']) {
|
||||
console.log('🐳 Initializing TradingView automation for session action in Docker...')
|
||||
await tradingViewAutomation.init()
|
||||
}
|
||||
|
||||
let result: any = { success: true }
|
||||
|
||||
switch (action) {
|
||||
case 'refresh':
|
||||
const refreshed = await tradingViewAutomation.refreshSession()
|
||||
result.refreshed = refreshed
|
||||
result.message = refreshed ? 'Session refreshed successfully' : 'Failed to refresh session'
|
||||
break
|
||||
|
||||
case 'clear':
|
||||
await tradingViewAutomation.clearSession()
|
||||
result.message = 'Session data cleared successfully'
|
||||
break
|
||||
|
||||
case 'test':
|
||||
const testResult = await tradingViewAutomation.testSessionPersistence()
|
||||
result.testResult = testResult
|
||||
result.message = testResult.isValid ? 'Session is valid' : 'Session is invalid or expired'
|
||||
break
|
||||
|
||||
case 'login-status':
|
||||
const isLoggedIn = await tradingViewAutomation.checkLoginStatus()
|
||||
result.isLoggedIn = isLoggedIn
|
||||
result.message = isLoggedIn ? 'User is logged in' : 'User is not logged in'
|
||||
break
|
||||
|
||||
default:
|
||||
result.success = false
|
||||
result.error = `Unknown action: ${action}`
|
||||
return NextResponse.json(result, { status: 400 })
|
||||
}
|
||||
|
||||
console.log(`✅ Session action '${action}' completed:`, result)
|
||||
return NextResponse.json({
|
||||
...result,
|
||||
dockerEnv: process.env.DOCKER_ENV === 'true',
|
||||
environment: process.env.NODE_ENV || 'development'
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Session action failed:', error)
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Session action failed',
|
||||
dockerEnv: process.env.DOCKER_ENV === 'true',
|
||||
environment: process.env.NODE_ENV || 'development'
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
163
app/globals.css
163
app/globals.css
@@ -1,7 +1,170 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
:root {
|
||||
--bg-primary: #0a0a0b;
|
||||
--bg-secondary: #1a1a1b;
|
||||
--bg-tertiary: #262626;
|
||||
--bg-card: #1e1e1f;
|
||||
--border-primary: #333;
|
||||
--text-primary: #ffffff;
|
||||
--text-secondary: #a1a1aa;
|
||||
--text-accent: #22d3ee;
|
||||
--success: #10b981;
|
||||
--danger: #ef4444;
|
||||
--warning: #f59e0b;
|
||||
--purple: #8b5cf6;
|
||||
--blue: #3b82f6;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', system-ui, sans-serif;
|
||||
background: linear-gradient(135deg, var(--bg-primary) 0%, #0f0f0f 100%);
|
||||
color: var(--text-primary);
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* Custom scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--border-primary);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #555;
|
||||
}
|
||||
|
||||
/* Glass morphism effect */
|
||||
.glass {
|
||||
background: rgba(26, 26, 27, 0.8);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
/* Gradient borders */
|
||||
.gradient-border {
|
||||
position: relative;
|
||||
background: var(--bg-card);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.gradient-border::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
padding: 1px;
|
||||
background: linear-gradient(135deg, rgba(34, 211, 238, 0.3), rgba(139, 92, 246, 0.3));
|
||||
border-radius: inherit;
|
||||
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
||||
mask-composite: subtract;
|
||||
}
|
||||
|
||||
/* Button components */
|
||||
@layer components {
|
||||
.btn {
|
||||
@apply px-4 py-2 rounded-lg font-medium transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
@apply bg-gradient-to-r from-cyan-500 to-blue-600 hover:from-cyan-600 hover:to-blue-700 text-white shadow-lg hover:shadow-cyan-500/25;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
@apply bg-gray-700 hover:bg-gray-600 text-gray-100 border border-gray-600;
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
@apply bg-gradient-to-r from-green-500 to-emerald-600 hover:from-green-600 hover:to-emerald-700 text-white shadow-lg hover:shadow-green-500/25;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
@apply bg-gradient-to-r from-red-500 to-rose-600 hover:from-red-600 hover:to-rose-700 text-white shadow-lg hover:shadow-red-500/25;
|
||||
}
|
||||
|
||||
.btn-warning {
|
||||
@apply bg-gradient-to-r from-yellow-500 to-orange-600 hover:from-yellow-600 hover:to-orange-700 text-white shadow-lg hover:shadow-yellow-500/25;
|
||||
}
|
||||
|
||||
.card {
|
||||
@apply bg-gray-900/50 backdrop-blur-sm border border-gray-800 rounded-xl p-6 shadow-xl hover:shadow-2xl transition-all duration-300;
|
||||
}
|
||||
|
||||
.card-gradient {
|
||||
@apply relative overflow-hidden;
|
||||
background: linear-gradient(135deg, rgba(30, 30, 31, 0.9) 0%, rgba(26, 26, 27, 0.9) 100%);
|
||||
}
|
||||
|
||||
.card-gradient::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, transparent, rgba(34, 211, 238, 0.5), transparent);
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
@apply inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium;
|
||||
}
|
||||
|
||||
.status-online {
|
||||
@apply bg-green-100 text-green-800 border border-green-200;
|
||||
}
|
||||
|
||||
.status-offline {
|
||||
@apply bg-red-100 text-red-800 border border-red-200;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
@apply bg-yellow-100 text-yellow-800 border border-yellow-200;
|
||||
}
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@keyframes pulse-glow {
|
||||
0%, 100% {
|
||||
box-shadow: 0 0 5px rgba(34, 211, 238, 0.5);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 0 20px rgba(34, 211, 238, 0.8), 0 0 30px rgba(34, 211, 238, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.pulse-glow {
|
||||
animation: pulse-glow 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes slide-up {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.slide-up {
|
||||
animation: slide-up 0.6s ease-out;
|
||||
}
|
||||
|
||||
/* Loading spinner */
|
||||
.spinner {
|
||||
@apply inline-block w-4 h-4 border-2 border-gray-300 border-t-cyan-500 rounded-full animate-spin;
|
||||
}
|
||||
|
||||
@@ -3,16 +3,68 @@ import type { Metadata } from 'next'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Trading Bot Dashboard',
|
||||
description: 'AI-powered trading bot dashboard with auto-trading, analysis, and developer tools.'
|
||||
description: 'AI-powered trading bot dashboard with auto-trading, analysis, and developer tools.',
|
||||
viewport: 'width=device-width, initial-scale=1',
|
||||
}
|
||||
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<body className="bg-gray-950 text-gray-100 min-h-screen" suppressHydrationWarning>
|
||||
<main className="max-w-5xl mx-auto py-8">
|
||||
{children}
|
||||
</main>
|
||||
<body className="bg-gray-950 text-gray-100 min-h-screen antialiased" suppressHydrationWarning>
|
||||
<div className="min-h-screen bg-gradient-to-br from-gray-950 via-gray-900 to-gray-950">
|
||||
{/* Header */}
|
||||
<header className="border-b border-gray-800 bg-gray-900/50 backdrop-blur-sm">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex justify-between items-center h-16">
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="w-8 h-8 bg-gradient-to-br from-cyan-400 to-blue-600 rounded-lg flex items-center justify-center">
|
||||
<span className="text-white font-bold text-sm">TB</span>
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-xl font-bold text-white">Trading Bot</h1>
|
||||
<p className="text-xs text-gray-400">AI-Powered Dashboard</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="hidden sm:flex items-center space-x-2 text-sm">
|
||||
<div className="w-2 h-2 bg-green-400 rounded-full animate-pulse"></div>
|
||||
<span className="text-gray-300">Live</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="w-8 h-8 bg-gray-700 rounded-full flex items-center justify-center">
|
||||
<span className="text-gray-300 text-sm">👤</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
{children}
|
||||
</main>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="border-t border-gray-800 bg-gray-900/30 backdrop-blur-sm mt-16">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
||||
<div className="flex flex-col sm:flex-row justify-between items-center">
|
||||
<div className="text-sm text-gray-400">
|
||||
© 2025 Trading Bot Dashboard. Powered by AI.
|
||||
</div>
|
||||
<div className="flex items-center space-x-4 mt-4 sm:mt-0">
|
||||
<div className="text-xs text-gray-500">
|
||||
Next.js 15 • TypeScript • Tailwind CSS
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
|
||||
17
app/page.tsx
17
app/page.tsx
@@ -1,11 +1,20 @@
|
||||
import AIAnalysisPanel from '../components/AIAnalysisPanel'
|
||||
import Dashboard from '../components/Dashboard'
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<>
|
||||
<AIAnalysisPanel />
|
||||
<div className="space-y-8">
|
||||
{/* Hero Section */}
|
||||
<div className="text-center py-8">
|
||||
<h1 className="text-4xl font-bold bg-gradient-to-r from-cyan-400 to-blue-600 bg-clip-text text-transparent mb-4">
|
||||
AI Trading Dashboard
|
||||
</h1>
|
||||
<p className="text-gray-400 text-lg max-w-2xl mx-auto">
|
||||
Advanced cryptocurrency trading with AI-powered analysis, automated execution, and real-time monitoring.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Main Dashboard */}
|
||||
<Dashboard />
|
||||
</>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user