Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Aditya writes here</title> | |
| <link href="https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap" rel="stylesheet"> | |
| <link id="code-theme-dark" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/tokyo-night-dark.min.css"> | |
| <link id="code-theme-light" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css" disabled> | |
| <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css"> | |
| <script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script> | |
| <script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/11.1.1/marked.min.js"></script> | |
| <style> | |
| :root { | |
| --bg-color: #1A1A1D; | |
| --text-color: #f3f2ec; | |
| --shadow-color: #f3f2ec; | |
| --snow-color: rgba(243, 242, 236, 0.5); | |
| } | |
| body.light-mode { | |
| --bg-color: #f3f2ec; | |
| --text-color: #1c1c1c; | |
| --shadow-color: #1c1c1c; | |
| --snow-color: rgba(28, 28, 28, 0.3); | |
| } | |
| * { margin: 0; padding: 0; box-sizing: border-box; } | |
| body { | |
| font-family: "Space Mono", monospace; | |
| background-color: var(--bg-color); | |
| color: var(--text-color); | |
| transition: background-color 0.4s ease, color 0.4s ease; | |
| line-height: 1.6; | |
| min-height: 100vh; | |
| overflow-x: hidden; | |
| } | |
| .katex, .katex * { font-family: "Space Mono", monospace ; } | |
| .katex-display { margin: 2.5rem 0 ; } | |
| #snowCanvas { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; } | |
| .container { max-width: 800px; margin: 0 auto; padding: 60px 24px; position: relative; } | |
| header { | |
| border-bottom: 1px solid var(--text-color); | |
| padding-bottom: 30px; | |
| margin-bottom: 50px; | |
| background: transparent; | |
| transition: border-color 0.4s ease; | |
| } | |
| h1 { font-size: 2.2rem; text-transform: uppercase; letter-spacing: -2px; } | |
| nav { display: flex; justify-content: space-between; align-items: center; margin-top: 20px; } | |
| .nav-links { display: flex; gap: 24px; } | |
| .nav-links a { | |
| color: var(--text-color); text-decoration: none; font-weight: 700; | |
| text-transform: uppercase; font-size: 0.9rem; border-bottom: 2px solid transparent; | |
| transition: color 0.4s ease; cursor: pointer; | |
| } | |
| .nav-links a:hover { opacity: 0.7; } | |
| .theme-toggle { | |
| background: none; border: 1px solid var(--text-color); color: var(--text-color); | |
| padding: 8px 16px; cursor: pointer; text-transform: uppercase; font-size: 0.75rem; | |
| font-family: inherit; font-weight: 700; transition: all 0.3s ease; | |
| } | |
| .theme-toggle:hover { background: var(--text-color); color: var(--bg-color); } | |
| .article-card, .link-card { | |
| border: 1px solid var(--text-color); padding: 32px; margin-bottom: 32px; | |
| cursor: pointer; transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.4s ease; | |
| background: transparent; backdrop-filter: blur(2px); text-decoration: none; display: block; color: inherit; | |
| } | |
| .article-card:hover, .link-card:hover { transform: translate(-4px, -4px); box-shadow: 6px 6px 0 var(--shadow-color); } | |
| .link-badge { | |
| display: inline-block; border: 1px solid var(--text-color); padding: 2px 8px; | |
| font-size: 0.7rem; text-transform: uppercase; margin-bottom: 10px; font-weight: 700; | |
| } | |
| /* --- Custom Code Block & Copy Button --- */ | |
| .code-wrapper { position: relative; margin: 24px 0; border: 1px solid var(--text-color); border-radius: 4px; transition: border-color 0.4s ease; } | |
| .code-header { | |
| display: flex; justify-content: space-between; align-items: center; | |
| background: rgba(150, 150, 150, 0.1); padding: 5px 15px; border-bottom: 1px solid var(--text-color); | |
| font-size: 0.75rem; font-family: "Space Mono", monospace; text-transform: uppercase; font-weight: 700; | |
| } | |
| .code-wrapper pre { margin: 0; border: none; border-radius: 0 0 4px 4px; padding: 24px; overflow-x: auto;} | |
| .light-mode .code-wrapper pre { background: #ffffff ; } | |
| body:not(.light-mode) .code-wrapper pre { background: #1a1b26 ; } | |
| code { font-family: "JetBrains Mono", monospace; font-size: 0.95rem; } | |
| .copy-btn { | |
| background: transparent; color: inherit; border: 1px solid var(--text-color); | |
| padding: 3px 10px; cursor: pointer; border-radius: 2px; font-size: 0.7rem; | |
| transition: all 0.2s; font-family: inherit; font-weight: 700; text-transform: uppercase; | |
| } | |
| .copy-btn:hover { background: var(--text-color); color: var(--bg-color); } | |
| /* --- Read Next Section --- */ | |
| .read-next-container { margin-top: 60px; border-top: 1px solid var(--text-color); padding-top: 40px; } | |
| .read-next-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 20px; } | |
| @media (max-width: 600px) { .read-next-grid { grid-template-columns: 1fr; } } | |
| .loading { text-align: center; padding: 50px; opacity: 0.6; text-transform: uppercase; } | |
| .back-btn { cursor: pointer; text-transform: uppercase; font-weight: 700; font-size: 0.8rem; margin-bottom: 40px; display: inline-block; } | |
| .markdown-body p { margin-bottom: 1.2rem; } | |
| .markdown-body h1 { font-size: 1.75rem; margin: 40px 0 20px; text-transform: uppercase; border-bottom: 1px solid var(--text-color); padding-bottom: 10px; } | |
| .markdown-body h2 { font-size: 1.35rem; margin: 35px 0 15px; text-transform: uppercase; border-bottom: 1px solid var(--text-color); padding-bottom: 10px; } | |
| .markdown-body h3 { font-size: 1.1rem; margin: 25px 0 10px; text-transform: uppercase; } | |
| .markdown-body ul, .markdown-body ol { padding-left: 24px; margin-bottom: 24px; margin-top: 8px; } | |
| .markdown-body li { margin-bottom: 12px; line-height: 1.6; } | |
| .markdown-body li > ul, .markdown-body li > ol { margin-top: 12px; margin-bottom: 0; } | |
| </style> | |
| </head> | |
| <body class="dark-mode"> | |
| <canvas id="snowCanvas"></canvas> | |
| <div class="container"> | |
| <header> | |
| <h1>Aditya</h1> | |
| <p style="opacity: 0.7; font-size: 0.9rem;">// AI RESEARCH & BACKEND</p> | |
| <nav> | |
| <div class="nav-links"> | |
| <a onclick="showView('listView')">/Articles</a> | |
| <a onclick="showView('libraryView')">/Library</a> | |
| <a href="https://adityaksingh.me" target="_blank">/Portfolio</a> | |
| </div> | |
| <button class="theme-toggle" id="themeToggle">Mode:Light</button> | |
| </nav> | |
| </header> | |
| <main id="app"> | |
| <div id="listView"> | |
| <div id="articleContainer" class="loading">Fetching_Data...</div> | |
| </div> | |
| <div id="libraryView" style="display: none;"> | |
| <h2 style="text-transform: uppercase; margin-bottom: 30px; font-size: 1.5rem; border-bottom: 1px solid var(--text-color); padding-bottom: 10px;">Resources_&_Links</h2> | |
| <div id="linkContainer" class="loading">Fetching_Library...</div> | |
| </div> | |
| <div id="singleView" style="display: none;"> | |
| <span class="back-btn" onclick="showView('listView')">← Return_to_List</span> | |
| <div id="articleContent" class="markdown-body"></div> | |
| </div> | |
| </main> | |
| </div> | |
| <script> | |
| const API = '/api'; | |
| const themeBtn = document.getElementById('themeToggle'); | |
| const darkStyle = document.getElementById('code-theme-dark'); | |
| const lightStyle = document.getElementById('code-theme-light'); | |
| let allArticles = []; // Global store for Read Next functionality | |
| function showView(viewId) { | |
| document.getElementById('listView').style.display = 'none'; | |
| document.getElementById('libraryView').style.display = 'none'; | |
| document.getElementById('singleView').style.display = 'none'; | |
| document.getElementById(viewId).style.display = 'block'; | |
| window.scrollTo(0, 0); | |
| if (viewId === 'libraryView' && document.getElementById('linkContainer').innerHTML.includes('Fetching')) { | |
| loadLinks(); | |
| } | |
| } | |
| // --- SNOWFALL --- | |
| const canvas = document.getElementById('snowCanvas'); | |
| const ctx = canvas.getContext('2d'); | |
| let particles = []; | |
| function resize() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } | |
| window.addEventListener('resize', resize); | |
| resize(); | |
| class Particle { | |
| constructor() { this.reset(); } | |
| reset() { | |
| this.x = Math.random() * canvas.width; this.y = Math.random() * canvas.height - canvas.height; | |
| this.size = Math.random() * 2 + 1; this.speed = Math.random() * 0.8 + 0.5; this.velX = Math.random() * 0.5 - 0.25; | |
| } | |
| update() { this.y += this.speed; this.x += this.velX; if (this.y > canvas.height) this.reset(); } | |
| draw() { | |
| ctx.fillStyle = getComputedStyle(document.body).getPropertyValue('--snow-color'); | |
| ctx.beginPath(); ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); ctx.fill(); | |
| } | |
| } | |
| function initSnow() { particles = []; for (let i = 0; i < 120; i++) particles.push(new Particle()); } | |
| function animate() { | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| particles.forEach(p => { p.update(); p.draw(); }); requestAnimationFrame(animate); | |
| } | |
| initSnow(); animate(); | |
| // --- THEME SWAPPER --- | |
| function setTheme(mode) { | |
| if (mode === 'light') { | |
| document.body.classList.add('light-mode'); themeBtn.textContent = 'Mode:Dark'; | |
| darkStyle.disabled = true; lightStyle.disabled = false; | |
| } else { | |
| document.body.classList.remove('light-mode'); themeBtn.textContent = 'Mode:Light'; | |
| darkStyle.disabled = false; lightStyle.disabled = true; | |
| } | |
| localStorage.setItem('theme', mode); | |
| } | |
| themeBtn.onclick = () => { setTheme(document.body.classList.contains('light-mode') ? 'dark' : 'light'); }; | |
| setTheme(localStorage.getItem('theme') || 'dark'); | |
| // --- DATA FETCHING (ARTICLES) --- | |
| async function loadArticles() { | |
| const container = document.getElementById('articleContainer'); | |
| try { | |
| const res = await fetch(`${API}/articles`); | |
| allArticles = await res.json(); | |
| container.innerHTML = allArticles.map(a => ` | |
| <div class="article-card" onclick="loadSingle('${a.slug}')"> | |
| <div style="font-size:0.8rem; opacity:0.6;">${new Date(a.created_at).toLocaleDateString()}</div> | |
| <h2>${a.title}</h2> | |
| <p style="opacity:0.7; margin-top:10px;">${a.excerpt || 'Read execution logs...'}</p> | |
| </div> | |
| `).join(''); | |
| } catch { container.innerHTML = "✗ ERROR_LOADING_STREAM"; } | |
| } | |
| async function loadSingle(slug) { | |
| showView('singleView'); | |
| const content = document.getElementById('articleContent'); | |
| try { | |
| const res = await fetch(`${API}/articles/${encodeURIComponent(slug)}`); | |
| const a = await res.json(); | |
| // 1. Calculate Estimated Reading Time | |
| const wordCount = a.content.trim().split(/\s+/).length; | |
| const readTime = Math.ceil(wordCount / 200) || 1; | |
| const tagHTML = a.tags && a.tags.length ? `<span>•</span><span style="opacity:0.8;">[${a.tags.join(', ')}]</span>` : ''; | |
| // Handle Math & Markdown Parsing | |
| let processedContent = a.content | |
| .replace(/\\\(/g, '$').replace(/\\\)/g, '$') | |
| .replace(/\\\[/g, '$$$$').replace(/\\\]/g, '$$$$'); | |
| const mathDict = {}; let mathIndex = 0; | |
| processedContent = processedContent.replace(/\$\$(.*?)\$\$/gs, (match) => { | |
| const token = `MATHBLOCKTOKEN${mathIndex}XYZ`; mathDict[token] = match; mathIndex++; return token; | |
| }); | |
| processedContent = processedContent.replace(/\$(.*?)\$/g, (match) => { | |
| const token = `MATHBLOCKTOKEN${mathIndex}XYZ`; mathDict[token] = match; mathIndex++; return token; | |
| }); | |
| let htmlContent = marked.parse(processedContent); | |
| for (const [token, mathStr] of Object.entries(mathDict)) { htmlContent = htmlContent.replace(token, mathStr); } | |
| // Build HTML Structure | |
| content.innerHTML = ` | |
| <div style="font-size:0.8rem; opacity:0.6; margin-bottom:10px; display:flex; gap:10px; flex-wrap: wrap; align-items: center;"> | |
| <span>${new Date(a.created_at).toLocaleDateString()}</span> | |
| <span>•</span> | |
| <span>${readTime} min read</span> | |
| ${tagHTML} | |
| </div> | |
| <h1 style="text-transform: uppercase; margin-bottom: 20px;">${a.title}</h1> | |
| <div>${htmlContent}</div> | |
| `; | |
| renderMathInElement(content, { | |
| delimiters: [{left: '$$', right: '$$', display: true}, {left: '$', right: '$', display: false}], | |
| throwOnError: false | |
| }); | |
| // 2. Inject Code Copy Buttons | |
| content.querySelectorAll('pre').forEach(pre => { | |
| const codeEl = pre.querySelector('code'); | |
| if(codeEl) hljs.highlightElement(codeEl); | |
| const wrapper = document.createElement('div'); | |
| wrapper.className = 'code-wrapper'; | |
| pre.parentNode.insertBefore(wrapper, pre); | |
| const header = document.createElement('div'); | |
| header.className = 'code-header'; | |
| const langClass = (codeEl && codeEl.className.match(/language-(\w+)/)) || []; | |
| const lang = langClass[1] || 'code'; | |
| header.innerHTML = `<span>${lang}</span><button class="copy-btn">COPY</button>`; | |
| wrapper.appendChild(header); | |
| wrapper.appendChild(pre); | |
| const copyBtn = header.querySelector('.copy-btn'); | |
| copyBtn.addEventListener('click', () => { | |
| navigator.clipboard.writeText(pre.innerText).then(() => { | |
| copyBtn.innerText = 'COPIED!'; | |
| setTimeout(() => copyBtn.innerText = 'COPY', 2000); | |
| }); | |
| }); | |
| }); | |
| // 3. Render "Read Next" Section based on Tags | |
| let related = allArticles.filter(art => art.id !== a.id); | |
| if (a.tags && a.tags.length > 0) { | |
| related.sort((x, y) => { | |
| const xScore = (x.tags || []).filter(t => a.tags.includes(t)).length; | |
| const yScore = (y.tags || []).filter(t => a.tags.includes(t)).length; | |
| return yScore - xScore; | |
| }); | |
| } | |
| const readNextArticles = related.slice(0, 2); | |
| if (readNextArticles.length > 0) { | |
| const readNextHTML = ` | |
| <div class="read-next-container"> | |
| <h3 style="text-transform: uppercase; font-size: 1.2rem; margin-bottom: 20px;">Read_Next</h3> | |
| <div class="read-next-grid"> | |
| ${readNextArticles.map(r => ` | |
| <div class="article-card" style="margin-bottom: 0;" onclick="loadSingle('${r.slug}')"> | |
| <h4 style="margin-bottom: 10px; font-size: 1.1rem;">${r.title}</h4> | |
| <p style="font-size: 0.8rem; opacity: 0.7;">${r.excerpt || 'Read execution logs...'}</p> | |
| </div> | |
| `).join('')} | |
| </div> | |
| </div> | |
| `; | |
| content.insertAdjacentHTML('beforeend', readNextHTML); | |
| } | |
| } catch { content.innerHTML = "✗ ERROR_DECODING_FAILED"; } | |
| } | |
| // --- DATA FETCHING (LINKS) --- | |
| async function loadLinks() { | |
| const container = document.getElementById('linkContainer'); | |
| try { | |
| const res = await fetch(`${API}/links`); | |
| const data = await res.json(); | |
| if (data.length === 0) { | |
| container.innerHTML = "NO_RECORDS_FOUND"; | |
| return; | |
| } | |
| container.innerHTML = data.map(l => ` | |
| <a href="${l.url}" target="_blank" class="link-card"> | |
| <span class="link-badge">${l.category}</span> | |
| <h2 style="font-size: 1.2rem; margin-bottom: 5px;">${l.title}</h2> | |
| ${l.description ? `<p style="opacity:0.7; font-size: 0.9rem;">${l.description}</p>` : ''} | |
| <div style="font-size:0.7rem; opacity:0.5; margin-top:15px; text-transform: lowercase;">↗ ${new URL(l.url).hostname}</div> | |
| </a> | |
| `).join(''); | |
| } catch { container.innerHTML = "✗ ERROR_LOADING_LIBRARY"; } | |
| } | |
| loadArticles(); | |
| </script> | |
| </body> | |
| </html> |