--- a +++ b/web_structure.txt @@ -0,0 +1,14915 @@ +Directory: . +================================================== +File: ./web/style.css.new +-------------------------------------------------- +/* DNA Helix Animation */ +.dna-helix { + position: relative; + width: 200px; + height: 400px; + margin: 0 auto; + perspective: 1200px; + transform-style: preserve-3d; +} + +.base-pair { + position: absolute; + width: 100%; + height: 20px; + animation: rotate 8s linear infinite; + transform-style: preserve-3d; +} + +.base { + position: absolute; + width: 25px; + height: 25px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; + color: white; + text-shadow: 0 0 3px rgba(0,0,0,0.5); + box-shadow: 0 0 15px rgba(0,0,0,0.2); +} + +.left-base { + left: 35px; + background: #FF0066; + animation: pulse 3s ease-in-out infinite; + filter: brightness(1.1); +} + +.right-base { + right: 35px; + background: #00B7FF; + animation: pulse 3s ease-in-out infinite; + filter: brightness(1.1); +} + +.base-connector { + position: absolute; + left: 50%; + width: 90px; + height: 3px; + background: linear-gradient(90deg, + rgba(255, 0, 102, 0.8), + rgba(255, 255, 255, 0.3) 50%, + rgba(0, 183, 255, 0.8) + ); + transform: translateX(-50%); + box-shadow: 0 0 8px rgba(0,0,0,0.15); +} + +@keyframes rotate { + 0% { transform: rotateY(0deg) translateZ(20px); } + 100% { transform: rotateY(360deg) translateZ(20px); } +} + +@keyframes pulse { + 0% { transform: scale(1); opacity: 0.9; filter: brightness(1.1); } + 50% { transform: scale(1.15); opacity: 1; filter: brightness(1.3); } + 100% { transform: scale(1); opacity: 0.9; filter: brightness(1.1); } +} + +-------------------------------------------------- +File: ./web/humans.txt +-------------------------------------------------- +contact@dnanalyzer.orgDNAnalyzer is built by a large team of engineers, designers, researchers, robots, and others in many different sites across the globe. It is updated continuously, and built with more tools and technologies than we can shake a stick at. If you'd like to help us out, see www.github.com/VerisimilitudeX/DNAnalyzer. We're always looking for more talent, and we're always looking for more ideas. If you have any suggestions, please let us know! We're always looking for ways to improve the site. If you have any questions, please feel free to contact us at contact@dnanalyzer.live. We'd love to hear from you! +-------------------------------------------------- +File: ./web/CITATION.cff +-------------------------------------------------- +cff-version: 1.2.0 +authors: + - family-names: Acharya + given-names: Piyush + orcid: "https://orcid.org/0009-0000-4726-5928" + +date-released: 2022-10-10 +message: "If you use this software, please cite it as below." +title: "DNAnalyzer: ML-Powered DNA Analysis Platform" +version: "3.5.0-beta.0" +url: "https://github.com/VerisimilitudeX/DNAnalyzer" +doi: "10.5281/zenodo.14556577" + +-------------------------------------------------- +File: ./web/all_files.py +-------------------------------------------------- +import os + +def save_directory_structure_and_files(root_dir, output_file): + with open(output_file, 'w', encoding='utf-8') as out: + for dirpath, dirnames, filenames in os.walk(root_dir): + # Write the directory name + rel_path = os.path.relpath(dirpath, root_dir) + out.write(f"Directory: {rel_path}\n") + out.write("=" * 50 + "\n") + + # Write file names and contents + for file in filenames: + file_path = os.path.join(dirpath, file) + out.write(f"File: {file_path}\n") # Include full file path + out.write("-" * 50 + "\n") + try: + with open(file_path, 'r', encoding='utf-8') as f: + out.write(f.read()) + except Exception as e: + out.write(f"[Could not read file: {e}]\n") + out.write("\n" + "-" * 50 + "\n") + out.write("\n") + +if __name__ == "__main__": + root_directory = "./web" + output_text_file = "web_structure.txt" + save_directory_structure_and_files(root_directory, output_text_file) + print(f"Directory structure and files saved to {output_text_file}") + +-------------------------------------------------- +File: ./web/index.js +-------------------------------------------------- +/** + * DNAnalyzer Main JavaScript + * Handles animations, interactivity and UI functionality + */ + +document.addEventListener('DOMContentLoaded', function() { + initNotificationBanner(); + initNotificationScroll(); // Must run after banner init to get height + initDNAHelix(); + initMobileMenu(); + initNavbarScroll(); + initStatsAnimation(); + initSmoothScroll(); + initScrollAnimations(); // Initialize general scroll animations + + // Log initialization + console.log("DNAnalyzer UI Initialized"); +}); + +// Shared state for notification banner +let notificationClosed = false; +let notificationHeight = 0; // Store banner height globally + +/** + * Initialize the notification banner dismiss functionality and store its height + */ +function initNotificationBanner() { + const banner = document.querySelector('.notification-banner'); + if (!banner) return; + + notificationHeight = banner.offsetHeight; + document.documentElement.style.setProperty('--notification-height', `${notificationHeight}px`); + console.log(`Notification banner height: ${notificationHeight}px`); + + const closeBtn = banner.querySelector('.notification-close'); + if (!closeBtn) return; + + closeBtn.addEventListener('click', function() { + banner.classList.add('closed'); // Hide immediately for visual feedback + notificationHeight = 0; // Set height to 0 + document.documentElement.style.setProperty('--notification-height', '0px'); + notificationClosed = true; + adjustNavbarPosition(); // Adjust navbar immediately + console.log("Notification banner closed"); + }); +} + +/** + * Adjusts the navbar's top position based on the notification banner's visibility. + */ +function adjustNavbarPosition() { + const navbar = document.getElementById('navbar'); + if (!navbar) return; + + const currentScroll = window.pageYOffset || document.documentElement.scrollTop; + const banner = document.querySelector('.notification-banner'); + + // If banner is closed or hidden by scroll, navbar top is 0 + if (notificationClosed || (banner && banner.classList.contains('hide-notification')) || currentScroll > notificationHeight) { + navbar.style.top = '0px'; + } + // Otherwise, position navbar below the banner + else if (!notificationClosed && banner && !banner.classList.contains('hide-notification')) { + navbar.style.top = `${notificationHeight}px`; + } + // Default case if something goes wrong + else { + navbar.style.top = '0px'; + } +} + + +/** + * Initialize notification banner scroll behavior (hide on scroll down, show on scroll up) + */ +function initNotificationScroll() { + const banner = document.querySelector('.notification-banner'); + if (!banner) return; + + let lastScrollTop = 0; + const scrollThreshold = 50; // Pixels to scroll before hiding/showing + + window.addEventListener('scroll', function() { + let scrollTop = window.pageYOffset || document.documentElement.scrollTop; + + // Ignore minor scroll fluctuations + if (Math.abs(scrollTop - lastScrollTop) <= 5) { + return; + } + + if (scrollTop > lastScrollTop && scrollTop > scrollThreshold) { + // Scrolling Down + if (!banner.classList.contains('hide-notification') && !notificationClosed) { + banner.classList.add('hide-notification'); + adjustNavbarPosition(); // Adjust navbar when banner hides + console.log("Hiding notification on scroll down"); + } + } else if (scrollTop < lastScrollTop || scrollTop <= scrollThreshold) { + // Scrolling Up or near top + if (banner.classList.contains('hide-notification') && !notificationClosed) { + banner.classList.remove('hide-notification'); + adjustNavbarPosition(); // Adjust navbar when banner shows + console.log("Showing notification on scroll up"); + } + } + + // Ensure correct navbar position even if banner wasn't hidden/shown + if (scrollTop <= scrollThreshold && !notificationClosed) { + banner.classList.remove('hide-notification'); + adjustNavbarPosition(); + } else if (scrollTop > scrollThreshold && !notificationClosed && banner.classList.contains('hide-notification')) { + adjustNavbarPosition(); // Keep navbar at top if banner is hidden + } else if (notificationClosed) { + adjustNavbarPosition(); // Keep navbar at top if banner is closed + } + + + lastScrollTop = scrollTop <= 0 ? 0 : scrollTop; // For Mobile or negative scrolling + }, { passive: true }); // Improve scroll performance +} + +/** + * Initialize the DNA Helix animation on the homepage + */ +function initDNAHelix() { + const dnaHelixContainer = document.getElementById('dnaHelix'); + if (!dnaHelixContainer) return; + + dnaHelixContainer.innerHTML = ''; // Clear existing + + const basePairsConfig = [ + { pair: ['A', 'T'], leftColor: 'var(--magenta)', rightColor: 'var(--blue)' }, + { pair: ['T', 'A'], leftColor: 'var(--blue)', rightColor: 'var(--magenta)' }, + { pair: ['G', 'C'], leftColor: 'var(--orange)', rightColor: '#34c759' }, // Added green + { pair: ['C', 'G'], leftColor: '#34c759', rightColor: 'var(--orange)' } + ]; + + const numBasePairs = 25; // Total number of pairs + const verticalSpacing = 20; // Space between pairs + const helixRadius = 50; // How far out the bases extend (Z-axis) + const rotationIncrement = 20; // Degrees twist per base pair + const animationDuration = 10; // seconds for full rotation + + for (let i = 0; i < numBasePairs; i++) { + const config = basePairsConfig[i % basePairsConfig.length]; // Cycle through colors/pairs + const [leftBaseChar, rightBaseChar] = config.pair; + + const basePairElement = document.createElement('div'); + basePairElement.className = 'base-pair'; + + // Vertical position + const yPos = (i - numBasePairs / 2) * verticalSpacing; // Center the helix vertically + basePairElement.style.transform = `translateY(${yPos}px)`; // Initial Y position + + // Calculate initial rotation angle and offsets for the helix shape + const angle = (i * rotationIncrement) % 360; + const xOffset = Math.sin(angle * Math.PI / 180) * 15; // Sideways curve + + // Store initial transform values in CSS variables for the animation + basePairElement.style.setProperty('--start-angle', `${angle}deg`); + basePairElement.style.setProperty('--x-offset', `${xOffset}px`); + + // Apply animation + const delay = (i * 0.1) % animationDuration; // Staggered animation start + basePairElement.style.animation = `rotate ${animationDuration}s linear infinite ${-delay}s`; + + // Create Left Base + const leftBase = document.createElement('div'); + leftBase.className = 'base left-base'; + leftBase.textContent = leftBaseChar; + leftBase.style.background = config.leftColor; + leftBase.style.animationDelay = `${(i * 0.15)}s`; // Stagger pulse + + // Create Right Base + const rightBase = document.createElement('div'); + rightBase.className = 'base right-base'; + rightBase.textContent = rightBaseChar; + rightBase.style.background = config.rightColor; + rightBase.style.animationDelay = `${(i * 0.15 + 0.1)}s`; // Stagger pulse slightly more + + // Create Connector + const connector = document.createElement('div'); + connector.className = 'base-connector'; + // Optional: Style connector dynamically if needed + + // Append elements + basePairElement.appendChild(leftBase); + basePairElement.appendChild(rightBase); + basePairElement.appendChild(connector); // Connector should be behind bases visually if needed + dnaHelixContainer.appendChild(basePairElement); + } + + // Adjust container height if needed (optional) + // dnaHelixContainer.style.height = `${numBasePairs * verticalSpacing + 100}px`; +} + + +/** + * Initialize the mobile menu toggle functionality + */ +function initMobileMenu() { + const mobileToggle = document.getElementById('mobileToggle'); + const navLinks = document.getElementById('navLinks'); + + if (!mobileToggle || !navLinks) return; + + mobileToggle.addEventListener('click', function() { + const isActive = navLinks.classList.toggle('active'); + mobileToggle.setAttribute('aria-expanded', isActive); + + const icon = mobileToggle.querySelector('i'); + if (isActive) { + icon.classList.remove('fa-bars'); + icon.classList.add('fa-times'); + } else { + icon.classList.remove('fa-times'); + icon.classList.add('fa-bars'); + } + }); + + // Close menu when a link is clicked + navLinks.querySelectorAll('a').forEach(link => { + link.addEventListener('click', () => { + if (navLinks.classList.contains('active')) { + navLinks.classList.remove('active'); + mobileToggle.setAttribute('aria-expanded', 'false'); + const icon = mobileToggle.querySelector('i'); + icon.classList.remove('fa-times'); + icon.classList.add('fa-bars'); + } + }); + }); +} + +/** + * Initialize the navbar scroll effect (adding 'scrolled' class) + */ +function initNavbarScroll() { + const navbar = document.getElementById('navbar'); + if (!navbar) return; + + const scrollThreshold = 30; // Pixels scrolled before adding class + + window.addEventListener('scroll', function() { + if (window.pageYOffset > scrollThreshold) { + navbar.classList.add('scrolled'); + } else { + navbar.classList.remove('scrolled'); + } + }, { passive: true }); +} + +/** + * Animate number counting from 0 to target with easing + */ +function animateNumber(element, targetString, suffix = '', duration = 2000) { + if (!element) return; + + const target = parseFloat(targetString.replace(/[^0-9.]/g, '')); // Extract number + if (isNaN(target)) { + element.textContent = targetString + suffix; // Fallback for non-numeric targets + return; + } + + let start = 0; + let startTime = null; + + // Easing function (easeOutExpo) + function easeOutExpo(t) { + return t === 1 ? 1 : 1 - Math.pow(2, -10 * t); + } + + function animationStep(timestamp) { + if (!startTime) startTime = timestamp; + const elapsed = timestamp - startTime; + const progress = Math.min(elapsed / duration, 1); + const easedProgress = easeOutExpo(progress); + + let currentValue = Math.floor(easedProgress * target); + + // Handle M+ and + suffixes correctly + let displaySuffix = suffix; + if (targetString.includes('M+')) { + currentValue = (easedProgress * target).toFixed(1); // Show decimal during animation + displaySuffix = 'M+'; + if (progress === 1) currentValue = target; // Ensure final value is integer if needed + } else if (targetString.includes('+') && suffix === '') { // Check if suffix wasn't passed but '+' exists + displaySuffix = '+'; + } + + // Prevent displaying 0M+ or 0+ initially + if (elapsed < 50 && currentValue === 0 && displaySuffix) { + element.textContent = 0; + } else { + element.textContent = `${currentValue}${displaySuffix}`; + } + + + if (progress < 1) { + requestAnimationFrame(animationStep); + } else { + // Ensure final display is exactly the target string + element.textContent = targetString.replace(/([0-9.]+)/, target) + displaySuffix; + + } + } + + requestAnimationFrame(animationStep); +} + + +/** + * Initialize the stats counter animation with Intersection Observer + */ +function initStatsAnimation() { + const statsSection = document.querySelector('.stats-section'); + if (!statsSection) return; + + const statElements = [ // Use array for easier iteration + { elem: document.getElementById('statAccuracy'), target: '141', suffix: '' }, + { elem: document.getElementById('statSequences'), target: '7M+', suffix: '' }, // Suffix handled in animateNumber + { elem: document.getElementById('statUsers'), target: '46+', suffix: '' } // Suffix handled in animateNumber + ]; + + let animated = false; + + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting && !animated) { + console.log("Stats section intersecting, animating numbers."); + statElements.forEach((stat, index) => { + setTimeout(() => { + if (stat.elem) { + // Pass target string directly, animateNumber handles extraction + animateNumber(stat.elem, stat.target, stat.suffix, 2000 + index * 100); + } + }, index * 200); // Stagger animation start + }); + + animated = true; + observer.unobserve(statsSection); // Stop observing once animated + } + }); + }, { threshold: 0.3 }); // Trigger when 30% visible + + observer.observe(statsSection); +} + +/** + * Add smooth scrolling for anchor links within the page + */ +function initSmoothScroll() { + document.querySelectorAll('a[href^="#"]').forEach(anchor => { + anchor.addEventListener('click', function(e) { + const targetId = this.getAttribute('href'); + // Ensure it's a valid internal link and not just "#" + if (targetId && targetId.length > 1 && targetId.startsWith('#')) { + try { + const targetElement = document.querySelector(targetId); + if (targetElement) { + e.preventDefault(); + const navbarHeight = document.getElementById('navbar')?.offsetHeight || 70; // Get current navbar height or default + const elementPosition = targetElement.getBoundingClientRect().top; + const offsetPosition = elementPosition + window.pageYOffset - navbarHeight - 20; // Extra 20px padding + + window.scrollTo({ + top: offsetPosition, + behavior: 'smooth' + }); + } + } catch (error) { + console.warn(`Smooth scroll target not found or invalid selector: ${targetId}`, error); + } + } + }); + }); +} + +/** + * Initialize Intersection Observer for general scroll-triggered animations + */ +function initScrollAnimations() { + const animatedElements = document.querySelectorAll('.scroll-animate, .scroll-animate-left, .scroll-animate-right, .scroll-animate-scale'); + + if (!animatedElements.length) return; + + const observerOptions = { + threshold: 0.15, // Trigger when 15% of the element is visible + rootMargin: '0px 0px -50px 0px' // Trigger slightly before element fully enters viewport bottom + }; + + const observer = new IntersectionObserver((entries, observer) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('animate-in'); + observer.unobserve(entry.target); // Stop observing once animated + } + }); + }, observerOptions); + + animatedElements.forEach(el => { + observer.observe(el); + }); + + console.log(`Observing ${animatedElements.length} elements for scroll animations.`); +} +-------------------------------------------------- +File: ./web/style.css +-------------------------------------------------- +/* DNAnalyzer - Main Stylesheet + * Global styles for all pages + */ + +/* Notification Banner Styling */ +.notification-banner { + background: linear-gradient(135deg, var(--orange), #FFB347); /* Adjusted gradient slightly */ + color: var(--dark-bg); /* Dark text for contrast */ + padding: 0.75rem 2.5rem 0.75rem 1rem; /* More padding on right for close button */ + text-align: center; + font-size: 0.95rem; /* Slightly smaller */ + font-weight: 500; /* Normal weight */ + position: fixed; + top: 0; + left: 0; + width: 100%; + z-index: 1000; /* High z-index */ + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); + transition: transform 0.4s ease-in-out, opacity 0.4s ease-in-out; + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); +} + +.notification-banner.hide-notification { + transform: translateY(-100%); + opacity: 0; + pointer-events: none; +} + +.notification-banner.closed { + display: none !important; /* Use !important carefully, needed here to override */ +} + +.notification-banner .notification-link { + color: var(--dark-bg); /* Dark text */ + text-decoration: underline; + font-weight: 600; /* Bold link */ + background-color: rgba(255, 255, 255, 0.3); + padding: 0.2rem 0.4rem; + border-radius: 4px; + margin: 0 0.4rem; + transition: all 0.2s ease; + white-space: nowrap; +} + +.notification-banner .notification-link:hover { + background-color: rgba(255, 255, 255, 0.5); + color: #000; /* Black on hover */ + text-decoration: none; +} + +.notification-banner .notification-close { + background: none; /* Transparent background */ + border: none; + color: var(--dark-bg); /* Dark color */ + font-size: 1.5rem; /* Larger close icon */ + line-height: 1; + position: absolute; + right: 0.75rem; /* Positioned closer */ + top: 50%; + transform: translateY(-50%); + cursor: pointer; + transition: all 0.2s ease; + width: 30px; /* Larger hit area */ + height: 30px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + padding: 0; + opacity: 0.7; +} + +.notification-banner .notification-close:hover { + background: rgba(0, 0, 0, 0.1); + opacity: 1; + transform: translateY(-50%) rotate(90deg); +} + +/* --- Root Variables --- */ +:root { + /* Brand colors from logo */ + --magenta: #ff0066; + --blue: #00a4ef; + --orange: #f48022; + --white: #ffffff; + --dark-bg: #001427; /* Deep Navy */ + + /* Additional UI colors */ + --dark-blue: #051e3e; /* Slightly lighter navy */ + --light-blue: #2596be; /* Accent blue */ + --light-gray: #f0f2f5; /* Off-white for light backgrounds if needed */ + --medium-gray: #a0a8b1; /* Text subtle */ + --dark-gray: #1e2a3a; /* Darker element backgrounds */ + + /* Functional colors */ + --success: #34c759; + --warning: #ffcc00; /* Brighter warning */ + --error: #ff3b30; + + /* Typography */ + --font-heading: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; + --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; + --font-mono: 'IBM Plex Mono', monospace; + + /* Spacing */ + --space-xs: 0.25rem; /* 4px */ + --space-sm: 0.5rem; /* 8px */ + --space-md: 1rem; /* 16px */ + --space-lg: 1.5rem; /* 24px */ + --space-xl: 2.5rem; /* 40px */ + --space-xxl: 4rem; /* 64px */ + + /* Border radius */ + --radius-sm: 4px; + --radius-md: 8px; + --radius-lg: 12px; + --radius-xl: 20px; + --radius-round: 50%; + + /* Shadows */ + --shadow-sm: 0 2px 4px rgba(0, 20, 39, 0.15); + --shadow-md: 0 5px 15px rgba(0, 20, 39, 0.2); + --shadow-lg: 0 10px 30px rgba(0, 20, 39, 0.25); + --shadow-glow-blue: 0 0 15px rgba(0, 164, 239, 0.3); + --shadow-glow-magenta: 0 0 15px rgba(255, 0, 102, 0.3); + + /* Transitions */ + --transition-fast: 0.2s ease; + --transition-normal: 0.4s ease; /* Slightly slower for smoother effect */ + --transition-slow: 0.6s ease; + + /* Z-index layers */ + --z-background: -1; + --z-base: 1; + --z-content: 10; + --z-sticky: 100; + --z-navbar: 900; /* Below notification */ + --z-notification: 1000; + --z-modal: 1100; + --z-tooltip: 1200; + + /* Notification Height - JS will set this */ + --notification-height: 0px; +} + +/* Reset & Base Styles */ +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html { + font-size: 16px; + scroll-behavior: smooth; + scroll-padding-top: 100px; /* Adjust for fixed navbar height */ +} + +body { + font-family: var(--font-body); + background-color: var(--dark-bg); + color: var(--medium-gray); /* Default text slightly softer */ + line-height: 1.7; /* Increased line-height */ + overflow-x: hidden; + min-height: 100vh; + display: flex; + flex-direction: column; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + position: relative; /* Needed for background elements */ +} + +/* Main content area */ +main { + flex-grow: 1; /* Ensure footer is pushed down */ +} + +h1, h2, h3, h4, h5, h6 { + font-family: var(--font-heading); + line-height: 1.3; + font-weight: 700; + margin-bottom: var(--space-md); + color: var(--white); /* Headings are white */ +} + +h1 { font-size: clamp(2.5rem, 5vw + 1rem, 3.8rem); margin-bottom: var(--space-lg); letter-spacing: -0.03em; } +h2 { font-size: clamp(2rem, 4vw + 0.8rem, 2.8rem); margin-bottom: var(--space-lg); } +h3 { font-size: clamp(1.3rem, 3vw + 0.5rem, 1.75rem); } +h4 { font-size: clamp(1.1rem, 2.5vw + 0.4rem, 1.375rem); } + +p { + margin-bottom: var(--space-lg); /* More space after paragraphs */ + max-width: 70ch; /* Improve readability */ +} + +a { + color: var(--blue); + text-decoration: none; + transition: color var(--transition-fast); +} +a:hover { color: var(--light-blue); } + +img, svg { + max-width: 100%; + height: auto; + display: block; /* Remove bottom space */ +} + +button { font-family: inherit; cursor: pointer; } + +code, pre { font-family: var(--font-mono); background-color: var(--dark-gray); padding: 0.2em 0.4em; border-radius: var(--radius-sm); font-size: 0.9em;} +pre { padding: var(--space-md); overflow-x: auto; } + +ul, ol { list-style-position: outside; padding-left: var(--space-lg); } +li { margin-bottom: var(--space-sm); } + +/* Container */ +.container { + width: 100%; + max-width: 1240px; /* Slightly wider */ + margin: 0 auto; + padding: 0 var(--space-lg); +} + +/* Background effects */ +.bg-gradient { + position: fixed; /* Fixed position */ + top: 0; + left: 0; + width: 100%; + height: 100vh; /* Full viewport height */ + overflow: hidden; + z-index: var(--z-background); + pointer-events: none; /* Allow clicks through */ +} + +.bg-blob { + position: absolute; + border-radius: var(--radius-round); + filter: blur(80px); /* More blur */ + opacity: 0.25; /* More subtle */ + will-change: transform; /* Optimize animation */ +} + +.bg-blob-1 { + width: 50vw; + height: 50vw; + min-width: 400px; + min-height: 400px; + max-width: 700px; + max-height: 700px; + top: -15%; + right: -10%; + background: radial-gradient(circle, var(--magenta) 0%, transparent 70%); + animation: float 25s ease-in-out infinite alternate; +} + +.bg-blob-2 { + width: 45vw; + height: 45vw; + min-width: 350px; + min-height: 350px; + max-width: 600px; + max-height: 600px; + bottom: -10%; + left: -10%; + background: radial-gradient(circle, var(--blue) 0%, transparent 70%); + animation: float 30s ease-in-out infinite alternate-reverse; +} + +@keyframes float { + 0% { transform: translate(0, 0) rotate(0deg) scale(1); } + 100% { transform: translate(50px, -30px) rotate(25deg) scale(1.1); } +} + + +/* Navbar */ +.navbar { + position: fixed; + top: var(--notification-height); /* Adjusted by JS */ + left: 0; + right: 0; + background: rgba(0, 20, 39, 0.7); /* Semi-transparent */ + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + border-bottom: 1px solid rgba(255, 255, 255, 0.08); + z-index: var(--z-navbar); + padding: var(--space-sm) 0; /* Consistent padding */ + transition: background-color var(--transition-normal), box-shadow var(--transition-normal), padding var(--transition-normal), top var(--transition-fast); + will-change: background-color, box-shadow, padding; +} + +.navbar.scrolled { + background: rgba(5, 30, 62, 0.9); /* Darker blue on scroll */ + box-shadow: var(--shadow-md); + /* padding: var(--space-xs) 0; Slightly reduced padding */ +} + +.navbar-container { + display: flex; + align-items: center; + justify-content: space-between; +} + +.logo { + display: flex; + align-items: center; + color: var(--white); /* Ensure logo text is white */ + gap: var(--space-sm); +} +.logo img { height: 32px; transition: transform var(--transition-fast); } +.logo:hover img { transform: rotate(-5deg) scale(1.05); } +.logo-text { font-size: 1.3rem; font-weight: 700; } + +.nav-links { + display: flex; + align-items: center; + list-style: none; + margin: 0; + padding: 0; +} +.nav-links li { margin: 0 var(--space-sm); } /* Reduced margin */ +.nav-links a { + color: var(--white); + font-weight: 500; + font-size: 0.95rem; + position: relative; + padding: var(--space-xs) var(--space-sm); /* Padding for larger hit area */ + border-radius: var(--radius-sm); + transition: background-color var(--transition-fast), color var(--transition-fast); +} +.nav-links a::after { + content: ''; + position: absolute; + width: 0; + height: 2px; + bottom: -2px; /* Position slightly below */ + left: 50%; + transform: translateX(-50%); + background: linear-gradient(90deg, var(--magenta), var(--blue)); + transition: width var(--transition-normal); + border-radius: 1px; +} +.nav-links a:hover, +.nav-links a.active { + background-color: rgba(255, 255, 255, 0.1); + color: var(--white); +} +.nav-links a.active::after { width: 60%; } /* Underline for active link */ +.nav-links a:hover::after { width: 80%; } /* Wider underline on hover */ + +.nav-buttons { display: flex; align-items: center; } +.mobile-toggle { display: none; background: none; border: none; color: var(--white); font-size: 1.75rem; padding: 0.5rem; } + +/* Buttons */ +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.8rem 1.8rem; /* Slightly adjusted padding */ + border-radius: var(--radius-md); + font-weight: 600; + font-size: 0.95rem; + transition: all var(--transition-fast); + border: none; + text-align: center; + cursor: pointer; + position: relative; + overflow: hidden; /* For hover effects */ + white-space: nowrap; +} +.btn-icon { margin-right: var(--space-sm); font-size: 1.1em; } + +.btn-primary { + background: linear-gradient(135deg, var(--orange), var(--magenta)); /* Orange to Magenta gradient */ + color: var(--white); + box-shadow: 0 4px 10px rgba(255, 0, 102, 0.2); +} +.btn-primary:hover { + transform: translateY(-3px) scale(1.02); + box-shadow: 0 6px 15px rgba(255, 0, 102, 0.3); + color: var(--white); +} + +.btn-secondary { + background: rgba(255, 255, 255, 0.1); + color: var(--white); + border: 1px solid rgba(255, 255, 255, 0.2); +} +.btn-secondary:hover { + background: rgba(255, 255, 255, 0.15); + border-color: rgba(255, 255, 255, 0.4); + transform: translateY(-3px); + color: var(--white); +} + +.btn-sm { padding: 0.6rem 1.2rem; font-size: 0.875rem; } +.btn-lg { padding: 1rem 2.2rem; font-size: 1.05rem; } + +/* Hero Section */ +.hero { + padding: calc(var(--space-xxl) * 2 + var(--notification-height)) 0 var(--space-xxl); /* More top padding, account for notification */ + min-height: 70vh; + display: flex; + align-items: center; + position: relative; + overflow: hidden; +} +.hero-content { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--space-xl); + align-items: center; +} +.hero-headings { position: relative; z-index: var(--z-content); } +.hero h1 { line-height: 1.2; } +.hero h1 span.gradient-text { /* Style specifically for hero gradient */ + background: linear-gradient(120deg, var(--magenta), var(--blue), var(--orange)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + background-size: 200% auto; + animation: hero-gradient-animation 5s linear infinite; +} +@keyframes hero-gradient-animation { + to { background-position: 200% center; } +} +.hero-subtitle { + font-size: clamp(1.1rem, 2.5vw + 0.5rem, 1.3rem); + margin-bottom: var(--space-xl); + color: var(--medium-gray); + max-width: 550px; +} +.hero-buttons { display: flex; flex-wrap: wrap; gap: var(--space-md); margin-bottom: var(--space-xl); } +.hero-animation { + position: relative; + width: 100%; + min-height: 450px; /* Ensure space for animation */ + display: flex; + align-items: center; + justify-content: center; + perspective: 1500px; /* Increased perspective */ +} + +/* DNA Helix Animation */ +.dna-helix { + position: absolute; + width: 250px; /* Wider */ + height: 100%; /* Fill the container */ + transform-style: preserve-3d; + /* Removed perspective from here, placed on parent (.hero-animation) */ +} + +.base-pair { + position: absolute; + width: 100%; + height: 20px; /* Base height */ + transform-style: preserve-3d; + /* Animation applied in JS */ +} + +.base { + position: absolute; + width: 28px; /* Slightly larger */ + height: 28px; + border-radius: var(--radius-round); + display: flex; + align-items: center; + justify-content: center; + font-size: 0.9rem; + font-weight: bold; + color: var(--dark-bg); /* Dark text on bases */ + text-shadow: none; + box-shadow: inset 0 0 5px rgba(0,0,0,0.2), 0 2px 5px rgba(0,0,0,0.3); + /* Animation applied in JS */ +} + +.left-base { + left: 30px; /* Adjusted positioning */ + background: linear-gradient(135deg, #ff4d88, var(--magenta)); /* Gradient base */ + animation: pulse 2.5s ease-in-out infinite; + filter: brightness(1.1); +} + +.right-base { + right: 30px; /* Adjusted positioning */ + background: linear-gradient(135deg, #4dd0ff, var(--blue)); /* Gradient base */ + animation: pulse 2.5s ease-in-out infinite 0.2s; /* Staggered animation */ + filter: brightness(1.1); +} + +.base-connector { + position: absolute; + left: 50%; + top: 50%; + width: 130px; /* Connects bases */ + height: 4px; + background: linear-gradient(90deg, + rgba(255, 0, 102, 0.6), + rgba(255, 255, 255, 0.4) 50%, + rgba(0, 164, 239, 0.6) + ); + transform: translate(-50%, -50%); + border-radius: 2px; + box-shadow: 0 0 8px rgba(255, 255, 255, 0.2); +} + +/* Keyframes for DNA animation */ +@keyframes rotate { /* Global rotation for each pair */ + 0% { transform: rotateY(var(--start-angle)) translateZ(50px) translateX(var(--x-offset)); } + 100% { transform: rotateY(calc(var(--start-angle) + 360deg)) translateZ(50px) translateX(var(--x-offset)); } +} + +@keyframes pulse { /* Base pulsing effect */ + 0%, 100% { transform: scale(1); opacity: 0.9; filter: brightness(1.1); } + 50% { transform: scale(1.1); opacity: 1; filter: brightness(1.3); } +} + +/* Section styling */ +.section { + padding: var(--space-xxl) 0; + position: relative; + overflow: hidden; /* Contain elements for animation */ +} +.section-title { + text-align: center; + margin-bottom: var(--space-xl); /* Reduced bottom margin */ +} +.section-title h2 { margin-bottom: var(--space-sm); } +.section-title p { + max-width: 700px; + margin: 0 auto var(--space-lg); /* Center paragraph */ + font-size: 1.1rem; + color: var(--medium-gray); +} +.section-bg-dark { background-color: var(--dark-blue); } +.section-bg-gradient { + background: linear-gradient(160deg, rgba(5, 30, 62, 0.9), rgba(0, 20, 39, 0.9) 70%); + border-top: 1px solid rgba(255, 255, 255, 0.05); + border-bottom: 1px solid rgba(255, 255, 255, 0.05); +} + +/* Cards */ +.card { + background: rgba(255, 255, 255, 0.03); /* More subtle */ + border-radius: var(--radius-lg); + padding: var(--space-lg); + transition: all var(--transition-normal); + border: 1px solid rgba(255, 255, 255, 0.1); + height: 100%; /* Ensure cards in grid have same height */ + display: flex; + flex-direction: column; +} +.card:hover { + transform: translateY(-8px) scale(1.02); /* More lift */ + background: rgba(255, 255, 255, 0.06); + box-shadow: var(--shadow-lg); + border-color: rgba(255, 255, 255, 0.2); +} +.card-title { font-size: 1.4rem; margin-bottom: var(--space-sm); color: var(--white); } +.card-icon { + width: 55px; + height: 55px; + background: linear-gradient(135deg, var(--magenta), var(--blue)); + border-radius: var(--radius-md); + display: flex; + align-items: center; + justify-content: center; + font-size: 1.6rem; + color: var(--white); + margin-bottom: var(--space-md); + flex-shrink: 0; /* Prevent icon from shrinking */ + box-shadow: var(--shadow-glow-blue); +} +.card p { flex-grow: 1; } /* Allow text to fill space */ +.card-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: var(--space-xl); + align-items: stretch; /* Make cards same height */ +} + +/* Feature List (Alternative Card Layout) */ +.feature-list { + display: flex; + flex-direction: column; + gap: var(--space-lg); +} +.feature-card { + display: flex; + align-items: flex-start; + gap: var(--space-lg); + padding: var(--space-lg); + background: rgba(255, 255, 255, 0.04); + border-radius: var(--radius-lg); + transition: all var(--transition-normal); + border: 1px solid rgba(255, 255, 255, 0.1); +} +.feature-card:hover { + transform: translateX(5px); /* Shift right on hover */ + background: rgba(255, 255, 255, 0.07); + box-shadow: var(--shadow-md); + border-left: 3px solid; /* Add left border on hover */ +} +.feature-card:hover.feature-icon-blue { border-left-color: var(--blue); } +.feature-card:hover.feature-icon-magenta { border-left-color: var(--magenta); } +.feature-card:hover.feature-icon-orange { border-left-color: var(--orange); } + +.feature-icon { + min-width: 50px; /* Slightly smaller */ + height: 50px; + border-radius: var(--radius-md); + display: flex; + align-items: center; + justify-content: center; + font-size: 1.4rem; + flex-shrink: 0; +} +/* Distinct feature icon styles */ +.feature-icon-blue { background: rgba(0, 164, 239, 0.1); color: var(--blue); box-shadow: 0 0 10px rgba(0, 164, 239, 0.2); } +.feature-icon-magenta { background: rgba(255, 0, 102, 0.1); color: var(--magenta); box-shadow: 0 0 10px rgba(255, 0, 102, 0.2); } +.feature-icon-orange { background: rgba(244, 128, 34, 0.1); color: var(--orange); box-shadow: 0 0 10px rgba(244, 128, 34, 0.2); } + +.feature-content h3 { margin-bottom: var(--space-xs); font-size: 1.3rem; color: var(--white); } +.feature-content p { margin-bottom: 0; font-size: 0.95rem; } + +/* Stats Section */ +.stats-section { + padding: var(--space-xl) 0; + text-align: center; + position: relative; + background: linear-gradient(180deg, var(--dark-bg) 0%, var(--dark-blue) 100%); /* Subtle vertical gradient */ + border-top: 1px solid rgba(255, 255, 255, 0.05); + border-bottom: 1px solid rgba(255, 255, 255, 0.05); +} +.stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); + gap: var(--space-lg); + text-align: center; + max-width: 1000px; + margin: 0 auto; +} +.stat-item { padding: var(--space-sm); } +.stat-icon { + font-size: 2rem; + margin-bottom: var(--space-sm); + color: var(--blue); /* Use brand blue for icons */ + opacity: 0.8; +} +.stat-number { + font-size: clamp(2.5rem, 6vw, 3.5rem); /* Responsive font size */ + font-weight: 700; + line-height: 1.1; + margin-bottom: var(--space-xs); + background: linear-gradient(135deg, var(--magenta), var(--light-blue)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} +.stat-label { color: var(--medium-gray); font-size: 0.95rem; font-weight: 500; } + +/* Steps Section (How it Works) */ +.steps-container { + position: relative; + display: flex; + flex-direction: column; + gap: var(--space-xl); + max-width: 800px; /* Constrain width */ + margin: var(--space-xl) auto 0; /* Add top margin */ +} +.steps-container::before { /* Vertical connecting line */ + content: ''; + position: absolute; + left: 29px; /* Aligned with center of icons */ + top: 30px; /* Start below first icon */ + bottom: 30px; /* End above last icon */ + width: 4px; + background: linear-gradient(to bottom, + rgba(0, 164, 239, 0.1), + rgba(0, 164, 239, 0.5), + rgba(0, 164, 239, 0.1) + ); + border-radius: 2px; + z-index: var(--z-base); +} + +.step-item { + position: relative; + display: flex; + align-items: flex-start; /* Align items to top */ + gap: var(--space-lg); + padding: var(--space-md); + background: rgba(255, 255, 255, 0.03); + border-radius: var(--radius-lg); + border: 1px solid rgba(255, 255, 255, 0.08); + z-index: var(--z-content); /* Above the line */ + transition: background-color var(--transition-normal), border-color var(--transition-normal); +} +.step-item:hover { + background: rgba(255, 255, 255, 0.06); + border-color: rgba(255, 255, 255, 0.15); +} + +.step-icon { + width: 60px; + height: 60px; + flex-shrink: 0; + background: linear-gradient(135deg, var(--blue), var(--light-blue)); + border-radius: var(--radius-round); + display: flex; + align-items: center; + justify-content: center; + font-size: 1.8rem; + color: var(--white); + box-shadow: var(--shadow-glow-blue); + z-index: var(--z-content); /* Ensure icon is above line */ +} + +/* Alternate step icon colors */ +.step-item:nth-child(1) .step-icon { background: linear-gradient(135deg, var(--orange), #ffb347); box-shadow: 0 0 15px rgba(244, 128, 34, 0.3); } +.step-item:nth-child(3) .step-icon { background: linear-gradient(135deg, var(--magenta), #ff4d88); box-shadow: var(--shadow-glow-magenta); } + + +.step-content h3 { margin-bottom: var(--space-xs); font-size: 1.4rem; color: var(--white); } +.step-content p { margin-bottom: 0; font-size: 1rem; } + + +/* Footer */ +.footer { + background: var(--dark-blue); + padding: var(--space-xxl) 0 var(--space-lg); + border-top: 1px solid rgba(255, 255, 255, 0.1); + margin-top: auto; /* Push footer to bottom */ +} +.footer-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); /* Responsive columns */ + gap: var(--space-xl); + margin-bottom: var(--space-xl); +} +.footer-brand img { height: 36px; margin-bottom: var(--space-md); } +.footer-brand p { margin-bottom: var(--space-lg); color: var(--medium-gray); font-size: 0.9rem; max-width: 300px;} +.footer-social { display: flex; gap: var(--space-md); } +.social-link { + width: 40px; + height: 40px; + border-radius: var(--radius-round); + background: rgba(255, 255, 255, 0.08); + display: flex; + align-items: center; + justify-content: center; + color: var(--white); + font-size: 1.1rem; + transition: all var(--transition-fast); +} +.social-link:hover { + background: var(--blue); /* Use brand color on hover */ + transform: translateY(-3px) scale(1.05); + color: var(--white); +} +.footer-nav h4 { + margin-bottom: var(--space-md); + color: var(--white); + font-size: 1.1rem; + font-weight: 600; +} +.footer-nav ul { list-style: none; padding: 0; margin: 0; } +.footer-nav li { margin-bottom: var(--space-sm); } +.footer-nav a { color: var(--medium-gray); font-size: 0.95rem; transition: color var(--transition-fast); } +.footer-nav a:hover { color: var(--white); text-decoration: underline; } + +.footer-bottom { + margin-top: var(--space-xl); + padding-top: var(--space-lg); + border-top: 1px solid rgba(255, 255, 255, 0.08); + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + gap: var(--space-md); + font-size: 0.85rem; + color: var(--medium-gray); +} +.footer-copyright a { color: var(--medium-gray); text-decoration: underline; } +.footer-copyright a:hover { color: var(--white); } +.footer-links { display: flex; gap: var(--space-lg); } +.footer-links a { color: var(--medium-gray); } +.footer-links a:hover { color: var(--white); } + +/* Disclaimer Section Specific Styles */ +.disclaimer-section { + padding: var(--space-lg) 0; /* Reduced padding */ + background: transparent !important; /* Ensure no background override */ +} +.disclaimer-content { + max-width: 900px; /* Wider */ + margin: 0 auto; + background-color: rgba(0, 10, 20, 0.4); /* Darker, subtle background */ + border-radius: var(--radius-md); + padding: var(--space-lg); + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); + border: 1px solid rgba(255, 255, 255, 0.1); +} +.disclaimer-title { + font-size: 0.9rem; + margin-bottom: var(--space-sm); + color: var(--medium-gray); /* Softer title color */ + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; + opacity: 0.8; +} +.disclaimer-text { + font-size: 0.75rem; /* Slightly larger */ + opacity: 0.7; /* Slightly more visible */ + line-height: 1.5; + color: var(--medium-gray); +} +.disclaimer-text p { margin-bottom: var(--space-sm); } /* Less space between paragraphs */ +.disclaimer-text strong { color: rgba(255, 255, 255, 0.8); font-weight: 600; } + +/* Utilities */ +.text-center { text-align: center; } +.mb-sm { margin-bottom: var(--space-sm); } +.mb-md { margin-bottom: var(--space-md); } +.mb-lg { margin-bottom: var(--space-lg); } +.mb-xl { margin-bottom: var(--space-xl); } +.mt-sm { margin-top: var(--space-sm); } +.mt-md { margin-top: var(--space-md); } +.mt-lg { margin-top: var(--space-lg); } +.mt-xl { margin-top: var(--space-xl); } +.gradient-text { + background: linear-gradient(135deg, var(--magenta), var(--blue)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} + +/* Scroll-based Animations */ +.scroll-animate, +.scroll-animate-left, +.scroll-animate-right, +.scroll-animate-scale { + opacity: 0; + transition: opacity 0.8s cubic-bezier(0.165, 0.84, 0.44, 1), transform 0.8s cubic-bezier(0.165, 0.84, 0.44, 1); + will-change: opacity, transform; /* Performance hint */ +} + +.scroll-animate { transform: translateY(40px); } +.scroll-animate-left { transform: translateX(-50px); } +.scroll-animate-right { transform: translateX(50px); } +.scroll-animate-scale { transform: scale(0.9); } + +.scroll-animate.animate-in, +.scroll-animate-left.animate-in, +.scroll-animate-right.animate-in, +.scroll-animate-scale.animate-in { + opacity: 1; + transform: translate(0, 0) scale(1); +} + +/* Delay classes */ +.scroll-animate-delay-1 { transition-delay: 0.15s; } +.scroll-animate-delay-2 { transition-delay: 0.3s; } +.scroll-animate-delay-3 { transition-delay: 0.45s; } + + +/* Responsive styles */ +@media screen and (max-width: 1024px) { + .hero-content { + grid-template-columns: 1fr; + text-align: center; + gap: var(--space-lg); + } + .hero-headings { order: 1; } /* Text below animation on smaller screens */ + .hero-animation { order: 0; min-height: 350px; margin-bottom: var(--space-lg); } + .hero-subtitle { margin-left: auto; margin-right: auto; } + .hero-buttons { justify-content: center; } + .dna-helix { width: 200px; /* Smaller helix */ } + .base-connector { width: 100px; } + .left-base { left: 25px; } + .right-base { right: 25px; } + + .footer-grid { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); } /* Adjust footer grid */ + .steps-container::before { left: 29px; } /* Adjust step line position if needed */ +} + +@media screen and (max-width: 768px) { + html { scroll-padding-top: 80px; /* Adjust for potentially smaller navbar */ } + h1 { font-size: 2.8rem; } + h2 { font-size: 2.1rem; } + + .navbar-container { position: relative; } + .mobile-toggle { display: block; } + .nav-links { + position: absolute; + top: 100%; + left: 0; + right: 0; + flex-direction: column; + background: var(--dark-blue); /* Solid background for mobile menu */ + padding: var(--space-lg) 0; + max-height: 0; /* Start closed */ + overflow: hidden; + opacity: 0; + visibility: hidden; + transition: max-height 0.4s ease, opacity 0.4s ease, visibility 0.4s ease; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + } + .nav-links.active { + max-height: 500px; /* Open height */ + opacity: 1; + visibility: visible; + } + .nav-links li { margin: var(--space-sm) 0; width: 100%; text-align: center; } + .nav-links a { display: block; padding: var(--space-md) 0; } + .nav-links a::after { display: none; } /* No underline in mobile */ + .nav-buttons { display: none; } /* Hide GitHub button in mobile nav area, could move it inside */ + + .hero { padding-top: calc(var(--space-xl) * 2 + var(--notification-height)); } /* Adjust hero padding */ + .hero-buttons { flex-direction: column; width: 100%; max-width: 300px; margin-left: auto; margin-right: auto; } + .card-grid { grid-template-columns: 1fr; } /* Stack cards */ + .feature-card { flex-direction: column; align-items: center; text-align: center; } + .feature-icon { margin-bottom: var(--space-md); } + .stats-grid { grid-template-columns: repeat(2, 1fr); gap: var(--space-md); } /* 2 columns for stats */ + .steps-container { padding-left: 0; max-width: 100%;} + .steps-container::before { display: none; } /* Hide vertical line on mobile */ + .step-item { flex-direction: column; align-items: center; text-align: center; } + .step-icon { margin-bottom: var(--space-md); } + + .footer-grid { grid-template-columns: 1fr; gap: var(--space-xl); text-align: center;} + .footer-brand { align-items: center; } + .footer-social { justify-content: center; } + .footer-nav h4 { margin-top: var(--space-lg); margin-bottom: var(--space-sm); } + .footer-bottom { flex-direction: column; text-align: center; } + + .notification-banner { + padding: 0.6rem 2.5rem 0.6rem 1rem; + font-size: 0.85rem; + line-height: 1.4; + } + .notification-banner .notification-link { margin: 0.2rem; } +} + +@media screen and (max-width: 480px) { + .container { padding: 0 var(--space-md); } + h1 { font-size: 2.2rem; } + h2 { font-size: 1.8rem; } + .stats-grid { grid-template-columns: 1fr; } /* Stack stats fully */ + .hero-buttons .btn { width: 100%; } /* Full width buttons */ + .footer-bottom { font-size: 0.8rem; } + .footer-links { gap: var(--space-md); } /* Less gap for footer links */ + .notification-banner { font-size: 0.8rem; } + .notification-banner .notification-close { font-size: 1.3rem; right: 0.5rem; width: 26px; height: 26px;} +} +-------------------------------------------------- +File: ./web/.htaccess +-------------------------------------------------- +RewriteEngine On + +# If the request doesn't directly map to an existing file or directory, append .html +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule ^([^/.]+)$ $1.html [L] +-------------------------------------------------- +File: ./web/index.html +-------------------------------------------------- +<!DOCTYPE html> +<html lang="en"> + +<head> + <script async src="https://www.googletagmanager.com/gtag/js?id=G-0LTP0WK7EM"></script> + <script> + window.dataLayer = window.dataLayer || []; + function gtag() { dataLayer.push(arguments); } + gtag('js', new Date()); + gtag('config', 'G-0LTP0WK7EM'); + </script> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>DNAnalyzer - DNA Sequence Analysis with Machine Learning</title> + <meta name="description" + content="DNAnalyzer is a powerful, privacy-focused DNA analysis tool using advanced machine learning for accurate, on-device genomic analysis."> + + <link rel="stylesheet" href="style.css"> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.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@300;400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap" + rel="stylesheet"> + + <link rel="shortcut icon" href="assets/icons/Icon_Dark_BG.svg" type="image/svg+xml"> +</head> + +<body> + <div class="notification-banner"> + <span>🚨 DNAnalyzer v2.0 is coming soon! Check out the</span> + <a href="https://github.com/VerisimilitudeX/DNAnalyzer/projects/1" class="notification-link" target="_blank" rel="noopener noreferrer">Roadmap</a> + <span>and join our</span> + <a href="https://discord.gg/xNpujz49gj" class="notification-link" target="_blank" rel="noopener noreferrer">Discord</a> + <span>for updates!</span> + <button class="notification-close" aria-label="Close notification">×</button> + </div> + + <div class="bg-gradient"> + <div class="bg-blob bg-blob-1"></div> + <div class="bg-blob bg-blob-2"></div> + </div> + + <nav class="navbar" id="navbar"> + <div class="container navbar-container"> + <a href="index.html" class="logo"> + <img src="assets/icons/Icon_Dark_BG.svg" alt="DNAnalyzer Logo"> + <span class="logo-text">DNAnalyzer</span> + </a> + + <button class="mobile-toggle" id="mobileToggle" aria-label="Toggle navigation"> + <i class="fas fa-bars"></i> + </button> + + <ul class="nav-links" id="navLinks"> + <li><a href="index.html" class="active">Home</a></li> + <li><a href="features/features.html">Features</a></li> + <li><a href="analyzer/analyzer.html">Analyzer</a></li> + <li><a href="server/server.html">Server</a></li> + <li><a href="docs/docs.html">Docs</a></li> + <li><a href="about/about.html">About</a></li> + </ul> + + <div class="nav-buttons"> + <a href="https://github.com/VerisimilitudeX/DNAnalyzer" class="btn btn-secondary btn-sm scroll-animate" target="_blank" rel="noopener noreferrer"> + <i class="fab fa-github btn-icon"></i> GitHub + </a> + </div> + </div> + </nav> + + <section class="hero"> + <div class="container"> + <div class="hero-content"> + <div class="hero-headings scroll-animate scroll-animate-left"> + <h1>Revolutionizing <span class="gradient-text">DNA analysis</span> with machine learning</h1> + <p class="hero-subtitle">Powerful, privacy-focused DNA analysis using advanced ML algorithms + designed for both researchers and individuals.</p> + + <div class="hero-buttons"> + <a href="analyzer/analyzer.html" class="btn btn-primary scroll-animate scroll-animate-delay-1"> + <i class="fas fa-dna btn-icon"></i> Try DNA Analysis + </a> + <a href="docs/docs.html" class="btn btn-secondary scroll-animate scroll-animate-delay-2"> + <i class="fas fa-book btn-icon"></i> Documentation + </a> + </div> + </div> + + <div class="hero-animation scroll-animate scroll-animate-right"> + <div class="dna-helix" id="dnaHelix"> + </div> + </div> + </div> + </div> + </section> + + <section class="stats-section scroll-animate"> + <div class="container"> + <div class="stats-grid"> + <div class="stat-item scroll-animate scroll-animate-scale scroll-animate-delay-1"> + <i class="fas fa-star stat-icon"></i> + <div class="stat-number" id="statAccuracy">0</div> <div class="stat-label">GitHub Stars</div> + </div> + <div class="stat-item scroll-animate scroll-animate-scale scroll-animate-delay-2"> + <i class="fas fa-database stat-icon"></i> + <div class="stat-number" id="statSequences">0M+</div> <div class="stat-label">DNA Sequences Analyzed</div> + </div> + <div class="stat-item scroll-animate scroll-animate-scale scroll-animate-delay-3"> + <i class="fas fa-users stat-icon"></i> + <div class="stat-number" id="statUsers">0+</div> <div class="stat-label">Contributors</div> + </div> + <div class="stat-item scroll-animate scroll-animate-scale scroll-animate-delay-3"> + <i class="fab fa-discord stat-icon"></i> + <div class="stat-number">86</div> <div class="stat-label">Discord Members</div> + </div> + </div> + </div> + </section> + + <section class="section"> + <div class="container"> + <div class="section-title scroll-animate"> + <h2>Why Choose <span class="gradient-text">DNAnalyzer</span>?</h2> + <p>Our cutting-edge technology provides unparalleled accuracy and insights while keeping your data + secure.</p> + </div> + + <div class="card-grid"> + <div class="card scroll-animate scroll-animate-delay-1"> + <div class="card-icon"> + <i class="fas fa-shield-alt"></i> + </div> + <h3 class="card-title">Privacy-First Analysis</h3> + <p>Your genetic data never leaves your device. All computation is performed locally using our + advanced on-device ML models.</p> + </div> + + <div class="card scroll-animate scroll-animate-delay-2"> + <div class="card-icon"> + <i class="fas fa-dna"></i> + </div> + <h3 class="card-title">Advanced DNA Analysis</h3> + <p>Identify open reading frames, high coverage regions, protein sequences, and transcription factor + binding sites with precision.</p> + </div> + + <div class="card scroll-animate scroll-animate-delay-3"> + <div class="card-icon"> + <i class="fas fa-brain"></i> + </div> + <h3 class="card-title">Machine Learning Powered</h3> + <p>Our cutting-edge neural networks provide insights and pattern recognition beyond traditional + analytics capabilities.</p> + </div> + </div> + </div> + </section> + + <section class="section section-bg-gradient"> + <div class="container"> + <div class="section-title scroll-animate"> + <h2>How It Works</h2> + <p>A simple three-step process to analyze your DNA sequences</p> + </div> + + <div class="steps-container"> + <div class="step-item scroll-animate scroll-animate-left"> + <div class="step-icon"><i class="fas fa-upload"></i></div> + <div class="step-content"> + <h3>1. Upload Your Sequence</h3> + <p>Upload your DNA sequence file in FASTA or FASTQ format. Your data stays securely on your device.</p> + </div> + </div> + + <div class="step-item scroll-animate scroll-animate-right scroll-animate-delay-1"> + <div class="step-icon"><i class="fas fa-cogs"></i></div> + <div class="step-content"> + <h3>2. Select Analysis Options</h3> + <p>Choose from a variety of analysis modules, including ORF detection, GC content analysis, and + promoter identification.</p> + </div> + </div> + + <div class="step-item scroll-animate scroll-animate-left scroll-animate-delay-2"> + <div class="step-icon"><i class="fas fa-chart-line"></i></div> + <div class="step-content"> + <h3>3. Get Comprehensive Results</h3> + <p>Receive detailed insights instantly with visualizations and downloadable reports for your research.</p> + </div> + </div> + </div> + </div> + </section> + + <section class="section"> + <div class="container"> + <div class="section-title scroll-animate"> + <h2>Powerful Analysis Features</h2> + <p>Comprehensive tools designed for researchers, students, and enthusiasts</p> + </div> + + <div class="feature-list"> + <div class="feature-card scroll-animate scroll-animate-right"> + <div class="feature-icon feature-icon-blue"> + <i class="fas fa-search-plus"></i> </div> + <div class="feature-content"> + <h3>Open Reading Frame Identification</h3> + <p>Scans DNA for start and stop codons to identify potential protein-coding sequences (ORFs). Recognizes canonical start/stop codons to pinpoint putative proteins within a genome.</p> + </div> + </div> + + <div class="feature-card scroll-animate scroll-animate-left scroll-animate-delay-1"> + <div class="feature-icon feature-icon-magenta"> + <i class="fas fa-thermometer-half"></i> </div> + <div class="feature-content"> + <h3>GC-Content Analysis</h3> <p>Calculates and visualizes GC content across the sequence, highlighting GC-rich regions often associated with gene density and regulatory elements.</p> + </div> + </div> + + <div class="feature-card scroll-animate scroll-animate-right scroll-animate-delay-2"> + <div class="feature-icon feature-icon-orange"> + <i class="fas fa-map-marker-alt"></i> </div> + <div class="feature-content"> + <h3>Core Promoter Element Identification</h3> + <p>Scans for known core promoter motifs (e.g., TATA box, BRE, INR, DPE). Detecting these elements helps locate potential gene start sites and regulatory regions.</p> + </div> + </div> + </div> + </div> + </section> + + <section class="section section-bg-dark scroll-animate"> + <div class="container text-center"> + <h2>Ready to Start Analyzing?</h2> + <p class="mb-xl">Join thousands of researchers and scientists using DNAnalyzer for their genetic analysis + needs.</p> + + <div class="hero-buttons" style="justify-content: center;"> + <a href="analyzer/analyzer.html" class="btn btn-primary"> + <i class="fas fa-dna btn-icon"></i> Start Analyzing Now + </a> + <a href="docs/docs.html" class="btn btn-secondary"> + <i class="fas fa-book btn-icon"></i> Read Documentation + </a> + </div> + </div> + </section> + + <section class="section section-bg-dark disclaimer-section scroll-animate"> + <div class="container"> + <div class="disclaimer-content"> + <h4 class="disclaimer-title">DNAnalyzer Disclaimer</h4> + <div class="disclaimer-text"> + <p><strong>Limitation of Liability:</strong> The DNAnalyzer tool is intended for research, educational, and informational purposes only. The machine learning-based DNA analysis provides computational predictions that should not be used for medical diagnosis, clinical interpretation, or treatment decisions. DNAnalyzer is not a substitute for professional medical advice, diagnosis, or treatment.</p> + <p><strong>Analysis Limitations:</strong> DNAnalyzer's computational analysis is based on algorithmic predictions using machine learning models trained on public datasets. Results may vary in accuracy. The absence of identified features does not rule out their presence, and identification does not guarantee biological relevance.</p> + <p><strong>Privacy Notice:</strong> While DNAnalyzer processes data locally, users should exercise caution with sensitive genetic information. We recommend against uploading identifiable human genomic data. DNAnalyzer is not responsible for privacy implications from user actions.</p> + <p><strong>Research Use Only:</strong> Results should be experimentally validated before use in publications. Citations should acknowledge its computational nature and limitations.</p> + <p><strong>No Warranty:</strong> DNAnalyzer is provided "as is" without warranty of any kind. The creators and contributors disclaim all warranties. In no event shall creators/contributors be liable for any claim, damages, or liability arising from the use of this software.</p> + </div> + </div> + </div> + </section> + + <footer class="footer"> + <div class="container"> + <div class="footer-grid"> + <div class="footer-brand"> + <a href="index.html" class="logo mb-md"> <img src="assets/icons/Icon_Dark_BG.svg" alt="DNAnalyzer Logo" style="height: 36px;"> + </a> + <p>DNAnalyzer: Powerful, privacy-focused DNA analysis with cutting-edge machine learning for on-device genomic insights.</p> + + <div class="footer-social"> + <a href="https://github.com/VerisimilitudeX/DNAnalyzer" class="social-link" target="_blank" rel="noopener noreferrer" aria-label="GitHub"> + <i class="fab fa-github"></i> + </a> + <a href="https://discord.gg/xNpujz49gj" class="social-link" target="_blank" rel="noopener noreferrer" aria-label="Discord"> + <i class="fab fa-discord"></i> + </a> + <a href="https://twitter.com/DNAnalyzer_" class="social-link" target="_blank" rel="noopener noreferrer" aria-label="Twitter"> + <i class="fab fa-twitter"></i> + </a> + </div> + </div> + + <div class="footer-nav"> + <h4>Product</h4> + <ul> + <li><a href="features/features.html">Features</a></li> + <li><a href="analyzer/analyzer.html">DNA Analyzer</a></li> + <li><a href="server/server.html">Server</a></li> + <li><a href="docs/docs.html">Documentation</a></li> + </ul> + </div> + + <div class="footer-nav"> + <h4>Resources</h4> + <ul> + <li><a href="docs/getting-started.md">Getting Started</a></li> + <li><a href="docs/citations.md">Citations</a></li> + <li><a href="docs/research/genes.md">Gene Research</a></li> + <li><a href="docs/samples/cli-arguments-examples.md">CLI Examples</a></li> + </ul> + </div> + + <div class="footer-nav"> + <h4>Community</h4> + <ul> + <li><a href="https://github.com/VerisimilitudeX/DNAnalyzer">GitHub</a></li> + <li><a href="https://discord.gg/xNpujz49gj">Discord</a></li> + <li><a href="docs/contributing/CONTRIBUTING.md">Contributing</a></li> + <li><a href="CODE_OF_CONDUCT.md">Code of Conduct</a></li> + </ul> + </div> + </div> + + <div class="footer-bottom"> + <div class="footer-copyright"> + Copyright © 2025 Piyush Acharya. DNAnalyzer is fiscally sponsored by <a href="https://theopensource.org/" target="_blank" rel="noopener">The Open Source Collective</a> 501(c)(3). MIT License. + </div> + + <div class="footer-links"> + <a href="LICENSE.md">License</a> + <a href="SECURITY.md">Security</a> + <a href="CITATION.cff">Citation</a> + </div> + </div> + </div> + </footer> + + <script src="index.js"></script> +</body> +</html> +-------------------------------------------------- +File: ./web/style.css.bak +-------------------------------------------------- +/* DNA Helix Animation */ +.dna-helix { + position: relative; + width: 200px; + height: 400px; + margin: 0 auto; + perspective: 1200px; + transform-style: preserve-3d; +} + +.base-pair { + position: absolute; + width: 100%; + height: 20px; + animation: rotate 8s linear infinite; + transform-style: preserve-3d; +} + +.base { + position: absolute; + width: 25px; + height: 25px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; + color: white; + text-shadow: 0 0 3px rgba(0,0,0,0.5); + box-shadow: 0 0 15px rgba(0,0,0,0.2); +} + +.left-base { + left: 35px; + background: #FF0066; + animation: pulse 3s ease-in-out infinite; + filter: brightness(1.1); +} + +.right-base { + right: 35px; + background: #00B7FF; + animation: pulse 3s ease-in-out infinite; + filter: brightness(1.1); +} + +.base-connector { + position: absolute; + left: 50%; + width: 90px; + height: 3px; + background: linear-gradient(90deg, + rgba(255, 0, 102, 0.8), + rgba(255, 255, 255, 0.3) 50%, + rgba(0, 183, 255, 0.8) + ); + transform: translateX(-50%); + box-shadow: 0 0 8px rgba(0,0,0,0.15); +} + +@keyframes rotate { + 0% { transform: rotateY(0deg) translateZ(20px); } + 100% { transform: rotateY(360deg) translateZ(20px); } +} + +@keyframes pulse { + 0% { transform: scale(1); opacity: 0.9; filter: brightness(1.1); } + 50% { transform: scale(1.15); opacity: 1; filter: brightness(1.3); } + 100% { transform: scale(1); opacity: 0.9; filter: brightness(1.1); } +} +/* DNAnalyzer - Main Stylesheet + * Global styles for all pages + */ +/* Notification Banner Styling */ +.notification-banner { + background: linear-gradient(135deg, #FF6F00, #FF9100); + color: var(--white); + padding: 0.75rem 1rem 0.75rem 0.75rem; + text-align: center; + font-size: 1rem; + font-weight: 600; + position: fixed; + top: 0; + left: 0; + width: 100%; + z-index: var(--z-navbar); + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + animation: notifPulse 3s infinite; + transition: transform 0.3s ease-in-out; + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; +} + +.notification-banner.hide-notification { + transform: translateY(-100%); +} + +.notification-banner.closed { + display: none !important; +} + +.notification-banner .notification-link { + color: inherit; + text-decoration: none; + font-weight: 700; + background-color: rgba(255, 255, 255, 0.2); + padding: 0.25rem 0.5rem; + border-radius: 4px; + margin: 0 0.5rem; + transition: all 0.3s ease; + white-space: nowrap; +} + +.notification-banner .notification-link:hover { + color: #FFD700; + text-shadow: 0 0 5px rgba(255, 215, 0, 0.5); +} + +.notification-banner .notification-close { + background: rgba(255, 255, 255, 0.1); + border: none; + color: var(--white); + font-size: 1.25rem; + line-height: 1; + position: absolute; + right: 0.5rem; + top: 50%; + transform: translateY(-50%); + cursor: pointer; + transition: all 0.3s ease; + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + padding: 0; +} + +.notification-banner .notification-close::before { + content: "×"; + display: block; + position: relative; + top: -1px; +} + +.notification-banner .notification-close:hover { + background: rgba(255, 255, 255, 0.2); + transform: translateY(-50%) rotate(90deg); + color: #FFD700; + text-shadow: 0 0 5px rgba(255, 215, 0, 0.5); +} + + :root { + /* Brand colors from logo */ + --magenta: #ff0066; + --blue: #00a4ef; + --orange: #f48022; + --white: #ffffff; + --dark-bg: #001427; + + /* Additional UI colors */ + --dark-blue: #051e3e; + --light-blue: #2596be; + --light-gray: #f5f5f7; + --medium-gray: #86868b; + --dark-gray: #333333; + + /* Functional colors */ + --success: #34c759; + --warning: #ff9500; + --error: #ff3b30; + + /* Typography */ + --font-heading: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; + --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; + --font-mono: 'IBM Plex Mono', monospace; + + /* Spacing */ + --space-xs: 0.25rem; + --space-sm: 0.5rem; + --space-md: 1rem; + --space-lg: 1.5rem; + --space-xl: 2rem; + --space-xxl: 3rem; + + /* Border radius */ + --radius-sm: 4px; + --radius-md: 8px; + --radius-lg: 12px; + --radius-xl: 20px; + + /* Shadows */ + --shadow-sm: 0 2px 5px rgba(0, 0, 0, 0.1); + --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.15); + --shadow-lg: 0 8px 20px rgba(0, 0, 0, 0.2); + + /* Transitions */ + --transition-fast: 0.2s ease; + --transition-normal: 0.3s ease; + --transition-slow: 0.5s ease; + + /* Z-index layers */ + --z-tooltip: 100; + --z-navbar: 200; + --z-modal: 300; + } + + /* Reset & Base Styles */ + *, + *::before, + *::after { + box-sizing: border-box; + margin: 0; + padding: 0; + } + + html { + font-size: 16px; + scroll-behavior: smooth; + } + + body { + font-family: var(--font-body); + background-color: var(--dark-bg); + color: var(--white); + line-height: 1.6; + overflow-x: hidden; + min-height: 100vh; + display: flex; + flex-direction: column; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + + h1, h2, h3, h4, h5, h6 { + font-family: var(--font-heading); + line-height: 1.2; + font-weight: 700; + margin-bottom: var(--space-md); + } + + h1 { + font-size: 3.5rem; + margin-bottom: var(--space-lg); + } + + h2 { + font-size: 2.5rem; + margin-bottom: var(--space-lg); + } + + h3 { + font-size: 1.75rem; + } + + h4 { + font-size: 1.375rem; + } + + p { + margin-bottom: var(--space-md); + color: rgba(255, 255, 255, 0.85); + } + + a { + color: var(--blue); + text-decoration: none; + transition: color var(--transition-fast); + } + + a:hover { + color: var(--light-blue); + } + + img { + max-width: 100%; + height: auto; + } + + button { + font-family: var(--font-body); + cursor: pointer; + } + + code, pre { + font-family: var(--font-mono); + } + + ul, ol { + padding-left: var(--space-lg); + margin-bottom: var(--space-md); + } + + /* Container */ + .container { + width: 100%; + max-width: 1200px; + margin: 0 auto; + padding: 0 var(--space-lg); + } + + .container-sm { + max-width: 800px; + } + + .container-lg { + max-width: 1400px; + } + + /* Navbar */ + .navbar { + position: fixed; + top: var(--notification-height, 0); + left: 0; + right: 0; + background: var(--dark-bg); + border-bottom: 1px solid rgba(255, 255, 255, 0.08); + z-index: var(--z-navbar); + padding: var(--space-md) 0; + transition: all var(--transition-normal), top 0.3s ease-in-out; + } + + .navbar.scrolled { + background: var(--dark-blue); + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); + padding: var(--space-sm) 0; + } + + .navbar-container { + display: flex; + align-items: center; + justify-content: space-between; + } + + .logo { + display: flex; + align-items: center; + } + + .logo img { + height: 36px; + margin-right: var(--space-sm); + } + + .logo-text { + font-size: 1.25rem; + font-weight: 700; + color: var(--white); + } + + .nav-links { + display: flex; + align-items: center; + list-style: none; + margin: 0; + padding: 0; + } + + .nav-links li { + margin: 0 var(--space-md); + } + + .nav-links a { + color: var(--white); + font-weight: 500; + position: relative; + padding: var(--space-xs) 0; + } + + .nav-links a::after { + content: ''; + position: absolute; + width: 0; + height: 2px; + bottom: 0; + left: 0; + background: linear-gradient(90deg, var(--magenta), var(--blue)); + transition: width var(--transition-normal); + } + + .nav-links a:hover::after, + .nav-links a.active::after { + width: 100%; + } + + .nav-buttons { + display: flex; + align-items: center; + } + + .mobile-toggle { + display: none; + background: none; + border: none; + color: var(--white); + font-size: 1.5rem; + } + + /* Buttons */ + .btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.75rem 1.5rem; + border-radius: var(--radius-md); + font-weight: 600; + transition: all var(--transition-fast); + border: none; + text-align: center; + cursor: pointer; + } + + .btn-primary { + background: linear-gradient(135deg, #FF7B00, #FFB347); + color: var(--white); + } + + .btn-primary:hover { + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(0, 164, 239, 0.4); + color: var(--white); + } + + .btn-secondary { + background: rgba(255, 255, 255, 0.1); + color: var(--white); + border: 1px solid rgba(255, 255, 255, 0.2); + } + + .btn-secondary:hover { + background: rgba(255, 255, 255, 0.15); + transform: translateY(-2px); + color: var(--white); + } + + .btn-sm { + padding: 0.5rem 1rem; + font-size: 0.875rem; + } + + .btn-lg { + padding: 1rem 2rem; + font-size: 1.125rem; + } + + .btn-icon { + margin-right: var(--space-xs); + } + + .btn-github { + background: #24292e; + color: var(--white); + } + + .btn-github:hover { + background: #2c3440; + color: var(--white); + } + + .btn-discord { + background: #5865F2; + color: var(--white); + } + + .btn-discord:hover { + background: #4752c4; + color: var(--white); + } + + /* Hero section */ + .hero { + padding: 160px 0 100px; + position: relative; + overflow: hidden; + } + + .hero-content { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--space-xxl); + align-items: center; + } + + .hero-headings { + position: relative; + z-index: 2; + } + + .hero h1 { + margin-bottom: var(--space-md); + letter-spacing: -0.02em; + line-height: 1.1; + } + + .hero h1 span { + background: linear-gradient(135deg, var(--magenta), var(--blue)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + } + + .hero-subtitle { + font-size: 1.25rem; + margin-bottom: var(--space-xl); + color: rgba(255, 255, 255, 0.85); + max-width: 500px; + } + + .hero-buttons { + display: flex; + gap: var(--space-md); + margin-bottom: var(--space-xl); + } + + .hero-animation { + position: relative; + width: 100%; + height: 500px; + display: flex; + align-items: center; + justify-content: center; + } + + /* DNA Helix Animation */ + .dna-helix { + position: relative; + width: 100%; + height: 100%; + transform-style: preserve-3d; + perspective: 1200px; + } + + .base-pair { + position: absolute; + width: 100%; + height: 30px; + display: flex; + justify-content: center; + align-items: center; + animation: rotate3D 12s linear infinite; + } + + @keyframes rotate3D { + 0% { transform: rotateY(0deg); } + 100% { transform: rotateY(360deg); } + } + + .base { + width: 35px; + height: 35px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; + color: white; + position: absolute; + box-shadow: 0 0 20px rgba(0, 0, 0, 0.3); + } + + .left-base { + background: var(--magenta); + left: calc(50% - 120px); + animation: moveLeft 6s ease-in-out infinite; + } + + .right-base { + background: var(--blue); + right: calc(50% - 120px); + animation: moveRight 6s ease-in-out infinite; + } + + .base-connector { + width: 200px; + height: 3px; + background: linear-gradient(90deg, var(--magenta), var(--blue)); + position: absolute; + animation: stretch 6s ease-in-out infinite; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); + } + + @keyframes moveLeft { + 0%, 100% { transform: translateX(-12px); } + 50% { transform: translateX(12px); } + } + + @keyframes moveRight { + 0%, 100% { transform: translateX(12px); } + 50% { transform: translateX(-12px); } + } + + @keyframes stretch { + 0%, 100% { width: 200px; } + 50% { width: 220px; } + } + + /* Section styling */ + .section { + padding: var(--space-xxl) 0; + position: relative; + } + + .section-title { + text-align: center; + margin-bottom: var(--space-xxl); + } + + .section-title h2 { + margin-bottom: var(--space-md); + } + + .section-title p { + max-width: 700px; + margin: 0 auto; + font-size: 1.1rem; + } + + .section-bg-dark { + background-color: var(--dark-blue); + } + + .section-bg-gradient { + background: linear-gradient(135deg, rgba(5, 30, 62, 0.7), rgba(0, 20, 39, 0.7)); + } + + /* Cards */ + .card { + background: rgba(255, 255, 255, 0.05); + border-radius: var(--radius-lg); + padding: var(--space-xl); + transition: all var(--transition-normal); + border: 1px solid rgba(255, 255, 255, 0.1); + } + + .card:hover { + transform: translateY(-5px); + background: rgba(255, 255, 255, 0.08); + box-shadow: var(--shadow-md); + border-color: rgba(255, 255, 255, 0.15); + } + + .card-title { + font-size: 1.3rem; + margin-bottom: var(--space-md); + } + + .card-icon { + width: 60px; + height: 60px; + background: linear-gradient(135deg, var(--magenta), var(--blue)); + border-radius: var(--radius-md); + display: flex; + align-items: center; + justify-content: center; + font-size: 1.5rem; + color: var(--white); + margin-bottom: var(--space-md); + } + + .card-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: var(--space-xl); + } + + /* Feature cards */ + .feature-card { + display: flex; + align-items: flex-start; + gap: var(--space-lg); + padding: var(--space-xl); + background: rgba(255, 255, 255, 0.05); + border-radius: var(--radius-lg); + transition: all var(--transition-normal); + border: 1px solid rgba(255, 255, 255, 0.1); + margin-bottom: var(--space-xl); + } + + .feature-card:hover { + transform: translateY(-5px); + background: rgba(255, 255, 255, 0.08); + box-shadow: var(--shadow-md); + border-color: rgba(255, 255, 255, 0.15); + } + + .feature-icon { + min-width: 60px; + height: 60px; + border-radius: var(--radius-md); + display: flex; + align-items: center; + justify-content: center; + font-size: 1.5rem; + } + + .feature-icon-blue { + background: rgba(0, 164, 239, 0.15); + color: var(--blue); + border: 1px solid rgba(0, 164, 239, 0.3); + } + + .feature-icon-magenta { + background: rgba(255, 0, 102, 0.15); + color: var(--magenta); + border: 1px solid rgba(255, 0, 102, 0.3); + } + + .feature-icon-orange { + background: rgba(244, 128, 34, 0.15); + color: var(--orange); + border: 1px solid rgba(244, 128, 34, 0.3); + } + + .feature-content h3 { + margin-bottom: var(--space-sm); + } + + /* Stats */ + .stats-section { + padding: var(--space-xxl) 0; + text-align: center; + position: relative; + background: linear-gradient(135deg, rgba(5, 30, 62, 0.7), rgba(0, 20, 39, 0.7)); + border-top: 1px solid rgba(255, 255, 255, 0.05); + border-bottom: 1px solid rgba(255, 255, 255, 0.05); + } + + .stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: var(--space-xl); + text-align: center; + max-width: 1000px; + margin: 0 auto; + } + + .stat-item { + padding: var(--space-md); + } + + .stat-number { + font-size: 3rem; + font-weight: 700; + margin-bottom: var(--space-xs); + background: linear-gradient(135deg, var(--magenta), var(--blue)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + } + + .stat-label { + color: rgba(255, 255, 255, 0.8); + font-size: 1rem; + font-weight: 500; + } + + /* Steps */ + .steps-container { + counter-reset: step; + position: relative; + } + + .step-item { + position: relative; + padding-left: 70px; + margin-bottom: var(--space-xl); + } + + .step-item::before { + counter-increment: step; + content: counter(step); + position: absolute; + left: 0; + top: 0; + width: 50px; + height: 50px; + background: linear-gradient(135deg, var(--magenta), var(--blue)); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-weight: 700; + font-size: 1.25rem; + color: var(--white); + } + + .step-item:not(:last-child)::after { + content: ''; + position: absolute; + left: 25px; + top: 50px; + bottom: -40px; + width: 2px; + background: linear-gradient(to bottom, var(--blue), transparent); + } + + .step-content h3 { + margin-bottom: var(--space-sm); + } + + /* Footer */ + .footer { + background: var(--dark-blue); + padding: var(--space-xxl) 0 var(--space-md); + border-top: 1px solid rgba(255, 255, 255, 0.1); + } + + .footer-grid { + display: grid; + grid-template-columns: 2fr 1fr 1fr 1fr; + gap: var(--space-xl); + } + + .footer-brand { + display: flex; + flex-direction: column; + } + + .footer-brand img { + height: 40px; + margin-bottom: var(--space-md); + } + + .footer-brand p { + margin-bottom: var(--space-lg); + color: rgba(255, 255, 255, 0.7); + } + + .footer-social { + display: flex; + gap: var(--space-md); + } + + .social-link { + width: 36px; + height: 36px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.1); + display: flex; + align-items: center; + justify-content: center; + color: var(--white); + transition: all var(--transition-fast); + } + + .social-link:hover { + background: rgba(255, 255, 255, 0.2); + transform: translateY(-2px); + color: var(--white); + } + + .footer-nav h4 { + margin-bottom: var(--space-lg); + color: var(--white); + font-size: 1.1rem; + } + + .footer-nav ul { + list-style: none; + padding: 0; + margin: 0; + } + + .footer-nav li { + margin-bottom: var(--space-sm); + } + + .footer-nav a { + color: rgba(255, 255, 255, 0.7); + transition: color var(--transition-fast); + } + + .footer-nav a:hover { + color: var(--white); + } + + .footer-bottom { + margin-top: var(--space-xxl); + padding-top: var(--space-md); + border-top: 1px solid rgba(255, 255, 255, 0.1); + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + gap: var(--space-md); + } + + .footer-copyright { + color: rgba(255, 255, 255, 0.6); + font-size: 0.875rem; + } + + .footer-links { + display: flex; + gap: var(--space-lg); + } + + .footer-links a { + color: rgba(255, 255, 255, 0.6); + font-size: 0.875rem; + } + + .footer-links a:hover { + color: var(--white); + } + + /* Background effects */ + .bg-gradient { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + overflow: hidden; + z-index: -1; + } + + .bg-blob { + position: absolute; + border-radius: 50%; + filter: blur(60px); + opacity: 0.5; + } + + .bg-blob-1 { + top: -200px; + right: -100px; + width: 600px; + height: 600px; + background: linear-gradient(135deg, rgba(255, 0, 102, 0.2), rgba(0, 0, 0, 0)); + animation: float 20s ease-in-out infinite alternate; + } + + .bg-blob-2 { + bottom: -150px; + left: -100px; + width: 500px; + height: 500px; + background: linear-gradient(135deg, rgba(0, 164, 239, 0.2), rgba(0, 0, 0, 0)); + animation: float 15s ease-in-out infinite alternate-reverse; + } + + @keyframes float { + 0% { transform: translate(0, 0) rotate(0deg); } + 100% { transform: translate(40px, 40px) rotate(15deg); } + } + + /* Utilities */ + .text-center { + text-align: center; + } + + .mb-sm { + margin-bottom: var(--space-sm); + } + + .mb-md { + margin-bottom: var(--space-md); + } + + .mb-lg { + margin-bottom: var(--space-lg); + } + + .mb-xl { + margin-bottom: var(--space-xl); + } + + .mt-sm { + margin-top: var(--space-sm); + } + + .mt-md { + margin-top: var(--space-md); + } + + .mt-lg { + margin-top: var(--space-lg); + } + + .mt-xl { + margin-top: var(--space-xl); + } + + .gradient-text { + background: linear-gradient(135deg, var(--magenta), var(--blue)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + } + + /* Responsive styles */ + @media screen and (max-width: 1024px) { + h1 { + font-size: 3rem; + } + + h2 { + font-size: 2.25rem; + } + + .hero-content { + grid-template-columns: 1fr; + text-align: center; + } + + .hero-subtitle { + margin-left: auto; + margin-right: auto; + } + + .hero-buttons { + justify-content: center; + } + + .hero-animation { + margin-top: var(--space-xl); + } + + .footer-grid { + grid-template-columns: 1fr 1fr; + gap: var(--space-xl) var(--space-xxl); + } + } + + @media screen and (max-width: 768px) { + h1 { + font-size: 2.5rem; + } + + h2 { + font-size: 2rem; + } + + .navbar-container { + position: relative; + } + + .nav-links { + position: absolute; + top: 100%; + left: 0; + right: 0; + flex-direction: column; + background: var(--dark-bg); + padding: var(--space-lg); + transform: translateY(-100%); + opacity: 0; + visibility: hidden; + transition: all var(--transition-normal); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + } + + .nav-links.active { + transform: translateY(0); + opacity: 1; + visibility: visible; + } + + .nav-links li { + margin: var(--space-sm) 0; + } + + .mobile-toggle { + display: block; + } + + .hero-buttons { + flex-direction: column; + width: 100%; + max-width: 300px; + margin-left: auto; + margin-right: auto; + } + + .feature-card { + flex-direction: column; + } + + .footer-grid { + grid-template-columns: 1fr; + gap: var(--space-xl); + } + + .footer-bottom { + flex-direction: column; + align-items: center; + text-align: center; + } + } + + @media screen and (max-width: 480px) { + .container { + padding: 0 var(--space-md); + } + + h1 { + font-size: 2rem; + } + + h2 { + font-size: 1.75rem; + } + + .stats-grid { + grid-template-columns: 1fr; + } + } + + @media screen and (max-width: 768px) { + .notification-banner { + padding: 0.5rem 2rem 0.5rem 0.5rem; + font-size: 0.9rem; + } + + .notification-banner span { + display: inline; + } + + .notification-banner .notification-link { + margin: 0 0.25rem; + } + } + + @media screen and (max-width: 480px) { + .notification-banner { + padding: 0.5rem 2rem 0.5rem 0.5rem; + font-size: 0.8rem; + line-height: 1.4; + } + + .notification-banner span { + display: inline; + } + + .notification-banner .notification-link { + margin: 0.25rem; + padding: 0.15rem 0.35rem; + } + } + + /* DNAnalyzer Disclaimer CSS Update */ +.disclaimer-section { + padding: 1rem 0; + background: transparent !important; /* Override any dark background */ +} + +.disclaimer-content { + max-width: 90%; + margin: 0 auto; + background-color: rgba(30, 30, 40, 0.4); /* Subtle dark background */ + border-radius: 8px; + padding: 1rem; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.disclaimer-title { + font-size: 0.85rem; + margin-bottom: 0.75rem; + opacity: 0.75; + color: rgba(255, 255, 255, 0.8); + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.disclaimer-text { + font-size: 0.7rem; + opacity: 0.65; + line-height: 1.4; + color: rgba(255, 255, 255, 0.7); +} + +/* Futuristic Notification Effects */ +@keyframes notifPulse { + 0% { box-shadow: 0 0 5px #FF9100; } + 50% { box-shadow: 0 0 20px #FF9100; } + 100% { box-shadow: 0 0 5px #FF9100; } +} + +/* JavaScript will add this class when scrolling down */ +.hide-notification { + transform: translateY(-100%); +} + +/* Scroll-based animations */ +.scroll-animate { + opacity: 0; + transform: translateY(30px); + transition: opacity 0.8s ease, transform 0.8s ease; +} + +.scroll-animate.animate-in { + opacity: 1; + transform: translateY(0); +} + +.scroll-animate-delay-1 { + transition-delay: 0.2s; +} + +.scroll-animate-delay-2 { + transition-delay: 0.4s; +} + +.scroll-animate-delay-3 { + transition-delay: 0.6s; +} + +.scroll-animate-right { + opacity: 0; + transform: translateX(50px); + transition: opacity 0.8s ease, transform 0.8s ease; +} + +.scroll-animate-right.animate-in { + opacity: 1; + transform: translateX(0); +} + +.scroll-animate-left { + opacity: 0; + transform: translateX(-50px); + transition: opacity 0.8s ease, transform 0.8s ease; +} + +.scroll-animate-left.animate-in { + opacity: 1; + transform: translateX(0); +} + +.scroll-animate-scale { + opacity: 0; + transform: scale(0.8); + transition: opacity 0.8s ease, transform 0.8s ease; +} + +.scroll-animate-scale.animate-in { + opacity: 1; + transform: scale(1); +} + +/* Interactive particles */ +.particles-container { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 0; + overflow: hidden; + pointer-events: none; +} + +.floating-particle { + position: absolute; + background: rgba(255, 255, 255, 0.1); + border-radius: 50%; + pointer-events: none; + transition: transform 0.3s ease; +} +-------------------------------------------------- + +Directory: about +================================================== +File: ./web/about/about.js +-------------------------------------------------- +/* + * DNAnalyzer About Page JavaScript + * Copyright © 2025 Piyush Acharya + */ + +document.addEventListener('DOMContentLoaded', function() { + // Mobile navigation toggle + const mobileToggle = document.getElementById('mobileToggle'); + const navLinks = document.getElementById('navLinks'); + + if (mobileToggle && navLinks) { + mobileToggle.addEventListener('click', function() { + navLinks.classList.toggle('active'); + mobileToggle.querySelector('i').classList.toggle('fa-bars'); + mobileToggle.querySelector('i').classList.toggle('fa-times'); + }); + } + + // Navbar scroll behavior + const navbar = document.getElementById('navbar'); + + window.addEventListener('scroll', function() { + if (window.scrollY > 100) { + navbar.classList.add('scrolled'); + } else { + navbar.classList.remove('scrolled'); + } + }); + + // Timeline animation - Adding view animation + const timelineItems = document.querySelectorAll('.timeline-item'); + + const observerOptions = { + root: null, + rootMargin: '0px', + threshold: 0.1 + }; + + const timelineObserver = new IntersectionObserver((entries, observer) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.style.opacity = '1'; + entry.target.style.transform = entry.target.classList.contains('timeline-item:nth-child(odd)') + ? 'translateX(0)' + : 'translateX(0)'; + observer.unobserve(entry.target); + } + }); + }, observerOptions); + + timelineItems.forEach(item => { + item.style.opacity = '0'; + item.style.transform = item.classList.contains('timeline-item:nth-child(odd)') + ? 'translateX(-20px)' + : 'translateX(20px)'; + item.style.transition = 'all 0.7s ease-out'; + timelineObserver.observe(item); + }); + + // Handle Vision Hexagon Hover/Click Interaction + const hexagons = document.querySelectorAll('.hexagon'); + const visionDetails = document.querySelectorAll('.vision-detail'); + + // Set first vision detail as active by default + if (visionDetails.length > 0) { + visionDetails[0].classList.add('active'); + } + + hexagons.forEach((hexagon, index) => { + hexagon.addEventListener('mouseenter', () => { + // Remove active class from all vision details + visionDetails.forEach(detail => { + detail.classList.remove('active'); + }); + + // Add active class to corresponding vision detail + if (visionDetails[index]) { + visionDetails[index].classList.add('active'); + } + }); + + hexagon.addEventListener('click', () => { + // Remove active class from all vision details + visionDetails.forEach(detail => { + detail.classList.remove('active'); + }); + + // Add active class to corresponding vision detail + if (visionDetails[index]) { + visionDetails[index].classList.add('active'); + + // If on mobile, scroll to the detail + if (window.innerWidth < 992) { + visionDetails[index].scrollIntoView({ + behavior: 'smooth', + block: 'center' + }); + } + } + }); + }); + + // Add some interactivity to stats + animateStats(); +}); + +/** + * Animates the stat numbers with a counting effect + */ +function animateStats() { + const statNumbers = document.querySelectorAll('.stat-number[data-count]'); + + const observerOptions = { + root: null, + rootMargin: '0px', + threshold: 0.1 + }; + + const statsObserver = new IntersectionObserver((entries, observer) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const targetNumber = parseInt(entry.target.getAttribute('data-count'), 10); + const duration = 2000; // Animation duration in milliseconds + const startTime = performance.now(); + + function updateCounter(currentTime) { + const elapsedTime = currentTime - startTime; + const progress = Math.min(elapsedTime / duration, 1); + const easeProgress = easeOutQuad(progress); + const currentCount = Math.floor(easeProgress * targetNumber); + + entry.target.textContent = currentCount; + + if (progress < 1) { + requestAnimationFrame(updateCounter); + } else { + entry.target.textContent = targetNumber; + } + } + + requestAnimationFrame(updateCounter); + observer.unobserve(entry.target); + } + }); + }, observerOptions); + + statNumbers.forEach(statNumber => { + statsObserver.observe(statNumber); + }); +} + +/** + * Easing function for smoother animation + * @param {number} t - Progress value between 0 and 1 + * @return {number} Eased value + */ +function easeOutQuad(t) { + return t * (2 - t); +} + +// Add a subtle parallax effect to the background blobs +window.addEventListener('mousemove', function(e) { + const blobs = document.querySelectorAll('.bg-blob'); + + blobs.forEach(blob => { + const speed = blob.classList.contains('bg-blob-1') ? 0.03 : 0.02; + const x = (window.innerWidth / 2 - e.clientX) * speed; + const y = (window.innerHeight / 2 - e.clientY) * speed; + + blob.style.transform = `translate(${x}px, ${y}px)`; + }); +}); +-------------------------------------------------- +File: ./web/about/about.html +-------------------------------------------------- +<!DOCTYPE html> +<html lang="en"> + +<head> + <!-- Google tag (gtag.js) --> + <script async src="https://www.googletagmanager.com/gtag/js?id=G-0LTP0WK7EM"></script> + <script> + window.dataLayer = window.dataLayer || []; + function gtag() { dataLayer.push(arguments); } + gtag('js', new Date()); + + gtag('config', 'G-0LTP0WK7EM'); + </script> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>About - DNAnalyzer</title> + <link rel="stylesheet" href="../style.css"> + <link rel="stylesheet" href="about.css"> + <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet"> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> + <link rel="shortcut icon" href="../assets/icons/Icon_Dark_BG.svg" type="image/svg+xml"> +</head> + +<body> + <!-- Background effects --> + <div class="bg-gradient"> + <div class="bg-blob bg-blob-1"></div> + <div class="bg-blob bg-blob-2"></div> + </div> + + <!-- Navbar --> + <nav class="navbar" id="navbar"> + <div class="container navbar-container"> + <a href="../index.html" class="logo"> + <img src="../assets/icons/Icon_Dark_BG.svg" alt="DNAnalyzer Logo"> + <span class="logo-text">DNAnalyzer</span> + </a> + + <button class="mobile-toggle" id="mobileToggle" aria-label="Toggle navigation"> + <i class="fas fa-bars"></i> + </button> + + <ul class="nav-links" id="navLinks"> + <li><a href="../index.html">Home</a></li> + <li><a href="../features/features.html">Features</a></li> + <li><a href="../analyzer/analyzer.html">Analyzer</a></li> + <li><a href="../server/server.html">Server</a></li> + <li><a href="../docs/docs.html">Docs</a></li> + <li><a href="about.html" class="active">About</a></li> + </ul> + + <div class="nav-buttons"> + <a href="https://github.com/VerisimilitudeX/DNAnalyzer" class="btn btn-secondary btn-sm"> + <i class="fab fa-github btn-icon"></i> GitHub + </a> + </div> + </div> + </nav> + + <!-- Main Content --> + <main> + <section class="about-hero"> + <div class="container"> + <div class="about-hero-content"> + <h1>About <span class="gradient-text">DNAnalyzer</span></h1> + <p>Revolutionizing DNA analysis through advanced machine learning and efficient computation</p> + </div> + </div> + </section> + + <section class="section mission-section"> + <div class="container"> + <div class="section-content"> + <div class="section-header"> + <h2>Our Mission</h2> + <div class="section-divider"></div> + </div> + <p class="mission-text">DNAnalyzer aims to democratize DNA analysis by providing powerful, + accessible tools for researchers, clinicians, and scientists worldwide. We're committed to + advancing genomic research through innovative technology and open collaboration.</p> + </div> + </div> + </section> + + <section class="section values-section"> + <div class="container"> + <div class="section-header"> + <h2>Our Core Values</h2> + <div class="section-divider"></div> + </div> + + <div class="values-grid"> + <div class="value-card"> + <div class="value-icon"> + <i class="fas fa-dna"></i> + </div> + <h3>Innovation</h3> + <p>Leveraging cutting-edge technology and machine learning to provide accurate, comprehensive + DNA analysis capabilities.</p> + </div> + + <div class="value-card"> + <div class="value-icon"> + <i class="fas fa-users"></i> + </div> + <h3>Accessibility</h3> + <p>Making advanced DNA analysis tools available to researchers and clinicians worldwide through + an intuitive interface.</p> + </div> + + <div class="value-card"> + <div class="value-icon"> + <i class="fas fa-shield-alt"></i> + </div> + <h3>Privacy</h3> + <p>Ensuring user data remains secure and private with our on-device processing approach and + transparent practices.</p> + </div> + + <div class="value-card"> + <div class="value-icon"> + <i class="fas fa-flask"></i> + </div> + <h3>Scientific Rigor</h3> + <p>Maintaining the highest standards of accuracy and reliability through extensive testing and + validation.</p> + </div> + </div> + </div> + </section> + + <section class="section technology-section section-dark"> + <div class="container"> + <div class="section-header"> + <h2>Our Technology</h2> + <div class="section-divider"></div> + </div> + + <div class="tech-showcase"> + <div class="tech-image"> + <img src="../assets/icons/Icon_Dark_BG.svg" alt="DNAnalyzer Technology" class="tech-logo"> + </div> + + <div class="tech-features"> + <div class="tech-feature"> + <div class="feature-icon"> + <i class="fas fa-microchip"></i> + </div> + <div class="feature-content"> + <h3>Advanced Analysis</h3> + <p>Identifies proteins, amino acids, start and stop codons, high coverage regions, and + regulatory elements with high accuracy.</p> + </div> + </div> + + <div class="tech-feature"> + <div class="feature-icon"> + <i class="fas fa-brain"></i> + </div> + <div class="feature-content"> + <h3>Machine Learning</h3> + <p>Utilizes advanced algorithms and ML models to process and analyze DNA sequences + efficiently.</p> + </div> + </div> + + <div class="tech-feature"> + <div class="feature-icon"> + <i class="fas fa-server"></i> + </div> + <div class="feature-content"> + <h3>Scalable Platform</h3> + <p>Built on modern technology stack ensuring fast processing of large sequences and + reliable performance.</p> + </div> + </div> + + <div class="tech-feature"> + <div class="feature-icon"> + <i class="fas fa-user-shield"></i> + </div> + <div class="feature-content"> + <h3>Privacy-First Design</h3> + <p>All processing happens on your device, ensuring your genetic data remains private and + secure.</p> + </div> + </div> + </div> + </div> + </div> + </section> + + <section class="section timeline-section"> + <div class="container"> + <div class="section-header"> + <h2>Our Journey</h2> + <div class="section-divider"></div> + <p class="section-subtitle">The evolution of DNAnalyzer from concept to cutting-edge DNA analysis + platform</p> + </div> + + <div class="vertical-timeline"> + <!-- First milestone --> + <div class="timeline-milestone"> + <div class="milestone-year">2022</div> + <div class="milestone-dot"></div> + <div class="milestone-card"> + <h3>Project Inception</h3> + <p>Piyush Acharya initiates DNAnalyzer as a response to privacy concerns and high costs in + the field of personal genomics.</p> + </div> + </div> + + <!-- Second milestone --> + <div class="timeline-milestone milestone-right"> + <div class="milestone-year">2023</div> + <div class="milestone-dot"></div> + <div class="milestone-card"> + <h3>Team Expansion</h3> + <p>Collaborator @LimesKey joins, and the project attracts its first contributors from the + computational biology community.</p> + </div> + </div> + + <!-- Third milestone --> + <div class="timeline-milestone"> + <div class="milestone-year">2023</div> + <div class="milestone-dot"></div> + <div class="milestone-card"> + <h3>Nonprofit Foundation</h3> + <p>DNAnalyzer becomes a fiscally sponsored 501(c)(3) nonprofit organization (EIN: + 81-2908499) to advance DNA analysis technology.</p> + </div> + </div> + + <!-- Fourth milestone --> + <div class="timeline-milestone milestone-right"> + <div class="milestone-year">2024</div> + <div class="milestone-dot"></div> + <div class="milestone-card"> + <h3>ML Integration</h3> + <p>Launch of machine learning components with the "DNAI" model, significantly enhancing + analysis capabilities.</p> + </div> + </div> + + <!-- Fifth milestone --> + <div class="timeline-milestone"> + <div class="milestone-year">2024</div> + <div class="milestone-dot"></div> + <div class="milestone-card"> + <h3>Web Platform</h3> + <p>Release of the comprehensive web interface, making DNA analysis accessible to researchers + worldwide.</p> + </div> + </div> + + <!-- Sixth milestone --> + <div class="timeline-milestone milestone-right"> + <div class="milestone-year">2025</div> + <div class="milestone-dot"></div> + <div class="milestone-card"> + <h3>Open Source Growth</h3> + <p>Community expands to 46+ contributors, including scientists from leading research + institutions around the world.</p> + </div> + </div> + </div> + </div> + </section> + + <section class="section team-section section-dark"> + <div class="container"> + <div class="section-header"> + <h2>Meet Our Leadership</h2> + <div class="section-divider"></div> + </div> + + <div class="team-horizontal"> + <div class="team-card"> + <div class="team-avatar"> + <img src="../assets/icons/Icon_Dark_BG.svg" alt="Piyush Acharya"> + </div> + <div class="team-info"> + <h3>Piyush Acharya</h3> + <p class="team-role">Founder & Lead Developer</p> + <p class="team-bio">Initiated DNAnalyzer to democratize genome analysis and make it + accessible while ensuring privacy.</p> + <div class="team-social"> + <a href="#" class="social-icon"><i class="fab fa-github"></i></a> + <a href="#" class="social-icon"><i class="fab fa-linkedin"></i></a> + <a href="https://www.x.com/DNAnalyzer_" class="social-icon"><i + class="fab fa-twitter"></i></a> + </div> + </div> + </div> + + <div class="team-card"> + <div class="team-avatar"> + <img src="../assets/icons/Icon_Dark_BG.svg" alt="LimesKey"> + </div> + <div class="team-info"> + <h3>@LimesKey</h3> + <p class="team-role">Co-Lead & ML Specialist</p> + <p class="team-bio">Leads the machine learning initiatives and computational biology aspects + of DNAnalyzer.</p> + <div class="team-social"> + <a href="#" class="social-icon"><i class="fab fa-github"></i></a> + <a href="#" class="social-icon"><i class="fab fa-linkedin"></i></a> + <a href="https://www.x.com/DNAnalyzer_" class="social-icon"><i + class="fab fa-twitter"></i></a> + </div> + </div> + </div> + </div> + + <div class="community-card"> + <div class="community-icon"> + <i class="fas fa-users"></i> + </div> + <h3>Open Source Community</h3> + <p class="community-count">46+ Contributors</p> + <p class="community-description">Dedicated contributors from Microsoft Research, University of + Macedonia, Northeastern University, and more.</p> + <div class="community-links"> + <a href="https://github.com/VerisimilitudeX/DNAnalyzer" class="btn btn-secondary btn-sm"> + <i class="fab fa-github btn-icon"></i> GitHub + </a> + <a href="https://discord.gg/xNpujz49gj" class="btn btn-secondary btn-sm"> + <i class="fab fa-discord btn-icon"></i> Discord + </a> + </div> + </div> + </div> + </section> + + <section class="section stats-section"> + <div class="container"> + <div class="stats-grid"> + <div class="stat-item"> + <div class="stat-icon"> + <i class="fas fa-star"></i> + </div> + <div class="stat-number" data-count="141">141</div> + <div class="stat-label">GitHub Stars</div> + </div> + + <div class="stat-item"> + <div class="stat-icon"> + <i class="fas fa-code-branch"></i> + </div> + <div class="stat-number" data-count="46">46</div> + <div class="stat-label">Contributors</div> + </div> + + <div class="stat-item"> + <div class="stat-icon"> + <i class="fas fa-dna"></i> + </div> + <div class="stat-number" data-count="5">5</div> + <div class="stat-suffix">M+</div> + <div class="stat-label">DNA Sequences Analyzed</div> + </div> + + <div class="stat-item"> + <div class="stat-icon"> + <i class="fas fa-globe"></i> + </div> + <div class="stat-label">Global Impact</div> + <div class="stat-description">Users from 42 countries</div> + </div> + </div> + </div> + </section> + + <section class="section future-vision-section"> + <div class="container"> + <div class="section-header"> + <h2>The Future of DNAnalyzer</h2> + <div class="section-divider"></div> + </div> + + <div class="future-grid-container"> + <div class="future-center"> + <img src="../assets/icons/Icon_Dark_BG.svg" alt="DNAnalyzer Logo" class="center-logo"> + </div> + + <div class="future-card top-left"> + <div class="future-card-inner"> + <div class="future-icon"> + <i class="fas fa-brain"></i> + </div> + <h3>Neural Networks</h3> + <div class="future-detail"> + <p>Our next-generation neural networks will process genotyped data from consumer DNA + tests with unprecedented accuracy.</p> + </div> + </div> + </div> + + <div class="future-card top-right"> + <div class="future-card-inner"> + <div class="future-icon"> + <i class="fas fa-project-diagram"></i> + </div> + <h3>DIAMOND Integration</h3> + <div class="future-detail"> + <p>Integration with the DIAMOND sequence aligner will deliver up to 20,000x faster + sequence alignment compared to traditional methods.</p> + </div> + </div> + </div> + + <div class="future-card bottom-left"> + <div class="future-card-inner"> + <div class="future-icon"> + <i class="fas fa-database"></i> + </div> + <h3>Genomic Database</h3> + <div class="future-detail"> + <p>A high-performance SQL database architecture specially designed for genomic data + integration across thousands of species.</p> + </div> + </div> + </div> + + <div class="future-card bottom-right"> + <div class="future-card-inner"> + <div class="future-icon"> + <i class="fas fa-layer-group"></i> + </div> + <h3>Advanced Analysis</h3> + <div class="future-detail"> + <p>Upcoming modules for repeat element detection, CRISPR site identification, and + comprehensive protein domain searches.</p> + </div> + </div> + </div> + </div> + </div> + </section> + + <section class="section cta-section section-dark"> + <div class="container"> + <div class="cta-content"> + <h2>Join Our Community</h2> + <p>Contribute to the future of DNA analysis technology and help us make genomic insights accessible + to all.</p> + <div class="cta-buttons"> + <a href="https://github.com/VerisimilitudeX/DNAnalyzer" class="btn btn-primary"> + <i class="fab fa-github btn-icon"></i> Join on GitHub + </a> + <a href="https://discord.gg/xNpujz49gj" class="btn btn-secondary"> + <i class="fab fa-discord btn-icon"></i> Join Discord + </a> + </div> + </div> + </div> + </section> + </main> + + <!-- Footer --> + <footer class="footer"> + <div class="container"> + <div class="footer-grid"> + <div class="footer-brand"> + <img src="../assets/icons/Icon_Dark_BG.svg" alt="DNAnalyzer Logo"> + <p>DNAnalyzer is a powerful, privacy-focused DNA analysis tool using cutting-edge machine learning + models for accurate, on-device genomic analysis.</p> + + <div class="footer-social"> + <a href="https://github.com/VerisimilitudeX/DNAnalyzer" class="social-link"> + <i class="fab fa-github"></i> + </a> + <a href="https://discord.gg/xNpujz49gj" class="social-link"> + <i class="fab fa-discord"></i> + </a> + <a href="https://www.x.com/DNAnalyzer_" class="social-link"> + <i class="fab fa-twitter"></i> + </a> + </div> + </div> + + <div class="footer-nav"> + <h4>Product</h4> + <ul> + <li><a href="../features/features.html">Features</a></li> + <li><a href="../analyzer/analyzer.html">DNA Analyzer</a></li> + <li><a href="../server/server.html">Server</a></li> + <li><a href="../docs/docs.html">Documentation</a></li> + </ul> + </div> + + <div class="footer-nav"> + <h4>Resources</h4> + <ul> + <li><a href="../docs/getting-started.md">Getting Started</a></li> + <li><a href="../docs/citations.md">Citations</a></li> + <li><a href="../docs/research/genes.md">Gene Research</a></li> + <li><a href="../docs/samples/cli-arguments-examples.md">CLI Examples</a></li> + </ul> + </div> + + <div class="footer-nav"> + <h4>Community</h4> + <ul> + <li><a href="https://github.com/VerisimilitudeX/DNAnalyzer">GitHub</a></li> + <li><a href="https://discord.gg/xNpujz49gj">Discord</a></li> + <li><a href="../docs/contributing/CONTRIBUTING.md">Contributing</a></li> + <li><a href="../CODE_OF_CONDUCT.md">Code of Conduct</a></li> + </ul> + </div> + </div> + + <div class="footer-bottom"> + <div class="footer-copyright"> + Copyright Piyush Acharya 2025. DNAnalyzer is a fiscally sponsored 501(c)(3) nonprofit (EIN: + 81-2908499). MIT License. + </div> + + <div class="footer-links"> + <a href="../LICENSE.md">License</a> + <a href="../SECURITY.md">Security</a> + <a href="../CITATION.cff">Citation</a> + </div> + </div> + </div> + </footer> + + <script src="about.js"></script> +</body> + +</html> +-------------------------------------------------- +File: ./web/about/about.css +-------------------------------------------------- +/* About Page Styles */ + +/* General section styling */ +.section { + padding: 5rem 0; +} + +.section-dark { + background: linear-gradient(135deg, rgba(5, 30, 62, 0.7), rgba(0, 20, 39, 0.7)); + border-top: 1px solid rgba(255, 255, 255, 0.05); + border-bottom: 1px solid rgba(255, 255, 255, 0.05); +} + +.section-header { + text-align: center; + margin-bottom: 3rem; + position: relative; +} + +.section-header h2 { + font-size: 2.5rem; + font-weight: 700; + margin-bottom: 0.5rem; + background: linear-gradient(135deg, var(--magenta), var(--blue)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + display: inline-block; +} + +.section-divider { + width: 80px; + height: 4px; + background: linear-gradient(135deg, var(--magenta), var(--blue)); + margin: 1rem auto; + border-radius: 2px; +} + +.section-subtitle { + max-width: 700px; + margin: 0 auto; + font-size: 1.1rem; + color: rgba(255, 255, 255, 0.8); +} + +.section-content { + max-width: 900px; + margin: 0 auto; +} + +/* Hero section */ +.about-hero { + padding: 9rem 0 5rem; + text-align: center; + position: relative; + background: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.1)); +} + +.about-hero-content h1 { + font-size: 3.5rem; + margin-bottom: 1.5rem; +} + +.about-hero-content p { + font-size: 1.2rem; + color: rgba(255, 255, 255, 0.9); + max-width: 800px; + margin: 0 auto; + line-height: 1.8; +} + +/* Mission section */ +.mission-section { + text-align: center; +} + +.mission-text { + font-size: 1.3rem; + line-height: 1.8; + max-width: 900px; + margin: 0 auto; + color: rgba(255, 255, 255, 0.9); +} + +/* Values section */ +.values-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 2rem; + margin-top: 2rem; +} + +.value-card { + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + padding: 2rem; + text-align: center; + transition: all 0.3s ease; +} + +.value-card:hover { + transform: translateY(-5px); + background: rgba(255, 255, 255, 0.08); + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.2); + border-color: rgba(255, 255, 255, 0.15); +} + +.value-icon { + width: 70px; + height: 70px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + margin: 0 auto 1.5rem; + background: linear-gradient(135deg, rgba(255, 0, 102, 0.15), rgba(0, 164, 239, 0.15)); + border: 2px solid transparent; + transition: all 0.3s ease; +} + +.value-card:hover .value-icon { + background: linear-gradient(135deg, rgba(255, 0, 102, 0.3), rgba(0, 164, 239, 0.3)); + transform: scale(1.1); +} + +.value-icon i { + font-size: 1.8rem; + background: linear-gradient(135deg, var(--magenta), var(--blue)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} + +.value-card h3 { + font-size: 1.5rem; + margin-bottom: 1rem; + color: var(--white); +} + +.value-card p { + color: rgba(255, 255, 255, 0.8); + line-height: 1.6; +} + +/* Technology section */ +.tech-showcase { + display: grid; + grid-template-columns: 1fr 1.5fr; + gap: 4rem; + align-items: center; +} + +.tech-image { + text-align: center; +} + +.tech-logo { + max-width: 100%; + height: auto; + max-height: 300px; + animation: pulse 3s infinite alternate; +} + +@keyframes pulse { + from { + transform: scale(1); + opacity: 0.8; + } + to { + transform: scale(1.05); + opacity: 1; + } +} + +.tech-features { + display: grid; + grid-template-columns: 1fr; + gap: 1.5rem; +} + +.tech-feature { + display: flex; + align-items: flex-start; + gap: 1.5rem; + background: rgba(255, 255, 255, 0.05); + border-radius: 12px; + padding: 1.5rem; + transition: all 0.3s ease; +} + +.tech-feature:hover { + transform: translateX(10px); + background: rgba(255, 255, 255, 0.08); +} + +.feature-icon { + flex-shrink: 0; + width: 50px; + height: 50px; + border-radius: 12px; + display: flex; + align-items: center; + justify-content: center; + background: linear-gradient(135deg, rgba(255, 0, 102, 0.2), rgba(0, 164, 239, 0.2)); + transition: all 0.3s ease; +} + +.tech-feature:hover .feature-icon { + background: linear-gradient(135deg, rgba(255, 0, 102, 0.3), rgba(0, 164, 239, 0.3)); + transform: scale(1.1); +} + +.feature-icon i { + font-size: 1.5rem; + background: linear-gradient(135deg, var(--magenta), var(--blue)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} + +.feature-content h3 { + margin-top: 0; + margin-bottom: 0.5rem; + font-size: 1.2rem; +} + +.feature-content p { + margin: 0; + color: rgba(255, 255, 255, 0.8); +} + +/* Timeline section - completely rewritten */ +.timeline-section { + position: relative; + padding: 5rem 0; +} + +.vertical-timeline { + position: relative; + max-width: 1100px; + margin: 0 auto; + padding: 2rem 0; +} + +.vertical-timeline::before { + content: ''; + position: absolute; + width: 2px; + height: 100%; + background: linear-gradient(to bottom, var(--magenta), var(--blue)); + left: 50%; + transform: translateX(-50%); + z-index: 1; +} + +.timeline-milestone { + display: flex; + position: relative; + margin-bottom: 3rem; +} + +.milestone-year { + position: absolute; + left: calc(50% - 60px); + transform: translateX(-50%); + background: var(--dark-blue); + color: var(--blue); + font-weight: 600; + z-index: 2; + padding: 0.2rem 0; +} + +.milestone-dot { + position: absolute; + width: 20px; + height: 20px; + border-radius: 50%; + background: linear-gradient(135deg, var(--magenta), var(--blue)); + top: 0; + left: 50%; + transform: translateX(-50%); + z-index: 2; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); +} + +.milestone-card { + width: 40%; + background: rgba(255, 255, 255, 0.05); + border-radius: 12px; + padding: 1.5rem; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + border: 1px solid rgba(255, 255, 255, 0.1); + margin-left: auto; + margin-right: 60px; + position: relative; + transition: all 0.3s ease; +} + +.milestone-right .milestone-card { + margin-left: 60px; + margin-right: auto; +} + +.milestone-card:hover { + transform: translateY(-5px); + background: rgba(255, 255, 255, 0.08); + box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2); +} + +.milestone-card h3 { + margin-top: 0; + margin-bottom: 0.5rem; + font-size: 1.3rem; +} + +.milestone-card p { + margin-bottom: 0; + color: rgba(255, 255, 255, 0.8); +} + +/* Connecting lines from timeline to cards */ +.milestone-card::before { + content: ''; + position: absolute; + width: 20px; + height: 2px; + background: linear-gradient(to right, var(--magenta), var(--blue)); + top: 10px; + right: -20px; +} + +.milestone-right .milestone-card::before { + left: -20px; + right: auto; +} + + +/* Team section */ +.team-horizontal { + display: flex; + gap: 2rem; + margin-bottom: 3rem; + flex-wrap: wrap; +} + +.team-card { + display: flex; + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + padding: 1.5rem; + transition: all 0.3s ease; + flex: 1; + min-width: 300px; + gap: 1.5rem; + align-items: center; +} + +.team-card:hover { + transform: translateY(-5px); + background: rgba(255, 255, 255, 0.08); + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.2); + border-color: rgba(255, 255, 255, 0.15); +} + +.team-avatar { + width: 100px; + height: 100px; + border-radius: 50%; + overflow: hidden; + background: linear-gradient(135deg, rgba(255, 0, 102, 0.1), rgba(0, 164, 239, 0.1)); + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.team-avatar img { + width: 60%; + height: auto; +} + +.team-info { + flex-grow: 1; +} + +.team-info h3 { + margin-top: 0; + margin-bottom: 0.3rem; + font-size: 1.4rem; +} + +.team-role { + color: var(--blue); + font-weight: 500; + margin-bottom: 0.5rem; + font-size: 0.95rem; +} + +.team-bio { + color: rgba(255, 255, 255, 0.8); + margin-bottom: 1rem; + font-size: 0.95rem; + line-height: 1.5; +} + +.team-social { + display: flex; + gap: 0.8rem; +} + +.social-icon { + width: 36px; + height: 36px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + background: rgba(255, 255, 255, 0.1); + color: var(--white); + transition: all 0.3s ease; +} + +.social-icon:hover { + background: rgba(255, 255, 255, 0.2); + transform: translateY(-3px); +} + +/* Community Card */ +.community-card { + background: linear-gradient(135deg, rgba(255, 0, 102, 0.1), rgba(0, 164, 239, 0.1)); + border-radius: 16px; + padding: 2.5rem; + text-align: center; + border: 1px solid rgba(255, 255, 255, 0.1); + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); + transition: all 0.3s ease; +} + +.community-card:hover { + transform: translateY(-8px); + box-shadow: 0 15px 40px rgba(0, 0, 0, 0.2); + border-color: rgba(255, 255, 255, 0.2); +} + +.community-icon { + width: 80px; + height: 80px; + border-radius: 50%; + background: linear-gradient(135deg, var(--magenta), var(--blue)); + margin: 0 auto 1.5rem; + display: flex; + align-items: center; + justify-content: center; +} + +.community-icon i { + font-size: 2rem; + color: white; +} + +.community-card h3 { + font-size: 1.8rem; + margin-bottom: 0.5rem; +} + +.community-count { + font-size: 1.2rem; + font-weight: 600; + color: var(--blue); + margin-bottom: 1rem; +} + +.community-description { + color: rgba(255, 255, 255, 0.8); + margin-bottom: 1.5rem; + line-height: 1.6; +} + +.community-links { + display: flex; + justify-content: center; + gap: 1rem; +} + +/* Stats section */ +.stats-section { + padding: 4rem 0; + background: linear-gradient(135deg, rgba(5, 30, 62, 0.8), rgba(0, 20, 39, 0.8)); +} + +.stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: 2rem; + text-align: center; +} + +.stat-item { + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + padding: 2rem 1rem; + transition: all 0.3s ease; +} + +.stat-item:hover { + transform: translateY(-5px); + background: rgba(255, 255, 255, 0.08); + box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2); +} + +.stat-icon { + width: 60px; + height: 60px; + border-radius: 50%; + background: linear-gradient(135deg, rgba(255, 0, 102, 0.2), rgba(0, 164, 239, 0.2)); + display: flex; + align-items: center; + justify-content: center; + margin: 0 auto 1rem; +} + +.stat-icon i { + font-size: 1.5rem; + background: linear-gradient(135deg, var(--magenta), var(--blue)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} + +.stat-number { + font-size: 2.5rem; + font-weight: 700; + background: linear-gradient(135deg, var(--magenta), var(--blue)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + margin-bottom: 0.2rem; + display: inline-block; +} + +.stat-suffix { + font-size: 1.8rem; + font-weight: 700; + background: linear-gradient(135deg, var(--magenta), var(--blue)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + display: inline-block; +} + +.stat-label { + color: var(--white); + font-weight: 500; + margin-bottom: 0.5rem; +} + +.stat-description { + color: rgba(255, 255, 255, 0.7); + font-size: 0.9rem; +} + +/* Future Vision Section - completely rewritten */ +.future-vision-section { + padding: 6rem 0; + background: linear-gradient(135deg, rgba(5, 30, 62, 0.5), rgba(0, 20, 39, 0.5)); + position: relative; + overflow: hidden; +} + +.future-grid-container { + position: relative; + width: 100%; + max-width: 1100px; + height: 550px; + margin: 0 auto; +} + +.future-center { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 120px; + height: 120px; + border-radius: 50%; + background: linear-gradient(135deg, rgba(255, 0, 102, 0.3), rgba(0, 164, 239, 0.3)); + display: flex; + align-items: center; + justify-content: center; + z-index: 5; + box-shadow: 0 0 30px rgba(0, 164, 239, 0.4); +} + +.center-logo { + width: 60%; + height: auto; + animation: pulse-grow 3s infinite alternate; +} + +@keyframes pulse-grow { + from { + transform: scale(1); + opacity: 0.8; + } + to { + transform: scale(1.2); + opacity: 1; + } +} + +/* Diagonal lines */ +.future-grid-container::before, +.future-grid-container::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + background: linear-gradient(135deg, rgba(255, 0, 102, 0.2), rgba(0, 164, 239, 0.2)); + height: 2px; + width: 70%; + transform-origin: center; + z-index: 1; +} + +.future-grid-container::before { + transform: translate(-50%, -50%) rotate(45deg); +} + +.future-grid-container::after { + transform: translate(-50%, -50%) rotate(-45deg); +} + +.future-card { + position: absolute; + width: 240px; + height: 150px; + z-index: 2; +} + +.future-card-inner { + width: 100%; + height: 100%; + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + padding: 1.5rem; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + transition: all 0.3s ease; +} + +.future-card-inner:hover { + transform: translateY(-5px); + background: rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.2); + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.2); +} + +.future-icon { + width: 50px; + height: 50px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.1); + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 0.8rem; +} + +.future-icon i { + font-size: 1.5rem; + background: linear-gradient(135deg, var(--magenta), var(--blue)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} + +.future-card h3 { + font-size: 1rem; + margin: 0 0 0.5rem 0; + color: var(--white); +} + +.future-detail { + display: none; + margin-top: 0.5rem; +} + +.future-card-inner:hover .future-detail { + display: block; +} + +.future-detail p { + font-size: 0.85rem; + color: rgba(255, 255, 255, 0.8); + margin: 0; + line-height: 1.4; +} + +/* Card positioning exactly matching the image */ +.top-left { + top: 25%; + left: 0; + transform: translateY(-50%); +} + +.top-right { + top: 25%; + right: 0; + transform: translateY(-50%); +} + +.bottom-left { + bottom: 25%; + left: 0; + transform: translateY(50%); +} + +.bottom-right { + bottom: 25%; + right: 0; + transform: translateY(50%); +} + +/* Connecting lines */ +.hexagon-container::before, +.hexagon-container::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 50%; + height: 1px; + background: linear-gradient(to right, rgba(255, 0, 102, 0.3), rgba(0, 164, 239, 0.3)); + z-index: 1; +} + +.hexagon-container::before { + transform: translate(-50%, -50%) rotate(45deg); +} + +.hexagon-container::after { + transform: translate(-50%, -50%) rotate(-45deg); +} + +.vision-details { + display: flex; + flex-direction: column; + gap: 1.5rem; +} + +.vision-detail { + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + padding: 1.5rem; + transition: all 0.3s ease; +} + +.vision-detail.active { + background: rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.2); + box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); + transform: translateY(-5px) translateX(10px); +} + +.vision-detail h3 { + display: flex; + align-items: center; + gap: 0.8rem; + margin-top: 0; + margin-bottom: 0.8rem; + font-size: 1.3rem; +} + +.vision-detail h3 i { + font-size: 1.2rem; + color: var(--blue); +} + +.vision-detail p { + color: rgba(255, 255, 255, 0.8); + line-height: 1.6; + margin: 0; +} + +/* CTA Section */ +.cta-section { + text-align: center; + padding: 5rem 0; +} + +.cta-content h2 { + font-size: 2.5rem; + margin-bottom: 1rem; +} + +.cta-content p { + max-width: 600px; + margin: 0 auto 2rem; + font-size: 1.1rem; + color: rgba(255, 255, 255, 0.9); +} + +.cta-buttons { + display: flex; + justify-content: center; + gap: 1rem; +} + +/* Media Queries */ +@media screen and (max-width: 1200px) { + .vision-container { + grid-template-columns: 1fr; + gap: 2rem; + } + + .vision-canvas { + height: 400px; + } +} + +@media screen and (max-width: 992px) { + .tech-showcase { + grid-template-columns: 1fr; + gap: 3rem; + } + + /* Timeline responsive styles */ + .vertical-timeline::before { + left: 30px; + } + + .timeline-milestone { + margin-left: 30px; + } + + .milestone-dot { + left: 30px; + +@media screen and (max-width: 768px) { + .about-hero-content h1 { + font-size: 2.8rem; + } + + .section-header h2 { + font-size: 2rem; + } + + .mission-text { + font-size: 1.1rem; + } + + .hexagon { + width: 150px; + height: 150px; + } + + .hex-content { + width: 130px; + height: 130px; + } + + .hex-icon { + width: 40px; + height: 40px; + } + + .hex-content h3 { + font-size: 0.85rem; + } + + .cta-buttons { + flex-direction: column; + max-width: 300px; + margin: 0 auto; + } +} + +@media screen and (max-width: 576px) { + .about-hero-content h1 { + font-size: 2.3rem; + } + + .about-hero-content p { + font-size: 1rem; + } + + .section { + padding: 3rem 0; + } + + .timeline-content { + padding: 1rem; + } + + .timeline-item { + padding-left: 4rem; + } + + .timeline-item:nth-child(odd) { + padding-left: 4rem; + } + + .stats-grid { + grid-template-columns: 1fr; + } + + .vision-canvas { + height: 350px; + } + + .hexagon-center { + width: 100px; + height: 100px; + } + + .hexagon { + width: 120px; + height: 120px; + } + + .hex-content { + width: 100px; + height: 100px; + } +} +-------------------------------------------------- + +Directory: analyzer +================================================== +File: ./web/analyzer/analyzer.css +-------------------------------------------------- +/* Analyzer Page Specific Styles */ + +/* Main layout */ +.analyzer-main { + padding-top: 100px; + min-height: calc(100vh - 100px); +} + +.analyzer-header { + text-align: center; + margin-bottom: var(--space-xl); +} + +.analyzer-header h1 { + margin-bottom: var(--space-md); +} + +.analyzer-header p { + font-size: 1.1rem; + max-width: 600px; + margin: 0 auto; + color: rgba(255, 255, 255, 0.8); +} + +/* Dashboard layout */ +.analyzer-dashboard { + display: grid; + grid-template-columns: 280px 1fr; + gap: var(--space-xl); + margin-bottom: var(--space-xxl); +} + +/* Sidebar */ +.dashboard-sidebar { + position: sticky; + top: 100px; + height: fit-content; +} + +.sidebar-section { + background: rgba(255, 255, 255, 0.05); + border-radius: var(--radius-lg); + padding: var(--space-lg); + margin-bottom: var(--space-lg); + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.sidebar-section h3 { + font-size: 1.1rem; + margin-bottom: var(--space-md); + color: var(--white); +} + +/* History list */ +.history-list { + background: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-md); + padding: var(--space-sm); +} + +.history-empty { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: var(--space-lg); + color: rgba(255, 255, 255, 0.5); + text-align: center; +} + +.history-empty i { + font-size: 1.5rem; + margin-bottom: var(--space-sm); +} + +.history-item { + display: flex; + align-items: center; + gap: var(--space-sm); + padding: var(--space-sm); + background: rgba(255, 255, 255, 0.05); + border-radius: var(--radius-md); + margin-bottom: var(--space-xs); + cursor: pointer; + transition: all var(--transition-fast); +} + +.history-item:hover { + background: rgba(255, 255, 255, 0.1); +} + +.history-item i { + color: var(--blue); + font-size: 1rem; +} + +.history-details { + flex: 1; + overflow: hidden; +} + +.history-name { + font-size: 0.9rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + color: var(--white); +} + +.history-time { + font-size: 0.8rem; + color: rgba(255, 255, 255, 0.5); +} + +/* Quick actions */ +.quick-actions { + display: flex; + flex-direction: column; + gap: var(--space-sm); +} + +.sidebar-btn { + display: flex; + align-items: center; + gap: var(--space-sm); + padding: var(--space-md); + background: rgba(255, 255, 255, 0.08); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: var(--radius-md); + color: var(--white); + font-size: 0.9rem; + font-weight: 500; + cursor: pointer; + transition: all var(--transition-fast); +} + +.sidebar-btn:hover { + background: rgba(255, 255, 255, 0.12); + transform: translateY(-2px); +} + +.sidebar-btn i { + color: var(--blue); +} + +/* API Status */ +.api-status-container { + margin-bottom: 0; +} + +.status-indicator { + display: flex; + align-items: center; + gap: var(--space-sm); + padding: var(--space-md); + background: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-md); +} + +.status-dot { + width: 12px; + height: 12px; + border-radius: 50%; + background: var(--medium-gray); +} + +.status-dot.pulse { + animation: pulse 1.5s infinite; +} + +.status-dot.online { + background: var(--success); +} + +.status-dot.offline { + background: var(--error); +} + +@keyframes pulse { + 0% { + transform: scale(0.9); + opacity: 0.7; + } + 50% { + transform: scale(1.1); + opacity: 1; + } + 100% { + transform: scale(0.9); + opacity: 0.7; + } +} + +/* Dashboard content */ +.dashboard-content { + min-height: 500px; +} + +/* Tabs */ +.analyzer-tabs { + display: flex; + gap: var(--space-md); + margin-bottom: var(--space-lg); +} + +.tab-btn { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + gap: var(--space-sm); + padding: var(--space-md); + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: var(--radius-md); + color: rgba(255, 255, 255, 0.8); + font-size: 1rem; + font-weight: 500; + cursor: pointer; + transition: all var(--transition-fast); +} + +.tab-btn:hover { + background: rgba(255, 255, 255, 0.08); +} + +.tab-btn.active { + background: linear-gradient(135deg, rgba(255, 0, 102, 0.15), rgba(0, 164, 239, 0.15)); + border-color: transparent; + border-bottom: 2px solid var(--blue); + color: var(--white); +} + +.tab-btn i { + color: var(--blue); +} + +.tab-content { + display: none; +} + +.tab-content.active { + display: block; +} + +/* File upload */ +.analyzer-upload { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: var(--space-xxl) var(--space-md); + background: rgba(255, 255, 255, 0.05); + border: 2px dashed rgba(255, 255, 255, 0.15); + border-radius: var(--radius-lg); + text-align: center; + cursor: pointer; + transition: all var(--transition-normal); + margin-bottom: var(--space-xl); +} + +.analyzer-upload:hover { + background: rgba(255, 255, 255, 0.08); + border-color: var(--blue); + transform: translateY(-2px); +} + +.analyzer-upload.drag-over { + background: rgba(0, 164, 239, 0.1); + border-color: var(--blue); +} + +.analyzer-upload i { + font-size: 3rem; + color: var(--blue); + margin-bottom: var(--space-md); +} + +.analyzer-upload h3 { + margin-bottom: var(--space-sm); + color: var(--white); +} + +.analyzer-upload p { + margin-bottom: var(--space-lg); + color: rgba(255, 255, 255, 0.7); + max-width: 400px; +} + +.upload-formats { + font-size: 0.8rem; + color: rgba(255, 255, 255, 0.5); +} + +/* Batch upload */ +.batch-upload { + margin-bottom: var(--space-xl); +} + +.batch-files { + display: flex; + flex-direction: column; + gap: var(--space-md); + margin: var(--space-lg) 0; +} + +.batch-file { + display: flex; + align-items: center; + background: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-md); + padding: var(--space-md); +} + +.batch-status { + margin-left: auto; + font-size: 0.9rem; + padding: var(--space-xs) var(--space-sm); + border-radius: var(--radius-sm); + background: rgba(255, 255, 255, 0.1); +} + +.batch-status.queued { + background: rgba(255, 255, 255, 0.15); +} + +.batch-status.processing { + background: rgba(0, 164, 239, 0.2); + color: var(--blue); +} + +.batch-status.completed { + background: rgba(40, 167, 69, 0.2); + color: var(--success); +} + +.batch-status.error { + background: rgba(220, 53, 69, 0.2); + color: var(--error); +} + +.batch-progress { + margin-top: var(--space-lg); +} + +.progress-container { + width: 100%; + height: 8px; + background: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-sm); + overflow: hidden; + margin-bottom: var(--space-sm); +} + +.progress-bar { + height: 100%; + background: var(--blue); + transition: width 0.3s ease; +} + +.progress-info { + display: flex; + justify-content: space-between; + font-size: 0.9rem; + color: rgba(255, 255, 255, 0.7); +} + +/* Genetic testing forms */ +.genetic-testing-form { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); + gap: var(--space-lg); + margin-bottom: var(--space-xl); +} + +.form-section { + background: rgba(255, 255, 255, 0.05); + border-radius: var(--radius-lg); + padding: var(--space-lg); + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.form-section h3 { + margin-bottom: var(--space-md); + font-size: 1.1rem; +} + +.form-group { + margin-bottom: var(--space-md); +} + +.form-group label { + display: block; + margin-bottom: var(--space-xs); + font-size: 0.9rem; + color: rgba(255, 255, 255, 0.8); +} + +.form-control { + width: 100%; + padding: var(--space-sm) var(--space-md); + background: rgba(0, 0, 0, 0.2); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: var(--radius-md); + color: var(--white); + font-size: 0.9rem; + transition: all var(--transition-fast); +} + +.form-control:focus { + border-color: var(--blue); + outline: none; +} + +.form-select { + height: 42px; +} + +.testing-options { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: var(--space-md); + margin-top: var(--space-lg); +} + +.test-option { + background: rgba(255, 255, 255, 0.05); + border-radius: var(--radius-md); + padding: var(--space-md); + border: 1px solid rgba(255, 255, 255, 0.1); + transition: all var(--transition-fast); + cursor: pointer; +} + +.test-option:hover { + background: rgba(255, 255, 255, 0.08); + transform: translateY(-2px); +} + +.test-option.selected { + border-color: var(--blue); + background: rgba(0, 164, 239, 0.1); +} + +.test-option-header { + display: flex; + align-items: center; + gap: var(--space-sm); + margin-bottom: var(--space-sm); +} + +.test-option-header i { + color: var(--blue); +} + +.test-option p { + font-size: 0.85rem; + color: rgba(255, 255, 255, 0.7); +} + +/* File preview */ +.file-preview { + display: flex; + align-items: center; + background: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-md); + padding: var(--space-md); + margin-bottom: var(--space-lg); + width: 100%; + max-width: 500px; +} + +.file-icon { + font-size: 2rem; + color: var(--blue); + margin-right: var(--space-md); +} + +.file-info { + flex: 1; +} + +.file-name { + font-weight: 500; + color: var(--white); + margin-bottom: var(--space-xs); +} + +.file-size { + font-size: 0.8rem; + color: rgba(255, 255, 255, 0.5); +} + +.file-remove { + color: rgba(255, 255, 255, 0.5); + background: none; + border: none; + cursor: pointer; + padding: var(--space-xs); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + transition: all var(--transition-fast); +} + +.file-remove:hover { + color: var(--white); + background: rgba(255, 255, 255, 0.1); +} + +/* Analysis options */ +.analysis-options { + margin-bottom: var(--space-xl); +} + +.analysis-options > h3 { + margin-bottom: var(--space-lg); + font-size: 1.2rem; +} + +.options-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: var(--space-lg); + margin-bottom: var(--space-xl); +} + +.option-card { + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: var(--radius-lg); + padding: var(--space-lg); + transition: all var(--transition-normal); +} + +.option-card:hover { + background: rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.15); + transform: translateY(-2px); +} + +.option-header { + display: flex; + align-items: center; + gap: var(--space-sm); + margin-bottom: var(--space-md); +} + +.option-header i { + color: var(--blue); + font-size: 1.1rem; +} + +.option-header h4 { + margin: 0; + font-size: 1.1rem; + color: var(--white); +} + +.option-content { + display: flex; + flex-direction: column; + gap: var(--space-md); +} + +/* Custom checkbox */ +.option-checkbox { + position: relative; + display: flex; + align-items: center; + gap: var(--space-md); + cursor: pointer; + padding: var(--space-xs) 0; + padding-left: 36px; /* Add left padding to make room for the checkmark */ + user-select: none; + color: rgba(255, 255, 255, 0.8); + transition: all var(--transition-fast); +} + +.option-checkbox:hover { + color: var(--white); +} + +.option-checkbox input { + position: absolute; + opacity: 0; + cursor: pointer; +} + +.checkmark { + position: absolute; + left: 0; + top: 50%; /* Center vertically */ + transform: translateY(-50%); /* Center vertically */ + width: 20px; + height: 20px; + background: rgba(255, 255, 255, 0.1); + border: 1px solid rgba(255, 255, 255, 0.2); + border-radius: var(--radius-sm); + transition: all var(--transition-fast); +} + +.option-checkbox:hover .checkmark { + background: rgba(255, 255, 255, 0.15); +} + +.option-checkbox input:checked ~ .checkmark { + background: var(--blue); + border-color: var(--blue); +} + +.checkmark:after { + content: ""; + position: absolute; + display: none; +} + +.option-checkbox input:checked ~ .checkmark:after { + display: block; +} + +.option-checkbox .checkmark:after { + left: 7px; + top: 3px; + width: 5px; + height: 10px; + border: solid white; + border-width: 0 2px 2px 0; + transform: rotate(45deg); +} + +/* Analyze button */ +.analyze-btn { + width: 100%; + padding: var(--space-lg); + background: linear-gradient(135deg, var(--magenta), var(--blue)); + border: none; + border-radius: var(--radius-md); + color: var(--white); + font-size: 1.1rem; + font-weight: 600; + cursor: pointer; + transition: all var(--transition-fast); + display: flex; + align-items: center; + justify-content: center; + gap: var(--space-sm); +} + +.analyze-btn:hover { + background: linear-gradient(135deg, var(--blue), var(--magenta)); + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); +} + +.analyze-btn:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none; + box-shadow: none; +} + +/* Results section */ +.analyzer-results { + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: var(--radius-lg); + overflow: hidden; + margin-bottom: var(--space-xxl); +} + +.results-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--space-lg); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + background: rgba(0, 0, 0, 0.2); +} + +.results-header h2 { + margin: 0; + font-size: 1.3rem; +} + +.results-actions { + display: flex; + align-items: center; + gap: var(--space-lg); +} + +.results-file-info { + display: flex; + align-items: center; + gap: var(--space-sm); + color: rgba(255, 255, 255, 0.7); + font-size: 0.9rem; +} + +.results-content { + padding: var(--space-xl); +} + +/* Results grid layout */ +.results-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: var(--space-lg); + margin-bottom: var(--space-xl); +} + +.result-card { + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: var(--radius-md); + padding: var(--space-lg); + text-align: center; + transition: all var(--transition-normal); +} + +.result-card:hover { + background: rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.15); + transform: translateY(-2px); +} + +.result-value { + font-size: 2rem; + font-weight: 700; + color: var(--blue); + margin-bottom: var(--space-xs); +} + +.result-label { + font-size: 0.9rem; + color: rgba(255, 255, 255, 0.7); +} + +.result-card.wide { + grid-column: 1 / -1; +} + +/* Charts and visualizations */ +.chart-container { + background: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-md); + padding: var(--space-lg); + margin-bottom: var(--space-xl); +} + +.base-composition { + display: flex; + align-items: center; + margin-bottom: var(--space-lg); +} + +.base-bar { + flex: 1; + height: 32px; + display: flex; + border-radius: var(--radius-md); + overflow: hidden; +} + +.base-segment { + height: 100%; + display: flex; + align-items: center; + justify-content: center; + color: white; + font-weight: 600; + font-size: 0.9rem; + transition: all var(--transition-normal); +} + +.base-segment:hover { + filter: brightness(1.1); +} + +.base-a { background-color: var(--magenta); } +.base-t { background-color: var(--blue); } +.base-g { background-color: var(--orange); } +.base-c { background-color: #34c759; } + +.base-legend { + display: flex; + flex-wrap: wrap; + gap: var(--space-md); +} + +.legend-item { + display: flex; + align-items: center; + gap: var(--space-xs); + font-size: 0.9rem; + color: rgba(255, 255, 255, 0.8); +} + +.color-box { + width: 12px; + height: 12px; + border-radius: 2px; +} + +/* Results table */ +.results-table-container { + margin-bottom: var(--space-xl); +} + +.results-table-container h3 { + margin-bottom: var(--space-md); + font-size: 1.2rem; +} + +.results-table { + width: 100%; + border-collapse: collapse; + background: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-md); + overflow: hidden; +} + +.results-table th { + text-align: left; + padding: var(--space-md); + background: rgba(0, 0, 0, 0.3); + color: var(--blue); + font-weight: 600; + font-size: 0.9rem; +} + +.results-table td { + padding: var(--space-md); + border-top: 1px solid rgba(255, 255, 255, 0.05); + color: rgba(255, 255, 255, 0.8); + font-size: 0.9rem; +} + +.results-table tr:hover td { + background: rgba(255, 255, 255, 0.05); +} + +.sequence-cell { + font-family: var(--font-mono); + font-size: 0.85rem; +} + +/* Sequence Visualization */ +.sequence-visualization { + margin-bottom: var(--space-xl); + background: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-md); + padding: var(--space-lg); + overflow: hidden; +} + +.sequence-visualization h3 { + margin-bottom: var(--space-md); +} + +.sequence-view { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(24px, 1fr)); + gap: 2px; + margin-bottom: var(--space-md); + font-family: var(--font-mono); + font-size: 0.8rem; +} + +.base-block { + width: 100%; + aspect-ratio: 1; + display: flex; + align-items: center; + justify-content: center; + color: white; + font-weight: 600; + border-radius: 2px; + transition: all var(--transition-fast); +} + +.base-block:hover { + transform: scale(1.1); + z-index: 10; +} + +.sequence-zoom { + margin-top: var(--space-md); + display: flex; + justify-content: center; + gap: var(--space-md); +} + +.zoom-btn { + background: rgba(255, 255, 255, 0.1); + border: none; + color: var(--white); + width: 36px; + height: 36px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all var(--transition-fast); +} + +.zoom-btn:hover { + background: rgba(255, 255, 255, 0.2); +} + +.zoom-btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.sequence-position { + font-size: 0.9rem; + color: rgba(255, 255, 255, 0.7); + text-align: center; + margin-top: var(--space-sm); +} + +/* Circular Visualization */ +.circular-genome { + display: flex; + justify-content: center; + align-items: center; + margin: var(--space-lg) 0; + position: relative; +} + +.circular-genome svg { + max-width: 100%; + height: auto; +} + +.genome-legend { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: var(--space-md); + margin-top: var(--space-md); +} + +/* Codon Distribution */ +.codon-distribution { + margin-bottom: var(--space-xl); +} + +.codon-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); + gap: var(--space-md); + margin-top: var(--space-md); +} + +.codon-box { + background: rgba(255, 255, 255, 0.05); + border-radius: var(--radius-sm); + padding: var(--space-sm); + text-align: center; + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.codon-box-name { + font-family: var(--font-mono); + font-weight: 600; + color: var(--white); + margin-bottom: var(--space-xs); +} + +.codon-count { + font-size: 0.85rem; + color: var(--blue); +} + +.codon-amino { + font-size: 0.85rem; + color: rgba(255, 255, 255, 0.7); +} + +/* 3D Protein Structure */ +.protein-structure { + width: 100%; + height: 400px; + background: rgba(0, 0, 0, 0.3); + border-radius: var(--radius-md); + margin-bottom: var(--space-xl); + position: relative; + overflow: hidden; +} + +.structure-controls { + position: absolute; + bottom: var(--space-md); + right: var(--space-md); + display: flex; + gap: var(--space-xs); +} + +.structure-control-btn { + width: 36px; + height: 36px; + border-radius: 50%; + background: rgba(0, 0, 0, 0.5); + color: white; + border: none; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all var(--transition-fast); +} + +.structure-control-btn:hover { + background: rgba(0, 0, 0, 0.7); +} + +/* Genetic Health Risk Display */ +.health-risk-section { + margin-bottom: var(--space-xl); +} + +.risk-cards { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: var(--space-lg); + margin-top: var(--space-lg); +} + +.risk-card { + background: rgba(255, 255, 255, 0.05); + border-radius: var(--radius-md); + padding: var(--space-lg); + border: 1px solid rgba(255, 255, 255, 0.1); + transition: all var(--transition-normal); +} + +.risk-card:hover { + transform: translateY(-3px); + border-color: rgba(255, 255, 255, 0.2); +} + +.risk-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: var(--space-md); +} + +.risk-title { + font-size: 1.1rem; + font-weight: 600; + color: var(--white); +} + +.risk-badge { + padding: var(--space-xs) var(--space-sm); + border-radius: var(--radius-sm); + font-size: 0.8rem; + font-weight: 600; +} + +.risk-badge.low { + background: rgba(40, 167, 69, 0.2); + color: var(--success); +} + +.risk-badge.moderate { + background: rgba(255, 193, 7, 0.2); + color: var(--warning); +} + +.risk-badge.elevated { + background: rgba(255, 105, 0, 0.2); + color: var(--orange); +} + +.risk-badge.high { + background: rgba(220, 53, 69, 0.2); + color: var(--error); +} + +.risk-genes { + margin-top: var(--space-md); + font-size: 0.9rem; + color: rgba(255, 255, 255, 0.7); +} + +.risk-genes span { + display: inline-block; + font-family: var(--font-mono); + background: rgba(0, 0, 0, 0.3); + padding: 0 var(--space-xs); + border-radius: var(--radius-sm); + margin-right: var(--space-xs); +} + +.risk-description { + margin-top: var(--space-md); + font-size: 0.9rem; + color: rgba(255, 255, 255, 0.8); + line-height: 1.5; +} + +/* Ancestry Composition */ +.ancestry-map { + width: 100%; + height: 400px; + background: rgba(0, 0, 0, 0.3); + border-radius: var(--radius-md); + margin-bottom: var(--space-lg); + position: relative; + overflow: hidden; +} + +.ancestry-chart { + display: flex; + margin-top: var(--space-lg); + margin-bottom: var(--space-lg); +} + +.ancestry-donut { + width: 200px; + height: 200px; + position: relative; +} + +.ancestry-categories { + flex: 1; + margin-left: var(--space-xl); +} + +.ancestry-category { + display: flex; + align-items: center; + margin-bottom: var(--space-sm); +} + +.ancestry-color { + width: 16px; + height: 16px; + border-radius: 2px; + margin-right: var(--space-sm); +} + +.ancestry-label { + flex: 1; + font-size: 0.9rem; + color: rgba(255, 255, 255, 0.9); +} + +.ancestry-percent { + font-size: 0.9rem; + font-weight: 600; + color: var(--white); +} + +/* Trait Analysis */ +.traits-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); + gap: var(--space-lg); + margin-top: var(--space-lg); +} + +.trait-card { + background: rgba(255, 255, 255, 0.05); + border-radius: var(--radius-md); + padding: var(--space-lg); + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.trait-header { + display: flex; + align-items: center; + gap: var(--space-md); + margin-bottom: var(--space-md); +} + +.trait-icon { + font-size: 1.5rem; + color: var(--blue); +} + +.trait-name { + font-size: 1.1rem; + font-weight: 500; + color: var(--white); +} + +.trait-value { + margin-top: var(--space-sm); + font-size: 1rem; + color: var(--white); +} + +.trait-probability { + display: flex; + align-items: center; + margin-top: var(--space-md); +} + +.probability-bar { + flex: 1; + height: 8px; + background: rgba(0, 0, 0, 0.3); + border-radius: var(--radius-sm); + overflow: hidden; + margin-right: var(--space-sm); +} + +.probability-fill { + height: 100%; + background: var(--blue); +} + +.probability-value { + font-size: 0.9rem; + color: rgba(255, 255, 255, 0.8); +} + +/* Batch results */ +.batch-results-list { + display: flex; + flex-direction: column; + gap: var(--space-md); + margin-bottom: var(--space-xl); +} + +.batch-result-item { + display: flex; + align-items: center; + background: rgba(255, 255, 255, 0.05); + border-radius: var(--radius-md); + padding: var(--space-md); + border: 1px solid rgba(255, 255, 255, 0.1); + transition: all var(--transition-fast); +} + +.batch-result-item:hover { + background: rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.2); +} + +.batch-result-icon { + font-size: 1.3rem; + color: var(--blue); + margin-right: var(--space-md); +} + +.batch-result-details { + flex: 1; +} + +.batch-result-name { + font-weight: 500; + color: var(--white); + margin-bottom: var(--space-xs); +} + +.batch-result-stats { + display: flex; + gap: var(--space-lg); + font-size: 0.85rem; + color: rgba(255, 255, 255, 0.7); +} + +.batch-actions { + display: flex; + gap: var(--space-xs); +} + +.batch-action-btn { + width: 36px; + height: 36px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.08); + color: rgba(255, 255, 255, 0.7); + border: none; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all var(--transition-fast); +} + +.batch-action-btn:hover { + background: rgba(255, 255, 255, 0.15); + color: var(--white); +} + +/* Compare view */ +.compare-container { + background: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-md); + padding: var(--space-lg); + margin-bottom: var(--space-xl); +} + +.compare-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: var(--space-lg); + padding-bottom: var(--space-md); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.compare-files { + display: flex; + gap: var(--space-md); +} + +.compare-file { + font-size: 0.9rem; + color: rgba(255, 255, 255, 0.8); + padding: var(--space-xs) var(--space-sm); + background: rgba(255, 255, 255, 0.08); + border-radius: var(--radius-sm); +} + +.compare-file.active { + background: rgba(0, 164, 239, 0.15); + color: var(--blue); +} + +.compare-table { + width: 100%; +} + +.compare-table th { + text-align: left; + padding: var(--space-md); + background: rgba(0, 0, 0, 0.3); + color: var(--blue); + font-weight: 600; + font-size: 0.9rem; +} + +.compare-table th:first-child { + background: transparent; + color: rgba(255, 255, 255, 0.8); +} + +.compare-table td { + padding: var(--space-md); + border-top: 1px solid rgba(255, 255, 255, 0.05); + color: rgba(255, 255, 255, 0.8); + font-size: 0.9rem; +} + +.compare-table tr:nth-child(odd) td { + background: rgba(255, 255, 255, 0.02); +} + +/* Nucleotide Distribution Hexplot */ +.nucleotide-hexplot { + display: flex; + justify-content: center; + margin: var(--space-lg) 0; +} + +/* Histogram */ +.histogram-container { + margin: var(--space-lg) 0; +} + +.histogram-bars { + display: flex; + align-items: flex-end; + height: 200px; + gap: 2px; +} + +.histogram-bar { + flex: 1; + background: var(--blue); + min-width: 4px; + border-radius: 2px 2px 0 0; + transition: all var(--transition-fast); +} + +.histogram-bar:hover { + background: var(--magenta); +} + +.histogram-labels { + display: flex; + justify-content: space-between; + margin-top: var(--space-xs); + font-size: 0.8rem; + color: rgba(255, 255, 255, 0.7); +} + +/* Download options */ +.download-options { + background: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-md); + padding: var(--space-lg); +} + +.download-options h3 { + margin-bottom: var(--space-md); + font-size: 1.1rem; +} + +.download-formats { + display: flex; + gap: var(--space-md); + flex-wrap: wrap; +} + +.download-format { + display: flex; + align-items: center; + gap: var(--space-xs); + padding: var(--space-sm) var(--space-md); + background: rgba(255, 255, 255, 0.08); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: var(--radius-md); + color: var(--white); + font-size: 0.9rem; + cursor: pointer; + transition: all var(--transition-fast); +} + +.download-format:hover { + background: rgba(255, 255, 255, 0.12); + transform: translateY(-2px); +} + +/* Loading state */ +.loading-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: var(--space-xxl); +} + +.loading-spinner { + width: 50px; + height: 50px; + border: 3px solid rgba(255, 255, 255, 0.1); + border-radius: 50%; + border-top: 3px solid var(--blue); + animation: spin 1s linear infinite; + margin-bottom: var(--space-md); +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* Coming soon */ +.coming-soon { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: var(--space-xxl); + text-align: center; +} + +.coming-soon i { + font-size: 3rem; + color: var(--blue); + margin-bottom: var(--space-lg); + opacity: 0.8; +} + +.coming-soon h3 { + margin-bottom: var(--space-md); + color: var(--white); +} + +.coming-soon p { + max-width: 500px; + color: rgba(255, 255, 255, 0.7); +} + +/* Modal */ +.modal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.8); + display: flex; + align-items: center; + justify-content: center; + z-index: var(--z-modal); + opacity: 0; + visibility: hidden; + transition: all var(--transition-normal); +} + +.modal.active { + opacity: 1; + visibility: visible; +} + +.modal-content { + background: var(--dark-bg); + border-radius: var(--radius-lg); + width: 90%; + max-width: 500px; + box-shadow: var(--shadow-lg); + overflow: hidden; + transform: translateY(20px); + transition: all var(--transition-normal); +} + +.modal.active .modal-content { + transform: translateY(0); +} + +.modal-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--space-lg); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.modal-header h3 { + margin: 0; + font-size: 1.2rem; +} + +.close-modal { + background: none; + border: none; + color: rgba(255, 255, 255, 0.7); + font-size: 1.5rem; + cursor: pointer; + transition: all var(--transition-fast); +} + +.close-modal:hover { + color: var(--white); +} + +.modal-body { + padding: var(--space-lg); +} + +/* Export options */ +.export-options { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: var(--space-md); + margin-top: var(--space-lg); +} + +.export-option { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: var(--space-lg); + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: var(--radius-md); + cursor: pointer; + transition: all var(--transition-fast); +} + +.export-option:hover { + background: rgba(255, 255, 255, 0.08); + transform: translateY(-3px); +} + +.export-option i { + font-size: 2rem; + margin-bottom: var(--space-sm); + color: var(--blue); +} + +/* Notification */ +.notification-container { + position: fixed; + bottom: var(--space-lg); + right: var(--space-lg); + z-index: var(--z-tooltip); + display: flex; + flex-direction: column; + gap: var(--space-sm); +} + +.notification { + display: flex; + align-items: center; + padding: var(--space-md) var(--space-lg); + background: rgba(0, 0, 0, 0.8); + border-left: 3px solid var(--blue); + border-radius: var(--radius-md); + box-shadow: var(--shadow-md); + min-width: 280px; + max-width: 400px; + transform: translateX(100%); + opacity: 0; + animation: slide-in 0.3s forwards; +} + +.notification.success { + border-left-color: var(--success); +} + +.notification.success i { + color: var(--success); +} + +.notification.error { + border-left-color: var(--error); +} + +.notification.error i { + color: var(--error); +} + +.notification.warning { + border-left-color: var(--warning); +} + +.notification.warning i { + color: var(--warning); +} + +.notification-icon { + font-size: 1.2rem; + margin-right: var(--space-md); +} + +.notification-message { + flex: 1; + font-size: 0.9rem; +} + +@keyframes slide-in { + to { + transform: translateX(0); + opacity: 1; + } +} + +/* Responsive styles */ +@media screen and (max-width: 1024px) { + .analyzer-dashboard { + grid-template-columns: 1fr; + } + + .dashboard-sidebar { + position: static; + margin-bottom: var(--space-xl); + } + + .sidebar-section { + margin-bottom: var(--space-md); + } + + .export-options { + grid-template-columns: 1fr; + } + + .genetic-testing-form { + grid-template-columns: 1fr; + } + + .ancestry-chart { + flex-direction: column; + align-items: center; + } + + .ancestry-categories { + margin-left: 0; + margin-top: var(--space-lg); + width: 100%; + } +} + +@media screen and (max-width: 768px) { + .options-grid { + grid-template-columns: 1fr; + } + + .analyzer-tabs { + flex-direction: column; + } + + .testing-options { + grid-template-columns: 1fr; + } + + .risk-cards { + grid-template-columns: 1fr; + } + + .traits-grid { + grid-template-columns: 1fr; + } +} + +@media screen and (max-width: 480px) { + .results-header { + flex-direction: column; + align-items: flex-start; + gap: var(--space-md); + } + + .results-actions { + width: 100%; + flex-direction: column; + align-items: flex-start; + gap: var(--space-sm); + } + + .results-grid { + grid-template-columns: 1fr; + } + + .notification { + min-width: auto; + max-width: 90%; + } + + .batch-result-stats { + flex-direction: column; + gap: var(--space-xs); + } +} +-------------------------------------------------- +File: ./web/analyzer/analyzer.js +-------------------------------------------------- +/** + * DNAnalyzer - Analyzer Page JavaScript + * Handles all DNA analysis functionality, file handling, and result visualization + */ + +document.addEventListener('DOMContentLoaded', function() { + // Initialize UI components + initializeUI(); + + // Check API status + checkAPIStatus(); +}); + +/** + * Initialize all UI components and event listeners + */ +function initializeUI() { + // Initialize file upload functionality + initFileUpload(); + + // Initialize tabs + initTabs(); + + // Initialize modals + initModals(); + + // Initialize analyze button + document.getElementById('analyzeBtn').addEventListener('click', handleAnalysis); + + // Initialize quick action buttons + document.getElementById('importSampleBtn').addEventListener('click', importSample); + document.getElementById('clearOptionsBtn').addEventListener('click', clearOptions); + document.getElementById('helpBtn').addEventListener('click', showHelpModal); +} + +/** + * Initialize file upload area with drag and drop functionality + */ +function initFileUpload() { + const dropZone = document.getElementById('fileDropZone'); + const fileInput = document.getElementById('fileInput'); + + // Handle click on drop zone + dropZone.addEventListener('click', function() { + fileInput.click(); + }); + + // Handle file selection via input + fileInput.addEventListener('change', function(e) { + if (e.target.files.length > 0) { + handleFileSelection(e.target.files[0]); + } + }); + + // Handle drag and drop events + dropZone.addEventListener('dragover', function(e) { + e.preventDefault(); + dropZone.classList.add('drag-over'); + }); + + dropZone.addEventListener('dragleave', function() { + dropZone.classList.remove('drag-over'); + }); + + dropZone.addEventListener('drop', function(e) { + e.preventDefault(); + dropZone.classList.remove('drag-over'); + + if (e.dataTransfer.files.length > 0) { + handleFileSelection(e.dataTransfer.files[0]); + } + }); +} + +/** + * Handle the selected file and update UI + * @param {File} file - The selected file + */ +function handleFileSelection(file) { + // Check if file type is supported + const validExtensions = ['.fa', '.fasta', '.fastq', '.txt']; + const fileName = file.name.toLowerCase(); + const isValid = validExtensions.some(ext => fileName.endsWith(ext)); + + if (!isValid) { + showNotification('Unsupported file format. Please upload a FASTA, FASTQ, or TXT file.', 'error'); + return; + } + + // Store file in global state for later use + window.selectedFile = file; + + // Update UI with file info + const dropZone = document.getElementById('fileDropZone'); + dropZone.innerHTML = ` + <div class="file-preview"> + <i class="fas fa-file-alt file-icon"></i> + <div class="file-info"> + <div class="file-name">${file.name}</div> + <div class="file-size">${formatFileSize(file.size)}</div> + </div> + <button class="file-remove" id="removeFileBtn"> + <i class="fas fa-times"></i> + </button> + </div> + `; + + // Add event listener to remove button + document.getElementById('removeFileBtn').addEventListener('click', function(e) { + e.stopPropagation(); + resetFileUpload(); + }); + + // Enable analyze button + document.getElementById('analyzeBtn').disabled = false; + + showNotification(`File "${file.name}" ready for analysis.`, 'success'); +} + +/** + * Reset the file upload area to its initial state + */ +function resetFileUpload() { + const dropZone = document.getElementById('fileDropZone'); + const fileInput = document.getElementById('fileInput'); + + // Clear the file input + fileInput.value = ''; + + // Reset global state + window.selectedFile = null; + + // Reset UI + dropZone.innerHTML = ` + <i class="fas fa-cloud-upload-alt"></i> + <h3>Upload DNA Sequence</h3> + <p>Drag and drop your sequence file here or click to browse</p> + <span class="upload-formats">Supported formats: .fa, .fasta, .fastq, .txt</span> + `; + + // Disable analyze button + document.getElementById('analyzeBtn').disabled = true; +} + +/** + * Initialize tab functionality + */ +function initTabs() { + const tabButtons = document.querySelectorAll('.tab-btn'); + const tabContents = document.querySelectorAll('.tab-content'); + + tabButtons.forEach(button => { + button.addEventListener('click', function() { + const tabId = this.getAttribute('data-tab'); + + // Remove active class from all tabs + tabButtons.forEach(btn => btn.classList.remove('active')); + tabContents.forEach(content => content.classList.remove('active')); + + // Add active class to current tab + this.classList.add('active'); + document.getElementById(tabId).classList.add('active'); + }); + }); +} + +/** + * Initialize modal functionality + */ +function initModals() { + // Export modal + const exportModal = document.getElementById('exportModal'); + const closeExportModal = document.getElementById('closeExportModal'); + + if (exportModal && closeExportModal) { + document.getElementById('exportBtn').addEventListener('click', function() { + exportModal.classList.add('active'); + }); + + closeExportModal.addEventListener('click', function() { + exportModal.classList.remove('active'); + }); + + // Close modal when clicking outside + exportModal.addEventListener('click', function(e) { + if (e.target === exportModal) { + exportModal.classList.remove('active'); + } + }); + + // Handle export format selection + document.querySelectorAll('.export-option').forEach(option => { + option.addEventListener('click', function() { + const format = this.getAttribute('data-format'); + downloadResults(format); + exportModal.classList.remove('active'); + }); + }); + } + + // Help modal + const helpModal = document.getElementById('helpModal'); + const closeHelpModal = document.getElementById('closeHelpModal'); + + if (helpModal && closeHelpModal) { + closeHelpModal.addEventListener('click', function() { + helpModal.classList.remove('active'); + }); + + // Close modal when clicking outside + helpModal.addEventListener('click', function(e) { + if (e.target === helpModal) { + helpModal.classList.remove('active'); + } + }); + } +} + +/** + * Show the help modal + */ +function showHelpModal() { + const helpModal = document.getElementById('helpModal'); + if (helpModal) { + helpModal.classList.add('active'); + } +} + +/** + * Import a sample DNA file for demonstration + */ +function importSample() { + // Create a mock file from a predefined DNA sequence + const sampleDNA = '>Sample DNA Sequence\nATGGCCTAGCTAGCTGATCGATCGATCGATCGATCGATCGATCGATCGATCGACTGATCTAGCATCGATCGATCGAATCGCTAGCTAGCATCGATCGATCGATCGATCGACTAGCTAGCTATCAGCTAGCTAGCTAGCTAGCTCGATCGATCGATCGATCGATCGACTAGCTAGCAGACTAGCTAGCATCATCGACTAGCTGATGATGGATTAGCATCGATCGATAGCTACGAT'; + + const blob = new Blob([sampleDNA], { type: 'text/plain' }); + const file = new File([blob], 'sample_dna.fa', { type: 'text/plain' }); + + // Process the sample file + handleFileSelection(file); +} + +/** + * Reset all analysis options to default + */ +function clearOptions() { + document.querySelectorAll('input[name="analysis-option"]').forEach(checkbox => { + // Set default checkboxes (first 5) to checked, others to unchecked + const isDefault = ['sequence-length', 'gc-content', 'base-composition', 'start-codons', 'stop-codons'].includes(checkbox.value); + checkbox.checked = isDefault; + }); + + showNotification('Analysis options reset to default.', 'success'); +} + +/** + * Check API connectivity status + */ +function checkAPIStatus() { + const apiStatus = document.getElementById('apiStatus'); + + if (!apiStatus) return; + + // Check if API client is available + if (typeof DNAnalyzerAPI === 'undefined') { + apiStatus.innerHTML = ` + <div class="status-indicator"> + <div class="status-dot offline"></div> + <span>API not available</span> + </div> + `; + return; + } + + // Try to connect to the API + DNAnalyzerAPI.checkStatus() + .then(status => { + console.log('API Status:', status); + apiStatus.innerHTML = ` + <div class="status-indicator"> + <div class="status-dot online"></div> + <span>API Connected v${status.version || '1.0'}</span> + </div> + `; + }) + .catch(error => { + console.error('API Error:', error); + apiStatus.innerHTML = ` + <div class="status-indicator"> + <div class="status-dot offline"></div> + <span>API Offline - Using Fallback Mode</span> + </div> + `; + }); +} + +/** + * Handle the DNA analysis process + */ +function handleAnalysis() { + if (!window.selectedFile) { + showNotification('Please upload a DNA sequence file first.', 'error'); + return; + } + + // Get selected analysis options + const options = getSelectedOptions(); + + // Show loading state + const analyzeBtn = document.getElementById('analyzeBtn'); + analyzeBtn.disabled = true; + analyzeBtn.innerHTML = '<i class="fas fa-circle-notch fa-spin"></i> Analyzing...'; + + // Show results section with loading state + const resultsSection = document.getElementById('resultsSection'); + resultsSection.style.display = 'block'; + + const resultsContent = document.getElementById('resultsContent'); + resultsContent.innerHTML = ` + <div class="loading-container"> + <div class="loading-spinner"></div> + <p>Analyzing DNA sequence...</p> + </div> + `; + + // Update file info in results header + document.getElementById('resultsFileInfo').innerHTML = ` + <i class="fas fa-file-alt"></i> + <span>${window.selectedFile.name}</span> + `; + + // Scroll to results + resultsSection.scrollIntoView({ behavior: 'smooth', block: 'start' }); + + // Try using API if available, otherwise use fallback + if (typeof DNAnalyzerAPI !== 'undefined') { + try { + performAPIAnalysis(window.selectedFile, options); + } catch (error) { + console.error('API Error:', error); + performFallbackAnalysis(window.selectedFile, options); + } + } else { + performFallbackAnalysis(window.selectedFile, options); + } +} + +/** + * Perform analysis using the API + * @param {File} file - The file to analyze + * @param {Object} options - Analysis options + */ +function performAPIAnalysis(file, options) { + // First try to analyze via API + DNAnalyzerAPI.analyzeDNA(file, options) + .then(results => { + displayResults(results); + + // Add to history + addToHistory(file.name); + + // Reset button + const analyzeBtn = document.getElementById('analyzeBtn'); + analyzeBtn.disabled = false; + analyzeBtn.innerHTML = '<i class="fas fa-play"></i> Start Analysis'; + + showNotification('Analysis completed successfully!', 'success'); + }) + .catch(error => { + console.error('API Analysis Error:', error); + // Fallback to local analysis + performFallbackAnalysis(file, options); + }); +} + +/** + * Perform analysis using local fallback method + * @param {File} file - The file to analyze + * @param {Object} options - Analysis options + */ +function performFallbackAnalysis(file, options) { + // Read the file content + const reader = new FileReader(); + + reader.onload = function(e) { + const sequence = parseFastaSequence(e.target.result); + + // Perform basic sequence analysis + const results = analyzeSequence(sequence, options); + + // Display results + displayResults(results); + + // Add to history + addToHistory(file.name); + + // Reset button + const analyzeBtn = document.getElementById('analyzeBtn'); + analyzeBtn.disabled = false; + analyzeBtn.innerHTML = '<i class="fas fa-play"></i> Start Analysis'; + + showNotification('Analysis completed using fallback mode.', 'success'); + }; + + reader.onerror = function() { + showNotification('Failed to read file. Please try again.', 'error'); + + // Reset button + const analyzeBtn = document.getElementById('analyzeBtn'); + analyzeBtn.disabled = false; + analyzeBtn.innerHTML = '<i class="fas fa-play"></i> Start Analysis'; + }; + + reader.readAsText(file); +} + +/** + * Parse FASTA format sequence + * @param {string} fastaData - Raw FASTA file content + * @returns {string} - Cleaned DNA sequence + */ +function parseFastaSequence(fastaData) { + // Split by lines + const lines = fastaData.split(/\r?\n/); + + // Skip header lines (starting with '>') and join the rest + let sequence = ''; + let foundHeader = false; + + for (let line of lines) { + line = line.trim(); + + if (line.startsWith('>')) { + foundHeader = true; + continue; + } + + if (line.length > 0) { + sequence += line; + } + } + + // If no header was found, assume the entire content is the sequence + if (!foundHeader && sequence === '') { + sequence = fastaData.replace(/\s+/g, ''); + } + + return sequence.toUpperCase(); +} + +/** + * Analyze DNA sequence + * @param {string} sequence - DNA sequence + * @param {Object} options - Analysis options + * @returns {Object} - Analysis results + */ +function analyzeSequence(sequence, options) { + const results = { + sequence: { + length: sequence.length, + sample: sequence.substring(0, 100) + (sequence.length > 100 ? '...' : '') + }, + basePairs: analyzeBasePairs(sequence), + options: options + }; + + // Codon analysis if selected + if (options.includes('start-codons') || options.includes('stop-codons')) { + results.codons = analyzeCodonFrequency(sequence); + } + + // Reading frames if selected + if (options.includes('reading-frames')) { + results.readingFrames = analyzeReadingFrames(sequence); + } + + // Protein prediction if selected + if (options.includes('protein-prediction')) { + results.proteins = findPotentialProteins(sequence); + } + + return results; +} + +/** + * Analyze base pair composition + * @param {string} sequence - DNA sequence + * @returns {Object} - Base pair analysis results + */ +function analyzeBasePairs(sequence) { + const counts = { + A: 0, + T: 0, + G: 0, + C: 0, + other: 0 + }; + + // Count occurrences of each base + for (let i = 0; i < sequence.length; i++) { + const base = sequence[i]; + if (counts.hasOwnProperty(base)) { + counts[base]++; + } else { + counts.other++; + } + } + + // Calculate percentages + const total = sequence.length; + const percentages = {}; + + for (const base in counts) { + percentages[base] = parseFloat(((counts[base] / total) * 100).toFixed(1)); + } + + // Calculate GC content + const gcContent = parseFloat(((counts.G + counts.C) / total * 100).toFixed(1)); + + return { + counts, + percentages, + gcContent + }; +} + +/** + * Analyze codon frequency + * @param {string} sequence - DNA sequence + * @returns {Object} - Codon analysis results + */ +function analyzeCodonFrequency(sequence) { + const startCodon = 'ATG'; + const stopCodons = ['TAA', 'TAG', 'TGA']; + + let startCount = 0; + let stopCount = 0; + + // Analyze each possible codon position + for (let i = 0; i < sequence.length - 2; i++) { + const codon = sequence.substring(i, i + 3); + + if (codon === startCodon) { + startCount++; + } + + if (stopCodons.includes(codon)) { + stopCount++; + } + } + + return { + startCodons: startCount, + stopCodons: stopCount + }; +} + +/** + * Analyze reading frames + * @param {string} sequence - DNA sequence + * @returns {Object} - Reading frames analysis + */ +function analyzeReadingFrames(sequence) { + const frames = []; + const startCodon = 'ATG'; + const stopCodons = ['TAA', 'TAG', 'TGA']; + + // Analyze each of the three forward reading frames + for (let offset = 0; offset < 3; offset++) { + const frame = { + frame: offset + 1, + direction: 'forward', + genes: [] + }; + + let inGene = false; + let geneStart = 0; + + for (let i = offset; i < sequence.length - 2; i += 3) { + const codon = sequence.substring(i, i + 3); + + if (codon === startCodon && !inGene) { + inGene = true; + geneStart = i; + } else if (stopCodons.includes(codon) && inGene) { + inGene = false; + const gene = { + start: geneStart, + end: i + 2, + length: i + 3 - geneStart + }; + frame.genes.push(gene); + } + } + + frames.push(frame); + } + + // Get the reverse complement sequence + const reverseComplement = getReverseComplement(sequence); + + // Analyze each of the three reverse reading frames + for (let offset = 0; offset < 3; offset++) { + const frame = { + frame: offset + 4, + direction: 'reverse', + genes: [] + }; + + let inGene = false; + let geneStart = 0; + + for (let i = offset; i < reverseComplement.length - 2; i += 3) { + const codon = reverseComplement.substring(i, i + 3); + + if (codon === startCodon && !inGene) { + inGene = true; + geneStart = i; + } else if (stopCodons.includes(codon) && inGene) { + inGene = false; + const gene = { + start: i + 2, + end: geneStart, + length: i + 3 - geneStart + }; + frame.genes.push(gene); + } + } + + frames.push(frame); + } + + return { + frames: frames, + totalGenes: frames.reduce((total, frame) => total + frame.genes.length, 0) + }; +} + +/** + * Get reverse complement of DNA sequence + * @param {string} sequence - DNA sequence + * @returns {string} - Reverse complement + */ +function getReverseComplement(sequence) { + const complementMap = { + 'A': 'T', + 'T': 'A', + 'G': 'C', + 'C': 'G', + 'N': 'N' + }; + + let reverseComplement = ''; + + for (let i = sequence.length - 1; i >= 0; i--) { + const base = sequence[i]; + reverseComplement += complementMap[base] || base; + } + + return reverseComplement; +} + +/** + * Find potential proteins in DNA sequence + * @param {string} sequence - DNA sequence + * @returns {Array} - List of potential proteins + */ +function findPotentialProteins(sequence) { + const startCodon = 'ATG'; + const stopCodons = ['TAA', 'TAG', 'TGA']; + const proteins = []; + + // Genetic code for translation + const geneticCode = { + 'TTT': 'F', 'TTC': 'F', 'TTA': 'L', 'TTG': 'L', + 'CTT': 'L', 'CTC': 'L', 'CTA': 'L', 'CTG': 'L', + 'ATT': 'I', 'ATC': 'I', 'ATA': 'I', 'ATG': 'M', + 'GTT': 'V', 'GTC': 'V', 'GTA': 'V', 'GTG': 'V', + 'TCT': 'S', 'TCC': 'S', 'TCA': 'S', 'TCG': 'S', + 'CCT': 'P', 'CCC': 'P', 'CCA': 'P', 'CCG': 'P', + 'ACT': 'T', 'ACC': 'T', 'ACA': 'T', 'ACG': 'T', + 'GCT': 'A', 'GCC': 'A', 'GCA': 'A', 'GCG': 'A', + 'TAT': 'Y', 'TAC': 'Y', 'TAA': '*', 'TAG': '*', + 'CAT': 'H', 'CAC': 'H', 'CAA': 'Q', 'CAG': 'Q', + 'AAT': 'N', 'AAC': 'N', 'AAA': 'K', 'AAG': 'K', + 'GAT': 'D', 'GAC': 'D', 'GAA': 'E', 'GAG': 'E', + 'TGT': 'C', 'TGC': 'C', 'TGA': '*', 'TGG': 'W', + 'CGT': 'R', 'CGC': 'R', 'CGA': 'R', 'CGG': 'R', + 'AGT': 'S', 'AGC': 'S', 'AGA': 'R', 'AGG': 'R', + 'GGT': 'G', 'GGC': 'G', 'GGA': 'G', 'GGG': 'G' + }; + + // Search for proteins in all three reading frames + for (let offset = 0; offset < 3; offset++) { + let i = offset; + + while (i < sequence.length - 2) { + const codon = sequence.substring(i, i + 3); + + // If we find a start codon, begin translating + if (codon === startCodon) { + let proteinStart = i; + let protein = 'M'; // Start with methionine + let j = i + 3; + + // Continue until stop codon or end of sequence + while (j < sequence.length - 2) { + const nextCodon = sequence.substring(j, j + 3); + + // Check if it's a stop codon + if (stopCodons.includes(nextCodon)) { + // We found a complete protein + if (protein.length >= 10) { // Only include proteins of significant length + proteins.push({ + start: proteinStart, + end: j + 2, + length: protein.length, + sequence: protein + }); + } + + // Move past this protein + i = j + 3; + break; + } + + // Add amino acid to protein + const aa = geneticCode[nextCodon] || 'X'; // X for unknown + protein += aa; + + j += 3; + } + + // If we reached the end without finding a stop codon + if (j >= sequence.length - 2) { + i = j; + } + } else { + i += 3; + } + } + } + + // Sort by length (longest first) + proteins.sort((a, b) => b.length - a.length); + + // Limit to top 10 + return proteins.slice(0, 10); +} + +/** + * Display analysis results + * @param {Object} results - Analysis results + */ +function displayResults(results) { + const resultsContent = document.getElementById('resultsContent'); + const options = results.options; + + // Basic results grid + let html = '<div class="results-grid">'; + + // Sequence length + if (options.includes('sequence-length')) { + html += ` + <div class="result-card"> + <div class="result-value">${results.sequence.length.toLocaleString()}</div> + <div class="result-label">Sequence Length</div> + </div> + `; + } + + // GC content + if (options.includes('gc-content')) { + html += ` + <div class="result-card"> + <div class="result-value">${results.basePairs.gcContent}%</div> + <div class="result-label">GC Content</div> + </div> + `; + } + + // Start and stop codons + if (options.includes('start-codons') && results.codons) { + html += ` + <div class="result-card"> + <div class="result-value">${results.codons.startCodons}</div> + <div class="result-label">Start Codons</div> + </div> + `; + } + + if (options.includes('stop-codons') && results.codons) { + html += ` + <div class="result-card"> + <div class="result-value">${results.codons.stopCodons}</div> + <div class="result-label">Stop Codons</div> + </div> + `; + } + + // Reading frames + if (options.includes('reading-frames') && results.readingFrames) { + html += ` + <div class="result-card"> + <div class="result-value">${results.readingFrames.totalGenes}</div> + <div class="result-label">Potential Genes</div> + </div> + `; + } + + // Protein prediction + if (options.includes('protein-prediction') && results.proteins) { + html += ` + <div class="result-card"> + <div class="result-value">${results.proteins.length}</div> + <div class="result-label">Proteins Found</div> + </div> + `; + + // Add longest protein info if available + if (results.proteins.length > 0) { + html += ` + <div class="result-card"> + <div class="result-value">${results.proteins[0].length}</div> + <div class="result-label">Longest Protein (aa)</div> + </div> + `; + } + } + + html += '</div>'; // End of results grid + + // Base composition chart + if (options.includes('base-composition')) { + const basePercentages = results.basePairs.percentages; + + html += ` + <div class="chart-container"> + <h3>Base Composition</h3> + <div class="base-composition"> + <div class="base-bar"> + <div class="base-segment base-a" style="width: ${basePercentages.A}%">A</div> + <div class="base-segment base-t" style="width: ${basePercentages.T}%">T</div> + <div class="base-segment base-g" style="width: ${basePercentages.G}%">G</div> + <div class="base-segment base-c" style="width: ${basePercentages.C}%">C</div> + ${basePercentages.other > 0 ? `<div class="base-segment" style="width: ${basePercentages.other}%">N</div>` : ''} + </div> + </div> + <div class="base-legend"> + <div class="legend-item"> + <div class="color-box base-a"></div> + <span>Adenine (A): ${basePercentages.A}%</span> + </div> + <div class="legend-item"> + <div class="color-box base-t"></div> + <span>Thymine (T): ${basePercentages.T}%</span> + </div> + <div class="legend-item"> + <div class="color-box base-g"></div> + <span>Guanine (G): ${basePercentages.G}%</span> + </div> + <div class="legend-item"> + <div class="color-box base-c"></div> + <span>Cytosine (C): ${basePercentages.C}%</span> + </div> + ${basePercentages.other > 0 ? ` + <div class="legend-item"> + <div class="color-box" style="background: #888;"></div> + <span>Other (N): ${basePercentages.other}%</span> + </div> + ` : ''} + </div> + </div> + `; + } + + // Reading frames table + if (options.includes('reading-frames') && results.readingFrames && results.readingFrames.frames) { + html += ` + <div class="results-table-container"> + <h3>Reading Frames</h3> + <table class="results-table"> + <thead> + <tr> + <th>Frame</th> + <th>Direction</th> + <th>Genes Found</th> + </tr> + </thead> + <tbody> + `; + + results.readingFrames.frames.forEach(frame => { + html += ` + <tr> + <td>${frame.frame}</td> + <td>${frame.direction}</td> + <td>${frame.genes.length}</td> + </tr> + `; + }); + + html += ` + </tbody> + </table> + </div> + `; + } + + // Proteins table + if (options.includes('protein-prediction') && results.proteins && results.proteins.length > 0) { + html += ` + <div class="results-table-container"> + <h3>Predicted Proteins</h3> + <table class="results-table"> + <thead> + <tr> + <th>#</th> + <th>Length</th> + <th>Sequence (First 30 aa)</th> + </tr> + </thead> + <tbody> + `; + + results.proteins.forEach((protein, index) => { + const proteinSeq = protein.sequence || protein; + const displaySeq = proteinSeq.substring(0, 30) + (proteinSeq.length > 30 ? '...' : ''); + + html += ` + <tr> + <td>${index + 1}</td> + <td>${protein.length || proteinSeq.length}</td> + <td class="sequence-cell">${displaySeq}</td> + </tr> + `; + }); + + html += ` + </tbody> + </table> + </div> + `; + } + + // Download options + html += ` + <div class="download-options"> + <h3>Download Results</h3> + <div class="download-formats"> + <button class="download-format" data-format="json"> + <i class="fas fa-file-code"></i> + JSON + </button> + <button class="download-format" data-format="csv"> + <i class="fas fa-file-csv"></i> + CSV + </button> + <button class="download-format" data-format="txt"> + <i class="fas fa-file-alt"></i> + Text + </button> + </div> + </div> + `; + + // Update the results content + resultsContent.innerHTML = html; + + // Add event listeners to download buttons + document.querySelectorAll('.download-format').forEach(btn => { + btn.addEventListener('click', function() { + const format = this.getAttribute('data-format'); + downloadResults(format, results); + }); + }); + + // Store results for later use + window.analysisResults = results; +} + +/** + * Download analysis results + * @param {string} format - File format (json, csv, txt) + * @param {Object} results - Analysis results + */ +function downloadResults(format, results = window.analysisResults) { + if (!results) { + showNotification('No analysis results to download.', 'error'); + return; + } + + let content = ''; + let fileName = `dna_analysis_${new Date().toISOString().slice(0, 10)}`; + let mimeType = 'text/plain'; + + if (format === 'json') { + content = JSON.stringify(results, null, 2); + fileName += '.json'; + mimeType = 'application/json'; + } else if (format === 'csv') { + // Basic info + content = 'Property,Value\n'; + content += `Sequence Length,${results.sequence.length}\n`; + content += `GC Content,${results.basePairs.gcContent}%\n\n`; + + // Base pairs + content += 'Base,Count,Percentage\n'; + for (const base in results.basePairs.counts) { + content += `${base},${results.basePairs.counts[base]},${results.basePairs.percentages[base]}%\n`; + } + content += '\n'; + + // Add codon info if available + if (results.codons) { + content += 'Codon Type,Count\n'; + content += `Start Codons,${results.codons.startCodons}\n`; + content += `Stop Codons,${results.codons.stopCodons}\n\n`; + } + + // Add reading frames if available + if (results.readingFrames && results.readingFrames.frames) { + content += 'Frame,Direction,Genes Found\n'; + results.readingFrames.frames.forEach(frame => { + content += `${frame.frame},${frame.direction},${frame.genes.length}\n`; + }); + content += '\n'; + } + + // Add proteins if available + if (results.proteins && results.proteins.length > 0) { + content += 'Protein,Length,Sequence\n'; + results.proteins.forEach((protein, index) => { + const proteinSeq = protein.sequence || protein; + content += `${index + 1},${protein.length || proteinSeq.length},"${proteinSeq}"\n`; + }); + } + + fileName += '.csv'; + mimeType = 'text/csv'; + } else { // txt format + content = 'DNA Sequence Analysis Results\n'; + content += '============================\n\n'; + + // Basic info + content += `Sequence Length: ${results.sequence.length}\n`; + content += `GC Content: ${results.basePairs.gcContent}%\n\n`; + + // Base composition + content += 'Base Composition:\n'; + for (const base in results.basePairs.counts) { + content += `${base}: ${results.basePairs.counts[base]} (${results.basePairs.percentages[base]}%)\n`; + } + content += '\n'; + + // Add codon info if available + if (results.codons) { + content += 'Codon Analysis:\n'; + content += `Start Codons (ATG): ${results.codons.startCodons}\n`; + content += `Stop Codons (TAA, TAG, TGA): ${results.codons.stopCodons}\n\n`; + } + + // Add reading frames if available + if (results.readingFrames && results.readingFrames.frames) { + content += 'Reading Frames:\n'; + results.readingFrames.frames.forEach(frame => { + content += `Frame ${frame.frame} (${frame.direction}): ${frame.genes.length} genes found\n`; + }); + content += '\n'; + } + + // Add proteins if available + if (results.proteins && results.proteins.length > 0) { + content += 'Predicted Proteins:\n'; + results.proteins.forEach((protein, index) => { + const proteinSeq = protein.sequence || protein; + content += `Protein ${index + 1} (${protein.length || proteinSeq.length} aa): ${proteinSeq}\n`; + }); + } + + content += '\nAnalysis Date: ' + new Date().toLocaleString(); + fileName += '.txt'; + } + + // Create download link + const blob = new Blob([content], { type: mimeType }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = fileName; + a.click(); + + // Cleanup + setTimeout(() => URL.revokeObjectURL(url), 100); + + showNotification(`Results saved as ${fileName}`, 'success'); +} + +/** + * Add an analysis to the history + * @param {string} fileName - Name of the analyzed file + */ +function addToHistory(fileName) { + const historyList = document.getElementById('historyList'); + + // Remove empty state if present + const emptyState = historyList.querySelector('.history-empty'); + if (emptyState) { + historyList.removeChild(emptyState); + } + + // Create new history item + const historyItem = document.createElement('div'); + historyItem.className = 'history-item'; + + const now = new Date(); + const timeString = now.toLocaleTimeString(); + + historyItem.innerHTML = ` + <i class="fas fa-file-alt"></i> + <div class="history-details"> + <div class="history-name">${fileName}</div> + <div class="history-time">${timeString}</div> + </div> + `; + + // Add to history (prepend) + historyList.insertBefore(historyItem, historyList.firstChild); + + // Limit to 5 items + const items = historyList.querySelectorAll('.history-item'); + if (items.length > 5) { + historyList.removeChild(items[items.length - 1]); + } +} + +/** + * Get selected analysis options + * @returns {Array} - List of selected option values + */ +function getSelectedOptions() { + const checkboxes = document.querySelectorAll('input[name="analysis-option"]:checked'); + const options = []; + + checkboxes.forEach(checkbox => { + options.push(checkbox.value); + }); + + return options; +} + +/** + * Format file size in human-readable format + * @param {number} bytes - File size in bytes + * @returns {string} - Formatted file size + */ +function formatFileSize(bytes) { + if (bytes < 1024) { + return bytes + ' bytes'; + } else if (bytes < 1024 * 1024) { + return (bytes / 1024).toFixed(1) + ' KB'; + } else { + return (bytes / (1024 * 1024)).toFixed(1) + ' MB'; + } +} + +/** + * Show a notification + * @param {string} message - Notification message + * @param {string} type - Notification type (success, error, warning, info) + * @param {number} duration - Duration in milliseconds + */ +function showNotification(message, type = 'info', duration = 5000) { + const container = document.getElementById('notificationContainer'); + + // Create notification element + const notification = document.createElement('div'); + notification.className = `notification ${type}`; + + // Set icon based on type + let icon = 'info-circle'; + if (type === 'success') icon = 'check-circle'; + if (type === 'error') icon = 'times-circle'; + if (type === 'warning') icon = 'exclamation-triangle'; + + notification.innerHTML = ` + <i class="fas fa-${icon} notification-icon"></i> + <div class="notification-message">${message}</div> + `; + + // Add to container + container.appendChild(notification); + + // Remove after duration + setTimeout(() => { + notification.style.opacity = '0'; + notification.style.transform = 'translateX(100%)'; + + // Remove from DOM after animation + setTimeout(() => { + if (notification.parentNode) { + notification.parentNode.removeChild(notification); + } + }, 300); + }, duration); +} + +-------------------------------------------------- +File: ./web/analyzer/genetic-testing.js +-------------------------------------------------- +/** + * DNAnalyzer - Genetic Testing Module + * Handles genetic testing functionality including file handling, analysis, and visualization + */ + +// Initialize genetic testing functionality when DOM is loaded +document.addEventListener('DOMContentLoaded', function() { + if (document.getElementById('genetic-testing')) { + initGeneticTesting(); + } +}); + +/** + * Initialize genetic testing functionality + */ +function initGeneticTesting() { + // Initialize file upload for genetic data + initGeneticFileUpload(); + + // Initialize test options selection + initTestOptions(); + + // Initialize consent checkbox + initConsentCheckbox(); + + // Initialize analyze button + const geneticAnalyzeBtn = document.getElementById('geneticAnalyzeBtn'); + if (geneticAnalyzeBtn) { + geneticAnalyzeBtn.addEventListener('click', handleGeneticAnalysis); + } + + // Add sample data button + addSampleDataButton(); +} + +/** + * Initialize genetic file upload with drag and drop functionality + */ +function initGeneticFileUpload() { + const dropZone = document.getElementById('geneticFileDropZone'); + const fileInput = document.getElementById('geneticFileInput'); + + if (!dropZone || !fileInput) return; + + // Handle click on drop zone + dropZone.addEventListener('click', function() { + fileInput.click(); + }); + + // Handle file selection via input + fileInput.addEventListener('change', function(e) { + if (e.target.files.length > 0) { + handleGeneticFileSelection(e.target.files[0]); + } + }); + + // Handle drag and drop events + dropZone.addEventListener('dragover', function(e) { + e.preventDefault(); + dropZone.classList.add('drag-over'); + }); + + dropZone.addEventListener('dragleave', function() { + dropZone.classList.remove('drag-over'); + }); + + dropZone.addEventListener('drop', function(e) { + e.preventDefault(); + dropZone.classList.remove('drag-over'); + + if (e.dataTransfer.files.length > 0) { + handleGeneticFileSelection(e.dataTransfer.files[0]); + } + }); +} + +/** + * Handle the selected genetic data file + * @param {File} file - The selected file + */ +function handleGeneticFileSelection(file) { + const dropZone = document.getElementById('geneticFileDropZone'); + const fileInput = document.getElementById('geneticFileInput'); + const geneticAnalyzeBtn = document.getElementById('geneticAnalyzeBtn'); + + if (!dropZone || !fileInput || !geneticAnalyzeBtn) return; + + // Check file type + const validExtensions = ['.txt', '.csv', '.vcf']; + const fileExt = file.name.substring(file.name.lastIndexOf('.')).toLowerCase(); + + if (!validExtensions.includes(fileExt)) { + showNotification('Invalid file format. Please upload a .txt, .csv, or .vcf file.', 'error'); + return; + } + + // Update UI to show selected file + dropZone.innerHTML = ` + <div class="selected-file"> + <i class="fas fa-dna"></i> + <div class="file-info"> + <h4>${file.name}</h4> + <span>${formatFileSize(file.size)}</span> + </div> + <button class="file-remove" aria-label="Remove file"> + <i class="fas fa-times"></i> + </button> + </div> + `; + + // Add remove button functionality + const removeBtn = dropZone.querySelector('.file-remove'); + if (removeBtn) { + removeBtn.addEventListener('click', function(e) { + e.stopPropagation(); + resetGeneticFileUpload(); + }); + } + + // Store file in global variable for later use + window.selectedGeneticFile = file; + + // Enable analyze button if consent is checked + const consentCheckbox = document.getElementById('consentCheckbox'); + if (consentCheckbox && consentCheckbox.checked) { + geneticAnalyzeBtn.disabled = false; + } + + // Show notification + showNotification('Genetic data file selected. Complete the form and select testing options.', 'success'); +} + +/** + * Reset the genetic file upload area to its initial state + */ +function resetGeneticFileUpload() { + const dropZone = document.getElementById('geneticFileDropZone'); + const fileInput = document.getElementById('geneticFileInput'); + const geneticAnalyzeBtn = document.getElementById('geneticAnalyzeBtn'); + + if (!dropZone || !fileInput || !geneticAnalyzeBtn) return; + + // Reset input value + fileInput.value = ''; + + // Reset drop zone content + dropZone.innerHTML = ` + <i class="fas fa-cloud-upload-alt"></i> + <h3>Upload Genetic Data</h3> + <p>Drag and drop your genetic data file here or click to browse</p> + <span class="upload-formats">Supported formats: .txt, .csv, .vcf (23andMe, AncestryDNA, etc.)</span> + `; + + // Disable analyze button + geneticAnalyzeBtn.disabled = true; + + // Clear stored file + window.selectedGeneticFile = null; +} + +/** + * Initialize test options selection + */ +function initTestOptions() { + const testOptions = document.querySelectorAll('.test-option'); + + testOptions.forEach(option => { + option.addEventListener('click', function() { + this.classList.toggle('selected'); + }); + }); +} + +/** + * Initialize consent checkbox + */ +function initConsentCheckbox() { + const consentCheckbox = document.getElementById('consentCheckbox'); + const geneticAnalyzeBtn = document.getElementById('geneticAnalyzeBtn'); + + if (!consentCheckbox || !geneticAnalyzeBtn) return; + + consentCheckbox.addEventListener('change', function() { + // Enable analyze button only if both file is selected and consent is checked + geneticAnalyzeBtn.disabled = !(this.checked && window.selectedGeneticFile); + }); +} + +/** + * Add sample data button to the genetic testing tab + */ +function addSampleDataButton() { + const uploadFormats = document.querySelector('#geneticFileDropZone .upload-formats'); + + if (!uploadFormats) return; + + const sampleBtn = document.createElement('button'); + sampleBtn.className = 'btn btn-secondary btn-sm sample-data-btn'; + sampleBtn.innerHTML = '<i class="fas fa-vial"></i> Load Sample Data'; + sampleBtn.addEventListener('click', function(e) { + e.stopPropagation(); + loadSampleGeneticData(); + }); + + uploadFormats.insertAdjacentElement('afterend', sampleBtn); +} + +/** + * Load sample genetic data for demonstration + */ +function loadSampleGeneticData() { + // Create a sample file + const sampleData = createSampleGeneticData(); + const blob = new Blob([sampleData], { type: 'text/plain' }); + const file = new File([blob], 'sample-genetic-data.txt', { type: 'text/plain' }); + + // Process the sample file + handleGeneticFileSelection(file); + + // Pre-fill form with sample data + document.getElementById('gender').value = 'male'; + document.getElementById('age').value = '35'; + document.getElementById('ethnicity').value = 'european'; + + // Select all test options + document.querySelectorAll('.test-option').forEach(option => { + option.classList.add('selected'); + }); + + // Check consent checkbox + const consentCheckbox = document.getElementById('consentCheckbox'); + if (consentCheckbox) { + consentCheckbox.checked = true; + + // Trigger change event + const event = new Event('change'); + consentCheckbox.dispatchEvent(event); + } + + // Show notification + showNotification('Sample genetic data loaded successfully!', 'success'); +} + +/** + * Create sample genetic data in 23andMe format + * @returns {string} - Sample genetic data + */ +function createSampleGeneticData() { + return `# This data is for demonstration purposes only +# Sample genetic data in 23andMe format +# This file contains a small subset of SNPs for educational purposes + +# rsid\tchromosome\tposition\tgenotype +rs4477212\t1\t82154\tAA +rs3094315\t1\t752566\tAG +rs12562034\t1\t768448\tGG +rs3934834\t1\t1005806\tCC +rs3737728\t1\t1011278\tAG +rs11260588\t1\t1021454\tGG +rs2905036\t1\t1021915\tCC +rs2973725\t1\t1025314\tAG +rs2980300\t1\t1041900\tTT +rs4475691\t1\t1051029\tCC +rs11497407\t1\t1061166\tAA +rs11260603\t1\t1070488\tGG +rs2341354\t1\t1088657\tAG +rs2341355\t1\t1088761\tTT +rs1320571\t1\t1089876\tAG +rs11260614\t1\t1093709\tAA +rs2978398\t1\t1099810\tGG +rs2820323\t1\t1105366\tAG +rs2887286\t1\t1110240\tAA +rs1815606\t1\t1110294\tCC +rs2978381\t1\t1114147\tGG +rs7526076\t1\t1117281\tAA +rs2887286\t1\t1110240\tAA +rs1815606\t1\t1110294\tCC`; +} + +/** + * Handle genetic analysis process + */ +function handleGeneticAnalysis() { + // Get selected file + const file = window.selectedGeneticFile; + if (!file) { + showNotification('Please upload a genetic data file first.', 'warning'); + return; + } + + // Get selected tests + const selectedTests = []; + document.querySelectorAll('.test-option.selected').forEach(option => { + selectedTests.push(option.dataset.test); + }); + + if (selectedTests.length === 0) { + showNotification('Please select at least one test to perform.', 'warning'); + return; + } + + // Get form data + const formData = { + gender: document.getElementById('gender').value, + age: document.getElementById('age').value, + ethnicity: document.getElementById('ethnicity').value + }; + + // Start analysis + showNotification('Starting genetic analysis...', 'info'); + + // Show loading state + const analyzeBtn = document.getElementById('geneticAnalyzeBtn'); + if (analyzeBtn) { + analyzeBtn.disabled = true; + analyzeBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Analyzing...'; + } + + // Simulate processing delay + setTimeout(() => { + // Perform analysis + const results = performGeneticAnalysis(file, selectedTests, formData); + + // Display results + displayGeneticResults(results); + + // Reset button + if (analyzeBtn) { + analyzeBtn.disabled = false; + analyzeBtn.innerHTML = '<i class="fas fa-vial"></i> Run Genetic Tests'; + } + }, 2000); +} + +/** + * Perform genetic analysis on the provided file + * @param {File} file - Genetic data file + * @param {Array} selectedTests - Array of selected test types + * @param {Object} formData - Personal information form data + * @returns {Object} - Analysis results + */ +function performGeneticAnalysis(file, selectedTests, formData) { + // This is a simplified demonstration that returns pre-defined results + // In a real implementation, this would parse the file and analyze the data + + // Sample results for demonstration + return { + summary: { + totalSnps: 24, + analyzedSnps: 24, + coverage: "0.001%", + quality: "High" + }, + health: { + risks: [ + { condition: "Type 2 Diabetes", risk: "Slightly Elevated", snps: ["rs4477212", "rs3094315"], confidence: "Medium" }, + { condition: "Coronary Heart Disease", risk: "Average", snps: ["rs12562034", "rs3934834"], confidence: "High" }, + { condition: "Age-related Macular Degeneration", risk: "Lower", snps: ["rs3737728"], confidence: "Medium" }, + { condition: "Alzheimer's Disease", risk: "Average", snps: ["rs11260588", "rs2905036"], confidence: "Low" } + ] + }, + traits: { + physical: [ + { trait: "Eye Color", prediction: "Brown", snps: ["rs2973725", "rs2980300"], confidence: "High" }, + { trait: "Hair Type", prediction: "Straight", snps: ["rs4475691"], confidence: "Medium" }, + { trait: "Earwax Type", prediction: "Wet", snps: ["rs11497407"], confidence: "High" }, + { trait: "Lactose Intolerance", prediction: "Likely Tolerant", snps: ["rs11260603"], confidence: "Medium" } + ], + behavioral: [ + { trait: "Caffeine Metabolism", prediction: "Fast Metabolizer", snps: ["rs2341354"], confidence: "Medium" }, + { trait: "Alcohol Flush Reaction", prediction: "No Reaction", snps: ["rs2341355"], confidence: "High" } + ] + }, + ancestry: { + composition: [ + { population: "Northern European", percentage: 68 }, + { population: "Southern European", percentage: 12 }, + { population: "Eastern European", percentage: 8 }, + { population: "Northwest Asian", percentage: 6 }, + { population: "Other", percentage: 6 } + ], + haplogroups: { + maternal: "H1c", + paternal: "R1b1b2a1a" + } + }, + carrier: { + conditions: [ + { condition: "Cystic Fibrosis", status: "Not a Carrier", snps: ["rs1320571"], confidence: "High" }, + { condition: "Sickle Cell Anemia", status: "Not a Carrier", snps: ["rs11260614"], confidence: "High" }, + { condition: "Tay-Sachs Disease", status: "Not a Carrier", snps: ["rs2978398"], confidence: "Medium" }, + { condition: "Phenylketonuria", status: "Not a Carrier", snps: ["rs2820323"], confidence: "High" } + ] + } + }; +} + +/** + * Display genetic analysis results + * @param {Object} results - Analysis results + */ +function displayGeneticResults(results) { + // Get results section and make it visible + const resultsSection = document.getElementById('resultsSection'); + if (!resultsSection) return; + + resultsSection.style.display = 'block'; + resultsSection.scrollIntoView({ behavior: 'smooth' }); + + // Update summary section + const summaryElement = document.querySelector('.results-summary'); + if (summaryElement) { + summaryElement.innerHTML = ` + <h2>Genetic Analysis Results</h2> + <div class="summary-stats"> + <div class="summary-stat"> + <span class="stat-value">${results.summary.totalSnps}</span> + <span class="stat-label">SNPs Analyzed</span> + </div> + <div class="summary-stat"> + <span class="stat-value">${results.summary.coverage}</span> + <span class="stat-label">Genome Coverage</span> + </div> + <div class="summary-stat"> + <span class="stat-value">${results.summary.quality}</span> + <span class="stat-label">Data Quality</span> + </div> + </div> + `; + } + + // Update content section with tabs for each test type + const contentElement = document.querySelector('.results-content'); + if (!contentElement) return; + + // Create tabs + let tabsHtml = '<div class="results-tabs">'; + + if (results.health) { + tabsHtml += `<button class="tab-btn active" data-result-tab="health"> + <i class="fas fa-heartbeat"></i> Health Risks + </button>`; + } + + if (results.traits) { + tabsHtml += `<button class="tab-btn" data-result-tab="traits"> + <i class="fas fa-user"></i> Traits + </button>`; + } + + if (results.ancestry) { + tabsHtml += `<button class="tab-btn" data-result-tab="ancestry"> + <i class="fas fa-globe"></i> Ancestry + </button>`; + } + + if (results.carrier) { + tabsHtml += `<button class="tab-btn" data-result-tab="carrier"> + <i class="fas fa-baby"></i> Carrier Status + </button>`; + } + + tabsHtml += '</div>'; + + // Create tab content + let contentHtml = tabsHtml + '<div class="results-tab-content">'; + + // Health risks tab + if (results.health) { + contentHtml += ` + <div class="result-tab-panel active" id="health-panel"> + <h3>Health Risk Assessment</h3> + <p class="disclaimer">Note: These results are for educational purposes only and should not be used for medical decisions.</p> + + <div class="risk-cards"> + ${results.health.risks.map(risk => ` + <div class="risk-card risk-${risk.risk.toLowerCase().replace(/\s+/g, '-')}"> + <div class="risk-header"> + <h4>${risk.condition}</h4> + <span class="risk-level">${risk.risk}</span> + </div> + <div class="risk-details"> + <div class="snp-list"> + <strong>Relevant SNPs:</strong> ${risk.snps.join(', ')} + </div> + <div class="confidence"> + <strong>Confidence:</strong> + <span class="confidence-${risk.confidence.toLowerCase()}">${risk.confidence}</span> + </div> + </div> + </div> + `).join('')} + </div> + </div> + `; + } + + // Traits tab + if (results.traits) { + contentHtml += ` + <div class="result-tab-panel" id="traits-panel"> + <h3>Genetic Traits</h3> + + <div class="traits-section"> + <h4>Physical Traits</h4> + <div class="trait-cards"> + ${results.traits.physical.map(trait => ` + <div class="trait-card"> + <div class="trait-header"> + <h5>${trait.trait}</h5> + </div> + <div class="trait-prediction"> + <strong>${trait.prediction}</strong> + <span class="confidence-${trait.confidence.toLowerCase()}">${trait.confidence} confidence</span> + </div> + <div class="trait-snps"> + <small>SNPs: ${trait.snps.join(', ')}</small> + </div> + </div> + `).join('')} + </div> + </div> + + <div class="traits-section"> + <h4>Behavioral Traits</h4> + <div class="trait-cards"> + ${results.traits.behavioral.map(trait => ` + <div class="trait-card"> + <div class="trait-header"> + <h5>${trait.trait}</h5> + </div> + <div class="trait-prediction"> + <strong>${trait.prediction}</strong> + <span class="confidence-${trait.confidence.toLowerCase()}">${trait.confidence} confidence</span> + </div> + <div class="trait-snps"> + <small>SNPs: ${trait.snps.join(', ')}</small> + </div> + </div> + `).join('')} + </div> + </div> + </div> + `; + } + + // Ancestry tab + if (results.ancestry) { + contentHtml += ` + <div class="result-tab-panel" id="ancestry-panel"> + <h3>Ancestry Composition</h3> + + <div class="ancestry-composition"> + <div class="ancestry-chart"> + <canvas id="ancestryChart"></canvas> + </div> + <div class="ancestry-breakdown"> + ${results.ancestry.composition.map(pop => ` + <div class="ancestry-item"> + <div class="ancestry-name">${pop.population}</div> + <div class="ancestry-bar"> + <div class="ancestry-progress" style="width: ${pop.percentage}%"></div> + </div> + <div class="ancestry-percentage">${pop.percentage}%</div> + </div> + `).join('')} + </div> + </div> + + <div class="haplogroups-section"> + <h4>Haplogroups</h4> + <div class="haplogroups-info"> + <div class="haplogroup-item"> + <strong>Maternal Haplogroup:</strong> ${results.ancestry.haplogroups.maternal} + </div> + <div class="haplogroup-item"> + <strong>Paternal Haplogroup:</strong> ${results.ancestry.haplogroups.paternal} + </div> + </div> + </div> + </div> + `; + } + + // Carrier status tab + if (results.carrier) { + contentHtml += ` + <div class="result-tab-panel" id="carrier-panel"> + <h3>Carrier Status</h3> + <p class="disclaimer">Note: These results are for educational purposes only and should not be used for family planning decisions.</p> + + <div class="carrier-cards"> + ${results.carrier.conditions.map(condition => ` + <div class="carrier-card"> + <div class="carrier-header"> + <h4>${condition.condition}</h4> + <span class="carrier-status status-${condition.status.toLowerCase().replace(/\s+/g, '-')}">${condition.status}</span> + </div> + <div class="carrier-details"> + <div class="snp-list"> + <strong>Relevant SNPs:</strong> ${condition.snps.join(', ')} + </div> + <div class="confidence"> + <strong>Confidence:</strong> + <span class="confidence-${condition.confidence.toLowerCase()}">${condition.confidence}</span> + </div> + </div> + </div> + `).join('')} + </div> + </div> + `; + } + + contentHtml += '</div>'; + + // Update content + contentElement.innerHTML = contentHtml; + + // Initialize results tabs + initResultsTabs(); + + // Initialize charts if ancestry results are present + if (results.ancestry) { + initAncestryChart(results.ancestry.composition); + } + + // Show notification + showNotification('Genetic analysis completed successfully!', 'success'); +} + +/** + * Initialize tabs in the results section + */ +function initResultsTabs() { + const tabButtons = document.querySelectorAll('.results-tabs .tab-btn'); + + tabButtons.forEach(button => { + button.addEventListener('click', function() { + // Remove active class from all buttons and panels + document.querySelectorAll('.results-tabs .tab-btn').forEach(btn => { + btn.classList.remove('active'); + }); + + document.querySelectorAll('.result-tab-panel').forEach(panel => { + panel.classList.remove('active'); + }); + + // Add active class to current button + this.classList.add('active'); + + // Show corresponding panel + const tabName = this.dataset.resultTab; + const panel = document.getElementById(tabName + '-panel'); + if (panel) { + panel.classList.add('active'); + } + }); + }); +} + +/** + * Initialize ancestry composition chart + * @param {Array} composition - Ancestry composition data + */ +function initAncestryChart(composition) { + const canvas = document.getElementById('ancestryChart'); + if (!canvas) return; + + const ctx = canvas.getContext('2d'); + + // Extract data for chart + const labels = composition.map(item => item.population); + const data = composition.map(item => item.percentage); + const colors = [ + '#4285F4', '#EA4335', '#FBBC05', '#34A853', '#FF6D01', + '#46BDC6', '#9C27B0', '#3F51B5', '#03A9F4', '#00BCD4' + ]; + + // Create chart + new Chart(ctx, { + type: 'doughnut', + data: { + labels: labels, + datasets: [{ + data: data, + backgroundColor: colors.slice(0, composition.length), + borderColor: '#001427', + borderWidth: 1 + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { + legend: { + display: false + }, + tooltip: { + backgroundColor: 'rgba(0, 20, 39, 0.8)', + titleFont: { + family: 'Inter, sans-serif', + size: 14 + }, + bodyFont: { + family: 'Inter, sans-serif', + size: 13 + }, + callbacks: { + label: function(context) { + return context.label + ': ' + context.raw + '%'; + } + } + } + }, + cutout: '70%' + } + }); +} + +// Utility function for formatting file size +function formatFileSize(bytes) { + if (bytes === 0) return '0 Bytes'; + const k = 1024; + const sizes = ['Bytes', 'KB', 'MB', 'GB']; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; +} + +// Utility function for showing notifications +function showNotification(message, type = 'info', duration = 5000) { + // Use the existing notification function from analyzer.js if available + if (window.showNotification) { + window.showNotification(message, type, duration); + return; + } + + // Fallback implementation + const container = document.getElementById('notificationContainer'); + if (!container) return; + + const notification = document.createElement('div'); + notification.className = `notification notification-${type}`; + + const icon = document.createElement('i'); + switch (type) { + case 'success': + icon.className = 'fas fa-check-circle'; + break; + case 'error': + icon.className = 'fas fa-exclamation-circle'; + break; + case 'warning': + icon.className = 'fas fa-exclamation-triangle'; + break; + default: + icon.className = 'fas fa-info-circle'; + } + + const content = document.createElement('div'); + content.className = 'notification-content'; + content.textContent = message; + + notification.appendChild(icon); + notification.appendChild(content); + container.appendChild(notification); + + // Show animation + setTimeout(() => { + notification.classList.add('show'); + }, 10); + + // Hide after duration + setTimeout(() => { + notification.classList.remove('show'); + setTimeout(() => { + notification.remove(); + }, 300); + }, duration); +} + +// Genetic Testing Implementation +const geneticTestingModule = { + // Supported file formats + supportedFormats: ['.fastq', '.fasta', '.sam', '.bam', '.vcf'], + + // Sample DNA sequences for testing + sampleSequences: { + 'sample1.fastq': 'ATCGATCGATCGATCG...', + 'sample2.fasta': '>Sample2\nGATTACAGATTACA...', + 'sample3.vcf': '##fileformat=VCFv4.2\n#CHROM\tPOS\tID...' + }, + + init() { + this.setupEventListeners(); + this.initializeUI(); + }, + + setupEventListeners() { + // File upload handling + const fileInput = document.getElementById('dnaFileInput'); + fileInput.addEventListener('change', (e) => this.handleFileUpload(e)); + + // Sample file selection + const sampleSelect = document.getElementById('sampleFileSelect'); + sampleSelect.addEventListener('change', (e) => this.loadSampleFile(e)); + + // Analysis button + const analyzeBtn = document.getElementById('analyzeButton'); + analyzeBtn.addEventListener('click', () => this.startAnalysis()); + }, + + initializeUI() { + // Initialize dropzone + const dropZone = document.getElementById('dropZone'); + ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { + dropZone.addEventListener(eventName, (e) => { + e.preventDefault(); + e.stopPropagation(); + }); + }); + + dropZone.addEventListener('drop', (e) => { + const files = e.dataTransfer.files; + this.handleFileUpload({ target: { files } }); + }); + + // Add sample files to select + const sampleSelect = document.getElementById('sampleFileSelect'); + Object.keys(this.sampleSequences).forEach(sample => { + const option = document.createElement('option'); + option.value = sample; + option.textContent = sample; + sampleSelect.appendChild(option); + }); + }, + + async handleFileUpload(event) { + const file = event.target.files[0]; + if (!file) return; + + if (!this.validateFileFormat(file)) { + this.showError(`Unsupported file format. Please use: ${this.supportedFormats.join(', ')}`); + return; + } + + try { + const sequence = await this.readFile(file); + this.updateUI('fileLoaded', { fileName: file.name, sequence }); + } catch (error) { + this.showError('Error reading file: ' + error.message); + } + }, + + loadSampleFile(event) { + const sampleName = event.target.value; + const sequence = this.sampleSequences[sampleName]; + if (sequence) { + this.updateUI('fileLoaded', { fileName: sampleName, sequence }); + } + }, + + async startAnalysis() { + const sequence = this.getCurrentSequence(); + if (!sequence) { + this.showError('Please upload a DNA sequence file or select a sample first.'); + return; + } + + this.updateUI('analysisStarted'); + + try { + // Perform various analyses + const results = await Promise.all([ + this.analyzeMutations(sequence), + this.predictTraits(sequence), + this.findAncestry(sequence), + this.assessHealthRisks(sequence) + ]); + + this.updateUI('analysisComplete', { results }); + } catch (error) { + this.showError('Analysis failed: ' + error.message); + } + }, + + // Analysis Methods + async analyzeMutations(sequence) { + // Implementation of mutation analysis + return { + type: 'mutations', + findings: [ + { position: 1234, mutation: 'SNP', reference: 'A', variant: 'G' }, + { position: 5678, mutation: 'Deletion', reference: 'CTG', variant: '-' } + ] + }; + }, + + async predictTraits(sequence) { + // Implementation of trait prediction + return { + type: 'traits', + predictions: [ + { trait: 'Eye Color', prediction: 'Brown', confidence: 0.89 }, + { trait: 'Height', prediction: 'Above Average', confidence: 0.75 } + ] + }; + }, + + async findAncestry(sequence) { + // Implementation of ancestry analysis + return { + type: 'ancestry', + composition: [ + { region: 'European', percentage: 45 }, + { region: 'East Asian', percentage: 30 }, + { region: 'African', percentage: 25 } + ] + }; + }, + + async assessHealthRisks(sequence) { + // Implementation of health risk assessment + return { + type: 'health', + risks: [ + { condition: 'Type 2 Diabetes', risk: 'Low', score: 0.2 }, + { condition: 'Heart Disease', risk: 'Moderate', score: 0.4 } + ] + }; + }, + + // Utility Methods + validateFileFormat(file) { + return this.supportedFormats.some(format => + file.name.toLowerCase().endsWith(format) + ); + }, + + async readFile(file) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = (e) => resolve(e.target.result); + reader.onerror = (e) => reject(new Error('File reading failed')); + reader.readAsText(file); + }); + }, + + getCurrentSequence() { + const sequenceDisplay = document.getElementById('sequenceDisplay'); + return sequenceDisplay?.dataset.sequence; + }, + + showError(message) { + const errorDisplay = document.getElementById('errorDisplay'); + errorDisplay.textContent = message; + errorDisplay.style.display = 'block'; + setTimeout(() => { + errorDisplay.style.display = 'none'; + }, 5000); + }, + + updateUI(state, data = {}) { + const loadingSpinner = document.getElementById('loadingSpinner'); + const resultsContainer = document.getElementById('resultsContainer'); + const sequenceDisplay = document.getElementById('sequenceDisplay'); + + switch (state) { + case 'fileLoaded': + sequenceDisplay.textContent = `File loaded: ${data.fileName}`; + sequenceDisplay.dataset.sequence = data.sequence; + break; + + case 'analysisStarted': + loadingSpinner.style.display = 'block'; + resultsContainer.innerHTML = ''; + break; + + case 'analysisComplete': + loadingSpinner.style.display = 'none'; + this.displayResults(data.results); + break; + } + }, + + displayResults(results) { + const resultsContainer = document.getElementById('resultsContainer'); + resultsContainer.innerHTML = ''; + + results.forEach(result => { + const section = document.createElement('div'); + section.className = 'result-section'; + + switch (result.type) { + case 'mutations': + section.innerHTML = this.createMutationsHTML(result); + break; + case 'traits': + section.innerHTML = this.createTraitsHTML(result); + break; + case 'ancestry': + section.innerHTML = this.createAncestryHTML(result); + break; + case 'health': + section.innerHTML = this.createHealthHTML(result); + break; + } + + resultsContainer.appendChild(section); + }); + }, + + createMutationsHTML(result) { + return ` + <h3>Genetic Mutations</h3> + <div class="mutations-list"> + ${result.findings.map(mutation => ` + <div class="mutation-item"> + <span>Position: ${mutation.position}</span> + <span>Type: ${mutation.mutation}</span> + <span>Change: ${mutation.reference} → ${mutation.variant}</span> + </div> + `).join('')} + </div> + `; + }, + + createTraitsHTML(result) { + return ` + <h3>Predicted Traits</h3> + <div class="traits-list"> + ${result.predictions.map(trait => ` + <div class="trait-item"> + <span>${trait.trait}</span> + <span>${trait.prediction}</span> + <div class="confidence-bar" style="width: ${trait.confidence * 100}%"></div> + </div> + `).join('')} + </div> + `; + }, + + createAncestryHTML(result) { + return ` + <h3>Ancestry Composition</h3> + <div class="ancestry-chart"> + ${result.composition.map(region => ` + <div class="ancestry-bar"> + <div class="ancestry-fill" style="width: ${region.percentage}%"></div> + <span>${region.region}: ${region.percentage}%</span> + </div> + `).join('')} + </div> + `; + }, + + createHealthHTML(result) { + return ` + <h3>Health Risk Assessment</h3> + <div class="health-risks"> + ${result.risks.map(risk => ` + <div class="risk-item ${risk.risk.toLowerCase()}"> + <span>${risk.condition}</span> + <span class="risk-level">${risk.risk}</span> + <div class="risk-bar" style="width: ${risk.score * 100}%"></div> + </div> + `).join('')} + </div> + `; + } +}; + +// Initialize the module when the page loads +document.addEventListener('DOMContentLoaded', () => geneticTestingModule.init()); +-------------------------------------------------- +File: ./web/analyzer/analyzer.html +-------------------------------------------------- +<!DOCTYPE html> +<html lang="en"> + +<head> + <!-- Google tag (gtag.js) --> + <script async src="https://www.googletagmanager.com/gtag/js?id=G-0LTP0WK7EM"></script> + <script> + window.dataLayer = window.dataLayer || []; + function gtag() { dataLayer.push(arguments); } + gtag('js', new Date()); + + gtag('config', 'G-0LTP0WK7EM'); + </script> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>DNA Analyzer - DNAnalyzer</title> + <meta name="description" + content="Analyze DNA sequences with advanced ML-powered tools. Upload FASTA or FASTQ files and get comprehensive analysis."> + + <!-- Stylesheets --> + <link rel="stylesheet" href="../style.css"> + <link rel="stylesheet" href="analyzer.css"> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.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@300;400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap" + rel="stylesheet"> + + <!-- Favicon --> + <link rel="shortcut icon" href="../assets/icons/Icon_Dark_BG.svg" type="image/svg+xml"> +</head> + +<body> + <!-- Background effects --> + <div class="bg-gradient"> + <div class="bg-blob bg-blob-1"></div> + <div class="bg-blob bg-blob-2"></div> + </div> + + <div class="notification-banner"> + <span>Exclusive WSSEF Preview: </span> + <span> Transformer Architecture in Epigenomics!</span> + <a href="https://epiclassify.dnanalyzer.org" target="_blank" class="notification-link">Explore Now</a> + <button class="notification-close" aria-label="Dismiss notification"></button> + </div> + + <!-- Navbar --> + <nav class="navbar" id="navbar"> + <div class="container navbar-container"> + <a href="../index.html" class="logo"> + <img src="../assets/icons/Icon_Dark_BG.svg" alt="DNAnalyzer Logo"> + <span class="logo-text">DNAnalyzer</span> + </a> + + <button class="mobile-toggle" id="mobileToggle" aria-label="Toggle navigation"> + <i class="fas fa-bars"></i> + </button> + + <ul class="nav-links" id="navLinks"> + <li><a href="../index.html">Home</a></li> + <li><a href="../features/features.html">Features</a></li> + <li><a href="analyzer.html" class="active">Analyzer</a></li> + <li><a href="../server/server.html">Server</a></li> + <li><a href="../docs/docs.html">Docs</a></li> + <li><a href="../about/about.html">About</a></li> + </ul> + + <div class="nav-buttons"> + <a href="https://github.com/VerisimilitudeX/DNAnalyzer" class="btn btn-secondary btn-sm"> + <i class="fab fa-github btn-icon"></i> GitHub + </a> + </div> + </div> + </nav> + + <!-- Main Content --> + <main class="analyzer-main"> + <div class="container"> + <div class="analyzer-header"> + <h1>DNA Sequence <span class="gradient-text">Analysis</span></h1> + <p>Analyze DNA sequences with advanced machine learning tools</p> + </div> + + <div class="analyzer-dashboard"> + <div class="dashboard-sidebar"> + <div class="sidebar-section"> + <h3>Analysis History</h3> + <div class="history-list" id="historyList"> + <div class="history-empty"> + <i class="fas fa-history"></i> + <p>No recent analyses</p> + </div> + </div> + </div> + + <div class="sidebar-section"> + <h3>Quick Actions</h3> + <div class="quick-actions"> + <button id="importSampleBtn" class="sidebar-btn"> + <i class="fas fa-file-import"></i> + Import Sample + </button> + <button id="clearOptionsBtn" class="sidebar-btn"> + <i class="fas fa-undo"></i> + Reset Options + </button> + <button id="helpBtn" class="sidebar-btn"> + <i class="fas fa-question-circle"></i> + Help Guide + </button> + </div> + </div> + + <div class="sidebar-section api-status-container"> + <h3>API Status</h3> + <div class="api-status" id="apiStatus"> + <div class="status-indicator"> + <div class="status-dot pulse"></div> + <span>Checking connection...</span> + </div> + </div> + </div> + </div> + + <div class="dashboard-content"> + <div class="analyzer-tabs"> + <button class="tab-btn active" data-tab="dna-analysis"> + <i class="fas fa-dna"></i> + DNA Analysis + </button> + <button class="tab-btn" data-tab="genetic-testing"> + <i class="fas fa-vial"></i> + Genetic Testing + </button> + <button class="tab-btn" data-tab="batch-processing"> + <i class="fas fa-layer-group"></i> + Batch Processing + </button> + </div> + + <div class="tab-content active" id="dna-analysis"> + <div class="analyzer-upload" id="fileDropZone"> + <i class="fas fa-cloud-upload-alt"></i> + <h3>Upload DNA Sequence</h3> + <p>Drag and drop your sequence file here or click to browse</p> + <input type="file" id="fileInput" accept=".fa,.fasta,.fastq,.txt" hidden> + <span class="upload-formats">Supported formats: .fa, .fasta, .fastq, .txt</span> + </div> + + <div class="analysis-options"> + <h3>Analysis Options</h3> + <div class="options-grid"> + <div class="option-card"> + <div class="option-header"> + <i class="fas fa-microscope"></i> + <h4>Basic Analysis</h4> + </div> + <div class="option-content"> + <label class="option-checkbox"> + <input type="checkbox" name="analysis-option" value="sequence-length" + checked> + <span class="checkmark"></span> + Sequence Length + </label> + <label class="option-checkbox"> + <input type="checkbox" name="analysis-option" value="gc-content" checked> + <span class="checkmark"></span> + GC Content + </label> + <label class="option-checkbox"> + <input type="checkbox" name="analysis-option" value="base-composition" + checked> + <span class="checkmark"></span> + Base Composition + </label> + </div> + </div> + + <div class="option-card"> + <div class="option-header"> + <i class="fas fa-dna"></i> + <h4>Codon Analysis</h4> + </div> + <div class="option-content"> + <label class="option-checkbox"> + <input type="checkbox" name="analysis-option" value="start-codons" checked> + <span class="checkmark"></span> + Start Codons + </label> + <label class="option-checkbox"> + <input type="checkbox" name="analysis-option" value="stop-codons" checked> + <span class="checkmark"></span> + Stop Codons + </label> + <label class="option-checkbox"> + <input type="checkbox" name="analysis-option" value="reading-frames"> + <span class="checkmark"></span> + Reading Frames + </label> + </div> + </div> + + <div class="option-card"> + <div class="option-header"> + <i class="fas fa-chart-line"></i> + <h4>Advanced Features</h4> + </div> + <div class="option-content"> + <label class="option-checkbox"> + <input type="checkbox" name="analysis-option" value="coverage"> + <span class="checkmark"></span> + Coverage Analysis + </label> + <label class="option-checkbox"> + <input type="checkbox" name="analysis-option" value="protein-prediction"> + <span class="checkmark"></span> + Protein Prediction + </label> + <label class="option-checkbox"> + <input type="checkbox" name="analysis-option" value="promoter-detection"> + <span class="checkmark"></span> + Promoter Detection + </label> + </div> + </div> + </div> + + <button class="btn btn-primary analyze-btn" id="analyzeBtn" disabled> + <i class="fas fa-play"></i> + Start Analysis + </button> + </div> + </div> + + <div class="tab-content" id="genetic-testing"> + <div class="genetic-testing-container"> + <div id="dropZone" class="drop-zone"> + <i class="fas fa-dna"></i> + <h3>Upload DNA File or Drop Here</h3> + <p>Supported formats: .fastq, .fasta, .sam, .bam, .vcf</p> + <input type="file" id="dnaFileInput" accept=".fastq,.fasta,.sam,.bam,.vcf" /> + + <div class="sample-selector"> + <p>Or try with a sample file:</p> + <select id="sampleFileSelect"> + <option value="">Select a sample file...</option> + </select> + </div> + </div> + + <div id="sequenceDisplay" class="sequence-display"></div> + + <button id="analyzeButton" class="analyze-btn"> + <i class="fas fa-microscope"></i> + Analyze DNA + </button> + + <div id="loadingSpinner" class="loading-spinner" style="display: none;"> + <div class="spinner"></div> + <p>Analyzing DNA sequence...</p> + </div> + + <div id="errorDisplay" class="error-display"></div> + + <div id="resultsContainer" class="results-container"></div> + </div> + </div> + + <div class="tab-content" id="batch-processing"> + <div class="coming-soon"> + <i class="fas fa-layer-group"></i> + <h3>Batch Processing Coming Soon</h3> + <p>Process multiple DNA sequence files simultaneously for high-throughput analysis. Sign up + for our newsletter to be notified when this feature launches.</p> + </div> + </div> + </div> + </div> + + <!-- Results Section (initially hidden) --> + <div class="analyzer-results" id="resultsSection" style="display: none;"> + <div class="results-header"> + <h2>Analysis Results</h2> + <div class="results-actions"> + <div class="results-file-info" id="resultsFileInfo"> + <i class="fas fa-file-alt"></i> + <span>sample.fa</span> + </div> + <button class="btn btn-secondary" id="exportBtn"> + <i class="fas fa-download"></i> + Export Results + </button> + </div> + </div> + + <div class="results-content" id="resultsContent"> + <!-- Results will be inserted here by JavaScript --> + </div> + </div> + </div> + + <!-- Export Modal --> + <div class="modal" id="exportModal"> + <div class="modal-content"> + <div class="modal-header"> + <h3>Export Results</h3> + <button class="close-modal" id="closeExportModal">×</button> + </div> + <div class="modal-body"> + <p>Choose format to download your analysis results:</p> + <div class="export-options"> + <button class="export-option" data-format="json"> + <i class="fas fa-file-code"></i> + <span>JSON</span> + </button> + <button class="export-option" data-format="csv"> + <i class="fas fa-file-csv"></i> + <span>CSV</span> + </button> + <button class="export-option" data-format="txt"> + <i class="fas fa-file-alt"></i> + <span>Text</span> + </button> + </div> + </div> + </div> + </div> + + <!-- Help Modal --> + <div class="modal" id="helpModal"> + <div class="modal-content"> + <div class="modal-header"> + <h3>DNA Analyzer Help</h3> + <button class="close-modal" id="closeHelpModal">×</button> + </div> + <div class="modal-body"> + <h4>Getting Started</h4> + <p>To analyze DNA sequences, follow these steps:</p> + <ol> + <li>Upload a DNA sequence file (.fa, .fasta, .fastq, .txt) by dragging it to the upload area or + clicking to browse.</li> + <li>Select the analysis options you want to run on your sequence.</li> + <li>Click "Start Analysis" to process your sequence.</li> + <li>View the results and download them if needed.</li> + </ol> + + <h4>Analysis Options</h4> + <p>DNAnalyzer offers several types of analysis:</p> + <ul> + <li><strong>Basic Analysis:</strong> Calculates sequence length, GC content percentage, and + nucleotide composition.</li> + <li><strong>Codon Analysis:</strong> Identifies start codons (ATG), stop codons (TAA, TAG, TGA), + and reading frames.</li> + <li><strong>Advanced Features:</strong> Performs coverage analysis, protein prediction, and + promoter sequence detection.</li> + </ul> + + <h4>Need More Help?</h4> + <p>Check out our <a href="../docs/docs.html">Documentation</a> for detailed guides or join our <a + href="https://discord.gg/xNpujz49gj">Discord community</a> for support.</p> + </div> + </div> + </div> + </main> + + <!-- Notification container --> + <div class="notification-container" id="notificationContainer"></div> + + <!-- Footer --> + <footer class="footer"> + <div class="container"> + <div class="footer-grid"> + <div class="footer-brand"> + <img src="../assets/icons/Icon_Dark_BG.svg" alt="DNAnalyzer Logo"> + <p>DNAnalyzer is a powerful, privacy-focused DNA analysis tool using cutting-edge machine learning + models for accurate, on-device genomic analysis.</p> + + <div class="social-links"> + <a href="https://github.com/VerisimilitudeX/DNAnalyzer" class="social-link"> + <i class="fab fa-github"></i> + </a> + <a href="https://discord.gg/xNpujz49gj" class="social-link"> + <i class="fab fa-discord"></i> + </a> + <a href="https://twitter.com/DNAnalyzer_" class="social-link"> + <i class="fab fa-twitter"></i> + </a> + <a href="https://www.x.com/DNAnalyzer_" class="social-link"> + <svg xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 512 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--> + <path + d="M389.2 48h70.6L305.6 224.2 487 464H345L233.7 318.6 106.5 464H35.8L200.7 275.5 26.8 48H172.4L272.9 180.9 389.2 48zM364.4 421.8h39.1L151.1 88h-42L364.4 421.8z" /> + </svg> + </a> + </div> + </div> + + <div class="footer-nav"> + <h4>Product</h4> + <ul> + <li><a href="../features/features.html">Features</a></li> + <li><a href="analyzer.html">DNA Analyzer</a></li> + <li><a href="../server/server.html">Server</a></li> + <li><a href="../docs/docs.html">Documentation</a></li> + </ul> + </div> + + <div class="footer-nav"> + <h4>Resources</h4> + <ul> + <li><a href="../docs/getting-started.md">Getting Started</a></li> + <li><a href="../docs/citations.md">Citations</a></li> + <li><a href="../docs/research/genes.md">Gene Research</a></li> + <li><a href="../docs/samples/cli-arguments-examples.md">CLI Examples</a></li> + </ul> + </div> + + <div class="footer-nav"> + <h4>Community</h4> + <ul> + <li><a href="https://github.com/VerisimilitudeX/DNAnalyzer">GitHub</a></li> + <li><a href="https://discord.gg/xNpujz49gj">Discord</a></li> + <li><a href="../docs/contributing/CONTRIBUTING.md">Contributing</a></li> + <li><a href="../CODE_OF_CONDUCT.md">Code of Conduct</a></li> + </ul> + </div> + </div> + + <div class="footer-bottom"> + <div class="footer-copyright"> + Copyright © Piyush Acharya 2025. DNAnalyzer is a fiscally sponsored 501(c)(3) nonprofit (EIN: + 81-2908499). MIT License. + </div> + + <div class="footer-links"> + <a href="../LICENSE.md">License</a> + <a href="../SECURITY.md">Security</a> + <a href="../CITATION.cff">Citation</a> + </div> + </div> + </div> + </footer> + + <!-- JavaScript --> + <script src="../assets/js/api-client.js"></script> + <script src="analyzer.js"></script> + <!-- Chart.js for visualizations --> + <script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script> + <!-- Genetic Testing Script --> + <script src="genetic-testing.js"></script> +</body> + +</html> +-------------------------------------------------- + +Directory: assets +================================================== +File: ./web/assets/full.png +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte] + +-------------------------------------------------- + +Directory: assets/IBM Plex Mono Inter +================================================== + +Directory: assets/IBM Plex Mono Inter/IBM_Plex_Mono +================================================== +File: ./web/assets/IBM Plex Mono Inter/IBM_Plex_Mono/IBMPlexMono-ThinItalic.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x9c in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/IBM_Plex_Mono/IBMPlexMono-LightItalic.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x9c in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/IBM_Plex_Mono/IBMPlexMono-SemiBoldItalic.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x9c in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/IBM_Plex_Mono/IBMPlexMono-Italic.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x9c in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/IBM_Plex_Mono/IBMPlexMono-Bold.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x82 in position 17: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/IBM_Plex_Mono/IBMPlexMono-Thin.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x82 in position 17: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/IBM_Plex_Mono/IBMPlexMono-Light.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x82 in position 17: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/IBM_Plex_Mono/IBMPlexMono-Regular.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x82 in position 17: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/IBM_Plex_Mono/IBMPlexMono-Medium.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x82 in position 17: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/IBM_Plex_Mono/IBMPlexMono-MediumItalic.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x9c in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/IBM_Plex_Mono/OFL.txt +-------------------------------------------------- +Copyright © 2017 IBM Corp. with Reserved Font Name "Plex" + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/IBM_Plex_Mono/IBMPlexMono-ExtraLightItalic.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x9c in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/IBM_Plex_Mono/IBMPlexMono-BoldItalic.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x9c in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/IBM_Plex_Mono/IBMPlexMono-ExtraLight.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x82 in position 17: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/IBM_Plex_Mono/IBMPlexMono-SemiBold.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x82 in position 17: invalid start byte] + +-------------------------------------------------- + +Directory: assets/IBM Plex Mono Inter/Inter +================================================== +File: ./web/assets/IBM Plex Mono Inter/Inter/Inter-VariableFont_slnt,wght.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0xeb in position 17: invalid continuation byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/Inter/README.txt +-------------------------------------------------- +Inter Variable Font +=================== + +This download contains Inter as both a variable font and static fonts. + +Inter is a variable font with these axes: + slnt + wght + +This means all the styles are contained in a single file: + Inter/Inter-VariableFont_slnt,wght.ttf + +If your app fully supports variable fonts, you can now pick intermediate styles +that aren’t available as static fonts. Not all apps support variable fonts, and +in those cases you can use the static font files for Inter: + Inter/static/Inter-Thin.ttf + Inter/static/Inter-ExtraLight.ttf + Inter/static/Inter-Light.ttf + Inter/static/Inter-Regular.ttf + Inter/static/Inter-Medium.ttf + Inter/static/Inter-SemiBold.ttf + Inter/static/Inter-Bold.ttf + Inter/static/Inter-ExtraBold.ttf + Inter/static/Inter-Black.ttf + +Get started +----------- + +1. Install the font files you want to use + +2. Use your app's font picker to view the font family and all the +available styles + +Learn more about variable fonts +------------------------------- + + https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts + https://variablefonts.typenetwork.com + https://medium.com/variable-fonts + +In desktop apps + + https://theblog.adobe.com/can-variable-fonts-illustrator-cc + https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts + +Online + + https://developers.google.com/fonts/docs/getting_started + https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide + https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts + +Installing fonts + + MacOS: https://support.apple.com/en-us/HT201749 + Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux + Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows + +Android Apps + + https://developers.google.com/fonts/docs/android + https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts + +License +------- +Please read the full license text (OFL.txt) to understand the permissions, +restrictions and requirements for usage, redistribution, and modification. + +You can use them in your products & projects – print or digital, +commercial or otherwise. + +This isn't legal advice, please consider consulting a lawyer and see the full +license for all details. + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/Inter/OFL.txt +-------------------------------------------------- +Copyright 2020 The Inter Project Authors (https://github.com/rsms/inter) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +-------------------------------------------------- + +Directory: assets/IBM Plex Mono Inter/Inter/static +================================================== +File: ./web/assets/IBM Plex Mono Inter/Inter/static/Inter-ExtraBold.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0xba in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/Inter/static/Inter-Light.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0xba in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/Inter/static/Inter-Medium.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0xba in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/Inter/static/Inter-SemiBold.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0xba in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/Inter/static/Inter-Bold.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0xba in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/Inter/static/Inter-ExtraLight.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0xba in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/Inter/static/Inter-Thin.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0xba in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/Inter/static/Inter-Regular.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0xba in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono Inter/Inter/static/Inter-Black.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0xba in position 19: invalid start byte] + +-------------------------------------------------- + +Directory: assets/mockup +================================================== +File: ./web/assets/mockup/image.png +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/mockup/Slide_01.png +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte] + +-------------------------------------------------- + +Directory: assets/IBM Plex Mono +================================================== +File: ./web/assets/IBM Plex Mono/IBMPlexMono-ThinItalic.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x9c in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono/IBMPlexMono-LightItalic.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x9c in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono/IBMPlexMono-SemiBoldItalic.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x9c in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono/IBMPlexMono-Italic.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x9c in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono/IBMPlexMono-Bold.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x82 in position 17: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono/IBMPlexMono-Thin.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x82 in position 17: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono/IBMPlexMono-Light.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x82 in position 17: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono/IBMPlexMono-Regular.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x82 in position 17: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono/IBMPlexMono-Medium.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x82 in position 17: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono/IBMPlexMono-MediumItalic.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x9c in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono/OFL.txt +-------------------------------------------------- +Copyright © 2017 IBM Corp. with Reserved Font Name "Plex" + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono/IBMPlexMono-ExtraLightItalic.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x9c in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono/IBMPlexMono-BoldItalic.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x9c in position 19: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono/IBMPlexMono-ExtraLight.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x82 in position 17: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/IBM Plex Mono/IBMPlexMono-SemiBold.ttf +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x82 in position 17: invalid start byte] + +-------------------------------------------------- + +Directory: assets/icons +================================================== +File: ./web/assets/icons/Icon.svg +-------------------------------------------------- +<svg width="400" height="400" viewBox="0 0 400 400" fill="none" xmlns="http://www.w3.org/2000/svg"> +<rect width="400" height="400" rx="100" fill="white"/> +<rect x="65" y="75" width="93.1035" height="46.5517" rx="23.2759" fill="#E3016D"/> +<rect x="176.725" y="75" width="93.1035" height="46.5517" rx="23.2759" fill="#01A4EF"/> +<rect x="288.448" y="75" width="46.5517" height="46.5517" rx="23.2759" fill="#0178D6"/> +<rect x="130.173" y="142.5" width="93.1035" height="46.5517" rx="23.2759" fill="#01A4EF"/> +<rect x="65" y="210" width="93.1035" height="46.5517" rx="23.2759" fill="#F48022"/> +<rect x="241.896" y="210" width="93.1035" height="46.5517" rx="23.2759" fill="#0178D6"/> +<rect x="65" y="277.5" width="46.5517" height="46.5517" rx="23.2759" fill="#0178D6"/> +<rect x="241.896" y="277.5" width="93.1035" height="46.5517" rx="23.2759" fill="#E3016D"/> +</svg> + +-------------------------------------------------- +File: ./web/assets/icons/Icon_Dark_BG_Base.png +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/icons/Icon_Base.svg +-------------------------------------------------- +<svg width="400" height="400" viewBox="0 0 400 400" fill="none" xmlns="http://www.w3.org/2000/svg"> +<rect width="400" height="400" fill="white"/> +<rect x="65" y="75" width="93.1035" height="46.5517" rx="23.2759" fill="#E3016D"/> +<rect x="176.725" y="75" width="93.1035" height="46.5517" rx="23.2759" fill="#01A4EF"/> +<rect x="288.448" y="75" width="46.5517" height="46.5517" rx="23.2759" fill="#0178D6"/> +<rect x="130.173" y="142.5" width="93.1035" height="46.5517" rx="23.2759" fill="#01A4EF"/> +<rect x="65" y="210" width="93.1035" height="46.5517" rx="23.2759" fill="#F48022"/> +<rect x="241.896" y="210" width="93.1035" height="46.5517" rx="23.2759" fill="#0178D6"/> +<rect x="65" y="277.5" width="46.5517" height="46.5517" rx="23.2759" fill="#0178D6"/> +<rect x="241.896" y="277.5" width="93.1035" height="46.5517" rx="23.2759" fill="#E3016D"/> +</svg> + +-------------------------------------------------- +File: ./web/assets/icons/Icon_Dark_BG.png +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/icons/Square_Logo.png +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/icons/Slide_E.png +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/icons/Icon_Dark_BG.svg +-------------------------------------------------- +<svg width="400" height="400" viewBox="0 0 400 400" fill="none" xmlns="http://www.w3.org/2000/svg"> +<rect width="400" height="400" rx="100" fill="#001627"/> +<rect x="65" y="75" width="93.1035" height="46.5517" rx="23.2759" fill="#E3016D"/> +<rect x="176.725" y="75" width="93.1035" height="46.5517" rx="23.2759" fill="#01A4EF"/> +<rect x="288.448" y="75" width="46.5517" height="46.5517" rx="23.2759" fill="white"/> +<rect x="130.173" y="142.5" width="93.1035" height="46.5517" rx="23.2759" fill="#01A4EF"/> +<rect x="65" y="210" width="93.1035" height="46.5517" rx="23.2759" fill="#F48022"/> +<rect x="241.896" y="210" width="93.1035" height="46.5517" rx="23.2759" fill="white"/> +<rect x="65" y="277.5" width="46.5517" height="46.5517" rx="23.2759" fill="white"/> +<rect x="241.896" y="277.5" width="93.1035" height="46.5517" rx="23.2759" fill="#E3016D"/> +</svg> + +-------------------------------------------------- +File: ./web/assets/icons/Icon_Dark_BG_Base.svg +-------------------------------------------------- +<svg width="400" height="400" viewBox="0 0 400 400" fill="none" xmlns="http://www.w3.org/2000/svg"> +<rect width="400" height="400" fill="#001627"/> +<rect x="65" y="75" width="93.1035" height="46.5517" rx="23.2759" fill="#E3016D"/> +<rect x="176.725" y="75" width="93.1035" height="46.5517" rx="23.2759" fill="#01A4EF"/> +<rect x="288.448" y="75" width="46.5517" height="46.5517" rx="23.2759" fill="white"/> +<rect x="130.173" y="142.5" width="93.1035" height="46.5517" rx="23.2759" fill="#01A4EF"/> +<rect x="65" y="210" width="93.1035" height="46.5517" rx="23.2759" fill="#F48022"/> +<rect x="241.896" y="210" width="93.1035" height="46.5517" rx="23.2759" fill="white"/> +<rect x="65" y="277.5" width="46.5517" height="46.5517" rx="23.2759" fill="white"/> +<rect x="241.896" y="277.5" width="93.1035" height="46.5517" rx="23.2759" fill="#E3016D"/> +</svg> + +-------------------------------------------------- +File: ./web/assets/icons/emblem-dark-bg.svg +-------------------------------------------------- +<svg xmlns="http://www.w3.org/2000/svg" width="81" height="75" fill="none" viewBox="0 0 81 75"><rect width="27.809" height="13.904" fill="#E3016D" rx="6.952"/><rect width="27.809" height="13.904" x="33.371" fill="#01A4EF" rx="6.952"/><rect width="13.904" height="13.904" x="66.741" fill="#fff" rx="6.952"/><rect width="27.809" height="13.904" x="19.466" y="20.161" fill="#01A4EF" rx="6.952"/><rect width="27.809" height="13.904" y="40.323" fill="#F48022" rx="6.952"/><rect width="27.809" height="13.904" x="52.837" y="40.323" fill="#fff" rx="6.952"/><rect width="13.904" height="13.904" y="60.484" fill="#fff" rx="6.952"/><rect width="27.809" height="13.904" x="52.837" y="60.484" fill="#E3016D" rx="6.952"/></svg> +-------------------------------------------------- +File: ./web/assets/icons/Gradient.png +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte] + +-------------------------------------------------- +File: ./web/assets/icons/emblem-light-bg.svg +-------------------------------------------------- +<svg width="81" height="75" viewBox="0 0 81 75" fill="none" xmlns="http://www.w3.org/2000/svg"> +<rect y="0.611572" width="27.8088" height="13.9044" rx="6.9522" fill="#E3016D"/> +<rect x="33.3706" y="0.611572" width="27.8088" height="13.9044" rx="6.9522" fill="#01A4EF"/> +<rect x="66.7412" y="0.611572" width="13.9044" height="13.9044" rx="6.9522" fill="#0178D6"/> +<rect x="19.4663" y="20.7729" width="27.8088" height="13.9044" rx="6.9522" fill="#01A4EF"/> +<rect y="40.9343" width="27.8088" height="13.9044" rx="6.9522" fill="#F48022"/> +<rect x="52.8369" y="40.9343" width="27.8088" height="13.9044" rx="6.9522" fill="#0178D6"/> +<rect y="61.0957" width="13.9044" height="13.9044" rx="6.9522" fill="#0178D6"/> +<rect x="52.8369" y="61.0957" width="27.8088" height="13.9044" rx="6.9522" fill="#E3016D"/> +</svg> + +-------------------------------------------------- +File: ./web/assets/icons/Circular.png +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte] + +-------------------------------------------------- + +Directory: assets/js +================================================== +File: ./web/assets/js/api-client.js +-------------------------------------------------- +/** + * DNAnalyzer API Client + * + * This module provides functions to interact with the DNAnalyzer API endpoints. + * It enables the website to access the core DNAnalyzer features through a unified interface. + * + * @version 1.0.0 + */ + +const DNAnalyzerAPI = { + // Base URL for API requests - configurable for different environments + baseUrl: 'http://localhost:8080/api/v1', + + /** + * Set the base URL for the API + * @param {string} url - The base URL for the API + */ + setBaseUrl(url) { + this.baseUrl = url; + }, + + /** + * Check if the API is online + * @returns {Promise<Object>} - API status information + */ + async checkStatus() { + try { + const response = await fetch(`${this.baseUrl}/status`); + if (!response.ok) { + throw new Error('API status check failed'); + } + return await response.json(); + } catch (error) { + console.error('API status check error:', error); + throw error; + } + }, + + /** + * Analyze a DNA file with various options + * @param {File} dnaFile - The DNA file to analyze + * @param {Object} options - Analysis options + * @returns {Promise<Object>} - Analysis results + */ + async analyzeDNA(dnaFile, options = {}) { + try { + const formData = new FormData(); + formData.append('dnaFile', dnaFile); + + // Add options to form data + if (options.amino) formData.append('amino', options.amino); + if (options.minCount) formData.append('minCount', options.minCount); + if (options.maxCount) formData.append('maxCount', options.maxCount); + if (options.reverse) formData.append('reverse', options.reverse); + if (options.rcomplement) formData.append('rcomplement', options.rcomplement); + if (options.codons) formData.append('codons', options.codons); + if (options.coverage) formData.append('coverage', options.coverage); + if (options.longest) formData.append('longest', options.longest); + if (options.format) formData.append('format', options.format); + + const response = await fetch(`${this.baseUrl}/analyze`, { + method: 'POST', + body: formData + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(errorData.message || 'DNA analysis failed'); + } + + // Handle different response formats + const contentType = response.headers.get('content-type'); + if (contentType && contentType.includes('application/json')) { + return await response.json(); + } else { + return await response.text(); + } + } catch (error) { + console.error('DNA analysis error:', error); + throw error; + } + }, + + /** + * Analyze base pair composition of a DNA sequence + * @param {string} sequence - The DNA sequence + * @returns {Promise<Object>} - Base pair analysis results + */ + async analyzeBasePairs(sequence) { + try { + const response = await fetch(`${this.baseUrl}/base-pairs`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ sequence }) + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(errorData.message || 'Base pair analysis failed'); + } + + return await response.json(); + } catch (error) { + console.error('Base pair analysis error:', error); + throw error; + } + }, + + /** + * Find proteins in a DNA sequence + * @param {string} sequence - The DNA sequence + * @param {string} aminoAcid - The amino acid to start proteins with + * @returns {Promise<Object>} - Protein analysis results + */ + async findProteins(sequence, aminoAcid = 'M') { + try { + const response = await fetch(`${this.baseUrl}/find-proteins`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + sequence, + aminoAcid + }) + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(errorData.message || 'Protein finding failed'); + } + + return await response.json(); + } catch (error) { + console.error('Protein finding error:', error); + throw error; + } + }, + + /** + * Analyze reading frames in a DNA sequence + * @param {string} sequence - The DNA sequence + * @param {number} minLength - Minimum length for potential genes + * @returns {Promise<Object>} - Reading frame analysis results + */ + async analyzeReadingFrames(sequence, minLength = 300) { + try { + const response = await fetch(`${this.baseUrl}/reading-frames`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + sequence, + minLength + }) + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(errorData.message || 'Reading frame analysis failed'); + } + + return await response.json(); + } catch (error) { + console.error('Reading frame analysis error:', error); + throw error; + } + }, + + /** + * Analyze genetic testing data (23andMe, AncestryDNA, etc.) + * @param {File} geneticFile - The genetic data file + * @param {boolean} snpAnalysis - Whether to include detailed SNP analysis + * @returns {Promise<Object>} - Genetic analysis results + */ + async analyzeGeneticData(geneticFile, snpAnalysis = false) { + try { + const formData = new FormData(); + formData.append('geneticFile', geneticFile); + formData.append('snpAnalysis', snpAnalysis); + + const response = await fetch(`${this.baseUrl}/analyze-genetic`, { + method: 'POST', + body: formData + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(errorData.message || 'Genetic data analysis failed'); + } + + return await response.json(); + } catch (error) { + console.error('Genetic data analysis error:', error); + throw error; + } + }, + + /** + * Manipulate a DNA sequence (reverse, complement) + * @param {string} sequence - The DNA sequence + * @param {boolean} reverse - Whether to reverse the sequence + * @param {boolean} complement - Whether to get the complement + * @returns {Promise<Object>} - Manipulated sequence results + */ + async manipulateDNA(sequence, reverse = false, complement = false) { + try { + const response = await fetch(`${this.baseUrl}/manipulate`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + sequence, + reverse, + complement + }) + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(errorData.message || 'DNA manipulation failed'); + } + + return await response.json(); + } catch (error) { + console.error('DNA manipulation error:', error); + throw error; + } + }, + + /** + * Parse a DNA file (FASTA, FASTQ) + * @param {File} file - The file to parse + * @returns {Promise<Object>} - Parsed DNA sequence + */ + async parseFile(file) { + try { + const formData = new FormData(); + formData.append('file', file); + + const response = await fetch(`${this.baseUrl}/parse`, { + method: 'POST', + body: formData + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(errorData.message || 'File parsing failed'); + } + + return await response.json(); + } catch (error) { + console.error('File parsing error:', error); + throw error; + } + } +}; + +// Export the API client for use in other modules +if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { + module.exports = DNAnalyzerAPI; +} else { + window.DNAnalyzerAPI = DNAnalyzerAPI; +} +-------------------------------------------------- + +Directory: assets/videos +================================================== +File: ./web/assets/videos/dna_spiral.mp4 +-------------------------------------------------- +[Could not read file: 'utf-8' codec can't decode byte 0x9b in position 35: invalid start byte] + +-------------------------------------------------- + +Directory: features +================================================== +File: ./web/features/features.css +-------------------------------------------------- +/* Features Page Styles */ + +/* Hero section */ +.features-hero { + padding: 140px 0 80px; + position: relative; + text-align: center; +} + +.features-hero-content h1 { + font-size: 3.5rem; + margin-bottom: var(--space-md); +} + +.features-hero-content p { + font-size: 1.2rem; + max-width: 700px; + margin: 0 auto; + color: rgba(255, 255, 255, 0.8); +} + +/* Feature highlights */ +.feature-highlights { + padding-top: var(--space-xxl); +} + +.features-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: var(--space-xl); +} + +.feature-card { + background: rgba(255, 255, 255, 0.05); + border-radius: var(--radius-lg); + padding: var(--space-xl); + border: 1px solid rgba(255, 255, 255, 0.1); + transition: all var(--transition-normal); + height: 100%; + display: flex; + flex-direction: column; +} + +.feature-card:hover { + transform: translateY(-5px); + background: rgba(255, 255, 255, 0.08); + box-shadow: var(--shadow-md); + border-color: rgba(255, 255, 255, 0.15); +} + +.feature-card .feature-icon { + width: 60px; + height: 60px; + background: linear-gradient(135deg, rgba(255, 0, 102, 0.15), rgba(0, 164, 239, 0.15)); + border-radius: var(--radius-md); + display: flex; + align-items: center; + justify-content: center; + font-size: 1.5rem; + color: var(--blue); + margin-bottom: var(--space-md); +} + +.feature-card h3 { + font-size: 1.3rem; + margin-bottom: var(--space-sm); + color: var(--white); +} + +.feature-card p { + color: rgba(255, 255, 255, 0.7); + flex: 1; + margin-bottom: var(--space-md); +} + +.feature-link { + display: inline-flex; + align-items: center; + gap: var(--space-xs); + color: var(--blue); + font-weight: 500; + font-size: 0.95rem; + transition: all var(--transition-fast); +} + +.feature-link i { + transition: all var(--transition-fast); +} + +.feature-link:hover { + color: var(--light-blue); +} + +.feature-link:hover i { + transform: translateX(var(--space-xs)); +} + +/* Detailed feature sections */ +.section-detailed { + padding: var(--space-xxl) 0; +} + +.feature-section-odd { + background: linear-gradient(135deg, rgba(5, 30, 62, 0.7), rgba(0, 20, 39, 0.7)); +} + +.feature-detailed { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--space-xxl); + align-items: center; +} + +.feature-detailed.reverse { + grid-template-columns: 1fr 1fr; + direction: rtl; +} + +.feature-detailed.reverse .feature-content { + direction: ltr; +} + +.feature-image { + position: relative; +} + +.feature-image-wrapper { + position: relative; + overflow: hidden; + border-radius: var(--radius-lg); + box-shadow: var(--shadow-lg); + background: linear-gradient(135deg, rgba(255, 0, 102, 0.1), rgba(0, 164, 239, 0.1)); + padding: var(--space-sm); + height: 0; + padding-bottom: 70%; + display: flex; + align-items: center; + justify-content: center; +} + +.feature-image-wrapper::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(135deg, rgba(255, 0, 102, 0.05), rgba(0, 164, 239, 0.05)); + z-index: 0; +} + +.feature-image-wrapper img { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + object-fit: cover; + object-position: center; + transition: all var(--transition-normal); +} + +.feature-content h2 { + font-size: 2.5rem; + margin-bottom: var(--space-md); + color: var(--white); +} + +.feature-content > p { + font-size: 1.1rem; + color: rgba(255, 255, 255, 0.8); + margin-bottom: var(--space-lg); +} + +.feature-list { + list-style: none; + padding: 0; + margin: 0 0 var(--space-xl) 0; +} + +.feature-list li { + display: flex; + margin-bottom: var(--space-lg); + gap: var(--space-md); +} + +.feature-list li i { + color: var(--blue); + font-size: 1.2rem; + flex-shrink: 0; + margin-top: 0.2rem; +} + +.feature-list li div h4 { + margin: 0 0 var(--space-xs) 0; + font-size: 1.1rem; + color: var(--white); +} + +.feature-list li div p { + margin: 0; + color: rgba(255, 255, 255, 0.7); +} + +/* Comparison table */ +.comparison-section { + background: var(--dark-blue); + padding: var(--space-xxl) 0; +} + +.comparison-table-container { + overflow-x: auto; + margin-top: var(--space-xl); +} + +.comparison-table { + width: 100%; + border-collapse: collapse; + color: var(--white); +} + +.comparison-table th, +.comparison-table td { + padding: var(--space-md) var(--space-lg); + text-align: left; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.comparison-table th { + background: rgba(0, 0, 0, 0.2); + font-weight: 600; + color: var(--blue); +} + +.comparison-table tr:hover td { + background: rgba(255, 255, 255, 0.05); +} + +.comparison-table td:nth-child(1) { + font-weight: 500; +} + +.check-icon { + color: var(--success); + margin-right: var(--space-xs); +} + +.x-icon { + color: var(--error); + margin-right: var(--space-xs); +} + +.minus-icon { + color: var(--warning); + margin-right: var(--space-xs); +} + +/* Testimonials */ +.testimonials-section { + padding: var(--space-xxl) 0; +} + +.testimonials-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: var(--space-xl); + margin-top: var(--space-xl); +} + +.testimonial-card { + background: rgba(255, 255, 255, 0.05); + border-radius: var(--radius-lg); + padding: var(--space-xl); + border: 1px solid rgba(255, 255, 255, 0.1); + transition: all var(--transition-normal); + height: 100%; + display: flex; + flex-direction: column; +} + +.testimonial-card:hover { + transform: translateY(-5px); + background: rgba(255, 255, 255, 0.08); + box-shadow: var(--shadow-md); + border-color: rgba(255, 255, 255, 0.15); +} + +.testimonial-content { + flex: 1; +} + +.testimonial-content p { + font-style: italic; + color: rgba(255, 255, 255, 0.85); + font-size: 1.05rem; + line-height: 1.6; + position: relative; + padding: 0 var(--space-sm); +} + +.testimonial-content p::before, +.testimonial-content p::after { + content: '"'; + color: var(--blue); + font-size: 1.5rem; + font-weight: 700; + position: absolute; +} + +.testimonial-content p::before { + left: -var(--space-xs); + top: -var(--space-xs); +} + +.testimonial-content p::after { + right: -var(--space-xs); + bottom: 0; +} + +.testimonial-author { + display: flex; + align-items: center; + margin-top: var(--space-md); + padding-top: var(--space-md); + border-top: 1px solid rgba(255, 255, 255, 0.1); +} + +.author-info h4 { + margin: 0 0 var(--space-xs) 0; + font-size: 1rem; + color: var(--white); +} + +.author-info p { + margin: 0; + font-size: 0.85rem; + color: rgba(255, 255, 255, 0.6); +} + +/* CTA Section */ +.cta-section { + background: linear-gradient(135deg, rgba(255, 0, 102, 0.1), rgba(0, 164, 239, 0.1)); + padding: var(--space-xxl) 0; + text-align: center; +} + +.cta-section h2 { + font-size: 2.5rem; + margin-bottom: var(--space-md); + color: var(--white); +} + +.cta-section p { + font-size: 1.2rem; + color: rgba(255, 255, 255, 0.8); + margin-bottom: var(--space-xl); + max-width: 700px; + margin-left: auto; + margin-right: auto; +} + +.cta-buttons { + display: flex; + gap: var(--space-md); + justify-content: center; +} + +/* Animation for fade-in elements */ +[data-aos] { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.8s ease, transform 0.8s ease; +} + +[data-aos].aos-animate { + opacity: 1; + transform: translateY(0); +} + +[data-aos-delay="100"] { + transition-delay: 0.1s; +} + +[data-aos-delay="200"] { + transition-delay: 0.2s; +} + +/* Responsive styles */ +@media (max-width: 1024px) { + .feature-detailed, + .feature-detailed.reverse { + grid-template-columns: 1fr; + gap: var(--space-xl); + direction: ltr; + } + + .feature-content h2 { + font-size: 2rem; + } + + .cta-buttons { + flex-direction: column; + max-width: 300px; + margin: 0 auto; + } +} + +@media (max-width: 768px) { + .features-hero-content h1 { + font-size: 2.5rem; + } + + .features-grid { + grid-template-columns: 1fr; + } + + .testimonials-grid { + grid-template-columns: 1fr; + } + + .feature-image-wrapper { + padding-bottom: 60%; + } +} + +@media (max-width: 480px) { + .features-hero-content h1 { + font-size: 2rem; + } + + .features-hero-content p { + font-size: 1rem; + } + + .feature-content h2 { + font-size: 1.75rem; + } + + .feature-list li { + flex-direction: column; + gap: var(--space-xs); + } + + .comparison-table th, + .comparison-table td { + padding: var(--space-sm); + } +} +-------------------------------------------------- +File: ./web/features/features.html +-------------------------------------------------- +<!DOCTYPE html> +<html lang="en"> + +<head> + <!-- Google tag (gtag.js) --> + <script async src="https://www.googletagmanager.com/gtag/js?id=G-0LTP0WK7EM"></script> + <script> + window.dataLayer = window.dataLayer || []; + function gtag() { dataLayer.push(arguments); } + gtag('js', new Date()); + + gtag('config', 'G-0LTP0WK7EM'); + </script> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Features - DNAnalyzer</title> + <meta name="description" + content="Explore DNAnalyzer's advanced features for DNA sequence analysis, including codon detection, high coverage analysis, and more."> + + <!-- Stylesheets --> + <link rel="stylesheet" href="../style.css"> + <link rel="stylesheet" href="features.css"> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.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@300;400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap" + rel="stylesheet"> + + <!-- Favicon --> + <link rel="shortcut icon" href="../assets/icons/Icon_Dark_BG.svg" type="image/svg+xml"> +</head> + +<body> + <!-- Background effects --> + <div class="bg-gradient"> + <div class="bg-blob bg-blob-1"></div> + <div class="bg-blob bg-blob-2"></div> + </div> + + <div class="notification-banner"> + <span>Exclusive WSSEF Preview: </span> + <span> Transformer Architecture in Epigenomics!</span> + <a href="https://epiclassify.dnanalyzer.org" target="_blank" class="notification-link">Explore Now</a> + <button class="notification-close" aria-label="Dismiss notification"></button> + </div> + + <!-- Navbar --> + <nav class="navbar" id="navbar"> + <div class="container navbar-container"> + <a href="../index.html" class="logo"> + <img src="../assets/icons/Icon_Dark_BG.svg" alt="DNAnalyzer Logo"> + <span class="logo-text">DNAnalyzer</span> + </a> + + <button class="mobile-toggle" id="mobileToggle" aria-label="Toggle navigation"> + <i class="fas fa-bars"></i> + </button> + + <ul class="nav-links" id="navLinks"> + <li><a href="../index.html">Home</a></li> + <li><a href="features.html" class="active">Features</a></li> + <li><a href="../analyzer/analyzer.html">Analyzer</a></li> + <li><a href="../server/server.html">Server</a></li> + <li><a href="../docs/docs.html">Docs</a></li> + <li><a href="../about/about.html">About</a></li> + </ul> + + <div class="nav-buttons"> + <a href="https://github.com/VerisimilitudeX/DNAnalyzer" class="btn btn-secondary btn-sm"> + <i class="fab fa-github btn-icon"></i> GitHub + </a> + </div> + </div> + </nav> + + <!-- Main Content --> + <main> + <section class="features-hero"> + <div class="container"> + <div class="features-hero-content"> + <h1>DNAnalyzer <span class="gradient-text">Features</span></h1> + <p>Advanced DNA analysis capabilities powered by machine learning, designed for researchers, + educators, and enthusiasts.</p> + </div> + </div> + </section> + + <section class="section feature-highlights"> + <div class="container"> + <div class="section-title"> + <h2>Key Capabilities</h2> + <p>Our comprehensive suite of DNA analysis tools provides insights from basic sequence statistics to + advanced protein prediction</p> + </div> + + <div class="features-grid"> + <div class="feature-card" data-aos="fade-up"> + <div class="feature-icon"> + <i class="fas fa-microscope"></i> + </div> + <h3>Sequence Analysis</h3> + <p>Get detailed statistics about your DNA sequence, including length, GC content, and nucleotide + composition with intuitive visualizations.</p> + <a href="#sequence-analysis" class="feature-link">Learn more <i + class="fas fa-arrow-right"></i></a> + </div> + + <div class="feature-card" data-aos="fade-up" data-aos-delay="100"> + <div class="feature-icon"> + <i class="fas fa-dna"></i> + </div> + <h3>Codon Detection</h3> + <p>Identify start and stop codons across your sequence to locate potential protein-coding + regions with high precision.</p> + <a href="#codon-detection" class="feature-link">Learn more <i + class="fas fa-arrow-right"></i></a> + </div> + + <div class="feature-card" data-aos="fade-up" data-aos-delay="200"> + <div class="feature-icon"> + <i class="fas fa-project-diagram"></i> + </div> + <h3>Reading Frames</h3> + <p>Analyze all six reading frames to identify potential protein-coding regions and open reading + frames (ORFs).</p> + <a href="#reading-frames" class="feature-link">Learn more <i class="fas fa-arrow-right"></i></a> + </div> + + <div class="feature-card" data-aos="fade-up"> + <div class="feature-icon"> + <i class="fas fa-chart-bar"></i> + </div> + <h3>Coverage Analysis</h3> + <p>Identify high-coverage (GC-rich) regions, often associated with gene-dense areas and promoter + regions.</p> + <a href="#coverage-analysis" class="feature-link">Learn more <i + class="fas fa-arrow-right"></i></a> + </div> + + <div class="feature-card" data-aos="fade-up" data-aos-delay="100"> + <div class="feature-icon"> + <i class="fas fa-prescription"></i> + </div> + <h3>Protein Prediction</h3> + <p>Predict potential proteins from your DNA sequence and analyze their amino acid composition. + </p> + <a href="#protein-prediction" class="feature-link">Learn more <i + class="fas fa-arrow-right"></i></a> + </div> + + <div class="feature-card" data-aos="fade-up" data-aos-delay="200"> + <div class="feature-icon"> + <i class="fas fa-server"></i> + </div> + <h3>Local Server</h3> + <p>Deploy DNAnalyzer as a local server for secure, high-throughput analysis of sensitive genomic + data.</p> + <a href="#local-server" class="feature-link">Learn more <i class="fas fa-arrow-right"></i></a> + </div> + </div> + </div> + </section> + + <section id="sequence-analysis" class="section section-detailed feature-section-odd"> + <div class="container"> + <div class="feature-detailed"> + <div class="feature-image" data-aos="fade-right"> + <div class="feature-image-wrapper"> + <img src="../assets/screenshots/sequence-analysis.png" alt="Sequence Analysis" + onerror="this.src='../assets/icons/Icon_Dark_BG.svg'"> + </div> + </div> + <div class="feature-content" data-aos="fade-left"> + <h2>Sequence Analysis</h2> + <p>Our basic sequence analysis tools give you immediate insights into your DNA sequence + properties.</p> + + <ul class="feature-list"> + <li> + <i class="fas fa-check-circle"></i> + <div> + <h4>Base Composition</h4> + <p>Interactive visualization of nucleotide distribution with precise percentages</p> + </div> + </li> + <li> + <i class="fas fa-check-circle"></i> + <div> + <h4>GC Content Calculation</h4> + <p>Identify regions with high GC content, important for gene density and stability + </p> + </div> + </li> + <li> + <i class="fas fa-check-circle"></i> + <div> + <h4>Sequence Length Analysis</h4> + <p>Get exact measurements of your DNA sequence with support for very large genomes + </p> + </div> + </li> + </ul> + + <a href="../analyzer/analyzer.html" class="btn btn-primary">Try Sequence Analysis</a> + </div> + </div> + </div> + </section> + + <section id="codon-detection" class="section section-detailed feature-section-even"> + <div class="container"> + <div class="feature-detailed reverse"> + <div class="feature-image" data-aos="fade-left"> + <div class="feature-image-wrapper"> + <img src="../assets/screenshots/codon-detection.png" alt="Codon Detection" + onerror="this.src='../assets/icons/Icon_Dark_BG.svg'"> + </div> + </div> + <div class="feature-content" data-aos="fade-right"> + <h2>Codon Detection</h2> + <p>Identify critical codon patterns in your DNA sequence with our advanced detection algorithms. + </p> + + <ul class="feature-list"> + <li> + <i class="fas fa-check-circle"></i> + <div> + <h4>Start Codon Identification</h4> + <p>Automatically detect ATG start codons that initiate protein translation</p> + </div> + </li> + <li> + <i class="fas fa-check-circle"></i> + <div> + <h4>Stop Codon Recognition</h4> + <p>Find all TAA, TAG, and TGA stop codons that terminate protein synthesis</p> + </div> + </li> + <li> + <i class="fas fa-check-circle"></i> + <div> + <h4>Codon Frequency Analysis</h4> + <p>Analyze codon usage patterns across your sequence to identify potential gene + regions</p> + </div> + </li> + </ul> + + <a href="../analyzer/analyzer.html" class="btn btn-primary">Try Codon Detection</a> + </div> + </div> + </div> + </section> + + <section id="reading-frames" class="section section-detailed feature-section-odd"> + <div class="container"> + <div class="feature-detailed"> + <div class="feature-image" data-aos="fade-right"> + <div class="feature-image-wrapper"> + <img src="../assets/screenshots/reading-frames.png" alt="Reading Frames" + onerror="this.src='../assets/icons/Icon_Dark_BG.svg'"> + </div> + </div> + <div class="feature-content" data-aos="fade-left"> + <h2>Reading Frames Analysis</h2> + <p>Comprehensive analysis of all six reading frames to identify potential genes and coding + regions.</p> + + <ul class="feature-list"> + <li> + <i class="fas fa-check-circle"></i> + <div> + <h4>Six-Frame Translation</h4> + <p>Analyze three forward and three reverse reading frames simultaneously</p> + </div> + </li> + <li> + <i class="fas fa-check-circle"></i> + <div> + <h4>Open Reading Frame (ORF) Detection</h4> + <p>Identify complete ORFs from start to stop codons across all frames</p> + </div> + </li> + <li> + <i class="fas fa-check-circle"></i> + <div> + <h4>Gene Prediction</h4> + <p>Find potential genes based on ORF length and composition characteristics</p> + </div> + </li> + </ul> + + <a href="../analyzer/analyzer.html" class="btn btn-primary">Try Reading Frames Analysis</a> + </div> + </div> + </div> + </section> + + <section id="coverage-analysis" class="section section-detailed feature-section-even"> + <div class="container"> + <div class="feature-detailed reverse"> + <div class="feature-image" data-aos="fade-left"> + <div class="feature-image-wrapper"> + <img src="../assets/screenshots/coverage-analysis.png" alt="Coverage Analysis" + onerror="this.src='../assets/icons/Icon_Dark_BG.svg'"> + </div> + </div> + <div class="feature-content" data-aos="fade-right"> + <h2>Coverage Analysis</h2> + <p>Identify regions of interest with our powerful coverage analysis tools to spot regulatory + elements and gene-dense areas.</p> + + <ul class="feature-list"> + <li> + <i class="fas fa-check-circle"></i> + <div> + <h4>GC-Rich Region Detection</h4> + <p>Find CpG islands and GC-rich regions often associated with gene promoters</p> + </div> + </li> + <li> + <i class="fas fa-check-circle"></i> + <div> + <h4>Promoter Element Identification</h4> + <p>Detect TATA boxes, BRE, INR, and DPE motifs that indicate promoter regions</p> + </div> + </li> + <li> + <i class="fas fa-check-circle"></i> + <div> + <h4>Visualization Tools</h4> + <p>Graphical representation of coverage across your sequence for easy interpretation + </p> + </div> + </li> + </ul> + + <a href="../analyzer/analyzer.html" class="btn btn-primary">Try Coverage Analysis</a> + </div> + </div> + </div> + </section> + + <section id="protein-prediction" class="section section-detailed feature-section-odd"> + <div class="container"> + <div class="feature-detailed"> + <div class="feature-image" data-aos="fade-right"> + <div class="feature-image-wrapper"> + <img src="../assets/screenshots/protein-prediction.png" alt="Protein Prediction" + onerror="this.src='../assets/icons/Icon_Dark_BG.svg'"> + </div> + </div> + <div class="feature-content" data-aos="fade-left"> + <h2>Protein Prediction</h2> + <p>Translate DNA sequences into proteins and analyze their properties with our advanced + prediction tools.</p> + + <ul class="feature-list"> + <li> + <i class="fas fa-check-circle"></i> + <div> + <h4>ORF Translation</h4> + <p>Convert open reading frames to amino acid sequences using the standard genetic + code</p> + </div> + </li> + <li> + <i class="fas fa-check-circle"></i> + <div> + <h4>Protein Length Filtering</h4> + <p>Focus on proteins of significant length to identify functional gene products</p> + </div> + </li> + <li> + <i class="fas fa-check-circle"></i> + <div> + <h4>Amino Acid Composition</h4> + <p>Analyze the distribution of amino acids within predicted proteins</p> + </div> + </li> + </ul> + + <a href="../analyzer/analyzer.html" class="btn btn-primary">Try Protein Prediction</a> + </div> + </div> + </div> + </section> + + <section id="local-server" class="section section-detailed feature-section-even"> + <div class="container"> + <div class="feature-detailed reverse"> + <div class="feature-image" data-aos="fade-left"> + <div class="feature-image-wrapper"> + <img src="../assets/screenshots/local-server.png" alt="Local Server" + onerror="this.src='../assets/icons/Icon_Dark_BG.svg'"> + </div> + </div> + <div class="feature-content" data-aos="fade-right"> + <h2>Local Server Deployment</h2> + <p>Run DNAnalyzer as a local server for secure, high-throughput analysis of sensitive genomic + data.</p> + + <ul class="feature-list"> + <li> + <i class="fas fa-check-circle"></i> + <div> + <h4>Privacy-Focused Analysis</h4> + <p>Keep sensitive genetic data on your own infrastructure with no external data + transfer</p> + </div> + </li> + <li> + <i class="fas fa-check-circle"></i> + <div> + <h4>High-Performance Processing</h4> + <p>Optimized for multi-core systems to handle large datasets and batch processing + </p> + </div> + </li> + <li> + <i class="fas fa-check-circle"></i> + <div> + <h4>API Integration</h4> + <p>RESTful API for seamless integration with your existing bioinformatics pipelines + </p> + </div> + </li> + </ul> + + <a href="../server/server.html" class="btn btn-primary">Learn About Server Setup</a> + </div> + </div> + </div> + </section> + + <section class="section comparison-section"> + <div class="container"> + <div class="section-title"> + <h2>Why Choose DNAnalyzer?</h2> + <p>See how DNAnalyzer compares to traditional DNA analysis tools</p> + </div> + + <div class="comparison-table-container" data-aos="fade-up"> + <table class="comparison-table"> + <thead> + <tr> + <th>Feature</th> + <th>DNAnalyzer</th> + <th>Traditional Tools</th> + </tr> + </thead> + <tbody> + <tr> + <td>User Interface</td> + <td><i class="fas fa-check-circle check-icon"></i> Modern web interface</td> + <td><i class="fas fa-times-circle x-icon"></i> Often command-line only</td> + </tr> + <tr> + <td>Privacy</td> + <td><i class="fas fa-check-circle check-icon"></i> On-device processing</td> + <td><i class="fas fa-times-circle x-icon"></i> May require server upload</td> + </tr> + <tr> + <td>Machine Learning</td> + <td><i class="fas fa-check-circle check-icon"></i> Advanced ML algorithms</td> + <td><i class="fas fa-times-circle x-icon"></i> Often rule-based only</td> + </tr> + <tr> + <td>Setup Complexity</td> + <td><i class="fas fa-check-circle check-icon"></i> Simple, instant setup</td> + <td><i class="fas fa-times-circle x-icon"></i> Complex dependencies</td> + </tr> + <tr> + <td>Visualization</td> + <td><i class="fas fa-check-circle check-icon"></i> Interactive graphics</td> + <td><i class="fas fa-times-circle x-icon"></i> Often text-only output</td> + </tr> + <tr> + <td>Multiple File Support</td> + <td><i class="fas fa-check-circle check-icon"></i> FASTA, FASTQ, plain text</td> + <td><i class="fas fa-check-circle check-icon"></i> Various formats</td> + </tr> + <tr> + <td>Cost</td> + <td><i class="fas fa-check-circle check-icon"></i> Free, open-source</td> + <td><i class="fas fa-minus-circle minus-icon"></i> Often commercial</td> + </tr> + </tbody> + </table> + </div> + </div> + </section> + + <section class="section testimonials-section"> + <div class="container"> + <div class="section-title"> + <h2>What Our Users Say</h2> + <p>Hear from researchers and educators who use DNAnalyzer</p> + </div> + + <div class="testimonials-grid"> + <div class="testimonial-card" data-aos="fade-up"> + <div class="testimonial-content"> + <p>"DNAnalyzer has transformed how I teach genomics to undergraduates. The visual interface + makes complex concepts accessible, and students can perform real analysis without a + steep learning curve."</p> + </div> + <div class="testimonial-author"> + <div class="author-info"> + <h4>Dr. Sarah Chen</h4> + <p>Associate Professor, Molecular Biology</p> + </div> + </div> + </div> + + <div class="testimonial-card" data-aos="fade-up" data-aos-delay="100"> + <div class="testimonial-content"> + <p>"As a researcher focusing on genetic disorders, I appreciate DNAnalyzer's privacy-first + approach. The local server option allows me to analyze sensitive patient data without + exposing it to third parties."</p> + </div> + <div class="testimonial-author"> + <div class="author-info"> + <h4>Dr. Michael Rodriguez</h4> + <p>Genetic Researcher</p> + </div> + </div> + </div> + + <div class="testimonial-card" data-aos="fade-up" data-aos-delay="200"> + <div class="testimonial-content"> + <p>"The ability to quickly identify promoter regions and protein-coding sequences has + accelerated my synthetic biology project significantly. DNAnalyzer is now a core part of + our design verification process."</p> + </div> + <div class="testimonial-author"> + <div class="author-info"> + <h4>Emily Takahashi</h4> + <p>Synthetic Biology Engineer</p> + </div> + </div> + </div> + </div> + </div> + </section> + + <section class="section cta-section"> + <div class="container text-center"> + <h2>Ready to start analyzing DNA sequences?</h2> + <p>Experience the power of DNAnalyzer's features today</p> + + <div class="cta-buttons"> + <a href="../analyzer/analyzer.html" class="btn btn-primary"> + <i class="fas fa-dna btn-icon"></i> Try DNAnalyzer Now + </a> + <a href="../docs/docs.html" class="btn btn-secondary"> + <i class="fas fa-book btn-icon"></i> Read Documentation + </a> + </div> + </div> + </section> + </main> + + <!-- Footer --> + <footer class="footer"> + <div class="container"> + <div class="footer-grid"> + <div class="footer-brand"> + <img src="../assets/icons/Icon_Dark_BG.svg" alt="DNAnalyzer Logo"> + <p>DNAnalyzer is a powerful, privacy-focused DNA analysis tool using cutting-edge machine learning + models for accurate, on-device genomic analysis.</p> + + <div class="footer-social"> + <a href="https://github.com/VerisimilitudeX/DNAnalyzer" class="social-link"> + <i class="fab fa-github"></i> + </a> + <a href="https://discord.gg/xNpujz49gj" class="social-link"> + <i class="fab fa-discord"></i> + </a> + <a href="https://www.twitter.com/DNAnalyzer_" class="social-link"> + <i class="fab fa-twitter"></i> + </a> + </div> + </div> + + <div class="footer-nav"> + <h4>Product</h4> + <ul> + <li><a href="features.html">Features</a></li> + <li><a href="../analyzer/analyzer.html">DNA Analyzer</a></li> + <li><a href="../server/server.html">Server</a></li> + <li><a href="../docs/docs.html">Documentation</a></li> + </ul> + </div> + + <div class="footer-nav"> + <h4>Resources</h4> + <ul> + <li><a href="../docs/getting-started.md">Getting Started</a></li> + <li><a href="../docs/citations.md">Citations</a></li> + <li><a href="../docs/research/genes.md">Gene Research</a></li> + <li><a href="../docs/samples/cli-arguments-examples.md">CLI Examples</a></li> + </ul> + </div> + + <div class="footer-nav"> + <h4>Community</h4> + <ul> + <li><a href="https://github.com/VerisimilitudeX/DNAnalyzer">GitHub</a></li> + <li><a href="https://discord.gg/xNpujz49gj">Discord</a></li> + <li><a href="../docs/contributing/CONTRIBUTING.md">Contributing</a></li> + <li><a href="../CODE_OF_CONDUCT.md">Code of Conduct</a></li> + </ul> + </div> + </div> + + <div class="footer-bottom"> + <div class="footer-copyright"> + Copyright © Piyush Acharya 2025. DNAnalyzer is a fiscally sponsored 501(c)(3) nonprofit (EIN: + 81-2908499). MIT License. + </div> + + <div class="footer-links"> + <a href="../LICENSE.md">License</a> + <a href="../SECURITY.md">Security</a> + <a href="../CITATION.cff">Citation</a> + </div> + </div> + </div> + </footer> + + <!-- JavaScript --> + <script src="features.js"></script> +</body> + +</html> +-------------------------------------------------- +File: ./web/features/features.js +-------------------------------------------------- +/** + * DNAnalyzer - Features Page JavaScript + * Handles animations, scroll events and interactivity + */ + +document.addEventListener('DOMContentLoaded', function() { + // Initialize navbar + initializeNavbar(); + + // Initialize animations + initializeAnimations(); + + // Initialize smooth scrolling + initializeSmoothScroll(); +}); + +/** + * Initialize navbar functionality + */ +function initializeNavbar() { + const navbar = document.getElementById('navbar'); + const mobileToggle = document.getElementById('mobileToggle'); + const navLinks = document.getElementById('navLinks'); + + // Handle scroll event to change navbar style + window.addEventListener('scroll', function() { + if (window.scrollY > 50) { + navbar.classList.add('scrolled'); + } else { + navbar.classList.remove('scrolled'); + } + }); + + // Handle mobile menu toggle + if (mobileToggle && navLinks) { + mobileToggle.addEventListener('click', function() { + navLinks.classList.toggle('active'); + + // Change the icon based on the state + const icon = mobileToggle.querySelector('i'); + if (navLinks.classList.contains('active')) { + icon.classList.remove('fa-bars'); + icon.classList.add('fa-times'); + } else { + icon.classList.remove('fa-times'); + icon.classList.add('fa-bars'); + } + }); + + // Close mobile menu when clicking a link + const links = navLinks.querySelectorAll('a'); + links.forEach(link => { + link.addEventListener('click', function() { + navLinks.classList.remove('active'); + const icon = mobileToggle.querySelector('i'); + icon.classList.remove('fa-times'); + icon.classList.add('fa-bars'); + }); + }); + } +} + +/** + * Initialize animations for elements + */ +function initializeAnimations() { + // Get all elements with data-aos attribute + const animatedElements = document.querySelectorAll('[data-aos]'); + + // Create Intersection Observer for animations + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('aos-animate'); + observer.unobserve(entry.target); + } + }); + }, { + threshold: 0.1, + rootMargin: '0px 0px -100px 0px' + }); + + // Observe all animated elements + animatedElements.forEach(element => { + observer.observe(element); + }); + + // Add parallax effect to feature images + const featureImages = document.querySelectorAll('.feature-image-wrapper'); + + window.addEventListener('scroll', () => { + featureImages.forEach(image => { + const rect = image.getBoundingClientRect(); + const isVisible = ( + rect.top <= window.innerHeight && + rect.bottom >= 0 + ); + + if (isVisible) { + const scrollPos = window.scrollY; + const imgOffset = rect.top + scrollPos; + const parallaxOffset = (scrollPos - imgOffset) * 0.1; + + // Apply parallax effect + image.querySelector('img').style.transform = `translateY(${parallaxOffset}px)`; + } + }); + }); +} + +/** + * Initialize smooth scrolling for anchor links + */ +function initializeSmoothScroll() { + document.querySelectorAll('a[href^="#"]').forEach(anchor => { + anchor.addEventListener('click', function(e) { + const targetId = this.getAttribute('href'); + + // Skip if it's just "#" or not an ID selector + if (targetId === '#' || !targetId.startsWith('#')) return; + + const targetElement = document.querySelector(targetId); + + if (targetElement) { + e.preventDefault(); + + const navbarHeight = document.querySelector('.navbar').offsetHeight; + const targetPosition = targetElement.getBoundingClientRect().top + window.pageYOffset - navbarHeight - 20; + + window.scrollTo({ + top: targetPosition, + behavior: 'smooth' + }); + } + }); + }); +} + +/** + * Add hover effects for feature cards + */ +document.querySelectorAll('.feature-card').forEach(card => { + card.addEventListener('mouseenter', function() { + const icon = this.querySelector('.feature-icon'); + if (icon) { + icon.style.transform = 'scale(1.1)'; + } + }); + + card.addEventListener('mouseleave', function() { + const icon = this.querySelector('.feature-icon'); + if (icon) { + icon.style.transform = 'scale(1)'; + } + }); +}); + +/** + * Add hover effects for comparison table rows + */ +document.querySelectorAll('.comparison-table tr').forEach(row => { + row.addEventListener('mouseenter', function() { + const cells = this.querySelectorAll('td'); + cells.forEach(cell => { + cell.style.transition = 'background-color 0.3s ease'; + }); + }); +}); + +/** + * Add animation for CTA buttons + */ +document.querySelectorAll('.cta-buttons .btn').forEach(button => { + button.addEventListener('mouseenter', function() { + this.style.transform = 'translateY(-5px)'; + }); + + button.addEventListener('mouseleave', function() { + this.style.transform = 'translateY(0)'; + }); +}); + +// Add scale effect for feature images on hover +document.querySelectorAll('.feature-image').forEach(image => { + image.addEventListener('mouseenter', function() { + const img = this.querySelector('img'); + if (img) { + img.style.transform = 'scale(1.03)'; + } + }); + + image.addEventListener('mouseleave', function() { + const img = this.querySelector('img'); + if (img) { + img.style.transform = 'scale(1)'; + } + }); +}); +-------------------------------------------------- + +Directory: hiring +================================================== +File: ./web/hiring/hiring.html +-------------------------------------------------- +<!DOCTYPE html> +<html lang="en"> + +<head> + <!-- Google tag (gtag.js) --> + <script async src="https://www.googletagmanager.com/gtag/js?id=G-0LTP0WK7EM"></script> + <script> + window.dataLayer = window.dataLayer || []; + function gtag() { dataLayer.push(arguments); } + gtag('js', new Date()); + + gtag('config', 'G-0LTP0WK7EM'); + </script> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Hiring - DNAnalyzer</title> + <link rel="stylesheet" href="../style.css"> + <link rel="stylesheet" href="hiring.css"> + <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@300;400;500;600;700&display=swap" + rel="stylesheet"> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"> + <link rel="shortcut icon" href="../assets/icons/Icon_Dark_BG.svg" type="image/svg+xml"> +</head> + +<body> + <div class="background-blur"></div> + <div class="gradient-sphere"></div> + <div class="gradient-sphere secondary"></div> + + <header class="floating-header"> + <nav class="floating-nav"> + <a href="../index.html" class="nav-link"> + <img src="../assets/icons/Icon_Base.svg" alt="DNAnalyzer Logo" class="nav-logo"> + </a> + <a href="../about/about.html" class="nav-link">About</a> + <a href="../features/features.html" class="nav-link">Features</a> + <a href="../analyzer/analyzer.html" class="nav-link">Analyzer</a> + <a href="../server/server.html" class="nav-link">Server</a> + <a href="../docs/docs.html" class="nav-link">Docs</a> + <a href="hiring.html" class="nav-link active">Hiring</a> + <div class="right-links"> + <a href="https://github.com/VerisimilitudeX/DNAnalyzer" class="glass-button">GitHub</a> + <a href="https://discord.gg/xNpujz49gj" class="glass-button">Discord</a> + </div> + </nav> + </header> + + <main class="container"> + <section class="hero"> + <h1>Join Our Team</h1> + <p>We're looking for talented individuals to help us revolutionize DNA analysis.</p> + </section> + + <section class="positions-section"> + <h2>Open Positions</h2> + <div class="positions-grid"> + <div class="position-card"> + <h3>Software Engineer</h3> + <p>Develop and maintain our DNA analysis tools and infrastructure.</p> + <a href="hiring-modal.html" class="primary-btn">Apply Now</a> + </div> + <div class="position-card"> + <h3>Data Scientist</h3> + <p>Analyze genetic data and develop machine learning models for DNA analysis.</p> + <a href="hiring-modal.html" class="primary-btn">Apply Now</a> + </div> + <div class="position-card"> + <h3>UI/UX Designer</h3> + <p>Design intuitive and engaging user interfaces for our web and mobile applications.</p> + <a href="hiring-modal.html" class="primary-btn">Apply Now</a> + </div> + </div> + </section> + + <section class="benefits-section"> + <h2>Why Work With Us?</h2> + <div class="benefits-grid"> + <div class="benefit-card"> + <i class="fas fa-rocket benefit-icon"></i> + <h3>Innovative Projects</h3> + <p>Work on cutting-edge technology and make a real impact in the field of genomics.</p> + </div> + <div class="benefit-card"> + <i class="fas fa-users benefit-icon"></i> + <h3>Collaborative Environment</h3> + <p>Join a team of passionate professionals who are dedicated to advancing DNA analysis.</p> + </div> + <div class="benefit-card"> + <i class="fas fa-heart benefit-icon"></i> + <h3>Comprehensive Benefits</h3> + <p>Enjoy competitive salaries, health insurance, and other great perks.</p> + </div> + </div> + </section> + </main> + + <footer class="footer-content"> + <div class="footer-grid"> + <div class="footer-section"> + <h3>Product</h3> + <ul> + <li><a href="../features/features.html">Features</a></li> + <li><a href="../analyzer/analyzer.html">DNA Analyzer</a></li> + <li><a href="../server/server.html">Server</a></li> + <li><a href="../docs/docs.html">Documentation</a></li> + </ul> + </div> + <div class="footer-section"> + <h3>Resources</h3> + <ul> + <li><a href="../docs/getting-started.md">Getting Started</a></li> + <li><a href="../docs/citations.md">Citations</a></li> + <li><a href="../docs/research/genes.md">Gene Research</a></li> + <li><a href="../docs/samples/cli-arguments-examples.md">CLI Examples</a></li> + </ul> + </div> + <div class="footer-section"> + <h3>Community</h3> + <ul> + <li><a href="https://github.com/VerisimilitudeX/DNAnalyzer">GitHub</a></li> + <li><a href="https://discord.gg/xNpujz49gj">Discord</a></li> + <li><a href="../docs/contributing/CONTRIBUTING.md">Contributing</a></li> + <li><a href="../CODE_OF_CONDUCT.md">Code of Conduct</a></li> + </ul> + </div> + <div class="footer-section"> + <h3>Legal</h3> + <ul> + <li><a href="../LICENSE.md">License</a></li> + <li><a href="../SECURITY.md">Security</a></li> + <li><a href="../CITATION.cff">Citation</a></li> + <li><a href="../humans.txt">Credits</a></li> + </ul> + </div> + </div> + <div class="footer-bottom"> + <p>Copyright © Piyush Acharya 2025. DNAnalyzer is a fiscally sponsored 501(c)(3) nonprofit (EIN: + 81-2908499). MIT License.</p> + </div> + </footer> + + <script src="hiring.js"></script> +</body> + +</html> +-------------------------------------------------- +File: ./web/hiring/hiring.css +-------------------------------------------------- +/* General Styles */ +body { + font-family: 'IBM Plex Mono', monospace; + background-color: #0a0c1b; + color: #ffffff; + line-height: 1.6; + margin: 0; + padding: 0; +} + +/* Container */ +.container { + max-width: 1200px; + margin: 6rem auto 2rem; + padding: 2rem; +} + +/* Hero Section */ +.hero { + text-align: center; + margin-bottom: 4rem; +} + +.hero h1 { + font-size: 3.5rem; + margin-bottom: 1.5rem; + background: linear-gradient(45deg, var(--gradient-start), var(--gradient-end)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +.hero p { + font-size: 1.2rem; + color: rgba(255, 255, 255, 0.9); + max-width: 800px; + margin: 0 auto; + line-height: 1.8; +} + +/* Positions Section */ +.positions-section { + margin: 4rem 0; + padding: 2rem; + background: rgba(0, 0, 0, 0.2); + border-radius: 12px; + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.positions-section h2 { + font-size: 2.5rem; + margin-bottom: 2rem; + text-align: center; + color: var(--gradient-end); +} + +.positions-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 2rem; + margin-top: 3rem; +} + +.position-card { + background: rgba(255, 255, 255, 0.05); + border-radius: 12px; + padding: 2rem; + text-align: center; + border: 1px solid rgba(255, 255, 255, 0.1); + transition: all 0.3s ease; +} + +.position-card:hover { + transform: translateY(-5px); + border-color: var(--gradient-end); + box-shadow: 0 4px 20px rgba(0, 122, 255, 0.2); +} + +.position-card h3 { + font-size: 1.5rem; + margin-bottom: 1rem; + color: var(--gradient-end); +} + +.position-card p { + color: rgba(255, 255, 255, 0.9); + font-size: 1rem; + line-height: 1.6; + margin-bottom: 1.5rem; +} + +.primary-btn { + background: linear-gradient(135deg, var(--gradient-start), var(--gradient-end)); + color: white; + border: none; + padding: 0.8rem 1.6rem; + border-radius: 8px; + font-size: 0.95rem; + font-weight: 500; + cursor: pointer; + transition: all 0.3s ease; + text-transform: uppercase; + letter-spacing: 1px; + min-width: 160px; + text-decoration: none; + text-align: center; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.5rem; +} + +.primary-btn:hover { + transform: translateY(-2px); + box-shadow: 0 8px 30px rgba(0, 122, 255, 0.4); + filter: brightness(1.1); +} + +/* Benefits Section */ +.benefits-section { + margin: 4rem 0; + padding: 2rem; + background: rgba(0, 0, 0, 0.2); + border-radius: 12px; + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.benefits-section h2 { + font-size: 2.5rem; + margin-bottom: 2rem; + text-align: center; + color: var(--gradient-end); +} + +.benefits-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 2rem; + margin-top: 3rem; +} + +.benefit-card { + background: rgba(255, 255, 255, 0.05); + border-radius: 12px; + padding: 2rem; + text-align: center; + border: 1px solid rgba(255, 255, 255, 0.1); + transition: all 0.3s ease; +} + +.benefit-card:hover { + transform: translateY(-5px); + border-color: var(--gradient-end); + box-shadow: 0 4px 20px rgba(0, 122, 255, 0.2); +} + +.benefit-icon { + font-size: 2.5rem; + margin-bottom: 1rem; + color: var(--gradient-end); +} + +.benefit-card h3 { + font-size: 1.5rem; + margin-bottom: 1rem; + color: var(--gradient-end); +} + +.benefit-card p { + color: rgba(255, 255, 255, 0.9); + font-size: 1rem; + line-height: 1.6; +} + +/* Responsive Design */ +@media screen and (max-width: 768px) { + .container { + margin: 4rem 1rem 2rem; + padding: 1rem; + } + + .hero h1 { + font-size: 2.5rem; + } + + .hero p { + font-size: 1.1rem; + } + + .positions-section, + .benefits-section { + padding: 1.5rem; + } + + .positions-grid, + .benefits-grid { + grid-template-columns: 1fr; + } +} + +-------------------------------------------------- +File: ./web/hiring/hiring-modal.css +-------------------------------------------------- +/* Modal Container */ +.modal-container { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.8); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + opacity: 0; + visibility: hidden; + transition: opacity 0.3s ease, visibility 0.3s ease; +} + +.modal-container.active { + opacity: 1; + visibility: visible; +} + +/* Modal Content */ +.modal-content { + background: var(--surface-color); + padding: 2rem; + border-radius: 12px; + max-width: 600px; + width: 100%; + position: relative; + box-shadow: 0 8px 32px rgba(0, 122, 255, 0.2); + border: 1px solid rgba(255, 255, 255, 0.1); + animation: slideIn 0.3s ease; +} + +@keyframes slideIn { + from { + transform: translateY(-20px); + opacity: 0; + } + to { + transform: translateY(0); + opacity: 1; + } +} + +/* Close Button */ +.close-modal { + position: absolute; + top: 1rem; + right: 1rem; + background: none; + border: none; + font-size: 1.5rem; + color: rgba(255, 255, 255, 0.7); + cursor: pointer; + transition: color 0.3s ease; +} + +.close-modal:hover { + color: rgba(255, 255, 255, 1); +} + +/* Form Styles */ +.form-group { + margin-bottom: 1.5rem; +} + +.form-group label { + display: block; + margin-bottom: 0.5rem; + color: rgba(255, 255, 255, 0.9); + font-size: 1.1rem; +} + +.form-group input, +.form-group select, +.form-group textarea { + width: 100%; + padding: 1rem; + background: rgba(0, 0, 0, 0.3); + border: 1px solid rgba(255, 255, 255, 0.2); + border-radius: 8px; + color: white; + font-size: 1rem; + font-family: 'IBM Plex Mono', monospace; +} + +.form-group input:focus, +.form-group select:focus, +.form-group textarea:focus { + outline: none; + border-color: var(--gradient-start); + box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.2); +} + +/* Submit Button */ +.primary-btn { + background: linear-gradient(135deg, var(--gradient-start), var(--gradient-end)); + color: white; + border: none; + padding: 0.8rem 1.6rem; + border-radius: 8px; + font-size: 0.95rem; + font-weight: 500; + cursor: pointer; + transition: all 0.3s ease; + text-transform: uppercase; + letter-spacing: 1px; + min-width: 160px; + text-decoration: none; + text-align: center; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.5rem; +} + +.primary-btn:hover { + transform: translateY(-2px); + box-shadow: 0 8px 30px rgba(0, 122, 255, 0.4); + filter: brightness(1.1); +} + +-------------------------------------------------- +File: ./web/hiring/hiring-modal.js +-------------------------------------------------- +document.addEventListener('DOMContentLoaded', function() { + const modalContainer = document.querySelector('.modal-container'); + const closeModalButton = document.querySelector('.close-modal'); + const applicationForm = document.getElementById('application-form'); + + // Function to open the modal + function openModal() { + modalContainer.classList.add('active'); + } + + // Function to close the modal + function closeModal() { + modalContainer.classList.remove('active'); + } + + // Event listener for close button + closeModalButton.addEventListener('click', closeModal); + + // Event listener for form submission + applicationForm.addEventListener('submit', function(event) { + event.preventDefault(); + // Handle form submission logic here + alert('Application submitted successfully!'); + closeModal(); + }); + + // Open the modal when the page loads + openModal(); +}); + +-------------------------------------------------- +File: ./web/hiring/hiring.js +-------------------------------------------------- +document.addEventListener('DOMContentLoaded', function() { + // Add smooth scrolling for any anchor links + document.querySelectorAll('a[href^="#"]').forEach(anchor => { + anchor.addEventListener('click', function (e) { + e.preventDefault(); + document.querySelector(this.getAttribute('href')).scrollIntoView({ + behavior: 'smooth' + }); + }); + }); + + // Add hover effects for position cards + document.querySelectorAll('.position-card').forEach(card => { + card.addEventListener('mouseenter', function() { + this.style.transform = 'translateY(-5px)'; + this.style.boxShadow = '0 8px 32px rgba(0, 0, 0, 0.2)'; + this.style.borderColor = 'var(--gradient-end)'; + }); + + card.addEventListener('mouseleave', function() { + this.style.transform = 'translateY(0)'; + this.style.boxShadow = 'none'; + this.style.borderColor = 'rgba(255, 255, 255, 0.1)'; + }); + }); + + // Add hover effects for benefit cards + document.querySelectorAll('.benefit-card').forEach(card => { + card.addEventListener('mouseenter', function() { + this.style.transform = 'translateY(-5px)'; + this.style.boxShadow = '0 8px 32px rgba(0, 0, 0, 0.2)'; + this.style.borderColor = 'var(--gradient-end)'; + }); + + card.addEventListener('mouseleave', function() { + this.style.transform = 'translateY(0)'; + this.style.boxShadow = 'none'; + this.style.borderColor = 'rgba(255, 255, 255, 0.1)'; + }); + }); +}); + +-------------------------------------------------- +File: ./web/hiring/hiring-modal.html +-------------------------------------------------- +<!DOCTYPE html> +<html lang="en"> + +<head> + <!-- Google tag (gtag.js) --> + <script async src="https://www.googletagmanager.com/gtag/js?id=G-0LTP0WK7EM"></script> + <script> + window.dataLayer = window.dataLayer || []; + function gtag() { dataLayer.push(arguments); } + gtag('js', new Date()); + + gtag('config', 'G-0LTP0WK7EM'); + </script> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Apply Now - DNAnalyzer</title> + <link rel="stylesheet" href="../style.css"> + <link rel="stylesheet" href="hiring-modal.css"> + <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@300;400;500;600;700&display=swap" + rel="stylesheet"> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"> + <link rel="shortcut icon" href="../assets/icons/Icon_Dark_BG.svg" type="image/svg+xml"> +</head> + +<body> + <div class="modal-container"> + <div class="modal-content"> + <button class="close-modal">×</button> + <h2>Apply for the Position</h2> + <form id="application-form"> + <div class="form-group"> + <label for="name">Full Name</label> + <input type="text" id="name" name="name" required> + </div> + <div class="form-group"> + <label for="email">Email Address</label> + <input type="email" id="email" name="email" required> + </div> + <div class="form-group"> + <label for="position">Position</label> + <select id="position" name="position" required> + <option value="software-engineer">Software Engineer</option> + <option value="data-scientist">Data Scientist</option> + <option value="ui-ux-designer">UI/UX Designer</option> + </select> + </div> + <div class="form-group"> + <label for="resume">Upload Resume</label> + <input type="file" id="resume" name="resume" accept=".pdf,.doc,.docx" required> + </div> + <div class="form-group"> + <label for="cover-letter">Cover Letter</label> + <textarea id="cover-letter" name="cover-letter" rows="5" required></textarea> + </div> + <button type="submit" class="primary-btn">Submit Application</button> + </form> + </div> + </div> + + <script src="hiring-modal.js"></script> +</body> + +</html> +-------------------------------------------------- + +Directory: server +================================================== +File: ./web/server/server.js +-------------------------------------------------- +/* + * DNAnalyzer Server Page JavaScript + * Copyright © 2025 Piyush Acharya + */ + +document.addEventListener('DOMContentLoaded', function() { + // Mobile navigation toggle + const mobileToggle = document.getElementById('mobileToggle'); + const navLinks = document.getElementById('navLinks'); + + if (mobileToggle && navLinks) { + mobileToggle.addEventListener('click', function() { + navLinks.classList.toggle('active'); + mobileToggle.querySelector('i').classList.toggle('fa-bars'); + mobileToggle.querySelector('i').classList.toggle('fa-times'); + }); + } + + // Navbar scroll behavior + const navbar = document.getElementById('navbar'); + + window.addEventListener('scroll', function() { + if (window.scrollY > 100) { + navbar.classList.add('scrolled'); + } else { + navbar.classList.remove('scrolled'); + } + }); + + // Server status check + const serverStatusElement = document.getElementById('server-status'); + let statusCheckInterval; + let retryCount = 0; + const MAX_RETRIES = 3; + const SERVER_PORT = 8080; + + // Copy commands functionality + window.copyCloneCommand = function() { + copyToClipboard('git clone https://github.com/VerisimilitudeX/DNAnalyzer.git && cd DNAnalyzer', 0); + }; + + window.copyChmodCommand = function() { + copyToClipboard('chmod +x ./gradlew', 1); + }; + + window.copyBuildCommand = function() { + copyToClipboard('./gradlew clean bootJar', 2); + }; + + window.copyRunCommand = function() { + copyToClipboard('java -jar build/libs/DNAnalyzer.jar', 3); + }; + + function copyToClipboard(text, buttonIndex) { + navigator.clipboard.writeText(text).then(() => { + const buttons = document.querySelectorAll('.copy-button'); + const button = buttons[buttonIndex]; + button.textContent = 'Copied!'; + button.classList.add('success'); + setTimeout(() => { + button.textContent = 'Copy'; + button.classList.remove('success'); + }, 2000); + }).catch(() => { + const buttons = document.querySelectorAll('.copy-button'); + const button = buttons[buttonIndex]; + button.textContent = 'Failed'; + button.classList.add('error'); + setTimeout(() => { + button.textContent = 'Copy'; + button.classList.remove('error'); + }, 2000); + }); + } + + // Server status check with retry logic + async function checkServerStatus(isInitialCheck = false) { + try { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 5000); + + // Try the API status endpoint first + const response = await fetch(`http://localhost:${SERVER_PORT}/api/v1/status`, { + method: 'GET', + signal: controller.signal, + headers: { + 'Accept': 'application/json', + } + }); + + clearTimeout(timeoutId); + retryCount = 0; // Reset retry count on success + + serverStatusElement.innerHTML = ` + <div class="status-indicator online"> + <div class="status-dot"></div> + <div class="status-details"> + <div class="status-main">Server Online</div> + <div class="status-info"> + <span>Status: Running</span> + <span>Last checked: ${new Date().toLocaleTimeString()}</span> + <span>Ready to process DNA sequences</span> + </div> + </div> + </div> + `; + return true; + } catch (error) { + // Try root URL as fallback + try { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 5000); + + const response = await fetch(`http://localhost:${SERVER_PORT}/`, { + method: 'GET', + signal: controller.signal + }); + + clearTimeout(timeoutId); + + if (response.ok || response.status === 404) { + // Even a 404 means the server is running + retryCount = 0; + + serverStatusElement.innerHTML = ` + <div class="status-indicator online"> + <div class="status-dot"></div> + <div class="status-details"> + <div class="status-main">Server Online</div> + <div class="status-info"> + <span>Status: Running</span> + <span>Last checked: ${new Date().toLocaleTimeString()}</span> + <span>Ready to process DNA sequences</span> + </div> + </div> + </div> + `; + return true; + } + throw new Error('Server not responding correctly'); + } catch (fallbackError) { + retryCount++; + const isMaxRetries = retryCount >= MAX_RETRIES; + + serverStatusElement.innerHTML = ` + <div class="status-indicator offline"> + <div class="status-dot"></div> + <div class="status-details"> + <div class="status-main">Server Offline</div> + <div class="status-info"> + <span>Last checked: ${new Date().toLocaleTimeString()}</span> + ${isInitialCheck ? '<span>Follow the setup steps above to start the server</span>' : ''} + ${!isInitialCheck && !isMaxRetries ? `<span>Retrying... (${retryCount}/${MAX_RETRIES})</span>` : ''} + ${isMaxRetries ? '<span>Max retries reached. Check server setup instructions above.</span>' : ''} + </div> + </div> + </div> + `; + if (isMaxRetries) { + clearInterval(statusCheckInterval); + showTroubleshooting(); + } + return false; + } + } + } + + function showTroubleshooting() { + const troubleshootingSection = document.getElementById('troubleshooting'); + if (troubleshootingSection) { + troubleshootingSection.classList.add('active'); + troubleshootingSection.scrollIntoView({ behavior: 'smooth', block: 'start' }); + } + } + + // Initialize status checking + async function initializeStatusCheck() { + const isOnline = await checkServerStatus(true); + + if (!isOnline) { + // If offline on first check, start checking more frequently initially + statusCheckInterval = setInterval(() => checkServerStatus(), 5000); + + // After 30 seconds, switch to normal interval if server is still offline + setTimeout(() => { + clearInterval(statusCheckInterval); + statusCheckInterval = setInterval(() => checkServerStatus(), 30000); + }, 30000); + } else { + // If online, check every 30 seconds + statusCheckInterval = setInterval(() => checkServerStatus(), 30000); + } + } + + // Start status checking + initializeStatusCheck(); + + // Cleanup on page unload + window.addEventListener('unload', () => { + if (statusCheckInterval) { + clearInterval(statusCheckInterval); + } + }); + + // Add animated appearance for steps + const animateSteps = () => { + const stepCards = document.querySelectorAll('.step-card'); + const observer = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + entry.target.style.opacity = 1; + entry.target.style.transform = 'translateY(0)'; + observer.unobserve(entry.target); + } + }); + }, { + threshold: 0.1 + }); + + stepCards.forEach((card, index) => { + card.style.opacity = 0; + card.style.transform = 'translateY(20px)'; + card.style.transition = 'opacity 0.5s ease, transform 0.5s ease'; + card.style.transitionDelay = `${index * 0.1}s`; + observer.observe(card); + }); + }; + + // Initialize animations + setTimeout(animateSteps, 500); +}); +-------------------------------------------------- +File: ./web/server/server.html +-------------------------------------------------- +<!DOCTYPE html> +<html lang="en"> + +<head> + <!-- Google tag (gtag.js) --> + <script async src="https://www.googletagmanager.com/gtag/js?id=G-0LTP0WK7EM"></script> + <script> + window.dataLayer = window.dataLayer || []; + function gtag() { dataLayer.push(arguments); } + gtag('js', new Date()); + + gtag('config', 'G-0LTP0WK7EM'); + </script> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Server - DNAnalyzer</title> + <link rel="stylesheet" href="../style.css"> + <link rel="stylesheet" href="server.css"> + <link + href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap" + rel="stylesheet"> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> + <link rel="shortcut icon" href="../assets/icons/Icon_Dark_BG.svg" type="image/svg+xml"> +</head> + +<body> + <!-- Background effects --> + <div class="bg-gradient"> + <div class="bg-blob bg-blob-1"></div> + <div class="bg-blob bg-blob-2"></div> + </div> + + <!-- Navbar --> + <nav class="navbar" id="navbar"> + <div class="container navbar-container"> + <a href="../index.html" class="logo"> + <img src="../assets/icons/Icon_Dark_BG.svg" alt="DNAnalyzer Logo"> + <span class="logo-text">DNAnalyzer</span> + </a> + + <button class="mobile-toggle" id="mobileToggle" aria-label="Toggle navigation"> + <i class="fas fa-bars"></i> + </button> + + <ul class="nav-links" id="navLinks"> + <li><a href="../index.html">Home</a></li> + <li><a href="../features/features.html">Features</a></li> + <li><a href="../analyzer/analyzer.html">Analyzer</a></li> + <li><a href="server.html" class="active">Server</a></li> + <li><a href="../docs/docs.html">Docs</a></li> + <li><a href="../about/about.html">About</a></li> + </ul> + + <div class="nav-buttons"> + <a href="https://github.com/VerisimilitudeX/DNAnalyzer" class="btn btn-secondary btn-sm"> + <i class="fab fa-github btn-icon"></i> GitHub + </a> + </div> + </div> + </nav> + + <!-- Main Content --> + <main> + <section class="hero"> + <div class="container"> + <div class="hero-content"> + <div class="hero-headings"> + <h1>DNAnalyzer <span>Server</span></h1> + <p class="hero-subtitle">Set up and run your own DNAnalyzer server for local development and + advanced genomic analysis</p> + </div> + </div> + </div> + </section> + + <section class="section"> + <div class="container"> + <div class="section-title"> + <h2>Server Status</h2> + <p>Check your local server installation status and requirements</p> + </div> + + <div class="card-grid"> + <div class="card"> + <div class="card-icon"> + <i class="fas fa-server"></i> + </div> + <h3 class="card-title">Server Status</h3> + <div id="server-status" class="status-value">Checking...</div> + <p>Local Server</p> + </div> + + <div class="card"> + <div class="card-icon"> + <i class="fas fa-memory"></i> + </div> + <h3 class="card-title">System Requirements</h3> + <div class="status-value">2GB+</div> + <p>Minimum RAM</p> + </div> + + <div class="card"> + <div class="card-icon"> + <i class="fas fa-code-branch"></i> + </div> + <h3 class="card-title">Version</h3> + <div class="status-value">Java 17+</div> + <p>Required Runtime</p> + </div> + </div> + </div> + </section> + + <section class="section section-bg-gradient"> + <div class="container"> + <div class="section-title"> + <h2>Quick Start Guide</h2> + <p>Follow these steps to set up your local DNAnalyzer server</p> + </div> + + <div class="steps-container"> + <div class="step-item"> + <div class="step-content"> + <h3>Clone the Repository</h3> + <div class="code-block"> + <code>git clone https://github.com/VerisimilitudeX/DNAnalyzer.git && cd DNAnalyzer</code> + <button class="copy-button" onclick="copyCloneCommand()">Copy</button> + </div> + <p>Clone the repository and navigate to the project directory</p> + </div> + </div> + + <div class="step-item"> + <div class="step-content"> + <h3>Setup Gradle</h3> + <div class="code-block"> + <code>chmod +x ./gradlew</code> + <button class="copy-button" onclick="copyChmodCommand()">Copy</button> + </div> + <p>Make the Gradle wrapper executable (Unix/macOS systems)</p> + </div> + </div> + + <div class="step-item"> + <div class="step-content"> + <h3>Build the Project</h3> + <div class="code-block"> + <code>./gradlew clean bootJar</code> + <button class="copy-button" onclick="copyBuildCommand()">Copy</button> + </div> + <p>Build the project (this may take a few minutes on first run)</p> + </div> + </div> + + <div class="step-item"> + <div class="step-content"> + <h3>Start the Server</h3> + <div class="code-block"> + <code>java -jar build/libs/DNAnalyzer.jar</code> + <button class="copy-button" onclick="copyRunCommand()">Copy</button> + </div> + <p>Start the local server on port 8080</p> + </div> + </div> + </div> + </div> + </section> + + <section class="section" id="troubleshooting"> + <div class="container"> + <div class="section-title"> + <h2>Troubleshooting</h2> + <p>Common issues and their solutions</p> + </div> + + <div class="feature-card"> + <div class="feature-icon feature-icon-magenta"> + <i class="fas fa-network-wired"></i> + </div> + <div class="feature-content"> + <h3>Port Already in Use</h3> + <p>If port 8080 is already in use, you may see an error like "Address already in use". To fix + this:</p> + <ul> + <li>Close any other applications using port 8080</li> + <li>Or modify the port in application.yml to use a different port</li> + <li>Alternatively, use the command line option to specify a different port</li> + </ul> + <div class="code-block"> + <code>java -jar build/libs/DNAnalyzer.jar --server.port=8090</code> + </div> + </div> + </div> + + <div class="feature-card"> + <div class="feature-icon feature-icon-blue"> + <i class="fab fa-java"></i> + </div> + <div class="feature-content"> + <h3>Java Version Issues</h3> + <p>If you see "UnsupportedClassVersionError", make sure you have Java 17+ installed:</p> + <div class="code-block"> + <code>java -version</code> + </div> + <p>Download and install Java 17 or later if your version is outdated.</p> + </div> + </div> + + <div class="feature-card"> + <div class="feature-icon feature-icon-orange"> + <i class="fas fa-exclamation-triangle"></i> + </div> + <div class="feature-content"> + <h3>Build Failures</h3> + <p>If you encounter build errors, try these solutions:</p> + <ul> + <li>Run './gradlew clean' first to clear any cached files</li> + <li>Make sure your Java installation is properly configured</li> + <li>Ensure you have write permissions in the project directory</li> + <li>Update Gradle wrapper if needed with './gradlew wrapper --gradle-version=7.5'</li> + </ul> + </div> + </div> + </div> + </section> + + <section class="section section-bg-dark"> + <div class="container text-center"> + <h2>Ready to Contribute?</h2> + <p class="mb-xl">Join our community and help improve DNAnalyzer's server capabilities.</p> + + <div class="hero-buttons" style="justify-content: center;"> + <a href="https://github.com/VerisimilitudeX/DNAnalyzer" class="btn btn-primary"> + <i class="fab fa-github btn-icon"></i> Fork on GitHub + </a> + <a href="https://discord.gg/xNpujz49gj" class="btn btn-secondary"> + <i class="fab fa-discord btn-icon"></i> Join Discord + </a> + </div> + </div> + </section> + </main> + + <!-- Footer --> + <footer class="footer"> + <div class="container"> + <div class="footer-grid"> + <div class="footer-brand"> + <img src="../assets/icons/Icon_Dark_BG.svg" alt="DNAnalyzer Logo"> + <p>DNAnalyzer is a powerful, privacy-focused DNA analysis tool using cutting-edge machine learning + models for accurate, on-device genomic analysis.</p> + + <div class="footer-social"> + <a href="https://github.com/VerisimilitudeX/DNAnalyzer" class="social-link"> + <i class="fab fa-github"></i> + </a> + <a href="https://discord.gg/xNpujz49gj" class="social-link"> + <i class="fab fa-discord"></i> + </a> + <a href="https://twitter.com/DNAnalyzer_" class="social-link"> + <i class="fab fa-twitter"></i> + </a> + </div> + </div> + + <div class="footer-nav"> + <h4>Product</h4> + <ul> + <li><a href="../features/features.html">Features</a></li> + <li><a href="../analyzer/analyzer.html">DNA Analyzer</a></li> + <li><a href="server.html">Server</a></li> + <li><a href="../docs/docs.html">Documentation</a></li> + </ul> + </div> + + <div class="footer-nav"> + <h4>Resources</h4> + <ul> + <li><a href="../docs/getting-started.md">Getting Started</a></li> + <li><a href="../docs/citations.md">Citations</a></li> + <li><a href="../docs/research/genes.md">Gene Research</a></li> + <li><a href="../docs/samples/cli-arguments-examples.md">CLI Examples</a></li> + </ul> + </div> + + <div class="footer-nav"> + <h4>Community</h4> + <ul> + <li><a href="https://github.com/VerisimilitudeX/DNAnalyzer">GitHub</a></li> + <li><a href="https://discord.gg/xNpujz49gj">Discord</a></li> + <li><a href="../docs/contributing/CONTRIBUTING.md">Contributing</a></li> + <li><a href="../CODE_OF_CONDUCT.md">Code of Conduct</a></li> + </ul> + </div> + </div> + + <div class="footer-bottom"> + <div class="footer-copyright"> + Copyright © Piyush Acharya 2025. DNAnalyzer is a fiscally sponsored 501(c)(3) nonprofit (EIN: + 81-2908499). MIT License. + </div> + + <div class="footer-links"> + <a href="../LICENSE.md">License</a> + <a href="../SECURITY.md">Security</a> + <a href="../CITATION.cff">Citation</a> + </div> + </div> + </div> + </footer> + + <script src="server.js"></script> +</body> + +</html> +-------------------------------------------------- +File: ./web/server/server.css +-------------------------------------------------- +/* Server Page Custom Styles */ + +/* Code blocks for server page */ +.code-block { + background-color: rgba(0, 0, 0, 0.3); + border-radius: var(--radius-md); + padding: 1rem; + margin: 1rem 0; + position: relative; + font-family: var(--font-mono); + font-size: 0.9rem; + overflow-x: auto; + color: rgba(255, 255, 255, 0.9); + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.copy-button { + position: absolute; + top: 0.5rem; + right: 0.5rem; + background: rgba(255, 255, 255, 0.1); + border: none; + color: rgba(255, 255, 255, 0.7); + padding: 0.3rem 0.6rem; + border-radius: 4px; + cursor: pointer; + font-size: 0.8rem; + transition: all 0.2s ease; +} + +.copy-button:hover { + background: rgba(255, 255, 255, 0.2); + color: white; +} + +.copy-button.success { + background: rgba(0, 200, 83, 0.2); + color: #00c853; +} + +.copy-button.error { + background: rgba(244, 67, 54, 0.2); + color: #f44336; +} + +/* Status Value styling */ +.status-value { + font-size: 1.8rem; + font-weight: 600; + margin: 0.5rem 0; + color: rgba(255, 255, 255, 0.9); +} + +/* Status indicators */ +.status-indicator { + display: flex; + align-items: center; + justify-content: center; + gap: 1rem; +} + +.status-dot { + width: 16px; + height: 16px; + border-radius: 50%; +} + +.online .status-dot { + background: #00c853; + box-shadow: 0 0 10px rgba(0, 200, 83, 0.5); +} + +.offline .status-dot { + background: #f44336; + box-shadow: 0 0 10px rgba(244, 67, 54, 0.5); +} + +.status-main { + font-weight: 600; + font-size: 1.2rem; +} + +.online .status-main { + color: #00c853; +} + +.offline .status-main { + color: #f44336; +} + +.status-info { + display: flex; + flex-direction: column; + font-size: 0.85rem; + color: rgba(255, 255, 255, 0.7); + margin-top: 0.5rem; +} + +/* Troubleshooting section */ +#troubleshooting { + opacity: 1; + transition: all 0.5s ease; +} + +#troubleshooting.active { + animation: pulse 1s ease; +} + +@keyframes pulse { + 0% { opacity: 0.7; } + 50% { opacity: 1; } + 100% { opacity: 0.7; } +}5rem; + margin-bottom: 1.5rem; +} + +.server-hero-content p { + font-size: 1.2rem; + color: rgba(255, 255, 255, 0.9); + max-width: 800px; + margin: 0 auto; + line-height: 1.8; +} + +/* Status Cards Section */ +.status-section { + margin: 4rem 0; + padding: 2rem; + background: rgba(0, 0, 0, 0.2); + border-radius: 12px; + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.status-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 2rem; + margin-top: 1rem; +} + +.status-card { + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + padding: 2rem; + text-align: center; + transition: all 0.3s ease; +} + +.status-card:hover { + transform: translateY(-5px); + background: rgba(255, 255, 255, 0.08); + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.2); + border-color: rgba(255, 255, 255, 0.15); +} + +.status-icon { + font-size: 2rem; + margin-bottom: 1rem; + background: linear-gradient(135deg, var(--magenta), var(--blue)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} + +.status-card h3 { + font-size: 1.3rem; + margin-bottom: 1rem; + color: var(--white); +} + +.status-value { + font-size: 1.8rem; + font-weight: 600; + margin-bottom: 0.5rem; + color: rgba(255, 255, 255, 0.9); +} + +.status-label { + color: rgba(255, 255, 255, 0.7); + font-size: 0.95rem; + margin: 0; +} + +/* Status Indicators */ +.status-indicator { + display: flex; + align-items: center; + justify-content: center; + gap: 1rem; +} + +.status-dot { + width: 16px; + height: 16px; + border-radius: 50%; +} + +.online .status-dot { + background: #00c853; + box-shadow: 0 0 10px rgba(0, 200, 83, 0.5); +} + +.offline .status-dot { + background: #f44336; + box-shadow: 0 0 10px rgba(244, 67, 54, 0.5); +} + +.status-main { + font-weight: 600; + font-size: 1.2rem; +} + +.online .status-main { + color: #00c853; +} + +.offline .status-main { + color: #f44336; +} + +.status-info { + display: flex; + flex-direction: column; + font-size: 0.85rem; + color: rgba(255, 255, 255, 0.7); + margin-top: 0.5rem; +} + +/* Guide Section */ +.guide-section { + margin: 4rem 0; + padding: 2rem; + background: rgba(0, 0, 0, 0.2); + border-radius: 12px; + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.guide-section h2 { + font-size: 2rem; + margin-bottom: 1.5rem; + background: linear-gradient(135deg, var(--magenta), var(--blue)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + display: inline-block; +} + +.step-list { + display: grid; + gap: 1.5rem; +} + +.step-card { + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + padding: 1.5rem; + transition: all 0.3s ease; + display: flex; + align-items: flex-start; + gap: 1rem; +} + +.step-card:hover { + transform: translateY(-5px); + background: rgba(255, 255, 255, 0.08); + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.2); + border-color: rgba(255, 255, 255, 0.15); +} + +.step-number { + display: flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + border-radius: 50%; + background: linear-gradient(135deg, var(--magenta), var(--blue)); + color: white; + font-weight: 600; + flex-shrink: 0; +} + +.step-content { + flex-grow: 1; +} + +.step-command { + font-family: 'IBM Plex Mono', monospace; + font-size: 0.95rem; + color: rgba(255, 255, 255, 0.9); + margin-bottom: 0.8rem; + padding: 0.8rem; + background: rgba(0, 0, 0, 0.3); + border-radius: 6px; + overflow-x: auto; + position: relative; +} + +.copy-button { + position: absolute; + top: 0.5rem; + right: 0.5rem; + background: rgba(255, 255, 255, 0.1); + border: none; + color: rgba(255, 255, 255, 0.7); + padding: 0.3rem 0.6rem; + border-radius: 4px; + cursor: pointer; + font-size: 0.8rem; + transition: all 0.2s ease; +} + +.copy-button:hover { + background: rgba(255, 255, 255, 0.2); + color: white; +} + +.copy-button.success { + background: rgba(0, 200, 83, 0.2); + color: #00c853; +} + +.copy-button.error { + background: rgba(244, 67, 54, 0.2); + color: #f44336; +} + +.step-description { + color: rgba(255, 255, 255, 0.8); + font-size: 0.95rem; + line-height: 1.5; + margin: 0; +} + +/* Troubleshooting Section */ +.troubleshooting-section { + margin: 4rem 0; + opacity: 0.7; + transition: all 0.5s ease; +} + +.troubleshooting-section.active { + opacity: 1; +} + +.troubleshooting-section h2 { + font-size: 2rem; + margin-bottom: 1.5rem; + background: linear-gradient(135deg, var(--magenta), var(--blue)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + display: inline-block; +} + +.issue-list { + display: grid; + gap: 1.5rem; +} + +.issue-card { + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + padding: 1.5rem; + transition: all 0.3s ease; +} + +.issue-card:hover { + transform: translateY(-5px); + background: rgba(255, 255, 255, 0.08); + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.2); + border-color: rgba(255, 255, 255, 0.15); +} + +.issue-card h3 { + display: flex; + align-items: center; + gap: 0.8rem; + font-size: 1.3rem; + margin-top: 0; + margin-bottom: 1rem; +} + +.issue-card h3 i { + color: var(--magenta); +} + +.issue-card p { + color: rgba(255, 255, 255, 0.8); + font-size: 1rem; + line-height: 1.6; + margin-bottom: 1rem; +} + +.issue-card ul { + margin: 0; + padding-left: 1.5rem; +} + +.issue-card li { + color: rgba(255, 255, 255, 0.8); + margin-bottom: 0.5rem; +} + +.issue-command { + font-family: 'IBM Plex Mono', monospace; + font-size: 0.95rem; + color: rgba(255, 255, 255, 0.9); + margin: 1rem 0; + padding: 0.8rem; + background: rgba(0, 0, 0, 0.3); + border-radius: 6px; + overflow-x: auto; +} + +/* Responsive Design */ +@media screen and (max-width: 992px) { + .server-hero-content h1 { + font-size: 3rem; + } +} + +@media screen and (max-width: 768px) { + .container { + margin: 4rem 1rem 2rem; + padding: 1rem; + } + + .server-hero-content h1 { + font-size: 2.5rem; + } + + .server-hero-content p { + font-size: 1.1rem; + } + + .status-grid { + grid-template-columns: 1fr; + } + + .step-command { + font-size: 0.85rem; + } +} + +@media screen and (max-width: 480px) { + .server-hero-content h1 { + font-size: 2rem; + } + + .status-card { + padding: 1.5rem; + } + + .step-card { + flex-direction: column; + } + + .step-number { + margin-bottom: 0.5rem; + } +} +-------------------------------------------------- + +Directory: docs +================================================== +File: ./web/docs/docs.js +-------------------------------------------------- +/** + * DNAnalyzer - Documentation Page JavaScript + * Handles navigation, search, and interactive elements + */ + +document.addEventListener('DOMContentLoaded', function() { + // Initialize mobile navigation + initMobileNav(); + + // Initialize smooth scrolling + initSmoothScroll(); + + // Initialize tabs + initTabs(); + + // Initialize code copy buttons + initCodeCopy(); + + // Initialize FAQ accordions + initFaqAccordions(); + + // Initialize active link tracking + initActiveLinkTracking(); + + // Initialize search functionality + initSearch(); +}); + +/** + * Initialize mobile navigation + */ +function initMobileNav() { + const sidebar = document.getElementById('docsSidebar'); + const sidebarToggle = document.getElementById('sidebarToggle'); + const closeSidebar = document.getElementById('closeSidebar'); + + if (sidebar && sidebarToggle) { + // Toggle sidebar on mobile + sidebarToggle.addEventListener('click', function() { + sidebar.classList.add('active'); + }); + + // Close sidebar on mobile + if (closeSidebar) { + closeSidebar.addEventListener('click', function() { + sidebar.classList.remove('active'); + }); + } + + // Close sidebar when clicking on links (mobile) + const sidebarLinks = sidebar.querySelectorAll('a'); + sidebarLinks.forEach(link => { + link.addEventListener('click', function() { + if (window.innerWidth <= 768) { + sidebar.classList.remove('active'); + } + }); + }); + + // Close sidebar when clicking outside (mobile) + document.addEventListener('click', function(event) { + if (window.innerWidth <= 768 && + !sidebar.contains(event.target) && + event.target !== sidebarToggle && + !sidebarToggle.contains(event.target)) { + sidebar.classList.remove('active'); + } + }); + } +} + +/** + * Initialize smooth scrolling for anchor links + */ +function initSmoothScroll() { + document.querySelectorAll('a[href^="#"]').forEach(anchor => { + anchor.addEventListener('click', function(e) { + const targetId = this.getAttribute('href'); + + // Skip if it's just "#" or not an ID selector + if (targetId === '#' || !targetId.startsWith('#')) return; + + const targetElement = document.querySelector(targetId); + + if (targetElement) { + e.preventDefault(); + + const navbarHeight = 70; // Height of the fixed navbar + const docsHeaderHeight = 50; // Height of the docs header (mobile) + const offset = window.innerWidth <= 768 ? navbarHeight + docsHeaderHeight : navbarHeight; + + const targetPosition = targetElement.getBoundingClientRect().top + window.pageYOffset - offset; + + window.scrollTo({ + top: targetPosition, + behavior: 'smooth' + }); + } + }); + }); +} + +/** + * Initialize tabs functionality + */ +function initTabs() { + const tabButtons = document.querySelectorAll('.tab-button'); + + tabButtons.forEach(button => { + button.addEventListener('click', function() { + const tabId = this.getAttribute('data-tab'); + const tabContent = document.getElementById(tabId); + + // Remove active class from all buttons and contents + document.querySelectorAll('.tab-button').forEach(btn => { + btn.classList.remove('active'); + }); + + document.querySelectorAll('.tab-content').forEach(content => { + content.classList.remove('active'); + }); + + // Add active class to current button and content + this.classList.add('active'); + if (tabContent) { + tabContent.classList.add('active'); + } + }); + }); +} + +/** + * Initialize code copy functionality + */ +function initCodeCopy() { + const copyButtons = document.querySelectorAll('.copy-button'); + + copyButtons.forEach(button => { + button.addEventListener('click', function() { + const codeBlock = this.closest('.code-block'); + const code = codeBlock.querySelector('code').textContent; + + // Copy to clipboard + navigator.clipboard.writeText(code) + .then(() => { + // Success feedback + const originalText = this.textContent; + this.textContent = 'Copied!'; + this.style.background = 'var(--success)'; + + // Reset after 2 seconds + setTimeout(() => { + this.textContent = originalText; + this.style.background = ''; + }, 2000); + }) + .catch(err => { + console.error('Could not copy text: ', err); + + // Fallback for older browsers + const textarea = document.createElement('textarea'); + textarea.value = code; + textarea.style.position = 'fixed'; + document.body.appendChild(textarea); + textarea.focus(); + textarea.select(); + + try { + document.execCommand('copy'); + // Success feedback + const originalText = this.textContent; + this.textContent = 'Copied!'; + this.style.background = 'var(--success)'; + + // Reset after 2 seconds + setTimeout(() => { + this.textContent = originalText; + this.style.background = ''; + }, 2000); + } catch (err) { + console.error('Fallback copy failed: ', err); + this.textContent = 'Failed!'; + this.style.background = 'var(--error)'; + + setTimeout(() => { + this.textContent = 'Copy'; + this.style.background = ''; + }, 2000); + } + + document.body.removeChild(textarea); + }); + }); + }); +} + +/** + * Initialize FAQ accordions + */ +function initFaqAccordions() { + const faqItems = document.querySelectorAll('.faq-item'); + + faqItems.forEach(item => { + const question = item.querySelector('.faq-question'); + + if (question) { + question.addEventListener('click', function() { + // Toggle active class on the FAQ item + item.classList.toggle('active'); + + // If this item was activated, close others + if (item.classList.contains('active')) { + faqItems.forEach(otherItem => { + if (otherItem !== item) { + otherItem.classList.remove('active'); + } + }); + } + }); + } + }); +} + +/** + * Initialize active link tracking based on scroll position + */ +function initActiveLinkTracking() { + const sections = document.querySelectorAll('.doc-section'); + const navLinks = document.querySelectorAll('.sidebar-nav a'); + + if (sections.length === 0 || navLinks.length === 0) return; + + // Update active link on scroll + function updateActiveLink() { + let currentSection = ''; + const navbarHeight = 70; + const docsHeaderHeight = 50; + const totalOffset = window.innerWidth <= 768 ? navbarHeight + docsHeaderHeight + 20 : navbarHeight + 20; + + sections.forEach(section => { + const sectionTop = section.offsetTop - totalOffset; + const sectionHeight = section.offsetHeight; + const sectionId = section.getAttribute('id'); + + if (window.scrollY >= sectionTop && window.scrollY < sectionTop + sectionHeight) { + currentSection = '#' + sectionId; + } + }); + + // Update active class on nav links + navLinks.forEach(link => { + link.classList.remove('active'); + if (link.getAttribute('href') === currentSection) { + link.classList.add('active'); + } + }); + } + + // Initial call to set active link on page load + updateActiveLink(); + + // Update active link on scroll + window.addEventListener('scroll', updateActiveLink); +} + +/** + * Initialize search functionality + */ +function initSearch() { + const searchInput = document.getElementById('docsSearch'); + const sections = document.querySelectorAll('.doc-section'); + + if (!searchInput || sections.length === 0) return; + + searchInput.addEventListener('input', function() { + const query = this.value.trim().toLowerCase(); + + if (query.length < 2) { + // If query is too short, show all sections + sections.forEach(section => { + section.style.display = 'block'; + + // Remove any highlights + removeHighlights(section); + }); + return; + } + + // Search and filter sections + sections.forEach(section => { + const sectionText = section.textContent.toLowerCase(); + const headings = Array.from(section.querySelectorAll('h1, h2, h3, h4')).map(h => h.textContent.toLowerCase()); + + // Check if section contains the query in text or headings + const containsQuery = sectionText.includes(query) || headings.some(h => h.includes(query)); + + if (containsQuery) { + section.style.display = 'block'; + + // Highlight matches + removeHighlights(section); + highlightText(section, query); + } else { + section.style.display = 'none'; + } + }); + + // If search is cleared, reset highlights + if (query.length === 0) { + sections.forEach(section => { + removeHighlights(section); + }); + } + }); +} + +/** + * Highlight matching text in an element + * @param {HTMLElement} element - The element to search in + * @param {string} query - The text to highlight + */ +function highlightText(element, query) { + // Only highlight text in paragraphs, list items, and code blocks + const textNodes = element.querySelectorAll('p, li, code'); + + textNodes.forEach(node => { + const html = node.innerHTML; + // Create regex with word boundary for whole words, or without for partial matches + const regex = new RegExp(`(\\b${query}\\b|${query})`, 'gi'); + const newHtml = html.replace(regex, '<mark>$1</mark>'); + + if (newHtml !== html) { + node.innerHTML = newHtml; + } + }); +} + +/** + * Remove highlights from an element + * @param {HTMLElement} element - The element to remove highlights from + */ +function removeHighlights(element) { + const marks = element.querySelectorAll('mark'); + + marks.forEach(mark => { + // Replace mark with its text content + const textNode = document.createTextNode(mark.textContent); + mark.parentNode.replaceChild(textNode, mark); + }); +} +-------------------------------------------------- +File: ./web/docs/docs.css +-------------------------------------------------- +/* Documentation Page Styles */ + +/* Layout */ +.docs-layout { + display: flex; + min-height: calc(100vh - 70px); + margin-top: 70px; +} + +/* Sidebar */ +.docs-sidebar { + width: 300px; + background: var(--dark-blue); + border-right: 1px solid rgba(255, 255, 255, 0.1); + position: fixed; + top: 70px; + left: 0; + bottom: 0; + overflow-y: auto; + z-index: 100; + transition: transform var(--transition-normal); +} + +.sidebar-header { + padding: var(--space-lg); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + display: flex; + justify-content: space-between; + align-items: center; +} + +.sidebar-header h2 { + margin: 0; + font-size: 1.3rem; + color: var(--white); +} + +.mobile-close { + display: none; + background: none; + border: none; + color: rgba(255, 255, 255, 0.7); + font-size: 1.2rem; + cursor: pointer; + transition: color var(--transition-fast); +} + +.mobile-close:hover { + color: var(--white); +} + +.sidebar-search { + padding: var(--space-md) var(--space-lg); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.search-input-wrapper { + position: relative; +} + +.search-input-wrapper i { + position: absolute; + left: var(--space-md); + top: 50%; + transform: translateY(-50%); + color: rgba(255, 255, 255, 0.5); + pointer-events: none; +} + +.search-input-wrapper input { + width: 100%; + padding: var(--space-sm) var(--space-sm) var(--space-sm) var(--space-xl); + background: rgba(255, 255, 255, 0.1); + border: 1px solid rgba(255, 255, 255, 0.15); + border-radius: var(--radius-md); + color: var(--white); + font-size: 0.9rem; + transition: all var(--transition-fast); +} + +.search-input-wrapper input:focus { + outline: none; + border-color: var(--blue); + background: rgba(255, 255, 255, 0.15); +} + +.sidebar-nav { + padding: var(--space-md) 0; +} + +.nav-section { + margin-bottom: var(--space-lg); + padding: 0 var(--space-lg); +} + +.nav-section h3 { + font-size: 0.9rem; + text-transform: uppercase; + letter-spacing: 1px; + color: rgba(255, 255, 255, 0.5); + margin: 0 0 var(--space-sm) 0; +} + +.nav-section ul { + list-style: none; + padding: 0; + margin: 0; +} + +.nav-section li { + margin-bottom: 2px; +} + +.nav-section a { + display: block; + padding: var(--space-xs) 0; + color: rgba(255, 255, 255, 0.7); + text-decoration: none; + font-size: 0.95rem; + transition: all var(--transition-fast); + border-radius: var(--radius-sm); +} + +.nav-section a:hover { + color: var(--white); + transform: translateX(2px); +} + +.nav-section a.active { + color: var(--blue); + font-weight: 500; +} + +/* Content */ +.docs-content { + flex: 1; + margin-left: 300px; + position: relative; +} + +.docs-container { + max-width: 900px; + margin: 0 auto; + padding: var(--space-xl) var(--space-xxl) var(--space-xxl); +} + +.docs-mobile-header { + display: none; + position: sticky; + top: 70px; + padding: var(--space-md) var(--space-lg); + background: var(--dark-blue); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + z-index: 90; +} + +.docs-mobile-header h2 { + margin: 0; + font-size: 1.3rem; + color: var(--white); +} + +.sidebar-toggle { + display: none; + background: none; + border: none; + color: rgba(255, 255, 255, 0.7); + font-size: 1.2rem; + cursor: pointer; + transition: color var(--transition-fast); + margin-right: var(--space-md); +} + +.sidebar-toggle:hover { + color: var(--white); +} + +/* Doc Sections */ +.doc-section { + margin-bottom: var(--space-xxl); + scroll-margin-top: 100px; +} + +.doc-section:last-child { + margin-bottom: 0; +} + +.doc-section h1 { + font-size: 2.5rem; + margin-bottom: var(--space-lg); + color: var(--white); +} + +.doc-section h2 { + font-size: 1.8rem; + margin: var(--space-xl) 0 var(--space-md); + color: var(--white); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + padding-bottom: var(--space-sm); +} + +.doc-section h3 { + font-size: 1.3rem; + margin: var(--space-lg) 0 var(--space-sm); + color: var(--white); +} + +.doc-section p { + margin-bottom: var(--space-md); + color: rgba(255, 255, 255, 0.8); + font-size: 1rem; + line-height: 1.7; +} + +.doc-section p.lead { + font-size: 1.1rem; + color: rgba(255, 255, 255, 0.9); +} + +.doc-section ul, +.doc-section ol { + margin-bottom: var(--space-md); + color: rgba(255, 255, 255, 0.8); + padding-left: var(--space-xl); +} + +.doc-section li { + margin-bottom: var(--space-xs); +} + +.doc-section a { + color: var(--blue); + text-decoration: none; + transition: color var(--transition-fast); +} + +.doc-section a:hover { + text-decoration: underline; + color: var(--light-blue); +} + +.doc-section code { + font-family: var(--font-mono); + background: rgba(0, 0, 0, 0.2); + padding: 2px 5px; + border-radius: var(--radius-sm); + font-size: 0.9em; + color: var(--white); +} + +/* Info Boxes */ +.info-box { + background: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-md); + padding: var(--space-lg); + margin: var(--space-lg) 0; + border-left: 4px solid var(--blue); +} + +.info-box h3 { + margin-top: 0; + font-size: 1.1rem; + color: var(--white); +} + +.info-box p:last-child, +.info-box ul:last-child { + margin-bottom: 0; +} + +.info-box.warning { + border-left-color: var(--warning); +} + +.info-box.warning h3 { + color: var(--warning); +} + +.info-box.error { + border-left-color: var(--error); +} + +.info-box.error h3 { + color: var(--error); +} + +.info-box.tip { + border-left-color: var(--success); +} + +.info-box.tip h3 { + color: var(--success); +} + +/* Code Blocks */ +.code-block { + margin: var(--space-md) 0; + background: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-md); + overflow: hidden; +} + +.code-header { + display: flex; + justify-content: space-between; + align-items: center; + background: rgba(0, 0, 0, 0.3); + padding: var(--space-sm) var(--space-md); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.code-label { + font-size: 0.9rem; + color: rgba(255, 255, 255, 0.7); +} + +.copy-button { + background: rgba(255, 255, 255, 0.1); + border: none; + color: rgba(255, 255, 255, 0.7); + padding: 4px 10px; + border-radius: var(--radius-sm); + font-size: 0.8rem; + cursor: pointer; + transition: all var(--transition-fast); +} + +.copy-button:hover { + background: rgba(255, 255, 255, 0.2); + color: var(--white); +} + +.code-block pre { + margin: 0; + padding: var(--space-md); + overflow-x: auto; +} + +.code-block code { + background: transparent; + padding: 0; + font-family: var(--font-mono); + font-size: 0.9rem; + line-height: 1.6; + color: rgba(255, 255, 255, 0.9); + display: block; +} + +/* Tabs */ +.tabs { + margin: var(--space-md) 0; + background: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-md); + overflow: hidden; +} + +.tab-header { + display: flex; + background: rgba(0, 0, 0, 0.3); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.tab-button { + padding: var(--space-sm) var(--space-md); + background: transparent; + border: none; + border-bottom: 2px solid transparent; + color: rgba(255, 255, 255, 0.7); + cursor: pointer; + transition: all var(--transition-fast); +} + +.tab-button:hover { + color: var(--white); +} + +.tab-button.active { + color: var(--blue); + border-bottom-color: var(--blue); + background: rgba(0, 164, 239, 0.1); +} + +.tab-content { + display: none; + padding: var(--space-md); +} + +.tab-content.active { + display: block; +} + +/* Steps */ +.steps { + margin: var(--space-lg) 0; +} + +.step { + display: flex; + margin-bottom: var(--space-lg); + gap: var(--space-md); +} + +.step-number { + flex-shrink: 0; + width: 34px; + height: 34px; + background: linear-gradient(135deg, var(--magenta), var(--blue)); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-weight: 600; + font-size: 1.1rem; + color: var(--white); + margin-top: 5px; +} + +.step-content { + flex: 1; +} + +.step-content h3 { + margin-top: 0; + font-size: 1.2rem; + margin-bottom: var(--space-sm); +} + +.step-content p { + margin-bottom: var(--space-sm); +} + +.step-content p:last-child { + margin-bottom: 0; +} + +/* API Endpoints */ +.api-endpoint { + margin-bottom: var(--space-lg); + background: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-md); + overflow: hidden; +} + +.endpoint-method { + display: inline-block; + padding: var(--space-xs) var(--space-sm); + font-weight: 600; + color: var(--white); + border-radius: var(--radius-sm); + font-size: 0.9rem; + margin-right: var(--space-sm); +} + +.endpoint-method.get { + background: var(--success); +} + +.endpoint-method.post { + background: var(--blue); +} + +.endpoint-method.put { + background: var(--warning); +} + +.endpoint-method.delete { + background: var(--error); +} + +.endpoint-path { + font-family: var(--font-mono); + font-size: 1rem; + margin-bottom: var(--space-sm); + color: var(--white); + padding: var(--space-md); + background: rgba(0, 0, 0, 0.3); + display: flex; + align-items: center; +} + +.endpoint-description { + padding: var(--space-md); +} + +.endpoint-description p { + margin-top: 0; +} + +.endpoint-description h4 { + font-size: 1.1rem; + margin: var(--space-md) 0 var(--space-xs); + color: var(--white); +} + +/* FAQ Section */ +.faq-item { + margin-bottom: var(--space-md); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: var(--radius-md); + overflow: hidden; +} + +.faq-question { + padding: var(--space-md); + background: rgba(0, 0, 0, 0.2); + cursor: pointer; + display: flex; + justify-content: space-between; + align-items: center; +} + +.faq-question h3 { + margin: 0; + font-size: 1.1rem; + color: var(--white); +} + +.faq-question i { + color: rgba(255, 255, 255, 0.7); + transition: transform var(--transition-fast); +} + +.faq-item.active .faq-question i { + transform: rotate(180deg); +} + +.faq-answer { + padding: 0 var(--space-md); + max-height: 0; + overflow: hidden; + transition: all var(--transition-normal); +} + +.faq-item.active .faq-answer { + padding: var(--space-md); + max-height: 1000px; +} + +/* Community Resources */ +.community-resources { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: var(--space-lg); + margin: var(--space-lg) 0; +} + +.resource-card { + background: rgba(255, 255, 255, 0.05); + border-radius: var(--radius-md); + padding: var(--space-lg); + text-align: center; + border: 1px solid rgba(255, 255, 255, 0.1); + transition: all var(--transition-normal); +} + +.resource-card:hover { + transform: translateY(-5px); + background: rgba(255, 255, 255, 0.08); + box-shadow: var(--shadow-md); + border-color: rgba(255, 255, 255, 0.15); +} + +.resource-card i { + font-size: 2rem; + margin-bottom: var(--space-md); + color: var(--blue); +} + +.resource-card h3 { + margin-top: 0; + margin-bottom: var(--space-sm); + font-size: 1.2rem; +} + +.resource-card p { + margin-bottom: var(--space-md); + color: rgba(255, 255, 255, 0.7); +} + +/* Responsive Design */ +@media screen and (max-width: 1024px) { + .docs-container { + padding: var(--space-xl) var(--space-lg); + } + + .community-resources { + grid-template-columns: 1fr; + } +} + +@media screen and (max-width: 768px) { + .docs-sidebar { + transform: translateX(-100%); + width: 280px; + } + + .docs-sidebar.active { + transform: translateX(0); + } + + .docs-content { + margin-left: 0; + } + + .docs-mobile-header { + display: flex; + align-items: center; + } + + .sidebar-toggle { + display: block; + } + + .mobile-close { + display: block; + } + + .api-endpoint { + overflow-x: auto; + } + + .step { + flex-direction: column; + gap: var(--space-sm); + } + + .step-number { + margin-bottom: var(--space-xs); + } +} + +@media screen and (max-width: 480px) { + .docs-container { + padding: var(--space-lg) var(--space-md); + } + + .doc-section h1 { + font-size: 2rem; + } + + .doc-section h2 { + font-size: 1.5rem; + } + + .doc-section h3 { + font-size: 1.2rem; + } + + .tab-header { + flex-wrap: wrap; + } + + .tab-button { + flex: 1; + min-width: 100px; + text-align: center; + } +} +-------------------------------------------------- +File: ./web/docs/docs.html +-------------------------------------------------- +<!DOCTYPE html> +<html lang="en"> + +<head> + <!-- Google tag (gtag.js) --> + <script async src="https://www.googletagmanager.com/gtag/js?id=G-0LTP0WK7EM"></script> + <script> + window.dataLayer = window.dataLayer || []; + function gtag() { dataLayer.push(arguments); } + gtag('js', new Date()); + + gtag('config', 'G-0LTP0WK7EM'); + </script> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Documentation - DNAnalyzer</title> + <meta name="description" + content="Comprehensive documentation for DNAnalyzer - Get started with our powerful DNA analysis tools and learn how to use all features."> + + <!-- Stylesheets --> + <link rel="stylesheet" href="../style.css"> + <link rel="stylesheet" href="docs.css"> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.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@300;400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap" + rel="stylesheet"> + + <!-- Favicon --> + <link rel="shortcut icon" href="../assets/icons/Icon_Dark_BG.svg" type="image/svg+xml"> +</head> + +<body> + <!-- Background effects --> + <div class="bg-gradient"> + <div class="bg-blob bg-blob-1"></div> + <div class="bg-blob bg-blob-2"></div> + </div> + + <div class="notification-banner"> + <span>Exclusive WSSEF Preview: </span> + <span> Transformer Architecture in Epigenomics!</span> + <a href="https://epiclassify.dnanalyzer.org" target="_blank" class="notification-link">Explore Now</a> + <button class="notification-close" aria-label="Dismiss notification"></button> + </div> + + <!-- Navbar --> + <nav class="navbar" id="navbar"> + <div class="container navbar-container"> + <a href="../index.html" class="logo"> + <img src="../assets/icons/Icon_Dark_BG.svg" alt="DNAnalyzer Logo"> + <span class="logo-text">DNAnalyzer</span> + </a> + + <button class="mobile-toggle" id="mobileToggle" aria-label="Toggle navigation"> + <i class="fas fa-bars"></i> + </button> + + <ul class="nav-links" id="navLinks"> + <li><a href="../index.html">Home</a></li> + <li><a href="../features/features.html">Features</a></li> + <li><a href="../analyzer/analyzer.html">Analyzer</a></li> + <li><a href="../server/server.html">Server</a></li> + <li><a href="docs.html" class="active">Docs</a></li> + <li><a href="../about/about.html">About</a></li> + </ul> + + <div class="nav-buttons"> + <a href="https://github.com/VerisimilitudeX/DNAnalyzer" class="btn btn-secondary btn-sm"> + <i class="fab fa-github btn-icon"></i> GitHub + </a> + </div> + </div> + </nav> + + <!-- Documentation Layout --> + <div class="docs-layout"> + <!-- Sidebar (Left) --> + <aside class="docs-sidebar" id="docsSidebar"> + <div class="sidebar-header"> + <h2>Documentation</h2> + <button class="mobile-close" id="closeSidebar"> + <i class="fas fa-times"></i> + </button> + </div> + + <div class="sidebar-search"> + <div class="search-input-wrapper"> + <i class="fas fa-search"></i> + <input type="text" id="docsSearch" placeholder="Search documentation..."> + </div> + </div> + + <nav class="sidebar-nav"> + <div class="nav-section"> + <h3>Getting Started</h3> + <ul> + <li><a href="#introduction" class="active">Introduction</a></li> + <li><a href="#installation">Installation</a></li> + <li><a href="#quick-start">Quick Start</a></li> + </ul> + </div> + + <div class="nav-section"> + <h3>Core Concepts</h3> + <ul> + <li><a href="#sequence-analysis">Sequence Analysis</a></li> + <li><a href="#codon-detection">Codon Detection</a></li> + <li><a href="#reading-frames">Reading Frames</a></li> + <li><a href="#protein-prediction">Protein Prediction</a></li> + </ul> + </div> + + <div class="nav-section"> + <h3>Advanced Usage</h3> + <ul> + <li><a href="#server-setup">Server Setup</a></li> + <li><a href="#api-reference">API Reference</a></li> + <li><a href="#cli-usage">CLI Usage</a></li> + </ul> + </div> + + <div class="nav-section"> + <h3>Resources</h3> + <ul> + <li><a href="#faq">FAQ</a></li> + <li><a href="#troubleshooting">Troubleshooting</a></li> + <li><a href="#community">Community</a></li> + </ul> + </div> + </nav> + </aside> + + <!-- Content (Right) --> + <div class="docs-content"> + <div class="docs-mobile-header"> + <button class="sidebar-toggle" id="sidebarToggle"> + <i class="fas fa-bars"></i> + </button> + <h2>Documentation</h2> + </div> + + <div class="docs-container"> + <!-- Introduction --> + <section id="introduction" class="doc-section"> + <h1>Introduction to DNAnalyzer</h1> + <p class="lead">DNAnalyzer is a powerful, privacy-focused DNA analysis tool using advanced machine + learning models for accurate, on-device genomic analysis.</p> + + <p>This documentation will guide you through the installation, setup, and usage of DNAnalyzer for + various DNA analysis tasks. Whether you're a researcher, educator, or bioinformatics enthusiast, + you'll find comprehensive information on all of DNAnalyzer's capabilities.</p> + + <div class="info-box"> + <h3>Key Features</h3> + <ul> + <li><strong>Privacy-First Analysis:</strong> All processing occurs on your device, ensuring + your genetic data never leaves your system.</li> + <li><strong>Machine Learning Powered:</strong> Advanced ML algorithms provide exceptional + accuracy in sequence analysis.</li> + <li><strong>Comprehensive Tools:</strong> From basic sequence statistics to advanced protein + prediction and promoter detection.</li> + <li><strong>Open Source:</strong> DNAnalyzer is completely open source under the MIT + License.</li> + </ul> + </div> + + <h2>System Requirements</h2> + <p>Before getting started, ensure your system meets the following requirements:</p> + + <div class="code-block"> + <div class="code-header"> + <span class="code-label">System Requirements</span> + <button class="copy-button">Copy</button> + </div> + <pre><code>- Operating System: Windows 10+, macOS 10.14+, or Linux (Ubuntu 18.04+) +- Memory: 2GB RAM minimum (4GB+ recommended for large sequences) +- Storage: 200MB for application, additional space for sequence files +- Browser: Chrome 80+, Firefox 75+, Safari 13+, Edge 80+ (for web interface) +- Java Runtime: Java 17+ (for server mode)</code></pre> + </div> + </section> + + <!-- Installation --> + <section id="installation" class="doc-section"> + <h1>Installation</h1> + <p>DNAnalyzer can be installed and used in multiple ways depending on your needs and technical + preferences.</p> + + <h2>Web Interface (No Installation)</h2> + <p>The simplest way to use DNAnalyzer is through our web interface, which requires no installation: + </p> + <ol> + <li>Visit <a href="../analyzer/analyzer.html">DNAnalyzer Web App</a></li> + <li>Upload your DNA sequence files</li> + <li>Select analysis options and get results</li> + </ol> + <p>The web interface runs entirely in your browser, ensuring your data never leaves your device.</p> + + <h2>Local Server Installation</h2> + <p>For more advanced usage or batch processing, you can install DNAnalyzer as a local server:</p> + + <div class="tabs"> + <div class="tab-header"> + <button class="tab-button active" data-tab="windows">Windows</button> + <button class="tab-button" data-tab="macos">macOS</button> + <button class="tab-button" data-tab="linux">Linux</button> + </div> + + <div class="tab-content active" id="windows"> + <ol> + <li>Download the latest <a + href="https://github.com/VerisimilitudeX/DNAnalyzer/releases">DNAnalyzer + release</a> for Windows</li> + <li>Extract the ZIP file to your preferred location</li> + <li>Ensure Java 17 or newer is installed on your system</li> + <li>Double-click on <code>dnanalyzer.bat</code> to start the server</li> + <li>Access the interface at <code>http://localhost:8080</code> in your browser</li> + </ol> + </div> + + <div class="tab-content" id="macos"> + <ol> + <li>Download the latest <a + href="https://github.com/VerisimilitudeX/DNAnalyzer/releases">DNAnalyzer + release</a> for macOS</li> + <li>Extract the ZIP file to your preferred location</li> + <li>Ensure Java 17 or newer is installed on your system</li> + <li>Open Terminal and navigate to the extracted folder</li> + <li>Run <code>chmod +x dnanalyzer.sh</code> to make the script executable</li> + <li>Execute <code>./dnanalyzer.sh</code> to start the server</li> + <li>Access the interface at <code>http://localhost:8080</code> in your browser</li> + </ol> + </div> + + <div class="tab-content" id="linux"> + <ol> + <li>Download the latest <a + href="https://github.com/VerisimilitudeX/DNAnalyzer/releases">DNAnalyzer + release</a> for Linux</li> + <li>Extract the archive to your preferred location</li> + <li>Ensure Java 17 or newer is installed on your system</li> + <li>Open Terminal and navigate to the extracted folder</li> + <li>Run <code>chmod +x dnanalyzer.sh</code> to make the script executable</li> + <li>Execute <code>./dnanalyzer.sh</code> to start the server</li> + <li>Access the interface at <code>http://localhost:8080</code> in your browser</li> + </ol> + </div> + </div> + + <h2>Building from Source</h2> + <p>For developers or those who want the latest features, you can build DNAnalyzer from source:</p> + + <div class="code-block"> + <div class="code-header"> + <span class="code-label">Building from Source</span> + <button class="copy-button">Copy</button> + </div> + <pre><code># Clone the repository +git clone https://github.com/VerisimilitudeX/DNAnalyzer.git +cd DNAnalyzer + +# Make the Gradle wrapper executable +chmod +x ./gradlew + +# Build the project +./gradlew clean bootJar + +# Run the server +java -jar build/libs/DNAnalyzer.jar</code></pre> + </div> + </section> + + <!-- Quick Start --> + <section id="quick-start" class="doc-section"> + <h1>Quick Start Guide</h1> + <p>This guide will help you quickly get started with DNAnalyzer's basic features.</p> + + <h2>Analyzing Your First DNA Sequence</h2> + <p>Follow these steps to perform your first DNA sequence analysis:</p> + + <div class="steps"> + <div class="step"> + <div class="step-number">1</div> + <div class="step-content"> + <h3>Upload a Sequence</h3> + <p>Navigate to the <a href="../analyzer/analyzer.html">DNA Analyzer</a> page and upload + your FASTA or FASTQ file by dragging it to the upload area or clicking to browse. + </p> + <p><strong>Don't have a sequence file?</strong> Click "Import Sample" to use a + pre-loaded sample sequence.</p> + </div> + </div> + + <div class="step"> + <div class="step-number">2</div> + <div class="step-content"> + <h3>Select Analysis Options</h3> + <p>Choose which analysis features you want to run:</p> + <ul> + <li><strong>Basic Analysis:</strong> Sequence length, GC content, base composition + </li> + <li><strong>Codon Analysis:</strong> Start codons, stop codons, reading frames</li> + <li><strong>Advanced Features:</strong> Coverage analysis, protein prediction, + promoter detection</li> + </ul> + </div> + </div> + + <div class="step"> + <div class="step-number">3</div> + <div class="step-content"> + <h3>Run Analysis</h3> + <p>Click the "Start Analysis" button to process your sequence. The analysis time depends + on the sequence length and selected options.</p> + </div> + </div> + + <div class="step"> + <div class="step-number">4</div> + <div class="step-content"> + <h3>Review Results</h3> + <p>Examine the analysis results, which include visualizations, statistics, and detailed + information about your sequence.</p> + <p>You can export the results in JSON, CSV, or text format for further processing or + documentation.</p> + </div> + </div> + </div> + + <div class="info-box tip"> + <h3>Pro Tip</h3> + <p>For large sequences (>1MB), consider using the local server installation for better + performance and additional analysis options.</p> + </div> + </section> + + <!-- Sequence Analysis --> + <section id="sequence-analysis" class="doc-section"> + <h1>Sequence Analysis</h1> + <p>DNAnalyzer provides comprehensive tools to analyze the basic properties of DNA sequences.</p> + + <h2>Base Composition Analysis</h2> + <p>One of the fundamental analyses is determining the nucleotide composition of your DNA sequence: + </p> + + <ul> + <li><strong>Nucleotide Counts:</strong> Total count of A, T, G, C, and any other bases (N) in + the sequence</li> + <li><strong>Percentage Distribution:</strong> Proportion of each nucleotide type</li> + <li><strong>Visualization:</strong> Interactive bar chart showing the distribution</li> + </ul> + + <h2>GC Content Analysis</h2> + <p>GC content is the percentage of nitrogenous bases in a DNA molecule that are either guanine (G) + or cytosine (C):</p> + + <div class="code-block"> + <div class="code-header"> + <span class="code-label">GC Content Formula</span> + <button class="copy-button">Copy</button> + </div> + <pre><code>GC Content (%) = (G + C) / (A + T + G + C) × 100</code></pre> + </div> + + <p>GC content is important because:</p> + <ul> + <li>It affects DNA stability (higher GC content = more stable)</li> + <li>GC-rich regions often indicate regulatory elements and gene-dense areas</li> + <li>Different organisms have characteristic GC content ranges</li> + </ul> + + <div class="info-box"> + <h3>Interpreting GC Content</h3> + <ul> + <li><strong>Low GC (< 40%):</strong> Common in AT-rich genomes like certain bacteria</li> + <li><strong>Medium GC (40-60%):</strong> Typical of many eukaryotic genomes, including + humans</li> + <li><strong>High GC (> 60%):</strong> Often found in gene-rich regions and certain + prokaryotes</li> + </ul> + </div> + </section> + + <!-- More sections would continue here... --> + + <!-- API Reference --> + <section id="api-reference" class="doc-section"> + <h1>API Reference</h1> + <p>DNAnalyzer provides a RESTful API when running in server mode, allowing programmatic access to + all analysis features.</p> + + <h2>API Endpoints</h2> + <p>The following endpoints are available when the server is running:</p> + + <div class="api-endpoint"> + <div class="endpoint-method get">GET</div> + <div class="endpoint-path">/api/v1/status</div> + <div class="endpoint-description"> + <p>Check server status and version information</p> + <h4>Response</h4> + <div class="code-block"> + <pre><code>{ + "status": "running", + "version": "1.0.0", + "uptime": "12h 34m 56s" +}</code></pre> + </div> + </div> + </div> + + <div class="api-endpoint"> + <div class="endpoint-method post">POST</div> + <div class="endpoint-path">/api/v1/analyze</div> + <div class="endpoint-description"> + <p>Analyze a DNA sequence file</p> + <h4>Request</h4> + <p>Form data with the following parameters:</p> + <ul> + <li><code>dnaFile</code> (required): The DNA sequence file to analyze</li> + <li><code>options</code>: JSON string with analysis options</li> + </ul> + <h4>Response</h4> + <div class="code-block"> + <pre><code>{ + "sequence": { + "length": 1234, + "filename": "example.fa" + }, + "basePairs": { + "counts": { "A": 300, "T": 310, "G": 320, "C": 304 }, + "percentages": { "A": 24.3, "T": 25.1, "G": 25.9, "C": 24.7 }, + "gcContent": 50.6 + }, + "analysis": { + // Additional analysis results based on options + } +}</code></pre> + </div> + </div> + </div> + + <div class="api-endpoint"> + <div class="endpoint-method post">POST</div> + <div class="endpoint-path">/api/v1/base-pairs</div> + <div class="endpoint-description"> + <p>Analyze base pair composition of a DNA sequence</p> + <h4>Request</h4> + <div class="code-block"> + <pre><code>{ + "sequence": "ATGCATGCATGC" +}</code></pre> + </div> + <h4>Response</h4> + <div class="code-block"> + <pre><code>{ + "counts": { "A": 3, "T": 3, "G": 3, "C": 3 }, + "percentages": { "A": 25, "T": 25, "G": 25, "C": 25 }, + "gcContent": 50 +}</code></pre> + </div> + </div> + </div> + + <h2>Python Client Example</h2> + <p>Here's a simple Python example to interact with the DNAnalyzer API:</p> + + <div class="code-block"> + <div class="code-header"> + <span class="code-label">Python</span> + <button class="copy-button">Copy</button> + </div> + <pre><code>import requests + +# API base URL +BASE_URL = "http://localhost:8080/api/v1" + +# Check server status +response = requests.get(f"{BASE_URL}/status") +print("Server status:", response.json()) + +# Analyze a sequence +with open("sequence.fa", "rb") as f: + files = {"dnaFile": f} + options = { + "sequence-length": True, + "gc-content": True, + "base-composition": True, + "start-codons": True, + "stop-codons": True + } + data = {"options": json.dumps(options)} + response = requests.post(f"{BASE_URL}/analyze", files=files, data=data) + + # Print results + result = response.json() + print(f"Sequence length: {result['sequence']['length']}") + print(f"GC content: {result['basePairs']['gcContent']}%")</code></pre> + </div> + </section> + + <!-- FAQ Section --> + <section id="faq" class="doc-section"> + <h1>Frequently Asked Questions</h1> + + <div class="faq-item"> + <div class="faq-question"> + <h3>Is my DNA data secure when using DNAnalyzer?</h3> + <i class="fas fa-chevron-down"></i> + </div> + <div class="faq-answer"> + <p>Yes, DNAnalyzer is designed with privacy as a fundamental principle. All processing + occurs locally on your device, and your DNA sequence data never leaves your system. In + web mode, analysis runs directly in your browser, and in server mode, it runs only on + your local machine. We don't collect, store, or transmit any of your sequence data.</p> + </div> + </div> + + <div class="faq-item"> + <div class="faq-question"> + <h3>What file formats does DNAnalyzer support?</h3> + <i class="fas fa-chevron-down"></i> + </div> + <div class="faq-answer"> + <p>DNAnalyzer supports the following file formats:</p> + <ul> + <li>FASTA (.fa, .fasta)</li> + <li>FASTQ (.fastq)</li> + <li>Plain text (.txt) containing DNA sequences</li> + </ul> + <p>The sequences should contain only A, T, G, C, and N (unknown) nucleotides. Other + characters will be treated as unknown bases.</p> + </div> + </div> + + <div class="faq-item"> + <div class="faq-question"> + <h3>How large of a sequence can DNAnalyzer handle?</h3> + <i class="fas fa-chevron-down"></i> + </div> + <div class="faq-answer"> + <p>The size limitations depend on the mode of operation:</p> + <ul> + <li><strong>Web Interface:</strong> Up to around 5MB sequence files, depending on your + browser and device memory</li> + <li><strong>Local Server:</strong> Can handle much larger sequences, typically up to + several hundred MB</li> + </ul> + <p>For very large genomes (e.g., human genome), we recommend using the local server + installation with a machine that has at least 8GB of RAM.</p> + </div> + </div> + + <div class="faq-item"> + <div class="faq-question"> + <h3>Can DNAnalyzer analyze my 23andMe or Ancestry DNA data?</h3> + <i class="fas fa-chevron-down"></i> + </div> + <div class="faq-answer"> + <p>Not directly in the current version. DNAnalyzer is designed to work with full DNA + sequences rather than SNP genotype data from consumer genetics services. However, we're + developing a feature to support genotype data analysis in an upcoming version.</p> + <p>If you have raw data from these services, you would need to convert it to a suitable + format before using it with DNAnalyzer.</p> + </div> + </div> + + <div class="faq-item"> + <div class="faq-question"> + <h3>Is DNAnalyzer open source?</h3> + <i class="fas fa-chevron-down"></i> + </div> + <div class="faq-answer"> + <p>Yes, DNAnalyzer is completely open source under the MIT License. You can view, modify, + and contribute to the code on our <a + href="https://github.com/VerisimilitudeX/DNAnalyzer">GitHub repository</a>.</p> + </div> + </div> + </section> + + <!-- Community Section --> + <section id="community" class="doc-section"> + <h1>Community & Support</h1> + <p>DNAnalyzer has an active community of users and developers. Here's how you can get involved and + find support.</p> + + <h2>Getting Help</h2> + <p>If you need assistance with DNAnalyzer, there are several resources available:</p> + + <div class="community-resources"> + <div class="resource-card"> + <i class="fab fa-discord"></i> + <h3>Discord Community</h3> + <p>Join our Discord server for real-time assistance and discussions about DNAnalyzer.</p> + <a href="https://discord.gg/xNpujz49gj" class="btn btn-secondary btn-sm">Join Discord</a> + </div> + + <div class="resource-card"> + <i class="fab fa-github"></i> + <h3>GitHub Issues</h3> + <p>Report bugs or request features through our GitHub issue tracker.</p> + <a href="https://github.com/VerisimilitudeX/DNAnalyzer/issues" + class="btn btn-secondary btn-sm">GitHub Issues</a> + </div> + + <div class="resource-card"> + <i class="fas fa-book"></i> + <h3>Documentation</h3> + <p>Browse comprehensive guides and tutorials in our documentation.</p> + <a href="docs.html" class="btn btn-secondary btn-sm">View Docs</a> + </div> + </div> + + <h2>Contributing</h2> + <p>DNAnalyzer is an open-source project, and we welcome contributions from the community. There are + many ways to contribute:</p> + + <ul> + <li><strong>Code Contributions:</strong> Help improve DNAnalyzer by fixing bugs or adding new + features</li> + <li><strong>Documentation:</strong> Improve our guides, tutorials, and API documentation</li> + <li><strong>Testing:</strong> Test DNAnalyzer and report issues or suggest improvements</li> + <li><strong>Translations:</strong> Help translate DNAnalyzer into different languages</li> + </ul> + + <p>To get started with contributing, please read our <a + href="https://github.com/VerisimilitudeX/DNAnalyzer/blob/main/CONTRIBUTING.md">contribution + guidelines</a>.</p> + + <div class="info-box"> + <h3>Code of Conduct</h3> + <p>We're committed to providing a welcoming and inclusive environment for all contributors. + Please read and follow our <a + href="https://github.com/VerisimilitudeX/DNAnalyzer/blob/main/CODE_OF_CONDUCT.md">Code + of Conduct</a>.</p> + </div> + </section> + </div> + </div> + </div> + + <!-- Footer --> + <footer class="footer"> + <div class="container"> + <div class="footer-grid"> + <div class="footer-brand"> + <img src="../assets/icons/Icon_Dark_BG.svg" alt="DNAnalyzer Logo"> + <p>DNAnalyzer is a powerful, privacy-focused DNA analysis tool using cutting-edge machine learning + models for accurate, on-device genomic analysis.</p> + + <div class="footer-social"> + <a href="https://www.twitter.com/DNAnalyzer_" class="social-link"> + <i class="fab fa-twitter"></i> + </a> + <a href="https://github.com/VerisimilitudeX/DNAnalyzer" class="social-link"> + <i class="fab fa-github"></i> + </a> + <a href="#" class="social-link"> + <i class="fab fa-twitter"></i> + </a> + </div> + </div> + + <div class="footer-nav"> + <h4>Product</h4> + <ul> + <li><a href="../features/features.html">Features</a></li> + <li><a href="../analyzer/analyzer.html">DNA Analyzer</a></li> + <li><a href="../server/server.html">Server</a></li> + <li><a href="docs.html">Documentation</a></li> + </ul> + </div> + + <div class="footer-nav"> + <h4>Resources</h4> + <ul> + <li><a href="getting-started.md">Getting Started</a></li> + <li><a href="citations.md">Citations</a></li> + <li><a href="research/genes.md">Gene Research</a></li> + <li><a href="samples/cli-arguments-examples.md">CLI Examples</a></li> + </ul> + </div> + + <div class="footer-nav"> + <h4>Community</h4> + <ul> + <li><a href="https://github.com/VerisimilitudeX/DNAnalyzer">GitHub</a></li> + <li><a href="https://discord.gg/xNpujz49gj">Discord</a></li> + <li><a href="contributing/CONTRIBUTING.md">Contributing</a></li> + <li><a href="../CODE_OF_CONDUCT.md">Code of Conduct</a></li> + </ul> + </div> + </div> + + <div class="footer-bottom"> + <div class="footer-copyright"> + Copyright © Piyush Acharya 2025. DNAnalyzer is a fiscally sponsored 501(c)(3) nonprofit (EIN: + 81-2908499). MIT License. + </div> + + <div class="footer-links"> + <a href="../LICENSE.md">License</a> + <a href="../SECURITY.md">Security</a> + <a href="../CITATION.cff">Citation</a> + </div> + </div> + </div> + </footer> + + <!-- JavaScript --> + <script src="docs.js"></script> +</body> + +</html> +-------------------------------------------------- +