1+ import * as React from 'react' ;
2+
3+ import { Route , Routes as DomRoutes , useParams } from 'react-router-dom' ;
4+ import { PageLayout } from '@redocly/theme/layouts/PageLayout' ;
5+ import { useThemeHooks } from '@redocly/theme/core/hooks' ;
6+
7+ import { SecondaryPostCard } from '@redocly/marketing-pages/components/Blog/SecondaryPostCard.js' ;
8+
9+ import { Button } from '@redocly/marketing-pages/components/Button/CustomButton.js' ;
10+ import { CallToAction } from '@redocly/marketing-pages/components/CallToAction/CallToAction.js' ;
11+ import { FirstThreePosts } from '@redocly/marketing-pages/components/Blog/FirstThreePosts.js' ;
12+ import { FeaturedClassics } from '@redocly/marketing-pages/components/Blog/FeaturedClassics.js' ;
13+ import { LatestPosts } from '@redocly/marketing-pages/components/Blog/LatestPosts.js' ;
14+ import { ContactUs } from '@redocly/marketing-pages/components/Blog/ContactUs.js' ;
15+ import { Breadcrumbs } from '@redocly/theme/components/Breadcrumbs/Breadcrumbs' ;
16+ import { BreadcrumbItem } from '@redocly/theme/core/types' ;
17+ import { H2 } from '@redocly/theme/components/Typography/H2' ;
18+ import styled from 'styled-components' ;
19+
20+ export default function BlogRoutes ( ) {
21+ return (
22+ < PageLayout >
23+ < DomRoutes >
24+ < Route path = "/" element = { < BlogMain /> } />
25+ < Route path = "/category/:category" element = { < CategoryPage /> } />
26+ < Route path = "/category/:category/:subcategory/" element = { < CategoryPage /> } />
27+ </ DomRoutes >
28+ </ PageLayout >
29+ ) ;
30+ }
31+
32+ // Blog main page component
33+ function BlogMain ( ) {
34+ return (
35+ < PageWrapper >
36+ < FirstThreePosts />
37+
38+ < FeaturedClassics />
39+
40+ < LatestPosts />
41+
42+ < ContactUs />
43+
44+ < CallToAction title = "Launch API docs you'll be proud of" >
45+ < Button
46+ to = "https://auth.cloud.redocly.com/registration"
47+ size = "large"
48+ className = "landing-button"
49+ >
50+ Start 30-day free trial
51+ </ Button >
52+ </ CallToAction >
53+ </ PageWrapper >
54+ ) ;
55+ }
56+
57+ const PageWrapper = styled . div `
58+ position: relative;
59+ overflow: hidden;
60+ ` ;
61+
62+ // Category page component
63+ function CategoryPage ( ) {
64+ const { category, subcategory } = useParams ( ) ;
65+ // @ts -ignore
66+ const { usePageSharedData } = useThemeHooks ( ) ;
67+ const { posts, metadata } = usePageSharedData < any > ( 'blog-posts' ) ;
68+
69+ const postList = React . useMemo ( ( ) => {
70+ return posts . filter ( ( post ) => {
71+ if ( ! post . categories || post . categories . length === 0 ) {
72+ return false ;
73+ }
74+ return post . categories . some ( ( postCategory ) => {
75+ if (
76+ subcategory &&
77+ postCategory . subcategory &&
78+ postCategory . subcategory . id === subcategory &&
79+ postCategory . category . id === category
80+ ) {
81+ return true ;
82+ } else if ( postCategory . category . id === category && ! subcategory ) {
83+ return true ;
84+ }
85+ return false ;
86+ } ) ;
87+ } ) ;
88+ } , [ posts , category , subcategory ] ) ;
89+
90+ const categoryLabel = React . useMemo ( ( ) => {
91+ if ( ! metadata ?. categories ) return category ;
92+ const categoryData = metadata . categories . find ( cat => cat . id === category ) ;
93+ return categoryData ?. label || category ;
94+ } , [ metadata , category ] ) ;
95+
96+ const subcategoryLabel = React . useMemo ( ( ) => {
97+ if ( ! subcategory || ! metadata ?. categories ) return subcategory ;
98+ const categoryData = metadata . categories . find ( cat => cat . id === category ) ;
99+ const subcategoryData = categoryData ?. subcategories ?. find ( sub => sub . id === subcategory ) ;
100+ return subcategoryData ?. label || subcategory ;
101+ } , [ metadata , category , subcategory ] ) ;
102+
103+ const breadcrumbItems : BreadcrumbItem [ ] = subcategory
104+ ? [
105+ { label : 'Blog' , link : '/blog' } ,
106+ { label : categoryLabel || '' , link : `/blog/category/${ category } ` } ,
107+ { label : subcategoryLabel || '' , link : `/blog/category/${ category } /${ subcategory } ` } ,
108+ ]
109+ : [
110+ { label : 'Blog' , link : '/blog' } ,
111+ { label : categoryLabel || '' , link : `/blog/category/${ category } ` } ,
112+ ] ;
113+
114+ return (
115+ < CategoryWrapper >
116+ < Breadcrumbs additionalBreadcrumbs = { breadcrumbItems } />
117+ < StyledH2 > { subcategory ? subcategoryLabel : categoryLabel } </ StyledH2 >
118+ < CardsWrapper >
119+ { postList . map ( ( post ) => (
120+ < SecondaryPostCard
121+ key = { post . slug }
122+ title = { post . title }
123+ to = { `${ post . slug } ` }
124+ img = { post . image }
125+ description = { post . description }
126+ date = { post . date }
127+ author = { post . author }
128+ />
129+ ) ) }
130+ </ CardsWrapper >
131+ </ CategoryWrapper >
132+ ) ;
133+ }
134+
135+ const StyledH2 = styled ( H2 ) `
136+ font-family: 'Red Hat Display';
137+ font-weight: 700;
138+ font-size: 54px;
139+ line-height: 64px;
140+
141+ margin: 0;
142+
143+ ` ;
144+
145+ const CardsWrapper = styled . div `
146+ display: grid;
147+ grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
148+ gap: 20px;
149+ ` ;
150+
151+ const CategoryWrapper = styled . div `
152+ display: flex;
153+ flex-direction: column;
154+ gap: 32px;
155+ margin: 96px auto 160px;
156+ max-width: 1032px;
157+ ` ;
0 commit comments