-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: common listing page components
- Loading branch information
1 parent
a1dbfc2
commit c61bca4
Showing
7 changed files
with
118 additions
and
84 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import Image from "next/image"; | ||
import { | ||
Card, | ||
CardDescription, | ||
CardFooter, | ||
CardHeader, | ||
CardTitle, | ||
} from "@/components/ui/card"; | ||
import Link from "next/link"; | ||
import clsx from "clsx"; | ||
|
||
interface Item { | ||
id: string; | ||
img: string; | ||
title: string; | ||
description: string; | ||
tags: string[]; | ||
link: string; | ||
} | ||
|
||
export function List({ list }: { list: Item[] }) { | ||
|
||
if (list.length === 0) { | ||
return <p>No items for the current search / filter.</p> | ||
} | ||
|
||
return ( | ||
<div className="grid grid-flow-row-dense grid-cols-2 lg:grid-cols-3 gap-8"> | ||
{list.map((i) => ( | ||
<Link key={i.id} href={i.link}> | ||
<Card className="flex flex-col h-full"> | ||
<div className="overflow-hidden"> | ||
<Image | ||
alt="Image" | ||
width={300} | ||
height={300} | ||
className="h-auto w-full object-cover transition-all hover:scale-105" | ||
src={i.img} | ||
/> | ||
</div> | ||
<CardHeader className="flex-grow"> | ||
<CardTitle>{i.title}</CardTitle> | ||
<CardDescription>{i.description}</CardDescription> | ||
</CardHeader> | ||
<CardFooter> | ||
{i.tags.map((tag, index) => ( | ||
<span | ||
key={tag} | ||
className={clsx( | ||
"inline-flex items-center rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10", | ||
{ "ml-3": index !== 0 } | ||
)} | ||
> | ||
{tag} | ||
</span> | ||
))} | ||
</CardFooter> | ||
</Card> | ||
</Link> | ||
))} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
"use client"; | ||
|
||
import { useSearchParams, useRouter, usePathname } from "next/navigation"; | ||
import { useCallback, useEffect, useState } from "react"; | ||
import { Input } from "@/components/ui/input"; | ||
|
||
export function Search({placeholder}: {placeholder?: string}) { | ||
const searchParams = useSearchParams(); | ||
const pathname = usePathname(); | ||
const router = useRouter(); | ||
const [search, setSearch] = useState(searchParams.get("search") || undefined); | ||
|
||
const createQueryString = useCallback( | ||
(value?: string) => { | ||
const params = new URLSearchParams(searchParams.toString()); | ||
params.delete("search"); | ||
|
||
if (value) params.set("search", value); | ||
|
||
const res = params.toString(); | ||
|
||
if (res) return "?" + res; | ||
|
||
return ""; | ||
}, | ||
[searchParams] | ||
); | ||
|
||
useEffect(() => { | ||
router.push(pathname + createQueryString(search)); | ||
}, [search]); | ||
|
||
return ( | ||
<Input | ||
value={search} | ||
placeholder={placeholder ?? "Search..."} | ||
onChange={(e) => setSearch(e.target.value)} | ||
className="w-1/2 mb-8" | ||
/> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,5 @@ | ||
"use client"; | ||
|
||
import { useSearchParams, useRouter, usePathname } from "next/navigation"; | ||
import { useCallback, useEffect, useState } from "react"; | ||
import { Input } from "@/components/ui/input"; | ||
import { Search } from "../listing-page/search"; | ||
|
||
export function TutorialSearch() { | ||
const searchParams = useSearchParams(); | ||
const pathname = usePathname(); | ||
const router = useRouter(); | ||
const [search, setSearch] = useState(searchParams.get("search") || undefined); | ||
|
||
const createQueryString = useCallback( | ||
(value?: string) => { | ||
const params = new URLSearchParams(searchParams.toString()); | ||
params.delete("search"); | ||
|
||
if (value) params.set("search", value); | ||
|
||
const res = params.toString(); | ||
|
||
if (res) return "?" + res; | ||
|
||
return ""; | ||
}, | ||
[searchParams] | ||
); | ||
|
||
useEffect(() => { | ||
router.push(pathname + createQueryString(search)); | ||
}, [search]); | ||
|
||
return ( | ||
<Input | ||
value={search} | ||
placeholder="Search tutorials..." | ||
onChange={(e) => setSearch(e.target.value)} | ||
className="w-1/2 mb-8" | ||
/> | ||
); | ||
return <Search placeholder="Search tutorials..." /> | ||
} |