diff --git a/css/style.css b/css/style.css
index 1def0f6..2c4eb6b 100644
--- a/css/style.css
+++ b/css/style.css
@@ -389,3 +389,128 @@ mark {
border-bottom: none;
margin-top: 0;
}
+
+/* News Article Styling */
+#articles-container {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: 2rem;
+}
+
+.article-card {
+ background-color: #2a344a;
+ padding: 2rem;
+ border-radius: 10px;
+ border-left: 5px solid #8a2be2;
+}
+
+.article-card img {
+ max-width: 100%;
+ border-radius: 5px;
+ margin-bottom: 1rem;
+}
+
+.article-card h3 {
+ margin-top: 0;
+ border-bottom: none;
+}
+
+.article-card h3 a {
+ text-decoration: none;
+ color: #f0f0f0;
+ transition: color 0.3s;
+}
+
+.article-card h3 a:hover {
+ color: #8a2be2;
+}
+
+.article-card .article-source,
+.article-card .article-published {
+ display: inline-block;
+ font-size: 0.9rem;
+ color: #808080;
+ margin-top: 1rem;
+ margin-right: 1rem;
+}
+
+.search-container {
+ padding: 0 1rem 1rem 1rem;
+ max-width: 400px;
+ margin: 0 auto;
+}
+
+/* Todo List App Styling */
+.todo-container {
+ max-width: 600px;
+ margin: 0 auto;
+}
+
+#todo-form {
+ display: flex;
+ gap: 10px;
+ margin-bottom: 2rem;
+}
+
+#todo-input {
+ flex-grow: 1;
+ padding: 10px;
+ border-radius: 5px;
+ border: 1px solid #808080;
+ background-color: #2a344a;
+ color: #f0f0f0;
+ font-size: 1rem;
+}
+
+#todo-form button {
+ padding: 10px 20px;
+ border-radius: 5px;
+ background-color: #8a2be2;
+ color: white;
+ border: none;
+ cursor: pointer;
+ font-size: 1rem;
+ transition: background-color 0.3s;
+}
+
+#todo-form button:hover {
+ background-color: #6a1eae;
+}
+
+#todo-list {
+ list-style: none;
+ padding: 0;
+}
+
+#todo-list li {
+ background-color: #2a344a;
+ padding: 15px;
+ border-radius: 5px;
+ margin-bottom: 10px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ transition: all 0.3s;
+ word-break: break-all;
+}
+
+#todo-list li.completed {
+ text-decoration: line-through;
+ opacity: 0.6;
+ background-color: #1c2333;
+}
+
+#todo-list .delete-btn {
+ background-color: #ff4d4d;
+ color: white;
+ border: none;
+ padding: 5px 10px;
+ border-radius: 5px;
+ cursor: pointer;
+ margin-left: 15px;
+ transition: background-color 0.3s;
+}
+
+#todo-list .delete-btn:hover {
+ background-color: #cc0000;
+}
diff --git a/games/calculator/index.html b/games/calculator/index.html
index 5f55071..bcb1668 100644
--- a/games/calculator/index.html
+++ b/games/calculator/index.html
@@ -13,8 +13,12 @@
Home
Projects
Games & Apps
+ News
+
+
+
diff --git a/games/chess/index.html b/games/chess/index.html
index 06f3d96..13bb480 100644
--- a/games/chess/index.html
+++ b/games/chess/index.html
@@ -13,8 +13,12 @@
Home
Projects
Games & Apps
+ News
+
+
+
diff --git a/games/index.html b/games/index.html
index 00c0724..c455cef 100644
--- a/games/index.html
+++ b/games/index.html
@@ -13,8 +13,12 @@
Home
Projects
Games & Apps
+ News
+
+
+
@@ -33,6 +37,10 @@ Chess
Calculator
A simple and stylish calculator app.
+
+ Todo List
+ A useful app to keep track of your tasks.
+
diff --git a/games/tictactoe/index.html b/games/tictactoe/index.html
index 456c1f4..6ab24d2 100644
--- a/games/tictactoe/index.html
+++ b/games/tictactoe/index.html
@@ -13,8 +13,12 @@
Home
Projects
Games & Apps
+ News
+
+
+
diff --git a/games/todo/index.html b/games/todo/index.html
new file mode 100644
index 0000000..9cb7c96
--- /dev/null
+++ b/games/todo/index.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+ Todo List - Rendani Manugeni
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/index.html b/index.html
index e3b4539..b53d874 100644
--- a/index.html
+++ b/index.html
@@ -13,8 +13,12 @@
Home
Projects
Games & Apps
+ News
+
+
+
diff --git a/js/chess.js b/js/chess.js
index 6f454b1..54b8373 100644
--- a/js/chess.js
+++ b/js/chess.js
@@ -70,6 +70,7 @@ function initializeChessGame() {
let selectedSquare = null;
let currentPlayer = 'white'; // White starts
let isGameOver = false;
+ let playerVsAiMode = true; // Default to playing against AI
function handleSquareClick(event) {
if (isGameOver) return;
@@ -209,6 +210,16 @@ function initializeChessGame() {
updateStatus();
updateBoardView(fromR, fromC, toR, toC);
checkGameState();
+
+ if (playerVsAiMode && currentPlayer === 'black' && !isGameOver) {
+ // Use a timeout to make the AI's move feel less instantaneous
+ setTimeout(() => {
+ const aiMove = getAiMove();
+ if (aiMove) {
+ movePiece(aiMove.from.r, aiMove.from.c, aiMove.to.r, aiMove.to.c);
+ }
+ }, 500); // 0.5 second delay
+ }
}
function updateStatus() {
@@ -414,4 +425,56 @@ function initializeChessGame() {
}
return null;
}
+
+ // --- AI Logic ---
+ const pieceValues = {
+ 'pawn': 10, 'knight': 30, 'bishop': 30, 'rook': 50, 'queen': 90, 'king': 900
+ };
+
+ function evaluateBoard(board) {
+ let totalScore = 0;
+ for (let r = 0; r < 8; r++) {
+ for (let c = 0; c < 8; c++) {
+ const piece = board[r][c];
+ if (piece) {
+ totalScore += (piece.color === 'white' ? pieceValues[piece.type] : -pieceValues[piece.type]);
+ }
+ }
+ }
+ return totalScore;
+ }
+
+ function getAiMove() {
+ let bestMove = null;
+ let bestScore = Infinity; // Black (AI) wants to find the lowest score
+
+ for (let r = 0; r < 8; r++) {
+ for (let c = 0; c < 8; c++) {
+ const piece = boardState[r][c];
+ if (piece && piece.color === 'black') {
+ const moves = getValidMoves(piece, r, c);
+ for (const move of moves) {
+ const [toR, toC] = move;
+
+ // Simulate the move to evaluate the resulting board state
+ const originalDestPiece = boardState[toR][toC];
+ boardState[toR][toC] = piece;
+ boardState[r][c] = null;
+
+ const score = evaluateBoard(boardState);
+
+ // Undo the move to restore the board state
+ boardState[r][c] = piece;
+ boardState[toR][toC] = originalDestPiece;
+
+ if (score < bestScore) {
+ bestScore = score;
+ bestMove = { from: { r, c }, to: { r: toR, c: toC }, piece };
+ }
+ }
+ }
+ }
+ }
+ return bestMove;
+ }
}
diff --git a/js/main.js b/js/main.js
index a3c4e44..75de3d7 100644
--- a/js/main.js
+++ b/js/main.js
@@ -19,15 +19,16 @@ document.addEventListener('DOMContentLoaded', () => {
return;
}
+ projectsContainer.classList.add('gallery-container');
const projectsHTML = projects.map(project => `
-
+
`).join('');
projectsContainer.innerHTML = projectsHTML;
diff --git a/js/news.js b/js/news.js
new file mode 100644
index 0000000..3a23a6c
--- /dev/null
+++ b/js/news.js
@@ -0,0 +1,73 @@
+document.addEventListener('DOMContentLoaded', () => {
+ const articlesContainer = document.getElementById('articles-container');
+ if (!articlesContainer) return;
+
+ const apiKey = 'c39dfc340784447bab487145f48bee80';
+ const keywords = 'developer OR software OR ai OR programming';
+ const url = `https://newsapi.org/v2/everything?q=${encodeURIComponent(keywords)}&apiKey=${apiKey}&language=en&sortBy=publishedAt&pageSize=20`;
+
+ async function fetchNews() {
+ try {
+ const response = await fetch(url);
+ if (!response.ok) {
+ throw new Error(`API request failed with status ${response.status}`);
+ }
+ const data = await response.json();
+ renderArticles(data.articles);
+ } catch (error) {
+ console.error('Error fetching news:', error);
+ articlesContainer.innerHTML = 'Could not fetch news articles. Please try again later.
';
+ }
+ }
+
+ function renderArticles(articles) {
+ if (!articles || articles.length === 0) {
+ articlesContainer.innerHTML = 'No news articles found.
';
+ return;
+ }
+
+ articlesContainer.innerHTML = ''; // Clear loading message
+
+ articles.forEach(article => {
+ if (!article.title || article.title === '[Removed]') return;
+
+ const articleEl = document.createElement('div');
+ articleEl.classList.add('article-card');
+
+ const title = document.createElement('h3');
+ const link = document.createElement('a');
+ link.href = article.url;
+ link.textContent = article.title;
+ link.target = '_blank';
+ link.rel = 'noopener noreferrer';
+ title.appendChild(link);
+
+ const description = document.createElement('p');
+ description.textContent = article.description || '';
+
+ const source = document.createElement('span');
+ source.classList.add('article-source');
+ source.textContent = `Source: ${article.source.name}`;
+
+ const published = document.createElement('span');
+ published.classList.add('article-published');
+ published.textContent = `Published: ${new Date(article.publishedAt).toLocaleDateString()}`;
+
+ const image = document.createElement('img');
+ if(article.urlToImage) {
+ image.src = article.urlToImage;
+ image.alt = article.title;
+ articleEl.appendChild(image);
+ }
+
+ articleEl.appendChild(title);
+ articleEl.appendChild(description);
+ articleEl.appendChild(source);
+ articleEl.appendChild(published);
+
+ articlesContainer.appendChild(articleEl);
+ });
+ }
+
+ fetchNews();
+});
diff --git a/js/project-detail.js b/js/project-detail.js
new file mode 100644
index 0000000..da57984
--- /dev/null
+++ b/js/project-detail.js
@@ -0,0 +1,47 @@
+document.addEventListener('DOMContentLoaded', () => {
+ const titleEl = document.getElementById('project-title');
+ const descriptionEl = document.getElementById('project-description');
+ const readmeEl = document.getElementById('project-readme');
+
+ const params = new URLSearchParams(window.location.search);
+ const repoName = params.get('repo');
+
+ if (!repoName) {
+ titleEl.textContent = 'Project not found.';
+ return;
+ }
+
+ const showdownConverter = new showdown.Converter();
+
+ async function fetchProjectDetails() {
+ try {
+ // Fetch basic repo info
+ const repoRes = await fetch(`https://api.github.com/repos/mononeer/${repoName}`);
+ if (!repoRes.ok) throw new Error('Repository not found');
+ const repoData = await repoRes.json();
+
+ titleEl.textContent = repoData.name;
+ descriptionEl.textContent = repoData.description || 'No description provided.';
+
+ // Fetch README
+ const readmeRes = await fetch(`https://api.github.com/repos/mononeer/${repoName}/readme`);
+ if (!readmeRes.ok) {
+ readmeEl.innerHTML = 'No README found for this project.
';
+ return;
+ }
+ const readmeData = await readmeRes.json();
+
+ // Decode base64 content and convert Markdown to HTML
+ const markdownContent = atob(readmeData.content);
+ const htmlContent = showdownConverter.makeHtml(markdownContent);
+ readmeEl.innerHTML = htmlContent;
+
+ } catch (error) {
+ console.error('Error fetching project details:', error);
+ titleEl.textContent = 'Error loading project';
+ descriptionEl.textContent = error.message;
+ }
+ }
+
+ fetchProjectDetails();
+});
diff --git a/js/todo.js b/js/todo.js
new file mode 100644
index 0000000..a365a25
--- /dev/null
+++ b/js/todo.js
@@ -0,0 +1,58 @@
+document.addEventListener('DOMContentLoaded', () => {
+ const todoForm = document.getElementById('todo-form');
+ const todoInput = document.getElementById('todo-input');
+ const todoList = document.getElementById('todo-list');
+
+ // Load todos from local storage
+ let todos = JSON.parse(localStorage.getItem('todos')) || [];
+
+ function saveTodos() {
+ localStorage.setItem('todos', JSON.stringify(todos));
+ }
+
+ function renderTodos() {
+ todoList.innerHTML = '';
+ todos.forEach((todo, index) => {
+ const li = document.createElement('li');
+ li.textContent = todo.text;
+ li.classList.toggle('completed', todo.completed);
+ li.dataset.index = index;
+
+ const deleteBtn = document.createElement('button');
+ deleteBtn.textContent = 'Delete';
+ deleteBtn.classList.add('delete-btn');
+
+ li.appendChild(deleteBtn);
+ todoList.appendChild(li);
+ });
+ }
+
+ todoForm.addEventListener('submit', (e) => {
+ e.preventDefault();
+ const text = todoInput.value.trim();
+ if (text) {
+ todos.push({ text: text, completed: false });
+ todoInput.value = '';
+ saveTodos();
+ renderTodos();
+ }
+ });
+
+ todoList.addEventListener('click', (e) => {
+ const target = e.target;
+ const index = target.closest('li')?.dataset.index;
+
+ if (index === undefined) return;
+
+ if (target.classList.contains('delete-btn')) {
+ todos.splice(index, 1);
+ } else {
+ todos[index].completed = !todos[index].completed;
+ }
+
+ saveTodos();
+ renderTodos();
+ });
+
+ renderTodos();
+});
diff --git a/news/index.html b/news/index.html
new file mode 100644
index 0000000..510be1b
--- /dev/null
+++ b/news/index.html
@@ -0,0 +1,41 @@
+
+
+
+
+
+ Tech News - Rendani Manugeni
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/project-detail/index.html b/project-detail/index.html
new file mode 100644
index 0000000..df96cdd
--- /dev/null
+++ b/project-detail/index.html
@@ -0,0 +1,41 @@
+
+
+
+
+
+ Project Details - Rendani Manugeni
+
+
+
+
+
+
+
+
+ Loading project...
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/projects/index.html b/projects/index.html
index 40b3d56..152956b 100644
--- a/projects/index.html
+++ b/projects/index.html
@@ -13,8 +13,12 @@
Home
Projects
Games & Apps
+ News
+
+
+