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 + + + +
    + +
    + +
    +
    + +
    +
    +

    Todo List

    +
    +
    +
    + + +
    +
      + +
    +
    +
    +
    +
    + +
    +

    © 2024 Rendani Manugeni. All rights reserved.

    +
    + + + + 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 + + + +
    + +
    + +
    +
    + +
    +
    +

    Tech News Feed

    +
    + +

    Loading news...

    +
    +
    +
    + +
    +

    © 2024 Rendani Manugeni. All rights reserved.

    +
    + + + + + 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...

    +

    +
    +
    +
    + +
    +

    © 2024 Rendani Manugeni. All rights reserved.

    +
    + + + + + + 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
  • +
    + +