feat(ui): improve blog list and terminal mockup responsiveness

- Make terminal mockup full width on all screen sizes
- Add empty state handling for blog list with visual feedback
- Maintain consistent styling across language versions
This commit is contained in:
joyzhao
2025-06-19 18:53:05 +08:00
parent 6c5813ecd2
commit c064c8a1c5
3 changed files with 92 additions and 70 deletions

View File

@@ -72,80 +72,103 @@ const readMoreText = lang === 'zh' ? '阅读更多' : 'Read More';
--- ---
<div class="space-y-6"> <div class="space-y-6">
{posts.map((post, index) => ( {posts.length > 0 ? (
<article class="group"> posts.map((post, index) => (
<div class="bg-card/50 backdrop-blur-sm rounded-2xl overflow-hidden border border-border hover:border-purple-500/50 transition-all duration-300 hover:transform hover:scale-[1.02]"> <article class="group">
<div class="flex flex-col md:flex-row"> <div class="bg-card/50 backdrop-blur-sm rounded-2xl overflow-hidden border border-border hover:border-purple-500/50 transition-all duration-300 hover:transform hover:scale-[1.02]">
{/* Featured Image */} <div class="flex flex-col md:flex-row">
<div class="relative overflow-hidden md:w-80 md:flex-shrink-0"> {/* Featured Image */}
<img <div class="relative overflow-hidden md:w-80 md:flex-shrink-0">
src={post.image} <img
alt={post.title} src={post.image}
class="w-full h-48 md:h-full object-cover group-hover:scale-110 transition-transform duration-300" alt={post.title}
/> class="w-full h-48 md:h-full object-cover group-hover:scale-110 transition-transform duration-300"
<div class="absolute inset-0 bg-gradient-to-t md:bg-gradient-to-r from-background/50 to-transparent"></div> />
</div> <div class="absolute inset-0 bg-gradient-to-t md:bg-gradient-to-r from-background/50 to-transparent"></div>
{/* Content */}
<div class="p-6 flex-1 flex flex-col justify-between">
<div>
<h2 class="text-xl font-bold text-card-foreground mb-3 group-hover:text-purple-500 transition-colors duration-200">
<a href={`${postBaseUrl}${post.slug}`}>
{post.title}
</a>
</h2>
<p class="text-muted-foreground mb-4 line-clamp-3">
{post.description}
</p>
{/* Tags */}
<div class="flex flex-wrap gap-2 mb-4">
{post.tags.map((tag, tagIndex) => {
// 使用 tagId 如果存在,否则使用 tag 本身
const tagRoute = post.tagId && Array.isArray(post.tagId) && tagIndex < post.tagId.length
? post.tagId[tagIndex]
: tag.toLowerCase();
return (
<a
href={`/${lang === 'en' ? '' : 'zh/'}blog/tags/${encodeURIComponent(tagRoute)}`}
class="px-2 py-1 text-xs bg-muted text-muted-foreground rounded-full hover:bg-muted/80 transition-colors"
>
# {tag}
</a>
);
})}
</div>
</div> </div>
{/* Meta Info */} {/* Content */}
<div class="flex items-center justify-between text-sm text-muted-foreground"> <div class="p-6 flex-1 flex flex-col justify-between">
<div class="flex items-center space-x-4"> <div>
<span class="flex items-center"> <h2 class="text-xl font-bold text-card-foreground mb-3 group-hover:text-purple-500 transition-colors duration-200">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <a href={`${postBaseUrl}${post.slug}`}>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 002 2v12a2 2 0 002 2z"></path> {post.title}
</svg> </a>
{post.date} </h2>
</span>
<span>{post.readTime}</span> <p class="text-muted-foreground mb-4 line-clamp-3">
{post.description}
</p>
{/* Tags */}
<div class="flex flex-wrap gap-2 mb-4">
{post.tags.map((tag, tagIndex) => {
// 使用 tagId 如果存在,否则使用 tag 本身
const tagRoute = post.tagId && Array.isArray(post.tagId) && tagIndex < post.tagId.length
? post.tagId[tagIndex]
: tag.toLowerCase();
return (
<a
href={`/${lang === 'en' ? '' : 'zh/'}blog/tags/${encodeURIComponent(tagRoute)}`}
class="px-2 py-1 text-xs bg-muted text-muted-foreground rounded-full hover:bg-muted/80 transition-colors"
>
# {tag}
</a>
);
})}
</div>
</div> </div>
<a {/* Meta Info */}
href={`${postBaseUrl}${post.slug}`} <div class="flex items-center justify-between text-sm text-muted-foreground">
class="text-purple-500 hover:text-purple-400 font-medium flex items-center group" <div class="flex items-center space-x-4">
> <span class="flex items-center">
{readMoreText} <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<svg class="w-4 h-4 ml-1 group-hover:translate-x-1 transition-transform duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 002 2v12a2 2 0 002 2z"></path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"></path> </svg>
</svg> {post.date}
</a> </span>
<span>{post.readTime}</span>
</div>
<a
href={`${postBaseUrl}${post.slug}`}
class="text-purple-500 hover:text-purple-400 font-medium flex items-center group"
>
{readMoreText}
<svg class="w-4 h-4 ml-1 group-hover:translate-x-1 transition-transform duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"></path>
</svg>
</a>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </article>
</article> ))
))} ) : (
<div class="flex flex-col items-center justify-center py-20 text-center bg-card/30 backdrop-blur-sm rounded-2xl border border-border p-8 min-h-[300px]">
<svg class="w-16 h-16 text-purple-500/70 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"></path>
</svg>
<p class="text-xl text-muted-foreground mb-4">
{lang === 'zh' ? '暂无博客文章' : 'No blog posts yet'}
</p>
<p class="text-sm text-muted-foreground/70 mb-6 max-w-md">
{lang === 'zh' ? '我们正在努力创作新的内容,请稍后再来查看。' : 'We are working on creating new content. Please check back later.'}
</p>
<a
href={`/${lang === 'en' ? '' : 'zh/'}`}
class="px-4 py-2 bg-purple-500/10 hover:bg-purple-500/20 text-purple-500 rounded-full transition-colors duration-200 flex items-center"
>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
</svg>
{lang === 'zh' ? '返回首页' : 'Back to Home'}
</a>
</div>
)}
</div> </div>
<style> <style>

View File

@@ -109,7 +109,7 @@ const pageTitle = t('site.title');
</div> </div>
<!-- Terminal mockup --> <!-- Terminal mockup -->
<div class="max-w-4xl mx-auto"> <div class="max-w-full mx-auto">
<div class="bg-gray-900/90 backdrop-blur-sm rounded-lg border border-gray-700/50 shadow-2xl overflow-hidden"> <div class="bg-gray-900/90 backdrop-blur-sm rounded-lg border border-gray-700/50 shadow-2xl overflow-hidden">
<!-- Terminal header --> <!-- Terminal header -->
<div class="flex items-center justify-between px-4 py-3 bg-gray-800/50 border-b border-gray-700/50"> <div class="flex items-center justify-between px-4 py-3 bg-gray-800/50 border-b border-gray-700/50">

View File

@@ -107,10 +107,9 @@ const pageTitle = t('site.title');
</a> </a>
</div> </div>
</div> </div>
</Container>
<!-- Terminal mockup --> <!-- Terminal mockup -->
<div class="max-w-4xl mx-auto"> <div class="max-w-full mx-auto">
<div class="bg-gray-900/90 backdrop-blur-sm rounded-lg border border-gray-700/50 shadow-2xl overflow-hidden"> <div class="bg-gray-900/90 backdrop-blur-sm rounded-lg border border-gray-700/50 shadow-2xl overflow-hidden">
<!-- Terminal header --> <!-- Terminal header -->
<div class="flex items-center justify-between px-4 py-3 bg-gray-800/50 border-b border-gray-700/50"> <div class="flex items-center justify-between px-4 py-3 bg-gray-800/50 border-b border-gray-700/50">