feat(ui): Enhance landing page interactions and animations

This commit is contained in:
cogwheel0
2025-11-26 20:01:48 +05:30
parent 1cd82c1916
commit 7fdb342b86
3 changed files with 1892 additions and 403 deletions

View File

@@ -4,137 +4,373 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Conduit - Native Mobile Client for Open-WebUI</title>
<title>Conduit — Your AI, Everywhere</title>
<meta name="description"
content="Conduit is an open-source, cross-platform mobile application for Open-WebUI, providing a native mobile experience for interacting with your self-hosted AI infrastructure.">
content="Conduit is an open-source, cross-platform mobile application for Open-WebUI. A native mobile experience for your self-hosted AI infrastructure.">
<link rel="stylesheet" href="styles.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=Outfit:wght@500;700&display=swap"
rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,300;12..96,400;12..96,500;12..96,600;12..96,700;12..96,800&family=Crimson+Pro:ital,wght@0,400;0,500;0,600;1,400;1,500&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="icon" type="image/png"
href="https://raw.githubusercontent.com/cogwheel0/conduit/main/assets/icon/icon.png">
href="https://raw.githubusercontent.com/cogwheel0/conduit/main/assets/icons/icon.png">
</head>
<body>
<!-- Grain overlay -->
<div class="grain"></div>
<!-- Floating orbs -->
<div class="orb orb-1"></div>
<div class="orb orb-2"></div>
<div class="orb orb-3"></div>
<nav class="navbar">
<div class="container">
<a href="#" class="logo">Conduit</a>
<a href="#" class="logo">
<span class="logo-mark"></span>
<span class="logo-text">Conduit</span>
</a>
<div class="nav-links">
<a href="#features">Features</a>
<a href="#screenshots">Screenshots</a>
<a href="#faq">FAQ</a>
<a href="https://github.com/cogwheel0/conduit" target="_blank" class="github-link">
<svg height="24" width="24" viewBox="0 0 16 16" fill="currentColor">
<path
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z">
</path>
<a href="#gallery">Gallery</a>
<a href="https://github.com/cogwheel0/conduit" target="_blank" class="nav-cta">
<span>View on GitHub</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M7 17L17 7M17 7H7M17 7V17"/>
</svg>
GitHub
</a>
</div>
<button class="mobile-menu-btn" aria-label="Menu">
<span></span>
<span></span>
</button>
</div>
</nav>
<!-- Mobile Menu -->
<div class="mobile-menu">
<a href="#features">Features</a>
<a href="#gallery">Gallery</a>
<a href="https://github.com/cogwheel0/conduit" target="_blank">GitHub</a>
</div>
<header class="hero">
<div class="container">
<div class="hero-content">
<h1 class="hero-title">Your AI, <span class="gradient-text">Unleashed.</span></h1>
<p class="hero-subtitle">The premium native mobile client for Open-WebUI. Connect to your self-hosted AI
infrastructure with a beautiful, fast, and secure experience.</p>
<div class="download-badges">
<a href="https://play.google.com/store/apps/details?id=app.cogwheel.conduit" class="store-badge">
<img src="store-badges/google.webp" alt="Get it on Google Play">
</a>
<a href="https://apps.apple.com/us/app/conduit-open-webui-client/id6749840287" class="store-badge">
<img src="store-badges/apple.webp" alt="Download on the App Store">
</a>
<div class="hero-badges">
<div class="hero-badge">
<span class="badge-dot"></span>
Open Source & Privacy-First
</div>
<a href="https://github.com/cogwheel0/conduit" target="_blank" class="social-badge">
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
</svg>
<span class="badge-value" id="github-stars"></span>
<span class="badge-label">Stars</span>
</a>
<a href="https://github.com/cogwheel0/conduit/releases" target="_blank" class="social-badge">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="7 10 12 15 17 10"/>
<line x1="12" y1="15" x2="12" y2="3"/>
</svg>
<span class="badge-value" id="github-downloads"></span>
<span class="badge-label">Downloads</span>
</a>
</div>
<div class="hero-stats">
<div class="stat-item">
<h1 class="hero-title">
<span class="title-line">Your AI,</span>
<span class="title-line title-accent">Everywhere<span class="title-dot">.</span></span>
</h1>
<p class="hero-subtitle">
The native mobile client for <strong>Open-WebUI</strong>.<br>
Beautiful, fast, and secure—connect to your self-hosted AI from anywhere.
</p>
<div class="hero-cta">
<a href="https://apps.apple.com/us/app/conduit-open-webui-client/id6749840287" class="btn btn-primary">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.81-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z"/>
</svg>
<span>App Store</span>
</a>
<a href="https://play.google.com/store/apps/details?id=app.cogwheel.conduit" class="btn btn-secondary">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M3,20.5V3.5C3,2.91 3.34,2.39 3.84,2.15L13.69,12L3.84,21.85C3.34,21.6 3,21.09 3,20.5M16.81,15.12L6.05,21.34L14.54,12.85L16.81,15.12M20.16,10.81C20.5,11.08 20.75,11.5 20.75,12C20.75,12.5 20.53,12.9 20.18,13.18L17.89,14.5L15.39,12L17.89,9.5L20.16,10.81M6.05,2.66L16.81,8.88L14.54,11.15L6.05,2.66Z"/>
</svg>
<span>Google Play</span>
</a>
</div>
<div class="hero-device">
<div class="device-glow"></div>
<div class="device-frame">
<img src="screenshots/conduit-demo.gif" alt="Conduit App Demo" loading="eager">
</div>
<div class="device-reflection"></div>
</div>
</div>
</header>
<section class="stats">
<div class="container">
<div class="stats-grid">
<div class="stat-card">
<div class="stat-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
</svg>
</div>
<div class="stat-content">
<span class="stat-value">Private</span>
<span class="stat-label">Your data stays yours</span>
</div>
</div>
<div class="stat-card">
<div class="stat-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/>
<polyline points="3.27 6.96 12 12.01 20.73 6.96"/>
<line x1="12" y1="22.08" x2="12" y2="12"/>
</svg>
</div>
<div class="stat-content">
<span class="stat-value">Open Source</span>
<span class="stat-label">GPLv3 Licensed</span>
</div>
<div class="stat-item">
<span class="stat-value">Private</span>
<span class="stat-label">Your Data, Your Control</span>
</div>
<div class="stat-card">
<div class="stat-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="5" y="2" width="14" height="20" rx="2" ry="2"/>
<line x1="12" y1="18" x2="12.01" y2="18"/>
</svg>
</div>
<div class="stat-item">
<div class="stat-content">
<span class="stat-value">Native</span>
<span class="stat-label">iOS & Android</span>
</div>
</div>
</div>
<div class="hero-image">
<div class="phone-frame">
<img src="screenshots/conduit-demo.gif" alt="Conduit App Demo">
</div>
</div>
</div>
</header>
</section>
<section id="features" class="features">
<div class="container">
<h2 class="section-title">Why Conduit?</h2>
<div class="features-grid">
<div class="feature-card">
<div class="feature-icon"></div>
<h3>Real-time Chat</h3>
<p>Stream responses from your AI models instantly with low latency WebSocket connections.</p>
<div class="section-header">
<span class="section-tag">What's inside</span>
<h2 class="section-title">Power meets<br><em>simplicity</em></h2>
</div>
<!-- Hero Feature -->
<div class="feature-hero">
<div class="feature-hero-content">
<div class="feature-hero-badge">
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>
</svg>
Signature Feature
</div>
<h3>Voice Call Mode</h3>
<p>Have a phone-style conversation with your AI. Speak naturally, hear responses read aloud, and chat completely hands-free.</p>
<ul class="feature-hero-list">
<li>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
Native CallKit integration on iOS
</li>
<li>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
Text-to-speech response playback
</li>
<li>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
Works in background & lock screen
</li>
</ul>
</div>
<div class="feature-card">
<div class="feature-icon">🎨</div>
<h3>Premium Design</h3>
<p>Beautifully crafted interface with light, dark, and system themes that feel right at home on your
device.</p>
<div class="feature-hero-visual">
<div class="feature-hero-icon">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/>
</svg>
</div>
<div class="feature-hero-rings">
<div class="ring"></div>
<div class="ring"></div>
<div class="ring"></div>
</div>
</div>
<div class="feature-card">
<div class="feature-icon">🔐</div>
<h3>Secure Storage</h3>
<p>Your credentials and API keys are stored securely using the platform's native keychain/keystore.
</p>
</div>
<!-- Feature Categories -->
<div class="feature-categories">
<!-- Voice & Input -->
<div class="feature-category">
<div class="category-header">
<div class="category-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/>
<path d="M19 10v2a7 7 0 0 1-14 0v-2"/>
</svg>
</div>
<h4>Voice & Input</h4>
</div>
<div class="category-features">
<div class="mini-feature">
<span class="mini-feature-name">Speech-to-Text</span>
<span class="mini-feature-desc">Dictate messages hands-free</span>
</div>
<div class="mini-feature">
<span class="mini-feature-name">Text-to-Speech</span>
<span class="mini-feature-desc">Hear AI responses read aloud</span>
</div>
<div class="mini-feature">
<span class="mini-feature-name">Share Extension</span>
<span class="mini-feature-desc">Send from any app to Conduit</span>
</div>
</div>
</div>
<div class="feature-card">
<div class="feature-icon">🎙️</div>
<h3>Voice Input</h3>
<p>Speak naturally to your AI with integrated speech-to-text support for hands-free interaction.</p>
<!-- System Integration -->
<div class="feature-category">
<div class="category-header">
<div class="category-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"/>
<line x1="8" y1="21" x2="16" y2="21"/>
<line x1="12" y1="17" x2="12" y2="21"/>
</svg>
</div>
<h4>System Integration</h4>
</div>
<div class="category-features">
<div class="mini-feature">
<span class="mini-feature-name">Siri Shortcuts</span>
<span class="mini-feature-desc">"Hey Siri, ask Conduit..."</span>
</div>
<div class="mini-feature">
<span class="mini-feature-name">Android Assistant</span>
<span class="mini-feature-desc">Trigger via digital assistant</span>
</div>
<div class="mini-feature">
<span class="mini-feature-name">Quick Actions</span>
<span class="mini-feature-desc">Home screen shortcuts</span>
</div>
</div>
</div>
<div class="feature-card">
<div class="feature-icon">📁</div>
<h3>File Uploads</h3>
<p>Upload images and documents for RAG (Retrieval-Augmented Generation) and vision capabilities.</p>
<!-- AI Capabilities -->
<div class="feature-category">
<div class="category-header">
<div class="category-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>
</svg>
</div>
<h4>AI Capabilities</h4>
</div>
<div class="category-features">
<div class="mini-feature">
<span class="mini-feature-name">Real-time Streaming</span>
<span class="mini-feature-desc">Instant WebSocket responses</span>
</div>
<div class="mini-feature">
<span class="mini-feature-name">Vision & RAG</span>
<span class="mini-feature-desc">Images & document analysis</span>
</div>
<div class="mini-feature">
<span class="mini-feature-name">Tool Support</span>
<span class="mini-feature-desc">Function calling & rendering</span>
</div>
</div>
</div>
<div class="feature-card">
<div class="feature-icon">🛠️</div>
<h3>Tool Support</h3>
<p>Full support for Open-WebUI tools and function calling with rich result rendering.</p>
<!-- Organization -->
<div class="feature-category">
<div class="category-header">
<div class="category-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
</svg>
</div>
<h4>Organization</h4>
</div>
<div class="category-features">
<div class="mini-feature">
<span class="mini-feature-name">Folders</span>
<span class="mini-feature-desc">Organize conversations</span>
</div>
<div class="mini-feature">
<span class="mini-feature-name">Search</span>
<span class="mini-feature-desc">Find across all history</span>
</div>
<div class="mini-feature">
<span class="mini-feature-name">Secure Storage</span>
<span class="mini-feature-desc">Native keychain/keystore</span>
</div>
</div>
</div>
</div>
</div>
</section>
<section id="screenshots" class="screenshots">
<section id="gallery" class="gallery">
<div class="container">
<h2 class="section-title">Experience Conduit</h2>
<div class="screenshot-gallery">
<div class="screenshot-item">
<img src="screenshots/1.png" alt="Chat Interface">
<p>Chat Interface</p>
<div class="section-header">
<span class="section-tag">See it in action</span>
<h2 class="section-title">Feels right<br><em>at home</em></h2>
</div>
<div class="gallery-showcase">
<div class="gallery-track">
<div class="gallery-item">
<img src="screenshots/1.png" alt="Chat Interface" loading="lazy">
<span class="gallery-label">Chat</span>
</div>
<div class="gallery-item">
<img src="screenshots/2.png" alt="Model Selector" loading="lazy">
<span class="gallery-label">Models</span>
</div>
<div class="gallery-item">
<img src="screenshots/3.png" alt="Navigation" loading="lazy">
<span class="gallery-label">Navigate</span>
</div>
<div class="gallery-item">
<img src="screenshots/4.png" alt="Settings" loading="lazy">
<span class="gallery-label">Settings</span>
</div>
</div>
<div class="screenshot-item">
<img src="screenshots/2.png" alt="Model Selector">
<p>Model Selector</p>
</div>
</div>
</section>
<section class="cta-section">
<div class="container">
<div class="cta-card">
<div class="cta-content">
<h2>Your AI awaits</h2>
<p>Free, open source, and ready when you are. Download now.</p>
<div class="cta-buttons">
<a href="https://apps.apple.com/us/app/conduit-open-webui-client/id6749840287" class="btn btn-white">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.81-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z"/>
</svg>
App Store
</a>
<a href="https://play.google.com/store/apps/details?id=app.cogwheel.conduit" class="btn btn-outline-white">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M3,20.5V3.5C3,2.91 3.34,2.39 3.84,2.15L13.69,12L3.84,21.85C3.34,21.6 3,21.09 3,20.5M16.81,15.12L6.05,21.34L14.54,12.85L16.81,15.12M20.16,10.81C20.5,11.08 20.75,11.5 20.75,12C20.75,12.5 20.53,12.9 20.18,13.18L17.89,14.5L15.39,12L17.89,9.5L20.16,10.81M6.05,2.66L16.81,8.88L14.54,11.15L6.05,2.66Z"/>
</svg>
Google Play
</a>
</div>
</div>
<div class="screenshot-item">
<img src="screenshots/3.png" alt="Navigation Drawer">
<p>Navigation</p>
</div>
<div class="screenshot-item">
<img src="screenshots/4.png" alt="Settings">
<p>Settings</p>
<div class="cta-decoration">
<div class="cta-ring"></div>
<div class="cta-ring"></div>
<div class="cta-ring"></div>
</div>
</div>
</div>
@@ -142,20 +378,42 @@
<footer class="footer">
<div class="container">
<div class="footer-content">
<div class="footer-logo">
<h3>Conduit</h3>
<p>The native mobile client for Open-WebUI.</p>
<div class="footer-main">
<div class="footer-brand">
<a href="#" class="logo">
<span class="logo-mark"></span>
<span class="logo-text">Conduit</span>
</a>
<p>The native mobile client for Open-WebUI.<br>Open source. Privacy-first. Beautiful.</p>
</div>
<div class="footer-links">
<h4>Links</h4>
<a href="https://github.com/cogwheel0/conduit">GitHub</a>
<a href="https://github.com/cogwheel0/conduit/issues">Issues</a>
<a href="https://github.com/cogwheel0/conduit/discussions">Discussions</a>
<div class="footer-links-grid">
<div class="footer-col">
<h4>Product</h4>
<a href="#features">Features</a>
<a href="#gallery">Gallery</a>
<a href="https://github.com/cogwheel0/conduit/releases">Releases</a>
</div>
<div class="footer-col">
<h4>Community</h4>
<a href="https://github.com/cogwheel0/conduit">GitHub</a>
<a href="https://github.com/cogwheel0/conduit/issues">Issues</a>
<a href="https://github.com/cogwheel0/conduit/discussions">Discussions</a>
</div>
<div class="footer-col">
<h4>Legal</h4>
<a href="https://github.com/cogwheel0/conduit/blob/main/LICENSE">License (GPLv3)</a>
<a href="https://github.com/cogwheel0/conduit/blob/main/PRIVACY_POLICY.md">Privacy Policy</a>
</div>
</div>
<div class="footer-legal">
<p>&copy; 2025 Conduit. Licensed under GPLv3.</p>
<p>Not affiliated with Open-WebUI.</p>
</div>
<div class="footer-bottom">
<p>&copy; 2025 Conduit. Not affiliated with Open-WebUI.</p>
<div class="footer-social">
<a href="https://github.com/cogwheel0/conduit" aria-label="GitHub">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
</svg>
</a>
</div>
</div>
</div>

View File

@@ -1,21 +1,79 @@
/**
* Conduit Landing Page
* Smooth interactions and animations
*/
document.addEventListener('DOMContentLoaded', () => {
// Smooth scrolling for anchor links
// ============================================
// SMOOTH SCROLL
// ============================================
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
const targetId = this.getAttribute('href');
if (targetId === '#') return;
const target = document.querySelector(targetId);
if (target) {
target.scrollIntoView({
const navHeight = document.querySelector('.navbar').offsetHeight;
const targetPosition = target.offsetTop - navHeight - 20;
window.scrollTo({
top: targetPosition,
behavior: 'smooth'
});
// Close mobile menu if open
mobileMenu.classList.remove('active');
}
});
});
// Intersection Observer for fade-in animations
// ============================================
// MOBILE MENU
// ============================================
const mobileMenuBtn = document.querySelector('.mobile-menu-btn');
const mobileMenu = document.querySelector('.mobile-menu');
if (mobileMenuBtn && mobileMenu) {
mobileMenuBtn.addEventListener('click', () => {
mobileMenu.classList.toggle('active');
mobileMenuBtn.classList.toggle('active');
});
// Close menu when clicking a link
mobileMenu.querySelectorAll('a').forEach(link => {
link.addEventListener('click', () => {
mobileMenu.classList.remove('active');
mobileMenuBtn.classList.remove('active');
});
});
}
// ============================================
// NAVBAR SCROLL EFFECT
// ============================================
const navbar = document.querySelector('.navbar');
let lastScroll = 0;
window.addEventListener('scroll', () => {
const currentScroll = window.pageYOffset;
if (currentScroll > 100) {
navbar.style.background = 'rgba(10, 10, 12, 0.9)';
} else {
navbar.style.background = 'rgba(10, 10, 12, 0.6)';
}
lastScroll = currentScroll;
}, { passive: true });
// ============================================
// INTERSECTION OBSERVER - FADE IN
// ============================================
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
rootMargin: '0px 0px -60px 0px'
};
const observer = new IntersectionObserver((entries) => {
@@ -27,32 +85,249 @@ document.addEventListener('DOMContentLoaded', () => {
});
}, observerOptions);
// Add fade-in class to elements we want to animate
const animatedElements = document.querySelectorAll('.feature-card, .screenshot-item, .hero-content, .hero-image');
animatedElements.forEach(el => {
// Observe feature cards
document.querySelectorAll('.feature-card').forEach(el => {
el.classList.add('fade-in');
observer.observe(el);
});
// Observe stat cards
document.querySelectorAll('.stat-card').forEach((el, i) => {
el.classList.add('fade-in');
el.style.transitionDelay = `${i * 0.1}s`;
observer.observe(el);
});
// Observe gallery items
document.querySelectorAll('.gallery-item').forEach((el, i) => {
el.classList.add('fade-in');
el.style.transitionDelay = `${i * 0.1}s`;
observer.observe(el);
});
// Observe section headers
document.querySelectorAll('.section-header').forEach(el => {
el.classList.add('fade-in');
observer.observe(el);
});
// ============================================
// PARALLAX ORBS (subtle effect)
// ============================================
const orbs = document.querySelectorAll('.orb');
if (window.matchMedia('(prefers-reduced-motion: no-preference)').matches) {
window.addEventListener('scroll', () => {
const scrollY = window.pageYOffset;
orbs.forEach((orb, i) => {
const speed = (i + 1) * 0.03;
orb.style.transform = `translateY(${scrollY * speed}px)`;
});
}, { passive: true });
}
// ============================================
// DEVICE FRAME TILT ON MOUSE MOVE
// ============================================
const deviceFrame = document.querySelector('.device-frame');
const heroSection = document.querySelector('.hero');
if (deviceFrame && heroSection && window.matchMedia('(prefers-reduced-motion: no-preference)').matches) {
heroSection.addEventListener('mousemove', (e) => {
const rect = heroSection.getBoundingClientRect();
const x = (e.clientX - rect.left) / rect.width - 0.5;
const y = (e.clientY - rect.top) / rect.height - 0.5;
const tiltX = y * 10;
const tiltY = -x * 10;
deviceFrame.style.transform = `perspective(1000px) rotateX(${tiltX}deg) rotateY(${tiltY}deg) scale(1.02)`;
});
heroSection.addEventListener('mouseleave', () => {
deviceFrame.style.transform = 'perspective(1000px) rotateX(0) rotateY(0) scale(1)';
});
}
// ============================================
// GALLERY DRAG SCROLL
// ============================================
const galleryTrack = document.querySelector('.gallery-track');
if (galleryTrack) {
let isDown = false;
let startX;
let scrollLeft;
galleryTrack.addEventListener('mousedown', (e) => {
isDown = true;
galleryTrack.style.cursor = 'grabbing';
startX = e.pageX - galleryTrack.offsetLeft;
scrollLeft = galleryTrack.scrollLeft;
});
galleryTrack.addEventListener('mouseleave', () => {
isDown = false;
galleryTrack.style.cursor = 'grab';
});
galleryTrack.addEventListener('mouseup', () => {
isDown = false;
galleryTrack.style.cursor = 'grab';
});
galleryTrack.addEventListener('mousemove', (e) => {
if (!isDown) return;
e.preventDefault();
const x = e.pageX - galleryTrack.offsetLeft;
const walk = (x - startX) * 1.5;
galleryTrack.scrollLeft = scrollLeft - walk;
});
// Set initial cursor
galleryTrack.style.cursor = 'grab';
}
// ============================================
// CTA RING ANIMATION RESET
// ============================================
const ctaSection = document.querySelector('.cta-section');
const ctaRings = document.querySelectorAll('.cta-ring');
if (ctaSection && ctaRings.length) {
const ctaObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// Reset animation when section comes into view
ctaRings.forEach(ring => {
ring.style.animation = 'none';
ring.offsetHeight; // Trigger reflow
ring.style.animation = null;
});
}
});
}, { threshold: 0.3 });
ctaObserver.observe(ctaSection);
}
// ============================================
// BUTTON RIPPLE EFFECT
// ============================================
document.querySelectorAll('.btn').forEach(btn => {
btn.addEventListener('click', function(e) {
const ripple = document.createElement('span');
const rect = this.getBoundingClientRect();
ripple.style.cssText = `
position: absolute;
background: rgba(255, 255, 255, 0.3);
border-radius: 50%;
pointer-events: none;
transform: scale(0);
animation: ripple 0.6s ease-out;
left: ${e.clientX - rect.left}px;
top: ${e.clientY - rect.top}px;
width: 0;
height: 0;
`;
this.style.position = 'relative';
this.style.overflow = 'hidden';
this.appendChild(ripple);
setTimeout(() => ripple.remove(), 600);
});
});
// Add ripple keyframes
const style = document.createElement('style');
style.textContent = `
@keyframes ripple {
to {
width: 200px;
height: 200px;
margin-left: -100px;
margin-top: -100px;
opacity: 0;
transform: scale(1);
}
}
`;
document.head.appendChild(style);
// ============================================
// PRELOAD IMAGES
// ============================================
const preloadImages = [
'screenshots/1.png',
'screenshots/2.png',
'screenshots/3.png',
'screenshots/4.png'
];
preloadImages.forEach(src => {
const img = new Image();
img.src = src;
});
// ============================================
// FETCH GITHUB STATS
// ============================================
const formatNumber = (num) => {
if (num >= 1000000) {
return (num / 1000000).toFixed(1).replace(/\.0$/, '') + 'M';
}
if (num >= 1000) {
return (num / 1000).toFixed(1).replace(/\.0$/, '') + 'k';
}
return num.toString();
};
const starsElement = document.getElementById('github-stars');
const downloadsElement = document.getElementById('github-downloads');
// Fetch repo stats (stars)
if (starsElement) {
fetch('https://api.github.com/repos/cogwheel0/conduit')
.then(response => response.json())
.then(data => {
if (data.stargazers_count !== undefined) {
starsElement.textContent = formatNumber(data.stargazers_count);
starsElement.classList.add('loaded');
}
})
.catch(() => {
starsElement.textContent = '★';
});
}
// Fetch releases (downloads)
if (downloadsElement) {
fetch('https://api.github.com/repos/cogwheel0/conduit/releases')
.then(response => response.json())
.then(releases => {
if (Array.isArray(releases)) {
const totalDownloads = releases.reduce((total, release) => {
return total + release.assets.reduce((assetTotal, asset) => {
return assetTotal + (asset.download_count || 0);
}, 0);
}, 0);
if (totalDownloads > 0) {
downloadsElement.textContent = formatNumber(totalDownloads);
} else {
// If no GitHub downloads, show a generic indicator
downloadsElement.textContent = 'New';
}
downloadsElement.classList.add('loaded');
}
})
.catch(() => {
downloadsElement.textContent = '↓';
});
}
console.log('✨ Conduit landing page initialized');
});
// Add this CSS to styles.css dynamically or ensure it's in the CSS file
const style = document.createElement('style');
style.textContent = `
.fade-in {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
}
.fade-in.visible {
opacity: 1;
transform: translateY(0);
}
.feature-card:nth-child(2) { transition-delay: 0.1s; }
.feature-card:nth-child(3) { transition-delay: 0.2s; }
.feature-card:nth-child(4) { transition-delay: 0.3s; }
.feature-card:nth-child(5) { transition-delay: 0.4s; }
.feature-card:nth-child(6) { transition-delay: 0.5s; }
`;
document.head.appendChild(style);

File diff suppressed because it is too large Load Diff