intoai / static /index.html
hello-aditya's picture
Update static/index.html
3f757e8 verified
Raw
History Blame Contribute Delete
18.8 kB
<!DOCTYPE html>
<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 !important; }
.katex-display { margin: 2.5rem 0 !important; }
#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 !important; }
body:not(.light-mode) .code-wrapper pre { background: #1a1b26 !important; }
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>