Improve UX: Add Footer everywhere, unified max-width, beautiful charts

- Added Footer component to all pages (home, dashboard, TLD pages)
- Changed max-width from 6xl to 7xl for consistent layout
- Enhanced mini-charts with gradients, area fills, and data points
- Better visual hierarchy and spacing
- Consistent design across all pages
This commit is contained in:
2025-12-08 07:46:58 +01:00
parent d12c5ddfa5
commit 48b33e9252
5 changed files with 75 additions and 35 deletions

View File

@ -5,6 +5,7 @@ import { useRouter } from 'next/navigation'
import { useStore } from '@/lib/store' import { useStore } from '@/lib/store'
import { api } from '@/lib/api' import { api } from '@/lib/api'
import { Header } from '@/components/Header' import { Header } from '@/components/Header'
import { Footer } from '@/components/Footer'
import { import {
Plus, Plus,
Trash2, Trash2,
@ -560,6 +561,8 @@ export default function DashboardPage() {
</div> </div>
</div> </div>
)} )}
<Footer />
</div> </div>
) )
} }

View File

@ -2,6 +2,7 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { Header } from '@/components/Header' import { Header } from '@/components/Header'
import { Footer } from '@/components/Footer'
import { DomainChecker } from '@/components/DomainChecker' import { DomainChecker } from '@/components/DomainChecker'
import { useStore } from '@/lib/store' import { useStore } from '@/lib/store'
import { api } from '@/lib/api' import { api } from '@/lib/api'
@ -148,7 +149,7 @@ export default function HomePage() {
{/* Hero Section */} {/* Hero Section */}
<section className="relative pt-32 sm:pt-36 md:pt-40 lg:pt-48 pb-16 sm:pb-20 px-4 sm:px-6"> <section className="relative pt-32 sm:pt-36 md:pt-40 lg:pt-48 pb-16 sm:pb-20 px-4 sm:px-6">
<div className="max-w-6xl mx-auto text-center"> <div className="max-w-7xl mx-auto text-center">
{/* Tagline */} {/* Tagline */}
<div className="inline-flex items-center gap-2 sm:gap-2.5 px-3 sm:px-4 py-1.5 sm:py-2 bg-background-secondary/80 backdrop-blur-sm border border-border rounded-full mb-6 sm:mb-8 md:mb-10 animate-fade-in"> <div className="inline-flex items-center gap-2 sm:gap-2.5 px-3 sm:px-4 py-1.5 sm:py-2 bg-background-secondary/80 backdrop-blur-sm border border-border rounded-full mb-6 sm:mb-8 md:mb-10 animate-fade-in">
<div className="w-1.5 h-1.5 rounded-full bg-accent animate-glow-pulse" /> <div className="w-1.5 h-1.5 rounded-full bg-accent animate-glow-pulse" />
@ -176,7 +177,7 @@ export default function HomePage() {
{/* TLD Price Intelligence Section */} {/* TLD Price Intelligence Section */}
<section className="relative py-16 sm:py-20 md:py-24 px-4 sm:px-6 border-t border-border-subtle"> <section className="relative py-16 sm:py-20 md:py-24 px-4 sm:px-6 border-t border-border-subtle">
<div className="max-w-6xl mx-auto"> <div className="max-w-7xl mx-auto">
{/* Section Header */} {/* Section Header */}
<div className="text-center mb-10 sm:mb-12"> <div className="text-center mb-10 sm:mb-12">
<div className="inline-flex items-center gap-2 px-3 py-1.5 bg-accent-muted border border-accent/20 rounded-full mb-5"> <div className="inline-flex items-center gap-2 px-3 py-1.5 bg-accent-muted border border-accent/20 rounded-full mb-5">
@ -287,7 +288,7 @@ export default function HomePage() {
{/* Features Section */} {/* Features Section */}
<section className="relative py-20 sm:py-24 md:py-32 px-4 sm:px-6"> <section className="relative py-20 sm:py-24 md:py-32 px-4 sm:px-6">
<div className="max-w-6xl mx-auto"> <div className="max-w-7xl mx-auto">
<div className="text-center mb-12 sm:mb-16 md:mb-20"> <div className="text-center mb-12 sm:mb-16 md:mb-20">
<p className="label sm:label-md text-accent mb-3 sm:mb-4 md:mb-5">How It Works</p> <p className="label sm:label-md text-accent mb-3 sm:mb-4 md:mb-5">How It Works</p>
<h2 className="font-display text-[1.75rem] sm:text-[2.5rem] md:text-[3.25rem] lg:text-[4rem] leading-[1.1] tracking-[-0.03em] text-foreground mb-4 sm:mb-5 md:mb-6"> <h2 className="font-display text-[1.75rem] sm:text-[2.5rem] md:text-[3.25rem] lg:text-[4rem] leading-[1.1] tracking-[-0.03em] text-foreground mb-4 sm:mb-5 md:mb-6">
@ -414,25 +415,7 @@ export default function HomePage() {
</div> </div>
</section> </section>
{/* Footer */} <Footer />
<footer className="py-8 sm:py-10 px-4 sm:px-6 border-t border-border-subtle">
<div className="max-w-6xl mx-auto flex flex-col sm:flex-row items-center justify-between gap-4 sm:gap-6">
<p className="text-ui-sm sm:text-ui text-foreground-subtle">
© 2024 pounce
</p>
<div className="flex items-center gap-6 sm:gap-8">
<Link href="/tld-pricing" className="text-ui-sm sm:text-ui text-foreground-subtle hover:text-foreground transition-colors duration-300">
TLD Pricing
</Link>
<Link href="/pricing" className="text-ui-sm sm:text-ui text-foreground-subtle hover:text-foreground transition-colors duration-300">
Plans
</Link>
<Link href="/login" className="text-ui-sm sm:text-ui text-foreground-subtle hover:text-foreground transition-colors duration-300">
Sign In
</Link>
</div>
</div>
</footer>
</div> </div>
) )
} }

View File

@ -3,6 +3,7 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useParams } from 'next/navigation' import { useParams } from 'next/navigation'
import { Header } from '@/components/Header' import { Header } from '@/components/Header'
import { Footer } from '@/components/Footer'
import { api } from '@/lib/api' import { api } from '@/lib/api'
import { import {
ArrowLeft, ArrowLeft,
@ -398,6 +399,8 @@ export default function TldDetailPage() {
</div> </div>
</div> </div>
</main> </main>
<Footer />
</div> </div>
) )
} }

View File

@ -48,7 +48,7 @@ interface TldHistoryData {
type SortField = 'tld' | 'avg_registration_price' | 'min_registration_price' | 'registrar_count' type SortField = 'tld' | 'avg_registration_price' | 'min_registration_price' | 'registrar_count'
type SortDirection = 'asc' | 'desc' type SortDirection = 'asc' | 'desc'
// Mini sparkline chart component with real data // Mini sparkline chart component with real data - Enhanced version
function MiniChart({ tld, isAuthenticated }: { tld: string, isAuthenticated: boolean }) { function MiniChart({ tld, isAuthenticated }: { tld: string, isAuthenticated: boolean }) {
const [historyData, setHistoryData] = useState<number[]>([]) const [historyData, setHistoryData] = useState<number[]>([])
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
@ -61,8 +61,7 @@ function MiniChart({ tld, isAuthenticated }: { tld: string, isAuthenticated: boo
const loadHistory = async () => { const loadHistory = async () => {
try { try {
const data = await api.getTldHistory(tld, 365) // Get 1 year of data const data = await api.getTldHistory(tld, 365)
// Sample down to 12 data points (monthly)
const history = data.history || [] const history = data.history || []
const sampledData = history const sampledData = history
.filter((_, i) => i % Math.floor(history.length / 12) === 0) .filter((_, i) => i % Math.floor(history.length / 12) === 0)
@ -90,27 +89,79 @@ function MiniChart({ tld, isAuthenticated }: { tld: string, isAuthenticated: boo
const min = Math.min(...historyData) const min = Math.min(...historyData)
const max = Math.max(...historyData) const max = Math.max(...historyData)
const range = max - min || 1 const range = max - min || 1
const isIncreasing = historyData[historyData.length - 1] > historyData[0]
const points = historyData.map((value, i) => { // Create line points
const linePoints = historyData.map((value, i) => {
const x = (i / (historyData.length - 1)) * 100 const x = (i / (historyData.length - 1)) * 100
const y = 100 - ((value - min) / range) * 100 const y = 100 - ((value - min) / range) * 80 - 10 // Add padding
return `${x},${y}` return `${x},${y}`
}).join(' ') }).join(' ')
const isIncreasing = historyData[historyData.length - 1] > historyData[0] // Create area path for gradient fill
const areaPath = historyData.map((value, i) => {
const x = (i / (historyData.length - 1)) * 100
const y = 100 - ((value - min) / range) * 80 - 10
return i === 0 ? `M${x},${y}` : `L${x},${y}`
}).join(' ') + ' L100,100 L0,100 Z'
const gradientId = `gradient-${tld}`
return ( return (
<svg className="w-24 h-8" viewBox="0 0 100 100" preserveAspectRatio="none"> <svg className="w-32 h-10" viewBox="0 0 100 100" preserveAspectRatio="none">
<defs>
<linearGradient id={gradientId} x1="0%" y1="0%" x2="0%" y2="100%">
<stop
offset="0%"
stopColor={isIncreasing ? "#f97316" : "#00d4aa"}
stopOpacity="0.3"
/>
<stop
offset="100%"
stopColor={isIncreasing ? "#f97316" : "#00d4aa"}
stopOpacity="0.02"
/>
</linearGradient>
</defs>
{/* Area fill */}
<path
d={areaPath}
fill={`url(#${gradientId})`}
className="transition-all duration-300"
/>
{/* Line */}
<polyline <polyline
points={points} points={linePoints}
fill="none" fill="none"
stroke="currentColor" strokeWidth="2.5"
strokeWidth="3" strokeLinecap="round"
strokeLinejoin="round"
className={clsx( className={clsx(
"transition-colors", "transition-all duration-300",
isIncreasing ? "text-[#f97316]/60" : "text-accent/60" isIncreasing ? "stroke-[#f97316]" : "stroke-accent"
)} )}
/> />
{/* Dots for each data point */}
{historyData.map((value, i) => {
const x = (i / (historyData.length - 1)) * 100
const y = 100 - ((value - min) / range) * 80 - 10
return (
<circle
key={i}
cx={x}
cy={y}
r="1.5"
className={clsx(
"transition-all duration-300",
isIncreasing ? "fill-[#f97316]" : "fill-accent"
)}
opacity={i === historyData.length - 1 ? "1" : "0.4"}
/>
)
})}
</svg> </svg>
) )
} }

View File

@ -27,7 +27,7 @@ export function Header() {
return ( return (
<header className="fixed top-0 left-0 right-0 z-50 bg-background/80 backdrop-blur-xl border-b border-border-subtle"> <header className="fixed top-0 left-0 right-0 z-50 bg-background/80 backdrop-blur-xl border-b border-border-subtle">
<div className="max-w-6xl mx-auto px-4 sm:px-6 h-14 sm:h-16 flex items-center justify-between"> <div className="max-w-7xl mx-auto px-4 sm:px-6 h-14 sm:h-16 flex items-center justify-between">
{/* Left side: Logo + Nav Links */} {/* Left side: Logo + Nav Links */}
<div className="flex items-center gap-6 sm:gap-8"> <div className="flex items-center gap-6 sm:gap-8">
{/* Logo */} {/* Logo */}