| <script setup> |
| import Navbar from './components/Navbar.vue' |
| import TickerCard from './components/TickerCard.vue' |
| import Watchlist from './components/Watchlist.vue' |
| import SidebarAction from './components/SidebarAction.vue' |
| import SearchModal from './components/SearchModal.vue' |
| import DataHubModal from './components/DataHubModal.vue' |
| import AIBuilderClassic from './components/AIBuilderClassic.vue' |
| import AIBuilderNeural from './components/AIBuilderNeural.vue' |
| import OptionsAnalysisModal from './components/OptionsAnalysisModal.vue' |
| import Quickstart from './components/Quickstart.vue' |
| import { |
| Search, Brain, Activity, Sparkles, Zap, Palette, |
| Github, Twitter, MessageSquare, Shield, BookOpen, Terminal |
| } from 'lucide-vue-next' |
| import { ref, onMounted, onUnmounted, computed, watch } from 'vue' |
| import { useAuth } from './services/auth' |
| import { api } from './services/api' |
| |
| const { setToken, isAuthenticated, login, fetchProfile, user } = useAuth() |
| const isSearchOpen = ref(false) |
| const isDataHubOpen = ref(false) |
| const isAIBuilderOpen = ref(false) |
| const classicBuilderTab = ref('Data') |
| const isAIBuilderNeuralOpen = ref(false) |
| const isOptionsAnalysisOpen = ref(false) |
| const dataHubTab = ref('universe') |
| const selectedSymbolForAnalysis = ref('') |
| const watchlistRef = ref(null) |
| const currentTheme = ref('dark') |
| |
| const switchTheme = (theme) => { |
| currentTheme.value = theme |
| document.documentElement.className = '' |
| if (theme !== 'dark') { |
| document.documentElement.classList.add(`theme-${theme}`) |
| } |
| } |
| |
| const workflowStats = ref({ |
| universeCount: 0, |
| readyFeatures: 0, |
| totalFeatures: 0, |
| modelCount: 0 |
| }) |
| |
| const fetchWorkflowStats = async () => { |
| if (!isAuthenticated()) return |
| try { |
| const [univ, feat, mods] = await Promise.all([ |
| api.get('/ai/universe'), |
| api.get('/ai/features-status'), |
| api.get('/ai/models') |
| ]) |
| workflowStats.value = { |
| universeCount: univ.length, |
| readyFeatures: feat.ready, |
| totalFeatures: feat.total, |
| modelCount: mods.length |
| } |
| } catch (err) { |
| console.error('Stats fetch failed:', err) |
| } |
| } |
| |
| const marketData = ref([ |
| { symbol: 'S&P 500', loading: true }, |
| { symbol: 'NASDAQ', loading: true }, |
| { symbol: 'DOW', loading: true }, |
| { symbol: 'VIX', loading: true } |
| ]) |
| let marketInterval = null |
| |
| const protectedAction = (callback) => { |
| return (...args) => { |
| if (!isAuthenticated()) { |
| login() |
| return |
| } |
| callback(...args) |
| } |
| } |
| |
| const refreshWatchlist = () => { |
| watchlistRef.value?.fetchData(true) |
| fetchWorkflowStats() |
| } |
| |
| const openOptionsAnalysis = (symbol) => { |
| selectedSymbolForAnalysis.value = symbol; |
| isOptionsAnalysisOpen.value = true; |
| } |
| |
| const protectedOpenSearch = protectedAction(() => isSearchOpen.value = true); |
| const protectedOpenOptionsAnalysis = protectedAction(openOptionsAnalysis); |
| const protectedOpenDataHub = protectedAction((tab = 'universe') => { |
| dataHubTab.value = tab; |
| isDataHubOpen.value = true; |
| }); |
| const protectedOpenAIBuilder = protectedAction((tab = 'Data') => { |
| classicBuilderTab.value = tab; |
| isAIBuilderOpen.value = true; |
| }); |
| const protectedOpenAIBuilderNeural = protectedAction(() => isAIBuilderNeuralOpen.value = true); |
| |
| const fetchMarketData = async () => { |
| try { |
| const data = await api.get('/market-indices') |
| if (data.results && data.results.length > 0) { |
| data.results.forEach(newItem => { |
| const index = marketData.value.findIndex(item => item.symbol === newItem.symbol) |
| if (index !== -1) { |
| marketData.value[index] = { ...newItem, loading: false } |
| } |
| }) |
| } |
| } catch (error) { |
| console.error('Failed to fetch market data:', error) |
| } |
| } |
| |
| const handleGlobalKeyDown = (e) => { |
| if ((e.metaKey || e.ctrlKey) && e.key === 'k') { |
| e.preventDefault() |
| protectedOpenSearch() |
| } |
| } |
| |
| const globalEvents = ref([ |
| { t: 'Watchlist', m: 'Global market indices updated with 15ms latency.', c: 'text-blue-400' }, |
| { t: 'Security', m: 'Encrypted tunnel established with NEXUS nodes.', c: 'text-slate-400' } |
| ]) |
| |
| const addGlobalEvent = (type, message, colorClass = 'text-slate-400') => { |
| globalEvents.value.unshift({ t: type, m: message, c: colorClass }) |
| if (globalEvents.value.length > 3) globalEvents.value.pop() |
| } |
| |
| onMounted(() => { |
| const params = new URLSearchParams(window.location.search) |
| const urlToken = params.get('token') |
| if (urlToken && window.location.pathname.includes('/auth/callback')) { |
| setToken(urlToken) |
| fetchProfile().then(() => { |
| fetchWorkflowStats() |
| addGlobalEvent('Auth', `Identity verified: ${user.value?.full_name?.split(' ')[0]}`, 'text-blue-400') |
| if (user.value?.theme) switchTheme(user.value.theme) |
| }) |
| window.history.replaceState({}, document.title, "/") |
| } else { |
| if (isAuthenticated()) { |
| fetchProfile().then(() => { |
| if (user.value?.theme) switchTheme(user.value.theme) |
| }); |
| } |
| } |
| |
| window.addEventListener('keydown', handleGlobalKeyDown) |
| fetchMarketData() |
| if (isAuthenticated()) fetchWorkflowStats() |
| |
| marketInterval = setInterval(() => { |
| fetchMarketData() |
| refreshWatchlist() |
| addGlobalEvent('Sync', 'Nexus heartbeats received.', 'text-emerald-500/80') |
| }, 60000) |
| }) |
| |
| onUnmounted(() => { |
| window.removeEventListener('keydown', handleGlobalKeyDown) |
| if (marketInterval) clearInterval(marketInterval) |
| }) |
| </script> |
| |
| <template> |
| <div class="min-h-screen font-sans bg-[#0b1120] text-slate-200 transition-colors duration-300 overflow-x-hidden"> |
| <Navbar /> |
| |
| <main class="max-w-[1400px] mx-auto px-4 md:px-8 py-6 md:py-16"> |
| |
| |
| <section class="text-center mb-10 md:mb-20"> |
| <template v-if="!isAuthenticated()"> |
| <h1 class="text-3xl sm:text-4xl md:text-7xl font-black text-white mb-4 md:mb-8 tracking-tighter leading-tight"> |
| Next-Gen Market <br/><span class="bg-gradient-to-r from-blue-400 to-indigo-600 bg-clip-text text-transparent">Intelligence.</span> |
| </h1> |
| <p class="text-slate-400 text-xs md:text-xl max-w-2xl mx-auto mb-8 md:mb-12 px-4 leading-relaxed"> |
| Harness institutional-grade AI and multi-agent systems to master the market with quantitative precision. |
| </p> |
| </template> |
| <template v-else> |
| <div class="flex flex-col sm:flex-row sm:items-center justify-between mb-8 md:mb-12 gap-6 text-left"> |
| <div> |
| <h2 class="text-2xl md:text-4xl font-bold text-white mb-2 tracking-tight">Intelligent Trade Model Builder</h2> |
| <p class="text-[10px] md:text-sm text-slate-500 uppercase font-black tracking-widest"> |
| Operator: <span class="text-blue-400">{{ user?.full_name }}</span> | System: <span class="text-emerald-500">NEXUS Core Sync Active</span> |
| </p> |
| </div> |
| <div class="flex items-center gap-3"> |
| <div class="bg-slate-900 border border-slate-800 px-4 py-2 rounded-2xl flex items-center gap-3 shadow-xl"> |
| <div class="w-2 h-2 bg-emerald-500 rounded-full animate-pulse"></div> |
| <span class="text-[10px] font-black uppercase tracking-widest text-slate-400">Node Connected</span> |
| </div> |
| </div> |
| </div> |
| |
| <Quickstart |
| v-bind="workflowStats" |
| @openUniverse="protectedOpenDataHub" |
| @openTraining="protectedOpenAIBuilder" |
| @openAgentic="protectedOpenSearch" |
| /> |
| </template> |
| |
| |
| <div class="grid grid-cols-2 md:grid-cols-4 gap-3 md:gap-6 mt-10 md:mt-16"> |
| <TickerCard |
| v-for="item in marketData" |
| :key="item.symbol" |
| v-bind="item" |
| /> |
| </div> |
| |
| |
| <div class="max-w-3xl mx-auto mt-10 md:mt-20 px-2"> |
| <div |
| @click="protectedOpenSearch" |
| class="bg-slate-900/40 border border-slate-800 p-1 rounded-2xl md:rounded-3xl group hover:border-blue-500/50 cursor-pointer transition-all active:scale-[0.98] shadow-2xl" |
| > |
| <div class="flex items-center gap-3 md:gap-5 p-3 md:p-5 text-left"> |
| <div class="bg-blue-600/20 p-2 md:p-4 rounded-xl md:rounded-2xl"> |
| <Search class="w-5 h-5 md:w-6 md:h-6 text-blue-500" /> |
| </div> |
| <div class="flex flex-col flex-1 truncate"> |
| <span class="text-sm md:text-xl font-black text-white tracking-tight">Search Assets & Strategies</span> |
| <span class="text-[10px] md:text-xs text-slate-500 uppercase tracking-widest font-bold">Options Architect Engine v3.2</span> |
| </div> |
| <div class="hidden md:flex items-center gap-2"> |
| <kbd class="px-2 py-1 text-[10px] font-black text-slate-600 bg-slate-800 border border-slate-700 rounded-lg">⌘K</kbd> |
| </div> |
| </div> |
| </div> |
| </div> |
| </section> |
| |
| |
| <div class="grid grid-cols-1 lg:grid-cols-12 gap-6 md:gap-8"> |
| |
| <div class="lg:col-span-8 xl:col-span-9 order-2 lg:order-1"> |
| <Watchlist |
| ref="watchlistRef" |
| @openSearch="protectedOpenSearch" |
| @openOptionsAnalysis="protectedOpenOptionsAnalysis" |
| /> |
| </div> |
| |
| |
| <div class="lg:col-span-4 xl:col-span-3 order-1 lg:order-2 space-y-4 md:space-y-6"> |
| <div class="flex items-center justify-between px-2"> |
| <h3 class="text-[10px] font-black text-slate-500 uppercase tracking-widest italic">Intelligence Operations</h3> |
| <Activity class="w-3 h-3 text-slate-700" /> |
| </div> |
| |
| <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-1 gap-3 md:gap-4"> |
| <SidebarAction @click="protectedOpenAIBuilder" label="NEXUS Quadrant" color="bg-blue-600" iconColor="text-blue-500"><template #icon><Brain class="w-5 h-5" /></template></SidebarAction> |
| <SidebarAction @click="protectedOpenAIBuilderNeural" label="NEXUS Neural" color="bg-rose-600" iconColor="text-rose-500"><template #icon><Sparkles class="w-5 h-5" /></template></SidebarAction> |
| <SidebarAction @click="protectedOpenDataHub" label="Data Hub" color="bg-cyan-600" iconColor="text-cyan-500"><template #icon><Activity class="w-5 h-5" /></template></SidebarAction> |
| <div class="p-6 bg-slate-900 border border-slate-800 rounded-3xl relative overflow-hidden flex flex-col items-start gap-4 shadow-xl"> |
| <Zap class="w-10 h-10 text-amber-500/20 absolute -right-2 -bottom-2 rotate-12" /> |
| <h4 class="text-xs font-black text-white uppercase tracking-widest">Agentic Option Strategist</h4> |
| <p class="text-[10px] text-slate-500 leading-relaxed font-medium">Deploy multi-source web scrapers to build sentiment-aware strategies.</p> |
| <button @click="protectedOpenSearch" class="w-full py-2 bg-blue-600 text-[10px] font-black uppercase tracking-widest text-white rounded-xl shadow-lg shadow-blue-900/40">New Op</button> |
| </div> |
| </div> |
| </div> |
| </div> |
| </main> |
| |
| |
| <footer class="py-12 md:py-24 px-4 md:px-8 border-t border-slate-800/50 mt-20 md:mt-40 bg-slate-950/20"> |
| <div class="max-w-[1400px] mx-auto grid grid-cols-1 md:grid-cols-12 gap-12"> |
| <div class="md:col-span-5 lg:col-span-4"> |
| <div class="flex items-center gap-2 mb-6"> |
| <Activity class="text-blue-500 w-6 h-6" /> |
| <span class="text-2xl font-black tracking-tighter text-white">k9t<span class="text-blue-500 italic">Trader</span></span> |
| </div> |
| <p class="text-sm text-slate-500 leading-relaxed mb-8 max-w-sm"> |
| Institutional-grade market intelligence powered by multi-agent AI ecosystems. Build, verify, and master the quantitative strategy lifecycle. |
| </p> |
| <div class="flex gap-4"> |
| <button class="w-10 h-10 rounded-xl bg-slate-900 border border-slate-800 flex items-center justify-center hover:border-blue-500 hover:text-blue-500 transition-all shadow-lg text-slate-500"> |
| <Github class="w-5 h-5" /> |
| </button> |
| <button class="w-10 h-10 rounded-xl bg-slate-900 border border-slate-800 flex items-center justify-center hover:border-sky-500 hover:text-sky-500 transition-all shadow-lg text-slate-500"> |
| <Twitter class="w-5 h-5" /> |
| </button> |
| <button class="w-10 h-10 rounded-xl bg-slate-900 border border-slate-800 flex items-center justify-center hover:border-indigo-500 hover:text-indigo-500 transition-all shadow-lg text-slate-500"> |
| <MessageSquare class="w-5 h-5" /> |
| </button> |
| </div> |
| </div> |
| |
| <div class="md:col-span-7 lg:col-span-8 grid grid-cols-2 sm:grid-cols-3 gap-8"> |
| <div> |
| <h4 class="text-[10px] font-black text-slate-600 uppercase tracking-widest mb-6">Nexus Pipeline</h4> |
| <ul class="space-y-4"> |
| <li v-for="l in ['Trade Model Builder', 'Neural Quadrant', 'Data Hub Provisioning', 'Agentic Strategist']" :key="l" class="text-xs font-bold text-slate-500 hover:text-white transition-colors cursor-pointer flex items-center gap-2"> |
| <div class="w-1 h-1 bg-blue-500 rounded-full"></div> {{ l }} |
| </li> |
| </ul> |
| </div> |
| <div> |
| <h4 class="text-[10px] font-black text-slate-600 uppercase tracking-widest mb-6">Terminal Resources</h4> |
| <ul class="space-y-4"> |
| <li class="group flex items-center gap-3 cursor-pointer"> |
| <div class="w-8 h-8 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-600 group-hover:border-emerald-500 group-hover:text-emerald-500 transition-all"><BookOpen class="w-4 h-4" /></div> |
| <span class="text-xs font-bold text-slate-500 group-hover:text-white transition-colors">Documentation</span> |
| </li> |
| <li class="group flex items-center gap-3 cursor-pointer"> |
| <div class="w-8 h-8 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-600 group-hover:border-blue-500 group-hover:text-blue-500 transition-all"><Terminal class="w-4 h-4" /></div> |
| <span class="text-xs font-bold text-slate-500 group-hover:text-white transition-colors">API Console</span> |
| </li> |
| <li class="group flex items-center gap-3 cursor-pointer"> |
| <div class="w-8 h-8 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-600 group-hover:border-rose-500 group-hover:text-rose-500 transition-all"><Shield class="w-4 h-4" /></div> |
| <span class="text-xs font-bold text-slate-500 group-hover:text-white transition-colors">Security Node</span> |
| </li> |
| </ul> |
| </div> |
| <div class="col-span-2 sm:col-span-1"> |
| <div class="bg-indigo-600/5 border border-indigo-500/20 rounded-2xl p-6 relative overflow-hidden group"> |
| <Sparkles class="w-16 h-16 text-indigo-500/5 absolute -right-2 -top-2" /> |
| <h4 class="text-[9px] font-black text-indigo-400 uppercase tracking-widest mb-4 flex items-center gap-2">Live Node Feed</h4> |
| <div class="space-y-3"> |
| <div v-for="(event, i) in globalEvents" :key="i" class="flex flex-col gap-1"> |
| <span class="text-[8px] font-black text-slate-700 uppercase tracking-widest">{{ event.t }}</span> |
| <p class="text-[10px] leading-tight font-bold" :class="event.c">{{ event.m }}</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| <div class="mt-20 pt-10 border-t border-slate-800/30 text-center"> |
| <p class="text-[9px] md:text-[10px] text-slate-600 mb-2 font-bold italic uppercase tracking-widest">Quantitative Risk Disclosure: For education only.</p> |
| <p class="text-[10px] text-slate-700 font-bold">© {{ new Date().getFullYear() }} k9t Intelligence Systems | Refactor Complete</p> |
| </div> |
| </footer> |
| |
| |
| <SearchModal :is-open="isSearchOpen" @close="isSearchOpen = false" @added="refreshWatchlist" @analyze="protectedOpenOptionsAnalysis" /> |
| <DataHubModal :is-open="isDataHubOpen" :initial-tab="dataHubTab" @close="isDataHubOpen = false" @universeUpdated="fetchWorkflowStats" /> |
| <AIBuilderClassic :is-open="isAIBuilderOpen" :initial-tab="classicBuilderTab" @close="isAIBuilderOpen = false" /> |
| <AIBuilderNeural :is-open="isAIBuilderNeuralOpen" @close="isAIBuilderNeuralOpen = false" /> |
| <OptionsAnalysisModal :is-open="isOptionsAnalysisOpen" :symbol="selectedSymbolForAnalysis" @close="isOptionsAnalysisOpen = false" /> |
| </div> |
| </template> |
| |
| <style> |
| body { background-color: #0b1120; margin: 0; padding: 0; } |
| ::-webkit-scrollbar { width: 6px; height: 6px; } |
| ::-webkit-scrollbar-track { background: transparent; } |
| ::-webkit-scrollbar-thumb { background: #1e293b; border-radius: 10px; } |
| ::-webkit-scrollbar-thumb:hover { background: #334155; } |
| </style> |
| |