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:
@ -5,6 +5,7 @@ import { useRouter } from 'next/navigation'
|
||||
import { useStore } from '@/lib/store'
|
||||
import { api } from '@/lib/api'
|
||||
import { Header } from '@/components/Header'
|
||||
import { Footer } from '@/components/Footer'
|
||||
import {
|
||||
Plus,
|
||||
Trash2,
|
||||
@ -560,6 +561,8 @@ export default function DashboardPage() {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Header } from '@/components/Header'
|
||||
import { Footer } from '@/components/Footer'
|
||||
import { DomainChecker } from '@/components/DomainChecker'
|
||||
import { useStore } from '@/lib/store'
|
||||
import { api } from '@/lib/api'
|
||||
@ -148,7 +149,7 @@ export default function HomePage() {
|
||||
|
||||
{/* 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">
|
||||
<div className="max-w-6xl mx-auto text-center">
|
||||
<div className="max-w-7xl mx-auto text-center">
|
||||
{/* 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="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 */}
|
||||
<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 */}
|
||||
<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">
|
||||
@ -287,7 +288,7 @@ export default function HomePage() {
|
||||
|
||||
{/* Features Section */}
|
||||
<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">
|
||||
<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">
|
||||
@ -414,25 +415,7 @@ export default function HomePage() {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* 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>
|
||||
<Footer />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useParams } from 'next/navigation'
|
||||
import { Header } from '@/components/Header'
|
||||
import { Footer } from '@/components/Footer'
|
||||
import { api } from '@/lib/api'
|
||||
import {
|
||||
ArrowLeft,
|
||||
@ -398,6 +399,8 @@ export default function TldDetailPage() {
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -48,7 +48,7 @@ interface TldHistoryData {
|
||||
type SortField = 'tld' | 'avg_registration_price' | 'min_registration_price' | 'registrar_count'
|
||||
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 }) {
|
||||
const [historyData, setHistoryData] = useState<number[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
@ -61,8 +61,7 @@ function MiniChart({ tld, isAuthenticated }: { tld: string, isAuthenticated: boo
|
||||
|
||||
const loadHistory = async () => {
|
||||
try {
|
||||
const data = await api.getTldHistory(tld, 365) // Get 1 year of data
|
||||
// Sample down to 12 data points (monthly)
|
||||
const data = await api.getTldHistory(tld, 365)
|
||||
const history = data.history || []
|
||||
const sampledData = history
|
||||
.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 max = Math.max(...historyData)
|
||||
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 y = 100 - ((value - min) / range) * 100
|
||||
const y = 100 - ((value - min) / range) * 80 - 10 // Add padding
|
||||
return `${x},${y}`
|
||||
}).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 (
|
||||
<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
|
||||
points={points}
|
||||
points={linePoints}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="3"
|
||||
strokeWidth="2.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className={clsx(
|
||||
"transition-colors",
|
||||
isIncreasing ? "text-[#f97316]/60" : "text-accent/60"
|
||||
"transition-all duration-300",
|
||||
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>
|
||||
)
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ export function Header() {
|
||||
|
||||
return (
|
||||
<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 */}
|
||||
<div className="flex items-center gap-6 sm:gap-8">
|
||||
{/* Logo */}
|
||||
|
||||
Reference in New Issue
Block a user