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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy