Skip to content

Commit

Permalink
Merge pull request #912 from rachelxhoot/rahchelxhoot/blog_template
Browse files Browse the repository at this point in the history
feat(omi-template): Implement tag-based and search-based blog post filtering, breadcrumb navigation and post content
  • Loading branch information
dntzhang authored Jul 19, 2024
2 parents 8e47952 + cdd116a commit ee1821e
Showing 1 changed file with 177 additions and 62 deletions.
239 changes: 177 additions & 62 deletions packages/omi-templates/src/pages/blog.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,162 @@
import { signal, tag, Component } from 'omi'
import '../components/omiu/button'
import '../components/omiu/breadcrumb'

// 博客数据接口
interface BlogPost {
title: string
date: string
author: string
summary: string
tag: string
image: string
content: string
}

// 标签
const tags = signal([
{ name: 'All' },
{ name: 'JavaScript' },
{ name: 'Python' },
{ name: 'Web Development' }
])

// 博客数据
const blogPosts = signal([
{
title: 'Exploring JavaScript ES2024 Features',
date: 'June 15, 2024',
author: 'Rachel',
summary: 'An in-depth look at the new features introduced in JavaScript ES2024, including pattern matching and top-level await.',
category: 'JavaScript',
image: 'https://tdesign.gtimg.com/site/images/banner-thumb.jpg'
},
{
title: 'Deep Learning with Python: A Comprehensive Guide',
date: 'July 5, 2024',
author: 'Rachel',
summary: 'This guide covers the fundamentals of deep learning with Python, including neural networks, TensorFlow, and practical applications.',
category: 'Python',
image: 'https://tdesign.gtimg.com/site/images/banner-thumb.jpg'
},
{
title: 'Building Scalable Web Applications with Node.js',
date: 'July 20, 2024',
author: 'Rachel',
summary: 'Learn how to build scalable and high-performance web applications using Node.js, including best practices and performance optimization techniques.',
category: 'Web Development',
image: 'https://tdesign.gtimg.com/site/images/banner-thumb.jpg'
},
]);
const blogPosts: BlogPost[] = [
{
title: 'Exploring JavaScript ES2024 Features',
date: 'June 15, 2024',
author: 'Rachel',
summary: 'An in-depth look at the new features introduced in JavaScript ES2024, including pattern matching and top-level await.',
tag: 'JavaScript',
image: 'https://tdesign.gtimg.com/site/images/banner-thumb.jpg',
content: `
This is content.
`
},
{
title: 'Deep Learning with Python: A Comprehensive Guide',
date: 'July 5, 2024',
author: 'Rachel',
summary: 'This guide covers the fundamentals of deep learning with Python, including neural networks, TensorFlow, and practical applications.',
tag: 'Python',
image: 'https://tdesign.gtimg.com/site/images/banner-thumb.jpg',
content: `
This is content.
`
},
{
title: 'Building Scalable Web Applications with Node.js',
date: 'July 20, 2024',
author: 'Rachel',
summary: 'Learn how to build scalable and high-performance web applications using Node.js, including best practices and performance optimization techniques.',
tag: 'Web Development',
image: 'https://tdesign.gtimg.com/site/images/banner-thumb.jpg',
content: `
This is content.
`
},
]

const selectedBlogs = signal(blogPosts)
const activePost = signal<BlogPost | null>(null)

@tag('blog-template')
class BlogTemplate extends Component {
activeTag = signal('All')
searchKeyword = signal('')

breadcrumbs = signal([
{ label: 'Home', icon: 'home' }
])

blogFilter(tag: string) {
this.activeTag.value = tag
this.filterBlogs()
}

filterBlogs() {
let filteredBlogs = blogPosts
if (this.activeTag.value !== 'All') {
filteredBlogs = filteredBlogs.filter(post => post.tag === this.activeTag.value)
}
if (this.searchKeyword.value) {
const keyword = this.searchKeyword.value.toLowerCase()
filteredBlogs = filteredBlogs.filter(post => post.title.toLowerCase().includes(keyword))
}
selectedBlogs.value = filteredBlogs
}

handleSearchInput(event: Event) {
const inputElement = event.target as HTMLInputElement
this.searchKeyword.value = inputElement.value
this.filterBlogs()
}

handlePostClick(post: BlogPost) {
activePost.value = post
this.breadcrumbs.value = [
{ label: 'Home', icon: 'home' },
{ label: post.title, icon: 'root-list' }
]
}

handleRuturnClick() {
activePost.value = null
this.breadcrumbs.value = [{ label: 'Home', icon: 'home' }]
}

renderPostContent(post: BlogPost) {
return (
<div class="flex flex-col pl-6 pr-4 pt-3">
<article className="my-4 shadow bg-card dark:bg-gray-800 rounded-lg">
<div className="flex flex-col p-6">
<h1 className="text-3xl font-serif font-bold">{post.title}</h1>
<p className="pb-3 text-sm">
By <a href="#" className="font-semibold hover:text-gray-800 dark:hover:text-gray-400">{post.author}</a>, {post.date}
</p>
<div className="markdown-body">
{post.content}
</div>
</div>
</article>
<div class="mt-4">
<o-button
theme="primary"
onClick={() => this.handleRuturnClick()}
>
Return to Post List
</o-button>
</div>
</div>
)
}

renderBlogList() {
return (
<div class="flex flex-col pl-6 pr-4 pt-3">
{selectedBlogs.value.length == 0 ? (
<div class="col-span-full text-center text-foreground">None</div>
) : (
selectedBlogs.value.map((post, index) => (
<article key={index} class="my-4 shadow bg-card dark:bg-gray-800">
<a onClick={() => this.handlePostClick(post)}>
<img class="hover:opacity-75" src={post.image} alt="Post Image" />
</a>
<div class="flex flex-col p-6 pt-2">
<a onClick={() => this.handlePostClick(post)} class="my-2 text-sm font-bold uppercase border-b-2 border-blue-500 text-blue-600">{post.tag}</a>
<a onClick={() => this.handlePostClick(post)} class="pb-4 text-3xl font-serif font-bold hover:text-gray-700 dark:hover:text-gray-400">{post.title}</a>
<p class="pb-3 text-sm">By <a href="#" class="font-semibold hover:text-gray-800 dark:hover:text-gray-400">{post.author}</a>, {post.date}</p>
<p class="pb-6">{post.summary}</p>
<a onClick={() => this.handlePostClick(post)} class="uppercase text-xs text-blue-600 hover:text-yellow-500">Continue Reading <i class="fas fa-arrow-right"></i></a>
</div>
</article>
))
)}
</div>
)
}

render() {
return (
<div class="container mx-auto">
Expand All @@ -44,8 +170,8 @@ class BlogTemplate extends Component {
<img
src={"https://tdesign.gtimg.com/site/images/banner-thumb.jpg"}
alt="About Me"
class="rounded-md mb-4"
style="width: 300px; height: 300px; object-fit: cover;"
class="rounded-md mb-4 mt-6"
style="width: 350px; height: 350px; object-fit: cover;"
/>
<h3 class="text-xl font-semibold">Rachel</h3>
<p class="text-gray-500 mt-2 text-center">
Expand All @@ -71,7 +197,7 @@ class BlogTemplate extends Component {

{/* 搜索栏 */}
<section class="mt-8">
<form class="flex">
<form class="flex" onInput={(event) => this.handleSearchInput(event)}>
<input type="text" class="w-full px-3 py-2 rounded-l-lg focus:outline-none text-gray-800" placeholder="Search..." />
<button class="px-2 rounded-r-lg focus:outline-none text-center text-xl text-gray-400 hover:text-gray-900 bg-white"><i class="fas fa-search"></i></button>
</form>
Expand All @@ -81,31 +207,29 @@ class BlogTemplate extends Component {
<section class="mt-8">
<h3 class="mb-4 pb-2 text-2xl font-semibold border-b-2 border-blue-500 text-blue-600">Popular Posts</h3>
<ul>
{blogPosts.value.map((post, index) => (
{selectedBlogs.value.map((post, index) => (
<li key={index} class="mb-1">
<a class="text-blue-900 hover:text-blue-500" href="#">{post.title} ({post.category})</a>
<a class="text-blue-900 hover:text-blue-500" onClick={() => this.handlePostClick(post)}>{post.title} ({post.tag})</a>
</li>
))}
</ul>
</section>

{/* 分类栏 */}
<section class="mt-8">
<h3 class="mb-4 pb-2 text-2xl font-semibold border-b-2 border-blue-500 text-blue-600">Tags</h3>
<ul>
<li class="mb-1">
<i class="t-icon t-icon-hashtag text-blue-900 hover:text-blue-500" href="#"> Coding</i>
</li>
<li class="mb-1">
<i class="t-icon t-icon-hashtag text-blue-900 hover:text-blue-500" href="#"> Network</i>
</li>
<li class="mb-1">
<i class="t-icon t-icon-hashtag text-blue-900 hover:text-blue-500" href="#"> Web</i>
</li>
<li class="mb-1">
<i class="t-icon t-icon-hashtag text-blue-900 hover:text-blue-500" href="#"> Artificial Intelligence</i>
</li>
</ul>
<h3 class="mb-4 pb-2 text-2xl font-bold border-b-2 border-blue-500 text-blue-600">Tags</h3>
<div class="flex justify-around mb-8 text-blue-600">
{tags.value.map((tag, index) => (
<o-button
key={index}
variant="outline"
theme={tag.name === this.activeTag.value ? 'primary' : 'default'}
onClick={() => this.blogFilter(tag.name)}
>
{tag.name}
</o-button>
))}
</div>
</section>

{/* 订阅表单 */}
Expand All @@ -123,25 +247,16 @@ class BlogTemplate extends Component {
</form>
</div>
</section>

</aside>

{/* 右栏 */}
<main class="flex flex-col w-2/3 pl-6 pr-4 pt-12">
{blogPosts.value.map((post, index) => (
<article key={index} class="my-4 shadow bg-card dark:bg-gray-800">
<a href="#">
<img class="hover:opacity-75" src={post.image} alt="Post Image" />
</a>
<div class="flex flex-col p-6 pt-2">
<a href="#" class="my-2 text-sm font-bold uppercase border-b-2 border-blue-500 text-blue-600">{post.category}</a>
<a href="#" class="pb-4 text-3xl font-serif font-bold hover:text-gray-700 dark:hover:text-gray-400">{post.title}</a>
<p class="pb-3 text-sm">By <a href="#" class="font-semibold hover:text-gray-800 dark:hover:text-gray-400">{post.author}</a>, {post.date}</p>
<p class="pb-6">{post.summary}</p>
<a href="#" class="uppercase text-xs text-blue-600 hover:text-yellow-500">Continue Reading <i class="fas fa-arrow-right"></i></a>
</div>
</article>
))}
<div class="flex pl-4">
<o-breadcrumb
items={this.breadcrumbs.value}
></o-breadcrumb>
</div>
{activePost.value ? this.renderPostContent(activePost.value) : this.renderBlogList()}
</main>
</div>
</div>
Expand All @@ -151,4 +266,4 @@ class BlogTemplate extends Component {

export function BlogPage() {
return <blog-template />
}
}

0 comments on commit ee1821e

Please sign in to comment.