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>
--------------------------------------------------