diff --git a/app.py b/app.py index a20216b..677e3fd 100644 --- a/app.py +++ b/app.py @@ -25,7 +25,7 @@ from typing import Any from flask import Flask, render_template, jsonify, send_file, Response, request -from config import VERSION +from config import VERSION, CHANGELOG from utils.dependencies import check_tool, check_all_dependencies, TOOL_DEPENDENCIES from utils.process import cleanup_stale_processes from utils.sdr import SDRFactory @@ -164,7 +164,7 @@ def index() -> str: 'rtl_433': check_tool('rtl_433') } devices = [d.to_dict() for d in SDRFactory.detect_devices()] - return render_template('index.html', tools=tools, devices=devices, version=VERSION) + return render_template('index.html', tools=tools, devices=devices, version=VERSION, changelog=CHANGELOG) @app.route('/favicon.svg') diff --git a/config.py b/config.py index 5bd4ec8..666c2d0 100644 --- a/config.py +++ b/config.py @@ -9,6 +9,40 @@ import sys # Application version VERSION = "2.9.0" +# Changelog - latest release notes (shown on welcome screen) +CHANGELOG = [ + { + "version": "2.9.0", + "date": "January 2026", + "highlights": [ + "New dropdown navigation menus for cleaner UI", + "TSCM baseline recording now captures device data", + "Device identity engine integration for threat detection", + "Welcome screen with mode selection", + ] + }, + { + "version": "2.8.0", + "date": "December 2025", + "highlights": [ + "Added TSCM counter-surveillance mode", + "WiFi/Bluetooth device correlation engine", + "Tracker detection (AirTag, Tile, SmartTag)", + "Risk scoring and threat classification", + ] + }, + { + "version": "2.7.0", + "date": "November 2025", + "highlights": [ + "Multi-SDR hardware support via SoapySDR", + "LimeSDR, HackRF, Airspy, SDRplay support", + "Improved aircraft database with photo lookup", + "GPS auto-detection and integration", + ] + }, +] + def _get_env(key: str, default: str) -> str: """Get environment variable with default.""" diff --git a/static/css/index.css b/static/css/index.css index 8838c3e..6f5586a 100644 --- a/static/css/index.css +++ b/static/css/index.css @@ -83,10 +83,10 @@ body { } /* ============================================ - LANDING PAGE / SPLASH SCREEN + WELCOME PAGE ============================================ */ -.landing-overlay { +.welcome-overlay { position: fixed; top: 0; left: 0; @@ -100,7 +100,7 @@ body { overflow: hidden; } -.landing-overlay::before { +.welcome-overlay::before { content: ''; position: absolute; top: 0; @@ -113,13 +113,14 @@ body { pointer-events: none; } -.landing-content { - text-align: center; +.welcome-container { + width: 90%; + max-width: 900px; z-index: 1; - animation: landingFadeIn 1s ease-out; + animation: welcomeFadeIn 0.8s ease-out; } -@keyframes landingFadeIn { +@keyframes welcomeFadeIn { from { opacity: 0; transform: translateY(20px); @@ -130,46 +131,44 @@ body { } } -.landing-logo { +/* Welcome Header */ +.welcome-header { + display: flex; + align-items: center; + justify-content: center; + gap: 20px; margin-bottom: 30px; + padding-bottom: 20px; + border-bottom: 1px solid var(--border-color); +} + +.welcome-logo { animation: logoPulse 3s ease-in-out infinite; } @keyframes logoPulse { 0%, 100% { - filter: drop-shadow(0 0 20px rgba(0, 212, 255, 0.3)); + filter: drop-shadow(0 0 15px rgba(0, 212, 255, 0.3)); } 50% { - filter: drop-shadow(0 0 40px rgba(0, 212, 255, 0.6)); + filter: drop-shadow(0 0 30px rgba(0, 212, 255, 0.6)); } } -.landing-logo .signal-wave { +.welcome-logo .signal-wave { animation: signalPulse 2s ease-in-out infinite; } -.landing-logo .signal-wave-1 { - animation-delay: 0s; -} - -.landing-logo .signal-wave-2 { - animation-delay: 0.2s; -} - -.landing-logo .signal-wave-3 { - animation-delay: 0.4s; -} +.welcome-logo .signal-wave-1 { animation-delay: 0s; } +.welcome-logo .signal-wave-2 { animation-delay: 0.2s; } +.welcome-logo .signal-wave-3 { animation-delay: 0.4s; } @keyframes signalPulse { - 0%, 100% { - opacity: 0.3; - } - 50% { - opacity: 1; - } + 0%, 100% { opacity: 0.3; } + 50% { opacity: 1; } } -.landing-logo .logo-dot { +.welcome-logo .logo-dot { animation: dotPulse 1.5s ease-in-out infinite; } @@ -184,119 +183,239 @@ body { } } -.landing-title { +.welcome-title-block { + text-align: left; +} + +.welcome-title { font-family: 'JetBrains Mono', monospace; - font-size: 4rem; + font-size: 2.5rem; font-weight: 700; color: var(--text-primary); - letter-spacing: 0.3em; - margin: 0 0 10px 0; - text-shadow: 0 0 30px rgba(0, 212, 255, 0.3); -} - -.landing-tagline { - font-family: 'JetBrains Mono', monospace; - font-size: 1.2rem; - color: #00d4ff; letter-spacing: 0.2em; - margin: 0 0 8px 0; - opacity: 0.9; + margin: 0; + text-shadow: 0 0 20px rgba(0, 212, 255, 0.3); } -.landing-subtitle { - font-family: 'Inter', sans-serif; +.welcome-tagline { + font-family: 'JetBrains Mono', monospace; font-size: 0.9rem; - color: var(--text-secondary); + color: var(--accent-cyan); letter-spacing: 0.15em; + margin: 4px 0 0 0; +} + +.welcome-version { + display: inline-block; + font-family: 'JetBrains Mono', monospace; + font-size: 0.65rem; + color: var(--bg-primary); + background: var(--accent-cyan); + padding: 2px 8px; + border-radius: 3px; + letter-spacing: 0.05em; + margin-top: 8px; +} + +/* Welcome Content Grid */ +.welcome-content { + display: grid; + grid-template-columns: 1fr 1.5fr; + gap: 30px; + margin-bottom: 20px; +} + +.welcome-content h2 { + font-family: 'JetBrains Mono', monospace; + font-size: 0.75rem; + color: var(--text-secondary); text-transform: uppercase; - margin: 0 0 40px 0; + letter-spacing: 0.15em; + margin: 0 0 15px 0; + padding-bottom: 8px; + border-bottom: 1px solid var(--border-color); } -.landing-enter-btn { - background: transparent; - border: 2px solid #00d4ff; - color: #00d4ff; - padding: 15px 50px; - font-family: 'JetBrains Mono', monospace; - font-size: 1rem; - letter-spacing: 0.2em; - cursor: pointer; - transition: all 0.3s ease; - display: inline-flex; +/* Changelog Section */ +.welcome-changelog { + background: var(--bg-secondary); + border: 1px solid var(--border-color); + border-radius: 8px; + padding: 20px; + max-height: 320px; + overflow-y: auto; +} + +.changelog-release { + margin-bottom: 20px; +} + +.changelog-release:last-child { + margin-bottom: 0; +} + +.changelog-version-header { + display: flex; align-items: center; - gap: 15px; - position: relative; - overflow: hidden; + gap: 10px; + margin-bottom: 10px; } -.landing-enter-btn::before { - content: ''; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(0, 212, 255, 0.2), transparent); - transition: left 0.5s ease; -} - -.landing-enter-btn:hover::before { - left: 100%; -} - -.landing-enter-btn:hover { - background: rgba(0, 212, 255, 0.1); - box-shadow: 0 0 30px rgba(0, 212, 255, 0.3), inset 0 0 20px rgba(0, 212, 255, 0.1); - transform: scale(1.02); -} - -.landing-enter-btn .btn-icon { - transition: transform 0.3s ease; -} - -.landing-enter-btn:hover .btn-icon { - transform: translateX(5px); -} - -.landing-version { +.changelog-version { font-family: 'JetBrains Mono', monospace; + font-size: 0.8rem; + color: var(--accent-cyan); + font-weight: 600; +} + +.changelog-date { + font-family: 'Inter', sans-serif; font-size: 0.7rem; color: var(--text-dim); - margin-top: 30px; - letter-spacing: 0.1em; } -.landing-scanline { +.changelog-list { + margin: 0; + padding-left: 18px; + list-style: none; +} + +.changelog-list li { + font-family: 'Inter', sans-serif; + font-size: 0.75rem; + color: var(--text-secondary); + margin-bottom: 6px; + position: relative; +} + +.changelog-list li::before { + content: '>'; + position: absolute; + left: -15px; + color: var(--accent-green); + font-family: 'JetBrains Mono', monospace; +} + +/* Mode Selection Grid */ +.welcome-modes { + background: var(--bg-secondary); + border: 1px solid var(--border-color); + border-radius: 8px; + padding: 20px; +} + +.mode-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 10px; +} + +.mode-card { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 15px 10px; + background: var(--bg-tertiary); + border: 1px solid var(--border-color); + border-radius: 6px; + cursor: pointer; + transition: all 0.2s ease; + text-align: center; +} + +.mode-card:hover { + background: var(--bg-elevated); + border-color: var(--accent-cyan); + transform: translateY(-2px); + box-shadow: 0 4px 20px rgba(0, 212, 255, 0.15); +} + +.mode-card:active { + transform: translateY(0); +} + +.mode-card .mode-icon { + font-size: 1.5rem; + margin-bottom: 6px; +} + +.mode-card .mode-name { + font-family: 'JetBrains Mono', monospace; + font-size: 0.75rem; + font-weight: 600; + color: var(--text-primary); + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.mode-card .mode-desc { + font-family: 'Inter', sans-serif; + font-size: 0.65rem; + color: var(--text-dim); + margin-top: 4px; +} + +/* Welcome Footer */ +.welcome-footer { + text-align: center; + padding-top: 15px; + border-top: 1px solid var(--border-color); +} + +.welcome-footer p { + font-family: 'Inter', sans-serif; + font-size: 0.7rem; + color: var(--text-dim); + letter-spacing: 0.1em; + text-transform: uppercase; + margin: 0; +} + +/* Welcome Scanline */ +.welcome-scanline { position: absolute; top: 0; left: 0; width: 100%; - height: 3px; - background: linear-gradient(90deg, transparent, #00d4ff, transparent); - animation: scanlineMove 4s linear infinite; - opacity: 0.5; + height: 2px; + background: linear-gradient(90deg, transparent, var(--accent-cyan), transparent); + animation: scanlineMove 5s linear infinite; + opacity: 0.4; } @keyframes scanlineMove { - 0% { - top: 0; - } - 100% { - top: 100%; - } + 0% { top: 0; } + 100% { top: 100%; } } -.landing-overlay.fade-out { - animation: landingFadeOut 0.5s ease-in forwards; +/* Welcome Fade Out */ +.welcome-overlay.fade-out { + animation: welcomeFadeOut 0.4s ease-in forwards; } -@keyframes landingFadeOut { - from { - opacity: 1; +@keyframes welcomeFadeOut { + from { opacity: 1; } + to { opacity: 0; visibility: hidden; } +} + +/* Responsive */ +@media (max-width: 768px) { + .welcome-content { + grid-template-columns: 1fr; } - to { - opacity: 0; - visibility: hidden; + + .welcome-header { + flex-direction: column; + text-align: center; + } + + .welcome-title-block { + text-align: center; + } + + .mode-grid { + grid-template-columns: repeat(2, 1fr); } } diff --git a/templates/index.html b/templates/index.html index eb69fbd..d62fb4b 100644 --- a/templates/index.html +++ b/templates/index.html @@ -17,36 +17,111 @@
- -