Skip to content

Commit 023a3c0

Browse files
feat: added resource section (#509)
* fixed * feat: added resource section * feat: added resource section * revert changes cd6d848 * revert changes 65e9f3e * revert changes 877b0f0 * revert changes 74711cd * fix: fixed the width issue * revert change * fix: added resource icon * Tiny changes to adjust look and feel. * Last changes to fix dark theme --------- Co-authored-by: Benjamin Granados <[email protected]>
1 parent ee6bfdf commit 023a3c0

File tree

7 files changed

+218
-65
lines changed

7 files changed

+218
-65
lines changed

CODEOWNERS

Lines changed: 0 additions & 16 deletions
This file was deleted.

components/CarbonsAds.tsx

Lines changed: 20 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,6 @@
11
import React, { useEffect, useRef } from 'react';
22
import { useRouter } from 'next/router';
33

4-
declare global {
5-
interface Window {
6-
_carbonads: {
7-
refresh: () => void;
8-
reload: (where: string, force_serve: boolean) => void;
9-
remove: (el: HTMLElement) => void;
10-
srv: () => void;
11-
};
12-
}
13-
}
14-
154
type Props = {
165
className?: string;
176
variant?: 'sidebar';
@@ -22,41 +11,28 @@ function CarbonAds({ className, variant = 'sidebar' }: Props) {
2211
const router = useRouter();
2312

2413
useEffect(() => {
25-
const mobileMediaQuery = window.matchMedia('(max-width: 1023px)');
26-
if (!mobileMediaQuery.matches) {
27-
const hasCarbonAds = document.querySelector('#carbonads');
28-
// Check if another ad is present to refresh
29-
if (hasCarbonAds) {
30-
window._carbonads.refresh();
31-
return;
32-
} else {
33-
// Check if the script is present (ad is not yet present) so that duplicate requests are not made to carbon ads
34-
const hasCarbonAdsScript = document.querySelector('#_carbonads_js');
35-
if (!hasCarbonAdsScript) {
36-
const carbonAdsScript = document.createElement('script');
37-
carbonAdsScript.id = '_carbonads_js';
38-
carbonAdsScript.type = 'text/javascript';
39-
carbonAdsScript.async = true;
40-
document
41-
.querySelector('#carbonads-container')
42-
?.appendChild(carbonAdsScript);
43-
carbonAdsScript.src = `//cdn.carbonads.com/carbon.js?serve=CE7I627Y&placement=json-schemaorg&rnd=${Math.random()}`;
44-
}
45-
}
14+
const hasCarbonAdsScript = document.querySelector('#_carbonads_js');
15+
if (!hasCarbonAdsScript) {
16+
const carbonAdsScript = document.createElement('script');
17+
carbonAdsScript.id = '_carbonads_js';
18+
carbonAdsScript.type = 'text/javascript';
19+
carbonAdsScript.async = true;
20+
document
21+
.querySelector('#carbonads-container')
22+
?.appendChild(carbonAdsScript);
23+
carbonAdsScript.src = `//cdn.carbonads.com/carbon.js?serve=CE7I627Y&placement=json-schemaorg&rnd=${Math.random()}`;
24+
}
4625

47-
const existingStyleSheet = document.querySelector('#_carbonads_css');
48-
if (existingStyleSheet) {
49-
existingStyleSheet.innerHTML = CarbonAds.stylesheet[variant];
50-
} else {
51-
const carbonAdsStyleSheet = document.createElement('style');
52-
carbonAdsStyleSheet.id = '_carbonads_css';
53-
carbonAdsStyleSheet.innerHTML = CarbonAds.stylesheet[variant];
54-
document
55-
.querySelector('#carbonads-container')
56-
?.appendChild(carbonAdsStyleSheet);
57-
}
26+
const existingStyleSheet = document.querySelector('#_carbonads_css');
27+
if (existingStyleSheet) {
28+
existingStyleSheet.innerHTML = CarbonAds.stylesheet[variant];
5829
} else {
59-
(carbonRef.current as HTMLElement).style.display = 'none';
30+
const carbonAdsStyleSheet = document.createElement('style');
31+
carbonAdsStyleSheet.id = '_carbonads_css';
32+
carbonAdsStyleSheet.innerHTML = CarbonAds.stylesheet[variant];
33+
document
34+
.querySelector('#carbonads-container')
35+
?.appendChild(carbonAdsStyleSheet);
6036
}
6137
}, [router.asPath]);
6238

components/Sidebar.tsx

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,22 @@ const getSpecificationPath = [
125125
'/specification-links',
126126
'/specification',
127127
];
128+
const getResourcePath = [
129+
'/resources/articles',
130+
'/resources/books',
131+
'/resources/articles',
132+
'/resources/podcasts',
133+
'/resources/papers',
134+
'/resources/audios',
135+
];
136+
const resourceRoutes = [
137+
{ uri: '/resources/books', label: 'Books' },
138+
{ uri: '/resources/articles', label: 'Articles' },
139+
{ uri: '/resources/courses', label: 'Courses' },
140+
{ uri: '/resources/videos', label: 'Videos' },
141+
{ uri: '/resources/podcasts', label: 'Podcasts' },
142+
{ uri: '/resources/papers', label: 'Papers' },
143+
];
128144
export const SidebarLayout = ({ children }: { children: React.ReactNode }) => {
129145
const router = useRouter();
130146
const [open, setOpen] = useState(false);
@@ -184,13 +200,14 @@ export const SidebarLayout = ({ children }: { children: React.ReactNode }) => {
184200
</div>
185201

186202
<div
187-
className={`z-[150] absolute top-10 mt-24 left-0 h-full w-screen bg-white transform ${open ? '-translate-x-0' : '-translate-x-full'} transition-transform duration-300 ease-in-out filter drop-shadow-md `}
203+
className={`z-[150] absolute top-10 mt-24 left-0 h-full w-screen bg-white transform ${
204+
open ? '-translate-x-0' : '-translate-x-full'
205+
} transition-transform duration-300 ease-in-out filter drop-shadow-md `}
188206
>
189207
<div className='flex flex-col mt-4'>
190208
<DocsNav />
191209
</div>
192210
</div>
193-
194211
<div className='dark:bg-slate-800 max-w-[1400px] grid grid-cols-1 lg:grid-cols-4 mx-4 md:mx-12'>
195212
<div className='hidden lg:block mt-24'>
196213
<DocsNav />
@@ -217,6 +234,7 @@ export const DocsNav = () => {
217234
getStarted: false,
218235
getReference: false,
219236
getSpecification: false,
237+
getResources: false,
220238
});
221239
useEffect(() => {
222240
const pathWtihoutFragment = extractPathWithoutFragment(router.asPath);
@@ -228,6 +246,8 @@ export const DocsNav = () => {
228246
setActive({ ...active, getReference: true });
229247
} else if (getSpecificationPath.includes(pathWtihoutFragment)) {
230248
setActive({ ...active, getSpecification: true });
249+
} else if (getResourcePath.includes(router.asPath)) {
250+
setActive({ ...active, getResources: true });
231251
}
232252
}, [router.asPath]);
233253

@@ -247,29 +267,37 @@ export const DocsNav = () => {
247267
setActive({ ...active, getSpecification: !active.getSpecification });
248268
};
249269

270+
const handleClickResources = () => {
271+
setActive({ ...active, getResources: !active.getResources });
272+
};
273+
250274
const rotate = active.getDocs ? 'rotate(180deg)' : 'rotate(0)';
251275
const rotateG = active.getStarted ? 'rotate(180deg)' : 'rotate(0)';
252276
const rotateR = active.getReference ? 'rotate(180deg)' : 'rotate(0)';
253277
const rotateSpec = active.getSpecification ? 'rotate(180deg)' : 'rotate(0)';
278+
const rotateResources = active.getResources ? 'rotate(180deg)' : 'rotate(0)';
254279

255280
const { theme } = useTheme();
256281

257282
const [learn_icon, setLearn_icon] = useState('');
258283
const [reference_icon, setReference_icon] = useState('');
259284
const [spec_icon, setSpec_icon] = useState('');
260285
const [overview_icon, setOverview_icon] = useState('');
286+
const [resources_icon, setResources_icon] = useState('');
261287

262288
useEffect(() => {
263289
if (theme === 'dark') {
264290
setOverview_icon('/icons/eye-dark.svg');
265291
setLearn_icon('/icons/compass-dark.svg');
266292
setReference_icon('/icons/book-dark.svg');
267293
setSpec_icon('/icons/clipboard-dark.svg');
294+
setResources_icon('/icons/bookshelf-dark.svg');
268295
} else {
269296
setOverview_icon('/icons/eye.svg');
270297
setLearn_icon('/icons/compass.svg');
271298
setReference_icon('/icons/book.svg');
272299
setSpec_icon('/icons/clipboard.svg');
300+
setResources_icon('/icons/bookshelf.svg');
273301
}
274302
}, [theme]);
275303

@@ -575,6 +603,50 @@ export const DocsNav = () => {
575603
</div>
576604
</div>
577605
</div>
606+
{/* Resources */}
607+
<div className='mb-2 bg-slate-200 dark:bg-slate-900 p-2 rounded'>
608+
<div
609+
className='flex justify-between w-full items-center'
610+
onClick={handleClickResources}
611+
>
612+
<div className='flex items-center align-middle'>
613+
<img
614+
src={`${resources_icon}`}
615+
alt='eye icon'
616+
className='mr-2 w-6'
617+
/>
618+
<SegmentHeadline label='Resources' />
619+
</div>
620+
<svg
621+
id='arrow'
622+
className='arrow'
623+
style={{
624+
transform: rotateResources,
625+
transition: 'all 0.2s linear',
626+
}}
627+
xmlns='http://www.w3.org/2000/svg'
628+
fill='none'
629+
height='32'
630+
viewBox='0 0 24 24'
631+
width='24'
632+
>
633+
<path
634+
clipRule='evenodd'
635+
d='m16.5303 8.96967c.2929.29289.2929.76777 0 1.06063l-4 4c-.2929.2929-.7677.2929-1.0606 0l-4.00003-4c-.29289-.29286-.29289-.76774 0-1.06063s.76777-.29289 1.06066 0l3.46967 3.46963 3.4697-3.46963c.2929-.29289.7677-.29289 1.0606 0z'
636+
fill='#707070'
637+
fillRule='evenodd'
638+
/>
639+
</svg>
640+
</div>
641+
<div
642+
className={classnames('ml-6', { hidden: !active.getResources })}
643+
id='resources'
644+
>
645+
{resourceRoutes.map(({ uri, label }) => (
646+
<DocLink key={uri} uri={uri} label={label} />
647+
))}
648+
</div>
649+
</div>
578650
</div>
579651
);
580652
};

components/StyledMarkdown.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -250,9 +250,7 @@ const StyledMarkdownBlock = ({ markdown }: { markdown: string }) => {
250250
},
251251
table: {
252252
component: ({ children }) => (
253-
<div className='max-w-[100%] mx-auto mb-8 overflow-auto'>
254-
<table className='table-auto'>{children}</table>
255-
</div>
253+
<table className='table-auto mb-8'>{children}</table>
256254
),
257255
},
258256
thead: {

pages/resources/[slug].page.tsx

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import React, { useEffect, useState } from 'react';
2+
import axios from 'axios';
3+
import yaml from 'js-yaml';
4+
import { getLayout } from '~/components/Sidebar';
5+
import Head from 'next/head';
6+
import { Headline1 } from '~/components/Headlines';
7+
8+
type ResourcesProps = {
9+
title: string;
10+
url: string;
11+
type: string;
12+
summary: string;
13+
};
14+
15+
type ParamProps = {
16+
slug: string;
17+
};
18+
19+
type DataProps = {
20+
slug: string;
21+
data: ResourcesProps[];
22+
};
23+
24+
export async function getStaticPaths() {
25+
const paths = [
26+
{ params: { slug: 'books' } },
27+
{ params: { slug: 'articles' } },
28+
{ params: { slug: 'courses' } },
29+
{ params: { slug: 'videos' } },
30+
{ params: { slug: 'podcasts' } },
31+
{ params: { slug: 'papers' } },
32+
];
33+
return { paths, fallback: false };
34+
}
35+
36+
export async function getStaticProps({ params }: { params: ParamProps }) {
37+
const { slug } = params;
38+
const data = await fetchResourceData(slug);
39+
40+
return {
41+
props: {
42+
data,
43+
},
44+
};
45+
}
46+
export default function ResourcePageComponent({ data }: { data: DataProps }) {
47+
const { slug, data: resourceData } = data;
48+
const routeName = slug.slice(0, -1);
49+
const [searchTerm, setSearchTerm] = useState('');
50+
const [filteredArticles, setFilteredArticles] = useState(
51+
resourceData?.filter((item: ResourcesProps) => item.type === routeName),
52+
);
53+
useEffect(() => {
54+
const results = resourceData.filter(
55+
(item: ResourcesProps) =>
56+
item.type === routeName &&
57+
item.title.toLowerCase().includes(searchTerm.toLowerCase()),
58+
);
59+
setFilteredArticles(results);
60+
}, [searchTerm, resourceData]);
61+
function capitalizeFirstLetter(value: string) {
62+
return value.charAt(0).toUpperCase() + value.slice(1);
63+
}
64+
const newTitle = capitalizeFirstLetter(slug);
65+
66+
return (
67+
<section>
68+
<Head>
69+
<title>{newTitle}</title>
70+
</Head>
71+
<Headline1>{newTitle}</Headline1>
72+
Welcome to the {`${newTitle}`} section. Please use the search box to
73+
search for specific terms.
74+
<div className='mt-6'>
75+
<input
76+
type='text'
77+
name='text'
78+
placeholder={`Search ${newTitle}`}
79+
value={searchTerm}
80+
onChange={(e) => setSearchTerm(e.target.value)}
81+
className='w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:border-blue-500 transition duration-300'
82+
/>
83+
{filteredArticles &&
84+
filteredArticles.map((item: ResourcesProps, index: number) => (
85+
<div key={index} className='p-3'>
86+
<a
87+
href={item.url}
88+
target='_blank'
89+
rel='noreferrer'
90+
className='text-xl text-blue-500 underline mb-2'
91+
>
92+
{item.title}
93+
</a>
94+
<p className='mt-2'>{item.summary}</p>
95+
</div>
96+
))}
97+
</div>
98+
</section>
99+
);
100+
}
101+
102+
const fetchResourceData = async (slug: string) => {
103+
try {
104+
const apiUrl =
105+
'https://raw.githubusercontent.com/sourcemeta/awesome-jsonschema/master/data.yaml';
106+
const response = await axios.get(apiUrl);
107+
const parsedData = yaml.load(response.data);
108+
return {
109+
slug,
110+
data: parsedData,
111+
};
112+
} catch (error) {
113+
console.error('Error fetching data');
114+
return { slug, dummyData: 'No Data Found' };
115+
}
116+
};
117+
ResourcePageComponent.getLayout = getLayout;

public/icons/bookshelf-dark.svg

Lines changed: 3 additions & 0 deletions
Loading

public/icons/bookshelf.svg

Lines changed: 3 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)