Skip to content

Commit f1192d3

Browse files
committed
Fixed routing for languages and categories
1 parent 3327984 commit f1192d3

File tree

11 files changed

+152
-112
lines changed

11 files changed

+152
-112
lines changed

src/App.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import { Outlet } from "react-router-dom";
12
import Footer from "./layouts/Footer";
23
import Header from "./layouts/Header";
34
import Sidebar from "./layouts/Sidebar";
45
import SnippetList from "./layouts/SnippetList";
6+
import LanguageSwitch from "./components/LanguageSwitch";
57

68
const App = () => {
79
return (
@@ -17,7 +19,10 @@ const App = () => {
1719
</p>
1820
</div>
1921
<main className="main">
20-
<Sidebar />
22+
<aside className="sidebar flow">
23+
<LanguageSwitch />
24+
<Outlet />
25+
</aside>
2126
<SnippetList />
2227
</main>
2328
<hr className="divider" />

src/components/Category.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1+
import { Link } from "react-router-dom";
12
import { CategoryProps } from "../types";
3+
import slugify from "../utils/slugify";
24

3-
const Category = ({ title }: CategoryProps) => {
5+
const Category = ({ title, language }: CategoryProps) => {
46
return (
5-
<li className={`category ${title === "API Requests" ? "active" : null}`}>
6-
<a className="category__link" href="#">
7+
<li className="category">
8+
<Link
9+
to={`/${slugify(language || "")}/${slugify(title)}`}
10+
className="category__link"
11+
>
712
{title}
8-
</a>
13+
</Link>
914
</li>
1015
);
1116
};

src/components/CategoryList.tsx

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,21 @@
11
import { useLoaderData, useParams } from "react-router-dom";
2-
import { CategoryProps } from "../types";
32
import Category from "./Category";
43

54
const CategoryList = () => {
65
const { language } = useParams();
7-
// const data = useLoaderData();
6+
const categories = useLoaderData() as string[];
87

9-
const sampleData: CategoryProps[] = [
10-
{
11-
title: "DOM Manipulation",
12-
},
13-
{
14-
title: "API Requests",
15-
},
16-
{
17-
title: "Local Storage",
18-
},
19-
{
20-
title: "Performance Optimization",
21-
},
22-
{
23-
title: "Date and Time",
24-
},
25-
];
8+
console.log(categories);
9+
10+
if (!categories) {
11+
return <div>empty</div>;
12+
}
2613

2714
return (
2815
<>
29-
<p>{language}</p>
3016
<ul role="list" className="categories">
31-
{sampleData.map((category) => (
32-
<Category key={category.title} {...category} />
17+
{categories.map((category) => (
18+
<Category key={category} title={category} language={language || ""} />
3319
))}
3420
</ul>
3521
</>

src/components/LanguageSwitch.tsx

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,55 @@
1-
import { SwitchIcon } from "./Icons";
1+
import { useEffect, useState } from "react";
2+
import slugify from "../utils/slugify";
3+
import { useNavigate } from "react-router-dom";
4+
// import { SwitchIcon } from "./Icons";
25

36
const LanguageSwitch = () => {
4-
// const sampleData = ["JavaScript", "Python", "Java"];
7+
const [languages, setLanguages] = useState<string[]>([]);
8+
const navigate = useNavigate();
9+
10+
useEffect(() => {
11+
const fetchLanguages = async () => {
12+
try {
13+
const res = await fetch(`/data/index.json`);
14+
if (!res.ok) {
15+
throw new Error("Failed to fetch languages");
16+
}
17+
18+
const data = await res.json();
19+
setLanguages(data.languages);
20+
} catch (error) {
21+
console.error(`Error occurred: ${error}`);
22+
}
23+
};
24+
25+
fetchLanguages();
26+
}, []);
27+
28+
const handleLanguageChange = (
29+
event: React.ChangeEvent<HTMLSelectElement>
30+
) => {
31+
const selectedLanguage = event.target.value;
32+
if (selectedLanguage) {
33+
navigate(`/${selectedLanguage}`);
34+
}
35+
};
536

637
return (
7-
<div className="language-switcher">
8-
<h2 className="section-title">JavaScript</h2>
9-
<SwitchIcon />
10-
</div>
38+
<select
39+
id="languages"
40+
className="language-switcher"
41+
onChange={handleLanguageChange}
42+
>
43+
{languages.map((language) => (
44+
<option key={language} value={slugify(language)}>
45+
{language}
46+
</option>
47+
))}
48+
</select>
49+
// <div >
50+
// <h2 className="section-title">JavaScript</h2>
51+
// <SwitchIcon />
52+
// </div>
1153
);
1254
};
1355

src/components/SnippetCard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const SnippetCard = ({ title }: SnippetCardProps) => {
1111
</IconButton>
1212
</div>
1313
<div className="snippet__content">
14-
<h3>{title}</h3>
14+
<h3 className="snippet__title">{title}</h3>
1515
<IconButton>
1616
<ExpandIcon />
1717
</IconButton>

src/layouts/Sidebar.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,7 @@ import CategoryList from "../components/CategoryList";
22
import LanguageSwitch from "../components/LanguageSwitch";
33

44
const Sidebar = () => {
5-
return (
6-
<aside className="sidebar flow">
7-
<LanguageSwitch />
8-
<CategoryList />
9-
</aside>
10-
);
5+
return <h1>H</h1>;
116
};
127

138
export default Sidebar;

src/layouts/SnippetList.tsx

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,24 @@
1+
import { useLoaderData, useParams } from "react-router-dom";
12
import SnippetCard from "../components/SnippetCard";
2-
import { SnippetCardProps } from "../types";
3+
import { SnippetCardProps, SnippetType } from "../types";
34

45
const SnippetList = () => {
5-
const sampleData: SnippetCardProps[] = [
6-
{
7-
title: "GET Request",
8-
},
9-
{
10-
title: "POST Request",
11-
},
12-
{
13-
title: "fetch() Request",
14-
},
15-
{
16-
title: "Async/Await",
17-
},
18-
{
19-
title: "Fetching with Axios",
20-
},
21-
];
6+
const { language, category } = useParams();
7+
const snippets = useLoaderData() as SnippetType[];
8+
9+
if (!snippets) return <div>empty</div>;
2210

2311
return (
2412
<section className="flow">
25-
<h2 className="section-title">API Requests</h2>
13+
<h2 className="section-title">{category}</h2>
2614
<ul role="list" className="snippets">
27-
{sampleData.map((snippet) => (
28-
<SnippetCard key={snippet.title} {...snippet} />
15+
{snippets.map((snippet) => (
16+
<SnippetCard
17+
key={snippet.title}
18+
language={language}
19+
category={category}
20+
{...snippet}
21+
/>
2922
))}
3023
</ul>
3124
</section>

src/main.tsx

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,27 @@ import { createBrowserRouter, RouterProvider } from "react-router-dom";
66
import CategoryList from "./components/CategoryList";
77
import SnippetList from "./layouts/SnippetList";
88
import SnippetModal from "./components/SnippetModal";
9-
import { fetchCategories, fetchLanguages, fetchSnippets } from "./services/api";
9+
import { fetchCategories, fetchSnippets } from "./services/api";
1010

1111
const router = createBrowserRouter([
1212
{
1313
path: "/",
1414
element: <App />,
15-
loader: fetchLanguages,
1615
children: [
1716
{
1817
path: ":language",
1918
element: <CategoryList />,
20-
loader: fetchCategories,
21-
children: [
22-
{
23-
path: ":category",
24-
element: <SnippetList />,
25-
loader: fetchSnippets,
26-
children: [
27-
{
28-
path: ":snippet",
29-
element: <SnippetModal />,
30-
loader: fetchSnippets,
31-
},
32-
],
33-
},
34-
],
19+
loader: ({ params }) => fetchCategories(params),
20+
},
21+
{
22+
path: ":language/:category",
23+
element: <SnippetList />,
24+
loader: ({ params }) => fetchSnippets(params),
25+
},
26+
{
27+
path: ":language/:category/:snippet",
28+
element: <SnippetModal />,
29+
loader: ({ params }) => fetchSnippets(params),
3530
},
3631
],
3732
},

src/services/api.ts

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,35 @@
1+
import { FileType, SnippetType } from "../types";
12
import slugify from "../utils/slugify";
23

3-
export const fetchLanguages = async ({ params }: any) => {
4-
try {
5-
const res = await fetch(`/data/${params.language}.json`);
6-
if (!res.ok) {
7-
throw new Error("Failed to fetch languages");
8-
}
9-
10-
console.log(`/data/${params.language}.json`);
11-
console.log("data fetch");
12-
13-
const data = await res.json();
14-
console.log(data);
15-
16-
return data;
17-
} catch (error) {
18-
return new Error(`Error occured: ${error}`);
19-
}
20-
};
21-
224
export const fetchCategories = async (params: any) => {
235
try {
246
const res = await fetch(`/data/${params.language}.json`);
25-
const data = await res.json();
26-
27-
const newData = data.map((category: any) => category.categoryName);
7+
const data: FileType = await res.json();
288

9+
const newData = data.map((category) => category.categoryName);
2910
console.log(newData);
11+
3012
return newData;
3113
} catch (error) {
32-
return new Error(`Error occured: ${error}`);
14+
console.error("Error occured");
15+
return [];
3316
}
3417
};
3518

3619
export const fetchSnippets = async (params: any) => {
3720
try {
3821
const res = await fetch(`/data/${params.language}.json`);
39-
const data = await res.json();
22+
const data: FileType = await res.json();
4023

4124
const categoryData = data.find(
42-
(cat: any) => slugify(cat.categoryName) === slugify(params.category)
25+
(cat) => slugify(cat.categoryName) === slugify(params.category)
4326
);
4427
return categoryData?.snippets.find(
45-
(snip: any) => slugify(snip.title) === params.snippet
28+
(snip) => slugify(snip.title) === params.snippet
4629
);
4730
} catch (error) {
4831
console.error("Error occured: ", error);
32+
return {};
4933
}
5034
};
5135

src/styles/main.css

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -283,17 +283,19 @@ ol:where([role="list"]) {
283283
align-items: start;
284284

285285
@media (width > 50em) {
286-
grid-template-columns: 2fr 5fr;
286+
grid-template-columns: 2fr 6fr;
287287
}
288288
}
289289

290290
/*------------------------------------*\
291291
#SIDEBAR
292292
\*------------------------------------*/
293293
.language-switcher {
294-
display: flex;
295-
justify-content: space-between;
296-
cursor: pointer;
294+
background-color: transparent;
295+
border: 0;
296+
/* padding-block: 0.5em; */
297+
font-weight: var(--fw-bold);
298+
font-size: var(--fs-600);
297299
}
298300

299301
.language-switcher option {
@@ -316,6 +318,8 @@ ol:where([role="list"]) {
316318
.category.active {
317319
background-image: var(--gradient-secondary);
318320
border: 1px solid var(--border-color);
321+
font-weight: var(--fw-bold);
322+
color: var(--text-primary);
319323
}
320324

321325
.category__link {
@@ -324,6 +328,7 @@ ol:where([role="list"]) {
324328
display: inline-block;
325329
padding: 0.75em 1em;
326330
width: 100%;
331+
font-size: var(--fs-500);
327332

328333
&:is(:hover, :focus) {
329334
color: var(--text-primary);
@@ -374,6 +379,10 @@ ol:where([role="list"]) {
374379
align-items: center;
375380
}
376381

382+
.snippet__title {
383+
color: var(--text-primary);
384+
}
385+
377386
/*------------------------------------*\
378387
#FOOTER
379388
\*------------------------------------*/

0 commit comments

Comments
 (0)