Skip to content

Commit cef56a4

Browse files
chore: update search input and add search
1 parent e4d2645 commit cef56a4

File tree

3 files changed

+100
-22
lines changed

3 files changed

+100
-22
lines changed

apps/sim/app/(landing)/studio/page.tsx

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ export const revalidate = 3600
1616
export default async function StudioIndex({
1717
searchParams,
1818
}: {
19-
searchParams: Promise<{ page?: string; tag?: string }>
19+
searchParams: Promise<{ page?: string; tag?: string; q?: string }>
2020
}) {
21-
const { page, tag } = await searchParams
21+
const { page, tag, q } = await searchParams
2222
const pageNum = Math.max(1, Number(page || 1))
2323
const perPage = 20
24+
const query = q?.trim().toLowerCase() ?? ''
2425

2526
const all = await getAllPostMeta()
2627

@@ -38,6 +39,22 @@ export default async function StudioIndex({
3839
}
3940
}
4041
}
42+
43+
if (query) {
44+
filtered = filtered.filter((p) => {
45+
const haystack = [
46+
p.title,
47+
p.description,
48+
...p.tags,
49+
p.author.name,
50+
...(p.authors?.map((a) => a.name) ?? []),
51+
]
52+
.join(' ')
53+
.toLowerCase()
54+
return haystack.includes(query)
55+
})
56+
}
57+
4158
const activeCategory = resolvedTag ? getCategoryById(resolvedTag) : null
4259

4360
const sorted = filtered.sort((a, b) => {
@@ -68,9 +85,28 @@ export default async function StudioIndex({
6885
type='application/ld+json'
6986
dangerouslySetInnerHTML={{ __html: JSON.stringify(studioJsonLd) }}
7087
/>
71-
{pageNum === 1 && !tag && <StudioHero />}
88+
{pageNum === 1 && !tag && !query && <StudioHero />}
7289
<div className='mx-auto w-full max-w-5xl py-12'>
73-
{activeCategory && (
90+
{query && (
91+
<div className='mb-8 flex items-center gap-3'>
92+
<span className='font-season text-[10px] uppercase tracking-widest text-[#666]'>
93+
Results for:
94+
</span>
95+
<span
96+
className='px-2 py-0.5 font-season text-[10px] uppercase tracking-wider text-[#ECECEC]'
97+
style={{ border: '1px solid #3d3d3d' }}
98+
>
99+
{q}
100+
</span>
101+
<Link
102+
href='/studio'
103+
className='font-mono text-[10px] uppercase tracking-wider text-[#999] transition-colors hover:text-[#ECECEC]'
104+
>
105+
Clear
106+
</Link>
107+
</div>
108+
)}
109+
{activeCategory && !query && (
74110
<div className='mb-8 flex items-center gap-3'>
75111
<span className='font-mono text-[10px] uppercase tracking-widest text-[#666]'>
76112
Filtered by:
@@ -105,14 +141,16 @@ export default async function StudioIndex({
105141
<section>
106142
<h2 className='mb-8 flex items-center gap-2 font-mono text-[11px] uppercase tracking-widest text-[#666]'>
107143
<span className='inline-block h-2 w-2 bg-[#00F701]' aria-hidden='true' />
108-
{activeCategory ? activeCategory.label : 'All Posts'}
144+
{query ? 'Search Results' : activeCategory ? activeCategory.label : 'All Posts'}
109145
</h2>
110146
<PostGrid posts={feed} />
111147
</section>
112148
)}
113149
{pagePosts.length === 0 && (
114150
<div className='py-20 text-center'>
115-
<p className='text-[14px] text-[#666]'>No posts found.</p>
151+
<p className='text-[14px] text-[#666]'>
152+
{query ? `No posts matching "${q}".` : 'No posts found.'}
153+
</p>
116154
<Link
117155
href='/studio'
118156
className='mt-4 inline-block font-mono text-[12px] uppercase tracking-wider text-[#999] transition-colors hover:text-[#ECECEC]'
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
'use client'
2+
3+
import { useCallback, useRef } from 'react'
4+
import { Search } from 'lucide-react'
5+
import { useRouter, useSearchParams } from 'next/navigation'
6+
7+
/**
8+
* Blog search input for the Studio sidebar.
9+
*
10+
* Reads the current `?q=` param as the default value.
11+
* On Enter, navigates to `/studio?q=<query>` which triggers
12+
* server-side filtering of posts by title, description, and tags.
13+
*/
14+
export function SearchInput() {
15+
const router = useRouter()
16+
const searchParams = useSearchParams()
17+
const inputRef = useRef<HTMLInputElement>(null)
18+
const currentQuery = searchParams.get('q') ?? ''
19+
20+
const handleSubmit = useCallback(
21+
(e: React.FormEvent) => {
22+
e.preventDefault()
23+
const value = inputRef.current?.value.trim() ?? ''
24+
if (value) {
25+
router.push(`/studio?q=${encodeURIComponent(value)}`)
26+
} else {
27+
router.push('/studio')
28+
}
29+
},
30+
[router]
31+
)
32+
33+
return (
34+
<form onSubmit={handleSubmit} className='relative'>
35+
<input
36+
ref={inputRef}
37+
type='text'
38+
defaultValue={currentQuery}
39+
placeholder='SEARCH POSTS...'
40+
className='w-full border border-[#2A2A2A] bg-[#232323] px-4 py-2 pr-9 font-season text-[11px] text-[#ECECEC] placeholder:text-[#666] transition-colors focus:border-[#00F701] focus:outline-none'
41+
style={{ borderRadius: '5px' }}
42+
aria-label='Search blog posts'
43+
/>
44+
<button
45+
type='submit'
46+
className='absolute right-0 top-0 flex h-full items-center px-3 text-[#666] transition-colors hover:text-[#999]'
47+
aria-label='Search'
48+
>
49+
<Search className='h-3.5 w-3.5' aria-hidden='true' />
50+
</button>
51+
</form>
52+
)
53+
}

apps/sim/app/(landing)/studio/sidebar.tsx

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { Search } from 'lucide-react'
21
import { getAllPostMeta } from '@/lib/blog/registry'
32
import { CategoryList } from '@/app/(landing)/studio/category-list'
3+
import { SearchInput } from '@/app/(landing)/studio/search-input'
44
import { CATEGORIES, getPrimaryCategory } from '@/app/(landing)/studio/tag-colors'
55

66
interface StudioSidebarProps {
@@ -45,22 +45,9 @@ export async function StudioSidebar({ activeTag }: StudioSidebarProps) {
4545
<h2 className='mb-4 font-season text-[10px] uppercase tracking-widest text-[#666]'>
4646
Find Insights
4747
</h2>
48-
<div className='relative'>
49-
<input
50-
type='text'
51-
placeholder='SEARCH COMING SOON...'
52-
disabled
53-
className='w-full cursor-not-allowed border border-[#2A2A2A] bg-[#232323] px-4 py-2 font-season text-[11px] text-[#ECECEC] opacity-50 placeholder:text-[#666]'
54-
style={{ borderRadius: '5px' }}
55-
aria-label='Search blog posts (coming soon)'
56-
/>
57-
<Search
58-
className='absolute right-3 top-2.5 h-3.5 w-3.5 text-[#666]'
59-
aria-hidden='true'
60-
/>
61-
</div>
48+
<SearchInput />
6249
</div>
63-
<div className='flex flex-col'>
50+
<div className='flex flex-col pt-6'>
6451
<h2 className='mb-3 font-season text-[10px] uppercase tracking-widest text-[#ECECEC]'>
6552
Categories
6653
</h2>

0 commit comments

Comments
 (0)