-
Notifications
You must be signed in to change notification settings - Fork 106
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: blog tags page redesign (#546)
Co-authored-by: Tushar Mathur <[email protected]>
- Loading branch information
1 parent
112f3db
commit 9044d58
Showing
5 changed files
with
266 additions
and
0 deletions.
There are no files selected for viewing
116 changes: 116 additions & 0 deletions
116
src/components/blog/TagSelectionModal/TagSelectionModal.tsx
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,116 @@ | ||
import React, {useEffect, useMemo, useState} from "react" | ||
import {blogTagsMapping} from "@site/src/constants" | ||
import clsx from "clsx" | ||
import {X, Search} from "lucide-react" | ||
import Link from "@docusaurus/Link" | ||
import styles from "./styles.module.css" | ||
|
||
interface TagSelectionModalProps { | ||
open: boolean | ||
onClose?: () => void | ||
} | ||
|
||
const TagSelectionModal: React.FC<TagSelectionModalProps> = ({open, onClose}) => { | ||
const [query, setQuery] = useState("") | ||
|
||
useEffect(() => { | ||
if (typeof window === "undefined") return | ||
|
||
if (open) { | ||
document.body.style.overflow = "hidden" | ||
} else { | ||
document.body.style.overflow = "visible" | ||
} | ||
}, [open]) | ||
|
||
const getSearchResults = () => { | ||
const results: Record<string, BlogTag[]> = {} | ||
const lowerCaseQuery = query.toLowerCase() | ||
|
||
for (const [category, tags] of Object.entries(blogTagsMapping)) { | ||
const matches = tags.filter((tag) => tag.label.toLowerCase().startsWith(lowerCaseQuery)) | ||
if (matches.length) { | ||
results[category] = matches | ||
} | ||
} | ||
|
||
return results | ||
} | ||
|
||
const handleModalClose = () => { | ||
setQuery("") | ||
|
||
if (onClose) { | ||
onClose() | ||
} | ||
} | ||
|
||
const handleQueryChange = (e: React.ChangeEvent<HTMLInputElement>) => { | ||
setQuery(e.target.value) | ||
} | ||
|
||
const searchResults = useMemo(() => { | ||
return getSearchResults() | ||
}, [query]) | ||
|
||
return ( | ||
<> | ||
{open ? ( | ||
<> | ||
{/* Overlay */} | ||
<div | ||
className={clsx("block lg:hidden fixed inset-0 bg-black bg-opacity-50", styles.modalOverlay)} | ||
onClick={handleModalClose} | ||
></div> | ||
|
||
{/* Modal Container */} | ||
<div | ||
className={clsx( | ||
"absolute w-full lg:w-4/12 h-full overflow-scroll right-0 bg-white rounded-xl lg:rounded-none lg:border lg:border-solid lg:border-tailCall-border-light-500 px-4 py-8 lg:px-10 lg:py-8 flex flex-col gap-8", | ||
styles.modalContainer, | ||
)} | ||
> | ||
<div className="flex items-center justify-between"> | ||
<span className="text-title-medium lg:text-title-large text-black">Explore All Tags</span> | ||
<X width={24} height={24} className="cursor-pointer" onClick={handleModalClose} /> | ||
</div> | ||
<div className="flex flex-col gap-5 pb-36"> | ||
<div className="flex items-center gap-3 border border-solid border-tailCall-border-light-500 rounded-lg py-3 px-6"> | ||
<Search width={20} height={20} className="text-tailCall-light-500" /> | ||
<input | ||
name="tag" | ||
type="text" | ||
value={query} | ||
onChange={handleQueryChange} | ||
placeholder="Search Tags" | ||
className="text-black placeholder:text-tailCall-light-500 border-none outline-none text-content-small" | ||
/> | ||
</div> | ||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-x-8 gap-y-8 lg:gap-y-10"> | ||
{Object.keys(searchResults).map((category: string) => { | ||
return ( | ||
<div className="flex flex-col gap-3 lg:gap-4" key={category}> | ||
<span className="text-title-tiny lg:text-title-small text-black">{category}</span> | ||
{searchResults?.[category]?.map((tag: BlogTag) => ( | ||
<Link | ||
key={tag.label} | ||
to={tag.permalink} | ||
onClick={handleModalClose} | ||
className="text-content-small text-black px-3 py-1 border border-solid border-tailCall-border-light-500 rounded-3xl w-fit cursor-pointer hover:no-underline" | ||
> | ||
{tag.label} | ||
</Link> | ||
))} | ||
</div> | ||
) | ||
})} | ||
</div> | ||
</div> | ||
</div> | ||
</> | ||
) : null} | ||
</> | ||
) | ||
} | ||
|
||
export default TagSelectionModal |
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,9 @@ | ||
.modalContainer { | ||
z-index: calc(var(--ifm-z-index-fixed) + 2); | ||
top: var(--ifm-navbar-height); | ||
box-shadow: -56px 32px 48px 0px rgba(0, 0, 0, 0.08); | ||
} | ||
|
||
.modalOverlay { | ||
z-index: calc(var(--ifm-z-index-fixed) + 1); | ||
} |
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,95 @@ | ||
import React, {useCallback, useState} from "react" | ||
import clsx from "clsx" | ||
import {translate} from "@docusaurus/Translate" | ||
import {PageMetadata, HtmlClassNameProvider, ThemeClassNames, usePluralForm} from "@docusaurus/theme-common" | ||
import SearchMetadata from "@theme/SearchMetadata" | ||
import type {Props} from "@theme/BlogTagsPostsPage" | ||
import BlogPostList from "../BlogPostList" | ||
import Layout from "@theme/Layout" | ||
import TagSelectionModal from "@site/src/components/blog/TagSelectionModal/TagSelectionModal" | ||
|
||
// Very simple pluralization: probably good enough for now | ||
function useBlogPostsPlural() { | ||
const {selectMessage} = usePluralForm() | ||
return (count: number) => | ||
selectMessage( | ||
count, | ||
translate( | ||
{ | ||
id: "theme.blog.post.plurals", | ||
description: | ||
'Pluralized label for "{count} posts". Use as much plural forms (separated by "|") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)', | ||
message: "One post|{count} posts", | ||
}, | ||
{count}, | ||
), | ||
) | ||
} | ||
|
||
function useBlogTagsPostsPageTitle(tag: Props["tag"]): string { | ||
const blogPostsPlural = useBlogPostsPlural() | ||
return translate( | ||
{ | ||
id: "theme.blog.tagTitle", | ||
description: "The title of the page for a blog tag", | ||
message: '{nPosts} tagged with "{tagName}"', | ||
}, | ||
{nPosts: blogPostsPlural(tag.count), tagName: tag.label}, | ||
) | ||
} | ||
|
||
function BlogTagsPostsPageMetadata({tag}: Props): JSX.Element { | ||
const title = useBlogTagsPostsPageTitle(tag) | ||
return ( | ||
<> | ||
<PageMetadata title={title} description={tag.description} /> | ||
<SearchMetadata tag="blog_tags_posts" /> | ||
</> | ||
) | ||
} | ||
|
||
function BlogTagsPostsPageContent({tag, items}: Props): JSX.Element { | ||
const [showTagsModal, setShowTagsModal] = useState(false) | ||
|
||
const openTagSelectionModal = useCallback(() => { | ||
setShowTagsModal(true) | ||
}, []) | ||
|
||
const closeTagSelectionModal = useCallback(() => { | ||
setShowTagsModal(false) | ||
}, []) | ||
|
||
return ( | ||
<Layout> | ||
<div className="container mx-auto mt-3 mb-10 md:my-8 px-4 md:w-8/12"> | ||
<div className="flex flex-col md:flex-row gap-2 mb-5"> | ||
<span className="text-title-medium text-tailCall-light-600">Results for</span> | ||
<span className="flex items-center justify-between flex-1"> | ||
<span className="text-content-small px-3 py-1 text-tailCall-dark-100 rounded-full bg-tailCall-light-200"> | ||
{tag.label} | ||
</span> | ||
<span | ||
className="text-content-small text-tailCall-dark-500 underline cursor-pointer" | ||
onClick={openTagSelectionModal} | ||
> | ||
See all Tags | ||
</span> | ||
</span> | ||
</div> | ||
<BlogPostList items={items} /> | ||
</div> | ||
<TagSelectionModal open={showTagsModal} onClose={closeTagSelectionModal} /> | ||
</Layout> | ||
) | ||
} | ||
|
||
export default function BlogTagsPostsPage(props: Props): JSX.Element { | ||
return ( | ||
<HtmlClassNameProvider | ||
className={clsx(ThemeClassNames.wrapper.blogPages, ThemeClassNames.page.blogTagPostListPage)} | ||
> | ||
<BlogTagsPostsPageMetadata {...props} /> | ||
<BlogTagsPostsPageContent {...props} /> | ||
</HtmlClassNameProvider> | ||
) | ||
} |
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