Seed: blog template (17 files)

This commit is contained in:
2026-07-23 22:10:06 +00:00
parent 2bd6c518da
commit 0814a832ef
+136
View File
@@ -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">
&copy; 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>
);
}