Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions Todo.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
body {
font-family: 'Open Sans', sans-serif;
background-color: #f8f9fa;
color: #343a40;
display: flex;
flex-direction: column;
align-items: center;
margin: 0;
}
#main-heading {
margin-top: 20px;
}
.container {
width: 90%;
max-width: 600px;
margin-top: 20px;
}
.grid-container {
display: grid;
grid-template-columns: 1fr auto auto;
gap: 10px;
margin-bottom: 20px;
}
.todo-container {
list-style-type: none;
padding: 0;
text-align: center;
}
.completed-todo-list {
margin-top: 20px;
}
.btn-todo {
background-color: #007bff;
color: white;
}
.completed {
text-decoration: line-through;
color: gray;
}
.light {
background-color: #343a40;
color: #f8f9fa;
}
.light-arrow {
color: #f8f9fa;
}
.delete-btn {
background: transparent;
border: none;
cursor: pointer;
color: #dc3545;
margin-left: 10px;
}
.delete-btn img {
width: 20px;
height: 20px;
}
117 changes: 117 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TO-DO APP</title>
<link rel="stylesheet" href="Todo.css">
</head>
<body style="background: url('https://naujienos.vu.lt/wp-content/uploads/2023/11/VU-MIF-robotai-2-1536x1024.jpg');
background-size: cover;
background-image: -moz-radial-gradient(cover);
background-repeat: no-repeat;
height: auto;
width: auto;">
<h1 id="main-heading" style=" background: linear-gradient(to right,green,rgb(212, 88, 26),gold,rgb(67, 67, 174), red, yellow,rgb(182, 8, 188));
-webkit-background-clip: text;
color: transparent;">TO-DO APP</h1>

<div class="container">
<header class="head-container">
<div class="text-center mb-2">

</div>
<div class="text-center mb-2" style="color: black;">
<p id="date" style="color: black;">24th Sep</p>
<p id="day" style="color: black;">Wednesday</p>
</div>
</header>

<div class="grid-container">
<input id="todo-input" type="text" placeholder="Enter Todo here" autocomplete="off">
<input id="todo-date" type="date">
<button class='btn-todo' onclick="addTodo();">Add</button>
</div>

<ul id="todo-list" class="todo-container"></ul>

<div class="completed-todo-list">
<h3 style="color: black;">Completed Tasks</h3>
<div class="completed-todo-list-title" id="completed-todo-list-title">
<button class="btn btn-block text-left completed_title pl-0 text-white" onclick="toggleCompleted()">
Completed
<div id="task_counter">(0)</div>
</button>
</div>
<div class="completed-todo-list-items" id="completed-todo-list-items"></div>
</div>
</div>

<script>
let completedCount = 0;

function addTodo() {
const input = document.getElementById('todo-input');
const date = document.getElementById('todo-date');
const todoList = document.getElementById('todo-list');

if (input.value) {
const li = document.createElement('li');
li.style.display = 'flex';
li.style.justifyContent = 'space-between';
li.style.alignItems = 'center';

li.textContent = `${input.value} - ${date.value}`;
li.style.cursor = "pointer";
const deleteBtn = document.createElement('button');
deleteBtn.className = 'delete-btn';
deleteBtn.innerHTML = '<img src="https://img.icons8.com/ios-filled/50/000000/trash.png" alt="delete icon" />';
deleteBtn.onclick = function(event) {
event.stopPropagation();
addToCompleted(li.textContent);
li.remove();
};

li.appendChild(deleteBtn);

li.onclick = function() {
li.classList.toggle("completed");
completedCount += li.classList.contains("completed") ? 1 : -1;
updateTaskCounter();
};

todoList.appendChild(li);
input.value = '';
date.value = '';
}
}

function addToCompleted(task) {
const completedList = document.getElementById('completed-todo-list-items');
const completedItem = document.createElement('div');
completedItem.textContent = task;
completedList.appendChild(completedItem);
completedCount++;
updateTaskCounter();
}

function updateTaskCounter() {
document.getElementById('task_counter').textContent = `(${completedCount})`;
}

function toggleCompleted() {
const completedList = document.getElementById('completed-todo-list-items');
completedList.style.display = completedList.style.display === 'none' ? 'block' : 'none';
}

function DarkMode() {
var element = document.body;
element.classList.toggle("light");

var arrow = document.querySelector('.completed_title');
arrow.classList.toggle("light-arrow");
}
</script>
</body>
</html>
208 changes: 208 additions & 0 deletions index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
import React, { useState, useEffect } from 'react';
import { Search, Globe, Users, MapPin, Loader } from 'lucide-react';

const CountryExplorer = () => {
const [countries, setCountries] = useState([]);
const [filteredCountries, setFilteredCountries] = useState([]);
const [searchTerm, setSearchTerm] = useState('');
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

// Fetch countries data on component mount
useEffect(() => {
const fetchCountries = async () => {
try {
setLoading(true);
const response = await fetch('https://restcountries.com/v3.1/all');

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

const data = await response.json();

// Sort countries alphabetically by name
const sortedCountries = data.sort((a, b) =>
a.name.common.localeCompare(b.name.common)
);

setCountries(sortedCountries);
setFilteredCountries(sortedCountries);
setError(null);
} catch (err) {
setError('Failed to fetch countries data. Please try again later.');
console.error('Error fetching countries:', err);
} finally {
setLoading(false);
}
};

fetchCountries();
}, []);

// Filter countries based on search term
useEffect(() => {
if (searchTerm === '') {
setFilteredCountries(countries);
} else {
const filtered = countries.filter(country =>
country.name.common.toLowerCase().includes(searchTerm.toLowerCase())
);
setFilteredCountries(filtered);
}
}, [searchTerm, countries]);

// Format population with commas
const formatPopulation = (population) => {
return population ? population.toLocaleString() : 'N/A';
};

// Get capital city (handle array format)
const getCapital = (capital) => {
if (!capital || capital.length === 0) return 'N/A';
return Array.isArray(capital) ? capital[0] : capital;
};

if (loading) {
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 flex items-center justify-center">
<div className="text-center">
<Loader className="w-12 h-12 animate-spin text-blue-600 mx-auto mb-4" />
<p className="text-lg text-gray-600">Loading countries...</p>
</div>
</div>
);
}

if (error) {
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 flex items-center justify-center">
<div className="text-center bg-white p-8 rounded-lg shadow-lg">
<div className="text-red-500 text-6xl mb-4">⚠️</div>
<h2 className="text-2xl font-bold text-gray-800 mb-2">Oops! Something went wrong</h2>
<p className="text-gray-600 mb-4">{error}</p>
<button
onClick={() => window.location.reload()}
className="bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700 transition-colors"
>
Try Again
</button>
</div>
</div>
);
}

return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
{/* Header */}
<header className="bg-white shadow-lg">
<div className="max-w-7xl mx-auto px-4 py-6">
<div className="flex items-center justify-center mb-6">
<Globe className="w-8 h-8 text-blue-600 mr-3" />
<h1 className="text-3xl font-bold text-gray-800">Country Explorer</h1>
</div>

{/* Search Bar */}
<div className="relative max-w-md mx-auto">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-5 h-5" />
<input
type="text"
placeholder="Search countries..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all"
/>
</div>

{/* Results Counter */}
<div className="text-center mt-4">
<p className="text-gray-600">
Showing {filteredCountries.length} of {countries.length} countries
</p>
</div>
</div>
</header>

{/* Countries Grid */}
<main className="max-w-7xl mx-auto px-4 py-8">
{filteredCountries.length === 0 ? (
<div className="text-center py-12">
<div className="text-6xl mb-4">🔍</div>
<h3 className="text-xl font-semibold text-gray-700 mb-2">No countries found</h3>
<p className="text-gray-500">Try adjusting your search term</p>
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
{filteredCountries.map((country) => (
<div
key={country.cca3}
className="bg-white rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 transform hover:-translate-y-1 overflow-hidden"
>
{/* Flag */}
<div className="h-48 overflow-hidden">
<img
src={country.flags?.png || country.flags?.svg}
alt={`Flag of ${country.name.common}`}
className="w-full h-full object-cover hover:scale-105 transition-transform duration-300"
onError={(e) => {
e.target.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIwIiBoZWlnaHQ9IjIxMyIgdmlld0JveD0iMCAwIDMyMCAyMTMiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIzMjAiIGhlaWdodD0iMjEzIiBmaWxsPSIjRjNGNEY2Ii8+CjxyZWN0IHg9IjEzNS41IiB5PSI5MS41IiB3aWR0aD0iNDkiIGhlaWdodD0iMzAiIHJ4PSIyIiBzdHJva2U9IiM5Q0EzQUYiLz4KPC9zdmc+';
}}
/>
</div>

{/* Country Info */}
<div className="p-6">
<h3 className="text-xl font-bold text-gray-800 mb-4 truncate">
{country.name.common}
</h3>

<div className="space-y-3">
<div className="flex items-center text-gray-600">
<MapPin className="w-4 h-4 mr-2 text-red-500 flex-shrink-0" />
<span className="text-sm">
<span className="font-medium">Capital:</span> {getCapital(country.capital)}
</span>
</div>

<div className="flex items-center text-gray-600">
<Users className="w-4 h-4 mr-2 text-blue-500 flex-shrink-0" />
<span className="text-sm">
<span className="font-medium">Population:</span> {formatPopulation(country.population)}
</span>
</div>

<div className="flex items-center text-gray-600">
<Globe className="w-4 h-4 mr-2 text-green-500 flex-shrink-0" />
<span className="text-sm">
<span className="font-medium">Region:</span> {country.region || 'N/A'}
</span>
</div>
</div>
</div>
</div>
))}
</div>
)}
</main>

{/* Footer */}
<footer className="bg-white mt-12 py-8 border-t">
<div className="max-w-7xl mx-auto px-4 text-center">
<p className="text-gray-600">
Data provided by{' '}
<a
href="https://restcountries.com"
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 hover:underline"
>
REST Countries API
</a>
</p>
</div>
</footer>
</div>
);
};

export default CountryExplorer;