diff --git a/docusaurus.config.ts b/docusaurus.config.ts
index 40af9d9a2b..9b772327c8 100644
--- a/docusaurus.config.ts
+++ b/docusaurus.config.ts
@@ -220,7 +220,7 @@ export default {
routeBasePath: "blog",
include: ["**/*.{md,mdx}"],
exclude: ["**/_*.{js,jsx,ts,tsx,md,mdx}", "**/_*/**", "**/*.test.{js,jsx,ts,tsx}", "**/__tests__/**"],
- postsPerPage: 10,
+ postsPerPage: "ALL",
blogListComponent: "@theme/BlogListPage",
blogPostComponent: "@theme/BlogPostPage",
blogTagsListComponent: "@theme/BlogTagsListPage",
diff --git a/package.json b/package.json
index 7d4bed23c1..be399c6995 100644
--- a/package.json
+++ b/package.json
@@ -45,6 +45,7 @@
"react-hot-toast": "^2.4.1",
"react-on-screen": "^2.1.1",
"react-platform-js": "^0.0.1",
+ "react-tabs-scrollable": "^2.0.7",
"tailwindcss": "^3.4.4"
},
"devDependencies": {
diff --git a/src/css/custom.css b/src/css/custom.css
index 4f5004ecfe..44d5e1165a 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -681,3 +681,28 @@ span.token.tag.script.language-javascript {
.pagination-nav a:nth-child(2) {
@apply justify-end;
}
+
+.rts___tab {
+ border: none !important;
+ border-radius: 0px !important;
+}
+
+.rts___btn {
+ background: transparent !important;
+ border: none !important;
+}
+
+.rts___tab___selected {
+ border-bottom: 2px solid black !important;
+ background: transparent !important;
+ color: black !important;
+ box-shadow: none !important;
+}
+
+.rts___svg___icon:hover {
+ stroke: black !important;
+}
+
+button[disabled] {
+ display: none !important;
+}
diff --git a/src/theme/BlogLayout/categories.tsx b/src/theme/BlogLayout/categories.tsx
new file mode 100644
index 0000000000..1c8665137e
--- /dev/null
+++ b/src/theme/BlogLayout/categories.tsx
@@ -0,0 +1,33 @@
+import {useState} from "react"
+import {Tab, Tabs} from "react-tabs-scrollable"
+import "react-tabs-scrollable/dist/rts.css"
+
+export default function Categories(props: any): JSX.Element {
+ const {tags, activeTag, setActiveTag} = props
+
+ // define state with initial value to let the tabs start with that value
+ const [activeTab, setActiveTab] = useState(0)
+
+ // define a onClick function to bind the value on tab click
+ const onTabClick = (e, index) => {
+ setActiveTab(index)
+ setActiveTag(tags[index])
+ }
+
+ return (
+ <>
+
+ {/* generating an array to loop through it */}
+ {tags.map((name) => (
+ {name}
+ ))}
+
+ >
+ )
+}
diff --git a/src/theme/BlogLayout/customblogitem.tsx b/src/theme/BlogLayout/customblogitem.tsx
new file mode 100644
index 0000000000..3973bdd7cd
--- /dev/null
+++ b/src/theme/BlogLayout/customblogitem.tsx
@@ -0,0 +1,44 @@
+import {dateformatter, limitApplier} from "@site/src/utils"
+
+export default function BlogItemCustom(props) {
+ const {title, authors, ismobile, main, link, image, date} = props
+
+ return (
+ title && (
+
+ {(!ismobile || main) && (
+
+
+
+ )}
+
{dateformatter(date)}
+
+
{authors?.map((info) =>
)}
+
+ )
+ )
+}
+
+export const AuthorInfo = ({url, image_url, name}) => (
+
+
+
+
{name}
+
+
+)
+
+export const BlogIntro = ({title, description, main, link}) => {
+ const [ttlLimit, descLimit] = main ? [50, 150] : [48, 70]
+ return (
+ <>
+
+ {limitApplier(title, ttlLimit)}
+
+ {limitApplier(description, descLimit)}
+ >
+ )
+}
diff --git a/src/theme/BlogLayout/featured.tsx b/src/theme/BlogLayout/featured.tsx
new file mode 100644
index 0000000000..50ff0c4b9b
--- /dev/null
+++ b/src/theme/BlogLayout/featured.tsx
@@ -0,0 +1,22 @@
+import {AuthorInfo, BlogIntro} from "./customblogitem"
+
+export default function Featured({items}) {
+ return (
+
+
Featured Posts
+ {items?.slice(0, 6).map((item) => )}
+
+ )
+}
+
+const FeaturedItem = (props) => {
+ return (
+
+ )
+}
diff --git a/src/theme/BlogLayout/index.tsx b/src/theme/BlogLayout/index.tsx
index 400fcb4b68..d035460739 100644
--- a/src/theme/BlogLayout/index.tsx
+++ b/src/theme/BlogLayout/index.tsx
@@ -1,29 +1,166 @@
-import React from "react"
+import React, {useEffect, useState} from "react"
import clsx from "clsx"
import Layout from "@theme/Layout"
import BlogRecentPosts from "../BlogRecentPosts"
import type {Props} from "@theme/BlogLayout"
+import Categories from "./categories"
+import LinkButton from "@site/src/components/shared/LinkButton"
+import {Theme} from "@site/src/constants"
+import Featured from "./featured"
+import BlogItemCustom from "./customblogitem"
+import BrowserOnly from "@docusaurus/BrowserOnly"
export default function BlogLayout(props: Props): JSX.Element {
const {sidebar, toc, children, ...layoutProps} = props
const hasSidebar = sidebar && sidebar.items.length > 0
+ const [tags, setTags] = useState([])
+ const [activeTag, setActiveTag] = useState("All")
+ const [mainPage, setMainPage] = useState(false)
+ const [loadmore, setloadmore] = useState(false)
+ const [ismobile, setismobile] = useState(false)
+ const [allBlogs, setAllBlogs] = useState({})
+ const [featuredBlogsState, setFeaturedBlogs] = useState([])
+
+ useEffect(() => {
+ if (!children[0].props?.items) {
+ //return if its not the home page
+ return
+ } else {
+ setMainPage(true)
+ }
+
+ //initialize the setup
+ tagsSetup(children[0].props.items)
+ }, [children])
+
+ // code to maintain responsiveness
+
+ const updateMobileState = (setismobile) => {
+ setismobile(window.innerWidth <= 650)
+ }
+
+ // end mobile control
+
+ //this one is often called in parallel for each blog
+ const blogProcessor = async (blog, tagOccurrences) => {
+ return new Promise((resolve) => {
+ //now the logic
+ let tagsOfThis = blog.frontMatter.tags || []
+ let isFeatured = false
+ let polishedBlog = blogInfoGather(blog)
+
+ tagsOfThis.forEach((tag) => {
+ if (tag === "Featured") {
+ //save as featured
+ isFeatured = true
+ } else {
+ // good luck figuring this out :)
+ tagOccurrences[tag] = {
+ occurrences: tagOccurrences[tag]?.occurrences + 1 || 1,
+ blogs: [polishedBlog, ...(tagOccurrences[tag]?.blogs || [])],
+ }
+ }
+ })
+
+ //now, add it to the 'All' tag
+ tagOccurrences["All"] = {
+ occurrences: tagOccurrences["All"]?.occurrences + 1 || 1,
+ blogs: [polishedBlog, ...(tagOccurrences["All"]?.blogs || [])],
+ }
+
+ resolve(isFeatured ? polishedBlog : undefined)
+ })
+ }
+
+ //this is the parent function
+ const tagsSetup = async (allblogs) => {
+ //get all the tags first
+ // let tagOccurrences = {tag: {occurrences: 5, blogs: []}, }
+ let tagOccurrences: any = {}
+
+ //process each blog in parallel, it also reaturns the featured posts
+ let featuredBlogs = await Promise.all(allblogs.map(({content}) => blogProcessor(content, tagOccurrences)))
+ //unfortunately, it also sends undefineds
+ featuredBlogs = featuredBlogs.filter((b) => b !== undefined)
+
+ //now update the states
+
+ setTags(["All", ...Object.keys(tagOccurrences)])
+ setAllBlogs(tagOccurrences)
+ setFeaturedBlogs(featuredBlogs)
+ }
+
+ //this one extracts useful data from the frontmatter jargon
+ const blogInfoGather = (rawInfo) => {
+ return {...rawInfo.frontMatter, date: rawInfo.metadata.date, link: rawInfo.metadata.permalink}
+ }
+
+ const MobileStateUpdater = ({ismobile, setismobile}) => (
+ }>
+ {() => {
+ useEffect(() => {
+ if (!window) {
+ return
+ }
+
+ window.addEventListener("resize", () => updateMobileState(setismobile))
+ updateMobileState(setismobile)
+ }, [window])
+ return
+ }}
+
+ )
+ //
return (
-
-
-
+
- {children}
-
- {toc &&
{toc}
}
-
-
-
+
+
+
+
+
+
+
+ {allBlogs[activeTag]?.blogs.slice(1, 7).map((blog) => )}
+ {loadmore &&
+ allBlogs[activeTag]?.blogs.slice(7).map((blog) => )}
+
+ {!loadmore && allBlogs[activeTag]?.blogs.length > 6 && (
+ setloadmore(true)} />
+ )}
+
+ {toc &&
{toc}
}
+
+ {!ismobile &&
}
+
+ >
+ ) : (
+ <>
+
+
+
+ {children}
+
+ {toc &&
{toc}
}
+
+
+
+ >
+ )}
)
}
diff --git a/src/utils/index.ts b/src/utils/index.ts
index f1f22ef712..23b7053cca 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -33,3 +33,20 @@ export const isValidURL = (url: string) => {
return false
}
}
+
+export const limitApplier = (string: string, limit: number) => {
+ if (string?.length > limit) {
+ return string.substr(0, limit) + "..."
+ } else {
+ return string
+ }
+}
+
+export const dateformatter = (date: string) => {
+ let dateobj = new Date(date)
+ return dateobj.toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+}