<div class="container">
<div class="header">
<h1>
<ion-icon name="people"></ion-icon>
Address Book
</h1>
<p>Manage your contacts efficiently</p>
</div>
<div class="main-content">
<!-- Add Contact Form -->
<div class="add-contact-section">
<h2 class="section-title">
<ion-icon name="person-add"></ion-icon>
<span id="formTitle">Add New Contact</span>
</h2>
<form id="contactForm">
<input type="hidden" id="editIndex" value="">
<div class="form-group">
<label>Full Name *</label>
<input type="text" id="fullName" placeholder="John Doe" required>
</div>
<div class="form-group">
<label>Phone Number *</label>
<input type="tel" id="phone" placeholder="+1 (555) 123-4567" required>
</div>
<div class="form-group">
<label>Email Address</label>
<input type="email" id="email" placeholder="john@example.com">
</div>
<div class="form-group">
<label>Category *</label>
<select id="category" required>
<option value="personal">Personal</option>
<option value="work">Work</option>
<option value="family">Family</option>
</select>
</div>
<div class="form-group">
<label>Address</label>
<textarea id="address" placeholder="123 Main Street, City, State"></textarea>
</div>
<button type="submit" class="btn btn-primary">
<ion-icon name="add-circle"></ion-icon>
<span id="submitBtnText">Add Contact</span>
</button>
<button type="button" class="btn btn-secondary" id="cancelBtn" style="display: none;">
<ion-icon name="close-circle"></ion-icon>
Cancel
</button>
</form>
</div>
<!-- Contacts List -->
<div class="contacts-section">
<h2 class="section-title">
<ion-icon name="list"></ion-icon>
My Contacts
</h2>
<!-- Stats -->
<div class="stats">
<div class="stat-card">
<ion-icon name="people"></ion-icon>
<div class="stat-number" id="totalContacts">0</div>
<div class="stat-label">Total Contacts</div>
</div>
<div class="stat-card">
<ion-icon name="briefcase"></ion-icon>
<div class="stat-number" id="workContacts">0</div>
<div class="stat-label">Work</div>
</div>
<div class="stat-card">
<ion-icon name="home"></ion-icon>
<div class="stat-number" id="personalContacts">0</div>
<div class="stat-label">Personal</div>
</div>
</div>
<!-- Search -->
<div class="search-bar">
<input type="text" id="searchInput" placeholder="Search contacts...">
<ion-icon name="search"></ion-icon>
</div>
<!-- Filter Tabs -->
<div class="filter-tabs">
<button class="filter-tab active" data-filter="all">All</button>
<button class="filter-tab" data-filter="personal">Personal</button>
<button class="filter-tab" data-filter="work">Work</button>
<button class="filter-tab" data-filter="family">Family</button>
</div>
<!-- Contact List -->
<div class="contact-list" id="contactList">
<div class="empty-state">
<ion-icon name="person-add"></ion-icon>
<h3>No contacts yet</h3>
<p>Start by adding your first contact</p>
</div>
</div>
</div>
</div>
</div>
<script type="module" src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.esm.js"></script>
<script nomodule src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js"></script>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.header {
text-align: center;
color: white;
margin-bottom: 40px;
}
.header h1 {
font-size: 2.5rem;
font-weight: 700;
margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: center;
gap: 15px;
}
.header p {
font-size: 1.1rem;
opacity: 0.9;
}
.main-content {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 25px;
}
.add-contact-section {
background: white;
border-radius: 16px;
padding: 30px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
height: fit-content;
}
.section-title {
font-size: 1.5rem;
color: #2c3e50;
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 10px;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
color: #555;
font-weight: 600;
margin-bottom: 8px;
font-size: 14px;
}
.form-group input,
.form-group select,
.form-group textarea {
width: 100%;
padding: 12px 15px;
border: 2px solid #e0e0e0;
border-radius: 10px;
font-size: 14px;
font-family: inherit;
transition: all 0.3s;
}
.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
outline: none;
border-color: #3498db;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
}
.form-group textarea {
resize: vertical;
min-height: 80px;
}
.btn {
padding: 12px 30px;
border: none;
border-radius: 10px;
font-weight: 600;
font-size: 15px;
cursor: pointer;
transition: all 0.3s;
display: inline-flex;
align-items: center;
gap: 8px;
}
.btn-primary {
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
color: white;
width: 100%;
justify-content: center;
box-shadow: 0 4px 15px rgba(52, 152, 219, 0.3);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(52, 152, 219, 0.4);
}
.btn-secondary {
background: #95a5a6;
color: white;
margin-top: 10px;
width: 100%;
justify-content: center;
}
.btn-secondary:hover {
background: #7f8c8d;
}
.contacts-section {
background: white;
border-radius: 16px;
padding: 30px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
}
.search-bar {
position: relative;
margin-bottom: 25px;
}
.search-bar input {
width: 100%;
padding: 15px 50px 15px 20px;
border: 2px solid #e0e0e0;
border-radius: 12px;
font-size: 15px;
transition: all 0.3s;
}
.search-bar input:focus {
outline: none;
border-color: #3498db;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
}
.search-bar ion-icon {
position: absolute;
right: 18px;
top: 50%;
transform: translateY(-50%);
font-size: 24px;
color: #95a5a6;
}
.filter-tabs {
display: flex;
gap: 10px;
margin-bottom: 25px;
flex-wrap: wrap;
}
.filter-tab {
padding: 8px 20px;
background: #ecf0f1;
border: none;
border-radius: 20px;
cursor: pointer;
font-weight: 600;
font-size: 13px;
color: #555;
transition: all 0.3s;
}
.filter-tab.active {
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
color: white;
}
.filter-tab:hover {
background: #3498db;
color: white;
}
.contact-list {
display: grid;
gap: 15px;
max-height: 600px;
overflow-y: auto;
padding-right: 10px;
}
.contact-list::-webkit-scrollbar {
width: 8px;
}
.contact-list::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
}
.contact-list::-webkit-scrollbar-thumb {
background: #3498db;
border-radius: 10px;
}
.contact-card {
background: #f8f9fa;
border-radius: 12px;
padding: 20px;
display: flex;
align-items: center;
gap: 20px;
transition: all 0.3s;
border: 2px solid transparent;
}
.contact-card:hover {
transform: translateX(5px);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
border-color: #3498db;
}
.contact-avatar {
width: 60px;
height: 60px;
border-radius: 50%;
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 24px;
font-weight: 700;
flex-shrink: 0;
}
.contact-info {
flex: 1;
}
.contact-name {
font-size: 18px;
font-weight: 700;
color: #2c3e50;
margin-bottom: 5px;
}
.contact-detail {
display: flex;
align-items: center;
gap: 8px;
color: #7f8c8d;
font-size: 14px;
margin-bottom: 3px;
}
.contact-detail ion-icon {
font-size: 16px;
color: #3498db;
}
.contact-category {
display: inline-block;
padding: 4px 12px;
background: #e8f5e9;
color: #27ae60;
border-radius: 12px;
font-size: 12px;
font-weight: 600;
margin-top: 8px;
}
.contact-category.work {
background: #e3f2fd;
color: #2196f3;
}
.contact-category.family {
background: #fce4ec;
color: #e91e63;
}
.contact-actions {
display: flex;
gap: 8px;
}
.action-btn {
width: 38px;
height: 38px;
border: none;
border-radius: 8px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s;
}
.action-btn.edit {
background: #fff3cd;
color: #f39c12;
}
.action-btn.edit:hover {
background: #f39c12;
color: white;
}
.action-btn.delete {
background: #f8d7da;
color: #e74c3c;
}
.action-btn.delete:hover {
background: #e74c3c;
color: white;
}
.empty-state {
text-align: center;
padding: 60px 20px;
color: #95a5a6;
}
.empty-state ion-icon {
font-size: 80px;
margin-bottom: 20px;
opacity: 0.3;
}
.stats {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
margin-bottom: 25px;
}
.stat-card {
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
padding: 20px;
border-radius: 12px;
color: white;
text-align: center;
}
.stat-card ion-icon {
font-size: 32px;
margin-bottom: 8px;
}
.stat-number {
font-size: 28px;
font-weight: 700;
margin-bottom: 5px;
}
.stat-label {
font-size: 13px;
opacity: 0.9;
}
@media (max-width: 768px) {
.main-content {
grid-template-columns: 1fr;
}
.header h1 {
font-size: 2rem;
}
.stats {
grid-template-columns: 1fr;
}
.contact-card {
flex-direction: column;
text-align: center;
}
.contact-actions {
width: 100%;
justify-content: center;
}
}
let contacts = JSON.parse(localStorage.getItem('contacts')) || [];
let currentFilter = 'all';
// Load contacts on page load
renderContacts();
updateStats();
// Form submission
document.getElementById('contactForm').addEventListener('submit', (e) => {
e.preventDefault();
const contact = {
name: document.getElementById('fullName').value,
phone: document.getElementById('phone').value,
email: document.getElementById('email').value,
category: document.getElementById('category').value,
address: document.getElementById('address').value,
id: Date.now()
};
const editIndex = document.getElementById('editIndex').value;
if (editIndex) {
// Update existing contact
contacts[editIndex] = { ...contact, id: contacts[editIndex].id };
document.getElementById('editIndex').value = '';
document.getElementById('formTitle').textContent = 'Add New Contact';
document.getElementById('submitBtnText').textContent = 'Add Contact';
document.getElementById('cancelBtn').style.display = 'none';
} else {
// Add new contact
contacts.push(contact);
}
localStorage.setItem('contacts', JSON.stringify(contacts));
document.getElementById('contactForm').reset();
renderContacts();
updateStats();
});
// Cancel edit
document.getElementById('cancelBtn').addEventListener('click', () => {
document.getElementById('contactForm').reset();
document.getElementById('editIndex').value = '';
document.getElementById('formTitle').textContent = 'Add New Contact';
document.getElementById('submitBtnText').textContent = 'Add Contact';
document.getElementById('cancelBtn').style.display = 'none';
});
// Search functionality
document.getElementById('searchInput').addEventListener('input', (e) => {
renderContacts(e.target.value);
});
// Filter tabs
document.querySelectorAll('.filter-tab').forEach(tab => {
tab.addEventListener('click', () => {
document.querySelectorAll('.filter-tab').forEach(t => t.classList.remove('active'));
tab.classList.add('active');
currentFilter = tab.dataset.filter;
renderContacts();
});
});
// Render contacts
function renderContacts(searchTerm = '') {
const contactList = document.getElementById('contactList');
let filteredContacts = contacts;
// Apply category filter
if (currentFilter !== 'all') {
filteredContacts = filteredContacts.filter(c => c.category === currentFilter);
}
// Apply search filter
if (searchTerm) {
filteredContacts = filteredContacts.filter(c =>
c.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
c.phone.includes(searchTerm) ||
c.email.toLowerCase().includes(searchTerm.toLowerCase())
);
}
if (filteredContacts.length === 0) {
contactList.innerHTML = `
<div class="empty-state">
<ion-icon name="search"></ion-icon>
<h3>No contacts found</h3>
<p>${searchTerm ? 'Try a different search term' : 'Start by adding your first contact'}</p>
</div>
`;
return;
}
contactList.innerHTML = filteredContacts.map((contact, index) => {
const actualIndex = contacts.indexOf(contact);
const initials = contact.name.split(' ').map(n => n[0]).join('').toUpperCase();
return `
<div class="contact-card">
<div class="contact-avatar">${initials}</div>
<div class="contact-info">
<div class="contact-name">${contact.name}</div>
<div class="contact-detail">
<ion-icon name="call"></ion-icon>
${contact.phone}
</div>
${contact.email ? `
<div class="contact-detail">
<ion-icon name="mail"></ion-icon>
${contact.email}
</div>
` : ''}
${contact.address ? `
<div class="contact-detail">
<ion-icon name="location"></ion-icon>
${contact.address}
</div>
` : ''}
<span class="contact-category ${contact.category}">${contact.category}</span>
</div>
<div class="contact-actions">
<button class="action-btn edit" onclick="editContact(${actualIndex})">
<ion-icon name="create"></ion-icon>
</button>
<button class="action-btn delete" onclick="deleteContact(${actualIndex})">
<ion-icon name="trash"></ion-icon>
</button>
</div>
</div>
`;
}).join('');
}
// Edit contact
function editContact(index) {
const contact = contacts[index];
document.getElementById('fullName').value = contact.name;
document.getElementById('phone').value = contact.phone;
document.getElementById('email').value = contact.email || '';
document.getElementById('category').value = contact.category;
document.getElementById('address').value = contact.address || '';
document.getElementById('editIndex').value = index;
document.getElementById('formTitle').textContent = 'Edit Contact';
document.getElementById('submitBtnText').textContent = 'Update Contact';
document.getElementById('cancelBtn').style.display = 'block';
window.scrollTo({ top: 0, behavior: 'smooth' });
}
// Delete contact
function deleteContact(index) {
if (confirm('Are you sure you want to delete this contact?')) {
contacts.splice(index, 1);
localStorage.setItem('contacts', JSON.stringify(contacts));
renderContacts();
updateStats();
}
}
// Update statistics
function updateStats() {
document.getElementById('totalContacts').textContent = contacts.length;
document.getElementById('workContacts').textContent = contacts.filter(c => c.category === 'work').length;
document.getElementById('personalContacts').textContent = contacts.filter(c => c.category === 'personal').length;
}
// Make functions global
window.editContact = editContact;
window.deleteContact = deleteContact;
No comments yet. Be the first!