Skip to content

Commit 7a6677a

Browse files
Enhance article modal and card interactions
Added article modal functionality and improved article card interactions.
1 parent f5d6dd4 commit 7a6677a

File tree

1 file changed

+133
-38
lines changed

1 file changed

+133
-38
lines changed

index.html

Lines changed: 133 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,38 @@
33
<head>
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width,initial-scale=1">
6-
<title>Code By Sushil</title>
6+
<title>Code By Sushil | Articles</title>
77

88
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&display=swap" rel="stylesheet">
9+
<link href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css" rel="stylesheet">
10+
911
<style>
1012
body{margin:0;font-family:'Inter',sans-serif;background:#0f1720;color:#e6eef8;line-height:1.6;}
1113
.wrap{max-width:1000px;margin:32px auto;padding:20px;}
1214
h1{text-align:center;margin-bottom:32px;}
1315
.articles-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:20px;}
14-
.article-card{background:rgba(255,255,255,0.02);border-radius:14px;padding:20px;border:1px solid rgba(255,255,255,0.03);transition:0.2s;}
16+
.article-card{background:rgba(255,255,255,0.02);border-radius:14px;padding:20px;border:1px solid rgba(255,255,255,0.03);cursor:pointer;transition:0.2s;}
1517
.article-card:hover{transform:translateY(-4px);box-shadow:0 12px 24px rgba(0,0,0,0.3);}
1618
.article-card h2{margin-top:0;color:#7c5cff;}
1719
.article-card p{color:#9aa4b2;}
1820
.article-card .meta{font-size:0.85rem;color:#9aa4b2;margin-top:10px;}
1921
.article-card .tags{margin-top:8px;font-size:0.8rem;color:#7c5cff;}
20-
.article-card a{text-decoration:none;color:inherit;}
22+
23+
/* Modal */
24+
#article-modal{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(15,23,32,0.95);color:#e6eef8;overflow:auto;display:none;flex-direction:column;padding:20px;z-index:999;}
25+
#article-modal .close{align-self:flex-end;font-size:28px;cursor:pointer;margin-bottom:12px;}
26+
#article-modal h1{margin-top:0;}
27+
#article-modal .article-meta{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:16px;color:#9aa4b2;font-size:0.9rem;}
28+
#article-modal img.cover{max-width:100%;border-radius:12px;margin:16px 0;}
29+
.article-body h1,h2,h3,h4,h5,h6{color:#e6eef8;margin-top:1.2rem;margin-bottom:0.6rem;}
30+
.article-body p{margin:0.6rem 0;}
31+
.article-body a{color:#7c5cff;}
32+
.article-body pre{background:#1e293b;padding:12px;border-radius:8px;overflow:auto;}
33+
34+
/* Navigation buttons */
35+
.nav-buttons{display:flex;justify-content:space-between;margin-top:12px;}
36+
.nav-buttons button{background:#7c5cff;color:#fff;border:none;padding:8px 16px;border-radius:8px;cursor:pointer;transition:0.2s;}
37+
.nav-buttons button:hover{background:#5a3edc;}
2138
</style>
2239
</head>
2340
<body>
@@ -26,7 +43,35 @@ <h1>Articles</h1>
2643
<div class="articles-grid" id="articles-grid"></div>
2744
</div>
2845

46+
<!-- Article Modal -->
47+
<div id="article-modal">
48+
<span class="close" id="modal-close">&times;</span>
49+
<h1 id="modal-title"></h1>
50+
<div class="article-meta">
51+
<span id="modal-author"></span>
52+
<span id="modal-date"></span>
53+
<span id="modal-readtime"></span>
54+
<span id="modal-tags"></span>
55+
<span id="modal-views"></span>
56+
</div>
57+
<img id="modal-cover" class="cover" src="" alt="Cover" style="display:none;">
58+
<div id="article-content" class="article-body"></div>
59+
<div class="nav-buttons">
60+
<button id="prev-article">← Previous</button>
61+
<button id="next-article">Next →</button>
62+
</div>
63+
</div>
64+
65+
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
66+
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.min.js"></script>
67+
2968
<script>
69+
// --- GitHub Config ---
70+
const GITHUB_USER = 'codebysushil';
71+
const GITHUB_REPO = "codebysushil.github.io";
72+
const ARTICLES_PATH = 'articles';
73+
const BRANCH = 'main';
74+
3075
// --- Helpers ---
3176
function parseFrontMatter(md){
3277
const fmRegex=/^---\s*([\s\S]*?)\s*---\s*/;
@@ -43,53 +88,103 @@ <h1>Articles</h1>
4388
return {fm, content};
4489
}
4590
function formatDate(iso){try{const d=new Date(iso);return isNaN(d)?iso:d.toLocaleDateString(undefined,{year:'numeric',month:'short',day:'numeric'});}catch(e){return iso}}
91+
function estimateReadTime(text){const words=text.trim().split(/\s+/).length;return Math.max(1,Math.round(words/200))+' min read'}
92+
async function incAndGetViews(key){
93+
try{
94+
const res=await fetch(`https://api.countapi.xyz/hit/${GITHUB_USER}-${GITHUB_REPO}/${key}`);
95+
const json=await res.json();
96+
return json.value||0;
97+
}catch(e){return '—'}
98+
}
99+
100+
// --- DOM Elements ---
101+
const grid=document.getElementById('articles-grid');
102+
const modal=document.getElementById('article-modal');
103+
const modalClose=document.getElementById('modal-close');
104+
const modalTitle=document.getElementById('modal-title');
105+
const modalAuthor=document.getElementById('modal-author');
106+
const modalDate=document.getElementById('modal-date');
107+
const modalReadtime=document.getElementById('modal-readtime');
108+
const modalTags=document.getElementById('modal-tags');
109+
const modalViews=document.getElementById('modal-views');
110+
const modalCover=document.getElementById('modal-cover');
111+
const articleContent=document.getElementById('article-content');
112+
const prevBtn=document.getElementById('prev-article');
113+
const nextBtn=document.getElementById('next-article');
46114

47-
// --- Config ---
48-
const GITHUB_USER='codebysushil'; // your GitHub username
49-
const GITHUB_REPO="codebysushil.github.io"; // your repository name
50-
const ARTICLES_PATH='articles'; // folder containing markdown files
51-
const BRANCH='main'; // default branch
115+
let articlesData=[]; // store all articles
116+
let currentIndex=0; // current article in modal
52117

118+
// --- Load articles dynamically ---
53119
(async function(){
54-
const grid=document.getElementById('articles-grid');
55120
try{
56-
// GitHub API: list files in articles folder
57-
const apiUrl=`https://api.github.com/repos/${GITHUB_USER}/${GITHUB_REPO}/contents/${ARTICLES_PATH}?ref=${BRANCH}`;
58-
const res=await fetch(apiUrl);
59-
if(!res.ok) throw new Error('Failed to fetch repo files');
60-
const files=await res.json();
61-
const mdFiles=files.filter(f=>f.name.endsWith('.md'));
62-
121+
const apiUrl = `https://api.github.com/repos/${GITHUB_USER}/${GITHUB_REPO}/contents/${ARTICLES_PATH}?ref=${BRANCH}`;
122+
const res = await fetch(apiUrl);
123+
if(!res.ok) throw new Error('Failed to fetch articles list');
124+
const files = await res.json();
125+
const mdFiles = files.filter(f=>f.name.endsWith('.md'));
126+
63127
for(const file of mdFiles){
64128
try{
65-
const rawUrl=file.download_url; // direct raw URL
66-
const resp=await fetch(rawUrl);
129+
const rawUrl = file.download_url;
130+
const resp = await fetch(rawUrl);
67131
if(!resp.ok) continue;
68-
const mdText=await resp.text();
69-
const {fm}=parseFrontMatter(mdText);
70-
const title=fm.title||file.name;
71-
const description=fm.description||'';
72-
const author=fm.author||'Unknown';
73-
const date=fm.date?formatDate(fm.date):'';
74-
const tags=fm.tags||'';
75-
76-
const card=document.createElement('a');
77-
card.href=`pages/article.html?file=${file.name}`;
78-
card.className='article-card';
132+
const mdText = await resp.text();
133+
const {fm, content} = parseFrontMatter(mdText);
134+
135+
const article = {
136+
fileName: file.name,
137+
title: fm.title||file.name,
138+
description: fm.description||'',
139+
author: fm.author||'Unknown',
140+
date: fm.date?formatDate(fm.date):'',
141+
tags: fm.tags||'',
142+
cover: fm.cover||'',
143+
content
144+
};
145+
articlesData.push(article);
146+
147+
// create card
148+
const card = document.createElement('div');
149+
card.className = 'article-card';
79150
card.innerHTML=`
80-
<h2>${title}</h2>
81-
<p>${description}</p>
82-
<div class="meta">By ${author} | ${date}</div>
83-
<div class="tags">${tags}</div>
151+
<h2>${article.title}</h2>
152+
<p>${article.description}</p>
153+
<div class="meta">By ${article.author} | ${article.date}</div>
154+
<div class="tags">${article.tags}</div>
84155
`;
156+
157+
card.addEventListener('click',()=>openModal(articlesData.indexOf(article)));
85158
grid.appendChild(card);
86-
}catch(e){console.error('Error loading markdown', file.name, e);}
159+
160+
}catch(err){console.error('Error loading file', file.name, err);}
87161
}
88-
}catch(e){
89-
console.error('Error fetching articles', e);
90-
grid.innerHTML='<p class="small">Unable to load articles.</p>';
91-
}
162+
}catch(e){console.error('Failed to fetch articles list', e);}
92163
})();
164+
165+
// --- Modal functions ---
166+
async function openModal(index){
167+
currentIndex=index;
168+
const article=articlesData[index];
169+
modalTitle.textContent=article.title;
170+
modalAuthor.textContent='By '+article.author;
171+
modalDate.textContent=article.date;
172+
modalReadtime.textContent=estimateReadTime(article.content);
173+
modalTags.textContent=article.tags;
174+
if(article.cover){modalCover.src=article.cover; modalCover.style.display='block';} else modalCover.style.display='none';
175+
articleContent.innerHTML=marked.parse(article.content);
176+
Prism.highlightAll();
177+
modalViews.textContent='Views: ' + await incAndGetViews(article.fileName.replace(/\.[^/.]+$/,""));
178+
modal.style.display='flex';
179+
}
180+
181+
// Next / Previous
182+
prevBtn.addEventListener('click',()=>openModal((currentIndex-1+articlesData.length)%articlesData.length));
183+
nextBtn.addEventListener('click',()=>openModal((currentIndex+1)%articlesData.length));
184+
185+
// Close modal
186+
modalClose.addEventListener('click',()=>modal.style.display='none');
187+
window.addEventListener('click',e=>{if(e.target==modal) modal.style.display='none'});
93188
</script>
94189
</body>
95190
</html>

0 commit comments

Comments
 (0)