Subhadip007 commited on
Commit
185ecb0
·
1 Parent(s): 5d26dc5

feat(ui): complete UI overhaul with smooth animations, glowing elements, and refined citation rendering

Browse files
frontend-next/app/globals.css CHANGED
@@ -929,8 +929,9 @@ select {
929
 
930
  /* -- UI Redesign -- */
931
  .layout-wrapper { display: flex; height: 100vh; width: 100vw; overflow: hidden; }
932
- .sidebar { width: 260px; background: rgba(5, 7, 10, 0.95); border-right: 1px solid var(--border); display: flex; flex-direction: column; overflow-y: auto; padding: 10px; z-index: 100; flex-shrink: 0; transition: transform 0.3s ease; }
933
- @media (max-width: 768px) { .sidebar { position: fixed; height: 100vh; transform: translateX(-100%); } .sidebar.open { transform: translateX(0); } }
 
934
  .sidebar-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 90; }
935
  .new-chat-btn { display: flex; align-items: center; gap: 10px; width: 100%; padding: 12px; border-radius: 8px; background: rgba(255,255,255,0.05); color: #fff; font-weight: 500; font-size: 0.9rem; margin-bottom: 20px; transition: 0.2s; border: 1px solid rgba(255,255,255,0.1); }
936
  .new-chat-btn:hover { background: rgba(255,255,255,0.1); border-color: rgba(255,255,255,0.2); }
 
929
 
930
  /* -- UI Redesign -- */
931
  .layout-wrapper { display: flex; height: 100vh; width: 100vw; overflow: hidden; }
932
+ .sidebar { width: 260px; background: rgba(5, 7, 10, 0.95); border-right: 1px solid var(--border); display: flex; flex-direction: column; overflow-y: auto; padding: 10px; z-index: 100; flex-shrink: 0; transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1), transform 0.3s ease, padding 0.3s ease, margin 0.3s ease; white-space: nowrap; overflow-x: hidden; }
933
+ .sidebar.collapsed { width: 0 !important; padding: 0 !important; border: none; opacity: 0; margin-left: -1px; }
934
+ @media (max-width: 768px) { .sidebar { position: fixed; height: 100vh; transform: translateX(-100%); width: 260px !important; opacity: 1 !important; padding: 10px !important; } .sidebar.open { transform: translateX(0); } }
935
  .sidebar-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 90; }
936
  .new-chat-btn { display: flex; align-items: center; gap: 10px; width: 100%; padding: 12px; border-radius: 8px; background: rgba(255,255,255,0.05); color: #fff; font-weight: 500; font-size: 0.9rem; margin-bottom: 20px; transition: 0.2s; border: 1px solid rgba(255,255,255,0.1); }
937
  .new-chat-btn:hover { background: rgba(255,255,255,0.1); border-color: rgba(255,255,255,0.2); }
frontend-next/app/page.tsx CHANGED
@@ -134,8 +134,8 @@ const MessageRenderer = ({ content, isStreaming }: { content: string, isStreamin
134
  );
135
  }
136
 
137
- // Match any Arxiv format number (YYYY.NNNNN) regardless of brackets or commas, and convert to Markdown link
138
- let processedContent = displayed.replace(/\b(\d{4}\.\d{4,5})\b/g, '[$1](CITATION:$1)');
139
 
140
  // Force $$ block math onto separate lines so remarkMath parses it tightly as centered block math
141
  processedContent = processedContent.replace(/\$\$([\s\S]*?)\$\$/g, '\n\n$$\n$1\n$$\n\n');
@@ -238,8 +238,6 @@ export default function App() {
238
  const [category, setCategory] = useState("All");
239
  const [filterYear, setFilterYear] = useState("All");
240
  const [apiStatus, setApiStatus] = useState<"connecting" | "online" | "offline">("connecting");
241
-
242
- // UI Enhancements
243
  const [desktopSidebarCollapsed, setDesktopSidebarCollapsed] = useState(false);
244
  const [showScrollDown, setShowScrollDown] = useState(false);
245
  const [showInfo, setShowInfo] = useState(false);
@@ -366,7 +364,8 @@ export default function App() {
366
  id: aiMessageId,
367
  role: "assistant",
368
  content: "",
369
- timestamp: Date.now() + 1
 
370
  };
371
 
372
  setSessions(prev => prev.map(s => {
@@ -542,8 +541,9 @@ export default function App() {
542
  </div>
543
 
544
  <div className="sidebar-footer">
545
- <a href="https://github.com/07subhadip" target="_blank" rel="noopener noreferrer" className="github-link">
546
- <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round" className="lucide lucide-github"><path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"/><path d="M9 18c-4.51 2-5-2-7-2"/></svg> @07subhadip
 
547
  </a>
548
  </div>
549
  </div>
@@ -593,14 +593,25 @@ export default function App() {
593
 
594
  <AnimatePresence>
595
  {showInfo && (
596
- <div className="info-modal-backdrop" onClick={() => setShowInfo(false)} style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.6)', zIndex: 100, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
597
  <motion.div
598
- initial={{ opacity: 0, scale: 0.95, y: 20 }}
599
  animate={{ opacity: 1, scale: 1, y: 0 }}
600
- exit={{ opacity: 0, scale: 0.95, y: 20 }}
601
  onClick={(e) => e.stopPropagation()}
602
  className="cyber-panel info-modal"
603
- style={{ background: 'var(--bg-panel)', border: '1px solid var(--border)', padding: '32px', borderRadius: '16px', maxWidth: '600px', width: '90%', position: 'relative', maxHeight: '80vh', overflowY: 'auto' }}
 
 
 
 
 
 
 
 
 
 
 
604
  >
605
  <button className="modal-close" onClick={() => setShowInfo(false)} style={{ position: 'absolute', top: '16px', right: '16px', background: 'transparent', border: 'none', color: 'var(--text-muted)', cursor: 'pointer' }}>
606
  <X size={18} />
@@ -625,7 +636,8 @@ export default function App() {
625
  <li style={{ marginBottom: '8px' }}><strong>Frontend Application</strong> Next.js 16 (App Router), React, Framer Motion, Vanilla CSS.</li>
626
  <li style={{ marginBottom: '8px' }}><strong>Backend Environment</strong> Python, FastAPI, Uvicorn, Pydantic.</li>
627
  <li style={{ marginBottom: '8px' }}><strong>Vector Database Engine</strong> Qdrant (GPU Accelerated Dense Vectors).</li>
628
- <li style={{ marginBottom: '8px' }}><strong>RAG Processing Pipeline</strong> SentenceTransformers (BGE-base), BM25 Sparse Search, Cross-Encoder Reranking, Groq LLM (LLaMA 3.3).</li>
 
629
  <li><strong>Mathematics Engine</strong> KaTeX & React-Markdown for fully dynamic native LaTeX equations.</li>
630
  </ul>
631
  <h3><Rocket size={18} style={{ display: 'inline', verticalAlign: 'middle', marginRight: '8px' }} /> Phase 2: In-Progress Architecture</h3>
@@ -661,8 +673,12 @@ export default function App() {
661
  ) : (
662
  <div style={{ width: '100%' }}>
663
  {/* Name header for AI */}
664
- <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '12px', fontSize: '0.9rem', color: 'var(--accent)', fontWeight: 600 }}>
665
- <div className="ai-avatar"><Brain size={16} /></div> ResearchPilot {msg.model_used && <span className="model-badge">{msg.model_used}</span>}
 
 
 
 
666
  </div>
667
 
668
  <>
@@ -705,39 +721,65 @@ export default function App() {
705
  </div>
706
 
707
  {/* Bottom Input Area */}
708
- <div className="bottom-input-bar">
 
 
 
 
709
  <div className="bottom-input-bar-inner">
710
  {/* Settings Popup inline */}
711
  <AnimatePresence>
712
  {settingsOpen && (
713
  <motion.div
714
- initial={{ opacity: 0, y: 10 }}
715
- animate={{ opacity: 1, y: 0 }}
716
- exit={{ opacity: 0, y: 10 }}
717
- style={{ background: 'rgba(20,25,35,0.95)', border: '1px solid rgba(255,255,255,0.1)', padding: '12px', borderRadius: '12px', display: 'flex', gap: '12px', flexWrap: 'wrap', marginBottom: '8px' }}
 
 
 
 
 
 
 
 
 
 
 
718
  >
719
- <select style={{ background: '#000', border: '1px solid #333', color: '#fff', padding: '6px 12px', borderRadius: '6px' }} value={topK} onChange={(e) => setTopK(Number(e.target.value))}>
720
- <option value={3}>Top 3</option>
721
- <option value={5}>Top 5</option>
722
- <option value={10}>Top 10</option>
723
- </select>
724
- <select style={{ background: '#000', border: '1px solid #333', color: '#fff', padding: '6px 12px', borderRadius: '6px' }} value={category} onChange={(e) => setCategory(e.target.value)}>
725
- <option value="All">All Topics</option>
726
- <option value="cs.LG">cs.LG (Machine Learning)</option>
727
- <option value="cs.AI">cs.AI (Artificial Intelligence)</option>
728
- <option value="stat.ML">stat.ML (Machine Learning Stats)</option>
729
- <option value="cs.CL">cs.CL (Computation & Language)</option>
730
- <option value="cs.CV">cs.CV (Computer Vision)</option>
731
- <option value="cs.RO">cs.RO (Robotics)</option>
732
- </select>
733
- <select style={{ background: '#000', border: '1px solid #333', color: '#fff', padding: '6px 12px', borderRadius: '6px' }} value={filterYear} onChange={(e) => setFilterYear(e.target.value)}>
734
- <option value="All">All Years</option>
735
- <option value="2024">2024 & Newer</option>
736
- <option value="2023">2023 & Newer</option>
737
- <option value="2022">2022 & Newer</option>
738
- <option value="2021">2021 & Newer</option>
739
- <option value="2020">2020 & Newer</option>
740
- </select>
 
 
 
 
 
 
 
 
 
 
 
741
  </motion.div>
742
  )}
743
  </AnimatePresence>
 
134
  );
135
  }
136
 
137
+ // Match any Arxiv format number (YYYY.NNNNN) regardless of brackets or commas, and convert to Markdown link. We eat the surrounding brackets to preserve design.
138
+ let processedContent = displayed.replace(/\[?\s*\b(\d{4}\.\d{4,5})\b\s*\]?/g, '[$1](CITATION:$1)');
139
 
140
  // Force $$ block math onto separate lines so remarkMath parses it tightly as centered block math
141
  processedContent = processedContent.replace(/\$\$([\s\S]*?)\$\$/g, '\n\n$$\n$1\n$$\n\n');
 
238
  const [category, setCategory] = useState("All");
239
  const [filterYear, setFilterYear] = useState("All");
240
  const [apiStatus, setApiStatus] = useState<"connecting" | "online" | "offline">("connecting");
 
 
241
  const [desktopSidebarCollapsed, setDesktopSidebarCollapsed] = useState(false);
242
  const [showScrollDown, setShowScrollDown] = useState(false);
243
  const [showInfo, setShowInfo] = useState(false);
 
364
  id: aiMessageId,
365
  role: "assistant",
366
  content: "",
367
+ timestamp: Date.now() + 1,
368
+ model_used: "Auto-Detecting..."
369
  };
370
 
371
  setSessions(prev => prev.map(s => {
 
541
  </div>
542
 
543
  <div className="sidebar-footer">
544
+ <a href="https://github.com/07subhadip" target="_blank" rel="noopener noreferrer" className="github-link" style={{ display: 'flex', alignItems: 'center', gap: '10px', color: 'var(--accent)', textDecoration: 'none', fontSize: '0.9rem', padding: '12px', borderRadius: '8px', transition: '0.3s', background: 'rgba(0, 240, 255, 0.1)', border: '1px solid rgba(0, 240, 255, 0.3)', boxShadow: '0 0 15px rgba(0, 240, 255, 0.2)' }} onMouseOver={e => e.currentTarget.style.boxShadow = '0 0 25px rgba(0, 240, 255, 0.6)'} onMouseOut={e => e.currentTarget.style.boxShadow = '0 0 15px rgba(0, 240, 255, 0.2)'}>
545
+ <svg viewBox="0 0 24 24" width="18" height="18" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round" className="lucide lucide-github"><path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"/><path d="M9 18c-4.51 2-5-2-7-2"/></svg>
546
+ <span style={{ fontWeight: 600, letterSpacing: '0.05em' }}>@07subhadip</span>
547
  </a>
548
  </div>
549
  </div>
 
593
 
594
  <AnimatePresence>
595
  {showInfo && (
596
+ <div className="info-modal-backdrop" onClick={() => setShowInfo(false)} style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.8)', backdropFilter: 'blur(8px)', zIndex: 1000, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
597
  <motion.div
598
+ initial={{ opacity: 0, scale: 0.95, y: 30 }}
599
  animate={{ opacity: 1, scale: 1, y: 0 }}
600
+ exit={{ opacity: 0, scale: 0.95, y: 30 }}
601
  onClick={(e) => e.stopPropagation()}
602
  className="cyber-panel info-modal"
603
+ style={{
604
+ background: 'linear-gradient(135deg, rgba(20, 25, 40, 0.95), rgba(10, 15, 25, 0.98))',
605
+ border: '1px solid rgba(0, 240, 255, 0.3)',
606
+ padding: '40px',
607
+ borderRadius: '24px',
608
+ maxWidth: '650px',
609
+ width: '90%',
610
+ position: 'relative',
611
+ maxHeight: '85vh',
612
+ overflowY: 'auto',
613
+ boxShadow: '0 20px 50px rgba(0, 0, 0, 0.9), 0 0 40px rgba(0, 240, 255, 0.1)'
614
+ }}
615
  >
616
  <button className="modal-close" onClick={() => setShowInfo(false)} style={{ position: 'absolute', top: '16px', right: '16px', background: 'transparent', border: 'none', color: 'var(--text-muted)', cursor: 'pointer' }}>
617
  <X size={18} />
 
636
  <li style={{ marginBottom: '8px' }}><strong>Frontend Application</strong> Next.js 16 (App Router), React, Framer Motion, Vanilla CSS.</li>
637
  <li style={{ marginBottom: '8px' }}><strong>Backend Environment</strong> Python, FastAPI, Uvicorn, Pydantic.</li>
638
  <li style={{ marginBottom: '8px' }}><strong>Vector Database Engine</strong> Qdrant (GPU Accelerated Dense Vectors).</li>
639
+ <li style={{ marginBottom: '8px' }}><strong>RAG Processing Pipeline</strong> SentenceTransformers (BGE-base-en-v1.5), BM25 Sparse Search, Cross-Encoder Reranking.</li>
640
+ <li style={{ marginBottom: '8px' }}><strong>Multi-Modal LLM Fabric</strong> Dynamic routing between Qwen 2.5 72B (Primary), LLaMA 3.3 70B (Fallback), and Qwen 2.5 Coder 7B (Code).</li>
641
  <li><strong>Mathematics Engine</strong> KaTeX & React-Markdown for fully dynamic native LaTeX equations.</li>
642
  </ul>
643
  <h3><Rocket size={18} style={{ display: 'inline', verticalAlign: 'middle', marginRight: '8px' }} /> Phase 2: In-Progress Architecture</h3>
 
673
  ) : (
674
  <div style={{ width: '100%' }}>
675
  {/* Name header for AI */}
676
+ <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '12px', fontSize: '0.85rem', color: 'var(--accent)', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.05em' }}>
677
+ <div className="ai-avatar" style={{ background: 'rgba(0, 240, 255, 0.1)', border: '1px solid rgba(0, 240, 255, 0.3)', padding: '6px', borderRadius: '8px' }}><Brain size={14} /></div>
678
+ ResearchPilot
679
+ <span className="model-badge" style={{ background: 'rgba(255,255,255,0.05)', padding: '2px 8px', borderRadius: '4px', border: '1px solid rgba(255,255,255,0.1)', color: 'var(--text-muted)', fontSize: '0.75rem' }}>
680
+ {msg.model_used || "Auto-Detecting..."}
681
+ </span>
682
  </div>
683
 
684
  <>
 
721
  </div>
722
 
723
  {/* Bottom Input Area */}
724
+ <div className="bottom-input-bar" style={{
725
+ left: desktopSidebarCollapsed ? '0' : '260px',
726
+ transition: 'left 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
727
+ width: 'auto'
728
+ }}>
729
  <div className="bottom-input-bar-inner">
730
  {/* Settings Popup inline */}
731
  <AnimatePresence>
732
  {settingsOpen && (
733
  <motion.div
734
+ initial={{ opacity: 0, y: 15, scale: 0.95 }}
735
+ animate={{ opacity: 1, y: 0, scale: 1 }}
736
+ exit={{ opacity: 0, y: 15, scale: 0.95 }}
737
+ style={{
738
+ background: 'rgba(15, 20, 30, 0.95)',
739
+ backdropFilter: 'blur(20px)',
740
+ border: '1px solid rgba(0, 240, 255, 0.2)',
741
+ padding: '16px',
742
+ borderRadius: '16px',
743
+ display: 'flex',
744
+ gap: '16px',
745
+ flexWrap: 'wrap',
746
+ marginBottom: '12px',
747
+ boxShadow: '0 10px 40px rgba(0,0,0,0.5)'
748
+ }}
749
  >
750
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>
751
+ <label style={{ fontSize: '0.7rem', color: 'var(--text-muted)', fontWeight: 700, marginLeft: '4px' }}>RETRIEVAL DEPTH</label>
752
+ <select style={{ background: 'rgba(0,0,0,0.4)', border: '1px solid rgba(255,255,255,0.1)', color: '#fff', padding: '8px 12px', borderRadius: '8px', cursor: 'pointer', outline: 'none', minWidth: '100px' }} value={topK} onChange={(e) => setTopK(Number(e.target.value))}>
753
+ <option value={3}>Fast (3 Papers)</option>
754
+ <option value={5}>Balanced (5 Papers)</option>
755
+ <option value={10}>Deep (10 Papers)</option>
756
+ </select>
757
+ </div>
758
+
759
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>
760
+ <label style={{ fontSize: '0.7rem', color: 'var(--text-muted)', fontWeight: 700, marginLeft: '4px' }}>RESEARCH DOMAIN</label>
761
+ <select style={{ background: 'rgba(0,0,0,0.4)', border: '1px solid rgba(255,255,255,0.1)', color: '#fff', padding: '8px 12px', borderRadius: '8px', cursor: 'pointer', outline: 'none' }} value={category} onChange={(e) => setCategory(e.target.value)}>
762
+ <option value="All">Global Search</option>
763
+ <option value="cs.LG">cs.LG (Machine Learning)</option>
764
+ <option value="cs.AI">cs.AI (Artificial Intelligence)</option>
765
+ <option value="stat.ML">stat.ML (ML Stats)</option>
766
+ <option value="cs.CL">cs.CL (NLP/Language)</option>
767
+ <option value="cs.CV">cs.CV (Vision)</option>
768
+ <option value="cs.RO">cs.RO (Robotics)</option>
769
+ </select>
770
+ </div>
771
+
772
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>
773
+ <label style={{ fontSize: '0.7rem', color: 'var(--text-muted)', fontWeight: 700, marginLeft: '4px' }}>RECENCY FILTER</label>
774
+ <select style={{ background: 'rgba(0,0,0,0.4)', border: '1px solid rgba(255,255,255,0.1)', color: '#fff', padding: '8px 12px', borderRadius: '8px', cursor: 'pointer', outline: 'none' }} value={filterYear} onChange={(e) => setFilterYear(e.target.value)}>
775
+ <option value="All">Legacy & Modern</option>
776
+ <option value="2024">2024 (Latest)</option>
777
+ <option value="2023">2023+</option>
778
+ <option value="2022">2022+</option>
779
+ <option value="2021">2021+</option>
780
+ <option value="2020">2020+</option>
781
+ </select>
782
+ </div>
783
  </motion.div>
784
  )}
785
  </AnimatePresence>