feat: update main blog
This commit is contained in:
parent
cff9197a6b
commit
7a9997cf79
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Mail } from 'lucide-react';
|
import { submitEmail } from '@/lib/actions/waitlistActions';
|
||||||
|
|
||||||
export const BlogNewsletter = () => {
|
export const BlogNewsletter = () => {
|
||||||
const [email, setEmail] = useState('');
|
const [email, setEmail] = useState('');
|
||||||
|
|
@ -13,28 +13,24 @@ export const BlogNewsletter = () => {
|
||||||
|
|
||||||
setStatus('loading');
|
setStatus('loading');
|
||||||
|
|
||||||
// TODO: Integrate with email service
|
const result = await submitEmail(email);
|
||||||
// For now, just simulate success
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
||||||
console.log('Newsletter subscription:', email);
|
|
||||||
|
|
||||||
setStatus('success');
|
if (result.success) {
|
||||||
setEmail('');
|
setStatus('success');
|
||||||
|
setEmail('');
|
||||||
// Reset status after 3 seconds
|
} else {
|
||||||
setTimeout(() => setStatus('idle'), 3000);
|
setStatus('error');
|
||||||
|
setTimeout(() => setStatus('idle'), 3000);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-xl bg-[#161b28] p-6 text-center border border-white/5 shadow-xl relative overflow-hidden">
|
<div className="rounded-xl bg-[#161b28] p-6 text-center border border-white/5 shadow-xl relative overflow-hidden">
|
||||||
<div className="absolute inset-0 bg-gradient-to-b from-violet-500/5 to-transparent pointer-events-none" />
|
<div className="absolute inset-0 bg-gradient-to-b from-violet-500/5 to-transparent pointer-events-none" />
|
||||||
<div className="relative z-10">
|
<div className="relative z-10">
|
||||||
<div className="w-12 h-12 bg-violet-500/10 rounded-xl flex items-center justify-center mx-auto mb-4 border border-violet-500/20">
|
|
||||||
<Mail className="w-5 h-5 text-violet-400" />
|
|
||||||
</div>
|
|
||||||
<h4 className="text-base font-bold text-white mb-2">Subscribe to Banatie</h4>
|
<h4 className="text-base font-bold text-white mb-2">Subscribe to Banatie</h4>
|
||||||
<p className="text-sm text-gray-400 mb-6 leading-relaxed">
|
<p className="text-sm text-gray-400 mb-4 leading-relaxed">
|
||||||
Get the latest technical articles, tutorials, and updates delivered right to your inbox.
|
Get the latest articles and updates delivered to your inbox.
|
||||||
</p>
|
</p>
|
||||||
<form onSubmit={handleSubmit} className="space-y-3">
|
<form onSubmit={handleSubmit} className="space-y-3">
|
||||||
<input
|
<input
|
||||||
|
|
@ -42,7 +38,7 @@ export const BlogNewsletter = () => {
|
||||||
value={email}
|
value={email}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
placeholder="your@email.com"
|
placeholder="your@email.com"
|
||||||
disabled={status === 'loading'}
|
disabled={status === 'loading' || status === 'success'}
|
||||||
className="block w-full rounded-lg border border-white/10 bg-[#0B0F19] py-2 px-3 text-white text-sm placeholder:text-gray-600 focus:border-violet-500 focus:ring-1 focus:ring-violet-500 focus:outline-none disabled:opacity-50"
|
className="block w-full rounded-lg border border-white/10 bg-[#0B0F19] py-2 px-3 text-white text-sm placeholder:text-gray-600 focus:border-violet-500 focus:ring-1 focus:ring-violet-500 focus:outline-none disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
|
|
@ -52,7 +48,8 @@ export const BlogNewsletter = () => {
|
||||||
>
|
>
|
||||||
{status === 'loading' && 'Subscribing...'}
|
{status === 'loading' && 'Subscribing...'}
|
||||||
{status === 'success' && 'Subscribed!'}
|
{status === 'success' && 'Subscribed!'}
|
||||||
{(status === 'idle' || status === 'error') && 'Subscribe'}
|
{status === 'error' && 'Try again'}
|
||||||
|
{status === 'idle' && 'Subscribe'}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,47 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
type TabType = 'latest' | 'popular';
|
||||||
|
|
||||||
interface BlogPageHeaderProps {
|
interface BlogPageHeaderProps {
|
||||||
title?: string;
|
title?: string;
|
||||||
|
onTabChange?: (tab: TabType) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BlogPageHeader = ({ title = 'Latest Articles' }: BlogPageHeaderProps) => {
|
export const BlogPageHeader = ({
|
||||||
|
title = 'Latest Articles',
|
||||||
|
onTabChange,
|
||||||
|
}: BlogPageHeaderProps) => {
|
||||||
|
const [activeTab, setActiveTab] = useState<TabType>('latest');
|
||||||
|
|
||||||
|
const handleTabClick = (tab: TabType) => {
|
||||||
|
setActiveTab(tab);
|
||||||
|
onTabChange?.(tab);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-between mb-8 pb-6 border-b border-white/5">
|
<div className="flex items-center justify-between mb-8 pb-6 border-b border-white/5">
|
||||||
<h1 className="text-3xl font-bold text-white tracking-tight">{title}</h1>
|
<h1 className="text-3xl font-bold text-white tracking-tight">{title}</h1>
|
||||||
<div className="flex items-center gap-2 text-sm text-gray-400 bg-white/5 p-1 rounded-lg border border-white/5">
|
<div className="flex items-center gap-2 text-sm text-gray-400 bg-white/5 p-1 rounded-lg border border-white/5">
|
||||||
<button className="px-3 py-1.5 rounded-md bg-[#111827] text-white shadow-sm font-medium text-xs transition-all">
|
<button
|
||||||
|
onClick={() => handleTabClick('latest')}
|
||||||
|
className={`px-3 py-1.5 rounded-md text-xs font-medium transition-all ${
|
||||||
|
activeTab === 'latest'
|
||||||
|
? 'bg-[#111827] text-white shadow-sm'
|
||||||
|
: 'hover:text-white'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
Latest
|
Latest
|
||||||
</button>
|
</button>
|
||||||
<button className="px-3 py-1.5 rounded-md hover:text-white text-xs font-medium transition-colors">
|
<button
|
||||||
|
onClick={() => handleTabClick('popular')}
|
||||||
|
className={`px-3 py-1.5 rounded-md text-xs font-medium transition-all ${
|
||||||
|
activeTab === 'popular'
|
||||||
|
? 'bg-[#111827] text-white shadow-sm'
|
||||||
|
: 'hover:text-white'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
Popular
|
Popular
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import type { Metadata } from 'next';
|
import type { Metadata } from 'next';
|
||||||
import { getAllPosts, getCategories } from './utils';
|
import { getAllPosts } from './utils';
|
||||||
import {
|
import {
|
||||||
BlogBackground,
|
BlogBackground,
|
||||||
BlogArticleCard,
|
BlogArticleCard,
|
||||||
BlogPageHeader,
|
BlogPageHeader,
|
||||||
BlogSearchInput,
|
// BlogSearchInput,
|
||||||
BlogCategories,
|
// BlogCategories,
|
||||||
BlogNewsletter,
|
BlogNewsletter,
|
||||||
BlogTags,
|
// BlogTags,
|
||||||
} from './_components';
|
} from './_components';
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
|
|
@ -16,11 +16,11 @@ export const metadata: Metadata = {
|
||||||
'Articles, guides, and updates about AI-powered placeholder images.',
|
'Articles, guides, and updates about AI-powered placeholder images.',
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultTags = ['ai', 'image-generation', 'api', 'midjourney', 'flux'];
|
// const defaultTags = ['ai', 'image-generation', 'api', 'midjourney', 'flux'];
|
||||||
|
|
||||||
export default function BlogPage() {
|
export default function BlogPage() {
|
||||||
const posts = getAllPosts();
|
const posts = getAllPosts();
|
||||||
const categories = getCategories();
|
// const categories = getCategories();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -53,10 +53,10 @@ export default function BlogPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<aside className="lg:col-span-4 xl:col-span-3 space-y-8">
|
<aside className="lg:col-span-4 xl:col-span-3 space-y-8">
|
||||||
<BlogSearchInput />
|
{/* <BlogSearchInput /> */}
|
||||||
<BlogCategories categories={categories} />
|
{/* <BlogCategories categories={categories} /> */}
|
||||||
<BlogNewsletter />
|
<BlogNewsletter />
|
||||||
<BlogTags tags={defaultTags} />
|
{/* <BlogTags tags={defaultTags} /> */}
|
||||||
</aside>
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue