Seed: blog template (17 files)
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Twitter, Github, Linkedin, Rss, Mail } from "lucide-react";
|
||||
import { useSaasMutation } from "@/hooks/use-tygarun";
|
||||
|
||||
const categoryLinks = [
|
||||
{ label: "Technology", to: "/category/technology" },
|
||||
{ label: "Design", to: "/category/design" },
|
||||
{ label: "Business", to: "/category/business" },
|
||||
{ label: "Lifestyle", to: "/category/lifestyle" },
|
||||
];
|
||||
|
||||
const quickLinks = [
|
||||
{ label: "About", to: "/" },
|
||||
{ label: "Contact", to: "/" },
|
||||
{ label: "Privacy Policy", to: "/" },
|
||||
{ label: "Terms of Service", to: "/" },
|
||||
{ label: "RSS Feed", to: "/" },
|
||||
];
|
||||
|
||||
export default function Footer() {
|
||||
const [email, setEmail] = useState("");
|
||||
const [subscribed, setSubscribed] = useState(false);
|
||||
const { mutate: subscribeNewsletter, loading: subscribing } = useSaasMutation("email", "/send/newsletter-confirm");
|
||||
|
||||
const handleSubscribe = async (e) => {
|
||||
e.preventDefault();
|
||||
if (!email) return;
|
||||
try {
|
||||
await subscribeNewsletter({ email });
|
||||
setSubscribed(true);
|
||||
toast.success("Subscribed! Check your inbox.");
|
||||
} catch {
|
||||
toast.error("Could not subscribe. Please try again.");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<footer className="bg-stone-900 text-white">
|
||||
<div className="mx-auto max-w-7xl px-6 py-24">
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-10">
|
||||
{/* Brand */}
|
||||
<div className="md:col-span-1">
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<div className="h-8 w-8 rounded-lg bg-emerald-500 flex items-center justify-center">
|
||||
<span className="text-white font-bold text-sm">B</span>
|
||||
</div>
|
||||
<span className="text-lg font-bold">ByteSize</span>
|
||||
</div>
|
||||
<p className="text-sm text-stone-400 leading-relaxed mb-6">
|
||||
ByteSize is a modern publication exploring technology, design, business, and lifestyle through thoughtful long-form writing.
|
||||
</p>
|
||||
<div className="flex items-center gap-3">
|
||||
<a href="#" className="h-8 w-8 rounded-full bg-stone-800 flex items-center justify-center text-stone-400 hover:text-white hover:bg-stone-700 transition-colors">
|
||||
<Twitter className="h-4 w-4" />
|
||||
</a>
|
||||
<a href="#" className="h-8 w-8 rounded-full bg-stone-800 flex items-center justify-center text-stone-400 hover:text-white hover:bg-stone-700 transition-colors">
|
||||
<Github className="h-4 w-4" />
|
||||
</a>
|
||||
<a href="#" className="h-8 w-8 rounded-full bg-stone-800 flex items-center justify-center text-stone-400 hover:text-white hover:bg-stone-700 transition-colors">
|
||||
<Linkedin className="h-4 w-4" />
|
||||
</a>
|
||||
<a href="#" className="h-8 w-8 rounded-full bg-stone-800 flex items-center justify-center text-stone-400 hover:text-white hover:bg-stone-700 transition-colors">
|
||||
<Rss className="h-4 w-4" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Categories */}
|
||||
<div>
|
||||
<h4 className="font-semibold text-sm mb-4 text-stone-300 uppercase tracking-wider">Categories</h4>
|
||||
<ul className="space-y-3">
|
||||
{categoryLinks.map((link) => (
|
||||
<li key={link.label}>
|
||||
<Link to={link.to} className="text-sm text-stone-400 hover:text-white transition-colors">{link.label}</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Quick Links */}
|
||||
<div>
|
||||
<h4 className="font-semibold text-sm mb-4 text-stone-300 uppercase tracking-wider">Quick Links</h4>
|
||||
<ul className="space-y-3">
|
||||
{quickLinks.map((link) => (
|
||||
<li key={link.label}>
|
||||
<Link to={link.to} className="text-sm text-stone-400 hover:text-white transition-colors">{link.label}</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Newsletter */}
|
||||
<div>
|
||||
<h4 className="font-semibold text-sm mb-4 text-stone-300 uppercase tracking-wider">Newsletter</h4>
|
||||
<p className="text-sm text-stone-400 mb-4">
|
||||
Get the best articles delivered to your inbox weekly.
|
||||
</p>
|
||||
{subscribed ? (
|
||||
<p className="text-sm text-emerald-400 font-medium">Subscribed! Check your inbox.</p>
|
||||
) : (
|
||||
<form onSubmit={handleSubscribe} className="flex gap-2">
|
||||
<Input
|
||||
type="email"
|
||||
required
|
||||
placeholder="your@email.com"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
className="bg-stone-800 border-stone-700 text-white placeholder:text-stone-500 focus-visible:ring-emerald-500 text-sm"
|
||||
/>
|
||||
<Button type="submit" disabled={subscribing} className="bg-emerald-600 hover:bg-emerald-700 active:scale-[0.98] text-white flex-shrink-0">
|
||||
<Mail className="h-4 w-4" />
|
||||
</Button>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator className="my-10 bg-stone-800" />
|
||||
|
||||
<div className="flex flex-col sm:flex-row items-center justify-between gap-4">
|
||||
<p className="text-xs text-stone-500">
|
||||
© 2025 ByteSize. All rights reserved.
|
||||
</p>
|
||||
<p className="text-xs text-stone-500">
|
||||
Built with care for readers who love great writing.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user