feat(blog): complete blog experience overhaul
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 5s
Build & Deploy / 🧪 QA (push) Failing after 1m4s
Build & Deploy / 🏗️ Build (push) Failing after 3m51s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 5s
Build & Deploy / 🧪 QA (push) Failing after 1m4s
Build & Deploy / 🏗️ Build (push) Failing after 3m51s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
- Implemented minimalist vertical teaser list (MediumCard) - Consolidated and refined 20 engineering-focused blog posts - Rebuilt blog overview with narrow, centered layout (max-w-3xl) - Introduced BlogCommandBar for integrated search and tag filtering - Consolidated tags to 6-8 core technical categories - Redesigned blog detail pages with industrial 'Technical Frame' layout - Added SectionHeader component for consistent industrial titling - Optimized vertical space by removing redundant PageHeaders
This commit is contained in:
80
apps/web/src/components/blog/BlogCommandBar.tsx
Normal file
80
apps/web/src/components/blog/BlogCommandBar.tsx
Normal file
@@ -0,0 +1,80 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { cn } from "../../utils/cn";
|
||||
import { Search } from "lucide-react";
|
||||
|
||||
interface BlogCommandBarProps {
|
||||
searchQuery: string;
|
||||
onSearchChange: (value: string) => void;
|
||||
tags: string[];
|
||||
activeTags: string[];
|
||||
onTagToggle: (tag: string) => void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const BlogCommandBar: React.FC<BlogCommandBarProps> = ({
|
||||
searchQuery,
|
||||
onSearchChange,
|
||||
tags,
|
||||
activeTags,
|
||||
onTagToggle,
|
||||
className = "",
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"w-full max-w-2xl mx-auto flex flex-col items-center space-y-6 px-4 md:px-0",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{/* Command Input Area */}
|
||||
<div className="relative group w-full">
|
||||
{/* Glow Effect */}
|
||||
<div className="absolute -inset-0.5 bg-gradient-to-r from-slate-200 to-slate-100 rounded-2xl blur opacity-30 group-hover:opacity-100 transition duration-500" />
|
||||
|
||||
<div className="relative flex items-center bg-white rounded-2xl border border-slate-200 p-2 shadow-sm transition-all focus-within:ring-2 focus-within:ring-slate-100 focus-within:border-slate-300">
|
||||
<div className="pl-4 text-slate-400">
|
||||
<Search className="w-5 h-5" />
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
value={searchQuery}
|
||||
onChange={(e) => onSearchChange(e.target.value)}
|
||||
placeholder="Search posts..."
|
||||
className="w-full bg-transparent px-4 py-3 text-lg text-slate-900 placeholder:text-slate-300 outline-none font-bold"
|
||||
/>
|
||||
{searchQuery && (
|
||||
<button
|
||||
onClick={() => onSearchChange("")}
|
||||
className="mr-2 px-3 py-1.5 bg-slate-100 hover:bg-slate-200 rounded-lg text-[10px] font-bold uppercase tracking-wider text-slate-500 hover:text-slate-900 transition-colors"
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tag Command Row */}
|
||||
<div className="flex flex-wrap items-center justify-center gap-2">
|
||||
{tags.map((tag) => {
|
||||
const isActive = activeTags.includes(tag);
|
||||
return (
|
||||
<button
|
||||
key={tag}
|
||||
onClick={() => onTagToggle(tag)}
|
||||
className={cn(
|
||||
"px-3 py-1.5 rounded-lg text-[10px] font-mono uppercase tracking-wider border transition-all duration-200 select-none",
|
||||
isActive
|
||||
? "bg-slate-900 text-white border-slate-900 shadow-md transform scale-105"
|
||||
: "bg-white text-slate-500 border-slate-200 hover:border-slate-400 hover:text-slate-900 hover:bg-slate-50",
|
||||
)}
|
||||
>
|
||||
#{tag}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user