Spaces:
Runtime error
Runtime error
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Contributors - TreeTrack</title> | |
| <link rel="stylesheet" href="/static/css/design-system.css"> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"> | |
| <!-- Leaflet CSS for background map --> | |
| <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" crossorigin=""> | |
| <style> | |
| /* Contributors Page - Matching Welcome Design */ | |
| :root { | |
| --forest-primary: #1a2e1a; | |
| --forest-secondary: #2d4a2d; | |
| --earth-accent: #4a5d4a; | |
| --sky-light: #f0f6f0; | |
| --energy-orange: #f97316; | |
| --cream-white: #fefefe; | |
| } | |
| body { | |
| margin: 0; | |
| font-family: 'Inter', sans-serif; | |
| min-height: 100vh; | |
| overflow-x: hidden; | |
| position: relative; | |
| } | |
| /* Background Map Display */ | |
| #background-map { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| z-index: 0; | |
| opacity: 0; | |
| transition: opacity 1s ease-in-out; | |
| } | |
| #background-map.loaded { | |
| opacity: 1; | |
| } | |
| /* Overlay for better text contrast */ | |
| .map-overlay { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: linear-gradient(135deg, | |
| rgba(26, 46, 26, 0.85) 0%, | |
| rgba(45, 74, 45, 0.75) 60%, | |
| rgba(74, 93, 74, 0.8) 100%); | |
| z-index: 1; | |
| pointer-events: none; | |
| } | |
| /* Content overlay with glassmorphism */ | |
| .content-overlay { | |
| position: relative; | |
| z-index: 2; | |
| min-height: 100vh; | |
| backdrop-filter: blur(1px); | |
| } | |
| /* Back Button */ | |
| .back-btn { | |
| position: fixed; | |
| top: 2rem; | |
| left: 2rem; | |
| z-index: 1000; | |
| background: rgba(255, 255, 255, 0.15); | |
| color: white; | |
| border: 1px solid rgba(255, 255, 255, 0.3); | |
| padding: 0.75rem 1.5rem; | |
| border-radius: 0.5rem; | |
| cursor: pointer; | |
| font-weight: 600; | |
| font-size: 0.875rem; | |
| backdrop-filter: blur(10px); | |
| transition: all 0.3s ease; | |
| text-decoration: none; | |
| } | |
| .back-btn:hover { | |
| background: rgba(255, 255, 255, 0.25); | |
| transform: translateY(-2px); | |
| box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2); | |
| } | |
| /* Hero Section */ | |
| .hero-section { | |
| min-height: 100vh; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| position: relative; | |
| background: transparent; | |
| padding: 2rem; | |
| } | |
| .contributors-container { | |
| max-width: 900px; | |
| width: 90%; | |
| text-align: center; | |
| color: white; | |
| z-index: 2; | |
| } | |
| .hero-badge { | |
| display: inline-block; | |
| background: rgba(255, 255, 255, 0.12); | |
| backdrop-filter: blur(10px); | |
| padding: 8px 24px; | |
| border-radius: 50px; | |
| font-size: 0.875rem; | |
| font-weight: 500; | |
| margin-bottom: 2rem; | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| } | |
| .hero-title { | |
| font-size: clamp(2.5rem, 6vw, 4rem); | |
| font-weight: 700; | |
| margin-bottom: 1rem; | |
| line-height: 1.1; | |
| background: linear-gradient(135deg, white, rgba(255, 255, 255, 0.8)); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| } | |
| .hero-subtitle { | |
| font-size: clamp(1rem, 2.5vw, 1.25rem); | |
| margin-bottom: 2rem; | |
| opacity: 0.9; | |
| font-weight: 400; | |
| } | |
| /* Contributors Content */ | |
| .contributors-content { | |
| background: rgba(255, 255, 255, 0.08); | |
| backdrop-filter: blur(20px); | |
| -webkit-backdrop-filter: blur(20px); | |
| border: 1px solid rgba(255, 255, 255, 0.15); | |
| border-radius: 2rem; | |
| padding: 3rem; | |
| margin: 2rem auto; | |
| box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); | |
| max-width: 700px; | |
| } | |
| .team-section { | |
| margin-bottom: 3rem; | |
| } | |
| .section-title { | |
| font-size: 1.5rem; | |
| font-weight: 600; | |
| margin-bottom: 1.5rem; | |
| color: rgba(255, 255, 255, 0.95); | |
| position: relative; | |
| display: inline-block; | |
| } | |
| .section-title::after { | |
| content: ''; | |
| position: absolute; | |
| bottom: -8px; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| width: 40px; | |
| height: 2px; | |
| background: var(--energy-orange); | |
| border-radius: 2px; | |
| } | |
| .team-member { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| margin-bottom: 1.5rem; | |
| padding: 1rem; | |
| background: rgba(255, 255, 255, 0.05); | |
| border-radius: 1rem; | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| transition: all 0.3s ease; | |
| } | |
| .team-member:hover { | |
| background: rgba(255, 255, 255, 0.1); | |
| transform: translateY(-2px); | |
| } | |
| .member-role { | |
| font-size: 0.875rem; | |
| color: rgba(255, 255, 255, 0.7); | |
| margin-right: 1rem; | |
| min-width: 120px; | |
| text-align: right; | |
| } | |
| .member-name { | |
| font-size: 1.125rem; | |
| font-weight: 600; | |
| color: rgba(255, 255, 255, 0.95); | |
| } | |
| .member-link { | |
| color: var(--energy-orange); | |
| text-decoration: none; | |
| transition: all 0.2s ease; | |
| border-bottom: 1px solid transparent; | |
| } | |
| .member-link:hover { | |
| color: #fbbf24; | |
| border-bottom-color: #fbbf24; | |
| transform: translateY(-1px); | |
| } | |
| .supporters-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
| gap: 1rem; | |
| margin-top: 2rem; | |
| } | |
| .supporter-item { | |
| background: rgba(255, 255, 255, 0.06); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: 1rem; | |
| padding: 1.5rem 1rem; | |
| text-align: center; | |
| transition: all 0.3s ease; | |
| } | |
| .supporter-item:hover { | |
| background: rgba(255, 255, 255, 0.12); | |
| transform: translateY(-3px); | |
| } | |
| .supporter-name { | |
| font-weight: 600; | |
| font-size: 1rem; | |
| color: rgba(255, 255, 255, 0.95); | |
| } | |
| .project-description { | |
| font-size: 1rem; | |
| line-height: 1.7; | |
| opacity: 0.9; | |
| margin: 2rem 0; | |
| text-align: left; | |
| } | |
| .back-button { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| background: rgba(255, 255, 255, 0.15); | |
| color: white; | |
| text-decoration: none; | |
| padding: 1rem 2rem; | |
| border-radius: 0.75rem; | |
| font-weight: 600; | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| backdrop-filter: blur(10px); | |
| transition: all 0.3s ease; | |
| margin-top: 2rem; | |
| } | |
| .back-button:hover { | |
| background: rgba(255, 255, 255, 0.25); | |
| transform: translateY(-2px); | |
| box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); | |
| } | |
| /* Responsive Design */ | |
| @media (max-width: 768px) { | |
| .contributors-container { | |
| width: 95%; | |
| } | |
| .contributors-content { | |
| padding: 2rem 1.5rem; | |
| margin: 1rem auto; | |
| } | |
| .team-member { | |
| flex-direction: column; | |
| text-align: center; | |
| } | |
| .member-role { | |
| text-align: center; | |
| margin-right: 0; | |
| margin-bottom: 0.5rem; | |
| min-width: auto; | |
| } | |
| .supporters-grid { | |
| grid-template-columns: 1fr; | |
| } | |
| .back-btn { | |
| top: 1rem; | |
| left: 1rem; | |
| padding: 0.5rem 1rem; | |
| font-size: 0.8rem; | |
| } | |
| } | |
| width: 100px; | |
| height: 100px; | |
| font-size: 2.5rem; | |
| } | |
| .action-buttons { | |
| flex-direction: column; | |
| align-items: center; | |
| } | |
| .btn { | |
| width: 100%; | |
| max-width: 300px; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- Background Map --> | |
| <div id="background-map"></div> | |
| <!-- Overlay for Better Text Contrast --> | |
| <div class="map-overlay"></div> | |
| <!-- Content Overlay --> | |
| <div class="content-overlay"> | |
| <!-- Back Button --> | |
| <a href="/welcome" class="back-btn">← Back to Homepage</a> | |
| <div class="hero-section"> | |
| <div class="contributors-container"> | |
| <div class="hero-badge">Tezpur, Assam</div> | |
| <h1 class="hero-title">Contributors</h1> | |
| <div class="hero-subtitle">Meet the people behind TreeTrack</div> | |
| <div class="contributors-content"> | |
| <div class="project-description"> | |
| TreeTrack is a collaborative forest research platform dedicated to mapping and | |
| conserving the biodiversity of Tezpur, Assam. This project combines | |
| web technology with traditional field research to create a | |
| digital repository of local tree species and their ecological significance. | |
| </div> | |
| <div class="team-section"> | |
| <h3 class="section-title">Core Team</h3> | |
| <div class="team-member"> | |
| <div class="member-role">Data Collection</div> | |
| <div class="member-name">Jeeb Das, Ishita Mohan, Deep Das</div> | |
| </div> | |
| <div class="team-member"> | |
| <div class="member-role">Web App Developer</div> | |
| <div class="member-name"> | |
| <a href="https://royaalekh.github.io/" target="_blank" class="member-link">Aalekh Roy</a> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="team-section"> | |
| <h3 class="section-title">Supporting Organizations</h3> | |
| <div class="supporters-grid"> | |
| <div class="supporter-item"> | |
| <div class="supporter-name">Greenhub</div> | |
| </div> | |
| <div class="supporter-item"> | |
| <div class="supporter-name">Royal Enfield</div> | |
| </div> | |
| <div class="supporter-item"> | |
| <div class="supporter-name">Rohini Nilekani Philanthropies</div> | |
| </div> | |
| </div> | |
| </div> | |
| <a href="/welcome" class="back-button"> | |
| ← Return to Homepage | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Leaflet JavaScript --> | |
| <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" crossorigin=""></script> | |
| <script> | |
| // Initialize Background Map Display | |
| function initializeMap() { | |
| // Tezpur, Assam coordinates | |
| const tezpurCoords = [26.6340, 92.7840]; | |
| // Create map instance for background display | |
| const map = L.map('background-map', { | |
| center: tezpurCoords, | |
| zoom: 12, | |
| zoomControl: false, | |
| scrollWheelZoom: false, | |
| doubleClickZoom: false, | |
| boxZoom: false, | |
| keyboard: false, | |
| dragging: false, | |
| touchZoom: false, | |
| attributionControl: false | |
| }); | |
| // Disable all interactions for decorative display only | |
| map.getContainer().style.cursor = 'default'; | |
| // Add satellite/terrain tile layer for background | |
| const satelliteLayer = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { | |
| maxZoom: 19, | |
| attribution: false | |
| }); | |
| const terrainLayer = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', { | |
| maxZoom: 17, | |
| attribution: false | |
| }); | |
| // Use satellite as primary, terrain as fallback | |
| satelliteLayer.on('tileerror', function() { | |
| console.log('Satellite layer failed, switching to terrain...'); | |
| map.removeLayer(satelliteLayer); | |
| terrainLayer.addTo(map); | |
| }); | |
| satelliteLayer.addTo(map); | |
| // Add decorative markers for Tezpur area | |
| const areaPoints = [ | |
| {coords: [26.6340, 92.7840], name: "Tezpur Center"}, | |
| {coords: [26.6500, 92.7900], name: "Research Area North"}, | |
| {coords: [26.6200, 92.7700], name: "Research Area South"}, | |
| {coords: [26.6400, 92.8000], name: "Research Area East"} | |
| ]; | |
| areaPoints.forEach(point => { | |
| L.circleMarker(point.coords, { | |
| radius: 3, | |
| fillColor: '#8ab070', | |
| color: '#739b5a', | |
| weight: 1, | |
| opacity: 0.6, | |
| fillOpacity: 0.4 | |
| }).addTo(map); | |
| }); | |
| // Fade in map when tiles are loaded | |
| satelliteLayer.on('load', function() { | |
| setTimeout(() => { | |
| document.getElementById('background-map').classList.add('loaded'); | |
| }, 500); | |
| }); | |
| // Fallback fade-in after 3 seconds | |
| setTimeout(() => { | |
| document.getElementById('background-map').classList.add('loaded'); | |
| }, 3000); | |
| } | |
| // Authentication check | |
| async function checkAuth() { | |
| const token = localStorage.getItem('auth_token'); | |
| if (!token) { | |
| window.location.href = '/login'; | |
| return; | |
| } | |
| try { | |
| const response = await fetch('/api/auth/validate', { | |
| headers: { | |
| 'Authorization': `Bearer ${token}` | |
| } | |
| }); | |
| if (!response.ok) { | |
| localStorage.removeItem('auth_token'); | |
| localStorage.removeItem('user_info'); | |
| window.location.href = '/login'; | |
| } | |
| } catch (error) { | |
| console.error('Auth check failed:', error); | |
| window.location.href = '/login'; | |
| } | |
| } | |
| // Initialize page | |
| document.addEventListener('DOMContentLoaded', () => { | |
| checkAuth(); | |
| // Small delay to ensure DOM is fully ready | |
| setTimeout(initializeMap, 200); | |
| }); | |
| // Fallback initialization | |
| window.addEventListener('load', function() { | |
| if (!document.getElementById('background-map').hasChildNodes()) { | |
| initializeMap(); | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |