Skip to content

Commit

Permalink
enable content searching (#62)
Browse files Browse the repository at this point in the history
why:
- in the current deployment the search bar is a placeholder and has no
function which is not working as intented
how:
- enables content searching through filtering pre-fetched data that is
pulled on the content hub homepage;
- enables filtering by category by clicking on category pills;
- includes latest content and highlights as recommendations while
content searching is happening;

For the time being [Fuse.js](https://www.fusejs.io/api/options.html) is
being used as it offers a robust out-of-the-box configurable fuzzy
search + weighted search functionality.

Desktop Demo:

https://github.com/user-attachments/assets/e6635f1f-a8c0-4351-8498-c86222c2cfa4

Mobile Demo:

https://github.com/user-attachments/assets/f021fea1-01e4-4f25-b803-41752ef52577
  • Loading branch information
rccsousa authored Oct 24, 2024
1 parent 6c999ba commit c7b5a60
Show file tree
Hide file tree
Showing 26 changed files with 706 additions and 182 deletions.
5 changes: 5 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ const CDN_DOMAIN = process.env.CDN_DOMAIN || 'http://localhost:3000'

/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
serverActions: {
allowedOrigins: [process.env.NEXT_PUBLIC_SERVER_URL || 'http://localhost:3000'],
}
},
images: {
remotePatterns: [
...[CDN_DOMAIN /* 'https://example.com' */].map((item) => {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"cross-env": "^7.0.3",
"fuse.js": "^7.0.0",
"geist": "^1.3.0",
"get-video-id": "^4.1.7",
"graphql": "^16.8.2",
Expand Down
File renamed without changes.
26 changes: 4 additions & 22 deletions src/app/(pages)/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import HubHead from "@/app/_blocks/HubHead";
import SearchBar from "@/app/_components/SearchBar";
import { Header } from "@/app/_components/Header";
import { Metadata } from "next";
import { Category } from "@/payload-types";

export const dynamic = "force-dynamic";
export const revalidate = 0;
Expand All @@ -18,8 +19,9 @@ export default async function Page() {
TalksAndRoundtables: await fetchAllContentByType("talks-and-roundtables"),
};


const highlights = await fetchGlobals("homepage-settings", 3);
const categories = await fetchAllContentByType('categories').then((res: Category[]) => res.map((item: Category) => item.title))


return (

Expand All @@ -29,7 +31,7 @@ export default async function Page() {
<HubHead highlights={highlights} />

{/* Search Bar*/}
<SearchBar />
<SearchBar currentContent={content} highlights={highlights} categories={categories}/>


{/* Content Grid*/}
Expand All @@ -38,23 +40,3 @@ export default async function Page() {
</div>
);
}

export function generateMetadata(): Metadata {
return {
title: 'Styleguide Page',
description: 'A guide to various styles in our application.',
openGraph: {
title: 'Styleguide Open Graph Title',
description: 'This is the Open Graph description for the Styleguide page.',
url: 'https://example.com/styleguide',
images: [
{
url: 'https://example.com/og-image.jpg',
width: 800,
height: 600,
alt: 'Og Image Alt Text',
},
],
},
};
}
9 changes: 9 additions & 0 deletions src/app/(pages)/talks-and-roundtables/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,16 @@ import Contributors from "@/app/_blocks/EpisodeContent/Contributors";
import { TalksAndRoundtable } from "@/payload-types";
import { Metadata } from "next";
import { generateMeta } from "@/utilities/generateMeta";
import { Header } from "@/app/_components/Header";

export const dynamic = "force-dynamic";

const headerStyle = {
'--dynamic-background': 'var(--sub-purple-400)',
'--dynamic-color': 'var(--soft-white-100)',
'--dynamic-width': 'calc(100% - 40px)',
}

export default async function TalksAndRoundTablesPage({ params: paramsPromise }) {
const { slug } = await paramsPromise;

Expand All @@ -30,7 +37,9 @@ export default async function TalksAndRoundTablesPage({ params: paramsPromise })
const videoID = getVideoId(talk.url);

return (

<div>
<Header style={headerStyle}/>
{/* Head Block */}
<div className={styles.headContainer}>
<BackButton color={"var(--soft-white-100)"} />
Expand Down
2 changes: 1 addition & 1 deletion src/app/_blocks/EpisodeHead/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default function EpisodeHead({ episode }) {

{/* TODO: Second Column displays EpisodeFeaturedImage if ContentType is podcast */}
<div className={styles.featuredImage}>
{featuredImage && <FeaturedImage className={styles.featuredImage} src={featuredImage.url} />}
{featuredImage && <FeaturedImage src={featuredImage.url} />}
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/app/_blocks/HubHead/Highlights/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const placeholder = {
authors: "Placeholder",
};

export async function Highlights({ content, main }) {
export function Highlights({ content, main }) {
if (!content) {
content = placeholder;
}
Expand Down
2 changes: 1 addition & 1 deletion src/app/_blocks/HubHead/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Highlights } from './Highlights'
import styles from './styles.module.css'

export default async function HubHead({ highlights }) {
export default function HubHead({ highlights }) {
const { mainHighlight, secondaryHighlight } = highlights

return (
Expand Down
4 changes: 2 additions & 2 deletions src/app/_components/ArchiveButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ interface ArchiveButtonProps {
export default function ArchiveButton({ collection, color }: ArchiveButtonProps) {
return (
<a href={`/${collection}`} style={{ color: color || 'var(--dark-rock-800)' }}>
<div className={styles.container}>
<h6 className={styles.container}>
{iconMap[collection]} {formatTitle(collection)}
</div>
</h6>
</a>
)
}
12 changes: 6 additions & 6 deletions src/app/_components/AuthorPill/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function AuthorPill({ authors }) {
<Link href={`${process.env.NEXT_PUBLIC_SERVER_URL}/authors/${slug}`}>
<div className={styles.authorPill}>
<div className={styles.authorImage}>
{featuredImage && <FeaturedImage src={featuredImage.url} />}
{featuredImage && <FeaturedImage radius={'50%'} src={featuredImage.url} />}
</div>
{name}
</div>
Expand All @@ -30,10 +30,10 @@ export function AuthorPill({ authors }) {
return (
<div className={styles.twoAuthorPill}>
<div className={`${styles.authorImage} ${styles.authorOne}`}>
<FeaturedImage src={authorOne.featuredImage.url} />
<FeaturedImage radius={'50%'} src={authorOne.featuredImage.url} />
</div>
<div className={`${styles.authorImage} ${styles.authorTwo}`}>
<FeaturedImage src={authorTwo.featuredImage.url} />
<FeaturedImage radius={'50%'} src={authorTwo.featuredImage.url} />
</div>
{`${authorOne.name.split(" ")[0]} & ${authorTwo.name.split(" ")[0]}`}
</div>
Expand All @@ -48,13 +48,13 @@ export function AuthorPill({ authors }) {
return (
<div className={styles.twoAuthorPill}>
<div className={`${styles.authorImage} ${styles.authorOne}`}>
<FeaturedImage src={authorOne.featuredImage.url} />
<FeaturedImage radius={'50%'} src={authorOne.featuredImage.url} />
</div>
<div className={`${styles.authorImage} ${styles.authorTwo}`}>
<FeaturedImage src={authorTwo.featuredImage.url} />
<FeaturedImage radius={'50%'} src={authorTwo.featuredImage.url} />
</div>
<div className={`${styles.authorImage} ${styles.authorThree}`}>
<FeaturedImage src={authorThree.featuredImage.url} />
<FeaturedImage radius={'50%'} src={authorThree.featuredImage.url} />
</div>
Various authors
</div>
Expand Down
1 change: 0 additions & 1 deletion src/app/_components/AuthorPill/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
position: relative;
width: 34px;
height: 34px;
border-radius: 50%;
transition: 0.5s ease;
}

Expand Down
42 changes: 39 additions & 3 deletions src/app/_components/CategoryPill/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,40 @@
import styles from './styles.module.css'
export default function CategoryPill({ title }: { title: string }) {
return <div className={styles.categoryPill}>{title}</div>
"use client";
import styles from "./styles.module.css";
import { CloseIcon } from "@/app/_icons/icons";
import React, { useState } from "react";

interface CategoryPillProps {
title: string,
id?: string,
selected?: boolean,
setActiveFilter?: React.Dispatch<React.SetStateAction<boolean>>
setActiveCategory?: React.Dispatch<React.SetStateAction<string>>
}

export default function CategoryPill({ title, id, selected = false, setActiveFilter, setActiveCategory }: CategoryPillProps) {

const dynamicStyle = {
"--dynamic-color": selected ? "var(--sub-blue-300)" : "var(--sub-blue-100)",
} as React.CSSProperties;

return (
<div id={id} className={styles.categoryPill} style={dynamicStyle}>
{title}
{selected && (
<button onClick={(e) => {
// Stop propagation due to heavily nestes structure
e.stopPropagation();
if (setActiveFilter) {
setActiveFilter(false)
}

if (setActiveCategory) {
setActiveCategory("")
}
}}>
<CloseIcon id={id} width="16px" color="currentColor" />
</button>
)}
</div>
);
}
5 changes: 4 additions & 1 deletion src/app/_components/CategoryPill/styles.module.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
.categoryPill {
display: flex;
gap: 20px;
color: var(--sub-blue-800);
background-color: var(--sub-blue-100);
background-color: var(--dynamic-color);
height: 28px;
padding: 4px 20px;
align-items: center;
border-radius: 100px;
font-family: var(--colfax);
font-weight: bold;
Expand Down
4 changes: 2 additions & 2 deletions src/app/_components/FeaturedImage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import Image from "next/image";
import styles from "./styles.module.css";
import { Media } from "@/payload-types";

export default function FeaturedImage({ src, className }: { className?: string; src: Media }) {
export default function FeaturedImage({ src, radius }: { radius?: string; src: Media }) {

return (

<Image fill={true}
className={className ? className : styles.featuredImage}
style={{borderRadius: radius ?? '10px'}}
// @ts-ignore
src={src}
alt={"alt info"}
Expand Down
4 changes: 0 additions & 4 deletions src/app/_components/FeaturedImage/styles.module.css
Original file line number Diff line number Diff line change
@@ -1,4 +0,0 @@
.featuredImage {
margin: auto;
border-radius: 45px;
}
13 changes: 13 additions & 0 deletions src/app/_components/SearchBar/Components/CloseButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import styles from "./styles.module.css";

export default function MobileCloseButton() {
return (<div className={styles.closeButton}>
<p>Close</p>
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="20" cy="20" r="19.5" stroke="#403F4C" />
<path d="M26.4016 13.6001L13.6016 26.4001M26.4016 26.4001L13.6016 13.6001" stroke="#403F4C" stroke-linecap="round" />
</svg>

</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.closeButton {
display: flex;
justify-content: flex-end;
align-items: center;
font-size: var(--size-16);
gap: 16px;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Link from "next/link";
import styles from "./styles.module.css";
import FeaturedImage from "@/app/_components/FeaturedImage";
import ArchiveButton from "@/app/_components/ArchiveButton";
import { toKebabCase } from "@/app/_utilities/toKebabCase";

export default function MicroContentCard({ article }) {

const contentType = article["contentType"] || article["relationTo"];
const { title, slug, featuredImage } = article["content"] || article["value"] || article;
const collection = toKebabCase(contentType);


return (
<div className={styles.container}>

{featuredImage && (
<div className={styles.featuredImage}>
<Link href={`${collection}/${slug}`}>
<FeaturedImage src={featuredImage.url} />
</Link>
</div>
)}
<div className={styles.summary}>
<ArchiveButton collection={contentType} />
<Link href={`${collection}/${slug}`}><p>Read more...</p></Link>
</div>
</div>

);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
.container {
display: grid;
flex-direction: column;
border: 1px solid var(--dark-rock-800);
border-radius: 25px;
padding: 20px;
column-gap: 15px;
width: 320px;
}


.container a {
color: var(--sub-purple-600);
font-weight: bold;
font-size: var(--size-16);
}

.featuredImage {
position: relative;
width: 140px;
height: 140px;
align-self: center;
grid-column: 1;
}

.summary {
grid-column: 2;
text-overflow: ellipsis;
overflow: hidden;
}




@media(min-width: 1024px){
.container {
display: grid;
flex-direction: column;
border: 1px solid var(--dark-rock-800);
border-radius: 25px;
padding: 20px;
column-gap: 15px;
}

.container a {
color: var(--sub-purple-600);
font-weight: bold;
font-size: var(--size-16);
}


.featuredImage {
position: relative;
width: 140px;
height: 140px;
align-self: center;
grid-column: 1;
}

.summary {
grid-column: 2;
}

}
Loading

0 comments on commit c7b5a60

Please sign in to comment.