fix(landing): design audit fixes — hamburger menu, dead links, branding, spacing (#117)
* fix(landing): design audit fixes — hamburger menu, dead links, branding, spacing - Add mobile hamburger menu with animated open/close and click-outside dismiss - Create Privacy and Terms pages (footer links were dead # anchors) - Change "Decision Tree Platform" to "AI-Powered Troubleshooting for MSPs" on login, register, and HTML title - Fix register page icon color (was red/coral via CSS invert, now uses BrandLogo directly) - Replace "0 Ticket Notes Written by Hand" stat with "100% Auto-Generated Documentation" - Increase nav link touch targets to 44px minimum - Fix heading hierarchy: section titles are now <h2>, standardize H3 to 1.25rem - Tighten section spacing (6rem → 4rem padding, remove extra 5rem spacer) - Add color-scheme: dark to HTML element - Replace all transition: all with specific properties (10 occurrences) - Fix loading ellipsis (... → …) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(mobile): responsive modals + landing preview overflow - PrepareSessionModal: bottom-sheet on mobile, centered on desktop - IntakeFormModal: bottom-sheet on mobile, responsive padding - ShareTreeModal: bottom-sheet on mobile, full-width on small screens - Landing preview: hide URL bar and window controls on mobile (<900px) to prevent 189px horizontal overflow Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(mobile): collapse search bar to icon on mobile On mobile (<640px), the full search bar with placeholder text and ⌘K badge was taking too much space in the topbar. Now shows just a magnifying glass icon that opens the same command palette on tap. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: chihlasm <michael@resolutionflow.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit was merged in pull request #117.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect, useCallback } from 'react'
|
||||
import { useState, useEffect, useCallback, useRef } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { PageMeta } from '@/components/common/PageMeta'
|
||||
import '@/styles/landing.css'
|
||||
@@ -7,8 +7,10 @@ const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000'
|
||||
|
||||
export default function LandingPage() {
|
||||
const [navScrolled, setNavScrolled] = useState(false)
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
||||
const [betaEmail, setBetaEmail] = useState('')
|
||||
const [betaStatus, setBetaStatus] = useState<'idle' | 'sending' | 'sent' | 'error'>('idle')
|
||||
const mobileMenuRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
// Nav scroll effect
|
||||
useEffect(() => {
|
||||
@@ -17,6 +19,22 @@ export default function LandingPage() {
|
||||
return () => window.removeEventListener('scroll', handleScroll)
|
||||
}, [])
|
||||
|
||||
// Close mobile menu on click outside
|
||||
useEffect(() => {
|
||||
function handleClickOutside(e: MouseEvent) {
|
||||
if (mobileMenuRef.current && !mobileMenuRef.current.contains(e.target as Node)) {
|
||||
setMobileMenuOpen(false)
|
||||
}
|
||||
}
|
||||
if (mobileMenuOpen) {
|
||||
document.addEventListener('mousedown', handleClickOutside)
|
||||
return () => document.removeEventListener('mousedown', handleClickOutside)
|
||||
}
|
||||
}, [mobileMenuOpen])
|
||||
|
||||
// Close mobile menu on scroll to section
|
||||
const handleMobileNavClick = () => setMobileMenuOpen(false)
|
||||
|
||||
// Scroll reveal
|
||||
useEffect(() => {
|
||||
const els = document.querySelectorAll('.landing-reveal')
|
||||
@@ -64,7 +82,7 @@ export default function LandingPage() {
|
||||
|
||||
<div className="landing-page-content">
|
||||
{/* Navigation */}
|
||||
<nav className={`landing-nav ${navScrolled ? 'scrolled' : ''}`}>
|
||||
<nav className={`landing-nav ${navScrolled ? 'scrolled' : ''}`} ref={mobileMenuRef}>
|
||||
<div className="landing-nav-inner">
|
||||
<a href="#" className="landing-nav-logo">
|
||||
<div className="landing-nav-logo-icon">
|
||||
@@ -88,7 +106,27 @@ export default function LandingPage() {
|
||||
<Link to="/login" className="landing-btn-ghost">Sign In</Link>
|
||||
<Link to="/register" className="landing-btn-primary">Get Started Free</Link>
|
||||
</div>
|
||||
<button
|
||||
className={`landing-hamburger ${mobileMenuOpen ? 'open' : ''}`}
|
||||
onClick={() => setMobileMenuOpen(v => !v)}
|
||||
aria-label="Toggle menu"
|
||||
aria-expanded={mobileMenuOpen}
|
||||
>
|
||||
<span />
|
||||
<span />
|
||||
<span />
|
||||
</button>
|
||||
</div>
|
||||
{mobileMenuOpen && (
|
||||
<div className="landing-mobile-menu">
|
||||
<a href="#features" onClick={handleMobileNavClick}>Features</a>
|
||||
<a href="#how-it-works" onClick={handleMobileNavClick}>How It Works</a>
|
||||
<a href="#pricing" onClick={handleMobileNavClick}>Pricing</a>
|
||||
<div className="landing-mobile-menu-divider" />
|
||||
<Link to="/login" onClick={handleMobileNavClick}>Sign In</Link>
|
||||
<Link to="/register" className="landing-btn-primary" onClick={handleMobileNavClick} style={{ textAlign: 'center' }}>Get Started Free</Link>
|
||||
</div>
|
||||
)}
|
||||
</nav>
|
||||
|
||||
{/* Hero */}
|
||||
@@ -120,8 +158,8 @@ export default function LandingPage() {
|
||||
<div className="label">Less Time on Documentation</div>
|
||||
</div>
|
||||
<div className="landing-proof-stat">
|
||||
<div className="number">0</div>
|
||||
<div className="label">Ticket Notes Written by Hand</div>
|
||||
<div className="number">100%</div>
|
||||
<div className="label">Auto-Generated Documentation</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -198,14 +236,13 @@ export default function LandingPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ height: '5rem' }} />
|
||||
<div className="landing-section-divider" />
|
||||
|
||||
{/* Problem Section */}
|
||||
<section id="problem" className="landing-reveal">
|
||||
<div className="landing-section-inner">
|
||||
<div className="landing-section-label">The Problem</div>
|
||||
<div className="landing-section-title">Documentation is broken.<br />Everyone knows it.</div>
|
||||
<h2 className="landing-section-title">Documentation is broken.<br />Everyone knows it.</h2>
|
||||
<div className="landing-section-desc">
|
||||
Engineers don't want to write it. Managers hate chasing it. Clients never see it. The same issues get solved from scratch every time.
|
||||
</div>
|
||||
@@ -243,7 +280,7 @@ export default function LandingPage() {
|
||||
<section id="how-it-works" className="landing-reveal">
|
||||
<div className="landing-section-inner">
|
||||
<div className="landing-section-label">How It Works</div>
|
||||
<div className="landing-section-title">Three steps. Zero note-writing.</div>
|
||||
<h2 className="landing-section-title">Three steps. Zero note-writing.</h2>
|
||||
<div className="landing-section-desc">
|
||||
Build once, run forever. Every session generates documentation automatically.
|
||||
</div>
|
||||
@@ -312,7 +349,7 @@ export default function LandingPage() {
|
||||
<section id="features" className="landing-reveal">
|
||||
<div className="landing-section-inner">
|
||||
<div className="landing-section-label">Features</div>
|
||||
<div className="landing-section-title">Everything your team needs to<br />resolve faster and document better.</div>
|
||||
<h2 className="landing-section-title">Everything your team needs to<br />resolve faster and document better.</h2>
|
||||
<div className="landing-features-grid">
|
||||
<FeatureCard
|
||||
highlight
|
||||
@@ -355,7 +392,7 @@ export default function LandingPage() {
|
||||
<section id="pricing" className="landing-reveal">
|
||||
<div className="landing-section-inner">
|
||||
<div className="landing-section-label">Pricing</div>
|
||||
<div className="landing-section-title">Simple pricing. No surprises.</div>
|
||||
<h2 className="landing-section-title">Simple pricing. No surprises.</h2>
|
||||
<div className="landing-section-desc">Start free. Upgrade when your team is ready.</div>
|
||||
<div className="landing-pricing-grid">
|
||||
<PricingCard
|
||||
@@ -453,8 +490,8 @@ export default function LandingPage() {
|
||||
<span className="landing-footer-copy">© 2026 ResolutionFlow. All rights reserved.</span>
|
||||
</div>
|
||||
<ul className="landing-footer-links">
|
||||
<li><a href="#">Privacy</a></li>
|
||||
<li><a href="#">Terms</a></li>
|
||||
<li><Link to="/privacy">Privacy</Link></li>
|
||||
<li><Link to="/terms">Terms</Link></li>
|
||||
<li><a href="mailto:hello@resolutionflow.com">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user