From aa021311b0431ba44d5e0537238bbd5425635873 Mon Sep 17 00:00:00 2001
From: Ammar Ahmed
Date: Thu, 9 May 2024 15:04:54 -0400
Subject: [PATCH 1/2] feat: add debounce hook + update blog metadata query
---
src/graphql/queries/Metadata.ts | 3 +++
src/hooks/debounce.ts | 25 +++++++++++++++++++++++++
src/pages/Blog/index.tsx | 15 ++++++++-------
3 files changed, 36 insertions(+), 7 deletions(-)
create mode 100644 src/hooks/debounce.ts
diff --git a/src/graphql/queries/Metadata.ts b/src/graphql/queries/Metadata.ts
index d210009..f9134a4 100644
--- a/src/graphql/queries/Metadata.ts
+++ b/src/graphql/queries/Metadata.ts
@@ -53,11 +53,13 @@ export const BLOG_METADATA_QUERY: DocumentNode = gql`
$tags: [String!]
$category: String
$onlyPublished: Boolean
+ $query: String
) {
blogMetadata(
tags: $tags
category: $category
onlyPublished: $onlyPublished
+ query: $query
) {
id
name
@@ -84,5 +86,6 @@ export namespace BlogMetadataQuery {
onlyPublished?: boolean
tags?: string[]
category?: string
+ query?: string
}
}
diff --git a/src/hooks/debounce.ts b/src/hooks/debounce.ts
new file mode 100644
index 0000000..13cfd9c
--- /dev/null
+++ b/src/hooks/debounce.ts
@@ -0,0 +1,25 @@
+import { useState, useEffect } from 'react'
+
+export type UseDebouncedOpts = {
+ delay?: number
+}
+
+export function useDebounced(
+ defaultValue: T,
+ opts?: UseDebouncedOpts,
+) {
+ let delay = 200
+ if (opts?.delay) delay = opts.delay
+
+ const [value, setValue] = useState(defaultValue)
+ const [debouncedValue, setDebouncedValue] =
+ useState(defaultValue)
+
+ useEffect(() => {
+ setTimeout(() => {
+ setDebouncedValue(value)
+ }, delay)
+ }, [value, delay])
+
+ return [value, debouncedValue, setValue]
+}
diff --git a/src/pages/Blog/index.tsx b/src/pages/Blog/index.tsx
index d123231..4bccd34 100644
--- a/src/pages/Blog/index.tsx
+++ b/src/pages/Blog/index.tsx
@@ -1,7 +1,7 @@
import React, { useState } from 'react'
import { useTextGradient } from '../../hooks/styles'
-// import { Input } from "@nextui-org/react";
-// import { MagnifyingGlassIcon } from "@heroicons/react/24/solid";
+import { Input } from '@nextui-org/react'
+import { MagnifyingGlassIcon } from '@heroicons/react/24/solid'
import BlogTags from './BlogTags'
import BlogCategories from './BlogCategories'
import {
@@ -20,6 +20,7 @@ const Blog: React.FC = () => {
})
const [tags, setTags] = useState([])
const [category, setCategory] = useState()
+
const { data, loading } = useQuery<
BlogMetadataQuery.Response,
BlogMetadataQuery.Variables
@@ -45,12 +46,12 @@ const Blog: React.FC = () => {
experiences or anything else of interest to me.
{/* TODO: Implement search in backend and come back to this. */}
- {/* }
+ }
isClearable
- /> */}
+ />
setTags(values)}
From 33b6724288ce7231bfc3403efb70ed78cebfbc5d Mon Sep 17 00:00:00 2001
From: Ammar Ahmed
Date: Thu, 9 May 2024 15:30:11 -0400
Subject: [PATCH 2/2] feat: add search to blog posts
---
src/hooks/debounce.ts | 7 +++++--
src/pages/Blog/index.tsx | 9 ++++++++-
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/src/hooks/debounce.ts b/src/hooks/debounce.ts
index 13cfd9c..c176092 100644
--- a/src/hooks/debounce.ts
+++ b/src/hooks/debounce.ts
@@ -4,10 +4,12 @@ export type UseDebouncedOpts = {
delay?: number
}
+export type UseDebouncedResponse = [T, T, SetState]
+
export function useDebounced(
defaultValue: T,
opts?: UseDebouncedOpts,
-) {
+): UseDebouncedResponse {
let delay = 200
if (opts?.delay) delay = opts.delay
@@ -16,9 +18,10 @@ export function useDebounced(
useState(defaultValue)
useEffect(() => {
- setTimeout(() => {
+ const id = setTimeout(() => {
setDebouncedValue(value)
}, delay)
+ return () => clearTimeout(id)
}, [value, delay])
return [value, debouncedValue, setValue]
diff --git a/src/pages/Blog/index.tsx b/src/pages/Blog/index.tsx
index 4bccd34..effff99 100644
--- a/src/pages/Blog/index.tsx
+++ b/src/pages/Blog/index.tsx
@@ -11,6 +11,7 @@ import {
import { useQuery } from '@apollo/client'
import BlogCard, { BlogCardSkeleton } from './BlogCard'
import { useBreakpointValue } from '../../hooks/mediaQuery'
+import { useDebounced } from '../../hooks/debounce'
const Blog: React.FC = () => {
const textGradient = useTextGradient({
@@ -20,6 +21,9 @@ const Blog: React.FC = () => {
})
const [tags, setTags] = useState([])
const [category, setCategory] = useState()
+ const [query, debouncedQuery, setQuery] = useDebounced('', {
+ delay: 400,
+ })
const { data, loading } = useQuery<
BlogMetadataQuery.Response,
@@ -29,6 +33,7 @@ const Blog: React.FC = () => {
onlyPublished: true,
category,
tags,
+ query: debouncedQuery,
},
})
const isMobile = useBreakpointValue({ default: true, md: false })
@@ -41,7 +46,7 @@ const Blog: React.FC = () => {
>
Blog
-
+
Sometimes I like to write about things I've worked on, my
experiences or anything else of interest to me.
@@ -51,6 +56,8 @@ const Blog: React.FC = () => {
label='Search'
startContent={}
isClearable
+ value={query}
+ onValueChange={setQuery}
/>