casmopedia / templates /telescopes.html
aradhyapavan's picture
CospmoPedia
7e3b585 verified
{% extends "base.html" %}
{% block title %}Telescopes - Cosmopedia{% endblock %}
{% block content %}
<div class="container-fluid" style="padding-top: 100px; max-width: 1400px;">
<!-- Header Section -->
<div class="row mb-5">
<div class="col-12">
<div class="text-center mb-4">
<h1 class="text-gradient mb-3">
<i class="fas fa-telescope me-3"></i>Telescopes
</h1>
<p class="lead text-light">Explore the instruments that reveal the universe</p>
</div>
</div>
</div>
<!-- Search and Filter Controls -->
<div class="row mb-5 justify-content-center">
<div class="col-lg-10">
<div class="card bg-glass border-0 p-4">
<div class="row g-3">
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text bg-dark border-0 text-primary">
<i class="fas fa-search"></i>
</span>
<input type="text" id="telescopeSearch" class="form-control bg-dark border-0 text-light"
placeholder="Search telescopes..." style="box-shadow: none;">
</div>
</div>
<div class="col-md-2">
<select id="countryFilter" class="form-select bg-dark border-0 text-light">
<option value="">All Countries</option>
</select>
</div>
<div class="col-md-2">
<select id="typeFilter" class="form-select bg-dark border-0 text-light">
<option value="">All Types</option>
<option value="ground-based">Ground-based</option>
<option value="space-based">Space-based</option>
<option value="radio">Radio</option>
<option value="infrared">Infrared</option>
<option value="x-ray">X-ray</option>
</select>
</div>
<div class="col-md-2">
<select id="statusFilter" class="form-select bg-dark border-0 text-light">
<option value="">All Status</option>
<option value="operational">Operational</option>
<option value="decommissioned">Decommissioned</option>
<option value="under construction">Under Construction</option>
</select>
</div>
<div class="col-md-2">
<button id="clearFilters" class="btn btn-outline-primary w-100">
<i class="fas fa-times me-1"></i>Clear
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Loading State -->
<div id="loadingState" class="text-center py-5">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-3">Loading telescopes...</p>
</div>
<!-- Results Count -->
<div id="resultsCount" class="text-center mb-4" style="display: none;">
<p class="text-muted">Found <span id="telescopeCount">0</span> telescope(s)</p>
</div>
<!-- Telescopes Grid -->
<div id="telescopesGrid" class="row g-4" style="display: none;">
<!-- Telescopes will be loaded here -->
</div>
<!-- Empty State -->
<div id="emptyState" class="text-center py-5" style="display: none;">
<div class="empty-state">
<i class="fas fa-search fa-3x text-muted mb-3"></i>
<h4>No Telescopes Found</h4>
<p>Try adjusting your search criteria or filters.</p>
</div>
</div>
</div>
<!-- Telescope Detail Modal -->
<div class="modal fade" id="telescopeModal" tabindex="-1" aria-labelledby="telescopeModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content" style="background: rgba(20, 25, 40, 0.95); backdrop-filter: blur(10px); border: 1px solid rgba(255, 255, 255, 0.1);">
<div class="modal-header border-bottom border-secondary">
<h5 class="modal-title text-light" id="telescopeModalLabel">Telescope Details</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="telescopeModalContent">
<!-- Telescope details will be loaded here -->
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const loadingState = document.getElementById('loadingState');
const resultsCount = document.getElementById('resultsCount');
const telescopesGrid = document.getElementById('telescopesGrid');
const emptyState = document.getElementById('emptyState');
const telescopeCount = document.getElementById('telescopeCount');
const searchInput = document.getElementById('telescopeSearch');
const countryFilter = document.getElementById('countryFilter');
const typeFilter = document.getElementById('typeFilter');
const statusFilter = document.getElementById('statusFilter');
const clearFiltersBtn = document.getElementById('clearFilters');
let allTelescopes = [];
let filteredTelescopes = [];
function showLoading() {
loadingState.style.display = 'block';
resultsCount.style.display = 'none';
telescopesGrid.style.display = 'none';
emptyState.style.display = 'none';
}
function hideLoading() {
loadingState.style.display = 'none';
}
function showResults() {
resultsCount.style.display = 'block';
telescopesGrid.style.display = 'block';
emptyState.style.display = 'none';
}
function showEmpty() {
resultsCount.style.display = 'none';
telescopesGrid.style.display = 'none';
emptyState.style.display = 'block';
}
function getTelescopeTypeIcon(type) {
const typeIcons = {
'ground-based': 'fas fa-mountain',
'space-based': 'fas fa-satellite',
'radio': 'fas fa-broadcast-tower',
'infrared': 'fas fa-thermometer-half',
'x-ray': 'fas fa-radiation'
};
return typeIcons[type.toLowerCase()] || 'fas fa-telescope';
}
function getStatusBadge(status) {
const statusClasses = {
'operational': 'bg-success',
'decommissioned': 'bg-secondary',
'under construction': 'bg-warning'
};
const badgeClass = statusClasses[status.toLowerCase()] || 'bg-secondary';
return `<span class="badge ${badgeClass}" style="font-size: 0.7rem; padding: 0.2rem 0.4rem; box-shadow: 0 2px 4px rgba(0,0,0,0.3);">${status}</span>`;
}
function populateCountryFilter() {
const countries = [...new Set(allTelescopes.map(t => t.country))].sort();
countryFilter.innerHTML = '<option value="">All Countries</option>';
countries.forEach(country => {
countryFilter.innerHTML += `<option value="${country.toLowerCase()}">${country}</option>`;
});
}
function createTelescopeCard(telescope) {
const typeIcon = getTelescopeTypeIcon(telescope.type);
const statusBadge = getStatusBadge(telescope.status);
const yearText = telescope.year ? `${telescope.year}` : 'Unknown';
return `
<div class="col-lg-4 col-md-6 col-sm-12 mb-5">
<div class="card h-100 glow-on-hover" onclick="showTelescopeDetails('${telescope.id}')" style="cursor: pointer; min-height: 580px; margin-bottom: 2rem;">
<div class="position-relative">
<img src="${telescope.image_url}"
class="card-img-top"
alt="${telescope.name}"
onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';"
style="height: 200px; object-fit: cover; border-radius: 12px 12px 0 0;">
<div class="d-none align-items-center justify-content-center bg-glass" style="height: 200px; border-radius: 12px 12px 0 0;">
<i class="fas fa-telescope fa-3x text-muted"></i>
</div>
<div class="position-absolute" style="top: 8px; right: 8px; z-index: 20;">
${statusBadge}
</div>
<div class="position-absolute" style="top: 8px; left: 8px; z-index: 20;">
<span class="badge bg-primary" style="font-size: 0.7rem; padding: 0.2rem 0.4rem; box-shadow: 0 2px 4px rgba(0,0,0,0.3);">${telescope.type}</span>
</div>
</div>
<div class="card-body d-flex flex-column" style="padding: 1.5rem; padding-top: 1.8rem;">
<h5 class="card-title text-center text-primary" style="margin-bottom: 1.2rem; font-size: 1.1rem; line-height: 1.3; min-height: 2.6rem; display: flex; align-items: center; justify-content: center;">${telescope.name}</h5>
<p class="card-text flex-grow-1 text-light" style="margin-bottom: 1.5rem; font-size: 0.85rem; line-height: 1.4; min-height: 4rem;">${telescope.description.substring(0, 110)}${telescope.description.length > 110 ? '...' : ''}</p>
<div class="telescope-stats" style="margin-bottom: 1.5rem; border-top: 1px solid rgba(255,255,255,0.1); padding-top: 1rem;">
<div class="d-flex justify-content-between align-items-center" style="margin-bottom: 0.6rem;">
<small class="text-muted" style="font-size: 0.75rem;">
<i class="fas fa-calendar me-1"></i>Year:
</small>
<small class="text-light" style="font-size: 0.75rem;">${yearText}</small>
</div>
<div class="d-flex justify-content-between align-items-center" style="margin-bottom: 0.6rem;">
<small class="text-muted" style="font-size: 0.75rem;">
<i class="fas fa-flag me-1"></i>Country:
</small>
<small class="text-light" style="font-size: 0.75rem;">${telescope.country}</small>
</div>
${telescope.aperture ? `
<div class="d-flex justify-content-between align-items-center" style="margin-bottom: 0.6rem;">
<small class="text-muted" style="font-size: 0.75rem;">
<i class="fas fa-circle me-1"></i>Aperture:
</small>
<small class="text-light" style="font-size: 0.75rem;">${telescope.aperture}</small>
</div>
` : ''}
</div>
<div class="d-flex justify-content-between align-items-center mt-auto" style="padding-top: 1rem; border-top: 1px solid rgba(255,255,255,0.1);">
<small class="text-primary" style="font-size: 0.75rem;">
<i class="${typeIcon} me-1"></i>${telescope.type}
</small>
<small class="text-muted" style="font-size: 0.75rem;">Click for details</small>
</div>
</div>
</div>
</div>
`;
}
function renderTelescopes(telescopes) {
const grid = document.getElementById('telescopesGrid');
const countElement = document.getElementById('telescopeCount');
const emptyState = document.getElementById('emptyState');
countElement.textContent = telescopes.length;
if (telescopes.length === 0) {
grid.style.display = 'none';
emptyState.style.display = 'block';
document.getElementById('resultsCount').style.display = 'none';
return;
}
grid.style.display = 'flex';
grid.style.flexWrap = 'wrap';
emptyState.style.display = 'none';
document.getElementById('resultsCount').style.display = 'block';
grid.innerHTML = telescopes.map(createTelescopeCard).join('');
}
function filterTelescopes() {
const searchTerm = searchInput.value.toLowerCase();
const countryValue = countryFilter.value.toLowerCase();
const typeValue = typeFilter.value.toLowerCase();
const statusValue = statusFilter.value.toLowerCase();
filteredTelescopes = allTelescopes.filter(telescope => {
const matchesSearch = !searchTerm ||
telescope.name.toLowerCase().includes(searchTerm) ||
telescope.description.toLowerCase().includes(searchTerm) ||
telescope.country.toLowerCase().includes(searchTerm) ||
telescope.inventor.toLowerCase().includes(searchTerm);
const matchesCountry = !countryValue || telescope.country.toLowerCase() === countryValue;
const matchesType = !typeValue || telescope.type.toLowerCase() === typeValue;
const matchesStatus = !statusValue || telescope.status.toLowerCase() === statusValue;
return matchesSearch && matchesCountry && matchesType && matchesStatus;
});
renderTelescopes(filteredTelescopes);
}
function clearFilters() {
searchInput.value = '';
countryFilter.value = '';
typeFilter.value = '';
statusFilter.value = '';
filteredTelescopes = [...allTelescopes];
renderTelescopes(filteredTelescopes);
}
window.showTelescopeDetails = function(telescopeId) {
const telescope = allTelescopes.find(t => t.id === telescopeId);
if (!telescope) return;
const modalLabel = document.getElementById('telescopeModalLabel');
const modalContent = document.getElementById('telescopeModalContent');
modalLabel.textContent = telescope.name;
const typeIcon = getTelescopeTypeIcon(telescope.type);
const statusBadge = getStatusBadge(telescope.status);
const yearText = telescope.year ? `${telescope.year}` : 'Unknown';
const keyDiscoveries = telescope.key_discoveries ?
telescope.key_discoveries.map(discovery => `<li>${discovery}</li>`).join('') :
'<li>No key discoveries listed</li>';
modalContent.innerHTML = `
<div class="row">
<div class="col-md-4">
<img src="${telescope.image_url}" class="img-fluid rounded mb-3" alt="${telescope.name}"
onerror="this.src='https://via.placeholder.com/400x300/1a1a2e/ffffff?text=Telescope+Image+Not+Available'">
</div>
<div class="col-md-8">
<div class="mb-3">
<h6 class="text-primary mb-2">Basic Information</h6>
<p class="mb-1"><strong>Year:</strong> ${yearText}</p>
<p class="mb-1"><strong>Type:</strong> <i class="${typeIcon} me-1"></i>${telescope.type}</p>
<p class="mb-1"><strong>Country:</strong> ${telescope.country}</p>
<p class="mb-1"><strong>Agency:</strong> ${telescope.agency || 'N/A'}</p>
<p class="mb-1"><strong>Inventor:</strong> ${telescope.inventor || 'N/A'}</p>
<p class="mb-1"><strong>Status:</strong> ${statusBadge}</p>
${telescope.aperture ? `<p class="mb-1"><strong>Aperture:</strong> ${telescope.aperture}</p>` : ''}
${telescope.budget ? `<p class="mb-1"><strong>Budget:</strong> ${telescope.budget}</p>` : ''}
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-12">
<h6 class="text-primary mb-2">Description</h6>
<p class="text-light">${telescope.description}</p>
</div>
</div>
${telescope.key_discoveries ? `
<div class="row mt-4">
<div class="col-12">
<h6 class="text-primary mb-2">Key Discoveries</h6>
<ul class="text-light">
${keyDiscoveries}
</ul>
</div>
</div>
` : ''}
`;
const modal = new bootstrap.Modal(document.getElementById('telescopeModal'));
modal.show();
};
// Load telescopes data
showLoading();
fetch('/api/telescopes')
.then(response => response.json())
.then(data => {
allTelescopes = data;
filteredTelescopes = [...allTelescopes];
populateCountryFilter();
renderTelescopes(filteredTelescopes);
hideLoading();
})
.catch(error => {
console.error('Error loading telescopes:', error);
hideLoading();
showEmpty();
});
// Event listeners
searchInput.addEventListener('input', filterTelescopes);
countryFilter.addEventListener('change', filterTelescopes);
typeFilter.addEventListener('change', filterTelescopes);
statusFilter.addEventListener('change', filterTelescopes);
clearFiltersBtn.addEventListener('click', clearFilters);
});
</script>
{% endblock %}